@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,59 @@ 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
+ }) });
14316
14302
  }
14317
- function createManifestValidatorWithNormalizer(manifestOrFields, options, normalize) {
14318
- return createManifestValidatorFromPlans(derivePlansFromManifestOrFields(manifestOrFields), options, normalize);
14303
+ /** Validates raw editor state without granting a stored-content proof. */
14304
+ function validateManifestDraft(contract, data) {
14305
+ const parsed = contract[compiledManifestContentContract].draftSchema.safeParse(data);
14306
+ if (parsed.success) return {
14307
+ kind: "previewable",
14308
+ data,
14309
+ issues: []
14310
+ };
14311
+ const [firstIssue, ...remainingIssues] = zodAdmissionIssues(parsed.error);
14312
+ if (!firstIssue) throw new Error("Draft manifest validation failed without an issue");
14313
+ return {
14314
+ kind: "invalid",
14315
+ data,
14316
+ issues: [firstIssue, ...remainingIssues]
14317
+ };
14318
+ }
14319
+ /**
14320
+ * Re-admits renderable content after a transport boundary has erased its
14321
+ * compile-time proof. Unlike write admission, this never canonicalizes or
14322
+ * grants a stored proof, so hydrated media cannot flow back to persistence.
14323
+ */
14324
+ function admitTransportedRenderableManifestContent(contract, content) {
14325
+ const parsed = contract[compiledManifestContentContract].renderSchema.safeParse(content);
14326
+ return parsed.success ? {
14327
+ ok: true,
14328
+ value: content
14329
+ } : {
14330
+ ok: false,
14331
+ error: zodAdmissionError(parsed.error)
14332
+ };
14319
14333
  }
14320
- function createManifestValidatorFromPlans(plans, options, normalize) {
14334
+ function deriveNormalizedContentZodFromPlans(plans, options, normalize) {
14321
14335
  const isDraft = options.mode === "draft";
14322
14336
  const baseSchema = deriveContentZodFromPlans(plans, options);
14323
14337
  if (isDraft) return z$1.preprocess((content) => preprocessEmptyValues(normalize(plans, content, options)), baseSchema);
@@ -14328,9 +14342,81 @@ function deriveContentZodFromPlans(plans, options) {
14328
14342
  for (const plan of plans) shape[plan.fieldId] = fieldPlanToObjectPropertyZod(plan, options);
14329
14343
  return z$1.object(shape).catchall(z$1.unknown()).passthrough();
14330
14344
  }
14345
+ function deriveStrictStoredZodFromPlans(plans) {
14346
+ const shape = {};
14347
+ for (const plan of plans) shape[plan.fieldId] = fieldPlanToStoredObjectPropertyZod(plan);
14348
+ return z$1.object(shape).catchall(z$1.unknown()).passthrough();
14349
+ }
14331
14350
  function derivePlansFromManifestOrFields(manifestOrFields) {
14332
14351
  return deriveFieldValidationPlans(Array.isArray(manifestOrFields) ? manifestOrFields : manifestOrFields.fields ?? []);
14333
14352
  }
14353
+ function zodAdmissionError(error) {
14354
+ return {
14355
+ kind: "invalid_shape",
14356
+ issues: zodAdmissionIssues(error)
14357
+ };
14358
+ }
14359
+ function zodAdmissionIssues(error) {
14360
+ return error.issues.map((issue) => ({
14361
+ code: issue.code,
14362
+ path: issue.path.map((segment) => typeof segment === "number" ? segment : String(segment)),
14363
+ message: issue.message
14364
+ }));
14365
+ }
14366
+ function findNonPortableMediaPaths(plans, content) {
14367
+ const paths = /* @__PURE__ */ new Set();
14368
+ collectNonPortablePlannedMedia(plans, content, [], paths);
14369
+ return [...paths].sort();
14370
+ }
14371
+ function collectNonPortablePlannedMedia(plans, content, parentPath, paths) {
14372
+ if (!isPlainRecord$1(content)) return;
14373
+ for (const plan of plans) {
14374
+ if (!(plan.fieldId in content)) continue;
14375
+ const value = content[plan.fieldId];
14376
+ const path = [...parentPath, plan.fieldId];
14377
+ switch (plan.kind) {
14378
+ case "media":
14379
+ if (isPlainRecord$1(value) && hasEnvironmentSpecificMediaField(value)) paths.add(formatFieldPath(path));
14380
+ break;
14381
+ case "richText":
14382
+ collectNonPortableRichTextImages(value, path, paths);
14383
+ break;
14384
+ case "group":
14385
+ collectNonPortablePlannedMedia(selectedGroupChildPlans(plan, value), value, path, paths);
14386
+ break;
14387
+ case "repeater":
14388
+ collectNonPortableRepeaterMedia(plan, value, path, paths);
14389
+ break;
14390
+ case "string":
14391
+ case "number":
14392
+ case "boolean":
14393
+ case "inlineText":
14394
+ case "link":
14395
+ case "select":
14396
+ case "passthrough": break;
14397
+ }
14398
+ }
14399
+ }
14400
+ function collectNonPortableRepeaterMedia(plan, value, path, paths) {
14401
+ if (!Array.isArray(value)) return;
14402
+ value.forEach((item, index) => {
14403
+ if (!isPlainRecord$1(item)) return;
14404
+ const childPlans = plan.repeatedItemVariants ? plan.repeatedItemVariants.find((variant) => variant.typeId === item._type)?.fields : plan.repeatedItemPlan;
14405
+ if (childPlans) collectNonPortablePlannedMedia(childPlans, item, [...path, index], paths);
14406
+ });
14407
+ }
14408
+ function collectNonPortableRichTextImages(value, path, paths) {
14409
+ const images = [];
14410
+ walkAndCollectImageAttrs(value, images);
14411
+ const prefix = formatFieldPath(path);
14412
+ for (const reference of images) if (hasEnvironmentSpecificMediaField(reference.attrs)) paths.add(reference.location ? `${prefix}.${reference.location}` : prefix);
14413
+ }
14414
+ function isPlainRecord$1(value) {
14415
+ return typeof value === "object" && value !== null && !Array.isArray(value);
14416
+ }
14417
+ function hasEnvironmentSpecificMediaField(value) {
14418
+ return "assetId" in value || "storageBucket" in value || "storagePath" in value || "src" in value || "mimeType" in value || looksLikeUuid(value.id);
14419
+ }
14334
14420
  //#endregion
14335
14421
  //#region ../blocks/src/system/manifest/variantKey.ts
14336
14422
  /**
@@ -17538,27 +17624,6 @@ function asHeaderStyleId(value) {
17538
17624
  return value;
17539
17625
  }
17540
17626
  //#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
17627
  //#region ../theme-core/src/site-styles/headerLayoutCatalog.ts
17563
17628
  const titleOnlyLogoAccommodation = {
17564
17629
  pattern: "title-only",
@@ -17718,43 +17783,37 @@ const headerStyleCatalog = defineExactCatalog()([
17718
17783
  id: asHeaderStyleId("minimal"),
17719
17784
  label: "Minimal",
17720
17785
  description: "Quiet surface with simple color-change navigation.",
17721
- supportedLayoutIds: supportedLayouts(["classic", "centered"]),
17722
- navTypography: "plain"
17786
+ supportedLayoutIds: supportedLayouts(["classic", "centered"])
17723
17787
  },
17724
17788
  {
17725
17789
  id: asHeaderStyleId("fine-line"),
17726
17790
  label: "Seamless",
17727
17791
  description: "Borderless surface with underline hover for a quieter page transition.",
17728
- supportedLayoutIds: supportedLayouts(["classic", "centered"]),
17729
- navTypography: "plain"
17792
+ supportedLayoutIds: supportedLayouts(["classic", "centered"])
17730
17793
  },
17731
17794
  {
17732
17795
  id: asHeaderStyleId("soft-bar"),
17733
17796
  label: "Soft Bar",
17734
17797
  description: "Soft tinted surface with gentle pill hover states.",
17735
- supportedLayoutIds: supportedLayouts(["classic", "centered"]),
17736
- navTypography: "plain"
17798
+ supportedLayoutIds: supportedLayouts(["classic", "centered"])
17737
17799
  },
17738
17800
  {
17739
17801
  id: asHeaderStyleId("pill-nav"),
17740
17802
  label: "Pill Nav",
17741
17803
  description: "A calm pill navigation rail over a neutral header.",
17742
- supportedLayoutIds: supportedLayouts(["classic", "centered"]),
17743
- navTypography: "plain"
17804
+ supportedLayoutIds: supportedLayouts(["classic", "centered"])
17744
17805
  },
17745
17806
  {
17746
17807
  id: asHeaderStyleId("brand-bar"),
17747
17808
  label: "Brand Bar",
17748
17809
  description: "Solid brand surface with high-contrast navigation.",
17749
- supportedLayoutIds: supportedLayouts(["classic", "centered"]),
17750
- navTypography: "brand-caps"
17810
+ supportedLayoutIds: supportedLayouts(["classic", "centered"])
17751
17811
  },
17752
17812
  {
17753
17813
  id: asHeaderStyleId("brand-underline"),
17754
17814
  label: "Brand Underline",
17755
17815
  description: "Brand surface with underline-grow navigation.",
17756
- supportedLayoutIds: supportedLayouts(["classic"]),
17757
- navTypography: "brand-caps"
17816
+ supportedLayoutIds: supportedLayouts(["classic"])
17758
17817
  },
17759
17818
  {
17760
17819
  id: asHeaderStyleId("brand-pill"),
@@ -17764,73 +17823,78 @@ const headerStyleCatalog = defineExactCatalog()([
17764
17823
  "classic",
17765
17824
  "centered",
17766
17825
  "floating"
17767
- ]),
17768
- navTypography: "brand-caps"
17826
+ ])
17769
17827
  },
17770
17828
  {
17771
17829
  id: asHeaderStyleId("brand-capsule"),
17772
17830
  label: "Brand Capsule",
17773
17831
  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"
17832
+ supportedLayoutIds: supportedLayouts(["classic"])
17776
17833
  },
17777
17834
  {
17778
17835
  id: asHeaderStyleId("serif-line"),
17779
17836
  label: "Serif Line",
17780
17837
  description: "Typographic logo treatment with understated underline navigation.",
17781
- supportedLayoutIds: supportedLayouts(["classic", "centered"]),
17782
- navTypography: "heading"
17838
+ supportedLayoutIds: supportedLayouts(["classic", "centered"])
17783
17839
  },
17784
17840
  {
17785
17841
  id: asHeaderStyleId("flat-tabs"),
17786
17842
  label: "Flat Tabs",
17787
17843
  description: "Flat block hover and active states with a Swiss utility feel.",
17788
- supportedLayoutIds: supportedLayouts(["classic", "centered"]),
17789
- navTypography: "quiet-caps"
17844
+ supportedLayoutIds: supportedLayouts(["classic", "centered"])
17790
17845
  },
17791
17846
  {
17792
17847
  id: asHeaderStyleId("glass"),
17793
17848
  label: "Glass",
17794
17849
  description: "Translucent chrome with frosted navigation backing.",
17795
- supportedLayoutIds: supportedLayouts(["floating"]),
17796
- navTypography: "plain"
17850
+ supportedLayoutIds: supportedLayouts(["floating"])
17797
17851
  },
17798
17852
  {
17799
17853
  id: asHeaderStyleId("minimal-surface"),
17800
17854
  label: "Clear Split",
17801
17855
  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
17856
+ supportedLayoutIds: supportedLayouts(["floating"])
17807
17857
  },
17808
17858
  {
17809
17859
  id: asHeaderStyleId("soft-shell"),
17810
17860
  label: "Soft Shell",
17811
17861
  description: "Floating rounded shell with soft pill navigation states.",
17812
- supportedLayoutIds: supportedLayouts(["floating"]),
17813
- navTypography: "plain"
17862
+ supportedLayoutIds: supportedLayouts(["floating"])
17814
17863
  },
17815
17864
  {
17816
17865
  id: asHeaderStyleId("split-glass"),
17817
17866
  label: "Split Glass",
17818
17867
  description: "Logo floats independently while the navigation sits in a glass rail.",
17819
- supportedLayoutIds: supportedLayouts(["floating"]),
17820
- navTypography: "quiet-caps",
17821
- openingForegroundTarget: "brand-only"
17868
+ supportedLayoutIds: supportedLayouts(["floating"])
17822
17869
  },
17823
17870
  {
17824
17871
  id: asHeaderStyleId("split-pill"),
17825
17872
  label: "Split Pill",
17826
17873
  description: "Logo floats independently with a soft pill-backed navigation rail.",
17827
- supportedLayoutIds: supportedLayouts(["floating"]),
17828
- navTypography: "heading",
17829
- openingForegroundTarget: "brand-only"
17874
+ supportedLayoutIds: supportedLayouts(["floating"])
17830
17875
  }
17831
17876
  ]);
17832
17877
  new Map(headerLayoutCatalog.map((layout) => [layout.id, layout]));
17833
17878
  new Map(headerStyleCatalog.map((style) => [style.id, style]));
17879
+ defineLookOptionGroup({
17880
+ id: "interaction-palette",
17881
+ label: "Hover colour",
17882
+ defaultOptionId: "accent",
17883
+ options: [
17884
+ {
17885
+ id: "accent",
17886
+ label: "Accent"
17887
+ },
17888
+ {
17889
+ id: "primary",
17890
+ label: "Primary"
17891
+ },
17892
+ {
17893
+ id: "secondary",
17894
+ label: "Secondary"
17895
+ }
17896
+ ]
17897
+ });
17834
17898
  function asFooterLookId(value) {
17835
17899
  return value;
17836
17900
  }
@@ -28785,26 +28849,6 @@ const headerLogoTextVisibleTransform = {
28785
28849
  return resolveHeaderBrandDisplay(asPartialObject(value)) !== "logo-only";
28786
28850
  }
28787
28851
  };
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
28852
  const maxWidthClassTransform = {
28809
28853
  id: "layout.maxWidthClass",
28810
28854
  kind: "string",
@@ -28910,7 +28954,6 @@ const headerRootClassTransform = {
28910
28954
  if (isHeaderScrollRuntimeEnabled(content)) classes.push(config.shrink);
28911
28955
  const variant = header?.variant;
28912
28956
  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
28957
  return joinClasses$2(classes);
28915
28958
  }
28916
28959
  };
@@ -29118,7 +29161,6 @@ const layoutTransforms = [
29118
29161
  headerLogoClassTransform,
29119
29162
  headerLogoMediaClassTransform,
29120
29163
  headerLogoTextVisibleTransform,
29121
- classicNavModeTransform,
29122
29164
  footerRootClassTransform,
29123
29165
  headerRootStyleTransform,
29124
29166
  headerSectionBackgroundTransform,
@@ -29521,18 +29563,7 @@ const classicLayout = inline({
29521
29563
  logoRow,
29522
29564
  createNavRow(`rb-ml-auto ${desktopOnlyDisplay("flex")} rb-gap-6`),
29523
29565
  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"));
29566
+ ], when("$root.theme.header.variant", { equals: "classic" }));
29536
29567
  const centeredLayout = stack({
29537
29568
  gap: "md",
29538
29569
  align: "center",
@@ -29597,7 +29628,6 @@ const siteHeaderManifest = createBlockManifest({
29597
29628
  }, [
29598
29629
  mobileHeaderBar,
29599
29630
  classicLayout,
29600
- classicCenteredNavLayout,
29601
29631
  centeredLayout,
29602
29632
  floatingLayout,
29603
29633
  mobileOverlay
@@ -32040,6 +32070,7 @@ const publicWholeSeriesPriceDisplaySchema = z$1.discriminatedUnion("kind", [
32040
32070
  freePriceDisplaySchema,
32041
32071
  exactPriceDisplaySchema,
32042
32072
  fromPriceDisplaySchema,
32073
+ rangePriceDisplaySchema,
32043
32074
  unavailablePriceDisplaySchema
32044
32075
  ]);
32045
32076
  z$1.discriminatedUnion("kind", [
@@ -33166,13 +33197,16 @@ function buildEventRegistrationShellStepLabels(source) {
33166
33197
  }) : false).map((step) => shellLabelForRegistrationStep(step, scopedEvents));
33167
33198
  }
33168
33199
  function scopeEventRegistrationEvents(source) {
33200
+ return toRegistrationEvents(scopeEventRegistrationSourceEvents(source));
33201
+ }
33202
+ function scopeEventRegistrationSourceEvents(source) {
33169
33203
  const scope = planEventRegistrationScope({
33170
- events: toRegistrationEvents(source.events ?? []),
33204
+ events: source.events ?? [],
33171
33205
  wholeSeriesOffering: source.wholeSeriesOffering,
33172
33206
  occurrenceContext: source.occurrenceContext,
33173
33207
  subject: source.subject
33174
33208
  });
33175
- return scope.kind === "invalidSelectedRun" ? [] : scope.events;
33209
+ return scope.kind === "invalidSelectedRun" ? [] : [...scope.events];
33176
33210
  }
33177
33211
  function shellLabelForRegistrationStep(step, events) {
33178
33212
  switch (step) {
@@ -33204,26 +33238,29 @@ const eventRegistrationBlockRuntime = defineClientOwnedBlockRuntime({
33204
33238
  source: createZodCodec(eventRegistrationSourceSchema),
33205
33239
  render: createZodCodec(eventRegistrationRenderSchema)
33206
33240
  },
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
- })
33241
+ buildRender: (source) => {
33242
+ const events = source.events == null ? null : scopeEventRegistrationSourceEvents(source);
33243
+ return {
33244
+ display: buildEventRegistrationDisplay(source),
33245
+ hydration: {
33246
+ occurrenceContext: source.occurrenceContext ?? null,
33247
+ subject: source.subject ?? null,
33248
+ events,
33249
+ wholeSeriesOfferings: source.wholeSeriesOfferings ?? null,
33250
+ wholeSeriesOffering: resolveWholeSeriesOffering(source),
33251
+ maxTickets: source.maxTickets ?? void 0,
33252
+ showVenue: source.showVenue,
33253
+ showCapacity: source.showCapacity,
33254
+ successMessage: source.successMessage,
33255
+ buttonVariant: source.buttonVariant,
33256
+ overlayEnabled: source.overlayEnabled,
33257
+ spamProtectionEnabled: source.spamProtectionEnabled,
33258
+ supportEmail: source.supportEmail,
33259
+ sitePasses: source.sitePasses ?? null,
33260
+ siteMemberships: source.siteMemberships ?? null
33261
+ }
33262
+ };
33263
+ }
33227
33264
  });
33228
33265
  function normalizeEventRegistrationEventInput(value) {
33229
33266
  if (!isRecord$22(value)) return value;
@@ -33924,67 +33961,49 @@ const MONTH_NAMES = [
33924
33961
  "November",
33925
33962
  "December"
33926
33963
  ];
33927
- /** Format a date as YYYY-MM-DD using the runtime's local timezone. */
33928
33964
  function formatDateKey(date) {
33929
- return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`;
33965
+ return `${String(date.year).padStart(4, "0")}-${String(date.month).padStart(2, "0")}-${String(date.day).padStart(2, "0")}`;
33930
33966
  }
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);
33967
+ function isToday(date, today) {
33968
+ return isSameCalendarDay(date, today);
33938
33969
  }
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();
33970
+ function isSameCalendarDay(left, right) {
33971
+ return left.year === right.year && left.month === right.month && left.day === right.day;
33972
+ }
33973
+ function addDays(date, days) {
33974
+ const result = new Date(Date.UTC(date.year, date.month - 1, date.day + days, 12));
33975
+ return {
33976
+ year: result.getUTCFullYear(),
33977
+ month: result.getUTCMonth() + 1,
33978
+ day: result.getUTCDate()
33979
+ };
33942
33980
  }
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
33981
  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;
33982
+ const firstDay = {
33983
+ year,
33984
+ month,
33985
+ day: 1
33986
+ };
33987
+ const dayOfWeek = getDayOfWeek(firstDay);
33988
+ const gridStart = addDays(firstDay, -(startOfWeek === "monday" ? dayOfWeek === 0 ? 6 : dayOfWeek - 1 : dayOfWeek));
33989
+ return Array.from({ length: 42 }, (_, index) => addDays(gridStart, index));
33960
33990
  }
33961
- /** Build the 7 dates of the week containing `baseDate`. */
33962
33991
  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;
33992
+ const dayOfWeek = getDayOfWeek(baseDate);
33993
+ const weekStart = addDays(baseDate, -(startOfWeek === "monday" ? dayOfWeek === 0 ? 6 : dayOfWeek - 1 : dayOfWeek));
33994
+ return Array.from({ length: 7 }, (_, index) => addDays(weekStart, index));
33995
+ }
33996
+ function getDayOfWeek(date) {
33997
+ return new Date(Date.UTC(date.year, date.month - 1, date.day, 12)).getUTCDay();
33974
33998
  }
33975
- /** Build the 7 dates of the week containing `baseDate` as a fixed-width tuple. */
33976
33999
  function getWeekCalendarDayTuple(baseDate, startOfWeek) {
33977
34000
  const days = getWeekCalendarDays(baseDate, startOfWeek);
33978
34001
  assertWeekCalendarDays(days);
33979
34002
  return days;
33980
34003
  }
33981
34004
  function assertWeekCalendarDays(days) {
33982
- if (days.length !== 7) throw new Error("Expected week calendar helper to return exactly 7 days");
34005
+ if (days.length !== 7) throw new Error("Expected exactly 7 calendar days");
33983
34006
  }
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
34007
  function getOrderedDayNames(startOfWeek, dayNames = DAY_NAMES) {
33989
34008
  if (startOfWeek === "monday") {
33990
34009
  const sunday = dayNames[0] ?? "Sun";
@@ -33992,22 +34011,17 @@ function getOrderedDayNames(startOfWeek, dayNames = DAY_NAMES) {
33992
34011
  }
33993
34012
  return [...dayNames];
33994
34013
  }
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
34014
  function formatCalendarTitle(viewDate, view, days, monthNames = MONTH_NAMES) {
34001
34015
  if (view === "week") {
34002
34016
  const weekStart = days[0];
34003
34017
  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()}`;
34018
+ if (weekStart === void 0 || weekEnd === void 0) return `${monthNames[viewDate.month - 1] ?? ""} ${viewDate.year}`;
34019
+ const startMonth = monthNames[weekStart.month - 1] ?? "";
34020
+ const endMonth = monthNames[weekEnd.month - 1] ?? "";
34021
+ if (weekStart.month === weekEnd.month) return `${startMonth} ${weekStart.day} - ${weekEnd.day}, ${weekEnd.year}`;
34022
+ return `${startMonth} ${weekStart.day} - ${endMonth} ${weekEnd.day}, ${weekEnd.year}`;
34009
34023
  }
34010
- return `${monthNames[viewDate.getMonth()] ?? ""} ${viewDate.getFullYear()}`;
34024
+ return `${monthNames[viewDate.month - 1] ?? ""} ${viewDate.year}`;
34011
34025
  }
34012
34026
  function buildCalendarViewport(input) {
34013
34027
  const monthNames = input.monthNames ?? MONTH_NAMES;
@@ -34017,10 +34031,10 @@ function buildCalendarViewport(input) {
34017
34031
  kind: "week",
34018
34032
  anchorDate: input.anchorDate,
34019
34033
  days,
34020
- title: formatCalendarTitle(input.anchorDate, "week", [...days], monthNames)
34034
+ title: formatCalendarTitle(input.anchorDate, "week", days, monthNames)
34021
34035
  };
34022
34036
  }
34023
- const days = getMonthCalendarDays(input.anchorDate.getFullYear(), input.anchorDate.getMonth(), input.startOfWeek);
34037
+ const days = getMonthCalendarDays(input.anchorDate.year, input.anchorDate.month, input.startOfWeek);
34024
34038
  return {
34025
34039
  kind: "month",
34026
34040
  anchorDate: input.anchorDate,
@@ -34168,13 +34182,12 @@ function buildTimetableModel$1(input) {
34168
34182
  const bounds = resolveBounds(input.bounds);
34169
34183
  const viewportDays = getTimetableDays(input.viewDate, input.view ?? "week", input.startOfWeek);
34170
34184
  const viewportKeys = new Set(viewportDays.map(formatDateKey));
34171
- const now = input.now ?? /* @__PURE__ */ new Date();
34172
34185
  const parsed = parseAllItems(input.items, input);
34173
34186
  const inViewport = deriveVisibleSegments(parsed.drafts, viewportKeys);
34174
34187
  const hourRange = resolveHourRange(inViewport, bounds);
34175
34188
  const laid = layoutCellsByDate(inViewport, hourRange, bounds);
34176
34189
  return {
34177
- days: assembleDays(viewportDays, laid.cellsByDate, now),
34190
+ days: assembleDays(viewportDays, laid.cellsByDate, input.today),
34178
34191
  hourTicks: buildHourTicks(hourRange.startHour, hourRange.endHour),
34179
34192
  startHour: hourRange.startHour,
34180
34193
  endHour: hourRange.endHour,
@@ -34231,13 +34244,13 @@ function layoutCellsByDate(segments, hourRange, bounds) {
34231
34244
  diagnostics
34232
34245
  };
34233
34246
  }
34234
- function assembleDays(viewportDays, cellsByDate, now) {
34247
+ function assembleDays(viewportDays, cellsByDate, today) {
34235
34248
  return viewportDays.map((date) => {
34236
34249
  const dateKey = formatDateKey(date);
34237
34250
  return {
34238
34251
  date,
34239
34252
  dateKey,
34240
- isToday: isSameLocalDay(date, now),
34253
+ isToday: isSameCalendarDay(date, today),
34241
34254
  cells: cellsByDate.get(dateKey) ?? []
34242
34255
  };
34243
34256
  });
@@ -34389,13 +34402,12 @@ function getTimetableDays(viewDate, view, startOfWeek) {
34389
34402
  function enumerateDateKeys(startDateKey, endDateKey) {
34390
34403
  if (startDateKey > endDateKey) throw new Error(`Invalid timetable date range: ${startDateKey} is after ${endDateKey}`);
34391
34404
  const start = parseDateKey(startDateKey);
34392
- const end = parseDateKey(endDateKey);
34405
+ parseDateKey(endDateKey);
34393
34406
  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()) {
34407
+ let cursor = start;
34408
+ while (formatDateKey(cursor) <= endDateKey) {
34397
34409
  keys.push(formatDateKey(cursor));
34398
- cursor.setDate(cursor.getDate() + 1);
34410
+ cursor = addDays(cursor, 1);
34399
34411
  }
34400
34412
  return keys;
34401
34413
  }
@@ -34620,10 +34632,10 @@ function formatEventTeacherLine(event) {
34620
34632
  * timezone). Thin domain wrapper over `groupItemsByDate` from the calendar
34621
34633
  * package; preserves the historical `Map<string, PublicEvent[]>` shape.
34622
34634
  */
34623
- function groupEventsByDate(events) {
34635
+ function groupEventsByDate(events, calendarTimeZone) {
34624
34636
  const grouped = groupItemsByDate(events, {
34625
34637
  getStartsAt: (event) => event.startsAt,
34626
- getTimeZone: (event) => event.timeZone ?? "UTC"
34638
+ getTimeZone: () => calendarTimeZone
34627
34639
  });
34628
34640
  const map = /* @__PURE__ */ new Map();
34629
34641
  for (const [dateKey, bucket] of grouped) map.set(dateKey, [...bucket]);
@@ -36409,7 +36421,8 @@ const eventCollectionSourceSchemaShape = {
36409
36421
  buttonVariant: eventButtonVariantSchema.optional(),
36410
36422
  buttonText: z$1.string().optional(),
36411
36423
  emptyMessage: z$1.string().optional(),
36412
- className: z$1.string().optional()
36424
+ className: z$1.string().optional(),
36425
+ bookingTimeZone: z$1.string().optional()
36413
36426
  };
36414
36427
  const eventCollectionDisplaySchemaShape = {
36415
36428
  events: z$1.array(publicEventSchema),
@@ -36444,7 +36457,15 @@ const eventCollectionHydrationSchema = z$1.object({
36444
36457
  prefetchedEvents: z$1.boolean(),
36445
36458
  eventSurface: eventSurfaceScopeSchema$1,
36446
36459
  filterEventPresets: z$1.string().nullable(),
36447
- scheduleScope: eventScheduleScopeSchema$1
36460
+ scheduleScope: eventScheduleScopeSchema$1,
36461
+ calendarContext: z$1.object({
36462
+ timeZone: z$1.string().transform(toBookingTimeZone),
36463
+ initialToday: z$1.object({
36464
+ year: z$1.number().int(),
36465
+ month: z$1.number().int().min(1).max(12),
36466
+ day: z$1.number().int().min(1).max(31)
36467
+ })
36468
+ })
36448
36469
  });
36449
36470
  function buildEventCollectionDisplay(source) {
36450
36471
  return {
@@ -36489,14 +36510,19 @@ function buildEventCollectionPresentationDisplay(source) {
36489
36510
  emptyMessage: source.emptyMessage ?? "No upcoming events scheduled."
36490
36511
  };
36491
36512
  }
36492
- function buildEventCollectionHydration(source) {
36513
+ function buildEventCollectionHydration(source, now = /* @__PURE__ */ new Date()) {
36514
+ const timeZone = toBookingTimeZone(source.bookingTimeZone);
36493
36515
  return {
36494
36516
  siteId: source.siteId,
36495
36517
  stage: source.stage,
36496
36518
  prefetchedEvents: source.events != null,
36497
36519
  eventSurface: normalizeEventSurfaceScope(source.eventSurface),
36498
36520
  filterEventPresets: normalizeEventSurfacePresetsCsv(source.filterEventPresets),
36499
- scheduleScope: normalizeEventScheduleScope(source.scheduleScope)
36521
+ scheduleScope: normalizeEventScheduleScope(source.scheduleScope),
36522
+ calendarContext: {
36523
+ timeZone,
36524
+ initialToday: getLocalScheduleDate(now, timeZone)
36525
+ }
36500
36526
  };
36501
36527
  }
36502
36528
  function buildEventCollectionListingDisplay(display, prefetchedEvents, className) {
@@ -42260,6 +42286,23 @@ function deriveNewsletterSignupRuntimeSource(values) {
42260
42286
  tags: parseTrimmedString$1(normalized.tags)
42261
42287
  };
42262
42288
  }
42289
+ function sanitizeNewsletterSignupPublicContent(content) {
42290
+ if (!isRecord$18(content)) return content;
42291
+ const provider = parseNewsletterSignupDestinationProvider(content.destinationProvider) ?? getProviderFromExplicitDestination(content.destination);
42292
+ const { destination: _destination, destinationProvider: _destinationProvider, mailchimpAudienceId: _mailchimpAudienceId, mailchimpTags: _mailchimpTags, listId, tags, ...publicContent } = content;
42293
+ const mutablePublicContent = { ...publicContent };
42294
+ if (provider !== "mailchimp") {
42295
+ if ("listId" in content) mutablePublicContent.listId = listId;
42296
+ if ("tags" in content) mutablePublicContent.tags = tags;
42297
+ }
42298
+ return mutablePublicContent;
42299
+ }
42300
+ function getProviderFromExplicitDestination(destination) {
42301
+ if (!isRecord$18(destination) || typeof destination.tag !== "string") return null;
42302
+ if (destination.tag === "riverbank_list") return "riverbank";
42303
+ if (destination.tag === "mailchimp_audience") return "mailchimp";
42304
+ return null;
42305
+ }
42263
42306
  const BLOCK_ID_PATTERN = /^[A-Za-z0-9._:-]{1,200}$/;
42264
42307
  const SIGNED_DESTINATION_REF_PATTERN = /^[A-Za-z0-9._~-]{16,1000}$/;
42265
42308
  function parseTrimmedString$1(value) {
@@ -42267,6 +42310,9 @@ function parseTrimmedString$1(value) {
42267
42310
  const trimmed = value.trim();
42268
42311
  return trimmed.length > 0 ? trimmed : null;
42269
42312
  }
42313
+ function isRecord$18(value) {
42314
+ return typeof value === "object" && value !== null;
42315
+ }
42270
42316
  //#endregion
42271
42317
  //#region ../blocks/src/system/runtime/nodes/newsletter-form.types.ts
42272
42318
  /**
@@ -46770,7 +46816,8 @@ function isOrdinaryEvent(event) {
46770
46816
  function deriveWholeSeriesPhase(sessions, nowIso) {
46771
46817
  const now = Date.parse(nowIso);
46772
46818
  if (now < Date.parse(sessions[0].startsAt)) return "upcoming";
46773
- return now <= Date.parse(sessions.at(-1)?.endsAt ?? sessions[0].endsAt) ? "inProgress" : "completed";
46819
+ const finalSession = sessions[sessions.length - 1] ?? sessions[0];
46820
+ return now <= Date.parse(finalSession.endsAt) ? "inProgress" : "completed";
46774
46821
  }
46775
46822
  function selectRelatedDates(input) {
46776
46823
  if (!input.seriesId) return [];
@@ -47168,9 +47215,13 @@ function EventDetailsSSR(props) {
47168
47215
  const { blockId, occurrenceContext = null, subject, events = null, className, children } = props;
47169
47216
  const nowIso = (/* @__PURE__ */ new Date()).toISOString();
47170
47217
  const normalizedSubject = normalizeEventRegistrationPageSurfaceSubject(subject);
47218
+ const scopedEvents = events === null ? null : resolveEventRegistrationScopedEvents(events, {
47219
+ occurrenceContext,
47220
+ subject: normalizedSubject
47221
+ });
47171
47222
  const presentation = resolveEventDetailsPresentation({
47172
47223
  ...props,
47173
- events,
47224
+ events: scopedEvents,
47174
47225
  occurrenceContext,
47175
47226
  subject: normalizedSubject,
47176
47227
  nowIso
@@ -47183,7 +47234,7 @@ function EventDetailsSSR(props) {
47183
47234
  /* @__PURE__ */ jsx(IslandPropsScript, { value: {
47184
47235
  occurrenceContext,
47185
47236
  subject: normalizedSubject,
47186
- events,
47237
+ events: scopedEvents,
47187
47238
  showVenue: presentation.showVenue,
47188
47239
  showMap: presentation.showMap,
47189
47240
  showOtherDates: presentation.showOtherDates,
@@ -48865,9 +48916,9 @@ const FULL_DAY_NAMES$1 = [
48865
48916
  * @returns "Monday, January 13"
48866
48917
  */
48867
48918
  function formatAgendaDayHeader(date) {
48868
- const dayName = FULL_DAY_NAMES$1[date.getDay()];
48869
- const monthName = MONTH_NAMES[date.getMonth()];
48870
- return `${dayName ?? "Day"}, ${monthName ?? "Month"} ${date.getDate()}`;
48919
+ const dayName = FULL_DAY_NAMES$1[getDayOfWeek(date)];
48920
+ const monthName = MONTH_NAMES[date.month - 1];
48921
+ return `${dayName ?? "Day"}, ${monthName ?? "Month"} ${date.day}`;
48871
48922
  }
48872
48923
  /**
48873
48924
  * WeekAgendaView Component
@@ -48875,14 +48926,14 @@ function formatAgendaDayHeader(date) {
48875
48926
  * Displays a week of events in an agenda/list style with rich event details.
48876
48927
  * Shows all 7 days with date headers, empty days show "No events scheduled".
48877
48928
  */
48878
- const WeekAgendaView = ({ days, events, showCapacity, emptyMessage = "No events scheduled" }) => {
48879
- const eventsByDate = groupEventsByDate(events);
48929
+ const WeekAgendaView = ({ days, events, showCapacity, emptyMessage = "No events scheduled", calendarTimeZone, today: currentDate }) => {
48930
+ const eventsByDate = groupEventsByDate(events, calendarTimeZone);
48880
48931
  return /* @__PURE__ */ jsx("div", {
48881
48932
  className: "event-agenda-week",
48882
48933
  children: days.map((date) => {
48883
48934
  const dateKey = formatDateKey(date);
48884
48935
  const dayEvents = eventsByDate.get(dateKey) || [];
48885
- const today = isToday(date);
48936
+ const today = isToday(date, currentDate);
48886
48937
  return /* @__PURE__ */ jsxs("div", {
48887
48938
  className: `event-agenda-day ${today ? "event-agenda-day--today" : ""}`,
48888
48939
  children: [/* @__PURE__ */ jsx("div", {
@@ -48911,6 +48962,50 @@ const WeekAgendaView = ({ days, events, showCapacity, emptyMessage = "No events
48911
48962
  })
48912
48963
  });
48913
48964
  };
48965
+ //#endregion
48966
+ //#region ../blocks/src/system/runtime/nodes/events/shared/CalendarNavigationChevron.tsx
48967
+ function CalendarNavigationChevron({ direction }) {
48968
+ return /* @__PURE__ */ jsx("svg", {
48969
+ width: "20",
48970
+ height: "20",
48971
+ fill: "none",
48972
+ stroke: "currentColor",
48973
+ strokeWidth: 2,
48974
+ viewBox: "0 0 24 24",
48975
+ "aria-hidden": "true",
48976
+ children: /* @__PURE__ */ jsx("path", {
48977
+ strokeLinecap: "round",
48978
+ strokeLinejoin: "round",
48979
+ d: direction === "previous" ? "M15 19l-7-7 7-7" : "M9 5l7 7-7 7"
48980
+ })
48981
+ });
48982
+ }
48983
+ //#endregion
48984
+ //#region ../blocks/src/system/runtime/nodes/events/shared/WeekBoardView.tsx
48985
+ function buildWeekBoardNavigationState(viewport, today) {
48986
+ return {
48987
+ rangeLabel: viewport.title,
48988
+ isCurrentWeek: viewport.days.some((day) => isToday(day, today))
48989
+ };
48990
+ }
48991
+ function buildWeekBoardViewProps(display, days, navigation, events = display.events) {
48992
+ return {
48993
+ days,
48994
+ events: [...events],
48995
+ navigation,
48996
+ showCapacity: display.showCapacity,
48997
+ emptyMessage: display.emptyMessage,
48998
+ title: display.boardTitle,
48999
+ footerNote: display.footerNote,
49000
+ ctaLabel: display.loadMoreText ?? display.buttonText,
49001
+ ctaHref: display.seeAllUrl,
49002
+ buttonVariant: display.buttonVariant,
49003
+ elevated: display.elevated,
49004
+ banded: display.banded,
49005
+ calendarTimeZone: display.calendarTimeZone,
49006
+ today: display.today
49007
+ };
49008
+ }
48914
49009
  const SHORT_DAY_NAMES = [
48915
49010
  "Sun",
48916
49011
  "Mon",
@@ -48972,6 +49067,114 @@ const WeekBoardCard = ({ event, showCapacity }) => {
48972
49067
  ]
48973
49068
  });
48974
49069
  };
49070
+ const WeekBoardNavigationControls = ({ navigation, todayClassName }) => {
49071
+ const handlers = navigation.kind === "interactive" ? navigation : {
49072
+ onPrevious: void 0,
49073
+ onNext: void 0,
49074
+ onToday: void 0
49075
+ };
49076
+ const isLoading = navigation.kind === "interactive" && navigation.loadState.kind === "loading";
49077
+ return /* @__PURE__ */ jsxs("nav", {
49078
+ className: "event-week-board-navigation",
49079
+ "aria-label": "Choose week",
49080
+ children: [
49081
+ /* @__PURE__ */ jsx("button", {
49082
+ type: "button",
49083
+ className: "event-week-board-nav-button",
49084
+ "aria-label": "Previous week",
49085
+ onClick: handlers.onPrevious,
49086
+ children: /* @__PURE__ */ jsx(CalendarNavigationChevron, { direction: "previous" })
49087
+ }),
49088
+ /* @__PURE__ */ jsxs("h3", {
49089
+ className: "event-week-board-range",
49090
+ "aria-live": "polite",
49091
+ children: [navigation.rangeLabel, isLoading ? /* @__PURE__ */ jsx("span", {
49092
+ className: "event-week-board-loading",
49093
+ children: " Loading…"
49094
+ }) : null]
49095
+ }),
49096
+ /* @__PURE__ */ jsx("button", {
49097
+ type: "button",
49098
+ className: "event-week-board-nav-button",
49099
+ "aria-label": "Next week",
49100
+ onClick: handlers.onNext,
49101
+ children: /* @__PURE__ */ jsx(CalendarNavigationChevron, { direction: "next" })
49102
+ }),
49103
+ /* @__PURE__ */ jsx("button", {
49104
+ type: "button",
49105
+ className: todayClassName,
49106
+ disabled: navigation.isCurrentWeek,
49107
+ onClick: handlers.onToday,
49108
+ children: "Today"
49109
+ })
49110
+ ]
49111
+ });
49112
+ };
49113
+ const WeekBoardLegend = () => /* @__PURE__ */ jsx("div", {
49114
+ className: "event-week-board-legend",
49115
+ "aria-hidden": "true",
49116
+ children: LEGEND_ITEMS.map((item) => /* @__PURE__ */ jsxs("span", {
49117
+ className: "event-week-board-legend-item",
49118
+ children: [/* @__PURE__ */ jsx("i", {
49119
+ className: "event-week-board-legend-dot",
49120
+ "data-status": item.status
49121
+ }), item.label]
49122
+ }, item.status))
49123
+ });
49124
+ const WeekBoardLoadError = ({ navigation, buttonClassName }) => {
49125
+ if (navigation.kind !== "interactive" || navigation.loadState.kind !== "error") return null;
49126
+ return /* @__PURE__ */ jsxs("div", {
49127
+ className: "event-week-board-error",
49128
+ role: "status",
49129
+ children: [/* @__PURE__ */ jsx("p", { children: "Failed to load events" }), /* @__PURE__ */ jsx("button", {
49130
+ type: "button",
49131
+ className: buttonClassName,
49132
+ onClick: navigation.loadState.onRetry,
49133
+ children: "Try again"
49134
+ })]
49135
+ });
49136
+ };
49137
+ const WeekBoardGrid = ({ days, eventsByDate, showCapacity, today: currentDate }) => /* @__PURE__ */ jsx("div", {
49138
+ className: "event-week-board-grid",
49139
+ children: days.map((date) => {
49140
+ const dateKey = formatDateKey(date);
49141
+ const dayEvents = eventsByDate.get(dateKey) ?? [];
49142
+ const today = isToday(date, currentDate);
49143
+ return /* @__PURE__ */ jsxs("div", {
49144
+ className: clsx("event-week-board-day", dayEvents.length === 0 && "event-week-board-day--empty", today && "event-week-board-day--today"),
49145
+ children: [/* @__PURE__ */ jsxs("div", {
49146
+ className: "event-week-board-day-head",
49147
+ children: [/* @__PURE__ */ jsx("span", {
49148
+ className: "event-week-board-day-abbr",
49149
+ children: SHORT_DAY_NAMES[getDayOfWeek(date)]
49150
+ }), /* @__PURE__ */ jsx("span", {
49151
+ className: "event-week-board-day-num",
49152
+ children: date.day
49153
+ })]
49154
+ }), /* @__PURE__ */ jsx("div", {
49155
+ className: "event-week-board-day-body",
49156
+ children: dayEvents.map((event) => /* @__PURE__ */ jsx(WeekBoardCard, {
49157
+ event,
49158
+ showCapacity
49159
+ }, event.occurrenceId || event.id))
49160
+ })]
49161
+ }, dateKey);
49162
+ })
49163
+ });
49164
+ const WeekBoardFooter = ({ note, ctaHref, ctaLabel, ctaClassName }) => {
49165
+ if (note === null && ctaHref === null) return null;
49166
+ return /* @__PURE__ */ jsxs("div", {
49167
+ className: "event-week-board-foot",
49168
+ children: [note === null ? null : /* @__PURE__ */ jsx("p", {
49169
+ className: "event-week-board-foot-note",
49170
+ children: note
49171
+ }), ctaHref === null ? null : /* @__PURE__ */ jsx("a", {
49172
+ className: ctaClassName,
49173
+ href: ctaHref,
49174
+ children: ctaLabel
49175
+ })]
49176
+ });
49177
+ };
48975
49178
  /**
48976
49179
  * WeekBoardView
48977
49180
  *
@@ -48980,18 +49183,21 @@ const WeekBoardCard = ({ event, showCapacity }) => {
48980
49183
  * to a stacked list on mobile. Repurposes the week-grouped agenda data as a
48981
49184
  * board rather than an hour-positioned timetable grid.
48982
49185
  */
48983
- 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 }) => {
48984
- const eventsByDate = groupEventsByDate(events);
49186
+ 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 }) => {
49187
+ const eventsByDate = groupEventsByDate(events, calendarTimeZone);
48985
49188
  const hasAnyEvents = days.some((date) => (eventsByDate.get(formatDateKey(date)) ?? []).length > 0);
48986
49189
  const ctaClassName = themeButtonClassName({
48987
49190
  variant: buttonVariant,
48988
49191
  size: "sm"
48989
49192
  });
49193
+ const todayClassName = themeButtonClassName({
49194
+ variant: buttonVariant,
49195
+ size: "sm"
49196
+ });
48990
49197
  const hasTitle = typeof title === "string" && title.length > 0;
48991
49198
  const hasFooterNote = typeof footerNote === "string" && footerNote.length > 0;
48992
- const hasCta = typeof ctaHref === "string" && ctaHref.length > 0;
48993
49199
  const footerNoteText = hasAnyEvents ? hasFooterNote ? footerNote : null : emptyMessage;
48994
- const showFooter = hasCta || footerNoteText !== null;
49200
+ const resolvedCtaHref = typeof ctaHref === "string" && ctaHref.length > 0 ? ctaHref : null;
48995
49201
  return /* @__PURE__ */ jsx("div", {
48996
49202
  className: "event-calendar event-calendar--week-board",
48997
49203
  "data-block": "event-calendar",
@@ -49003,59 +49209,34 @@ const WeekBoardView = ({ days, events, showCapacity, emptyMessage = "No classes
49003
49209
  children: [
49004
49210
  /* @__PURE__ */ jsxs("div", {
49005
49211
  className: "event-week-board-top",
49006
- children: [hasTitle ? /* @__PURE__ */ jsx("span", {
49007
- className: "event-week-board-title",
49008
- children: title
49009
- }) : null, /* @__PURE__ */ jsx("div", {
49010
- className: "event-week-board-legend",
49011
- "aria-hidden": "true",
49012
- children: LEGEND_ITEMS.map((item) => /* @__PURE__ */ jsxs("span", {
49013
- className: "event-week-board-legend-item",
49014
- children: [/* @__PURE__ */ jsx("i", {
49015
- className: "event-week-board-legend-dot",
49016
- "data-status": item.status
49017
- }), item.label]
49018
- }, item.status))
49019
- })]
49212
+ children: [
49213
+ hasTitle ? /* @__PURE__ */ jsx("span", {
49214
+ className: "event-week-board-title",
49215
+ children: title
49216
+ }) : null,
49217
+ /* @__PURE__ */ jsx(WeekBoardNavigationControls, {
49218
+ navigation,
49219
+ todayClassName
49220
+ }),
49221
+ /* @__PURE__ */ jsx(WeekBoardLegend, {})
49222
+ ]
49020
49223
  }),
49021
- /* @__PURE__ */ jsx("div", {
49022
- className: "event-week-board-grid",
49023
- children: days.map((date) => {
49024
- const dateKey = formatDateKey(date);
49025
- const dayEvents = eventsByDate.get(dateKey) ?? [];
49026
- const today = isToday(date);
49027
- return /* @__PURE__ */ jsxs("div", {
49028
- className: clsx("event-week-board-day", dayEvents.length === 0 && "event-week-board-day--empty", today && "event-week-board-day--today"),
49029
- children: [/* @__PURE__ */ jsxs("div", {
49030
- className: "event-week-board-day-head",
49031
- children: [/* @__PURE__ */ jsx("span", {
49032
- className: "event-week-board-day-abbr",
49033
- children: SHORT_DAY_NAMES[date.getDay()]
49034
- }), /* @__PURE__ */ jsx("span", {
49035
- className: "event-week-board-day-num",
49036
- children: date.getDate()
49037
- })]
49038
- }), /* @__PURE__ */ jsx("div", {
49039
- className: "event-week-board-day-body",
49040
- children: dayEvents.map((event) => /* @__PURE__ */ jsx(WeekBoardCard, {
49041
- event,
49042
- showCapacity
49043
- }, event.occurrenceId || event.id))
49044
- })]
49045
- }, dateKey);
49046
- })
49224
+ /* @__PURE__ */ jsx(WeekBoardLoadError, {
49225
+ navigation,
49226
+ buttonClassName: todayClassName
49047
49227
  }),
49048
- showFooter ? /* @__PURE__ */ jsxs("div", {
49049
- className: "event-week-board-foot",
49050
- children: [footerNoteText !== null ? /* @__PURE__ */ jsx("p", {
49051
- className: "event-week-board-foot-note",
49052
- children: footerNoteText
49053
- }) : null, hasCta ? /* @__PURE__ */ jsx("a", {
49054
- className: ctaClassName,
49055
- href: ctaHref ?? void 0,
49056
- children: ctaLabel
49057
- }) : null]
49058
- }) : null
49228
+ /* @__PURE__ */ jsx(WeekBoardGrid, {
49229
+ days,
49230
+ eventsByDate,
49231
+ showCapacity,
49232
+ today
49233
+ }),
49234
+ /* @__PURE__ */ jsx(WeekBoardFooter, {
49235
+ note: footerNoteText,
49236
+ ctaHref: resolvedCtaHref,
49237
+ ctaLabel,
49238
+ ctaClassName
49239
+ })
49059
49240
  ]
49060
49241
  })
49061
49242
  });
@@ -49086,6 +49267,7 @@ function buildTimetableModel(input) {
49086
49267
  items: input.events,
49087
49268
  viewDate: input.viewDate,
49088
49269
  startOfWeek: input.startOfWeek,
49270
+ today: input.today,
49089
49271
  getId: (event) => event.id,
49090
49272
  getStartsAt: (event) => event.startsAt,
49091
49273
  getEndsAt: (event) => event.endsAt,
@@ -49147,10 +49329,10 @@ function formatEventTimeRange(event) {
49147
49329
  return `${formatTime(event.startsAt, { timeZone })} - ${formatTime(event.endsAt, { timeZone })}`;
49148
49330
  }
49149
49331
  function formatDayLabel(date) {
49150
- return `${FULL_DAY_NAMES[date.getDay()] ?? ""}, ${MONTH_NAMES[date.getMonth()] ?? ""} ${date.getDate()}`;
49332
+ return `${FULL_DAY_NAMES[getDayOfWeek(date)] ?? ""}, ${MONTH_NAMES[date.month - 1] ?? ""} ${date.day}`;
49151
49333
  }
49152
49334
  function formatShortDayLabel(date) {
49153
- return `${(FULL_DAY_NAMES[date.getDay()] ?? "").slice(0, 3)} ${date.getDate()}`;
49335
+ return `${(FULL_DAY_NAMES[getDayOfWeek(date)] ?? "").slice(0, 3)} ${date.day}`;
49154
49336
  }
49155
49337
  //#endregion
49156
49338
  //#region ../blocks/src/system/runtime/nodes/events/EventCalendar.server.tsx
@@ -49197,15 +49379,15 @@ function renderListSsr(display, prefetchedEvents) {
49197
49379
  renderEventCard: (event) => renderEventCard(event, listDisplay)
49198
49380
  });
49199
49381
  }
49200
- function renderCalendarSsr(display) {
49382
+ function renderCalendarSsr(display, hydration) {
49201
49383
  const calendarView = display.defaultCalendarView;
49202
- const viewDate = /* @__PURE__ */ new Date();
49384
+ const viewDate = hydration.calendarContext.initialToday;
49203
49385
  const viewport = buildCalendarViewport({
49204
49386
  view: calendarView,
49205
49387
  anchorDate: viewDate,
49206
49388
  startOfWeek: display.startOfWeek
49207
49389
  });
49208
- const eventsByDate = groupEventsByDate([...display.events]);
49390
+ const eventsByDate = groupEventsByDate([...display.events], hydration.calendarContext.timeZone);
49209
49391
  const dayNames = getOrderedDayNames(display.startOfWeek);
49210
49392
  return /* @__PURE__ */ jsxs("div", {
49211
49393
  className: clsx("event-calendar", display.className ?? void 0),
@@ -49272,7 +49454,9 @@ function renderCalendarSsr(display) {
49272
49454
  days: viewport.days,
49273
49455
  events: [...display.events],
49274
49456
  emptyMessage: display.emptyMessage,
49275
- showCapacity: display.showCapacity
49457
+ showCapacity: display.showCapacity,
49458
+ calendarTimeZone: hydration.calendarContext.timeZone,
49459
+ today: hydration.calendarContext.initialToday
49276
49460
  }) : /* @__PURE__ */ jsxs("div", {
49277
49461
  className: "event-calendar-container",
49278
49462
  children: [/* @__PURE__ */ jsx("div", {
@@ -49286,13 +49470,13 @@ function renderCalendarSsr(display) {
49286
49470
  children: viewport.days.map((date) => {
49287
49471
  const dateKey = formatDateKey(date);
49288
49472
  const dayEvents = eventsByDate.get(dateKey) || [];
49289
- const isCurrentMonth = date.getMonth() === viewDate.getMonth();
49290
- const today = isToday(date);
49473
+ const isCurrentMonth = date.month === viewDate.month;
49474
+ const today = isToday(date, hydration.calendarContext.initialToday);
49291
49475
  return /* @__PURE__ */ jsxs("div", {
49292
49476
  className: clsx("event-calendar-day", !isCurrentMonth && "event-calendar-day--other-month", today && "event-calendar-day--today"),
49293
49477
  children: [/* @__PURE__ */ jsx("div", {
49294
49478
  className: "event-calendar-day-number",
49295
- children: date.getDate()
49479
+ children: date.day
49296
49480
  }), /* @__PURE__ */ jsxs("div", {
49297
49481
  className: "event-calendar-events",
49298
49482
  children: [dayEvents.slice(0, 3).map((event) => /* @__PURE__ */ jsxs("a", {
@@ -49330,8 +49514,8 @@ function renderCalendarSsr(display) {
49330
49514
  ]
49331
49515
  });
49332
49516
  }
49333
- function renderTimetableSsr(display) {
49334
- const viewDate = /* @__PURE__ */ new Date();
49517
+ function renderTimetableSsr(display, hydration) {
49518
+ const viewDate = hydration.calendarContext.initialToday;
49335
49519
  const viewport = buildCalendarViewport({
49336
49520
  view: "week",
49337
49521
  anchorDate: viewDate,
@@ -49340,7 +49524,8 @@ function renderTimetableSsr(display) {
49340
49524
  const model = buildTimetableModel({
49341
49525
  events: [...display.events],
49342
49526
  viewDate,
49343
- startOfWeek: display.startOfWeek
49527
+ startOfWeek: display.startOfWeek,
49528
+ today: hydration.calendarContext.initialToday
49344
49529
  });
49345
49530
  const selectedDayKey = model.days.find((day) => day.isToday)?.dateKey ?? model.days[0]?.dateKey ?? "";
49346
49531
  return /* @__PURE__ */ jsxs("div", {
@@ -49495,20 +49680,21 @@ function renderTimetableSsr(display) {
49495
49680
  })]
49496
49681
  });
49497
49682
  }
49498
- function renderWeekBoardSsr(display) {
49499
- return /* @__PURE__ */ jsx(WeekBoardView, {
49500
- days: getWeekCalendarDayTuple(/* @__PURE__ */ new Date(), display.startOfWeek),
49501
- events: [...display.events],
49502
- showCapacity: display.showCapacity,
49503
- emptyMessage: display.emptyMessage,
49504
- title: display.boardTitle,
49505
- footerNote: display.footerNote,
49506
- ctaLabel: display.loadMoreText ?? display.buttonText,
49507
- ctaHref: display.seeAllUrl,
49508
- buttonVariant: display.buttonVariant,
49509
- elevated: display.elevated,
49510
- banded: display.banded
49511
- });
49683
+ function renderWeekBoardSsr(display, hydration) {
49684
+ const today = hydration.calendarContext.initialToday;
49685
+ const days = getWeekCalendarDayTuple(today, display.startOfWeek);
49686
+ const navigation = {
49687
+ kind: "static",
49688
+ ...buildWeekBoardNavigationState({
49689
+ days,
49690
+ title: formatCalendarTitle(today, "week", [...days])
49691
+ }, today)
49692
+ };
49693
+ return /* @__PURE__ */ jsx(WeekBoardView, { ...buildWeekBoardViewProps({
49694
+ ...display,
49695
+ calendarTimeZone: hydration.calendarContext.timeZone,
49696
+ today
49697
+ }, days, navigation) });
49512
49698
  }
49513
49699
  function formatHourLabel(hour) {
49514
49700
  if (hour === 0) return "12 AM";
@@ -49534,13 +49720,13 @@ const EventCalendarSSR = (props) => {
49534
49720
  content = renderListSsr(display, hydration.prefetchedEvents);
49535
49721
  break;
49536
49722
  case "timetable":
49537
- content = renderTimetableSsr(display);
49723
+ content = renderTimetableSsr(display, hydration);
49538
49724
  break;
49539
49725
  case "week-board":
49540
- content = renderWeekBoardSsr(display);
49726
+ content = renderWeekBoardSsr(display, hydration);
49541
49727
  break;
49542
49728
  case "calendar":
49543
- content = renderCalendarSsr(display);
49729
+ content = renderCalendarSsr(display, hydration);
49544
49730
  break;
49545
49731
  default: content = assertNeverDisplayMode(display.displayMode);
49546
49732
  }
@@ -52769,36 +52955,9 @@ function buildLegacyHeaderNavLinkStyle(header, contrastTreatment, navTextSize) {
52769
52955
  ...navTextSize ? { textSize: navTextSize } : {}
52770
52956
  };
52771
52957
  if (header.navWeight === "bold" && navStyle === "solid") style.textTransform = "uppercase";
52772
- applyLegacyNavEffects(style, header);
52773
52958
  applyLegacyGlassTreatment(style, header, navStyle);
52774
52959
  return style;
52775
52960
  }
52776
- function applyLegacyNavEffects(style, header) {
52777
- if (!header.navEffects) return;
52778
- const effects = style.effects = {
52779
- ...style.effects,
52780
- hover: [...style.effects?.hover ?? []],
52781
- active: [...style.effects?.active ?? []]
52782
- };
52783
- if (header.navEffects.glow) effects.hover.push({
52784
- effectId: "outer-glow",
52785
- options: { spread: 5 }
52786
- });
52787
- if (header.navEffects.neumorphic) {
52788
- effects.hover.push({
52789
- effectId: "neumorphic-shadow",
52790
- options: { mode: "pressed" }
52791
- });
52792
- effects.hover.push({
52793
- effectId: "text-color-change",
52794
- options: { hoverColorToken: "primary" }
52795
- });
52796
- }
52797
- if (header.navEffects.underlineGradient) effects.hover.push({
52798
- effectId: "border-bottom-grow",
52799
- options: { origin: "center" }
52800
- });
52801
- }
52802
52961
  function applyLegacyGlassTreatment(style, header, navStyle) {
52803
52962
  if (header.navContainer?.type !== "glass" || navStyle !== "minimal") return;
52804
52963
  style.borderRadius = "full";
@@ -52824,19 +52983,6 @@ function glassStateEffects(opacity) {
52824
52983
  //#region ../theme-core/src/header/generateHeaderCss.ts
52825
52984
  const HEADER_BLUR = "blur(12px)";
52826
52985
  const FLOATING_BLUR = "blur(16px)";
52827
- const INSET_SHELL_MARKER_CLASS = "header-bar-frame-inset-shell";
52828
- const INSET_SHELL_EDGE = "1rem";
52829
- const INSET_SHELL_INSET_BLOCK = "0.875rem";
52830
- const INSET_SHELL_RADIUS = "9999px";
52831
- const INSET_SHELL_CONTAINER_MAX = "80rem";
52832
- const INSET_SHELL_INTERIOR_PADDING_X = "1.75rem";
52833
- /**
52834
- * Whether the classic header should render as an inset "brand capsule" shell.
52835
- * The facet is only meaningful for the classic layout; other variants ignore it.
52836
- */
52837
- function usesInsetShell(header) {
52838
- return header.barFrame === "inset-shell" && header.variant === "classic";
52839
- }
52840
52986
  /**
52841
52987
  * Generate complete CSS for header system from theme config
52842
52988
  *
@@ -52914,36 +53060,7 @@ function generateHeaderRootStyles(header, themeId, tokens) {
52914
53060
  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`;
52915
53061
  const scrollTreatmentStyles = generateHeaderScrollTreatmentStyles(header.scrollTreatment, themeId, header.variant, scrolledPaintRules);
52916
53062
  if (isContainedNav || basePaintRules.length === 0) return `${baseBlock}\n${overlayFix}${scrollTreatmentStyles}`;
52917
- return `${baseBlock}\n${renderHeaderPaintTargetRules(getHeaderPaintTargets(header.variant, themeId), basePaintRules)}\n${overlayFix}${usesInsetShell(header) ? generateInsetShellStyles(header, themeId) : ""}${scrollTreatmentStyles}`;
52918
- }
52919
- /**
52920
- * Reshapes the full-bleed header paint layer into a contained brand capsule at
52921
- * the desktop breakpoint. The capsule is centred, capped to the page container
52922
- * width, inset from the top, fully rounded, and carries the header depth so it
52923
- * reads as a floating pill. Root border/shadow are neutralised on desktop so a
52924
- * bordered style does not leave a full-width hairline around the capsule. Sticky
52925
- * positioning is unaffected — the root stays full width and sticky while the
52926
- * ::before paint provides the capsule.
52927
- */
52928
- function generateInsetShellStyles(header, themeId) {
52929
- const scope = `:where([data-theme-scope="${themeId}"])`;
52930
- const shellRootSelector = `${scope} .header-root.${INSET_SHELL_MARKER_CLASS}`;
52931
- const shellBeforeSelector = `${scope} .header-root.${INSET_SHELL_MARKER_CLASS}::before`;
52932
- const layoutSelector = `${scope} .header-root.${INSET_SHELL_MARKER_CLASS} .rb-header-layout`;
52933
- const widthValue = header.maxWidth === "full" ? `calc(100% - (${INSET_SHELL_EDGE} * 2))` : `min(${INSET_SHELL_CONTAINER_MAX}, calc(100% - (${INSET_SHELL_EDGE} * 2)))`;
52934
- const shadowVar = getComponentShadowVar(header.shadow?.elevation ?? "none");
52935
- const rootRules = ["border: none;", "box-shadow: none;"];
52936
- const beforeRules = [
52937
- `inset: ${INSET_SHELL_INSET_BLOCK} auto;`,
52938
- "left: 50%;",
52939
- "right: auto;",
52940
- "transform: translateX(-50%);",
52941
- `width: ${widthValue};`,
52942
- `border-radius: ${INSET_SHELL_RADIUS};`,
52943
- ...shadowVar ? [`box-shadow: ${shadowVar};`] : []
52944
- ];
52945
- const layoutRules = [`padding-inline: ${INSET_SHELL_INTERIOR_PADDING_X};`];
52946
- 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`;
53063
+ return `${baseBlock}\n${renderHeaderPaintTargetRules(getHeaderPaintTargets(header.variant, themeId), basePaintRules)}\n${overlayFix}${scrollTreatmentStyles}`;
52947
53064
  }
52948
53065
  /**
52949
53066
  * Generate logo typography styles
@@ -53017,7 +53134,7 @@ function generateLogoTextBehaviorStyles(logoText, themeId) {
53017
53134
  * Generate navigation link styles based on navStyle and effects
53018
53135
  *
53019
53136
  * Uses the composable NavLinkStyle system with backward compatibility for
53020
- * legacy navStyle, navWeight, navColor, and navEffects settings.
53137
+ * legacy navStyle, navWeight and navColor settings.
53021
53138
  */
53022
53139
  function generateNavLinkStyles(header, themeId, tokens, theme, contrastTreatment, navTextSize) {
53023
53140
  const navPreferences = {
@@ -55654,9 +55771,43 @@ function pageBlockPosition(index, blockCount) {
55654
55771
  return "middle";
55655
55772
  }
55656
55773
  //#endregion
55774
+ //#region ../blocks/src/pageRenderAdmission.ts
55775
+ function toPresentationPage(page) {
55776
+ if (!page) return null;
55777
+ return {
55778
+ ...page,
55779
+ blocks: page.blocks.map((block) => {
55780
+ const presentationMetadata = {
55781
+ id: block.id,
55782
+ kind: block.kind,
55783
+ purpose: block.purpose,
55784
+ ...block.bindings ? { bindings: block.bindings } : {}
55785
+ };
55786
+ return block.admission.kind === "renderable" ? {
55787
+ ...presentationMetadata,
55788
+ content: block.admission.content,
55789
+ presentationAdmission: { kind: "renderable" }
55790
+ } : {
55791
+ ...presentationMetadata,
55792
+ presentationAdmission: {
55793
+ kind: "invalid",
55794
+ error: block.admission.error
55795
+ }
55796
+ };
55797
+ })
55798
+ };
55799
+ }
55800
+ //#endregion
55657
55801
  //#region ../blocks/src/PageRenderer.tsx
55658
55802
  function PageRenderer$1(props) {
55659
- const { page, runtimeBoundaries, usePlaceholders = false, dataContext, wrapBlock, wrapBoundary, registry, routeMap, blockOverrides, sdkConfig, customBlocks, previewAuthoring } = props;
55803
+ const page = React$1.useMemo(() => toPresentationPage(props.page), [props.page]);
55804
+ return /* @__PURE__ */ jsx(PageRendererCore, {
55805
+ ...props,
55806
+ page
55807
+ });
55808
+ }
55809
+ function PageRendererCore(props) {
55810
+ const { page, runtimeBoundaries, dataContext, wrapBlock, wrapBoundary, registry } = props;
55660
55811
  const imageResolveContext = React$1.useMemo(() => resolvePageRendererImageResolveContext(dataContext), [
55661
55812
  dataContext?.imageResolveContext,
55662
55813
  dataContext?.mediaAssets,
@@ -55755,11 +55906,11 @@ function resolvePageRendererImageResolveContext(dataContext) {
55755
55906
  mediaAssets: input?.mediaAssets ?? dataContext?.mediaAssets
55756
55907
  });
55757
55908
  }
55909
+ const resolveBookingTimeZone = (dataContext) => dataContext?.bookingTimeZone;
55758
55910
  function buildBlockSectionProps(input) {
55759
55911
  return {
55760
55912
  themeResources: input.themeResources,
55761
55913
  block: input.block,
55762
- usePlaceholders: input.props.usePlaceholders ?? false,
55763
55914
  dataContext: input.props.dataContext,
55764
55915
  blockKey: input.blockKey,
55765
55916
  registry: input.registry,
@@ -55783,7 +55934,6 @@ function getBlockOverride(blockKind, overrides) {
55783
55934
  if (overrides[shortKind]) return overrides[shortKind];
55784
55935
  }
55785
55936
  const blockComponentCache = /* @__PURE__ */ new WeakMap();
55786
- const manifestValidatorCache = /* @__PURE__ */ new WeakMap();
55787
55937
  const DEFAULT_PERF_SLOW_BLOCK_RENDER_THRESHOLD_MS = 25;
55788
55938
  let cachedPerfSlowBlockRenderThresholdMs = null;
55789
55939
  function getPerfSlowBlockRenderThresholdMs() {
@@ -55801,44 +55951,13 @@ function getCachedBlockComponent(manifest) {
55801
55951
  return created;
55802
55952
  }
55803
55953
  /**
55804
- * Render-time manifest validator — see `.claude/plans/dapper-jingling-emerson.md`
55805
- * Phase 10. One function, two flavours:
55806
- *
55807
- * - `strict` (default): the contract every render surface tries first. No
55808
- * null tolerance, no missing-required tolerance. Production frontends and
55809
- * the dashboard preview both go through this path; after Phases 6-9 the
55810
- * preview satisfies strict structurally.
55811
- * - `relaxed`: editor-mid-edit fallback. Reached via `usePlaceholders` when
55812
- * strict fails. Built on `mode: 'draft'` so empty required fields parse
55813
- * as `undefined` and the user's valid in-flight fields flow through.
55814
- *
55815
- * Per-manifest, per-flavour cached. Adding a third flavour means adding a
55816
- * branch to the `createManifestValidator` call below and a member to
55817
- * `ValidationFlavour` — no per-flavour helper duplication.
55818
- */
55819
- function getCachedValidator(manifest, flavour) {
55820
- let perFlavour = manifestValidatorCache.get(manifest);
55821
- if (!perFlavour) {
55822
- perFlavour = /* @__PURE__ */ new Map();
55823
- manifestValidatorCache.set(manifest, perFlavour);
55824
- }
55825
- const cached = perFlavour.get(flavour);
55826
- if (cached) return cached;
55827
- const created = createManifestValidator(manifest, {
55828
- allowNull: false,
55829
- ...flavour === "relaxed" ? { mode: "draft" } : {}
55830
- });
55831
- perFlavour.set(flavour, created);
55832
- return created;
55833
- }
55834
- /**
55835
55954
  * Memoized block section component.
55836
55955
  *
55837
55956
  * Custom memoization prevents render loops during editing by explicitly checking
55838
55957
  * referential equality of all props that affect rendering. Standard React.memo
55839
55958
  * wouldn't catch all the render triggers from the editor store.
55840
55959
  */
55841
- const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeResources, block, usePlaceholders, dataContext, registry, routeMap, wrapBlock, blockOverrides, sdkConfig, customBlocks, imageResolveContext, previewAuthoring }) {
55960
+ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeResources, block, dataContext, registry, routeMap, wrapBlock, blockOverrides, sdkConfig, customBlocks, imageResolveContext, previewAuthoring }) {
55842
55961
  const perfStart = globalThis.process?.env?.DEBUG_PERF === "1" && typeof window === "undefined" ? Date.now() : 0;
55843
55962
  const fallbackImageResolveContext = getCurrentResolveImageUrlContext();
55844
55963
  const resolvedImageResolveContext = imageResolveContext ?? fallbackImageResolveContext;
@@ -55858,6 +55977,19 @@ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeResources
55858
55977
  } catch {}
55859
55978
  return node;
55860
55979
  }
55980
+ if (block.presentationAdmission.kind === "invalid") {
55981
+ try {
55982
+ if (globalThis.process?.env?.NODE_ENV !== "production") console.warn("[blocks:PageRenderer] block admission failed", {
55983
+ blockId: block.id ?? null,
55984
+ blockKind: block.kind,
55985
+ error: block.presentationAdmission.error
55986
+ });
55987
+ } catch {}
55988
+ return finish(fallback(`Invalid content for block kind "${block.kind}".`), {
55989
+ outcome: "invalidContent",
55990
+ override: false
55991
+ });
55992
+ }
55861
55993
  const OverrideComponent = getBlockOverride(block.kind, blockOverrides);
55862
55994
  requireBlockOverride(themeResources, OverrideComponent, block.kind);
55863
55995
  let definition = getBlockDefinition(block.kind);
@@ -55927,25 +56059,10 @@ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeResources
55927
56059
  });
55928
56060
  }
55929
56061
  const content = getRenderableContent(block, dataContext?.previewStage);
55930
- const parsed = getCachedValidator(definition.manifest, "strict").safeParse(content);
55931
- try {
55932
- if (globalThis.process?.env?.NODE_ENV !== "production" && !parsed.success && !usePlaceholders) console.warn("[blocks:PageRenderer] manifest validation failed", {
55933
- blockId: block.id ?? null,
55934
- blockKind: block.kind,
55935
- content: summarizeValue(content),
55936
- expectedFields: (definition.manifest.fields ?? []).map((f) => ({
55937
- id: f.id,
55938
- type: f.type,
55939
- required: !!f.required
55940
- })),
55941
- issues: parsed.error?.issues ?? null
55942
- });
55943
- } catch {}
55944
- let data;
55945
- if (parsed.success) data = parsed.data;
55946
- else if (usePlaceholders) {
55947
- const relaxed = getCachedValidator(definition.manifest, "relaxed").safeParse(content);
55948
- if (relaxed.success) data = relaxed.data;
56062
+ let data = content;
56063
+ if (block.presentationAdmission.kind === "editor") {
56064
+ const draft = validateManifestDraft(compileManifestContentContract(definition.manifest), content);
56065
+ if (draft.kind === "previewable") data = draft.data;
55949
56066
  else {
55950
56067
  const rendered = fallback(`Unable to render block kind "${block.kind}".`);
55951
56068
  return finish(wrapBlock && block.id ? /* @__PURE__ */ jsx(Fragment, { children: wrapBlock(block.id, rendered) }) : /* @__PURE__ */ jsx(Fragment, { children: rendered }), {
@@ -55953,12 +56070,6 @@ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeResources
55953
56070
  override: false
55954
56071
  });
55955
56072
  }
55956
- } else {
55957
- const rendered = fallback(`Invalid content for block kind "${block.kind}".`);
55958
- return finish(wrapBlock && block.id ? /* @__PURE__ */ jsx(Fragment, { children: wrapBlock(block.id, rendered) }) : /* @__PURE__ */ jsx(Fragment, { children: rendered }), {
55959
- outcome: "invalidContent",
55960
- override: false
55961
- });
55962
56073
  }
55963
56074
  try {
55964
56075
  const routes = routeMap ?? dataContext?.routes;
@@ -55984,6 +56095,7 @@ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeResources
55984
56095
  blockId: block.id ?? null,
55985
56096
  blockKind: block.kind
55986
56097
  };
56098
+ baseProps.bookingTimeZone = resolveBookingTimeZone(dataContext);
55987
56099
  let rendered;
55988
56100
  if (OverrideComponent) rendered = /* @__PURE__ */ jsx(OverrideComponent, { ...baseProps });
55989
56101
  else {
@@ -56030,14 +56142,14 @@ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeResources
56030
56142
  hasResolvedData
56031
56143
  });
56032
56144
  } catch {
56033
- const rendered = usePlaceholders ? fallback(`Unable to render block kind "${block.kind}".`) : fallback(`Invalid content for block kind "${block.kind}".`);
56145
+ const rendered = block.presentationAdmission.kind === "editor" ? fallback(`Unable to render block kind "${block.kind}".`) : fallback(`Invalid content for block kind "${block.kind}".`);
56034
56146
  return finish(wrapBlock && block.id ? /* @__PURE__ */ jsx(Fragment, { children: wrapBlock(block.id, rendered) }) : /* @__PURE__ */ jsx(Fragment, { children: rendered }), {
56035
56147
  outcome: "exception",
56036
56148
  override: false
56037
56149
  });
56038
56150
  }
56039
56151
  }, (prev, next) => {
56040
- 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;
56152
+ 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;
56041
56153
  });
56042
56154
  function fallback(message) {
56043
56155
  return /* @__PURE__ */ jsx("div", {
@@ -56064,32 +56176,6 @@ function getRenderableContent(block, previewStage = "published") {
56064
56176
  if (!isObjectRecord$1(source)) return {};
56065
56177
  return source;
56066
56178
  }
56067
- function summarizeValue(value) {
56068
- try {
56069
- if (value === null || value === void 0) return value;
56070
- if (typeof value === "string") return value.length > 160 ? `${value.slice(0, 160)}…` : value;
56071
- if (typeof value === "number" || typeof value === "boolean") return value;
56072
- if (Array.isArray(value)) return `[array(${value.length})]`;
56073
- if (typeof value === "object") {
56074
- const rec = value;
56075
- const keys = Object.keys(rec);
56076
- const preview = {};
56077
- for (const k of keys.slice(0, 8)) {
56078
- const v = rec[k];
56079
- if (k === "body" || k === "content") preview[k] = !!(v && typeof v === "object" && isObjectRecord$1(v) && v.type === "doc") ? "{type:doc}" : summarizeValue(v);
56080
- else preview[k] = summarizeValue(v);
56081
- }
56082
- return {
56083
- keys,
56084
- preview
56085
- };
56086
- }
56087
- if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint" || typeof value === "symbol") return String(value);
56088
- return "[uninspectable]";
56089
- } catch {
56090
- return "[uninspectable]";
56091
- }
56092
- }
56093
56179
  //#endregion
56094
56180
  //#region ../theme-core/src/generated/containerResponsiveThemeCss.ts
56095
56181
  /**
@@ -62686,31 +62772,37 @@ const containerResponsiveThemeCss = `/*
62686
62772
  */
62687
62773
 
62688
62774
  /* Main container */
62689
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar {
62775
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-calendar {
62690
62776
  width: 100%;
62691
62777
  }
62692
62778
 
62693
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-container {
62779
+ :where(.theme-scope)
62780
+ :where([data-block='event-calendar'])
62781
+ .event-calendar-container {
62694
62782
  border: 1px solid var(--ec-border);
62695
62783
  border-radius: var(--rb-block-radius);
62696
62784
  overflow: hidden;
62697
62785
  }
62698
62786
 
62699
62787
  /* Calendar navigation */
62700
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-header {
62788
+ :where(.theme-scope)
62789
+ :where([data-block='event-calendar'])
62790
+ .event-calendar-header {
62701
62791
  display: flex;
62702
62792
  align-items: center;
62703
62793
  justify-content: space-between;
62704
62794
  margin-bottom: 1rem;
62705
62795
  }
62706
62796
 
62707
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-nav {
62797
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-calendar-nav {
62708
62798
  display: flex;
62709
62799
  align-items: center;
62710
62800
  gap: 0.5rem;
62711
62801
  }
62712
62802
 
62713
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-nav-btn {
62803
+ :where(.theme-scope)
62804
+ :where([data-block='event-calendar'])
62805
+ .event-calendar-nav-btn {
62714
62806
  display: flex;
62715
62807
  align-items: center;
62716
62808
  justify-content: center;
@@ -62725,11 +62817,15 @@ const containerResponsiveThemeCss = `/*
62725
62817
  transition: background-color var(--rb-block-transition) ease;
62726
62818
  }
62727
62819
 
62728
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-nav-btn:hover {
62820
+ :where(.theme-scope)
62821
+ :where([data-block='event-calendar'])
62822
+ .event-calendar-nav-btn:hover {
62729
62823
  background-color: var(--ec-nav-hover-bg);
62730
62824
  }
62731
62825
 
62732
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-title {
62826
+ :where(.theme-scope)
62827
+ :where([data-block='event-calendar'])
62828
+ .event-calendar-title {
62733
62829
  font-size: 1.125rem;
62734
62830
  font-weight: 600;
62735
62831
  min-width: 200px;
@@ -62737,13 +62833,17 @@ const containerResponsiveThemeCss = `/*
62737
62833
  }
62738
62834
 
62739
62835
  /* Day headers */
62740
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-day-headers {
62836
+ :where(.theme-scope)
62837
+ :where([data-block='event-calendar'])
62838
+ .event-calendar-day-headers {
62741
62839
  display: grid;
62742
62840
  grid-template-columns: repeat(7, minmax(0, 1fr));
62743
62841
  background-color: var(--ec-header-bg);
62744
62842
  }
62745
62843
 
62746
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-day-header {
62844
+ :where(.theme-scope)
62845
+ :where([data-block='event-calendar'])
62846
+ .event-calendar-day-header {
62747
62847
  text-align: center;
62748
62848
  padding: 0.5rem;
62749
62849
  font-size: 0.875rem;
@@ -62753,33 +62853,43 @@ const containerResponsiveThemeCss = `/*
62753
62853
  }
62754
62854
 
62755
62855
  /* Calendar grid */
62756
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-grid {
62856
+ :where(.theme-scope)
62857
+ :where([data-block='event-calendar'])
62858
+ .event-calendar-grid {
62757
62859
  display: grid;
62758
62860
  grid-template-columns: repeat(7, minmax(0, 1fr));
62759
62861
  }
62760
62862
 
62761
62863
  /* Day cells */
62762
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-day {
62864
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-calendar-day {
62763
62865
  min-height: 100px;
62764
62866
  border-bottom: 1px solid var(--ec-border-subtle);
62765
62867
  border-right: 1px solid var(--ec-border-subtle);
62766
62868
  padding: 0.25rem;
62767
62869
  }
62768
62870
 
62769
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-day:nth-child(7n) {
62871
+ :where(.theme-scope)
62872
+ :where([data-block='event-calendar'])
62873
+ .event-calendar-day:nth-child(7n) {
62770
62874
  border-right: none;
62771
62875
  }
62772
62876
 
62773
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-day--today {
62877
+ :where(.theme-scope)
62878
+ :where([data-block='event-calendar'])
62879
+ .event-calendar-day--today {
62774
62880
  background-color: var(--ec-today-bg);
62775
62881
  }
62776
62882
 
62777
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-day--other-month {
62883
+ :where(.theme-scope)
62884
+ :where([data-block='event-calendar'])
62885
+ .event-calendar-day--other-month {
62778
62886
  opacity: var(--ec-other-month-opacity);
62779
62887
  }
62780
62888
 
62781
62889
  /* Day number */
62782
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-day-number {
62890
+ :where(.theme-scope)
62891
+ :where([data-block='event-calendar'])
62892
+ .event-calendar-day-number {
62783
62893
  font-size: 0.875rem;
62784
62894
  font-weight: 500;
62785
62895
  margin-bottom: 0.25rem;
@@ -62787,21 +62897,28 @@ const containerResponsiveThemeCss = `/*
62787
62897
  opacity: var(--ec-day-number-opacity);
62788
62898
  }
62789
62899
 
62790
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-day--today .event-calendar-day-number {
62900
+ :where(.theme-scope)
62901
+ :where([data-block='event-calendar'])
62902
+ .event-calendar-day--today
62903
+ .event-calendar-day-number {
62791
62904
  font-weight: 700;
62792
62905
  opacity: 1;
62793
62906
  color: var(--ec-today-text);
62794
62907
  }
62795
62908
 
62796
62909
  /* Events list */
62797
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-events {
62910
+ :where(.theme-scope)
62911
+ :where([data-block='event-calendar'])
62912
+ .event-calendar-events {
62798
62913
  display: flex;
62799
62914
  flex-direction: column;
62800
62915
  gap: 0.25rem;
62801
62916
  }
62802
62917
 
62803
62918
  /* Event item - solid primary background */
62804
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-event {
62919
+ :where(.theme-scope)
62920
+ :where([data-block='event-calendar'])
62921
+ .event-calendar-event {
62805
62922
  display: flex;
62806
62923
  align-items: center;
62807
62924
  gap: 0.375rem;
@@ -62822,24 +62939,32 @@ const containerResponsiveThemeCss = `/*
62822
62939
  transform var(--rb-block-transition) ease;
62823
62940
  }
62824
62941
 
62825
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-event:hover {
62942
+ :where(.theme-scope)
62943
+ :where([data-block='event-calendar'])
62944
+ .event-calendar-event:hover {
62826
62945
  background-color: var(--ec-event-solid-hover-bg);
62827
62946
  transform: translateY(-1px);
62828
62947
  }
62829
62948
 
62830
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-event:focus-visible {
62949
+ :where(.theme-scope)
62950
+ :where([data-block='event-calendar'])
62951
+ .event-calendar-event:focus-visible {
62831
62952
  outline: 2px solid var(--ec-event-solid-bg);
62832
62953
  outline-offset: 2px;
62833
62954
  }
62834
62955
 
62835
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-event-time {
62956
+ :where(.theme-scope)
62957
+ :where([data-block='event-calendar'])
62958
+ .event-calendar-event-time {
62836
62959
  flex-shrink: 0;
62837
62960
  white-space: nowrap;
62838
62961
  font-weight: 600;
62839
62962
  opacity: 0.9;
62840
62963
  }
62841
62964
 
62842
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-event-title {
62965
+ :where(.theme-scope)
62966
+ :where([data-block='event-calendar'])
62967
+ .event-calendar-event-title {
62843
62968
  min-width: 0;
62844
62969
  overflow: hidden;
62845
62970
  text-overflow: ellipsis;
@@ -62847,7 +62972,9 @@ const containerResponsiveThemeCss = `/*
62847
62972
  }
62848
62973
 
62849
62974
  /* More indicator - clickable button style */
62850
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-more {
62975
+ :where(.theme-scope)
62976
+ :where([data-block='event-calendar'])
62977
+ .event-calendar-more {
62851
62978
  font-size: 0.75rem;
62852
62979
  padding: 0.25rem 0.5rem;
62853
62980
  color: rgb(var(--tb-primary));
@@ -62859,16 +62986,22 @@ const containerResponsiveThemeCss = `/*
62859
62986
  transition: background-color var(--rb-block-transition) ease;
62860
62987
  }
62861
62988
 
62862
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-more:hover {
62989
+ :where(.theme-scope)
62990
+ :where([data-block='event-calendar'])
62991
+ .event-calendar-more:hover {
62863
62992
  background-color: rgba(var(--tb-primary), 0.1);
62864
62993
  }
62865
62994
 
62866
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-more:focus-visible {
62995
+ :where(.theme-scope)
62996
+ :where([data-block='event-calendar'])
62997
+ .event-calendar-more:focus-visible {
62867
62998
  outline: 2px solid rgb(var(--tb-primary));
62868
62999
  outline-offset: 2px;
62869
63000
  }
62870
63001
 
62871
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-empty {
63002
+ :where(.theme-scope)
63003
+ :where([data-block='event-calendar'])
63004
+ .event-calendar-empty {
62872
63005
  text-align: center;
62873
63006
  font-size: 0.875rem;
62874
63007
  opacity: var(--ec-empty-opacity);
@@ -62876,21 +63009,21 @@ const containerResponsiveThemeCss = `/*
62876
63009
  }
62877
63010
 
62878
63011
  /* Filters container */
62879
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-filters {
63012
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-filters {
62880
63013
  display: flex;
62881
63014
  flex-wrap: wrap;
62882
63015
  gap: 1rem;
62883
63016
  margin-bottom: 1.5rem;
62884
63017
  }
62885
63018
 
62886
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-filter {
63019
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-filter {
62887
63020
  display: flex;
62888
63021
  flex-direction: column;
62889
63022
  gap: 0.375rem;
62890
63023
  min-width: 180px;
62891
63024
  }
62892
63025
 
62893
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-filter-label {
63026
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-filter-label {
62894
63027
  font-size: 0.75rem;
62895
63028
  font-weight: 500;
62896
63029
  text-transform: uppercase;
@@ -62899,19 +63032,23 @@ const containerResponsiveThemeCss = `/*
62899
63032
  }
62900
63033
 
62901
63034
  /* Event filter select inherits base styling from .form-select, only block-specific overrides here */
62902
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-filter-select {
63035
+ :where(.theme-scope)
63036
+ :where([data-block='event-calendar'])
63037
+ .event-filter-select {
62903
63038
  /* Use theme input radius instead of block radius for consistency with other form inputs */
62904
63039
  border-radius: var(--rb-input-radius, var(--rb-block-radius));
62905
63040
  }
62906
63041
 
62907
63042
  /* Category filter buttons */
62908
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-category-buttons {
63043
+ :where(.theme-scope)
63044
+ :where([data-block='event-calendar'])
63045
+ .event-category-buttons {
62909
63046
  display: flex;
62910
63047
  flex-wrap: wrap;
62911
63048
  gap: 0.5rem;
62912
63049
  }
62913
63050
 
62914
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-category-btn {
63051
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-category-btn {
62915
63052
  padding: 0.5rem 1rem;
62916
63053
  font-size: 0.875rem;
62917
63054
  font-weight: 500;
@@ -62923,50 +63060,66 @@ const containerResponsiveThemeCss = `/*
62923
63060
  transition: all var(--rb-block-transition) ease;
62924
63061
  }
62925
63062
 
62926
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-category-btn:hover:not(:disabled) {
63063
+ :where(.theme-scope)
63064
+ :where([data-block='event-calendar'])
63065
+ .event-category-btn:hover:not(:disabled) {
62927
63066
  border-color: rgba(var(--tb-primary), 0.5);
62928
63067
  }
62929
63068
 
62930
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-category-btn:focus-visible {
63069
+ :where(.theme-scope)
63070
+ :where([data-block='event-calendar'])
63071
+ .event-category-btn:focus-visible {
62931
63072
  outline: 2px solid rgb(var(--tb-primary));
62932
63073
  outline-offset: 2px;
62933
63074
  }
62934
63075
 
62935
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-category-btn--active {
63076
+ :where(.theme-scope)
63077
+ :where([data-block='event-calendar'])
63078
+ .event-category-btn--active {
62936
63079
  background-color: rgb(var(--tb-primary));
62937
63080
  border-color: rgb(var(--tb-primary));
62938
63081
  color: var(--ec-event-solid-text);
62939
63082
  }
62940
63083
 
62941
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-category-btn:disabled {
63084
+ :where(.theme-scope)
63085
+ :where([data-block='event-calendar'])
63086
+ .event-category-btn:disabled {
62942
63087
  opacity: 0.5;
62943
63088
  cursor: not-allowed;
62944
63089
  }
62945
63090
 
62946
63091
  /* Allow category filter to be wider for button group */
62947
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-filter:has(.event-category-buttons) {
63092
+ :where(.theme-scope)
63093
+ :where([data-block='event-calendar'])
63094
+ .event-filter:has(.event-category-buttons) {
62948
63095
  min-width: auto;
62949
63096
  flex: 1 1 auto;
62950
63097
  }
62951
63098
 
62952
63099
  /* Combined mode container */
62953
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-combined {
63100
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-combined {
62954
63101
  width: 100%;
62955
63102
  }
62956
63103
 
62957
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-combined-content {
63104
+ :where(.theme-scope)
63105
+ :where([data-block='event-calendar'])
63106
+ .event-combined-content {
62958
63107
  display: flex;
62959
63108
  flex-direction: column;
62960
63109
  }
62961
63110
 
62962
63111
  /* Calendar view toggle (Month/Week) in Combined mode */
62963
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-view-toggle {
63112
+ :where(.theme-scope)
63113
+ :where([data-block='event-calendar'])
63114
+ .event-calendar-view-toggle {
62964
63115
  display: flex;
62965
63116
  gap: 0.25rem;
62966
63117
  margin-bottom: 1rem;
62967
63118
  }
62968
63119
 
62969
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-view-btn {
63120
+ :where(.theme-scope)
63121
+ :where([data-block='event-calendar'])
63122
+ .event-calendar-view-btn {
62970
63123
  padding: 0.5rem 1rem;
62971
63124
  font-size: 0.875rem;
62972
63125
  font-weight: 500;
@@ -62979,12 +63132,16 @@ const containerResponsiveThemeCss = `/*
62979
63132
  transition: all var(--rb-block-transition) ease;
62980
63133
  }
62981
63134
 
62982
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-view-btn:hover {
63135
+ :where(.theme-scope)
63136
+ :where([data-block='event-calendar'])
63137
+ .event-calendar-view-btn:hover {
62983
63138
  opacity: 1;
62984
63139
  border-color: rgba(var(--tb-primary), 0.5);
62985
63140
  }
62986
63141
 
62987
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-view-btn--active {
63142
+ :where(.theme-scope)
63143
+ :where([data-block='event-calendar'])
63144
+ .event-calendar-view-btn--active {
62988
63145
  opacity: 1;
62989
63146
  background-color: rgb(var(--tb-primary));
62990
63147
  border-color: rgb(var(--tb-primary));
@@ -62997,29 +63154,35 @@ const containerResponsiveThemeCss = `/*
62997
63154
  * ----------------------------------------------------------------------------- */
62998
63155
 
62999
63156
  /* Agenda week container */
63000
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-week {
63157
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-agenda-week {
63001
63158
  display: flex;
63002
63159
  flex-direction: column;
63003
63160
  gap: 0;
63004
63161
  }
63005
63162
 
63006
63163
  /* Individual day section */
63007
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-day {
63164
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-agenda-day {
63008
63165
  border-bottom: 1px solid var(--ec-border-subtle);
63009
63166
  }
63010
63167
 
63011
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-day:last-child {
63168
+ :where(.theme-scope)
63169
+ :where([data-block='event-calendar'])
63170
+ .event-agenda-day:last-child {
63012
63171
  border-bottom: none;
63013
63172
  }
63014
63173
 
63015
63174
  /* Day header */
63016
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-day-header {
63175
+ :where(.theme-scope)
63176
+ :where([data-block='event-calendar'])
63177
+ .event-agenda-day-header {
63017
63178
  padding: 0.75rem 0;
63018
63179
  background-color: var(--ec-header-bg);
63019
63180
  border-bottom: 1px solid var(--ec-border-subtle);
63020
63181
  }
63021
63182
 
63022
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-day-title {
63183
+ :where(.theme-scope)
63184
+ :where([data-block='event-calendar'])
63185
+ .event-agenda-day-title {
63023
63186
  font-size: 0.875rem;
63024
63187
  font-weight: 600;
63025
63188
  margin: 0;
@@ -63029,7 +63192,9 @@ const containerResponsiveThemeCss = `/*
63029
63192
  }
63030
63193
 
63031
63194
  /* Today badge */
63032
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-day-today-badge {
63195
+ :where(.theme-scope)
63196
+ :where([data-block='event-calendar'])
63197
+ .event-agenda-day-today-badge {
63033
63198
  display: inline-flex;
63034
63199
  align-items: center;
63035
63200
  padding: 0.125rem 0.5rem;
@@ -63043,24 +63208,33 @@ const containerResponsiveThemeCss = `/*
63043
63208
  }
63044
63209
 
63045
63210
  /* Today highlight for entire day section */
63046
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-day--today .event-agenda-day-header {
63211
+ :where(.theme-scope)
63212
+ :where([data-block='event-calendar'])
63213
+ .event-agenda-day--today
63214
+ .event-agenda-day-header {
63047
63215
  background-color: var(--ec-today-bg);
63048
63216
  }
63049
63217
 
63050
63218
  /* Day content area */
63051
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-day-content {
63219
+ :where(.theme-scope)
63220
+ :where([data-block='event-calendar'])
63221
+ .event-agenda-day-content {
63052
63222
  padding: 0.75rem 0;
63053
63223
  }
63054
63224
 
63055
63225
  /* Events list within a day */
63056
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-day-events {
63226
+ :where(.theme-scope)
63227
+ :where([data-block='event-calendar'])
63228
+ .event-agenda-day-events {
63057
63229
  display: flex;
63058
63230
  flex-direction: column;
63059
63231
  gap: 0.5rem;
63060
63232
  }
63061
63233
 
63062
63234
  /* Empty day message */
63063
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-day-empty {
63235
+ :where(.theme-scope)
63236
+ :where([data-block='event-calendar'])
63237
+ .event-agenda-day-empty {
63064
63238
  font-size: 0.875rem;
63065
63239
  opacity: var(--ec-empty-opacity);
63066
63240
  margin: 0;
@@ -63072,7 +63246,7 @@ const containerResponsiveThemeCss = `/*
63072
63246
  * Rich event card for agenda view
63073
63247
  * ----------------------------------------------------------------------------- */
63074
63248
 
63075
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-card {
63249
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-agenda-card {
63076
63250
  display: flex;
63077
63251
  align-items: flex-start;
63078
63252
  gap: 0.75rem;
@@ -63085,13 +63259,17 @@ const containerResponsiveThemeCss = `/*
63085
63259
  transition: all var(--rb-block-transition) ease;
63086
63260
  }
63087
63261
 
63088
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-card:hover {
63262
+ :where(.theme-scope)
63263
+ :where([data-block='event-calendar'])
63264
+ .event-agenda-card:hover {
63089
63265
  border-color: rgba(var(--tb-primary), 0.5);
63090
63266
  background-color: var(--ec-event-bg);
63091
63267
  }
63092
63268
 
63093
63269
  /* Category color indicator */
63094
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-card-indicator {
63270
+ :where(.theme-scope)
63271
+ :where([data-block='event-calendar'])
63272
+ .event-agenda-card-indicator {
63095
63273
  flex-shrink: 0;
63096
63274
  width: 4px;
63097
63275
  align-self: stretch;
@@ -63100,7 +63278,9 @@ const containerResponsiveThemeCss = `/*
63100
63278
  }
63101
63279
 
63102
63280
  /* Card content wrapper */
63103
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-card-content {
63281
+ :where(.theme-scope)
63282
+ :where([data-block='event-calendar'])
63283
+ .event-agenda-card-content {
63104
63284
  flex: 1;
63105
63285
  min-width: 0;
63106
63286
  display: flex;
@@ -63109,28 +63289,36 @@ const containerResponsiveThemeCss = `/*
63109
63289
  }
63110
63290
 
63111
63291
  /* Header row: time + title */
63112
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-card-header {
63292
+ :where(.theme-scope)
63293
+ :where([data-block='event-calendar'])
63294
+ .event-agenda-card-header {
63113
63295
  display: flex;
63114
63296
  align-items: baseline;
63115
63297
  gap: 0.5rem;
63116
63298
  flex-wrap: wrap;
63117
63299
  }
63118
63300
 
63119
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-card-time {
63301
+ :where(.theme-scope)
63302
+ :where([data-block='event-calendar'])
63303
+ .event-agenda-card-time {
63120
63304
  font-size: 0.75rem;
63121
63305
  font-weight: 600;
63122
63306
  opacity: var(--ec-time-opacity);
63123
63307
  white-space: nowrap;
63124
63308
  }
63125
63309
 
63126
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-card-title {
63310
+ :where(.theme-scope)
63311
+ :where([data-block='event-calendar'])
63312
+ .event-agenda-card-title {
63127
63313
  font-size: 0.875rem;
63128
63314
  font-weight: 500;
63129
63315
  line-height: 1.3;
63130
63316
  }
63131
63317
 
63132
63318
  /* Details row: venue, price, capacity */
63133
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-card-details {
63319
+ :where(.theme-scope)
63320
+ :where([data-block='event-calendar'])
63321
+ .event-agenda-card-details {
63134
63322
  display: flex;
63135
63323
  align-items: center;
63136
63324
  gap: 0.75rem;
@@ -63139,26 +63327,36 @@ const containerResponsiveThemeCss = `/*
63139
63327
  opacity: 0.7;
63140
63328
  }
63141
63329
 
63142
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-card-venue {
63330
+ :where(.theme-scope)
63331
+ :where([data-block='event-calendar'])
63332
+ .event-agenda-card-venue {
63143
63333
  display: inline-flex;
63144
63334
  align-items: center;
63145
63335
  gap: 0.25rem;
63146
63336
  }
63147
63337
 
63148
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-card-icon {
63338
+ :where(.theme-scope)
63339
+ :where([data-block='event-calendar'])
63340
+ .event-agenda-card-icon {
63149
63341
  flex-shrink: 0;
63150
63342
  opacity: 0.7;
63151
63343
  }
63152
63344
 
63153
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-card-price {
63345
+ :where(.theme-scope)
63346
+ :where([data-block='event-calendar'])
63347
+ .event-agenda-card-price {
63154
63348
  font-weight: 500;
63155
63349
  }
63156
63350
 
63157
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-card-capacity {
63351
+ :where(.theme-scope)
63352
+ :where([data-block='event-calendar'])
63353
+ .event-agenda-card-capacity {
63158
63354
  font-weight: 500;
63159
63355
  }
63160
63356
 
63161
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-card-capacity--full {
63357
+ :where(.theme-scope)
63358
+ :where([data-block='event-calendar'])
63359
+ .event-agenda-card-capacity--full {
63162
63360
  color: rgb(var(--tb-error, 239 68 68));
63163
63361
  opacity: 1;
63164
63362
  }
@@ -63168,20 +63366,24 @@ const containerResponsiveThemeCss = `/*
63168
63366
  * Time-grid layout for recurring class schedules
63169
63367
  * ----------------------------------------------------------------------------- */
63170
63368
 
63171
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable {
63369
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-timetable {
63172
63370
  display: flex;
63173
63371
  flex-direction: column;
63174
63372
  gap: 0.75rem;
63175
63373
  }
63176
63374
 
63177
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-day-selector {
63375
+ :where(.theme-scope)
63376
+ :where([data-block='event-calendar'])
63377
+ .event-timetable-day-selector {
63178
63378
  display: none;
63179
63379
  gap: 0.375rem;
63180
63380
  overflow-x: auto;
63181
63381
  padding-bottom: 0.125rem;
63182
63382
  }
63183
63383
 
63184
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-day-tab {
63384
+ :where(.theme-scope)
63385
+ :where([data-block='event-calendar'])
63386
+ .event-timetable-day-tab {
63185
63387
  flex: 0 0 auto;
63186
63388
  padding: 0.5rem 0.75rem;
63187
63389
  border: 1px solid var(--ec-border);
@@ -63196,35 +63398,49 @@ const containerResponsiveThemeCss = `/*
63196
63398
  border-color var(--rb-block-transition) ease;
63197
63399
  }
63198
63400
 
63199
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-day-tab--active {
63401
+ :where(.theme-scope)
63402
+ :where([data-block='event-calendar'])
63403
+ .event-timetable-day-tab--active {
63200
63404
  background-color: rgb(var(--tb-primary));
63201
63405
  border-color: rgb(var(--tb-primary));
63202
63406
  color: rgb(var(--tb-primaryText, 255 255 255));
63203
63407
  }
63204
63408
 
63205
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-container {
63409
+ :where(.theme-scope)
63410
+ :where([data-block='event-calendar'])
63411
+ .event-timetable-container {
63206
63412
  border: 1px solid var(--ec-border);
63207
63413
  border-radius: var(--rb-block-radius);
63208
63414
  overflow-x: auto;
63209
63415
  overflow-y: hidden;
63210
63416
  }
63211
63417
 
63212
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-grid {
63418
+ :where(.theme-scope)
63419
+ :where([data-block='event-calendar'])
63420
+ .event-timetable-grid {
63213
63421
  display: grid;
63214
63422
  grid-template-columns: 4.5rem repeat(7, minmax(8rem, 1fr));
63215
63423
  min-width: 62rem;
63216
63424
  }
63217
63425
 
63218
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-time-rail,
63219
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-day {
63426
+ :where(.theme-scope)
63427
+ :where([data-block='event-calendar'])
63428
+ .event-timetable-time-rail,
63429
+ :where(.theme-scope)
63430
+ :where([data-block='event-calendar'])
63431
+ .event-timetable-day {
63220
63432
  border-right: 1px solid var(--ec-border-subtle);
63221
63433
  }
63222
63434
 
63223
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-day:last-child {
63435
+ :where(.theme-scope)
63436
+ :where([data-block='event-calendar'])
63437
+ .event-timetable-day:last-child {
63224
63438
  border-right: none;
63225
63439
  }
63226
63440
 
63227
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-day-heading {
63441
+ :where(.theme-scope)
63442
+ :where([data-block='event-calendar'])
63443
+ .event-timetable-day-heading {
63228
63444
  min-height: 3.25rem;
63229
63445
  margin: 0;
63230
63446
  padding: 0.75rem 0.5rem;
@@ -63239,12 +63455,17 @@ const containerResponsiveThemeCss = `/*
63239
63455
  font-weight: 600;
63240
63456
  }
63241
63457
 
63242
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-day--today .event-timetable-day-heading {
63458
+ :where(.theme-scope)
63459
+ :where([data-block='event-calendar'])
63460
+ .event-timetable-day--today
63461
+ .event-timetable-day-heading {
63243
63462
  background-color: var(--ec-today-bg);
63244
63463
  color: var(--ec-today-text);
63245
63464
  }
63246
63465
 
63247
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-today-badge {
63466
+ :where(.theme-scope)
63467
+ :where([data-block='event-calendar'])
63468
+ .event-timetable-today-badge {
63248
63469
  padding: 0.125rem 0.375rem;
63249
63470
  border-radius: var(--rb-button-radius);
63250
63471
  background-color: rgb(var(--tb-primary));
@@ -63254,17 +63475,29 @@ const containerResponsiveThemeCss = `/*
63254
63475
  text-transform: uppercase;
63255
63476
  }
63256
63477
 
63257
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-time-body,
63258
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-day-body {
63478
+ :where(.theme-scope)
63479
+ :where([data-block='event-calendar'])
63480
+ .event-timetable-time-body,
63481
+ :where(.theme-scope)
63482
+ :where([data-block='event-calendar'])
63483
+ .event-timetable-day-body {
63259
63484
  position: relative;
63260
- height: clamp(34rem, calc(var(--event-timetable-range-minutes, 900) * 0.055rem), 56rem);
63485
+ height: clamp(
63486
+ 34rem,
63487
+ calc(var(--event-timetable-range-minutes, 900) * 0.055rem),
63488
+ 56rem
63489
+ );
63261
63490
  }
63262
63491
 
63263
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-time-body {
63492
+ :where(.theme-scope)
63493
+ :where([data-block='event-calendar'])
63494
+ .event-timetable-time-body {
63264
63495
  background-color: var(--ec-header-bg);
63265
63496
  }
63266
63497
 
63267
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-time-label {
63498
+ :where(.theme-scope)
63499
+ :where([data-block='event-calendar'])
63500
+ .event-timetable-time-label {
63268
63501
  position: absolute;
63269
63502
  left: 0.625rem;
63270
63503
  transform: translateY(-50%);
@@ -63273,14 +63506,18 @@ const containerResponsiveThemeCss = `/*
63273
63506
  white-space: nowrap;
63274
63507
  }
63275
63508
 
63276
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-hour-line {
63509
+ :where(.theme-scope)
63510
+ :where([data-block='event-calendar'])
63511
+ .event-timetable-hour-line {
63277
63512
  position: absolute;
63278
63513
  left: 0;
63279
63514
  right: 0;
63280
63515
  border-top: 1px solid var(--ec-border-subtle);
63281
63516
  }
63282
63517
 
63283
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event {
63518
+ :where(.theme-scope)
63519
+ :where([data-block='event-calendar'])
63520
+ .event-timetable-event {
63284
63521
  position: absolute;
63285
63522
  min-height: 2.75rem;
63286
63523
  padding: 0.375rem 0.5rem;
@@ -63300,21 +63537,35 @@ const containerResponsiveThemeCss = `/*
63300
63537
  transform var(--rb-block-transition) ease;
63301
63538
  }
63302
63539
 
63303
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event:hover {
63540
+ :where(.theme-scope)
63541
+ :where([data-block='event-calendar'])
63542
+ .event-timetable-event:hover {
63304
63543
  box-shadow: 0 4px 12px rgba(var(--tb-text), 0.12);
63305
63544
  transform: translateY(-1px);
63306
63545
  }
63307
63546
 
63308
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event:focus-visible {
63547
+ :where(.theme-scope)
63548
+ :where([data-block='event-calendar'])
63549
+ .event-timetable-event:focus-visible {
63309
63550
  outline: 2px solid rgb(var(--tb-primary));
63310
63551
  outline-offset: 2px;
63311
63552
  }
63312
63553
 
63313
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event-time,
63314
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event-title,
63315
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event-teacher,
63316
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event-meta,
63317
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event-capacity {
63554
+ :where(.theme-scope)
63555
+ :where([data-block='event-calendar'])
63556
+ .event-timetable-event-time,
63557
+ :where(.theme-scope)
63558
+ :where([data-block='event-calendar'])
63559
+ .event-timetable-event-title,
63560
+ :where(.theme-scope)
63561
+ :where([data-block='event-calendar'])
63562
+ .event-timetable-event-teacher,
63563
+ :where(.theme-scope)
63564
+ :where([data-block='event-calendar'])
63565
+ .event-timetable-event-meta,
63566
+ :where(.theme-scope)
63567
+ :where([data-block='event-calendar'])
63568
+ .event-timetable-event-capacity {
63318
63569
  display: block;
63319
63570
  min-width: 0;
63320
63571
  overflow: hidden;
@@ -63322,36 +63573,50 @@ const containerResponsiveThemeCss = `/*
63322
63573
  white-space: nowrap;
63323
63574
  }
63324
63575
 
63325
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event-time {
63576
+ :where(.theme-scope)
63577
+ :where([data-block='event-calendar'])
63578
+ .event-timetable-event-time {
63326
63579
  font-size: 0.6875rem;
63327
63580
  font-weight: 700;
63328
63581
  opacity: var(--ec-time-opacity);
63329
63582
  }
63330
63583
 
63331
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event-title {
63584
+ :where(.theme-scope)
63585
+ :where([data-block='event-calendar'])
63586
+ .event-timetable-event-title {
63332
63587
  font-size: 0.8125rem;
63333
63588
  font-weight: 700;
63334
63589
  line-height: 1.25;
63335
63590
  }
63336
63591
 
63337
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event-teacher,
63338
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event-meta {
63592
+ :where(.theme-scope)
63593
+ :where([data-block='event-calendar'])
63594
+ .event-timetable-event-teacher,
63595
+ :where(.theme-scope)
63596
+ :where([data-block='event-calendar'])
63597
+ .event-timetable-event-meta {
63339
63598
  font-size: 0.6875rem;
63340
63599
  opacity: 0.72;
63341
63600
  }
63342
63601
 
63343
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event-capacity {
63602
+ :where(.theme-scope)
63603
+ :where([data-block='event-calendar'])
63604
+ .event-timetable-event-capacity {
63344
63605
  font-size: 0.6875rem;
63345
63606
  font-weight: 600;
63346
63607
  opacity: 0.85;
63347
63608
  }
63348
63609
 
63349
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event-capacity--full {
63610
+ :where(.theme-scope)
63611
+ :where([data-block='event-calendar'])
63612
+ .event-timetable-event-capacity--full {
63350
63613
  color: rgb(var(--tb-danger, 220 38 38));
63351
63614
  opacity: 1;
63352
63615
  }
63353
63616
 
63354
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-day-empty {
63617
+ :where(.theme-scope)
63618
+ :where([data-block='event-calendar'])
63619
+ .event-timetable-day-empty {
63355
63620
  margin: 0;
63356
63621
  padding: 1rem 0.5rem;
63357
63622
  text-align: center;
@@ -63359,7 +63624,9 @@ const containerResponsiveThemeCss = `/*
63359
63624
  opacity: var(--ec-empty-opacity);
63360
63625
  }
63361
63626
 
63362
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-empty {
63627
+ :where(.theme-scope)
63628
+ :where([data-block='event-calendar'])
63629
+ .event-timetable-empty {
63363
63630
  margin: 0.25rem 0 0;
63364
63631
  text-align: center;
63365
63632
  font-size: 0.875rem;
@@ -63368,32 +63635,46 @@ const containerResponsiveThemeCss = `/*
63368
63635
 
63369
63636
  @container rb-site (max-width: 767px) {
63370
63637
  @scope ([data-rb-responsive-mode="container"]) to (:scope [data-rb-responsive-mode]) {
63371
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-day-selector {
63638
+ :where(.theme-scope)
63639
+ :where([data-block='event-calendar'])
63640
+ .event-timetable-day-selector {
63372
63641
  display: flex;
63373
63642
  }
63374
63643
 
63375
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-container {
63644
+ :where(.theme-scope)
63645
+ :where([data-block='event-calendar'])
63646
+ .event-timetable-container {
63376
63647
  overflow: hidden;
63377
63648
  }
63378
63649
 
63379
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-grid {
63650
+ :where(.theme-scope)
63651
+ :where([data-block='event-calendar'])
63652
+ .event-timetable-grid {
63380
63653
  grid-template-columns: 4rem minmax(0, 1fr);
63381
63654
  min-width: 0;
63382
63655
  }
63383
63656
 
63384
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-day[data-selected="false"] {
63657
+ :where(.theme-scope)
63658
+ :where([data-block='event-calendar'])
63659
+ .event-timetable-day[data-selected='false'] {
63385
63660
  display: none;
63386
63661
  }
63387
63662
 
63388
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-day {
63663
+ :where(.theme-scope)
63664
+ :where([data-block='event-calendar'])
63665
+ .event-timetable-day {
63389
63666
  border-right: none;
63390
63667
  }
63391
63668
 
63392
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-time-rail {
63669
+ :where(.theme-scope)
63670
+ :where([data-block='event-calendar'])
63671
+ .event-timetable-time-rail {
63393
63672
  border-right: 1px solid var(--ec-border-subtle);
63394
63673
  }
63395
63674
 
63396
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-day-heading {
63675
+ :where(.theme-scope)
63676
+ :where([data-block='event-calendar'])
63677
+ .event-timetable-day-heading {
63397
63678
  justify-content: flex-start;
63398
63679
  padding-inline: 0.75rem;
63399
63680
  }
@@ -63406,7 +63687,7 @@ const containerResponsiveThemeCss = `/*
63406
63687
  * three-state availability (available / filling / waitlist), and a footer CTA.
63407
63688
  * ----------------------------------------------------------------------------- */
63408
63689
 
63409
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board {
63690
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-week-board {
63410
63691
  /* Status accent tokens — map the three availability states onto theme colours.
63411
63692
  * available -> secondary, filling -> accent, waitlist -> muted text. */
63412
63693
  --ec-status-available: rgb(var(--tb-secondary));
@@ -63423,17 +63704,20 @@ const containerResponsiveThemeCss = `/*
63423
63704
 
63424
63705
  /* Opt-in raised look: a soft drop shadow so the board lifts off the page.
63425
63706
  * Generic default (no [data-elevated]) stays flat. */
63426
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board[data-elevated] {
63707
+ :where(.theme-scope)
63708
+ :where([data-block='event-calendar'])
63709
+ .event-week-board[data-elevated] {
63427
63710
  box-shadow: 0 14px 34px -24px rgba(var(--tb-text), 0.35);
63428
63711
  }
63429
63712
 
63430
- /* Top bar: title + legend */
63431
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-top {
63432
- display: flex;
63713
+ /* Top bar: authored title + week navigation + legend */
63714
+ :where(.theme-scope)
63715
+ :where([data-block='event-calendar'])
63716
+ .event-week-board-top {
63717
+ display: grid;
63718
+ grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
63433
63719
  align-items: center;
63434
- justify-content: space-between;
63435
63720
  gap: 1rem;
63436
- flex-wrap: wrap;
63437
63721
  padding: 1.1rem 1.5rem;
63438
63722
  /* surfaceAlt gives the header/footer a legible tint against the white day-grid
63439
63723
  * body — the faint \`--ec-header-bg\` (5% text) is invisible on light palettes. */
@@ -63441,7 +63725,10 @@ const containerResponsiveThemeCss = `/*
63441
63725
  border-bottom: 1px solid var(--ec-border-subtle);
63442
63726
  }
63443
63727
 
63444
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-title {
63728
+ :where(.theme-scope)
63729
+ :where([data-block='event-calendar'])
63730
+ .event-week-board-title {
63731
+ grid-column: 1;
63445
63732
  font-size: 0.8125rem;
63446
63733
  font-weight: 600;
63447
63734
  letter-spacing: 0.12em;
@@ -63449,7 +63736,67 @@ const containerResponsiveThemeCss = `/*
63449
63736
  color: rgb(var(--tb-primary));
63450
63737
  }
63451
63738
 
63452
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-legend {
63739
+ :where(.theme-scope)
63740
+ :where([data-block='event-calendar'])
63741
+ .event-week-board-navigation {
63742
+ grid-column: 2;
63743
+ display: flex;
63744
+ align-items: center;
63745
+ justify-content: center;
63746
+ gap: 0.65rem;
63747
+ }
63748
+
63749
+ :where(.theme-scope)
63750
+ :where([data-block='event-calendar'])
63751
+ .event-week-board-nav-button {
63752
+ display: inline-flex;
63753
+ align-items: center;
63754
+ justify-content: center;
63755
+ width: 2.25rem;
63756
+ height: 2.25rem;
63757
+ padding: 0;
63758
+ border: 1px solid var(--ec-border);
63759
+ border-radius: 999px;
63760
+ background: transparent;
63761
+ color: inherit;
63762
+ cursor: pointer;
63763
+ }
63764
+
63765
+ :where(.theme-scope)
63766
+ :where([data-block='event-calendar'])
63767
+ .event-week-board-nav-button:hover {
63768
+ background-color: var(--ec-hover-bg);
63769
+ }
63770
+
63771
+ :where(.theme-scope)
63772
+ :where([data-block='event-calendar'])
63773
+ .event-week-board-nav-button:focus-visible {
63774
+ outline: 2px solid rgb(var(--tb-primary));
63775
+ outline-offset: 2px;
63776
+ }
63777
+
63778
+ :where(.theme-scope)
63779
+ :where([data-block='event-calendar'])
63780
+ .event-week-board-range {
63781
+ min-width: 12rem;
63782
+ margin: 0;
63783
+ text-align: center;
63784
+ font-size: 0.875rem;
63785
+ font-weight: 600;
63786
+ }
63787
+
63788
+ :where(.theme-scope)
63789
+ :where([data-block='event-calendar'])
63790
+ .event-week-board-loading {
63791
+ font-weight: 400;
63792
+ opacity: 0.65;
63793
+ }
63794
+
63795
+ :where(.theme-scope)
63796
+ :where([data-block='event-calendar'])
63797
+ .event-week-board-legend {
63798
+ grid-column: 3;
63799
+ justify-self: end;
63453
63800
  display: flex;
63454
63801
  align-items: center;
63455
63802
  gap: 1.1rem;
@@ -63459,38 +63806,72 @@ const containerResponsiveThemeCss = `/*
63459
63806
  opacity: 0.75;
63460
63807
  }
63461
63808
 
63462
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-legend-item {
63809
+ :where(.theme-scope)
63810
+ :where([data-block='event-calendar'])
63811
+ .event-week-board-error {
63812
+ display: flex;
63813
+ align-items: center;
63814
+ justify-content: center;
63815
+ gap: 0.75rem;
63816
+ padding: 0.75rem 1.5rem;
63817
+ border-bottom: 1px solid var(--ec-border-subtle);
63818
+ color: rgb(var(--tb-error, var(--tb-text)));
63819
+ }
63820
+
63821
+ :where(.theme-scope)
63822
+ :where([data-block='event-calendar'])
63823
+ .event-week-board-error
63824
+ p {
63825
+ margin: 0;
63826
+ font-size: 0.8125rem;
63827
+ }
63828
+
63829
+ :where(.theme-scope)
63830
+ :where([data-block='event-calendar'])
63831
+ .event-week-board-legend-item {
63463
63832
  display: inline-flex;
63464
63833
  align-items: center;
63465
63834
  gap: 0.4rem;
63466
63835
  }
63467
63836
 
63468
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-legend-dot {
63837
+ :where(.theme-scope)
63838
+ :where([data-block='event-calendar'])
63839
+ .event-week-board-legend-dot {
63469
63840
  width: 0.55rem;
63470
63841
  height: 0.55rem;
63471
63842
  border-radius: 50%;
63472
63843
  display: inline-block;
63473
63844
  }
63474
63845
 
63475
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-legend-dot[data-status="available"] {
63846
+ :where(.theme-scope)
63847
+ :where([data-block='event-calendar'])
63848
+ .event-week-board-legend-dot[data-status='available'] {
63476
63849
  background-color: var(--ec-status-available);
63477
63850
  }
63478
63851
 
63479
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-legend-dot[data-status="filling"] {
63852
+ :where(.theme-scope)
63853
+ :where([data-block='event-calendar'])
63854
+ .event-week-board-legend-dot[data-status='filling'] {
63480
63855
  background-color: var(--ec-status-filling);
63481
63856
  }
63482
63857
 
63483
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-legend-dot[data-status="waitlist"] {
63858
+ :where(.theme-scope)
63859
+ :where([data-block='event-calendar'])
63860
+ .event-week-board-legend-dot[data-status='waitlist'] {
63484
63861
  background-color: var(--ec-status-waitlist);
63485
63862
  }
63486
63863
 
63487
63864
  /* Day columns grid */
63488
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-grid {
63865
+ :where(.theme-scope)
63866
+ :where([data-block='event-calendar'])
63867
+ .event-week-board-grid {
63489
63868
  display: grid;
63490
63869
  grid-template-columns: repeat(var(--event-week-board-cols), minmax(0, 1fr));
63491
63870
  }
63492
63871
 
63493
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-day {
63872
+ :where(.theme-scope)
63873
+ :where([data-block='event-calendar'])
63874
+ .event-week-board-day {
63494
63875
  display: flex;
63495
63876
  flex-direction: column;
63496
63877
  min-height: 15rem;
@@ -63500,11 +63881,15 @@ const containerResponsiveThemeCss = `/*
63500
63881
  border-right: var(--rb-border-width, 1px) solid rgb(var(--tb-border));
63501
63882
  }
63502
63883
 
63503
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-day:last-child {
63884
+ :where(.theme-scope)
63885
+ :where([data-block='event-calendar'])
63886
+ .event-week-board-day:last-child {
63504
63887
  border-right: none;
63505
63888
  }
63506
63889
 
63507
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-day-head {
63890
+ :where(.theme-scope)
63891
+ :where([data-block='event-calendar'])
63892
+ .event-week-board-day-head {
63508
63893
  display: flex;
63509
63894
  align-items: baseline;
63510
63895
  gap: 0.4rem;
@@ -63513,11 +63898,16 @@ const containerResponsiveThemeCss = `/*
63513
63898
  border-bottom: var(--rb-border-width, 1px) solid rgb(var(--tb-border));
63514
63899
  }
63515
63900
 
63516
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-day--today .event-week-board-day-head {
63901
+ :where(.theme-scope)
63902
+ :where([data-block='event-calendar'])
63903
+ .event-week-board-day--today
63904
+ .event-week-board-day-head {
63517
63905
  background-color: var(--ec-today-bg);
63518
63906
  }
63519
63907
 
63520
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-day-abbr {
63908
+ :where(.theme-scope)
63909
+ :where([data-block='event-calendar'])
63910
+ .event-week-board-day-abbr {
63521
63911
  font-size: 0.6875rem;
63522
63912
  font-weight: 600;
63523
63913
  letter-spacing: 0.1em;
@@ -63525,18 +63915,25 @@ const containerResponsiveThemeCss = `/*
63525
63915
  opacity: 0.65;
63526
63916
  }
63527
63917
 
63528
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-day--today .event-week-board-day-abbr {
63918
+ :where(.theme-scope)
63919
+ :where([data-block='event-calendar'])
63920
+ .event-week-board-day--today
63921
+ .event-week-board-day-abbr {
63529
63922
  opacity: 1;
63530
63923
  color: var(--ec-today-text);
63531
63924
  }
63532
63925
 
63533
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-day-num {
63926
+ :where(.theme-scope)
63927
+ :where([data-block='event-calendar'])
63928
+ .event-week-board-day-num {
63534
63929
  font-size: 0.8125rem;
63535
63930
  font-weight: 600;
63536
63931
  opacity: 0.5;
63537
63932
  }
63538
63933
 
63539
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-day-body {
63934
+ :where(.theme-scope)
63935
+ :where([data-block='event-calendar'])
63936
+ .event-week-board-day-body {
63540
63937
  display: flex;
63541
63938
  flex-direction: column;
63542
63939
  gap: 0.65rem;
@@ -63545,7 +63942,9 @@ const containerResponsiveThemeCss = `/*
63545
63942
  }
63546
63943
 
63547
63944
  /* Class card */
63548
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-card {
63945
+ :where(.theme-scope)
63946
+ :where([data-block='event-calendar'])
63947
+ .event-week-board-card {
63549
63948
  display: flex;
63550
63949
  flex-direction: column;
63551
63950
  gap: 0.45rem;
@@ -63565,40 +63964,54 @@ const containerResponsiveThemeCss = `/*
63565
63964
  border-color var(--rb-block-transition) ease;
63566
63965
  }
63567
63966
 
63568
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-card[data-status="filling"] {
63967
+ :where(.theme-scope)
63968
+ :where([data-block='event-calendar'])
63969
+ .event-week-board-card[data-status='filling'] {
63569
63970
  border-left-color: var(--ec-status-filling);
63570
63971
  }
63571
63972
 
63572
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-card[data-status="waitlist"] {
63973
+ :where(.theme-scope)
63974
+ :where([data-block='event-calendar'])
63975
+ .event-week-board-card[data-status='waitlist'] {
63573
63976
  border-left-color: var(--ec-status-waitlist);
63574
63977
  }
63575
63978
 
63576
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-card:hover {
63979
+ :where(.theme-scope)
63980
+ :where([data-block='event-calendar'])
63981
+ .event-week-board-card:hover {
63577
63982
  transform: translateY(-2px);
63578
63983
  box-shadow: 0 6px 16px -8px rgba(var(--tb-text), 0.28);
63579
63984
  border-color: rgba(var(--tb-primary), 0.4);
63580
63985
  }
63581
63986
 
63582
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-card:focus-visible {
63987
+ :where(.theme-scope)
63988
+ :where([data-block='event-calendar'])
63989
+ .event-week-board-card:focus-visible {
63583
63990
  outline: 2px solid rgb(var(--tb-primary));
63584
63991
  outline-offset: 2px;
63585
63992
  }
63586
63993
 
63587
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-card-title {
63994
+ :where(.theme-scope)
63995
+ :where([data-block='event-calendar'])
63996
+ .event-week-board-card-title {
63588
63997
  font-family: var(--font-heading, inherit);
63589
63998
  font-size: 0.9375rem;
63590
63999
  font-weight: 600;
63591
64000
  line-height: 1.2;
63592
64001
  }
63593
64002
 
63594
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-card-time {
64003
+ :where(.theme-scope)
64004
+ :where([data-block='event-calendar'])
64005
+ .event-week-board-card-time {
63595
64006
  font-size: 0.75rem;
63596
64007
  letter-spacing: 0.01em;
63597
64008
  opacity: 0.7;
63598
64009
  }
63599
64010
 
63600
64011
  /* Capacity pill */
63601
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-card-pill {
64012
+ :where(.theme-scope)
64013
+ :where([data-block='event-calendar'])
64014
+ .event-week-board-card-pill {
63602
64015
  align-self: flex-start;
63603
64016
  display: inline-flex;
63604
64017
  align-items: center;
@@ -63616,20 +64029,26 @@ const containerResponsiveThemeCss = `/*
63616
64029
  border-color: var(--ec-border);
63617
64030
  }
63618
64031
 
63619
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-card-pill[data-status="filling"] {
64032
+ :where(.theme-scope)
64033
+ :where([data-block='event-calendar'])
64034
+ .event-week-board-card-pill[data-status='filling'] {
63620
64035
  background-color: rgba(var(--tb-accent), 0.14);
63621
64036
  color: var(--ec-status-filling);
63622
64037
  border-color: rgba(var(--tb-accent), 0.32);
63623
64038
  }
63624
64039
 
63625
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-card-pill[data-status="waitlist"] {
64040
+ :where(.theme-scope)
64041
+ :where([data-block='event-calendar'])
64042
+ .event-week-board-card-pill[data-status='waitlist'] {
63626
64043
  background-color: transparent;
63627
64044
  color: rgba(var(--tb-text), 0.6);
63628
64045
  border-color: var(--ec-border);
63629
64046
  }
63630
64047
 
63631
64048
  /* Footer */
63632
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-foot {
64049
+ :where(.theme-scope)
64050
+ :where([data-block='event-calendar'])
64051
+ .event-week-board-foot {
63633
64052
  display: flex;
63634
64053
  align-items: center;
63635
64054
  justify-content: space-between;
@@ -63641,7 +64060,9 @@ const containerResponsiveThemeCss = `/*
63641
64060
  border-top: 1px solid var(--ec-border-subtle);
63642
64061
  }
63643
64062
 
63644
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-foot-note {
64063
+ :where(.theme-scope)
64064
+ :where([data-block='event-calendar'])
64065
+ .event-week-board-foot-note {
63645
64066
  margin: 0;
63646
64067
  font-size: 0.875rem;
63647
64068
  opacity: 0.75;
@@ -63650,36 +64071,69 @@ const containerResponsiveThemeCss = `/*
63650
64071
  /* Responsive: collapse day columns to a stacked list on narrow viewports */
63651
64072
  @container rb-site (max-width: 1023px) {
63652
64073
  @scope ([data-rb-responsive-mode="container"]) to (:scope [data-rb-responsive-mode]) {
63653
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-grid {
64074
+ :where(.theme-scope)
64075
+ :where([data-block='event-calendar'])
64076
+ .event-week-board-top {
64077
+ grid-template-columns: 1fr;
64078
+ }
64079
+
64080
+ :where(.theme-scope)
64081
+ :where([data-block='event-calendar'])
64082
+ .event-week-board-title,
64083
+ :where(.theme-scope)
64084
+ :where([data-block='event-calendar'])
64085
+ .event-week-board-navigation,
64086
+ :where(.theme-scope)
64087
+ :where([data-block='event-calendar'])
64088
+ .event-week-board-legend {
64089
+ grid-column: 1;
64090
+ justify-self: center;
64091
+ }
64092
+
64093
+ :where(.theme-scope)
64094
+ :where([data-block='event-calendar'])
64095
+ .event-week-board-grid {
63654
64096
  grid-template-columns: 1fr;
63655
64097
  }
63656
64098
 
63657
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-day {
64099
+ :where(.theme-scope)
64100
+ :where([data-block='event-calendar'])
64101
+ .event-week-board-day {
63658
64102
  min-height: 0;
63659
64103
  border-right: none;
63660
64104
  border-bottom: var(--rb-border-width, 1px) solid rgb(var(--tb-border));
63661
64105
  }
63662
64106
 
63663
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-day:last-child {
64107
+ :where(.theme-scope)
64108
+ :where([data-block='event-calendar'])
64109
+ .event-week-board-day:last-child {
63664
64110
  border-bottom: none;
63665
64111
  }
63666
64112
 
63667
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-day--empty {
64113
+ :where(.theme-scope)
64114
+ :where([data-block='event-calendar'])
64115
+ .event-week-board-day--empty {
63668
64116
  display: none;
63669
64117
  }
63670
64118
 
63671
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-day-head {
64119
+ :where(.theme-scope)
64120
+ :where([data-block='event-calendar'])
64121
+ .event-week-board-day-head {
63672
64122
  border-bottom: none;
63673
64123
  padding-bottom: 0.25rem;
63674
64124
  }
63675
64125
 
63676
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-day-body {
64126
+ :where(.theme-scope)
64127
+ :where([data-block='event-calendar'])
64128
+ .event-week-board-day-body {
63677
64129
  flex-direction: row;
63678
64130
  flex-wrap: wrap;
63679
64131
  padding-top: 0.35rem;
63680
64132
  }
63681
64133
 
63682
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-card {
64134
+ :where(.theme-scope)
64135
+ :where([data-block='event-calendar'])
64136
+ .event-week-board-card {
63683
64137
  flex: 1 1 14rem;
63684
64138
  }
63685
64139
  }
@@ -63687,11 +64141,37 @@ const containerResponsiveThemeCss = `/*
63687
64141
 
63688
64142
  @container rb-site (max-width: 639px) {
63689
64143
  @scope ([data-rb-responsive-mode="container"]) to (:scope [data-rb-responsive-mode]) {
63690
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-legend {
64144
+ :where(.theme-scope)
64145
+ :where([data-block='event-calendar'])
64146
+ .event-week-board-navigation {
64147
+ display: grid;
64148
+ grid-template-columns: 2.25rem minmax(0, 1fr) 2.25rem;
64149
+ width: 100%;
64150
+ }
64151
+
64152
+ :where(.theme-scope)
64153
+ :where([data-block='event-calendar'])
64154
+ .event-week-board-navigation
64155
+ > :last-child {
64156
+ grid-column: 1 / -1;
64157
+ justify-self: center;
64158
+ }
64159
+
64160
+ :where(.theme-scope)
64161
+ :where([data-block='event-calendar'])
64162
+ .event-week-board-range {
64163
+ min-width: 0;
64164
+ }
64165
+
64166
+ :where(.theme-scope)
64167
+ :where([data-block='event-calendar'])
64168
+ .event-week-board-legend {
63691
64169
  display: none;
63692
64170
  }
63693
64171
 
63694
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-card {
64172
+ :where(.theme-scope)
64173
+ :where([data-block='event-calendar'])
64174
+ .event-week-board-card {
63695
64175
  flex: 1 1 100%;
63696
64176
  }
63697
64177
  }
@@ -63708,8 +64188,9 @@ const containerResponsiveThemeCss = `/*
63708
64188
  * Opt-in only: the band paints when the board root carries [data-banded];
63709
64189
  * the generic default is bandless.
63710
64190
  * ----------------------------------------------------------------------------- */
63711
- :where(.theme-scope) [data-slot="section"]:has(.event-calendar--week-board[data-banded])::before {
63712
- content: "";
64191
+ :where(.theme-scope)
64192
+ [data-slot='section']:has(.event-calendar--week-board[data-banded])::before {
64193
+ content: '';
63713
64194
  position: absolute;
63714
64195
  inset: 0;
63715
64196
  z-index: -9;
@@ -63763,7 +64244,7 @@ const containerResponsiveThemeCss = `/*
63763
64244
  * ----------------------------------------------------------------------------- */
63764
64245
 
63765
64246
  /* Modal overlay */
63766
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal-overlay {
64247
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal-overlay {
63767
64248
  position: fixed;
63768
64249
  inset: 0;
63769
64250
  background: var(--ec-modal-overlay-bg);
@@ -63777,12 +64258,16 @@ const containerResponsiveThemeCss = `/*
63777
64258
  }
63778
64259
 
63779
64260
  @keyframes ec-modal-fade-in {
63780
- from { opacity: 0; }
63781
- to { opacity: 1; }
64261
+ from {
64262
+ opacity: 0;
64263
+ }
64264
+ to {
64265
+ opacity: 1;
64266
+ }
63782
64267
  }
63783
64268
 
63784
64269
  /* Modal dialog */
63785
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal {
64270
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal {
63786
64271
  position: relative;
63787
64272
  background: var(--ec-modal-bg);
63788
64273
  border-radius: var(--rb-block-radius);
@@ -63806,17 +64291,17 @@ const containerResponsiveThemeCss = `/*
63806
64291
  }
63807
64292
 
63808
64293
  /* Event modal - constrained width for card */
63809
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal--event {
64294
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal--event {
63810
64295
  max-width: 26rem;
63811
64296
  }
63812
64297
 
63813
64298
  /* Day modal */
63814
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal--day {
64299
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal--day {
63815
64300
  max-width: 28rem;
63816
64301
  }
63817
64302
 
63818
64303
  /* Close button */
63819
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal-close {
64304
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal-close {
63820
64305
  position: absolute;
63821
64306
  top: 0.75rem;
63822
64307
  right: 0.75rem;
@@ -63837,31 +64322,35 @@ const containerResponsiveThemeCss = `/*
63837
64322
  z-index: 10;
63838
64323
  }
63839
64324
 
63840
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal-close:hover {
64325
+ :where(.theme-scope)
64326
+ :where([data-block='event-calendar'])
64327
+ .ec-modal-close:hover {
63841
64328
  opacity: 1;
63842
64329
  background-color: rgba(var(--tb-text), 0.1);
63843
64330
  }
63844
64331
 
63845
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal-close:focus-visible {
64332
+ :where(.theme-scope)
64333
+ :where([data-block='event-calendar'])
64334
+ .ec-modal-close:focus-visible {
63846
64335
  outline: 2px solid rgb(var(--tb-primary));
63847
64336
  outline-offset: 2px;
63848
64337
  }
63849
64338
 
63850
64339
  /* Modal header (for day modal) */
63851
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal-header {
64340
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal-header {
63852
64341
  padding: 1.5rem 1.5rem 1rem;
63853
64342
  padding-right: 3rem; /* Space for close button */
63854
64343
  border-bottom: 1px solid var(--ec-border);
63855
64344
  }
63856
64345
 
63857
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal-title {
64346
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal-title {
63858
64347
  font-size: 1.125rem;
63859
64348
  font-weight: 600;
63860
64349
  color: var(--ec-text);
63861
64350
  margin: 0;
63862
64351
  }
63863
64352
 
63864
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal-subtitle {
64353
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal-subtitle {
63865
64354
  font-size: 0.875rem;
63866
64355
  color: var(--ec-text);
63867
64356
  opacity: 0.7;
@@ -63869,17 +64358,20 @@ const containerResponsiveThemeCss = `/*
63869
64358
  }
63870
64359
 
63871
64360
  /* Modal content */
63872
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal-content {
64361
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal-content {
63873
64362
  padding: 1rem;
63874
64363
  }
63875
64364
 
63876
64365
  /* Event modal: tighter padding for card */
63877
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal--event .ec-modal-content {
64366
+ :where(.theme-scope)
64367
+ :where([data-block='event-calendar'])
64368
+ .ec-modal--event
64369
+ .ec-modal-content {
63878
64370
  padding: 0.5rem;
63879
64371
  }
63880
64372
 
63881
64373
  /* Day events list */
63882
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-day-events-list {
64374
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-day-events-list {
63883
64375
  display: flex;
63884
64376
  flex-direction: column;
63885
64377
  gap: 0.5rem;
@@ -63887,7 +64379,9 @@ const containerResponsiveThemeCss = `/*
63887
64379
  }
63888
64380
 
63889
64381
  /* AgendaEventCard in button mode inherits most styles, just needs cursor */
63890
- :where(.theme-scope) :where([data-block="event-calendar"]) button.event-agenda-card {
64382
+ :where(.theme-scope)
64383
+ :where([data-block='event-calendar'])
64384
+ button.event-agenda-card {
63891
64385
  cursor: pointer;
63892
64386
  text-align: left;
63893
64387
  font-family: inherit;
@@ -63896,7 +64390,9 @@ const containerResponsiveThemeCss = `/*
63896
64390
  /* Responsive adjustments */
63897
64391
  @container rb-site (max-width: 640px) {
63898
64392
  @scope ([data-rb-responsive-mode="container"]) to (:scope [data-rb-responsive-mode]) {
63899
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-container {
64393
+ :where(.theme-scope)
64394
+ :where([data-block='event-calendar'])
64395
+ .event-calendar-container {
63900
64396
  margin-left: -1.5rem;
63901
64397
  margin-right: -1.5rem;
63902
64398
  border-left: none;
@@ -63904,28 +64400,38 @@ const containerResponsiveThemeCss = `/*
63904
64400
  border-radius: 0;
63905
64401
  }
63906
64402
 
63907
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-day-header {
64403
+ :where(.theme-scope)
64404
+ :where([data-block='event-calendar'])
64405
+ .event-calendar-day-header {
63908
64406
  font-size: 0.75rem;
63909
64407
  padding: 0.375rem 0.125rem;
63910
64408
  }
63911
64409
 
63912
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-day {
64410
+ :where(.theme-scope)
64411
+ :where([data-block='event-calendar'])
64412
+ .event-calendar-day {
63913
64413
  min-height: 88px;
63914
64414
  padding: 0.125rem;
63915
64415
  }
63916
64416
 
63917
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-title {
64417
+ :where(.theme-scope)
64418
+ :where([data-block='event-calendar'])
64419
+ .event-calendar-title {
63918
64420
  font-size: 0.9375rem;
63919
64421
  min-width: 0;
63920
64422
  }
63921
64423
 
63922
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-day-number {
64424
+ :where(.theme-scope)
64425
+ :where([data-block='event-calendar'])
64426
+ .event-calendar-day-number {
63923
64427
  font-size: 0.75rem;
63924
64428
  margin-bottom: 0.125rem;
63925
64429
  padding: 0 0.125rem;
63926
64430
  }
63927
64431
 
63928
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-event {
64432
+ :where(.theme-scope)
64433
+ :where([data-block='event-calendar'])
64434
+ .event-calendar-event {
63929
64435
  justify-content: center;
63930
64436
  gap: 0.25rem;
63931
64437
  padding: 0.1875rem 0.25rem;
@@ -63933,25 +64439,34 @@ const containerResponsiveThemeCss = `/*
63933
64439
  border-radius: calc(var(--rb-block-radius) / 3);
63934
64440
  }
63935
64441
 
63936
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-event-time {
64442
+ :where(.theme-scope)
64443
+ :where([data-block='event-calendar'])
64444
+ .event-calendar-event-time {
63937
64445
  text-align: center;
63938
64446
  font-size: 0.625rem;
63939
64447
  }
63940
64448
 
63941
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-event-title {
64449
+ :where(.theme-scope)
64450
+ :where([data-block='event-calendar'])
64451
+ .event-calendar-event-title {
63942
64452
  display: none;
63943
64453
  }
63944
64454
 
63945
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-more {
64455
+ :where(.theme-scope)
64456
+ :where([data-block='event-calendar'])
64457
+ .event-calendar-more {
63946
64458
  padding: 0.125rem 0.25rem;
63947
64459
  font-size: 0.6875rem;
63948
64460
  }
63949
64461
 
63950
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-header > button {
64462
+ :where(.theme-scope)
64463
+ :where([data-block='event-calendar'])
64464
+ .event-calendar-header
64465
+ > button {
63951
64466
  margin-right: 0.25rem;
63952
64467
  }
63953
64468
 
63954
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal {
64469
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal {
63955
64470
  max-width: 100%;
63956
64471
  max-height: 85vh;
63957
64472
  margin: 0 0.5rem;
@@ -68753,16 +69268,21 @@ function toBlocksPageRendererDataContext(dataContext) {
68753
69268
  imageResolveContext: toBlocksImageResolveContextInput(dataContext.imageResolveContext)
68754
69269
  };
68755
69270
  }
68756
- function PageRenderer(props) {
68757
- const blocksSdkConfig = props.sdkConfig ? { customBlocks: normalizeSdkCustomBlocks(props.sdkConfig.customBlocks) } : props.sdkConfig;
68758
- const { rendering: _rendering, theme: _theme, themeTokens: _themeTokens, ...commonProps } = props;
68759
- const commonBlocksProps = {
68760
- ...commonProps,
69271
+ function toBlocksCommonProps(props) {
69272
+ return {
69273
+ page: props.page,
69274
+ runtimeBoundaries: props.runtimeBoundaries,
68761
69275
  dataContext: props.dataContext ? toBlocksPageRendererDataContext(props.dataContext) : void 0,
69276
+ routeMap: props.routeMap,
69277
+ wrapBlock: props.wrapBlock,
69278
+ registry: props.registry,
68762
69279
  blockOverrides: toBlocksBlockOverrides(props.blockOverrides),
68763
- sdkConfig: blocksSdkConfig,
69280
+ sdkConfig: props.sdkConfig ? { customBlocks: normalizeSdkCustomBlocks(props.sdkConfig.customBlocks) } : props.sdkConfig,
68764
69281
  customBlocks: normalizeSdkCustomBlocks(props.customBlocks)
68765
69282
  };
69283
+ }
69284
+ function PageRenderer(props) {
69285
+ const commonBlocksProps = toBlocksCommonProps(props);
68766
69286
  const blocksProps = isOverrideOnlyPageRenderer(props) ? {
68767
69287
  ...commonBlocksProps,
68768
69288
  rendering: { kind: "overrides-only" },
@@ -68845,12 +69365,14 @@ function toPageHydrationBootstrapConfig(props) {
68845
69365
  mediaAssets: props.mediaAssets
68846
69366
  };
68847
69367
  }
69368
+ function resolveSdkBookingTimeZone(timeZone) {
69369
+ return timeZone ?? "UTC";
69370
+ }
68848
69371
  function PageContent(props) {
68849
- const { page, runtimeBoundaries, siteId, resolvedData, bookingOfferingPresets, routeMap, pagesByIdentifier, entriesByIdentifier, wrapBlock, registry, usePlaceholders = false, blockOverrides, sdkConfig, customBlocks, supabaseUrl, mediaAssets, apiBaseUrl, portalToken, previewToken, dataContext } = props;
69372
+ const { page, runtimeBoundaries, siteId, resolvedData, bookingOfferingPresets, bookingTimeZone, routeMap, pagesByIdentifier, entriesByIdentifier, wrapBlock, registry, blockOverrides, sdkConfig, customBlocks, supabaseUrl, mediaAssets, apiBaseUrl, portalToken, previewToken, dataContext } = props;
68850
69373
  const rendererCommonProps = {
68851
69374
  page,
68852
69375
  runtimeBoundaries,
68853
- usePlaceholders,
68854
69376
  dataContext: {
68855
69377
  siteId,
68856
69378
  apiBaseUrl,
@@ -68858,6 +69380,7 @@ function PageContent(props) {
68858
69380
  previewToken,
68859
69381
  resolvedData,
68860
69382
  bookingOfferingPresets: bookingOfferingPresets ?? [],
69383
+ bookingTimeZone: resolveSdkBookingTimeZone(bookingTimeZone),
68861
69384
  routes: routeMap,
68862
69385
  pagesByIdentifier,
68863
69386
  entriesByIdentifier,
@@ -69441,233 +69964,6 @@ function requireSdkTheme(theme, siteId, reason = "cms_theme_absent") {
69441
69964
  //#region src/rendering/renderingMode.ts
69442
69965
  const defaultOverrideOnlyRuntime = { kind: "responsive-only" };
69443
69966
  //#endregion
69444
- //#region src/rendering/components/Layout.tsx
69445
- /**
69446
- * Layout component with header and footer
69447
- *
69448
- * Renders site header and footer around content. Fetches site data if not provided.
69449
- */
69450
- function isOverrideOnlyLayout(props) {
69451
- return props.rendering?.kind === "overrides-only";
69452
- }
69453
- var UnsupportedOverrideOnlyLayoutChromeError = class extends Error {
69454
- constructor(surface) {
69455
- super(`Override-only Layout requires a custom or disabled ${surface}; SDK default chrome is unavailable.`);
69456
- this.surface = surface;
69457
- this.code = "unsupported_override_only_layout_chrome";
69458
- this.name = "UnsupportedOverrideOnlyLayoutChromeError";
69459
- }
69460
- };
69461
- async function resolveLayoutSiteData(props) {
69462
- if (props.siteData) return props.siteData;
69463
- if (!props.client) throw new Error("Layout: must provide either siteData or client");
69464
- if (!props.siteId && !props.slug && !props.domain) throw new Error("Layout: must provide siteId, slug, or domain when using client");
69465
- return props.client.getSite({
69466
- id: props.siteId,
69467
- slug: props.slug,
69468
- domain: props.domain
69469
- });
69470
- }
69471
- function renderOverrideOnlyLayout(props, data) {
69472
- if (data.header === true) throw new UnsupportedOverrideOnlyLayoutChromeError("header");
69473
- if (data.footer === true) throw new UnsupportedOverrideOnlyLayoutChromeError("footer");
69474
- return renderWithOverrideOnlyRuntime({
69475
- runtime: props.rendering.runtime ?? defaultOverrideOnlyRuntime,
69476
- children: /* @__PURE__ */ jsxs(Fragment, { children: [
69477
- typeof props.header === "function" ? props.header(data.headerData) : null,
69478
- props.children,
69479
- typeof props.footer === "function" ? props.footer(data.footerData) : null
69480
- ] })
69481
- });
69482
- }
69483
- /**
69484
- * Layout component that wraps content with site header and footer.
69485
- *
69486
- * This is a server/RSC-safe component. The default `@riverbankcms/sdk/rendering`
69487
- * `Page` and `Block` surfaces mount CMS island hydration automatically, while
69488
- * the strict `@riverbankcms/sdk/rendering/server` surface stays bootstrap-free.
69489
- * If a custom host renders hydratable CMS islands through the strict server
69490
- * surface, mount `BlocksIslandsHydrator` from
69491
- * `@riverbankcms/sdk/rendering/islands` explicitly.
69492
- *
69493
- * @example With pre-fetched site data (recommended)
69494
- * ```tsx
69495
- * import { Layout } from '@riverbankcms/sdk/rendering/server';
69496
- * import { Page } from '@riverbankcms/sdk/rendering';
69497
- *
69498
- * const site = await client.getSite({ slug: 'my-site' });
69499
- *
69500
- * <Layout siteData={site}>
69501
- * <Page {...pageData} />
69502
- * </Layout>
69503
- * ```
69504
- *
69505
- * @example With strict server rendering
69506
- * ```tsx
69507
- * import { Layout, Page } from '@riverbankcms/sdk/rendering/server';
69508
- * import { BlocksIslandsHydrator } from '@riverbankcms/sdk/rendering/islands';
69509
- *
69510
- * const site = await client.getSite({ slug: 'my-site' });
69511
- *
69512
- * <Layout siteData={site}>
69513
- * <BlocksIslandsHydrator siteId={site.site.id} supabaseUrl={site.supabaseUrl} />
69514
- * <Page {...pageData} />
69515
- * </Layout>
69516
- * ```
69517
- */
69518
- async function Layout(props) {
69519
- const { children, hasPortalSession = false, previewStage = "published" } = props;
69520
- const header = props.header ?? true;
69521
- const footer = props.footer ?? true;
69522
- const siteData = await resolveLayoutSiteData(props);
69523
- const { site, navigation, layout, routes } = siteData;
69524
- const footerBlocks = siteData.footerBlocks ?? [];
69525
- const navigationOptions = {
69526
- hasPortalSession,
69527
- previewStage,
69528
- pagesByIdentifier: siteData.pagesByIdentifier,
69529
- entriesByIdentifier: siteData.entriesByIdentifier,
69530
- portalEnabled: siteData.portalEnabled ?? false,
69531
- commerceEnabled: siteData.commerceEnabled ?? false,
69532
- checkoutHref: "/checkout"
69533
- };
69534
- const menuViewModel = buildMenu(navigation, routes, navigationOptions);
69535
- const footerMenuViewModel = buildFooterMenu(navigation, routes, navigationOptions);
69536
- const legalFooterMenuViewModel = buildFooterMenuForRole(navigation, routes, "legal-policy", navigationOptions);
69537
- const logoViewModel = buildLogo(layout.logo ?? null, site.title);
69538
- const customHeaderData = {
69539
- menu: menuViewModel,
69540
- logo: logoViewModel,
69541
- site,
69542
- routes
69543
- };
69544
- const customFooterData = {
69545
- menu: menuViewModel,
69546
- footerMenu: footerMenuViewModel,
69547
- legalFooterMenu: legalFooterMenuViewModel,
69548
- logo: logoViewModel,
69549
- site,
69550
- routes
69551
- };
69552
- if (isOverrideOnlyLayout(props)) return renderOverrideOnlyLayout(props, {
69553
- header: props.header ?? true,
69554
- footer: props.footer ?? true,
69555
- headerData: customHeaderData,
69556
- footerData: customFooterData
69557
- });
69558
- const theme = requireSdkTheme(siteData.theme, site.id);
69559
- const builtThemeRuntime = buildThemeRuntime(theme);
69560
- const headerVariant = props.headerVariant;
69561
- const themeRuntime = props.themeRuntime;
69562
- const headerData = {
69563
- ...customHeaderData,
69564
- theme
69565
- };
69566
- const footerData = {
69567
- ...customFooterData,
69568
- theme
69569
- };
69570
- const headerContent = headerVariant ? {
69571
- ...layout.header,
69572
- variant: headerVariant
69573
- } : layout.header;
69574
- const themeWithVariant = headerVariant ? {
69575
- ...theme,
69576
- header: {
69577
- ...theme.header,
69578
- variant: headerVariant
69579
- }
69580
- } : theme;
69581
- const blocksThemeWithVariant = themeWithVariant;
69582
- const blocksTheme = theme;
69583
- let apiBaseUrl;
69584
- try {
69585
- apiBaseUrl = getRiverbankEnv().baseUrl;
69586
- } catch {}
69587
- const sharedViewModelOverrides = {
69588
- $root: {
69589
- siteId: site.id,
69590
- apiBaseUrl,
69591
- previewStage,
69592
- routes,
69593
- pagesByIdentifier: siteData.pagesByIdentifier,
69594
- entriesByIdentifier: siteData.entriesByIdentifier,
69595
- theme: themeWithVariant
69596
- },
69597
- site,
69598
- menu: menuViewModel,
69599
- footerMenu: footerMenuViewModel,
69600
- legalFooterMenu: legalFooterMenuViewModel
69601
- };
69602
- const headerViewModelOverrides = {
69603
- ...sharedViewModelOverrides,
69604
- content: { logo: logoViewModel }
69605
- };
69606
- const footerViewModelOverrides = {
69607
- ...sharedViewModelOverrides,
69608
- content: {
69609
- ...layout.footer,
69610
- logo: logoViewModel
69611
- }
69612
- };
69613
- let headerElement = null;
69614
- if (header === true) headerElement = renderBlock(siteHeaderManifest, headerContent, {
69615
- theme: builtThemeRuntime.tokens,
69616
- themeConfig: blocksThemeWithVariant,
69617
- viewModelOverrides: headerViewModelOverrides
69618
- });
69619
- else if (typeof header === "function") headerElement = header(headerData);
69620
- let footerElement = null;
69621
- if (footer === true) {
69622
- const footerPlan = resolveFooterRenderPlan({
69623
- isSdkSite: Boolean(site.is_sdk_site),
69624
- mode: theme.footer?.mode
69625
- });
69626
- const footerBlocksElement = footerPlan.renderFooterBlocks && footerBlocks.length > 0 ? /* @__PURE__ */ jsx(PageRenderer, {
69627
- theme,
69628
- page: {
69629
- name: "Footer",
69630
- path: "/__footer",
69631
- purpose: "footer",
69632
- blocks: footerBlocks
69633
- },
69634
- routeMap: routes,
69635
- dataContext: {
69636
- previewStage,
69637
- siteId: site.id,
69638
- apiBaseUrl,
69639
- routes,
69640
- pagesByIdentifier: siteData.pagesByIdentifier,
69641
- entriesByIdentifier: siteData.entriesByIdentifier
69642
- },
69643
- sdkConfig: siteData.sdkConfig ?? null
69644
- }) : null;
69645
- if (footerPlan.renderFooterBlocks && !footerBlocksElement && process.env.NODE_ENV !== "production") console.debug("[sdk] Footer mode renders blocks, but footerBlocks is empty/missing", {
69646
- siteId: site.id,
69647
- mode: footerPlan.mode
69648
- });
69649
- const defaultFooterElement = footerPlan.renderDefaultFooter ? renderBlock(siteFooterManifest, layout.footer, {
69650
- theme: builtThemeRuntime.tokens,
69651
- themeConfig: blocksTheme,
69652
- viewModelOverrides: footerViewModelOverrides
69653
- }) : null;
69654
- footerElement = footerPlan.mode === "default+blocks" ? /* @__PURE__ */ jsxs(Fragment, { children: [footerBlocksElement, defaultFooterElement] }) : footerPlan.mode === "blocks" ? footerBlocksElement : footerPlan.mode === "none" ? null : defaultFooterElement;
69655
- } else if (typeof footer === "function") footerElement = footer(footerData);
69656
- const content = /* @__PURE__ */ jsxs(Fragment, { children: [
69657
- headerElement,
69658
- children,
69659
- footerElement
69660
- ] });
69661
- return renderWithSdkThemeRuntime({
69662
- theme,
69663
- themeRuntime: planLayoutThemeRuntime({
69664
- themeRuntime,
69665
- usesSdkChrome: header === true || footer === true
69666
- }),
69667
- children: content
69668
- });
69669
- }
69670
- //#endregion
69671
69967
  //#region ../blocks/src/structure/schema.ts
69672
69968
  const BlockKind = z.string();
69673
69969
  const blockSchema = z.object({
@@ -70932,6 +71228,346 @@ function parseBackgroundColorToken(value) {
70932
71228
  if (!token) return null;
70933
71229
  return token ? token : null;
70934
71230
  }
71231
+ //#endregion
71232
+ //#region src/rendering/helpers/siteCustomBlocks.ts
71233
+ /**
71234
+ * Prefer the DB-backed custom block manifest list (`site.customBlocks`) when available,
71235
+ * but fall back to SDK config custom blocks (`site.sdkConfig.customBlocks`) for SDK-mode sites.
71236
+ *
71237
+ * This avoids subtle DX bugs where one source is populated but the renderer/prefetch layer
71238
+ * is looking at the other.
71239
+ */
71240
+ function resolveSiteCustomBlocks(site) {
71241
+ const dbBlocks = site.customBlocks;
71242
+ if (Array.isArray(dbBlocks) && dbBlocks.length > 0) return dbBlocks;
71243
+ const sdkBlocks = site.sdkConfig?.customBlocks;
71244
+ if (Array.isArray(sdkBlocks) && sdkBlocks.length > 0) return sdkBlocks;
71245
+ }
71246
+ function convertPageResponseBlock(block) {
71247
+ if (!isRecord$8(block)) throw new Error("Invalid block format in page API response");
71248
+ if (typeof block.id !== "string" && block.id !== null) throw new Error(`Invalid block id in page: expected string or null, got ${typeof block.id}`);
71249
+ if (typeof block.kind !== "string") throw new Error(`Invalid block kind in page: expected string, got ${typeof block.kind}`);
71250
+ if (typeof block.purpose !== "string") throw new Error(`Invalid block purpose in page: expected string, got ${typeof block.purpose}`);
71251
+ const admission = readInvalidBlockAdmission(block.admission);
71252
+ return {
71253
+ id: block.id,
71254
+ kind: block.kind,
71255
+ purpose: block.purpose,
71256
+ content: sanitizeSdkRuntimeBlockContent(block.kind, readContentRecord(block.content) ?? {}),
71257
+ draftContent: sanitizeNullableSdkRuntimeBlockContent(block.kind, readNestedContentRecord(block.draftContent)),
71258
+ ...admission ? { admission } : {}
71259
+ };
71260
+ }
71261
+ function readInvalidBlockAdmission(value) {
71262
+ if (!isRecord$8(value) || value.kind !== "invalid" || !isRecord$8(value.error)) return null;
71263
+ if (value.error.kind !== "invalid_manifest_content" && value.error.kind !== "manifest_unavailable") return null;
71264
+ return value;
71265
+ }
71266
+ function buildPageOutline(input) {
71267
+ return {
71268
+ name: input.name,
71269
+ path: input.path ?? input.fallbackPath,
71270
+ purpose: input.purpose,
71271
+ blocks: input.blocks.map(convertPageResponseBlock)
71272
+ };
71273
+ }
71274
+ function buildRenderablePageOutline(input) {
71275
+ const page = buildPageOutline(input);
71276
+ return {
71277
+ ...page,
71278
+ blocks: page.blocks.map((block) => admitSdkRuntimePageBlock(block, input.customBlocks))
71279
+ };
71280
+ }
71281
+ function admitSdkRuntimePageBlock(block, customBlocks) {
71282
+ const base = {
71283
+ id: block.id,
71284
+ kind: block.kind,
71285
+ purpose: block.purpose,
71286
+ ...block.bindings ? { bindings: block.bindings } : {}
71287
+ };
71288
+ const transportedAdmission = readInvalidBlockAdmission(block.admission);
71289
+ if (transportedAdmission) return invalidRenderableBlock(base, transportedAdmission.error);
71290
+ const manifest = resolveSdkBlockManifest(block.kind, customBlocks);
71291
+ if (!manifest) return invalidRenderableBlock(base, { kind: "manifest_unavailable" });
71292
+ const content = block.content ?? {};
71293
+ const renderable = admitTransportedRenderableManifestContent(compileManifestContentContract(manifest), content);
71294
+ if (!renderable.ok) return invalidRenderableBlock(base, {
71295
+ kind: "invalid_manifest_content",
71296
+ error: renderable.error
71297
+ });
71298
+ return {
71299
+ ...base,
71300
+ admission: {
71301
+ kind: "renderable",
71302
+ content: renderable.value
71303
+ }
71304
+ };
71305
+ }
71306
+ function resolveSdkBlockManifest(blockKind, customBlocks) {
71307
+ const customBlock = customBlocks?.find((candidate) => candidate.id === blockKind);
71308
+ return customBlock ? parseFieldDefinitions(customBlock.fields) : getBlockDefinition(blockKind)?.manifest ?? null;
71309
+ }
71310
+ function invalidRenderableBlock(block, error) {
71311
+ return {
71312
+ ...block,
71313
+ admission: {
71314
+ kind: "invalid",
71315
+ error
71316
+ }
71317
+ };
71318
+ }
71319
+ function isRecord$8(value) {
71320
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
71321
+ }
71322
+ function readContentRecord(value) {
71323
+ return isRecord$8(value) ? value : void 0;
71324
+ }
71325
+ function readNestedContentRecord(value) {
71326
+ if (!isRecord$8(value)) return null;
71327
+ return readContentRecord(value.data) ?? null;
71328
+ }
71329
+ function sanitizeSdkRuntimeBlockContent(blockKind, content) {
71330
+ if (blockKind !== "block.newsletter-signup") return content;
71331
+ const sanitized = sanitizeNewsletterSignupPublicContent(content);
71332
+ return isRecord$8(sanitized) ? sanitized : {};
71333
+ }
71334
+ function sanitizeNullableSdkRuntimeBlockContent(blockKind, content) {
71335
+ return content ? sanitizeSdkRuntimeBlockContent(blockKind, content) : null;
71336
+ }
71337
+ //#endregion
71338
+ //#region src/rendering/helpers/footerPageOutline.ts
71339
+ function buildFooterRenderablePageOutline(siteData, blocks) {
71340
+ return buildRenderablePageOutline({
71341
+ name: "Footer",
71342
+ path: "/__footer",
71343
+ fallbackPath: "/__footer",
71344
+ purpose: "footer",
71345
+ blocks,
71346
+ customBlocks: resolveSiteCustomBlocks(siteData)
71347
+ });
71348
+ }
71349
+ //#endregion
71350
+ //#region src/rendering/components/Layout.tsx
71351
+ /**
71352
+ * Layout component with header and footer
71353
+ *
71354
+ * Renders site header and footer around content. Fetches site data if not provided.
71355
+ */
71356
+ function isOverrideOnlyLayout(props) {
71357
+ return props.rendering?.kind === "overrides-only";
71358
+ }
71359
+ var UnsupportedOverrideOnlyLayoutChromeError = class extends Error {
71360
+ constructor(surface) {
71361
+ super(`Override-only Layout requires a custom or disabled ${surface}; SDK default chrome is unavailable.`);
71362
+ this.surface = surface;
71363
+ this.code = "unsupported_override_only_layout_chrome";
71364
+ this.name = "UnsupportedOverrideOnlyLayoutChromeError";
71365
+ }
71366
+ };
71367
+ async function resolveLayoutSiteData(props) {
71368
+ if (props.siteData) return props.siteData;
71369
+ if (!props.client) throw new Error("Layout: must provide either siteData or client");
71370
+ if (!props.siteId && !props.slug && !props.domain) throw new Error("Layout: must provide siteId, slug, or domain when using client");
71371
+ return props.client.getSite({
71372
+ id: props.siteId,
71373
+ slug: props.slug,
71374
+ domain: props.domain
71375
+ });
71376
+ }
71377
+ function renderOverrideOnlyLayout(props, data) {
71378
+ if (data.header === true) throw new UnsupportedOverrideOnlyLayoutChromeError("header");
71379
+ if (data.footer === true) throw new UnsupportedOverrideOnlyLayoutChromeError("footer");
71380
+ return renderWithOverrideOnlyRuntime({
71381
+ runtime: props.rendering.runtime ?? defaultOverrideOnlyRuntime,
71382
+ children: /* @__PURE__ */ jsxs(Fragment, { children: [
71383
+ typeof props.header === "function" ? props.header(data.headerData) : null,
71384
+ props.children,
71385
+ typeof props.footer === "function" ? props.footer(data.footerData) : null
71386
+ ] })
71387
+ });
71388
+ }
71389
+ /**
71390
+ * Layout component that wraps content with site header and footer.
71391
+ *
71392
+ * This is a server/RSC-safe component. The default `@riverbankcms/sdk/rendering`
71393
+ * `Page` and `Block` surfaces mount CMS island hydration automatically, while
71394
+ * the strict `@riverbankcms/sdk/rendering/server` surface stays bootstrap-free.
71395
+ * If a custom host renders hydratable CMS islands through the strict server
71396
+ * surface, mount `BlocksIslandsHydrator` from
71397
+ * `@riverbankcms/sdk/rendering/islands` explicitly.
71398
+ *
71399
+ * @example With pre-fetched site data (recommended)
71400
+ * ```tsx
71401
+ * import { Layout } from '@riverbankcms/sdk/rendering/server';
71402
+ * import { Page } from '@riverbankcms/sdk/rendering';
71403
+ *
71404
+ * const site = await client.getSite({ slug: 'my-site' });
71405
+ *
71406
+ * <Layout siteData={site}>
71407
+ * <Page {...pageData} />
71408
+ * </Layout>
71409
+ * ```
71410
+ *
71411
+ * @example With strict server rendering
71412
+ * ```tsx
71413
+ * import { Layout, Page } from '@riverbankcms/sdk/rendering/server';
71414
+ * import { BlocksIslandsHydrator } from '@riverbankcms/sdk/rendering/islands';
71415
+ *
71416
+ * const site = await client.getSite({ slug: 'my-site' });
71417
+ *
71418
+ * <Layout siteData={site}>
71419
+ * <BlocksIslandsHydrator siteId={site.site.id} supabaseUrl={site.supabaseUrl} />
71420
+ * <Page {...pageData} />
71421
+ * </Layout>
71422
+ * ```
71423
+ */
71424
+ async function Layout(props) {
71425
+ const { children, hasPortalSession = false, previewStage = "published" } = props;
71426
+ const header = props.header ?? true;
71427
+ const footer = props.footer ?? true;
71428
+ const siteData = await resolveLayoutSiteData(props);
71429
+ const { site, navigation, layout, routes } = siteData;
71430
+ const footerBlocks = siteData.footerBlocks ?? [];
71431
+ const navigationOptions = {
71432
+ hasPortalSession,
71433
+ previewStage,
71434
+ pagesByIdentifier: siteData.pagesByIdentifier,
71435
+ entriesByIdentifier: siteData.entriesByIdentifier,
71436
+ portalEnabled: siteData.portalEnabled ?? false,
71437
+ commerceEnabled: siteData.commerceEnabled ?? false,
71438
+ checkoutHref: "/checkout"
71439
+ };
71440
+ const menuViewModel = buildMenu(navigation, routes, navigationOptions);
71441
+ const footerMenuViewModel = buildFooterMenu(navigation, routes, navigationOptions);
71442
+ const legalFooterMenuViewModel = buildFooterMenuForRole(navigation, routes, "legal-policy", navigationOptions);
71443
+ const logoViewModel = buildLogo(layout.logo ?? null, site.title);
71444
+ const customHeaderData = {
71445
+ menu: menuViewModel,
71446
+ logo: logoViewModel,
71447
+ site,
71448
+ routes
71449
+ };
71450
+ const customFooterData = {
71451
+ menu: menuViewModel,
71452
+ footerMenu: footerMenuViewModel,
71453
+ legalFooterMenu: legalFooterMenuViewModel,
71454
+ logo: logoViewModel,
71455
+ site,
71456
+ routes
71457
+ };
71458
+ if (isOverrideOnlyLayout(props)) return renderOverrideOnlyLayout(props, {
71459
+ header: props.header ?? true,
71460
+ footer: props.footer ?? true,
71461
+ headerData: customHeaderData,
71462
+ footerData: customFooterData
71463
+ });
71464
+ const theme = requireSdkTheme(siteData.theme, site.id);
71465
+ const builtThemeRuntime = buildThemeRuntime(theme);
71466
+ const headerVariant = props.headerVariant;
71467
+ const themeRuntime = props.themeRuntime;
71468
+ const headerData = {
71469
+ ...customHeaderData,
71470
+ theme
71471
+ };
71472
+ const footerData = {
71473
+ ...customFooterData,
71474
+ theme
71475
+ };
71476
+ const headerContent = headerVariant ? {
71477
+ ...layout.header,
71478
+ variant: headerVariant
71479
+ } : layout.header;
71480
+ const themeWithVariant = headerVariant ? {
71481
+ ...theme,
71482
+ header: {
71483
+ ...theme.header,
71484
+ variant: headerVariant
71485
+ }
71486
+ } : theme;
71487
+ const blocksThemeWithVariant = themeWithVariant;
71488
+ const blocksTheme = theme;
71489
+ let apiBaseUrl;
71490
+ try {
71491
+ apiBaseUrl = getRiverbankEnv().baseUrl;
71492
+ } catch {}
71493
+ const sharedViewModelOverrides = {
71494
+ $root: {
71495
+ siteId: site.id,
71496
+ apiBaseUrl,
71497
+ previewStage,
71498
+ routes,
71499
+ pagesByIdentifier: siteData.pagesByIdentifier,
71500
+ entriesByIdentifier: siteData.entriesByIdentifier,
71501
+ theme: themeWithVariant
71502
+ },
71503
+ site,
71504
+ menu: menuViewModel,
71505
+ footerMenu: footerMenuViewModel,
71506
+ legalFooterMenu: legalFooterMenuViewModel
71507
+ };
71508
+ const headerViewModelOverrides = {
71509
+ ...sharedViewModelOverrides,
71510
+ content: { logo: logoViewModel }
71511
+ };
71512
+ const footerViewModelOverrides = {
71513
+ ...sharedViewModelOverrides,
71514
+ content: {
71515
+ ...layout.footer,
71516
+ logo: logoViewModel
71517
+ }
71518
+ };
71519
+ let headerElement = null;
71520
+ if (header === true) headerElement = renderBlock(siteHeaderManifest, headerContent, {
71521
+ theme: builtThemeRuntime.tokens,
71522
+ themeConfig: blocksThemeWithVariant,
71523
+ viewModelOverrides: headerViewModelOverrides
71524
+ });
71525
+ else if (typeof header === "function") headerElement = header(headerData);
71526
+ let footerElement = null;
71527
+ if (footer === true) {
71528
+ const footerPlan = resolveFooterRenderPlan({
71529
+ isSdkSite: Boolean(site.is_sdk_site),
71530
+ mode: theme.footer?.mode
71531
+ });
71532
+ const footerBlocksElement = footerPlan.renderFooterBlocks && footerBlocks.length > 0 ? /* @__PURE__ */ jsx(PageRenderer, {
71533
+ theme,
71534
+ page: buildFooterRenderablePageOutline(siteData, footerBlocks),
71535
+ routeMap: routes,
71536
+ dataContext: {
71537
+ previewStage,
71538
+ siteId: site.id,
71539
+ apiBaseUrl,
71540
+ routes,
71541
+ pagesByIdentifier: siteData.pagesByIdentifier,
71542
+ entriesByIdentifier: siteData.entriesByIdentifier
71543
+ },
71544
+ sdkConfig: siteData.sdkConfig ?? null
71545
+ }) : null;
71546
+ if (footerPlan.renderFooterBlocks && !footerBlocksElement && process.env.NODE_ENV !== "production") console.debug("[sdk] Footer mode renders blocks, but footerBlocks is empty/missing", {
71547
+ siteId: site.id,
71548
+ mode: footerPlan.mode
71549
+ });
71550
+ const defaultFooterElement = footerPlan.renderDefaultFooter ? renderBlock(siteFooterManifest, layout.footer, {
71551
+ theme: builtThemeRuntime.tokens,
71552
+ themeConfig: blocksTheme,
71553
+ viewModelOverrides: footerViewModelOverrides
71554
+ }) : null;
71555
+ footerElement = footerPlan.mode === "default+blocks" ? /* @__PURE__ */ jsxs(Fragment, { children: [footerBlocksElement, defaultFooterElement] }) : footerPlan.mode === "blocks" ? footerBlocksElement : footerPlan.mode === "none" ? null : defaultFooterElement;
71556
+ } else if (typeof footer === "function") footerElement = footer(footerData);
71557
+ const content = /* @__PURE__ */ jsxs(Fragment, { children: [
71558
+ headerElement,
71559
+ children,
71560
+ footerElement
71561
+ ] });
71562
+ return renderWithSdkThemeRuntime({
71563
+ theme,
71564
+ themeRuntime: planLayoutThemeRuntime({
71565
+ themeRuntime,
71566
+ usesSdkChrome: header === true || footer === true
71567
+ }),
71568
+ children: content
71569
+ });
71570
+ }
70935
71571
  function blockedDemoMutationPolicy(classification, publicMessage) {
70936
71572
  if (publicMessage.trim() === "") throw new Error(`Demo mutation policy ${classification} requires publicMessage.`);
70937
71573
  return {
@@ -72128,6 +72764,13 @@ const PUBLIC_WHOLE_SERIES_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
72128
72764
  //#endregion
72129
72765
  //#region ../api/src/publicEventEndpointDefinitions.ts
72130
72766
  const PUBLIC_EVENT_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
72767
+ resolvePublicEventCheckoutReturn: {
72768
+ path: "/public/sites/{siteId}/events/checkout-return",
72769
+ method: "POST",
72770
+ tags: [TAG_TEMPLATES.publicEvents, "event-checkout"],
72771
+ auth: "public",
72772
+ responseKind: "json"
72773
+ },
72131
72774
  getPublicEventRegistrationOptions: {
72132
72775
  path: "/public/sites/{siteId}/events/registration-options",
72133
72776
  method: "POST",
@@ -73389,7 +74032,7 @@ z$1.object({
73389
74032
  });
73390
74033
  //#endregion
73391
74034
  //#region ../api/src/utils/isRecord.ts
73392
- function isRecord$6(value) {
74035
+ function isRecord$5(value) {
73393
74036
  return typeof value === "object" && value !== null && !Array.isArray(value);
73394
74037
  }
73395
74038
  //#endregion
@@ -73636,7 +74279,7 @@ function sanitizeMarks(marks) {
73636
74279
  if (!Array.isArray(marks) || marks.length === 0) return;
73637
74280
  const sanitized = marks.flatMap((mark) => {
73638
74281
  if (mark.type === "bold" || mark.type === "strong" || mark.type === "italic" || mark.type === "em") return [{ type: mark.type }];
73639
- if (mark.type === "link" && isRecord$6(mark.attrs) && typeof mark.attrs.href === "string") {
74282
+ if (mark.type === "link" && isRecord$5(mark.attrs) && typeof mark.attrs.href === "string") {
73640
74283
  const attrs = { href: mark.attrs.href };
73641
74284
  if (typeof mark.attrs.target === "string" && mark.attrs.target.trim().length > 0) attrs.target = mark.attrs.target;
73642
74285
  if (typeof mark.attrs.rel === "string" && mark.attrs.rel.trim().length > 0) attrs.rel = mark.attrs.rel;
@@ -73661,7 +74304,7 @@ function collectText(node) {
73661
74304
  }
73662
74305
  function stableSerialize(value) {
73663
74306
  if (Array.isArray(value)) return `[${value.map(stableSerialize).join(",")}]`;
73664
- 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(",")}}`;
74307
+ 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(",")}}`;
73665
74308
  return JSON.stringify(value);
73666
74309
  }
73667
74310
  //#endregion
@@ -73798,7 +74441,7 @@ function collectCartLinkStats(items, depth = 0) {
73798
74441
  return result;
73799
74442
  }
73800
74443
  function isNavigationMenuValidationItem(value) {
73801
- if (!isRecord$6(value)) return false;
74444
+ if (!isRecord$5(value)) return false;
73802
74445
  return typeof value.label === "string";
73803
74446
  }
73804
74447
  //#endregion
@@ -73816,7 +74459,7 @@ function normalizeIdList(value) {
73816
74459
  return result.length > 0 ? result : null;
73817
74460
  }
73818
74461
  function extractNavVisibilityConfig(raw) {
73819
- if (!isRecord$6(raw)) return null;
74462
+ if (!isRecord$5(raw)) return null;
73820
74463
  const modeRaw = raw.mode;
73821
74464
  const mode = modeRaw === "augment" || modeRaw === "restrict" ? modeRaw : null;
73822
74465
  const allowIds = normalizeIdList(raw.allowIds);
@@ -73829,7 +74472,7 @@ function extractNavVisibilityConfig(raw) {
73829
74472
  };
73830
74473
  }
73831
74474
  function asRecord(value) {
73832
- return isRecord$6(value) ? value : null;
74475
+ return isRecord$5(value) ? value : null;
73833
74476
  }
73834
74477
  /**
73835
74478
  * Check if a raw config object has any nav visibility values defined.
@@ -75169,6 +75812,7 @@ const DEFAULT_TEMPLATE_DEFINITIONS = {
75169
75812
  {
75170
75813
  blockKind: "block.body-text",
75171
75814
  scope: "entry",
75815
+ content: { body: createRichTextDoc([""]) },
75172
75816
  bindings: EVENT_BODY_TEXT_BINDINGS
75173
75817
  },
75174
75818
  {
@@ -75215,6 +75859,7 @@ const DEFAULT_TEMPLATE_DEFINITIONS = {
75215
75859
  }, {
75216
75860
  blockKind: "block.body-text",
75217
75861
  scope: "entry",
75862
+ content: { body: createRichTextDoc([""]) },
75218
75863
  bindings: TEAM_MEMBER_BODY_TEXT_BINDINGS
75219
75864
  }]
75220
75865
  },