@riverbankcms/sdk 0.139.0 → 0.141.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 (232) hide show
  1. package/README.md +1 -1
  2. package/dist/{PreviewEditorSidebar-BDeenhi3.mjs → PreviewEditorSidebar-Q-fy9GYw.mjs} +4 -4
  3. package/dist/{PreviewEditorUI-DSRhgjF5.mjs → PreviewEditorUI-LYGzgk85.mjs} +3 -3
  4. package/dist/{PreviewQueryProvider-D2K8GLUG.mjs → PreviewQueryProvider-CN0ewic5.mjs} +1 -1
  5. package/dist/{SdkPreviewModeRuntime-CL7wSnYu.mjs → SdkPreviewModeRuntime-CoPYI5Jq.mjs} +90 -50
  6. package/dist/{SiteChromeCustomizeContext-BhDn-5ir.mjs → SiteChromeCustomizeContext-D8LePX8x.mjs} +2731 -1303
  7. package/dist/_dts/ai/src/contracts/proposals.d.ts +165 -165
  8. package/dist/_dts/ai/src/contracts/siteStyleProposalSchemas.d.ts +212 -212
  9. package/dist/_dts/api/src/accessAdmin.d.ts +74 -104
  10. package/dist/_dts/api/src/aiEndpoints.d.ts +5 -1
  11. package/dist/_dts/api/src/authSubmission.d.ts +46 -0
  12. package/dist/_dts/api/src/billing.d.ts +8 -4
  13. package/dist/_dts/api/src/billingEndpointDefinitions.d.ts +23 -0
  14. package/dist/_dts/api/src/billingEndpointTypes.d.ts +26 -0
  15. package/dist/_dts/api/src/blocks.d.ts +2 -0
  16. package/dist/_dts/api/src/bookingRecords.d.ts +1 -2
  17. package/dist/_dts/api/src/commercePortalEndpoints.d.ts +8 -1
  18. package/dist/_dts/api/src/communications.d.ts +0 -1
  19. package/dist/_dts/api/src/contentRuntime.d.ts +17 -31
  20. package/dist/_dts/api/src/domainConnection.d.ts +4 -0
  21. package/dist/_dts/api/src/endpoints.d.ts +93 -64
  22. package/dist/_dts/api/src/event-destination-policy.d.ts +2 -1
  23. package/dist/_dts/api/src/footerCompositionContracts.d.ts +25 -0
  24. package/dist/_dts/api/src/footerSettings.d.ts +9 -6
  25. package/dist/_dts/api/src/index.d.ts +6 -7
  26. package/dist/_dts/api/src/indexCoreTypes.d.ts +1 -1
  27. package/dist/_dts/api/src/indexExtendedTypes.d.ts +1 -1
  28. package/dist/_dts/api/src/launchReadiness.d.ts +1 -0
  29. package/dist/_dts/api/src/mailingListIntegration.d.ts +8 -2
  30. package/dist/_dts/api/src/navigation/dashboardSettingsNav.d.ts +1 -1
  31. package/dist/_dts/api/src/navigation/dashboardSiteNav.d.ts +2 -1
  32. package/dist/_dts/api/src/navigation/types.d.ts +1 -1
  33. package/dist/_dts/api/src/onboarding/confirmationResend.d.ts +25 -0
  34. package/dist/_dts/api/src/onboarding/surfaceData.d.ts +32 -32
  35. package/dist/_dts/api/src/publicBookingAvailabilityEndpointDefinitions.d.ts +8 -0
  36. package/dist/_dts/api/src/publicExperience/commerceEndpoints.d.ts +1 -0
  37. package/dist/_dts/api/src/publicExperience/eventEndpoints.d.ts +11 -3
  38. package/dist/_dts/api/src/publicExperience/sharedTypes.d.ts +3 -29
  39. package/dist/_dts/api/src/publicOnboardingAttemptEndpointDefinitions.d.ts +65 -0
  40. package/dist/_dts/api/src/saveOutcome.d.ts +20 -0
  41. package/dist/_dts/api/src/sdkContracts.d.ts +3 -22
  42. package/dist/_dts/api/src/sdkPushContracts.d.ts +18 -0
  43. package/dist/_dts/api/src/sdkThemeWire.d.ts +44 -44
  44. package/dist/_dts/api/src/settings/permissions.d.ts +12 -0
  45. package/dist/_dts/api/src/siteManagementEndpoints.d.ts +10 -29
  46. package/dist/_dts/api/src/siteOnboarding.d.ts +9 -9
  47. package/dist/_dts/api/src/sitePlatformEndpoints.d.ts +2 -4
  48. package/dist/_dts/api/src/siteRuntimeEndpoints.d.ts +3 -1
  49. package/dist/_dts/api/src/siteSettings.d.ts +20 -7
  50. package/dist/_dts/api/src/types.d.ts +77 -77
  51. package/dist/_dts/api/src/wholeSeriesRuns.d.ts +2 -37
  52. package/dist/_dts/billing/src/membership/index.d.ts +3 -0
  53. package/dist/_dts/billing/src/plans/types.d.ts +3 -0
  54. package/dist/_dts/billing/src/site-arrangements.d.ts +23 -3
  55. package/dist/_dts/blocks/src/contracts/proof-block-islands.d.ts +20 -4
  56. package/dist/_dts/blocks/src/pageRenderAdmission.d.ts +2 -0
  57. package/dist/_dts/blocks/src/pageRendererContracts.d.ts +7 -0
  58. package/dist/_dts/blocks/src/portal/types.d.ts +2 -4
  59. package/dist/_dts/blocks/src/portal/waitlist-types.d.ts +35 -0
  60. package/dist/_dts/blocks/src/system/blocks/event-registration.d.ts +2 -0
  61. package/dist/_dts/blocks/src/system/blocks/events/event-calendar.d.ts +2 -0
  62. package/dist/_dts/blocks/src/system/blocks/events/eventSelectionFields.d.ts +122 -0
  63. package/dist/_dts/blocks/src/system/blocks/events/shared/calendarWindow.d.ts +2 -1
  64. package/dist/_dts/blocks/src/system/blocks/events/shared/eventSelection.d.ts +11 -0
  65. package/dist/_dts/blocks/src/system/blocks/events/shared/schemas.d.ts +42 -0
  66. package/dist/_dts/blocks/src/system/blocks/events/shared/types.d.ts +4 -0
  67. package/dist/_dts/blocks/src/system/blocks/location-map.d.ts +2 -2
  68. package/dist/_dts/blocks/src/system/blocks/media-text.d.ts +47 -47
  69. package/dist/_dts/blocks/src/system/data/index.d.ts +2 -2
  70. package/dist/_dts/blocks/src/system/data/prefetchBlockData.d.ts +7 -1
  71. package/dist/_dts/blocks/src/system/data/types.d.ts +9 -0
  72. package/dist/_dts/blocks/src/system/data/utils.d.ts +1 -1
  73. package/dist/_dts/blocks/src/system/manifest/schema.d.ts +27 -1
  74. package/dist/_dts/blocks/src/system/registry.d.ts +1 -0
  75. package/dist/_dts/blocks/src/system/runtime/api/client.d.ts +0 -28
  76. package/dist/_dts/blocks/src/system/runtime/api/index.d.ts +1 -1
  77. package/dist/_dts/blocks/src/system/runtime/api/types/events.d.ts +7 -3
  78. package/dist/_dts/blocks/src/system/runtime/api/types/portal.d.ts +1 -1
  79. package/dist/_dts/blocks/src/system/runtime/api/types/waitlist-claims.d.ts +7 -2
  80. package/dist/_dts/blocks/src/system/runtime/components/registry.client.d.ts +42 -186
  81. package/dist/_dts/blocks/src/system/runtime/components/runtime-backed-blocks.d.ts +21 -93
  82. package/dist/_dts/blocks/src/system/runtime/hooks/useEventFilters.d.ts +2 -1
  83. package/dist/_dts/blocks/src/system/runtime/nodes/appointment-services.d.ts +48 -1
  84. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/EventRegistrationSurface.d.ts +1 -2
  85. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/TicketSelectionStep.d.ts +2 -0
  86. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/checkoutRecovery.d.ts +14 -0
  87. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/eventSourceRecovery.d.ts +56 -0
  88. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/hooks.d.ts +4 -0
  89. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/hooks.state.d.ts +5 -0
  90. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/types.d.ts +6 -8
  91. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useCheckoutRecovery.d.ts +8 -0
  92. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useDiscountCodeUi.d.ts +3 -0
  93. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useDiscountCodeUi.state.d.ts +10 -3
  94. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventCheckoutHandoffRestore.d.ts +9 -0
  95. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationSubmit.d.ts +8 -7
  96. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationWizard.d.ts +14 -7
  97. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventSourceRecovery.d.ts +18 -0
  98. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useSettledCommerceView.d.ts +37 -0
  99. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration.client.d.ts +1 -1
  100. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration.interactive.d.ts +24 -6
  101. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration.server.d.ts +4 -2
  102. package/dist/_dts/blocks/src/system/runtime/nodes/events/EventCombined.client.d.ts +4 -3
  103. package/dist/_dts/blocks/src/system/runtime/nodes/events/EventCombined.interactive.d.ts +3 -0
  104. package/dist/_dts/blocks/src/system/runtime/nodes/events/EventListing.interactive.d.ts +11 -101
  105. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/eventCollectionContract.d.ts +7 -2
  106. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/listOptions.d.ts +2 -0
  107. package/dist/_dts/blocks/src/system/runtime/nodes/newsletter-form.interactive.d.ts +6 -0
  108. package/dist/_dts/blocks/src/system/runtime/nodes/newsletter-form.types.d.ts +1 -0
  109. package/dist/_dts/blocks/src/system/runtime/resolver.d.ts +1 -0
  110. package/dist/_dts/blocks/src/system/runtime/shared/components/index.d.ts +2 -6
  111. package/dist/_dts/blocks/src/system/runtime/shared/index.d.ts +2 -2
  112. package/dist/_dts/blocks/src/system/runtime/shared/useWaitlistClaim.d.ts +2 -0
  113. package/dist/_dts/blocks/src/system/transforms/registry/eventCalendar.d.ts +12 -0
  114. package/dist/_dts/commerce/src/purchase/bookingInstalmentSchedule.d.ts +4 -0
  115. package/dist/_dts/commerce/src/purchase/event-registration-errors.d.ts +4 -0
  116. package/dist/_dts/commerce/src/purchase/orderItemMetadata.d.ts +27 -4
  117. package/dist/_dts/content-editor/src/controller/EntryControllerProvider.d.ts +2 -1
  118. package/dist/_dts/content-editor/src/hooks/useBlockAutosave.d.ts +3 -1
  119. package/dist/_dts/content-editor/src/useFooterComposerState.d.ts +3 -0
  120. package/dist/_dts/core/src/branded.d.ts +0 -8
  121. package/dist/_dts/core/src/index.d.ts +1 -0
  122. package/dist/_dts/core/src/mailing-list-setup-parser.d.ts +1 -1
  123. package/dist/_dts/core/src/mailing-list-setup.d.ts +14 -1
  124. package/dist/_dts/core/src/mailing-list-submission.d.ts +7 -27
  125. package/dist/_dts/core/src/participants.d.ts +2 -29
  126. package/dist/_dts/core/src/public-experience.d.ts +4 -0
  127. package/dist/_dts/core/src/public-profile.d.ts +27 -1
  128. package/dist/_dts/core/src/site-route-target.d.ts +9 -2
  129. package/dist/_dts/db/src/generated/supabase/database.types.d.ts +296 -606
  130. package/dist/_dts/editor-blocks/src/widgets/mailing-list-targeting/MailingListGlobalSettingsSummary.d.ts +10 -0
  131. package/dist/_dts/editor-blocks/src/widgets/mailing-list-targeting/MailingListTargetingField.d.ts +3 -2
  132. package/dist/_dts/editor-blocks/src/widgets/mailing-list-targeting/context.d.ts +3 -2
  133. package/dist/_dts/editor-blocks/src/widgets/mailing-list-targeting/loaders.d.ts +3 -2
  134. package/dist/_dts/editor-blocks/src/widgets/mailing-list-targeting/targetingState.d.ts +19 -0
  135. package/dist/_dts/editor-blocks/src/widgets/site-option-picker/loaders.d.ts +27 -1
  136. package/dist/_dts/sdk/src/public-api/contracts.d.ts +14 -20
  137. package/dist/_dts/sdk/src/rendering/blocks-page-renderer.d.ts +2 -0
  138. package/dist/_dts/sdk/src/rendering/components/pageShared.d.ts +2 -0
  139. package/dist/_dts/sdk/src/rendering/helpers/pageRuntimeSupport.d.ts +7 -1
  140. package/dist/_dts/sdk/src/rendering/helpers/templateContent.d.ts +1 -0
  141. package/dist/_dts/sdk/src/version.d.ts +1 -1
  142. package/dist/_dts/theme-core/src/ThemeFontLoader.d.ts +17 -1
  143. package/dist/_dts/theme-core/src/accordions/types.d.ts +3 -3
  144. package/dist/_dts/theme-core/src/buttons/affordanceSuppression.d.ts +17 -0
  145. package/dist/_dts/theme-core/src/buttons/buttonColourContract.d.ts +1 -1
  146. package/dist/_dts/theme-core/src/buttons/classNames.d.ts +16 -0
  147. package/dist/_dts/theme-core/src/buttons/generateButtonCss.d.ts +0 -6
  148. package/dist/_dts/theme-core/src/buttons/resolvedButtonCss.d.ts +4 -4
  149. package/dist/_dts/theme-core/src/cards/types.d.ts +21 -21
  150. package/dist/_dts/theme-core/src/generated/containerResponsiveThemeCss.d.ts +1 -1
  151. package/dist/_dts/theme-core/src/header/interactionPalette.d.ts +8 -2
  152. package/dist/_dts/theme-core/src/header/legacyHeaderVariant.d.ts +2 -2
  153. package/dist/_dts/theme-core/src/hosted-booking-appearance.d.ts +54 -12
  154. package/dist/_dts/theme-core/src/index.d.ts +1 -1
  155. package/dist/_dts/theme-core/src/inputs/types.d.ts +2 -2
  156. package/dist/_dts/theme-core/src/mock-themes/all.d.ts +54 -54
  157. package/dist/_dts/theme-core/src/runtime/buildThemeRuntimeFromBridge.d.ts +1 -4
  158. package/dist/_dts/theme-core/src/schema.d.ts +84 -84
  159. package/dist/_dts/theme-core/src/shared/componentStyles.d.ts +1 -1
  160. package/dist/_dts/theme-core/src/site-styles/backgroundAppearance.d.ts +2 -2
  161. package/dist/_dts/theme-core/src/surfaces/foregroundInteraction.d.ts +77 -0
  162. package/dist/_dts/theme-core/src/surfaces/index.d.ts +1 -0
  163. package/dist/_dts/theme-core/src/typography/generateTypographyCss.d.ts +2 -2
  164. package/dist/_dts/ui/src/lib/use-delayed-flag.d.ts +9 -0
  165. package/dist/_dts/ui/src/pending-button.d.ts +10 -0
  166. package/dist/client/{BookingConsentAgreement-CZvTDtsK.mjs → BookingConsentAgreement-xJeYNdnb.mjs} +4 -4
  167. package/dist/client/{DiscountCodeDisclosure-D-DsLCMU.mjs → DiscountCodeDisclosure-DdT6uzl9.mjs} +1 -1
  168. package/dist/client/{EventCombined.client-dWqgd5ZO.mjs → EventCombined.client-Cp28uYuM.mjs} +12 -16
  169. package/dist/client/{EventListing.client-BMRa9IYp.mjs → EventListing.client-CD6AJsMr.mjs} +4 -17
  170. package/dist/client/{LeafletStaticMap-D21W9kBZ.mjs → LeafletStaticMap-DBsAi9-e.mjs} +1 -1
  171. package/dist/client/{accordion-FxF_ta47.mjs → accordion-6dwbOKYR.mjs} +1 -1
  172. package/dist/client/{bookingForm-YnwW4TGw.mjs → bookingForm-CZE9_qPQ.mjs} +7 -7
  173. package/dist/client/bookings.mjs +500 -233
  174. package/dist/client/{carousel-vng7fFT5.mjs → carousel-7VHGQARz.mjs} +2 -2
  175. package/dist/client/{carousel.client-59G_WMr4.mjs → carousel.client-DQTjCVQT.mjs} +1 -1
  176. package/dist/client/{cart-DEPDsjNk.mjs → cart-Qg_mvQhh.mjs} +3 -3
  177. package/dist/client/{checkout-CZRWu9rW.mjs → checkout-D84rpgdr.mjs} +3 -3
  178. package/dist/client/{checkoutUrls-BuseL0dw.mjs → checkoutUrls-FL6lRkrt.mjs} +1 -1
  179. package/dist/client/client.mjs +2315 -1017
  180. package/dist/client/{colorStyles-CrxJrPjJ.mjs → colorStyles-3013aRAY.mjs} +3 -1
  181. package/dist/client/{context-DvU_WUmd.mjs → context-Ctp3T0Wr.mjs} +6 -19
  182. package/dist/client/{dates-wnPMiRl5.mjs → dates-DJKFcI_N.mjs} +2 -2
  183. package/dist/client/{eventCalendar-BA3Q5L15.mjs → eventCalendar-CK31z3vs.mjs} +12 -8
  184. package/dist/client/{eventCombined-51wgR-1R.mjs → eventCombined-DiXd-ewn.mjs} +3 -3
  185. package/dist/client/{eventDetails-modaetpm.mjs → eventDetails-CTRgt2DK.mjs} +4 -4
  186. package/dist/client/{eventListing-D8t2J3Kv.mjs → eventListing-Dy9vi_j_.mjs} +3 -3
  187. package/dist/client/{eventRegistration-CYqtkCE_.mjs → eventRegistration-CnalYMr2.mjs} +618 -177
  188. package/dist/client/{form-CBKXN5In.mjs → form-eUiMveTT.mjs} +3 -3
  189. package/dist/client/{headerSection-DylDqNrs.mjs → headerSection-Dy9kQpB1.mjs} +2 -2
  190. package/dist/client/hooks.mjs +692 -212
  191. package/dist/client/{locationMap-CvWrG0vZ.mjs → locationMap-DalCmWU0.mjs} +3 -3
  192. package/dist/client/{media-BOHuueS5.mjs → media-DHpfFwd3.mjs} +1 -1
  193. package/dist/client/{newsletterForm-Btwk70zw.mjs → newsletterForm-SDDPvhS0.mjs} +150 -94
  194. package/dist/client/{pricing-Uzw-GQ6Y.mjs → pricing-OcMz4SnX.mjs} +1 -1
  195. package/dist/client/{productDetail-JLcUYKnd.mjs → productDetail-BQrgHElM.mjs} +3 -3
  196. package/dist/client/{productList-FM0cbUzj.mjs → productList-OnPn_UJj.mjs} +3 -3
  197. package/dist/client/{propsDecoder-DYzafZb2.mjs → propsDecoder-zBdsnS-N.mjs} +168 -32
  198. package/dist/client/rendering/client.mjs +1355 -519
  199. package/dist/client/rendering/islands.mjs +19 -19
  200. package/dist/client/rendering.mjs +2294 -953
  201. package/dist/client/{scrollToBlock-CvXszexS.mjs → scrollToBlock-BNM4Ob2Y.mjs} +28 -11
  202. package/dist/client/{shop-BIcjvy5a.mjs → shop-Bv1fPTwQ.mjs} +6 -6
  203. package/dist/client/{shop-commerce-BZQsy7xw.mjs → shop-commerce-D4KNGaW8.mjs} +7 -7
  204. package/dist/client/{shop-commerce-store-D5V7XAb5.mjs → shop-commerce-store-2N5EV0Rc.mjs} +1 -1
  205. package/dist/client/{shopShared-DowkXevB.mjs → shopShared-DvJGdHTV.mjs} +4 -4
  206. package/dist/client/{useEventFilters-oMoTw_JE.mjs → useEventFilters-BBBvGDHQ.mjs} +19 -13
  207. package/dist/preview-next/before-render.mjs +119 -64
  208. package/dist/preview-next/client/runtime.mjs +4 -4
  209. package/dist/preview-next/editor-chrome.css +4 -8
  210. package/dist/preview-next/keepAlive.mjs +119 -64
  211. package/dist/preview-next/middleware.mjs +119 -64
  212. package/dist/{previewAuthStore-COUyAKaX.mjs → previewAuthStore-Gjb6r6vz.mjs} +119 -64
  213. package/dist/{sdk-runtime-D4k2LSGF.mjs → sdk-runtime-Defnbfzw.mjs} +2 -2
  214. package/dist/{separator-UGtpag4Z.mjs → separator-CZXO3Sb0.mjs} +1 -1
  215. package/dist/server/components.mjs +1170 -384
  216. package/dist/server/config-validation.mjs +560 -105
  217. package/dist/server/config.mjs +564 -109
  218. package/dist/server/data.mjs +688 -212
  219. package/dist/server/index.mjs +126 -66
  220. package/dist/server/next.mjs +1429 -662
  221. package/dist/server/page-converter.mjs +372 -99
  222. package/dist/server/prebuild.mjs +1 -1
  223. package/dist/server/rendering/server.mjs +1624 -817
  224. package/dist/server/rendering.mjs +1200 -391
  225. package/dist/server/routing.mjs +767 -247
  226. package/dist/server/server.mjs +715 -276
  227. package/dist/server/theme-bridge.mjs +475 -110
  228. package/dist/server/theme.mjs +9 -3
  229. package/dist/styles/index.css +265 -45
  230. package/package.json +1 -1
  231. package/dist/_dts/blocks/src/system/runtime/shared/components/BookingOptionCompactRow.d.ts +0 -29
  232. package/dist/_dts/blocks/src/system/runtime/shared/components/BookingOptionList.d.ts +0 -13
@@ -33,10 +33,12 @@ const unsafeAsMediaAssetId = (id) => id;
33
33
  const unsafeAsStorageBucketName = (value) => value;
34
34
  const unsafeAsStoragePath = (value) => value;
35
35
  const unsafeAsUserId = (id) => id;
36
+ const unsafeAsContentVersionId = (id) => id;
36
37
  const parseSiteId = (value) => parseUuidBrand(value, unsafeAsSiteId);
37
38
  const parseApiKeyId = (value) => parseUuidBrand(value, unsafeAsApiKeyId);
38
39
  const parseEventOfferingId = (value) => parseUuidBrand(value, unsafeAsEventOfferingId);
39
40
  const parseUserId = (value) => parseUuidBrand(value, unsafeAsUserId);
41
+ const parseContentVersionId = (value) => parseUuidBrand(value, unsafeAsContentVersionId);
40
42
  const parseEventSeriesId = (value) => parseUuidBrand(value, unsafeAsEventSeriesId);
41
43
  //#endregion
42
44
  //#region ../core/src/assert-never.ts
@@ -313,7 +315,7 @@ function parseEventPageSurfaceDestinationMode(value) {
313
315
  return value === "cms-managed" || value === "system-managed" ? value : void 0;
314
316
  }
315
317
  function parseEventPageSurfaceSubject(value) {
316
- if (!isRecord$20(value)) return err({ kind: "notObject" });
318
+ if (!isRecord$21(value)) return err({ kind: "notObject" });
317
319
  switch (value.kind) {
318
320
  case "eventSeries": {
319
321
  const eventSeriesId = parseEventSeriesId(value.eventSeriesId);
@@ -368,7 +370,7 @@ function parseEventSeriesIdList(values) {
368
370
  }
369
371
  return ok$1(parsed);
370
372
  }
371
- function isRecord$20(value) {
373
+ function isRecord$21(value) {
372
374
  return typeof value === "object" && value !== null && !Array.isArray(value);
373
375
  }
374
376
  //#endregion
@@ -625,16 +627,47 @@ function parsePositiveInteger(value) {
625
627
  function parseNewsletterListId(value) {
626
628
  return parseTrimmedMatchingString(value, UUID_PATTERN);
627
629
  }
630
+ function parseMailchimpAccountId(value) {
631
+ return parseTrimmedMatchingString(value, OPAQUE_ID_PATTERN);
632
+ }
628
633
  function parseMailchimpAudienceId(value) {
629
634
  return parseTrimmedMatchingString(value, OPAQUE_ID_PATTERN);
630
635
  }
631
636
  function parseMailchimpInterestId(value) {
632
637
  return parseTrimmedMatchingString(value, OPAQUE_ID_PATTERN);
633
638
  }
639
+ function parseBrevoAccountId(value) {
640
+ return parseTrimmedMatchingString(value, OPAQUE_ID_PATTERN);
641
+ }
634
642
  function parseBrevoListId(value) {
635
643
  return parsePositiveInteger(value);
636
644
  }
637
645
  //#endregion
646
+ //#region ../core/src/mailing-list-setup.ts
647
+ function isRecord$20(value) {
648
+ return typeof value === "object" && value !== null && !Array.isArray(value);
649
+ }
650
+ const DEFAULT_MAILING_LIST_SUCCESS_MESSAGE = "Thanks — you're on the list.";
651
+ function parseMailingListProviderScope(value) {
652
+ if (!isRecord$20(value)) return err("invalid_mailing_list_provider_scope");
653
+ if (value.provider === "native") return ok$1({ provider: "native" });
654
+ if (value.provider === "brevo") {
655
+ const accountId = parseBrevoAccountId(value.accountId);
656
+ return accountId !== null ? ok$1({
657
+ provider: "brevo",
658
+ accountId
659
+ }) : err("invalid_mailing_list_provider_scope");
660
+ }
661
+ if (value.provider === "mailchimp") {
662
+ const accountId = parseMailchimpAccountId(value.accountId);
663
+ return accountId !== null ? ok$1({
664
+ provider: "mailchimp",
665
+ accountId
666
+ }) : err("invalid_mailing_list_provider_scope");
667
+ }
668
+ return err("invalid_mailing_list_provider_scope");
669
+ }
670
+ //#endregion
638
671
  //#region ../core/src/mailing-list-setup-parser.ts
639
672
  function parseMailingListGlobalForm(value) {
640
673
  if (!isRecord$19(value)) return formError("shape");
@@ -643,12 +676,15 @@ function parseMailingListGlobalForm(value) {
643
676
  if (typeof value.includeOptionalPhone !== "boolean") return formError("includeOptionalPhone");
644
677
  const buttonLabel = parseRequiredString(value.buttonLabel);
645
678
  if (buttonLabel === null) return formError("buttonLabel");
679
+ const successMessage = parseRequiredString(value.successMessage);
680
+ if (successMessage === null) return formError("successMessage");
646
681
  const privacyNote = parseOptionalString(value.privacyNote);
647
682
  if (privacyNote === void 0) return formError("privacyNote");
648
683
  return ok$1({
649
684
  fields,
650
685
  includeOptionalPhone: value.includeOptionalPhone,
651
686
  buttonLabel,
687
+ successMessage,
652
688
  privacyNote
653
689
  });
654
690
  }
@@ -978,11 +1014,17 @@ function parseMailingListSignedSourceToken(value) {
978
1014
  const parsed = typeof value === "string" ? value.trim() : "";
979
1015
  return /^[A-Za-z0-9._~-]{16,1000}$/u.test(parsed) ? parsed : null;
980
1016
  }
981
- function buildMailingListSignupBlockSourceRef(blockId) {
982
- const parsed = parseMailingListBlockId(blockId);
983
- return parsed !== null ? {
1017
+ function parseMailingListContentVersionId(value) {
1018
+ const parsed = parseContentVersionId(value);
1019
+ return parsed.ok ? parsed.value : null;
1020
+ }
1021
+ function buildMailingListSignupBlockSourceRef(blockId, contentVersionId) {
1022
+ const parsedBlockId = parseMailingListBlockId(blockId);
1023
+ const parsedContentVersionId = parseMailingListContentVersionId(contentVersionId);
1024
+ return parsedBlockId !== null && parsedContentVersionId !== null ? {
984
1025
  tag: "block_ref",
985
- blockId: parsed
1026
+ blockId: parsedBlockId,
1027
+ contentVersionId: parsedContentVersionId
986
1028
  } : null;
987
1029
  }
988
1030
  //#endregion
@@ -1961,6 +2003,7 @@ function isDisplayMediaKind(kind) {
1961
2003
  }
1962
2004
  const siteOptionSources = [
1963
2005
  "eventCategories",
2006
+ "eventSeries",
1964
2007
  "venues",
1965
2008
  "staffMembers"
1966
2009
  ];
@@ -5286,6 +5329,509 @@ function parseThemeColorToken(value) {
5286
5329
  }
5287
5330
  const themeColorTokenSchema = z.string().min(1).refine((value) => Boolean(isThemeColorToken(value)), "Expected a known Theme V2 color token");
5288
5331
  //#endregion
5332
+ //#region ../theme-core/src/surfaces/foregroundRoles.ts
5333
+ const SURFACE_FOREGROUND_ROLES = [
5334
+ "text",
5335
+ "heading",
5336
+ "link",
5337
+ "supporting"
5338
+ ];
5339
+ //#endregion
5340
+ //#region ../theme-core/src/surfaces/foregroundContract.ts
5341
+ const SURFACE_FOREGROUND_CSS_VARS = {
5342
+ text: "--rb-surface-text-color",
5343
+ heading: "--rb-surface-heading-color",
5344
+ link: "--rb-surface-link-color",
5345
+ supporting: "--rb-surface-supporting-color"
5346
+ };
5347
+ const DEFAULT_SURFACE_TEXT_COLOR = "rgb(var(--tb-text, 17 24 39))";
5348
+ const DEFAULT_ROLE_FALLBACKS = {
5349
+ text: DEFAULT_SURFACE_TEXT_COLOR,
5350
+ heading: DEFAULT_SURFACE_TEXT_COLOR,
5351
+ link: "rgb(var(--tb-primary, var(--tb-text, 17 24 39)))",
5352
+ supporting: "rgb(var(--tb-mutedText, 100 116 139))"
5353
+ };
5354
+ function requireSurfaceColorValue(role, value) {
5355
+ const normalized = value.trim();
5356
+ if (normalized.length === 0) throw new RangeError(`Surface foreground ${role} must be a non-empty CSS color.`);
5357
+ return normalized;
5358
+ }
5359
+ function completeSurfaceForegrounds(input) {
5360
+ const text = requireSurfaceColorValue("text", input.text);
5361
+ return {
5362
+ text,
5363
+ heading: input.heading === void 0 ? text : requireSurfaceColorValue("heading", input.heading),
5364
+ link: input.link === void 0 ? text : requireSurfaceColorValue("link", input.link),
5365
+ supporting: input.supporting === void 0 ? text : requireSurfaceColorValue("supporting", input.supporting)
5366
+ };
5367
+ }
5368
+ function surfaceForegroundValue(role, outsideProviderFallback = DEFAULT_ROLE_FALLBACKS[role]) {
5369
+ const roleVariable = SURFACE_FOREGROUND_CSS_VARS[role];
5370
+ const fallback = requireSurfaceColorValue("fallback", outsideProviderFallback);
5371
+ if (role === "text") return `var(${roleVariable}, ${fallback})`;
5372
+ return `var(${roleVariable}, var(${SURFACE_FOREGROUND_CSS_VARS.text}, ${fallback}))`;
5373
+ }
5374
+ function surfaceForegroundValueWithOpacity(role, opacityPercent) {
5375
+ if (!Number.isFinite(opacityPercent) || opacityPercent < 0 || opacityPercent > 100) throw new RangeError("Surface foreground opacity must be between 0 and 100.");
5376
+ return `color-mix(in srgb, ${surfaceForegroundValue(role)} ${opacityPercent}%, transparent)`;
5377
+ }
5378
+ function surfaceForegroundStyle(input) {
5379
+ const foregrounds = completeSurfaceForegrounds(input);
5380
+ return {
5381
+ color: foregrounds.text,
5382
+ [SURFACE_FOREGROUND_CSS_VARS.text]: foregrounds.text,
5383
+ [SURFACE_FOREGROUND_CSS_VARS.heading]: foregrounds.heading,
5384
+ [SURFACE_FOREGROUND_CSS_VARS.link]: foregrounds.link,
5385
+ [SURFACE_FOREGROUND_CSS_VARS.supporting]: foregrounds.supporting
5386
+ };
5387
+ }
5388
+ function surfaceForegroundDeclarations(input) {
5389
+ const foregrounds = completeSurfaceForegrounds(input);
5390
+ return [`color: ${foregrounds.text}`, ...SURFACE_FOREGROUND_ROLES.map((role) => `${SURFACE_FOREGROUND_CSS_VARS[role]}: ${foregrounds[role]}`)];
5391
+ }
5392
+ //#endregion
5393
+ //#region ../theme-core/src/palette/colors.ts
5394
+ const HEX_COLOR_REGEX = /^#[0-9a-f]{6}$/;
5395
+ const NORMALIZABLE_HEX_REGEX = /^#(?:[0-9a-f]{3}|[0-9a-f]{6})$/i;
5396
+ const THEME_PALETTE_COLOR_ORDER = [
5397
+ "primary",
5398
+ "secondary",
5399
+ "accent",
5400
+ "success",
5401
+ "warning",
5402
+ "destructive",
5403
+ "background",
5404
+ "surface",
5405
+ "surfaceAlt",
5406
+ "muted",
5407
+ "text",
5408
+ "primaryForeground",
5409
+ "border"
5410
+ ];
5411
+ const hexColorSchema = z.string().regex(HEX_COLOR_REGEX, "Hex must be #RRGGBB (lowercase)").transform((value) => value);
5412
+ const paletteModeSchema = z.enum(["light", "dark"]);
5413
+ const PALETTE_VALUE_KEY_PREFIX = "palette-value:v1|";
5414
+ z.string().regex(/^[0-9a-f]{64}$/, "Palette hash must be a lowercase SHA-256 value").transform((value) => value);
5415
+ const paletteColorsSchema = z.object({
5416
+ primary: hexColorSchema,
5417
+ primaryForeground: hexColorSchema,
5418
+ secondary: hexColorSchema,
5419
+ accent: hexColorSchema,
5420
+ success: hexColorSchema,
5421
+ warning: hexColorSchema,
5422
+ destructive: hexColorSchema,
5423
+ background: hexColorSchema,
5424
+ surface: hexColorSchema,
5425
+ surfaceAlt: hexColorSchema,
5426
+ muted: hexColorSchema,
5427
+ text: hexColorSchema,
5428
+ border: hexColorSchema
5429
+ }).strict().transform((value) => value);
5430
+ function normalizePaletteHex(value) {
5431
+ if (!NORMALIZABLE_HEX_REGEX.test(value)) return null;
5432
+ const normalized = value.toLowerCase();
5433
+ if (normalized.length === 7) return normalized;
5434
+ const triplet = normalized.slice(1);
5435
+ const red = triplet.charAt(0);
5436
+ const green = triplet.charAt(1);
5437
+ const blue = triplet.charAt(2);
5438
+ return `#${red}${red}${green}${green}${blue}${blue}`;
5439
+ }
5440
+ function paletteColorsFromEntries(entries) {
5441
+ const values = {};
5442
+ for (const entry of entries) {
5443
+ const parsedRole = paletteTokenNameSchema.safeParse(entry.name);
5444
+ if (!parsedRole.success) return {
5445
+ ok: false,
5446
+ error: {
5447
+ kind: "unknown-role",
5448
+ role: entry.name
5449
+ }
5450
+ };
5451
+ const role = parsedRole.data;
5452
+ if (values[role] !== void 0) return {
5453
+ ok: false,
5454
+ error: {
5455
+ kind: "duplicate-role",
5456
+ role
5457
+ }
5458
+ };
5459
+ const hex = normalizePaletteHex(entry.hex);
5460
+ if (!hex) return {
5461
+ ok: false,
5462
+ error: {
5463
+ kind: "invalid-color",
5464
+ role,
5465
+ value: entry.hex
5466
+ }
5467
+ };
5468
+ values[role] = hex;
5469
+ }
5470
+ const missing = PALETTE_TOKEN_NAMES.filter((role) => values[role] === void 0);
5471
+ if (missing.length > 0) return {
5472
+ ok: false,
5473
+ error: {
5474
+ kind: "missing-roles",
5475
+ roles: missing
5476
+ }
5477
+ };
5478
+ return {
5479
+ ok: true,
5480
+ colors: paletteColorsSchema.parse(values)
5481
+ };
5482
+ }
5483
+ function requirePaletteColorsFromEntries(entries) {
5484
+ const result = paletteColorsFromEntries(entries);
5485
+ if (result.ok) return result.colors;
5486
+ throw new Error(`Invalid complete palette: ${result.error.kind}`);
5487
+ }
5488
+ function paletteColorEntries(colors) {
5489
+ return THEME_PALETTE_COLOR_ORDER.map((name) => ({
5490
+ name,
5491
+ hex: colors[name]
5492
+ }));
5493
+ }
5494
+ function paletteColorFingerprint(colors) {
5495
+ return PALETTE_TOKEN_NAMES.map((name) => `${name}:${colors[name]}`).join("|");
5496
+ }
5497
+ function canonicalPaletteHashInput(colors, mode) {
5498
+ return `${mode}|${paletteColorFingerprint(colors)}`;
5499
+ }
5500
+ /**
5501
+ * Stable curated-catalogue identity. Do not reorder roles: the order comes
5502
+ * from PALETTE_TOKEN_NAMES through canonicalPaletteHashInput.
5503
+ */
5504
+ function paletteValueKey(colors, mode) {
5505
+ return `${PALETTE_VALUE_KEY_PREFIX}${canonicalPaletteHashInput(colors, mode)}`;
5506
+ }
5507
+ /** Parses only the exact v1 canonical form emitted by paletteValueKey. */
5508
+ function parsePaletteValueKey(value) {
5509
+ if (typeof value !== "string" || !value.startsWith(PALETTE_VALUE_KEY_PREFIX)) return null;
5510
+ const [rawMode, ...rawRoles] = value.slice(17).split("|");
5511
+ const mode = paletteModeSchema.safeParse(rawMode);
5512
+ if (!mode.success || rawRoles.length !== PALETTE_TOKEN_NAMES.length) return null;
5513
+ const colors = paletteColorsFromEntries(rawRoles.map((roleValue) => {
5514
+ const separator = roleValue.indexOf(":");
5515
+ return separator === -1 ? {
5516
+ name: "",
5517
+ hex: ""
5518
+ } : {
5519
+ name: roleValue.slice(0, separator),
5520
+ hex: roleValue.slice(separator + 1)
5521
+ };
5522
+ }));
5523
+ if (!colors.ok || paletteValueKey(colors.colors, mode.data) !== value) return null;
5524
+ return value;
5525
+ }
5526
+ const paletteValueKeySchema = z.string().transform((value, ctx) => {
5527
+ const parsed = parsePaletteValueKey(value);
5528
+ if (parsed) return parsed;
5529
+ ctx.addIssue({
5530
+ code: "custom",
5531
+ message: "Invalid canonical palette value key"
5532
+ });
5533
+ return z.NEVER;
5534
+ });
5535
+ //#endregion
5536
+ //#region ../theme-core/src/palette/utils/opaqueSurfaceColor.ts
5537
+ /** Resolve an opaque colour, compositing alpha against an explicit underlay. */
5538
+ function resolveOpaqueSurfaceHex(reference, palette, underlayReference) {
5539
+ const opaque = resolveConcreteColorHex(reference, palette);
5540
+ if (opaque) return opaque;
5541
+ if (!underlayReference) return null;
5542
+ const underlayHex = resolveConcreteColorHex(underlayReference, palette);
5543
+ if (!underlayHex) return null;
5544
+ const parts = parseColorTokenParts(reference);
5545
+ if (parts.kind === "token" && parts.opacityPercent !== null) {
5546
+ const foregroundHex = normalizePaletteHex(palette[parts.token] ?? "");
5547
+ return foregroundHex ? compositeHex(foregroundHex, underlayHex, parts.opacityPercent / 100) : null;
5548
+ }
5549
+ const rgba = parseRgba(parts.kind === "raw" ? parts.value : reference);
5550
+ return rgba ? compositeHex(rgbToHex(rgba.r, rgba.g, rgba.b), underlayHex, rgba.alpha) : null;
5551
+ }
5552
+ /** Resolve a colour reference only when it is already fully opaque. */
5553
+ function resolveConcreteColorHex(reference, palette) {
5554
+ const literalHex = normalizePaletteHex(reference);
5555
+ if (literalHex) return literalHex;
5556
+ const parts = parseColorTokenParts(reference);
5557
+ if (parts.kind === "token") {
5558
+ if (parts.opacityPercent !== null) return null;
5559
+ return normalizePaletteHex(palette[parts.token] ?? "");
5560
+ }
5561
+ const literal = parts.kind === "raw" ? parts.value : reference;
5562
+ if (literal.toLowerCase() === "black") return "#000000";
5563
+ if (literal.toLowerCase() === "white") return "#ffffff";
5564
+ return normalizePaletteHex(literal);
5565
+ }
5566
+ function compositeHex(foregroundHex, underlayHex, alpha) {
5567
+ const foreground = hexToRgb(foregroundHex);
5568
+ const underlay = hexToRgb(underlayHex);
5569
+ const channel = (foregroundValue, underlayValue) => Math.round(foregroundValue * alpha + underlayValue * (1 - alpha));
5570
+ return rgbToHex(channel(foreground.r, underlay.r), channel(foreground.g, underlay.g), channel(foreground.b, underlay.b));
5571
+ }
5572
+ function parseRgba(value) {
5573
+ const match = value.trim().match(/^rgba?\(\s*([\d.]+)(?:\s*,\s*|\s+)([\d.]+)(?:\s*,\s*|\s+)([\d.]+)(?:\s*(?:,|\/)\s*([\d.]+%?))?\s*\)$/i);
5574
+ if (!match) return null;
5575
+ const [, rSource, gSource, bSource] = match;
5576
+ if (!rSource || !gSource || !bSource) return null;
5577
+ const r = Number(rSource);
5578
+ const g = Number(gSource);
5579
+ const b = Number(bSource);
5580
+ const alpha = parseAlpha(match[4]);
5581
+ if (alpha === null || !isRgbChannel(r) || !isRgbChannel(g) || !isRgbChannel(b)) return null;
5582
+ return {
5583
+ r,
5584
+ g,
5585
+ b,
5586
+ alpha
5587
+ };
5588
+ }
5589
+ function parseAlpha(source) {
5590
+ if (!source) return 1;
5591
+ const value = source.endsWith("%") ? Number(source.slice(0, -1)) / 100 : Number(source);
5592
+ return Number.isFinite(value) && value >= 0 && value <= 1 ? value : null;
5593
+ }
5594
+ function isRgbChannel(value) {
5595
+ return Number.isFinite(value) && value >= 0 && value <= 255;
5596
+ }
5597
+ //#endregion
5598
+ //#region ../theme-core/src/surfaces/resolveSurfaceForeground.ts
5599
+ const FALLBACK_TEXT_TOKENS = [
5600
+ "text",
5601
+ "primaryForeground",
5602
+ "secondaryForeground",
5603
+ "accentForeground",
5604
+ "neutral-950",
5605
+ "neutral-50"
5606
+ ];
5607
+ const CANONICAL_EQUIVALENT_TOKEN_ORDER = [
5608
+ "text",
5609
+ "primaryForeground",
5610
+ "secondaryForeground",
5611
+ "accentForeground",
5612
+ "onPrimary",
5613
+ "onSecondary",
5614
+ "onAccent",
5615
+ "onSurface",
5616
+ "neutral-950",
5617
+ "neutral-50"
5618
+ ];
5619
+ /**
5620
+ * Resolve the complete foreground contract for an effective page/section or
5621
+ * site-chrome background.
5622
+ *
5623
+ * Deterministic colour backgrounds are validated at ordinary-text WCAG AA.
5624
+ * Existing image/video/gradient treatments are trusted only when they already
5625
+ * carry a usable foreground token; this function deliberately does not claim
5626
+ * pixel-level contrast proof for media.
5627
+ */
5628
+ function resolveSurfaceForeground(background, palette, candidates = {}, options = {}) {
5629
+ const authored = foregroundCandidates(background, candidates);
5630
+ if (background === null) return resolveDeterministicForeground("background", {
5631
+ ...authored,
5632
+ text: authored.text ?? "text"
5633
+ }, palette);
5634
+ if (background.type === "color") {
5635
+ const backgroundReference = normalizedReference(background.color);
5636
+ if (!backgroundReference || backgroundReference === "transparent") return { kind: "unknown" };
5637
+ return resolveDeterministicForeground(backgroundReference, authored, palette, options.compositeBase);
5638
+ }
5639
+ return resolveTrustedTreatmentForeground(authored, palette);
5640
+ }
5641
+ function foregroundCandidates(background, overrides) {
5642
+ return {
5643
+ text: overrides.text ?? background?.textColor ?? null,
5644
+ heading: overrides.heading ?? background?.headingColor ?? null,
5645
+ link: overrides.link ?? background?.linkColor ?? null,
5646
+ supporting: overrides.supporting ?? background?.supportingColor ?? null
5647
+ };
5648
+ }
5649
+ function resolveDeterministicForeground(backgroundReference, candidates, palette, compositeBase) {
5650
+ const backgroundHex = resolveOpaqueSurfaceHex(backgroundReference, palette, compositeBase);
5651
+ if (!backgroundHex) return resolveTrustedTreatmentForeground(candidates, palette);
5652
+ const backgroundToken = paletteToken(backgroundReference);
5653
+ const derivedOnToken = backgroundToken ? onColorTokenName(backgroundToken) : null;
5654
+ const text = firstSafeToken([
5655
+ candidates.text,
5656
+ derivedOnToken,
5657
+ ...FALLBACK_TEXT_TOKENS
5658
+ ], backgroundHex, palette, derivedOnToken ? [derivedOnToken] : []);
5659
+ if (!text) return { kind: "unknown" };
5660
+ return {
5661
+ kind: "known",
5662
+ roles: {
5663
+ text,
5664
+ heading: safeTokenOr(candidates.heading, text, backgroundHex, palette),
5665
+ link: safeTokenOr(candidates.link, text, backgroundHex, palette),
5666
+ supporting: safeTokenOr(candidates.supporting, text, backgroundHex, palette)
5667
+ }
5668
+ };
5669
+ }
5670
+ function resolveTrustedTreatmentForeground(candidates, palette) {
5671
+ const text = canonicalToken(candidates.text, palette);
5672
+ if (!text) return { kind: "unknown" };
5673
+ return {
5674
+ kind: "known",
5675
+ roles: {
5676
+ text,
5677
+ heading: canonicalToken(candidates.heading, palette) ?? text,
5678
+ link: canonicalToken(candidates.link, palette) ?? text,
5679
+ supporting: canonicalToken(candidates.supporting, palette) ?? text
5680
+ }
5681
+ };
5682
+ }
5683
+ function safeTokenOr(candidate, fallback, backgroundHex, palette) {
5684
+ return firstSafeToken([candidate], backgroundHex, palette) ?? fallback;
5685
+ }
5686
+ function firstSafeToken(candidates, backgroundHex, palette, preferredEquivalentTokens = []) {
5687
+ const seen = /* @__PURE__ */ new Set();
5688
+ for (const candidate of candidates) {
5689
+ const token = canonicalToken(candidate, palette, preferredEquivalentTokens);
5690
+ if (!token || seen.has(token)) continue;
5691
+ seen.add(token);
5692
+ const foregroundHex = resolveConcreteColorHex(token, palette);
5693
+ if (foregroundHex && contrastRatio(backgroundHex, foregroundHex) >= 4.5) return token;
5694
+ }
5695
+ return null;
5696
+ }
5697
+ function canonicalToken(reference, palette, preferredEquivalentTokens = []) {
5698
+ const normalized = normalizedReference(reference);
5699
+ if (!normalized || normalized === "transparent") return null;
5700
+ const direct = parseThemeColorToken(normalized);
5701
+ if (direct && resolveConcreteColorHex(direct, palette)) return direct;
5702
+ const referenceHex = resolveConcreteColorHex(normalized, palette);
5703
+ if (!referenceHex) return null;
5704
+ const equivalent = [
5705
+ ...preferredEquivalentTokens,
5706
+ ...CANONICAL_EQUIVALENT_TOKEN_ORDER,
5707
+ ...Object.keys(palette).sort()
5708
+ ].find((token) => {
5709
+ const parsed = parseThemeColorToken(token);
5710
+ return parsed !== null && resolveConcreteColorHex(parsed, palette)?.toLowerCase() === referenceHex.toLowerCase();
5711
+ });
5712
+ return equivalent ? parseThemeColorToken(equivalent) : null;
5713
+ }
5714
+ function paletteToken(reference) {
5715
+ const parts = parseColorTokenParts(reference);
5716
+ return parts.kind === "token" && parts.opacityPercent === null ? parts.token : null;
5717
+ }
5718
+ function normalizedReference(value) {
5719
+ if (typeof value !== "string") return null;
5720
+ const normalized = value.trim();
5721
+ return normalized.length > 0 ? normalized : null;
5722
+ }
5723
+ //#endregion
5724
+ //#region ../theme-core/src/utils/colorStyles.ts
5725
+ const COLOR_VAR_PREFIX = "--tb-";
5726
+ function parseToken(source) {
5727
+ const parts = parseColorTokenParts(source);
5728
+ if (parts.kind === "raw") return {
5729
+ token: source,
5730
+ raw: parts.value
5731
+ };
5732
+ if (parts.kind === "invalid") return { token: source };
5733
+ return {
5734
+ token: parts.token,
5735
+ opacityPercent: parts.opacityPercent === null ? void 0 : parts.opacityPercent
5736
+ };
5737
+ }
5738
+ const SURFACE_TEXT_ROLE_BY_TOKEN = {
5739
+ text: "text",
5740
+ heading: "heading",
5741
+ mutedText: "supporting"
5742
+ };
5743
+ function surfaceRoleForTextToken(token) {
5744
+ return Object.prototype.hasOwnProperty.call(SURFACE_TEXT_ROLE_BY_TOKEN, token) ? SURFACE_TEXT_ROLE_BY_TOKEN[token] : null;
5745
+ }
5746
+ /**
5747
+ * Converts a theme color token to a CSS rgb value.
5748
+ * This is the primary function for applying theme colors to CSS properties.
5749
+ *
5750
+ * @param token - Theme color token (semantic, with opacity, or raw)
5751
+ * @returns CSS color value (rgb with optional alpha, or raw CSS value)
5752
+ *
5753
+ * @example
5754
+ * rgbColorValue('primary') // => 'rgb(var(--tb-primary))'
5755
+ * rgbColorValue('surface/95') // => 'rgb(var(--tb-surface) / 0.95)'
5756
+ * rgbColorValue('raw:transparent') // => 'transparent'
5757
+ */
5758
+ function rgbColorValue(token) {
5759
+ const { token: baseToken, opacityPercent, raw } = parseToken(token);
5760
+ if (raw) return raw;
5761
+ const cssVar = `${COLOR_VAR_PREFIX}${baseToken}`;
5762
+ if (opacityPercent === void 0) return `rgb(var(${cssVar}))`;
5763
+ return `rgb(var(${cssVar}) / ${opacityPercent / 100})`;
5764
+ }
5765
+ /**
5766
+ * Converts a theme color token to a CSS variable reference.
5767
+ * Note: This returns the base variable without rgb() wrapper, ignoring opacity.
5768
+ *
5769
+ * @param token - Theme color token
5770
+ * @returns CSS variable reference
5771
+ *
5772
+ * @example
5773
+ * cssVarValue('primary') // => 'var(--tb-primary)'
5774
+ * cssVarValue('surface/95') // => 'var(--tb-surface)' (opacity ignored)
5775
+ */
5776
+ function cssVarValue(token) {
5777
+ const { token: baseToken } = parseToken(token);
5778
+ return `var(${COLOR_VAR_PREFIX}${baseToken})`;
5779
+ }
5780
+ /**
5781
+ * Creates a backgroundColor style object from a theme token.
5782
+ *
5783
+ * @param token - Theme color token
5784
+ * @returns CSSProperties with backgroundColor
5785
+ */
5786
+ function backgroundColorStyle(token) {
5787
+ return { backgroundColor: rgbColorValue(token) };
5788
+ }
5789
+ /**
5790
+ * Creates a text color style object from a theme token.
5791
+ *
5792
+ * @param token - Theme color token
5793
+ * @returns CSSProperties with color
5794
+ */
5795
+ function textColorStyle(token) {
5796
+ const parsed = parseToken(token);
5797
+ const surfaceRole = parsed.raw ? null : surfaceRoleForTextToken(parsed.token);
5798
+ if (surfaceRole) return { color: parsed.opacityPercent === void 0 ? surfaceForegroundValue(surfaceRole) : surfaceForegroundValueWithOpacity(surfaceRole, parsed.opacityPercent) };
5799
+ return { color: rgbColorValue(token) };
5800
+ }
5801
+ /**
5802
+ * Creates a border color style object from a theme token.
5803
+ *
5804
+ * @param token - Theme color token
5805
+ * @returns CSSProperties with borderColor
5806
+ */
5807
+ function borderColorStyle(token) {
5808
+ return { borderColor: rgbColorValue(token) };
5809
+ }
5810
+ /**
5811
+ * Merges multiple CSSProperties objects into a single object.
5812
+ * Later styles override earlier ones. Undefined values are filtered out.
5813
+ * Returns undefined if the merged result is empty.
5814
+ *
5815
+ * @param styles - Variable number of CSSProperties objects (can be undefined)
5816
+ * @returns Merged CSSProperties object, or undefined if empty
5817
+ *
5818
+ * @example
5819
+ * mergeStyles(
5820
+ * backgroundColorStyle('surface'),
5821
+ * textColorStyle('text'),
5822
+ * borderColorStyle('border')
5823
+ * )
5824
+ * // => { backgroundColor: '...', color: '...', borderColor: '...' }
5825
+ */
5826
+ function mergeStyles(...styles) {
5827
+ const merged = {};
5828
+ for (const style of styles) {
5829
+ if (!style) continue;
5830
+ Object.assign(merged, style);
5831
+ }
5832
+ return Object.keys(merged).length ? merged : void 0;
5833
+ }
5834
+ //#endregion
5289
5835
  //#region ../theme-core/src/tokens/resolver.ts
5290
5836
  /**
5291
5837
  * Resolves theme tokens to CSS variables
@@ -5312,7 +5858,7 @@ var TokenResolver = class {
5312
5858
  */
5313
5859
  getColor(token) {
5314
5860
  if (!this.tokenExists(token)) console.warn(`[TokenResolver] Color token "${token}" not found in theme palette. Button may render incorrectly.`);
5315
- return `rgb(var(--tb-${token}))`;
5861
+ return rgbColorValue(token);
5316
5862
  }
5317
5863
  /**
5318
5864
  * Adjust a color token's shade by a given amount
@@ -5843,571 +6389,179 @@ function cardDecorationPseudoRules(containerSelectors, decorations, resolveColor
5843
6389
  */
5844
6390
  function boxlessOpenCardVariant(marking) {
5845
6391
  return {
5846
- id: "open",
5847
- name: "Open",
5848
- enabled: true,
5849
- priority: 3,
5850
- role: "open",
5851
- background: { type: "transparent" },
5852
- spacing: {
5853
- block: "comfortable",
5854
- inline: "none"
5855
- },
5856
- corners: "square",
5857
- shadow: {
5858
- elevation: "none",
5859
- softness: null,
5860
- position: "bottom"
5861
- },
5862
- decorations: [{
5863
- edge: "top",
5864
- colorToken: marking.ruleToken ?? "border",
5865
- width: "hairline",
5866
- length: "full",
5867
- ...marking.ruleAlpha === void 0 ? {} : { alpha: marking.ruleAlpha }
5868
- }, {
5869
- edge: "top",
5870
- colorToken: marking.accentToken,
5871
- width: marking.accentWidth,
5872
- length: "short",
5873
- align: "start"
5874
- }]
5875
- };
5876
- }
5877
- //#endregion
5878
- //#region ../theme-core/src/cards/generateDefaultCardSystem.ts
5879
- /**
5880
- * Generate a default card system from theme settings
5881
- *
5882
- * Creates the baseline card roles that blocks can request:
5883
- * - `default` for everyday surfaced cards
5884
- * - `alternative` for emphasised cards
5885
- * - `open` for boxless-but-marked cards
5886
- *
5887
- * This is the terminal arm of the role fallback chain, so every theme
5888
- * implements every surface role whether or not its site style defines cards.
5889
- *
5890
- * The surfaced variants explicitly set theme.shadow and theme.corners for
5891
- * runtime transform access, and both use theme.border when it has meaningful
5892
- * width.
5893
- *
5894
- * This ensures cards have sensible defaults even when theme.cards is undefined.
5895
- *
5896
- * Note: We explicitly set corners and shadow (rather than leaving undefined)
5897
- * so that runtime transforms can access them without needing the full theme config.
5898
- */
5899
- function generateDefaultCardSystem(theme) {
5900
- const defaultVariant = {
5901
- id: "default",
5902
- name: "Default",
5903
- enabled: true,
5904
- priority: 1,
5905
- role: "default",
5906
- background: {
5907
- type: "solid",
5908
- colorToken: "surface"
5909
- },
5910
- foregroundToken: "text",
5911
- spacing: "comfortable",
5912
- corners: theme.corners,
5913
- shadow: theme.shadow
5914
- };
5915
- const alternativeVariant = {
5916
- id: "alternative",
5917
- name: "Alternative",
5918
- enabled: true,
5919
- priority: 2,
5920
- role: "alternative",
5921
- background: {
5922
- type: "solid",
5923
- colorToken: "surfaceAlt"
5924
- },
5925
- foregroundToken: "text",
5926
- spacing: "comfortable",
5927
- corners: theme.corners,
5928
- shadow: {
5929
- ...theme.shadow,
5930
- elevation: theme.shadow.elevation === "none" ? "low" : theme.shadow.elevation
5931
- }
5932
- };
5933
- /** A site style that declares no `open` variant is marked in its primary. */
5934
- const openVariant = boxlessOpenCardVariant({
5935
- accentToken: "primary",
5936
- accentWidth: "thin",
5937
- ruleAlpha: .75
5938
- });
5939
- if (theme.border && theme.border.width !== "none") {
5940
- const border = {
5941
- widthClass: {
5942
- "hairline": "border",
5943
- "thin": "border",
5944
- "thick": "border-4"
5945
- }[theme.border.width] || "border",
5946
- colorToken: "border"
5947
- };
5948
- defaultVariant.border = border;
5949
- alternativeVariant.border = border;
5950
- }
5951
- return { variants: [
5952
- defaultVariant,
5953
- alternativeVariant,
5954
- openVariant
5955
- ] };
5956
- }
5957
- //#endregion
5958
- //#region ../theme-core/src/cards/roles.ts
5959
- function findVariantForRole(cardSystem, role) {
5960
- return cardSystem?.variants.find((variant) => cardVariantRole(variant) === role) ?? null;
5961
- }
5962
- function findEnabledVariantForRole(cardSystem, role) {
5963
- const variant = findVariantForRole(cardSystem, role);
5964
- return variant?.enabled ? variant : null;
5965
- }
5966
- function surface(requestedRole, resolvedRole, variant, source) {
5967
- return {
5968
- kind: "surface",
5969
- requestedRole,
5970
- resolvedRole,
5971
- variant,
5972
- source
5973
- };
5974
- }
5975
- function baselineSurface(requestedRole, resolvedRole, theme) {
5976
- const variant = findEnabledVariantForRole(generateDefaultCardSystem(theme), resolvedRole);
5977
- return variant ? surface(requestedRole, resolvedRole, variant, "generated-baseline") : {
5978
- kind: "none",
5979
- requestedRole
5980
- };
5981
- }
5982
- /**
5983
- * Resolve a card role against a site style's card system.
5984
- *
5985
- * - `none` — terminal, no surface.
5986
- * - `open` — site style's `open` variant → generated baseline `open`.
5987
- * - `default` — site style's `default` → generated baseline `default`.
5988
- * - `alternative` — site style's `alternative` → site style's `default` →
5989
- * generated baseline `default`.
5990
- *
5991
- * The `theme` argument exists solely so the chain can reach the generated
5992
- * baseline without the caller synthesizing one. Pass `null` for `cardSystem`
5993
- * when the site style declares none — resolving against a baseline the caller
5994
- * synthesized would report `source: 'site-style'` for a surface no site style
5995
- * chose.
5996
- */
5997
- function resolveCardRole(theme, cardSystem, role) {
5998
- switch (role) {
5999
- case "none": return {
6000
- kind: "none",
6001
- requestedRole: role
6002
- };
6003
- case "open": {
6004
- const declared = findEnabledVariantForRole(cardSystem, "open");
6005
- return declared ? surface(role, "open", declared, "site-style") : baselineSurface(role, "open", theme);
6006
- }
6007
- case "default": {
6008
- const declared = findEnabledVariantForRole(cardSystem, "default");
6009
- return declared ? surface(role, "default", declared, "site-style") : baselineSurface(role, "default", theme);
6010
- }
6011
- case "alternative": {
6012
- const declared = findEnabledVariantForRole(cardSystem, "alternative");
6013
- if (declared) return surface(role, "alternative", declared, "site-style");
6014
- const fallback = findEnabledVariantForRole(cardSystem, "default");
6015
- if (fallback) return surface(role, "default", fallback, "site-style");
6016
- return baselineSurface(role, "default", theme);
6017
- }
6018
- }
6019
- }
6020
- //#endregion
6021
- //#region ../theme-core/src/surfaces/foregroundRoles.ts
6022
- const SURFACE_FOREGROUND_ROLES = [
6023
- "text",
6024
- "heading",
6025
- "link",
6026
- "supporting"
6027
- ];
6028
- //#endregion
6029
- //#region ../theme-core/src/surfaces/foregroundContract.ts
6030
- const SURFACE_FOREGROUND_CSS_VARS = {
6031
- text: "--rb-surface-text-color",
6032
- heading: "--rb-surface-heading-color",
6033
- link: "--rb-surface-link-color",
6034
- supporting: "--rb-surface-supporting-color"
6035
- };
6036
- const DEFAULT_SURFACE_TEXT_COLOR = "rgb(var(--tb-text, 17 24 39))";
6037
- const DEFAULT_ROLE_FALLBACKS = {
6038
- text: DEFAULT_SURFACE_TEXT_COLOR,
6039
- heading: DEFAULT_SURFACE_TEXT_COLOR,
6040
- link: "rgb(var(--tb-primary, var(--tb-text, 17 24 39)))",
6041
- supporting: "rgb(var(--tb-mutedText, 100 116 139))"
6042
- };
6043
- function requireSurfaceColorValue(role, value) {
6044
- const normalized = value.trim();
6045
- if (normalized.length === 0) throw new RangeError(`Surface foreground ${role} must be a non-empty CSS color.`);
6046
- return normalized;
6047
- }
6048
- function completeSurfaceForegrounds(input) {
6049
- const text = requireSurfaceColorValue("text", input.text);
6050
- return {
6051
- text,
6052
- heading: input.heading === void 0 ? text : requireSurfaceColorValue("heading", input.heading),
6053
- link: input.link === void 0 ? text : requireSurfaceColorValue("link", input.link),
6054
- supporting: input.supporting === void 0 ? text : requireSurfaceColorValue("supporting", input.supporting)
6055
- };
6056
- }
6057
- function surfaceForegroundValue(role, outsideProviderFallback = DEFAULT_ROLE_FALLBACKS[role]) {
6058
- const roleVariable = SURFACE_FOREGROUND_CSS_VARS[role];
6059
- const fallback = requireSurfaceColorValue("fallback", outsideProviderFallback);
6060
- if (role === "text") return `var(${roleVariable}, ${fallback})`;
6061
- return `var(${roleVariable}, var(${SURFACE_FOREGROUND_CSS_VARS.text}, ${fallback}))`;
6062
- }
6063
- function surfaceForegroundValueWithOpacity(role, opacityPercent) {
6064
- if (!Number.isFinite(opacityPercent) || opacityPercent < 0 || opacityPercent > 100) throw new RangeError("Surface foreground opacity must be between 0 and 100.");
6065
- return `color-mix(in srgb, ${surfaceForegroundValue(role)} ${opacityPercent}%, transparent)`;
6066
- }
6067
- function surfaceForegroundStyle(input) {
6068
- const foregrounds = completeSurfaceForegrounds(input);
6069
- return {
6070
- color: foregrounds.text,
6071
- [SURFACE_FOREGROUND_CSS_VARS.text]: foregrounds.text,
6072
- [SURFACE_FOREGROUND_CSS_VARS.heading]: foregrounds.heading,
6073
- [SURFACE_FOREGROUND_CSS_VARS.link]: foregrounds.link,
6074
- [SURFACE_FOREGROUND_CSS_VARS.supporting]: foregrounds.supporting
6075
- };
6076
- }
6077
- function surfaceForegroundDeclarations(input) {
6078
- const foregrounds = completeSurfaceForegrounds(input);
6079
- return [`color: ${foregrounds.text}`, ...SURFACE_FOREGROUND_ROLES.map((role) => `${SURFACE_FOREGROUND_CSS_VARS[role]}: ${foregrounds[role]}`)];
6080
- }
6081
- //#endregion
6082
- //#region ../theme-core/src/palette/colors.ts
6083
- const HEX_COLOR_REGEX = /^#[0-9a-f]{6}$/;
6084
- const NORMALIZABLE_HEX_REGEX = /^#(?:[0-9a-f]{3}|[0-9a-f]{6})$/i;
6085
- const THEME_PALETTE_COLOR_ORDER = [
6086
- "primary",
6087
- "secondary",
6088
- "accent",
6089
- "success",
6090
- "warning",
6091
- "destructive",
6092
- "background",
6093
- "surface",
6094
- "surfaceAlt",
6095
- "muted",
6096
- "text",
6097
- "primaryForeground",
6098
- "border"
6099
- ];
6100
- const hexColorSchema = z.string().regex(HEX_COLOR_REGEX, "Hex must be #RRGGBB (lowercase)").transform((value) => value);
6101
- const paletteModeSchema = z.enum(["light", "dark"]);
6102
- const PALETTE_VALUE_KEY_PREFIX = "palette-value:v1|";
6103
- z.string().regex(/^[0-9a-f]{64}$/, "Palette hash must be a lowercase SHA-256 value").transform((value) => value);
6104
- const paletteColorsSchema = z.object({
6105
- primary: hexColorSchema,
6106
- primaryForeground: hexColorSchema,
6107
- secondary: hexColorSchema,
6108
- accent: hexColorSchema,
6109
- success: hexColorSchema,
6110
- warning: hexColorSchema,
6111
- destructive: hexColorSchema,
6112
- background: hexColorSchema,
6113
- surface: hexColorSchema,
6114
- surfaceAlt: hexColorSchema,
6115
- muted: hexColorSchema,
6116
- text: hexColorSchema,
6117
- border: hexColorSchema
6118
- }).strict().transform((value) => value);
6119
- function normalizePaletteHex(value) {
6120
- if (!NORMALIZABLE_HEX_REGEX.test(value)) return null;
6121
- const normalized = value.toLowerCase();
6122
- if (normalized.length === 7) return normalized;
6123
- const triplet = normalized.slice(1);
6124
- const red = triplet.charAt(0);
6125
- const green = triplet.charAt(1);
6126
- const blue = triplet.charAt(2);
6127
- return `#${red}${red}${green}${green}${blue}${blue}`;
6128
- }
6129
- function paletteColorsFromEntries(entries) {
6130
- const values = {};
6131
- for (const entry of entries) {
6132
- const parsedRole = paletteTokenNameSchema.safeParse(entry.name);
6133
- if (!parsedRole.success) return {
6134
- ok: false,
6135
- error: {
6136
- kind: "unknown-role",
6137
- role: entry.name
6138
- }
6139
- };
6140
- const role = parsedRole.data;
6141
- if (values[role] !== void 0) return {
6142
- ok: false,
6143
- error: {
6144
- kind: "duplicate-role",
6145
- role
6146
- }
6147
- };
6148
- const hex = normalizePaletteHex(entry.hex);
6149
- if (!hex) return {
6150
- ok: false,
6151
- error: {
6152
- kind: "invalid-color",
6153
- role,
6154
- value: entry.hex
6155
- }
6156
- };
6157
- values[role] = hex;
6158
- }
6159
- const missing = PALETTE_TOKEN_NAMES.filter((role) => values[role] === void 0);
6160
- if (missing.length > 0) return {
6161
- ok: false,
6162
- error: {
6163
- kind: "missing-roles",
6164
- roles: missing
6165
- }
6166
- };
6167
- return {
6168
- ok: true,
6169
- colors: paletteColorsSchema.parse(values)
6170
- };
6171
- }
6172
- function requirePaletteColorsFromEntries(entries) {
6173
- const result = paletteColorsFromEntries(entries);
6174
- if (result.ok) return result.colors;
6175
- throw new Error(`Invalid complete palette: ${result.error.kind}`);
6176
- }
6177
- function paletteColorEntries(colors) {
6178
- return THEME_PALETTE_COLOR_ORDER.map((name) => ({
6179
- name,
6180
- hex: colors[name]
6181
- }));
6182
- }
6183
- function paletteColorFingerprint(colors) {
6184
- return PALETTE_TOKEN_NAMES.map((name) => `${name}:${colors[name]}`).join("|");
6185
- }
6186
- function canonicalPaletteHashInput(colors, mode) {
6187
- return `${mode}|${paletteColorFingerprint(colors)}`;
6188
- }
6189
- /**
6190
- * Stable curated-catalogue identity. Do not reorder roles: the order comes
6191
- * from PALETTE_TOKEN_NAMES through canonicalPaletteHashInput.
6192
- */
6193
- function paletteValueKey(colors, mode) {
6194
- return `${PALETTE_VALUE_KEY_PREFIX}${canonicalPaletteHashInput(colors, mode)}`;
6195
- }
6196
- /** Parses only the exact v1 canonical form emitted by paletteValueKey. */
6197
- function parsePaletteValueKey(value) {
6198
- if (typeof value !== "string" || !value.startsWith(PALETTE_VALUE_KEY_PREFIX)) return null;
6199
- const [rawMode, ...rawRoles] = value.slice(17).split("|");
6200
- const mode = paletteModeSchema.safeParse(rawMode);
6201
- if (!mode.success || rawRoles.length !== PALETTE_TOKEN_NAMES.length) return null;
6202
- const colors = paletteColorsFromEntries(rawRoles.map((roleValue) => {
6203
- const separator = roleValue.indexOf(":");
6204
- return separator === -1 ? {
6205
- name: "",
6206
- hex: ""
6207
- } : {
6208
- name: roleValue.slice(0, separator),
6209
- hex: roleValue.slice(separator + 1)
6210
- };
6211
- }));
6212
- if (!colors.ok || paletteValueKey(colors.colors, mode.data) !== value) return null;
6213
- return value;
6214
- }
6215
- const paletteValueKeySchema = z.string().transform((value, ctx) => {
6216
- const parsed = parsePaletteValueKey(value);
6217
- if (parsed) return parsed;
6218
- ctx.addIssue({
6219
- code: "custom",
6220
- message: "Invalid canonical palette value key"
6221
- });
6222
- return z.NEVER;
6223
- });
6224
- //#endregion
6225
- //#region ../theme-core/src/palette/utils/opaqueSurfaceColor.ts
6226
- /** Resolve an opaque colour, compositing alpha against an explicit underlay. */
6227
- function resolveOpaqueSurfaceHex(reference, palette, underlayReference) {
6228
- const opaque = resolveConcreteColorHex(reference, palette);
6229
- if (opaque) return opaque;
6230
- if (!underlayReference) return null;
6231
- const underlayHex = resolveConcreteColorHex(underlayReference, palette);
6232
- if (!underlayHex) return null;
6233
- const parts = parseColorTokenParts(reference);
6234
- if (parts.kind === "token" && parts.opacityPercent !== null) {
6235
- const foregroundHex = normalizePaletteHex(palette[parts.token] ?? "");
6236
- return foregroundHex ? compositeHex(foregroundHex, underlayHex, parts.opacityPercent / 100) : null;
6237
- }
6238
- const rgba = parseRgba(parts.kind === "raw" ? parts.value : reference);
6239
- return rgba ? compositeHex(rgbToHex(rgba.r, rgba.g, rgba.b), underlayHex, rgba.alpha) : null;
6240
- }
6241
- /** Resolve a colour reference only when it is already fully opaque. */
6242
- function resolveConcreteColorHex(reference, palette) {
6243
- const literalHex = normalizePaletteHex(reference);
6244
- if (literalHex) return literalHex;
6245
- const parts = parseColorTokenParts(reference);
6246
- if (parts.kind === "token") {
6247
- if (parts.opacityPercent !== null) return null;
6248
- return normalizePaletteHex(palette[parts.token] ?? "");
6249
- }
6250
- const literal = parts.kind === "raw" ? parts.value : reference;
6251
- if (literal.toLowerCase() === "black") return "#000000";
6252
- if (literal.toLowerCase() === "white") return "#ffffff";
6253
- return normalizePaletteHex(literal);
6254
- }
6255
- function compositeHex(foregroundHex, underlayHex, alpha) {
6256
- const foreground = hexToRgb(foregroundHex);
6257
- const underlay = hexToRgb(underlayHex);
6258
- const channel = (foregroundValue, underlayValue) => Math.round(foregroundValue * alpha + underlayValue * (1 - alpha));
6259
- return rgbToHex(channel(foreground.r, underlay.r), channel(foreground.g, underlay.g), channel(foreground.b, underlay.b));
6260
- }
6261
- function parseRgba(value) {
6262
- const match = value.trim().match(/^rgba?\(\s*([\d.]+)(?:\s*,\s*|\s+)([\d.]+)(?:\s*,\s*|\s+)([\d.]+)(?:\s*(?:,|\/)\s*([\d.]+%?))?\s*\)$/i);
6263
- if (!match) return null;
6264
- const [, rSource, gSource, bSource] = match;
6265
- if (!rSource || !gSource || !bSource) return null;
6266
- const r = Number(rSource);
6267
- const g = Number(gSource);
6268
- const b = Number(bSource);
6269
- const alpha = parseAlpha(match[4]);
6270
- if (alpha === null || !isRgbChannel(r) || !isRgbChannel(g) || !isRgbChannel(b)) return null;
6271
- return {
6272
- r,
6273
- g,
6274
- b,
6275
- alpha
6392
+ id: "open",
6393
+ name: "Open",
6394
+ enabled: true,
6395
+ priority: 3,
6396
+ role: "open",
6397
+ background: { type: "transparent" },
6398
+ spacing: {
6399
+ block: "comfortable",
6400
+ inline: "none"
6401
+ },
6402
+ corners: "square",
6403
+ shadow: {
6404
+ elevation: "none",
6405
+ softness: null,
6406
+ position: "bottom"
6407
+ },
6408
+ decorations: [{
6409
+ edge: "top",
6410
+ colorToken: marking.ruleToken ?? "border",
6411
+ width: "hairline",
6412
+ length: "full",
6413
+ ...marking.ruleAlpha === void 0 ? {} : { alpha: marking.ruleAlpha }
6414
+ }, {
6415
+ edge: "top",
6416
+ colorToken: marking.accentToken,
6417
+ width: marking.accentWidth,
6418
+ length: "short",
6419
+ align: "start"
6420
+ }]
6276
6421
  };
6277
6422
  }
6278
- function parseAlpha(source) {
6279
- if (!source) return 1;
6280
- const value = source.endsWith("%") ? Number(source.slice(0, -1)) / 100 : Number(source);
6281
- return Number.isFinite(value) && value >= 0 && value <= 1 ? value : null;
6282
- }
6283
- function isRgbChannel(value) {
6284
- return Number.isFinite(value) && value >= 0 && value <= 255;
6285
- }
6286
6423
  //#endregion
6287
- //#region ../theme-core/src/surfaces/resolveSurfaceForeground.ts
6288
- const FALLBACK_TEXT_TOKENS = [
6289
- "text",
6290
- "primaryForeground",
6291
- "secondaryForeground",
6292
- "accentForeground",
6293
- "neutral-950",
6294
- "neutral-50"
6295
- ];
6296
- const CANONICAL_EQUIVALENT_TOKEN_ORDER = [
6297
- "text",
6298
- "primaryForeground",
6299
- "secondaryForeground",
6300
- "accentForeground",
6301
- "onPrimary",
6302
- "onSecondary",
6303
- "onAccent",
6304
- "onSurface",
6305
- "neutral-950",
6306
- "neutral-50"
6307
- ];
6424
+ //#region ../theme-core/src/cards/generateDefaultCardSystem.ts
6308
6425
  /**
6309
- * Resolve the complete foreground contract for an effective page/section or
6310
- * site-chrome background.
6426
+ * Generate a default card system from theme settings
6311
6427
  *
6312
- * Deterministic colour backgrounds are validated at ordinary-text WCAG AA.
6313
- * Existing image/video/gradient treatments are trusted only when they already
6314
- * carry a usable foreground token; this function deliberately does not claim
6315
- * pixel-level contrast proof for media.
6428
+ * Creates the baseline card roles that blocks can request:
6429
+ * - `default` for everyday surfaced cards
6430
+ * - `alternative` for emphasised cards
6431
+ * - `open` for boxless-but-marked cards
6432
+ *
6433
+ * This is the terminal arm of the role fallback chain, so every theme
6434
+ * implements every surface role whether or not its site style defines cards.
6435
+ *
6436
+ * The surfaced variants explicitly set theme.shadow and theme.corners for
6437
+ * runtime transform access, and both use theme.border when it has meaningful
6438
+ * width.
6439
+ *
6440
+ * This ensures cards have sensible defaults even when theme.cards is undefined.
6441
+ *
6442
+ * Note: We explicitly set corners and shadow (rather than leaving undefined)
6443
+ * so that runtime transforms can access them without needing the full theme config.
6316
6444
  */
6317
- function resolveSurfaceForeground(background, palette, candidates = {}, options = {}) {
6318
- const authored = foregroundCandidates(background, candidates);
6319
- if (background === null) return resolveDeterministicForeground("background", {
6320
- ...authored,
6321
- text: authored.text ?? "text"
6322
- }, palette);
6323
- if (background.type === "color") {
6324
- const backgroundReference = normalizedReference(background.color);
6325
- if (!backgroundReference || backgroundReference === "transparent") return { kind: "unknown" };
6326
- return resolveDeterministicForeground(backgroundReference, authored, palette, options.compositeBase);
6327
- }
6328
- return resolveTrustedTreatmentForeground(authored, palette);
6329
- }
6330
- function foregroundCandidates(background, overrides) {
6331
- return {
6332
- text: overrides.text ?? background?.textColor ?? null,
6333
- heading: overrides.heading ?? background?.headingColor ?? null,
6334
- link: overrides.link ?? background?.linkColor ?? null,
6335
- supporting: overrides.supporting ?? background?.supportingColor ?? null
6445
+ function generateDefaultCardSystem(theme) {
6446
+ const defaultVariant = {
6447
+ id: "default",
6448
+ name: "Default",
6449
+ enabled: true,
6450
+ priority: 1,
6451
+ role: "default",
6452
+ background: {
6453
+ type: "solid",
6454
+ colorToken: "surface"
6455
+ },
6456
+ foregroundToken: "text",
6457
+ spacing: "comfortable",
6458
+ corners: theme.corners,
6459
+ shadow: theme.shadow
6336
6460
  };
6337
- }
6338
- function resolveDeterministicForeground(backgroundReference, candidates, palette, compositeBase) {
6339
- const backgroundHex = resolveOpaqueSurfaceHex(backgroundReference, palette, compositeBase);
6340
- if (!backgroundHex) return resolveTrustedTreatmentForeground(candidates, palette);
6341
- const backgroundToken = paletteToken(backgroundReference);
6342
- const derivedOnToken = backgroundToken ? onColorTokenName(backgroundToken) : null;
6343
- const text = firstSafeToken([
6344
- candidates.text,
6345
- derivedOnToken,
6346
- ...FALLBACK_TEXT_TOKENS
6347
- ], backgroundHex, palette, derivedOnToken ? [derivedOnToken] : []);
6348
- if (!text) return { kind: "unknown" };
6349
- return {
6350
- kind: "known",
6351
- roles: {
6352
- text,
6353
- heading: safeTokenOr(candidates.heading, text, backgroundHex, palette),
6354
- link: safeTokenOr(candidates.link, text, backgroundHex, palette),
6355
- supporting: safeTokenOr(candidates.supporting, text, backgroundHex, palette)
6461
+ const alternativeVariant = {
6462
+ id: "alternative",
6463
+ name: "Alternative",
6464
+ enabled: true,
6465
+ priority: 2,
6466
+ role: "alternative",
6467
+ background: {
6468
+ type: "solid",
6469
+ colorToken: "surfaceAlt"
6470
+ },
6471
+ foregroundToken: "text",
6472
+ spacing: "comfortable",
6473
+ corners: theme.corners,
6474
+ shadow: {
6475
+ ...theme.shadow,
6476
+ elevation: theme.shadow.elevation === "none" ? "low" : theme.shadow.elevation
6356
6477
  }
6357
6478
  };
6479
+ /** A site style that declares no `open` variant is marked in its primary. */
6480
+ const openVariant = boxlessOpenCardVariant({
6481
+ accentToken: "primary",
6482
+ accentWidth: "thin",
6483
+ ruleAlpha: .75
6484
+ });
6485
+ if (theme.border && theme.border.width !== "none") {
6486
+ const border = {
6487
+ widthClass: {
6488
+ "hairline": "border",
6489
+ "thin": "border",
6490
+ "thick": "border-4"
6491
+ }[theme.border.width] || "border",
6492
+ colorToken: "border"
6493
+ };
6494
+ defaultVariant.border = border;
6495
+ alternativeVariant.border = border;
6496
+ }
6497
+ return { variants: [
6498
+ defaultVariant,
6499
+ alternativeVariant,
6500
+ openVariant
6501
+ ] };
6358
6502
  }
6359
- function resolveTrustedTreatmentForeground(candidates, palette) {
6360
- const text = canonicalToken(candidates.text, palette);
6361
- if (!text) return { kind: "unknown" };
6503
+ //#endregion
6504
+ //#region ../theme-core/src/cards/roles.ts
6505
+ function findVariantForRole(cardSystem, role) {
6506
+ return cardSystem?.variants.find((variant) => cardVariantRole(variant) === role) ?? null;
6507
+ }
6508
+ function findEnabledVariantForRole(cardSystem, role) {
6509
+ const variant = findVariantForRole(cardSystem, role);
6510
+ return variant?.enabled ? variant : null;
6511
+ }
6512
+ function surface(requestedRole, resolvedRole, variant, source) {
6362
6513
  return {
6363
- kind: "known",
6364
- roles: {
6365
- text,
6366
- heading: canonicalToken(candidates.heading, palette) ?? text,
6367
- link: canonicalToken(candidates.link, palette) ?? text,
6368
- supporting: canonicalToken(candidates.supporting, palette) ?? text
6369
- }
6514
+ kind: "surface",
6515
+ requestedRole,
6516
+ resolvedRole,
6517
+ variant,
6518
+ source
6370
6519
  };
6371
6520
  }
6372
- function safeTokenOr(candidate, fallback, backgroundHex, palette) {
6373
- return firstSafeToken([candidate], backgroundHex, palette) ?? fallback;
6521
+ function baselineSurface(requestedRole, resolvedRole, theme) {
6522
+ const variant = findEnabledVariantForRole(generateDefaultCardSystem(theme), resolvedRole);
6523
+ return variant ? surface(requestedRole, resolvedRole, variant, "generated-baseline") : {
6524
+ kind: "none",
6525
+ requestedRole
6526
+ };
6374
6527
  }
6375
- function firstSafeToken(candidates, backgroundHex, palette, preferredEquivalentTokens = []) {
6376
- const seen = /* @__PURE__ */ new Set();
6377
- for (const candidate of candidates) {
6378
- const token = canonicalToken(candidate, palette, preferredEquivalentTokens);
6379
- if (!token || seen.has(token)) continue;
6380
- seen.add(token);
6381
- const foregroundHex = resolveConcreteColorHex(token, palette);
6382
- if (foregroundHex && contrastRatio(backgroundHex, foregroundHex) >= 4.5) return token;
6528
+ /**
6529
+ * Resolve a card role against a site style's card system.
6530
+ *
6531
+ * - `none` — terminal, no surface.
6532
+ * - `open` — site style's `open` variant → generated baseline `open`.
6533
+ * - `default` — site style's `default` → generated baseline `default`.
6534
+ * - `alternative` — site style's `alternative` → site style's `default` →
6535
+ * generated baseline `default`.
6536
+ *
6537
+ * The `theme` argument exists solely so the chain can reach the generated
6538
+ * baseline without the caller synthesizing one. Pass `null` for `cardSystem`
6539
+ * when the site style declares none — resolving against a baseline the caller
6540
+ * synthesized would report `source: 'site-style'` for a surface no site style
6541
+ * chose.
6542
+ */
6543
+ function resolveCardRole(theme, cardSystem, role) {
6544
+ switch (role) {
6545
+ case "none": return {
6546
+ kind: "none",
6547
+ requestedRole: role
6548
+ };
6549
+ case "open": {
6550
+ const declared = findEnabledVariantForRole(cardSystem, "open");
6551
+ return declared ? surface(role, "open", declared, "site-style") : baselineSurface(role, "open", theme);
6552
+ }
6553
+ case "default": {
6554
+ const declared = findEnabledVariantForRole(cardSystem, "default");
6555
+ return declared ? surface(role, "default", declared, "site-style") : baselineSurface(role, "default", theme);
6556
+ }
6557
+ case "alternative": {
6558
+ const declared = findEnabledVariantForRole(cardSystem, "alternative");
6559
+ if (declared) return surface(role, "alternative", declared, "site-style");
6560
+ const fallback = findEnabledVariantForRole(cardSystem, "default");
6561
+ if (fallback) return surface(role, "default", fallback, "site-style");
6562
+ return baselineSurface(role, "default", theme);
6563
+ }
6383
6564
  }
6384
- return null;
6385
- }
6386
- function canonicalToken(reference, palette, preferredEquivalentTokens = []) {
6387
- const normalized = normalizedReference(reference);
6388
- if (!normalized || normalized === "transparent") return null;
6389
- const direct = parseThemeColorToken(normalized);
6390
- if (direct && resolveConcreteColorHex(direct, palette)) return direct;
6391
- const referenceHex = resolveConcreteColorHex(normalized, palette);
6392
- if (!referenceHex) return null;
6393
- const equivalent = [
6394
- ...preferredEquivalentTokens,
6395
- ...CANONICAL_EQUIVALENT_TOKEN_ORDER,
6396
- ...Object.keys(palette).sort()
6397
- ].find((token) => {
6398
- const parsed = parseThemeColorToken(token);
6399
- return parsed !== null && resolveConcreteColorHex(parsed, palette)?.toLowerCase() === referenceHex.toLowerCase();
6400
- });
6401
- return equivalent ? parseThemeColorToken(equivalent) : null;
6402
- }
6403
- function paletteToken(reference) {
6404
- const parts = parseColorTokenParts(reference);
6405
- return parts.kind === "token" && parts.opacityPercent === null ? parts.token : null;
6406
- }
6407
- function normalizedReference(value) {
6408
- if (typeof value !== "string") return null;
6409
- const normalized = value.trim();
6410
- return normalized.length > 0 ? normalized : null;
6411
6565
  }
6412
6566
  //#endregion
6413
6567
  //#region ../theme-core/src/cards/generateCardCss.ts
@@ -6534,14 +6688,12 @@ function generateVariantCSS(variant, themeId, cardClasses, tokens, theme) {
6534
6688
  const shadowValue = generateShadowValue$1(shadow);
6535
6689
  rules.push(`box-shadow: ${shadowValue}`);
6536
6690
  }
6537
- rules.push(`display: flex`);
6538
- rules.push(`flex-direction: column`);
6539
- rules.push(`position: relative`);
6540
- rules.push(`overflow: visible`);
6691
+ const structureSelector = cardClasses.map((cardClass) => `:where([data-theme-scope="${themeId}"]) :where(.${cardClass})`).join(",\n");
6541
6692
  const mediaRadius = MEDIA_CORNER_MAP[corners];
6542
6693
  const mediaRules = [`border-top-left-radius: ${mediaRadius}`, `border-top-right-radius: ${mediaRadius}`];
6543
6694
  const contentRules = [`padding: ${resolveContentPadding(variant)}`];
6544
6695
  return [
6696
+ `${structureSelector} {\n display: flex;\n flex-direction: column;\n position: relative;\n overflow: visible;\n}`,
6545
6697
  `${containerSelector} {\n ${rules.join(";\n ")};\n}`,
6546
6698
  ...cardDecorationPseudoRules(containerSelectors, variant.decorations, resolveColor),
6547
6699
  `${fallbackBackgroundSelector} {\n background: transparent;\n}`,
@@ -11378,8 +11530,14 @@ const headerInteractionPillPaletteValues = [
11378
11530
  "accent"
11379
11531
  ];
11380
11532
  /**
11381
- * "No pill": the nav link keeps whatever hover treatment its recipe compiled,
11382
- * and the palette step writes nothing at all (#1318 Phase 4c decision 2).
11533
+ * "No pill": a colour change on hover rather than a filled background.
11534
+ *
11535
+ * The palette step writes nothing (#1318 Phase 4c decision 2), but on a
11536
+ * foreground-adaptive style that is not the end of the story: the hover colour
11537
+ * is derived from the resolved opening foreground at render time, paired with
11538
+ * the resting colour, so `quiet` resolves to a definite colour rather than to
11539
+ * whatever brand token the recipe happened to name. See
11540
+ * `applyOpeningForeground`.
11383
11541
  *
11384
11542
  * It exists because "a colour change on hover, no filled background" was not
11385
11543
  * expressible in the vocabulary, and it is what
@@ -12541,7 +12699,7 @@ const BUTTON_CONTRAST_POLICY = {
12541
12699
  nonTextMinimumRatio: 3,
12542
12700
  gradientSamplesPerSegment: 20,
12543
12701
  alphaBackgrounds: "reject-without-known-surface",
12544
- disabled: "retain-full-colour-contract"
12702
+ disabled: "validated-colour-pair-with-muted-control-opacity"
12545
12703
  };
12546
12704
  function formatButtonColourContractError(error) {
12547
12705
  switch (error.tag) {
@@ -13129,6 +13287,25 @@ function parseThemeForPersistence(value) {
13129
13287
  };
13130
13288
  }
13131
13289
  //#endregion
13290
+ //#region ../theme-core/src/buttons/affordanceSuppression.ts
13291
+ /**
13292
+ * Internal: the opt-out the generated affordance rule is written against.
13293
+ *
13294
+ * A button style may declare a trailing `affordance`, which the theme renders as
13295
+ * a CSS `::after` on every button of that variant. An authored button that
13296
+ * renders its own trailing icon must not also receive the theme's, or it shows
13297
+ * two.
13298
+ *
13299
+ * Deliberately not exported from `./index`. This used to be public, and two
13300
+ * block components reached past the theme to draw arrows of their own — one of
13301
+ * them doubling up on the styles that declare an affordance, both of them
13302
+ * overriding the twelve styles that deliberately declare none. Whether a button
13303
+ * carries a trailing affordance is the style's decision; the only caller that
13304
+ * legitimately opts out is the authored-button renderer, which reaches it
13305
+ * through `themeButtonClassNameWithTrailingIcon`.
13306
+ */
13307
+ const AFFORDANCE_SUPPRESS_CLASS = "rb-affordance-off";
13308
+ //#endregion
13132
13309
  //#region ../theme-core/src/buttons/classNames.ts
13133
13310
  /**
13134
13311
  * Parse content/runtime variant identifiers into the closed theme-button class
@@ -13161,6 +13338,27 @@ function themeButtonClassName(spec) {
13161
13338
  spec.extraClassName
13162
13339
  ].filter(Boolean).join(" ");
13163
13340
  }
13341
+ /**
13342
+ * Button classes for an authored button that renders its own trailing icon.
13343
+ *
13344
+ * A separate function rather than a flag on `themeButtonClassName`, because
13345
+ * there is exactly one caller and it should stay visible in a diff. The name
13346
+ * states what the caller knows to be true of its own markup — that it renders a
13347
+ * trailing icon — rather than what the theme does about it. The consequence is
13348
+ * the theme's to decide and to change; a caller naming the consequence would be
13349
+ * asserting a policy it does not own, and would quietly become a lie the moment
13350
+ * that policy moved.
13351
+ *
13352
+ * Do not reach for this to remove an arrow you simply do not want. A trailing
13353
+ * affordance is declared by the button style, and a block overriding that is the
13354
+ * defect this replaced.
13355
+ */
13356
+ function themeButtonClassNameWithTrailingIcon(spec) {
13357
+ return themeButtonClassName({
13358
+ ...spec,
13359
+ extraClassName: [spec.extraClassName, AFFORDANCE_SUPPRESS_CLASS].filter(Boolean).join(" ")
13360
+ });
13361
+ }
13164
13362
  //#endregion
13165
13363
  //#region ../theme-core/src/interactive/generateBaseCSS.ts
13166
13364
  /**
@@ -14588,117 +14786,6 @@ function affordanceIconMaskUrl(iconId) {
14588
14786
  return `data:image/svg+xml,${`<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'>${paths.map((d) => `<path d='${d}'/>`).join("")}</svg>`.replace(/"/g, "'").replace(/#/g, "%23").replace(/</g, "%3C").replace(/>/g, "%3E").replace(/\s+/g, " ")}`;
14589
14787
  }
14590
14788
  //#endregion
14591
- //#region ../theme-core/src/utils/colorStyles.ts
14592
- const COLOR_VAR_PREFIX = "--tb-";
14593
- function parseToken(source) {
14594
- const parts = parseColorTokenParts(source);
14595
- if (parts.kind === "raw") return {
14596
- token: source,
14597
- raw: parts.value
14598
- };
14599
- if (parts.kind === "invalid") return { token: source };
14600
- return {
14601
- token: parts.token,
14602
- opacityPercent: parts.opacityPercent === null ? void 0 : parts.opacityPercent
14603
- };
14604
- }
14605
- const SURFACE_TEXT_ROLE_BY_TOKEN = {
14606
- text: "text",
14607
- heading: "heading",
14608
- mutedText: "supporting"
14609
- };
14610
- function surfaceRoleForTextToken(token) {
14611
- return Object.prototype.hasOwnProperty.call(SURFACE_TEXT_ROLE_BY_TOKEN, token) ? SURFACE_TEXT_ROLE_BY_TOKEN[token] : null;
14612
- }
14613
- /**
14614
- * Converts a theme color token to a CSS rgb value.
14615
- * This is the primary function for applying theme colors to CSS properties.
14616
- *
14617
- * @param token - Theme color token (semantic, with opacity, or raw)
14618
- * @returns CSS color value (rgb with optional alpha, or raw CSS value)
14619
- *
14620
- * @example
14621
- * rgbColorValue('primary') // => 'rgb(var(--tb-primary))'
14622
- * rgbColorValue('surface/95') // => 'rgb(var(--tb-surface) / 0.95)'
14623
- * rgbColorValue('raw:transparent') // => 'transparent'
14624
- */
14625
- function rgbColorValue(token) {
14626
- const { token: baseToken, opacityPercent, raw } = parseToken(token);
14627
- if (raw) return raw;
14628
- const cssVar = `${COLOR_VAR_PREFIX}${baseToken}`;
14629
- if (opacityPercent === void 0) return `rgb(var(${cssVar}))`;
14630
- return `rgb(var(${cssVar}) / ${opacityPercent / 100})`;
14631
- }
14632
- /**
14633
- * Converts a theme color token to a CSS variable reference.
14634
- * Note: This returns the base variable without rgb() wrapper, ignoring opacity.
14635
- *
14636
- * @param token - Theme color token
14637
- * @returns CSS variable reference
14638
- *
14639
- * @example
14640
- * cssVarValue('primary') // => 'var(--tb-primary)'
14641
- * cssVarValue('surface/95') // => 'var(--tb-surface)' (opacity ignored)
14642
- */
14643
- function cssVarValue(token) {
14644
- const { token: baseToken } = parseToken(token);
14645
- return `var(${COLOR_VAR_PREFIX}${baseToken})`;
14646
- }
14647
- /**
14648
- * Creates a backgroundColor style object from a theme token.
14649
- *
14650
- * @param token - Theme color token
14651
- * @returns CSSProperties with backgroundColor
14652
- */
14653
- function backgroundColorStyle(token) {
14654
- return { backgroundColor: rgbColorValue(token) };
14655
- }
14656
- /**
14657
- * Creates a text color style object from a theme token.
14658
- *
14659
- * @param token - Theme color token
14660
- * @returns CSSProperties with color
14661
- */
14662
- function textColorStyle(token) {
14663
- const parsed = parseToken(token);
14664
- const surfaceRole = parsed.raw ? null : surfaceRoleForTextToken(parsed.token);
14665
- if (surfaceRole) return { color: parsed.opacityPercent === void 0 ? surfaceForegroundValue(surfaceRole) : surfaceForegroundValueWithOpacity(surfaceRole, parsed.opacityPercent) };
14666
- return { color: rgbColorValue(token) };
14667
- }
14668
- /**
14669
- * Creates a border color style object from a theme token.
14670
- *
14671
- * @param token - Theme color token
14672
- * @returns CSSProperties with borderColor
14673
- */
14674
- function borderColorStyle(token) {
14675
- return { borderColor: rgbColorValue(token) };
14676
- }
14677
- /**
14678
- * Merges multiple CSSProperties objects into a single object.
14679
- * Later styles override earlier ones. Undefined values are filtered out.
14680
- * Returns undefined if the merged result is empty.
14681
- *
14682
- * @param styles - Variable number of CSSProperties objects (can be undefined)
14683
- * @returns Merged CSSProperties object, or undefined if empty
14684
- *
14685
- * @example
14686
- * mergeStyles(
14687
- * backgroundColorStyle('surface'),
14688
- * textColorStyle('text'),
14689
- * borderColorStyle('border')
14690
- * )
14691
- * // => { backgroundColor: '...', color: '...', borderColor: '...' }
14692
- */
14693
- function mergeStyles(...styles) {
14694
- const merged = {};
14695
- for (const style of styles) {
14696
- if (!style) continue;
14697
- Object.assign(merged, style);
14698
- }
14699
- return Object.keys(merged).length ? merged : void 0;
14700
- }
14701
- //#endregion
14702
14789
  //#region ../theme-core/src/utils/tokenOrColor.ts
14703
14790
  /**
14704
14791
  * Runtime color-reference fields intentionally accept any string, including
@@ -15184,26 +15271,19 @@ function resolvedButtonFocusDeclarations(indicator, role) {
15184
15271
  ] : [["outline", value("outline", `3px solid ${indicator.colorCss}`)], ["outline-offset", value("outline-offset", "3px")]];
15185
15272
  }
15186
15273
  /**
15187
- * Disabled buttons retain their validated colour pair and add a non-layout
15188
- * visual affordance. `currentColor` keeps the cue inside the same contrast
15189
- * relationship, while retaining pointer events lets the not-allowed cursor
15190
- * remain observable.
15274
+ * Disabled buttons are deliberately muted as unavailable controls. Native
15275
+ * disabled controls are exempt from active-control contrast requirements;
15276
+ * opacity distinguishes the state without introducing a focus-like outline.
15277
+ * Retaining pointer events lets the not-allowed cursor remain observable.
15191
15278
  */
15192
15279
  const RESOLVED_BUTTON_DISABLED_DECLARATIONS = [
15193
15280
  ["cursor", "not-allowed"],
15194
15281
  ["transform", "none"],
15195
15282
  ["box-shadow", "none"],
15196
- ["outline", "2px dashed currentColor"],
15197
- ["outline-offset", "-4px"]
15283
+ ["opacity", "0.55"]
15198
15284
  ];
15199
15285
  //#endregion
15200
15286
  //#region ../theme-core/src/buttons/generateButtonCss.ts
15201
- /**
15202
- * Class the `button` runtime node adds when it renders its own trailing icon,
15203
- * so a node-level icon suppresses the theme's CSS `::after` affordance.
15204
- * Shared so generator and renderer can't drift.
15205
- */
15206
- const AFFORDANCE_SUPPRESS_CLASS = "rb-affordance-off";
15207
15287
  const BUTTON_SIZE_NAMES = buttonSizeNameSchema.options;
15208
15288
  /**
15209
15289
  * Letter spacing token → CSS value.
@@ -26896,6 +26976,28 @@ const bookingRequirementConsentFieldSchema = z.object({
26896
26976
  const bookingConsentCarrierSchema = z.union([blockBookingConsentSchema, bookingRequirementConsentFieldSchema]);
26897
26977
  //#endregion
26898
26978
  //#region ../blocks/src/system/blocks/events/shared/schemas.ts
26979
+ const publicEventLoaderQuerySchemaShape = {
26980
+ limit: z.string().optional(),
26981
+ from: z.string().optional(),
26982
+ to: z.string().optional(),
26983
+ afterStartsAt: z.string().optional(),
26984
+ afterId: z.string().optional(),
26985
+ categoryIds: z.string().optional(),
26986
+ venueId: z.string().optional(),
26987
+ staffMemberId: z.string().optional(),
26988
+ eventSurface: z.string().optional(),
26989
+ eventPresets: z.string().optional(),
26990
+ scheduleScope: z.string().optional(),
26991
+ seriesId: z.string().optional(),
26992
+ seriesIds: z.string().optional(),
26993
+ runSeriesId: z.string().optional(),
26994
+ seriesSlug: z.string().optional(),
26995
+ includeOccurrenceId: z.string().optional(),
26996
+ readIntent: z.string().optional(),
26997
+ detailLevel: z.string().optional(),
26998
+ readProfile: z.string().optional()
26999
+ };
27000
+ z.object(publicEventLoaderQuerySchemaShape);
26899
27001
  const eventPresetSchema = z.enum([
26900
27002
  "event",
26901
27003
  "class",
@@ -27262,6 +27364,7 @@ const calendarWindowQuerySchema = z.object({
27262
27364
  eventSurface: z.enum(eventSurfaceScopeValues).optional(),
27263
27365
  eventPresets: z.string().optional(),
27264
27366
  scheduleScope: z.enum(eventScheduleScopeValues).optional(),
27367
+ seriesIds: z.string().optional(),
27265
27368
  categoryIds: z.string().optional(),
27266
27369
  venueId: z.string().transform(normalizeCalendarFilterId).optional(),
27267
27370
  staffMemberId: z.string().transform(normalizeCalendarFilterId).optional()
@@ -27312,7 +27415,56 @@ const calendarWindowPageSchema = z.discriminatedUnion("kind", [z.object({
27312
27415
  kind: z.literal("partial"),
27313
27416
  nextCursor: calendarSourceCursorSchema
27314
27417
  })]);
27418
+ //#endregion
27419
+ //#region ../blocks/src/system/blocks/events/shared/eventSelection.ts
27420
+ /** Invalid saved selections fail closed rather than widening discovery. */
27421
+ function resolveEventSelection(mode, value) {
27422
+ if (mode !== "selected") return { kind: "matching" };
27423
+ const candidates = Array.isArray(value) ? value : typeof value === "string" ? value.split(",").filter(Boolean) : [];
27424
+ const ids = [];
27425
+ for (const candidate of candidates) {
27426
+ if (typeof candidate !== "string") return {
27427
+ kind: "selected",
27428
+ seriesIds: []
27429
+ };
27430
+ const parsed = parseEventSeriesId(candidate.trim());
27431
+ if (!parsed.ok) return {
27432
+ kind: "selected",
27433
+ seriesIds: []
27434
+ };
27435
+ ids.push(parsed.value);
27436
+ }
27437
+ return {
27438
+ kind: "selected",
27439
+ seriesIds: [...new Set(ids)].sort()
27440
+ };
27441
+ }
27442
+ /** Undefined means discovery; an empty string is an explicitly empty selection. */
27443
+ function eventSeriesScopeCsv(value) {
27444
+ if (value == null) return void 0;
27445
+ return typeof value === "string" ? value : value.join(",");
27446
+ }
27315
27447
  const defaultTransforms = createTransformRegistry([
27448
+ {
27449
+ id: "events.calendarSelectionParam",
27450
+ kind: "formatter",
27451
+ summary: "Resolve selected events instead of discovery filters",
27452
+ schema: z.object({ key: z.enum([
27453
+ "seriesIds",
27454
+ "eventSurface",
27455
+ "filterEventPresets",
27456
+ "scheduleScope",
27457
+ "filterCategoryIds",
27458
+ "filterStaffMemberId",
27459
+ "filterVenueId"
27460
+ ]) }),
27461
+ run(value, { key }) {
27462
+ const content = asPartialObject(value) ?? {};
27463
+ const selection = resolveEventSelection(content.eventSelection, content.selectedEventSeriesIds);
27464
+ if (selection.kind === "selected") return key === "seriesIds" ? selection.seriesIds : void 0;
27465
+ return key === "seriesIds" ? void 0 : content[key];
27466
+ }
27467
+ },
27316
27468
  {
27317
27469
  id: "events.calendarReadEnabled",
27318
27470
  kind: "formatter",
@@ -29068,17 +29220,16 @@ const ButtonNode = ({ value, children, href, variantId = "primary", size = "md",
29068
29220
  if (process.env.NODE_ENV === "development") console.warn("[ButtonNode] Missing href for link-required button");
29069
29221
  return null;
29070
29222
  }
29071
- const extraClassName = affordanceIcon ? [className, AFFORDANCE_SUPPRESS_CLASS].filter(Boolean).join(" ") : className;
29072
29223
  const resolvedVariantId = parseThemeButtonVariantId(variantId);
29073
29224
  if (variantId && !resolvedVariantId) {
29074
29225
  console.error("[ButtonNode] Invalid button variant", { variantId });
29075
29226
  return null;
29076
29227
  }
29077
- const combinedClassName = resolvedVariantId ? themeButtonClassName({
29228
+ const combinedClassName = resolvedVariantId ? (affordanceIcon ? themeButtonClassNameWithTrailingIcon : themeButtonClassName)({
29078
29229
  variant: resolvedVariantId,
29079
29230
  size,
29080
- extraClassName
29081
- }) : extraClassName;
29231
+ extraClassName: className
29232
+ }) : className;
29082
29233
  if (resolvedHref) return /* @__PURE__ */ jsxs("a", {
29083
29234
  href: resolvedHref,
29084
29235
  target,
@@ -30337,10 +30488,11 @@ const publicPricingSchema = z.object({
30337
30488
  singlePriceAmount: z.number().nullable(),
30338
30489
  slidingMinAmount: z.number().nullable(),
30339
30490
  slidingMaxAmount: z.number().nullable(),
30340
- options: z.array(publicPricingOptionSchema)
30491
+ options: z.array(publicPricingOptionSchema).readonly()
30341
30492
  });
30342
30493
  const publicAppointmentServiceSchema = z.object({
30343
30494
  id: z.string().min(1),
30495
+ slug: z.string().min(1).optional(),
30344
30496
  title: z.string(),
30345
30497
  description: z.string().nullable().optional(),
30346
30498
  durationMinutes: z.number().int().positive(),
@@ -30417,7 +30569,7 @@ function formatAmountOrFree(amount, currency) {
30417
30569
  currency
30418
30570
  }, { decimals: "auto" });
30419
30571
  }
30420
- function buildRows(services, pathname) {
30572
+ function buildRows(services, pathname, servicePathPrefix) {
30421
30573
  return services.map((service) => ({
30422
30574
  id: service.id,
30423
30575
  title: service.title,
@@ -30428,7 +30580,8 @@ function buildRows(services, pathname) {
30428
30580
  href: resolveDedicatedBookingHref(pathname, {
30429
30581
  kind: "appointment_service",
30430
30582
  serviceId: service.id
30431
- })
30583
+ }),
30584
+ detailsHref: servicePathPrefix && service.slug ? `${servicePathPrefix.replace(/\/$/, "")}/${encodeURIComponent(service.slug)}` : null
30432
30585
  }));
30433
30586
  }
30434
30587
  function buildAppointmentServicesView(input) {
@@ -30447,13 +30600,14 @@ function buildAppointmentServicesView(input) {
30447
30600
  };
30448
30601
  return {
30449
30602
  kind: "items",
30450
- rows: buildRows(parsed.services, input.pathname)
30603
+ rows: buildRows(parsed.services, input.pathname, input.servicePathPrefix ?? null)
30451
30604
  };
30452
30605
  }
30453
- function AppointmentServicesNode({ sectionHeading, services, pathname, className }) {
30606
+ function AppointmentServicesNode({ sectionHeading, services, pathname, servicePathPrefix, className }) {
30454
30607
  const view = buildAppointmentServicesView({
30455
30608
  services,
30456
- pathname: typeof pathname === "string" ? pathname : void 0
30609
+ pathname: typeof pathname === "string" ? pathname : void 0,
30610
+ servicePathPrefix: typeof servicePathPrefix === "string" ? servicePathPrefix : null
30457
30611
  });
30458
30612
  const rootClassName = `appointment-services ${className ?? ""}`.trim();
30459
30613
  const RowTitle = sectionHeading ? "h3" : "h2";
@@ -30484,7 +30638,10 @@ function AppointmentServicesNode({ sectionHeading, services, pathname, className
30484
30638
  children: [
30485
30639
  /* @__PURE__ */ jsx(RowTitle, {
30486
30640
  className: "appointment-services-row-title rb-text-lg rb-font-medium rb-leading-tight",
30487
- children: row.title
30641
+ children: row.detailsHref ? /* @__PURE__ */ jsx("a", {
30642
+ href: row.detailsHref,
30643
+ children: row.title
30644
+ }) : row.title
30488
30645
  }),
30489
30646
  row.description ? /* @__PURE__ */ jsx("p", {
30490
30647
  className: "appointment-services-row-description rb-text-sm rb-leading-6 status-muted",
@@ -32975,12 +33132,12 @@ const EventCompactRow = ({ event, buttonVariant = "primary", buttonText }) => {
32975
33132
  }), cta.hidden ? /* @__PURE__ */ jsx("span", {
32976
33133
  className: "event-compact-row-status",
32977
33134
  children: cta.label
32978
- }) : /* @__PURE__ */ jsxs("a", {
33135
+ }) : /* @__PURE__ */ jsx("a", {
32979
33136
  href: cta.href,
32980
33137
  target: cta.external ? "_blank" : void 0,
32981
33138
  rel: cta.external ? "noopener noreferrer" : void 0,
32982
33139
  className: `${buttonClass} event-compact-row-cta`,
32983
- children: [/* @__PURE__ */ jsx("span", { children: cta.label }), /* @__PURE__ */ jsx(ArrowRightIcon, { "aria-hidden": "true" })]
33140
+ children: /* @__PURE__ */ jsx("span", { children: cta.label })
32984
33141
  })]
32985
33142
  })]
32986
33143
  })]
@@ -34062,6 +34219,7 @@ const eventCollectionFilterSourceSchemaShape = {
34062
34219
  eventSurface: eventSurfaceScopeSchema$1.nullable().optional(),
34063
34220
  filterEventPresets: z.union([z.string(), z.array(z.string())]).nullable().optional(),
34064
34221
  scheduleScope: eventScheduleScopeSchema$1.nullable().optional(),
34222
+ seriesIds: z.union([z.string(), z.array(z.string())]).nullable().optional(),
34065
34223
  filterCategoryIds: z.union([z.string(), z.array(z.string())]).nullable().optional(),
34066
34224
  filterStaffMemberId: z.string().nullable().optional(),
34067
34225
  filterVenueId: z.string().nullable().optional()
@@ -34108,6 +34266,7 @@ const eventCollectionDisplaySchemaShape = {
34108
34266
  eventSurface: eventSurfaceScopeSchema$1,
34109
34267
  filterEventPresets: z.string().nullable(),
34110
34268
  scheduleScope: eventScheduleScopeSchema$1,
34269
+ seriesIds: z.string().nullable().optional(),
34111
34270
  filterCategoryIds: z.string().nullable(),
34112
34271
  filterStaffMemberId: z.string().nullable(),
34113
34272
  filterVenueId: z.string().nullable(),
@@ -34155,11 +34314,15 @@ function buildEventCollectionDisplay(source) {
34155
34314
  };
34156
34315
  }
34157
34316
  function buildEventCollectionFilterDisplay(source) {
34158
- return {
34159
- showFilters: source.showFilters ?? true,
34160
- showCategoryFilter: source.showCategoryFilter ?? "auto",
34161
- showVenueFilter: source.showVenueFilter ?? false,
34162
- showStaffFilter: source.showStaffFilter ?? true,
34317
+ const selected = source.seriesIds != null;
34318
+ const matchingFilters = selected ? {
34319
+ eventSurface: "all",
34320
+ filterEventPresets: null,
34321
+ scheduleScope: "any",
34322
+ filterCategoryIds: null,
34323
+ filterStaffMemberId: null,
34324
+ filterVenueId: null
34325
+ } : {
34163
34326
  eventSurface: normalizeEventSurfaceScope(source.eventSurface),
34164
34327
  filterEventPresets: normalizeEventSurfacePresetsCsv(source.filterEventPresets),
34165
34328
  scheduleScope: normalizeEventScheduleScope(source.scheduleScope),
@@ -34167,6 +34330,14 @@ function buildEventCollectionFilterDisplay(source) {
34167
34330
  filterStaffMemberId: normalizeEventStaffMemberId(source.filterStaffMemberId),
34168
34331
  filterVenueId: normalizeEventVenueId(source.filterVenueId)
34169
34332
  };
34333
+ return {
34334
+ seriesIds: eventSeriesScopeCsv(source.seriesIds),
34335
+ showFilters: selected ? false : source.showFilters ?? true,
34336
+ showCategoryFilter: source.showCategoryFilter ?? "auto",
34337
+ showVenueFilter: source.showVenueFilter ?? false,
34338
+ showStaffFilter: source.showStaffFilter ?? true,
34339
+ ...matchingFilters
34340
+ };
34170
34341
  }
34171
34342
  function buildEventCollectionPresentationDisplay(source) {
34172
34343
  return {
@@ -34181,14 +34352,15 @@ function buildEventCollectionPresentationDisplay(source) {
34181
34352
  }
34182
34353
  function buildEventCollectionHydration(source, now = /* @__PURE__ */ new Date()) {
34183
34354
  const timeZone = source.calendarWindow?.scope.timeZone ?? toBookingTimeZone(source.bookingTimeZone);
34355
+ const selected = source.seriesIds != null;
34184
34356
  return {
34185
34357
  calendarWindow: source.calendarWindow ?? void 0,
34186
34358
  siteId: source.siteId,
34187
34359
  stage: source.stage,
34188
34360
  prefetchedEvents: source.events != null,
34189
- eventSurface: normalizeEventSurfaceScope(source.eventSurface),
34190
- filterEventPresets: normalizeEventSurfacePresetsCsv(source.filterEventPresets),
34191
- scheduleScope: normalizeEventScheduleScope(source.scheduleScope),
34361
+ eventSurface: selected ? "all" : normalizeEventSurfaceScope(source.eventSurface),
34362
+ filterEventPresets: selected ? null : normalizeEventSurfacePresetsCsv(source.filterEventPresets),
34363
+ scheduleScope: selected ? "any" : normalizeEventScheduleScope(source.scheduleScope),
34192
34364
  calendarContext: {
34193
34365
  timeZone,
34194
34366
  initialToday: source.calendarWindow?.initialToday ?? getLocalScheduleDate(now, timeZone)
@@ -34758,13 +34930,10 @@ function OfferingsPreviewContent(props) {
34758
34930
  }),
34759
34931
  groupCta ? /* @__PURE__ */ jsx("footer", {
34760
34932
  className: "offerings-preview-card-footer rb-mt-auto rb-flex",
34761
- children: /* @__PURE__ */ jsxs("a", {
34933
+ children: /* @__PURE__ */ jsx("a", {
34762
34934
  className: groupLinkClass,
34763
34935
  href: groupCta.href,
34764
- children: [/* @__PURE__ */ jsx("span", { children: groupCta.label }), /* @__PURE__ */ jsx(ArrowRightIcon, {
34765
- "aria-hidden": "true",
34766
- className: "offerings-preview-link-icon rb-h-4 rb-w-4"
34767
- })]
34936
+ children: /* @__PURE__ */ jsx("span", { children: groupCta.label })
34768
34937
  })
34769
34938
  }) : null
34770
34939
  ]
@@ -36971,6 +37140,44 @@ function toWholeSeriesRegistrationEvents(events) {
36971
37140
  return groupPublicEventsByRun(events).map(toWholeSeriesRegistrationEvent).filter((event) => event !== null);
36972
37141
  }
36973
37142
  //#endregion
37143
+ //#region ../blocks/src/system/runtime/nodes/event-registration/eventSourceRecovery.ts
37144
+ const { limit: _rawLimit, eventSurface: _rawEventSurface, scheduleScope: _rawScheduleScope, detailLevel: _rawDetailLevel, ...stringEventQueryShape } = publicEventLoaderQuerySchemaShape;
37145
+ const eventRecoveryRequestSchema = z.object({
37146
+ ...stringEventQueryShape,
37147
+ limit: z.coerce.number().int().positive().optional(),
37148
+ eventSurface: z.enum(eventSurfaceScopeValues).optional(),
37149
+ scheduleScope: z.enum(eventScheduleScopeValues).optional(),
37150
+ detailLevel: z.enum(["full", "listing"]).optional(),
37151
+ stage: z.enum(["preview", "published"]).optional()
37152
+ });
37153
+ function resolveEventRegistrationEventSource(input) {
37154
+ if (input.wholeSeriesRunEvents != null) return {
37155
+ kind: "loaded",
37156
+ events: input.wholeSeriesRunEvents
37157
+ };
37158
+ if (input.events != null) return {
37159
+ kind: "loaded",
37160
+ events: input.events
37161
+ };
37162
+ return {
37163
+ kind: "unresolved",
37164
+ request: parseEventLoaderRecoveryRequest(input.failures?.wholeSeriesRunEvents ?? input.failures?.events)
37165
+ };
37166
+ }
37167
+ const eventLoaderFailureSchema = z.object({
37168
+ endpoint: z.literal("listPublicEvents"),
37169
+ params: eventRecoveryRequestSchema.extend({ siteId: z.string().optional() })
37170
+ });
37171
+ function parseEventLoaderRecoveryRequest(value) {
37172
+ const parsed = eventLoaderFailureSchema.safeParse(value);
37173
+ if (!parsed.success) return null;
37174
+ const { siteId: _siteId, stage, ...params } = parsed.data.params;
37175
+ return {
37176
+ ...params,
37177
+ stage: stage ?? "published"
37178
+ };
37179
+ }
37180
+ //#endregion
36974
37181
  //#region ../blocks/src/system/runtime/nodes/event-registration.interactive.ts
36975
37182
  const EVENT_REGISTRATION_GENERIC_SHELL_STEP_LABELS = [
36976
37183
  "Date",
@@ -36988,8 +37195,6 @@ const eventRegistrationPublicEventSchema = z.preprocess(normalizeEventRegistrati
36988
37195
  const eventRegistrationHydrationSchemaShape = {
36989
37196
  occurrenceContext: occurrenceContextSchema.optional(),
36990
37197
  subject: eventRegistrationPageSurfaceSubjectSchema.nullable().optional(),
36991
- events: z.array(eventRegistrationPublicEventSchema).nullable().optional(),
36992
- wholeSeriesRunEvents: z.array(eventRegistrationPublicEventSchema).nullable().optional(),
36993
37198
  maxTickets: z.string().optional(),
36994
37199
  showVenue: z.boolean().optional(),
36995
37200
  showCapacity: z.boolean().optional(),
@@ -37001,12 +37206,22 @@ const eventRegistrationHydrationSchemaShape = {
37001
37206
  sitePasses: publicPassProductCollectionSchema.nullable().optional(),
37002
37207
  siteMemberships: publicMembershipProductCollectionSchema.nullable().optional()
37003
37208
  };
37209
+ const eventRegistrationEventSourceSchema = z.discriminatedUnion("kind", [z.object({
37210
+ kind: z.literal("loaded"),
37211
+ events: z.array(eventRegistrationPublicEventSchema)
37212
+ }), z.object({
37213
+ kind: z.literal("unresolved"),
37214
+ request: eventRecoveryRequestSchema.nullable()
37215
+ })]);
37004
37216
  const eventRegistrationSourceSchema = z.object({
37005
37217
  siteId: z.string().optional(),
37006
37218
  apiBaseUrl: z.string().optional(),
37007
37219
  portalToken: z.string().nullable().optional(),
37008
37220
  previewToken: z.string().nullable().optional(),
37009
37221
  ...eventRegistrationHydrationSchemaShape,
37222
+ events: z.array(eventRegistrationPublicEventSchema).nullable().optional(),
37223
+ wholeSeriesRunEvents: z.array(eventRegistrationPublicEventSchema).nullable().optional(),
37224
+ eventLoaderFailures: z.record(z.string(), z.unknown()).nullable().optional(),
37010
37225
  className: z.string().nullable().optional(),
37011
37226
  buttonText: z.string().nullable().optional(),
37012
37227
  maxTickets: z.string().nullable().optional(),
@@ -37027,7 +37242,10 @@ const eventRegistrationDisplaySchema = z.discriminatedUnion("state", [z.object({
37027
37242
  titleText: z.string(),
37028
37243
  bodyText: z.string()
37029
37244
  })]);
37030
- const eventRegistrationHydrationSchema = z.object(eventRegistrationHydrationSchemaShape);
37245
+ const eventRegistrationHydrationSchema = z.object({
37246
+ ...eventRegistrationHydrationSchemaShape,
37247
+ eventSource: eventRegistrationEventSourceSchema
37248
+ });
37031
37249
  const eventRegistrationRenderSchema = z.object({
37032
37250
  display: eventRegistrationDisplaySchema,
37033
37251
  hydration: eventRegistrationHydrationSchema
@@ -37086,16 +37304,12 @@ function buildEventRegistrationShellStepLabels(source, scopedSourceEvents) {
37086
37304
  function toScopedEventRegistrationEvents(scopedSourceEvents) {
37087
37305
  return [...toRegistrationEvents(scopedSourceEvents), ...toWholeSeriesRegistrationEvents(scopedSourceEvents)];
37088
37306
  }
37089
- function scopeEventRegistrationSourceEvents(source) {
37090
- return resolveEventRegistrationScopedEvents(source.wholeSeriesRunEvents ?? source.events ?? [], {
37307
+ function scopeEventRegistrationSourceEvents(source, eventSource) {
37308
+ return resolveEventRegistrationScopedEvents(eventSource.kind === "loaded" ? eventSource.events : [], {
37091
37309
  occurrenceContext: source.occurrenceContext,
37092
37310
  subject: source.subject
37093
37311
  });
37094
37312
  }
37095
- function resolveLoadedEventRegistrationSourceEvents(source, scopedSourceEvents) {
37096
- if (source.events == null && source.wholeSeriesRunEvents == null) return null;
37097
- return [...scopedSourceEvents];
37098
- }
37099
37313
  /**
37100
37314
  * The one run this surface is registering for, when the scoped events describe
37101
37315
  * exactly one. More than one run means the visitor still has to choose.
@@ -37135,14 +37349,21 @@ const eventRegistrationBlockRuntime = defineClientOwnedBlockRuntime({
37135
37349
  render: createZodCodec(eventRegistrationRenderSchema)
37136
37350
  },
37137
37351
  buildRender: (source) => {
37138
- const scopedSourceEvents = scopeEventRegistrationSourceEvents(source);
37139
- const events = resolveLoadedEventRegistrationSourceEvents(source, scopedSourceEvents);
37352
+ const eventSource = resolveEventRegistrationEventSource({
37353
+ events: source.events,
37354
+ wholeSeriesRunEvents: source.wholeSeriesRunEvents,
37355
+ failures: source.eventLoaderFailures
37356
+ });
37357
+ const scopedSourceEvents = scopeEventRegistrationSourceEvents(source, eventSource);
37140
37358
  return {
37141
37359
  display: buildEventRegistrationDisplayFromScopedEvents(source, scopedSourceEvents),
37142
37360
  hydration: {
37143
37361
  occurrenceContext: source.occurrenceContext ?? null,
37144
37362
  subject: source.subject ?? null,
37145
- events,
37363
+ eventSource: eventSource.kind === "loaded" ? {
37364
+ ...eventSource,
37365
+ events: [...scopedSourceEvents]
37366
+ } : eventSource,
37146
37367
  maxTickets: source.maxTickets ?? void 0,
37147
37368
  showVenue: source.showVenue,
37148
37369
  showCapacity: source.showCapacity,
@@ -37332,6 +37553,7 @@ const eventRegistrationBlockDefinition = {
37332
37553
  } },
37333
37554
  events: { $bind: { from: "data.events" } },
37334
37555
  wholeSeriesRunEvents: { $bind: { from: "data.wholeSeriesRunEvents" } },
37556
+ loaderFailures: { $bind: { from: "$root.loaderFailures" } },
37335
37557
  sitePasses: { $bind: { from: "data.sitePasses" } },
37336
37558
  siteMemberships: { $bind: { from: "data.siteMemberships" } },
37337
37559
  stage: { $bind: {
@@ -37658,6 +37880,65 @@ const formBlockDefinition = {
37658
37880
  runtime: formBlockRuntime
37659
37881
  };
37660
37882
  //#endregion
37883
+ //#region ../blocks/src/system/blocks/events/eventSelectionFields.ts
37884
+ const eventSelectionFields = [{
37885
+ id: "eventSelection",
37886
+ type: "select",
37887
+ label: "Events to show",
37888
+ required: false,
37889
+ multiple: false,
37890
+ defaultValue: "matching",
37891
+ options: [{
37892
+ value: "matching",
37893
+ label: "All matching events"
37894
+ }, {
37895
+ value: "selected",
37896
+ label: "Selected events"
37897
+ }],
37898
+ ui: { intent: "behavior" }
37899
+ }, createSiteOptionSelectField({
37900
+ id: "selectedEventSeriesIds",
37901
+ label: "Selected events",
37902
+ description: "Show upcoming dates for these events. Other event filters do not apply.",
37903
+ required: false,
37904
+ multiple: true,
37905
+ defaultValue: [],
37906
+ optionSource: "eventSeries",
37907
+ ui: {
37908
+ intent: "behavior",
37909
+ searchThreshold: 1,
37910
+ visibleWhen: {
37911
+ field: "eventSelection",
37912
+ equals: "selected"
37913
+ }
37914
+ }
37915
+ })];
37916
+ function withEventSelectionVisibility(field) {
37917
+ if (![
37918
+ "eventSurface",
37919
+ "filterEventPresets",
37920
+ "scheduleScope",
37921
+ "filterCategoryIds",
37922
+ "filterStaffMemberId",
37923
+ "filterVenueId",
37924
+ "showFilters",
37925
+ "showCategoryFilter",
37926
+ "showVenueFilter",
37927
+ "showStaffFilter"
37928
+ ].includes(field.id)) return field;
37929
+ const visibleWhen = field.ui?.visibleWhen;
37930
+ return {
37931
+ ...field,
37932
+ ui: {
37933
+ ...field.ui,
37934
+ visibleWhen: { allOf: [{
37935
+ field: "eventSelection",
37936
+ notEquals: "selected"
37937
+ }, ...visibleWhen ? [visibleWhen] : []] }
37938
+ }
37939
+ };
37940
+ }
37941
+ //#endregion
37661
37942
  //#region ../blocks/src/system/runtime/nodes/events/EventCalendar.interactive.ts
37662
37943
  const eventCalendarSourceSchema = z.object({
37663
37944
  ...eventCollectionSourceSchemaShape,
@@ -37755,19 +38036,59 @@ function buildEventCalendarInteractiveIslandProps(props) {
37755
38036
  //#region ../blocks/src/system/blocks/events/eventCalendarDataLoaders.ts
37756
38037
  const scopeParams = {
37757
38038
  siteId: { $bind: { from: "$root.siteId" } },
38039
+ seriesIds: { $bind: {
38040
+ from: "content",
38041
+ transforms: [{
38042
+ id: "events.calendarSelectionParam",
38043
+ options: { key: "seriesIds" }
38044
+ }]
38045
+ } },
37758
38046
  stage: { $bind: {
37759
38047
  from: "$root.previewStage",
37760
38048
  fallback: "published"
37761
38049
  } },
37762
- eventSurface: { $bind: { from: "content.eventSurface" } },
38050
+ eventSurface: { $bind: {
38051
+ from: "content",
38052
+ transforms: [{
38053
+ id: "events.calendarSelectionParam",
38054
+ options: { key: "eventSurface" }
38055
+ }, { id: "value.csv" }]
38056
+ } },
37763
38057
  eventPresets: { $bind: {
37764
- from: "content.filterEventPresets",
37765
- transforms: [{ id: "value.csv" }]
38058
+ from: "content",
38059
+ transforms: [{
38060
+ id: "events.calendarSelectionParam",
38061
+ options: { key: "filterEventPresets" }
38062
+ }, { id: "value.csv" }]
37766
38063
  } },
37767
- scheduleScope: { $bind: { from: "content.scheduleScope" } },
37768
- categoryIds: { $bind: { from: "content.filterCategoryIds" } },
37769
- staffMemberId: { $bind: { from: "content.filterStaffMemberId" } },
37770
- venueId: { $bind: { from: "content.filterVenueId" } }
38064
+ scheduleScope: { $bind: {
38065
+ from: "content",
38066
+ transforms: [{
38067
+ id: "events.calendarSelectionParam",
38068
+ options: { key: "scheduleScope" }
38069
+ }, { id: "value.csv" }]
38070
+ } },
38071
+ categoryIds: { $bind: {
38072
+ from: "content",
38073
+ transforms: [{
38074
+ id: "events.calendarSelectionParam",
38075
+ options: { key: "filterCategoryIds" }
38076
+ }, { id: "value.csv" }]
38077
+ } },
38078
+ staffMemberId: { $bind: {
38079
+ from: "content",
38080
+ transforms: [{
38081
+ id: "events.calendarSelectionParam",
38082
+ options: { key: "filterStaffMemberId" }
38083
+ }, { id: "value.csv" }]
38084
+ } },
38085
+ venueId: { $bind: {
38086
+ from: "content",
38087
+ transforms: [{
38088
+ id: "events.calendarSelectionParam",
38089
+ options: { key: "filterVenueId" }
38090
+ }, { id: "value.csv" }]
38091
+ } }
37771
38092
  };
37772
38093
  /** Combined renders two jobs; calendar-only variants never pay for the list seed. */
37773
38094
  const eventCalendarDataLoaders = {
@@ -37897,6 +38218,13 @@ const eventCalendarLayout = [styledSection({
37897
38218
  from: "content.defaultCalendarView",
37898
38219
  fallback: "month"
37899
38220
  } },
38221
+ seriesIds: { $bind: {
38222
+ from: "content",
38223
+ transforms: [{
38224
+ id: "events.calendarSelectionParam",
38225
+ options: { key: "seriesIds" }
38226
+ }]
38227
+ } },
37900
38228
  showFilters: { $bind: {
37901
38229
  from: "content.showFilters",
37902
38230
  fallback: true
@@ -37918,17 +38246,47 @@ const eventCalendarLayout = [styledSection({
37918
38246
  fallback: true
37919
38247
  } },
37920
38248
  eventSurface: { $bind: {
37921
- from: "content.eventSurface",
37922
- fallback: "all"
38249
+ from: "content",
38250
+ transforms: [{
38251
+ id: "events.calendarSelectionParam",
38252
+ options: { key: "eventSurface" }
38253
+ }]
38254
+ } },
38255
+ filterEventPresets: { $bind: {
38256
+ from: "content",
38257
+ transforms: [{
38258
+ id: "events.calendarSelectionParam",
38259
+ options: { key: "filterEventPresets" }
38260
+ }]
37923
38261
  } },
37924
- filterEventPresets: { $bind: { from: "content.filterEventPresets" } },
37925
38262
  scheduleScope: { $bind: {
37926
- from: "content.scheduleScope",
37927
- fallback: "any"
38263
+ from: "content",
38264
+ transforms: [{
38265
+ id: "events.calendarSelectionParam",
38266
+ options: { key: "scheduleScope" }
38267
+ }]
38268
+ } },
38269
+ filterCategoryIds: { $bind: {
38270
+ from: "content",
38271
+ transforms: [{
38272
+ id: "events.calendarSelectionParam",
38273
+ options: { key: "filterCategoryIds" }
38274
+ }]
38275
+ } },
38276
+ filterStaffMemberId: { $bind: {
38277
+ from: "content",
38278
+ transforms: [{
38279
+ id: "events.calendarSelectionParam",
38280
+ options: { key: "filterStaffMemberId" }
38281
+ }]
38282
+ } },
38283
+ filterVenueId: { $bind: {
38284
+ from: "content",
38285
+ transforms: [{
38286
+ id: "events.calendarSelectionParam",
38287
+ options: { key: "filterVenueId" }
38288
+ }]
37928
38289
  } },
37929
- filterCategoryIds: { $bind: { from: "content.filterCategoryIds" } },
37930
- filterStaffMemberId: { $bind: { from: "content.filterStaffMemberId" } },
37931
- filterVenueId: { $bind: { from: "content.filterVenueId" } },
37932
38290
  cardRole: { $bind: {
37933
38291
  from: "content._cardStyles.role",
37934
38292
  fallback: "default"
@@ -38432,6 +38790,7 @@ const eventCalendarAdditionalFields = [
38432
38790
  }
38433
38791
  }
38434
38792
  },
38793
+ ...eventSelectionFields,
38435
38794
  {
38436
38795
  id: "eventSurface",
38437
38796
  type: "select",
@@ -38641,7 +39000,7 @@ const eventCalendarBlockDefinition = {
38641
39000
  titleSource: "heading",
38642
39001
  description: "Display events with calendar, list, or combined views with filtering",
38643
39002
  skipSectionStyles: true,
38644
- additionalFields: eventCalendarAdditionalFields,
39003
+ additionalFields: eventCalendarAdditionalFields.map(withEventSelectionVisibility),
38645
39004
  styleTokens: {
38646
39005
  background: "surface",
38647
39006
  typography: "body",
@@ -38750,6 +39109,7 @@ const eventListingHydrationSchema = z.object({
38750
39109
  eventSurface: eventSurfaceScopeSchema,
38751
39110
  filterEventPresets: z.string().nullable(),
38752
39111
  scheduleScope: eventScheduleScopeSchema,
39112
+ seriesIds: z.string().nullable().optional(),
38753
39113
  filterCategoryIds: z.string().nullable().optional(),
38754
39114
  filterStaffMemberId: z.string().nullable().optional(),
38755
39115
  filterVenueId: z.string().nullable().optional(),
@@ -38810,6 +39170,7 @@ const eventListingBlockRuntime = defineProgressiveBlockRuntime({
38810
39170
  eventSurface: normalizeEventSurfaceScope(source.eventSurface),
38811
39171
  filterEventPresets: normalizeEventSurfacePresetsCsv(source.filterEventPresets),
38812
39172
  scheduleScope: normalizeEventScheduleScope(source.scheduleScope),
39173
+ seriesIds: eventSeriesScopeCsv(source.seriesIds),
38813
39174
  filterCategoryIds: normalizeEventCategoryIdsCsv(source.filterCategoryIds),
38814
39175
  filterStaffMemberId: normalizeEventStaffMemberId(source.filterStaffMemberId),
38815
39176
  filterVenueId: normalizeEventVenueId(source.filterVenueId),
@@ -39314,6 +39675,15 @@ const newsletterFieldSchema = z.object({
39314
39675
  placeholder: z.string().optional()
39315
39676
  });
39316
39677
  const mailingListSignupBlockIdSchema = z.string().trim().min(1).transform(parseRequiredMailingListSignupBlockId);
39678
+ const mailingListContentVersionIdSchema = z.string().transform((value, ctx) => {
39679
+ const parsed = parseMailingListContentVersionId(value);
39680
+ if (parsed) return parsed;
39681
+ ctx.addIssue({
39682
+ code: z.ZodIssueCode.custom,
39683
+ message: "Invalid mailing-list content version ID"
39684
+ });
39685
+ return z.NEVER;
39686
+ });
39317
39687
  const signedMailingListSourceTokenSchema = z.string().trim().min(1).transform(parseRequiredMailingListSignedSourceToken);
39318
39688
  const newsletterSourceCommonSchema = z.object({
39319
39689
  siteId: z.string().optional(),
@@ -39327,7 +39697,8 @@ const newsletterSourceCommonSchema = z.object({
39327
39697
  const newsletterSourceSchema = z.discriminatedUnion("source", [
39328
39698
  newsletterSourceCommonSchema.extend({
39329
39699
  source: z.literal("block"),
39330
- blockId: z.string().nullable().optional()
39700
+ blockId: z.string().nullable().optional(),
39701
+ contentVersionId: z.string().nullable().optional()
39331
39702
  }),
39332
39703
  newsletterSourceCommonSchema.extend({
39333
39704
  source: z.literal("signed-footer"),
@@ -39343,6 +39714,7 @@ const newsletterDisplaySchema = z.object({
39343
39714
  availability: z.enum(["ready", "unavailable"]),
39344
39715
  className: z.string().nullable(),
39345
39716
  buttonLabel: z.string(),
39717
+ successMessage: z.string(),
39346
39718
  buttonVariant: newsletterButtonVariantSchema,
39347
39719
  privacyNote: z.string().nullable(),
39348
39720
  fields: z.array(newsletterFieldSchema),
@@ -39357,7 +39729,8 @@ const newsletterHydrationSchema = z.object({
39357
39729
  tag: z.literal("block-source"),
39358
39730
  sourceRef: z.object({
39359
39731
  tag: z.literal("block_ref"),
39360
- blockId: mailingListSignupBlockIdSchema
39732
+ blockId: mailingListSignupBlockIdSchema,
39733
+ contentVersionId: mailingListContentVersionIdSchema
39361
39734
  }).nullable()
39362
39735
  }),
39363
39736
  z.object({
@@ -39396,6 +39769,7 @@ function buildNewsletterDisplay(source) {
39396
39769
  fields: { preset: "emailOnly" },
39397
39770
  includeOptionalPhone: false,
39398
39771
  buttonLabel: "Subscribe",
39772
+ successMessage: DEFAULT_MAILING_LIST_SUCCESS_MESSAGE,
39399
39773
  privacyNote: null
39400
39774
  };
39401
39775
  const targeting = source.targeting ?? { mode: "default" };
@@ -39405,6 +39779,7 @@ function buildNewsletterDisplay(source) {
39405
39779
  availability: runtimeTargetingIsAvailable(context, targeting, choices) ? "ready" : "unavailable",
39406
39780
  className: source.className ?? null,
39407
39781
  buttonLabel: form.buttonLabel,
39782
+ successMessage: form.successMessage,
39408
39783
  buttonVariant: source.buttonVariant ?? "primary",
39409
39784
  privacyNote: form.privacyNote,
39410
39785
  fields: getGlobalFormFields(form),
@@ -39435,7 +39810,7 @@ const newsletterFormBlockRuntime = defineProgressiveBlockRuntime({
39435
39810
  function projectNewsletterFormHydrationTarget(source) {
39436
39811
  switch (source.source) {
39437
39812
  case "block": {
39438
- const sourceRef = buildMailingListSignupBlockSourceRef(source.blockId);
39813
+ const sourceRef = buildMailingListSignupBlockSourceRef(source.blockId, source.contentVersionId);
39439
39814
  if (sourceRef?.tag === "block_ref") return {
39440
39815
  tag: "block-source",
39441
39816
  sourceRef
@@ -41860,9 +42235,10 @@ function cx(...classes) {
41860
42235
  * Server-safe placeholder for event registration.
41861
42236
  * Provides a static container for island hydration without importing client hooks.
41862
42237
  */
41863
- function EventRegistrationSSR({ blockId, subject, children, ...sourceProps }) {
42238
+ function EventRegistrationSSR({ blockId, subject, loaderFailures, children, ...sourceProps }) {
41864
42239
  const islandProps = buildEventRegistrationInteractiveIslandProps({
41865
42240
  ...sourceProps,
42241
+ eventLoaderFailures: blockId ? loaderFailures?.[blockId] : void 0,
41866
42242
  subject: normalizeEventRegistrationPageSurfaceSubject(subject)
41867
42243
  });
41868
42244
  const display = islandProps.render.display;
@@ -42195,7 +42571,7 @@ function NewsletterFormSSR(props) {
42195
42571
  className: clsx("newsletter-form-ssr", className),
42196
42572
  children: /* @__PURE__ */ jsx("p", {
42197
42573
  role: "status",
42198
- children: "Mailing-list signup is not available right now."
42574
+ children: "We can’t accept signups right now. Please try again later."
42199
42575
  })
42200
42576
  });
42201
42577
  const renderField = (field) => {
@@ -42241,14 +42617,18 @@ function NewsletterFormSSR(props) {
42241
42617
  children: [
42242
42618
  fields.map(renderField),
42243
42619
  islandProps.render.hydration.choicePresentation === "visitor_choice" ? /* @__PURE__ */ jsxs("fieldset", {
42244
- className: "newsletter-topics",
42245
- children: [/* @__PURE__ */ jsx("legend", { children: "What would you like to hear about?" }), display.choices.map((choice) => /* @__PURE__ */ jsxs("label", {
42246
- className: "newsletter-topic-choice",
42620
+ className: "fb-fieldset newsletter-topics",
42621
+ children: [/* @__PURE__ */ jsx("legend", {
42622
+ className: "form-label",
42623
+ children: "What would you like to hear about?"
42624
+ }), display.choices.map((choice) => /* @__PURE__ */ jsxs("label", {
42625
+ className: "fb-inline form-label newsletter-topic-choice",
42247
42626
  children: [/* @__PURE__ */ jsx("input", {
42248
42627
  type: "checkbox",
42249
42628
  name: "mailingListChoice",
42250
- value: choice.id
42251
- }), choice.label]
42629
+ value: choice.id,
42630
+ className: "form-checkbox"
42631
+ }), /* @__PURE__ */ jsx("span", { children: choice.label })]
42252
42632
  }, choice.id))]
42253
42633
  }) : null,
42254
42634
  /* @__PURE__ */ jsx("div", {
@@ -43237,6 +43617,18 @@ function resolveChildren(nodes, context) {
43237
43617
  function isReactNode(value) {
43238
43618
  return value !== null && value !== void 0;
43239
43619
  }
43620
+ function resolveNodeMetadata(nodeType, context) {
43621
+ return {
43622
+ pathBase: context.pathBase,
43623
+ blockId: context.blockId,
43624
+ blockKind: context.blockKind,
43625
+ blockContent: context.blockContent,
43626
+ fragmentRegistry: context.fragmentRegistry,
43627
+ previewAuthoring: context.previewAuthoring,
43628
+ ...nodeType.toLowerCase() === "newsletter-form" ? { contentVersionId: context.contentVersionId } : {},
43629
+ ...nodeType === "media" && context.imageResolveContext ? { imageResolveContext: context.imageResolveContext } : {}
43630
+ };
43631
+ }
43240
43632
  /**
43241
43633
  * Resolves a node definition into a React element.
43242
43634
  * Handles conditionals ($when), scopes ($scopes), repeaters ($repeat), bindings ($bind), and children.
@@ -43272,13 +43664,7 @@ function resolveNode(node, context, indexFallback) {
43272
43664
  const elementProps = {
43273
43665
  ...props,
43274
43666
  key: node.key ?? indexFallback,
43275
- pathBase: context.pathBase,
43276
- blockId: context.blockId,
43277
- blockKind: context.blockKind,
43278
- blockContent: context.blockContent,
43279
- ...node.type === "media" && context.imageResolveContext ? { imageResolveContext: context.imageResolveContext } : {},
43280
- fragmentRegistry: context.fragmentRegistry,
43281
- previewAuthoring: context.previewAuthoring
43667
+ ...resolveNodeMetadata(node.type, context)
43282
43668
  };
43283
43669
  const element = React.createElement(component, elementProps, ...children);
43284
43670
  if (headingDecorationPlan.kind === "skip") return element;
@@ -44153,9 +44539,56 @@ function generateNavLinkCSS(options) {
44153
44539
  if (baseRules.length > 0) cssChunks.unshift(`\n${selector} {\n ${baseRules.join("\n ")}\n}\n`);
44154
44540
  if (hoverRules.length > 0) cssChunks.push(`\n${hoverSelector} {\n ${hoverRules.join("\n ")}\n}\n`);
44155
44541
  if (activeRules.length > 0) cssChunks.push(`\n${activeSelector} {\n ${activeRules.join("\n ")}\n}\n`);
44542
+ cssChunks.push(navLinkFocusVisibleCss(selector, style, theme, tokens));
44156
44543
  cssChunks.push(generateInteractiveChildInheritanceCSS(selector));
44157
44544
  return cssChunks.join("");
44158
44545
  }
44546
+ /**
44547
+ * Keyboard focus indicator for nav links, in the header, the footer and header
44548
+ * dropdown menus — the three surfaces `generateNavLinkCSS` serves.
44549
+ *
44550
+ * Emitted unconditionally rather than as an effect, because focus visibility is
44551
+ * a floor rather than a style choice. Only the interaction-palette pill ever
44552
+ * wrote an `effects.focus` group, so every other nav — every `quiet` palette,
44553
+ * every footer, every dropdown — previously fell back to whatever outline the
44554
+ * browser drew.
44555
+ *
44556
+ * The outline takes the link's own resolved colour, so on a header that adapts
44557
+ * to the section it floats over it moves with the adaptation instead of
44558
+ * asserting a brand colour against an unknown backdrop.
44559
+ *
44560
+ * Where the style asks for `soft-glow`, the same halo goes on the outline. That
44561
+ * treatment exists because the theme has already conceded the resolved colour
44562
+ * alone is not reliable over an unpredictable backdrop — a hero photograph with
44563
+ * mixed luminance. Without it the text would stay legible by its halo while the
44564
+ * focus ring, which is the part with a contrast requirement of its own, would
44565
+ * not.
44566
+ *
44567
+ * A style that also paints a focus pill keeps it: this adds an outline around
44568
+ * that pill rather than replacing it.
44569
+ */
44570
+ function navLinkFocusVisibleCss(selector, style, theme, tokens) {
44571
+ const color = tokens.getColor(style.colorToken);
44572
+ const halo = buildTextContrastShadow({
44573
+ theme,
44574
+ colorToken: style.colorToken,
44575
+ treatment: style.contrastTreatment
44576
+ });
44577
+ return `
44578
+ ${selector}:focus-visible {
44579
+ outline: 2px solid ${color};
44580
+ outline-offset: ${focusOutlineOffset(selector)};${halo ? `\n box-shadow: ${halo};` : ""}
44581
+ }
44582
+ `;
44583
+ }
44584
+ /**
44585
+ * Dropdown items are full-width inside a panel with no horizontal padding, so
44586
+ * an outset outline would paint over and past the panel's own border. Keeping
44587
+ * it flush is the only way it reads as belonging to the item.
44588
+ */
44589
+ function focusOutlineOffset(selector) {
44590
+ return selector.includes("nav-dropdown-link") ? "-2px" : "3px";
44591
+ }
44159
44592
  function buildTextContrastShadow(input) {
44160
44593
  if (input.treatment !== "soft-glow") return null;
44161
44594
  return isLikelyLightColorToken(input.theme, input.colorToken) ? "0 1px 3px rgb(0 0 0 / 0.55), 0 0 18px rgb(0 0 0 / 0.38)" : "0 1px 3px rgb(255 255 255 / 0.72), 0 0 18px rgb(255 255 255 / 0.5)";
@@ -47288,7 +47721,7 @@ function pageBlockPosition(index, blockCount) {
47288
47721
  //#endregion
47289
47722
  //#region ../blocks/src/pageRendererContracts.ts
47290
47723
  function buildPageRendererRootRuntime(dataContext) {
47291
- const { siteId = null, pageId = null, pathname = null, bookingTimeZone, previewStage = "published", apiBaseUrl = null, portalToken = null, bookingOfferingPresets = [], mailingList = { tag: "not_configured" }, eventRegistrationOverlayEnabled = false } = dataContext ?? {};
47724
+ const { siteId = null, pageId = null, pathname = null, bookingTimeZone, previewStage = "published", apiBaseUrl = null, portalToken = null, bookingOfferingPresets = [], appointmentServicePathPrefix = null, mailingList = { tag: "not_configured" }, eventRegistrationOverlayEnabled = false, loaderFailures = {} } = dataContext ?? {};
47292
47725
  return {
47293
47726
  siteId,
47294
47727
  pageId,
@@ -47298,8 +47731,10 @@ function buildPageRendererRootRuntime(dataContext) {
47298
47731
  apiBaseUrl,
47299
47732
  portalToken,
47300
47733
  bookingOfferingPresets,
47734
+ appointmentServicePathPrefix,
47301
47735
  mailingList,
47302
- eventRegistrationOverlayEnabled
47736
+ eventRegistrationOverlayEnabled,
47737
+ loaderFailures
47303
47738
  };
47304
47739
  }
47305
47740
  //#endregion
@@ -52013,7 +52448,8 @@ const appointmentServicesBlockDefinition = {
52013
52448
  el("appointment-services", {
52014
52449
  sectionHeading: { $bind: { from: "content.heading" } },
52015
52450
  services: { $bind: { from: "data.services" } },
52016
- pathname: { $bind: { from: "$root.pathname" } }
52451
+ pathname: { $bind: { from: "$root.pathname" } },
52452
+ servicePathPrefix: { $bind: { from: "$root.appointmentServicePathPrefix" } }
52017
52453
  })
52018
52454
  ], { gap: "lg" })
52019
52455
  })]
@@ -56543,7 +56979,7 @@ function collectNestedPreviewFieldConstraintEntries(field, path) {
56543
56979
  }
56544
56980
  function makeDefaultBlockComponent(args) {
56545
56981
  const { manifest } = args;
56546
- return function DefaultBlockComponent({ content, data, registry, theme, themeConfig, transforms, viewModelOverrides, pathBase, blockId, blockKind, blockBindings, editableRouteMetadataFieldIds, fragmentRegistry, imageResolveContext, previewAuthoring }) {
56982
+ return function DefaultBlockComponent({ content, data, registry, theme, themeConfig, transforms, viewModelOverrides, pathBase, blockId, contentVersionId, blockKind, blockBindings, editableRouteMetadataFieldIds, fragmentRegistry, imageResolveContext, previewAuthoring }) {
56547
56983
  const perf = beginBlockRenderMeasurement();
56548
56984
  if (!theme) throw new Error("Block rendering requires theme tokens; none were provided to makeDefaultBlockComponent");
56549
56985
  if (!registry) throw new Error("Block rendering requires a component registry; none was provided");
@@ -56563,6 +56999,7 @@ function makeDefaultBlockComponent(args) {
56563
56999
  theme: withButtonSystem(theme, themeConfig),
56564
57000
  pathBase,
56565
57001
  blockId,
57002
+ contentVersionId,
56566
57003
  blockKind,
56567
57004
  blockContent: mergedContent,
56568
57005
  blockBindings,
@@ -57271,6 +57708,7 @@ function buildBlockOverrideProps(input) {
57271
57708
  ...blockSubjectProps(dataContext),
57272
57709
  imageResolveContext: input.imageResolveContext,
57273
57710
  blockId: block.id ?? null,
57711
+ contentVersionId: block.contentVersionId ?? null,
57274
57712
  blockKind: block.kind
57275
57713
  };
57276
57714
  }
@@ -57371,6 +57809,7 @@ function toPresentationPage(page) {
57371
57809
  id: block.id,
57372
57810
  kind: block.kind,
57373
57811
  purpose: block.purpose,
57812
+ ...block.contentVersionId ? { contentVersionId: block.contentVersionId } : {},
57374
57813
  ...block.bindings ? { bindings: block.bindings } : {}
57375
57814
  };
57376
57815
  return block.admission.kind === "renderable" ? {
@@ -58638,10 +59077,19 @@ const containerResponsiveThemeCss = `/*
58638
59077
  padding-top: 2.5rem;
58639
59078
  padding-bottom: 2.5rem;
58640
59079
  }
59080
+ /* Clearance for a surface that is not an authored block page.
59081
+ An authored page gets this through its opening block's container (see the
59082
+ overlay-clearance rule in styles.css). A reserved surface or a system
59083
+ destination page has no such block, so it consumes the same variable here.
59084
+ Marked with one class rather than per-surface selectors, because the last
59085
+ two additions to this family were both missed and shipped overlapping. */
58641
59086
  :where(.theme-scope)
58642
59087
  [data-site-document-layout-mode="header-overlay"]
58643
- [data-rb-reserved-surface].rb-reserved-surface-main {
58644
- padding-top: calc(var(--rb-reserved-surface-header-offset, 5.5rem) + 2.5rem);
59088
+ .rb-overlay-clearance-surface {
59089
+ padding-top: calc(
59090
+ var(--site-overlay-header-clearance, 5.5rem) +
59091
+ var(--site-overlay-opening-content-extra-pad, clamp(1rem, 2vw, 1.75rem))
59092
+ );
58645
59093
  }
58646
59094
  .rb-preview-editor-offset {
58647
59095
  padding-bottom: calc(
@@ -67643,7 +68091,9 @@ const containerResponsiveThemeCss = `/*
67643
68091
  text-align: left;
67644
68092
  }
67645
68093
 
67646
- :where(.theme-scope) :where([data-block="customer-portal"]) .cp-login__subtitle {
68094
+ :where(.theme-scope)
68095
+ :where([data-block="customer-portal"])
68096
+ .cp-login__subtitle {
67647
68097
  color: var(--cp-muted);
67648
68098
  font-size: 0.9375rem;
67649
68099
  text-align: left;
@@ -67670,7 +68120,9 @@ const containerResponsiveThemeCss = `/*
67670
68120
  text-align: left;
67671
68121
  }
67672
68122
 
67673
- :where(.theme-scope) :where([data-block="customer-portal"]) .cp-login__reset-link {
68123
+ :where(.theme-scope)
68124
+ :where([data-block="customer-portal"])
68125
+ .cp-login__reset-link {
67674
68126
  appearance: none;
67675
68127
  background: none;
67676
68128
  border: 0;
@@ -67684,11 +68136,15 @@ const containerResponsiveThemeCss = `/*
67684
68136
  text-underline-offset: 0.15em;
67685
68137
  }
67686
68138
 
67687
- :where(.theme-scope) :where([data-block="customer-portal"]) .cp-login__reset-link:hover {
68139
+ :where(.theme-scope)
68140
+ :where([data-block="customer-portal"])
68141
+ .cp-login__reset-link:hover {
67688
68142
  color: var(--cp-text);
67689
68143
  }
67690
68144
 
67691
- :where(.theme-scope) :where([data-block="customer-portal"]) .cp-login__reset-link:focus-visible {
68145
+ :where(.theme-scope)
68146
+ :where([data-block="customer-portal"])
68147
+ .cp-login__reset-link:focus-visible {
67692
68148
  outline: 2px solid currentColor;
67693
68149
  outline-offset: 3px;
67694
68150
  }
@@ -67733,7 +68189,9 @@ const containerResponsiveThemeCss = `/*
67733
68189
  border-bottom: none;
67734
68190
  }
67735
68191
 
67736
- :where(.theme-scope) :where([data-block="customer-portal"]) .cp-header__welcome {
68192
+ :where(.theme-scope)
68193
+ :where([data-block="customer-portal"])
68194
+ .cp-header__welcome {
67737
68195
  font-size: 1.125rem;
67738
68196
  font-weight: 500;
67739
68197
  }
@@ -67749,8 +68207,14 @@ const containerResponsiveThemeCss = `/*
67749
68207
  }
67750
68208
 
67751
68209
  @keyframes cp-fade-in {
67752
- from { opacity: 0; transform: translateY(4px); }
67753
- to { opacity: 1; transform: translateY(0); }
68210
+ from {
68211
+ opacity: 0;
68212
+ transform: translateY(4px);
68213
+ }
68214
+ to {
68215
+ opacity: 1;
68216
+ transform: translateY(0);
68217
+ }
67754
68218
  }
67755
68219
 
67756
68220
  /* Empty state */
@@ -67839,6 +68303,77 @@ const containerResponsiveThemeCss = `/*
67839
68303
  margin-top: 1rem;
67840
68304
  }
67841
68305
 
68306
+ /* Event waitlists */
68307
+ :where(.theme-scope) :where([data-block="customer-portal"]) .cp-waitlist-list {
68308
+ display: grid;
68309
+ gap: 1rem;
68310
+ }
68311
+
68312
+ :where(.theme-scope)
68313
+ :where([data-block="customer-portal"])
68314
+ .cp-waitlists
68315
+ > .cp-alert {
68316
+ margin-bottom: 1rem;
68317
+ }
68318
+
68319
+ :where(.theme-scope) :where([data-block="customer-portal"]) .cp-waitlist-card {
68320
+ transition:
68321
+ border-color 180ms ease,
68322
+ box-shadow 180ms ease;
68323
+ }
68324
+
68325
+ :where(.theme-scope)
68326
+ :where([data-block="customer-portal"])
68327
+ .cp-waitlist-card--focused {
68328
+ border-color: var(--cp-primary);
68329
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--cp-primary) 22%, transparent);
68330
+ }
68331
+
68332
+ :where(.theme-scope)
68333
+ :where([data-block="customer-portal"])
68334
+ .cp-waitlist-card__summary,
68335
+ :where(.theme-scope)
68336
+ :where([data-block="customer-portal"])
68337
+ .cp-waitlist-card__position {
68338
+ font-weight: 600;
68339
+ }
68340
+
68341
+ :where(.theme-scope)
68342
+ :where([data-block="customer-portal"])
68343
+ .cp-waitlist-card
68344
+ .cp-card-body
68345
+ p {
68346
+ margin: 0.4rem 0;
68347
+ }
68348
+
68349
+ @container rb-site (max-width: 640px) {
68350
+ @scope ([data-rb-responsive-mode="container"]) to (:scope [data-rb-responsive-mode]) {
68351
+ :where(.theme-scope)
68352
+ :where([data-block="customer-portal"])
68353
+ .cp-waitlist-card
68354
+ .cp-card-header {
68355
+ flex-direction: column-reverse;
68356
+ }
68357
+
68358
+ :where(.theme-scope)
68359
+ :where([data-block="customer-portal"])
68360
+ .cp-waitlist-card
68361
+ .cp-card-actions {
68362
+ align-items: stretch;
68363
+ flex-direction: column;
68364
+ }
68365
+
68366
+ :where(.theme-scope)
68367
+ :where([data-block="customer-portal"])
68368
+ .cp-waitlist-card
68369
+ .cp-card-actions
68370
+ > * {
68371
+ justify-content: center;
68372
+ text-align: center;
68373
+ }
68374
+ }
68375
+ }
68376
+
67842
68377
  /* Badge */
67843
68378
  :where(.theme-scope) :where([data-block="customer-portal"]) .cp-badge {
67844
68379
  display: inline-flex;
@@ -67975,11 +68510,18 @@ const containerResponsiveThemeCss = `/*
67975
68510
  background: rgba(var(--tb-border), 0.2);
67976
68511
  }
67977
68512
 
67978
- :where(.theme-scope) :where([data-block="customer-portal"]) .cp-table tbody tr:last-child td {
68513
+ :where(.theme-scope)
68514
+ :where([data-block="customer-portal"])
68515
+ .cp-table
68516
+ tbody
68517
+ tr:last-child
68518
+ td {
67979
68519
  border-bottom: none;
67980
68520
  }
67981
68521
 
67982
- :where(.theme-scope) :where([data-block="customer-portal"]) :is(.cp-row--past, .cp-row--muted) {
68522
+ :where(.theme-scope)
68523
+ :where([data-block="customer-portal"])
68524
+ :is(.cp-row--past, .cp-row--muted) {
67983
68525
  opacity: 0.65;
67984
68526
  }
67985
68527
 
@@ -67992,7 +68534,9 @@ const containerResponsiveThemeCss = `/*
67992
68534
  line-height: 1.2;
67993
68535
  }
67994
68536
 
67995
- :where(.theme-scope) :where([data-block="customer-portal"]) .cp-row-title__badges {
68537
+ :where(.theme-scope)
68538
+ :where([data-block="customer-portal"])
68539
+ .cp-row-title__badges {
67996
68540
  margin-left: auto;
67997
68541
  display: flex;
67998
68542
  flex-wrap: wrap;
@@ -68000,7 +68544,9 @@ const containerResponsiveThemeCss = `/*
68000
68544
  gap: 0.375rem;
68001
68545
  }
68002
68546
 
68003
- :where(.theme-scope) :where([data-block="customer-portal"]) .cp-row-title__text {
68547
+ :where(.theme-scope)
68548
+ :where([data-block="customer-portal"])
68549
+ .cp-row-title__text {
68004
68550
  min-width: 0;
68005
68551
  }
68006
68552
 
@@ -68020,12 +68566,16 @@ const containerResponsiveThemeCss = `/*
68020
68566
  line-height: 1.35;
68021
68567
  }
68022
68568
 
68023
- :where(.theme-scope) :where([data-block="customer-portal"]) .cp-row-note--success {
68569
+ :where(.theme-scope)
68570
+ :where([data-block="customer-portal"])
68571
+ .cp-row-note--success {
68024
68572
  border-left-color: rgb(var(--tb-success));
68025
68573
  color: rgb(var(--tb-success));
68026
68574
  }
68027
68575
 
68028
- :where(.theme-scope) :where([data-block="customer-portal"]) .cp-row-note--error {
68576
+ :where(.theme-scope)
68577
+ :where([data-block="customer-portal"])
68578
+ .cp-row-note--error {
68029
68579
  border-left-color: rgb(var(--tb-destructive));
68030
68580
  color: rgb(var(--tb-destructive));
68031
68581
  }
@@ -68044,16 +68594,23 @@ const containerResponsiveThemeCss = `/*
68044
68594
  white-space: nowrap;
68045
68595
  }
68046
68596
 
68047
- :where(.theme-scope) :where([data-block="customer-portal"]) .cp-col-actions .btn-sm {
68597
+ :where(.theme-scope)
68598
+ :where([data-block="customer-portal"])
68599
+ .cp-col-actions
68600
+ .btn-sm {
68048
68601
  white-space: nowrap;
68049
68602
  }
68050
68603
 
68051
- :where(.theme-scope) :where([data-block="customer-portal"]) .cp-row-title__link {
68604
+ :where(.theme-scope)
68605
+ :where([data-block="customer-portal"])
68606
+ .cp-row-title__link {
68052
68607
  color: inherit;
68053
68608
  text-decoration: none;
68054
68609
  }
68055
68610
 
68056
- :where(.theme-scope) :where([data-block="customer-portal"]) .cp-row-title__link:hover {
68611
+ :where(.theme-scope)
68612
+ :where([data-block="customer-portal"])
68613
+ .cp-row-title__link:hover {
68057
68614
  text-decoration: underline;
68058
68615
  text-decoration-thickness: 2px;
68059
68616
  text-underline-offset: 2px;
@@ -68075,7 +68632,9 @@ const containerResponsiveThemeCss = `/*
68075
68632
  }
68076
68633
 
68077
68634
  /* Profile actions */
68078
- :where(.theme-scope) :where([data-block="customer-portal"]) .cp-profile__actions {
68635
+ :where(.theme-scope)
68636
+ :where([data-block="customer-portal"])
68637
+ .cp-profile__actions {
68079
68638
  display: flex;
68080
68639
  gap: 0.75rem;
68081
68640
  margin-top: 1rem;
@@ -68142,28 +68701,39 @@ const containerResponsiveThemeCss = `/*
68142
68701
  gap: 0.375rem;
68143
68702
  }
68144
68703
 
68145
- :where(.theme-scope) :where([data-block="customer-portal"]) .cp-guest-edit-row__index {
68704
+ :where(.theme-scope)
68705
+ :where([data-block="customer-portal"])
68706
+ .cp-guest-edit-row__index {
68146
68707
  font-size: 0.75rem;
68147
68708
  font-weight: 500;
68148
68709
  color: var(--cp-muted);
68149
68710
  }
68150
68711
 
68151
- :where(.theme-scope) :where([data-block="customer-portal"]) .cp-guest-edit-row__fields {
68712
+ :where(.theme-scope)
68713
+ :where([data-block="customer-portal"])
68714
+ .cp-guest-edit-row__fields {
68152
68715
  display: flex;
68153
68716
  gap: 0.5rem;
68154
68717
  }
68155
68718
 
68156
- :where(.theme-scope) :where([data-block="customer-portal"]) .cp-guest-edit-row__fields input {
68719
+ :where(.theme-scope)
68720
+ :where([data-block="customer-portal"])
68721
+ .cp-guest-edit-row__fields
68722
+ input {
68157
68723
  flex: 1;
68158
68724
  min-width: 0;
68159
68725
  }
68160
68726
 
68161
- :where(.theme-scope) :where([data-block="customer-portal"]) .cp-guest-edit-row__error {
68727
+ :where(.theme-scope)
68728
+ :where([data-block="customer-portal"])
68729
+ .cp-guest-edit-row__error {
68162
68730
  font-size: 0.75rem;
68163
68731
  color: var(--cp-error);
68164
68732
  }
68165
68733
 
68166
- :where(.theme-scope) :where([data-block="customer-portal"]) .cp-guests__actions {
68734
+ :where(.theme-scope)
68735
+ :where([data-block="customer-portal"])
68736
+ .cp-guests__actions {
68167
68737
  display: flex;
68168
68738
  gap: 0.5rem;
68169
68739
  margin-top: 0.5rem;
@@ -68177,13 +68747,18 @@ const containerResponsiveThemeCss = `/*
68177
68747
  }
68178
68748
 
68179
68749
  /* In the actions modal, tiles sit on a surface modal, so use "background" for contrast. */
68180
- :where(.theme-scope) :where([data-block="customer-portal"]) .cp-actions-list :where(.rb-tile) {
68750
+ :where(.theme-scope)
68751
+ :where([data-block="customer-portal"])
68752
+ .cp-actions-list
68753
+ :where(.rb-tile) {
68181
68754
  --rb-event-tile-bg: rgb(var(--tb-background));
68182
68755
  --rb-event-tile-border: rgb(var(--tb-border));
68183
68756
  }
68184
68757
 
68185
68758
  /* Actions trigger: icon-only kebab button */
68186
- :where(.theme-scope) :where([data-block="customer-portal"]) .cp-actions-trigger.btn-sm {
68759
+ :where(.theme-scope)
68760
+ :where([data-block="customer-portal"])
68761
+ .cp-actions-trigger.btn-sm {
68187
68762
  padding: 0.35rem !important;
68188
68763
  line-height: 1 !important;
68189
68764
  min-width: 32px;
@@ -68207,17 +68782,24 @@ const containerResponsiveThemeCss = `/*
68207
68782
  gap: 0.25rem;
68208
68783
  }
68209
68784
 
68210
- :where(.theme-scope) :where([data-block="customer-portal"]) .cp-action-tile__title {
68785
+ :where(.theme-scope)
68786
+ :where([data-block="customer-portal"])
68787
+ .cp-action-tile__title {
68211
68788
  font-weight: 600;
68212
68789
  font-size: 0.9375rem;
68213
68790
  }
68214
68791
 
68215
- :where(.theme-scope) :where([data-block="customer-portal"]) .cp-action-tile__desc {
68792
+ :where(.theme-scope)
68793
+ :where([data-block="customer-portal"])
68794
+ .cp-action-tile__desc {
68216
68795
  font-size: 0.875rem;
68217
68796
  line-height: 1.35;
68218
68797
  }
68219
68798
 
68220
- :where(.theme-scope) :where([data-block="customer-portal"]) .cp-action-tile--danger .cp-action-tile__title {
68799
+ :where(.theme-scope)
68800
+ :where([data-block="customer-portal"])
68801
+ .cp-action-tile--danger
68802
+ .cp-action-tile__title {
68221
68803
  color: rgb(var(--tb-destructive));
68222
68804
  }
68223
68805
 
@@ -68239,7 +68821,9 @@ const containerResponsiveThemeCss = `/*
68239
68821
  text-decoration: underline;
68240
68822
  }
68241
68823
 
68242
- :where(.theme-scope) :where([data-block="customer-portal"]) .cp-btn--link:hover {
68824
+ :where(.theme-scope)
68825
+ :where([data-block="customer-portal"])
68826
+ .cp-btn--link:hover {
68243
68827
  color: var(--cp-primary-hover);
68244
68828
  }
68245
68829
 
@@ -68278,34 +68862,48 @@ const containerResponsiveThemeCss = `/*
68278
68862
  margin-top: 0.75rem;
68279
68863
  }
68280
68864
 
68281
- :where(.theme-scope) :where([data-block="customer-portal"]) .cp-cancel-confirm__title {
68865
+ :where(.theme-scope)
68866
+ :where([data-block="customer-portal"])
68867
+ .cp-cancel-confirm__title {
68282
68868
  font-weight: 600;
68283
68869
  margin-bottom: 0.5rem;
68284
68870
  }
68285
68871
 
68286
- :where(.theme-scope) :where([data-block="customer-portal"]) .cp-cancel-confirm__message {
68872
+ :where(.theme-scope)
68873
+ :where([data-block="customer-portal"])
68874
+ .cp-cancel-confirm__message {
68287
68875
  margin-bottom: 0.25rem;
68288
68876
  }
68289
68877
 
68290
- :where(.theme-scope) :where([data-block="customer-portal"]) .cp-cancel-confirm__warning {
68878
+ :where(.theme-scope)
68879
+ :where([data-block="customer-portal"])
68880
+ .cp-cancel-confirm__warning {
68291
68881
  margin-bottom: 0.75rem;
68292
68882
  }
68293
68883
 
68294
- :where(.theme-scope) :where([data-block="customer-portal"]) .cp-cancel-confirm__actions {
68884
+ :where(.theme-scope)
68885
+ :where([data-block="customer-portal"])
68886
+ .cp-cancel-confirm__actions {
68295
68887
  display: flex;
68296
68888
  gap: 0.75rem;
68297
68889
  }
68298
68890
 
68299
68891
  /* Membership actions */
68300
- :where(.theme-scope) :where([data-block="customer-portal"]) .cp-membership-actions {
68892
+ :where(.theme-scope)
68893
+ :where([data-block="customer-portal"])
68894
+ .cp-membership-actions {
68301
68895
  margin-top: 0.75rem;
68302
68896
  }
68303
68897
 
68304
- :where(.theme-scope) :where([data-block="customer-portal"]) .cp-section-actions {
68898
+ :where(.theme-scope)
68899
+ :where([data-block="customer-portal"])
68900
+ .cp-section-actions {
68305
68901
  margin-top: 1rem;
68306
68902
  }
68307
68903
 
68308
- :where(.theme-scope) :where([data-block="customer-portal"]) .cp-card-subtitle--spaced {
68904
+ :where(.theme-scope)
68905
+ :where([data-block="customer-portal"])
68906
+ .cp-card-subtitle--spaced {
68309
68907
  margin-top: 0.75rem;
68310
68908
  }
68311
68909
 
@@ -68329,9 +68927,18 @@ const containerResponsiveThemeCss = `/*
68329
68927
  display: none;
68330
68928
  }
68331
68929
 
68332
- :where(.theme-scope) :where([data-block="customer-portal"]) .cp-table :is(th, td).cp-col-guests,
68333
- :where(.theme-scope) :where([data-block="customer-portal"]) .cp-table :is(th, td).cp-col-tickets,
68334
- :where(.theme-scope) :where([data-block="customer-portal"]) .cp-table :is(th, td).cp-col-actions {
68930
+ :where(.theme-scope)
68931
+ :where([data-block="customer-portal"])
68932
+ .cp-table
68933
+ :is(th, td).cp-col-guests,
68934
+ :where(.theme-scope)
68935
+ :where([data-block="customer-portal"])
68936
+ .cp-table
68937
+ :is(th, td).cp-col-tickets,
68938
+ :where(.theme-scope)
68939
+ :where([data-block="customer-portal"])
68940
+ .cp-table
68941
+ :is(th, td).cp-col-actions {
68335
68942
  display: none;
68336
68943
  }
68337
68944
 
@@ -68340,24 +68947,34 @@ const containerResponsiveThemeCss = `/*
68340
68947
  }
68341
68948
 
68342
68949
  /* Make the cell a positioning context for the kebab */
68343
- :where(.theme-scope) :where([data-block="customer-portal"]) .cp-row > td:first-child {
68950
+ :where(.theme-scope)
68951
+ :where([data-block="customer-portal"])
68952
+ .cp-row
68953
+ > td:first-child {
68344
68954
  position: relative;
68345
68955
  padding-right: 2.5rem;
68346
68956
  }
68347
68957
 
68348
68958
  /* Position kebab in top-right of the cell */
68349
- :where(.theme-scope) :where([data-block="customer-portal"]) .cp-row-mobile-actions {
68959
+ :where(.theme-scope)
68960
+ :where([data-block="customer-portal"])
68961
+ .cp-row-mobile-actions {
68350
68962
  position: absolute;
68351
68963
  top: 0.5rem;
68352
68964
  right: 0.5rem;
68353
68965
  margin-top: 0;
68354
68966
  }
68355
68967
 
68356
- :where(.theme-scope) :where([data-block="customer-portal"]) .cp-row-mobile-actions .btn-sm {
68968
+ :where(.theme-scope)
68969
+ :where([data-block="customer-portal"])
68970
+ .cp-row-mobile-actions
68971
+ .btn-sm {
68357
68972
  width: auto;
68358
68973
  }
68359
68974
 
68360
- :where(.theme-scope) :where([data-block="customer-portal"]) .cp-profile__edit {
68975
+ :where(.theme-scope)
68976
+ :where([data-block="customer-portal"])
68977
+ .cp-profile__edit {
68361
68978
  align-self: stretch;
68362
68979
  }
68363
68980
  }
@@ -68805,6 +69422,47 @@ const containerResponsiveThemeCss = `/*
68805
69422
  gap: 0.25rem;
68806
69423
  }
68807
69424
 
69425
+ /* Topic choices (visitor picks what to hear about). Same treatment as the
69426
+ form block's .fb-fieldset / .fb-inline, defined here because the newsletter
69427
+ form also renders inside contact-newsletter and the site footer. */
69428
+ :where(.theme-scope) .newsletter-topics {
69429
+ display: flex;
69430
+ flex-direction: column;
69431
+ gap: 0.5rem;
69432
+ border: none;
69433
+ padding: 0;
69434
+ margin: 0;
69435
+ min-width: 0;
69436
+ }
69437
+
69438
+ :where(.theme-scope) .newsletter-topics > legend {
69439
+ padding: 0;
69440
+ margin-bottom: 0.25rem;
69441
+ }
69442
+
69443
+ :where(.theme-scope) .newsletter-topic-choice {
69444
+ display: flex;
69445
+ align-items: center;
69446
+ gap: 0.5rem;
69447
+ }
69448
+
69449
+ /* Error panel and field notes. The form block scopes these to its own
69450
+ data-block, so the newsletter form (which also renders in the footer)
69451
+ needs its own copy of the treatment. */
69452
+ :where(.theme-scope) .newsletter-form .fb-error:not([data-field-validation-message]) {
69453
+ background-color: var(--fb-error-bg);
69454
+ color: var(--fb-error-text);
69455
+ border: 1px solid var(--fb-error-border);
69456
+ border-radius: var(--rb-block-radius);
69457
+ padding: 1rem;
69458
+ font-size: 0.875rem;
69459
+ }
69460
+
69461
+ :where(.theme-scope) .newsletter-form [data-field-validation-message] {
69462
+ font-size: 0.875rem;
69463
+ color: var(--fb-error-text);
69464
+ }
69465
+
68808
69466
  /* Required indicator */
68809
69467
  :where(.theme-scope) .newsletter-required {
68810
69468
  color: rgb(var(--tb-primary));
@@ -68854,6 +69512,10 @@ const containerResponsiveThemeCss = `/*
68854
69512
  flex-shrink: 0;
68855
69513
  }
68856
69514
 
69515
+ :where(.theme-scope) .newsletter-inline .newsletter-topics {
69516
+ flex-basis: 100%;
69517
+ }
69518
+
68857
69519
  /* Mobile fallback for inline variant */
68858
69520
  @container rb-site (max-width: 640px) {
68859
69521
  @scope ([data-rb-responsive-mode="container"]) to (:scope [data-rb-responsive-mode]) {
@@ -71134,6 +71796,15 @@ z.object({
71134
71796
  }).optional(),
71135
71797
  overrides: z.record(z.string(), z.string()).optional()
71136
71798
  }).passthrough();
71799
+ z.object({
71800
+ palette: paletteColorsSchema,
71801
+ paletteMode: paletteModeSchema,
71802
+ typography: z.object({
71803
+ headingFamily: z.string().trim().min(1),
71804
+ bodyFamily: z.string().trim().min(1)
71805
+ }).strict(),
71806
+ corners
71807
+ }).strict();
71137
71808
  //#endregion
71138
71809
  //#region src/rendering/blocks-theme-runtime.ts
71139
71810
  function parseBlocksTheme(theme) {
@@ -71312,7 +71983,7 @@ function PageContent(props) {
71312
71983
  previewToken,
71313
71984
  resolvedData,
71314
71985
  bookingOfferingPresets: bookingOfferingPresets ?? [],
71315
- mailingList,
71986
+ mailingList: mailingList ?? dataContext?.mailingList,
71316
71987
  bookingTimeZone: resolveSdkBookingTimeZone(bookingTimeZone),
71317
71988
  routes: routeMap,
71318
71989
  pagesByIdentifier,
@@ -71973,12 +72644,12 @@ function normalizeContent(block) {
71973
72644
  }
71974
72645
  /**
71975
72646
  * Normalize params for API calls.
71976
- * Converts all values to strings.
72647
+ * Converts supplied values to strings, preserving absent versus explicitly empty params.
71977
72648
  */
71978
72649
  function normalizeParams(input) {
71979
72650
  if (!input || typeof input !== "object") return {};
71980
72651
  const output = {};
71981
- for (const [key, value] of Object.entries(input)) output[key] = coerceToString(value);
72652
+ for (const [key, value] of Object.entries(input)) if (value !== void 0 && value !== null) output[key] = coerceToString(value);
71982
72653
  return output;
71983
72654
  }
71984
72655
  function isNonArrayObject(value) {
@@ -72042,6 +72713,14 @@ function coercePayload(payload) {
72042
72713
  * - Frontend: provide internal API client
72043
72714
  * - SDK: provide SDK client with endpoint mapping
72044
72715
  */
72716
+ function projectDataLoaders(loaders, shouldLoad, blockId, blockKind) {
72717
+ if (!shouldLoad) return [...loaders];
72718
+ return loaders.filter(({ key }) => shouldLoad({
72719
+ blockId,
72720
+ blockKind,
72721
+ loaderKey: key
72722
+ }));
72723
+ }
72045
72724
  function shouldSkipResolvedLoader(input) {
72046
72725
  if (input.loader.requiredParams?.some((param) => !input.params[param]?.trim())) return true;
72047
72726
  return Boolean(input.isValidEndpoint && !input.isValidEndpoint(input.endpoint));
@@ -72067,8 +72746,12 @@ function shouldSkipResolvedLoader(input) {
72067
72746
  * ```
72068
72747
  */
72069
72748
  async function prefetchBlockData$1(page, context, options) {
72070
- const { apiClient, isValidEndpoint, onError, getCustomBlockLoaders, getBlockDefinition: getBlockDefinition$1 = getBlockDefinition, resolveParamsBindings: resolveParamsBindings$1 = resolveParamsBindings } = options;
72749
+ return (await prefetchBlockDataWithFailures(page, context, options)).resolvedData;
72750
+ }
72751
+ async function prefetchBlockDataWithFailures(page, context, options) {
72752
+ const { apiClient, isValidEndpoint, onError, getCustomBlockLoaders, getBlockDefinition: getBlockDefinition$1 = getBlockDefinition, resolveParamsBindings: resolveParamsBindings$1 = resolveParamsBindings, shouldLoad } = options;
72071
72753
  const results = {};
72754
+ const loaderFailures = {};
72072
72755
  const tasks = [];
72073
72756
  for (const block of page.blocks) {
72074
72757
  const blockId = block.id;
@@ -72083,6 +72766,7 @@ async function prefetchBlockData$1(page, context, options) {
72083
72766
  loader
72084
72767
  })) : [];
72085
72768
  } else loaders = [];
72769
+ loaders = projectDataLoaders(loaders, shouldLoad, blockId, block.kind);
72086
72770
  if (loaders.length === 0) continue;
72087
72771
  const root = {
72088
72772
  ...context.root ?? {},
@@ -72116,6 +72800,11 @@ async function prefetchBlockData$1(page, context, options) {
72116
72800
  const blockResults = results[blockId] ?? (results[blockId] = {});
72117
72801
  blockResults[key] = data;
72118
72802
  } catch (error) {
72803
+ const blockFailures = loaderFailures[blockId] ?? (loaderFailures[blockId] = {});
72804
+ blockFailures[key] = {
72805
+ endpoint,
72806
+ params
72807
+ };
72119
72808
  if (onError) onError(error, {
72120
72809
  block: block.kind,
72121
72810
  loader: key
@@ -72125,7 +72814,10 @@ async function prefetchBlockData$1(page, context, options) {
72125
72814
  }
72126
72815
  }
72127
72816
  if (tasks.length > 0) await Promise.all(tasks);
72128
- return results;
72817
+ return {
72818
+ resolvedData: results,
72819
+ loaderFailures
72820
+ };
72129
72821
  }
72130
72822
  //#endregion
72131
72823
  //#region ../blocks/src/system/data/loaderEndpoints.ts
@@ -72153,8 +72845,8 @@ function toStringParams(value) {
72153
72845
  for (const [k, v] of Object.entries(value)) if (typeof v === "string") out[k] = v;
72154
72846
  return out;
72155
72847
  }
72156
- function stripEmptyStringValues(params) {
72157
- for (const [key, value] of Object.entries(params)) if (value === "") delete params[key];
72848
+ function stripEmptyStringValues(params, endpoint) {
72849
+ for (const [key, value] of Object.entries(params)) if (value === "" && !(key === "seriesIds" && (endpoint === "listPublicEvents" || endpoint === "listPublicEventCalendarWindow"))) delete params[key];
72158
72850
  }
72159
72851
  function ensureSiteId(params, context) {
72160
72852
  if (!params.siteId && typeof context.siteId === "string" && context.siteId) params.siteId = context.siteId;
@@ -72167,7 +72859,7 @@ function ensureSiteId(params, context) {
72167
72859
  */
72168
72860
  function normalizeLoaderParams(endpoint, params, context) {
72169
72861
  const out = toStringParams(params);
72170
- stripEmptyStringValues(out);
72862
+ stripEmptyStringValues(out, endpoint);
72171
72863
  if (endpoint === "getPublicFormById") {
72172
72864
  ensureSiteId(out, context);
72173
72865
  if (!out.formId && out.formSlug) {
@@ -72233,9 +72925,11 @@ function convertPageResponseBlock(block) {
72233
72925
  if (typeof block.id !== "string" && block.id !== null) throw new Error(`Invalid block id in page: expected string or null, got ${typeof block.id}`);
72234
72926
  if (typeof block.kind !== "string") throw new Error(`Invalid block kind in page: expected string, got ${typeof block.kind}`);
72235
72927
  if (typeof block.purpose !== "string") throw new Error(`Invalid block purpose in page: expected string, got ${typeof block.purpose}`);
72928
+ if (block.contentVersionId !== void 0 && block.contentVersionId !== null && typeof block.contentVersionId !== "string") throw new Error(`Invalid content version id in page: expected string or null, got ${typeof block.contentVersionId}`);
72236
72929
  const admission = readInvalidBlockAdmission(block.admission);
72237
72930
  return {
72238
72931
  id: block.id,
72932
+ ...block.contentVersionId !== void 0 ? { contentVersionId: block.contentVersionId } : {},
72239
72933
  kind: block.kind,
72240
72934
  purpose: block.purpose,
72241
72935
  content: sanitizeSdkRuntimeBlockContent(block.kind, readContentRecord(block.content) ?? {}),
@@ -72266,6 +72960,7 @@ function buildRenderablePageOutline(input) {
72266
72960
  function admitSdkRuntimePageBlock(block, customBlocks) {
72267
72961
  const base = {
72268
72962
  id: block.id,
72963
+ ...block.contentVersionId !== void 0 ? { contentVersionId: block.contentVersionId } : {},
72269
72964
  kind: block.kind,
72270
72965
  purpose: block.purpose,
72271
72966
  ...block.bindings ? { bindings: block.bindings } : {}
@@ -73944,6 +74639,14 @@ const PUBLIC_BOOKING_AVAILABILITY_ENDPOINT_DEFINITIONS = defineEndpointDefinitio
73944
74639
  auth: "public",
73945
74640
  responseKind: "json"
73946
74641
  },
74642
+ getPublicBookingServiceBySlug: {
74643
+ path: "/public/bookings/services/by-slug/{slug}",
74644
+ method: "GET",
74645
+ revalidate: publicReadFreshnessSeconds("getPublicBookingService"),
74646
+ tags: [TAG_TEMPLATES.publicBookingServices],
74647
+ auth: "public",
74648
+ responseKind: "json"
74649
+ },
73947
74650
  getPublicBookingResourcesReference: {
73948
74651
  path: "/public/bookings/resources/reference",
73949
74652
  method: "GET",
@@ -74496,16 +75199,110 @@ const PUBLIC_READ_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
74496
75199
  responseKind: "json"
74497
75200
  }
74498
75201
  });
75202
+ //#endregion
75203
+ //#region ../api/src/publicOnboardingAttemptEndpointDefinitions.ts
75204
+ /**
75205
+ * The anonymous onboarding attempt, addressed by its opaque resume token.
75206
+ *
75207
+ * Every route here is reached before there is an account, so none of them can
75208
+ * be scoped to a site or a user: the token is the whole credential. They are
75209
+ * kept together so that stays obvious.
75210
+ */
75211
+ const PUBLIC_ONBOARDING_ATTEMPT_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
75212
+ createPublicOnboardingAttempt: {
75213
+ path: "/public/onboarding/attempts",
75214
+ method: "POST",
75215
+ auth: "public",
75216
+ errors: [],
75217
+ responseKind: "json"
75218
+ },
75219
+ createPublicOnboardingLogoUploadUrl: {
75220
+ path: "/public/onboarding/attempts/{attemptToken}/logo-upload-url",
75221
+ method: "POST",
75222
+ auth: "public",
75223
+ errors: [],
75224
+ responseKind: "json"
75225
+ },
75226
+ uploadPublicOnboardingLogo: {
75227
+ path: "/public/onboarding/attempts/{attemptToken}/logo",
75228
+ method: "POST",
75229
+ auth: "public",
75230
+ errors: [],
75231
+ responseKind: "json"
75232
+ },
75233
+ getPublicOnboardingAttempt: {
75234
+ path: "/public/onboarding/attempts/{attemptToken}",
75235
+ method: "GET",
75236
+ auth: "public",
75237
+ errors: [],
75238
+ responseKind: "json"
75239
+ },
75240
+ getPublicOnboardingAttemptProgress: {
75241
+ path: "/public/onboarding/attempts/{attemptToken}/status",
75242
+ method: "GET",
75243
+ auth: "public",
75244
+ errors: [],
75245
+ responseKind: "json"
75246
+ },
75247
+ updatePublicOnboardingAttempt: {
75248
+ path: "/public/onboarding/attempts/{attemptToken}",
75249
+ method: "PATCH",
75250
+ auth: "public",
75251
+ errors: [],
75252
+ responseKind: "json"
75253
+ },
75254
+ runPublicOnboardingAttempt: {
75255
+ path: "/public/onboarding/attempts/{attemptToken}/run",
75256
+ method: "POST",
75257
+ auth: "public",
75258
+ errors: [],
75259
+ responseKind: "json"
75260
+ },
75261
+ resendPublicOnboardingAttemptConfirmation: {
75262
+ path: "/public/onboarding/attempts/{attemptToken}/resend-confirmation",
75263
+ method: "POST",
75264
+ auth: "public",
75265
+ errors: [],
75266
+ responseKind: "json"
75267
+ }
75268
+ });
75269
+ //#endregion
75270
+ //#region ../api/src/billingEndpointDefinitions.ts
75271
+ const BILLING_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
75272
+ adminChangePlan: {
75273
+ path: "/admin/billing/plan",
75274
+ method: "POST",
75275
+ tags: ["admin", "billing"],
75276
+ auth: "admin",
75277
+ responseKind: "json"
75278
+ },
75279
+ changePlan: {
75280
+ path: "/billing/plan/change",
75281
+ method: "POST",
75282
+ tags: ["billing"],
75283
+ auth: "user",
75284
+ responseKind: "json"
75285
+ },
75286
+ createBillingPortalSession: {
75287
+ path: "/billing/portal/session",
75288
+ method: "POST",
75289
+ tags: ["billing"],
75290
+ auth: "user",
75291
+ responseKind: "json"
75292
+ }
75293
+ });
74499
75294
  ({
74500
75295
  ...ACCOUNT_ENDPOINT_DEFINITIONS,
75296
+ ...PUBLIC_ONBOARDING_ATTEMPT_ENDPOINT_DEFINITIONS,
74501
75297
  ...PUBLIC_EVENT_ENDPOINT_DEFINITIONS,
74502
75298
  ...GIFTING_ENDPOINT_DEFINITIONS,
74503
- ...PUBLIC_READ_ENDPOINT_DEFINITIONS
75299
+ ...PUBLIC_READ_ENDPOINT_DEFINITIONS,
75300
+ ...BILLING_ENDPOINT_DEFINITIONS
74504
75301
  }), TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteTheme, TAG_TEMPLATES.siteCollection, { ...SITE_API_KEY_ENDPOINT_DEFINITIONS }, TAG_TEMPLATES.site, TAG_TEMPLATES.siteBookingSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteBookingSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteEmailSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteEmailSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteEmailSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteEmailSettings, {
74505
75302
  ...NEWSLETTER_ENDPOINT_DEFINITIONS,
74506
75303
  ...APPOINTMENT_ENDPOINT_DEFINITIONS,
74507
75304
  ...EVENT_SERIES_REGISTRATION_ENDPOINT_DEFINITIONS
74508
- }, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteById, TAG_TEMPLATES.siteBySlug, TAG_TEMPLATES.siteByDomain, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteById, TAG_TEMPLATES.siteBySlug, TAG_TEMPLATES.siteByDomain, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.workflowRunById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.routeById, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.site, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.navigationMenuById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.navigationMenuById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.navigationMenuById, TAG_TEMPLATES.navigationItemById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.navigationMenuById, TAG_TEMPLATES.navigationItemById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.navigationMenuById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteTheme, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteTheme, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteTheme, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteRedirects, TAG_TEMPLATES.siteRouteOutcomes, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteRedirects, TAG_TEMPLATES.siteRouteOutcomes, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.formSubmissionsBySlug, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.formSubmissionsBySlug, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.formSubmissionsBySlug, TAG_TEMPLATES.siteForms, { ...PUBLIC_BOOKING_AVAILABILITY_ENDPOINT_DEFINITIONS }, TAG_TEMPLATES.publicEventFilters, TAG_TEMPLATES.publicEvents, TAG_TEMPLATES.publicShop, TAG_TEMPLATES.publicCheckout, TAG_TEMPLATES.siteRoutableContent, { ...PUBLIC_EVENT_CHECKOUT_ENDPOINT_DEFINITIONS }, TAG_TEMPLATES.publicEvents, TAG_TEMPLATES.publicEvents, { ...EVENT_MANAGEMENT_ENDPOINT_DEFINITIONS }, { ...SDK_MEDIA_ENDPOINT_DEFINITIONS }, { ...SDK_ENDPOINT_DEFINITIONS }, { ...SDK_ENTRY_READ_ENDPOINTS };
75305
+ }, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteById, TAG_TEMPLATES.siteBySlug, TAG_TEMPLATES.siteByDomain, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteById, TAG_TEMPLATES.siteBySlug, TAG_TEMPLATES.siteByDomain, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.workflowRunById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.routeById, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.site, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.navigationMenuById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.navigationMenuById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.navigationMenuById, TAG_TEMPLATES.navigationItemById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.navigationMenuById, TAG_TEMPLATES.navigationItemById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.navigationMenuById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.publicEvents, TAG_TEMPLATES.publicBookingServices, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteTheme, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteTheme, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteTheme, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteRedirects, TAG_TEMPLATES.siteRouteOutcomes, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteRedirects, TAG_TEMPLATES.siteRouteOutcomes, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.formSubmissionsBySlug, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.formSubmissionsBySlug, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.formSubmissionsBySlug, TAG_TEMPLATES.siteForms, { ...PUBLIC_BOOKING_AVAILABILITY_ENDPOINT_DEFINITIONS }, TAG_TEMPLATES.publicEventFilters, TAG_TEMPLATES.publicEvents, TAG_TEMPLATES.publicShop, TAG_TEMPLATES.publicCheckout, TAG_TEMPLATES.siteRoutableContent, { ...PUBLIC_EVENT_CHECKOUT_ENDPOINT_DEFINITIONS }, TAG_TEMPLATES.publicEvents, TAG_TEMPLATES.publicEvents, { ...EVENT_MANAGEMENT_ENDPOINT_DEFINITIONS }, { ...SDK_MEDIA_ENDPOINT_DEFINITIONS }, { ...SDK_ENDPOINT_DEFINITIONS }, { ...SDK_ENTRY_READ_ENDPOINTS };
74509
75306
  z.object({ refreshToken: z.string().min(1).max(4096) }).strict();
74510
75307
  z.object({
74511
75308
  accessToken: z.string().min(1).max(4096),
@@ -74933,7 +75730,17 @@ const riverbankSiteConfigInputSchema = z.object({
74933
75730
  z.object({
74934
75731
  config: riverbankSiteConfigInputSchema,
74935
75732
  forceContentTypes: z.boolean().optional(),
74936
- mode: z.enum(["apply", "preview"]).optional()
75733
+ mode: z.enum(["apply", "preview"]).optional(),
75734
+ expectedMailingListProviderScope: z.unknown().transform((value, ctx) => {
75735
+ if (value === void 0) return void 0;
75736
+ const parsed = parseMailingListProviderScope(value);
75737
+ if (parsed.ok) return parsed.value;
75738
+ ctx.addIssue({
75739
+ code: "custom",
75740
+ message: "Invalid mailing-list provider scope"
75741
+ });
75742
+ return z.NEVER;
75743
+ }).optional()
74937
75744
  }).strict();
74938
75745
  //#endregion
74939
75746
  //#region ../api/src/sdkThemeWire.ts