@riverbankcms/sdk 0.152.0 → 0.153.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (178) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/{EventEmbeddedCheckoutStep-DVQXWFm6.mjs → EventEmbeddedCheckoutStep-veN-QiAE.mjs} +1 -1
  3. package/dist/{PreviewEditorSidebar-Dr4NJi3Q.mjs → PreviewEditorSidebar-jI_4DTZY.mjs} +4 -4
  4. package/dist/{PreviewEditorUI-DSZXQbyh.mjs → PreviewEditorUI-ORkVZhfu.mjs} +3 -3
  5. package/dist/{SdkPreviewModeRuntime-Dl4GyMc3.mjs → SdkPreviewModeRuntime-DaNqevI1.mjs} +221 -115
  6. package/dist/{SiteChromeCustomizeContext-DgBe-FlM.mjs → SiteChromeCustomizeContext-CgNuBHC0.mjs} +1798 -2024
  7. package/dist/{ThemedButton-B8ViBnLK.mjs → ThemedButton-X2UxhW6F.mjs} +213 -38
  8. package/dist/_dts/ai/src/contracts/proposals.d.ts +52 -52
  9. package/dist/_dts/ai/src/contracts/siteStyleProposalSchemas.d.ts +2357 -7859
  10. package/dist/_dts/api/src/communications.d.ts +19 -5
  11. package/dist/_dts/api/src/indexExtendedTypes.d.ts +1 -1
  12. package/dist/_dts/api/src/sdkThemeWire.d.ts +186 -1434
  13. package/dist/_dts/api/src/shared-contracts.d.ts +10 -0
  14. package/dist/_dts/api/src/siteInfrastructure.d.ts +2 -1
  15. package/dist/_dts/api/src/teamMembers.d.ts +2 -27
  16. package/dist/_dts/block-form/src/widgets/RepeaterField/components/layoutGridDomain.d.ts +3 -13
  17. package/dist/_dts/blocks/src/contracts/index.d.ts +1 -0
  18. package/dist/_dts/blocks/src/index.d.ts +1 -0
  19. package/dist/_dts/blocks/src/lib/media.d.ts +1 -0
  20. package/dist/_dts/blocks/src/lib/picsum.d.ts +2 -2
  21. package/dist/_dts/blocks/src/pageRendererContracts.d.ts +2 -1
  22. package/dist/_dts/blocks/src/system/blocks/events/eventSelectionFields.d.ts +1 -1
  23. package/dist/_dts/blocks/src/system/blocks/events/shared/schemas.d.ts +196 -804
  24. package/dist/_dts/blocks/src/system/blocks/events/shared/types.d.ts +2 -2
  25. package/dist/_dts/blocks/src/system/blocks/location-map.d.ts +1 -1
  26. package/dist/_dts/blocks/src/system/blocks/media-text.d.ts +45 -45
  27. package/dist/_dts/blocks/src/system/blocks/shared/teamMembers.d.ts +4 -7
  28. package/dist/_dts/blocks/src/system/blocks/team-members.d.ts +2 -2
  29. package/dist/_dts/blocks/src/system/customize/backgrounds.d.ts +6 -6
  30. package/dist/_dts/blocks/src/system/fields/backgroundContent.d.ts +377 -1
  31. package/dist/_dts/blocks/src/system/helpers/backgroundMedia.d.ts +6 -2
  32. package/dist/_dts/blocks/src/system/helpers/resolveBackground.d.ts +3 -3
  33. package/dist/_dts/blocks/src/system/layout/repeaterGrid.d.ts +12 -5
  34. package/dist/_dts/blocks/src/system/manifest/fieldValidation/index.d.ts +3 -3
  35. package/dist/_dts/blocks/src/system/manifest/schema.d.ts +24 -24
  36. package/dist/_dts/blocks/src/system/manifest/validation.d.ts +2 -0
  37. package/dist/_dts/blocks/src/system/node/fragments/lookSlot.d.ts +1 -1
  38. package/dist/_dts/blocks/src/system/runtime/hooks/useBookingFlowController.d.ts +1 -1
  39. package/dist/_dts/blocks/src/system/runtime/hooks/useHeadlessBookingFlow.d.ts +2 -0
  40. package/dist/_dts/blocks/src/system/runtime/lookSurfaces.d.ts +2 -2
  41. package/dist/_dts/blocks/src/system/runtime/nodes/ImageResolveContext.d.ts +1 -1
  42. package/dist/_dts/blocks/src/system/runtime/nodes/appointment-services.d.ts +50 -202
  43. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.headless.state.d.ts +28 -1
  44. package/dist/_dts/blocks/src/system/runtime/nodes/event-details/lookPresentation.d.ts +2 -2
  45. package/dist/_dts/blocks/src/system/runtime/nodes/event-details/presentation.d.ts +1 -1
  46. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/CardListItem.d.ts +1 -1
  47. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/eventCollectionContract.d.ts +276 -884
  48. package/dist/_dts/blocks/src/system/runtime/nodes/file-download.d.ts +3 -2
  49. package/dist/_dts/blocks/src/system/runtime/nodes/media.d.ts +22 -90
  50. package/dist/_dts/blocks/src/system/runtime/nodes/mediaContext.d.ts +69 -0
  51. package/dist/_dts/blocks/src/system/transforms/registry/index.d.ts +1 -0
  52. package/dist/_dts/blocks/src/system/transforms/registry/links.d.ts +3 -3
  53. package/dist/_dts/content-model/src/content-types/schema.d.ts +3 -3
  54. package/dist/_dts/core/src/mailing-list-runtime.d.ts +2 -2
  55. package/dist/_dts/core/src/mailing-list-setup-parser.d.ts +9 -1
  56. package/dist/_dts/core/src/mailing-list-setup.d.ts +9 -1
  57. package/dist/_dts/core/src/mailing-list-submission.d.ts +1 -1
  58. package/dist/_dts/core/src/mailing-list-targeting.d.ts +9 -1
  59. package/dist/_dts/db/src/generated/supabase/database.types.d.ts +55 -4
  60. package/dist/_dts/editor-blocks/src/index.d.ts +1 -0
  61. package/dist/_dts/editor-blocks/src/media/MediaField.d.ts +2 -2
  62. package/dist/_dts/editor-blocks/src/media/admitEditorMediaField.d.ts +4 -0
  63. package/dist/_dts/editor-blocks/src/widgets/mailing-list-targeting/targetingState.d.ts +2 -2
  64. package/dist/_dts/media-core/src/assetsInUseSummary.d.ts +6 -0
  65. package/dist/_dts/media-core/src/contentMediaAudit.d.ts +3 -2
  66. package/dist/_dts/media-core/src/index.d.ts +4 -0
  67. package/dist/_dts/media-core/src/media.d.ts +406 -0
  68. package/dist/_dts/media-core/src/mediaIdentifierSchema.d.ts +3 -0
  69. package/dist/_dts/media-core/src/mediaKinds.d.ts +2 -0
  70. package/dist/_dts/media-core/src/mediaUsageProjection.d.ts +13 -1
  71. package/dist/_dts/media-core/src/mediaWriteNormalizer.d.ts +2 -6
  72. package/dist/_dts/media-core/src/portableMediaReferences.d.ts +8 -21
  73. package/dist/_dts/media-core/src/renderableMediaAsset.d.ts +28 -14
  74. package/dist/_dts/media-core/src/renderableMediaAssetAdmission.d.ts +15 -0
  75. package/dist/_dts/media-editor/src/CropDialog.d.ts +6 -3
  76. package/dist/_dts/media-editor/src/MediaEditor.d.ts +2 -1
  77. package/dist/_dts/media-editor/src/MediaPreview.d.ts +3 -3
  78. package/dist/_dts/media-editor/src/cropEditorSource.d.ts +5 -7
  79. package/dist/_dts/media-editor/src/editorMediaState.d.ts +29 -0
  80. package/dist/_dts/media-editor/src/mediaSelection.d.ts +1 -2
  81. package/dist/_dts/media-editor/src/runtimeMediaAssetState.d.ts +4 -5
  82. package/dist/_dts/media-editor/src/types.d.ts +1 -1
  83. package/dist/_dts/media-editor/src/utils.d.ts +0 -1
  84. package/dist/_dts/media-react/src/components/cropChangePolicy.d.ts +4 -1
  85. package/dist/_dts/media-react/src/components/cropGeometry.d.ts +1 -0
  86. package/dist/_dts/media-react/src/components/useImageCropperController.d.ts +1 -0
  87. package/dist/_dts/preview-next/src/client/blocks/BlockBackgroundChooser.d.ts +2 -1
  88. package/dist/_dts/preview-next/src/client/blocks/previewCustomizeSelectedMedia.d.ts +11 -12
  89. package/dist/_dts/sdk/src/contracts/content.d.ts +2 -45
  90. package/dist/_dts/sdk/src/contracts/index.d.ts +1 -1
  91. package/dist/_dts/sdk/src/contracts/rendering.d.ts +3 -3
  92. package/dist/_dts/sdk/src/index.d.ts +1 -0
  93. package/dist/_dts/sdk/src/rendering/image.d.ts +5 -5
  94. package/dist/_dts/sdk/src/rendering/index.d.ts +2 -1
  95. package/dist/_dts/sdk/src/rendering/link.d.ts +3 -7
  96. package/dist/_dts/sdk/src/rendering/mediaAssets.d.ts +2 -4
  97. package/dist/_dts/sdk/src/version.d.ts +1 -1
  98. package/dist/_dts/theme-core/src/accordions/types.d.ts +1 -1
  99. package/dist/_dts/theme-core/src/boxBackgroundSchema.d.ts +397 -26
  100. package/dist/_dts/theme-core/src/buttons/types.d.ts +21 -21
  101. package/dist/_dts/theme-core/src/cards/types.d.ts +34 -34
  102. package/dist/_dts/theme-core/src/inputs/types.d.ts +3 -3
  103. package/dist/_dts/theme-core/src/lib/media.d.ts +2 -616
  104. package/dist/_dts/theme-core/src/mock-themes/all.d.ts +261 -2619
  105. package/dist/_dts/theme-core/src/palette/curated/types.d.ts +1 -1
  106. package/dist/_dts/theme-core/src/schema.d.ts +548 -3187
  107. package/dist/_dts/theme-core/src/site-styles/backgroundAppearance.d.ts +2 -2
  108. package/dist/_dts/theme-core/src/site-styles/runtimeBackgroundResolution.d.ts +9 -9
  109. package/dist/_dts/theme-core/src/site-styles/styleTags.d.ts +1 -1
  110. package/dist/_dts/theme-core/src/site-styles/tokenRecipes.d.ts +1 -1
  111. package/dist/_dts/theme-core/src/styles/skinTokens.d.ts +2 -2
  112. package/dist/_dts/theme-core/src/typography/schema.d.ts +2 -2
  113. package/dist/client/{BookingMailingListNote-CBuMKN0w.mjs → BookingMailingListNote-DrchYW1m.mjs} +2 -2
  114. package/dist/client/{CardListItem-Dc9XTXhB.mjs → CardListItem-CC_GVmF6.mjs} +5 -4
  115. package/dist/client/{CheckboxChoice-CIqx_o0E.mjs → CheckboxChoice-Dq30m3DO.mjs} +1 -1
  116. package/dist/client/{DemoBookingPortalAccess-D3VQ_kLj.mjs → DemoBookingPortalAccess-ojwbVUmx.mjs} +2 -2
  117. package/dist/client/{EventCombined.client-BHGEKise.mjs → EventCombined.client-DyN0v0Xk.mjs} +5 -6
  118. package/dist/client/{EventEmbeddedCheckoutStep-Bo1Cm23R.mjs → EventEmbeddedCheckoutStep-CgfpKc3n.mjs} +2 -2
  119. package/dist/client/{EventListing.client-D5OQgVPr.mjs → EventListing.client-CuOuvYMz.mjs} +2 -2
  120. package/dist/client/{LeafletStaticMap-CLL5cWrr.mjs → LeafletStaticMap-B0WhRr3j.mjs} +1 -1
  121. package/dist/client/{RichText-BoDmnopf.mjs → RichText-C1fIXBzA.mjs} +45 -32
  122. package/dist/client/{ThemedButton-Ciltp0IK.mjs → ThemedButton-B7HFqFBg.mjs} +1 -2
  123. package/dist/client/{accordion-DOkRS64-.mjs → accordion-DCDVWSye.mjs} +1 -1
  124. package/dist/client/{bookingForm-wlMVwo9h.mjs → bookingForm-BJ3C4GlM.mjs} +42 -15
  125. package/dist/client/bookings.mjs +116989 -22191
  126. package/dist/client/{carousel-CGWk-Z0u.mjs → carousel-BSCBhfHY.mjs} +2 -2
  127. package/dist/client/{carousel.client-kX5mN1Eg.mjs → carousel.client-GEtOGsxo.mjs} +1 -1
  128. package/dist/client/{cart-OBBPlaH4.mjs → cart-Yv-aAtck.mjs} +3 -3
  129. package/dist/client/{checkout-Bmw2WjQX.mjs → checkout-B9xDkl30.mjs} +3 -3
  130. package/dist/client/client.mjs +17577 -17361
  131. package/dist/client/{context-BI77UFAn.mjs → context-BOGe3rIA.mjs} +1 -1
  132. package/dist/client/{eventCalendar-qkej2Edn.mjs → eventCalendar-D6M0T9hs.mjs} +8 -9
  133. package/dist/client/{eventCombined-DApKHvat.mjs → eventCombined-NM4UFBq8.mjs} +4 -4
  134. package/dist/client/{eventDetails-BQyUDPH0.mjs → eventDetails-f_FhV4O8.mjs} +3 -3
  135. package/dist/client/{eventListing-CeAnshlZ.mjs → eventListing-WLkfAROh.mjs} +4 -4
  136. package/dist/client/{eventRegistration-C3A3NyBO.mjs → eventRegistration-D3ejfLvW.mjs} +10 -10
  137. package/dist/client/{form-DW8rU7jO.mjs → form-D5Or2Jyu.mjs} +4 -5
  138. package/dist/client/{headerSection-CkIhsoNm.mjs → headerSection-hWgnv27V.mjs} +3 -3
  139. package/dist/client/hooks.mjs +16014 -15751
  140. package/dist/client/{locationMap-D4O8wbli.mjs → locationMap-Di1K0O2S.mjs} +3 -4
  141. package/dist/client/{media-C5K_0xPd.mjs → media-D29-F1u_.mjs} +183 -362
  142. package/dist/client/mediaContext-CwbbimYB.mjs +135 -0
  143. package/dist/client/{newsletterForm-B7IxSPuz.mjs → newsletterForm-CwxcwTNO.mjs} +4 -4
  144. package/dist/client/{productDetail-Bqxpwy5N.mjs → productDetail-BLSnhPdA.mjs} +3 -3
  145. package/dist/client/{productList-u9Lz8V15.mjs → productList-oGytONOX.mjs} +3 -3
  146. package/dist/client/{propsDecoder-Bf1jucUp.mjs → propsDecoder-lf_dTeZS.mjs} +1467 -125
  147. package/dist/client/renderableMediaAssetAdmission-CHkXYDC_.mjs +143 -0
  148. package/dist/client/rendering/client.mjs +10855 -10689
  149. package/dist/client/rendering/islands.mjs +20 -23
  150. package/dist/client/rendering.mjs +18411 -18181
  151. package/dist/client/{routeIslandApiConfig-BgP-aPMl.mjs → routeIslandApiConfig-Bc_WVPS8.mjs} +1 -1
  152. package/dist/client/{shop-B_eykR-_.mjs → shop-BQ3bR7fA.mjs} +7 -7
  153. package/dist/client/{shop-commerce-CT0APkFV.mjs → shop-commerce-DDPll6ZC.mjs} +8 -8
  154. package/dist/client/{shop-commerce-store-DcvZxdEK.mjs → shop-commerce-store-DO-e1pTe.mjs} +1 -1
  155. package/dist/client/{shopShared-BVJOiUiJ.mjs → shopShared-BylM9jh1.mjs} +5 -5
  156. package/dist/client/{useDiscountCodeUi-DPmYDunz.mjs → useDiscountCodeUi-B1Puub2v.mjs} +1 -1
  157. package/dist/client/{useEventPagination-8-U55vH5.mjs → useEventPagination-BBhkmQaT.mjs} +6 -7
  158. package/dist/preview-next/before-render.mjs +89 -4
  159. package/dist/preview-next/client/runtime.mjs +3 -3
  160. package/dist/{sdk-runtime-C5jPdSrk.mjs → sdk-runtime-DWCvhJGu.mjs} +1 -1
  161. package/dist/server/components.mjs +18663 -18510
  162. package/dist/server/config-validation.mjs +450 -215
  163. package/dist/server/config.mjs +450 -215
  164. package/dist/server/data.mjs +15940 -15705
  165. package/dist/server/index.mjs +227 -2
  166. package/dist/server/next.mjs +18643 -18490
  167. package/dist/server/page-converter.mjs +12588 -12477
  168. package/dist/server/prebuild.mjs +1 -1
  169. package/dist/server/rendering/server.mjs +18007 -17855
  170. package/dist/server/rendering.mjs +18677 -18516
  171. package/dist/server/routing.mjs +17747 -17469
  172. package/dist/server/server.mjs +539 -276
  173. package/dist/server/theme-bridge.mjs +154 -37
  174. package/dist/server/theme.mjs +154 -37
  175. package/dist/{spinner-B-ab2rJp.mjs → spinner-BYM-Y81w.mjs} +1 -1
  176. package/package.json +1 -1
  177. package/dist/client/aspectTransforms-D-TnDdq4.mjs +0 -93
  178. package/dist/client/colorStyles-ECDNPE_P.mjs +0 -1253
@@ -1,5 +1,4 @@
1
- import { A as themeColorTokenSchema, C as paletteColorsSchema, D as requirePaletteColorsFromEntries, E as paletteValueKeySchema, N as err$1, O as parseThemeColorToken, P as ok$1, S as paletteColorsFromEntries, T as paletteValueKey, _ as buttonSystemSchema, b as hexColorSchema, c as tokenOrCssColorValueSchema, d as mapButtonRoleAppearances, f as mapButtonVisualAppearances, g as buttonSizeNameSchema, h as VARIANT_ROLES, i as opaqueSurfaceDeclarations, k as themeColorShadeSteps, l as PUBLIC_BUTTON_ROLES, p as resolveButtonStyleRecipe, u as defineButtonStyleRecipe, v as buttonVisualStatesSchema, w as paletteModeSchema, x as paletteColorEntries, y as unsafeAsOpaqueButtonColourToken } from "./colorStyles-ECDNPE_P.mjs";
2
- import { a as parseEventOfferingId, i as parseContentVersionId, n as parseAspectRatioValue, o as parseEventSeriesId } from "./aspectTransforms-D-TnDdq4.mjs";
1
+ import { _ as err$1, c as parseEventSeriesId, i as mediaIdentifierSchema, n as renderableMediaAssetSchema, o as parseContentVersionId, s as parseEventOfferingId, v as ok$1 } from "./renderableMediaAssetAdmission-CHkXYDC_.mjs";
3
2
  import "react";
4
3
  import { z } from "zod";
5
4
  import "react/jsx-runtime";
@@ -834,7 +833,7 @@ function parsePositiveInteger(value) {
834
833
  return typeof value === "number" && Number.isSafeInteger(value) && value > 0 ? value : null;
835
834
  }
836
835
  function parseNewsletterListId(value) {
837
- return parseTrimmedMatchingString(value, UUID_PATTERN);
836
+ return parseTrimmedMatchingString(typeof value === "string" ? value.toLowerCase() : value, UUID_PATTERN);
838
837
  }
839
838
  function parseMailchimpAudienceId(value) {
840
839
  return parseTrimmedMatchingString(value, OPAQUE_ID_PATTERN);
@@ -848,8 +847,15 @@ function parseBrevoListId(value) {
848
847
  //#endregion
849
848
  //#region ../core/src/mailing-list-setup.ts
850
849
  const DEFAULT_MAILING_LIST_SUCCESS_MESSAGE = "Thanks — you're on the list.";
851
- //#endregion
852
- //#region ../core/src/mailing-list-setup-parser.ts
850
+ z.unknown().transform((value, ctx) => {
851
+ const parsed = parseNewsletterAudience(value);
852
+ if (parsed.ok) return parsed.value;
853
+ ctx.addIssue({
854
+ code: "custom",
855
+ message: "Choose a valid newsletter audience."
856
+ });
857
+ return z.NEVER;
858
+ });
853
859
  function parseMailingListGlobalForm(value) {
854
860
  if (!isRecord$8(value)) return formError("shape");
855
861
  const fields = parseGlobalFields(value.fields);
@@ -869,6 +875,16 @@ function parseMailingListGlobalForm(value) {
869
875
  privacyNote
870
876
  });
871
877
  }
878
+ function parseNewsletterAudience(value) {
879
+ if (!isRecord$8(value)) return err$1("invalid_newsletter_audience");
880
+ if (value.kind === "general" && Object.keys(value).length === 1) return ok$1({ kind: "general" });
881
+ if (value.kind !== "topic" || Object.keys(value).some((key) => key !== "kind" && key !== "topicId")) return err$1("invalid_newsletter_audience");
882
+ const topicId = parseNewsletterListId(value.topicId);
883
+ return topicId === null ? err$1("invalid_newsletter_audience") : ok$1({
884
+ kind: "topic",
885
+ topicId
886
+ });
887
+ }
872
888
  function parseGlobalFields(value) {
873
889
  if (!isRecord$8(value) || typeof value.preset !== "string") return null;
874
890
  switch (value.preset) {
@@ -921,54 +937,49 @@ function formError(field) {
921
937
  const DEFAULT_MAILING_LIST_TARGETING = { mode: "default" };
922
938
  function mailingListTargetingChoiceIds(targeting) {
923
939
  switch (targeting.provider) {
924
- case "native": return targeting.selection.tag === "fixed" ? targeting.selection.topicIds : targeting.selection.offeredTopicIds;
940
+ case "native": return targeting.selection.tag === "general" ? [] : targeting.selection.tag === "fixed" ? targeting.selection.topicIds : targeting.selection.offeredTopicIds;
925
941
  case "brevo": return targeting.selection.tag === "fixed" ? targeting.selection.listIds : targeting.selection.offeredListIds;
926
942
  case "mailchimp": return targeting.selection.tag === "fixed" ? targeting.selection.interestIds : targeting.selection.offeredInterestIds;
927
943
  }
928
944
  }
929
945
  function planMailingListChoicePresentation(targeting) {
930
- if (targeting.mode === "default" || targeting.selection.tag === "fixed") return { tag: "hidden" };
946
+ if (targeting.mode === "default" || targeting.selection.tag === "fixed" || targeting.selection.tag === "general") return { tag: "hidden" };
931
947
  switch (targeting.provider) {
932
- case "native": return targeting.selection.offeredTopicIds.length === 1 ? {
933
- tag: "automatic",
934
- selection: {
935
- provider: "native",
936
- topicIds: targeting.selection.offeredTopicIds
937
- }
938
- } : {
939
- tag: "visitor_choice",
948
+ case "native": return presentVisitorSelection({
940
949
  provider: "native",
941
- optionCount: targeting.selection.offeredTopicIds.length
942
- };
943
- case "brevo": return targeting.selection.offeredListIds.length === 1 ? {
944
- tag: "automatic",
945
- selection: {
946
- provider: "brevo",
947
- listIds: targeting.selection.offeredListIds
948
- }
949
- } : {
950
- tag: "visitor_choice",
950
+ topicIds: targeting.selection.offeredTopicIds
951
+ }, targeting.selection.offeredTopicIds.length);
952
+ case "brevo": return presentVisitorSelection({
951
953
  provider: "brevo",
952
- optionCount: targeting.selection.offeredListIds.length
953
- };
954
- case "mailchimp": return targeting.selection.offeredInterestIds.length === 1 ? {
955
- tag: "automatic",
956
- selection: {
957
- provider: "mailchimp",
958
- interestIds: targeting.selection.offeredInterestIds
959
- }
960
- } : {
961
- tag: "visitor_choice",
954
+ listIds: targeting.selection.offeredListIds
955
+ }, targeting.selection.offeredListIds.length);
956
+ case "mailchimp": return presentVisitorSelection({
962
957
  provider: "mailchimp",
963
- optionCount: targeting.selection.offeredInterestIds.length
964
- };
958
+ interestIds: targeting.selection.offeredInterestIds
959
+ }, targeting.selection.offeredInterestIds.length);
965
960
  }
966
961
  }
962
+ function presentVisitorSelection(selection, optionCount) {
963
+ return optionCount === 1 ? {
964
+ tag: "automatic",
965
+ selection
966
+ } : {
967
+ tag: "visitor_choice",
968
+ provider: selection.provider,
969
+ optionCount
970
+ };
971
+ }
967
972
  //#endregion
968
973
  //#region ../core/src/mailing-list-targeting-availability.ts
969
974
  function resolveMailingListDefaultDestination(provider) {
970
975
  switch (provider.provider) {
971
- case "native": return provider.topics.find((item) => item.id === provider.defaultTopicId) ?? null;
976
+ case "native": {
977
+ const audience = provider.defaultAudience;
978
+ return audience.kind === "general" ? {
979
+ id: "general",
980
+ name: "General mailing list"
981
+ } : provider.topics.find((item) => item.id === audience.topicId) ?? null;
982
+ }
972
983
  case "brevo": return provider.lists.find((item) => item.id === provider.defaultListId) ?? null;
973
984
  case "mailchimp": return provider.audiences.find((item) => item.id === provider.defaultAudienceId) ?? null;
974
985
  }
@@ -1110,11 +1121,12 @@ function parseRuntimeProvider(value) {
1110
1121
  }
1111
1122
  }
1112
1123
  function parseNativeRuntimeProvider(value) {
1113
- const defaultTopicId = parseNewsletterListId(value.defaultTopicId);
1124
+ if ("defaultTopicId" in value) return null;
1125
+ const defaultAudience = parseNewsletterAudience(value.defaultAudience);
1114
1126
  const topics = parseNamedItems(value.topics, parseNewsletterListId);
1115
- return defaultTopicId !== null && topics !== null ? {
1127
+ return defaultAudience.ok && topics !== null ? {
1116
1128
  provider: "native",
1117
- defaultTopicId,
1129
+ defaultAudience: defaultAudience.value,
1118
1130
  topics
1119
1131
  } : null;
1120
1132
  }
@@ -1202,6 +1214,7 @@ function parseMailingListVisitorSelection(value) {
1202
1214
  if (!isRecord$6(value)) return visitorSelectionError("shape");
1203
1215
  switch (value.provider) {
1204
1216
  case "native": {
1217
+ if (Object.keys(value).some((key) => key !== "provider" && key !== "topicIds")) return visitorSelectionError("shape");
1205
1218
  const topicIds = parseVisitorIds(value.topicIds, parseNewsletterListId);
1206
1219
  return topicIds === null ? visitorSelectionError("targets") : ok$1({
1207
1220
  provider: "native",
@@ -1226,6 +1239,11 @@ function parseMailingListVisitorSelection(value) {
1226
1239
  }
1227
1240
  }
1228
1241
  function parseNativeTargeting(selection) {
1242
+ if (selection.tag === "general") return Object.keys(selection).length === 1 ? ok$1({
1243
+ mode: "custom",
1244
+ provider: "native",
1245
+ selection: { tag: "general" }
1246
+ }) : targetingError("selection");
1229
1247
  if (selection.tag === "fixed") {
1230
1248
  const topicIds = parseNonEmptyUniqueIds(selection.topicIds, parseNewsletterListId);
1231
1249
  return topicIds.ok ? ok$1({
@@ -1475,6 +1493,169 @@ const EVENT_PRESET_VOCABULARY = {
1475
1493
  }
1476
1494
  };
1477
1495
  //#endregion
1496
+ //#region ../media-core/src/mediaKinds.ts
1497
+ const mediaTypeDiscriminants = [
1498
+ "image",
1499
+ "video",
1500
+ "audio",
1501
+ "document",
1502
+ "spreadsheet",
1503
+ "archive"
1504
+ ];
1505
+ //#endregion
1506
+ //#region ../media-core/src/media.ts
1507
+ const hotspotSchema = z.object({
1508
+ x: z.number().min(0).max(1),
1509
+ y: z.number().min(0).max(1),
1510
+ radius: z.number().optional()
1511
+ });
1512
+ const rotationSchema = z.union([
1513
+ z.literal(0),
1514
+ z.literal(90),
1515
+ z.literal(180),
1516
+ z.literal(270)
1517
+ ]);
1518
+ const rectSchema = z.tuple([
1519
+ z.number(),
1520
+ z.number(),
1521
+ z.number(),
1522
+ z.number()
1523
+ ]);
1524
+ const aspectCropSchema = z.object({
1525
+ aspect: z.preprocess((value) => value == null ? void 0 : value, z.string().optional()),
1526
+ rect: z.preprocess((value) => value == null ? void 0 : value, rectSchema.optional()),
1527
+ hotspot: z.preprocess((value) => value == null ? void 0 : value, hotspotSchema.optional()),
1528
+ rotation: z.preprocess((value) => value == null ? void 0 : value, rotationSchema.optional())
1529
+ });
1530
+ const transformSchema = z.object({
1531
+ aspectCrops: z.preprocess((value) => {
1532
+ if (!value || typeof value !== "object" || Array.isArray(value)) return;
1533
+ return value;
1534
+ }, z.record(z.string(), aspectCropSchema.catch({}))).optional(),
1535
+ rect: rectSchema.optional(),
1536
+ hotspot: hotspotSchema.optional(),
1537
+ rotation: rotationSchema.optional()
1538
+ });
1539
+ const mediaPosterSchema = z.discriminatedUnion("tag", [z.object({
1540
+ tag: z.literal("media"),
1541
+ identifier: mediaIdentifierSchema
1542
+ }).strict(), z.object({
1543
+ tag: z.literal("external-src"),
1544
+ src: z.string().url()
1545
+ }).strict()]);
1546
+ const mediaUsageShape = {
1547
+ purpose: z.string().optional(),
1548
+ placeholder: z.boolean().default(true).optional(),
1549
+ alt: z.string().optional(),
1550
+ filename: z.string().optional(),
1551
+ width: z.number().optional(),
1552
+ height: z.number().optional(),
1553
+ poster: mediaPosterSchema.optional(),
1554
+ transform: transformSchema.optional()
1555
+ };
1556
+ const environmentExclusions = {
1557
+ assetId: z.never().optional(),
1558
+ id: z.never().optional(),
1559
+ src: z.never().optional(),
1560
+ storageBucket: z.never().optional(),
1561
+ storagePath: z.never().optional(),
1562
+ mimeType: z.never().optional()
1563
+ };
1564
+ const mediaBaseSchema = z.object({
1565
+ ...mediaUsageShape,
1566
+ ...environmentExclusions,
1567
+ identifier: mediaIdentifierSchema
1568
+ }).strict();
1569
+ const imageMediaSchema = mediaBaseSchema.extend({ type: z.literal("image") });
1570
+ const videoMediaSchema = mediaBaseSchema.extend({ type: z.literal("video") });
1571
+ const mediaSchema = mediaBaseSchema.extend({ type: z.enum(mediaTypeDiscriminants) });
1572
+ const externalMediaSchema = z.object({
1573
+ ...mediaUsageShape,
1574
+ ...environmentExclusions,
1575
+ type: z.enum(mediaTypeDiscriminants),
1576
+ src: z.string().min(1),
1577
+ identifier: z.never().optional()
1578
+ }).strict();
1579
+ const assetMediaSchema = z.object({
1580
+ ...mediaUsageShape,
1581
+ ...environmentExclusions,
1582
+ type: z.enum(mediaTypeDiscriminants),
1583
+ asset: renderableMediaAssetSchema,
1584
+ identifier: z.never().optional()
1585
+ }).strict();
1586
+ const runtimeMediaSchema = z.union([
1587
+ mediaSchema,
1588
+ externalMediaSchema,
1589
+ assetMediaSchema
1590
+ ]);
1591
+ //#endregion
1592
+ //#region ../media-core/src/transformRect.ts
1593
+ function isValidTransformRectStructure(rect) {
1594
+ if (!Array.isArray(rect) || rect.length !== 4) return false;
1595
+ const [left, top, width, height] = rect;
1596
+ return Number.isFinite(left) && Number.isFinite(top) && Number.isFinite(width) && Number.isFinite(height) && left >= 0 && top >= 0 && width > 0 && height > 0;
1597
+ }
1598
+ //#endregion
1599
+ //#region ../media-core/src/aspectTransforms.ts
1600
+ const DEFAULT_RECT_EPSILON = .5;
1601
+ function parseAspectRatioValue(value) {
1602
+ if (typeof value === "number") return Number.isFinite(value) && value > 0 ? value : void 0;
1603
+ if (typeof value !== "string") return void 0;
1604
+ const normalized = value.trim();
1605
+ if (!normalized) return void 0;
1606
+ if (normalized === "auto") return void 0;
1607
+ if (normalized.includes(":") || normalized.includes("/")) {
1608
+ const delimiter = normalized.includes(":") ? ":" : "/";
1609
+ const [wRaw, hRaw] = normalized.split(delimiter);
1610
+ const width = Number(wRaw?.trim());
1611
+ const height = Number(hRaw?.trim());
1612
+ if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) return;
1613
+ return width / height;
1614
+ }
1615
+ const numeric = Number(normalized);
1616
+ if (!Number.isFinite(numeric) || numeric <= 0) return void 0;
1617
+ return numeric;
1618
+ }
1619
+ const MAX_ASPECT_DISTANCE = .25;
1620
+ function resolveMediaTransformForAspect(transform, targetAspect) {
1621
+ if (!transform) return {};
1622
+ const base = {
1623
+ rect: transform.rect,
1624
+ hotspot: transform.hotspot,
1625
+ rotation: transform.rotation
1626
+ };
1627
+ const target = parseAspectRatioValue(targetAspect);
1628
+ const crops = transform.aspectCrops;
1629
+ if (!target || !crops || Object.keys(crops).length === 0) return base;
1630
+ let best = null;
1631
+ let bestDistance = Number.POSITIVE_INFINITY;
1632
+ for (const [key, candidate] of Object.entries(crops)) {
1633
+ const candidateAspect = parseAspectRatioValue(candidate.aspect ?? key);
1634
+ if (!candidateAspect) continue;
1635
+ const distance = Math.abs(Math.log(candidateAspect / target));
1636
+ if (distance < bestDistance) {
1637
+ best = candidate;
1638
+ bestDistance = distance;
1639
+ }
1640
+ }
1641
+ if (!best) return base;
1642
+ if (bestDistance > MAX_ASPECT_DISTANCE) return base;
1643
+ return {
1644
+ rect: best.rect ?? base.rect,
1645
+ hotspot: best.hotspot ?? base.hotspot,
1646
+ rotation: best.rotation ?? base.rotation
1647
+ };
1648
+ }
1649
+ function isValidTransformRect(rect) {
1650
+ return isValidTransformRectStructure(rect);
1651
+ }
1652
+ function isExplicitRectCrop(rect, sourceWidth, sourceHeight, epsilon = DEFAULT_RECT_EPSILON) {
1653
+ if (!isValidTransformRect(rect)) return false;
1654
+ if (!(typeof sourceWidth === "number" && Number.isFinite(sourceWidth) && sourceWidth > 0 && typeof sourceHeight === "number" && Number.isFinite(sourceHeight) && sourceHeight > 0)) return true;
1655
+ const [x, y, width, height] = rect;
1656
+ return !(Math.abs(x) <= epsilon && Math.abs(y) <= epsilon && Math.abs(width - sourceWidth) <= epsilon && Math.abs(height - sourceHeight) <= epsilon);
1657
+ }
1658
+ //#endregion
1478
1659
  //#region ../commerce/src/utils/assertNever.ts
1479
1660
  function assertNever$3(value, message) {
1480
1661
  if (message) throw new Error(message);
@@ -2048,6 +2229,606 @@ function checkBrowserStripeKey(publishableKey, livemode) {
2048
2229
  };
2049
2230
  }
2050
2231
  //#endregion
2232
+ //#region ../../node_modules/.pnpm/clsx@2.1.1/node_modules/clsx/dist/clsx.mjs
2233
+ function r(e) {
2234
+ var t, f, n = "";
2235
+ if ("string" == typeof e || "number" == typeof e) n += e;
2236
+ else if ("object" == typeof e) if (Array.isArray(e)) {
2237
+ var o = e.length;
2238
+ for (t = 0; t < o; t++) e[t] && (f = r(e[t])) && (n && (n += " "), n += f);
2239
+ } else for (f in e) e[f] && (n && (n += " "), n += f);
2240
+ return n;
2241
+ }
2242
+ function clsx() {
2243
+ for (var e, t, f = 0, n = "", o = arguments.length; f < o; f++) (e = arguments[f]) && (t = r(e)) && (n && (n += " "), n += t);
2244
+ return n;
2245
+ }
2246
+ //#endregion
2247
+ //#region ../theme-core/src/tokens/colorTokenParts.ts
2248
+ function parseOpacityPercent(source) {
2249
+ const trimmed = source.trim();
2250
+ if (!trimmed) return null;
2251
+ if (!/^\d{1,3}(?:\.\d+)?$/.test(trimmed)) return null;
2252
+ const value = Number(trimmed);
2253
+ if (!Number.isFinite(value)) return null;
2254
+ if (value < 0 || value > 100) return null;
2255
+ return value;
2256
+ }
2257
+ function parseColorTokenParts(source) {
2258
+ const trimmed = source.trim();
2259
+ if (trimmed.startsWith("raw:")) return {
2260
+ kind: "raw",
2261
+ value: trimmed.slice(4)
2262
+ };
2263
+ const [token, opacityRaw, extra] = trimmed.split("/");
2264
+ if (!token || extra !== void 0) return {
2265
+ kind: "invalid",
2266
+ token: trimmed
2267
+ };
2268
+ if (opacityRaw === void 0) return {
2269
+ kind: "token",
2270
+ token,
2271
+ opacityPercent: null
2272
+ };
2273
+ const opacityPercent = parseOpacityPercent(opacityRaw);
2274
+ if (opacityPercent === null) return {
2275
+ kind: "invalid",
2276
+ token: trimmed
2277
+ };
2278
+ return {
2279
+ kind: "token",
2280
+ token,
2281
+ opacityPercent
2282
+ };
2283
+ }
2284
+ //#endregion
2285
+ //#region ../theme-core/src/tokens/blockColorTokens.ts
2286
+ const blockColorTokenNames = [
2287
+ "text",
2288
+ "heading",
2289
+ "mutedText",
2290
+ "surface",
2291
+ "background",
2292
+ "foreground",
2293
+ "border",
2294
+ "primary",
2295
+ "secondary",
2296
+ "accent",
2297
+ "success",
2298
+ "warning",
2299
+ "info",
2300
+ "error",
2301
+ "destructive",
2302
+ "scrim",
2303
+ "shadow",
2304
+ "onPrimary",
2305
+ "onSecondary",
2306
+ "onAccent",
2307
+ "onSuccess",
2308
+ "onWarning",
2309
+ "onInfo",
2310
+ "onError",
2311
+ "onDestructive",
2312
+ "onSurface",
2313
+ "onText"
2314
+ ];
2315
+ new Set(blockColorTokenNames);
2316
+ //#endregion
2317
+ //#region ../theme-core/src/tokens/themeColorTokens.ts
2318
+ /**
2319
+ * Known palette role token names. This is the low-level source of truth for
2320
+ * palette roles used by palette variants, Theme V2 schemas, and runtime color
2321
+ * reference parsing.
2322
+ */
2323
+ const PALETTE_TOKEN_NAMES = [
2324
+ "primary",
2325
+ "primaryForeground",
2326
+ "secondary",
2327
+ "accent",
2328
+ "success",
2329
+ "warning",
2330
+ "destructive",
2331
+ "background",
2332
+ "surface",
2333
+ "surfaceAlt",
2334
+ "muted",
2335
+ "text",
2336
+ "border"
2337
+ ];
2338
+ const paletteTokenNameSchema = z.enum(PALETTE_TOKEN_NAMES);
2339
+ const themeColorBaseTokenNames = [
2340
+ ...PALETTE_TOKEN_NAMES,
2341
+ ...blockColorTokenNames,
2342
+ "white",
2343
+ "neutral",
2344
+ "primaryText",
2345
+ "secondaryForeground",
2346
+ "accentForeground"
2347
+ ];
2348
+ const themeColorBaseTokenSet = new Set(themeColorBaseTokenNames);
2349
+ const themeColorShadeSteps = [
2350
+ "50",
2351
+ "100",
2352
+ "200",
2353
+ "300",
2354
+ "400",
2355
+ "500",
2356
+ "600",
2357
+ "700",
2358
+ "800",
2359
+ "900",
2360
+ "950"
2361
+ ];
2362
+ const shadeStepSet = new Set(themeColorShadeSteps);
2363
+ function isKnownBaseToken(value) {
2364
+ return themeColorBaseTokenSet.has(value);
2365
+ }
2366
+ function isKnownShadeToken(value) {
2367
+ const match = value.match(/^([a-zA-Z][a-zA-Z0-9]*)(?:-([0-9]{2,3}))$/);
2368
+ if (!match) return false;
2369
+ const [, base, shade] = match;
2370
+ return Boolean(base && shade && isKnownBaseToken(base) && shadeStepSet.has(shade));
2371
+ }
2372
+ function isThemeColorTokenBase(value) {
2373
+ return isKnownBaseToken(value) || isKnownShadeToken(value);
2374
+ }
2375
+ function isThemeColorToken(value) {
2376
+ if (typeof value !== "string") return false;
2377
+ const parts = parseColorTokenParts(value);
2378
+ return parts.kind === "token" && isThemeColorTokenBase(parts.token);
2379
+ }
2380
+ function parseThemeColorToken(value) {
2381
+ if (!isThemeColorToken(value)) return null;
2382
+ return value.trim();
2383
+ }
2384
+ const themeColorTokenSchema = z.string().min(1).refine((value) => Boolean(isThemeColorToken(value)), "Expected a known Theme V2 color token");
2385
+ //#endregion
2386
+ //#region ../theme-core/src/buttons/types.ts
2387
+ /**
2388
+ * Standard semantic variant roles a theme exposes.
2389
+ *
2390
+ * Block content references variants by role; the active theme determines
2391
+ * what each role looks like.
2392
+ */
2393
+ const VARIANT_ROLES = [
2394
+ "primary",
2395
+ "secondary",
2396
+ "outline",
2397
+ "ghost",
2398
+ "accent"
2399
+ ];
2400
+ /**
2401
+ * Canonical persisted/CSS-safe button variant identifier.
2402
+ *
2403
+ * IDs become class selectors, so keep the contract deliberately narrower than
2404
+ * an arbitrary string and shared with every authoring/runtime boundary.
2405
+ */
2406
+ const buttonVariantIdSchema = z.string().min(1).max(50).regex(/^[a-z0-9-]+$/, "Button variant IDs may contain lowercase letters, numbers, and hyphens only").refine((value) => value !== "link" && value !== "tertiary", { message: "Retired button role IDs are not valid variant IDs" });
2407
+ function parseOpaqueButtonColourToken(value) {
2408
+ const token = parseThemeColorToken(value);
2409
+ if (token === null) return null;
2410
+ const parts = parseColorTokenParts(token);
2411
+ return parts.kind === "token" && parts.opacityPercent === null ? token : null;
2412
+ }
2413
+ function unsafeAsOpaqueButtonColourToken(value) {
2414
+ return value;
2415
+ }
2416
+ const opaqueButtonColourTokenSchema = themeColorTokenSchema.refine((value) => parseOpaqueButtonColourToken(value) !== null, "Button colour tokens must be opaque").transform((value) => {
2417
+ const token = parseOpaqueButtonColourToken(value);
2418
+ if (token === null) throw new Error("Invariant: opaque button token passed its schema");
2419
+ return token;
2420
+ });
2421
+ const contextualButtonHoverSchema = z.strictObject({
2422
+ kind: z.literal("shade-shift"),
2423
+ seedToken: opaqueButtonColourTokenSchema,
2424
+ fallbackDirection: z.enum(["lighter", "darker"]),
2425
+ preferredToken: opaqueButtonColourTokenSchema.optional()
2426
+ });
2427
+ const buttonShadeAmountSchema = z.number().finite().min(0).max(900).multipleOf(100);
2428
+ const buttonShadowIntensitySchema = z.enum([
2429
+ "subtle",
2430
+ "medium",
2431
+ "strong"
2432
+ ]);
2433
+ /**
2434
+ * The complete persisted button-effect contract.
2435
+ *
2436
+ * Navigation has its own generic interactive-effect model. Button variants use
2437
+ * this closed union so unsupported effect IDs, unknown option keys, and unsafe
2438
+ * CSS values cannot become representable after the schema boundary.
2439
+ */
2440
+ const buttonPressOffsetSchema = z.strictObject({
2441
+ x: z.number().int().min(0).max(12),
2442
+ y: z.number().int().min(0).max(12)
2443
+ });
2444
+ const buttonEffectApplicationSchema = z.discriminatedUnion("effectId", [
2445
+ z.strictObject({
2446
+ effectId: z.literal("darken-background"),
2447
+ options: z.strictObject({ amount: buttonShadeAmountSchema.optional() }).optional()
2448
+ }),
2449
+ z.strictObject({
2450
+ effectId: z.literal("lighten-background"),
2451
+ options: z.strictObject({ amount: buttonShadeAmountSchema.optional() }).optional()
2452
+ }),
2453
+ z.strictObject({
2454
+ effectId: z.literal("background-on-hover"),
2455
+ options: z.strictObject({ colorToken: opaqueButtonColourTokenSchema.optional() }).optional()
2456
+ }),
2457
+ z.strictObject({
2458
+ effectId: z.literal("animated-gradient"),
2459
+ options: z.strictObject({ direction: z.enum(["horizontal", "vertical"]).optional() }).optional()
2460
+ }),
2461
+ z.strictObject({
2462
+ effectId: z.literal("drop-shadow"),
2463
+ options: z.strictObject({ intensity: buttonShadowIntensitySchema.optional() }).optional()
2464
+ }),
2465
+ z.strictObject({
2466
+ effectId: z.literal("inner-shadow"),
2467
+ options: z.strictObject({}).optional()
2468
+ }),
2469
+ z.strictObject({
2470
+ effectId: z.literal("neumorphic-shadow"),
2471
+ options: z.strictObject({
2472
+ mode: z.enum(["raised", "pressed"]).optional(),
2473
+ intensity: buttonShadowIntensitySchema.optional()
2474
+ }).optional()
2475
+ }),
2476
+ z.strictObject({
2477
+ effectId: z.literal("retro-3d-shadow"),
2478
+ options: z.strictObject({}).optional()
2479
+ }),
2480
+ z.strictObject({
2481
+ effectId: z.literal("scale-up"),
2482
+ options: z.strictObject({ scale: z.enum([
2483
+ "1.02",
2484
+ "1.03",
2485
+ "1.05",
2486
+ "1.10"
2487
+ ]).optional() }).optional()
2488
+ }),
2489
+ z.strictObject({
2490
+ effectId: z.literal("scale-down"),
2491
+ options: z.strictObject({ scale: z.enum([
2492
+ "0.90",
2493
+ "0.95",
2494
+ "0.97",
2495
+ "0.98"
2496
+ ]).optional() }).optional()
2497
+ }),
2498
+ z.strictObject({
2499
+ effectId: z.literal("lift"),
2500
+ options: z.strictObject({ amount: z.enum([
2501
+ "0.25",
2502
+ "0.5",
2503
+ "1"
2504
+ ]).optional() }).optional()
2505
+ }),
2506
+ z.strictObject({
2507
+ effectId: z.literal("press-down"),
2508
+ options: z.strictObject({ offset: buttonPressOffsetSchema.optional() }).optional()
2509
+ }),
2510
+ z.strictObject({
2511
+ effectId: z.literal("pop"),
2512
+ options: z.strictObject({ intensity: z.enum([
2513
+ "subtle",
2514
+ "medium",
2515
+ "dramatic"
2516
+ ]).optional() }).optional()
2517
+ }),
2518
+ z.strictObject({
2519
+ effectId: z.literal("border-bottom-grow"),
2520
+ options: z.strictObject({
2521
+ height: z.union([z.literal(1), z.literal(2)]).optional(),
2522
+ origin: z.enum([
2523
+ "left",
2524
+ "center",
2525
+ "right"
2526
+ ]).optional(),
2527
+ persistent: z.boolean().optional(),
2528
+ colourRole: z.literal("mark").optional()
2529
+ }).optional()
2530
+ }),
2531
+ z.strictObject({
2532
+ effectId: z.literal("sketchy-border"),
2533
+ options: z.strictObject({ intensity: buttonShadowIntensitySchema.optional() }).optional()
2534
+ })
2535
+ ]);
2536
+ const cornerStyleSchema = z.enum([
2537
+ "square",
2538
+ "rounded",
2539
+ "pill"
2540
+ ]);
2541
+ const shadowSizeSchema = z.enum([
2542
+ "none",
2543
+ "low",
2544
+ "medium",
2545
+ "high"
2546
+ ]);
2547
+ const textTransformSchema = z.enum([
2548
+ "none",
2549
+ "uppercase",
2550
+ "lowercase",
2551
+ "capitalize"
2552
+ ]);
2553
+ const fontWeightSchema = z.union([
2554
+ z.literal(500),
2555
+ z.literal(600),
2556
+ z.literal(700),
2557
+ z.literal(800)
2558
+ ]);
2559
+ const buttonTypographySchema = z.enum(["body", "heading"]);
2560
+ const letterSpacingSchema = z.enum([
2561
+ "tight",
2562
+ "normal",
2563
+ "loose"
2564
+ ]);
2565
+ const hoverTransformSchema = z.enum([
2566
+ "none",
2567
+ "lift",
2568
+ "scale",
2569
+ "press"
2570
+ ]);
2571
+ z.enum(["none", "token"]);
2572
+ const buttonPaddingPresetSchema = z.enum([
2573
+ "compact",
2574
+ "default",
2575
+ "spacious"
2576
+ ]);
2577
+ const gradientStyleSchema = z.enum([
2578
+ "linear",
2579
+ "radial",
2580
+ "conic"
2581
+ ]);
2582
+ const gradientSharpnessSchema = z.enum([
2583
+ "smooth",
2584
+ "medium",
2585
+ "hard"
2586
+ ]);
2587
+ const prioritySchema = z.union([
2588
+ z.literal(1),
2589
+ z.literal(2),
2590
+ z.literal(3)
2591
+ ]);
2592
+ const variantRoleSchema = z.enum(VARIANT_ROLES);
2593
+ const buttonSurfaceFallbackSchema = z.discriminatedUnion("kind", [z.strictObject({ kind: z.literal("surface-outline") }), z.strictObject({
2594
+ kind: z.literal("variant"),
2595
+ role: variantRoleSchema
2596
+ })]);
2597
+ const standardButtonSurfacePolicy = {
2598
+ primary: [{ kind: "surface-outline" }],
2599
+ secondary: [{ kind: "surface-outline" }, {
2600
+ kind: "variant",
2601
+ role: "primary"
2602
+ }],
2603
+ outline: [{ kind: "surface-outline" }],
2604
+ ghost: [{ kind: "surface-outline" }],
2605
+ accent: [{ kind: "surface-outline" }, {
2606
+ kind: "variant",
2607
+ role: "primary"
2608
+ }]
2609
+ };
2610
+ const STANDARD_BUTTON_SURFACE_POLICY = Object.freeze(Object.fromEntries(VARIANT_ROLES.map((role) => [role, Object.freeze([...standardButtonSurfacePolicy[role]])])));
2611
+ function createStandardButtonSurfacePolicy() {
2612
+ return Object.fromEntries(VARIANT_ROLES.map((role) => [role, [...STANDARD_BUTTON_SURFACE_POLICY[role]]]));
2613
+ }
2614
+ const buttonSurfacePolicyShape = Object.fromEntries(VARIANT_ROLES.map((role) => [role, z.array(buttonSurfaceFallbackSchema).max(VARIANT_ROLES.length)]));
2615
+ const buttonSurfacePolicySchema = z.strictObject(buttonSurfacePolicyShape);
2616
+ const buttonSizeNameSchema = z.enum([
2617
+ "sm",
2618
+ "md",
2619
+ "lg",
2620
+ "xl"
2621
+ ]);
2622
+ /**
2623
+ * CSS padding string in `"<vertical> <horizontal>"` shorthand form.
2624
+ *
2625
+ * Exactly two space-separated CSS length tokens. Each token is either the
2626
+ * literal `0` or a number followed by `rem`/`em`/`px`/`%`. This lets the
2627
+ * generator trust the shape rather than defensively defaulting downstream.
2628
+ */
2629
+ const PADDING_TOKEN_PATTERN = /^(?:0|\d+(?:\.\d+)?(?:rem|em|px|%))$/;
2630
+ const paddingShorthandSchema = z.string().refine((value) => {
2631
+ const parts = value.split(/\s+/).filter(Boolean);
2632
+ return parts.length === 2 && parts.every((token) => PADDING_TOKEN_PATTERN.test(token));
2633
+ }, { message: "Padding must be two space-separated CSS length tokens (e.g. \"0.5rem 1rem\"). Use `0` for zero." });
2634
+ const buttonSizeConfigSchema = z.object({
2635
+ padding: paddingShorthandSchema,
2636
+ fontSize: z.string().optional()
2637
+ });
2638
+ /**
2639
+ * `xl` is optional on the wire so themes persisted before the `xl` size was
2640
+ * added (e.g. SWTS) continue to parse. When `xl` is missing the schema
2641
+ * backfills it from `lg`, keeping `ButtonSizes` a complete `sm/md/lg/xl` map
2642
+ * downstream — generators never need to deal with an undefined `xl`.
2643
+ */
2644
+ const buttonSizesSchema = z.object({
2645
+ sm: buttonSizeConfigSchema,
2646
+ md: buttonSizeConfigSchema,
2647
+ lg: buttonSizeConfigSchema,
2648
+ xl: buttonSizeConfigSchema.optional()
2649
+ }).transform(({ sm, md, lg, xl }) => ({
2650
+ sm,
2651
+ md,
2652
+ lg,
2653
+ xl: xl ?? lg
2654
+ }));
2655
+ const buttonGlobalSettingsBaseSchema = z.strictObject({
2656
+ cornerStyle: cornerStyleSchema,
2657
+ cornerRadius: z.number().min(0).max(24).optional(),
2658
+ /**
2659
+ * Family-level shadow inherited by variants that don't set their own.
2660
+ * Optional and flat-by-default: when omitted, buttons carry no drop shadow
2661
+ * (`elevation: 'none'`). A personality opts the whole family into a shadow by
2662
+ * setting this; individual variants still override. There is no system-level
2663
+ * shadow-by-default — shadows only appear when explicitly declared.
2664
+ */
2665
+ shadow: shadowSizeSchema.optional(),
2666
+ textTransform: textTransformSchema,
2667
+ fontWeight: fontWeightSchema,
2668
+ typography: buttonTypographySchema.optional(),
2669
+ fontSize: z.string().optional(),
2670
+ letterSpacing: letterSpacingSchema.optional(),
2671
+ italic: z.boolean().optional(),
2672
+ paddingPreset: buttonPaddingPresetSchema.optional(),
2673
+ hoverTransform: hoverTransformSchema,
2674
+ gradientStyle: gradientStyleSchema.optional(),
2675
+ gradientAngle: z.number().min(0).max(360).optional(),
2676
+ gradientSharpness: gradientSharpnessSchema.optional()
2677
+ });
2678
+ const buttonGlobalSettingsSchema = z.discriminatedUnion("hoverColor", [buttonGlobalSettingsBaseSchema.extend({
2679
+ hoverColor: z.literal("none"),
2680
+ hoverColorToken: z.never().optional()
2681
+ }), buttonGlobalSettingsBaseSchema.extend({
2682
+ hoverColor: z.literal("token"),
2683
+ hoverColorToken: opaqueButtonColourTokenSchema
2684
+ })]);
2685
+ const gradientDirectionSchema$1 = z.enum([
2686
+ "to-r",
2687
+ "to-l",
2688
+ "to-t",
2689
+ "to-b",
2690
+ "to-tr",
2691
+ "to-tl",
2692
+ "to-br",
2693
+ "to-bl"
2694
+ ]);
2695
+ const buttonColourTreatmentSchema = z.discriminatedUnion("type", [
2696
+ z.strictObject({
2697
+ type: z.literal("solid"),
2698
+ colorToken: opaqueButtonColourTokenSchema
2699
+ }),
2700
+ z.strictObject({
2701
+ type: z.literal("gradient"),
2702
+ stops: z.array(opaqueButtonColourTokenSchema).min(2).transform((stops) => {
2703
+ const [first, second, ...rest] = stops;
2704
+ if (first === void 0 || second === void 0) throw new Error("Invariant: gradient stops passed the minimum length schema");
2705
+ return [
2706
+ first,
2707
+ second,
2708
+ ...rest
2709
+ ];
2710
+ }),
2711
+ direction: gradientDirectionSchema$1,
2712
+ foregroundToken: opaqueButtonColourTokenSchema
2713
+ }),
2714
+ z.strictObject({
2715
+ type: z.literal("surface"),
2716
+ role: z.literal("link")
2717
+ })
2718
+ ]);
2719
+ const buttonBackgroundSchema = buttonColourTreatmentSchema;
2720
+ const buttonBorderSchema = z.strictObject({
2721
+ widthClass: z.string(),
2722
+ marksBoundary: z.literal(true).optional(),
2723
+ ring: z.literal(true).optional(),
2724
+ boundaryInk: opaqueButtonColourTokenSchema.optional()
2725
+ });
2726
+ const buttonVariantAffordanceSchema = z.strictObject({ iconId: z.string().min(1) });
2727
+ const variantShadowSchema = z.strictObject({
2728
+ elevation: z.enum([
2729
+ "none",
2730
+ "low",
2731
+ "medium",
2732
+ "high"
2733
+ ]),
2734
+ softness: z.enum([
2735
+ "crisp",
2736
+ "soft",
2737
+ "hard"
2738
+ ]).nullable(),
2739
+ position: z.enum(["bottom", "bottom-right"]).default("bottom"),
2740
+ colorToken: opaqueButtonColourTokenSchema.optional()
2741
+ });
2742
+ /** Recipe states own every visual property; treatment owns its readable label. */
2743
+ const buttonVisualAppearanceSchema = z.strictObject({
2744
+ background: buttonColourTreatmentSchema,
2745
+ text: z.literal("treatment"),
2746
+ border: z.union([z.literal("none"), buttonBorderSchema]),
2747
+ borderRadius: z.string(),
2748
+ shadow: z.union([z.literal("focus-indicator"), variantShadowSchema]),
2749
+ sizes: buttonSizesSchema,
2750
+ typography: z.strictObject({
2751
+ fontWeight: fontWeightSchema,
2752
+ typography: buttonTypographySchema,
2753
+ fontSize: z.string().nullable(),
2754
+ letterSpacing: z.union([letterSpacingSchema, z.literal("heading")]).nullable(),
2755
+ italic: z.boolean(),
2756
+ textTransform: textTransformSchema
2757
+ }),
2758
+ effects: z.array(buttonEffectApplicationSchema),
2759
+ contextualHover: contextualButtonHoverSchema.optional()
2760
+ });
2761
+ const buttonVisualStatesSchema = z.strictObject({
2762
+ base: buttonVisualAppearanceSchema.extend({ shadow: variantShadowSchema }),
2763
+ hover: buttonVisualAppearanceSchema.extend({ shadow: variantShadowSchema }),
2764
+ focus: buttonVisualAppearanceSchema.extend({ shadow: z.literal("focus-indicator") }),
2765
+ active: buttonVisualAppearanceSchema.extend({ shadow: variantShadowSchema }),
2766
+ disabled: buttonVisualAppearanceSchema.extend({ shadow: variantShadowSchema })
2767
+ });
2768
+ const variantEffectsSchema = z.strictObject({
2769
+ base: z.array(buttonEffectApplicationSchema).optional(),
2770
+ hover: z.array(buttonEffectApplicationSchema).optional(),
2771
+ active: z.array(buttonEffectApplicationSchema).optional(),
2772
+ focus: z.array(buttonEffectApplicationSchema).optional()
2773
+ });
2774
+ /**
2775
+ * Per-variant size overrides schema — every entry is optional.
2776
+ *
2777
+ * For each size key present, the values override the theme's `sizes` config
2778
+ * for that size on this variant. Missing sizes fall through to theme.sizes,
2779
+ * then system defaults.
2780
+ */
2781
+ const variantSizeOverridesSchema = z.object({
2782
+ sm: buttonSizeConfigSchema.optional(),
2783
+ md: buttonSizeConfigSchema.optional(),
2784
+ lg: buttonSizeConfigSchema.optional(),
2785
+ xl: buttonSizeConfigSchema.optional()
2786
+ });
2787
+ /**
2788
+ * Unified variant schema. Every variant participates in the size system; the
2789
+ * optional `sizes` field lets a variant scale differently than the theme
2790
+ * default (e.g. link-style variants declaring zero horizontal padding at
2791
+ * every size).
2792
+ */
2793
+ const buttonVariantSchema = z.strictObject({
2794
+ id: buttonVariantIdSchema,
2795
+ name: z.string().min(1).max(20),
2796
+ enabled: z.boolean(),
2797
+ priority: prioritySchema,
2798
+ visualStates: buttonVisualStatesSchema.optional(),
2799
+ background: buttonBackgroundSchema,
2800
+ /** Tailwind radius token (e.g. `'rounded-md'`). Omit to inherit from `global.cornerStyle`. */
2801
+ borderRadius: z.string().optional(),
2802
+ shadow: variantShadowSchema.optional(),
2803
+ border: buttonBorderSchema.optional(),
2804
+ hoverBackgroundToken: opaqueButtonColourTokenSchema.optional(),
2805
+ contextualHover: contextualButtonHoverSchema.optional(),
2806
+ effects: variantEffectsSchema.optional(),
2807
+ sizes: variantSizeOverridesSchema.optional(),
2808
+ affordance: buttonVariantAffordanceSchema.optional()
2809
+ });
2810
+ const buttonSystemSchema = z.strictObject({
2811
+ global: buttonGlobalSettingsSchema,
2812
+ variants: z.array(buttonVariantSchema).min(1).max(6),
2813
+ sizes: buttonSizesSchema.optional(),
2814
+ surfacePolicy: buttonSurfacePolicySchema.optional(),
2815
+ surfaceContexts: z.record(z.string(), z.strictObject({ primary: opaqueButtonColourTokenSchema })).optional()
2816
+ }).superRefine((system, ctx) => {
2817
+ const seen = /* @__PURE__ */ new Set();
2818
+ system.variants.forEach((variant, index) => {
2819
+ if (seen.has(variant.id)) ctx.addIssue({
2820
+ code: "custom",
2821
+ path: [
2822
+ "variants",
2823
+ index,
2824
+ "id"
2825
+ ],
2826
+ message: `Duplicate button variant ID: ${variant.id}`
2827
+ });
2828
+ seen.add(variant.id);
2829
+ });
2830
+ });
2831
+ //#endregion
2051
2832
  //#region ../theme-core/src/fonts/types.ts
2052
2833
  const fontWeightListSchema = z.array(z.number().int().min(100).max(900));
2053
2834
  const fontLoadingSchema = z.object({
@@ -2439,89 +3220,148 @@ const footerModeSchema = z.enum([
2439
3220
  "none"
2440
3221
  ]);
2441
3222
  //#endregion
2442
- //#region ../theme-core/src/lib/media.ts
2443
- const hotspotSchema = z.object({
2444
- x: z.number().min(0).max(1),
2445
- y: z.number().min(0).max(1),
2446
- radius: z.number().optional()
2447
- });
2448
- const rotationSchema = z.union([
2449
- z.literal(0),
2450
- z.literal(90),
2451
- z.literal(180),
2452
- z.literal(270)
2453
- ]);
2454
- const rectSchema = z.tuple([
2455
- z.number(),
2456
- z.number(),
2457
- z.number(),
2458
- z.number()
2459
- ]);
2460
- const aspectCropSchema = z.object({
2461
- aspect: z.preprocess((value) => value == null ? void 0 : value, z.string().optional()),
2462
- rect: z.preprocess((value) => value == null ? void 0 : value, rectSchema.optional()),
2463
- hotspot: z.preprocess((value) => value == null ? void 0 : value, hotspotSchema.optional()),
2464
- rotation: z.preprocess((value) => value == null ? void 0 : value, rotationSchema.optional())
2465
- });
2466
- const transformSchema = z.object({
2467
- aspectCrops: z.preprocess((value) => {
2468
- if (!value || typeof value !== "object" || Array.isArray(value)) return;
2469
- return value;
2470
- }, z.record(z.string(), aspectCropSchema.catch({}))).optional(),
2471
- rect: rectSchema.optional(),
2472
- hotspot: hotspotSchema.optional(),
2473
- rotation: rotationSchema.optional()
2474
- });
2475
- const mediaPosterSchema = z.discriminatedUnion("tag", [z.object({
2476
- tag: z.literal("storage"),
2477
- assetId: z.string().optional(),
2478
- storageBucket: z.string().min(1),
2479
- storagePath: z.string().min(1)
2480
- }), z.object({
2481
- tag: z.literal("external-src"),
2482
- assetId: z.string().optional(),
2483
- src: z.string().url()
2484
- })]);
2485
- const mediaBaseSchema = z.object({
2486
- purpose: z.string().optional(),
2487
- placeholder: z.boolean().default(true).optional(),
2488
- assetId: z.string().optional(),
2489
- identifier: z.string().optional(),
2490
- src: z.string().optional(),
2491
- alt: z.string().optional(),
2492
- filename: z.string().optional(),
2493
- mimeType: z.string().optional(),
2494
- width: z.number().optional(),
2495
- height: z.number().optional(),
2496
- storageBucket: z.string().optional(),
2497
- storagePath: z.string().optional(),
2498
- poster: mediaPosterSchema.optional(),
2499
- transform: transformSchema.optional()
3223
+ //#region ../theme-core/src/palette/colors.ts
3224
+ const HEX_COLOR_REGEX = /^#[0-9a-f]{6}$/;
3225
+ const NORMALIZABLE_HEX_REGEX = /^#(?:[0-9a-f]{3}|[0-9a-f]{6})$/i;
3226
+ const THEME_PALETTE_COLOR_ORDER = [
3227
+ "primary",
3228
+ "secondary",
3229
+ "accent",
3230
+ "success",
3231
+ "warning",
3232
+ "destructive",
3233
+ "background",
3234
+ "surface",
3235
+ "surfaceAlt",
3236
+ "muted",
3237
+ "text",
3238
+ "primaryForeground",
3239
+ "border"
3240
+ ];
3241
+ const hexColorSchema = z.string().regex(HEX_COLOR_REGEX, "Hex must be #RRGGBB (lowercase)").transform((value) => value);
3242
+ const paletteModeSchema = z.enum(["light", "dark"]);
3243
+ const PALETTE_VALUE_KEY_PREFIX = "palette-value:v1|";
3244
+ z.string().regex(/^[0-9a-f]{64}$/, "Palette hash must be a lowercase SHA-256 value").transform((value) => value);
3245
+ const paletteColorsSchema = z.object({
3246
+ primary: hexColorSchema,
3247
+ primaryForeground: hexColorSchema,
3248
+ secondary: hexColorSchema,
3249
+ accent: hexColorSchema,
3250
+ success: hexColorSchema,
3251
+ warning: hexColorSchema,
3252
+ destructive: hexColorSchema,
3253
+ background: hexColorSchema,
3254
+ surface: hexColorSchema,
3255
+ surfaceAlt: hexColorSchema,
3256
+ muted: hexColorSchema,
3257
+ text: hexColorSchema,
3258
+ border: hexColorSchema
3259
+ }).strict().transform((value) => value);
3260
+ function normalizePaletteHex(value) {
3261
+ if (!NORMALIZABLE_HEX_REGEX.test(value)) return null;
3262
+ const normalized = value.toLowerCase();
3263
+ if (normalized.length === 7) return normalized;
3264
+ const triplet = normalized.slice(1);
3265
+ const red = triplet.charAt(0);
3266
+ const green = triplet.charAt(1);
3267
+ const blue = triplet.charAt(2);
3268
+ return `#${red}${red}${green}${green}${blue}${blue}`;
3269
+ }
3270
+ function paletteColorsFromEntries(entries) {
3271
+ const values = {};
3272
+ for (const entry of entries) {
3273
+ const parsedRole = paletteTokenNameSchema.safeParse(entry.name);
3274
+ if (!parsedRole.success) return {
3275
+ ok: false,
3276
+ error: {
3277
+ kind: "unknown-role",
3278
+ role: entry.name
3279
+ }
3280
+ };
3281
+ const role = parsedRole.data;
3282
+ if (values[role] !== void 0) return {
3283
+ ok: false,
3284
+ error: {
3285
+ kind: "duplicate-role",
3286
+ role
3287
+ }
3288
+ };
3289
+ const hex = normalizePaletteHex(entry.hex);
3290
+ if (!hex) return {
3291
+ ok: false,
3292
+ error: {
3293
+ kind: "invalid-color",
3294
+ role,
3295
+ value: entry.hex
3296
+ }
3297
+ };
3298
+ values[role] = hex;
3299
+ }
3300
+ const missing = PALETTE_TOKEN_NAMES.filter((role) => values[role] === void 0);
3301
+ if (missing.length > 0) return {
3302
+ ok: false,
3303
+ error: {
3304
+ kind: "missing-roles",
3305
+ roles: missing
3306
+ }
3307
+ };
3308
+ return {
3309
+ ok: true,
3310
+ colors: paletteColorsSchema.parse(values)
3311
+ };
3312
+ }
3313
+ function requirePaletteColorsFromEntries(entries) {
3314
+ const result = paletteColorsFromEntries(entries);
3315
+ if (result.ok) return result.colors;
3316
+ throw new Error(`Invalid complete palette: ${result.error.kind}`);
3317
+ }
3318
+ function paletteColorEntries(colors) {
3319
+ return THEME_PALETTE_COLOR_ORDER.map((name) => ({
3320
+ name,
3321
+ hex: colors[name]
3322
+ }));
3323
+ }
3324
+ function paletteColorFingerprint(colors) {
3325
+ return PALETTE_TOKEN_NAMES.map((name) => `${name}:${colors[name]}`).join("|");
3326
+ }
3327
+ function canonicalPaletteHashInput(colors, mode) {
3328
+ return `${mode}|${paletteColorFingerprint(colors)}`;
3329
+ }
3330
+ /**
3331
+ * Stable curated-catalogue identity. Do not reorder roles: the order comes
3332
+ * from PALETTE_TOKEN_NAMES through canonicalPaletteHashInput.
3333
+ */
3334
+ function paletteValueKey(colors, mode) {
3335
+ return `${PALETTE_VALUE_KEY_PREFIX}${canonicalPaletteHashInput(colors, mode)}`;
3336
+ }
3337
+ /** Parses only the exact v1 canonical form emitted by paletteValueKey. */
3338
+ function parsePaletteValueKey(value) {
3339
+ if (typeof value !== "string" || !value.startsWith(PALETTE_VALUE_KEY_PREFIX)) return null;
3340
+ const [rawMode, ...rawRoles] = value.slice(17).split("|");
3341
+ const mode = paletteModeSchema.safeParse(rawMode);
3342
+ if (!mode.success || rawRoles.length !== PALETTE_TOKEN_NAMES.length) return null;
3343
+ const colors = paletteColorsFromEntries(rawRoles.map((roleValue) => {
3344
+ const separator = roleValue.indexOf(":");
3345
+ return separator === -1 ? {
3346
+ name: "",
3347
+ hex: ""
3348
+ } : {
3349
+ name: roleValue.slice(0, separator),
3350
+ hex: roleValue.slice(separator + 1)
3351
+ };
3352
+ }));
3353
+ if (!colors.ok || paletteValueKey(colors.colors, mode.data) !== value) return null;
3354
+ return value;
3355
+ }
3356
+ const paletteValueKeySchema = z.string().transform((value, ctx) => {
3357
+ const parsed = parsePaletteValueKey(value);
3358
+ if (parsed) return parsed;
3359
+ ctx.addIssue({
3360
+ code: "custom",
3361
+ message: "Invalid canonical palette value key"
3362
+ });
3363
+ return z.NEVER;
2500
3364
  });
2501
- const mediaIdentifierSchema = z.string().trim().min(1).brand();
2502
- const imageMediaSchema = mediaBaseSchema.extend({ type: z.literal("image") });
2503
- const videoMediaSchema = mediaBaseSchema.extend({ type: z.literal("video") });
2504
- const audioMediaSchema = mediaBaseSchema.extend({ type: z.literal("audio") });
2505
- const documentMediaSchema = mediaBaseSchema.extend({ type: z.literal("document") });
2506
- const spreadsheetMediaSchema = mediaBaseSchema.extend({ type: z.literal("spreadsheet") });
2507
- const archiveMediaSchema = mediaBaseSchema.extend({ type: z.literal("archive") });
2508
- const mediaSchema = z.discriminatedUnion("type", [
2509
- imageMediaSchema,
2510
- videoMediaSchema,
2511
- audioMediaSchema,
2512
- documentMediaSchema,
2513
- spreadsheetMediaSchema,
2514
- archiveMediaSchema
2515
- ]);
2516
- const persistableMediaBaseSchema = mediaBaseSchema.extend({ identifier: mediaIdentifierSchema });
2517
- z.discriminatedUnion("type", [
2518
- persistableMediaBaseSchema.extend({ type: z.literal("image") }),
2519
- persistableMediaBaseSchema.extend({ type: z.literal("video") }),
2520
- persistableMediaBaseSchema.extend({ type: z.literal("audio") }),
2521
- persistableMediaBaseSchema.extend({ type: z.literal("document") }),
2522
- persistableMediaBaseSchema.extend({ type: z.literal("spreadsheet") }),
2523
- persistableMediaBaseSchema.extend({ type: z.literal("archive") })
2524
- ]);
2525
3365
  //#endregion
2526
3366
  //#region ../theme-core/src/palette/schema.ts
2527
3367
  const colourHexString = z.string().regex(/^#([0-9A-Fa-f]{3}){1,2}$/);
@@ -2838,6 +3678,494 @@ function validateUniqueDeclaredCardVariantRoles(system, ctx) {
2838
3678
  }
2839
3679
  const cardSystemSchema = z.object({ variants: z.array(cardVariantSchema).min(1).max(3) }).superRefine(validateUniqueDeclaredCardVariantRoles).transform((system) => ({ variants: withInferredRoles(system.variants) }));
2840
3680
  //#endregion
3681
+ //#region ../theme-core/src/surfaces/foregroundContract.ts
3682
+ const SURFACE_FOREGROUND_CSS_VARS = {
3683
+ text: "--rb-surface-text-color",
3684
+ heading: "--rb-surface-heading-color",
3685
+ link: "--rb-surface-link-color",
3686
+ linkHover: "--rb-surface-link-hover-color",
3687
+ supporting: "--rb-surface-supporting-color",
3688
+ muted: "--rb-surface-muted-color",
3689
+ line: "--rb-surface-line-color",
3690
+ mark: "--rb-surface-mark-color"
3691
+ };
3692
+ const DEFAULT_SURFACE_TEXT_COLOR = "rgb(var(--tb-text, 17 24 39))";
3693
+ const DEFAULT_SURFACE_LINK_COLOR = "rgb(var(--tb-primary, var(--tb-text, 17 24 39)))";
3694
+ const DEFAULT_SURFACE_SUPPORTING_COLOR = "rgb(var(--tb-mutedText, 100 116 139))";
3695
+ const DEFAULT_ROLE_FALLBACKS = {
3696
+ text: DEFAULT_SURFACE_TEXT_COLOR,
3697
+ heading: DEFAULT_SURFACE_TEXT_COLOR,
3698
+ link: DEFAULT_SURFACE_LINK_COLOR,
3699
+ linkHover: DEFAULT_SURFACE_LINK_COLOR,
3700
+ supporting: DEFAULT_SURFACE_SUPPORTING_COLOR,
3701
+ muted: DEFAULT_SURFACE_SUPPORTING_COLOR
3702
+ };
3703
+ function requireSurfaceColorValue(role, value) {
3704
+ const normalized = value.trim();
3705
+ if (normalized.length === 0) throw new RangeError(`Surface foreground ${role} must be a non-empty CSS color.`);
3706
+ return normalized;
3707
+ }
3708
+ function completeSurfaceForegrounds(input) {
3709
+ const text = requireSurfaceColorValue("text", input.text);
3710
+ const link = input.link === void 0 ? text : requireSurfaceColorValue("link", input.link);
3711
+ return {
3712
+ text,
3713
+ heading: input.heading === void 0 ? text : requireSurfaceColorValue("heading", input.heading),
3714
+ link,
3715
+ linkHover: input.linkHover === void 0 ? link : requireSurfaceColorValue("linkHover", input.linkHover),
3716
+ muted: input.muted === void 0 ? text : requireSurfaceColorValue("muted", input.muted),
3717
+ supporting: input.supporting === void 0 ? text : requireSurfaceColorValue("supporting", input.supporting)
3718
+ };
3719
+ }
3720
+ function surfaceForegroundValue(role, outsideProviderFallback = DEFAULT_ROLE_FALLBACKS[role]) {
3721
+ const roleVariable = SURFACE_FOREGROUND_CSS_VARS[role];
3722
+ const fallback = requireSurfaceColorValue("fallback", outsideProviderFallback);
3723
+ if (role === "text") return `var(${roleVariable}, ${fallback})`;
3724
+ if (role === "linkHover") return `var(${roleVariable}, ${surfaceForegroundValue("link", fallback)})`;
3725
+ return `var(${roleVariable}, var(${SURFACE_FOREGROUND_CSS_VARS.text}, ${fallback}))`;
3726
+ }
3727
+ function surfaceForegroundValueWithOpacity(role, opacityPercent) {
3728
+ if (!Number.isFinite(opacityPercent) || opacityPercent < 0 || opacityPercent > 100) throw new RangeError("Surface foreground opacity must be between 0 and 100.");
3729
+ return `color-mix(in srgb, ${surfaceForegroundValue(role)} ${opacityPercent}%, transparent)`;
3730
+ }
3731
+ function surfaceForegroundStyle(input) {
3732
+ const foregrounds = completeSurfaceForegrounds(input);
3733
+ return {
3734
+ color: foregrounds.text,
3735
+ [SURFACE_FOREGROUND_CSS_VARS.text]: foregrounds.text,
3736
+ [SURFACE_FOREGROUND_CSS_VARS.heading]: foregrounds.heading,
3737
+ [SURFACE_FOREGROUND_CSS_VARS.link]: foregrounds.link,
3738
+ [SURFACE_FOREGROUND_CSS_VARS.linkHover]: foregrounds.linkHover,
3739
+ [SURFACE_FOREGROUND_CSS_VARS.supporting]: foregrounds.supporting,
3740
+ ...input.muted === void 0 ? {} : { [SURFACE_FOREGROUND_CSS_VARS.muted]: foregrounds.muted },
3741
+ "--rb-surface-link-hover-decoration": hoverDecoration(input)
3742
+ };
3743
+ }
3744
+ function surfaceForegroundDeclarations(input) {
3745
+ return Object.entries(surfaceForegroundStyle(input)).map(([property, value]) => `${property}: ${value};`);
3746
+ }
3747
+ function hoverDecoration(input) {
3748
+ return input.hoverDecoration ?? "underline";
3749
+ }
3750
+ //#endregion
3751
+ //#region ../theme-core/src/palette/utils/colorConversion.ts
3752
+ function hexToRgb(hex) {
3753
+ const h = hex.replace(/^#/, "");
3754
+ const m = h.length === 3 ? h.split("").map((c) => c + c).join("") : h;
3755
+ if (m.length !== 6) throw new Error("Bad hex");
3756
+ const int = parseInt(m, 16);
3757
+ return {
3758
+ r: int >> 16 & 255,
3759
+ g: int >> 8 & 255,
3760
+ b: int & 255
3761
+ };
3762
+ }
3763
+ function srgbToLinear(u) {
3764
+ const x = u / 255;
3765
+ return x <= .04045 ? x / 12.92 : Math.pow((x + .055) / 1.055, 2.4);
3766
+ }
3767
+ //#endregion
3768
+ //#region ../theme-core/src/palette/utils/contrast.ts
3769
+ function relativeLuminance(r, g, b) {
3770
+ const R = srgbToLinear(r), G = srgbToLinear(g), B = srgbToLinear(b);
3771
+ return .2126 * R + .7152 * G + .0722 * B;
3772
+ }
3773
+ //#endregion
3774
+ //#region ../theme-core/src/buttons/styles/domain.ts
3775
+ const PUBLIC_BUTTON_ROLES = VARIANT_ROLES;
3776
+ function defineButtonStyleRecipe(recipe) {
3777
+ return recipe;
3778
+ }
3779
+ function mapButtonVisualAppearances(states, transform) {
3780
+ return {
3781
+ base: transform(states.base, "base"),
3782
+ hover: transform(states.hover, "hover"),
3783
+ focus: transform(states.focus, "focus"),
3784
+ active: transform(states.active, "active"),
3785
+ disabled: transform(states.disabled, "disabled")
3786
+ };
3787
+ }
3788
+ function mapButtonRoleAppearances(roles, transform) {
3789
+ const role = (name) => transform(roles[name], name);
3790
+ return {
3791
+ primary: role("primary"),
3792
+ secondary: role("secondary"),
3793
+ outline: role("outline"),
3794
+ ghost: role("ghost"),
3795
+ accent: role("accent")
3796
+ };
3797
+ }
3798
+ function materializeButtonRoles(definitions) {
3799
+ return {
3800
+ primary: materializeCompleteRole("primary", definitions.primary),
3801
+ secondary: materializeCompleteRole("secondary", definitions.secondary),
3802
+ outline: materializeCompleteRole("outline", definitions.outline),
3803
+ ghost: materializeCompleteRole("ghost", definitions.ghost),
3804
+ accent: materializeCompleteRole("accent", definitions.accent)
3805
+ };
3806
+ }
3807
+ function resolveButtonStyleRecipe(recipe, parameters) {
3808
+ const parsedParameters = recipe.parameterSchema.safeParse(parameters);
3809
+ if (!parsedParameters.success) return {
3810
+ kind: "error",
3811
+ error: {
3812
+ kind: "invalid-parameters",
3813
+ styleId: recipe.id,
3814
+ issues: parsedParameters.error.issues.map((issue) => issue.message)
3815
+ }
3816
+ };
3817
+ const definition = recipe.defineSystem(parsedParameters.data);
3818
+ const roles = materializeButtonRoles(definition.roles);
3819
+ const buttonSystem = {
3820
+ global: buttonFamilyProjection(roles.primary),
3821
+ sizes: roles.primary.visualStates?.base.sizes,
3822
+ variants: PUBLIC_BUTTON_ROLES.map((role) => roles[role]),
3823
+ surfacePolicy: definition.surfacePolicy ?? createStandardButtonSurfacePolicy()
3824
+ };
3825
+ const parsedButtonSystem = buttonSystemSchema.safeParse(buttonSystem);
3826
+ if (!parsedButtonSystem.success) return {
3827
+ kind: "error",
3828
+ error: {
3829
+ kind: "invalid-button-system",
3830
+ styleId: recipe.id,
3831
+ issues: parsedButtonSystem.error.issues.map((issue) => issue.message)
3832
+ }
3833
+ };
3834
+ return {
3835
+ kind: "resolved",
3836
+ buttonSystem: parsedButtonSystem.data
3837
+ };
3838
+ }
3839
+ /** Historical family metadata remains a projection; recipes never read it. */
3840
+ function buttonFamilyProjection(primary) {
3841
+ const base = primary.visualStates.base;
3842
+ const type = base.typography;
3843
+ return {
3844
+ cornerStyle: base.borderRadius === "rounded-none" ? "square" : base.borderRadius === "rounded-full" ? "pill" : "rounded",
3845
+ shadow: base.shadow.elevation,
3846
+ fontWeight: type.fontWeight,
3847
+ textTransform: type.textTransform,
3848
+ typography: type.typography,
3849
+ ...type.fontSize === null ? {} : { fontSize: type.fontSize },
3850
+ ...type.letterSpacing === null || type.letterSpacing === "heading" ? {} : { letterSpacing: type.letterSpacing },
3851
+ ...type.italic ? { italic: true } : {},
3852
+ hoverTransform: "none",
3853
+ hoverColor: "none"
3854
+ };
3855
+ }
3856
+ function materializeCompleteRole(role, appearance) {
3857
+ return {
3858
+ visualStates: appearance.states,
3859
+ background: appearance.states.base.background,
3860
+ borderRadius: appearance.states.base.borderRadius,
3861
+ ...appearance.states.base.border === "none" ? {} : { border: appearance.states.base.border },
3862
+ shadow: appearance.states.base.shadow,
3863
+ sizes: appearance.states.base.sizes,
3864
+ effects: Object.fromEntries([
3865
+ "base",
3866
+ "hover",
3867
+ "focus",
3868
+ "active"
3869
+ ].flatMap((state) => {
3870
+ const effects = appearance.states[state].effects;
3871
+ return effects.length === 0 ? [] : [[state, effects]];
3872
+ })),
3873
+ ...appearance.states.hover.contextualHover ? { contextualHover: appearance.states.hover.contextualHover } : {},
3874
+ ...appearance.affordance ? { affordance: appearance.affordance } : {},
3875
+ id: role,
3876
+ name: roleName(role),
3877
+ enabled: true,
3878
+ priority: rolePriority(role)
3879
+ };
3880
+ }
3881
+ function roleName(role) {
3882
+ return role.charAt(0).toUpperCase() + role.slice(1);
3883
+ }
3884
+ function rolePriority(role) {
3885
+ if (role === "primary") return 1;
3886
+ if (role === "secondary") return 2;
3887
+ return 3;
3888
+ }
3889
+ //#endregion
3890
+ //#region ../theme-core/src/utils/tokenOrColor.ts
3891
+ /**
3892
+ * Runtime color-reference fields intentionally accept any string, including
3893
+ * the legacy empty-string "no color" sentinel. Semantic validation needs
3894
+ * palette context and happens in `parseThemeColorReference`.
3895
+ */
3896
+ const tokenOrCssColorValueSchema = z.string();
3897
+ const CSS_COLOR_FUNCTION_PATTERN = /^(?:rgb|rgba|hsl|hsla|hwb|lab|lch|oklab|oklch|color|color-mix|light-dark)\(/i;
3898
+ const CSS_HEX_COLOR_PATTERN = /^#(?:[0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/i;
3899
+ const CSS_COLOR_KEYWORDS = /* @__PURE__ */ new Set([
3900
+ "transparent",
3901
+ "currentcolor",
3902
+ "inherit",
3903
+ "initial",
3904
+ "revert",
3905
+ "revert-layer",
3906
+ "unset"
3907
+ ]);
3908
+ const COMMON_CSS_NAMED_COLORS = /* @__PURE__ */ new Set([
3909
+ "black",
3910
+ "blue",
3911
+ "gray",
3912
+ "green",
3913
+ "grey",
3914
+ "orange",
3915
+ "pink",
3916
+ "purple",
3917
+ "red",
3918
+ "white",
3919
+ "yellow"
3920
+ ]);
3921
+ function isCssColorLiteral(value) {
3922
+ const trimmed = value.trim();
3923
+ if (!trimmed) return false;
3924
+ return CSS_HEX_COLOR_PATTERN.test(trimmed) || CSS_COLOR_FUNCTION_PATTERN.test(trimmed) || /^var\(/i.test(trimmed) || CSS_COLOR_KEYWORDS.has(trimmed.toLowerCase());
3925
+ }
3926
+ function parseThemeToken(token) {
3927
+ const trimmed = token.trim();
3928
+ const match = trimmed.match(/^(.*?)-(\d{2,3})$/);
3929
+ if (!match) return {
3930
+ role: trimmed,
3931
+ shade: null
3932
+ };
3933
+ const role = match[1] ?? trimmed;
3934
+ const shade = match[2] ? Number(match[2]) : null;
3935
+ return {
3936
+ role,
3937
+ shade: Number.isFinite(shade) ? shade : null
3938
+ };
3939
+ }
3940
+ function parseContextThemeColorToken(value, context) {
3941
+ const parts = parseColorTokenParts(value);
3942
+ if (parts.kind !== "token") return null;
3943
+ if (!(Boolean(context?.palette?.[value.trim()]) || parts.opacityPercent !== null && Boolean(context?.palette?.[parts.token]))) return null;
3944
+ return value.trim();
3945
+ }
3946
+ function isTokenShapedTypo(value) {
3947
+ if (COMMON_CSS_NAMED_COLORS.has(value.toLowerCase())) return false;
3948
+ if (!/^[a-zA-Z][a-zA-Z0-9]*(?:-[a-zA-Z0-9]+)*(?:\/[^/]+)?$/.test(value)) return false;
3949
+ return !isCssColorLiteral(value);
3950
+ }
3951
+ function warnUnknownThemeColorReference(value) {
3952
+ if (!isTokenShapedTypo(value)) return;
3953
+ console.warn(`[theme-core] Unknown Theme V2 color token "${value}" treated as literal CSS. Use raw:* for deliberate custom CSS values.`);
3954
+ }
3955
+ function parseThemeColorReference(input, context) {
3956
+ const trimmed = input.trim();
3957
+ if (trimmed.startsWith("raw:")) return {
3958
+ kind: "literal-css",
3959
+ value: trimmed.slice(4)
3960
+ };
3961
+ const contextToken = parseContextThemeColorToken(trimmed, context);
3962
+ if (contextToken) return {
3963
+ kind: "palette-context-token",
3964
+ token: contextToken
3965
+ };
3966
+ const knownToken = parseThemeColorToken(trimmed);
3967
+ if (knownToken) return {
3968
+ kind: "theme-token",
3969
+ token: knownToken
3970
+ };
3971
+ warnUnknownThemeColorReference(trimmed);
3972
+ return {
3973
+ kind: "literal-css",
3974
+ value: trimmed
3975
+ };
3976
+ }
3977
+ function resolveThemeColorReferenceValue(input, context) {
3978
+ const reference = parseThemeColorReference(input, context);
3979
+ return reference.kind === "literal-css" ? reference.value : rgbColorValue(reference.token);
3980
+ }
3981
+ function resolveTokenOrCssColorValue(input, context) {
3982
+ return resolveThemeColorReferenceValue(input, context);
3983
+ }
3984
+ function resolveOnColorForThemeToken(token) {
3985
+ if (!parseThemeColorToken(token)) return null;
3986
+ const parts = parseColorTokenParts(token);
3987
+ if (parts.kind !== "token") return null;
3988
+ const { role, shade } = parseThemeToken(parts.token);
3989
+ const normalizedRole = role.trim();
3990
+ if (!normalizedRole) return null;
3991
+ if (!shade) return rgbColorValue(`on${normalizedRole.charAt(0).toUpperCase() + normalizedRole.slice(1)}`);
3992
+ return shade <= 400 ? "#000000" : "#FFFFFF";
3993
+ }
3994
+ //#endregion
3995
+ //#region ../theme-core/src/buttons/buttonColourContract.ts
3996
+ const BUTTON_VISUAL_STATES = [
3997
+ "base",
3998
+ "hover",
3999
+ "focus",
4000
+ "active",
4001
+ "disabled"
4002
+ ];
4003
+ //#endregion
4004
+ //#region ../theme-core/src/buttons/buttonSurfaceContext.ts
4005
+ /**
4006
+ * Break an inherited surface contract when a nested element establishes a
4007
+ * backing whose colours cannot be proven (for example an image or gradient).
4008
+ */
4009
+ function contextualButtonSurfaceResetStyles() {
4010
+ return Object.fromEntries(VARIANT_ROLES.flatMap((role) => Object.entries(resetActionVariables(role))));
4011
+ }
4012
+ function resetActionVariables(role) {
4013
+ const styles = {};
4014
+ for (const state of BUTTON_VISUAL_STATES) for (const property of [
4015
+ "background-color",
4016
+ "background-image",
4017
+ "color"
4018
+ ]) styles[actionVariableName(role, state, property)] = "initial";
4019
+ for (const [state, property] of [
4020
+ ["base", "outline"],
4021
+ ["base", "outline-offset"],
4022
+ ["focus", "outline"],
4023
+ ["focus", "outline-offset"],
4024
+ ["focus", "box-shadow"]
4025
+ ]) styles[actionVariableName(role, state, property)] = "initial";
4026
+ return styles;
4027
+ }
4028
+ function actionVariableName(role, state, property) {
4029
+ return `--rb-action-${role}-${state}-${property}`;
4030
+ }
4031
+ //#endregion
4032
+ //#region ../theme-core/src/surfaces/opaqueSurface.ts
4033
+ /**
4034
+ * The declarations that make an element own its surface: `color`, every
4035
+ * `--rb-surface-*` role and every `--rb-action-*` variable. Card roles and
4036
+ * opaque block panels both publish through this, so a nested surface can never
4037
+ * inherit a band's light text or its band-resolved buttons.
4038
+ */
4039
+ function opaqueSurfaceDeclarations(surface, arrangement = false) {
4040
+ if (surface.kind === "inherit") return inheritedSurfaceDeclarations(arrangement);
4041
+ const foreground = surface.foreground;
4042
+ return [
4043
+ ...surfaceForegroundDeclarations({
4044
+ text: colorValue(foreground.text),
4045
+ heading: colorValue(foreground.heading),
4046
+ link: colorValue(foreground.link),
4047
+ linkHover: colorValue(foreground.linkHover),
4048
+ supporting: colorValue(foreground.supporting),
4049
+ ...arrangement ? { muted: colorValue(foreground.muted) } : {},
4050
+ hoverDecoration: surface.hoverDecoration
4051
+ }),
4052
+ ...arrangement && surface.decorations !== void 0 ? [`${SURFACE_FOREGROUND_CSS_VARS.line}: ${surface.decorations.line};`, `${SURFACE_FOREGROUND_CSS_VARS.mark}: ${surface.decorations.mark};`] : [],
4053
+ ...Object.entries(surface.buttonContext.styles).map(([property, value]) => `${property}: ${value};`)
4054
+ ];
4055
+ }
4056
+ function colorValue(token) {
4057
+ const parsed = parseThemeColorToken(token);
4058
+ return parsed ? rgbColorValue(parsed) : token;
4059
+ }
4060
+ /** Every property a surface publishes, set to `inherit`. */
4061
+ function inheritedSurfaceDeclarations(arrangement) {
4062
+ return [
4063
+ "color",
4064
+ ...Object.entries(SURFACE_FOREGROUND_CSS_VARS).filter(([role]) => arrangement || role !== "line" && role !== "mark" && role !== "muted").map(([, variable]) => variable),
4065
+ "--rb-surface-link-hover-decoration",
4066
+ ...Object.keys(contextualButtonSurfaceResetStyles())
4067
+ ].map((property) => `${property}: inherit;`);
4068
+ }
4069
+ //#endregion
4070
+ //#region ../theme-core/src/utils/colorStyles.ts
4071
+ const COLOR_VAR_PREFIX = "--tb-";
4072
+ function parseToken(source) {
4073
+ const parts = parseColorTokenParts(source);
4074
+ if (parts.kind === "raw") return {
4075
+ token: source,
4076
+ raw: parts.value
4077
+ };
4078
+ if (parts.kind === "invalid") return { token: source };
4079
+ return {
4080
+ token: parts.token,
4081
+ opacityPercent: parts.opacityPercent === null ? void 0 : parts.opacityPercent
4082
+ };
4083
+ }
4084
+ const SURFACE_TEXT_ROLE_BY_TOKEN = {
4085
+ text: "text",
4086
+ heading: "heading",
4087
+ mutedText: "supporting"
4088
+ };
4089
+ function surfaceRoleForTextToken(token) {
4090
+ return Object.prototype.hasOwnProperty.call(SURFACE_TEXT_ROLE_BY_TOKEN, token) ? SURFACE_TEXT_ROLE_BY_TOKEN[token] : null;
4091
+ }
4092
+ /**
4093
+ * Converts a theme color token to a CSS rgb value.
4094
+ * This is the primary function for applying theme colors to CSS properties.
4095
+ *
4096
+ * @param token - Theme color token (semantic, with opacity, or raw)
4097
+ * @returns CSS color value (rgb with optional alpha, or raw CSS value)
4098
+ *
4099
+ * @example
4100
+ * rgbColorValue('primary') // => 'rgb(var(--tb-primary))'
4101
+ * rgbColorValue('surface/95') // => 'rgb(var(--tb-surface) / 0.95)'
4102
+ * rgbColorValue('raw:transparent') // => 'transparent'
4103
+ */
4104
+ function rgbColorValue(token) {
4105
+ const { token: baseToken, opacityPercent, raw } = parseToken(token);
4106
+ if (raw) return raw;
4107
+ const cssVar = `${COLOR_VAR_PREFIX}${baseToken}`;
4108
+ if (opacityPercent === void 0) return `rgb(var(${cssVar}))`;
4109
+ return `rgb(var(${cssVar}) / ${opacityPercent / 100})`;
4110
+ }
4111
+ /**
4112
+ * Creates a backgroundColor style object from a theme token.
4113
+ *
4114
+ * @param token - Theme color token
4115
+ * @returns CSSProperties with backgroundColor
4116
+ */
4117
+ function backgroundColorStyle(token) {
4118
+ return { backgroundColor: rgbColorValue(token) };
4119
+ }
4120
+ /**
4121
+ * Converts a text color token to a CSS color value that follows the enclosing
4122
+ * surface. The semantic text tokens (`text`, `heading`, `mutedText`) resolve
4123
+ * to the surface foreground variables, so text adapts when a section's
4124
+ * background changes; any other token is a fixed theme color.
4125
+ *
4126
+ * @param token - Theme color token
4127
+ * @returns CSS color value
4128
+ */
4129
+ function textColorValue(token) {
4130
+ const parsed = parseToken(token);
4131
+ const surfaceRole = parsed.raw ? null : surfaceRoleForTextToken(parsed.token);
4132
+ if (!surfaceRole) return rgbColorValue(token);
4133
+ return parsed.opacityPercent === void 0 ? surfaceForegroundValue(surfaceRole) : surfaceForegroundValueWithOpacity(surfaceRole, parsed.opacityPercent);
4134
+ }
4135
+ /**
4136
+ * Creates a text color style object from a theme token.
4137
+ *
4138
+ * @param token - Theme color token
4139
+ * @returns CSSProperties with color
4140
+ */
4141
+ function textColorStyle(token) {
4142
+ return { color: textColorValue(token) };
4143
+ }
4144
+ /**
4145
+ * Merges multiple CSSProperties objects into a single object.
4146
+ * Later styles override earlier ones. Undefined values are filtered out.
4147
+ * Returns undefined if the merged result is empty.
4148
+ *
4149
+ * @param styles - Variable number of CSSProperties objects (can be undefined)
4150
+ * @returns Merged CSSProperties object, or undefined if empty
4151
+ *
4152
+ * @example
4153
+ * mergeStyles(
4154
+ * backgroundColorStyle('surface'),
4155
+ * textColorStyle('text'),
4156
+ * borderColorStyle('border')
4157
+ * )
4158
+ * // => { backgroundColor: '...', color: '...', borderColor: '...' }
4159
+ */
4160
+ function mergeStyles(...styles) {
4161
+ const merged = {};
4162
+ for (const style of styles) {
4163
+ if (!style) continue;
4164
+ Object.assign(merged, style);
4165
+ }
4166
+ return Object.keys(merged).length ? merged : void 0;
4167
+ }
4168
+ //#endregion
2841
4169
  //#region ../theme-core/src/accordions/types.ts
2842
4170
  /**
2843
4171
  * Accordion icon styles for expand/collapse indicators
@@ -3789,6 +5117,20 @@ const boxBackgroundSchema = z.discriminatedUnion("type", [
3789
5117
  showVideoOnMobile: z.boolean().nullable().optional()
3790
5118
  })
3791
5119
  ]);
5120
+ z.discriminatedUnion("type", [
5121
+ boxBackgroundSchema.options[0],
5122
+ boxBackgroundSchema.options[1],
5123
+ boxBackgroundSchema.options[2].extend({ image: z.union([
5124
+ imageMediaSchema,
5125
+ externalMediaSchema.extend({ type: z.literal("image") }),
5126
+ assetMediaSchema.extend({ type: z.literal("image") })
5127
+ ]).nullable().optional() }),
5128
+ boxBackgroundSchema.options[3].extend({ image: z.union([
5129
+ videoMediaSchema,
5130
+ externalMediaSchema.extend({ type: z.literal("video") }),
5131
+ assetMediaSchema.extend({ type: z.literal("video") })
5132
+ ]).nullable().optional() })
5133
+ ]);
3792
5134
  function normalizeAuthoringOpacity(value) {
3793
5135
  if (!isRecord$5(value)) return value;
3794
5136
  return {
@@ -18488,7 +19830,7 @@ const publicEventBaseSchema = z.object({
18488
19830
  content: z.object({ body: RichTextDocSchema.nullable().optional() }).optional(),
18489
19831
  presentation: z.object({
18490
19832
  summary: z.string().nullable().optional(),
18491
- image: mediaSchema.nullable().optional()
19833
+ image: runtimeMediaSchema.nullable().optional()
18492
19834
  }).optional(),
18493
19835
  slug: z.string(),
18494
19836
  path: z.string().nullable(),
@@ -27373,4 +28715,4 @@ function defineIslandPropsDecoder(kind) {
27373
28715
  };
27374
28716
  }
27375
28717
  //#endregion
27376
- export { formatRegistrationSchedule as $, resolveRuntimeEventDestination as $n, orderedLiveRunSessions as $r, placesLeftLabel as $t, getEventSelectionMode as A, eventDateOptions as An, toSelectedCollectionOptionKind as Ar, buildBookingPaymentSelectionViewModel as At, getDeclinedPass as B, getLocalDateKey as Bn, ok as Br, resolveRouteRequiresPayment as Bt, offeringNounForEvent as C, normalizeCsvString as Cn, parseBookingCurrencyInputToCents as Cr, resolveRegistrationTicketContinuation as Ct, bookingEntry as D, formatEventPriceAmount as Dn, resolveBookingSiteId as Dr, normalizeEventRegistrationMaxTickets as Dt, bookingCardEntry as E, formatEventPrice as En, resolveBookingPaymentStep as Er, isEventRegistrationAvailable as Et, registrationStepLabel as F, formatEventNextDateFact as Fn, RichTextDocSchema as Fr, OFFLINE_BOOKING_PAYMENT_INSTRUCTIONS as Ft, shouldPromptForLogin as G, buildCalendarViewport as Gn, themeButtonVariantClassNames as Gr, formatCentsAsCurrencyInput as Gt, registrationFlowReducer as H, MONTH_NAMES as Hn, reportWorkflowError as Hr, beginWaitlistInvitation as Ht, registrationStepLabelContext as I, formatEventTimeRange as In, isRecord$4 as Ir, findPreSelectedEvent as It, findSelectedTicketType as J, getOrderedDayNames as Jn, checkBrowserStripeKey as Jr, getSlidingScaleForEvent as Jt, ENTITLEMENT_SINGLE_TICKET_TOOLTIP as K, formatDateKey as Kn, boxBackgroundSchema as Kr, getEligibilityFlowFlags as Kt, areEventRegistrationPaymentSelectionsEqual as L, formatTime$1 as Ln, assertNever$1 as Lr, resolveDiscountContext as Lt, registrationPaymentRoute as M, formatDate$1 as Mn, resolveSelectedAppointmentConsent as Mr, paymentChoiceDetails as Mt, registrationPresentation as N, formatEventCompactDateRail as Nn, BOOKING_FORM_DATA_RESERVED_KEYS as Nr, paymentChoicePrice as Nt, bookingEntryProgress as O, formatEventPriceDisplay as On, resolveDefaultBookingServiceId as Or, resolveEventRegistrationSubmitPlan as Ot, registrationRoute as P, formatEventDateParts as Pn, isBookingRequirementConsentFieldId as Pr, formatPrice as Pt, formatPassCreditUsageLabel as Q, shiftCalendarAnchorDate as Qn, CANCELLED_SESSION_STATUS as Qr, validateFormData as Qt, createInitialRegistrationFlowState as R, groupEventsByDate as Rn, clearWorkflowFeedback as Rr, resolveEventRequiresPayment as Rt, toWholeSeriesRegistrationEvents as S, normalizeCsvIds as Sn, isBookingServiceSlidingAmountInRange as Sr, resolveRegistrationAvailabilityBlocker as St, bookingBarPlacement as T, buildEventListWeek as Tn, resolveAppointmentCheckoutVerificationState as Tr, visitorHoldsOwnPlace as Tt, buildEventRegistrationPaymentOptionsViewModel as U, addDays as Un, reportWorkflowSuccess as Ur, createRegistrationDraftData as Ut, isRegistrationLocked as V, getLocalMinuteOfDay as Vn, okWith as Vr, toRegistrationRequestSubject as Vt, decideEventRegistrationPayment as W, addMonths as Wn, themeButtonSizeClassName as Wr, invitationSubmission as Wt, formatDate as X, isSameCalendarDay as Xn, parseEventRegistrationErrorReason as Xr, parseCurrencyInputToCents as Xt, formatBookingWhen as Y, getWeekCalendarDays as Yn, eventRegistrationErrors as Yr, getSlidingScaleSelectionMessage as Yt, formatEventDateTime as Z, isToday as Zn, confirmationPaymentSchema as Zr, shouldLoadRegistrationOptions as Zt, buildEventRegistrationDisplayFromScopedEvents as _, publicEventPricingType as _i, resolveCalendarReadProfile as _n, getBookingRedirectStateFromLocation as _r, placeCountCeiling as _t, buildProductDetailDisplay as a, formatLocalScheduleDate as ai, isSemanticSpacing as an, getEventAvailabilityStatus as ar, occurrenceTitleOverride as at, getRegistrationStartAt as b, buildEventRuntimeFilters as bn, getRegistrationSuccessCopy as br, resolveGuestNextStepCheck as bt, EMPTY_COMMERCE_CART_STATE as c, parseBookingLocalDate as ci, eventListingBlockRuntime as cn, selectEventCapacitySource as cr, canRequestTicketOption as ct, deriveCommerceCheckoutState as d, toScheduledBookingDateTime as di, calendarPageResponseError as dn, listItemPresentation as dr, getTicketSelectionTotal as dt, resolveWholeSeriesBookingPhase as ei, shownVenue as en, canJoinEventWaitlist as er, formatTime as et, parseStoredCommerceCartState as f, formatBookingPriceDisplay as fi, calendarQueryKey as fn, listLookSlot as fr, getTicketTypeLineMax as ft, newsletterBlockSubmissionMessage as g, publicEventPricingStrategy as gi, planCalendarMonthRanges as gn, formatBookingSubmissionPreparationError as gr, fullyBookedLabel as gt, NEWSLETTER_SIGNUPS_PAUSED_MESSAGE as h, publicEventPricingDisplay as hi, calendarWindowPageSchema as hn, formatBookingCentsAsCurrencyInput as hr, setTicketLineQuantity as ht, buildProductCardDisplay as i, formatBookingInstant as ii, SEMANTIC_SPACING_VALUES as in, getEventAvailability as ir, getVisibleTicketTypes as it, panelShouldOpen as j, eventLocalDateKey as jn, projectSelectedAppointmentConsentIntoForm as jr, buildReviewedBookingPaymentViewModel as jt, bookingPanelHeading as k, eventDateLocale as kn, selectedBookingCollectionOptionKind as kr, calculateEventRegistrationPreviewTotal as kt, buildPassCartItem as l, resolveBookingTimeZoneId as li, calendarMonthDate as ln, selectMostOpenCapacitySource as lr, getSingleSelectedPricingOptionId as lt, reduceCommerceCart as m, publicEventPricingCurrency as mi, calendarWindowMonths as mn, deriveBookingFormViewState as mr, normalizeTicketSelectionLines as mt, getShopDisplayForItems as n, resolveBookingSignupOffer as ni, staticHeaderChromeRuntime as nn, formatEventRemainingPlaces as nr, getPortalSubjectEmail as nt, formatCommercePrice as o, getBookingLocalDateKey as oi, resolveSpacing as on, getRemainingPlaces as or, transformRegistrationOptionsResponse as ot, productItemKey as p, isPublicEventPricingOptionDisplayable as pi, calendarWindowBounds as pn, logger as pr, hasValidPricingOptionSelection as pt, areEntitlementsDisabledForTicketCount as q, getDayOfWeek as qn, normalizeCardRole as qr, getRegistrationOccurrenceId as qt, buildCartDisplay as r, addLocalScheduleDays as ri, resolveEventRegistrationScopedEvents as rn, formatTotalCapacity as rr, getTicketTypeAvailabilityLabel as rt, formatInterval as s, getLocalScheduleDate as si, asPartialObject as sn, isEventFull as sr, withOccurrenceTitle as st, defineIslandPropsDecoder as t, parseMailingListVisitorSelection as ti, buildEventCalendarListingRender as tn, canJoinEventWaitlistOnAnyMode as tr, getImplicitSingleTicketType as tt, buildProductCartItem as u, toBookingTimeZone as ui, calendarMonthKey as un, groupPublicEventsByRun as ur, getTicketLineQuantity as ut, displayButtonText as v, formatCurrencyAmount as vi, createHostedBlockApiConfig as vn, getBookingServiceSlidingScale as vr, planRegistrationDetailsCheck as vt, DEFAULT_BOOKING_BUTTON_TEXT as w, normalizeOptionalId as wn, prepareBookingSubmission as wr, settledRemainingPlaces as wt, toRegistrationEvents as x, getEventRuntimeFiltersKey as xn, getShopSuccessCopy as xr, resolveRegistrationAdmission as xt, findBookedEvent as y, assertNever$6 as yi, getBlockApiReadStage as yn, getBookingSuccessCopy as yr, planRegistrationDetailsContinuation as yt, decideEventChoice as z, resolveEventTimeZone as zn, err as zr, resolveRegistrationTarget as zt };
28718
+ export { formatRegistrationSchedule as $, resolveRuntimeEventDestination as $n, relativeLuminance as $r, placesLeftLabel as $t, getEventSelectionMode as A, formatCurrencyAmount as Ai, eventDateOptions as An, toSelectedCollectionOptionKind as Ar, buildBookingPaymentSelectionViewModel as At, getDeclinedPass as B, getLocalDateKey as Bn, ok as Br, resolveRouteRequiresPayment as Bt, offeringNounForEvent as C, toScheduledBookingDateTime as Ci, normalizeCsvString as Cn, parseBookingCurrencyInputToCents as Cr, resolveRegistrationTicketContinuation as Ct, bookingEntry as D, publicEventPricingDisplay as Di, formatEventPriceAmount as Dn, resolveBookingSiteId as Dr, normalizeEventRegistrationMaxTickets as Dt, bookingCardEntry as E, publicEventPricingCurrency as Ei, formatEventPrice as En, resolveBookingPaymentStep as Er, isEventRegistrationAvailable as Et, registrationStepLabel as F, formatEventNextDateFact as Fn, RichTextDocSchema as Fr, OFFLINE_BOOKING_PAYMENT_INSTRUCTIONS as Ft, shouldPromptForLogin as G, buildCalendarViewport as Gn, themeButtonVariantClassNames as Gr, formatCentsAsCurrencyInput as Gt, registrationFlowReducer as H, MONTH_NAMES as Hn, reportWorkflowError as Hr, beginWaitlistInvitation as Ht, registrationStepLabelContext as I, formatEventTimeRange as In, isRecord$4 as Ir, findPreSelectedEvent as It, findSelectedTicketType as J, getOrderedDayNames as Jn, mergeStyles as Jr, getSlidingScaleForEvent as Jt, ENTITLEMENT_SINGLE_TICKET_TOOLTIP as K, formatDateKey as Kn, boxBackgroundSchema as Kr, getEligibilityFlowFlags as Kt, areEventRegistrationPaymentSelectionsEqual as L, formatTime$1 as Ln, assertNever$1 as Lr, resolveDiscountContext as Lt, registrationPaymentRoute as M, formatDate$1 as Mn, resolveSelectedAppointmentConsent as Mr, paymentChoiceDetails as Mt, registrationPresentation as N, formatEventCompactDateRail as Nn, BOOKING_FORM_DATA_RESERVED_KEYS as Nr, paymentChoicePrice as Nt, bookingEntryProgress as O, publicEventPricingStrategy as Oi, formatEventPriceDisplay as On, resolveDefaultBookingServiceId as Or, resolveEventRegistrationSubmitPlan as Ot, registrationRoute as P, formatEventDateParts as Pn, isBookingRequirementConsentFieldId as Pr, formatPrice as Pt, formatPassCreditUsageLabel as Q, shiftCalendarAnchorDate as Qn, resolveTokenOrCssColorValue as Qr, validateFormData as Qt, createInitialRegistrationFlowState as R, groupEventsByDate as Rn, clearWorkflowFeedback as Rr, resolveEventRequiresPayment as Rt, toWholeSeriesRegistrationEvents as S, toBookingTimeZone as Si, normalizeCsvIds as Sn, isBookingServiceSlidingAmountInRange as Sr, resolveRegistrationAvailabilityBlocker as St, bookingBarPlacement as T, isPublicEventPricingOptionDisplayable as Ti, buildEventListWeek as Tn, resolveAppointmentCheckoutVerificationState as Tr, visitorHoldsOwnPlace as Tt, buildEventRegistrationPaymentOptionsViewModel as U, addDays as Un, reportWorkflowSuccess as Ur, createRegistrationDraftData as Ut, isRegistrationLocked as V, getLocalMinuteOfDay as Vn, okWith as Vr, toRegistrationRequestSubject as Vt, decideEventRegistrationPayment as W, addMonths as Wn, themeButtonSizeClassName as Wr, invitationSubmission as Wt, formatDate as X, isSameCalendarDay as Xn, isCssColorLiteral as Xr, parseCurrencyInputToCents as Xt, formatBookingWhen as Y, getWeekCalendarDays as Yn, textColorStyle as Yr, getSlidingScaleSelectionMessage as Yt, formatEventDateTime as Z, isToday as Zn, resolveOnColorForThemeToken as Zr, shouldLoadRegistrationOptions as Zt, buildEventRegistrationDisplayFromScopedEvents as _, formatLocalScheduleDate as _i, resolveCalendarReadProfile as _n, getBookingRedirectStateFromLocation as _r, placeCountCeiling as _t, buildProductDetailDisplay as a, parseEventRegistrationErrorReason as ai, isSemanticSpacing as an, getEventAvailabilityStatus as ar, occurrenceTitleOverride as at, getRegistrationStartAt as b, parseBookingLocalDate as bi, buildEventRuntimeFilters as bn, getRegistrationSuccessCopy as br, resolveGuestNextStepCheck as bt, EMPTY_COMMERCE_CART_STATE as c, parseAspectRatioValue as ci, eventListingBlockRuntime as cn, selectEventCapacitySource as cr, canRequestTicketOption as ct, deriveCommerceCheckoutState as d, orderedLiveRunSessions as di, calendarPageResponseError as dn, listItemPresentation as dr, getTicketSelectionTotal as dt, hexToRgb as ei, shownVenue as en, canJoinEventWaitlist as er, formatTime as et, parseStoredCommerceCartState as f, resolveWholeSeriesBookingPhase as fi, calendarQueryKey as fn, listLookSlot as fr, getTicketTypeLineMax as ft, newsletterBlockSubmissionMessage as g, formatBookingInstant as gi, planCalendarMonthRanges as gn, formatBookingSubmissionPreparationError as gr, fullyBookedLabel as gt, NEWSLETTER_SIGNUPS_PAUSED_MESSAGE as h, addLocalScheduleDays as hi, calendarWindowPageSchema as hn, formatBookingCentsAsCurrencyInput as hr, setTicketLineQuantity as ht, buildProductCardDisplay as i, eventRegistrationErrors as ii, SEMANTIC_SPACING_VALUES as in, getEventAvailability as ir, getVisibleTicketTypes as it, panelShouldOpen as j, assertNever$6 as ji, eventLocalDateKey as jn, projectSelectedAppointmentConsentIntoForm as jr, buildReviewedBookingPaymentViewModel as jt, bookingPanelHeading as k, publicEventPricingType as ki, eventDateLocale as kn, selectedBookingCollectionOptionKind as kr, calculateEventRegistrationPreviewTotal as kt, buildPassCartItem as l, resolveMediaTransformForAspect as li, calendarMonthDate as ln, selectMostOpenCapacitySource as lr, getSingleSelectedPricingOptionId as lt, reduceCommerceCart as m, resolveBookingSignupOffer as mi, calendarWindowMonths as mn, deriveBookingFormViewState as mr, normalizeTicketSelectionLines as mt, getShopDisplayForItems as n, clsx as ni, staticHeaderChromeRuntime as nn, formatEventRemainingPlaces as nr, getPortalSubjectEmail as nt, formatCommercePrice as o, confirmationPaymentSchema as oi, resolveSpacing as on, getRemainingPlaces as or, transformRegistrationOptionsResponse as ot, productItemKey as p, parseMailingListVisitorSelection as pi, calendarWindowBounds as pn, logger as pr, hasValidPricingOptionSelection as pt, areEntitlementsDisabledForTicketCount as q, getDayOfWeek as qn, backgroundColorStyle as qr, getRegistrationOccurrenceId as qt, buildCartDisplay as r, checkBrowserStripeKey as ri, resolveEventRegistrationScopedEvents as rn, formatTotalCapacity as rr, getTicketTypeAvailabilityLabel as rt, formatInterval as s, isExplicitRectCrop as si, asPartialObject as sn, isEventFull as sr, withOccurrenceTitle as st, defineIslandPropsDecoder as t, normalizeCardRole as ti, buildEventCalendarListingRender as tn, canJoinEventWaitlistOnAnyMode as tr, getImplicitSingleTicketType as tt, buildProductCartItem as u, CANCELLED_SESSION_STATUS as ui, calendarMonthKey as un, groupPublicEventsByRun as ur, getTicketLineQuantity as ut, displayButtonText as v, getBookingLocalDateKey as vi, createHostedBlockApiConfig as vn, getBookingServiceSlidingScale as vr, planRegistrationDetailsCheck as vt, DEFAULT_BOOKING_BUTTON_TEXT as w, formatBookingPriceDisplay as wi, normalizeOptionalId as wn, prepareBookingSubmission as wr, settledRemainingPlaces as wt, toRegistrationEvents as x, resolveBookingTimeZoneId as xi, getEventRuntimeFiltersKey as xn, getShopSuccessCopy as xr, resolveRegistrationAdmission as xt, findBookedEvent as y, getLocalScheduleDate as yi, getBlockApiReadStage as yn, getBookingSuccessCopy as yr, planRegistrationDetailsContinuation as yt, decideEventChoice as z, resolveEventTimeZone as zn, err as zr, resolveRegistrationTarget as zt };