@riverbankcms/sdk 0.135.1 → 0.136.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 (152) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/README.md +4 -8
  3. package/dist/{PreviewEditorSidebar-D4p_5TdY.mjs → PreviewEditorSidebar-BU5ZlhQR.mjs} +4 -4
  4. package/dist/{PreviewEditorUI-D0cRoTX1.mjs → PreviewEditorUI-9XkHL-bC.mjs} +3 -3
  5. package/dist/{PreviewQueryProvider-DcgaESkm.mjs → PreviewQueryProvider-wbEpXryy.mjs} +1 -1
  6. package/dist/{SdkPreviewModeRuntime-BKLtM3Nz.mjs → SdkPreviewModeRuntime-CnWmj-2B.mjs} +50 -99
  7. package/dist/{SiteChromeCustomizeContext-61X2m7QV.mjs → SiteChromeCustomizeContext-B6d5zkog.mjs} +2299 -1149
  8. package/dist/_dts/ai/src/contracts/proposals.d.ts +8 -554
  9. package/dist/_dts/ai/src/contracts/siteStyleProposalSchemas.d.ts +401 -2312
  10. package/dist/_dts/api/src/contentRuntime.d.ts +6 -0
  11. package/dist/_dts/api/src/endpoints.d.ts +7 -0
  12. package/dist/_dts/api/src/index.d.ts +1 -0
  13. package/dist/_dts/api/src/publicEventEndpointDefinitions.d.ts +7 -0
  14. package/dist/_dts/api/src/publicExperience/eventEndpoints.d.ts +26 -0
  15. package/dist/_dts/api/src/sdkBlockContentAdmission.d.ts +5 -0
  16. package/dist/_dts/api/src/sdkThemeWire.d.ts +6 -432
  17. package/dist/_dts/block-form/src/blockDraftSaveability.d.ts +2 -3
  18. package/dist/_dts/block-form/src/utils/slug.d.ts +6 -0
  19. package/dist/_dts/blocks/src/PageRenderer.d.ts +12 -6
  20. package/dist/_dts/blocks/src/contracts/proof-block-islands.d.ts +48 -0
  21. package/dist/_dts/blocks/src/definitions.d.ts +14 -0
  22. package/dist/_dts/blocks/src/index.d.ts +4 -3
  23. package/dist/_dts/blocks/src/pageRenderAdmission.d.ts +40 -0
  24. package/dist/_dts/blocks/src/server.d.ts +2 -2
  25. package/dist/_dts/blocks/src/system/data/index.d.ts +2 -0
  26. package/dist/_dts/blocks/src/system/data/publicLoaderCachePolicy.d.ts +78 -0
  27. package/dist/_dts/blocks/src/system/manifest/fieldValidation/index.d.ts +2 -18
  28. package/dist/_dts/blocks/src/system/manifest/validation.d.ts +103 -16
  29. package/dist/_dts/blocks/src/system/node/validation-constants.d.ts +1 -1
  30. package/dist/_dts/blocks/src/system/runtime/api/client.d.ts +2 -1
  31. package/dist/_dts/blocks/src/system/runtime/api/endpoints.d.ts +8 -0
  32. package/dist/_dts/blocks/src/system/runtime/api/index.d.ts +1 -1
  33. package/dist/_dts/blocks/src/system/runtime/api/types/events.d.ts +19 -0
  34. package/dist/_dts/blocks/src/system/runtime/components/registry.client.d.ts +52 -0
  35. package/dist/_dts/blocks/src/system/runtime/components/runtime-backed-blocks.d.ts +24 -0
  36. package/dist/_dts/blocks/src/system/runtime/hooks/useCalendarEvents.d.ts +44 -18
  37. package/dist/_dts/blocks/src/system/runtime/hooks/useCalendarEvents.state.d.ts +20 -3
  38. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/VerifyingTimeoutStep.d.ts +3 -1
  39. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationStripeReturn.d.ts +1 -0
  40. package/dist/_dts/blocks/src/system/runtime/nodes/events/EventCalendar.client.d.ts +2 -2
  41. package/dist/_dts/blocks/src/system/runtime/nodes/events/EventCalendar.interactive.d.ts +40 -0
  42. package/dist/_dts/blocks/src/system/runtime/nodes/events/EventCombined.client.d.ts +2 -0
  43. package/dist/_dts/blocks/src/system/runtime/nodes/events/EventCombined.interactive.d.ts +43 -0
  44. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/CalendarDayCell.d.ts +3 -1
  45. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/CalendarNavigationChevron.d.ts +4 -0
  46. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/DayEventsModal.d.ts +2 -1
  47. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/EventModalContext.d.ts +3 -2
  48. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/WeekAgendaView.d.ts +3 -0
  49. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/WeekBoardView.d.ts +31 -3
  50. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/WeekTimetableView.d.ts +3 -1
  51. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/eventCollectionContract.d.ts +9 -1
  52. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/timetableModel.d.ts +4 -3
  53. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/utils.d.ts +3 -3
  54. package/dist/_dts/blocks/src/system/transforms/registry/layout.d.ts +0 -1
  55. package/dist/_dts/calendar/src/grid.d.ts +24 -66
  56. package/dist/_dts/calendar/src/index.d.ts +2 -2
  57. package/dist/_dts/calendar/src/timetable.d.ts +5 -9
  58. package/dist/_dts/commerce/src/purchase/allocation.d.ts +11 -0
  59. package/dist/_dts/commerce/src/purchase/index.d.ts +2 -0
  60. package/dist/_dts/commerce/src/purchase/settlement.d.ts +33 -0
  61. package/dist/_dts/commerce/src/purchase/stripeCheckoutReturnUrl.d.ts +8 -0
  62. package/dist/_dts/content-model/src/templates/defaults.d.ts +6 -0
  63. package/dist/_dts/core/src/slug.d.ts +20 -5
  64. package/dist/_dts/preview-next/src/client/blocks/EditablePageRenderer.d.ts +1 -1
  65. package/dist/_dts/preview-next/src/client/preview/headerInteractionPaletteSurfaceState.d.ts +2 -1
  66. package/dist/_dts/sdk/src/client/publicLoaderCacheAccess.d.ts +6 -0
  67. package/dist/_dts/sdk/src/public-api/contracts.d.ts +5 -1
  68. package/dist/_dts/sdk/src/rendering/blocks-page-renderer.d.ts +10 -6
  69. package/dist/_dts/sdk/src/rendering/components/Block.shared.d.ts +0 -1
  70. package/dist/_dts/sdk/src/rendering/components/pageShared.d.ts +4 -4
  71. package/dist/_dts/sdk/src/rendering/helpers/footerPageOutline.d.ts +3 -0
  72. package/dist/_dts/sdk/src/rendering/helpers/loadContent.d.ts +3 -0
  73. package/dist/_dts/sdk/src/rendering/helpers/loadPage.d.ts +1 -1
  74. package/dist/_dts/sdk/src/rendering/helpers/pageRuntimeSupport.d.ts +17 -0
  75. package/dist/_dts/sdk/src/rendering/helpers/templateContent.d.ts +9 -3
  76. package/dist/_dts/sdk/src/rendering/hooks/usePage.d.ts +1 -1
  77. package/dist/_dts/sdk/src/rendering/index.d.ts +2 -2
  78. package/dist/_dts/sdk/src/rendering/overrideResolution.d.ts +7 -4
  79. package/dist/_dts/sdk/src/version.d.ts +1 -1
  80. package/dist/_dts/theme-core/src/cards/types.d.ts +8 -8
  81. package/dist/_dts/theme-core/src/data.d.ts +12 -0
  82. package/dist/_dts/theme-core/src/generated/containerResponsiveThemeCss.d.ts +1 -1
  83. package/dist/_dts/theme-core/src/header/legacyHeaderVariant.d.ts +2 -6
  84. package/dist/_dts/theme-core/src/mock-themes/all.d.ts +6 -807
  85. package/dist/_dts/theme-core/src/schema.d.ts +452 -1278
  86. package/dist/_dts/theme-core/src/site-styles/curatedSiteStyles.d.ts +213 -1
  87. package/dist/_dts/theme-core/src/site-styles/headerLayoutCatalog.d.ts +0 -29
  88. package/dist/_dts/theme-core/src/site-styles/headerLayoutStyles.d.ts +10 -0
  89. package/dist/_dts/theme-core/src/site-styles/headerLayoutTypes.d.ts +8 -5
  90. package/dist/_dts/theme-core/src/site-styles/headerOpeningForeground.d.ts +4 -4
  91. package/dist/_dts/theme-core/src/site-styles/headerStyleCompiler.d.ts +16 -2
  92. package/dist/_dts/theme-core/src/site-styles/headerStyleDefaults.d.ts +465 -0
  93. package/dist/_dts/theme-core/src/site-styles/headerStyleRecipe.d.ts +161 -0
  94. package/dist/client/{BookingConsentAgreement-Bz9znbpn.mjs → BookingConsentAgreement-DCch21a6.mjs} +2 -2
  95. package/dist/client/{DiscountCodeDisclosure-35Ru8yB9.mjs → DiscountCodeDisclosure-DIj1T59K.mjs} +1 -1
  96. package/dist/client/{EventCombined.client-BKB0ZxRR.mjs → EventCombined.client-BWVNlXTx.mjs} +226 -206
  97. package/dist/client/{EventListing.client-Dx8I21ok.mjs → EventListing.client-DVFCDe3i.mjs} +2 -2
  98. package/dist/client/{LeafletStaticMap-CEWx-Bhe.mjs → LeafletStaticMap-BY5mIHw9.mjs} +1 -1
  99. package/dist/client/{accordion-KIDsKTwS.mjs → accordion-CK29E8rG.mjs} +1 -1
  100. package/dist/client/{bookingForm-D96Rmp-5.mjs → bookingForm-DFvnet-N.mjs} +5 -5
  101. package/dist/client/bookings.mjs +86 -47
  102. package/dist/client/{carousel-YwUgyL66.mjs → carousel-BVU5NQlb.mjs} +1 -1
  103. package/dist/client/{cart-BbwuNrUT.mjs → cart-BNItcZVa.mjs} +3 -3
  104. package/dist/client/{checkout-hp1ucmEY.mjs → checkout-Bu6iCdkP.mjs} +3 -3
  105. package/dist/client/client.mjs +1950 -1031
  106. package/dist/client/{context-DljQn8L5.mjs → context-BImarOAq.mjs} +12 -0
  107. package/dist/client/{eventCalendar-DU4iNLpo.mjs → eventCalendar-DS2h-UXD.mjs} +256 -114
  108. package/dist/client/{eventCombined-CZuupW8m.mjs → eventCombined-Drt4Oq9p.mjs} +3 -3
  109. package/dist/client/{eventDetails-DPQWwCIi.mjs → eventDetails-Bl2vWgTX.mjs} +4 -3
  110. package/dist/client/{eventListing-C7oMidwS.mjs → eventListing-CS7PHY7v.mjs} +3 -3
  111. package/dist/client/{eventRegistration-zEiunlUs.mjs → eventRegistration-D-j8eNy2.mjs} +85 -41
  112. package/dist/client/{form-D2KIyCVJ.mjs → form-RMpoLTyr.mjs} +2 -2
  113. package/dist/client/{headerSection-CK5uChUK.mjs → headerSection-BYE3Lb3k.mjs} +2 -2
  114. package/dist/client/hooks.mjs +2225 -276
  115. package/dist/client/{locationMap-DLQNH1ln.mjs → locationMap-BxSr7Kkh.mjs} +2 -2
  116. package/dist/client/{newsletterForm-ZuhIG7fZ.mjs → newsletterForm-DerbXwFC.mjs} +2 -2
  117. package/dist/client/{productDetail-7hIcGeae.mjs → productDetail-4SZCLhAf.mjs} +3 -3
  118. package/dist/client/{productList-T4Cii1ot.mjs → productList-D7AP4GNq.mjs} +3 -3
  119. package/dist/client/{propsDecoder-mB0aC_Fi.mjs → propsDecoder-pzBeCh14.mjs} +94 -24
  120. package/dist/client/rendering/client.mjs +758 -464
  121. package/dist/client/rendering/islands.mjs +17 -17
  122. package/dist/client/rendering.mjs +2126 -1244
  123. package/dist/client/{scrollToBlock-Du5mHgvL.mjs → scrollToBlock-CduAKf8T.mjs} +1 -1
  124. package/dist/client/{shop-B5zAcKZn.mjs → shop-Cp5p_kGe.mjs} +6 -6
  125. package/dist/client/{shop-commerce-BKBZB6l5.mjs → shop-commerce-DicXYaYX.mjs} +5 -5
  126. package/dist/client/{shop-commerce-store-Cq4qlNtQ.mjs → shop-commerce-store-CGWnpY4K.mjs} +1 -1
  127. package/dist/client/{shopShared-DYGzEs9D.mjs → shopShared-BDf9ljkm.mjs} +3 -3
  128. package/dist/client/{useEventFilters-Bphkda8m.mjs → useEventFilters-DeeyGYuk.mjs} +3 -3
  129. package/dist/preview-next/before-render.mjs +7 -0
  130. package/dist/preview-next/client/runtime.mjs +4 -4
  131. package/dist/preview-next/keepAlive.mjs +7 -0
  132. package/dist/preview-next/middleware.mjs +7 -0
  133. package/dist/{previewAuthStore-C7ksxt5b.mjs → previewAuthStore-DbqBol0V.mjs} +7 -0
  134. package/dist/{sdk-runtime-BbIC8G4J.mjs → sdk-runtime-19MO27F0.mjs} +2 -2
  135. package/dist/{separator-CadhAtI7.mjs → separator-DaPLtJ1f.mjs} +1 -1
  136. package/dist/server/components.mjs +1527 -893
  137. package/dist/server/config-validation.mjs +65 -113
  138. package/dist/server/config.mjs +65 -113
  139. package/dist/server/data.mjs +65 -112
  140. package/dist/server/index.mjs +122 -4
  141. package/dist/server/manifest.mjs +0 -1
  142. package/dist/server/next.mjs +1432 -708
  143. package/dist/server/page-converter.mjs +58 -91
  144. package/dist/server/prebuild.mjs +1 -1
  145. package/dist/server/rendering/server.mjs +1682 -915
  146. package/dist/server/rendering.mjs +1694 -1020
  147. package/dist/server/routing.mjs +3230 -1843
  148. package/dist/server/server.mjs +21710 -19779
  149. package/dist/server/theme-bridge.mjs +656 -264
  150. package/dist/server/theme.mjs +2 -17
  151. package/dist/styles/index.css +609 -181
  152. package/package.json +1 -1
@@ -8480,12 +8480,8 @@ const legacyHeaderVariantValues = Object.keys(legacyHeaderVariants);
8480
8480
  * `@riverbankcms/api` is `z.input<typeof themeSchema>`, so a widened input here
8481
8481
  * would leak straight into a public type.
8482
8482
  *
8483
- * Not every read of a persisted theme goes through the schema:
8484
- * `resolveRuntimeTheme` in
8485
- * `apps/dashboard/src/server/services/sites/runtimeSiteResponse.ts` returns the
8486
- * raw database JSON asserted as `Theme` with no parse, so a theme still
8487
- * carrying a legacy spelling reaches the theme editor un-aliased. That gap
8488
- * predates this alias and is harmless while persisted usage is zero.
8483
+ * Persisted runtime themes are admitted through `parseThemeForPersistence`
8484
+ * before reaching consumers, so legacy spellings normalize at that boundary.
8489
8485
  */
8490
8486
  const headerVariantWithLegacyAliasSchema = z.enum([...headerVariantValues, ...legacyHeaderVariantValues]).transform((value) => value in legacyHeaderVariants ? legacyHeaderVariants[value] : value);
8491
8487
  const BREAKPOINT_LG = 1024;
@@ -8732,7 +8728,7 @@ const boxBackgroundSchema = z.discriminatedUnion("type", [
8732
8728
  })
8733
8729
  ]);
8734
8730
  function normalizeAuthoringOpacity(value) {
8735
- if (!isRecord$17(value)) return value;
8731
+ if (!isRecord$19(value)) return value;
8736
8732
  return {
8737
8733
  ...value,
8738
8734
  opacity: normalizeOpacity(value.opacity)
@@ -8741,7 +8737,7 @@ function normalizeAuthoringOpacity(value) {
8741
8737
  function normalizeOpacity(value) {
8742
8738
  return typeof value === "number" && value > 1 && value <= 100 ? value / 100 : value;
8743
8739
  }
8744
- function isRecord$17(value) {
8740
+ function isRecord$19(value) {
8745
8741
  return typeof value === "object" && value !== null && !Array.isArray(value);
8746
8742
  }
8747
8743
  //#endregion
@@ -9077,7 +9073,6 @@ const navFontWeight = z.enum([
9077
9073
  "bold"
9078
9074
  ]);
9079
9075
  const headerMaxWidth = z.enum(["container", "full"]);
9080
- const headerBarFrame = z.enum(["full-bleed", "inset-shell"]);
9081
9076
  const headerBorderSchema = componentBorderSchema.extend({ position: z.enum([
9082
9077
  "bottom",
9083
9078
  "top",
@@ -9106,12 +9101,6 @@ const headerLogoTextSchema = z.object({
9106
9101
  ]).optional(),
9107
9102
  hideOnShrink: z.boolean().optional()
9108
9103
  }).optional();
9109
- const navEffectsSchema = z.object({
9110
- underlineGradient: z.boolean().default(false),
9111
- glow: z.boolean().default(false),
9112
- glowColor: z.string().optional(),
9113
- neumorphic: z.boolean().default(false)
9114
- }).optional();
9115
9104
  const dropdownStyleSchema = z.object({
9116
9105
  background: themeColorTokenSchema.default("surface"),
9117
9106
  textColor: themeColorTokenSchema.default("text"),
@@ -9203,9 +9192,7 @@ const headerSchema = z.object({
9203
9192
  positioning: headerPositioning,
9204
9193
  shrinkOnScroll: z.boolean(),
9205
9194
  maxWidth: headerMaxWidth,
9206
- barFrame: headerBarFrame.optional(),
9207
9195
  scrollTreatment: headerScrollTreatmentSchema,
9208
- logoOverride: mediaSchema.nullable().optional(),
9209
9196
  background: headerBackgroundSchema.default({
9210
9197
  type: "color",
9211
9198
  color: "surface"
@@ -9217,13 +9204,11 @@ const headerSchema = z.object({
9217
9204
  navFontRole: z.enum(["body", "heading"]).optional(),
9218
9205
  navTextSize: navLinkStyleSchema.shape.textSize,
9219
9206
  interactionPalette: headerInteractionPaletteSchema.optional(),
9220
- navPlacement: z.enum(["end", "center"]).optional(),
9221
9207
  container: headerContainerSchema,
9222
9208
  border: headerBorderSchema,
9223
9209
  shadow: componentShadowSchema.optional(),
9224
9210
  logo: logoStyleSchema,
9225
9211
  logoText: headerLogoTextSchema,
9226
- navEffects: navEffectsSchema,
9227
9212
  navContainer: navContainerSchema,
9228
9213
  navLinkStyle: navLinkStyleSchema.optional(),
9229
9214
  ctaGap: headerCtaGapSchema.optional(),
@@ -9733,7 +9718,7 @@ function createEventSeriesPageSurfaceSubject(eventSeriesId, bookingScope) {
9733
9718
  };
9734
9719
  }
9735
9720
  function parseEventPageSurfaceSubject(value) {
9736
- if (!isRecord$16(value)) return err({ kind: "notObject" });
9721
+ if (!isRecord$18(value)) return err({ kind: "notObject" });
9737
9722
  switch (value.kind) {
9738
9723
  case "eventSeries": {
9739
9724
  const eventSeriesId = parseEventSeriesId(value.eventSeriesId);
@@ -9778,7 +9763,7 @@ function parseEventPageSurfaceSubject(value) {
9778
9763
  });
9779
9764
  }
9780
9765
  }
9781
- function isRecord$16(value) {
9766
+ function isRecord$18(value) {
9782
9767
  return typeof value === "object" && value !== null && !Array.isArray(value);
9783
9768
  }
9784
9769
  //#endregion
@@ -10527,11 +10512,11 @@ const getImageUrl = (asset, params = {}, basePath = DEFAULT_BASE_PATH) => {
10527
10512
  };
10528
10513
  //#endregion
10529
10514
  //#region ../media-core/src/typeGuards.ts
10530
- function isRecord$15(value) {
10515
+ function isRecord$17(value) {
10531
10516
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
10532
10517
  }
10533
10518
  function asRecord$1(value) {
10534
- return isRecord$15(value) ? value : void 0;
10519
+ return isRecord$17(value) ? value : void 0;
10535
10520
  }
10536
10521
  //#endregion
10537
10522
  //#region ../media-core/src/transformRect.ts
@@ -10644,6 +10629,37 @@ function rotateNormalizedPoint(point, rotation) {
10644
10629
  }
10645
10630
  }
10646
10631
  //#endregion
10632
+ //#region ../media-core/src/mediaRefNormalizer.ts
10633
+ function looksLikeUuid(value) {
10634
+ return typeof value === "string" && /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value);
10635
+ }
10636
+ /**
10637
+ * Strip environment-specific keys from a CMS media object.
10638
+ * @mutates Mutates the passed object in-place.
10639
+ */
10640
+ function deleteEnvSpecificKeys(obj) {
10641
+ delete obj.assetId;
10642
+ delete obj.storageBucket;
10643
+ delete obj.storagePath;
10644
+ delete obj.src;
10645
+ delete obj.mimeType;
10646
+ if (looksLikeUuid(obj.id)) delete obj.id;
10647
+ }
10648
+ //#endregion
10649
+ //#region ../media-core/src/richTextImageCollector.ts
10650
+ function walkAndCollectImageAttrs(value, out, location = "") {
10651
+ if (Array.isArray(value)) {
10652
+ value.forEach((item, index) => walkAndCollectImageAttrs(item, out, `${location}[${index}]`));
10653
+ return;
10654
+ }
10655
+ if (!isRecord$17(value)) return;
10656
+ if (value.type === "image" && isRecord$17(value.attrs)) out.push({
10657
+ attrs: value.attrs,
10658
+ location: location ? `${location}.attrs` : "attrs"
10659
+ });
10660
+ for (const [key, child] of Object.entries(value)) walkAndCollectImageAttrs(child, out, location ? `${location}.${key}` : key);
10661
+ }
10662
+ //#endregion
10647
10663
  //#region ../media-core/src/renderableMediaAsset.ts
10648
10664
  function buildRenderableMediaAssetIndex(assets) {
10649
10665
  if (!assets || assets.length === 0) return void 0;
@@ -12615,7 +12631,7 @@ function getSemanticIconComponent(name) {
12615
12631
  //#endregion
12616
12632
  //#region ../blocks/src/system/icons/value.ts
12617
12633
  const NO_BLOCK_ICON_VALUE = { kind: "none" };
12618
- function isRecord$14(value) {
12634
+ function isRecord$16(value) {
12619
12635
  return typeof value === "object" && value !== null && !Array.isArray(value);
12620
12636
  }
12621
12637
  function parseBlockIconValue(value) {
@@ -12623,7 +12639,7 @@ function parseBlockIconValue(value) {
12623
12639
  kind: "semantic",
12624
12640
  iconId: value
12625
12641
  };
12626
- if (!isRecord$14(value)) return NO_BLOCK_ICON_VALUE;
12642
+ if (!isRecord$16(value)) return NO_BLOCK_ICON_VALUE;
12627
12643
  switch (value.kind) {
12628
12644
  case "none": return NO_BLOCK_ICON_VALUE;
12629
12645
  case "semantic": return isSemanticIconId(value.iconId) ? {
@@ -12696,7 +12712,7 @@ function buildGeneratedBlockIconRenderAssetLookupFromUnknown(value) {
12696
12712
  if (!Array.isArray(value)) return { kind: "invalid_asset_list" };
12697
12713
  const inputs = [];
12698
12714
  for (const [index, item] of value.entries()) {
12699
- if (!isRecord$14(item)) return {
12715
+ if (!isRecord$16(item)) return {
12700
12716
  kind: "invalid_asset_entry",
12701
12717
  index,
12702
12718
  reason: "not_object"
@@ -12760,7 +12776,7 @@ function resolveBlockIconRenderValue(value, generatedAssets = /* @__PURE__ */ ne
12760
12776
  /**
12761
12777
  * Strict record guard: excludes null, primitives, and arrays.
12762
12778
  */
12763
- function isRecord$13(value) {
12779
+ function isRecord$15(value) {
12764
12780
  return typeof value === "object" && value !== null && !Array.isArray(value);
12765
12781
  }
12766
12782
  /**
@@ -12862,15 +12878,78 @@ const PUBLIC_DOWNLOAD_MEDIA_TYPES = [
12862
12878
  ];
12863
12879
  //#endregion
12864
12880
  //#region ../blocks/src/system/manifest/fieldValidation/writeCanonicalization.ts
12881
+ function allGroupChildPlans(plan) {
12882
+ return plan.childSelection.kind === "all" ? plan.childSelection.fields : plan.childSelection.tabs.flatMap((tab) => tab.fields);
12883
+ }
12865
12884
  function selectedGroupChildPlans(plan, value) {
12866
12885
  if (plan.childSelection.kind === "all") return plan.childSelection.fields;
12867
12886
  if (!isPlainObject$5(value)) return [];
12868
12887
  const selectedType = value[plan.childSelection.activeTabField];
12869
12888
  return plan.childSelection.tabs.find((tab) => tab.typeId === selectedType)?.fields ?? [];
12870
12889
  }
12890
+ function canonicalizeObjectForWrite(plans, value) {
12891
+ if (!isPlainObject$5(value)) return value;
12892
+ const canonical = { ...value };
12893
+ for (const plan of plans) {
12894
+ if (!(plan.fieldId in canonical)) continue;
12895
+ canonical[plan.fieldId] = canonicalizeFieldValue(plan, canonical[plan.fieldId]);
12896
+ }
12897
+ return omitUndefined(canonical);
12898
+ }
12899
+ function canonicalizeFieldValue(plan, value) {
12900
+ switch (plan.kind) {
12901
+ case "media": return canonicalizeMedia(value);
12902
+ case "group": return plan.childSelection.kind === "discriminatedTabs" ? canonicalizeDiscriminatedGroup(plan, value) : canonicalizeObjectForWrite(plan.childSelection.fields, value);
12903
+ case "repeater": return canonicalizeRepeater(plan, value);
12904
+ case "string":
12905
+ case "number":
12906
+ case "boolean":
12907
+ case "richText":
12908
+ case "inlineText":
12909
+ case "link":
12910
+ case "select":
12911
+ case "passthrough": return value;
12912
+ }
12913
+ }
12914
+ function canonicalizeMedia(value) {
12915
+ if (!isPlainObject$5(value)) return value;
12916
+ const canonical = { ...value };
12917
+ if (mediaIdentifierSchema.safeParse(canonical.identifier).success) deleteEnvSpecificKeys(canonical);
12918
+ return canonical;
12919
+ }
12920
+ function canonicalizeRepeater(plan, value) {
12921
+ if (!isUnknownArray$2(value)) return value;
12922
+ return value.map((item) => {
12923
+ if (!isPlainObject$5(item)) return item;
12924
+ const childPlans = plan.repeatedItemVariants ? plan.repeatedItemVariants.find((variant) => variant.typeId === item._type)?.fields : plan.repeatedItemPlan;
12925
+ return childPlans ? canonicalizeObjectForWrite(childPlans, item) : item;
12926
+ });
12927
+ }
12928
+ function canonicalizeDiscriminatedGroup(plan, value) {
12929
+ if (!isPlainObject$5(value) || plan.childSelection.kind !== "discriminatedTabs") return value;
12930
+ const selection = plan.childSelection;
12931
+ const selectedPlans = selectedGroupChildPlans(plan, value);
12932
+ const selectedIds = rootFieldIds(selectedPlans);
12933
+ const allChildIds = rootFieldIds(allGroupChildPlans(plan));
12934
+ const canonical = omitUndefined(canonicalizeObjectForWrite(selectedPlans, Object.fromEntries(Object.entries(value).filter(([key]) => key === selection.activeTabField || selectedIds.has(key) || !allChildIds.has(key)))));
12935
+ if (plan.valueContract !== "boxBackground") return canonical;
12936
+ const parsed = boxBackgroundSchema.safeParse(canonical);
12937
+ return parsed.success ? parsed.data : canonical;
12938
+ }
12939
+ function rootFieldIds(plans) {
12940
+ return new Set(plans.map((child) => child.fieldId.split(".")[0] ?? child.fieldId));
12941
+ }
12942
+ function omitUndefined(value) {
12943
+ if (isUnknownArray$2(value)) return value.map(omitUndefined);
12944
+ if (!isPlainObject$5(value)) return value;
12945
+ return Object.fromEntries(Object.entries(value).filter(([, field]) => field !== void 0).map(([key, field]) => [key, omitUndefined(field)]));
12946
+ }
12871
12947
  function isPlainObject$5(value) {
12872
12948
  return typeof value === "object" && value !== null && !Array.isArray(value);
12873
12949
  }
12950
+ function isUnknownArray$2(value) {
12951
+ return Array.isArray(value);
12952
+ }
12874
12953
  //#endregion
12875
12954
  //#region ../blocks/src/system/manifest/fieldValidation/index.ts
12876
12955
  const TEL_RE = /^[+()0-9\s-]{3,}$/;
@@ -12889,6 +12968,12 @@ function validationContext(options = {}) {
12889
12968
  allowIncomplete: isDraft || (options.allowIncomplete ?? false)
12890
12969
  };
12891
12970
  }
12971
+ function strictValidationContext(options = {}) {
12972
+ return {
12973
+ ...validationContext(options),
12974
+ allowNull: options.allowNull ?? false
12975
+ };
12976
+ }
12892
12977
  function formatFieldPath(path) {
12893
12978
  return path.map((segment) => String(segment)).join(".");
12894
12979
  }
@@ -13144,6 +13229,15 @@ function normalizeStoredContentValues(plans, content, options = {}) {
13144
13229
  normalizeInlineTextFallbacks(plans, normalized, ctx);
13145
13230
  return normalized;
13146
13231
  }
13232
+ /**
13233
+ * Produces the portable representation accepted by content persistence.
13234
+ * Runtime-hydrated media fields are stripped only when a canonical identifier
13235
+ * is already present; unresolved environment-specific references remain
13236
+ * invalid and must be handled by the site-scoped media write normalizer first.
13237
+ */
13238
+ function normalizeManifestContentForWrite(plans, content, options = {}) {
13239
+ return canonicalizeObjectForWrite(plans, normalizeStoredContentValues(plans, content, options));
13240
+ }
13147
13241
  function normalizeStoredFieldValueWithContext(plan, value, ctx) {
13148
13242
  if (value === null && !plan.required) return;
13149
13243
  switch (plan.kind) {
@@ -13477,6 +13571,14 @@ function fieldPlanToObjectPropertyZod(plan, options = {}) {
13477
13571
  default: return assertNever$2(presence);
13478
13572
  }
13479
13573
  }
13574
+ /** Validate stored field values without applying editor/write normalization. */
13575
+ function fieldPlanToStoredObjectPropertyZod(plan) {
13576
+ const ctx = strictValidationContext({ allowNull: false });
13577
+ const schema = z.any().superRefine((value, zodCtx) => {
13578
+ for (const validationIssue of validateNormalizedFieldValue(plan, value, ctx)) addFieldIssueToZodContext(zodCtx, validationIssue, plan.path);
13579
+ });
13580
+ return plan.required ? schema : schema.optional();
13581
+ }
13480
13582
  function addFieldIssueToZodContext(zodCtx, validationIssue, rootPath) {
13481
13583
  const message = fieldIssueToMessage(validationIssue);
13482
13584
  const path = relativeZodIssuePath(validationIssue.path, rootPath);
@@ -13658,6 +13760,7 @@ function registerManifest(manifest) {
13658
13760
  }
13659
13761
  //#endregion
13660
13762
  //#region ../blocks/src/system/manifest/validation.ts
13763
+ const compiledManifestContentContract = Symbol("compiledManifestContentContract");
13661
13764
  /**
13662
13765
  * Preprocess content by converting empty values to undefined.
13663
13766
  * Used in draft mode to allow required fields to be temporarily empty.
@@ -13668,13 +13771,59 @@ function preprocessEmptyValues(content) {
13668
13771
  for (const [key, value] of Object.entries(content)) result[key] = isEmptyValue(value) ? void 0 : value;
13669
13772
  return result;
13670
13773
  }
13671
- function createManifestValidator(manifestOrFields, options = {}) {
13672
- return createManifestValidatorWithNormalizer(manifestOrFields, options, normalizeStoredContentValues);
13774
+ /**
13775
+ * Compiles editor-facing manifest structure into the presentation-independent
13776
+ * validation contract used by every manifest-content trust transition.
13777
+ */
13778
+ function compileManifestContentContract(manifestOrFields) {
13779
+ const plans = derivePlansFromManifestOrFields(manifestOrFields);
13780
+ const strictOptions = { allowNull: false };
13781
+ const strictStoredSchema = deriveStrictStoredZodFromPlans(plans);
13782
+ return Object.freeze({ [compiledManifestContentContract]: Object.freeze({
13783
+ plans,
13784
+ strictStoredSchema,
13785
+ writeSchema: deriveNormalizedContentZodFromPlans(plans, strictOptions, normalizeManifestContentForWrite).transform((value) => canonicalizeObjectForWrite(plans, value)),
13786
+ draftSchema: deriveNormalizedContentZodFromPlans(plans, {
13787
+ allowNull: true,
13788
+ allowIncomplete: true,
13789
+ mode: "draft"
13790
+ }, normalizeStoredContentValues),
13791
+ renderSchema: strictStoredSchema,
13792
+ findNonPortableMediaPaths: (content) => findNonPortableMediaPaths(plans, content)
13793
+ }) });
13673
13794
  }
13674
- function createManifestValidatorWithNormalizer(manifestOrFields, options, normalize) {
13675
- return createManifestValidatorFromPlans(derivePlansFromManifestOrFields(manifestOrFields), options, normalize);
13795
+ /** Validates raw editor state without granting a stored-content proof. */
13796
+ function validateManifestDraft(contract, data) {
13797
+ const parsed = contract[compiledManifestContentContract].draftSchema.safeParse(data);
13798
+ if (parsed.success) return {
13799
+ kind: "previewable",
13800
+ data,
13801
+ issues: []
13802
+ };
13803
+ const [firstIssue, ...remainingIssues] = zodAdmissionIssues(parsed.error);
13804
+ if (!firstIssue) throw new Error("Draft manifest validation failed without an issue");
13805
+ return {
13806
+ kind: "invalid",
13807
+ data,
13808
+ issues: [firstIssue, ...remainingIssues]
13809
+ };
13676
13810
  }
13677
- function createManifestValidatorFromPlans(plans, options, normalize) {
13811
+ /**
13812
+ * Re-admits renderable content after a transport boundary has erased its
13813
+ * compile-time proof. Unlike write admission, this never canonicalizes or
13814
+ * grants a stored proof, so hydrated media cannot flow back to persistence.
13815
+ */
13816
+ function admitTransportedRenderableManifestContent(contract, content) {
13817
+ const parsed = contract[compiledManifestContentContract].renderSchema.safeParse(content);
13818
+ return parsed.success ? {
13819
+ ok: true,
13820
+ value: content
13821
+ } : {
13822
+ ok: false,
13823
+ error: zodAdmissionError(parsed.error)
13824
+ };
13825
+ }
13826
+ function deriveNormalizedContentZodFromPlans(plans, options, normalize) {
13678
13827
  const isDraft = options.mode === "draft";
13679
13828
  const baseSchema = deriveContentZodFromPlans(plans, options);
13680
13829
  if (isDraft) return z.preprocess((content) => preprocessEmptyValues(normalize(plans, content, options)), baseSchema);
@@ -13685,9 +13834,81 @@ function deriveContentZodFromPlans(plans, options) {
13685
13834
  for (const plan of plans) shape[plan.fieldId] = fieldPlanToObjectPropertyZod(plan, options);
13686
13835
  return z.object(shape).catchall(z.unknown()).passthrough();
13687
13836
  }
13837
+ function deriveStrictStoredZodFromPlans(plans) {
13838
+ const shape = {};
13839
+ for (const plan of plans) shape[plan.fieldId] = fieldPlanToStoredObjectPropertyZod(plan);
13840
+ return z.object(shape).catchall(z.unknown()).passthrough();
13841
+ }
13688
13842
  function derivePlansFromManifestOrFields(manifestOrFields) {
13689
13843
  return deriveFieldValidationPlans(Array.isArray(manifestOrFields) ? manifestOrFields : manifestOrFields.fields ?? []);
13690
13844
  }
13845
+ function zodAdmissionError(error) {
13846
+ return {
13847
+ kind: "invalid_shape",
13848
+ issues: zodAdmissionIssues(error)
13849
+ };
13850
+ }
13851
+ function zodAdmissionIssues(error) {
13852
+ return error.issues.map((issue) => ({
13853
+ code: issue.code,
13854
+ path: issue.path.map((segment) => typeof segment === "number" ? segment : String(segment)),
13855
+ message: issue.message
13856
+ }));
13857
+ }
13858
+ function findNonPortableMediaPaths(plans, content) {
13859
+ const paths = /* @__PURE__ */ new Set();
13860
+ collectNonPortablePlannedMedia(plans, content, [], paths);
13861
+ return [...paths].sort();
13862
+ }
13863
+ function collectNonPortablePlannedMedia(plans, content, parentPath, paths) {
13864
+ if (!isPlainRecord(content)) return;
13865
+ for (const plan of plans) {
13866
+ if (!(plan.fieldId in content)) continue;
13867
+ const value = content[plan.fieldId];
13868
+ const path = [...parentPath, plan.fieldId];
13869
+ switch (plan.kind) {
13870
+ case "media":
13871
+ if (isPlainRecord(value) && hasEnvironmentSpecificMediaField(value)) paths.add(formatFieldPath(path));
13872
+ break;
13873
+ case "richText":
13874
+ collectNonPortableRichTextImages(value, path, paths);
13875
+ break;
13876
+ case "group":
13877
+ collectNonPortablePlannedMedia(selectedGroupChildPlans(plan, value), value, path, paths);
13878
+ break;
13879
+ case "repeater":
13880
+ collectNonPortableRepeaterMedia(plan, value, path, paths);
13881
+ break;
13882
+ case "string":
13883
+ case "number":
13884
+ case "boolean":
13885
+ case "inlineText":
13886
+ case "link":
13887
+ case "select":
13888
+ case "passthrough": break;
13889
+ }
13890
+ }
13891
+ }
13892
+ function collectNonPortableRepeaterMedia(plan, value, path, paths) {
13893
+ if (!Array.isArray(value)) return;
13894
+ value.forEach((item, index) => {
13895
+ if (!isPlainRecord(item)) return;
13896
+ const childPlans = plan.repeatedItemVariants ? plan.repeatedItemVariants.find((variant) => variant.typeId === item._type)?.fields : plan.repeatedItemPlan;
13897
+ if (childPlans) collectNonPortablePlannedMedia(childPlans, item, [...path, index], paths);
13898
+ });
13899
+ }
13900
+ function collectNonPortableRichTextImages(value, path, paths) {
13901
+ const images = [];
13902
+ walkAndCollectImageAttrs(value, images);
13903
+ const prefix = formatFieldPath(path);
13904
+ for (const reference of images) if (hasEnvironmentSpecificMediaField(reference.attrs)) paths.add(reference.location ? `${prefix}.${reference.location}` : prefix);
13905
+ }
13906
+ function isPlainRecord(value) {
13907
+ return typeof value === "object" && value !== null && !Array.isArray(value);
13908
+ }
13909
+ function hasEnvironmentSpecificMediaField(value) {
13910
+ return "assetId" in value || "storageBucket" in value || "storagePath" in value || "src" in value || "mimeType" in value || looksLikeUuid(value.id);
13911
+ }
13691
13912
  //#endregion
13692
13913
  //#region ../blocks/src/system/manifest/variantKey.ts
13693
13914
  /**
@@ -16880,27 +17101,6 @@ function asHeaderStyleId(value) {
16880
17101
  return value;
16881
17102
  }
16882
17103
  //#endregion
16883
- //#region ../theme-core/src/site-styles/headerInteractionPalette.ts
16884
- const clearSplitInteractionPalette = defineLookOptionGroup({
16885
- id: "interaction-palette",
16886
- label: "Hover colour",
16887
- defaultOptionId: "accent",
16888
- options: [
16889
- {
16890
- id: "accent",
16891
- label: "Accent"
16892
- },
16893
- {
16894
- id: "primary",
16895
- label: "Primary"
16896
- },
16897
- {
16898
- id: "secondary",
16899
- label: "Secondary"
16900
- }
16901
- ]
16902
- });
16903
- //#endregion
16904
17104
  //#region ../theme-core/src/site-styles/headerLayoutCatalog.ts
16905
17105
  const titleOnlyLogoAccommodation = {
16906
17106
  pattern: "title-only",
@@ -17060,43 +17260,37 @@ const headerStyleCatalog = defineExactCatalog()([
17060
17260
  id: asHeaderStyleId("minimal"),
17061
17261
  label: "Minimal",
17062
17262
  description: "Quiet surface with simple color-change navigation.",
17063
- supportedLayoutIds: supportedLayouts(["classic", "centered"]),
17064
- navTypography: "plain"
17263
+ supportedLayoutIds: supportedLayouts(["classic", "centered"])
17065
17264
  },
17066
17265
  {
17067
17266
  id: asHeaderStyleId("fine-line"),
17068
17267
  label: "Seamless",
17069
17268
  description: "Borderless surface with underline hover for a quieter page transition.",
17070
- supportedLayoutIds: supportedLayouts(["classic", "centered"]),
17071
- navTypography: "plain"
17269
+ supportedLayoutIds: supportedLayouts(["classic", "centered"])
17072
17270
  },
17073
17271
  {
17074
17272
  id: asHeaderStyleId("soft-bar"),
17075
17273
  label: "Soft Bar",
17076
17274
  description: "Soft tinted surface with gentle pill hover states.",
17077
- supportedLayoutIds: supportedLayouts(["classic", "centered"]),
17078
- navTypography: "plain"
17275
+ supportedLayoutIds: supportedLayouts(["classic", "centered"])
17079
17276
  },
17080
17277
  {
17081
17278
  id: asHeaderStyleId("pill-nav"),
17082
17279
  label: "Pill Nav",
17083
17280
  description: "A calm pill navigation rail over a neutral header.",
17084
- supportedLayoutIds: supportedLayouts(["classic", "centered"]),
17085
- navTypography: "plain"
17281
+ supportedLayoutIds: supportedLayouts(["classic", "centered"])
17086
17282
  },
17087
17283
  {
17088
17284
  id: asHeaderStyleId("brand-bar"),
17089
17285
  label: "Brand Bar",
17090
17286
  description: "Solid brand surface with high-contrast navigation.",
17091
- supportedLayoutIds: supportedLayouts(["classic", "centered"]),
17092
- navTypography: "brand-caps"
17287
+ supportedLayoutIds: supportedLayouts(["classic", "centered"])
17093
17288
  },
17094
17289
  {
17095
17290
  id: asHeaderStyleId("brand-underline"),
17096
17291
  label: "Brand Underline",
17097
17292
  description: "Brand surface with underline-grow navigation.",
17098
- supportedLayoutIds: supportedLayouts(["classic"]),
17099
- navTypography: "brand-caps"
17293
+ supportedLayoutIds: supportedLayouts(["classic"])
17100
17294
  },
17101
17295
  {
17102
17296
  id: asHeaderStyleId("brand-pill"),
@@ -17106,73 +17300,78 @@ const headerStyleCatalog = defineExactCatalog()([
17106
17300
  "classic",
17107
17301
  "centered",
17108
17302
  "floating"
17109
- ]),
17110
- navTypography: "brand-caps"
17303
+ ])
17111
17304
  },
17112
17305
  {
17113
17306
  id: asHeaderStyleId("brand-capsule"),
17114
17307
  label: "Brand Capsule",
17115
17308
  description: "Solid brand chrome designed as a floating capsule, with quiet-caps nav, a soft pill active state, and an inverted CTA pill.",
17116
- supportedLayoutIds: supportedLayouts(["classic"]),
17117
- navTypography: "quiet-caps"
17309
+ supportedLayoutIds: supportedLayouts(["classic"])
17118
17310
  },
17119
17311
  {
17120
17312
  id: asHeaderStyleId("serif-line"),
17121
17313
  label: "Serif Line",
17122
17314
  description: "Typographic logo treatment with understated underline navigation.",
17123
- supportedLayoutIds: supportedLayouts(["classic", "centered"]),
17124
- navTypography: "heading"
17315
+ supportedLayoutIds: supportedLayouts(["classic", "centered"])
17125
17316
  },
17126
17317
  {
17127
17318
  id: asHeaderStyleId("flat-tabs"),
17128
17319
  label: "Flat Tabs",
17129
17320
  description: "Flat block hover and active states with a Swiss utility feel.",
17130
- supportedLayoutIds: supportedLayouts(["classic", "centered"]),
17131
- navTypography: "quiet-caps"
17321
+ supportedLayoutIds: supportedLayouts(["classic", "centered"])
17132
17322
  },
17133
17323
  {
17134
17324
  id: asHeaderStyleId("glass"),
17135
17325
  label: "Glass",
17136
17326
  description: "Translucent chrome with frosted navigation backing.",
17137
- supportedLayoutIds: supportedLayouts(["floating"]),
17138
- navTypography: "plain"
17327
+ supportedLayoutIds: supportedLayouts(["floating"])
17139
17328
  },
17140
17329
  {
17141
17330
  id: asHeaderStyleId("minimal-surface"),
17142
17331
  label: "Clear Split",
17143
17332
  description: "Floating logo with transparent navigation and no shared shell.",
17144
- supportedLayoutIds: supportedLayouts(["floating"]),
17145
- navTypography: "plain",
17146
- openingForegroundTarget: "all",
17147
- scrollTreatment: "contrast-glass",
17148
- interactionPalette: clearSplitInteractionPalette
17333
+ supportedLayoutIds: supportedLayouts(["floating"])
17149
17334
  },
17150
17335
  {
17151
17336
  id: asHeaderStyleId("soft-shell"),
17152
17337
  label: "Soft Shell",
17153
17338
  description: "Floating rounded shell with soft pill navigation states.",
17154
- supportedLayoutIds: supportedLayouts(["floating"]),
17155
- navTypography: "plain"
17339
+ supportedLayoutIds: supportedLayouts(["floating"])
17156
17340
  },
17157
17341
  {
17158
17342
  id: asHeaderStyleId("split-glass"),
17159
17343
  label: "Split Glass",
17160
17344
  description: "Logo floats independently while the navigation sits in a glass rail.",
17161
- supportedLayoutIds: supportedLayouts(["floating"]),
17162
- navTypography: "quiet-caps",
17163
- openingForegroundTarget: "brand-only"
17345
+ supportedLayoutIds: supportedLayouts(["floating"])
17164
17346
  },
17165
17347
  {
17166
17348
  id: asHeaderStyleId("split-pill"),
17167
17349
  label: "Split Pill",
17168
17350
  description: "Logo floats independently with a soft pill-backed navigation rail.",
17169
- supportedLayoutIds: supportedLayouts(["floating"]),
17170
- navTypography: "heading",
17171
- openingForegroundTarget: "brand-only"
17351
+ supportedLayoutIds: supportedLayouts(["floating"])
17172
17352
  }
17173
17353
  ]);
17174
17354
  new Map(headerLayoutCatalog.map((layout) => [layout.id, layout]));
17175
17355
  new Map(headerStyleCatalog.map((style) => [style.id, style]));
17356
+ defineLookOptionGroup({
17357
+ id: "interaction-palette",
17358
+ label: "Hover colour",
17359
+ defaultOptionId: "accent",
17360
+ options: [
17361
+ {
17362
+ id: "accent",
17363
+ label: "Accent"
17364
+ },
17365
+ {
17366
+ id: "primary",
17367
+ label: "Primary"
17368
+ },
17369
+ {
17370
+ id: "secondary",
17371
+ label: "Secondary"
17372
+ }
17373
+ ]
17374
+ });
17176
17375
  //#endregion
17177
17376
  //#region ../theme-core/src/site-styles/footerLooks.ts
17178
17377
  function asFooterLookId(value) {
@@ -27860,26 +28059,6 @@ const headerLogoTextVisibleTransform = {
27860
28059
  return resolveHeaderBrandDisplay(asPartialObject(value)) !== "logo-only";
27861
28060
  }
27862
28061
  };
27863
- /**
27864
- * Selects which classic-layout nav row should render.
27865
- *
27866
- * - `'inline'` → classic variant with the historical logo-left / nav-right row
27867
- * - `'centered'`→ classic variant with a centred (flex-1) nav and a right CTA
27868
- * - `'other'` → not a classic variant (centered/floating handle it)
27869
- *
27870
- * Consumed by the site-header block's `$when` gates so the two classic rows are
27871
- * mutually exclusive without introducing a new top-level header variant.
27872
- */
27873
- const classicNavModeTransform = {
27874
- id: "layout.classicNavMode",
27875
- kind: "formatter",
27876
- summary: "Resolve which classic-layout nav row to render",
27877
- run: (value) => {
27878
- const header = asPartialObject(value);
27879
- if (header?.variant !== "classic") return "other";
27880
- return header?.navPlacement === "center" ? "centered" : "inline";
27881
- }
27882
- };
27883
28062
  const maxWidthClassTransform = {
27884
28063
  id: "layout.maxWidthClass",
27885
28064
  kind: "string",
@@ -27985,7 +28164,6 @@ const headerRootClassTransform = {
27985
28164
  if (isHeaderScrollRuntimeEnabled(content)) classes.push(config.shrink);
27986
28165
  const variant = header?.variant;
27987
28166
  if (variant && headerVariantValues.includes(variant)) classes.push(`header-variant-${variant}`);
27988
- if (header?.barFrame === "inset-shell" && variant === "classic") classes.push("header-bar-frame-inset-shell");
27989
28167
  return joinClasses$2(classes);
27990
28168
  }
27991
28169
  };
@@ -28193,7 +28371,6 @@ const layoutTransforms = [
28193
28371
  headerLogoClassTransform,
28194
28372
  headerLogoMediaClassTransform,
28195
28373
  headerLogoTextVisibleTransform,
28196
- classicNavModeTransform,
28197
28374
  footerRootClassTransform,
28198
28375
  headerRootStyleTransform,
28199
28376
  headerSectionBackgroundTransform,
@@ -28275,16 +28452,16 @@ const interpolateRichTextTokensOptionsSchema = z.object({ tokens: z.array(suppor
28275
28452
  const richTextTokenPattern = /\{\{\s*([a-zA-Z0-9_]+)\s*\}\}/g;
28276
28453
  function getSiteName(context) {
28277
28454
  const viewModel = context.viewModel;
28278
- if (!isRecord$13(viewModel)) return null;
28455
+ if (!isRecord$15(viewModel)) return null;
28279
28456
  const site = viewModel.site;
28280
- if (isRecord$13(site) && typeof site.title === "string") {
28457
+ if (isRecord$15(site) && typeof site.title === "string") {
28281
28458
  const title = site.title.trim();
28282
28459
  return title.length > 0 ? title : null;
28283
28460
  }
28284
28461
  const root = viewModel.$root;
28285
- if (isRecord$13(root)) {
28462
+ if (isRecord$15(root)) {
28286
28463
  const rootSite = root.site;
28287
- if (isRecord$13(rootSite) && typeof rootSite.title === "string") {
28464
+ if (isRecord$15(rootSite) && typeof rootSite.title === "string") {
28288
28465
  const title = rootSite.title.trim();
28289
28466
  if (title.length > 0) return title;
28290
28467
  }
@@ -28306,7 +28483,7 @@ function replaceTokenText(input, allowedTokens, tokenValues) {
28306
28483
  });
28307
28484
  }
28308
28485
  function visitRichTextNode(node, allowedTokens, tokenValues) {
28309
- if (!isRecord$13(node)) return node;
28486
+ if (!isRecord$15(node)) return node;
28310
28487
  let changed = false;
28311
28488
  const nextNode = { ...node };
28312
28489
  if (nextNode.type === "text" && typeof nextNode.text === "string") {
@@ -28327,7 +28504,7 @@ function visitRichTextNode(node, allowedTokens, tokenValues) {
28327
28504
  return changed ? nextNode : node;
28328
28505
  }
28329
28506
  function interpolateRichTextTokens(value, options, context) {
28330
- if (!isRecord$13(value)) return value;
28507
+ if (!isRecord$15(value)) return value;
28331
28508
  return visitRichTextNode(value, new Set(options.tokens), {
28332
28509
  year: String((/* @__PURE__ */ new Date()).getFullYear()),
28333
28510
  site_name: getSiteName(context)
@@ -28608,18 +28785,7 @@ const classicLayout = inline({
28608
28785
  logoRow,
28609
28786
  createNavRow(`rb-ml-auto ${desktopOnlyDisplay("flex")} rb-gap-6`),
28610
28787
  headerCta
28611
- ], whenTransformed("$root.theme.header", "layout.classicNavMode", "inline"));
28612
- const classicCenteredNavLayout = inline({
28613
- className: bindProp("$root.theme.header.maxWidth", {
28614
- transforms: pipe(tx("layout.maxWidthClass", { base: `rb-header-layout ${desktopOnlyDisplay("flex")} rb-w-full rb-items-center rb-gap-6` })),
28615
- fallback: `rb-container rb-header-layout ${desktopOnlyDisplay("flex")} rb-w-full rb-items-center rb-gap-6`
28616
- }),
28617
- align: "center"
28618
- }, [
28619
- logoRow,
28620
- createNavRow(`rb-flex-1 rb-justify-center ${desktopOnlyDisplay("flex")} rb-gap-6`, "center"),
28621
- headerCta
28622
- ], whenTransformed("$root.theme.header", "layout.classicNavMode", "centered"));
28788
+ ], when("$root.theme.header.variant", { equals: "classic" }));
28623
28789
  const centeredLayout = stack({
28624
28790
  gap: "md",
28625
28791
  align: "center",
@@ -28684,7 +28850,6 @@ const siteHeaderManifest = createBlockManifest({
28684
28850
  }, [
28685
28851
  mobileHeaderBar,
28686
28852
  classicLayout,
28687
- classicCenteredNavLayout,
28688
28853
  centeredLayout,
28689
28854
  floatingLayout,
28690
28855
  mobileOverlay
@@ -31719,11 +31884,11 @@ function planEventRegistrationScope(input) {
31719
31884
  }
31720
31885
  //#endregion
31721
31886
  //#region ../blocks/src/system/runtime/nodes/events/shared/destination.ts
31722
- function isRecord$12(value) {
31887
+ function isRecord$14(value) {
31723
31888
  return typeof value === "object" && value !== null && !Array.isArray(value);
31724
31889
  }
31725
31890
  function isRuntimeEventDestination(value) {
31726
- if (!isRecord$12(value) || typeof value.kind !== "string") return false;
31891
+ if (!isRecord$14(value) || typeof value.kind !== "string") return false;
31727
31892
  if (value.kind === "native") return (value.mode === "cms-managed" || value.mode === "system-managed") && typeof value.path === "string";
31728
31893
  return value.kind === "external" && typeof value.url === "string" && typeof value.label === "string";
31729
31894
  }
@@ -31786,15 +31951,15 @@ function resolveRuntimeEventPricing(event) {
31786
31951
  function readCurrency(value) {
31787
31952
  return typeof value === "string" && value.trim().length > 0 ? value : DEFAULT_EVENT_CURRENCY;
31788
31953
  }
31789
- function isRecord$11(value) {
31954
+ function isRecord$13(value) {
31790
31955
  return typeof value === "object" && value !== null && !Array.isArray(value);
31791
31956
  }
31792
31957
  function isPublicEventPricing(value) {
31793
- if (!isRecord$11(value) || typeof value.kind !== "string") return false;
31958
+ if (!isRecord$13(value) || typeof value.kind !== "string") return false;
31794
31959
  return value.kind === "drop_in" || value.kind === "free_registration" || value.kind === "single_paid" || value.kind === "sliding_scale" || value.kind === "ticket_types" || value.kind === "whole_series" || value.kind === "external";
31795
31960
  }
31796
31961
  function isPublicEventTicketType(value) {
31797
- return isRecord$11(value) && typeof value.id === "string";
31962
+ return isRecord$13(value) && typeof value.id === "string";
31798
31963
  }
31799
31964
  function readTicketTypePriceDisplay(value, currency) {
31800
31965
  const display = readLegacyPriceDisplay(value, currency);
@@ -31804,7 +31969,7 @@ function readTicketTypePriceDisplay(value, currency) {
31804
31969
  } : display;
31805
31970
  }
31806
31971
  function readLegacyPriceDisplay(value, currency) {
31807
- if (!isRecord$11(value) || typeof value.kind !== "string") return {
31972
+ if (!isRecord$13(value) || typeof value.kind !== "string") return {
31808
31973
  kind: "unavailable",
31809
31974
  currency
31810
31975
  };
@@ -31856,7 +32021,7 @@ function readLegacyPriceDisplay(value, currency) {
31856
32021
  kind: "unavailable",
31857
32022
  currency: displayCurrency
31858
32023
  };
31859
- case "whole_series": return isRecord$11(value.display) ? {
32024
+ case "whole_series": return isRecord$13(value.display) ? {
31860
32025
  kind: "whole_series",
31861
32026
  display: readCoursePriceDisplay(value.display, displayCurrency)
31862
32027
  } : {
@@ -32317,14 +32482,14 @@ const eventRegistrationBlockRuntime = defineClientOwnedBlockRuntime({
32317
32482
  }
32318
32483
  });
32319
32484
  function normalizeEventRegistrationEventInput(value) {
32320
- if (!isRecord$10(value)) return value;
32485
+ if (!isRecord$12(value)) return value;
32321
32486
  return {
32322
32487
  ...value,
32323
32488
  destination: resolveRuntimeEventDestination(value),
32324
32489
  pricing: resolveRuntimeEventPricing(value)
32325
32490
  };
32326
32491
  }
32327
- function isRecord$10(value) {
32492
+ function isRecord$12(value) {
32328
32493
  return typeof value === "object" && value !== null && !Array.isArray(value);
32329
32494
  }
32330
32495
  function buildEventRegistrationInteractiveIslandProps(props) {
@@ -33015,67 +33180,49 @@ const MONTH_NAMES = [
33015
33180
  "November",
33016
33181
  "December"
33017
33182
  ];
33018
- /** Format a date as YYYY-MM-DD using the runtime's local timezone. */
33019
33183
  function formatDateKey(date) {
33020
- return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`;
33184
+ return `${String(date.year).padStart(4, "0")}-${String(date.month).padStart(2, "0")}-${String(date.day).padStart(2, "0")}`;
33021
33185
  }
33022
- /**
33023
- * True when `date` and `now` are the same local calendar day.
33024
- * `now` defaults to `new Date()` so casual callers don't need to thread it,
33025
- * but tests and snapshot-rendering should pass an explicit value.
33026
- */
33027
- function isToday(date, now = /* @__PURE__ */ new Date()) {
33028
- return isSameLocalDay(date, now);
33186
+ function isToday(date, today) {
33187
+ return isSameCalendarDay(date, today);
33029
33188
  }
33030
- /** True when two dates fall on the same local calendar day. */
33031
- function isSameLocalDay(left, right) {
33032
- return left.getFullYear() === right.getFullYear() && left.getMonth() === right.getMonth() && left.getDate() === right.getDate();
33189
+ function isSameCalendarDay(left, right) {
33190
+ return left.year === right.year && left.month === right.month && left.day === right.day;
33191
+ }
33192
+ function addDays(date, days) {
33193
+ const result = new Date(Date.UTC(date.year, date.month - 1, date.day + days, 12));
33194
+ return {
33195
+ year: result.getUTCFullYear(),
33196
+ month: result.getUTCMonth() + 1,
33197
+ day: result.getUTCDate()
33198
+ };
33033
33199
  }
33034
- /**
33035
- * Build the calendar days for a month view. Returns 42 dates (6 rows × 7
33036
- * days) including padding from prior/next months for a stable grid.
33037
- */
33038
33200
  function getMonthCalendarDays(year, month, startOfWeek) {
33039
- const firstDayOfMonth = new Date(year, month, 1);
33040
- const lastDayOfMonth = new Date(year, month + 1, 0);
33041
- let startOffset = firstDayOfMonth.getDay();
33042
- if (startOfWeek === "monday") startOffset = startOffset === 0 ? 6 : startOffset - 1;
33043
- const days = [];
33044
- for (let i = startOffset - 1; i >= 0; i--) days.push(new Date(year, month, -i));
33045
- for (let day = 1; day <= lastDayOfMonth.getDate(); day++) days.push(new Date(year, month, day));
33046
- while (days.length < 42) {
33047
- const nextDay = days.length - startOffset - lastDayOfMonth.getDate() + 1;
33048
- days.push(new Date(year, month + 1, nextDay));
33049
- }
33050
- return days;
33201
+ const firstDay = {
33202
+ year,
33203
+ month,
33204
+ day: 1
33205
+ };
33206
+ const dayOfWeek = getDayOfWeek(firstDay);
33207
+ const gridStart = addDays(firstDay, -(startOfWeek === "monday" ? dayOfWeek === 0 ? 6 : dayOfWeek - 1 : dayOfWeek));
33208
+ return Array.from({ length: 42 }, (_, index) => addDays(gridStart, index));
33051
33209
  }
33052
- /** Build the 7 dates of the week containing `baseDate`. */
33053
33210
  function getWeekCalendarDays(baseDate, startOfWeek) {
33054
- const days = [];
33055
- const dayOfWeek = baseDate.getDay();
33056
- const daysToStart = startOfWeek === "monday" ? dayOfWeek === 0 ? 6 : dayOfWeek - 1 : dayOfWeek;
33057
- const weekStart = new Date(baseDate);
33058
- weekStart.setDate(baseDate.getDate() - daysToStart);
33059
- for (let i = 0; i < 7; i++) {
33060
- const date = new Date(weekStart);
33061
- date.setDate(weekStart.getDate() + i);
33062
- days.push(date);
33063
- }
33064
- return days;
33211
+ const dayOfWeek = getDayOfWeek(baseDate);
33212
+ const weekStart = addDays(baseDate, -(startOfWeek === "monday" ? dayOfWeek === 0 ? 6 : dayOfWeek - 1 : dayOfWeek));
33213
+ return Array.from({ length: 7 }, (_, index) => addDays(weekStart, index));
33214
+ }
33215
+ function getDayOfWeek(date) {
33216
+ return new Date(Date.UTC(date.year, date.month - 1, date.day, 12)).getUTCDay();
33065
33217
  }
33066
- /** Build the 7 dates of the week containing `baseDate` as a fixed-width tuple. */
33067
33218
  function getWeekCalendarDayTuple(baseDate, startOfWeek) {
33068
33219
  const days = getWeekCalendarDays(baseDate, startOfWeek);
33069
33220
  assertWeekCalendarDays(days);
33070
33221
  return days;
33071
33222
  }
33072
33223
  function assertWeekCalendarDays(days) {
33073
- if (days.length !== 7) throw new Error("Expected week calendar helper to return exactly 7 days");
33224
+ if (days.length !== 7) throw new Error("Expected exactly 7 calendar days");
33074
33225
  }
33075
- /**
33076
- * Day-name labels reordered for the chosen week start. Pass a custom
33077
- * `dayNames` array (length 7, Sunday-first) to localize.
33078
- */
33079
33226
  function getOrderedDayNames(startOfWeek, dayNames = DAY_NAMES) {
33080
33227
  if (startOfWeek === "monday") {
33081
33228
  const sunday = dayNames[0] ?? "Sun";
@@ -33083,22 +33230,17 @@ function getOrderedDayNames(startOfWeek, dayNames = DAY_NAMES) {
33083
33230
  }
33084
33231
  return [...dayNames];
33085
33232
  }
33086
- /**
33087
- * Header title for a calendar view.
33088
- * - month: "January 2025"
33089
- * - week: "January 5 - 11, 2025" or "December 30 - January 5, 2025"
33090
- */
33091
33233
  function formatCalendarTitle(viewDate, view, days, monthNames = MONTH_NAMES) {
33092
33234
  if (view === "week") {
33093
33235
  const weekStart = days[0];
33094
33236
  const weekEnd = days[6];
33095
- if (weekStart === void 0 || weekEnd === void 0) return `${monthNames[viewDate.getMonth()] ?? ""} ${viewDate.getFullYear()}`;
33096
- const startMonth = monthNames[weekStart.getMonth()] ?? "";
33097
- const endMonth = monthNames[weekEnd.getMonth()] ?? "";
33098
- if (weekStart.getMonth() === weekEnd.getMonth()) return `${startMonth} ${weekStart.getDate()} - ${weekEnd.getDate()}, ${weekEnd.getFullYear()}`;
33099
- return `${startMonth} ${weekStart.getDate()} - ${endMonth} ${weekEnd.getDate()}, ${weekEnd.getFullYear()}`;
33237
+ if (weekStart === void 0 || weekEnd === void 0) return `${monthNames[viewDate.month - 1] ?? ""} ${viewDate.year}`;
33238
+ const startMonth = monthNames[weekStart.month - 1] ?? "";
33239
+ const endMonth = monthNames[weekEnd.month - 1] ?? "";
33240
+ if (weekStart.month === weekEnd.month) return `${startMonth} ${weekStart.day} - ${weekEnd.day}, ${weekEnd.year}`;
33241
+ return `${startMonth} ${weekStart.day} - ${endMonth} ${weekEnd.day}, ${weekEnd.year}`;
33100
33242
  }
33101
- return `${monthNames[viewDate.getMonth()] ?? ""} ${viewDate.getFullYear()}`;
33243
+ return `${monthNames[viewDate.month - 1] ?? ""} ${viewDate.year}`;
33102
33244
  }
33103
33245
  function buildCalendarViewport(input) {
33104
33246
  const monthNames = input.monthNames ?? MONTH_NAMES;
@@ -33108,10 +33250,10 @@ function buildCalendarViewport(input) {
33108
33250
  kind: "week",
33109
33251
  anchorDate: input.anchorDate,
33110
33252
  days,
33111
- title: formatCalendarTitle(input.anchorDate, "week", [...days], monthNames)
33253
+ title: formatCalendarTitle(input.anchorDate, "week", days, monthNames)
33112
33254
  };
33113
33255
  }
33114
- const days = getMonthCalendarDays(input.anchorDate.getFullYear(), input.anchorDate.getMonth(), input.startOfWeek);
33256
+ const days = getMonthCalendarDays(input.anchorDate.year, input.anchorDate.month, input.startOfWeek);
33115
33257
  return {
33116
33258
  kind: "month",
33117
33259
  anchorDate: input.anchorDate,
@@ -33259,13 +33401,12 @@ function buildTimetableModel$1(input) {
33259
33401
  const bounds = resolveBounds(input.bounds);
33260
33402
  const viewportDays = getTimetableDays(input.viewDate, input.view ?? "week", input.startOfWeek);
33261
33403
  const viewportKeys = new Set(viewportDays.map(formatDateKey));
33262
- const now = input.now ?? /* @__PURE__ */ new Date();
33263
33404
  const parsed = parseAllItems(input.items, input);
33264
33405
  const inViewport = deriveVisibleSegments(parsed.drafts, viewportKeys);
33265
33406
  const hourRange = resolveHourRange(inViewport, bounds);
33266
33407
  const laid = layoutCellsByDate(inViewport, hourRange, bounds);
33267
33408
  return {
33268
- days: assembleDays(viewportDays, laid.cellsByDate, now),
33409
+ days: assembleDays(viewportDays, laid.cellsByDate, input.today),
33269
33410
  hourTicks: buildHourTicks(hourRange.startHour, hourRange.endHour),
33270
33411
  startHour: hourRange.startHour,
33271
33412
  endHour: hourRange.endHour,
@@ -33322,13 +33463,13 @@ function layoutCellsByDate(segments, hourRange, bounds) {
33322
33463
  diagnostics
33323
33464
  };
33324
33465
  }
33325
- function assembleDays(viewportDays, cellsByDate, now) {
33466
+ function assembleDays(viewportDays, cellsByDate, today) {
33326
33467
  return viewportDays.map((date) => {
33327
33468
  const dateKey = formatDateKey(date);
33328
33469
  return {
33329
33470
  date,
33330
33471
  dateKey,
33331
- isToday: isSameLocalDay(date, now),
33472
+ isToday: isSameCalendarDay(date, today),
33332
33473
  cells: cellsByDate.get(dateKey) ?? []
33333
33474
  };
33334
33475
  });
@@ -33480,13 +33621,12 @@ function getTimetableDays(viewDate, view, startOfWeek) {
33480
33621
  function enumerateDateKeys(startDateKey, endDateKey) {
33481
33622
  if (startDateKey > endDateKey) throw new Error(`Invalid timetable date range: ${startDateKey} is after ${endDateKey}`);
33482
33623
  const start = parseDateKey(startDateKey);
33483
- const end = parseDateKey(endDateKey);
33624
+ parseDateKey(endDateKey);
33484
33625
  const keys = [];
33485
- const cursor = new Date(start.year, start.month - 1, start.day);
33486
- const endDate = new Date(end.year, end.month - 1, end.day);
33487
- while (cursor.getTime() <= endDate.getTime()) {
33626
+ let cursor = start;
33627
+ while (formatDateKey(cursor) <= endDateKey) {
33488
33628
  keys.push(formatDateKey(cursor));
33489
- cursor.setDate(cursor.getDate() + 1);
33629
+ cursor = addDays(cursor, 1);
33490
33630
  }
33491
33631
  return keys;
33492
33632
  }
@@ -33711,10 +33851,10 @@ function formatEventTeacherLine(event) {
33711
33851
  * timezone). Thin domain wrapper over `groupItemsByDate` from the calendar
33712
33852
  * package; preserves the historical `Map<string, PublicEvent[]>` shape.
33713
33853
  */
33714
- function groupEventsByDate(events) {
33854
+ function groupEventsByDate(events, calendarTimeZone) {
33715
33855
  const grouped = groupItemsByDate(events, {
33716
33856
  getStartsAt: (event) => event.startsAt,
33717
- getTimeZone: (event) => event.timeZone ?? "UTC"
33857
+ getTimeZone: () => calendarTimeZone
33718
33858
  });
33719
33859
  const map = /* @__PURE__ */ new Map();
33720
33860
  for (const [dateKey, bucket] of grouped) map.set(dateKey, [...bucket]);
@@ -35445,7 +35585,8 @@ const eventCollectionSourceSchemaShape = {
35445
35585
  buttonVariant: eventButtonVariantSchema.optional(),
35446
35586
  buttonText: z.string().optional(),
35447
35587
  emptyMessage: z.string().optional(),
35448
- className: z.string().optional()
35588
+ className: z.string().optional(),
35589
+ bookingTimeZone: z.string().optional()
35449
35590
  };
35450
35591
  const eventCollectionDisplaySchemaShape = {
35451
35592
  events: z.array(publicEventSchema),
@@ -35480,7 +35621,15 @@ const eventCollectionHydrationSchema = z.object({
35480
35621
  prefetchedEvents: z.boolean(),
35481
35622
  eventSurface: eventSurfaceScopeSchema$1,
35482
35623
  filterEventPresets: z.string().nullable(),
35483
- scheduleScope: eventScheduleScopeSchema$1
35624
+ scheduleScope: eventScheduleScopeSchema$1,
35625
+ calendarContext: z.object({
35626
+ timeZone: z.string().transform(toBookingTimeZone),
35627
+ initialToday: z.object({
35628
+ year: z.number().int(),
35629
+ month: z.number().int().min(1).max(12),
35630
+ day: z.number().int().min(1).max(31)
35631
+ })
35632
+ })
35484
35633
  });
35485
35634
  function buildEventCollectionDisplay(source) {
35486
35635
  return {
@@ -35525,14 +35674,19 @@ function buildEventCollectionPresentationDisplay(source) {
35525
35674
  emptyMessage: source.emptyMessage ?? "No upcoming events scheduled."
35526
35675
  };
35527
35676
  }
35528
- function buildEventCollectionHydration(source) {
35677
+ function buildEventCollectionHydration(source, now = /* @__PURE__ */ new Date()) {
35678
+ const timeZone = toBookingTimeZone(source.bookingTimeZone);
35529
35679
  return {
35530
35680
  siteId: source.siteId,
35531
35681
  stage: source.stage,
35532
35682
  prefetchedEvents: source.events != null,
35533
35683
  eventSurface: normalizeEventSurfaceScope(source.eventSurface),
35534
35684
  filterEventPresets: normalizeEventSurfacePresetsCsv(source.filterEventPresets),
35535
- scheduleScope: normalizeEventScheduleScope(source.scheduleScope)
35685
+ scheduleScope: normalizeEventScheduleScope(source.scheduleScope),
35686
+ calendarContext: {
35687
+ timeZone,
35688
+ initialToday: getLocalScheduleDate(now, timeZone)
35689
+ }
35536
35690
  };
35537
35691
  }
35538
35692
  function buildEventCollectionListingDisplay(display, prefetchedEvents, className) {
@@ -37650,7 +37804,7 @@ function inferLegacyOfferingsPreviewGroupOrder(overrides) {
37650
37804
  return keys.length >= 2 ? keys : [];
37651
37805
  }
37652
37806
  function normalizeOfferingsPreviewContentForWrite(value) {
37653
- if (!isRecord$9(value)) return null;
37807
+ if (!isRecord$11(value)) return null;
37654
37808
  const groupOrderValue = value.groupOrder;
37655
37809
  if (Array.isArray(groupOrderValue)) {
37656
37810
  const normalized = normalizeOfferingsPreviewGroupOrder(groupOrderValue);
@@ -37663,7 +37817,7 @@ function normalizeOfferingsPreviewContentForWrite(value) {
37663
37817
  ...value,
37664
37818
  groupOrder: []
37665
37819
  };
37666
- const legacyOrder = inferLegacyOfferingsPreviewGroupOrder(Array.isArray(value.groupOverrides) ? value.groupOverrides.filter(isRecord$9) : []);
37820
+ const legacyOrder = inferLegacyOfferingsPreviewGroupOrder(Array.isArray(value.groupOverrides) ? value.groupOverrides.filter(isRecord$11) : []);
37667
37821
  return legacyOrder.length > 0 ? {
37668
37822
  ...value,
37669
37823
  groupOrder: legacyOrder
@@ -37728,7 +37882,7 @@ function uniqueOfferingsPreviewSourceKeys(values) {
37728
37882
  }
37729
37883
  return keys;
37730
37884
  }
37731
- function isRecord$9(value) {
37885
+ function isRecord$11(value) {
37732
37886
  return typeof value === "object" && value !== null && !Array.isArray(value);
37733
37887
  }
37734
37888
  function mergeOrderedKeysWithDefaults(orderedKeys, defaultKeys) {
@@ -38183,7 +38337,7 @@ function isOfferingsPreviewItemLimit(value) {
38183
38337
  return value === "1" || value === "2" || value === "3" || value === "4" || value === "5" || value === "6" || value === null;
38184
38338
  }
38185
38339
  function normalizeOfferingsPreviewGroupOverride(value) {
38186
- if (!isRecord$8(value)) return [];
38340
+ if (!isRecord$10(value)) return [];
38187
38341
  const override = {};
38188
38342
  if (isOfferingsPreviewSourceKey(value.sourceKey) || value.sourceKey === null) override.sourceKey = value.sourceKey;
38189
38343
  if (typeof value.title === "string" || value.title === null) override.title = value.title;
@@ -38206,7 +38360,7 @@ function normalizeSectionStylesContent(value) {
38206
38360
  }
38207
38361
  function normalizeBoxStylesContent(value) {
38208
38362
  if (value === null) return null;
38209
- if (!isRecord$8(value)) return void 0;
38363
+ if (!isRecord$10(value)) return void 0;
38210
38364
  const { background: _background, ...rest } = value;
38211
38365
  const background = parseBackgroundContent(value.background);
38212
38366
  return {
@@ -38214,7 +38368,7 @@ function normalizeBoxStylesContent(value) {
38214
38368
  ...background ? { background } : {}
38215
38369
  };
38216
38370
  }
38217
- function isRecord$8(value) {
38371
+ function isRecord$10(value) {
38218
38372
  return typeof value === "object" && value !== null && !Array.isArray(value);
38219
38373
  }
38220
38374
  const embedManifest = createBlockManifest({
@@ -41521,6 +41675,23 @@ function deriveNewsletterSignupRuntimeSource(values) {
41521
41675
  tags: parseTrimmedString(normalized.tags)
41522
41676
  };
41523
41677
  }
41678
+ function sanitizeNewsletterSignupPublicContent(content) {
41679
+ if (!isRecord$9(content)) return content;
41680
+ const provider = parseNewsletterSignupDestinationProvider(content.destinationProvider) ?? getProviderFromExplicitDestination(content.destination);
41681
+ const { destination: _destination, destinationProvider: _destinationProvider, mailchimpAudienceId: _mailchimpAudienceId, mailchimpTags: _mailchimpTags, listId, tags, ...publicContent } = content;
41682
+ const mutablePublicContent = { ...publicContent };
41683
+ if (provider !== "mailchimp") {
41684
+ if ("listId" in content) mutablePublicContent.listId = listId;
41685
+ if ("tags" in content) mutablePublicContent.tags = tags;
41686
+ }
41687
+ return mutablePublicContent;
41688
+ }
41689
+ function getProviderFromExplicitDestination(destination) {
41690
+ if (!isRecord$9(destination) || typeof destination.tag !== "string") return null;
41691
+ if (destination.tag === "riverbank_list") return "riverbank";
41692
+ if (destination.tag === "mailchimp_audience") return "mailchimp";
41693
+ return null;
41694
+ }
41524
41695
  const BLOCK_ID_PATTERN = /^[A-Za-z0-9._:-]{1,200}$/;
41525
41696
  const SIGNED_DESTINATION_REF_PATTERN = /^[A-Za-z0-9._~-]{16,1000}$/;
41526
41697
  function parseTrimmedString(value) {
@@ -41528,6 +41699,9 @@ function parseTrimmedString(value) {
41528
41699
  const trimmed = value.trim();
41529
41700
  return trimmed.length > 0 ? trimmed : null;
41530
41701
  }
41702
+ function isRecord$9(value) {
41703
+ return typeof value === "object" && value !== null;
41704
+ }
41531
41705
  //#endregion
41532
41706
  //#region ../blocks/src/system/runtime/nodes/newsletter-form.types.ts
41533
41707
  /**
@@ -43796,7 +43970,7 @@ const defaultTransforms = createTransformRegistry([
43796
43970
  //#region ../blocks/src/system/data/linkedContentEntries.ts
43797
43971
  const LINKED_CONTENT_ENTRY_META_KEY = "__rbLinkedContentEntry";
43798
43972
  function coerceLinkedContentEntriesPayload(payload) {
43799
- if (!isRecord$7(payload)) return payload;
43973
+ if (!isRecord$8(payload)) return payload;
43800
43974
  const response = payload;
43801
43975
  if (!Array.isArray(response.entries)) return payload;
43802
43976
  const contentType = parsePublicContentTypeMeta(response.contentType);
@@ -43804,16 +43978,16 @@ function coerceLinkedContentEntriesPayload(payload) {
43804
43978
  return response.entries.map((entry) => enrichLinkedContentEntry(entry, contentType));
43805
43979
  }
43806
43980
  function getLinkedContentEntryMeta(value) {
43807
- if (!isRecord$7(value)) return null;
43981
+ if (!isRecord$8(value)) return null;
43808
43982
  const candidate = value[LINKED_CONTENT_ENTRY_META_KEY];
43809
43983
  return isLinkedContentEntryMeta(candidate) ? candidate : null;
43810
43984
  }
43811
43985
  function buildLinkedContentEditTarget(input) {
43812
43986
  const { entry, sourceBlockId, sourceBlockKind, itemIndex } = input;
43813
- if (!isRecord$7(entry)) return null;
43987
+ if (!isRecord$8(entry)) return null;
43814
43988
  const meta = getLinkedContentEntryMeta(entry);
43815
43989
  if (!meta || meta.support.kind !== "supported") return null;
43816
- const content = isRecord$7(entry.content) ? entry.content : {};
43990
+ const content = isRecord$8(entry.content) ? entry.content : {};
43817
43991
  return {
43818
43992
  kind: "linked-content-entry",
43819
43993
  entryId: meta.entryId,
@@ -43877,12 +44051,12 @@ function resolveLinkedEntryInlineFieldEligibility(input) {
43877
44051
  };
43878
44052
  }
43879
44053
  function enrichLinkedContentEntry(entry, contentType) {
43880
- if (!isRecord$7(entry)) return entry;
44054
+ if (!isRecord$8(entry)) return entry;
43881
44055
  const entryId = typeof entry.id === "string" ? entry.id : null;
43882
44056
  if (!entryId) return entry;
43883
44057
  const title = typeof entry.title === "string" && entry.title.trim().length > 0 ? entry.title : entryId;
43884
44058
  const optimisticHash = typeof entry.optimisticHash === "string" && entry.optimisticHash.length > 0 ? entry.optimisticHash : null;
43885
- const content = isRecord$7(entry.content) ? entry.content : {};
44059
+ const content = isRecord$8(entry.content) ? entry.content : {};
43886
44060
  const meta = {
43887
44061
  kind: "linked-content-entry",
43888
44062
  entryId,
@@ -43978,7 +44152,7 @@ function capitalize(value) {
43978
44152
  return value.charAt(0).toUpperCase() + value.slice(1).toLowerCase();
43979
44153
  }
43980
44154
  function parsePublicContentTypeMeta(value) {
43981
- if (!isRecord$7(value)) return null;
44155
+ if (!isRecord$8(value)) return null;
43982
44156
  if (typeof value.key !== "string" || value.key.trim().length === 0) return null;
43983
44157
  return {
43984
44158
  key: value.key,
@@ -43988,7 +44162,7 @@ function parsePublicContentTypeMeta(value) {
43988
44162
  };
43989
44163
  }
43990
44164
  function parsePublicContentTypeLinkedEntryEditing(value) {
43991
- if (!isRecord$7(value) || typeof value.kind !== "string") return null;
44165
+ if (!isRecord$8(value) || typeof value.kind !== "string") return null;
43992
44166
  switch (value.kind) {
43993
44167
  case "generic": return { kind: "generic" };
43994
44168
  case "unsupported-domain-backed": return {
@@ -43999,7 +44173,7 @@ function parsePublicContentTypeLinkedEntryEditing(value) {
43999
44173
  }
44000
44174
  }
44001
44175
  function parsePublicContentTypeFieldMeta(value) {
44002
- if (!isRecord$7(value)) return [];
44176
+ if (!isRecord$8(value)) return [];
44003
44177
  if (typeof value.id !== "string" || typeof value.type !== "string") return [];
44004
44178
  return [{
44005
44179
  id: value.id,
@@ -44014,14 +44188,14 @@ function parseStringArray(value) {
44014
44188
  return value.filter((item) => typeof item === "string");
44015
44189
  }
44016
44190
  function isLinkedContentEntryMeta(value) {
44017
- if (!isRecord$7(value)) return false;
44191
+ if (!isRecord$8(value)) return false;
44018
44192
  if (value.kind !== "linked-content-entry") return false;
44019
44193
  if (typeof value.entryId !== "string") return false;
44020
44194
  if (typeof value.contentTypeKey !== "string") return false;
44021
44195
  if (typeof value.contentTypeLabel !== "string") return false;
44022
44196
  if (typeof value.title !== "string") return false;
44023
44197
  if (!(value.optimisticHash === null || typeof value.optimisticHash === "string")) return false;
44024
- if (!isRecord$7(value.contentType)) return false;
44198
+ if (!isRecord$8(value.contentType)) return false;
44025
44199
  if (!isLinkedEntryFieldSourceArray(value.fieldSources)) return false;
44026
44200
  return isLinkedContentEditSupport(value.support);
44027
44201
  }
@@ -44029,7 +44203,7 @@ function isLinkedEntryFieldSourceArray(value) {
44029
44203
  return Array.isArray(value) && value.every(isLinkedEntryFieldSource);
44030
44204
  }
44031
44205
  function isLinkedEntryFieldSource(value) {
44032
- if (!isRecord$7(value)) return false;
44206
+ if (!isRecord$8(value)) return false;
44033
44207
  if (typeof value.displayPath !== "string") return false;
44034
44208
  switch (value.kind) {
44035
44209
  case "content-field": return typeof value.fieldPath === "string" && (value.fieldType === "text" || value.fieldType === "richText");
@@ -44050,7 +44224,7 @@ function isLinkedEntryInlineFieldReadOnlyReason(value) {
44050
44224
  }
44051
44225
  }
44052
44226
  function isLinkedContentEditSupport(value) {
44053
- if (!isRecord$7(value) || typeof value.kind !== "string") return false;
44227
+ if (!isRecord$8(value) || typeof value.kind !== "string") return false;
44054
44228
  switch (value.kind) {
44055
44229
  case "supported": return true;
44056
44230
  case "unsupported-domain-backed":
@@ -44059,7 +44233,7 @@ function isLinkedContentEditSupport(value) {
44059
44233
  default: return false;
44060
44234
  }
44061
44235
  }
44062
- function isRecord$7(value) {
44236
+ function isRecord$8(value) {
44063
44237
  return typeof value === "object" && value !== null && !Array.isArray(value);
44064
44238
  }
44065
44239
  //#endregion
@@ -44156,11 +44330,11 @@ var UnsafePathSegmentError = class extends Error {
44156
44330
  function assertSafePathSegments(segments) {
44157
44331
  for (const segment of segments) if (typeof segment === "string" && UNSAFE_PATH_SEGMENTS.has(segment)) throw new UnsafePathSegmentError(segment);
44158
44332
  }
44159
- function isRecord$6(value) {
44333
+ function isRecord$7(value) {
44160
44334
  return typeof value === "object" && value !== null && !Array.isArray(value);
44161
44335
  }
44162
44336
  function isPathContainer(value) {
44163
- return Array.isArray(value) || isRecord$6(value);
44337
+ return Array.isArray(value) || isRecord$7(value);
44164
44338
  }
44165
44339
  function getContainerValue(container, segment) {
44166
44340
  if (typeof segment === "number") return Array.isArray(container) ? container[segment] : void 0;
@@ -45621,12 +45795,12 @@ function toTrimmedString(value) {
45621
45795
  return trimmed ? trimmed : void 0;
45622
45796
  }
45623
45797
  function normalizeBookingFormConfig(form) {
45624
- if (!isRecord$5(form)) return null;
45798
+ if (!isRecord$6(form)) return null;
45625
45799
  const id = readNonEmptyString(form.id);
45626
45800
  const name = readNonEmptyString(form.name);
45627
45801
  if (!id || !name) return null;
45628
- const schemaSource = isRecord$5(form.schema) ? form.schema : isRecord$5(form.schemaJson) ? form.schemaJson : null;
45629
- const settingsSource = isRecord$5(form.settings) ? form.settings : isRecord$5(form.settingsJson) ? form.settingsJson : null;
45802
+ const schemaSource = isRecord$6(form.schema) ? form.schema : isRecord$6(form.schemaJson) ? form.schemaJson : null;
45803
+ const settingsSource = isRecord$6(form.settings) ? form.settings : isRecord$6(form.settingsJson) ? form.settingsJson : null;
45630
45804
  return {
45631
45805
  id,
45632
45806
  name,
@@ -45646,8 +45820,8 @@ function normalizeBookingServices(services) {
45646
45820
  };
45647
45821
  if (!services) return [];
45648
45822
  if (Array.isArray(services)) return services.filter(isBookingFormService).map(normalizeService);
45649
- if (isRecord$5(services) && "services" in services) return Array.isArray(services.services) ? services.services.filter(isBookingFormService).map(normalizeService) : [];
45650
- return isRecord$5(services) ? Object.values(services).filter(isBookingFormService).map(normalizeService) : [];
45823
+ if (isRecord$6(services) && "services" in services) return Array.isArray(services.services) ? services.services.filter(isBookingFormService).map(normalizeService) : [];
45824
+ return isRecord$6(services) ? Object.values(services).filter(isBookingFormService).map(normalizeService) : [];
45651
45825
  }
45652
45826
  function normalizeBookingSchema(value) {
45653
45827
  if (!value) return void 0;
@@ -45658,7 +45832,7 @@ function normalizeBookingSchema(value) {
45658
45832
  };
45659
45833
  }
45660
45834
  function readBookingFormField(value) {
45661
- if (!isRecord$5(value)) return null;
45835
+ if (!isRecord$6(value)) return null;
45662
45836
  const id = readNonEmptyString(value.id);
45663
45837
  const label = readNonEmptyString(value.label);
45664
45838
  const type = readBookingFieldType(value.type);
@@ -45701,7 +45875,7 @@ function readBookingFieldOptions(value) {
45701
45875
  return options.length > 0 ? options : void 0;
45702
45876
  }
45703
45877
  function readBookingFieldOption(value) {
45704
- if (!isRecord$5(value)) return null;
45878
+ if (!isRecord$6(value)) return null;
45705
45879
  const optionValue = readNonEmptyString(value.value);
45706
45880
  const label = readNonEmptyString(value.label);
45707
45881
  return optionValue && label ? {
@@ -45721,7 +45895,7 @@ function normalizeBookingSettings(value) {
45721
45895
  };
45722
45896
  }
45723
45897
  function isBookingFormService(value) {
45724
- return isRecord$5(value) && typeof value.id === "string" && typeof value.siteId === "string" && typeof value.title === "string" && (value.consent === void 0 || blockBookingConsentSchema.safeParse(value.consent).success);
45898
+ return isRecord$6(value) && typeof value.id === "string" && typeof value.siteId === "string" && typeof value.title === "string" && (value.consent === void 0 || blockBookingConsentSchema.safeParse(value.consent).success);
45725
45899
  }
45726
45900
  function readNonEmptyString(value) {
45727
45901
  if (typeof value !== "string") return null;
@@ -45739,7 +45913,7 @@ function readStringArray(value) {
45739
45913
  const strings = value.filter((item) => typeof item === "string");
45740
45914
  return strings.length > 0 ? strings : void 0;
45741
45915
  }
45742
- function isRecord$5(value) {
45916
+ function isRecord$6(value) {
45743
45917
  return typeof value === "object" && value !== null;
45744
45918
  }
45745
45919
  //#endregion
@@ -46154,7 +46328,8 @@ function isOrdinaryEvent(event) {
46154
46328
  function deriveWholeSeriesPhase(sessions, nowIso) {
46155
46329
  const now = Date.parse(nowIso);
46156
46330
  if (now < Date.parse(sessions[0].startsAt)) return "upcoming";
46157
- return now <= Date.parse(sessions.at(-1)?.endsAt ?? sessions[0].endsAt) ? "inProgress" : "completed";
46331
+ const finalSession = sessions[sessions.length - 1] ?? sessions[0];
46332
+ return now <= Date.parse(finalSession.endsAt) ? "inProgress" : "completed";
46158
46333
  }
46159
46334
  function selectRelatedDates(input) {
46160
46335
  if (!input.seriesId) return [];
@@ -48276,9 +48451,9 @@ const FULL_DAY_NAMES$1 = [
48276
48451
  * @returns "Monday, January 13"
48277
48452
  */
48278
48453
  function formatAgendaDayHeader(date) {
48279
- const dayName = FULL_DAY_NAMES$1[date.getDay()];
48280
- const monthName = MONTH_NAMES[date.getMonth()];
48281
- return `${dayName ?? "Day"}, ${monthName ?? "Month"} ${date.getDate()}`;
48454
+ const dayName = FULL_DAY_NAMES$1[getDayOfWeek(date)];
48455
+ const monthName = MONTH_NAMES[date.month - 1];
48456
+ return `${dayName ?? "Day"}, ${monthName ?? "Month"} ${date.day}`;
48282
48457
  }
48283
48458
  /**
48284
48459
  * WeekAgendaView Component
@@ -48286,14 +48461,14 @@ function formatAgendaDayHeader(date) {
48286
48461
  * Displays a week of events in an agenda/list style with rich event details.
48287
48462
  * Shows all 7 days with date headers, empty days show "No events scheduled".
48288
48463
  */
48289
- const WeekAgendaView = ({ days, events, showCapacity, emptyMessage = "No events scheduled" }) => {
48290
- const eventsByDate = groupEventsByDate(events);
48464
+ const WeekAgendaView = ({ days, events, showCapacity, emptyMessage = "No events scheduled", calendarTimeZone, today: currentDate }) => {
48465
+ const eventsByDate = groupEventsByDate(events, calendarTimeZone);
48291
48466
  return /* @__PURE__ */ jsx("div", {
48292
48467
  className: "event-agenda-week",
48293
48468
  children: days.map((date) => {
48294
48469
  const dateKey = formatDateKey(date);
48295
48470
  const dayEvents = eventsByDate.get(dateKey) || [];
48296
- const today = isToday(date);
48471
+ const today = isToday(date, currentDate);
48297
48472
  return /* @__PURE__ */ jsxs("div", {
48298
48473
  className: `event-agenda-day ${today ? "event-agenda-day--today" : ""}`,
48299
48474
  children: [/* @__PURE__ */ jsx("div", {
@@ -48323,7 +48498,49 @@ const WeekAgendaView = ({ days, events, showCapacity, emptyMessage = "No events
48323
48498
  });
48324
48499
  };
48325
48500
  //#endregion
48501
+ //#region ../blocks/src/system/runtime/nodes/events/shared/CalendarNavigationChevron.tsx
48502
+ function CalendarNavigationChevron({ direction }) {
48503
+ return /* @__PURE__ */ jsx("svg", {
48504
+ width: "20",
48505
+ height: "20",
48506
+ fill: "none",
48507
+ stroke: "currentColor",
48508
+ strokeWidth: 2,
48509
+ viewBox: "0 0 24 24",
48510
+ "aria-hidden": "true",
48511
+ children: /* @__PURE__ */ jsx("path", {
48512
+ strokeLinecap: "round",
48513
+ strokeLinejoin: "round",
48514
+ d: direction === "previous" ? "M15 19l-7-7 7-7" : "M9 5l7 7-7 7"
48515
+ })
48516
+ });
48517
+ }
48518
+ //#endregion
48326
48519
  //#region ../blocks/src/system/runtime/nodes/events/shared/WeekBoardView.tsx
48520
+ function buildWeekBoardNavigationState(viewport, today) {
48521
+ return {
48522
+ rangeLabel: viewport.title,
48523
+ isCurrentWeek: viewport.days.some((day) => isToday(day, today))
48524
+ };
48525
+ }
48526
+ function buildWeekBoardViewProps(display, days, navigation, events = display.events) {
48527
+ return {
48528
+ days,
48529
+ events: [...events],
48530
+ navigation,
48531
+ showCapacity: display.showCapacity,
48532
+ emptyMessage: display.emptyMessage,
48533
+ title: display.boardTitle,
48534
+ footerNote: display.footerNote,
48535
+ ctaLabel: display.loadMoreText ?? display.buttonText,
48536
+ ctaHref: display.seeAllUrl,
48537
+ buttonVariant: display.buttonVariant,
48538
+ elevated: display.elevated,
48539
+ banded: display.banded,
48540
+ calendarTimeZone: display.calendarTimeZone,
48541
+ today: display.today
48542
+ };
48543
+ }
48327
48544
  const SHORT_DAY_NAMES = [
48328
48545
  "Sun",
48329
48546
  "Mon",
@@ -48385,6 +48602,114 @@ const WeekBoardCard = ({ event, showCapacity }) => {
48385
48602
  ]
48386
48603
  });
48387
48604
  };
48605
+ const WeekBoardNavigationControls = ({ navigation, todayClassName }) => {
48606
+ const handlers = navigation.kind === "interactive" ? navigation : {
48607
+ onPrevious: void 0,
48608
+ onNext: void 0,
48609
+ onToday: void 0
48610
+ };
48611
+ const isLoading = navigation.kind === "interactive" && navigation.loadState.kind === "loading";
48612
+ return /* @__PURE__ */ jsxs("nav", {
48613
+ className: "event-week-board-navigation",
48614
+ "aria-label": "Choose week",
48615
+ children: [
48616
+ /* @__PURE__ */ jsx("button", {
48617
+ type: "button",
48618
+ className: "event-week-board-nav-button",
48619
+ "aria-label": "Previous week",
48620
+ onClick: handlers.onPrevious,
48621
+ children: /* @__PURE__ */ jsx(CalendarNavigationChevron, { direction: "previous" })
48622
+ }),
48623
+ /* @__PURE__ */ jsxs("h3", {
48624
+ className: "event-week-board-range",
48625
+ "aria-live": "polite",
48626
+ children: [navigation.rangeLabel, isLoading ? /* @__PURE__ */ jsx("span", {
48627
+ className: "event-week-board-loading",
48628
+ children: " Loading…"
48629
+ }) : null]
48630
+ }),
48631
+ /* @__PURE__ */ jsx("button", {
48632
+ type: "button",
48633
+ className: "event-week-board-nav-button",
48634
+ "aria-label": "Next week",
48635
+ onClick: handlers.onNext,
48636
+ children: /* @__PURE__ */ jsx(CalendarNavigationChevron, { direction: "next" })
48637
+ }),
48638
+ /* @__PURE__ */ jsx("button", {
48639
+ type: "button",
48640
+ className: todayClassName,
48641
+ disabled: navigation.isCurrentWeek,
48642
+ onClick: handlers.onToday,
48643
+ children: "Today"
48644
+ })
48645
+ ]
48646
+ });
48647
+ };
48648
+ const WeekBoardLegend = () => /* @__PURE__ */ jsx("div", {
48649
+ className: "event-week-board-legend",
48650
+ "aria-hidden": "true",
48651
+ children: LEGEND_ITEMS.map((item) => /* @__PURE__ */ jsxs("span", {
48652
+ className: "event-week-board-legend-item",
48653
+ children: [/* @__PURE__ */ jsx("i", {
48654
+ className: "event-week-board-legend-dot",
48655
+ "data-status": item.status
48656
+ }), item.label]
48657
+ }, item.status))
48658
+ });
48659
+ const WeekBoardLoadError = ({ navigation, buttonClassName }) => {
48660
+ if (navigation.kind !== "interactive" || navigation.loadState.kind !== "error") return null;
48661
+ return /* @__PURE__ */ jsxs("div", {
48662
+ className: "event-week-board-error",
48663
+ role: "status",
48664
+ children: [/* @__PURE__ */ jsx("p", { children: "Failed to load events" }), /* @__PURE__ */ jsx("button", {
48665
+ type: "button",
48666
+ className: buttonClassName,
48667
+ onClick: navigation.loadState.onRetry,
48668
+ children: "Try again"
48669
+ })]
48670
+ });
48671
+ };
48672
+ const WeekBoardGrid = ({ days, eventsByDate, showCapacity, today: currentDate }) => /* @__PURE__ */ jsx("div", {
48673
+ className: "event-week-board-grid",
48674
+ children: days.map((date) => {
48675
+ const dateKey = formatDateKey(date);
48676
+ const dayEvents = eventsByDate.get(dateKey) ?? [];
48677
+ const today = isToday(date, currentDate);
48678
+ return /* @__PURE__ */ jsxs("div", {
48679
+ className: clsx("event-week-board-day", dayEvents.length === 0 && "event-week-board-day--empty", today && "event-week-board-day--today"),
48680
+ children: [/* @__PURE__ */ jsxs("div", {
48681
+ className: "event-week-board-day-head",
48682
+ children: [/* @__PURE__ */ jsx("span", {
48683
+ className: "event-week-board-day-abbr",
48684
+ children: SHORT_DAY_NAMES[getDayOfWeek(date)]
48685
+ }), /* @__PURE__ */ jsx("span", {
48686
+ className: "event-week-board-day-num",
48687
+ children: date.day
48688
+ })]
48689
+ }), /* @__PURE__ */ jsx("div", {
48690
+ className: "event-week-board-day-body",
48691
+ children: dayEvents.map((event) => /* @__PURE__ */ jsx(WeekBoardCard, {
48692
+ event,
48693
+ showCapacity
48694
+ }, event.occurrenceId || event.id))
48695
+ })]
48696
+ }, dateKey);
48697
+ })
48698
+ });
48699
+ const WeekBoardFooter = ({ note, ctaHref, ctaLabel, ctaClassName }) => {
48700
+ if (note === null && ctaHref === null) return null;
48701
+ return /* @__PURE__ */ jsxs("div", {
48702
+ className: "event-week-board-foot",
48703
+ children: [note === null ? null : /* @__PURE__ */ jsx("p", {
48704
+ className: "event-week-board-foot-note",
48705
+ children: note
48706
+ }), ctaHref === null ? null : /* @__PURE__ */ jsx("a", {
48707
+ className: ctaClassName,
48708
+ href: ctaHref,
48709
+ children: ctaLabel
48710
+ })]
48711
+ });
48712
+ };
48388
48713
  /**
48389
48714
  * WeekBoardView
48390
48715
  *
@@ -48393,18 +48718,21 @@ const WeekBoardCard = ({ event, showCapacity }) => {
48393
48718
  * to a stacked list on mobile. Repurposes the week-grouped agenda data as a
48394
48719
  * board rather than an hour-positioned timetable grid.
48395
48720
  */
48396
- const WeekBoardView = ({ days, events, showCapacity, emptyMessage = "No classes scheduled this week", title, footerNote, ctaLabel = "Reserve a place", ctaHref = null, buttonVariant = "outline", elevated = false, banded = false }) => {
48397
- const eventsByDate = groupEventsByDate(events);
48721
+ const WeekBoardView = ({ days, events, navigation, showCapacity, emptyMessage = "No classes scheduled this week", title, footerNote, ctaLabel = "Reserve a place", ctaHref = null, buttonVariant = "outline", elevated = false, banded = false, calendarTimeZone, today }) => {
48722
+ const eventsByDate = groupEventsByDate(events, calendarTimeZone);
48398
48723
  const hasAnyEvents = days.some((date) => (eventsByDate.get(formatDateKey(date)) ?? []).length > 0);
48399
48724
  const ctaClassName = themeButtonClassName({
48400
48725
  variant: buttonVariant,
48401
48726
  size: "sm"
48402
48727
  });
48728
+ const todayClassName = themeButtonClassName({
48729
+ variant: buttonVariant,
48730
+ size: "sm"
48731
+ });
48403
48732
  const hasTitle = typeof title === "string" && title.length > 0;
48404
48733
  const hasFooterNote = typeof footerNote === "string" && footerNote.length > 0;
48405
- const hasCta = typeof ctaHref === "string" && ctaHref.length > 0;
48406
48734
  const footerNoteText = hasAnyEvents ? hasFooterNote ? footerNote : null : emptyMessage;
48407
- const showFooter = hasCta || footerNoteText !== null;
48735
+ const resolvedCtaHref = typeof ctaHref === "string" && ctaHref.length > 0 ? ctaHref : null;
48408
48736
  return /* @__PURE__ */ jsx("div", {
48409
48737
  className: "event-calendar event-calendar--week-board",
48410
48738
  "data-block": "event-calendar",
@@ -48416,59 +48744,34 @@ const WeekBoardView = ({ days, events, showCapacity, emptyMessage = "No classes
48416
48744
  children: [
48417
48745
  /* @__PURE__ */ jsxs("div", {
48418
48746
  className: "event-week-board-top",
48419
- children: [hasTitle ? /* @__PURE__ */ jsx("span", {
48420
- className: "event-week-board-title",
48421
- children: title
48422
- }) : null, /* @__PURE__ */ jsx("div", {
48423
- className: "event-week-board-legend",
48424
- "aria-hidden": "true",
48425
- children: LEGEND_ITEMS.map((item) => /* @__PURE__ */ jsxs("span", {
48426
- className: "event-week-board-legend-item",
48427
- children: [/* @__PURE__ */ jsx("i", {
48428
- className: "event-week-board-legend-dot",
48429
- "data-status": item.status
48430
- }), item.label]
48431
- }, item.status))
48432
- })]
48747
+ children: [
48748
+ hasTitle ? /* @__PURE__ */ jsx("span", {
48749
+ className: "event-week-board-title",
48750
+ children: title
48751
+ }) : null,
48752
+ /* @__PURE__ */ jsx(WeekBoardNavigationControls, {
48753
+ navigation,
48754
+ todayClassName
48755
+ }),
48756
+ /* @__PURE__ */ jsx(WeekBoardLegend, {})
48757
+ ]
48433
48758
  }),
48434
- /* @__PURE__ */ jsx("div", {
48435
- className: "event-week-board-grid",
48436
- children: days.map((date) => {
48437
- const dateKey = formatDateKey(date);
48438
- const dayEvents = eventsByDate.get(dateKey) ?? [];
48439
- const today = isToday(date);
48440
- return /* @__PURE__ */ jsxs("div", {
48441
- className: clsx("event-week-board-day", dayEvents.length === 0 && "event-week-board-day--empty", today && "event-week-board-day--today"),
48442
- children: [/* @__PURE__ */ jsxs("div", {
48443
- className: "event-week-board-day-head",
48444
- children: [/* @__PURE__ */ jsx("span", {
48445
- className: "event-week-board-day-abbr",
48446
- children: SHORT_DAY_NAMES[date.getDay()]
48447
- }), /* @__PURE__ */ jsx("span", {
48448
- className: "event-week-board-day-num",
48449
- children: date.getDate()
48450
- })]
48451
- }), /* @__PURE__ */ jsx("div", {
48452
- className: "event-week-board-day-body",
48453
- children: dayEvents.map((event) => /* @__PURE__ */ jsx(WeekBoardCard, {
48454
- event,
48455
- showCapacity
48456
- }, event.occurrenceId || event.id))
48457
- })]
48458
- }, dateKey);
48459
- })
48759
+ /* @__PURE__ */ jsx(WeekBoardLoadError, {
48760
+ navigation,
48761
+ buttonClassName: todayClassName
48460
48762
  }),
48461
- showFooter ? /* @__PURE__ */ jsxs("div", {
48462
- className: "event-week-board-foot",
48463
- children: [footerNoteText !== null ? /* @__PURE__ */ jsx("p", {
48464
- className: "event-week-board-foot-note",
48465
- children: footerNoteText
48466
- }) : null, hasCta ? /* @__PURE__ */ jsx("a", {
48467
- className: ctaClassName,
48468
- href: ctaHref ?? void 0,
48469
- children: ctaLabel
48470
- }) : null]
48471
- }) : null
48763
+ /* @__PURE__ */ jsx(WeekBoardGrid, {
48764
+ days,
48765
+ eventsByDate,
48766
+ showCapacity,
48767
+ today
48768
+ }),
48769
+ /* @__PURE__ */ jsx(WeekBoardFooter, {
48770
+ note: footerNoteText,
48771
+ ctaHref: resolvedCtaHref,
48772
+ ctaLabel,
48773
+ ctaClassName
48774
+ })
48472
48775
  ]
48473
48776
  })
48474
48777
  });
@@ -48499,6 +48802,7 @@ function buildTimetableModel(input) {
48499
48802
  items: input.events,
48500
48803
  viewDate: input.viewDate,
48501
48804
  startOfWeek: input.startOfWeek,
48805
+ today: input.today,
48502
48806
  getId: (event) => event.id,
48503
48807
  getStartsAt: (event) => event.startsAt,
48504
48808
  getEndsAt: (event) => event.endsAt,
@@ -48560,10 +48864,10 @@ function formatEventTimeRange(event) {
48560
48864
  return `${formatTime(event.startsAt, { timeZone })} - ${formatTime(event.endsAt, { timeZone })}`;
48561
48865
  }
48562
48866
  function formatDayLabel(date) {
48563
- return `${FULL_DAY_NAMES[date.getDay()] ?? ""}, ${MONTH_NAMES[date.getMonth()] ?? ""} ${date.getDate()}`;
48867
+ return `${FULL_DAY_NAMES[getDayOfWeek(date)] ?? ""}, ${MONTH_NAMES[date.month - 1] ?? ""} ${date.day}`;
48564
48868
  }
48565
48869
  function formatShortDayLabel(date) {
48566
- return `${(FULL_DAY_NAMES[date.getDay()] ?? "").slice(0, 3)} ${date.getDate()}`;
48870
+ return `${(FULL_DAY_NAMES[getDayOfWeek(date)] ?? "").slice(0, 3)} ${date.day}`;
48567
48871
  }
48568
48872
  //#endregion
48569
48873
  //#region ../blocks/src/system/runtime/nodes/events/EventCalendar.server.tsx
@@ -48610,15 +48914,15 @@ function renderListSsr(display, prefetchedEvents) {
48610
48914
  renderEventCard: (event) => renderEventCard(event, listDisplay)
48611
48915
  });
48612
48916
  }
48613
- function renderCalendarSsr(display) {
48917
+ function renderCalendarSsr(display, hydration) {
48614
48918
  const calendarView = display.defaultCalendarView;
48615
- const viewDate = /* @__PURE__ */ new Date();
48919
+ const viewDate = hydration.calendarContext.initialToday;
48616
48920
  const viewport = buildCalendarViewport({
48617
48921
  view: calendarView,
48618
48922
  anchorDate: viewDate,
48619
48923
  startOfWeek: display.startOfWeek
48620
48924
  });
48621
- const eventsByDate = groupEventsByDate([...display.events]);
48925
+ const eventsByDate = groupEventsByDate([...display.events], hydration.calendarContext.timeZone);
48622
48926
  const dayNames = getOrderedDayNames(display.startOfWeek);
48623
48927
  return /* @__PURE__ */ jsxs("div", {
48624
48928
  className: clsx("event-calendar", display.className ?? void 0),
@@ -48685,7 +48989,9 @@ function renderCalendarSsr(display) {
48685
48989
  days: viewport.days,
48686
48990
  events: [...display.events],
48687
48991
  emptyMessage: display.emptyMessage,
48688
- showCapacity: display.showCapacity
48992
+ showCapacity: display.showCapacity,
48993
+ calendarTimeZone: hydration.calendarContext.timeZone,
48994
+ today: hydration.calendarContext.initialToday
48689
48995
  }) : /* @__PURE__ */ jsxs("div", {
48690
48996
  className: "event-calendar-container",
48691
48997
  children: [/* @__PURE__ */ jsx("div", {
@@ -48699,13 +49005,13 @@ function renderCalendarSsr(display) {
48699
49005
  children: viewport.days.map((date) => {
48700
49006
  const dateKey = formatDateKey(date);
48701
49007
  const dayEvents = eventsByDate.get(dateKey) || [];
48702
- const isCurrentMonth = date.getMonth() === viewDate.getMonth();
48703
- const today = isToday(date);
49008
+ const isCurrentMonth = date.month === viewDate.month;
49009
+ const today = isToday(date, hydration.calendarContext.initialToday);
48704
49010
  return /* @__PURE__ */ jsxs("div", {
48705
49011
  className: clsx("event-calendar-day", !isCurrentMonth && "event-calendar-day--other-month", today && "event-calendar-day--today"),
48706
49012
  children: [/* @__PURE__ */ jsx("div", {
48707
49013
  className: "event-calendar-day-number",
48708
- children: date.getDate()
49014
+ children: date.day
48709
49015
  }), /* @__PURE__ */ jsxs("div", {
48710
49016
  className: "event-calendar-events",
48711
49017
  children: [dayEvents.slice(0, 3).map((event) => /* @__PURE__ */ jsxs("a", {
@@ -48743,8 +49049,8 @@ function renderCalendarSsr(display) {
48743
49049
  ]
48744
49050
  });
48745
49051
  }
48746
- function renderTimetableSsr(display) {
48747
- const viewDate = /* @__PURE__ */ new Date();
49052
+ function renderTimetableSsr(display, hydration) {
49053
+ const viewDate = hydration.calendarContext.initialToday;
48748
49054
  const viewport = buildCalendarViewport({
48749
49055
  view: "week",
48750
49056
  anchorDate: viewDate,
@@ -48753,7 +49059,8 @@ function renderTimetableSsr(display) {
48753
49059
  const model = buildTimetableModel({
48754
49060
  events: [...display.events],
48755
49061
  viewDate,
48756
- startOfWeek: display.startOfWeek
49062
+ startOfWeek: display.startOfWeek,
49063
+ today: hydration.calendarContext.initialToday
48757
49064
  });
48758
49065
  const selectedDayKey = model.days.find((day) => day.isToday)?.dateKey ?? model.days[0]?.dateKey ?? "";
48759
49066
  return /* @__PURE__ */ jsxs("div", {
@@ -48908,20 +49215,21 @@ function renderTimetableSsr(display) {
48908
49215
  })]
48909
49216
  });
48910
49217
  }
48911
- function renderWeekBoardSsr(display) {
48912
- return /* @__PURE__ */ jsx(WeekBoardView, {
48913
- days: getWeekCalendarDayTuple(/* @__PURE__ */ new Date(), display.startOfWeek),
48914
- events: [...display.events],
48915
- showCapacity: display.showCapacity,
48916
- emptyMessage: display.emptyMessage,
48917
- title: display.boardTitle,
48918
- footerNote: display.footerNote,
48919
- ctaLabel: display.loadMoreText ?? display.buttonText,
48920
- ctaHref: display.seeAllUrl,
48921
- buttonVariant: display.buttonVariant,
48922
- elevated: display.elevated,
48923
- banded: display.banded
48924
- });
49218
+ function renderWeekBoardSsr(display, hydration) {
49219
+ const today = hydration.calendarContext.initialToday;
49220
+ const days = getWeekCalendarDayTuple(today, display.startOfWeek);
49221
+ const navigation = {
49222
+ kind: "static",
49223
+ ...buildWeekBoardNavigationState({
49224
+ days,
49225
+ title: formatCalendarTitle(today, "week", [...days])
49226
+ }, today)
49227
+ };
49228
+ return /* @__PURE__ */ jsx(WeekBoardView, { ...buildWeekBoardViewProps({
49229
+ ...display,
49230
+ calendarTimeZone: hydration.calendarContext.timeZone,
49231
+ today
49232
+ }, days, navigation) });
48925
49233
  }
48926
49234
  function formatHourLabel(hour) {
48927
49235
  if (hour === 0) return "12 AM";
@@ -48947,13 +49255,13 @@ const EventCalendarSSR = (props) => {
48947
49255
  content = renderListSsr(display, hydration.prefetchedEvents);
48948
49256
  break;
48949
49257
  case "timetable":
48950
- content = renderTimetableSsr(display);
49258
+ content = renderTimetableSsr(display, hydration);
48951
49259
  break;
48952
49260
  case "week-board":
48953
- content = renderWeekBoardSsr(display);
49261
+ content = renderWeekBoardSsr(display, hydration);
48954
49262
  break;
48955
49263
  case "calendar":
48956
- content = renderCalendarSsr(display);
49264
+ content = renderCalendarSsr(display, hydration);
48957
49265
  break;
48958
49266
  default: content = assertNeverDisplayMode(display.displayMode);
48959
49267
  }
@@ -49626,14 +49934,14 @@ function isDecoratedHeadingBlockKind(blockKind) {
49626
49934
  return blockKind === "block.intro" || blockKind === "block.feature-cards" || blockKind === "block.testimonials" || blockKind === "block.faq";
49627
49935
  }
49628
49936
  function readVariant(blockContent) {
49629
- if (!isRecord$4(blockContent)) return void 0;
49937
+ if (!isRecord$5(blockContent)) return void 0;
49630
49938
  const variant = blockContent.variant;
49631
49939
  return typeof variant === "string" ? variant : void 0;
49632
49940
  }
49633
49941
  function isFaqDecoratedVariant(variant) {
49634
49942
  return variant === "default" || variant === "question-columns";
49635
49943
  }
49636
- function isRecord$4(value) {
49944
+ function isRecord$5(value) {
49637
49945
  return typeof value === "object" && value !== null && !Array.isArray(value);
49638
49946
  }
49639
49947
  function buildHeadingDecorationWrapperClassName(className) {
@@ -50739,11 +51047,11 @@ function readTreatment(kind, value) {
50739
51047
  };
50740
51048
  }
50741
51049
  function readBlockComposition(value) {
50742
- if (!isRecord$3(value) || typeof value.kind !== "string") return null;
51050
+ if (!isRecord$4(value) || typeof value.kind !== "string") return null;
50743
51051
  if (!isCompositionKind(value.kind)) return null;
50744
51052
  return readTreatment(value.kind, value.treatment);
50745
51053
  }
50746
- function isRecord$3(value) {
51054
+ function isRecord$4(value) {
50747
51055
  return typeof value === "object" && value !== null && !Array.isArray(value);
50748
51056
  }
50749
51057
  //#endregion
@@ -50995,7 +51303,7 @@ function hydrateResolvedBookingConsentValue(value, context) {
50995
51303
  const hydratedItems = value.map((item) => hydrateResolvedBookingConsentValue(item, context));
50996
51304
  return hydratedItems.every((item, index) => item === value[index]) ? value : hydratedItems;
50997
51305
  }
50998
- if (!isRecord$13(value)) return value;
51306
+ if (!isRecord$15(value)) return value;
50999
51307
  if (isBookingConsentCarrier(value)) {
51000
51308
  const agreement = hydrateValue(value.agreement, context);
51001
51309
  return agreement === value.agreement ? value : {
@@ -51015,7 +51323,7 @@ function hydrateValue(value, context) {
51015
51323
  const resolvedItems = value.map((item) => hydrateValue(item, context));
51016
51324
  return resolvedItems.every((item, index) => item === value[index]) ? value : resolvedItems;
51017
51325
  }
51018
- if (isRecord$13(value)) {
51326
+ if (isRecord$15(value)) {
51019
51327
  if (isInternalLink(value)) return hydrateInternalLink(value, context.routes);
51020
51328
  if (isPageLink(value)) return hydratePageLink(value, context);
51021
51329
  if (isEntryLink(value)) return hydrateEntryLink(value, context);
@@ -51080,7 +51388,7 @@ function hydrateEntryLink(link, context) {
51080
51388
  //#region ../blocks/src/system/manifest/resolveBlockData.ts
51081
51389
  function resolveBlockData(blockId, dataLoaders, dataContext, routes) {
51082
51390
  const raw = blockId ? dataContext?.resolvedData?.[blockId] : void 0;
51083
- if (isRecord$13(raw)) return routes ? hydrateResolvedBookingConsentLinks(raw, routes, dataContext?.pagesByIdentifier, dataContext?.entriesByIdentifier) : raw;
51391
+ if (isRecord$15(raw)) return routes ? hydrateResolvedBookingConsentLinks(raw, routes, dataContext?.pagesByIdentifier, dataContext?.entriesByIdentifier) : raw;
51084
51392
  return dataLoaders && typeof dataLoaders === "object" && Object.keys(dataLoaders).length > 0 ? {} : void 0;
51085
51393
  }
51086
51394
  //#endregion
@@ -52097,36 +52405,9 @@ function buildLegacyHeaderNavLinkStyle(header, contrastTreatment, navTextSize) {
52097
52405
  ...navTextSize ? { textSize: navTextSize } : {}
52098
52406
  };
52099
52407
  if (header.navWeight === "bold" && navStyle === "solid") style.textTransform = "uppercase";
52100
- applyLegacyNavEffects(style, header);
52101
52408
  applyLegacyGlassTreatment(style, header, navStyle);
52102
52409
  return style;
52103
52410
  }
52104
- function applyLegacyNavEffects(style, header) {
52105
- if (!header.navEffects) return;
52106
- const effects = style.effects = {
52107
- ...style.effects,
52108
- hover: [...style.effects?.hover ?? []],
52109
- active: [...style.effects?.active ?? []]
52110
- };
52111
- if (header.navEffects.glow) effects.hover.push({
52112
- effectId: "outer-glow",
52113
- options: { spread: 5 }
52114
- });
52115
- if (header.navEffects.neumorphic) {
52116
- effects.hover.push({
52117
- effectId: "neumorphic-shadow",
52118
- options: { mode: "pressed" }
52119
- });
52120
- effects.hover.push({
52121
- effectId: "text-color-change",
52122
- options: { hoverColorToken: "primary" }
52123
- });
52124
- }
52125
- if (header.navEffects.underlineGradient) effects.hover.push({
52126
- effectId: "border-bottom-grow",
52127
- options: { origin: "center" }
52128
- });
52129
- }
52130
52411
  function applyLegacyGlassTreatment(style, header, navStyle) {
52131
52412
  if (header.navContainer?.type !== "glass" || navStyle !== "minimal") return;
52132
52413
  style.borderRadius = "full";
@@ -52152,19 +52433,6 @@ function glassStateEffects(opacity) {
52152
52433
  //#region ../theme-core/src/header/generateHeaderCss.ts
52153
52434
  const HEADER_BLUR = "blur(12px)";
52154
52435
  const FLOATING_BLUR = "blur(16px)";
52155
- const INSET_SHELL_MARKER_CLASS = "header-bar-frame-inset-shell";
52156
- const INSET_SHELL_EDGE = "1rem";
52157
- const INSET_SHELL_INSET_BLOCK = "0.875rem";
52158
- const INSET_SHELL_RADIUS = "9999px";
52159
- const INSET_SHELL_CONTAINER_MAX = "80rem";
52160
- const INSET_SHELL_INTERIOR_PADDING_X = "1.75rem";
52161
- /**
52162
- * Whether the classic header should render as an inset "brand capsule" shell.
52163
- * The facet is only meaningful for the classic layout; other variants ignore it.
52164
- */
52165
- function usesInsetShell(header) {
52166
- return header.barFrame === "inset-shell" && header.variant === "classic";
52167
- }
52168
52436
  /**
52169
52437
  * Generate complete CSS for header system from theme config
52170
52438
  *
@@ -52242,36 +52510,7 @@ function generateHeaderRootStyles(header, themeId, tokens) {
52242
52510
  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`;
52243
52511
  const scrollTreatmentStyles = generateHeaderScrollTreatmentStyles(header.scrollTreatment, themeId, header.variant, scrolledPaintRules);
52244
52512
  if (isContainedNav || basePaintRules.length === 0) return `${baseBlock}\n${overlayFix}${scrollTreatmentStyles}`;
52245
- return `${baseBlock}\n${renderHeaderPaintTargetRules(getHeaderPaintTargets(header.variant, themeId), basePaintRules)}\n${overlayFix}${usesInsetShell(header) ? generateInsetShellStyles(header, themeId) : ""}${scrollTreatmentStyles}`;
52246
- }
52247
- /**
52248
- * Reshapes the full-bleed header paint layer into a contained brand capsule at
52249
- * the desktop breakpoint. The capsule is centred, capped to the page container
52250
- * width, inset from the top, fully rounded, and carries the header depth so it
52251
- * reads as a floating pill. Root border/shadow are neutralised on desktop so a
52252
- * bordered style does not leave a full-width hairline around the capsule. Sticky
52253
- * positioning is unaffected — the root stays full width and sticky while the
52254
- * ::before paint provides the capsule.
52255
- */
52256
- function generateInsetShellStyles(header, themeId) {
52257
- const scope = `:where([data-theme-scope="${themeId}"])`;
52258
- const shellRootSelector = `${scope} .header-root.${INSET_SHELL_MARKER_CLASS}`;
52259
- const shellBeforeSelector = `${scope} .header-root.${INSET_SHELL_MARKER_CLASS}::before`;
52260
- const layoutSelector = `${scope} .header-root.${INSET_SHELL_MARKER_CLASS} .rb-header-layout`;
52261
- const widthValue = header.maxWidth === "full" ? `calc(100% - (${INSET_SHELL_EDGE} * 2))` : `min(${INSET_SHELL_CONTAINER_MAX}, calc(100% - (${INSET_SHELL_EDGE} * 2)))`;
52262
- const shadowVar = getComponentShadowVar(header.shadow?.elevation ?? "none");
52263
- const rootRules = ["border: none;", "box-shadow: none;"];
52264
- const beforeRules = [
52265
- `inset: ${INSET_SHELL_INSET_BLOCK} auto;`,
52266
- "left: 50%;",
52267
- "right: auto;",
52268
- "transform: translateX(-50%);",
52269
- `width: ${widthValue};`,
52270
- `border-radius: ${INSET_SHELL_RADIUS};`,
52271
- ...shadowVar ? [`box-shadow: ${shadowVar};`] : []
52272
- ];
52273
- const layoutRules = [`padding-inline: ${INSET_SHELL_INTERIOR_PADDING_X};`];
52274
- return `\n@media ${MQ_MD_UP} {\n${shellRootSelector} {\n ${rootRules.join("\n ")}\n}\n${shellBeforeSelector} {\n ${beforeRules.join("\n ")}\n}\n${layoutSelector} {\n ${layoutRules.join("\n ")}\n}\n}\n`;
52513
+ return `${baseBlock}\n${renderHeaderPaintTargetRules(getHeaderPaintTargets(header.variant, themeId), basePaintRules)}\n${overlayFix}${scrollTreatmentStyles}`;
52275
52514
  }
52276
52515
  /**
52277
52516
  * Generate logo typography styles
@@ -52345,7 +52584,7 @@ function generateLogoTextBehaviorStyles(logoText, themeId) {
52345
52584
  * Generate navigation link styles based on navStyle and effects
52346
52585
  *
52347
52586
  * Uses the composable NavLinkStyle system with backward compatibility for
52348
- * legacy navStyle, navWeight, navColor, and navEffects settings.
52587
+ * legacy navStyle, navWeight and navColor settings.
52349
52588
  */
52350
52589
  function generateNavLinkStyles(header, themeId, tokens, theme, contrastTreatment, navTextSize) {
52351
52590
  const navPreferences = {
@@ -54982,9 +55221,43 @@ function pageBlockPosition(index, blockCount) {
54982
55221
  return "middle";
54983
55222
  }
54984
55223
  //#endregion
55224
+ //#region ../blocks/src/pageRenderAdmission.ts
55225
+ function toPresentationPage(page) {
55226
+ if (!page) return null;
55227
+ return {
55228
+ ...page,
55229
+ blocks: page.blocks.map((block) => {
55230
+ const presentationMetadata = {
55231
+ id: block.id,
55232
+ kind: block.kind,
55233
+ purpose: block.purpose,
55234
+ ...block.bindings ? { bindings: block.bindings } : {}
55235
+ };
55236
+ return block.admission.kind === "renderable" ? {
55237
+ ...presentationMetadata,
55238
+ content: block.admission.content,
55239
+ presentationAdmission: { kind: "renderable" }
55240
+ } : {
55241
+ ...presentationMetadata,
55242
+ presentationAdmission: {
55243
+ kind: "invalid",
55244
+ error: block.admission.error
55245
+ }
55246
+ };
55247
+ })
55248
+ };
55249
+ }
55250
+ //#endregion
54985
55251
  //#region ../blocks/src/PageRenderer.tsx
54986
55252
  function PageRenderer$1(props) {
54987
- const { page, runtimeBoundaries, usePlaceholders = false, dataContext, wrapBlock, wrapBoundary, registry, routeMap, blockOverrides, sdkConfig, customBlocks, previewAuthoring } = props;
55253
+ const page = React$1.useMemo(() => toPresentationPage(props.page), [props.page]);
55254
+ return /* @__PURE__ */ jsx(PageRendererCore, {
55255
+ ...props,
55256
+ page
55257
+ });
55258
+ }
55259
+ function PageRendererCore(props) {
55260
+ const { page, runtimeBoundaries, dataContext, wrapBlock, wrapBoundary, registry } = props;
54988
55261
  const imageResolveContext = React$1.useMemo(() => resolvePageRendererImageResolveContext(dataContext), [
54989
55262
  dataContext?.imageResolveContext,
54990
55263
  dataContext?.mediaAssets,
@@ -55083,11 +55356,11 @@ function resolvePageRendererImageResolveContext(dataContext) {
55083
55356
  mediaAssets: input?.mediaAssets ?? dataContext?.mediaAssets
55084
55357
  });
55085
55358
  }
55359
+ const resolveBookingTimeZone = (dataContext) => dataContext?.bookingTimeZone;
55086
55360
  function buildBlockSectionProps(input) {
55087
55361
  return {
55088
55362
  themeResources: input.themeResources,
55089
55363
  block: input.block,
55090
- usePlaceholders: input.props.usePlaceholders ?? false,
55091
55364
  dataContext: input.props.dataContext,
55092
55365
  blockKey: input.blockKey,
55093
55366
  registry: input.registry,
@@ -55111,7 +55384,6 @@ function getBlockOverride(blockKind, overrides) {
55111
55384
  if (overrides[shortKind]) return overrides[shortKind];
55112
55385
  }
55113
55386
  const blockComponentCache = /* @__PURE__ */ new WeakMap();
55114
- const manifestValidatorCache = /* @__PURE__ */ new WeakMap();
55115
55387
  const DEFAULT_PERF_SLOW_BLOCK_RENDER_THRESHOLD_MS = 25;
55116
55388
  let cachedPerfSlowBlockRenderThresholdMs = null;
55117
55389
  function getPerfSlowBlockRenderThresholdMs() {
@@ -55129,44 +55401,13 @@ function getCachedBlockComponent(manifest) {
55129
55401
  return created;
55130
55402
  }
55131
55403
  /**
55132
- * Render-time manifest validator — see `.claude/plans/dapper-jingling-emerson.md`
55133
- * Phase 10. One function, two flavours:
55134
- *
55135
- * - `strict` (default): the contract every render surface tries first. No
55136
- * null tolerance, no missing-required tolerance. Production frontends and
55137
- * the dashboard preview both go through this path; after Phases 6-9 the
55138
- * preview satisfies strict structurally.
55139
- * - `relaxed`: editor-mid-edit fallback. Reached via `usePlaceholders` when
55140
- * strict fails. Built on `mode: 'draft'` so empty required fields parse
55141
- * as `undefined` and the user's valid in-flight fields flow through.
55142
- *
55143
- * Per-manifest, per-flavour cached. Adding a third flavour means adding a
55144
- * branch to the `createManifestValidator` call below and a member to
55145
- * `ValidationFlavour` — no per-flavour helper duplication.
55146
- */
55147
- function getCachedValidator(manifest, flavour) {
55148
- let perFlavour = manifestValidatorCache.get(manifest);
55149
- if (!perFlavour) {
55150
- perFlavour = /* @__PURE__ */ new Map();
55151
- manifestValidatorCache.set(manifest, perFlavour);
55152
- }
55153
- const cached = perFlavour.get(flavour);
55154
- if (cached) return cached;
55155
- const created = createManifestValidator(manifest, {
55156
- allowNull: false,
55157
- ...flavour === "relaxed" ? { mode: "draft" } : {}
55158
- });
55159
- perFlavour.set(flavour, created);
55160
- return created;
55161
- }
55162
- /**
55163
55404
  * Memoized block section component.
55164
55405
  *
55165
55406
  * Custom memoization prevents render loops during editing by explicitly checking
55166
55407
  * referential equality of all props that affect rendering. Standard React.memo
55167
55408
  * wouldn't catch all the render triggers from the editor store.
55168
55409
  */
55169
- const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeResources, block, usePlaceholders, dataContext, registry, routeMap, wrapBlock, blockOverrides, sdkConfig, customBlocks, imageResolveContext, previewAuthoring }) {
55410
+ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeResources, block, dataContext, registry, routeMap, wrapBlock, blockOverrides, sdkConfig, customBlocks, imageResolveContext, previewAuthoring }) {
55170
55411
  const perfStart = globalThis.process?.env?.DEBUG_PERF === "1" && typeof window === "undefined" ? Date.now() : 0;
55171
55412
  const fallbackImageResolveContext = getCurrentResolveImageUrlContext();
55172
55413
  const resolvedImageResolveContext = imageResolveContext ?? fallbackImageResolveContext;
@@ -55186,6 +55427,19 @@ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeResources
55186
55427
  } catch {}
55187
55428
  return node;
55188
55429
  }
55430
+ if (block.presentationAdmission.kind === "invalid") {
55431
+ try {
55432
+ if (globalThis.process?.env?.NODE_ENV !== "production") console.warn("[blocks:PageRenderer] block admission failed", {
55433
+ blockId: block.id ?? null,
55434
+ blockKind: block.kind,
55435
+ error: block.presentationAdmission.error
55436
+ });
55437
+ } catch {}
55438
+ return finish(fallback(`Invalid content for block kind "${block.kind}".`), {
55439
+ outcome: "invalidContent",
55440
+ override: false
55441
+ });
55442
+ }
55189
55443
  const OverrideComponent = getBlockOverride(block.kind, blockOverrides);
55190
55444
  requireBlockOverride(themeResources, OverrideComponent, block.kind);
55191
55445
  let definition = getBlockDefinition(block.kind);
@@ -55255,25 +55509,10 @@ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeResources
55255
55509
  });
55256
55510
  }
55257
55511
  const content = getRenderableContent(block, dataContext?.previewStage);
55258
- const parsed = getCachedValidator(definition.manifest, "strict").safeParse(content);
55259
- try {
55260
- if (globalThis.process?.env?.NODE_ENV !== "production" && !parsed.success && !usePlaceholders) console.warn("[blocks:PageRenderer] manifest validation failed", {
55261
- blockId: block.id ?? null,
55262
- blockKind: block.kind,
55263
- content: summarizeValue(content),
55264
- expectedFields: (definition.manifest.fields ?? []).map((f) => ({
55265
- id: f.id,
55266
- type: f.type,
55267
- required: !!f.required
55268
- })),
55269
- issues: parsed.error?.issues ?? null
55270
- });
55271
- } catch {}
55272
- let data;
55273
- if (parsed.success) data = parsed.data;
55274
- else if (usePlaceholders) {
55275
- const relaxed = getCachedValidator(definition.manifest, "relaxed").safeParse(content);
55276
- if (relaxed.success) data = relaxed.data;
55512
+ let data = content;
55513
+ if (block.presentationAdmission.kind === "editor") {
55514
+ const draft = validateManifestDraft(compileManifestContentContract(definition.manifest), content);
55515
+ if (draft.kind === "previewable") data = draft.data;
55277
55516
  else {
55278
55517
  const rendered = fallback(`Unable to render block kind "${block.kind}".`);
55279
55518
  return finish(wrapBlock && block.id ? /* @__PURE__ */ jsx(Fragment, { children: wrapBlock(block.id, rendered) }) : /* @__PURE__ */ jsx(Fragment, { children: rendered }), {
@@ -55281,12 +55520,6 @@ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeResources
55281
55520
  override: false
55282
55521
  });
55283
55522
  }
55284
- } else {
55285
- const rendered = fallback(`Invalid content for block kind "${block.kind}".`);
55286
- return finish(wrapBlock && block.id ? /* @__PURE__ */ jsx(Fragment, { children: wrapBlock(block.id, rendered) }) : /* @__PURE__ */ jsx(Fragment, { children: rendered }), {
55287
- outcome: "invalidContent",
55288
- override: false
55289
- });
55290
55523
  }
55291
55524
  try {
55292
55525
  const routes = routeMap ?? dataContext?.routes;
@@ -55312,6 +55545,7 @@ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeResources
55312
55545
  blockId: block.id ?? null,
55313
55546
  blockKind: block.kind
55314
55547
  };
55548
+ baseProps.bookingTimeZone = resolveBookingTimeZone(dataContext);
55315
55549
  let rendered;
55316
55550
  if (OverrideComponent) rendered = /* @__PURE__ */ jsx(OverrideComponent, { ...baseProps });
55317
55551
  else {
@@ -55358,14 +55592,14 @@ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeResources
55358
55592
  hasResolvedData
55359
55593
  });
55360
55594
  } catch {
55361
- const rendered = usePlaceholders ? fallback(`Unable to render block kind "${block.kind}".`) : fallback(`Invalid content for block kind "${block.kind}".`);
55595
+ const rendered = block.presentationAdmission.kind === "editor" ? fallback(`Unable to render block kind "${block.kind}".`) : fallback(`Invalid content for block kind "${block.kind}".`);
55362
55596
  return finish(wrapBlock && block.id ? /* @__PURE__ */ jsx(Fragment, { children: wrapBlock(block.id, rendered) }) : /* @__PURE__ */ jsx(Fragment, { children: rendered }), {
55363
55597
  outcome: "exception",
55364
55598
  override: false
55365
55599
  });
55366
55600
  }
55367
55601
  }, (prev, next) => {
55368
- return prev.block === next.block && prev.registry === next.registry && prev.dataContext === next.dataContext && prev.themeResources === next.themeResources && prev.routeMap === next.routeMap && prev.usePlaceholders === next.usePlaceholders && prev.wrapBlock === next.wrapBlock && prev.blockOverrides === next.blockOverrides && prev.sdkConfig === next.sdkConfig && prev.customBlocks === next.customBlocks && prev.imageResolveContext === next.imageResolveContext && prev.previewAuthoring === next.previewAuthoring;
55602
+ return prev.block === next.block && prev.registry === next.registry && prev.dataContext === next.dataContext && prev.themeResources === next.themeResources && prev.routeMap === next.routeMap && prev.block.presentationAdmission === next.block.presentationAdmission && prev.wrapBlock === next.wrapBlock && prev.blockOverrides === next.blockOverrides && prev.sdkConfig === next.sdkConfig && prev.customBlocks === next.customBlocks && prev.imageResolveContext === next.imageResolveContext && prev.previewAuthoring === next.previewAuthoring;
55369
55603
  });
55370
55604
  function fallback(message) {
55371
55605
  return /* @__PURE__ */ jsx("div", {
@@ -55392,32 +55626,6 @@ function getRenderableContent(block, previewStage = "published") {
55392
55626
  if (!isObjectRecord$1(source)) return {};
55393
55627
  return source;
55394
55628
  }
55395
- function summarizeValue(value) {
55396
- try {
55397
- if (value === null || value === void 0) return value;
55398
- if (typeof value === "string") return value.length > 160 ? `${value.slice(0, 160)}…` : value;
55399
- if (typeof value === "number" || typeof value === "boolean") return value;
55400
- if (Array.isArray(value)) return `[array(${value.length})]`;
55401
- if (typeof value === "object") {
55402
- const rec = value;
55403
- const keys = Object.keys(rec);
55404
- const preview = {};
55405
- for (const k of keys.slice(0, 8)) {
55406
- const v = rec[k];
55407
- if (k === "body" || k === "content") preview[k] = !!(v && typeof v === "object" && isObjectRecord$1(v) && v.type === "doc") ? "{type:doc}" : summarizeValue(v);
55408
- else preview[k] = summarizeValue(v);
55409
- }
55410
- return {
55411
- keys,
55412
- preview
55413
- };
55414
- }
55415
- if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint" || typeof value === "symbol") return String(value);
55416
- return "[uninspectable]";
55417
- } catch {
55418
- return "[uninspectable]";
55419
- }
55420
- }
55421
55629
  //#endregion
55422
55630
  //#region ../theme-core/src/footer/mode.ts
55423
55631
  /**
@@ -62051,31 +62259,37 @@ const containerResponsiveThemeCss = `/*
62051
62259
  */
62052
62260
 
62053
62261
  /* Main container */
62054
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar {
62262
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-calendar {
62055
62263
  width: 100%;
62056
62264
  }
62057
62265
 
62058
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-container {
62266
+ :where(.theme-scope)
62267
+ :where([data-block='event-calendar'])
62268
+ .event-calendar-container {
62059
62269
  border: 1px solid var(--ec-border);
62060
62270
  border-radius: var(--rb-block-radius);
62061
62271
  overflow: hidden;
62062
62272
  }
62063
62273
 
62064
62274
  /* Calendar navigation */
62065
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-header {
62275
+ :where(.theme-scope)
62276
+ :where([data-block='event-calendar'])
62277
+ .event-calendar-header {
62066
62278
  display: flex;
62067
62279
  align-items: center;
62068
62280
  justify-content: space-between;
62069
62281
  margin-bottom: 1rem;
62070
62282
  }
62071
62283
 
62072
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-nav {
62284
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-calendar-nav {
62073
62285
  display: flex;
62074
62286
  align-items: center;
62075
62287
  gap: 0.5rem;
62076
62288
  }
62077
62289
 
62078
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-nav-btn {
62290
+ :where(.theme-scope)
62291
+ :where([data-block='event-calendar'])
62292
+ .event-calendar-nav-btn {
62079
62293
  display: flex;
62080
62294
  align-items: center;
62081
62295
  justify-content: center;
@@ -62090,11 +62304,15 @@ const containerResponsiveThemeCss = `/*
62090
62304
  transition: background-color var(--rb-block-transition) ease;
62091
62305
  }
62092
62306
 
62093
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-nav-btn:hover {
62307
+ :where(.theme-scope)
62308
+ :where([data-block='event-calendar'])
62309
+ .event-calendar-nav-btn:hover {
62094
62310
  background-color: var(--ec-nav-hover-bg);
62095
62311
  }
62096
62312
 
62097
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-title {
62313
+ :where(.theme-scope)
62314
+ :where([data-block='event-calendar'])
62315
+ .event-calendar-title {
62098
62316
  font-size: 1.125rem;
62099
62317
  font-weight: 600;
62100
62318
  min-width: 200px;
@@ -62102,13 +62320,17 @@ const containerResponsiveThemeCss = `/*
62102
62320
  }
62103
62321
 
62104
62322
  /* Day headers */
62105
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-day-headers {
62323
+ :where(.theme-scope)
62324
+ :where([data-block='event-calendar'])
62325
+ .event-calendar-day-headers {
62106
62326
  display: grid;
62107
62327
  grid-template-columns: repeat(7, minmax(0, 1fr));
62108
62328
  background-color: var(--ec-header-bg);
62109
62329
  }
62110
62330
 
62111
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-day-header {
62331
+ :where(.theme-scope)
62332
+ :where([data-block='event-calendar'])
62333
+ .event-calendar-day-header {
62112
62334
  text-align: center;
62113
62335
  padding: 0.5rem;
62114
62336
  font-size: 0.875rem;
@@ -62118,33 +62340,43 @@ const containerResponsiveThemeCss = `/*
62118
62340
  }
62119
62341
 
62120
62342
  /* Calendar grid */
62121
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-grid {
62343
+ :where(.theme-scope)
62344
+ :where([data-block='event-calendar'])
62345
+ .event-calendar-grid {
62122
62346
  display: grid;
62123
62347
  grid-template-columns: repeat(7, minmax(0, 1fr));
62124
62348
  }
62125
62349
 
62126
62350
  /* Day cells */
62127
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-day {
62351
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-calendar-day {
62128
62352
  min-height: 100px;
62129
62353
  border-bottom: 1px solid var(--ec-border-subtle);
62130
62354
  border-right: 1px solid var(--ec-border-subtle);
62131
62355
  padding: 0.25rem;
62132
62356
  }
62133
62357
 
62134
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-day:nth-child(7n) {
62358
+ :where(.theme-scope)
62359
+ :where([data-block='event-calendar'])
62360
+ .event-calendar-day:nth-child(7n) {
62135
62361
  border-right: none;
62136
62362
  }
62137
62363
 
62138
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-day--today {
62364
+ :where(.theme-scope)
62365
+ :where([data-block='event-calendar'])
62366
+ .event-calendar-day--today {
62139
62367
  background-color: var(--ec-today-bg);
62140
62368
  }
62141
62369
 
62142
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-day--other-month {
62370
+ :where(.theme-scope)
62371
+ :where([data-block='event-calendar'])
62372
+ .event-calendar-day--other-month {
62143
62373
  opacity: var(--ec-other-month-opacity);
62144
62374
  }
62145
62375
 
62146
62376
  /* Day number */
62147
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-day-number {
62377
+ :where(.theme-scope)
62378
+ :where([data-block='event-calendar'])
62379
+ .event-calendar-day-number {
62148
62380
  font-size: 0.875rem;
62149
62381
  font-weight: 500;
62150
62382
  margin-bottom: 0.25rem;
@@ -62152,21 +62384,28 @@ const containerResponsiveThemeCss = `/*
62152
62384
  opacity: var(--ec-day-number-opacity);
62153
62385
  }
62154
62386
 
62155
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-day--today .event-calendar-day-number {
62387
+ :where(.theme-scope)
62388
+ :where([data-block='event-calendar'])
62389
+ .event-calendar-day--today
62390
+ .event-calendar-day-number {
62156
62391
  font-weight: 700;
62157
62392
  opacity: 1;
62158
62393
  color: var(--ec-today-text);
62159
62394
  }
62160
62395
 
62161
62396
  /* Events list */
62162
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-events {
62397
+ :where(.theme-scope)
62398
+ :where([data-block='event-calendar'])
62399
+ .event-calendar-events {
62163
62400
  display: flex;
62164
62401
  flex-direction: column;
62165
62402
  gap: 0.25rem;
62166
62403
  }
62167
62404
 
62168
62405
  /* Event item - solid primary background */
62169
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-event {
62406
+ :where(.theme-scope)
62407
+ :where([data-block='event-calendar'])
62408
+ .event-calendar-event {
62170
62409
  display: flex;
62171
62410
  align-items: center;
62172
62411
  gap: 0.375rem;
@@ -62187,24 +62426,32 @@ const containerResponsiveThemeCss = `/*
62187
62426
  transform var(--rb-block-transition) ease;
62188
62427
  }
62189
62428
 
62190
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-event:hover {
62429
+ :where(.theme-scope)
62430
+ :where([data-block='event-calendar'])
62431
+ .event-calendar-event:hover {
62191
62432
  background-color: var(--ec-event-solid-hover-bg);
62192
62433
  transform: translateY(-1px);
62193
62434
  }
62194
62435
 
62195
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-event:focus-visible {
62436
+ :where(.theme-scope)
62437
+ :where([data-block='event-calendar'])
62438
+ .event-calendar-event:focus-visible {
62196
62439
  outline: 2px solid var(--ec-event-solid-bg);
62197
62440
  outline-offset: 2px;
62198
62441
  }
62199
62442
 
62200
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-event-time {
62443
+ :where(.theme-scope)
62444
+ :where([data-block='event-calendar'])
62445
+ .event-calendar-event-time {
62201
62446
  flex-shrink: 0;
62202
62447
  white-space: nowrap;
62203
62448
  font-weight: 600;
62204
62449
  opacity: 0.9;
62205
62450
  }
62206
62451
 
62207
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-event-title {
62452
+ :where(.theme-scope)
62453
+ :where([data-block='event-calendar'])
62454
+ .event-calendar-event-title {
62208
62455
  min-width: 0;
62209
62456
  overflow: hidden;
62210
62457
  text-overflow: ellipsis;
@@ -62212,7 +62459,9 @@ const containerResponsiveThemeCss = `/*
62212
62459
  }
62213
62460
 
62214
62461
  /* More indicator - clickable button style */
62215
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-more {
62462
+ :where(.theme-scope)
62463
+ :where([data-block='event-calendar'])
62464
+ .event-calendar-more {
62216
62465
  font-size: 0.75rem;
62217
62466
  padding: 0.25rem 0.5rem;
62218
62467
  color: rgb(var(--tb-primary));
@@ -62224,16 +62473,22 @@ const containerResponsiveThemeCss = `/*
62224
62473
  transition: background-color var(--rb-block-transition) ease;
62225
62474
  }
62226
62475
 
62227
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-more:hover {
62476
+ :where(.theme-scope)
62477
+ :where([data-block='event-calendar'])
62478
+ .event-calendar-more:hover {
62228
62479
  background-color: rgba(var(--tb-primary), 0.1);
62229
62480
  }
62230
62481
 
62231
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-more:focus-visible {
62482
+ :where(.theme-scope)
62483
+ :where([data-block='event-calendar'])
62484
+ .event-calendar-more:focus-visible {
62232
62485
  outline: 2px solid rgb(var(--tb-primary));
62233
62486
  outline-offset: 2px;
62234
62487
  }
62235
62488
 
62236
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-empty {
62489
+ :where(.theme-scope)
62490
+ :where([data-block='event-calendar'])
62491
+ .event-calendar-empty {
62237
62492
  text-align: center;
62238
62493
  font-size: 0.875rem;
62239
62494
  opacity: var(--ec-empty-opacity);
@@ -62241,21 +62496,21 @@ const containerResponsiveThemeCss = `/*
62241
62496
  }
62242
62497
 
62243
62498
  /* Filters container */
62244
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-filters {
62499
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-filters {
62245
62500
  display: flex;
62246
62501
  flex-wrap: wrap;
62247
62502
  gap: 1rem;
62248
62503
  margin-bottom: 1.5rem;
62249
62504
  }
62250
62505
 
62251
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-filter {
62506
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-filter {
62252
62507
  display: flex;
62253
62508
  flex-direction: column;
62254
62509
  gap: 0.375rem;
62255
62510
  min-width: 180px;
62256
62511
  }
62257
62512
 
62258
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-filter-label {
62513
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-filter-label {
62259
62514
  font-size: 0.75rem;
62260
62515
  font-weight: 500;
62261
62516
  text-transform: uppercase;
@@ -62264,19 +62519,23 @@ const containerResponsiveThemeCss = `/*
62264
62519
  }
62265
62520
 
62266
62521
  /* Event filter select inherits base styling from .form-select, only block-specific overrides here */
62267
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-filter-select {
62522
+ :where(.theme-scope)
62523
+ :where([data-block='event-calendar'])
62524
+ .event-filter-select {
62268
62525
  /* Use theme input radius instead of block radius for consistency with other form inputs */
62269
62526
  border-radius: var(--rb-input-radius, var(--rb-block-radius));
62270
62527
  }
62271
62528
 
62272
62529
  /* Category filter buttons */
62273
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-category-buttons {
62530
+ :where(.theme-scope)
62531
+ :where([data-block='event-calendar'])
62532
+ .event-category-buttons {
62274
62533
  display: flex;
62275
62534
  flex-wrap: wrap;
62276
62535
  gap: 0.5rem;
62277
62536
  }
62278
62537
 
62279
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-category-btn {
62538
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-category-btn {
62280
62539
  padding: 0.5rem 1rem;
62281
62540
  font-size: 0.875rem;
62282
62541
  font-weight: 500;
@@ -62288,50 +62547,66 @@ const containerResponsiveThemeCss = `/*
62288
62547
  transition: all var(--rb-block-transition) ease;
62289
62548
  }
62290
62549
 
62291
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-category-btn:hover:not(:disabled) {
62550
+ :where(.theme-scope)
62551
+ :where([data-block='event-calendar'])
62552
+ .event-category-btn:hover:not(:disabled) {
62292
62553
  border-color: rgba(var(--tb-primary), 0.5);
62293
62554
  }
62294
62555
 
62295
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-category-btn:focus-visible {
62556
+ :where(.theme-scope)
62557
+ :where([data-block='event-calendar'])
62558
+ .event-category-btn:focus-visible {
62296
62559
  outline: 2px solid rgb(var(--tb-primary));
62297
62560
  outline-offset: 2px;
62298
62561
  }
62299
62562
 
62300
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-category-btn--active {
62563
+ :where(.theme-scope)
62564
+ :where([data-block='event-calendar'])
62565
+ .event-category-btn--active {
62301
62566
  background-color: rgb(var(--tb-primary));
62302
62567
  border-color: rgb(var(--tb-primary));
62303
62568
  color: var(--ec-event-solid-text);
62304
62569
  }
62305
62570
 
62306
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-category-btn:disabled {
62571
+ :where(.theme-scope)
62572
+ :where([data-block='event-calendar'])
62573
+ .event-category-btn:disabled {
62307
62574
  opacity: 0.5;
62308
62575
  cursor: not-allowed;
62309
62576
  }
62310
62577
 
62311
62578
  /* Allow category filter to be wider for button group */
62312
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-filter:has(.event-category-buttons) {
62579
+ :where(.theme-scope)
62580
+ :where([data-block='event-calendar'])
62581
+ .event-filter:has(.event-category-buttons) {
62313
62582
  min-width: auto;
62314
62583
  flex: 1 1 auto;
62315
62584
  }
62316
62585
 
62317
62586
  /* Combined mode container */
62318
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-combined {
62587
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-combined {
62319
62588
  width: 100%;
62320
62589
  }
62321
62590
 
62322
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-combined-content {
62591
+ :where(.theme-scope)
62592
+ :where([data-block='event-calendar'])
62593
+ .event-combined-content {
62323
62594
  display: flex;
62324
62595
  flex-direction: column;
62325
62596
  }
62326
62597
 
62327
62598
  /* Calendar view toggle (Month/Week) in Combined mode */
62328
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-view-toggle {
62599
+ :where(.theme-scope)
62600
+ :where([data-block='event-calendar'])
62601
+ .event-calendar-view-toggle {
62329
62602
  display: flex;
62330
62603
  gap: 0.25rem;
62331
62604
  margin-bottom: 1rem;
62332
62605
  }
62333
62606
 
62334
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-view-btn {
62607
+ :where(.theme-scope)
62608
+ :where([data-block='event-calendar'])
62609
+ .event-calendar-view-btn {
62335
62610
  padding: 0.5rem 1rem;
62336
62611
  font-size: 0.875rem;
62337
62612
  font-weight: 500;
@@ -62344,12 +62619,16 @@ const containerResponsiveThemeCss = `/*
62344
62619
  transition: all var(--rb-block-transition) ease;
62345
62620
  }
62346
62621
 
62347
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-view-btn:hover {
62622
+ :where(.theme-scope)
62623
+ :where([data-block='event-calendar'])
62624
+ .event-calendar-view-btn:hover {
62348
62625
  opacity: 1;
62349
62626
  border-color: rgba(var(--tb-primary), 0.5);
62350
62627
  }
62351
62628
 
62352
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-view-btn--active {
62629
+ :where(.theme-scope)
62630
+ :where([data-block='event-calendar'])
62631
+ .event-calendar-view-btn--active {
62353
62632
  opacity: 1;
62354
62633
  background-color: rgb(var(--tb-primary));
62355
62634
  border-color: rgb(var(--tb-primary));
@@ -62362,29 +62641,35 @@ const containerResponsiveThemeCss = `/*
62362
62641
  * ----------------------------------------------------------------------------- */
62363
62642
 
62364
62643
  /* Agenda week container */
62365
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-week {
62644
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-agenda-week {
62366
62645
  display: flex;
62367
62646
  flex-direction: column;
62368
62647
  gap: 0;
62369
62648
  }
62370
62649
 
62371
62650
  /* Individual day section */
62372
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-day {
62651
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-agenda-day {
62373
62652
  border-bottom: 1px solid var(--ec-border-subtle);
62374
62653
  }
62375
62654
 
62376
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-day:last-child {
62655
+ :where(.theme-scope)
62656
+ :where([data-block='event-calendar'])
62657
+ .event-agenda-day:last-child {
62377
62658
  border-bottom: none;
62378
62659
  }
62379
62660
 
62380
62661
  /* Day header */
62381
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-day-header {
62662
+ :where(.theme-scope)
62663
+ :where([data-block='event-calendar'])
62664
+ .event-agenda-day-header {
62382
62665
  padding: 0.75rem 0;
62383
62666
  background-color: var(--ec-header-bg);
62384
62667
  border-bottom: 1px solid var(--ec-border-subtle);
62385
62668
  }
62386
62669
 
62387
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-day-title {
62670
+ :where(.theme-scope)
62671
+ :where([data-block='event-calendar'])
62672
+ .event-agenda-day-title {
62388
62673
  font-size: 0.875rem;
62389
62674
  font-weight: 600;
62390
62675
  margin: 0;
@@ -62394,7 +62679,9 @@ const containerResponsiveThemeCss = `/*
62394
62679
  }
62395
62680
 
62396
62681
  /* Today badge */
62397
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-day-today-badge {
62682
+ :where(.theme-scope)
62683
+ :where([data-block='event-calendar'])
62684
+ .event-agenda-day-today-badge {
62398
62685
  display: inline-flex;
62399
62686
  align-items: center;
62400
62687
  padding: 0.125rem 0.5rem;
@@ -62408,24 +62695,33 @@ const containerResponsiveThemeCss = `/*
62408
62695
  }
62409
62696
 
62410
62697
  /* Today highlight for entire day section */
62411
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-day--today .event-agenda-day-header {
62698
+ :where(.theme-scope)
62699
+ :where([data-block='event-calendar'])
62700
+ .event-agenda-day--today
62701
+ .event-agenda-day-header {
62412
62702
  background-color: var(--ec-today-bg);
62413
62703
  }
62414
62704
 
62415
62705
  /* Day content area */
62416
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-day-content {
62706
+ :where(.theme-scope)
62707
+ :where([data-block='event-calendar'])
62708
+ .event-agenda-day-content {
62417
62709
  padding: 0.75rem 0;
62418
62710
  }
62419
62711
 
62420
62712
  /* Events list within a day */
62421
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-day-events {
62713
+ :where(.theme-scope)
62714
+ :where([data-block='event-calendar'])
62715
+ .event-agenda-day-events {
62422
62716
  display: flex;
62423
62717
  flex-direction: column;
62424
62718
  gap: 0.5rem;
62425
62719
  }
62426
62720
 
62427
62721
  /* Empty day message */
62428
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-day-empty {
62722
+ :where(.theme-scope)
62723
+ :where([data-block='event-calendar'])
62724
+ .event-agenda-day-empty {
62429
62725
  font-size: 0.875rem;
62430
62726
  opacity: var(--ec-empty-opacity);
62431
62727
  margin: 0;
@@ -62437,7 +62733,7 @@ const containerResponsiveThemeCss = `/*
62437
62733
  * Rich event card for agenda view
62438
62734
  * ----------------------------------------------------------------------------- */
62439
62735
 
62440
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-card {
62736
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-agenda-card {
62441
62737
  display: flex;
62442
62738
  align-items: flex-start;
62443
62739
  gap: 0.75rem;
@@ -62450,13 +62746,17 @@ const containerResponsiveThemeCss = `/*
62450
62746
  transition: all var(--rb-block-transition) ease;
62451
62747
  }
62452
62748
 
62453
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-card:hover {
62749
+ :where(.theme-scope)
62750
+ :where([data-block='event-calendar'])
62751
+ .event-agenda-card:hover {
62454
62752
  border-color: rgba(var(--tb-primary), 0.5);
62455
62753
  background-color: var(--ec-event-bg);
62456
62754
  }
62457
62755
 
62458
62756
  /* Category color indicator */
62459
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-card-indicator {
62757
+ :where(.theme-scope)
62758
+ :where([data-block='event-calendar'])
62759
+ .event-agenda-card-indicator {
62460
62760
  flex-shrink: 0;
62461
62761
  width: 4px;
62462
62762
  align-self: stretch;
@@ -62465,7 +62765,9 @@ const containerResponsiveThemeCss = `/*
62465
62765
  }
62466
62766
 
62467
62767
  /* Card content wrapper */
62468
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-card-content {
62768
+ :where(.theme-scope)
62769
+ :where([data-block='event-calendar'])
62770
+ .event-agenda-card-content {
62469
62771
  flex: 1;
62470
62772
  min-width: 0;
62471
62773
  display: flex;
@@ -62474,28 +62776,36 @@ const containerResponsiveThemeCss = `/*
62474
62776
  }
62475
62777
 
62476
62778
  /* Header row: time + title */
62477
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-card-header {
62779
+ :where(.theme-scope)
62780
+ :where([data-block='event-calendar'])
62781
+ .event-agenda-card-header {
62478
62782
  display: flex;
62479
62783
  align-items: baseline;
62480
62784
  gap: 0.5rem;
62481
62785
  flex-wrap: wrap;
62482
62786
  }
62483
62787
 
62484
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-card-time {
62788
+ :where(.theme-scope)
62789
+ :where([data-block='event-calendar'])
62790
+ .event-agenda-card-time {
62485
62791
  font-size: 0.75rem;
62486
62792
  font-weight: 600;
62487
62793
  opacity: var(--ec-time-opacity);
62488
62794
  white-space: nowrap;
62489
62795
  }
62490
62796
 
62491
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-card-title {
62797
+ :where(.theme-scope)
62798
+ :where([data-block='event-calendar'])
62799
+ .event-agenda-card-title {
62492
62800
  font-size: 0.875rem;
62493
62801
  font-weight: 500;
62494
62802
  line-height: 1.3;
62495
62803
  }
62496
62804
 
62497
62805
  /* Details row: venue, price, capacity */
62498
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-card-details {
62806
+ :where(.theme-scope)
62807
+ :where([data-block='event-calendar'])
62808
+ .event-agenda-card-details {
62499
62809
  display: flex;
62500
62810
  align-items: center;
62501
62811
  gap: 0.75rem;
@@ -62504,26 +62814,36 @@ const containerResponsiveThemeCss = `/*
62504
62814
  opacity: 0.7;
62505
62815
  }
62506
62816
 
62507
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-card-venue {
62817
+ :where(.theme-scope)
62818
+ :where([data-block='event-calendar'])
62819
+ .event-agenda-card-venue {
62508
62820
  display: inline-flex;
62509
62821
  align-items: center;
62510
62822
  gap: 0.25rem;
62511
62823
  }
62512
62824
 
62513
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-card-icon {
62825
+ :where(.theme-scope)
62826
+ :where([data-block='event-calendar'])
62827
+ .event-agenda-card-icon {
62514
62828
  flex-shrink: 0;
62515
62829
  opacity: 0.7;
62516
62830
  }
62517
62831
 
62518
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-card-price {
62832
+ :where(.theme-scope)
62833
+ :where([data-block='event-calendar'])
62834
+ .event-agenda-card-price {
62519
62835
  font-weight: 500;
62520
62836
  }
62521
62837
 
62522
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-card-capacity {
62838
+ :where(.theme-scope)
62839
+ :where([data-block='event-calendar'])
62840
+ .event-agenda-card-capacity {
62523
62841
  font-weight: 500;
62524
62842
  }
62525
62843
 
62526
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-card-capacity--full {
62844
+ :where(.theme-scope)
62845
+ :where([data-block='event-calendar'])
62846
+ .event-agenda-card-capacity--full {
62527
62847
  color: rgb(var(--tb-error, 239 68 68));
62528
62848
  opacity: 1;
62529
62849
  }
@@ -62533,20 +62853,24 @@ const containerResponsiveThemeCss = `/*
62533
62853
  * Time-grid layout for recurring class schedules
62534
62854
  * ----------------------------------------------------------------------------- */
62535
62855
 
62536
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable {
62856
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-timetable {
62537
62857
  display: flex;
62538
62858
  flex-direction: column;
62539
62859
  gap: 0.75rem;
62540
62860
  }
62541
62861
 
62542
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-day-selector {
62862
+ :where(.theme-scope)
62863
+ :where([data-block='event-calendar'])
62864
+ .event-timetable-day-selector {
62543
62865
  display: none;
62544
62866
  gap: 0.375rem;
62545
62867
  overflow-x: auto;
62546
62868
  padding-bottom: 0.125rem;
62547
62869
  }
62548
62870
 
62549
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-day-tab {
62871
+ :where(.theme-scope)
62872
+ :where([data-block='event-calendar'])
62873
+ .event-timetable-day-tab {
62550
62874
  flex: 0 0 auto;
62551
62875
  padding: 0.5rem 0.75rem;
62552
62876
  border: 1px solid var(--ec-border);
@@ -62561,35 +62885,49 @@ const containerResponsiveThemeCss = `/*
62561
62885
  border-color var(--rb-block-transition) ease;
62562
62886
  }
62563
62887
 
62564
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-day-tab--active {
62888
+ :where(.theme-scope)
62889
+ :where([data-block='event-calendar'])
62890
+ .event-timetable-day-tab--active {
62565
62891
  background-color: rgb(var(--tb-primary));
62566
62892
  border-color: rgb(var(--tb-primary));
62567
62893
  color: rgb(var(--tb-primaryText, 255 255 255));
62568
62894
  }
62569
62895
 
62570
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-container {
62896
+ :where(.theme-scope)
62897
+ :where([data-block='event-calendar'])
62898
+ .event-timetable-container {
62571
62899
  border: 1px solid var(--ec-border);
62572
62900
  border-radius: var(--rb-block-radius);
62573
62901
  overflow-x: auto;
62574
62902
  overflow-y: hidden;
62575
62903
  }
62576
62904
 
62577
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-grid {
62905
+ :where(.theme-scope)
62906
+ :where([data-block='event-calendar'])
62907
+ .event-timetable-grid {
62578
62908
  display: grid;
62579
62909
  grid-template-columns: 4.5rem repeat(7, minmax(8rem, 1fr));
62580
62910
  min-width: 62rem;
62581
62911
  }
62582
62912
 
62583
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-time-rail,
62584
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-day {
62913
+ :where(.theme-scope)
62914
+ :where([data-block='event-calendar'])
62915
+ .event-timetable-time-rail,
62916
+ :where(.theme-scope)
62917
+ :where([data-block='event-calendar'])
62918
+ .event-timetable-day {
62585
62919
  border-right: 1px solid var(--ec-border-subtle);
62586
62920
  }
62587
62921
 
62588
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-day:last-child {
62922
+ :where(.theme-scope)
62923
+ :where([data-block='event-calendar'])
62924
+ .event-timetable-day:last-child {
62589
62925
  border-right: none;
62590
62926
  }
62591
62927
 
62592
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-day-heading {
62928
+ :where(.theme-scope)
62929
+ :where([data-block='event-calendar'])
62930
+ .event-timetable-day-heading {
62593
62931
  min-height: 3.25rem;
62594
62932
  margin: 0;
62595
62933
  padding: 0.75rem 0.5rem;
@@ -62604,12 +62942,17 @@ const containerResponsiveThemeCss = `/*
62604
62942
  font-weight: 600;
62605
62943
  }
62606
62944
 
62607
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-day--today .event-timetable-day-heading {
62945
+ :where(.theme-scope)
62946
+ :where([data-block='event-calendar'])
62947
+ .event-timetable-day--today
62948
+ .event-timetable-day-heading {
62608
62949
  background-color: var(--ec-today-bg);
62609
62950
  color: var(--ec-today-text);
62610
62951
  }
62611
62952
 
62612
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-today-badge {
62953
+ :where(.theme-scope)
62954
+ :where([data-block='event-calendar'])
62955
+ .event-timetable-today-badge {
62613
62956
  padding: 0.125rem 0.375rem;
62614
62957
  border-radius: var(--rb-button-radius);
62615
62958
  background-color: rgb(var(--tb-primary));
@@ -62619,17 +62962,29 @@ const containerResponsiveThemeCss = `/*
62619
62962
  text-transform: uppercase;
62620
62963
  }
62621
62964
 
62622
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-time-body,
62623
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-day-body {
62965
+ :where(.theme-scope)
62966
+ :where([data-block='event-calendar'])
62967
+ .event-timetable-time-body,
62968
+ :where(.theme-scope)
62969
+ :where([data-block='event-calendar'])
62970
+ .event-timetable-day-body {
62624
62971
  position: relative;
62625
- height: clamp(34rem, calc(var(--event-timetable-range-minutes, 900) * 0.055rem), 56rem);
62972
+ height: clamp(
62973
+ 34rem,
62974
+ calc(var(--event-timetable-range-minutes, 900) * 0.055rem),
62975
+ 56rem
62976
+ );
62626
62977
  }
62627
62978
 
62628
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-time-body {
62979
+ :where(.theme-scope)
62980
+ :where([data-block='event-calendar'])
62981
+ .event-timetable-time-body {
62629
62982
  background-color: var(--ec-header-bg);
62630
62983
  }
62631
62984
 
62632
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-time-label {
62985
+ :where(.theme-scope)
62986
+ :where([data-block='event-calendar'])
62987
+ .event-timetable-time-label {
62633
62988
  position: absolute;
62634
62989
  left: 0.625rem;
62635
62990
  transform: translateY(-50%);
@@ -62638,14 +62993,18 @@ const containerResponsiveThemeCss = `/*
62638
62993
  white-space: nowrap;
62639
62994
  }
62640
62995
 
62641
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-hour-line {
62996
+ :where(.theme-scope)
62997
+ :where([data-block='event-calendar'])
62998
+ .event-timetable-hour-line {
62642
62999
  position: absolute;
62643
63000
  left: 0;
62644
63001
  right: 0;
62645
63002
  border-top: 1px solid var(--ec-border-subtle);
62646
63003
  }
62647
63004
 
62648
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event {
63005
+ :where(.theme-scope)
63006
+ :where([data-block='event-calendar'])
63007
+ .event-timetable-event {
62649
63008
  position: absolute;
62650
63009
  min-height: 2.75rem;
62651
63010
  padding: 0.375rem 0.5rem;
@@ -62665,21 +63024,35 @@ const containerResponsiveThemeCss = `/*
62665
63024
  transform var(--rb-block-transition) ease;
62666
63025
  }
62667
63026
 
62668
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event:hover {
63027
+ :where(.theme-scope)
63028
+ :where([data-block='event-calendar'])
63029
+ .event-timetable-event:hover {
62669
63030
  box-shadow: 0 4px 12px rgba(var(--tb-text), 0.12);
62670
63031
  transform: translateY(-1px);
62671
63032
  }
62672
63033
 
62673
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event:focus-visible {
63034
+ :where(.theme-scope)
63035
+ :where([data-block='event-calendar'])
63036
+ .event-timetable-event:focus-visible {
62674
63037
  outline: 2px solid rgb(var(--tb-primary));
62675
63038
  outline-offset: 2px;
62676
63039
  }
62677
63040
 
62678
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event-time,
62679
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event-title,
62680
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event-teacher,
62681
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event-meta,
62682
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event-capacity {
63041
+ :where(.theme-scope)
63042
+ :where([data-block='event-calendar'])
63043
+ .event-timetable-event-time,
63044
+ :where(.theme-scope)
63045
+ :where([data-block='event-calendar'])
63046
+ .event-timetable-event-title,
63047
+ :where(.theme-scope)
63048
+ :where([data-block='event-calendar'])
63049
+ .event-timetable-event-teacher,
63050
+ :where(.theme-scope)
63051
+ :where([data-block='event-calendar'])
63052
+ .event-timetable-event-meta,
63053
+ :where(.theme-scope)
63054
+ :where([data-block='event-calendar'])
63055
+ .event-timetable-event-capacity {
62683
63056
  display: block;
62684
63057
  min-width: 0;
62685
63058
  overflow: hidden;
@@ -62687,36 +63060,50 @@ const containerResponsiveThemeCss = `/*
62687
63060
  white-space: nowrap;
62688
63061
  }
62689
63062
 
62690
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event-time {
63063
+ :where(.theme-scope)
63064
+ :where([data-block='event-calendar'])
63065
+ .event-timetable-event-time {
62691
63066
  font-size: 0.6875rem;
62692
63067
  font-weight: 700;
62693
63068
  opacity: var(--ec-time-opacity);
62694
63069
  }
62695
63070
 
62696
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event-title {
63071
+ :where(.theme-scope)
63072
+ :where([data-block='event-calendar'])
63073
+ .event-timetable-event-title {
62697
63074
  font-size: 0.8125rem;
62698
63075
  font-weight: 700;
62699
63076
  line-height: 1.25;
62700
63077
  }
62701
63078
 
62702
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event-teacher,
62703
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event-meta {
63079
+ :where(.theme-scope)
63080
+ :where([data-block='event-calendar'])
63081
+ .event-timetable-event-teacher,
63082
+ :where(.theme-scope)
63083
+ :where([data-block='event-calendar'])
63084
+ .event-timetable-event-meta {
62704
63085
  font-size: 0.6875rem;
62705
63086
  opacity: 0.72;
62706
63087
  }
62707
63088
 
62708
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event-capacity {
63089
+ :where(.theme-scope)
63090
+ :where([data-block='event-calendar'])
63091
+ .event-timetable-event-capacity {
62709
63092
  font-size: 0.6875rem;
62710
63093
  font-weight: 600;
62711
63094
  opacity: 0.85;
62712
63095
  }
62713
63096
 
62714
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event-capacity--full {
63097
+ :where(.theme-scope)
63098
+ :where([data-block='event-calendar'])
63099
+ .event-timetable-event-capacity--full {
62715
63100
  color: rgb(var(--tb-danger, 220 38 38));
62716
63101
  opacity: 1;
62717
63102
  }
62718
63103
 
62719
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-day-empty {
63104
+ :where(.theme-scope)
63105
+ :where([data-block='event-calendar'])
63106
+ .event-timetable-day-empty {
62720
63107
  margin: 0;
62721
63108
  padding: 1rem 0.5rem;
62722
63109
  text-align: center;
@@ -62724,7 +63111,9 @@ const containerResponsiveThemeCss = `/*
62724
63111
  opacity: var(--ec-empty-opacity);
62725
63112
  }
62726
63113
 
62727
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-empty {
63114
+ :where(.theme-scope)
63115
+ :where([data-block='event-calendar'])
63116
+ .event-timetable-empty {
62728
63117
  margin: 0.25rem 0 0;
62729
63118
  text-align: center;
62730
63119
  font-size: 0.875rem;
@@ -62733,32 +63122,46 @@ const containerResponsiveThemeCss = `/*
62733
63122
 
62734
63123
  @container rb-site (max-width: 767px) {
62735
63124
  @scope ([data-rb-responsive-mode="container"]) to (:scope [data-rb-responsive-mode]) {
62736
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-day-selector {
63125
+ :where(.theme-scope)
63126
+ :where([data-block='event-calendar'])
63127
+ .event-timetable-day-selector {
62737
63128
  display: flex;
62738
63129
  }
62739
63130
 
62740
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-container {
63131
+ :where(.theme-scope)
63132
+ :where([data-block='event-calendar'])
63133
+ .event-timetable-container {
62741
63134
  overflow: hidden;
62742
63135
  }
62743
63136
 
62744
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-grid {
63137
+ :where(.theme-scope)
63138
+ :where([data-block='event-calendar'])
63139
+ .event-timetable-grid {
62745
63140
  grid-template-columns: 4rem minmax(0, 1fr);
62746
63141
  min-width: 0;
62747
63142
  }
62748
63143
 
62749
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-day[data-selected="false"] {
63144
+ :where(.theme-scope)
63145
+ :where([data-block='event-calendar'])
63146
+ .event-timetable-day[data-selected='false'] {
62750
63147
  display: none;
62751
63148
  }
62752
63149
 
62753
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-day {
63150
+ :where(.theme-scope)
63151
+ :where([data-block='event-calendar'])
63152
+ .event-timetable-day {
62754
63153
  border-right: none;
62755
63154
  }
62756
63155
 
62757
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-time-rail {
63156
+ :where(.theme-scope)
63157
+ :where([data-block='event-calendar'])
63158
+ .event-timetable-time-rail {
62758
63159
  border-right: 1px solid var(--ec-border-subtle);
62759
63160
  }
62760
63161
 
62761
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-day-heading {
63162
+ :where(.theme-scope)
63163
+ :where([data-block='event-calendar'])
63164
+ .event-timetable-day-heading {
62762
63165
  justify-content: flex-start;
62763
63166
  padding-inline: 0.75rem;
62764
63167
  }
@@ -62771,7 +63174,7 @@ const containerResponsiveThemeCss = `/*
62771
63174
  * three-state availability (available / filling / waitlist), and a footer CTA.
62772
63175
  * ----------------------------------------------------------------------------- */
62773
63176
 
62774
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board {
63177
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-week-board {
62775
63178
  /* Status accent tokens — map the three availability states onto theme colours.
62776
63179
  * available -> secondary, filling -> accent, waitlist -> muted text. */
62777
63180
  --ec-status-available: rgb(var(--tb-secondary));
@@ -62788,17 +63191,20 @@ const containerResponsiveThemeCss = `/*
62788
63191
 
62789
63192
  /* Opt-in raised look: a soft drop shadow so the board lifts off the page.
62790
63193
  * Generic default (no [data-elevated]) stays flat. */
62791
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board[data-elevated] {
63194
+ :where(.theme-scope)
63195
+ :where([data-block='event-calendar'])
63196
+ .event-week-board[data-elevated] {
62792
63197
  box-shadow: 0 14px 34px -24px rgba(var(--tb-text), 0.35);
62793
63198
  }
62794
63199
 
62795
- /* Top bar: title + legend */
62796
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-top {
62797
- display: flex;
63200
+ /* Top bar: authored title + week navigation + legend */
63201
+ :where(.theme-scope)
63202
+ :where([data-block='event-calendar'])
63203
+ .event-week-board-top {
63204
+ display: grid;
63205
+ grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
62798
63206
  align-items: center;
62799
- justify-content: space-between;
62800
63207
  gap: 1rem;
62801
- flex-wrap: wrap;
62802
63208
  padding: 1.1rem 1.5rem;
62803
63209
  /* surfaceAlt gives the header/footer a legible tint against the white day-grid
62804
63210
  * body — the faint \`--ec-header-bg\` (5% text) is invisible on light palettes. */
@@ -62806,7 +63212,10 @@ const containerResponsiveThemeCss = `/*
62806
63212
  border-bottom: 1px solid var(--ec-border-subtle);
62807
63213
  }
62808
63214
 
62809
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-title {
63215
+ :where(.theme-scope)
63216
+ :where([data-block='event-calendar'])
63217
+ .event-week-board-title {
63218
+ grid-column: 1;
62810
63219
  font-size: 0.8125rem;
62811
63220
  font-weight: 600;
62812
63221
  letter-spacing: 0.12em;
@@ -62814,7 +63223,67 @@ const containerResponsiveThemeCss = `/*
62814
63223
  color: rgb(var(--tb-primary));
62815
63224
  }
62816
63225
 
62817
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-legend {
63226
+ :where(.theme-scope)
63227
+ :where([data-block='event-calendar'])
63228
+ .event-week-board-navigation {
63229
+ grid-column: 2;
63230
+ display: flex;
63231
+ align-items: center;
63232
+ justify-content: center;
63233
+ gap: 0.65rem;
63234
+ }
63235
+
63236
+ :where(.theme-scope)
63237
+ :where([data-block='event-calendar'])
63238
+ .event-week-board-nav-button {
63239
+ display: inline-flex;
63240
+ align-items: center;
63241
+ justify-content: center;
63242
+ width: 2.25rem;
63243
+ height: 2.25rem;
63244
+ padding: 0;
63245
+ border: 1px solid var(--ec-border);
63246
+ border-radius: 999px;
63247
+ background: transparent;
63248
+ color: inherit;
63249
+ cursor: pointer;
63250
+ }
63251
+
63252
+ :where(.theme-scope)
63253
+ :where([data-block='event-calendar'])
63254
+ .event-week-board-nav-button:hover {
63255
+ background-color: var(--ec-hover-bg);
63256
+ }
63257
+
63258
+ :where(.theme-scope)
63259
+ :where([data-block='event-calendar'])
63260
+ .event-week-board-nav-button:focus-visible {
63261
+ outline: 2px solid rgb(var(--tb-primary));
63262
+ outline-offset: 2px;
63263
+ }
63264
+
63265
+ :where(.theme-scope)
63266
+ :where([data-block='event-calendar'])
63267
+ .event-week-board-range {
63268
+ min-width: 12rem;
63269
+ margin: 0;
63270
+ text-align: center;
63271
+ font-size: 0.875rem;
63272
+ font-weight: 600;
63273
+ }
63274
+
63275
+ :where(.theme-scope)
63276
+ :where([data-block='event-calendar'])
63277
+ .event-week-board-loading {
63278
+ font-weight: 400;
63279
+ opacity: 0.65;
63280
+ }
63281
+
63282
+ :where(.theme-scope)
63283
+ :where([data-block='event-calendar'])
63284
+ .event-week-board-legend {
63285
+ grid-column: 3;
63286
+ justify-self: end;
62818
63287
  display: flex;
62819
63288
  align-items: center;
62820
63289
  gap: 1.1rem;
@@ -62824,38 +63293,72 @@ const containerResponsiveThemeCss = `/*
62824
63293
  opacity: 0.75;
62825
63294
  }
62826
63295
 
62827
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-legend-item {
63296
+ :where(.theme-scope)
63297
+ :where([data-block='event-calendar'])
63298
+ .event-week-board-error {
63299
+ display: flex;
63300
+ align-items: center;
63301
+ justify-content: center;
63302
+ gap: 0.75rem;
63303
+ padding: 0.75rem 1.5rem;
63304
+ border-bottom: 1px solid var(--ec-border-subtle);
63305
+ color: rgb(var(--tb-error, var(--tb-text)));
63306
+ }
63307
+
63308
+ :where(.theme-scope)
63309
+ :where([data-block='event-calendar'])
63310
+ .event-week-board-error
63311
+ p {
63312
+ margin: 0;
63313
+ font-size: 0.8125rem;
63314
+ }
63315
+
63316
+ :where(.theme-scope)
63317
+ :where([data-block='event-calendar'])
63318
+ .event-week-board-legend-item {
62828
63319
  display: inline-flex;
62829
63320
  align-items: center;
62830
63321
  gap: 0.4rem;
62831
63322
  }
62832
63323
 
62833
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-legend-dot {
63324
+ :where(.theme-scope)
63325
+ :where([data-block='event-calendar'])
63326
+ .event-week-board-legend-dot {
62834
63327
  width: 0.55rem;
62835
63328
  height: 0.55rem;
62836
63329
  border-radius: 50%;
62837
63330
  display: inline-block;
62838
63331
  }
62839
63332
 
62840
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-legend-dot[data-status="available"] {
63333
+ :where(.theme-scope)
63334
+ :where([data-block='event-calendar'])
63335
+ .event-week-board-legend-dot[data-status='available'] {
62841
63336
  background-color: var(--ec-status-available);
62842
63337
  }
62843
63338
 
62844
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-legend-dot[data-status="filling"] {
63339
+ :where(.theme-scope)
63340
+ :where([data-block='event-calendar'])
63341
+ .event-week-board-legend-dot[data-status='filling'] {
62845
63342
  background-color: var(--ec-status-filling);
62846
63343
  }
62847
63344
 
62848
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-legend-dot[data-status="waitlist"] {
63345
+ :where(.theme-scope)
63346
+ :where([data-block='event-calendar'])
63347
+ .event-week-board-legend-dot[data-status='waitlist'] {
62849
63348
  background-color: var(--ec-status-waitlist);
62850
63349
  }
62851
63350
 
62852
63351
  /* Day columns grid */
62853
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-grid {
63352
+ :where(.theme-scope)
63353
+ :where([data-block='event-calendar'])
63354
+ .event-week-board-grid {
62854
63355
  display: grid;
62855
63356
  grid-template-columns: repeat(var(--event-week-board-cols), minmax(0, 1fr));
62856
63357
  }
62857
63358
 
62858
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-day {
63359
+ :where(.theme-scope)
63360
+ :where([data-block='event-calendar'])
63361
+ .event-week-board-day {
62859
63362
  display: flex;
62860
63363
  flex-direction: column;
62861
63364
  min-height: 15rem;
@@ -62865,11 +63368,15 @@ const containerResponsiveThemeCss = `/*
62865
63368
  border-right: var(--rb-border-width, 1px) solid rgb(var(--tb-border));
62866
63369
  }
62867
63370
 
62868
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-day:last-child {
63371
+ :where(.theme-scope)
63372
+ :where([data-block='event-calendar'])
63373
+ .event-week-board-day:last-child {
62869
63374
  border-right: none;
62870
63375
  }
62871
63376
 
62872
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-day-head {
63377
+ :where(.theme-scope)
63378
+ :where([data-block='event-calendar'])
63379
+ .event-week-board-day-head {
62873
63380
  display: flex;
62874
63381
  align-items: baseline;
62875
63382
  gap: 0.4rem;
@@ -62878,11 +63385,16 @@ const containerResponsiveThemeCss = `/*
62878
63385
  border-bottom: var(--rb-border-width, 1px) solid rgb(var(--tb-border));
62879
63386
  }
62880
63387
 
62881
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-day--today .event-week-board-day-head {
63388
+ :where(.theme-scope)
63389
+ :where([data-block='event-calendar'])
63390
+ .event-week-board-day--today
63391
+ .event-week-board-day-head {
62882
63392
  background-color: var(--ec-today-bg);
62883
63393
  }
62884
63394
 
62885
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-day-abbr {
63395
+ :where(.theme-scope)
63396
+ :where([data-block='event-calendar'])
63397
+ .event-week-board-day-abbr {
62886
63398
  font-size: 0.6875rem;
62887
63399
  font-weight: 600;
62888
63400
  letter-spacing: 0.1em;
@@ -62890,18 +63402,25 @@ const containerResponsiveThemeCss = `/*
62890
63402
  opacity: 0.65;
62891
63403
  }
62892
63404
 
62893
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-day--today .event-week-board-day-abbr {
63405
+ :where(.theme-scope)
63406
+ :where([data-block='event-calendar'])
63407
+ .event-week-board-day--today
63408
+ .event-week-board-day-abbr {
62894
63409
  opacity: 1;
62895
63410
  color: var(--ec-today-text);
62896
63411
  }
62897
63412
 
62898
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-day-num {
63413
+ :where(.theme-scope)
63414
+ :where([data-block='event-calendar'])
63415
+ .event-week-board-day-num {
62899
63416
  font-size: 0.8125rem;
62900
63417
  font-weight: 600;
62901
63418
  opacity: 0.5;
62902
63419
  }
62903
63420
 
62904
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-day-body {
63421
+ :where(.theme-scope)
63422
+ :where([data-block='event-calendar'])
63423
+ .event-week-board-day-body {
62905
63424
  display: flex;
62906
63425
  flex-direction: column;
62907
63426
  gap: 0.65rem;
@@ -62910,7 +63429,9 @@ const containerResponsiveThemeCss = `/*
62910
63429
  }
62911
63430
 
62912
63431
  /* Class card */
62913
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-card {
63432
+ :where(.theme-scope)
63433
+ :where([data-block='event-calendar'])
63434
+ .event-week-board-card {
62914
63435
  display: flex;
62915
63436
  flex-direction: column;
62916
63437
  gap: 0.45rem;
@@ -62930,40 +63451,54 @@ const containerResponsiveThemeCss = `/*
62930
63451
  border-color var(--rb-block-transition) ease;
62931
63452
  }
62932
63453
 
62933
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-card[data-status="filling"] {
63454
+ :where(.theme-scope)
63455
+ :where([data-block='event-calendar'])
63456
+ .event-week-board-card[data-status='filling'] {
62934
63457
  border-left-color: var(--ec-status-filling);
62935
63458
  }
62936
63459
 
62937
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-card[data-status="waitlist"] {
63460
+ :where(.theme-scope)
63461
+ :where([data-block='event-calendar'])
63462
+ .event-week-board-card[data-status='waitlist'] {
62938
63463
  border-left-color: var(--ec-status-waitlist);
62939
63464
  }
62940
63465
 
62941
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-card:hover {
63466
+ :where(.theme-scope)
63467
+ :where([data-block='event-calendar'])
63468
+ .event-week-board-card:hover {
62942
63469
  transform: translateY(-2px);
62943
63470
  box-shadow: 0 6px 16px -8px rgba(var(--tb-text), 0.28);
62944
63471
  border-color: rgba(var(--tb-primary), 0.4);
62945
63472
  }
62946
63473
 
62947
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-card:focus-visible {
63474
+ :where(.theme-scope)
63475
+ :where([data-block='event-calendar'])
63476
+ .event-week-board-card:focus-visible {
62948
63477
  outline: 2px solid rgb(var(--tb-primary));
62949
63478
  outline-offset: 2px;
62950
63479
  }
62951
63480
 
62952
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-card-title {
63481
+ :where(.theme-scope)
63482
+ :where([data-block='event-calendar'])
63483
+ .event-week-board-card-title {
62953
63484
  font-family: var(--font-heading, inherit);
62954
63485
  font-size: 0.9375rem;
62955
63486
  font-weight: 600;
62956
63487
  line-height: 1.2;
62957
63488
  }
62958
63489
 
62959
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-card-time {
63490
+ :where(.theme-scope)
63491
+ :where([data-block='event-calendar'])
63492
+ .event-week-board-card-time {
62960
63493
  font-size: 0.75rem;
62961
63494
  letter-spacing: 0.01em;
62962
63495
  opacity: 0.7;
62963
63496
  }
62964
63497
 
62965
63498
  /* Capacity pill */
62966
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-card-pill {
63499
+ :where(.theme-scope)
63500
+ :where([data-block='event-calendar'])
63501
+ .event-week-board-card-pill {
62967
63502
  align-self: flex-start;
62968
63503
  display: inline-flex;
62969
63504
  align-items: center;
@@ -62981,20 +63516,26 @@ const containerResponsiveThemeCss = `/*
62981
63516
  border-color: var(--ec-border);
62982
63517
  }
62983
63518
 
62984
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-card-pill[data-status="filling"] {
63519
+ :where(.theme-scope)
63520
+ :where([data-block='event-calendar'])
63521
+ .event-week-board-card-pill[data-status='filling'] {
62985
63522
  background-color: rgba(var(--tb-accent), 0.14);
62986
63523
  color: var(--ec-status-filling);
62987
63524
  border-color: rgba(var(--tb-accent), 0.32);
62988
63525
  }
62989
63526
 
62990
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-card-pill[data-status="waitlist"] {
63527
+ :where(.theme-scope)
63528
+ :where([data-block='event-calendar'])
63529
+ .event-week-board-card-pill[data-status='waitlist'] {
62991
63530
  background-color: transparent;
62992
63531
  color: rgba(var(--tb-text), 0.6);
62993
63532
  border-color: var(--ec-border);
62994
63533
  }
62995
63534
 
62996
63535
  /* Footer */
62997
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-foot {
63536
+ :where(.theme-scope)
63537
+ :where([data-block='event-calendar'])
63538
+ .event-week-board-foot {
62998
63539
  display: flex;
62999
63540
  align-items: center;
63000
63541
  justify-content: space-between;
@@ -63006,7 +63547,9 @@ const containerResponsiveThemeCss = `/*
63006
63547
  border-top: 1px solid var(--ec-border-subtle);
63007
63548
  }
63008
63549
 
63009
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-foot-note {
63550
+ :where(.theme-scope)
63551
+ :where([data-block='event-calendar'])
63552
+ .event-week-board-foot-note {
63010
63553
  margin: 0;
63011
63554
  font-size: 0.875rem;
63012
63555
  opacity: 0.75;
@@ -63015,36 +63558,69 @@ const containerResponsiveThemeCss = `/*
63015
63558
  /* Responsive: collapse day columns to a stacked list on narrow viewports */
63016
63559
  @container rb-site (max-width: 1023px) {
63017
63560
  @scope ([data-rb-responsive-mode="container"]) to (:scope [data-rb-responsive-mode]) {
63018
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-grid {
63561
+ :where(.theme-scope)
63562
+ :where([data-block='event-calendar'])
63563
+ .event-week-board-top {
63564
+ grid-template-columns: 1fr;
63565
+ }
63566
+
63567
+ :where(.theme-scope)
63568
+ :where([data-block='event-calendar'])
63569
+ .event-week-board-title,
63570
+ :where(.theme-scope)
63571
+ :where([data-block='event-calendar'])
63572
+ .event-week-board-navigation,
63573
+ :where(.theme-scope)
63574
+ :where([data-block='event-calendar'])
63575
+ .event-week-board-legend {
63576
+ grid-column: 1;
63577
+ justify-self: center;
63578
+ }
63579
+
63580
+ :where(.theme-scope)
63581
+ :where([data-block='event-calendar'])
63582
+ .event-week-board-grid {
63019
63583
  grid-template-columns: 1fr;
63020
63584
  }
63021
63585
 
63022
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-day {
63586
+ :where(.theme-scope)
63587
+ :where([data-block='event-calendar'])
63588
+ .event-week-board-day {
63023
63589
  min-height: 0;
63024
63590
  border-right: none;
63025
63591
  border-bottom: var(--rb-border-width, 1px) solid rgb(var(--tb-border));
63026
63592
  }
63027
63593
 
63028
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-day:last-child {
63594
+ :where(.theme-scope)
63595
+ :where([data-block='event-calendar'])
63596
+ .event-week-board-day:last-child {
63029
63597
  border-bottom: none;
63030
63598
  }
63031
63599
 
63032
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-day--empty {
63600
+ :where(.theme-scope)
63601
+ :where([data-block='event-calendar'])
63602
+ .event-week-board-day--empty {
63033
63603
  display: none;
63034
63604
  }
63035
63605
 
63036
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-day-head {
63606
+ :where(.theme-scope)
63607
+ :where([data-block='event-calendar'])
63608
+ .event-week-board-day-head {
63037
63609
  border-bottom: none;
63038
63610
  padding-bottom: 0.25rem;
63039
63611
  }
63040
63612
 
63041
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-day-body {
63613
+ :where(.theme-scope)
63614
+ :where([data-block='event-calendar'])
63615
+ .event-week-board-day-body {
63042
63616
  flex-direction: row;
63043
63617
  flex-wrap: wrap;
63044
63618
  padding-top: 0.35rem;
63045
63619
  }
63046
63620
 
63047
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-card {
63621
+ :where(.theme-scope)
63622
+ :where([data-block='event-calendar'])
63623
+ .event-week-board-card {
63048
63624
  flex: 1 1 14rem;
63049
63625
  }
63050
63626
  }
@@ -63052,11 +63628,37 @@ const containerResponsiveThemeCss = `/*
63052
63628
 
63053
63629
  @container rb-site (max-width: 639px) {
63054
63630
  @scope ([data-rb-responsive-mode="container"]) to (:scope [data-rb-responsive-mode]) {
63055
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-legend {
63631
+ :where(.theme-scope)
63632
+ :where([data-block='event-calendar'])
63633
+ .event-week-board-navigation {
63634
+ display: grid;
63635
+ grid-template-columns: 2.25rem minmax(0, 1fr) 2.25rem;
63636
+ width: 100%;
63637
+ }
63638
+
63639
+ :where(.theme-scope)
63640
+ :where([data-block='event-calendar'])
63641
+ .event-week-board-navigation
63642
+ > :last-child {
63643
+ grid-column: 1 / -1;
63644
+ justify-self: center;
63645
+ }
63646
+
63647
+ :where(.theme-scope)
63648
+ :where([data-block='event-calendar'])
63649
+ .event-week-board-range {
63650
+ min-width: 0;
63651
+ }
63652
+
63653
+ :where(.theme-scope)
63654
+ :where([data-block='event-calendar'])
63655
+ .event-week-board-legend {
63056
63656
  display: none;
63057
63657
  }
63058
63658
 
63059
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-card {
63659
+ :where(.theme-scope)
63660
+ :where([data-block='event-calendar'])
63661
+ .event-week-board-card {
63060
63662
  flex: 1 1 100%;
63061
63663
  }
63062
63664
  }
@@ -63073,8 +63675,9 @@ const containerResponsiveThemeCss = `/*
63073
63675
  * Opt-in only: the band paints when the board root carries [data-banded];
63074
63676
  * the generic default is bandless.
63075
63677
  * ----------------------------------------------------------------------------- */
63076
- :where(.theme-scope) [data-slot="section"]:has(.event-calendar--week-board[data-banded])::before {
63077
- content: "";
63678
+ :where(.theme-scope)
63679
+ [data-slot='section']:has(.event-calendar--week-board[data-banded])::before {
63680
+ content: '';
63078
63681
  position: absolute;
63079
63682
  inset: 0;
63080
63683
  z-index: -9;
@@ -63128,7 +63731,7 @@ const containerResponsiveThemeCss = `/*
63128
63731
  * ----------------------------------------------------------------------------- */
63129
63732
 
63130
63733
  /* Modal overlay */
63131
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal-overlay {
63734
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal-overlay {
63132
63735
  position: fixed;
63133
63736
  inset: 0;
63134
63737
  background: var(--ec-modal-overlay-bg);
@@ -63142,12 +63745,16 @@ const containerResponsiveThemeCss = `/*
63142
63745
  }
63143
63746
 
63144
63747
  @keyframes ec-modal-fade-in {
63145
- from { opacity: 0; }
63146
- to { opacity: 1; }
63748
+ from {
63749
+ opacity: 0;
63750
+ }
63751
+ to {
63752
+ opacity: 1;
63753
+ }
63147
63754
  }
63148
63755
 
63149
63756
  /* Modal dialog */
63150
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal {
63757
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal {
63151
63758
  position: relative;
63152
63759
  background: var(--ec-modal-bg);
63153
63760
  border-radius: var(--rb-block-radius);
@@ -63171,17 +63778,17 @@ const containerResponsiveThemeCss = `/*
63171
63778
  }
63172
63779
 
63173
63780
  /* Event modal - constrained width for card */
63174
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal--event {
63781
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal--event {
63175
63782
  max-width: 26rem;
63176
63783
  }
63177
63784
 
63178
63785
  /* Day modal */
63179
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal--day {
63786
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal--day {
63180
63787
  max-width: 28rem;
63181
63788
  }
63182
63789
 
63183
63790
  /* Close button */
63184
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal-close {
63791
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal-close {
63185
63792
  position: absolute;
63186
63793
  top: 0.75rem;
63187
63794
  right: 0.75rem;
@@ -63202,31 +63809,35 @@ const containerResponsiveThemeCss = `/*
63202
63809
  z-index: 10;
63203
63810
  }
63204
63811
 
63205
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal-close:hover {
63812
+ :where(.theme-scope)
63813
+ :where([data-block='event-calendar'])
63814
+ .ec-modal-close:hover {
63206
63815
  opacity: 1;
63207
63816
  background-color: rgba(var(--tb-text), 0.1);
63208
63817
  }
63209
63818
 
63210
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal-close:focus-visible {
63819
+ :where(.theme-scope)
63820
+ :where([data-block='event-calendar'])
63821
+ .ec-modal-close:focus-visible {
63211
63822
  outline: 2px solid rgb(var(--tb-primary));
63212
63823
  outline-offset: 2px;
63213
63824
  }
63214
63825
 
63215
63826
  /* Modal header (for day modal) */
63216
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal-header {
63827
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal-header {
63217
63828
  padding: 1.5rem 1.5rem 1rem;
63218
63829
  padding-right: 3rem; /* Space for close button */
63219
63830
  border-bottom: 1px solid var(--ec-border);
63220
63831
  }
63221
63832
 
63222
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal-title {
63833
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal-title {
63223
63834
  font-size: 1.125rem;
63224
63835
  font-weight: 600;
63225
63836
  color: var(--ec-text);
63226
63837
  margin: 0;
63227
63838
  }
63228
63839
 
63229
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal-subtitle {
63840
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal-subtitle {
63230
63841
  font-size: 0.875rem;
63231
63842
  color: var(--ec-text);
63232
63843
  opacity: 0.7;
@@ -63234,17 +63845,20 @@ const containerResponsiveThemeCss = `/*
63234
63845
  }
63235
63846
 
63236
63847
  /* Modal content */
63237
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal-content {
63848
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal-content {
63238
63849
  padding: 1rem;
63239
63850
  }
63240
63851
 
63241
63852
  /* Event modal: tighter padding for card */
63242
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal--event .ec-modal-content {
63853
+ :where(.theme-scope)
63854
+ :where([data-block='event-calendar'])
63855
+ .ec-modal--event
63856
+ .ec-modal-content {
63243
63857
  padding: 0.5rem;
63244
63858
  }
63245
63859
 
63246
63860
  /* Day events list */
63247
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-day-events-list {
63861
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-day-events-list {
63248
63862
  display: flex;
63249
63863
  flex-direction: column;
63250
63864
  gap: 0.5rem;
@@ -63252,7 +63866,9 @@ const containerResponsiveThemeCss = `/*
63252
63866
  }
63253
63867
 
63254
63868
  /* AgendaEventCard in button mode inherits most styles, just needs cursor */
63255
- :where(.theme-scope) :where([data-block="event-calendar"]) button.event-agenda-card {
63869
+ :where(.theme-scope)
63870
+ :where([data-block='event-calendar'])
63871
+ button.event-agenda-card {
63256
63872
  cursor: pointer;
63257
63873
  text-align: left;
63258
63874
  font-family: inherit;
@@ -63261,7 +63877,9 @@ const containerResponsiveThemeCss = `/*
63261
63877
  /* Responsive adjustments */
63262
63878
  @container rb-site (max-width: 640px) {
63263
63879
  @scope ([data-rb-responsive-mode="container"]) to (:scope [data-rb-responsive-mode]) {
63264
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-container {
63880
+ :where(.theme-scope)
63881
+ :where([data-block='event-calendar'])
63882
+ .event-calendar-container {
63265
63883
  margin-left: -1.5rem;
63266
63884
  margin-right: -1.5rem;
63267
63885
  border-left: none;
@@ -63269,28 +63887,38 @@ const containerResponsiveThemeCss = `/*
63269
63887
  border-radius: 0;
63270
63888
  }
63271
63889
 
63272
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-day-header {
63890
+ :where(.theme-scope)
63891
+ :where([data-block='event-calendar'])
63892
+ .event-calendar-day-header {
63273
63893
  font-size: 0.75rem;
63274
63894
  padding: 0.375rem 0.125rem;
63275
63895
  }
63276
63896
 
63277
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-day {
63897
+ :where(.theme-scope)
63898
+ :where([data-block='event-calendar'])
63899
+ .event-calendar-day {
63278
63900
  min-height: 88px;
63279
63901
  padding: 0.125rem;
63280
63902
  }
63281
63903
 
63282
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-title {
63904
+ :where(.theme-scope)
63905
+ :where([data-block='event-calendar'])
63906
+ .event-calendar-title {
63283
63907
  font-size: 0.9375rem;
63284
63908
  min-width: 0;
63285
63909
  }
63286
63910
 
63287
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-day-number {
63911
+ :where(.theme-scope)
63912
+ :where([data-block='event-calendar'])
63913
+ .event-calendar-day-number {
63288
63914
  font-size: 0.75rem;
63289
63915
  margin-bottom: 0.125rem;
63290
63916
  padding: 0 0.125rem;
63291
63917
  }
63292
63918
 
63293
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-event {
63919
+ :where(.theme-scope)
63920
+ :where([data-block='event-calendar'])
63921
+ .event-calendar-event {
63294
63922
  justify-content: center;
63295
63923
  gap: 0.25rem;
63296
63924
  padding: 0.1875rem 0.25rem;
@@ -63298,25 +63926,34 @@ const containerResponsiveThemeCss = `/*
63298
63926
  border-radius: calc(var(--rb-block-radius) / 3);
63299
63927
  }
63300
63928
 
63301
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-event-time {
63929
+ :where(.theme-scope)
63930
+ :where([data-block='event-calendar'])
63931
+ .event-calendar-event-time {
63302
63932
  text-align: center;
63303
63933
  font-size: 0.625rem;
63304
63934
  }
63305
63935
 
63306
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-event-title {
63936
+ :where(.theme-scope)
63937
+ :where([data-block='event-calendar'])
63938
+ .event-calendar-event-title {
63307
63939
  display: none;
63308
63940
  }
63309
63941
 
63310
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-more {
63942
+ :where(.theme-scope)
63943
+ :where([data-block='event-calendar'])
63944
+ .event-calendar-more {
63311
63945
  padding: 0.125rem 0.25rem;
63312
63946
  font-size: 0.6875rem;
63313
63947
  }
63314
63948
 
63315
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-header > button {
63949
+ :where(.theme-scope)
63950
+ :where([data-block='event-calendar'])
63951
+ .event-calendar-header
63952
+ > button {
63316
63953
  margin-right: 0.25rem;
63317
63954
  }
63318
63955
 
63319
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal {
63956
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal {
63320
63957
  max-width: 100%;
63321
63958
  max-height: 85vh;
63322
63959
  margin: 0 0.5rem;
@@ -68086,16 +68723,21 @@ function toBlocksPageRendererDataContext(dataContext) {
68086
68723
  imageResolveContext: toBlocksImageResolveContextInput(dataContext.imageResolveContext)
68087
68724
  };
68088
68725
  }
68089
- function PageRenderer(props) {
68090
- const blocksSdkConfig = props.sdkConfig ? { customBlocks: normalizeSdkCustomBlocks(props.sdkConfig.customBlocks) } : props.sdkConfig;
68091
- const { rendering: _rendering, theme: _theme, themeTokens: _themeTokens, ...commonProps } = props;
68092
- const commonBlocksProps = {
68093
- ...commonProps,
68726
+ function toBlocksCommonProps(props) {
68727
+ return {
68728
+ page: props.page,
68729
+ runtimeBoundaries: props.runtimeBoundaries,
68094
68730
  dataContext: props.dataContext ? toBlocksPageRendererDataContext(props.dataContext) : void 0,
68731
+ routeMap: props.routeMap,
68732
+ wrapBlock: props.wrapBlock,
68733
+ registry: props.registry,
68095
68734
  blockOverrides: toBlocksBlockOverrides(props.blockOverrides),
68096
- sdkConfig: blocksSdkConfig,
68735
+ sdkConfig: props.sdkConfig ? { customBlocks: normalizeSdkCustomBlocks(props.sdkConfig.customBlocks) } : props.sdkConfig,
68097
68736
  customBlocks: normalizeSdkCustomBlocks(props.customBlocks)
68098
68737
  };
68738
+ }
68739
+ function PageRenderer(props) {
68740
+ const commonBlocksProps = toBlocksCommonProps(props);
68099
68741
  const blocksProps = isOverrideOnlyPageRenderer(props) ? {
68100
68742
  ...commonBlocksProps,
68101
68743
  rendering: { kind: "overrides-only" },
@@ -68171,12 +68813,14 @@ function resolvePageThemeTokens(props) {
68171
68813
  }
68172
68814
  } : baseTokens;
68173
68815
  }
68816
+ function resolveSdkBookingTimeZone(timeZone) {
68817
+ return timeZone ?? "UTC";
68818
+ }
68174
68819
  function PageContent(props) {
68175
- const { page, runtimeBoundaries, siteId, resolvedData, bookingOfferingPresets, routeMap, pagesByIdentifier, entriesByIdentifier, wrapBlock, registry, usePlaceholders = false, blockOverrides, sdkConfig, customBlocks, supabaseUrl, mediaAssets, apiBaseUrl, portalToken, previewToken, dataContext } = props;
68820
+ const { page, runtimeBoundaries, siteId, resolvedData, bookingOfferingPresets, bookingTimeZone, routeMap, pagesByIdentifier, entriesByIdentifier, wrapBlock, registry, blockOverrides, sdkConfig, customBlocks, supabaseUrl, mediaAssets, apiBaseUrl, portalToken, previewToken, dataContext } = props;
68176
68821
  const rendererCommonProps = {
68177
68822
  page,
68178
68823
  runtimeBoundaries,
68179
- usePlaceholders,
68180
68824
  dataContext: {
68181
68825
  siteId,
68182
68826
  apiBaseUrl,
@@ -68184,6 +68828,7 @@ function PageContent(props) {
68184
68828
  previewToken,
68185
68829
  resolvedData,
68186
68830
  bookingOfferingPresets: bookingOfferingPresets ?? [],
68831
+ bookingTimeZone: resolveSdkBookingTimeZone(bookingTimeZone),
68187
68832
  routes: routeMap,
68188
68833
  pagesByIdentifier,
68189
68834
  entriesByIdentifier,
@@ -68723,233 +69368,6 @@ function requireSdkTheme(theme, siteId, reason = "cms_theme_absent") {
68723
69368
  //#region src/rendering/renderingMode.ts
68724
69369
  const defaultOverrideOnlyRuntime = { kind: "responsive-only" };
68725
69370
  //#endregion
68726
- //#region src/rendering/components/Layout.tsx
68727
- /**
68728
- * Layout component with header and footer
68729
- *
68730
- * Renders site header and footer around content. Fetches site data if not provided.
68731
- */
68732
- function isOverrideOnlyLayout(props) {
68733
- return props.rendering?.kind === "overrides-only";
68734
- }
68735
- var UnsupportedOverrideOnlyLayoutChromeError = class extends Error {
68736
- constructor(surface) {
68737
- super(`Override-only Layout requires a custom or disabled ${surface}; SDK default chrome is unavailable.`);
68738
- this.surface = surface;
68739
- this.code = "unsupported_override_only_layout_chrome";
68740
- this.name = "UnsupportedOverrideOnlyLayoutChromeError";
68741
- }
68742
- };
68743
- async function resolveLayoutSiteData(props) {
68744
- if (props.siteData) return props.siteData;
68745
- if (!props.client) throw new Error("Layout: must provide either siteData or client");
68746
- if (!props.siteId && !props.slug && !props.domain) throw new Error("Layout: must provide siteId, slug, or domain when using client");
68747
- return props.client.getSite({
68748
- id: props.siteId,
68749
- slug: props.slug,
68750
- domain: props.domain
68751
- });
68752
- }
68753
- function renderOverrideOnlyLayout(props, data) {
68754
- if (data.header === true) throw new UnsupportedOverrideOnlyLayoutChromeError("header");
68755
- if (data.footer === true) throw new UnsupportedOverrideOnlyLayoutChromeError("footer");
68756
- return renderWithOverrideOnlyRuntime({
68757
- runtime: props.rendering.runtime ?? defaultOverrideOnlyRuntime,
68758
- children: /* @__PURE__ */ jsxs(Fragment, { children: [
68759
- typeof props.header === "function" ? props.header(data.headerData) : null,
68760
- props.children,
68761
- typeof props.footer === "function" ? props.footer(data.footerData) : null
68762
- ] })
68763
- });
68764
- }
68765
- /**
68766
- * Layout component that wraps content with site header and footer.
68767
- *
68768
- * This is a server/RSC-safe component. The default `@riverbankcms/sdk/rendering`
68769
- * `Page` and `Block` surfaces mount CMS island hydration automatically, while
68770
- * the strict `@riverbankcms/sdk/rendering/server` surface stays bootstrap-free.
68771
- * If a custom host renders hydratable CMS islands through the strict server
68772
- * surface, mount `BlocksIslandsHydrator` from
68773
- * `@riverbankcms/sdk/rendering/islands` explicitly.
68774
- *
68775
- * @example With pre-fetched site data (recommended)
68776
- * ```tsx
68777
- * import { Layout } from '@riverbankcms/sdk/rendering/server';
68778
- * import { Page } from '@riverbankcms/sdk/rendering';
68779
- *
68780
- * const site = await client.getSite({ slug: 'my-site' });
68781
- *
68782
- * <Layout siteData={site}>
68783
- * <Page {...pageData} />
68784
- * </Layout>
68785
- * ```
68786
- *
68787
- * @example With strict server rendering
68788
- * ```tsx
68789
- * import { Layout, Page } from '@riverbankcms/sdk/rendering/server';
68790
- * import { BlocksIslandsHydrator } from '@riverbankcms/sdk/rendering/islands';
68791
- *
68792
- * const site = await client.getSite({ slug: 'my-site' });
68793
- *
68794
- * <Layout siteData={site}>
68795
- * <BlocksIslandsHydrator siteId={site.site.id} supabaseUrl={site.supabaseUrl} />
68796
- * <Page {...pageData} />
68797
- * </Layout>
68798
- * ```
68799
- */
68800
- async function Layout(props) {
68801
- const { children, hasPortalSession = false, previewStage = "published" } = props;
68802
- const header = props.header ?? true;
68803
- const footer = props.footer ?? true;
68804
- const siteData = await resolveLayoutSiteData(props);
68805
- const { site, navigation, layout, routes } = siteData;
68806
- const footerBlocks = siteData.footerBlocks ?? [];
68807
- const navigationOptions = {
68808
- hasPortalSession,
68809
- previewStage,
68810
- pagesByIdentifier: siteData.pagesByIdentifier,
68811
- entriesByIdentifier: siteData.entriesByIdentifier,
68812
- portalEnabled: siteData.portalEnabled ?? false,
68813
- commerceEnabled: siteData.commerceEnabled ?? false,
68814
- checkoutHref: "/checkout"
68815
- };
68816
- const menuViewModel = buildMenu(navigation, routes, navigationOptions);
68817
- const footerMenuViewModel = buildFooterMenu(navigation, routes, navigationOptions);
68818
- const legalFooterMenuViewModel = buildFooterMenuForRole(navigation, routes, "legal-policy", navigationOptions);
68819
- const logoViewModel = buildLogo(layout.logo ?? null, site.title);
68820
- const customHeaderData = {
68821
- menu: menuViewModel,
68822
- logo: logoViewModel,
68823
- site,
68824
- routes
68825
- };
68826
- const customFooterData = {
68827
- menu: menuViewModel,
68828
- footerMenu: footerMenuViewModel,
68829
- legalFooterMenu: legalFooterMenuViewModel,
68830
- logo: logoViewModel,
68831
- site,
68832
- routes
68833
- };
68834
- if (isOverrideOnlyLayout(props)) return renderOverrideOnlyLayout(props, {
68835
- header: props.header ?? true,
68836
- footer: props.footer ?? true,
68837
- headerData: customHeaderData,
68838
- footerData: customFooterData
68839
- });
68840
- const theme = requireSdkTheme(siteData.theme, site.id);
68841
- const builtThemeRuntime = buildThemeRuntime(theme);
68842
- const headerVariant = props.headerVariant;
68843
- const themeRuntime = props.themeRuntime;
68844
- const headerData = {
68845
- ...customHeaderData,
68846
- theme
68847
- };
68848
- const footerData = {
68849
- ...customFooterData,
68850
- theme
68851
- };
68852
- const headerContent = headerVariant ? {
68853
- ...layout.header,
68854
- variant: headerVariant
68855
- } : layout.header;
68856
- const themeWithVariant = headerVariant ? {
68857
- ...theme,
68858
- header: {
68859
- ...theme.header,
68860
- variant: headerVariant
68861
- }
68862
- } : theme;
68863
- const blocksThemeWithVariant = themeWithVariant;
68864
- const blocksTheme = theme;
68865
- let apiBaseUrl;
68866
- try {
68867
- apiBaseUrl = getRiverbankEnv().baseUrl;
68868
- } catch {}
68869
- const sharedViewModelOverrides = {
68870
- $root: {
68871
- siteId: site.id,
68872
- apiBaseUrl,
68873
- previewStage,
68874
- routes,
68875
- pagesByIdentifier: siteData.pagesByIdentifier,
68876
- entriesByIdentifier: siteData.entriesByIdentifier,
68877
- theme: themeWithVariant
68878
- },
68879
- site,
68880
- menu: menuViewModel,
68881
- footerMenu: footerMenuViewModel,
68882
- legalFooterMenu: legalFooterMenuViewModel
68883
- };
68884
- const headerViewModelOverrides = {
68885
- ...sharedViewModelOverrides,
68886
- content: { logo: logoViewModel }
68887
- };
68888
- const footerViewModelOverrides = {
68889
- ...sharedViewModelOverrides,
68890
- content: {
68891
- ...layout.footer,
68892
- logo: logoViewModel
68893
- }
68894
- };
68895
- let headerElement = null;
68896
- if (header === true) headerElement = renderBlock(siteHeaderManifest, headerContent, {
68897
- theme: builtThemeRuntime.tokens,
68898
- themeConfig: blocksThemeWithVariant,
68899
- viewModelOverrides: headerViewModelOverrides
68900
- });
68901
- else if (typeof header === "function") headerElement = header(headerData);
68902
- let footerElement = null;
68903
- if (footer === true) {
68904
- const footerPlan = resolveFooterRenderPlan({
68905
- isSdkSite: Boolean(site.is_sdk_site),
68906
- mode: theme.footer?.mode
68907
- });
68908
- const footerBlocksElement = footerPlan.renderFooterBlocks && footerBlocks.length > 0 ? /* @__PURE__ */ jsx(PageRenderer, {
68909
- theme,
68910
- page: {
68911
- name: "Footer",
68912
- path: "/__footer",
68913
- purpose: "footer",
68914
- blocks: footerBlocks
68915
- },
68916
- routeMap: routes,
68917
- dataContext: {
68918
- previewStage,
68919
- siteId: site.id,
68920
- apiBaseUrl,
68921
- routes,
68922
- pagesByIdentifier: siteData.pagesByIdentifier,
68923
- entriesByIdentifier: siteData.entriesByIdentifier
68924
- },
68925
- sdkConfig: siteData.sdkConfig ?? null
68926
- }) : null;
68927
- if (footerPlan.renderFooterBlocks && !footerBlocksElement && process.env.NODE_ENV !== "production") console.debug("[sdk] Footer mode renders blocks, but footerBlocks is empty/missing", {
68928
- siteId: site.id,
68929
- mode: footerPlan.mode
68930
- });
68931
- const defaultFooterElement = footerPlan.renderDefaultFooter ? renderBlock(siteFooterManifest, layout.footer, {
68932
- theme: builtThemeRuntime.tokens,
68933
- themeConfig: blocksTheme,
68934
- viewModelOverrides: footerViewModelOverrides
68935
- }) : null;
68936
- footerElement = footerPlan.mode === "default+blocks" ? /* @__PURE__ */ jsxs(Fragment, { children: [footerBlocksElement, defaultFooterElement] }) : footerPlan.mode === "blocks" ? footerBlocksElement : footerPlan.mode === "none" ? null : defaultFooterElement;
68937
- } else if (typeof footer === "function") footerElement = footer(footerData);
68938
- const content = /* @__PURE__ */ jsxs(Fragment, { children: [
68939
- headerElement,
68940
- children,
68941
- footerElement
68942
- ] });
68943
- return renderWithSdkThemeRuntime({
68944
- theme,
68945
- themeRuntime: planLayoutThemeRuntime({
68946
- themeRuntime,
68947
- usesSdkChrome: header === true || footer === true
68948
- }),
68949
- children: content
68950
- });
68951
- }
68952
- //#endregion
68953
69371
  //#region ../blocks/src/system/runtime/bindings.ts
68954
69372
  const shouldLogWarnings = isNonProductionEnv();
68955
69373
  function isPlainObject(value) {
@@ -69326,6 +69744,348 @@ function normalizeLoaderParams(endpoint, params, context) {
69326
69744
  ensureSiteId(out, context);
69327
69745
  return out;
69328
69746
  }
69747
+ //#endregion
69748
+ //#region src/rendering/helpers/siteCustomBlocks.ts
69749
+ /**
69750
+ * Prefer the DB-backed custom block manifest list (`site.customBlocks`) when available,
69751
+ * but fall back to SDK config custom blocks (`site.sdkConfig.customBlocks`) for SDK-mode sites.
69752
+ *
69753
+ * This avoids subtle DX bugs where one source is populated but the renderer/prefetch layer
69754
+ * is looking at the other.
69755
+ */
69756
+ function resolveSiteCustomBlocks(site) {
69757
+ const dbBlocks = site.customBlocks;
69758
+ if (Array.isArray(dbBlocks) && dbBlocks.length > 0) return dbBlocks;
69759
+ const sdkBlocks = site.sdkConfig?.customBlocks;
69760
+ if (Array.isArray(sdkBlocks) && sdkBlocks.length > 0) return sdkBlocks;
69761
+ }
69762
+ //#endregion
69763
+ //#region src/rendering/helpers/pageRuntimeSupport.ts
69764
+ function convertPageResponseBlock(block) {
69765
+ if (!isRecord$3(block)) throw new Error("Invalid block format in page API response");
69766
+ if (typeof block.id !== "string" && block.id !== null) throw new Error(`Invalid block id in page: expected string or null, got ${typeof block.id}`);
69767
+ if (typeof block.kind !== "string") throw new Error(`Invalid block kind in page: expected string, got ${typeof block.kind}`);
69768
+ if (typeof block.purpose !== "string") throw new Error(`Invalid block purpose in page: expected string, got ${typeof block.purpose}`);
69769
+ const admission = readInvalidBlockAdmission(block.admission);
69770
+ return {
69771
+ id: block.id,
69772
+ kind: block.kind,
69773
+ purpose: block.purpose,
69774
+ content: sanitizeSdkRuntimeBlockContent(block.kind, readContentRecord(block.content) ?? {}),
69775
+ draftContent: sanitizeNullableSdkRuntimeBlockContent(block.kind, readNestedContentRecord(block.draftContent)),
69776
+ ...admission ? { admission } : {}
69777
+ };
69778
+ }
69779
+ function readInvalidBlockAdmission(value) {
69780
+ if (!isRecord$3(value) || value.kind !== "invalid" || !isRecord$3(value.error)) return null;
69781
+ if (value.error.kind !== "invalid_manifest_content" && value.error.kind !== "manifest_unavailable") return null;
69782
+ return value;
69783
+ }
69784
+ function buildPageOutline(input) {
69785
+ return {
69786
+ name: input.name,
69787
+ path: input.path ?? input.fallbackPath,
69788
+ purpose: input.purpose,
69789
+ blocks: input.blocks.map(convertPageResponseBlock)
69790
+ };
69791
+ }
69792
+ function buildRenderablePageOutline(input) {
69793
+ const page = buildPageOutline(input);
69794
+ return {
69795
+ ...page,
69796
+ blocks: page.blocks.map((block) => admitSdkRuntimePageBlock(block, input.customBlocks))
69797
+ };
69798
+ }
69799
+ function admitSdkRuntimePageBlock(block, customBlocks) {
69800
+ const base = {
69801
+ id: block.id,
69802
+ kind: block.kind,
69803
+ purpose: block.purpose,
69804
+ ...block.bindings ? { bindings: block.bindings } : {}
69805
+ };
69806
+ const transportedAdmission = readInvalidBlockAdmission(block.admission);
69807
+ if (transportedAdmission) return invalidRenderableBlock(base, transportedAdmission.error);
69808
+ const manifest = resolveSdkBlockManifest(block.kind, customBlocks);
69809
+ if (!manifest) return invalidRenderableBlock(base, { kind: "manifest_unavailable" });
69810
+ const content = block.content ?? {};
69811
+ const renderable = admitTransportedRenderableManifestContent(compileManifestContentContract(manifest), content);
69812
+ if (!renderable.ok) return invalidRenderableBlock(base, {
69813
+ kind: "invalid_manifest_content",
69814
+ error: renderable.error
69815
+ });
69816
+ return {
69817
+ ...base,
69818
+ admission: {
69819
+ kind: "renderable",
69820
+ content: renderable.value
69821
+ }
69822
+ };
69823
+ }
69824
+ function resolveSdkBlockManifest(blockKind, customBlocks) {
69825
+ const customBlock = customBlocks?.find((candidate) => candidate.id === blockKind);
69826
+ return customBlock ? parseFieldDefinitions(customBlock.fields) : getBlockDefinition(blockKind)?.manifest ?? null;
69827
+ }
69828
+ function invalidRenderableBlock(block, error) {
69829
+ return {
69830
+ ...block,
69831
+ admission: {
69832
+ kind: "invalid",
69833
+ error
69834
+ }
69835
+ };
69836
+ }
69837
+ function isRecord$3(value) {
69838
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
69839
+ }
69840
+ function readContentRecord(value) {
69841
+ return isRecord$3(value) ? value : void 0;
69842
+ }
69843
+ function readNestedContentRecord(value) {
69844
+ if (!isRecord$3(value)) return null;
69845
+ return readContentRecord(value.data) ?? null;
69846
+ }
69847
+ function sanitizeSdkRuntimeBlockContent(blockKind, content) {
69848
+ if (blockKind !== "block.newsletter-signup") return content;
69849
+ const sanitized = sanitizeNewsletterSignupPublicContent(content);
69850
+ return isRecord$3(sanitized) ? sanitized : {};
69851
+ }
69852
+ function sanitizeNullableSdkRuntimeBlockContent(blockKind, content) {
69853
+ return content ? sanitizeSdkRuntimeBlockContent(blockKind, content) : null;
69854
+ }
69855
+ //#endregion
69856
+ //#region src/rendering/helpers/footerPageOutline.ts
69857
+ function buildFooterRenderablePageOutline(siteData, blocks) {
69858
+ return buildRenderablePageOutline({
69859
+ name: "Footer",
69860
+ path: "/__footer",
69861
+ fallbackPath: "/__footer",
69862
+ purpose: "footer",
69863
+ blocks,
69864
+ customBlocks: resolveSiteCustomBlocks(siteData)
69865
+ });
69866
+ }
69867
+ //#endregion
69868
+ //#region src/rendering/components/Layout.tsx
69869
+ /**
69870
+ * Layout component with header and footer
69871
+ *
69872
+ * Renders site header and footer around content. Fetches site data if not provided.
69873
+ */
69874
+ function isOverrideOnlyLayout(props) {
69875
+ return props.rendering?.kind === "overrides-only";
69876
+ }
69877
+ var UnsupportedOverrideOnlyLayoutChromeError = class extends Error {
69878
+ constructor(surface) {
69879
+ super(`Override-only Layout requires a custom or disabled ${surface}; SDK default chrome is unavailable.`);
69880
+ this.surface = surface;
69881
+ this.code = "unsupported_override_only_layout_chrome";
69882
+ this.name = "UnsupportedOverrideOnlyLayoutChromeError";
69883
+ }
69884
+ };
69885
+ async function resolveLayoutSiteData(props) {
69886
+ if (props.siteData) return props.siteData;
69887
+ if (!props.client) throw new Error("Layout: must provide either siteData or client");
69888
+ if (!props.siteId && !props.slug && !props.domain) throw new Error("Layout: must provide siteId, slug, or domain when using client");
69889
+ return props.client.getSite({
69890
+ id: props.siteId,
69891
+ slug: props.slug,
69892
+ domain: props.domain
69893
+ });
69894
+ }
69895
+ function renderOverrideOnlyLayout(props, data) {
69896
+ if (data.header === true) throw new UnsupportedOverrideOnlyLayoutChromeError("header");
69897
+ if (data.footer === true) throw new UnsupportedOverrideOnlyLayoutChromeError("footer");
69898
+ return renderWithOverrideOnlyRuntime({
69899
+ runtime: props.rendering.runtime ?? defaultOverrideOnlyRuntime,
69900
+ children: /* @__PURE__ */ jsxs(Fragment, { children: [
69901
+ typeof props.header === "function" ? props.header(data.headerData) : null,
69902
+ props.children,
69903
+ typeof props.footer === "function" ? props.footer(data.footerData) : null
69904
+ ] })
69905
+ });
69906
+ }
69907
+ /**
69908
+ * Layout component that wraps content with site header and footer.
69909
+ *
69910
+ * This is a server/RSC-safe component. The default `@riverbankcms/sdk/rendering`
69911
+ * `Page` and `Block` surfaces mount CMS island hydration automatically, while
69912
+ * the strict `@riverbankcms/sdk/rendering/server` surface stays bootstrap-free.
69913
+ * If a custom host renders hydratable CMS islands through the strict server
69914
+ * surface, mount `BlocksIslandsHydrator` from
69915
+ * `@riverbankcms/sdk/rendering/islands` explicitly.
69916
+ *
69917
+ * @example With pre-fetched site data (recommended)
69918
+ * ```tsx
69919
+ * import { Layout } from '@riverbankcms/sdk/rendering/server';
69920
+ * import { Page } from '@riverbankcms/sdk/rendering';
69921
+ *
69922
+ * const site = await client.getSite({ slug: 'my-site' });
69923
+ *
69924
+ * <Layout siteData={site}>
69925
+ * <Page {...pageData} />
69926
+ * </Layout>
69927
+ * ```
69928
+ *
69929
+ * @example With strict server rendering
69930
+ * ```tsx
69931
+ * import { Layout, Page } from '@riverbankcms/sdk/rendering/server';
69932
+ * import { BlocksIslandsHydrator } from '@riverbankcms/sdk/rendering/islands';
69933
+ *
69934
+ * const site = await client.getSite({ slug: 'my-site' });
69935
+ *
69936
+ * <Layout siteData={site}>
69937
+ * <BlocksIslandsHydrator siteId={site.site.id} supabaseUrl={site.supabaseUrl} />
69938
+ * <Page {...pageData} />
69939
+ * </Layout>
69940
+ * ```
69941
+ */
69942
+ async function Layout(props) {
69943
+ const { children, hasPortalSession = false, previewStage = "published" } = props;
69944
+ const header = props.header ?? true;
69945
+ const footer = props.footer ?? true;
69946
+ const siteData = await resolveLayoutSiteData(props);
69947
+ const { site, navigation, layout, routes } = siteData;
69948
+ const footerBlocks = siteData.footerBlocks ?? [];
69949
+ const navigationOptions = {
69950
+ hasPortalSession,
69951
+ previewStage,
69952
+ pagesByIdentifier: siteData.pagesByIdentifier,
69953
+ entriesByIdentifier: siteData.entriesByIdentifier,
69954
+ portalEnabled: siteData.portalEnabled ?? false,
69955
+ commerceEnabled: siteData.commerceEnabled ?? false,
69956
+ checkoutHref: "/checkout"
69957
+ };
69958
+ const menuViewModel = buildMenu(navigation, routes, navigationOptions);
69959
+ const footerMenuViewModel = buildFooterMenu(navigation, routes, navigationOptions);
69960
+ const legalFooterMenuViewModel = buildFooterMenuForRole(navigation, routes, "legal-policy", navigationOptions);
69961
+ const logoViewModel = buildLogo(layout.logo ?? null, site.title);
69962
+ const customHeaderData = {
69963
+ menu: menuViewModel,
69964
+ logo: logoViewModel,
69965
+ site,
69966
+ routes
69967
+ };
69968
+ const customFooterData = {
69969
+ menu: menuViewModel,
69970
+ footerMenu: footerMenuViewModel,
69971
+ legalFooterMenu: legalFooterMenuViewModel,
69972
+ logo: logoViewModel,
69973
+ site,
69974
+ routes
69975
+ };
69976
+ if (isOverrideOnlyLayout(props)) return renderOverrideOnlyLayout(props, {
69977
+ header: props.header ?? true,
69978
+ footer: props.footer ?? true,
69979
+ headerData: customHeaderData,
69980
+ footerData: customFooterData
69981
+ });
69982
+ const theme = requireSdkTheme(siteData.theme, site.id);
69983
+ const builtThemeRuntime = buildThemeRuntime(theme);
69984
+ const headerVariant = props.headerVariant;
69985
+ const themeRuntime = props.themeRuntime;
69986
+ const headerData = {
69987
+ ...customHeaderData,
69988
+ theme
69989
+ };
69990
+ const footerData = {
69991
+ ...customFooterData,
69992
+ theme
69993
+ };
69994
+ const headerContent = headerVariant ? {
69995
+ ...layout.header,
69996
+ variant: headerVariant
69997
+ } : layout.header;
69998
+ const themeWithVariant = headerVariant ? {
69999
+ ...theme,
70000
+ header: {
70001
+ ...theme.header,
70002
+ variant: headerVariant
70003
+ }
70004
+ } : theme;
70005
+ const blocksThemeWithVariant = themeWithVariant;
70006
+ const blocksTheme = theme;
70007
+ let apiBaseUrl;
70008
+ try {
70009
+ apiBaseUrl = getRiverbankEnv().baseUrl;
70010
+ } catch {}
70011
+ const sharedViewModelOverrides = {
70012
+ $root: {
70013
+ siteId: site.id,
70014
+ apiBaseUrl,
70015
+ previewStage,
70016
+ routes,
70017
+ pagesByIdentifier: siteData.pagesByIdentifier,
70018
+ entriesByIdentifier: siteData.entriesByIdentifier,
70019
+ theme: themeWithVariant
70020
+ },
70021
+ site,
70022
+ menu: menuViewModel,
70023
+ footerMenu: footerMenuViewModel,
70024
+ legalFooterMenu: legalFooterMenuViewModel
70025
+ };
70026
+ const headerViewModelOverrides = {
70027
+ ...sharedViewModelOverrides,
70028
+ content: { logo: logoViewModel }
70029
+ };
70030
+ const footerViewModelOverrides = {
70031
+ ...sharedViewModelOverrides,
70032
+ content: {
70033
+ ...layout.footer,
70034
+ logo: logoViewModel
70035
+ }
70036
+ };
70037
+ let headerElement = null;
70038
+ if (header === true) headerElement = renderBlock(siteHeaderManifest, headerContent, {
70039
+ theme: builtThemeRuntime.tokens,
70040
+ themeConfig: blocksThemeWithVariant,
70041
+ viewModelOverrides: headerViewModelOverrides
70042
+ });
70043
+ else if (typeof header === "function") headerElement = header(headerData);
70044
+ let footerElement = null;
70045
+ if (footer === true) {
70046
+ const footerPlan = resolveFooterRenderPlan({
70047
+ isSdkSite: Boolean(site.is_sdk_site),
70048
+ mode: theme.footer?.mode
70049
+ });
70050
+ const footerBlocksElement = footerPlan.renderFooterBlocks && footerBlocks.length > 0 ? /* @__PURE__ */ jsx(PageRenderer, {
70051
+ theme,
70052
+ page: buildFooterRenderablePageOutline(siteData, footerBlocks),
70053
+ routeMap: routes,
70054
+ dataContext: {
70055
+ previewStage,
70056
+ siteId: site.id,
70057
+ apiBaseUrl,
70058
+ routes,
70059
+ pagesByIdentifier: siteData.pagesByIdentifier,
70060
+ entriesByIdentifier: siteData.entriesByIdentifier
70061
+ },
70062
+ sdkConfig: siteData.sdkConfig ?? null
70063
+ }) : null;
70064
+ if (footerPlan.renderFooterBlocks && !footerBlocksElement && process.env.NODE_ENV !== "production") console.debug("[sdk] Footer mode renders blocks, but footerBlocks is empty/missing", {
70065
+ siteId: site.id,
70066
+ mode: footerPlan.mode
70067
+ });
70068
+ const defaultFooterElement = footerPlan.renderDefaultFooter ? renderBlock(siteFooterManifest, layout.footer, {
70069
+ theme: builtThemeRuntime.tokens,
70070
+ themeConfig: blocksTheme,
70071
+ viewModelOverrides: footerViewModelOverrides
70072
+ }) : null;
70073
+ footerElement = footerPlan.mode === "default+blocks" ? /* @__PURE__ */ jsxs(Fragment, { children: [footerBlocksElement, defaultFooterElement] }) : footerPlan.mode === "blocks" ? footerBlocksElement : footerPlan.mode === "none" ? null : defaultFooterElement;
70074
+ } else if (typeof footer === "function") footerElement = footer(footerData);
70075
+ const content = /* @__PURE__ */ jsxs(Fragment, { children: [
70076
+ headerElement,
70077
+ children,
70078
+ footerElement
70079
+ ] });
70080
+ return renderWithSdkThemeRuntime({
70081
+ theme,
70082
+ themeRuntime: planLayoutThemeRuntime({
70083
+ themeRuntime,
70084
+ usesSdkChrome: header === true || footer === true
70085
+ }),
70086
+ children: content
70087
+ });
70088
+ }
69329
70089
  function blockedDemoMutationPolicy(classification, publicMessage) {
69330
70090
  if (publicMessage.trim() === "") throw new Error(`Demo mutation policy ${classification} requires publicMessage.`);
69331
70091
  return {
@@ -70524,6 +71284,13 @@ const PUBLIC_WHOLE_SERIES_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
70524
71284
  //#endregion
70525
71285
  //#region ../api/src/publicEventEndpointDefinitions.ts
70526
71286
  const PUBLIC_EVENT_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
71287
+ resolvePublicEventCheckoutReturn: {
71288
+ path: "/public/sites/{siteId}/events/checkout-return",
71289
+ method: "POST",
71290
+ tags: [TAG_TEMPLATES.publicEvents, "event-checkout"],
71291
+ auth: "public",
71292
+ responseKind: "json"
71293
+ },
70527
71294
  getPublicEventRegistrationOptions: {
70528
71295
  path: "/public/sites/{siteId}/events/registration-options",
70529
71296
  method: "POST",