@riverbankcms/sdk 0.146.0 → 0.147.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 (195) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/{PreviewEditorSidebar-kg2r2Fyi.mjs → PreviewEditorSidebar-DtpB3_sS.mjs} +51 -33
  3. package/dist/{PreviewEditorUI-sWMLp5dT.mjs → PreviewEditorUI-DxTLgaHo.mjs} +3 -3
  4. package/dist/{PreviewQueryProvider-Cg51xq1w.mjs → PreviewQueryProvider-Dd4dxOiU.mjs} +1 -1
  5. package/dist/{SdkPreviewModeRuntime-h2ti3Hch.mjs → SdkPreviewModeRuntime-DMMNCngt.mjs} +39 -12
  6. package/dist/{SiteChromeCustomizeContext-DEACFH9m.mjs → SiteChromeCustomizeContext-DQXZXiqS.mjs} +2499 -1682
  7. package/dist/_dts/ai/src/contracts/proposals.d.ts +198 -0
  8. package/dist/_dts/ai/src/contracts/siteStyleProposalSchemas.d.ts +18 -0
  9. package/dist/_dts/api/src/accountApi.d.ts +5 -5
  10. package/dist/_dts/api/src/bookingConfig.d.ts +16 -0
  11. package/dist/_dts/api/src/bookingManagementEndpoints.d.ts +4 -13
  12. package/dist/_dts/api/src/bookingOperations.d.ts +2 -44
  13. package/dist/_dts/api/src/bookingPeople.d.ts +92 -0
  14. package/dist/_dts/api/src/bookingPeopleEndpointDefinitions.d.ts +38 -0
  15. package/dist/_dts/api/src/bookingRecords.d.ts +11 -49
  16. package/dist/_dts/api/src/bookingSettingsSections.d.ts +1 -1
  17. package/dist/_dts/api/src/bookings.d.ts +1 -0
  18. package/dist/_dts/api/src/endpoints.d.ts +587 -561
  19. package/dist/_dts/api/src/eventManagementContracts.d.ts +23 -8
  20. package/dist/_dts/api/src/eventManagementEndpointDefinitions.d.ts +1 -1
  21. package/dist/_dts/api/src/index.d.ts +3 -2
  22. package/dist/_dts/api/src/indexCoreTypes.d.ts +1 -1
  23. package/dist/_dts/api/src/launchReadiness.d.ts +1 -6
  24. package/dist/_dts/api/src/mailingListIntegration.d.ts +6 -0
  25. package/dist/_dts/api/src/navigation/dashboardBookingsNav.d.ts +1 -1
  26. package/dist/_dts/api/src/newsletterEndpointDefinitions.d.ts +15 -0
  27. package/dist/_dts/api/src/occurrenceScheduling.d.ts +19 -0
  28. package/dist/_dts/api/src/publicAppointmentBookingContracts.d.ts +48 -0
  29. package/dist/_dts/api/src/publicExperience/eventEndpoints.d.ts +7 -0
  30. package/dist/_dts/api/src/sdk-event-upsert.d.ts +15 -0
  31. package/dist/_dts/api/src/sdkCourseBooking.d.ts +4 -4
  32. package/dist/_dts/api/src/siteLifecycleEndpoints.d.ts +61 -0
  33. package/dist/_dts/api/src/siteManagementEndpoints.d.ts +5 -18
  34. package/dist/_dts/api/src/siteOnboarding.d.ts +2 -14
  35. package/dist/_dts/blocks/src/PageRenderer.d.ts +3 -4
  36. package/dist/_dts/blocks/src/contracts/proof-block-islands.d.ts +8 -0
  37. package/dist/_dts/blocks/src/index.d.ts +1 -1
  38. package/dist/_dts/blocks/src/pageRenderAdmission.d.ts +22 -4
  39. package/dist/_dts/blocks/src/pageRendererContracts.d.ts +2 -0
  40. package/dist/_dts/blocks/src/system/blocks/newsletter-signup.d.ts +4 -1
  41. package/dist/_dts/blocks/src/system/runtime/api/types/appointments.d.ts +4 -0
  42. package/dist/_dts/blocks/src/system/runtime/api/types/events.d.ts +12 -0
  43. package/dist/_dts/blocks/src/system/runtime/components/registry.client.d.ts +12 -0
  44. package/dist/_dts/blocks/src/system/runtime/components/runtime-backed-blocks.d.ts +6 -0
  45. package/dist/_dts/blocks/src/system/runtime/hooks/useHeadlessBookingFlow.d.ts +8 -0
  46. package/dist/_dts/blocks/src/system/runtime/hooks/useHeadlessEventRegistrationFlow.d.ts +2 -0
  47. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.completion.d.ts +9 -0
  48. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.headless.state.d.ts +9 -0
  49. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.interactive.d.ts +19 -0
  50. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.mailing-list-choice.d.ts +5 -0
  51. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.mailing-list-note.d.ts +3 -0
  52. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.mailing-list-state.d.ts +9 -0
  53. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.reserved-fields.d.ts +1 -1
  54. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.server.d.ts +1 -1
  55. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.state.d.ts +2 -0
  56. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.submit-handler.d.ts +8 -0
  57. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.submit-success.d.ts +9 -0
  58. package/dist/_dts/blocks/src/system/runtime/nodes/booking-runtime-sources.d.ts +3 -0
  59. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/AttendeeDetailsStep.d.ts +3 -0
  60. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/SuccessStep.d.ts +3 -0
  61. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/event-registration.headless.contract.d.ts +3 -0
  62. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/sessionStorage.d.ts +2 -0
  63. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/types.d.ts +6 -0
  64. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationSubmit.d.ts +3 -0
  65. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationWizard.d.ts +8 -0
  66. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration.interactive.d.ts +9 -0
  67. package/dist/_dts/blocks/src/system/runtime/nodes/newsletter-form.block-submission.d.ts +2 -4
  68. package/dist/_dts/blocks/src/system/runtime/resolver.d.ts +2 -0
  69. package/dist/_dts/blocks/src/system/runtime/shared/components/BookingMailingListNote.d.ts +6 -0
  70. package/dist/_dts/blocks/src/system/runtime/shared/mailingListSignupCopy.d.ts +6 -0
  71. package/dist/_dts/blocks/src/system/runtime/shared/types.d.ts +1 -0
  72. package/dist/_dts/blocks/src/system/transforms/registry/_utils/surfaceForegroundStyles.d.ts +3 -2
  73. package/dist/_dts/blocks/src/system/transforms/registry/core.d.ts +2 -0
  74. package/dist/_dts/blocks/src/system/transforms/registry/layout.d.ts +1 -3
  75. package/dist/_dts/core/src/index.d.ts +1 -1
  76. package/dist/_dts/core/src/mailing-list-runtime.d.ts +15 -0
  77. package/dist/_dts/core/src/mailing-list-setup.d.ts +2 -0
  78. package/dist/_dts/core/src/mailing-list-submission.d.ts +6 -0
  79. package/dist/_dts/core/src/navigation-portal-labels.d.ts +9 -0
  80. package/dist/_dts/core/src/participants.d.ts +0 -38
  81. package/dist/_dts/db/src/generated/supabase/database.types.d.ts +102 -22
  82. package/dist/_dts/editor-blocks/src/block-editor/actionPresentation.d.ts +1 -0
  83. package/dist/_dts/preview-next/src/client/blocks/EditablePageRenderer.d.ts +7 -1
  84. package/dist/_dts/preview-next/src/client/blocks/composer/types.d.ts +4 -3
  85. package/dist/_dts/sdk/src/rendering/blocks-page-renderer.d.ts +1 -0
  86. package/dist/_dts/sdk/src/rendering/components/pageShared.d.ts +1 -0
  87. package/dist/_dts/sdk/src/rendering/helpers/loadPage.d.ts +1 -1
  88. package/dist/_dts/sdk/src/rendering/helpers/pageRuntimeSupport.d.ts +2 -2
  89. package/dist/_dts/sdk/src/version.d.ts +1 -1
  90. package/dist/_dts/theme-core/src/buttons/effects/types.d.ts +1 -1
  91. package/dist/_dts/theme-core/src/footer/effectiveNavLinkStyle.d.ts +13 -0
  92. package/dist/_dts/theme-core/src/footer/index.d.ts +1 -0
  93. package/dist/_dts/theme-core/src/generated/containerResponsiveThemeCss.d.ts +1 -1
  94. package/dist/_dts/theme-core/src/header/effectiveNavLinkStyle.d.ts +17 -0
  95. package/dist/_dts/theme-core/src/header/generateHeaderLogoStyles.d.ts +15 -0
  96. package/dist/_dts/theme-core/src/header/generateHeaderNavLinkStyles.d.ts +4 -0
  97. package/dist/_dts/theme-core/src/header/index.d.ts +3 -0
  98. package/dist/_dts/theme-core/src/header/legacyNavLinkStyle.d.ts +1 -1
  99. package/dist/_dts/theme-core/src/header/openingForegroundProjection.d.ts +7 -0
  100. package/dist/_dts/theme-core/src/header/rootPaint.d.ts +4 -0
  101. package/dist/_dts/theme-core/src/navigation/effectPolicy.d.ts +38 -0
  102. package/dist/_dts/theme-core/src/navigation/generateNavLinkCSS.d.ts +4 -0
  103. package/dist/_dts/theme-core/src/navigation/types.d.ts +4 -0
  104. package/dist/_dts/theme-core/src/site-styles/accessibleSurfaces.d.ts +1 -1
  105. package/dist/_dts/theme-core/src/surfaces/foregroundContract.d.ts +7 -0
  106. package/dist/_dts/theme-core/src/surfaces/foregroundInteraction.d.ts +29 -22
  107. package/dist/_dts/theme-core/src/surfaces/foregroundRoles.d.ts +10 -2
  108. package/dist/_dts/theme-core/src/surfaces/resolveSurfaceForeground.d.ts +9 -0
  109. package/dist/_dts/theme-core/src/utils/cssDeclarations.d.ts +2 -0
  110. package/dist/_dts/ui/src/badge.d.ts +2 -1
  111. package/dist/_dts/ui/src/button.d.ts +1 -1
  112. package/dist/_dts/ui/src/combobox-keys.d.ts +23 -0
  113. package/dist/_dts/ui/src/combobox-rows.d.ts +34 -0
  114. package/dist/_dts/ui/src/combobox.d.ts +26 -1
  115. package/dist/_dts/ui/src/date-picker.d.ts +5 -8
  116. package/dist/_dts/ui/src/editor-item-card.d.ts +1 -0
  117. package/dist/_dts/ui/src/field-trigger.d.ts +39 -0
  118. package/dist/_dts/ui/src/fieldControl.d.ts +27 -0
  119. package/dist/_dts/ui/src/index.d.ts +4 -1
  120. package/dist/_dts/ui/src/native-select.d.ts +8 -0
  121. package/dist/_dts/ui/src/popover.d.ts +7 -1
  122. package/dist/_dts/ui/src/segmented-control.d.ts +4 -0
  123. package/dist/_dts/ui/src/surface.d.ts +1 -1
  124. package/dist/client/{BookingConsentAgreement-BQKL045f.mjs → BookingMailingListNote-1n4Ch_u_.mjs} +15 -4
  125. package/dist/client/{CheckboxChoice--W2n6yKs.mjs → CheckboxChoice-B33MqoUo.mjs} +1 -1
  126. package/dist/client/{DiscountCodeDisclosure-CsOtjFY7.mjs → DiscountCodeDisclosure-CKJtz0mY.mjs} +1 -1
  127. package/dist/client/{EventCombined.client-BdRjVbhH.mjs → EventCombined.client-C0pgma9y.mjs} +7 -7
  128. package/dist/client/{EventListing.client-DBxC6xOU.mjs → EventListing.client-4fhLOvHP.mjs} +2 -2
  129. package/dist/client/{LeafletStaticMap-mHEJKrTs.mjs → LeafletStaticMap-DScC4F3w.mjs} +1 -1
  130. package/dist/client/{scrollToBlock-BNgaEUpo.mjs → TerminalPanel-B5ZUsYhe.mjs} +77 -77
  131. package/dist/client/{ThemedButton-CE5KYT6z.mjs → ThemedButton-DoVIV1Ao.mjs} +2 -2
  132. package/dist/client/{accordion-BEQNSptH.mjs → accordion-CoT5g7zo.mjs} +1 -1
  133. package/dist/client/{bookingForm-AMr-s5vw.mjs → bookingForm-BWxB46xD.mjs} +226 -106
  134. package/dist/client/bookings.mjs +367 -188
  135. package/dist/client/{carousel-Bbt_QgJy.mjs → carousel-DtNYWFd3.mjs} +2 -2
  136. package/dist/client/{carousel.client-jahpU9Vz.mjs → carousel.client-A2lG-9od.mjs} +1 -1
  137. package/dist/client/{cart-CnWi30zJ.mjs → cart-z4qZih1Y.mjs} +3 -3
  138. package/dist/client/{checkout-f3nkWgd4.mjs → checkout-DpL7euFH.mjs} +3 -3
  139. package/dist/client/{checkoutUrls-CW3-78uu.mjs → checkoutUrls-BEfR7kVu.mjs} +1 -1
  140. package/dist/client/client.mjs +2125 -1420
  141. package/dist/client/{colorStyles-CuJBiS-1.mjs → colorStyles-j5U9v5JA.mjs} +5 -1
  142. package/dist/client/{context-Bc8T6pCe.mjs → context-C8TinPJc.mjs} +1 -1
  143. package/dist/client/{dates-DUsCEzLb.mjs → dates-vwwxTeB0.mjs} +2 -2
  144. package/dist/client/{eventCalendar-CKwgXui5.mjs → eventCalendar-DIbHfJXO.mjs} +10 -10
  145. package/dist/client/{eventCombined-CBAOSTGR.mjs → eventCombined-DoGMJ6cg.mjs} +4 -4
  146. package/dist/client/{eventDetails-Dh-_WiBD.mjs → eventDetails-BjN9v6a1.mjs} +4 -4
  147. package/dist/client/{eventListing-CA3frIH5.mjs → eventListing-DajjWgOv.mjs} +4 -4
  148. package/dist/client/{eventRegistration-BHtsgdcg.mjs → eventRegistration-DMq9gMA-.mjs} +109 -41
  149. package/dist/client/{form-C2h3YAcg.mjs → form-Qf6qTbos.mjs} +5 -5
  150. package/dist/client/{headerSection-lwMuMTH9.mjs → headerSection-D7qJrqFX.mjs} +3 -3
  151. package/dist/client/hooks.mjs +661 -116
  152. package/dist/client/{locationMap-DJ2bLODV.mjs → locationMap-CCF9-t_0.mjs} +4 -4
  153. package/dist/client/{FieldValidationMessage-AYanWFb-.mjs → mailingListSignupCopy-DZSHZrm6.mjs} +14 -1
  154. package/dist/client/{media-BtJ37tzS.mjs → media-CwBGetqC.mjs} +1 -1
  155. package/dist/client/{newsletterForm-8Pu5K32g.mjs → newsletterForm-DzCLSP4S.mjs} +6 -6
  156. package/dist/client/{pricing-HHx3IgBz.mjs → pricing-Cgxv2KLC.mjs} +1 -1
  157. package/dist/client/{productDetail-C_1odnAf.mjs → productDetail-ru9w5GHx.mjs} +3 -3
  158. package/dist/client/{productList-CtCv-Nmx.mjs → productList-zaapKSl-.mjs} +3 -3
  159. package/dist/client/{propsDecoder-Dcgsncxb.mjs → propsDecoder-CwvvNOHx.mjs} +52 -6
  160. package/dist/client/rendering/client.mjs +951 -369
  161. package/dist/client/rendering/islands.mjs +19 -19
  162. package/dist/client/rendering.mjs +2153 -1393
  163. package/dist/client/{routeIslandApiConfig-CWLP7wu3.mjs → routeIslandApiConfig-BwVFo0Y4.mjs} +1 -1
  164. package/dist/client/{shop-commerce-B88zmWWo.mjs → shop-commerce-De7gEnkA.mjs} +8 -8
  165. package/dist/client/{shop-commerce-store-DtSfkKuX.mjs → shop-commerce-store-B3MCxIBW.mjs} +1 -1
  166. package/dist/client/{shop-DQXrQ8kJ.mjs → shop-mktkXvbV.mjs} +7 -7
  167. package/dist/client/{shopShared-cuaONpkJ.mjs → shopShared-TqExh235.mjs} +5 -5
  168. package/dist/client/{useEventFilters-Bukew6Gb.mjs → useEventFilters-n_OjkIjX.mjs} +8 -8
  169. package/dist/preview-next/before-render.mjs +122 -50
  170. package/dist/preview-next/client/runtime.mjs +4 -4
  171. package/dist/preview-next/editor-base.css +53 -2
  172. package/dist/preview-next/editor-chrome.css +7 -4
  173. package/dist/preview-next/keepAlive.mjs +122 -50
  174. package/dist/preview-next/middleware.mjs +122 -50
  175. package/dist/{previewAuthStore-h5IgbSp4.mjs → previewAuthStore-C_EHQ5XA.mjs} +122 -50
  176. package/dist/{sdk-runtime-DTc1uIXn.mjs → sdk-runtime-BIkJg5y1.mjs} +2 -2
  177. package/dist/{separator-BpHS1KZK.mjs → separator-C9qDP95Z.mjs} +1 -1
  178. package/dist/server/components.mjs +25345 -24942
  179. package/dist/server/config-validation.mjs +711 -163
  180. package/dist/server/config.mjs +711 -163
  181. package/dist/server/data.mjs +709 -162
  182. package/dist/server/index.mjs +123 -51
  183. package/dist/server/navigation.mjs +13 -2
  184. package/dist/server/next.mjs +4538 -4169
  185. package/dist/server/page-converter.mjs +107 -64
  186. package/dist/server/prebuild.mjs +1 -1
  187. package/dist/server/rendering/server.mjs +2509 -2104
  188. package/dist/server/rendering.mjs +25526 -25104
  189. package/dist/server/routing.mjs +750 -289
  190. package/dist/server/server.mjs +671 -148
  191. package/dist/server/theme-bridge.mjs +66 -17
  192. package/dist/server/theme.mjs +5 -1
  193. package/dist/styles/index.css +32 -4
  194. package/package.json +1 -1
  195. package/dist/_dts/core/src/participant-identity.d.ts +0 -135
@@ -1560,9 +1560,6 @@ var init_participants = __esmMin((() => {
1560
1560
  init_result$1();
1561
1561
  init_string();
1562
1562
  }));
1563
- var init_participant_identity = __esmMin((() => {
1564
- init_assertNever$1();
1565
- }));
1566
1563
  var init_public_url_validation = __esmMin((() => {}));
1567
1564
  var init_public_profile = __esmMin((() => {
1568
1565
  init_public_url_validation();
@@ -2001,17 +1998,39 @@ function parseMailingListRuntimeContext(value) {
2001
1998
  if (!isRecord$33(value)) return invalidRuntimeContext();
2002
1999
  if (value.tag === "not_configured") return ok$2({ tag: "not_configured" });
2003
2000
  if (value.tag !== "configured") return invalidRuntimeContext();
2001
+ return parseConfiguredRuntimeContext(value);
2002
+ }
2003
+ function parseConfiguredRuntimeContext(value) {
2004
2004
  const revision = parseMailingListSetupRevision(value.revision);
2005
2005
  const form = parseMailingListGlobalForm(value.form);
2006
2006
  const provider = parseRuntimeProvider(value.provider);
2007
- if (revision === null || !form.ok || provider === null) return invalidRuntimeContext();
2007
+ const bookingSignup = parseBookingSignupOffer(value.bookingSignup);
2008
+ if (revision === null || !form.ok || provider === null || bookingSignup === null) return invalidRuntimeContext();
2008
2009
  return ok$2({
2009
2010
  tag: "configured",
2010
2011
  revision,
2012
+ bookingSignup,
2011
2013
  form: form.value,
2012
2014
  provider
2013
2015
  });
2014
2016
  }
2017
+ function resolveBookingSignupOffer(context, siteName) {
2018
+ const name = siteName?.trim() ?? "";
2019
+ return context?.tag === "configured" && context.bookingSignup.tag === "offered" ? { siteName: name.length > 0 ? name : "this site" } : null;
2020
+ }
2021
+ function parseBookingSignupOffer(value) {
2022
+ if (value === void 0) return {
2023
+ tag: "unavailable",
2024
+ reason: "disabled"
2025
+ };
2026
+ if (!isRecord$33(value)) return null;
2027
+ if (value.tag === "offered") return { tag: "offered" };
2028
+ if (value.tag === "unavailable" && (value.reason === "disabled" || value.reason === "fields" || value.reason === "destination")) return {
2029
+ tag: "unavailable",
2030
+ reason: value.reason
2031
+ };
2032
+ return null;
2033
+ }
2015
2034
  function parseRuntimeProvider(value) {
2016
2035
  if (!isRecord$33(value)) return null;
2017
2036
  switch (value.provider) {
@@ -2109,6 +2128,7 @@ var init_mailing_list_runtime = __esmMin((() => {
2109
2128
  init_mailing_list_identifiers();
2110
2129
  init_mailing_list_setup_parser();
2111
2130
  init_result$1();
2131
+ init_mailing_list_setup();
2112
2132
  }));
2113
2133
  //#endregion
2114
2134
  //#region ../core/src/mailing-list-submission.ts
@@ -2664,6 +2684,7 @@ var init_booking_verticals = __esmMin((() => {
2664
2684
  var init_navigation_locations = __esmMin((() => {
2665
2685
  init_result$1();
2666
2686
  }));
2687
+ var init_navigation_portal_labels = __esmMin((() => {}));
2667
2688
  var init_event_preset_vocabulary = __esmMin((() => {}));
2668
2689
  var init_event_catalogue = __esmMin((() => {
2669
2690
  init_booking_verticals();
@@ -2709,7 +2730,6 @@ var init_src$2 = __esmMin((() => {
2709
2730
  init_sensitive_collection();
2710
2731
  init_assertNever$1();
2711
2732
  init_participants();
2712
- init_participant_identity();
2713
2733
  init_public_url_validation();
2714
2734
  init_public_profile();
2715
2735
  init_public_experience();
@@ -2750,6 +2770,7 @@ var init_src$2 = __esmMin((() => {
2750
2770
  init_booking_verticals();
2751
2771
  init_event_series_behaviour();
2752
2772
  init_navigation_locations();
2773
+ init_navigation_portal_labels();
2753
2774
  init_event_preset_vocabulary();
2754
2775
  init_event_catalogue();
2755
2776
  }));
@@ -4844,17 +4865,6 @@ var init_expandPalette = __esmMin((() => {
4844
4865
  ]);
4845
4866
  }));
4846
4867
  //#endregion
4847
- //#region ../theme-core/src/surfaces/foregroundRoles.ts
4848
- var SURFACE_FOREGROUND_ROLES;
4849
- var init_foregroundRoles = __esmMin((() => {
4850
- SURFACE_FOREGROUND_ROLES = [
4851
- "text",
4852
- "heading",
4853
- "link",
4854
- "supporting"
4855
- ];
4856
- }));
4857
- //#endregion
4858
4868
  //#region ../theme-core/src/surfaces/foregroundContract.ts
4859
4869
  function requireSurfaceColorValue(role, value) {
4860
4870
  const normalized = value.trim();
@@ -4863,10 +4873,12 @@ function requireSurfaceColorValue(role, value) {
4863
4873
  }
4864
4874
  function completeSurfaceForegrounds(input) {
4865
4875
  const text = requireSurfaceColorValue("text", input.text);
4876
+ const link = input.link === void 0 ? text : requireSurfaceColorValue("link", input.link);
4866
4877
  return {
4867
4878
  text,
4868
4879
  heading: input.heading === void 0 ? text : requireSurfaceColorValue("heading", input.heading),
4869
- link: input.link === void 0 ? text : requireSurfaceColorValue("link", input.link),
4880
+ link,
4881
+ linkHover: input.linkHover === void 0 ? link : requireSurfaceColorValue("linkHover", input.linkHover),
4870
4882
  supporting: input.supporting === void 0 ? text : requireSurfaceColorValue("supporting", input.supporting)
4871
4883
  };
4872
4884
  }
@@ -4874,6 +4886,7 @@ function surfaceForegroundValue(role, outsideProviderFallback = DEFAULT_ROLE_FAL
4874
4886
  const roleVariable = SURFACE_FOREGROUND_CSS_VARS[role];
4875
4887
  const fallback = requireSurfaceColorValue("fallback", outsideProviderFallback);
4876
4888
  if (role === "text") return `var(${roleVariable}, ${fallback})`;
4889
+ if (role === "linkHover") return `var(${roleVariable}, ${surfaceForegroundValue("link", fallback)})`;
4877
4890
  return `var(${roleVariable}, var(${SURFACE_FOREGROUND_CSS_VARS.text}, ${fallback}))`;
4878
4891
  }
4879
4892
  function surfaceForegroundValueWithOpacity(role, opacityPercent) {
@@ -4887,20 +4900,35 @@ function surfaceForegroundStyle(input) {
4887
4900
  [SURFACE_FOREGROUND_CSS_VARS.text]: foregrounds.text,
4888
4901
  [SURFACE_FOREGROUND_CSS_VARS.heading]: foregrounds.heading,
4889
4902
  [SURFACE_FOREGROUND_CSS_VARS.link]: foregrounds.link,
4890
- [SURFACE_FOREGROUND_CSS_VARS.supporting]: foregrounds.supporting
4903
+ [SURFACE_FOREGROUND_CSS_VARS.linkHover]: foregrounds.linkHover,
4904
+ [SURFACE_FOREGROUND_CSS_VARS.supporting]: foregrounds.supporting,
4905
+ "--rb-surface-link-hover-decoration": hoverDecoration(input)
4891
4906
  };
4892
4907
  }
4893
4908
  function surfaceForegroundDeclarations(input) {
4894
- const foregrounds = completeSurfaceForegrounds(input);
4895
- return [`color: ${foregrounds.text}`, ...SURFACE_FOREGROUND_ROLES.map((role) => `${SURFACE_FOREGROUND_CSS_VARS[role]}: ${foregrounds[role]}`)];
4909
+ return Object.entries(surfaceForegroundStyle(input)).map(([property, value]) => `${property}: ${value};`);
4910
+ }
4911
+ function surfaceForegroundInputFromResolved(foreground, color) {
4912
+ const { roles } = foreground;
4913
+ return {
4914
+ text: color(roles.text),
4915
+ heading: color(roles.heading),
4916
+ link: color(roles.link),
4917
+ linkHover: color(roles.linkHover),
4918
+ supporting: color(roles.supporting),
4919
+ hoverDecoration: foreground.hoverDecoration
4920
+ };
4921
+ }
4922
+ function hoverDecoration(input) {
4923
+ return input.hoverDecoration ?? "underline";
4896
4924
  }
4897
4925
  var SURFACE_FOREGROUND_CSS_VARS, DEFAULT_SURFACE_TEXT_COLOR, DEFAULT_SURFACE_LINK_COLOR, DEFAULT_SURFACE_SUPPORTING_COLOR, DEFAULT_ROLE_FALLBACKS;
4898
4926
  var init_foregroundContract = __esmMin((() => {
4899
- init_foregroundRoles();
4900
4927
  SURFACE_FOREGROUND_CSS_VARS = {
4901
4928
  text: "--rb-surface-text-color",
4902
4929
  heading: "--rb-surface-heading-color",
4903
4930
  link: "--rb-surface-link-color",
4931
+ linkHover: "--rb-surface-link-hover-color",
4904
4932
  supporting: "--rb-surface-supporting-color"
4905
4933
  };
4906
4934
  DEFAULT_SURFACE_TEXT_COLOR = "rgb(var(--tb-text, 17 24 39))";
@@ -4910,6 +4938,7 @@ var init_foregroundContract = __esmMin((() => {
4910
4938
  text: DEFAULT_SURFACE_TEXT_COLOR,
4911
4939
  heading: DEFAULT_SURFACE_TEXT_COLOR,
4912
4940
  link: DEFAULT_SURFACE_LINK_COLOR,
4941
+ linkHover: DEFAULT_SURFACE_LINK_COLOR,
4913
4942
  supporting: DEFAULT_SURFACE_SUPPORTING_COLOR
4914
4943
  };
4915
4944
  }));
@@ -5963,12 +5992,6 @@ var init_tokens = __esmMin((() => {
5963
5992
  init_colorTokenParts();
5964
5993
  init_resolver$1();
5965
5994
  }));
5966
- var init_foregroundInteraction = __esmMin((() => {
5967
- init_contrast$1();
5968
- init_colorConversion();
5969
- init_colorTokenParts();
5970
- init_tokens();
5971
- }));
5972
5995
  //#endregion
5973
5996
  //#region ../theme-core/src/palette/utils/opaqueSurfaceColor.ts
5974
5997
  /** Resolve an opaque colour, compositing alpha against an explicit underlay. */
@@ -5981,10 +6004,10 @@ function resolveOpaqueSurfaceHex(reference, palette, underlayReference) {
5981
6004
  const parts = parseColorTokenParts(reference);
5982
6005
  if (parts.kind === "token" && parts.opacityPercent !== null) {
5983
6006
  const foregroundHex = normalizePaletteHex(palette[parts.token] ?? "");
5984
- return foregroundHex ? compositeHex(foregroundHex, underlayHex, parts.opacityPercent / 100) : null;
6007
+ return foregroundHex ? compositeHex$1(foregroundHex, underlayHex, parts.opacityPercent / 100) : null;
5985
6008
  }
5986
6009
  const rgba = parseRgba(parts.kind === "raw" ? parts.value : reference);
5987
- return rgba ? compositeHex(rgbToHex$1(rgba.r, rgba.g, rgba.b), underlayHex, rgba.alpha) : null;
6010
+ return rgba ? compositeHex$1(rgbToHex$1(rgba.r, rgba.g, rgba.b), underlayHex, rgba.alpha) : null;
5988
6011
  }
5989
6012
  /** Resolve a colour reference only when it is already fully opaque. */
5990
6013
  function resolveConcreteColorHex(reference, palette) {
@@ -6000,7 +6023,7 @@ function resolveConcreteColorHex(reference, palette) {
6000
6023
  if (literal.toLowerCase() === "white") return "#ffffff";
6001
6024
  return normalizePaletteHex(literal);
6002
6025
  }
6003
- function compositeHex(foregroundHex, underlayHex, alpha) {
6026
+ function compositeHex$1(foregroundHex, underlayHex, alpha) {
6004
6027
  const foreground = hexToRgb$1(foregroundHex);
6005
6028
  const underlay = hexToRgb$1(underlayHex);
6006
6029
  const channel = (foregroundValue, underlayValue) => Math.round(foregroundValue * alpha + underlayValue * (1 - alpha));
@@ -6037,6 +6060,74 @@ var init_opaqueSurfaceColor = __esmMin((() => {
6037
6060
  init_colorConversion();
6038
6061
  }));
6039
6062
  //#endregion
6063
+ //#region ../theme-core/src/surfaces/foregroundInteraction.ts
6064
+ /**
6065
+ * Derive the hover foreground that belongs with a resolved resting foreground.
6066
+ *
6067
+ * A resting foreground is chosen to be legible against a known surface. A hover
6068
+ * state derived from it stays within a bounded distance of that colour, so it
6069
+ * inherits most of the resting colour's contrast margin instead of asserting
6070
+ * an unrelated brand colour that no one checked against the surface.
6071
+ *
6072
+ * That bounded-distance property is what lets this be used on a transparent
6073
+ * overlay header, where the backdrop is only partly knowable: the scrolled
6074
+ * state composites a 60% glass tint over arbitrary page content, so no
6075
+ * compile-time contrast proof is available there. Staying near a colour that
6076
+ * is already trusted in both states is a weaker claim than a contrast proof,
6077
+ * and it is one this function can actually keep.
6078
+ *
6079
+ * Returns `null` when the resting token is not a plain palette token — an
6080
+ * already-faded or raw value has no well-defined softening, and the caller
6081
+ * should leave hover alone rather than guess.
6082
+ */
6083
+ function deriveForegroundHoverToken(restingToken) {
6084
+ const parts = parseColorTokenParts(restingToken);
6085
+ if (parts.kind !== "token") return null;
6086
+ if (parts.opacityPercent !== null) return null;
6087
+ return parseThemeColorToken(`${parts.token}/85`);
6088
+ }
6089
+ /**
6090
+ * Prefer an authored hover that survives every measured backdrop, then a
6091
+ * checked softening of the resting colour. A null backdrop set represents a
6092
+ * trusted treatment: only an explicit authored hover may change the colour.
6093
+ * When neither option works, retain the resting colour and underline it.
6094
+ */
6095
+ function planForegroundHover(input) {
6096
+ const { restingToken, candidate, palette, backdrops } = input;
6097
+ if (candidate && candidate !== restingToken) {
6098
+ if (backdrops === null || survivesEveryBackdrop(candidate, palette, backdrops)) return {
6099
+ kind: "candidate",
6100
+ token: candidate,
6101
+ decoration: "initial"
6102
+ };
6103
+ }
6104
+ const softened = deriveForegroundHoverToken(restingToken);
6105
+ if (softened && backdrops && survivesEveryBackdrop(softened, palette, backdrops)) return {
6106
+ kind: "softened",
6107
+ token: softened,
6108
+ decoration: "initial"
6109
+ };
6110
+ return {
6111
+ kind: "resting",
6112
+ token: restingToken,
6113
+ decoration: "underline"
6114
+ };
6115
+ }
6116
+ function survivesEveryBackdrop(token, palette, backdrops) {
6117
+ return backdrops.length > 0 && backdrops.every((backdrop) => {
6118
+ const foreground = resolveOpaqueSurfaceHex(token, palette, backdrop);
6119
+ return foreground !== null && contrastRatio(foreground, backdrop) >= 4.5;
6120
+ });
6121
+ }
6122
+ var init_foregroundInteraction = __esmMin((() => {
6123
+ init_contrast$1();
6124
+ init_colorConversion();
6125
+ init_colorTokenParts();
6126
+ init_tokens();
6127
+ init_opaqueSurfaceColor();
6128
+ }));
6129
+ var init_foregroundRoles = __esmMin((() => {}));
6130
+ //#endregion
6040
6131
  //#region ../theme-core/src/surfaces/resolveSurfaceForeground.ts
6041
6132
  /**
6042
6133
  * Resolve the complete foreground contract for an effective page/section or
@@ -6062,12 +6153,16 @@ function resolveSurfaceForeground(background, palette, candidates = {}, options
6062
6153
  }
6063
6154
  function foregroundCandidates(background, overrides) {
6064
6155
  return {
6065
- text: overrides.text ?? background?.textColor ?? null,
6066
- heading: overrides.heading ?? background?.headingColor ?? null,
6067
- link: overrides.link ?? background?.linkColor ?? null,
6068
- supporting: overrides.supporting ?? background?.supportingColor ?? null
6156
+ text: candidateOrBackground(overrides.text, background?.textColor),
6157
+ heading: candidateOrBackground(overrides.heading, background?.headingColor),
6158
+ link: candidateOrBackground(overrides.link, background?.linkColor),
6159
+ linkHover: candidateOrBackground(overrides.linkHover),
6160
+ supporting: candidateOrBackground(overrides.supporting, background?.supportingColor)
6069
6161
  };
6070
6162
  }
6163
+ function candidateOrBackground(candidate, backgroundValue) {
6164
+ return candidate ?? backgroundValue ?? null;
6165
+ }
6071
6166
  function resolveDeterministicForeground(backgroundReference, candidates, palette, compositeBase) {
6072
6167
  const backgroundHex = resolveOpaqueSurfaceHex(backgroundReference, palette, compositeBase);
6073
6168
  if (!backgroundHex) return resolveTrustedTreatmentForeground(candidates, palette);
@@ -6079,29 +6174,51 @@ function resolveDeterministicForeground(backgroundReference, candidates, palette
6079
6174
  ...FALLBACK_TEXT_TOKENS
6080
6175
  ], backgroundHex, palette, derivedOnToken ? [derivedOnToken] : []);
6081
6176
  if (!text) return { kind: "unknown" };
6082
- return {
6083
- kind: "known",
6084
- roles: {
6085
- text,
6086
- heading: safeTokenOr(candidates.heading, text, backgroundHex, palette),
6087
- link: safeTokenOr(candidates.link, text, backgroundHex, palette),
6088
- supporting: safeTokenOr(candidates.supporting, text, backgroundHex, palette)
6089
- }
6090
- };
6177
+ return knownForeground({
6178
+ text,
6179
+ heading: safeTokenOr(candidates.heading, text, backgroundHex, palette),
6180
+ link: safeTokenOr(candidates.link, text, backgroundHex, palette),
6181
+ supporting: safeTokenOr(candidates.supporting, text, backgroundHex, palette)
6182
+ }, {
6183
+ kind: "measured",
6184
+ backdropHex: backgroundHex
6185
+ }, candidates.linkHover, palette);
6091
6186
  }
6092
6187
  function resolveTrustedTreatmentForeground(candidates, palette) {
6093
6188
  const text = canonicalToken(candidates.text, palette);
6094
6189
  if (!text) return { kind: "unknown" };
6190
+ return knownForeground({
6191
+ text,
6192
+ heading: canonicalToken(candidates.heading, palette) ?? text,
6193
+ link: canonicalToken(candidates.link, palette) ?? text,
6194
+ supporting: canonicalToken(candidates.supporting, palette) ?? text
6195
+ }, { kind: "trusted-treatment" }, candidates.linkHover, palette);
6196
+ }
6197
+ function knownForeground(roles, provenance, hoverCandidate, palette) {
6198
+ const hover = planForegroundHover({
6199
+ restingToken: roles.link,
6200
+ candidate: canonicalHoverToken(hoverCandidate, palette),
6201
+ palette,
6202
+ backdrops: provenance.kind === "measured" ? [provenance.backdropHex] : null
6203
+ });
6095
6204
  return {
6096
6205
  kind: "known",
6206
+ provenance,
6097
6207
  roles: {
6098
- text,
6099
- heading: canonicalToken(candidates.heading, palette) ?? text,
6100
- link: canonicalToken(candidates.link, palette) ?? text,
6101
- supporting: canonicalToken(candidates.supporting, palette) ?? text
6102
- }
6208
+ ...roles,
6209
+ linkHover: hover.token
6210
+ },
6211
+ hoverDecoration: hover.decoration
6103
6212
  };
6104
6213
  }
6214
+ function canonicalHoverToken(reference, palette) {
6215
+ const token = parseThemeColorToken(reference);
6216
+ if (token) {
6217
+ const parts = parseColorTokenParts(token);
6218
+ if (parts.kind === "token" && resolveConcreteColorHex(parts.token, palette)) return token;
6219
+ }
6220
+ return canonicalToken(reference, palette);
6221
+ }
6105
6222
  function safeTokenOr(candidate, fallback, backgroundHex, palette) {
6106
6223
  return firstSafeToken([candidate], backgroundHex, palette) ?? fallback;
6107
6224
  }
@@ -6149,6 +6266,7 @@ var init_resolveSurfaceForeground = __esmMin((() => {
6149
6266
  init_opaqueSurfaceColor();
6150
6267
  init_colorTokenParts();
6151
6268
  init_themeColorTokens();
6269
+ init_foregroundInteraction();
6152
6270
  FALLBACK_TEXT_TOKENS = [
6153
6271
  "text",
6154
6272
  "primaryForeground",
@@ -10497,7 +10615,7 @@ function presetCategory(recipe) {
10497
10615
  case void 0: return "modern";
10498
10616
  }
10499
10617
  }
10500
- var init_presets$2 = __esmMin((() => {
10618
+ var init_presets$3 = __esmMin((() => {
10501
10619
  init_styles();
10502
10620
  buttonStyleRecipes.map((recipe) => {
10503
10621
  const resolved = resolveButtonStyleSelection(defaultButtonStyleSelectionFor(recipe.id));
@@ -10528,7 +10646,7 @@ var init_buttons = __esmMin((() => {
10528
10646
  init_affordanceIcons();
10529
10647
  init_generateDefaultButtonSystem();
10530
10648
  init_constants$2();
10531
- init_presets$2();
10649
+ init_presets$3();
10532
10650
  init_styles();
10533
10651
  init_styles();
10534
10652
  }));
@@ -11122,6 +11240,13 @@ var init_roles = __esmMin((() => {
11122
11240
  init_generateDefaultCardSystem();
11123
11241
  }));
11124
11242
  //#endregion
11243
+ //#region ../theme-core/src/utils/cssDeclarations.ts
11244
+ /** Render CSS declarations whether callers provide terminators or fragments. */
11245
+ function renderCssDeclarations(declarations) {
11246
+ return declarations.map((declaration) => declaration.endsWith(";") ? declaration : `${declaration};`).join("\n ");
11247
+ }
11248
+ var init_cssDeclarations = __esmMin((() => {}));
11249
+ //#endregion
11125
11250
  //#region ../theme-core/src/cards/generateCardCss.ts
11126
11251
  function resolveCornerRadiiCss$1(cornerRadii, fallback) {
11127
11252
  const fallbackValue = CORNER_RADIUS_MAP$3[fallback];
@@ -11131,6 +11256,7 @@ function resolveCornerRadiiCss$1(cornerRadii, fallback) {
11131
11256
  function generateCardCss(options) {
11132
11257
  const { themeId, theme, cardSystem: providedCardSystem } = options;
11133
11258
  const tokens = new TokenResolver(theme);
11259
+ const palette = expandPalette(theme.palette);
11134
11260
  const cardSystem = providedCardSystem ?? generateDefaultCardSystem(theme);
11135
11261
  const source = providedCardSystem ? "site-style" : "generated-baseline";
11136
11262
  const aliasGroups = resolveRoleAliasGroups(theme, providedCardSystem ?? null);
@@ -11141,11 +11267,11 @@ function generateCardCss(options) {
11141
11267
  const groupKey = roleAliasGroupKey(source, variant.id);
11142
11268
  emittedGroupKeys.add(groupKey);
11143
11269
  const aliasClasses = aliasGroups.get(groupKey)?.classes ?? [];
11144
- cssChunks.push(generateVariantCSS(variant, themeId, [`card-${variant.id}`, ...aliasClasses], tokens, theme));
11270
+ cssChunks.push(generateVariantCSS(variant, themeId, [`card-${variant.id}`, ...aliasClasses], tokens, theme, palette));
11145
11271
  }
11146
11272
  for (const [groupKey, group] of aliasGroups) {
11147
11273
  if (emittedGroupKeys.has(groupKey)) continue;
11148
- cssChunks.push(generateVariantCSS(group.variant, themeId, group.classes, tokens, theme));
11274
+ cssChunks.push(generateVariantCSS(group.variant, themeId, group.classes, tokens, theme, palette));
11149
11275
  }
11150
11276
  return cssChunks.filter(Boolean).join("\n\n");
11151
11277
  }
@@ -11187,7 +11313,7 @@ function resolveRoleAliasGroups(theme, cardSystem) {
11187
11313
  * This CSS-first approach eliminates runtime transforms for styling,
11188
11314
  * keeping transforms only for data normalization and dynamic layout.
11189
11315
  */
11190
- function generateVariantCSS(variant, themeId, cardClasses, tokens, theme) {
11316
+ function generateVariantCSS(variant, themeId, cardClasses, tokens, theme, palette) {
11191
11317
  const selectorsFor = (suffix) => cardClasses.map((cardClass) => `:where([data-theme-scope="${themeId}"]) .${cardClass}.${cardClass}${suffix}`).join(",\n");
11192
11318
  const containerSelectors = cardClasses.map((cardClass) => `:where([data-theme-scope="${themeId}"]) .${cardClass}.${cardClass}`);
11193
11319
  const containerSelector = containerSelectors.join(",\n");
@@ -11195,19 +11321,7 @@ function generateVariantCSS(variant, themeId, cardClasses, tokens, theme) {
11195
11321
  const contentSelector = selectorsFor(" .card-content");
11196
11322
  const fallbackBackgroundSelector = selectorsFor(" > .rb-bg-surface");
11197
11323
  const rules = [];
11198
- if (variant.background.type === "solid") {
11199
- const bgColor = tokens.getColor(variant.background.colorToken);
11200
- rules.push(`background: ${bgColor}`);
11201
- } else if (variant.background.type === "gradient") {
11202
- const fromColor = tokens.getColor(variant.background.fromToken);
11203
- const toColor = tokens.getColor(variant.background.toToken);
11204
- const direction = GRADIENT_DIRECTION_MAP$1[variant.background.direction] || "to right";
11205
- rules.push(`background: linear-gradient(${direction}, ${fromColor}, ${toColor})`);
11206
- } else rules.push(`background: transparent`);
11207
- if (variant.background.type !== "transparent") {
11208
- const foreground = tokens.getColor(variant.foregroundToken ?? "text");
11209
- rules.push(...surfaceForegroundDeclarations({ text: foreground }));
11210
- }
11324
+ rules.push(...cardSurfaceRules(variant, tokens, theme, palette));
11211
11325
  const resolveColor = (token) => tokens.getColor(token);
11212
11326
  rules.push(...cardBorderDeclarations(variant.border ? borderDeclaration(variant.border, tokens) : null, variant.decorations, resolveColor));
11213
11327
  const corners = variant.corners ?? theme.corners;
@@ -11224,13 +11338,31 @@ function generateVariantCSS(variant, themeId, cardClasses, tokens, theme) {
11224
11338
  const contentRules = [`padding: ${resolveContentPadding(variant)}`];
11225
11339
  return [
11226
11340
  `${structureSelector} {\n display: flex;\n flex-direction: column;\n position: relative;\n overflow: visible;\n}`,
11227
- `${containerSelector} {\n ${rules.join(";\n ")};\n}`,
11341
+ `${containerSelector} {\n ${renderCssDeclarations(rules)}\n}`,
11228
11342
  ...cardDecorationPseudoRules(containerSelectors, variant.decorations, resolveColor),
11229
11343
  `${fallbackBackgroundSelector} {\n background: transparent;\n}`,
11230
11344
  `${mediaSelector} {\n ${mediaRules.join(";\n ")};\n}`,
11231
11345
  `${contentSelector} {\n ${contentRules.join(";\n ")};\n}`
11232
11346
  ].join("\n\n");
11233
11347
  }
11348
+ function cardSurfaceRules(variant, tokens, theme, palette) {
11349
+ if (variant.background.type === "transparent") return ["background: transparent"];
11350
+ const foreground = resolveSurfaceForeground(variant.background.type === "solid" ? {
11351
+ type: "color",
11352
+ color: variant.background.colorToken,
11353
+ textColor: variant.foregroundToken ?? "text"
11354
+ } : {
11355
+ type: "gradient",
11356
+ textColor: variant.foregroundToken ?? "text"
11357
+ }, palette, { linkHover: theme.typography.proseLinkStyle?.hoverColorToken });
11358
+ return [cardBackgroundRule(variant.background, tokens), ...surfaceForegroundDeclarations(foreground.kind === "known" ? surfaceForegroundInputFromResolved(foreground, (token) => tokens.getColor(token)) : { text: tokens.getColor(variant.foregroundToken ?? "text") })];
11359
+ }
11360
+ function cardBackgroundRule(background, tokens) {
11361
+ if (background.type === "solid") return `background: ${tokens.getColor(background.colorToken)}`;
11362
+ const from = tokens.getColor(background.fromToken);
11363
+ const to = tokens.getColor(background.toToken);
11364
+ return `background: linear-gradient(${GRADIENT_DIRECTION_MAP$1[background.direction] || "to right"}, ${from}, ${to})`;
11365
+ }
11234
11366
  function borderDeclaration(border, tokens) {
11235
11367
  const borderColor = tokens.getColor(border.colorToken);
11236
11368
  return `border: ${border.widthClass === "border-4" ? "4px" : border.widthClass === "border-2" ? "2px" : border.widthClass === "border" ? "1px" : "1px"} solid ${borderColor}`;
@@ -11251,6 +11383,8 @@ var PER_CORNER_RADIUS_MAP$1, CONTENT_PADDING_MAP, MEDIA_CORNER_MAP, init_generat
11251
11383
  init_roles();
11252
11384
  init_types$13();
11253
11385
  init_surfaces();
11386
+ init_expandPalette();
11387
+ init_cssDeclarations();
11254
11388
  PER_CORNER_RADIUS_MAP$1 = {
11255
11389
  square: "0",
11256
11390
  soft: "0.5rem",
@@ -11276,6 +11410,7 @@ var PER_CORNER_RADIUS_MAP$1, CONTENT_PADDING_MAP, MEDIA_CORNER_MAP, init_generat
11276
11410
  var init_core$2 = __esmMin((() => {
11277
11411
  init_surfaces();
11278
11412
  init_decorations();
11413
+ init_cssDeclarations();
11279
11414
  }));
11280
11415
  //#endregion
11281
11416
  //#region ../theme-core/src/cards/index.ts
@@ -11643,16 +11778,70 @@ var init_baseSchema = __esmMin((() => {
11643
11778
  });
11644
11779
  }));
11645
11780
  //#endregion
11781
+ //#region ../theme-core/src/navigation/effectPolicy.ts
11782
+ function navEffectPolicy(effectId) {
11783
+ return policiesById[effectId] ?? null;
11784
+ }
11785
+ var NAV_EFFECT_POLICIES, policiesById;
11786
+ var init_effectPolicy = __esmMin((() => {
11787
+ NAV_EFFECT_POLICIES = {
11788
+ "darken-background": "other",
11789
+ "lighten-background": "other",
11790
+ "fade-background": "other",
11791
+ "opacity-reduce": "other",
11792
+ "animated-gradient": "other",
11793
+ "background-on-hover": "paired-hover",
11794
+ "background-on-hover-alpha": "paired-hover",
11795
+ "border-glow": "other",
11796
+ "drop-shadow": "other",
11797
+ "inner-shadow": "other",
11798
+ "neumorphic-shadow": "other",
11799
+ "outer-glow": "other",
11800
+ "retro-3d-shadow": "other",
11801
+ "scale-up": "other",
11802
+ "scale-down": "other",
11803
+ lift: "other",
11804
+ "press-down": "other",
11805
+ pop: "other",
11806
+ "aurora-glow": "other",
11807
+ "cosmic-stardust": "other",
11808
+ "gradient-border-fill": "other",
11809
+ "animated-gradient-border-fill": "other",
11810
+ "border-bottom-grow": "other",
11811
+ "gradient-text": "other",
11812
+ "text-color-change": "text-colour",
11813
+ "border-color-change": "other",
11814
+ "sketchy-border": "other",
11815
+ "pulse-animation": "other",
11816
+ "nav-underline": "underline",
11817
+ "nav-frosted-base": "other",
11818
+ "nav-frosted-hover": "other",
11819
+ "nav-frosted-active": "other"
11820
+ };
11821
+ policiesById = NAV_EFFECT_POLICIES;
11822
+ }));
11823
+ //#endregion
11646
11824
  //#region ../theme-core/src/navigation/types.ts
11647
11825
  /**
11648
11826
  * Navigation Link Style Types
11649
11827
  *
11650
11828
  * Schema and types for composable nav link styling used by header and footer.
11651
11829
  */
11830
+ function navLinkHoverColorCandidate(style) {
11831
+ const effect = style?.effects?.hover?.find((item) => navEffectPolicy(item.effectId) === "text-colour");
11832
+ return parseThemeColorToken(effect?.options?.hoverColorToken ?? style?.hoverColorToken);
11833
+ }
11834
+ function navLinkOwnsHoverForeground(style) {
11835
+ return style?.effects?.hover?.some((effect) => navEffectPolicy(effect.effectId) === "paired-hover") ?? false;
11836
+ }
11837
+ function navLinkOwnsUnderline(style) {
11838
+ return style?.effects?.hover?.some((effect) => navEffectPolicy(effect.effectId) === "underline") ?? false;
11839
+ }
11652
11840
  var navLinkPaddingSchema, navLinkPaddingXSchema, navLinkBorderRadiusSchema, navLinkTextSizeSchema, navLinkLetterSpacingSchema, navLinkContrastTreatmentSchema, navLinkStyleSchema, NAV_LINK_PADDING_MAP, NAV_LINK_PADDING_X_MAP, NAV_LINK_BORDER_RADIUS_MAP, NAV_LINK_TEXT_SIZE_MAP, NAV_LINK_LETTER_SPACING_MAP;
11653
11841
  var init_types$9 = __esmMin((() => {
11654
11842
  init_baseSchema();
11655
11843
  init_themeColorTokens();
11844
+ init_effectPolicy();
11656
11845
  navLinkPaddingSchema = z$1.enum([
11657
11846
  "none",
11658
11847
  "compact",
@@ -18575,7 +18764,7 @@ function getGradientPreset(id) {
18575
18764
  return gradientPresetById[id];
18576
18765
  }
18577
18766
  var rawGradientPresets, GRADIENT_PRESETS, GRADIENT_PRESET_IDS, gradientPresetIdSet, gradientPresetById;
18578
- var init_presets$1 = __esmMin((() => {
18767
+ var init_presets$2 = __esmMin((() => {
18579
18768
  rawGradientPresets = [
18580
18769
  {
18581
18770
  id: "primary-secondary",
@@ -18805,7 +18994,7 @@ var init_utils$2 = __esmMin((() => {}));
18805
18994
  //#region ../theme-core/src/gradients/index.ts
18806
18995
  var init_gradients = __esmMin((() => {
18807
18996
  init_types$10();
18808
- init_presets$1();
18997
+ init_presets$2();
18809
18998
  init_utils$2();
18810
18999
  }));
18811
19000
  //#endregion
@@ -21668,6 +21857,15 @@ var init_resolver = __esmMin((() => {
21668
21857
  };
21669
21858
  blockDesignFallback.sectionSurface, blockDesignFallback.contentFrame, blockDesignFallback.sectionHeight, blockDesignFallback.heroLegibility, blockDesignFallback.imageSurfaceTreatment, blockDesignFallback.imageSurfaceMotion, blockDesignFallback.tileTreatment, blockDesignFallback.eventListTreatment, blockDesignFallback.eyebrowTreatment, blockDesignFallback.accordionIconTreatment, blockDesignFallback.composition;
21670
21859
  }));
21860
+ //#endregion
21861
+ //#region ../theme-core/src/header/rootPaint.ts
21862
+ /** The nav container takes precedence when a floating header also has one. */
21863
+ function headerRootPaint(header) {
21864
+ const navContainerType = header?.navContainer?.type ?? "none";
21865
+ if (navContainerType === "glass" || navContainerType === "pill") return "contained-nav";
21866
+ return header?.variant === "floating" ? "overlay" : "own-surface";
21867
+ }
21868
+ var init_rootPaint = __esmMin((() => {}));
21671
21869
  function parseSiteChromeBackgroundColorToken(value) {
21672
21870
  const token = parseBackgroundAppearanceColorToken(value);
21673
21871
  return token ? token : null;
@@ -21684,6 +21882,7 @@ var init_siteChromeBackgrounds = __esmMin((() => {
21684
21882
  init_surfaces();
21685
21883
  init_backgroundAppearance();
21686
21884
  init_rawStyleFields();
21885
+ init_rootPaint();
21687
21886
  siteChromeBackgroundColorTokens = toSiteChromeBackgroundColorTokens(backgroundAppearanceColorTokenNames);
21688
21887
  quickSiteChromeBackgroundColorTokens = toSiteChromeBackgroundColorTokens(backgroundAppearanceQuickColorTokenNames);
21689
21888
  siteChromeBackgroundColorTokens.filter((token) => !quickSiteChromeBackgroundColorTokens.includes(token));
@@ -22004,13 +22203,278 @@ function diffJsonPaths(left, right, path = "") {
22004
22203
  }];
22005
22204
  }
22006
22205
  var init_headerBytesComparison = __esmMin((() => {}));
22206
+ //#endregion
22207
+ //#region ../theme-core/src/navigation/presets.ts
22208
+ /**
22209
+ * Get a nav link style preset by ID
22210
+ */
22211
+ function getNavLinkPreset(presetId) {
22212
+ return NAV_LINK_PRESETS[presetId];
22213
+ }
22214
+ var NAV_LINK_PRESETS;
22215
+ var init_presets$1 = __esmMin((() => {
22216
+ NAV_LINK_PRESETS = {
22217
+ /**
22218
+ * Minimal - subtle color change on hover
22219
+ */
22220
+ minimal: {
22221
+ name: "Minimal",
22222
+ typography: "body",
22223
+ fontWeight: "medium",
22224
+ textTransform: "none",
22225
+ italic: false,
22226
+ colorToken: "text",
22227
+ hoverColorToken: "primary",
22228
+ padding: "none",
22229
+ borderRadius: "none",
22230
+ effects: { hover: [{
22231
+ effectId: "text-color-change",
22232
+ options: { hoverColorToken: "primary" }
22233
+ }] }
22234
+ },
22235
+ /**
22236
+ * Underline - static underline appears on hover
22237
+ */
22238
+ underline: {
22239
+ name: "Underline",
22240
+ typography: "body",
22241
+ fontWeight: "medium",
22242
+ textTransform: "none",
22243
+ italic: false,
22244
+ colorToken: "text",
22245
+ padding: "none",
22246
+ borderRadius: "none",
22247
+ effects: { hover: [{
22248
+ effectId: "nav-underline",
22249
+ options: { style: "static" }
22250
+ }] }
22251
+ },
22252
+ /**
22253
+ * Underline Grow - animated underline grows from center on hover
22254
+ */
22255
+ "underline-grow": {
22256
+ name: "Underline Grow",
22257
+ typography: "body",
22258
+ fontWeight: "medium",
22259
+ textTransform: "none",
22260
+ italic: false,
22261
+ colorToken: "text",
22262
+ padding: "none",
22263
+ borderRadius: "none",
22264
+ effects: { hover: [{
22265
+ effectId: "nav-underline",
22266
+ options: { style: "grow" }
22267
+ }] }
22268
+ },
22269
+ /**
22270
+ * Capsule - pill-shaped background on hover
22271
+ */
22272
+ capsule: {
22273
+ name: "Capsule",
22274
+ typography: "body",
22275
+ fontWeight: "medium",
22276
+ textTransform: "none",
22277
+ italic: false,
22278
+ colorToken: "text",
22279
+ padding: "compact",
22280
+ borderRadius: "full",
22281
+ effects: {
22282
+ hover: [{
22283
+ effectId: "background-on-hover-alpha",
22284
+ options: {
22285
+ colorToken: "primary",
22286
+ opacity: 10
22287
+ }
22288
+ }],
22289
+ active: [{
22290
+ effectId: "background-on-hover-alpha",
22291
+ options: {
22292
+ colorToken: "primary",
22293
+ opacity: 15
22294
+ }
22295
+ }]
22296
+ }
22297
+ },
22298
+ /**
22299
+ * Solid - solid background color on hover
22300
+ */
22301
+ solid: {
22302
+ name: "Solid",
22303
+ typography: "body",
22304
+ fontWeight: "medium",
22305
+ textTransform: "none",
22306
+ italic: false,
22307
+ colorToken: "text",
22308
+ padding: "compact",
22309
+ borderRadius: "none",
22310
+ effects: {
22311
+ hover: [{
22312
+ effectId: "background-on-hover",
22313
+ options: {
22314
+ colorToken: "primary",
22315
+ textColorToken: "primaryForeground"
22316
+ }
22317
+ }],
22318
+ active: [{
22319
+ effectId: "background-on-hover",
22320
+ options: {
22321
+ colorToken: "primary",
22322
+ textColorToken: "primaryForeground"
22323
+ }
22324
+ }]
22325
+ }
22326
+ },
22327
+ /**
22328
+ * Scale - gentle scale-up on hover
22329
+ */
22330
+ scale: {
22331
+ name: "Scale",
22332
+ typography: "body",
22333
+ fontWeight: "medium",
22334
+ textTransform: "none",
22335
+ italic: false,
22336
+ colorToken: "text",
22337
+ padding: "none",
22338
+ borderRadius: "none",
22339
+ effects: { hover: [{
22340
+ effectId: "scale-up",
22341
+ options: { scale: 1.05 }
22342
+ }] }
22343
+ },
22344
+ /**
22345
+ * Frosted - semi-transparent glass-like background
22346
+ */
22347
+ frosted: {
22348
+ name: "Frosted",
22349
+ typography: "body",
22350
+ fontWeight: "medium",
22351
+ textTransform: "none",
22352
+ italic: false,
22353
+ colorToken: "text",
22354
+ padding: "compact",
22355
+ borderRadius: "md",
22356
+ effects: {
22357
+ base: [{ effectId: "nav-frosted-base" }],
22358
+ hover: [{ effectId: "nav-frosted-hover" }],
22359
+ active: [{ effectId: "nav-frosted-active" }]
22360
+ }
22361
+ }
22362
+ };
22363
+ Object.keys(NAV_LINK_PRESETS);
22364
+ }));
22365
+ //#endregion
22366
+ //#region ../theme-core/src/header/legacyNavLinkStyle.ts
22367
+ function buildLegacyHeaderNavLinkStyle(header, contrastTreatment, navTextSize) {
22368
+ const navStyle = header.navStyle ?? "minimal";
22369
+ const basePreset = getNavLinkPreset(navStyle);
22370
+ if (!basePreset) return null;
22371
+ const style = {
22372
+ ...basePreset,
22373
+ fontWeight: header.navWeight ?? basePreset.fontWeight,
22374
+ colorToken: (header.navColor ?? header.textColor)?.trim() || basePreset.colorToken,
22375
+ ...contrastTreatment ? { contrastTreatment } : {},
22376
+ ...navTextSize ? { textSize: navTextSize } : {}
22377
+ };
22378
+ if (header.navWeight === "bold" && navStyle === "solid") style.textTransform = "uppercase";
22379
+ applyLegacyGlassTreatment(style, header, navStyle);
22380
+ return style;
22381
+ }
22382
+ function applyLegacyGlassTreatment(style, header, navStyle) {
22383
+ if (header.navContainer?.type !== "glass" || navStyle !== "minimal") return;
22384
+ style.borderRadius = "full";
22385
+ style.effects = {
22386
+ ...style.effects,
22387
+ hover: glassStateEffects(10),
22388
+ active: glassStateEffects(18)
22389
+ };
22390
+ }
22391
+ function glassStateEffects(opacity) {
22392
+ return [{
22393
+ effectId: "background-on-hover-alpha",
22394
+ options: {
22395
+ colorToken: "neutral-50",
22396
+ opacity
22397
+ }
22398
+ }, {
22399
+ effectId: "text-color-change",
22400
+ options: { hoverColorToken: "neutral-50" }
22401
+ }];
22402
+ }
22403
+ var init_legacyNavLinkStyle = __esmMin((() => {
22404
+ init_presets$1();
22405
+ }));
22406
+ function readOpeningForegroundProjection(header) {
22407
+ return header?.__runtimeOpeningForeground ?? null;
22408
+ }
22409
+ var init_openingForegroundProjection = __esmMin((() => {}));
22410
+ //#endregion
22411
+ //#region ../theme-core/src/header/effectiveNavLinkStyle.ts
22412
+ function effectiveHeaderNavLinkStyle(header, contrastTreatment = null, navTextSize = null) {
22413
+ if (!header) return null;
22414
+ if (!header.navLinkStyle) return buildLegacyHeaderNavLinkStyle(header, contrastTreatment, navTextSize);
22415
+ return {
22416
+ ...header.navLinkStyle,
22417
+ ...contrastTreatment ? { contrastTreatment } : {},
22418
+ ...navTextSize ? { textSize: navTextSize } : {}
22419
+ };
22420
+ }
22421
+ function headerForegroundCandidates(header) {
22422
+ if (!header) return {};
22423
+ const style = effectiveHeaderNavLinkStyle(header);
22424
+ return {
22425
+ text: header.textColor ?? header.background?.textColor,
22426
+ link: style?.colorToken ?? header.navColor ?? header.textColor,
22427
+ linkHover: navLinkHoverColorCandidate(style)
22428
+ };
22429
+ }
22430
+ function headerLeafTextColor(header) {
22431
+ if (!header) return "text";
22432
+ return header.textColor ?? header.navColor ?? header.background?.textColor ?? header.navLinkStyle?.colorToken ?? "text";
22433
+ }
22434
+ /** Transparent chrome must reset the whole contract on its own root. */
22435
+ function transparentHeaderForegroundInput(header, palette) {
22436
+ const projection = readOpeningForegroundProjection(header);
22437
+ if (projection?.kind === "known") return surfaceForegroundInputFromResolved(projection, rgbColorValue);
22438
+ return authoredTransparentHeaderForegroundInput(header, palette);
22439
+ }
22440
+ function authoredTransparentHeaderForegroundInput(header, palette) {
22441
+ const text = headerLeafTextColor(header);
22442
+ const style = effectiveHeaderNavLinkStyle(header);
22443
+ const link = style?.colorToken ?? text;
22444
+ const restingToken = parseThemeColorToken(link) ?? parseThemeColorToken("text");
22445
+ if (!restingToken) throw new Error("Built-in text colour token is invalid");
22446
+ const hover = planForegroundHover({
22447
+ restingToken,
22448
+ candidate: navLinkOwnsHoverForeground(style) ? null : navLinkHoverColorCandidate(style),
22449
+ palette,
22450
+ backdrops: null
22451
+ });
22452
+ return {
22453
+ text: rgbColorValue(text),
22454
+ link: rgbColorValue(link),
22455
+ linkHover: rgbColorValue(hover.token),
22456
+ hoverDecoration: navLinkOwnsUnderline(style) ? "initial" : hover.decoration
22457
+ };
22458
+ }
22459
+ var init_effectiveNavLinkStyle$1 = __esmMin((() => {
22460
+ init_types$9();
22461
+ init_legacyNavLinkStyle();
22462
+ init_openingForegroundProjection();
22463
+ init_surfaces();
22464
+ init_foregroundInteraction();
22465
+ init_tokens();
22466
+ init_colorStyles();
22467
+ }));
22007
22468
  var init_headerOpeningForeground = __esmMin((() => {
22008
22469
  init_foregroundInteraction();
22009
22470
  init_expandPalette();
22010
22471
  init_colorConversion();
22011
22472
  init_tokens();
22012
- init_logoVariant();
22013
22473
  init_colorTokenParts();
22474
+ init_types$9();
22475
+ init_effectPolicy();
22476
+ init_effectiveNavLinkStyle$1();
22477
+ init_openingForegroundProjection();
22014
22478
  init_types$8();
22015
22479
  }));
22016
22480
  var init_effectivePageDesign = __esmMin((() => {
@@ -22323,6 +22787,824 @@ var init_site_styles = __esmMin((() => {
22323
22787
  init_themeParity();
22324
22788
  init_types$8();
22325
22789
  }));
22790
+ //#endregion
22791
+ //#region ../theme-core/src/navigation/generateNavLinkCSS.ts
22792
+ /**
22793
+ * Generate complete CSS for nav links from a NavLinkStyle configuration
22794
+ */
22795
+ function generateNavLinkCSS(options) {
22796
+ const { themeId, tokens, theme, style, className } = options;
22797
+ const surfaceDependent = options.surfaceDependent === true && !navLinkOwnsHoverForeground(style);
22798
+ const overriddenSurface = options.surfaceDependent === true && options.surfaceRestingColor === true;
22799
+ const surfaceRestingColor = surfaceDependent || overriddenSurface;
22800
+ const selector = `:where([data-theme-scope="${themeId}"]) .${className}`;
22801
+ const activeSelector = `${selector}:active, ${selector}[data-active="true"]`;
22802
+ const baseRules = navBaseRules(style, tokens, theme, surfaceRestingColor, overriddenSurface);
22803
+ const hoverRules = navHoverRules(style, tokens, surfaceDependent);
22804
+ const activeRules = surfaceDependent ? [`color: ${surfaceForegroundValue("linkHover", tokens.getColor(style.colorToken))};`] : [];
22805
+ const authoredColor = tokens.getColor(style.colorToken);
22806
+ const effectsCss = style.effects ? generateEffectsCSS({
22807
+ themeId,
22808
+ variantId: className,
22809
+ effects: surfaceDependent ? withoutSurfaceTextColorEffects(style.effects) : style.effects,
22810
+ elementConfig: {
22811
+ background: { type: "transparent" },
22812
+ textColorToken: style.colorToken || "text"
22813
+ },
22814
+ tokens,
22815
+ theme
22816
+ }) : "";
22817
+ const underlineColorCss = surfaceDependent && navLinkOwnsUnderline(style) ? `\n${selector}::after {\n background: ${surfaceForegroundValue("link", authoredColor)};\n}\n` : "";
22818
+ return [
22819
+ cssRule(selector, baseRules),
22820
+ effectsCss,
22821
+ cssRule(`${selector}:hover`, hoverRules),
22822
+ cssRule(activeSelector, activeRules),
22823
+ underlineColorCss,
22824
+ navLinkFocusVisibleCss(selector, style, theme, tokens, surfaceRestingColor, overriddenSurface),
22825
+ generateInteractiveChildInheritanceCSS(selector)
22826
+ ].join("");
22827
+ }
22828
+ function navBaseRules(style, tokens, theme, surfaceRestingColor, overriddenSurface) {
22829
+ const typographyRules = generateBaseInteractiveCSS({
22830
+ typography: {
22831
+ typography: style.typography,
22832
+ fontWeight: style.fontWeight,
22833
+ textTransform: style.textTransform,
22834
+ italic: style.italic
22835
+ },
22836
+ padding: style.padding ? NAV_LINK_PADDING_MAP[style.padding] : void 0,
22837
+ borderRadius: style.borderRadius ? NAV_LINK_BORDER_RADIUS_MAP[style.borderRadius] : void 0,
22838
+ includeTransition: true,
22839
+ includeFlexCenter: false
22840
+ });
22841
+ const contrastShadow = navContrastShadow(style, theme, overriddenSurface);
22842
+ return [
22843
+ ...typographyRules,
22844
+ ...style.paddingX ? [`padding-left: ${NAV_LINK_PADDING_X_MAP[style.paddingX]};`, `padding-right: ${NAV_LINK_PADDING_X_MAP[style.paddingX]};`] : [],
22845
+ ...style.textSize ? [`font-size: ${NAV_LINK_TEXT_SIZE_MAP[style.textSize]};`] : [],
22846
+ ...style.letterSpacing && style.letterSpacing !== "normal" ? [`letter-spacing: ${NAV_LINK_LETTER_SPACING_MAP[style.letterSpacing]};`] : [],
22847
+ ...surfaceRestingColor ? [`color: ${surfaceForegroundValue("link", tokens.getColor(style.colorToken))};`] : style.colorToken ? [`color: ${tokens.getColor(style.colorToken)};`] : [],
22848
+ ...contrastShadow ? [`text-shadow: ${contrastShadow};`] : []
22849
+ ];
22850
+ }
22851
+ function navHoverRules(style, tokens, surfaceDependent) {
22852
+ if (surfaceDependent) return [`color: ${surfaceForegroundValue("linkHover", tokens.getColor(style.colorToken))};`, ...navLinkOwnsUnderline(style) ? [] : ["text-decoration-line: var(--rb-surface-link-hover-decoration, none);"]];
22853
+ return style.hoverColorToken && !style.effects?.hover?.length ? [`color: ${tokens.getColor(style.hoverColorToken)};`] : [];
22854
+ }
22855
+ function cssRule(selector, rules) {
22856
+ return rules.length > 0 ? `\n${selector} {\n ${rules.join("\n ")}\n}\n` : "";
22857
+ }
22858
+ function navContrastShadow(style, theme, overriddenSurface) {
22859
+ return overriddenSurface ? null : buildTextContrastShadow({
22860
+ theme,
22861
+ colorToken: style.colorToken,
22862
+ treatment: style.contrastTreatment
22863
+ });
22864
+ }
22865
+ function withoutSurfaceTextColorEffects(effects) {
22866
+ const withoutColor = (items) => items?.filter((effect) => navEffectPolicy(effect.effectId) !== "text-colour");
22867
+ return {
22868
+ base: withoutColor(effects.base),
22869
+ hover: withoutColor(effects.hover),
22870
+ active: withoutColor(effects.active),
22871
+ focus: withoutColor(effects.focus)
22872
+ };
22873
+ }
22874
+ /**
22875
+ * Keyboard focus indicator for nav links, in the header, the footer and header
22876
+ * dropdown menus — the three surfaces `generateNavLinkCSS` serves.
22877
+ *
22878
+ * Emitted unconditionally rather than as an effect, because focus visibility is
22879
+ * a floor rather than a style choice. Only the interaction-palette pill ever
22880
+ * wrote an `effects.focus` group, so every other nav — every `quiet` palette,
22881
+ * every footer, every dropdown — previously fell back to whatever outline the
22882
+ * browser drew.
22883
+ *
22884
+ * The outline takes the link's own resolved colour, so on a header that adapts
22885
+ * to the section it floats over it moves with the adaptation instead of
22886
+ * asserting a brand colour against an unknown backdrop.
22887
+ *
22888
+ * Where the style asks for `soft-glow`, the same halo goes on the outline. That
22889
+ * treatment exists because the theme has already conceded the resolved colour
22890
+ * alone is not reliable over an unpredictable backdrop — a hero photograph with
22891
+ * mixed luminance. Without it the text would stay legible by its halo while the
22892
+ * focus ring, which is the part with a contrast requirement of its own, would
22893
+ * not.
22894
+ *
22895
+ * A style that also paints a focus pill keeps it: this adds an outline around
22896
+ * that pill rather than replacing it.
22897
+ */
22898
+ function navLinkFocusVisibleCss(selector, style, theme, tokens, surfaceRestingColor, overriddenSurface) {
22899
+ const color = surfaceRestingColor ? surfaceForegroundValue("link", tokens.getColor(style.colorToken)) : tokens.getColor(style.colorToken);
22900
+ const halo = navContrastShadow(style, theme, overriddenSurface);
22901
+ return `
22902
+ ${selector}:focus-visible {
22903
+ outline: 2px solid ${color};
22904
+ outline-offset: ${focusOutlineOffset(selector)};${halo ? `\n box-shadow: ${halo};` : ""}
22905
+ }
22906
+ `;
22907
+ }
22908
+ /**
22909
+ * Dropdown items are full-width inside a panel with no horizontal padding, so
22910
+ * an outset outline would paint over and past the panel's own border. Keeping
22911
+ * it flush is the only way it reads as belonging to the item.
22912
+ */
22913
+ function focusOutlineOffset(selector) {
22914
+ return selector.includes("nav-dropdown-link") ? "-2px" : "3px";
22915
+ }
22916
+ function buildTextContrastShadow(input) {
22917
+ if (input.treatment !== "soft-glow") return null;
22918
+ 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)";
22919
+ }
22920
+ function isLikelyLightColorToken(theme, colorToken) {
22921
+ const hex = resolveColorTokenHex(theme, colorToken);
22922
+ if (hex) try {
22923
+ return featuresFromHex(hex).Y >= .5;
22924
+ } catch {}
22925
+ const normalizedToken = colorToken?.toLowerCase() ?? "";
22926
+ if (normalizedToken.includes("foreground") || normalizedToken.startsWith("on") || normalizedToken.includes("white") || normalizedToken.endsWith("-50") || normalizedToken.endsWith("-100")) return true;
22927
+ if (normalizedToken.includes("black") || normalizedToken.endsWith("-800") || normalizedToken.endsWith("-900") || normalizedToken.endsWith("-950")) return false;
22928
+ return theme.palette.meta.mode === "dark";
22929
+ }
22930
+ function resolveColorTokenHex(theme, colorToken) {
22931
+ if (!colorToken) return null;
22932
+ if (colorToken === "white") return "#ffffff";
22933
+ if (colorToken === "black") return "#000000";
22934
+ if (colorToken === "transparent") return null;
22935
+ return expandPalette(theme.palette)[colorToken] ?? null;
22936
+ }
22937
+ var init_generateNavLinkCSS = __esmMin((() => {
22938
+ init_types$9();
22939
+ init_expandPalette();
22940
+ init_colorConversion();
22941
+ init_generateBaseCSS();
22942
+ init_generateEffectsCSS();
22943
+ init_foregroundContract();
22944
+ init_effectPolicy();
22945
+ })), NAV_DROPDOWN_SHIFT_PROPERTY, NAV_DROPDOWN_MAX_WIDTH_CSS, NAV_DROPDOWN_CONTAINER_RAIL_CSS_RULES;
22946
+ var init_navDropdownSizing = __esmMin((() => {
22947
+ NAV_DROPDOWN_SHIFT_PROPERTY = "--nav-dropdown-shift-x";
22948
+ NAV_DROPDOWN_MAX_WIDTH_CSS = `min(22rem, calc(100vw - 2rem))`;
22949
+ NAV_DROPDOWN_CONTAINER_RAIL_CSS_RULES = [
22950
+ `min-width: 12rem;`,
22951
+ `width: max-content;`,
22952
+ `max-width: ${NAV_DROPDOWN_MAX_WIDTH_CSS};`,
22953
+ `transform: translateX(var(${NAV_DROPDOWN_SHIFT_PROPERTY}, 0px));`
22954
+ ];
22955
+ }));
22956
+ //#endregion
22957
+ //#region ../theme-core/src/header/surfaceRules.ts
22958
+ /** Compile the at-rest surface independently of scroll treatment and paint geometry. */
22959
+ function buildHeaderSurfaceRules(header, tokens) {
22960
+ const base = [];
22961
+ const background = header.background;
22962
+ if (background.type === "color") base.push(`background-color: ${tokens.getColor(background.color || "surface")};`);
22963
+ else if (background.type === "gradient" && background.gradient) {
22964
+ const stops = background.gradient.stops.map((stop) => tokens.getColor(stop.color)).join(", ");
22965
+ base.push(`background-image: linear-gradient(${background.gradient.angle ?? 180}deg, ${stops});`);
22966
+ }
22967
+ const borderWidth = getComponentBorderWidthPx(header.border?.width ?? "none");
22968
+ if (!header.border || borderWidth === "0") return {
22969
+ base,
22970
+ border: []
22971
+ };
22972
+ const color = rgbColorValue(header.border.colorToken?.trim() || "border");
22973
+ const style = header.border.style === "dashed" ? "dashed" : "solid";
22974
+ return {
22975
+ base,
22976
+ border: header.border.position === "both" ? [`border-top: ${borderWidth} ${style} ${color};`, `border-bottom: ${borderWidth} ${style} ${color};`] : [`border-${header.border.position}: ${borderWidth} ${style} ${color};`]
22977
+ };
22978
+ }
22979
+ var init_surfaceRules = __esmMin((() => {
22980
+ init_shared$4();
22981
+ init_colorStyles();
22982
+ }));
22983
+ //#endregion
22984
+ //#region ../theme-core/src/header/generateHeaderNavLinkStyles.ts
22985
+ function generateHeaderNavLinkStyles(header, themeId, tokens, theme, contrastTreatment, navTextSize) {
22986
+ const style = effectiveHeaderNavLinkStyle(header, contrastTreatment, navTextSize);
22987
+ if (!style) {
22988
+ console.warn(`[generateHeaderCss] Nav link preset not found: ${header.navStyle}`);
22989
+ return "";
22990
+ }
22991
+ return generateNavLinkCSS({
22992
+ themeId,
22993
+ tokens,
22994
+ theme,
22995
+ style: mergeHeaderNavTypographyPreference(style, {
22996
+ typography: header.navFontRole ?? "inherit",
22997
+ fontSize: readHeaderNavFontSizePreference(header.navTextSize),
22998
+ interactionPalette: header.interactionPalette ?? "recommended"
22999
+ }),
23000
+ className: "header-nav-link",
23001
+ surfaceDependent: true,
23002
+ surfaceRestingColor: header.background?.contentOwner === siteChromeBackgroundOverrideOwner
23003
+ });
23004
+ }
23005
+ var init_generateHeaderNavLinkStyles = __esmMin((() => {
23006
+ init_generateNavLinkCSS();
23007
+ init_siteChromeNavPreferences();
23008
+ init_effectiveNavLinkStyle$1();
23009
+ init_rawStyleFields();
23010
+ }));
23011
+ //#endregion
23012
+ //#region ../theme-core/src/header/generateHeaderLogoStyles.ts
23013
+ function generateHeaderLogoStyles(input) {
23014
+ const { logo, themeId, tokens } = input;
23015
+ return `\n${`:where([data-theme-scope="${themeId}"]) .header-logo-text`} {\n ${[
23016
+ ...logoTextColorRules(input),
23017
+ logo?.fontFamily === "body" ? "font-family: var(--font-body);" : "font-family: var(--font-heading);",
23018
+ ...logoLetterSpacingRules(logo),
23019
+ ...logoGradientRules(logo, tokens),
23020
+ ...logoContrastRules(input)
23021
+ ].join("\n ")}\n}\n${mobilePanelLogoColor(input)}`;
23022
+ }
23023
+ function mobilePanelLogoColor(input) {
23024
+ if (input.logo?.gradient) return "";
23025
+ const { themeId, tokens, textColor, fallbackTextColor } = input;
23026
+ const fallback = tokens.getColor(textColor ?? fallbackTextColor ?? "text");
23027
+ return `\n${`:where([data-theme-scope="${themeId}"]) .nav-mobile-panel .header-logo-text`},\n${`:where(.nav-mobile-panel[data-theme-scope="${themeId}"]) .header-logo-text`} {\n color: ${surfaceForegroundValue("text", fallback)};\n}\n`;
23028
+ }
23029
+ function logoTextColorRules(input) {
23030
+ const { logo, textColor, fallbackTextColor, tokens, useSurfaceTextColor } = input;
23031
+ if (logo?.gradient || !textColor && !useSurfaceTextColor) return [];
23032
+ const authoredColor = tokens.getColor(textColor ?? fallbackTextColor ?? "text");
23033
+ return [`color: ${useSurfaceTextColor ? surfaceForegroundValue("text", authoredColor) : authoredColor};`];
23034
+ }
23035
+ function logoLetterSpacingRules(logo) {
23036
+ const spacing = logo?.letterSpacing;
23037
+ if (!spacing || spacing === "normal") return [];
23038
+ return [`letter-spacing: ${{
23039
+ wide: "0.05em",
23040
+ wider: "0.1em",
23041
+ widest: "0.15em"
23042
+ }[spacing]};`];
23043
+ }
23044
+ function logoGradientRules(logo, tokens) {
23045
+ if (!logo?.gradient) return [];
23046
+ return [
23047
+ `background: linear-gradient(to right, ${tokens.getColor("primary")}, ${tokens.getColor("accent")});`,
23048
+ "-webkit-background-clip: text;",
23049
+ "-webkit-text-fill-color: transparent;",
23050
+ "background-clip: text;",
23051
+ "color: transparent;"
23052
+ ];
23053
+ }
23054
+ function logoContrastRules(input) {
23055
+ if (input.logo?.gradient || input.useSurfaceTextColor) return [];
23056
+ const colorToken = input.textColor?.trim() || input.fallbackTextColor?.trim() || "text";
23057
+ const shadow = buildTextContrastShadow({
23058
+ theme: input.theme,
23059
+ colorToken,
23060
+ treatment: input.contrastTreatment
23061
+ });
23062
+ return shadow ? [`text-shadow: ${shadow};`] : [];
23063
+ }
23064
+ var init_generateHeaderLogoStyles = __esmMin((() => {
23065
+ init_generateNavLinkCSS();
23066
+ init_surfaces();
23067
+ }));
23068
+ //#endregion
23069
+ //#region ../theme-core/src/header/generateHeaderCss.ts
23070
+ /**
23071
+ * Generate complete CSS for header system from theme config
23072
+ *
23073
+ * Similar to button system - generates theme-scoped CSS using [data-theme-scope] selector
23074
+ */
23075
+ function generateHeaderCss(options) {
23076
+ const { themeId, theme } = options;
23077
+ const tokens = new TokenResolver(theme);
23078
+ const header = theme.header;
23079
+ const cssChunks = [];
23080
+ const headerContrastTreatment = resolveHeaderContrastTreatment(header);
23081
+ const headerNavTextSize = resolveHeaderNavTextSize(header);
23082
+ cssChunks.push(generateHeaderRootStyles(header, themeId, tokens));
23083
+ cssChunks.push(generateMobileOverlayBackdropFilterFix(themeId, header.variant));
23084
+ cssChunks.push(generateHeaderLogoStyles({
23085
+ logo: header.logo,
23086
+ themeId,
23087
+ tokens,
23088
+ theme,
23089
+ textColor: header.textColor,
23090
+ fallbackTextColor: header.navLinkStyle?.colorToken,
23091
+ contrastTreatment: headerContrastTreatment ?? void 0,
23092
+ useSurfaceTextColor: header.background?.contentOwner === siteChromeBackgroundOverrideOwner
23093
+ }));
23094
+ cssChunks.push(generateLogoTextBehaviorStyles(header.logoText, themeId));
23095
+ cssChunks.push(generateHeaderNavLinkStyles(header, themeId, tokens, theme, headerContrastTreatment, headerNavTextSize));
23096
+ cssChunks.push(generateDropdownContainerStyles(header, themeId, tokens));
23097
+ cssChunks.push(generateDropdownLinkStyles(header, themeId, tokens, theme));
23098
+ cssChunks.push(generateDropdownCaretStyles(themeId));
23099
+ cssChunks.push(generateDropdownTriggerOverrides(header, themeId));
23100
+ cssChunks.push(generateMobilePanelStyles(header, themeId, tokens, theme));
23101
+ if (header.variant === "floating" && header.container) cssChunks.push(generateFloatingContainerStyles(header, themeId, tokens));
23102
+ cssChunks.push(generateNavContainerStyles(header, themeId, tokens));
23103
+ cssChunks.push(generateHeaderCtaTreatmentStyles(header, themeId, tokens));
23104
+ cssChunks.push(generateCtaGapStyles(header, themeId));
23105
+ return cssChunks.filter(Boolean).join("\n\n");
23106
+ }
23107
+ function resolveHeaderContrastTreatment(header) {
23108
+ if (header.navLinkStyle?.contrastTreatment) return header.navLinkStyle.contrastTreatment;
23109
+ return isClearSplitHeaderShape(header) ? "soft-glow" : null;
23110
+ }
23111
+ function resolveHeaderNavTextSize(header) {
23112
+ if (header.navLinkStyle?.textSize) return header.navLinkStyle.textSize;
23113
+ return isClearSplitHeaderShape(header) ? "lg" : null;
23114
+ }
23115
+ function isClearSplitHeaderShape(header) {
23116
+ const hasSharedFloatingSurface = Boolean(header.container);
23117
+ return header.variant === "floating" && (header.navStyle ?? "minimal") === "minimal" && !hasSharedFloatingSurface;
23118
+ }
23119
+ function isDetachedFloatingHeaderShape(header) {
23120
+ return header.variant === "floating" && !header.container;
23121
+ }
23122
+ /**
23123
+ * Generate root header container styles
23124
+ */
23125
+ function generateHeaderRootStyles(header, themeId, tokens) {
23126
+ const selector = `:where([data-theme-scope="${themeId}"]) .header-root`;
23127
+ const rules = [];
23128
+ const isContainedNav = headerRootPaint(header) === "contained-nav";
23129
+ rules.push("position: relative;");
23130
+ rules.push("isolation: isolate;");
23131
+ const surfaceRules = isContainedNav ? {
23132
+ base: [],
23133
+ border: []
23134
+ } : buildHeaderSurfaceRules(header, tokens);
23135
+ const floatingSurfaceBorder = header.variant === "floating";
23136
+ if (!floatingSurfaceBorder) rules.push(...surfaceRules.border);
23137
+ const basePaintRules = floatingSurfaceBorder ? [...surfaceRules.base, ...surfaceRules.border] : surfaceRules.base;
23138
+ const scrolledPaintRules = floatingSurfaceBorder ? surfaceRules.border : [];
23139
+ if (header.positioning === "sticky" || header.positioning === "fixed") {
23140
+ const shadowVar = getComponentShadowVar(header.shadow?.elevation ?? "none");
23141
+ if (shadowVar) rules.push(`box-shadow: ${shadowVar};`);
23142
+ }
23143
+ const baseBlock = `\n${selector} {\n ${rules.join("\n ")}\n}\n`;
23144
+ const overlayFix = `\n${`${selector}:has([data-nav-mobile-overlay][aria-hidden="false"])`} {\n backdrop-filter: none !important;\n -webkit-backdrop-filter: none !important;\n}\n`;
23145
+ const scrollTreatmentStyles = generateHeaderScrollTreatmentStyles(header.scrollTreatment, themeId, header.variant, scrolledPaintRules);
23146
+ if (isContainedNav || basePaintRules.length === 0) return `${baseBlock}\n${overlayFix}${scrollTreatmentStyles}`;
23147
+ return `${baseBlock}\n${renderHeaderPaintTargetRules(getHeaderPaintTargets(header.variant, themeId), basePaintRules)}\n${overlayFix}${scrollTreatmentStyles}`;
23148
+ }
23149
+ function generateLogoTextBehaviorStyles(logoText, themeId) {
23150
+ if (!logoText) return "";
23151
+ const selector = `:where([data-theme-scope="${themeId}"]) .header-logo-text`;
23152
+ const cssChunks = [];
23153
+ const mobileRules = [];
23154
+ if (logoText.mobileWrapLines === 1) {
23155
+ mobileRules.push("display: block;");
23156
+ mobileRules.push("white-space: nowrap;");
23157
+ mobileRules.push("overflow: hidden;");
23158
+ mobileRules.push("text-overflow: ellipsis;");
23159
+ }
23160
+ if (logoText.mobileWrapLines === 2) {
23161
+ mobileRules.push("display: -webkit-box;");
23162
+ mobileRules.push("-webkit-box-orient: vertical;");
23163
+ mobileRules.push("-webkit-line-clamp: 2;");
23164
+ mobileRules.push("white-space: normal;");
23165
+ mobileRules.push("overflow: hidden;");
23166
+ mobileRules.push("text-overflow: ellipsis;");
23167
+ }
23168
+ if (logoText.mobileMaxWidth) mobileRules.push(`max-width: ${{
23169
+ xs: "8rem",
23170
+ sm: "10rem",
23171
+ md: "12rem"
23172
+ }[logoText.mobileMaxWidth]};`);
23173
+ if (mobileRules.length > 0) cssChunks.push(`@media ${MQ_MD_DOWN} {\n ${selector} {\n ${mobileRules.join("\n ")}\n }\n}`);
23174
+ if (logoText.hideOnShrink) {
23175
+ const shrinkSelector = `:where([data-theme-scope="${themeId}"]) .rb-header-shrink.header-scrolled .header-logo-text`;
23176
+ cssChunks.push(`\n${shrinkSelector} {\n display: none;\n}\n`);
23177
+ }
23178
+ return cssChunks.join("\n\n");
23179
+ }
23180
+ /**
23181
+ * Generate dropdown menu container styles
23182
+ */
23183
+ function generateDropdownContainerStyles(header, themeId, tokens) {
23184
+ const selector = `:where([data-theme-scope="${themeId}"]) .nav-dropdown-menu`;
23185
+ const rules = [];
23186
+ const dropdownStyle = header.dropdownStyle;
23187
+ rules.push(...NAV_DROPDOWN_CONTAINER_RAIL_CSS_RULES);
23188
+ const bgToken = dropdownStyle?.background ?? "surface";
23189
+ rules.push(`background-color: ${tokens.getColor(bgToken)};`);
23190
+ const textToken = dropdownStyle?.textColor ?? "text";
23191
+ rules.push(`color: ${tokens.getColor(textToken)};`);
23192
+ const borderToken = dropdownStyle?.borderColor;
23193
+ if (borderToken === null) rules.push(`border: none;`);
23194
+ else rules.push(`border: 1px solid ${tokens.getColor(borderToken ?? "border")};`);
23195
+ const shadowVar = getComponentShadowVar(dropdownStyle?.shadow ?? "md");
23196
+ if (shadowVar) rules.push(`box-shadow: ${shadowVar};`);
23197
+ const borderRadius = dropdownStyle?.borderRadius ?? "md";
23198
+ rules.push(`border-radius: ${{
23199
+ none: "0",
23200
+ sm: "0.25rem",
23201
+ md: "0.5rem",
23202
+ lg: "0.75rem"
23203
+ }[borderRadius]};`);
23204
+ rules.push(`padding: 0.5rem 0;`);
23205
+ return `\n${selector} {\n ${rules.join("\n ")}\n}\n`;
23206
+ }
23207
+ function generateDropdownLinkStyles(header, themeId, tokens, theme) {
23208
+ const configuredDropdownStyle = header.dropdownStyle;
23209
+ const textColorToken = configuredDropdownStyle?.textColor ?? ((header.navColor ?? header.textColor)?.trim() || "text");
23210
+ const hoverBgToken = configuredDropdownStyle?.hoverBackground ?? textColorToken;
23211
+ const hoverEffects = {
23212
+ hover: hoverBgToken === null ? [] : [{
23213
+ effectId: "background-on-hover-alpha",
23214
+ options: {
23215
+ colorToken: hoverBgToken,
23216
+ opacity: 12
23217
+ }
23218
+ }],
23219
+ active: hoverBgToken === null ? [] : [{
23220
+ effectId: "background-on-hover-alpha",
23221
+ options: {
23222
+ colorToken: hoverBgToken,
23223
+ opacity: 18
23224
+ }
23225
+ }]
23226
+ };
23227
+ if (configuredDropdownStyle?.hoverTextColor) {
23228
+ hoverEffects.hover?.push({
23229
+ effectId: "text-color-change",
23230
+ options: { hoverColorToken: configuredDropdownStyle.hoverTextColor }
23231
+ });
23232
+ hoverEffects.active?.push({
23233
+ effectId: "text-color-change",
23234
+ options: { hoverColorToken: configuredDropdownStyle.hoverTextColor }
23235
+ });
23236
+ }
23237
+ const baseCSS = generateNavLinkCSS({
23238
+ themeId,
23239
+ tokens,
23240
+ theme,
23241
+ style: {
23242
+ name: "Dropdown",
23243
+ typography: "body",
23244
+ fontWeight: configuredDropdownStyle?.fontWeight ?? header.navWeight ?? "medium",
23245
+ textTransform: configuredDropdownStyle?.textTransform ?? "none",
23246
+ italic: false,
23247
+ colorToken: textColorToken,
23248
+ padding: "compact",
23249
+ borderRadius: "sm",
23250
+ effects: hoverEffects
23251
+ },
23252
+ className: "nav-dropdown-link"
23253
+ });
23254
+ const additionalRules = [];
23255
+ const letterSpacing = configuredDropdownStyle?.letterSpacing ?? "normal";
23256
+ if (letterSpacing !== "normal") additionalRules.push(`letter-spacing: ${{
23257
+ normal: "0em",
23258
+ wide: "0.05em",
23259
+ wider: "0.1em"
23260
+ }[letterSpacing]};`);
23261
+ const textSize = configuredDropdownStyle?.textSize ?? "sm";
23262
+ additionalRules.push(`font-size: ${{
23263
+ xs: "0.75rem",
23264
+ sm: "0.875rem",
23265
+ base: "1rem",
23266
+ lg: "1.125rem"
23267
+ }[textSize]};`);
23268
+ if (additionalRules.length > 0) return baseCSS + `\n${`:where([data-theme-scope="${themeId}"]) .nav-dropdown-link`} {\n ${additionalRules.join("\n ")}\n}\n`;
23269
+ return baseCSS;
23270
+ }
23271
+ function generateDropdownCaretStyles(themeId) {
23272
+ return `
23273
+ ${`:where([data-theme-scope="${themeId}"]) .nav-caret`} {
23274
+ width: 0.45rem;
23275
+ height: 0.45rem;
23276
+ margin-left: 0.5rem;
23277
+ border-right: 2px solid currentColor;
23278
+ border-bottom: 2px solid currentColor;
23279
+ transform: rotate(45deg) translateY(-1px);
23280
+ transition: transform 150ms ease;
23281
+ }
23282
+
23283
+ ${`:where([data-theme-scope="${themeId}"]) .nav-dropdown-trigger[aria-expanded="true"] .nav-caret, :where([data-theme-scope="${themeId}"]) .nav-mobile-trigger[aria-expanded="true"] .nav-caret`} {
23284
+ transform: rotate(-135deg) translateY(1px);
23285
+ }
23286
+ `.trim();
23287
+ }
23288
+ function generateDropdownTriggerOverrides(header, themeId) {
23289
+ const navStyle = header.navStyle ?? "minimal";
23290
+ if (navStyle !== "underline" && navStyle !== "underline-grow") return "";
23291
+ return `
23292
+ ${`:where([data-theme-scope="${themeId}"]) .nav-dropdown-trigger.header-nav-link::after`} {
23293
+ content: none;
23294
+ }
23295
+ `.trim();
23296
+ }
23297
+ /**
23298
+ * Generate mobile navigation panel styles
23299
+ * Uses the same dropdownStyle settings as the desktop dropdown menus
23300
+ */
23301
+ function generateMobilePanelStyles(header, themeId, tokens, theme) {
23302
+ const selector = `:where([data-theme-scope="${themeId}"]) .nav-mobile-panel`;
23303
+ const selfSelector = `:where(.nav-mobile-panel[data-theme-scope="${themeId}"])`;
23304
+ const dropdownStyle = header.dropdownStyle;
23305
+ const bgToken = dropdownStyle?.background ?? "surface";
23306
+ const textToken = dropdownStyle?.textColor ?? "text";
23307
+ const foreground = resolveSurfaceForeground({
23308
+ type: "color",
23309
+ color: bgToken,
23310
+ textColor: textToken
23311
+ }, expandPalette(theme.palette));
23312
+ const body = renderCssDeclarations([`background-color: ${tokens.getColor(bgToken)};`, ...foreground.kind === "known" ? surfaceForegroundDeclarations(surfaceForegroundInputFromResolved(foreground, (token) => tokens.getColor(token))) : [`color: ${tokens.getColor(textToken)};`]]);
23313
+ return `\n${selector} {\n ${body}\n}\n\n${selfSelector} {\n ${body}\n}\n`;
23314
+ }
23315
+ /**
23316
+ * Generate nav container styles (pill/glass)
23317
+ */
23318
+ function generateNavContainerStyles(header, themeId, tokens) {
23319
+ const navContainer = header.navContainer;
23320
+ const navContainerType = navContainer?.type ?? "none";
23321
+ if (!navContainer || navContainerType === "none") return "";
23322
+ const selector = `:where([data-theme-scope="${themeId}"]) .header-nav-row`;
23323
+ const rules = [];
23324
+ if (navContainerType === "pill" || navContainerType === "glass") {
23325
+ rules.push("padding: 0.5rem 0.75rem;");
23326
+ rules.push("border-radius: 9999px;");
23327
+ rules.push("display: inline-flex;");
23328
+ rules.push("align-items: center;");
23329
+ rules.push("gap: 1.5rem;");
23330
+ if (isDetachedFloatingHeaderShape(header)) rules.push("align-self: flex-start;");
23331
+ }
23332
+ if (navContainerType === "glass") {
23333
+ const opacity = resolveFloatingGlassOpacity(header, navContainer.opacity, .15);
23334
+ const background = navContainer.tint ? buildTint(tokens.getColor(navContainer.tint), opacity) : buildRgbWhite(opacity);
23335
+ rules.push(`background-color: ${background};`);
23336
+ rules.push(`backdrop-filter: ${HEADER_BLUR};`);
23337
+ rules.push(`-webkit-backdrop-filter: ${HEADER_BLUR};`);
23338
+ rules.push("border: 1px solid rgba(255, 255, 255, 0.2);");
23339
+ rules.push("box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);");
23340
+ } else if (navContainerType === "pill") {
23341
+ const opacity = clampOpacity(navContainer.opacity, .15);
23342
+ if (navContainer.tint) rules.push(`background-color: ${buildTint(tokens.getColor(navContainer.tint), opacity)};`);
23343
+ else rules.push(`background-color: ${tokens.getColor("surface")};`);
23344
+ rules.push(`border: 1px solid ${tokens.getColor("border")};`);
23345
+ }
23346
+ if (rules.length > 0) return `${selector} { ${rules.join(" ")} }`;
23347
+ return "";
23348
+ }
23349
+ /**
23350
+ * Generate floating container styles
23351
+ */
23352
+ function generateFloatingContainerStyles(header, themeId, tokens) {
23353
+ const container = header.container;
23354
+ if (!container) return "";
23355
+ const selector = `:where([data-theme-scope="${themeId}"]) .header-floating-container`;
23356
+ const rules = [];
23357
+ const opacity = container.tint === "surface" ? resolveFloatingGlassOpacity(header, container.opacity, .12) : clampOpacity(container.opacity, .12);
23358
+ if (container.tint) rules.push(`background-color: ${buildTint(tokens.getColor(container.tint), opacity)};`);
23359
+ else rules.push(`background-color: ${buildRgbWhite(opacity)};`);
23360
+ rules.push(`backdrop-filter: ${FLOATING_BLUR};`);
23361
+ rules.push(`-webkit-backdrop-filter: ${FLOATING_BLUR};`);
23362
+ if (container.border) rules.push(`border: 1px solid rgb(255 255 255 / 0.2);`);
23363
+ rules.push(`border-radius: ${{
23364
+ none: "0",
23365
+ sm: "0.375rem",
23366
+ md: "0.5rem",
23367
+ lg: "0.75rem",
23368
+ xl: "1rem",
23369
+ "2xl": "1.5rem"
23370
+ }[container.rounded]};`);
23371
+ if (container.shadow) rules.push(`box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);`);
23372
+ rules.push(`padding: ${{
23373
+ sm: "1rem 1.5rem",
23374
+ md: "1.5rem 2rem",
23375
+ lg: "2rem 2.5rem"
23376
+ }[container.padding]};`);
23377
+ return `\n${selector} {\n ${rules.join("\n ")}\n}\n`;
23378
+ }
23379
+ /**
23380
+ * The inverted CTA treatment is contextual to branded header surfaces. It
23381
+ * cannot be represented by the generic secondary button role alone because
23382
+ * that role is transparent and inherits the surrounding surface foreground.
23383
+ * Keep the shared button's structure/effects while making the header own the
23384
+ * palette relationship for both desktop and mobile CTAs.
23385
+ */
23386
+ function generateHeaderCtaTreatmentStyles(header, themeId, tokens) {
23387
+ if (header.ctaTreatment !== "inverted") return "";
23388
+ const desktopSelector = `:where([data-theme-scope="${themeId}"]) .header-cta`;
23389
+ const mobileSelector = `:where([data-theme-scope="${themeId}"]) .nav-mobile-cta`;
23390
+ const selectors = `${desktopSelector},\n${mobileSelector}`;
23391
+ const hoverSelectors = [
23392
+ `${desktopSelector}:hover`,
23393
+ `${desktopSelector}[data-force-hover="true"]`,
23394
+ `${mobileSelector}:hover`,
23395
+ `${mobileSelector}[data-force-hover="true"]`
23396
+ ].join(",\n");
23397
+ const focusSelectors = [`${desktopSelector}:focus-visible`, `${mobileSelector}:focus-visible`].join(",\n");
23398
+ return `
23399
+ ${selectors} {
23400
+ background-color: ${tokens.getColor("background")};
23401
+ background-image: none;
23402
+ color: ${tokens.getColor("onBackground")};
23403
+ border-color: currentColor;
23404
+ }
23405
+
23406
+ ${hoverSelectors} {
23407
+ background-color: ${tokens.getColor("surface")};
23408
+ background-image: none;
23409
+ color: ${tokens.getColor("onSurface")};
23410
+ }
23411
+
23412
+ ${focusSelectors} {
23413
+ outline: 2px solid ${tokens.getColor("onBackground")};
23414
+ outline-offset: 2px;
23415
+ box-shadow: 0 0 0 4px ${tokens.getColor("background")};
23416
+ }
23417
+ `;
23418
+ }
23419
+ /**
23420
+ * Generate CTA button gap styles (left margin between nav links and CTA)
23421
+ */
23422
+ function generateCtaGapStyles(header, themeId) {
23423
+ if (!header.ctaGap) return "";
23424
+ const value = HEADER_CTA_GAP_MAP[header.ctaGap];
23425
+ if (!value) return "";
23426
+ return `\n${`:where([data-theme-scope="${themeId}"]) .header-cta`} {\n margin-left: ${value};\n}\n`;
23427
+ }
23428
+ function clampOpacity(value, fallback) {
23429
+ if (typeof value !== "number" || Number.isNaN(value)) return fallback;
23430
+ return Math.min(Math.max(value, 0), 1);
23431
+ }
23432
+ function resolveFloatingGlassOpacity(header, value, fallback) {
23433
+ const opacity = clampOpacity(value, fallback);
23434
+ return header.variant === "floating" ? Math.max(opacity, .4) : opacity;
23435
+ }
23436
+ function buildTint(color, opacity) {
23437
+ return applyAlpha(color, opacity);
23438
+ }
23439
+ function buildRgbWhite(opacity) {
23440
+ return `rgb(255 255 255 / ${clampOpacity(opacity, 1)})`;
23441
+ }
23442
+ function applyAlpha(color, opacity) {
23443
+ const clamped = clampOpacity(opacity, 1);
23444
+ if (color.startsWith("rgb(") && color.endsWith(")")) {
23445
+ const inner = color.slice(4, -1).trim();
23446
+ return `rgb(${inner.includes("/") ? (inner.split("/")[0] ?? inner).trim() : inner} / ${clamped})`;
23447
+ }
23448
+ return color;
23449
+ }
23450
+ var HEADER_BLUR, FLOATING_BLUR, HEADER_CTA_GAP_MAP;
23451
+ var init_generateHeaderCss = __esmMin((() => {
23452
+ init_resolver$1();
23453
+ init_generateNavLinkCSS();
23454
+ init_shared$4();
23455
+ init_breakpoints();
23456
+ init_navDropdownSizing();
23457
+ init_scrollTreatment();
23458
+ init_paintTargets();
23459
+ init_surfaceRules();
23460
+ init_generateHeaderNavLinkStyles();
23461
+ init_rootPaint();
23462
+ init_rawStyleFields();
23463
+ init_generateHeaderLogoStyles();
23464
+ init_surfaces();
23465
+ init_expandPalette();
23466
+ init_cssDeclarations();
23467
+ HEADER_BLUR = "blur(12px)";
23468
+ FLOATING_BLUR = "blur(16px)";
23469
+ HEADER_CTA_GAP_MAP = {
23470
+ none: "0",
23471
+ tight: "0.5rem",
23472
+ compact: "1rem",
23473
+ default: "1.5rem",
23474
+ relaxed: "2rem",
23475
+ spacious: "3rem"
23476
+ };
23477
+ }));
23478
+ //#endregion
23479
+ //#region ../theme-core/src/header/index.ts
23480
+ var init_header$1 = __esmMin((() => {
23481
+ init_generateHeaderCss();
23482
+ init_rootPaint();
23483
+ init_effectiveNavLinkStyle$1();
23484
+ init_openingForegroundProjection();
23485
+ }));
23486
+ //#endregion
23487
+ //#region ../theme-core/src/footer/effectiveNavLinkStyle.ts
23488
+ function effectiveFooterNavLinkStyle(footer) {
23489
+ if (!footer) return null;
23490
+ if (footer.navLinkStyle) return footer.navLinkStyle;
23491
+ const basePreset = getNavLinkPreset(footer.navStyle ?? "minimal");
23492
+ if (!basePreset) return null;
23493
+ return {
23494
+ ...basePreset,
23495
+ fontWeight: footer.navWeight ?? basePreset.fontWeight,
23496
+ colorToken: footer.navColor?.trim() || basePreset.colorToken
23497
+ };
23498
+ }
23499
+ function footerForegroundCandidates(footer, proseHoverCandidate) {
23500
+ if (!footer) return {};
23501
+ const style = effectiveFooterNavLinkStyle(footer);
23502
+ return {
23503
+ text: footer.background?.textColor,
23504
+ link: style?.colorToken ?? footer.navColor ?? footer.background?.textColor,
23505
+ linkHover: navLinkOwnsHoverForeground(style) ? proseHoverCandidate : navLinkHoverColorCandidate(style)
23506
+ };
23507
+ }
23508
+ var init_effectiveNavLinkStyle = __esmMin((() => {
23509
+ init_presets$1();
23510
+ init_types$9();
23511
+ }));
23512
+ //#endregion
23513
+ //#region ../theme-core/src/footer/generateFooterCss.ts
23514
+ /**
23515
+ * Generate CSS for footer navigation styling
23516
+ *
23517
+ * Similar to header nav but with independent configuration and no advanced effects
23518
+ */
23519
+ function generateFooterCss(options) {
23520
+ const { themeId, theme } = options;
23521
+ const tokens = new TokenResolver(theme);
23522
+ const footer = theme.footer;
23523
+ const cssChunks = [];
23524
+ cssChunks.push(generateFooterNavLinkStyles(footer, themeId, tokens, theme));
23525
+ cssChunks.push(generateFooterLogoStyles(theme, themeId));
23526
+ cssChunks.push(generateFooterBottomTextLinkStyles(footer, themeId, tokens));
23527
+ return cssChunks.filter(Boolean).join("\n\n");
23528
+ }
23529
+ function generateFooterLogoStyles(theme, themeId) {
23530
+ const height = footerLogoHeight(resolveFooterLogoSize(theme.footer, theme.header.logo));
23531
+ return `
23532
+ ${`:where([data-theme-scope="${themeId}"])`} .footer-logo img {
23533
+ width: auto;
23534
+ height: ${height};
23535
+ }
23536
+ `;
23537
+ }
23538
+ function resolveFooterLogoSize(footer, headerLogo) {
23539
+ const brandDrivenSize = footerLogoSizeFromHeaderLogo(headerLogo);
23540
+ return footer.logo?.maxHeight ?? brandDrivenSize ?? footer.logo?.size ?? "md";
23541
+ }
23542
+ function footerLogoSizeFromHeaderLogo(headerLogo) {
23543
+ const size = headerLogo?.size;
23544
+ switch (size) {
23545
+ case "compact": return "sm";
23546
+ case "standard": return "md";
23547
+ case "generous": return "lg";
23548
+ case "display": return "xl";
23549
+ case "auto":
23550
+ case void 0: return null;
23551
+ default: return size;
23552
+ }
23553
+ }
23554
+ function footerLogoHeight(size) {
23555
+ switch (size) {
23556
+ case "sm": return "2.5rem";
23557
+ case "md": return "4rem";
23558
+ case "lg": return "5rem";
23559
+ case "xl": return "6rem";
23560
+ default: return size;
23561
+ }
23562
+ }
23563
+ /**
23564
+ * Generate navigation link styles for footer
23565
+ *
23566
+ * Uses the composable NavLinkStyle system with backward compatibility for
23567
+ * legacy navStyle, navWeight, and navColor settings.
23568
+ */
23569
+ function generateFooterNavLinkStyles(footer, themeId, tokens, theme) {
23570
+ const style = effectiveFooterNavLinkStyle(footer);
23571
+ if (!style) return "";
23572
+ return generateNavLinkCSS({
23573
+ themeId,
23574
+ tokens,
23575
+ theme,
23576
+ style,
23577
+ className: "footer-nav-link",
23578
+ surfaceDependent: true,
23579
+ surfaceRestingColor: footer.background?.contentOwner === siteChromeBackgroundOverrideOwner
23580
+ });
23581
+ }
23582
+ function generateFooterBottomTextLinkStyles(footer, themeId, tokens) {
23583
+ const style = footer.bottomTextLinkStyle;
23584
+ if (!style) return "";
23585
+ const scope = `:where([data-theme-scope="${themeId}"])`;
23586
+ const selectors = [`${scope} .block-site-footer [data-footer-region="bottom"] .rb-prose a`, `${scope} .block-siteFooter [data-footer-region="bottom"] .rb-prose a`];
23587
+ const baseRules = [];
23588
+ const decorationColorToken = style.decorationColorToken?.trim();
23589
+ if (decorationColorToken) baseRules.push(`text-decoration-color: ${tokens.getColor(decorationColorToken)};`);
23590
+ if (style.underline === true) baseRules.push("text-decoration: underline;");
23591
+ else if (style.underline === false) baseRules.push("text-decoration: none;");
23592
+ const cssChunks = [];
23593
+ if (baseRules.length > 0) cssChunks.push(`\n${selectors.join(",\n")} {\n ${baseRules.join("\n ")}\n}\n`);
23594
+ return cssChunks.join("\n");
23595
+ }
23596
+ var init_generateFooterCss = __esmMin((() => {
23597
+ init_resolver$1();
23598
+ init_generateNavLinkCSS();
23599
+ init_effectiveNavLinkStyle();
23600
+ init_rawStyleFields();
23601
+ }));
23602
+ //#endregion
23603
+ //#region ../theme-core/src/footer/index.ts
23604
+ var init_footer = __esmMin((() => {
23605
+ init_generateFooterCss();
23606
+ init_effectiveNavLinkStyle();
23607
+ }));
22326
23608
  function parseBackgroundContent(value) {
22327
23609
  const result = boxBackgroundSchema.safeParse(value);
22328
23610
  return result.success ? result.data : null;
@@ -22344,33 +23626,28 @@ var init_themeColorResolution = __esmMin((() => {
22344
23626
  }));
22345
23627
  //#endregion
22346
23628
  //#region ../blocks/src/system/transforms/registry/_utils/surfaceForegroundStyles.ts
22347
- function resolveHeaderLeafTextColor(header) {
22348
- return header?.textColor ?? header?.navColor ?? header?.background?.textColor ?? header?.navLinkStyle?.colorToken ?? "text";
22349
- }
22350
23629
  function resolveHeaderRootForeground(header, palette, isTransparent) {
22351
- if (isTransparent) return { kind: "unknown" };
23630
+ if (isTransparent) return readOpeningForegroundProjection(header) ?? { kind: "unknown" };
22352
23631
  const background = header?.background;
22353
23632
  return resolveSurfaceForeground(background ?? {
22354
23633
  type: "color",
22355
23634
  color: "surface"
22356
- }, palette, {
22357
- text: header?.textColor ?? background?.textColor,
22358
- link: header?.navLinkStyle?.colorToken ?? header?.navColor ?? header?.textColor
22359
- });
23635
+ }, palette, headerForegroundCandidates(header));
23636
+ }
23637
+ function resolveFooterRootForeground(footer, palette, proseHoverCandidate) {
23638
+ return resolveSurfaceForeground(footer?.background ?? {
23639
+ type: "color",
23640
+ color: "surface"
23641
+ }, palette, footerForegroundCandidates(footer, proseHoverCandidate), { compositeBase: "background" });
22360
23642
  }
22361
23643
  function resolveSurfaceForegroundStyles(value, context, options) {
22362
23644
  const input = parseBackgroundContent(value);
22363
- const foreground = input ? resolveSurfaceForeground(input, context.theme.palette, {}, { compositeBase: options?.fallbackToken }) : { kind: "unknown" };
23645
+ const foreground = input ? resolveSurfaceForeground(input, context.theme.palette, { linkHover: context.proseHoverCandidate }, { compositeBase: options?.fallbackToken }) : { kind: "unknown" };
22364
23646
  const buttonStyles = resolveContextualButtonStyles(input, foreground, context, options);
22365
23647
  if (foreground.kind === "unknown") return buttonStyles;
22366
23648
  return {
22367
23649
  ...buttonStyles,
22368
- ...surfaceForegroundStyle({
22369
- text: resolveBackgroundColorValue(foreground.roles.text, context),
22370
- heading: resolveBackgroundColorValue(foreground.roles.heading, context),
22371
- link: resolveBackgroundColorValue(foreground.roles.link, context),
22372
- supporting: resolveBackgroundColorValue(foreground.roles.supporting, context)
22373
- })
23650
+ ...surfaceForegroundStyle(surfaceForegroundInputFromResolved(foreground, (token) => resolveBackgroundColorValue(token, context)))
22374
23651
  };
22375
23652
  }
22376
23653
  function resolveContextualButtonStyles(background, foreground, context, options) {
@@ -22420,6 +23697,8 @@ function deriveButtonSurfaceInput(background, foreground) {
22420
23697
  var contextualButtonStylesCache;
22421
23698
  var init_surfaceForegroundStyles = __esmMin((() => {
22422
23699
  init_surfaces();
23700
+ init_header$1();
23701
+ init_footer();
22423
23702
  init_buttons();
22424
23703
  init_backgroundContent();
22425
23704
  init_themeColorResolution();
@@ -28814,7 +30093,8 @@ var init_booking_form_reserved_fields = __esmMin((() => {
28814
30093
  "discountCode",
28815
30094
  "selectedSlidingAmountInput",
28816
30095
  "selectedCollectionOptionKind",
28817
- "selectedAppointmentPackageId"
30096
+ "selectedAppointmentPackageId",
30097
+ "mailingListOptIn"
28818
30098
  ];
28819
30099
  BOOKING_FORM_DATA_RESERVED_KEYS = new Set(BOOKING_FORM_DATA_RESERVED_KEY_VALUES);
28820
30100
  }));
@@ -29238,6 +30518,7 @@ function prepareBookingSubmission(input) {
29238
30518
  startAt: selectedSlot,
29239
30519
  endAt: endDate.toISOString(),
29240
30520
  customFields: collectBookingCustomFields(input.data),
30521
+ ...selectedMailingListOptIn(input.data),
29241
30522
  timezone: toBookingTimeZone(input.viewerTimeZone ?? null)
29242
30523
  };
29243
30524
  if (customerPassId) return {
@@ -29288,6 +30569,9 @@ function prepareBookingSubmission(input) {
29288
30569
  }
29289
30570
  };
29290
30571
  }
30572
+ function selectedMailingListOptIn(data) {
30573
+ return data.mailingListOptIn === true ? { mailingListOptIn: true } : {};
30574
+ }
29291
30575
  function formatBookingSubmissionPreparationError(error) {
29292
30576
  switch (error.tag) {
29293
30577
  case "missing-required-booking-information": return "Missing required booking information";
@@ -29433,8 +30717,9 @@ function buildBookingFormInteractiveIslandProps(props) {
29433
30717
  source: props
29434
30718
  });
29435
30719
  }
29436
- var blockBookingPaymentTermsAvailabilitySchema, bookingServiceSchema, bookingServiceCategorySchema, bookingServicesSourceSchema, bookingConfigSchema, bookingSourceSchema, bookingDisplaySchema, bookingHydrationSchema, bookingRenderSchema, bookingFormIslandMetaCodec, bookingFormIslandMetaKeys, bookingFormBlockRuntime, bookingFormInteractiveIslandPropsCodec;
30720
+ var blockBookingPaymentTermsAvailabilitySchema, bookingServiceSchema, bookingServiceCategorySchema, bookingServicesSourceSchema, bookingConfigSchema, bookingMailingListContextSchema, bookingSourceSchema, bookingDisplaySchema, bookingHydrationSchema, bookingRenderSchema, bookingFormIslandMetaCodec, bookingFormIslandMetaKeys, bookingFormBlockRuntime, bookingFormInteractiveIslandPropsCodec;
29437
30721
  var init_booking_form_interactive = __esmMin((() => {
30722
+ init_src$2();
29438
30723
  init_islands();
29439
30724
  init_runtime();
29440
30725
  init_booking_form_state();
@@ -29487,7 +30772,14 @@ var init_booking_form_interactive = __esmMin((() => {
29487
30772
  fields: z$1.array(bookingFieldSchema)
29488
30773
  }).optional()
29489
30774
  });
30775
+ bookingMailingListContextSchema = z$1.unknown().transform((value) => {
30776
+ if (value === void 0) return void 0;
30777
+ const parsed = parseMailingListRuntimeContext(value);
30778
+ return parsed.ok ? parsed.value : void 0;
30779
+ });
29490
30780
  bookingSourceSchema = z$1.object({
30781
+ mailingList: bookingMailingListContextSchema.optional(),
30782
+ siteName: z$1.string().optional(),
29491
30783
  siteId: z$1.string().optional(),
29492
30784
  apiBaseUrl: z$1.string().optional(),
29493
30785
  portalToken: z$1.string().nullable().optional(),
@@ -29516,6 +30808,8 @@ var init_booking_form_interactive = __esmMin((() => {
29516
30808
  message: z$1.string().nullable()
29517
30809
  });
29518
30810
  bookingHydrationSchema = z$1.object({
30811
+ mailingList: bookingMailingListContextSchema.optional(),
30812
+ siteName: z$1.string().optional(),
29519
30813
  formId: z$1.string().nullable(),
29520
30814
  serviceId: z$1.string().nullable(),
29521
30815
  resourceId: z$1.string().nullable(),
@@ -29552,6 +30846,8 @@ var init_booking_form_interactive = __esmMin((() => {
29552
30846
  return {
29553
30847
  display: buildBookingFormDisplay(source, form),
29554
30848
  hydration: {
30849
+ mailingList: source.mailingList,
30850
+ siteName: source.siteName,
29555
30851
  formId: form?.id ?? source.formId ?? null,
29556
30852
  serviceId: source.serviceId ?? form?.settings?.serviceId ?? null,
29557
30853
  resourceId: source.resourceId ?? form?.settings?.resourceId ?? null,
@@ -34546,6 +35842,7 @@ function buildEventRegistrationInteractiveIslandProps(props) {
34546
35842
  }
34547
35843
  var EVENT_REGISTRATION_GENERIC_SHELL_STEP_LABELS, EVENT_REGISTRATION_SHELL_STEP_LABELS, eventRegistrationPublicEventSchema, eventRegistrationHydrationSchemaShape, eventRegistrationEventSourceSchema, eventRegistrationSourceSchema, eventRegistrationDisplaySchema, eventRegistrationHydrationSchema, eventRegistrationRenderSchema, eventRegistrationIslandMetaCodec, eventRegistrationIslandMetaKeys, eventRegistrationBlockRuntime, eventRegistrationInteractiveIslandPropsCodec;
34548
35844
  var init_event_registration_interactive = __esmMin((() => {
35845
+ init_src$2();
34549
35846
  init_readAuthority();
34550
35847
  init_schemas();
34551
35848
  init_runGrouping();
@@ -34585,7 +35882,13 @@ var init_event_registration_interactive = __esmMin((() => {
34585
35882
  spamProtectionEnabled: z$1.boolean().optional(),
34586
35883
  supportEmail: z$1.string().optional(),
34587
35884
  sitePasses: publicPassProductCollectionSchema.nullable().optional(),
34588
- siteMemberships: publicMembershipProductCollectionSchema.nullable().optional()
35885
+ siteMemberships: publicMembershipProductCollectionSchema.nullable().optional(),
35886
+ mailingList: z$1.unknown().transform((value) => {
35887
+ if (value === void 0) return void 0;
35888
+ const parsed = parseMailingListRuntimeContext(value);
35889
+ return parsed.ok ? parsed.value : void 0;
35890
+ }),
35891
+ siteName: z$1.string().optional()
34589
35892
  };
34590
35893
  eventRegistrationEventSourceSchema = z$1.discriminatedUnion("kind", [z$1.object({
34591
35894
  kind: z$1.literal("loaded"),
@@ -34672,7 +35975,9 @@ var init_event_registration_interactive = __esmMin((() => {
34672
35975
  spamProtectionEnabled: source.spamProtectionEnabled,
34673
35976
  supportEmail: source.supportEmail,
34674
35977
  sitePasses: source.sitePasses ?? null,
34675
- siteMemberships: source.siteMemberships ?? null
35978
+ siteMemberships: source.siteMemberships ?? null,
35979
+ mailingList: source.mailingList,
35980
+ siteName: source.siteName
34676
35981
  }
34677
35982
  };
34678
35983
  }
@@ -36396,6 +37701,64 @@ function defineEndpointDefinitions(definitions) {
36396
37701
  return definitions;
36397
37702
  }
36398
37703
  //#endregion
37704
+ //#region ../api/src/apiEndpointTypes.ts
37705
+ function allowedDemoMutationPolicy() {
37706
+ return {
37707
+ classification: "allowed",
37708
+ publicMessage: ""
37709
+ };
37710
+ }
37711
+ function blockedDemoMutationPolicy(classification, publicMessage) {
37712
+ if (publicMessage.trim() === "") throw new Error(`Demo mutation policy ${classification} requires publicMessage.`);
37713
+ return {
37714
+ classification,
37715
+ publicMessage
37716
+ };
37717
+ }
37718
+ //#endregion
37719
+ //#region ../api/src/demoMutationPolicies.ts
37720
+ const DEMO_MUTATION_BLOCKED_HIDDEN = blockedDemoMutationPolicy("blocked-hidden", "This action is not available in demo sites.");
37721
+ const DEMO_MUTATION_BLOCKED_DISABLED = blockedDemoMutationPolicy("blocked-disabled", "This setting is disabled in demo sites.");
37722
+ const DEMO_MUTATION_INTERNAL_ONLY = blockedDemoMutationPolicy("internal-only", "This internal operation is not available in demo sites.");
37723
+ const DEMO_MUTATION_ALLOWED = allowedDemoMutationPolicy();
37724
+ //#endregion
37725
+ //#region ../api/src/siteLifecycleEndpoints.ts
37726
+ const SITE_LIFECYCLE_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
37727
+ createSite: {
37728
+ path: "/sites/manage",
37729
+ method: "POST",
37730
+ tags: ["site"],
37731
+ auth: "user",
37732
+ responseKind: "json",
37733
+ errors: []
37734
+ },
37735
+ createSiteManual: {
37736
+ path: "/sites/manual",
37737
+ method: "POST",
37738
+ tags: ["site"],
37739
+ auth: "user",
37740
+ responseKind: "json",
37741
+ errors: []
37742
+ },
37743
+ updateSite: {
37744
+ path: "/sites/manage",
37745
+ method: "PUT",
37746
+ tags: ["site"],
37747
+ auth: "user",
37748
+ responseKind: "json",
37749
+ errors: []
37750
+ },
37751
+ deleteSite: {
37752
+ path: "/sites/{siteId}",
37753
+ method: "DELETE",
37754
+ tags: ["site", "site-{siteId}"],
37755
+ auth: "user",
37756
+ responseKind: "json",
37757
+ errors: [],
37758
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
37759
+ }
37760
+ });
37761
+ //#endregion
36399
37762
  //#region ../api/src/publicNewsletterEndpointDefinitions.ts
36400
37763
  const PUBLIC_NEWSLETTER_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
36401
37764
  subscribeNewsletter: {
@@ -36455,27 +37818,6 @@ const PUBLIC_NEWSLETTER_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
36455
37818
  responseKind: "text"
36456
37819
  }
36457
37820
  });
36458
- //#endregion
36459
- //#region ../api/src/apiEndpointTypes.ts
36460
- function allowedDemoMutationPolicy() {
36461
- return {
36462
- classification: "allowed",
36463
- publicMessage: ""
36464
- };
36465
- }
36466
- function blockedDemoMutationPolicy(classification, publicMessage) {
36467
- if (publicMessage.trim() === "") throw new Error(`Demo mutation policy ${classification} requires publicMessage.`);
36468
- return {
36469
- classification,
36470
- publicMessage
36471
- };
36472
- }
36473
- //#endregion
36474
- //#region ../api/src/demoMutationPolicies.ts
36475
- const DEMO_MUTATION_BLOCKED_HIDDEN = blockedDemoMutationPolicy("blocked-hidden", "This action is not available in demo sites.");
36476
- const DEMO_MUTATION_BLOCKED_DISABLED = blockedDemoMutationPolicy("blocked-disabled", "This setting is disabled in demo sites.");
36477
- const DEMO_MUTATION_INTERNAL_ONLY = blockedDemoMutationPolicy("internal-only", "This internal operation is not available in demo sites.");
36478
- const DEMO_MUTATION_ALLOWED = allowedDemoMutationPolicy();
36479
37821
  /**
36480
37822
  * Tag templates for endpoint definitions (support `{param}` placeholders).
36481
37823
  */
@@ -37501,6 +38843,20 @@ const NEWSLETTER_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
37501
38843
  responseKind: "json",
37502
38844
  errors: ["auth:forbidden", "server:internal_error"]
37503
38845
  },
38846
+ setMailingListBookingOptIn: {
38847
+ path: "/sites/{siteId}/mailing-list/setup/booking-opt-in",
38848
+ method: "PUT",
38849
+ tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteNewsletter],
38850
+ auth: "user",
38851
+ responseKind: "json",
38852
+ demoMutation: DEMO_MUTATION_BLOCKED_DISABLED,
38853
+ errors: [
38854
+ "auth:forbidden",
38855
+ "validation:invalid_input",
38856
+ "resource:conflict",
38857
+ "server:internal_error"
38858
+ ]
38859
+ },
37504
38860
  getMailingListAuthoringContext: {
37505
38861
  path: "/sites/{siteId}/mailing-list/authoring-context",
37506
38862
  method: "GET",
@@ -38828,6 +40184,54 @@ const BILLING_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
38828
40184
  }
38829
40185
  });
38830
40186
  //#endregion
40187
+ //#region ../api/src/bookingPeopleEndpointDefinitions.ts
40188
+ /**
40189
+ * People endpoints (#1356): the People list, its CSV export, and deleting a
40190
+ * person when nothing is attached to them.
40191
+ */
40192
+ const BOOKING_PEOPLE_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
40193
+ listPeople: {
40194
+ path: "/sites/{siteId}/bookings/people",
40195
+ method: "GET",
40196
+ tags: ["site-{siteId}", "customers-{siteId}"],
40197
+ auth: "user",
40198
+ responseKind: "json",
40199
+ errors: ["server:internal_error"]
40200
+ },
40201
+ exportPeopleCsv: {
40202
+ path: "/sites/{siteId}/bookings/people/export.csv",
40203
+ method: "GET",
40204
+ tags: ["site-{siteId}", "customers-{siteId}"],
40205
+ auth: "user",
40206
+ errors: [],
40207
+ responseKind: "blob"
40208
+ },
40209
+ checkPersonDeletion: {
40210
+ path: "/sites/{siteId}/bookings/people/{personId}/deletion-check",
40211
+ method: "GET",
40212
+ tags: ["site-{siteId}", "customers-{siteId}"],
40213
+ auth: "user",
40214
+ responseKind: "json",
40215
+ errors: [
40216
+ "auth:forbidden",
40217
+ "resource:not_found",
40218
+ "server:internal_error"
40219
+ ]
40220
+ },
40221
+ deletePerson: {
40222
+ path: "/sites/{siteId}/bookings/people/{personId}",
40223
+ method: "DELETE",
40224
+ tags: ["site-{siteId}", "customers-{siteId}"],
40225
+ auth: "user",
40226
+ responseKind: "json",
40227
+ errors: [
40228
+ "auth:forbidden",
40229
+ "resource:not_found",
40230
+ "server:internal_error"
40231
+ ]
40232
+ }
40233
+ });
40234
+ //#endregion
38831
40235
  //#region ../api/src/clientErrorReporting.ts
38832
40236
  const CLIENT_ERROR_REPORT_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({ reportClientError: {
38833
40237
  path: "/client/error-report",
@@ -38863,6 +40267,7 @@ z$1.object({
38863
40267
  sourceLocation: z$1.string().max(CLIENT_ERROR_REPORT_LIMITS.sourceLocation).nullable()
38864
40268
  }).strict();
38865
40269
  const API_ENDPOINTS$1 = {
40270
+ ...SITE_LIFECYCLE_ENDPOINT_DEFINITIONS,
38866
40271
  ...CLIENT_ERROR_REPORT_ENDPOINT_DEFINITIONS,
38867
40272
  ...PUBLIC_NEWSLETTER_ENDPOINT_DEFINITIONS,
38868
40273
  ...ACCOUNT_ENDPOINT_DEFINITIONS,
@@ -39398,13 +40803,6 @@ const API_ENDPOINTS$1 = {
39398
40803
  auth: "user",
39399
40804
  responseKind: "json"
39400
40805
  },
39401
- createSiteManual: {
39402
- path: "/sites/manual",
39403
- method: "POST",
39404
- tags: ["site"],
39405
- auth: "user",
39406
- responseKind: "json"
39407
- },
39408
40806
  listSiteMembers: {
39409
40807
  path: "/sites/{siteId}/members",
39410
40808
  method: "GET",
@@ -42910,21 +44308,7 @@ const API_ENDPOINTS$1 = {
42910
44308
  responseKind: "json",
42911
44309
  errors: []
42912
44310
  },
42913
- listBookingCustomers: {
42914
- path: "/sites/{siteId}/bookings/customers",
42915
- method: "GET",
42916
- tags: ["site-{siteId}", "customers-{siteId}"],
42917
- auth: "user",
42918
- responseKind: "json"
42919
- },
42920
- exportBookingCustomersCsv: {
42921
- path: "/sites/{siteId}/bookings/customers/export.csv",
42922
- method: "GET",
42923
- tags: ["site-{siteId}", "customers-{siteId}"],
42924
- auth: "user",
42925
- errors: [],
42926
- responseKind: "blob"
42927
- },
44311
+ ...BOOKING_PEOPLE_ENDPOINT_DEFINITIONS,
42928
44312
  createBookingCustomer: {
42929
44313
  path: "/sites/{siteId}/bookings/customers",
42930
44314
  method: "POST",
@@ -43015,13 +44399,6 @@ const API_ENDPOINTS$1 = {
43015
44399
  "server:internal_error"
43016
44400
  ]
43017
44401
  },
43018
- listCustomerAttendances: {
43019
- path: "/sites/{siteId}/bookings/customers/{customerId}/attendances",
43020
- method: "GET",
43021
- tags: ["site-{siteId}", "customers-{siteId}"],
43022
- auth: "user",
43023
- responseKind: "json"
43024
- },
43025
44402
  createPersonRecordEntry: {
43026
44403
  path: "/sites/{siteId}/bookings/person-records/entries",
43027
44404
  method: "POST",
@@ -45267,6 +46644,8 @@ init_colorStyles();
45267
46644
  init_surfaces();
45268
46645
  init_siteChromePlacement();
45269
46646
  init_runtimeContract();
46647
+ init_header$1();
46648
+ init_site_styles();
45270
46649
  init_surfaceForegroundStyles();
45271
46650
  const joinClasses$5 = (parts) => parts.filter((part) => typeof part === "string" && part.trim().length > 0).join(" ").replace(/\s+/g, " ").trim();
45272
46651
  function resolveHeaderBrandDisplay(logo) {
@@ -45372,10 +46751,7 @@ function resolveBackgroundVisualStyles(backgroundColor, defaultToken = "surface"
45372
46751
  };
45373
46752
  }
45374
46753
  function resolveHeaderVisualStyles(header) {
45375
- const navContainerType = header?.navContainer?.type ?? "none";
45376
- const hasContainedNav = navContainerType === "glass" || navContainerType === "pill";
45377
- const hasOverlayVariant = header?.variant === "floating";
45378
- if (hasContainedNav || hasOverlayVariant) return {
46754
+ if (headerRootPaint(header) !== "own-surface") return {
45379
46755
  backgroundToken: "transparent",
45380
46756
  isTransparent: true
45381
46757
  };
@@ -45386,23 +46762,7 @@ function resolveHeaderVisualStyles(header) {
45386
46762
  }
45387
46763
  function resolvedForegroundStyle(foreground) {
45388
46764
  if (foreground.kind === "unknown") return void 0;
45389
- const { roles } = foreground;
45390
- return surfaceForegroundStyle({
45391
- text: rgbColorValue(roles.text),
45392
- heading: rgbColorValue(roles.heading),
45393
- link: rgbColorValue(roles.link),
45394
- supporting: rgbColorValue(roles.supporting)
45395
- });
45396
- }
45397
- function resolveFooterRootForeground(footer, palette) {
45398
- const background = footer?.background;
45399
- return resolveSurfaceForeground(background ?? {
45400
- type: "color",
45401
- color: "surface"
45402
- }, palette, {
45403
- text: background?.textColor,
45404
- link: footer?.navLinkStyle?.colorToken ?? footer?.navColor ?? background?.textColor
45405
- });
46765
+ return surfaceForegroundStyle(surfaceForegroundInputFromResolved(foreground, rgbColorValue));
45406
46766
  }
45407
46767
  function footerBottomBarBorderWidthStyle(width) {
45408
46768
  if (!width) return void 0;
@@ -45429,8 +46789,7 @@ const headerRootClassTransform = {
45429
46789
  const placement = planSiteChromePlacement(parseHeaderPositioning(content.positioning));
45430
46790
  const header = asPartialObject(value);
45431
46791
  const visuals = resolveHeaderVisualStyles(header);
45432
- const navContainerType = header?.navContainer?.type ?? "none";
45433
- const hasContainedNav = navContainerType === "glass" || navContainerType === "pill";
46792
+ const hasContainedNav = headerRootPaint(header) === "contained-nav";
45434
46793
  const backgroundClass = visuals.isTransparent || hasContainedNav ? "rb-bg-transparent" : null;
45435
46794
  const classes = [config.base, backgroundClass];
45436
46795
  if (!hasContainedNav) {
@@ -45473,7 +46832,7 @@ const headerRootStyleTransform = {
45473
46832
  run: (value, _options, context) => {
45474
46833
  const header = asPartialObject(value);
45475
46834
  const visuals = resolveHeaderVisualStyles(header);
45476
- return mergeStyles(resolvedForegroundStyle(resolveHeaderRootForeground(header, context.theme.palette, visuals.isTransparent)) ?? { color: rgbColorValue(resolveHeaderLeafTextColor(header)) }, borderColorStyle(header?.border?.colorToken ?? "border"));
46835
+ return mergeStyles(resolvedForegroundStyle(resolveHeaderRootForeground(header, context.theme.palette, visuals.isTransparent)) ?? (visuals.isTransparent ? surfaceForegroundStyle(transparentHeaderForegroundInput(header, context.theme.palette)) : { color: rgbColorValue(headerLeafTextColor(header)) }), borderColorStyle(header?.border?.colorToken ?? "border"));
45477
46836
  }
45478
46837
  };
45479
46838
  const headerSectionBackgroundTransform = {
@@ -45481,9 +46840,7 @@ const headerSectionBackgroundTransform = {
45481
46840
  kind: "string",
45482
46841
  summary: "Resolve the inner site-header section background token",
45483
46842
  run: (value) => {
45484
- const header = asPartialObject(value);
45485
- const navContainerType = header?.navContainer?.type ?? "none";
45486
- return header?.variant === "floating" || navContainerType === "glass" || navContainerType === "pill" ? "raw:transparent" : "background";
46843
+ return headerRootPaint(asPartialObject(value)) !== "own-surface" ? "raw:transparent" : "background";
45487
46844
  }
45488
46845
  };
45489
46846
  const footerRootStyleTransform = {
@@ -45501,7 +46858,7 @@ const footerRootStyleTransform = {
45501
46858
  styleParts.push(backgroundColorStyle(token));
45502
46859
  }
45503
46860
  }
45504
- styleParts.push(resolvedForegroundStyle(resolveFooterRootForeground(footer, context.theme.palette)));
46861
+ styleParts.push(resolvedForegroundStyle(resolveFooterRootForeground(footer, context.theme.palette, context.proseHoverCandidate)));
45505
46862
  styleParts.push(borderColorStyle("border"));
45506
46863
  return mergeStyles(...styleParts);
45507
46864
  }
@@ -45563,22 +46920,28 @@ const footerBottomBarStyleTransform = {
45563
46920
  run: (value, _options, context) => {
45564
46921
  const footer = asPartialObject(value);
45565
46922
  const bottomBar = footer?.bottomBar;
45566
- const styleParts = [];
45567
- const background = bottomBar?.background;
45568
- if (background?.type === "color") styleParts.push(backgroundColorStyle(background.color ?? "surface"));
45569
- styleParts.push(borderColorStyle(bottomBar?.borderTop?.colorToken ?? "border"), footerBottomBarBorderWidthStyle(bottomBar?.borderTop?.width));
45570
- const foreground = resolveSurfaceForeground(background?.type === "color" ? background : {
45571
- type: "color",
45572
- color: "transparent"
45573
- }, context.theme.palette, {
45574
- text: bottomBar?.textColor,
45575
- link: footer?.bottomTextLinkStyle?.colorToken ?? bottomBar?.textColor
45576
- });
45577
- if (background?.type === "color") styleParts.push(resolvedForegroundStyle(foreground));
45578
- else if (bottomBar?.textColor) styleParts.push(textColorStyle(bottomBar.textColor));
45579
- return mergeStyles(...styleParts);
46923
+ return mergeStyles(bottomBar?.background?.type === "color" ? backgroundColorStyle(bottomBar.background.color ?? "surface") : void 0, borderColorStyle(bottomBar?.borderTop?.colorToken ?? "border"), footerBottomBarBorderWidthStyle(bottomBar?.borderTop?.width), footerBottomBarForegroundStyle(footer, context.theme.palette));
45580
46924
  }
45581
46925
  };
46926
+ function footerBottomBarForegroundStyle(footer, palette) {
46927
+ if (!footer?.bottomBar) return void 0;
46928
+ const bar = footer.bottomBar;
46929
+ if (bar.background?.type !== "color") return backgroundlessBottomBarForegroundStyle(footer);
46930
+ return resolvedForegroundStyle(resolveSurfaceForeground(bar.background, palette, {
46931
+ text: bar.textColor,
46932
+ link: footer.bottomTextLinkStyle?.colorToken ?? bar.textColor,
46933
+ linkHover: footer.bottomTextLinkStyle?.hoverColorToken
46934
+ }, { compositeBase: measuredFooterBackdrop(footer, palette) }));
46935
+ }
46936
+ function backgroundlessBottomBarForegroundStyle(footer) {
46937
+ if (footer.background?.contentOwner === "site-chrome-editor") return;
46938
+ const textColor = footer.bottomBar?.textColor;
46939
+ return textColor ? textColorStyle(textColor) : void 0;
46940
+ }
46941
+ function measuredFooterBackdrop(footer, palette) {
46942
+ const foreground = resolveFooterRootForeground(footer, palette);
46943
+ return foreground.kind === "known" && foreground.provenance.kind === "measured" ? foreground.provenance.backdropHex : null;
46944
+ }
45582
46945
  const footerSplitMainClassTransform = {
45583
46946
  id: "layout.footerSplitMainClass",
45584
46947
  kind: "string",
@@ -45666,6 +47029,7 @@ const layoutTransforms = [
45666
47029
  init_surfaces();
45667
47030
  init_core$1();
45668
47031
  init_surfaceForegroundStyles();
47032
+ init_header$1();
45669
47033
  const chromeLogoSchema = z$1.object({ surface: z$1.enum([
45670
47034
  "header-root",
45671
47035
  "header-mobile-panel",
@@ -45677,7 +47041,7 @@ function chromeSurfaceTextToken(surface, theme, palette) {
45677
47041
  case "header-root": {
45678
47042
  const header = theme.header;
45679
47043
  const foreground = resolveHeaderRootForeground(header, palette, resolveHeaderVisualStyles(header).isTransparent);
45680
- return foreground.kind === "known" ? foreground.roles.text : resolveHeaderLeafTextColor(header);
47044
+ return foreground.kind === "known" ? foreground.roles.text : headerLeafTextColor(header);
45681
47045
  }
45682
47046
  case "header-mobile-panel": return theme.header?.dropdownStyle?.textColor ?? "text";
45683
47047
  case "footer-root": {
@@ -48695,34 +50059,15 @@ init_booking_form_interactive();
48695
50059
  * own `.rb-reg-surface`, and leaves no stale loading state on the mounted form.
48696
50060
  * `event-registration.server.tsx` follows the same shape.
48697
50061
  */
48698
- function BookingFormSSR({ blockId, siteId, apiBaseUrl, portalToken, formId, serviceId, resourceId, initialData, noticeMessage, requiresServiceSelection, requiresResourceSelection, shouldAutoSelectSingleResource, rebookContext, submitLabel, successMessage, form, services, spamProtectionEnabled, className, children }) {
48699
- const islandProps = buildBookingFormInteractiveIslandProps({
48700
- siteId,
48701
- apiBaseUrl,
48702
- portalToken,
48703
- formId,
48704
- serviceId,
48705
- resourceId,
48706
- initialData,
48707
- noticeMessage,
48708
- requiresServiceSelection,
48709
- requiresResourceSelection,
48710
- shouldAutoSelectSingleResource,
48711
- rebookContext,
48712
- submitLabel,
48713
- successMessage,
48714
- form,
48715
- services,
48716
- spamProtectionEnabled,
48717
- className
48718
- });
50062
+ function BookingFormSSR({ blockId, children, ...sourceProps }) {
50063
+ const islandProps = buildBookingFormInteractiveIslandProps(sourceProps);
48719
50064
  const display = islandProps.render.display;
48720
50065
  return /* @__PURE__ */ jsxs("div", {
48721
50066
  ...getIslandRootProps("booking-form", blockId),
48722
50067
  children: [
48723
50068
  /* @__PURE__ */ jsx(IslandPropsScript, { value: islandProps }),
48724
50069
  display.state === "missing" ? /* @__PURE__ */ jsx("div", {
48725
- className: `rb-reg-surface booking-form-ssr ${className ?? ""}`.trim(),
50070
+ className: `rb-reg-surface booking-form-ssr ${sourceProps.className ?? ""}`.trim(),
48726
50071
  children: /* @__PURE__ */ jsx("div", {
48727
50072
  className: "alert alert-error",
48728
50073
  role: "alert",
@@ -48732,7 +50077,7 @@ function BookingFormSSR({ blockId, siteId, apiBaseUrl, portalToken, formId, serv
48732
50077
  })
48733
50078
  })
48734
50079
  }) : /* @__PURE__ */ jsxs("div", {
48735
- className: `rb-reg-surface booking-form-ssr ab-shell ${className ?? ""}`.trim(),
50080
+ className: `rb-reg-surface booking-form-ssr ab-shell ${sourceProps.className ?? ""}`.trim(),
48736
50081
  "aria-busy": true,
48737
50082
  "aria-label": "Loading booking form",
48738
50083
  role: "status",
@@ -51439,6 +52784,8 @@ const eventRegistrationBlockDefinition = {
51439
52784
  events: { $bind: { from: "data.events" } },
51440
52785
  wholeSeriesRunEvents: { $bind: { from: "data.wholeSeriesRunEvents" } },
51441
52786
  loaderFailures: { $bind: { from: "$root.loaderFailures" } },
52787
+ mailingList: { $bind: { from: "$root.mailingList" } },
52788
+ siteName: { $bind: { from: "$root.siteName" } },
51442
52789
  sitePasses: { $bind: { from: "data.sitePasses" } },
51443
52790
  siteMemberships: { $bind: { from: "data.siteMemberships" } },
51444
52791
  stage: { $bind: {
@@ -53198,18 +54545,11 @@ const newsletterSignupManifest = createBlockManifest({
53198
54545
  ],
53199
54546
  icon: "Mail"
53200
54547
  });
54548
+ const newsletterPublicFieldIds = [...(newsletterSignupManifest.fields ?? []).map((field) => field.id), "_containerStyles"];
53201
54549
  function sanitizeNewsletterSignupPublicContent(content) {
53202
54550
  if (typeof content !== "object" || content === null || Array.isArray(content)) return content;
53203
54551
  const value = content;
53204
- return {
53205
- title: value.title,
53206
- subtitle: value.subtitle,
53207
- targeting: value.targeting,
53208
- buttonVariant: value.buttonVariant,
53209
- mailingListSource: value.mailingListSource,
53210
- mailingListSourceToken: value.mailingListSourceToken,
53211
- _sectionStyles: value._sectionStyles
53212
- };
54552
+ return Object.fromEntries(newsletterPublicFieldIds.map((id) => [id, value[id]]));
53213
54553
  }
53214
54554
  const newsletterSignupBlockDefinition = {
53215
54555
  manifest: newsletterSignupManifest,
@@ -56514,6 +57854,7 @@ function applyTransformsAndFallback(value, binding, context) {
56514
57854
  options: step.options
56515
57855
  })) ?? [], {
56516
57856
  theme: context.theme ?? defaultThemeTokens,
57857
+ proseHoverCandidate: context.proseHoverCandidate,
56517
57858
  stage,
56518
57859
  data: resolveTransformData(context, binding.from),
56519
57860
  routes: routeMap,
@@ -57430,6 +58771,8 @@ init_types$12();
57430
58771
  init_constants$1();
57431
58772
  init_colorStyles();
57432
58773
  init_surfaces();
58774
+ init_expandPalette();
58775
+ init_cssDeclarations();
57433
58776
  /**
57434
58777
  * Corner radius map for accordion surfaces. Pill is capped here because FAQ
57435
58778
  * rows contain long text and expanded content; full capsules clip awkwardly.
@@ -57462,14 +58805,7 @@ function generateAccordionCss({ themeId, theme, accordionSystem }) {
57462
58805
  const questionColumnsItemSelector = `${rootSelector}.rb-faq-question-columns .accordion-item`;
57463
58806
  const questionColumnsLastItemSelector = `${questionColumnsItemSelector}:last-child`;
57464
58807
  const questionColumnsTriggerSelector = `${questionColumnsItemSelector} .accordion-trigger`;
57465
- const rootRules = [];
57466
- if (accordionSystem.background) {
57467
- rootRules.push(`background-color: ${rgbColorValue(accordionSystem.background.colorToken)}`);
57468
- rootRules.push(...surfaceForegroundDeclarations({
57469
- text: rgbColorValue(accordionSystem.content.textColorToken),
57470
- heading: rgbColorValue(accordionSystem.trigger.textColorToken)
57471
- }));
57472
- }
58808
+ const rootRules = accordionSurfaceRules(theme, accordionSystem);
57473
58809
  const borderRadius = CORNER_MAP$2[accordionSystem.corners ?? theme.corners];
57474
58810
  rootRules.push(`border-radius: ${borderRadius}`);
57475
58811
  if (accordionSystem.border) {
@@ -57588,7 +58924,7 @@ function generateAccordionCss({ themeId, theme, accordionSystem }) {
57588
58924
  }
57589
58925
  }
57590
58926
  const cssBlocks = [];
57591
- cssBlocks.push(`${rootSelector} {\n ${rootRules.join(";\n ")};\n}`);
58927
+ cssBlocks.push(`${rootSelector} {\n ${renderCssDeclarations(rootRules)}\n}`);
57592
58928
  cssBlocks.push(`${itemSelector} {\n ${itemRules.join(";\n ")};\n}`);
57593
58929
  cssBlocks.push(`${itemSelector}.accordion-item {\n border-radius: ${borderRadius};\n}`);
57594
58930
  cssBlocks.push(`${lastItemSelector} {\n ${lastItemRules.join(";\n ")};\n}`);
@@ -57609,6 +58945,16 @@ function generateAccordionCss({ themeId, theme, accordionSystem }) {
57609
58945
  if (iconRotateBlock.length > 0) cssBlocks.push(...iconRotateBlock);
57610
58946
  return cssBlocks.join("\n\n");
57611
58947
  }
58948
+ function accordionSurfaceRules(theme, system) {
58949
+ if (!system.background) return [];
58950
+ const foreground = resolveSurfaceForeground({
58951
+ type: "color",
58952
+ color: system.background.colorToken,
58953
+ textColor: system.content.textColorToken,
58954
+ headingColor: system.trigger.textColorToken
58955
+ }, expandPalette(theme.palette), { linkHover: theme.typography.proseLinkStyle?.hoverColorToken });
58956
+ return [`background-color: ${rgbColorValue(system.background.colorToken)}`, ...surfaceForegroundDeclarations(foreground.kind === "known" ? surfaceForegroundInputFromResolved(foreground, rgbColorValue) : { text: rgbColorValue(system.content.textColorToken) })];
58957
+ }
57612
58958
  //#endregion
57613
58959
  //#region ../theme-core/src/accordions/defaults.ts
57614
58960
  init_curatedSiteStyles();
@@ -58166,957 +59512,6 @@ function generateDefaultInputSystem(theme) {
58166
59512
  };
58167
59513
  }
58168
59514
  //#endregion
58169
- //#region ../theme-core/src/navigation/generateNavLinkCSS.ts
58170
- init_types$9();
58171
- init_expandPalette();
58172
- init_colorConversion();
58173
- init_generateBaseCSS();
58174
- init_generateEffectsCSS();
58175
- /**
58176
- * Generate complete CSS for nav links from a NavLinkStyle configuration
58177
- */
58178
- function generateNavLinkCSS(options) {
58179
- const { themeId, tokens, theme, style, className } = options;
58180
- const selector = `:where([data-theme-scope="${themeId}"]) .${className}`;
58181
- const hoverSelector = `${selector}:hover`;
58182
- const activeSelector = `${selector}:active, ${selector}[data-active="true"]`;
58183
- const cssChunks = [];
58184
- const hoverRules = [];
58185
- const activeRules = [];
58186
- const baseRules = generateBaseInteractiveCSS({
58187
- typography: {
58188
- typography: style.typography,
58189
- fontWeight: style.fontWeight,
58190
- textTransform: style.textTransform,
58191
- italic: style.italic
58192
- },
58193
- padding: style.padding ? NAV_LINK_PADDING_MAP[style.padding] : void 0,
58194
- borderRadius: style.borderRadius ? NAV_LINK_BORDER_RADIUS_MAP[style.borderRadius] : void 0,
58195
- includeTransition: true,
58196
- includeFlexCenter: false
58197
- });
58198
- if (style.paddingX) {
58199
- const px = NAV_LINK_PADDING_X_MAP[style.paddingX];
58200
- baseRules.push(`padding-left: ${px};`);
58201
- baseRules.push(`padding-right: ${px};`);
58202
- }
58203
- if (style.textSize) baseRules.push(`font-size: ${NAV_LINK_TEXT_SIZE_MAP[style.textSize]};`);
58204
- if (style.letterSpacing && style.letterSpacing !== "normal") baseRules.push(`letter-spacing: ${NAV_LINK_LETTER_SPACING_MAP[style.letterSpacing]};`);
58205
- if (style.colorToken) baseRules.push(`color: ${tokens.getColor(style.colorToken)};`);
58206
- const contrastShadow = buildTextContrastShadow({
58207
- theme,
58208
- colorToken: style.colorToken,
58209
- treatment: style.contrastTreatment
58210
- });
58211
- if (contrastShadow) baseRules.push(`text-shadow: ${contrastShadow};`);
58212
- if (style.hoverColorToken && !style.effects?.hover?.length) hoverRules.push(`color: ${tokens.getColor(style.hoverColorToken)};`);
58213
- const elementConfig = {
58214
- background: { type: "transparent" },
58215
- textColorToken: style.colorToken || "text"
58216
- };
58217
- if (style.effects) {
58218
- const effectsCss = generateEffectsCSS({
58219
- themeId,
58220
- variantId: className,
58221
- effects: style.effects,
58222
- elementConfig,
58223
- tokens,
58224
- theme
58225
- });
58226
- if (effectsCss) cssChunks.push(effectsCss);
58227
- }
58228
- if (baseRules.length > 0) cssChunks.unshift(`\n${selector} {\n ${baseRules.join("\n ")}\n}\n`);
58229
- if (hoverRules.length > 0) cssChunks.push(`\n${hoverSelector} {\n ${hoverRules.join("\n ")}\n}\n`);
58230
- if (activeRules.length > 0) cssChunks.push(`\n${activeSelector} {\n ${activeRules.join("\n ")}\n}\n`);
58231
- cssChunks.push(navLinkFocusVisibleCss(selector, style, theme, tokens));
58232
- cssChunks.push(generateInteractiveChildInheritanceCSS(selector));
58233
- return cssChunks.join("");
58234
- }
58235
- /**
58236
- * Keyboard focus indicator for nav links, in the header, the footer and header
58237
- * dropdown menus — the three surfaces `generateNavLinkCSS` serves.
58238
- *
58239
- * Emitted unconditionally rather than as an effect, because focus visibility is
58240
- * a floor rather than a style choice. Only the interaction-palette pill ever
58241
- * wrote an `effects.focus` group, so every other nav — every `quiet` palette,
58242
- * every footer, every dropdown — previously fell back to whatever outline the
58243
- * browser drew.
58244
- *
58245
- * The outline takes the link's own resolved colour, so on a header that adapts
58246
- * to the section it floats over it moves with the adaptation instead of
58247
- * asserting a brand colour against an unknown backdrop.
58248
- *
58249
- * Where the style asks for `soft-glow`, the same halo goes on the outline. That
58250
- * treatment exists because the theme has already conceded the resolved colour
58251
- * alone is not reliable over an unpredictable backdrop — a hero photograph with
58252
- * mixed luminance. Without it the text would stay legible by its halo while the
58253
- * focus ring, which is the part with a contrast requirement of its own, would
58254
- * not.
58255
- *
58256
- * A style that also paints a focus pill keeps it: this adds an outline around
58257
- * that pill rather than replacing it.
58258
- */
58259
- function navLinkFocusVisibleCss(selector, style, theme, tokens) {
58260
- const color = tokens.getColor(style.colorToken);
58261
- const halo = buildTextContrastShadow({
58262
- theme,
58263
- colorToken: style.colorToken,
58264
- treatment: style.contrastTreatment
58265
- });
58266
- return `
58267
- ${selector}:focus-visible {
58268
- outline: 2px solid ${color};
58269
- outline-offset: ${focusOutlineOffset(selector)};${halo ? `\n box-shadow: ${halo};` : ""}
58270
- }
58271
- `;
58272
- }
58273
- /**
58274
- * Dropdown items are full-width inside a panel with no horizontal padding, so
58275
- * an outset outline would paint over and past the panel's own border. Keeping
58276
- * it flush is the only way it reads as belonging to the item.
58277
- */
58278
- function focusOutlineOffset(selector) {
58279
- return selector.includes("nav-dropdown-link") ? "-2px" : "3px";
58280
- }
58281
- function buildTextContrastShadow(input) {
58282
- if (input.treatment !== "soft-glow") return null;
58283
- 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)";
58284
- }
58285
- function isLikelyLightColorToken(theme, colorToken) {
58286
- const hex = resolveColorTokenHex(theme, colorToken);
58287
- if (hex) try {
58288
- return featuresFromHex(hex).Y >= .5;
58289
- } catch {}
58290
- const normalizedToken = colorToken?.toLowerCase() ?? "";
58291
- if (normalizedToken.includes("foreground") || normalizedToken.startsWith("on") || normalizedToken.includes("white") || normalizedToken.endsWith("-50") || normalizedToken.endsWith("-100")) return true;
58292
- if (normalizedToken.includes("black") || normalizedToken.endsWith("-800") || normalizedToken.endsWith("-900") || normalizedToken.endsWith("-950")) return false;
58293
- return theme.palette.meta.mode === "dark";
58294
- }
58295
- function resolveColorTokenHex(theme, colorToken) {
58296
- if (!colorToken) return null;
58297
- if (colorToken === "white") return "#ffffff";
58298
- if (colorToken === "black") return "#000000";
58299
- if (colorToken === "transparent") return null;
58300
- return expandPalette(theme.palette)[colorToken] ?? null;
58301
- }
58302
- //#endregion
58303
- //#region ../theme-core/src/header/navDropdownSizing.ts
58304
- var NAV_DROPDOWN_SHIFT_PROPERTY, NAV_DROPDOWN_MAX_WIDTH_CSS, NAV_DROPDOWN_CONTAINER_RAIL_CSS_RULES;
58305
- var init_navDropdownSizing = __esmMin((() => {
58306
- NAV_DROPDOWN_SHIFT_PROPERTY = "--nav-dropdown-shift-x";
58307
- NAV_DROPDOWN_MAX_WIDTH_CSS = `min(22rem, calc(100vw - 2rem))`;
58308
- NAV_DROPDOWN_CONTAINER_RAIL_CSS_RULES = [
58309
- `min-width: 12rem;`,
58310
- `width: max-content;`,
58311
- `max-width: ${NAV_DROPDOWN_MAX_WIDTH_CSS};`,
58312
- `transform: translateX(var(${NAV_DROPDOWN_SHIFT_PROPERTY}, 0px));`
58313
- ];
58314
- }));
58315
- //#endregion
58316
- //#region ../theme-core/src/header/surfaceRules.ts
58317
- init_navDropdownSizing();
58318
- init_shared$4();
58319
- init_colorStyles();
58320
- /** Compile the at-rest surface independently of scroll treatment and paint geometry. */
58321
- function buildHeaderSurfaceRules(header, tokens) {
58322
- const base = [];
58323
- const background = header.background;
58324
- if (background.type === "color") base.push(`background-color: ${tokens.getColor(background.color || "surface")};`);
58325
- else if (background.type === "gradient" && background.gradient) {
58326
- const stops = background.gradient.stops.map((stop) => tokens.getColor(stop.color)).join(", ");
58327
- base.push(`background-image: linear-gradient(${background.gradient.angle ?? 180}deg, ${stops});`);
58328
- }
58329
- const borderWidth = getComponentBorderWidthPx(header.border?.width ?? "none");
58330
- if (!header.border || borderWidth === "0") return {
58331
- base,
58332
- border: []
58333
- };
58334
- const color = rgbColorValue(header.border.colorToken?.trim() || "border");
58335
- const style = header.border.style === "dashed" ? "dashed" : "solid";
58336
- return {
58337
- base,
58338
- border: header.border.position === "both" ? [`border-top: ${borderWidth} ${style} ${color};`, `border-bottom: ${borderWidth} ${style} ${color};`] : [`border-${header.border.position}: ${borderWidth} ${style} ${color};`]
58339
- };
58340
- }
58341
- //#endregion
58342
- //#region ../theme-core/src/navigation/presets.ts
58343
- /**
58344
- * Built-in nav link style presets
58345
- *
58346
- * Each preset uses composable effects to achieve its look.
58347
- */
58348
- const NAV_LINK_PRESETS = {
58349
- /**
58350
- * Minimal - subtle color change on hover
58351
- */
58352
- minimal: {
58353
- name: "Minimal",
58354
- typography: "body",
58355
- fontWeight: "medium",
58356
- textTransform: "none",
58357
- italic: false,
58358
- colorToken: "text",
58359
- hoverColorToken: "primary",
58360
- padding: "none",
58361
- borderRadius: "none",
58362
- effects: { hover: [{
58363
- effectId: "text-color-change",
58364
- options: { hoverColorToken: "primary" }
58365
- }] }
58366
- },
58367
- /**
58368
- * Underline - static underline appears on hover
58369
- */
58370
- underline: {
58371
- name: "Underline",
58372
- typography: "body",
58373
- fontWeight: "medium",
58374
- textTransform: "none",
58375
- italic: false,
58376
- colorToken: "text",
58377
- padding: "none",
58378
- borderRadius: "none",
58379
- effects: { hover: [{
58380
- effectId: "nav-underline",
58381
- options: { style: "static" }
58382
- }] }
58383
- },
58384
- /**
58385
- * Underline Grow - animated underline grows from center on hover
58386
- */
58387
- "underline-grow": {
58388
- name: "Underline Grow",
58389
- typography: "body",
58390
- fontWeight: "medium",
58391
- textTransform: "none",
58392
- italic: false,
58393
- colorToken: "text",
58394
- padding: "none",
58395
- borderRadius: "none",
58396
- effects: { hover: [{
58397
- effectId: "nav-underline",
58398
- options: { style: "grow" }
58399
- }] }
58400
- },
58401
- /**
58402
- * Capsule - pill-shaped background on hover
58403
- */
58404
- capsule: {
58405
- name: "Capsule",
58406
- typography: "body",
58407
- fontWeight: "medium",
58408
- textTransform: "none",
58409
- italic: false,
58410
- colorToken: "text",
58411
- padding: "compact",
58412
- borderRadius: "full",
58413
- effects: {
58414
- hover: [{
58415
- effectId: "background-on-hover-alpha",
58416
- options: {
58417
- colorToken: "primary",
58418
- opacity: 10
58419
- }
58420
- }],
58421
- active: [{
58422
- effectId: "background-on-hover-alpha",
58423
- options: {
58424
- colorToken: "primary",
58425
- opacity: 15
58426
- }
58427
- }]
58428
- }
58429
- },
58430
- /**
58431
- * Solid - solid background color on hover
58432
- */
58433
- solid: {
58434
- name: "Solid",
58435
- typography: "body",
58436
- fontWeight: "medium",
58437
- textTransform: "none",
58438
- italic: false,
58439
- colorToken: "text",
58440
- padding: "compact",
58441
- borderRadius: "none",
58442
- effects: {
58443
- hover: [{
58444
- effectId: "background-on-hover",
58445
- options: {
58446
- colorToken: "primary",
58447
- textColorToken: "primaryForeground"
58448
- }
58449
- }],
58450
- active: [{
58451
- effectId: "background-on-hover",
58452
- options: {
58453
- colorToken: "primary",
58454
- textColorToken: "primaryForeground"
58455
- }
58456
- }]
58457
- }
58458
- },
58459
- /**
58460
- * Scale - gentle scale-up on hover
58461
- */
58462
- scale: {
58463
- name: "Scale",
58464
- typography: "body",
58465
- fontWeight: "medium",
58466
- textTransform: "none",
58467
- italic: false,
58468
- colorToken: "text",
58469
- padding: "none",
58470
- borderRadius: "none",
58471
- effects: { hover: [{
58472
- effectId: "scale-up",
58473
- options: { scale: 1.05 }
58474
- }] }
58475
- },
58476
- /**
58477
- * Frosted - semi-transparent glass-like background
58478
- */
58479
- frosted: {
58480
- name: "Frosted",
58481
- typography: "body",
58482
- fontWeight: "medium",
58483
- textTransform: "none",
58484
- italic: false,
58485
- colorToken: "text",
58486
- padding: "compact",
58487
- borderRadius: "md",
58488
- effects: {
58489
- base: [{ effectId: "nav-frosted-base" }],
58490
- hover: [{ effectId: "nav-frosted-hover" }],
58491
- active: [{ effectId: "nav-frosted-active" }]
58492
- }
58493
- }
58494
- };
58495
- /**
58496
- * Get a nav link style preset by ID
58497
- */
58498
- function getNavLinkPreset(presetId) {
58499
- return NAV_LINK_PRESETS[presetId];
58500
- }
58501
- Object.keys(NAV_LINK_PRESETS);
58502
- //#endregion
58503
- //#region ../theme-core/src/header/legacyNavLinkStyle.ts
58504
- function buildLegacyHeaderNavLinkStyle(header, contrastTreatment, navTextSize) {
58505
- const navStyle = header.navStyle ?? "minimal";
58506
- const basePreset = getNavLinkPreset(navStyle);
58507
- if (!basePreset) return null;
58508
- const style = {
58509
- ...basePreset,
58510
- fontWeight: header.navWeight ?? basePreset.fontWeight,
58511
- colorToken: (header.navColor ?? header.textColor)?.trim() || basePreset.colorToken,
58512
- ...contrastTreatment ? { contrastTreatment } : {},
58513
- ...navTextSize ? { textSize: navTextSize } : {}
58514
- };
58515
- if (header.navWeight === "bold" && navStyle === "solid") style.textTransform = "uppercase";
58516
- applyLegacyGlassTreatment(style, header, navStyle);
58517
- return style;
58518
- }
58519
- function applyLegacyGlassTreatment(style, header, navStyle) {
58520
- if (header.navContainer?.type !== "glass" || navStyle !== "minimal") return;
58521
- style.borderRadius = "full";
58522
- style.effects = {
58523
- ...style.effects,
58524
- hover: glassStateEffects(10),
58525
- active: glassStateEffects(18)
58526
- };
58527
- }
58528
- function glassStateEffects(opacity) {
58529
- return [{
58530
- effectId: "background-on-hover-alpha",
58531
- options: {
58532
- colorToken: "neutral-50",
58533
- opacity
58534
- }
58535
- }, {
58536
- effectId: "text-color-change",
58537
- options: { hoverColorToken: "neutral-50" }
58538
- }];
58539
- }
58540
- //#endregion
58541
- //#region ../theme-core/src/header/generateHeaderCss.ts
58542
- init_resolver$1();
58543
- init_siteChromeNavPreferences();
58544
- init_shared$4();
58545
- init_breakpoints();
58546
- init_scrollTreatment();
58547
- init_paintTargets();
58548
- const HEADER_BLUR = "blur(12px)";
58549
- const FLOATING_BLUR = "blur(16px)";
58550
- /**
58551
- * Generate complete CSS for header system from theme config
58552
- *
58553
- * Similar to button system - generates theme-scoped CSS using [data-theme-scope] selector
58554
- */
58555
- function generateHeaderCss(options) {
58556
- const { themeId, theme } = options;
58557
- const tokens = new TokenResolver(theme);
58558
- const header = theme.header;
58559
- const cssChunks = [];
58560
- const headerContrastTreatment = resolveHeaderContrastTreatment(header);
58561
- const headerNavTextSize = resolveHeaderNavTextSize(header);
58562
- cssChunks.push(generateHeaderRootStyles(header, themeId, tokens));
58563
- cssChunks.push(generateMobileOverlayBackdropFilterFix(themeId, header.variant));
58564
- cssChunks.push(generateLogoStyles({
58565
- logo: header.logo,
58566
- themeId,
58567
- tokens,
58568
- theme,
58569
- textColor: header.textColor,
58570
- fallbackTextColor: header.navLinkStyle?.colorToken,
58571
- contrastTreatment: headerContrastTreatment ?? void 0
58572
- }));
58573
- cssChunks.push(generateLogoTextBehaviorStyles(header.logoText, themeId));
58574
- cssChunks.push(generateNavLinkStyles(header, themeId, tokens, theme, headerContrastTreatment, headerNavTextSize));
58575
- cssChunks.push(generateDropdownContainerStyles(header, themeId, tokens));
58576
- cssChunks.push(generateDropdownLinkStyles(header, themeId, tokens, theme));
58577
- cssChunks.push(generateDropdownCaretStyles(themeId));
58578
- cssChunks.push(generateDropdownTriggerOverrides(header, themeId));
58579
- cssChunks.push(generateMobilePanelStyles(header, themeId, tokens));
58580
- if (header.variant === "floating" && header.container) cssChunks.push(generateFloatingContainerStyles(header, themeId, tokens));
58581
- cssChunks.push(generateNavContainerStyles(header, themeId, tokens));
58582
- cssChunks.push(generateHeaderCtaTreatmentStyles(header, themeId, tokens));
58583
- cssChunks.push(generateCtaGapStyles(header, themeId));
58584
- return cssChunks.filter(Boolean).join("\n\n");
58585
- }
58586
- function resolveHeaderContrastTreatment(header) {
58587
- if (header.navLinkStyle?.contrastTreatment) return header.navLinkStyle.contrastTreatment;
58588
- return isClearSplitHeaderShape(header) ? "soft-glow" : null;
58589
- }
58590
- function resolveHeaderNavTextSize(header) {
58591
- if (header.navLinkStyle?.textSize) return header.navLinkStyle.textSize;
58592
- return isClearSplitHeaderShape(header) ? "lg" : null;
58593
- }
58594
- function isClearSplitHeaderShape(header) {
58595
- const hasSharedFloatingSurface = Boolean(header.container);
58596
- return header.variant === "floating" && (header.navStyle ?? "minimal") === "minimal" && !hasSharedFloatingSurface;
58597
- }
58598
- function isDetachedFloatingHeaderShape(header) {
58599
- return header.variant === "floating" && !header.container;
58600
- }
58601
- /**
58602
- * Generate root header container styles
58603
- */
58604
- function generateHeaderRootStyles(header, themeId, tokens) {
58605
- const selector = `:where([data-theme-scope="${themeId}"]) .header-root`;
58606
- const rules = [];
58607
- const navContainerType = header.navContainer?.type ?? "none";
58608
- const isContainedNav = navContainerType === "pill" || navContainerType === "glass";
58609
- rules.push("position: relative;");
58610
- rules.push("isolation: isolate;");
58611
- const surfaceRules = isContainedNav ? {
58612
- base: [],
58613
- border: []
58614
- } : buildHeaderSurfaceRules(header, tokens);
58615
- const floatingSurfaceBorder = header.variant === "floating";
58616
- if (!floatingSurfaceBorder) rules.push(...surfaceRules.border);
58617
- const basePaintRules = floatingSurfaceBorder ? [...surfaceRules.base, ...surfaceRules.border] : surfaceRules.base;
58618
- const scrolledPaintRules = floatingSurfaceBorder ? surfaceRules.border : [];
58619
- if (header.positioning === "sticky" || header.positioning === "fixed") {
58620
- const shadowVar = getComponentShadowVar(header.shadow?.elevation ?? "none");
58621
- if (shadowVar) rules.push(`box-shadow: ${shadowVar};`);
58622
- }
58623
- const baseBlock = `\n${selector} {\n ${rules.join("\n ")}\n}\n`;
58624
- const overlayFix = `\n${`${selector}:has([data-nav-mobile-overlay][aria-hidden="false"])`} {\n backdrop-filter: none !important;\n -webkit-backdrop-filter: none !important;\n}\n`;
58625
- const scrollTreatmentStyles = generateHeaderScrollTreatmentStyles(header.scrollTreatment, themeId, header.variant, scrolledPaintRules);
58626
- if (isContainedNav || basePaintRules.length === 0) return `${baseBlock}\n${overlayFix}${scrollTreatmentStyles}`;
58627
- return `${baseBlock}\n${renderHeaderPaintTargetRules(getHeaderPaintTargets(header.variant, themeId), basePaintRules)}\n${overlayFix}${scrollTreatmentStyles}`;
58628
- }
58629
- /**
58630
- * Generate logo typography styles
58631
- */
58632
- function generateLogoStyles(input) {
58633
- const { logo, themeId, tokens, theme, textColor, fallbackTextColor, contrastTreatment } = input;
58634
- const selector = `:where([data-theme-scope="${themeId}"]) .header-logo-text`;
58635
- const rules = [];
58636
- const primaryColor = tokens.getColor("primary");
58637
- const accentColor = tokens.getColor("accent");
58638
- if (textColor && !logo?.gradient) rules.push(`color: ${tokens.getColor(textColor)};`);
58639
- if ((logo?.fontFamily ?? "heading") === "body") rules.push(`font-family: var(--font-body);`);
58640
- else rules.push(`font-family: var(--font-heading);`);
58641
- if (logo) {
58642
- if (logo.letterSpacing && logo.letterSpacing !== "normal") rules.push(`letter-spacing: ${{
58643
- normal: "0em",
58644
- wide: "0.05em",
58645
- wider: "0.1em",
58646
- widest: "0.15em"
58647
- }[logo.letterSpacing]};`);
58648
- if (logo.gradient) {
58649
- rules.push(`background: linear-gradient(to right, ${primaryColor}, ${accentColor});`);
58650
- rules.push(`-webkit-background-clip: text;`);
58651
- rules.push(`-webkit-text-fill-color: transparent;`);
58652
- rules.push(`background-clip: text;`);
58653
- rules.push(`color: transparent;`);
58654
- }
58655
- }
58656
- const logoTextColorToken = textColor?.trim() || fallbackTextColor?.trim() || "text";
58657
- const contrastShadow = logo?.gradient ? null : buildTextContrastShadow({
58658
- theme,
58659
- colorToken: logoTextColorToken,
58660
- treatment: contrastTreatment
58661
- });
58662
- if (contrastShadow) rules.push(`text-shadow: ${contrastShadow};`);
58663
- if (rules.length === 0) return "";
58664
- return `\n${selector} {\n ${rules.join("\n ")}\n}\n`;
58665
- }
58666
- function generateLogoTextBehaviorStyles(logoText, themeId) {
58667
- if (!logoText) return "";
58668
- const selector = `:where([data-theme-scope="${themeId}"]) .header-logo-text`;
58669
- const cssChunks = [];
58670
- const mobileRules = [];
58671
- if (logoText.mobileWrapLines === 1) {
58672
- mobileRules.push("display: block;");
58673
- mobileRules.push("white-space: nowrap;");
58674
- mobileRules.push("overflow: hidden;");
58675
- mobileRules.push("text-overflow: ellipsis;");
58676
- }
58677
- if (logoText.mobileWrapLines === 2) {
58678
- mobileRules.push("display: -webkit-box;");
58679
- mobileRules.push("-webkit-box-orient: vertical;");
58680
- mobileRules.push("-webkit-line-clamp: 2;");
58681
- mobileRules.push("white-space: normal;");
58682
- mobileRules.push("overflow: hidden;");
58683
- mobileRules.push("text-overflow: ellipsis;");
58684
- }
58685
- if (logoText.mobileMaxWidth) mobileRules.push(`max-width: ${{
58686
- xs: "8rem",
58687
- sm: "10rem",
58688
- md: "12rem"
58689
- }[logoText.mobileMaxWidth]};`);
58690
- if (mobileRules.length > 0) cssChunks.push(`@media ${MQ_MD_DOWN} {\n ${selector} {\n ${mobileRules.join("\n ")}\n }\n}`);
58691
- if (logoText.hideOnShrink) {
58692
- const shrinkSelector = `:where([data-theme-scope="${themeId}"]) .rb-header-shrink.header-scrolled .header-logo-text`;
58693
- cssChunks.push(`\n${shrinkSelector} {\n display: none;\n}\n`);
58694
- }
58695
- return cssChunks.join("\n\n");
58696
- }
58697
- /**
58698
- * Generate navigation link styles based on navStyle and effects
58699
- *
58700
- * Uses the composable NavLinkStyle system with backward compatibility for
58701
- * legacy navStyle, navWeight and navColor settings.
58702
- */
58703
- function generateNavLinkStyles(header, themeId, tokens, theme, contrastTreatment, navTextSize) {
58704
- const navPreferences = {
58705
- typography: header.navFontRole ?? "inherit",
58706
- fontSize: readHeaderNavFontSizePreference(header.navTextSize),
58707
- interactionPalette: header.interactionPalette ?? "recommended"
58708
- };
58709
- if (header.navLinkStyle) return generateNavLinkCSS({
58710
- themeId,
58711
- tokens,
58712
- theme,
58713
- style: mergeHeaderNavTypographyPreference(contrastTreatment || navTextSize ? {
58714
- ...header.navLinkStyle,
58715
- ...contrastTreatment ? { contrastTreatment } : {},
58716
- ...navTextSize ? { textSize: navTextSize } : {}
58717
- } : header.navLinkStyle, navPreferences),
58718
- className: "header-nav-link"
58719
- });
58720
- const mergedStyle = buildLegacyHeaderNavLinkStyle(header, contrastTreatment, navTextSize);
58721
- if (!mergedStyle) {
58722
- console.warn(`[generateHeaderCss] Nav link preset not found: ${header.navStyle}`);
58723
- return "";
58724
- }
58725
- return generateNavLinkCSS({
58726
- themeId,
58727
- tokens,
58728
- theme,
58729
- style: mergeHeaderNavTypographyPreference(mergedStyle, navPreferences),
58730
- className: "header-nav-link"
58731
- });
58732
- }
58733
- /**
58734
- * Generate dropdown menu container styles
58735
- */
58736
- function generateDropdownContainerStyles(header, themeId, tokens) {
58737
- const selector = `:where([data-theme-scope="${themeId}"]) .nav-dropdown-menu`;
58738
- const rules = [];
58739
- const dropdownStyle = header.dropdownStyle;
58740
- rules.push(...NAV_DROPDOWN_CONTAINER_RAIL_CSS_RULES);
58741
- const bgToken = dropdownStyle?.background ?? "surface";
58742
- rules.push(`background-color: ${tokens.getColor(bgToken)};`);
58743
- const textToken = dropdownStyle?.textColor ?? "text";
58744
- rules.push(`color: ${tokens.getColor(textToken)};`);
58745
- const borderToken = dropdownStyle?.borderColor;
58746
- if (borderToken === null) rules.push(`border: none;`);
58747
- else rules.push(`border: 1px solid ${tokens.getColor(borderToken ?? "border")};`);
58748
- const shadowVar = getComponentShadowVar(dropdownStyle?.shadow ?? "md");
58749
- if (shadowVar) rules.push(`box-shadow: ${shadowVar};`);
58750
- const borderRadius = dropdownStyle?.borderRadius ?? "md";
58751
- rules.push(`border-radius: ${{
58752
- none: "0",
58753
- sm: "0.25rem",
58754
- md: "0.5rem",
58755
- lg: "0.75rem"
58756
- }[borderRadius]};`);
58757
- rules.push(`padding: 0.5rem 0;`);
58758
- return `\n${selector} {\n ${rules.join("\n ")}\n}\n`;
58759
- }
58760
- function generateDropdownLinkStyles(header, themeId, tokens, theme) {
58761
- const configuredDropdownStyle = header.dropdownStyle;
58762
- const textColorToken = configuredDropdownStyle?.textColor ?? ((header.navColor ?? header.textColor)?.trim() || "text");
58763
- const hoverBgToken = configuredDropdownStyle?.hoverBackground ?? textColorToken;
58764
- const hoverEffects = {
58765
- hover: hoverBgToken === null ? [] : [{
58766
- effectId: "background-on-hover-alpha",
58767
- options: {
58768
- colorToken: hoverBgToken,
58769
- opacity: 12
58770
- }
58771
- }],
58772
- active: hoverBgToken === null ? [] : [{
58773
- effectId: "background-on-hover-alpha",
58774
- options: {
58775
- colorToken: hoverBgToken,
58776
- opacity: 18
58777
- }
58778
- }]
58779
- };
58780
- if (configuredDropdownStyle?.hoverTextColor) {
58781
- hoverEffects.hover?.push({
58782
- effectId: "text-color-change",
58783
- options: { hoverColorToken: configuredDropdownStyle.hoverTextColor }
58784
- });
58785
- hoverEffects.active?.push({
58786
- effectId: "text-color-change",
58787
- options: { hoverColorToken: configuredDropdownStyle.hoverTextColor }
58788
- });
58789
- }
58790
- const baseCSS = generateNavLinkCSS({
58791
- themeId,
58792
- tokens,
58793
- theme,
58794
- style: {
58795
- name: "Dropdown",
58796
- typography: "body",
58797
- fontWeight: configuredDropdownStyle?.fontWeight ?? header.navWeight ?? "medium",
58798
- textTransform: configuredDropdownStyle?.textTransform ?? "none",
58799
- italic: false,
58800
- colorToken: textColorToken,
58801
- padding: "compact",
58802
- borderRadius: "sm",
58803
- effects: hoverEffects
58804
- },
58805
- className: "nav-dropdown-link"
58806
- });
58807
- const additionalRules = [];
58808
- const letterSpacing = configuredDropdownStyle?.letterSpacing ?? "normal";
58809
- if (letterSpacing !== "normal") additionalRules.push(`letter-spacing: ${{
58810
- normal: "0em",
58811
- wide: "0.05em",
58812
- wider: "0.1em"
58813
- }[letterSpacing]};`);
58814
- const textSize = configuredDropdownStyle?.textSize ?? "sm";
58815
- additionalRules.push(`font-size: ${{
58816
- xs: "0.75rem",
58817
- sm: "0.875rem",
58818
- base: "1rem",
58819
- lg: "1.125rem"
58820
- }[textSize]};`);
58821
- if (additionalRules.length > 0) return baseCSS + `\n${`:where([data-theme-scope="${themeId}"]) .nav-dropdown-link`} {\n ${additionalRules.join("\n ")}\n}\n`;
58822
- return baseCSS;
58823
- }
58824
- function generateDropdownCaretStyles(themeId) {
58825
- return `
58826
- ${`:where([data-theme-scope="${themeId}"]) .nav-caret`} {
58827
- width: 0.45rem;
58828
- height: 0.45rem;
58829
- margin-left: 0.5rem;
58830
- border-right: 2px solid currentColor;
58831
- border-bottom: 2px solid currentColor;
58832
- transform: rotate(45deg) translateY(-1px);
58833
- transition: transform 150ms ease;
58834
- }
58835
-
58836
- ${`:where([data-theme-scope="${themeId}"]) .nav-dropdown-trigger[aria-expanded="true"] .nav-caret, :where([data-theme-scope="${themeId}"]) .nav-mobile-trigger[aria-expanded="true"] .nav-caret`} {
58837
- transform: rotate(-135deg) translateY(1px);
58838
- }
58839
- `.trim();
58840
- }
58841
- function generateDropdownTriggerOverrides(header, themeId) {
58842
- const navStyle = header.navStyle ?? "minimal";
58843
- if (navStyle !== "underline" && navStyle !== "underline-grow") return "";
58844
- return `
58845
- ${`:where([data-theme-scope="${themeId}"]) .nav-dropdown-trigger.header-nav-link::after`} {
58846
- content: none;
58847
- }
58848
- `.trim();
58849
- }
58850
- /**
58851
- * Generate mobile navigation panel styles
58852
- * Uses the same dropdownStyle settings as the desktop dropdown menus
58853
- */
58854
- function generateMobilePanelStyles(header, themeId, tokens) {
58855
- const selector = `:where([data-theme-scope="${themeId}"]) .nav-mobile-panel`;
58856
- const selfSelector = `:where(.nav-mobile-panel[data-theme-scope="${themeId}"])`;
58857
- const rules = [];
58858
- const dropdownStyle = header.dropdownStyle;
58859
- const bgToken = dropdownStyle?.background ?? "surface";
58860
- rules.push(`background-color: ${tokens.getColor(bgToken)};`);
58861
- const textToken = dropdownStyle?.textColor ?? "text";
58862
- rules.push(`color: ${tokens.getColor(textToken)};`);
58863
- const body = rules.join("\n ");
58864
- return `\n${selector} {\n ${body}\n}\n\n${selfSelector} {\n ${body}\n}\n`;
58865
- }
58866
- /**
58867
- * Generate nav container styles (pill/glass)
58868
- */
58869
- function generateNavContainerStyles(header, themeId, tokens) {
58870
- const navContainer = header.navContainer;
58871
- const navContainerType = navContainer?.type ?? "none";
58872
- if (!navContainer || navContainerType === "none") return "";
58873
- const selector = `:where([data-theme-scope="${themeId}"]) .header-nav-row`;
58874
- const rules = [];
58875
- if (navContainerType === "pill" || navContainerType === "glass") {
58876
- rules.push("padding: 0.5rem 0.75rem;");
58877
- rules.push("border-radius: 9999px;");
58878
- rules.push("display: inline-flex;");
58879
- rules.push("align-items: center;");
58880
- rules.push("gap: 1.5rem;");
58881
- if (isDetachedFloatingHeaderShape(header)) rules.push("align-self: flex-start;");
58882
- }
58883
- if (navContainerType === "glass") {
58884
- const opacity = resolveFloatingGlassOpacity(header, navContainer.opacity, .15);
58885
- const background = navContainer.tint ? buildTint(tokens.getColor(navContainer.tint), opacity) : buildRgbWhite(opacity);
58886
- rules.push(`background-color: ${background};`);
58887
- rules.push(`backdrop-filter: ${HEADER_BLUR};`);
58888
- rules.push(`-webkit-backdrop-filter: ${HEADER_BLUR};`);
58889
- rules.push("border: 1px solid rgba(255, 255, 255, 0.2);");
58890
- rules.push("box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);");
58891
- } else if (navContainerType === "pill") {
58892
- const opacity = clampOpacity(navContainer.opacity, .15);
58893
- if (navContainer.tint) rules.push(`background-color: ${buildTint(tokens.getColor(navContainer.tint), opacity)};`);
58894
- else rules.push(`background-color: ${tokens.getColor("surface")};`);
58895
- rules.push(`border: 1px solid ${tokens.getColor("border")};`);
58896
- }
58897
- if (rules.length > 0) return `${selector} { ${rules.join(" ")} }`;
58898
- return "";
58899
- }
58900
- /**
58901
- * Generate floating container styles
58902
- */
58903
- function generateFloatingContainerStyles(header, themeId, tokens) {
58904
- const container = header.container;
58905
- if (!container) return "";
58906
- const selector = `:where([data-theme-scope="${themeId}"]) .header-floating-container`;
58907
- const rules = [];
58908
- const opacity = container.tint === "surface" ? resolveFloatingGlassOpacity(header, container.opacity, .12) : clampOpacity(container.opacity, .12);
58909
- if (container.tint) rules.push(`background-color: ${buildTint(tokens.getColor(container.tint), opacity)};`);
58910
- else rules.push(`background-color: ${buildRgbWhite(opacity)};`);
58911
- rules.push(`backdrop-filter: ${FLOATING_BLUR};`);
58912
- rules.push(`-webkit-backdrop-filter: ${FLOATING_BLUR};`);
58913
- if (container.border) rules.push(`border: 1px solid rgb(255 255 255 / 0.2);`);
58914
- rules.push(`border-radius: ${{
58915
- none: "0",
58916
- sm: "0.375rem",
58917
- md: "0.5rem",
58918
- lg: "0.75rem",
58919
- xl: "1rem",
58920
- "2xl": "1.5rem"
58921
- }[container.rounded]};`);
58922
- if (container.shadow) rules.push(`box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);`);
58923
- rules.push(`padding: ${{
58924
- sm: "1rem 1.5rem",
58925
- md: "1.5rem 2rem",
58926
- lg: "2rem 2.5rem"
58927
- }[container.padding]};`);
58928
- return `\n${selector} {\n ${rules.join("\n ")}\n}\n`;
58929
- }
58930
- /**
58931
- * CTA gap value map — controls left margin on the desktop CTA button
58932
- */
58933
- const HEADER_CTA_GAP_MAP = {
58934
- none: "0",
58935
- tight: "0.5rem",
58936
- compact: "1rem",
58937
- default: "1.5rem",
58938
- relaxed: "2rem",
58939
- spacious: "3rem"
58940
- };
58941
- /**
58942
- * The inverted CTA treatment is contextual to branded header surfaces. It
58943
- * cannot be represented by the generic secondary button role alone because
58944
- * that role is transparent and inherits the surrounding surface foreground.
58945
- * Keep the shared button's structure/effects while making the header own the
58946
- * palette relationship for both desktop and mobile CTAs.
58947
- */
58948
- function generateHeaderCtaTreatmentStyles(header, themeId, tokens) {
58949
- if (header.ctaTreatment !== "inverted") return "";
58950
- const desktopSelector = `:where([data-theme-scope="${themeId}"]) .header-cta`;
58951
- const mobileSelector = `:where([data-theme-scope="${themeId}"]) .nav-mobile-cta`;
58952
- const selectors = `${desktopSelector},\n${mobileSelector}`;
58953
- const hoverSelectors = [
58954
- `${desktopSelector}:hover`,
58955
- `${desktopSelector}[data-force-hover="true"]`,
58956
- `${mobileSelector}:hover`,
58957
- `${mobileSelector}[data-force-hover="true"]`
58958
- ].join(",\n");
58959
- const focusSelectors = [`${desktopSelector}:focus-visible`, `${mobileSelector}:focus-visible`].join(",\n");
58960
- return `
58961
- ${selectors} {
58962
- background-color: ${tokens.getColor("background")};
58963
- background-image: none;
58964
- color: ${tokens.getColor("onBackground")};
58965
- border-color: currentColor;
58966
- }
58967
-
58968
- ${hoverSelectors} {
58969
- background-color: ${tokens.getColor("surface")};
58970
- background-image: none;
58971
- color: ${tokens.getColor("onSurface")};
58972
- }
58973
-
58974
- ${focusSelectors} {
58975
- outline: 2px solid ${tokens.getColor("onBackground")};
58976
- outline-offset: 2px;
58977
- box-shadow: 0 0 0 4px ${tokens.getColor("background")};
58978
- }
58979
- `;
58980
- }
58981
- /**
58982
- * Generate CTA button gap styles (left margin between nav links and CTA)
58983
- */
58984
- function generateCtaGapStyles(header, themeId) {
58985
- if (!header.ctaGap) return "";
58986
- const value = HEADER_CTA_GAP_MAP[header.ctaGap];
58987
- if (!value) return "";
58988
- return `\n${`:where([data-theme-scope="${themeId}"]) .header-cta`} {\n margin-left: ${value};\n}\n`;
58989
- }
58990
- function clampOpacity(value, fallback) {
58991
- if (typeof value !== "number" || Number.isNaN(value)) return fallback;
58992
- return Math.min(Math.max(value, 0), 1);
58993
- }
58994
- function resolveFloatingGlassOpacity(header, value, fallback) {
58995
- const opacity = clampOpacity(value, fallback);
58996
- return header.variant === "floating" ? Math.max(opacity, .4) : opacity;
58997
- }
58998
- function buildTint(color, opacity) {
58999
- return applyAlpha(color, opacity);
59000
- }
59001
- function buildRgbWhite(opacity) {
59002
- return `rgb(255 255 255 / ${clampOpacity(opacity, 1)})`;
59003
- }
59004
- function applyAlpha(color, opacity) {
59005
- const clamped = clampOpacity(opacity, 1);
59006
- if (color.startsWith("rgb(") && color.endsWith(")")) {
59007
- const inner = color.slice(4, -1).trim();
59008
- return `rgb(${inner.includes("/") ? (inner.split("/")[0] ?? inner).trim() : inner} / ${clamped})`;
59009
- }
59010
- return color;
59011
- }
59012
- //#endregion
59013
- //#region ../theme-core/src/footer/generateFooterCss.ts
59014
- init_resolver$1();
59015
- /**
59016
- * Generate CSS for footer navigation styling
59017
- *
59018
- * Similar to header nav but with independent configuration and no advanced effects
59019
- */
59020
- function generateFooterCss(options) {
59021
- const { themeId, theme } = options;
59022
- const tokens = new TokenResolver(theme);
59023
- const footer = theme.footer;
59024
- const cssChunks = [];
59025
- cssChunks.push(generateFooterNavLinkStyles(footer, themeId, tokens, theme));
59026
- cssChunks.push(generateFooterLogoStyles(theme, themeId));
59027
- cssChunks.push(generateFooterBottomTextLinkStyles(footer, themeId, tokens));
59028
- return cssChunks.filter(Boolean).join("\n\n");
59029
- }
59030
- function generateFooterLogoStyles(theme, themeId) {
59031
- const height = footerLogoHeight(resolveFooterLogoSize(theme.footer, theme.header.logo));
59032
- return `
59033
- ${`:where([data-theme-scope="${themeId}"])`} .footer-logo img {
59034
- width: auto;
59035
- height: ${height};
59036
- }
59037
- `;
59038
- }
59039
- function resolveFooterLogoSize(footer, headerLogo) {
59040
- const brandDrivenSize = footerLogoSizeFromHeaderLogo(headerLogo);
59041
- return footer.logo?.maxHeight ?? brandDrivenSize ?? footer.logo?.size ?? "md";
59042
- }
59043
- function footerLogoSizeFromHeaderLogo(headerLogo) {
59044
- const size = headerLogo?.size;
59045
- switch (size) {
59046
- case "compact": return "sm";
59047
- case "standard": return "md";
59048
- case "generous": return "lg";
59049
- case "display": return "xl";
59050
- case "auto":
59051
- case void 0: return null;
59052
- default: return size;
59053
- }
59054
- }
59055
- function footerLogoHeight(size) {
59056
- switch (size) {
59057
- case "sm": return "2.5rem";
59058
- case "md": return "4rem";
59059
- case "lg": return "5rem";
59060
- case "xl": return "6rem";
59061
- default: return size;
59062
- }
59063
- }
59064
- /**
59065
- * Generate navigation link styles for footer
59066
- *
59067
- * Uses the composable NavLinkStyle system with backward compatibility for
59068
- * legacy navStyle, navWeight, and navColor settings.
59069
- */
59070
- function generateFooterNavLinkStyles(footer, themeId, tokens, theme) {
59071
- if (footer.navLinkStyle) return generateNavLinkCSS({
59072
- themeId,
59073
- tokens,
59074
- theme,
59075
- style: footer.navLinkStyle,
59076
- className: "footer-nav-link"
59077
- });
59078
- const navStyle = footer.navStyle ?? "minimal";
59079
- const basePreset = getNavLinkPreset(navStyle);
59080
- if (!basePreset) {
59081
- console.warn(`[generateFooterCss] Nav link preset not found: ${navStyle}`);
59082
- return "";
59083
- }
59084
- return generateNavLinkCSS({
59085
- themeId,
59086
- tokens,
59087
- theme,
59088
- style: {
59089
- ...basePreset,
59090
- fontWeight: footer.navWeight ?? basePreset.fontWeight,
59091
- colorToken: footer.navColor?.trim() || basePreset.colorToken
59092
- },
59093
- className: "footer-nav-link"
59094
- });
59095
- }
59096
- function generateFooterBottomTextLinkStyles(footer, themeId, tokens) {
59097
- const style = footer.bottomTextLinkStyle;
59098
- if (!style) return "";
59099
- const scope = `:where([data-theme-scope="${themeId}"])`;
59100
- const selectors = [`${scope} .block-site-footer .rb-prose a`, `${scope} .block-siteFooter .rb-prose a`];
59101
- const baseRules = [];
59102
- const hoverRules = [];
59103
- const colorToken = style.colorToken?.trim();
59104
- if (colorToken) baseRules.push(`color: ${tokens.getColor(colorToken)};`);
59105
- const decorationColorToken = style.decorationColorToken?.trim();
59106
- if (decorationColorToken) baseRules.push(`text-decoration-color: ${tokens.getColor(decorationColorToken)};`);
59107
- if (style.underline === true) baseRules.push("text-decoration: underline;");
59108
- else if (style.underline === false) baseRules.push("text-decoration: none;");
59109
- const hoverColorToken = style.hoverColorToken?.trim();
59110
- if (hoverColorToken) hoverRules.push(`color: ${tokens.getColor(hoverColorToken)};`);
59111
- const cssChunks = [];
59112
- if (baseRules.length > 0) cssChunks.push(`\n${selectors.join(",\n")} {\n ${baseRules.join("\n ")}\n}\n`);
59113
- if (hoverRules.length > 0) {
59114
- const hoverSelectors = selectors.map((selector) => `${selector}:hover`);
59115
- cssChunks.push(`\n${hoverSelectors.join(",\n")} {\n ${hoverRules.join("\n ")}\n}\n`);
59116
- }
59117
- return cssChunks.join("\n");
59118
- }
59119
- //#endregion
59120
59515
  //#region ../theme-core/src/layout/boundaryCss.ts
59121
59516
  init_sectionTransitions();
59122
59517
  init_transitionCatalogue();
@@ -60736,6 +61131,8 @@ init_atRuleValidation();
60736
61131
  init_expandPalette();
60737
61132
  init_generateButtonCss();
60738
61133
  init_generateCardCss();
61134
+ init_header$1();
61135
+ init_footer();
60739
61136
  init_tokens();
60740
61137
  init_colorStyles();
60741
61138
  function buildThemeRuntime$1(theme, options) {
@@ -61474,9 +61871,10 @@ function pageBlockPosition(index, blockCount) {
61474
61871
  //#endregion
61475
61872
  //#region ../blocks/src/pageRendererContracts.ts
61476
61873
  function buildPageRendererRootRuntime(dataContext) {
61477
- const { siteId = null, pageId = null, pathname = null, bookingTimeZone, previewStage = "published", apiBaseUrl = null, portalToken = null, readAuthority, bookingOfferingPresets = [], appointmentServicePathPrefix = null, mailingList = { tag: "not_configured" }, eventRegistrationOverlayEnabled = false, loaderFailures = {} } = dataContext ?? {};
61874
+ const { siteId = null, siteName, pageId = null, pathname = null, bookingTimeZone, previewStage = "published", apiBaseUrl = null, portalToken = null, readAuthority, bookingOfferingPresets = [], appointmentServicePathPrefix = null, mailingList = { tag: "not_configured" }, eventRegistrationOverlayEnabled = false, loaderFailures = {} } = dataContext ?? {};
61478
61875
  return {
61479
61876
  siteId,
61877
+ siteName,
61480
61878
  pageId,
61481
61879
  pathname,
61482
61880
  bookingTimeZone,
@@ -66106,7 +66504,9 @@ const bookingWizard = bookingForm(withApiBindings({
66106
66504
  } },
66107
66505
  formId: { $bind: { from: "content.formId" } },
66108
66506
  form: { $bind: { from: "data.form" } },
66109
- services: { $bind: { from: "data.services" } }
66507
+ services: { $bind: { from: "data.services" } },
66508
+ mailingList: { $bind: { from: "$root.mailingList" } },
66509
+ siteName: { $bind: { from: "$root.siteName" } }
66110
66510
  }));
66111
66511
  /** Both variants sit in the same section shell; only the inner layout differs. */
66112
66512
  function bookingSection(children) {
@@ -70612,6 +71012,7 @@ function getBlockDefinition(name) {
70612
71012
  //#endregion
70613
71013
  //#region ../blocks/src/system/componentFactory.ts
70614
71014
  init_src$2();
71015
+ init_tokens();
70615
71016
  init_buttons();
70616
71017
  /**
70617
71018
  * Resolves the layout definition for a block based on its manifest and content.
@@ -70687,19 +71088,19 @@ function prepareDefaultBlockRender(manifest, props) {
70687
71088
  const content = props.content;
70688
71089
  const layout = resolveBlockLayout(manifest, content);
70689
71090
  if (!layout) throw new Error(`Block manifest "${manifest.name}" requires a layout definition`);
70690
- const mergedContent = mergeContentWithBlockStyleOverrides(content, props.themeConfig, props.blockKind ?? manifest.name);
71091
+ const prepared = prepareBlockRender({
71092
+ content,
71093
+ theme: props.theme,
71094
+ themeConfig: props.themeConfig,
71095
+ blockKind: props.blockKind ?? manifest.name,
71096
+ data: props.data,
71097
+ viewModelOverrides: props.viewModelOverrides
71098
+ });
70691
71099
  return {
70692
71100
  registry: props.registry,
70693
71101
  layout,
70694
- mergedContent,
70695
- fieldConstraints: buildPreviewFieldConstraints(manifest),
70696
- viewModel: buildBlockViewModel({
70697
- mergedContent,
70698
- data: props.data,
70699
- resolvedThemeConfig: resolveThemeConfigForBindings(props.themeConfig),
70700
- viewModelOverrides: props.viewModelOverrides
70701
- }),
70702
- themeForTransforms: withButtonSystem(props.theme, props.themeConfig)
71102
+ ...prepared,
71103
+ fieldConstraints: buildPreviewFieldConstraints(manifest)
70703
71104
  };
70704
71105
  }
70705
71106
  function makeDefaultBlockComponent(args) {
@@ -70711,6 +71112,7 @@ function makeDefaultBlockComponent(args) {
70711
71112
  viewModel: prepared.viewModel,
70712
71113
  transforms: props.transforms,
70713
71114
  theme: prepared.themeForTransforms,
71115
+ proseHoverCandidate: prepared.proseHoverCandidate,
70714
71116
  pathBase: props.pathBase,
70715
71117
  blockId: props.blockId,
70716
71118
  newsletterBlockSubmission: props.newsletterBlockSubmission,
@@ -70732,6 +71134,20 @@ function makeDefaultBlockComponent(args) {
70732
71134
  return result;
70733
71135
  };
70734
71136
  }
71137
+ function prepareBlockRender(input) {
71138
+ const mergedContent = mergeContentWithBlockStyleOverrides(input.content, input.themeConfig, input.blockKind);
71139
+ return {
71140
+ mergedContent,
71141
+ viewModel: buildBlockViewModel({
71142
+ mergedContent,
71143
+ data: input.data,
71144
+ resolvedThemeConfig: resolveThemeConfigForBindings(input.themeConfig),
71145
+ viewModelOverrides: input.viewModelOverrides
71146
+ }),
71147
+ themeForTransforms: withButtonSystem(input.theme, input.themeConfig),
71148
+ proseHoverCandidate: parseThemeColorToken(input.themeConfig?.typography.proseLinkStyle?.hoverColorToken) ?? void 0
71149
+ };
71150
+ }
70735
71151
  function buildBlockViewModel(input) {
70736
71152
  const themeBinding = input.resolvedThemeConfig ? { theme: input.resolvedThemeConfig } : {};
70737
71153
  const baseData = input.data ? { data: { ...input.data } } : {};
@@ -71317,6 +71733,7 @@ function planNewsletterBlockSubmission(placement) {
71317
71733
  sourceRef
71318
71734
  } : { tag: "unavailable" };
71319
71735
  }
71736
+ if (placement.publishedPlacement && "kind" in placement.publishedPlacement) return { tag: "unpublished-settings" };
71320
71737
  if (placement.publishedPlacement) return planNewsletterPreviewSubmission({
71321
71738
  blockId: placement.blockId,
71322
71739
  publishedContentId: placement.publishedPlacement.id,
@@ -71477,7 +71894,7 @@ function newsletterBlockProps(block, renderedContent, stage) {
71477
71894
  return { newsletterBlockSubmission: planNewsletterBlockSubmission({
71478
71895
  blockId: block.id,
71479
71896
  selectedContentVersionId: block.contentVersionId ?? null,
71480
- publishedPlacement: block.publishedPlacement ?? null,
71897
+ publishedPlacement: block.publishedPlacement,
71481
71898
  renderedContent,
71482
71899
  stage
71483
71900
  }) };
@@ -71574,7 +71991,11 @@ const BlockErrorBoundary = createBlockErrorBoundary();
71574
71991
  /** Pair a published version with the content it authorises at the render boundary. */
71575
71992
  function readPublishedBlockPlacement(id, content) {
71576
71993
  if (id == null && content == null) return null;
71577
- if (id == null || content == null) throw new Error("Published block placement requires both an ID and content");
71994
+ if (id == null || content == null) return {
71995
+ kind: "incomplete",
71996
+ id: id ?? null,
71997
+ content: content ?? null
71998
+ };
71578
71999
  return {
71579
72000
  id,
71580
72001
  content
@@ -71591,7 +72012,7 @@ function toPresentationPage(page) {
71591
72012
  purpose: block.purpose,
71592
72013
  ...block.contentVersionId ? { contentVersionId: block.contentVersionId } : {},
71593
72014
  ...block.draftContentId !== void 0 ? { draftContentId: block.draftContentId } : {},
71594
- ...block.publishedPlacement !== void 0 ? { publishedPlacement: block.publishedPlacement } : {},
72015
+ publishedPlacement: block.publishedPlacement,
71595
72016
  ...block.bindings ? { bindings: block.bindings } : {}
71596
72017
  };
71597
72018
  return block.admission.kind === "renderable" ? {
@@ -74996,6 +75417,8 @@ const containerResponsiveThemeCss = `/*
74996
75417
  --rb-surface-text-color: var(--rb-modal-text, rgb(var(--tb-text, 17 24 39)));
74997
75418
  --rb-surface-heading-color: var(--rb-modal-heading, var(--rb-modal-text, rgb(var(--tb-text, 17 24 39))));
74998
75419
  --rb-surface-link-color: var(--rb-modal-link, var(--rb-modal-text, rgb(var(--tb-text, 17 24 39))));
75420
+ --rb-surface-link-hover-color: var(--rb-modal-link, var(--rb-modal-text, rgb(var(--tb-text, 17 24 39))));
75421
+ --rb-surface-link-hover-decoration: underline;
74999
75422
  --rb-surface-supporting-color: var(--rb-modal-supporting, var(--rb-modal-text, rgb(var(--tb-text, 17 24 39))));
75000
75423
  border: 1px solid var(--rb-modal-border, rgb(var(--tb-border)));
75001
75424
  border-radius: var(--rb-modal-radius, var(--radius-card));
@@ -75425,14 +75848,18 @@ const containerResponsiveThemeCss = `/*
75425
75848
 
75426
75849
  :where(.theme-scope) .rb-prose a:hover {
75427
75850
  color: var(
75428
- --rb-prose-link-hover-color,
75429
- var(--rb-prose-effective-link-color)
75851
+ --rb-surface-link-hover-color,
75852
+ var(--rb-prose-link-hover-color, var(--rb-prose-effective-link-color))
75853
+ );
75854
+ text-decoration-line: var(
75855
+ --rb-surface-link-hover-decoration,
75856
+ var(--rb-prose-link-decoration-line, underline)
75430
75857
  );
75431
75858
  text-decoration-color: var(
75432
75859
  --rb-prose-link-hover-decoration-color,
75433
75860
  var(
75434
- --rb-prose-link-hover-color,
75435
- var(--rb-prose-effective-link-color)
75861
+ --rb-surface-link-hover-color,
75862
+ var(--rb-prose-link-hover-color, var(--rb-prose-effective-link-color))
75436
75863
  )
75437
75864
  );
75438
75865
  }
@@ -76476,6 +76903,8 @@ const containerResponsiveThemeCss = `/*
76476
76903
  --rb-surface-text-color: rgb(var(--tb-onSurface, var(--tb-text)));
76477
76904
  --rb-surface-heading-color: rgb(var(--tb-onSurface, var(--tb-text)));
76478
76905
  --rb-surface-link-color: rgb(var(--tb-onSurface, var(--tb-text)));
76906
+ --rb-surface-link-hover-color: rgb(var(--tb-onSurface, var(--tb-text)));
76907
+ --rb-surface-link-hover-decoration: underline;
76479
76908
  --rb-surface-supporting-color: rgb(var(--tb-onSurface, var(--tb-text)));
76480
76909
  border: 1px solid rgb(var(--tb-border));
76481
76910
  border-radius: var(--radius-card);
@@ -76623,6 +77052,8 @@ const containerResponsiveThemeCss = `/*
76623
77052
  --rb-surface-text-color: var(--rb-reg-on-surface, rgb(var(--tb-onSurface, var(--tb-text, 15 23 42))));
76624
77053
  --rb-surface-heading-color: var(--rb-reg-on-surface, rgb(var(--tb-onSurface, var(--tb-text, 15 23 42))));
76625
77054
  --rb-surface-link-color: var(--rb-reg-on-surface, rgb(var(--tb-onSurface, var(--tb-text, 15 23 42))));
77055
+ --rb-surface-link-hover-color: var(--rb-reg-on-surface, rgb(var(--tb-onSurface, var(--tb-text, 15 23 42))));
77056
+ --rb-surface-link-hover-decoration: underline;
76626
77057
  --rb-surface-supporting-color: var(--rb-reg-on-surface-muted, var(--rb-reg-on-surface, rgb(var(--tb-onSurface, var(--tb-text, 15 23 42)))));
76627
77058
  transition: border-color var(--rb-block-transition, 150ms) ease;
76628
77059
  width: 100%;
@@ -82602,6 +83033,8 @@ const containerResponsiveThemeCss = `/*
82602
83033
  --rb-surface-text-color: inherit;
82603
83034
  --rb-surface-heading-color: inherit;
82604
83035
  --rb-surface-link-color: inherit;
83036
+ --rb-surface-link-hover-color: inherit;
83037
+ --rb-surface-link-hover-decoration: inherit;
82605
83038
  --rb-surface-supporting-color: inherit;
82606
83039
  }
82607
83040
 
@@ -82699,6 +83132,8 @@ const containerResponsiveThemeCss = `/*
82699
83132
  --rb-surface-text-color: rgb(var(--tb-text, 17 24 39));
82700
83133
  --rb-surface-heading-color: rgb(var(--tb-text, 17 24 39));
82701
83134
  --rb-surface-link-color: rgb(var(--tb-primary, var(--tb-text, 17 24 39)));
83135
+ --rb-surface-link-hover-color: var(--rb-prose-link-hover-color, rgb(var(--tb-primary, var(--tb-text, 17 24 39))));
83136
+ --rb-surface-link-hover-decoration: initial;
82702
83137
  --rb-surface-supporting-color: rgb(var(--tb-mutedText, 100 116 139));
82703
83138
  border: 1px solid rgb(var(--tb-border));
82704
83139
  border-radius: var(--shop-card-radius);
@@ -82865,6 +83300,8 @@ const containerResponsiveThemeCss = `/*
82865
83300
  --rb-surface-text-color: rgb(var(--tb-text, 17 24 39));
82866
83301
  --rb-surface-heading-color: rgb(var(--tb-text, 17 24 39));
82867
83302
  --rb-surface-link-color: rgb(var(--tb-primary, var(--tb-text, 17 24 39)));
83303
+ --rb-surface-link-hover-color: var(--rb-prose-link-hover-color, rgb(var(--tb-primary, var(--tb-text, 17 24 39))));
83304
+ --rb-surface-link-hover-decoration: initial;
82868
83305
  --rb-surface-supporting-color: rgb(var(--tb-mutedText, 100 116 139));
82869
83306
  }
82870
83307
 
@@ -82942,6 +83379,8 @@ const containerResponsiveThemeCss = `/*
82942
83379
  --rb-surface-text-color: var(--cp-text);
82943
83380
  --rb-surface-heading-color: var(--cp-text);
82944
83381
  --rb-surface-link-color: var(--cp-primary);
83382
+ --rb-surface-link-hover-color: var(--rb-prose-link-hover-color, var(--cp-primary));
83383
+ --rb-surface-link-hover-decoration: initial;
82945
83384
  --rb-surface-supporting-color: var(--cp-muted);
82946
83385
  border: 1px solid var(--cp-card-border);
82947
83386
  border-radius: var(--cp-card-radius);
@@ -83091,6 +83530,8 @@ const containerResponsiveThemeCss = `/*
83091
83530
  --rb-surface-text-color: var(--cp-text);
83092
83531
  --rb-surface-heading-color: var(--cp-text);
83093
83532
  --rb-surface-link-color: var(--cp-primary);
83533
+ --rb-surface-link-hover-color: var(--rb-prose-link-hover-color, var(--cp-primary));
83534
+ --rb-surface-link-hover-decoration: initial;
83094
83535
  --rb-surface-supporting-color: var(--cp-muted);
83095
83536
  border: 1px dashed var(--cp-card-border);
83096
83537
  border-radius: var(--cp-card-radius);
@@ -83108,6 +83549,8 @@ const containerResponsiveThemeCss = `/*
83108
83549
  --rb-surface-text-color: var(--cp-text);
83109
83550
  --rb-surface-heading-color: var(--cp-text);
83110
83551
  --rb-surface-link-color: var(--cp-primary);
83552
+ --rb-surface-link-hover-color: var(--rb-prose-link-hover-color, var(--cp-primary));
83553
+ --rb-surface-link-hover-decoration: initial;
83111
83554
  --rb-surface-supporting-color: var(--cp-muted);
83112
83555
  border: 1px solid var(--cp-card-border);
83113
83556
  border-radius: var(--cp-card-radius);
@@ -83348,6 +83791,8 @@ const containerResponsiveThemeCss = `/*
83348
83791
  --rb-surface-text-color: var(--cp-text);
83349
83792
  --rb-surface-heading-color: var(--cp-text);
83350
83793
  --rb-surface-link-color: var(--cp-primary);
83794
+ --rb-surface-link-hover-color: var(--rb-prose-link-hover-color, var(--cp-primary));
83795
+ --rb-surface-link-hover-decoration: initial;
83351
83796
  --rb-surface-supporting-color: var(--cp-muted);
83352
83797
  border: 1px solid var(--cp-card-border);
83353
83798
  border-radius: var(--cp-card-radius);
@@ -86011,6 +86456,8 @@ const containerResponsiveThemeCss = `/*
86011
86456
  --rb-surface-text-color: rgb(var(--tb-onSecondary));
86012
86457
  --rb-surface-heading-color: rgb(var(--tb-onSecondary));
86013
86458
  --rb-surface-link-color: rgb(var(--tb-onSecondary));
86459
+ --rb-surface-link-hover-color: rgb(var(--tb-onSecondary));
86460
+ --rb-surface-link-hover-decoration: underline;
86014
86461
  --rb-surface-supporting-color: rgb(var(--tb-onSecondary));
86015
86462
  }
86016
86463
 
@@ -86142,6 +86589,8 @@ const containerResponsiveThemeCss = `/*
86142
86589
  --rb-surface-text-color: rgb(var(--tb-onPrimary));
86143
86590
  --rb-surface-heading-color: rgb(var(--tb-onPrimary));
86144
86591
  --rb-surface-link-color: rgb(var(--tb-onPrimary));
86592
+ --rb-surface-link-hover-color: rgb(var(--tb-onPrimary));
86593
+ --rb-surface-link-hover-decoration: underline;
86145
86594
  --rb-surface-supporting-color: color-mix(in oklab, rgb(var(--tb-onPrimary)), transparent 18%);
86146
86595
  }
86147
86596
 
@@ -89615,7 +90064,10 @@ function usePage(params) {
89615
90064
  let cancelled = false;
89616
90065
  async function fetchPage() {
89617
90066
  try {
89618
- const [site, pageResponse] = await Promise.all([client.getSite({ id: siteId }), client.getPage({
90067
+ const [site, pageResponse] = await Promise.all([client.getSite({
90068
+ id: siteId,
90069
+ currentPath: path
90070
+ }), client.getPage({
89619
90071
  siteId,
89620
90072
  path,
89621
90073
  preview
@@ -89837,7 +90289,10 @@ function useContent(params) {
89837
90289
  let cancelled = false;
89838
90290
  async function fetchContent() {
89839
90291
  try {
89840
- const [site, contentResponse] = await Promise.all([client.getSite({ id: siteId }), client.getPage({
90292
+ const [site, contentResponse] = await Promise.all([client.getSite({
90293
+ id: siteId,
90294
+ currentPath: path
90295
+ }), client.getPage({
89841
90296
  siteId,
89842
90297
  path,
89843
90298
  preview
@@ -90110,7 +90565,7 @@ var init_accordion = __esmMin((() => {
90110
90565
  }));
90111
90566
  //#endregion
90112
90567
  //#region ../blocks/src/system/runtime/nodes/shop-commerce-store.ts
90113
- function storageKey(siteId) {
90568
+ function storageKey$1(siteId) {
90114
90569
  return `riverbank:shop-cart:${siteId}`;
90115
90570
  }
90116
90571
  function getStore(siteId) {
@@ -90144,7 +90599,7 @@ var init_shop_commerce_store = __esmMin((() => {
90144
90599
  constructor(siteId) {
90145
90600
  this.siteId = siteId;
90146
90601
  this.listeners = /* @__PURE__ */ new Set();
90147
- this.state = typeof window === "undefined" ? EMPTY_STATE : parseStoredCommerceCartState(window.localStorage.getItem(storageKey(siteId)));
90602
+ this.state = typeof window === "undefined" ? EMPTY_STATE : parseStoredCommerceCartState(window.localStorage.getItem(storageKey$1(siteId)));
90148
90603
  }
90149
90604
  subscribe(listener) {
90150
90605
  this.listeners.add(listener);
@@ -90198,7 +90653,7 @@ var init_shop_commerce_store = __esmMin((() => {
90198
90653
  }
90199
90654
  setState(nextState) {
90200
90655
  this.state = nextState;
90201
- if (typeof window !== "undefined") window.localStorage.setItem(storageKey(this.siteId), JSON.stringify(nextState));
90656
+ if (typeof window !== "undefined") window.localStorage.setItem(storageKey$1(this.siteId), JSON.stringify(nextState));
90202
90657
  for (const listener of this.listeners) listener();
90203
90658
  }
90204
90659
  };
@@ -151264,121 +151719,6 @@ var init_form = __esmMin((() => {
151264
151719
  };
151265
151720
  }));
151266
151721
  //#endregion
151267
- //#region ../blocks/src/system/runtime/shared/components/CheckIcon.tsx
151268
- function CheckIcon({ className, strokeWidth = 2 }) {
151269
- return /* @__PURE__ */ jsx("svg", {
151270
- fill: "none",
151271
- strokeLinecap: "round",
151272
- strokeLinejoin: "round",
151273
- strokeWidth,
151274
- viewBox: "0 0 24 24",
151275
- stroke: "currentColor",
151276
- className,
151277
- width: "1em",
151278
- height: "1em",
151279
- "aria-hidden": "true",
151280
- children: /* @__PURE__ */ jsx("path", { d: "M5 13l4 4L19 7" })
151281
- });
151282
- }
151283
- var init_CheckIcon$1 = __esmMin((() => {}));
151284
- //#endregion
151285
- //#region ../blocks/src/system/runtime/shared/components/StateIcon.tsx
151286
- /**
151287
- * Circular icon wrapper for terminal state screens (success, error, waitlist, etc.).
151288
- *
151289
- * Layout is provided by shared `rb-state-icon` CSS; color variants are
151290
- * block-scoped by the owning registration surface.
151291
- */
151292
- function StateIcon({ variant, children }) {
151293
- return /* @__PURE__ */ jsx("div", {
151294
- className: `rb-state-icon rb-state-icon--${variant}`,
151295
- "aria-hidden": "true",
151296
- children
151297
- });
151298
- }
151299
- var init_StateIcon = __esmMin((() => {}));
151300
- //#endregion
151301
- //#region ../blocks/src/system/runtime/shared/components/TerminalPanel.tsx
151302
- function joinClasses$1(...parts) {
151303
- return parts.filter((part) => typeof part === "string" && part.length > 0).join(" ");
151304
- }
151305
- function TerminalPanel({ tone, title, titleAs: Title = "h3", body, secondaryBody, icon, actions, className, titleClassName, bodyClassName, secondaryBodyClassName, iconClassName, actionsClassName, role, live }) {
151306
- const resolvedRole = role ?? (tone === "error" ? "alert" : "status");
151307
- const resolvedLive = live ?? (resolvedRole === "alert" ? "assertive" : "polite");
151308
- return /* @__PURE__ */ jsxs("div", {
151309
- className,
151310
- "data-terminal-panel": true,
151311
- "data-terminal-tone": tone,
151312
- role: resolvedRole,
151313
- "aria-live": resolvedLive === "off" ? void 0 : resolvedLive,
151314
- children: [
151315
- icon ? /* @__PURE__ */ jsx("div", {
151316
- className: joinClasses$1(iconClassName),
151317
- "data-terminal-icon": true,
151318
- children: icon
151319
- }) : null,
151320
- /* @__PURE__ */ jsx(Title, {
151321
- className: joinClasses$1(titleClassName),
151322
- "data-terminal-title": true,
151323
- children: title
151324
- }),
151325
- body ? /* @__PURE__ */ jsx("div", {
151326
- className: joinClasses$1(bodyClassName),
151327
- "data-terminal-body": true,
151328
- children: body
151329
- }) : null,
151330
- actions ? /* @__PURE__ */ jsx("div", {
151331
- className: joinClasses$1(actionsClassName),
151332
- "data-terminal-actions": true,
151333
- children: actions
151334
- }) : null,
151335
- secondaryBody ? /* @__PURE__ */ jsx("div", {
151336
- className: joinClasses$1(secondaryBodyClassName),
151337
- "data-terminal-secondary-body": true,
151338
- children: secondaryBody
151339
- }) : null
151340
- ]
151341
- });
151342
- }
151343
- var init_TerminalPanel = __esmMin((() => {}));
151344
- //#endregion
151345
- //#region ../blocks/src/system/runtime/components/booking/SuccessMessage.tsx
151346
- /**
151347
- * SuccessMessage Component
151348
- *
151349
- * Terminal success state after a completed appointment booking.
151350
- * Rendered on the shared registration-surface (see booking-form.client),
151351
- * using the shared TerminalPanel + StateIcon primitives.
151352
- */
151353
- var SuccessMessage;
151354
- var init_SuccessMessage = __esmMin((() => {
151355
- init_CheckIcon$1();
151356
- init_StateIcon();
151357
- init_TerminalPanel();
151358
- SuccessMessage = ({ message, resourceName, className }) => {
151359
- return /* @__PURE__ */ jsx(TerminalPanel, {
151360
- tone: "success",
151361
- title: "Booking confirmed",
151362
- icon: /* @__PURE__ */ jsx(StateIcon, {
151363
- variant: "success",
151364
- children: /* @__PURE__ */ jsx(CheckIcon, { strokeWidth: 3 })
151365
- }),
151366
- body: /* @__PURE__ */ jsx("p", {
151367
- className: "ab-text",
151368
- children: message
151369
- }),
151370
- secondaryBody: resourceName ? /* @__PURE__ */ jsxs("p", {
151371
- className: "ab-text rb-on-surface--muted",
151372
- children: ["Practitioner: ", resourceName]
151373
- }) : null,
151374
- className: ["ab-center", className ?? ""].join(" ").trim(),
151375
- titleClassName: "ab-terminal-title",
151376
- role: "alert",
151377
- live: "polite"
151378
- });
151379
- };
151380
- }));
151381
- //#endregion
151382
151722
  //#region ../blocks/src/system/runtime/hooks/useSelectedAppointmentConsentForm.ts
151383
151723
  function useSelectedAppointmentConsentForm(form, selectedService) {
151384
151724
  return useMemo(() => projectSelectedAppointmentConsentIntoForm(form, resolveSelectedAppointmentConsent(selectedService)), [form, selectedService]);
@@ -151960,6 +152300,7 @@ function useBookingSubmission(_siteId) {
151960
152300
  startAt: data.startAt,
151961
152301
  endAt: data.endAt,
151962
152302
  customFields: data.customFields,
152303
+ mailingListOptIn: data.mailingListOptIn,
151963
152304
  timezone: data.timezone,
151964
152305
  customerPassId: data.customerPassId
151965
152306
  }) : await api.submitBooking({
@@ -151969,6 +152310,7 @@ function useBookingSubmission(_siteId) {
151969
152310
  startAt: data.startAt,
151970
152311
  endAt: data.endAt,
151971
152312
  customFields: data.customFields,
152313
+ mailingListOptIn: data.mailingListOptIn,
151972
152314
  timezone: data.timezone,
151973
152315
  discountCode: data.discountCode,
151974
152316
  selectedSlidingAmount: data.selectedSlidingAmount,
@@ -152009,6 +152351,43 @@ var init_useBookingSubmission = __esmMin((() => {
152009
152351
  init_useBookingSubmission_state();
152010
152352
  }));
152011
152353
  //#endregion
152354
+ //#region ../blocks/src/system/runtime/nodes/booking-form.submit-success.ts
152355
+ function completeBookingSubmission(input) {
152356
+ const { data } = input;
152357
+ if (data.type === "checkout_redirect") {
152358
+ if (input.redirect === "auto" && typeof window !== "undefined") input.navigateToCheckout(data.checkoutUrl);
152359
+ return {
152360
+ ok: true,
152361
+ outcome: {
152362
+ kind: "checkout_redirect",
152363
+ checkoutUrl: data.checkoutUrl,
152364
+ sessionId: data.sessionId,
152365
+ ...data.mailingListSignupNote ? { mailingListSignupNote: data.mailingListSignupNote } : {}
152366
+ }
152367
+ };
152368
+ }
152369
+ input.dispatch({
152370
+ type: "feedback-set",
152371
+ feedback: {
152372
+ kind: "success",
152373
+ message: getBookingSuccessMessage(input.successMessage),
152374
+ resourceName: data.appointment.resourceName
152375
+ }
152376
+ });
152377
+ return {
152378
+ ok: true,
152379
+ outcome: {
152380
+ kind: "booked",
152381
+ appointmentId: data.appointment.id,
152382
+ resourceName: data.appointment.resourceName,
152383
+ ...data.mailingListSignupNote ? { mailingListSignupNote: data.mailingListSignupNote } : {}
152384
+ }
152385
+ };
152386
+ }
152387
+ var init_booking_form_submit_success = __esmMin((() => {
152388
+ init_booking_form_state();
152389
+ }));
152390
+ //#endregion
152012
152391
  //#region ../blocks/src/system/runtime/nodes/event-registration/useDiscountCodeUi.state.ts
152013
152392
  function getDiscountContextKey(context) {
152014
152393
  if (!context) return "disabled";
@@ -152506,6 +152885,43 @@ function clearBookingFieldError(errors, fieldId) {
152506
152885
  }
152507
152886
  var init_booking_form_validationErrors = __esmMin((() => {}));
152508
152887
  //#endregion
152888
+ //#region ../blocks/src/system/runtime/nodes/booking-form.mailing-list-state.ts
152889
+ function bookingFormDataWithEligibleOptIn(data, eligible) {
152890
+ return {
152891
+ ...data,
152892
+ mailingListOptIn: eligible && data.mailingListOptIn === true
152893
+ };
152894
+ }
152895
+ function isBookingContactEvent(event) {
152896
+ return event.type === "field-updated" || event.type === "field-touched" || event.type === "mailing-list-opt-in-set";
152897
+ }
152898
+ function applyBookingContactEvent(state, event) {
152899
+ switch (event.type) {
152900
+ case "field-updated": return {
152901
+ ...state,
152902
+ fieldValues: {
152903
+ ...state.fieldValues,
152904
+ [event.fieldId]: event.value
152905
+ },
152906
+ validationErrors: clearBookingFieldError(clearBookingFormError(state.validationErrors), event.fieldId)
152907
+ };
152908
+ case "field-touched": return {
152909
+ ...state,
152910
+ touchedFields: {
152911
+ ...state.touchedFields,
152912
+ [event.fieldId]: true
152913
+ }
152914
+ };
152915
+ case "mailing-list-opt-in-set": return {
152916
+ ...state,
152917
+ mailingListOptIn: event.checked
152918
+ };
152919
+ }
152920
+ }
152921
+ var init_booking_form_mailing_list_state = __esmMin((() => {
152922
+ init_booking_form_validationErrors();
152923
+ }));
152924
+ //#endregion
152509
152925
  //#region ../blocks/src/system/runtime/nodes/booking-form.field-values.ts
152510
152926
  function collectInitialBookingFieldValues(initialData) {
152511
152927
  const values = {};
@@ -152534,6 +152950,7 @@ function createInitialBookingFlowReducerState(input) {
152534
152950
  selectedDate: toOptionalString(initialData.selectedDate),
152535
152951
  selectedSlot: null,
152536
152952
  fieldValues: collectInitialBookingFieldValues(initialData),
152953
+ mailingListOptIn: initialData.mailingListOptIn === true,
152537
152954
  touchedFields: {},
152538
152955
  attemptedStepIds: {},
152539
152956
  discountCode: toOptionalString(initialData.discountCode) ?? "",
@@ -152583,6 +153000,7 @@ function applyAvailabilitySelectionInvalidation(state, invalidation) {
152583
153000
  };
152584
153001
  }
152585
153002
  function bookingFlowReducer(state, event) {
153003
+ if (isBookingContactEvent(event)) return applyBookingContactEvent(state, event);
152586
153004
  switch (event.type) {
152587
153005
  case "service-selected": return applyBookingServiceSelection(state, event.serviceId);
152588
153006
  case "resource-selected": return {
@@ -152605,21 +153023,6 @@ function bookingFlowReducer(state, event) {
152605
153023
  feedback: clearAvailabilityFeedback(state.feedback),
152606
153024
  validationErrors: clearBookingFormError(state.validationErrors)
152607
153025
  };
152608
- case "field-updated": return {
152609
- ...state,
152610
- fieldValues: {
152611
- ...state.fieldValues,
152612
- [event.fieldId]: event.value
152613
- },
152614
- validationErrors: clearBookingFieldError(clearBookingFormError(state.validationErrors), event.fieldId)
152615
- };
152616
- case "field-touched": return {
152617
- ...state,
152618
- touchedFields: {
152619
- ...state.touchedFields,
152620
- [event.fieldId]: true
152621
- }
152622
- };
152623
153026
  case "step-advance-attempted": return state.attemptedStepIds[event.stepId] ? state : {
152624
153027
  ...state,
152625
153028
  attemptedStepIds: {
@@ -152757,6 +153160,7 @@ function deriveBookingSlotDisplayOptions(input) {
152757
153160
  function toBookingFormData(state) {
152758
153161
  return {
152759
153162
  ...state.fieldValues,
153163
+ mailingListOptIn: state.mailingListOptIn,
152760
153164
  serviceId: state.selectedServiceId,
152761
153165
  resourceId: state.selectedResourceId ?? state.selectedSlot?.resourceId,
152762
153166
  selectedDate: state.selectedDate,
@@ -153019,10 +153423,7 @@ function buildBookingSubmitPlan(input) {
153019
153423
  };
153020
153424
  const prepared = prepareBookingSubmission({
153021
153425
  formId: input.formId,
153022
- data: toBookingFormData({
153023
- ...input.state,
153024
- altchaSolution: input.altchaSolution ?? input.state.altchaSolution
153025
- }),
153426
+ data: bookingFormDataWithEligibleOptIn(toBookingFormData(input.state), Boolean(input.mailingListEligible)),
153026
153427
  services: input.services,
153027
153428
  defaultServiceId: input.defaultServiceId,
153028
153429
  defaultResourceId: input.defaultResourceId,
@@ -153170,6 +153571,7 @@ var init_booking_form_headless_state = __esmMin((() => {
153170
153571
  init_dist$1();
153171
153572
  init_booking_form_state();
153172
153573
  init_booking_form_service_categories();
153574
+ init_booking_form_mailing_list_state();
153173
153575
  init_booking_form_validationErrors();
153174
153576
  init_booking_form_field_values();
153175
153577
  unsafeAsBookingFieldId = (id) => id;
@@ -153223,6 +153625,8 @@ function useHeadlessBookingFlow(options) {
153223
153625
  const canLoadAppointmentPackages = Boolean(options.enableAppointmentPackages && hasPortalBearerAuth && selectedService && !selectedServiceSlidingScale && (selectedService.priceAmount ?? 0) > 0);
153224
153626
  const appointmentPackagesUnavailableReason = !options.enableAppointmentPackages ? "disabled" : !selectedService || selectedServiceSlidingScale || (selectedService.priceAmount ?? 0) <= 0 ? "missing-priced-service" : !hasPortalBearerAuth ? "missing-portal-auth" : null;
153225
153627
  const data = useMemo(() => toBookingFormData(state), [state]);
153628
+ const mailingList = resolveBookingSignupOffer(options.mailingList, options.siteName);
153629
+ const mailingListEligible = mailingList !== null;
153226
153630
  const availabilityDatesQuery = useMemo(() => buildBookingAvailabilityQuery({
153227
153631
  serviceId: selectedServiceId,
153228
153632
  resourceId: selectedResourceId,
@@ -153483,7 +153887,8 @@ function useHeadlessBookingFlow(options) {
153483
153887
  viewerTimeZone: latest.viewerTimeZone,
153484
153888
  redirect: submitOptions?.redirect ?? "manual",
153485
153889
  successUrl: submitOptions?.successUrl,
153486
- cancelUrl: submitOptions?.cancelUrl
153890
+ cancelUrl: submitOptions?.cancelUrl,
153891
+ mailingListEligible
153487
153892
  });
153488
153893
  if (!plan.ok) {
153489
153894
  dispatch({
@@ -153516,37 +153921,18 @@ function useHeadlessBookingFlow(options) {
153516
153921
  message: result.error
153517
153922
  };
153518
153923
  }
153519
- if (result.data.type === "checkout_redirect") {
153520
- if (plan.redirect === "auto" && typeof window !== "undefined") latest.navigateToCheckout(result.data.checkoutUrl);
153521
- return {
153522
- ok: true,
153523
- outcome: {
153524
- kind: "checkout_redirect",
153525
- checkoutUrl: result.data.checkoutUrl
153526
- }
153527
- };
153528
- }
153529
- dispatch({
153530
- type: "feedback-set",
153531
- feedback: {
153532
- kind: "success",
153533
- message: getBookingSuccessMessage(latest.successMessage),
153534
- resourceName: result.data.appointment.resourceName
153535
- }
153924
+ return completeBookingSubmission({
153925
+ data: result.data,
153926
+ redirect: plan.redirect,
153927
+ successMessage: latest.successMessage,
153928
+ navigateToCheckout: latest.navigateToCheckout,
153929
+ dispatch
153536
153930
  });
153537
- return {
153538
- ok: true,
153539
- outcome: {
153540
- kind: "booked",
153541
- appointmentId: result.data.appointment.id,
153542
- resourceName: result.data.appointment.resourceName
153543
- }
153544
- };
153545
153931
  } finally {
153546
153932
  submittingRef.current = false;
153547
153933
  dispatch({ type: "submission-finished" });
153548
153934
  }
153549
- }, [latestRef]);
153935
+ }, [latestRef, mailingListEligible]);
153550
153936
  const actions = useMemo(() => ({
153551
153937
  selectService: (serviceId) => dispatch({
153552
153938
  type: "service-selected",
@@ -153569,6 +153955,10 @@ function useHeadlessBookingFlow(options) {
153569
153955
  fieldId: unsafeAsBookingFieldId(fieldId),
153570
153956
  value
153571
153957
  }),
153958
+ setMailingListOptIn: (checked) => dispatch({
153959
+ type: "mailing-list-opt-in-set",
153960
+ checked
153961
+ }),
153572
153962
  markFieldTouched: (fieldId) => dispatch({
153573
153963
  type: "field-touched",
153574
153964
  fieldId: unsafeAsBookingFieldId(fieldId)
@@ -153727,6 +154117,8 @@ function useHeadlessBookingFlow(options) {
153727
154117
  appointmentPackages: appointmentPackagesModel
153728
154118
  };
153729
154119
  return {
154120
+ mailingList,
154121
+ mailingListOptIn: state.mailingListOptIn,
153730
154122
  status,
153731
154123
  view,
153732
154124
  steps: stepState.steps,
@@ -153826,6 +154218,7 @@ var init_useHeadlessBookingFlow = __esmMin((() => {
153826
154218
  init_useAvailableDates();
153827
154219
  init_useAvailableSlots();
153828
154220
  init_useBookingSubmission();
154221
+ init_booking_form_submit_success();
153829
154222
  init_useDiscountCodeUi();
153830
154223
  init_date_formatting();
153831
154224
  init_bookingPaymentOptions();
@@ -154297,6 +154690,24 @@ var init_TimeSlotSelector = __esmMin((() => {
154297
154690
  };
154298
154691
  }));
154299
154692
  //#endregion
154693
+ //#region ../blocks/src/system/runtime/shared/components/CheckIcon.tsx
154694
+ function CheckIcon({ className, strokeWidth = 2 }) {
154695
+ return /* @__PURE__ */ jsx("svg", {
154696
+ fill: "none",
154697
+ strokeLinecap: "round",
154698
+ strokeLinejoin: "round",
154699
+ strokeWidth,
154700
+ viewBox: "0 0 24 24",
154701
+ stroke: "currentColor",
154702
+ className,
154703
+ width: "1em",
154704
+ height: "1em",
154705
+ "aria-hidden": "true",
154706
+ children: /* @__PURE__ */ jsx("path", { d: "M5 13l4 4L19 7" })
154707
+ });
154708
+ }
154709
+ var init_CheckIcon$1 = __esmMin((() => {}));
154710
+ //#endregion
154300
154711
  //#region ../blocks/src/system/runtime/shared/components/StepIndicator.tsx
154301
154712
  function buildClassChannels(slot, classPrefix, emitSharedClasses) {
154302
154713
  const classes = [];
@@ -154494,6 +154905,28 @@ var init_BookingConsentAgreement = __esmMin((() => {
154494
154905
  init_RichText();
154495
154906
  }));
154496
154907
  //#endregion
154908
+ //#region ../blocks/src/system/runtime/nodes/booking-form.mailing-list-choice.tsx
154909
+ function BookingMailingListChoice({ booking }) {
154910
+ const id = React.useId();
154911
+ if (!booking.mailingList) return null;
154912
+ return /* @__PURE__ */ jsxs("div", {
154913
+ className: "rb-space-y-2",
154914
+ children: [/* @__PURE__ */ jsx(CheckboxChoice, {
154915
+ id,
154916
+ name: "mailingListOptIn",
154917
+ checked: booking.mailingListOptIn,
154918
+ onChange: (event) => booking.actions.setMailingListOptIn(event.target.checked),
154919
+ label: `Email me news and updates from ${booking.mailingList.siteName}.`
154920
+ }), /* @__PURE__ */ jsx("p", {
154921
+ className: "rb-caption status-muted",
154922
+ children: "Optional. You can unsubscribe at any time."
154923
+ })]
154924
+ });
154925
+ }
154926
+ var init_booking_form_mailing_list_choice = __esmMin((() => {
154927
+ init_CheckboxChoice();
154928
+ }));
154929
+ //#endregion
154497
154930
  //#region ../blocks/src/system/runtime/nodes/booking-form.service-choices.tsx
154498
154931
  function optionCardClassName(isSelected) {
154499
154932
  return `rb-option-card${isSelected ? " rb-option-card--selected" : ""}`;
@@ -154978,12 +155411,17 @@ function PaymentOptionContent({ description, helperText, id, summaryRows, title
154978
155411
  });
154979
155412
  }
154980
155413
  function DefaultDynamicFields({ booking, fields }) {
155414
+ const lastContactIndex = fields.reduce((last, field, index) => [
155415
+ "name",
155416
+ "email",
155417
+ "phone"
155418
+ ].includes(field.id) ? index : last, -1);
154981
155419
  return /* @__PURE__ */ jsx("div", {
154982
155420
  className: "rb-space-y-6",
154983
- children: fields.map((field) => /* @__PURE__ */ jsx(DefaultDynamicField, {
155421
+ children: fields.map((field, index) => /* @__PURE__ */ jsxs(React.Fragment, { children: [/* @__PURE__ */ jsx(DefaultDynamicField, {
154984
155422
  booking,
154985
155423
  field
154986
- }, field.id))
155424
+ }), index === lastContactIndex && booking.mailingList ? /* @__PURE__ */ jsx(BookingMailingListChoice, { booking }) : null] }, field.id))
154987
155425
  });
154988
155426
  }
154989
155427
  function DefaultDynamicField({ booking, field }) {
@@ -155267,6 +155705,7 @@ var init_booking_form_default_ui = __esmMin((() => {
155267
155705
  init_DiscountCodeDisclosure();
155268
155706
  init_FieldValidationMessage();
155269
155707
  init_BookingConsentAgreement();
155708
+ init_booking_form_mailing_list_choice();
155270
155709
  init_CheckboxChoice();
155271
155710
  init_booking_form_service_choices();
155272
155711
  }));
@@ -155472,12 +155911,12 @@ function CrossIcon({ className, strokeWidth = 2 }) {
155472
155911
  var init_CrossIcon = __esmMin((() => {}));
155473
155912
  //#endregion
155474
155913
  //#region ../blocks/src/system/runtime/shared/components/ActionRow.tsx
155475
- function joinClasses(...parts) {
155914
+ function joinClasses$1(...parts) {
155476
155915
  return parts.filter((part) => typeof part === "string" && part.length > 0).join(" ");
155477
155916
  }
155478
155917
  function ActionRow({ children, className, align = "start" }) {
155479
155918
  return /* @__PURE__ */ jsx("div", {
155480
- className: joinClasses("rb-flex rb-flex-wrap rb-items-center rb-gap-2", alignmentClasses[align], className),
155919
+ className: joinClasses$1("rb-flex rb-flex-wrap rb-items-center rb-gap-2", alignmentClasses[align], className),
155481
155920
  "data-action-row": true,
155482
155921
  children
155483
155922
  });
@@ -155514,6 +155953,22 @@ function LoggedInAsUser({ email, onLogout, classPrefix }) {
155514
155953
  });
155515
155954
  }
155516
155955
  var init_LoggedInAsUser = __esmMin((() => {}));
155956
+ //#endregion
155957
+ //#region ../blocks/src/system/runtime/shared/components/StateIcon.tsx
155958
+ /**
155959
+ * Circular icon wrapper for terminal state screens (success, error, waitlist, etc.).
155960
+ *
155961
+ * Layout is provided by shared `rb-state-icon` CSS; color variants are
155962
+ * block-scoped by the owning registration surface.
155963
+ */
155964
+ function StateIcon({ variant, children }) {
155965
+ return /* @__PURE__ */ jsx("div", {
155966
+ className: `rb-state-icon rb-state-icon--${variant}`,
155967
+ "aria-hidden": "true",
155968
+ children
155969
+ });
155970
+ }
155971
+ var init_StateIcon = __esmMin((() => {}));
155517
155972
  var init_MembershipHero$1 = __esmMin((() => {
155518
155973
  init_FeedbackMessage();
155519
155974
  }));
@@ -155572,6 +156027,50 @@ var init_TabBarFragment = __esmMin((() => {
155572
156027
  init_clsx();
155573
156028
  }));
155574
156029
  //#endregion
156030
+ //#region ../blocks/src/system/runtime/shared/components/TerminalPanel.tsx
156031
+ function joinClasses(...parts) {
156032
+ return parts.filter((part) => typeof part === "string" && part.length > 0).join(" ");
156033
+ }
156034
+ function TerminalPanel({ tone, title, titleAs: Title = "h3", body, secondaryBody, icon, actions, className, titleClassName, bodyClassName, secondaryBodyClassName, iconClassName, actionsClassName, role, live }) {
156035
+ const resolvedRole = role ?? (tone === "error" ? "alert" : "status");
156036
+ const resolvedLive = live ?? (resolvedRole === "alert" ? "assertive" : "polite");
156037
+ return /* @__PURE__ */ jsxs("div", {
156038
+ className,
156039
+ "data-terminal-panel": true,
156040
+ "data-terminal-tone": tone,
156041
+ role: resolvedRole,
156042
+ "aria-live": resolvedLive === "off" ? void 0 : resolvedLive,
156043
+ children: [
156044
+ icon ? /* @__PURE__ */ jsx("div", {
156045
+ className: joinClasses(iconClassName),
156046
+ "data-terminal-icon": true,
156047
+ children: icon
156048
+ }) : null,
156049
+ /* @__PURE__ */ jsx(Title, {
156050
+ className: joinClasses(titleClassName),
156051
+ "data-terminal-title": true,
156052
+ children: title
156053
+ }),
156054
+ body ? /* @__PURE__ */ jsx("div", {
156055
+ className: joinClasses(bodyClassName),
156056
+ "data-terminal-body": true,
156057
+ children: body
156058
+ }) : null,
156059
+ actions ? /* @__PURE__ */ jsx("div", {
156060
+ className: joinClasses(actionsClassName),
156061
+ "data-terminal-actions": true,
156062
+ children: actions
156063
+ }) : null,
156064
+ secondaryBody ? /* @__PURE__ */ jsx("div", {
156065
+ className: joinClasses(secondaryBodyClassName),
156066
+ "data-terminal-secondary-body": true,
156067
+ children: secondaryBody
156068
+ }) : null
156069
+ ]
156070
+ });
156071
+ }
156072
+ var init_TerminalPanel = __esmMin((() => {}));
156073
+ //#endregion
155575
156074
  //#region ../blocks/src/system/runtime/shared/components/SelectableOptionCard.tsx
155576
156075
  function SelectableOptionCard(props) {
155577
156076
  const { baseClassName, selectedClassName, disabledClassName, iconClassName, labelClassName, detailClassName, icon, label, detail, selected, disabled, tooltip, extraClassNames = [], onClick, renderCheck, renderDisabledTooltip } = props;
@@ -155635,6 +156134,140 @@ var init_shared = __esmMin((() => {
155635
156134
  init_components();
155636
156135
  }));
155637
156136
  //#endregion
156137
+ //#region ../blocks/src/system/runtime/components/booking/SuccessMessage.tsx
156138
+ /**
156139
+ * SuccessMessage Component
156140
+ *
156141
+ * Terminal success state after a completed appointment booking.
156142
+ * Rendered on the shared registration-surface (see booking-form.client),
156143
+ * using the shared TerminalPanel + StateIcon primitives.
156144
+ */
156145
+ var SuccessMessage;
156146
+ var init_SuccessMessage = __esmMin((() => {
156147
+ init_CheckIcon$1();
156148
+ init_StateIcon();
156149
+ init_TerminalPanel();
156150
+ SuccessMessage = ({ message, resourceName, className }) => {
156151
+ return /* @__PURE__ */ jsx(TerminalPanel, {
156152
+ tone: "success",
156153
+ title: "Booking confirmed",
156154
+ icon: /* @__PURE__ */ jsx(StateIcon, {
156155
+ variant: "success",
156156
+ children: /* @__PURE__ */ jsx(CheckIcon, { strokeWidth: 3 })
156157
+ }),
156158
+ body: /* @__PURE__ */ jsx("p", {
156159
+ className: "ab-text",
156160
+ children: message
156161
+ }),
156162
+ secondaryBody: resourceName ? /* @__PURE__ */ jsxs("p", {
156163
+ className: "ab-text rb-on-surface--muted",
156164
+ children: ["Practitioner: ", resourceName]
156165
+ }) : null,
156166
+ className: ["ab-center", className ?? ""].join(" ").trim(),
156167
+ titleClassName: "ab-terminal-title",
156168
+ role: "alert",
156169
+ live: "polite"
156170
+ });
156171
+ };
156172
+ }));
156173
+ //#endregion
156174
+ //#region ../blocks/src/system/runtime/shared/mailingListSignupCopy.ts
156175
+ function getBookingMailingListNoteCopy(note, context) {
156176
+ if (note === "confirmation_required") return {
156177
+ title: MAILING_LIST_CONFIRMATION_MESSAGE,
156178
+ detail: context === "booking" ? "This is separate from your booking confirmation." : null
156179
+ };
156180
+ return {
156181
+ title: "We couldn’t confirm your mailing-list signup.",
156182
+ detail: context === "booking" ? "This does not affect your booking." : null
156183
+ };
156184
+ }
156185
+ var MAILING_LIST_CONFIRMATION_MESSAGE;
156186
+ var init_mailingListSignupCopy = __esmMin((() => {
156187
+ MAILING_LIST_CONFIRMATION_MESSAGE = "Please check your inbox to confirm your signup.";
156188
+ }));
156189
+ //#endregion
156190
+ //#region ../blocks/src/system/runtime/shared/components/BookingMailingListNote.tsx
156191
+ function BookingMailingListNote(props) {
156192
+ const copy = getBookingMailingListNoteCopy(props.note, props.context);
156193
+ return /* @__PURE__ */ jsxs("div", {
156194
+ role: "status",
156195
+ className: props.className,
156196
+ children: [/* @__PURE__ */ jsx("p", { children: copy.title }), copy.detail ? /* @__PURE__ */ jsx("p", { children: copy.detail }) : null]
156197
+ });
156198
+ }
156199
+ var init_BookingMailingListNote = __esmMin((() => {
156200
+ init_mailingListSignupCopy();
156201
+ }));
156202
+ //#endregion
156203
+ //#region ../blocks/src/system/runtime/nodes/booking-form.mailing-list-note.ts
156204
+ function storageKey(sessionId) {
156205
+ return `riverbank:booking:mailing-list:${sessionId}`;
156206
+ }
156207
+ function saveAppointmentMailingListNote(sessionId, note) {
156208
+ if (!note) return;
156209
+ try {
156210
+ window.sessionStorage.setItem(storageKey(sessionId), note);
156211
+ } catch {}
156212
+ }
156213
+ function readAppointmentMailingListNote(sessionId) {
156214
+ try {
156215
+ const stored = window.sessionStorage.getItem(storageKey(sessionId));
156216
+ return stored === "confirmation_required" || stored === "not_confirmed" ? stored : null;
156217
+ } catch {
156218
+ return null;
156219
+ }
156220
+ }
156221
+ var init_booking_form_mailing_list_note = __esmMin((() => {}));
156222
+ //#endregion
156223
+ //#region ../blocks/src/system/runtime/nodes/booking-form.completion.tsx
156224
+ function BookingFormCompletion({ resourceName, successMessage, redirectState, localNote }) {
156225
+ const note = redirectState.kind === "success" ? readAppointmentMailingListNote(redirectState.sessionId) : localNote;
156226
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(SuccessMessage, {
156227
+ message: getBookingSuccessMessage(successMessage),
156228
+ resourceName
156229
+ }), note ? /* @__PURE__ */ jsx(BookingMailingListNote, {
156230
+ note,
156231
+ context: "booking",
156232
+ className: "rb-mt-4"
156233
+ }) : null] });
156234
+ }
156235
+ var init_booking_form_completion = __esmMin((() => {
156236
+ init_SuccessMessage();
156237
+ init_BookingMailingListNote();
156238
+ init_booking_form_state();
156239
+ init_booking_form_mailing_list_note();
156240
+ }));
156241
+ //#endregion
156242
+ //#region ../blocks/src/system/runtime/nodes/booking-form.submit-handler.ts
156243
+ function appendRebookFlag(url, enabled) {
156244
+ if (!enabled) return url;
156245
+ const nextUrl = new URL(url);
156246
+ nextUrl.searchParams.set("rebook", "1");
156247
+ return nextUrl.toString();
156248
+ }
156249
+ function createBookingFormSubmitHandler(input) {
156250
+ return async () => {
156251
+ const { successUrl, cancelUrl } = buildCheckoutReturnUrls("booking", input.bookingAnchorId);
156252
+ const result = await input.booking.actions.submit({
156253
+ redirect: "manual",
156254
+ successUrl: appendRebookFlag(successUrl, input.isPortalRebook),
156255
+ cancelUrl: appendRebookFlag(cancelUrl, input.isPortalRebook)
156256
+ });
156257
+ if (!result.ok) return;
156258
+ if (result.outcome.kind === "checkout_redirect") {
156259
+ saveAppointmentMailingListNote(result.outcome.sessionId, result.outcome.mailingListSignupNote);
156260
+ window.location.href = result.outcome.checkoutUrl;
156261
+ return;
156262
+ }
156263
+ input.setLocalMailingListNote(result.outcome.mailingListSignupNote ?? null);
156264
+ };
156265
+ }
156266
+ var init_booking_form_submit_handler = __esmMin((() => {
156267
+ init_shared();
156268
+ init_booking_form_mailing_list_note();
156269
+ }));
156270
+ //#endregion
155638
156271
  //#region ../blocks/src/system/runtime/nodes/booking-form.client.tsx
155639
156272
  function getBookingRedirectLocationSnapshot() {
155640
156273
  if (typeof window === "undefined") return {
@@ -155646,12 +156279,6 @@ function getBookingRedirectLocationSnapshot() {
155646
156279
  hash: window.location.hash
155647
156280
  };
155648
156281
  }
155649
- function appendRebookFlag(url, enabled) {
155650
- if (!enabled) return url;
155651
- const nextUrl = new URL(url);
155652
- nextUrl.searchParams.set(PORTAL_REBOOK_QUERY_PARAM, PORTAL_REBOOK_QUERY_VALUE);
155653
- return nextUrl.toString();
155654
- }
155655
156282
  /**
155656
156283
  * Themed surface container for every booking view state (wizard, success,
155657
156284
  * verifying). Styled by the shared registration-surface layer.
@@ -155663,12 +156290,11 @@ function BookingSurface({ id, className, children }) {
155663
156290
  children
155664
156291
  });
155665
156292
  }
155666
- var PORTAL_REBOOK_QUERY_PARAM, PORTAL_REBOOK_QUERY_VALUE, REBOOK_COMPLETION_MODE_VERIFIED_CHECKOUT, REBOOK_COMPLETION_MODE_BYPASSED, BookingFormClient;
156293
+ var REBOOK_COMPLETION_MODE_VERIFIED_CHECKOUT, REBOOK_COMPLETION_MODE_BYPASSED, BookingFormClient;
155667
156294
  var init_booking_form_client = __esmMin((() => {
155668
156295
  init_noop();
155669
156296
  init_client();
155670
156297
  init_api$1();
155671
- init_SuccessMessage();
155672
156298
  init_useHeadlessBookingFlow();
155673
156299
  init_useAppointmentCheckoutVerification();
155674
156300
  init_booking_form_state();
@@ -155676,9 +156302,9 @@ var init_booking_form_client = __esmMin((() => {
155676
156302
  init_booking_form_interactive();
155677
156303
  init_shared();
155678
156304
  init_FeedbackMessage();
156305
+ init_booking_form_completion();
156306
+ init_booking_form_submit_handler();
155679
156307
  init_date_formatting();
155680
- PORTAL_REBOOK_QUERY_PARAM = "rebook";
155681
- PORTAL_REBOOK_QUERY_VALUE = "1";
155682
156308
  REBOOK_COMPLETION_MODE_VERIFIED_CHECKOUT = "verified_checkout";
155683
156309
  REBOOK_COMPLETION_MODE_BYPASSED = "bypassed";
155684
156310
  BookingFormClient = ({ siteId: siteIdProp, render }) => {
@@ -155692,12 +156318,16 @@ var init_booking_form_client = __esmMin((() => {
155692
156318
  const isPortalRebook = render.hydration.rebookContext?.kind === "portal_rebook";
155693
156319
  const hasLoggedRebookCompletionRef = useRef(false);
155694
156320
  const [redirectState] = useState(() => getBookingRedirectStateFromLocation(getBookingRedirectLocationSnapshot()));
156321
+ const [localMailingListNote, setLocalMailingListNote] = useState(null);
155695
156322
  const showSpamProtection = render.hydration.spamProtectionEnabled ?? isSpamProtectionEnabled();
155696
156323
  const api = useBlockApi();
155697
156324
  const hasPortalAuth = api.config.auth.type === "bearer" || api.config.authOverrides?.portal?.type === "bearer";
156325
+ const formId = render.hydration.formId ?? form?.id ?? "booking-form";
155698
156326
  const booking = useHeadlessBookingFlow({
156327
+ mailingList: render.hydration.mailingList,
156328
+ siteName: render.hydration.siteName,
155699
156329
  siteId,
155700
- formId: render.hydration.formId ?? form?.id ?? "booking-form",
156330
+ formId,
155701
156331
  form,
155702
156332
  services,
155703
156333
  serviceCategories: render.hydration.serviceCategories,
@@ -155767,22 +156397,20 @@ var init_booking_form_client = __esmMin((() => {
155767
156397
  children: render.display.message ?? "Booking form not found. Please check your configuration."
155768
156398
  })
155769
156399
  });
155770
- const handleComplete = async () => {
155771
- const { successUrl, cancelUrl } = buildCheckoutReturnUrls("booking", bookingAnchorId);
155772
- const result = await booking.actions.submit({
155773
- redirect: "manual",
155774
- successUrl: appendRebookFlag(successUrl, isPortalRebook),
155775
- cancelUrl: appendRebookFlag(cancelUrl, isPortalRebook)
155776
- });
155777
- if (!result.ok) return;
155778
- if (result.outcome.kind === "checkout_redirect") window.location.href = result.outcome.checkoutUrl;
155779
- };
156400
+ const handleComplete = createBookingFormSubmitHandler({
156401
+ booking,
156402
+ bookingAnchorId,
156403
+ isPortalRebook,
156404
+ setLocalMailingListNote
156405
+ });
155780
156406
  if (viewState.kind === "success") return /* @__PURE__ */ jsx(BookingSurface, {
155781
156407
  id: bookingAnchorId,
155782
156408
  className: render.display.className,
155783
- children: /* @__PURE__ */ jsx(SuccessMessage, {
155784
- message: getBookingSuccessMessage(render.display.successMessage),
155785
- resourceName: viewState.resourceName
156409
+ children: /* @__PURE__ */ jsx(BookingFormCompletion, {
156410
+ successMessage: render.display.successMessage,
156411
+ resourceName: viewState.resourceName,
156412
+ redirectState,
156413
+ localNote: localMailingListNote
155786
156414
  })
155787
156415
  });
155788
156416
  if (viewState.kind === "verifying") return /* @__PURE__ */ jsx(BookingSurface, {
@@ -156582,7 +157210,8 @@ function createInitialRegistrationFormData() {
156582
157210
  email: "",
156583
157211
  phone: "",
156584
157212
  notes: "",
156585
- consentAccepted: false
157213
+ consentAccepted: false,
157214
+ mailingListOptIn: false
156586
157215
  };
156587
157216
  }
156588
157217
  function validateFormData(formData, requiresConsent = false) {
@@ -157940,7 +158569,10 @@ async function handleCheckoutReturn(options, deps, returnContextRef) {
157940
158569
  }
157941
158570
  const { checkoutAttemptId } = command;
157942
158571
  const pending = deps.getPendingRegistration(siteId, checkoutAttemptId);
157943
- returnContextRef.current = { checkoutAttemptId };
158572
+ returnContextRef.current = {
158573
+ checkoutAttemptId,
158574
+ mailingListSignupNote: pending?.mailingListSignupNote
158575
+ };
157944
158576
  if (pending) restorePendingPresentation(options, pending);
157945
158577
  options.setStep("verifying-payment");
157946
158578
  try {
@@ -157961,7 +158593,10 @@ function completeVerifiedRegistration(options, deps, returnContext) {
157961
158593
  const siteId = options.api.config.siteId;
157962
158594
  const checkoutAttemptId = returnContext?.checkoutAttemptId;
157963
158595
  if (siteId && checkoutAttemptId) deps.clearPendingRegistration(siteId, checkoutAttemptId);
157964
- options.setRegistrationResult({ status: "confirmed" });
158596
+ options.setRegistrationResult({
158597
+ status: "confirmed",
158598
+ mailingListSignupNote: returnContext?.mailingListSignupNote
158599
+ });
157965
158600
  options.setStep("success");
157966
158601
  }
157967
158602
  function useEventRegistrationStripeReturnWithDeps(options, deps) {
@@ -158068,6 +158703,9 @@ var init_registrationErrorPresentation = __esmMin((() => {
158068
158703
  }));
158069
158704
  //#endregion
158070
158705
  //#region ../blocks/src/system/runtime/nodes/event-registration/useEventRegistrationSubmit.ts
158706
+ function wantsMailingListSignup(options) {
158707
+ return options.mailingListSignup !== null && options.formData.mailingListOptIn === true;
158708
+ }
158071
158709
  function createClientCommandId(cryptoSource = {
158072
158710
  randomUUID: globalThis.crypto.randomUUID?.bind(globalThis.crypto),
158073
158711
  getRandomValues: (bytes) => globalThis.crypto.getRandomValues(bytes)
@@ -158161,7 +158799,8 @@ async function completeRegistrationSubmission(options, deps, prepared, result, s
158161
158799
  case "paymentStatusRequired":
158162
158800
  options.setPaymentStatusRecovery({
158163
158801
  kind: "ready",
158164
- subject: result.subject
158802
+ subject: result.subject,
158803
+ mailingListSignupNote: result.mailingListSignupNote
158165
158804
  });
158166
158805
  options.setStep("payment-status");
158167
158806
  return {
@@ -158170,14 +158809,15 @@ async function completeRegistrationSubmission(options, deps, prepared, result, s
158170
158809
  };
158171
158810
  case "checkoutRequired":
158172
158811
  options.setPendingRegistrationReference(result.reference);
158173
- savePendingCheckout(options, deps, prepared, result.submissionId, result.reference);
158812
+ savePendingCheckout(options, deps, prepared, result.submissionId, result.reference, result.mailingListSignupNote);
158174
158813
  options.setStep("redirecting");
158175
158814
  return redirectToCheckout(result.checkoutUrl, submitOptions);
158176
158815
  case "waitlisted":
158177
158816
  options.setRegistrationResult({
158178
158817
  status: "waitlist",
158179
158818
  title: "Added to waitlist",
158180
- message: result.waitlist.message
158819
+ message: result.waitlist.message,
158820
+ mailingListSignupNote: result.mailingListSignupNote
158181
158821
  });
158182
158822
  break;
158183
158823
  case "bookingComplete":
@@ -158185,7 +158825,8 @@ async function completeRegistrationSubmission(options, deps, prepared, result, s
158185
158825
  options.setPendingRegistrationReference(result.reference);
158186
158826
  options.setRegistrationResult({
158187
158827
  status: "confirmed",
158188
- message: result.summary.paymentMethod === "pass" ? result.summary.message : void 0
158828
+ message: result.summary.paymentMethod === "pass" ? result.summary.message : void 0,
158829
+ mailingListSignupNote: result.mailingListSignupNote
158189
158830
  });
158190
158831
  break;
158191
158832
  }
@@ -158244,7 +158885,7 @@ function resolveSelectionSnapshot(method, passId, membershipId, bundleProductId,
158244
158885
  if (method === "free") return { method };
158245
158886
  throw new Error("Choose an available payment option.");
158246
158887
  }
158247
- function savePendingCheckout(options, deps, prepared, checkoutAttemptId, reference) {
158888
+ function savePendingCheckout(options, deps, prepared, checkoutAttemptId, reference, mailingListSignupNote) {
158248
158889
  const siteId = options.api.config.siteId;
158249
158890
  if (!siteId) return;
158250
158891
  deps.savePendingRegistration(siteId, checkoutAttemptId, {
@@ -158253,7 +158894,8 @@ function savePendingCheckout(options, deps, prepared, checkoutAttemptId, referen
158253
158894
  ticketSelections: prepared.ticketSelections,
158254
158895
  selectedEventId: options.registrationTarget?.selectedEventId ?? null,
158255
158896
  selectedAttendanceMode: options.selectedAttendanceMode,
158256
- paymentSelection: prepared.selectionSnapshot
158897
+ paymentSelection: prepared.selectionSnapshot,
158898
+ mailingListSignupNote
158257
158899
  });
158258
158900
  }
158259
158901
  function redirectToCheckout(checkoutUrl, submitOptions) {
@@ -158267,7 +158909,7 @@ function redirectToCheckout(checkoutUrl, submitOptions) {
158267
158909
  };
158268
158910
  }
158269
158911
  function registrationRequestIntentKey(request) {
158270
- const { registrationCommandId: _command, altchaSolution: _proof, checkout, ...intent } = request;
158912
+ const { registrationCommandId: _command, altchaSolution: _proof, mailingListOptIn: _marketingConsent, checkout, ...intent } = request;
158271
158913
  return JSON.stringify({
158272
158914
  ...intent,
158273
158915
  checkout: checkout ? {
@@ -158292,6 +158934,7 @@ function buildRegistrationRequest(options, prepared, method, passId, membershipI
158292
158934
  phone: options.formData.phone.trim() || void 0,
158293
158935
  notes: options.formData.notes.trim() || void 0,
158294
158936
  consentAccepted: options.formData.consentAccepted,
158937
+ mailingListOptIn: wantsMailingListSignup(options),
158295
158938
  altchaSolution: options.altchaSolution,
158296
158939
  paymentMethod: method,
158297
158940
  customerPassId: method === "pass" ? passId : void 0,
@@ -158552,13 +159195,17 @@ function isCheckableRecovery(state) {
158552
159195
  function assistanceRequired(recovery) {
158553
159196
  return {
158554
159197
  kind: "assistanceRequired",
158555
- subject: recovery.subject
159198
+ subject: recovery.subject,
159199
+ mailingListSignupNote: recovery.mailingListSignupNote
158556
159200
  };
158557
159201
  }
158558
159202
  function applyStatusOutcome(outcome, recovery, setters, setRecovery) {
158559
159203
  if (outcome.kind === "resolved") {
158560
159204
  setters.setPendingRegistrationReference(outcome.reference);
158561
- setters.setRegistrationResult({ status: "confirmed" });
159205
+ setters.setRegistrationResult({
159206
+ status: "confirmed",
159207
+ mailingListSignupNote: recovery.mailingListSignupNote
159208
+ });
158562
159209
  setRecovery(null);
158563
159210
  setters.setStep("success");
158564
159211
  return;
@@ -158679,6 +159326,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
158679
159326
  const paymentSelection = flowState.paymentSelection;
158680
159327
  const [selectedEvent, setSelectedEvent] = useState(preSelectedEvent ?? null);
158681
159328
  const [formData, setFormData] = useState(createInitialRegistrationFormData);
159329
+ const mailingListSignup = resolveBookingSignupOffer(options.mailingList, options.siteName);
158682
159330
  const [errors, setErrors] = useState({});
158683
159331
  const [guests, setGuests] = useState([]);
158684
159332
  const [guestErrors, setGuestErrors] = useState({});
@@ -159125,6 +159773,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
159125
159773
  ticketSelections,
159126
159774
  selectedSlidingAmount,
159127
159775
  formData,
159776
+ mailingListSignup,
159128
159777
  altchaSolution,
159129
159778
  requireGuestDetails,
159130
159779
  guests,
@@ -159221,6 +159870,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
159221
159870
  hasValidTicketSelection,
159222
159871
  eventRequiresPayment,
159223
159872
  formData,
159873
+ mailingListSignup,
159224
159874
  setFormData,
159225
159875
  errors,
159226
159876
  guests,
@@ -160724,6 +161374,24 @@ function NotesField({ id, onChange, value }) {
160724
161374
  })]
160725
161375
  });
160726
161376
  }
161377
+ function MailingListOptInField({ signup, formData, onChange }) {
161378
+ if (!signup) return null;
161379
+ return /* @__PURE__ */ jsxs("div", {
161380
+ className: "er-field",
161381
+ children: [/* @__PURE__ */ jsx(CheckboxChoice, {
161382
+ checked: formData.mailingListOptIn === true,
161383
+ onChange: (event) => onChange({
161384
+ ...formData,
161385
+ mailingListOptIn: event.target.checked
161386
+ }),
161387
+ label: `Email me news and updates from ${signup.siteName}.`,
161388
+ presentation: "row"
161389
+ }), /* @__PURE__ */ jsx("p", {
161390
+ className: "er-text er-text--muted",
161391
+ children: "Optional. You can unsubscribe at any time."
161392
+ })]
161393
+ });
161394
+ }
160727
161395
  var AttendeeDetailsStep;
160728
161396
  var init_AttendeeDetailsStep = __esmMin((() => {
160729
161397
  init_GuestDetailsSection();
@@ -160731,7 +161399,7 @@ var init_AttendeeDetailsStep = __esmMin((() => {
160731
161399
  init_FieldValidationMessage();
160732
161400
  init_BookingConsentAgreement();
160733
161401
  init_CheckboxChoice();
160734
- AttendeeDetailsStep = ({ formData, onChange, errors, emailLocked = false, onLogout, ticketsCount = 1, requireGuestDetails = false, guests = [], onGuestsChange, guestErrors = {}, guestSectionShake = false, onGuestShakeEnd, consent }) => {
161402
+ AttendeeDetailsStep = ({ formData, onChange, errors, emailLocked = false, onLogout, ticketsCount = 1, requireGuestDetails = false, guests = [], onGuestsChange, guestErrors = {}, guestSectionShake = false, onGuestShakeEnd, consent, mailingListSignup }) => {
160735
161403
  const idBase = useId();
160736
161404
  const nameId = `${idBase}-name`;
160737
161405
  const emailId = `${idBase}-email`;
@@ -160840,6 +161508,11 @@ var init_AttendeeDetailsStep = __esmMin((() => {
160840
161508
  placeholder: "(optional)"
160841
161509
  })]
160842
161510
  }),
161511
+ /* @__PURE__ */ jsx(MailingListOptInField, {
161512
+ signup: mailingListSignup,
161513
+ formData,
161514
+ onChange
161515
+ }),
160843
161516
  /* @__PURE__ */ jsx(NotesField, {
160844
161517
  id: notesId,
160845
161518
  value: formData.notes,
@@ -161288,7 +161961,8 @@ var init_PaymentSelectionStep = __esmMin((() => {
161288
161961
  var SuccessStep;
161289
161962
  var init_SuccessStep = __esmMin((() => {
161290
161963
  init_shared();
161291
- SuccessStep = ({ title, message, variant = "success" }) => {
161964
+ init_BookingMailingListNote();
161965
+ SuccessStep = ({ title, message, variant = "success", mailingListSignupNote, context = "booking" }) => {
161292
161966
  return /* @__PURE__ */ jsx(TerminalPanel, {
161293
161967
  tone: variant === "info" ? "info" : "success",
161294
161968
  className: "er-center",
@@ -161329,7 +162003,11 @@ var init_SuccessStep = __esmMin((() => {
161329
162003
  })
161330
162004
  }),
161331
162005
  title: title ?? (variant === "info" ? "Already Registered" : "Registration Confirmed!"),
161332
- body: message
162006
+ body: message,
162007
+ secondaryBody: mailingListSignupNote ? /* @__PURE__ */ jsx(BookingMailingListNote, {
162008
+ note: mailingListSignupNote,
162009
+ context
162010
+ }) : void 0
161333
162011
  });
161334
162012
  };
161335
162013
  }));
@@ -161533,7 +162211,8 @@ function AttendeeDetailsContent(props) {
161533
162211
  guestErrors: wizard.guestErrors,
161534
162212
  guestSectionShake: wizard.guestSectionShake,
161535
162213
  onGuestShakeEnd: wizard.handleGuestShakeEnd,
161536
- consent: (wizard.selectedEvent ?? wizard.preSelectedEvent)?.consent ?? null
162214
+ consent: (wizard.selectedEvent ?? wizard.preSelectedEvent)?.consent ?? null,
162215
+ mailingListSignup: wizard.mailingListSignup
161537
162216
  }),
161538
162217
  props.showSpamProtection && /* @__PURE__ */ jsx("div", {
161539
162218
  className: "er-altcha",
@@ -161714,6 +162393,10 @@ function PaymentStatusStep(props) {
161714
162393
  "aria-atomic": "true",
161715
162394
  children: props.state.kind === "checking" ? "Checking payment…" : view.title
161716
162395
  })] }),
162396
+ secondaryBody: props.state.mailingListSignupNote ? /* @__PURE__ */ jsx(BookingMailingListNote, {
162397
+ note: props.state.mailingListSignupNote,
162398
+ context: "booking"
162399
+ }) : void 0,
161717
162400
  actionsClassName: "er-button-group",
161718
162401
  actions: view.action ? /* @__PURE__ */ jsx("button", {
161719
162402
  type: "button",
@@ -161726,6 +162409,7 @@ function PaymentStatusStep(props) {
161726
162409
  }
161727
162410
  var init_PaymentStatusStep = __esmMin((() => {
161728
162411
  init_shared();
162412
+ init_BookingMailingListNote();
161729
162413
  }));
161730
162414
  //#endregion
161731
162415
  //#region ../blocks/src/system/runtime/nodes/event-registration/EventRegistrationSurface.tsx
@@ -161819,11 +162503,10 @@ function EventRegistrationTerminalState(props) {
161819
162503
  onReturnToPayment: wizard.handleReturnToPayment,
161820
162504
  onReturnToBooking: wizard.handleReturnToBooking
161821
162505
  }) : null;
161822
- case "success": return wizard.registrationResult ? /* @__PURE__ */ jsx(SuccessStep, {
161823
- title: wizard.registrationResult.title,
161824
- variant: wizard.registrationResult.variant,
161825
- message: wizard.registrationResult.message ?? props.successMessage
161826
- }) : null;
162506
+ case "success": return /* @__PURE__ */ jsx(EventRegistrationSuccess, {
162507
+ wizard,
162508
+ fallbackMessage: props.successMessage
162509
+ });
161827
162510
  case "error": return /* @__PURE__ */ jsx(ErrorStep, {
161828
162511
  message: wizard.errorMessage,
161829
162512
  action: wizard.errorAction,
@@ -161836,6 +162519,17 @@ function EventRegistrationTerminalState(props) {
161836
162519
  case "select-payment": return null;
161837
162520
  }
161838
162521
  }
162522
+ function EventRegistrationSuccess(props) {
162523
+ const result = props.wizard.registrationResult;
162524
+ if (!result) return null;
162525
+ return /* @__PURE__ */ jsx(SuccessStep, {
162526
+ title: result.title,
162527
+ variant: result.variant,
162528
+ message: result.message ?? props.fallbackMessage,
162529
+ mailingListSignupNote: result.mailingListSignupNote,
162530
+ context: result.status === "waitlist" ? "waitlist" : "booking"
162531
+ });
162532
+ }
161839
162533
  function EventRegistrationSurface(props) {
161840
162534
  const { wizard } = props;
161841
162535
  const mainRef = useRef(null);
@@ -162038,19 +162732,23 @@ function getWizardStepLabel(input) {
162038
162732
  case "payment-failed": return "";
162039
162733
  }
162040
162734
  }
162735
+ function useConfiguredEventRegistrationWizard(props) {
162736
+ return useEventRegistrationWizard({
162737
+ anchorId: EVENT_REGISTRATION_ANCHOR_ID,
162738
+ occurrenceContext: props.occurrenceContext ?? null,
162739
+ subject: props.subject ?? null,
162740
+ events: props.events ?? [],
162741
+ maxTicketsNum: normalizeEventRegistrationMaxTickets(props.maxTickets ?? "5"),
162742
+ mailingList: props.mailingList,
162743
+ siteName: props.siteName
162744
+ });
162745
+ }
162041
162746
  function EventRegistrationWizard(props) {
162042
- const { occurrenceContext, subject, events, maxTickets = "5", showVenue = true, showCapacity = true, successMessage = "Thank you for registering! Check your email for confirmation details.", buttonText = "Complete Registration", buttonVariant = "primary", className, spamProtectionEnabled, supportEmail } = props;
162043
- const maxTicketsNum = normalizeEventRegistrationMaxTickets(maxTickets);
162747
+ const { occurrenceContext, subject, events, showVenue = true, showCapacity = true, successMessage = "Thank you for registering! Check your email for confirmation details.", buttonText = "Complete Registration", buttonVariant = "primary", className, spamProtectionEnabled, supportEmail } = props;
162044
162748
  const showSpamProtection = spamProtectionEnabled ?? isSpamProtectionEnabled();
162045
162749
  const registrationRootClassName = `event-registration ${className || ""}`;
162046
162750
  const registrationRootRef = React.useRef(null);
162047
- const wizard = useEventRegistrationWizard({
162048
- anchorId: EVENT_REGISTRATION_ANCHOR_ID,
162049
- occurrenceContext: occurrenceContext ?? null,
162050
- subject: subject ?? null,
162051
- events: events ?? [],
162052
- maxTicketsNum
162053
- });
162751
+ const wizard = useConfiguredEventRegistrationWizard(props);
162054
162752
  useEventCheckoutHandoffRestore(wizard.step === "redirecting");
162055
162753
  const [bookingOverlayOpen, setBookingOverlayOpen] = useState(false);
162056
162754
  const [floatingPortalRoot, setFloatingPortalRoot] = useState(null);
@@ -166946,7 +167644,7 @@ function NewsletterFormClient({ render }) {
166946
167644
  tone: "success",
166947
167645
  className: "fb-success",
166948
167646
  role: "status",
166949
- children: getNewsletterSuccessOutcome(submissionState) === "confirmation_required" ? "Please check your inbox to confirm your signup." : render.display.successMessage
167647
+ children: getNewsletterSuccessOutcome(submissionState) === "confirmation_required" ? MAILING_LIST_CONFIRMATION_MESSAGE : render.display.successMessage
166950
167648
  })
166951
167649
  });
166952
167650
  if (render.display.availability === "unavailable") return /* @__PURE__ */ jsx(UnavailableNewsletterForm, { className: render.display.className });
@@ -167102,6 +167800,7 @@ var init_newsletter_form_client = __esmMin((() => {
167102
167800
  init_api$1();
167103
167801
  init_src$2();
167104
167802
  init_FeedbackMessage();
167803
+ init_mailingListSignupCopy();
167105
167804
  init_newsletter_form_parts();
167106
167805
  init_newsletter_form_client_state();
167107
167806
  init_newsletter_form_submission();
@@ -167557,7 +168256,7 @@ function resolveSdkBookingTimeZone(timeZone) {
167557
168256
  }
167558
168257
  function buildPageRouteRenderContext(dataContext) {
167559
168258
  return {
167560
- pathname: dataContext.pathname,
168259
+ ...buildPageIdentityRenderContext(dataContext),
167561
168260
  occurrenceContext: dataContext.occurrenceContext ?? null,
167562
168261
  entrySubrouteContext: dataContext.entrySubrouteContext ?? null,
167563
168262
  contentEntry: dataContext.contentEntry ?? null,
@@ -167567,6 +168266,12 @@ function buildPageRouteRenderContext(dataContext) {
167567
168266
  previewStage: dataContext.previewStage
167568
168267
  };
167569
168268
  }
168269
+ function buildPageIdentityRenderContext(dataContext) {
168270
+ return {
168271
+ siteName: dataContext.siteName,
168272
+ pathname: dataContext.pathname
168273
+ };
168274
+ }
167570
168275
  function PageContent(props) {
167571
168276
  const { page, runtimeJoins, siteId, resolvedData, bookingOfferingPresets, mailingList, bookingTimeZone, routeMap, pagesByIdentifier, entriesByIdentifier, wrapBlock, registry, blockOverrides, sdkConfig, customBlocks, supabaseUrl, mediaAssets, apiBaseUrl, portalToken, previewToken, readAuthority, dataContext } = props;
167572
168277
  const rendererCommonProps = {
@@ -167782,7 +168487,7 @@ var SimpleCache = class {
167782
168487
  * 1. This constant
167783
168488
  * 2. The "version" field in package.json
167784
168489
  */
167785
- const SDK_VERSION = "0.146.0";
168490
+ const SDK_VERSION = "0.147.0";
167786
168491
  //#endregion
167787
168492
  //#region src/client/error.ts
167788
168493
  let _Symbol$for;