@riverbankcms/sdk 0.4.2 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (180) hide show
  1. package/README.md +84 -0
  2. package/dist/cli/index.js +3104 -120
  3. package/dist/cli/index.js.map +1 -1
  4. package/dist/client/analytics.js +1 -1
  5. package/dist/client/analytics.js.map +1 -1
  6. package/dist/client/analytics.mjs +1 -1
  7. package/dist/client/analytics.mjs.map +1 -1
  8. package/dist/client/bookings.js +6 -6
  9. package/dist/client/bookings.js.map +1 -1
  10. package/dist/client/bookings.mjs +6 -6
  11. package/dist/client/bookings.mjs.map +1 -1
  12. package/dist/client/client.d.mts +2 -2
  13. package/dist/client/client.d.ts +2 -2
  14. package/dist/client/client.js +1368 -520
  15. package/dist/client/client.js.map +1 -1
  16. package/dist/client/client.mjs +1368 -520
  17. package/dist/client/client.mjs.map +1 -1
  18. package/dist/client/hooks.d.mts +2 -2
  19. package/dist/client/hooks.d.ts +2 -2
  20. package/dist/client/hooks.js +26 -11
  21. package/dist/client/hooks.js.map +1 -1
  22. package/dist/client/hooks.mjs +26 -11
  23. package/dist/client/hooks.mjs.map +1 -1
  24. package/dist/client/rendering/client.js +24 -14
  25. package/dist/client/rendering/client.js.map +1 -1
  26. package/dist/client/rendering/client.mjs +24 -14
  27. package/dist/client/rendering/client.mjs.map +1 -1
  28. package/dist/client/usePage--fGlyrgj.d.mts +6439 -0
  29. package/dist/client/usePage-BTPnCuWC.d.mts +6511 -0
  30. package/dist/client/usePage-BafOS9UT.d.mts +6512 -0
  31. package/dist/client/usePage-Bnx-kA6x.d.mts +6670 -0
  32. package/dist/client/usePage-CE7X5NcN.d.ts +6439 -0
  33. package/dist/client/usePage-DoPI6b8V.d.ts +6511 -0
  34. package/dist/client/usePage-QNWArrVO.d.ts +6670 -0
  35. package/dist/client/usePage-fBgPB6Oq.d.ts +6512 -0
  36. package/dist/server/{Layout-kRv5sU81.d.ts → Layout-B-q2Py4v.d.ts} +4 -4
  37. package/dist/server/{Layout-ByUnm35V.d.mts → Layout-Cc5HUXAH.d.mts} +4 -4
  38. package/dist/server/{chunk-6JBKKV3G.js → chunk-2KCF2DNK.js} +30 -10
  39. package/dist/server/chunk-2KCF2DNK.js.map +1 -0
  40. package/dist/server/{chunk-N3PX76AP.mjs → chunk-4HIRA33Z.mjs} +247 -135
  41. package/dist/server/chunk-4HIRA33Z.mjs.map +1 -0
  42. package/dist/server/chunk-5STV4MWD.js +189 -0
  43. package/dist/server/chunk-5STV4MWD.js.map +1 -0
  44. package/dist/server/{chunk-R5B6IOFQ.js → chunk-6OSNCH4F.js} +247 -135
  45. package/dist/server/chunk-6OSNCH4F.js.map +1 -0
  46. package/dist/server/{chunk-TKMA6D6U.js → chunk-7UPVCT3K.js} +1215 -497
  47. package/dist/server/chunk-7UPVCT3K.js.map +1 -0
  48. package/dist/server/{chunk-7DS4Q3GA.mjs → chunk-AEFWG657.mjs} +3 -3
  49. package/dist/server/chunk-AEFWG657.mjs.map +1 -0
  50. package/dist/server/{chunk-USQF2XTU.mjs → chunk-BYBJA6SP.mjs} +26 -11
  51. package/dist/server/chunk-BYBJA6SP.mjs.map +1 -0
  52. package/dist/server/{chunk-ZEAJW6T3.mjs → chunk-C6FIJC7T.mjs} +4 -3
  53. package/dist/server/chunk-C6FIJC7T.mjs.map +1 -0
  54. package/dist/server/{chunk-TO7FD6TQ.js → chunk-I2D7KOEA.js} +4 -4
  55. package/dist/server/{chunk-TO7FD6TQ.js.map → chunk-I2D7KOEA.js.map} +1 -1
  56. package/dist/server/chunk-KFLZGNPO.mjs +189 -0
  57. package/dist/server/chunk-KFLZGNPO.mjs.map +1 -0
  58. package/dist/server/chunk-L5EA4FXU.mjs +134 -0
  59. package/dist/server/chunk-L5EA4FXU.mjs.map +1 -0
  60. package/dist/server/{chunk-TNRADRPH.mjs → chunk-LNOUXALA.mjs} +1137 -419
  61. package/dist/server/chunk-LNOUXALA.mjs.map +1 -0
  62. package/dist/server/{chunk-SPXMMX3C.mjs → chunk-OSF34JTQ.mjs} +4 -4
  63. package/dist/server/{chunk-SWPHIUVE.js → chunk-P3NNN73G.js} +5 -4
  64. package/dist/server/chunk-P3NNN73G.js.map +1 -0
  65. package/dist/server/{chunk-I6K5REFT.mjs → chunk-P4K63SBZ.mjs} +24 -4
  66. package/dist/server/chunk-P4K63SBZ.mjs.map +1 -0
  67. package/dist/server/{chunk-HOY77YBF.js → chunk-RVDS7VSP.js} +5 -5
  68. package/dist/server/chunk-RVDS7VSP.js.map +1 -0
  69. package/dist/server/{chunk-NW5KHH4A.js → chunk-TT5JWA4X.js} +9 -9
  70. package/dist/server/{chunk-NW5KHH4A.js.map → chunk-TT5JWA4X.js.map} +1 -1
  71. package/dist/server/chunk-VSFQRHYZ.js +134 -0
  72. package/dist/server/chunk-VSFQRHYZ.js.map +1 -0
  73. package/dist/server/{chunk-EGTDJ4PL.js → chunk-YYO3RIFO.js} +26 -11
  74. package/dist/server/chunk-YYO3RIFO.js.map +1 -0
  75. package/dist/server/{chunk-OP2GHK27.mjs → chunk-Z5ZA6Q4D.mjs} +2 -2
  76. package/dist/server/{components-D1Z2mSDr.d.ts → components-CU46ZkAv.d.mts} +20 -75
  77. package/dist/server/{components-CY8jDQjv.d.mts → components-DvozDwRN.d.ts} +20 -75
  78. package/dist/server/components.d.mts +11 -8
  79. package/dist/server/components.d.ts +11 -8
  80. package/dist/server/components.js +5 -4
  81. package/dist/server/components.js.map +1 -1
  82. package/dist/server/components.mjs +4 -3
  83. package/dist/server/config-validation.d.mts +3 -3
  84. package/dist/server/config-validation.d.ts +3 -3
  85. package/dist/server/config-validation.js +9 -5
  86. package/dist/server/config-validation.js.map +1 -1
  87. package/dist/server/config-validation.mjs +8 -4
  88. package/dist/server/config.d.mts +243 -5
  89. package/dist/server/config.d.ts +243 -5
  90. package/dist/server/config.js +72 -5
  91. package/dist/server/config.js.map +1 -1
  92. package/dist/server/config.mjs +72 -5
  93. package/dist/server/config.mjs.map +1 -1
  94. package/dist/server/core-DsNWrl3o.d.mts +44 -0
  95. package/dist/server/core-DsNWrl3o.d.ts +44 -0
  96. package/dist/server/data.d.mts +4 -3
  97. package/dist/server/data.d.ts +4 -3
  98. package/dist/server/data.js +3 -3
  99. package/dist/server/data.mjs +2 -2
  100. package/dist/server/{index-DCIz9Ptv.d.ts → index-CJfMXZQr.d.ts} +2 -1
  101. package/dist/server/{index-DFQwtj3J.d.mts → index-Q7RLMAQ6.d.mts} +2 -1
  102. package/dist/server/index.d.mts +63 -6
  103. package/dist/server/index.d.ts +63 -6
  104. package/dist/server/index.js +91 -2
  105. package/dist/server/index.js.map +1 -1
  106. package/dist/server/index.mjs +90 -1
  107. package/dist/server/index.mjs.map +1 -1
  108. package/dist/server/link-DjxLyC82.d.mts +23 -0
  109. package/dist/server/link-DjxLyC82.d.ts +23 -0
  110. package/dist/server/{loadContent-CWuE8FCx.d.mts → loadContent-DgpSKWqY.d.mts} +4 -4
  111. package/dist/server/{loadContent-DynBuR5f.d.ts → loadContent-GPvUI1bN.d.ts} +4 -4
  112. package/dist/server/{loadPage-B8RmlYgV.d.mts → loadPage-DGnIK7s4.d.mts} +17 -47
  113. package/dist/server/loadPage-DNQTTRHL.mjs +11 -0
  114. package/dist/server/{loadPage-BTkKpizX.d.ts → loadPage-DW9WB-u9.d.ts} +17 -47
  115. package/dist/server/loadPage-IDGVDFBB.js +11 -0
  116. package/dist/server/{loadPage-DUHBXDEW.js.map → loadPage-IDGVDFBB.js.map} +1 -1
  117. package/dist/server/metadata.d.mts +6 -4
  118. package/dist/server/metadata.d.ts +6 -4
  119. package/dist/server/navigation.d.mts +199 -29
  120. package/dist/server/navigation.d.ts +199 -29
  121. package/dist/server/navigation.js +27 -43
  122. package/dist/server/navigation.js.map +1 -1
  123. package/dist/server/navigation.mjs +20 -36
  124. package/dist/server/navigation.mjs.map +1 -1
  125. package/dist/server/rendering/server.d.mts +8 -6
  126. package/dist/server/rendering/server.d.ts +8 -6
  127. package/dist/server/rendering/server.js +7 -6
  128. package/dist/server/rendering/server.js.map +1 -1
  129. package/dist/server/rendering/server.mjs +6 -5
  130. package/dist/server/rendering.d.mts +14 -10
  131. package/dist/server/rendering.d.ts +14 -10
  132. package/dist/server/rendering.js +9 -8
  133. package/dist/server/rendering.js.map +1 -1
  134. package/dist/server/rendering.mjs +8 -7
  135. package/dist/server/richTextSchema-DURiozvD.d.mts +62 -0
  136. package/dist/server/richTextSchema-DURiozvD.d.ts +62 -0
  137. package/dist/server/routing.d.mts +178 -11
  138. package/dist/server/routing.d.ts +178 -11
  139. package/dist/server/routing.js +95 -2
  140. package/dist/server/routing.js.map +1 -1
  141. package/dist/server/routing.mjs +94 -1
  142. package/dist/server/routing.mjs.map +1 -1
  143. package/dist/server/{schema-Bpy9N5ZI.d.ts → schema-Z6-afHJG.d.mts} +1 -1
  144. package/dist/server/{schema-Bpy9N5ZI.d.mts → schema-Z6-afHJG.d.ts} +1 -1
  145. package/dist/server/server.d.mts +9 -7
  146. package/dist/server/server.d.ts +9 -7
  147. package/dist/server/server.js +6 -6
  148. package/dist/server/server.mjs +5 -5
  149. package/dist/server/theme-bridge.js +8 -8
  150. package/dist/server/theme-bridge.mjs +2 -2
  151. package/dist/server/{types-oCM-fw4O.d.ts → types-0f4PIlgx.d.mts} +55 -2
  152. package/dist/server/{types-txWsSxN7.d.mts → types-BjgZt8xJ.d.mts} +63 -2
  153. package/dist/server/{types-BiRZnxDx.d.ts → types-C28kMfa1.d.ts} +256 -82
  154. package/dist/server/{types-CL916r6x.d.ts → types-DLBhEPSt.d.ts} +63 -2
  155. package/dist/server/{types-CdrJqlKx.d.mts → types-DuzJZKJI.d.mts} +256 -82
  156. package/dist/server/{types-DkKEctWn.d.mts → types-kOQyCFXO.d.ts} +55 -2
  157. package/dist/server/{validation-DzvDwwRo.d.mts → validation-BGuRo8P1.d.mts} +18 -5
  158. package/dist/server/{validation-CoU8uAiu.d.ts → validation-DU2YE7u5.d.ts} +18 -5
  159. package/package.json +5 -3
  160. package/dist/server/chunk-6JBKKV3G.js.map +0 -1
  161. package/dist/server/chunk-7BOIO2S7.mjs +0 -833
  162. package/dist/server/chunk-7BOIO2S7.mjs.map +0 -1
  163. package/dist/server/chunk-7DS4Q3GA.mjs.map +0 -1
  164. package/dist/server/chunk-BLKVTULP.js +0 -833
  165. package/dist/server/chunk-BLKVTULP.js.map +0 -1
  166. package/dist/server/chunk-EGTDJ4PL.js.map +0 -1
  167. package/dist/server/chunk-HOY77YBF.js.map +0 -1
  168. package/dist/server/chunk-I6K5REFT.mjs.map +0 -1
  169. package/dist/server/chunk-N3PX76AP.mjs.map +0 -1
  170. package/dist/server/chunk-R5B6IOFQ.js.map +0 -1
  171. package/dist/server/chunk-SWPHIUVE.js.map +0 -1
  172. package/dist/server/chunk-TKMA6D6U.js.map +0 -1
  173. package/dist/server/chunk-TNRADRPH.mjs.map +0 -1
  174. package/dist/server/chunk-USQF2XTU.mjs.map +0 -1
  175. package/dist/server/chunk-ZEAJW6T3.mjs.map +0 -1
  176. package/dist/server/loadPage-DUHBXDEW.js +0 -11
  177. package/dist/server/loadPage-LYVKY3WZ.mjs +0 -11
  178. /package/dist/server/{chunk-SPXMMX3C.mjs.map → chunk-OSF34JTQ.mjs.map} +0 -0
  179. /package/dist/server/{chunk-OP2GHK27.mjs.map → chunk-Z5ZA6Q4D.mjs.map} +0 -0
  180. /package/dist/server/{loadPage-LYVKY3WZ.mjs.map → loadPage-DNQTTRHL.mjs.map} +0 -0
@@ -908,7 +908,7 @@ function parseToken(source) {
908
908
  if (source.includes("/")) {
909
909
  const [token, opacity] = source.split("/");
910
910
  const alpha = Number(opacity) / 100;
911
- if (!Number.isNaN(alpha)) {
911
+ if (!Number.isNaN(alpha) && token) {
912
912
  return { token, alpha };
913
913
  }
914
914
  return { token: source };
@@ -948,7 +948,8 @@ function headingGroup(opts) {
948
948
  containerClass = "text-center",
949
949
  className,
950
950
  eyebrowClass = "heading-eyebrow text-sm font-semibold tracking-wide",
951
- titleClass = "heading-title text-3xl font-semibold sm:text-4xl",
951
+ // h2 now gets size/weight from theme typography CSS
952
+ titleClass = "heading-title",
952
953
  eyebrowStyle = textColorStyle("neutral-500"),
953
954
  titleStyle = textColorStyle("neutral-900")
954
955
  } = opts;
@@ -1529,6 +1530,8 @@ var bodyCopyFragment = defineFragment({
1529
1530
  text(
1530
1531
  {
1531
1532
  as: "h2",
1533
+ // h2 now gets size/weight from theme typography CSS
1534
+ // Only dynamic class here is for text alignment
1532
1535
  className: {
1533
1536
  $bind: {
1534
1537
  from: "content.alignment",
@@ -1536,11 +1539,11 @@ var bodyCopyFragment = defineFragment({
1536
1539
  {
1537
1540
  id: "ui.headingClassFromAlignment",
1538
1541
  options: {
1539
- base: "text-3xl font-semibold sm:text-4xl"
1542
+ base: ""
1540
1543
  }
1541
1544
  }
1542
1545
  ],
1543
- fallback: "text-3xl font-semibold sm:text-4xl"
1546
+ fallback: ""
1544
1547
  }
1545
1548
  },
1546
1549
  style: textColorStyle("neutral-900")
@@ -1613,7 +1616,9 @@ var heroCopyFragment = defineFragment({
1613
1616
  text(
1614
1617
  {
1615
1618
  as: "h1",
1616
- className: "hero-headline text-4xl font-semibold sm:text-5xl md:text-6xl",
1619
+ // heading-display: uses fluid typography from theme (--fs-h1-display-fluid)
1620
+ // Removes hardcoded text-4xl/5xl/6xl - size now controlled by theme
1621
+ className: "hero-headline heading-display",
1617
1622
  style: textColorStyle("neutral-900")
1618
1623
  },
1619
1624
  bind("content.headline")
@@ -1792,7 +1797,8 @@ var testimonialsHeadingFragment = defineFragment({
1792
1797
  { gap: "md", className: "mx-auto max-w-2xl text-center" },
1793
1798
  [
1794
1799
  text(
1795
- { as: "h2", className: "text-3xl font-semibold sm:text-4xl", style: textColorStyle("neutral-900") },
1800
+ // h2 now gets size/weight from theme typography CSS
1801
+ { as: "h2", style: textColorStyle("neutral-900") },
1796
1802
  when("content.heading"),
1797
1803
  bind("content.heading")
1798
1804
  ),
@@ -2242,7 +2248,7 @@ var blogFeaturedPostFragment = defineFragment({
2242
2248
  text(
2243
2249
  {
2244
2250
  as: "h2",
2245
- className: "text-2xl font-semibold md:text-3xl",
2251
+ // h2 now gets size/weight from theme typography CSS
2246
2252
  style: textColorStyle("neutral-900")
2247
2253
  },
2248
2254
  bind("title", { fallback: "Latest post" })
@@ -2639,7 +2645,8 @@ var faqHeadingFragment = defineFragment({
2639
2645
  text(
2640
2646
  {
2641
2647
  as: "h2",
2642
- className: "faq-title text-3xl font-semibold sm:text-4xl",
2648
+ // h2 now gets size/weight from theme typography CSS
2649
+ className: "faq-title",
2643
2650
  style: textColorStyle("neutral-900")
2644
2651
  },
2645
2652
  when("content.title"),
@@ -4582,7 +4589,11 @@ var simpleFooterLayout = stack(
4582
4589
  }
4583
4590
  },
4584
4591
  [
4585
- navRow({ align: "center", className: "flex flex-wrap justify-center gap-x-6 gap-y-3" }),
4592
+ navRow({
4593
+ align: "center",
4594
+ className: "flex flex-wrap justify-center gap-x-6 gap-y-3",
4595
+ linkClassName: "footer-nav-link inline-flex items-center px-4 py-2 text-sm font-medium transition-theme-standard"
4596
+ }),
4586
4597
  ...bottomTextLayout()
4587
4598
  ],
4588
4599
  when("$root.theme.footer.variant", { equals: "simple" })
@@ -4610,7 +4621,11 @@ var columnsFooterLayout = stack(
4610
4621
  { className: "flex w-full flex-wrap items-center justify-between gap-4" },
4611
4622
  [
4612
4623
  text({ as: "span", className: "text-sm font-semibold", style: textColorStyle("text") }, bind("site.title", { fallback: "Your Site" })),
4613
- navRow({ className: "flex flex-wrap justify-end gap-x-6 gap-y-3", align: "end" })
4624
+ navRow({
4625
+ className: "flex flex-wrap justify-end gap-x-6 gap-y-3",
4626
+ align: "end",
4627
+ linkClassName: "footer-nav-link inline-flex items-center px-4 py-2 text-sm font-medium transition-theme-standard"
4628
+ })
4614
4629
  ]
4615
4630
  ),
4616
4631
  ...bottomTextLayout()
@@ -5901,7 +5916,7 @@ function splitPath(path) {
5901
5916
  for (const raw of parts) {
5902
5917
  if (!raw) continue;
5903
5918
  const baseMatch = raw.match(/^([^\[]+)/);
5904
- if (baseMatch) {
5919
+ if (baseMatch && baseMatch[1]) {
5905
5920
  segments.push(baseMatch[1]);
5906
5921
  }
5907
5922
  const bracketMatches = raw.matchAll(BRACKET_ACCESS_REGEX2);
@@ -6683,6 +6698,10 @@ var resolveLinkTransform = {
6683
6698
  const href = link2.href.trim();
6684
6699
  return href.length > 0 ? href : null;
6685
6700
  }
6701
+ if (!kind && typeof link2.href === "string") {
6702
+ const href = link2.href.trim();
6703
+ return href.length > 0 ? href : null;
6704
+ }
6686
6705
  return null;
6687
6706
  }
6688
6707
  };
@@ -7179,7 +7198,14 @@ function getDirectImageUrl(supabaseUrl, storagePath, storageBucket = "media", op
7179
7198
 
7180
7199
  // ../blocks/src/system/runtime/nodes/media.tsx
7181
7200
  var import_jsx_runtime9 = require("react/jsx-runtime");
7201
+ var _contextSupabaseUrl;
7202
+ function setContextSupabaseUrl(url) {
7203
+ _contextSupabaseUrl = url?.replace(/\/$/, "");
7204
+ }
7182
7205
  function getSupabaseUrl() {
7206
+ if (_contextSupabaseUrl) {
7207
+ return _contextSupabaseUrl;
7208
+ }
7183
7209
  const url = process.env.NEXT_PUBLIC_SUPABASE_URL;
7184
7210
  if (!url) {
7185
7211
  throw new Error(
@@ -7499,7 +7525,7 @@ var COLUMN_CLASSES = {
7499
7525
  "4": "sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4"
7500
7526
  };
7501
7527
  function formatDateForUrl(isoTimestamp) {
7502
- return isoTimestamp.split("T")[0];
7528
+ return isoTimestamp.split("T")[0] ?? "";
7503
7529
  }
7504
7530
  function buildEventUrl(basePath, slug, startsAt) {
7505
7531
  const date = formatDateForUrl(startsAt);
@@ -7684,7 +7710,7 @@ function getContainerClass(layout, columns) {
7684
7710
  return `grid gap-6 ${COLUMN_CLASSES2[columns] || COLUMN_CLASSES2["3"]}`;
7685
7711
  }
7686
7712
  function formatDateForUrl2(isoTimestamp) {
7687
- return isoTimestamp.split("T")[0];
7713
+ return isoTimestamp.split("T")[0] ?? "";
7688
7714
  }
7689
7715
  function buildEventUrl2(basePath, slug, startsAt) {
7690
7716
  const date = formatDateForUrl2(startsAt);
@@ -7903,7 +7929,7 @@ function extractSegmentsFromPart(part) {
7903
7929
  if (!part) return [];
7904
7930
  const segments = [];
7905
7931
  const baseMatch = part.match(/^([^\[]+)/);
7906
- if (baseMatch) {
7932
+ if (baseMatch && baseMatch[1]) {
7907
7933
  segments.push(baseMatch[1]);
7908
7934
  }
7909
7935
  const bracketMatches = Array.from(part.matchAll(BRACKET_ACCESS_REGEX));
@@ -8869,8 +8895,8 @@ function getLabWhitePoint() {
8869
8895
  var lab2rgb = (...args) => {
8870
8896
  args = unpack_default(args, "lab");
8871
8897
  const [L, a, b] = args;
8872
- const [x, y, z19] = lab2xyz(L, a, b);
8873
- const [r2, g, b_] = xyz2rgb(x, y, z19);
8898
+ const [x, y, z20] = lab2xyz(L, a, b);
8899
+ const [r2, g, b_] = xyz2rgb(x, y, z20);
8874
8900
  return [r2, g, b_, args.length > 3 ? args[3] : 1];
8875
8901
  };
8876
8902
  var lab2xyz = (L, a, b) => {
@@ -8885,15 +8911,15 @@ var lab2xyz = (L, a, b) => {
8885
8911
  const zr = fz3 > kE ? fz3 : (116 * fz - 16) / kK;
8886
8912
  const x = xr * Xn;
8887
8913
  const y = yr * Yn;
8888
- const z19 = zr * Zn;
8889
- return [x, y, z19];
8914
+ const z20 = zr * Zn;
8915
+ return [x, y, z20];
8890
8916
  };
8891
8917
  var compand = (linear) => {
8892
8918
  const sign = Math.sign(linear);
8893
8919
  linear = Math.abs(linear);
8894
8920
  return (linear <= 31308e-7 ? linear * 12.92 : 1.055 * Math.pow(linear, 1 / 2.4) - 0.055) * sign;
8895
8921
  };
8896
- var xyz2rgb = (x, y, z19) => {
8922
+ var xyz2rgb = (x, y, z20) => {
8897
8923
  const { MtxAdaptMa, MtxAdaptMaI, MtxXYZ2RGB, RefWhiteRGB, Xn, Yn, Zn } = lab_constants_default;
8898
8924
  const As = Xn * MtxAdaptMa.m00 + Yn * MtxAdaptMa.m10 + Zn * MtxAdaptMa.m20;
8899
8925
  const Bs = Xn * MtxAdaptMa.m01 + Yn * MtxAdaptMa.m11 + Zn * MtxAdaptMa.m21;
@@ -8901,9 +8927,9 @@ var xyz2rgb = (x, y, z19) => {
8901
8927
  const Ad = RefWhiteRGB.X * MtxAdaptMa.m00 + RefWhiteRGB.Y * MtxAdaptMa.m10 + RefWhiteRGB.Z * MtxAdaptMa.m20;
8902
8928
  const Bd = RefWhiteRGB.X * MtxAdaptMa.m01 + RefWhiteRGB.Y * MtxAdaptMa.m11 + RefWhiteRGB.Z * MtxAdaptMa.m21;
8903
8929
  const Cd = RefWhiteRGB.X * MtxAdaptMa.m02 + RefWhiteRGB.Y * MtxAdaptMa.m12 + RefWhiteRGB.Z * MtxAdaptMa.m22;
8904
- const X1 = (x * MtxAdaptMa.m00 + y * MtxAdaptMa.m10 + z19 * MtxAdaptMa.m20) * (Ad / As);
8905
- const Y1 = (x * MtxAdaptMa.m01 + y * MtxAdaptMa.m11 + z19 * MtxAdaptMa.m21) * (Bd / Bs);
8906
- const Z1 = (x * MtxAdaptMa.m02 + y * MtxAdaptMa.m12 + z19 * MtxAdaptMa.m22) * (Cd / Cs);
8930
+ const X1 = (x * MtxAdaptMa.m00 + y * MtxAdaptMa.m10 + z20 * MtxAdaptMa.m20) * (Ad / As);
8931
+ const Y1 = (x * MtxAdaptMa.m01 + y * MtxAdaptMa.m11 + z20 * MtxAdaptMa.m21) * (Bd / Bs);
8932
+ const Z1 = (x * MtxAdaptMa.m02 + y * MtxAdaptMa.m12 + z20 * MtxAdaptMa.m22) * (Cd / Cs);
8907
8933
  const X2 = X1 * MtxAdaptMaI.m00 + Y1 * MtxAdaptMaI.m10 + Z1 * MtxAdaptMaI.m20;
8908
8934
  const Y2 = X1 * MtxAdaptMaI.m01 + Y1 * MtxAdaptMaI.m11 + Z1 * MtxAdaptMaI.m21;
8909
8935
  const Z2 = X1 * MtxAdaptMaI.m02 + Y1 * MtxAdaptMaI.m12 + Z1 * MtxAdaptMaI.m22;
@@ -8923,15 +8949,15 @@ var lab2rgb_default = lab2rgb;
8923
8949
  // ../../node_modules/.pnpm/chroma-js@3.1.2/node_modules/chroma-js/src/io/lab/rgb2lab.js
8924
8950
  var rgb2lab = (...args) => {
8925
8951
  const [r2, g, b, ...rest] = unpack_default(args, "rgb");
8926
- const [x, y, z19] = rgb2xyz(r2, g, b);
8927
- const [L, a, b_] = xyz2lab(x, y, z19);
8952
+ const [x, y, z20] = rgb2xyz(r2, g, b);
8953
+ const [L, a, b_] = xyz2lab(x, y, z20);
8928
8954
  return [L, a, b_, ...rest.length > 0 && rest[0] < 1 ? [rest[0]] : []];
8929
8955
  };
8930
- function xyz2lab(x, y, z19) {
8956
+ function xyz2lab(x, y, z20) {
8931
8957
  const { Xn, Yn, Zn, kE, kK } = lab_constants_default;
8932
8958
  const xr = x / Xn;
8933
8959
  const yr = y / Yn;
8934
- const zr = z19 / Zn;
8960
+ const zr = z20 / Zn;
8935
8961
  const fx = xr > kE ? Math.pow(xr, 1 / 3) : (kK * xr + 16) / 116;
8936
8962
  const fy = yr > kE ? Math.pow(yr, 1 / 3) : (kK * yr + 16) / 116;
8937
8963
  const fz = zr > kE ? Math.pow(zr, 1 / 3) : (kK * zr + 16) / 116;
@@ -8950,20 +8976,20 @@ var rgb2xyz = (r2, g, b) => {
8950
8976
  const { MtxRGB2XYZ, MtxAdaptMa, MtxAdaptMaI, Xn, Yn, Zn, As, Bs, Cs } = lab_constants_default;
8951
8977
  let x = r2 * MtxRGB2XYZ.m00 + g * MtxRGB2XYZ.m10 + b * MtxRGB2XYZ.m20;
8952
8978
  let y = r2 * MtxRGB2XYZ.m01 + g * MtxRGB2XYZ.m11 + b * MtxRGB2XYZ.m21;
8953
- let z19 = r2 * MtxRGB2XYZ.m02 + g * MtxRGB2XYZ.m12 + b * MtxRGB2XYZ.m22;
8979
+ let z20 = r2 * MtxRGB2XYZ.m02 + g * MtxRGB2XYZ.m12 + b * MtxRGB2XYZ.m22;
8954
8980
  const Ad = Xn * MtxAdaptMa.m00 + Yn * MtxAdaptMa.m10 + Zn * MtxAdaptMa.m20;
8955
8981
  const Bd = Xn * MtxAdaptMa.m01 + Yn * MtxAdaptMa.m11 + Zn * MtxAdaptMa.m21;
8956
8982
  const Cd = Xn * MtxAdaptMa.m02 + Yn * MtxAdaptMa.m12 + Zn * MtxAdaptMa.m22;
8957
- let X = x * MtxAdaptMa.m00 + y * MtxAdaptMa.m10 + z19 * MtxAdaptMa.m20;
8958
- let Y = x * MtxAdaptMa.m01 + y * MtxAdaptMa.m11 + z19 * MtxAdaptMa.m21;
8959
- let Z = x * MtxAdaptMa.m02 + y * MtxAdaptMa.m12 + z19 * MtxAdaptMa.m22;
8983
+ let X = x * MtxAdaptMa.m00 + y * MtxAdaptMa.m10 + z20 * MtxAdaptMa.m20;
8984
+ let Y = x * MtxAdaptMa.m01 + y * MtxAdaptMa.m11 + z20 * MtxAdaptMa.m21;
8985
+ let Z = x * MtxAdaptMa.m02 + y * MtxAdaptMa.m12 + z20 * MtxAdaptMa.m22;
8960
8986
  X *= Ad / As;
8961
8987
  Y *= Bd / Bs;
8962
8988
  Z *= Cd / Cs;
8963
8989
  x = X * MtxAdaptMaI.m00 + Y * MtxAdaptMaI.m10 + Z * MtxAdaptMaI.m20;
8964
8990
  y = X * MtxAdaptMaI.m01 + Y * MtxAdaptMaI.m11 + Z * MtxAdaptMaI.m21;
8965
- z19 = X * MtxAdaptMaI.m02 + Y * MtxAdaptMaI.m12 + Z * MtxAdaptMaI.m22;
8966
- return [x, y, z19];
8991
+ z20 = X * MtxAdaptMaI.m02 + Y * MtxAdaptMaI.m12 + Z * MtxAdaptMaI.m22;
8992
+ return [x, y, z20];
8967
8993
  };
8968
8994
  var rgb2lab_default = rgb2lab;
8969
8995
 
@@ -11292,7 +11318,7 @@ function generateShades(hexColor, name) {
11292
11318
  900: 0.1,
11293
11319
  950: 0.05
11294
11320
  };
11295
- const lightness = lightnessMap[shadeNumber];
11321
+ const lightness = lightnessMap[shadeNumber] ?? 0.5;
11296
11322
  const shadeColor = base.luminance(lightness).hex();
11297
11323
  return {
11298
11324
  name: shadeName,
@@ -11363,7 +11389,7 @@ function expandPalette(palette) {
11363
11389
  if (base.text) expanded.body = base.text;
11364
11390
  const isDark = base.background ? isBackgroundDark(base.background) : false;
11365
11391
  const isDarkMode = palette.meta?.mode === "dark" || isDark;
11366
- expanded.mutedText = isDarkMode ? expanded["neutral-600"] : expanded["neutral-500"];
11392
+ expanded.mutedText = isDarkMode ? expanded["neutral-600"] ?? "#666" : expanded["neutral-500"] ?? "#888";
11367
11393
  return expanded;
11368
11394
  }
11369
11395
 
@@ -11431,6 +11457,83 @@ function generateShadowCssVars(theme) {
11431
11457
  };
11432
11458
  }
11433
11459
 
11460
+ // ../blocks/src/theme/tokens/resolver.ts
11461
+ var TokenResolver = class {
11462
+ constructor(theme) {
11463
+ this.theme = theme;
11464
+ }
11465
+ /**
11466
+ * Resolve a color token to a CSS variable reference wrapped in rgb()
11467
+ *
11468
+ * @param token - Token name (e.g., 'primary-500', 'white', 'text-900')
11469
+ * @returns CSS rgb() function with var reference (e.g., 'rgb(var(--tb-primary-500))')
11470
+ *
11471
+ * Note: CSS variables are stored as RGB channels (e.g., "37 99 235") following Tailwind convention,
11472
+ * so we must wrap them with rgb() to create a valid color value.
11473
+ *
11474
+ * @example
11475
+ * resolver.getColor('primary-500') // => 'rgb(var(--tb-primary-500))'
11476
+ * resolver.getColor('white') // => 'rgb(var(--tb-white))'
11477
+ */
11478
+ getColor(token) {
11479
+ if (!this.tokenExists(token)) {
11480
+ console.warn(
11481
+ `[TokenResolver] Color token "${token}" not found in theme palette. Button may render incorrectly.`
11482
+ );
11483
+ }
11484
+ return `rgb(var(--tb-${token}))`;
11485
+ }
11486
+ /**
11487
+ * Adjust a color token's shade by a given amount
11488
+ *
11489
+ * @param token - Base token (e.g., 'primary-500')
11490
+ * @param amount - Shade adjustment (+100 = darker, -100 = lighter)
11491
+ * @returns Adjusted token name (e.g., 'primary-600')
11492
+ *
11493
+ * @example
11494
+ * resolver.adjustShade('primary-500', 100) // => 'primary-600' (darker)
11495
+ * resolver.adjustShade('primary-500', -100) // => 'primary-400' (lighter)
11496
+ */
11497
+ adjustShade(token, amount) {
11498
+ const parts = token.split("-");
11499
+ if (parts.length < 2) {
11500
+ const newShade2 = Math.max(100, Math.min(900, 500 + amount));
11501
+ return `${token}-${newShade2}`;
11502
+ }
11503
+ const base = parts.slice(0, -1).join("-");
11504
+ const shade = parseInt(parts[parts.length - 1] ?? "", 10);
11505
+ if (isNaN(shade)) {
11506
+ console.warn(
11507
+ `[TokenResolver] Cannot adjust shade for non-shade token "${token}". Returning original token.`
11508
+ );
11509
+ return token;
11510
+ }
11511
+ const newShade = Math.max(100, Math.min(900, shade + amount));
11512
+ return `${base}-${newShade}`;
11513
+ }
11514
+ /**
11515
+ * Check if a token exists in the theme palette
11516
+ *
11517
+ * @param token - Token name to check
11518
+ * @returns True if token exists in theme
11519
+ */
11520
+ tokenExists(token) {
11521
+ const commonTokens = ["white", "black", "transparent"];
11522
+ if (commonTokens.includes(token)) {
11523
+ return true;
11524
+ }
11525
+ const parts = token.split("-");
11526
+ if (parts.length >= 2) {
11527
+ const lastPart = parts[parts.length - 1] ?? "";
11528
+ const shade = parseInt(lastPart, 10);
11529
+ if (!isNaN(shade) && shade >= 100 && shade <= 900 && shade % 100 === 0) {
11530
+ return true;
11531
+ }
11532
+ }
11533
+ return true;
11534
+ }
11535
+ };
11536
+
11434
11537
  // ../blocks/src/theme/buttons/effects/presets/background.ts
11435
11538
  var darkenBackgroundEffect = {
11436
11539
  id: "darken-background",
@@ -11438,6 +11541,7 @@ var darkenBackgroundEffect = {
11438
11541
  description: "Darkens the background color on hover",
11439
11542
  category: "background",
11440
11543
  pseudoElement: "none",
11544
+ applicableTo: ["button"],
11441
11545
  customizableOption: {
11442
11546
  name: "amount",
11443
11547
  type: "number",
@@ -11469,6 +11573,7 @@ var lightenBackgroundEffect = {
11469
11573
  description: "Lightens the background color on hover",
11470
11574
  category: "background",
11471
11575
  pseudoElement: "none",
11576
+ applicableTo: ["button"],
11472
11577
  customizableOption: {
11473
11578
  name: "amount",
11474
11579
  type: "number",
@@ -11500,6 +11605,7 @@ var fadeBackgroundEffect = {
11500
11605
  description: "Reduces background opacity on hover",
11501
11606
  category: "background",
11502
11607
  pseudoElement: "none",
11608
+ applicableTo: ["button", "nav-link"],
11503
11609
  customizableOption: {
11504
11610
  name: "opacity",
11505
11611
  type: "percentage",
@@ -11522,6 +11628,7 @@ var opacityReduceEffect = {
11522
11628
  description: "Reduces button opacity on hover by a percentage",
11523
11629
  category: "background",
11524
11630
  pseudoElement: "none",
11631
+ applicableTo: ["button", "nav-link"],
11525
11632
  customizableOption: {
11526
11633
  name: "reduction",
11527
11634
  type: "percentage",
@@ -11545,6 +11652,7 @@ var animatedGradientEffect = {
11545
11652
  description: "Animates gradient position on hover",
11546
11653
  category: "background",
11547
11654
  pseudoElement: "none",
11655
+ applicableTo: ["button"],
11548
11656
  customizableOption: {
11549
11657
  name: "direction",
11550
11658
  type: "select",
@@ -11584,6 +11692,7 @@ var backgroundOnHoverEffect = {
11584
11692
  description: "Adds background color on hover",
11585
11693
  category: "background",
11586
11694
  pseudoElement: "none",
11695
+ applicableTo: ["button", "nav-link"],
11587
11696
  customizableOption: {
11588
11697
  name: "colorToken",
11589
11698
  type: "select",
@@ -11609,6 +11718,7 @@ var backgroundOnHoverAlphaEffect = {
11609
11718
  description: "Adds semi-transparent background on hover",
11610
11719
  category: "background",
11611
11720
  pseudoElement: "none",
11721
+ applicableTo: ["button", "nav-link"],
11612
11722
  customizableOption: {
11613
11723
  name: "opacity",
11614
11724
  type: "percentage",
@@ -11630,6 +11740,33 @@ var backgroundOnHoverAlphaEffect = {
11630
11740
  }
11631
11741
  };
11632
11742
 
11743
+ // ../blocks/src/theme/buttons/effects/cssUtils.ts
11744
+ var STATE_SELECTORS = {
11745
+ hover: ':hover, [data-force-hover="true"]',
11746
+ active: ":active",
11747
+ focus: ":focus-visible",
11748
+ base: ""
11749
+ };
11750
+ function getStateSelector(themeId, variantId, state) {
11751
+ const stateSelector = STATE_SELECTORS[state];
11752
+ if (state === "base") {
11753
+ return `:where([data-theme-scope="${themeId}"]) .${variantId}`;
11754
+ }
11755
+ if (state === "hover") {
11756
+ return `:where([data-theme-scope="${themeId}"]) .${variantId}:hover,
11757
+ :where([data-theme-scope="${themeId}"]) .${variantId}[data-force-hover="true"]`;
11758
+ }
11759
+ return `:where([data-theme-scope="${themeId}"]) .${variantId}${stateSelector}`;
11760
+ }
11761
+ function generateStateCSS(themeId, variantId, state, cssProperties) {
11762
+ const selector = getStateSelector(themeId, variantId, state);
11763
+ return `
11764
+ ${selector} {
11765
+ ${cssProperties}
11766
+ }
11767
+ `;
11768
+ }
11769
+
11633
11770
  // ../blocks/src/theme/buttons/effects/presets/shadow.ts
11634
11771
  var borderGlowEffect = {
11635
11772
  id: "border-glow",
@@ -11637,6 +11774,7 @@ var borderGlowEffect = {
11637
11774
  description: "Adds a glowing shadow on hover",
11638
11775
  category: "shadow",
11639
11776
  pseudoElement: "none",
11777
+ applicableTo: ["button", "nav-link"],
11640
11778
  customizableOption: {
11641
11779
  name: "glowColorToken",
11642
11780
  type: "colorToken",
@@ -11647,11 +11785,7 @@ var borderGlowEffect = {
11647
11785
  const { themeId, variantId, options, tokens } = ctx;
11648
11786
  const glowToken = options.glowColorToken || "primary-400";
11649
11787
  const glowColor = tokens.getColor(glowToken);
11650
- return `
11651
- :where([data-theme-scope="${themeId}"]) .${variantId}:hover {
11652
- box-shadow: 0 0 15px ${glowColor};
11653
- }
11654
- `;
11788
+ return generateStateCSS(themeId, variantId, "hover", `box-shadow: 0 0 15px ${glowColor};`);
11655
11789
  }
11656
11790
  };
11657
11791
  var dropShadowEffect = {
@@ -11660,6 +11794,7 @@ var dropShadowEffect = {
11660
11794
  description: "Adds an elevated shadow on hover",
11661
11795
  category: "shadow",
11662
11796
  pseudoElement: "none",
11797
+ applicableTo: ["button"],
11663
11798
  customizableOption: {
11664
11799
  name: "intensity",
11665
11800
  type: "select",
@@ -11675,11 +11810,7 @@ var dropShadowEffect = {
11675
11810
  medium: "0 10px 15px rgba(0, 0, 0, 0.15)",
11676
11811
  strong: "0 20px 25px rgba(0, 0, 0, 0.2)"
11677
11812
  };
11678
- return `
11679
- :where([data-theme-scope="${themeId}"]) .${variantId}:hover {
11680
- box-shadow: ${shadows[intensity]};
11681
- }
11682
- `;
11813
+ return generateStateCSS(themeId, variantId, "hover", `box-shadow: ${shadows[intensity]};`);
11683
11814
  }
11684
11815
  };
11685
11816
  var innerShadowEffect = {
@@ -11688,6 +11819,7 @@ var innerShadowEffect = {
11688
11819
  description: "Adds an inset shadow for a pressed appearance",
11689
11820
  category: "shadow",
11690
11821
  pseudoElement: "none",
11822
+ applicableTo: ["button"],
11691
11823
  generateCSS: (ctx) => {
11692
11824
  const { themeId, variantId } = ctx;
11693
11825
  return `
@@ -11703,6 +11835,7 @@ var neumorphicShadowEffect = {
11703
11835
  description: "Dual shadows for soft UI design (raised or pressed)",
11704
11836
  category: "shadow",
11705
11837
  pseudoElement: "none",
11838
+ applicableTo: ["button", "nav-link"],
11706
11839
  customizableOption: {
11707
11840
  name: "mode",
11708
11841
  type: "select",
@@ -11745,6 +11878,7 @@ var outerGlowEffect = {
11745
11878
  description: "Creates an outer glow around the button",
11746
11879
  category: "shadow",
11747
11880
  pseudoElement: "none",
11881
+ applicableTo: ["button", "nav-link"],
11748
11882
  customizableOption: {
11749
11883
  name: "spread",
11750
11884
  type: "number",
@@ -11779,6 +11913,7 @@ var retro3DShadowEffect = {
11779
11913
  description: "3D pressed shadow with vertical movement (retro style)",
11780
11914
  category: "shadow",
11781
11915
  pseudoElement: "none",
11916
+ applicableTo: ["button"],
11782
11917
  generateCSS: (ctx) => {
11783
11918
  const { themeId, variantId } = ctx;
11784
11919
  return `
@@ -11811,6 +11946,7 @@ var scaleUpEffect = {
11811
11946
  description: "Slightly enlarges the button on hover",
11812
11947
  category: "transform",
11813
11948
  pseudoElement: "none",
11949
+ applicableTo: ["button", "nav-link"],
11814
11950
  customizableOption: {
11815
11951
  name: "scale",
11816
11952
  type: "select",
@@ -11821,11 +11957,7 @@ var scaleUpEffect = {
11821
11957
  generateCSS: (ctx) => {
11822
11958
  const { themeId, variantId, options } = ctx;
11823
11959
  const scale = options.scale || "1.05";
11824
- return `
11825
- :where([data-theme-scope="${themeId}"]) .${variantId}:hover {
11826
- transform: scale(${scale});
11827
- }
11828
- `;
11960
+ return generateStateCSS(themeId, variantId, "hover", `transform: scale(${scale});`);
11829
11961
  }
11830
11962
  };
11831
11963
  var scaleDownEffect = {
@@ -11834,6 +11966,7 @@ var scaleDownEffect = {
11834
11966
  description: "Slightly shrinks the button when clicked",
11835
11967
  category: "transform",
11836
11968
  pseudoElement: "none",
11969
+ applicableTo: ["button", "nav-link"],
11837
11970
  customizableOption: {
11838
11971
  name: "scale",
11839
11972
  type: "select",
@@ -11857,6 +11990,7 @@ var liftEffect = {
11857
11990
  description: "Lifts the button upward on hover",
11858
11991
  category: "transform",
11859
11992
  pseudoElement: "none",
11993
+ applicableTo: ["button", "nav-link"],
11860
11994
  customizableOption: {
11861
11995
  name: "amount",
11862
11996
  type: "select",
@@ -11867,11 +12001,7 @@ var liftEffect = {
11867
12001
  generateCSS: (ctx) => {
11868
12002
  const { themeId, variantId, options } = ctx;
11869
12003
  const amount = options.amount || "0.5";
11870
- return `
11871
- :where([data-theme-scope="${themeId}"]) .${variantId}:hover {
11872
- transform: translateY(-${amount}rem);
11873
- }
11874
- `;
12004
+ return generateStateCSS(themeId, variantId, "hover", `transform: translateY(-${amount}rem);`);
11875
12005
  }
11876
12006
  };
11877
12007
  var pressDownEffect = {
@@ -11880,6 +12010,7 @@ var pressDownEffect = {
11880
12010
  description: "Translates button to shadow position and removes shadow on hover",
11881
12011
  category: "transform",
11882
12012
  pseudoElement: "none",
12013
+ applicableTo: ["button"],
11883
12014
  generateCSS: (ctx) => {
11884
12015
  const { themeId, variantId, theme } = ctx;
11885
12016
  const shadowConfig = theme.shadow;
@@ -11892,12 +12023,12 @@ var pressDownEffect = {
11892
12023
  const offset = elevationOffsets[shadowConfig.elevation];
11893
12024
  const xOffset = (shadowConfig.position || "bottom") === "bottom-right" ? offset : 0;
11894
12025
  const yOffset = offset;
11895
- return `
11896
- :where([data-theme-scope="${themeId}"]) .${variantId}:hover {
11897
- transform: translate(${xOffset}px, ${yOffset}px);
11898
- box-shadow: none;
11899
- }
11900
- `;
12026
+ return generateStateCSS(
12027
+ themeId,
12028
+ variantId,
12029
+ "hover",
12030
+ `transform: translate(${xOffset}px, ${yOffset}px); box-shadow: none;`
12031
+ );
11901
12032
  }
11902
12033
  };
11903
12034
  var popEffect = {
@@ -11906,6 +12037,7 @@ var popEffect = {
11906
12037
  description: "Scales up and tilts the button on hover for a playful pop effect",
11907
12038
  category: "transform",
11908
12039
  pseudoElement: "none",
12040
+ applicableTo: ["button"],
11909
12041
  customizableOption: {
11910
12042
  name: "intensity",
11911
12043
  type: "select",
@@ -11922,11 +12054,12 @@ var popEffect = {
11922
12054
  dramatic: { scale: 1.08, rotate: 3 }
11923
12055
  };
11924
12056
  const config = intensityConfig[intensity] || intensityConfig.medium;
11925
- return `
11926
- :where([data-theme-scope="${themeId}"]) .${variantId}:hover {
11927
- transform: scale(${config.scale}) rotate(${config.rotate}deg);
11928
- }
11929
- `;
12057
+ return generateStateCSS(
12058
+ themeId,
12059
+ variantId,
12060
+ "hover",
12061
+ `transform: scale(${config.scale}) rotate(${config.rotate}deg);`
12062
+ );
11930
12063
  }
11931
12064
  };
11932
12065
 
@@ -11937,6 +12070,7 @@ var auroraGlowEffect = {
11937
12070
  description: "Blurred gradient glow that appears on hover",
11938
12071
  category: "overlay",
11939
12072
  pseudoElement: "before",
12073
+ applicableTo: ["button"],
11940
12074
  customizableOption: {
11941
12075
  name: "intensity",
11942
12076
  type: "percentage",
@@ -11949,8 +12083,8 @@ var auroraGlowEffect = {
11949
12083
  let toColor;
11950
12084
  if (buttonConfig.background.type === "gradient") {
11951
12085
  const stops = buttonConfig.background.stops;
11952
- fromColor = tokens.getColor(stops[0]);
11953
- toColor = tokens.getColor(stops[stops.length - 1]);
12086
+ fromColor = tokens.getColor(stops[0] ?? "primary-500");
12087
+ toColor = tokens.getColor(stops[stops.length - 1] ?? "primary-300");
11954
12088
  } else if (buttonConfig.background.type === "solid") {
11955
12089
  fromColor = tokens.getColor(buttonConfig.background.colorToken);
11956
12090
  const lighterToken = tokens.adjustShade(buttonConfig.background.colorToken, -200);
@@ -11993,6 +12127,7 @@ var cosmicStardustEffect = {
11993
12127
  description: "Rotating rainbow gradient glow (always visible, intensifies on hover)",
11994
12128
  category: "overlay",
11995
12129
  pseudoElement: "before",
12130
+ applicableTo: ["button"],
11996
12131
  customizableOption: {
11997
12132
  name: "speed",
11998
12133
  type: "select",
@@ -12055,6 +12190,7 @@ var gradientBorderFillEffect = {
12055
12190
  description: "Gradient border that fills on hover using ::before pseudo-element",
12056
12191
  category: "overlay",
12057
12192
  pseudoElement: "before",
12193
+ applicableTo: ["button"],
12058
12194
  customizableOption: {
12059
12195
  name: "borderWidth",
12060
12196
  type: "number",
@@ -12111,6 +12247,7 @@ var animatedGradientBorderFillEffect = {
12111
12247
  description: "Rotating gradient border that fills on hover",
12112
12248
  category: "overlay",
12113
12249
  pseudoElement: "before",
12250
+ applicableTo: ["button"],
12114
12251
  customizableOption: {
12115
12252
  name: "speed",
12116
12253
  type: "select",
@@ -12186,6 +12323,7 @@ var borderBottomGrowEffect = {
12186
12323
  description: "Animated underline that grows on hover",
12187
12324
  category: "overlay",
12188
12325
  pseudoElement: "after",
12326
+ applicableTo: ["button", "nav-link"],
12189
12327
  customizableOption: {
12190
12328
  name: "height",
12191
12329
  type: "number",
@@ -12233,6 +12371,7 @@ var gradientTextEffect = {
12233
12371
  description: "Gradient text using background-clip",
12234
12372
  category: "text",
12235
12373
  pseudoElement: "none",
12374
+ applicableTo: ["button"],
12236
12375
  customizableOption: {
12237
12376
  name: "solidOnHover",
12238
12377
  type: "select",
@@ -12284,6 +12423,7 @@ var textColorChangeEffect = {
12284
12423
  description: "Changes text color on hover",
12285
12424
  category: "text",
12286
12425
  pseudoElement: "none",
12426
+ applicableTo: ["button", "nav-link"],
12287
12427
  customizableOption: {
12288
12428
  name: "hoverColorToken",
12289
12429
  type: "select",
@@ -12311,6 +12451,7 @@ var borderColorChangeEffect = {
12311
12451
  description: "Changes border color on hover",
12312
12452
  category: "border",
12313
12453
  pseudoElement: "none",
12454
+ applicableTo: ["button", "nav-link"],
12314
12455
  customizableOption: {
12315
12456
  name: "hoverColorToken",
12316
12457
  type: "select",
@@ -12336,6 +12477,7 @@ var sketchyBorderEffect = {
12336
12477
  description: "Hand-drawn style with imperfect edges",
12337
12478
  category: "border",
12338
12479
  pseudoElement: "none",
12480
+ applicableTo: ["button"],
12339
12481
  customizableOption: {
12340
12482
  name: "intensity",
12341
12483
  type: "select",
@@ -12383,6 +12525,7 @@ var pulseAnimationEffect = {
12383
12525
  description: "Continuous pulse animation (opacity fade)",
12384
12526
  category: "animation",
12385
12527
  pseudoElement: "none",
12528
+ applicableTo: ["button", "nav-link"],
12386
12529
  customizableOption: {
12387
12530
  name: "speed",
12388
12531
  type: "select",
@@ -12411,6 +12554,138 @@ var pulseAnimationEffect = {
12411
12554
  }
12412
12555
  };
12413
12556
 
12557
+ // ../blocks/src/theme/interactive/effects/nav-underline.ts
12558
+ var navUnderlineEffect = {
12559
+ id: "nav-underline",
12560
+ name: "Nav Underline",
12561
+ description: "Underline that appears or grows on hover",
12562
+ category: "overlay",
12563
+ pseudoElement: "after",
12564
+ applicableTo: ["nav-link"],
12565
+ customizableOption: {
12566
+ name: "style",
12567
+ type: "select",
12568
+ label: "Underline Style",
12569
+ default: "static",
12570
+ options: ["static", "grow"]
12571
+ },
12572
+ generateCSS: (ctx) => {
12573
+ const { themeId, variantId, options, tokens } = ctx;
12574
+ const style = options.style || "static";
12575
+ const colorToken = options.colorToken || "primary";
12576
+ const color = tokens.getColor(colorToken);
12577
+ const height = options.height || 2;
12578
+ if (style === "grow") {
12579
+ return `
12580
+ /* Setup nav link for pseudo-element */
12581
+ :where([data-theme-scope="${themeId}"]) .${variantId} {
12582
+ position: relative;
12583
+ }
12584
+
12585
+ /* Underline using ::after - starts at 0 width */
12586
+ :where([data-theme-scope="${themeId}"]) .${variantId}::after {
12587
+ content: '';
12588
+ position: absolute;
12589
+ bottom: 0;
12590
+ left: 50%;
12591
+ width: 0;
12592
+ height: ${height}px;
12593
+ background: ${color};
12594
+ transform: translateX(-50%);
12595
+ transition: width 200ms ease-in-out;
12596
+ }
12597
+
12598
+ /* Grow underline on hover */
12599
+ :where([data-theme-scope="${themeId}"]) .${variantId}:hover::after {
12600
+ width: 100%;
12601
+ }
12602
+ `;
12603
+ }
12604
+ return `
12605
+ /* Setup nav link for pseudo-element */
12606
+ :where([data-theme-scope="${themeId}"]) .${variantId} {
12607
+ position: relative;
12608
+ }
12609
+
12610
+ /* Hidden underline using ::after */
12611
+ :where([data-theme-scope="${themeId}"]) .${variantId}::after {
12612
+ content: '';
12613
+ position: absolute;
12614
+ bottom: 0;
12615
+ left: 0;
12616
+ width: 100%;
12617
+ height: ${height}px;
12618
+ background: ${color};
12619
+ opacity: 0;
12620
+ transition: opacity 150ms ease-in-out;
12621
+ }
12622
+
12623
+ /* Show underline on hover */
12624
+ :where([data-theme-scope="${themeId}"]) .${variantId}:hover::after {
12625
+ opacity: 1;
12626
+ }
12627
+ `;
12628
+ }
12629
+ };
12630
+
12631
+ // ../blocks/src/theme/interactive/effects/nav-frosted.ts
12632
+ var navFrostedBaseEffect = {
12633
+ id: "nav-frosted-base",
12634
+ name: "Nav Frosted Base",
12635
+ description: "Base frosted glass styling for nav links",
12636
+ category: "background",
12637
+ pseudoElement: "none",
12638
+ applicableTo: ["nav-link"],
12639
+ generateCSS: (ctx) => {
12640
+ const { themeId, variantId } = ctx;
12641
+ return `
12642
+ /* Frosted glass base state */
12643
+ :where([data-theme-scope="${themeId}"]) .${variantId} {
12644
+ background: rgba(255, 255, 255, 0.05);
12645
+ backdrop-filter: blur(4px);
12646
+ -webkit-backdrop-filter: blur(4px);
12647
+ transition: background 150ms ease, backdrop-filter 150ms ease;
12648
+ }
12649
+ `;
12650
+ }
12651
+ };
12652
+ var navFrostedHoverEffect = {
12653
+ id: "nav-frosted-hover",
12654
+ name: "Nav Frosted Hover",
12655
+ description: "Enhanced frosted glass on hover",
12656
+ category: "background",
12657
+ pseudoElement: "none",
12658
+ applicableTo: ["nav-link"],
12659
+ generateCSS: (ctx) => {
12660
+ const { themeId, variantId } = ctx;
12661
+ return `
12662
+ /* Frosted glass hover state */
12663
+ :where([data-theme-scope="${themeId}"]) .${variantId}:hover {
12664
+ background: rgba(255, 255, 255, 0.1);
12665
+ backdrop-filter: blur(8px);
12666
+ -webkit-backdrop-filter: blur(8px);
12667
+ }
12668
+ `;
12669
+ }
12670
+ };
12671
+ var navFrostedActiveEffect = {
12672
+ id: "nav-frosted-active",
12673
+ name: "Nav Frosted Active",
12674
+ description: "Frosted glass active/pressed state",
12675
+ category: "background",
12676
+ pseudoElement: "none",
12677
+ applicableTo: ["nav-link"],
12678
+ generateCSS: (ctx) => {
12679
+ const { themeId, variantId } = ctx;
12680
+ return `
12681
+ /* Frosted glass active state */
12682
+ :where([data-theme-scope="${themeId}"]) .${variantId}:active {
12683
+ background: rgba(255, 255, 255, 0.15);
12684
+ }
12685
+ `;
12686
+ }
12687
+ };
12688
+
12414
12689
  // ../blocks/src/theme/buttons/effects/registry.ts
12415
12690
  var EFFECT_PRESETS = [
12416
12691
  // Background effects
@@ -12447,88 +12722,65 @@ var EFFECT_PRESETS = [
12447
12722
  borderColorChangeEffect,
12448
12723
  sketchyBorderEffect,
12449
12724
  // Animation effects
12450
- pulseAnimationEffect
12725
+ pulseAnimationEffect,
12726
+ // Nav-link specific effects
12727
+ navUnderlineEffect,
12728
+ navFrostedBaseEffect,
12729
+ navFrostedHoverEffect,
12730
+ navFrostedActiveEffect
12451
12731
  ];
12452
12732
  function getEffectPreset(id) {
12453
12733
  return EFFECT_PRESETS.find((preset) => preset.id === id);
12454
12734
  }
12455
12735
 
12456
- // ../blocks/src/theme/tokens/resolver.ts
12457
- var TokenResolver = class {
12458
- constructor(theme) {
12459
- this.theme = theme;
12460
- }
12461
- /**
12462
- * Resolve a color token to a CSS variable reference wrapped in rgb()
12463
- *
12464
- * @param token - Token name (e.g., 'primary-500', 'white', 'text-900')
12465
- * @returns CSS rgb() function with var reference (e.g., 'rgb(var(--tb-primary-500))')
12466
- *
12467
- * Note: CSS variables are stored as RGB channels (e.g., "37 99 235") following Tailwind convention,
12468
- * so we must wrap them with rgb() to create a valid color value.
12469
- *
12470
- * @example
12471
- * resolver.getColor('primary-500') // => 'rgb(var(--tb-primary-500))'
12472
- * resolver.getColor('white') // => 'rgb(var(--tb-white))'
12473
- */
12474
- getColor(token) {
12475
- if (!this.tokenExists(token)) {
12476
- console.warn(
12477
- `[TokenResolver] Color token "${token}" not found in theme palette. Button may render incorrectly.`
12736
+ // ../blocks/src/theme/interactive/generateEffectsCSS.ts
12737
+ function generateEffectsCSS(options) {
12738
+ const { themeId, variantId, effects, elementConfig, tokens, theme } = options;
12739
+ if (!effects) return "";
12740
+ const cssChunks = [];
12741
+ const stateGroups = [
12742
+ ["base", effects.base],
12743
+ ["hover", effects.hover],
12744
+ ["active", effects.active],
12745
+ ["focus", effects.focus]
12746
+ ];
12747
+ for (const [stateGroup, effectApps] of stateGroups) {
12748
+ if (!effectApps || effectApps.length === 0) continue;
12749
+ for (const effectApp of effectApps) {
12750
+ const css2 = generateSingleEffectCSS(
12751
+ themeId,
12752
+ variantId,
12753
+ stateGroup,
12754
+ effectApp,
12755
+ elementConfig,
12756
+ tokens,
12757
+ theme
12478
12758
  );
12759
+ if (css2) {
12760
+ cssChunks.push(css2);
12761
+ }
12479
12762
  }
12480
- return `rgb(var(--tb-${token}))`;
12481
12763
  }
12482
- /**
12483
- * Adjust a color token's shade by a given amount
12484
- *
12485
- * @param token - Base token (e.g., 'primary-500')
12486
- * @param amount - Shade adjustment (+100 = darker, -100 = lighter)
12487
- * @returns Adjusted token name (e.g., 'primary-600')
12488
- *
12489
- * @example
12490
- * resolver.adjustShade('primary-500', 100) // => 'primary-600' (darker)
12491
- * resolver.adjustShade('primary-500', -100) // => 'primary-400' (lighter)
12492
- */
12493
- adjustShade(token, amount) {
12494
- const parts = token.split("-");
12495
- if (parts.length < 2) {
12496
- const newShade2 = Math.max(100, Math.min(900, 500 + amount));
12497
- return `${token}-${newShade2}`;
12498
- }
12499
- const base = parts.slice(0, -1).join("-");
12500
- const shade = parseInt(parts[parts.length - 1], 10);
12501
- if (isNaN(shade)) {
12502
- console.warn(
12503
- `[TokenResolver] Cannot adjust shade for non-shade token "${token}". Returning original token.`
12504
- );
12505
- return token;
12506
- }
12507
- const newShade = Math.max(100, Math.min(900, shade + amount));
12508
- return `${base}-${newShade}`;
12764
+ return cssChunks.join("\n\n");
12765
+ }
12766
+ function generateSingleEffectCSS(themeId, variantId, stateGroup, effectApp, elementConfig, tokens, theme) {
12767
+ const effectPreset = getEffectPreset(effectApp.effectId);
12768
+ if (!effectPreset) {
12769
+ console.warn(`[generateEffectsCSS] Unknown effect: ${effectApp.effectId}`);
12770
+ return "";
12509
12771
  }
12510
- /**
12511
- * Check if a token exists in the theme palette
12512
- *
12513
- * @param token - Token name to check
12514
- * @returns True if token exists in theme
12515
- */
12516
- tokenExists(token) {
12517
- const commonTokens = ["white", "black", "transparent"];
12518
- if (commonTokens.includes(token)) {
12519
- return true;
12520
- }
12521
- const parts = token.split("-");
12522
- if (parts.length >= 2) {
12523
- const lastPart = parts[parts.length - 1];
12524
- const shade = parseInt(lastPart, 10);
12525
- if (!isNaN(shade) && shade >= 100 && shade <= 900 && shade % 100 === 0) {
12526
- return true;
12527
- }
12528
- }
12529
- return true;
12530
- }
12531
- };
12772
+ const ctx = {
12773
+ themeId,
12774
+ variantId,
12775
+ stateGroup,
12776
+ options: effectApp.options || {},
12777
+ buttonConfig: elementConfig,
12778
+ // Effects access .background, .textColorToken, .border
12779
+ tokens,
12780
+ theme
12781
+ };
12782
+ return effectPreset.generateCSS(ctx);
12783
+ }
12532
12784
 
12533
12785
  // ../blocks/src/theme/buttons/constants.ts
12534
12786
  var GRADIENT_DIRECTION_MAP = {
@@ -12587,6 +12839,11 @@ var FONT_SIZE_MAP = {
12587
12839
  "text-xl": "1.25rem",
12588
12840
  "text-2xl": "1.5rem"
12589
12841
  };
12842
+ var BUTTON_PADDING_PRESETS = {
12843
+ compact: "0.375rem 0.75rem",
12844
+ default: "0.5rem 1rem",
12845
+ spacious: "0.75rem 1.5rem"
12846
+ };
12590
12847
 
12591
12848
  // ../blocks/src/theme/buttons/utils/contrast.ts
12592
12849
  function getContrastingTextColorToken(backgroundToken, theme) {
@@ -12596,7 +12853,7 @@ function getContrastingTextColorToken(backgroundToken, theme) {
12596
12853
  }
12597
12854
  if (backgroundToken.startsWith("neutral-")) {
12598
12855
  const match = backgroundToken.match(/neutral-(\d+)/);
12599
- if (match) {
12856
+ if (match?.[1]) {
12600
12857
  const shade = parseInt(match[1], 10);
12601
12858
  return shade >= 500 ? "neutral-50" : "neutral-950";
12602
12859
  }
@@ -12605,16 +12862,6 @@ function getContrastingTextColorToken(backgroundToken, theme) {
12605
12862
  }
12606
12863
 
12607
12864
  // ../blocks/src/theme/buttons/generateDefaultButtonSystem.ts
12608
- var CORNERS_TO_RADIUS_MAP = {
12609
- square: "rounded-none",
12610
- // 0px - sharp corners
12611
- soft: "rounded-md",
12612
- // 6px - subtle rounding
12613
- rounded: "rounded-md",
12614
- // 6px - standard rounded (same as soft for buttons)
12615
- pill: "rounded-full"
12616
- // 9999px - full pill shape
12617
- };
12618
12865
  var BORDER_WIDTH_TO_CLASS_MAP = {
12619
12866
  none: "border-0",
12620
12867
  // 0px
@@ -12626,7 +12873,6 @@ var BORDER_WIDTH_TO_CLASS_MAP = {
12626
12873
  // 4px - clearly thick
12627
12874
  };
12628
12875
  function generateDefaultButtonSystem(theme) {
12629
- const borderRadius = CORNERS_TO_RADIUS_MAP[theme.corners] || "rounded-lg";
12630
12876
  const borderWidthClass = BORDER_WIDTH_TO_CLASS_MAP[theme.border.width] || "border-2";
12631
12877
  const variants = [];
12632
12878
  const primaryVariant = {
@@ -12636,10 +12882,11 @@ function generateDefaultButtonSystem(theme) {
12636
12882
  priority: 1,
12637
12883
  background: {
12638
12884
  type: "solid",
12639
- colorToken: "primary-500"
12885
+ colorToken: "primary"
12640
12886
  },
12641
- textColorToken: getContrastingTextColorToken("primary-500", theme),
12642
- borderRadius,
12887
+ textColorToken: getContrastingTextColorToken("primary", theme),
12888
+ borderRadius: "",
12889
+ // Empty string = inherit from global.cornerStyle
12643
12890
  // Inherits shadow from theme
12644
12891
  effects: {
12645
12892
  hover: [
@@ -12661,7 +12908,8 @@ function generateDefaultButtonSystem(theme) {
12661
12908
  colorToken: "neutral-700"
12662
12909
  },
12663
12910
  textColorToken: getContrastingTextColorToken("neutral-700", theme),
12664
- borderRadius,
12911
+ borderRadius: "",
12912
+ // Empty string = inherit from global.cornerStyle
12665
12913
  // Inherits shadow from theme
12666
12914
  effects: {
12667
12915
  hover: [
@@ -12681,12 +12929,13 @@ function generateDefaultButtonSystem(theme) {
12681
12929
  background: {
12682
12930
  type: "transparent"
12683
12931
  },
12684
- textColorToken: "primary-600",
12685
- borderRadius,
12932
+ textColorToken: "primary",
12933
+ borderRadius: "",
12934
+ // Empty string = inherit from global.cornerStyle
12686
12935
  shadow: { elevation: "none", softness: null, position: "bottom" },
12687
12936
  // Outline buttons typically don't have shadows
12688
12937
  border: {
12689
- colorToken: "primary-500",
12938
+ colorToken: "primary",
12690
12939
  widthClass: borderWidthClass
12691
12940
  },
12692
12941
  effects: {
@@ -12707,8 +12956,9 @@ function generateDefaultButtonSystem(theme) {
12707
12956
  background: {
12708
12957
  type: "transparent"
12709
12958
  },
12710
- textColorToken: "primary-600",
12711
- borderRadius,
12959
+ textColorToken: "primary",
12960
+ borderRadius: "",
12961
+ // Empty string = inherit from global.cornerStyle
12712
12962
  shadow: { elevation: "none", softness: null, position: "bottom" },
12713
12963
  // Ghost buttons have no shadow
12714
12964
  // No border for ghost buttons
@@ -12774,6 +13024,10 @@ function generateButtonCss(options) {
12774
13024
  if (!variant.enabled) continue;
12775
13025
  const baseCSS = generateVariantBaseCSS(variant, buttonSystem.global, themeId, tokens, theme);
12776
13026
  cssChunks.push(baseCSS);
13027
+ const hoverBgCSS = generateHoverBackgroundCSS(variant, buttonSystem.global, themeId, tokens);
13028
+ if (hoverBgCSS) {
13029
+ cssChunks.push(hoverBgCSS);
13030
+ }
12777
13031
  const effectCSS = generateVariantEffectCSS(variant, themeId, tokens, theme);
12778
13032
  if (effectCSS) {
12779
13033
  cssChunks.push(effectCSS);
@@ -12792,7 +13046,7 @@ function generateVariantBaseCSS(variant, global, themeId, tokens, theme) {
12792
13046
  const rules = [];
12793
13047
  const borderWidth = variant.border ? BORDER_WIDTH_MAP[variant.border.widthClass] || "1px" : "0px";
12794
13048
  const hasBorder = borderWidth !== "0px";
12795
- const padding = variant.padding || STRUCTURAL_BASE_STYLES.padding;
13049
+ const padding = variant.padding || (global.paddingPreset ? BUTTON_PADDING_PRESETS[global.paddingPreset] : null) || STRUCTURAL_BASE_STYLES.padding;
12796
13050
  const paddingParts = padding.split(" ");
12797
13051
  const verticalPadding = paddingParts[0] || "0.5rem";
12798
13052
  const horizontalPadding = paddingParts[1] || paddingParts[0] || "1rem";
@@ -12805,6 +13059,15 @@ function generateVariantBaseCSS(variant, global, themeId, tokens, theme) {
12805
13059
  rules.push(`padding: ${padding};`);
12806
13060
  }
12807
13061
  rules.push(`font-weight: ${global.fontWeight};`);
13062
+ if (global.typography === "heading") {
13063
+ rules.push(`font-family: var(--font-heading);`);
13064
+ rules.push(`letter-spacing: var(--ls-heading);`);
13065
+ } else {
13066
+ rules.push(`font-family: var(--font-body);`);
13067
+ }
13068
+ if (global.italic) {
13069
+ rules.push(`font-style: italic;`);
13070
+ }
12808
13071
  if (variant.fontSize) {
12809
13072
  const fontSize = FONT_SIZE_MAP[variant.fontSize] || "1rem";
12810
13073
  rules.push(`font-size: ${fontSize};`);
@@ -12818,16 +13081,16 @@ function generateVariantBaseCSS(variant, global, themeId, tokens, theme) {
12818
13081
  rules.push(`align-items: ${STRUCTURAL_BASE_STYLES.alignItems};`);
12819
13082
  rules.push(`justify-content: ${STRUCTURAL_BASE_STYLES.justifyContent};`);
12820
13083
  let borderRadius;
12821
- if (variant.borderRadius) {
12822
- borderRadius = BORDER_RADIUS_MAP[variant.borderRadius] || BORDER_RADIUS_MAP["rounded"];
13084
+ if (variant.borderRadius && variant.borderRadius !== "") {
13085
+ borderRadius = BORDER_RADIUS_MAP[variant.borderRadius] ?? BORDER_RADIUS_MAP["rounded"] ?? "0.375rem";
12823
13086
  } else {
12824
13087
  const cornerStyleMap = {
12825
13088
  "square": "rounded-none",
12826
13089
  "rounded": "rounded-md",
12827
13090
  "pill": "rounded-full"
12828
13091
  };
12829
- const fallbackRadius = cornerStyleMap[global.cornerStyle] || "rounded-md";
12830
- borderRadius = BORDER_RADIUS_MAP[fallbackRadius] || BORDER_RADIUS_MAP["rounded"];
13092
+ const fallbackRadius = cornerStyleMap[global.cornerStyle] ?? "rounded-md";
13093
+ borderRadius = BORDER_RADIUS_MAP[fallbackRadius] ?? BORDER_RADIUS_MAP["rounded"] ?? "0.375rem";
12831
13094
  }
12832
13095
  rules.push(`border-radius: ${borderRadius};`);
12833
13096
  const shadowConfig = variant.shadow || shadowSizeToShadow(global.shadow, theme) || theme.shadow;
@@ -12863,31 +13126,33 @@ ${selector} {
12863
13126
  }
12864
13127
  function generateVariantEffectCSS(variant, themeId, tokens, theme) {
12865
13128
  if (!variant.effects) return "";
12866
- const cssChunks = [];
12867
- for (const [stateGroup, effectApps] of Object.entries(variant.effects)) {
12868
- if (!effectApps || effectApps.length === 0) continue;
12869
- for (const effectApp of effectApps) {
12870
- const effectPreset = getEffectPreset(effectApp.effectId);
12871
- if (!effectPreset) {
12872
- console.warn(`[generateVariantEffectCSS] Unknown effect: ${effectApp.effectId}`);
12873
- continue;
12874
- }
12875
- const ctx = {
12876
- themeId,
12877
- variantId: variant.id,
12878
- stateGroup,
12879
- options: effectApp.options || {},
12880
- buttonConfig: variant,
12881
- tokens,
12882
- theme
12883
- };
12884
- const css2 = effectPreset.generateCSS(ctx);
12885
- if (css2) {
12886
- cssChunks.push(css2);
12887
- }
12888
- }
13129
+ const elementConfig = {
13130
+ background: variant.background,
13131
+ textColorToken: variant.textColorToken,
13132
+ border: variant.border ? { colorToken: variant.border.colorToken } : void 0
13133
+ };
13134
+ return generateEffectsCSS({
13135
+ themeId,
13136
+ variantId: variant.id,
13137
+ effects: variant.effects,
13138
+ elementConfig,
13139
+ tokens,
13140
+ theme
13141
+ });
13142
+ }
13143
+ function generateHoverBackgroundCSS(variant, global, themeId, tokens) {
13144
+ let hoverToken = variant.hoverBackgroundToken;
13145
+ if (!hoverToken && global.hoverColor === "token" && global.hoverColorToken) {
13146
+ hoverToken = global.hoverColorToken;
12889
13147
  }
12890
- return cssChunks.join("\n\n");
13148
+ if (!hoverToken) return null;
13149
+ const selector = `:where([data-theme-scope="${themeId}"]) .${variant.id}:hover`;
13150
+ const hoverBgColor = tokens.getColor(hoverToken);
13151
+ return `
13152
+ ${selector} {
13153
+ background-color: ${hoverBgColor};
13154
+ }
13155
+ `.trim();
12891
13156
  }
12892
13157
  function generateDisabledCSS(variant, themeId) {
12893
13158
  const selector = `:where([data-theme-scope="${themeId}"]) .${variant.id}:disabled`;
@@ -13780,6 +14045,345 @@ function generateDefaultInputSystem(theme) {
13780
14045
  };
13781
14046
  }
13782
14047
 
14048
+ // ../blocks/src/theme/navigation/types.ts
14049
+ var import_zod19 = require("zod");
14050
+
14051
+ // ../blocks/src/theme/interactive/baseSchema.ts
14052
+ var import_zod18 = require("zod");
14053
+ var interactiveTypographySchema = import_zod18.z.object({
14054
+ /** Font family source */
14055
+ typography: import_zod18.z.enum(["body", "heading"]).default("body"),
14056
+ /** Font weight */
14057
+ fontWeight: import_zod18.z.enum(["regular", "medium", "semibold", "bold"]).default("medium"),
14058
+ /** Text transform */
14059
+ textTransform: import_zod18.z.enum(["none", "uppercase", "capitalize"]).default("none"),
14060
+ /** Italic style */
14061
+ italic: import_zod18.z.boolean().default(false)
14062
+ });
14063
+ var effectApplicationSchema = import_zod18.z.object({
14064
+ /** Effect preset ID */
14065
+ effectId: import_zod18.z.string(),
14066
+ /** User-provided customization options */
14067
+ options: import_zod18.z.record(import_zod18.z.string(), import_zod18.z.any()).optional()
14068
+ });
14069
+ var effectCompositionSchema = import_zod18.z.object({
14070
+ /** Effects always applied */
14071
+ base: import_zod18.z.array(effectApplicationSchema).optional(),
14072
+ /** Effects applied on hover */
14073
+ hover: import_zod18.z.array(effectApplicationSchema).optional(),
14074
+ /** Effects applied on active/pressed */
14075
+ active: import_zod18.z.array(effectApplicationSchema).optional(),
14076
+ /** Effects applied on focus */
14077
+ focus: import_zod18.z.array(effectApplicationSchema).optional()
14078
+ });
14079
+
14080
+ // ../blocks/src/theme/navigation/types.ts
14081
+ var navLinkPaddingSchema = import_zod19.z.enum(["none", "compact", "default"]);
14082
+ var navLinkBorderRadiusSchema = import_zod19.z.enum(["none", "sm", "md", "full"]);
14083
+ var navLinkStyleSchema = import_zod19.z.object({
14084
+ /** Display name for the style */
14085
+ name: import_zod19.z.string().min(1).max(30).optional(),
14086
+ /** Typography settings (inherited from interactive base) */
14087
+ ...interactiveTypographySchema.shape,
14088
+ /** Text color token */
14089
+ colorToken: import_zod19.z.string().default("text"),
14090
+ /** Hover/active color token (for color-change effects) */
14091
+ hoverColorToken: import_zod19.z.string().nullable().optional(),
14092
+ /** Padding preset */
14093
+ padding: navLinkPaddingSchema.default("compact"),
14094
+ /** Border radius (for capsule/pill styles) */
14095
+ borderRadius: navLinkBorderRadiusSchema.default("none"),
14096
+ /** Composable effects */
14097
+ effects: effectCompositionSchema.optional()
14098
+ });
14099
+ var NAV_LINK_PADDING_MAP = {
14100
+ none: "0",
14101
+ compact: "0.5rem 1rem",
14102
+ default: "0.75rem 1.25rem"
14103
+ };
14104
+ var NAV_LINK_BORDER_RADIUS_MAP = {
14105
+ none: "0",
14106
+ sm: "0.25rem",
14107
+ md: "0.5rem",
14108
+ full: "9999px"
14109
+ };
14110
+
14111
+ // ../blocks/src/theme/interactive/generateBaseCSS.ts
14112
+ var FONT_WEIGHT_MAP2 = {
14113
+ regular: 400,
14114
+ medium: 500,
14115
+ semibold: 600,
14116
+ bold: 700
14117
+ };
14118
+ function generateBaseInteractiveCSS(options) {
14119
+ const {
14120
+ typography,
14121
+ padding,
14122
+ borderRadius,
14123
+ includeTransition = true,
14124
+ includeFlexCenter = false,
14125
+ borderWidth
14126
+ } = options;
14127
+ const rules = [];
14128
+ if (typography.fontWeight !== void 0) {
14129
+ const weight = typeof typography.fontWeight === "number" ? typography.fontWeight : FONT_WEIGHT_MAP2[typography.fontWeight];
14130
+ rules.push(`font-weight: ${weight};`);
14131
+ }
14132
+ if (typography.typography === "heading") {
14133
+ rules.push(`font-family: var(--font-heading);`);
14134
+ rules.push(`letter-spacing: var(--ls-heading);`);
14135
+ } else if (typography.typography === "body") {
14136
+ rules.push(`font-family: var(--font-body);`);
14137
+ }
14138
+ if (typography.italic) {
14139
+ rules.push(`font-style: italic;`);
14140
+ }
14141
+ if (typography.textTransform && typography.textTransform !== "none") {
14142
+ rules.push(`text-transform: ${typography.textTransform};`);
14143
+ }
14144
+ if (padding) {
14145
+ if (borderWidth && borderWidth !== "0px") {
14146
+ const paddingParts = padding.split(" ");
14147
+ const verticalPadding = paddingParts[0] || "0.5rem";
14148
+ const horizontalPadding = paddingParts[1] || paddingParts[0] || "1rem";
14149
+ rules.push(`padding-top: calc(${verticalPadding} - ${borderWidth} - 1px);`);
14150
+ rules.push(`padding-bottom: calc(${verticalPadding} - ${borderWidth} - 1px);`);
14151
+ rules.push(`padding-left: calc(${horizontalPadding} - ${borderWidth});`);
14152
+ rules.push(`padding-right: calc(${horizontalPadding} - ${borderWidth});`);
14153
+ } else {
14154
+ rules.push(`padding: ${padding};`);
14155
+ }
14156
+ }
14157
+ if (borderRadius) {
14158
+ rules.push(`border-radius: ${borderRadius};`);
14159
+ }
14160
+ if (includeTransition) {
14161
+ rules.push(`transition: all 200ms ease;`);
14162
+ }
14163
+ if (includeFlexCenter) {
14164
+ rules.push(`display: inline-flex;`);
14165
+ rules.push(`align-items: center;`);
14166
+ rules.push(`justify-content: center;`);
14167
+ rules.push(`cursor: pointer;`);
14168
+ }
14169
+ return rules;
14170
+ }
14171
+
14172
+ // ../blocks/src/theme/navigation/generateNavLinkCSS.ts
14173
+ function generateNavLinkCSS(options) {
14174
+ const { themeId, tokens, theme, style, className } = options;
14175
+ const selector = `:where([data-theme-scope="${themeId}"]) .${className}`;
14176
+ const hoverSelector = `${selector}:hover`;
14177
+ const activeSelector = `${selector}:active, ${selector}[data-active="true"]`;
14178
+ const cssChunks = [];
14179
+ const hoverRules = [];
14180
+ const activeRules = [];
14181
+ const baseRules = generateBaseInteractiveCSS({
14182
+ typography: {
14183
+ typography: style.typography,
14184
+ fontWeight: style.fontWeight,
14185
+ textTransform: style.textTransform,
14186
+ italic: style.italic
14187
+ },
14188
+ padding: style.padding ? NAV_LINK_PADDING_MAP[style.padding] : void 0,
14189
+ borderRadius: style.borderRadius ? NAV_LINK_BORDER_RADIUS_MAP[style.borderRadius] : void 0,
14190
+ includeTransition: true,
14191
+ includeFlexCenter: false
14192
+ });
14193
+ if (style.colorToken) {
14194
+ baseRules.push(`color: ${tokens.getColor(style.colorToken)};`);
14195
+ }
14196
+ if (style.hoverColorToken && !style.effects?.hover?.length) {
14197
+ hoverRules.push(`color: ${tokens.getColor(style.hoverColorToken)};`);
14198
+ }
14199
+ const elementConfig = {
14200
+ background: { type: "transparent" },
14201
+ textColorToken: style.colorToken || "text"
14202
+ };
14203
+ if (style.effects) {
14204
+ const effectsCss = generateEffectsCSS({
14205
+ themeId,
14206
+ variantId: className,
14207
+ effects: style.effects,
14208
+ elementConfig,
14209
+ tokens,
14210
+ theme
14211
+ });
14212
+ if (effectsCss) {
14213
+ cssChunks.push(effectsCss);
14214
+ }
14215
+ }
14216
+ if (baseRules.length > 0) {
14217
+ cssChunks.unshift(`
14218
+ ${selector} {
14219
+ ${baseRules.join("\n ")}
14220
+ }
14221
+ `);
14222
+ }
14223
+ if (hoverRules.length > 0) {
14224
+ cssChunks.push(`
14225
+ ${hoverSelector} {
14226
+ ${hoverRules.join("\n ")}
14227
+ }
14228
+ `);
14229
+ }
14230
+ if (activeRules.length > 0) {
14231
+ cssChunks.push(`
14232
+ ${activeSelector} {
14233
+ ${activeRules.join("\n ")}
14234
+ }
14235
+ `);
14236
+ }
14237
+ return cssChunks.join("");
14238
+ }
14239
+
14240
+ // ../blocks/src/theme/navigation/presets.ts
14241
+ var NAV_LINK_PRESETS = {
14242
+ /**
14243
+ * Minimal - subtle color change on hover
14244
+ */
14245
+ minimal: {
14246
+ name: "Minimal",
14247
+ typography: "body",
14248
+ fontWeight: "medium",
14249
+ textTransform: "none",
14250
+ italic: false,
14251
+ colorToken: "text",
14252
+ hoverColorToken: "primary",
14253
+ padding: "none",
14254
+ borderRadius: "none",
14255
+ effects: {
14256
+ hover: [
14257
+ { effectId: "text-color-change", options: { colorToken: "primary" } }
14258
+ ]
14259
+ }
14260
+ },
14261
+ /**
14262
+ * Underline - static underline appears on hover
14263
+ */
14264
+ underline: {
14265
+ name: "Underline",
14266
+ typography: "body",
14267
+ fontWeight: "medium",
14268
+ textTransform: "none",
14269
+ italic: false,
14270
+ colorToken: "text",
14271
+ padding: "none",
14272
+ borderRadius: "none",
14273
+ effects: {
14274
+ hover: [
14275
+ { effectId: "nav-underline", options: { style: "static" } }
14276
+ ]
14277
+ }
14278
+ },
14279
+ /**
14280
+ * Underline Grow - animated underline grows from center on hover
14281
+ */
14282
+ "underline-grow": {
14283
+ name: "Underline Grow",
14284
+ typography: "body",
14285
+ fontWeight: "medium",
14286
+ textTransform: "none",
14287
+ italic: false,
14288
+ colorToken: "text",
14289
+ padding: "none",
14290
+ borderRadius: "none",
14291
+ effects: {
14292
+ hover: [
14293
+ { effectId: "nav-underline", options: { style: "grow" } }
14294
+ ]
14295
+ }
14296
+ },
14297
+ /**
14298
+ * Capsule - pill-shaped background on hover
14299
+ */
14300
+ capsule: {
14301
+ name: "Capsule",
14302
+ typography: "body",
14303
+ fontWeight: "medium",
14304
+ textTransform: "none",
14305
+ italic: false,
14306
+ colorToken: "text",
14307
+ padding: "compact",
14308
+ borderRadius: "full",
14309
+ effects: {
14310
+ hover: [
14311
+ { effectId: "background-on-hover-alpha", options: { colorToken: "primary", opacity: 0.1 } }
14312
+ ],
14313
+ active: [
14314
+ { effectId: "background-on-hover-alpha", options: { colorToken: "primary", opacity: 0.15 } }
14315
+ ]
14316
+ }
14317
+ },
14318
+ /**
14319
+ * Solid - solid background color on hover
14320
+ */
14321
+ solid: {
14322
+ name: "Solid",
14323
+ typography: "body",
14324
+ fontWeight: "medium",
14325
+ textTransform: "none",
14326
+ italic: false,
14327
+ colorToken: "text",
14328
+ padding: "compact",
14329
+ borderRadius: "none",
14330
+ effects: {
14331
+ hover: [
14332
+ { effectId: "background-on-hover", options: { colorToken: "primary" } }
14333
+ ],
14334
+ active: [
14335
+ { effectId: "background-on-hover", options: { colorToken: "primary" } }
14336
+ ]
14337
+ }
14338
+ },
14339
+ /**
14340
+ * Scale - gentle scale-up on hover
14341
+ */
14342
+ scale: {
14343
+ name: "Scale",
14344
+ typography: "body",
14345
+ fontWeight: "medium",
14346
+ textTransform: "none",
14347
+ italic: false,
14348
+ colorToken: "text",
14349
+ padding: "none",
14350
+ borderRadius: "none",
14351
+ effects: {
14352
+ hover: [
14353
+ { effectId: "scale-up", options: { scale: 1.05 } }
14354
+ ]
14355
+ }
14356
+ },
14357
+ /**
14358
+ * Frosted - semi-transparent glass-like background
14359
+ */
14360
+ frosted: {
14361
+ name: "Frosted",
14362
+ typography: "body",
14363
+ fontWeight: "medium",
14364
+ textTransform: "none",
14365
+ italic: false,
14366
+ colorToken: "text",
14367
+ padding: "compact",
14368
+ borderRadius: "md",
14369
+ effects: {
14370
+ base: [
14371
+ { effectId: "nav-frosted-base" }
14372
+ ],
14373
+ hover: [
14374
+ { effectId: "nav-frosted-hover" }
14375
+ ],
14376
+ active: [
14377
+ { effectId: "nav-frosted-active" }
14378
+ ]
14379
+ }
14380
+ }
14381
+ };
14382
+ function getNavLinkPreset(presetId) {
14383
+ return NAV_LINK_PRESETS[presetId];
14384
+ }
14385
+ var NAV_LINK_PRESET_IDS = Object.keys(NAV_LINK_PRESETS);
14386
+
13783
14387
  // ../blocks/src/theme/header/generateHeaderCss.ts
13784
14388
  function generateHeaderCss(options) {
13785
14389
  const { themeId, theme } = options;
@@ -13787,10 +14391,8 @@ function generateHeaderCss(options) {
13787
14391
  const header = theme.header;
13788
14392
  const cssChunks = [];
13789
14393
  cssChunks.push(generateHeaderRootStyles(header, themeId, tokens, theme));
13790
- if (header.logo) {
13791
- cssChunks.push(generateLogoStyles(header.logo, themeId, tokens));
13792
- }
13793
- cssChunks.push(generateNavLinkStyles(header, themeId, tokens));
14394
+ cssChunks.push(generateLogoStyles(header.logo, themeId, tokens, header.textColor));
14395
+ cssChunks.push(generateNavLinkStyles(header, themeId, tokens, theme));
13794
14396
  if (header.variant === "floating" && header.container) {
13795
14397
  cssChunks.push(generateFloatingContainerStyles(header.container, themeId, tokens));
13796
14398
  }
@@ -13846,32 +14448,36 @@ ${selector} {
13846
14448
  }
13847
14449
  `;
13848
14450
  }
13849
- function generateLogoStyles(logo, themeId, tokens) {
13850
- if (!logo) return "";
14451
+ function generateLogoStyles(logo, themeId, tokens, textColor) {
13851
14452
  const selector = `:where([data-theme-scope="${themeId}"]) .header-logo-text`;
13852
14453
  const rules = [];
13853
14454
  const primaryColor = tokens.getColor("primary");
13854
14455
  const accentColor = tokens.getColor("accent");
13855
- if (logo.fontFamily === "mono") {
13856
- rules.push(`font-family: ui-monospace, monospace;`);
13857
- } else if (logo.fontFamily === "serif") {
13858
- rules.push(`font-family: ui-serif, serif;`);
13859
- }
13860
- if (logo.letterSpacing && logo.letterSpacing !== "normal") {
13861
- const spacingMap = {
13862
- "normal": "0em",
13863
- "wide": "0.05em",
13864
- "wider": "0.1em",
13865
- "widest": "0.15em"
13866
- };
13867
- rules.push(`letter-spacing: ${spacingMap[logo.letterSpacing]};`);
13868
- }
13869
- if (logo.gradient) {
13870
- rules.push(`background: linear-gradient(to right, ${primaryColor}, ${accentColor});`);
13871
- rules.push(`-webkit-background-clip: text;`);
13872
- rules.push(`-webkit-text-fill-color: transparent;`);
13873
- rules.push(`background-clip: text;`);
13874
- rules.push(`color: transparent;`);
14456
+ if (textColor && !logo?.gradient) {
14457
+ rules.push(`color: ${tokens.getColor(textColor)};`);
14458
+ }
14459
+ if (logo) {
14460
+ if (logo.fontFamily === "mono") {
14461
+ rules.push(`font-family: ui-monospace, monospace;`);
14462
+ } else if (logo.fontFamily === "serif") {
14463
+ rules.push(`font-family: ui-serif, serif;`);
14464
+ }
14465
+ if (logo.letterSpacing && logo.letterSpacing !== "normal") {
14466
+ const spacingMap = {
14467
+ "normal": "0em",
14468
+ "wide": "0.05em",
14469
+ "wider": "0.1em",
14470
+ "widest": "0.15em"
14471
+ };
14472
+ rules.push(`letter-spacing: ${spacingMap[logo.letterSpacing]};`);
14473
+ }
14474
+ if (logo.gradient) {
14475
+ rules.push(`background: linear-gradient(to right, ${primaryColor}, ${accentColor});`);
14476
+ rules.push(`-webkit-background-clip: text;`);
14477
+ rules.push(`-webkit-text-fill-color: transparent;`);
14478
+ rules.push(`background-clip: text;`);
14479
+ rules.push(`color: transparent;`);
14480
+ }
13875
14481
  }
13876
14482
  if (rules.length === 0) return "";
13877
14483
  return `
@@ -13880,129 +14486,82 @@ ${selector} {
13880
14486
  }
13881
14487
  `;
13882
14488
  }
13883
- function generateNavLinkStyles(header, themeId, tokens) {
13884
- const selector = `:where([data-theme-scope="${themeId}"]) .header-nav-link`;
13885
- const hoverSelector = `${selector}:hover`;
13886
- const activeSelector = `${selector}[data-active="true"]`;
13887
- const cssChunks = [];
13888
- const baseRules = [];
13889
- const hoverRules = [];
13890
- const activeRules = [];
13891
- const navContainerType = header.navContainer?.type ?? "none";
13892
- const usesGlassNavContainer = navContainerType === "glass";
13893
- const navColorToken = header.navColor?.trim();
13894
- const primaryColor = tokens.getColor("primary");
13895
- const navWeight = header.navWeight ?? "medium";
13896
- const navWeightMap = {
13897
- regular: 400,
13898
- medium: 500,
13899
- semibold: 600,
13900
- bold: 700
13901
- };
13902
- if (navColorToken) {
13903
- baseRules.push(`color: ${tokens.getColor(navColorToken)};`);
13904
- }
13905
- if (navWeight) {
13906
- baseRules.push(`font-weight: ${navWeightMap[navWeight]};`);
13907
- }
13908
- if (navWeight === "bold" && header.navStyle === "solid") {
13909
- baseRules.push(`text-transform: uppercase;`);
13910
- }
13911
- switch (header.navStyle) {
13912
- case "minimal":
13913
- baseRules.push(`transition: color 200ms ease;`);
13914
- hoverRules.push(`color: ${primaryColor};`);
13915
- activeRules.push(`color: ${primaryColor};`);
13916
- break;
13917
- case "underline":
13918
- baseRules.push(`transition: all 200ms ease;`);
13919
- hoverRules.push(`text-decoration: underline;`);
13920
- hoverRules.push(`text-underline-offset: 4px;`);
13921
- activeRules.push(`text-decoration: underline;`);
13922
- activeRules.push(`text-underline-offset: 4px;`);
13923
- break;
13924
- case "underline-grow":
13925
- baseRules.push(`position: relative;`);
13926
- baseRules.push(`transition: color 200ms ease;`);
13927
- hoverRules.push(`color: ${primaryColor};`);
13928
- activeRules.push(`color: ${primaryColor};`);
13929
- cssChunks.push(generateUnderlineGrowCSS(themeId));
13930
- break;
13931
- case "capsule":
13932
- baseRules.push(`border-radius: 9999px;`);
13933
- baseRules.push(`transition: background-color 200ms ease;`);
13934
- hoverRules.push(`background-color: color-mix(in srgb, ${primaryColor} 10%, transparent);`);
13935
- activeRules.push(`background-color: color-mix(in srgb, ${primaryColor} 15%, transparent);`);
13936
- break;
13937
- case "solid":
13938
- baseRules.push(`border-radius: 0;`);
13939
- baseRules.push(`transition: background-color 200ms ease, color 200ms ease;`);
13940
- hoverRules.push(`background-color: ${primaryColor};`);
13941
- if (navColorToken) {
13942
- hoverRules.push(`color: ${tokens.getColor(navColorToken)};`);
13943
- }
13944
- activeRules.push(`background-color: ${primaryColor};`);
13945
- if (navColorToken) {
13946
- activeRules.push(`color: ${tokens.getColor(navColorToken)};`);
13947
- }
13948
- break;
13949
- case "scale":
13950
- baseRules.push(`transition: all 200ms ease;`);
13951
- hoverRules.push(`transform: scale(1.05);`);
13952
- break;
13953
- case "frosted":
13954
- baseRules.push(`border-radius: 0.5rem;`);
13955
- baseRules.push(`background-color: rgb(255 255 255 / 0.1);`);
13956
- baseRules.push(`backdrop-filter: blur(8px);`);
13957
- baseRules.push(`transition: background-color 200ms ease;`);
13958
- hoverRules.push(`background-color: rgb(255 255 255 / 0.2);`);
13959
- activeRules.push(`background-color: rgb(255 255 255 / 0.25);`);
13960
- break;
14489
+ function generateNavLinkStyles(header, themeId, tokens, theme) {
14490
+ if (header.navLinkStyle) {
14491
+ return generateNavLinkCSS({
14492
+ themeId,
14493
+ tokens,
14494
+ theme,
14495
+ style: header.navLinkStyle,
14496
+ className: "header-nav-link"
14497
+ });
13961
14498
  }
13962
- if (usesGlassNavContainer && header.navStyle === "minimal") {
13963
- baseRules.push(`border-radius: 9999px;`);
13964
- hoverRules.push(`background-color: rgba(255, 255, 255, 0.1);`);
13965
- activeRules.push(`background-color: rgba(255, 255, 255, 0.18);`);
13966
- hoverRules.push(`color: #fff;`);
13967
- activeRules.push(`color: #fff;`);
14499
+ const navStyle = header.navStyle ?? "minimal";
14500
+ const basePreset = getNavLinkPreset(navStyle);
14501
+ if (!basePreset) {
14502
+ console.warn(`[generateHeaderCss] Nav link preset not found: ${navStyle}`);
14503
+ return "";
14504
+ }
14505
+ const mergedStyle = {
14506
+ ...basePreset,
14507
+ // Override with legacy settings
14508
+ fontWeight: header.navWeight ?? basePreset.fontWeight,
14509
+ colorToken: (header.navColor ?? header.textColor)?.trim() || basePreset.colorToken
14510
+ };
14511
+ if (header.navWeight === "bold" && navStyle === "solid") {
14512
+ mergedStyle.textTransform = "uppercase";
13968
14513
  }
13969
14514
  if (header.navEffects) {
14515
+ mergedStyle.effects = {
14516
+ ...mergedStyle.effects,
14517
+ hover: [...mergedStyle.effects?.hover || []],
14518
+ active: [...mergedStyle.effects?.active || []]
14519
+ };
13970
14520
  if (header.navEffects.glow) {
13971
- hoverRules.push(`filter: drop-shadow(0 0 5px currentColor);`);
14521
+ mergedStyle.effects.hover.push({
14522
+ effectId: "outer-glow",
14523
+ options: { spread: 5 }
14524
+ });
13972
14525
  }
13973
14526
  if (header.navEffects.neumorphic) {
13974
- console.log("[generateHeaderCss] Generating neumorphic styles for theme:", themeId);
13975
- baseRules.push(`transition: all 200ms ease;`);
13976
- baseRules.push(`border-radius: 0.5rem;`);
13977
- hoverRules.push(`box-shadow: inset 4px 4px 8px #c7c7c7, inset -4px -4px 8px #ffffff;`);
13978
- hoverRules.push(`color: ${primaryColor};`);
14527
+ mergedStyle.effects.hover.push({
14528
+ effectId: "neumorphic-shadow",
14529
+ options: { mode: "pressed" }
14530
+ });
14531
+ mergedStyle.effects.hover.push({
14532
+ effectId: "text-color-change",
14533
+ options: { hoverColorToken: "primary" }
14534
+ });
13979
14535
  }
13980
14536
  if (header.navEffects.underlineGradient) {
13981
- cssChunks.push(generateGradientUnderlineCSS(themeId, tokens));
14537
+ mergedStyle.effects.hover.push({
14538
+ effectId: "border-bottom-grow",
14539
+ options: { origin: "center" }
14540
+ });
13982
14541
  }
13983
14542
  }
13984
- if (baseRules.length > 0) {
13985
- cssChunks.push(`
13986
- ${selector} {
13987
- ${baseRules.join("\n ")}
13988
- }
13989
- `);
13990
- }
13991
- if (hoverRules.length > 0) {
13992
- cssChunks.push(`
13993
- ${hoverSelector} {
13994
- ${hoverRules.join("\n ")}
13995
- }
13996
- `);
13997
- }
13998
- if (activeRules.length > 0) {
13999
- cssChunks.push(`
14000
- ${activeSelector} {
14001
- ${activeRules.join("\n ")}
14002
- }
14003
- `);
14543
+ const navContainerType = header.navContainer?.type ?? "none";
14544
+ if (navContainerType === "glass" && navStyle === "minimal") {
14545
+ mergedStyle.borderRadius = "full";
14546
+ mergedStyle.effects = {
14547
+ ...mergedStyle.effects,
14548
+ hover: [
14549
+ { effectId: "background-on-hover-alpha", options: { colorToken: "neutral-50", opacity: 10 } },
14550
+ { effectId: "text-color-change", options: { hoverColorToken: "neutral-50" } }
14551
+ ],
14552
+ active: [
14553
+ { effectId: "background-on-hover-alpha", options: { colorToken: "neutral-50", opacity: 18 } },
14554
+ { effectId: "text-color-change", options: { hoverColorToken: "neutral-50" } }
14555
+ ]
14556
+ };
14004
14557
  }
14005
- return cssChunks.join("");
14558
+ return generateNavLinkCSS({
14559
+ themeId,
14560
+ tokens,
14561
+ theme,
14562
+ style: mergedStyle,
14563
+ className: "header-nav-link"
14564
+ });
14006
14565
  }
14007
14566
  function generateNavContainerStyles(header, themeId, tokens) {
14008
14567
  const navContainer = header.navContainer;
@@ -14039,52 +14598,6 @@ function generateNavContainerStyles(header, themeId, tokens) {
14039
14598
  }
14040
14599
  return "";
14041
14600
  }
14042
- function generateGradientUnderlineCSS(themeId, tokens) {
14043
- const selector = `:where([data-theme-scope="${themeId}"]) .header-nav-link`;
14044
- const primaryColor = tokens.getColor("primary");
14045
- const accentColor = tokens.getColor("accent");
14046
- return `
14047
- ${selector}::after {
14048
- content: '';
14049
- position: absolute;
14050
- bottom: 0;
14051
- left: 0;
14052
- width: 100%;
14053
- height: 2px;
14054
- background: linear-gradient(to right, ${primaryColor}, ${accentColor});
14055
- transform: scaleX(0);
14056
- transform-origin: center;
14057
- transition: transform 0.3s ease;
14058
- }
14059
-
14060
- ${selector}:hover::after,
14061
- ${selector}[data-active="true"]::after {
14062
- transform: scaleX(1);
14063
- }
14064
- `.trim();
14065
- }
14066
- function generateUnderlineGrowCSS(themeId) {
14067
- const selector = `:where([data-theme-scope="${themeId}"]) .header-nav-link`;
14068
- return `
14069
- ${selector}::after {
14070
- content: '';
14071
- position: absolute;
14072
- bottom: 0;
14073
- left: 0;
14074
- width: 100%;
14075
- height: 2px;
14076
- background: currentColor;
14077
- transform: scaleX(0);
14078
- transform-origin: center;
14079
- transition: transform 0.3s ease;
14080
- }
14081
-
14082
- ${selector}:hover::after,
14083
- ${selector}[data-active="true"]::after {
14084
- transform: scaleX(1);
14085
- }
14086
- `.trim();
14087
- }
14088
14601
  function generateFloatingContainerStyles(container, themeId, tokens) {
14089
14602
  if (!container) return "";
14090
14603
  const selector = `:where([data-theme-scope="${themeId}"]) .header-floating-container`;
@@ -14141,12 +14654,52 @@ function applyAlpha(color, opacity) {
14141
14654
  const clamped = clampOpacity(opacity, 1);
14142
14655
  if (color.startsWith("rgb(") && color.endsWith(")")) {
14143
14656
  const inner = color.slice(4, -1).trim();
14144
- const channels = inner.includes("/") ? inner.split("/")[0].trim() : inner;
14657
+ const channels = inner.includes("/") ? (inner.split("/")[0] ?? inner).trim() : inner;
14145
14658
  return `rgb(${channels} / ${clamped})`;
14146
14659
  }
14147
14660
  return color;
14148
14661
  }
14149
14662
 
14663
+ // ../blocks/src/theme/footer/generateFooterCss.ts
14664
+ function generateFooterCss(options) {
14665
+ const { themeId, theme } = options;
14666
+ const tokens = new TokenResolver(theme);
14667
+ const footer = theme.footer;
14668
+ const cssChunks = [];
14669
+ cssChunks.push(generateFooterNavLinkStyles(footer, themeId, tokens, theme));
14670
+ return cssChunks.filter(Boolean).join("\n\n");
14671
+ }
14672
+ function generateFooterNavLinkStyles(footer, themeId, tokens, theme) {
14673
+ if (footer.navLinkStyle) {
14674
+ return generateNavLinkCSS({
14675
+ themeId,
14676
+ tokens,
14677
+ theme,
14678
+ style: footer.navLinkStyle,
14679
+ className: "footer-nav-link"
14680
+ });
14681
+ }
14682
+ const navStyle = footer.navStyle ?? "minimal";
14683
+ const basePreset = getNavLinkPreset(navStyle);
14684
+ if (!basePreset) {
14685
+ console.warn(`[generateFooterCss] Nav link preset not found: ${navStyle}`);
14686
+ return "";
14687
+ }
14688
+ const mergedStyle = {
14689
+ ...basePreset,
14690
+ // Override with legacy settings
14691
+ fontWeight: footer.navWeight ?? basePreset.fontWeight,
14692
+ colorToken: footer.navColor?.trim() || basePreset.colorToken
14693
+ };
14694
+ return generateNavLinkCSS({
14695
+ themeId,
14696
+ tokens,
14697
+ theme,
14698
+ style: mergedStyle,
14699
+ className: "footer-nav-link"
14700
+ });
14701
+ }
14702
+
14150
14703
  // ../blocks/src/theme/layout/generateLayoutCss.ts
14151
14704
  function generateLayoutCss(options) {
14152
14705
  const { themeId } = options;
@@ -14300,6 +14853,105 @@ ${root} .step-connector {
14300
14853
  return cssBlocks.join("\n\n");
14301
14854
  }
14302
14855
 
14856
+ // ../blocks/src/theme/typography/generateTypographyCss.ts
14857
+ function generateTypographyCss({ themeId }) {
14858
+ const root = `:where([data-theme-scope="${themeId}"])`;
14859
+ const cssBlocks = [];
14860
+ cssBlocks.push(`/* Base heading styles */
14861
+ ${root} :where(h1, h2, h3, h4, h5, h6) {
14862
+ font-family: var(--font-heading);
14863
+ font-style: var(--fi-heading, normal);
14864
+ text-transform: var(--tt-heading, none);
14865
+ font-variant: var(--fv-heading, normal);
14866
+ margin: 0;
14867
+ }`);
14868
+ cssBlocks.push(`/* Heading level styles with fluid typography */
14869
+ ${root} :where(h1) {
14870
+ font-size: var(--fs-h1-fluid, var(--fs-h1));
14871
+ font-weight: var(--fw-h1, var(--font-weight-heading));
14872
+ font-style: var(--fi-h1, var(--fi-heading, normal));
14873
+ letter-spacing: var(--ls-h1, var(--ls-heading));
14874
+ line-height: var(--lh-h1, var(--lh-heading));
14875
+ }
14876
+
14877
+ ${root} :where(h2) {
14878
+ font-size: var(--fs-h2-fluid, var(--fs-h2));
14879
+ font-weight: var(--fw-h2, var(--font-weight-heading));
14880
+ font-style: var(--fi-h2, var(--fi-heading, normal));
14881
+ letter-spacing: var(--ls-h2, var(--ls-heading));
14882
+ line-height: var(--lh-h2, var(--lh-heading));
14883
+ }
14884
+
14885
+ ${root} :where(h3) {
14886
+ font-size: var(--fs-h3-fluid, var(--fs-h3));
14887
+ font-weight: var(--fw-h3, var(--font-weight-heading));
14888
+ font-style: var(--fi-h3, var(--fi-heading, normal));
14889
+ letter-spacing: var(--ls-h3, var(--ls-heading));
14890
+ line-height: var(--lh-h3, var(--lh-heading));
14891
+ }
14892
+
14893
+ ${root} :where(h4) {
14894
+ font-size: var(--fs-h4-fluid, var(--fs-h4, var(--fs-h3)));
14895
+ font-weight: var(--fw-h4, var(--font-weight-heading));
14896
+ font-style: var(--fi-h4, var(--fi-heading, normal));
14897
+ letter-spacing: var(--ls-h4, var(--ls-heading));
14898
+ line-height: var(--lh-h4, var(--lh-heading));
14899
+ }
14900
+
14901
+ ${root} :where(h5) {
14902
+ font-size: var(--fs-h5-fluid, var(--fs-h5, var(--fs-body)));
14903
+ font-weight: var(--fw-h5, var(--font-weight-heading));
14904
+ font-style: var(--fi-h5, var(--fi-heading, normal));
14905
+ letter-spacing: var(--ls-h5, var(--ls-heading));
14906
+ line-height: var(--lh-h5, var(--lh-heading));
14907
+ }
14908
+
14909
+ ${root} :where(h6) {
14910
+ font-size: var(--fs-h6-fluid, var(--fs-h6, var(--fs-body)));
14911
+ font-weight: var(--fw-h6, var(--font-weight-heading));
14912
+ font-style: var(--fi-h6, var(--fi-heading, normal));
14913
+ letter-spacing: var(--ls-h6, var(--ls-heading));
14914
+ line-height: var(--lh-h6, var(--lh-heading));
14915
+ }`);
14916
+ cssBlocks.push(`/* Display variant for hero/splash headings */
14917
+ ${root} :where(.heading-display) {
14918
+ font-size: var(--fs-display-fluid, var(--fs-display));
14919
+ }
14920
+
14921
+ ${root} :where(h1.heading-display) {
14922
+ font-size: var(--fs-h1-display-fluid, var(--fs-h1-display, calc(var(--fs-h1) * 1.5)));
14923
+ }
14924
+
14925
+ ${root} :where(h2.heading-display) {
14926
+ font-size: var(--fs-h2-display-fluid, var(--fs-h2-display, calc(var(--fs-h2) * 1.35)));
14927
+ }`);
14928
+ cssBlocks.push(`/* Compact variant for cards/sidebars */
14929
+ ${root} :where(.heading-compact) {
14930
+ font-size: var(--fs-compact);
14931
+ }
14932
+
14933
+ ${root} :where(h1.heading-compact) {
14934
+ font-size: calc(var(--fs-h1) * 0.75);
14935
+ }
14936
+
14937
+ ${root} :where(h2.heading-compact) {
14938
+ font-size: calc(var(--fs-h2) * 0.8);
14939
+ }
14940
+
14941
+ ${root} :where(h3.heading-compact) {
14942
+ font-size: calc(var(--fs-h3) * 0.85);
14943
+ }`);
14944
+ cssBlocks.push(`/* Body text base styles */
14945
+ ${root} :where(p, li, td, th, label, span) {
14946
+ font-family: var(--font-body);
14947
+ font-weight: var(--font-weight-body);
14948
+ font-size: var(--fs-body);
14949
+ letter-spacing: var(--ls-body);
14950
+ line-height: var(--lh-body);
14951
+ }`);
14952
+ return cssBlocks.join("\n\n");
14953
+ }
14954
+
14303
14955
  // ../blocks/src/theme/runtime/buildThemeRuntime.ts
14304
14956
  function buildThemeRuntime(theme, options) {
14305
14957
  const hydrated = hydrateTheme(theme);
@@ -14314,6 +14966,10 @@ function buildThemeRuntime(theme, options) {
14314
14966
  themeId,
14315
14967
  theme
14316
14968
  });
14969
+ const footerCss = generateFooterCss({
14970
+ themeId,
14971
+ theme
14972
+ });
14317
14973
  const cardCss = generateCardCss({
14318
14974
  themeId,
14319
14975
  theme,
@@ -14343,8 +14999,12 @@ function buildThemeRuntime(theme, options) {
14343
14999
  themeId,
14344
15000
  theme
14345
15001
  });
15002
+ const typographyCss = generateTypographyCss({
15003
+ themeId,
15004
+ theme
15005
+ });
14346
15006
  const tokens = buildThemeTokens(hydrated, theme);
14347
- return { hydrated, cssVars, tokens, paletteTokens: hydrated.palette, buttonCss, headerCss, cardCss, accordionCss, inputCss, layoutCss, statusCss, progressCss };
15007
+ return { hydrated, cssVars, tokens, paletteTokens: hydrated.palette, buttonCss, headerCss, footerCss, cardCss, accordionCss, inputCss, layoutCss, statusCss, progressCss, typographyCss };
14348
15008
  }
14349
15009
  function hydrateTheme(theme) {
14350
15010
  return {
@@ -14374,17 +15034,39 @@ function buildThemeCssVars(theme) {
14374
15034
  ...typography.headings.h1.letterSpacing ? { ["--ls-h1"]: mapLetterSpacing(typography.headings.h1.letterSpacing) } : {},
14375
15035
  ...typography.headings.h2.letterSpacing ? { ["--ls-h2"]: mapLetterSpacing(typography.headings.h2.letterSpacing) } : {},
14376
15036
  ...typography.headings.h3.letterSpacing ? { ["--ls-h3"]: mapLetterSpacing(typography.headings.h3.letterSpacing) } : {},
15037
+ ...typography.headings.h4?.letterSpacing ? { ["--ls-h4"]: mapLetterSpacing(typography.headings.h4.letterSpacing) } : {},
15038
+ ...typography.headings.h5?.letterSpacing ? { ["--ls-h5"]: mapLetterSpacing(typography.headings.h5.letterSpacing) } : {},
15039
+ ...typography.headings.h6?.letterSpacing ? { ["--ls-h6"]: mapLetterSpacing(typography.headings.h6.letterSpacing) } : {},
14377
15040
  ["--lh-heading"]: mapLineHeight(typography.headings.default.lineHeight),
14378
15041
  ["--lh-body"]: mapLineHeight(typography.body.lineHeight),
14379
15042
  ...typography.headings.h1.lineHeight ? { ["--lh-h1"]: mapLineHeight(typography.headings.h1.lineHeight) } : {},
14380
15043
  ...typography.headings.h2.lineHeight ? { ["--lh-h2"]: mapLineHeight(typography.headings.h2.lineHeight) } : {},
14381
15044
  ...typography.headings.h3.lineHeight ? { ["--lh-h3"]: mapLineHeight(typography.headings.h3.lineHeight) } : {},
15045
+ ...typography.headings.h4?.lineHeight ? { ["--lh-h4"]: mapLineHeight(typography.headings.h4.lineHeight) } : {},
15046
+ ...typography.headings.h5?.lineHeight ? { ["--lh-h5"]: mapLineHeight(typography.headings.h5.lineHeight) } : {},
15047
+ ...typography.headings.h6?.lineHeight ? { ["--lh-h6"]: mapLineHeight(typography.headings.h6.lineHeight) } : {},
14382
15048
  ["--tt-heading"]: mapTextTransform(typography.headings.default.case),
14383
15049
  ["--fv-heading"]: mapFontVariant(typography.headings.default.case),
15050
+ ["--fi-heading"]: mapFontStyle(typography.headings.default.italic),
15051
+ // Per-level italic overrides
15052
+ ...typography.headings.h1.italic != null ? { ["--fi-h1"]: mapFontStyle(typography.headings.h1.italic) } : {},
15053
+ ...typography.headings.h2.italic != null ? { ["--fi-h2"]: mapFontStyle(typography.headings.h2.italic) } : {},
15054
+ ...typography.headings.h3.italic != null ? { ["--fi-h3"]: mapFontStyle(typography.headings.h3.italic) } : {},
15055
+ ...typography.headings.h4?.italic != null ? { ["--fi-h4"]: mapFontStyle(typography.headings.h4.italic) } : {},
15056
+ ...typography.headings.h5?.italic != null ? { ["--fi-h5"]: mapFontStyle(typography.headings.h5.italic) } : {},
15057
+ ...typography.headings.h6?.italic != null ? { ["--fi-h6"]: mapFontStyle(typography.headings.h6.italic) } : {},
15058
+ // Static font sizes (fallback)
14384
15059
  ["--fs-body"]: sized.body,
14385
15060
  ["--fs-h3"]: sized.h3,
14386
15061
  ["--fs-h2"]: sized.h2,
14387
15062
  ["--fs-h1"]: sized.h1,
15063
+ // Fluid font sizes (responsive with clamp)
15064
+ ["--fs-h1-fluid"]: sized.h1Fluid,
15065
+ ["--fs-h2-fluid"]: sized.h2Fluid,
15066
+ ["--fs-h3-fluid"]: sized.h3Fluid,
15067
+ // Display variant (for hero/splash headings)
15068
+ ["--fs-h1-display"]: sized.h1Display,
15069
+ ["--fs-h1-display-fluid"]: sized.h1DisplayFluid,
14388
15070
  ["--shadow-elev"]: mapShadow(shadow.elevation, shadow.softness, shadow.position || "bottom"),
14389
15071
  ["--space-mult"]: mapSpaceMult(space),
14390
15072
  ["--motion-duration"]: mapMotionDuration(motion.level),
@@ -14490,33 +15172,81 @@ function mapMotionEasing(e) {
14490
15172
  gentle: "cubic-bezier(.15,.85,.15,1)"
14491
15173
  }[e];
14492
15174
  }
15175
+ function normalizeScaleName(scale) {
15176
+ const aliasMap = {
15177
+ minorThird: "compact",
15178
+ majorThird: "balanced",
15179
+ perfectFourth: "spacious",
15180
+ compact: "compact",
15181
+ balanced: "balanced",
15182
+ spacious: "spacious"
15183
+ };
15184
+ return aliasMap[scale] ?? "balanced";
15185
+ }
14493
15186
  function computeTypeScale(scale, bodySize) {
14494
15187
  const base = { md: 16, lg: 17, xl: 18 }[bodySize];
14495
- const ratio = { minorThird: 1.2, majorThird: 1.25, perfectFourth: 1.333 }[scale];
15188
+ const normalizedScale = normalizeScaleName(scale);
15189
+ const ratio = { compact: 1.2, balanced: 1.25, spacious: 1.333 }[normalizedScale];
14496
15190
  const h3 = Math.round(base * ratio);
14497
15191
  const h2 = Math.round(h3 * ratio);
14498
15192
  const h1 = Math.round(h2 * ratio);
15193
+ const fluidMin = 0.7;
15194
+ const fluidMax = 1.3;
14499
15195
  return {
15196
+ // Static sizes (fallback)
14500
15197
  ["--fs-body"]: `${base}px`,
14501
15198
  ["--fs-h3"]: `${h3}px`,
14502
15199
  ["--fs-h2"]: `${h2}px`,
14503
- ["--fs-h1"]: `${h1}px`
15200
+ ["--fs-h1"]: `${h1}px`,
15201
+ // Fluid typography min/max values
15202
+ ["--fs-h1-min"]: `${Math.round(h1 * fluidMin)}px`,
15203
+ ["--fs-h1-max"]: `${Math.round(h1 * fluidMax)}px`,
15204
+ ["--fs-h2-min"]: `${Math.round(h2 * fluidMin)}px`,
15205
+ ["--fs-h2-max"]: `${Math.round(h2 * fluidMax)}px`,
15206
+ ["--fs-h3-min"]: `${Math.round(h3 * fluidMin)}px`,
15207
+ ["--fs-h3-max"]: `${Math.round(h3 * fluidMax)}px`,
15208
+ // Fluid clamp values (320px to 1200px viewport range = 880px)
15209
+ ["--fs-h1-fluid"]: `clamp(${Math.round(h1 * fluidMin)}px, calc(${Math.round(h1 * fluidMin)}px + ${Math.round(h1 * (fluidMax - fluidMin))} * ((100vw - 320px) / 880)), ${Math.round(h1 * fluidMax)}px)`,
15210
+ ["--fs-h2-fluid"]: `clamp(${Math.round(h2 * fluidMin)}px, calc(${Math.round(h2 * fluidMin)}px + ${Math.round(h2 * (fluidMax - fluidMin))} * ((100vw - 320px) / 880)), ${Math.round(h2 * fluidMax)}px)`,
15211
+ ["--fs-h3-fluid"]: `clamp(${Math.round(h3 * fluidMin)}px, calc(${Math.round(h3 * fluidMin)}px + ${Math.round(h3 * (fluidMax - fluidMin))} * ((100vw - 320px) / 880)), ${Math.round(h3 * fluidMax)}px)`,
15212
+ // Display variant sizes (1.5x for hero headings)
15213
+ ["--fs-h1-display"]: `${Math.round(h1 * 1.5)}px`,
15214
+ ["--fs-h1-display-fluid"]: `clamp(${Math.round(h1 * fluidMin * 1.5)}px, calc(${Math.round(h1 * fluidMin * 1.5)}px + ${Math.round(h1 * (fluidMax - fluidMin) * 1.5)} * ((100vw - 320px) / 880)), ${Math.round(h1 * fluidMax * 1.5)}px)`
14504
15215
  };
14505
15216
  }
15217
+ var SIZE_SCALE_MAP = {
15218
+ xs: 0.85,
15219
+ sm: 0.925,
15220
+ md: 1,
15221
+ lg: 1.1,
15222
+ xl: 1.2,
15223
+ "2xl": 1.35
15224
+ };
14506
15225
  function applyHeadingSizeOverrides(base, typography) {
14507
15226
  const body = base["--fs-body"];
14508
15227
  const h1Base = parseFloat(base["--fs-h1"].replace("px", ""));
14509
15228
  const h2Base = parseFloat(base["--fs-h2"].replace("px", ""));
14510
15229
  const h3Base = parseFloat(base["--fs-h3"].replace("px", ""));
14511
- const scaleMap = { md: 1, lg: 1.1, xl: 1.2 };
14512
- const h1Scale = typography.headings.h1.size ? scaleMap[typography.headings.h1.size] : 1;
14513
- const h2Scale = typography.headings.h2.size ? scaleMap[typography.headings.h2.size] : 1;
14514
- const h3Scale = typography.headings.h3.size ? scaleMap[typography.headings.h3.size] : 1;
15230
+ const h1Scale = typography.headings.h1.size ? SIZE_SCALE_MAP[typography.headings.h1.size] : 1;
15231
+ const h2Scale = typography.headings.h2.size ? SIZE_SCALE_MAP[typography.headings.h2.size] : 1;
15232
+ const h3Scale = typography.headings.h3.size ? SIZE_SCALE_MAP[typography.headings.h3.size] : 1;
15233
+ const h1 = Math.round(h1Base * h1Scale);
15234
+ const h2 = Math.round(h2Base * h2Scale);
15235
+ const h3 = Math.round(h3Base * h3Scale);
15236
+ const fluidMin = 0.7;
15237
+ const fluidMax = 1.3;
14515
15238
  return {
14516
15239
  body,
14517
- h1: `${Math.round(h1Base * h1Scale)}px`,
14518
- h2: `${Math.round(h2Base * h2Scale)}px`,
14519
- h3: `${Math.round(h3Base * h3Scale)}px`
15240
+ h1: `${h1}px`,
15241
+ h2: `${h2}px`,
15242
+ h3: `${h3}px`,
15243
+ // Fluid versions with size overrides applied
15244
+ h1Fluid: `clamp(${Math.round(h1 * fluidMin)}px, calc(${Math.round(h1 * fluidMin)}px + ${Math.round(h1 * (fluidMax - fluidMin))} * ((100vw - 320px) / 880)), ${Math.round(h1 * fluidMax)}px)`,
15245
+ h2Fluid: `clamp(${Math.round(h2 * fluidMin)}px, calc(${Math.round(h2 * fluidMin)}px + ${Math.round(h2 * (fluidMax - fluidMin))} * ((100vw - 320px) / 880)), ${Math.round(h2 * fluidMax)}px)`,
15246
+ h3Fluid: `clamp(${Math.round(h3 * fluidMin)}px, calc(${Math.round(h3 * fluidMin)}px + ${Math.round(h3 * (fluidMax - fluidMin))} * ((100vw - 320px) / 880)), ${Math.round(h3 * fluidMax)}px)`,
15247
+ // Display variant (1.5x scale for hero headings)
15248
+ h1Display: `${Math.round(h1 * 1.5)}px`,
15249
+ h1DisplayFluid: `clamp(${Math.round(h1 * 1.5 * fluidMin)}px, calc(${Math.round(h1 * 1.5 * fluidMin)}px + ${Math.round(h1 * 1.5 * (fluidMax - fluidMin))} * ((100vw - 320px) / 880)), ${Math.round(h1 * 1.5 * fluidMax)}px)`
14520
15250
  };
14521
15251
  }
14522
15252
  function mapLetterSpacing(s) {
@@ -14533,6 +15263,9 @@ function mapFontVariant(c) {
14533
15263
  if (c === "smallCaps") return "small-caps";
14534
15264
  return "normal";
14535
15265
  }
15266
+ function mapFontStyle(italic) {
15267
+ return italic ? "italic" : "normal";
15268
+ }
14536
15269
 
14537
15270
  // ../blocks/src/system/manifest/hydrateLinks.ts
14538
15271
  function hydrateManifestLinks(manifest, content, routes) {
@@ -14679,6 +15412,7 @@ function PageRenderer({
14679
15412
  blockOverrides,
14680
15413
  sdkConfig
14681
15414
  }) {
15415
+ setContextSupabaseUrl(dataContext?.supabaseUrl);
14682
15416
  if (!page || page.blocks.length === 0) {
14683
15417
  return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "p-6 text-sm", style: textColorStyle("mutedText"), children: "No blocks found." });
14684
15418
  }
@@ -14915,6 +15649,7 @@ function Page({
14915
15649
  usePlaceholders = false,
14916
15650
  blockOverrides,
14917
15651
  sdkConfig,
15652
+ supabaseUrl,
14918
15653
  dataContext
14919
15654
  }) {
14920
15655
  const baseTokens = providedTokens ?? buildThemeRuntime(theme).tokens;
@@ -14931,7 +15666,8 @@ function Page({
14931
15666
  resolvedData,
14932
15667
  routes: routeMap,
14933
15668
  occurrenceContext: dataContext?.occurrenceContext ?? null,
14934
- contentEntry: dataContext?.contentEntry ?? null
15669
+ contentEntry: dataContext?.contentEntry ?? null,
15670
+ supabaseUrl
14935
15671
  },
14936
15672
  routeMap,
14937
15673
  wrapBlock,
@@ -16397,6 +17133,15 @@ var ENDPOINT_DEFINITIONS = {
16397
17133
  auth: "public",
16398
17134
  responseKind: "json"
16399
17135
  },
17136
+ // Resolve event occurrence by URL segment (date or UUID)
17137
+ resolveEventOccurrence: {
17138
+ path: "/public/sites/{siteId}/events/occurrences/resolve",
17139
+ method: "GET",
17140
+ revalidate: 60,
17141
+ tags: ["public-events-{siteId}", "event-occurrence"],
17142
+ auth: "public",
17143
+ responseKind: "json"
17144
+ },
16400
17145
  // Public event registration
16401
17146
  registerForEvent: {
16402
17147
  path: "/public/sites/{siteId}/events/register",
@@ -16571,6 +17316,20 @@ if (typeof window === "undefined") {
16571
17316
  revalidateTag = null;
16572
17317
  }
16573
17318
  }
17319
+ var sdkVersion;
17320
+ function generateRequestId() {
17321
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
17322
+ return crypto.randomUUID();
17323
+ }
17324
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
17325
+ const r2 = Math.random() * 16 | 0;
17326
+ const v = c === "x" ? r2 : r2 & 3 | 8;
17327
+ return v.toString(16);
17328
+ });
17329
+ }
17330
+ function setSdkVersion(version2) {
17331
+ sdkVersion = version2;
17332
+ }
16574
17333
  var ApiRequestError = class extends Error {
16575
17334
  constructor(message, options) {
16576
17335
  super(message);
@@ -16582,6 +17341,7 @@ var ApiRequestError = class extends Error {
16582
17341
  this.requestId = options.requestId;
16583
17342
  this.body = options.body;
16584
17343
  this.cause = options.cause;
17344
+ this.errorCode = options.errorCode;
16585
17345
  }
16586
17346
  };
16587
17347
  function buildEndpointURL(baseURL, endpoint) {
@@ -16618,6 +17378,29 @@ async function parseErrorBody(response) {
16618
17378
  return null;
16619
17379
  }
16620
17380
  }
17381
+ function buildSuccessEnvelope(data, requestId) {
17382
+ return {
17383
+ success: true,
17384
+ data,
17385
+ meta: {
17386
+ requestId: requestId ?? generateRequestId(),
17387
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
17388
+ apiVersion: "2025-01-01"
17389
+ }
17390
+ };
17391
+ }
17392
+ function buildErrorEnvelope(code, message, status, requestId) {
17393
+ return {
17394
+ success: false,
17395
+ error: {
17396
+ code,
17397
+ message,
17398
+ requestId: requestId ?? generateRequestId(),
17399
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
17400
+ status
17401
+ }
17402
+ };
17403
+ }
16621
17404
  async function parseSuccessResponse(endpoint, response, config) {
16622
17405
  const responseKind = config.responseKind ?? "json";
16623
17406
  const auth = config.auth ?? "user";
@@ -16625,14 +17408,15 @@ async function parseSuccessResponse(endpoint, response, config) {
16625
17408
  switch (responseKind) {
16626
17409
  case "json": {
16627
17410
  if (response.status === 204 || response.status === 205 || response.status === 304) {
16628
- return void 0;
17411
+ return buildSuccessEnvelope(void 0, requestId);
16629
17412
  }
16630
17413
  const raw = await response.text();
16631
17414
  if (!raw.trim()) {
16632
- return void 0;
17415
+ return buildSuccessEnvelope(void 0, requestId);
16633
17416
  }
17417
+ let parsed;
16634
17418
  try {
16635
- return JSON.parse(raw);
17419
+ parsed = JSON.parse(raw);
16636
17420
  } catch (cause) {
16637
17421
  throw new ApiRequestError(
16638
17422
  `Failed to parse JSON response for endpoint ${String(endpoint)}`,
@@ -16647,32 +17431,33 @@ async function parseSuccessResponse(endpoint, response, config) {
16647
17431
  }
16648
17432
  );
16649
17433
  }
17434
+ if (parsed && typeof parsed === "object" && "success" in parsed && typeof parsed.success === "boolean") {
17435
+ return parsed;
17436
+ }
17437
+ return buildSuccessEnvelope(parsed, requestId);
16650
17438
  }
16651
17439
  case "text": {
16652
- return await response.text();
17440
+ const text2 = await response.text();
17441
+ return buildSuccessEnvelope(text2, requestId);
16653
17442
  }
16654
17443
  case "stream": {
16655
17444
  const body = response.body;
16656
17445
  if (!body) {
16657
- throw new ApiRequestError(
17446
+ return buildErrorEnvelope(
17447
+ "server:internal_error",
16658
17448
  `Expected a streamed body for endpoint ${String(endpoint)}`,
16659
- {
16660
- endpoint,
16661
- status: response.status,
16662
- method: config.method,
16663
- auth,
16664
- requestId
16665
- }
17449
+ response.status,
17450
+ requestId
16666
17451
  );
16667
17452
  }
16668
17453
  const stream = body;
16669
- return stream;
17454
+ return buildSuccessEnvelope(stream, requestId);
16670
17455
  }
16671
17456
  case "void": {
16672
- return void 0;
17457
+ return buildSuccessEnvelope(void 0, requestId);
16673
17458
  }
16674
17459
  default: {
16675
- return void 0;
17460
+ return buildSuccessEnvelope(void 0, requestId);
16676
17461
  }
16677
17462
  }
16678
17463
  }
@@ -16738,11 +17523,15 @@ function createRawCMSClient(headers = {}, baseUrl) {
16738
17523
  const requestInit = {
16739
17524
  method,
16740
17525
  ...options,
17526
+ // Include credentials for same-origin requests (sends cookies for auth)
17527
+ credentials: "same-origin",
16741
17528
  // Don't include body for GET/HEAD requests
16742
17529
  body: isGetOrHead ? void 0 : isFormData ? body : body ? JSON.stringify(body) : void 0,
16743
17530
  headers: {
16744
17531
  ...options.headers,
16745
17532
  ...headers,
17533
+ // Include SDK version if set
17534
+ ...sdkVersion && { "x-sdk-version": sdkVersion },
16746
17535
  // Don't set Content-Type for GET/HEAD requests without body
16747
17536
  ...isGetOrHead ? {} : isFormData ? {} : { "Content-Type": "application/json" }
16748
17537
  },
@@ -16796,94 +17585,30 @@ function createBearerAPIClient(token, baseUrl) {
16796
17585
  return createCMSClient(authHeaders, baseUrl);
16797
17586
  }
16798
17587
 
16799
- // ../api/src/aiPlayground.ts
16800
- var import_zod18 = require("zod");
16801
- var Rfc6902PatchOp = import_zod18.z.discriminatedUnion("op", [
16802
- // Standard RFC-6902 operations
16803
- import_zod18.z.object({
16804
- op: import_zod18.z.literal("add"),
16805
- path: import_zod18.z.string(),
16806
- value: import_zod18.z.unknown()
16807
- }),
16808
- import_zod18.z.object({
16809
- op: import_zod18.z.literal("remove"),
16810
- path: import_zod18.z.string()
16811
- }),
16812
- import_zod18.z.object({
16813
- op: import_zod18.z.literal("replace"),
16814
- path: import_zod18.z.string(),
16815
- value: import_zod18.z.unknown()
16816
- }),
16817
- import_zod18.z.object({
16818
- op: import_zod18.z.literal("move"),
16819
- from: import_zod18.z.string(),
16820
- path: import_zod18.z.string()
16821
- }),
16822
- import_zod18.z.object({
16823
- op: import_zod18.z.literal("copy"),
16824
- from: import_zod18.z.string(),
16825
- path: import_zod18.z.string()
16826
- }),
16827
- // Block-level operations (Phase 2)
16828
- import_zod18.z.object({
16829
- op: import_zod18.z.literal("add_block"),
16830
- blockKind: import_zod18.z.string(),
16831
- afterBlockId: import_zod18.z.string().nullable(),
16832
- content: import_zod18.z.record(import_zod18.z.string(), import_zod18.z.unknown()),
16833
- rationale: import_zod18.z.string()
16834
- }),
16835
- import_zod18.z.object({
16836
- op: import_zod18.z.literal("delete_block"),
16837
- blockId: import_zod18.z.string(),
16838
- rationale: import_zod18.z.string()
16839
- }),
16840
- import_zod18.z.object({
16841
- op: import_zod18.z.literal("reorder_block"),
16842
- blockId: import_zod18.z.string(),
16843
- afterBlockId: import_zod18.z.string().nullable(),
16844
- rationale: import_zod18.z.string()
16845
- })
16846
- ]);
16847
- var PatchEnvelope = import_zod18.z.object({
16848
- blockId: import_zod18.z.string(),
16849
- blockKind: import_zod18.z.string().optional(),
16850
- blockPurpose: import_zod18.z.string().optional().nullable(),
16851
- ops: import_zod18.z.array(Rfc6902PatchOp),
16852
- rationale: import_zod18.z.string(),
16853
- currentContent: import_zod18.z.record(import_zod18.z.string(), import_zod18.z.unknown()).optional()
16854
- });
16855
- var ContentUpdateResponse = import_zod18.z.object({
16856
- patches: import_zod18.z.array(PatchEnvelope),
16857
- assistantMessage: import_zod18.z.string()
16858
- });
16859
- var PlaygroundProposeRequest = import_zod18.z.object({
16860
- request: import_zod18.z.string().min(1).max(2e3)
16861
- });
16862
- var PlaygroundProposeResponse = import_zod18.z.object({
16863
- patches: import_zod18.z.array(PatchEnvelope),
16864
- assistantMessage: import_zod18.z.string(),
16865
- validation: import_zod18.z.object({
16866
- valid: import_zod18.z.boolean(),
16867
- issues: import_zod18.z.array(import_zod18.z.string()),
16868
- filtered: import_zod18.z.number()
16869
- })
16870
- });
16871
- var MultiPagePatchEnvelope = import_zod18.z.object({
16872
- pageId: import_zod18.z.string(),
16873
- blockId: import_zod18.z.string().optional(),
16874
- // Not present for page-level ops
16875
- blockKind: import_zod18.z.string().optional(),
16876
- blockPurpose: import_zod18.z.string().optional().nullable(),
16877
- ops: import_zod18.z.array(Rfc6902PatchOp),
16878
- rationale: import_zod18.z.string(),
16879
- currentContent: import_zod18.z.record(import_zod18.z.string(), import_zod18.z.unknown()).optional()
16880
- });
16881
- var MultiPageUpdateResponse = import_zod18.z.object({
16882
- patches: import_zod18.z.array(MultiPagePatchEnvelope),
16883
- assistantMessage: import_zod18.z.string(),
16884
- pagesModified: import_zod18.z.number(),
16885
- toolCallsUsed: import_zod18.z.number()
16886
- });
17588
+ // ../api/src/common/envelope.ts
17589
+ function isApiError(result) {
17590
+ return result.success === false;
17591
+ }
17592
+ function isApiSuccess(result) {
17593
+ return result.success === true;
17594
+ }
17595
+ var ApiEnvelopeError = class extends Error {
17596
+ constructor(error) {
17597
+ super(error.message);
17598
+ this.name = "ApiEnvelopeError";
17599
+ this.code = error.code;
17600
+ this.requestId = error.requestId;
17601
+ this.timestamp = error.timestamp;
17602
+ this.status = error.status;
17603
+ this.fieldErrors = error.fieldErrors;
17604
+ }
17605
+ };
17606
+ function unwrapResponse(result) {
17607
+ if (isApiSuccess(result)) {
17608
+ return result.data;
17609
+ }
17610
+ throw new ApiEnvelopeError(result.error);
17611
+ }
16887
17612
 
16888
17613
  // src/client/cache.ts
16889
17614
  var SimpleCache = class {
@@ -16921,7 +17646,100 @@ var SimpleCache = class {
16921
17646
  }
16922
17647
  };
16923
17648
 
17649
+ // src/version.ts
17650
+ var SDK_VERSION = "0.4.3";
17651
+
17652
+ // src/client/error.ts
17653
+ var RiverbankApiError = class _RiverbankApiError extends Error {
17654
+ constructor(apiError) {
17655
+ super(apiError.message);
17656
+ this.name = "RiverbankApiError";
17657
+ this.code = apiError.code;
17658
+ this.requestId = apiError.requestId;
17659
+ this.status = apiError.status;
17660
+ this.fieldErrors = apiError.fieldErrors;
17661
+ this.timestamp = apiError.timestamp;
17662
+ Object.setPrototypeOf(this, _RiverbankApiError.prototype);
17663
+ }
17664
+ /**
17665
+ * Check if this error matches a specific error code
17666
+ *
17667
+ * @example
17668
+ * ```ts
17669
+ * if (error.is('auth:unauthenticated')) {
17670
+ * // Redirect to login
17671
+ * }
17672
+ * ```
17673
+ */
17674
+ is(code) {
17675
+ return this.code === code;
17676
+ }
17677
+ /**
17678
+ * Check if this is an authentication or authorization error
17679
+ *
17680
+ * Matches: auth:unauthenticated, auth:token_expired, auth:token_invalid,
17681
+ * auth:forbidden, auth:mfa_required, auth:insufficient_permissions
17682
+ */
17683
+ isAuthError() {
17684
+ return this.code.startsWith("auth:");
17685
+ }
17686
+ /**
17687
+ * Check if this is a validation error
17688
+ *
17689
+ * Matches: validation:invalid_input, validation:missing_field, validation:invalid_format
17690
+ */
17691
+ isValidationError() {
17692
+ return this.code.startsWith("validation:");
17693
+ }
17694
+ /**
17695
+ * Check if this is a resource error (not found, conflict, etc.)
17696
+ *
17697
+ * Matches: resource:not_found, resource:already_exists, resource:conflict, resource:gone
17698
+ */
17699
+ isResourceError() {
17700
+ return this.code.startsWith("resource:");
17701
+ }
17702
+ /**
17703
+ * Check if this is a rate limiting error
17704
+ */
17705
+ isRateLimitError() {
17706
+ return this.code.startsWith("rate_limit:");
17707
+ }
17708
+ /**
17709
+ * Check if this is a billing/payment error
17710
+ */
17711
+ isBillingError() {
17712
+ return this.code.startsWith("billing:");
17713
+ }
17714
+ /**
17715
+ * Check if this is a server error
17716
+ */
17717
+ isServerError() {
17718
+ return this.code.startsWith("server:");
17719
+ }
17720
+ };
17721
+
16924
17722
  // src/client/index.ts
17723
+ setSdkVersion(SDK_VERSION);
17724
+ function convertToTypedError(error) {
17725
+ if (error instanceof ApiEnvelopeError) {
17726
+ throw new RiverbankApiError({
17727
+ code: error.code,
17728
+ message: error.message,
17729
+ requestId: error.requestId,
17730
+ timestamp: error.timestamp,
17731
+ status: error.status,
17732
+ fieldErrors: error.fieldErrors
17733
+ });
17734
+ }
17735
+ if (error instanceof ApiRequestError && error.body && typeof error.body === "object") {
17736
+ const body = error.body;
17737
+ if (isApiError(body)) {
17738
+ throw new RiverbankApiError(body.error);
17739
+ }
17740
+ }
17741
+ throw error;
17742
+ }
16925
17743
  function createRiverbankClient(config) {
16926
17744
  if (!config.baseUrl) {
16927
17745
  throw new Error(
@@ -16948,7 +17766,13 @@ function createRiverbankClient(config) {
16948
17766
  return cached;
16949
17767
  }
16950
17768
  }
16951
- const data = await fetcher();
17769
+ let data;
17770
+ try {
17771
+ const response = await fetcher();
17772
+ data = unwrapResponse(response);
17773
+ } catch (error) {
17774
+ convertToTypedError(error);
17775
+ }
16952
17776
  if (cacheEnabled) {
16953
17777
  cache.set(cacheKey, data);
16954
17778
  }
@@ -16983,33 +17807,27 @@ function createRiverbankClient(config) {
16983
17807
  const entryIdsCacheKey = mode === "manual" && entryIds?.length ? entryIds.join(",") : "";
16984
17808
  const cacheKey = `entries:${siteId}:${contentType}:${limit ?? ""}:${offset ?? ""}:${order ?? ""}:${preview}:${mode ?? ""}:${entryIdsCacheKey}:${includeMeta ?? ""}`;
16985
17809
  return cachedFetch(cacheKey, async () => {
16986
- const apiParams = {
16987
- siteId,
16988
- type: contentType
16989
- };
16990
- if (typeof limit === "number") {
16991
- apiParams.limit = String(limit);
16992
- }
16993
- if (typeof offset === "number") {
16994
- apiParams.offset = String(offset);
16995
- }
16996
- if (includeMeta) {
16997
- apiParams.meta = "true";
16998
- }
17810
+ let orderParam;
16999
17811
  if (order === "newest") {
17000
- apiParams.order = "published_at.desc";
17812
+ orderParam = "published_at.desc";
17001
17813
  } else if (order === "oldest") {
17002
- apiParams.order = "published_at.asc";
17814
+ orderParam = "published_at.asc";
17003
17815
  } else if (order === "title") {
17004
- apiParams.order = "title.asc";
17005
- }
17006
- if (preview) {
17007
- apiParams.stage = "preview";
17008
- }
17009
- if (mode === "manual" && entryIds?.length) {
17010
- apiParams.mode = "manual";
17011
- apiParams.entryIds = JSON.stringify(entryIds);
17816
+ orderParam = "title.asc";
17012
17817
  }
17818
+ const apiParams = {
17819
+ siteId,
17820
+ type: contentType,
17821
+ ...typeof limit === "number" && { limit: String(limit) },
17822
+ ...typeof offset === "number" && { offset: String(offset) },
17823
+ ...includeMeta && { meta: "true" },
17824
+ ...orderParam && { order: orderParam },
17825
+ ...preview && { stage: "preview" },
17826
+ ...mode === "manual" && entryIds?.length && {
17827
+ mode: "manual",
17828
+ entryIds: JSON.stringify(entryIds)
17829
+ }
17830
+ };
17013
17831
  return await apiClient({ endpoint: "listPublishedEntries", params: apiParams });
17014
17832
  });
17015
17833
  },
@@ -17037,8 +17855,10 @@ function createRiverbankClient(config) {
17037
17855
  }
17038
17856
  const cacheKey = `public-booking-services:${siteId}:${ids ?? ""}`;
17039
17857
  return cachedFetch(cacheKey, async () => {
17040
- const apiParams = { siteId };
17041
- if (ids) apiParams.ids = ids;
17858
+ const apiParams = {
17859
+ siteId,
17860
+ ...ids && { ids }
17861
+ };
17042
17862
  return await apiClient({ endpoint: "getPublicBookingServices", params: apiParams });
17043
17863
  });
17044
17864
  },
@@ -17049,14 +17869,42 @@ function createRiverbankClient(config) {
17049
17869
  }
17050
17870
  const cacheKey = `public-events:${siteId}:${limit ?? ""}:${from ?? ""}:${to ?? ""}:${stage ?? ""}`;
17051
17871
  return cachedFetch(cacheKey, async () => {
17052
- const apiParams = { siteId };
17053
- if (typeof limit === "number") apiParams.limit = String(limit);
17054
- if (from) apiParams.from = from;
17055
- if (to) apiParams.to = to;
17056
- if (stage) apiParams.stage = stage;
17872
+ const apiParams = {
17873
+ siteId,
17874
+ ...typeof limit === "number" && { limit: String(limit) },
17875
+ ...from && { from },
17876
+ ...to && { to },
17877
+ ...stage && { stage }
17878
+ };
17057
17879
  return await apiClient({ endpoint: "listPublicEvents", params: apiParams });
17058
17880
  });
17059
17881
  },
17882
+ async resolveEventOccurrence(params) {
17883
+ const { siteId, entryId, segment } = params;
17884
+ if (!siteId || !entryId || !segment) {
17885
+ throw new Error("resolveEventOccurrence() requires siteId, entryId, and segment");
17886
+ }
17887
+ const cacheKey = `event-occurrence:${siteId}:${entryId}:${segment}`;
17888
+ return cachedFetch(cacheKey, async () => {
17889
+ return await apiClient({
17890
+ endpoint: "resolveEventOccurrence",
17891
+ params: { siteId, entryId, segment }
17892
+ });
17893
+ });
17894
+ },
17895
+ async checkRedirect(params) {
17896
+ const { siteId, path } = params;
17897
+ if (!siteId || !path) {
17898
+ throw new Error("checkRedirect() requires siteId and path");
17899
+ }
17900
+ const cacheKey = `redirect:${siteId}:${path}`;
17901
+ return cachedFetch(cacheKey, async () => {
17902
+ return await apiClient({
17903
+ endpoint: "checkRedirect",
17904
+ params: { site: siteId, path }
17905
+ });
17906
+ });
17907
+ },
17060
17908
  clearCache() {
17061
17909
  cache.clear();
17062
17910
  }