@eduardoalvarez/arrecife 0.5.1 → 0.7.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 (78) hide show
  1. package/CHANGELOG.md +114 -0
  2. package/README.md +868 -467
  3. package/dist/brand/index.cjs +112 -95
  4. package/dist/brand/index.d.cts +40 -39
  5. package/dist/brand/index.d.ts +40 -39
  6. package/dist/brand/index.js +5 -4
  7. package/dist/catalog-D13txprv.d.cts +78 -0
  8. package/dist/catalog-D13txprv.d.ts +78 -0
  9. package/dist/chart/index.cjs +100 -83
  10. package/dist/chart/index.d.cts +66 -66
  11. package/dist/chart/index.d.ts +66 -66
  12. package/dist/chart/index.js +14 -12
  13. package/dist/chunk-2WPWEIMD.js +27 -0
  14. package/dist/chunk-45HVCTB7.js +70 -0
  15. package/dist/{chunk-ZEOQKRQ7.js → chunk-727HCBD4.js} +1 -1
  16. package/dist/chunk-CKRSQPTX.js +36 -0
  17. package/dist/chunk-E6KFUSKB.js +144 -0
  18. package/dist/chunk-GCRII2KQ.js +86 -0
  19. package/dist/{chunk-YZ2SDOVZ.js → chunk-JN3IS5OS.js} +30 -30
  20. package/dist/chunk-ODBFN44D.js +45 -0
  21. package/dist/chunk-OMKSESQB.js +300 -0
  22. package/dist/{chunk-VPT32GPG.js → chunk-TA7TLWW4.js} +2 -2
  23. package/dist/chunk-WGNIRIN7.js +42 -0
  24. package/dist/doctor.mjs +166 -0
  25. package/dist/form/index.cjs +109 -92
  26. package/dist/form/index.d.cts +43 -42
  27. package/dist/form/index.d.ts +43 -42
  28. package/dist/form/index.js +25 -23
  29. package/dist/icons/index.cjs +149 -0
  30. package/dist/icons/index.d.cts +94 -0
  31. package/dist/icons/index.d.ts +94 -0
  32. package/dist/icons/index.js +28 -0
  33. package/dist/index-DlAO2JZs.d.cts +47 -0
  34. package/dist/index-DlAO2JZs.d.ts +47 -0
  35. package/dist/index.cjs +1292 -983
  36. package/dist/index.d.cts +927 -806
  37. package/dist/index.d.ts +927 -806
  38. package/dist/index.js +809 -778
  39. package/dist/{label-DuTvJGxD.d.ts → label-MgHFKnFy.d.cts} +3 -3
  40. package/dist/{label-DuTvJGxD.d.cts → label-MgHFKnFy.d.ts} +3 -3
  41. package/dist/og/index.cjs +133 -132
  42. package/dist/og/index.d.cts +93 -89
  43. package/dist/og/index.d.ts +93 -89
  44. package/dist/og/index.js +106 -106
  45. package/dist/shiki/index.cjs +28 -30
  46. package/dist/shiki/index.d.cts +4 -4
  47. package/dist/shiki/index.d.ts +4 -4
  48. package/dist/shiki/index.js +12 -12
  49. package/dist/social/index.cjs +67 -0
  50. package/dist/social/index.d.cts +2 -0
  51. package/dist/social/index.d.ts +2 -0
  52. package/dist/social/index.js +2 -0
  53. package/dist/theme/index.cjs +97 -0
  54. package/dist/theme/index.d.cts +144 -0
  55. package/dist/theme/index.d.ts +144 -0
  56. package/dist/theme/index.js +2 -0
  57. package/dist/tokens/index.cjs +159 -88
  58. package/dist/tokens/index.d.cts +277 -165
  59. package/dist/tokens/index.d.ts +277 -165
  60. package/dist/tokens/index.js +2 -2
  61. package/dist/tokens/theme.css +165 -100
  62. package/dist/variants/index.cjs +195 -0
  63. package/dist/variants/index.d.cts +195 -0
  64. package/dist/variants/index.d.ts +195 -0
  65. package/dist/variants/index.js +3 -0
  66. package/llms.txt +1145 -746
  67. package/package.json +42 -11
  68. package/dist/catalogo-Du5ID-Hi.d.cts +0 -77
  69. package/dist/catalogo-Du5ID-Hi.d.ts +0 -77
  70. package/dist/chunk-E3OMP2DL.js +0 -36
  71. package/dist/chunk-KPZNNMV5.js +0 -83
  72. package/dist/chunk-NHS7ETKJ.js +0 -27
  73. package/dist/chunk-TSPJOM6K.js +0 -229
  74. package/dist/chunk-UOWIDFCB.js +0 -81
  75. package/dist/tema/index.cjs +0 -94
  76. package/dist/tema/index.d.cts +0 -110
  77. package/dist/tema/index.d.ts +0 -110
  78. package/dist/tema/index.js +0 -2
package/dist/index.js CHANGED
@@ -1,25 +1,30 @@
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';
6
- export { RUTA_ASSETS, aletas, caras, listaCaras, listaPoses, poses, usoDeCara } from './chunk-E3OMP2DL.js';
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';
1
+ 'use client';
2
+ import { Label } from './chunk-727HCBD4.js';
3
+ export { Label } from './chunk-727HCBD4.js';
4
+ import { Text } from './chunk-WGNIRIN7.js';
5
+ export { Text } from './chunk-WGNIRIN7.js';
6
+ export { tokens } from './chunk-TA7TLWW4.js';
7
+ import { toggleTheme, currentTheme, watchTheme } from './chunk-GCRII2KQ.js';
8
+ export { THEME_ATTRIBUTE, THEME_EVENT, THEME_KEY, applyTheme, currentTheme, preferredTheme, storedTheme, themeScript, toggleTheme, watchTheme } from './chunk-GCRII2KQ.js';
9
+ import { alert, button, avatar, badge, category, metric, CARD_SURFACE, CARD } from './chunk-E6KFUSKB.js';
10
+ export { CARD, CARD_HOVER, CARD_SURFACE, alert as alertVariants, avatar as avatarVariants, badge as badgeVariants, button as buttonVariants, category as categoryBadgeVariants, metric as metricBadgeVariants } from './chunk-E6KFUSKB.js';
11
+ export { text as textVariants } from './chunk-ODBFN44D.js';
12
+ import { MascotFace, Mascot } from './chunk-JN3IS5OS.js';
13
+ export { Isotype, Logo, Mascot, MascotFace } from './chunk-JN3IS5OS.js';
14
+ export { social_exports as social } from './chunk-45HVCTB7.js';
15
+ import { cn } from './chunk-2WPWEIMD.js';
16
+ export { cn } from './chunk-2WPWEIMD.js';
17
+ export { ASSETS_PATH, faceList, faceUsage, faces, fins, poseList, poses } from './chunk-CKRSQPTX.js';
18
+ import { naming } from './chunk-OMKSESQB.js';
19
+ export { brand, colors, control, dark, fonts, gradient, light, limits, motion, naming, radius, series, shadow, size, spacing, syntax, tagline, typeScale } from './chunk-OMKSESQB.js';
20
+ import './chunk-MLKGABMK.js';
16
21
  import * as AccordionPrimitive from '@radix-ui/react-accordion';
17
22
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
18
23
  import { cva } from 'class-variance-authority';
19
24
  import * as AlertDialogPrimitive from '@radix-ui/react-alert-dialog';
20
- import { Slot } from '@radix-ui/react-slot';
21
25
  import * as AvatarPrimitive from '@radix-ui/react-avatar';
22
- import { useId, useState, useEffect, useSyncExternalStore, useRef, useCallback } from 'react';
26
+ import { createContext, useId, useState, useEffect, useSyncExternalStore, useRef, useCallback, useContext } from 'react';
27
+ import { Slot } from '@radix-ui/react-slot';
23
28
  import { es } from 'date-fns/locale';
24
29
  import { DayPicker } from 'react-day-picker';
25
30
  import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
@@ -88,16 +93,16 @@ var Spinner = (props) => /* @__PURE__ */ jsxs(
88
93
  ]
89
94
  }
90
95
  );
91
- var Camara = (props) => /* @__PURE__ */ jsxs(Glyph, { ...props, children: [
96
+ var Camera = (props) => /* @__PURE__ */ jsxs(Glyph, { ...props, children: [
92
97
  /* @__PURE__ */ jsx("path", { d: "M2 5.5h2.6l1-1.5h4.8l1 1.5H14v7.5H2z" }),
93
98
  /* @__PURE__ */ jsx("circle", { cx: "8", cy: "9", r: "2.4" })
94
99
  ] });
95
- var Sol = (props) => /* @__PURE__ */ jsxs(Glyph, { ...props, children: [
100
+ var Sun = (props) => /* @__PURE__ */ jsxs(Glyph, { ...props, children: [
96
101
  /* @__PURE__ */ jsx("circle", { cx: "8", cy: "8", r: "3" }),
97
102
  /* @__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
103
  ] });
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 }) {
104
+ var Moon = (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" }) });
105
+ function MediaGlyph({ children, ...props }) {
101
106
  return /* @__PURE__ */ jsx(
102
107
  "svg",
103
108
  {
@@ -111,10 +116,10 @@ function GlifoMedia({ children, ...props }) {
111
116
  }
112
117
  );
113
118
  }
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" }) });
119
+ var Play = (props) => /* @__PURE__ */ jsx(MediaGlyph, { fill: "currentColor", ...props, children: /* @__PURE__ */ jsx("path", { d: "M8 5v14l11-7z" }) });
120
+ var Pause = (props) => /* @__PURE__ */ jsx(MediaGlyph, { fill: "currentColor", ...props, children: /* @__PURE__ */ jsx("path", { d: "M6 4h4v16H6V4zm8 0h4v16h-4V4z" }) });
116
121
  var Retry = (props) => /* @__PURE__ */ jsx(
117
- GlifoMedia,
122
+ MediaGlyph,
118
123
  {
119
124
  stroke: "currentColor",
120
125
  strokeWidth: 2,
@@ -124,7 +129,7 @@ var Retry = (props) => /* @__PURE__ */ jsx(
124
129
  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
130
  }
126
131
  );
127
- var GoBackSeconds = (props) => /* @__PURE__ */ jsxs(GlifoMedia, { stroke: "currentColor", strokeWidth: 1.5, strokeLinecap: "round", ...props, children: [
132
+ var GoBackSeconds = (props) => /* @__PURE__ */ jsxs(MediaGlyph, { stroke: "currentColor", strokeWidth: 1.5, strokeLinecap: "round", ...props, children: [
128
133
  /* @__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
134
  /* @__PURE__ */ jsx("path", { d: "M7.5 10.5L10 8.5V15.5", strokeLinejoin: "round" }),
130
135
  /* @__PURE__ */ jsx(
@@ -135,7 +140,7 @@ var GoBackSeconds = (props) => /* @__PURE__ */ jsxs(GlifoMedia, { stroke: "curre
135
140
  }
136
141
  )
137
142
  ] });
138
- var AdvanceSeconds = (props) => /* @__PURE__ */ jsxs(GlifoMedia, { stroke: "currentColor", strokeWidth: 1.5, strokeLinecap: "round", ...props, children: [
143
+ var AdvanceSeconds = (props) => /* @__PURE__ */ jsxs(MediaGlyph, { stroke: "currentColor", strokeWidth: 1.5, strokeLinecap: "round", ...props, children: [
139
144
  /* @__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
145
  /* @__PURE__ */ jsx("path", { d: "M7.5 10.5L10 8.5V15.5", strokeLinejoin: "round" }),
141
146
  /* @__PURE__ */ jsx(
@@ -146,8 +151,8 @@ var AdvanceSeconds = (props) => /* @__PURE__ */ jsxs(GlifoMedia, { stroke: "curr
146
151
  }
147
152
  )
148
153
  ] });
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" }) });
154
+ var VolumeOn = (props) => /* @__PURE__ */ jsx(MediaGlyph, { 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" }) });
155
+ var VolumeMuted = (props) => /* @__PURE__ */ jsx(MediaGlyph, { 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
156
  function Accordion({ className, ...props }) {
152
157
  return /* @__PURE__ */ jsx(
153
158
  AccordionPrimitive.Root,
@@ -169,8 +174,8 @@ function AccordionTrigger({
169
174
  headingLevel = 3,
170
175
  ...props
171
176
  }) {
172
- const Encabezado = `h${headingLevel}`;
173
- return /* @__PURE__ */ jsx(AccordionPrimitive.Header, { asChild: true, children: /* @__PURE__ */ jsx(Encabezado, { children: /* @__PURE__ */ jsxs(
177
+ const Heading = `h${headingLevel}`;
178
+ return /* @__PURE__ */ jsx(AccordionPrimitive.Header, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { children: /* @__PURE__ */ jsxs(
174
179
  AccordionPrimitive.Trigger,
175
180
  {
176
181
  className: cn(
@@ -178,7 +183,7 @@ function AccordionTrigger({
178
183
  "font-sans text-lead font-medium text-text-primary",
179
184
  "transition-standard",
180
185
  "hover:text-accent",
181
- "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent",
186
+ "focus-ring",
182
187
  "disabled:pointer-events-none disabled:opacity-50",
183
188
  "[&[data-state=open]>svg]:rotate-180",
184
189
  className
@@ -201,45 +206,20 @@ function AccordionContent({
201
206
  {
202
207
  className: cn(
203
208
  "overflow-hidden",
204
- "motion-safe:data-[state=open]:desplegar motion-safe:data-[state=closed]:replegar"
209
+ "motion-safe:data-[state=open]:expand motion-safe:data-[state=closed]:collapse"
205
210
  ),
206
211
  ...props,
207
212
  children: /* @__PURE__ */ jsx("div", { className: cn("pb-step-md font-sans text-ui text-text-secondary max-w-measure", className), children })
208
213
  }
209
214
  );
210
215
  }
211
- var alert = cva("w-full rounded-card border p-step-md font-sans text-ui", {
212
- variants: {
213
- variant: {
214
- accent: "text-text-secondary",
215
- success: "text-text-secondary",
216
- warning: "text-text-secondary",
217
- error: "text-text-secondary"
218
- },
219
- enfasis: {
220
- sutil: "",
221
- fuerte: ""
222
- }
223
- },
224
- compoundVariants: [
225
- { variant: "accent", enfasis: "sutil", class: "border-accent/22 bg-accent/8" },
226
- { variant: "success", enfasis: "sutil", class: "border-success/22 bg-success/8" },
227
- { variant: "warning", enfasis: "sutil", class: "border-warning/22 bg-warning/8" },
228
- { variant: "error", enfasis: "sutil", class: "border-error/22 bg-error/8" },
229
- { variant: "accent", enfasis: "fuerte", class: "border-accent bg-accent/10" },
230
- { variant: "success", enfasis: "fuerte", class: "border-success bg-success/10" },
231
- { variant: "warning", enfasis: "fuerte", class: "border-warning bg-warning/10" },
232
- { variant: "error", enfasis: "fuerte", class: "border-error bg-error/10" }
233
- ],
234
- defaultVariants: { variant: "accent", enfasis: "sutil" }
235
- });
236
- var glifoColor = {
216
+ var colorGlyph = {
237
217
  accent: "text-accent",
238
218
  success: "text-success",
239
219
  warning: "text-warning",
240
220
  error: "text-error"
241
221
  };
242
- var GLIFO = {
222
+ var GLYPH = {
243
223
  accent: "\u2726",
244
224
  success: "\u2713",
245
225
  warning: "!",
@@ -248,26 +228,26 @@ var GLIFO = {
248
228
  function Alert({
249
229
  className,
250
230
  variant,
251
- enfasis,
231
+ emphasis,
252
232
  title,
253
233
  icon,
254
234
  children,
255
235
  ...props
256
236
  }) {
257
- const tono = variant ?? "accent";
237
+ const tone = variant ?? "accent";
258
238
  return /* @__PURE__ */ jsx(
259
239
  "div",
260
240
  {
261
- role: tono === "error" ? "alert" : "status",
262
- className: cn(alert({ variant, enfasis }), className),
241
+ role: tone === "error" ? "alert" : "status",
242
+ className: cn(alert({ variant, emphasis }), className),
263
243
  ...props,
264
244
  children: /* @__PURE__ */ jsxs("div", { className: "gap-step-sm flex items-start", children: [
265
245
  /* @__PURE__ */ jsx(
266
246
  "span",
267
247
  {
268
248
  "aria-hidden": "true",
269
- className: cn("font-mono text-ui leading-normal select-none", glifoColor[tono]),
270
- children: icon ?? GLIFO[tono]
249
+ className: cn("font-mono text-ui leading-normal select-none", colorGlyph[tone]),
250
+ children: icon ?? GLYPH[tone]
271
251
  }
272
252
  ),
273
253
  /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
@@ -278,79 +258,6 @@ function Alert({
278
258
  }
279
259
  );
280
260
  }
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
- ],
290
- {
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
- },
307
- size: {
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"
313
- }
314
- },
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" }
324
- }
325
- );
326
- function Button({
327
- className,
328
- variant,
329
- size: size2,
330
- asChild = false,
331
- loading = false,
332
- icon,
333
- children,
334
- disabled,
335
- ...props
336
- }) {
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
- );
353
- }
354
261
  var AlertDialog = AlertDialogPrimitive.Root;
355
262
  var AlertDialogTrigger = AlertDialogPrimitive.Trigger;
356
263
  function AlertDialogOverlay({
@@ -448,20 +355,6 @@ function AlertDialogAction({
448
355
  }
449
356
  );
450
357
  }
451
- var avatar = cva(
452
- "relative flex shrink-0 overflow-hidden rounded-pill bg-surface-raised border border-hairline",
453
- {
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" }
463
- }
464
- );
465
358
  function Avatar({ className, size: size2, ...props }) {
466
359
  return /* @__PURE__ */ jsx(AvatarPrimitive.Root, { className: cn(avatar({ size: size2 }), className), ...props });
467
360
  }
@@ -498,22 +391,22 @@ function AvatarUpload({
498
391
  ...props
499
392
  }) {
500
393
  const id = useId();
501
- const [previa, setPrevia] = useState(null);
394
+ const [preview, setPreview] = useState(null);
502
395
  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 = "";
396
+ if (!preview) return;
397
+ return () => URL.revokeObjectURL(preview);
398
+ }, [preview]);
399
+ function pick(event) {
400
+ const file = event.target.files?.[0];
401
+ if (!file) return;
402
+ setPreview(URL.createObjectURL(file));
403
+ onSelectFile?.(file);
404
+ event.target.value = "";
512
405
  }
513
- const imagen = previa ?? src;
406
+ const image = preview ?? src;
514
407
  return /* @__PURE__ */ jsxs("div", { className: cn("relative inline-flex", className), ...props, children: [
515
408
  /* @__PURE__ */ jsxs(Avatar, { size: size2, children: [
516
- imagen ? /* @__PURE__ */ jsx(AvatarImage, { src: imagen, alt: "" }) : null,
409
+ image ? /* @__PURE__ */ jsx(AvatarImage, { src: image, alt: "" }) : null,
517
410
  /* @__PURE__ */ jsx(AvatarFallback, { children: fallback })
518
411
  ] }),
519
412
  /* @__PURE__ */ jsxs(
@@ -524,13 +417,13 @@ function AvatarUpload({
524
417
  "rounded-pill absolute -right-1 -bottom-1 flex size-6 cursor-pointer items-center justify-center",
525
418
  "border-hairline bg-surface-raised text-text-secondary border",
526
419
  "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",
420
+ // Focus lives on the input, which is hidden: without this, tabbing to
421
+ // the control shows up nowhere.
422
+ "has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-3 has-[:focus-visible]:outline-accent",
530
423
  disabled && "pointer-events-none opacity-50"
531
424
  ),
532
425
  children: [
533
- /* @__PURE__ */ jsx(Camara, { "aria-hidden": "true" }),
426
+ /* @__PURE__ */ jsx(Camera, { "aria-hidden": "true" }),
534
427
  /* @__PURE__ */ jsx("span", { className: "sr-only", children: label }),
535
428
  /* @__PURE__ */ jsx(
536
429
  "input",
@@ -539,7 +432,7 @@ function AvatarUpload({
539
432
  type: "file",
540
433
  accept,
541
434
  disabled,
542
- onChange: elegir,
435
+ onChange: pick,
543
436
  className: "sr-only"
544
437
  }
545
438
  )
@@ -548,62 +441,56 @@ function AvatarUpload({
548
441
  )
549
442
  ] });
550
443
  }
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"],
553
- {
554
- variants: {
555
- variant: {
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"
562
- }
563
- },
564
- defaultVariants: { variant: "neutral" }
565
- }
566
- );
567
444
  function Badge({ className, variant, ...props }) {
568
445
  return /* @__PURE__ */ jsx("span", { className: cn(badge({ variant }), className), ...props });
569
446
  }
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 }
585
- }
586
- );
587
447
  function CategoryBadge({ className, active = false, ...props }) {
588
448
  return /* @__PURE__ */ jsx(
589
449
  "span",
590
450
  {
591
451
  "data-active": active || void 0,
592
- className: cn(categoria({ active }), className),
452
+ className: cn(category({ active }), className),
593
453
  ...props
594
454
  }
595
455
  );
596
456
  }
597
- var metrica = ["inline-flex items-center gap-step-xs", "rounded-pill", "font-mono text-chip text-text-muted"];
598
457
  function MetricBadge({ className, boxed = false, ...props }) {
599
458
  return /* @__PURE__ */ jsx(
600
459
  "span",
601
460
  {
602
- className: cn(metrica, boxed && "border-hairline px-step-sm py-0.5 border", className),
461
+ className: cn(metric, boxed && "border-hairline px-step-sm py-0.5 border", className),
603
462
  ...props
604
463
  }
605
464
  );
606
465
  }
466
+ function Button({
467
+ className,
468
+ variant,
469
+ size: size2,
470
+ asChild = false,
471
+ loading = false,
472
+ icon,
473
+ children,
474
+ disabled,
475
+ ...props
476
+ }) {
477
+ if (asChild) {
478
+ return /* @__PURE__ */ jsx(Slot, { className: cn(button({ variant, size: size2 }), className), ...props, children });
479
+ }
480
+ return /* @__PURE__ */ jsxs(
481
+ "button",
482
+ {
483
+ className: cn(button({ variant, size: size2 }), className),
484
+ disabled: disabled === true || loading,
485
+ "aria-busy": loading || void 0,
486
+ ...props,
487
+ children: [
488
+ loading ? /* @__PURE__ */ jsx(Spinner, {}) : icon,
489
+ children
490
+ ]
491
+ }
492
+ );
493
+ }
607
494
  function Calendar({
608
495
  className,
609
496
  classNames,
@@ -611,24 +498,24 @@ function Calendar({
611
498
  fullWidth = false,
612
499
  ...props
613
500
  }) {
614
- const dia = [
501
+ const day = [
615
502
  "relative p-0 text-center",
616
503
  fullWidth ? "h-9 flex-1" : "size-9",
617
504
  "text-ui font-sans text-text-primary"
618
505
  ].join(" ");
619
- const botonDia = [
506
+ const dayButton = [
620
507
  fullWidth ? "h-9 w-full" : "size-9",
621
508
  "rounded-chip inline-flex items-center justify-center",
622
509
  "transition-standard cursor-pointer",
623
510
  "hover:bg-surface-raised",
624
- "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent",
511
+ "focus-ring",
625
512
  "disabled:pointer-events-none disabled:opacity-50"
626
513
  ].join(" ");
627
- const navegacion = [
514
+ const navigation = [
628
515
  "size-8 rounded-chip inline-flex items-center justify-center",
629
516
  "text-text-secondary transition-standard cursor-pointer",
630
517
  "hover:bg-surface-raised hover:text-text-primary",
631
- "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent",
518
+ "focus-ring",
632
519
  "disabled:pointer-events-none disabled:opacity-50"
633
520
  ].join(" ");
634
521
  return /* @__PURE__ */ jsx(
@@ -638,32 +525,32 @@ function Calendar({
638
525
  showOutsideDays,
639
526
  className: cn("font-sans", className),
640
527
  classNames: {
641
- // `relative` obligatorio: la navegación se posiciona en absoluto contra
642
- // la raíz, y sin esto se ancla al primer ancestro posicionado —o al
643
- // viewport— y las flechas acaban en los bordes de la página.
528
+ // `relative` is mandatory: the navigation is absolutely positioned
529
+ // against the root, and without this it anchors to the first positioned
530
+ // ancestor — or to the viewport — and the arrows end up at the page edges.
644
531
  root: cn("relative", fullWidth ? "w-full" : "w-fit"),
645
532
  months: cn("gap-step-md flex flex-col sm:flex-row", fullWidth && "w-full"),
646
533
  month: cn("gap-step-sm flex flex-col", fullWidth && "min-w-0 flex-1"),
647
534
  month_caption: "h-8 flex items-center justify-center",
648
535
  caption_label: "text-ui font-sans font-medium text-text-primary capitalize",
649
536
  nav: "absolute inset-x-0 top-0 flex items-center justify-between",
650
- button_previous: navegacion,
651
- button_next: navegacion,
537
+ button_previous: navigation,
538
+ button_next: navigation,
652
539
  month_grid: "w-full border-collapse",
653
540
  weekdays: cn("flex", fullWidth && "w-full"),
654
- // `textMuted` no va sobre `surfaceRaised` —4.07:1—, y un calendario dentro de
655
- // un Popover vive justo ahí.
541
+ // `textMuted` does not go over `surfaceRaised` — 4.07:1 — and a calendar
542
+ // inside a Popover lives exactly there.
656
543
  weekday: cn(
657
544
  "h-9 text-eyebrow font-mono text-text-secondary uppercase flex items-center justify-center",
658
545
  fullWidth ? "flex-1" : "w-9"
659
546
  ),
660
547
  week: "flex w-full",
661
- day: dia,
662
- day_button: botonDia,
548
+ day,
549
+ day_button: dayButton,
663
550
  today: "text-accent font-medium",
664
- // Los días de los meses vecinos se atenúan, pero no por debajo de AA:
665
- // `textSecondary` al 85 % da 5.09:1 en el peor caso, que es sobre
666
- // `surfaceRaised`. Al 75 % ya no pasa en modo claro.
551
+ // Days from neighbouring months are dimmed, but not below AA:
552
+ // `textSecondary` at 85 % gives 5.09:1 in the worst case, which is over
553
+ // `surfaceRaised`. At 75 % it no longer passes in light mode.
667
554
  outside: "text-text-secondary opacity-85",
668
555
  disabled: "opacity-50",
669
556
  hidden: "invisible",
@@ -681,10 +568,8 @@ function Calendar({
681
568
  }
682
569
  );
683
570
  }
684
- var SUPERFICIE_TARJETA = "rounded-card border-hairline bg-surface border";
685
- var HOVER_TARJETA = "transition-standard hover:border-hairline-hover";
686
571
  function Card({ className, ...props }) {
687
- return /* @__PURE__ */ jsx("div", { className: cn(SUPERFICIE_TARJETA, className), ...props });
572
+ return /* @__PURE__ */ jsx("div", { className: cn(CARD_SURFACE, className), ...props });
688
573
  }
689
574
  function CardHeader({ className, ...props }) {
690
575
  return /* @__PURE__ */ jsx("div", { className: cn("gap-step-xs p-step-lg flex flex-col", className), ...props });
@@ -715,7 +600,7 @@ function Checkbox({ className, ...props }) {
715
600
  "rounded-chip border-border bg-surface size-5 shrink-0 cursor-pointer border",
716
601
  "text-accent-on transition-standard",
717
602
  "hover:border-hairline-hover",
718
- "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent",
603
+ "focus-ring",
719
604
  "disabled:pointer-events-none disabled:opacity-50",
720
605
  "data-[state=checked]:border-accent data-[state=checked]:bg-accent",
721
606
  "data-[state=indeterminate]:border-accent data-[state=indeterminate]:bg-accent",
@@ -758,10 +643,10 @@ function DateField({
758
643
  "font-mono text-ui text-text-primary",
759
644
  "transition-standard",
760
645
  "hover:border-hairline-hover",
761
- "focus-visible:border-accent focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent",
646
+ "focus-visible:border-accent focus-ring",
762
647
  "disabled:pointer-events-none disabled:opacity-50",
763
648
  "data-[invalid]:border-error data-[invalid]:focus-visible:outline-error",
764
- // El indicador nativo hereda el esquema del tema activo.
649
+ // The native indicator inherits the active theme's scheme.
765
650
  "scheme-light dark:scheme-dark [&::-webkit-calendar-picker-indicator]:cursor-pointer",
766
651
  className
767
652
  ),
@@ -812,7 +697,7 @@ function DialogContent({
812
697
  "rounded-chip text-text-muted absolute top-4 right-4 flex size-8 cursor-pointer items-center justify-center",
813
698
  "transition-standard",
814
699
  "hover:bg-surface-raised hover:text-text-primary",
815
- "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent"
700
+ "focus-ring"
816
701
  ),
817
702
  children: /* @__PURE__ */ jsx(Close, {})
818
703
  }
@@ -961,7 +846,7 @@ function Input({ className, invalid = false, ...props }) {
961
846
  "font-sans text-ui text-text-primary placeholder:text-text-muted",
962
847
  "transition-standard",
963
848
  "hover:border-hairline-hover",
964
- "focus-visible:border-accent focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent",
849
+ "focus-visible:border-accent focus-ring",
965
850
  "disabled:pointer-events-none disabled:opacity-50",
966
851
  "data-[invalid]:border-error data-[invalid]:focus-visible:outline-error",
967
852
  "file:mr-step-sm file:border-0 file:bg-transparent file:font-sans file:text-label file:text-text-secondary",
@@ -998,7 +883,7 @@ function PaginationLink({ className, isActive = false, ...props }) {
998
883
  "font-sans text-ui text-text-secondary",
999
884
  "transition-standard",
1000
885
  "hover:bg-surface hover:text-text-primary",
1001
- "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent",
886
+ "focus-ring",
1002
887
  isActive && "bg-surface-raised text-text-primary",
1003
888
  className
1004
889
  ),
@@ -1083,7 +968,7 @@ function RadioGroupItem({ className, ...props }) {
1083
968
  "rounded-pill border-border bg-surface size-5 shrink-0 cursor-pointer border",
1084
969
  "transition-standard",
1085
970
  "hover:border-hairline-hover",
1086
- "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent",
971
+ "focus-ring",
1087
972
  "disabled:pointer-events-none disabled:opacity-50",
1088
973
  "data-[state=checked]:border-accent",
1089
974
  className
@@ -1110,7 +995,7 @@ function SelectTrigger({
1110
995
  "font-sans text-ui text-text-primary",
1111
996
  "transition-standard",
1112
997
  "hover:border-hairline-hover",
1113
- "focus-visible:border-accent focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent",
998
+ "focus-visible:border-accent focus-ring",
1114
999
  "disabled:pointer-events-none disabled:opacity-50",
1115
1000
  "data-[placeholder]:text-text-muted",
1116
1001
  className
@@ -1224,23 +1109,23 @@ var panel2 = cva(
1224
1109
  side: {
1225
1110
  right: [
1226
1111
  "inset-y-0 right-0 h-full w-3/4 max-w-content border-l",
1227
- "motion-safe:data-[state=open]:deslizar-entra-derecha",
1228
- "motion-safe:data-[state=closed]:deslizar-sale-derecha"
1112
+ "motion-safe:data-[state=open]:slide-in-right",
1113
+ "motion-safe:data-[state=closed]:slide-out-right"
1229
1114
  ],
1230
1115
  left: [
1231
1116
  "inset-y-0 left-0 h-full w-3/4 max-w-content border-r",
1232
- "motion-safe:data-[state=open]:deslizar-entra-izquierda",
1233
- "motion-safe:data-[state=closed]:deslizar-sale-izquierda"
1117
+ "motion-safe:data-[state=open]:slide-in-left",
1118
+ "motion-safe:data-[state=closed]:slide-out-left"
1234
1119
  ],
1235
1120
  top: [
1236
1121
  "inset-x-0 top-0 border-b",
1237
- "motion-safe:data-[state=open]:deslizar-entra-arriba",
1238
- "motion-safe:data-[state=closed]:deslizar-sale-arriba"
1122
+ "motion-safe:data-[state=open]:slide-in-top",
1123
+ "motion-safe:data-[state=closed]:slide-out-top"
1239
1124
  ],
1240
1125
  bottom: [
1241
1126
  "inset-x-0 bottom-0 border-t",
1242
- "motion-safe:data-[state=open]:deslizar-entra-abajo",
1243
- "motion-safe:data-[state=closed]:deslizar-sale-abajo"
1127
+ "motion-safe:data-[state=open]:slide-in-bottom",
1128
+ "motion-safe:data-[state=closed]:slide-out-bottom"
1244
1129
  ]
1245
1130
  }
1246
1131
  },
@@ -1260,7 +1145,7 @@ function SheetContent({ className, side, children, ...props }) {
1260
1145
  "rounded-chip text-text-muted absolute top-4 right-4 flex size-8 cursor-pointer items-center justify-center",
1261
1146
  "transition-standard",
1262
1147
  "hover:bg-surface-raised hover:text-text-primary",
1263
- "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent"
1148
+ "focus-ring"
1264
1149
  ),
1265
1150
  children: /* @__PURE__ */ jsx(Close, {})
1266
1151
  }
@@ -1335,7 +1220,7 @@ function Switch({ className, ...props }) {
1335
1220
  "rounded-pill border-border bg-surface-raised inline-flex h-6 w-11 shrink-0 cursor-pointer items-center border",
1336
1221
  "transition-standard",
1337
1222
  "hover:border-hairline-hover",
1338
- "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent",
1223
+ "focus-ring",
1339
1224
  "disabled:pointer-events-none disabled:opacity-50",
1340
1225
  "data-[state=checked]:border-accent data-[state=checked]:bg-accent",
1341
1226
  className
@@ -1436,7 +1321,7 @@ function TabsTrigger({
1436
1321
  "font-sans text-label text-text-secondary",
1437
1322
  "transition-standard",
1438
1323
  "hover:text-text-primary",
1439
- "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent",
1324
+ "focus-ring",
1440
1325
  "disabled:pointer-events-none disabled:opacity-50",
1441
1326
  "data-[state=active]:bg-surface-raised data-[state=active]:text-text-primary",
1442
1327
  className
@@ -1453,7 +1338,7 @@ function TabsContent({
1453
1338
  TabsPrimitive.Content,
1454
1339
  {
1455
1340
  className: cn(
1456
- "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent",
1341
+ "focus-ring",
1457
1342
  className
1458
1343
  ),
1459
1344
  ...props
@@ -1472,7 +1357,7 @@ function Textarea({ className, invalid = false, ...props }) {
1472
1357
  "font-sans text-ui text-text-primary placeholder:text-text-muted",
1473
1358
  "transition-standard",
1474
1359
  "hover:border-hairline-hover",
1475
- "focus-visible:border-accent focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent",
1360
+ "focus-visible:border-accent focus-ring",
1476
1361
  "disabled:pointer-events-none disabled:opacity-50",
1477
1362
  "data-[invalid]:border-error data-[invalid]:focus-visible:outline-error",
1478
1363
  className
@@ -1527,7 +1412,7 @@ function Toast({ className, variant, children, ...props }) {
1527
1412
  "rounded-chip text-text-muted absolute top-3 right-3 flex size-7 cursor-pointer items-center justify-center",
1528
1413
  "transition-standard",
1529
1414
  "hover:bg-surface-raised hover:text-text-primary",
1530
- "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent"
1415
+ "focus-ring"
1531
1416
  ),
1532
1417
  children: /* @__PURE__ */ jsx(Close, {})
1533
1418
  }
@@ -1552,62 +1437,62 @@ function ToastDescription({
1552
1437
  }) {
1553
1438
  return /* @__PURE__ */ jsx(ToastPrimitive.Description, { className: cn("max-w-measure", className), ...props });
1554
1439
  }
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();
1440
+ var warnings = [];
1441
+ var subscribers = /* @__PURE__ */ new Set();
1442
+ var counter = 0;
1443
+ function emit(next) {
1444
+ warnings = next;
1445
+ for (const warn of subscribers) warn();
1561
1446
  }
1562
- var suscribirse = (avisar) => {
1563
- suscriptores.add(avisar);
1447
+ var subscribe = (warn) => {
1448
+ subscribers.add(warn);
1564
1449
  return () => {
1565
- suscriptores.delete(avisar);
1450
+ subscribers.delete(warn);
1566
1451
  };
1567
1452
  };
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 } },
1453
+ var read = () => warnings;
1454
+ var EMPTY = [];
1455
+ var onServer = () => EMPTY;
1456
+ function create(message, options = {}) {
1457
+ counter += 1;
1458
+ const id = `arrecife-toast-${counter}`;
1459
+ const { description, ...rest } = options;
1460
+ emit([
1461
+ ...warnings,
1462
+ {
1463
+ ...rest,
1464
+ // The first argument is the main line. If a `title` also arrives, the
1465
+ // message becomes the description: that way `toast('Guardado')` and
1466
+ // `toast('No se pudo guardar', { title: 'Error' })` both read well.
1467
+ ...options.title ? { description: description ?? message } : { title: message, ...description === void 0 ? {} : { description } },
1583
1468
  id,
1584
- abierto: true
1469
+ open: true
1585
1470
  }
1586
1471
  ]);
1587
1472
  return id;
1588
1473
  }
1589
- function descartar(id) {
1590
- emitir(avisos.map((a) => id === void 0 || a.id === id ? { ...a, abierto: false } : a));
1474
+ function discard(id) {
1475
+ emit(warnings.map((a) => id === void 0 || a.id === id ? { ...a, open: false } : a));
1591
1476
  }
1592
- function retirar(id) {
1593
- emitir(avisos.filter((a) => a.id !== id));
1477
+ function remove(id) {
1478
+ emit(warnings.filter((a) => a.id !== id));
1594
1479
  }
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
1480
+ var toast2 = Object.assign(create, {
1481
+ success: (message, options = {}) => create(message, { ...options, variant: "success" }),
1482
+ error: (message, options = {}) => create(message, { ...options, variant: "error" }),
1483
+ dismiss: discard
1599
1484
  });
1600
1485
  function Toaster({ duration = 5e3, label = "Avisos" }) {
1601
- const lista = useSyncExternalStore(suscribirse, leer, enServidor);
1486
+ const list = useSyncExternalStore(subscribe, read, onServer);
1602
1487
  return /* @__PURE__ */ jsxs(ToastProvider, { duration, label, children: [
1603
- lista.map(({ id, title, description, variant, duration: propio, action, abierto }) => /* @__PURE__ */ jsxs(
1488
+ list.map(({ id, title, description, variant, duration: own, action, open }) => /* @__PURE__ */ jsxs(
1604
1489
  Toast,
1605
1490
  {
1606
- open: abierto,
1491
+ open,
1607
1492
  variant: variant ?? "neutral",
1608
- ...propio === void 0 ? {} : { duration: propio },
1609
- onOpenChange: (sigue) => {
1610
- if (!sigue) retirar(id);
1493
+ ...own === void 0 ? {} : { duration: own },
1494
+ onOpenChange: (stillOpen) => {
1495
+ if (!stillOpen) remove(id);
1611
1496
  },
1612
1497
  children: [
1613
1498
  /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
@@ -1644,15 +1529,9 @@ function TooltipContent({
1644
1529
  }
1645
1530
  ) });
1646
1531
  }
1647
- var TARJETA = [
1648
- "group block cursor-pointer",
1649
- SUPERFICIE_TARJETA,
1650
- HOVER_TARJETA,
1651
- "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent"
1652
- ];
1653
- function Tarjeta({ asChild = false, className, children, ...props }) {
1654
- const Raiz = asChild ? Slot : "a";
1655
- return /* @__PURE__ */ jsx(Raiz, { className: cn(TARJETA, className), ...props, children });
1532
+ function CardShell({ asChild = false, className, children, ...props }) {
1533
+ const Root17 = asChild ? Slot : "a";
1534
+ return /* @__PURE__ */ jsx(Root17, { className: cn(CARD, className), ...props, children });
1656
1535
  }
1657
1536
  function ArticleCard({
1658
1537
  title,
@@ -1662,17 +1541,18 @@ function ArticleCard({
1662
1541
  readingMinutes,
1663
1542
  tags,
1664
1543
  headingLevel = 3,
1544
+ tagAsChild,
1665
1545
  className,
1666
1546
  ...props
1667
1547
  }) {
1668
1548
  const meta = [
1669
- date ? /* @__PURE__ */ jsx("time", { dateTime, children: date }, "fecha") : null,
1549
+ date ? /* @__PURE__ */ jsx("time", { dateTime, children: date }, "date") : null,
1670
1550
  readingMinutes ? /* @__PURE__ */ jsxs("span", { children: [
1671
1551
  readingMinutes,
1672
1552
  " min de lectura"
1673
1553
  ] }, "lectura") : null
1674
1554
  ].filter(Boolean);
1675
- return /* @__PURE__ */ jsx(Tarjeta, { className: cn("p-step-lg", className), ...props, children: /* @__PURE__ */ jsxs("article", { className: "gap-step-sm flex h-full flex-col", children: [
1555
+ return /* @__PURE__ */ jsx(CardShell, { className: cn("p-step-lg", className), ...props, children: /* @__PURE__ */ jsxs("article", { className: "gap-step-sm flex h-full flex-col", children: [
1676
1556
  meta.length > 0 ? /* @__PURE__ */ jsx(Text, { variant: "meta", tone: "muted", as: "p", className: "gap-step-xs flex items-center", children: meta.map((m, i) => /* @__PURE__ */ jsxs("span", { className: "gap-step-xs flex items-center", children: [
1677
1557
  i > 0 ? /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\xB7" }) : null,
1678
1558
  m
@@ -1687,18 +1567,20 @@ function ArticleCard({
1687
1567
  }
1688
1568
  ),
1689
1569
  excerpt ? /* @__PURE__ */ jsx(Text, { variant: "ui", tone: "secondary", className: "line-clamp-2", children: excerpt }) : null,
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
1570
+ tags && tags.length > 0 ? /* @__PURE__ */ jsx("div", { className: "gap-step-xs mt-auto flex flex-wrap pt-step-sm", children: tags.map(
1571
+ (t) => tagAsChild ? /* @__PURE__ */ jsx(Slot, { className: category({ active: false }), children: tagAsChild({ tag: t, children: t }) }, t) : /* @__PURE__ */ jsx(CategoryBadge, { children: t }, t)
1572
+ ) }) : null
1691
1573
  ] }) });
1692
1574
  }
1693
1575
  var AVATAR = "size-[52px]";
1694
- function iniciales(nombre) {
1695
- return nombre.split(/\s+/).slice(0, 2).map((p) => p[0] ?? "").join("").toUpperCase();
1576
+ function initials(name) {
1577
+ return name.split(/\s+/).slice(0, 2).map((p) => p[0] ?? "").join("").toUpperCase();
1696
1578
  }
1697
1579
  function AuthorCard({ name, role, src, bio, action, className, ...props }) {
1698
- return /* @__PURE__ */ jsxs("div", { className: cn(SUPERFICIE_TARJETA, "p-step-lg gap-step-md flex items-start", className), ...props, children: [
1580
+ return /* @__PURE__ */ jsxs("div", { className: cn(CARD_SURFACE, "p-step-lg gap-step-md flex items-start", className), ...props, children: [
1699
1581
  /* @__PURE__ */ jsxs(Avatar, { className: cn(AVATAR, "shrink-0"), children: [
1700
1582
  src ? /* @__PURE__ */ jsx(AvatarImage, { src, alt: "" }) : null,
1701
- /* @__PURE__ */ jsx(AvatarFallback, { children: iniciales(name) })
1583
+ /* @__PURE__ */ jsx(AvatarFallback, { children: initials(name) })
1702
1584
  ] }),
1703
1585
  /* @__PURE__ */ jsxs("div", { className: "gap-step-xs flex min-w-0 flex-1 flex-col", children: [
1704
1586
  /* @__PURE__ */ jsx(Text, { variant: "ui", as: "p", className: "font-medium", children: name }),
@@ -1716,45 +1598,45 @@ function formatTime(seconds) {
1716
1598
  }
1717
1599
  var WAVEFORM_HEIGHTS = [35, 65, 100, 65, 35];
1718
1600
  var RATES = [1, 1.25, 1.5, 1.75, 2];
1719
- function Onda({ grosor, alto, sonando }) {
1720
- return /* @__PURE__ */ jsx("div", { className: cn("flex items-end gap-[2px]", alto), "aria-hidden": "true", children: WAVEFORM_HEIGHTS.map((h, i) => /* @__PURE__ */ jsx(
1601
+ function Wave({ strokeWidth, height, playing }) {
1602
+ return /* @__PURE__ */ jsx("div", { className: cn("flex items-end gap-[2px]", height), "aria-hidden": "true", children: WAVEFORM_HEIGHTS.map((h, i) => /* @__PURE__ */ jsx(
1721
1603
  "span",
1722
1604
  {
1723
- className: cn("rounded-pill bg-accent transition-standard", grosor),
1724
- style: { height: `${h}%`, opacity: sonando ? 1 : 0.3 + h / 100 * 0.4 }
1605
+ className: cn("rounded-pill bg-accent transition-standard", strokeWidth),
1606
+ style: { height: `${h}%`, opacity: playing ? 1 : 0.3 + h / 100 * 0.4 }
1725
1607
  },
1726
1608
  i
1727
1609
  )) });
1728
1610
  }
1729
- function BarraProgreso({
1730
- alto,
1731
- perilla,
1732
- progreso,
1611
+ function ProgressBar({
1612
+ height,
1613
+ knob,
1614
+ progress,
1733
1615
  redondeada = true,
1734
1616
  tabIndex = 0,
1735
- ...puntero
1617
+ ...pointer
1736
1618
  }) {
1737
1619
  return /* @__PURE__ */ jsxs(
1738
1620
  "div",
1739
1621
  {
1740
1622
  className: cn(
1741
1623
  "group bg-surface-raised relative cursor-pointer",
1742
- alto,
1624
+ height,
1743
1625
  redondeada && "rounded-pill"
1744
1626
  ),
1745
1627
  role: "slider",
1746
1628
  "aria-label": "Progreso del audio",
1747
1629
  "aria-valuemin": 0,
1748
1630
  "aria-valuemax": 100,
1749
- "aria-valuenow": Math.round(progreso),
1631
+ "aria-valuenow": Math.round(progress),
1750
1632
  tabIndex,
1751
- ...puntero,
1633
+ ...pointer,
1752
1634
  children: [
1753
1635
  /* @__PURE__ */ jsx(
1754
1636
  "div",
1755
1637
  {
1756
1638
  className: cn("bg-accent absolute h-full", redondeada && "rounded-pill"),
1757
- style: { width: `${progreso}%` }
1639
+ style: { width: `${progress}%` }
1758
1640
  }
1759
1641
  ),
1760
1642
  /* @__PURE__ */ jsx(
@@ -1762,9 +1644,9 @@ function BarraProgreso({
1762
1644
  {
1763
1645
  className: "rounded-pill bg-text-primary absolute top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100",
1764
1646
  style: {
1765
- width: perilla,
1766
- height: perilla,
1767
- left: `calc(${progreso}% - ${perilla / 2}px)`
1647
+ width: knob,
1648
+ height: knob,
1649
+ left: `calc(${progress}% - ${knob / 2}px)`
1768
1650
  }
1769
1651
  }
1770
1652
  )
@@ -1772,66 +1654,66 @@ function BarraProgreso({
1772
1654
  }
1773
1655
  );
1774
1656
  }
1775
- var CONTROL = "rounded-chip transition-standard cursor-pointer focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent";
1776
- function BotonSalto({
1777
- segundos,
1657
+ var CONTROL = "rounded-chip transition-standard cursor-pointer focus-ring";
1658
+ function SkipButton({
1659
+ seconds,
1778
1660
  className,
1779
- tamano,
1780
- onSaltar
1661
+ size: size2,
1662
+ onSkip
1781
1663
  }) {
1782
1664
  return /* @__PURE__ */ jsx(
1783
1665
  "button",
1784
1666
  {
1785
1667
  type: "button",
1786
- onClick: () => onSaltar(segundos),
1668
+ onClick: () => onSkip(seconds),
1787
1669
  className: cn("text-text-muted hover:text-text-primary", CONTROL, className),
1788
- "aria-label": segundos < 0 ? "Retroceder 15 segundos" : "Adelantar 15 segundos",
1789
- children: segundos < 0 ? /* @__PURE__ */ jsx(GoBackSeconds, { className: tamano }) : /* @__PURE__ */ jsx(AdvanceSeconds, { className: tamano })
1670
+ "aria-label": seconds < 0 ? "Retroceder 15 segundos" : "Adelantar 15 segundos",
1671
+ children: seconds < 0 ? /* @__PURE__ */ jsx(GoBackSeconds, { className: size2 }) : /* @__PURE__ */ jsx(AdvanceSeconds, { className: size2 })
1790
1672
  }
1791
1673
  );
1792
1674
  }
1793
- function BotonVelocidad({
1675
+ function SpeedButton({
1794
1676
  className,
1795
- velocidad,
1796
- onCambiar
1677
+ speed,
1678
+ onChange
1797
1679
  }) {
1798
1680
  return /* @__PURE__ */ jsxs(
1799
1681
  "button",
1800
1682
  {
1801
1683
  type: "button",
1802
- onClick: onCambiar,
1684
+ onClick: onChange,
1803
1685
  className: cn(
1804
- // `textMuted` sobre `surfaceRaised` da 4.07:1 en oscuro y no pasa AA.
1805
- // El original del portafolio arrastra ese mismo fallo.
1686
+ // `textMuted` over `surfaceRaised` gives 4.07:1 in dark and fails AA.
1687
+ // The portfolio original carries that same failure.
1806
1688
  "text-text-secondary hover:text-text-primary bg-surface-raised",
1807
1689
  CONTROL,
1808
1690
  className
1809
1691
  ),
1810
1692
  "aria-label": "Cambiar velocidad de reproducci\xF3n",
1811
1693
  children: [
1812
- velocidad,
1694
+ speed,
1813
1695
  "x"
1814
1696
  ]
1815
1697
  }
1816
1698
  );
1817
1699
  }
1818
- function Volumen({
1819
- tamano,
1820
- ancho,
1821
- silenciado,
1822
- volumen,
1823
- onSilenciar,
1824
- onCambiarVolumen
1700
+ function Volume({
1701
+ size: size2,
1702
+ width,
1703
+ muted,
1704
+ volume,
1705
+ onMute,
1706
+ onVolumeChange
1825
1707
  }) {
1826
1708
  return /* @__PURE__ */ jsxs("div", { className: "gap-step-xs hidden items-center sm:flex", children: [
1827
1709
  /* @__PURE__ */ jsx(
1828
1710
  "button",
1829
1711
  {
1830
1712
  type: "button",
1831
- onClick: onSilenciar,
1713
+ onClick: onMute,
1832
1714
  className: cn("text-text-muted hover:text-text-primary p-1", CONTROL),
1833
- "aria-label": silenciado ? "Activar sonido" : "Silenciar",
1834
- children: silenciado || volumen === 0 ? /* @__PURE__ */ jsx(VolumeMuted, { className: tamano }) : /* @__PURE__ */ jsx(VolumeOn, { className: tamano })
1715
+ "aria-label": muted ? "Activar sonido" : "Silenciar",
1716
+ children: muted || volume === 0 ? /* @__PURE__ */ jsx(VolumeMuted, { className: size2 }) : /* @__PURE__ */ jsx(VolumeOn, { className: size2 })
1835
1717
  }
1836
1718
  ),
1837
1719
  /* @__PURE__ */ jsx(
@@ -1841,47 +1723,47 @@ function Volumen({
1841
1723
  min: "0",
1842
1724
  max: "1",
1843
1725
  step: "0.1",
1844
- value: silenciado ? 0 : volumen,
1845
- onChange: onCambiarVolumen,
1726
+ value: muted ? 0 : volume,
1727
+ onChange: onVolumeChange,
1846
1728
  className: cn(
1847
1729
  "bg-surface-raised rounded-pill h-1 cursor-pointer appearance-none",
1848
1730
  "[accent-color:var(--color-accent)]",
1849
- ancho
1731
+ width
1850
1732
  ),
1851
1733
  "aria-label": "Volumen"
1852
1734
  }
1853
1735
  )
1854
1736
  ] });
1855
1737
  }
1856
- function IconoPlay({ className, cargando, error, sonando }) {
1857
- if (cargando) return /* @__PURE__ */ jsx(Spinner, { className: cn("motion-safe:animate-spin", className) });
1738
+ function PlayIcon({ className, loading, error, playing }) {
1739
+ if (loading) return /* @__PURE__ */ jsx(Spinner, { className: cn("motion-safe:animate-spin", className) });
1858
1740
  if (error) return /* @__PURE__ */ jsx(Retry, { className });
1859
- if (sonando) return /* @__PURE__ */ jsx(Pause, { className });
1741
+ if (playing) return /* @__PURE__ */ jsx(Pause, { className });
1860
1742
  return /* @__PURE__ */ jsx(Play, { className });
1861
1743
  }
1862
- function BotonPlay({
1744
+ function PlayButton({
1863
1745
  className,
1864
- tamano,
1865
- etiqueta,
1866
- texto: texto2,
1867
- onAlternar,
1868
- ...estado
1746
+ size: size2,
1747
+ label,
1748
+ text: text2,
1749
+ onToggle,
1750
+ ...state
1869
1751
  }) {
1870
1752
  return /* @__PURE__ */ jsxs(
1871
1753
  "button",
1872
1754
  {
1873
1755
  type: "button",
1874
- onClick: onAlternar,
1756
+ onClick: onToggle,
1875
1757
  className: cn(
1876
1758
  "text-accent-on transition-standard cursor-pointer",
1877
- "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent",
1878
- estado.error ? "bg-error hover:bg-error/80" : "bg-accent hover:bg-accent-hover",
1759
+ "focus-ring",
1760
+ state.error ? "bg-error hover:bg-error/80" : "bg-accent hover:bg-accent-hover",
1879
1761
  className
1880
1762
  ),
1881
- "aria-label": etiqueta,
1763
+ "aria-label": label,
1882
1764
  children: [
1883
- /* @__PURE__ */ jsx(IconoPlay, { className: tamano, ...estado }),
1884
- texto2 ? /* @__PURE__ */ jsx("span", { children: texto2 }) : null
1765
+ /* @__PURE__ */ jsx(PlayIcon, { className: size2, ...state }),
1766
+ text2 ? /* @__PURE__ */ jsx("span", { children: text2 }) : null
1885
1767
  ]
1886
1768
  }
1887
1769
  );
@@ -1900,7 +1782,7 @@ function AudioPlayer({ src, title, mode = "full", onFirstPlay }) {
1900
1782
  const [isMuted, setIsMuted] = useState(false);
1901
1783
  const [playbackRate, setPlaybackRate] = useState(1);
1902
1784
  const [isStaticVisible, setIsStaticVisible] = useState(true);
1903
- const flotante = mode === "banner" || mode === "compact";
1785
+ const floating = mode === "banner" || mode === "compact";
1904
1786
  useEffect(() => {
1905
1787
  const audio = audioRef.current;
1906
1788
  if (!audio) return;
@@ -1943,7 +1825,7 @@ function AudioPlayer({ src, title, mode = "full", onFirstPlay }) {
1943
1825
  };
1944
1826
  }, []);
1945
1827
  useEffect(() => {
1946
- if (!flotante || !staticRef.current) return;
1828
+ if (!floating || !staticRef.current) return;
1947
1829
  const observer = new IntersectionObserver(
1948
1830
  (entries) => {
1949
1831
  const entry = entries[0];
@@ -1953,7 +1835,7 @@ function AudioPlayer({ src, title, mode = "full", onFirstPlay }) {
1953
1835
  );
1954
1836
  observer.observe(staticRef.current);
1955
1837
  return () => observer.disconnect();
1956
- }, [flotante]);
1838
+ }, [floating]);
1957
1839
  const togglePlay = useCallback(async () => {
1958
1840
  const audio = audioRef.current;
1959
1841
  if (!audio) return;
@@ -2042,37 +1924,37 @@ function AudioPlayer({ src, title, mode = "full", onFirstPlay }) {
2042
1924
  [duration]
2043
1925
  );
2044
1926
  const progress = duration > 0 ? currentTime / duration * 100 : 0;
2045
- const etiquetaPlay = hasError ? "Reintentar" : isPlaying ? "Pausar" : "Reproducir";
2046
- const estadoPlay = { cargando: isLoading, error: hasError, sonando: isPlaying };
2047
- const puntero = {
1927
+ const playLabel = hasError ? "Reintentar" : isPlaying ? "Pausar" : "Reproducir";
1928
+ const playState = { loading: isLoading, error: hasError, playing: isPlaying };
1929
+ const pointer = {
2048
1930
  onPointerDown: handlePointerDown,
2049
1931
  onPointerMove: handlePointerMove,
2050
1932
  onPointerUp: handlePointerUp
2051
1933
  };
2052
- const flotanteJsx = /* @__PURE__ */ jsxs(
1934
+ const floatingJsx = /* @__PURE__ */ jsxs(
2053
1935
  "div",
2054
1936
  {
2055
1937
  "aria-hidden": isStaticVisible,
2056
1938
  className: cn(
2057
1939
  "fixed inset-x-0 bottom-0 z-40 xl:hidden",
2058
- // Aparece y desaparece: el sistema no anima desplazamiento.
1940
+ // It appears and disappears: the system does not animate displacement.
2059
1941
  isStaticVisible && "hidden"
2060
1942
  ),
2061
1943
  children: [
2062
1944
  /* @__PURE__ */ jsx(
2063
- BarraProgreso,
1945
+ ProgressBar,
2064
1946
  {
2065
- alto: "h-1",
2066
- perilla: 10,
2067
- progreso: progress,
1947
+ height: "h-1",
1948
+ knob: 10,
1949
+ progress,
2068
1950
  redondeada: false,
2069
1951
  tabIndex: -1,
2070
- ...puntero
1952
+ ...pointer
2071
1953
  }
2072
1954
  ),
2073
1955
  /* @__PURE__ */ jsx("div", { className: "bg-surface/95 border-accent/25 border-t backdrop-blur-md", children: /* @__PURE__ */ jsxs("div", { className: "gap-step-sm px-step-md flex items-center py-5", children: [
2074
1956
  /* @__PURE__ */ jsxs("div", { className: "gap-step-xs flex shrink-0 items-center", children: [
2075
- /* @__PURE__ */ jsx(Onda, { grosor: "w-[2px]", alto: "h-4", sonando: isPlaying }),
1957
+ /* @__PURE__ */ jsx(Wave, { strokeWidth: "w-[2px]", height: "h-4", playing: isPlaying }),
2076
1958
  /* @__PURE__ */ jsx("span", { className: "text-eyebrow font-mono text-accent hidden uppercase sm:block", children: "Narraci\xF3n" })
2077
1959
  ] }),
2078
1960
  /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
@@ -2084,24 +1966,24 @@ function AudioPlayer({ src, title, mode = "full", onFirstPlay }) {
2084
1966
  ] })
2085
1967
  ] }),
2086
1968
  /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center gap-1", children: [
2087
- /* @__PURE__ */ jsx(BotonSalto, { segundos: -15, className: "p-1.5", tamano: "w-5 h-5", onSaltar: skip }),
1969
+ /* @__PURE__ */ jsx(SkipButton, { seconds: -15, className: "p-1.5", size: "w-5 h-5", onSkip: skip }),
2088
1970
  /* @__PURE__ */ jsx(
2089
- BotonPlay,
1971
+ PlayButton,
2090
1972
  {
2091
1973
  className: "rounded-pill px-step-sm gap-step-xs flex items-center py-1.5",
2092
- tamano: "w-4 h-4",
2093
- etiqueta: etiquetaPlay,
2094
- onAlternar: togglePlay,
2095
- ...estadoPlay
1974
+ size: "w-4 h-4",
1975
+ label: playLabel,
1976
+ onToggle: togglePlay,
1977
+ ...playState
2096
1978
  }
2097
1979
  ),
2098
- /* @__PURE__ */ jsx(BotonSalto, { segundos: 15, className: "p-1.5", tamano: "w-5 h-5", onSaltar: skip }),
1980
+ /* @__PURE__ */ jsx(SkipButton, { seconds: 15, className: "p-1.5", size: "w-5 h-5", onSkip: skip }),
2099
1981
  /* @__PURE__ */ jsx(
2100
- BotonVelocidad,
1982
+ SpeedButton,
2101
1983
  {
2102
1984
  className: "text-label ml-0.5 px-1.5 py-0.5",
2103
- velocidad: playbackRate,
2104
- onCambiar: handlePlaybackRateChange
1985
+ speed: playbackRate,
1986
+ onChange: handlePlaybackRateChange
2105
1987
  }
2106
1988
  )
2107
1989
  ] })
@@ -2114,7 +1996,7 @@ function AudioPlayer({ src, title, mode = "full", onFirstPlay }) {
2114
1996
  /* @__PURE__ */ jsx("audio", { ref: audioRef, src, preload: "metadata" }),
2115
1997
  /* @__PURE__ */ jsxs("div", { ref: staticRef, children: [
2116
1998
  /* @__PURE__ */ jsxs("div", { className: "gap-step-sm mb-step-md flex items-center", children: [
2117
- /* @__PURE__ */ jsx(Onda, { grosor: "w-[3px]", alto: "h-5", sonando: isPlaying }),
1999
+ /* @__PURE__ */ jsx(Wave, { strokeWidth: "w-[3px]", height: "h-5", playing: isPlaying }),
2118
2000
  /* @__PURE__ */ jsx("span", { className: "text-eyebrow font-mono text-accent uppercase", children: "Narraci\xF3n de audio" }),
2119
2001
  /* @__PURE__ */ jsxs("span", { className: "text-chip font-mono text-text-muted ml-auto tabular-nums", children: [
2120
2002
  formatTime(currentTime),
@@ -2122,125 +2004,125 @@ function AudioPlayer({ src, title, mode = "full", onFirstPlay }) {
2122
2004
  formatTime(duration)
2123
2005
  ] })
2124
2006
  ] }),
2125
- /* @__PURE__ */ jsx("div", { className: "mb-step-md", children: /* @__PURE__ */ jsx(BarraProgreso, { alto: "h-1.5", perilla: 14, progreso: progress, ...puntero }) }),
2007
+ /* @__PURE__ */ jsx("div", { className: "mb-step-md", children: /* @__PURE__ */ jsx(ProgressBar, { height: "h-1.5", knob: 14, progress, ...pointer }) }),
2126
2008
  /* @__PURE__ */ jsxs("div", { className: "gap-step-sm flex items-center", children: [
2127
- /* @__PURE__ */ jsx(BotonSalto, { segundos: -15, className: "p-2", tamano: "w-6 h-6", onSaltar: skip }),
2009
+ /* @__PURE__ */ jsx(SkipButton, { seconds: -15, className: "p-2", size: "w-6 h-6", onSkip: skip }),
2128
2010
  /* @__PURE__ */ jsx(
2129
- BotonPlay,
2011
+ PlayButton,
2130
2012
  {
2131
2013
  className: "rounded-pill px-step-lg gap-step-xs text-ui flex items-center py-2 font-medium",
2132
- tamano: "w-4 h-4",
2133
- etiqueta: etiquetaPlay,
2134
- texto: etiquetaPlay,
2135
- onAlternar: togglePlay,
2136
- ...estadoPlay
2014
+ size: "w-4 h-4",
2015
+ label: playLabel,
2016
+ text: playLabel,
2017
+ onToggle: togglePlay,
2018
+ ...playState
2137
2019
  }
2138
2020
  ),
2139
- /* @__PURE__ */ jsx(BotonSalto, { segundos: 15, className: "p-2", tamano: "w-6 h-6", onSaltar: skip }),
2021
+ /* @__PURE__ */ jsx(SkipButton, { seconds: 15, className: "p-2", size: "w-6 h-6", onSkip: skip }),
2140
2022
  /* @__PURE__ */ jsxs("div", { className: "gap-step-sm ml-auto flex items-center", children: [
2141
2023
  /* @__PURE__ */ jsx(
2142
- BotonVelocidad,
2024
+ SpeedButton,
2143
2025
  {
2144
2026
  className: "text-label px-2 py-1",
2145
- velocidad: playbackRate,
2146
- onCambiar: handlePlaybackRateChange
2027
+ speed: playbackRate,
2028
+ onChange: handlePlaybackRateChange
2147
2029
  }
2148
2030
  ),
2149
2031
  /* @__PURE__ */ jsx(
2150
- Volumen,
2032
+ Volume,
2151
2033
  {
2152
- tamano: "w-4 h-4",
2153
- ancho: "w-16",
2154
- silenciado: isMuted,
2155
- volumen: volume,
2156
- onSilenciar: toggleMute,
2157
- onCambiarVolumen: handleVolumeChange
2034
+ size: "w-4 h-4",
2035
+ width: "w-16",
2036
+ muted: isMuted,
2037
+ volume,
2038
+ onMute: toggleMute,
2039
+ onVolumeChange: handleVolumeChange
2158
2040
  }
2159
2041
  )
2160
2042
  ] })
2161
2043
  ] })
2162
2044
  ] }),
2163
- flotanteJsx
2045
+ floatingJsx
2164
2046
  ] });
2165
2047
  }
2166
2048
  if (mode === "compact") {
2167
2049
  return /* @__PURE__ */ jsxs(Fragment, { children: [
2168
2050
  /* @__PURE__ */ jsx("audio", { ref: audioRef, src, preload: "metadata" }),
2169
2051
  /* @__PURE__ */ jsxs("div", { ref: staticRef, className: "w-full", children: [
2170
- /* @__PURE__ */ jsx("div", { className: "mb-step-xs", children: /* @__PURE__ */ jsx(BarraProgreso, { alto: "h-1.5", perilla: 12, progreso: progress, ...puntero }) }),
2052
+ /* @__PURE__ */ jsx("div", { className: "mb-step-xs", children: /* @__PURE__ */ jsx(ProgressBar, { height: "h-1.5", knob: 12, progress, ...pointer }) }),
2171
2053
  /* @__PURE__ */ jsxs("div", { className: "text-chip font-mono text-text-muted mb-step-sm flex justify-between", children: [
2172
2054
  /* @__PURE__ */ jsx("span", { children: formatTime(currentTime) }),
2173
2055
  /* @__PURE__ */ jsx("span", { children: formatTime(duration) })
2174
2056
  ] }),
2175
2057
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
2176
2058
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
2177
- /* @__PURE__ */ jsx(BotonSalto, { segundos: -15, className: "p-1.5", tamano: "w-5 h-5", onSaltar: skip }),
2059
+ /* @__PURE__ */ jsx(SkipButton, { seconds: -15, className: "p-1.5", size: "w-5 h-5", onSkip: skip }),
2178
2060
  /* @__PURE__ */ jsx(
2179
- BotonPlay,
2061
+ PlayButton,
2180
2062
  {
2181
2063
  className: "rounded-pill flex size-[34px] items-center justify-center",
2182
- tamano: "w-4 h-4",
2183
- etiqueta: etiquetaPlay,
2184
- onAlternar: togglePlay,
2185
- ...estadoPlay
2064
+ size: "w-4 h-4",
2065
+ label: playLabel,
2066
+ onToggle: togglePlay,
2067
+ ...playState
2186
2068
  }
2187
2069
  ),
2188
- /* @__PURE__ */ jsx(BotonSalto, { segundos: 15, className: "p-1.5", tamano: "w-5 h-5", onSaltar: skip })
2070
+ /* @__PURE__ */ jsx(SkipButton, { seconds: 15, className: "p-1.5", size: "w-5 h-5", onSkip: skip })
2189
2071
  ] }),
2190
2072
  /* @__PURE__ */ jsx(
2191
- BotonVelocidad,
2073
+ SpeedButton,
2192
2074
  {
2193
2075
  className: "text-label px-1.5 py-0.5",
2194
- velocidad: playbackRate,
2195
- onCambiar: handlePlaybackRateChange
2076
+ speed: playbackRate,
2077
+ onChange: handlePlaybackRateChange
2196
2078
  }
2197
2079
  )
2198
2080
  ] })
2199
2081
  ] }),
2200
- flotanteJsx
2082
+ floatingJsx
2201
2083
  ] });
2202
2084
  }
2203
2085
  return /* @__PURE__ */ jsxs("div", { className: "bg-surface rounded-control border-border p-step-md w-full border", children: [
2204
2086
  /* @__PURE__ */ jsx("audio", { ref: audioRef, src, preload: "metadata" }),
2205
2087
  title ? /* @__PURE__ */ jsx("p", { className: "text-ui font-sans text-text-secondary mb-step-sm truncate", children: title }) : null,
2206
- /* @__PURE__ */ jsx("div", { className: "mb-step-sm", children: /* @__PURE__ */ jsx(BarraProgreso, { alto: "h-2", perilla: 16, progreso: progress, ...puntero }) }),
2088
+ /* @__PURE__ */ jsx("div", { className: "mb-step-sm", children: /* @__PURE__ */ jsx(ProgressBar, { height: "h-2", knob: 16, progress, ...pointer }) }),
2207
2089
  /* @__PURE__ */ jsxs("div", { className: "text-chip font-mono text-text-muted mb-step-sm flex justify-between", children: [
2208
2090
  /* @__PURE__ */ jsx("span", { children: formatTime(currentTime) }),
2209
2091
  /* @__PURE__ */ jsx("span", { children: formatTime(duration) })
2210
2092
  ] }),
2211
2093
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
2212
2094
  /* @__PURE__ */ jsxs("div", { className: "gap-step-xs flex items-center", children: [
2213
- /* @__PURE__ */ jsx(BotonSalto, { segundos: -15, className: "p-2", tamano: "w-5 h-5", onSaltar: skip }),
2095
+ /* @__PURE__ */ jsx(SkipButton, { seconds: -15, className: "p-2", size: "w-5 h-5", onSkip: skip }),
2214
2096
  /* @__PURE__ */ jsx(
2215
- BotonPlay,
2097
+ PlayButton,
2216
2098
  {
2217
2099
  className: "rounded-pill flex size-12 items-center justify-center",
2218
- tamano: "w-6 h-6",
2219
- etiqueta: etiquetaPlay,
2220
- onAlternar: togglePlay,
2221
- ...estadoPlay
2100
+ size: "w-6 h-6",
2101
+ label: playLabel,
2102
+ onToggle: togglePlay,
2103
+ ...playState
2222
2104
  }
2223
2105
  ),
2224
- /* @__PURE__ */ jsx(BotonSalto, { segundos: 15, className: "p-2", tamano: "w-5 h-5", onSaltar: skip })
2106
+ /* @__PURE__ */ jsx(SkipButton, { seconds: 15, className: "p-2", size: "w-5 h-5", onSkip: skip })
2225
2107
  ] }),
2226
2108
  /* @__PURE__ */ jsxs("div", { className: "gap-step-sm flex items-center", children: [
2227
2109
  /* @__PURE__ */ jsx(
2228
- BotonVelocidad,
2110
+ SpeedButton,
2229
2111
  {
2230
2112
  className: "text-label px-2 py-1",
2231
- velocidad: playbackRate,
2232
- onCambiar: handlePlaybackRateChange
2113
+ speed: playbackRate,
2114
+ onChange: handlePlaybackRateChange
2233
2115
  }
2234
2116
  ),
2235
2117
  /* @__PURE__ */ jsx(
2236
- Volumen,
2118
+ Volume,
2237
2119
  {
2238
- tamano: "w-5 h-5",
2239
- ancho: "w-20",
2240
- silenciado: isMuted,
2241
- volumen: volume,
2242
- onSilenciar: toggleMute,
2243
- onCambiarVolumen: handleVolumeChange
2120
+ size: "w-5 h-5",
2121
+ width: "w-20",
2122
+ muted: isMuted,
2123
+ volume,
2124
+ onMute: toggleMute,
2125
+ onVolumeChange: handleVolumeChange
2244
2126
  }
2245
2127
  )
2246
2128
  ] })
@@ -2264,7 +2146,7 @@ function Blockquote({ children, author, source, className, ...props }) {
2264
2146
  }
2265
2147
  );
2266
2148
  }
2267
- var ENLACE = "transition-standard hover:text-accent focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent rounded-chip cursor-pointer";
2149
+ var LINK = "transition-standard hover:text-accent focus-ring rounded-chip cursor-pointer";
2268
2150
  function Breadcrumb({
2269
2151
  items,
2270
2152
  homeHref = "/",
@@ -2273,28 +2155,28 @@ function Breadcrumb({
2273
2155
  className,
2274
2156
  ...props
2275
2157
  }) {
2276
- const enlace = (href, contenido) => linkAsChild ? /* @__PURE__ */ jsx(Slot, { className: ENLACE, children: linkAsChild({ href, children: contenido }) }) : /* @__PURE__ */ jsx("a", { href, className: ENLACE, children: contenido });
2158
+ const link = (href, content) => linkAsChild ? /* @__PURE__ */ jsx(Slot, { className: LINK, children: linkAsChild({ href, children: content }) }) : /* @__PURE__ */ jsx("a", { href, className: LINK, children: content });
2277
2159
  return /* @__PURE__ */ jsx("nav", { "aria-label": "Ruta", className: cn("font-mono text-meta text-text-muted", className), ...props, children: /* @__PURE__ */ jsxs("ol", { className: "gap-step-xs flex flex-wrap items-center", children: [
2278
- /* @__PURE__ */ jsx("li", { children: enlace(homeHref, /* @__PURE__ */ jsx("span", { "aria-label": homeLabel, children: "~" })) }),
2160
+ /* @__PURE__ */ jsx("li", { children: link(homeHref, /* @__PURE__ */ jsx("span", { "aria-label": homeLabel, children: "~" })) }),
2279
2161
  items.map((item2, i) => {
2280
- const ultimo = i === items.length - 1;
2162
+ const last = i === items.length - 1;
2281
2163
  return /* @__PURE__ */ jsxs("li", { className: "gap-step-xs flex items-center", children: [
2282
2164
  /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "text-border", children: "/" }),
2283
- item2.href && !ultimo ? enlace(item2.href, item2.label) : /* @__PURE__ */ jsx("span", { "aria-current": ultimo ? "page" : void 0, className: "text-text-secondary", children: item2.label })
2165
+ item2.href && !last ? link(item2.href, item2.label) : /* @__PURE__ */ jsx("span", { "aria-current": last ? "page" : void 0, className: "text-text-secondary", children: item2.label })
2284
2166
  ] }, i);
2285
2167
  })
2286
2168
  ] }) });
2287
2169
  }
2288
2170
  function CodeBlock({ children, language, copyText, className, ...props }) {
2289
2171
  const [copiado, setCopiado] = useState(false);
2290
- const temporizador = useRef(null);
2291
- const copiar = useCallback(async () => {
2172
+ const timer = useRef(null);
2173
+ const copy = useCallback(async () => {
2292
2174
  if (!copyText) return;
2293
2175
  try {
2294
2176
  await navigator.clipboard.writeText(copyText);
2295
2177
  setCopiado(true);
2296
- if (temporizador.current) clearTimeout(temporizador.current);
2297
- temporizador.current = setTimeout(() => setCopiado(false), 2e3);
2178
+ if (timer.current) clearTimeout(timer.current);
2179
+ timer.current = setTimeout(() => setCopiado(false), 2e3);
2298
2180
  } catch {
2299
2181
  }
2300
2182
  }, [copyText]);
@@ -2318,14 +2200,14 @@ function CodeBlock({ children, language, copyText, className, ...props }) {
2318
2200
  "button",
2319
2201
  {
2320
2202
  type: "button",
2321
- onClick: copiar,
2203
+ onClick: copy,
2322
2204
  "aria-label": copiado ? "C\xF3digo copiado" : "Copiar c\xF3digo",
2323
2205
  "aria-live": "polite",
2324
2206
  className: cn(
2325
2207
  "gap-step-xs rounded-chip flex items-center px-2 py-1",
2326
2208
  "text-label font-mono text-text-muted cursor-pointer",
2327
2209
  "transition-standard hover:bg-surface hover:text-text-primary",
2328
- "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent"
2210
+ "focus-ring"
2329
2211
  ),
2330
2212
  children: [
2331
2213
  copiado ? /* @__PURE__ */ jsx(Check, { className: "text-accent" }) : /* @__PURE__ */ jsx(Copy, {}),
@@ -2348,7 +2230,7 @@ function CourseCard({
2348
2230
  className,
2349
2231
  ...props
2350
2232
  }) {
2351
- return /* @__PURE__ */ jsx(Tarjeta, { className: cn("p-step-lg", className), ...props, children: /* @__PURE__ */ jsxs("article", { className: "gap-step-sm flex h-full flex-col", children: [
2233
+ return /* @__PURE__ */ jsx(CardShell, { className: cn("p-step-lg", className), ...props, children: /* @__PURE__ */ jsxs("article", { className: "gap-step-sm flex h-full flex-col", children: [
2352
2234
  status ? /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Badge, { variant: "warm", children: status }) }) : null,
2353
2235
  /* @__PURE__ */ jsx(Text, { as: "h3", variant: "h3", className: "group-hover:text-accent transition-standard", children: title }),
2354
2236
  summary ? /* @__PURE__ */ jsx(Text, { variant: "ui", tone: "secondary", className: "line-clamp-3", children: summary }) : null,
@@ -2365,23 +2247,35 @@ function CourseCard({
2365
2247
  ] }) : null
2366
2248
  ] }) });
2367
2249
  }
2368
- var CARA = "w-[66px] max-w-none";
2369
- function EmptyState({
2370
- expresion,
2371
- title,
2372
- description,
2373
- action,
2374
- basePath,
2375
- className,
2376
- ...props
2377
- }) {
2250
+ var FACE = "w-[66px] max-w-none";
2251
+ function EmptyState(props) {
2252
+ if (props.variant === "inline") {
2253
+ const { variant: variant2, title: title2, description: description2, action: action2, icon, className: className2, ...rest2 } = props;
2254
+ return /* @__PURE__ */ jsxs(
2255
+ "div",
2256
+ {
2257
+ className: cn(
2258
+ "py-step-lg px-step-md gap-step-xs flex flex-col items-center text-center",
2259
+ className2
2260
+ ),
2261
+ ...rest2,
2262
+ children: [
2263
+ icon ? /* @__PURE__ */ jsx("span", { className: "text-text-muted shrink-0", children: icon }) : null,
2264
+ /* @__PURE__ */ jsx(Text, { variant: "ui", tone: "muted", as: "p", className: "max-w-measure", children: title2 }),
2265
+ description2 ? /* @__PURE__ */ jsx(Text, { variant: "label", tone: "muted", as: "p", className: "max-w-measure font-normal", children: description2 }) : null,
2266
+ action2 ? /* @__PURE__ */ jsx("div", { className: "mt-step-xs", children: action2 }) : null
2267
+ ]
2268
+ }
2269
+ );
2270
+ }
2271
+ const { variant, title, description, action, expression, basePath, className, ...rest } = props;
2378
2272
  return /* @__PURE__ */ jsxs(
2379
2273
  "div",
2380
2274
  {
2381
- className: cn(SUPERFICIE_TARJETA, "p-step-lg gap-step-sm flex flex-col items-center text-center", className),
2382
- ...props,
2275
+ className: cn(CARD_SURFACE, "p-step-lg gap-step-sm flex flex-col items-center text-center", className),
2276
+ ...rest,
2383
2277
  children: [
2384
- /* @__PURE__ */ jsx(CaraDeMascota, { expresion, className: CARA, basePath }),
2278
+ /* @__PURE__ */ jsx(MascotFace, { expression, className: FACE, basePath }),
2385
2279
  /* @__PURE__ */ jsx(Text, { variant: "ui", as: "p", className: "font-medium", children: title }),
2386
2280
  description ? /* @__PURE__ */ jsx(Text, { variant: "label", tone: "muted", as: "p", className: "max-w-measure font-normal", children: description }) : null,
2387
2281
  action ? /* @__PURE__ */ jsx("div", { className: "mt-step-xs", children: action }) : null
@@ -2389,12 +2283,12 @@ function EmptyState({
2389
2283
  }
2390
2284
  );
2391
2285
  }
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())}`;
2286
+ var sameDay = (a, b) => a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
2287
+ function toFieldValue(date) {
2288
+ const two = (n) => String(n).padStart(2, "0");
2289
+ return `${date.getFullYear()}-${two(date.getMonth() + 1)}-${two(date.getDate())}T${two(
2290
+ date.getHours()
2291
+ )}:${two(date.getMinutes())}`;
2398
2292
  }
2399
2293
  function EventCalendar({
2400
2294
  events,
@@ -2403,68 +2297,68 @@ function EventCalendar({
2403
2297
  onDeleteEvent,
2404
2298
  selected,
2405
2299
  onSelectDay,
2406
- formatDay = (dia) => format(dia, "EEEE d 'de' MMMM", { locale: es }),
2407
- formatTime: formatTime2 = (fecha) => format(fecha, "HH:mm", { locale: es }),
2300
+ formatDay = (day) => format(day, "EEEE d 'de' MMMM", { locale: es }),
2301
+ formatTime: formatTime2 = (date) => format(date, "HH:mm", { locale: es }),
2408
2302
  emptyMessage = "Nada en este d\xEDa.",
2409
2303
  className,
2410
2304
  ...props
2411
2305
  }) {
2412
2306
  const id = useId();
2413
2307
  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("");
2308
+ const day = selected ?? diaInterno;
2309
+ const [month, setMonth] = useState(() => day);
2310
+ const [editing, setEditing] = useState(null);
2311
+ const [title, setTitle] = useState("");
2312
+ const [when, setWhen] = useState("");
2419
2313
  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) {
2314
+ const ofTheDay = events.filter((e) => sameDay(e.start, day)).sort((a, b) => a.start.getTime() - b.start.getTime());
2315
+ function pickDay(nuevo) {
2422
2316
  if (!nuevo) return;
2423
2317
  setDiaInterno(nuevo);
2424
- setMes(nuevo);
2318
+ setMonth(nuevo);
2425
2319
  onSelectDay?.(nuevo);
2426
- cancelar();
2320
+ cancel();
2427
2321
  }
2428
- function cancelar() {
2429
- setEditando(null);
2430
- setTitulo("");
2431
- setCuando("");
2322
+ function cancel() {
2323
+ setEditing(null);
2324
+ setTitle("");
2325
+ setWhen("");
2432
2326
  }
2433
- function editar(evento) {
2434
- setEditando(evento.id);
2435
- setTitulo(evento.title);
2436
- setCuando(aValorDeCampo(evento.start));
2327
+ function edit(event) {
2328
+ setEditing(event.id);
2329
+ setTitle(event.title);
2330
+ setWhen(toFieldValue(event.start));
2437
2331
  }
2438
- function enviar(e) {
2332
+ function submit(e) {
2439
2333
  e.preventDefault();
2440
- if (!titulo.trim() || !cuando) return;
2441
- const start = new Date(cuando);
2334
+ if (!title.trim() || !when) return;
2335
+ const start = new Date(when);
2442
2336
  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 });
2337
+ if (editing) {
2338
+ const previous = events.find((ev) => ev.id === editing);
2339
+ if (previous) onUpdateEvent?.({ ...previous, title: title.trim(), start });
2446
2340
  } else {
2447
- onCreateEvent?.({ title: titulo.trim(), start });
2341
+ onCreateEvent?.({ title: title.trim(), start });
2448
2342
  }
2449
- cancelar();
2343
+ cancel();
2450
2344
  }
2451
- const conEvento = events.map((e) => e.start);
2345
+ const withEvent = events.map((e) => e.start);
2452
2346
  return /* @__PURE__ */ jsxs("div", { className: cn("gap-step-lg flex flex-col md:flex-row md:items-start", className), ...props, children: [
2453
2347
  /* @__PURE__ */ jsx(
2454
2348
  Calendar,
2455
2349
  {
2456
2350
  mode: "single",
2457
- selected: dia,
2458
- onSelect: elegirDia,
2459
- month: mes,
2460
- onMonthChange: setMes,
2461
- modifiers: { conEvento },
2351
+ selected: day,
2352
+ onSelect: pickDay,
2353
+ month,
2354
+ onMonthChange: setMonth,
2355
+ modifiers: { withEvent },
2462
2356
  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(
2357
+ // The dot goes under the number, not on top of the day's background:
2358
+ // over the selected one — which is solid biolume — an accent dot
2359
+ // disappears. `after:` in Tailwind v4 already ships `content: ""`, so
2360
+ // there is no need to declare it with an arbitrary value.
2361
+ withEvent: cn(
2468
2362
  "after:bg-accent after:absolute after:bottom-1 after:left-1/2",
2469
2363
  "after:size-1 after:-translate-x-1/2 after:rounded-pill",
2470
2364
  "[&[data-selected=true]]:after:bg-accent-on"
@@ -2479,8 +2373,8 @@ function EventCalendar({
2479
2373
  "aria-labelledby": `${id}-dia`,
2480
2374
  className: "border-hairline rounded-card p-step-md gap-step-md flex min-w-0 flex-1 flex-col border",
2481
2375
  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(
2376
+ /* @__PURE__ */ jsx(Text, { as: "h3", variant: "h3", id: `${id}-dia`, className: "first-letter:uppercase", children: formatDay(day) }),
2377
+ ofTheDay.length > 0 ? /* @__PURE__ */ jsx("ul", { className: "gap-step-xs flex flex-col", children: ofTheDay.map((event) => /* @__PURE__ */ jsxs(
2484
2378
  "li",
2485
2379
  {
2486
2380
  className: "border-hairline gap-step-sm py-step-xs flex items-center border-b last:border-b-0",
@@ -2490,85 +2384,85 @@ function EventCalendar({
2490
2384
  {
2491
2385
  as: "span",
2492
2386
  variant: "meta",
2493
- tone: evento.tone === "warm" ? "warm" : "accent",
2387
+ tone: event.tone === "warm" ? "warm" : "accent",
2494
2388
  className: "shrink-0 tabular-nums",
2495
- children: /* @__PURE__ */ jsx("time", { dateTime: evento.start.toISOString(), children: formatTime2(evento.start) })
2389
+ children: /* @__PURE__ */ jsx("time", { dateTime: event.start.toISOString(), children: formatTime2(event.start) })
2496
2390
  }
2497
2391
  ),
2498
- /* @__PURE__ */ jsx(Text, { as: "span", variant: "ui", className: "min-w-0 flex-1 truncate", children: evento.title }),
2392
+ /* @__PURE__ */ jsx(Text, { as: "span", variant: "ui", className: "min-w-0 flex-1 truncate", children: event.title }),
2499
2393
  onUpdateEvent ? /* @__PURE__ */ jsx(
2500
2394
  Button,
2501
2395
  {
2502
2396
  variant: "tertiary",
2503
2397
  size: "sm",
2504
- onClick: () => editar(evento),
2505
- "aria-label": `Editar \xAB${evento.title}\xBB`,
2506
- children: "./editar"
2398
+ onClick: () => edit(event),
2399
+ "aria-label": `Editar \xAB${event.title}\xBB`,
2400
+ children: "./edit"
2507
2401
  }
2508
2402
  ) : null,
2509
2403
  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" }) }),
2404
+ /* @__PURE__ */ jsx(AlertDialogTrigger, { asChild: true, children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", size: "sm", "aria-label": `Borrar \xAB${event.title}\xBB`, children: "./borrar" }) }),
2511
2405
  /* @__PURE__ */ jsxs(AlertDialogContent, { children: [
2512
2406
  /* @__PURE__ */ jsxs(AlertDialogHeader, { children: [
2513
2407
  /* @__PURE__ */ jsxs(AlertDialogTitle, { children: [
2514
2408
  "Borrar \xAB",
2515
- evento.title,
2409
+ event.title,
2516
2410
  "\xBB"
2517
2411
  ] }),
2518
2412
  /* @__PURE__ */ jsxs(AlertDialogDescription, { children: [
2519
2413
  "Se borra del ",
2520
- formatDay(evento.start),
2414
+ formatDay(event.start),
2521
2415
  " a las ",
2522
- formatTime2(evento.start),
2416
+ formatTime2(event.start),
2523
2417
  ". No se puede deshacer."
2524
2418
  ] })
2525
2419
  ] }),
2526
2420
  /* @__PURE__ */ jsxs(AlertDialogFooter, { children: [
2527
2421
  /* @__PURE__ */ jsx(AlertDialogCancel, { children: "Mejor no" }),
2528
- /* @__PURE__ */ jsx(AlertDialogAction, { onClick: () => onDeleteEvent(evento.id), children: "Borrar el evento" })
2422
+ /* @__PURE__ */ jsx(AlertDialogAction, { onClick: () => onDeleteEvent(event.id), children: "Borrar el event" })
2529
2423
  ] })
2530
2424
  ] })
2531
2425
  ] }) : null
2532
2426
  ]
2533
2427
  },
2534
- evento.id
2428
+ event.id
2535
2429
  )) }) : (
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.
2430
+ // `EmptyState` is not used: it carries a mascot face, and the mascot
2431
+ // has seven counted places where it may appear. An empty day in a
2432
+ // schedule is not one of them — and in a thirty-day month, half of them
2433
+ // would be.
2540
2434
  /* @__PURE__ */ jsx(Text, { as: "p", variant: "ui", tone: "muted", children: emptyMessage })
2541
2435
  ),
2542
- editable ? /* @__PURE__ */ jsxs("form", { onSubmit: enviar, className: "gap-step-sm border-hairline pt-step-md flex flex-col border-t", children: [
2436
+ editable ? /* @__PURE__ */ jsxs("form", { onSubmit: submit, className: "gap-step-sm border-hairline pt-step-md flex flex-col border-t", children: [
2543
2437
  /* @__PURE__ */ jsxs("div", { className: "gap-step-xs flex flex-col", children: [
2544
- /* @__PURE__ */ jsx(Label, { htmlFor: `${id}-titulo`, children: "T\xEDtulo" }),
2438
+ /* @__PURE__ */ jsx(Label, { htmlFor: `${id}-title`, children: "T\xEDtulo" }),
2545
2439
  /* @__PURE__ */ jsx(
2546
2440
  Input,
2547
2441
  {
2548
- id: `${id}-titulo`,
2549
- value: titulo,
2550
- onChange: (e) => setTitulo(e.target.value),
2442
+ id: `${id}-title`,
2443
+ value: title,
2444
+ onChange: (e) => setTitle(e.target.value),
2551
2445
  placeholder: "Publicar el art\xEDculo",
2552
2446
  required: true
2553
2447
  }
2554
2448
  )
2555
2449
  ] }),
2556
2450
  /* @__PURE__ */ jsxs("div", { className: "gap-step-xs flex flex-col", children: [
2557
- /* @__PURE__ */ jsx(Label, { htmlFor: `${id}-cuando`, children: "Cu\xE1ndo" }),
2451
+ /* @__PURE__ */ jsx(Label, { htmlFor: `${id}-when`, children: "Cu\xE1ndo" }),
2558
2452
  /* @__PURE__ */ jsx(
2559
2453
  DateField,
2560
2454
  {
2561
- id: `${id}-cuando`,
2455
+ id: `${id}-when`,
2562
2456
  withTime: true,
2563
- value: cuando,
2564
- onChange: (e) => setCuando(e.target.value),
2457
+ value: when,
2458
+ onChange: (e) => setWhen(e.target.value),
2565
2459
  required: true
2566
2460
  }
2567
2461
  )
2568
2462
  ] }),
2569
2463
  /* @__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
2464
+ /* @__PURE__ */ jsx(Button, { type: "submit", size: "sm", children: editing ? "Guardar" : "A\xF1adir" }),
2465
+ editing ? /* @__PURE__ */ jsx(Button, { type: "button", variant: "tertiary", size: "sm", onClick: cancel, children: "./cancelar" }) : null
2572
2466
  ] })
2573
2467
  ] }) : null
2574
2468
  ]
@@ -2584,7 +2478,7 @@ function Footer({
2584
2478
  className,
2585
2479
  ...props
2586
2480
  }) {
2587
- const firma = /* @__PURE__ */ jsxs(Text, { variant: "meta", tone: "muted", as: "p", className: "ml-auto shrink-0", children: [
2481
+ const signature = /* @__PURE__ */ jsxs(Text, { variant: "meta", tone: "muted", as: "p", className: "ml-auto shrink-0", children: [
2588
2482
  /* @__PURE__ */ jsxs("span", { "aria-hidden": "true", className: "text-accent", children: [
2589
2483
  "$",
2590
2484
  " "
@@ -2592,45 +2486,52 @@ function Footer({
2592
2486
  "cd ~/",
2593
2487
  naming.domain,
2594
2488
  "/",
2595
- year
2489
+ year,
2490
+ /* @__PURE__ */ jsx(
2491
+ "span",
2492
+ {
2493
+ "aria-hidden": "true",
2494
+ className: "bg-accent motion-safe:caret ml-[0.2em] inline-block h-[1em] w-[0.5em] translate-y-[0.15em]"
2495
+ }
2496
+ )
2596
2497
  ] });
2597
- const filas = [
2498
+ const rows = [
2598
2499
  brand2 ? /* @__PURE__ */ jsx("div", { className: "flex items-center", children: brand2 }, "marca") : null,
2599
2500
  children ? /* @__PURE__ */ jsx("div", { className: "gap-step-md flex flex-wrap items-center", children }, "enlaces") : null,
2600
2501
  social && social.length > 0 ? (
2601
- // 18px de separación, del documento. No es un escalón de `spacing`:
2602
- // es el ritmo de una fila de iconos, no el de una página.
2603
- /* @__PURE__ */ jsx("ul", { className: "flex items-center gap-[18px]", children: social.map((red) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
2502
+ // 18px of separation, from the document. It is not a `spacing` step: it is
2503
+ // the rhythm of a row of icons, not that of a page.
2504
+ /* @__PURE__ */ jsx("ul", { className: "flex items-center gap-[18px]", children: social.map((socialLink) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
2604
2505
  "a",
2605
2506
  {
2606
- href: red.href,
2607
- "aria-label": red.label,
2507
+ href: socialLink.href,
2508
+ "aria-label": socialLink.label,
2608
2509
  className: cn(
2609
2510
  "text-text-muted hover:text-accent transition-standard block cursor-pointer text-[19px]",
2610
- "rounded-chip focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent"
2511
+ "rounded-chip focus-ring"
2611
2512
  ),
2612
- children: red.icon
2513
+ children: socialLink.icon
2613
2514
  }
2614
- ) }, red.href)) }, "redes")
2515
+ ) }, socialLink.href)) }, "socialLinks")
2615
2516
  ) : null
2616
2517
  ].filter(Boolean);
2617
- const [primera, ...resto] = filas;
2518
+ const [first, ...rest] = rows;
2618
2519
  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: [
2619
2520
  /* @__PURE__ */ jsxs("div", { className: "gap-step-md flex flex-wrap items-center", children: [
2620
- primera ?? null,
2621
- firma
2521
+ first ?? null,
2522
+ signature
2622
2523
  ] }),
2623
- resto
2524
+ rest
2624
2525
  ] }) });
2625
2526
  }
2626
2527
  function FooterLink({ asChild = false, className, ...props }) {
2627
- const Raiz = asChild ? Slot : "a";
2528
+ const Root17 = asChild ? Slot : "a";
2628
2529
  return /* @__PURE__ */ jsx(
2629
- Raiz,
2530
+ Root17,
2630
2531
  {
2631
2532
  className: cn(
2632
2533
  "font-mono text-meta text-text-secondary hover:text-accent transition-standard cursor-pointer",
2633
- "rounded-chip focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent",
2534
+ "rounded-chip focus-ring",
2634
2535
  className
2635
2536
  ),
2636
2537
  ...props
@@ -2644,24 +2545,24 @@ function Hero({
2644
2545
  action,
2645
2546
  pose,
2646
2547
  basePath,
2647
- variant = "cabecera",
2548
+ variant = "header",
2648
2549
  className,
2649
2550
  ...props
2650
2551
  }) {
2651
- const centrado = variant === "centrado";
2552
+ const centered = variant === "centered";
2652
2553
  return /* @__PURE__ */ jsxs(
2653
2554
  "section",
2654
2555
  {
2655
2556
  className: cn(
2656
- "degradado-hero rounded-panel border-hairline relative overflow-hidden border",
2657
- // 44 arriba, 40 a los lados y abajo. Del documento.
2557
+ "gradient-hero rounded-panel border-hairline relative overflow-hidden border",
2558
+ // 44 top, 40 on the sides and bottom. From the document.
2658
2559
  "px-step-xl pt-[44px] pb-step-xl",
2659
2560
  className
2660
2561
  ),
2661
2562
  ...props,
2662
2563
  children: [
2663
- centrado && pose ? /* @__PURE__ */ jsx(
2664
- Mascota,
2564
+ centered && pose ? /* @__PURE__ */ jsx(
2565
+ Mascot,
2665
2566
  {
2666
2567
  pose,
2667
2568
  basePath,
@@ -2673,7 +2574,7 @@ function Hero({
2673
2574
  {
2674
2575
  className: cn(
2675
2576
  "gap-step-md flex flex-col",
2676
- centrado ? "items-center text-center" : "md:max-w-[62%]"
2577
+ centered ? "items-center text-center" : "md:max-w-[62%]"
2677
2578
  ),
2678
2579
  children: [
2679
2580
  eyebrow ? /* @__PURE__ */ jsx(Text, { variant: "eyebrow", tone: "accent", as: "p", children: eyebrow }) : null,
@@ -2684,7 +2585,7 @@ function Hero({
2684
2585
  {
2685
2586
  className: cn(
2686
2587
  "gap-step-sm mt-step-xs flex flex-wrap items-center",
2687
- centrado && "justify-center"
2588
+ centered && "justify-center"
2688
2589
  ),
2689
2590
  children: action
2690
2591
  }
@@ -2692,14 +2593,14 @@ function Hero({
2692
2593
  ]
2693
2594
  }
2694
2595
  ),
2695
- !centrado && pose ? /* @__PURE__ */ jsx(
2696
- Mascota,
2596
+ !centered && pose ? /* @__PURE__ */ jsx(
2597
+ Mascot,
2697
2598
  {
2698
2599
  pose,
2699
2600
  basePath,
2700
2601
  className: cn(
2701
- // En móvil, en el flujo y bajo los botones. Desde md, sangrando por
2702
- // la esquina inferior derecha.
2602
+ // On mobile, in the flow and below the buttons. From md up, bleeding
2603
+ // off the bottom-right corner.
2703
2604
  "mt-step-lg mx-auto w-40",
2704
2605
  "md:mt-0 md:absolute md:right-0 md:-bottom-4 md:mx-0 md:w-64"
2705
2606
  )
@@ -2720,7 +2621,7 @@ function LinkRow({
2720
2621
  const rel = external ? "noopener noreferrer" : props.rel;
2721
2622
  const target = external ? "_blank" : props.target;
2722
2623
  return /* @__PURE__ */ jsx(
2723
- Tarjeta,
2624
+ CardShell,
2724
2625
  {
2725
2626
  className: cn("px-step-md py-step-sm", className),
2726
2627
  ...props,
@@ -2743,39 +2644,48 @@ function LinkRow({
2743
2644
  }
2744
2645
  );
2745
2646
  }
2746
- function Nav({ brand: brand2, children, actions, className, ...props }) {
2647
+ function Nav({ brand: brand2, children, actions, size: size2 = "default", className, ...props }) {
2747
2648
  return /* @__PURE__ */ jsx(
2748
2649
  "header",
2749
2650
  {
2750
2651
  className: cn(
2751
2652
  "sticky top-0 z-50 w-full",
2752
- // abismo al 86 % con 14px de desenfoque detrás. El alfa va sobre el
2753
- // token, así que sigue el modo: en claro es papel al 86 %.
2653
+ // Abyss at 86 % with 14px of blur behind. The alpha rides on the token,
2654
+ // so it follows the mode: in light it is paper at 86 %.
2754
2655
  "bg-background/86 backdrop-blur-[14px]",
2755
2656
  "border-hairline border-b",
2756
2657
  className
2757
2658
  ),
2758
2659
  ...props,
2759
- children: /* @__PURE__ */ jsxs("div", { className: "max-w-wide px-step-md h-nav gap-step-lg mx-auto flex items-center", children: [
2760
- brand2 ? /* @__PURE__ */ jsx("div", { className: "shrink-0", children: brand2 }) : null,
2761
- 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: [
2762
- /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "text-text-muted font-mono text-meta select-none", children: "~/" }),
2763
- children
2764
- ] }) }) : /* @__PURE__ */ jsx("div", { className: "flex-1" }),
2765
- actions ? /* @__PURE__ */ jsx("div", { className: "gap-step-sm flex shrink-0 items-center", children: actions }) : null
2766
- ] })
2660
+ children: /* @__PURE__ */ jsxs(
2661
+ "div",
2662
+ {
2663
+ className: cn(
2664
+ "max-w-wide px-step-md gap-step-lg mx-auto flex items-center",
2665
+ size2 === "compact" ? "h-nav-compact" : "h-nav"
2666
+ ),
2667
+ children: [
2668
+ brand2 ? /* @__PURE__ */ jsx("div", { className: "shrink-0", children: brand2 }) : null,
2669
+ 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: [
2670
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "text-text-muted font-mono text-meta select-none", children: "~/" }),
2671
+ children
2672
+ ] }) }) : /* @__PURE__ */ jsx("div", { className: "flex-1" }),
2673
+ actions ? /* @__PURE__ */ jsx("div", { className: "gap-step-sm flex shrink-0 items-center", children: actions }) : null
2674
+ ]
2675
+ }
2676
+ )
2767
2677
  }
2768
2678
  );
2769
2679
  }
2770
2680
  function NavItem({ active = false, asChild = false, className, children, ...props }) {
2771
- const Raiz = asChild ? Slot : "a";
2681
+ const Root17 = asChild ? Slot : "a";
2772
2682
  return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(
2773
- Raiz,
2683
+ Root17,
2774
2684
  {
2775
2685
  "aria-current": active ? "page" : void 0,
2776
2686
  className: cn(
2777
2687
  "font-mono text-meta transition-standard cursor-pointer",
2778
- "rounded-chip focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent",
2688
+ "rounded-chip focus-ring",
2779
2689
  active ? "text-accent underline decoration-1 underline-offset-4" : "text-text-secondary hover:text-accent",
2780
2690
  className
2781
2691
  ),
@@ -2792,39 +2702,49 @@ function NavItem({ active = false, asChild = false, className, children, ...prop
2792
2702
  function NewsletterForm({
2793
2703
  title,
2794
2704
  description,
2795
- state = "reposo",
2705
+ state = "idle",
2796
2706
  onSubmitEmail,
2797
2707
  successMessage = "Ya est\xE1s dentro. Te llega un correo cada dos semanas, y nada m\xE1s.",
2798
2708
  errorMessage = "No se pudo suscribir ese correo. Rev\xEDsalo y vuelve a intentar.",
2799
2709
  disclaimer,
2800
- expresion,
2710
+ expression,
2801
2711
  basePath,
2802
2712
  submitLabel = "Suscribirme",
2803
- placeholder = "tu@correo.dev",
2713
+ placeholder = "tu@email.dev",
2804
2714
  fieldLabel = "Correo electr\xF3nico",
2805
2715
  nameField = false,
2806
2716
  nameLabel = "Nombre",
2807
2717
  namePlaceholder = "C\xF3mo te llamas",
2808
2718
  nameInputProps,
2719
+ aside,
2720
+ resetOnSuccess = true,
2721
+ onFieldChange,
2722
+ fieldErrors,
2809
2723
  className,
2810
2724
  ...props
2811
2725
  }) {
2812
2726
  const id = useId();
2813
- const enviando = state === "enviando";
2727
+ const form = useRef(null);
2728
+ const sending = state === "sending";
2814
2729
  const error = state === "error";
2815
- function enviar(evento) {
2816
- evento.preventDefault();
2817
- const datos = new FormData(evento.currentTarget);
2818
- const correo = String(datos.get("email") ?? "");
2819
- const nombre = nameField ? String(datos.get("name") ?? "") : void 0;
2820
- onSubmitEmail?.(correo, nombre);
2730
+ const nameError = fieldErrors?.name;
2731
+ const emailError = fieldErrors?.email;
2732
+ useEffect(() => {
2733
+ if (state === "success" && resetOnSuccess) form.current?.reset();
2734
+ }, [state, resetOnSuccess]);
2735
+ function submit(event) {
2736
+ event.preventDefault();
2737
+ const data = new FormData(event.currentTarget);
2738
+ const email = String(data.get("email") ?? "");
2739
+ const name = nameField ? String(data.get("name") ?? "") : void 0;
2740
+ onSubmitEmail?.(email, name);
2821
2741
  }
2822
- const boton = /* @__PURE__ */ jsx(
2742
+ const button2 = /* @__PURE__ */ jsx(
2823
2743
  Button,
2824
2744
  {
2825
2745
  type: "submit",
2826
2746
  variant: "conversion",
2827
- loading: enviando,
2747
+ loading: sending,
2828
2748
  className: cn("disabled:opacity-60", nameField && "sm:self-start"),
2829
2749
  children: submitLabel
2830
2750
  }
@@ -2833,65 +2753,79 @@ function NewsletterForm({
2833
2753
  "section",
2834
2754
  {
2835
2755
  className: cn(
2836
- "degradado-seccion rounded-panel border-hairline p-step-lg gap-step-md flex flex-col border",
2756
+ "gradient-section rounded-panel border-hairline p-step-lg border",
2757
+ // Two columns from `md` up when there is an illustration, one otherwise.
2758
+ // `items-center` centres the pose against the block of text and form
2759
+ // rather than against the panel, which is what the blog was doing by
2760
+ // hand with an absolute position and a reserved `pr`.
2761
+ aside ? "gap-step-lg flex flex-col md:flex-row md:items-center" : "gap-step-md flex flex-col",
2837
2762
  className
2838
2763
  ),
2839
2764
  ...props,
2840
2765
  children: [
2841
- /* @__PURE__ */ jsxs("div", { className: "gap-step-xs flex flex-col", children: [
2842
- /* @__PURE__ */ jsx(Text, { as: "h2", variant: "h3", children: title }),
2843
- description ? /* @__PURE__ */ jsx(Text, { variant: "ui", tone: "secondary", children: description }) : null
2844
- ] }),
2845
- /* @__PURE__ */ jsxs("form", { onSubmit: enviar, className: "gap-step-sm flex flex-col", noValidate: true, children: [
2846
- /* @__PURE__ */ jsxs("div", { className: "gap-step-sm flex flex-col sm:flex-row sm:items-end", children: [
2847
- nameField ? /* @__PURE__ */ jsxs("div", { className: "gap-step-xs flex flex-1 flex-col", children: [
2848
- /* @__PURE__ */ jsx(Label, { htmlFor: `${id}-nombre`, children: nameLabel }),
2849
- /* @__PURE__ */ jsx(
2850
- Input,
2851
- {
2852
- id: `${id}-nombre`,
2853
- name: "name",
2854
- type: "text",
2855
- autoComplete: "name",
2856
- required: true,
2857
- placeholder: namePlaceholder,
2858
- disabled: enviando,
2859
- ...nameInputProps
2860
- }
2861
- )
2862
- ] }) : null,
2863
- /* @__PURE__ */ jsxs("div", { className: "gap-step-xs flex flex-1 flex-col", children: [
2864
- /* @__PURE__ */ jsx(Label, { htmlFor: id, children: fieldLabel }),
2865
- /* @__PURE__ */ jsx(
2866
- Input,
2867
- {
2868
- id,
2869
- name: "email",
2870
- type: "email",
2871
- autoComplete: "email",
2872
- required: true,
2873
- placeholder,
2874
- disabled: enviando,
2875
- invalid: error,
2876
- "aria-describedby": state === "exito" || error ? `${id}-aviso` : void 0
2877
- }
2878
- )
2766
+ /* @__PURE__ */ jsxs("div", { className: cn("gap-step-md flex min-w-0 flex-1 flex-col"), children: [
2767
+ /* @__PURE__ */ jsxs("div", { className: "gap-step-xs flex flex-col", children: [
2768
+ /* @__PURE__ */ jsx(Text, { as: "h2", variant: "h3", children: title }),
2769
+ description ? /* @__PURE__ */ jsx(Text, { variant: "ui", tone: "secondary", children: description }) : null
2770
+ ] }),
2771
+ /* @__PURE__ */ jsxs("form", { ref: form, onSubmit: submit, className: "gap-step-sm flex flex-col", noValidate: true, children: [
2772
+ /* @__PURE__ */ jsxs("div", { className: "gap-step-sm flex flex-col sm:flex-row sm:items-start", children: [
2773
+ nameField ? /* @__PURE__ */ jsxs("div", { className: "gap-step-xs flex flex-1 flex-col", children: [
2774
+ /* @__PURE__ */ jsx(Label, { htmlFor: `${id}-name`, children: nameLabel }),
2775
+ /* @__PURE__ */ jsx(
2776
+ Input,
2777
+ {
2778
+ id: `${id}-name`,
2779
+ name: "name",
2780
+ type: "text",
2781
+ autoComplete: "name",
2782
+ required: true,
2783
+ placeholder: namePlaceholder,
2784
+ disabled: sending,
2785
+ invalid: Boolean(nameError),
2786
+ "aria-describedby": nameError ? `${id}-name-error` : void 0,
2787
+ onChange: (e) => onFieldChange?.("name", e.currentTarget.value),
2788
+ ...nameInputProps
2789
+ }
2790
+ ),
2791
+ nameError ? /* @__PURE__ */ jsx(Text, { id: `${id}-name-error`, variant: "label", tone: "error", as: "p", role: "alert", children: nameError }) : null
2792
+ ] }) : null,
2793
+ /* @__PURE__ */ jsxs("div", { className: "gap-step-xs flex flex-1 flex-col", children: [
2794
+ /* @__PURE__ */ jsx(Label, { htmlFor: id, children: fieldLabel }),
2795
+ /* @__PURE__ */ jsx(
2796
+ Input,
2797
+ {
2798
+ id,
2799
+ name: "email",
2800
+ type: "email",
2801
+ autoComplete: "email",
2802
+ required: true,
2803
+ placeholder,
2804
+ disabled: sending,
2805
+ invalid: error || Boolean(emailError),
2806
+ onChange: (e) => onFieldChange?.("email", e.currentTarget.value),
2807
+ "aria-describedby": emailError ? `${id}-email-error` : state === "success" || error ? `${id}-notice` : void 0
2808
+ }
2809
+ ),
2810
+ emailError ? /* @__PURE__ */ jsx(Text, { id: `${id}-email-error`, variant: "label", tone: "error", as: "p", role: "alert", children: emailError }) : null
2811
+ ] }),
2812
+ nameField ? null : /* @__PURE__ */ jsx("div", { className: "sm:mt-[26px]", children: button2 })
2879
2813
  ] }),
2880
- nameField ? null : boton
2814
+ nameField ? button2 : null
2881
2815
  ] }),
2882
- nameField ? boton : null
2816
+ state === "success" ? /* @__PURE__ */ jsx(Alert, { id: `${id}-notice`, variant: "success", emphasis: "strong", children: successMessage }) : null,
2817
+ error ? /* @__PURE__ */ jsx(Alert, { id: `${id}-notice`, variant: "error", emphasis: "strong", children: errorMessage }) : null,
2818
+ disclaimer ? /* @__PURE__ */ jsxs("div", { className: "gap-step-sm flex items-center", children: [
2819
+ expression ? /* @__PURE__ */ jsx(MascotFace, { expression, basePath, className: "w-10 max-w-none" }) : null,
2820
+ /* @__PURE__ */ jsx(Text, { variant: "label", tone: "muted", as: "p", className: "font-normal", children: disclaimer })
2821
+ ] }) : null
2883
2822
  ] }),
2884
- state === "exito" ? /* @__PURE__ */ jsx(Alert, { id: `${id}-aviso`, variant: "success", enfasis: "fuerte", children: successMessage }) : null,
2885
- error ? /* @__PURE__ */ jsx(Alert, { id: `${id}-aviso`, variant: "error", enfasis: "fuerte", children: errorMessage }) : null,
2886
- disclaimer ? /* @__PURE__ */ jsxs("div", { className: "gap-step-sm flex items-center", children: [
2887
- expresion ? /* @__PURE__ */ jsx(CaraDeMascota, { expresion, basePath, className: "w-10 max-w-none" }) : null,
2888
- /* @__PURE__ */ jsx(Text, { variant: "label", tone: "muted", as: "p", className: "font-normal", children: disclaimer })
2889
- ] }) : null
2823
+ aside ? /* @__PURE__ */ jsx("div", { className: "shrink-0 md:max-w-[42%]", children: aside }) : null
2890
2824
  ]
2891
2825
  }
2892
2826
  );
2893
2827
  }
2894
- var cabecera = cva("gap-step-sm flex flex-col", {
2828
+ var header = cva("gap-step-sm flex flex-col", {
2895
2829
  variants: {
2896
2830
  size: {
2897
2831
  display: "py-section",
@@ -2910,7 +2844,7 @@ function PageHeader({
2910
2844
  className,
2911
2845
  ...props
2912
2846
  }) {
2913
- return /* @__PURE__ */ jsxs("header", { className: cn(cabecera({ size: size2 }), className), ...props, children: [
2847
+ return /* @__PURE__ */ jsxs("header", { className: cn(header({ size: size2 }), className), ...props, children: [
2914
2848
  eyebrow ? /* @__PURE__ */ jsx(Text, { variant: "eyebrow", tone: "accent", as: "p", children: eyebrow }) : null,
2915
2849
  /* @__PURE__ */ jsx(Text, { as, variant: size2 === "display" ? "display" : "h1", className: "max-w-measure", children: title }),
2916
2850
  description ? /* @__PURE__ */ jsx(Text, { variant: "body", tone: "secondary", children: description }) : null,
@@ -2924,33 +2858,33 @@ function ScrollingProgressBar({
2924
2858
  className,
2925
2859
  ...props
2926
2860
  }) {
2927
- const [avance, setAvance] = useState(0);
2928
- const pendiente = useRef(0);
2861
+ const [seek, setAvance] = useState(0);
2862
+ const pendingOne = useRef(0);
2929
2863
  useEffect(() => {
2930
- const medir = () => {
2931
- pendiente.current = 0;
2932
- const elemento = target?.current;
2933
- const inicio = elemento ? elemento.getBoundingClientRect().top + scrollY : 0;
2934
- const alto = elemento ? elemento.offsetHeight : document.documentElement.scrollHeight;
2935
- const recorrible = alto - innerHeight;
2936
- if (recorrible <= 0) {
2937
- setAvance(scrollY >= inicio ? 100 : 0);
2864
+ const measure = () => {
2865
+ pendingOne.current = 0;
2866
+ const element = target?.current;
2867
+ const start = element ? element.getBoundingClientRect().top + scrollY : 0;
2868
+ const height = element ? element.offsetHeight : document.documentElement.scrollHeight;
2869
+ const walkable = height - innerHeight;
2870
+ if (walkable <= 0) {
2871
+ setAvance(scrollY >= start ? 100 : 0);
2938
2872
  return;
2939
2873
  }
2940
- const recorrido = scrollY - inicio;
2941
- setAvance(Math.min(100, Math.max(0, recorrido / recorrible * 100)));
2874
+ const walk = scrollY - start;
2875
+ setAvance(Math.min(100, Math.max(0, walk / walkable * 100)));
2942
2876
  };
2943
- const alMoverse = () => {
2944
- if (pendiente.current) return;
2945
- pendiente.current = requestAnimationFrame(medir);
2877
+ const onMove = () => {
2878
+ if (pendingOne.current) return;
2879
+ pendingOne.current = requestAnimationFrame(measure);
2946
2880
  };
2947
- medir();
2948
- addEventListener("scroll", alMoverse, { passive: true });
2949
- addEventListener("resize", alMoverse);
2881
+ measure();
2882
+ addEventListener("scroll", onMove, { passive: true });
2883
+ addEventListener("resize", onMove);
2950
2884
  return () => {
2951
- if (pendiente.current) cancelAnimationFrame(pendiente.current);
2952
- removeEventListener("scroll", alMoverse);
2953
- removeEventListener("resize", alMoverse);
2885
+ if (pendingOne.current) cancelAnimationFrame(pendingOne.current);
2886
+ removeEventListener("scroll", onMove);
2887
+ removeEventListener("resize", onMove);
2954
2888
  };
2955
2889
  }, [target]);
2956
2890
  return /* @__PURE__ */ jsx(
@@ -2967,75 +2901,181 @@ function ScrollingProgressBar({
2967
2901
  "div",
2968
2902
  {
2969
2903
  className: cn("h-full", tone === "warm" ? "bg-warm" : "bg-accent"),
2970
- style: { width: `${avance}%` }
2904
+ style: { width: `${seek}%` }
2971
2905
  }
2972
2906
  )
2973
2907
  }
2974
2908
  );
2975
2909
  }
2910
+ var Collapsed = createContext(false);
2976
2911
  function SidebarItem({
2977
2912
  active = false,
2978
2913
  asChild = false,
2979
2914
  badge: badge2,
2915
+ icon,
2980
2916
  className,
2981
2917
  children,
2982
2918
  ...props
2983
2919
  }) {
2984
- const Raiz = asChild ? Slot : "a";
2920
+ const Root17 = asChild ? Slot : "a";
2921
+ const collapsed = useContext(Collapsed);
2985
2922
  return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(
2986
- Raiz,
2923
+ Root17,
2987
2924
  {
2988
2925
  "aria-current": active ? "page" : void 0,
2989
2926
  className: cn(
2990
2927
  "rounded-chip px-step-sm gap-step-xs flex cursor-pointer items-center py-1.5",
2928
+ collapsed && "justify-center",
2991
2929
  "font-mono text-meta transition-standard",
2992
- "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent",
2993
- // El activo es fondo `surfaceRaised` y tinta primaria, igual que
2994
- // `TabsTrigger`. NO bioluz: `tokens.ts` lo dice explícito — acento
2995
- // claro pasa sobre background y sobre surface, pero sobre
2996
- // surfaceRaised mide 4.2 y no es color de texto ahí. El acento se
2997
- // queda en el `▸`, que es decorativo y le aplica el umbral de 3:1.
2930
+ "focus-ring",
2931
+ // The active item is `surfaceRaised` with primary ink, same as
2932
+ // `TabsTrigger`. NOT biolume: `tokens.ts` says so explicitly — light
2933
+ // accent passes over background and over surface, but over
2934
+ // surfaceRaised it measures 4.2 and is not a text color there. The
2935
+ // accent stays on the `▸`, which is decorative and gets the 3:1
2936
+ // threshold.
2998
2937
  active ? "bg-surface-raised text-text-primary" : "text-text-secondary hover:text-text-primary hover:bg-surface-raised",
2999
2938
  className
3000
2939
  ),
3001
2940
  ...props,
3002
2941
  children: [
3003
- /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: active ? "text-accent" : "text-text-muted", children: "\u25B8" }),
3004
- /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate", children }),
3005
- badge2 ? /* @__PURE__ */ jsx("span", { className: "text-text-muted shrink-0", children: badge2 }) : null
2942
+ icon ? (
2943
+ // A shade bigger than the 13px mono label, which is what keeps it
2944
+ // reading as a glyph rather than as a character in the word.
2945
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "text-body shrink-0", children: icon })
2946
+ ) : /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: active ? "text-accent" : "text-text-muted", children: "\u25B8" }),
2947
+ /* @__PURE__ */ jsx("span", { className: collapsed ? "sr-only" : "min-w-0 flex-1 truncate", children }),
2948
+ badge2 ? /* @__PURE__ */ jsx("span", { className: cn("text-text-muted", collapsed ? "sr-only" : "shrink-0"), children: badge2 }) : null
3006
2949
  ]
3007
2950
  }
3008
2951
  ) });
3009
2952
  }
2953
+ function SidebarGroup({ label, children, className, ...props }) {
2954
+ const id = useId();
2955
+ const collapsed = useContext(Collapsed);
2956
+ return /* @__PURE__ */ jsxs(
2957
+ "li",
2958
+ {
2959
+ className: cn(
2960
+ "mt-step-md first:mt-0",
2961
+ // In a rail the label has nowhere to go, so the block becomes a rule.
2962
+ // The label itself stays in the accessibility tree naming the list.
2963
+ collapsed && "border-hairline pt-step-md mt-step-sm border-t first:border-t-0",
2964
+ className
2965
+ ),
2966
+ ...props,
2967
+ children: [
2968
+ /* @__PURE__ */ jsx(
2969
+ Text,
2970
+ {
2971
+ variant: "meta",
2972
+ tone: "muted",
2973
+ as: "p",
2974
+ id,
2975
+ className: collapsed ? "sr-only" : "px-step-sm pb-step-xs",
2976
+ children: label
2977
+ }
2978
+ ),
2979
+ /* @__PURE__ */ jsx("ul", { "aria-labelledby": id, className: "gap-0.5 flex flex-col", children })
2980
+ ]
2981
+ }
2982
+ );
2983
+ }
3010
2984
  function SidebarNav({
3011
2985
  title,
2986
+ brand: brand2,
2987
+ mark,
2988
+ user,
2989
+ collapsed = false,
2990
+ onCollapsedChange,
2991
+ collapseLabel = "Plegar el panel",
2992
+ expandLabel = "Desplegar el panel",
3012
2993
  version,
3013
2994
  branch,
3014
2995
  children,
3015
2996
  className,
3016
2997
  ...props
3017
2998
  }) {
3018
- const pie = [version, branch].filter(Boolean);
3019
- return /* @__PURE__ */ jsxs(
2999
+ const footer = [version, branch].filter(Boolean);
3000
+ const top = collapsed ? mark : brand2;
3001
+ return /* @__PURE__ */ jsx(Collapsed.Provider, { value: collapsed, children: /* @__PURE__ */ jsxs(
3020
3002
  "nav",
3021
3003
  {
3022
3004
  "aria-label": typeof title === "string" ? title : "Administraci\xF3n",
3023
3005
  className: cn(
3024
3006
  "border-hairline bg-surface p-step-sm gap-step-sm flex h-full flex-col border-r",
3007
+ // The width is the component's only when it can collapse: the layout
3008
+ // beside it has to reserve one of the two, and it cannot know which.
3009
+ // It does NOT transition. The system's only transition animates colour
3010
+ // and border, and a rail that slides is the entrance animation this
3011
+ // library does not have — same call as the `Switch` knob, which changes
3012
+ // position without moving.
3013
+ onCollapsedChange && (collapsed ? "w-sidebar-rail" : "w-sidebar"),
3025
3014
  className
3026
3015
  ),
3027
3016
  ...props,
3028
3017
  children: [
3029
- title ? /* @__PURE__ */ jsx(Text, { variant: "eyebrow", tone: "muted", as: "p", className: "px-step-sm", children: title }) : null,
3018
+ top || onCollapsedChange ? /* @__PURE__ */ jsxs(
3019
+ "div",
3020
+ {
3021
+ className: cn(
3022
+ "border-hairline px-step-sm pb-step-sm mb-step-xs gap-step-xs flex items-center border-b",
3023
+ collapsed ? "justify-center" : "justify-between"
3024
+ ),
3025
+ children: [
3026
+ top ? /* @__PURE__ */ jsx("span", { className: "min-w-0", children: top }) : null,
3027
+ onCollapsedChange ? /* @__PURE__ */ jsx(
3028
+ "button",
3029
+ {
3030
+ type: "button",
3031
+ onClick: () => onCollapsedChange(!collapsed),
3032
+ "aria-expanded": !collapsed,
3033
+ "aria-label": collapsed ? expandLabel : collapseLabel,
3034
+ className: cn(
3035
+ "rounded-chip transition-standard shrink-0 cursor-pointer p-1",
3036
+ "text-text-muted hover:text-text-primary hover:bg-surface-raised",
3037
+ "focus-ring"
3038
+ ),
3039
+ children: collapsed ? /* @__PURE__ */ jsx(ChevronRight, {}) : /* @__PURE__ */ jsx(ChevronLeft, {})
3040
+ }
3041
+ ) : null
3042
+ ]
3043
+ }
3044
+ ) : null,
3045
+ title && !collapsed ? /* @__PURE__ */ jsx(Text, { variant: "eyebrow", tone: "muted", as: "p", className: "px-step-sm", children: title }) : null,
3030
3046
  /* @__PURE__ */ jsx("ul", { className: "gap-0.5 flex flex-1 flex-col", children }),
3031
- pie.length > 0 ? /* @__PURE__ */ jsx(Text, { variant: "meta", tone: "muted", as: "p", className: "border-hairline px-step-sm pt-step-sm border-t", children: pie.map((p, i) => /* @__PURE__ */ jsxs("span", { children: [
3032
- i > 0 ? /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: " \xB7 " }) : null,
3033
- p
3034
- ] }, i)) }) : null
3047
+ user ? /* @__PURE__ */ jsx(
3048
+ "div",
3049
+ {
3050
+ className: cn(
3051
+ "border-hairline px-step-sm pt-step-sm border-t",
3052
+ collapsed && "flex justify-center"
3053
+ ),
3054
+ children: user
3055
+ }
3056
+ ) : null,
3057
+ footer.length > 0 && !collapsed ? /* @__PURE__ */ jsx(
3058
+ Text,
3059
+ {
3060
+ variant: "meta",
3061
+ tone: "muted",
3062
+ as: "p",
3063
+ className: cn("px-step-sm", user ? "" : "border-hairline pt-step-sm border-t"),
3064
+ children: footer.map((p, i) => /* @__PURE__ */ jsxs("span", { children: [
3065
+ i > 0 ? /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: " \xB7 " }) : null,
3066
+ p
3067
+ ] }, i))
3068
+ }
3069
+ ) : null
3035
3070
  ]
3036
3071
  }
3037
- );
3072
+ ) });
3038
3073
  }
3074
+ var DELTA = {
3075
+ up: { glyph: ChevronUp, label: "sube" },
3076
+ down: { glyph: ChevronDown, label: "baja" },
3077
+ flat: { glyph: Minus, label: "sin cambio" }
3078
+ };
3039
3079
  function Stat({
3040
3080
  value,
3041
3081
  label,
@@ -3043,30 +3083,52 @@ function Stat({
3043
3083
  progress,
3044
3084
  icon,
3045
3085
  description,
3086
+ delta,
3087
+ spark,
3046
3088
  className,
3047
3089
  ...props
3048
3090
  }) {
3049
- return /* @__PURE__ */ jsxs("div", { className: cn(SUPERFICIE_TARJETA, "p-step-lg gap-step-xs flex flex-col", className), ...props, children: [
3050
- /* @__PURE__ */ jsxs(Text, { variant: "eyebrow", tone: "muted", as: "p", className: "gap-step-xs flex items-center", children: [
3091
+ const DeltaGlyph = delta ? DELTA[delta.direction].glyph : null;
3092
+ return /* @__PURE__ */ jsxs("div", { className: cn(CARD_SURFACE, "p-step-lg gap-step-xs flex flex-col", className), ...props, children: [
3093
+ /* @__PURE__ */ jsxs("div", { className: "gap-step-sm flex items-start justify-between", children: [
3094
+ /* @__PURE__ */ jsx(Text, { variant: "eyebrow", tone: "muted", as: "p", className: "min-w-0", children: label }),
3051
3095
  icon ? (
3052
- // `aria-hidden` no hace falta: los glifos del sistema ya lo traen
3053
- // puesto. Lo que sí hace falta es que no encoja al lado de un título
3054
- // largo, porque un icono aplastado se lee como otro icono.
3055
- /* @__PURE__ */ jsx("span", { className: "shrink-0", children: icon })
3056
- ) : null,
3057
- label
3096
+ // `aria-hidden` is not needed: the system's glyphs already carry it.
3097
+ // The circle is a SURFACE — the tint at 10 %, same as an alert's — and
3098
+ // the colour stays on the glyph, which is § 4b and also what keeps it
3099
+ // on the 3:1 graphical threshold instead of text's 4.5.
3100
+ /* @__PURE__ */ jsx(
3101
+ "span",
3102
+ {
3103
+ className: cn(
3104
+ "size-control-icon-sm text-ui flex shrink-0 items-center justify-center rounded-full",
3105
+ tone === "neutral" ? "bg-accent/10 text-accent" : "bg-warm/10 text-warm"
3106
+ ),
3107
+ children: icon
3108
+ }
3109
+ )
3110
+ ) : null
3058
3111
  ] }),
3059
- /* @__PURE__ */ jsx(Text, { variant: "stat", as: "p", tone: tone === "alerta" ? "warm" : "accent", children: value }),
3112
+ /* @__PURE__ */ jsx(Text, { variant: "stat", as: "p", tone: tone === "neutral" ? "primary" : "warm", children: value }),
3113
+ delta && DeltaGlyph ? /* @__PURE__ */ jsxs(Text, { variant: "label", tone: "secondary", as: "p", className: "gap-step-xs flex items-center", children: [
3114
+ /* @__PURE__ */ jsxs("span", { className: "sr-only", children: [
3115
+ DELTA[delta.direction].label,
3116
+ " "
3117
+ ] }),
3118
+ /* @__PURE__ */ jsx(DeltaGlyph, { className: "shrink-0" }),
3119
+ delta.value
3120
+ ] }) : null,
3060
3121
  description ? /* @__PURE__ */ jsx(Text, { variant: "ui", tone: "secondary", as: "p", children: description }) : null,
3061
3122
  typeof progress === "number" ? /* @__PURE__ */ jsx(
3062
3123
  Progress,
3063
3124
  {
3064
3125
  value: progress,
3065
- tone: tone === "alerta" ? "warm" : "accent",
3126
+ tone: tone === "neutral" ? "accent" : "warm",
3066
3127
  label: `${label}: ${progress}%`,
3067
3128
  className: "mt-step-sm"
3068
3129
  }
3069
- ) : null
3130
+ ) : null,
3131
+ spark ? /* @__PURE__ */ jsx("div", { className: "mt-auto pt-step-md", children: spark }) : null
3070
3132
  ] });
3071
3133
  }
3072
3134
  function TalkCard({
@@ -3077,25 +3139,55 @@ function TalkCard({
3077
3139
  location,
3078
3140
  status,
3079
3141
  description,
3142
+ resources,
3080
3143
  className,
3081
3144
  ...props
3082
3145
  }) {
3083
- const pie = [
3084
- date ? /* @__PURE__ */ jsx("time", { dateTime, children: date }, "fecha") : null,
3085
- location ? /* @__PURE__ */ jsx("span", { children: location }, "lugar") : null
3146
+ const footer = [
3147
+ date ? /* @__PURE__ */ jsx("time", { dateTime, children: date }, "date") : null,
3148
+ location ? /* @__PURE__ */ jsx("span", { children: location }, "location") : null
3086
3149
  ].filter(Boolean);
3087
- return /* @__PURE__ */ jsx(Tarjeta, { className: cn("p-step-lg", className), ...props, children: /* @__PURE__ */ jsxs("article", { className: "gap-step-sm flex h-full flex-col", children: [
3150
+ const body = /* @__PURE__ */ jsxs(Fragment, { children: [
3088
3151
  /* @__PURE__ */ jsxs("div", { className: "gap-step-sm flex items-start justify-between", children: [
3089
3152
  /* @__PURE__ */ jsx(Text, { variant: "eyebrow", tone: "accent", as: "p", children: event }),
3090
3153
  status ? /* @__PURE__ */ jsx(Badge, { variant: "neutral", children: status }) : null
3091
3154
  ] }),
3092
- /* @__PURE__ */ jsx(Text, { as: "h3", variant: "h3", className: "group-hover:text-accent transition-standard", children: title }),
3155
+ /* @__PURE__ */ jsx(
3156
+ Text,
3157
+ {
3158
+ as: "h3",
3159
+ variant: "h3",
3160
+ className: cn(!resources && "group-hover:text-accent transition-standard"),
3161
+ children: title
3162
+ }
3163
+ ),
3093
3164
  description ? /* @__PURE__ */ jsx(Text, { variant: "ui", tone: "secondary", className: "line-clamp-2", children: description }) : null,
3094
- 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: [
3095
- i > 0 ? /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\xB7" }) : null,
3096
- m
3097
- ] }, i)) }) : null
3098
- ] }) });
3165
+ footer.length > 0 ? /* @__PURE__ */ jsx(
3166
+ Text,
3167
+ {
3168
+ variant: "label",
3169
+ tone: "muted",
3170
+ as: "p",
3171
+ className: cn("gap-step-xs flex items-center pt-step-sm", !resources && "mt-auto"),
3172
+ children: footer.map((m, i) => /* @__PURE__ */ jsxs("span", { className: "gap-step-xs flex items-center", children: [
3173
+ i > 0 ? /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\xB7" }) : null,
3174
+ m
3175
+ ] }, i))
3176
+ }
3177
+ ) : null,
3178
+ resources ? /* @__PURE__ */ jsx("div", { className: "gap-step-md mt-auto flex flex-wrap items-center pt-step-sm", children: resources }) : null
3179
+ ] });
3180
+ if (resources) {
3181
+ return /* @__PURE__ */ jsx(
3182
+ "article",
3183
+ {
3184
+ className: cn(CARD_SURFACE, "p-step-lg gap-step-sm flex h-full flex-col", className),
3185
+ ...props,
3186
+ children: body
3187
+ }
3188
+ );
3189
+ }
3190
+ return /* @__PURE__ */ jsx(CardShell, { className: cn("p-step-lg", className), ...props, children: /* @__PURE__ */ jsx("article", { className: "gap-step-sm flex h-full flex-col", children: body }) });
3099
3191
  }
3100
3192
  function ThemeToggle({
3101
3193
  label = "Cambiar de tema",
@@ -3113,20 +3205,20 @@ function ThemeToggle({
3113
3205
  size: size2,
3114
3206
  "aria-label": label,
3115
3207
  className: cn("[&_svg]:size-[19px]", className),
3116
- onClick: () => onThemeChange?.(alternarTema()),
3208
+ onClick: () => onThemeChange?.(toggleTheme()),
3117
3209
  ...props,
3118
3210
  children: [
3119
- /* @__PURE__ */ jsx(Sol, { className: "light:hidden" }),
3120
- /* @__PURE__ */ jsx(Luna, { className: "hidden light:block" })
3211
+ /* @__PURE__ */ jsx(Sun, { className: "light:hidden" }),
3212
+ /* @__PURE__ */ jsx(Moon, { className: "hidden light:block" })
3121
3213
  ]
3122
3214
  }
3123
3215
  );
3124
3216
  }
3125
- function useTema() {
3126
- return useSyncExternalStore(suscribirse2, temaActual, servidor);
3217
+ function useTheme() {
3218
+ return useSyncExternalStore(subscribe2, currentTheme, server);
3127
3219
  }
3128
- var suscribirse2 = (avisar) => escucharTema(() => avisar());
3129
- var servidor = () => "dark";
3220
+ var subscribe2 = (warn) => watchTheme(() => warn());
3221
+ var server = () => "dark";
3130
3222
  function TableOfContents({
3131
3223
  items,
3132
3224
  title = "En esta p\xE1gina",
@@ -3138,83 +3230,22 @@ function TableOfContents({
3138
3230
  return /* @__PURE__ */ jsxs("nav", { "aria-label": typeof title === "string" ? title : "En esta p\xE1gina", className: cn("gap-step-sm flex flex-col", className), ...props, children: [
3139
3231
  /* @__PURE__ */ jsx(Text, { variant: "eyebrow", tone: "muted", as: "p", children: title }),
3140
3232
  /* @__PURE__ */ jsx("ul", { className: "border-hairline gap-step-xs flex flex-col border-l", children: items.map((item2) => {
3141
- const activo = item2.href === activeHref;
3142
- const clases = cn(
3233
+ const active = item2.href === activeHref;
3234
+ const classes = cn(
3143
3235
  "px-step-sm -ml-px block border-l",
3144
3236
  "font-sans text-label transition-standard",
3145
- "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent",
3237
+ "focus-ring",
3146
3238
  "cursor-pointer",
3147
3239
  item2.nested && "pl-step-lg",
3148
3240
  "border-transparent text-text-secondary hover:text-text-primary",
3149
- // El hover del activo se declara con las dos variantes juntas para
3150
- // que gane al `hover:` de arriba por especificidad y no por el orden
3151
- // en que Tailwind decida emitir las reglas.
3241
+ // The active hover is declared with both variants together so it
3242
+ // beats the `hover:` above by specificity and not by the order
3243
+ // Tailwind happens to emit the rules in.
3152
3244
  "aria-[current]:border-accent aria-[current]:text-accent aria-[current]:hover:text-accent"
3153
3245
  );
3154
- 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);
3246
+ return /* @__PURE__ */ jsx("li", { children: linkAsChild ? /* @__PURE__ */ jsx(Slot, { className: classes, "aria-current": active ? "location" : void 0, children: linkAsChild({ href: item2.href, children: item2.label }) }) : /* @__PURE__ */ jsx("a", { href: item2.href, className: classes, "aria-current": active ? "location" : void 0, children: item2.label }) }, item2.href);
3155
3247
  }) })
3156
3248
  ] });
3157
3249
  }
3158
3250
 
3159
- // src/lib/social.tsx
3160
- var social_exports = {};
3161
- __export(social_exports, {
3162
- Correo: () => Correo,
3163
- Discord: () => Discord,
3164
- GitHub: () => GitHub,
3165
- Instagram: () => Instagram,
3166
- LinkedIn: () => LinkedIn,
3167
- Rss: () => Rss,
3168
- X: () => X,
3169
- YouTube: () => YouTube
3170
- });
3171
- function Marca({ children, ...props }) {
3172
- return /* @__PURE__ */ jsx(
3173
- "svg",
3174
- {
3175
- viewBox: "0 0 24 24",
3176
- width: "1em",
3177
- height: "1em",
3178
- fill: "currentColor",
3179
- "aria-hidden": "true",
3180
- focusable: "false",
3181
- ...props,
3182
- children
3183
- }
3184
- );
3185
- }
3186
- function Funcional({ children, ...props }) {
3187
- return /* @__PURE__ */ jsx(
3188
- "svg",
3189
- {
3190
- viewBox: "0 0 24 24",
3191
- width: "1em",
3192
- height: "1em",
3193
- fill: "none",
3194
- stroke: "currentColor",
3195
- strokeWidth: 1.6,
3196
- strokeLinecap: "round",
3197
- strokeLinejoin: "round",
3198
- "aria-hidden": "true",
3199
- focusable: "false",
3200
- ...props,
3201
- children
3202
- }
3203
- );
3204
- }
3205
- var GitHub = (props) => /* @__PURE__ */ jsx(Marca, { ...props, children: /* @__PURE__ */ jsx("path", { d: "M12 .5C5.73.5.5 5.73.5 12a11.5 11.5 0 0 0 7.86 10.91c.58.1.79-.25.79-.55 0-.27-.01-1.18-.02-2.14-3.2.7-3.88-1.36-3.88-1.36-.52-1.33-1.28-1.68-1.28-1.68-1.05-.72.08-.7.08-.7 1.16.08 1.77 1.19 1.77 1.19 1.03 1.77 2.7 1.26 3.36.96.1-.75.4-1.26.73-1.55-2.55-.29-5.24-1.28-5.24-5.69 0-1.26.45-2.29 1.19-3.09-.12-.29-.52-1.46.11-3.05 0 0 .97-.31 3.18 1.18a11 11 0 0 1 5.79 0c2.2-1.49 3.17-1.18 3.17-1.18.63 1.59.23 2.76.12 3.05.74.8 1.18 1.83 1.18 3.09 0 4.42-2.69 5.39-5.25 5.68.41.36.78 1.06.78 2.14 0 1.55-.01 2.79-.01 3.17 0 .3.2.66.79.55A11.5 11.5 0 0 0 23.5 12C23.5 5.73 18.27.5 12 .5Z" }) });
3206
- var LinkedIn = (props) => /* @__PURE__ */ jsx(Marca, { ...props, children: /* @__PURE__ */ jsx("path", { d: "M4.98 3.5a2.5 2.5 0 1 1 0 5 2.5 2.5 0 0 1 0-5ZM3 9h4v12H3V9Zm7 0h3.8v1.71h.05a4.17 4.17 0 0 1 3.75-2.06c4.01 0 4.75 2.64 4.75 6.07V21h-4v-5.4c0-1.29-.02-2.95-1.8-2.95-1.8 0-2.08 1.4-2.08 2.85V21h-3.97V9Z" }) });
3207
- var X = (props) => /* @__PURE__ */ jsx(Marca, { ...props, children: /* @__PURE__ */ jsx("path", { d: "M17.53 3h3.06l-6.69 7.64L21.75 21h-6.16l-4.83-6.3L5.25 21H2.19l7.15-8.17L2.5 3h6.32l4.36 5.77L17.53 3Zm-1.07 16.17h1.7L7.62 4.74H5.8l10.66 14.43Z" }) });
3208
- var Instagram = (props) => /* @__PURE__ */ jsx(Marca, { ...props, children: /* @__PURE__ */ jsx("path", { d: "M12 2.16c3.2 0 3.58.01 4.85.07 1.17.05 1.8.25 2.23.41.56.22.96.48 1.38.9.42.42.68.82.9 1.38.16.42.36 1.06.41 2.23.06 1.27.07 1.65.07 4.85s-.01 3.58-.07 4.85c-.05 1.17-.25 1.8-.41 2.23-.22.56-.48.96-.9 1.38-.42.42-.82.68-1.38.9-.42.16-1.06.36-2.23.41-1.27.06-1.65.07-4.85.07s-3.58-.01-4.85-.07c-1.17-.05-1.8-.25-2.23-.41-.56-.22-.96-.48-1.38-.9-.42-.42-.68-.82-.9-1.38-.16-.42-.36-1.06-.41-2.23C2.17 15.58 2.16 15.2 2.16 12s.01-3.58.07-4.85c.05-1.17.25-1.8.41-2.23.22-.56.48-.96.9-1.38.42-.42.82-.68 1.38-.9.42-.16 1.06-.36 2.23-.41C8.42 2.17 8.8 2.16 12 2.16Zm0 3.68a6.16 6.16 0 1 0 0 12.32 6.16 6.16 0 0 0 0-12.32Zm0 10.16a4 4 0 1 1 0-8 4 4 0 0 1 0 8Zm7.85-10.4a1.44 1.44 0 1 1-2.88 0 1.44 1.44 0 0 1 2.88 0Z" }) });
3209
- var Discord = (props) => /* @__PURE__ */ jsx(Marca, { ...props, children: /* @__PURE__ */ jsx("path", { d: "M20.32 5.56A18.5 18.5 0 0 0 15.7 4.1a.07.07 0 0 0-.07.04c-.2.36-.42.82-.58 1.19a17 17 0 0 0-5.1 0c-.16-.38-.39-.83-.59-1.19a.07.07 0 0 0-.07-.04c-1.6.28-3.15.77-4.62 1.46a.06.06 0 0 0-.03.03C1.66 10 .9 14.28 1.28 18.5a.08.08 0 0 0 .03.05 18.6 18.6 0 0 0 5.6 2.84.07.07 0 0 0 .08-.03c.43-.59.81-1.21 1.14-1.86a.07.07 0 0 0-.04-.1c-.6-.23-1.18-.51-1.74-.83a.07.07 0 0 1-.01-.12l.35-.27a.07.07 0 0 1 .07-.01 13.3 13.3 0 0 0 11.3 0 .07.07 0 0 1 .08.01l.34.27c.04.04.04.1-.01.12-.55.33-1.13.6-1.74.83a.07.07 0 0 0-.04.1c.34.65.72 1.27 1.14 1.86a.07.07 0 0 0 .08.03 18.5 18.5 0 0 0 5.6-2.84.07.07 0 0 0 .04-.05c.45-4.88-.75-9.12-3.18-12.88a.06.06 0 0 0-.03-.03ZM8.4 15.93c-1.1 0-2.01-1.01-2.01-2.25 0-1.24.89-2.25 2.01-2.25 1.13 0 2.03 1.02 2.02 2.25 0 1.24-.9 2.25-2.02 2.25Zm7.22 0c-1.1 0-2.01-1.01-2.01-2.25 0-1.24.89-2.25 2.01-2.25 1.13 0 2.03 1.02 2.02 2.25 0 1.24-.89 2.25-2.02 2.25Z" }) });
3210
- var YouTube = (props) => /* @__PURE__ */ jsx(Marca, { ...props, children: /* @__PURE__ */ jsx("path", { d: "M23.5 6.9a3 3 0 0 0-2.12-2.12C19.5 4.27 12 4.27 12 4.27s-7.5 0-9.38.51A3 3 0 0 0 .5 6.9 31.3 31.3 0 0 0 0 12a31.3 31.3 0 0 0 .5 5.1 3 3 0 0 0 2.12 2.12c1.88.51 9.38.51 9.38.51s7.5 0 9.38-.51a3 3 0 0 0 2.12-2.12A31.3 31.3 0 0 0 24 12a31.3 31.3 0 0 0-.5-5.1ZM9.6 15.6V8.4l6.24 3.6-6.24 3.6Z" }) });
3211
- var Rss = (props) => /* @__PURE__ */ jsxs(Funcional, { ...props, children: [
3212
- /* @__PURE__ */ jsx("path", { d: "M4 11a9 9 0 0 1 9 9M4 4a16 16 0 0 1 16 16" }),
3213
- /* @__PURE__ */ jsx("circle", { cx: "5", cy: "19", r: "1.6", fill: "currentColor", stroke: "none" })
3214
- ] });
3215
- var Correo = (props) => /* @__PURE__ */ jsxs(Funcional, { ...props, children: [
3216
- /* @__PURE__ */ jsx("rect", { x: "2.75", y: "4.75", width: "18.5", height: "14.5", rx: "2" }),
3217
- /* @__PURE__ */ jsx("path", { d: "m3.5 7.5 7.4 5.2a2 2 0 0 0 2.2 0l7.4-5.2" })
3218
- ] });
3219
-
3220
- 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 };
3251
+ 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, Hero, Input, LinkRow, MetricBadge, Nav, NavItem, NewsletterForm, PageHeader, Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, Progress, RadioGroup2 as RadioGroup, RadioGroupItem, ScrollingProgressBar, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectSeparator, SelectTrigger, SelectValue, Separator3 as Separator, Sheet, SheetBody, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger, SidebarGroup, 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, toast2 as toast, useTheme };