@riverbankcms/sdk 0.4.3 → 0.5.1

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 (178) hide show
  1. package/README.md +84 -0
  2. package/dist/cli/index.js +3463 -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 +1379 -519
  15. package/dist/client/client.js.map +1 -1
  16. package/dist/client/client.mjs +1379 -519
  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 +20 -14
  25. package/dist/client/rendering/client.js.map +1 -1
  26. package/dist/client/rendering/client.mjs +20 -14
  27. package/dist/client/rendering/client.mjs.map +1 -1
  28. package/dist/client/usePage-BTPnCuWC.d.mts +6511 -0
  29. package/dist/client/usePage-BXjk8BhD.d.mts +6704 -0
  30. package/dist/client/usePage-BafOS9UT.d.mts +6512 -0
  31. package/dist/client/usePage-BiOReg0_.d.ts +6704 -0
  32. package/dist/client/usePage-Bnx-kA6x.d.mts +6670 -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-CXI_VkhN.d.ts → Layout-BClXUTsd.d.mts} +4 -4
  37. package/dist/server/{Layout-p6f3TLw9.d.mts → Layout-UXGjXv8M.d.ts} +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-5STV4MWD.js +189 -0
  41. package/dist/server/chunk-5STV4MWD.js.map +1 -0
  42. package/dist/server/{chunk-VHDDXCK6.js → chunk-7UPVCT3K.js} +1206 -496
  43. package/dist/server/chunk-7UPVCT3K.js.map +1 -0
  44. package/dist/server/{chunk-7DS4Q3GA.mjs → chunk-AEFWG657.mjs} +3 -3
  45. package/dist/server/chunk-AEFWG657.mjs.map +1 -0
  46. package/dist/server/{chunk-USQF2XTU.mjs → chunk-BYBJA6SP.mjs} +26 -11
  47. package/dist/server/chunk-BYBJA6SP.mjs.map +1 -0
  48. package/dist/server/{chunk-ES6QDZUX.mjs → chunk-C6FIJC7T.mjs} +2 -2
  49. package/dist/server/{chunk-N3PX76AP.mjs → chunk-CMABGYGI.mjs} +269 -135
  50. package/dist/server/chunk-CMABGYGI.mjs.map +1 -0
  51. package/dist/server/{chunk-TO7FD6TQ.js → chunk-I2D7KOEA.js} +4 -4
  52. package/dist/server/{chunk-TO7FD6TQ.js.map → chunk-I2D7KOEA.js.map} +1 -1
  53. package/dist/server/{chunk-R5B6IOFQ.js → chunk-KA74YRK6.js} +269 -135
  54. package/dist/server/chunk-KA74YRK6.js.map +1 -0
  55. package/dist/server/chunk-KFLZGNPO.mjs +189 -0
  56. package/dist/server/chunk-KFLZGNPO.mjs.map +1 -0
  57. package/dist/server/chunk-L5EA4FXU.mjs +134 -0
  58. package/dist/server/chunk-L5EA4FXU.mjs.map +1 -0
  59. package/dist/server/{chunk-U2NI3TS3.mjs → chunk-LNOUXALA.mjs} +1135 -425
  60. package/dist/server/chunk-LNOUXALA.mjs.map +1 -0
  61. package/dist/server/{chunk-24F6FTCI.mjs → chunk-OSF34JTQ.mjs} +4 -4
  62. package/dist/server/{chunk-G35R7N7B.js → chunk-P3NNN73G.js} +3 -3
  63. package/dist/server/{chunk-G35R7N7B.js.map → chunk-P3NNN73G.js.map} +1 -1
  64. package/dist/server/{chunk-I6K5REFT.mjs → chunk-P4K63SBZ.mjs} +24 -4
  65. package/dist/server/chunk-P4K63SBZ.mjs.map +1 -0
  66. package/dist/server/{chunk-HOY77YBF.js → chunk-RVDS7VSP.js} +5 -5
  67. package/dist/server/chunk-RVDS7VSP.js.map +1 -0
  68. package/dist/server/{chunk-2SSEBAHC.js → chunk-TT5JWA4X.js} +9 -9
  69. package/dist/server/{chunk-2SSEBAHC.js.map → chunk-TT5JWA4X.js.map} +1 -1
  70. package/dist/server/chunk-VSFQRHYZ.js +134 -0
  71. package/dist/server/chunk-VSFQRHYZ.js.map +1 -0
  72. package/dist/server/{chunk-EGTDJ4PL.js → chunk-YYO3RIFO.js} +26 -11
  73. package/dist/server/chunk-YYO3RIFO.js.map +1 -0
  74. package/dist/server/{chunk-OP2GHK27.mjs → chunk-Z5ZA6Q4D.mjs} +2 -2
  75. package/dist/server/{components-Dhiemsjd.d.ts → components-BmaJxgCV.d.mts} +20 -75
  76. package/dist/server/{components-C75e4poV.d.mts → components-DppHY5oD.d.ts} +20 -75
  77. package/dist/server/components.d.mts +11 -8
  78. package/dist/server/components.d.ts +11 -8
  79. package/dist/server/components.js +5 -4
  80. package/dist/server/components.js.map +1 -1
  81. package/dist/server/components.mjs +4 -3
  82. package/dist/server/config-validation.d.mts +3 -3
  83. package/dist/server/config-validation.d.ts +3 -3
  84. package/dist/server/config-validation.js +9 -5
  85. package/dist/server/config-validation.js.map +1 -1
  86. package/dist/server/config-validation.mjs +8 -4
  87. package/dist/server/config.d.mts +243 -5
  88. package/dist/server/config.d.ts +243 -5
  89. package/dist/server/config.js +72 -5
  90. package/dist/server/config.js.map +1 -1
  91. package/dist/server/config.mjs +72 -5
  92. package/dist/server/config.mjs.map +1 -1
  93. package/dist/server/core-DsNWrl3o.d.mts +44 -0
  94. package/dist/server/core-DsNWrl3o.d.ts +44 -0
  95. package/dist/server/data.d.mts +4 -3
  96. package/dist/server/data.d.ts +4 -3
  97. package/dist/server/data.js +3 -3
  98. package/dist/server/data.mjs +2 -2
  99. package/dist/server/{index-CAwBj3-A.d.ts → index-Bucs6UqG.d.mts} +2 -1
  100. package/dist/server/{index-C6o9LPvq.d.mts → index-Cp7tJuRt.d.ts} +2 -1
  101. package/dist/server/index.d.mts +84 -6
  102. package/dist/server/index.d.ts +84 -6
  103. package/dist/server/index.js +91 -2
  104. package/dist/server/index.js.map +1 -1
  105. package/dist/server/index.mjs +90 -1
  106. package/dist/server/index.mjs.map +1 -1
  107. package/dist/server/link-DjxLyC82.d.mts +23 -0
  108. package/dist/server/link-DjxLyC82.d.ts +23 -0
  109. package/dist/server/{loadContent-CdXfuCuE.d.mts → loadContent-BS-3wesN.d.mts} +4 -4
  110. package/dist/server/{loadContent-CsvQRoxb.d.ts → loadContent-Buvmudee.d.ts} +4 -4
  111. package/dist/server/{loadPage-p3AWwwrd.d.mts → loadPage-B8mQUUSo.d.mts} +5 -46
  112. package/dist/server/loadPage-DNQTTRHL.mjs +11 -0
  113. package/dist/server/{loadPage-BA0HiT-6.d.ts → loadPage-DP3nrHBi.d.ts} +5 -46
  114. package/dist/server/loadPage-IDGVDFBB.js +11 -0
  115. package/dist/server/{loadPage-DLC7DJZP.js.map → loadPage-IDGVDFBB.js.map} +1 -1
  116. package/dist/server/metadata.d.mts +6 -4
  117. package/dist/server/metadata.d.ts +6 -4
  118. package/dist/server/navigation.d.mts +199 -29
  119. package/dist/server/navigation.d.ts +199 -29
  120. package/dist/server/navigation.js +27 -43
  121. package/dist/server/navigation.js.map +1 -1
  122. package/dist/server/navigation.mjs +20 -36
  123. package/dist/server/navigation.mjs.map +1 -1
  124. package/dist/server/rendering/server.d.mts +8 -6
  125. package/dist/server/rendering/server.d.ts +8 -6
  126. package/dist/server/rendering/server.js +7 -6
  127. package/dist/server/rendering/server.js.map +1 -1
  128. package/dist/server/rendering/server.mjs +6 -5
  129. package/dist/server/rendering.d.mts +14 -10
  130. package/dist/server/rendering.d.ts +14 -10
  131. package/dist/server/rendering.js +9 -8
  132. package/dist/server/rendering.js.map +1 -1
  133. package/dist/server/rendering.mjs +8 -7
  134. package/dist/server/richTextSchema-DURiozvD.d.mts +62 -0
  135. package/dist/server/richTextSchema-DURiozvD.d.ts +62 -0
  136. package/dist/server/routing.d.mts +178 -11
  137. package/dist/server/routing.d.ts +178 -11
  138. package/dist/server/routing.js +95 -2
  139. package/dist/server/routing.js.map +1 -1
  140. package/dist/server/routing.mjs +94 -1
  141. package/dist/server/routing.mjs.map +1 -1
  142. package/dist/server/{schema-Bpy9N5ZI.d.mts → schema-Z6-afHJG.d.mts} +1 -1
  143. package/dist/server/{schema-Bpy9N5ZI.d.ts → schema-Z6-afHJG.d.ts} +1 -1
  144. package/dist/server/server.d.mts +9 -7
  145. package/dist/server/server.d.ts +9 -7
  146. package/dist/server/server.js +6 -6
  147. package/dist/server/server.mjs +5 -5
  148. package/dist/server/theme-bridge.js +8 -8
  149. package/dist/server/theme-bridge.mjs +2 -2
  150. package/dist/server/{types-Dj8B3QRb.d.ts → types-1cLz0vnq.d.mts} +55 -2
  151. package/dist/server/{types-txWsSxN7.d.mts → types-BjgZt8xJ.d.mts} +63 -2
  152. package/dist/server/{types-CdhKJrB0.d.mts → types-BvcJU7zk.d.ts} +55 -2
  153. package/dist/server/{types-BWQ-TohG.d.ts → types-CVykEqXN.d.ts} +289 -83
  154. package/dist/server/{types-CL916r6x.d.ts → types-DLBhEPSt.d.ts} +63 -2
  155. package/dist/server/{types-BLf-hE50.d.mts → types-Dsu9wsUh.d.mts} +289 -83
  156. package/dist/server/{validation-DzvDwwRo.d.mts → validation-BGuRo8P1.d.mts} +18 -5
  157. package/dist/server/{validation-CoU8uAiu.d.ts → validation-DU2YE7u5.d.ts} +18 -5
  158. package/package.json +5 -1
  159. package/dist/server/chunk-6JBKKV3G.js.map +0 -1
  160. package/dist/server/chunk-7DS4Q3GA.mjs.map +0 -1
  161. package/dist/server/chunk-EGTDJ4PL.js.map +0 -1
  162. package/dist/server/chunk-HOY77YBF.js.map +0 -1
  163. package/dist/server/chunk-I6K5REFT.mjs.map +0 -1
  164. package/dist/server/chunk-LCYGQDAB.mjs +0 -835
  165. package/dist/server/chunk-LCYGQDAB.mjs.map +0 -1
  166. package/dist/server/chunk-N3PX76AP.mjs.map +0 -1
  167. package/dist/server/chunk-R5B6IOFQ.js.map +0 -1
  168. package/dist/server/chunk-TNYU5EIO.js +0 -835
  169. package/dist/server/chunk-TNYU5EIO.js.map +0 -1
  170. package/dist/server/chunk-U2NI3TS3.mjs.map +0 -1
  171. package/dist/server/chunk-USQF2XTU.mjs.map +0 -1
  172. package/dist/server/chunk-VHDDXCK6.js.map +0 -1
  173. package/dist/server/loadPage-DLC7DJZP.js +0 -11
  174. package/dist/server/loadPage-GEGN4UAL.mjs +0 -11
  175. /package/dist/server/{chunk-ES6QDZUX.mjs.map → chunk-C6FIJC7T.mjs.map} +0 -0
  176. /package/dist/server/{chunk-24F6FTCI.mjs.map → chunk-OSF34JTQ.mjs.map} +0 -0
  177. /package/dist/server/{chunk-OP2GHK27.mjs.map → chunk-Z5ZA6Q4D.mjs.map} +0 -0
  178. /package/dist/server/{loadPage-GEGN4UAL.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
  };
@@ -7506,7 +7525,7 @@ var COLUMN_CLASSES = {
7506
7525
  "4": "sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4"
7507
7526
  };
7508
7527
  function formatDateForUrl(isoTimestamp) {
7509
- return isoTimestamp.split("T")[0];
7528
+ return isoTimestamp.split("T")[0] ?? "";
7510
7529
  }
7511
7530
  function buildEventUrl(basePath, slug, startsAt) {
7512
7531
  const date = formatDateForUrl(startsAt);
@@ -7691,7 +7710,7 @@ function getContainerClass(layout, columns) {
7691
7710
  return `grid gap-6 ${COLUMN_CLASSES2[columns] || COLUMN_CLASSES2["3"]}`;
7692
7711
  }
7693
7712
  function formatDateForUrl2(isoTimestamp) {
7694
- return isoTimestamp.split("T")[0];
7713
+ return isoTimestamp.split("T")[0] ?? "";
7695
7714
  }
7696
7715
  function buildEventUrl2(basePath, slug, startsAt) {
7697
7716
  const date = formatDateForUrl2(startsAt);
@@ -7910,7 +7929,7 @@ function extractSegmentsFromPart(part) {
7910
7929
  if (!part) return [];
7911
7930
  const segments = [];
7912
7931
  const baseMatch = part.match(/^([^\[]+)/);
7913
- if (baseMatch) {
7932
+ if (baseMatch && baseMatch[1]) {
7914
7933
  segments.push(baseMatch[1]);
7915
7934
  }
7916
7935
  const bracketMatches = Array.from(part.matchAll(BRACKET_ACCESS_REGEX));
@@ -8876,8 +8895,8 @@ function getLabWhitePoint() {
8876
8895
  var lab2rgb = (...args) => {
8877
8896
  args = unpack_default(args, "lab");
8878
8897
  const [L, a, b] = args;
8879
- const [x, y, z19] = lab2xyz(L, a, b);
8880
- 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);
8881
8900
  return [r2, g, b_, args.length > 3 ? args[3] : 1];
8882
8901
  };
8883
8902
  var lab2xyz = (L, a, b) => {
@@ -8892,15 +8911,15 @@ var lab2xyz = (L, a, b) => {
8892
8911
  const zr = fz3 > kE ? fz3 : (116 * fz - 16) / kK;
8893
8912
  const x = xr * Xn;
8894
8913
  const y = yr * Yn;
8895
- const z19 = zr * Zn;
8896
- return [x, y, z19];
8914
+ const z20 = zr * Zn;
8915
+ return [x, y, z20];
8897
8916
  };
8898
8917
  var compand = (linear) => {
8899
8918
  const sign = Math.sign(linear);
8900
8919
  linear = Math.abs(linear);
8901
8920
  return (linear <= 31308e-7 ? linear * 12.92 : 1.055 * Math.pow(linear, 1 / 2.4) - 0.055) * sign;
8902
8921
  };
8903
- var xyz2rgb = (x, y, z19) => {
8922
+ var xyz2rgb = (x, y, z20) => {
8904
8923
  const { MtxAdaptMa, MtxAdaptMaI, MtxXYZ2RGB, RefWhiteRGB, Xn, Yn, Zn } = lab_constants_default;
8905
8924
  const As = Xn * MtxAdaptMa.m00 + Yn * MtxAdaptMa.m10 + Zn * MtxAdaptMa.m20;
8906
8925
  const Bs = Xn * MtxAdaptMa.m01 + Yn * MtxAdaptMa.m11 + Zn * MtxAdaptMa.m21;
@@ -8908,9 +8927,9 @@ var xyz2rgb = (x, y, z19) => {
8908
8927
  const Ad = RefWhiteRGB.X * MtxAdaptMa.m00 + RefWhiteRGB.Y * MtxAdaptMa.m10 + RefWhiteRGB.Z * MtxAdaptMa.m20;
8909
8928
  const Bd = RefWhiteRGB.X * MtxAdaptMa.m01 + RefWhiteRGB.Y * MtxAdaptMa.m11 + RefWhiteRGB.Z * MtxAdaptMa.m21;
8910
8929
  const Cd = RefWhiteRGB.X * MtxAdaptMa.m02 + RefWhiteRGB.Y * MtxAdaptMa.m12 + RefWhiteRGB.Z * MtxAdaptMa.m22;
8911
- const X1 = (x * MtxAdaptMa.m00 + y * MtxAdaptMa.m10 + z19 * MtxAdaptMa.m20) * (Ad / As);
8912
- const Y1 = (x * MtxAdaptMa.m01 + y * MtxAdaptMa.m11 + z19 * MtxAdaptMa.m21) * (Bd / Bs);
8913
- 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);
8914
8933
  const X2 = X1 * MtxAdaptMaI.m00 + Y1 * MtxAdaptMaI.m10 + Z1 * MtxAdaptMaI.m20;
8915
8934
  const Y2 = X1 * MtxAdaptMaI.m01 + Y1 * MtxAdaptMaI.m11 + Z1 * MtxAdaptMaI.m21;
8916
8935
  const Z2 = X1 * MtxAdaptMaI.m02 + Y1 * MtxAdaptMaI.m12 + Z1 * MtxAdaptMaI.m22;
@@ -8930,15 +8949,15 @@ var lab2rgb_default = lab2rgb;
8930
8949
  // ../../node_modules/.pnpm/chroma-js@3.1.2/node_modules/chroma-js/src/io/lab/rgb2lab.js
8931
8950
  var rgb2lab = (...args) => {
8932
8951
  const [r2, g, b, ...rest] = unpack_default(args, "rgb");
8933
- const [x, y, z19] = rgb2xyz(r2, g, b);
8934
- 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);
8935
8954
  return [L, a, b_, ...rest.length > 0 && rest[0] < 1 ? [rest[0]] : []];
8936
8955
  };
8937
- function xyz2lab(x, y, z19) {
8956
+ function xyz2lab(x, y, z20) {
8938
8957
  const { Xn, Yn, Zn, kE, kK } = lab_constants_default;
8939
8958
  const xr = x / Xn;
8940
8959
  const yr = y / Yn;
8941
- const zr = z19 / Zn;
8960
+ const zr = z20 / Zn;
8942
8961
  const fx = xr > kE ? Math.pow(xr, 1 / 3) : (kK * xr + 16) / 116;
8943
8962
  const fy = yr > kE ? Math.pow(yr, 1 / 3) : (kK * yr + 16) / 116;
8944
8963
  const fz = zr > kE ? Math.pow(zr, 1 / 3) : (kK * zr + 16) / 116;
@@ -8957,20 +8976,20 @@ var rgb2xyz = (r2, g, b) => {
8957
8976
  const { MtxRGB2XYZ, MtxAdaptMa, MtxAdaptMaI, Xn, Yn, Zn, As, Bs, Cs } = lab_constants_default;
8958
8977
  let x = r2 * MtxRGB2XYZ.m00 + g * MtxRGB2XYZ.m10 + b * MtxRGB2XYZ.m20;
8959
8978
  let y = r2 * MtxRGB2XYZ.m01 + g * MtxRGB2XYZ.m11 + b * MtxRGB2XYZ.m21;
8960
- let z19 = r2 * MtxRGB2XYZ.m02 + g * MtxRGB2XYZ.m12 + b * MtxRGB2XYZ.m22;
8979
+ let z20 = r2 * MtxRGB2XYZ.m02 + g * MtxRGB2XYZ.m12 + b * MtxRGB2XYZ.m22;
8961
8980
  const Ad = Xn * MtxAdaptMa.m00 + Yn * MtxAdaptMa.m10 + Zn * MtxAdaptMa.m20;
8962
8981
  const Bd = Xn * MtxAdaptMa.m01 + Yn * MtxAdaptMa.m11 + Zn * MtxAdaptMa.m21;
8963
8982
  const Cd = Xn * MtxAdaptMa.m02 + Yn * MtxAdaptMa.m12 + Zn * MtxAdaptMa.m22;
8964
- let X = x * MtxAdaptMa.m00 + y * MtxAdaptMa.m10 + z19 * MtxAdaptMa.m20;
8965
- let Y = x * MtxAdaptMa.m01 + y * MtxAdaptMa.m11 + z19 * MtxAdaptMa.m21;
8966
- 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;
8967
8986
  X *= Ad / As;
8968
8987
  Y *= Bd / Bs;
8969
8988
  Z *= Cd / Cs;
8970
8989
  x = X * MtxAdaptMaI.m00 + Y * MtxAdaptMaI.m10 + Z * MtxAdaptMaI.m20;
8971
8990
  y = X * MtxAdaptMaI.m01 + Y * MtxAdaptMaI.m11 + Z * MtxAdaptMaI.m21;
8972
- z19 = X * MtxAdaptMaI.m02 + Y * MtxAdaptMaI.m12 + Z * MtxAdaptMaI.m22;
8973
- return [x, y, z19];
8991
+ z20 = X * MtxAdaptMaI.m02 + Y * MtxAdaptMaI.m12 + Z * MtxAdaptMaI.m22;
8992
+ return [x, y, z20];
8974
8993
  };
8975
8994
  var rgb2lab_default = rgb2lab;
8976
8995
 
@@ -11299,7 +11318,7 @@ function generateShades(hexColor, name) {
11299
11318
  900: 0.1,
11300
11319
  950: 0.05
11301
11320
  };
11302
- const lightness = lightnessMap[shadeNumber];
11321
+ const lightness = lightnessMap[shadeNumber] ?? 0.5;
11303
11322
  const shadeColor = base.luminance(lightness).hex();
11304
11323
  return {
11305
11324
  name: shadeName,
@@ -11370,7 +11389,7 @@ function expandPalette(palette) {
11370
11389
  if (base.text) expanded.body = base.text;
11371
11390
  const isDark = base.background ? isBackgroundDark(base.background) : false;
11372
11391
  const isDarkMode = palette.meta?.mode === "dark" || isDark;
11373
- expanded.mutedText = isDarkMode ? expanded["neutral-600"] : expanded["neutral-500"];
11392
+ expanded.mutedText = isDarkMode ? expanded["neutral-600"] ?? "#666" : expanded["neutral-500"] ?? "#888";
11374
11393
  return expanded;
11375
11394
  }
11376
11395
 
@@ -11438,6 +11457,83 @@ function generateShadowCssVars(theme) {
11438
11457
  };
11439
11458
  }
11440
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
+
11441
11537
  // ../blocks/src/theme/buttons/effects/presets/background.ts
11442
11538
  var darkenBackgroundEffect = {
11443
11539
  id: "darken-background",
@@ -11445,6 +11541,7 @@ var darkenBackgroundEffect = {
11445
11541
  description: "Darkens the background color on hover",
11446
11542
  category: "background",
11447
11543
  pseudoElement: "none",
11544
+ applicableTo: ["button"],
11448
11545
  customizableOption: {
11449
11546
  name: "amount",
11450
11547
  type: "number",
@@ -11476,6 +11573,7 @@ var lightenBackgroundEffect = {
11476
11573
  description: "Lightens the background color on hover",
11477
11574
  category: "background",
11478
11575
  pseudoElement: "none",
11576
+ applicableTo: ["button"],
11479
11577
  customizableOption: {
11480
11578
  name: "amount",
11481
11579
  type: "number",
@@ -11507,6 +11605,7 @@ var fadeBackgroundEffect = {
11507
11605
  description: "Reduces background opacity on hover",
11508
11606
  category: "background",
11509
11607
  pseudoElement: "none",
11608
+ applicableTo: ["button", "nav-link"],
11510
11609
  customizableOption: {
11511
11610
  name: "opacity",
11512
11611
  type: "percentage",
@@ -11529,6 +11628,7 @@ var opacityReduceEffect = {
11529
11628
  description: "Reduces button opacity on hover by a percentage",
11530
11629
  category: "background",
11531
11630
  pseudoElement: "none",
11631
+ applicableTo: ["button", "nav-link"],
11532
11632
  customizableOption: {
11533
11633
  name: "reduction",
11534
11634
  type: "percentage",
@@ -11552,6 +11652,7 @@ var animatedGradientEffect = {
11552
11652
  description: "Animates gradient position on hover",
11553
11653
  category: "background",
11554
11654
  pseudoElement: "none",
11655
+ applicableTo: ["button"],
11555
11656
  customizableOption: {
11556
11657
  name: "direction",
11557
11658
  type: "select",
@@ -11591,6 +11692,7 @@ var backgroundOnHoverEffect = {
11591
11692
  description: "Adds background color on hover",
11592
11693
  category: "background",
11593
11694
  pseudoElement: "none",
11695
+ applicableTo: ["button", "nav-link"],
11594
11696
  customizableOption: {
11595
11697
  name: "colorToken",
11596
11698
  type: "select",
@@ -11616,6 +11718,7 @@ var backgroundOnHoverAlphaEffect = {
11616
11718
  description: "Adds semi-transparent background on hover",
11617
11719
  category: "background",
11618
11720
  pseudoElement: "none",
11721
+ applicableTo: ["button", "nav-link"],
11619
11722
  customizableOption: {
11620
11723
  name: "opacity",
11621
11724
  type: "percentage",
@@ -11637,6 +11740,33 @@ var backgroundOnHoverAlphaEffect = {
11637
11740
  }
11638
11741
  };
11639
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
+
11640
11770
  // ../blocks/src/theme/buttons/effects/presets/shadow.ts
11641
11771
  var borderGlowEffect = {
11642
11772
  id: "border-glow",
@@ -11644,6 +11774,7 @@ var borderGlowEffect = {
11644
11774
  description: "Adds a glowing shadow on hover",
11645
11775
  category: "shadow",
11646
11776
  pseudoElement: "none",
11777
+ applicableTo: ["button", "nav-link"],
11647
11778
  customizableOption: {
11648
11779
  name: "glowColorToken",
11649
11780
  type: "colorToken",
@@ -11654,11 +11785,7 @@ var borderGlowEffect = {
11654
11785
  const { themeId, variantId, options, tokens } = ctx;
11655
11786
  const glowToken = options.glowColorToken || "primary-400";
11656
11787
  const glowColor = tokens.getColor(glowToken);
11657
- return `
11658
- :where([data-theme-scope="${themeId}"]) .${variantId}:hover {
11659
- box-shadow: 0 0 15px ${glowColor};
11660
- }
11661
- `;
11788
+ return generateStateCSS(themeId, variantId, "hover", `box-shadow: 0 0 15px ${glowColor};`);
11662
11789
  }
11663
11790
  };
11664
11791
  var dropShadowEffect = {
@@ -11667,6 +11794,7 @@ var dropShadowEffect = {
11667
11794
  description: "Adds an elevated shadow on hover",
11668
11795
  category: "shadow",
11669
11796
  pseudoElement: "none",
11797
+ applicableTo: ["button"],
11670
11798
  customizableOption: {
11671
11799
  name: "intensity",
11672
11800
  type: "select",
@@ -11682,11 +11810,7 @@ var dropShadowEffect = {
11682
11810
  medium: "0 10px 15px rgba(0, 0, 0, 0.15)",
11683
11811
  strong: "0 20px 25px rgba(0, 0, 0, 0.2)"
11684
11812
  };
11685
- return `
11686
- :where([data-theme-scope="${themeId}"]) .${variantId}:hover {
11687
- box-shadow: ${shadows[intensity]};
11688
- }
11689
- `;
11813
+ return generateStateCSS(themeId, variantId, "hover", `box-shadow: ${shadows[intensity]};`);
11690
11814
  }
11691
11815
  };
11692
11816
  var innerShadowEffect = {
@@ -11695,6 +11819,7 @@ var innerShadowEffect = {
11695
11819
  description: "Adds an inset shadow for a pressed appearance",
11696
11820
  category: "shadow",
11697
11821
  pseudoElement: "none",
11822
+ applicableTo: ["button"],
11698
11823
  generateCSS: (ctx) => {
11699
11824
  const { themeId, variantId } = ctx;
11700
11825
  return `
@@ -11710,6 +11835,7 @@ var neumorphicShadowEffect = {
11710
11835
  description: "Dual shadows for soft UI design (raised or pressed)",
11711
11836
  category: "shadow",
11712
11837
  pseudoElement: "none",
11838
+ applicableTo: ["button", "nav-link"],
11713
11839
  customizableOption: {
11714
11840
  name: "mode",
11715
11841
  type: "select",
@@ -11752,6 +11878,7 @@ var outerGlowEffect = {
11752
11878
  description: "Creates an outer glow around the button",
11753
11879
  category: "shadow",
11754
11880
  pseudoElement: "none",
11881
+ applicableTo: ["button", "nav-link"],
11755
11882
  customizableOption: {
11756
11883
  name: "spread",
11757
11884
  type: "number",
@@ -11786,6 +11913,7 @@ var retro3DShadowEffect = {
11786
11913
  description: "3D pressed shadow with vertical movement (retro style)",
11787
11914
  category: "shadow",
11788
11915
  pseudoElement: "none",
11916
+ applicableTo: ["button"],
11789
11917
  generateCSS: (ctx) => {
11790
11918
  const { themeId, variantId } = ctx;
11791
11919
  return `
@@ -11818,6 +11946,7 @@ var scaleUpEffect = {
11818
11946
  description: "Slightly enlarges the button on hover",
11819
11947
  category: "transform",
11820
11948
  pseudoElement: "none",
11949
+ applicableTo: ["button", "nav-link"],
11821
11950
  customizableOption: {
11822
11951
  name: "scale",
11823
11952
  type: "select",
@@ -11828,11 +11957,7 @@ var scaleUpEffect = {
11828
11957
  generateCSS: (ctx) => {
11829
11958
  const { themeId, variantId, options } = ctx;
11830
11959
  const scale = options.scale || "1.05";
11831
- return `
11832
- :where([data-theme-scope="${themeId}"]) .${variantId}:hover {
11833
- transform: scale(${scale});
11834
- }
11835
- `;
11960
+ return generateStateCSS(themeId, variantId, "hover", `transform: scale(${scale});`);
11836
11961
  }
11837
11962
  };
11838
11963
  var scaleDownEffect = {
@@ -11841,6 +11966,7 @@ var scaleDownEffect = {
11841
11966
  description: "Slightly shrinks the button when clicked",
11842
11967
  category: "transform",
11843
11968
  pseudoElement: "none",
11969
+ applicableTo: ["button", "nav-link"],
11844
11970
  customizableOption: {
11845
11971
  name: "scale",
11846
11972
  type: "select",
@@ -11864,6 +11990,7 @@ var liftEffect = {
11864
11990
  description: "Lifts the button upward on hover",
11865
11991
  category: "transform",
11866
11992
  pseudoElement: "none",
11993
+ applicableTo: ["button", "nav-link"],
11867
11994
  customizableOption: {
11868
11995
  name: "amount",
11869
11996
  type: "select",
@@ -11874,11 +12001,7 @@ var liftEffect = {
11874
12001
  generateCSS: (ctx) => {
11875
12002
  const { themeId, variantId, options } = ctx;
11876
12003
  const amount = options.amount || "0.5";
11877
- return `
11878
- :where([data-theme-scope="${themeId}"]) .${variantId}:hover {
11879
- transform: translateY(-${amount}rem);
11880
- }
11881
- `;
12004
+ return generateStateCSS(themeId, variantId, "hover", `transform: translateY(-${amount}rem);`);
11882
12005
  }
11883
12006
  };
11884
12007
  var pressDownEffect = {
@@ -11887,6 +12010,7 @@ var pressDownEffect = {
11887
12010
  description: "Translates button to shadow position and removes shadow on hover",
11888
12011
  category: "transform",
11889
12012
  pseudoElement: "none",
12013
+ applicableTo: ["button"],
11890
12014
  generateCSS: (ctx) => {
11891
12015
  const { themeId, variantId, theme } = ctx;
11892
12016
  const shadowConfig = theme.shadow;
@@ -11899,12 +12023,12 @@ var pressDownEffect = {
11899
12023
  const offset = elevationOffsets[shadowConfig.elevation];
11900
12024
  const xOffset = (shadowConfig.position || "bottom") === "bottom-right" ? offset : 0;
11901
12025
  const yOffset = offset;
11902
- return `
11903
- :where([data-theme-scope="${themeId}"]) .${variantId}:hover {
11904
- transform: translate(${xOffset}px, ${yOffset}px);
11905
- box-shadow: none;
11906
- }
11907
- `;
12026
+ return generateStateCSS(
12027
+ themeId,
12028
+ variantId,
12029
+ "hover",
12030
+ `transform: translate(${xOffset}px, ${yOffset}px); box-shadow: none;`
12031
+ );
11908
12032
  }
11909
12033
  };
11910
12034
  var popEffect = {
@@ -11913,6 +12037,7 @@ var popEffect = {
11913
12037
  description: "Scales up and tilts the button on hover for a playful pop effect",
11914
12038
  category: "transform",
11915
12039
  pseudoElement: "none",
12040
+ applicableTo: ["button"],
11916
12041
  customizableOption: {
11917
12042
  name: "intensity",
11918
12043
  type: "select",
@@ -11929,11 +12054,12 @@ var popEffect = {
11929
12054
  dramatic: { scale: 1.08, rotate: 3 }
11930
12055
  };
11931
12056
  const config = intensityConfig[intensity] || intensityConfig.medium;
11932
- return `
11933
- :where([data-theme-scope="${themeId}"]) .${variantId}:hover {
11934
- transform: scale(${config.scale}) rotate(${config.rotate}deg);
11935
- }
11936
- `;
12057
+ return generateStateCSS(
12058
+ themeId,
12059
+ variantId,
12060
+ "hover",
12061
+ `transform: scale(${config.scale}) rotate(${config.rotate}deg);`
12062
+ );
11937
12063
  }
11938
12064
  };
11939
12065
 
@@ -11944,6 +12070,7 @@ var auroraGlowEffect = {
11944
12070
  description: "Blurred gradient glow that appears on hover",
11945
12071
  category: "overlay",
11946
12072
  pseudoElement: "before",
12073
+ applicableTo: ["button"],
11947
12074
  customizableOption: {
11948
12075
  name: "intensity",
11949
12076
  type: "percentage",
@@ -11956,8 +12083,8 @@ var auroraGlowEffect = {
11956
12083
  let toColor;
11957
12084
  if (buttonConfig.background.type === "gradient") {
11958
12085
  const stops = buttonConfig.background.stops;
11959
- fromColor = tokens.getColor(stops[0]);
11960
- 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");
11961
12088
  } else if (buttonConfig.background.type === "solid") {
11962
12089
  fromColor = tokens.getColor(buttonConfig.background.colorToken);
11963
12090
  const lighterToken = tokens.adjustShade(buttonConfig.background.colorToken, -200);
@@ -12000,6 +12127,7 @@ var cosmicStardustEffect = {
12000
12127
  description: "Rotating rainbow gradient glow (always visible, intensifies on hover)",
12001
12128
  category: "overlay",
12002
12129
  pseudoElement: "before",
12130
+ applicableTo: ["button"],
12003
12131
  customizableOption: {
12004
12132
  name: "speed",
12005
12133
  type: "select",
@@ -12062,6 +12190,7 @@ var gradientBorderFillEffect = {
12062
12190
  description: "Gradient border that fills on hover using ::before pseudo-element",
12063
12191
  category: "overlay",
12064
12192
  pseudoElement: "before",
12193
+ applicableTo: ["button"],
12065
12194
  customizableOption: {
12066
12195
  name: "borderWidth",
12067
12196
  type: "number",
@@ -12118,6 +12247,7 @@ var animatedGradientBorderFillEffect = {
12118
12247
  description: "Rotating gradient border that fills on hover",
12119
12248
  category: "overlay",
12120
12249
  pseudoElement: "before",
12250
+ applicableTo: ["button"],
12121
12251
  customizableOption: {
12122
12252
  name: "speed",
12123
12253
  type: "select",
@@ -12193,6 +12323,7 @@ var borderBottomGrowEffect = {
12193
12323
  description: "Animated underline that grows on hover",
12194
12324
  category: "overlay",
12195
12325
  pseudoElement: "after",
12326
+ applicableTo: ["button", "nav-link"],
12196
12327
  customizableOption: {
12197
12328
  name: "height",
12198
12329
  type: "number",
@@ -12240,6 +12371,7 @@ var gradientTextEffect = {
12240
12371
  description: "Gradient text using background-clip",
12241
12372
  category: "text",
12242
12373
  pseudoElement: "none",
12374
+ applicableTo: ["button"],
12243
12375
  customizableOption: {
12244
12376
  name: "solidOnHover",
12245
12377
  type: "select",
@@ -12291,6 +12423,7 @@ var textColorChangeEffect = {
12291
12423
  description: "Changes text color on hover",
12292
12424
  category: "text",
12293
12425
  pseudoElement: "none",
12426
+ applicableTo: ["button", "nav-link"],
12294
12427
  customizableOption: {
12295
12428
  name: "hoverColorToken",
12296
12429
  type: "select",
@@ -12318,6 +12451,7 @@ var borderColorChangeEffect = {
12318
12451
  description: "Changes border color on hover",
12319
12452
  category: "border",
12320
12453
  pseudoElement: "none",
12454
+ applicableTo: ["button", "nav-link"],
12321
12455
  customizableOption: {
12322
12456
  name: "hoverColorToken",
12323
12457
  type: "select",
@@ -12343,6 +12477,7 @@ var sketchyBorderEffect = {
12343
12477
  description: "Hand-drawn style with imperfect edges",
12344
12478
  category: "border",
12345
12479
  pseudoElement: "none",
12480
+ applicableTo: ["button"],
12346
12481
  customizableOption: {
12347
12482
  name: "intensity",
12348
12483
  type: "select",
@@ -12390,6 +12525,7 @@ var pulseAnimationEffect = {
12390
12525
  description: "Continuous pulse animation (opacity fade)",
12391
12526
  category: "animation",
12392
12527
  pseudoElement: "none",
12528
+ applicableTo: ["button", "nav-link"],
12393
12529
  customizableOption: {
12394
12530
  name: "speed",
12395
12531
  type: "select",
@@ -12418,6 +12554,138 @@ var pulseAnimationEffect = {
12418
12554
  }
12419
12555
  };
12420
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
+
12421
12689
  // ../blocks/src/theme/buttons/effects/registry.ts
12422
12690
  var EFFECT_PRESETS = [
12423
12691
  // Background effects
@@ -12454,88 +12722,65 @@ var EFFECT_PRESETS = [
12454
12722
  borderColorChangeEffect,
12455
12723
  sketchyBorderEffect,
12456
12724
  // Animation effects
12457
- pulseAnimationEffect
12725
+ pulseAnimationEffect,
12726
+ // Nav-link specific effects
12727
+ navUnderlineEffect,
12728
+ navFrostedBaseEffect,
12729
+ navFrostedHoverEffect,
12730
+ navFrostedActiveEffect
12458
12731
  ];
12459
12732
  function getEffectPreset(id) {
12460
12733
  return EFFECT_PRESETS.find((preset) => preset.id === id);
12461
12734
  }
12462
12735
 
12463
- // ../blocks/src/theme/tokens/resolver.ts
12464
- var TokenResolver = class {
12465
- constructor(theme) {
12466
- this.theme = theme;
12467
- }
12468
- /**
12469
- * Resolve a color token to a CSS variable reference wrapped in rgb()
12470
- *
12471
- * @param token - Token name (e.g., 'primary-500', 'white', 'text-900')
12472
- * @returns CSS rgb() function with var reference (e.g., 'rgb(var(--tb-primary-500))')
12473
- *
12474
- * Note: CSS variables are stored as RGB channels (e.g., "37 99 235") following Tailwind convention,
12475
- * so we must wrap them with rgb() to create a valid color value.
12476
- *
12477
- * @example
12478
- * resolver.getColor('primary-500') // => 'rgb(var(--tb-primary-500))'
12479
- * resolver.getColor('white') // => 'rgb(var(--tb-white))'
12480
- */
12481
- getColor(token) {
12482
- if (!this.tokenExists(token)) {
12483
- console.warn(
12484
- `[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
12485
12758
  );
12759
+ if (css2) {
12760
+ cssChunks.push(css2);
12761
+ }
12486
12762
  }
12487
- return `rgb(var(--tb-${token}))`;
12488
12763
  }
12489
- /**
12490
- * Adjust a color token's shade by a given amount
12491
- *
12492
- * @param token - Base token (e.g., 'primary-500')
12493
- * @param amount - Shade adjustment (+100 = darker, -100 = lighter)
12494
- * @returns Adjusted token name (e.g., 'primary-600')
12495
- *
12496
- * @example
12497
- * resolver.adjustShade('primary-500', 100) // => 'primary-600' (darker)
12498
- * resolver.adjustShade('primary-500', -100) // => 'primary-400' (lighter)
12499
- */
12500
- adjustShade(token, amount) {
12501
- const parts = token.split("-");
12502
- if (parts.length < 2) {
12503
- const newShade2 = Math.max(100, Math.min(900, 500 + amount));
12504
- return `${token}-${newShade2}`;
12505
- }
12506
- const base = parts.slice(0, -1).join("-");
12507
- const shade = parseInt(parts[parts.length - 1], 10);
12508
- if (isNaN(shade)) {
12509
- console.warn(
12510
- `[TokenResolver] Cannot adjust shade for non-shade token "${token}". Returning original token.`
12511
- );
12512
- return token;
12513
- }
12514
- const newShade = Math.max(100, Math.min(900, shade + amount));
12515
- 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 "";
12516
12771
  }
12517
- /**
12518
- * Check if a token exists in the theme palette
12519
- *
12520
- * @param token - Token name to check
12521
- * @returns True if token exists in theme
12522
- */
12523
- tokenExists(token) {
12524
- const commonTokens = ["white", "black", "transparent"];
12525
- if (commonTokens.includes(token)) {
12526
- return true;
12527
- }
12528
- const parts = token.split("-");
12529
- if (parts.length >= 2) {
12530
- const lastPart = parts[parts.length - 1];
12531
- const shade = parseInt(lastPart, 10);
12532
- if (!isNaN(shade) && shade >= 100 && shade <= 900 && shade % 100 === 0) {
12533
- return true;
12534
- }
12535
- }
12536
- return true;
12537
- }
12538
- };
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
+ }
12539
12784
 
12540
12785
  // ../blocks/src/theme/buttons/constants.ts
12541
12786
  var GRADIENT_DIRECTION_MAP = {
@@ -12594,6 +12839,11 @@ var FONT_SIZE_MAP = {
12594
12839
  "text-xl": "1.25rem",
12595
12840
  "text-2xl": "1.5rem"
12596
12841
  };
12842
+ var BUTTON_PADDING_PRESETS = {
12843
+ compact: "0.375rem 0.75rem",
12844
+ default: "0.5rem 1rem",
12845
+ spacious: "0.75rem 1.5rem"
12846
+ };
12597
12847
 
12598
12848
  // ../blocks/src/theme/buttons/utils/contrast.ts
12599
12849
  function getContrastingTextColorToken(backgroundToken, theme) {
@@ -12603,7 +12853,7 @@ function getContrastingTextColorToken(backgroundToken, theme) {
12603
12853
  }
12604
12854
  if (backgroundToken.startsWith("neutral-")) {
12605
12855
  const match = backgroundToken.match(/neutral-(\d+)/);
12606
- if (match) {
12856
+ if (match?.[1]) {
12607
12857
  const shade = parseInt(match[1], 10);
12608
12858
  return shade >= 500 ? "neutral-50" : "neutral-950";
12609
12859
  }
@@ -12612,16 +12862,6 @@ function getContrastingTextColorToken(backgroundToken, theme) {
12612
12862
  }
12613
12863
 
12614
12864
  // ../blocks/src/theme/buttons/generateDefaultButtonSystem.ts
12615
- var CORNERS_TO_RADIUS_MAP = {
12616
- square: "rounded-none",
12617
- // 0px - sharp corners
12618
- soft: "rounded-md",
12619
- // 6px - subtle rounding
12620
- rounded: "rounded-md",
12621
- // 6px - standard rounded (same as soft for buttons)
12622
- pill: "rounded-full"
12623
- // 9999px - full pill shape
12624
- };
12625
12865
  var BORDER_WIDTH_TO_CLASS_MAP = {
12626
12866
  none: "border-0",
12627
12867
  // 0px
@@ -12633,7 +12873,6 @@ var BORDER_WIDTH_TO_CLASS_MAP = {
12633
12873
  // 4px - clearly thick
12634
12874
  };
12635
12875
  function generateDefaultButtonSystem(theme) {
12636
- const borderRadius = CORNERS_TO_RADIUS_MAP[theme.corners] || "rounded-lg";
12637
12876
  const borderWidthClass = BORDER_WIDTH_TO_CLASS_MAP[theme.border.width] || "border-2";
12638
12877
  const variants = [];
12639
12878
  const primaryVariant = {
@@ -12643,10 +12882,11 @@ function generateDefaultButtonSystem(theme) {
12643
12882
  priority: 1,
12644
12883
  background: {
12645
12884
  type: "solid",
12646
- colorToken: "primary-500"
12885
+ colorToken: "primary"
12647
12886
  },
12648
- textColorToken: getContrastingTextColorToken("primary-500", theme),
12649
- borderRadius,
12887
+ textColorToken: getContrastingTextColorToken("primary", theme),
12888
+ borderRadius: "",
12889
+ // Empty string = inherit from global.cornerStyle
12650
12890
  // Inherits shadow from theme
12651
12891
  effects: {
12652
12892
  hover: [
@@ -12668,7 +12908,8 @@ function generateDefaultButtonSystem(theme) {
12668
12908
  colorToken: "neutral-700"
12669
12909
  },
12670
12910
  textColorToken: getContrastingTextColorToken("neutral-700", theme),
12671
- borderRadius,
12911
+ borderRadius: "",
12912
+ // Empty string = inherit from global.cornerStyle
12672
12913
  // Inherits shadow from theme
12673
12914
  effects: {
12674
12915
  hover: [
@@ -12688,12 +12929,13 @@ function generateDefaultButtonSystem(theme) {
12688
12929
  background: {
12689
12930
  type: "transparent"
12690
12931
  },
12691
- textColorToken: "primary-600",
12692
- borderRadius,
12932
+ textColorToken: "primary",
12933
+ borderRadius: "",
12934
+ // Empty string = inherit from global.cornerStyle
12693
12935
  shadow: { elevation: "none", softness: null, position: "bottom" },
12694
12936
  // Outline buttons typically don't have shadows
12695
12937
  border: {
12696
- colorToken: "primary-500",
12938
+ colorToken: "primary",
12697
12939
  widthClass: borderWidthClass
12698
12940
  },
12699
12941
  effects: {
@@ -12714,8 +12956,9 @@ function generateDefaultButtonSystem(theme) {
12714
12956
  background: {
12715
12957
  type: "transparent"
12716
12958
  },
12717
- textColorToken: "primary-600",
12718
- borderRadius,
12959
+ textColorToken: "primary",
12960
+ borderRadius: "",
12961
+ // Empty string = inherit from global.cornerStyle
12719
12962
  shadow: { elevation: "none", softness: null, position: "bottom" },
12720
12963
  // Ghost buttons have no shadow
12721
12964
  // No border for ghost buttons
@@ -12781,6 +13024,10 @@ function generateButtonCss(options) {
12781
13024
  if (!variant.enabled) continue;
12782
13025
  const baseCSS = generateVariantBaseCSS(variant, buttonSystem.global, themeId, tokens, theme);
12783
13026
  cssChunks.push(baseCSS);
13027
+ const hoverBgCSS = generateHoverBackgroundCSS(variant, buttonSystem.global, themeId, tokens);
13028
+ if (hoverBgCSS) {
13029
+ cssChunks.push(hoverBgCSS);
13030
+ }
12784
13031
  const effectCSS = generateVariantEffectCSS(variant, themeId, tokens, theme);
12785
13032
  if (effectCSS) {
12786
13033
  cssChunks.push(effectCSS);
@@ -12799,7 +13046,7 @@ function generateVariantBaseCSS(variant, global, themeId, tokens, theme) {
12799
13046
  const rules = [];
12800
13047
  const borderWidth = variant.border ? BORDER_WIDTH_MAP[variant.border.widthClass] || "1px" : "0px";
12801
13048
  const hasBorder = borderWidth !== "0px";
12802
- 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;
12803
13050
  const paddingParts = padding.split(" ");
12804
13051
  const verticalPadding = paddingParts[0] || "0.5rem";
12805
13052
  const horizontalPadding = paddingParts[1] || paddingParts[0] || "1rem";
@@ -12812,6 +13059,15 @@ function generateVariantBaseCSS(variant, global, themeId, tokens, theme) {
12812
13059
  rules.push(`padding: ${padding};`);
12813
13060
  }
12814
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
+ }
12815
13071
  if (variant.fontSize) {
12816
13072
  const fontSize = FONT_SIZE_MAP[variant.fontSize] || "1rem";
12817
13073
  rules.push(`font-size: ${fontSize};`);
@@ -12825,16 +13081,16 @@ function generateVariantBaseCSS(variant, global, themeId, tokens, theme) {
12825
13081
  rules.push(`align-items: ${STRUCTURAL_BASE_STYLES.alignItems};`);
12826
13082
  rules.push(`justify-content: ${STRUCTURAL_BASE_STYLES.justifyContent};`);
12827
13083
  let borderRadius;
12828
- if (variant.borderRadius) {
12829
- 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";
12830
13086
  } else {
12831
13087
  const cornerStyleMap = {
12832
13088
  "square": "rounded-none",
12833
13089
  "rounded": "rounded-md",
12834
13090
  "pill": "rounded-full"
12835
13091
  };
12836
- const fallbackRadius = cornerStyleMap[global.cornerStyle] || "rounded-md";
12837
- 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";
12838
13094
  }
12839
13095
  rules.push(`border-radius: ${borderRadius};`);
12840
13096
  const shadowConfig = variant.shadow || shadowSizeToShadow(global.shadow, theme) || theme.shadow;
@@ -12870,31 +13126,33 @@ ${selector} {
12870
13126
  }
12871
13127
  function generateVariantEffectCSS(variant, themeId, tokens, theme) {
12872
13128
  if (!variant.effects) return "";
12873
- const cssChunks = [];
12874
- for (const [stateGroup, effectApps] of Object.entries(variant.effects)) {
12875
- if (!effectApps || effectApps.length === 0) continue;
12876
- for (const effectApp of effectApps) {
12877
- const effectPreset = getEffectPreset(effectApp.effectId);
12878
- if (!effectPreset) {
12879
- console.warn(`[generateVariantEffectCSS] Unknown effect: ${effectApp.effectId}`);
12880
- continue;
12881
- }
12882
- const ctx = {
12883
- themeId,
12884
- variantId: variant.id,
12885
- stateGroup,
12886
- options: effectApp.options || {},
12887
- buttonConfig: variant,
12888
- tokens,
12889
- theme
12890
- };
12891
- const css2 = effectPreset.generateCSS(ctx);
12892
- if (css2) {
12893
- cssChunks.push(css2);
12894
- }
12895
- }
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;
12896
13147
  }
12897
- 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();
12898
13156
  }
12899
13157
  function generateDisabledCSS(variant, themeId) {
12900
13158
  const selector = `:where([data-theme-scope="${themeId}"]) .${variant.id}:disabled`;
@@ -13787,6 +14045,345 @@ function generateDefaultInputSystem(theme) {
13787
14045
  };
13788
14046
  }
13789
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
+
13790
14387
  // ../blocks/src/theme/header/generateHeaderCss.ts
13791
14388
  function generateHeaderCss(options) {
13792
14389
  const { themeId, theme } = options;
@@ -13794,10 +14391,8 @@ function generateHeaderCss(options) {
13794
14391
  const header = theme.header;
13795
14392
  const cssChunks = [];
13796
14393
  cssChunks.push(generateHeaderRootStyles(header, themeId, tokens, theme));
13797
- if (header.logo) {
13798
- cssChunks.push(generateLogoStyles(header.logo, themeId, tokens));
13799
- }
13800
- cssChunks.push(generateNavLinkStyles(header, themeId, tokens));
14394
+ cssChunks.push(generateLogoStyles(header.logo, themeId, tokens, header.textColor));
14395
+ cssChunks.push(generateNavLinkStyles(header, themeId, tokens, theme));
13801
14396
  if (header.variant === "floating" && header.container) {
13802
14397
  cssChunks.push(generateFloatingContainerStyles(header.container, themeId, tokens));
13803
14398
  }
@@ -13853,32 +14448,36 @@ ${selector} {
13853
14448
  }
13854
14449
  `;
13855
14450
  }
13856
- function generateLogoStyles(logo, themeId, tokens) {
13857
- if (!logo) return "";
14451
+ function generateLogoStyles(logo, themeId, tokens, textColor) {
13858
14452
  const selector = `:where([data-theme-scope="${themeId}"]) .header-logo-text`;
13859
14453
  const rules = [];
13860
14454
  const primaryColor = tokens.getColor("primary");
13861
14455
  const accentColor = tokens.getColor("accent");
13862
- if (logo.fontFamily === "mono") {
13863
- rules.push(`font-family: ui-monospace, monospace;`);
13864
- } else if (logo.fontFamily === "serif") {
13865
- rules.push(`font-family: ui-serif, serif;`);
13866
- }
13867
- if (logo.letterSpacing && logo.letterSpacing !== "normal") {
13868
- const spacingMap = {
13869
- "normal": "0em",
13870
- "wide": "0.05em",
13871
- "wider": "0.1em",
13872
- "widest": "0.15em"
13873
- };
13874
- rules.push(`letter-spacing: ${spacingMap[logo.letterSpacing]};`);
13875
- }
13876
- if (logo.gradient) {
13877
- rules.push(`background: linear-gradient(to right, ${primaryColor}, ${accentColor});`);
13878
- rules.push(`-webkit-background-clip: text;`);
13879
- rules.push(`-webkit-text-fill-color: transparent;`);
13880
- rules.push(`background-clip: text;`);
13881
- 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
+ }
13882
14481
  }
13883
14482
  if (rules.length === 0) return "";
13884
14483
  return `
@@ -13887,129 +14486,82 @@ ${selector} {
13887
14486
  }
13888
14487
  `;
13889
14488
  }
13890
- function generateNavLinkStyles(header, themeId, tokens) {
13891
- const selector = `:where([data-theme-scope="${themeId}"]) .header-nav-link`;
13892
- const hoverSelector = `${selector}:hover`;
13893
- const activeSelector = `${selector}[data-active="true"]`;
13894
- const cssChunks = [];
13895
- const baseRules = [];
13896
- const hoverRules = [];
13897
- const activeRules = [];
13898
- const navContainerType = header.navContainer?.type ?? "none";
13899
- const usesGlassNavContainer = navContainerType === "glass";
13900
- const navColorToken = header.navColor?.trim();
13901
- const primaryColor = tokens.getColor("primary");
13902
- const navWeight = header.navWeight ?? "medium";
13903
- const navWeightMap = {
13904
- regular: 400,
13905
- medium: 500,
13906
- semibold: 600,
13907
- bold: 700
13908
- };
13909
- if (navColorToken) {
13910
- baseRules.push(`color: ${tokens.getColor(navColorToken)};`);
13911
- }
13912
- if (navWeight) {
13913
- baseRules.push(`font-weight: ${navWeightMap[navWeight]};`);
13914
- }
13915
- if (navWeight === "bold" && header.navStyle === "solid") {
13916
- baseRules.push(`text-transform: uppercase;`);
13917
- }
13918
- switch (header.navStyle) {
13919
- case "minimal":
13920
- baseRules.push(`transition: color 200ms ease;`);
13921
- hoverRules.push(`color: ${primaryColor};`);
13922
- activeRules.push(`color: ${primaryColor};`);
13923
- break;
13924
- case "underline":
13925
- baseRules.push(`transition: all 200ms ease;`);
13926
- hoverRules.push(`text-decoration: underline;`);
13927
- hoverRules.push(`text-underline-offset: 4px;`);
13928
- activeRules.push(`text-decoration: underline;`);
13929
- activeRules.push(`text-underline-offset: 4px;`);
13930
- break;
13931
- case "underline-grow":
13932
- baseRules.push(`position: relative;`);
13933
- baseRules.push(`transition: color 200ms ease;`);
13934
- hoverRules.push(`color: ${primaryColor};`);
13935
- activeRules.push(`color: ${primaryColor};`);
13936
- cssChunks.push(generateUnderlineGrowCSS(themeId));
13937
- break;
13938
- case "capsule":
13939
- baseRules.push(`border-radius: 9999px;`);
13940
- baseRules.push(`transition: background-color 200ms ease;`);
13941
- hoverRules.push(`background-color: color-mix(in srgb, ${primaryColor} 10%, transparent);`);
13942
- activeRules.push(`background-color: color-mix(in srgb, ${primaryColor} 15%, transparent);`);
13943
- break;
13944
- case "solid":
13945
- baseRules.push(`border-radius: 0;`);
13946
- baseRules.push(`transition: background-color 200ms ease, color 200ms ease;`);
13947
- hoverRules.push(`background-color: ${primaryColor};`);
13948
- if (navColorToken) {
13949
- hoverRules.push(`color: ${tokens.getColor(navColorToken)};`);
13950
- }
13951
- activeRules.push(`background-color: ${primaryColor};`);
13952
- if (navColorToken) {
13953
- activeRules.push(`color: ${tokens.getColor(navColorToken)};`);
13954
- }
13955
- break;
13956
- case "scale":
13957
- baseRules.push(`transition: all 200ms ease;`);
13958
- hoverRules.push(`transform: scale(1.05);`);
13959
- break;
13960
- case "frosted":
13961
- baseRules.push(`border-radius: 0.5rem;`);
13962
- baseRules.push(`background-color: rgb(255 255 255 / 0.1);`);
13963
- baseRules.push(`backdrop-filter: blur(8px);`);
13964
- baseRules.push(`transition: background-color 200ms ease;`);
13965
- hoverRules.push(`background-color: rgb(255 255 255 / 0.2);`);
13966
- activeRules.push(`background-color: rgb(255 255 255 / 0.25);`);
13967
- 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
+ });
13968
14498
  }
13969
- if (usesGlassNavContainer && header.navStyle === "minimal") {
13970
- baseRules.push(`border-radius: 9999px;`);
13971
- hoverRules.push(`background-color: rgba(255, 255, 255, 0.1);`);
13972
- activeRules.push(`background-color: rgba(255, 255, 255, 0.18);`);
13973
- hoverRules.push(`color: #fff;`);
13974
- 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";
13975
14513
  }
13976
14514
  if (header.navEffects) {
14515
+ mergedStyle.effects = {
14516
+ ...mergedStyle.effects,
14517
+ hover: [...mergedStyle.effects?.hover || []],
14518
+ active: [...mergedStyle.effects?.active || []]
14519
+ };
13977
14520
  if (header.navEffects.glow) {
13978
- hoverRules.push(`filter: drop-shadow(0 0 5px currentColor);`);
14521
+ mergedStyle.effects.hover.push({
14522
+ effectId: "outer-glow",
14523
+ options: { spread: 5 }
14524
+ });
13979
14525
  }
13980
14526
  if (header.navEffects.neumorphic) {
13981
- console.log("[generateHeaderCss] Generating neumorphic styles for theme:", themeId);
13982
- baseRules.push(`transition: all 200ms ease;`);
13983
- baseRules.push(`border-radius: 0.5rem;`);
13984
- hoverRules.push(`box-shadow: inset 4px 4px 8px #c7c7c7, inset -4px -4px 8px #ffffff;`);
13985
- 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
+ });
13986
14535
  }
13987
14536
  if (header.navEffects.underlineGradient) {
13988
- cssChunks.push(generateGradientUnderlineCSS(themeId, tokens));
14537
+ mergedStyle.effects.hover.push({
14538
+ effectId: "border-bottom-grow",
14539
+ options: { origin: "center" }
14540
+ });
13989
14541
  }
13990
14542
  }
13991
- if (baseRules.length > 0) {
13992
- cssChunks.push(`
13993
- ${selector} {
13994
- ${baseRules.join("\n ")}
13995
- }
13996
- `);
13997
- }
13998
- if (hoverRules.length > 0) {
13999
- cssChunks.push(`
14000
- ${hoverSelector} {
14001
- ${hoverRules.join("\n ")}
14002
- }
14003
- `);
14004
- }
14005
- if (activeRules.length > 0) {
14006
- cssChunks.push(`
14007
- ${activeSelector} {
14008
- ${activeRules.join("\n ")}
14009
- }
14010
- `);
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
+ };
14011
14557
  }
14012
- return cssChunks.join("");
14558
+ return generateNavLinkCSS({
14559
+ themeId,
14560
+ tokens,
14561
+ theme,
14562
+ style: mergedStyle,
14563
+ className: "header-nav-link"
14564
+ });
14013
14565
  }
14014
14566
  function generateNavContainerStyles(header, themeId, tokens) {
14015
14567
  const navContainer = header.navContainer;
@@ -14046,52 +14598,6 @@ function generateNavContainerStyles(header, themeId, tokens) {
14046
14598
  }
14047
14599
  return "";
14048
14600
  }
14049
- function generateGradientUnderlineCSS(themeId, tokens) {
14050
- const selector = `:where([data-theme-scope="${themeId}"]) .header-nav-link`;
14051
- const primaryColor = tokens.getColor("primary");
14052
- const accentColor = tokens.getColor("accent");
14053
- return `
14054
- ${selector}::after {
14055
- content: '';
14056
- position: absolute;
14057
- bottom: 0;
14058
- left: 0;
14059
- width: 100%;
14060
- height: 2px;
14061
- background: linear-gradient(to right, ${primaryColor}, ${accentColor});
14062
- transform: scaleX(0);
14063
- transform-origin: center;
14064
- transition: transform 0.3s ease;
14065
- }
14066
-
14067
- ${selector}:hover::after,
14068
- ${selector}[data-active="true"]::after {
14069
- transform: scaleX(1);
14070
- }
14071
- `.trim();
14072
- }
14073
- function generateUnderlineGrowCSS(themeId) {
14074
- const selector = `:where([data-theme-scope="${themeId}"]) .header-nav-link`;
14075
- return `
14076
- ${selector}::after {
14077
- content: '';
14078
- position: absolute;
14079
- bottom: 0;
14080
- left: 0;
14081
- width: 100%;
14082
- height: 2px;
14083
- background: currentColor;
14084
- transform: scaleX(0);
14085
- transform-origin: center;
14086
- transition: transform 0.3s ease;
14087
- }
14088
-
14089
- ${selector}:hover::after,
14090
- ${selector}[data-active="true"]::after {
14091
- transform: scaleX(1);
14092
- }
14093
- `.trim();
14094
- }
14095
14601
  function generateFloatingContainerStyles(container, themeId, tokens) {
14096
14602
  if (!container) return "";
14097
14603
  const selector = `:where([data-theme-scope="${themeId}"]) .header-floating-container`;
@@ -14148,12 +14654,52 @@ function applyAlpha(color, opacity) {
14148
14654
  const clamped = clampOpacity(opacity, 1);
14149
14655
  if (color.startsWith("rgb(") && color.endsWith(")")) {
14150
14656
  const inner = color.slice(4, -1).trim();
14151
- const channels = inner.includes("/") ? inner.split("/")[0].trim() : inner;
14657
+ const channels = inner.includes("/") ? (inner.split("/")[0] ?? inner).trim() : inner;
14152
14658
  return `rgb(${channels} / ${clamped})`;
14153
14659
  }
14154
14660
  return color;
14155
14661
  }
14156
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
+
14157
14703
  // ../blocks/src/theme/layout/generateLayoutCss.ts
14158
14704
  function generateLayoutCss(options) {
14159
14705
  const { themeId } = options;
@@ -14307,6 +14853,105 @@ ${root} .step-connector {
14307
14853
  return cssBlocks.join("\n\n");
14308
14854
  }
14309
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
+
14310
14955
  // ../blocks/src/theme/runtime/buildThemeRuntime.ts
14311
14956
  function buildThemeRuntime(theme, options) {
14312
14957
  const hydrated = hydrateTheme(theme);
@@ -14321,6 +14966,10 @@ function buildThemeRuntime(theme, options) {
14321
14966
  themeId,
14322
14967
  theme
14323
14968
  });
14969
+ const footerCss = generateFooterCss({
14970
+ themeId,
14971
+ theme
14972
+ });
14324
14973
  const cardCss = generateCardCss({
14325
14974
  themeId,
14326
14975
  theme,
@@ -14350,8 +14999,12 @@ function buildThemeRuntime(theme, options) {
14350
14999
  themeId,
14351
15000
  theme
14352
15001
  });
15002
+ const typographyCss = generateTypographyCss({
15003
+ themeId,
15004
+ theme
15005
+ });
14353
15006
  const tokens = buildThemeTokens(hydrated, theme);
14354
- 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 };
14355
15008
  }
14356
15009
  function hydrateTheme(theme) {
14357
15010
  return {
@@ -14381,17 +15034,39 @@ function buildThemeCssVars(theme) {
14381
15034
  ...typography.headings.h1.letterSpacing ? { ["--ls-h1"]: mapLetterSpacing(typography.headings.h1.letterSpacing) } : {},
14382
15035
  ...typography.headings.h2.letterSpacing ? { ["--ls-h2"]: mapLetterSpacing(typography.headings.h2.letterSpacing) } : {},
14383
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) } : {},
14384
15040
  ["--lh-heading"]: mapLineHeight(typography.headings.default.lineHeight),
14385
15041
  ["--lh-body"]: mapLineHeight(typography.body.lineHeight),
14386
15042
  ...typography.headings.h1.lineHeight ? { ["--lh-h1"]: mapLineHeight(typography.headings.h1.lineHeight) } : {},
14387
15043
  ...typography.headings.h2.lineHeight ? { ["--lh-h2"]: mapLineHeight(typography.headings.h2.lineHeight) } : {},
14388
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) } : {},
14389
15048
  ["--tt-heading"]: mapTextTransform(typography.headings.default.case),
14390
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)
14391
15059
  ["--fs-body"]: sized.body,
14392
15060
  ["--fs-h3"]: sized.h3,
14393
15061
  ["--fs-h2"]: sized.h2,
14394
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,
14395
15070
  ["--shadow-elev"]: mapShadow(shadow.elevation, shadow.softness, shadow.position || "bottom"),
14396
15071
  ["--space-mult"]: mapSpaceMult(space),
14397
15072
  ["--motion-duration"]: mapMotionDuration(motion.level),
@@ -14497,33 +15172,81 @@ function mapMotionEasing(e) {
14497
15172
  gentle: "cubic-bezier(.15,.85,.15,1)"
14498
15173
  }[e];
14499
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
+ }
14500
15186
  function computeTypeScale(scale, bodySize) {
14501
15187
  const base = { md: 16, lg: 17, xl: 18 }[bodySize];
14502
- 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];
14503
15190
  const h3 = Math.round(base * ratio);
14504
15191
  const h2 = Math.round(h3 * ratio);
14505
15192
  const h1 = Math.round(h2 * ratio);
15193
+ const fluidMin = 0.7;
15194
+ const fluidMax = 1.3;
14506
15195
  return {
15196
+ // Static sizes (fallback)
14507
15197
  ["--fs-body"]: `${base}px`,
14508
15198
  ["--fs-h3"]: `${h3}px`,
14509
15199
  ["--fs-h2"]: `${h2}px`,
14510
- ["--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)`
14511
15215
  };
14512
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
+ };
14513
15225
  function applyHeadingSizeOverrides(base, typography) {
14514
15226
  const body = base["--fs-body"];
14515
15227
  const h1Base = parseFloat(base["--fs-h1"].replace("px", ""));
14516
15228
  const h2Base = parseFloat(base["--fs-h2"].replace("px", ""));
14517
15229
  const h3Base = parseFloat(base["--fs-h3"].replace("px", ""));
14518
- const scaleMap = { md: 1, lg: 1.1, xl: 1.2 };
14519
- const h1Scale = typography.headings.h1.size ? scaleMap[typography.headings.h1.size] : 1;
14520
- const h2Scale = typography.headings.h2.size ? scaleMap[typography.headings.h2.size] : 1;
14521
- 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;
14522
15238
  return {
14523
15239
  body,
14524
- h1: `${Math.round(h1Base * h1Scale)}px`,
14525
- h2: `${Math.round(h2Base * h2Scale)}px`,
14526
- 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)`
14527
15250
  };
14528
15251
  }
14529
15252
  function mapLetterSpacing(s) {
@@ -14540,6 +15263,9 @@ function mapFontVariant(c) {
14540
15263
  if (c === "smallCaps") return "small-caps";
14541
15264
  return "normal";
14542
15265
  }
15266
+ function mapFontStyle(italic) {
15267
+ return italic ? "italic" : "normal";
15268
+ }
14543
15269
 
14544
15270
  // ../blocks/src/system/manifest/hydrateLinks.ts
14545
15271
  function hydrateManifestLinks(manifest, content, routes) {
@@ -15132,6 +15858,28 @@ var ENDPOINT_DEFINITIONS = {
15132
15858
  tags: ["site-{siteId}", "api-keys", "access-logs"],
15133
15859
  responseKind: "json"
15134
15860
  },
15861
+ // Management API Keys (SDK write operations)
15862
+ listManagementKeys: {
15863
+ path: "/sites/{siteId}/api-keys/management",
15864
+ method: "GET",
15865
+ auth: "user",
15866
+ tags: ["site-{siteId}", "api-keys", "management-keys"],
15867
+ responseKind: "json"
15868
+ },
15869
+ createManagementKey: {
15870
+ path: "/sites/{siteId}/api-keys/management",
15871
+ method: "POST",
15872
+ auth: "user",
15873
+ tags: ["site-{siteId}", "api-keys", "management-keys"],
15874
+ responseKind: "json"
15875
+ },
15876
+ revokeManagementKey: {
15877
+ path: "/sites/{siteId}/api-keys/management",
15878
+ method: "DELETE",
15879
+ auth: "user",
15880
+ tags: ["site-{siteId}", "api-keys", "management-keys"],
15881
+ responseKind: "json"
15882
+ },
15135
15883
  getBookingSettings: {
15136
15884
  path: "/sites/{siteId}/bookings/settings",
15137
15885
  method: "GET",
@@ -16407,6 +17155,15 @@ var ENDPOINT_DEFINITIONS = {
16407
17155
  auth: "public",
16408
17156
  responseKind: "json"
16409
17157
  },
17158
+ // Resolve event occurrence by URL segment (date or UUID)
17159
+ resolveEventOccurrence: {
17160
+ path: "/public/sites/{siteId}/events/occurrences/resolve",
17161
+ method: "GET",
17162
+ revalidate: 60,
17163
+ tags: ["public-events-{siteId}", "event-occurrence"],
17164
+ auth: "public",
17165
+ responseKind: "json"
17166
+ },
16410
17167
  // Public event registration
16411
17168
  registerForEvent: {
16412
17169
  path: "/public/sites/{siteId}/events/register",
@@ -16581,6 +17338,20 @@ if (typeof window === "undefined") {
16581
17338
  revalidateTag = null;
16582
17339
  }
16583
17340
  }
17341
+ var sdkVersion;
17342
+ function generateRequestId() {
17343
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
17344
+ return crypto.randomUUID();
17345
+ }
17346
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
17347
+ const r2 = Math.random() * 16 | 0;
17348
+ const v = c === "x" ? r2 : r2 & 3 | 8;
17349
+ return v.toString(16);
17350
+ });
17351
+ }
17352
+ function setSdkVersion(version2) {
17353
+ sdkVersion = version2;
17354
+ }
16584
17355
  var ApiRequestError = class extends Error {
16585
17356
  constructor(message, options) {
16586
17357
  super(message);
@@ -16592,6 +17363,7 @@ var ApiRequestError = class extends Error {
16592
17363
  this.requestId = options.requestId;
16593
17364
  this.body = options.body;
16594
17365
  this.cause = options.cause;
17366
+ this.errorCode = options.errorCode;
16595
17367
  }
16596
17368
  };
16597
17369
  function buildEndpointURL(baseURL, endpoint) {
@@ -16628,6 +17400,29 @@ async function parseErrorBody(response) {
16628
17400
  return null;
16629
17401
  }
16630
17402
  }
17403
+ function buildSuccessEnvelope(data, requestId) {
17404
+ return {
17405
+ success: true,
17406
+ data,
17407
+ meta: {
17408
+ requestId: requestId ?? generateRequestId(),
17409
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
17410
+ apiVersion: "2025-01-01"
17411
+ }
17412
+ };
17413
+ }
17414
+ function buildErrorEnvelope(code, message, status, requestId) {
17415
+ return {
17416
+ success: false,
17417
+ error: {
17418
+ code,
17419
+ message,
17420
+ requestId: requestId ?? generateRequestId(),
17421
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
17422
+ status
17423
+ }
17424
+ };
17425
+ }
16631
17426
  async function parseSuccessResponse(endpoint, response, config) {
16632
17427
  const responseKind = config.responseKind ?? "json";
16633
17428
  const auth = config.auth ?? "user";
@@ -16635,14 +17430,15 @@ async function parseSuccessResponse(endpoint, response, config) {
16635
17430
  switch (responseKind) {
16636
17431
  case "json": {
16637
17432
  if (response.status === 204 || response.status === 205 || response.status === 304) {
16638
- return void 0;
17433
+ return buildSuccessEnvelope(void 0, requestId);
16639
17434
  }
16640
17435
  const raw = await response.text();
16641
17436
  if (!raw.trim()) {
16642
- return void 0;
17437
+ return buildSuccessEnvelope(void 0, requestId);
16643
17438
  }
17439
+ let parsed;
16644
17440
  try {
16645
- return JSON.parse(raw);
17441
+ parsed = JSON.parse(raw);
16646
17442
  } catch (cause) {
16647
17443
  throw new ApiRequestError(
16648
17444
  `Failed to parse JSON response for endpoint ${String(endpoint)}`,
@@ -16657,32 +17453,33 @@ async function parseSuccessResponse(endpoint, response, config) {
16657
17453
  }
16658
17454
  );
16659
17455
  }
17456
+ if (parsed && typeof parsed === "object" && "success" in parsed && typeof parsed.success === "boolean") {
17457
+ return parsed;
17458
+ }
17459
+ return buildSuccessEnvelope(parsed, requestId);
16660
17460
  }
16661
17461
  case "text": {
16662
- return await response.text();
17462
+ const text2 = await response.text();
17463
+ return buildSuccessEnvelope(text2, requestId);
16663
17464
  }
16664
17465
  case "stream": {
16665
17466
  const body = response.body;
16666
17467
  if (!body) {
16667
- throw new ApiRequestError(
17468
+ return buildErrorEnvelope(
17469
+ "server:internal_error",
16668
17470
  `Expected a streamed body for endpoint ${String(endpoint)}`,
16669
- {
16670
- endpoint,
16671
- status: response.status,
16672
- method: config.method,
16673
- auth,
16674
- requestId
16675
- }
17471
+ response.status,
17472
+ requestId
16676
17473
  );
16677
17474
  }
16678
17475
  const stream = body;
16679
- return stream;
17476
+ return buildSuccessEnvelope(stream, requestId);
16680
17477
  }
16681
17478
  case "void": {
16682
- return void 0;
17479
+ return buildSuccessEnvelope(void 0, requestId);
16683
17480
  }
16684
17481
  default: {
16685
- return void 0;
17482
+ return buildSuccessEnvelope(void 0, requestId);
16686
17483
  }
16687
17484
  }
16688
17485
  }
@@ -16748,11 +17545,15 @@ function createRawCMSClient(headers = {}, baseUrl) {
16748
17545
  const requestInit = {
16749
17546
  method,
16750
17547
  ...options,
17548
+ // Include credentials for same-origin requests (sends cookies for auth)
17549
+ credentials: "same-origin",
16751
17550
  // Don't include body for GET/HEAD requests
16752
17551
  body: isGetOrHead ? void 0 : isFormData ? body : body ? JSON.stringify(body) : void 0,
16753
17552
  headers: {
16754
17553
  ...options.headers,
16755
17554
  ...headers,
17555
+ // Include SDK version if set
17556
+ ...sdkVersion && { "x-sdk-version": sdkVersion },
16756
17557
  // Don't set Content-Type for GET/HEAD requests without body
16757
17558
  ...isGetOrHead ? {} : isFormData ? {} : { "Content-Type": "application/json" }
16758
17559
  },
@@ -16806,94 +17607,30 @@ function createBearerAPIClient(token, baseUrl) {
16806
17607
  return createCMSClient(authHeaders, baseUrl);
16807
17608
  }
16808
17609
 
16809
- // ../api/src/aiPlayground.ts
16810
- var import_zod18 = require("zod");
16811
- var Rfc6902PatchOp = import_zod18.z.discriminatedUnion("op", [
16812
- // Standard RFC-6902 operations
16813
- import_zod18.z.object({
16814
- op: import_zod18.z.literal("add"),
16815
- path: import_zod18.z.string(),
16816
- value: import_zod18.z.unknown()
16817
- }),
16818
- import_zod18.z.object({
16819
- op: import_zod18.z.literal("remove"),
16820
- path: import_zod18.z.string()
16821
- }),
16822
- import_zod18.z.object({
16823
- op: import_zod18.z.literal("replace"),
16824
- path: import_zod18.z.string(),
16825
- value: import_zod18.z.unknown()
16826
- }),
16827
- import_zod18.z.object({
16828
- op: import_zod18.z.literal("move"),
16829
- from: import_zod18.z.string(),
16830
- path: import_zod18.z.string()
16831
- }),
16832
- import_zod18.z.object({
16833
- op: import_zod18.z.literal("copy"),
16834
- from: import_zod18.z.string(),
16835
- path: import_zod18.z.string()
16836
- }),
16837
- // Block-level operations (Phase 2)
16838
- import_zod18.z.object({
16839
- op: import_zod18.z.literal("add_block"),
16840
- blockKind: import_zod18.z.string(),
16841
- afterBlockId: import_zod18.z.string().nullable(),
16842
- content: import_zod18.z.record(import_zod18.z.string(), import_zod18.z.unknown()),
16843
- rationale: import_zod18.z.string()
16844
- }),
16845
- import_zod18.z.object({
16846
- op: import_zod18.z.literal("delete_block"),
16847
- blockId: import_zod18.z.string(),
16848
- rationale: import_zod18.z.string()
16849
- }),
16850
- import_zod18.z.object({
16851
- op: import_zod18.z.literal("reorder_block"),
16852
- blockId: import_zod18.z.string(),
16853
- afterBlockId: import_zod18.z.string().nullable(),
16854
- rationale: import_zod18.z.string()
16855
- })
16856
- ]);
16857
- var PatchEnvelope = import_zod18.z.object({
16858
- blockId: import_zod18.z.string(),
16859
- blockKind: import_zod18.z.string().optional(),
16860
- blockPurpose: import_zod18.z.string().optional().nullable(),
16861
- ops: import_zod18.z.array(Rfc6902PatchOp),
16862
- rationale: import_zod18.z.string(),
16863
- currentContent: import_zod18.z.record(import_zod18.z.string(), import_zod18.z.unknown()).optional()
16864
- });
16865
- var ContentUpdateResponse = import_zod18.z.object({
16866
- patches: import_zod18.z.array(PatchEnvelope),
16867
- assistantMessage: import_zod18.z.string()
16868
- });
16869
- var PlaygroundProposeRequest = import_zod18.z.object({
16870
- request: import_zod18.z.string().min(1).max(2e3)
16871
- });
16872
- var PlaygroundProposeResponse = import_zod18.z.object({
16873
- patches: import_zod18.z.array(PatchEnvelope),
16874
- assistantMessage: import_zod18.z.string(),
16875
- validation: import_zod18.z.object({
16876
- valid: import_zod18.z.boolean(),
16877
- issues: import_zod18.z.array(import_zod18.z.string()),
16878
- filtered: import_zod18.z.number()
16879
- })
16880
- });
16881
- var MultiPagePatchEnvelope = import_zod18.z.object({
16882
- pageId: import_zod18.z.string(),
16883
- blockId: import_zod18.z.string().optional(),
16884
- // Not present for page-level ops
16885
- blockKind: import_zod18.z.string().optional(),
16886
- blockPurpose: import_zod18.z.string().optional().nullable(),
16887
- ops: import_zod18.z.array(Rfc6902PatchOp),
16888
- rationale: import_zod18.z.string(),
16889
- currentContent: import_zod18.z.record(import_zod18.z.string(), import_zod18.z.unknown()).optional()
16890
- });
16891
- var MultiPageUpdateResponse = import_zod18.z.object({
16892
- patches: import_zod18.z.array(MultiPagePatchEnvelope),
16893
- assistantMessage: import_zod18.z.string(),
16894
- pagesModified: import_zod18.z.number(),
16895
- toolCallsUsed: import_zod18.z.number()
16896
- });
17610
+ // ../api/src/common/envelope.ts
17611
+ function isApiError(result) {
17612
+ return result.success === false;
17613
+ }
17614
+ function isApiSuccess(result) {
17615
+ return result.success === true;
17616
+ }
17617
+ var ApiEnvelopeError = class extends Error {
17618
+ constructor(error) {
17619
+ super(error.message);
17620
+ this.name = "ApiEnvelopeError";
17621
+ this.code = error.code;
17622
+ this.requestId = error.requestId;
17623
+ this.timestamp = error.timestamp;
17624
+ this.status = error.status;
17625
+ this.fieldErrors = error.fieldErrors;
17626
+ }
17627
+ };
17628
+ function unwrapResponse(result) {
17629
+ if (isApiSuccess(result)) {
17630
+ return result.data;
17631
+ }
17632
+ throw new ApiEnvelopeError(result.error);
17633
+ }
16897
17634
 
16898
17635
  // src/client/cache.ts
16899
17636
  var SimpleCache = class {
@@ -16931,7 +17668,100 @@ var SimpleCache = class {
16931
17668
  }
16932
17669
  };
16933
17670
 
17671
+ // src/version.ts
17672
+ var SDK_VERSION = "0.5.0";
17673
+
17674
+ // src/client/error.ts
17675
+ var RiverbankApiError = class _RiverbankApiError extends Error {
17676
+ constructor(apiError) {
17677
+ super(apiError.message);
17678
+ this.name = "RiverbankApiError";
17679
+ this.code = apiError.code;
17680
+ this.requestId = apiError.requestId;
17681
+ this.status = apiError.status;
17682
+ this.fieldErrors = apiError.fieldErrors;
17683
+ this.timestamp = apiError.timestamp;
17684
+ Object.setPrototypeOf(this, _RiverbankApiError.prototype);
17685
+ }
17686
+ /**
17687
+ * Check if this error matches a specific error code
17688
+ *
17689
+ * @example
17690
+ * ```ts
17691
+ * if (error.is('auth:unauthenticated')) {
17692
+ * // Redirect to login
17693
+ * }
17694
+ * ```
17695
+ */
17696
+ is(code) {
17697
+ return this.code === code;
17698
+ }
17699
+ /**
17700
+ * Check if this is an authentication or authorization error
17701
+ *
17702
+ * Matches: auth:unauthenticated, auth:token_expired, auth:token_invalid,
17703
+ * auth:forbidden, auth:mfa_required, auth:insufficient_permissions
17704
+ */
17705
+ isAuthError() {
17706
+ return this.code.startsWith("auth:");
17707
+ }
17708
+ /**
17709
+ * Check if this is a validation error
17710
+ *
17711
+ * Matches: validation:invalid_input, validation:missing_field, validation:invalid_format
17712
+ */
17713
+ isValidationError() {
17714
+ return this.code.startsWith("validation:");
17715
+ }
17716
+ /**
17717
+ * Check if this is a resource error (not found, conflict, etc.)
17718
+ *
17719
+ * Matches: resource:not_found, resource:already_exists, resource:conflict, resource:gone
17720
+ */
17721
+ isResourceError() {
17722
+ return this.code.startsWith("resource:");
17723
+ }
17724
+ /**
17725
+ * Check if this is a rate limiting error
17726
+ */
17727
+ isRateLimitError() {
17728
+ return this.code.startsWith("rate_limit:");
17729
+ }
17730
+ /**
17731
+ * Check if this is a billing/payment error
17732
+ */
17733
+ isBillingError() {
17734
+ return this.code.startsWith("billing:");
17735
+ }
17736
+ /**
17737
+ * Check if this is a server error
17738
+ */
17739
+ isServerError() {
17740
+ return this.code.startsWith("server:");
17741
+ }
17742
+ };
17743
+
16934
17744
  // src/client/index.ts
17745
+ setSdkVersion(SDK_VERSION);
17746
+ function convertToTypedError(error) {
17747
+ if (error instanceof ApiEnvelopeError) {
17748
+ throw new RiverbankApiError({
17749
+ code: error.code,
17750
+ message: error.message,
17751
+ requestId: error.requestId,
17752
+ timestamp: error.timestamp,
17753
+ status: error.status,
17754
+ fieldErrors: error.fieldErrors
17755
+ });
17756
+ }
17757
+ if (error instanceof ApiRequestError && error.body && typeof error.body === "object") {
17758
+ const body = error.body;
17759
+ if (isApiError(body)) {
17760
+ throw new RiverbankApiError(body.error);
17761
+ }
17762
+ }
17763
+ throw error;
17764
+ }
16935
17765
  function createRiverbankClient(config) {
16936
17766
  if (!config.baseUrl) {
16937
17767
  throw new Error(
@@ -16958,7 +17788,13 @@ function createRiverbankClient(config) {
16958
17788
  return cached;
16959
17789
  }
16960
17790
  }
16961
- const data = await fetcher();
17791
+ let data;
17792
+ try {
17793
+ const response = await fetcher();
17794
+ data = unwrapResponse(response);
17795
+ } catch (error) {
17796
+ convertToTypedError(error);
17797
+ }
16962
17798
  if (cacheEnabled) {
16963
17799
  cache.set(cacheKey, data);
16964
17800
  }
@@ -16993,33 +17829,27 @@ function createRiverbankClient(config) {
16993
17829
  const entryIdsCacheKey = mode === "manual" && entryIds?.length ? entryIds.join(",") : "";
16994
17830
  const cacheKey = `entries:${siteId}:${contentType}:${limit ?? ""}:${offset ?? ""}:${order ?? ""}:${preview}:${mode ?? ""}:${entryIdsCacheKey}:${includeMeta ?? ""}`;
16995
17831
  return cachedFetch(cacheKey, async () => {
16996
- const apiParams = {
16997
- siteId,
16998
- type: contentType
16999
- };
17000
- if (typeof limit === "number") {
17001
- apiParams.limit = String(limit);
17002
- }
17003
- if (typeof offset === "number") {
17004
- apiParams.offset = String(offset);
17005
- }
17006
- if (includeMeta) {
17007
- apiParams.meta = "true";
17008
- }
17832
+ let orderParam;
17009
17833
  if (order === "newest") {
17010
- apiParams.order = "published_at.desc";
17834
+ orderParam = "published_at.desc";
17011
17835
  } else if (order === "oldest") {
17012
- apiParams.order = "published_at.asc";
17836
+ orderParam = "published_at.asc";
17013
17837
  } else if (order === "title") {
17014
- apiParams.order = "title.asc";
17015
- }
17016
- if (preview) {
17017
- apiParams.stage = "preview";
17018
- }
17019
- if (mode === "manual" && entryIds?.length) {
17020
- apiParams.mode = "manual";
17021
- apiParams.entryIds = JSON.stringify(entryIds);
17838
+ orderParam = "title.asc";
17022
17839
  }
17840
+ const apiParams = {
17841
+ siteId,
17842
+ type: contentType,
17843
+ ...typeof limit === "number" && { limit: String(limit) },
17844
+ ...typeof offset === "number" && { offset: String(offset) },
17845
+ ...includeMeta && { meta: "true" },
17846
+ ...orderParam && { order: orderParam },
17847
+ ...preview && { stage: "preview" },
17848
+ ...mode === "manual" && entryIds?.length && {
17849
+ mode: "manual",
17850
+ entryIds: JSON.stringify(entryIds)
17851
+ }
17852
+ };
17023
17853
  return await apiClient({ endpoint: "listPublishedEntries", params: apiParams });
17024
17854
  });
17025
17855
  },
@@ -17047,8 +17877,10 @@ function createRiverbankClient(config) {
17047
17877
  }
17048
17878
  const cacheKey = `public-booking-services:${siteId}:${ids ?? ""}`;
17049
17879
  return cachedFetch(cacheKey, async () => {
17050
- const apiParams = { siteId };
17051
- if (ids) apiParams.ids = ids;
17880
+ const apiParams = {
17881
+ siteId,
17882
+ ...ids && { ids }
17883
+ };
17052
17884
  return await apiClient({ endpoint: "getPublicBookingServices", params: apiParams });
17053
17885
  });
17054
17886
  },
@@ -17059,14 +17891,42 @@ function createRiverbankClient(config) {
17059
17891
  }
17060
17892
  const cacheKey = `public-events:${siteId}:${limit ?? ""}:${from ?? ""}:${to ?? ""}:${stage ?? ""}`;
17061
17893
  return cachedFetch(cacheKey, async () => {
17062
- const apiParams = { siteId };
17063
- if (typeof limit === "number") apiParams.limit = String(limit);
17064
- if (from) apiParams.from = from;
17065
- if (to) apiParams.to = to;
17066
- if (stage) apiParams.stage = stage;
17894
+ const apiParams = {
17895
+ siteId,
17896
+ ...typeof limit === "number" && { limit: String(limit) },
17897
+ ...from && { from },
17898
+ ...to && { to },
17899
+ ...stage && { stage }
17900
+ };
17067
17901
  return await apiClient({ endpoint: "listPublicEvents", params: apiParams });
17068
17902
  });
17069
17903
  },
17904
+ async resolveEventOccurrence(params) {
17905
+ const { siteId, entryId, segment } = params;
17906
+ if (!siteId || !entryId || !segment) {
17907
+ throw new Error("resolveEventOccurrence() requires siteId, entryId, and segment");
17908
+ }
17909
+ const cacheKey = `event-occurrence:${siteId}:${entryId}:${segment}`;
17910
+ return cachedFetch(cacheKey, async () => {
17911
+ return await apiClient({
17912
+ endpoint: "resolveEventOccurrence",
17913
+ params: { siteId, entryId, segment }
17914
+ });
17915
+ });
17916
+ },
17917
+ async checkRedirect(params) {
17918
+ const { siteId, path } = params;
17919
+ if (!siteId || !path) {
17920
+ throw new Error("checkRedirect() requires siteId and path");
17921
+ }
17922
+ const cacheKey = `redirect:${siteId}:${path}`;
17923
+ return cachedFetch(cacheKey, async () => {
17924
+ return await apiClient({
17925
+ endpoint: "checkRedirect",
17926
+ params: { site: siteId, path }
17927
+ });
17928
+ });
17929
+ },
17070
17930
  clearCache() {
17071
17931
  cache.clear();
17072
17932
  }