@eduardoalvarez/arrecife 0.3.0 → 0.5.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.
Files changed (41) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/README.md +121 -1
  3. package/dist/brand/index.cjs +29 -10
  4. package/dist/brand/index.d.cts +9 -1
  5. package/dist/brand/index.d.ts +9 -1
  6. package/dist/brand/index.js +4 -2
  7. package/dist/chart/index.cjs +287 -0
  8. package/dist/chart/index.d.cts +127 -0
  9. package/dist/chart/index.d.ts +127 -0
  10. package/dist/chart/index.js +103 -0
  11. package/dist/chunk-KPZNNMV5.js +83 -0
  12. package/dist/chunk-MLKGABMK.js +7 -0
  13. package/dist/chunk-NHS7ETKJ.js +27 -0
  14. package/dist/{chunk-I7GYZD2A.js → chunk-TSPJOM6K.js} +5 -7
  15. package/dist/chunk-UOWIDFCB.js +81 -0
  16. package/dist/{chunk-VSMW2CT4.js → chunk-VPT32GPG.js} +2 -1
  17. package/dist/{chunk-ND45OQOC.js → chunk-YZ2SDOVZ.js} +29 -35
  18. package/dist/chunk-ZEOQKRQ7.js +19 -0
  19. package/dist/form/index.cjs +301 -0
  20. package/dist/form/index.d.cts +86 -0
  21. package/dist/form/index.d.ts +86 -0
  22. package/dist/form/index.js +84 -0
  23. package/dist/index.cjs +1094 -293
  24. package/dist/index.d.cts +452 -37
  25. package/dist/index.d.ts +452 -37
  26. package/dist/index.js +963 -373
  27. package/dist/label-DuTvJGxD.d.cts +14 -0
  28. package/dist/label-DuTvJGxD.d.ts +14 -0
  29. package/dist/og/index.js +2 -1
  30. package/dist/shiki/index.js +2 -1
  31. package/dist/tema/index.cjs +94 -0
  32. package/dist/tema/index.d.cts +110 -0
  33. package/dist/tema/index.d.ts +110 -0
  34. package/dist/tema/index.js +2 -0
  35. package/dist/tokens/index.cjs +6 -0
  36. package/dist/tokens/index.d.cts +33 -1
  37. package/dist/tokens/index.d.ts +33 -1
  38. package/dist/tokens/index.js +3 -2
  39. package/dist/tokens/theme.css +43 -0
  40. package/llms.txt +351 -44
  41. package/package.json +31 -2
package/dist/index.js CHANGED
@@ -1,19 +1,30 @@
1
- export { tokens } from './chunk-VSMW2CT4.js';
2
- import { cn, CaraDeMascota, Mascota } from './chunk-ND45OQOC.js';
3
- export { CaraDeMascota, Isotipo, Logo, Mascota, cn } from './chunk-ND45OQOC.js';
1
+ export { tokens } from './chunk-VPT32GPG.js';
2
+ import { alternarTema, temaActual, escucharTema } from './chunk-KPZNNMV5.js';
3
+ export { TEMA_ATRIBUTO, TEMA_CLAVE, TEMA_EVENTO, alternarTema, aplicarTema, escucharTema, scriptTema, temaActual, temaGuardado, temaPreferido } from './chunk-KPZNNMV5.js';
4
+ import { CaraDeMascota, Mascota } from './chunk-YZ2SDOVZ.js';
5
+ export { CaraDeMascota, Isotipo, Logo, Mascota } from './chunk-YZ2SDOVZ.js';
4
6
  export { RUTA_ASSETS, aletas, caras, listaCaras, listaPoses, poses, usoDeCara } from './chunk-E3OMP2DL.js';
5
- import { __export, naming } from './chunk-I7GYZD2A.js';
6
- export { brand, colors, control, dark, fonts, gradient, light, limits, motion, naming, radius, shadow, sintaxis, size, spacing, tagline, typeScale } from './chunk-I7GYZD2A.js';
7
- import { cva } from 'class-variance-authority';
7
+ import { Label } from './chunk-ZEOQKRQ7.js';
8
+ export { Label } from './chunk-ZEOQKRQ7.js';
9
+ import { Text } from './chunk-UOWIDFCB.js';
10
+ export { Text, texto as textVariants } from './chunk-UOWIDFCB.js';
11
+ import { cn } from './chunk-NHS7ETKJ.js';
12
+ export { cn } from './chunk-NHS7ETKJ.js';
13
+ import { naming } from './chunk-TSPJOM6K.js';
14
+ export { brand, colors, control, dark, fonts, gradient, light, limits, motion, naming, radius, series, shadow, sintaxis, size, spacing, tagline, typeScale } from './chunk-TSPJOM6K.js';
15
+ import { __export } from './chunk-MLKGABMK.js';
16
+ import * as AccordionPrimitive from '@radix-ui/react-accordion';
8
17
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
9
- import * as AvatarPrimitive from '@radix-ui/react-avatar';
18
+ import { cva } from 'class-variance-authority';
19
+ import * as AlertDialogPrimitive from '@radix-ui/react-alert-dialog';
10
20
  import { Slot } from '@radix-ui/react-slot';
21
+ import * as AvatarPrimitive from '@radix-ui/react-avatar';
22
+ import { useId, useState, useEffect, useSyncExternalStore, useRef, useCallback } from 'react';
11
23
  import { es } from 'date-fns/locale';
12
24
  import { DayPicker } from 'react-day-picker';
13
25
  import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
14
26
  import * as DialogPrimitive from '@radix-ui/react-dialog';
15
27
  import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
16
- import * as LabelPrimitive from '@radix-ui/react-label';
17
28
  import * as PopoverPrimitive from '@radix-ui/react-popover';
18
29
  import * as ProgressPrimitive from '@radix-ui/react-progress';
19
30
  import * as RadioGroupPrimitive from '@radix-ui/react-radio-group';
@@ -23,8 +34,180 @@ import * as SwitchPrimitive from '@radix-ui/react-switch';
23
34
  import * as TabsPrimitive from '@radix-ui/react-tabs';
24
35
  import * as ToastPrimitive from '@radix-ui/react-toast';
25
36
  import * as TooltipPrimitive from '@radix-ui/react-tooltip';
26
- import { useRef, useState, useEffect, useCallback, useId } from 'react';
37
+ import { format } from 'date-fns';
27
38
 
39
+ function Glyph({ children, ...props }) {
40
+ return /* @__PURE__ */ jsx(
41
+ "svg",
42
+ {
43
+ viewBox: "0 0 16 16",
44
+ width: "1em",
45
+ height: "1em",
46
+ fill: "none",
47
+ stroke: "currentColor",
48
+ strokeWidth: 1.75,
49
+ strokeLinecap: "round",
50
+ strokeLinejoin: "round",
51
+ "aria-hidden": "true",
52
+ focusable: "false",
53
+ ...props,
54
+ children
55
+ }
56
+ );
57
+ }
58
+ var Check = (props) => /* @__PURE__ */ jsx(Glyph, { ...props, children: /* @__PURE__ */ jsx("path", { d: "M3 8.5 6.5 12 13 4.5" }) });
59
+ var Minus = (props) => /* @__PURE__ */ jsx(Glyph, { ...props, children: /* @__PURE__ */ jsx("path", { d: "M3.5 8h9" }) });
60
+ var ChevronDown = (props) => /* @__PURE__ */ jsx(Glyph, { ...props, children: /* @__PURE__ */ jsx("path", { d: "M4 6l4 4 4-4" }) });
61
+ var ChevronUp = (props) => /* @__PURE__ */ jsx(Glyph, { ...props, children: /* @__PURE__ */ jsx("path", { d: "M4 10l4-4 4 4" }) });
62
+ var ChevronLeft = (props) => /* @__PURE__ */ jsx(Glyph, { ...props, children: /* @__PURE__ */ jsx("path", { d: "M10 4L6 8l4 4" }) });
63
+ var ChevronRight = (props) => /* @__PURE__ */ jsx(Glyph, { ...props, children: /* @__PURE__ */ jsx("path", { d: "M6 4l4 4-4 4" }) });
64
+ var Close = (props) => /* @__PURE__ */ jsx(Glyph, { ...props, children: /* @__PURE__ */ jsx("path", { d: "M4 4l8 8M12 4l-8 8" }) });
65
+ var Copy = (props) => /* @__PURE__ */ jsxs(Glyph, { ...props, children: [
66
+ /* @__PURE__ */ jsx("rect", { x: "5.5", y: "5.5", width: "8", height: "8", rx: "1.5" }),
67
+ /* @__PURE__ */ jsx("path", { d: "M10.5 3.5h-7a1.5 1.5 0 0 0-1.5 1.5v7" })
68
+ ] });
69
+ var ArrowUpRight = (props) => /* @__PURE__ */ jsx(Glyph, { ...props, children: /* @__PURE__ */ jsx("path", { d: "M5 11l6-6M5.5 5h5.5v5.5" }) });
70
+ var Ellipsis = (props) => /* @__PURE__ */ jsx(Glyph, { ...props, strokeWidth: 2.25, children: /* @__PURE__ */ jsx("path", { d: "M4 8h.01M8 8h.01M12 8h.01" }) });
71
+ var Spinner = (props) => /* @__PURE__ */ jsxs(
72
+ "svg",
73
+ {
74
+ viewBox: "0 0 16 16",
75
+ width: "1em",
76
+ height: "1em",
77
+ fill: "none",
78
+ stroke: "currentColor",
79
+ strokeWidth: 2,
80
+ strokeLinecap: "round",
81
+ "aria-hidden": "true",
82
+ focusable: "false",
83
+ className: "motion-safe:animate-spin",
84
+ ...props,
85
+ children: [
86
+ /* @__PURE__ */ jsx("circle", { cx: "8", cy: "8", r: "6", opacity: 0.3 }),
87
+ /* @__PURE__ */ jsx("path", { d: "M8 2a6 6 0 0 1 6 6" })
88
+ ]
89
+ }
90
+ );
91
+ var Camara = (props) => /* @__PURE__ */ jsxs(Glyph, { ...props, children: [
92
+ /* @__PURE__ */ jsx("path", { d: "M2 5.5h2.6l1-1.5h4.8l1 1.5H14v7.5H2z" }),
93
+ /* @__PURE__ */ jsx("circle", { cx: "8", cy: "9", r: "2.4" })
94
+ ] });
95
+ var Sol = (props) => /* @__PURE__ */ jsxs(Glyph, { ...props, children: [
96
+ /* @__PURE__ */ jsx("circle", { cx: "8", cy: "8", r: "3" }),
97
+ /* @__PURE__ */ jsx("path", { d: "M8 1.5v1.2M8 13.3v1.2M14.5 8h-1.2M2.7 8H1.5M12.6 3.4l-.85.85M4.25 11.75l-.85.85M12.6 12.6l-.85-.85M4.25 4.25l-.85-.85" })
98
+ ] });
99
+ var Luna = (props) => /* @__PURE__ */ jsx(Glyph, { ...props, children: /* @__PURE__ */ jsx("path", { d: "M13.5 9.4A5.8 5.8 0 0 1 6.6 2.5a5.8 5.8 0 1 0 6.9 6.9Z" }) });
100
+ function GlifoMedia({ children, ...props }) {
101
+ return /* @__PURE__ */ jsx(
102
+ "svg",
103
+ {
104
+ xmlns: "http://www.w3.org/2000/svg",
105
+ viewBox: "0 0 24 24",
106
+ fill: "none",
107
+ "aria-hidden": "true",
108
+ focusable: "false",
109
+ ...props,
110
+ children
111
+ }
112
+ );
113
+ }
114
+ var Play = (props) => /* @__PURE__ */ jsx(GlifoMedia, { fill: "currentColor", ...props, children: /* @__PURE__ */ jsx("path", { d: "M8 5v14l11-7z" }) });
115
+ var Pause = (props) => /* @__PURE__ */ jsx(GlifoMedia, { fill: "currentColor", ...props, children: /* @__PURE__ */ jsx("path", { d: "M6 4h4v16H6V4zm8 0h4v16h-4V4z" }) });
116
+ var Retry = (props) => /* @__PURE__ */ jsx(
117
+ GlifoMedia,
118
+ {
119
+ stroke: "currentColor",
120
+ strokeWidth: 2,
121
+ strokeLinecap: "round",
122
+ strokeLinejoin: "round",
123
+ ...props,
124
+ children: /* @__PURE__ */ jsx("path", { d: "M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" })
125
+ }
126
+ );
127
+ var GoBackSeconds = (props) => /* @__PURE__ */ jsxs(GlifoMedia, { stroke: "currentColor", strokeWidth: 1.5, strokeLinecap: "round", ...props, children: [
128
+ /* @__PURE__ */ jsx("path", { d: "M16.5 8.5H13.8604C13.6452 8.5 13.4541 8.63772 13.386 8.84189L12.7194 10.8419C12.6114 11.1657 12.8524 11.5 13.1937 11.5H14.5C15.6046 11.5 16.5 12.3954 16.5 13.5C16.5 14.6046 15.6046 15.5 14.5 15.5H12.5" }),
129
+ /* @__PURE__ */ jsx("path", { d: "M7.5 10.5L10 8.5V15.5", strokeLinejoin: "round" }),
130
+ /* @__PURE__ */ jsx(
131
+ "path",
132
+ {
133
+ d: "M14 4.5L12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22C8.7288 22 5.82446 20.4293 4 18.001M8 2.83209C6.87754 3.32251 5.86251 4.01303 5 4.85857C3.14864 6.67349 2 9.20261 2 12C2 12.6849 2.06886 13.3538 2.20004 14",
134
+ strokeLinejoin: "round"
135
+ }
136
+ )
137
+ ] });
138
+ var AdvanceSeconds = (props) => /* @__PURE__ */ jsxs(GlifoMedia, { stroke: "currentColor", strokeWidth: 1.5, strokeLinecap: "round", ...props, children: [
139
+ /* @__PURE__ */ jsx("path", { d: "M16.5 8.5H13.8604C13.6452 8.5 13.4541 8.63772 13.386 8.84189L12.7194 10.8419C12.6114 11.1657 12.8524 11.5 13.1937 11.5H14.5C15.6046 11.5 16.5 12.3954 16.5 13.5C16.5 14.6046 15.6046 15.5 14.5 15.5H12.5" }),
140
+ /* @__PURE__ */ jsx("path", { d: "M7.5 10.5L10 8.5V15.5", strokeLinejoin: "round" }),
141
+ /* @__PURE__ */ jsx(
142
+ "path",
143
+ {
144
+ d: "M10 4.5L12 2C6.47715 2 2 6.47715 2 12C2 12.6849 2.06886 13.3538 2.20004 14M16 2.83209C19.5318 4.3752 22 7.89936 22 12C22 17.5228 17.5228 22 12 22C8.72852 22 5.82443 20.4287 4 18",
145
+ strokeLinejoin: "round"
146
+ }
147
+ )
148
+ ] });
149
+ var VolumeOn = (props) => /* @__PURE__ */ jsx(GlifoMedia, { fill: "currentColor", ...props, children: /* @__PURE__ */ jsx("path", { d: "M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z" }) });
150
+ var VolumeMuted = (props) => /* @__PURE__ */ jsx(GlifoMedia, { fill: "currentColor", ...props, children: /* @__PURE__ */ jsx("path", { d: "M16.5 12c0-1.77-1.02-3.29-2.5-4.03v2.21l2.45 2.45c.03-.2.05-.41.05-.63zm2.5 0c0 .94-.2 1.82-.54 2.64l1.51 1.51C20.63 14.91 21 13.5 21 12c0-4.28-2.99-7.86-7-8.77v2.06c2.89.86 5 3.54 5 6.71zM4.27 3L3 4.27 7.73 9H3v6h4l5 5v-6.73l4.25 4.25c-.67.52-1.42.93-2.25 1.18v2.06c1.38-.31 2.63-.95 3.69-1.81L19.73 21 21 19.73l-9-9L4.27 3zM12 4L9.91 6.09 12 8.18V4z" }) });
151
+ function Accordion({ className, ...props }) {
152
+ return /* @__PURE__ */ jsx(
153
+ AccordionPrimitive.Root,
154
+ {
155
+ className: cn("border-hairline w-full border-t", className),
156
+ ...props
157
+ }
158
+ );
159
+ }
160
+ function AccordionItem({
161
+ className,
162
+ ...props
163
+ }) {
164
+ return /* @__PURE__ */ jsx(AccordionPrimitive.Item, { className: cn("border-hairline border-b", className), ...props });
165
+ }
166
+ function AccordionTrigger({
167
+ className,
168
+ children,
169
+ headingLevel = 3,
170
+ ...props
171
+ }) {
172
+ const Encabezado = `h${headingLevel}`;
173
+ return /* @__PURE__ */ jsx(AccordionPrimitive.Header, { asChild: true, children: /* @__PURE__ */ jsx(Encabezado, { children: /* @__PURE__ */ jsxs(
174
+ AccordionPrimitive.Trigger,
175
+ {
176
+ className: cn(
177
+ "gap-step-sm py-step-sm flex w-full cursor-pointer items-center justify-between text-left",
178
+ "font-sans text-lead font-medium text-text-primary",
179
+ "transition-standard",
180
+ "hover:text-accent",
181
+ "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent",
182
+ "disabled:pointer-events-none disabled:opacity-50",
183
+ "[&[data-state=open]>svg]:rotate-180",
184
+ className
185
+ ),
186
+ ...props,
187
+ children: [
188
+ children,
189
+ /* @__PURE__ */ jsx(ChevronDown, { className: "text-text-muted shrink-0" })
190
+ ]
191
+ }
192
+ ) }) });
193
+ }
194
+ function AccordionContent({
195
+ className,
196
+ children,
197
+ ...props
198
+ }) {
199
+ return /* @__PURE__ */ jsx(
200
+ AccordionPrimitive.Content,
201
+ {
202
+ className: cn(
203
+ "overflow-hidden",
204
+ "motion-safe:data-[state=open]:desplegar motion-safe:data-[state=closed]:replegar"
205
+ ),
206
+ ...props,
207
+ children: /* @__PURE__ */ jsx("div", { className: cn("pb-step-md font-sans text-ui text-text-secondary max-w-measure", className), children })
208
+ }
209
+ );
210
+ }
28
211
  var alert = cva("w-full rounded-card border p-step-md font-sans text-ui", {
29
212
  variants: {
30
213
  variant: {
@@ -95,273 +278,329 @@ function Alert({
95
278
  }
96
279
  );
97
280
  }
98
- var avatar = cva(
99
- "relative flex shrink-0 overflow-hidden rounded-pill bg-surface-raised border border-hairline",
281
+ var button = cva(
282
+ [
283
+ "inline-flex cursor-pointer items-center justify-center gap-step-xs whitespace-nowrap select-none",
284
+ "rounded-control font-sans font-medium",
285
+ "transition-standard",
286
+ "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent",
287
+ "disabled:pointer-events-none disabled:opacity-50",
288
+ "[&_svg]:shrink-0"
289
+ ],
100
290
  {
101
291
  variants: {
292
+ variant: {
293
+ primary: [
294
+ "bg-accent text-accent-on hover:bg-accent-hover",
295
+ "light:bg-brand-hull light:text-accent-on light:hover:bg-text-secondary"
296
+ ],
297
+ conversion: "bg-warm text-warm-on hover:bg-warm-hover",
298
+ secondary: [
299
+ "border-hairline-hover border bg-transparent text-text-primary",
300
+ "hover:border-accent hover:text-accent"
301
+ ],
302
+ tertiary: [
303
+ "bg-transparent font-mono font-normal text-text-secondary",
304
+ "hover:text-accent hover:underline hover:underline-offset-4"
305
+ ]
306
+ },
102
307
  size: {
103
- sm: "size-8",
104
- md: "size-10",
105
- lg: "size-14",
106
- xl: "size-24"
308
+ sm: "h-8 px-control-sm text-label",
309
+ md: "h-10 px-control-md text-ui",
310
+ lg: "h-12 px-control-lg text-lead",
311
+ /** Cuadrado 42×42, sin texto. Lleva `aria-label` obligatorio. */
312
+ icon: "size-control-icon p-0"
107
313
  }
108
314
  },
109
- defaultVariants: { size: "md" }
315
+ compoundVariants: [
316
+ /**
317
+ * El terciario no tiene caja: ni padding horizontal ni alto de control.
318
+ * Va aquí y no como `px-0` en la variante para que gane al `px-*` del
319
+ * tamaño sin depender del orden en que cva concatena las clases.
320
+ */
321
+ { variant: "tertiary", size: ["sm", "md", "lg"], class: "h-auto px-0" }
322
+ ],
323
+ defaultVariants: { variant: "primary", size: "md" }
110
324
  }
111
325
  );
112
- function Avatar({ className, size: size2, ...props }) {
113
- return /* @__PURE__ */ jsx(AvatarPrimitive.Root, { className: cn(avatar({ size: size2 }), className), ...props });
114
- }
115
- function AvatarImage({
326
+ function Button({
116
327
  className,
328
+ variant,
329
+ size: size2,
330
+ asChild = false,
331
+ loading = false,
332
+ icon,
333
+ children,
334
+ disabled,
117
335
  ...props
118
336
  }) {
119
- return /* @__PURE__ */ jsx(AvatarPrimitive.Image, { className: cn("aspect-square size-full object-cover", className), ...props });
337
+ if (asChild) {
338
+ return /* @__PURE__ */ jsx(Slot, { className: cn(button({ variant, size: size2 }), className), ...props, children });
339
+ }
340
+ return /* @__PURE__ */ jsxs(
341
+ "button",
342
+ {
343
+ className: cn(button({ variant, size: size2 }), className),
344
+ disabled: disabled === true || loading,
345
+ "aria-busy": loading || void 0,
346
+ ...props,
347
+ children: [
348
+ loading ? /* @__PURE__ */ jsx(Spinner, {}) : icon,
349
+ children
350
+ ]
351
+ }
352
+ );
120
353
  }
121
- function AvatarFallback({
354
+ var AlertDialog = AlertDialogPrimitive.Root;
355
+ var AlertDialogTrigger = AlertDialogPrimitive.Trigger;
356
+ function AlertDialogOverlay({
122
357
  className,
123
358
  ...props
124
359
  }) {
125
360
  return /* @__PURE__ */ jsx(
126
- AvatarPrimitive.Fallback,
361
+ AlertDialogPrimitive.Overlay,
127
362
  {
128
- className: cn(
129
- "text-label font-mono text-text-secondary flex size-full items-center justify-center uppercase",
130
- className
131
- ),
363
+ className: cn("bg-brand-hull/70 fixed inset-0 z-50", className),
132
364
  ...props
133
365
  }
134
366
  );
135
367
  }
136
- var badge = cva(
137
- ["inline-flex items-center gap-step-xs", "rounded-chip px-step-xs py-0.5", "font-sans text-tag", "transition-standard"],
138
- {
139
- variants: {
140
- variant: {
141
- neutral: "bg-surface-raised text-text-secondary",
142
- accent: "bg-accent/8 text-text-primary",
143
- warm: "bg-warm/8 text-text-primary",
144
- success: "bg-success/8 text-text-primary",
145
- warning: "bg-warning/8 text-text-primary",
146
- error: "bg-error/8 text-text-primary"
368
+ function AlertDialogContent({
369
+ className,
370
+ children,
371
+ ...props
372
+ }) {
373
+ return /* @__PURE__ */ jsxs(AlertDialogPrimitive.Portal, { children: [
374
+ /* @__PURE__ */ jsx(AlertDialogOverlay, {}),
375
+ /* @__PURE__ */ jsx(
376
+ AlertDialogPrimitive.Content,
377
+ {
378
+ className: cn(
379
+ "fixed top-1/2 left-1/2 z-50 w-full max-w-content -translate-x-1/2 -translate-y-1/2",
380
+ "gap-step-md p-step-lg flex flex-col",
381
+ "rounded-panel border-border bg-surface shadow-standard border",
382
+ "text-text-primary font-sans",
383
+ className
384
+ ),
385
+ ...props,
386
+ children
147
387
  }
148
- },
149
- defaultVariants: { variant: "neutral" }
150
- }
151
- );
152
- function Badge({ className, variant, ...props }) {
153
- return /* @__PURE__ */ jsx("span", { className: cn(badge({ variant }), className), ...props });
388
+ )
389
+ ] });
154
390
  }
155
- var categoria = cva(
156
- [
157
- "inline-flex items-center gap-step-xs",
158
- "rounded-pill px-step-sm py-0.5",
159
- "font-mono text-chip",
160
- "border transition-standard"
161
- ],
162
- {
163
- variants: {
164
- active: {
165
- false: "border-warm/28 bg-transparent text-warm",
166
- true: "border-warm bg-warm text-warm-on"
167
- }
168
- },
169
- defaultVariants: { active: false }
170
- }
171
- );
172
- function CategoryBadge({ className, active = false, ...props }) {
391
+ function AlertDialogHeader({ className, ...props }) {
392
+ return /* @__PURE__ */ jsx("div", { className: cn("gap-step-xs flex flex-col", className), ...props });
393
+ }
394
+ function AlertDialogFooter({ className, ...props }) {
173
395
  return /* @__PURE__ */ jsx(
174
- "span",
396
+ "div",
175
397
  {
176
- "data-active": active || void 0,
177
- className: cn(categoria({ active }), className),
398
+ className: cn("gap-step-sm flex flex-col-reverse sm:flex-row sm:justify-end", className),
178
399
  ...props
179
400
  }
180
401
  );
181
402
  }
182
- var metrica = ["inline-flex items-center gap-step-xs", "rounded-pill", "font-mono text-chip text-text-muted"];
183
- function MetricBadge({ className, boxed = false, ...props }) {
403
+ function AlertDialogTitle({
404
+ className,
405
+ ...props
406
+ }) {
184
407
  return /* @__PURE__ */ jsx(
185
- "span",
408
+ AlertDialogPrimitive.Title,
186
409
  {
187
- className: cn(metrica, boxed && "border-hairline px-step-sm py-0.5 border", className),
410
+ className: cn("text-h3 font-display text-text-primary", className),
188
411
  ...props
189
412
  }
190
413
  );
191
414
  }
192
- function Glyph({ children, ...props }) {
415
+ function AlertDialogDescription({
416
+ className,
417
+ ...props
418
+ }) {
193
419
  return /* @__PURE__ */ jsx(
194
- "svg",
420
+ AlertDialogPrimitive.Description,
195
421
  {
196
- viewBox: "0 0 16 16",
197
- width: "1em",
198
- height: "1em",
199
- fill: "none",
200
- stroke: "currentColor",
201
- strokeWidth: 1.75,
202
- strokeLinecap: "round",
203
- strokeLinejoin: "round",
204
- "aria-hidden": "true",
205
- focusable: "false",
206
- ...props,
207
- children
422
+ className: cn("text-ui text-text-secondary max-w-measure", className),
423
+ ...props
208
424
  }
209
425
  );
210
426
  }
211
- var Check = (props) => /* @__PURE__ */ jsx(Glyph, { ...props, children: /* @__PURE__ */ jsx("path", { d: "M3 8.5 6.5 12 13 4.5" }) });
212
- var Minus = (props) => /* @__PURE__ */ jsx(Glyph, { ...props, children: /* @__PURE__ */ jsx("path", { d: "M3.5 8h9" }) });
213
- var ChevronDown = (props) => /* @__PURE__ */ jsx(Glyph, { ...props, children: /* @__PURE__ */ jsx("path", { d: "M4 6l4 4 4-4" }) });
214
- var ChevronUp = (props) => /* @__PURE__ */ jsx(Glyph, { ...props, children: /* @__PURE__ */ jsx("path", { d: "M4 10l4-4 4 4" }) });
215
- var ChevronLeft = (props) => /* @__PURE__ */ jsx(Glyph, { ...props, children: /* @__PURE__ */ jsx("path", { d: "M10 4L6 8l4 4" }) });
216
- var ChevronRight = (props) => /* @__PURE__ */ jsx(Glyph, { ...props, children: /* @__PURE__ */ jsx("path", { d: "M6 4l4 4-4 4" }) });
217
- var Close = (props) => /* @__PURE__ */ jsx(Glyph, { ...props, children: /* @__PURE__ */ jsx("path", { d: "M4 4l8 8M12 4l-8 8" }) });
218
- var Copy = (props) => /* @__PURE__ */ jsxs(Glyph, { ...props, children: [
219
- /* @__PURE__ */ jsx("rect", { x: "5.5", y: "5.5", width: "8", height: "8", rx: "1.5" }),
220
- /* @__PURE__ */ jsx("path", { d: "M10.5 3.5h-7a1.5 1.5 0 0 0-1.5 1.5v7" })
221
- ] });
222
- var ArrowUpRight = (props) => /* @__PURE__ */ jsx(Glyph, { ...props, children: /* @__PURE__ */ jsx("path", { d: "M5 11l6-6M5.5 5h5.5v5.5" }) });
223
- var Ellipsis = (props) => /* @__PURE__ */ jsx(Glyph, { ...props, strokeWidth: 2.25, children: /* @__PURE__ */ jsx("path", { d: "M4 8h.01M8 8h.01M12 8h.01" }) });
224
- var Spinner = (props) => /* @__PURE__ */ jsxs(
225
- "svg",
226
- {
227
- viewBox: "0 0 16 16",
228
- width: "1em",
229
- height: "1em",
230
- fill: "none",
231
- stroke: "currentColor",
232
- strokeWidth: 2,
233
- strokeLinecap: "round",
234
- "aria-hidden": "true",
235
- focusable: "false",
236
- className: "motion-safe:animate-spin",
237
- ...props,
238
- children: [
239
- /* @__PURE__ */ jsx("circle", { cx: "8", cy: "8", r: "6", opacity: 0.3 }),
240
- /* @__PURE__ */ jsx("path", { d: "M8 2a6 6 0 0 1 6 6" })
241
- ]
242
- }
243
- );
244
- function GlifoMedia({ children, ...props }) {
427
+ function AlertDialogCancel({
428
+ className,
429
+ ...props
430
+ }) {
245
431
  return /* @__PURE__ */ jsx(
246
- "svg",
432
+ AlertDialogPrimitive.Cancel,
247
433
  {
248
- xmlns: "http://www.w3.org/2000/svg",
249
- viewBox: "0 0 24 24",
250
- fill: "none",
251
- "aria-hidden": "true",
252
- focusable: "false",
253
- ...props,
254
- children
434
+ className: cn(button({ variant: "secondary" }), className),
435
+ ...props
255
436
  }
256
437
  );
257
438
  }
258
- var Play = (props) => /* @__PURE__ */ jsx(GlifoMedia, { fill: "currentColor", ...props, children: /* @__PURE__ */ jsx("path", { d: "M8 5v14l11-7z" }) });
259
- var Pause = (props) => /* @__PURE__ */ jsx(GlifoMedia, { fill: "currentColor", ...props, children: /* @__PURE__ */ jsx("path", { d: "M6 4h4v16H6V4zm8 0h4v16h-4V4z" }) });
260
- var Retry = (props) => /* @__PURE__ */ jsx(
261
- GlifoMedia,
439
+ function AlertDialogAction({
440
+ className,
441
+ ...props
442
+ }) {
443
+ return /* @__PURE__ */ jsx(
444
+ AlertDialogPrimitive.Action,
445
+ {
446
+ className: cn(button({ variant: "primary" }), className),
447
+ ...props
448
+ }
449
+ );
450
+ }
451
+ var avatar = cva(
452
+ "relative flex shrink-0 overflow-hidden rounded-pill bg-surface-raised border border-hairline",
262
453
  {
263
- stroke: "currentColor",
264
- strokeWidth: 2,
265
- strokeLinecap: "round",
266
- strokeLinejoin: "round",
267
- ...props,
268
- children: /* @__PURE__ */ jsx("path", { d: "M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" })
454
+ variants: {
455
+ size: {
456
+ sm: "size-8",
457
+ md: "size-10",
458
+ lg: "size-14",
459
+ xl: "size-24"
460
+ }
461
+ },
462
+ defaultVariants: { size: "md" }
269
463
  }
270
464
  );
271
- var GoBackSeconds = (props) => /* @__PURE__ */ jsxs(GlifoMedia, { stroke: "currentColor", strokeWidth: 1.5, strokeLinecap: "round", ...props, children: [
272
- /* @__PURE__ */ jsx("path", { d: "M16.5 8.5H13.8604C13.6452 8.5 13.4541 8.63772 13.386 8.84189L12.7194 10.8419C12.6114 11.1657 12.8524 11.5 13.1937 11.5H14.5C15.6046 11.5 16.5 12.3954 16.5 13.5C16.5 14.6046 15.6046 15.5 14.5 15.5H12.5" }),
273
- /* @__PURE__ */ jsx("path", { d: "M7.5 10.5L10 8.5V15.5", strokeLinejoin: "round" }),
274
- /* @__PURE__ */ jsx(
275
- "path",
276
- {
277
- d: "M14 4.5L12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22C8.7288 22 5.82446 20.4293 4 18.001M8 2.83209C6.87754 3.32251 5.86251 4.01303 5 4.85857C3.14864 6.67349 2 9.20261 2 12C2 12.6849 2.06886 13.3538 2.20004 14",
278
- strokeLinejoin: "round"
279
- }
280
- )
281
- ] });
282
- var AdvanceSeconds = (props) => /* @__PURE__ */ jsxs(GlifoMedia, { stroke: "currentColor", strokeWidth: 1.5, strokeLinecap: "round", ...props, children: [
283
- /* @__PURE__ */ jsx("path", { d: "M16.5 8.5H13.8604C13.6452 8.5 13.4541 8.63772 13.386 8.84189L12.7194 10.8419C12.6114 11.1657 12.8524 11.5 13.1937 11.5H14.5C15.6046 11.5 16.5 12.3954 16.5 13.5C16.5 14.6046 15.6046 15.5 14.5 15.5H12.5" }),
284
- /* @__PURE__ */ jsx("path", { d: "M7.5 10.5L10 8.5V15.5", strokeLinejoin: "round" }),
285
- /* @__PURE__ */ jsx(
286
- "path",
465
+ function Avatar({ className, size: size2, ...props }) {
466
+ return /* @__PURE__ */ jsx(AvatarPrimitive.Root, { className: cn(avatar({ size: size2 }), className), ...props });
467
+ }
468
+ function AvatarImage({
469
+ className,
470
+ ...props
471
+ }) {
472
+ return /* @__PURE__ */ jsx(AvatarPrimitive.Image, { className: cn("aspect-square size-full object-cover", className), ...props });
473
+ }
474
+ function AvatarFallback({
475
+ className,
476
+ ...props
477
+ }) {
478
+ return /* @__PURE__ */ jsx(
479
+ AvatarPrimitive.Fallback,
287
480
  {
288
- d: "M10 4.5L12 2C6.47715 2 2 6.47715 2 12C2 12.6849 2.06886 13.3538 2.20004 14M16 2.83209C19.5318 4.3752 22 7.89936 22 12C22 17.5228 17.5228 22 12 22C8.72852 22 5.82443 20.4287 4 18",
289
- strokeLinejoin: "round"
481
+ className: cn(
482
+ "text-label font-mono text-text-secondary flex size-full items-center justify-center uppercase",
483
+ className
484
+ ),
485
+ ...props
290
486
  }
291
- )
292
- ] });
293
- var VolumeOn = (props) => /* @__PURE__ */ jsx(GlifoMedia, { fill: "currentColor", ...props, children: /* @__PURE__ */ jsx("path", { d: "M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z" }) });
294
- var VolumeMuted = (props) => /* @__PURE__ */ jsx(GlifoMedia, { fill: "currentColor", ...props, children: /* @__PURE__ */ jsx("path", { d: "M16.5 12c0-1.77-1.02-3.29-2.5-4.03v2.21l2.45 2.45c.03-.2.05-.41.05-.63zm2.5 0c0 .94-.2 1.82-.54 2.64l1.51 1.51C20.63 14.91 21 13.5 21 12c0-4.28-2.99-7.86-7-8.77v2.06c2.89.86 5 3.54 5 6.71zM4.27 3L3 4.27 7.73 9H3v6h4l5 5v-6.73l4.25 4.25c-.67.52-1.42.93-2.25 1.18v2.06c1.38-.31 2.63-.95 3.69-1.81L19.73 21 21 19.73l-9-9L4.27 3zM12 4L9.91 6.09 12 8.18V4z" }) });
295
- var button = cva(
296
- [
297
- "inline-flex cursor-pointer items-center justify-center gap-step-xs whitespace-nowrap select-none",
298
- "rounded-control font-sans font-medium",
299
- "transition-standard",
300
- "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent",
301
- "disabled:pointer-events-none disabled:opacity-50",
302
- "[&_svg]:shrink-0"
303
- ],
487
+ );
488
+ }
489
+ function AvatarUpload({
490
+ src,
491
+ fallback,
492
+ onSelectFile,
493
+ accept = "image/*",
494
+ label = "Cambiar la foto",
495
+ size: size2,
496
+ disabled = false,
497
+ className,
498
+ ...props
499
+ }) {
500
+ const id = useId();
501
+ const [previa, setPrevia] = useState(null);
502
+ useEffect(() => {
503
+ if (!previa) return;
504
+ return () => URL.revokeObjectURL(previa);
505
+ }, [previa]);
506
+ function elegir(evento) {
507
+ const archivo = evento.target.files?.[0];
508
+ if (!archivo) return;
509
+ setPrevia(URL.createObjectURL(archivo));
510
+ onSelectFile?.(archivo);
511
+ evento.target.value = "";
512
+ }
513
+ const imagen = previa ?? src;
514
+ return /* @__PURE__ */ jsxs("div", { className: cn("relative inline-flex", className), ...props, children: [
515
+ /* @__PURE__ */ jsxs(Avatar, { size: size2, children: [
516
+ imagen ? /* @__PURE__ */ jsx(AvatarImage, { src: imagen, alt: "" }) : null,
517
+ /* @__PURE__ */ jsx(AvatarFallback, { children: fallback })
518
+ ] }),
519
+ /* @__PURE__ */ jsxs(
520
+ "label",
521
+ {
522
+ htmlFor: id,
523
+ className: cn(
524
+ "rounded-pill absolute -right-1 -bottom-1 flex size-6 cursor-pointer items-center justify-center",
525
+ "border-hairline bg-surface-raised text-text-secondary border",
526
+ "transition-standard hover:text-accent hover:border-accent",
527
+ // El foco vive en el input, que está oculto: sin esto, tabular hasta
528
+ // el control no se ve por ninguna parte.
529
+ "has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-accent",
530
+ disabled && "pointer-events-none opacity-50"
531
+ ),
532
+ children: [
533
+ /* @__PURE__ */ jsx(Camara, { "aria-hidden": "true" }),
534
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: label }),
535
+ /* @__PURE__ */ jsx(
536
+ "input",
537
+ {
538
+ id,
539
+ type: "file",
540
+ accept,
541
+ disabled,
542
+ onChange: elegir,
543
+ className: "sr-only"
544
+ }
545
+ )
546
+ ]
547
+ }
548
+ )
549
+ ] });
550
+ }
551
+ var badge = cva(
552
+ ["inline-flex items-center gap-step-xs", "rounded-chip px-step-xs py-0.5", "font-sans text-tag", "transition-standard"],
304
553
  {
305
554
  variants: {
306
555
  variant: {
307
- primary: [
308
- "bg-accent text-accent-on hover:bg-accent-hover",
309
- "light:bg-brand-hull light:text-accent-on light:hover:bg-text-secondary"
310
- ],
311
- conversion: "bg-warm text-warm-on hover:bg-warm-hover",
312
- secondary: [
313
- "border-hairline-hover border bg-transparent text-text-primary",
314
- "hover:border-accent hover:text-accent"
315
- ],
316
- tertiary: [
317
- "bg-transparent font-mono font-normal text-text-secondary",
318
- "hover:text-accent hover:underline hover:underline-offset-4"
319
- ]
320
- },
321
- size: {
322
- sm: "h-8 px-control-sm text-label",
323
- md: "h-10 px-control-md text-ui",
324
- lg: "h-12 px-control-lg text-lead",
325
- /** Cuadrado 42×42, sin texto. Lleva `aria-label` obligatorio. */
326
- icon: "size-control-icon p-0"
556
+ neutral: "bg-surface-raised text-text-secondary",
557
+ accent: "bg-accent/8 text-text-primary",
558
+ warm: "bg-warm/8 text-text-primary",
559
+ success: "bg-success/8 text-text-primary",
560
+ warning: "bg-warning/8 text-text-primary",
561
+ error: "bg-error/8 text-text-primary"
327
562
  }
328
563
  },
329
- compoundVariants: [
330
- /**
331
- * El terciario no tiene caja: ni padding horizontal ni alto de control.
332
- * Va aquí y no como `px-0` en la variante para que gane al `px-*` del
333
- * tamaño sin depender del orden en que cva concatena las clases.
334
- */
335
- { variant: "tertiary", size: ["sm", "md", "lg"], class: "h-auto px-0" }
336
- ],
337
- defaultVariants: { variant: "primary", size: "md" }
564
+ defaultVariants: { variant: "neutral" }
338
565
  }
339
566
  );
340
- function Button({
341
- className,
342
- variant,
343
- size: size2,
344
- asChild = false,
345
- loading = false,
346
- icon,
347
- children,
348
- disabled,
349
- ...props
350
- }) {
351
- if (asChild) {
352
- return /* @__PURE__ */ jsx(Slot, { className: cn(button({ variant, size: size2 }), className), ...props, children });
567
+ function Badge({ className, variant, ...props }) {
568
+ return /* @__PURE__ */ jsx("span", { className: cn(badge({ variant }), className), ...props });
569
+ }
570
+ var categoria = cva(
571
+ [
572
+ "inline-flex items-center gap-step-xs",
573
+ "rounded-pill px-step-sm py-0.5",
574
+ "font-mono text-chip",
575
+ "border transition-standard"
576
+ ],
577
+ {
578
+ variants: {
579
+ active: {
580
+ false: "border-warm/28 bg-transparent text-warm",
581
+ true: "border-warm bg-warm text-warm-on"
582
+ }
583
+ },
584
+ defaultVariants: { active: false }
353
585
  }
354
- return /* @__PURE__ */ jsxs(
355
- "button",
586
+ );
587
+ function CategoryBadge({ className, active = false, ...props }) {
588
+ return /* @__PURE__ */ jsx(
589
+ "span",
356
590
  {
357
- className: cn(button({ variant, size: size2 }), className),
358
- disabled: disabled === true || loading,
359
- "aria-busy": loading || void 0,
360
- ...props,
361
- children: [
362
- loading ? /* @__PURE__ */ jsx(Spinner, {}) : icon,
363
- children
364
- ]
591
+ "data-active": active || void 0,
592
+ className: cn(categoria({ active }), className),
593
+ ...props
594
+ }
595
+ );
596
+ }
597
+ var metrica = ["inline-flex items-center gap-step-xs", "rounded-pill", "font-mono text-chip text-text-muted"];
598
+ function MetricBadge({ className, boxed = false, ...props }) {
599
+ return /* @__PURE__ */ jsx(
600
+ "span",
601
+ {
602
+ className: cn(metrica, boxed && "border-hairline px-step-sm py-0.5 border", className),
603
+ ...props
365
604
  }
366
605
  );
367
606
  }
@@ -442,80 +681,6 @@ function Calendar({
442
681
  }
443
682
  );
444
683
  }
445
- var ETIQUETA = {
446
- display: "h1",
447
- stat: "p",
448
- h1: "h1",
449
- h2: "h2",
450
- h3: "h3",
451
- body: "p",
452
- lead: "p",
453
- ui: "p",
454
- label: "span",
455
- tag: "span",
456
- meta: "p",
457
- chip: "span",
458
- eyebrow: "p"
459
- };
460
- var texto = cva("", {
461
- variants: {
462
- variant: {
463
- display: "text-display font-display",
464
- // Métricas grandes: 46px de display. Es la única escala pensada para un
465
- // número, y por eso el interlineado es 1.
466
- stat: "text-stat font-display",
467
- h1: "text-h1 font-display",
468
- h2: "text-h2 font-display",
469
- h3: "text-h3 font-display",
470
- body: "text-body font-sans",
471
- // 17px: la bajada de las páginas internas y el botón grande.
472
- lead: "text-lead font-sans",
473
- ui: "text-ui font-sans",
474
- label: "text-label font-sans",
475
- // Las dos escalas de etiqueta. `tag` es el estado (sans 12.5/500) y `chip`
476
- // la categoría y la métrica (mono 11.5). Ninguna transforma el texto.
477
- tag: "text-tag font-sans",
478
- chip: "text-chip font-mono",
479
- // Mono SIN transformar: fechas, rutas, versiones, nombres de archivo y la
480
- // firma del footer. Es el escalón que faltaba, y por el que cada sitio de
481
- // uso terminaba escribiendo `variant="eyebrow" className="normal-case"`.
482
- meta: "text-meta font-mono",
483
- // `uppercase` no cabe en un token de tamaño: text-transform no es un
484
- // modificador de --text-*. Por eso lo pone la variante y no theme.css.
485
- eyebrow: "text-eyebrow font-mono uppercase"
486
- },
487
- tone: {
488
- primary: "text-text-primary",
489
- secondary: "text-text-secondary",
490
- muted: "text-text-muted",
491
- accent: "text-accent",
492
- warm: "text-warm",
493
- success: "text-success",
494
- warning: "text-warning",
495
- error: "text-error"
496
- }
497
- },
498
- defaultVariants: { variant: "body", tone: "primary" }
499
- });
500
- function Text({
501
- className,
502
- variant,
503
- tone,
504
- as,
505
- asChild = false,
506
- measure,
507
- children,
508
- ...props
509
- }) {
510
- const escala = variant ?? "body";
511
- const limitar = measure ?? escala === "body";
512
- const clases = cn(texto({ variant, tone }), limitar && "max-w-measure", className);
513
- if (asChild) {
514
- return /* @__PURE__ */ jsx(Slot, { className: clases, ...props, children });
515
- }
516
- const Etiqueta = as ?? ETIQUETA[escala];
517
- return /* @__PURE__ */ jsx(Etiqueta, { className: clases, ...props, children });
518
- }
519
684
  var SUPERFICIE_TARJETA = "rounded-card border-hairline bg-surface border";
520
685
  var HOVER_TARJETA = "transition-standard hover:border-hairline-hover";
521
686
  function Card({ className, ...props }) {
@@ -806,19 +971,6 @@ function Input({ className, invalid = false, ...props }) {
806
971
  }
807
972
  );
808
973
  }
809
- function Label2({ className, ...props }) {
810
- return /* @__PURE__ */ jsx(
811
- LabelPrimitive.Root,
812
- {
813
- className: cn(
814
- "text-label font-sans text-text-secondary select-none",
815
- "peer-disabled:opacity-50 group-data-[disabled]:opacity-50",
816
- className
817
- ),
818
- ...props
819
- }
820
- );
821
- }
822
974
  function Pagination({ className, ...props }) {
823
975
  return /* @__PURE__ */ jsx(
824
976
  "nav",
@@ -1400,6 +1552,76 @@ function ToastDescription({
1400
1552
  }) {
1401
1553
  return /* @__PURE__ */ jsx(ToastPrimitive.Description, { className: cn("max-w-measure", className), ...props });
1402
1554
  }
1555
+ var avisos = [];
1556
+ var suscriptores = /* @__PURE__ */ new Set();
1557
+ var contador = 0;
1558
+ function emitir(siguientes) {
1559
+ avisos = siguientes;
1560
+ for (const avisar of suscriptores) avisar();
1561
+ }
1562
+ var suscribirse = (avisar) => {
1563
+ suscriptores.add(avisar);
1564
+ return () => {
1565
+ suscriptores.delete(avisar);
1566
+ };
1567
+ };
1568
+ var leer = () => avisos;
1569
+ var VACIO = [];
1570
+ var enServidor = () => VACIO;
1571
+ function crear(mensaje, opciones = {}) {
1572
+ contador += 1;
1573
+ const id = `arrecife-toast-${contador}`;
1574
+ const { description, ...resto } = opciones;
1575
+ emitir([
1576
+ ...avisos,
1577
+ {
1578
+ ...resto,
1579
+ // El primer argumento es la línea principal. Si además llega `title`, el
1580
+ // mensaje pasa a ser la descripción: así `toast('Guardado')` y
1581
+ // `toast('No se pudo guardar', { title: 'Error' })` se leen igual de bien.
1582
+ ...opciones.title ? { description: description ?? mensaje } : { title: mensaje, ...description === void 0 ? {} : { description } },
1583
+ id,
1584
+ abierto: true
1585
+ }
1586
+ ]);
1587
+ return id;
1588
+ }
1589
+ function descartar(id) {
1590
+ emitir(avisos.map((a) => id === void 0 || a.id === id ? { ...a, abierto: false } : a));
1591
+ }
1592
+ function retirar(id) {
1593
+ emitir(avisos.filter((a) => a.id !== id));
1594
+ }
1595
+ var toast2 = Object.assign(crear, {
1596
+ success: (mensaje, opciones = {}) => crear(mensaje, { ...opciones, variant: "success" }),
1597
+ error: (mensaje, opciones = {}) => crear(mensaje, { ...opciones, variant: "error" }),
1598
+ dismiss: descartar
1599
+ });
1600
+ function Toaster({ duration = 5e3, label = "Avisos" }) {
1601
+ const lista = useSyncExternalStore(suscribirse, leer, enServidor);
1602
+ return /* @__PURE__ */ jsxs(ToastProvider, { duration, label, children: [
1603
+ lista.map(({ id, title, description, variant, duration: propio, action, abierto }) => /* @__PURE__ */ jsxs(
1604
+ Toast,
1605
+ {
1606
+ open: abierto,
1607
+ variant: variant ?? "neutral",
1608
+ ...propio === void 0 ? {} : { duration: propio },
1609
+ onOpenChange: (sigue) => {
1610
+ if (!sigue) retirar(id);
1611
+ },
1612
+ children: [
1613
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
1614
+ title ? /* @__PURE__ */ jsx(ToastTitle, { children: title }) : null,
1615
+ description ? /* @__PURE__ */ jsx(ToastDescription, { children: description }) : null
1616
+ ] }),
1617
+ action
1618
+ ]
1619
+ },
1620
+ id
1621
+ )),
1622
+ /* @__PURE__ */ jsx(ToastViewport, {})
1623
+ ] });
1624
+ }
1403
1625
  var TooltipProvider = TooltipPrimitive.Provider;
1404
1626
  var Tooltip = TooltipPrimitive.Root;
1405
1627
  var TooltipTrigger = TooltipPrimitive.Trigger;
@@ -1439,6 +1661,7 @@ function ArticleCard({
1439
1661
  dateTime,
1440
1662
  readingMinutes,
1441
1663
  tags,
1664
+ headingLevel = 3,
1442
1665
  className,
1443
1666
  ...props
1444
1667
  }) {
@@ -1454,7 +1677,15 @@ function ArticleCard({
1454
1677
  i > 0 ? /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\xB7" }) : null,
1455
1678
  m
1456
1679
  ] }, i)) }) : null,
1457
- /* @__PURE__ */ jsx(Text, { as: "h3", variant: "h3", className: "group-hover:text-accent transition-standard", children: title }),
1680
+ /* @__PURE__ */ jsx(
1681
+ Text,
1682
+ {
1683
+ as: headingLevel === 2 ? "h2" : "h3",
1684
+ variant: "h3",
1685
+ className: "group-hover:text-accent transition-standard",
1686
+ children: title
1687
+ }
1688
+ ),
1458
1689
  excerpt ? /* @__PURE__ */ jsx(Text, { variant: "ui", tone: "secondary", className: "line-clamp-2", children: excerpt }) : null,
1459
1690
  tags && tags.length > 0 ? /* @__PURE__ */ jsx("div", { className: "gap-step-xs mt-auto flex flex-wrap pt-step-sm", children: tags.map((t) => /* @__PURE__ */ jsx(CategoryBadge, { children: t }, t)) }) : null
1460
1691
  ] }) });
@@ -2158,40 +2389,231 @@ function EmptyState({
2158
2389
  }
2159
2390
  );
2160
2391
  }
2392
+ var mismoDia = (a, b) => a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
2393
+ function aValorDeCampo(fecha) {
2394
+ const dos = (n) => String(n).padStart(2, "0");
2395
+ return `${fecha.getFullYear()}-${dos(fecha.getMonth() + 1)}-${dos(fecha.getDate())}T${dos(
2396
+ fecha.getHours()
2397
+ )}:${dos(fecha.getMinutes())}`;
2398
+ }
2399
+ function EventCalendar({
2400
+ events,
2401
+ onCreateEvent,
2402
+ onUpdateEvent,
2403
+ onDeleteEvent,
2404
+ selected,
2405
+ onSelectDay,
2406
+ formatDay = (dia) => format(dia, "EEEE d 'de' MMMM", { locale: es }),
2407
+ formatTime: formatTime2 = (fecha) => format(fecha, "HH:mm", { locale: es }),
2408
+ emptyMessage = "Nada en este d\xEDa.",
2409
+ className,
2410
+ ...props
2411
+ }) {
2412
+ const id = useId();
2413
+ const [diaInterno, setDiaInterno] = useState(() => selected ?? /* @__PURE__ */ new Date());
2414
+ const dia = selected ?? diaInterno;
2415
+ const [mes, setMes] = useState(() => dia);
2416
+ const [editando, setEditando] = useState(null);
2417
+ const [titulo, setTitulo] = useState("");
2418
+ const [cuando, setCuando] = useState("");
2419
+ const editable = Boolean(onCreateEvent ?? onUpdateEvent);
2420
+ const delDia = events.filter((e) => mismoDia(e.start, dia)).sort((a, b) => a.start.getTime() - b.start.getTime());
2421
+ function elegirDia(nuevo) {
2422
+ if (!nuevo) return;
2423
+ setDiaInterno(nuevo);
2424
+ setMes(nuevo);
2425
+ onSelectDay?.(nuevo);
2426
+ cancelar();
2427
+ }
2428
+ function cancelar() {
2429
+ setEditando(null);
2430
+ setTitulo("");
2431
+ setCuando("");
2432
+ }
2433
+ function editar(evento) {
2434
+ setEditando(evento.id);
2435
+ setTitulo(evento.title);
2436
+ setCuando(aValorDeCampo(evento.start));
2437
+ }
2438
+ function enviar(e) {
2439
+ e.preventDefault();
2440
+ if (!titulo.trim() || !cuando) return;
2441
+ const start = new Date(cuando);
2442
+ if (Number.isNaN(start.getTime())) return;
2443
+ if (editando) {
2444
+ const previo = events.find((ev) => ev.id === editando);
2445
+ if (previo) onUpdateEvent?.({ ...previo, title: titulo.trim(), start });
2446
+ } else {
2447
+ onCreateEvent?.({ title: titulo.trim(), start });
2448
+ }
2449
+ cancelar();
2450
+ }
2451
+ const conEvento = events.map((e) => e.start);
2452
+ return /* @__PURE__ */ jsxs("div", { className: cn("gap-step-lg flex flex-col md:flex-row md:items-start", className), ...props, children: [
2453
+ /* @__PURE__ */ jsx(
2454
+ Calendar,
2455
+ {
2456
+ mode: "single",
2457
+ selected: dia,
2458
+ onSelect: elegirDia,
2459
+ month: mes,
2460
+ onMonthChange: setMes,
2461
+ modifiers: { conEvento },
2462
+ modifiersClassNames: {
2463
+ // El punto va bajo el número, no encima del fondo del día: sobre el
2464
+ // seleccionado —que es bioluz sólido— un punto de acento desaparece.
2465
+ // `after:` en Tailwind v4 ya trae `content: ""`, así que no hace falta
2466
+ // declararlo con un valor arbitrario.
2467
+ conEvento: cn(
2468
+ "after:bg-accent after:absolute after:bottom-1 after:left-1/2",
2469
+ "after:size-1 after:-translate-x-1/2 after:rounded-pill",
2470
+ "[&[data-selected=true]]:after:bg-accent-on"
2471
+ )
2472
+ },
2473
+ className: "shrink-0"
2474
+ }
2475
+ ),
2476
+ /* @__PURE__ */ jsxs(
2477
+ "section",
2478
+ {
2479
+ "aria-labelledby": `${id}-dia`,
2480
+ className: "border-hairline rounded-card p-step-md gap-step-md flex min-w-0 flex-1 flex-col border",
2481
+ children: [
2482
+ /* @__PURE__ */ jsx(Text, { as: "h3", variant: "h3", id: `${id}-dia`, className: "first-letter:uppercase", children: formatDay(dia) }),
2483
+ delDia.length > 0 ? /* @__PURE__ */ jsx("ul", { className: "gap-step-xs flex flex-col", children: delDia.map((evento) => /* @__PURE__ */ jsxs(
2484
+ "li",
2485
+ {
2486
+ className: "border-hairline gap-step-sm py-step-xs flex items-center border-b last:border-b-0",
2487
+ children: [
2488
+ /* @__PURE__ */ jsx(
2489
+ Text,
2490
+ {
2491
+ as: "span",
2492
+ variant: "meta",
2493
+ tone: evento.tone === "warm" ? "warm" : "accent",
2494
+ className: "shrink-0 tabular-nums",
2495
+ children: /* @__PURE__ */ jsx("time", { dateTime: evento.start.toISOString(), children: formatTime2(evento.start) })
2496
+ }
2497
+ ),
2498
+ /* @__PURE__ */ jsx(Text, { as: "span", variant: "ui", className: "min-w-0 flex-1 truncate", children: evento.title }),
2499
+ onUpdateEvent ? /* @__PURE__ */ jsx(
2500
+ Button,
2501
+ {
2502
+ variant: "tertiary",
2503
+ size: "sm",
2504
+ onClick: () => editar(evento),
2505
+ "aria-label": `Editar \xAB${evento.title}\xBB`,
2506
+ children: "./editar"
2507
+ }
2508
+ ) : null,
2509
+ onDeleteEvent ? /* @__PURE__ */ jsxs(AlertDialog, { children: [
2510
+ /* @__PURE__ */ jsx(AlertDialogTrigger, { asChild: true, children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", size: "sm", "aria-label": `Borrar \xAB${evento.title}\xBB`, children: "./borrar" }) }),
2511
+ /* @__PURE__ */ jsxs(AlertDialogContent, { children: [
2512
+ /* @__PURE__ */ jsxs(AlertDialogHeader, { children: [
2513
+ /* @__PURE__ */ jsxs(AlertDialogTitle, { children: [
2514
+ "Borrar \xAB",
2515
+ evento.title,
2516
+ "\xBB"
2517
+ ] }),
2518
+ /* @__PURE__ */ jsxs(AlertDialogDescription, { children: [
2519
+ "Se borra del ",
2520
+ formatDay(evento.start),
2521
+ " a las ",
2522
+ formatTime2(evento.start),
2523
+ ". No se puede deshacer."
2524
+ ] })
2525
+ ] }),
2526
+ /* @__PURE__ */ jsxs(AlertDialogFooter, { children: [
2527
+ /* @__PURE__ */ jsx(AlertDialogCancel, { children: "Mejor no" }),
2528
+ /* @__PURE__ */ jsx(AlertDialogAction, { onClick: () => onDeleteEvent(evento.id), children: "Borrar el evento" })
2529
+ ] })
2530
+ ] })
2531
+ ] }) : null
2532
+ ]
2533
+ },
2534
+ evento.id
2535
+ )) }) : (
2536
+ // `EmptyState` no: lleva una cara de la mascota, y la mascota tiene
2537
+ // siete sitios contados donde puede aparecer. Un día vacío de una
2538
+ // agenda no es uno de ellos — y en un mes de treinta días, la mitad lo
2539
+ // serían.
2540
+ /* @__PURE__ */ jsx(Text, { as: "p", variant: "ui", tone: "muted", children: emptyMessage })
2541
+ ),
2542
+ editable ? /* @__PURE__ */ jsxs("form", { onSubmit: enviar, className: "gap-step-sm border-hairline pt-step-md flex flex-col border-t", children: [
2543
+ /* @__PURE__ */ jsxs("div", { className: "gap-step-xs flex flex-col", children: [
2544
+ /* @__PURE__ */ jsx(Label, { htmlFor: `${id}-titulo`, children: "T\xEDtulo" }),
2545
+ /* @__PURE__ */ jsx(
2546
+ Input,
2547
+ {
2548
+ id: `${id}-titulo`,
2549
+ value: titulo,
2550
+ onChange: (e) => setTitulo(e.target.value),
2551
+ placeholder: "Publicar el art\xEDculo",
2552
+ required: true
2553
+ }
2554
+ )
2555
+ ] }),
2556
+ /* @__PURE__ */ jsxs("div", { className: "gap-step-xs flex flex-col", children: [
2557
+ /* @__PURE__ */ jsx(Label, { htmlFor: `${id}-cuando`, children: "Cu\xE1ndo" }),
2558
+ /* @__PURE__ */ jsx(
2559
+ DateField,
2560
+ {
2561
+ id: `${id}-cuando`,
2562
+ withTime: true,
2563
+ value: cuando,
2564
+ onChange: (e) => setCuando(e.target.value),
2565
+ required: true
2566
+ }
2567
+ )
2568
+ ] }),
2569
+ /* @__PURE__ */ jsxs("div", { className: "gap-step-sm flex flex-wrap items-center", children: [
2570
+ /* @__PURE__ */ jsx(Button, { type: "submit", size: "sm", children: editando ? "Guardar" : "A\xF1adir" }),
2571
+ editando ? /* @__PURE__ */ jsx(Button, { type: "button", variant: "tertiary", size: "sm", onClick: cancelar, children: "./cancelar" }) : null
2572
+ ] })
2573
+ ] }) : null
2574
+ ]
2575
+ }
2576
+ )
2577
+ ] });
2578
+ }
2161
2579
  function Footer({
2162
2580
  social,
2163
2581
  year = (/* @__PURE__ */ new Date()).getFullYear(),
2164
2582
  children,
2583
+ brand: brand2,
2165
2584
  className,
2166
2585
  ...props
2167
2586
  }) {
2168
2587
  return /* @__PURE__ */ jsx("footer", { className: cn("border-hairline w-full border-t", className), ...props, children: /* @__PURE__ */ jsxs("div", { className: "max-w-wide px-step-md py-step-xl gap-step-lg mx-auto flex flex-col", children: [
2588
+ brand2 ? /* @__PURE__ */ jsx("div", { className: "flex items-center", children: brand2 }) : null,
2169
2589
  children ? /* @__PURE__ */ jsx("div", { className: "gap-step-md flex flex-wrap items-center", children }) : null,
2170
- social && social.length > 0 ? (
2171
- // 18px de separación, del documento. No es un escalón de `spacing`:
2172
- // es el ritmo de una fila de iconos, no el de una página.
2173
- /* @__PURE__ */ jsx("ul", { className: "flex items-center gap-[18px]", children: social.map((red) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
2174
- "a",
2175
- {
2176
- href: red.href,
2177
- "aria-label": red.label,
2178
- className: cn(
2179
- "text-text-muted hover:text-accent transition-standard block cursor-pointer text-[19px]",
2180
- "rounded-chip focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent"
2181
- ),
2182
- children: red.icon
2183
- }
2184
- ) }, red.href)) })
2185
- ) : null,
2186
- /* @__PURE__ */ jsxs(Text, { variant: "meta", tone: "muted", as: "p", children: [
2187
- /* @__PURE__ */ jsxs("span", { "aria-hidden": "true", className: "text-accent", children: [
2188
- "$",
2189
- " "
2190
- ] }),
2191
- "cd ~/",
2192
- naming.domain,
2193
- "/",
2194
- year
2590
+ /* @__PURE__ */ jsxs("div", { className: "gap-step-md flex flex-wrap items-center", children: [
2591
+ social && social.length > 0 ? (
2592
+ // 18px de separación, del documento. No es un escalón de `spacing`:
2593
+ // es el ritmo de una fila de iconos, no el de una página.
2594
+ /* @__PURE__ */ jsx("ul", { className: "flex items-center gap-[18px]", children: social.map((red) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
2595
+ "a",
2596
+ {
2597
+ href: red.href,
2598
+ "aria-label": red.label,
2599
+ className: cn(
2600
+ "text-text-muted hover:text-accent transition-standard block cursor-pointer text-[19px]",
2601
+ "rounded-chip focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent"
2602
+ ),
2603
+ children: red.icon
2604
+ }
2605
+ ) }, red.href)) })
2606
+ ) : null,
2607
+ /* @__PURE__ */ jsxs(Text, { variant: "meta", tone: "muted", as: "p", className: "ml-auto", children: [
2608
+ /* @__PURE__ */ jsxs("span", { "aria-hidden": "true", className: "text-accent", children: [
2609
+ "$",
2610
+ " "
2611
+ ] }),
2612
+ "cd ~/",
2613
+ naming.domain,
2614
+ "/",
2615
+ year
2616
+ ] })
2195
2617
  ] })
2196
2618
  ] }) });
2197
2619
  }
@@ -2216,9 +2638,11 @@ function Hero({
2216
2638
  action,
2217
2639
  pose,
2218
2640
  basePath,
2641
+ variant = "cabecera",
2219
2642
  className,
2220
2643
  ...props
2221
2644
  }) {
2645
+ const centrado = variant === "centrado";
2222
2646
  return /* @__PURE__ */ jsxs(
2223
2647
  "section",
2224
2648
  {
@@ -2230,13 +2654,39 @@ function Hero({
2230
2654
  ),
2231
2655
  ...props,
2232
2656
  children: [
2233
- /* @__PURE__ */ jsxs("div", { className: "gap-step-md flex flex-col md:max-w-[62%]", children: [
2234
- eyebrow ? /* @__PURE__ */ jsx(Text, { variant: "eyebrow", tone: "accent", as: "p", children: eyebrow }) : null,
2235
- /* @__PURE__ */ jsx(Text, { as: "h1", variant: "display", children: title }),
2236
- description ? /* @__PURE__ */ jsx(Text, { variant: "body", tone: "secondary", children: description }) : null,
2237
- action ? /* @__PURE__ */ jsx("div", { className: "gap-step-sm mt-step-xs flex flex-wrap items-center", children: action }) : null
2238
- ] }),
2239
- pose ? /* @__PURE__ */ jsx(
2657
+ centrado && pose ? /* @__PURE__ */ jsx(
2658
+ Mascota,
2659
+ {
2660
+ pose,
2661
+ basePath,
2662
+ className: "mb-step-md mx-auto w-48 md:w-56"
2663
+ }
2664
+ ) : null,
2665
+ /* @__PURE__ */ jsxs(
2666
+ "div",
2667
+ {
2668
+ className: cn(
2669
+ "gap-step-md flex flex-col",
2670
+ centrado ? "items-center text-center" : "md:max-w-[62%]"
2671
+ ),
2672
+ children: [
2673
+ eyebrow ? /* @__PURE__ */ jsx(Text, { variant: "eyebrow", tone: "accent", as: "p", children: eyebrow }) : null,
2674
+ /* @__PURE__ */ jsx(Text, { as: "h1", variant: "display", children: title }),
2675
+ description ? /* @__PURE__ */ jsx(Text, { variant: "body", tone: "secondary", children: description }) : null,
2676
+ action ? /* @__PURE__ */ jsx(
2677
+ "div",
2678
+ {
2679
+ className: cn(
2680
+ "gap-step-sm mt-step-xs flex flex-wrap items-center",
2681
+ centrado && "justify-center"
2682
+ ),
2683
+ children: action
2684
+ }
2685
+ ) : null
2686
+ ]
2687
+ }
2688
+ ),
2689
+ !centrado && pose ? /* @__PURE__ */ jsx(
2240
2690
  Mascota,
2241
2691
  {
2242
2692
  pose,
@@ -2302,7 +2752,10 @@ function Nav({ brand: brand2, children, actions, className, ...props }) {
2302
2752
  ...props,
2303
2753
  children: /* @__PURE__ */ jsxs("div", { className: "max-w-wide px-step-md h-nav gap-step-lg mx-auto flex items-center", children: [
2304
2754
  brand2 ? /* @__PURE__ */ jsx("div", { className: "shrink-0", children: brand2 }) : null,
2305
- children ? /* @__PURE__ */ jsx("nav", { "aria-label": "Principal", className: "min-w-0 flex-1", children: /* @__PURE__ */ jsx("ul", { className: "gap-step-md flex items-center", children }) }) : /* @__PURE__ */ jsx("div", { className: "flex-1" }),
2755
+ children ? /* @__PURE__ */ jsx("nav", { "aria-label": "Principal", className: "ml-auto min-w-0", children: /* @__PURE__ */ jsxs("ul", { className: "gap-step-md flex items-center", children: [
2756
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "text-text-muted font-mono text-meta select-none", children: "~/" }),
2757
+ children
2758
+ ] }) }) : /* @__PURE__ */ jsx("div", { className: "flex-1" }),
2306
2759
  actions ? /* @__PURE__ */ jsx("div", { className: "gap-step-sm flex shrink-0 items-center", children: actions }) : null
2307
2760
  ] })
2308
2761
  }
@@ -2322,8 +2775,10 @@ function NavItem({ active = false, asChild = false, className, children, ...prop
2322
2775
  ),
2323
2776
  ...props,
2324
2777
  children: [
2325
- /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "text-text-muted", children: "./" }),
2326
- children
2778
+ active ? /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "text-accent", children: "[" }) : null,
2779
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: active ? "text-accent" : "text-text-muted", children: "./" }),
2780
+ children,
2781
+ active ? /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "text-accent", children: "]" }) : null
2327
2782
  ]
2328
2783
  }
2329
2784
  ) });
@@ -2341,6 +2796,10 @@ function NewsletterForm({
2341
2796
  submitLabel = "Suscribirme",
2342
2797
  placeholder = "tu@correo.dev",
2343
2798
  fieldLabel = "Correo electr\xF3nico",
2799
+ nameField = false,
2800
+ nameLabel = "Nombre",
2801
+ namePlaceholder = "C\xF3mo te llamas",
2802
+ nameInputProps,
2344
2803
  className,
2345
2804
  ...props
2346
2805
  }) {
@@ -2351,8 +2810,19 @@ function NewsletterForm({
2351
2810
  evento.preventDefault();
2352
2811
  const datos = new FormData(evento.currentTarget);
2353
2812
  const correo = String(datos.get("email") ?? "");
2354
- onSubmitEmail?.(correo);
2813
+ const nombre = nameField ? String(datos.get("name") ?? "") : void 0;
2814
+ onSubmitEmail?.(correo, nombre);
2355
2815
  }
2816
+ const boton = /* @__PURE__ */ jsx(
2817
+ Button,
2818
+ {
2819
+ type: "submit",
2820
+ variant: "conversion",
2821
+ loading: enviando,
2822
+ className: cn("disabled:opacity-60", nameField && "sm:self-start"),
2823
+ children: submitLabel
2824
+ }
2825
+ );
2356
2826
  return /* @__PURE__ */ jsxs(
2357
2827
  "section",
2358
2828
  {
@@ -2366,34 +2836,44 @@ function NewsletterForm({
2366
2836
  /* @__PURE__ */ jsx(Text, { as: "h2", variant: "h3", children: title }),
2367
2837
  description ? /* @__PURE__ */ jsx(Text, { variant: "ui", tone: "secondary", children: description }) : null
2368
2838
  ] }),
2369
- /* @__PURE__ */ jsxs("form", { onSubmit: enviar, className: "gap-step-sm flex flex-col sm:flex-row sm:items-end", noValidate: true, children: [
2370
- /* @__PURE__ */ jsxs("div", { className: "gap-step-xs flex flex-1 flex-col", children: [
2371
- /* @__PURE__ */ jsx(Label2, { htmlFor: id, children: fieldLabel }),
2372
- /* @__PURE__ */ jsx(
2373
- Input,
2374
- {
2375
- id,
2376
- name: "email",
2377
- type: "email",
2378
- autoComplete: "email",
2379
- required: true,
2380
- placeholder,
2381
- disabled: enviando,
2382
- invalid: error,
2383
- "aria-describedby": state === "exito" || error ? `${id}-aviso` : void 0
2384
- }
2385
- )
2839
+ /* @__PURE__ */ jsxs("form", { onSubmit: enviar, className: "gap-step-sm flex flex-col", noValidate: true, children: [
2840
+ /* @__PURE__ */ jsxs("div", { className: "gap-step-sm flex flex-col sm:flex-row sm:items-end", children: [
2841
+ nameField ? /* @__PURE__ */ jsxs("div", { className: "gap-step-xs flex flex-1 flex-col", children: [
2842
+ /* @__PURE__ */ jsx(Label, { htmlFor: `${id}-nombre`, children: nameLabel }),
2843
+ /* @__PURE__ */ jsx(
2844
+ Input,
2845
+ {
2846
+ id: `${id}-nombre`,
2847
+ name: "name",
2848
+ type: "text",
2849
+ autoComplete: "name",
2850
+ required: true,
2851
+ placeholder: namePlaceholder,
2852
+ disabled: enviando,
2853
+ ...nameInputProps
2854
+ }
2855
+ )
2856
+ ] }) : null,
2857
+ /* @__PURE__ */ jsxs("div", { className: "gap-step-xs flex flex-1 flex-col", children: [
2858
+ /* @__PURE__ */ jsx(Label, { htmlFor: id, children: fieldLabel }),
2859
+ /* @__PURE__ */ jsx(
2860
+ Input,
2861
+ {
2862
+ id,
2863
+ name: "email",
2864
+ type: "email",
2865
+ autoComplete: "email",
2866
+ required: true,
2867
+ placeholder,
2868
+ disabled: enviando,
2869
+ invalid: error,
2870
+ "aria-describedby": state === "exito" || error ? `${id}-aviso` : void 0
2871
+ }
2872
+ )
2873
+ ] }),
2874
+ nameField ? null : boton
2386
2875
  ] }),
2387
- /* @__PURE__ */ jsx(
2388
- Button,
2389
- {
2390
- type: "submit",
2391
- variant: "conversion",
2392
- loading: enviando,
2393
- className: "disabled:opacity-60",
2394
- children: submitLabel
2395
- }
2396
- )
2876
+ nameField ? boton : null
2397
2877
  ] }),
2398
2878
  state === "exito" ? /* @__PURE__ */ jsx(Alert, { id: `${id}-aviso`, variant: "success", enfasis: "fuerte", children: successMessage }) : null,
2399
2879
  error ? /* @__PURE__ */ jsx(Alert, { id: `${id}-aviso`, variant: "error", enfasis: "fuerte", children: errorMessage }) : null,
@@ -2431,6 +2911,62 @@ function PageHeader({
2431
2911
  action ? /* @__PURE__ */ jsx("div", { className: "gap-step-sm mt-step-sm flex flex-wrap items-center", children: action }) : null
2432
2912
  ] });
2433
2913
  }
2914
+ function ScrollingProgressBar({
2915
+ target,
2916
+ tone = "accent",
2917
+ sticky = true,
2918
+ className,
2919
+ ...props
2920
+ }) {
2921
+ const [avance, setAvance] = useState(0);
2922
+ const pendiente = useRef(0);
2923
+ useEffect(() => {
2924
+ const medir = () => {
2925
+ pendiente.current = 0;
2926
+ const elemento = target?.current;
2927
+ const inicio = elemento ? elemento.getBoundingClientRect().top + scrollY : 0;
2928
+ const alto = elemento ? elemento.offsetHeight : document.documentElement.scrollHeight;
2929
+ const recorrible = alto - innerHeight;
2930
+ if (recorrible <= 0) {
2931
+ setAvance(scrollY >= inicio ? 100 : 0);
2932
+ return;
2933
+ }
2934
+ const recorrido = scrollY - inicio;
2935
+ setAvance(Math.min(100, Math.max(0, recorrido / recorrible * 100)));
2936
+ };
2937
+ const alMoverse = () => {
2938
+ if (pendiente.current) return;
2939
+ pendiente.current = requestAnimationFrame(medir);
2940
+ };
2941
+ medir();
2942
+ addEventListener("scroll", alMoverse, { passive: true });
2943
+ addEventListener("resize", alMoverse);
2944
+ return () => {
2945
+ if (pendiente.current) cancelAnimationFrame(pendiente.current);
2946
+ removeEventListener("scroll", alMoverse);
2947
+ removeEventListener("resize", alMoverse);
2948
+ };
2949
+ }, [target]);
2950
+ return /* @__PURE__ */ jsx(
2951
+ "div",
2952
+ {
2953
+ "aria-hidden": "true",
2954
+ className: cn(
2955
+ "h-1 w-full overflow-hidden",
2956
+ sticky && "sticky top-0 z-40",
2957
+ className
2958
+ ),
2959
+ ...props,
2960
+ children: /* @__PURE__ */ jsx(
2961
+ "div",
2962
+ {
2963
+ className: cn("h-full", tone === "warm" ? "bg-warm" : "bg-accent"),
2964
+ style: { width: `${avance}%` }
2965
+ }
2966
+ )
2967
+ }
2968
+ );
2969
+ }
2434
2970
  function SidebarItem({
2435
2971
  active = false,
2436
2972
  asChild = false,
@@ -2494,10 +3030,28 @@ function SidebarNav({
2494
3030
  }
2495
3031
  );
2496
3032
  }
2497
- function Stat({ value, label, tone = "neutral", progress, className, ...props }) {
3033
+ function Stat({
3034
+ value,
3035
+ label,
3036
+ tone = "neutral",
3037
+ progress,
3038
+ icon,
3039
+ description,
3040
+ className,
3041
+ ...props
3042
+ }) {
2498
3043
  return /* @__PURE__ */ jsxs("div", { className: cn(SUPERFICIE_TARJETA, "p-step-lg gap-step-xs flex flex-col", className), ...props, children: [
3044
+ /* @__PURE__ */ jsxs(Text, { variant: "eyebrow", tone: "muted", as: "p", className: "gap-step-xs flex items-center", children: [
3045
+ icon ? (
3046
+ // `aria-hidden` no hace falta: los glifos del sistema ya lo traen
3047
+ // puesto. Lo que sí hace falta es que no encoja al lado de un título
3048
+ // largo, porque un icono aplastado se lee como otro icono.
3049
+ /* @__PURE__ */ jsx("span", { className: "shrink-0", children: icon })
3050
+ ) : null,
3051
+ label
3052
+ ] }),
2499
3053
  /* @__PURE__ */ jsx(Text, { variant: "stat", as: "p", tone: tone === "alerta" ? "warm" : "accent", children: value }),
2500
- /* @__PURE__ */ jsx(Text, { variant: "eyebrow", tone: "muted", as: "p", children: label }),
3054
+ description ? /* @__PURE__ */ jsx(Text, { variant: "ui", tone: "secondary", as: "p", children: description }) : null,
2501
3055
  typeof progress === "number" ? /* @__PURE__ */ jsx(
2502
3056
  Progress,
2503
3057
  {
@@ -2516,6 +3070,7 @@ function TalkCard({
2516
3070
  dateTime,
2517
3071
  location,
2518
3072
  status,
3073
+ description,
2519
3074
  className,
2520
3075
  ...props
2521
3076
  }) {
@@ -2529,12 +3084,43 @@ function TalkCard({
2529
3084
  status ? /* @__PURE__ */ jsx(Badge, { variant: "neutral", children: status }) : null
2530
3085
  ] }),
2531
3086
  /* @__PURE__ */ jsx(Text, { as: "h3", variant: "h3", className: "group-hover:text-accent transition-standard", children: title }),
3087
+ description ? /* @__PURE__ */ jsx(Text, { variant: "ui", tone: "secondary", className: "line-clamp-2", children: description }) : null,
2532
3088
  pie.length > 0 ? /* @__PURE__ */ jsx(Text, { variant: "label", tone: "muted", as: "p", className: "gap-step-xs mt-auto flex items-center pt-step-sm", children: pie.map((m, i) => /* @__PURE__ */ jsxs("span", { className: "gap-step-xs flex items-center", children: [
2533
3089
  i > 0 ? /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\xB7" }) : null,
2534
3090
  m
2535
3091
  ] }, i)) }) : null
2536
3092
  ] }) });
2537
3093
  }
3094
+ function ThemeToggle({
3095
+ label = "Cambiar de tema",
3096
+ onThemeChange,
3097
+ variant = "secondary",
3098
+ size: size2 = "icon",
3099
+ className,
3100
+ ...props
3101
+ }) {
3102
+ return /* @__PURE__ */ jsxs(
3103
+ Button,
3104
+ {
3105
+ type: "button",
3106
+ variant,
3107
+ size: size2,
3108
+ "aria-label": label,
3109
+ className: cn("[&_svg]:size-[19px]", className),
3110
+ onClick: () => onThemeChange?.(alternarTema()),
3111
+ ...props,
3112
+ children: [
3113
+ /* @__PURE__ */ jsx(Sol, { className: "light:hidden" }),
3114
+ /* @__PURE__ */ jsx(Luna, { className: "hidden light:block" })
3115
+ ]
3116
+ }
3117
+ );
3118
+ }
3119
+ function useTema() {
3120
+ return useSyncExternalStore(suscribirse2, temaActual, servidor);
3121
+ }
3122
+ var suscribirse2 = (avisar) => escucharTema(() => avisar());
3123
+ var servidor = () => "dark";
2538
3124
  function TableOfContents({
2539
3125
  items,
2540
3126
  title = "En esta p\xE1gina",
@@ -2553,7 +3139,11 @@ function TableOfContents({
2553
3139
  "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent",
2554
3140
  "cursor-pointer",
2555
3141
  item2.nested && "pl-step-lg",
2556
- activo ? "border-accent text-accent" : "border-transparent text-text-secondary hover:text-text-primary"
3142
+ "border-transparent text-text-secondary hover:text-text-primary",
3143
+ // El hover del activo se declara con las dos variantes juntas para
3144
+ // que gane al `hover:` de arriba por especificidad y no por el orden
3145
+ // en que Tailwind decida emitir las reglas.
3146
+ "aria-[current]:border-accent aria-[current]:text-accent aria-[current]:hover:text-accent"
2557
3147
  );
2558
3148
  return /* @__PURE__ */ jsx("li", { children: linkAsChild ? /* @__PURE__ */ jsx(Slot, { className: clases, "aria-current": activo ? "location" : void 0, children: linkAsChild({ href: item2.href, children: item2.label }) }) : /* @__PURE__ */ jsx("a", { href: item2.href, className: clases, "aria-current": activo ? "location" : void 0, children: item2.label }) }, item2.href);
2559
3149
  }) })
@@ -2621,4 +3211,4 @@ var Correo = (props) => /* @__PURE__ */ jsxs(Funcional, { ...props, children: [
2621
3211
  /* @__PURE__ */ jsx("path", { d: "m3.5 7.5 7.4 5.2a2 2 0 0 0 2.2 0l7.4-5.2" })
2622
3212
  ] });
2623
3213
 
2624
- export { Alert, ArticleCard, AudioPlayer, AuthorCard, Avatar, AvatarFallback, AvatarImage, Badge, Blockquote, Breadcrumb, Button, Calendar, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, CategoryBadge, Checkbox, Code, CodeBlock, CourseCard, DateField, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogTitle, DialogTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EmptyState, Footer, FooterLink, HOVER_TARJETA, Hero, Input, Label2 as Label, LinkRow, MetricBadge, Nav, NavItem, NewsletterForm, PageHeader, Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, Progress, RadioGroup2 as RadioGroup, RadioGroupItem, SUPERFICIE_TARJETA, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectSeparator, SelectTrigger, SelectValue, Separator3 as Separator, Sheet, SheetBody, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger, SidebarItem, SidebarNav, Skeleton, Stat, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableOfContents, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, TalkCard, Text, Textarea, Toast, ToastAction, ToastDescription, ToastProvider, ToastTitle, ToastViewport, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, alert as alertVariants, avatar as avatarVariants, badge as badgeVariants, button as buttonVariants, categoria as categoryBadgeVariants, social_exports as social, texto as textVariants };
3214
+ export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, Alert, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogTitle, AlertDialogTrigger, ArticleCard, AudioPlayer, AuthorCard, Avatar, AvatarFallback, AvatarImage, AvatarUpload, Badge, Blockquote, Breadcrumb, Button, Calendar, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, CategoryBadge, Checkbox, Code, CodeBlock, CourseCard, DateField, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogTitle, DialogTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EmptyState, EventCalendar, Footer, FooterLink, HOVER_TARJETA, Hero, Input, LinkRow, MetricBadge, Nav, NavItem, NewsletterForm, PageHeader, Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, Progress, RadioGroup2 as RadioGroup, RadioGroupItem, SUPERFICIE_TARJETA, ScrollingProgressBar, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectSeparator, SelectTrigger, SelectValue, Separator3 as Separator, Sheet, SheetBody, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger, SidebarItem, SidebarNav, Skeleton, Stat, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableOfContents, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, TalkCard, Textarea, ThemeToggle, ToastAction, Toaster, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, alert as alertVariants, avatar as avatarVariants, badge as badgeVariants, button as buttonVariants, categoria as categoryBadgeVariants, social_exports as social, toast2 as toast, useTema };