@riverbankcms/sdk 0.135.0 → 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 (153) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/README.md +4 -8
  3. package/dist/{PreviewEditorSidebar-roNY0GVy.mjs → PreviewEditorSidebar-BU5ZlhQR.mjs} +4 -4
  4. package/dist/{PreviewEditorUI-KboDbEh_.mjs → PreviewEditorUI-9XkHL-bC.mjs} +3 -3
  5. package/dist/{PreviewQueryProvider-DcgaESkm.mjs → PreviewQueryProvider-wbEpXryy.mjs} +1 -1
  6. package/dist/{SdkPreviewModeRuntime-DBrF7Caa.mjs → SdkPreviewModeRuntime-CnWmj-2B.mjs} +50 -99
  7. package/dist/{SiteChromeCustomizeContext-DrIEpJKn.mjs → SiteChromeCustomizeContext-B6d5zkog.mjs} +2334 -1173
  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/blocks/events/shared/schemas.d.ts +25 -0
  26. package/dist/_dts/blocks/src/system/data/index.d.ts +2 -0
  27. package/dist/_dts/blocks/src/system/data/publicLoaderCachePolicy.d.ts +78 -0
  28. package/dist/_dts/blocks/src/system/manifest/fieldValidation/index.d.ts +2 -18
  29. package/dist/_dts/blocks/src/system/manifest/validation.d.ts +103 -16
  30. package/dist/_dts/blocks/src/system/node/validation-constants.d.ts +1 -1
  31. package/dist/_dts/blocks/src/system/runtime/api/client.d.ts +2 -1
  32. package/dist/_dts/blocks/src/system/runtime/api/endpoints.d.ts +8 -0
  33. package/dist/_dts/blocks/src/system/runtime/api/index.d.ts +1 -1
  34. package/dist/_dts/blocks/src/system/runtime/api/types/events.d.ts +19 -0
  35. package/dist/_dts/blocks/src/system/runtime/components/registry.client.d.ts +52 -0
  36. package/dist/_dts/blocks/src/system/runtime/components/runtime-backed-blocks.d.ts +24 -0
  37. package/dist/_dts/blocks/src/system/runtime/hooks/useCalendarEvents.d.ts +44 -18
  38. package/dist/_dts/blocks/src/system/runtime/hooks/useCalendarEvents.state.d.ts +20 -3
  39. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/VerifyingTimeoutStep.d.ts +3 -1
  40. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationStripeReturn.d.ts +1 -0
  41. package/dist/_dts/blocks/src/system/runtime/nodes/events/EventCalendar.client.d.ts +2 -2
  42. package/dist/_dts/blocks/src/system/runtime/nodes/events/EventCalendar.interactive.d.ts +40 -0
  43. package/dist/_dts/blocks/src/system/runtime/nodes/events/EventCombined.client.d.ts +2 -0
  44. package/dist/_dts/blocks/src/system/runtime/nodes/events/EventCombined.interactive.d.ts +43 -0
  45. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/CalendarDayCell.d.ts +3 -1
  46. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/CalendarNavigationChevron.d.ts +4 -0
  47. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/DayEventsModal.d.ts +2 -1
  48. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/EventModalContext.d.ts +3 -2
  49. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/WeekAgendaView.d.ts +3 -0
  50. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/WeekBoardView.d.ts +31 -3
  51. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/WeekTimetableView.d.ts +3 -1
  52. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/eventCollectionContract.d.ts +19 -1
  53. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/timetableModel.d.ts +4 -3
  54. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/utils.d.ts +3 -3
  55. package/dist/_dts/blocks/src/system/transforms/registry/layout.d.ts +0 -1
  56. package/dist/_dts/calendar/src/grid.d.ts +24 -66
  57. package/dist/_dts/calendar/src/index.d.ts +2 -2
  58. package/dist/_dts/calendar/src/timetable.d.ts +5 -9
  59. package/dist/_dts/commerce/src/purchase/allocation.d.ts +11 -0
  60. package/dist/_dts/commerce/src/purchase/index.d.ts +2 -0
  61. package/dist/_dts/commerce/src/purchase/settlement.d.ts +33 -0
  62. package/dist/_dts/commerce/src/purchase/stripeCheckoutReturnUrl.d.ts +8 -0
  63. package/dist/_dts/content-model/src/templates/defaults.d.ts +6 -0
  64. package/dist/_dts/core/src/slug.d.ts +20 -5
  65. package/dist/_dts/preview-next/src/client/blocks/EditablePageRenderer.d.ts +1 -1
  66. package/dist/_dts/preview-next/src/client/preview/headerInteractionPaletteSurfaceState.d.ts +2 -1
  67. package/dist/_dts/sdk/src/client/publicLoaderCacheAccess.d.ts +6 -0
  68. package/dist/_dts/sdk/src/public-api/contracts.d.ts +5 -1
  69. package/dist/_dts/sdk/src/rendering/blocks-page-renderer.d.ts +10 -6
  70. package/dist/_dts/sdk/src/rendering/components/Block.shared.d.ts +0 -1
  71. package/dist/_dts/sdk/src/rendering/components/pageShared.d.ts +4 -4
  72. package/dist/_dts/sdk/src/rendering/helpers/footerPageOutline.d.ts +3 -0
  73. package/dist/_dts/sdk/src/rendering/helpers/loadContent.d.ts +3 -0
  74. package/dist/_dts/sdk/src/rendering/helpers/loadPage.d.ts +1 -1
  75. package/dist/_dts/sdk/src/rendering/helpers/pageRuntimeSupport.d.ts +17 -0
  76. package/dist/_dts/sdk/src/rendering/helpers/templateContent.d.ts +9 -3
  77. package/dist/_dts/sdk/src/rendering/hooks/usePage.d.ts +1 -1
  78. package/dist/_dts/sdk/src/rendering/index.d.ts +2 -2
  79. package/dist/_dts/sdk/src/rendering/overrideResolution.d.ts +7 -4
  80. package/dist/_dts/sdk/src/version.d.ts +1 -1
  81. package/dist/_dts/theme-core/src/cards/types.d.ts +8 -8
  82. package/dist/_dts/theme-core/src/data.d.ts +12 -0
  83. package/dist/_dts/theme-core/src/generated/containerResponsiveThemeCss.d.ts +1 -1
  84. package/dist/_dts/theme-core/src/header/legacyHeaderVariant.d.ts +2 -6
  85. package/dist/_dts/theme-core/src/mock-themes/all.d.ts +6 -807
  86. package/dist/_dts/theme-core/src/schema.d.ts +452 -1278
  87. package/dist/_dts/theme-core/src/site-styles/curatedSiteStyles.d.ts +213 -1
  88. package/dist/_dts/theme-core/src/site-styles/headerLayoutCatalog.d.ts +0 -29
  89. package/dist/_dts/theme-core/src/site-styles/headerLayoutStyles.d.ts +10 -0
  90. package/dist/_dts/theme-core/src/site-styles/headerLayoutTypes.d.ts +8 -5
  91. package/dist/_dts/theme-core/src/site-styles/headerOpeningForeground.d.ts +4 -4
  92. package/dist/_dts/theme-core/src/site-styles/headerStyleCompiler.d.ts +16 -2
  93. package/dist/_dts/theme-core/src/site-styles/headerStyleDefaults.d.ts +465 -0
  94. package/dist/_dts/theme-core/src/site-styles/headerStyleRecipe.d.ts +161 -0
  95. package/dist/client/{BookingConsentAgreement-BQqwi8Oa.mjs → BookingConsentAgreement-DCch21a6.mjs} +2 -2
  96. package/dist/client/{DiscountCodeDisclosure-B97aMo0V.mjs → DiscountCodeDisclosure-DIj1T59K.mjs} +1 -1
  97. package/dist/client/{EventCombined.client-Bs2Iw9Q6.mjs → EventCombined.client-BWVNlXTx.mjs} +226 -206
  98. package/dist/client/{EventListing.client-C4QUQdmg.mjs → EventListing.client-DVFCDe3i.mjs} +2 -2
  99. package/dist/client/{LeafletStaticMap-CwWRk69M.mjs → LeafletStaticMap-BY5mIHw9.mjs} +1 -1
  100. package/dist/client/{accordion-BA0j8Mpw.mjs → accordion-CK29E8rG.mjs} +1 -1
  101. package/dist/client/{bookingForm-Br2e41H0.mjs → bookingForm-DFvnet-N.mjs} +5 -5
  102. package/dist/client/bookings.mjs +87 -47
  103. package/dist/client/{carousel-B4dmwnpD.mjs → carousel-BVU5NQlb.mjs} +1 -1
  104. package/dist/client/{cart-B_ckGW4b.mjs → cart-BNItcZVa.mjs} +3 -3
  105. package/dist/client/{checkout-DAyspHdf.mjs → checkout-Bu6iCdkP.mjs} +3 -3
  106. package/dist/client/client.mjs +1985 -1055
  107. package/dist/client/{context-DljQn8L5.mjs → context-BImarOAq.mjs} +12 -0
  108. package/dist/client/{eventCalendar-pJu3FUod.mjs → eventCalendar-DS2h-UXD.mjs} +256 -114
  109. package/dist/client/{eventCombined-B6Kacm9F.mjs → eventCombined-Drt4Oq9p.mjs} +3 -3
  110. package/dist/client/{eventDetails-CaX9z1pv.mjs → eventDetails-Bl2vWgTX.mjs} +4 -3
  111. package/dist/client/{eventListing-B9aXPO-I.mjs → eventListing-CS7PHY7v.mjs} +3 -3
  112. package/dist/client/{eventRegistration-CBSovBkg.mjs → eventRegistration-D-j8eNy2.mjs} +85 -41
  113. package/dist/client/{form-Cm0tu_7o.mjs → form-RMpoLTyr.mjs} +2 -2
  114. package/dist/client/{headerSection-OgRtHeKS.mjs → headerSection-BYE3Lb3k.mjs} +2 -2
  115. package/dist/client/hooks.mjs +2254 -298
  116. package/dist/client/{locationMap-DmjcYqNM.mjs → locationMap-BxSr7Kkh.mjs} +2 -2
  117. package/dist/client/{newsletterForm-D08OZQAC.mjs → newsletterForm-DerbXwFC.mjs} +2 -2
  118. package/dist/client/{productDetail-BqZeu2P4.mjs → productDetail-4SZCLhAf.mjs} +3 -3
  119. package/dist/client/{productList-mNyIF9FG.mjs → productList-D7AP4GNq.mjs} +3 -3
  120. package/dist/client/{propsDecoder-DwHXRm9X.mjs → propsDecoder-pzBeCh14.mjs} +123 -46
  121. package/dist/client/rendering/client.mjs +793 -488
  122. package/dist/client/rendering/islands.mjs +17 -17
  123. package/dist/client/rendering.mjs +2161 -1268
  124. package/dist/client/{scrollToBlock-DtmdM3v-.mjs → scrollToBlock-CduAKf8T.mjs} +1 -1
  125. package/dist/client/{shop-CNjZK16F.mjs → shop-Cp5p_kGe.mjs} +6 -6
  126. package/dist/client/{shop-commerce-DkNNao1J.mjs → shop-commerce-DicXYaYX.mjs} +5 -5
  127. package/dist/client/{shop-commerce-store-9WA--zuW.mjs → shop-commerce-store-CGWnpY4K.mjs} +1 -1
  128. package/dist/client/{shopShared-CHCVfccY.mjs → shopShared-BDf9ljkm.mjs} +3 -3
  129. package/dist/client/{useEventFilters-DvuaB4ZN.mjs → useEventFilters-DeeyGYuk.mjs} +3 -3
  130. package/dist/preview-next/before-render.mjs +7 -0
  131. package/dist/preview-next/client/runtime.mjs +4 -4
  132. package/dist/preview-next/keepAlive.mjs +7 -0
  133. package/dist/preview-next/middleware.mjs +7 -0
  134. package/dist/{previewAuthStore-C7ksxt5b.mjs → previewAuthStore-DbqBol0V.mjs} +7 -0
  135. package/dist/{sdk-runtime-3GhW4knb.mjs → sdk-runtime-19MO27F0.mjs} +2 -2
  136. package/dist/{separator-D3bCWYYb.mjs → separator-DaPLtJ1f.mjs} +1 -1
  137. package/dist/server/components.mjs +1562 -917
  138. package/dist/server/config-validation.mjs +94 -135
  139. package/dist/server/config.mjs +94 -135
  140. package/dist/server/data.mjs +94 -134
  141. package/dist/server/index.mjs +122 -4
  142. package/dist/server/manifest.mjs +0 -1
  143. package/dist/server/next.mjs +1467 -732
  144. package/dist/server/page-converter.mjs +87 -113
  145. package/dist/server/prebuild.mjs +1 -1
  146. package/dist/server/rendering/server.mjs +1717 -939
  147. package/dist/server/rendering.mjs +1729 -1044
  148. package/dist/server/routing.mjs +3229 -1835
  149. package/dist/server/server.mjs +21739 -19801
  150. package/dist/server/theme-bridge.mjs +656 -264
  151. package/dist/server/theme.mjs +2 -17
  152. package/dist/styles/index.css +609 -181
  153. 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
+ };
13810
+ }
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
+ };
13676
13825
  }
13677
- function createManifestValidatorFromPlans(plans, options, normalize) {
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
@@ -31121,6 +31286,7 @@ const publicWholeSeriesPriceDisplaySchema = z.discriminatedUnion("kind", [
31121
31286
  freePriceDisplaySchema,
31122
31287
  exactPriceDisplaySchema,
31123
31288
  fromPriceDisplaySchema,
31289
+ rangePriceDisplaySchema,
31124
31290
  unavailablePriceDisplaySchema
31125
31291
  ]);
31126
31292
  z.discriminatedUnion("kind", [
@@ -31718,11 +31884,11 @@ function planEventRegistrationScope(input) {
31718
31884
  }
31719
31885
  //#endregion
31720
31886
  //#region ../blocks/src/system/runtime/nodes/events/shared/destination.ts
31721
- function isRecord$12(value) {
31887
+ function isRecord$14(value) {
31722
31888
  return typeof value === "object" && value !== null && !Array.isArray(value);
31723
31889
  }
31724
31890
  function isRuntimeEventDestination(value) {
31725
- if (!isRecord$12(value) || typeof value.kind !== "string") return false;
31891
+ if (!isRecord$14(value) || typeof value.kind !== "string") return false;
31726
31892
  if (value.kind === "native") return (value.mode === "cms-managed" || value.mode === "system-managed") && typeof value.path === "string";
31727
31893
  return value.kind === "external" && typeof value.url === "string" && typeof value.label === "string";
31728
31894
  }
@@ -31785,15 +31951,15 @@ function resolveRuntimeEventPricing(event) {
31785
31951
  function readCurrency(value) {
31786
31952
  return typeof value === "string" && value.trim().length > 0 ? value : DEFAULT_EVENT_CURRENCY;
31787
31953
  }
31788
- function isRecord$11(value) {
31954
+ function isRecord$13(value) {
31789
31955
  return typeof value === "object" && value !== null && !Array.isArray(value);
31790
31956
  }
31791
31957
  function isPublicEventPricing(value) {
31792
- if (!isRecord$11(value) || typeof value.kind !== "string") return false;
31958
+ if (!isRecord$13(value) || typeof value.kind !== "string") return false;
31793
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";
31794
31960
  }
31795
31961
  function isPublicEventTicketType(value) {
31796
- return isRecord$11(value) && typeof value.id === "string";
31962
+ return isRecord$13(value) && typeof value.id === "string";
31797
31963
  }
31798
31964
  function readTicketTypePriceDisplay(value, currency) {
31799
31965
  const display = readLegacyPriceDisplay(value, currency);
@@ -31803,7 +31969,7 @@ function readTicketTypePriceDisplay(value, currency) {
31803
31969
  } : display;
31804
31970
  }
31805
31971
  function readLegacyPriceDisplay(value, currency) {
31806
- if (!isRecord$11(value) || typeof value.kind !== "string") return {
31972
+ if (!isRecord$13(value) || typeof value.kind !== "string") return {
31807
31973
  kind: "unavailable",
31808
31974
  currency
31809
31975
  };
@@ -31855,7 +32021,7 @@ function readLegacyPriceDisplay(value, currency) {
31855
32021
  kind: "unavailable",
31856
32022
  currency: displayCurrency
31857
32023
  };
31858
- case "whole_series": return isRecord$11(value.display) ? {
32024
+ case "whole_series": return isRecord$13(value.display) ? {
31859
32025
  kind: "whole_series",
31860
32026
  display: readCoursePriceDisplay(value.display, displayCurrency)
31861
32027
  } : {
@@ -32250,13 +32416,16 @@ function buildEventRegistrationShellStepLabels(source) {
32250
32416
  }) : false).map((step) => shellLabelForRegistrationStep(step, scopedEvents));
32251
32417
  }
32252
32418
  function scopeEventRegistrationEvents(source) {
32419
+ return toRegistrationEvents(scopeEventRegistrationSourceEvents(source));
32420
+ }
32421
+ function scopeEventRegistrationSourceEvents(source) {
32253
32422
  const scope = planEventRegistrationScope({
32254
- events: toRegistrationEvents(source.events ?? []),
32423
+ events: source.events ?? [],
32255
32424
  wholeSeriesOffering: source.wholeSeriesOffering,
32256
32425
  occurrenceContext: source.occurrenceContext,
32257
32426
  subject: source.subject
32258
32427
  });
32259
- return scope.kind === "invalidSelectedRun" ? [] : scope.events;
32428
+ return scope.kind === "invalidSelectedRun" ? [] : [...scope.events];
32260
32429
  }
32261
32430
  function shellLabelForRegistrationStep(step, events) {
32262
32431
  switch (step) {
@@ -32288,36 +32457,39 @@ const eventRegistrationBlockRuntime = defineClientOwnedBlockRuntime({
32288
32457
  source: createZodCodec(eventRegistrationSourceSchema),
32289
32458
  render: createZodCodec(eventRegistrationRenderSchema)
32290
32459
  },
32291
- buildRender: (source) => ({
32292
- display: buildEventRegistrationDisplay(source),
32293
- hydration: {
32294
- occurrenceContext: source.occurrenceContext ?? null,
32295
- subject: source.subject ?? null,
32296
- events: source.events ?? null,
32297
- wholeSeriesOfferings: source.wholeSeriesOfferings ?? null,
32298
- wholeSeriesOffering: resolveWholeSeriesOffering(source),
32299
- maxTickets: source.maxTickets ?? void 0,
32300
- showVenue: source.showVenue,
32301
- showCapacity: source.showCapacity,
32302
- successMessage: source.successMessage,
32303
- buttonVariant: source.buttonVariant,
32304
- overlayEnabled: source.overlayEnabled,
32305
- spamProtectionEnabled: source.spamProtectionEnabled,
32306
- supportEmail: source.supportEmail,
32307
- sitePasses: source.sitePasses ?? null,
32308
- siteMemberships: source.siteMemberships ?? null
32309
- }
32310
- })
32460
+ buildRender: (source) => {
32461
+ const events = source.events == null ? null : scopeEventRegistrationSourceEvents(source);
32462
+ return {
32463
+ display: buildEventRegistrationDisplay(source),
32464
+ hydration: {
32465
+ occurrenceContext: source.occurrenceContext ?? null,
32466
+ subject: source.subject ?? null,
32467
+ events,
32468
+ wholeSeriesOfferings: source.wholeSeriesOfferings ?? null,
32469
+ wholeSeriesOffering: resolveWholeSeriesOffering(source),
32470
+ maxTickets: source.maxTickets ?? void 0,
32471
+ showVenue: source.showVenue,
32472
+ showCapacity: source.showCapacity,
32473
+ successMessage: source.successMessage,
32474
+ buttonVariant: source.buttonVariant,
32475
+ overlayEnabled: source.overlayEnabled,
32476
+ spamProtectionEnabled: source.spamProtectionEnabled,
32477
+ supportEmail: source.supportEmail,
32478
+ sitePasses: source.sitePasses ?? null,
32479
+ siteMemberships: source.siteMemberships ?? null
32480
+ }
32481
+ };
32482
+ }
32311
32483
  });
32312
32484
  function normalizeEventRegistrationEventInput(value) {
32313
- if (!isRecord$10(value)) return value;
32485
+ if (!isRecord$12(value)) return value;
32314
32486
  return {
32315
32487
  ...value,
32316
32488
  destination: resolveRuntimeEventDestination(value),
32317
32489
  pricing: resolveRuntimeEventPricing(value)
32318
32490
  };
32319
32491
  }
32320
- function isRecord$10(value) {
32492
+ function isRecord$12(value) {
32321
32493
  return typeof value === "object" && value !== null && !Array.isArray(value);
32322
32494
  }
32323
32495
  function buildEventRegistrationInteractiveIslandProps(props) {
@@ -33008,67 +33180,49 @@ const MONTH_NAMES = [
33008
33180
  "November",
33009
33181
  "December"
33010
33182
  ];
33011
- /** Format a date as YYYY-MM-DD using the runtime's local timezone. */
33012
33183
  function formatDateKey(date) {
33013
- 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")}`;
33014
33185
  }
33015
- /**
33016
- * True when `date` and `now` are the same local calendar day.
33017
- * `now` defaults to `new Date()` so casual callers don't need to thread it,
33018
- * but tests and snapshot-rendering should pass an explicit value.
33019
- */
33020
- function isToday(date, now = /* @__PURE__ */ new Date()) {
33021
- return isSameLocalDay(date, now);
33186
+ function isToday(date, today) {
33187
+ return isSameCalendarDay(date, today);
33022
33188
  }
33023
- /** True when two dates fall on the same local calendar day. */
33024
- function isSameLocalDay(left, right) {
33025
- 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
+ };
33026
33199
  }
33027
- /**
33028
- * Build the calendar days for a month view. Returns 42 dates (6 rows × 7
33029
- * days) including padding from prior/next months for a stable grid.
33030
- */
33031
33200
  function getMonthCalendarDays(year, month, startOfWeek) {
33032
- const firstDayOfMonth = new Date(year, month, 1);
33033
- const lastDayOfMonth = new Date(year, month + 1, 0);
33034
- let startOffset = firstDayOfMonth.getDay();
33035
- if (startOfWeek === "monday") startOffset = startOffset === 0 ? 6 : startOffset - 1;
33036
- const days = [];
33037
- for (let i = startOffset - 1; i >= 0; i--) days.push(new Date(year, month, -i));
33038
- for (let day = 1; day <= lastDayOfMonth.getDate(); day++) days.push(new Date(year, month, day));
33039
- while (days.length < 42) {
33040
- const nextDay = days.length - startOffset - lastDayOfMonth.getDate() + 1;
33041
- days.push(new Date(year, month + 1, nextDay));
33042
- }
33043
- 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));
33044
33209
  }
33045
- /** Build the 7 dates of the week containing `baseDate`. */
33046
33210
  function getWeekCalendarDays(baseDate, startOfWeek) {
33047
- const days = [];
33048
- const dayOfWeek = baseDate.getDay();
33049
- const daysToStart = startOfWeek === "monday" ? dayOfWeek === 0 ? 6 : dayOfWeek - 1 : dayOfWeek;
33050
- const weekStart = new Date(baseDate);
33051
- weekStart.setDate(baseDate.getDate() - daysToStart);
33052
- for (let i = 0; i < 7; i++) {
33053
- const date = new Date(weekStart);
33054
- date.setDate(weekStart.getDate() + i);
33055
- days.push(date);
33056
- }
33057
- 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();
33058
33217
  }
33059
- /** Build the 7 dates of the week containing `baseDate` as a fixed-width tuple. */
33060
33218
  function getWeekCalendarDayTuple(baseDate, startOfWeek) {
33061
33219
  const days = getWeekCalendarDays(baseDate, startOfWeek);
33062
33220
  assertWeekCalendarDays(days);
33063
33221
  return days;
33064
33222
  }
33065
33223
  function assertWeekCalendarDays(days) {
33066
- 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");
33067
33225
  }
33068
- /**
33069
- * Day-name labels reordered for the chosen week start. Pass a custom
33070
- * `dayNames` array (length 7, Sunday-first) to localize.
33071
- */
33072
33226
  function getOrderedDayNames(startOfWeek, dayNames = DAY_NAMES) {
33073
33227
  if (startOfWeek === "monday") {
33074
33228
  const sunday = dayNames[0] ?? "Sun";
@@ -33076,22 +33230,17 @@ function getOrderedDayNames(startOfWeek, dayNames = DAY_NAMES) {
33076
33230
  }
33077
33231
  return [...dayNames];
33078
33232
  }
33079
- /**
33080
- * Header title for a calendar view.
33081
- * - month: "January 2025"
33082
- * - week: "January 5 - 11, 2025" or "December 30 - January 5, 2025"
33083
- */
33084
33233
  function formatCalendarTitle(viewDate, view, days, monthNames = MONTH_NAMES) {
33085
33234
  if (view === "week") {
33086
33235
  const weekStart = days[0];
33087
33236
  const weekEnd = days[6];
33088
- if (weekStart === void 0 || weekEnd === void 0) return `${monthNames[viewDate.getMonth()] ?? ""} ${viewDate.getFullYear()}`;
33089
- const startMonth = monthNames[weekStart.getMonth()] ?? "";
33090
- const endMonth = monthNames[weekEnd.getMonth()] ?? "";
33091
- if (weekStart.getMonth() === weekEnd.getMonth()) return `${startMonth} ${weekStart.getDate()} - ${weekEnd.getDate()}, ${weekEnd.getFullYear()}`;
33092
- 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}`;
33093
33242
  }
33094
- return `${monthNames[viewDate.getMonth()] ?? ""} ${viewDate.getFullYear()}`;
33243
+ return `${monthNames[viewDate.month - 1] ?? ""} ${viewDate.year}`;
33095
33244
  }
33096
33245
  function buildCalendarViewport(input) {
33097
33246
  const monthNames = input.monthNames ?? MONTH_NAMES;
@@ -33101,10 +33250,10 @@ function buildCalendarViewport(input) {
33101
33250
  kind: "week",
33102
33251
  anchorDate: input.anchorDate,
33103
33252
  days,
33104
- title: formatCalendarTitle(input.anchorDate, "week", [...days], monthNames)
33253
+ title: formatCalendarTitle(input.anchorDate, "week", days, monthNames)
33105
33254
  };
33106
33255
  }
33107
- const days = getMonthCalendarDays(input.anchorDate.getFullYear(), input.anchorDate.getMonth(), input.startOfWeek);
33256
+ const days = getMonthCalendarDays(input.anchorDate.year, input.anchorDate.month, input.startOfWeek);
33108
33257
  return {
33109
33258
  kind: "month",
33110
33259
  anchorDate: input.anchorDate,
@@ -33252,13 +33401,12 @@ function buildTimetableModel$1(input) {
33252
33401
  const bounds = resolveBounds(input.bounds);
33253
33402
  const viewportDays = getTimetableDays(input.viewDate, input.view ?? "week", input.startOfWeek);
33254
33403
  const viewportKeys = new Set(viewportDays.map(formatDateKey));
33255
- const now = input.now ?? /* @__PURE__ */ new Date();
33256
33404
  const parsed = parseAllItems(input.items, input);
33257
33405
  const inViewport = deriveVisibleSegments(parsed.drafts, viewportKeys);
33258
33406
  const hourRange = resolveHourRange(inViewport, bounds);
33259
33407
  const laid = layoutCellsByDate(inViewport, hourRange, bounds);
33260
33408
  return {
33261
- days: assembleDays(viewportDays, laid.cellsByDate, now),
33409
+ days: assembleDays(viewportDays, laid.cellsByDate, input.today),
33262
33410
  hourTicks: buildHourTicks(hourRange.startHour, hourRange.endHour),
33263
33411
  startHour: hourRange.startHour,
33264
33412
  endHour: hourRange.endHour,
@@ -33315,13 +33463,13 @@ function layoutCellsByDate(segments, hourRange, bounds) {
33315
33463
  diagnostics
33316
33464
  };
33317
33465
  }
33318
- function assembleDays(viewportDays, cellsByDate, now) {
33466
+ function assembleDays(viewportDays, cellsByDate, today) {
33319
33467
  return viewportDays.map((date) => {
33320
33468
  const dateKey = formatDateKey(date);
33321
33469
  return {
33322
33470
  date,
33323
33471
  dateKey,
33324
- isToday: isSameLocalDay(date, now),
33472
+ isToday: isSameCalendarDay(date, today),
33325
33473
  cells: cellsByDate.get(dateKey) ?? []
33326
33474
  };
33327
33475
  });
@@ -33473,13 +33621,12 @@ function getTimetableDays(viewDate, view, startOfWeek) {
33473
33621
  function enumerateDateKeys(startDateKey, endDateKey) {
33474
33622
  if (startDateKey > endDateKey) throw new Error(`Invalid timetable date range: ${startDateKey} is after ${endDateKey}`);
33475
33623
  const start = parseDateKey(startDateKey);
33476
- const end = parseDateKey(endDateKey);
33624
+ parseDateKey(endDateKey);
33477
33625
  const keys = [];
33478
- const cursor = new Date(start.year, start.month - 1, start.day);
33479
- const endDate = new Date(end.year, end.month - 1, end.day);
33480
- while (cursor.getTime() <= endDate.getTime()) {
33626
+ let cursor = start;
33627
+ while (formatDateKey(cursor) <= endDateKey) {
33481
33628
  keys.push(formatDateKey(cursor));
33482
- cursor.setDate(cursor.getDate() + 1);
33629
+ cursor = addDays(cursor, 1);
33483
33630
  }
33484
33631
  return keys;
33485
33632
  }
@@ -33704,10 +33851,10 @@ function formatEventTeacherLine(event) {
33704
33851
  * timezone). Thin domain wrapper over `groupItemsByDate` from the calendar
33705
33852
  * package; preserves the historical `Map<string, PublicEvent[]>` shape.
33706
33853
  */
33707
- function groupEventsByDate(events) {
33854
+ function groupEventsByDate(events, calendarTimeZone) {
33708
33855
  const grouped = groupItemsByDate(events, {
33709
33856
  getStartsAt: (event) => event.startsAt,
33710
- getTimeZone: (event) => event.timeZone ?? "UTC"
33857
+ getTimeZone: () => calendarTimeZone
33711
33858
  });
33712
33859
  const map = /* @__PURE__ */ new Map();
33713
33860
  for (const [dateKey, bucket] of grouped) map.set(dateKey, [...bucket]);
@@ -35438,7 +35585,8 @@ const eventCollectionSourceSchemaShape = {
35438
35585
  buttonVariant: eventButtonVariantSchema.optional(),
35439
35586
  buttonText: z.string().optional(),
35440
35587
  emptyMessage: z.string().optional(),
35441
- className: z.string().optional()
35588
+ className: z.string().optional(),
35589
+ bookingTimeZone: z.string().optional()
35442
35590
  };
35443
35591
  const eventCollectionDisplaySchemaShape = {
35444
35592
  events: z.array(publicEventSchema),
@@ -35473,7 +35621,15 @@ const eventCollectionHydrationSchema = z.object({
35473
35621
  prefetchedEvents: z.boolean(),
35474
35622
  eventSurface: eventSurfaceScopeSchema$1,
35475
35623
  filterEventPresets: z.string().nullable(),
35476
- 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
+ })
35477
35633
  });
35478
35634
  function buildEventCollectionDisplay(source) {
35479
35635
  return {
@@ -35518,14 +35674,19 @@ function buildEventCollectionPresentationDisplay(source) {
35518
35674
  emptyMessage: source.emptyMessage ?? "No upcoming events scheduled."
35519
35675
  };
35520
35676
  }
35521
- function buildEventCollectionHydration(source) {
35677
+ function buildEventCollectionHydration(source, now = /* @__PURE__ */ new Date()) {
35678
+ const timeZone = toBookingTimeZone(source.bookingTimeZone);
35522
35679
  return {
35523
35680
  siteId: source.siteId,
35524
35681
  stage: source.stage,
35525
35682
  prefetchedEvents: source.events != null,
35526
35683
  eventSurface: normalizeEventSurfaceScope(source.eventSurface),
35527
35684
  filterEventPresets: normalizeEventSurfacePresetsCsv(source.filterEventPresets),
35528
- scheduleScope: normalizeEventScheduleScope(source.scheduleScope)
35685
+ scheduleScope: normalizeEventScheduleScope(source.scheduleScope),
35686
+ calendarContext: {
35687
+ timeZone,
35688
+ initialToday: getLocalScheduleDate(now, timeZone)
35689
+ }
35529
35690
  };
35530
35691
  }
35531
35692
  function buildEventCollectionListingDisplay(display, prefetchedEvents, className) {
@@ -37643,7 +37804,7 @@ function inferLegacyOfferingsPreviewGroupOrder(overrides) {
37643
37804
  return keys.length >= 2 ? keys : [];
37644
37805
  }
37645
37806
  function normalizeOfferingsPreviewContentForWrite(value) {
37646
- if (!isRecord$9(value)) return null;
37807
+ if (!isRecord$11(value)) return null;
37647
37808
  const groupOrderValue = value.groupOrder;
37648
37809
  if (Array.isArray(groupOrderValue)) {
37649
37810
  const normalized = normalizeOfferingsPreviewGroupOrder(groupOrderValue);
@@ -37656,7 +37817,7 @@ function normalizeOfferingsPreviewContentForWrite(value) {
37656
37817
  ...value,
37657
37818
  groupOrder: []
37658
37819
  };
37659
- 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) : []);
37660
37821
  return legacyOrder.length > 0 ? {
37661
37822
  ...value,
37662
37823
  groupOrder: legacyOrder
@@ -37721,7 +37882,7 @@ function uniqueOfferingsPreviewSourceKeys(values) {
37721
37882
  }
37722
37883
  return keys;
37723
37884
  }
37724
- function isRecord$9(value) {
37885
+ function isRecord$11(value) {
37725
37886
  return typeof value === "object" && value !== null && !Array.isArray(value);
37726
37887
  }
37727
37888
  function mergeOrderedKeysWithDefaults(orderedKeys, defaultKeys) {
@@ -38176,7 +38337,7 @@ function isOfferingsPreviewItemLimit(value) {
38176
38337
  return value === "1" || value === "2" || value === "3" || value === "4" || value === "5" || value === "6" || value === null;
38177
38338
  }
38178
38339
  function normalizeOfferingsPreviewGroupOverride(value) {
38179
- if (!isRecord$8(value)) return [];
38340
+ if (!isRecord$10(value)) return [];
38180
38341
  const override = {};
38181
38342
  if (isOfferingsPreviewSourceKey(value.sourceKey) || value.sourceKey === null) override.sourceKey = value.sourceKey;
38182
38343
  if (typeof value.title === "string" || value.title === null) override.title = value.title;
@@ -38199,7 +38360,7 @@ function normalizeSectionStylesContent(value) {
38199
38360
  }
38200
38361
  function normalizeBoxStylesContent(value) {
38201
38362
  if (value === null) return null;
38202
- if (!isRecord$8(value)) return void 0;
38363
+ if (!isRecord$10(value)) return void 0;
38203
38364
  const { background: _background, ...rest } = value;
38204
38365
  const background = parseBackgroundContent(value.background);
38205
38366
  return {
@@ -38207,7 +38368,7 @@ function normalizeBoxStylesContent(value) {
38207
38368
  ...background ? { background } : {}
38208
38369
  };
38209
38370
  }
38210
- function isRecord$8(value) {
38371
+ function isRecord$10(value) {
38211
38372
  return typeof value === "object" && value !== null && !Array.isArray(value);
38212
38373
  }
38213
38374
  const embedManifest = createBlockManifest({
@@ -41514,6 +41675,23 @@ function deriveNewsletterSignupRuntimeSource(values) {
41514
41675
  tags: parseTrimmedString(normalized.tags)
41515
41676
  };
41516
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
+ }
41517
41695
  const BLOCK_ID_PATTERN = /^[A-Za-z0-9._:-]{1,200}$/;
41518
41696
  const SIGNED_DESTINATION_REF_PATTERN = /^[A-Za-z0-9._~-]{16,1000}$/;
41519
41697
  function parseTrimmedString(value) {
@@ -41521,6 +41699,9 @@ function parseTrimmedString(value) {
41521
41699
  const trimmed = value.trim();
41522
41700
  return trimmed.length > 0 ? trimmed : null;
41523
41701
  }
41702
+ function isRecord$9(value) {
41703
+ return typeof value === "object" && value !== null;
41704
+ }
41524
41705
  //#endregion
41525
41706
  //#region ../blocks/src/system/runtime/nodes/newsletter-form.types.ts
41526
41707
  /**
@@ -43789,7 +43970,7 @@ const defaultTransforms = createTransformRegistry([
43789
43970
  //#region ../blocks/src/system/data/linkedContentEntries.ts
43790
43971
  const LINKED_CONTENT_ENTRY_META_KEY = "__rbLinkedContentEntry";
43791
43972
  function coerceLinkedContentEntriesPayload(payload) {
43792
- if (!isRecord$7(payload)) return payload;
43973
+ if (!isRecord$8(payload)) return payload;
43793
43974
  const response = payload;
43794
43975
  if (!Array.isArray(response.entries)) return payload;
43795
43976
  const contentType = parsePublicContentTypeMeta(response.contentType);
@@ -43797,16 +43978,16 @@ function coerceLinkedContentEntriesPayload(payload) {
43797
43978
  return response.entries.map((entry) => enrichLinkedContentEntry(entry, contentType));
43798
43979
  }
43799
43980
  function getLinkedContentEntryMeta(value) {
43800
- if (!isRecord$7(value)) return null;
43981
+ if (!isRecord$8(value)) return null;
43801
43982
  const candidate = value[LINKED_CONTENT_ENTRY_META_KEY];
43802
43983
  return isLinkedContentEntryMeta(candidate) ? candidate : null;
43803
43984
  }
43804
43985
  function buildLinkedContentEditTarget(input) {
43805
43986
  const { entry, sourceBlockId, sourceBlockKind, itemIndex } = input;
43806
- if (!isRecord$7(entry)) return null;
43987
+ if (!isRecord$8(entry)) return null;
43807
43988
  const meta = getLinkedContentEntryMeta(entry);
43808
43989
  if (!meta || meta.support.kind !== "supported") return null;
43809
- const content = isRecord$7(entry.content) ? entry.content : {};
43990
+ const content = isRecord$8(entry.content) ? entry.content : {};
43810
43991
  return {
43811
43992
  kind: "linked-content-entry",
43812
43993
  entryId: meta.entryId,
@@ -43870,12 +44051,12 @@ function resolveLinkedEntryInlineFieldEligibility(input) {
43870
44051
  };
43871
44052
  }
43872
44053
  function enrichLinkedContentEntry(entry, contentType) {
43873
- if (!isRecord$7(entry)) return entry;
44054
+ if (!isRecord$8(entry)) return entry;
43874
44055
  const entryId = typeof entry.id === "string" ? entry.id : null;
43875
44056
  if (!entryId) return entry;
43876
44057
  const title = typeof entry.title === "string" && entry.title.trim().length > 0 ? entry.title : entryId;
43877
44058
  const optimisticHash = typeof entry.optimisticHash === "string" && entry.optimisticHash.length > 0 ? entry.optimisticHash : null;
43878
- const content = isRecord$7(entry.content) ? entry.content : {};
44059
+ const content = isRecord$8(entry.content) ? entry.content : {};
43879
44060
  const meta = {
43880
44061
  kind: "linked-content-entry",
43881
44062
  entryId,
@@ -43971,7 +44152,7 @@ function capitalize(value) {
43971
44152
  return value.charAt(0).toUpperCase() + value.slice(1).toLowerCase();
43972
44153
  }
43973
44154
  function parsePublicContentTypeMeta(value) {
43974
- if (!isRecord$7(value)) return null;
44155
+ if (!isRecord$8(value)) return null;
43975
44156
  if (typeof value.key !== "string" || value.key.trim().length === 0) return null;
43976
44157
  return {
43977
44158
  key: value.key,
@@ -43981,7 +44162,7 @@ function parsePublicContentTypeMeta(value) {
43981
44162
  };
43982
44163
  }
43983
44164
  function parsePublicContentTypeLinkedEntryEditing(value) {
43984
- if (!isRecord$7(value) || typeof value.kind !== "string") return null;
44165
+ if (!isRecord$8(value) || typeof value.kind !== "string") return null;
43985
44166
  switch (value.kind) {
43986
44167
  case "generic": return { kind: "generic" };
43987
44168
  case "unsupported-domain-backed": return {
@@ -43992,7 +44173,7 @@ function parsePublicContentTypeLinkedEntryEditing(value) {
43992
44173
  }
43993
44174
  }
43994
44175
  function parsePublicContentTypeFieldMeta(value) {
43995
- if (!isRecord$7(value)) return [];
44176
+ if (!isRecord$8(value)) return [];
43996
44177
  if (typeof value.id !== "string" || typeof value.type !== "string") return [];
43997
44178
  return [{
43998
44179
  id: value.id,
@@ -44007,14 +44188,14 @@ function parseStringArray(value) {
44007
44188
  return value.filter((item) => typeof item === "string");
44008
44189
  }
44009
44190
  function isLinkedContentEntryMeta(value) {
44010
- if (!isRecord$7(value)) return false;
44191
+ if (!isRecord$8(value)) return false;
44011
44192
  if (value.kind !== "linked-content-entry") return false;
44012
44193
  if (typeof value.entryId !== "string") return false;
44013
44194
  if (typeof value.contentTypeKey !== "string") return false;
44014
44195
  if (typeof value.contentTypeLabel !== "string") return false;
44015
44196
  if (typeof value.title !== "string") return false;
44016
44197
  if (!(value.optimisticHash === null || typeof value.optimisticHash === "string")) return false;
44017
- if (!isRecord$7(value.contentType)) return false;
44198
+ if (!isRecord$8(value.contentType)) return false;
44018
44199
  if (!isLinkedEntryFieldSourceArray(value.fieldSources)) return false;
44019
44200
  return isLinkedContentEditSupport(value.support);
44020
44201
  }
@@ -44022,7 +44203,7 @@ function isLinkedEntryFieldSourceArray(value) {
44022
44203
  return Array.isArray(value) && value.every(isLinkedEntryFieldSource);
44023
44204
  }
44024
44205
  function isLinkedEntryFieldSource(value) {
44025
- if (!isRecord$7(value)) return false;
44206
+ if (!isRecord$8(value)) return false;
44026
44207
  if (typeof value.displayPath !== "string") return false;
44027
44208
  switch (value.kind) {
44028
44209
  case "content-field": return typeof value.fieldPath === "string" && (value.fieldType === "text" || value.fieldType === "richText");
@@ -44043,7 +44224,7 @@ function isLinkedEntryInlineFieldReadOnlyReason(value) {
44043
44224
  }
44044
44225
  }
44045
44226
  function isLinkedContentEditSupport(value) {
44046
- if (!isRecord$7(value) || typeof value.kind !== "string") return false;
44227
+ if (!isRecord$8(value) || typeof value.kind !== "string") return false;
44047
44228
  switch (value.kind) {
44048
44229
  case "supported": return true;
44049
44230
  case "unsupported-domain-backed":
@@ -44052,7 +44233,7 @@ function isLinkedContentEditSupport(value) {
44052
44233
  default: return false;
44053
44234
  }
44054
44235
  }
44055
- function isRecord$7(value) {
44236
+ function isRecord$8(value) {
44056
44237
  return typeof value === "object" && value !== null && !Array.isArray(value);
44057
44238
  }
44058
44239
  //#endregion
@@ -44149,11 +44330,11 @@ var UnsafePathSegmentError = class extends Error {
44149
44330
  function assertSafePathSegments(segments) {
44150
44331
  for (const segment of segments) if (typeof segment === "string" && UNSAFE_PATH_SEGMENTS.has(segment)) throw new UnsafePathSegmentError(segment);
44151
44332
  }
44152
- function isRecord$6(value) {
44333
+ function isRecord$7(value) {
44153
44334
  return typeof value === "object" && value !== null && !Array.isArray(value);
44154
44335
  }
44155
44336
  function isPathContainer(value) {
44156
- return Array.isArray(value) || isRecord$6(value);
44337
+ return Array.isArray(value) || isRecord$7(value);
44157
44338
  }
44158
44339
  function getContainerValue(container, segment) {
44159
44340
  if (typeof segment === "number") return Array.isArray(container) ? container[segment] : void 0;
@@ -45614,12 +45795,12 @@ function toTrimmedString(value) {
45614
45795
  return trimmed ? trimmed : void 0;
45615
45796
  }
45616
45797
  function normalizeBookingFormConfig(form) {
45617
- if (!isRecord$5(form)) return null;
45798
+ if (!isRecord$6(form)) return null;
45618
45799
  const id = readNonEmptyString(form.id);
45619
45800
  const name = readNonEmptyString(form.name);
45620
45801
  if (!id || !name) return null;
45621
- const schemaSource = isRecord$5(form.schema) ? form.schema : isRecord$5(form.schemaJson) ? form.schemaJson : null;
45622
- 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;
45623
45804
  return {
45624
45805
  id,
45625
45806
  name,
@@ -45639,8 +45820,8 @@ function normalizeBookingServices(services) {
45639
45820
  };
45640
45821
  if (!services) return [];
45641
45822
  if (Array.isArray(services)) return services.filter(isBookingFormService).map(normalizeService);
45642
- if (isRecord$5(services) && "services" in services) return Array.isArray(services.services) ? services.services.filter(isBookingFormService).map(normalizeService) : [];
45643
- 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) : [];
45644
45825
  }
45645
45826
  function normalizeBookingSchema(value) {
45646
45827
  if (!value) return void 0;
@@ -45651,7 +45832,7 @@ function normalizeBookingSchema(value) {
45651
45832
  };
45652
45833
  }
45653
45834
  function readBookingFormField(value) {
45654
- if (!isRecord$5(value)) return null;
45835
+ if (!isRecord$6(value)) return null;
45655
45836
  const id = readNonEmptyString(value.id);
45656
45837
  const label = readNonEmptyString(value.label);
45657
45838
  const type = readBookingFieldType(value.type);
@@ -45694,7 +45875,7 @@ function readBookingFieldOptions(value) {
45694
45875
  return options.length > 0 ? options : void 0;
45695
45876
  }
45696
45877
  function readBookingFieldOption(value) {
45697
- if (!isRecord$5(value)) return null;
45878
+ if (!isRecord$6(value)) return null;
45698
45879
  const optionValue = readNonEmptyString(value.value);
45699
45880
  const label = readNonEmptyString(value.label);
45700
45881
  return optionValue && label ? {
@@ -45714,7 +45895,7 @@ function normalizeBookingSettings(value) {
45714
45895
  };
45715
45896
  }
45716
45897
  function isBookingFormService(value) {
45717
- 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);
45718
45899
  }
45719
45900
  function readNonEmptyString(value) {
45720
45901
  if (typeof value !== "string") return null;
@@ -45732,7 +45913,7 @@ function readStringArray(value) {
45732
45913
  const strings = value.filter((item) => typeof item === "string");
45733
45914
  return strings.length > 0 ? strings : void 0;
45734
45915
  }
45735
- function isRecord$5(value) {
45916
+ function isRecord$6(value) {
45736
45917
  return typeof value === "object" && value !== null;
45737
45918
  }
45738
45919
  //#endregion
@@ -46147,7 +46328,8 @@ function isOrdinaryEvent(event) {
46147
46328
  function deriveWholeSeriesPhase(sessions, nowIso) {
46148
46329
  const now = Date.parse(nowIso);
46149
46330
  if (now < Date.parse(sessions[0].startsAt)) return "upcoming";
46150
- 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";
46151
46333
  }
46152
46334
  function selectRelatedDates(input) {
46153
46335
  if (!input.seriesId) return [];
@@ -46568,9 +46750,13 @@ function EventDetailsSSR(props) {
46568
46750
  const { blockId, occurrenceContext = null, subject, events = null, className, children } = props;
46569
46751
  const nowIso = (/* @__PURE__ */ new Date()).toISOString();
46570
46752
  const normalizedSubject = normalizeEventRegistrationPageSurfaceSubject(subject);
46753
+ const scopedEvents = events === null ? null : resolveEventRegistrationScopedEvents(events, {
46754
+ occurrenceContext,
46755
+ subject: normalizedSubject
46756
+ });
46571
46757
  const presentation = resolveEventDetailsPresentation({
46572
46758
  ...props,
46573
- events,
46759
+ events: scopedEvents,
46574
46760
  occurrenceContext,
46575
46761
  subject: normalizedSubject,
46576
46762
  nowIso
@@ -46583,7 +46769,7 @@ function EventDetailsSSR(props) {
46583
46769
  /* @__PURE__ */ jsx(IslandPropsScript, { value: {
46584
46770
  occurrenceContext,
46585
46771
  subject: normalizedSubject,
46586
- events,
46772
+ events: scopedEvents,
46587
46773
  showVenue: presentation.showVenue,
46588
46774
  showMap: presentation.showMap,
46589
46775
  showOtherDates: presentation.showOtherDates,
@@ -48265,9 +48451,9 @@ const FULL_DAY_NAMES$1 = [
48265
48451
  * @returns "Monday, January 13"
48266
48452
  */
48267
48453
  function formatAgendaDayHeader(date) {
48268
- const dayName = FULL_DAY_NAMES$1[date.getDay()];
48269
- const monthName = MONTH_NAMES[date.getMonth()];
48270
- 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}`;
48271
48457
  }
48272
48458
  /**
48273
48459
  * WeekAgendaView Component
@@ -48275,14 +48461,14 @@ function formatAgendaDayHeader(date) {
48275
48461
  * Displays a week of events in an agenda/list style with rich event details.
48276
48462
  * Shows all 7 days with date headers, empty days show "No events scheduled".
48277
48463
  */
48278
- const WeekAgendaView = ({ days, events, showCapacity, emptyMessage = "No events scheduled" }) => {
48279
- const eventsByDate = groupEventsByDate(events);
48464
+ const WeekAgendaView = ({ days, events, showCapacity, emptyMessage = "No events scheduled", calendarTimeZone, today: currentDate }) => {
48465
+ const eventsByDate = groupEventsByDate(events, calendarTimeZone);
48280
48466
  return /* @__PURE__ */ jsx("div", {
48281
48467
  className: "event-agenda-week",
48282
48468
  children: days.map((date) => {
48283
48469
  const dateKey = formatDateKey(date);
48284
48470
  const dayEvents = eventsByDate.get(dateKey) || [];
48285
- const today = isToday(date);
48471
+ const today = isToday(date, currentDate);
48286
48472
  return /* @__PURE__ */ jsxs("div", {
48287
48473
  className: `event-agenda-day ${today ? "event-agenda-day--today" : ""}`,
48288
48474
  children: [/* @__PURE__ */ jsx("div", {
@@ -48312,7 +48498,49 @@ const WeekAgendaView = ({ days, events, showCapacity, emptyMessage = "No events
48312
48498
  });
48313
48499
  };
48314
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
48315
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
+ }
48316
48544
  const SHORT_DAY_NAMES = [
48317
48545
  "Sun",
48318
48546
  "Mon",
@@ -48374,6 +48602,114 @@ const WeekBoardCard = ({ event, showCapacity }) => {
48374
48602
  ]
48375
48603
  });
48376
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
+ };
48377
48713
  /**
48378
48714
  * WeekBoardView
48379
48715
  *
@@ -48382,18 +48718,21 @@ const WeekBoardCard = ({ event, showCapacity }) => {
48382
48718
  * to a stacked list on mobile. Repurposes the week-grouped agenda data as a
48383
48719
  * board rather than an hour-positioned timetable grid.
48384
48720
  */
48385
- 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 }) => {
48386
- 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);
48387
48723
  const hasAnyEvents = days.some((date) => (eventsByDate.get(formatDateKey(date)) ?? []).length > 0);
48388
48724
  const ctaClassName = themeButtonClassName({
48389
48725
  variant: buttonVariant,
48390
48726
  size: "sm"
48391
48727
  });
48728
+ const todayClassName = themeButtonClassName({
48729
+ variant: buttonVariant,
48730
+ size: "sm"
48731
+ });
48392
48732
  const hasTitle = typeof title === "string" && title.length > 0;
48393
48733
  const hasFooterNote = typeof footerNote === "string" && footerNote.length > 0;
48394
- const hasCta = typeof ctaHref === "string" && ctaHref.length > 0;
48395
48734
  const footerNoteText = hasAnyEvents ? hasFooterNote ? footerNote : null : emptyMessage;
48396
- const showFooter = hasCta || footerNoteText !== null;
48735
+ const resolvedCtaHref = typeof ctaHref === "string" && ctaHref.length > 0 ? ctaHref : null;
48397
48736
  return /* @__PURE__ */ jsx("div", {
48398
48737
  className: "event-calendar event-calendar--week-board",
48399
48738
  "data-block": "event-calendar",
@@ -48405,59 +48744,34 @@ const WeekBoardView = ({ days, events, showCapacity, emptyMessage = "No classes
48405
48744
  children: [
48406
48745
  /* @__PURE__ */ jsxs("div", {
48407
48746
  className: "event-week-board-top",
48408
- children: [hasTitle ? /* @__PURE__ */ jsx("span", {
48409
- className: "event-week-board-title",
48410
- children: title
48411
- }) : null, /* @__PURE__ */ jsx("div", {
48412
- className: "event-week-board-legend",
48413
- "aria-hidden": "true",
48414
- children: LEGEND_ITEMS.map((item) => /* @__PURE__ */ jsxs("span", {
48415
- className: "event-week-board-legend-item",
48416
- children: [/* @__PURE__ */ jsx("i", {
48417
- className: "event-week-board-legend-dot",
48418
- "data-status": item.status
48419
- }), item.label]
48420
- }, item.status))
48421
- })]
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
+ ]
48422
48758
  }),
48423
- /* @__PURE__ */ jsx("div", {
48424
- className: "event-week-board-grid",
48425
- children: days.map((date) => {
48426
- const dateKey = formatDateKey(date);
48427
- const dayEvents = eventsByDate.get(dateKey) ?? [];
48428
- const today = isToday(date);
48429
- return /* @__PURE__ */ jsxs("div", {
48430
- className: clsx("event-week-board-day", dayEvents.length === 0 && "event-week-board-day--empty", today && "event-week-board-day--today"),
48431
- children: [/* @__PURE__ */ jsxs("div", {
48432
- className: "event-week-board-day-head",
48433
- children: [/* @__PURE__ */ jsx("span", {
48434
- className: "event-week-board-day-abbr",
48435
- children: SHORT_DAY_NAMES[date.getDay()]
48436
- }), /* @__PURE__ */ jsx("span", {
48437
- className: "event-week-board-day-num",
48438
- children: date.getDate()
48439
- })]
48440
- }), /* @__PURE__ */ jsx("div", {
48441
- className: "event-week-board-day-body",
48442
- children: dayEvents.map((event) => /* @__PURE__ */ jsx(WeekBoardCard, {
48443
- event,
48444
- showCapacity
48445
- }, event.occurrenceId || event.id))
48446
- })]
48447
- }, dateKey);
48448
- })
48759
+ /* @__PURE__ */ jsx(WeekBoardLoadError, {
48760
+ navigation,
48761
+ buttonClassName: todayClassName
48449
48762
  }),
48450
- showFooter ? /* @__PURE__ */ jsxs("div", {
48451
- className: "event-week-board-foot",
48452
- children: [footerNoteText !== null ? /* @__PURE__ */ jsx("p", {
48453
- className: "event-week-board-foot-note",
48454
- children: footerNoteText
48455
- }) : null, hasCta ? /* @__PURE__ */ jsx("a", {
48456
- className: ctaClassName,
48457
- href: ctaHref ?? void 0,
48458
- children: ctaLabel
48459
- }) : null]
48460
- }) : 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
+ })
48461
48775
  ]
48462
48776
  })
48463
48777
  });
@@ -48488,6 +48802,7 @@ function buildTimetableModel(input) {
48488
48802
  items: input.events,
48489
48803
  viewDate: input.viewDate,
48490
48804
  startOfWeek: input.startOfWeek,
48805
+ today: input.today,
48491
48806
  getId: (event) => event.id,
48492
48807
  getStartsAt: (event) => event.startsAt,
48493
48808
  getEndsAt: (event) => event.endsAt,
@@ -48549,10 +48864,10 @@ function formatEventTimeRange(event) {
48549
48864
  return `${formatTime(event.startsAt, { timeZone })} - ${formatTime(event.endsAt, { timeZone })}`;
48550
48865
  }
48551
48866
  function formatDayLabel(date) {
48552
- 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}`;
48553
48868
  }
48554
48869
  function formatShortDayLabel(date) {
48555
- return `${(FULL_DAY_NAMES[date.getDay()] ?? "").slice(0, 3)} ${date.getDate()}`;
48870
+ return `${(FULL_DAY_NAMES[getDayOfWeek(date)] ?? "").slice(0, 3)} ${date.day}`;
48556
48871
  }
48557
48872
  //#endregion
48558
48873
  //#region ../blocks/src/system/runtime/nodes/events/EventCalendar.server.tsx
@@ -48599,15 +48914,15 @@ function renderListSsr(display, prefetchedEvents) {
48599
48914
  renderEventCard: (event) => renderEventCard(event, listDisplay)
48600
48915
  });
48601
48916
  }
48602
- function renderCalendarSsr(display) {
48917
+ function renderCalendarSsr(display, hydration) {
48603
48918
  const calendarView = display.defaultCalendarView;
48604
- const viewDate = /* @__PURE__ */ new Date();
48919
+ const viewDate = hydration.calendarContext.initialToday;
48605
48920
  const viewport = buildCalendarViewport({
48606
48921
  view: calendarView,
48607
48922
  anchorDate: viewDate,
48608
48923
  startOfWeek: display.startOfWeek
48609
48924
  });
48610
- const eventsByDate = groupEventsByDate([...display.events]);
48925
+ const eventsByDate = groupEventsByDate([...display.events], hydration.calendarContext.timeZone);
48611
48926
  const dayNames = getOrderedDayNames(display.startOfWeek);
48612
48927
  return /* @__PURE__ */ jsxs("div", {
48613
48928
  className: clsx("event-calendar", display.className ?? void 0),
@@ -48674,7 +48989,9 @@ function renderCalendarSsr(display) {
48674
48989
  days: viewport.days,
48675
48990
  events: [...display.events],
48676
48991
  emptyMessage: display.emptyMessage,
48677
- showCapacity: display.showCapacity
48992
+ showCapacity: display.showCapacity,
48993
+ calendarTimeZone: hydration.calendarContext.timeZone,
48994
+ today: hydration.calendarContext.initialToday
48678
48995
  }) : /* @__PURE__ */ jsxs("div", {
48679
48996
  className: "event-calendar-container",
48680
48997
  children: [/* @__PURE__ */ jsx("div", {
@@ -48688,13 +49005,13 @@ function renderCalendarSsr(display) {
48688
49005
  children: viewport.days.map((date) => {
48689
49006
  const dateKey = formatDateKey(date);
48690
49007
  const dayEvents = eventsByDate.get(dateKey) || [];
48691
- const isCurrentMonth = date.getMonth() === viewDate.getMonth();
48692
- const today = isToday(date);
49008
+ const isCurrentMonth = date.month === viewDate.month;
49009
+ const today = isToday(date, hydration.calendarContext.initialToday);
48693
49010
  return /* @__PURE__ */ jsxs("div", {
48694
49011
  className: clsx("event-calendar-day", !isCurrentMonth && "event-calendar-day--other-month", today && "event-calendar-day--today"),
48695
49012
  children: [/* @__PURE__ */ jsx("div", {
48696
49013
  className: "event-calendar-day-number",
48697
- children: date.getDate()
49014
+ children: date.day
48698
49015
  }), /* @__PURE__ */ jsxs("div", {
48699
49016
  className: "event-calendar-events",
48700
49017
  children: [dayEvents.slice(0, 3).map((event) => /* @__PURE__ */ jsxs("a", {
@@ -48732,8 +49049,8 @@ function renderCalendarSsr(display) {
48732
49049
  ]
48733
49050
  });
48734
49051
  }
48735
- function renderTimetableSsr(display) {
48736
- const viewDate = /* @__PURE__ */ new Date();
49052
+ function renderTimetableSsr(display, hydration) {
49053
+ const viewDate = hydration.calendarContext.initialToday;
48737
49054
  const viewport = buildCalendarViewport({
48738
49055
  view: "week",
48739
49056
  anchorDate: viewDate,
@@ -48742,7 +49059,8 @@ function renderTimetableSsr(display) {
48742
49059
  const model = buildTimetableModel({
48743
49060
  events: [...display.events],
48744
49061
  viewDate,
48745
- startOfWeek: display.startOfWeek
49062
+ startOfWeek: display.startOfWeek,
49063
+ today: hydration.calendarContext.initialToday
48746
49064
  });
48747
49065
  const selectedDayKey = model.days.find((day) => day.isToday)?.dateKey ?? model.days[0]?.dateKey ?? "";
48748
49066
  return /* @__PURE__ */ jsxs("div", {
@@ -48897,20 +49215,21 @@ function renderTimetableSsr(display) {
48897
49215
  })]
48898
49216
  });
48899
49217
  }
48900
- function renderWeekBoardSsr(display) {
48901
- return /* @__PURE__ */ jsx(WeekBoardView, {
48902
- days: getWeekCalendarDayTuple(/* @__PURE__ */ new Date(), display.startOfWeek),
48903
- events: [...display.events],
48904
- showCapacity: display.showCapacity,
48905
- emptyMessage: display.emptyMessage,
48906
- title: display.boardTitle,
48907
- footerNote: display.footerNote,
48908
- ctaLabel: display.loadMoreText ?? display.buttonText,
48909
- ctaHref: display.seeAllUrl,
48910
- buttonVariant: display.buttonVariant,
48911
- elevated: display.elevated,
48912
- banded: display.banded
48913
- });
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) });
48914
49233
  }
48915
49234
  function formatHourLabel(hour) {
48916
49235
  if (hour === 0) return "12 AM";
@@ -48936,13 +49255,13 @@ const EventCalendarSSR = (props) => {
48936
49255
  content = renderListSsr(display, hydration.prefetchedEvents);
48937
49256
  break;
48938
49257
  case "timetable":
48939
- content = renderTimetableSsr(display);
49258
+ content = renderTimetableSsr(display, hydration);
48940
49259
  break;
48941
49260
  case "week-board":
48942
- content = renderWeekBoardSsr(display);
49261
+ content = renderWeekBoardSsr(display, hydration);
48943
49262
  break;
48944
49263
  case "calendar":
48945
- content = renderCalendarSsr(display);
49264
+ content = renderCalendarSsr(display, hydration);
48946
49265
  break;
48947
49266
  default: content = assertNeverDisplayMode(display.displayMode);
48948
49267
  }
@@ -49615,14 +49934,14 @@ function isDecoratedHeadingBlockKind(blockKind) {
49615
49934
  return blockKind === "block.intro" || blockKind === "block.feature-cards" || blockKind === "block.testimonials" || blockKind === "block.faq";
49616
49935
  }
49617
49936
  function readVariant(blockContent) {
49618
- if (!isRecord$4(blockContent)) return void 0;
49937
+ if (!isRecord$5(blockContent)) return void 0;
49619
49938
  const variant = blockContent.variant;
49620
49939
  return typeof variant === "string" ? variant : void 0;
49621
49940
  }
49622
49941
  function isFaqDecoratedVariant(variant) {
49623
49942
  return variant === "default" || variant === "question-columns";
49624
49943
  }
49625
- function isRecord$4(value) {
49944
+ function isRecord$5(value) {
49626
49945
  return typeof value === "object" && value !== null && !Array.isArray(value);
49627
49946
  }
49628
49947
  function buildHeadingDecorationWrapperClassName(className) {
@@ -50728,11 +51047,11 @@ function readTreatment(kind, value) {
50728
51047
  };
50729
51048
  }
50730
51049
  function readBlockComposition(value) {
50731
- if (!isRecord$3(value) || typeof value.kind !== "string") return null;
51050
+ if (!isRecord$4(value) || typeof value.kind !== "string") return null;
50732
51051
  if (!isCompositionKind(value.kind)) return null;
50733
51052
  return readTreatment(value.kind, value.treatment);
50734
51053
  }
50735
- function isRecord$3(value) {
51054
+ function isRecord$4(value) {
50736
51055
  return typeof value === "object" && value !== null && !Array.isArray(value);
50737
51056
  }
50738
51057
  //#endregion
@@ -50984,7 +51303,7 @@ function hydrateResolvedBookingConsentValue(value, context) {
50984
51303
  const hydratedItems = value.map((item) => hydrateResolvedBookingConsentValue(item, context));
50985
51304
  return hydratedItems.every((item, index) => item === value[index]) ? value : hydratedItems;
50986
51305
  }
50987
- if (!isRecord$13(value)) return value;
51306
+ if (!isRecord$15(value)) return value;
50988
51307
  if (isBookingConsentCarrier(value)) {
50989
51308
  const agreement = hydrateValue(value.agreement, context);
50990
51309
  return agreement === value.agreement ? value : {
@@ -51004,7 +51323,7 @@ function hydrateValue(value, context) {
51004
51323
  const resolvedItems = value.map((item) => hydrateValue(item, context));
51005
51324
  return resolvedItems.every((item, index) => item === value[index]) ? value : resolvedItems;
51006
51325
  }
51007
- if (isRecord$13(value)) {
51326
+ if (isRecord$15(value)) {
51008
51327
  if (isInternalLink(value)) return hydrateInternalLink(value, context.routes);
51009
51328
  if (isPageLink(value)) return hydratePageLink(value, context);
51010
51329
  if (isEntryLink(value)) return hydrateEntryLink(value, context);
@@ -51069,7 +51388,7 @@ function hydrateEntryLink(link, context) {
51069
51388
  //#region ../blocks/src/system/manifest/resolveBlockData.ts
51070
51389
  function resolveBlockData(blockId, dataLoaders, dataContext, routes) {
51071
51390
  const raw = blockId ? dataContext?.resolvedData?.[blockId] : void 0;
51072
- 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;
51073
51392
  return dataLoaders && typeof dataLoaders === "object" && Object.keys(dataLoaders).length > 0 ? {} : void 0;
51074
51393
  }
51075
51394
  //#endregion
@@ -52086,36 +52405,9 @@ function buildLegacyHeaderNavLinkStyle(header, contrastTreatment, navTextSize) {
52086
52405
  ...navTextSize ? { textSize: navTextSize } : {}
52087
52406
  };
52088
52407
  if (header.navWeight === "bold" && navStyle === "solid") style.textTransform = "uppercase";
52089
- applyLegacyNavEffects(style, header);
52090
52408
  applyLegacyGlassTreatment(style, header, navStyle);
52091
52409
  return style;
52092
52410
  }
52093
- function applyLegacyNavEffects(style, header) {
52094
- if (!header.navEffects) return;
52095
- const effects = style.effects = {
52096
- ...style.effects,
52097
- hover: [...style.effects?.hover ?? []],
52098
- active: [...style.effects?.active ?? []]
52099
- };
52100
- if (header.navEffects.glow) effects.hover.push({
52101
- effectId: "outer-glow",
52102
- options: { spread: 5 }
52103
- });
52104
- if (header.navEffects.neumorphic) {
52105
- effects.hover.push({
52106
- effectId: "neumorphic-shadow",
52107
- options: { mode: "pressed" }
52108
- });
52109
- effects.hover.push({
52110
- effectId: "text-color-change",
52111
- options: { hoverColorToken: "primary" }
52112
- });
52113
- }
52114
- if (header.navEffects.underlineGradient) effects.hover.push({
52115
- effectId: "border-bottom-grow",
52116
- options: { origin: "center" }
52117
- });
52118
- }
52119
52411
  function applyLegacyGlassTreatment(style, header, navStyle) {
52120
52412
  if (header.navContainer?.type !== "glass" || navStyle !== "minimal") return;
52121
52413
  style.borderRadius = "full";
@@ -52141,19 +52433,6 @@ function glassStateEffects(opacity) {
52141
52433
  //#region ../theme-core/src/header/generateHeaderCss.ts
52142
52434
  const HEADER_BLUR = "blur(12px)";
52143
52435
  const FLOATING_BLUR = "blur(16px)";
52144
- const INSET_SHELL_MARKER_CLASS = "header-bar-frame-inset-shell";
52145
- const INSET_SHELL_EDGE = "1rem";
52146
- const INSET_SHELL_INSET_BLOCK = "0.875rem";
52147
- const INSET_SHELL_RADIUS = "9999px";
52148
- const INSET_SHELL_CONTAINER_MAX = "80rem";
52149
- const INSET_SHELL_INTERIOR_PADDING_X = "1.75rem";
52150
- /**
52151
- * Whether the classic header should render as an inset "brand capsule" shell.
52152
- * The facet is only meaningful for the classic layout; other variants ignore it.
52153
- */
52154
- function usesInsetShell(header) {
52155
- return header.barFrame === "inset-shell" && header.variant === "classic";
52156
- }
52157
52436
  /**
52158
52437
  * Generate complete CSS for header system from theme config
52159
52438
  *
@@ -52231,36 +52510,7 @@ function generateHeaderRootStyles(header, themeId, tokens) {
52231
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`;
52232
52511
  const scrollTreatmentStyles = generateHeaderScrollTreatmentStyles(header.scrollTreatment, themeId, header.variant, scrolledPaintRules);
52233
52512
  if (isContainedNav || basePaintRules.length === 0) return `${baseBlock}\n${overlayFix}${scrollTreatmentStyles}`;
52234
- return `${baseBlock}\n${renderHeaderPaintTargetRules(getHeaderPaintTargets(header.variant, themeId), basePaintRules)}\n${overlayFix}${usesInsetShell(header) ? generateInsetShellStyles(header, themeId) : ""}${scrollTreatmentStyles}`;
52235
- }
52236
- /**
52237
- * Reshapes the full-bleed header paint layer into a contained brand capsule at
52238
- * the desktop breakpoint. The capsule is centred, capped to the page container
52239
- * width, inset from the top, fully rounded, and carries the header depth so it
52240
- * reads as a floating pill. Root border/shadow are neutralised on desktop so a
52241
- * bordered style does not leave a full-width hairline around the capsule. Sticky
52242
- * positioning is unaffected — the root stays full width and sticky while the
52243
- * ::before paint provides the capsule.
52244
- */
52245
- function generateInsetShellStyles(header, themeId) {
52246
- const scope = `:where([data-theme-scope="${themeId}"])`;
52247
- const shellRootSelector = `${scope} .header-root.${INSET_SHELL_MARKER_CLASS}`;
52248
- const shellBeforeSelector = `${scope} .header-root.${INSET_SHELL_MARKER_CLASS}::before`;
52249
- const layoutSelector = `${scope} .header-root.${INSET_SHELL_MARKER_CLASS} .rb-header-layout`;
52250
- const widthValue = header.maxWidth === "full" ? `calc(100% - (${INSET_SHELL_EDGE} * 2))` : `min(${INSET_SHELL_CONTAINER_MAX}, calc(100% - (${INSET_SHELL_EDGE} * 2)))`;
52251
- const shadowVar = getComponentShadowVar(header.shadow?.elevation ?? "none");
52252
- const rootRules = ["border: none;", "box-shadow: none;"];
52253
- const beforeRules = [
52254
- `inset: ${INSET_SHELL_INSET_BLOCK} auto;`,
52255
- "left: 50%;",
52256
- "right: auto;",
52257
- "transform: translateX(-50%);",
52258
- `width: ${widthValue};`,
52259
- `border-radius: ${INSET_SHELL_RADIUS};`,
52260
- ...shadowVar ? [`box-shadow: ${shadowVar};`] : []
52261
- ];
52262
- const layoutRules = [`padding-inline: ${INSET_SHELL_INTERIOR_PADDING_X};`];
52263
- 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}`;
52264
52514
  }
52265
52515
  /**
52266
52516
  * Generate logo typography styles
@@ -52334,7 +52584,7 @@ function generateLogoTextBehaviorStyles(logoText, themeId) {
52334
52584
  * Generate navigation link styles based on navStyle and effects
52335
52585
  *
52336
52586
  * Uses the composable NavLinkStyle system with backward compatibility for
52337
- * legacy navStyle, navWeight, navColor, and navEffects settings.
52587
+ * legacy navStyle, navWeight and navColor settings.
52338
52588
  */
52339
52589
  function generateNavLinkStyles(header, themeId, tokens, theme, contrastTreatment, navTextSize) {
52340
52590
  const navPreferences = {
@@ -54971,9 +55221,43 @@ function pageBlockPosition(index, blockCount) {
54971
55221
  return "middle";
54972
55222
  }
54973
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
54974
55251
  //#region ../blocks/src/PageRenderer.tsx
54975
55252
  function PageRenderer$1(props) {
54976
- 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;
54977
55261
  const imageResolveContext = React$1.useMemo(() => resolvePageRendererImageResolveContext(dataContext), [
54978
55262
  dataContext?.imageResolveContext,
54979
55263
  dataContext?.mediaAssets,
@@ -55072,11 +55356,11 @@ function resolvePageRendererImageResolveContext(dataContext) {
55072
55356
  mediaAssets: input?.mediaAssets ?? dataContext?.mediaAssets
55073
55357
  });
55074
55358
  }
55359
+ const resolveBookingTimeZone = (dataContext) => dataContext?.bookingTimeZone;
55075
55360
  function buildBlockSectionProps(input) {
55076
55361
  return {
55077
55362
  themeResources: input.themeResources,
55078
55363
  block: input.block,
55079
- usePlaceholders: input.props.usePlaceholders ?? false,
55080
55364
  dataContext: input.props.dataContext,
55081
55365
  blockKey: input.blockKey,
55082
55366
  registry: input.registry,
@@ -55100,7 +55384,6 @@ function getBlockOverride(blockKind, overrides) {
55100
55384
  if (overrides[shortKind]) return overrides[shortKind];
55101
55385
  }
55102
55386
  const blockComponentCache = /* @__PURE__ */ new WeakMap();
55103
- const manifestValidatorCache = /* @__PURE__ */ new WeakMap();
55104
55387
  const DEFAULT_PERF_SLOW_BLOCK_RENDER_THRESHOLD_MS = 25;
55105
55388
  let cachedPerfSlowBlockRenderThresholdMs = null;
55106
55389
  function getPerfSlowBlockRenderThresholdMs() {
@@ -55118,44 +55401,13 @@ function getCachedBlockComponent(manifest) {
55118
55401
  return created;
55119
55402
  }
55120
55403
  /**
55121
- * Render-time manifest validator — see `.claude/plans/dapper-jingling-emerson.md`
55122
- * Phase 10. One function, two flavours:
55123
- *
55124
- * - `strict` (default): the contract every render surface tries first. No
55125
- * null tolerance, no missing-required tolerance. Production frontends and
55126
- * the dashboard preview both go through this path; after Phases 6-9 the
55127
- * preview satisfies strict structurally.
55128
- * - `relaxed`: editor-mid-edit fallback. Reached via `usePlaceholders` when
55129
- * strict fails. Built on `mode: 'draft'` so empty required fields parse
55130
- * as `undefined` and the user's valid in-flight fields flow through.
55131
- *
55132
- * Per-manifest, per-flavour cached. Adding a third flavour means adding a
55133
- * branch to the `createManifestValidator` call below and a member to
55134
- * `ValidationFlavour` — no per-flavour helper duplication.
55135
- */
55136
- function getCachedValidator(manifest, flavour) {
55137
- let perFlavour = manifestValidatorCache.get(manifest);
55138
- if (!perFlavour) {
55139
- perFlavour = /* @__PURE__ */ new Map();
55140
- manifestValidatorCache.set(manifest, perFlavour);
55141
- }
55142
- const cached = perFlavour.get(flavour);
55143
- if (cached) return cached;
55144
- const created = createManifestValidator(manifest, {
55145
- allowNull: false,
55146
- ...flavour === "relaxed" ? { mode: "draft" } : {}
55147
- });
55148
- perFlavour.set(flavour, created);
55149
- return created;
55150
- }
55151
- /**
55152
55404
  * Memoized block section component.
55153
55405
  *
55154
55406
  * Custom memoization prevents render loops during editing by explicitly checking
55155
55407
  * referential equality of all props that affect rendering. Standard React.memo
55156
55408
  * wouldn't catch all the render triggers from the editor store.
55157
55409
  */
55158
- 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 }) {
55159
55411
  const perfStart = globalThis.process?.env?.DEBUG_PERF === "1" && typeof window === "undefined" ? Date.now() : 0;
55160
55412
  const fallbackImageResolveContext = getCurrentResolveImageUrlContext();
55161
55413
  const resolvedImageResolveContext = imageResolveContext ?? fallbackImageResolveContext;
@@ -55175,6 +55427,19 @@ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeResources
55175
55427
  } catch {}
55176
55428
  return node;
55177
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
+ }
55178
55443
  const OverrideComponent = getBlockOverride(block.kind, blockOverrides);
55179
55444
  requireBlockOverride(themeResources, OverrideComponent, block.kind);
55180
55445
  let definition = getBlockDefinition(block.kind);
@@ -55244,25 +55509,10 @@ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeResources
55244
55509
  });
55245
55510
  }
55246
55511
  const content = getRenderableContent(block, dataContext?.previewStage);
55247
- const parsed = getCachedValidator(definition.manifest, "strict").safeParse(content);
55248
- try {
55249
- if (globalThis.process?.env?.NODE_ENV !== "production" && !parsed.success && !usePlaceholders) console.warn("[blocks:PageRenderer] manifest validation failed", {
55250
- blockId: block.id ?? null,
55251
- blockKind: block.kind,
55252
- content: summarizeValue(content),
55253
- expectedFields: (definition.manifest.fields ?? []).map((f) => ({
55254
- id: f.id,
55255
- type: f.type,
55256
- required: !!f.required
55257
- })),
55258
- issues: parsed.error?.issues ?? null
55259
- });
55260
- } catch {}
55261
- let data;
55262
- if (parsed.success) data = parsed.data;
55263
- else if (usePlaceholders) {
55264
- const relaxed = getCachedValidator(definition.manifest, "relaxed").safeParse(content);
55265
- 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;
55266
55516
  else {
55267
55517
  const rendered = fallback(`Unable to render block kind "${block.kind}".`);
55268
55518
  return finish(wrapBlock && block.id ? /* @__PURE__ */ jsx(Fragment, { children: wrapBlock(block.id, rendered) }) : /* @__PURE__ */ jsx(Fragment, { children: rendered }), {
@@ -55270,12 +55520,6 @@ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeResources
55270
55520
  override: false
55271
55521
  });
55272
55522
  }
55273
- } else {
55274
- const rendered = fallback(`Invalid content for block kind "${block.kind}".`);
55275
- return finish(wrapBlock && block.id ? /* @__PURE__ */ jsx(Fragment, { children: wrapBlock(block.id, rendered) }) : /* @__PURE__ */ jsx(Fragment, { children: rendered }), {
55276
- outcome: "invalidContent",
55277
- override: false
55278
- });
55279
55523
  }
55280
55524
  try {
55281
55525
  const routes = routeMap ?? dataContext?.routes;
@@ -55301,6 +55545,7 @@ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeResources
55301
55545
  blockId: block.id ?? null,
55302
55546
  blockKind: block.kind
55303
55547
  };
55548
+ baseProps.bookingTimeZone = resolveBookingTimeZone(dataContext);
55304
55549
  let rendered;
55305
55550
  if (OverrideComponent) rendered = /* @__PURE__ */ jsx(OverrideComponent, { ...baseProps });
55306
55551
  else {
@@ -55347,14 +55592,14 @@ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeResources
55347
55592
  hasResolvedData
55348
55593
  });
55349
55594
  } catch {
55350
- 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}".`);
55351
55596
  return finish(wrapBlock && block.id ? /* @__PURE__ */ jsx(Fragment, { children: wrapBlock(block.id, rendered) }) : /* @__PURE__ */ jsx(Fragment, { children: rendered }), {
55352
55597
  outcome: "exception",
55353
55598
  override: false
55354
55599
  });
55355
55600
  }
55356
55601
  }, (prev, next) => {
55357
- 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;
55358
55603
  });
55359
55604
  function fallback(message) {
55360
55605
  return /* @__PURE__ */ jsx("div", {
@@ -55381,32 +55626,6 @@ function getRenderableContent(block, previewStage = "published") {
55381
55626
  if (!isObjectRecord$1(source)) return {};
55382
55627
  return source;
55383
55628
  }
55384
- function summarizeValue(value) {
55385
- try {
55386
- if (value === null || value === void 0) return value;
55387
- if (typeof value === "string") return value.length > 160 ? `${value.slice(0, 160)}…` : value;
55388
- if (typeof value === "number" || typeof value === "boolean") return value;
55389
- if (Array.isArray(value)) return `[array(${value.length})]`;
55390
- if (typeof value === "object") {
55391
- const rec = value;
55392
- const keys = Object.keys(rec);
55393
- const preview = {};
55394
- for (const k of keys.slice(0, 8)) {
55395
- const v = rec[k];
55396
- if (k === "body" || k === "content") preview[k] = !!(v && typeof v === "object" && isObjectRecord$1(v) && v.type === "doc") ? "{type:doc}" : summarizeValue(v);
55397
- else preview[k] = summarizeValue(v);
55398
- }
55399
- return {
55400
- keys,
55401
- preview
55402
- };
55403
- }
55404
- if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint" || typeof value === "symbol") return String(value);
55405
- return "[uninspectable]";
55406
- } catch {
55407
- return "[uninspectable]";
55408
- }
55409
- }
55410
55629
  //#endregion
55411
55630
  //#region ../theme-core/src/footer/mode.ts
55412
55631
  /**
@@ -62040,31 +62259,37 @@ const containerResponsiveThemeCss = `/*
62040
62259
  */
62041
62260
 
62042
62261
  /* Main container */
62043
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar {
62262
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-calendar {
62044
62263
  width: 100%;
62045
62264
  }
62046
62265
 
62047
- :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 {
62048
62269
  border: 1px solid var(--ec-border);
62049
62270
  border-radius: var(--rb-block-radius);
62050
62271
  overflow: hidden;
62051
62272
  }
62052
62273
 
62053
62274
  /* Calendar navigation */
62054
- :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 {
62055
62278
  display: flex;
62056
62279
  align-items: center;
62057
62280
  justify-content: space-between;
62058
62281
  margin-bottom: 1rem;
62059
62282
  }
62060
62283
 
62061
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-nav {
62284
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-calendar-nav {
62062
62285
  display: flex;
62063
62286
  align-items: center;
62064
62287
  gap: 0.5rem;
62065
62288
  }
62066
62289
 
62067
- :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 {
62068
62293
  display: flex;
62069
62294
  align-items: center;
62070
62295
  justify-content: center;
@@ -62079,11 +62304,15 @@ const containerResponsiveThemeCss = `/*
62079
62304
  transition: background-color var(--rb-block-transition) ease;
62080
62305
  }
62081
62306
 
62082
- :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 {
62083
62310
  background-color: var(--ec-nav-hover-bg);
62084
62311
  }
62085
62312
 
62086
- :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 {
62087
62316
  font-size: 1.125rem;
62088
62317
  font-weight: 600;
62089
62318
  min-width: 200px;
@@ -62091,13 +62320,17 @@ const containerResponsiveThemeCss = `/*
62091
62320
  }
62092
62321
 
62093
62322
  /* Day headers */
62094
- :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 {
62095
62326
  display: grid;
62096
62327
  grid-template-columns: repeat(7, minmax(0, 1fr));
62097
62328
  background-color: var(--ec-header-bg);
62098
62329
  }
62099
62330
 
62100
- :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 {
62101
62334
  text-align: center;
62102
62335
  padding: 0.5rem;
62103
62336
  font-size: 0.875rem;
@@ -62107,33 +62340,43 @@ const containerResponsiveThemeCss = `/*
62107
62340
  }
62108
62341
 
62109
62342
  /* Calendar grid */
62110
- :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 {
62111
62346
  display: grid;
62112
62347
  grid-template-columns: repeat(7, minmax(0, 1fr));
62113
62348
  }
62114
62349
 
62115
62350
  /* Day cells */
62116
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-day {
62351
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-calendar-day {
62117
62352
  min-height: 100px;
62118
62353
  border-bottom: 1px solid var(--ec-border-subtle);
62119
62354
  border-right: 1px solid var(--ec-border-subtle);
62120
62355
  padding: 0.25rem;
62121
62356
  }
62122
62357
 
62123
- :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) {
62124
62361
  border-right: none;
62125
62362
  }
62126
62363
 
62127
- :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 {
62128
62367
  background-color: var(--ec-today-bg);
62129
62368
  }
62130
62369
 
62131
- :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 {
62132
62373
  opacity: var(--ec-other-month-opacity);
62133
62374
  }
62134
62375
 
62135
62376
  /* Day number */
62136
- :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 {
62137
62380
  font-size: 0.875rem;
62138
62381
  font-weight: 500;
62139
62382
  margin-bottom: 0.25rem;
@@ -62141,21 +62384,28 @@ const containerResponsiveThemeCss = `/*
62141
62384
  opacity: var(--ec-day-number-opacity);
62142
62385
  }
62143
62386
 
62144
- :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 {
62145
62391
  font-weight: 700;
62146
62392
  opacity: 1;
62147
62393
  color: var(--ec-today-text);
62148
62394
  }
62149
62395
 
62150
62396
  /* Events list */
62151
- :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 {
62152
62400
  display: flex;
62153
62401
  flex-direction: column;
62154
62402
  gap: 0.25rem;
62155
62403
  }
62156
62404
 
62157
62405
  /* Event item - solid primary background */
62158
- :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 {
62159
62409
  display: flex;
62160
62410
  align-items: center;
62161
62411
  gap: 0.375rem;
@@ -62176,24 +62426,32 @@ const containerResponsiveThemeCss = `/*
62176
62426
  transform var(--rb-block-transition) ease;
62177
62427
  }
62178
62428
 
62179
- :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 {
62180
62432
  background-color: var(--ec-event-solid-hover-bg);
62181
62433
  transform: translateY(-1px);
62182
62434
  }
62183
62435
 
62184
- :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 {
62185
62439
  outline: 2px solid var(--ec-event-solid-bg);
62186
62440
  outline-offset: 2px;
62187
62441
  }
62188
62442
 
62189
- :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 {
62190
62446
  flex-shrink: 0;
62191
62447
  white-space: nowrap;
62192
62448
  font-weight: 600;
62193
62449
  opacity: 0.9;
62194
62450
  }
62195
62451
 
62196
- :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 {
62197
62455
  min-width: 0;
62198
62456
  overflow: hidden;
62199
62457
  text-overflow: ellipsis;
@@ -62201,7 +62459,9 @@ const containerResponsiveThemeCss = `/*
62201
62459
  }
62202
62460
 
62203
62461
  /* More indicator - clickable button style */
62204
- :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 {
62205
62465
  font-size: 0.75rem;
62206
62466
  padding: 0.25rem 0.5rem;
62207
62467
  color: rgb(var(--tb-primary));
@@ -62213,16 +62473,22 @@ const containerResponsiveThemeCss = `/*
62213
62473
  transition: background-color var(--rb-block-transition) ease;
62214
62474
  }
62215
62475
 
62216
- :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 {
62217
62479
  background-color: rgba(var(--tb-primary), 0.1);
62218
62480
  }
62219
62481
 
62220
- :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 {
62221
62485
  outline: 2px solid rgb(var(--tb-primary));
62222
62486
  outline-offset: 2px;
62223
62487
  }
62224
62488
 
62225
- :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 {
62226
62492
  text-align: center;
62227
62493
  font-size: 0.875rem;
62228
62494
  opacity: var(--ec-empty-opacity);
@@ -62230,21 +62496,21 @@ const containerResponsiveThemeCss = `/*
62230
62496
  }
62231
62497
 
62232
62498
  /* Filters container */
62233
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-filters {
62499
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-filters {
62234
62500
  display: flex;
62235
62501
  flex-wrap: wrap;
62236
62502
  gap: 1rem;
62237
62503
  margin-bottom: 1.5rem;
62238
62504
  }
62239
62505
 
62240
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-filter {
62506
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-filter {
62241
62507
  display: flex;
62242
62508
  flex-direction: column;
62243
62509
  gap: 0.375rem;
62244
62510
  min-width: 180px;
62245
62511
  }
62246
62512
 
62247
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-filter-label {
62513
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-filter-label {
62248
62514
  font-size: 0.75rem;
62249
62515
  font-weight: 500;
62250
62516
  text-transform: uppercase;
@@ -62253,19 +62519,23 @@ const containerResponsiveThemeCss = `/*
62253
62519
  }
62254
62520
 
62255
62521
  /* Event filter select inherits base styling from .form-select, only block-specific overrides here */
62256
- :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 {
62257
62525
  /* Use theme input radius instead of block radius for consistency with other form inputs */
62258
62526
  border-radius: var(--rb-input-radius, var(--rb-block-radius));
62259
62527
  }
62260
62528
 
62261
62529
  /* Category filter buttons */
62262
- :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 {
62263
62533
  display: flex;
62264
62534
  flex-wrap: wrap;
62265
62535
  gap: 0.5rem;
62266
62536
  }
62267
62537
 
62268
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-category-btn {
62538
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-category-btn {
62269
62539
  padding: 0.5rem 1rem;
62270
62540
  font-size: 0.875rem;
62271
62541
  font-weight: 500;
@@ -62277,50 +62547,66 @@ const containerResponsiveThemeCss = `/*
62277
62547
  transition: all var(--rb-block-transition) ease;
62278
62548
  }
62279
62549
 
62280
- :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) {
62281
62553
  border-color: rgba(var(--tb-primary), 0.5);
62282
62554
  }
62283
62555
 
62284
- :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 {
62285
62559
  outline: 2px solid rgb(var(--tb-primary));
62286
62560
  outline-offset: 2px;
62287
62561
  }
62288
62562
 
62289
- :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 {
62290
62566
  background-color: rgb(var(--tb-primary));
62291
62567
  border-color: rgb(var(--tb-primary));
62292
62568
  color: var(--ec-event-solid-text);
62293
62569
  }
62294
62570
 
62295
- :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 {
62296
62574
  opacity: 0.5;
62297
62575
  cursor: not-allowed;
62298
62576
  }
62299
62577
 
62300
62578
  /* Allow category filter to be wider for button group */
62301
- :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) {
62302
62582
  min-width: auto;
62303
62583
  flex: 1 1 auto;
62304
62584
  }
62305
62585
 
62306
62586
  /* Combined mode container */
62307
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-combined {
62587
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-combined {
62308
62588
  width: 100%;
62309
62589
  }
62310
62590
 
62311
- :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 {
62312
62594
  display: flex;
62313
62595
  flex-direction: column;
62314
62596
  }
62315
62597
 
62316
62598
  /* Calendar view toggle (Month/Week) in Combined mode */
62317
- :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 {
62318
62602
  display: flex;
62319
62603
  gap: 0.25rem;
62320
62604
  margin-bottom: 1rem;
62321
62605
  }
62322
62606
 
62323
- :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 {
62324
62610
  padding: 0.5rem 1rem;
62325
62611
  font-size: 0.875rem;
62326
62612
  font-weight: 500;
@@ -62333,12 +62619,16 @@ const containerResponsiveThemeCss = `/*
62333
62619
  transition: all var(--rb-block-transition) ease;
62334
62620
  }
62335
62621
 
62336
- :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 {
62337
62625
  opacity: 1;
62338
62626
  border-color: rgba(var(--tb-primary), 0.5);
62339
62627
  }
62340
62628
 
62341
- :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 {
62342
62632
  opacity: 1;
62343
62633
  background-color: rgb(var(--tb-primary));
62344
62634
  border-color: rgb(var(--tb-primary));
@@ -62351,29 +62641,35 @@ const containerResponsiveThemeCss = `/*
62351
62641
  * ----------------------------------------------------------------------------- */
62352
62642
 
62353
62643
  /* Agenda week container */
62354
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-week {
62644
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-agenda-week {
62355
62645
  display: flex;
62356
62646
  flex-direction: column;
62357
62647
  gap: 0;
62358
62648
  }
62359
62649
 
62360
62650
  /* Individual day section */
62361
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-day {
62651
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-agenda-day {
62362
62652
  border-bottom: 1px solid var(--ec-border-subtle);
62363
62653
  }
62364
62654
 
62365
- :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 {
62366
62658
  border-bottom: none;
62367
62659
  }
62368
62660
 
62369
62661
  /* Day header */
62370
- :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 {
62371
62665
  padding: 0.75rem 0;
62372
62666
  background-color: var(--ec-header-bg);
62373
62667
  border-bottom: 1px solid var(--ec-border-subtle);
62374
62668
  }
62375
62669
 
62376
- :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 {
62377
62673
  font-size: 0.875rem;
62378
62674
  font-weight: 600;
62379
62675
  margin: 0;
@@ -62383,7 +62679,9 @@ const containerResponsiveThemeCss = `/*
62383
62679
  }
62384
62680
 
62385
62681
  /* Today badge */
62386
- :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 {
62387
62685
  display: inline-flex;
62388
62686
  align-items: center;
62389
62687
  padding: 0.125rem 0.5rem;
@@ -62397,24 +62695,33 @@ const containerResponsiveThemeCss = `/*
62397
62695
  }
62398
62696
 
62399
62697
  /* Today highlight for entire day section */
62400
- :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 {
62401
62702
  background-color: var(--ec-today-bg);
62402
62703
  }
62403
62704
 
62404
62705
  /* Day content area */
62405
- :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 {
62406
62709
  padding: 0.75rem 0;
62407
62710
  }
62408
62711
 
62409
62712
  /* Events list within a day */
62410
- :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 {
62411
62716
  display: flex;
62412
62717
  flex-direction: column;
62413
62718
  gap: 0.5rem;
62414
62719
  }
62415
62720
 
62416
62721
  /* Empty day message */
62417
- :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 {
62418
62725
  font-size: 0.875rem;
62419
62726
  opacity: var(--ec-empty-opacity);
62420
62727
  margin: 0;
@@ -62426,7 +62733,7 @@ const containerResponsiveThemeCss = `/*
62426
62733
  * Rich event card for agenda view
62427
62734
  * ----------------------------------------------------------------------------- */
62428
62735
 
62429
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-card {
62736
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-agenda-card {
62430
62737
  display: flex;
62431
62738
  align-items: flex-start;
62432
62739
  gap: 0.75rem;
@@ -62439,13 +62746,17 @@ const containerResponsiveThemeCss = `/*
62439
62746
  transition: all var(--rb-block-transition) ease;
62440
62747
  }
62441
62748
 
62442
- :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 {
62443
62752
  border-color: rgba(var(--tb-primary), 0.5);
62444
62753
  background-color: var(--ec-event-bg);
62445
62754
  }
62446
62755
 
62447
62756
  /* Category color indicator */
62448
- :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 {
62449
62760
  flex-shrink: 0;
62450
62761
  width: 4px;
62451
62762
  align-self: stretch;
@@ -62454,7 +62765,9 @@ const containerResponsiveThemeCss = `/*
62454
62765
  }
62455
62766
 
62456
62767
  /* Card content wrapper */
62457
- :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 {
62458
62771
  flex: 1;
62459
62772
  min-width: 0;
62460
62773
  display: flex;
@@ -62463,28 +62776,36 @@ const containerResponsiveThemeCss = `/*
62463
62776
  }
62464
62777
 
62465
62778
  /* Header row: time + title */
62466
- :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 {
62467
62782
  display: flex;
62468
62783
  align-items: baseline;
62469
62784
  gap: 0.5rem;
62470
62785
  flex-wrap: wrap;
62471
62786
  }
62472
62787
 
62473
- :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 {
62474
62791
  font-size: 0.75rem;
62475
62792
  font-weight: 600;
62476
62793
  opacity: var(--ec-time-opacity);
62477
62794
  white-space: nowrap;
62478
62795
  }
62479
62796
 
62480
- :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 {
62481
62800
  font-size: 0.875rem;
62482
62801
  font-weight: 500;
62483
62802
  line-height: 1.3;
62484
62803
  }
62485
62804
 
62486
62805
  /* Details row: venue, price, capacity */
62487
- :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 {
62488
62809
  display: flex;
62489
62810
  align-items: center;
62490
62811
  gap: 0.75rem;
@@ -62493,26 +62814,36 @@ const containerResponsiveThemeCss = `/*
62493
62814
  opacity: 0.7;
62494
62815
  }
62495
62816
 
62496
- :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 {
62497
62820
  display: inline-flex;
62498
62821
  align-items: center;
62499
62822
  gap: 0.25rem;
62500
62823
  }
62501
62824
 
62502
- :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 {
62503
62828
  flex-shrink: 0;
62504
62829
  opacity: 0.7;
62505
62830
  }
62506
62831
 
62507
- :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 {
62508
62835
  font-weight: 500;
62509
62836
  }
62510
62837
 
62511
- :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 {
62512
62841
  font-weight: 500;
62513
62842
  }
62514
62843
 
62515
- :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 {
62516
62847
  color: rgb(var(--tb-error, 239 68 68));
62517
62848
  opacity: 1;
62518
62849
  }
@@ -62522,20 +62853,24 @@ const containerResponsiveThemeCss = `/*
62522
62853
  * Time-grid layout for recurring class schedules
62523
62854
  * ----------------------------------------------------------------------------- */
62524
62855
 
62525
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable {
62856
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-timetable {
62526
62857
  display: flex;
62527
62858
  flex-direction: column;
62528
62859
  gap: 0.75rem;
62529
62860
  }
62530
62861
 
62531
- :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 {
62532
62865
  display: none;
62533
62866
  gap: 0.375rem;
62534
62867
  overflow-x: auto;
62535
62868
  padding-bottom: 0.125rem;
62536
62869
  }
62537
62870
 
62538
- :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 {
62539
62874
  flex: 0 0 auto;
62540
62875
  padding: 0.5rem 0.75rem;
62541
62876
  border: 1px solid var(--ec-border);
@@ -62550,35 +62885,49 @@ const containerResponsiveThemeCss = `/*
62550
62885
  border-color var(--rb-block-transition) ease;
62551
62886
  }
62552
62887
 
62553
- :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 {
62554
62891
  background-color: rgb(var(--tb-primary));
62555
62892
  border-color: rgb(var(--tb-primary));
62556
62893
  color: rgb(var(--tb-primaryText, 255 255 255));
62557
62894
  }
62558
62895
 
62559
- :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 {
62560
62899
  border: 1px solid var(--ec-border);
62561
62900
  border-radius: var(--rb-block-radius);
62562
62901
  overflow-x: auto;
62563
62902
  overflow-y: hidden;
62564
62903
  }
62565
62904
 
62566
- :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 {
62567
62908
  display: grid;
62568
62909
  grid-template-columns: 4.5rem repeat(7, minmax(8rem, 1fr));
62569
62910
  min-width: 62rem;
62570
62911
  }
62571
62912
 
62572
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-time-rail,
62573
- :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 {
62574
62919
  border-right: 1px solid var(--ec-border-subtle);
62575
62920
  }
62576
62921
 
62577
- :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 {
62578
62925
  border-right: none;
62579
62926
  }
62580
62927
 
62581
- :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 {
62582
62931
  min-height: 3.25rem;
62583
62932
  margin: 0;
62584
62933
  padding: 0.75rem 0.5rem;
@@ -62593,12 +62942,17 @@ const containerResponsiveThemeCss = `/*
62593
62942
  font-weight: 600;
62594
62943
  }
62595
62944
 
62596
- :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 {
62597
62949
  background-color: var(--ec-today-bg);
62598
62950
  color: var(--ec-today-text);
62599
62951
  }
62600
62952
 
62601
- :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 {
62602
62956
  padding: 0.125rem 0.375rem;
62603
62957
  border-radius: var(--rb-button-radius);
62604
62958
  background-color: rgb(var(--tb-primary));
@@ -62608,17 +62962,29 @@ const containerResponsiveThemeCss = `/*
62608
62962
  text-transform: uppercase;
62609
62963
  }
62610
62964
 
62611
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-time-body,
62612
- :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 {
62613
62971
  position: relative;
62614
- 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
+ );
62615
62977
  }
62616
62978
 
62617
- :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 {
62618
62982
  background-color: var(--ec-header-bg);
62619
62983
  }
62620
62984
 
62621
- :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 {
62622
62988
  position: absolute;
62623
62989
  left: 0.625rem;
62624
62990
  transform: translateY(-50%);
@@ -62627,14 +62993,18 @@ const containerResponsiveThemeCss = `/*
62627
62993
  white-space: nowrap;
62628
62994
  }
62629
62995
 
62630
- :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 {
62631
62999
  position: absolute;
62632
63000
  left: 0;
62633
63001
  right: 0;
62634
63002
  border-top: 1px solid var(--ec-border-subtle);
62635
63003
  }
62636
63004
 
62637
- :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 {
62638
63008
  position: absolute;
62639
63009
  min-height: 2.75rem;
62640
63010
  padding: 0.375rem 0.5rem;
@@ -62654,21 +63024,35 @@ const containerResponsiveThemeCss = `/*
62654
63024
  transform var(--rb-block-transition) ease;
62655
63025
  }
62656
63026
 
62657
- :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 {
62658
63030
  box-shadow: 0 4px 12px rgba(var(--tb-text), 0.12);
62659
63031
  transform: translateY(-1px);
62660
63032
  }
62661
63033
 
62662
- :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 {
62663
63037
  outline: 2px solid rgb(var(--tb-primary));
62664
63038
  outline-offset: 2px;
62665
63039
  }
62666
63040
 
62667
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event-time,
62668
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event-title,
62669
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event-teacher,
62670
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event-meta,
62671
- :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 {
62672
63056
  display: block;
62673
63057
  min-width: 0;
62674
63058
  overflow: hidden;
@@ -62676,36 +63060,50 @@ const containerResponsiveThemeCss = `/*
62676
63060
  white-space: nowrap;
62677
63061
  }
62678
63062
 
62679
- :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 {
62680
63066
  font-size: 0.6875rem;
62681
63067
  font-weight: 700;
62682
63068
  opacity: var(--ec-time-opacity);
62683
63069
  }
62684
63070
 
62685
- :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 {
62686
63074
  font-size: 0.8125rem;
62687
63075
  font-weight: 700;
62688
63076
  line-height: 1.25;
62689
63077
  }
62690
63078
 
62691
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event-teacher,
62692
- :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 {
62693
63085
  font-size: 0.6875rem;
62694
63086
  opacity: 0.72;
62695
63087
  }
62696
63088
 
62697
- :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 {
62698
63092
  font-size: 0.6875rem;
62699
63093
  font-weight: 600;
62700
63094
  opacity: 0.85;
62701
63095
  }
62702
63096
 
62703
- :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 {
62704
63100
  color: rgb(var(--tb-danger, 220 38 38));
62705
63101
  opacity: 1;
62706
63102
  }
62707
63103
 
62708
- :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 {
62709
63107
  margin: 0;
62710
63108
  padding: 1rem 0.5rem;
62711
63109
  text-align: center;
@@ -62713,7 +63111,9 @@ const containerResponsiveThemeCss = `/*
62713
63111
  opacity: var(--ec-empty-opacity);
62714
63112
  }
62715
63113
 
62716
- :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 {
62717
63117
  margin: 0.25rem 0 0;
62718
63118
  text-align: center;
62719
63119
  font-size: 0.875rem;
@@ -62722,32 +63122,46 @@ const containerResponsiveThemeCss = `/*
62722
63122
 
62723
63123
  @container rb-site (max-width: 767px) {
62724
63124
  @scope ([data-rb-responsive-mode="container"]) to (:scope [data-rb-responsive-mode]) {
62725
- :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 {
62726
63128
  display: flex;
62727
63129
  }
62728
63130
 
62729
- :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 {
62730
63134
  overflow: hidden;
62731
63135
  }
62732
63136
 
62733
- :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 {
62734
63140
  grid-template-columns: 4rem minmax(0, 1fr);
62735
63141
  min-width: 0;
62736
63142
  }
62737
63143
 
62738
- :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'] {
62739
63147
  display: none;
62740
63148
  }
62741
63149
 
62742
- :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 {
62743
63153
  border-right: none;
62744
63154
  }
62745
63155
 
62746
- :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 {
62747
63159
  border-right: 1px solid var(--ec-border-subtle);
62748
63160
  }
62749
63161
 
62750
- :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 {
62751
63165
  justify-content: flex-start;
62752
63166
  padding-inline: 0.75rem;
62753
63167
  }
@@ -62760,7 +63174,7 @@ const containerResponsiveThemeCss = `/*
62760
63174
  * three-state availability (available / filling / waitlist), and a footer CTA.
62761
63175
  * ----------------------------------------------------------------------------- */
62762
63176
 
62763
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board {
63177
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-week-board {
62764
63178
  /* Status accent tokens — map the three availability states onto theme colours.
62765
63179
  * available -> secondary, filling -> accent, waitlist -> muted text. */
62766
63180
  --ec-status-available: rgb(var(--tb-secondary));
@@ -62777,17 +63191,20 @@ const containerResponsiveThemeCss = `/*
62777
63191
 
62778
63192
  /* Opt-in raised look: a soft drop shadow so the board lifts off the page.
62779
63193
  * Generic default (no [data-elevated]) stays flat. */
62780
- :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] {
62781
63197
  box-shadow: 0 14px 34px -24px rgba(var(--tb-text), 0.35);
62782
63198
  }
62783
63199
 
62784
- /* Top bar: title + legend */
62785
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-top {
62786
- 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);
62787
63206
  align-items: center;
62788
- justify-content: space-between;
62789
63207
  gap: 1rem;
62790
- flex-wrap: wrap;
62791
63208
  padding: 1.1rem 1.5rem;
62792
63209
  /* surfaceAlt gives the header/footer a legible tint against the white day-grid
62793
63210
  * body — the faint \`--ec-header-bg\` (5% text) is invisible on light palettes. */
@@ -62795,7 +63212,10 @@ const containerResponsiveThemeCss = `/*
62795
63212
  border-bottom: 1px solid var(--ec-border-subtle);
62796
63213
  }
62797
63214
 
62798
- :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;
62799
63219
  font-size: 0.8125rem;
62800
63220
  font-weight: 600;
62801
63221
  letter-spacing: 0.12em;
@@ -62803,7 +63223,67 @@ const containerResponsiveThemeCss = `/*
62803
63223
  color: rgb(var(--tb-primary));
62804
63224
  }
62805
63225
 
62806
- :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;
62807
63287
  display: flex;
62808
63288
  align-items: center;
62809
63289
  gap: 1.1rem;
@@ -62813,38 +63293,72 @@ const containerResponsiveThemeCss = `/*
62813
63293
  opacity: 0.75;
62814
63294
  }
62815
63295
 
62816
- :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 {
62817
63319
  display: inline-flex;
62818
63320
  align-items: center;
62819
63321
  gap: 0.4rem;
62820
63322
  }
62821
63323
 
62822
- :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 {
62823
63327
  width: 0.55rem;
62824
63328
  height: 0.55rem;
62825
63329
  border-radius: 50%;
62826
63330
  display: inline-block;
62827
63331
  }
62828
63332
 
62829
- :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'] {
62830
63336
  background-color: var(--ec-status-available);
62831
63337
  }
62832
63338
 
62833
- :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'] {
62834
63342
  background-color: var(--ec-status-filling);
62835
63343
  }
62836
63344
 
62837
- :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'] {
62838
63348
  background-color: var(--ec-status-waitlist);
62839
63349
  }
62840
63350
 
62841
63351
  /* Day columns grid */
62842
- :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 {
62843
63355
  display: grid;
62844
63356
  grid-template-columns: repeat(var(--event-week-board-cols), minmax(0, 1fr));
62845
63357
  }
62846
63358
 
62847
- :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 {
62848
63362
  display: flex;
62849
63363
  flex-direction: column;
62850
63364
  min-height: 15rem;
@@ -62854,11 +63368,15 @@ const containerResponsiveThemeCss = `/*
62854
63368
  border-right: var(--rb-border-width, 1px) solid rgb(var(--tb-border));
62855
63369
  }
62856
63370
 
62857
- :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 {
62858
63374
  border-right: none;
62859
63375
  }
62860
63376
 
62861
- :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 {
62862
63380
  display: flex;
62863
63381
  align-items: baseline;
62864
63382
  gap: 0.4rem;
@@ -62867,11 +63385,16 @@ const containerResponsiveThemeCss = `/*
62867
63385
  border-bottom: var(--rb-border-width, 1px) solid rgb(var(--tb-border));
62868
63386
  }
62869
63387
 
62870
- :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 {
62871
63392
  background-color: var(--ec-today-bg);
62872
63393
  }
62873
63394
 
62874
- :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 {
62875
63398
  font-size: 0.6875rem;
62876
63399
  font-weight: 600;
62877
63400
  letter-spacing: 0.1em;
@@ -62879,18 +63402,25 @@ const containerResponsiveThemeCss = `/*
62879
63402
  opacity: 0.65;
62880
63403
  }
62881
63404
 
62882
- :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 {
62883
63409
  opacity: 1;
62884
63410
  color: var(--ec-today-text);
62885
63411
  }
62886
63412
 
62887
- :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 {
62888
63416
  font-size: 0.8125rem;
62889
63417
  font-weight: 600;
62890
63418
  opacity: 0.5;
62891
63419
  }
62892
63420
 
62893
- :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 {
62894
63424
  display: flex;
62895
63425
  flex-direction: column;
62896
63426
  gap: 0.65rem;
@@ -62899,7 +63429,9 @@ const containerResponsiveThemeCss = `/*
62899
63429
  }
62900
63430
 
62901
63431
  /* Class card */
62902
- :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 {
62903
63435
  display: flex;
62904
63436
  flex-direction: column;
62905
63437
  gap: 0.45rem;
@@ -62919,40 +63451,54 @@ const containerResponsiveThemeCss = `/*
62919
63451
  border-color var(--rb-block-transition) ease;
62920
63452
  }
62921
63453
 
62922
- :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'] {
62923
63457
  border-left-color: var(--ec-status-filling);
62924
63458
  }
62925
63459
 
62926
- :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'] {
62927
63463
  border-left-color: var(--ec-status-waitlist);
62928
63464
  }
62929
63465
 
62930
- :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 {
62931
63469
  transform: translateY(-2px);
62932
63470
  box-shadow: 0 6px 16px -8px rgba(var(--tb-text), 0.28);
62933
63471
  border-color: rgba(var(--tb-primary), 0.4);
62934
63472
  }
62935
63473
 
62936
- :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 {
62937
63477
  outline: 2px solid rgb(var(--tb-primary));
62938
63478
  outline-offset: 2px;
62939
63479
  }
62940
63480
 
62941
- :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 {
62942
63484
  font-family: var(--font-heading, inherit);
62943
63485
  font-size: 0.9375rem;
62944
63486
  font-weight: 600;
62945
63487
  line-height: 1.2;
62946
63488
  }
62947
63489
 
62948
- :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 {
62949
63493
  font-size: 0.75rem;
62950
63494
  letter-spacing: 0.01em;
62951
63495
  opacity: 0.7;
62952
63496
  }
62953
63497
 
62954
63498
  /* Capacity pill */
62955
- :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 {
62956
63502
  align-self: flex-start;
62957
63503
  display: inline-flex;
62958
63504
  align-items: center;
@@ -62970,20 +63516,26 @@ const containerResponsiveThemeCss = `/*
62970
63516
  border-color: var(--ec-border);
62971
63517
  }
62972
63518
 
62973
- :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'] {
62974
63522
  background-color: rgba(var(--tb-accent), 0.14);
62975
63523
  color: var(--ec-status-filling);
62976
63524
  border-color: rgba(var(--tb-accent), 0.32);
62977
63525
  }
62978
63526
 
62979
- :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'] {
62980
63530
  background-color: transparent;
62981
63531
  color: rgba(var(--tb-text), 0.6);
62982
63532
  border-color: var(--ec-border);
62983
63533
  }
62984
63534
 
62985
63535
  /* Footer */
62986
- :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 {
62987
63539
  display: flex;
62988
63540
  align-items: center;
62989
63541
  justify-content: space-between;
@@ -62995,7 +63547,9 @@ const containerResponsiveThemeCss = `/*
62995
63547
  border-top: 1px solid var(--ec-border-subtle);
62996
63548
  }
62997
63549
 
62998
- :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 {
62999
63553
  margin: 0;
63000
63554
  font-size: 0.875rem;
63001
63555
  opacity: 0.75;
@@ -63004,36 +63558,69 @@ const containerResponsiveThemeCss = `/*
63004
63558
  /* Responsive: collapse day columns to a stacked list on narrow viewports */
63005
63559
  @container rb-site (max-width: 1023px) {
63006
63560
  @scope ([data-rb-responsive-mode="container"]) to (:scope [data-rb-responsive-mode]) {
63007
- :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 {
63008
63583
  grid-template-columns: 1fr;
63009
63584
  }
63010
63585
 
63011
- :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 {
63012
63589
  min-height: 0;
63013
63590
  border-right: none;
63014
63591
  border-bottom: var(--rb-border-width, 1px) solid rgb(var(--tb-border));
63015
63592
  }
63016
63593
 
63017
- :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 {
63018
63597
  border-bottom: none;
63019
63598
  }
63020
63599
 
63021
- :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 {
63022
63603
  display: none;
63023
63604
  }
63024
63605
 
63025
- :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 {
63026
63609
  border-bottom: none;
63027
63610
  padding-bottom: 0.25rem;
63028
63611
  }
63029
63612
 
63030
- :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 {
63031
63616
  flex-direction: row;
63032
63617
  flex-wrap: wrap;
63033
63618
  padding-top: 0.35rem;
63034
63619
  }
63035
63620
 
63036
- :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 {
63037
63624
  flex: 1 1 14rem;
63038
63625
  }
63039
63626
  }
@@ -63041,11 +63628,37 @@ const containerResponsiveThemeCss = `/*
63041
63628
 
63042
63629
  @container rb-site (max-width: 639px) {
63043
63630
  @scope ([data-rb-responsive-mode="container"]) to (:scope [data-rb-responsive-mode]) {
63044
- :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 {
63045
63656
  display: none;
63046
63657
  }
63047
63658
 
63048
- :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 {
63049
63662
  flex: 1 1 100%;
63050
63663
  }
63051
63664
  }
@@ -63062,8 +63675,9 @@ const containerResponsiveThemeCss = `/*
63062
63675
  * Opt-in only: the band paints when the board root carries [data-banded];
63063
63676
  * the generic default is bandless.
63064
63677
  * ----------------------------------------------------------------------------- */
63065
- :where(.theme-scope) [data-slot="section"]:has(.event-calendar--week-board[data-banded])::before {
63066
- content: "";
63678
+ :where(.theme-scope)
63679
+ [data-slot='section']:has(.event-calendar--week-board[data-banded])::before {
63680
+ content: '';
63067
63681
  position: absolute;
63068
63682
  inset: 0;
63069
63683
  z-index: -9;
@@ -63117,7 +63731,7 @@ const containerResponsiveThemeCss = `/*
63117
63731
  * ----------------------------------------------------------------------------- */
63118
63732
 
63119
63733
  /* Modal overlay */
63120
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal-overlay {
63734
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal-overlay {
63121
63735
  position: fixed;
63122
63736
  inset: 0;
63123
63737
  background: var(--ec-modal-overlay-bg);
@@ -63131,12 +63745,16 @@ const containerResponsiveThemeCss = `/*
63131
63745
  }
63132
63746
 
63133
63747
  @keyframes ec-modal-fade-in {
63134
- from { opacity: 0; }
63135
- to { opacity: 1; }
63748
+ from {
63749
+ opacity: 0;
63750
+ }
63751
+ to {
63752
+ opacity: 1;
63753
+ }
63136
63754
  }
63137
63755
 
63138
63756
  /* Modal dialog */
63139
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal {
63757
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal {
63140
63758
  position: relative;
63141
63759
  background: var(--ec-modal-bg);
63142
63760
  border-radius: var(--rb-block-radius);
@@ -63160,17 +63778,17 @@ const containerResponsiveThemeCss = `/*
63160
63778
  }
63161
63779
 
63162
63780
  /* Event modal - constrained width for card */
63163
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal--event {
63781
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal--event {
63164
63782
  max-width: 26rem;
63165
63783
  }
63166
63784
 
63167
63785
  /* Day modal */
63168
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal--day {
63786
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal--day {
63169
63787
  max-width: 28rem;
63170
63788
  }
63171
63789
 
63172
63790
  /* Close button */
63173
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal-close {
63791
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal-close {
63174
63792
  position: absolute;
63175
63793
  top: 0.75rem;
63176
63794
  right: 0.75rem;
@@ -63191,31 +63809,35 @@ const containerResponsiveThemeCss = `/*
63191
63809
  z-index: 10;
63192
63810
  }
63193
63811
 
63194
- :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 {
63195
63815
  opacity: 1;
63196
63816
  background-color: rgba(var(--tb-text), 0.1);
63197
63817
  }
63198
63818
 
63199
- :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 {
63200
63822
  outline: 2px solid rgb(var(--tb-primary));
63201
63823
  outline-offset: 2px;
63202
63824
  }
63203
63825
 
63204
63826
  /* Modal header (for day modal) */
63205
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal-header {
63827
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal-header {
63206
63828
  padding: 1.5rem 1.5rem 1rem;
63207
63829
  padding-right: 3rem; /* Space for close button */
63208
63830
  border-bottom: 1px solid var(--ec-border);
63209
63831
  }
63210
63832
 
63211
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal-title {
63833
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal-title {
63212
63834
  font-size: 1.125rem;
63213
63835
  font-weight: 600;
63214
63836
  color: var(--ec-text);
63215
63837
  margin: 0;
63216
63838
  }
63217
63839
 
63218
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal-subtitle {
63840
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal-subtitle {
63219
63841
  font-size: 0.875rem;
63220
63842
  color: var(--ec-text);
63221
63843
  opacity: 0.7;
@@ -63223,17 +63845,20 @@ const containerResponsiveThemeCss = `/*
63223
63845
  }
63224
63846
 
63225
63847
  /* Modal content */
63226
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal-content {
63848
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal-content {
63227
63849
  padding: 1rem;
63228
63850
  }
63229
63851
 
63230
63852
  /* Event modal: tighter padding for card */
63231
- :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 {
63232
63857
  padding: 0.5rem;
63233
63858
  }
63234
63859
 
63235
63860
  /* Day events list */
63236
- :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 {
63237
63862
  display: flex;
63238
63863
  flex-direction: column;
63239
63864
  gap: 0.5rem;
@@ -63241,7 +63866,9 @@ const containerResponsiveThemeCss = `/*
63241
63866
  }
63242
63867
 
63243
63868
  /* AgendaEventCard in button mode inherits most styles, just needs cursor */
63244
- :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 {
63245
63872
  cursor: pointer;
63246
63873
  text-align: left;
63247
63874
  font-family: inherit;
@@ -63250,7 +63877,9 @@ const containerResponsiveThemeCss = `/*
63250
63877
  /* Responsive adjustments */
63251
63878
  @container rb-site (max-width: 640px) {
63252
63879
  @scope ([data-rb-responsive-mode="container"]) to (:scope [data-rb-responsive-mode]) {
63253
- :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 {
63254
63883
  margin-left: -1.5rem;
63255
63884
  margin-right: -1.5rem;
63256
63885
  border-left: none;
@@ -63258,28 +63887,38 @@ const containerResponsiveThemeCss = `/*
63258
63887
  border-radius: 0;
63259
63888
  }
63260
63889
 
63261
- :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 {
63262
63893
  font-size: 0.75rem;
63263
63894
  padding: 0.375rem 0.125rem;
63264
63895
  }
63265
63896
 
63266
- :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 {
63267
63900
  min-height: 88px;
63268
63901
  padding: 0.125rem;
63269
63902
  }
63270
63903
 
63271
- :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 {
63272
63907
  font-size: 0.9375rem;
63273
63908
  min-width: 0;
63274
63909
  }
63275
63910
 
63276
- :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 {
63277
63914
  font-size: 0.75rem;
63278
63915
  margin-bottom: 0.125rem;
63279
63916
  padding: 0 0.125rem;
63280
63917
  }
63281
63918
 
63282
- :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 {
63283
63922
  justify-content: center;
63284
63923
  gap: 0.25rem;
63285
63924
  padding: 0.1875rem 0.25rem;
@@ -63287,25 +63926,34 @@ const containerResponsiveThemeCss = `/*
63287
63926
  border-radius: calc(var(--rb-block-radius) / 3);
63288
63927
  }
63289
63928
 
63290
- :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 {
63291
63932
  text-align: center;
63292
63933
  font-size: 0.625rem;
63293
63934
  }
63294
63935
 
63295
- :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 {
63296
63939
  display: none;
63297
63940
  }
63298
63941
 
63299
- :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 {
63300
63945
  padding: 0.125rem 0.25rem;
63301
63946
  font-size: 0.6875rem;
63302
63947
  }
63303
63948
 
63304
- :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 {
63305
63953
  margin-right: 0.25rem;
63306
63954
  }
63307
63955
 
63308
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal {
63956
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal {
63309
63957
  max-width: 100%;
63310
63958
  max-height: 85vh;
63311
63959
  margin: 0 0.5rem;
@@ -68075,16 +68723,21 @@ function toBlocksPageRendererDataContext(dataContext) {
68075
68723
  imageResolveContext: toBlocksImageResolveContextInput(dataContext.imageResolveContext)
68076
68724
  };
68077
68725
  }
68078
- function PageRenderer(props) {
68079
- const blocksSdkConfig = props.sdkConfig ? { customBlocks: normalizeSdkCustomBlocks(props.sdkConfig.customBlocks) } : props.sdkConfig;
68080
- const { rendering: _rendering, theme: _theme, themeTokens: _themeTokens, ...commonProps } = props;
68081
- const commonBlocksProps = {
68082
- ...commonProps,
68726
+ function toBlocksCommonProps(props) {
68727
+ return {
68728
+ page: props.page,
68729
+ runtimeBoundaries: props.runtimeBoundaries,
68083
68730
  dataContext: props.dataContext ? toBlocksPageRendererDataContext(props.dataContext) : void 0,
68731
+ routeMap: props.routeMap,
68732
+ wrapBlock: props.wrapBlock,
68733
+ registry: props.registry,
68084
68734
  blockOverrides: toBlocksBlockOverrides(props.blockOverrides),
68085
- sdkConfig: blocksSdkConfig,
68735
+ sdkConfig: props.sdkConfig ? { customBlocks: normalizeSdkCustomBlocks(props.sdkConfig.customBlocks) } : props.sdkConfig,
68086
68736
  customBlocks: normalizeSdkCustomBlocks(props.customBlocks)
68087
68737
  };
68738
+ }
68739
+ function PageRenderer(props) {
68740
+ const commonBlocksProps = toBlocksCommonProps(props);
68088
68741
  const blocksProps = isOverrideOnlyPageRenderer(props) ? {
68089
68742
  ...commonBlocksProps,
68090
68743
  rendering: { kind: "overrides-only" },
@@ -68160,12 +68813,14 @@ function resolvePageThemeTokens(props) {
68160
68813
  }
68161
68814
  } : baseTokens;
68162
68815
  }
68816
+ function resolveSdkBookingTimeZone(timeZone) {
68817
+ return timeZone ?? "UTC";
68818
+ }
68163
68819
  function PageContent(props) {
68164
- 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;
68165
68821
  const rendererCommonProps = {
68166
68822
  page,
68167
68823
  runtimeBoundaries,
68168
- usePlaceholders,
68169
68824
  dataContext: {
68170
68825
  siteId,
68171
68826
  apiBaseUrl,
@@ -68173,6 +68828,7 @@ function PageContent(props) {
68173
68828
  previewToken,
68174
68829
  resolvedData,
68175
68830
  bookingOfferingPresets: bookingOfferingPresets ?? [],
68831
+ bookingTimeZone: resolveSdkBookingTimeZone(bookingTimeZone),
68176
68832
  routes: routeMap,
68177
68833
  pagesByIdentifier,
68178
68834
  entriesByIdentifier,
@@ -68712,233 +69368,6 @@ function requireSdkTheme(theme, siteId, reason = "cms_theme_absent") {
68712
69368
  //#region src/rendering/renderingMode.ts
68713
69369
  const defaultOverrideOnlyRuntime = { kind: "responsive-only" };
68714
69370
  //#endregion
68715
- //#region src/rendering/components/Layout.tsx
68716
- /**
68717
- * Layout component with header and footer
68718
- *
68719
- * Renders site header and footer around content. Fetches site data if not provided.
68720
- */
68721
- function isOverrideOnlyLayout(props) {
68722
- return props.rendering?.kind === "overrides-only";
68723
- }
68724
- var UnsupportedOverrideOnlyLayoutChromeError = class extends Error {
68725
- constructor(surface) {
68726
- super(`Override-only Layout requires a custom or disabled ${surface}; SDK default chrome is unavailable.`);
68727
- this.surface = surface;
68728
- this.code = "unsupported_override_only_layout_chrome";
68729
- this.name = "UnsupportedOverrideOnlyLayoutChromeError";
68730
- }
68731
- };
68732
- async function resolveLayoutSiteData(props) {
68733
- if (props.siteData) return props.siteData;
68734
- if (!props.client) throw new Error("Layout: must provide either siteData or client");
68735
- if (!props.siteId && !props.slug && !props.domain) throw new Error("Layout: must provide siteId, slug, or domain when using client");
68736
- return props.client.getSite({
68737
- id: props.siteId,
68738
- slug: props.slug,
68739
- domain: props.domain
68740
- });
68741
- }
68742
- function renderOverrideOnlyLayout(props, data) {
68743
- if (data.header === true) throw new UnsupportedOverrideOnlyLayoutChromeError("header");
68744
- if (data.footer === true) throw new UnsupportedOverrideOnlyLayoutChromeError("footer");
68745
- return renderWithOverrideOnlyRuntime({
68746
- runtime: props.rendering.runtime ?? defaultOverrideOnlyRuntime,
68747
- children: /* @__PURE__ */ jsxs(Fragment, { children: [
68748
- typeof props.header === "function" ? props.header(data.headerData) : null,
68749
- props.children,
68750
- typeof props.footer === "function" ? props.footer(data.footerData) : null
68751
- ] })
68752
- });
68753
- }
68754
- /**
68755
- * Layout component that wraps content with site header and footer.
68756
- *
68757
- * This is a server/RSC-safe component. The default `@riverbankcms/sdk/rendering`
68758
- * `Page` and `Block` surfaces mount CMS island hydration automatically, while
68759
- * the strict `@riverbankcms/sdk/rendering/server` surface stays bootstrap-free.
68760
- * If a custom host renders hydratable CMS islands through the strict server
68761
- * surface, mount `BlocksIslandsHydrator` from
68762
- * `@riverbankcms/sdk/rendering/islands` explicitly.
68763
- *
68764
- * @example With pre-fetched site data (recommended)
68765
- * ```tsx
68766
- * import { Layout } from '@riverbankcms/sdk/rendering/server';
68767
- * import { Page } from '@riverbankcms/sdk/rendering';
68768
- *
68769
- * const site = await client.getSite({ slug: 'my-site' });
68770
- *
68771
- * <Layout siteData={site}>
68772
- * <Page {...pageData} />
68773
- * </Layout>
68774
- * ```
68775
- *
68776
- * @example With strict server rendering
68777
- * ```tsx
68778
- * import { Layout, Page } from '@riverbankcms/sdk/rendering/server';
68779
- * import { BlocksIslandsHydrator } from '@riverbankcms/sdk/rendering/islands';
68780
- *
68781
- * const site = await client.getSite({ slug: 'my-site' });
68782
- *
68783
- * <Layout siteData={site}>
68784
- * <BlocksIslandsHydrator siteId={site.site.id} supabaseUrl={site.supabaseUrl} />
68785
- * <Page {...pageData} />
68786
- * </Layout>
68787
- * ```
68788
- */
68789
- async function Layout(props) {
68790
- const { children, hasPortalSession = false, previewStage = "published" } = props;
68791
- const header = props.header ?? true;
68792
- const footer = props.footer ?? true;
68793
- const siteData = await resolveLayoutSiteData(props);
68794
- const { site, navigation, layout, routes } = siteData;
68795
- const footerBlocks = siteData.footerBlocks ?? [];
68796
- const navigationOptions = {
68797
- hasPortalSession,
68798
- previewStage,
68799
- pagesByIdentifier: siteData.pagesByIdentifier,
68800
- entriesByIdentifier: siteData.entriesByIdentifier,
68801
- portalEnabled: siteData.portalEnabled ?? false,
68802
- commerceEnabled: siteData.commerceEnabled ?? false,
68803
- checkoutHref: "/checkout"
68804
- };
68805
- const menuViewModel = buildMenu(navigation, routes, navigationOptions);
68806
- const footerMenuViewModel = buildFooterMenu(navigation, routes, navigationOptions);
68807
- const legalFooterMenuViewModel = buildFooterMenuForRole(navigation, routes, "legal-policy", navigationOptions);
68808
- const logoViewModel = buildLogo(layout.logo ?? null, site.title);
68809
- const customHeaderData = {
68810
- menu: menuViewModel,
68811
- logo: logoViewModel,
68812
- site,
68813
- routes
68814
- };
68815
- const customFooterData = {
68816
- menu: menuViewModel,
68817
- footerMenu: footerMenuViewModel,
68818
- legalFooterMenu: legalFooterMenuViewModel,
68819
- logo: logoViewModel,
68820
- site,
68821
- routes
68822
- };
68823
- if (isOverrideOnlyLayout(props)) return renderOverrideOnlyLayout(props, {
68824
- header: props.header ?? true,
68825
- footer: props.footer ?? true,
68826
- headerData: customHeaderData,
68827
- footerData: customFooterData
68828
- });
68829
- const theme = requireSdkTheme(siteData.theme, site.id);
68830
- const builtThemeRuntime = buildThemeRuntime(theme);
68831
- const headerVariant = props.headerVariant;
68832
- const themeRuntime = props.themeRuntime;
68833
- const headerData = {
68834
- ...customHeaderData,
68835
- theme
68836
- };
68837
- const footerData = {
68838
- ...customFooterData,
68839
- theme
68840
- };
68841
- const headerContent = headerVariant ? {
68842
- ...layout.header,
68843
- variant: headerVariant
68844
- } : layout.header;
68845
- const themeWithVariant = headerVariant ? {
68846
- ...theme,
68847
- header: {
68848
- ...theme.header,
68849
- variant: headerVariant
68850
- }
68851
- } : theme;
68852
- const blocksThemeWithVariant = themeWithVariant;
68853
- const blocksTheme = theme;
68854
- let apiBaseUrl;
68855
- try {
68856
- apiBaseUrl = getRiverbankEnv().baseUrl;
68857
- } catch {}
68858
- const sharedViewModelOverrides = {
68859
- $root: {
68860
- siteId: site.id,
68861
- apiBaseUrl,
68862
- previewStage,
68863
- routes,
68864
- pagesByIdentifier: siteData.pagesByIdentifier,
68865
- entriesByIdentifier: siteData.entriesByIdentifier,
68866
- theme: themeWithVariant
68867
- },
68868
- site,
68869
- menu: menuViewModel,
68870
- footerMenu: footerMenuViewModel,
68871
- legalFooterMenu: legalFooterMenuViewModel
68872
- };
68873
- const headerViewModelOverrides = {
68874
- ...sharedViewModelOverrides,
68875
- content: { logo: logoViewModel }
68876
- };
68877
- const footerViewModelOverrides = {
68878
- ...sharedViewModelOverrides,
68879
- content: {
68880
- ...layout.footer,
68881
- logo: logoViewModel
68882
- }
68883
- };
68884
- let headerElement = null;
68885
- if (header === true) headerElement = renderBlock(siteHeaderManifest, headerContent, {
68886
- theme: builtThemeRuntime.tokens,
68887
- themeConfig: blocksThemeWithVariant,
68888
- viewModelOverrides: headerViewModelOverrides
68889
- });
68890
- else if (typeof header === "function") headerElement = header(headerData);
68891
- let footerElement = null;
68892
- if (footer === true) {
68893
- const footerPlan = resolveFooterRenderPlan({
68894
- isSdkSite: Boolean(site.is_sdk_site),
68895
- mode: theme.footer?.mode
68896
- });
68897
- const footerBlocksElement = footerPlan.renderFooterBlocks && footerBlocks.length > 0 ? /* @__PURE__ */ jsx(PageRenderer, {
68898
- theme,
68899
- page: {
68900
- name: "Footer",
68901
- path: "/__footer",
68902
- purpose: "footer",
68903
- blocks: footerBlocks
68904
- },
68905
- routeMap: routes,
68906
- dataContext: {
68907
- previewStage,
68908
- siteId: site.id,
68909
- apiBaseUrl,
68910
- routes,
68911
- pagesByIdentifier: siteData.pagesByIdentifier,
68912
- entriesByIdentifier: siteData.entriesByIdentifier
68913
- },
68914
- sdkConfig: siteData.sdkConfig ?? null
68915
- }) : null;
68916
- if (footerPlan.renderFooterBlocks && !footerBlocksElement && process.env.NODE_ENV !== "production") console.debug("[sdk] Footer mode renders blocks, but footerBlocks is empty/missing", {
68917
- siteId: site.id,
68918
- mode: footerPlan.mode
68919
- });
68920
- const defaultFooterElement = footerPlan.renderDefaultFooter ? renderBlock(siteFooterManifest, layout.footer, {
68921
- theme: builtThemeRuntime.tokens,
68922
- themeConfig: blocksTheme,
68923
- viewModelOverrides: footerViewModelOverrides
68924
- }) : null;
68925
- footerElement = footerPlan.mode === "default+blocks" ? /* @__PURE__ */ jsxs(Fragment, { children: [footerBlocksElement, defaultFooterElement] }) : footerPlan.mode === "blocks" ? footerBlocksElement : footerPlan.mode === "none" ? null : defaultFooterElement;
68926
- } else if (typeof footer === "function") footerElement = footer(footerData);
68927
- const content = /* @__PURE__ */ jsxs(Fragment, { children: [
68928
- headerElement,
68929
- children,
68930
- footerElement
68931
- ] });
68932
- return renderWithSdkThemeRuntime({
68933
- theme,
68934
- themeRuntime: planLayoutThemeRuntime({
68935
- themeRuntime,
68936
- usesSdkChrome: header === true || footer === true
68937
- }),
68938
- children: content
68939
- });
68940
- }
68941
- //#endregion
68942
69371
  //#region ../blocks/src/system/runtime/bindings.ts
68943
69372
  const shouldLogWarnings = isNonProductionEnv();
68944
69373
  function isPlainObject(value) {
@@ -69315,6 +69744,348 @@ function normalizeLoaderParams(endpoint, params, context) {
69315
69744
  ensureSiteId(out, context);
69316
69745
  return out;
69317
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
+ }
69318
70089
  function blockedDemoMutationPolicy(classification, publicMessage) {
69319
70090
  if (publicMessage.trim() === "") throw new Error(`Demo mutation policy ${classification} requires publicMessage.`);
69320
70091
  return {
@@ -70513,6 +71284,13 @@ const PUBLIC_WHOLE_SERIES_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
70513
71284
  //#endregion
70514
71285
  //#region ../api/src/publicEventEndpointDefinitions.ts
70515
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
+ },
70516
71294
  getPublicEventRegistrationOptions: {
70517
71295
  path: "/public/sites/{siteId}/events/registration-options",
70518
71296
  method: "POST",