@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
@@ -1631,9 +1631,6 @@ var init_participants = __esmMin((() => {
1631
1631
  init_result$1();
1632
1632
  init_string();
1633
1633
  }));
1634
- var init_participant_identity = __esmMin((() => {
1635
- init_assertNever$1();
1636
- }));
1637
1634
  var init_public_url_validation = __esmMin((() => {}));
1638
1635
  var init_public_profile = __esmMin((() => {
1639
1636
  init_public_url_validation();
@@ -2072,17 +2069,39 @@ function parseMailingListRuntimeContext(value) {
2072
2069
  if (!isRecord$37(value)) return invalidRuntimeContext();
2073
2070
  if (value.tag === "not_configured") return ok$3({ tag: "not_configured" });
2074
2071
  if (value.tag !== "configured") return invalidRuntimeContext();
2072
+ return parseConfiguredRuntimeContext(value);
2073
+ }
2074
+ function parseConfiguredRuntimeContext(value) {
2075
2075
  const revision = parseMailingListSetupRevision(value.revision);
2076
2076
  const form = parseMailingListGlobalForm(value.form);
2077
2077
  const provider = parseRuntimeProvider(value.provider);
2078
- if (revision === null || !form.ok || provider === null) return invalidRuntimeContext();
2078
+ const bookingSignup = parseBookingSignupOffer(value.bookingSignup);
2079
+ if (revision === null || !form.ok || provider === null || bookingSignup === null) return invalidRuntimeContext();
2079
2080
  return ok$3({
2080
2081
  tag: "configured",
2081
2082
  revision,
2083
+ bookingSignup,
2082
2084
  form: form.value,
2083
2085
  provider
2084
2086
  });
2085
2087
  }
2088
+ function resolveBookingSignupOffer(context, siteName) {
2089
+ const name = siteName?.trim() ?? "";
2090
+ return context?.tag === "configured" && context.bookingSignup.tag === "offered" ? { siteName: name.length > 0 ? name : "this site" } : null;
2091
+ }
2092
+ function parseBookingSignupOffer(value) {
2093
+ if (value === void 0) return {
2094
+ tag: "unavailable",
2095
+ reason: "disabled"
2096
+ };
2097
+ if (!isRecord$37(value)) return null;
2098
+ if (value.tag === "offered") return { tag: "offered" };
2099
+ if (value.tag === "unavailable" && (value.reason === "disabled" || value.reason === "fields" || value.reason === "destination")) return {
2100
+ tag: "unavailable",
2101
+ reason: value.reason
2102
+ };
2103
+ return null;
2104
+ }
2086
2105
  function parseRuntimeProvider(value) {
2087
2106
  if (!isRecord$37(value)) return null;
2088
2107
  switch (value.provider) {
@@ -2180,6 +2199,7 @@ var init_mailing_list_runtime = __esmMin((() => {
2180
2199
  init_mailing_list_identifiers();
2181
2200
  init_mailing_list_setup_parser();
2182
2201
  init_result$1();
2202
+ init_mailing_list_setup();
2183
2203
  }));
2184
2204
  //#endregion
2185
2205
  //#region ../core/src/mailing-list-submission.ts
@@ -2732,6 +2752,15 @@ var init_booking_verticals = __esmMin((() => {
2732
2752
  var init_navigation_locations = __esmMin((() => {
2733
2753
  init_result$1();
2734
2754
  }));
2755
+ //#endregion
2756
+ //#region ../core/src/navigation-portal-labels.ts
2757
+ var PORTAL_NAV_DEFAULT_LABELS;
2758
+ var init_navigation_portal_labels = __esmMin((() => {
2759
+ PORTAL_NAV_DEFAULT_LABELS = {
2760
+ loggedOut: "Login",
2761
+ loggedIn: "My Account"
2762
+ };
2763
+ }));
2735
2764
  var init_event_preset_vocabulary = __esmMin((() => {}));
2736
2765
  var init_event_catalogue = __esmMin((() => {
2737
2766
  init_booking_verticals();
@@ -2777,7 +2806,6 @@ var init_src$2 = __esmMin((() => {
2777
2806
  init_sensitive_collection();
2778
2807
  init_assertNever$1();
2779
2808
  init_participants();
2780
- init_participant_identity();
2781
2809
  init_public_url_validation();
2782
2810
  init_public_profile();
2783
2811
  init_public_experience();
@@ -2818,6 +2846,7 @@ var init_src$2 = __esmMin((() => {
2818
2846
  init_booking_verticals();
2819
2847
  init_event_series_behaviour();
2820
2848
  init_navigation_locations();
2849
+ init_navigation_portal_labels();
2821
2850
  init_event_preset_vocabulary();
2822
2851
  init_event_catalogue();
2823
2852
  }));
@@ -4954,17 +4983,6 @@ var init_expandPalette = __esmMin((() => {
4954
4983
  ]);
4955
4984
  }));
4956
4985
  //#endregion
4957
- //#region ../theme-core/src/surfaces/foregroundRoles.ts
4958
- var SURFACE_FOREGROUND_ROLES;
4959
- var init_foregroundRoles = __esmMin((() => {
4960
- SURFACE_FOREGROUND_ROLES = [
4961
- "text",
4962
- "heading",
4963
- "link",
4964
- "supporting"
4965
- ];
4966
- }));
4967
- //#endregion
4968
4986
  //#region ../theme-core/src/surfaces/foregroundContract.ts
4969
4987
  function requireSurfaceColorValue(role, value) {
4970
4988
  const normalized = value.trim();
@@ -4973,10 +4991,12 @@ function requireSurfaceColorValue(role, value) {
4973
4991
  }
4974
4992
  function completeSurfaceForegrounds(input) {
4975
4993
  const text = requireSurfaceColorValue("text", input.text);
4994
+ const link = input.link === void 0 ? text : requireSurfaceColorValue("link", input.link);
4976
4995
  return {
4977
4996
  text,
4978
4997
  heading: input.heading === void 0 ? text : requireSurfaceColorValue("heading", input.heading),
4979
- link: input.link === void 0 ? text : requireSurfaceColorValue("link", input.link),
4998
+ link,
4999
+ linkHover: input.linkHover === void 0 ? link : requireSurfaceColorValue("linkHover", input.linkHover),
4980
5000
  supporting: input.supporting === void 0 ? text : requireSurfaceColorValue("supporting", input.supporting)
4981
5001
  };
4982
5002
  }
@@ -4984,6 +5004,7 @@ function surfaceForegroundValue(role, outsideProviderFallback = DEFAULT_ROLE_FAL
4984
5004
  const roleVariable = SURFACE_FOREGROUND_CSS_VARS[role];
4985
5005
  const fallback = requireSurfaceColorValue("fallback", outsideProviderFallback);
4986
5006
  if (role === "text") return `var(${roleVariable}, ${fallback})`;
5007
+ if (role === "linkHover") return `var(${roleVariable}, ${surfaceForegroundValue("link", fallback)})`;
4987
5008
  return `var(${roleVariable}, var(${SURFACE_FOREGROUND_CSS_VARS.text}, ${fallback}))`;
4988
5009
  }
4989
5010
  function surfaceForegroundValueWithOpacity(role, opacityPercent) {
@@ -4997,20 +5018,35 @@ function surfaceForegroundStyle(input) {
4997
5018
  [SURFACE_FOREGROUND_CSS_VARS.text]: foregrounds.text,
4998
5019
  [SURFACE_FOREGROUND_CSS_VARS.heading]: foregrounds.heading,
4999
5020
  [SURFACE_FOREGROUND_CSS_VARS.link]: foregrounds.link,
5000
- [SURFACE_FOREGROUND_CSS_VARS.supporting]: foregrounds.supporting
5021
+ [SURFACE_FOREGROUND_CSS_VARS.linkHover]: foregrounds.linkHover,
5022
+ [SURFACE_FOREGROUND_CSS_VARS.supporting]: foregrounds.supporting,
5023
+ "--rb-surface-link-hover-decoration": hoverDecoration(input)
5001
5024
  };
5002
5025
  }
5003
5026
  function surfaceForegroundDeclarations(input) {
5004
- const foregrounds = completeSurfaceForegrounds(input);
5005
- return [`color: ${foregrounds.text}`, ...SURFACE_FOREGROUND_ROLES.map((role) => `${SURFACE_FOREGROUND_CSS_VARS[role]}: ${foregrounds[role]}`)];
5027
+ return Object.entries(surfaceForegroundStyle(input)).map(([property, value]) => `${property}: ${value};`);
5028
+ }
5029
+ function surfaceForegroundInputFromResolved(foreground, color) {
5030
+ const { roles } = foreground;
5031
+ return {
5032
+ text: color(roles.text),
5033
+ heading: color(roles.heading),
5034
+ link: color(roles.link),
5035
+ linkHover: color(roles.linkHover),
5036
+ supporting: color(roles.supporting),
5037
+ hoverDecoration: foreground.hoverDecoration
5038
+ };
5039
+ }
5040
+ function hoverDecoration(input) {
5041
+ return input.hoverDecoration ?? "underline";
5006
5042
  }
5007
5043
  var SURFACE_FOREGROUND_CSS_VARS, DEFAULT_SURFACE_TEXT_COLOR, DEFAULT_SURFACE_LINK_COLOR, DEFAULT_SURFACE_SUPPORTING_COLOR, DEFAULT_ROLE_FALLBACKS;
5008
5044
  var init_foregroundContract = __esmMin((() => {
5009
- init_foregroundRoles();
5010
5045
  SURFACE_FOREGROUND_CSS_VARS = {
5011
5046
  text: "--rb-surface-text-color",
5012
5047
  heading: "--rb-surface-heading-color",
5013
5048
  link: "--rb-surface-link-color",
5049
+ linkHover: "--rb-surface-link-hover-color",
5014
5050
  supporting: "--rb-surface-supporting-color"
5015
5051
  };
5016
5052
  DEFAULT_SURFACE_TEXT_COLOR = "rgb(var(--tb-text, 17 24 39))";
@@ -5020,6 +5056,7 @@ var init_foregroundContract = __esmMin((() => {
5020
5056
  text: DEFAULT_SURFACE_TEXT_COLOR,
5021
5057
  heading: DEFAULT_SURFACE_TEXT_COLOR,
5022
5058
  link: DEFAULT_SURFACE_LINK_COLOR,
5059
+ linkHover: DEFAULT_SURFACE_LINK_COLOR,
5023
5060
  supporting: DEFAULT_SURFACE_SUPPORTING_COLOR
5024
5061
  };
5025
5062
  }));
@@ -6073,12 +6110,6 @@ var init_tokens = __esmMin((() => {
6073
6110
  init_colorTokenParts();
6074
6111
  init_resolver$1();
6075
6112
  }));
6076
- var init_foregroundInteraction = __esmMin((() => {
6077
- init_contrast$1();
6078
- init_colorConversion();
6079
- init_colorTokenParts();
6080
- init_tokens();
6081
- }));
6082
6113
  //#endregion
6083
6114
  //#region ../theme-core/src/palette/utils/opaqueSurfaceColor.ts
6084
6115
  /** Resolve an opaque colour, compositing alpha against an explicit underlay. */
@@ -6091,10 +6122,10 @@ function resolveOpaqueSurfaceHex(reference, palette, underlayReference) {
6091
6122
  const parts = parseColorTokenParts(reference);
6092
6123
  if (parts.kind === "token" && parts.opacityPercent !== null) {
6093
6124
  const foregroundHex = normalizePaletteHex(palette[parts.token] ?? "");
6094
- return foregroundHex ? compositeHex(foregroundHex, underlayHex, parts.opacityPercent / 100) : null;
6125
+ return foregroundHex ? compositeHex$1(foregroundHex, underlayHex, parts.opacityPercent / 100) : null;
6095
6126
  }
6096
6127
  const rgba = parseRgba(parts.kind === "raw" ? parts.value : reference);
6097
- return rgba ? compositeHex(rgbToHex$1(rgba.r, rgba.g, rgba.b), underlayHex, rgba.alpha) : null;
6128
+ return rgba ? compositeHex$1(rgbToHex$1(rgba.r, rgba.g, rgba.b), underlayHex, rgba.alpha) : null;
6098
6129
  }
6099
6130
  /** Resolve a colour reference only when it is already fully opaque. */
6100
6131
  function resolveConcreteColorHex(reference, palette) {
@@ -6110,7 +6141,7 @@ function resolveConcreteColorHex(reference, palette) {
6110
6141
  if (literal.toLowerCase() === "white") return "#ffffff";
6111
6142
  return normalizePaletteHex(literal);
6112
6143
  }
6113
- function compositeHex(foregroundHex, underlayHex, alpha) {
6144
+ function compositeHex$1(foregroundHex, underlayHex, alpha) {
6114
6145
  const foreground = hexToRgb$1(foregroundHex);
6115
6146
  const underlay = hexToRgb$1(underlayHex);
6116
6147
  const channel = (foregroundValue, underlayValue) => Math.round(foregroundValue * alpha + underlayValue * (1 - alpha));
@@ -6147,6 +6178,74 @@ var init_opaqueSurfaceColor = __esmMin((() => {
6147
6178
  init_colorConversion();
6148
6179
  }));
6149
6180
  //#endregion
6181
+ //#region ../theme-core/src/surfaces/foregroundInteraction.ts
6182
+ /**
6183
+ * Derive the hover foreground that belongs with a resolved resting foreground.
6184
+ *
6185
+ * A resting foreground is chosen to be legible against a known surface. A hover
6186
+ * state derived from it stays within a bounded distance of that colour, so it
6187
+ * inherits most of the resting colour's contrast margin instead of asserting
6188
+ * an unrelated brand colour that no one checked against the surface.
6189
+ *
6190
+ * That bounded-distance property is what lets this be used on a transparent
6191
+ * overlay header, where the backdrop is only partly knowable: the scrolled
6192
+ * state composites a 60% glass tint over arbitrary page content, so no
6193
+ * compile-time contrast proof is available there. Staying near a colour that
6194
+ * is already trusted in both states is a weaker claim than a contrast proof,
6195
+ * and it is one this function can actually keep.
6196
+ *
6197
+ * Returns `null` when the resting token is not a plain palette token — an
6198
+ * already-faded or raw value has no well-defined softening, and the caller
6199
+ * should leave hover alone rather than guess.
6200
+ */
6201
+ function deriveForegroundHoverToken(restingToken) {
6202
+ const parts = parseColorTokenParts(restingToken);
6203
+ if (parts.kind !== "token") return null;
6204
+ if (parts.opacityPercent !== null) return null;
6205
+ return parseThemeColorToken(`${parts.token}/85`);
6206
+ }
6207
+ /**
6208
+ * Prefer an authored hover that survives every measured backdrop, then a
6209
+ * checked softening of the resting colour. A null backdrop set represents a
6210
+ * trusted treatment: only an explicit authored hover may change the colour.
6211
+ * When neither option works, retain the resting colour and underline it.
6212
+ */
6213
+ function planForegroundHover(input) {
6214
+ const { restingToken, candidate, palette, backdrops } = input;
6215
+ if (candidate && candidate !== restingToken) {
6216
+ if (backdrops === null || survivesEveryBackdrop(candidate, palette, backdrops)) return {
6217
+ kind: "candidate",
6218
+ token: candidate,
6219
+ decoration: "initial"
6220
+ };
6221
+ }
6222
+ const softened = deriveForegroundHoverToken(restingToken);
6223
+ if (softened && backdrops && survivesEveryBackdrop(softened, palette, backdrops)) return {
6224
+ kind: "softened",
6225
+ token: softened,
6226
+ decoration: "initial"
6227
+ };
6228
+ return {
6229
+ kind: "resting",
6230
+ token: restingToken,
6231
+ decoration: "underline"
6232
+ };
6233
+ }
6234
+ function survivesEveryBackdrop(token, palette, backdrops) {
6235
+ return backdrops.length > 0 && backdrops.every((backdrop) => {
6236
+ const foreground = resolveOpaqueSurfaceHex(token, palette, backdrop);
6237
+ return foreground !== null && contrastRatio(foreground, backdrop) >= 4.5;
6238
+ });
6239
+ }
6240
+ var init_foregroundInteraction = __esmMin((() => {
6241
+ init_contrast$1();
6242
+ init_colorConversion();
6243
+ init_colorTokenParts();
6244
+ init_tokens();
6245
+ init_opaqueSurfaceColor();
6246
+ }));
6247
+ var init_foregroundRoles = __esmMin((() => {}));
6248
+ //#endregion
6150
6249
  //#region ../theme-core/src/surfaces/resolveSurfaceForeground.ts
6151
6250
  /**
6152
6251
  * Resolve the complete foreground contract for an effective page/section or
@@ -6172,12 +6271,16 @@ function resolveSurfaceForeground(background, palette, candidates = {}, options
6172
6271
  }
6173
6272
  function foregroundCandidates(background, overrides) {
6174
6273
  return {
6175
- text: overrides.text ?? background?.textColor ?? null,
6176
- heading: overrides.heading ?? background?.headingColor ?? null,
6177
- link: overrides.link ?? background?.linkColor ?? null,
6178
- supporting: overrides.supporting ?? background?.supportingColor ?? null
6274
+ text: candidateOrBackground(overrides.text, background?.textColor),
6275
+ heading: candidateOrBackground(overrides.heading, background?.headingColor),
6276
+ link: candidateOrBackground(overrides.link, background?.linkColor),
6277
+ linkHover: candidateOrBackground(overrides.linkHover),
6278
+ supporting: candidateOrBackground(overrides.supporting, background?.supportingColor)
6179
6279
  };
6180
6280
  }
6281
+ function candidateOrBackground(candidate, backgroundValue) {
6282
+ return candidate ?? backgroundValue ?? null;
6283
+ }
6181
6284
  function resolveDeterministicForeground(backgroundReference, candidates, palette, compositeBase) {
6182
6285
  const backgroundHex = resolveOpaqueSurfaceHex(backgroundReference, palette, compositeBase);
6183
6286
  if (!backgroundHex) return resolveTrustedTreatmentForeground(candidates, palette);
@@ -6189,29 +6292,51 @@ function resolveDeterministicForeground(backgroundReference, candidates, palette
6189
6292
  ...FALLBACK_TEXT_TOKENS
6190
6293
  ], backgroundHex, palette, derivedOnToken ? [derivedOnToken] : []);
6191
6294
  if (!text) return { kind: "unknown" };
6192
- return {
6193
- kind: "known",
6194
- roles: {
6195
- text,
6196
- heading: safeTokenOr(candidates.heading, text, backgroundHex, palette),
6197
- link: safeTokenOr(candidates.link, text, backgroundHex, palette),
6198
- supporting: safeTokenOr(candidates.supporting, text, backgroundHex, palette)
6199
- }
6200
- };
6295
+ return knownForeground({
6296
+ text,
6297
+ heading: safeTokenOr(candidates.heading, text, backgroundHex, palette),
6298
+ link: safeTokenOr(candidates.link, text, backgroundHex, palette),
6299
+ supporting: safeTokenOr(candidates.supporting, text, backgroundHex, palette)
6300
+ }, {
6301
+ kind: "measured",
6302
+ backdropHex: backgroundHex
6303
+ }, candidates.linkHover, palette);
6201
6304
  }
6202
6305
  function resolveTrustedTreatmentForeground(candidates, palette) {
6203
6306
  const text = canonicalToken(candidates.text, palette);
6204
6307
  if (!text) return { kind: "unknown" };
6308
+ return knownForeground({
6309
+ text,
6310
+ heading: canonicalToken(candidates.heading, palette) ?? text,
6311
+ link: canonicalToken(candidates.link, palette) ?? text,
6312
+ supporting: canonicalToken(candidates.supporting, palette) ?? text
6313
+ }, { kind: "trusted-treatment" }, candidates.linkHover, palette);
6314
+ }
6315
+ function knownForeground(roles, provenance, hoverCandidate, palette) {
6316
+ const hover = planForegroundHover({
6317
+ restingToken: roles.link,
6318
+ candidate: canonicalHoverToken(hoverCandidate, palette),
6319
+ palette,
6320
+ backdrops: provenance.kind === "measured" ? [provenance.backdropHex] : null
6321
+ });
6205
6322
  return {
6206
6323
  kind: "known",
6324
+ provenance,
6207
6325
  roles: {
6208
- text,
6209
- heading: canonicalToken(candidates.heading, palette) ?? text,
6210
- link: canonicalToken(candidates.link, palette) ?? text,
6211
- supporting: canonicalToken(candidates.supporting, palette) ?? text
6212
- }
6326
+ ...roles,
6327
+ linkHover: hover.token
6328
+ },
6329
+ hoverDecoration: hover.decoration
6213
6330
  };
6214
6331
  }
6332
+ function canonicalHoverToken(reference, palette) {
6333
+ const token = parseThemeColorToken(reference);
6334
+ if (token) {
6335
+ const parts = parseColorTokenParts(token);
6336
+ if (parts.kind === "token" && resolveConcreteColorHex(parts.token, palette)) return token;
6337
+ }
6338
+ return canonicalToken(reference, palette);
6339
+ }
6215
6340
  function safeTokenOr(candidate, fallback, backgroundHex, palette) {
6216
6341
  return firstSafeToken([candidate], backgroundHex, palette) ?? fallback;
6217
6342
  }
@@ -6259,6 +6384,7 @@ var init_resolveSurfaceForeground = __esmMin((() => {
6259
6384
  init_opaqueSurfaceColor();
6260
6385
  init_colorTokenParts();
6261
6386
  init_themeColorTokens();
6387
+ init_foregroundInteraction();
6262
6388
  FALLBACK_TEXT_TOKENS = [
6263
6389
  "text",
6264
6390
  "primaryForeground",
@@ -10607,7 +10733,7 @@ function presetCategory(recipe) {
10607
10733
  case void 0: return "modern";
10608
10734
  }
10609
10735
  }
10610
- var init_presets$2 = __esmMin((() => {
10736
+ var init_presets$3 = __esmMin((() => {
10611
10737
  init_styles();
10612
10738
  buttonStyleRecipes.map((recipe) => {
10613
10739
  const resolved = resolveButtonStyleSelection(defaultButtonStyleSelectionFor(recipe.id));
@@ -10638,7 +10764,7 @@ var init_buttons = __esmMin((() => {
10638
10764
  init_affordanceIcons();
10639
10765
  init_generateDefaultButtonSystem();
10640
10766
  init_constants$2();
10641
- init_presets$2();
10767
+ init_presets$3();
10642
10768
  init_styles();
10643
10769
  init_styles();
10644
10770
  }));
@@ -11232,6 +11358,13 @@ var init_roles = __esmMin((() => {
11232
11358
  init_generateDefaultCardSystem();
11233
11359
  }));
11234
11360
  //#endregion
11361
+ //#region ../theme-core/src/utils/cssDeclarations.ts
11362
+ /** Render CSS declarations whether callers provide terminators or fragments. */
11363
+ function renderCssDeclarations(declarations) {
11364
+ return declarations.map((declaration) => declaration.endsWith(";") ? declaration : `${declaration};`).join("\n ");
11365
+ }
11366
+ var init_cssDeclarations = __esmMin((() => {}));
11367
+ //#endregion
11235
11368
  //#region ../theme-core/src/cards/generateCardCss.ts
11236
11369
  function resolveCornerRadiiCss$1(cornerRadii, fallback) {
11237
11370
  const fallbackValue = CORNER_RADIUS_MAP$3[fallback];
@@ -11241,6 +11374,7 @@ function resolveCornerRadiiCss$1(cornerRadii, fallback) {
11241
11374
  function generateCardCss(options) {
11242
11375
  const { themeId, theme, cardSystem: providedCardSystem } = options;
11243
11376
  const tokens = new TokenResolver(theme);
11377
+ const palette = expandPalette(theme.palette);
11244
11378
  const cardSystem = providedCardSystem ?? generateDefaultCardSystem(theme);
11245
11379
  const source = providedCardSystem ? "site-style" : "generated-baseline";
11246
11380
  const aliasGroups = resolveRoleAliasGroups(theme, providedCardSystem ?? null);
@@ -11251,11 +11385,11 @@ function generateCardCss(options) {
11251
11385
  const groupKey = roleAliasGroupKey(source, variant.id);
11252
11386
  emittedGroupKeys.add(groupKey);
11253
11387
  const aliasClasses = aliasGroups.get(groupKey)?.classes ?? [];
11254
- cssChunks.push(generateVariantCSS(variant, themeId, [`card-${variant.id}`, ...aliasClasses], tokens, theme));
11388
+ cssChunks.push(generateVariantCSS(variant, themeId, [`card-${variant.id}`, ...aliasClasses], tokens, theme, palette));
11255
11389
  }
11256
11390
  for (const [groupKey, group] of aliasGroups) {
11257
11391
  if (emittedGroupKeys.has(groupKey)) continue;
11258
- cssChunks.push(generateVariantCSS(group.variant, themeId, group.classes, tokens, theme));
11392
+ cssChunks.push(generateVariantCSS(group.variant, themeId, group.classes, tokens, theme, palette));
11259
11393
  }
11260
11394
  return cssChunks.filter(Boolean).join("\n\n");
11261
11395
  }
@@ -11297,7 +11431,7 @@ function resolveRoleAliasGroups(theme, cardSystem) {
11297
11431
  * This CSS-first approach eliminates runtime transforms for styling,
11298
11432
  * keeping transforms only for data normalization and dynamic layout.
11299
11433
  */
11300
- function generateVariantCSS(variant, themeId, cardClasses, tokens, theme) {
11434
+ function generateVariantCSS(variant, themeId, cardClasses, tokens, theme, palette) {
11301
11435
  const selectorsFor = (suffix) => cardClasses.map((cardClass) => `:where([data-theme-scope="${themeId}"]) .${cardClass}.${cardClass}${suffix}`).join(",\n");
11302
11436
  const containerSelectors = cardClasses.map((cardClass) => `:where([data-theme-scope="${themeId}"]) .${cardClass}.${cardClass}`);
11303
11437
  const containerSelector = containerSelectors.join(",\n");
@@ -11305,19 +11439,7 @@ function generateVariantCSS(variant, themeId, cardClasses, tokens, theme) {
11305
11439
  const contentSelector = selectorsFor(" .card-content");
11306
11440
  const fallbackBackgroundSelector = selectorsFor(" > .rb-bg-surface");
11307
11441
  const rules = [];
11308
- if (variant.background.type === "solid") {
11309
- const bgColor = tokens.getColor(variant.background.colorToken);
11310
- rules.push(`background: ${bgColor}`);
11311
- } else if (variant.background.type === "gradient") {
11312
- const fromColor = tokens.getColor(variant.background.fromToken);
11313
- const toColor = tokens.getColor(variant.background.toToken);
11314
- const direction = GRADIENT_DIRECTION_MAP$1[variant.background.direction] || "to right";
11315
- rules.push(`background: linear-gradient(${direction}, ${fromColor}, ${toColor})`);
11316
- } else rules.push(`background: transparent`);
11317
- if (variant.background.type !== "transparent") {
11318
- const foreground = tokens.getColor(variant.foregroundToken ?? "text");
11319
- rules.push(...surfaceForegroundDeclarations({ text: foreground }));
11320
- }
11442
+ rules.push(...cardSurfaceRules(variant, tokens, theme, palette));
11321
11443
  const resolveColor = (token) => tokens.getColor(token);
11322
11444
  rules.push(...cardBorderDeclarations(variant.border ? borderDeclaration(variant.border, tokens) : null, variant.decorations, resolveColor));
11323
11445
  const corners = variant.corners ?? theme.corners;
@@ -11334,13 +11456,31 @@ function generateVariantCSS(variant, themeId, cardClasses, tokens, theme) {
11334
11456
  const contentRules = [`padding: ${resolveContentPadding(variant)}`];
11335
11457
  return [
11336
11458
  `${structureSelector} {\n display: flex;\n flex-direction: column;\n position: relative;\n overflow: visible;\n}`,
11337
- `${containerSelector} {\n ${rules.join(";\n ")};\n}`,
11459
+ `${containerSelector} {\n ${renderCssDeclarations(rules)}\n}`,
11338
11460
  ...cardDecorationPseudoRules(containerSelectors, variant.decorations, resolveColor),
11339
11461
  `${fallbackBackgroundSelector} {\n background: transparent;\n}`,
11340
11462
  `${mediaSelector} {\n ${mediaRules.join(";\n ")};\n}`,
11341
11463
  `${contentSelector} {\n ${contentRules.join(";\n ")};\n}`
11342
11464
  ].join("\n\n");
11343
11465
  }
11466
+ function cardSurfaceRules(variant, tokens, theme, palette) {
11467
+ if (variant.background.type === "transparent") return ["background: transparent"];
11468
+ const foreground = resolveSurfaceForeground(variant.background.type === "solid" ? {
11469
+ type: "color",
11470
+ color: variant.background.colorToken,
11471
+ textColor: variant.foregroundToken ?? "text"
11472
+ } : {
11473
+ type: "gradient",
11474
+ textColor: variant.foregroundToken ?? "text"
11475
+ }, palette, { linkHover: theme.typography.proseLinkStyle?.hoverColorToken });
11476
+ return [cardBackgroundRule(variant.background, tokens), ...surfaceForegroundDeclarations(foreground.kind === "known" ? surfaceForegroundInputFromResolved(foreground, (token) => tokens.getColor(token)) : { text: tokens.getColor(variant.foregroundToken ?? "text") })];
11477
+ }
11478
+ function cardBackgroundRule(background, tokens) {
11479
+ if (background.type === "solid") return `background: ${tokens.getColor(background.colorToken)}`;
11480
+ const from = tokens.getColor(background.fromToken);
11481
+ const to = tokens.getColor(background.toToken);
11482
+ return `background: linear-gradient(${GRADIENT_DIRECTION_MAP$1[background.direction] || "to right"}, ${from}, ${to})`;
11483
+ }
11344
11484
  function borderDeclaration(border, tokens) {
11345
11485
  const borderColor = tokens.getColor(border.colorToken);
11346
11486
  return `border: ${border.widthClass === "border-4" ? "4px" : border.widthClass === "border-2" ? "2px" : border.widthClass === "border" ? "1px" : "1px"} solid ${borderColor}`;
@@ -11361,6 +11501,8 @@ var PER_CORNER_RADIUS_MAP$1, CONTENT_PADDING_MAP, MEDIA_CORNER_MAP, init_generat
11361
11501
  init_roles();
11362
11502
  init_types$13();
11363
11503
  init_surfaces();
11504
+ init_expandPalette();
11505
+ init_cssDeclarations();
11364
11506
  PER_CORNER_RADIUS_MAP$1 = {
11365
11507
  square: "0",
11366
11508
  soft: "0.5rem",
@@ -11386,6 +11528,7 @@ var PER_CORNER_RADIUS_MAP$1, CONTENT_PADDING_MAP, MEDIA_CORNER_MAP, init_generat
11386
11528
  var init_core$2 = __esmMin((() => {
11387
11529
  init_surfaces();
11388
11530
  init_decorations();
11531
+ init_cssDeclarations();
11389
11532
  }));
11390
11533
  //#endregion
11391
11534
  //#region ../theme-core/src/cards/index.ts
@@ -11753,16 +11896,70 @@ var init_baseSchema = __esmMin((() => {
11753
11896
  });
11754
11897
  }));
11755
11898
  //#endregion
11899
+ //#region ../theme-core/src/navigation/effectPolicy.ts
11900
+ function navEffectPolicy(effectId) {
11901
+ return policiesById[effectId] ?? null;
11902
+ }
11903
+ var NAV_EFFECT_POLICIES, policiesById;
11904
+ var init_effectPolicy = __esmMin((() => {
11905
+ NAV_EFFECT_POLICIES = {
11906
+ "darken-background": "other",
11907
+ "lighten-background": "other",
11908
+ "fade-background": "other",
11909
+ "opacity-reduce": "other",
11910
+ "animated-gradient": "other",
11911
+ "background-on-hover": "paired-hover",
11912
+ "background-on-hover-alpha": "paired-hover",
11913
+ "border-glow": "other",
11914
+ "drop-shadow": "other",
11915
+ "inner-shadow": "other",
11916
+ "neumorphic-shadow": "other",
11917
+ "outer-glow": "other",
11918
+ "retro-3d-shadow": "other",
11919
+ "scale-up": "other",
11920
+ "scale-down": "other",
11921
+ lift: "other",
11922
+ "press-down": "other",
11923
+ pop: "other",
11924
+ "aurora-glow": "other",
11925
+ "cosmic-stardust": "other",
11926
+ "gradient-border-fill": "other",
11927
+ "animated-gradient-border-fill": "other",
11928
+ "border-bottom-grow": "other",
11929
+ "gradient-text": "other",
11930
+ "text-color-change": "text-colour",
11931
+ "border-color-change": "other",
11932
+ "sketchy-border": "other",
11933
+ "pulse-animation": "other",
11934
+ "nav-underline": "underline",
11935
+ "nav-frosted-base": "other",
11936
+ "nav-frosted-hover": "other",
11937
+ "nav-frosted-active": "other"
11938
+ };
11939
+ policiesById = NAV_EFFECT_POLICIES;
11940
+ }));
11941
+ //#endregion
11756
11942
  //#region ../theme-core/src/navigation/types.ts
11757
11943
  /**
11758
11944
  * Navigation Link Style Types
11759
11945
  *
11760
11946
  * Schema and types for composable nav link styling used by header and footer.
11761
11947
  */
11948
+ function navLinkHoverColorCandidate(style) {
11949
+ const effect = style?.effects?.hover?.find((item) => navEffectPolicy(item.effectId) === "text-colour");
11950
+ return parseThemeColorToken(effect?.options?.hoverColorToken ?? style?.hoverColorToken);
11951
+ }
11952
+ function navLinkOwnsHoverForeground(style) {
11953
+ return style?.effects?.hover?.some((effect) => navEffectPolicy(effect.effectId) === "paired-hover") ?? false;
11954
+ }
11955
+ function navLinkOwnsUnderline(style) {
11956
+ return style?.effects?.hover?.some((effect) => navEffectPolicy(effect.effectId) === "underline") ?? false;
11957
+ }
11762
11958
  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;
11763
11959
  var init_types$9 = __esmMin((() => {
11764
11960
  init_baseSchema();
11765
11961
  init_themeColorTokens();
11962
+ init_effectPolicy();
11766
11963
  navLinkPaddingSchema = z$1.enum([
11767
11964
  "none",
11768
11965
  "compact",
@@ -18710,7 +18907,7 @@ function getGradientPreset(id) {
18710
18907
  return gradientPresetById[id];
18711
18908
  }
18712
18909
  var rawGradientPresets, GRADIENT_PRESETS, GRADIENT_PRESET_IDS, gradientPresetIdSet, gradientPresetById;
18713
- var init_presets$1 = __esmMin((() => {
18910
+ var init_presets$2 = __esmMin((() => {
18714
18911
  rawGradientPresets = [
18715
18912
  {
18716
18913
  id: "primary-secondary",
@@ -18940,7 +19137,7 @@ var init_utils$2 = __esmMin((() => {}));
18940
19137
  //#region ../theme-core/src/gradients/index.ts
18941
19138
  var init_gradients = __esmMin((() => {
18942
19139
  init_types$10();
18943
- init_presets$1();
19140
+ init_presets$2();
18944
19141
  init_utils$2();
18945
19142
  }));
18946
19143
  //#endregion
@@ -21803,6 +22000,15 @@ var init_resolver = __esmMin((() => {
21803
22000
  };
21804
22001
  blockDesignFallback.sectionSurface, blockDesignFallback.contentFrame, blockDesignFallback.sectionHeight, blockDesignFallback.heroLegibility, blockDesignFallback.imageSurfaceTreatment, blockDesignFallback.imageSurfaceMotion, blockDesignFallback.tileTreatment, blockDesignFallback.eventListTreatment, blockDesignFallback.eyebrowTreatment, blockDesignFallback.accordionIconTreatment, blockDesignFallback.composition;
21805
22002
  }));
22003
+ //#endregion
22004
+ //#region ../theme-core/src/header/rootPaint.ts
22005
+ /** The nav container takes precedence when a floating header also has one. */
22006
+ function headerRootPaint(header) {
22007
+ const navContainerType = header?.navContainer?.type ?? "none";
22008
+ if (navContainerType === "glass" || navContainerType === "pill") return "contained-nav";
22009
+ return header?.variant === "floating" ? "overlay" : "own-surface";
22010
+ }
22011
+ var init_rootPaint = __esmMin((() => {}));
21806
22012
  function parseSiteChromeBackgroundColorToken(value) {
21807
22013
  const token = parseBackgroundAppearanceColorToken(value);
21808
22014
  return token ? token : null;
@@ -21819,6 +22025,7 @@ var init_siteChromeBackgrounds = __esmMin((() => {
21819
22025
  init_surfaces();
21820
22026
  init_backgroundAppearance();
21821
22027
  init_rawStyleFields();
22028
+ init_rootPaint();
21822
22029
  siteChromeBackgroundColorTokens = toSiteChromeBackgroundColorTokens(backgroundAppearanceColorTokenNames);
21823
22030
  quickSiteChromeBackgroundColorTokens = toSiteChromeBackgroundColorTokens(backgroundAppearanceQuickColorTokenNames);
21824
22031
  siteChromeBackgroundColorTokens.filter((token) => !quickSiteChromeBackgroundColorTokens.includes(token));
@@ -22139,13 +22346,278 @@ function diffJsonPaths(left, right, path = "") {
22139
22346
  }];
22140
22347
  }
22141
22348
  var init_headerBytesComparison = __esmMin((() => {}));
22349
+ //#endregion
22350
+ //#region ../theme-core/src/navigation/presets.ts
22351
+ /**
22352
+ * Get a nav link style preset by ID
22353
+ */
22354
+ function getNavLinkPreset(presetId) {
22355
+ return NAV_LINK_PRESETS[presetId];
22356
+ }
22357
+ var NAV_LINK_PRESETS;
22358
+ var init_presets$1 = __esmMin((() => {
22359
+ NAV_LINK_PRESETS = {
22360
+ /**
22361
+ * Minimal - subtle color change on hover
22362
+ */
22363
+ minimal: {
22364
+ name: "Minimal",
22365
+ typography: "body",
22366
+ fontWeight: "medium",
22367
+ textTransform: "none",
22368
+ italic: false,
22369
+ colorToken: "text",
22370
+ hoverColorToken: "primary",
22371
+ padding: "none",
22372
+ borderRadius: "none",
22373
+ effects: { hover: [{
22374
+ effectId: "text-color-change",
22375
+ options: { hoverColorToken: "primary" }
22376
+ }] }
22377
+ },
22378
+ /**
22379
+ * Underline - static underline appears on hover
22380
+ */
22381
+ underline: {
22382
+ name: "Underline",
22383
+ typography: "body",
22384
+ fontWeight: "medium",
22385
+ textTransform: "none",
22386
+ italic: false,
22387
+ colorToken: "text",
22388
+ padding: "none",
22389
+ borderRadius: "none",
22390
+ effects: { hover: [{
22391
+ effectId: "nav-underline",
22392
+ options: { style: "static" }
22393
+ }] }
22394
+ },
22395
+ /**
22396
+ * Underline Grow - animated underline grows from center on hover
22397
+ */
22398
+ "underline-grow": {
22399
+ name: "Underline Grow",
22400
+ typography: "body",
22401
+ fontWeight: "medium",
22402
+ textTransform: "none",
22403
+ italic: false,
22404
+ colorToken: "text",
22405
+ padding: "none",
22406
+ borderRadius: "none",
22407
+ effects: { hover: [{
22408
+ effectId: "nav-underline",
22409
+ options: { style: "grow" }
22410
+ }] }
22411
+ },
22412
+ /**
22413
+ * Capsule - pill-shaped background on hover
22414
+ */
22415
+ capsule: {
22416
+ name: "Capsule",
22417
+ typography: "body",
22418
+ fontWeight: "medium",
22419
+ textTransform: "none",
22420
+ italic: false,
22421
+ colorToken: "text",
22422
+ padding: "compact",
22423
+ borderRadius: "full",
22424
+ effects: {
22425
+ hover: [{
22426
+ effectId: "background-on-hover-alpha",
22427
+ options: {
22428
+ colorToken: "primary",
22429
+ opacity: 10
22430
+ }
22431
+ }],
22432
+ active: [{
22433
+ effectId: "background-on-hover-alpha",
22434
+ options: {
22435
+ colorToken: "primary",
22436
+ opacity: 15
22437
+ }
22438
+ }]
22439
+ }
22440
+ },
22441
+ /**
22442
+ * Solid - solid background color on hover
22443
+ */
22444
+ solid: {
22445
+ name: "Solid",
22446
+ typography: "body",
22447
+ fontWeight: "medium",
22448
+ textTransform: "none",
22449
+ italic: false,
22450
+ colorToken: "text",
22451
+ padding: "compact",
22452
+ borderRadius: "none",
22453
+ effects: {
22454
+ hover: [{
22455
+ effectId: "background-on-hover",
22456
+ options: {
22457
+ colorToken: "primary",
22458
+ textColorToken: "primaryForeground"
22459
+ }
22460
+ }],
22461
+ active: [{
22462
+ effectId: "background-on-hover",
22463
+ options: {
22464
+ colorToken: "primary",
22465
+ textColorToken: "primaryForeground"
22466
+ }
22467
+ }]
22468
+ }
22469
+ },
22470
+ /**
22471
+ * Scale - gentle scale-up on hover
22472
+ */
22473
+ scale: {
22474
+ name: "Scale",
22475
+ typography: "body",
22476
+ fontWeight: "medium",
22477
+ textTransform: "none",
22478
+ italic: false,
22479
+ colorToken: "text",
22480
+ padding: "none",
22481
+ borderRadius: "none",
22482
+ effects: { hover: [{
22483
+ effectId: "scale-up",
22484
+ options: { scale: 1.05 }
22485
+ }] }
22486
+ },
22487
+ /**
22488
+ * Frosted - semi-transparent glass-like background
22489
+ */
22490
+ frosted: {
22491
+ name: "Frosted",
22492
+ typography: "body",
22493
+ fontWeight: "medium",
22494
+ textTransform: "none",
22495
+ italic: false,
22496
+ colorToken: "text",
22497
+ padding: "compact",
22498
+ borderRadius: "md",
22499
+ effects: {
22500
+ base: [{ effectId: "nav-frosted-base" }],
22501
+ hover: [{ effectId: "nav-frosted-hover" }],
22502
+ active: [{ effectId: "nav-frosted-active" }]
22503
+ }
22504
+ }
22505
+ };
22506
+ Object.keys(NAV_LINK_PRESETS);
22507
+ }));
22508
+ //#endregion
22509
+ //#region ../theme-core/src/header/legacyNavLinkStyle.ts
22510
+ function buildLegacyHeaderNavLinkStyle(header, contrastTreatment, navTextSize) {
22511
+ const navStyle = header.navStyle ?? "minimal";
22512
+ const basePreset = getNavLinkPreset(navStyle);
22513
+ if (!basePreset) return null;
22514
+ const style = {
22515
+ ...basePreset,
22516
+ fontWeight: header.navWeight ?? basePreset.fontWeight,
22517
+ colorToken: (header.navColor ?? header.textColor)?.trim() || basePreset.colorToken,
22518
+ ...contrastTreatment ? { contrastTreatment } : {},
22519
+ ...navTextSize ? { textSize: navTextSize } : {}
22520
+ };
22521
+ if (header.navWeight === "bold" && navStyle === "solid") style.textTransform = "uppercase";
22522
+ applyLegacyGlassTreatment(style, header, navStyle);
22523
+ return style;
22524
+ }
22525
+ function applyLegacyGlassTreatment(style, header, navStyle) {
22526
+ if (header.navContainer?.type !== "glass" || navStyle !== "minimal") return;
22527
+ style.borderRadius = "full";
22528
+ style.effects = {
22529
+ ...style.effects,
22530
+ hover: glassStateEffects(10),
22531
+ active: glassStateEffects(18)
22532
+ };
22533
+ }
22534
+ function glassStateEffects(opacity) {
22535
+ return [{
22536
+ effectId: "background-on-hover-alpha",
22537
+ options: {
22538
+ colorToken: "neutral-50",
22539
+ opacity
22540
+ }
22541
+ }, {
22542
+ effectId: "text-color-change",
22543
+ options: { hoverColorToken: "neutral-50" }
22544
+ }];
22545
+ }
22546
+ var init_legacyNavLinkStyle = __esmMin((() => {
22547
+ init_presets$1();
22548
+ }));
22549
+ function readOpeningForegroundProjection(header) {
22550
+ return header?.__runtimeOpeningForeground ?? null;
22551
+ }
22552
+ var init_openingForegroundProjection = __esmMin((() => {}));
22553
+ //#endregion
22554
+ //#region ../theme-core/src/header/effectiveNavLinkStyle.ts
22555
+ function effectiveHeaderNavLinkStyle(header, contrastTreatment = null, navTextSize = null) {
22556
+ if (!header) return null;
22557
+ if (!header.navLinkStyle) return buildLegacyHeaderNavLinkStyle(header, contrastTreatment, navTextSize);
22558
+ return {
22559
+ ...header.navLinkStyle,
22560
+ ...contrastTreatment ? { contrastTreatment } : {},
22561
+ ...navTextSize ? { textSize: navTextSize } : {}
22562
+ };
22563
+ }
22564
+ function headerForegroundCandidates(header) {
22565
+ if (!header) return {};
22566
+ const style = effectiveHeaderNavLinkStyle(header);
22567
+ return {
22568
+ text: header.textColor ?? header.background?.textColor,
22569
+ link: style?.colorToken ?? header.navColor ?? header.textColor,
22570
+ linkHover: navLinkHoverColorCandidate(style)
22571
+ };
22572
+ }
22573
+ function headerLeafTextColor(header) {
22574
+ if (!header) return "text";
22575
+ return header.textColor ?? header.navColor ?? header.background?.textColor ?? header.navLinkStyle?.colorToken ?? "text";
22576
+ }
22577
+ /** Transparent chrome must reset the whole contract on its own root. */
22578
+ function transparentHeaderForegroundInput(header, palette) {
22579
+ const projection = readOpeningForegroundProjection(header);
22580
+ if (projection?.kind === "known") return surfaceForegroundInputFromResolved(projection, rgbColorValue);
22581
+ return authoredTransparentHeaderForegroundInput(header, palette);
22582
+ }
22583
+ function authoredTransparentHeaderForegroundInput(header, palette) {
22584
+ const text = headerLeafTextColor(header);
22585
+ const style = effectiveHeaderNavLinkStyle(header);
22586
+ const link = style?.colorToken ?? text;
22587
+ const restingToken = parseThemeColorToken(link) ?? parseThemeColorToken("text");
22588
+ if (!restingToken) throw new Error("Built-in text colour token is invalid");
22589
+ const hover = planForegroundHover({
22590
+ restingToken,
22591
+ candidate: navLinkOwnsHoverForeground(style) ? null : navLinkHoverColorCandidate(style),
22592
+ palette,
22593
+ backdrops: null
22594
+ });
22595
+ return {
22596
+ text: rgbColorValue(text),
22597
+ link: rgbColorValue(link),
22598
+ linkHover: rgbColorValue(hover.token),
22599
+ hoverDecoration: navLinkOwnsUnderline(style) ? "initial" : hover.decoration
22600
+ };
22601
+ }
22602
+ var init_effectiveNavLinkStyle$1 = __esmMin((() => {
22603
+ init_types$9();
22604
+ init_legacyNavLinkStyle();
22605
+ init_openingForegroundProjection();
22606
+ init_surfaces();
22607
+ init_foregroundInteraction();
22608
+ init_tokens();
22609
+ init_colorStyles();
22610
+ }));
22142
22611
  var init_headerOpeningForeground = __esmMin((() => {
22143
22612
  init_foregroundInteraction();
22144
22613
  init_expandPalette();
22145
22614
  init_colorConversion();
22146
22615
  init_tokens();
22147
- init_logoVariant();
22148
22616
  init_colorTokenParts();
22617
+ init_types$9();
22618
+ init_effectPolicy();
22619
+ init_effectiveNavLinkStyle$1();
22620
+ init_openingForegroundProjection();
22149
22621
  init_types$8();
22150
22622
  }));
22151
22623
  var init_effectivePageDesign = __esmMin((() => {
@@ -22458,6 +22930,824 @@ var init_site_styles = __esmMin((() => {
22458
22930
  init_themeParity();
22459
22931
  init_types$8();
22460
22932
  }));
22933
+ //#endregion
22934
+ //#region ../theme-core/src/navigation/generateNavLinkCSS.ts
22935
+ /**
22936
+ * Generate complete CSS for nav links from a NavLinkStyle configuration
22937
+ */
22938
+ function generateNavLinkCSS(options) {
22939
+ const { themeId, tokens, theme, style, className } = options;
22940
+ const surfaceDependent = options.surfaceDependent === true && !navLinkOwnsHoverForeground(style);
22941
+ const overriddenSurface = options.surfaceDependent === true && options.surfaceRestingColor === true;
22942
+ const surfaceRestingColor = surfaceDependent || overriddenSurface;
22943
+ const selector = `:where([data-theme-scope="${themeId}"]) .${className}`;
22944
+ const activeSelector = `${selector}:active, ${selector}[data-active="true"]`;
22945
+ const baseRules = navBaseRules(style, tokens, theme, surfaceRestingColor, overriddenSurface);
22946
+ const hoverRules = navHoverRules(style, tokens, surfaceDependent);
22947
+ const activeRules = surfaceDependent ? [`color: ${surfaceForegroundValue("linkHover", tokens.getColor(style.colorToken))};`] : [];
22948
+ const authoredColor = tokens.getColor(style.colorToken);
22949
+ const effectsCss = style.effects ? generateEffectsCSS({
22950
+ themeId,
22951
+ variantId: className,
22952
+ effects: surfaceDependent ? withoutSurfaceTextColorEffects(style.effects) : style.effects,
22953
+ elementConfig: {
22954
+ background: { type: "transparent" },
22955
+ textColorToken: style.colorToken || "text"
22956
+ },
22957
+ tokens,
22958
+ theme
22959
+ }) : "";
22960
+ const underlineColorCss = surfaceDependent && navLinkOwnsUnderline(style) ? `\n${selector}::after {\n background: ${surfaceForegroundValue("link", authoredColor)};\n}\n` : "";
22961
+ return [
22962
+ cssRule(selector, baseRules),
22963
+ effectsCss,
22964
+ cssRule(`${selector}:hover`, hoverRules),
22965
+ cssRule(activeSelector, activeRules),
22966
+ underlineColorCss,
22967
+ navLinkFocusVisibleCss(selector, style, theme, tokens, surfaceRestingColor, overriddenSurface),
22968
+ generateInteractiveChildInheritanceCSS(selector)
22969
+ ].join("");
22970
+ }
22971
+ function navBaseRules(style, tokens, theme, surfaceRestingColor, overriddenSurface) {
22972
+ const typographyRules = generateBaseInteractiveCSS({
22973
+ typography: {
22974
+ typography: style.typography,
22975
+ fontWeight: style.fontWeight,
22976
+ textTransform: style.textTransform,
22977
+ italic: style.italic
22978
+ },
22979
+ padding: style.padding ? NAV_LINK_PADDING_MAP[style.padding] : void 0,
22980
+ borderRadius: style.borderRadius ? NAV_LINK_BORDER_RADIUS_MAP[style.borderRadius] : void 0,
22981
+ includeTransition: true,
22982
+ includeFlexCenter: false
22983
+ });
22984
+ const contrastShadow = navContrastShadow(style, theme, overriddenSurface);
22985
+ return [
22986
+ ...typographyRules,
22987
+ ...style.paddingX ? [`padding-left: ${NAV_LINK_PADDING_X_MAP[style.paddingX]};`, `padding-right: ${NAV_LINK_PADDING_X_MAP[style.paddingX]};`] : [],
22988
+ ...style.textSize ? [`font-size: ${NAV_LINK_TEXT_SIZE_MAP[style.textSize]};`] : [],
22989
+ ...style.letterSpacing && style.letterSpacing !== "normal" ? [`letter-spacing: ${NAV_LINK_LETTER_SPACING_MAP[style.letterSpacing]};`] : [],
22990
+ ...surfaceRestingColor ? [`color: ${surfaceForegroundValue("link", tokens.getColor(style.colorToken))};`] : style.colorToken ? [`color: ${tokens.getColor(style.colorToken)};`] : [],
22991
+ ...contrastShadow ? [`text-shadow: ${contrastShadow};`] : []
22992
+ ];
22993
+ }
22994
+ function navHoverRules(style, tokens, surfaceDependent) {
22995
+ if (surfaceDependent) return [`color: ${surfaceForegroundValue("linkHover", tokens.getColor(style.colorToken))};`, ...navLinkOwnsUnderline(style) ? [] : ["text-decoration-line: var(--rb-surface-link-hover-decoration, none);"]];
22996
+ return style.hoverColorToken && !style.effects?.hover?.length ? [`color: ${tokens.getColor(style.hoverColorToken)};`] : [];
22997
+ }
22998
+ function cssRule(selector, rules) {
22999
+ return rules.length > 0 ? `\n${selector} {\n ${rules.join("\n ")}\n}\n` : "";
23000
+ }
23001
+ function navContrastShadow(style, theme, overriddenSurface) {
23002
+ return overriddenSurface ? null : buildTextContrastShadow({
23003
+ theme,
23004
+ colorToken: style.colorToken,
23005
+ treatment: style.contrastTreatment
23006
+ });
23007
+ }
23008
+ function withoutSurfaceTextColorEffects(effects) {
23009
+ const withoutColor = (items) => items?.filter((effect) => navEffectPolicy(effect.effectId) !== "text-colour");
23010
+ return {
23011
+ base: withoutColor(effects.base),
23012
+ hover: withoutColor(effects.hover),
23013
+ active: withoutColor(effects.active),
23014
+ focus: withoutColor(effects.focus)
23015
+ };
23016
+ }
23017
+ /**
23018
+ * Keyboard focus indicator for nav links, in the header, the footer and header
23019
+ * dropdown menus — the three surfaces `generateNavLinkCSS` serves.
23020
+ *
23021
+ * Emitted unconditionally rather than as an effect, because focus visibility is
23022
+ * a floor rather than a style choice. Only the interaction-palette pill ever
23023
+ * wrote an `effects.focus` group, so every other nav — every `quiet` palette,
23024
+ * every footer, every dropdown — previously fell back to whatever outline the
23025
+ * browser drew.
23026
+ *
23027
+ * The outline takes the link's own resolved colour, so on a header that adapts
23028
+ * to the section it floats over it moves with the adaptation instead of
23029
+ * asserting a brand colour against an unknown backdrop.
23030
+ *
23031
+ * Where the style asks for `soft-glow`, the same halo goes on the outline. That
23032
+ * treatment exists because the theme has already conceded the resolved colour
23033
+ * alone is not reliable over an unpredictable backdrop — a hero photograph with
23034
+ * mixed luminance. Without it the text would stay legible by its halo while the
23035
+ * focus ring, which is the part with a contrast requirement of its own, would
23036
+ * not.
23037
+ *
23038
+ * A style that also paints a focus pill keeps it: this adds an outline around
23039
+ * that pill rather than replacing it.
23040
+ */
23041
+ function navLinkFocusVisibleCss(selector, style, theme, tokens, surfaceRestingColor, overriddenSurface) {
23042
+ const color = surfaceRestingColor ? surfaceForegroundValue("link", tokens.getColor(style.colorToken)) : tokens.getColor(style.colorToken);
23043
+ const halo = navContrastShadow(style, theme, overriddenSurface);
23044
+ return `
23045
+ ${selector}:focus-visible {
23046
+ outline: 2px solid ${color};
23047
+ outline-offset: ${focusOutlineOffset(selector)};${halo ? `\n box-shadow: ${halo};` : ""}
23048
+ }
23049
+ `;
23050
+ }
23051
+ /**
23052
+ * Dropdown items are full-width inside a panel with no horizontal padding, so
23053
+ * an outset outline would paint over and past the panel's own border. Keeping
23054
+ * it flush is the only way it reads as belonging to the item.
23055
+ */
23056
+ function focusOutlineOffset(selector) {
23057
+ return selector.includes("nav-dropdown-link") ? "-2px" : "3px";
23058
+ }
23059
+ function buildTextContrastShadow(input) {
23060
+ if (input.treatment !== "soft-glow") return null;
23061
+ 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)";
23062
+ }
23063
+ function isLikelyLightColorToken(theme, colorToken) {
23064
+ const hex = resolveColorTokenHex(theme, colorToken);
23065
+ if (hex) try {
23066
+ return featuresFromHex(hex).Y >= .5;
23067
+ } catch {}
23068
+ const normalizedToken = colorToken?.toLowerCase() ?? "";
23069
+ if (normalizedToken.includes("foreground") || normalizedToken.startsWith("on") || normalizedToken.includes("white") || normalizedToken.endsWith("-50") || normalizedToken.endsWith("-100")) return true;
23070
+ if (normalizedToken.includes("black") || normalizedToken.endsWith("-800") || normalizedToken.endsWith("-900") || normalizedToken.endsWith("-950")) return false;
23071
+ return theme.palette.meta.mode === "dark";
23072
+ }
23073
+ function resolveColorTokenHex(theme, colorToken) {
23074
+ if (!colorToken) return null;
23075
+ if (colorToken === "white") return "#ffffff";
23076
+ if (colorToken === "black") return "#000000";
23077
+ if (colorToken === "transparent") return null;
23078
+ return expandPalette(theme.palette)[colorToken] ?? null;
23079
+ }
23080
+ var init_generateNavLinkCSS = __esmMin((() => {
23081
+ init_types$9();
23082
+ init_expandPalette();
23083
+ init_colorConversion();
23084
+ init_generateBaseCSS();
23085
+ init_generateEffectsCSS();
23086
+ init_foregroundContract();
23087
+ init_effectPolicy();
23088
+ })), NAV_DROPDOWN_SHIFT_PROPERTY, NAV_DROPDOWN_MAX_WIDTH_CSS, NAV_DROPDOWN_CONTAINER_RAIL_CSS_RULES;
23089
+ var init_navDropdownSizing = __esmMin((() => {
23090
+ NAV_DROPDOWN_SHIFT_PROPERTY = "--nav-dropdown-shift-x";
23091
+ NAV_DROPDOWN_MAX_WIDTH_CSS = `min(22rem, calc(100vw - 2rem))`;
23092
+ NAV_DROPDOWN_CONTAINER_RAIL_CSS_RULES = [
23093
+ `min-width: 12rem;`,
23094
+ `width: max-content;`,
23095
+ `max-width: ${NAV_DROPDOWN_MAX_WIDTH_CSS};`,
23096
+ `transform: translateX(var(${NAV_DROPDOWN_SHIFT_PROPERTY}, 0px));`
23097
+ ];
23098
+ }));
23099
+ //#endregion
23100
+ //#region ../theme-core/src/header/surfaceRules.ts
23101
+ /** Compile the at-rest surface independently of scroll treatment and paint geometry. */
23102
+ function buildHeaderSurfaceRules(header, tokens) {
23103
+ const base = [];
23104
+ const background = header.background;
23105
+ if (background.type === "color") base.push(`background-color: ${tokens.getColor(background.color || "surface")};`);
23106
+ else if (background.type === "gradient" && background.gradient) {
23107
+ const stops = background.gradient.stops.map((stop) => tokens.getColor(stop.color)).join(", ");
23108
+ base.push(`background-image: linear-gradient(${background.gradient.angle ?? 180}deg, ${stops});`);
23109
+ }
23110
+ const borderWidth = getComponentBorderWidthPx(header.border?.width ?? "none");
23111
+ if (!header.border || borderWidth === "0") return {
23112
+ base,
23113
+ border: []
23114
+ };
23115
+ const color = rgbColorValue(header.border.colorToken?.trim() || "border");
23116
+ const style = header.border.style === "dashed" ? "dashed" : "solid";
23117
+ return {
23118
+ base,
23119
+ border: header.border.position === "both" ? [`border-top: ${borderWidth} ${style} ${color};`, `border-bottom: ${borderWidth} ${style} ${color};`] : [`border-${header.border.position}: ${borderWidth} ${style} ${color};`]
23120
+ };
23121
+ }
23122
+ var init_surfaceRules = __esmMin((() => {
23123
+ init_shared$4();
23124
+ init_colorStyles();
23125
+ }));
23126
+ //#endregion
23127
+ //#region ../theme-core/src/header/generateHeaderNavLinkStyles.ts
23128
+ function generateHeaderNavLinkStyles(header, themeId, tokens, theme, contrastTreatment, navTextSize) {
23129
+ const style = effectiveHeaderNavLinkStyle(header, contrastTreatment, navTextSize);
23130
+ if (!style) {
23131
+ console.warn(`[generateHeaderCss] Nav link preset not found: ${header.navStyle}`);
23132
+ return "";
23133
+ }
23134
+ return generateNavLinkCSS({
23135
+ themeId,
23136
+ tokens,
23137
+ theme,
23138
+ style: mergeHeaderNavTypographyPreference(style, {
23139
+ typography: header.navFontRole ?? "inherit",
23140
+ fontSize: readHeaderNavFontSizePreference(header.navTextSize),
23141
+ interactionPalette: header.interactionPalette ?? "recommended"
23142
+ }),
23143
+ className: "header-nav-link",
23144
+ surfaceDependent: true,
23145
+ surfaceRestingColor: header.background?.contentOwner === siteChromeBackgroundOverrideOwner
23146
+ });
23147
+ }
23148
+ var init_generateHeaderNavLinkStyles = __esmMin((() => {
23149
+ init_generateNavLinkCSS();
23150
+ init_siteChromeNavPreferences();
23151
+ init_effectiveNavLinkStyle$1();
23152
+ init_rawStyleFields();
23153
+ }));
23154
+ //#endregion
23155
+ //#region ../theme-core/src/header/generateHeaderLogoStyles.ts
23156
+ function generateHeaderLogoStyles(input) {
23157
+ const { logo, themeId, tokens } = input;
23158
+ return `\n${`:where([data-theme-scope="${themeId}"]) .header-logo-text`} {\n ${[
23159
+ ...logoTextColorRules(input),
23160
+ logo?.fontFamily === "body" ? "font-family: var(--font-body);" : "font-family: var(--font-heading);",
23161
+ ...logoLetterSpacingRules(logo),
23162
+ ...logoGradientRules(logo, tokens),
23163
+ ...logoContrastRules(input)
23164
+ ].join("\n ")}\n}\n${mobilePanelLogoColor(input)}`;
23165
+ }
23166
+ function mobilePanelLogoColor(input) {
23167
+ if (input.logo?.gradient) return "";
23168
+ const { themeId, tokens, textColor, fallbackTextColor } = input;
23169
+ const fallback = tokens.getColor(textColor ?? fallbackTextColor ?? "text");
23170
+ 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`;
23171
+ }
23172
+ function logoTextColorRules(input) {
23173
+ const { logo, textColor, fallbackTextColor, tokens, useSurfaceTextColor } = input;
23174
+ if (logo?.gradient || !textColor && !useSurfaceTextColor) return [];
23175
+ const authoredColor = tokens.getColor(textColor ?? fallbackTextColor ?? "text");
23176
+ return [`color: ${useSurfaceTextColor ? surfaceForegroundValue("text", authoredColor) : authoredColor};`];
23177
+ }
23178
+ function logoLetterSpacingRules(logo) {
23179
+ const spacing = logo?.letterSpacing;
23180
+ if (!spacing || spacing === "normal") return [];
23181
+ return [`letter-spacing: ${{
23182
+ wide: "0.05em",
23183
+ wider: "0.1em",
23184
+ widest: "0.15em"
23185
+ }[spacing]};`];
23186
+ }
23187
+ function logoGradientRules(logo, tokens) {
23188
+ if (!logo?.gradient) return [];
23189
+ return [
23190
+ `background: linear-gradient(to right, ${tokens.getColor("primary")}, ${tokens.getColor("accent")});`,
23191
+ "-webkit-background-clip: text;",
23192
+ "-webkit-text-fill-color: transparent;",
23193
+ "background-clip: text;",
23194
+ "color: transparent;"
23195
+ ];
23196
+ }
23197
+ function logoContrastRules(input) {
23198
+ if (input.logo?.gradient || input.useSurfaceTextColor) return [];
23199
+ const colorToken = input.textColor?.trim() || input.fallbackTextColor?.trim() || "text";
23200
+ const shadow = buildTextContrastShadow({
23201
+ theme: input.theme,
23202
+ colorToken,
23203
+ treatment: input.contrastTreatment
23204
+ });
23205
+ return shadow ? [`text-shadow: ${shadow};`] : [];
23206
+ }
23207
+ var init_generateHeaderLogoStyles = __esmMin((() => {
23208
+ init_generateNavLinkCSS();
23209
+ init_surfaces();
23210
+ }));
23211
+ //#endregion
23212
+ //#region ../theme-core/src/header/generateHeaderCss.ts
23213
+ /**
23214
+ * Generate complete CSS for header system from theme config
23215
+ *
23216
+ * Similar to button system - generates theme-scoped CSS using [data-theme-scope] selector
23217
+ */
23218
+ function generateHeaderCss(options) {
23219
+ const { themeId, theme } = options;
23220
+ const tokens = new TokenResolver(theme);
23221
+ const header = theme.header;
23222
+ const cssChunks = [];
23223
+ const headerContrastTreatment = resolveHeaderContrastTreatment(header);
23224
+ const headerNavTextSize = resolveHeaderNavTextSize(header);
23225
+ cssChunks.push(generateHeaderRootStyles(header, themeId, tokens));
23226
+ cssChunks.push(generateMobileOverlayBackdropFilterFix(themeId, header.variant));
23227
+ cssChunks.push(generateHeaderLogoStyles({
23228
+ logo: header.logo,
23229
+ themeId,
23230
+ tokens,
23231
+ theme,
23232
+ textColor: header.textColor,
23233
+ fallbackTextColor: header.navLinkStyle?.colorToken,
23234
+ contrastTreatment: headerContrastTreatment ?? void 0,
23235
+ useSurfaceTextColor: header.background?.contentOwner === siteChromeBackgroundOverrideOwner
23236
+ }));
23237
+ cssChunks.push(generateLogoTextBehaviorStyles(header.logoText, themeId));
23238
+ cssChunks.push(generateHeaderNavLinkStyles(header, themeId, tokens, theme, headerContrastTreatment, headerNavTextSize));
23239
+ cssChunks.push(generateDropdownContainerStyles(header, themeId, tokens));
23240
+ cssChunks.push(generateDropdownLinkStyles(header, themeId, tokens, theme));
23241
+ cssChunks.push(generateDropdownCaretStyles(themeId));
23242
+ cssChunks.push(generateDropdownTriggerOverrides(header, themeId));
23243
+ cssChunks.push(generateMobilePanelStyles(header, themeId, tokens, theme));
23244
+ if (header.variant === "floating" && header.container) cssChunks.push(generateFloatingContainerStyles(header, themeId, tokens));
23245
+ cssChunks.push(generateNavContainerStyles(header, themeId, tokens));
23246
+ cssChunks.push(generateHeaderCtaTreatmentStyles(header, themeId, tokens));
23247
+ cssChunks.push(generateCtaGapStyles(header, themeId));
23248
+ return cssChunks.filter(Boolean).join("\n\n");
23249
+ }
23250
+ function resolveHeaderContrastTreatment(header) {
23251
+ if (header.navLinkStyle?.contrastTreatment) return header.navLinkStyle.contrastTreatment;
23252
+ return isClearSplitHeaderShape(header) ? "soft-glow" : null;
23253
+ }
23254
+ function resolveHeaderNavTextSize(header) {
23255
+ if (header.navLinkStyle?.textSize) return header.navLinkStyle.textSize;
23256
+ return isClearSplitHeaderShape(header) ? "lg" : null;
23257
+ }
23258
+ function isClearSplitHeaderShape(header) {
23259
+ const hasSharedFloatingSurface = Boolean(header.container);
23260
+ return header.variant === "floating" && (header.navStyle ?? "minimal") === "minimal" && !hasSharedFloatingSurface;
23261
+ }
23262
+ function isDetachedFloatingHeaderShape(header) {
23263
+ return header.variant === "floating" && !header.container;
23264
+ }
23265
+ /**
23266
+ * Generate root header container styles
23267
+ */
23268
+ function generateHeaderRootStyles(header, themeId, tokens) {
23269
+ const selector = `:where([data-theme-scope="${themeId}"]) .header-root`;
23270
+ const rules = [];
23271
+ const isContainedNav = headerRootPaint(header) === "contained-nav";
23272
+ rules.push("position: relative;");
23273
+ rules.push("isolation: isolate;");
23274
+ const surfaceRules = isContainedNav ? {
23275
+ base: [],
23276
+ border: []
23277
+ } : buildHeaderSurfaceRules(header, tokens);
23278
+ const floatingSurfaceBorder = header.variant === "floating";
23279
+ if (!floatingSurfaceBorder) rules.push(...surfaceRules.border);
23280
+ const basePaintRules = floatingSurfaceBorder ? [...surfaceRules.base, ...surfaceRules.border] : surfaceRules.base;
23281
+ const scrolledPaintRules = floatingSurfaceBorder ? surfaceRules.border : [];
23282
+ if (header.positioning === "sticky" || header.positioning === "fixed") {
23283
+ const shadowVar = getComponentShadowVar(header.shadow?.elevation ?? "none");
23284
+ if (shadowVar) rules.push(`box-shadow: ${shadowVar};`);
23285
+ }
23286
+ const baseBlock = `\n${selector} {\n ${rules.join("\n ")}\n}\n`;
23287
+ 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`;
23288
+ const scrollTreatmentStyles = generateHeaderScrollTreatmentStyles(header.scrollTreatment, themeId, header.variant, scrolledPaintRules);
23289
+ if (isContainedNav || basePaintRules.length === 0) return `${baseBlock}\n${overlayFix}${scrollTreatmentStyles}`;
23290
+ return `${baseBlock}\n${renderHeaderPaintTargetRules(getHeaderPaintTargets(header.variant, themeId), basePaintRules)}\n${overlayFix}${scrollTreatmentStyles}`;
23291
+ }
23292
+ function generateLogoTextBehaviorStyles(logoText, themeId) {
23293
+ if (!logoText) return "";
23294
+ const selector = `:where([data-theme-scope="${themeId}"]) .header-logo-text`;
23295
+ const cssChunks = [];
23296
+ const mobileRules = [];
23297
+ if (logoText.mobileWrapLines === 1) {
23298
+ mobileRules.push("display: block;");
23299
+ mobileRules.push("white-space: nowrap;");
23300
+ mobileRules.push("overflow: hidden;");
23301
+ mobileRules.push("text-overflow: ellipsis;");
23302
+ }
23303
+ if (logoText.mobileWrapLines === 2) {
23304
+ mobileRules.push("display: -webkit-box;");
23305
+ mobileRules.push("-webkit-box-orient: vertical;");
23306
+ mobileRules.push("-webkit-line-clamp: 2;");
23307
+ mobileRules.push("white-space: normal;");
23308
+ mobileRules.push("overflow: hidden;");
23309
+ mobileRules.push("text-overflow: ellipsis;");
23310
+ }
23311
+ if (logoText.mobileMaxWidth) mobileRules.push(`max-width: ${{
23312
+ xs: "8rem",
23313
+ sm: "10rem",
23314
+ md: "12rem"
23315
+ }[logoText.mobileMaxWidth]};`);
23316
+ if (mobileRules.length > 0) cssChunks.push(`@media ${MQ_MD_DOWN} {\n ${selector} {\n ${mobileRules.join("\n ")}\n }\n}`);
23317
+ if (logoText.hideOnShrink) {
23318
+ const shrinkSelector = `:where([data-theme-scope="${themeId}"]) .rb-header-shrink.header-scrolled .header-logo-text`;
23319
+ cssChunks.push(`\n${shrinkSelector} {\n display: none;\n}\n`);
23320
+ }
23321
+ return cssChunks.join("\n\n");
23322
+ }
23323
+ /**
23324
+ * Generate dropdown menu container styles
23325
+ */
23326
+ function generateDropdownContainerStyles(header, themeId, tokens) {
23327
+ const selector = `:where([data-theme-scope="${themeId}"]) .nav-dropdown-menu`;
23328
+ const rules = [];
23329
+ const dropdownStyle = header.dropdownStyle;
23330
+ rules.push(...NAV_DROPDOWN_CONTAINER_RAIL_CSS_RULES);
23331
+ const bgToken = dropdownStyle?.background ?? "surface";
23332
+ rules.push(`background-color: ${tokens.getColor(bgToken)};`);
23333
+ const textToken = dropdownStyle?.textColor ?? "text";
23334
+ rules.push(`color: ${tokens.getColor(textToken)};`);
23335
+ const borderToken = dropdownStyle?.borderColor;
23336
+ if (borderToken === null) rules.push(`border: none;`);
23337
+ else rules.push(`border: 1px solid ${tokens.getColor(borderToken ?? "border")};`);
23338
+ const shadowVar = getComponentShadowVar(dropdownStyle?.shadow ?? "md");
23339
+ if (shadowVar) rules.push(`box-shadow: ${shadowVar};`);
23340
+ const borderRadius = dropdownStyle?.borderRadius ?? "md";
23341
+ rules.push(`border-radius: ${{
23342
+ none: "0",
23343
+ sm: "0.25rem",
23344
+ md: "0.5rem",
23345
+ lg: "0.75rem"
23346
+ }[borderRadius]};`);
23347
+ rules.push(`padding: 0.5rem 0;`);
23348
+ return `\n${selector} {\n ${rules.join("\n ")}\n}\n`;
23349
+ }
23350
+ function generateDropdownLinkStyles(header, themeId, tokens, theme) {
23351
+ const configuredDropdownStyle = header.dropdownStyle;
23352
+ const textColorToken = configuredDropdownStyle?.textColor ?? ((header.navColor ?? header.textColor)?.trim() || "text");
23353
+ const hoverBgToken = configuredDropdownStyle?.hoverBackground ?? textColorToken;
23354
+ const hoverEffects = {
23355
+ hover: hoverBgToken === null ? [] : [{
23356
+ effectId: "background-on-hover-alpha",
23357
+ options: {
23358
+ colorToken: hoverBgToken,
23359
+ opacity: 12
23360
+ }
23361
+ }],
23362
+ active: hoverBgToken === null ? [] : [{
23363
+ effectId: "background-on-hover-alpha",
23364
+ options: {
23365
+ colorToken: hoverBgToken,
23366
+ opacity: 18
23367
+ }
23368
+ }]
23369
+ };
23370
+ if (configuredDropdownStyle?.hoverTextColor) {
23371
+ hoverEffects.hover?.push({
23372
+ effectId: "text-color-change",
23373
+ options: { hoverColorToken: configuredDropdownStyle.hoverTextColor }
23374
+ });
23375
+ hoverEffects.active?.push({
23376
+ effectId: "text-color-change",
23377
+ options: { hoverColorToken: configuredDropdownStyle.hoverTextColor }
23378
+ });
23379
+ }
23380
+ const baseCSS = generateNavLinkCSS({
23381
+ themeId,
23382
+ tokens,
23383
+ theme,
23384
+ style: {
23385
+ name: "Dropdown",
23386
+ typography: "body",
23387
+ fontWeight: configuredDropdownStyle?.fontWeight ?? header.navWeight ?? "medium",
23388
+ textTransform: configuredDropdownStyle?.textTransform ?? "none",
23389
+ italic: false,
23390
+ colorToken: textColorToken,
23391
+ padding: "compact",
23392
+ borderRadius: "sm",
23393
+ effects: hoverEffects
23394
+ },
23395
+ className: "nav-dropdown-link"
23396
+ });
23397
+ const additionalRules = [];
23398
+ const letterSpacing = configuredDropdownStyle?.letterSpacing ?? "normal";
23399
+ if (letterSpacing !== "normal") additionalRules.push(`letter-spacing: ${{
23400
+ normal: "0em",
23401
+ wide: "0.05em",
23402
+ wider: "0.1em"
23403
+ }[letterSpacing]};`);
23404
+ const textSize = configuredDropdownStyle?.textSize ?? "sm";
23405
+ additionalRules.push(`font-size: ${{
23406
+ xs: "0.75rem",
23407
+ sm: "0.875rem",
23408
+ base: "1rem",
23409
+ lg: "1.125rem"
23410
+ }[textSize]};`);
23411
+ if (additionalRules.length > 0) return baseCSS + `\n${`:where([data-theme-scope="${themeId}"]) .nav-dropdown-link`} {\n ${additionalRules.join("\n ")}\n}\n`;
23412
+ return baseCSS;
23413
+ }
23414
+ function generateDropdownCaretStyles(themeId) {
23415
+ return `
23416
+ ${`:where([data-theme-scope="${themeId}"]) .nav-caret`} {
23417
+ width: 0.45rem;
23418
+ height: 0.45rem;
23419
+ margin-left: 0.5rem;
23420
+ border-right: 2px solid currentColor;
23421
+ border-bottom: 2px solid currentColor;
23422
+ transform: rotate(45deg) translateY(-1px);
23423
+ transition: transform 150ms ease;
23424
+ }
23425
+
23426
+ ${`: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`} {
23427
+ transform: rotate(-135deg) translateY(1px);
23428
+ }
23429
+ `.trim();
23430
+ }
23431
+ function generateDropdownTriggerOverrides(header, themeId) {
23432
+ const navStyle = header.navStyle ?? "minimal";
23433
+ if (navStyle !== "underline" && navStyle !== "underline-grow") return "";
23434
+ return `
23435
+ ${`:where([data-theme-scope="${themeId}"]) .nav-dropdown-trigger.header-nav-link::after`} {
23436
+ content: none;
23437
+ }
23438
+ `.trim();
23439
+ }
23440
+ /**
23441
+ * Generate mobile navigation panel styles
23442
+ * Uses the same dropdownStyle settings as the desktop dropdown menus
23443
+ */
23444
+ function generateMobilePanelStyles(header, themeId, tokens, theme) {
23445
+ const selector = `:where([data-theme-scope="${themeId}"]) .nav-mobile-panel`;
23446
+ const selfSelector = `:where(.nav-mobile-panel[data-theme-scope="${themeId}"])`;
23447
+ const dropdownStyle = header.dropdownStyle;
23448
+ const bgToken = dropdownStyle?.background ?? "surface";
23449
+ const textToken = dropdownStyle?.textColor ?? "text";
23450
+ const foreground = resolveSurfaceForeground({
23451
+ type: "color",
23452
+ color: bgToken,
23453
+ textColor: textToken
23454
+ }, expandPalette(theme.palette));
23455
+ const body = renderCssDeclarations([`background-color: ${tokens.getColor(bgToken)};`, ...foreground.kind === "known" ? surfaceForegroundDeclarations(surfaceForegroundInputFromResolved(foreground, (token) => tokens.getColor(token))) : [`color: ${tokens.getColor(textToken)};`]]);
23456
+ return `\n${selector} {\n ${body}\n}\n\n${selfSelector} {\n ${body}\n}\n`;
23457
+ }
23458
+ /**
23459
+ * Generate nav container styles (pill/glass)
23460
+ */
23461
+ function generateNavContainerStyles(header, themeId, tokens) {
23462
+ const navContainer = header.navContainer;
23463
+ const navContainerType = navContainer?.type ?? "none";
23464
+ if (!navContainer || navContainerType === "none") return "";
23465
+ const selector = `:where([data-theme-scope="${themeId}"]) .header-nav-row`;
23466
+ const rules = [];
23467
+ if (navContainerType === "pill" || navContainerType === "glass") {
23468
+ rules.push("padding: 0.5rem 0.75rem;");
23469
+ rules.push("border-radius: 9999px;");
23470
+ rules.push("display: inline-flex;");
23471
+ rules.push("align-items: center;");
23472
+ rules.push("gap: 1.5rem;");
23473
+ if (isDetachedFloatingHeaderShape(header)) rules.push("align-self: flex-start;");
23474
+ }
23475
+ if (navContainerType === "glass") {
23476
+ const opacity = resolveFloatingGlassOpacity(header, navContainer.opacity, .15);
23477
+ const background = navContainer.tint ? buildTint(tokens.getColor(navContainer.tint), opacity) : buildRgbWhite(opacity);
23478
+ rules.push(`background-color: ${background};`);
23479
+ rules.push(`backdrop-filter: ${HEADER_BLUR};`);
23480
+ rules.push(`-webkit-backdrop-filter: ${HEADER_BLUR};`);
23481
+ rules.push("border: 1px solid rgba(255, 255, 255, 0.2);");
23482
+ rules.push("box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);");
23483
+ } else if (navContainerType === "pill") {
23484
+ const opacity = clampOpacity(navContainer.opacity, .15);
23485
+ if (navContainer.tint) rules.push(`background-color: ${buildTint(tokens.getColor(navContainer.tint), opacity)};`);
23486
+ else rules.push(`background-color: ${tokens.getColor("surface")};`);
23487
+ rules.push(`border: 1px solid ${tokens.getColor("border")};`);
23488
+ }
23489
+ if (rules.length > 0) return `${selector} { ${rules.join(" ")} }`;
23490
+ return "";
23491
+ }
23492
+ /**
23493
+ * Generate floating container styles
23494
+ */
23495
+ function generateFloatingContainerStyles(header, themeId, tokens) {
23496
+ const container = header.container;
23497
+ if (!container) return "";
23498
+ const selector = `:where([data-theme-scope="${themeId}"]) .header-floating-container`;
23499
+ const rules = [];
23500
+ const opacity = container.tint === "surface" ? resolveFloatingGlassOpacity(header, container.opacity, .12) : clampOpacity(container.opacity, .12);
23501
+ if (container.tint) rules.push(`background-color: ${buildTint(tokens.getColor(container.tint), opacity)};`);
23502
+ else rules.push(`background-color: ${buildRgbWhite(opacity)};`);
23503
+ rules.push(`backdrop-filter: ${FLOATING_BLUR};`);
23504
+ rules.push(`-webkit-backdrop-filter: ${FLOATING_BLUR};`);
23505
+ if (container.border) rules.push(`border: 1px solid rgb(255 255 255 / 0.2);`);
23506
+ rules.push(`border-radius: ${{
23507
+ none: "0",
23508
+ sm: "0.375rem",
23509
+ md: "0.5rem",
23510
+ lg: "0.75rem",
23511
+ xl: "1rem",
23512
+ "2xl": "1.5rem"
23513
+ }[container.rounded]};`);
23514
+ 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);`);
23515
+ rules.push(`padding: ${{
23516
+ sm: "1rem 1.5rem",
23517
+ md: "1.5rem 2rem",
23518
+ lg: "2rem 2.5rem"
23519
+ }[container.padding]};`);
23520
+ return `\n${selector} {\n ${rules.join("\n ")}\n}\n`;
23521
+ }
23522
+ /**
23523
+ * The inverted CTA treatment is contextual to branded header surfaces. It
23524
+ * cannot be represented by the generic secondary button role alone because
23525
+ * that role is transparent and inherits the surrounding surface foreground.
23526
+ * Keep the shared button's structure/effects while making the header own the
23527
+ * palette relationship for both desktop and mobile CTAs.
23528
+ */
23529
+ function generateHeaderCtaTreatmentStyles(header, themeId, tokens) {
23530
+ if (header.ctaTreatment !== "inverted") return "";
23531
+ const desktopSelector = `:where([data-theme-scope="${themeId}"]) .header-cta`;
23532
+ const mobileSelector = `:where([data-theme-scope="${themeId}"]) .nav-mobile-cta`;
23533
+ const selectors = `${desktopSelector},\n${mobileSelector}`;
23534
+ const hoverSelectors = [
23535
+ `${desktopSelector}:hover`,
23536
+ `${desktopSelector}[data-force-hover="true"]`,
23537
+ `${mobileSelector}:hover`,
23538
+ `${mobileSelector}[data-force-hover="true"]`
23539
+ ].join(",\n");
23540
+ const focusSelectors = [`${desktopSelector}:focus-visible`, `${mobileSelector}:focus-visible`].join(",\n");
23541
+ return `
23542
+ ${selectors} {
23543
+ background-color: ${tokens.getColor("background")};
23544
+ background-image: none;
23545
+ color: ${tokens.getColor("onBackground")};
23546
+ border-color: currentColor;
23547
+ }
23548
+
23549
+ ${hoverSelectors} {
23550
+ background-color: ${tokens.getColor("surface")};
23551
+ background-image: none;
23552
+ color: ${tokens.getColor("onSurface")};
23553
+ }
23554
+
23555
+ ${focusSelectors} {
23556
+ outline: 2px solid ${tokens.getColor("onBackground")};
23557
+ outline-offset: 2px;
23558
+ box-shadow: 0 0 0 4px ${tokens.getColor("background")};
23559
+ }
23560
+ `;
23561
+ }
23562
+ /**
23563
+ * Generate CTA button gap styles (left margin between nav links and CTA)
23564
+ */
23565
+ function generateCtaGapStyles(header, themeId) {
23566
+ if (!header.ctaGap) return "";
23567
+ const value = HEADER_CTA_GAP_MAP[header.ctaGap];
23568
+ if (!value) return "";
23569
+ return `\n${`:where([data-theme-scope="${themeId}"]) .header-cta`} {\n margin-left: ${value};\n}\n`;
23570
+ }
23571
+ function clampOpacity(value, fallback) {
23572
+ if (typeof value !== "number" || Number.isNaN(value)) return fallback;
23573
+ return Math.min(Math.max(value, 0), 1);
23574
+ }
23575
+ function resolveFloatingGlassOpacity(header, value, fallback) {
23576
+ const opacity = clampOpacity(value, fallback);
23577
+ return header.variant === "floating" ? Math.max(opacity, .4) : opacity;
23578
+ }
23579
+ function buildTint(color, opacity) {
23580
+ return applyAlpha(color, opacity);
23581
+ }
23582
+ function buildRgbWhite(opacity) {
23583
+ return `rgb(255 255 255 / ${clampOpacity(opacity, 1)})`;
23584
+ }
23585
+ function applyAlpha(color, opacity) {
23586
+ const clamped = clampOpacity(opacity, 1);
23587
+ if (color.startsWith("rgb(") && color.endsWith(")")) {
23588
+ const inner = color.slice(4, -1).trim();
23589
+ return `rgb(${inner.includes("/") ? (inner.split("/")[0] ?? inner).trim() : inner} / ${clamped})`;
23590
+ }
23591
+ return color;
23592
+ }
23593
+ var HEADER_BLUR, FLOATING_BLUR, HEADER_CTA_GAP_MAP;
23594
+ var init_generateHeaderCss = __esmMin((() => {
23595
+ init_resolver$1();
23596
+ init_generateNavLinkCSS();
23597
+ init_shared$4();
23598
+ init_breakpoints();
23599
+ init_navDropdownSizing();
23600
+ init_scrollTreatment();
23601
+ init_paintTargets();
23602
+ init_surfaceRules();
23603
+ init_generateHeaderNavLinkStyles();
23604
+ init_rootPaint();
23605
+ init_rawStyleFields();
23606
+ init_generateHeaderLogoStyles();
23607
+ init_surfaces();
23608
+ init_expandPalette();
23609
+ init_cssDeclarations();
23610
+ HEADER_BLUR = "blur(12px)";
23611
+ FLOATING_BLUR = "blur(16px)";
23612
+ HEADER_CTA_GAP_MAP = {
23613
+ none: "0",
23614
+ tight: "0.5rem",
23615
+ compact: "1rem",
23616
+ default: "1.5rem",
23617
+ relaxed: "2rem",
23618
+ spacious: "3rem"
23619
+ };
23620
+ }));
23621
+ //#endregion
23622
+ //#region ../theme-core/src/header/index.ts
23623
+ var init_header$1 = __esmMin((() => {
23624
+ init_generateHeaderCss();
23625
+ init_rootPaint();
23626
+ init_effectiveNavLinkStyle$1();
23627
+ init_openingForegroundProjection();
23628
+ }));
23629
+ //#endregion
23630
+ //#region ../theme-core/src/footer/effectiveNavLinkStyle.ts
23631
+ function effectiveFooterNavLinkStyle(footer) {
23632
+ if (!footer) return null;
23633
+ if (footer.navLinkStyle) return footer.navLinkStyle;
23634
+ const basePreset = getNavLinkPreset(footer.navStyle ?? "minimal");
23635
+ if (!basePreset) return null;
23636
+ return {
23637
+ ...basePreset,
23638
+ fontWeight: footer.navWeight ?? basePreset.fontWeight,
23639
+ colorToken: footer.navColor?.trim() || basePreset.colorToken
23640
+ };
23641
+ }
23642
+ function footerForegroundCandidates(footer, proseHoverCandidate) {
23643
+ if (!footer) return {};
23644
+ const style = effectiveFooterNavLinkStyle(footer);
23645
+ return {
23646
+ text: footer.background?.textColor,
23647
+ link: style?.colorToken ?? footer.navColor ?? footer.background?.textColor,
23648
+ linkHover: navLinkOwnsHoverForeground(style) ? proseHoverCandidate : navLinkHoverColorCandidate(style)
23649
+ };
23650
+ }
23651
+ var init_effectiveNavLinkStyle = __esmMin((() => {
23652
+ init_presets$1();
23653
+ init_types$9();
23654
+ }));
23655
+ //#endregion
23656
+ //#region ../theme-core/src/footer/generateFooterCss.ts
23657
+ /**
23658
+ * Generate CSS for footer navigation styling
23659
+ *
23660
+ * Similar to header nav but with independent configuration and no advanced effects
23661
+ */
23662
+ function generateFooterCss(options) {
23663
+ const { themeId, theme } = options;
23664
+ const tokens = new TokenResolver(theme);
23665
+ const footer = theme.footer;
23666
+ const cssChunks = [];
23667
+ cssChunks.push(generateFooterNavLinkStyles(footer, themeId, tokens, theme));
23668
+ cssChunks.push(generateFooterLogoStyles(theme, themeId));
23669
+ cssChunks.push(generateFooterBottomTextLinkStyles(footer, themeId, tokens));
23670
+ return cssChunks.filter(Boolean).join("\n\n");
23671
+ }
23672
+ function generateFooterLogoStyles(theme, themeId) {
23673
+ const height = footerLogoHeight(resolveFooterLogoSize(theme.footer, theme.header.logo));
23674
+ return `
23675
+ ${`:where([data-theme-scope="${themeId}"])`} .footer-logo img {
23676
+ width: auto;
23677
+ height: ${height};
23678
+ }
23679
+ `;
23680
+ }
23681
+ function resolveFooterLogoSize(footer, headerLogo) {
23682
+ const brandDrivenSize = footerLogoSizeFromHeaderLogo(headerLogo);
23683
+ return footer.logo?.maxHeight ?? brandDrivenSize ?? footer.logo?.size ?? "md";
23684
+ }
23685
+ function footerLogoSizeFromHeaderLogo(headerLogo) {
23686
+ const size = headerLogo?.size;
23687
+ switch (size) {
23688
+ case "compact": return "sm";
23689
+ case "standard": return "md";
23690
+ case "generous": return "lg";
23691
+ case "display": return "xl";
23692
+ case "auto":
23693
+ case void 0: return null;
23694
+ default: return size;
23695
+ }
23696
+ }
23697
+ function footerLogoHeight(size) {
23698
+ switch (size) {
23699
+ case "sm": return "2.5rem";
23700
+ case "md": return "4rem";
23701
+ case "lg": return "5rem";
23702
+ case "xl": return "6rem";
23703
+ default: return size;
23704
+ }
23705
+ }
23706
+ /**
23707
+ * Generate navigation link styles for footer
23708
+ *
23709
+ * Uses the composable NavLinkStyle system with backward compatibility for
23710
+ * legacy navStyle, navWeight, and navColor settings.
23711
+ */
23712
+ function generateFooterNavLinkStyles(footer, themeId, tokens, theme) {
23713
+ const style = effectiveFooterNavLinkStyle(footer);
23714
+ if (!style) return "";
23715
+ return generateNavLinkCSS({
23716
+ themeId,
23717
+ tokens,
23718
+ theme,
23719
+ style,
23720
+ className: "footer-nav-link",
23721
+ surfaceDependent: true,
23722
+ surfaceRestingColor: footer.background?.contentOwner === siteChromeBackgroundOverrideOwner
23723
+ });
23724
+ }
23725
+ function generateFooterBottomTextLinkStyles(footer, themeId, tokens) {
23726
+ const style = footer.bottomTextLinkStyle;
23727
+ if (!style) return "";
23728
+ const scope = `:where([data-theme-scope="${themeId}"])`;
23729
+ const selectors = [`${scope} .block-site-footer [data-footer-region="bottom"] .rb-prose a`, `${scope} .block-siteFooter [data-footer-region="bottom"] .rb-prose a`];
23730
+ const baseRules = [];
23731
+ const decorationColorToken = style.decorationColorToken?.trim();
23732
+ if (decorationColorToken) baseRules.push(`text-decoration-color: ${tokens.getColor(decorationColorToken)};`);
23733
+ if (style.underline === true) baseRules.push("text-decoration: underline;");
23734
+ else if (style.underline === false) baseRules.push("text-decoration: none;");
23735
+ const cssChunks = [];
23736
+ if (baseRules.length > 0) cssChunks.push(`\n${selectors.join(",\n")} {\n ${baseRules.join("\n ")}\n}\n`);
23737
+ return cssChunks.join("\n");
23738
+ }
23739
+ var init_generateFooterCss = __esmMin((() => {
23740
+ init_resolver$1();
23741
+ init_generateNavLinkCSS();
23742
+ init_effectiveNavLinkStyle();
23743
+ init_rawStyleFields();
23744
+ }));
23745
+ //#endregion
23746
+ //#region ../theme-core/src/footer/index.ts
23747
+ var init_footer = __esmMin((() => {
23748
+ init_generateFooterCss();
23749
+ init_effectiveNavLinkStyle();
23750
+ }));
22461
23751
  function parseBackgroundContent(value) {
22462
23752
  const result = boxBackgroundSchema.safeParse(value);
22463
23753
  return result.success ? result.data : null;
@@ -22479,33 +23769,28 @@ var init_themeColorResolution = __esmMin((() => {
22479
23769
  }));
22480
23770
  //#endregion
22481
23771
  //#region ../blocks/src/system/transforms/registry/_utils/surfaceForegroundStyles.ts
22482
- function resolveHeaderLeafTextColor(header) {
22483
- return header?.textColor ?? header?.navColor ?? header?.background?.textColor ?? header?.navLinkStyle?.colorToken ?? "text";
22484
- }
22485
23772
  function resolveHeaderRootForeground(header, palette, isTransparent) {
22486
- if (isTransparent) return { kind: "unknown" };
23773
+ if (isTransparent) return readOpeningForegroundProjection(header) ?? { kind: "unknown" };
22487
23774
  const background = header?.background;
22488
23775
  return resolveSurfaceForeground(background ?? {
22489
23776
  type: "color",
22490
23777
  color: "surface"
22491
- }, palette, {
22492
- text: header?.textColor ?? background?.textColor,
22493
- link: header?.navLinkStyle?.colorToken ?? header?.navColor ?? header?.textColor
22494
- });
23778
+ }, palette, headerForegroundCandidates(header));
23779
+ }
23780
+ function resolveFooterRootForeground(footer, palette, proseHoverCandidate) {
23781
+ return resolveSurfaceForeground(footer?.background ?? {
23782
+ type: "color",
23783
+ color: "surface"
23784
+ }, palette, footerForegroundCandidates(footer, proseHoverCandidate), { compositeBase: "background" });
22495
23785
  }
22496
23786
  function resolveSurfaceForegroundStyles(value, context, options) {
22497
23787
  const input = parseBackgroundContent(value);
22498
- const foreground = input ? resolveSurfaceForeground(input, context.theme.palette, {}, { compositeBase: options?.fallbackToken }) : { kind: "unknown" };
23788
+ const foreground = input ? resolveSurfaceForeground(input, context.theme.palette, { linkHover: context.proseHoverCandidate }, { compositeBase: options?.fallbackToken }) : { kind: "unknown" };
22499
23789
  const buttonStyles = resolveContextualButtonStyles(input, foreground, context, options);
22500
23790
  if (foreground.kind === "unknown") return buttonStyles;
22501
23791
  return {
22502
23792
  ...buttonStyles,
22503
- ...surfaceForegroundStyle({
22504
- text: resolveBackgroundColorValue(foreground.roles.text, context),
22505
- heading: resolveBackgroundColorValue(foreground.roles.heading, context),
22506
- link: resolveBackgroundColorValue(foreground.roles.link, context),
22507
- supporting: resolveBackgroundColorValue(foreground.roles.supporting, context)
22508
- })
23793
+ ...surfaceForegroundStyle(surfaceForegroundInputFromResolved(foreground, (token) => resolveBackgroundColorValue(token, context)))
22509
23794
  };
22510
23795
  }
22511
23796
  function resolveContextualButtonStyles(background, foreground, context, options) {
@@ -22555,6 +23840,8 @@ function deriveButtonSurfaceInput(background, foreground) {
22555
23840
  var contextualButtonStylesCache;
22556
23841
  var init_surfaceForegroundStyles = __esmMin((() => {
22557
23842
  init_surfaces();
23843
+ init_header$1();
23844
+ init_footer();
22558
23845
  init_buttons();
22559
23846
  init_backgroundContent();
22560
23847
  init_themeColorResolution();
@@ -28949,7 +30236,8 @@ var init_booking_form_reserved_fields = __esmMin((() => {
28949
30236
  "discountCode",
28950
30237
  "selectedSlidingAmountInput",
28951
30238
  "selectedCollectionOptionKind",
28952
- "selectedAppointmentPackageId"
30239
+ "selectedAppointmentPackageId",
30240
+ "mailingListOptIn"
28953
30241
  ];
28954
30242
  BOOKING_FORM_DATA_RESERVED_KEYS = new Set(BOOKING_FORM_DATA_RESERVED_KEY_VALUES);
28955
30243
  }));
@@ -29373,6 +30661,7 @@ function prepareBookingSubmission(input) {
29373
30661
  startAt: selectedSlot,
29374
30662
  endAt: endDate.toISOString(),
29375
30663
  customFields: collectBookingCustomFields(input.data),
30664
+ ...selectedMailingListOptIn(input.data),
29376
30665
  timezone: toBookingTimeZone(input.viewerTimeZone ?? null)
29377
30666
  };
29378
30667
  if (customerPassId) return {
@@ -29423,6 +30712,9 @@ function prepareBookingSubmission(input) {
29423
30712
  }
29424
30713
  };
29425
30714
  }
30715
+ function selectedMailingListOptIn(data) {
30716
+ return data.mailingListOptIn === true ? { mailingListOptIn: true } : {};
30717
+ }
29426
30718
  function formatBookingSubmissionPreparationError(error) {
29427
30719
  switch (error.tag) {
29428
30720
  case "missing-required-booking-information": return "Missing required booking information";
@@ -29568,8 +30860,9 @@ function buildBookingFormInteractiveIslandProps(props) {
29568
30860
  source: props
29569
30861
  });
29570
30862
  }
29571
- var blockBookingPaymentTermsAvailabilitySchema, bookingServiceSchema, bookingServiceCategorySchema, bookingServicesSourceSchema, bookingConfigSchema, bookingSourceSchema, bookingDisplaySchema, bookingHydrationSchema, bookingRenderSchema, bookingFormIslandMetaCodec, bookingFormIslandMetaKeys, bookingFormBlockRuntime, bookingFormInteractiveIslandPropsCodec;
30863
+ var blockBookingPaymentTermsAvailabilitySchema, bookingServiceSchema, bookingServiceCategorySchema, bookingServicesSourceSchema, bookingConfigSchema, bookingMailingListContextSchema, bookingSourceSchema, bookingDisplaySchema, bookingHydrationSchema, bookingRenderSchema, bookingFormIslandMetaCodec, bookingFormIslandMetaKeys, bookingFormBlockRuntime, bookingFormInteractiveIslandPropsCodec;
29572
30864
  var init_booking_form_interactive = __esmMin((() => {
30865
+ init_src$2();
29573
30866
  init_islands();
29574
30867
  init_runtime();
29575
30868
  init_booking_form_state();
@@ -29622,7 +30915,14 @@ var init_booking_form_interactive = __esmMin((() => {
29622
30915
  fields: z$1.array(bookingFieldSchema)
29623
30916
  }).optional()
29624
30917
  });
30918
+ bookingMailingListContextSchema = z$1.unknown().transform((value) => {
30919
+ if (value === void 0) return void 0;
30920
+ const parsed = parseMailingListRuntimeContext(value);
30921
+ return parsed.ok ? parsed.value : void 0;
30922
+ });
29625
30923
  bookingSourceSchema = z$1.object({
30924
+ mailingList: bookingMailingListContextSchema.optional(),
30925
+ siteName: z$1.string().optional(),
29626
30926
  siteId: z$1.string().optional(),
29627
30927
  apiBaseUrl: z$1.string().optional(),
29628
30928
  portalToken: z$1.string().nullable().optional(),
@@ -29651,6 +30951,8 @@ var init_booking_form_interactive = __esmMin((() => {
29651
30951
  message: z$1.string().nullable()
29652
30952
  });
29653
30953
  bookingHydrationSchema = z$1.object({
30954
+ mailingList: bookingMailingListContextSchema.optional(),
30955
+ siteName: z$1.string().optional(),
29654
30956
  formId: z$1.string().nullable(),
29655
30957
  serviceId: z$1.string().nullable(),
29656
30958
  resourceId: z$1.string().nullable(),
@@ -29687,6 +30989,8 @@ var init_booking_form_interactive = __esmMin((() => {
29687
30989
  return {
29688
30990
  display: buildBookingFormDisplay(source, form),
29689
30991
  hydration: {
30992
+ mailingList: source.mailingList,
30993
+ siteName: source.siteName,
29690
30994
  formId: form?.id ?? source.formId ?? null,
29691
30995
  serviceId: source.serviceId ?? form?.settings?.serviceId ?? null,
29692
30996
  resourceId: source.resourceId ?? form?.settings?.resourceId ?? null,
@@ -34706,6 +36010,7 @@ function buildEventRegistrationInteractiveIslandProps(props) {
34706
36010
  }
34707
36011
  var EVENT_REGISTRATION_GENERIC_SHELL_STEP_LABELS, EVENT_REGISTRATION_SHELL_STEP_LABELS, eventRegistrationPublicEventSchema, eventRegistrationHydrationSchemaShape, eventRegistrationEventSourceSchema, eventRegistrationSourceSchema, eventRegistrationDisplaySchema, eventRegistrationHydrationSchema, eventRegistrationRenderSchema, eventRegistrationIslandMetaCodec, eventRegistrationIslandMetaKeys, eventRegistrationBlockRuntime, eventRegistrationInteractiveIslandPropsCodec;
34708
36012
  var init_event_registration_interactive = __esmMin((() => {
36013
+ init_src$2();
34709
36014
  init_readAuthority();
34710
36015
  init_schemas();
34711
36016
  init_runGrouping();
@@ -34745,7 +36050,13 @@ var init_event_registration_interactive = __esmMin((() => {
34745
36050
  spamProtectionEnabled: z$1.boolean().optional(),
34746
36051
  supportEmail: z$1.string().optional(),
34747
36052
  sitePasses: publicPassProductCollectionSchema.nullable().optional(),
34748
- siteMemberships: publicMembershipProductCollectionSchema.nullable().optional()
36053
+ siteMemberships: publicMembershipProductCollectionSchema.nullable().optional(),
36054
+ mailingList: z$1.unknown().transform((value) => {
36055
+ if (value === void 0) return void 0;
36056
+ const parsed = parseMailingListRuntimeContext(value);
36057
+ return parsed.ok ? parsed.value : void 0;
36058
+ }),
36059
+ siteName: z$1.string().optional()
34749
36060
  };
34750
36061
  eventRegistrationEventSourceSchema = z$1.discriminatedUnion("kind", [z$1.object({
34751
36062
  kind: z$1.literal("loaded"),
@@ -34832,7 +36143,9 @@ var init_event_registration_interactive = __esmMin((() => {
34832
36143
  spamProtectionEnabled: source.spamProtectionEnabled,
34833
36144
  supportEmail: source.supportEmail,
34834
36145
  sitePasses: source.sitePasses ?? null,
34835
- siteMemberships: source.siteMemberships ?? null
36146
+ siteMemberships: source.siteMemberships ?? null,
36147
+ mailingList: source.mailingList,
36148
+ siteName: source.siteName
34836
36149
  }
34837
36150
  };
34838
36151
  }
@@ -36695,20 +38008,10 @@ var init_accordion = __esmMin((() => {
36695
38008
  cleanups.forEach((fn) => fn());
36696
38009
  };
36697
38010
  };
36698
- })), NAV_DROPDOWN_SHIFT_PROPERTY, NAV_DROPDOWN_MAX_WIDTH_CSS, NAV_DROPDOWN_CONTAINER_RAIL_CSS_RULES;
36699
- var init_navDropdownSizing = __esmMin((() => {
36700
- NAV_DROPDOWN_SHIFT_PROPERTY = "--nav-dropdown-shift-x";
36701
- NAV_DROPDOWN_MAX_WIDTH_CSS = `min(22rem, calc(100vw - 2rem))`;
36702
- NAV_DROPDOWN_CONTAINER_RAIL_CSS_RULES = [
36703
- `min-width: 12rem;`,
36704
- `width: max-content;`,
36705
- `max-width: ${NAV_DROPDOWN_MAX_WIDTH_CSS};`,
36706
- `transform: translateX(var(${NAV_DROPDOWN_SHIFT_PROPERTY}, 0px));`
36707
- ];
36708
38011
  }));
36709
38012
  //#endregion
36710
38013
  //#region ../blocks/src/system/runtime/nodes/shop-commerce-store.ts
36711
- function storageKey(siteId) {
38014
+ function storageKey$1(siteId) {
36712
38015
  return `riverbank:shop-cart:${siteId}`;
36713
38016
  }
36714
38017
  function getStore(siteId) {
@@ -36742,7 +38045,7 @@ var init_shop_commerce_store = __esmMin((() => {
36742
38045
  constructor(siteId) {
36743
38046
  this.siteId = siteId;
36744
38047
  this.listeners = /* @__PURE__ */ new Set();
36745
- this.state = typeof window === "undefined" ? EMPTY_STATE : parseStoredCommerceCartState(window.localStorage.getItem(storageKey(siteId)));
38048
+ this.state = typeof window === "undefined" ? EMPTY_STATE : parseStoredCommerceCartState(window.localStorage.getItem(storageKey$1(siteId)));
36746
38049
  }
36747
38050
  subscribe(listener) {
36748
38051
  this.listeners.add(listener);
@@ -36796,7 +38099,7 @@ var init_shop_commerce_store = __esmMin((() => {
36796
38099
  }
36797
38100
  setState(nextState) {
36798
38101
  this.state = nextState;
36799
- if (typeof window !== "undefined") window.localStorage.setItem(storageKey(this.siteId), JSON.stringify(nextState));
38102
+ if (typeof window !== "undefined") window.localStorage.setItem(storageKey$1(this.siteId), JSON.stringify(nextState));
36800
38103
  for (const listener of this.listeners) listener();
36801
38104
  }
36802
38105
  };
@@ -98099,121 +99402,6 @@ var init_form = __esmMin((() => {
98099
99402
  };
98100
99403
  }));
98101
99404
  //#endregion
98102
- //#region ../blocks/src/system/runtime/shared/components/CheckIcon.tsx
98103
- function CheckIcon({ className, strokeWidth = 2 }) {
98104
- return /* @__PURE__ */ jsx("svg", {
98105
- fill: "none",
98106
- strokeLinecap: "round",
98107
- strokeLinejoin: "round",
98108
- strokeWidth,
98109
- viewBox: "0 0 24 24",
98110
- stroke: "currentColor",
98111
- className,
98112
- width: "1em",
98113
- height: "1em",
98114
- "aria-hidden": "true",
98115
- children: /* @__PURE__ */ jsx("path", { d: "M5 13l4 4L19 7" })
98116
- });
98117
- }
98118
- var init_CheckIcon$1 = __esmMin((() => {}));
98119
- //#endregion
98120
- //#region ../blocks/src/system/runtime/shared/components/StateIcon.tsx
98121
- /**
98122
- * Circular icon wrapper for terminal state screens (success, error, waitlist, etc.).
98123
- *
98124
- * Layout is provided by shared `rb-state-icon` CSS; color variants are
98125
- * block-scoped by the owning registration surface.
98126
- */
98127
- function StateIcon({ variant, children }) {
98128
- return /* @__PURE__ */ jsx("div", {
98129
- className: `rb-state-icon rb-state-icon--${variant}`,
98130
- "aria-hidden": "true",
98131
- children
98132
- });
98133
- }
98134
- var init_StateIcon = __esmMin((() => {}));
98135
- //#endregion
98136
- //#region ../blocks/src/system/runtime/shared/components/TerminalPanel.tsx
98137
- function joinClasses$4(...parts) {
98138
- return parts.filter((part) => typeof part === "string" && part.length > 0).join(" ");
98139
- }
98140
- function TerminalPanel({ tone, title, titleAs: Title = "h3", body, secondaryBody, icon, actions, className, titleClassName, bodyClassName, secondaryBodyClassName, iconClassName, actionsClassName, role, live }) {
98141
- const resolvedRole = role ?? (tone === "error" ? "alert" : "status");
98142
- const resolvedLive = live ?? (resolvedRole === "alert" ? "assertive" : "polite");
98143
- return /* @__PURE__ */ jsxs("div", {
98144
- className,
98145
- "data-terminal-panel": true,
98146
- "data-terminal-tone": tone,
98147
- role: resolvedRole,
98148
- "aria-live": resolvedLive === "off" ? void 0 : resolvedLive,
98149
- children: [
98150
- icon ? /* @__PURE__ */ jsx("div", {
98151
- className: joinClasses$4(iconClassName),
98152
- "data-terminal-icon": true,
98153
- children: icon
98154
- }) : null,
98155
- /* @__PURE__ */ jsx(Title, {
98156
- className: joinClasses$4(titleClassName),
98157
- "data-terminal-title": true,
98158
- children: title
98159
- }),
98160
- body ? /* @__PURE__ */ jsx("div", {
98161
- className: joinClasses$4(bodyClassName),
98162
- "data-terminal-body": true,
98163
- children: body
98164
- }) : null,
98165
- actions ? /* @__PURE__ */ jsx("div", {
98166
- className: joinClasses$4(actionsClassName),
98167
- "data-terminal-actions": true,
98168
- children: actions
98169
- }) : null,
98170
- secondaryBody ? /* @__PURE__ */ jsx("div", {
98171
- className: joinClasses$4(secondaryBodyClassName),
98172
- "data-terminal-secondary-body": true,
98173
- children: secondaryBody
98174
- }) : null
98175
- ]
98176
- });
98177
- }
98178
- var init_TerminalPanel = __esmMin((() => {}));
98179
- //#endregion
98180
- //#region ../blocks/src/system/runtime/components/booking/SuccessMessage.tsx
98181
- /**
98182
- * SuccessMessage Component
98183
- *
98184
- * Terminal success state after a completed appointment booking.
98185
- * Rendered on the shared registration-surface (see booking-form.client),
98186
- * using the shared TerminalPanel + StateIcon primitives.
98187
- */
98188
- var SuccessMessage;
98189
- var init_SuccessMessage = __esmMin((() => {
98190
- init_CheckIcon$1();
98191
- init_StateIcon();
98192
- init_TerminalPanel();
98193
- SuccessMessage = ({ message, resourceName, className }) => {
98194
- return /* @__PURE__ */ jsx(TerminalPanel, {
98195
- tone: "success",
98196
- title: "Booking confirmed",
98197
- icon: /* @__PURE__ */ jsx(StateIcon, {
98198
- variant: "success",
98199
- children: /* @__PURE__ */ jsx(CheckIcon, { strokeWidth: 3 })
98200
- }),
98201
- body: /* @__PURE__ */ jsx("p", {
98202
- className: "ab-text",
98203
- children: message
98204
- }),
98205
- secondaryBody: resourceName ? /* @__PURE__ */ jsxs("p", {
98206
- className: "ab-text rb-on-surface--muted",
98207
- children: ["Practitioner: ", resourceName]
98208
- }) : null,
98209
- className: ["ab-center", className ?? ""].join(" ").trim(),
98210
- titleClassName: "ab-terminal-title",
98211
- role: "alert",
98212
- live: "polite"
98213
- });
98214
- };
98215
- }));
98216
- //#endregion
98217
99405
  //#region ../blocks/src/system/runtime/hooks/useSelectedAppointmentConsentForm.ts
98218
99406
  function useSelectedAppointmentConsentForm(form, selectedService) {
98219
99407
  return useMemo(() => projectSelectedAppointmentConsentIntoForm(form, resolveSelectedAppointmentConsent(selectedService)), [form, selectedService]);
@@ -98795,6 +99983,7 @@ function useBookingSubmission(_siteId) {
98795
99983
  startAt: data.startAt,
98796
99984
  endAt: data.endAt,
98797
99985
  customFields: data.customFields,
99986
+ mailingListOptIn: data.mailingListOptIn,
98798
99987
  timezone: data.timezone,
98799
99988
  customerPassId: data.customerPassId
98800
99989
  }) : await api.submitBooking({
@@ -98804,6 +99993,7 @@ function useBookingSubmission(_siteId) {
98804
99993
  startAt: data.startAt,
98805
99994
  endAt: data.endAt,
98806
99995
  customFields: data.customFields,
99996
+ mailingListOptIn: data.mailingListOptIn,
98807
99997
  timezone: data.timezone,
98808
99998
  discountCode: data.discountCode,
98809
99999
  selectedSlidingAmount: data.selectedSlidingAmount,
@@ -98844,6 +100034,43 @@ var init_useBookingSubmission = __esmMin((() => {
98844
100034
  init_useBookingSubmission_state();
98845
100035
  }));
98846
100036
  //#endregion
100037
+ //#region ../blocks/src/system/runtime/nodes/booking-form.submit-success.ts
100038
+ function completeBookingSubmission(input) {
100039
+ const { data } = input;
100040
+ if (data.type === "checkout_redirect") {
100041
+ if (input.redirect === "auto" && typeof window !== "undefined") input.navigateToCheckout(data.checkoutUrl);
100042
+ return {
100043
+ ok: true,
100044
+ outcome: {
100045
+ kind: "checkout_redirect",
100046
+ checkoutUrl: data.checkoutUrl,
100047
+ sessionId: data.sessionId,
100048
+ ...data.mailingListSignupNote ? { mailingListSignupNote: data.mailingListSignupNote } : {}
100049
+ }
100050
+ };
100051
+ }
100052
+ input.dispatch({
100053
+ type: "feedback-set",
100054
+ feedback: {
100055
+ kind: "success",
100056
+ message: getBookingSuccessMessage(input.successMessage),
100057
+ resourceName: data.appointment.resourceName
100058
+ }
100059
+ });
100060
+ return {
100061
+ ok: true,
100062
+ outcome: {
100063
+ kind: "booked",
100064
+ appointmentId: data.appointment.id,
100065
+ resourceName: data.appointment.resourceName,
100066
+ ...data.mailingListSignupNote ? { mailingListSignupNote: data.mailingListSignupNote } : {}
100067
+ }
100068
+ };
100069
+ }
100070
+ var init_booking_form_submit_success = __esmMin((() => {
100071
+ init_booking_form_state();
100072
+ }));
100073
+ //#endregion
98847
100074
  //#region ../blocks/src/system/runtime/nodes/event-registration/useDiscountCodeUi.state.ts
98848
100075
  function getDiscountContextKey(context) {
98849
100076
  if (!context) return "disabled";
@@ -99341,6 +100568,43 @@ function clearBookingFieldError(errors, fieldId) {
99341
100568
  }
99342
100569
  var init_booking_form_validationErrors = __esmMin((() => {}));
99343
100570
  //#endregion
100571
+ //#region ../blocks/src/system/runtime/nodes/booking-form.mailing-list-state.ts
100572
+ function bookingFormDataWithEligibleOptIn(data, eligible) {
100573
+ return {
100574
+ ...data,
100575
+ mailingListOptIn: eligible && data.mailingListOptIn === true
100576
+ };
100577
+ }
100578
+ function isBookingContactEvent(event) {
100579
+ return event.type === "field-updated" || event.type === "field-touched" || event.type === "mailing-list-opt-in-set";
100580
+ }
100581
+ function applyBookingContactEvent(state, event) {
100582
+ switch (event.type) {
100583
+ case "field-updated": return {
100584
+ ...state,
100585
+ fieldValues: {
100586
+ ...state.fieldValues,
100587
+ [event.fieldId]: event.value
100588
+ },
100589
+ validationErrors: clearBookingFieldError(clearBookingFormError(state.validationErrors), event.fieldId)
100590
+ };
100591
+ case "field-touched": return {
100592
+ ...state,
100593
+ touchedFields: {
100594
+ ...state.touchedFields,
100595
+ [event.fieldId]: true
100596
+ }
100597
+ };
100598
+ case "mailing-list-opt-in-set": return {
100599
+ ...state,
100600
+ mailingListOptIn: event.checked
100601
+ };
100602
+ }
100603
+ }
100604
+ var init_booking_form_mailing_list_state = __esmMin((() => {
100605
+ init_booking_form_validationErrors();
100606
+ }));
100607
+ //#endregion
99344
100608
  //#region ../blocks/src/system/runtime/nodes/booking-form.field-values.ts
99345
100609
  function collectInitialBookingFieldValues(initialData) {
99346
100610
  const values = {};
@@ -99369,6 +100633,7 @@ function createInitialBookingFlowReducerState(input) {
99369
100633
  selectedDate: toOptionalString(initialData.selectedDate),
99370
100634
  selectedSlot: null,
99371
100635
  fieldValues: collectInitialBookingFieldValues(initialData),
100636
+ mailingListOptIn: initialData.mailingListOptIn === true,
99372
100637
  touchedFields: {},
99373
100638
  attemptedStepIds: {},
99374
100639
  discountCode: toOptionalString(initialData.discountCode) ?? "",
@@ -99418,6 +100683,7 @@ function applyAvailabilitySelectionInvalidation(state, invalidation) {
99418
100683
  };
99419
100684
  }
99420
100685
  function bookingFlowReducer(state, event) {
100686
+ if (isBookingContactEvent(event)) return applyBookingContactEvent(state, event);
99421
100687
  switch (event.type) {
99422
100688
  case "service-selected": return applyBookingServiceSelection(state, event.serviceId);
99423
100689
  case "resource-selected": return {
@@ -99440,21 +100706,6 @@ function bookingFlowReducer(state, event) {
99440
100706
  feedback: clearAvailabilityFeedback(state.feedback),
99441
100707
  validationErrors: clearBookingFormError(state.validationErrors)
99442
100708
  };
99443
- case "field-updated": return {
99444
- ...state,
99445
- fieldValues: {
99446
- ...state.fieldValues,
99447
- [event.fieldId]: event.value
99448
- },
99449
- validationErrors: clearBookingFieldError(clearBookingFormError(state.validationErrors), event.fieldId)
99450
- };
99451
- case "field-touched": return {
99452
- ...state,
99453
- touchedFields: {
99454
- ...state.touchedFields,
99455
- [event.fieldId]: true
99456
- }
99457
- };
99458
100709
  case "step-advance-attempted": return state.attemptedStepIds[event.stepId] ? state : {
99459
100710
  ...state,
99460
100711
  attemptedStepIds: {
@@ -99592,6 +100843,7 @@ function deriveBookingSlotDisplayOptions(input) {
99592
100843
  function toBookingFormData(state) {
99593
100844
  return {
99594
100845
  ...state.fieldValues,
100846
+ mailingListOptIn: state.mailingListOptIn,
99595
100847
  serviceId: state.selectedServiceId,
99596
100848
  resourceId: state.selectedResourceId ?? state.selectedSlot?.resourceId,
99597
100849
  selectedDate: state.selectedDate,
@@ -99854,10 +101106,7 @@ function buildBookingSubmitPlan(input) {
99854
101106
  };
99855
101107
  const prepared = prepareBookingSubmission({
99856
101108
  formId: input.formId,
99857
- data: toBookingFormData({
99858
- ...input.state,
99859
- altchaSolution: input.altchaSolution ?? input.state.altchaSolution
99860
- }),
101109
+ data: bookingFormDataWithEligibleOptIn(toBookingFormData(input.state), Boolean(input.mailingListEligible)),
99861
101110
  services: input.services,
99862
101111
  defaultServiceId: input.defaultServiceId,
99863
101112
  defaultResourceId: input.defaultResourceId,
@@ -100005,6 +101254,7 @@ var init_booking_form_headless_state = __esmMin((() => {
100005
101254
  init_dist$1();
100006
101255
  init_booking_form_state();
100007
101256
  init_booking_form_service_categories();
101257
+ init_booking_form_mailing_list_state();
100008
101258
  init_booking_form_validationErrors();
100009
101259
  init_booking_form_field_values();
100010
101260
  unsafeAsBookingFieldId = (id) => id;
@@ -100058,6 +101308,8 @@ function useHeadlessBookingFlow(options) {
100058
101308
  const canLoadAppointmentPackages = Boolean(options.enableAppointmentPackages && hasPortalBearerAuth && selectedService && !selectedServiceSlidingScale && (selectedService.priceAmount ?? 0) > 0);
100059
101309
  const appointmentPackagesUnavailableReason = !options.enableAppointmentPackages ? "disabled" : !selectedService || selectedServiceSlidingScale || (selectedService.priceAmount ?? 0) <= 0 ? "missing-priced-service" : !hasPortalBearerAuth ? "missing-portal-auth" : null;
100060
101310
  const data = useMemo(() => toBookingFormData(state), [state]);
101311
+ const mailingList = resolveBookingSignupOffer(options.mailingList, options.siteName);
101312
+ const mailingListEligible = mailingList !== null;
100061
101313
  const availabilityDatesQuery = useMemo(() => buildBookingAvailabilityQuery({
100062
101314
  serviceId: selectedServiceId,
100063
101315
  resourceId: selectedResourceId,
@@ -100318,7 +101570,8 @@ function useHeadlessBookingFlow(options) {
100318
101570
  viewerTimeZone: latest.viewerTimeZone,
100319
101571
  redirect: submitOptions?.redirect ?? "manual",
100320
101572
  successUrl: submitOptions?.successUrl,
100321
- cancelUrl: submitOptions?.cancelUrl
101573
+ cancelUrl: submitOptions?.cancelUrl,
101574
+ mailingListEligible
100322
101575
  });
100323
101576
  if (!plan.ok) {
100324
101577
  dispatch({
@@ -100351,37 +101604,18 @@ function useHeadlessBookingFlow(options) {
100351
101604
  message: result.error
100352
101605
  };
100353
101606
  }
100354
- if (result.data.type === "checkout_redirect") {
100355
- if (plan.redirect === "auto" && typeof window !== "undefined") latest.navigateToCheckout(result.data.checkoutUrl);
100356
- return {
100357
- ok: true,
100358
- outcome: {
100359
- kind: "checkout_redirect",
100360
- checkoutUrl: result.data.checkoutUrl
100361
- }
100362
- };
100363
- }
100364
- dispatch({
100365
- type: "feedback-set",
100366
- feedback: {
100367
- kind: "success",
100368
- message: getBookingSuccessMessage(latest.successMessage),
100369
- resourceName: result.data.appointment.resourceName
100370
- }
101607
+ return completeBookingSubmission({
101608
+ data: result.data,
101609
+ redirect: plan.redirect,
101610
+ successMessage: latest.successMessage,
101611
+ navigateToCheckout: latest.navigateToCheckout,
101612
+ dispatch
100371
101613
  });
100372
- return {
100373
- ok: true,
100374
- outcome: {
100375
- kind: "booked",
100376
- appointmentId: result.data.appointment.id,
100377
- resourceName: result.data.appointment.resourceName
100378
- }
100379
- };
100380
101614
  } finally {
100381
101615
  submittingRef.current = false;
100382
101616
  dispatch({ type: "submission-finished" });
100383
101617
  }
100384
- }, [latestRef]);
101618
+ }, [latestRef, mailingListEligible]);
100385
101619
  const actions = useMemo(() => ({
100386
101620
  selectService: (serviceId) => dispatch({
100387
101621
  type: "service-selected",
@@ -100404,6 +101638,10 @@ function useHeadlessBookingFlow(options) {
100404
101638
  fieldId: unsafeAsBookingFieldId(fieldId),
100405
101639
  value
100406
101640
  }),
101641
+ setMailingListOptIn: (checked) => dispatch({
101642
+ type: "mailing-list-opt-in-set",
101643
+ checked
101644
+ }),
100407
101645
  markFieldTouched: (fieldId) => dispatch({
100408
101646
  type: "field-touched",
100409
101647
  fieldId: unsafeAsBookingFieldId(fieldId)
@@ -100562,6 +101800,8 @@ function useHeadlessBookingFlow(options) {
100562
101800
  appointmentPackages: appointmentPackagesModel
100563
101801
  };
100564
101802
  return {
101803
+ mailingList,
101804
+ mailingListOptIn: state.mailingListOptIn,
100565
101805
  status,
100566
101806
  view,
100567
101807
  steps: stepState.steps,
@@ -100661,6 +101901,7 @@ var init_useHeadlessBookingFlow = __esmMin((() => {
100661
101901
  init_useAvailableDates();
100662
101902
  init_useAvailableSlots();
100663
101903
  init_useBookingSubmission();
101904
+ init_booking_form_submit_success();
100664
101905
  init_useDiscountCodeUi();
100665
101906
  init_date_formatting();
100666
101907
  init_bookingPaymentOptions();
@@ -101132,6 +102373,24 @@ var init_TimeSlotSelector = __esmMin((() => {
101132
102373
  };
101133
102374
  }));
101134
102375
  //#endregion
102376
+ //#region ../blocks/src/system/runtime/shared/components/CheckIcon.tsx
102377
+ function CheckIcon({ className, strokeWidth = 2 }) {
102378
+ return /* @__PURE__ */ jsx("svg", {
102379
+ fill: "none",
102380
+ strokeLinecap: "round",
102381
+ strokeLinejoin: "round",
102382
+ strokeWidth,
102383
+ viewBox: "0 0 24 24",
102384
+ stroke: "currentColor",
102385
+ className,
102386
+ width: "1em",
102387
+ height: "1em",
102388
+ "aria-hidden": "true",
102389
+ children: /* @__PURE__ */ jsx("path", { d: "M5 13l4 4L19 7" })
102390
+ });
102391
+ }
102392
+ var init_CheckIcon$1 = __esmMin((() => {}));
102393
+ //#endregion
101135
102394
  //#region ../blocks/src/system/runtime/shared/components/StepIndicator.tsx
101136
102395
  function buildClassChannels(slot, classPrefix, emitSharedClasses) {
101137
102396
  const classes = [];
@@ -101516,6 +102775,28 @@ var init_BookingConsentAgreement = __esmMin((() => {
101516
102775
  init_RichText();
101517
102776
  }));
101518
102777
  //#endregion
102778
+ //#region ../blocks/src/system/runtime/nodes/booking-form.mailing-list-choice.tsx
102779
+ function BookingMailingListChoice({ booking }) {
102780
+ const id = React.useId();
102781
+ if (!booking.mailingList) return null;
102782
+ return /* @__PURE__ */ jsxs("div", {
102783
+ className: "rb-space-y-2",
102784
+ children: [/* @__PURE__ */ jsx(CheckboxChoice, {
102785
+ id,
102786
+ name: "mailingListOptIn",
102787
+ checked: booking.mailingListOptIn,
102788
+ onChange: (event) => booking.actions.setMailingListOptIn(event.target.checked),
102789
+ label: `Email me news and updates from ${booking.mailingList.siteName}.`
102790
+ }), /* @__PURE__ */ jsx("p", {
102791
+ className: "rb-caption status-muted",
102792
+ children: "Optional. You can unsubscribe at any time."
102793
+ })]
102794
+ });
102795
+ }
102796
+ var init_booking_form_mailing_list_choice = __esmMin((() => {
102797
+ init_CheckboxChoice();
102798
+ }));
102799
+ //#endregion
101519
102800
  //#region ../blocks/src/system/runtime/nodes/booking-form.service-choices.tsx
101520
102801
  function optionCardClassName(isSelected) {
101521
102802
  return `rb-option-card${isSelected ? " rb-option-card--selected" : ""}`;
@@ -102000,12 +103281,17 @@ function PaymentOptionContent({ description, helperText, id, summaryRows, title
102000
103281
  });
102001
103282
  }
102002
103283
  function DefaultDynamicFields({ booking, fields }) {
103284
+ const lastContactIndex = fields.reduce((last, field, index) => [
103285
+ "name",
103286
+ "email",
103287
+ "phone"
103288
+ ].includes(field.id) ? index : last, -1);
102003
103289
  return /* @__PURE__ */ jsx("div", {
102004
103290
  className: "rb-space-y-6",
102005
- children: fields.map((field) => /* @__PURE__ */ jsx(DefaultDynamicField, {
103291
+ children: fields.map((field, index) => /* @__PURE__ */ jsxs(React.Fragment, { children: [/* @__PURE__ */ jsx(DefaultDynamicField, {
102006
103292
  booking,
102007
103293
  field
102008
- }, field.id))
103294
+ }), index === lastContactIndex && booking.mailingList ? /* @__PURE__ */ jsx(BookingMailingListChoice, { booking }) : null] }, field.id))
102009
103295
  });
102010
103296
  }
102011
103297
  function DefaultDynamicField({ booking, field }) {
@@ -102289,6 +103575,7 @@ var init_booking_form_default_ui = __esmMin((() => {
102289
103575
  init_DiscountCodeDisclosure();
102290
103576
  init_FieldValidationMessage();
102291
103577
  init_BookingConsentAgreement();
103578
+ init_booking_form_mailing_list_choice();
102292
103579
  init_CheckboxChoice();
102293
103580
  init_booking_form_service_choices();
102294
103581
  }));
@@ -102494,12 +103781,12 @@ function CrossIcon({ className, strokeWidth = 2 }) {
102494
103781
  var init_CrossIcon = __esmMin((() => {}));
102495
103782
  //#endregion
102496
103783
  //#region ../blocks/src/system/runtime/shared/components/ActionRow.tsx
102497
- function joinClasses$3(...parts) {
103784
+ function joinClasses$4(...parts) {
102498
103785
  return parts.filter((part) => typeof part === "string" && part.length > 0).join(" ");
102499
103786
  }
102500
103787
  function ActionRow({ children, className, align = "start" }) {
102501
103788
  return /* @__PURE__ */ jsx("div", {
102502
- className: joinClasses$3("rb-flex rb-flex-wrap rb-items-center rb-gap-2", alignmentClasses[align], className),
103789
+ className: joinClasses$4("rb-flex rb-flex-wrap rb-items-center rb-gap-2", alignmentClasses[align], className),
102503
103790
  "data-action-row": true,
102504
103791
  children
102505
103792
  });
@@ -102536,6 +103823,22 @@ function LoggedInAsUser({ email, onLogout, classPrefix }) {
102536
103823
  });
102537
103824
  }
102538
103825
  var init_LoggedInAsUser = __esmMin((() => {}));
103826
+ //#endregion
103827
+ //#region ../blocks/src/system/runtime/shared/components/StateIcon.tsx
103828
+ /**
103829
+ * Circular icon wrapper for terminal state screens (success, error, waitlist, etc.).
103830
+ *
103831
+ * Layout is provided by shared `rb-state-icon` CSS; color variants are
103832
+ * block-scoped by the owning registration surface.
103833
+ */
103834
+ function StateIcon({ variant, children }) {
103835
+ return /* @__PURE__ */ jsx("div", {
103836
+ className: `rb-state-icon rb-state-icon--${variant}`,
103837
+ "aria-hidden": "true",
103838
+ children
103839
+ });
103840
+ }
103841
+ var init_StateIcon = __esmMin((() => {}));
102539
103842
  var init_MembershipHero$1 = __esmMin((() => {
102540
103843
  init_FeedbackMessage();
102541
103844
  }));
@@ -102594,6 +103897,50 @@ var init_TabBarFragment = __esmMin((() => {
102594
103897
  init_clsx();
102595
103898
  }));
102596
103899
  //#endregion
103900
+ //#region ../blocks/src/system/runtime/shared/components/TerminalPanel.tsx
103901
+ function joinClasses$3(...parts) {
103902
+ return parts.filter((part) => typeof part === "string" && part.length > 0).join(" ");
103903
+ }
103904
+ function TerminalPanel({ tone, title, titleAs: Title = "h3", body, secondaryBody, icon, actions, className, titleClassName, bodyClassName, secondaryBodyClassName, iconClassName, actionsClassName, role, live }) {
103905
+ const resolvedRole = role ?? (tone === "error" ? "alert" : "status");
103906
+ const resolvedLive = live ?? (resolvedRole === "alert" ? "assertive" : "polite");
103907
+ return /* @__PURE__ */ jsxs("div", {
103908
+ className,
103909
+ "data-terminal-panel": true,
103910
+ "data-terminal-tone": tone,
103911
+ role: resolvedRole,
103912
+ "aria-live": resolvedLive === "off" ? void 0 : resolvedLive,
103913
+ children: [
103914
+ icon ? /* @__PURE__ */ jsx("div", {
103915
+ className: joinClasses$3(iconClassName),
103916
+ "data-terminal-icon": true,
103917
+ children: icon
103918
+ }) : null,
103919
+ /* @__PURE__ */ jsx(Title, {
103920
+ className: joinClasses$3(titleClassName),
103921
+ "data-terminal-title": true,
103922
+ children: title
103923
+ }),
103924
+ body ? /* @__PURE__ */ jsx("div", {
103925
+ className: joinClasses$3(bodyClassName),
103926
+ "data-terminal-body": true,
103927
+ children: body
103928
+ }) : null,
103929
+ actions ? /* @__PURE__ */ jsx("div", {
103930
+ className: joinClasses$3(actionsClassName),
103931
+ "data-terminal-actions": true,
103932
+ children: actions
103933
+ }) : null,
103934
+ secondaryBody ? /* @__PURE__ */ jsx("div", {
103935
+ className: joinClasses$3(secondaryBodyClassName),
103936
+ "data-terminal-secondary-body": true,
103937
+ children: secondaryBody
103938
+ }) : null
103939
+ ]
103940
+ });
103941
+ }
103942
+ var init_TerminalPanel = __esmMin((() => {}));
103943
+ //#endregion
102597
103944
  //#region ../blocks/src/system/runtime/shared/components/SelectableOptionCard.tsx
102598
103945
  function SelectableOptionCard(props) {
102599
103946
  const { baseClassName, selectedClassName, disabledClassName, iconClassName, labelClassName, detailClassName, icon, label, detail, selected, disabled, tooltip, extraClassNames = [], onClick, renderCheck, renderDisabledTooltip } = props;
@@ -102657,6 +104004,140 @@ var init_shared = __esmMin((() => {
102657
104004
  init_components();
102658
104005
  }));
102659
104006
  //#endregion
104007
+ //#region ../blocks/src/system/runtime/components/booking/SuccessMessage.tsx
104008
+ /**
104009
+ * SuccessMessage Component
104010
+ *
104011
+ * Terminal success state after a completed appointment booking.
104012
+ * Rendered on the shared registration-surface (see booking-form.client),
104013
+ * using the shared TerminalPanel + StateIcon primitives.
104014
+ */
104015
+ var SuccessMessage;
104016
+ var init_SuccessMessage = __esmMin((() => {
104017
+ init_CheckIcon$1();
104018
+ init_StateIcon();
104019
+ init_TerminalPanel();
104020
+ SuccessMessage = ({ message, resourceName, className }) => {
104021
+ return /* @__PURE__ */ jsx(TerminalPanel, {
104022
+ tone: "success",
104023
+ title: "Booking confirmed",
104024
+ icon: /* @__PURE__ */ jsx(StateIcon, {
104025
+ variant: "success",
104026
+ children: /* @__PURE__ */ jsx(CheckIcon, { strokeWidth: 3 })
104027
+ }),
104028
+ body: /* @__PURE__ */ jsx("p", {
104029
+ className: "ab-text",
104030
+ children: message
104031
+ }),
104032
+ secondaryBody: resourceName ? /* @__PURE__ */ jsxs("p", {
104033
+ className: "ab-text rb-on-surface--muted",
104034
+ children: ["Practitioner: ", resourceName]
104035
+ }) : null,
104036
+ className: ["ab-center", className ?? ""].join(" ").trim(),
104037
+ titleClassName: "ab-terminal-title",
104038
+ role: "alert",
104039
+ live: "polite"
104040
+ });
104041
+ };
104042
+ }));
104043
+ //#endregion
104044
+ //#region ../blocks/src/system/runtime/shared/mailingListSignupCopy.ts
104045
+ function getBookingMailingListNoteCopy(note, context) {
104046
+ if (note === "confirmation_required") return {
104047
+ title: MAILING_LIST_CONFIRMATION_MESSAGE,
104048
+ detail: context === "booking" ? "This is separate from your booking confirmation." : null
104049
+ };
104050
+ return {
104051
+ title: "We couldn’t confirm your mailing-list signup.",
104052
+ detail: context === "booking" ? "This does not affect your booking." : null
104053
+ };
104054
+ }
104055
+ var MAILING_LIST_CONFIRMATION_MESSAGE;
104056
+ var init_mailingListSignupCopy = __esmMin((() => {
104057
+ MAILING_LIST_CONFIRMATION_MESSAGE = "Please check your inbox to confirm your signup.";
104058
+ }));
104059
+ //#endregion
104060
+ //#region ../blocks/src/system/runtime/shared/components/BookingMailingListNote.tsx
104061
+ function BookingMailingListNote(props) {
104062
+ const copy = getBookingMailingListNoteCopy(props.note, props.context);
104063
+ return /* @__PURE__ */ jsxs("div", {
104064
+ role: "status",
104065
+ className: props.className,
104066
+ children: [/* @__PURE__ */ jsx("p", { children: copy.title }), copy.detail ? /* @__PURE__ */ jsx("p", { children: copy.detail }) : null]
104067
+ });
104068
+ }
104069
+ var init_BookingMailingListNote = __esmMin((() => {
104070
+ init_mailingListSignupCopy();
104071
+ }));
104072
+ //#endregion
104073
+ //#region ../blocks/src/system/runtime/nodes/booking-form.mailing-list-note.ts
104074
+ function storageKey(sessionId) {
104075
+ return `riverbank:booking:mailing-list:${sessionId}`;
104076
+ }
104077
+ function saveAppointmentMailingListNote(sessionId, note) {
104078
+ if (!note) return;
104079
+ try {
104080
+ window.sessionStorage.setItem(storageKey(sessionId), note);
104081
+ } catch {}
104082
+ }
104083
+ function readAppointmentMailingListNote(sessionId) {
104084
+ try {
104085
+ const stored = window.sessionStorage.getItem(storageKey(sessionId));
104086
+ return stored === "confirmation_required" || stored === "not_confirmed" ? stored : null;
104087
+ } catch {
104088
+ return null;
104089
+ }
104090
+ }
104091
+ var init_booking_form_mailing_list_note = __esmMin((() => {}));
104092
+ //#endregion
104093
+ //#region ../blocks/src/system/runtime/nodes/booking-form.completion.tsx
104094
+ function BookingFormCompletion({ resourceName, successMessage, redirectState, localNote }) {
104095
+ const note = redirectState.kind === "success" ? readAppointmentMailingListNote(redirectState.sessionId) : localNote;
104096
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(SuccessMessage, {
104097
+ message: getBookingSuccessMessage(successMessage),
104098
+ resourceName
104099
+ }), note ? /* @__PURE__ */ jsx(BookingMailingListNote, {
104100
+ note,
104101
+ context: "booking",
104102
+ className: "rb-mt-4"
104103
+ }) : null] });
104104
+ }
104105
+ var init_booking_form_completion = __esmMin((() => {
104106
+ init_SuccessMessage();
104107
+ init_BookingMailingListNote();
104108
+ init_booking_form_state();
104109
+ init_booking_form_mailing_list_note();
104110
+ }));
104111
+ //#endregion
104112
+ //#region ../blocks/src/system/runtime/nodes/booking-form.submit-handler.ts
104113
+ function appendRebookFlag(url, enabled) {
104114
+ if (!enabled) return url;
104115
+ const nextUrl = new URL(url);
104116
+ nextUrl.searchParams.set("rebook", "1");
104117
+ return nextUrl.toString();
104118
+ }
104119
+ function createBookingFormSubmitHandler(input) {
104120
+ return async () => {
104121
+ const { successUrl, cancelUrl } = buildCheckoutReturnUrls("booking", input.bookingAnchorId);
104122
+ const result = await input.booking.actions.submit({
104123
+ redirect: "manual",
104124
+ successUrl: appendRebookFlag(successUrl, input.isPortalRebook),
104125
+ cancelUrl: appendRebookFlag(cancelUrl, input.isPortalRebook)
104126
+ });
104127
+ if (!result.ok) return;
104128
+ if (result.outcome.kind === "checkout_redirect") {
104129
+ saveAppointmentMailingListNote(result.outcome.sessionId, result.outcome.mailingListSignupNote);
104130
+ window.location.href = result.outcome.checkoutUrl;
104131
+ return;
104132
+ }
104133
+ input.setLocalMailingListNote(result.outcome.mailingListSignupNote ?? null);
104134
+ };
104135
+ }
104136
+ var init_booking_form_submit_handler = __esmMin((() => {
104137
+ init_shared();
104138
+ init_booking_form_mailing_list_note();
104139
+ }));
104140
+ //#endregion
102660
104141
  //#region ../blocks/src/system/runtime/nodes/booking-form.client.tsx
102661
104142
  function getBookingRedirectLocationSnapshot() {
102662
104143
  if (typeof window === "undefined") return {
@@ -102668,12 +104149,6 @@ function getBookingRedirectLocationSnapshot() {
102668
104149
  hash: window.location.hash
102669
104150
  };
102670
104151
  }
102671
- function appendRebookFlag(url, enabled) {
102672
- if (!enabled) return url;
102673
- const nextUrl = new URL(url);
102674
- nextUrl.searchParams.set(PORTAL_REBOOK_QUERY_PARAM, PORTAL_REBOOK_QUERY_VALUE);
102675
- return nextUrl.toString();
102676
- }
102677
104152
  /**
102678
104153
  * Themed surface container for every booking view state (wizard, success,
102679
104154
  * verifying). Styled by the shared registration-surface layer.
@@ -102685,12 +104160,11 @@ function BookingSurface({ id, className, children }) {
102685
104160
  children
102686
104161
  });
102687
104162
  }
102688
- var PORTAL_REBOOK_QUERY_PARAM, PORTAL_REBOOK_QUERY_VALUE, REBOOK_COMPLETION_MODE_VERIFIED_CHECKOUT, REBOOK_COMPLETION_MODE_BYPASSED, BookingFormClient;
104163
+ var REBOOK_COMPLETION_MODE_VERIFIED_CHECKOUT, REBOOK_COMPLETION_MODE_BYPASSED, BookingFormClient;
102689
104164
  var init_booking_form_client = __esmMin((() => {
102690
104165
  init_noop();
102691
104166
  init_client();
102692
104167
  init_api$1();
102693
- init_SuccessMessage();
102694
104168
  init_useHeadlessBookingFlow();
102695
104169
  init_useAppointmentCheckoutVerification();
102696
104170
  init_booking_form_state();
@@ -102698,9 +104172,9 @@ var init_booking_form_client = __esmMin((() => {
102698
104172
  init_booking_form_interactive();
102699
104173
  init_shared();
102700
104174
  init_FeedbackMessage();
104175
+ init_booking_form_completion();
104176
+ init_booking_form_submit_handler();
102701
104177
  init_date_formatting();
102702
- PORTAL_REBOOK_QUERY_PARAM = "rebook";
102703
- PORTAL_REBOOK_QUERY_VALUE = "1";
102704
104178
  REBOOK_COMPLETION_MODE_VERIFIED_CHECKOUT = "verified_checkout";
102705
104179
  REBOOK_COMPLETION_MODE_BYPASSED = "bypassed";
102706
104180
  BookingFormClient = ({ siteId: siteIdProp, render }) => {
@@ -102714,12 +104188,16 @@ var init_booking_form_client = __esmMin((() => {
102714
104188
  const isPortalRebook = render.hydration.rebookContext?.kind === "portal_rebook";
102715
104189
  const hasLoggedRebookCompletionRef = useRef(false);
102716
104190
  const [redirectState] = useState(() => getBookingRedirectStateFromLocation(getBookingRedirectLocationSnapshot()));
104191
+ const [localMailingListNote, setLocalMailingListNote] = useState(null);
102717
104192
  const showSpamProtection = render.hydration.spamProtectionEnabled ?? isSpamProtectionEnabled();
102718
104193
  const api = useBlockApi();
102719
104194
  const hasPortalAuth = api.config.auth.type === "bearer" || api.config.authOverrides?.portal?.type === "bearer";
104195
+ const formId = render.hydration.formId ?? form?.id ?? "booking-form";
102720
104196
  const booking = useHeadlessBookingFlow({
104197
+ mailingList: render.hydration.mailingList,
104198
+ siteName: render.hydration.siteName,
102721
104199
  siteId,
102722
- formId: render.hydration.formId ?? form?.id ?? "booking-form",
104200
+ formId,
102723
104201
  form,
102724
104202
  services,
102725
104203
  serviceCategories: render.hydration.serviceCategories,
@@ -102789,22 +104267,20 @@ var init_booking_form_client = __esmMin((() => {
102789
104267
  children: render.display.message ?? "Booking form not found. Please check your configuration."
102790
104268
  })
102791
104269
  });
102792
- const handleComplete = async () => {
102793
- const { successUrl, cancelUrl } = buildCheckoutReturnUrls("booking", bookingAnchorId);
102794
- const result = await booking.actions.submit({
102795
- redirect: "manual",
102796
- successUrl: appendRebookFlag(successUrl, isPortalRebook),
102797
- cancelUrl: appendRebookFlag(cancelUrl, isPortalRebook)
102798
- });
102799
- if (!result.ok) return;
102800
- if (result.outcome.kind === "checkout_redirect") window.location.href = result.outcome.checkoutUrl;
102801
- };
104270
+ const handleComplete = createBookingFormSubmitHandler({
104271
+ booking,
104272
+ bookingAnchorId,
104273
+ isPortalRebook,
104274
+ setLocalMailingListNote
104275
+ });
102802
104276
  if (viewState.kind === "success") return /* @__PURE__ */ jsx(BookingSurface, {
102803
104277
  id: bookingAnchorId,
102804
104278
  className: render.display.className,
102805
- children: /* @__PURE__ */ jsx(SuccessMessage, {
102806
- message: getBookingSuccessMessage(render.display.successMessage),
102807
- resourceName: viewState.resourceName
104279
+ children: /* @__PURE__ */ jsx(BookingFormCompletion, {
104280
+ successMessage: render.display.successMessage,
104281
+ resourceName: viewState.resourceName,
104282
+ redirectState,
104283
+ localNote: localMailingListNote
102808
104284
  })
102809
104285
  });
102810
104286
  if (viewState.kind === "verifying") return /* @__PURE__ */ jsx(BookingSurface, {
@@ -103604,7 +105080,8 @@ function createInitialRegistrationFormData() {
103604
105080
  email: "",
103605
105081
  phone: "",
103606
105082
  notes: "",
103607
- consentAccepted: false
105083
+ consentAccepted: false,
105084
+ mailingListOptIn: false
103608
105085
  };
103609
105086
  }
103610
105087
  function validateFormData(formData, requiresConsent = false) {
@@ -104969,7 +106446,10 @@ async function handleCheckoutReturn(options, deps, returnContextRef) {
104969
106446
  }
104970
106447
  const { checkoutAttemptId } = command;
104971
106448
  const pending = deps.getPendingRegistration(siteId, checkoutAttemptId);
104972
- returnContextRef.current = { checkoutAttemptId };
106449
+ returnContextRef.current = {
106450
+ checkoutAttemptId,
106451
+ mailingListSignupNote: pending?.mailingListSignupNote
106452
+ };
104973
106453
  if (pending) restorePendingPresentation(options, pending);
104974
106454
  options.setStep("verifying-payment");
104975
106455
  try {
@@ -104990,7 +106470,10 @@ function completeVerifiedRegistration(options, deps, returnContext) {
104990
106470
  const siteId = options.api.config.siteId;
104991
106471
  const checkoutAttemptId = returnContext?.checkoutAttemptId;
104992
106472
  if (siteId && checkoutAttemptId) deps.clearPendingRegistration(siteId, checkoutAttemptId);
104993
- options.setRegistrationResult({ status: "confirmed" });
106473
+ options.setRegistrationResult({
106474
+ status: "confirmed",
106475
+ mailingListSignupNote: returnContext?.mailingListSignupNote
106476
+ });
104994
106477
  options.setStep("success");
104995
106478
  }
104996
106479
  function useEventRegistrationStripeReturnWithDeps(options, deps) {
@@ -105097,6 +106580,9 @@ var init_registrationErrorPresentation = __esmMin((() => {
105097
106580
  }));
105098
106581
  //#endregion
105099
106582
  //#region ../blocks/src/system/runtime/nodes/event-registration/useEventRegistrationSubmit.ts
106583
+ function wantsMailingListSignup(options) {
106584
+ return options.mailingListSignup !== null && options.formData.mailingListOptIn === true;
106585
+ }
105100
106586
  function createClientCommandId(cryptoSource = {
105101
106587
  randomUUID: globalThis.crypto.randomUUID?.bind(globalThis.crypto),
105102
106588
  getRandomValues: (bytes) => globalThis.crypto.getRandomValues(bytes)
@@ -105190,7 +106676,8 @@ async function completeRegistrationSubmission(options, deps, prepared, result, s
105190
106676
  case "paymentStatusRequired":
105191
106677
  options.setPaymentStatusRecovery({
105192
106678
  kind: "ready",
105193
- subject: result.subject
106679
+ subject: result.subject,
106680
+ mailingListSignupNote: result.mailingListSignupNote
105194
106681
  });
105195
106682
  options.setStep("payment-status");
105196
106683
  return {
@@ -105199,14 +106686,15 @@ async function completeRegistrationSubmission(options, deps, prepared, result, s
105199
106686
  };
105200
106687
  case "checkoutRequired":
105201
106688
  options.setPendingRegistrationReference(result.reference);
105202
- savePendingCheckout(options, deps, prepared, result.submissionId, result.reference);
106689
+ savePendingCheckout(options, deps, prepared, result.submissionId, result.reference, result.mailingListSignupNote);
105203
106690
  options.setStep("redirecting");
105204
106691
  return redirectToCheckout(result.checkoutUrl, submitOptions);
105205
106692
  case "waitlisted":
105206
106693
  options.setRegistrationResult({
105207
106694
  status: "waitlist",
105208
106695
  title: "Added to waitlist",
105209
- message: result.waitlist.message
106696
+ message: result.waitlist.message,
106697
+ mailingListSignupNote: result.mailingListSignupNote
105210
106698
  });
105211
106699
  break;
105212
106700
  case "bookingComplete":
@@ -105214,7 +106702,8 @@ async function completeRegistrationSubmission(options, deps, prepared, result, s
105214
106702
  options.setPendingRegistrationReference(result.reference);
105215
106703
  options.setRegistrationResult({
105216
106704
  status: "confirmed",
105217
- message: result.summary.paymentMethod === "pass" ? result.summary.message : void 0
106705
+ message: result.summary.paymentMethod === "pass" ? result.summary.message : void 0,
106706
+ mailingListSignupNote: result.mailingListSignupNote
105218
106707
  });
105219
106708
  break;
105220
106709
  }
@@ -105273,7 +106762,7 @@ function resolveSelectionSnapshot(method, passId, membershipId, bundleProductId,
105273
106762
  if (method === "free") return { method };
105274
106763
  throw new Error("Choose an available payment option.");
105275
106764
  }
105276
- function savePendingCheckout(options, deps, prepared, checkoutAttemptId, reference) {
106765
+ function savePendingCheckout(options, deps, prepared, checkoutAttemptId, reference, mailingListSignupNote) {
105277
106766
  const siteId = options.api.config.siteId;
105278
106767
  if (!siteId) return;
105279
106768
  deps.savePendingRegistration(siteId, checkoutAttemptId, {
@@ -105282,7 +106771,8 @@ function savePendingCheckout(options, deps, prepared, checkoutAttemptId, referen
105282
106771
  ticketSelections: prepared.ticketSelections,
105283
106772
  selectedEventId: options.registrationTarget?.selectedEventId ?? null,
105284
106773
  selectedAttendanceMode: options.selectedAttendanceMode,
105285
- paymentSelection: prepared.selectionSnapshot
106774
+ paymentSelection: prepared.selectionSnapshot,
106775
+ mailingListSignupNote
105286
106776
  });
105287
106777
  }
105288
106778
  function redirectToCheckout(checkoutUrl, submitOptions) {
@@ -105296,7 +106786,7 @@ function redirectToCheckout(checkoutUrl, submitOptions) {
105296
106786
  };
105297
106787
  }
105298
106788
  function registrationRequestIntentKey(request) {
105299
- const { registrationCommandId: _command, altchaSolution: _proof, checkout, ...intent } = request;
106789
+ const { registrationCommandId: _command, altchaSolution: _proof, mailingListOptIn: _marketingConsent, checkout, ...intent } = request;
105300
106790
  return JSON.stringify({
105301
106791
  ...intent,
105302
106792
  checkout: checkout ? {
@@ -105321,6 +106811,7 @@ function buildRegistrationRequest(options, prepared, method, passId, membershipI
105321
106811
  phone: options.formData.phone.trim() || void 0,
105322
106812
  notes: options.formData.notes.trim() || void 0,
105323
106813
  consentAccepted: options.formData.consentAccepted,
106814
+ mailingListOptIn: wantsMailingListSignup(options),
105324
106815
  altchaSolution: options.altchaSolution,
105325
106816
  paymentMethod: method,
105326
106817
  customerPassId: method === "pass" ? passId : void 0,
@@ -105581,13 +107072,17 @@ function isCheckableRecovery(state) {
105581
107072
  function assistanceRequired(recovery) {
105582
107073
  return {
105583
107074
  kind: "assistanceRequired",
105584
- subject: recovery.subject
107075
+ subject: recovery.subject,
107076
+ mailingListSignupNote: recovery.mailingListSignupNote
105585
107077
  };
105586
107078
  }
105587
107079
  function applyStatusOutcome(outcome, recovery, setters, setRecovery) {
105588
107080
  if (outcome.kind === "resolved") {
105589
107081
  setters.setPendingRegistrationReference(outcome.reference);
105590
- setters.setRegistrationResult({ status: "confirmed" });
107082
+ setters.setRegistrationResult({
107083
+ status: "confirmed",
107084
+ mailingListSignupNote: recovery.mailingListSignupNote
107085
+ });
105591
107086
  setRecovery(null);
105592
107087
  setters.setStep("success");
105593
107088
  return;
@@ -105708,6 +107203,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
105708
107203
  const paymentSelection = flowState.paymentSelection;
105709
107204
  const [selectedEvent, setSelectedEvent] = useState(preSelectedEvent ?? null);
105710
107205
  const [formData, setFormData] = useState(createInitialRegistrationFormData);
107206
+ const mailingListSignup = resolveBookingSignupOffer(options.mailingList, options.siteName);
105711
107207
  const [errors, setErrors] = useState({});
105712
107208
  const [guests, setGuests] = useState([]);
105713
107209
  const [guestErrors, setGuestErrors] = useState({});
@@ -106154,6 +107650,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
106154
107650
  ticketSelections,
106155
107651
  selectedSlidingAmount,
106156
107652
  formData,
107653
+ mailingListSignup,
106157
107654
  altchaSolution,
106158
107655
  requireGuestDetails,
106159
107656
  guests,
@@ -106250,6 +107747,7 @@ function useEventRegistrationWizardWithDeps(options, deps) {
106250
107747
  hasValidTicketSelection,
106251
107748
  eventRequiresPayment,
106252
107749
  formData,
107750
+ mailingListSignup,
106253
107751
  setFormData,
106254
107752
  errors,
106255
107753
  guests,
@@ -107753,6 +109251,24 @@ function NotesField({ id, onChange, value }) {
107753
109251
  })]
107754
109252
  });
107755
109253
  }
109254
+ function MailingListOptInField({ signup, formData, onChange }) {
109255
+ if (!signup) return null;
109256
+ return /* @__PURE__ */ jsxs("div", {
109257
+ className: "er-field",
109258
+ children: [/* @__PURE__ */ jsx(CheckboxChoice, {
109259
+ checked: formData.mailingListOptIn === true,
109260
+ onChange: (event) => onChange({
109261
+ ...formData,
109262
+ mailingListOptIn: event.target.checked
109263
+ }),
109264
+ label: `Email me news and updates from ${signup.siteName}.`,
109265
+ presentation: "row"
109266
+ }), /* @__PURE__ */ jsx("p", {
109267
+ className: "er-text er-text--muted",
109268
+ children: "Optional. You can unsubscribe at any time."
109269
+ })]
109270
+ });
109271
+ }
107756
109272
  var AttendeeDetailsStep;
107757
109273
  var init_AttendeeDetailsStep = __esmMin((() => {
107758
109274
  init_GuestDetailsSection();
@@ -107760,7 +109276,7 @@ var init_AttendeeDetailsStep = __esmMin((() => {
107760
109276
  init_FieldValidationMessage();
107761
109277
  init_BookingConsentAgreement();
107762
109278
  init_CheckboxChoice();
107763
- AttendeeDetailsStep = ({ formData, onChange, errors, emailLocked = false, onLogout, ticketsCount = 1, requireGuestDetails = false, guests = [], onGuestsChange, guestErrors = {}, guestSectionShake = false, onGuestShakeEnd, consent }) => {
109279
+ AttendeeDetailsStep = ({ formData, onChange, errors, emailLocked = false, onLogout, ticketsCount = 1, requireGuestDetails = false, guests = [], onGuestsChange, guestErrors = {}, guestSectionShake = false, onGuestShakeEnd, consent, mailingListSignup }) => {
107764
109280
  const idBase = useId();
107765
109281
  const nameId = `${idBase}-name`;
107766
109282
  const emailId = `${idBase}-email`;
@@ -107869,6 +109385,11 @@ var init_AttendeeDetailsStep = __esmMin((() => {
107869
109385
  placeholder: "(optional)"
107870
109386
  })]
107871
109387
  }),
109388
+ /* @__PURE__ */ jsx(MailingListOptInField, {
109389
+ signup: mailingListSignup,
109390
+ formData,
109391
+ onChange
109392
+ }),
107872
109393
  /* @__PURE__ */ jsx(NotesField, {
107873
109394
  id: notesId,
107874
109395
  value: formData.notes,
@@ -108317,7 +109838,8 @@ var init_PaymentSelectionStep = __esmMin((() => {
108317
109838
  var SuccessStep;
108318
109839
  var init_SuccessStep = __esmMin((() => {
108319
109840
  init_shared();
108320
- SuccessStep = ({ title, message, variant = "success" }) => {
109841
+ init_BookingMailingListNote();
109842
+ SuccessStep = ({ title, message, variant = "success", mailingListSignupNote, context = "booking" }) => {
108321
109843
  return /* @__PURE__ */ jsx(TerminalPanel, {
108322
109844
  tone: variant === "info" ? "info" : "success",
108323
109845
  className: "er-center",
@@ -108358,7 +109880,11 @@ var init_SuccessStep = __esmMin((() => {
108358
109880
  })
108359
109881
  }),
108360
109882
  title: title ?? (variant === "info" ? "Already Registered" : "Registration Confirmed!"),
108361
- body: message
109883
+ body: message,
109884
+ secondaryBody: mailingListSignupNote ? /* @__PURE__ */ jsx(BookingMailingListNote, {
109885
+ note: mailingListSignupNote,
109886
+ context
109887
+ }) : void 0
108362
109888
  });
108363
109889
  };
108364
109890
  }));
@@ -108562,7 +110088,8 @@ function AttendeeDetailsContent(props) {
108562
110088
  guestErrors: wizard.guestErrors,
108563
110089
  guestSectionShake: wizard.guestSectionShake,
108564
110090
  onGuestShakeEnd: wizard.handleGuestShakeEnd,
108565
- consent: (wizard.selectedEvent ?? wizard.preSelectedEvent)?.consent ?? null
110091
+ consent: (wizard.selectedEvent ?? wizard.preSelectedEvent)?.consent ?? null,
110092
+ mailingListSignup: wizard.mailingListSignup
108566
110093
  }),
108567
110094
  props.showSpamProtection && /* @__PURE__ */ jsx("div", {
108568
110095
  className: "er-altcha",
@@ -108743,6 +110270,10 @@ function PaymentStatusStep(props) {
108743
110270
  "aria-atomic": "true",
108744
110271
  children: props.state.kind === "checking" ? "Checking payment…" : view.title
108745
110272
  })] }),
110273
+ secondaryBody: props.state.mailingListSignupNote ? /* @__PURE__ */ jsx(BookingMailingListNote, {
110274
+ note: props.state.mailingListSignupNote,
110275
+ context: "booking"
110276
+ }) : void 0,
108746
110277
  actionsClassName: "er-button-group",
108747
110278
  actions: view.action ? /* @__PURE__ */ jsx("button", {
108748
110279
  type: "button",
@@ -108755,6 +110286,7 @@ function PaymentStatusStep(props) {
108755
110286
  }
108756
110287
  var init_PaymentStatusStep = __esmMin((() => {
108757
110288
  init_shared();
110289
+ init_BookingMailingListNote();
108758
110290
  }));
108759
110291
  //#endregion
108760
110292
  //#region ../blocks/src/system/runtime/nodes/event-registration/EventRegistrationSurface.tsx
@@ -108848,11 +110380,10 @@ function EventRegistrationTerminalState(props) {
108848
110380
  onReturnToPayment: wizard.handleReturnToPayment,
108849
110381
  onReturnToBooking: wizard.handleReturnToBooking
108850
110382
  }) : null;
108851
- case "success": return wizard.registrationResult ? /* @__PURE__ */ jsx(SuccessStep, {
108852
- title: wizard.registrationResult.title,
108853
- variant: wizard.registrationResult.variant,
108854
- message: wizard.registrationResult.message ?? props.successMessage
108855
- }) : null;
110383
+ case "success": return /* @__PURE__ */ jsx(EventRegistrationSuccess, {
110384
+ wizard,
110385
+ fallbackMessage: props.successMessage
110386
+ });
108856
110387
  case "error": return /* @__PURE__ */ jsx(ErrorStep, {
108857
110388
  message: wizard.errorMessage,
108858
110389
  action: wizard.errorAction,
@@ -108865,6 +110396,17 @@ function EventRegistrationTerminalState(props) {
108865
110396
  case "select-payment": return null;
108866
110397
  }
108867
110398
  }
110399
+ function EventRegistrationSuccess(props) {
110400
+ const result = props.wizard.registrationResult;
110401
+ if (!result) return null;
110402
+ return /* @__PURE__ */ jsx(SuccessStep, {
110403
+ title: result.title,
110404
+ variant: result.variant,
110405
+ message: result.message ?? props.fallbackMessage,
110406
+ mailingListSignupNote: result.mailingListSignupNote,
110407
+ context: result.status === "waitlist" ? "waitlist" : "booking"
110408
+ });
110409
+ }
108868
110410
  function EventRegistrationSurface(props) {
108869
110411
  const { wizard } = props;
108870
110412
  const mainRef = useRef(null);
@@ -109067,19 +110609,23 @@ function getWizardStepLabel(input) {
109067
110609
  case "payment-failed": return "";
109068
110610
  }
109069
110611
  }
110612
+ function useConfiguredEventRegistrationWizard(props) {
110613
+ return useEventRegistrationWizard({
110614
+ anchorId: EVENT_REGISTRATION_ANCHOR_ID,
110615
+ occurrenceContext: props.occurrenceContext ?? null,
110616
+ subject: props.subject ?? null,
110617
+ events: props.events ?? [],
110618
+ maxTicketsNum: normalizeEventRegistrationMaxTickets(props.maxTickets ?? "5"),
110619
+ mailingList: props.mailingList,
110620
+ siteName: props.siteName
110621
+ });
110622
+ }
109070
110623
  function EventRegistrationWizard(props) {
109071
- 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;
109072
- const maxTicketsNum = normalizeEventRegistrationMaxTickets(maxTickets);
110624
+ 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;
109073
110625
  const showSpamProtection = spamProtectionEnabled ?? isSpamProtectionEnabled();
109074
110626
  const registrationRootClassName = `event-registration ${className || ""}`;
109075
110627
  const registrationRootRef = React.useRef(null);
109076
- const wizard = useEventRegistrationWizard({
109077
- anchorId: EVENT_REGISTRATION_ANCHOR_ID,
109078
- occurrenceContext: occurrenceContext ?? null,
109079
- subject: subject ?? null,
109080
- events: events ?? [],
109081
- maxTicketsNum
109082
- });
110628
+ const wizard = useConfiguredEventRegistrationWizard(props);
109083
110629
  useEventCheckoutHandoffRestore(wizard.step === "redirecting");
109084
110630
  const [bookingOverlayOpen, setBookingOverlayOpen] = useState(false);
109085
110631
  const [floatingPortalRoot, setFloatingPortalRoot] = useState(null);
@@ -115908,7 +117454,7 @@ function NewsletterFormClient({ render }) {
115908
117454
  tone: "success",
115909
117455
  className: "fb-success",
115910
117456
  role: "status",
115911
- children: getNewsletterSuccessOutcome(submissionState) === "confirmation_required" ? "Please check your inbox to confirm your signup." : render.display.successMessage
117457
+ children: getNewsletterSuccessOutcome(submissionState) === "confirmation_required" ? MAILING_LIST_CONFIRMATION_MESSAGE : render.display.successMessage
115912
117458
  })
115913
117459
  });
115914
117460
  if (render.display.availability === "unavailable") return /* @__PURE__ */ jsx(UnavailableNewsletterForm, { className: render.display.className });
@@ -116064,6 +117610,7 @@ var init_newsletter_form_client = __esmMin((() => {
116064
117610
  init_api$1();
116065
117611
  init_src$2();
116066
117612
  init_FeedbackMessage();
117613
+ init_mailingListSignupCopy();
116067
117614
  init_newsletter_form_parts();
116068
117615
  init_newsletter_form_client_state();
116069
117616
  init_newsletter_form_submission();
@@ -116916,6 +118463,8 @@ init_colorStyles();
116916
118463
  init_surfaces();
116917
118464
  init_siteChromePlacement();
116918
118465
  init_runtimeContract();
118466
+ init_header$1();
118467
+ init_site_styles();
116919
118468
  init_surfaceForegroundStyles();
116920
118469
  const joinClasses$2 = (parts) => parts.filter((part) => typeof part === "string" && part.trim().length > 0).join(" ").replace(/\s+/g, " ").trim();
116921
118470
  function resolveHeaderBrandDisplay(logo) {
@@ -117021,10 +118570,7 @@ function resolveBackgroundVisualStyles(backgroundColor, defaultToken = "surface"
117021
118570
  };
117022
118571
  }
117023
118572
  function resolveHeaderVisualStyles(header) {
117024
- const navContainerType = header?.navContainer?.type ?? "none";
117025
- const hasContainedNav = navContainerType === "glass" || navContainerType === "pill";
117026
- const hasOverlayVariant = header?.variant === "floating";
117027
- if (hasContainedNav || hasOverlayVariant) return {
118573
+ if (headerRootPaint(header) !== "own-surface") return {
117028
118574
  backgroundToken: "transparent",
117029
118575
  isTransparent: true
117030
118576
  };
@@ -117035,23 +118581,7 @@ function resolveHeaderVisualStyles(header) {
117035
118581
  }
117036
118582
  function resolvedForegroundStyle(foreground) {
117037
118583
  if (foreground.kind === "unknown") return void 0;
117038
- const { roles } = foreground;
117039
- return surfaceForegroundStyle({
117040
- text: rgbColorValue(roles.text),
117041
- heading: rgbColorValue(roles.heading),
117042
- link: rgbColorValue(roles.link),
117043
- supporting: rgbColorValue(roles.supporting)
117044
- });
117045
- }
117046
- function resolveFooterRootForeground(footer, palette) {
117047
- const background = footer?.background;
117048
- return resolveSurfaceForeground(background ?? {
117049
- type: "color",
117050
- color: "surface"
117051
- }, palette, {
117052
- text: background?.textColor,
117053
- link: footer?.navLinkStyle?.colorToken ?? footer?.navColor ?? background?.textColor
117054
- });
118584
+ return surfaceForegroundStyle(surfaceForegroundInputFromResolved(foreground, rgbColorValue));
117055
118585
  }
117056
118586
  function footerBottomBarBorderWidthStyle(width) {
117057
118587
  if (!width) return void 0;
@@ -117078,8 +118608,7 @@ const headerRootClassTransform = {
117078
118608
  const placement = planSiteChromePlacement(parseHeaderPositioning(content.positioning));
117079
118609
  const header = asPartialObject(value);
117080
118610
  const visuals = resolveHeaderVisualStyles(header);
117081
- const navContainerType = header?.navContainer?.type ?? "none";
117082
- const hasContainedNav = navContainerType === "glass" || navContainerType === "pill";
118611
+ const hasContainedNav = headerRootPaint(header) === "contained-nav";
117083
118612
  const backgroundClass = visuals.isTransparent || hasContainedNav ? "rb-bg-transparent" : null;
117084
118613
  const classes = [config.base, backgroundClass];
117085
118614
  if (!hasContainedNav) {
@@ -117122,7 +118651,7 @@ const headerRootStyleTransform = {
117122
118651
  run: (value, _options, context) => {
117123
118652
  const header = asPartialObject(value);
117124
118653
  const visuals = resolveHeaderVisualStyles(header);
117125
- return mergeStyles(resolvedForegroundStyle(resolveHeaderRootForeground(header, context.theme.palette, visuals.isTransparent)) ?? { color: rgbColorValue(resolveHeaderLeafTextColor(header)) }, borderColorStyle(header?.border?.colorToken ?? "border"));
118654
+ 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"));
117126
118655
  }
117127
118656
  };
117128
118657
  const headerSectionBackgroundTransform = {
@@ -117130,9 +118659,7 @@ const headerSectionBackgroundTransform = {
117130
118659
  kind: "string",
117131
118660
  summary: "Resolve the inner site-header section background token",
117132
118661
  run: (value) => {
117133
- const header = asPartialObject(value);
117134
- const navContainerType = header?.navContainer?.type ?? "none";
117135
- return header?.variant === "floating" || navContainerType === "glass" || navContainerType === "pill" ? "raw:transparent" : "background";
118662
+ return headerRootPaint(asPartialObject(value)) !== "own-surface" ? "raw:transparent" : "background";
117136
118663
  }
117137
118664
  };
117138
118665
  const footerRootStyleTransform = {
@@ -117150,7 +118677,7 @@ const footerRootStyleTransform = {
117150
118677
  styleParts.push(backgroundColorStyle(token));
117151
118678
  }
117152
118679
  }
117153
- styleParts.push(resolvedForegroundStyle(resolveFooterRootForeground(footer, context.theme.palette)));
118680
+ styleParts.push(resolvedForegroundStyle(resolveFooterRootForeground(footer, context.theme.palette, context.proseHoverCandidate)));
117154
118681
  styleParts.push(borderColorStyle("border"));
117155
118682
  return mergeStyles(...styleParts);
117156
118683
  }
@@ -117212,22 +118739,28 @@ const footerBottomBarStyleTransform = {
117212
118739
  run: (value, _options, context) => {
117213
118740
  const footer = asPartialObject(value);
117214
118741
  const bottomBar = footer?.bottomBar;
117215
- const styleParts = [];
117216
- const background = bottomBar?.background;
117217
- if (background?.type === "color") styleParts.push(backgroundColorStyle(background.color ?? "surface"));
117218
- styleParts.push(borderColorStyle(bottomBar?.borderTop?.colorToken ?? "border"), footerBottomBarBorderWidthStyle(bottomBar?.borderTop?.width));
117219
- const foreground = resolveSurfaceForeground(background?.type === "color" ? background : {
117220
- type: "color",
117221
- color: "transparent"
117222
- }, context.theme.palette, {
117223
- text: bottomBar?.textColor,
117224
- link: footer?.bottomTextLinkStyle?.colorToken ?? bottomBar?.textColor
117225
- });
117226
- if (background?.type === "color") styleParts.push(resolvedForegroundStyle(foreground));
117227
- else if (bottomBar?.textColor) styleParts.push(textColorStyle(bottomBar.textColor));
117228
- return mergeStyles(...styleParts);
118742
+ 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));
117229
118743
  }
117230
118744
  };
118745
+ function footerBottomBarForegroundStyle(footer, palette) {
118746
+ if (!footer?.bottomBar) return void 0;
118747
+ const bar = footer.bottomBar;
118748
+ if (bar.background?.type !== "color") return backgroundlessBottomBarForegroundStyle(footer);
118749
+ return resolvedForegroundStyle(resolveSurfaceForeground(bar.background, palette, {
118750
+ text: bar.textColor,
118751
+ link: footer.bottomTextLinkStyle?.colorToken ?? bar.textColor,
118752
+ linkHover: footer.bottomTextLinkStyle?.hoverColorToken
118753
+ }, { compositeBase: measuredFooterBackdrop(footer, palette) }));
118754
+ }
118755
+ function backgroundlessBottomBarForegroundStyle(footer) {
118756
+ if (footer.background?.contentOwner === "site-chrome-editor") return;
118757
+ const textColor = footer.bottomBar?.textColor;
118758
+ return textColor ? textColorStyle(textColor) : void 0;
118759
+ }
118760
+ function measuredFooterBackdrop(footer, palette) {
118761
+ const foreground = resolveFooterRootForeground(footer, palette);
118762
+ return foreground.kind === "known" && foreground.provenance.kind === "measured" ? foreground.provenance.backdropHex : null;
118763
+ }
117231
118764
  const footerSplitMainClassTransform = {
117232
118765
  id: "layout.footerSplitMainClass",
117233
118766
  kind: "string",
@@ -117315,6 +118848,7 @@ const layoutTransforms = [
117315
118848
  init_surfaces();
117316
118849
  init_core$1();
117317
118850
  init_surfaceForegroundStyles();
118851
+ init_header$1();
117318
118852
  const chromeLogoSchema = z$1.object({ surface: z$1.enum([
117319
118853
  "header-root",
117320
118854
  "header-mobile-panel",
@@ -117326,7 +118860,7 @@ function chromeSurfaceTextToken(surface, theme, palette) {
117326
118860
  case "header-root": {
117327
118861
  const header = theme.header;
117328
118862
  const foreground = resolveHeaderRootForeground(header, palette, resolveHeaderVisualStyles(header).isTransparent);
117329
- return foreground.kind === "known" ? foreground.roles.text : resolveHeaderLeafTextColor(header);
118863
+ return foreground.kind === "known" ? foreground.roles.text : headerLeafTextColor(header);
117330
118864
  }
117331
118865
  case "header-mobile-panel": return theme.header?.dropdownStyle?.textColor ?? "text";
117332
118866
  case "footer-root": {
@@ -120110,34 +121644,15 @@ init_booking_form_interactive();
120110
121644
  * own `.rb-reg-surface`, and leaves no stale loading state on the mounted form.
120111
121645
  * `event-registration.server.tsx` follows the same shape.
120112
121646
  */
120113
- function BookingFormSSR({ blockId, siteId, apiBaseUrl, portalToken, formId, serviceId, resourceId, initialData, noticeMessage, requiresServiceSelection, requiresResourceSelection, shouldAutoSelectSingleResource, rebookContext, submitLabel, successMessage, form, services, spamProtectionEnabled, className, children }) {
120114
- const islandProps = buildBookingFormInteractiveIslandProps({
120115
- siteId,
120116
- apiBaseUrl,
120117
- portalToken,
120118
- formId,
120119
- serviceId,
120120
- resourceId,
120121
- initialData,
120122
- noticeMessage,
120123
- requiresServiceSelection,
120124
- requiresResourceSelection,
120125
- shouldAutoSelectSingleResource,
120126
- rebookContext,
120127
- submitLabel,
120128
- successMessage,
120129
- form,
120130
- services,
120131
- spamProtectionEnabled,
120132
- className
120133
- });
121647
+ function BookingFormSSR({ blockId, children, ...sourceProps }) {
121648
+ const islandProps = buildBookingFormInteractiveIslandProps(sourceProps);
120134
121649
  const display = islandProps.render.display;
120135
121650
  return /* @__PURE__ */ jsxs("div", {
120136
121651
  ...getIslandRootProps("booking-form", blockId),
120137
121652
  children: [
120138
121653
  /* @__PURE__ */ jsx(IslandPropsScript, { value: islandProps }),
120139
121654
  display.state === "missing" ? /* @__PURE__ */ jsx("div", {
120140
- className: `rb-reg-surface booking-form-ssr ${className ?? ""}`.trim(),
121655
+ className: `rb-reg-surface booking-form-ssr ${sourceProps.className ?? ""}`.trim(),
120141
121656
  children: /* @__PURE__ */ jsx("div", {
120142
121657
  className: "alert alert-error",
120143
121658
  role: "alert",
@@ -120147,7 +121662,7 @@ function BookingFormSSR({ blockId, siteId, apiBaseUrl, portalToken, formId, serv
120147
121662
  })
120148
121663
  })
120149
121664
  }) : /* @__PURE__ */ jsxs("div", {
120150
- className: `rb-reg-surface booking-form-ssr ab-shell ${className ?? ""}`.trim(),
121665
+ className: `rb-reg-surface booking-form-ssr ab-shell ${sourceProps.className ?? ""}`.trim(),
120151
121666
  "aria-busy": true,
120152
121667
  "aria-label": "Loading booking form",
120153
121668
  role: "status",
@@ -122056,6 +123571,8 @@ const eventRegistrationBlockDefinition = {
122056
123571
  events: { $bind: { from: "data.events" } },
122057
123572
  wholeSeriesRunEvents: { $bind: { from: "data.wholeSeriesRunEvents" } },
122058
123573
  loaderFailures: { $bind: { from: "$root.loaderFailures" } },
123574
+ mailingList: { $bind: { from: "$root.mailingList" } },
123575
+ siteName: { $bind: { from: "$root.siteName" } },
122059
123576
  sitePasses: { $bind: { from: "data.sitePasses" } },
122060
123577
  siteMemberships: { $bind: { from: "data.siteMemberships" } },
122061
123578
  stage: { $bind: {
@@ -123815,18 +125332,11 @@ const newsletterSignupManifest = createBlockManifest({
123815
125332
  ],
123816
125333
  icon: "Mail"
123817
125334
  });
125335
+ const newsletterPublicFieldIds = [...(newsletterSignupManifest.fields ?? []).map((field) => field.id), "_containerStyles"];
123818
125336
  function sanitizeNewsletterSignupPublicContent(content) {
123819
125337
  if (typeof content !== "object" || content === null || Array.isArray(content)) return content;
123820
125338
  const value = content;
123821
- return {
123822
- title: value.title,
123823
- subtitle: value.subtitle,
123824
- targeting: value.targeting,
123825
- buttonVariant: value.buttonVariant,
123826
- mailingListSource: value.mailingListSource,
123827
- mailingListSourceToken: value.mailingListSourceToken,
123828
- _sectionStyles: value._sectionStyles
123829
- };
125339
+ return Object.fromEntries(newsletterPublicFieldIds.map((id) => [id, value[id]]));
123830
125340
  }
123831
125341
  const newsletterSignupBlockDefinition = {
123832
125342
  manifest: newsletterSignupManifest,
@@ -125802,6 +127312,7 @@ function applyTransformsAndFallback(value, binding, context) {
125802
127312
  options: step.options
125803
127313
  })) ?? [], {
125804
127314
  theme: context.theme ?? defaultThemeTokens,
127315
+ proseHoverCandidate: context.proseHoverCandidate,
125805
127316
  stage,
125806
127317
  data: resolveTransformData(context, binding.from),
125807
127318
  routes: routeMap,
@@ -126718,6 +128229,8 @@ init_types$12();
126718
128229
  init_constants$1();
126719
128230
  init_colorStyles();
126720
128231
  init_surfaces();
128232
+ init_expandPalette();
128233
+ init_cssDeclarations();
126721
128234
  /**
126722
128235
  * Corner radius map for accordion surfaces. Pill is capped here because FAQ
126723
128236
  * rows contain long text and expanded content; full capsules clip awkwardly.
@@ -126750,14 +128263,7 @@ function generateAccordionCss({ themeId, theme, accordionSystem }) {
126750
128263
  const questionColumnsItemSelector = `${rootSelector}.rb-faq-question-columns .accordion-item`;
126751
128264
  const questionColumnsLastItemSelector = `${questionColumnsItemSelector}:last-child`;
126752
128265
  const questionColumnsTriggerSelector = `${questionColumnsItemSelector} .accordion-trigger`;
126753
- const rootRules = [];
126754
- if (accordionSystem.background) {
126755
- rootRules.push(`background-color: ${rgbColorValue(accordionSystem.background.colorToken)}`);
126756
- rootRules.push(...surfaceForegroundDeclarations({
126757
- text: rgbColorValue(accordionSystem.content.textColorToken),
126758
- heading: rgbColorValue(accordionSystem.trigger.textColorToken)
126759
- }));
126760
- }
128266
+ const rootRules = accordionSurfaceRules(theme, accordionSystem);
126761
128267
  const borderRadius = CORNER_MAP$2[accordionSystem.corners ?? theme.corners];
126762
128268
  rootRules.push(`border-radius: ${borderRadius}`);
126763
128269
  if (accordionSystem.border) {
@@ -126876,7 +128382,7 @@ function generateAccordionCss({ themeId, theme, accordionSystem }) {
126876
128382
  }
126877
128383
  }
126878
128384
  const cssBlocks = [];
126879
- cssBlocks.push(`${rootSelector} {\n ${rootRules.join(";\n ")};\n}`);
128385
+ cssBlocks.push(`${rootSelector} {\n ${renderCssDeclarations(rootRules)}\n}`);
126880
128386
  cssBlocks.push(`${itemSelector} {\n ${itemRules.join(";\n ")};\n}`);
126881
128387
  cssBlocks.push(`${itemSelector}.accordion-item {\n border-radius: ${borderRadius};\n}`);
126882
128388
  cssBlocks.push(`${lastItemSelector} {\n ${lastItemRules.join(";\n ")};\n}`);
@@ -126897,6 +128403,16 @@ function generateAccordionCss({ themeId, theme, accordionSystem }) {
126897
128403
  if (iconRotateBlock.length > 0) cssBlocks.push(...iconRotateBlock);
126898
128404
  return cssBlocks.join("\n\n");
126899
128405
  }
128406
+ function accordionSurfaceRules(theme, system) {
128407
+ if (!system.background) return [];
128408
+ const foreground = resolveSurfaceForeground({
128409
+ type: "color",
128410
+ color: system.background.colorToken,
128411
+ textColor: system.content.textColorToken,
128412
+ headingColor: system.trigger.textColorToken
128413
+ }, expandPalette(theme.palette), { linkHover: theme.typography.proseLinkStyle?.hoverColorToken });
128414
+ return [`background-color: ${rgbColorValue(system.background.colorToken)}`, ...surfaceForegroundDeclarations(foreground.kind === "known" ? surfaceForegroundInputFromResolved(foreground, rgbColorValue) : { text: rgbColorValue(system.content.textColorToken) })];
128415
+ }
126900
128416
  //#endregion
126901
128417
  //#region ../theme-core/src/accordions/defaults.ts
126902
128418
  init_curatedSiteStyles();
@@ -127454,944 +128970,6 @@ function generateDefaultInputSystem(theme) {
127454
128970
  };
127455
128971
  }
127456
128972
  //#endregion
127457
- //#region ../theme-core/src/navigation/generateNavLinkCSS.ts
127458
- init_types$9();
127459
- init_expandPalette();
127460
- init_colorConversion();
127461
- init_generateBaseCSS();
127462
- init_generateEffectsCSS();
127463
- /**
127464
- * Generate complete CSS for nav links from a NavLinkStyle configuration
127465
- */
127466
- function generateNavLinkCSS(options) {
127467
- const { themeId, tokens, theme, style, className } = options;
127468
- const selector = `:where([data-theme-scope="${themeId}"]) .${className}`;
127469
- const hoverSelector = `${selector}:hover`;
127470
- const activeSelector = `${selector}:active, ${selector}[data-active="true"]`;
127471
- const cssChunks = [];
127472
- const hoverRules = [];
127473
- const activeRules = [];
127474
- const baseRules = generateBaseInteractiveCSS({
127475
- typography: {
127476
- typography: style.typography,
127477
- fontWeight: style.fontWeight,
127478
- textTransform: style.textTransform,
127479
- italic: style.italic
127480
- },
127481
- padding: style.padding ? NAV_LINK_PADDING_MAP[style.padding] : void 0,
127482
- borderRadius: style.borderRadius ? NAV_LINK_BORDER_RADIUS_MAP[style.borderRadius] : void 0,
127483
- includeTransition: true,
127484
- includeFlexCenter: false
127485
- });
127486
- if (style.paddingX) {
127487
- const px = NAV_LINK_PADDING_X_MAP[style.paddingX];
127488
- baseRules.push(`padding-left: ${px};`);
127489
- baseRules.push(`padding-right: ${px};`);
127490
- }
127491
- if (style.textSize) baseRules.push(`font-size: ${NAV_LINK_TEXT_SIZE_MAP[style.textSize]};`);
127492
- if (style.letterSpacing && style.letterSpacing !== "normal") baseRules.push(`letter-spacing: ${NAV_LINK_LETTER_SPACING_MAP[style.letterSpacing]};`);
127493
- if (style.colorToken) baseRules.push(`color: ${tokens.getColor(style.colorToken)};`);
127494
- const contrastShadow = buildTextContrastShadow({
127495
- theme,
127496
- colorToken: style.colorToken,
127497
- treatment: style.contrastTreatment
127498
- });
127499
- if (contrastShadow) baseRules.push(`text-shadow: ${contrastShadow};`);
127500
- if (style.hoverColorToken && !style.effects?.hover?.length) hoverRules.push(`color: ${tokens.getColor(style.hoverColorToken)};`);
127501
- const elementConfig = {
127502
- background: { type: "transparent" },
127503
- textColorToken: style.colorToken || "text"
127504
- };
127505
- if (style.effects) {
127506
- const effectsCss = generateEffectsCSS({
127507
- themeId,
127508
- variantId: className,
127509
- effects: style.effects,
127510
- elementConfig,
127511
- tokens,
127512
- theme
127513
- });
127514
- if (effectsCss) cssChunks.push(effectsCss);
127515
- }
127516
- if (baseRules.length > 0) cssChunks.unshift(`\n${selector} {\n ${baseRules.join("\n ")}\n}\n`);
127517
- if (hoverRules.length > 0) cssChunks.push(`\n${hoverSelector} {\n ${hoverRules.join("\n ")}\n}\n`);
127518
- if (activeRules.length > 0) cssChunks.push(`\n${activeSelector} {\n ${activeRules.join("\n ")}\n}\n`);
127519
- cssChunks.push(navLinkFocusVisibleCss(selector, style, theme, tokens));
127520
- cssChunks.push(generateInteractiveChildInheritanceCSS(selector));
127521
- return cssChunks.join("");
127522
- }
127523
- /**
127524
- * Keyboard focus indicator for nav links, in the header, the footer and header
127525
- * dropdown menus — the three surfaces `generateNavLinkCSS` serves.
127526
- *
127527
- * Emitted unconditionally rather than as an effect, because focus visibility is
127528
- * a floor rather than a style choice. Only the interaction-palette pill ever
127529
- * wrote an `effects.focus` group, so every other nav — every `quiet` palette,
127530
- * every footer, every dropdown — previously fell back to whatever outline the
127531
- * browser drew.
127532
- *
127533
- * The outline takes the link's own resolved colour, so on a header that adapts
127534
- * to the section it floats over it moves with the adaptation instead of
127535
- * asserting a brand colour against an unknown backdrop.
127536
- *
127537
- * Where the style asks for `soft-glow`, the same halo goes on the outline. That
127538
- * treatment exists because the theme has already conceded the resolved colour
127539
- * alone is not reliable over an unpredictable backdrop — a hero photograph with
127540
- * mixed luminance. Without it the text would stay legible by its halo while the
127541
- * focus ring, which is the part with a contrast requirement of its own, would
127542
- * not.
127543
- *
127544
- * A style that also paints a focus pill keeps it: this adds an outline around
127545
- * that pill rather than replacing it.
127546
- */
127547
- function navLinkFocusVisibleCss(selector, style, theme, tokens) {
127548
- const color = tokens.getColor(style.colorToken);
127549
- const halo = buildTextContrastShadow({
127550
- theme,
127551
- colorToken: style.colorToken,
127552
- treatment: style.contrastTreatment
127553
- });
127554
- return `
127555
- ${selector}:focus-visible {
127556
- outline: 2px solid ${color};
127557
- outline-offset: ${focusOutlineOffset(selector)};${halo ? `\n box-shadow: ${halo};` : ""}
127558
- }
127559
- `;
127560
- }
127561
- /**
127562
- * Dropdown items are full-width inside a panel with no horizontal padding, so
127563
- * an outset outline would paint over and past the panel's own border. Keeping
127564
- * it flush is the only way it reads as belonging to the item.
127565
- */
127566
- function focusOutlineOffset(selector) {
127567
- return selector.includes("nav-dropdown-link") ? "-2px" : "3px";
127568
- }
127569
- function buildTextContrastShadow(input) {
127570
- if (input.treatment !== "soft-glow") return null;
127571
- 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)";
127572
- }
127573
- function isLikelyLightColorToken(theme, colorToken) {
127574
- const hex = resolveColorTokenHex(theme, colorToken);
127575
- if (hex) try {
127576
- return featuresFromHex(hex).Y >= .5;
127577
- } catch {}
127578
- const normalizedToken = colorToken?.toLowerCase() ?? "";
127579
- if (normalizedToken.includes("foreground") || normalizedToken.startsWith("on") || normalizedToken.includes("white") || normalizedToken.endsWith("-50") || normalizedToken.endsWith("-100")) return true;
127580
- if (normalizedToken.includes("black") || normalizedToken.endsWith("-800") || normalizedToken.endsWith("-900") || normalizedToken.endsWith("-950")) return false;
127581
- return theme.palette.meta.mode === "dark";
127582
- }
127583
- function resolveColorTokenHex(theme, colorToken) {
127584
- if (!colorToken) return null;
127585
- if (colorToken === "white") return "#ffffff";
127586
- if (colorToken === "black") return "#000000";
127587
- if (colorToken === "transparent") return null;
127588
- return expandPalette(theme.palette)[colorToken] ?? null;
127589
- }
127590
- //#endregion
127591
- //#region ../theme-core/src/header/surfaceRules.ts
127592
- init_shared$4();
127593
- init_colorStyles();
127594
- /** Compile the at-rest surface independently of scroll treatment and paint geometry. */
127595
- function buildHeaderSurfaceRules(header, tokens) {
127596
- const base = [];
127597
- const background = header.background;
127598
- if (background.type === "color") base.push(`background-color: ${tokens.getColor(background.color || "surface")};`);
127599
- else if (background.type === "gradient" && background.gradient) {
127600
- const stops = background.gradient.stops.map((stop) => tokens.getColor(stop.color)).join(", ");
127601
- base.push(`background-image: linear-gradient(${background.gradient.angle ?? 180}deg, ${stops});`);
127602
- }
127603
- const borderWidth = getComponentBorderWidthPx(header.border?.width ?? "none");
127604
- if (!header.border || borderWidth === "0") return {
127605
- base,
127606
- border: []
127607
- };
127608
- const color = rgbColorValue(header.border.colorToken?.trim() || "border");
127609
- const style = header.border.style === "dashed" ? "dashed" : "solid";
127610
- return {
127611
- base,
127612
- border: header.border.position === "both" ? [`border-top: ${borderWidth} ${style} ${color};`, `border-bottom: ${borderWidth} ${style} ${color};`] : [`border-${header.border.position}: ${borderWidth} ${style} ${color};`]
127613
- };
127614
- }
127615
- //#endregion
127616
- //#region ../theme-core/src/navigation/presets.ts
127617
- /**
127618
- * Built-in nav link style presets
127619
- *
127620
- * Each preset uses composable effects to achieve its look.
127621
- */
127622
- const NAV_LINK_PRESETS = {
127623
- /**
127624
- * Minimal - subtle color change on hover
127625
- */
127626
- minimal: {
127627
- name: "Minimal",
127628
- typography: "body",
127629
- fontWeight: "medium",
127630
- textTransform: "none",
127631
- italic: false,
127632
- colorToken: "text",
127633
- hoverColorToken: "primary",
127634
- padding: "none",
127635
- borderRadius: "none",
127636
- effects: { hover: [{
127637
- effectId: "text-color-change",
127638
- options: { hoverColorToken: "primary" }
127639
- }] }
127640
- },
127641
- /**
127642
- * Underline - static underline appears on hover
127643
- */
127644
- underline: {
127645
- name: "Underline",
127646
- typography: "body",
127647
- fontWeight: "medium",
127648
- textTransform: "none",
127649
- italic: false,
127650
- colorToken: "text",
127651
- padding: "none",
127652
- borderRadius: "none",
127653
- effects: { hover: [{
127654
- effectId: "nav-underline",
127655
- options: { style: "static" }
127656
- }] }
127657
- },
127658
- /**
127659
- * Underline Grow - animated underline grows from center on hover
127660
- */
127661
- "underline-grow": {
127662
- name: "Underline Grow",
127663
- typography: "body",
127664
- fontWeight: "medium",
127665
- textTransform: "none",
127666
- italic: false,
127667
- colorToken: "text",
127668
- padding: "none",
127669
- borderRadius: "none",
127670
- effects: { hover: [{
127671
- effectId: "nav-underline",
127672
- options: { style: "grow" }
127673
- }] }
127674
- },
127675
- /**
127676
- * Capsule - pill-shaped background on hover
127677
- */
127678
- capsule: {
127679
- name: "Capsule",
127680
- typography: "body",
127681
- fontWeight: "medium",
127682
- textTransform: "none",
127683
- italic: false,
127684
- colorToken: "text",
127685
- padding: "compact",
127686
- borderRadius: "full",
127687
- effects: {
127688
- hover: [{
127689
- effectId: "background-on-hover-alpha",
127690
- options: {
127691
- colorToken: "primary",
127692
- opacity: 10
127693
- }
127694
- }],
127695
- active: [{
127696
- effectId: "background-on-hover-alpha",
127697
- options: {
127698
- colorToken: "primary",
127699
- opacity: 15
127700
- }
127701
- }]
127702
- }
127703
- },
127704
- /**
127705
- * Solid - solid background color on hover
127706
- */
127707
- solid: {
127708
- name: "Solid",
127709
- typography: "body",
127710
- fontWeight: "medium",
127711
- textTransform: "none",
127712
- italic: false,
127713
- colorToken: "text",
127714
- padding: "compact",
127715
- borderRadius: "none",
127716
- effects: {
127717
- hover: [{
127718
- effectId: "background-on-hover",
127719
- options: {
127720
- colorToken: "primary",
127721
- textColorToken: "primaryForeground"
127722
- }
127723
- }],
127724
- active: [{
127725
- effectId: "background-on-hover",
127726
- options: {
127727
- colorToken: "primary",
127728
- textColorToken: "primaryForeground"
127729
- }
127730
- }]
127731
- }
127732
- },
127733
- /**
127734
- * Scale - gentle scale-up on hover
127735
- */
127736
- scale: {
127737
- name: "Scale",
127738
- typography: "body",
127739
- fontWeight: "medium",
127740
- textTransform: "none",
127741
- italic: false,
127742
- colorToken: "text",
127743
- padding: "none",
127744
- borderRadius: "none",
127745
- effects: { hover: [{
127746
- effectId: "scale-up",
127747
- options: { scale: 1.05 }
127748
- }] }
127749
- },
127750
- /**
127751
- * Frosted - semi-transparent glass-like background
127752
- */
127753
- frosted: {
127754
- name: "Frosted",
127755
- typography: "body",
127756
- fontWeight: "medium",
127757
- textTransform: "none",
127758
- italic: false,
127759
- colorToken: "text",
127760
- padding: "compact",
127761
- borderRadius: "md",
127762
- effects: {
127763
- base: [{ effectId: "nav-frosted-base" }],
127764
- hover: [{ effectId: "nav-frosted-hover" }],
127765
- active: [{ effectId: "nav-frosted-active" }]
127766
- }
127767
- }
127768
- };
127769
- /**
127770
- * Get a nav link style preset by ID
127771
- */
127772
- function getNavLinkPreset(presetId) {
127773
- return NAV_LINK_PRESETS[presetId];
127774
- }
127775
- Object.keys(NAV_LINK_PRESETS);
127776
- //#endregion
127777
- //#region ../theme-core/src/header/legacyNavLinkStyle.ts
127778
- function buildLegacyHeaderNavLinkStyle(header, contrastTreatment, navTextSize) {
127779
- const navStyle = header.navStyle ?? "minimal";
127780
- const basePreset = getNavLinkPreset(navStyle);
127781
- if (!basePreset) return null;
127782
- const style = {
127783
- ...basePreset,
127784
- fontWeight: header.navWeight ?? basePreset.fontWeight,
127785
- colorToken: (header.navColor ?? header.textColor)?.trim() || basePreset.colorToken,
127786
- ...contrastTreatment ? { contrastTreatment } : {},
127787
- ...navTextSize ? { textSize: navTextSize } : {}
127788
- };
127789
- if (header.navWeight === "bold" && navStyle === "solid") style.textTransform = "uppercase";
127790
- applyLegacyGlassTreatment(style, header, navStyle);
127791
- return style;
127792
- }
127793
- function applyLegacyGlassTreatment(style, header, navStyle) {
127794
- if (header.navContainer?.type !== "glass" || navStyle !== "minimal") return;
127795
- style.borderRadius = "full";
127796
- style.effects = {
127797
- ...style.effects,
127798
- hover: glassStateEffects(10),
127799
- active: glassStateEffects(18)
127800
- };
127801
- }
127802
- function glassStateEffects(opacity) {
127803
- return [{
127804
- effectId: "background-on-hover-alpha",
127805
- options: {
127806
- colorToken: "neutral-50",
127807
- opacity
127808
- }
127809
- }, {
127810
- effectId: "text-color-change",
127811
- options: { hoverColorToken: "neutral-50" }
127812
- }];
127813
- }
127814
- //#endregion
127815
- //#region ../theme-core/src/header/generateHeaderCss.ts
127816
- init_resolver$1();
127817
- init_siteChromeNavPreferences();
127818
- init_shared$4();
127819
- init_breakpoints();
127820
- init_navDropdownSizing();
127821
- init_scrollTreatment();
127822
- init_paintTargets();
127823
- const HEADER_BLUR = "blur(12px)";
127824
- const FLOATING_BLUR = "blur(16px)";
127825
- /**
127826
- * Generate complete CSS for header system from theme config
127827
- *
127828
- * Similar to button system - generates theme-scoped CSS using [data-theme-scope] selector
127829
- */
127830
- function generateHeaderCss(options) {
127831
- const { themeId, theme } = options;
127832
- const tokens = new TokenResolver(theme);
127833
- const header = theme.header;
127834
- const cssChunks = [];
127835
- const headerContrastTreatment = resolveHeaderContrastTreatment(header);
127836
- const headerNavTextSize = resolveHeaderNavTextSize(header);
127837
- cssChunks.push(generateHeaderRootStyles(header, themeId, tokens));
127838
- cssChunks.push(generateMobileOverlayBackdropFilterFix(themeId, header.variant));
127839
- cssChunks.push(generateLogoStyles({
127840
- logo: header.logo,
127841
- themeId,
127842
- tokens,
127843
- theme,
127844
- textColor: header.textColor,
127845
- fallbackTextColor: header.navLinkStyle?.colorToken,
127846
- contrastTreatment: headerContrastTreatment ?? void 0
127847
- }));
127848
- cssChunks.push(generateLogoTextBehaviorStyles(header.logoText, themeId));
127849
- cssChunks.push(generateNavLinkStyles(header, themeId, tokens, theme, headerContrastTreatment, headerNavTextSize));
127850
- cssChunks.push(generateDropdownContainerStyles(header, themeId, tokens));
127851
- cssChunks.push(generateDropdownLinkStyles(header, themeId, tokens, theme));
127852
- cssChunks.push(generateDropdownCaretStyles(themeId));
127853
- cssChunks.push(generateDropdownTriggerOverrides(header, themeId));
127854
- cssChunks.push(generateMobilePanelStyles(header, themeId, tokens));
127855
- if (header.variant === "floating" && header.container) cssChunks.push(generateFloatingContainerStyles(header, themeId, tokens));
127856
- cssChunks.push(generateNavContainerStyles(header, themeId, tokens));
127857
- cssChunks.push(generateHeaderCtaTreatmentStyles(header, themeId, tokens));
127858
- cssChunks.push(generateCtaGapStyles(header, themeId));
127859
- return cssChunks.filter(Boolean).join("\n\n");
127860
- }
127861
- function resolveHeaderContrastTreatment(header) {
127862
- if (header.navLinkStyle?.contrastTreatment) return header.navLinkStyle.contrastTreatment;
127863
- return isClearSplitHeaderShape(header) ? "soft-glow" : null;
127864
- }
127865
- function resolveHeaderNavTextSize(header) {
127866
- if (header.navLinkStyle?.textSize) return header.navLinkStyle.textSize;
127867
- return isClearSplitHeaderShape(header) ? "lg" : null;
127868
- }
127869
- function isClearSplitHeaderShape(header) {
127870
- const hasSharedFloatingSurface = Boolean(header.container);
127871
- return header.variant === "floating" && (header.navStyle ?? "minimal") === "minimal" && !hasSharedFloatingSurface;
127872
- }
127873
- function isDetachedFloatingHeaderShape(header) {
127874
- return header.variant === "floating" && !header.container;
127875
- }
127876
- /**
127877
- * Generate root header container styles
127878
- */
127879
- function generateHeaderRootStyles(header, themeId, tokens) {
127880
- const selector = `:where([data-theme-scope="${themeId}"]) .header-root`;
127881
- const rules = [];
127882
- const navContainerType = header.navContainer?.type ?? "none";
127883
- const isContainedNav = navContainerType === "pill" || navContainerType === "glass";
127884
- rules.push("position: relative;");
127885
- rules.push("isolation: isolate;");
127886
- const surfaceRules = isContainedNav ? {
127887
- base: [],
127888
- border: []
127889
- } : buildHeaderSurfaceRules(header, tokens);
127890
- const floatingSurfaceBorder = header.variant === "floating";
127891
- if (!floatingSurfaceBorder) rules.push(...surfaceRules.border);
127892
- const basePaintRules = floatingSurfaceBorder ? [...surfaceRules.base, ...surfaceRules.border] : surfaceRules.base;
127893
- const scrolledPaintRules = floatingSurfaceBorder ? surfaceRules.border : [];
127894
- if (header.positioning === "sticky" || header.positioning === "fixed") {
127895
- const shadowVar = getComponentShadowVar(header.shadow?.elevation ?? "none");
127896
- if (shadowVar) rules.push(`box-shadow: ${shadowVar};`);
127897
- }
127898
- const baseBlock = `\n${selector} {\n ${rules.join("\n ")}\n}\n`;
127899
- 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`;
127900
- const scrollTreatmentStyles = generateHeaderScrollTreatmentStyles(header.scrollTreatment, themeId, header.variant, scrolledPaintRules);
127901
- if (isContainedNav || basePaintRules.length === 0) return `${baseBlock}\n${overlayFix}${scrollTreatmentStyles}`;
127902
- return `${baseBlock}\n${renderHeaderPaintTargetRules(getHeaderPaintTargets(header.variant, themeId), basePaintRules)}\n${overlayFix}${scrollTreatmentStyles}`;
127903
- }
127904
- /**
127905
- * Generate logo typography styles
127906
- */
127907
- function generateLogoStyles(input) {
127908
- const { logo, themeId, tokens, theme, textColor, fallbackTextColor, contrastTreatment } = input;
127909
- const selector = `:where([data-theme-scope="${themeId}"]) .header-logo-text`;
127910
- const rules = [];
127911
- const primaryColor = tokens.getColor("primary");
127912
- const accentColor = tokens.getColor("accent");
127913
- if (textColor && !logo?.gradient) rules.push(`color: ${tokens.getColor(textColor)};`);
127914
- if ((logo?.fontFamily ?? "heading") === "body") rules.push(`font-family: var(--font-body);`);
127915
- else rules.push(`font-family: var(--font-heading);`);
127916
- if (logo) {
127917
- if (logo.letterSpacing && logo.letterSpacing !== "normal") rules.push(`letter-spacing: ${{
127918
- normal: "0em",
127919
- wide: "0.05em",
127920
- wider: "0.1em",
127921
- widest: "0.15em"
127922
- }[logo.letterSpacing]};`);
127923
- if (logo.gradient) {
127924
- rules.push(`background: linear-gradient(to right, ${primaryColor}, ${accentColor});`);
127925
- rules.push(`-webkit-background-clip: text;`);
127926
- rules.push(`-webkit-text-fill-color: transparent;`);
127927
- rules.push(`background-clip: text;`);
127928
- rules.push(`color: transparent;`);
127929
- }
127930
- }
127931
- const logoTextColorToken = textColor?.trim() || fallbackTextColor?.trim() || "text";
127932
- const contrastShadow = logo?.gradient ? null : buildTextContrastShadow({
127933
- theme,
127934
- colorToken: logoTextColorToken,
127935
- treatment: contrastTreatment
127936
- });
127937
- if (contrastShadow) rules.push(`text-shadow: ${contrastShadow};`);
127938
- if (rules.length === 0) return "";
127939
- return `\n${selector} {\n ${rules.join("\n ")}\n}\n`;
127940
- }
127941
- function generateLogoTextBehaviorStyles(logoText, themeId) {
127942
- if (!logoText) return "";
127943
- const selector = `:where([data-theme-scope="${themeId}"]) .header-logo-text`;
127944
- const cssChunks = [];
127945
- const mobileRules = [];
127946
- if (logoText.mobileWrapLines === 1) {
127947
- mobileRules.push("display: block;");
127948
- mobileRules.push("white-space: nowrap;");
127949
- mobileRules.push("overflow: hidden;");
127950
- mobileRules.push("text-overflow: ellipsis;");
127951
- }
127952
- if (logoText.mobileWrapLines === 2) {
127953
- mobileRules.push("display: -webkit-box;");
127954
- mobileRules.push("-webkit-box-orient: vertical;");
127955
- mobileRules.push("-webkit-line-clamp: 2;");
127956
- mobileRules.push("white-space: normal;");
127957
- mobileRules.push("overflow: hidden;");
127958
- mobileRules.push("text-overflow: ellipsis;");
127959
- }
127960
- if (logoText.mobileMaxWidth) mobileRules.push(`max-width: ${{
127961
- xs: "8rem",
127962
- sm: "10rem",
127963
- md: "12rem"
127964
- }[logoText.mobileMaxWidth]};`);
127965
- if (mobileRules.length > 0) cssChunks.push(`@media ${MQ_MD_DOWN} {\n ${selector} {\n ${mobileRules.join("\n ")}\n }\n}`);
127966
- if (logoText.hideOnShrink) {
127967
- const shrinkSelector = `:where([data-theme-scope="${themeId}"]) .rb-header-shrink.header-scrolled .header-logo-text`;
127968
- cssChunks.push(`\n${shrinkSelector} {\n display: none;\n}\n`);
127969
- }
127970
- return cssChunks.join("\n\n");
127971
- }
127972
- /**
127973
- * Generate navigation link styles based on navStyle and effects
127974
- *
127975
- * Uses the composable NavLinkStyle system with backward compatibility for
127976
- * legacy navStyle, navWeight and navColor settings.
127977
- */
127978
- function generateNavLinkStyles(header, themeId, tokens, theme, contrastTreatment, navTextSize) {
127979
- const navPreferences = {
127980
- typography: header.navFontRole ?? "inherit",
127981
- fontSize: readHeaderNavFontSizePreference(header.navTextSize),
127982
- interactionPalette: header.interactionPalette ?? "recommended"
127983
- };
127984
- if (header.navLinkStyle) return generateNavLinkCSS({
127985
- themeId,
127986
- tokens,
127987
- theme,
127988
- style: mergeHeaderNavTypographyPreference(contrastTreatment || navTextSize ? {
127989
- ...header.navLinkStyle,
127990
- ...contrastTreatment ? { contrastTreatment } : {},
127991
- ...navTextSize ? { textSize: navTextSize } : {}
127992
- } : header.navLinkStyle, navPreferences),
127993
- className: "header-nav-link"
127994
- });
127995
- const mergedStyle = buildLegacyHeaderNavLinkStyle(header, contrastTreatment, navTextSize);
127996
- if (!mergedStyle) {
127997
- console.warn(`[generateHeaderCss] Nav link preset not found: ${header.navStyle}`);
127998
- return "";
127999
- }
128000
- return generateNavLinkCSS({
128001
- themeId,
128002
- tokens,
128003
- theme,
128004
- style: mergeHeaderNavTypographyPreference(mergedStyle, navPreferences),
128005
- className: "header-nav-link"
128006
- });
128007
- }
128008
- /**
128009
- * Generate dropdown menu container styles
128010
- */
128011
- function generateDropdownContainerStyles(header, themeId, tokens) {
128012
- const selector = `:where([data-theme-scope="${themeId}"]) .nav-dropdown-menu`;
128013
- const rules = [];
128014
- const dropdownStyle = header.dropdownStyle;
128015
- rules.push(...NAV_DROPDOWN_CONTAINER_RAIL_CSS_RULES);
128016
- const bgToken = dropdownStyle?.background ?? "surface";
128017
- rules.push(`background-color: ${tokens.getColor(bgToken)};`);
128018
- const textToken = dropdownStyle?.textColor ?? "text";
128019
- rules.push(`color: ${tokens.getColor(textToken)};`);
128020
- const borderToken = dropdownStyle?.borderColor;
128021
- if (borderToken === null) rules.push(`border: none;`);
128022
- else rules.push(`border: 1px solid ${tokens.getColor(borderToken ?? "border")};`);
128023
- const shadowVar = getComponentShadowVar(dropdownStyle?.shadow ?? "md");
128024
- if (shadowVar) rules.push(`box-shadow: ${shadowVar};`);
128025
- const borderRadius = dropdownStyle?.borderRadius ?? "md";
128026
- rules.push(`border-radius: ${{
128027
- none: "0",
128028
- sm: "0.25rem",
128029
- md: "0.5rem",
128030
- lg: "0.75rem"
128031
- }[borderRadius]};`);
128032
- rules.push(`padding: 0.5rem 0;`);
128033
- return `\n${selector} {\n ${rules.join("\n ")}\n}\n`;
128034
- }
128035
- function generateDropdownLinkStyles(header, themeId, tokens, theme) {
128036
- const configuredDropdownStyle = header.dropdownStyle;
128037
- const textColorToken = configuredDropdownStyle?.textColor ?? ((header.navColor ?? header.textColor)?.trim() || "text");
128038
- const hoverBgToken = configuredDropdownStyle?.hoverBackground ?? textColorToken;
128039
- const hoverEffects = {
128040
- hover: hoverBgToken === null ? [] : [{
128041
- effectId: "background-on-hover-alpha",
128042
- options: {
128043
- colorToken: hoverBgToken,
128044
- opacity: 12
128045
- }
128046
- }],
128047
- active: hoverBgToken === null ? [] : [{
128048
- effectId: "background-on-hover-alpha",
128049
- options: {
128050
- colorToken: hoverBgToken,
128051
- opacity: 18
128052
- }
128053
- }]
128054
- };
128055
- if (configuredDropdownStyle?.hoverTextColor) {
128056
- hoverEffects.hover?.push({
128057
- effectId: "text-color-change",
128058
- options: { hoverColorToken: configuredDropdownStyle.hoverTextColor }
128059
- });
128060
- hoverEffects.active?.push({
128061
- effectId: "text-color-change",
128062
- options: { hoverColorToken: configuredDropdownStyle.hoverTextColor }
128063
- });
128064
- }
128065
- const baseCSS = generateNavLinkCSS({
128066
- themeId,
128067
- tokens,
128068
- theme,
128069
- style: {
128070
- name: "Dropdown",
128071
- typography: "body",
128072
- fontWeight: configuredDropdownStyle?.fontWeight ?? header.navWeight ?? "medium",
128073
- textTransform: configuredDropdownStyle?.textTransform ?? "none",
128074
- italic: false,
128075
- colorToken: textColorToken,
128076
- padding: "compact",
128077
- borderRadius: "sm",
128078
- effects: hoverEffects
128079
- },
128080
- className: "nav-dropdown-link"
128081
- });
128082
- const additionalRules = [];
128083
- const letterSpacing = configuredDropdownStyle?.letterSpacing ?? "normal";
128084
- if (letterSpacing !== "normal") additionalRules.push(`letter-spacing: ${{
128085
- normal: "0em",
128086
- wide: "0.05em",
128087
- wider: "0.1em"
128088
- }[letterSpacing]};`);
128089
- const textSize = configuredDropdownStyle?.textSize ?? "sm";
128090
- additionalRules.push(`font-size: ${{
128091
- xs: "0.75rem",
128092
- sm: "0.875rem",
128093
- base: "1rem",
128094
- lg: "1.125rem"
128095
- }[textSize]};`);
128096
- if (additionalRules.length > 0) return baseCSS + `\n${`:where([data-theme-scope="${themeId}"]) .nav-dropdown-link`} {\n ${additionalRules.join("\n ")}\n}\n`;
128097
- return baseCSS;
128098
- }
128099
- function generateDropdownCaretStyles(themeId) {
128100
- return `
128101
- ${`:where([data-theme-scope="${themeId}"]) .nav-caret`} {
128102
- width: 0.45rem;
128103
- height: 0.45rem;
128104
- margin-left: 0.5rem;
128105
- border-right: 2px solid currentColor;
128106
- border-bottom: 2px solid currentColor;
128107
- transform: rotate(45deg) translateY(-1px);
128108
- transition: transform 150ms ease;
128109
- }
128110
-
128111
- ${`: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`} {
128112
- transform: rotate(-135deg) translateY(1px);
128113
- }
128114
- `.trim();
128115
- }
128116
- function generateDropdownTriggerOverrides(header, themeId) {
128117
- const navStyle = header.navStyle ?? "minimal";
128118
- if (navStyle !== "underline" && navStyle !== "underline-grow") return "";
128119
- return `
128120
- ${`:where([data-theme-scope="${themeId}"]) .nav-dropdown-trigger.header-nav-link::after`} {
128121
- content: none;
128122
- }
128123
- `.trim();
128124
- }
128125
- /**
128126
- * Generate mobile navigation panel styles
128127
- * Uses the same dropdownStyle settings as the desktop dropdown menus
128128
- */
128129
- function generateMobilePanelStyles(header, themeId, tokens) {
128130
- const selector = `:where([data-theme-scope="${themeId}"]) .nav-mobile-panel`;
128131
- const selfSelector = `:where(.nav-mobile-panel[data-theme-scope="${themeId}"])`;
128132
- const rules = [];
128133
- const dropdownStyle = header.dropdownStyle;
128134
- const bgToken = dropdownStyle?.background ?? "surface";
128135
- rules.push(`background-color: ${tokens.getColor(bgToken)};`);
128136
- const textToken = dropdownStyle?.textColor ?? "text";
128137
- rules.push(`color: ${tokens.getColor(textToken)};`);
128138
- const body = rules.join("\n ");
128139
- return `\n${selector} {\n ${body}\n}\n\n${selfSelector} {\n ${body}\n}\n`;
128140
- }
128141
- /**
128142
- * Generate nav container styles (pill/glass)
128143
- */
128144
- function generateNavContainerStyles(header, themeId, tokens) {
128145
- const navContainer = header.navContainer;
128146
- const navContainerType = navContainer?.type ?? "none";
128147
- if (!navContainer || navContainerType === "none") return "";
128148
- const selector = `:where([data-theme-scope="${themeId}"]) .header-nav-row`;
128149
- const rules = [];
128150
- if (navContainerType === "pill" || navContainerType === "glass") {
128151
- rules.push("padding: 0.5rem 0.75rem;");
128152
- rules.push("border-radius: 9999px;");
128153
- rules.push("display: inline-flex;");
128154
- rules.push("align-items: center;");
128155
- rules.push("gap: 1.5rem;");
128156
- if (isDetachedFloatingHeaderShape(header)) rules.push("align-self: flex-start;");
128157
- }
128158
- if (navContainerType === "glass") {
128159
- const opacity = resolveFloatingGlassOpacity(header, navContainer.opacity, .15);
128160
- const background = navContainer.tint ? buildTint(tokens.getColor(navContainer.tint), opacity) : buildRgbWhite(opacity);
128161
- rules.push(`background-color: ${background};`);
128162
- rules.push(`backdrop-filter: ${HEADER_BLUR};`);
128163
- rules.push(`-webkit-backdrop-filter: ${HEADER_BLUR};`);
128164
- rules.push("border: 1px solid rgba(255, 255, 255, 0.2);");
128165
- rules.push("box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);");
128166
- } else if (navContainerType === "pill") {
128167
- const opacity = clampOpacity(navContainer.opacity, .15);
128168
- if (navContainer.tint) rules.push(`background-color: ${buildTint(tokens.getColor(navContainer.tint), opacity)};`);
128169
- else rules.push(`background-color: ${tokens.getColor("surface")};`);
128170
- rules.push(`border: 1px solid ${tokens.getColor("border")};`);
128171
- }
128172
- if (rules.length > 0) return `${selector} { ${rules.join(" ")} }`;
128173
- return "";
128174
- }
128175
- /**
128176
- * Generate floating container styles
128177
- */
128178
- function generateFloatingContainerStyles(header, themeId, tokens) {
128179
- const container = header.container;
128180
- if (!container) return "";
128181
- const selector = `:where([data-theme-scope="${themeId}"]) .header-floating-container`;
128182
- const rules = [];
128183
- const opacity = container.tint === "surface" ? resolveFloatingGlassOpacity(header, container.opacity, .12) : clampOpacity(container.opacity, .12);
128184
- if (container.tint) rules.push(`background-color: ${buildTint(tokens.getColor(container.tint), opacity)};`);
128185
- else rules.push(`background-color: ${buildRgbWhite(opacity)};`);
128186
- rules.push(`backdrop-filter: ${FLOATING_BLUR};`);
128187
- rules.push(`-webkit-backdrop-filter: ${FLOATING_BLUR};`);
128188
- if (container.border) rules.push(`border: 1px solid rgb(255 255 255 / 0.2);`);
128189
- rules.push(`border-radius: ${{
128190
- none: "0",
128191
- sm: "0.375rem",
128192
- md: "0.5rem",
128193
- lg: "0.75rem",
128194
- xl: "1rem",
128195
- "2xl": "1.5rem"
128196
- }[container.rounded]};`);
128197
- 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);`);
128198
- rules.push(`padding: ${{
128199
- sm: "1rem 1.5rem",
128200
- md: "1.5rem 2rem",
128201
- lg: "2rem 2.5rem"
128202
- }[container.padding]};`);
128203
- return `\n${selector} {\n ${rules.join("\n ")}\n}\n`;
128204
- }
128205
- /**
128206
- * CTA gap value map — controls left margin on the desktop CTA button
128207
- */
128208
- const HEADER_CTA_GAP_MAP = {
128209
- none: "0",
128210
- tight: "0.5rem",
128211
- compact: "1rem",
128212
- default: "1.5rem",
128213
- relaxed: "2rem",
128214
- spacious: "3rem"
128215
- };
128216
- /**
128217
- * The inverted CTA treatment is contextual to branded header surfaces. It
128218
- * cannot be represented by the generic secondary button role alone because
128219
- * that role is transparent and inherits the surrounding surface foreground.
128220
- * Keep the shared button's structure/effects while making the header own the
128221
- * palette relationship for both desktop and mobile CTAs.
128222
- */
128223
- function generateHeaderCtaTreatmentStyles(header, themeId, tokens) {
128224
- if (header.ctaTreatment !== "inverted") return "";
128225
- const desktopSelector = `:where([data-theme-scope="${themeId}"]) .header-cta`;
128226
- const mobileSelector = `:where([data-theme-scope="${themeId}"]) .nav-mobile-cta`;
128227
- const selectors = `${desktopSelector},\n${mobileSelector}`;
128228
- const hoverSelectors = [
128229
- `${desktopSelector}:hover`,
128230
- `${desktopSelector}[data-force-hover="true"]`,
128231
- `${mobileSelector}:hover`,
128232
- `${mobileSelector}[data-force-hover="true"]`
128233
- ].join(",\n");
128234
- const focusSelectors = [`${desktopSelector}:focus-visible`, `${mobileSelector}:focus-visible`].join(",\n");
128235
- return `
128236
- ${selectors} {
128237
- background-color: ${tokens.getColor("background")};
128238
- background-image: none;
128239
- color: ${tokens.getColor("onBackground")};
128240
- border-color: currentColor;
128241
- }
128242
-
128243
- ${hoverSelectors} {
128244
- background-color: ${tokens.getColor("surface")};
128245
- background-image: none;
128246
- color: ${tokens.getColor("onSurface")};
128247
- }
128248
-
128249
- ${focusSelectors} {
128250
- outline: 2px solid ${tokens.getColor("onBackground")};
128251
- outline-offset: 2px;
128252
- box-shadow: 0 0 0 4px ${tokens.getColor("background")};
128253
- }
128254
- `;
128255
- }
128256
- /**
128257
- * Generate CTA button gap styles (left margin between nav links and CTA)
128258
- */
128259
- function generateCtaGapStyles(header, themeId) {
128260
- if (!header.ctaGap) return "";
128261
- const value = HEADER_CTA_GAP_MAP[header.ctaGap];
128262
- if (!value) return "";
128263
- return `\n${`:where([data-theme-scope="${themeId}"]) .header-cta`} {\n margin-left: ${value};\n}\n`;
128264
- }
128265
- function clampOpacity(value, fallback) {
128266
- if (typeof value !== "number" || Number.isNaN(value)) return fallback;
128267
- return Math.min(Math.max(value, 0), 1);
128268
- }
128269
- function resolveFloatingGlassOpacity(header, value, fallback) {
128270
- const opacity = clampOpacity(value, fallback);
128271
- return header.variant === "floating" ? Math.max(opacity, .4) : opacity;
128272
- }
128273
- function buildTint(color, opacity) {
128274
- return applyAlpha(color, opacity);
128275
- }
128276
- function buildRgbWhite(opacity) {
128277
- return `rgb(255 255 255 / ${clampOpacity(opacity, 1)})`;
128278
- }
128279
- function applyAlpha(color, opacity) {
128280
- const clamped = clampOpacity(opacity, 1);
128281
- if (color.startsWith("rgb(") && color.endsWith(")")) {
128282
- const inner = color.slice(4, -1).trim();
128283
- return `rgb(${inner.includes("/") ? (inner.split("/")[0] ?? inner).trim() : inner} / ${clamped})`;
128284
- }
128285
- return color;
128286
- }
128287
- //#endregion
128288
- //#region ../theme-core/src/footer/generateFooterCss.ts
128289
- init_resolver$1();
128290
- /**
128291
- * Generate CSS for footer navigation styling
128292
- *
128293
- * Similar to header nav but with independent configuration and no advanced effects
128294
- */
128295
- function generateFooterCss(options) {
128296
- const { themeId, theme } = options;
128297
- const tokens = new TokenResolver(theme);
128298
- const footer = theme.footer;
128299
- const cssChunks = [];
128300
- cssChunks.push(generateFooterNavLinkStyles(footer, themeId, tokens, theme));
128301
- cssChunks.push(generateFooterLogoStyles(theme, themeId));
128302
- cssChunks.push(generateFooterBottomTextLinkStyles(footer, themeId, tokens));
128303
- return cssChunks.filter(Boolean).join("\n\n");
128304
- }
128305
- function generateFooterLogoStyles(theme, themeId) {
128306
- const height = footerLogoHeight(resolveFooterLogoSize(theme.footer, theme.header.logo));
128307
- return `
128308
- ${`:where([data-theme-scope="${themeId}"])`} .footer-logo img {
128309
- width: auto;
128310
- height: ${height};
128311
- }
128312
- `;
128313
- }
128314
- function resolveFooterLogoSize(footer, headerLogo) {
128315
- const brandDrivenSize = footerLogoSizeFromHeaderLogo(headerLogo);
128316
- return footer.logo?.maxHeight ?? brandDrivenSize ?? footer.logo?.size ?? "md";
128317
- }
128318
- function footerLogoSizeFromHeaderLogo(headerLogo) {
128319
- const size = headerLogo?.size;
128320
- switch (size) {
128321
- case "compact": return "sm";
128322
- case "standard": return "md";
128323
- case "generous": return "lg";
128324
- case "display": return "xl";
128325
- case "auto":
128326
- case void 0: return null;
128327
- default: return size;
128328
- }
128329
- }
128330
- function footerLogoHeight(size) {
128331
- switch (size) {
128332
- case "sm": return "2.5rem";
128333
- case "md": return "4rem";
128334
- case "lg": return "5rem";
128335
- case "xl": return "6rem";
128336
- default: return size;
128337
- }
128338
- }
128339
- /**
128340
- * Generate navigation link styles for footer
128341
- *
128342
- * Uses the composable NavLinkStyle system with backward compatibility for
128343
- * legacy navStyle, navWeight, and navColor settings.
128344
- */
128345
- function generateFooterNavLinkStyles(footer, themeId, tokens, theme) {
128346
- if (footer.navLinkStyle) return generateNavLinkCSS({
128347
- themeId,
128348
- tokens,
128349
- theme,
128350
- style: footer.navLinkStyle,
128351
- className: "footer-nav-link"
128352
- });
128353
- const navStyle = footer.navStyle ?? "minimal";
128354
- const basePreset = getNavLinkPreset(navStyle);
128355
- if (!basePreset) {
128356
- console.warn(`[generateFooterCss] Nav link preset not found: ${navStyle}`);
128357
- return "";
128358
- }
128359
- return generateNavLinkCSS({
128360
- themeId,
128361
- tokens,
128362
- theme,
128363
- style: {
128364
- ...basePreset,
128365
- fontWeight: footer.navWeight ?? basePreset.fontWeight,
128366
- colorToken: footer.navColor?.trim() || basePreset.colorToken
128367
- },
128368
- className: "footer-nav-link"
128369
- });
128370
- }
128371
- function generateFooterBottomTextLinkStyles(footer, themeId, tokens) {
128372
- const style = footer.bottomTextLinkStyle;
128373
- if (!style) return "";
128374
- const scope = `:where([data-theme-scope="${themeId}"])`;
128375
- const selectors = [`${scope} .block-site-footer .rb-prose a`, `${scope} .block-siteFooter .rb-prose a`];
128376
- const baseRules = [];
128377
- const hoverRules = [];
128378
- const colorToken = style.colorToken?.trim();
128379
- if (colorToken) baseRules.push(`color: ${tokens.getColor(colorToken)};`);
128380
- const decorationColorToken = style.decorationColorToken?.trim();
128381
- if (decorationColorToken) baseRules.push(`text-decoration-color: ${tokens.getColor(decorationColorToken)};`);
128382
- if (style.underline === true) baseRules.push("text-decoration: underline;");
128383
- else if (style.underline === false) baseRules.push("text-decoration: none;");
128384
- const hoverColorToken = style.hoverColorToken?.trim();
128385
- if (hoverColorToken) hoverRules.push(`color: ${tokens.getColor(hoverColorToken)};`);
128386
- const cssChunks = [];
128387
- if (baseRules.length > 0) cssChunks.push(`\n${selectors.join(",\n")} {\n ${baseRules.join("\n ")}\n}\n`);
128388
- if (hoverRules.length > 0) {
128389
- const hoverSelectors = selectors.map((selector) => `${selector}:hover`);
128390
- cssChunks.push(`\n${hoverSelectors.join(",\n")} {\n ${hoverRules.join("\n ")}\n}\n`);
128391
- }
128392
- return cssChunks.join("\n");
128393
- }
128394
- //#endregion
128395
128973
  //#region ../theme-core/src/layout/boundaryCss.ts
128396
128974
  init_sectionTransitions();
128397
128975
  init_transitionCatalogue();
@@ -130011,6 +130589,8 @@ init_atRuleValidation();
130011
130589
  init_expandPalette();
130012
130590
  init_generateButtonCss();
130013
130591
  init_generateCardCss();
130592
+ init_header$1();
130593
+ init_footer();
130014
130594
  init_tokens();
130015
130595
  init_colorStyles();
130016
130596
  function buildThemeRuntime$1(theme, options) {
@@ -130749,9 +131329,10 @@ function pageBlockPosition(index, blockCount) {
130749
131329
  //#endregion
130750
131330
  //#region ../blocks/src/pageRendererContracts.ts
130751
131331
  function buildPageRendererRootRuntime(dataContext) {
130752
- 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 ?? {};
131332
+ 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 ?? {};
130753
131333
  return {
130754
131334
  siteId,
131335
+ siteName,
130755
131336
  pageId,
130756
131337
  pathname,
130757
131338
  bookingTimeZone,
@@ -135445,7 +136026,9 @@ const bookingWizard = bookingForm(withApiBindings({
135445
136026
  } },
135446
136027
  formId: { $bind: { from: "content.formId" } },
135447
136028
  form: { $bind: { from: "data.form" } },
135448
- services: { $bind: { from: "data.services" } }
136029
+ services: { $bind: { from: "data.services" } },
136030
+ mailingList: { $bind: { from: "$root.mailingList" } },
136031
+ siteName: { $bind: { from: "$root.siteName" } }
135449
136032
  }));
135450
136033
  /** Both variants sit in the same section shell; only the inner layout differs. */
135451
136034
  function bookingSection(children) {
@@ -139951,6 +140534,7 @@ function getBlockDefinition(name) {
139951
140534
  //#endregion
139952
140535
  //#region ../blocks/src/system/componentFactory.ts
139953
140536
  init_src$2();
140537
+ init_tokens();
139954
140538
  init_buttons();
139955
140539
  /**
139956
140540
  * Resolves the layout definition for a block based on its manifest and content.
@@ -140026,19 +140610,19 @@ function prepareDefaultBlockRender(manifest, props) {
140026
140610
  const content = props.content;
140027
140611
  const layout = resolveBlockLayout(manifest, content);
140028
140612
  if (!layout) throw new Error(`Block manifest "${manifest.name}" requires a layout definition`);
140029
- const mergedContent = mergeContentWithBlockStyleOverrides(content, props.themeConfig, props.blockKind ?? manifest.name);
140613
+ const prepared = prepareBlockRender({
140614
+ content,
140615
+ theme: props.theme,
140616
+ themeConfig: props.themeConfig,
140617
+ blockKind: props.blockKind ?? manifest.name,
140618
+ data: props.data,
140619
+ viewModelOverrides: props.viewModelOverrides
140620
+ });
140030
140621
  return {
140031
140622
  registry: props.registry,
140032
140623
  layout,
140033
- mergedContent,
140034
- fieldConstraints: buildPreviewFieldConstraints(manifest),
140035
- viewModel: buildBlockViewModel({
140036
- mergedContent,
140037
- data: props.data,
140038
- resolvedThemeConfig: resolveThemeConfigForBindings(props.themeConfig),
140039
- viewModelOverrides: props.viewModelOverrides
140040
- }),
140041
- themeForTransforms: withButtonSystem(props.theme, props.themeConfig)
140624
+ ...prepared,
140625
+ fieldConstraints: buildPreviewFieldConstraints(manifest)
140042
140626
  };
140043
140627
  }
140044
140628
  function makeDefaultBlockComponent(args) {
@@ -140050,6 +140634,7 @@ function makeDefaultBlockComponent(args) {
140050
140634
  viewModel: prepared.viewModel,
140051
140635
  transforms: props.transforms,
140052
140636
  theme: prepared.themeForTransforms,
140637
+ proseHoverCandidate: prepared.proseHoverCandidate,
140053
140638
  pathBase: props.pathBase,
140054
140639
  blockId: props.blockId,
140055
140640
  newsletterBlockSubmission: props.newsletterBlockSubmission,
@@ -140071,6 +140656,20 @@ function makeDefaultBlockComponent(args) {
140071
140656
  return result;
140072
140657
  };
140073
140658
  }
140659
+ function prepareBlockRender(input) {
140660
+ const mergedContent = mergeContentWithBlockStyleOverrides(input.content, input.themeConfig, input.blockKind);
140661
+ return {
140662
+ mergedContent,
140663
+ viewModel: buildBlockViewModel({
140664
+ mergedContent,
140665
+ data: input.data,
140666
+ resolvedThemeConfig: resolveThemeConfigForBindings(input.themeConfig),
140667
+ viewModelOverrides: input.viewModelOverrides
140668
+ }),
140669
+ themeForTransforms: withButtonSystem(input.theme, input.themeConfig),
140670
+ proseHoverCandidate: parseThemeColorToken(input.themeConfig?.typography.proseLinkStyle?.hoverColorToken) ?? void 0
140671
+ };
140672
+ }
140074
140673
  function buildBlockViewModel(input) {
140075
140674
  const themeBinding = input.resolvedThemeConfig ? { theme: input.resolvedThemeConfig } : {};
140076
140675
  const baseData = input.data ? { data: { ...input.data } } : {};
@@ -140695,6 +141294,7 @@ function planNewsletterBlockSubmission(placement) {
140695
141294
  sourceRef
140696
141295
  } : { tag: "unavailable" };
140697
141296
  }
141297
+ if (placement.publishedPlacement && "kind" in placement.publishedPlacement) return { tag: "unpublished-settings" };
140698
141298
  if (placement.publishedPlacement) return planNewsletterPreviewSubmission({
140699
141299
  blockId: placement.blockId,
140700
141300
  publishedContentId: placement.publishedPlacement.id,
@@ -140855,7 +141455,7 @@ function newsletterBlockProps(block, renderedContent, stage) {
140855
141455
  return { newsletterBlockSubmission: planNewsletterBlockSubmission({
140856
141456
  blockId: block.id,
140857
141457
  selectedContentVersionId: block.contentVersionId ?? null,
140858
- publishedPlacement: block.publishedPlacement ?? null,
141458
+ publishedPlacement: block.publishedPlacement,
140859
141459
  renderedContent,
140860
141460
  stage
140861
141461
  }) };
@@ -140952,7 +141552,11 @@ const BlockErrorBoundary = createBlockErrorBoundary();
140952
141552
  /** Pair a published version with the content it authorises at the render boundary. */
140953
141553
  function readPublishedBlockPlacement(id, content) {
140954
141554
  if (id == null && content == null) return null;
140955
- if (id == null || content == null) throw new Error("Published block placement requires both an ID and content");
141555
+ if (id == null || content == null) return {
141556
+ kind: "incomplete",
141557
+ id: id ?? null,
141558
+ content: content ?? null
141559
+ };
140956
141560
  return {
140957
141561
  id,
140958
141562
  content
@@ -140969,7 +141573,7 @@ function toPresentationPage(page) {
140969
141573
  purpose: block.purpose,
140970
141574
  ...block.contentVersionId ? { contentVersionId: block.contentVersionId } : {},
140971
141575
  ...block.draftContentId !== void 0 ? { draftContentId: block.draftContentId } : {},
140972
- ...block.publishedPlacement !== void 0 ? { publishedPlacement: block.publishedPlacement } : {},
141576
+ publishedPlacement: block.publishedPlacement,
140973
141577
  ...block.bindings ? { bindings: block.bindings } : {}
140974
141578
  };
140975
141579
  return block.admission.kind === "renderable" ? {
@@ -140992,6 +141596,7 @@ function toEditorPresentationPage(page) {
140992
141596
  ...page,
140993
141597
  blocks: page.blocks.map((block) => ({
140994
141598
  ...block,
141599
+ publishedPlacement: block.publishedPlacement,
140995
141600
  presentationAdmission: { kind: "editor" }
140996
141601
  }))
140997
141602
  };
@@ -143270,6 +143875,8 @@ const containerResponsiveThemeCss = `/*
143270
143875
  --rb-surface-text-color: var(--rb-modal-text, rgb(var(--tb-text, 17 24 39)));
143271
143876
  --rb-surface-heading-color: var(--rb-modal-heading, var(--rb-modal-text, rgb(var(--tb-text, 17 24 39))));
143272
143877
  --rb-surface-link-color: var(--rb-modal-link, var(--rb-modal-text, rgb(var(--tb-text, 17 24 39))));
143878
+ --rb-surface-link-hover-color: var(--rb-modal-link, var(--rb-modal-text, rgb(var(--tb-text, 17 24 39))));
143879
+ --rb-surface-link-hover-decoration: underline;
143273
143880
  --rb-surface-supporting-color: var(--rb-modal-supporting, var(--rb-modal-text, rgb(var(--tb-text, 17 24 39))));
143274
143881
  border: 1px solid var(--rb-modal-border, rgb(var(--tb-border)));
143275
143882
  border-radius: var(--rb-modal-radius, var(--radius-card));
@@ -143699,14 +144306,18 @@ const containerResponsiveThemeCss = `/*
143699
144306
 
143700
144307
  :where(.theme-scope) .rb-prose a:hover {
143701
144308
  color: var(
143702
- --rb-prose-link-hover-color,
143703
- var(--rb-prose-effective-link-color)
144309
+ --rb-surface-link-hover-color,
144310
+ var(--rb-prose-link-hover-color, var(--rb-prose-effective-link-color))
144311
+ );
144312
+ text-decoration-line: var(
144313
+ --rb-surface-link-hover-decoration,
144314
+ var(--rb-prose-link-decoration-line, underline)
143704
144315
  );
143705
144316
  text-decoration-color: var(
143706
144317
  --rb-prose-link-hover-decoration-color,
143707
144318
  var(
143708
- --rb-prose-link-hover-color,
143709
- var(--rb-prose-effective-link-color)
144319
+ --rb-surface-link-hover-color,
144320
+ var(--rb-prose-link-hover-color, var(--rb-prose-effective-link-color))
143710
144321
  )
143711
144322
  );
143712
144323
  }
@@ -144750,6 +145361,8 @@ const containerResponsiveThemeCss = `/*
144750
145361
  --rb-surface-text-color: rgb(var(--tb-onSurface, var(--tb-text)));
144751
145362
  --rb-surface-heading-color: rgb(var(--tb-onSurface, var(--tb-text)));
144752
145363
  --rb-surface-link-color: rgb(var(--tb-onSurface, var(--tb-text)));
145364
+ --rb-surface-link-hover-color: rgb(var(--tb-onSurface, var(--tb-text)));
145365
+ --rb-surface-link-hover-decoration: underline;
144753
145366
  --rb-surface-supporting-color: rgb(var(--tb-onSurface, var(--tb-text)));
144754
145367
  border: 1px solid rgb(var(--tb-border));
144755
145368
  border-radius: var(--radius-card);
@@ -144897,6 +145510,8 @@ const containerResponsiveThemeCss = `/*
144897
145510
  --rb-surface-text-color: var(--rb-reg-on-surface, rgb(var(--tb-onSurface, var(--tb-text, 15 23 42))));
144898
145511
  --rb-surface-heading-color: var(--rb-reg-on-surface, rgb(var(--tb-onSurface, var(--tb-text, 15 23 42))));
144899
145512
  --rb-surface-link-color: var(--rb-reg-on-surface, rgb(var(--tb-onSurface, var(--tb-text, 15 23 42))));
145513
+ --rb-surface-link-hover-color: var(--rb-reg-on-surface, rgb(var(--tb-onSurface, var(--tb-text, 15 23 42))));
145514
+ --rb-surface-link-hover-decoration: underline;
144900
145515
  --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)))));
144901
145516
  transition: border-color var(--rb-block-transition, 150ms) ease;
144902
145517
  width: 100%;
@@ -150876,6 +151491,8 @@ const containerResponsiveThemeCss = `/*
150876
151491
  --rb-surface-text-color: inherit;
150877
151492
  --rb-surface-heading-color: inherit;
150878
151493
  --rb-surface-link-color: inherit;
151494
+ --rb-surface-link-hover-color: inherit;
151495
+ --rb-surface-link-hover-decoration: inherit;
150879
151496
  --rb-surface-supporting-color: inherit;
150880
151497
  }
150881
151498
 
@@ -150973,6 +151590,8 @@ const containerResponsiveThemeCss = `/*
150973
151590
  --rb-surface-text-color: rgb(var(--tb-text, 17 24 39));
150974
151591
  --rb-surface-heading-color: rgb(var(--tb-text, 17 24 39));
150975
151592
  --rb-surface-link-color: rgb(var(--tb-primary, var(--tb-text, 17 24 39)));
151593
+ --rb-surface-link-hover-color: var(--rb-prose-link-hover-color, rgb(var(--tb-primary, var(--tb-text, 17 24 39))));
151594
+ --rb-surface-link-hover-decoration: initial;
150976
151595
  --rb-surface-supporting-color: rgb(var(--tb-mutedText, 100 116 139));
150977
151596
  border: 1px solid rgb(var(--tb-border));
150978
151597
  border-radius: var(--shop-card-radius);
@@ -151139,6 +151758,8 @@ const containerResponsiveThemeCss = `/*
151139
151758
  --rb-surface-text-color: rgb(var(--tb-text, 17 24 39));
151140
151759
  --rb-surface-heading-color: rgb(var(--tb-text, 17 24 39));
151141
151760
  --rb-surface-link-color: rgb(var(--tb-primary, var(--tb-text, 17 24 39)));
151761
+ --rb-surface-link-hover-color: var(--rb-prose-link-hover-color, rgb(var(--tb-primary, var(--tb-text, 17 24 39))));
151762
+ --rb-surface-link-hover-decoration: initial;
151142
151763
  --rb-surface-supporting-color: rgb(var(--tb-mutedText, 100 116 139));
151143
151764
  }
151144
151765
 
@@ -151216,6 +151837,8 @@ const containerResponsiveThemeCss = `/*
151216
151837
  --rb-surface-text-color: var(--cp-text);
151217
151838
  --rb-surface-heading-color: var(--cp-text);
151218
151839
  --rb-surface-link-color: var(--cp-primary);
151840
+ --rb-surface-link-hover-color: var(--rb-prose-link-hover-color, var(--cp-primary));
151841
+ --rb-surface-link-hover-decoration: initial;
151219
151842
  --rb-surface-supporting-color: var(--cp-muted);
151220
151843
  border: 1px solid var(--cp-card-border);
151221
151844
  border-radius: var(--cp-card-radius);
@@ -151365,6 +151988,8 @@ const containerResponsiveThemeCss = `/*
151365
151988
  --rb-surface-text-color: var(--cp-text);
151366
151989
  --rb-surface-heading-color: var(--cp-text);
151367
151990
  --rb-surface-link-color: var(--cp-primary);
151991
+ --rb-surface-link-hover-color: var(--rb-prose-link-hover-color, var(--cp-primary));
151992
+ --rb-surface-link-hover-decoration: initial;
151368
151993
  --rb-surface-supporting-color: var(--cp-muted);
151369
151994
  border: 1px dashed var(--cp-card-border);
151370
151995
  border-radius: var(--cp-card-radius);
@@ -151382,6 +152007,8 @@ const containerResponsiveThemeCss = `/*
151382
152007
  --rb-surface-text-color: var(--cp-text);
151383
152008
  --rb-surface-heading-color: var(--cp-text);
151384
152009
  --rb-surface-link-color: var(--cp-primary);
152010
+ --rb-surface-link-hover-color: var(--rb-prose-link-hover-color, var(--cp-primary));
152011
+ --rb-surface-link-hover-decoration: initial;
151385
152012
  --rb-surface-supporting-color: var(--cp-muted);
151386
152013
  border: 1px solid var(--cp-card-border);
151387
152014
  border-radius: var(--cp-card-radius);
@@ -151622,6 +152249,8 @@ const containerResponsiveThemeCss = `/*
151622
152249
  --rb-surface-text-color: var(--cp-text);
151623
152250
  --rb-surface-heading-color: var(--cp-text);
151624
152251
  --rb-surface-link-color: var(--cp-primary);
152252
+ --rb-surface-link-hover-color: var(--rb-prose-link-hover-color, var(--cp-primary));
152253
+ --rb-surface-link-hover-decoration: initial;
151625
152254
  --rb-surface-supporting-color: var(--cp-muted);
151626
152255
  border: 1px solid var(--cp-card-border);
151627
152256
  border-radius: var(--cp-card-radius);
@@ -154285,6 +154914,8 @@ const containerResponsiveThemeCss = `/*
154285
154914
  --rb-surface-text-color: rgb(var(--tb-onSecondary));
154286
154915
  --rb-surface-heading-color: rgb(var(--tb-onSecondary));
154287
154916
  --rb-surface-link-color: rgb(var(--tb-onSecondary));
154917
+ --rb-surface-link-hover-color: rgb(var(--tb-onSecondary));
154918
+ --rb-surface-link-hover-decoration: underline;
154288
154919
  --rb-surface-supporting-color: rgb(var(--tb-onSecondary));
154289
154920
  }
154290
154921
 
@@ -154416,6 +155047,8 @@ const containerResponsiveThemeCss = `/*
154416
155047
  --rb-surface-text-color: rgb(var(--tb-onPrimary));
154417
155048
  --rb-surface-heading-color: rgb(var(--tb-onPrimary));
154418
155049
  --rb-surface-link-color: rgb(var(--tb-onPrimary));
155050
+ --rb-surface-link-hover-color: rgb(var(--tb-onPrimary));
155051
+ --rb-surface-link-hover-decoration: underline;
154419
155052
  --rb-surface-supporting-color: color-mix(in oklab, rgb(var(--tb-onPrimary)), transparent 18%);
154420
155053
  }
154421
155054
 
@@ -155239,7 +155872,16 @@ function PageRenderer(props) {
155239
155872
  return React$1.createElement(PageRenderer$1, blocksProps);
155240
155873
  }
155241
155874
  function EditorPageRenderer(props) {
155242
- const commonBlocksProps = toBlocksCommonProps(props);
155875
+ const commonBlocksProps = toBlocksCommonProps({
155876
+ ...props,
155877
+ page: props.page && {
155878
+ ...props.page,
155879
+ blocks: props.page.blocks.map((block) => ({
155880
+ ...block,
155881
+ publishedPlacement: null
155882
+ }))
155883
+ }
155884
+ });
155243
155885
  const blocksProps = isOverrideOnlyEditorPageRenderer(props) ? {
155244
155886
  ...commonBlocksProps,
155245
155887
  rendering: { kind: "overrides-only" },
@@ -155328,7 +155970,7 @@ function resolveSdkBookingTimeZone(timeZone) {
155328
155970
  }
155329
155971
  function buildPageRouteRenderContext(dataContext) {
155330
155972
  return {
155331
- pathname: dataContext.pathname,
155973
+ ...buildPageIdentityRenderContext(dataContext),
155332
155974
  occurrenceContext: dataContext.occurrenceContext ?? null,
155333
155975
  entrySubrouteContext: dataContext.entrySubrouteContext ?? null,
155334
155976
  contentEntry: dataContext.contentEntry ?? null,
@@ -155338,6 +155980,12 @@ function buildPageRouteRenderContext(dataContext) {
155338
155980
  previewStage: dataContext.previewStage
155339
155981
  };
155340
155982
  }
155983
+ function buildPageIdentityRenderContext(dataContext) {
155984
+ return {
155985
+ siteName: dataContext.siteName,
155986
+ pathname: dataContext.pathname
155987
+ };
155988
+ }
155341
155989
  function PageContent(props) {
155342
155990
  const { page, runtimeJoins, siteId, resolvedData, bookingOfferingPresets, mailingList, bookingTimeZone, routeMap, pagesByIdentifier, entriesByIdentifier, wrapBlock, registry, blockOverrides, sdkConfig, customBlocks, supabaseUrl, mediaAssets, apiBaseUrl, portalToken, previewToken, readAuthority, dataContext } = props;
155343
155991
  const rendererCommonProps = {
@@ -155568,6 +156216,9 @@ function getRiverbankEnv() {
155568
156216
  keyType
155569
156217
  };
155570
156218
  }
156219
+ //#endregion
156220
+ //#region src/navigation/index.ts
156221
+ init_src$2();
155571
156222
  /**
155572
156223
  * Get the fixed main navigation menu object.
155573
156224
  * Returns null when the runtime payload is incomplete.
@@ -155613,8 +156264,8 @@ function resolveCheckoutHref(options) {
155613
156264
  return href && href.length > 0 ? href : "/checkout";
155614
156265
  }
155615
156266
  function resolvePortalLabel(link, options) {
155616
- const loggedOutLabel = link.labels?.loggedOut?.trim() || "Login";
155617
- const loggedInLabel = link.labels?.loggedIn?.trim() || "My Account";
156267
+ const loggedOutLabel = link.labels?.loggedOut?.trim() || PORTAL_NAV_DEFAULT_LABELS.loggedOut;
156268
+ const loggedInLabel = link.labels?.loggedIn?.trim() || PORTAL_NAV_DEFAULT_LABELS.loggedIn;
155618
156269
  return options?.hasPortalSession ? loggedInLabel : loggedOutLabel;
155619
156270
  }
155620
156271
  function resolveItemLabel(link, fallbackLabel, options) {
@@ -157948,6 +158599,64 @@ function defineEndpointDefinitions(definitions) {
157948
158599
  return definitions;
157949
158600
  }
157950
158601
  //#endregion
158602
+ //#region ../api/src/apiEndpointTypes.ts
158603
+ function allowedDemoMutationPolicy() {
158604
+ return {
158605
+ classification: "allowed",
158606
+ publicMessage: ""
158607
+ };
158608
+ }
158609
+ function blockedDemoMutationPolicy(classification, publicMessage) {
158610
+ if (publicMessage.trim() === "") throw new Error(`Demo mutation policy ${classification} requires publicMessage.`);
158611
+ return {
158612
+ classification,
158613
+ publicMessage
158614
+ };
158615
+ }
158616
+ //#endregion
158617
+ //#region ../api/src/demoMutationPolicies.ts
158618
+ const DEMO_MUTATION_BLOCKED_HIDDEN = blockedDemoMutationPolicy("blocked-hidden", "This action is not available in demo sites.");
158619
+ const DEMO_MUTATION_BLOCKED_DISABLED = blockedDemoMutationPolicy("blocked-disabled", "This setting is disabled in demo sites.");
158620
+ blockedDemoMutationPolicy("internal-only", "This internal operation is not available in demo sites.");
158621
+ const DEMO_MUTATION_ALLOWED = allowedDemoMutationPolicy();
158622
+ //#endregion
158623
+ //#region ../api/src/siteLifecycleEndpoints.ts
158624
+ const SITE_LIFECYCLE_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
158625
+ createSite: {
158626
+ path: "/sites/manage",
158627
+ method: "POST",
158628
+ tags: ["site"],
158629
+ auth: "user",
158630
+ responseKind: "json",
158631
+ errors: []
158632
+ },
158633
+ createSiteManual: {
158634
+ path: "/sites/manual",
158635
+ method: "POST",
158636
+ tags: ["site"],
158637
+ auth: "user",
158638
+ responseKind: "json",
158639
+ errors: []
158640
+ },
158641
+ updateSite: {
158642
+ path: "/sites/manage",
158643
+ method: "PUT",
158644
+ tags: ["site"],
158645
+ auth: "user",
158646
+ responseKind: "json",
158647
+ errors: []
158648
+ },
158649
+ deleteSite: {
158650
+ path: "/sites/{siteId}",
158651
+ method: "DELETE",
158652
+ tags: ["site", "site-{siteId}"],
158653
+ auth: "user",
158654
+ responseKind: "json",
158655
+ errors: [],
158656
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
158657
+ }
158658
+ });
158659
+ //#endregion
157951
158660
  //#region ../api/src/publicNewsletterEndpointDefinitions.ts
157952
158661
  const PUBLIC_NEWSLETTER_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
157953
158662
  subscribeNewsletter: {
@@ -158007,27 +158716,6 @@ const PUBLIC_NEWSLETTER_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
158007
158716
  responseKind: "text"
158008
158717
  }
158009
158718
  });
158010
- //#endregion
158011
- //#region ../api/src/apiEndpointTypes.ts
158012
- function allowedDemoMutationPolicy() {
158013
- return {
158014
- classification: "allowed",
158015
- publicMessage: ""
158016
- };
158017
- }
158018
- function blockedDemoMutationPolicy(classification, publicMessage) {
158019
- if (publicMessage.trim() === "") throw new Error(`Demo mutation policy ${classification} requires publicMessage.`);
158020
- return {
158021
- classification,
158022
- publicMessage
158023
- };
158024
- }
158025
- //#endregion
158026
- //#region ../api/src/demoMutationPolicies.ts
158027
- const DEMO_MUTATION_BLOCKED_HIDDEN = blockedDemoMutationPolicy("blocked-hidden", "This action is not available in demo sites.");
158028
- const DEMO_MUTATION_BLOCKED_DISABLED = blockedDemoMutationPolicy("blocked-disabled", "This setting is disabled in demo sites.");
158029
- blockedDemoMutationPolicy("internal-only", "This internal operation is not available in demo sites.");
158030
- const DEMO_MUTATION_ALLOWED = allowedDemoMutationPolicy();
158031
158719
  /**
158032
158720
  * Tag templates for endpoint definitions (support `{param}` placeholders).
158033
158721
  */
@@ -159053,6 +159741,20 @@ const NEWSLETTER_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
159053
159741
  responseKind: "json",
159054
159742
  errors: ["auth:forbidden", "server:internal_error"]
159055
159743
  },
159744
+ setMailingListBookingOptIn: {
159745
+ path: "/sites/{siteId}/mailing-list/setup/booking-opt-in",
159746
+ method: "PUT",
159747
+ tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteNewsletter],
159748
+ auth: "user",
159749
+ responseKind: "json",
159750
+ demoMutation: DEMO_MUTATION_BLOCKED_DISABLED,
159751
+ errors: [
159752
+ "auth:forbidden",
159753
+ "validation:invalid_input",
159754
+ "resource:conflict",
159755
+ "server:internal_error"
159756
+ ]
159757
+ },
159056
159758
  getMailingListAuthoringContext: {
159057
159759
  path: "/sites/{siteId}/mailing-list/authoring-context",
159058
159760
  method: "GET",
@@ -160380,6 +161082,54 @@ const BILLING_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
160380
161082
  }
160381
161083
  });
160382
161084
  //#endregion
161085
+ //#region ../api/src/bookingPeopleEndpointDefinitions.ts
161086
+ /**
161087
+ * People endpoints (#1356): the People list, its CSV export, and deleting a
161088
+ * person when nothing is attached to them.
161089
+ */
161090
+ const BOOKING_PEOPLE_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
161091
+ listPeople: {
161092
+ path: "/sites/{siteId}/bookings/people",
161093
+ method: "GET",
161094
+ tags: ["site-{siteId}", "customers-{siteId}"],
161095
+ auth: "user",
161096
+ responseKind: "json",
161097
+ errors: ["server:internal_error"]
161098
+ },
161099
+ exportPeopleCsv: {
161100
+ path: "/sites/{siteId}/bookings/people/export.csv",
161101
+ method: "GET",
161102
+ tags: ["site-{siteId}", "customers-{siteId}"],
161103
+ auth: "user",
161104
+ errors: [],
161105
+ responseKind: "blob"
161106
+ },
161107
+ checkPersonDeletion: {
161108
+ path: "/sites/{siteId}/bookings/people/{personId}/deletion-check",
161109
+ method: "GET",
161110
+ tags: ["site-{siteId}", "customers-{siteId}"],
161111
+ auth: "user",
161112
+ responseKind: "json",
161113
+ errors: [
161114
+ "auth:forbidden",
161115
+ "resource:not_found",
161116
+ "server:internal_error"
161117
+ ]
161118
+ },
161119
+ deletePerson: {
161120
+ path: "/sites/{siteId}/bookings/people/{personId}",
161121
+ method: "DELETE",
161122
+ tags: ["site-{siteId}", "customers-{siteId}"],
161123
+ auth: "user",
161124
+ responseKind: "json",
161125
+ errors: [
161126
+ "auth:forbidden",
161127
+ "resource:not_found",
161128
+ "server:internal_error"
161129
+ ]
161130
+ }
161131
+ });
161132
+ //#endregion
160383
161133
  //#region ../api/src/clientErrorReporting.ts
160384
161134
  const CLIENT_ERROR_REPORT_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({ reportClientError: {
160385
161135
  path: "/client/error-report",
@@ -160415,6 +161165,7 @@ z$1.object({
160415
161165
  sourceLocation: z$1.string().max(CLIENT_ERROR_REPORT_LIMITS.sourceLocation).nullable()
160416
161166
  }).strict();
160417
161167
  ({
161168
+ ...SITE_LIFECYCLE_ENDPOINT_DEFINITIONS,
160418
161169
  ...CLIENT_ERROR_REPORT_ENDPOINT_DEFINITIONS,
160419
161170
  ...PUBLIC_NEWSLETTER_ENDPOINT_DEFINITIONS,
160420
161171
  ...ACCOUNT_ENDPOINT_DEFINITIONS,
@@ -160428,7 +161179,7 @@ z$1.object({
160428
161179
  ...NEWSLETTER_ENDPOINT_DEFINITIONS,
160429
161180
  ...APPOINTMENT_ENDPOINT_DEFINITIONS,
160430
161181
  ...EVENT_SERIES_REGISTRATION_ENDPOINT_DEFINITIONS
160431
- }, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteById, TAG_TEMPLATES.siteBySlug, TAG_TEMPLATES.siteByDomain, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteById, TAG_TEMPLATES.siteBySlug, TAG_TEMPLATES.siteByDomain, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.workflowRunById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.routeById, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.site, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.navigationMenuById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.navigationMenuById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.navigationMenuById, TAG_TEMPLATES.navigationItemById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.navigationMenuById, TAG_TEMPLATES.navigationItemById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.navigationMenuById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.publicEvents, TAG_TEMPLATES.publicBookingServices, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteTheme, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteTheme, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteTheme, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteRedirects, TAG_TEMPLATES.siteRouteOutcomes, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteRedirects, TAG_TEMPLATES.siteRouteOutcomes, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.formSubmissionsBySlug, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.formSubmissionsBySlug, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.formSubmissionsBySlug, TAG_TEMPLATES.siteForms, { ...PUBLIC_BOOKING_AVAILABILITY_ENDPOINT_DEFINITIONS }, TAG_TEMPLATES.publicEventFilters, TAG_TEMPLATES.publicEvents, TAG_TEMPLATES.publicShop, TAG_TEMPLATES.publicCheckout, TAG_TEMPLATES.siteRoutableContent, { ...PUBLIC_EVENT_CHECKOUT_ENDPOINT_DEFINITIONS }, TAG_TEMPLATES.publicEvents, TAG_TEMPLATES.publicEvents, { ...EVENT_MANAGEMENT_ENDPOINT_DEFINITIONS }, { ...SDK_MEDIA_ENDPOINT_DEFINITIONS }, { ...SDK_ENDPOINT_DEFINITIONS }, { ...SDK_PAGE_DESIGN_ENDPOINT_DEFINITIONS }, { ...SDK_EVENT_ENDPOINT_DEFINITIONS }, { ...SDK_ENTRY_READ_ENDPOINTS };
161182
+ }, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteById, TAG_TEMPLATES.siteBySlug, TAG_TEMPLATES.siteByDomain, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteById, TAG_TEMPLATES.siteBySlug, TAG_TEMPLATES.siteByDomain, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.workflowRunById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.routeById, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.site, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.site, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.navigationMenuById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.navigationMenuById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.navigationMenuById, TAG_TEMPLATES.navigationItemById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.navigationMenuById, TAG_TEMPLATES.navigationItemById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteNavigation, TAG_TEMPLATES.navigationMenuById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteSettings, TAG_TEMPLATES.publicEvents, TAG_TEMPLATES.publicBookingServices, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteTheme, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteTheme, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.siteTheme, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteCollection, TAG_TEMPLATES.pageSurfaceById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.pageById, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteRedirects, TAG_TEMPLATES.siteRouteOutcomes, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteRedirects, TAG_TEMPLATES.siteRouteOutcomes, TAG_TEMPLATES.siteRoutableContent, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.formSubmissionsBySlug, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.formSubmissionsBySlug, TAG_TEMPLATES.siteForms, TAG_TEMPLATES.formSubmissionsBySlug, TAG_TEMPLATES.siteForms, { ...PUBLIC_BOOKING_AVAILABILITY_ENDPOINT_DEFINITIONS }, TAG_TEMPLATES.publicEventFilters, TAG_TEMPLATES.publicEvents, TAG_TEMPLATES.publicShop, TAG_TEMPLATES.publicCheckout, TAG_TEMPLATES.siteRoutableContent, { ...PUBLIC_EVENT_CHECKOUT_ENDPOINT_DEFINITIONS }, TAG_TEMPLATES.publicEvents, TAG_TEMPLATES.publicEvents, { ...EVENT_MANAGEMENT_ENDPOINT_DEFINITIONS }, { ...BOOKING_PEOPLE_ENDPOINT_DEFINITIONS }, { ...SDK_MEDIA_ENDPOINT_DEFINITIONS }, { ...SDK_ENDPOINT_DEFINITIONS }, { ...SDK_PAGE_DESIGN_ENDPOINT_DEFINITIONS }, { ...SDK_EVENT_ENDPOINT_DEFINITIONS }, { ...SDK_ENTRY_READ_ENDPOINTS };
160432
161183
  z$1.object({ refreshToken: z$1.string().min(1).max(4096) }).strict();
160433
161184
  z$1.object({
160434
161185
  accessToken: z$1.string().min(1).max(4096),
@@ -163043,15 +163794,14 @@ async function loadPageWithDeps(deps, params) {
163043
163794
  const { client, siteId, path, pageId, preview = false, dataLoaderOverrides, searchParams, forceSite } = params;
163044
163795
  const [site, pageResponse] = await Promise.all([client.getSite({
163045
163796
  id: siteId,
163797
+ currentPath: path,
163046
163798
  ...forceSite ? { force: true } : {}
163047
163799
  }), client.getPage({
163048
163800
  siteId,
163049
163801
  path,
163050
163802
  preview
163051
163803
  })]);
163052
- if ("entry" in pageResponse) throw new Error("This path resolves to a content entry, not a page. Use loadContent() instead, which handles both pages and entries. For entries, loadContent() returns the raw entry data for custom rendering.");
163053
- if ("pageSurface" in pageResponse) throw new Error("This path resolves to a page surface, not a page. Use loadContent() instead, which handles pages, entries, and page surfaces.");
163054
- const { page: pageData } = pageResponse;
163804
+ const pageData = requirePageRecord(pageResponse);
163055
163805
  const support = buildSiteRenderSupport(site, collectMediaAssetSidecar(pageResponse.mediaAssets));
163056
163806
  const previewStage = preview ? "preview" : "published";
163057
163807
  const pageOutline = buildRenderablePageOutline({
@@ -163081,8 +163831,11 @@ async function loadPageWithDeps(deps, params) {
163081
163831
  theme: requireSdkTheme(support.theme, siteId),
163082
163832
  sdkConfig: support.sdkConfig,
163083
163833
  siteId,
163834
+ dataContext: {
163835
+ siteName: support.site.title,
163836
+ previewStage
163837
+ },
163084
163838
  resolvedData,
163085
- dataContext: { previewStage },
163086
163839
  bookingOfferingPresets: support.bookingOfferingPresets,
163087
163840
  mailingList: support.mailingList,
163088
163841
  bookingTimeZone: support.bookingTimeZone,
@@ -163094,6 +163847,11 @@ async function loadPageWithDeps(deps, params) {
163094
163847
  entriesByIdentifier: support.entriesByIdentifier
163095
163848
  };
163096
163849
  }
163850
+ function requirePageRecord(response) {
163851
+ if ("entry" in response) throw new Error("This path resolves to a content entry, not a page. Use loadContent() instead, which handles both pages and entries. For entries, loadContent() returns the raw entry data for custom rendering.");
163852
+ if ("pageSurface" in response) throw new Error("This path resolves to a page surface, not a page. Use loadContent() instead, which handles pages, entries, and page surfaces.");
163853
+ return response.page;
163854
+ }
163097
163855
  const builtInReferenceKindSet = /* @__PURE__ */ new Set([
163098
163856
  "post",
163099
163857
  "form",
@@ -165693,6 +166451,7 @@ function resolveTemplateBlock(block, bindingContext, customBlocks) {
165693
166451
  id: block.id,
165694
166452
  kind: block.blockKind,
165695
166453
  purpose: block.scope === "template" ? "template-layout" : "entry-content",
166454
+ publishedPlacement: null,
165696
166455
  ...isRecord(block.bindings) ? { bindings: block.bindings } : {}
165697
166456
  };
165698
166457
  const manifest = resolveSdkBlockManifest(block.blockKind, customBlocks);
@@ -165858,6 +166617,7 @@ async function loadContentWithDeps(deps, params) {
165858
166617
  const { client, siteId, path, preview = false, forceSite, dataLoaderOverrides, searchParams } = params;
165859
166618
  const [siteResult, contentResult] = await Promise.allSettled([client.getSite({
165860
166619
  id: siteId,
166620
+ currentPath: path,
165861
166621
  ...forceSite ? { force: true } : {}
165862
166622
  }), client.getPage({
165863
166623
  siteId,