@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
@@ -8479,12 +8479,8 @@ const legacyHeaderVariantValues = Object.keys(legacyHeaderVariants);
8479
8479
  * `@riverbankcms/api` is `z.input<typeof themeSchema>`, so a widened input here
8480
8480
  * would leak straight into a public type.
8481
8481
  *
8482
- * Not every read of a persisted theme goes through the schema:
8483
- * `resolveRuntimeTheme` in
8484
- * `apps/dashboard/src/server/services/sites/runtimeSiteResponse.ts` returns the
8485
- * raw database JSON asserted as `Theme` with no parse, so a theme still
8486
- * carrying a legacy spelling reaches the theme editor un-aliased. That gap
8487
- * predates this alias and is harmless while persisted usage is zero.
8482
+ * Persisted runtime themes are admitted through `parseThemeForPersistence`
8483
+ * before reaching consumers, so legacy spellings normalize at that boundary.
8488
8484
  */
8489
8485
  const headerVariantWithLegacyAliasSchema = z$1.enum([...headerVariantValues, ...legacyHeaderVariantValues]).transform((value) => value in legacyHeaderVariants ? legacyHeaderVariants[value] : value);
8490
8486
  const BREAKPOINT_LG = 1024;
@@ -9075,7 +9071,6 @@ const navFontWeight = z$1.enum([
9075
9071
  "bold"
9076
9072
  ]);
9077
9073
  const headerMaxWidth = z$1.enum(["container", "full"]);
9078
- const headerBarFrame = z$1.enum(["full-bleed", "inset-shell"]);
9079
9074
  const headerBorderSchema = componentBorderSchema.extend({ position: z$1.enum([
9080
9075
  "bottom",
9081
9076
  "top",
@@ -9104,12 +9099,6 @@ const headerLogoTextSchema = z$1.object({
9104
9099
  ]).optional(),
9105
9100
  hideOnShrink: z$1.boolean().optional()
9106
9101
  }).optional();
9107
- const navEffectsSchema = z$1.object({
9108
- underlineGradient: z$1.boolean().default(false),
9109
- glow: z$1.boolean().default(false),
9110
- glowColor: z$1.string().optional(),
9111
- neumorphic: z$1.boolean().default(false)
9112
- }).optional();
9113
9102
  const dropdownStyleSchema = z$1.object({
9114
9103
  background: themeColorTokenSchema.default("surface"),
9115
9104
  textColor: themeColorTokenSchema.default("text"),
@@ -9201,9 +9190,7 @@ const headerSchema = z$1.object({
9201
9190
  positioning: headerPositioning,
9202
9191
  shrinkOnScroll: z$1.boolean(),
9203
9192
  maxWidth: headerMaxWidth,
9204
- barFrame: headerBarFrame.optional(),
9205
9193
  scrollTreatment: headerScrollTreatmentSchema,
9206
- logoOverride: mediaSchema.nullable().optional(),
9207
9194
  background: headerBackgroundSchema.default({
9208
9195
  type: "color",
9209
9196
  color: "surface"
@@ -9215,13 +9202,11 @@ const headerSchema = z$1.object({
9215
9202
  navFontRole: z$1.enum(["body", "heading"]).optional(),
9216
9203
  navTextSize: navLinkStyleSchema.shape.textSize,
9217
9204
  interactionPalette: headerInteractionPaletteSchema.optional(),
9218
- navPlacement: z$1.enum(["end", "center"]).optional(),
9219
9205
  container: headerContainerSchema,
9220
9206
  border: headerBorderSchema,
9221
9207
  shadow: componentShadowSchema.optional(),
9222
9208
  logo: logoStyleSchema,
9223
9209
  logoText: headerLogoTextSchema,
9224
- navEffects: navEffectsSchema,
9225
9210
  navContainer: navContainerSchema,
9226
9211
  navLinkStyle: navLinkStyleSchema.optional(),
9227
9212
  ctaGap: headerCtaGapSchema.optional(),
@@ -11234,7 +11219,6 @@ const ALLOWED_TRANSFORM_IDS = [
11234
11219
  "layout.footerRootClass",
11235
11220
  "layout.headerRootStyle",
11236
11221
  "layout.headerSectionBackground",
11237
- "layout.classicNavMode",
11238
11222
  "layout.footerRootStyle",
11239
11223
  "ui.headerNavLinkClass",
11240
11224
  "ui.headingClassFromAlignment",
@@ -13722,6 +13706,15 @@ function normalizeStoredContentValues(plans, content, options = {}) {
13722
13706
  normalizeInlineTextFallbacks(plans, normalized, ctx);
13723
13707
  return normalized;
13724
13708
  }
13709
+ /**
13710
+ * Produces the portable representation accepted by content persistence.
13711
+ * Runtime-hydrated media fields are stripped only when a canonical identifier
13712
+ * is already present; unresolved environment-specific references remain
13713
+ * invalid and must be handled by the site-scoped media write normalizer first.
13714
+ */
13715
+ function normalizeManifestContentForWrite(plans, content, options = {}) {
13716
+ return canonicalizeObjectForWrite(plans, normalizeStoredContentValues(plans, content, options));
13717
+ }
13725
13718
  function normalizeStoredFieldValueWithContext(plan, value, ctx) {
13726
13719
  if (value === null && !plan.required) return;
13727
13720
  switch (plan.kind) {
@@ -13756,10 +13749,6 @@ function normalizeStoredRepeaterItems(plan, value, ctx) {
13756
13749
  return normalizeStoredObjectChildren(fields, itemRecord, ctx);
13757
13750
  });
13758
13751
  }
13759
- function validateFieldValue(plan, value, options = {}) {
13760
- const ctx = strictValidationContext(options);
13761
- return validateNormalizedFieldValue(plan, normalizeFieldValue(plan, value, ctx), ctx);
13762
- }
13763
13752
  function normalizeFieldValue(plan, value, ctx) {
13764
13753
  switch (plan.kind) {
13765
13754
  case "number": return normalizeNumberInput(value, ctx.allowNull);
@@ -14059,6 +14048,14 @@ function fieldPlanToObjectPropertyZod(plan, options = {}) {
14059
14048
  default: return assertNever$15(presence);
14060
14049
  }
14061
14050
  }
14051
+ /** Validate stored field values without applying editor/write normalization. */
14052
+ function fieldPlanToStoredObjectPropertyZod(plan) {
14053
+ const ctx = strictValidationContext({ allowNull: false });
14054
+ const schema = z$1.any().superRefine((value, zodCtx) => {
14055
+ for (const validationIssue of validateNormalizedFieldValue(plan, value, ctx)) addFieldIssueToZodContext(zodCtx, validationIssue, plan.path);
14056
+ });
14057
+ return plan.required ? schema : schema.optional();
14058
+ }
14062
14059
  function addFieldIssueToZodContext(zodCtx, validationIssue, rootPath) {
14063
14060
  const message = fieldIssueToMessage(validationIssue);
14064
14061
  const path = relativeZodIssuePath(validationIssue.path, rootPath);
@@ -14164,36 +14161,6 @@ function findNestedFieldValidationPlan(plan, path) {
14164
14161
  function sameFieldPath(left, right) {
14165
14162
  return left.length === right.length && left.every((segment, index) => segment === right[index]);
14166
14163
  }
14167
- function validateExplicitNullsForPush(plans, content, ctx) {
14168
- if (!isPlainObject$5(content)) return [];
14169
- return plans.flatMap((plan) => validateExplicitNullForPushPlan(plan, content[plan.fieldId], ctx));
14170
- }
14171
- function validateExplicitNullForPushPlan(plan, value, ctx) {
14172
- if (value === null) return !plan.required && !ctx.allowNull && !acceptsOptionalNullValue(plan) ? validateFieldValue(plan, value, { allowNull: false }) : [];
14173
- switch (plan.kind) {
14174
- case "group": return validateExplicitNullsForPush(selectedGroupChildPlans(plan, value), value, childValidationContext(plan, ctx));
14175
- case "repeater": return validateExplicitNullsForPushRepeater(plan, value, ctx);
14176
- case "string":
14177
- case "number":
14178
- case "boolean":
14179
- case "richText":
14180
- case "inlineText":
14181
- case "media":
14182
- case "link":
14183
- case "select":
14184
- case "passthrough": return [];
14185
- default: return assertNever$15(plan);
14186
- }
14187
- }
14188
- function validateExplicitNullsForPushRepeater(plan, value, ctx) {
14189
- if (!isUnknownArray$2(value)) return [];
14190
- return value.flatMap((item, index) => {
14191
- if (!isPlainObject$5(item)) return [];
14192
- const childPlans = plan.repeatedItemVariants ? plan.repeatedItemVariants.find((variant) => variant.typeId === item._type)?.fields : plan.repeatedItemPlan;
14193
- if (!childPlans) return [];
14194
- return childPlans.flatMap((childPlan) => validateExplicitNullForPushPlan(materializeRepeaterItemPlan(childPlan, plan.path, index), item[childPlan.fieldId], ctx));
14195
- });
14196
- }
14197
14164
  function compilePattern(pattern) {
14198
14165
  try {
14199
14166
  return new RegExp(pattern);
@@ -14301,6 +14268,7 @@ function registerManifest(manifest) {
14301
14268
  }
14302
14269
  //#endregion
14303
14270
  //#region ../blocks/src/system/manifest/validation.ts
14271
+ const compiledManifestContentContract = Symbol("compiledManifestContentContract");
14304
14272
  /**
14305
14273
  * Preprocess content by converting empty values to undefined.
14306
14274
  * Used in draft mode to allow required fields to be temporarily empty.
@@ -14311,13 +14279,94 @@ function preprocessEmptyValues(content) {
14311
14279
  for (const [key, value] of Object.entries(content)) result[key] = isEmptyValue$1(value) ? void 0 : value;
14312
14280
  return result;
14313
14281
  }
14314
- function createManifestValidator(manifestOrFields, options = {}) {
14315
- return createManifestValidatorWithNormalizer(manifestOrFields, options, normalizeStoredContentValues);
14282
+ /**
14283
+ * Compiles editor-facing manifest structure into the presentation-independent
14284
+ * validation contract used by every manifest-content trust transition.
14285
+ */
14286
+ function compileManifestContentContract(manifestOrFields) {
14287
+ const plans = derivePlansFromManifestOrFields(manifestOrFields);
14288
+ const strictOptions = { allowNull: false };
14289
+ const strictStoredSchema = deriveStrictStoredZodFromPlans(plans);
14290
+ return Object.freeze({ [compiledManifestContentContract]: Object.freeze({
14291
+ plans,
14292
+ strictStoredSchema,
14293
+ writeSchema: deriveNormalizedContentZodFromPlans(plans, strictOptions, normalizeManifestContentForWrite).transform((value) => canonicalizeObjectForWrite(plans, value)),
14294
+ draftSchema: deriveNormalizedContentZodFromPlans(plans, {
14295
+ allowNull: true,
14296
+ allowIncomplete: true,
14297
+ mode: "draft"
14298
+ }, normalizeStoredContentValues),
14299
+ renderSchema: strictStoredSchema,
14300
+ findNonPortableMediaPaths: (content) => findNonPortableMediaPaths(plans, content)
14301
+ }) });
14302
+ }
14303
+ /** Strictly admits already-persisted content without repairing it. */
14304
+ function admitStoredManifestContent(contract, content) {
14305
+ const state = contract[compiledManifestContentContract];
14306
+ const nonPortablePaths = state.findNonPortableMediaPaths(content);
14307
+ if (nonPortablePaths.length > 0) return {
14308
+ ok: false,
14309
+ error: {
14310
+ kind: "non_portable_media",
14311
+ paths: nonPortablePaths
14312
+ }
14313
+ };
14314
+ const parsed = state.strictStoredSchema.safeParse(content);
14315
+ return parsed.success ? {
14316
+ ok: true,
14317
+ value: content
14318
+ } : {
14319
+ ok: false,
14320
+ error: zodAdmissionError(parsed.error)
14321
+ };
14322
+ }
14323
+ /** Validates raw editor state without granting a stored-content proof. */
14324
+ function validateManifestDraft(contract, data) {
14325
+ const parsed = contract[compiledManifestContentContract].draftSchema.safeParse(data);
14326
+ if (parsed.success) return {
14327
+ kind: "previewable",
14328
+ data,
14329
+ issues: []
14330
+ };
14331
+ const [firstIssue, ...remainingIssues] = zodAdmissionIssues(parsed.error);
14332
+ if (!firstIssue) throw new Error("Draft manifest validation failed without an issue");
14333
+ return {
14334
+ kind: "invalid",
14335
+ data,
14336
+ issues: [firstIssue, ...remainingIssues]
14337
+ };
14338
+ }
14339
+ /**
14340
+ * Applies a pure runtime projection to admitted stored content and validates
14341
+ * the resulting render shape before granting the renderable proof.
14342
+ */
14343
+ function deriveRenderableManifestContent(contract, stored, project) {
14344
+ const projected = project(stored);
14345
+ const parsed = contract[compiledManifestContentContract].renderSchema.safeParse(projected);
14346
+ return parsed.success ? {
14347
+ ok: true,
14348
+ value: projected
14349
+ } : {
14350
+ ok: false,
14351
+ error: zodAdmissionError(parsed.error)
14352
+ };
14316
14353
  }
14317
- function createManifestValidatorWithNormalizer(manifestOrFields, options, normalize) {
14318
- return createManifestValidatorFromPlans(derivePlansFromManifestOrFields(manifestOrFields), options, normalize);
14354
+ /**
14355
+ * Re-admits renderable content after a transport boundary has erased its
14356
+ * compile-time proof. Unlike write admission, this never canonicalizes or
14357
+ * grants a stored proof, so hydrated media cannot flow back to persistence.
14358
+ */
14359
+ function admitTransportedRenderableManifestContent(contract, content) {
14360
+ const parsed = contract[compiledManifestContentContract].renderSchema.safeParse(content);
14361
+ return parsed.success ? {
14362
+ ok: true,
14363
+ value: content
14364
+ } : {
14365
+ ok: false,
14366
+ error: zodAdmissionError(parsed.error)
14367
+ };
14319
14368
  }
14320
- function createManifestValidatorFromPlans(plans, options, normalize) {
14369
+ function deriveNormalizedContentZodFromPlans(plans, options, normalize) {
14321
14370
  const isDraft = options.mode === "draft";
14322
14371
  const baseSchema = deriveContentZodFromPlans(plans, options);
14323
14372
  if (isDraft) return z$1.preprocess((content) => preprocessEmptyValues(normalize(plans, content, options)), baseSchema);
@@ -14328,9 +14377,81 @@ function deriveContentZodFromPlans(plans, options) {
14328
14377
  for (const plan of plans) shape[plan.fieldId] = fieldPlanToObjectPropertyZod(plan, options);
14329
14378
  return z$1.object(shape).catchall(z$1.unknown()).passthrough();
14330
14379
  }
14380
+ function deriveStrictStoredZodFromPlans(plans) {
14381
+ const shape = {};
14382
+ for (const plan of plans) shape[plan.fieldId] = fieldPlanToStoredObjectPropertyZod(plan);
14383
+ return z$1.object(shape).catchall(z$1.unknown()).passthrough();
14384
+ }
14331
14385
  function derivePlansFromManifestOrFields(manifestOrFields) {
14332
14386
  return deriveFieldValidationPlans(Array.isArray(manifestOrFields) ? manifestOrFields : manifestOrFields.fields ?? []);
14333
14387
  }
14388
+ function zodAdmissionError(error) {
14389
+ return {
14390
+ kind: "invalid_shape",
14391
+ issues: zodAdmissionIssues(error)
14392
+ };
14393
+ }
14394
+ function zodAdmissionIssues(error) {
14395
+ return error.issues.map((issue) => ({
14396
+ code: issue.code,
14397
+ path: issue.path.map((segment) => typeof segment === "number" ? segment : String(segment)),
14398
+ message: issue.message
14399
+ }));
14400
+ }
14401
+ function findNonPortableMediaPaths(plans, content) {
14402
+ const paths = /* @__PURE__ */ new Set();
14403
+ collectNonPortablePlannedMedia(plans, content, [], paths);
14404
+ return [...paths].sort();
14405
+ }
14406
+ function collectNonPortablePlannedMedia(plans, content, parentPath, paths) {
14407
+ if (!isPlainRecord$1(content)) return;
14408
+ for (const plan of plans) {
14409
+ if (!(plan.fieldId in content)) continue;
14410
+ const value = content[plan.fieldId];
14411
+ const path = [...parentPath, plan.fieldId];
14412
+ switch (plan.kind) {
14413
+ case "media":
14414
+ if (isPlainRecord$1(value) && hasEnvironmentSpecificMediaField(value)) paths.add(formatFieldPath(path));
14415
+ break;
14416
+ case "richText":
14417
+ collectNonPortableRichTextImages(value, path, paths);
14418
+ break;
14419
+ case "group":
14420
+ collectNonPortablePlannedMedia(selectedGroupChildPlans(plan, value), value, path, paths);
14421
+ break;
14422
+ case "repeater":
14423
+ collectNonPortableRepeaterMedia(plan, value, path, paths);
14424
+ break;
14425
+ case "string":
14426
+ case "number":
14427
+ case "boolean":
14428
+ case "inlineText":
14429
+ case "link":
14430
+ case "select":
14431
+ case "passthrough": break;
14432
+ }
14433
+ }
14434
+ }
14435
+ function collectNonPortableRepeaterMedia(plan, value, path, paths) {
14436
+ if (!Array.isArray(value)) return;
14437
+ value.forEach((item, index) => {
14438
+ if (!isPlainRecord$1(item)) return;
14439
+ const childPlans = plan.repeatedItemVariants ? plan.repeatedItemVariants.find((variant) => variant.typeId === item._type)?.fields : plan.repeatedItemPlan;
14440
+ if (childPlans) collectNonPortablePlannedMedia(childPlans, item, [...path, index], paths);
14441
+ });
14442
+ }
14443
+ function collectNonPortableRichTextImages(value, path, paths) {
14444
+ const images = [];
14445
+ walkAndCollectImageAttrs(value, images);
14446
+ const prefix = formatFieldPath(path);
14447
+ for (const reference of images) if (hasEnvironmentSpecificMediaField(reference.attrs)) paths.add(reference.location ? `${prefix}.${reference.location}` : prefix);
14448
+ }
14449
+ function isPlainRecord$1(value) {
14450
+ return typeof value === "object" && value !== null && !Array.isArray(value);
14451
+ }
14452
+ function hasEnvironmentSpecificMediaField(value) {
14453
+ return "assetId" in value || "storageBucket" in value || "storagePath" in value || "src" in value || "mimeType" in value || looksLikeUuid(value.id);
14454
+ }
14334
14455
  //#endregion
14335
14456
  //#region ../blocks/src/system/manifest/variantKey.ts
14336
14457
  /**
@@ -17538,27 +17659,6 @@ function asHeaderStyleId(value) {
17538
17659
  return value;
17539
17660
  }
17540
17661
  //#endregion
17541
- //#region ../theme-core/src/site-styles/headerInteractionPalette.ts
17542
- const clearSplitInteractionPalette = defineLookOptionGroup({
17543
- id: "interaction-palette",
17544
- label: "Hover colour",
17545
- defaultOptionId: "accent",
17546
- options: [
17547
- {
17548
- id: "accent",
17549
- label: "Accent"
17550
- },
17551
- {
17552
- id: "primary",
17553
- label: "Primary"
17554
- },
17555
- {
17556
- id: "secondary",
17557
- label: "Secondary"
17558
- }
17559
- ]
17560
- });
17561
- //#endregion
17562
17662
  //#region ../theme-core/src/site-styles/headerLayoutCatalog.ts
17563
17663
  const titleOnlyLogoAccommodation = {
17564
17664
  pattern: "title-only",
@@ -17718,43 +17818,37 @@ const headerStyleCatalog = defineExactCatalog()([
17718
17818
  id: asHeaderStyleId("minimal"),
17719
17819
  label: "Minimal",
17720
17820
  description: "Quiet surface with simple color-change navigation.",
17721
- supportedLayoutIds: supportedLayouts(["classic", "centered"]),
17722
- navTypography: "plain"
17821
+ supportedLayoutIds: supportedLayouts(["classic", "centered"])
17723
17822
  },
17724
17823
  {
17725
17824
  id: asHeaderStyleId("fine-line"),
17726
17825
  label: "Seamless",
17727
17826
  description: "Borderless surface with underline hover for a quieter page transition.",
17728
- supportedLayoutIds: supportedLayouts(["classic", "centered"]),
17729
- navTypography: "plain"
17827
+ supportedLayoutIds: supportedLayouts(["classic", "centered"])
17730
17828
  },
17731
17829
  {
17732
17830
  id: asHeaderStyleId("soft-bar"),
17733
17831
  label: "Soft Bar",
17734
17832
  description: "Soft tinted surface with gentle pill hover states.",
17735
- supportedLayoutIds: supportedLayouts(["classic", "centered"]),
17736
- navTypography: "plain"
17833
+ supportedLayoutIds: supportedLayouts(["classic", "centered"])
17737
17834
  },
17738
17835
  {
17739
17836
  id: asHeaderStyleId("pill-nav"),
17740
17837
  label: "Pill Nav",
17741
17838
  description: "A calm pill navigation rail over a neutral header.",
17742
- supportedLayoutIds: supportedLayouts(["classic", "centered"]),
17743
- navTypography: "plain"
17839
+ supportedLayoutIds: supportedLayouts(["classic", "centered"])
17744
17840
  },
17745
17841
  {
17746
17842
  id: asHeaderStyleId("brand-bar"),
17747
17843
  label: "Brand Bar",
17748
17844
  description: "Solid brand surface with high-contrast navigation.",
17749
- supportedLayoutIds: supportedLayouts(["classic", "centered"]),
17750
- navTypography: "brand-caps"
17845
+ supportedLayoutIds: supportedLayouts(["classic", "centered"])
17751
17846
  },
17752
17847
  {
17753
17848
  id: asHeaderStyleId("brand-underline"),
17754
17849
  label: "Brand Underline",
17755
17850
  description: "Brand surface with underline-grow navigation.",
17756
- supportedLayoutIds: supportedLayouts(["classic"]),
17757
- navTypography: "brand-caps"
17851
+ supportedLayoutIds: supportedLayouts(["classic"])
17758
17852
  },
17759
17853
  {
17760
17854
  id: asHeaderStyleId("brand-pill"),
@@ -17764,73 +17858,78 @@ const headerStyleCatalog = defineExactCatalog()([
17764
17858
  "classic",
17765
17859
  "centered",
17766
17860
  "floating"
17767
- ]),
17768
- navTypography: "brand-caps"
17861
+ ])
17769
17862
  },
17770
17863
  {
17771
17864
  id: asHeaderStyleId("brand-capsule"),
17772
17865
  label: "Brand Capsule",
17773
17866
  description: "Solid brand chrome designed as a floating capsule, with quiet-caps nav, a soft pill active state, and an inverted CTA pill.",
17774
- supportedLayoutIds: supportedLayouts(["classic"]),
17775
- navTypography: "quiet-caps"
17867
+ supportedLayoutIds: supportedLayouts(["classic"])
17776
17868
  },
17777
17869
  {
17778
17870
  id: asHeaderStyleId("serif-line"),
17779
17871
  label: "Serif Line",
17780
17872
  description: "Typographic logo treatment with understated underline navigation.",
17781
- supportedLayoutIds: supportedLayouts(["classic", "centered"]),
17782
- navTypography: "heading"
17873
+ supportedLayoutIds: supportedLayouts(["classic", "centered"])
17783
17874
  },
17784
17875
  {
17785
17876
  id: asHeaderStyleId("flat-tabs"),
17786
17877
  label: "Flat Tabs",
17787
17878
  description: "Flat block hover and active states with a Swiss utility feel.",
17788
- supportedLayoutIds: supportedLayouts(["classic", "centered"]),
17789
- navTypography: "quiet-caps"
17879
+ supportedLayoutIds: supportedLayouts(["classic", "centered"])
17790
17880
  },
17791
17881
  {
17792
17882
  id: asHeaderStyleId("glass"),
17793
17883
  label: "Glass",
17794
17884
  description: "Translucent chrome with frosted navigation backing.",
17795
- supportedLayoutIds: supportedLayouts(["floating"]),
17796
- navTypography: "plain"
17885
+ supportedLayoutIds: supportedLayouts(["floating"])
17797
17886
  },
17798
17887
  {
17799
17888
  id: asHeaderStyleId("minimal-surface"),
17800
17889
  label: "Clear Split",
17801
17890
  description: "Floating logo with transparent navigation and no shared shell.",
17802
- supportedLayoutIds: supportedLayouts(["floating"]),
17803
- navTypography: "plain",
17804
- openingForegroundTarget: "all",
17805
- scrollTreatment: "contrast-glass",
17806
- interactionPalette: clearSplitInteractionPalette
17891
+ supportedLayoutIds: supportedLayouts(["floating"])
17807
17892
  },
17808
17893
  {
17809
17894
  id: asHeaderStyleId("soft-shell"),
17810
17895
  label: "Soft Shell",
17811
17896
  description: "Floating rounded shell with soft pill navigation states.",
17812
- supportedLayoutIds: supportedLayouts(["floating"]),
17813
- navTypography: "plain"
17897
+ supportedLayoutIds: supportedLayouts(["floating"])
17814
17898
  },
17815
17899
  {
17816
17900
  id: asHeaderStyleId("split-glass"),
17817
17901
  label: "Split Glass",
17818
17902
  description: "Logo floats independently while the navigation sits in a glass rail.",
17819
- supportedLayoutIds: supportedLayouts(["floating"]),
17820
- navTypography: "quiet-caps",
17821
- openingForegroundTarget: "brand-only"
17903
+ supportedLayoutIds: supportedLayouts(["floating"])
17822
17904
  },
17823
17905
  {
17824
17906
  id: asHeaderStyleId("split-pill"),
17825
17907
  label: "Split Pill",
17826
17908
  description: "Logo floats independently with a soft pill-backed navigation rail.",
17827
- supportedLayoutIds: supportedLayouts(["floating"]),
17828
- navTypography: "heading",
17829
- openingForegroundTarget: "brand-only"
17909
+ supportedLayoutIds: supportedLayouts(["floating"])
17830
17910
  }
17831
17911
  ]);
17832
17912
  new Map(headerLayoutCatalog.map((layout) => [layout.id, layout]));
17833
17913
  new Map(headerStyleCatalog.map((style) => [style.id, style]));
17914
+ defineLookOptionGroup({
17915
+ id: "interaction-palette",
17916
+ label: "Hover colour",
17917
+ defaultOptionId: "accent",
17918
+ options: [
17919
+ {
17920
+ id: "accent",
17921
+ label: "Accent"
17922
+ },
17923
+ {
17924
+ id: "primary",
17925
+ label: "Primary"
17926
+ },
17927
+ {
17928
+ id: "secondary",
17929
+ label: "Secondary"
17930
+ }
17931
+ ]
17932
+ });
17834
17933
  function asFooterLookId(value) {
17835
17934
  return value;
17836
17935
  }
@@ -28785,26 +28884,6 @@ const headerLogoTextVisibleTransform = {
28785
28884
  return resolveHeaderBrandDisplay(asPartialObject(value)) !== "logo-only";
28786
28885
  }
28787
28886
  };
28788
- /**
28789
- * Selects which classic-layout nav row should render.
28790
- *
28791
- * - `'inline'` → classic variant with the historical logo-left / nav-right row
28792
- * - `'centered'`→ classic variant with a centred (flex-1) nav and a right CTA
28793
- * - `'other'` → not a classic variant (centered/floating handle it)
28794
- *
28795
- * Consumed by the site-header block's `$when` gates so the two classic rows are
28796
- * mutually exclusive without introducing a new top-level header variant.
28797
- */
28798
- const classicNavModeTransform = {
28799
- id: "layout.classicNavMode",
28800
- kind: "formatter",
28801
- summary: "Resolve which classic-layout nav row to render",
28802
- run: (value) => {
28803
- const header = asPartialObject(value);
28804
- if (header?.variant !== "classic") return "other";
28805
- return header?.navPlacement === "center" ? "centered" : "inline";
28806
- }
28807
- };
28808
28887
  const maxWidthClassTransform = {
28809
28888
  id: "layout.maxWidthClass",
28810
28889
  kind: "string",
@@ -28910,7 +28989,6 @@ const headerRootClassTransform = {
28910
28989
  if (isHeaderScrollRuntimeEnabled(content)) classes.push(config.shrink);
28911
28990
  const variant = header?.variant;
28912
28991
  if (variant && headerVariantValues.includes(variant)) classes.push(`header-variant-${variant}`);
28913
- if (header?.barFrame === "inset-shell" && variant === "classic") classes.push("header-bar-frame-inset-shell");
28914
28992
  return joinClasses$2(classes);
28915
28993
  }
28916
28994
  };
@@ -29118,7 +29196,6 @@ const layoutTransforms = [
29118
29196
  headerLogoClassTransform,
29119
29197
  headerLogoMediaClassTransform,
29120
29198
  headerLogoTextVisibleTransform,
29121
- classicNavModeTransform,
29122
29199
  footerRootClassTransform,
29123
29200
  headerRootStyleTransform,
29124
29201
  headerSectionBackgroundTransform,
@@ -29521,18 +29598,7 @@ const classicLayout = inline({
29521
29598
  logoRow,
29522
29599
  createNavRow(`rb-ml-auto ${desktopOnlyDisplay("flex")} rb-gap-6`),
29523
29600
  headerCta
29524
- ], whenTransformed("$root.theme.header", "layout.classicNavMode", "inline"));
29525
- const classicCenteredNavLayout = inline({
29526
- className: bindProp("$root.theme.header.maxWidth", {
29527
- transforms: pipe(tx("layout.maxWidthClass", { base: `rb-header-layout ${desktopOnlyDisplay("flex")} rb-w-full rb-items-center rb-gap-6` })),
29528
- fallback: `rb-container rb-header-layout ${desktopOnlyDisplay("flex")} rb-w-full rb-items-center rb-gap-6`
29529
- }),
29530
- align: "center"
29531
- }, [
29532
- logoRow,
29533
- createNavRow(`rb-flex-1 rb-justify-center ${desktopOnlyDisplay("flex")} rb-gap-6`, "center"),
29534
- headerCta
29535
- ], whenTransformed("$root.theme.header", "layout.classicNavMode", "centered"));
29601
+ ], when("$root.theme.header.variant", { equals: "classic" }));
29536
29602
  const centeredLayout = stack({
29537
29603
  gap: "md",
29538
29604
  align: "center",
@@ -29597,7 +29663,6 @@ const siteHeaderManifest = createBlockManifest({
29597
29663
  }, [
29598
29664
  mobileHeaderBar,
29599
29665
  classicLayout,
29600
- classicCenteredNavLayout,
29601
29666
  centeredLayout,
29602
29667
  floatingLayout,
29603
29668
  mobileOverlay
@@ -32040,6 +32105,7 @@ const publicWholeSeriesPriceDisplaySchema = z$1.discriminatedUnion("kind", [
32040
32105
  freePriceDisplaySchema,
32041
32106
  exactPriceDisplaySchema,
32042
32107
  fromPriceDisplaySchema,
32108
+ rangePriceDisplaySchema,
32043
32109
  unavailablePriceDisplaySchema
32044
32110
  ]);
32045
32111
  z$1.discriminatedUnion("kind", [
@@ -33166,13 +33232,16 @@ function buildEventRegistrationShellStepLabels(source) {
33166
33232
  }) : false).map((step) => shellLabelForRegistrationStep(step, scopedEvents));
33167
33233
  }
33168
33234
  function scopeEventRegistrationEvents(source) {
33235
+ return toRegistrationEvents(scopeEventRegistrationSourceEvents(source));
33236
+ }
33237
+ function scopeEventRegistrationSourceEvents(source) {
33169
33238
  const scope = planEventRegistrationScope({
33170
- events: toRegistrationEvents(source.events ?? []),
33239
+ events: source.events ?? [],
33171
33240
  wholeSeriesOffering: source.wholeSeriesOffering,
33172
33241
  occurrenceContext: source.occurrenceContext,
33173
33242
  subject: source.subject
33174
33243
  });
33175
- return scope.kind === "invalidSelectedRun" ? [] : scope.events;
33244
+ return scope.kind === "invalidSelectedRun" ? [] : [...scope.events];
33176
33245
  }
33177
33246
  function shellLabelForRegistrationStep(step, events) {
33178
33247
  switch (step) {
@@ -33204,26 +33273,29 @@ const eventRegistrationBlockRuntime = defineClientOwnedBlockRuntime({
33204
33273
  source: createZodCodec(eventRegistrationSourceSchema),
33205
33274
  render: createZodCodec(eventRegistrationRenderSchema)
33206
33275
  },
33207
- buildRender: (source) => ({
33208
- display: buildEventRegistrationDisplay(source),
33209
- hydration: {
33210
- occurrenceContext: source.occurrenceContext ?? null,
33211
- subject: source.subject ?? null,
33212
- events: source.events ?? null,
33213
- wholeSeriesOfferings: source.wholeSeriesOfferings ?? null,
33214
- wholeSeriesOffering: resolveWholeSeriesOffering(source),
33215
- maxTickets: source.maxTickets ?? void 0,
33216
- showVenue: source.showVenue,
33217
- showCapacity: source.showCapacity,
33218
- successMessage: source.successMessage,
33219
- buttonVariant: source.buttonVariant,
33220
- overlayEnabled: source.overlayEnabled,
33221
- spamProtectionEnabled: source.spamProtectionEnabled,
33222
- supportEmail: source.supportEmail,
33223
- sitePasses: source.sitePasses ?? null,
33224
- siteMemberships: source.siteMemberships ?? null
33225
- }
33226
- })
33276
+ buildRender: (source) => {
33277
+ const events = source.events == null ? null : scopeEventRegistrationSourceEvents(source);
33278
+ return {
33279
+ display: buildEventRegistrationDisplay(source),
33280
+ hydration: {
33281
+ occurrenceContext: source.occurrenceContext ?? null,
33282
+ subject: source.subject ?? null,
33283
+ events,
33284
+ wholeSeriesOfferings: source.wholeSeriesOfferings ?? null,
33285
+ wholeSeriesOffering: resolveWholeSeriesOffering(source),
33286
+ maxTickets: source.maxTickets ?? void 0,
33287
+ showVenue: source.showVenue,
33288
+ showCapacity: source.showCapacity,
33289
+ successMessage: source.successMessage,
33290
+ buttonVariant: source.buttonVariant,
33291
+ overlayEnabled: source.overlayEnabled,
33292
+ spamProtectionEnabled: source.spamProtectionEnabled,
33293
+ supportEmail: source.supportEmail,
33294
+ sitePasses: source.sitePasses ?? null,
33295
+ siteMemberships: source.siteMemberships ?? null
33296
+ }
33297
+ };
33298
+ }
33227
33299
  });
33228
33300
  function normalizeEventRegistrationEventInput(value) {
33229
33301
  if (!isRecord$22(value)) return value;
@@ -33924,67 +33996,49 @@ const MONTH_NAMES = [
33924
33996
  "November",
33925
33997
  "December"
33926
33998
  ];
33927
- /** Format a date as YYYY-MM-DD using the runtime's local timezone. */
33928
33999
  function formatDateKey(date) {
33929
- return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`;
34000
+ return `${String(date.year).padStart(4, "0")}-${String(date.month).padStart(2, "0")}-${String(date.day).padStart(2, "0")}`;
33930
34001
  }
33931
- /**
33932
- * True when `date` and `now` are the same local calendar day.
33933
- * `now` defaults to `new Date()` so casual callers don't need to thread it,
33934
- * but tests and snapshot-rendering should pass an explicit value.
33935
- */
33936
- function isToday(date, now = /* @__PURE__ */ new Date()) {
33937
- return isSameLocalDay(date, now);
34002
+ function isToday(date, today) {
34003
+ return isSameCalendarDay(date, today);
33938
34004
  }
33939
- /** True when two dates fall on the same local calendar day. */
33940
- function isSameLocalDay(left, right) {
33941
- return left.getFullYear() === right.getFullYear() && left.getMonth() === right.getMonth() && left.getDate() === right.getDate();
34005
+ function isSameCalendarDay(left, right) {
34006
+ return left.year === right.year && left.month === right.month && left.day === right.day;
34007
+ }
34008
+ function addDays(date, days) {
34009
+ const result = new Date(Date.UTC(date.year, date.month - 1, date.day + days, 12));
34010
+ return {
34011
+ year: result.getUTCFullYear(),
34012
+ month: result.getUTCMonth() + 1,
34013
+ day: result.getUTCDate()
34014
+ };
33942
34015
  }
33943
- /**
33944
- * Build the calendar days for a month view. Returns 42 dates (6 rows × 7
33945
- * days) including padding from prior/next months for a stable grid.
33946
- */
33947
34016
  function getMonthCalendarDays(year, month, startOfWeek) {
33948
- const firstDayOfMonth = new Date(year, month, 1);
33949
- const lastDayOfMonth = new Date(year, month + 1, 0);
33950
- let startOffset = firstDayOfMonth.getDay();
33951
- if (startOfWeek === "monday") startOffset = startOffset === 0 ? 6 : startOffset - 1;
33952
- const days = [];
33953
- for (let i = startOffset - 1; i >= 0; i--) days.push(new Date(year, month, -i));
33954
- for (let day = 1; day <= lastDayOfMonth.getDate(); day++) days.push(new Date(year, month, day));
33955
- while (days.length < 42) {
33956
- const nextDay = days.length - startOffset - lastDayOfMonth.getDate() + 1;
33957
- days.push(new Date(year, month + 1, nextDay));
33958
- }
33959
- return days;
34017
+ const firstDay = {
34018
+ year,
34019
+ month,
34020
+ day: 1
34021
+ };
34022
+ const dayOfWeek = getDayOfWeek(firstDay);
34023
+ const gridStart = addDays(firstDay, -(startOfWeek === "monday" ? dayOfWeek === 0 ? 6 : dayOfWeek - 1 : dayOfWeek));
34024
+ return Array.from({ length: 42 }, (_, index) => addDays(gridStart, index));
33960
34025
  }
33961
- /** Build the 7 dates of the week containing `baseDate`. */
33962
34026
  function getWeekCalendarDays(baseDate, startOfWeek) {
33963
- const days = [];
33964
- const dayOfWeek = baseDate.getDay();
33965
- const daysToStart = startOfWeek === "monday" ? dayOfWeek === 0 ? 6 : dayOfWeek - 1 : dayOfWeek;
33966
- const weekStart = new Date(baseDate);
33967
- weekStart.setDate(baseDate.getDate() - daysToStart);
33968
- for (let i = 0; i < 7; i++) {
33969
- const date = new Date(weekStart);
33970
- date.setDate(weekStart.getDate() + i);
33971
- days.push(date);
33972
- }
33973
- return days;
34027
+ const dayOfWeek = getDayOfWeek(baseDate);
34028
+ const weekStart = addDays(baseDate, -(startOfWeek === "monday" ? dayOfWeek === 0 ? 6 : dayOfWeek - 1 : dayOfWeek));
34029
+ return Array.from({ length: 7 }, (_, index) => addDays(weekStart, index));
34030
+ }
34031
+ function getDayOfWeek(date) {
34032
+ return new Date(Date.UTC(date.year, date.month - 1, date.day, 12)).getUTCDay();
33974
34033
  }
33975
- /** Build the 7 dates of the week containing `baseDate` as a fixed-width tuple. */
33976
34034
  function getWeekCalendarDayTuple(baseDate, startOfWeek) {
33977
34035
  const days = getWeekCalendarDays(baseDate, startOfWeek);
33978
34036
  assertWeekCalendarDays(days);
33979
34037
  return days;
33980
34038
  }
33981
34039
  function assertWeekCalendarDays(days) {
33982
- if (days.length !== 7) throw new Error("Expected week calendar helper to return exactly 7 days");
34040
+ if (days.length !== 7) throw new Error("Expected exactly 7 calendar days");
33983
34041
  }
33984
- /**
33985
- * Day-name labels reordered for the chosen week start. Pass a custom
33986
- * `dayNames` array (length 7, Sunday-first) to localize.
33987
- */
33988
34042
  function getOrderedDayNames(startOfWeek, dayNames = DAY_NAMES) {
33989
34043
  if (startOfWeek === "monday") {
33990
34044
  const sunday = dayNames[0] ?? "Sun";
@@ -33992,22 +34046,17 @@ function getOrderedDayNames(startOfWeek, dayNames = DAY_NAMES) {
33992
34046
  }
33993
34047
  return [...dayNames];
33994
34048
  }
33995
- /**
33996
- * Header title for a calendar view.
33997
- * - month: "January 2025"
33998
- * - week: "January 5 - 11, 2025" or "December 30 - January 5, 2025"
33999
- */
34000
34049
  function formatCalendarTitle(viewDate, view, days, monthNames = MONTH_NAMES) {
34001
34050
  if (view === "week") {
34002
34051
  const weekStart = days[0];
34003
34052
  const weekEnd = days[6];
34004
- if (weekStart === void 0 || weekEnd === void 0) return `${monthNames[viewDate.getMonth()] ?? ""} ${viewDate.getFullYear()}`;
34005
- const startMonth = monthNames[weekStart.getMonth()] ?? "";
34006
- const endMonth = monthNames[weekEnd.getMonth()] ?? "";
34007
- if (weekStart.getMonth() === weekEnd.getMonth()) return `${startMonth} ${weekStart.getDate()} - ${weekEnd.getDate()}, ${weekEnd.getFullYear()}`;
34008
- return `${startMonth} ${weekStart.getDate()} - ${endMonth} ${weekEnd.getDate()}, ${weekEnd.getFullYear()}`;
34053
+ if (weekStart === void 0 || weekEnd === void 0) return `${monthNames[viewDate.month - 1] ?? ""} ${viewDate.year}`;
34054
+ const startMonth = monthNames[weekStart.month - 1] ?? "";
34055
+ const endMonth = monthNames[weekEnd.month - 1] ?? "";
34056
+ if (weekStart.month === weekEnd.month) return `${startMonth} ${weekStart.day} - ${weekEnd.day}, ${weekEnd.year}`;
34057
+ return `${startMonth} ${weekStart.day} - ${endMonth} ${weekEnd.day}, ${weekEnd.year}`;
34009
34058
  }
34010
- return `${monthNames[viewDate.getMonth()] ?? ""} ${viewDate.getFullYear()}`;
34059
+ return `${monthNames[viewDate.month - 1] ?? ""} ${viewDate.year}`;
34011
34060
  }
34012
34061
  function buildCalendarViewport(input) {
34013
34062
  const monthNames = input.monthNames ?? MONTH_NAMES;
@@ -34017,10 +34066,10 @@ function buildCalendarViewport(input) {
34017
34066
  kind: "week",
34018
34067
  anchorDate: input.anchorDate,
34019
34068
  days,
34020
- title: formatCalendarTitle(input.anchorDate, "week", [...days], monthNames)
34069
+ title: formatCalendarTitle(input.anchorDate, "week", days, monthNames)
34021
34070
  };
34022
34071
  }
34023
- const days = getMonthCalendarDays(input.anchorDate.getFullYear(), input.anchorDate.getMonth(), input.startOfWeek);
34072
+ const days = getMonthCalendarDays(input.anchorDate.year, input.anchorDate.month, input.startOfWeek);
34024
34073
  return {
34025
34074
  kind: "month",
34026
34075
  anchorDate: input.anchorDate,
@@ -34168,13 +34217,12 @@ function buildTimetableModel$1(input) {
34168
34217
  const bounds = resolveBounds(input.bounds);
34169
34218
  const viewportDays = getTimetableDays(input.viewDate, input.view ?? "week", input.startOfWeek);
34170
34219
  const viewportKeys = new Set(viewportDays.map(formatDateKey));
34171
- const now = input.now ?? /* @__PURE__ */ new Date();
34172
34220
  const parsed = parseAllItems(input.items, input);
34173
34221
  const inViewport = deriveVisibleSegments(parsed.drafts, viewportKeys);
34174
34222
  const hourRange = resolveHourRange(inViewport, bounds);
34175
34223
  const laid = layoutCellsByDate(inViewport, hourRange, bounds);
34176
34224
  return {
34177
- days: assembleDays(viewportDays, laid.cellsByDate, now),
34225
+ days: assembleDays(viewportDays, laid.cellsByDate, input.today),
34178
34226
  hourTicks: buildHourTicks(hourRange.startHour, hourRange.endHour),
34179
34227
  startHour: hourRange.startHour,
34180
34228
  endHour: hourRange.endHour,
@@ -34231,13 +34279,13 @@ function layoutCellsByDate(segments, hourRange, bounds) {
34231
34279
  diagnostics
34232
34280
  };
34233
34281
  }
34234
- function assembleDays(viewportDays, cellsByDate, now) {
34282
+ function assembleDays(viewportDays, cellsByDate, today) {
34235
34283
  return viewportDays.map((date) => {
34236
34284
  const dateKey = formatDateKey(date);
34237
34285
  return {
34238
34286
  date,
34239
34287
  dateKey,
34240
- isToday: isSameLocalDay(date, now),
34288
+ isToday: isSameCalendarDay(date, today),
34241
34289
  cells: cellsByDate.get(dateKey) ?? []
34242
34290
  };
34243
34291
  });
@@ -34389,13 +34437,12 @@ function getTimetableDays(viewDate, view, startOfWeek) {
34389
34437
  function enumerateDateKeys(startDateKey, endDateKey) {
34390
34438
  if (startDateKey > endDateKey) throw new Error(`Invalid timetable date range: ${startDateKey} is after ${endDateKey}`);
34391
34439
  const start = parseDateKey(startDateKey);
34392
- const end = parseDateKey(endDateKey);
34440
+ parseDateKey(endDateKey);
34393
34441
  const keys = [];
34394
- const cursor = new Date(start.year, start.month - 1, start.day);
34395
- const endDate = new Date(end.year, end.month - 1, end.day);
34396
- while (cursor.getTime() <= endDate.getTime()) {
34442
+ let cursor = start;
34443
+ while (formatDateKey(cursor) <= endDateKey) {
34397
34444
  keys.push(formatDateKey(cursor));
34398
- cursor.setDate(cursor.getDate() + 1);
34445
+ cursor = addDays(cursor, 1);
34399
34446
  }
34400
34447
  return keys;
34401
34448
  }
@@ -34620,10 +34667,10 @@ function formatEventTeacherLine(event) {
34620
34667
  * timezone). Thin domain wrapper over `groupItemsByDate` from the calendar
34621
34668
  * package; preserves the historical `Map<string, PublicEvent[]>` shape.
34622
34669
  */
34623
- function groupEventsByDate(events) {
34670
+ function groupEventsByDate(events, calendarTimeZone) {
34624
34671
  const grouped = groupItemsByDate(events, {
34625
34672
  getStartsAt: (event) => event.startsAt,
34626
- getTimeZone: (event) => event.timeZone ?? "UTC"
34673
+ getTimeZone: () => calendarTimeZone
34627
34674
  });
34628
34675
  const map = /* @__PURE__ */ new Map();
34629
34676
  for (const [dateKey, bucket] of grouped) map.set(dateKey, [...bucket]);
@@ -36409,7 +36456,8 @@ const eventCollectionSourceSchemaShape = {
36409
36456
  buttonVariant: eventButtonVariantSchema.optional(),
36410
36457
  buttonText: z$1.string().optional(),
36411
36458
  emptyMessage: z$1.string().optional(),
36412
- className: z$1.string().optional()
36459
+ className: z$1.string().optional(),
36460
+ bookingTimeZone: z$1.string().optional()
36413
36461
  };
36414
36462
  const eventCollectionDisplaySchemaShape = {
36415
36463
  events: z$1.array(publicEventSchema),
@@ -36444,7 +36492,15 @@ const eventCollectionHydrationSchema = z$1.object({
36444
36492
  prefetchedEvents: z$1.boolean(),
36445
36493
  eventSurface: eventSurfaceScopeSchema$1,
36446
36494
  filterEventPresets: z$1.string().nullable(),
36447
- scheduleScope: eventScheduleScopeSchema$1
36495
+ scheduleScope: eventScheduleScopeSchema$1,
36496
+ calendarContext: z$1.object({
36497
+ timeZone: z$1.string().transform(toBookingTimeZone),
36498
+ initialToday: z$1.object({
36499
+ year: z$1.number().int(),
36500
+ month: z$1.number().int().min(1).max(12),
36501
+ day: z$1.number().int().min(1).max(31)
36502
+ })
36503
+ })
36448
36504
  });
36449
36505
  function buildEventCollectionDisplay(source) {
36450
36506
  return {
@@ -36489,14 +36545,19 @@ function buildEventCollectionPresentationDisplay(source) {
36489
36545
  emptyMessage: source.emptyMessage ?? "No upcoming events scheduled."
36490
36546
  };
36491
36547
  }
36492
- function buildEventCollectionHydration(source) {
36548
+ function buildEventCollectionHydration(source, now = /* @__PURE__ */ new Date()) {
36549
+ const timeZone = toBookingTimeZone(source.bookingTimeZone);
36493
36550
  return {
36494
36551
  siteId: source.siteId,
36495
36552
  stage: source.stage,
36496
36553
  prefetchedEvents: source.events != null,
36497
36554
  eventSurface: normalizeEventSurfaceScope(source.eventSurface),
36498
36555
  filterEventPresets: normalizeEventSurfacePresetsCsv(source.filterEventPresets),
36499
- scheduleScope: normalizeEventScheduleScope(source.scheduleScope)
36556
+ scheduleScope: normalizeEventScheduleScope(source.scheduleScope),
36557
+ calendarContext: {
36558
+ timeZone,
36559
+ initialToday: getLocalScheduleDate(now, timeZone)
36560
+ }
36500
36561
  };
36501
36562
  }
36502
36563
  function buildEventCollectionListingDisplay(display, prefetchedEvents, className) {
@@ -47150,7 +47211,8 @@ function isOrdinaryEvent(event) {
47150
47211
  function deriveWholeSeriesPhase(sessions, nowIso) {
47151
47212
  const now = Date.parse(nowIso);
47152
47213
  if (now < Date.parse(sessions[0].startsAt)) return "upcoming";
47153
- return now <= Date.parse(sessions.at(-1)?.endsAt ?? sessions[0].endsAt) ? "inProgress" : "completed";
47214
+ const finalSession = sessions[sessions.length - 1] ?? sessions[0];
47215
+ return now <= Date.parse(finalSession.endsAt) ? "inProgress" : "completed";
47154
47216
  }
47155
47217
  function selectRelatedDates(input) {
47156
47218
  if (!input.seriesId) return [];
@@ -47548,9 +47610,13 @@ function EventDetailsSSR(props) {
47548
47610
  const { blockId, occurrenceContext = null, subject, events = null, className, children } = props;
47549
47611
  const nowIso = (/* @__PURE__ */ new Date()).toISOString();
47550
47612
  const normalizedSubject = normalizeEventRegistrationPageSurfaceSubject(subject);
47613
+ const scopedEvents = events === null ? null : resolveEventRegistrationScopedEvents(events, {
47614
+ occurrenceContext,
47615
+ subject: normalizedSubject
47616
+ });
47551
47617
  const presentation = resolveEventDetailsPresentation({
47552
47618
  ...props,
47553
- events,
47619
+ events: scopedEvents,
47554
47620
  occurrenceContext,
47555
47621
  subject: normalizedSubject,
47556
47622
  nowIso
@@ -47563,7 +47629,7 @@ function EventDetailsSSR(props) {
47563
47629
  /* @__PURE__ */ jsx(IslandPropsScript, { value: {
47564
47630
  occurrenceContext,
47565
47631
  subject: normalizedSubject,
47566
- events,
47632
+ events: scopedEvents,
47567
47633
  showVenue: presentation.showVenue,
47568
47634
  showMap: presentation.showMap,
47569
47635
  showOtherDates: presentation.showOtherDates,
@@ -49245,9 +49311,9 @@ const FULL_DAY_NAMES$1 = [
49245
49311
  * @returns "Monday, January 13"
49246
49312
  */
49247
49313
  function formatAgendaDayHeader(date) {
49248
- const dayName = FULL_DAY_NAMES$1[date.getDay()];
49249
- const monthName = MONTH_NAMES[date.getMonth()];
49250
- return `${dayName ?? "Day"}, ${monthName ?? "Month"} ${date.getDate()}`;
49314
+ const dayName = FULL_DAY_NAMES$1[getDayOfWeek(date)];
49315
+ const monthName = MONTH_NAMES[date.month - 1];
49316
+ return `${dayName ?? "Day"}, ${monthName ?? "Month"} ${date.day}`;
49251
49317
  }
49252
49318
  /**
49253
49319
  * WeekAgendaView Component
@@ -49255,14 +49321,14 @@ function formatAgendaDayHeader(date) {
49255
49321
  * Displays a week of events in an agenda/list style with rich event details.
49256
49322
  * Shows all 7 days with date headers, empty days show "No events scheduled".
49257
49323
  */
49258
- const WeekAgendaView = ({ days, events, showCapacity, emptyMessage = "No events scheduled" }) => {
49259
- const eventsByDate = groupEventsByDate(events);
49324
+ const WeekAgendaView = ({ days, events, showCapacity, emptyMessage = "No events scheduled", calendarTimeZone, today: currentDate }) => {
49325
+ const eventsByDate = groupEventsByDate(events, calendarTimeZone);
49260
49326
  return /* @__PURE__ */ jsx("div", {
49261
49327
  className: "event-agenda-week",
49262
49328
  children: days.map((date) => {
49263
49329
  const dateKey = formatDateKey(date);
49264
49330
  const dayEvents = eventsByDate.get(dateKey) || [];
49265
- const today = isToday(date);
49331
+ const today = isToday(date, currentDate);
49266
49332
  return /* @__PURE__ */ jsxs("div", {
49267
49333
  className: `event-agenda-day ${today ? "event-agenda-day--today" : ""}`,
49268
49334
  children: [/* @__PURE__ */ jsx("div", {
@@ -49291,6 +49357,50 @@ const WeekAgendaView = ({ days, events, showCapacity, emptyMessage = "No events
49291
49357
  })
49292
49358
  });
49293
49359
  };
49360
+ //#endregion
49361
+ //#region ../blocks/src/system/runtime/nodes/events/shared/CalendarNavigationChevron.tsx
49362
+ function CalendarNavigationChevron({ direction }) {
49363
+ return /* @__PURE__ */ jsx("svg", {
49364
+ width: "20",
49365
+ height: "20",
49366
+ fill: "none",
49367
+ stroke: "currentColor",
49368
+ strokeWidth: 2,
49369
+ viewBox: "0 0 24 24",
49370
+ "aria-hidden": "true",
49371
+ children: /* @__PURE__ */ jsx("path", {
49372
+ strokeLinecap: "round",
49373
+ strokeLinejoin: "round",
49374
+ d: direction === "previous" ? "M15 19l-7-7 7-7" : "M9 5l7 7-7 7"
49375
+ })
49376
+ });
49377
+ }
49378
+ //#endregion
49379
+ //#region ../blocks/src/system/runtime/nodes/events/shared/WeekBoardView.tsx
49380
+ function buildWeekBoardNavigationState(viewport, today) {
49381
+ return {
49382
+ rangeLabel: viewport.title,
49383
+ isCurrentWeek: viewport.days.some((day) => isToday(day, today))
49384
+ };
49385
+ }
49386
+ function buildWeekBoardViewProps(display, days, navigation, events = display.events) {
49387
+ return {
49388
+ days,
49389
+ events: [...events],
49390
+ navigation,
49391
+ showCapacity: display.showCapacity,
49392
+ emptyMessage: display.emptyMessage,
49393
+ title: display.boardTitle,
49394
+ footerNote: display.footerNote,
49395
+ ctaLabel: display.loadMoreText ?? display.buttonText,
49396
+ ctaHref: display.seeAllUrl,
49397
+ buttonVariant: display.buttonVariant,
49398
+ elevated: display.elevated,
49399
+ banded: display.banded,
49400
+ calendarTimeZone: display.calendarTimeZone,
49401
+ today: display.today
49402
+ };
49403
+ }
49294
49404
  const SHORT_DAY_NAMES = [
49295
49405
  "Sun",
49296
49406
  "Mon",
@@ -49352,6 +49462,114 @@ const WeekBoardCard = ({ event, showCapacity }) => {
49352
49462
  ]
49353
49463
  });
49354
49464
  };
49465
+ const WeekBoardNavigationControls = ({ navigation, todayClassName }) => {
49466
+ const handlers = navigation.kind === "interactive" ? navigation : {
49467
+ onPrevious: void 0,
49468
+ onNext: void 0,
49469
+ onToday: void 0
49470
+ };
49471
+ const isLoading = navigation.kind === "interactive" && navigation.loadState.kind === "loading";
49472
+ return /* @__PURE__ */ jsxs("nav", {
49473
+ className: "event-week-board-navigation",
49474
+ "aria-label": "Choose week",
49475
+ children: [
49476
+ /* @__PURE__ */ jsx("button", {
49477
+ type: "button",
49478
+ className: "event-week-board-nav-button",
49479
+ "aria-label": "Previous week",
49480
+ onClick: handlers.onPrevious,
49481
+ children: /* @__PURE__ */ jsx(CalendarNavigationChevron, { direction: "previous" })
49482
+ }),
49483
+ /* @__PURE__ */ jsxs("h3", {
49484
+ className: "event-week-board-range",
49485
+ "aria-live": "polite",
49486
+ children: [navigation.rangeLabel, isLoading ? /* @__PURE__ */ jsx("span", {
49487
+ className: "event-week-board-loading",
49488
+ children: " Loading…"
49489
+ }) : null]
49490
+ }),
49491
+ /* @__PURE__ */ jsx("button", {
49492
+ type: "button",
49493
+ className: "event-week-board-nav-button",
49494
+ "aria-label": "Next week",
49495
+ onClick: handlers.onNext,
49496
+ children: /* @__PURE__ */ jsx(CalendarNavigationChevron, { direction: "next" })
49497
+ }),
49498
+ /* @__PURE__ */ jsx("button", {
49499
+ type: "button",
49500
+ className: todayClassName,
49501
+ disabled: navigation.isCurrentWeek,
49502
+ onClick: handlers.onToday,
49503
+ children: "Today"
49504
+ })
49505
+ ]
49506
+ });
49507
+ };
49508
+ const WeekBoardLegend = () => /* @__PURE__ */ jsx("div", {
49509
+ className: "event-week-board-legend",
49510
+ "aria-hidden": "true",
49511
+ children: LEGEND_ITEMS.map((item) => /* @__PURE__ */ jsxs("span", {
49512
+ className: "event-week-board-legend-item",
49513
+ children: [/* @__PURE__ */ jsx("i", {
49514
+ className: "event-week-board-legend-dot",
49515
+ "data-status": item.status
49516
+ }), item.label]
49517
+ }, item.status))
49518
+ });
49519
+ const WeekBoardLoadError = ({ navigation, buttonClassName }) => {
49520
+ if (navigation.kind !== "interactive" || navigation.loadState.kind !== "error") return null;
49521
+ return /* @__PURE__ */ jsxs("div", {
49522
+ className: "event-week-board-error",
49523
+ role: "status",
49524
+ children: [/* @__PURE__ */ jsx("p", { children: "Failed to load events" }), /* @__PURE__ */ jsx("button", {
49525
+ type: "button",
49526
+ className: buttonClassName,
49527
+ onClick: navigation.loadState.onRetry,
49528
+ children: "Try again"
49529
+ })]
49530
+ });
49531
+ };
49532
+ const WeekBoardGrid = ({ days, eventsByDate, showCapacity, today: currentDate }) => /* @__PURE__ */ jsx("div", {
49533
+ className: "event-week-board-grid",
49534
+ children: days.map((date) => {
49535
+ const dateKey = formatDateKey(date);
49536
+ const dayEvents = eventsByDate.get(dateKey) ?? [];
49537
+ const today = isToday(date, currentDate);
49538
+ return /* @__PURE__ */ jsxs("div", {
49539
+ className: clsx("event-week-board-day", dayEvents.length === 0 && "event-week-board-day--empty", today && "event-week-board-day--today"),
49540
+ children: [/* @__PURE__ */ jsxs("div", {
49541
+ className: "event-week-board-day-head",
49542
+ children: [/* @__PURE__ */ jsx("span", {
49543
+ className: "event-week-board-day-abbr",
49544
+ children: SHORT_DAY_NAMES[getDayOfWeek(date)]
49545
+ }), /* @__PURE__ */ jsx("span", {
49546
+ className: "event-week-board-day-num",
49547
+ children: date.day
49548
+ })]
49549
+ }), /* @__PURE__ */ jsx("div", {
49550
+ className: "event-week-board-day-body",
49551
+ children: dayEvents.map((event) => /* @__PURE__ */ jsx(WeekBoardCard, {
49552
+ event,
49553
+ showCapacity
49554
+ }, event.occurrenceId || event.id))
49555
+ })]
49556
+ }, dateKey);
49557
+ })
49558
+ });
49559
+ const WeekBoardFooter = ({ note, ctaHref, ctaLabel, ctaClassName }) => {
49560
+ if (note === null && ctaHref === null) return null;
49561
+ return /* @__PURE__ */ jsxs("div", {
49562
+ className: "event-week-board-foot",
49563
+ children: [note === null ? null : /* @__PURE__ */ jsx("p", {
49564
+ className: "event-week-board-foot-note",
49565
+ children: note
49566
+ }), ctaHref === null ? null : /* @__PURE__ */ jsx("a", {
49567
+ className: ctaClassName,
49568
+ href: ctaHref,
49569
+ children: ctaLabel
49570
+ })]
49571
+ });
49572
+ };
49355
49573
  /**
49356
49574
  * WeekBoardView
49357
49575
  *
@@ -49360,18 +49578,21 @@ const WeekBoardCard = ({ event, showCapacity }) => {
49360
49578
  * to a stacked list on mobile. Repurposes the week-grouped agenda data as a
49361
49579
  * board rather than an hour-positioned timetable grid.
49362
49580
  */
49363
- 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 }) => {
49364
- const eventsByDate = groupEventsByDate(events);
49581
+ 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 }) => {
49582
+ const eventsByDate = groupEventsByDate(events, calendarTimeZone);
49365
49583
  const hasAnyEvents = days.some((date) => (eventsByDate.get(formatDateKey(date)) ?? []).length > 0);
49366
49584
  const ctaClassName = themeButtonClassName({
49367
49585
  variant: buttonVariant,
49368
49586
  size: "sm"
49369
49587
  });
49588
+ const todayClassName = themeButtonClassName({
49589
+ variant: buttonVariant,
49590
+ size: "sm"
49591
+ });
49370
49592
  const hasTitle = typeof title === "string" && title.length > 0;
49371
49593
  const hasFooterNote = typeof footerNote === "string" && footerNote.length > 0;
49372
- const hasCta = typeof ctaHref === "string" && ctaHref.length > 0;
49373
49594
  const footerNoteText = hasAnyEvents ? hasFooterNote ? footerNote : null : emptyMessage;
49374
- const showFooter = hasCta || footerNoteText !== null;
49595
+ const resolvedCtaHref = typeof ctaHref === "string" && ctaHref.length > 0 ? ctaHref : null;
49375
49596
  return /* @__PURE__ */ jsx("div", {
49376
49597
  className: "event-calendar event-calendar--week-board",
49377
49598
  "data-block": "event-calendar",
@@ -49383,59 +49604,34 @@ const WeekBoardView = ({ days, events, showCapacity, emptyMessage = "No classes
49383
49604
  children: [
49384
49605
  /* @__PURE__ */ jsxs("div", {
49385
49606
  className: "event-week-board-top",
49386
- children: [hasTitle ? /* @__PURE__ */ jsx("span", {
49387
- className: "event-week-board-title",
49388
- children: title
49389
- }) : null, /* @__PURE__ */ jsx("div", {
49390
- className: "event-week-board-legend",
49391
- "aria-hidden": "true",
49392
- children: LEGEND_ITEMS.map((item) => /* @__PURE__ */ jsxs("span", {
49393
- className: "event-week-board-legend-item",
49394
- children: [/* @__PURE__ */ jsx("i", {
49395
- className: "event-week-board-legend-dot",
49396
- "data-status": item.status
49397
- }), item.label]
49398
- }, item.status))
49399
- })]
49607
+ children: [
49608
+ hasTitle ? /* @__PURE__ */ jsx("span", {
49609
+ className: "event-week-board-title",
49610
+ children: title
49611
+ }) : null,
49612
+ /* @__PURE__ */ jsx(WeekBoardNavigationControls, {
49613
+ navigation,
49614
+ todayClassName
49615
+ }),
49616
+ /* @__PURE__ */ jsx(WeekBoardLegend, {})
49617
+ ]
49400
49618
  }),
49401
- /* @__PURE__ */ jsx("div", {
49402
- className: "event-week-board-grid",
49403
- children: days.map((date) => {
49404
- const dateKey = formatDateKey(date);
49405
- const dayEvents = eventsByDate.get(dateKey) ?? [];
49406
- const today = isToday(date);
49407
- return /* @__PURE__ */ jsxs("div", {
49408
- className: clsx("event-week-board-day", dayEvents.length === 0 && "event-week-board-day--empty", today && "event-week-board-day--today"),
49409
- children: [/* @__PURE__ */ jsxs("div", {
49410
- className: "event-week-board-day-head",
49411
- children: [/* @__PURE__ */ jsx("span", {
49412
- className: "event-week-board-day-abbr",
49413
- children: SHORT_DAY_NAMES[date.getDay()]
49414
- }), /* @__PURE__ */ jsx("span", {
49415
- className: "event-week-board-day-num",
49416
- children: date.getDate()
49417
- })]
49418
- }), /* @__PURE__ */ jsx("div", {
49419
- className: "event-week-board-day-body",
49420
- children: dayEvents.map((event) => /* @__PURE__ */ jsx(WeekBoardCard, {
49421
- event,
49422
- showCapacity
49423
- }, event.occurrenceId || event.id))
49424
- })]
49425
- }, dateKey);
49426
- })
49619
+ /* @__PURE__ */ jsx(WeekBoardLoadError, {
49620
+ navigation,
49621
+ buttonClassName: todayClassName
49427
49622
  }),
49428
- showFooter ? /* @__PURE__ */ jsxs("div", {
49429
- className: "event-week-board-foot",
49430
- children: [footerNoteText !== null ? /* @__PURE__ */ jsx("p", {
49431
- className: "event-week-board-foot-note",
49432
- children: footerNoteText
49433
- }) : null, hasCta ? /* @__PURE__ */ jsx("a", {
49434
- className: ctaClassName,
49435
- href: ctaHref ?? void 0,
49436
- children: ctaLabel
49437
- }) : null]
49438
- }) : null
49623
+ /* @__PURE__ */ jsx(WeekBoardGrid, {
49624
+ days,
49625
+ eventsByDate,
49626
+ showCapacity,
49627
+ today
49628
+ }),
49629
+ /* @__PURE__ */ jsx(WeekBoardFooter, {
49630
+ note: footerNoteText,
49631
+ ctaHref: resolvedCtaHref,
49632
+ ctaLabel,
49633
+ ctaClassName
49634
+ })
49439
49635
  ]
49440
49636
  })
49441
49637
  });
@@ -49466,6 +49662,7 @@ function buildTimetableModel(input) {
49466
49662
  items: input.events,
49467
49663
  viewDate: input.viewDate,
49468
49664
  startOfWeek: input.startOfWeek,
49665
+ today: input.today,
49469
49666
  getId: (event) => event.id,
49470
49667
  getStartsAt: (event) => event.startsAt,
49471
49668
  getEndsAt: (event) => event.endsAt,
@@ -49527,10 +49724,10 @@ function formatEventTimeRange(event) {
49527
49724
  return `${formatTime(event.startsAt, { timeZone })} - ${formatTime(event.endsAt, { timeZone })}`;
49528
49725
  }
49529
49726
  function formatDayLabel(date) {
49530
- return `${FULL_DAY_NAMES[date.getDay()] ?? ""}, ${MONTH_NAMES[date.getMonth()] ?? ""} ${date.getDate()}`;
49727
+ return `${FULL_DAY_NAMES[getDayOfWeek(date)] ?? ""}, ${MONTH_NAMES[date.month - 1] ?? ""} ${date.day}`;
49531
49728
  }
49532
49729
  function formatShortDayLabel(date) {
49533
- return `${(FULL_DAY_NAMES[date.getDay()] ?? "").slice(0, 3)} ${date.getDate()}`;
49730
+ return `${(FULL_DAY_NAMES[getDayOfWeek(date)] ?? "").slice(0, 3)} ${date.day}`;
49534
49731
  }
49535
49732
  //#endregion
49536
49733
  //#region ../blocks/src/system/runtime/nodes/events/EventCalendar.server.tsx
@@ -49577,15 +49774,15 @@ function renderListSsr(display, prefetchedEvents) {
49577
49774
  renderEventCard: (event) => renderEventCard(event, listDisplay)
49578
49775
  });
49579
49776
  }
49580
- function renderCalendarSsr(display) {
49777
+ function renderCalendarSsr(display, hydration) {
49581
49778
  const calendarView = display.defaultCalendarView;
49582
- const viewDate = /* @__PURE__ */ new Date();
49779
+ const viewDate = hydration.calendarContext.initialToday;
49583
49780
  const viewport = buildCalendarViewport({
49584
49781
  view: calendarView,
49585
49782
  anchorDate: viewDate,
49586
49783
  startOfWeek: display.startOfWeek
49587
49784
  });
49588
- const eventsByDate = groupEventsByDate([...display.events]);
49785
+ const eventsByDate = groupEventsByDate([...display.events], hydration.calendarContext.timeZone);
49589
49786
  const dayNames = getOrderedDayNames(display.startOfWeek);
49590
49787
  return /* @__PURE__ */ jsxs("div", {
49591
49788
  className: clsx("event-calendar", display.className ?? void 0),
@@ -49652,7 +49849,9 @@ function renderCalendarSsr(display) {
49652
49849
  days: viewport.days,
49653
49850
  events: [...display.events],
49654
49851
  emptyMessage: display.emptyMessage,
49655
- showCapacity: display.showCapacity
49852
+ showCapacity: display.showCapacity,
49853
+ calendarTimeZone: hydration.calendarContext.timeZone,
49854
+ today: hydration.calendarContext.initialToday
49656
49855
  }) : /* @__PURE__ */ jsxs("div", {
49657
49856
  className: "event-calendar-container",
49658
49857
  children: [/* @__PURE__ */ jsx("div", {
@@ -49666,13 +49865,13 @@ function renderCalendarSsr(display) {
49666
49865
  children: viewport.days.map((date) => {
49667
49866
  const dateKey = formatDateKey(date);
49668
49867
  const dayEvents = eventsByDate.get(dateKey) || [];
49669
- const isCurrentMonth = date.getMonth() === viewDate.getMonth();
49670
- const today = isToday(date);
49868
+ const isCurrentMonth = date.month === viewDate.month;
49869
+ const today = isToday(date, hydration.calendarContext.initialToday);
49671
49870
  return /* @__PURE__ */ jsxs("div", {
49672
49871
  className: clsx("event-calendar-day", !isCurrentMonth && "event-calendar-day--other-month", today && "event-calendar-day--today"),
49673
49872
  children: [/* @__PURE__ */ jsx("div", {
49674
49873
  className: "event-calendar-day-number",
49675
- children: date.getDate()
49874
+ children: date.day
49676
49875
  }), /* @__PURE__ */ jsxs("div", {
49677
49876
  className: "event-calendar-events",
49678
49877
  children: [dayEvents.slice(0, 3).map((event) => /* @__PURE__ */ jsxs("a", {
@@ -49710,8 +49909,8 @@ function renderCalendarSsr(display) {
49710
49909
  ]
49711
49910
  });
49712
49911
  }
49713
- function renderTimetableSsr(display) {
49714
- const viewDate = /* @__PURE__ */ new Date();
49912
+ function renderTimetableSsr(display, hydration) {
49913
+ const viewDate = hydration.calendarContext.initialToday;
49715
49914
  const viewport = buildCalendarViewport({
49716
49915
  view: "week",
49717
49916
  anchorDate: viewDate,
@@ -49720,7 +49919,8 @@ function renderTimetableSsr(display) {
49720
49919
  const model = buildTimetableModel({
49721
49920
  events: [...display.events],
49722
49921
  viewDate,
49723
- startOfWeek: display.startOfWeek
49922
+ startOfWeek: display.startOfWeek,
49923
+ today: hydration.calendarContext.initialToday
49724
49924
  });
49725
49925
  const selectedDayKey = model.days.find((day) => day.isToday)?.dateKey ?? model.days[0]?.dateKey ?? "";
49726
49926
  return /* @__PURE__ */ jsxs("div", {
@@ -49875,20 +50075,21 @@ function renderTimetableSsr(display) {
49875
50075
  })]
49876
50076
  });
49877
50077
  }
49878
- function renderWeekBoardSsr(display) {
49879
- return /* @__PURE__ */ jsx(WeekBoardView, {
49880
- days: getWeekCalendarDayTuple(/* @__PURE__ */ new Date(), display.startOfWeek),
49881
- events: [...display.events],
49882
- showCapacity: display.showCapacity,
49883
- emptyMessage: display.emptyMessage,
49884
- title: display.boardTitle,
49885
- footerNote: display.footerNote,
49886
- ctaLabel: display.loadMoreText ?? display.buttonText,
49887
- ctaHref: display.seeAllUrl,
49888
- buttonVariant: display.buttonVariant,
49889
- elevated: display.elevated,
49890
- banded: display.banded
49891
- });
50078
+ function renderWeekBoardSsr(display, hydration) {
50079
+ const today = hydration.calendarContext.initialToday;
50080
+ const days = getWeekCalendarDayTuple(today, display.startOfWeek);
50081
+ const navigation = {
50082
+ kind: "static",
50083
+ ...buildWeekBoardNavigationState({
50084
+ days,
50085
+ title: formatCalendarTitle(today, "week", [...days])
50086
+ }, today)
50087
+ };
50088
+ return /* @__PURE__ */ jsx(WeekBoardView, { ...buildWeekBoardViewProps({
50089
+ ...display,
50090
+ calendarTimeZone: hydration.calendarContext.timeZone,
50091
+ today
50092
+ }, days, navigation) });
49892
50093
  }
49893
50094
  function formatHourLabel(hour) {
49894
50095
  if (hour === 0) return "12 AM";
@@ -49914,13 +50115,13 @@ const EventCalendarSSR = (props) => {
49914
50115
  content = renderListSsr(display, hydration.prefetchedEvents);
49915
50116
  break;
49916
50117
  case "timetable":
49917
- content = renderTimetableSsr(display);
50118
+ content = renderTimetableSsr(display, hydration);
49918
50119
  break;
49919
50120
  case "week-board":
49920
- content = renderWeekBoardSsr(display);
50121
+ content = renderWeekBoardSsr(display, hydration);
49921
50122
  break;
49922
50123
  case "calendar":
49923
- content = renderCalendarSsr(display);
50124
+ content = renderCalendarSsr(display, hydration);
49924
50125
  break;
49925
50126
  default: content = assertNeverDisplayMode(display.displayMode);
49926
50127
  }
@@ -53149,36 +53350,9 @@ function buildLegacyHeaderNavLinkStyle(header, contrastTreatment, navTextSize) {
53149
53350
  ...navTextSize ? { textSize: navTextSize } : {}
53150
53351
  };
53151
53352
  if (header.navWeight === "bold" && navStyle === "solid") style.textTransform = "uppercase";
53152
- applyLegacyNavEffects(style, header);
53153
53353
  applyLegacyGlassTreatment(style, header, navStyle);
53154
53354
  return style;
53155
53355
  }
53156
- function applyLegacyNavEffects(style, header) {
53157
- if (!header.navEffects) return;
53158
- const effects = style.effects = {
53159
- ...style.effects,
53160
- hover: [...style.effects?.hover ?? []],
53161
- active: [...style.effects?.active ?? []]
53162
- };
53163
- if (header.navEffects.glow) effects.hover.push({
53164
- effectId: "outer-glow",
53165
- options: { spread: 5 }
53166
- });
53167
- if (header.navEffects.neumorphic) {
53168
- effects.hover.push({
53169
- effectId: "neumorphic-shadow",
53170
- options: { mode: "pressed" }
53171
- });
53172
- effects.hover.push({
53173
- effectId: "text-color-change",
53174
- options: { hoverColorToken: "primary" }
53175
- });
53176
- }
53177
- if (header.navEffects.underlineGradient) effects.hover.push({
53178
- effectId: "border-bottom-grow",
53179
- options: { origin: "center" }
53180
- });
53181
- }
53182
53356
  function applyLegacyGlassTreatment(style, header, navStyle) {
53183
53357
  if (header.navContainer?.type !== "glass" || navStyle !== "minimal") return;
53184
53358
  style.borderRadius = "full";
@@ -53204,19 +53378,6 @@ function glassStateEffects(opacity) {
53204
53378
  //#region ../theme-core/src/header/generateHeaderCss.ts
53205
53379
  const HEADER_BLUR = "blur(12px)";
53206
53380
  const FLOATING_BLUR = "blur(16px)";
53207
- const INSET_SHELL_MARKER_CLASS = "header-bar-frame-inset-shell";
53208
- const INSET_SHELL_EDGE = "1rem";
53209
- const INSET_SHELL_INSET_BLOCK = "0.875rem";
53210
- const INSET_SHELL_RADIUS = "9999px";
53211
- const INSET_SHELL_CONTAINER_MAX = "80rem";
53212
- const INSET_SHELL_INTERIOR_PADDING_X = "1.75rem";
53213
- /**
53214
- * Whether the classic header should render as an inset "brand capsule" shell.
53215
- * The facet is only meaningful for the classic layout; other variants ignore it.
53216
- */
53217
- function usesInsetShell(header) {
53218
- return header.barFrame === "inset-shell" && header.variant === "classic";
53219
- }
53220
53381
  /**
53221
53382
  * Generate complete CSS for header system from theme config
53222
53383
  *
@@ -53294,36 +53455,7 @@ function generateHeaderRootStyles(header, themeId, tokens) {
53294
53455
  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`;
53295
53456
  const scrollTreatmentStyles = generateHeaderScrollTreatmentStyles(header.scrollTreatment, themeId, header.variant, scrolledPaintRules);
53296
53457
  if (isContainedNav || basePaintRules.length === 0) return `${baseBlock}\n${overlayFix}${scrollTreatmentStyles}`;
53297
- return `${baseBlock}\n${renderHeaderPaintTargetRules(getHeaderPaintTargets(header.variant, themeId), basePaintRules)}\n${overlayFix}${usesInsetShell(header) ? generateInsetShellStyles(header, themeId) : ""}${scrollTreatmentStyles}`;
53298
- }
53299
- /**
53300
- * Reshapes the full-bleed header paint layer into a contained brand capsule at
53301
- * the desktop breakpoint. The capsule is centred, capped to the page container
53302
- * width, inset from the top, fully rounded, and carries the header depth so it
53303
- * reads as a floating pill. Root border/shadow are neutralised on desktop so a
53304
- * bordered style does not leave a full-width hairline around the capsule. Sticky
53305
- * positioning is unaffected — the root stays full width and sticky while the
53306
- * ::before paint provides the capsule.
53307
- */
53308
- function generateInsetShellStyles(header, themeId) {
53309
- const scope = `:where([data-theme-scope="${themeId}"])`;
53310
- const shellRootSelector = `${scope} .header-root.${INSET_SHELL_MARKER_CLASS}`;
53311
- const shellBeforeSelector = `${scope} .header-root.${INSET_SHELL_MARKER_CLASS}::before`;
53312
- const layoutSelector = `${scope} .header-root.${INSET_SHELL_MARKER_CLASS} .rb-header-layout`;
53313
- const widthValue = header.maxWidth === "full" ? `calc(100% - (${INSET_SHELL_EDGE} * 2))` : `min(${INSET_SHELL_CONTAINER_MAX}, calc(100% - (${INSET_SHELL_EDGE} * 2)))`;
53314
- const shadowVar = getComponentShadowVar(header.shadow?.elevation ?? "none");
53315
- const rootRules = ["border: none;", "box-shadow: none;"];
53316
- const beforeRules = [
53317
- `inset: ${INSET_SHELL_INSET_BLOCK} auto;`,
53318
- "left: 50%;",
53319
- "right: auto;",
53320
- "transform: translateX(-50%);",
53321
- `width: ${widthValue};`,
53322
- `border-radius: ${INSET_SHELL_RADIUS};`,
53323
- ...shadowVar ? [`box-shadow: ${shadowVar};`] : []
53324
- ];
53325
- const layoutRules = [`padding-inline: ${INSET_SHELL_INTERIOR_PADDING_X};`];
53326
- 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`;
53458
+ return `${baseBlock}\n${renderHeaderPaintTargetRules(getHeaderPaintTargets(header.variant, themeId), basePaintRules)}\n${overlayFix}${scrollTreatmentStyles}`;
53327
53459
  }
53328
53460
  /**
53329
53461
  * Generate logo typography styles
@@ -53397,7 +53529,7 @@ function generateLogoTextBehaviorStyles(logoText, themeId) {
53397
53529
  * Generate navigation link styles based on navStyle and effects
53398
53530
  *
53399
53531
  * Uses the composable NavLinkStyle system with backward compatibility for
53400
- * legacy navStyle, navWeight, navColor, and navEffects settings.
53532
+ * legacy navStyle, navWeight and navColor settings.
53401
53533
  */
53402
53534
  function generateNavLinkStyles(header, themeId, tokens, theme, contrastTreatment, navTextSize) {
53403
53535
  const navPreferences = {
@@ -56034,9 +56166,60 @@ function pageBlockPosition(index, blockCount) {
56034
56166
  return "middle";
56035
56167
  }
56036
56168
  //#endregion
56169
+ //#region ../blocks/src/pageRenderAdmission.ts
56170
+ function toPresentationPage(page) {
56171
+ if (!page) return null;
56172
+ return {
56173
+ ...page,
56174
+ blocks: page.blocks.map((block) => {
56175
+ const presentationMetadata = {
56176
+ id: block.id,
56177
+ kind: block.kind,
56178
+ purpose: block.purpose,
56179
+ ...block.bindings ? { bindings: block.bindings } : {}
56180
+ };
56181
+ return block.admission.kind === "renderable" ? {
56182
+ ...presentationMetadata,
56183
+ content: block.admission.content,
56184
+ presentationAdmission: { kind: "renderable" }
56185
+ } : {
56186
+ ...presentationMetadata,
56187
+ presentationAdmission: {
56188
+ kind: "invalid",
56189
+ error: block.admission.error
56190
+ }
56191
+ };
56192
+ })
56193
+ };
56194
+ }
56195
+ function toEditorPresentationPage(page) {
56196
+ if (!page) return null;
56197
+ return {
56198
+ ...page,
56199
+ blocks: page.blocks.map((block) => ({
56200
+ ...block,
56201
+ presentationAdmission: { kind: "editor" }
56202
+ }))
56203
+ };
56204
+ }
56205
+ //#endregion
56037
56206
  //#region ../blocks/src/PageRenderer.tsx
56038
56207
  function PageRenderer$1(props) {
56039
- const { page, runtimeBoundaries, usePlaceholders = false, dataContext, wrapBlock, wrapBoundary, registry, routeMap, blockOverrides, sdkConfig, customBlocks, previewAuthoring } = props;
56208
+ const page = React$1.useMemo(() => toPresentationPage(props.page), [props.page]);
56209
+ return /* @__PURE__ */ jsx(PageRendererCore, {
56210
+ ...props,
56211
+ page
56212
+ });
56213
+ }
56214
+ function EditorPageRenderer$1(props) {
56215
+ const page = React$1.useMemo(() => toEditorPresentationPage(props.page), [props.page]);
56216
+ return /* @__PURE__ */ jsx(PageRendererCore, {
56217
+ ...props,
56218
+ page
56219
+ });
56220
+ }
56221
+ function PageRendererCore(props) {
56222
+ const { page, runtimeBoundaries, dataContext, wrapBlock, wrapBoundary, registry } = props;
56040
56223
  const imageResolveContext = React$1.useMemo(() => resolvePageRendererImageResolveContext(dataContext), [
56041
56224
  dataContext?.imageResolveContext,
56042
56225
  dataContext?.mediaAssets,
@@ -56135,11 +56318,11 @@ function resolvePageRendererImageResolveContext(dataContext) {
56135
56318
  mediaAssets: input?.mediaAssets ?? dataContext?.mediaAssets
56136
56319
  });
56137
56320
  }
56321
+ const resolveBookingTimeZone = (dataContext) => dataContext?.bookingTimeZone;
56138
56322
  function buildBlockSectionProps(input) {
56139
56323
  return {
56140
56324
  themeResources: input.themeResources,
56141
56325
  block: input.block,
56142
- usePlaceholders: input.props.usePlaceholders ?? false,
56143
56326
  dataContext: input.props.dataContext,
56144
56327
  blockKey: input.blockKey,
56145
56328
  registry: input.registry,
@@ -56163,7 +56346,6 @@ function getBlockOverride(blockKind, overrides) {
56163
56346
  if (overrides[shortKind]) return overrides[shortKind];
56164
56347
  }
56165
56348
  const blockComponentCache = /* @__PURE__ */ new WeakMap();
56166
- const manifestValidatorCache = /* @__PURE__ */ new WeakMap();
56167
56349
  const DEFAULT_PERF_SLOW_BLOCK_RENDER_THRESHOLD_MS = 25;
56168
56350
  let cachedPerfSlowBlockRenderThresholdMs = null;
56169
56351
  function getPerfSlowBlockRenderThresholdMs() {
@@ -56181,44 +56363,13 @@ function getCachedBlockComponent(manifest) {
56181
56363
  return created;
56182
56364
  }
56183
56365
  /**
56184
- * Render-time manifest validator — see `.claude/plans/dapper-jingling-emerson.md`
56185
- * Phase 10. One function, two flavours:
56186
- *
56187
- * - `strict` (default): the contract every render surface tries first. No
56188
- * null tolerance, no missing-required tolerance. Production frontends and
56189
- * the dashboard preview both go through this path; after Phases 6-9 the
56190
- * preview satisfies strict structurally.
56191
- * - `relaxed`: editor-mid-edit fallback. Reached via `usePlaceholders` when
56192
- * strict fails. Built on `mode: 'draft'` so empty required fields parse
56193
- * as `undefined` and the user's valid in-flight fields flow through.
56194
- *
56195
- * Per-manifest, per-flavour cached. Adding a third flavour means adding a
56196
- * branch to the `createManifestValidator` call below and a member to
56197
- * `ValidationFlavour` — no per-flavour helper duplication.
56198
- */
56199
- function getCachedValidator(manifest, flavour) {
56200
- let perFlavour = manifestValidatorCache.get(manifest);
56201
- if (!perFlavour) {
56202
- perFlavour = /* @__PURE__ */ new Map();
56203
- manifestValidatorCache.set(manifest, perFlavour);
56204
- }
56205
- const cached = perFlavour.get(flavour);
56206
- if (cached) return cached;
56207
- const created = createManifestValidator(manifest, {
56208
- allowNull: false,
56209
- ...flavour === "relaxed" ? { mode: "draft" } : {}
56210
- });
56211
- perFlavour.set(flavour, created);
56212
- return created;
56213
- }
56214
- /**
56215
56366
  * Memoized block section component.
56216
56367
  *
56217
56368
  * Custom memoization prevents render loops during editing by explicitly checking
56218
56369
  * referential equality of all props that affect rendering. Standard React.memo
56219
56370
  * wouldn't catch all the render triggers from the editor store.
56220
56371
  */
56221
- const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeResources, block, usePlaceholders, dataContext, registry, routeMap, wrapBlock, blockOverrides, sdkConfig, customBlocks, imageResolveContext, previewAuthoring }) {
56372
+ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeResources, block, dataContext, registry, routeMap, wrapBlock, blockOverrides, sdkConfig, customBlocks, imageResolveContext, previewAuthoring }) {
56222
56373
  const perfStart = globalThis.process?.env?.DEBUG_PERF === "1" && typeof window === "undefined" ? Date.now() : 0;
56223
56374
  const fallbackImageResolveContext = getCurrentResolveImageUrlContext();
56224
56375
  const resolvedImageResolveContext = imageResolveContext ?? fallbackImageResolveContext;
@@ -56238,6 +56389,19 @@ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeResources
56238
56389
  } catch {}
56239
56390
  return node;
56240
56391
  }
56392
+ if (block.presentationAdmission.kind === "invalid") {
56393
+ try {
56394
+ if (globalThis.process?.env?.NODE_ENV !== "production") console.warn("[blocks:PageRenderer] block admission failed", {
56395
+ blockId: block.id ?? null,
56396
+ blockKind: block.kind,
56397
+ error: block.presentationAdmission.error
56398
+ });
56399
+ } catch {}
56400
+ return finish(fallback(`Invalid content for block kind "${block.kind}".`), {
56401
+ outcome: "invalidContent",
56402
+ override: false
56403
+ });
56404
+ }
56241
56405
  const OverrideComponent = getBlockOverride(block.kind, blockOverrides);
56242
56406
  requireBlockOverride(themeResources, OverrideComponent, block.kind);
56243
56407
  let definition = getBlockDefinition(block.kind);
@@ -56307,25 +56471,10 @@ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeResources
56307
56471
  });
56308
56472
  }
56309
56473
  const content = getRenderableContent(block, dataContext?.previewStage);
56310
- const parsed = getCachedValidator(definition.manifest, "strict").safeParse(content);
56311
- try {
56312
- if (globalThis.process?.env?.NODE_ENV !== "production" && !parsed.success && !usePlaceholders) console.warn("[blocks:PageRenderer] manifest validation failed", {
56313
- blockId: block.id ?? null,
56314
- blockKind: block.kind,
56315
- content: summarizeValue(content),
56316
- expectedFields: (definition.manifest.fields ?? []).map((f) => ({
56317
- id: f.id,
56318
- type: f.type,
56319
- required: !!f.required
56320
- })),
56321
- issues: parsed.error?.issues ?? null
56322
- });
56323
- } catch {}
56324
- let data;
56325
- if (parsed.success) data = parsed.data;
56326
- else if (usePlaceholders) {
56327
- const relaxed = getCachedValidator(definition.manifest, "relaxed").safeParse(content);
56328
- if (relaxed.success) data = relaxed.data;
56474
+ let data = content;
56475
+ if (block.presentationAdmission.kind === "editor") {
56476
+ const draft = validateManifestDraft(compileManifestContentContract(definition.manifest), content);
56477
+ if (draft.kind === "previewable") data = draft.data;
56329
56478
  else {
56330
56479
  const rendered = fallback(`Unable to render block kind "${block.kind}".`);
56331
56480
  return finish(wrapBlock && block.id ? /* @__PURE__ */ jsx(Fragment, { children: wrapBlock(block.id, rendered) }) : /* @__PURE__ */ jsx(Fragment, { children: rendered }), {
@@ -56333,12 +56482,6 @@ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeResources
56333
56482
  override: false
56334
56483
  });
56335
56484
  }
56336
- } else {
56337
- const rendered = fallback(`Invalid content for block kind "${block.kind}".`);
56338
- return finish(wrapBlock && block.id ? /* @__PURE__ */ jsx(Fragment, { children: wrapBlock(block.id, rendered) }) : /* @__PURE__ */ jsx(Fragment, { children: rendered }), {
56339
- outcome: "invalidContent",
56340
- override: false
56341
- });
56342
56485
  }
56343
56486
  try {
56344
56487
  const routes = routeMap ?? dataContext?.routes;
@@ -56364,6 +56507,7 @@ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeResources
56364
56507
  blockId: block.id ?? null,
56365
56508
  blockKind: block.kind
56366
56509
  };
56510
+ baseProps.bookingTimeZone = resolveBookingTimeZone(dataContext);
56367
56511
  let rendered;
56368
56512
  if (OverrideComponent) rendered = /* @__PURE__ */ jsx(OverrideComponent, { ...baseProps });
56369
56513
  else {
@@ -56410,14 +56554,14 @@ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeResources
56410
56554
  hasResolvedData
56411
56555
  });
56412
56556
  } catch {
56413
- const rendered = usePlaceholders ? fallback(`Unable to render block kind "${block.kind}".`) : fallback(`Invalid content for block kind "${block.kind}".`);
56557
+ const rendered = block.presentationAdmission.kind === "editor" ? fallback(`Unable to render block kind "${block.kind}".`) : fallback(`Invalid content for block kind "${block.kind}".`);
56414
56558
  return finish(wrapBlock && block.id ? /* @__PURE__ */ jsx(Fragment, { children: wrapBlock(block.id, rendered) }) : /* @__PURE__ */ jsx(Fragment, { children: rendered }), {
56415
56559
  outcome: "exception",
56416
56560
  override: false
56417
56561
  });
56418
56562
  }
56419
56563
  }, (prev, next) => {
56420
- 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;
56564
+ 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;
56421
56565
  });
56422
56566
  function fallback(message) {
56423
56567
  return /* @__PURE__ */ jsx("div", {
@@ -56444,32 +56588,6 @@ function getRenderableContent(block, previewStage = "published") {
56444
56588
  if (!isObjectRecord$1(source)) return {};
56445
56589
  return source;
56446
56590
  }
56447
- function summarizeValue(value) {
56448
- try {
56449
- if (value === null || value === void 0) return value;
56450
- if (typeof value === "string") return value.length > 160 ? `${value.slice(0, 160)}…` : value;
56451
- if (typeof value === "number" || typeof value === "boolean") return value;
56452
- if (Array.isArray(value)) return `[array(${value.length})]`;
56453
- if (typeof value === "object") {
56454
- const rec = value;
56455
- const keys = Object.keys(rec);
56456
- const preview = {};
56457
- for (const k of keys.slice(0, 8)) {
56458
- const v = rec[k];
56459
- if (k === "body" || k === "content") preview[k] = !!(v && typeof v === "object" && isObjectRecord$1(v) && v.type === "doc") ? "{type:doc}" : summarizeValue(v);
56460
- else preview[k] = summarizeValue(v);
56461
- }
56462
- return {
56463
- keys,
56464
- preview
56465
- };
56466
- }
56467
- if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint" || typeof value === "symbol") return String(value);
56468
- return "[uninspectable]";
56469
- } catch {
56470
- return "[uninspectable]";
56471
- }
56472
- }
56473
56591
  //#endregion
56474
56592
  //#region ../theme-core/src/generated/containerResponsiveThemeCss.ts
56475
56593
  /**
@@ -63066,31 +63184,37 @@ const containerResponsiveThemeCss = `/*
63066
63184
  */
63067
63185
 
63068
63186
  /* Main container */
63069
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar {
63187
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-calendar {
63070
63188
  width: 100%;
63071
63189
  }
63072
63190
 
63073
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-container {
63191
+ :where(.theme-scope)
63192
+ :where([data-block='event-calendar'])
63193
+ .event-calendar-container {
63074
63194
  border: 1px solid var(--ec-border);
63075
63195
  border-radius: var(--rb-block-radius);
63076
63196
  overflow: hidden;
63077
63197
  }
63078
63198
 
63079
63199
  /* Calendar navigation */
63080
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-header {
63200
+ :where(.theme-scope)
63201
+ :where([data-block='event-calendar'])
63202
+ .event-calendar-header {
63081
63203
  display: flex;
63082
63204
  align-items: center;
63083
63205
  justify-content: space-between;
63084
63206
  margin-bottom: 1rem;
63085
63207
  }
63086
63208
 
63087
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-nav {
63209
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-calendar-nav {
63088
63210
  display: flex;
63089
63211
  align-items: center;
63090
63212
  gap: 0.5rem;
63091
63213
  }
63092
63214
 
63093
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-nav-btn {
63215
+ :where(.theme-scope)
63216
+ :where([data-block='event-calendar'])
63217
+ .event-calendar-nav-btn {
63094
63218
  display: flex;
63095
63219
  align-items: center;
63096
63220
  justify-content: center;
@@ -63105,11 +63229,15 @@ const containerResponsiveThemeCss = `/*
63105
63229
  transition: background-color var(--rb-block-transition) ease;
63106
63230
  }
63107
63231
 
63108
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-nav-btn:hover {
63232
+ :where(.theme-scope)
63233
+ :where([data-block='event-calendar'])
63234
+ .event-calendar-nav-btn:hover {
63109
63235
  background-color: var(--ec-nav-hover-bg);
63110
63236
  }
63111
63237
 
63112
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-title {
63238
+ :where(.theme-scope)
63239
+ :where([data-block='event-calendar'])
63240
+ .event-calendar-title {
63113
63241
  font-size: 1.125rem;
63114
63242
  font-weight: 600;
63115
63243
  min-width: 200px;
@@ -63117,13 +63245,17 @@ const containerResponsiveThemeCss = `/*
63117
63245
  }
63118
63246
 
63119
63247
  /* Day headers */
63120
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-day-headers {
63248
+ :where(.theme-scope)
63249
+ :where([data-block='event-calendar'])
63250
+ .event-calendar-day-headers {
63121
63251
  display: grid;
63122
63252
  grid-template-columns: repeat(7, minmax(0, 1fr));
63123
63253
  background-color: var(--ec-header-bg);
63124
63254
  }
63125
63255
 
63126
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-day-header {
63256
+ :where(.theme-scope)
63257
+ :where([data-block='event-calendar'])
63258
+ .event-calendar-day-header {
63127
63259
  text-align: center;
63128
63260
  padding: 0.5rem;
63129
63261
  font-size: 0.875rem;
@@ -63133,33 +63265,43 @@ const containerResponsiveThemeCss = `/*
63133
63265
  }
63134
63266
 
63135
63267
  /* Calendar grid */
63136
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-grid {
63268
+ :where(.theme-scope)
63269
+ :where([data-block='event-calendar'])
63270
+ .event-calendar-grid {
63137
63271
  display: grid;
63138
63272
  grid-template-columns: repeat(7, minmax(0, 1fr));
63139
63273
  }
63140
63274
 
63141
63275
  /* Day cells */
63142
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-day {
63276
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-calendar-day {
63143
63277
  min-height: 100px;
63144
63278
  border-bottom: 1px solid var(--ec-border-subtle);
63145
63279
  border-right: 1px solid var(--ec-border-subtle);
63146
63280
  padding: 0.25rem;
63147
63281
  }
63148
63282
 
63149
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-day:nth-child(7n) {
63283
+ :where(.theme-scope)
63284
+ :where([data-block='event-calendar'])
63285
+ .event-calendar-day:nth-child(7n) {
63150
63286
  border-right: none;
63151
63287
  }
63152
63288
 
63153
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-day--today {
63289
+ :where(.theme-scope)
63290
+ :where([data-block='event-calendar'])
63291
+ .event-calendar-day--today {
63154
63292
  background-color: var(--ec-today-bg);
63155
63293
  }
63156
63294
 
63157
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-day--other-month {
63295
+ :where(.theme-scope)
63296
+ :where([data-block='event-calendar'])
63297
+ .event-calendar-day--other-month {
63158
63298
  opacity: var(--ec-other-month-opacity);
63159
63299
  }
63160
63300
 
63161
63301
  /* Day number */
63162
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-day-number {
63302
+ :where(.theme-scope)
63303
+ :where([data-block='event-calendar'])
63304
+ .event-calendar-day-number {
63163
63305
  font-size: 0.875rem;
63164
63306
  font-weight: 500;
63165
63307
  margin-bottom: 0.25rem;
@@ -63167,21 +63309,28 @@ const containerResponsiveThemeCss = `/*
63167
63309
  opacity: var(--ec-day-number-opacity);
63168
63310
  }
63169
63311
 
63170
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-day--today .event-calendar-day-number {
63312
+ :where(.theme-scope)
63313
+ :where([data-block='event-calendar'])
63314
+ .event-calendar-day--today
63315
+ .event-calendar-day-number {
63171
63316
  font-weight: 700;
63172
63317
  opacity: 1;
63173
63318
  color: var(--ec-today-text);
63174
63319
  }
63175
63320
 
63176
63321
  /* Events list */
63177
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-events {
63322
+ :where(.theme-scope)
63323
+ :where([data-block='event-calendar'])
63324
+ .event-calendar-events {
63178
63325
  display: flex;
63179
63326
  flex-direction: column;
63180
63327
  gap: 0.25rem;
63181
63328
  }
63182
63329
 
63183
63330
  /* Event item - solid primary background */
63184
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-event {
63331
+ :where(.theme-scope)
63332
+ :where([data-block='event-calendar'])
63333
+ .event-calendar-event {
63185
63334
  display: flex;
63186
63335
  align-items: center;
63187
63336
  gap: 0.375rem;
@@ -63202,24 +63351,32 @@ const containerResponsiveThemeCss = `/*
63202
63351
  transform var(--rb-block-transition) ease;
63203
63352
  }
63204
63353
 
63205
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-event:hover {
63354
+ :where(.theme-scope)
63355
+ :where([data-block='event-calendar'])
63356
+ .event-calendar-event:hover {
63206
63357
  background-color: var(--ec-event-solid-hover-bg);
63207
63358
  transform: translateY(-1px);
63208
63359
  }
63209
63360
 
63210
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-event:focus-visible {
63361
+ :where(.theme-scope)
63362
+ :where([data-block='event-calendar'])
63363
+ .event-calendar-event:focus-visible {
63211
63364
  outline: 2px solid var(--ec-event-solid-bg);
63212
63365
  outline-offset: 2px;
63213
63366
  }
63214
63367
 
63215
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-event-time {
63368
+ :where(.theme-scope)
63369
+ :where([data-block='event-calendar'])
63370
+ .event-calendar-event-time {
63216
63371
  flex-shrink: 0;
63217
63372
  white-space: nowrap;
63218
63373
  font-weight: 600;
63219
63374
  opacity: 0.9;
63220
63375
  }
63221
63376
 
63222
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-event-title {
63377
+ :where(.theme-scope)
63378
+ :where([data-block='event-calendar'])
63379
+ .event-calendar-event-title {
63223
63380
  min-width: 0;
63224
63381
  overflow: hidden;
63225
63382
  text-overflow: ellipsis;
@@ -63227,7 +63384,9 @@ const containerResponsiveThemeCss = `/*
63227
63384
  }
63228
63385
 
63229
63386
  /* More indicator - clickable button style */
63230
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-more {
63387
+ :where(.theme-scope)
63388
+ :where([data-block='event-calendar'])
63389
+ .event-calendar-more {
63231
63390
  font-size: 0.75rem;
63232
63391
  padding: 0.25rem 0.5rem;
63233
63392
  color: rgb(var(--tb-primary));
@@ -63239,16 +63398,22 @@ const containerResponsiveThemeCss = `/*
63239
63398
  transition: background-color var(--rb-block-transition) ease;
63240
63399
  }
63241
63400
 
63242
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-more:hover {
63401
+ :where(.theme-scope)
63402
+ :where([data-block='event-calendar'])
63403
+ .event-calendar-more:hover {
63243
63404
  background-color: rgba(var(--tb-primary), 0.1);
63244
63405
  }
63245
63406
 
63246
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-more:focus-visible {
63407
+ :where(.theme-scope)
63408
+ :where([data-block='event-calendar'])
63409
+ .event-calendar-more:focus-visible {
63247
63410
  outline: 2px solid rgb(var(--tb-primary));
63248
63411
  outline-offset: 2px;
63249
63412
  }
63250
63413
 
63251
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-empty {
63414
+ :where(.theme-scope)
63415
+ :where([data-block='event-calendar'])
63416
+ .event-calendar-empty {
63252
63417
  text-align: center;
63253
63418
  font-size: 0.875rem;
63254
63419
  opacity: var(--ec-empty-opacity);
@@ -63256,21 +63421,21 @@ const containerResponsiveThemeCss = `/*
63256
63421
  }
63257
63422
 
63258
63423
  /* Filters container */
63259
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-filters {
63424
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-filters {
63260
63425
  display: flex;
63261
63426
  flex-wrap: wrap;
63262
63427
  gap: 1rem;
63263
63428
  margin-bottom: 1.5rem;
63264
63429
  }
63265
63430
 
63266
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-filter {
63431
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-filter {
63267
63432
  display: flex;
63268
63433
  flex-direction: column;
63269
63434
  gap: 0.375rem;
63270
63435
  min-width: 180px;
63271
63436
  }
63272
63437
 
63273
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-filter-label {
63438
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-filter-label {
63274
63439
  font-size: 0.75rem;
63275
63440
  font-weight: 500;
63276
63441
  text-transform: uppercase;
@@ -63279,19 +63444,23 @@ const containerResponsiveThemeCss = `/*
63279
63444
  }
63280
63445
 
63281
63446
  /* Event filter select inherits base styling from .form-select, only block-specific overrides here */
63282
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-filter-select {
63447
+ :where(.theme-scope)
63448
+ :where([data-block='event-calendar'])
63449
+ .event-filter-select {
63283
63450
  /* Use theme input radius instead of block radius for consistency with other form inputs */
63284
63451
  border-radius: var(--rb-input-radius, var(--rb-block-radius));
63285
63452
  }
63286
63453
 
63287
63454
  /* Category filter buttons */
63288
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-category-buttons {
63455
+ :where(.theme-scope)
63456
+ :where([data-block='event-calendar'])
63457
+ .event-category-buttons {
63289
63458
  display: flex;
63290
63459
  flex-wrap: wrap;
63291
63460
  gap: 0.5rem;
63292
63461
  }
63293
63462
 
63294
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-category-btn {
63463
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-category-btn {
63295
63464
  padding: 0.5rem 1rem;
63296
63465
  font-size: 0.875rem;
63297
63466
  font-weight: 500;
@@ -63303,50 +63472,66 @@ const containerResponsiveThemeCss = `/*
63303
63472
  transition: all var(--rb-block-transition) ease;
63304
63473
  }
63305
63474
 
63306
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-category-btn:hover:not(:disabled) {
63475
+ :where(.theme-scope)
63476
+ :where([data-block='event-calendar'])
63477
+ .event-category-btn:hover:not(:disabled) {
63307
63478
  border-color: rgba(var(--tb-primary), 0.5);
63308
63479
  }
63309
63480
 
63310
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-category-btn:focus-visible {
63481
+ :where(.theme-scope)
63482
+ :where([data-block='event-calendar'])
63483
+ .event-category-btn:focus-visible {
63311
63484
  outline: 2px solid rgb(var(--tb-primary));
63312
63485
  outline-offset: 2px;
63313
63486
  }
63314
63487
 
63315
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-category-btn--active {
63488
+ :where(.theme-scope)
63489
+ :where([data-block='event-calendar'])
63490
+ .event-category-btn--active {
63316
63491
  background-color: rgb(var(--tb-primary));
63317
63492
  border-color: rgb(var(--tb-primary));
63318
63493
  color: var(--ec-event-solid-text);
63319
63494
  }
63320
63495
 
63321
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-category-btn:disabled {
63496
+ :where(.theme-scope)
63497
+ :where([data-block='event-calendar'])
63498
+ .event-category-btn:disabled {
63322
63499
  opacity: 0.5;
63323
63500
  cursor: not-allowed;
63324
63501
  }
63325
63502
 
63326
63503
  /* Allow category filter to be wider for button group */
63327
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-filter:has(.event-category-buttons) {
63504
+ :where(.theme-scope)
63505
+ :where([data-block='event-calendar'])
63506
+ .event-filter:has(.event-category-buttons) {
63328
63507
  min-width: auto;
63329
63508
  flex: 1 1 auto;
63330
63509
  }
63331
63510
 
63332
63511
  /* Combined mode container */
63333
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-combined {
63512
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-combined {
63334
63513
  width: 100%;
63335
63514
  }
63336
63515
 
63337
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-combined-content {
63516
+ :where(.theme-scope)
63517
+ :where([data-block='event-calendar'])
63518
+ .event-combined-content {
63338
63519
  display: flex;
63339
63520
  flex-direction: column;
63340
63521
  }
63341
63522
 
63342
63523
  /* Calendar view toggle (Month/Week) in Combined mode */
63343
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-view-toggle {
63524
+ :where(.theme-scope)
63525
+ :where([data-block='event-calendar'])
63526
+ .event-calendar-view-toggle {
63344
63527
  display: flex;
63345
63528
  gap: 0.25rem;
63346
63529
  margin-bottom: 1rem;
63347
63530
  }
63348
63531
 
63349
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-view-btn {
63532
+ :where(.theme-scope)
63533
+ :where([data-block='event-calendar'])
63534
+ .event-calendar-view-btn {
63350
63535
  padding: 0.5rem 1rem;
63351
63536
  font-size: 0.875rem;
63352
63537
  font-weight: 500;
@@ -63359,12 +63544,16 @@ const containerResponsiveThemeCss = `/*
63359
63544
  transition: all var(--rb-block-transition) ease;
63360
63545
  }
63361
63546
 
63362
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-view-btn:hover {
63547
+ :where(.theme-scope)
63548
+ :where([data-block='event-calendar'])
63549
+ .event-calendar-view-btn:hover {
63363
63550
  opacity: 1;
63364
63551
  border-color: rgba(var(--tb-primary), 0.5);
63365
63552
  }
63366
63553
 
63367
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-view-btn--active {
63554
+ :where(.theme-scope)
63555
+ :where([data-block='event-calendar'])
63556
+ .event-calendar-view-btn--active {
63368
63557
  opacity: 1;
63369
63558
  background-color: rgb(var(--tb-primary));
63370
63559
  border-color: rgb(var(--tb-primary));
@@ -63377,29 +63566,35 @@ const containerResponsiveThemeCss = `/*
63377
63566
  * ----------------------------------------------------------------------------- */
63378
63567
 
63379
63568
  /* Agenda week container */
63380
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-week {
63569
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-agenda-week {
63381
63570
  display: flex;
63382
63571
  flex-direction: column;
63383
63572
  gap: 0;
63384
63573
  }
63385
63574
 
63386
63575
  /* Individual day section */
63387
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-day {
63576
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-agenda-day {
63388
63577
  border-bottom: 1px solid var(--ec-border-subtle);
63389
63578
  }
63390
63579
 
63391
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-day:last-child {
63580
+ :where(.theme-scope)
63581
+ :where([data-block='event-calendar'])
63582
+ .event-agenda-day:last-child {
63392
63583
  border-bottom: none;
63393
63584
  }
63394
63585
 
63395
63586
  /* Day header */
63396
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-day-header {
63587
+ :where(.theme-scope)
63588
+ :where([data-block='event-calendar'])
63589
+ .event-agenda-day-header {
63397
63590
  padding: 0.75rem 0;
63398
63591
  background-color: var(--ec-header-bg);
63399
63592
  border-bottom: 1px solid var(--ec-border-subtle);
63400
63593
  }
63401
63594
 
63402
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-day-title {
63595
+ :where(.theme-scope)
63596
+ :where([data-block='event-calendar'])
63597
+ .event-agenda-day-title {
63403
63598
  font-size: 0.875rem;
63404
63599
  font-weight: 600;
63405
63600
  margin: 0;
@@ -63409,7 +63604,9 @@ const containerResponsiveThemeCss = `/*
63409
63604
  }
63410
63605
 
63411
63606
  /* Today badge */
63412
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-day-today-badge {
63607
+ :where(.theme-scope)
63608
+ :where([data-block='event-calendar'])
63609
+ .event-agenda-day-today-badge {
63413
63610
  display: inline-flex;
63414
63611
  align-items: center;
63415
63612
  padding: 0.125rem 0.5rem;
@@ -63423,24 +63620,33 @@ const containerResponsiveThemeCss = `/*
63423
63620
  }
63424
63621
 
63425
63622
  /* Today highlight for entire day section */
63426
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-day--today .event-agenda-day-header {
63623
+ :where(.theme-scope)
63624
+ :where([data-block='event-calendar'])
63625
+ .event-agenda-day--today
63626
+ .event-agenda-day-header {
63427
63627
  background-color: var(--ec-today-bg);
63428
63628
  }
63429
63629
 
63430
63630
  /* Day content area */
63431
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-day-content {
63631
+ :where(.theme-scope)
63632
+ :where([data-block='event-calendar'])
63633
+ .event-agenda-day-content {
63432
63634
  padding: 0.75rem 0;
63433
63635
  }
63434
63636
 
63435
63637
  /* Events list within a day */
63436
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-day-events {
63638
+ :where(.theme-scope)
63639
+ :where([data-block='event-calendar'])
63640
+ .event-agenda-day-events {
63437
63641
  display: flex;
63438
63642
  flex-direction: column;
63439
63643
  gap: 0.5rem;
63440
63644
  }
63441
63645
 
63442
63646
  /* Empty day message */
63443
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-day-empty {
63647
+ :where(.theme-scope)
63648
+ :where([data-block='event-calendar'])
63649
+ .event-agenda-day-empty {
63444
63650
  font-size: 0.875rem;
63445
63651
  opacity: var(--ec-empty-opacity);
63446
63652
  margin: 0;
@@ -63452,7 +63658,7 @@ const containerResponsiveThemeCss = `/*
63452
63658
  * Rich event card for agenda view
63453
63659
  * ----------------------------------------------------------------------------- */
63454
63660
 
63455
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-card {
63661
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-agenda-card {
63456
63662
  display: flex;
63457
63663
  align-items: flex-start;
63458
63664
  gap: 0.75rem;
@@ -63465,13 +63671,17 @@ const containerResponsiveThemeCss = `/*
63465
63671
  transition: all var(--rb-block-transition) ease;
63466
63672
  }
63467
63673
 
63468
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-card:hover {
63674
+ :where(.theme-scope)
63675
+ :where([data-block='event-calendar'])
63676
+ .event-agenda-card:hover {
63469
63677
  border-color: rgba(var(--tb-primary), 0.5);
63470
63678
  background-color: var(--ec-event-bg);
63471
63679
  }
63472
63680
 
63473
63681
  /* Category color indicator */
63474
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-card-indicator {
63682
+ :where(.theme-scope)
63683
+ :where([data-block='event-calendar'])
63684
+ .event-agenda-card-indicator {
63475
63685
  flex-shrink: 0;
63476
63686
  width: 4px;
63477
63687
  align-self: stretch;
@@ -63480,7 +63690,9 @@ const containerResponsiveThemeCss = `/*
63480
63690
  }
63481
63691
 
63482
63692
  /* Card content wrapper */
63483
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-card-content {
63693
+ :where(.theme-scope)
63694
+ :where([data-block='event-calendar'])
63695
+ .event-agenda-card-content {
63484
63696
  flex: 1;
63485
63697
  min-width: 0;
63486
63698
  display: flex;
@@ -63489,28 +63701,36 @@ const containerResponsiveThemeCss = `/*
63489
63701
  }
63490
63702
 
63491
63703
  /* Header row: time + title */
63492
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-card-header {
63704
+ :where(.theme-scope)
63705
+ :where([data-block='event-calendar'])
63706
+ .event-agenda-card-header {
63493
63707
  display: flex;
63494
63708
  align-items: baseline;
63495
63709
  gap: 0.5rem;
63496
63710
  flex-wrap: wrap;
63497
63711
  }
63498
63712
 
63499
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-card-time {
63713
+ :where(.theme-scope)
63714
+ :where([data-block='event-calendar'])
63715
+ .event-agenda-card-time {
63500
63716
  font-size: 0.75rem;
63501
63717
  font-weight: 600;
63502
63718
  opacity: var(--ec-time-opacity);
63503
63719
  white-space: nowrap;
63504
63720
  }
63505
63721
 
63506
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-card-title {
63722
+ :where(.theme-scope)
63723
+ :where([data-block='event-calendar'])
63724
+ .event-agenda-card-title {
63507
63725
  font-size: 0.875rem;
63508
63726
  font-weight: 500;
63509
63727
  line-height: 1.3;
63510
63728
  }
63511
63729
 
63512
63730
  /* Details row: venue, price, capacity */
63513
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-card-details {
63731
+ :where(.theme-scope)
63732
+ :where([data-block='event-calendar'])
63733
+ .event-agenda-card-details {
63514
63734
  display: flex;
63515
63735
  align-items: center;
63516
63736
  gap: 0.75rem;
@@ -63519,26 +63739,36 @@ const containerResponsiveThemeCss = `/*
63519
63739
  opacity: 0.7;
63520
63740
  }
63521
63741
 
63522
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-card-venue {
63742
+ :where(.theme-scope)
63743
+ :where([data-block='event-calendar'])
63744
+ .event-agenda-card-venue {
63523
63745
  display: inline-flex;
63524
63746
  align-items: center;
63525
63747
  gap: 0.25rem;
63526
63748
  }
63527
63749
 
63528
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-card-icon {
63750
+ :where(.theme-scope)
63751
+ :where([data-block='event-calendar'])
63752
+ .event-agenda-card-icon {
63529
63753
  flex-shrink: 0;
63530
63754
  opacity: 0.7;
63531
63755
  }
63532
63756
 
63533
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-card-price {
63757
+ :where(.theme-scope)
63758
+ :where([data-block='event-calendar'])
63759
+ .event-agenda-card-price {
63534
63760
  font-weight: 500;
63535
63761
  }
63536
63762
 
63537
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-card-capacity {
63763
+ :where(.theme-scope)
63764
+ :where([data-block='event-calendar'])
63765
+ .event-agenda-card-capacity {
63538
63766
  font-weight: 500;
63539
63767
  }
63540
63768
 
63541
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-card-capacity--full {
63769
+ :where(.theme-scope)
63770
+ :where([data-block='event-calendar'])
63771
+ .event-agenda-card-capacity--full {
63542
63772
  color: rgb(var(--tb-error, 239 68 68));
63543
63773
  opacity: 1;
63544
63774
  }
@@ -63548,20 +63778,24 @@ const containerResponsiveThemeCss = `/*
63548
63778
  * Time-grid layout for recurring class schedules
63549
63779
  * ----------------------------------------------------------------------------- */
63550
63780
 
63551
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable {
63781
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-timetable {
63552
63782
  display: flex;
63553
63783
  flex-direction: column;
63554
63784
  gap: 0.75rem;
63555
63785
  }
63556
63786
 
63557
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-day-selector {
63787
+ :where(.theme-scope)
63788
+ :where([data-block='event-calendar'])
63789
+ .event-timetable-day-selector {
63558
63790
  display: none;
63559
63791
  gap: 0.375rem;
63560
63792
  overflow-x: auto;
63561
63793
  padding-bottom: 0.125rem;
63562
63794
  }
63563
63795
 
63564
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-day-tab {
63796
+ :where(.theme-scope)
63797
+ :where([data-block='event-calendar'])
63798
+ .event-timetable-day-tab {
63565
63799
  flex: 0 0 auto;
63566
63800
  padding: 0.5rem 0.75rem;
63567
63801
  border: 1px solid var(--ec-border);
@@ -63576,35 +63810,49 @@ const containerResponsiveThemeCss = `/*
63576
63810
  border-color var(--rb-block-transition) ease;
63577
63811
  }
63578
63812
 
63579
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-day-tab--active {
63813
+ :where(.theme-scope)
63814
+ :where([data-block='event-calendar'])
63815
+ .event-timetable-day-tab--active {
63580
63816
  background-color: rgb(var(--tb-primary));
63581
63817
  border-color: rgb(var(--tb-primary));
63582
63818
  color: rgb(var(--tb-primaryText, 255 255 255));
63583
63819
  }
63584
63820
 
63585
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-container {
63821
+ :where(.theme-scope)
63822
+ :where([data-block='event-calendar'])
63823
+ .event-timetable-container {
63586
63824
  border: 1px solid var(--ec-border);
63587
63825
  border-radius: var(--rb-block-radius);
63588
63826
  overflow-x: auto;
63589
63827
  overflow-y: hidden;
63590
63828
  }
63591
63829
 
63592
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-grid {
63830
+ :where(.theme-scope)
63831
+ :where([data-block='event-calendar'])
63832
+ .event-timetable-grid {
63593
63833
  display: grid;
63594
63834
  grid-template-columns: 4.5rem repeat(7, minmax(8rem, 1fr));
63595
63835
  min-width: 62rem;
63596
63836
  }
63597
63837
 
63598
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-time-rail,
63599
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-day {
63838
+ :where(.theme-scope)
63839
+ :where([data-block='event-calendar'])
63840
+ .event-timetable-time-rail,
63841
+ :where(.theme-scope)
63842
+ :where([data-block='event-calendar'])
63843
+ .event-timetable-day {
63600
63844
  border-right: 1px solid var(--ec-border-subtle);
63601
63845
  }
63602
63846
 
63603
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-day:last-child {
63847
+ :where(.theme-scope)
63848
+ :where([data-block='event-calendar'])
63849
+ .event-timetable-day:last-child {
63604
63850
  border-right: none;
63605
63851
  }
63606
63852
 
63607
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-day-heading {
63853
+ :where(.theme-scope)
63854
+ :where([data-block='event-calendar'])
63855
+ .event-timetable-day-heading {
63608
63856
  min-height: 3.25rem;
63609
63857
  margin: 0;
63610
63858
  padding: 0.75rem 0.5rem;
@@ -63619,12 +63867,17 @@ const containerResponsiveThemeCss = `/*
63619
63867
  font-weight: 600;
63620
63868
  }
63621
63869
 
63622
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-day--today .event-timetable-day-heading {
63870
+ :where(.theme-scope)
63871
+ :where([data-block='event-calendar'])
63872
+ .event-timetable-day--today
63873
+ .event-timetable-day-heading {
63623
63874
  background-color: var(--ec-today-bg);
63624
63875
  color: var(--ec-today-text);
63625
63876
  }
63626
63877
 
63627
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-today-badge {
63878
+ :where(.theme-scope)
63879
+ :where([data-block='event-calendar'])
63880
+ .event-timetable-today-badge {
63628
63881
  padding: 0.125rem 0.375rem;
63629
63882
  border-radius: var(--rb-button-radius);
63630
63883
  background-color: rgb(var(--tb-primary));
@@ -63634,17 +63887,29 @@ const containerResponsiveThemeCss = `/*
63634
63887
  text-transform: uppercase;
63635
63888
  }
63636
63889
 
63637
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-time-body,
63638
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-day-body {
63890
+ :where(.theme-scope)
63891
+ :where([data-block='event-calendar'])
63892
+ .event-timetable-time-body,
63893
+ :where(.theme-scope)
63894
+ :where([data-block='event-calendar'])
63895
+ .event-timetable-day-body {
63639
63896
  position: relative;
63640
- height: clamp(34rem, calc(var(--event-timetable-range-minutes, 900) * 0.055rem), 56rem);
63897
+ height: clamp(
63898
+ 34rem,
63899
+ calc(var(--event-timetable-range-minutes, 900) * 0.055rem),
63900
+ 56rem
63901
+ );
63641
63902
  }
63642
63903
 
63643
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-time-body {
63904
+ :where(.theme-scope)
63905
+ :where([data-block='event-calendar'])
63906
+ .event-timetable-time-body {
63644
63907
  background-color: var(--ec-header-bg);
63645
63908
  }
63646
63909
 
63647
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-time-label {
63910
+ :where(.theme-scope)
63911
+ :where([data-block='event-calendar'])
63912
+ .event-timetable-time-label {
63648
63913
  position: absolute;
63649
63914
  left: 0.625rem;
63650
63915
  transform: translateY(-50%);
@@ -63653,14 +63918,18 @@ const containerResponsiveThemeCss = `/*
63653
63918
  white-space: nowrap;
63654
63919
  }
63655
63920
 
63656
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-hour-line {
63921
+ :where(.theme-scope)
63922
+ :where([data-block='event-calendar'])
63923
+ .event-timetable-hour-line {
63657
63924
  position: absolute;
63658
63925
  left: 0;
63659
63926
  right: 0;
63660
63927
  border-top: 1px solid var(--ec-border-subtle);
63661
63928
  }
63662
63929
 
63663
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event {
63930
+ :where(.theme-scope)
63931
+ :where([data-block='event-calendar'])
63932
+ .event-timetable-event {
63664
63933
  position: absolute;
63665
63934
  min-height: 2.75rem;
63666
63935
  padding: 0.375rem 0.5rem;
@@ -63680,21 +63949,35 @@ const containerResponsiveThemeCss = `/*
63680
63949
  transform var(--rb-block-transition) ease;
63681
63950
  }
63682
63951
 
63683
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event:hover {
63952
+ :where(.theme-scope)
63953
+ :where([data-block='event-calendar'])
63954
+ .event-timetable-event:hover {
63684
63955
  box-shadow: 0 4px 12px rgba(var(--tb-text), 0.12);
63685
63956
  transform: translateY(-1px);
63686
63957
  }
63687
63958
 
63688
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event:focus-visible {
63959
+ :where(.theme-scope)
63960
+ :where([data-block='event-calendar'])
63961
+ .event-timetable-event:focus-visible {
63689
63962
  outline: 2px solid rgb(var(--tb-primary));
63690
63963
  outline-offset: 2px;
63691
63964
  }
63692
63965
 
63693
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event-time,
63694
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event-title,
63695
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event-teacher,
63696
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event-meta,
63697
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event-capacity {
63966
+ :where(.theme-scope)
63967
+ :where([data-block='event-calendar'])
63968
+ .event-timetable-event-time,
63969
+ :where(.theme-scope)
63970
+ :where([data-block='event-calendar'])
63971
+ .event-timetable-event-title,
63972
+ :where(.theme-scope)
63973
+ :where([data-block='event-calendar'])
63974
+ .event-timetable-event-teacher,
63975
+ :where(.theme-scope)
63976
+ :where([data-block='event-calendar'])
63977
+ .event-timetable-event-meta,
63978
+ :where(.theme-scope)
63979
+ :where([data-block='event-calendar'])
63980
+ .event-timetable-event-capacity {
63698
63981
  display: block;
63699
63982
  min-width: 0;
63700
63983
  overflow: hidden;
@@ -63702,36 +63985,50 @@ const containerResponsiveThemeCss = `/*
63702
63985
  white-space: nowrap;
63703
63986
  }
63704
63987
 
63705
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event-time {
63988
+ :where(.theme-scope)
63989
+ :where([data-block='event-calendar'])
63990
+ .event-timetable-event-time {
63706
63991
  font-size: 0.6875rem;
63707
63992
  font-weight: 700;
63708
63993
  opacity: var(--ec-time-opacity);
63709
63994
  }
63710
63995
 
63711
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event-title {
63996
+ :where(.theme-scope)
63997
+ :where([data-block='event-calendar'])
63998
+ .event-timetable-event-title {
63712
63999
  font-size: 0.8125rem;
63713
64000
  font-weight: 700;
63714
64001
  line-height: 1.25;
63715
64002
  }
63716
64003
 
63717
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event-teacher,
63718
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event-meta {
64004
+ :where(.theme-scope)
64005
+ :where([data-block='event-calendar'])
64006
+ .event-timetable-event-teacher,
64007
+ :where(.theme-scope)
64008
+ :where([data-block='event-calendar'])
64009
+ .event-timetable-event-meta {
63719
64010
  font-size: 0.6875rem;
63720
64011
  opacity: 0.72;
63721
64012
  }
63722
64013
 
63723
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event-capacity {
64014
+ :where(.theme-scope)
64015
+ :where([data-block='event-calendar'])
64016
+ .event-timetable-event-capacity {
63724
64017
  font-size: 0.6875rem;
63725
64018
  font-weight: 600;
63726
64019
  opacity: 0.85;
63727
64020
  }
63728
64021
 
63729
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event-capacity--full {
64022
+ :where(.theme-scope)
64023
+ :where([data-block='event-calendar'])
64024
+ .event-timetable-event-capacity--full {
63730
64025
  color: rgb(var(--tb-danger, 220 38 38));
63731
64026
  opacity: 1;
63732
64027
  }
63733
64028
 
63734
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-day-empty {
64029
+ :where(.theme-scope)
64030
+ :where([data-block='event-calendar'])
64031
+ .event-timetable-day-empty {
63735
64032
  margin: 0;
63736
64033
  padding: 1rem 0.5rem;
63737
64034
  text-align: center;
@@ -63739,7 +64036,9 @@ const containerResponsiveThemeCss = `/*
63739
64036
  opacity: var(--ec-empty-opacity);
63740
64037
  }
63741
64038
 
63742
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-empty {
64039
+ :where(.theme-scope)
64040
+ :where([data-block='event-calendar'])
64041
+ .event-timetable-empty {
63743
64042
  margin: 0.25rem 0 0;
63744
64043
  text-align: center;
63745
64044
  font-size: 0.875rem;
@@ -63748,32 +64047,46 @@ const containerResponsiveThemeCss = `/*
63748
64047
 
63749
64048
  @container rb-site (max-width: 767px) {
63750
64049
  @scope ([data-rb-responsive-mode="container"]) to (:scope [data-rb-responsive-mode]) {
63751
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-day-selector {
64050
+ :where(.theme-scope)
64051
+ :where([data-block='event-calendar'])
64052
+ .event-timetable-day-selector {
63752
64053
  display: flex;
63753
64054
  }
63754
64055
 
63755
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-container {
64056
+ :where(.theme-scope)
64057
+ :where([data-block='event-calendar'])
64058
+ .event-timetable-container {
63756
64059
  overflow: hidden;
63757
64060
  }
63758
64061
 
63759
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-grid {
64062
+ :where(.theme-scope)
64063
+ :where([data-block='event-calendar'])
64064
+ .event-timetable-grid {
63760
64065
  grid-template-columns: 4rem minmax(0, 1fr);
63761
64066
  min-width: 0;
63762
64067
  }
63763
64068
 
63764
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-day[data-selected="false"] {
64069
+ :where(.theme-scope)
64070
+ :where([data-block='event-calendar'])
64071
+ .event-timetable-day[data-selected='false'] {
63765
64072
  display: none;
63766
64073
  }
63767
64074
 
63768
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-day {
64075
+ :where(.theme-scope)
64076
+ :where([data-block='event-calendar'])
64077
+ .event-timetable-day {
63769
64078
  border-right: none;
63770
64079
  }
63771
64080
 
63772
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-time-rail {
64081
+ :where(.theme-scope)
64082
+ :where([data-block='event-calendar'])
64083
+ .event-timetable-time-rail {
63773
64084
  border-right: 1px solid var(--ec-border-subtle);
63774
64085
  }
63775
64086
 
63776
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-day-heading {
64087
+ :where(.theme-scope)
64088
+ :where([data-block='event-calendar'])
64089
+ .event-timetable-day-heading {
63777
64090
  justify-content: flex-start;
63778
64091
  padding-inline: 0.75rem;
63779
64092
  }
@@ -63786,7 +64099,7 @@ const containerResponsiveThemeCss = `/*
63786
64099
  * three-state availability (available / filling / waitlist), and a footer CTA.
63787
64100
  * ----------------------------------------------------------------------------- */
63788
64101
 
63789
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board {
64102
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-week-board {
63790
64103
  /* Status accent tokens — map the three availability states onto theme colours.
63791
64104
  * available -> secondary, filling -> accent, waitlist -> muted text. */
63792
64105
  --ec-status-available: rgb(var(--tb-secondary));
@@ -63803,17 +64116,20 @@ const containerResponsiveThemeCss = `/*
63803
64116
 
63804
64117
  /* Opt-in raised look: a soft drop shadow so the board lifts off the page.
63805
64118
  * Generic default (no [data-elevated]) stays flat. */
63806
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board[data-elevated] {
64119
+ :where(.theme-scope)
64120
+ :where([data-block='event-calendar'])
64121
+ .event-week-board[data-elevated] {
63807
64122
  box-shadow: 0 14px 34px -24px rgba(var(--tb-text), 0.35);
63808
64123
  }
63809
64124
 
63810
- /* Top bar: title + legend */
63811
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-top {
63812
- display: flex;
64125
+ /* Top bar: authored title + week navigation + legend */
64126
+ :where(.theme-scope)
64127
+ :where([data-block='event-calendar'])
64128
+ .event-week-board-top {
64129
+ display: grid;
64130
+ grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
63813
64131
  align-items: center;
63814
- justify-content: space-between;
63815
64132
  gap: 1rem;
63816
- flex-wrap: wrap;
63817
64133
  padding: 1.1rem 1.5rem;
63818
64134
  /* surfaceAlt gives the header/footer a legible tint against the white day-grid
63819
64135
  * body — the faint \`--ec-header-bg\` (5% text) is invisible on light palettes. */
@@ -63821,7 +64137,10 @@ const containerResponsiveThemeCss = `/*
63821
64137
  border-bottom: 1px solid var(--ec-border-subtle);
63822
64138
  }
63823
64139
 
63824
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-title {
64140
+ :where(.theme-scope)
64141
+ :where([data-block='event-calendar'])
64142
+ .event-week-board-title {
64143
+ grid-column: 1;
63825
64144
  font-size: 0.8125rem;
63826
64145
  font-weight: 600;
63827
64146
  letter-spacing: 0.12em;
@@ -63829,7 +64148,67 @@ const containerResponsiveThemeCss = `/*
63829
64148
  color: rgb(var(--tb-primary));
63830
64149
  }
63831
64150
 
63832
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-legend {
64151
+ :where(.theme-scope)
64152
+ :where([data-block='event-calendar'])
64153
+ .event-week-board-navigation {
64154
+ grid-column: 2;
64155
+ display: flex;
64156
+ align-items: center;
64157
+ justify-content: center;
64158
+ gap: 0.65rem;
64159
+ }
64160
+
64161
+ :where(.theme-scope)
64162
+ :where([data-block='event-calendar'])
64163
+ .event-week-board-nav-button {
64164
+ display: inline-flex;
64165
+ align-items: center;
64166
+ justify-content: center;
64167
+ width: 2.25rem;
64168
+ height: 2.25rem;
64169
+ padding: 0;
64170
+ border: 1px solid var(--ec-border);
64171
+ border-radius: 999px;
64172
+ background: transparent;
64173
+ color: inherit;
64174
+ cursor: pointer;
64175
+ }
64176
+
64177
+ :where(.theme-scope)
64178
+ :where([data-block='event-calendar'])
64179
+ .event-week-board-nav-button:hover {
64180
+ background-color: var(--ec-hover-bg);
64181
+ }
64182
+
64183
+ :where(.theme-scope)
64184
+ :where([data-block='event-calendar'])
64185
+ .event-week-board-nav-button:focus-visible {
64186
+ outline: 2px solid rgb(var(--tb-primary));
64187
+ outline-offset: 2px;
64188
+ }
64189
+
64190
+ :where(.theme-scope)
64191
+ :where([data-block='event-calendar'])
64192
+ .event-week-board-range {
64193
+ min-width: 12rem;
64194
+ margin: 0;
64195
+ text-align: center;
64196
+ font-size: 0.875rem;
64197
+ font-weight: 600;
64198
+ }
64199
+
64200
+ :where(.theme-scope)
64201
+ :where([data-block='event-calendar'])
64202
+ .event-week-board-loading {
64203
+ font-weight: 400;
64204
+ opacity: 0.65;
64205
+ }
64206
+
64207
+ :where(.theme-scope)
64208
+ :where([data-block='event-calendar'])
64209
+ .event-week-board-legend {
64210
+ grid-column: 3;
64211
+ justify-self: end;
63833
64212
  display: flex;
63834
64213
  align-items: center;
63835
64214
  gap: 1.1rem;
@@ -63839,38 +64218,72 @@ const containerResponsiveThemeCss = `/*
63839
64218
  opacity: 0.75;
63840
64219
  }
63841
64220
 
63842
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-legend-item {
64221
+ :where(.theme-scope)
64222
+ :where([data-block='event-calendar'])
64223
+ .event-week-board-error {
64224
+ display: flex;
64225
+ align-items: center;
64226
+ justify-content: center;
64227
+ gap: 0.75rem;
64228
+ padding: 0.75rem 1.5rem;
64229
+ border-bottom: 1px solid var(--ec-border-subtle);
64230
+ color: rgb(var(--tb-error, var(--tb-text)));
64231
+ }
64232
+
64233
+ :where(.theme-scope)
64234
+ :where([data-block='event-calendar'])
64235
+ .event-week-board-error
64236
+ p {
64237
+ margin: 0;
64238
+ font-size: 0.8125rem;
64239
+ }
64240
+
64241
+ :where(.theme-scope)
64242
+ :where([data-block='event-calendar'])
64243
+ .event-week-board-legend-item {
63843
64244
  display: inline-flex;
63844
64245
  align-items: center;
63845
64246
  gap: 0.4rem;
63846
64247
  }
63847
64248
 
63848
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-legend-dot {
64249
+ :where(.theme-scope)
64250
+ :where([data-block='event-calendar'])
64251
+ .event-week-board-legend-dot {
63849
64252
  width: 0.55rem;
63850
64253
  height: 0.55rem;
63851
64254
  border-radius: 50%;
63852
64255
  display: inline-block;
63853
64256
  }
63854
64257
 
63855
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-legend-dot[data-status="available"] {
64258
+ :where(.theme-scope)
64259
+ :where([data-block='event-calendar'])
64260
+ .event-week-board-legend-dot[data-status='available'] {
63856
64261
  background-color: var(--ec-status-available);
63857
64262
  }
63858
64263
 
63859
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-legend-dot[data-status="filling"] {
64264
+ :where(.theme-scope)
64265
+ :where([data-block='event-calendar'])
64266
+ .event-week-board-legend-dot[data-status='filling'] {
63860
64267
  background-color: var(--ec-status-filling);
63861
64268
  }
63862
64269
 
63863
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-legend-dot[data-status="waitlist"] {
64270
+ :where(.theme-scope)
64271
+ :where([data-block='event-calendar'])
64272
+ .event-week-board-legend-dot[data-status='waitlist'] {
63864
64273
  background-color: var(--ec-status-waitlist);
63865
64274
  }
63866
64275
 
63867
64276
  /* Day columns grid */
63868
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-grid {
64277
+ :where(.theme-scope)
64278
+ :where([data-block='event-calendar'])
64279
+ .event-week-board-grid {
63869
64280
  display: grid;
63870
64281
  grid-template-columns: repeat(var(--event-week-board-cols), minmax(0, 1fr));
63871
64282
  }
63872
64283
 
63873
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-day {
64284
+ :where(.theme-scope)
64285
+ :where([data-block='event-calendar'])
64286
+ .event-week-board-day {
63874
64287
  display: flex;
63875
64288
  flex-direction: column;
63876
64289
  min-height: 15rem;
@@ -63880,11 +64293,15 @@ const containerResponsiveThemeCss = `/*
63880
64293
  border-right: var(--rb-border-width, 1px) solid rgb(var(--tb-border));
63881
64294
  }
63882
64295
 
63883
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-day:last-child {
64296
+ :where(.theme-scope)
64297
+ :where([data-block='event-calendar'])
64298
+ .event-week-board-day:last-child {
63884
64299
  border-right: none;
63885
64300
  }
63886
64301
 
63887
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-day-head {
64302
+ :where(.theme-scope)
64303
+ :where([data-block='event-calendar'])
64304
+ .event-week-board-day-head {
63888
64305
  display: flex;
63889
64306
  align-items: baseline;
63890
64307
  gap: 0.4rem;
@@ -63893,11 +64310,16 @@ const containerResponsiveThemeCss = `/*
63893
64310
  border-bottom: var(--rb-border-width, 1px) solid rgb(var(--tb-border));
63894
64311
  }
63895
64312
 
63896
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-day--today .event-week-board-day-head {
64313
+ :where(.theme-scope)
64314
+ :where([data-block='event-calendar'])
64315
+ .event-week-board-day--today
64316
+ .event-week-board-day-head {
63897
64317
  background-color: var(--ec-today-bg);
63898
64318
  }
63899
64319
 
63900
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-day-abbr {
64320
+ :where(.theme-scope)
64321
+ :where([data-block='event-calendar'])
64322
+ .event-week-board-day-abbr {
63901
64323
  font-size: 0.6875rem;
63902
64324
  font-weight: 600;
63903
64325
  letter-spacing: 0.1em;
@@ -63905,18 +64327,25 @@ const containerResponsiveThemeCss = `/*
63905
64327
  opacity: 0.65;
63906
64328
  }
63907
64329
 
63908
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-day--today .event-week-board-day-abbr {
64330
+ :where(.theme-scope)
64331
+ :where([data-block='event-calendar'])
64332
+ .event-week-board-day--today
64333
+ .event-week-board-day-abbr {
63909
64334
  opacity: 1;
63910
64335
  color: var(--ec-today-text);
63911
64336
  }
63912
64337
 
63913
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-day-num {
64338
+ :where(.theme-scope)
64339
+ :where([data-block='event-calendar'])
64340
+ .event-week-board-day-num {
63914
64341
  font-size: 0.8125rem;
63915
64342
  font-weight: 600;
63916
64343
  opacity: 0.5;
63917
64344
  }
63918
64345
 
63919
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-day-body {
64346
+ :where(.theme-scope)
64347
+ :where([data-block='event-calendar'])
64348
+ .event-week-board-day-body {
63920
64349
  display: flex;
63921
64350
  flex-direction: column;
63922
64351
  gap: 0.65rem;
@@ -63925,7 +64354,9 @@ const containerResponsiveThemeCss = `/*
63925
64354
  }
63926
64355
 
63927
64356
  /* Class card */
63928
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-card {
64357
+ :where(.theme-scope)
64358
+ :where([data-block='event-calendar'])
64359
+ .event-week-board-card {
63929
64360
  display: flex;
63930
64361
  flex-direction: column;
63931
64362
  gap: 0.45rem;
@@ -63945,40 +64376,54 @@ const containerResponsiveThemeCss = `/*
63945
64376
  border-color var(--rb-block-transition) ease;
63946
64377
  }
63947
64378
 
63948
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-card[data-status="filling"] {
64379
+ :where(.theme-scope)
64380
+ :where([data-block='event-calendar'])
64381
+ .event-week-board-card[data-status='filling'] {
63949
64382
  border-left-color: var(--ec-status-filling);
63950
64383
  }
63951
64384
 
63952
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-card[data-status="waitlist"] {
64385
+ :where(.theme-scope)
64386
+ :where([data-block='event-calendar'])
64387
+ .event-week-board-card[data-status='waitlist'] {
63953
64388
  border-left-color: var(--ec-status-waitlist);
63954
64389
  }
63955
64390
 
63956
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-card:hover {
64391
+ :where(.theme-scope)
64392
+ :where([data-block='event-calendar'])
64393
+ .event-week-board-card:hover {
63957
64394
  transform: translateY(-2px);
63958
64395
  box-shadow: 0 6px 16px -8px rgba(var(--tb-text), 0.28);
63959
64396
  border-color: rgba(var(--tb-primary), 0.4);
63960
64397
  }
63961
64398
 
63962
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-card:focus-visible {
64399
+ :where(.theme-scope)
64400
+ :where([data-block='event-calendar'])
64401
+ .event-week-board-card:focus-visible {
63963
64402
  outline: 2px solid rgb(var(--tb-primary));
63964
64403
  outline-offset: 2px;
63965
64404
  }
63966
64405
 
63967
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-card-title {
64406
+ :where(.theme-scope)
64407
+ :where([data-block='event-calendar'])
64408
+ .event-week-board-card-title {
63968
64409
  font-family: var(--font-heading, inherit);
63969
64410
  font-size: 0.9375rem;
63970
64411
  font-weight: 600;
63971
64412
  line-height: 1.2;
63972
64413
  }
63973
64414
 
63974
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-card-time {
64415
+ :where(.theme-scope)
64416
+ :where([data-block='event-calendar'])
64417
+ .event-week-board-card-time {
63975
64418
  font-size: 0.75rem;
63976
64419
  letter-spacing: 0.01em;
63977
64420
  opacity: 0.7;
63978
64421
  }
63979
64422
 
63980
64423
  /* Capacity pill */
63981
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-card-pill {
64424
+ :where(.theme-scope)
64425
+ :where([data-block='event-calendar'])
64426
+ .event-week-board-card-pill {
63982
64427
  align-self: flex-start;
63983
64428
  display: inline-flex;
63984
64429
  align-items: center;
@@ -63996,20 +64441,26 @@ const containerResponsiveThemeCss = `/*
63996
64441
  border-color: var(--ec-border);
63997
64442
  }
63998
64443
 
63999
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-card-pill[data-status="filling"] {
64444
+ :where(.theme-scope)
64445
+ :where([data-block='event-calendar'])
64446
+ .event-week-board-card-pill[data-status='filling'] {
64000
64447
  background-color: rgba(var(--tb-accent), 0.14);
64001
64448
  color: var(--ec-status-filling);
64002
64449
  border-color: rgba(var(--tb-accent), 0.32);
64003
64450
  }
64004
64451
 
64005
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-card-pill[data-status="waitlist"] {
64452
+ :where(.theme-scope)
64453
+ :where([data-block='event-calendar'])
64454
+ .event-week-board-card-pill[data-status='waitlist'] {
64006
64455
  background-color: transparent;
64007
64456
  color: rgba(var(--tb-text), 0.6);
64008
64457
  border-color: var(--ec-border);
64009
64458
  }
64010
64459
 
64011
64460
  /* Footer */
64012
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-foot {
64461
+ :where(.theme-scope)
64462
+ :where([data-block='event-calendar'])
64463
+ .event-week-board-foot {
64013
64464
  display: flex;
64014
64465
  align-items: center;
64015
64466
  justify-content: space-between;
@@ -64021,7 +64472,9 @@ const containerResponsiveThemeCss = `/*
64021
64472
  border-top: 1px solid var(--ec-border-subtle);
64022
64473
  }
64023
64474
 
64024
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-foot-note {
64475
+ :where(.theme-scope)
64476
+ :where([data-block='event-calendar'])
64477
+ .event-week-board-foot-note {
64025
64478
  margin: 0;
64026
64479
  font-size: 0.875rem;
64027
64480
  opacity: 0.75;
@@ -64030,36 +64483,69 @@ const containerResponsiveThemeCss = `/*
64030
64483
  /* Responsive: collapse day columns to a stacked list on narrow viewports */
64031
64484
  @container rb-site (max-width: 1023px) {
64032
64485
  @scope ([data-rb-responsive-mode="container"]) to (:scope [data-rb-responsive-mode]) {
64033
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-grid {
64486
+ :where(.theme-scope)
64487
+ :where([data-block='event-calendar'])
64488
+ .event-week-board-top {
64034
64489
  grid-template-columns: 1fr;
64035
64490
  }
64036
64491
 
64037
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-day {
64492
+ :where(.theme-scope)
64493
+ :where([data-block='event-calendar'])
64494
+ .event-week-board-title,
64495
+ :where(.theme-scope)
64496
+ :where([data-block='event-calendar'])
64497
+ .event-week-board-navigation,
64498
+ :where(.theme-scope)
64499
+ :where([data-block='event-calendar'])
64500
+ .event-week-board-legend {
64501
+ grid-column: 1;
64502
+ justify-self: center;
64503
+ }
64504
+
64505
+ :where(.theme-scope)
64506
+ :where([data-block='event-calendar'])
64507
+ .event-week-board-grid {
64508
+ grid-template-columns: 1fr;
64509
+ }
64510
+
64511
+ :where(.theme-scope)
64512
+ :where([data-block='event-calendar'])
64513
+ .event-week-board-day {
64038
64514
  min-height: 0;
64039
64515
  border-right: none;
64040
64516
  border-bottom: var(--rb-border-width, 1px) solid rgb(var(--tb-border));
64041
64517
  }
64042
64518
 
64043
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-day:last-child {
64519
+ :where(.theme-scope)
64520
+ :where([data-block='event-calendar'])
64521
+ .event-week-board-day:last-child {
64044
64522
  border-bottom: none;
64045
64523
  }
64046
64524
 
64047
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-day--empty {
64525
+ :where(.theme-scope)
64526
+ :where([data-block='event-calendar'])
64527
+ .event-week-board-day--empty {
64048
64528
  display: none;
64049
64529
  }
64050
64530
 
64051
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-day-head {
64531
+ :where(.theme-scope)
64532
+ :where([data-block='event-calendar'])
64533
+ .event-week-board-day-head {
64052
64534
  border-bottom: none;
64053
64535
  padding-bottom: 0.25rem;
64054
64536
  }
64055
64537
 
64056
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-day-body {
64538
+ :where(.theme-scope)
64539
+ :where([data-block='event-calendar'])
64540
+ .event-week-board-day-body {
64057
64541
  flex-direction: row;
64058
64542
  flex-wrap: wrap;
64059
64543
  padding-top: 0.35rem;
64060
64544
  }
64061
64545
 
64062
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-card {
64546
+ :where(.theme-scope)
64547
+ :where([data-block='event-calendar'])
64548
+ .event-week-board-card {
64063
64549
  flex: 1 1 14rem;
64064
64550
  }
64065
64551
  }
@@ -64067,11 +64553,37 @@ const containerResponsiveThemeCss = `/*
64067
64553
 
64068
64554
  @container rb-site (max-width: 639px) {
64069
64555
  @scope ([data-rb-responsive-mode="container"]) to (:scope [data-rb-responsive-mode]) {
64070
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-legend {
64556
+ :where(.theme-scope)
64557
+ :where([data-block='event-calendar'])
64558
+ .event-week-board-navigation {
64559
+ display: grid;
64560
+ grid-template-columns: 2.25rem minmax(0, 1fr) 2.25rem;
64561
+ width: 100%;
64562
+ }
64563
+
64564
+ :where(.theme-scope)
64565
+ :where([data-block='event-calendar'])
64566
+ .event-week-board-navigation
64567
+ > :last-child {
64568
+ grid-column: 1 / -1;
64569
+ justify-self: center;
64570
+ }
64571
+
64572
+ :where(.theme-scope)
64573
+ :where([data-block='event-calendar'])
64574
+ .event-week-board-range {
64575
+ min-width: 0;
64576
+ }
64577
+
64578
+ :where(.theme-scope)
64579
+ :where([data-block='event-calendar'])
64580
+ .event-week-board-legend {
64071
64581
  display: none;
64072
64582
  }
64073
64583
 
64074
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-card {
64584
+ :where(.theme-scope)
64585
+ :where([data-block='event-calendar'])
64586
+ .event-week-board-card {
64075
64587
  flex: 1 1 100%;
64076
64588
  }
64077
64589
  }
@@ -64088,8 +64600,9 @@ const containerResponsiveThemeCss = `/*
64088
64600
  * Opt-in only: the band paints when the board root carries [data-banded];
64089
64601
  * the generic default is bandless.
64090
64602
  * ----------------------------------------------------------------------------- */
64091
- :where(.theme-scope) [data-slot="section"]:has(.event-calendar--week-board[data-banded])::before {
64092
- content: "";
64603
+ :where(.theme-scope)
64604
+ [data-slot='section']:has(.event-calendar--week-board[data-banded])::before {
64605
+ content: '';
64093
64606
  position: absolute;
64094
64607
  inset: 0;
64095
64608
  z-index: -9;
@@ -64143,7 +64656,7 @@ const containerResponsiveThemeCss = `/*
64143
64656
  * ----------------------------------------------------------------------------- */
64144
64657
 
64145
64658
  /* Modal overlay */
64146
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal-overlay {
64659
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal-overlay {
64147
64660
  position: fixed;
64148
64661
  inset: 0;
64149
64662
  background: var(--ec-modal-overlay-bg);
@@ -64157,12 +64670,16 @@ const containerResponsiveThemeCss = `/*
64157
64670
  }
64158
64671
 
64159
64672
  @keyframes ec-modal-fade-in {
64160
- from { opacity: 0; }
64161
- to { opacity: 1; }
64673
+ from {
64674
+ opacity: 0;
64675
+ }
64676
+ to {
64677
+ opacity: 1;
64678
+ }
64162
64679
  }
64163
64680
 
64164
64681
  /* Modal dialog */
64165
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal {
64682
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal {
64166
64683
  position: relative;
64167
64684
  background: var(--ec-modal-bg);
64168
64685
  border-radius: var(--rb-block-radius);
@@ -64186,17 +64703,17 @@ const containerResponsiveThemeCss = `/*
64186
64703
  }
64187
64704
 
64188
64705
  /* Event modal - constrained width for card */
64189
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal--event {
64706
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal--event {
64190
64707
  max-width: 26rem;
64191
64708
  }
64192
64709
 
64193
64710
  /* Day modal */
64194
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal--day {
64711
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal--day {
64195
64712
  max-width: 28rem;
64196
64713
  }
64197
64714
 
64198
64715
  /* Close button */
64199
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal-close {
64716
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal-close {
64200
64717
  position: absolute;
64201
64718
  top: 0.75rem;
64202
64719
  right: 0.75rem;
@@ -64217,31 +64734,35 @@ const containerResponsiveThemeCss = `/*
64217
64734
  z-index: 10;
64218
64735
  }
64219
64736
 
64220
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal-close:hover {
64737
+ :where(.theme-scope)
64738
+ :where([data-block='event-calendar'])
64739
+ .ec-modal-close:hover {
64221
64740
  opacity: 1;
64222
64741
  background-color: rgba(var(--tb-text), 0.1);
64223
64742
  }
64224
64743
 
64225
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal-close:focus-visible {
64744
+ :where(.theme-scope)
64745
+ :where([data-block='event-calendar'])
64746
+ .ec-modal-close:focus-visible {
64226
64747
  outline: 2px solid rgb(var(--tb-primary));
64227
64748
  outline-offset: 2px;
64228
64749
  }
64229
64750
 
64230
64751
  /* Modal header (for day modal) */
64231
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal-header {
64752
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal-header {
64232
64753
  padding: 1.5rem 1.5rem 1rem;
64233
64754
  padding-right: 3rem; /* Space for close button */
64234
64755
  border-bottom: 1px solid var(--ec-border);
64235
64756
  }
64236
64757
 
64237
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal-title {
64758
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal-title {
64238
64759
  font-size: 1.125rem;
64239
64760
  font-weight: 600;
64240
64761
  color: var(--ec-text);
64241
64762
  margin: 0;
64242
64763
  }
64243
64764
 
64244
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal-subtitle {
64765
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal-subtitle {
64245
64766
  font-size: 0.875rem;
64246
64767
  color: var(--ec-text);
64247
64768
  opacity: 0.7;
@@ -64249,17 +64770,20 @@ const containerResponsiveThemeCss = `/*
64249
64770
  }
64250
64771
 
64251
64772
  /* Modal content */
64252
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal-content {
64773
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal-content {
64253
64774
  padding: 1rem;
64254
64775
  }
64255
64776
 
64256
64777
  /* Event modal: tighter padding for card */
64257
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal--event .ec-modal-content {
64778
+ :where(.theme-scope)
64779
+ :where([data-block='event-calendar'])
64780
+ .ec-modal--event
64781
+ .ec-modal-content {
64258
64782
  padding: 0.5rem;
64259
64783
  }
64260
64784
 
64261
64785
  /* Day events list */
64262
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-day-events-list {
64786
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-day-events-list {
64263
64787
  display: flex;
64264
64788
  flex-direction: column;
64265
64789
  gap: 0.5rem;
@@ -64267,7 +64791,9 @@ const containerResponsiveThemeCss = `/*
64267
64791
  }
64268
64792
 
64269
64793
  /* AgendaEventCard in button mode inherits most styles, just needs cursor */
64270
- :where(.theme-scope) :where([data-block="event-calendar"]) button.event-agenda-card {
64794
+ :where(.theme-scope)
64795
+ :where([data-block='event-calendar'])
64796
+ button.event-agenda-card {
64271
64797
  cursor: pointer;
64272
64798
  text-align: left;
64273
64799
  font-family: inherit;
@@ -64276,7 +64802,9 @@ const containerResponsiveThemeCss = `/*
64276
64802
  /* Responsive adjustments */
64277
64803
  @container rb-site (max-width: 640px) {
64278
64804
  @scope ([data-rb-responsive-mode="container"]) to (:scope [data-rb-responsive-mode]) {
64279
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-container {
64805
+ :where(.theme-scope)
64806
+ :where([data-block='event-calendar'])
64807
+ .event-calendar-container {
64280
64808
  margin-left: -1.5rem;
64281
64809
  margin-right: -1.5rem;
64282
64810
  border-left: none;
@@ -64284,28 +64812,38 @@ const containerResponsiveThemeCss = `/*
64284
64812
  border-radius: 0;
64285
64813
  }
64286
64814
 
64287
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-day-header {
64815
+ :where(.theme-scope)
64816
+ :where([data-block='event-calendar'])
64817
+ .event-calendar-day-header {
64288
64818
  font-size: 0.75rem;
64289
64819
  padding: 0.375rem 0.125rem;
64290
64820
  }
64291
64821
 
64292
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-day {
64822
+ :where(.theme-scope)
64823
+ :where([data-block='event-calendar'])
64824
+ .event-calendar-day {
64293
64825
  min-height: 88px;
64294
64826
  padding: 0.125rem;
64295
64827
  }
64296
64828
 
64297
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-title {
64829
+ :where(.theme-scope)
64830
+ :where([data-block='event-calendar'])
64831
+ .event-calendar-title {
64298
64832
  font-size: 0.9375rem;
64299
64833
  min-width: 0;
64300
64834
  }
64301
64835
 
64302
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-day-number {
64836
+ :where(.theme-scope)
64837
+ :where([data-block='event-calendar'])
64838
+ .event-calendar-day-number {
64303
64839
  font-size: 0.75rem;
64304
64840
  margin-bottom: 0.125rem;
64305
64841
  padding: 0 0.125rem;
64306
64842
  }
64307
64843
 
64308
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-event {
64844
+ :where(.theme-scope)
64845
+ :where([data-block='event-calendar'])
64846
+ .event-calendar-event {
64309
64847
  justify-content: center;
64310
64848
  gap: 0.25rem;
64311
64849
  padding: 0.1875rem 0.25rem;
@@ -64313,25 +64851,34 @@ const containerResponsiveThemeCss = `/*
64313
64851
  border-radius: calc(var(--rb-block-radius) / 3);
64314
64852
  }
64315
64853
 
64316
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-event-time {
64854
+ :where(.theme-scope)
64855
+ :where([data-block='event-calendar'])
64856
+ .event-calendar-event-time {
64317
64857
  text-align: center;
64318
64858
  font-size: 0.625rem;
64319
64859
  }
64320
64860
 
64321
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-event-title {
64861
+ :where(.theme-scope)
64862
+ :where([data-block='event-calendar'])
64863
+ .event-calendar-event-title {
64322
64864
  display: none;
64323
64865
  }
64324
64866
 
64325
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-more {
64867
+ :where(.theme-scope)
64868
+ :where([data-block='event-calendar'])
64869
+ .event-calendar-more {
64326
64870
  padding: 0.125rem 0.25rem;
64327
64871
  font-size: 0.6875rem;
64328
64872
  }
64329
64873
 
64330
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-header > button {
64874
+ :where(.theme-scope)
64875
+ :where([data-block='event-calendar'])
64876
+ .event-calendar-header
64877
+ > button {
64331
64878
  margin-right: 0.25rem;
64332
64879
  }
64333
64880
 
64334
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal {
64881
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal {
64335
64882
  max-width: 100%;
64336
64883
  max-height: 85vh;
64337
64884
  margin: 0 0.5rem;
@@ -69108,6 +69655,9 @@ const MissingBlockOverrideError = MissingBlockOverrideError$1;
69108
69655
  function isOverrideOnlyPageRenderer(props) {
69109
69656
  return props.rendering?.kind === "overrides-only";
69110
69657
  }
69658
+ function isOverrideOnlyEditorPageRenderer(props) {
69659
+ return props.rendering?.kind === "overrides-only";
69660
+ }
69111
69661
  function normalizeSdkCustomBlocks(customBlocks) {
69112
69662
  if (!customBlocks) return void 0;
69113
69663
  return customBlocks.map((block) => {
@@ -69136,16 +69686,21 @@ function toBlocksPageRendererDataContext(dataContext) {
69136
69686
  imageResolveContext: toBlocksImageResolveContextInput(dataContext.imageResolveContext)
69137
69687
  };
69138
69688
  }
69139
- function PageRenderer(props) {
69140
- const blocksSdkConfig = props.sdkConfig ? { customBlocks: normalizeSdkCustomBlocks(props.sdkConfig.customBlocks) } : props.sdkConfig;
69141
- const { rendering: _rendering, theme: _theme, themeTokens: _themeTokens, ...commonProps } = props;
69142
- const commonBlocksProps = {
69143
- ...commonProps,
69689
+ function toBlocksCommonProps(props) {
69690
+ return {
69691
+ page: props.page,
69692
+ runtimeBoundaries: props.runtimeBoundaries,
69144
69693
  dataContext: props.dataContext ? toBlocksPageRendererDataContext(props.dataContext) : void 0,
69694
+ routeMap: props.routeMap,
69695
+ wrapBlock: props.wrapBlock,
69696
+ registry: props.registry,
69145
69697
  blockOverrides: toBlocksBlockOverrides(props.blockOverrides),
69146
- sdkConfig: blocksSdkConfig,
69698
+ sdkConfig: props.sdkConfig ? { customBlocks: normalizeSdkCustomBlocks(props.sdkConfig.customBlocks) } : props.sdkConfig,
69147
69699
  customBlocks: normalizeSdkCustomBlocks(props.customBlocks)
69148
69700
  };
69701
+ }
69702
+ function PageRenderer(props) {
69703
+ const commonBlocksProps = toBlocksCommonProps(props);
69149
69704
  const blocksProps = isOverrideOnlyPageRenderer(props) ? {
69150
69705
  ...commonBlocksProps,
69151
69706
  rendering: { kind: "overrides-only" },
@@ -69157,6 +69712,19 @@ function PageRenderer(props) {
69157
69712
  };
69158
69713
  return React$1.createElement(PageRenderer$1, blocksProps);
69159
69714
  }
69715
+ function EditorPageRenderer(props) {
69716
+ const commonBlocksProps = toBlocksCommonProps(props);
69717
+ const blocksProps = isOverrideOnlyEditorPageRenderer(props) ? {
69718
+ ...commonBlocksProps,
69719
+ rendering: { kind: "overrides-only" },
69720
+ blockOverrides: toBlocksBlockOverrides(props.blockOverrides) ?? {}
69721
+ } : {
69722
+ ...commonBlocksProps,
69723
+ theme: parseBlocksTheme(props.theme),
69724
+ themeTokens: props.themeTokens
69725
+ };
69726
+ return React$1.createElement(EditorPageRenderer$1, blocksProps);
69727
+ }
69160
69728
  //#endregion
69161
69729
  //#region src/rendering/blocks-theme-scope.ts
69162
69730
  function ThemeScope(props) {
@@ -69228,12 +69796,14 @@ function toPageHydrationBootstrapConfig(props) {
69228
69796
  mediaAssets: props.mediaAssets
69229
69797
  };
69230
69798
  }
69799
+ function resolveSdkBookingTimeZone(timeZone) {
69800
+ return timeZone ?? "UTC";
69801
+ }
69231
69802
  function PageContent(props) {
69232
- const { page, runtimeBoundaries, siteId, resolvedData, bookingOfferingPresets, routeMap, pagesByIdentifier, entriesByIdentifier, wrapBlock, registry, usePlaceholders = false, blockOverrides, sdkConfig, customBlocks, supabaseUrl, mediaAssets, apiBaseUrl, portalToken, previewToken, dataContext } = props;
69803
+ const { page, runtimeBoundaries, siteId, resolvedData, bookingOfferingPresets, bookingTimeZone, routeMap, pagesByIdentifier, entriesByIdentifier, wrapBlock, registry, blockOverrides, sdkConfig, customBlocks, supabaseUrl, mediaAssets, apiBaseUrl, portalToken, previewToken, dataContext } = props;
69233
69804
  const rendererCommonProps = {
69234
69805
  page,
69235
69806
  runtimeBoundaries,
69236
- usePlaceholders,
69237
69807
  dataContext: {
69238
69808
  siteId,
69239
69809
  apiBaseUrl,
@@ -69241,6 +69811,7 @@ function PageContent(props) {
69241
69811
  previewToken,
69242
69812
  resolvedData,
69243
69813
  bookingOfferingPresets: bookingOfferingPresets ?? [],
69814
+ bookingTimeZone: resolveSdkBookingTimeZone(bookingTimeZone),
69244
69815
  routes: routeMap,
69245
69816
  pagesByIdentifier,
69246
69817
  entriesByIdentifier,
@@ -69824,233 +70395,6 @@ function requireSdkTheme(theme, siteId, reason = "cms_theme_absent") {
69824
70395
  //#region src/rendering/renderingMode.ts
69825
70396
  const defaultOverrideOnlyRuntime = { kind: "responsive-only" };
69826
70397
  //#endregion
69827
- //#region src/rendering/components/Layout.tsx
69828
- /**
69829
- * Layout component with header and footer
69830
- *
69831
- * Renders site header and footer around content. Fetches site data if not provided.
69832
- */
69833
- function isOverrideOnlyLayout(props) {
69834
- return props.rendering?.kind === "overrides-only";
69835
- }
69836
- var UnsupportedOverrideOnlyLayoutChromeError = class extends Error {
69837
- constructor(surface) {
69838
- super(`Override-only Layout requires a custom or disabled ${surface}; SDK default chrome is unavailable.`);
69839
- this.surface = surface;
69840
- this.code = "unsupported_override_only_layout_chrome";
69841
- this.name = "UnsupportedOverrideOnlyLayoutChromeError";
69842
- }
69843
- };
69844
- async function resolveLayoutSiteData(props) {
69845
- if (props.siteData) return props.siteData;
69846
- if (!props.client) throw new Error("Layout: must provide either siteData or client");
69847
- if (!props.siteId && !props.slug && !props.domain) throw new Error("Layout: must provide siteId, slug, or domain when using client");
69848
- return props.client.getSite({
69849
- id: props.siteId,
69850
- slug: props.slug,
69851
- domain: props.domain
69852
- });
69853
- }
69854
- function renderOverrideOnlyLayout(props, data) {
69855
- if (data.header === true) throw new UnsupportedOverrideOnlyLayoutChromeError("header");
69856
- if (data.footer === true) throw new UnsupportedOverrideOnlyLayoutChromeError("footer");
69857
- return renderWithOverrideOnlyRuntime({
69858
- runtime: props.rendering.runtime ?? defaultOverrideOnlyRuntime,
69859
- children: /* @__PURE__ */ jsxs(Fragment, { children: [
69860
- typeof props.header === "function" ? props.header(data.headerData) : null,
69861
- props.children,
69862
- typeof props.footer === "function" ? props.footer(data.footerData) : null
69863
- ] })
69864
- });
69865
- }
69866
- /**
69867
- * Layout component that wraps content with site header and footer.
69868
- *
69869
- * This is a server/RSC-safe component. The default `@riverbankcms/sdk/rendering`
69870
- * `Page` and `Block` surfaces mount CMS island hydration automatically, while
69871
- * the strict `@riverbankcms/sdk/rendering/server` surface stays bootstrap-free.
69872
- * If a custom host renders hydratable CMS islands through the strict server
69873
- * surface, mount `BlocksIslandsHydrator` from
69874
- * `@riverbankcms/sdk/rendering/islands` explicitly.
69875
- *
69876
- * @example With pre-fetched site data (recommended)
69877
- * ```tsx
69878
- * import { Layout } from '@riverbankcms/sdk/rendering/server';
69879
- * import { Page } from '@riverbankcms/sdk/rendering';
69880
- *
69881
- * const site = await client.getSite({ slug: 'my-site' });
69882
- *
69883
- * <Layout siteData={site}>
69884
- * <Page {...pageData} />
69885
- * </Layout>
69886
- * ```
69887
- *
69888
- * @example With strict server rendering
69889
- * ```tsx
69890
- * import { Layout, Page } from '@riverbankcms/sdk/rendering/server';
69891
- * import { BlocksIslandsHydrator } from '@riverbankcms/sdk/rendering/islands';
69892
- *
69893
- * const site = await client.getSite({ slug: 'my-site' });
69894
- *
69895
- * <Layout siteData={site}>
69896
- * <BlocksIslandsHydrator siteId={site.site.id} supabaseUrl={site.supabaseUrl} />
69897
- * <Page {...pageData} />
69898
- * </Layout>
69899
- * ```
69900
- */
69901
- async function Layout(props) {
69902
- const { children, hasPortalSession = false, previewStage = "published" } = props;
69903
- const header = props.header ?? true;
69904
- const footer = props.footer ?? true;
69905
- const siteData = await resolveLayoutSiteData(props);
69906
- const { site, navigation, layout, routes } = siteData;
69907
- const footerBlocks = siteData.footerBlocks ?? [];
69908
- const navigationOptions = {
69909
- hasPortalSession,
69910
- previewStage,
69911
- pagesByIdentifier: siteData.pagesByIdentifier,
69912
- entriesByIdentifier: siteData.entriesByIdentifier,
69913
- portalEnabled: siteData.portalEnabled ?? false,
69914
- commerceEnabled: siteData.commerceEnabled ?? false,
69915
- checkoutHref: "/checkout"
69916
- };
69917
- const menuViewModel = buildMenu(navigation, routes, navigationOptions);
69918
- const footerMenuViewModel = buildFooterMenu(navigation, routes, navigationOptions);
69919
- const legalFooterMenuViewModel = buildFooterMenuForRole(navigation, routes, "legal-policy", navigationOptions);
69920
- const logoViewModel = buildLogo(layout.logo ?? null, site.title);
69921
- const customHeaderData = {
69922
- menu: menuViewModel,
69923
- logo: logoViewModel,
69924
- site,
69925
- routes
69926
- };
69927
- const customFooterData = {
69928
- menu: menuViewModel,
69929
- footerMenu: footerMenuViewModel,
69930
- legalFooterMenu: legalFooterMenuViewModel,
69931
- logo: logoViewModel,
69932
- site,
69933
- routes
69934
- };
69935
- if (isOverrideOnlyLayout(props)) return renderOverrideOnlyLayout(props, {
69936
- header: props.header ?? true,
69937
- footer: props.footer ?? true,
69938
- headerData: customHeaderData,
69939
- footerData: customFooterData
69940
- });
69941
- const theme = requireSdkTheme(siteData.theme, site.id);
69942
- const builtThemeRuntime = buildThemeRuntime(theme);
69943
- const headerVariant = props.headerVariant;
69944
- const themeRuntime = props.themeRuntime;
69945
- const headerData = {
69946
- ...customHeaderData,
69947
- theme
69948
- };
69949
- const footerData = {
69950
- ...customFooterData,
69951
- theme
69952
- };
69953
- const headerContent = headerVariant ? {
69954
- ...layout.header,
69955
- variant: headerVariant
69956
- } : layout.header;
69957
- const themeWithVariant = headerVariant ? {
69958
- ...theme,
69959
- header: {
69960
- ...theme.header,
69961
- variant: headerVariant
69962
- }
69963
- } : theme;
69964
- const blocksThemeWithVariant = themeWithVariant;
69965
- const blocksTheme = theme;
69966
- let apiBaseUrl;
69967
- try {
69968
- apiBaseUrl = getRiverbankEnv().baseUrl;
69969
- } catch {}
69970
- const sharedViewModelOverrides = {
69971
- $root: {
69972
- siteId: site.id,
69973
- apiBaseUrl,
69974
- previewStage,
69975
- routes,
69976
- pagesByIdentifier: siteData.pagesByIdentifier,
69977
- entriesByIdentifier: siteData.entriesByIdentifier,
69978
- theme: themeWithVariant
69979
- },
69980
- site,
69981
- menu: menuViewModel,
69982
- footerMenu: footerMenuViewModel,
69983
- legalFooterMenu: legalFooterMenuViewModel
69984
- };
69985
- const headerViewModelOverrides = {
69986
- ...sharedViewModelOverrides,
69987
- content: { logo: logoViewModel }
69988
- };
69989
- const footerViewModelOverrides = {
69990
- ...sharedViewModelOverrides,
69991
- content: {
69992
- ...layout.footer,
69993
- logo: logoViewModel
69994
- }
69995
- };
69996
- let headerElement = null;
69997
- if (header === true) headerElement = renderBlock(siteHeaderManifest, headerContent, {
69998
- theme: builtThemeRuntime.tokens,
69999
- themeConfig: blocksThemeWithVariant,
70000
- viewModelOverrides: headerViewModelOverrides
70001
- });
70002
- else if (typeof header === "function") headerElement = header(headerData);
70003
- let footerElement = null;
70004
- if (footer === true) {
70005
- const footerPlan = resolveFooterRenderPlan({
70006
- isSdkSite: Boolean(site.is_sdk_site),
70007
- mode: theme.footer?.mode
70008
- });
70009
- const footerBlocksElement = footerPlan.renderFooterBlocks && footerBlocks.length > 0 ? /* @__PURE__ */ jsx(PageRenderer, {
70010
- theme,
70011
- page: {
70012
- name: "Footer",
70013
- path: "/__footer",
70014
- purpose: "footer",
70015
- blocks: footerBlocks
70016
- },
70017
- routeMap: routes,
70018
- dataContext: {
70019
- previewStage,
70020
- siteId: site.id,
70021
- apiBaseUrl,
70022
- routes,
70023
- pagesByIdentifier: siteData.pagesByIdentifier,
70024
- entriesByIdentifier: siteData.entriesByIdentifier
70025
- },
70026
- sdkConfig: siteData.sdkConfig ?? null
70027
- }) : null;
70028
- if (footerPlan.renderFooterBlocks && !footerBlocksElement && process.env.NODE_ENV !== "production") console.debug("[sdk] Footer mode renders blocks, but footerBlocks is empty/missing", {
70029
- siteId: site.id,
70030
- mode: footerPlan.mode
70031
- });
70032
- const defaultFooterElement = footerPlan.renderDefaultFooter ? renderBlock(siteFooterManifest, layout.footer, {
70033
- theme: builtThemeRuntime.tokens,
70034
- themeConfig: blocksTheme,
70035
- viewModelOverrides: footerViewModelOverrides
70036
- }) : null;
70037
- footerElement = footerPlan.mode === "default+blocks" ? /* @__PURE__ */ jsxs(Fragment, { children: [footerBlocksElement, defaultFooterElement] }) : footerPlan.mode === "blocks" ? footerBlocksElement : footerPlan.mode === "none" ? null : defaultFooterElement;
70038
- } else if (typeof footer === "function") footerElement = footer(footerData);
70039
- const content = /* @__PURE__ */ jsxs(Fragment, { children: [
70040
- headerElement,
70041
- children,
70042
- footerElement
70043
- ] });
70044
- return renderWithSdkThemeRuntime({
70045
- theme,
70046
- themeRuntime: planLayoutThemeRuntime({
70047
- themeRuntime,
70048
- usesSdkChrome: header === true || footer === true
70049
- }),
70050
- children: content
70051
- });
70052
- }
70053
- //#endregion
70054
70398
  //#region ../blocks/src/structure/schema.ts
70055
70399
  const BlockKind = z.string();
70056
70400
  const blockSchema = z.object({
@@ -71534,6 +71878,379 @@ function parseBackgroundColorToken(value) {
71534
71878
  if (!token) return null;
71535
71879
  return token ? token : null;
71536
71880
  }
71881
+ //#endregion
71882
+ //#region src/rendering/helpers/siteCustomBlocks.ts
71883
+ /**
71884
+ * Prefer the DB-backed custom block manifest list (`site.customBlocks`) when available,
71885
+ * but fall back to SDK config custom blocks (`site.sdkConfig.customBlocks`) for SDK-mode sites.
71886
+ *
71887
+ * This avoids subtle DX bugs where one source is populated but the renderer/prefetch layer
71888
+ * is looking at the other.
71889
+ */
71890
+ function resolveSiteCustomBlocks(site) {
71891
+ const dbBlocks = site.customBlocks;
71892
+ if (Array.isArray(dbBlocks) && dbBlocks.length > 0) return dbBlocks;
71893
+ const sdkBlocks = site.sdkConfig?.customBlocks;
71894
+ if (Array.isArray(sdkBlocks) && sdkBlocks.length > 0) return sdkBlocks;
71895
+ }
71896
+ //#endregion
71897
+ //#region src/rendering/helpers/pageRuntimeSupport.ts
71898
+ function buildSiteRenderSupport(site, mediaAssets) {
71899
+ const customBlocks = resolveSiteCustomBlocks(site);
71900
+ return {
71901
+ theme: site.theme,
71902
+ site: site.site,
71903
+ sdkConfig: site.sdkConfig ?? null,
71904
+ bookingOfferingPresets: site.bookingOfferingPresets ?? [],
71905
+ bookingTimeZone: site.bookingTimeZone ?? "UTC",
71906
+ ...customBlocks ? { customBlocks } : {},
71907
+ supabaseUrl: site.supabaseUrl,
71908
+ routeMap: site.routes,
71909
+ pagesByIdentifier: site.pagesByIdentifier,
71910
+ entriesByIdentifier: site.entriesByIdentifier,
71911
+ ...mediaAssets ? { mediaAssets } : {}
71912
+ };
71913
+ }
71914
+ function collectMediaAssetSidecar(mediaAssets) {
71915
+ return Array.isArray(mediaAssets) && mediaAssets.length > 0 ? mediaAssets : void 0;
71916
+ }
71917
+ function convertPageResponseBlock(block) {
71918
+ if (!isRecord$8(block)) throw new Error("Invalid block format in page API response");
71919
+ if (typeof block.id !== "string" && block.id !== null) throw new Error(`Invalid block id in page: expected string or null, got ${typeof block.id}`);
71920
+ if (typeof block.kind !== "string") throw new Error(`Invalid block kind in page: expected string, got ${typeof block.kind}`);
71921
+ if (typeof block.purpose !== "string") throw new Error(`Invalid block purpose in page: expected string, got ${typeof block.purpose}`);
71922
+ const admission = readInvalidBlockAdmission(block.admission);
71923
+ return {
71924
+ id: block.id,
71925
+ kind: block.kind,
71926
+ purpose: block.purpose,
71927
+ content: sanitizeSdkRuntimeBlockContent(block.kind, readContentRecord(block.content) ?? {}),
71928
+ draftContent: sanitizeNullableSdkRuntimeBlockContent(block.kind, readNestedContentRecord(block.draftContent)),
71929
+ ...admission ? { admission } : {}
71930
+ };
71931
+ }
71932
+ function readInvalidBlockAdmission(value) {
71933
+ if (!isRecord$8(value) || value.kind !== "invalid" || !isRecord$8(value.error)) return null;
71934
+ if (value.error.kind !== "invalid_manifest_content" && value.error.kind !== "manifest_unavailable") return null;
71935
+ return value;
71936
+ }
71937
+ function buildPageOutline(input) {
71938
+ return {
71939
+ name: input.name,
71940
+ path: input.path ?? input.fallbackPath,
71941
+ purpose: input.purpose,
71942
+ blocks: input.blocks.map(convertPageResponseBlock)
71943
+ };
71944
+ }
71945
+ function buildRenderablePageOutline(input) {
71946
+ const page = buildPageOutline(input);
71947
+ return {
71948
+ ...page,
71949
+ blocks: page.blocks.map((block) => admitSdkRuntimePageBlock(block, input.customBlocks))
71950
+ };
71951
+ }
71952
+ function projectRenderablePageOutline(page) {
71953
+ return {
71954
+ ...page,
71955
+ blocks: page.blocks.flatMap((block) => block.admission.kind === "renderable" ? [{
71956
+ id: block.id,
71957
+ kind: block.kind,
71958
+ purpose: block.purpose,
71959
+ content: block.admission.content,
71960
+ ...block.bindings ? { bindings: block.bindings } : {}
71961
+ }] : [])
71962
+ };
71963
+ }
71964
+ function admitSdkRuntimePageBlock(block, customBlocks) {
71965
+ const base = {
71966
+ id: block.id,
71967
+ kind: block.kind,
71968
+ purpose: block.purpose,
71969
+ ...block.bindings ? { bindings: block.bindings } : {}
71970
+ };
71971
+ const transportedAdmission = readInvalidBlockAdmission(block.admission);
71972
+ if (transportedAdmission) return invalidRenderableBlock(base, transportedAdmission.error);
71973
+ const manifest = resolveSdkBlockManifest(block.kind, customBlocks);
71974
+ if (!manifest) return invalidRenderableBlock(base, { kind: "manifest_unavailable" });
71975
+ const content = block.content ?? {};
71976
+ const renderable = admitTransportedRenderableManifestContent(compileManifestContentContract(manifest), content);
71977
+ if (!renderable.ok) return invalidRenderableBlock(base, {
71978
+ kind: "invalid_manifest_content",
71979
+ error: renderable.error
71980
+ });
71981
+ return {
71982
+ ...base,
71983
+ admission: {
71984
+ kind: "renderable",
71985
+ content: renderable.value
71986
+ }
71987
+ };
71988
+ }
71989
+ function resolveSdkBlockManifest(blockKind, customBlocks) {
71990
+ const customBlock = customBlocks?.find((candidate) => candidate.id === blockKind);
71991
+ return customBlock ? parseFieldDefinitions(customBlock.fields) : getBlockDefinition(blockKind)?.manifest ?? null;
71992
+ }
71993
+ function invalidRenderableBlock(block, error) {
71994
+ return {
71995
+ ...block,
71996
+ admission: {
71997
+ kind: "invalid",
71998
+ error
71999
+ }
72000
+ };
72001
+ }
72002
+ function isRecord$8(value) {
72003
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
72004
+ }
72005
+ function readContentRecord(value) {
72006
+ return isRecord$8(value) ? value : void 0;
72007
+ }
72008
+ function readNestedContentRecord(value) {
72009
+ if (!isRecord$8(value)) return null;
72010
+ return readContentRecord(value.data) ?? null;
72011
+ }
72012
+ function sanitizeSdkRuntimeBlockContent(blockKind, content) {
72013
+ if (blockKind !== "block.newsletter-signup") return content;
72014
+ const sanitized = sanitizeNewsletterSignupPublicContent(content);
72015
+ return isRecord$8(sanitized) ? sanitized : {};
72016
+ }
72017
+ function sanitizeNullableSdkRuntimeBlockContent(blockKind, content) {
72018
+ return content ? sanitizeSdkRuntimeBlockContent(blockKind, content) : null;
72019
+ }
72020
+ //#endregion
72021
+ //#region src/rendering/helpers/footerPageOutline.ts
72022
+ function buildFooterRenderablePageOutline(siteData, blocks) {
72023
+ return buildRenderablePageOutline({
72024
+ name: "Footer",
72025
+ path: "/__footer",
72026
+ fallbackPath: "/__footer",
72027
+ purpose: "footer",
72028
+ blocks,
72029
+ customBlocks: resolveSiteCustomBlocks(siteData)
72030
+ });
72031
+ }
72032
+ //#endregion
72033
+ //#region src/rendering/components/Layout.tsx
72034
+ /**
72035
+ * Layout component with header and footer
72036
+ *
72037
+ * Renders site header and footer around content. Fetches site data if not provided.
72038
+ */
72039
+ function isOverrideOnlyLayout(props) {
72040
+ return props.rendering?.kind === "overrides-only";
72041
+ }
72042
+ var UnsupportedOverrideOnlyLayoutChromeError = class extends Error {
72043
+ constructor(surface) {
72044
+ super(`Override-only Layout requires a custom or disabled ${surface}; SDK default chrome is unavailable.`);
72045
+ this.surface = surface;
72046
+ this.code = "unsupported_override_only_layout_chrome";
72047
+ this.name = "UnsupportedOverrideOnlyLayoutChromeError";
72048
+ }
72049
+ };
72050
+ async function resolveLayoutSiteData(props) {
72051
+ if (props.siteData) return props.siteData;
72052
+ if (!props.client) throw new Error("Layout: must provide either siteData or client");
72053
+ if (!props.siteId && !props.slug && !props.domain) throw new Error("Layout: must provide siteId, slug, or domain when using client");
72054
+ return props.client.getSite({
72055
+ id: props.siteId,
72056
+ slug: props.slug,
72057
+ domain: props.domain
72058
+ });
72059
+ }
72060
+ function renderOverrideOnlyLayout(props, data) {
72061
+ if (data.header === true) throw new UnsupportedOverrideOnlyLayoutChromeError("header");
72062
+ if (data.footer === true) throw new UnsupportedOverrideOnlyLayoutChromeError("footer");
72063
+ return renderWithOverrideOnlyRuntime({
72064
+ runtime: props.rendering.runtime ?? defaultOverrideOnlyRuntime,
72065
+ children: /* @__PURE__ */ jsxs(Fragment, { children: [
72066
+ typeof props.header === "function" ? props.header(data.headerData) : null,
72067
+ props.children,
72068
+ typeof props.footer === "function" ? props.footer(data.footerData) : null
72069
+ ] })
72070
+ });
72071
+ }
72072
+ /**
72073
+ * Layout component that wraps content with site header and footer.
72074
+ *
72075
+ * This is a server/RSC-safe component. The default `@riverbankcms/sdk/rendering`
72076
+ * `Page` and `Block` surfaces mount CMS island hydration automatically, while
72077
+ * the strict `@riverbankcms/sdk/rendering/server` surface stays bootstrap-free.
72078
+ * If a custom host renders hydratable CMS islands through the strict server
72079
+ * surface, mount `BlocksIslandsHydrator` from
72080
+ * `@riverbankcms/sdk/rendering/islands` explicitly.
72081
+ *
72082
+ * @example With pre-fetched site data (recommended)
72083
+ * ```tsx
72084
+ * import { Layout } from '@riverbankcms/sdk/rendering/server';
72085
+ * import { Page } from '@riverbankcms/sdk/rendering';
72086
+ *
72087
+ * const site = await client.getSite({ slug: 'my-site' });
72088
+ *
72089
+ * <Layout siteData={site}>
72090
+ * <Page {...pageData} />
72091
+ * </Layout>
72092
+ * ```
72093
+ *
72094
+ * @example With strict server rendering
72095
+ * ```tsx
72096
+ * import { Layout, Page } from '@riverbankcms/sdk/rendering/server';
72097
+ * import { BlocksIslandsHydrator } from '@riverbankcms/sdk/rendering/islands';
72098
+ *
72099
+ * const site = await client.getSite({ slug: 'my-site' });
72100
+ *
72101
+ * <Layout siteData={site}>
72102
+ * <BlocksIslandsHydrator siteId={site.site.id} supabaseUrl={site.supabaseUrl} />
72103
+ * <Page {...pageData} />
72104
+ * </Layout>
72105
+ * ```
72106
+ */
72107
+ async function Layout(props) {
72108
+ const { children, hasPortalSession = false, previewStage = "published" } = props;
72109
+ const header = props.header ?? true;
72110
+ const footer = props.footer ?? true;
72111
+ const siteData = await resolveLayoutSiteData(props);
72112
+ const { site, navigation, layout, routes } = siteData;
72113
+ const footerBlocks = siteData.footerBlocks ?? [];
72114
+ const navigationOptions = {
72115
+ hasPortalSession,
72116
+ previewStage,
72117
+ pagesByIdentifier: siteData.pagesByIdentifier,
72118
+ entriesByIdentifier: siteData.entriesByIdentifier,
72119
+ portalEnabled: siteData.portalEnabled ?? false,
72120
+ commerceEnabled: siteData.commerceEnabled ?? false,
72121
+ checkoutHref: "/checkout"
72122
+ };
72123
+ const menuViewModel = buildMenu(navigation, routes, navigationOptions);
72124
+ const footerMenuViewModel = buildFooterMenu(navigation, routes, navigationOptions);
72125
+ const legalFooterMenuViewModel = buildFooterMenuForRole(navigation, routes, "legal-policy", navigationOptions);
72126
+ const logoViewModel = buildLogo(layout.logo ?? null, site.title);
72127
+ const customHeaderData = {
72128
+ menu: menuViewModel,
72129
+ logo: logoViewModel,
72130
+ site,
72131
+ routes
72132
+ };
72133
+ const customFooterData = {
72134
+ menu: menuViewModel,
72135
+ footerMenu: footerMenuViewModel,
72136
+ legalFooterMenu: legalFooterMenuViewModel,
72137
+ logo: logoViewModel,
72138
+ site,
72139
+ routes
72140
+ };
72141
+ if (isOverrideOnlyLayout(props)) return renderOverrideOnlyLayout(props, {
72142
+ header: props.header ?? true,
72143
+ footer: props.footer ?? true,
72144
+ headerData: customHeaderData,
72145
+ footerData: customFooterData
72146
+ });
72147
+ const theme = requireSdkTheme(siteData.theme, site.id);
72148
+ const builtThemeRuntime = buildThemeRuntime(theme);
72149
+ const headerVariant = props.headerVariant;
72150
+ const themeRuntime = props.themeRuntime;
72151
+ const headerData = {
72152
+ ...customHeaderData,
72153
+ theme
72154
+ };
72155
+ const footerData = {
72156
+ ...customFooterData,
72157
+ theme
72158
+ };
72159
+ const headerContent = headerVariant ? {
72160
+ ...layout.header,
72161
+ variant: headerVariant
72162
+ } : layout.header;
72163
+ const themeWithVariant = headerVariant ? {
72164
+ ...theme,
72165
+ header: {
72166
+ ...theme.header,
72167
+ variant: headerVariant
72168
+ }
72169
+ } : theme;
72170
+ const blocksThemeWithVariant = themeWithVariant;
72171
+ const blocksTheme = theme;
72172
+ let apiBaseUrl;
72173
+ try {
72174
+ apiBaseUrl = getRiverbankEnv().baseUrl;
72175
+ } catch {}
72176
+ const sharedViewModelOverrides = {
72177
+ $root: {
72178
+ siteId: site.id,
72179
+ apiBaseUrl,
72180
+ previewStage,
72181
+ routes,
72182
+ pagesByIdentifier: siteData.pagesByIdentifier,
72183
+ entriesByIdentifier: siteData.entriesByIdentifier,
72184
+ theme: themeWithVariant
72185
+ },
72186
+ site,
72187
+ menu: menuViewModel,
72188
+ footerMenu: footerMenuViewModel,
72189
+ legalFooterMenu: legalFooterMenuViewModel
72190
+ };
72191
+ const headerViewModelOverrides = {
72192
+ ...sharedViewModelOverrides,
72193
+ content: { logo: logoViewModel }
72194
+ };
72195
+ const footerViewModelOverrides = {
72196
+ ...sharedViewModelOverrides,
72197
+ content: {
72198
+ ...layout.footer,
72199
+ logo: logoViewModel
72200
+ }
72201
+ };
72202
+ let headerElement = null;
72203
+ if (header === true) headerElement = renderBlock(siteHeaderManifest, headerContent, {
72204
+ theme: builtThemeRuntime.tokens,
72205
+ themeConfig: blocksThemeWithVariant,
72206
+ viewModelOverrides: headerViewModelOverrides
72207
+ });
72208
+ else if (typeof header === "function") headerElement = header(headerData);
72209
+ let footerElement = null;
72210
+ if (footer === true) {
72211
+ const footerPlan = resolveFooterRenderPlan({
72212
+ isSdkSite: Boolean(site.is_sdk_site),
72213
+ mode: theme.footer?.mode
72214
+ });
72215
+ const footerBlocksElement = footerPlan.renderFooterBlocks && footerBlocks.length > 0 ? /* @__PURE__ */ jsx(PageRenderer, {
72216
+ theme,
72217
+ page: buildFooterRenderablePageOutline(siteData, footerBlocks),
72218
+ routeMap: routes,
72219
+ dataContext: {
72220
+ previewStage,
72221
+ siteId: site.id,
72222
+ apiBaseUrl,
72223
+ routes,
72224
+ pagesByIdentifier: siteData.pagesByIdentifier,
72225
+ entriesByIdentifier: siteData.entriesByIdentifier
72226
+ },
72227
+ sdkConfig: siteData.sdkConfig ?? null
72228
+ }) : null;
72229
+ if (footerPlan.renderFooterBlocks && !footerBlocksElement && process.env.NODE_ENV !== "production") console.debug("[sdk] Footer mode renders blocks, but footerBlocks is empty/missing", {
72230
+ siteId: site.id,
72231
+ mode: footerPlan.mode
72232
+ });
72233
+ const defaultFooterElement = footerPlan.renderDefaultFooter ? renderBlock(siteFooterManifest, layout.footer, {
72234
+ theme: builtThemeRuntime.tokens,
72235
+ themeConfig: blocksTheme,
72236
+ viewModelOverrides: footerViewModelOverrides
72237
+ }) : null;
72238
+ footerElement = footerPlan.mode === "default+blocks" ? /* @__PURE__ */ jsxs(Fragment, { children: [footerBlocksElement, defaultFooterElement] }) : footerPlan.mode === "blocks" ? footerBlocksElement : footerPlan.mode === "none" ? null : defaultFooterElement;
72239
+ } else if (typeof footer === "function") footerElement = footer(footerData);
72240
+ const content = /* @__PURE__ */ jsxs(Fragment, { children: [
72241
+ headerElement,
72242
+ children,
72243
+ footerElement
72244
+ ] });
72245
+ return renderWithSdkThemeRuntime({
72246
+ theme,
72247
+ themeRuntime: planLayoutThemeRuntime({
72248
+ themeRuntime,
72249
+ usesSdkChrome: header === true || footer === true
72250
+ }),
72251
+ children: content
72252
+ });
72253
+ }
71537
72254
  function blockedDemoMutationPolicy(classification, publicMessage) {
71538
72255
  if (publicMessage.trim() === "") throw new Error(`Demo mutation policy ${classification} requires publicMessage.`);
71539
72256
  return {
@@ -72730,6 +73447,13 @@ const PUBLIC_WHOLE_SERIES_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
72730
73447
  //#endregion
72731
73448
  //#region ../api/src/publicEventEndpointDefinitions.ts
72732
73449
  const PUBLIC_EVENT_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
73450
+ resolvePublicEventCheckoutReturn: {
73451
+ path: "/public/sites/{siteId}/events/checkout-return",
73452
+ method: "POST",
73453
+ tags: [TAG_TEMPLATES.publicEvents, "event-checkout"],
73454
+ auth: "public",
73455
+ responseKind: "json"
73456
+ },
72733
73457
  getPublicEventRegistrationOptions: {
72734
73458
  path: "/public/sites/{siteId}/events/registration-options",
72735
73459
  method: "POST",
@@ -73991,7 +74715,7 @@ z$1.object({
73991
74715
  });
73992
74716
  //#endregion
73993
74717
  //#region ../api/src/utils/isRecord.ts
73994
- function isRecord$6(value) {
74718
+ function isRecord$5(value) {
73995
74719
  return typeof value === "object" && value !== null && !Array.isArray(value);
73996
74720
  }
73997
74721
  //#endregion
@@ -74238,7 +74962,7 @@ function sanitizeMarks(marks) {
74238
74962
  if (!Array.isArray(marks) || marks.length === 0) return;
74239
74963
  const sanitized = marks.flatMap((mark) => {
74240
74964
  if (mark.type === "bold" || mark.type === "strong" || mark.type === "italic" || mark.type === "em") return [{ type: mark.type }];
74241
- if (mark.type === "link" && isRecord$6(mark.attrs) && typeof mark.attrs.href === "string") {
74965
+ if (mark.type === "link" && isRecord$5(mark.attrs) && typeof mark.attrs.href === "string") {
74242
74966
  const attrs = { href: mark.attrs.href };
74243
74967
  if (typeof mark.attrs.target === "string" && mark.attrs.target.trim().length > 0) attrs.target = mark.attrs.target;
74244
74968
  if (typeof mark.attrs.rel === "string" && mark.attrs.rel.trim().length > 0) attrs.rel = mark.attrs.rel;
@@ -74263,7 +74987,7 @@ function collectText(node) {
74263
74987
  }
74264
74988
  function stableSerialize(value) {
74265
74989
  if (Array.isArray(value)) return `[${value.map(stableSerialize).join(",")}]`;
74266
- if (isRecord$6(value)) return `{${Object.entries(value).filter(([, entryValue]) => entryValue !== void 0).sort(([left], [right]) => left.localeCompare(right)).map(([key, entryValue]) => `${JSON.stringify(key)}:${stableSerialize(entryValue)}`).join(",")}}`;
74990
+ if (isRecord$5(value)) return `{${Object.entries(value).filter(([, entryValue]) => entryValue !== void 0).sort(([left], [right]) => left.localeCompare(right)).map(([key, entryValue]) => `${JSON.stringify(key)}:${stableSerialize(entryValue)}`).join(",")}}`;
74267
74991
  return JSON.stringify(value);
74268
74992
  }
74269
74993
  //#endregion
@@ -74427,7 +75151,7 @@ function collectCartLinkStats(items, depth = 0) {
74427
75151
  return result;
74428
75152
  }
74429
75153
  function isNavigationMenuValidationItem(value) {
74430
- if (!isRecord$6(value)) return false;
75154
+ if (!isRecord$5(value)) return false;
74431
75155
  return typeof value.label === "string";
74432
75156
  }
74433
75157
  //#endregion
@@ -74445,7 +75169,7 @@ function normalizeIdList(value) {
74445
75169
  return result.length > 0 ? result : null;
74446
75170
  }
74447
75171
  function extractNavVisibilityConfig(raw) {
74448
- if (!isRecord$6(raw)) return null;
75172
+ if (!isRecord$5(raw)) return null;
74449
75173
  const modeRaw = raw.mode;
74450
75174
  const mode = modeRaw === "augment" || modeRaw === "restrict" ? modeRaw : null;
74451
75175
  const allowIds = normalizeIdList(raw.allowIds);
@@ -74458,7 +75182,7 @@ function extractNavVisibilityConfig(raw) {
74458
75182
  };
74459
75183
  }
74460
75184
  function asRecord(value) {
74461
- return isRecord$6(value) ? value : null;
75185
+ return isRecord$5(value) ? value : null;
74462
75186
  }
74463
75187
  /**
74464
75188
  * Check if a raw config object has any nav visibility values defined.
@@ -74561,7 +75285,7 @@ const ENTRY_REF_KEYS = [
74561
75285
  "entryId",
74562
75286
  "slug"
74563
75287
  ];
74564
- function isRecord$5(value) {
75288
+ function isRecord$4(value) {
74565
75289
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
74566
75290
  }
74567
75291
  function extractManualEntryRef(item) {
@@ -74569,7 +75293,7 @@ function extractManualEntryRef(item) {
74569
75293
  const trimmed = item.trim();
74570
75294
  return trimmed.length > 0 ? trimmed : null;
74571
75295
  }
74572
- if (!isRecord$5(item)) return null;
75296
+ if (!isRecord$4(item)) return null;
74573
75297
  for (const key of ENTRY_REF_KEYS) {
74574
75298
  const raw = item[key];
74575
75299
  if (typeof raw === "string" && raw.trim().length > 0) return raw.trim();
@@ -75529,80 +76253,6 @@ async function resolveBlockDataWithDeps(deps, input) {
75529
76253
  return deps.mergeLoaderResults(configData, hostResult.data);
75530
76254
  }
75531
76255
  //#endregion
75532
- //#region src/rendering/helpers/siteCustomBlocks.ts
75533
- /**
75534
- * Prefer the DB-backed custom block manifest list (`site.customBlocks`) when available,
75535
- * but fall back to SDK config custom blocks (`site.sdkConfig.customBlocks`) for SDK-mode sites.
75536
- *
75537
- * This avoids subtle DX bugs where one source is populated but the renderer/prefetch layer
75538
- * is looking at the other.
75539
- */
75540
- function resolveSiteCustomBlocks(site) {
75541
- const dbBlocks = site.customBlocks;
75542
- if (Array.isArray(dbBlocks) && dbBlocks.length > 0) return dbBlocks;
75543
- const sdkBlocks = site.sdkConfig?.customBlocks;
75544
- if (Array.isArray(sdkBlocks) && sdkBlocks.length > 0) return sdkBlocks;
75545
- }
75546
- //#endregion
75547
- //#region src/rendering/helpers/pageRuntimeSupport.ts
75548
- function buildSiteRenderSupport(site, mediaAssets) {
75549
- const customBlocks = resolveSiteCustomBlocks(site);
75550
- return {
75551
- theme: site.theme,
75552
- site: site.site,
75553
- sdkConfig: site.sdkConfig ?? null,
75554
- bookingOfferingPresets: site.bookingOfferingPresets ?? [],
75555
- ...customBlocks ? { customBlocks } : {},
75556
- supabaseUrl: site.supabaseUrl,
75557
- routeMap: site.routes,
75558
- pagesByIdentifier: site.pagesByIdentifier,
75559
- entriesByIdentifier: site.entriesByIdentifier,
75560
- ...mediaAssets ? { mediaAssets } : {}
75561
- };
75562
- }
75563
- function collectMediaAssetSidecar(mediaAssets) {
75564
- return Array.isArray(mediaAssets) && mediaAssets.length > 0 ? mediaAssets : void 0;
75565
- }
75566
- function convertPageResponseBlock(block) {
75567
- if (!isRecord$4(block)) throw new Error("Invalid block format in page API response");
75568
- if (typeof block.id !== "string" && block.id !== null) throw new Error(`Invalid block id in page: expected string or null, got ${typeof block.id}`);
75569
- if (typeof block.kind !== "string") throw new Error(`Invalid block kind in page: expected string, got ${typeof block.kind}`);
75570
- if (typeof block.purpose !== "string") throw new Error(`Invalid block purpose in page: expected string, got ${typeof block.purpose}`);
75571
- return {
75572
- id: block.id,
75573
- kind: block.kind,
75574
- purpose: block.purpose,
75575
- content: sanitizeSdkRuntimeBlockContent(block.kind, readContentRecord(block.content) ?? {}),
75576
- draftContent: sanitizeNullableSdkRuntimeBlockContent(block.kind, readNestedContentRecord(block.draftContent))
75577
- };
75578
- }
75579
- function buildPageOutline(input) {
75580
- return {
75581
- name: input.name,
75582
- path: input.path ?? input.fallbackPath,
75583
- purpose: input.purpose,
75584
- blocks: input.blocks.map(convertPageResponseBlock)
75585
- };
75586
- }
75587
- function isRecord$4(value) {
75588
- return Boolean(value) && typeof value === "object" && !Array.isArray(value);
75589
- }
75590
- function readContentRecord(value) {
75591
- return isRecord$4(value) ? value : void 0;
75592
- }
75593
- function readNestedContentRecord(value) {
75594
- if (!isRecord$4(value)) return null;
75595
- return readContentRecord(value.data) ?? null;
75596
- }
75597
- function sanitizeSdkRuntimeBlockContent(blockKind, content) {
75598
- if (blockKind !== "block.newsletter-signup") return content;
75599
- const sanitized = sanitizeNewsletterSignupPublicContent(content);
75600
- return isRecord$4(sanitized) ? sanitized : {};
75601
- }
75602
- function sanitizeNullableSdkRuntimeBlockContent(blockKind, content) {
75603
- return content ? sanitizeSdkRuntimeBlockContent(blockKind, content) : null;
75604
- }
75605
- //#endregion
75606
76256
  //#region src/rendering/helpers/loadPage.ts
75607
76257
  /**
75608
76258
  * Server-side helper to fetch all data needed for <Page> component.
@@ -75678,21 +76328,23 @@ async function loadPageWithDeps(deps, params) {
75678
76328
  if ("pageSurface" in pageResponse) throw new Error("This path resolves to a page surface, not a page. Use loadContent() instead, which handles pages, entries, and page surfaces.");
75679
76329
  const { page: pageData } = pageResponse;
75680
76330
  const support = buildSiteRenderSupport(site, collectMediaAssetSidecar(pageResponse.mediaAssets));
75681
- const pageOutline = buildPageOutline({
76331
+ const pageOutline = buildRenderablePageOutline({
75682
76332
  name: pageData.name,
75683
76333
  path: pageData.path,
75684
76334
  fallbackPath: path,
75685
76335
  purpose: pageData.purpose,
75686
- blocks: pageData.blocks
76336
+ blocks: pageData.blocks,
76337
+ customBlocks: support.customBlocks
75687
76338
  });
75688
76339
  const previewStage = preview ? "preview" : "published";
76340
+ const renderTarget = {
76341
+ kind: "page",
76342
+ pageId: pageId ?? pageData.id
76343
+ };
75689
76344
  const resolvedData = await resolveBlockDataWithDeps(deps, {
75690
- page: pageOutline,
76345
+ page: projectRenderablePageOutline(pageOutline),
75691
76346
  siteId,
75692
- renderTarget: {
75693
- kind: "page",
75694
- pageId: pageId ?? pageData.id
75695
- },
76347
+ renderTarget,
75696
76348
  previewStage,
75697
76349
  policy: createBlockDataLoadPolicy(dataLoaderOverrides, normalizeDataLoaderSearchParams(searchParams)),
75698
76350
  client,
@@ -75706,6 +76358,7 @@ async function loadPageWithDeps(deps, params) {
75706
76358
  siteId,
75707
76359
  resolvedData,
75708
76360
  bookingOfferingPresets: support.bookingOfferingPresets,
76361
+ bookingTimeZone: support.bookingTimeZone,
75709
76362
  supabaseUrl: support.supabaseUrl,
75710
76363
  ...support.mediaAssets ? { mediaAssets: support.mediaAssets } : {},
75711
76364
  ...support.customBlocks ? { customBlocks: support.customBlocks } : {},
@@ -76997,6 +77650,7 @@ const DEFAULT_TEMPLATE_DEFINITIONS = {
76997
77650
  {
76998
77651
  blockKind: "block.body-text",
76999
77652
  scope: "entry",
77653
+ content: { body: createRichTextDoc([""]) },
77000
77654
  bindings: EVENT_BODY_TEXT_BINDINGS
77001
77655
  },
77002
77656
  {
@@ -77043,6 +77697,7 @@ const DEFAULT_TEMPLATE_DEFINITIONS = {
77043
77697
  }, {
77044
77698
  blockKind: "block.body-text",
77045
77699
  scope: "entry",
77700
+ content: { body: createRichTextDoc([""]) },
77046
77701
  bindings: TEAM_MEMBER_BODY_TEXT_BINDINGS
77047
77702
  }]
77048
77703
  },
@@ -78201,6 +78856,14 @@ const isRecord = isRecord$27;
78201
78856
  const applyBindingsToContent = applyBindingsToContent$1;
78202
78857
  //#endregion
78203
78858
  //#region src/rendering/helpers/templateContent.ts
78859
+ function admitMaterializedSdkTemplateBlockContent(input) {
78860
+ const baseContent = sanitizeSdkRuntimeBlockContent(input.block.blockKind, input.block.content ?? {});
78861
+ const bindings = input.block.bindings ?? {};
78862
+ const materialized = input.block.scope === "entry" && Object.keys(bindings).length > 0 ? applyBindingsToContent(baseContent, bindings, input.bindingContext) : baseContent;
78863
+ const contract = compileManifestContentContract(input.manifestOrFields);
78864
+ const stored = admitStoredManifestContent(contract, materialized);
78865
+ return stored.ok ? deriveRenderableManifestContent(contract, stored.value, (content) => content) : stored;
78866
+ }
78204
78867
  function createTemplateRenderTarget(source, templateId) {
78205
78868
  switch (source.kind) {
78206
78869
  case "entry-template": return {
@@ -78251,7 +78914,12 @@ async function processTemplatePage(input) {
78251
78914
  templatePage: null,
78252
78915
  resolvedData: {}
78253
78916
  };
78254
- const blocks = template.blocks.flatMap((block) => resolveTemplateBlockSequence(block, input.bindingContext, input.slotContent));
78917
+ const blocks = template.blocks.flatMap((block) => resolveTemplateBlockSequence({
78918
+ block,
78919
+ bindingContext: input.bindingContext,
78920
+ slotContent: input.slotContent,
78921
+ customBlocks: input.customBlocks
78922
+ }));
78255
78923
  if (blocks.length === 0) return {
78256
78924
  templatePage: null,
78257
78925
  resolvedData: {}
@@ -78265,7 +78933,7 @@ async function processTemplatePage(input) {
78265
78933
  return {
78266
78934
  templatePage,
78267
78935
  resolvedData: await resolveBlockDataWithDeps(input.deps, {
78268
- page: templatePage,
78936
+ page: projectRenderablePageOutline(templatePage),
78269
78937
  siteId: input.siteId,
78270
78938
  renderTarget: createTemplateRenderTarget(input.renderTargetSource, template.id),
78271
78939
  previewStage: input.previewStage,
@@ -78275,58 +78943,74 @@ async function processTemplatePage(input) {
78275
78943
  })
78276
78944
  };
78277
78945
  }
78278
- function resolveTemplateBlockSequence(block, bindingContext, slotContent) {
78946
+ function resolveTemplateBlockSequence(input) {
78947
+ const { block } = input;
78279
78948
  const slotKey = readEntrySlotKey(block);
78280
78949
  if (slotKey) return selectBlocksForDeclaredEntrySlot({
78281
78950
  declaredSlotKey: slotKey,
78282
- entrySlots: slotContent ?? []
78283
- }).map(mapEntrySlotBlock);
78951
+ entrySlots: input.slotContent ?? []
78952
+ }).map((slotBlock) => admitEntrySlotBlock(slotBlock, input.customBlocks));
78284
78953
  if (block.blockKind === "system.entry-slot") return [];
78285
- return [resolveTemplateBlock(block, bindingContext)];
78954
+ return [resolveTemplateBlock(block, input.bindingContext, input.customBlocks)];
78286
78955
  }
78287
- function resolveTemplateBlock(block, bindingContext) {
78288
- const baseContent = sanitizeSdkRuntimeBlockContent(block.blockKind, block.content ?? {});
78289
- if (block.scope === "template") return {
78290
- id: block.id,
78291
- kind: block.blockKind,
78292
- purpose: "template-layout",
78293
- content: baseContent
78294
- };
78295
- const bindings = block.bindings ?? {};
78296
- const resolvedContent = Object.keys(bindings).length > 0 ? applyBindingsToContent(baseContent, bindings, bindingContext) : baseContent;
78297
- return {
78956
+ function resolveTemplateBlock(block, bindingContext, customBlocks) {
78957
+ const base = {
78298
78958
  id: block.id,
78299
78959
  kind: block.blockKind,
78300
- purpose: "entry-content",
78301
- content: resolvedContent
78302
- };
78960
+ purpose: block.scope === "template" ? "template-layout" : "entry-content",
78961
+ ...isRecord(block.bindings) ? { bindings: block.bindings } : {}
78962
+ };
78963
+ const manifest = resolveSdkBlockManifest(block.blockKind, customBlocks);
78964
+ if (manifest === null) return invalidRenderableBlock(base, { kind: "manifest_unavailable" });
78965
+ const admission = admitMaterializedSdkTemplateBlockContent({
78966
+ block,
78967
+ bindingContext,
78968
+ manifestOrFields: manifest
78969
+ });
78970
+ return admission.ok ? {
78971
+ ...base,
78972
+ admission: {
78973
+ kind: "renderable",
78974
+ content: admission.value
78975
+ }
78976
+ } : invalidRenderableBlock(base, {
78977
+ kind: "invalid_manifest_content",
78978
+ error: admission.error
78979
+ });
78303
78980
  }
78304
78981
  function readEntrySlotKey(block) {
78305
78982
  if (block.blockKind !== "system.entry-slot" || block.scope !== "template") return null;
78306
78983
  const parsed = parseSlotKey(block.content?.slotKey);
78307
78984
  return parsed.ok ? parsed.value : null;
78308
78985
  }
78309
- function mapEntrySlotBlock(block) {
78310
- const mapped = {
78986
+ function admitEntrySlotBlock(block, customBlocks) {
78987
+ const base = {
78311
78988
  id: block.id ?? block.blockId ?? null,
78312
78989
  kind: block.kind,
78313
78990
  purpose: block.purpose,
78314
- orderIndex: block.orderIndex ?? null,
78315
- content: normalizeEntrySlotBlockContent(block.content),
78316
- draftContent: normalizeNullableEntrySlotContent(block.draftContent),
78317
- publishedContent: normalizeNullableEntrySlotContent(block.publishedContent)
78318
- };
78319
- return block.bindings == null ? mapped : {
78320
- ...mapped,
78321
- bindings: block.bindings
78322
- };
78323
- }
78324
- function normalizeNullableEntrySlotContent(content) {
78325
- return content == null ? null : normalizeEntrySlotBlockContent(content);
78326
- }
78327
- function normalizeEntrySlotBlockContent(content) {
78328
- const value = content ?? {};
78329
- return isRecord(value) ? value : {};
78991
+ ...isRecord(block.bindings) ? { bindings: block.bindings } : {}
78992
+ };
78993
+ const transportedAdmission = readInvalidBlockAdmission(block.admission);
78994
+ if (transportedAdmission) return invalidRenderableBlock(base, transportedAdmission.error);
78995
+ const manifest = resolveSdkBlockManifest(block.kind, customBlocks);
78996
+ if (manifest === null) return invalidRenderableBlock(base, { kind: "manifest_unavailable" });
78997
+ const contract = compileManifestContentContract(manifest);
78998
+ const stored = admitStoredManifestContent(contract, block.content ?? {});
78999
+ if (!stored.ok) return invalidRenderableBlock(base, {
79000
+ kind: "invalid_manifest_content",
79001
+ error: stored.error
79002
+ });
79003
+ const renderable = deriveRenderableManifestContent(contract, stored.value, (content) => content);
79004
+ return renderable.ok ? {
79005
+ ...base,
79006
+ admission: {
79007
+ kind: "renderable",
79008
+ content: renderable.value
79009
+ }
79010
+ } : invalidRenderableBlock(base, {
79011
+ kind: "invalid_manifest_content",
79012
+ error: renderable.error
79013
+ });
78330
79014
  }
78331
79015
  //#endregion
78332
79016
  //#region src/rendering/helpers/loadContent.ts
@@ -78355,6 +79039,7 @@ function getRejectedReason(result) {
78355
79039
  function toTemplateContentRenderSupport(support, siteId) {
78356
79040
  return {
78357
79041
  bookingOfferingPresets: support.bookingOfferingPresets,
79042
+ bookingTimeZone: support.bookingTimeZone,
78358
79043
  ...support.customBlocks ? { customBlocks: support.customBlocks } : {},
78359
79044
  entriesByIdentifier: support.entriesByIdentifier,
78360
79045
  ...support.mediaAssets ? { mediaAssets: support.mediaAssets } : {},
@@ -78497,7 +79182,6 @@ async function loadContentFromContentResponseWithDeps(deps, params) {
78497
79182
  entry,
78498
79183
  templatePage,
78499
79184
  resolvedData,
78500
- bookingOfferingPresets: support.bookingOfferingPresets,
78501
79185
  dataContext: { contentEntry: {
78502
79186
  ...entry.content ?? {},
78503
79187
  id: entry.id,
@@ -78566,7 +79250,6 @@ async function loadContentFromContentResponseWithDeps(deps, params) {
78566
79250
  pageSurface,
78567
79251
  templatePage,
78568
79252
  resolvedData,
78569
- bookingOfferingPresets: support.bookingOfferingPresets,
78570
79253
  dataContext: {
78571
79254
  pageSurface: {
78572
79255
  ...pageSurface.content ?? {},
@@ -78585,15 +79268,16 @@ async function loadContentFromContentResponseWithDeps(deps, params) {
78585
79268
  const pageRecord = pageData;
78586
79269
  const canonicalPagePath = pageData.path ?? pageRecord.path ?? "/";
78587
79270
  const draftPagePath = pageRecord.draftPath ?? pageRecord.path ?? canonicalPagePath;
78588
- const pageOutline = buildPageOutline({
79271
+ const pageOutline = buildRenderablePageOutline({
78589
79272
  name: pageData.name,
78590
79273
  path: canonicalPagePath,
78591
79274
  fallbackPath: "/",
78592
79275
  purpose: pageData.purpose,
78593
- blocks: pageData.blocks
79276
+ blocks: pageData.blocks,
79277
+ customBlocks: support.customBlocks
78594
79278
  });
78595
79279
  const resolvedData = await resolveBlockDataWithDeps(deps, {
78596
- page: pageOutline,
79280
+ page: projectRenderablePageOutline(pageOutline),
78597
79281
  siteId,
78598
79282
  renderTarget: {
78599
79283
  kind: "page",
@@ -78629,6 +79313,7 @@ async function loadContentFromContentResponseWithDeps(deps, params) {
78629
79313
  ...support.customBlocks ? { customBlocks: support.customBlocks } : {},
78630
79314
  resolvedData,
78631
79315
  bookingOfferingPresets: support.bookingOfferingPresets,
79316
+ bookingTimeZone: support.bookingTimeZone,
78632
79317
  site: support.site,
78633
79318
  sdkConfig: support.sdkConfig,
78634
79319
  supabaseUrl: support.supabaseUrl,
@@ -78732,4 +79417,4 @@ function defineBlockOverrideRegistrations(registrations) {
78732
79417
  * ```
78733
79418
  */
78734
79419
  //#endregion
78735
- export { Block, ImagePresets, Layout, MISSING_SDK_THEME_ERROR_CODE, MissingBlockOverrideError, MissingSdkThemeError, Page, PageRenderer, RichText, ThemeScope, UnsupportedOverrideOnlyLayoutChromeError, buildThemeRuntime, defineBlockOverrideRegistrations, defineBlockOverrides, defineLazyBlockOverride, isEntryContent, isPageContent, isPageSurfaceContent, loadContent, loadPage, resolveImageSourceSetWithContext, resolveImageUrl, resolveImageUrlWithContext, toBlocksImageResolveContextInput, toBlocksMediaAssets, toBlocksPageRendererDataContext };
79420
+ export { Block, EditorPageRenderer, ImagePresets, Layout, MISSING_SDK_THEME_ERROR_CODE, MissingBlockOverrideError, MissingSdkThemeError, Page, PageRenderer, RichText, ThemeScope, UnsupportedOverrideOnlyLayoutChromeError, buildThemeRuntime, defineBlockOverrideRegistrations, defineBlockOverrides, defineLazyBlockOverride, isEntryContent, isPageContent, isPageSurfaceContent, loadContent, loadPage, resolveImageSourceSetWithContext, resolveImageUrl, resolveImageUrlWithContext, toBlocksImageResolveContextInput, toBlocksMediaAssets, toBlocksPageRendererDataContext };