@eduardoalvarez/arrecife 0.3.0 → 0.4.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/dist/index.js CHANGED
@@ -1,19 +1,29 @@
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-TB3IYPOD.js';
5
+ export { CaraDeMascota, Isotipo, Logo, Mascota } from './chunk-TB3IYPOD.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';
11
22
  import { es } from 'date-fns/locale';
12
23
  import { DayPicker } from 'react-day-picker';
13
24
  import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
14
25
  import * as DialogPrimitive from '@radix-ui/react-dialog';
15
26
  import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
16
- import * as LabelPrimitive from '@radix-ui/react-label';
17
27
  import * as PopoverPrimitive from '@radix-ui/react-popover';
18
28
  import * as ProgressPrimitive from '@radix-ui/react-progress';
19
29
  import * as RadioGroupPrimitive from '@radix-ui/react-radio-group';
@@ -22,9 +32,167 @@ import * as SeparatorPrimitive from '@radix-ui/react-separator';
22
32
  import * as SwitchPrimitive from '@radix-ui/react-switch';
23
33
  import * as TabsPrimitive from '@radix-ui/react-tabs';
24
34
  import * as ToastPrimitive from '@radix-ui/react-toast';
35
+ import { useSyncExternalStore, useRef, useState, useEffect, useCallback, useId } from 'react';
25
36
  import * as TooltipPrimitive from '@radix-ui/react-tooltip';
26
- import { useRef, useState, useEffect, useCallback, useId } from 'react';
27
37
 
38
+ function Glyph({ children, ...props }) {
39
+ return /* @__PURE__ */ jsx(
40
+ "svg",
41
+ {
42
+ viewBox: "0 0 16 16",
43
+ width: "1em",
44
+ height: "1em",
45
+ fill: "none",
46
+ stroke: "currentColor",
47
+ strokeWidth: 1.75,
48
+ strokeLinecap: "round",
49
+ strokeLinejoin: "round",
50
+ "aria-hidden": "true",
51
+ focusable: "false",
52
+ ...props,
53
+ children
54
+ }
55
+ );
56
+ }
57
+ var Check = (props) => /* @__PURE__ */ jsx(Glyph, { ...props, children: /* @__PURE__ */ jsx("path", { d: "M3 8.5 6.5 12 13 4.5" }) });
58
+ var Minus = (props) => /* @__PURE__ */ jsx(Glyph, { ...props, children: /* @__PURE__ */ jsx("path", { d: "M3.5 8h9" }) });
59
+ var ChevronDown = (props) => /* @__PURE__ */ jsx(Glyph, { ...props, children: /* @__PURE__ */ jsx("path", { d: "M4 6l4 4 4-4" }) });
60
+ var ChevronUp = (props) => /* @__PURE__ */ jsx(Glyph, { ...props, children: /* @__PURE__ */ jsx("path", { d: "M4 10l4-4 4 4" }) });
61
+ var ChevronLeft = (props) => /* @__PURE__ */ jsx(Glyph, { ...props, children: /* @__PURE__ */ jsx("path", { d: "M10 4L6 8l4 4" }) });
62
+ var ChevronRight = (props) => /* @__PURE__ */ jsx(Glyph, { ...props, children: /* @__PURE__ */ jsx("path", { d: "M6 4l4 4-4 4" }) });
63
+ var Close = (props) => /* @__PURE__ */ jsx(Glyph, { ...props, children: /* @__PURE__ */ jsx("path", { d: "M4 4l8 8M12 4l-8 8" }) });
64
+ var Copy = (props) => /* @__PURE__ */ jsxs(Glyph, { ...props, children: [
65
+ /* @__PURE__ */ jsx("rect", { x: "5.5", y: "5.5", width: "8", height: "8", rx: "1.5" }),
66
+ /* @__PURE__ */ jsx("path", { d: "M10.5 3.5h-7a1.5 1.5 0 0 0-1.5 1.5v7" })
67
+ ] });
68
+ var ArrowUpRight = (props) => /* @__PURE__ */ jsx(Glyph, { ...props, children: /* @__PURE__ */ jsx("path", { d: "M5 11l6-6M5.5 5h5.5v5.5" }) });
69
+ var Ellipsis = (props) => /* @__PURE__ */ jsx(Glyph, { ...props, strokeWidth: 2.25, children: /* @__PURE__ */ jsx("path", { d: "M4 8h.01M8 8h.01M12 8h.01" }) });
70
+ var Spinner = (props) => /* @__PURE__ */ jsxs(
71
+ "svg",
72
+ {
73
+ viewBox: "0 0 16 16",
74
+ width: "1em",
75
+ height: "1em",
76
+ fill: "none",
77
+ stroke: "currentColor",
78
+ strokeWidth: 2,
79
+ strokeLinecap: "round",
80
+ "aria-hidden": "true",
81
+ focusable: "false",
82
+ className: "motion-safe:animate-spin",
83
+ ...props,
84
+ children: [
85
+ /* @__PURE__ */ jsx("circle", { cx: "8", cy: "8", r: "6", opacity: 0.3 }),
86
+ /* @__PURE__ */ jsx("path", { d: "M8 2a6 6 0 0 1 6 6" })
87
+ ]
88
+ }
89
+ );
90
+ var Sol = (props) => /* @__PURE__ */ jsxs(Glyph, { ...props, children: [
91
+ /* @__PURE__ */ jsx("circle", { cx: "8", cy: "8", r: "3" }),
92
+ /* @__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" })
93
+ ] });
94
+ 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" }) });
95
+ function GlifoMedia({ children, ...props }) {
96
+ return /* @__PURE__ */ jsx(
97
+ "svg",
98
+ {
99
+ xmlns: "http://www.w3.org/2000/svg",
100
+ viewBox: "0 0 24 24",
101
+ fill: "none",
102
+ "aria-hidden": "true",
103
+ focusable: "false",
104
+ ...props,
105
+ children
106
+ }
107
+ );
108
+ }
109
+ var Play = (props) => /* @__PURE__ */ jsx(GlifoMedia, { fill: "currentColor", ...props, children: /* @__PURE__ */ jsx("path", { d: "M8 5v14l11-7z" }) });
110
+ var Pause = (props) => /* @__PURE__ */ jsx(GlifoMedia, { fill: "currentColor", ...props, children: /* @__PURE__ */ jsx("path", { d: "M6 4h4v16H6V4zm8 0h4v16h-4V4z" }) });
111
+ var Retry = (props) => /* @__PURE__ */ jsx(
112
+ GlifoMedia,
113
+ {
114
+ stroke: "currentColor",
115
+ strokeWidth: 2,
116
+ strokeLinecap: "round",
117
+ strokeLinejoin: "round",
118
+ ...props,
119
+ 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" })
120
+ }
121
+ );
122
+ var GoBackSeconds = (props) => /* @__PURE__ */ jsxs(GlifoMedia, { stroke: "currentColor", strokeWidth: 1.5, strokeLinecap: "round", ...props, children: [
123
+ /* @__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" }),
124
+ /* @__PURE__ */ jsx("path", { d: "M7.5 10.5L10 8.5V15.5", strokeLinejoin: "round" }),
125
+ /* @__PURE__ */ jsx(
126
+ "path",
127
+ {
128
+ 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",
129
+ strokeLinejoin: "round"
130
+ }
131
+ )
132
+ ] });
133
+ var AdvanceSeconds = (props) => /* @__PURE__ */ jsxs(GlifoMedia, { stroke: "currentColor", strokeWidth: 1.5, strokeLinecap: "round", ...props, children: [
134
+ /* @__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" }),
135
+ /* @__PURE__ */ jsx("path", { d: "M7.5 10.5L10 8.5V15.5", strokeLinejoin: "round" }),
136
+ /* @__PURE__ */ jsx(
137
+ "path",
138
+ {
139
+ 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",
140
+ strokeLinejoin: "round"
141
+ }
142
+ )
143
+ ] });
144
+ 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" }) });
145
+ 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" }) });
146
+ function Accordion({ className, ...props }) {
147
+ return /* @__PURE__ */ jsx(
148
+ AccordionPrimitive.Root,
149
+ {
150
+ className: cn("border-hairline w-full border-t", className),
151
+ ...props
152
+ }
153
+ );
154
+ }
155
+ function AccordionItem({
156
+ className,
157
+ ...props
158
+ }) {
159
+ return /* @__PURE__ */ jsx(AccordionPrimitive.Item, { className: cn("border-hairline border-b", className), ...props });
160
+ }
161
+ function AccordionTrigger({
162
+ className,
163
+ children,
164
+ headingLevel = 3,
165
+ ...props
166
+ }) {
167
+ const Encabezado = `h${headingLevel}`;
168
+ return /* @__PURE__ */ jsx(AccordionPrimitive.Header, { asChild: true, children: /* @__PURE__ */ jsx(Encabezado, { children: /* @__PURE__ */ jsxs(
169
+ AccordionPrimitive.Trigger,
170
+ {
171
+ className: cn(
172
+ "gap-step-sm py-step-sm flex w-full cursor-pointer items-center justify-between text-left",
173
+ "font-sans text-lead font-medium text-text-primary",
174
+ "transition-standard",
175
+ "hover:text-accent",
176
+ "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent",
177
+ "disabled:pointer-events-none disabled:opacity-50",
178
+ "[&[data-state=open]>svg]:rotate-180",
179
+ className
180
+ ),
181
+ ...props,
182
+ children: [
183
+ children,
184
+ /* @__PURE__ */ jsx(ChevronDown, { className: "text-text-muted shrink-0" })
185
+ ]
186
+ }
187
+ ) }) });
188
+ }
189
+ function AccordionContent({
190
+ className,
191
+ children,
192
+ ...props
193
+ }) {
194
+ return /* @__PURE__ */ jsx(AccordionPrimitive.Content, { className: "overflow-hidden", ...props, children: /* @__PURE__ */ jsx("div", { className: cn("pb-step-md font-sans text-ui text-text-secondary max-w-measure", className), children }) });
195
+ }
28
196
  var alert = cva("w-full rounded-card border p-step-md font-sans text-ui", {
29
197
  variants: {
30
198
  variant: {
@@ -95,273 +263,267 @@ function Alert({
95
263
  }
96
264
  );
97
265
  }
98
- var avatar = cva(
99
- "relative flex shrink-0 overflow-hidden rounded-pill bg-surface-raised border border-hairline",
266
+ var button = cva(
267
+ [
268
+ "inline-flex cursor-pointer items-center justify-center gap-step-xs whitespace-nowrap select-none",
269
+ "rounded-control font-sans font-medium",
270
+ "transition-standard",
271
+ "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent",
272
+ "disabled:pointer-events-none disabled:opacity-50",
273
+ "[&_svg]:shrink-0"
274
+ ],
100
275
  {
101
276
  variants: {
277
+ variant: {
278
+ primary: [
279
+ "bg-accent text-accent-on hover:bg-accent-hover",
280
+ "light:bg-brand-hull light:text-accent-on light:hover:bg-text-secondary"
281
+ ],
282
+ conversion: "bg-warm text-warm-on hover:bg-warm-hover",
283
+ secondary: [
284
+ "border-hairline-hover border bg-transparent text-text-primary",
285
+ "hover:border-accent hover:text-accent"
286
+ ],
287
+ tertiary: [
288
+ "bg-transparent font-mono font-normal text-text-secondary",
289
+ "hover:text-accent hover:underline hover:underline-offset-4"
290
+ ]
291
+ },
102
292
  size: {
103
- sm: "size-8",
104
- md: "size-10",
105
- lg: "size-14",
106
- xl: "size-24"
293
+ sm: "h-8 px-control-sm text-label",
294
+ md: "h-10 px-control-md text-ui",
295
+ lg: "h-12 px-control-lg text-lead",
296
+ /** Cuadrado 42×42, sin texto. Lleva `aria-label` obligatorio. */
297
+ icon: "size-control-icon p-0"
107
298
  }
108
299
  },
109
- defaultVariants: { size: "md" }
300
+ compoundVariants: [
301
+ /**
302
+ * El terciario no tiene caja: ni padding horizontal ni alto de control.
303
+ * Va aquí y no como `px-0` en la variante para que gane al `px-*` del
304
+ * tamaño sin depender del orden en que cva concatena las clases.
305
+ */
306
+ { variant: "tertiary", size: ["sm", "md", "lg"], class: "h-auto px-0" }
307
+ ],
308
+ defaultVariants: { variant: "primary", size: "md" }
110
309
  }
111
310
  );
112
- function Avatar({ className, size: size2, ...props }) {
113
- return /* @__PURE__ */ jsx(AvatarPrimitive.Root, { className: cn(avatar({ size: size2 }), className), ...props });
114
- }
115
- function AvatarImage({
311
+ function Button({
116
312
  className,
313
+ variant,
314
+ size: size2,
315
+ asChild = false,
316
+ loading = false,
317
+ icon,
318
+ children,
319
+ disabled,
117
320
  ...props
118
321
  }) {
119
- return /* @__PURE__ */ jsx(AvatarPrimitive.Image, { className: cn("aspect-square size-full object-cover", className), ...props });
322
+ if (asChild) {
323
+ return /* @__PURE__ */ jsx(Slot, { className: cn(button({ variant, size: size2 }), className), ...props, children });
324
+ }
325
+ return /* @__PURE__ */ jsxs(
326
+ "button",
327
+ {
328
+ className: cn(button({ variant, size: size2 }), className),
329
+ disabled: disabled === true || loading,
330
+ "aria-busy": loading || void 0,
331
+ ...props,
332
+ children: [
333
+ loading ? /* @__PURE__ */ jsx(Spinner, {}) : icon,
334
+ children
335
+ ]
336
+ }
337
+ );
120
338
  }
121
- function AvatarFallback({
339
+ var AlertDialog = AlertDialogPrimitive.Root;
340
+ var AlertDialogTrigger = AlertDialogPrimitive.Trigger;
341
+ function AlertDialogOverlay({
122
342
  className,
123
343
  ...props
124
344
  }) {
125
345
  return /* @__PURE__ */ jsx(
126
- AvatarPrimitive.Fallback,
346
+ AlertDialogPrimitive.Overlay,
127
347
  {
128
- className: cn(
129
- "text-label font-mono text-text-secondary flex size-full items-center justify-center uppercase",
130
- className
131
- ),
348
+ className: cn("bg-brand-hull/70 fixed inset-0 z-50", className),
132
349
  ...props
133
350
  }
134
351
  );
135
352
  }
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"
353
+ function AlertDialogContent({
354
+ className,
355
+ children,
356
+ ...props
357
+ }) {
358
+ return /* @__PURE__ */ jsxs(AlertDialogPrimitive.Portal, { children: [
359
+ /* @__PURE__ */ jsx(AlertDialogOverlay, {}),
360
+ /* @__PURE__ */ jsx(
361
+ AlertDialogPrimitive.Content,
362
+ {
363
+ className: cn(
364
+ "fixed top-1/2 left-1/2 z-50 w-full max-w-content -translate-x-1/2 -translate-y-1/2",
365
+ "gap-step-md p-step-lg flex flex-col",
366
+ "rounded-panel border-border bg-surface shadow-standard border",
367
+ "text-text-primary font-sans",
368
+ className
369
+ ),
370
+ ...props,
371
+ children
147
372
  }
148
- },
149
- defaultVariants: { variant: "neutral" }
150
- }
151
- );
152
- function Badge({ className, variant, ...props }) {
153
- return /* @__PURE__ */ jsx("span", { className: cn(badge({ variant }), className), ...props });
373
+ )
374
+ ] });
154
375
  }
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 }) {
376
+ function AlertDialogHeader({ className, ...props }) {
377
+ return /* @__PURE__ */ jsx("div", { className: cn("gap-step-xs flex flex-col", className), ...props });
378
+ }
379
+ function AlertDialogFooter({ className, ...props }) {
173
380
  return /* @__PURE__ */ jsx(
174
- "span",
381
+ "div",
175
382
  {
176
- "data-active": active || void 0,
177
- className: cn(categoria({ active }), className),
383
+ className: cn("gap-step-sm flex flex-col-reverse sm:flex-row sm:justify-end", className),
178
384
  ...props
179
385
  }
180
386
  );
181
387
  }
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 }) {
388
+ function AlertDialogTitle({
389
+ className,
390
+ ...props
391
+ }) {
184
392
  return /* @__PURE__ */ jsx(
185
- "span",
393
+ AlertDialogPrimitive.Title,
186
394
  {
187
- className: cn(metrica, boxed && "border-hairline px-step-sm py-0.5 border", className),
395
+ className: cn("text-h3 font-display text-text-primary", className),
188
396
  ...props
189
397
  }
190
398
  );
191
399
  }
192
- function Glyph({ children, ...props }) {
400
+ function AlertDialogDescription({
401
+ className,
402
+ ...props
403
+ }) {
193
404
  return /* @__PURE__ */ jsx(
194
- "svg",
405
+ AlertDialogPrimitive.Description,
195
406
  {
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
407
+ className: cn("text-ui text-text-secondary max-w-measure", className),
408
+ ...props
208
409
  }
209
410
  );
210
411
  }
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",
412
+ function AlertDialogCancel({
413
+ className,
414
+ ...props
415
+ }) {
416
+ return /* @__PURE__ */ jsx(
417
+ AlertDialogPrimitive.Cancel,
418
+ {
419
+ className: cn(button({ variant: "secondary" }), className),
420
+ ...props
421
+ }
422
+ );
423
+ }
424
+ function AlertDialogAction({
425
+ className,
426
+ ...props
427
+ }) {
428
+ return /* @__PURE__ */ jsx(
429
+ AlertDialogPrimitive.Action,
430
+ {
431
+ className: cn(button({ variant: "primary" }), className),
432
+ ...props
433
+ }
434
+ );
435
+ }
436
+ var avatar = cva(
437
+ "relative flex shrink-0 overflow-hidden rounded-pill bg-surface-raised border border-hairline",
226
438
  {
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
- ]
439
+ variants: {
440
+ size: {
441
+ sm: "size-8",
442
+ md: "size-10",
443
+ lg: "size-14",
444
+ xl: "size-24"
445
+ }
446
+ },
447
+ defaultVariants: { size: "md" }
242
448
  }
243
449
  );
244
- function GlifoMedia({ children, ...props }) {
450
+ function Avatar({ className, size: size2, ...props }) {
451
+ return /* @__PURE__ */ jsx(AvatarPrimitive.Root, { className: cn(avatar({ size: size2 }), className), ...props });
452
+ }
453
+ function AvatarImage({
454
+ className,
455
+ ...props
456
+ }) {
457
+ return /* @__PURE__ */ jsx(AvatarPrimitive.Image, { className: cn("aspect-square size-full object-cover", className), ...props });
458
+ }
459
+ function AvatarFallback({
460
+ className,
461
+ ...props
462
+ }) {
245
463
  return /* @__PURE__ */ jsx(
246
- "svg",
464
+ AvatarPrimitive.Fallback,
247
465
  {
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
466
+ className: cn(
467
+ "text-label font-mono text-text-secondary flex size-full items-center justify-center uppercase",
468
+ className
469
+ ),
470
+ ...props
255
471
  }
256
472
  );
257
473
  }
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,
474
+ var badge = cva(
475
+ ["inline-flex items-center gap-step-xs", "rounded-chip px-step-xs py-0.5", "font-sans text-tag", "transition-standard"],
262
476
  {
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" })
477
+ variants: {
478
+ variant: {
479
+ neutral: "bg-surface-raised text-text-secondary",
480
+ accent: "bg-accent/8 text-text-primary",
481
+ warm: "bg-warm/8 text-text-primary",
482
+ success: "bg-success/8 text-text-primary",
483
+ warning: "bg-warning/8 text-text-primary",
484
+ error: "bg-error/8 text-text-primary"
485
+ }
486
+ },
487
+ defaultVariants: { variant: "neutral" }
269
488
  }
270
489
  );
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",
287
- {
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"
290
- }
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(
490
+ function Badge({ className, variant, ...props }) {
491
+ return /* @__PURE__ */ jsx("span", { className: cn(badge({ variant }), className), ...props });
492
+ }
493
+ var categoria = cva(
296
494
  [
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"
495
+ "inline-flex items-center gap-step-xs",
496
+ "rounded-pill px-step-sm py-0.5",
497
+ "font-mono text-chip",
498
+ "border transition-standard"
303
499
  ],
304
500
  {
305
501
  variants: {
306
- 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"
502
+ active: {
503
+ false: "border-warm/28 bg-transparent text-warm",
504
+ true: "border-warm bg-warm text-warm-on"
327
505
  }
328
506
  },
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" }
507
+ defaultVariants: { active: false }
338
508
  }
339
509
  );
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 });
353
- }
354
- return /* @__PURE__ */ jsxs(
355
- "button",
510
+ function CategoryBadge({ className, active = false, ...props }) {
511
+ return /* @__PURE__ */ jsx(
512
+ "span",
356
513
  {
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
- ]
514
+ "data-active": active || void 0,
515
+ className: cn(categoria({ active }), className),
516
+ ...props
517
+ }
518
+ );
519
+ }
520
+ var metrica = ["inline-flex items-center gap-step-xs", "rounded-pill", "font-mono text-chip text-text-muted"];
521
+ function MetricBadge({ className, boxed = false, ...props }) {
522
+ return /* @__PURE__ */ jsx(
523
+ "span",
524
+ {
525
+ className: cn(metrica, boxed && "border-hairline px-step-sm py-0.5 border", className),
526
+ ...props
365
527
  }
366
528
  );
367
529
  }
@@ -442,80 +604,6 @@ function Calendar({
442
604
  }
443
605
  );
444
606
  }
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
607
  var SUPERFICIE_TARJETA = "rounded-card border-hairline bg-surface border";
520
608
  var HOVER_TARJETA = "transition-standard hover:border-hairline-hover";
521
609
  function Card({ className, ...props }) {
@@ -806,19 +894,6 @@ function Input({ className, invalid = false, ...props }) {
806
894
  }
807
895
  );
808
896
  }
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
897
  function Pagination({ className, ...props }) {
823
898
  return /* @__PURE__ */ jsx(
824
899
  "nav",
@@ -1400,6 +1475,76 @@ function ToastDescription({
1400
1475
  }) {
1401
1476
  return /* @__PURE__ */ jsx(ToastPrimitive.Description, { className: cn("max-w-measure", className), ...props });
1402
1477
  }
1478
+ var avisos = [];
1479
+ var suscriptores = /* @__PURE__ */ new Set();
1480
+ var contador = 0;
1481
+ function emitir(siguientes) {
1482
+ avisos = siguientes;
1483
+ for (const avisar of suscriptores) avisar();
1484
+ }
1485
+ var suscribirse = (avisar) => {
1486
+ suscriptores.add(avisar);
1487
+ return () => {
1488
+ suscriptores.delete(avisar);
1489
+ };
1490
+ };
1491
+ var leer = () => avisos;
1492
+ var VACIO = [];
1493
+ var enServidor = () => VACIO;
1494
+ function crear(mensaje, opciones = {}) {
1495
+ contador += 1;
1496
+ const id = `arrecife-toast-${contador}`;
1497
+ const { description, ...resto } = opciones;
1498
+ emitir([
1499
+ ...avisos,
1500
+ {
1501
+ ...resto,
1502
+ // El primer argumento es la línea principal. Si además llega `title`, el
1503
+ // mensaje pasa a ser la descripción: así `toast('Guardado')` y
1504
+ // `toast('No se pudo guardar', { title: 'Error' })` se leen igual de bien.
1505
+ ...opciones.title ? { description: description ?? mensaje } : { title: mensaje, ...description === void 0 ? {} : { description } },
1506
+ id,
1507
+ abierto: true
1508
+ }
1509
+ ]);
1510
+ return id;
1511
+ }
1512
+ function descartar(id) {
1513
+ emitir(avisos.map((a) => id === void 0 || a.id === id ? { ...a, abierto: false } : a));
1514
+ }
1515
+ function retirar(id) {
1516
+ emitir(avisos.filter((a) => a.id !== id));
1517
+ }
1518
+ var toast2 = Object.assign(crear, {
1519
+ success: (mensaje, opciones = {}) => crear(mensaje, { ...opciones, variant: "success" }),
1520
+ error: (mensaje, opciones = {}) => crear(mensaje, { ...opciones, variant: "error" }),
1521
+ dismiss: descartar
1522
+ });
1523
+ function Toaster({ duration = 5e3, label = "Avisos" }) {
1524
+ const lista = useSyncExternalStore(suscribirse, leer, enServidor);
1525
+ return /* @__PURE__ */ jsxs(ToastProvider, { duration, label, children: [
1526
+ lista.map(({ id, title, description, variant, duration: propio, action, abierto }) => /* @__PURE__ */ jsxs(
1527
+ Toast,
1528
+ {
1529
+ open: abierto,
1530
+ variant: variant ?? "neutral",
1531
+ ...propio === void 0 ? {} : { duration: propio },
1532
+ onOpenChange: (sigue) => {
1533
+ if (!sigue) retirar(id);
1534
+ },
1535
+ children: [
1536
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
1537
+ title ? /* @__PURE__ */ jsx(ToastTitle, { children: title }) : null,
1538
+ description ? /* @__PURE__ */ jsx(ToastDescription, { children: description }) : null
1539
+ ] }),
1540
+ action
1541
+ ]
1542
+ },
1543
+ id
1544
+ )),
1545
+ /* @__PURE__ */ jsx(ToastViewport, {})
1546
+ ] });
1547
+ }
1403
1548
  var TooltipProvider = TooltipPrimitive.Provider;
1404
1549
  var Tooltip = TooltipPrimitive.Root;
1405
1550
  var TooltipTrigger = TooltipPrimitive.Trigger;
@@ -1439,6 +1584,7 @@ function ArticleCard({
1439
1584
  dateTime,
1440
1585
  readingMinutes,
1441
1586
  tags,
1587
+ headingLevel = 3,
1442
1588
  className,
1443
1589
  ...props
1444
1590
  }) {
@@ -1454,7 +1600,15 @@ function ArticleCard({
1454
1600
  i > 0 ? /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\xB7" }) : null,
1455
1601
  m
1456
1602
  ] }, i)) }) : null,
1457
- /* @__PURE__ */ jsx(Text, { as: "h3", variant: "h3", className: "group-hover:text-accent transition-standard", children: title }),
1603
+ /* @__PURE__ */ jsx(
1604
+ Text,
1605
+ {
1606
+ as: headingLevel === 2 ? "h2" : "h3",
1607
+ variant: "h3",
1608
+ className: "group-hover:text-accent transition-standard",
1609
+ children: title
1610
+ }
1611
+ ),
1458
1612
  excerpt ? /* @__PURE__ */ jsx(Text, { variant: "ui", tone: "secondary", className: "line-clamp-2", children: excerpt }) : null,
1459
1613
  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
1614
  ] }) });
@@ -2162,10 +2316,12 @@ function Footer({
2162
2316
  social,
2163
2317
  year = (/* @__PURE__ */ new Date()).getFullYear(),
2164
2318
  children,
2319
+ brand: brand2,
2165
2320
  className,
2166
2321
  ...props
2167
2322
  }) {
2168
2323
  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: [
2324
+ brand2 ? /* @__PURE__ */ jsx("div", { className: "flex items-center", children: brand2 }) : null,
2169
2325
  children ? /* @__PURE__ */ jsx("div", { className: "gap-step-md flex flex-wrap items-center", children }) : null,
2170
2326
  social && social.length > 0 ? (
2171
2327
  // 18px de separación, del documento. No es un escalón de `spacing`:
@@ -2216,9 +2372,11 @@ function Hero({
2216
2372
  action,
2217
2373
  pose,
2218
2374
  basePath,
2375
+ variant = "cabecera",
2219
2376
  className,
2220
2377
  ...props
2221
2378
  }) {
2379
+ const centrado = variant === "centrado";
2222
2380
  return /* @__PURE__ */ jsxs(
2223
2381
  "section",
2224
2382
  {
@@ -2230,13 +2388,39 @@ function Hero({
2230
2388
  ),
2231
2389
  ...props,
2232
2390
  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(
2391
+ centrado && pose ? /* @__PURE__ */ jsx(
2392
+ Mascota,
2393
+ {
2394
+ pose,
2395
+ basePath,
2396
+ className: "mb-step-md mx-auto w-48 md:w-56"
2397
+ }
2398
+ ) : null,
2399
+ /* @__PURE__ */ jsxs(
2400
+ "div",
2401
+ {
2402
+ className: cn(
2403
+ "gap-step-md flex flex-col",
2404
+ centrado ? "items-center text-center" : "md:max-w-[62%]"
2405
+ ),
2406
+ children: [
2407
+ eyebrow ? /* @__PURE__ */ jsx(Text, { variant: "eyebrow", tone: "accent", as: "p", children: eyebrow }) : null,
2408
+ /* @__PURE__ */ jsx(Text, { as: "h1", variant: "display", children: title }),
2409
+ description ? /* @__PURE__ */ jsx(Text, { variant: "body", tone: "secondary", children: description }) : null,
2410
+ action ? /* @__PURE__ */ jsx(
2411
+ "div",
2412
+ {
2413
+ className: cn(
2414
+ "gap-step-sm mt-step-xs flex flex-wrap items-center",
2415
+ centrado && "justify-center"
2416
+ ),
2417
+ children: action
2418
+ }
2419
+ ) : null
2420
+ ]
2421
+ }
2422
+ ),
2423
+ !centrado && pose ? /* @__PURE__ */ jsx(
2240
2424
  Mascota,
2241
2425
  {
2242
2426
  pose,
@@ -2341,6 +2525,10 @@ function NewsletterForm({
2341
2525
  submitLabel = "Suscribirme",
2342
2526
  placeholder = "tu@correo.dev",
2343
2527
  fieldLabel = "Correo electr\xF3nico",
2528
+ nameField = false,
2529
+ nameLabel = "Nombre",
2530
+ namePlaceholder = "C\xF3mo te llamas",
2531
+ nameInputProps,
2344
2532
  className,
2345
2533
  ...props
2346
2534
  }) {
@@ -2351,8 +2539,19 @@ function NewsletterForm({
2351
2539
  evento.preventDefault();
2352
2540
  const datos = new FormData(evento.currentTarget);
2353
2541
  const correo = String(datos.get("email") ?? "");
2354
- onSubmitEmail?.(correo);
2542
+ const nombre = nameField ? String(datos.get("name") ?? "") : void 0;
2543
+ onSubmitEmail?.(correo, nombre);
2355
2544
  }
2545
+ const boton = /* @__PURE__ */ jsx(
2546
+ Button,
2547
+ {
2548
+ type: "submit",
2549
+ variant: "conversion",
2550
+ loading: enviando,
2551
+ className: cn("disabled:opacity-60", nameField && "sm:self-start"),
2552
+ children: submitLabel
2553
+ }
2554
+ );
2356
2555
  return /* @__PURE__ */ jsxs(
2357
2556
  "section",
2358
2557
  {
@@ -2366,34 +2565,44 @@ function NewsletterForm({
2366
2565
  /* @__PURE__ */ jsx(Text, { as: "h2", variant: "h3", children: title }),
2367
2566
  description ? /* @__PURE__ */ jsx(Text, { variant: "ui", tone: "secondary", children: description }) : null
2368
2567
  ] }),
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
- )
2568
+ /* @__PURE__ */ jsxs("form", { onSubmit: enviar, className: "gap-step-sm flex flex-col", noValidate: true, children: [
2569
+ /* @__PURE__ */ jsxs("div", { className: "gap-step-sm flex flex-col sm:flex-row sm:items-end", children: [
2570
+ nameField ? /* @__PURE__ */ jsxs("div", { className: "gap-step-xs flex flex-1 flex-col", children: [
2571
+ /* @__PURE__ */ jsx(Label, { htmlFor: `${id}-nombre`, children: nameLabel }),
2572
+ /* @__PURE__ */ jsx(
2573
+ Input,
2574
+ {
2575
+ id: `${id}-nombre`,
2576
+ name: "name",
2577
+ type: "text",
2578
+ autoComplete: "name",
2579
+ required: true,
2580
+ placeholder: namePlaceholder,
2581
+ disabled: enviando,
2582
+ ...nameInputProps
2583
+ }
2584
+ )
2585
+ ] }) : null,
2586
+ /* @__PURE__ */ jsxs("div", { className: "gap-step-xs flex flex-1 flex-col", children: [
2587
+ /* @__PURE__ */ jsx(Label, { htmlFor: id, children: fieldLabel }),
2588
+ /* @__PURE__ */ jsx(
2589
+ Input,
2590
+ {
2591
+ id,
2592
+ name: "email",
2593
+ type: "email",
2594
+ autoComplete: "email",
2595
+ required: true,
2596
+ placeholder,
2597
+ disabled: enviando,
2598
+ invalid: error,
2599
+ "aria-describedby": state === "exito" || error ? `${id}-aviso` : void 0
2600
+ }
2601
+ )
2602
+ ] }),
2603
+ nameField ? null : boton
2386
2604
  ] }),
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
- )
2605
+ nameField ? boton : null
2397
2606
  ] }),
2398
2607
  state === "exito" ? /* @__PURE__ */ jsx(Alert, { id: `${id}-aviso`, variant: "success", enfasis: "fuerte", children: successMessage }) : null,
2399
2608
  error ? /* @__PURE__ */ jsx(Alert, { id: `${id}-aviso`, variant: "error", enfasis: "fuerte", children: errorMessage }) : null,
@@ -2431,6 +2640,62 @@ function PageHeader({
2431
2640
  action ? /* @__PURE__ */ jsx("div", { className: "gap-step-sm mt-step-sm flex flex-wrap items-center", children: action }) : null
2432
2641
  ] });
2433
2642
  }
2643
+ function ScrollingProgressBar({
2644
+ target,
2645
+ tone = "accent",
2646
+ sticky = true,
2647
+ className,
2648
+ ...props
2649
+ }) {
2650
+ const [avance, setAvance] = useState(0);
2651
+ const pendiente = useRef(0);
2652
+ useEffect(() => {
2653
+ const medir = () => {
2654
+ pendiente.current = 0;
2655
+ const elemento = target?.current;
2656
+ const inicio = elemento ? elemento.getBoundingClientRect().top + scrollY : 0;
2657
+ const alto = elemento ? elemento.offsetHeight : document.documentElement.scrollHeight;
2658
+ const recorrible = alto - innerHeight;
2659
+ if (recorrible <= 0) {
2660
+ setAvance(scrollY >= inicio ? 100 : 0);
2661
+ return;
2662
+ }
2663
+ const recorrido = scrollY - inicio;
2664
+ setAvance(Math.min(100, Math.max(0, recorrido / recorrible * 100)));
2665
+ };
2666
+ const alMoverse = () => {
2667
+ if (pendiente.current) return;
2668
+ pendiente.current = requestAnimationFrame(medir);
2669
+ };
2670
+ medir();
2671
+ addEventListener("scroll", alMoverse, { passive: true });
2672
+ addEventListener("resize", alMoverse);
2673
+ return () => {
2674
+ if (pendiente.current) cancelAnimationFrame(pendiente.current);
2675
+ removeEventListener("scroll", alMoverse);
2676
+ removeEventListener("resize", alMoverse);
2677
+ };
2678
+ }, [target]);
2679
+ return /* @__PURE__ */ jsx(
2680
+ "div",
2681
+ {
2682
+ "aria-hidden": "true",
2683
+ className: cn(
2684
+ "h-1 w-full overflow-hidden",
2685
+ sticky && "sticky top-0 z-40",
2686
+ className
2687
+ ),
2688
+ ...props,
2689
+ children: /* @__PURE__ */ jsx(
2690
+ "div",
2691
+ {
2692
+ className: cn("h-full", tone === "warm" ? "bg-warm" : "bg-accent"),
2693
+ style: { width: `${avance}%` }
2694
+ }
2695
+ )
2696
+ }
2697
+ );
2698
+ }
2434
2699
  function SidebarItem({
2435
2700
  active = false,
2436
2701
  asChild = false,
@@ -2516,6 +2781,7 @@ function TalkCard({
2516
2781
  dateTime,
2517
2782
  location,
2518
2783
  status,
2784
+ description,
2519
2785
  className,
2520
2786
  ...props
2521
2787
  }) {
@@ -2529,12 +2795,43 @@ function TalkCard({
2529
2795
  status ? /* @__PURE__ */ jsx(Badge, { variant: "neutral", children: status }) : null
2530
2796
  ] }),
2531
2797
  /* @__PURE__ */ jsx(Text, { as: "h3", variant: "h3", className: "group-hover:text-accent transition-standard", children: title }),
2798
+ description ? /* @__PURE__ */ jsx(Text, { variant: "ui", tone: "secondary", className: "line-clamp-2", children: description }) : null,
2532
2799
  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
2800
  i > 0 ? /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\xB7" }) : null,
2534
2801
  m
2535
2802
  ] }, i)) }) : null
2536
2803
  ] }) });
2537
2804
  }
2805
+ function ThemeToggle({
2806
+ label = "Cambiar de tema",
2807
+ onThemeChange,
2808
+ variant = "secondary",
2809
+ size: size2 = "icon",
2810
+ className,
2811
+ ...props
2812
+ }) {
2813
+ return /* @__PURE__ */ jsxs(
2814
+ Button,
2815
+ {
2816
+ type: "button",
2817
+ variant,
2818
+ size: size2,
2819
+ "aria-label": label,
2820
+ className: cn("[&_svg]:size-[19px]", className),
2821
+ onClick: () => onThemeChange?.(alternarTema()),
2822
+ ...props,
2823
+ children: [
2824
+ /* @__PURE__ */ jsx(Sol, { className: "light:hidden" }),
2825
+ /* @__PURE__ */ jsx(Luna, { className: "hidden light:block" })
2826
+ ]
2827
+ }
2828
+ );
2829
+ }
2830
+ function useTema() {
2831
+ return useSyncExternalStore(suscribirse2, temaActual, servidor);
2832
+ }
2833
+ var suscribirse2 = (avisar) => escucharTema(() => avisar());
2834
+ var servidor = () => "dark";
2538
2835
  function TableOfContents({
2539
2836
  items,
2540
2837
  title = "En esta p\xE1gina",
@@ -2553,7 +2850,11 @@ function TableOfContents({
2553
2850
  "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent",
2554
2851
  "cursor-pointer",
2555
2852
  item2.nested && "pl-step-lg",
2556
- activo ? "border-accent text-accent" : "border-transparent text-text-secondary hover:text-text-primary"
2853
+ "border-transparent text-text-secondary hover:text-text-primary",
2854
+ // El hover del activo se declara con las dos variantes juntas para
2855
+ // que gane al `hover:` de arriba por especificidad y no por el orden
2856
+ // en que Tailwind decida emitir las reglas.
2857
+ "aria-[current]:border-accent aria-[current]:text-accent aria-[current]:hover:text-accent"
2557
2858
  );
2558
2859
  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
2860
  }) })
@@ -2621,4 +2922,4 @@ var Correo = (props) => /* @__PURE__ */ jsxs(Funcional, { ...props, children: [
2621
2922
  /* @__PURE__ */ jsx("path", { d: "m3.5 7.5 7.4 5.2a2 2 0 0 0 2.2 0l7.4-5.2" })
2622
2923
  ] });
2623
2924
 
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 };
2925
+ export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, Alert, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogTitle, AlertDialogTrigger, 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, 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, Toast, ToastAction, ToastDescription, ToastProvider, ToastTitle, ToastViewport, 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 };