@riverbankcms/sdk 0.135.1 → 0.136.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (152) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/README.md +4 -8
  3. package/dist/{PreviewEditorSidebar-D4p_5TdY.mjs → PreviewEditorSidebar-BU5ZlhQR.mjs} +4 -4
  4. package/dist/{PreviewEditorUI-D0cRoTX1.mjs → PreviewEditorUI-9XkHL-bC.mjs} +3 -3
  5. package/dist/{PreviewQueryProvider-DcgaESkm.mjs → PreviewQueryProvider-wbEpXryy.mjs} +1 -1
  6. package/dist/{SdkPreviewModeRuntime-BKLtM3Nz.mjs → SdkPreviewModeRuntime-CnWmj-2B.mjs} +50 -99
  7. package/dist/{SiteChromeCustomizeContext-61X2m7QV.mjs → SiteChromeCustomizeContext-B6d5zkog.mjs} +2299 -1149
  8. package/dist/_dts/ai/src/contracts/proposals.d.ts +8 -554
  9. package/dist/_dts/ai/src/contracts/siteStyleProposalSchemas.d.ts +401 -2312
  10. package/dist/_dts/api/src/contentRuntime.d.ts +6 -0
  11. package/dist/_dts/api/src/endpoints.d.ts +7 -0
  12. package/dist/_dts/api/src/index.d.ts +1 -0
  13. package/dist/_dts/api/src/publicEventEndpointDefinitions.d.ts +7 -0
  14. package/dist/_dts/api/src/publicExperience/eventEndpoints.d.ts +26 -0
  15. package/dist/_dts/api/src/sdkBlockContentAdmission.d.ts +5 -0
  16. package/dist/_dts/api/src/sdkThemeWire.d.ts +6 -432
  17. package/dist/_dts/block-form/src/blockDraftSaveability.d.ts +2 -3
  18. package/dist/_dts/block-form/src/utils/slug.d.ts +6 -0
  19. package/dist/_dts/blocks/src/PageRenderer.d.ts +12 -6
  20. package/dist/_dts/blocks/src/contracts/proof-block-islands.d.ts +48 -0
  21. package/dist/_dts/blocks/src/definitions.d.ts +14 -0
  22. package/dist/_dts/blocks/src/index.d.ts +4 -3
  23. package/dist/_dts/blocks/src/pageRenderAdmission.d.ts +40 -0
  24. package/dist/_dts/blocks/src/server.d.ts +2 -2
  25. package/dist/_dts/blocks/src/system/data/index.d.ts +2 -0
  26. package/dist/_dts/blocks/src/system/data/publicLoaderCachePolicy.d.ts +78 -0
  27. package/dist/_dts/blocks/src/system/manifest/fieldValidation/index.d.ts +2 -18
  28. package/dist/_dts/blocks/src/system/manifest/validation.d.ts +103 -16
  29. package/dist/_dts/blocks/src/system/node/validation-constants.d.ts +1 -1
  30. package/dist/_dts/blocks/src/system/runtime/api/client.d.ts +2 -1
  31. package/dist/_dts/blocks/src/system/runtime/api/endpoints.d.ts +8 -0
  32. package/dist/_dts/blocks/src/system/runtime/api/index.d.ts +1 -1
  33. package/dist/_dts/blocks/src/system/runtime/api/types/events.d.ts +19 -0
  34. package/dist/_dts/blocks/src/system/runtime/components/registry.client.d.ts +52 -0
  35. package/dist/_dts/blocks/src/system/runtime/components/runtime-backed-blocks.d.ts +24 -0
  36. package/dist/_dts/blocks/src/system/runtime/hooks/useCalendarEvents.d.ts +44 -18
  37. package/dist/_dts/blocks/src/system/runtime/hooks/useCalendarEvents.state.d.ts +20 -3
  38. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/VerifyingTimeoutStep.d.ts +3 -1
  39. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationStripeReturn.d.ts +1 -0
  40. package/dist/_dts/blocks/src/system/runtime/nodes/events/EventCalendar.client.d.ts +2 -2
  41. package/dist/_dts/blocks/src/system/runtime/nodes/events/EventCalendar.interactive.d.ts +40 -0
  42. package/dist/_dts/blocks/src/system/runtime/nodes/events/EventCombined.client.d.ts +2 -0
  43. package/dist/_dts/blocks/src/system/runtime/nodes/events/EventCombined.interactive.d.ts +43 -0
  44. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/CalendarDayCell.d.ts +3 -1
  45. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/CalendarNavigationChevron.d.ts +4 -0
  46. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/DayEventsModal.d.ts +2 -1
  47. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/EventModalContext.d.ts +3 -2
  48. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/WeekAgendaView.d.ts +3 -0
  49. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/WeekBoardView.d.ts +31 -3
  50. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/WeekTimetableView.d.ts +3 -1
  51. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/eventCollectionContract.d.ts +9 -1
  52. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/timetableModel.d.ts +4 -3
  53. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/utils.d.ts +3 -3
  54. package/dist/_dts/blocks/src/system/transforms/registry/layout.d.ts +0 -1
  55. package/dist/_dts/calendar/src/grid.d.ts +24 -66
  56. package/dist/_dts/calendar/src/index.d.ts +2 -2
  57. package/dist/_dts/calendar/src/timetable.d.ts +5 -9
  58. package/dist/_dts/commerce/src/purchase/allocation.d.ts +11 -0
  59. package/dist/_dts/commerce/src/purchase/index.d.ts +2 -0
  60. package/dist/_dts/commerce/src/purchase/settlement.d.ts +33 -0
  61. package/dist/_dts/commerce/src/purchase/stripeCheckoutReturnUrl.d.ts +8 -0
  62. package/dist/_dts/content-model/src/templates/defaults.d.ts +6 -0
  63. package/dist/_dts/core/src/slug.d.ts +20 -5
  64. package/dist/_dts/preview-next/src/client/blocks/EditablePageRenderer.d.ts +1 -1
  65. package/dist/_dts/preview-next/src/client/preview/headerInteractionPaletteSurfaceState.d.ts +2 -1
  66. package/dist/_dts/sdk/src/client/publicLoaderCacheAccess.d.ts +6 -0
  67. package/dist/_dts/sdk/src/public-api/contracts.d.ts +5 -1
  68. package/dist/_dts/sdk/src/rendering/blocks-page-renderer.d.ts +10 -6
  69. package/dist/_dts/sdk/src/rendering/components/Block.shared.d.ts +0 -1
  70. package/dist/_dts/sdk/src/rendering/components/pageShared.d.ts +4 -4
  71. package/dist/_dts/sdk/src/rendering/helpers/footerPageOutline.d.ts +3 -0
  72. package/dist/_dts/sdk/src/rendering/helpers/loadContent.d.ts +3 -0
  73. package/dist/_dts/sdk/src/rendering/helpers/loadPage.d.ts +1 -1
  74. package/dist/_dts/sdk/src/rendering/helpers/pageRuntimeSupport.d.ts +17 -0
  75. package/dist/_dts/sdk/src/rendering/helpers/templateContent.d.ts +9 -3
  76. package/dist/_dts/sdk/src/rendering/hooks/usePage.d.ts +1 -1
  77. package/dist/_dts/sdk/src/rendering/index.d.ts +2 -2
  78. package/dist/_dts/sdk/src/rendering/overrideResolution.d.ts +7 -4
  79. package/dist/_dts/sdk/src/version.d.ts +1 -1
  80. package/dist/_dts/theme-core/src/cards/types.d.ts +8 -8
  81. package/dist/_dts/theme-core/src/data.d.ts +12 -0
  82. package/dist/_dts/theme-core/src/generated/containerResponsiveThemeCss.d.ts +1 -1
  83. package/dist/_dts/theme-core/src/header/legacyHeaderVariant.d.ts +2 -6
  84. package/dist/_dts/theme-core/src/mock-themes/all.d.ts +6 -807
  85. package/dist/_dts/theme-core/src/schema.d.ts +452 -1278
  86. package/dist/_dts/theme-core/src/site-styles/curatedSiteStyles.d.ts +213 -1
  87. package/dist/_dts/theme-core/src/site-styles/headerLayoutCatalog.d.ts +0 -29
  88. package/dist/_dts/theme-core/src/site-styles/headerLayoutStyles.d.ts +10 -0
  89. package/dist/_dts/theme-core/src/site-styles/headerLayoutTypes.d.ts +8 -5
  90. package/dist/_dts/theme-core/src/site-styles/headerOpeningForeground.d.ts +4 -4
  91. package/dist/_dts/theme-core/src/site-styles/headerStyleCompiler.d.ts +16 -2
  92. package/dist/_dts/theme-core/src/site-styles/headerStyleDefaults.d.ts +465 -0
  93. package/dist/_dts/theme-core/src/site-styles/headerStyleRecipe.d.ts +161 -0
  94. package/dist/client/{BookingConsentAgreement-Bz9znbpn.mjs → BookingConsentAgreement-DCch21a6.mjs} +2 -2
  95. package/dist/client/{DiscountCodeDisclosure-35Ru8yB9.mjs → DiscountCodeDisclosure-DIj1T59K.mjs} +1 -1
  96. package/dist/client/{EventCombined.client-BKB0ZxRR.mjs → EventCombined.client-BWVNlXTx.mjs} +226 -206
  97. package/dist/client/{EventListing.client-Dx8I21ok.mjs → EventListing.client-DVFCDe3i.mjs} +2 -2
  98. package/dist/client/{LeafletStaticMap-CEWx-Bhe.mjs → LeafletStaticMap-BY5mIHw9.mjs} +1 -1
  99. package/dist/client/{accordion-KIDsKTwS.mjs → accordion-CK29E8rG.mjs} +1 -1
  100. package/dist/client/{bookingForm-D96Rmp-5.mjs → bookingForm-DFvnet-N.mjs} +5 -5
  101. package/dist/client/bookings.mjs +86 -47
  102. package/dist/client/{carousel-YwUgyL66.mjs → carousel-BVU5NQlb.mjs} +1 -1
  103. package/dist/client/{cart-BbwuNrUT.mjs → cart-BNItcZVa.mjs} +3 -3
  104. package/dist/client/{checkout-hp1ucmEY.mjs → checkout-Bu6iCdkP.mjs} +3 -3
  105. package/dist/client/client.mjs +1950 -1031
  106. package/dist/client/{context-DljQn8L5.mjs → context-BImarOAq.mjs} +12 -0
  107. package/dist/client/{eventCalendar-DU4iNLpo.mjs → eventCalendar-DS2h-UXD.mjs} +256 -114
  108. package/dist/client/{eventCombined-CZuupW8m.mjs → eventCombined-Drt4Oq9p.mjs} +3 -3
  109. package/dist/client/{eventDetails-DPQWwCIi.mjs → eventDetails-Bl2vWgTX.mjs} +4 -3
  110. package/dist/client/{eventListing-C7oMidwS.mjs → eventListing-CS7PHY7v.mjs} +3 -3
  111. package/dist/client/{eventRegistration-zEiunlUs.mjs → eventRegistration-D-j8eNy2.mjs} +85 -41
  112. package/dist/client/{form-D2KIyCVJ.mjs → form-RMpoLTyr.mjs} +2 -2
  113. package/dist/client/{headerSection-CK5uChUK.mjs → headerSection-BYE3Lb3k.mjs} +2 -2
  114. package/dist/client/hooks.mjs +2225 -276
  115. package/dist/client/{locationMap-DLQNH1ln.mjs → locationMap-BxSr7Kkh.mjs} +2 -2
  116. package/dist/client/{newsletterForm-ZuhIG7fZ.mjs → newsletterForm-DerbXwFC.mjs} +2 -2
  117. package/dist/client/{productDetail-7hIcGeae.mjs → productDetail-4SZCLhAf.mjs} +3 -3
  118. package/dist/client/{productList-T4Cii1ot.mjs → productList-D7AP4GNq.mjs} +3 -3
  119. package/dist/client/{propsDecoder-mB0aC_Fi.mjs → propsDecoder-pzBeCh14.mjs} +94 -24
  120. package/dist/client/rendering/client.mjs +758 -464
  121. package/dist/client/rendering/islands.mjs +17 -17
  122. package/dist/client/rendering.mjs +2126 -1244
  123. package/dist/client/{scrollToBlock-Du5mHgvL.mjs → scrollToBlock-CduAKf8T.mjs} +1 -1
  124. package/dist/client/{shop-B5zAcKZn.mjs → shop-Cp5p_kGe.mjs} +6 -6
  125. package/dist/client/{shop-commerce-BKBZB6l5.mjs → shop-commerce-DicXYaYX.mjs} +5 -5
  126. package/dist/client/{shop-commerce-store-Cq4qlNtQ.mjs → shop-commerce-store-CGWnpY4K.mjs} +1 -1
  127. package/dist/client/{shopShared-DYGzEs9D.mjs → shopShared-BDf9ljkm.mjs} +3 -3
  128. package/dist/client/{useEventFilters-Bphkda8m.mjs → useEventFilters-DeeyGYuk.mjs} +3 -3
  129. package/dist/preview-next/before-render.mjs +7 -0
  130. package/dist/preview-next/client/runtime.mjs +4 -4
  131. package/dist/preview-next/keepAlive.mjs +7 -0
  132. package/dist/preview-next/middleware.mjs +7 -0
  133. package/dist/{previewAuthStore-C7ksxt5b.mjs → previewAuthStore-DbqBol0V.mjs} +7 -0
  134. package/dist/{sdk-runtime-BbIC8G4J.mjs → sdk-runtime-19MO27F0.mjs} +2 -2
  135. package/dist/{separator-CadhAtI7.mjs → separator-DaPLtJ1f.mjs} +1 -1
  136. package/dist/server/components.mjs +1527 -893
  137. package/dist/server/config-validation.mjs +65 -113
  138. package/dist/server/config.mjs +65 -113
  139. package/dist/server/data.mjs +65 -112
  140. package/dist/server/index.mjs +122 -4
  141. package/dist/server/manifest.mjs +0 -1
  142. package/dist/server/next.mjs +1432 -708
  143. package/dist/server/page-converter.mjs +58 -91
  144. package/dist/server/prebuild.mjs +1 -1
  145. package/dist/server/rendering/server.mjs +1682 -915
  146. package/dist/server/rendering.mjs +1694 -1020
  147. package/dist/server/routing.mjs +3230 -1843
  148. package/dist/server/server.mjs +21710 -19779
  149. package/dist/server/theme-bridge.mjs +656 -264
  150. package/dist/server/theme.mjs +2 -17
  151. package/dist/styles/index.css +609 -181
  152. package/package.json +1 -1
@@ -1788,6 +1788,13 @@ const PUBLIC_WHOLE_SERIES_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
1788
1788
  //#endregion
1789
1789
  //#region ../api/src/publicEventEndpointDefinitions.ts
1790
1790
  const PUBLIC_EVENT_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
1791
+ resolvePublicEventCheckoutReturn: {
1792
+ path: "/public/sites/{siteId}/events/checkout-return",
1793
+ method: "POST",
1794
+ tags: [TAG_TEMPLATES.publicEvents, "event-checkout"],
1795
+ auth: "public",
1796
+ responseKind: "json"
1797
+ },
1791
1798
  getPublicEventRegistrationOptions: {
1792
1799
  path: "/public/sites/{siteId}/events/registration-options",
1793
1800
  method: "POST",
@@ -17795,12 +17802,8 @@ const legacyHeaderVariantValues = Object.keys(legacyHeaderVariants);
17795
17802
  * `@riverbankcms/api` is `z.input<typeof themeSchema>`, so a widened input here
17796
17803
  * would leak straight into a public type.
17797
17804
  *
17798
- * Not every read of a persisted theme goes through the schema:
17799
- * `resolveRuntimeTheme` in
17800
- * `apps/dashboard/src/server/services/sites/runtimeSiteResponse.ts` returns the
17801
- * raw database JSON asserted as `Theme` with no parse, so a theme still
17802
- * carrying a legacy spelling reaches the theme editor un-aliased. That gap
17803
- * predates this alias and is harmless while persisted usage is zero.
17805
+ * Persisted runtime themes are admitted through `parseThemeForPersistence`
17806
+ * before reaching consumers, so legacy spellings normalize at that boundary.
17804
17807
  */
17805
17808
  const headerVariantWithLegacyAliasSchema = z$1.enum([...headerVariantValues, ...legacyHeaderVariantValues]).transform((value) => value in legacyHeaderVariants ? legacyHeaderVariants[value] : value);
17806
17809
  const BREAKPOINT_LG = 1024;
@@ -18391,7 +18394,6 @@ const navFontWeight = z$1.enum([
18391
18394
  "bold"
18392
18395
  ]);
18393
18396
  const headerMaxWidth = z$1.enum(["container", "full"]);
18394
- const headerBarFrame = z$1.enum(["full-bleed", "inset-shell"]);
18395
18397
  const headerBorderSchema = componentBorderSchema.extend({ position: z$1.enum([
18396
18398
  "bottom",
18397
18399
  "top",
@@ -18420,12 +18422,6 @@ const headerLogoTextSchema = z$1.object({
18420
18422
  ]).optional(),
18421
18423
  hideOnShrink: z$1.boolean().optional()
18422
18424
  }).optional();
18423
- const navEffectsSchema = z$1.object({
18424
- underlineGradient: z$1.boolean().default(false),
18425
- glow: z$1.boolean().default(false),
18426
- glowColor: z$1.string().optional(),
18427
- neumorphic: z$1.boolean().default(false)
18428
- }).optional();
18429
18425
  const dropdownStyleSchema = z$1.object({
18430
18426
  background: themeColorTokenSchema.default("surface"),
18431
18427
  textColor: themeColorTokenSchema.default("text"),
@@ -18517,9 +18513,7 @@ const headerSchema = z$1.object({
18517
18513
  positioning: headerPositioning,
18518
18514
  shrinkOnScroll: z$1.boolean(),
18519
18515
  maxWidth: headerMaxWidth,
18520
- barFrame: headerBarFrame.optional(),
18521
18516
  scrollTreatment: headerScrollTreatmentSchema,
18522
- logoOverride: mediaSchema.nullable().optional(),
18523
18517
  background: headerBackgroundSchema.default({
18524
18518
  type: "color",
18525
18519
  color: "surface"
@@ -18531,13 +18525,11 @@ const headerSchema = z$1.object({
18531
18525
  navFontRole: z$1.enum(["body", "heading"]).optional(),
18532
18526
  navTextSize: navLinkStyleSchema.shape.textSize,
18533
18527
  interactionPalette: headerInteractionPaletteSchema.optional(),
18534
- navPlacement: z$1.enum(["end", "center"]).optional(),
18535
18528
  container: headerContainerSchema,
18536
18529
  border: headerBorderSchema,
18537
18530
  shadow: componentShadowSchema.optional(),
18538
18531
  logo: logoStyleSchema,
18539
18532
  logoText: headerLogoTextSchema,
18540
- navEffects: navEffectsSchema,
18541
18533
  navContainer: navContainerSchema,
18542
18534
  navLinkStyle: navLinkStyleSchema.optional(),
18543
18535
  ctaGap: headerCtaGapSchema.optional(),
@@ -19627,7 +19619,6 @@ const ALLOWED_TRANSFORM_IDS = [
19627
19619
  "layout.footerRootClass",
19628
19620
  "layout.headerRootStyle",
19629
19621
  "layout.headerSectionBackground",
19630
- "layout.classicNavMode",
19631
19622
  "layout.footerRootStyle",
19632
19623
  "ui.headerNavLinkClass",
19633
19624
  "ui.headingClassFromAlignment",
@@ -22115,6 +22106,15 @@ function normalizeStoredContentValues(plans, content, options = {}) {
22115
22106
  normalizeInlineTextFallbacks(plans, normalized, ctx);
22116
22107
  return normalized;
22117
22108
  }
22109
+ /**
22110
+ * Produces the portable representation accepted by content persistence.
22111
+ * Runtime-hydrated media fields are stripped only when a canonical identifier
22112
+ * is already present; unresolved environment-specific references remain
22113
+ * invalid and must be handled by the site-scoped media write normalizer first.
22114
+ */
22115
+ function normalizeManifestContentForWrite(plans, content, options = {}) {
22116
+ return canonicalizeObjectForWrite(plans, normalizeStoredContentValues(plans, content, options));
22117
+ }
22118
22118
  function normalizeStoredFieldValueWithContext(plan, value, ctx) {
22119
22119
  if (value === null && !plan.required) return;
22120
22120
  switch (plan.kind) {
@@ -22149,10 +22149,6 @@ function normalizeStoredRepeaterItems(plan, value, ctx) {
22149
22149
  return normalizeStoredObjectChildren(fields, itemRecord, ctx);
22150
22150
  });
22151
22151
  }
22152
- function validateFieldValue(plan, value, options = {}) {
22153
- const ctx = strictValidationContext(options);
22154
- return validateNormalizedFieldValue(plan, normalizeFieldValue(plan, value, ctx), ctx);
22155
- }
22156
22152
  function normalizeFieldValue(plan, value, ctx) {
22157
22153
  switch (plan.kind) {
22158
22154
  case "number": return normalizeNumberInput(value, ctx.allowNull);
@@ -22452,6 +22448,14 @@ function fieldPlanToObjectPropertyZod(plan, options = {}) {
22452
22448
  default: return assertNever$15(presence);
22453
22449
  }
22454
22450
  }
22451
+ /** Validate stored field values without applying editor/write normalization. */
22452
+ function fieldPlanToStoredObjectPropertyZod(plan) {
22453
+ const ctx = strictValidationContext({ allowNull: false });
22454
+ const schema = z$1.any().superRefine((value, zodCtx) => {
22455
+ for (const validationIssue of validateNormalizedFieldValue(plan, value, ctx)) addFieldIssueToZodContext(zodCtx, validationIssue, plan.path);
22456
+ });
22457
+ return plan.required ? schema : schema.optional();
22458
+ }
22455
22459
  function addFieldIssueToZodContext(zodCtx, validationIssue, rootPath) {
22456
22460
  const message = fieldIssueToMessage(validationIssue);
22457
22461
  const path = relativeZodIssuePath(validationIssue.path, rootPath);
@@ -22557,36 +22561,6 @@ function findNestedFieldValidationPlan(plan, path) {
22557
22561
  function sameFieldPath(left, right) {
22558
22562
  return left.length === right.length && left.every((segment, index) => segment === right[index]);
22559
22563
  }
22560
- function validateExplicitNullsForPush(plans, content, ctx) {
22561
- if (!isPlainObject$5(content)) return [];
22562
- return plans.flatMap((plan) => validateExplicitNullForPushPlan(plan, content[plan.fieldId], ctx));
22563
- }
22564
- function validateExplicitNullForPushPlan(plan, value, ctx) {
22565
- if (value === null) return !plan.required && !ctx.allowNull && !acceptsOptionalNullValue(plan) ? validateFieldValue(plan, value, { allowNull: false }) : [];
22566
- switch (plan.kind) {
22567
- case "group": return validateExplicitNullsForPush(selectedGroupChildPlans(plan, value), value, childValidationContext(plan, ctx));
22568
- case "repeater": return validateExplicitNullsForPushRepeater(plan, value, ctx);
22569
- case "string":
22570
- case "number":
22571
- case "boolean":
22572
- case "richText":
22573
- case "inlineText":
22574
- case "media":
22575
- case "link":
22576
- case "select":
22577
- case "passthrough": return [];
22578
- default: return assertNever$15(plan);
22579
- }
22580
- }
22581
- function validateExplicitNullsForPushRepeater(plan, value, ctx) {
22582
- if (!isUnknownArray$2(value)) return [];
22583
- return value.flatMap((item, index) => {
22584
- if (!isPlainObject$5(item)) return [];
22585
- const childPlans = plan.repeatedItemVariants ? plan.repeatedItemVariants.find((variant) => variant.typeId === item._type)?.fields : plan.repeatedItemPlan;
22586
- if (!childPlans) return [];
22587
- return childPlans.flatMap((childPlan) => validateExplicitNullForPushPlan(materializeRepeaterItemPlan(childPlan, plan.path, index), item[childPlan.fieldId], ctx));
22588
- });
22589
- }
22590
22564
  function compilePattern(pattern) {
22591
22565
  try {
22592
22566
  return new RegExp(pattern);
@@ -22694,6 +22668,7 @@ function registerManifest(manifest) {
22694
22668
  }
22695
22669
  //#endregion
22696
22670
  //#region ../blocks/src/system/manifest/validation.ts
22671
+ const compiledManifestContentContract = Symbol("compiledManifestContentContract");
22697
22672
  /**
22698
22673
  * Preprocess content by converting empty values to undefined.
22699
22674
  * Used in draft mode to allow required fields to be temporarily empty.
@@ -22704,13 +22679,94 @@ function preprocessEmptyValues(content) {
22704
22679
  for (const [key, value] of Object.entries(content)) result[key] = isEmptyValue$1(value) ? void 0 : value;
22705
22680
  return result;
22706
22681
  }
22707
- function createManifestValidator(manifestOrFields, options = {}) {
22708
- return createManifestValidatorWithNormalizer(manifestOrFields, options, normalizeStoredContentValues);
22682
+ /**
22683
+ * Compiles editor-facing manifest structure into the presentation-independent
22684
+ * validation contract used by every manifest-content trust transition.
22685
+ */
22686
+ function compileManifestContentContract(manifestOrFields) {
22687
+ const plans = derivePlansFromManifestOrFields(manifestOrFields);
22688
+ const strictOptions = { allowNull: false };
22689
+ const strictStoredSchema = deriveStrictStoredZodFromPlans(plans);
22690
+ return Object.freeze({ [compiledManifestContentContract]: Object.freeze({
22691
+ plans,
22692
+ strictStoredSchema,
22693
+ writeSchema: deriveNormalizedContentZodFromPlans(plans, strictOptions, normalizeManifestContentForWrite).transform((value) => canonicalizeObjectForWrite(plans, value)),
22694
+ draftSchema: deriveNormalizedContentZodFromPlans(plans, {
22695
+ allowNull: true,
22696
+ allowIncomplete: true,
22697
+ mode: "draft"
22698
+ }, normalizeStoredContentValues),
22699
+ renderSchema: strictStoredSchema,
22700
+ findNonPortableMediaPaths: (content) => findNonPortableMediaPaths(plans, content)
22701
+ }) });
22709
22702
  }
22710
- function createManifestValidatorWithNormalizer(manifestOrFields, options, normalize) {
22711
- return createManifestValidatorFromPlans(derivePlansFromManifestOrFields(manifestOrFields), options, normalize);
22703
+ /** Strictly admits already-persisted content without repairing it. */
22704
+ function admitStoredManifestContent(contract, content) {
22705
+ const state = contract[compiledManifestContentContract];
22706
+ const nonPortablePaths = state.findNonPortableMediaPaths(content);
22707
+ if (nonPortablePaths.length > 0) return {
22708
+ ok: false,
22709
+ error: {
22710
+ kind: "non_portable_media",
22711
+ paths: nonPortablePaths
22712
+ }
22713
+ };
22714
+ const parsed = state.strictStoredSchema.safeParse(content);
22715
+ return parsed.success ? {
22716
+ ok: true,
22717
+ value: content
22718
+ } : {
22719
+ ok: false,
22720
+ error: zodAdmissionError(parsed.error)
22721
+ };
22722
+ }
22723
+ /** Validates raw editor state without granting a stored-content proof. */
22724
+ function validateManifestDraft(contract, data) {
22725
+ const parsed = contract[compiledManifestContentContract].draftSchema.safeParse(data);
22726
+ if (parsed.success) return {
22727
+ kind: "previewable",
22728
+ data,
22729
+ issues: []
22730
+ };
22731
+ const [firstIssue, ...remainingIssues] = zodAdmissionIssues(parsed.error);
22732
+ if (!firstIssue) throw new Error("Draft manifest validation failed without an issue");
22733
+ return {
22734
+ kind: "invalid",
22735
+ data,
22736
+ issues: [firstIssue, ...remainingIssues]
22737
+ };
22738
+ }
22739
+ /**
22740
+ * Applies a pure runtime projection to admitted stored content and validates
22741
+ * the resulting render shape before granting the renderable proof.
22742
+ */
22743
+ function deriveRenderableManifestContent(contract, stored, project) {
22744
+ const projected = project(stored);
22745
+ const parsed = contract[compiledManifestContentContract].renderSchema.safeParse(projected);
22746
+ return parsed.success ? {
22747
+ ok: true,
22748
+ value: projected
22749
+ } : {
22750
+ ok: false,
22751
+ error: zodAdmissionError(parsed.error)
22752
+ };
22753
+ }
22754
+ /**
22755
+ * Re-admits renderable content after a transport boundary has erased its
22756
+ * compile-time proof. Unlike write admission, this never canonicalizes or
22757
+ * grants a stored proof, so hydrated media cannot flow back to persistence.
22758
+ */
22759
+ function admitTransportedRenderableManifestContent(contract, content) {
22760
+ const parsed = contract[compiledManifestContentContract].renderSchema.safeParse(content);
22761
+ return parsed.success ? {
22762
+ ok: true,
22763
+ value: content
22764
+ } : {
22765
+ ok: false,
22766
+ error: zodAdmissionError(parsed.error)
22767
+ };
22712
22768
  }
22713
- function createManifestValidatorFromPlans(plans, options, normalize) {
22769
+ function deriveNormalizedContentZodFromPlans(plans, options, normalize) {
22714
22770
  const isDraft = options.mode === "draft";
22715
22771
  const baseSchema = deriveContentZodFromPlans(plans, options);
22716
22772
  if (isDraft) return z$1.preprocess((content) => preprocessEmptyValues(normalize(plans, content, options)), baseSchema);
@@ -22721,9 +22777,81 @@ function deriveContentZodFromPlans(plans, options) {
22721
22777
  for (const plan of plans) shape[plan.fieldId] = fieldPlanToObjectPropertyZod(plan, options);
22722
22778
  return z$1.object(shape).catchall(z$1.unknown()).passthrough();
22723
22779
  }
22780
+ function deriveStrictStoredZodFromPlans(plans) {
22781
+ const shape = {};
22782
+ for (const plan of plans) shape[plan.fieldId] = fieldPlanToStoredObjectPropertyZod(plan);
22783
+ return z$1.object(shape).catchall(z$1.unknown()).passthrough();
22784
+ }
22724
22785
  function derivePlansFromManifestOrFields(manifestOrFields) {
22725
22786
  return deriveFieldValidationPlans(Array.isArray(manifestOrFields) ? manifestOrFields : manifestOrFields.fields ?? []);
22726
22787
  }
22788
+ function zodAdmissionError(error) {
22789
+ return {
22790
+ kind: "invalid_shape",
22791
+ issues: zodAdmissionIssues(error)
22792
+ };
22793
+ }
22794
+ function zodAdmissionIssues(error) {
22795
+ return error.issues.map((issue) => ({
22796
+ code: issue.code,
22797
+ path: issue.path.map((segment) => typeof segment === "number" ? segment : String(segment)),
22798
+ message: issue.message
22799
+ }));
22800
+ }
22801
+ function findNonPortableMediaPaths(plans, content) {
22802
+ const paths = /* @__PURE__ */ new Set();
22803
+ collectNonPortablePlannedMedia(plans, content, [], paths);
22804
+ return [...paths].sort();
22805
+ }
22806
+ function collectNonPortablePlannedMedia(plans, content, parentPath, paths) {
22807
+ if (!isPlainRecord$1(content)) return;
22808
+ for (const plan of plans) {
22809
+ if (!(plan.fieldId in content)) continue;
22810
+ const value = content[plan.fieldId];
22811
+ const path = [...parentPath, plan.fieldId];
22812
+ switch (plan.kind) {
22813
+ case "media":
22814
+ if (isPlainRecord$1(value) && hasEnvironmentSpecificMediaField(value)) paths.add(formatFieldPath(path));
22815
+ break;
22816
+ case "richText":
22817
+ collectNonPortableRichTextImages(value, path, paths);
22818
+ break;
22819
+ case "group":
22820
+ collectNonPortablePlannedMedia(selectedGroupChildPlans(plan, value), value, path, paths);
22821
+ break;
22822
+ case "repeater":
22823
+ collectNonPortableRepeaterMedia(plan, value, path, paths);
22824
+ break;
22825
+ case "string":
22826
+ case "number":
22827
+ case "boolean":
22828
+ case "inlineText":
22829
+ case "link":
22830
+ case "select":
22831
+ case "passthrough": break;
22832
+ }
22833
+ }
22834
+ }
22835
+ function collectNonPortableRepeaterMedia(plan, value, path, paths) {
22836
+ if (!Array.isArray(value)) return;
22837
+ value.forEach((item, index) => {
22838
+ if (!isPlainRecord$1(item)) return;
22839
+ const childPlans = plan.repeatedItemVariants ? plan.repeatedItemVariants.find((variant) => variant.typeId === item._type)?.fields : plan.repeatedItemPlan;
22840
+ if (childPlans) collectNonPortablePlannedMedia(childPlans, item, [...path, index], paths);
22841
+ });
22842
+ }
22843
+ function collectNonPortableRichTextImages(value, path, paths) {
22844
+ const images = [];
22845
+ walkAndCollectImageAttrs(value, images);
22846
+ const prefix = formatFieldPath(path);
22847
+ for (const reference of images) if (hasEnvironmentSpecificMediaField(reference.attrs)) paths.add(reference.location ? `${prefix}.${reference.location}` : prefix);
22848
+ }
22849
+ function isPlainRecord$1(value) {
22850
+ return typeof value === "object" && value !== null && !Array.isArray(value);
22851
+ }
22852
+ function hasEnvironmentSpecificMediaField(value) {
22853
+ return "assetId" in value || "storageBucket" in value || "storagePath" in value || "src" in value || "mimeType" in value || looksLikeUuid(value.id);
22854
+ }
22727
22855
  //#endregion
22728
22856
  //#region ../blocks/src/system/manifest/variantKey.ts
22729
22857
  /**
@@ -25931,27 +26059,6 @@ function asHeaderStyleId(value) {
25931
26059
  return value;
25932
26060
  }
25933
26061
  //#endregion
25934
- //#region ../theme-core/src/site-styles/headerInteractionPalette.ts
25935
- const clearSplitInteractionPalette = defineLookOptionGroup({
25936
- id: "interaction-palette",
25937
- label: "Hover colour",
25938
- defaultOptionId: "accent",
25939
- options: [
25940
- {
25941
- id: "accent",
25942
- label: "Accent"
25943
- },
25944
- {
25945
- id: "primary",
25946
- label: "Primary"
25947
- },
25948
- {
25949
- id: "secondary",
25950
- label: "Secondary"
25951
- }
25952
- ]
25953
- });
25954
- //#endregion
25955
26062
  //#region ../theme-core/src/site-styles/headerLayoutCatalog.ts
25956
26063
  const titleOnlyLogoAccommodation = {
25957
26064
  pattern: "title-only",
@@ -26111,43 +26218,37 @@ const headerStyleCatalog = defineExactCatalog()([
26111
26218
  id: asHeaderStyleId("minimal"),
26112
26219
  label: "Minimal",
26113
26220
  description: "Quiet surface with simple color-change navigation.",
26114
- supportedLayoutIds: supportedLayouts(["classic", "centered"]),
26115
- navTypography: "plain"
26221
+ supportedLayoutIds: supportedLayouts(["classic", "centered"])
26116
26222
  },
26117
26223
  {
26118
26224
  id: asHeaderStyleId("fine-line"),
26119
26225
  label: "Seamless",
26120
26226
  description: "Borderless surface with underline hover for a quieter page transition.",
26121
- supportedLayoutIds: supportedLayouts(["classic", "centered"]),
26122
- navTypography: "plain"
26227
+ supportedLayoutIds: supportedLayouts(["classic", "centered"])
26123
26228
  },
26124
26229
  {
26125
26230
  id: asHeaderStyleId("soft-bar"),
26126
26231
  label: "Soft Bar",
26127
26232
  description: "Soft tinted surface with gentle pill hover states.",
26128
- supportedLayoutIds: supportedLayouts(["classic", "centered"]),
26129
- navTypography: "plain"
26233
+ supportedLayoutIds: supportedLayouts(["classic", "centered"])
26130
26234
  },
26131
26235
  {
26132
26236
  id: asHeaderStyleId("pill-nav"),
26133
26237
  label: "Pill Nav",
26134
26238
  description: "A calm pill navigation rail over a neutral header.",
26135
- supportedLayoutIds: supportedLayouts(["classic", "centered"]),
26136
- navTypography: "plain"
26239
+ supportedLayoutIds: supportedLayouts(["classic", "centered"])
26137
26240
  },
26138
26241
  {
26139
26242
  id: asHeaderStyleId("brand-bar"),
26140
26243
  label: "Brand Bar",
26141
26244
  description: "Solid brand surface with high-contrast navigation.",
26142
- supportedLayoutIds: supportedLayouts(["classic", "centered"]),
26143
- navTypography: "brand-caps"
26245
+ supportedLayoutIds: supportedLayouts(["classic", "centered"])
26144
26246
  },
26145
26247
  {
26146
26248
  id: asHeaderStyleId("brand-underline"),
26147
26249
  label: "Brand Underline",
26148
26250
  description: "Brand surface with underline-grow navigation.",
26149
- supportedLayoutIds: supportedLayouts(["classic"]),
26150
- navTypography: "brand-caps"
26251
+ supportedLayoutIds: supportedLayouts(["classic"])
26151
26252
  },
26152
26253
  {
26153
26254
  id: asHeaderStyleId("brand-pill"),
@@ -26157,73 +26258,78 @@ const headerStyleCatalog = defineExactCatalog()([
26157
26258
  "classic",
26158
26259
  "centered",
26159
26260
  "floating"
26160
- ]),
26161
- navTypography: "brand-caps"
26261
+ ])
26162
26262
  },
26163
26263
  {
26164
26264
  id: asHeaderStyleId("brand-capsule"),
26165
26265
  label: "Brand Capsule",
26166
26266
  description: "Solid brand chrome designed as a floating capsule, with quiet-caps nav, a soft pill active state, and an inverted CTA pill.",
26167
- supportedLayoutIds: supportedLayouts(["classic"]),
26168
- navTypography: "quiet-caps"
26267
+ supportedLayoutIds: supportedLayouts(["classic"])
26169
26268
  },
26170
26269
  {
26171
26270
  id: asHeaderStyleId("serif-line"),
26172
26271
  label: "Serif Line",
26173
26272
  description: "Typographic logo treatment with understated underline navigation.",
26174
- supportedLayoutIds: supportedLayouts(["classic", "centered"]),
26175
- navTypography: "heading"
26273
+ supportedLayoutIds: supportedLayouts(["classic", "centered"])
26176
26274
  },
26177
26275
  {
26178
26276
  id: asHeaderStyleId("flat-tabs"),
26179
26277
  label: "Flat Tabs",
26180
26278
  description: "Flat block hover and active states with a Swiss utility feel.",
26181
- supportedLayoutIds: supportedLayouts(["classic", "centered"]),
26182
- navTypography: "quiet-caps"
26279
+ supportedLayoutIds: supportedLayouts(["classic", "centered"])
26183
26280
  },
26184
26281
  {
26185
26282
  id: asHeaderStyleId("glass"),
26186
26283
  label: "Glass",
26187
26284
  description: "Translucent chrome with frosted navigation backing.",
26188
- supportedLayoutIds: supportedLayouts(["floating"]),
26189
- navTypography: "plain"
26285
+ supportedLayoutIds: supportedLayouts(["floating"])
26190
26286
  },
26191
26287
  {
26192
26288
  id: asHeaderStyleId("minimal-surface"),
26193
26289
  label: "Clear Split",
26194
26290
  description: "Floating logo with transparent navigation and no shared shell.",
26195
- supportedLayoutIds: supportedLayouts(["floating"]),
26196
- navTypography: "plain",
26197
- openingForegroundTarget: "all",
26198
- scrollTreatment: "contrast-glass",
26199
- interactionPalette: clearSplitInteractionPalette
26291
+ supportedLayoutIds: supportedLayouts(["floating"])
26200
26292
  },
26201
26293
  {
26202
26294
  id: asHeaderStyleId("soft-shell"),
26203
26295
  label: "Soft Shell",
26204
26296
  description: "Floating rounded shell with soft pill navigation states.",
26205
- supportedLayoutIds: supportedLayouts(["floating"]),
26206
- navTypography: "plain"
26297
+ supportedLayoutIds: supportedLayouts(["floating"])
26207
26298
  },
26208
26299
  {
26209
26300
  id: asHeaderStyleId("split-glass"),
26210
26301
  label: "Split Glass",
26211
26302
  description: "Logo floats independently while the navigation sits in a glass rail.",
26212
- supportedLayoutIds: supportedLayouts(["floating"]),
26213
- navTypography: "quiet-caps",
26214
- openingForegroundTarget: "brand-only"
26303
+ supportedLayoutIds: supportedLayouts(["floating"])
26215
26304
  },
26216
26305
  {
26217
26306
  id: asHeaderStyleId("split-pill"),
26218
26307
  label: "Split Pill",
26219
26308
  description: "Logo floats independently with a soft pill-backed navigation rail.",
26220
- supportedLayoutIds: supportedLayouts(["floating"]),
26221
- navTypography: "heading",
26222
- openingForegroundTarget: "brand-only"
26309
+ supportedLayoutIds: supportedLayouts(["floating"])
26223
26310
  }
26224
26311
  ]);
26225
26312
  new Map(headerLayoutCatalog.map((layout) => [layout.id, layout]));
26226
26313
  new Map(headerStyleCatalog.map((style) => [style.id, style]));
26314
+ defineLookOptionGroup({
26315
+ id: "interaction-palette",
26316
+ label: "Hover colour",
26317
+ defaultOptionId: "accent",
26318
+ options: [
26319
+ {
26320
+ id: "accent",
26321
+ label: "Accent"
26322
+ },
26323
+ {
26324
+ id: "primary",
26325
+ label: "Primary"
26326
+ },
26327
+ {
26328
+ id: "secondary",
26329
+ label: "Secondary"
26330
+ }
26331
+ ]
26332
+ });
26227
26333
  function asFooterLookId(value) {
26228
26334
  return value;
26229
26335
  }
@@ -37178,26 +37284,6 @@ const headerLogoTextVisibleTransform = {
37178
37284
  return resolveHeaderBrandDisplay(asPartialObject(value)) !== "logo-only";
37179
37285
  }
37180
37286
  };
37181
- /**
37182
- * Selects which classic-layout nav row should render.
37183
- *
37184
- * - `'inline'` → classic variant with the historical logo-left / nav-right row
37185
- * - `'centered'`→ classic variant with a centred (flex-1) nav and a right CTA
37186
- * - `'other'` → not a classic variant (centered/floating handle it)
37187
- *
37188
- * Consumed by the site-header block's `$when` gates so the two classic rows are
37189
- * mutually exclusive without introducing a new top-level header variant.
37190
- */
37191
- const classicNavModeTransform = {
37192
- id: "layout.classicNavMode",
37193
- kind: "formatter",
37194
- summary: "Resolve which classic-layout nav row to render",
37195
- run: (value) => {
37196
- const header = asPartialObject(value);
37197
- if (header?.variant !== "classic") return "other";
37198
- return header?.navPlacement === "center" ? "centered" : "inline";
37199
- }
37200
- };
37201
37287
  const maxWidthClassTransform = {
37202
37288
  id: "layout.maxWidthClass",
37203
37289
  kind: "string",
@@ -37303,7 +37389,6 @@ const headerRootClassTransform = {
37303
37389
  if (isHeaderScrollRuntimeEnabled(content)) classes.push(config.shrink);
37304
37390
  const variant = header?.variant;
37305
37391
  if (variant && headerVariantValues.includes(variant)) classes.push(`header-variant-${variant}`);
37306
- if (header?.barFrame === "inset-shell" && variant === "classic") classes.push("header-bar-frame-inset-shell");
37307
37392
  return joinClasses$2(classes);
37308
37393
  }
37309
37394
  };
@@ -37511,7 +37596,6 @@ const layoutTransforms = [
37511
37596
  headerLogoClassTransform,
37512
37597
  headerLogoMediaClassTransform,
37513
37598
  headerLogoTextVisibleTransform,
37514
- classicNavModeTransform,
37515
37599
  footerRootClassTransform,
37516
37600
  headerRootStyleTransform,
37517
37601
  headerSectionBackgroundTransform,
@@ -37914,18 +37998,7 @@ const classicLayout = inline({
37914
37998
  logoRow,
37915
37999
  createNavRow(`rb-ml-auto ${desktopOnlyDisplay("flex")} rb-gap-6`),
37916
38000
  headerCta
37917
- ], whenTransformed("$root.theme.header", "layout.classicNavMode", "inline"));
37918
- const classicCenteredNavLayout = inline({
37919
- className: bindProp("$root.theme.header.maxWidth", {
37920
- transforms: pipe(tx("layout.maxWidthClass", { base: `rb-header-layout ${desktopOnlyDisplay("flex")} rb-w-full rb-items-center rb-gap-6` })),
37921
- fallback: `rb-container rb-header-layout ${desktopOnlyDisplay("flex")} rb-w-full rb-items-center rb-gap-6`
37922
- }),
37923
- align: "center"
37924
- }, [
37925
- logoRow,
37926
- createNavRow(`rb-flex-1 rb-justify-center ${desktopOnlyDisplay("flex")} rb-gap-6`, "center"),
37927
- headerCta
37928
- ], whenTransformed("$root.theme.header", "layout.classicNavMode", "centered"));
38001
+ ], when("$root.theme.header.variant", { equals: "classic" }));
37929
38002
  const centeredLayout = stack({
37930
38003
  gap: "md",
37931
38004
  align: "center",
@@ -37990,7 +38063,6 @@ const siteHeaderBlockDefinition = { manifest: createBlockManifest({
37990
38063
  }, [
37991
38064
  mobileHeaderBar,
37992
38065
  classicLayout,
37993
- classicCenteredNavLayout,
37994
38066
  centeredLayout,
37995
38067
  floatingLayout,
37996
38068
  mobileOverlay
@@ -42322,67 +42394,49 @@ const MONTH_NAMES = [
42322
42394
  "November",
42323
42395
  "December"
42324
42396
  ];
42325
- /** Format a date as YYYY-MM-DD using the runtime's local timezone. */
42326
42397
  function formatDateKey(date) {
42327
- return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`;
42398
+ return `${String(date.year).padStart(4, "0")}-${String(date.month).padStart(2, "0")}-${String(date.day).padStart(2, "0")}`;
42328
42399
  }
42329
- /**
42330
- * True when `date` and `now` are the same local calendar day.
42331
- * `now` defaults to `new Date()` so casual callers don't need to thread it,
42332
- * but tests and snapshot-rendering should pass an explicit value.
42333
- */
42334
- function isToday(date, now = /* @__PURE__ */ new Date()) {
42335
- return isSameLocalDay(date, now);
42400
+ function isToday(date, today) {
42401
+ return isSameCalendarDay(date, today);
42336
42402
  }
42337
- /** True when two dates fall on the same local calendar day. */
42338
- function isSameLocalDay(left, right) {
42339
- return left.getFullYear() === right.getFullYear() && left.getMonth() === right.getMonth() && left.getDate() === right.getDate();
42403
+ function isSameCalendarDay(left, right) {
42404
+ return left.year === right.year && left.month === right.month && left.day === right.day;
42405
+ }
42406
+ function addDays(date, days) {
42407
+ const result = new Date(Date.UTC(date.year, date.month - 1, date.day + days, 12));
42408
+ return {
42409
+ year: result.getUTCFullYear(),
42410
+ month: result.getUTCMonth() + 1,
42411
+ day: result.getUTCDate()
42412
+ };
42340
42413
  }
42341
- /**
42342
- * Build the calendar days for a month view. Returns 42 dates (6 rows × 7
42343
- * days) including padding from prior/next months for a stable grid.
42344
- */
42345
42414
  function getMonthCalendarDays(year, month, startOfWeek) {
42346
- const firstDayOfMonth = new Date(year, month, 1);
42347
- const lastDayOfMonth = new Date(year, month + 1, 0);
42348
- let startOffset = firstDayOfMonth.getDay();
42349
- if (startOfWeek === "monday") startOffset = startOffset === 0 ? 6 : startOffset - 1;
42350
- const days = [];
42351
- for (let i = startOffset - 1; i >= 0; i--) days.push(new Date(year, month, -i));
42352
- for (let day = 1; day <= lastDayOfMonth.getDate(); day++) days.push(new Date(year, month, day));
42353
- while (days.length < 42) {
42354
- const nextDay = days.length - startOffset - lastDayOfMonth.getDate() + 1;
42355
- days.push(new Date(year, month + 1, nextDay));
42356
- }
42357
- return days;
42415
+ const firstDay = {
42416
+ year,
42417
+ month,
42418
+ day: 1
42419
+ };
42420
+ const dayOfWeek = getDayOfWeek(firstDay);
42421
+ const gridStart = addDays(firstDay, -(startOfWeek === "monday" ? dayOfWeek === 0 ? 6 : dayOfWeek - 1 : dayOfWeek));
42422
+ return Array.from({ length: 42 }, (_, index) => addDays(gridStart, index));
42358
42423
  }
42359
- /** Build the 7 dates of the week containing `baseDate`. */
42360
42424
  function getWeekCalendarDays(baseDate, startOfWeek) {
42361
- const days = [];
42362
- const dayOfWeek = baseDate.getDay();
42363
- const daysToStart = startOfWeek === "monday" ? dayOfWeek === 0 ? 6 : dayOfWeek - 1 : dayOfWeek;
42364
- const weekStart = new Date(baseDate);
42365
- weekStart.setDate(baseDate.getDate() - daysToStart);
42366
- for (let i = 0; i < 7; i++) {
42367
- const date = new Date(weekStart);
42368
- date.setDate(weekStart.getDate() + i);
42369
- days.push(date);
42370
- }
42371
- return days;
42425
+ const dayOfWeek = getDayOfWeek(baseDate);
42426
+ const weekStart = addDays(baseDate, -(startOfWeek === "monday" ? dayOfWeek === 0 ? 6 : dayOfWeek - 1 : dayOfWeek));
42427
+ return Array.from({ length: 7 }, (_, index) => addDays(weekStart, index));
42428
+ }
42429
+ function getDayOfWeek(date) {
42430
+ return new Date(Date.UTC(date.year, date.month - 1, date.day, 12)).getUTCDay();
42372
42431
  }
42373
- /** Build the 7 dates of the week containing `baseDate` as a fixed-width tuple. */
42374
42432
  function getWeekCalendarDayTuple(baseDate, startOfWeek) {
42375
42433
  const days = getWeekCalendarDays(baseDate, startOfWeek);
42376
42434
  assertWeekCalendarDays(days);
42377
42435
  return days;
42378
42436
  }
42379
42437
  function assertWeekCalendarDays(days) {
42380
- if (days.length !== 7) throw new Error("Expected week calendar helper to return exactly 7 days");
42438
+ if (days.length !== 7) throw new Error("Expected exactly 7 calendar days");
42381
42439
  }
42382
- /**
42383
- * Day-name labels reordered for the chosen week start. Pass a custom
42384
- * `dayNames` array (length 7, Sunday-first) to localize.
42385
- */
42386
42440
  function getOrderedDayNames(startOfWeek, dayNames = DAY_NAMES) {
42387
42441
  if (startOfWeek === "monday") {
42388
42442
  const sunday = dayNames[0] ?? "Sun";
@@ -42390,22 +42444,17 @@ function getOrderedDayNames(startOfWeek, dayNames = DAY_NAMES) {
42390
42444
  }
42391
42445
  return [...dayNames];
42392
42446
  }
42393
- /**
42394
- * Header title for a calendar view.
42395
- * - month: "January 2025"
42396
- * - week: "January 5 - 11, 2025" or "December 30 - January 5, 2025"
42397
- */
42398
42447
  function formatCalendarTitle(viewDate, view, days, monthNames = MONTH_NAMES) {
42399
42448
  if (view === "week") {
42400
42449
  const weekStart = days[0];
42401
42450
  const weekEnd = days[6];
42402
- if (weekStart === void 0 || weekEnd === void 0) return `${monthNames[viewDate.getMonth()] ?? ""} ${viewDate.getFullYear()}`;
42403
- const startMonth = monthNames[weekStart.getMonth()] ?? "";
42404
- const endMonth = monthNames[weekEnd.getMonth()] ?? "";
42405
- if (weekStart.getMonth() === weekEnd.getMonth()) return `${startMonth} ${weekStart.getDate()} - ${weekEnd.getDate()}, ${weekEnd.getFullYear()}`;
42406
- return `${startMonth} ${weekStart.getDate()} - ${endMonth} ${weekEnd.getDate()}, ${weekEnd.getFullYear()}`;
42451
+ if (weekStart === void 0 || weekEnd === void 0) return `${monthNames[viewDate.month - 1] ?? ""} ${viewDate.year}`;
42452
+ const startMonth = monthNames[weekStart.month - 1] ?? "";
42453
+ const endMonth = monthNames[weekEnd.month - 1] ?? "";
42454
+ if (weekStart.month === weekEnd.month) return `${startMonth} ${weekStart.day} - ${weekEnd.day}, ${weekEnd.year}`;
42455
+ return `${startMonth} ${weekStart.day} - ${endMonth} ${weekEnd.day}, ${weekEnd.year}`;
42407
42456
  }
42408
- return `${monthNames[viewDate.getMonth()] ?? ""} ${viewDate.getFullYear()}`;
42457
+ return `${monthNames[viewDate.month - 1] ?? ""} ${viewDate.year}`;
42409
42458
  }
42410
42459
  function buildCalendarViewport(input) {
42411
42460
  const monthNames = input.monthNames ?? MONTH_NAMES;
@@ -42415,10 +42464,10 @@ function buildCalendarViewport(input) {
42415
42464
  kind: "week",
42416
42465
  anchorDate: input.anchorDate,
42417
42466
  days,
42418
- title: formatCalendarTitle(input.anchorDate, "week", [...days], monthNames)
42467
+ title: formatCalendarTitle(input.anchorDate, "week", days, monthNames)
42419
42468
  };
42420
42469
  }
42421
- const days = getMonthCalendarDays(input.anchorDate.getFullYear(), input.anchorDate.getMonth(), input.startOfWeek);
42470
+ const days = getMonthCalendarDays(input.anchorDate.year, input.anchorDate.month, input.startOfWeek);
42422
42471
  return {
42423
42472
  kind: "month",
42424
42473
  anchorDate: input.anchorDate,
@@ -42566,13 +42615,12 @@ function buildTimetableModel$1(input) {
42566
42615
  const bounds = resolveBounds(input.bounds);
42567
42616
  const viewportDays = getTimetableDays(input.viewDate, input.view ?? "week", input.startOfWeek);
42568
42617
  const viewportKeys = new Set(viewportDays.map(formatDateKey));
42569
- const now = input.now ?? /* @__PURE__ */ new Date();
42570
42618
  const parsed = parseAllItems(input.items, input);
42571
42619
  const inViewport = deriveVisibleSegments(parsed.drafts, viewportKeys);
42572
42620
  const hourRange = resolveHourRange(inViewport, bounds);
42573
42621
  const laid = layoutCellsByDate(inViewport, hourRange, bounds);
42574
42622
  return {
42575
- days: assembleDays(viewportDays, laid.cellsByDate, now),
42623
+ days: assembleDays(viewportDays, laid.cellsByDate, input.today),
42576
42624
  hourTicks: buildHourTicks(hourRange.startHour, hourRange.endHour),
42577
42625
  startHour: hourRange.startHour,
42578
42626
  endHour: hourRange.endHour,
@@ -42629,13 +42677,13 @@ function layoutCellsByDate(segments, hourRange, bounds) {
42629
42677
  diagnostics
42630
42678
  };
42631
42679
  }
42632
- function assembleDays(viewportDays, cellsByDate, now) {
42680
+ function assembleDays(viewportDays, cellsByDate, today) {
42633
42681
  return viewportDays.map((date) => {
42634
42682
  const dateKey = formatDateKey(date);
42635
42683
  return {
42636
42684
  date,
42637
42685
  dateKey,
42638
- isToday: isSameLocalDay(date, now),
42686
+ isToday: isSameCalendarDay(date, today),
42639
42687
  cells: cellsByDate.get(dateKey) ?? []
42640
42688
  };
42641
42689
  });
@@ -42787,13 +42835,12 @@ function getTimetableDays(viewDate, view, startOfWeek) {
42787
42835
  function enumerateDateKeys(startDateKey, endDateKey) {
42788
42836
  if (startDateKey > endDateKey) throw new Error(`Invalid timetable date range: ${startDateKey} is after ${endDateKey}`);
42789
42837
  const start = parseDateKey(startDateKey);
42790
- const end = parseDateKey(endDateKey);
42838
+ parseDateKey(endDateKey);
42791
42839
  const keys = [];
42792
- const cursor = new Date(start.year, start.month - 1, start.day);
42793
- const endDate = new Date(end.year, end.month - 1, end.day);
42794
- while (cursor.getTime() <= endDate.getTime()) {
42840
+ let cursor = start;
42841
+ while (formatDateKey(cursor) <= endDateKey) {
42795
42842
  keys.push(formatDateKey(cursor));
42796
- cursor.setDate(cursor.getDate() + 1);
42843
+ cursor = addDays(cursor, 1);
42797
42844
  }
42798
42845
  return keys;
42799
42846
  }
@@ -43018,10 +43065,10 @@ function formatEventTeacherLine(event) {
43018
43065
  * timezone). Thin domain wrapper over `groupItemsByDate` from the calendar
43019
43066
  * package; preserves the historical `Map<string, PublicEvent[]>` shape.
43020
43067
  */
43021
- function groupEventsByDate(events) {
43068
+ function groupEventsByDate(events, calendarTimeZone) {
43022
43069
  const grouped = groupItemsByDate(events, {
43023
43070
  getStartsAt: (event) => event.startsAt,
43024
- getTimeZone: (event) => event.timeZone ?? "UTC"
43071
+ getTimeZone: () => calendarTimeZone
43025
43072
  });
43026
43073
  const map = /* @__PURE__ */ new Map();
43027
43074
  for (const [dateKey, bucket] of grouped) map.set(dateKey, [...bucket]);
@@ -44782,7 +44829,8 @@ const eventCollectionSourceSchemaShape = {
44782
44829
  buttonVariant: eventButtonVariantSchema.optional(),
44783
44830
  buttonText: z$1.string().optional(),
44784
44831
  emptyMessage: z$1.string().optional(),
44785
- className: z$1.string().optional()
44832
+ className: z$1.string().optional(),
44833
+ bookingTimeZone: z$1.string().optional()
44786
44834
  };
44787
44835
  const eventCollectionDisplaySchemaShape = {
44788
44836
  events: z$1.array(publicEventSchema),
@@ -44817,7 +44865,15 @@ const eventCollectionHydrationSchema = z$1.object({
44817
44865
  prefetchedEvents: z$1.boolean(),
44818
44866
  eventSurface: eventSurfaceScopeSchema$1,
44819
44867
  filterEventPresets: z$1.string().nullable(),
44820
- scheduleScope: eventScheduleScopeSchema$1
44868
+ scheduleScope: eventScheduleScopeSchema$1,
44869
+ calendarContext: z$1.object({
44870
+ timeZone: z$1.string().transform(toBookingTimeZone),
44871
+ initialToday: z$1.object({
44872
+ year: z$1.number().int(),
44873
+ month: z$1.number().int().min(1).max(12),
44874
+ day: z$1.number().int().min(1).max(31)
44875
+ })
44876
+ })
44821
44877
  });
44822
44878
  function buildEventCollectionDisplay(source) {
44823
44879
  return {
@@ -44862,14 +44918,19 @@ function buildEventCollectionPresentationDisplay(source) {
44862
44918
  emptyMessage: source.emptyMessage ?? "No upcoming events scheduled."
44863
44919
  };
44864
44920
  }
44865
- function buildEventCollectionHydration(source) {
44921
+ function buildEventCollectionHydration(source, now = /* @__PURE__ */ new Date()) {
44922
+ const timeZone = toBookingTimeZone(source.bookingTimeZone);
44866
44923
  return {
44867
44924
  siteId: source.siteId,
44868
44925
  stage: source.stage,
44869
44926
  prefetchedEvents: source.events != null,
44870
44927
  eventSurface: normalizeEventSurfaceScope(source.eventSurface),
44871
44928
  filterEventPresets: normalizeEventSurfacePresetsCsv(source.filterEventPresets),
44872
- scheduleScope: normalizeEventScheduleScope(source.scheduleScope)
44929
+ scheduleScope: normalizeEventScheduleScope(source.scheduleScope),
44930
+ calendarContext: {
44931
+ timeZone,
44932
+ initialToday: getLocalScheduleDate(now, timeZone)
44933
+ }
44873
44934
  };
44874
44935
  }
44875
44936
  function buildEventCollectionListingDisplay(display, prefetchedEvents, className) {
@@ -55450,7 +55511,8 @@ function isOrdinaryEvent(event) {
55450
55511
  function deriveWholeSeriesPhase(sessions, nowIso) {
55451
55512
  const now = Date.parse(nowIso);
55452
55513
  if (now < Date.parse(sessions[0].startsAt)) return "upcoming";
55453
- return now <= Date.parse(sessions.at(-1)?.endsAt ?? sessions[0].endsAt) ? "inProgress" : "completed";
55514
+ const finalSession = sessions[sessions.length - 1] ?? sessions[0];
55515
+ return now <= Date.parse(finalSession.endsAt) ? "inProgress" : "completed";
55454
55516
  }
55455
55517
  function selectRelatedDates(input) {
55456
55518
  if (!input.seriesId) return [];
@@ -57549,9 +57611,9 @@ const FULL_DAY_NAMES$1 = [
57549
57611
  * @returns "Monday, January 13"
57550
57612
  */
57551
57613
  function formatAgendaDayHeader(date) {
57552
- const dayName = FULL_DAY_NAMES$1[date.getDay()];
57553
- const monthName = MONTH_NAMES[date.getMonth()];
57554
- return `${dayName ?? "Day"}, ${monthName ?? "Month"} ${date.getDate()}`;
57614
+ const dayName = FULL_DAY_NAMES$1[getDayOfWeek(date)];
57615
+ const monthName = MONTH_NAMES[date.month - 1];
57616
+ return `${dayName ?? "Day"}, ${monthName ?? "Month"} ${date.day}`;
57555
57617
  }
57556
57618
  /**
57557
57619
  * WeekAgendaView Component
@@ -57559,14 +57621,14 @@ function formatAgendaDayHeader(date) {
57559
57621
  * Displays a week of events in an agenda/list style with rich event details.
57560
57622
  * Shows all 7 days with date headers, empty days show "No events scheduled".
57561
57623
  */
57562
- const WeekAgendaView = ({ days, events, showCapacity, emptyMessage = "No events scheduled" }) => {
57563
- const eventsByDate = groupEventsByDate(events);
57624
+ const WeekAgendaView = ({ days, events, showCapacity, emptyMessage = "No events scheduled", calendarTimeZone, today: currentDate }) => {
57625
+ const eventsByDate = groupEventsByDate(events, calendarTimeZone);
57564
57626
  return /* @__PURE__ */ jsx("div", {
57565
57627
  className: "event-agenda-week",
57566
57628
  children: days.map((date) => {
57567
57629
  const dateKey = formatDateKey(date);
57568
57630
  const dayEvents = eventsByDate.get(dateKey) || [];
57569
- const today = isToday(date);
57631
+ const today = isToday(date, currentDate);
57570
57632
  return /* @__PURE__ */ jsxs("div", {
57571
57633
  className: `event-agenda-day ${today ? "event-agenda-day--today" : ""}`,
57572
57634
  children: [/* @__PURE__ */ jsx("div", {
@@ -57595,6 +57657,50 @@ const WeekAgendaView = ({ days, events, showCapacity, emptyMessage = "No events
57595
57657
  })
57596
57658
  });
57597
57659
  };
57660
+ //#endregion
57661
+ //#region ../blocks/src/system/runtime/nodes/events/shared/CalendarNavigationChevron.tsx
57662
+ function CalendarNavigationChevron({ direction }) {
57663
+ return /* @__PURE__ */ jsx("svg", {
57664
+ width: "20",
57665
+ height: "20",
57666
+ fill: "none",
57667
+ stroke: "currentColor",
57668
+ strokeWidth: 2,
57669
+ viewBox: "0 0 24 24",
57670
+ "aria-hidden": "true",
57671
+ children: /* @__PURE__ */ jsx("path", {
57672
+ strokeLinecap: "round",
57673
+ strokeLinejoin: "round",
57674
+ d: direction === "previous" ? "M15 19l-7-7 7-7" : "M9 5l7 7-7 7"
57675
+ })
57676
+ });
57677
+ }
57678
+ //#endregion
57679
+ //#region ../blocks/src/system/runtime/nodes/events/shared/WeekBoardView.tsx
57680
+ function buildWeekBoardNavigationState(viewport, today) {
57681
+ return {
57682
+ rangeLabel: viewport.title,
57683
+ isCurrentWeek: viewport.days.some((day) => isToday(day, today))
57684
+ };
57685
+ }
57686
+ function buildWeekBoardViewProps(display, days, navigation, events = display.events) {
57687
+ return {
57688
+ days,
57689
+ events: [...events],
57690
+ navigation,
57691
+ showCapacity: display.showCapacity,
57692
+ emptyMessage: display.emptyMessage,
57693
+ title: display.boardTitle,
57694
+ footerNote: display.footerNote,
57695
+ ctaLabel: display.loadMoreText ?? display.buttonText,
57696
+ ctaHref: display.seeAllUrl,
57697
+ buttonVariant: display.buttonVariant,
57698
+ elevated: display.elevated,
57699
+ banded: display.banded,
57700
+ calendarTimeZone: display.calendarTimeZone,
57701
+ today: display.today
57702
+ };
57703
+ }
57598
57704
  const SHORT_DAY_NAMES = [
57599
57705
  "Sun",
57600
57706
  "Mon",
@@ -57656,6 +57762,114 @@ const WeekBoardCard = ({ event, showCapacity }) => {
57656
57762
  ]
57657
57763
  });
57658
57764
  };
57765
+ const WeekBoardNavigationControls = ({ navigation, todayClassName }) => {
57766
+ const handlers = navigation.kind === "interactive" ? navigation : {
57767
+ onPrevious: void 0,
57768
+ onNext: void 0,
57769
+ onToday: void 0
57770
+ };
57771
+ const isLoading = navigation.kind === "interactive" && navigation.loadState.kind === "loading";
57772
+ return /* @__PURE__ */ jsxs("nav", {
57773
+ className: "event-week-board-navigation",
57774
+ "aria-label": "Choose week",
57775
+ children: [
57776
+ /* @__PURE__ */ jsx("button", {
57777
+ type: "button",
57778
+ className: "event-week-board-nav-button",
57779
+ "aria-label": "Previous week",
57780
+ onClick: handlers.onPrevious,
57781
+ children: /* @__PURE__ */ jsx(CalendarNavigationChevron, { direction: "previous" })
57782
+ }),
57783
+ /* @__PURE__ */ jsxs("h3", {
57784
+ className: "event-week-board-range",
57785
+ "aria-live": "polite",
57786
+ children: [navigation.rangeLabel, isLoading ? /* @__PURE__ */ jsx("span", {
57787
+ className: "event-week-board-loading",
57788
+ children: " Loading…"
57789
+ }) : null]
57790
+ }),
57791
+ /* @__PURE__ */ jsx("button", {
57792
+ type: "button",
57793
+ className: "event-week-board-nav-button",
57794
+ "aria-label": "Next week",
57795
+ onClick: handlers.onNext,
57796
+ children: /* @__PURE__ */ jsx(CalendarNavigationChevron, { direction: "next" })
57797
+ }),
57798
+ /* @__PURE__ */ jsx("button", {
57799
+ type: "button",
57800
+ className: todayClassName,
57801
+ disabled: navigation.isCurrentWeek,
57802
+ onClick: handlers.onToday,
57803
+ children: "Today"
57804
+ })
57805
+ ]
57806
+ });
57807
+ };
57808
+ const WeekBoardLegend = () => /* @__PURE__ */ jsx("div", {
57809
+ className: "event-week-board-legend",
57810
+ "aria-hidden": "true",
57811
+ children: LEGEND_ITEMS.map((item) => /* @__PURE__ */ jsxs("span", {
57812
+ className: "event-week-board-legend-item",
57813
+ children: [/* @__PURE__ */ jsx("i", {
57814
+ className: "event-week-board-legend-dot",
57815
+ "data-status": item.status
57816
+ }), item.label]
57817
+ }, item.status))
57818
+ });
57819
+ const WeekBoardLoadError = ({ navigation, buttonClassName }) => {
57820
+ if (navigation.kind !== "interactive" || navigation.loadState.kind !== "error") return null;
57821
+ return /* @__PURE__ */ jsxs("div", {
57822
+ className: "event-week-board-error",
57823
+ role: "status",
57824
+ children: [/* @__PURE__ */ jsx("p", { children: "Failed to load events" }), /* @__PURE__ */ jsx("button", {
57825
+ type: "button",
57826
+ className: buttonClassName,
57827
+ onClick: navigation.loadState.onRetry,
57828
+ children: "Try again"
57829
+ })]
57830
+ });
57831
+ };
57832
+ const WeekBoardGrid = ({ days, eventsByDate, showCapacity, today: currentDate }) => /* @__PURE__ */ jsx("div", {
57833
+ className: "event-week-board-grid",
57834
+ children: days.map((date) => {
57835
+ const dateKey = formatDateKey(date);
57836
+ const dayEvents = eventsByDate.get(dateKey) ?? [];
57837
+ const today = isToday(date, currentDate);
57838
+ return /* @__PURE__ */ jsxs("div", {
57839
+ className: clsx("event-week-board-day", dayEvents.length === 0 && "event-week-board-day--empty", today && "event-week-board-day--today"),
57840
+ children: [/* @__PURE__ */ jsxs("div", {
57841
+ className: "event-week-board-day-head",
57842
+ children: [/* @__PURE__ */ jsx("span", {
57843
+ className: "event-week-board-day-abbr",
57844
+ children: SHORT_DAY_NAMES[getDayOfWeek(date)]
57845
+ }), /* @__PURE__ */ jsx("span", {
57846
+ className: "event-week-board-day-num",
57847
+ children: date.day
57848
+ })]
57849
+ }), /* @__PURE__ */ jsx("div", {
57850
+ className: "event-week-board-day-body",
57851
+ children: dayEvents.map((event) => /* @__PURE__ */ jsx(WeekBoardCard, {
57852
+ event,
57853
+ showCapacity
57854
+ }, event.occurrenceId || event.id))
57855
+ })]
57856
+ }, dateKey);
57857
+ })
57858
+ });
57859
+ const WeekBoardFooter = ({ note, ctaHref, ctaLabel, ctaClassName }) => {
57860
+ if (note === null && ctaHref === null) return null;
57861
+ return /* @__PURE__ */ jsxs("div", {
57862
+ className: "event-week-board-foot",
57863
+ children: [note === null ? null : /* @__PURE__ */ jsx("p", {
57864
+ className: "event-week-board-foot-note",
57865
+ children: note
57866
+ }), ctaHref === null ? null : /* @__PURE__ */ jsx("a", {
57867
+ className: ctaClassName,
57868
+ href: ctaHref,
57869
+ children: ctaLabel
57870
+ })]
57871
+ });
57872
+ };
57659
57873
  /**
57660
57874
  * WeekBoardView
57661
57875
  *
@@ -57664,18 +57878,21 @@ const WeekBoardCard = ({ event, showCapacity }) => {
57664
57878
  * to a stacked list on mobile. Repurposes the week-grouped agenda data as a
57665
57879
  * board rather than an hour-positioned timetable grid.
57666
57880
  */
57667
- 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 }) => {
57668
- const eventsByDate = groupEventsByDate(events);
57881
+ 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 }) => {
57882
+ const eventsByDate = groupEventsByDate(events, calendarTimeZone);
57669
57883
  const hasAnyEvents = days.some((date) => (eventsByDate.get(formatDateKey(date)) ?? []).length > 0);
57670
57884
  const ctaClassName = themeButtonClassName({
57671
57885
  variant: buttonVariant,
57672
57886
  size: "sm"
57673
57887
  });
57888
+ const todayClassName = themeButtonClassName({
57889
+ variant: buttonVariant,
57890
+ size: "sm"
57891
+ });
57674
57892
  const hasTitle = typeof title === "string" && title.length > 0;
57675
57893
  const hasFooterNote = typeof footerNote === "string" && footerNote.length > 0;
57676
- const hasCta = typeof ctaHref === "string" && ctaHref.length > 0;
57677
57894
  const footerNoteText = hasAnyEvents ? hasFooterNote ? footerNote : null : emptyMessage;
57678
- const showFooter = hasCta || footerNoteText !== null;
57895
+ const resolvedCtaHref = typeof ctaHref === "string" && ctaHref.length > 0 ? ctaHref : null;
57679
57896
  return /* @__PURE__ */ jsx("div", {
57680
57897
  className: "event-calendar event-calendar--week-board",
57681
57898
  "data-block": "event-calendar",
@@ -57687,59 +57904,34 @@ const WeekBoardView = ({ days, events, showCapacity, emptyMessage = "No classes
57687
57904
  children: [
57688
57905
  /* @__PURE__ */ jsxs("div", {
57689
57906
  className: "event-week-board-top",
57690
- children: [hasTitle ? /* @__PURE__ */ jsx("span", {
57691
- className: "event-week-board-title",
57692
- children: title
57693
- }) : null, /* @__PURE__ */ jsx("div", {
57694
- className: "event-week-board-legend",
57695
- "aria-hidden": "true",
57696
- children: LEGEND_ITEMS.map((item) => /* @__PURE__ */ jsxs("span", {
57697
- className: "event-week-board-legend-item",
57698
- children: [/* @__PURE__ */ jsx("i", {
57699
- className: "event-week-board-legend-dot",
57700
- "data-status": item.status
57701
- }), item.label]
57702
- }, item.status))
57703
- })]
57907
+ children: [
57908
+ hasTitle ? /* @__PURE__ */ jsx("span", {
57909
+ className: "event-week-board-title",
57910
+ children: title
57911
+ }) : null,
57912
+ /* @__PURE__ */ jsx(WeekBoardNavigationControls, {
57913
+ navigation,
57914
+ todayClassName
57915
+ }),
57916
+ /* @__PURE__ */ jsx(WeekBoardLegend, {})
57917
+ ]
57704
57918
  }),
57705
- /* @__PURE__ */ jsx("div", {
57706
- className: "event-week-board-grid",
57707
- children: days.map((date) => {
57708
- const dateKey = formatDateKey(date);
57709
- const dayEvents = eventsByDate.get(dateKey) ?? [];
57710
- const today = isToday(date);
57711
- return /* @__PURE__ */ jsxs("div", {
57712
- className: clsx("event-week-board-day", dayEvents.length === 0 && "event-week-board-day--empty", today && "event-week-board-day--today"),
57713
- children: [/* @__PURE__ */ jsxs("div", {
57714
- className: "event-week-board-day-head",
57715
- children: [/* @__PURE__ */ jsx("span", {
57716
- className: "event-week-board-day-abbr",
57717
- children: SHORT_DAY_NAMES[date.getDay()]
57718
- }), /* @__PURE__ */ jsx("span", {
57719
- className: "event-week-board-day-num",
57720
- children: date.getDate()
57721
- })]
57722
- }), /* @__PURE__ */ jsx("div", {
57723
- className: "event-week-board-day-body",
57724
- children: dayEvents.map((event) => /* @__PURE__ */ jsx(WeekBoardCard, {
57725
- event,
57726
- showCapacity
57727
- }, event.occurrenceId || event.id))
57728
- })]
57729
- }, dateKey);
57730
- })
57919
+ /* @__PURE__ */ jsx(WeekBoardLoadError, {
57920
+ navigation,
57921
+ buttonClassName: todayClassName
57731
57922
  }),
57732
- showFooter ? /* @__PURE__ */ jsxs("div", {
57733
- className: "event-week-board-foot",
57734
- children: [footerNoteText !== null ? /* @__PURE__ */ jsx("p", {
57735
- className: "event-week-board-foot-note",
57736
- children: footerNoteText
57737
- }) : null, hasCta ? /* @__PURE__ */ jsx("a", {
57738
- className: ctaClassName,
57739
- href: ctaHref ?? void 0,
57740
- children: ctaLabel
57741
- }) : null]
57742
- }) : null
57923
+ /* @__PURE__ */ jsx(WeekBoardGrid, {
57924
+ days,
57925
+ eventsByDate,
57926
+ showCapacity,
57927
+ today
57928
+ }),
57929
+ /* @__PURE__ */ jsx(WeekBoardFooter, {
57930
+ note: footerNoteText,
57931
+ ctaHref: resolvedCtaHref,
57932
+ ctaLabel,
57933
+ ctaClassName
57934
+ })
57743
57935
  ]
57744
57936
  })
57745
57937
  });
@@ -57770,6 +57962,7 @@ function buildTimetableModel(input) {
57770
57962
  items: input.events,
57771
57963
  viewDate: input.viewDate,
57772
57964
  startOfWeek: input.startOfWeek,
57965
+ today: input.today,
57773
57966
  getId: (event) => event.id,
57774
57967
  getStartsAt: (event) => event.startsAt,
57775
57968
  getEndsAt: (event) => event.endsAt,
@@ -57831,10 +58024,10 @@ function formatEventTimeRange(event) {
57831
58024
  return `${formatTime(event.startsAt, { timeZone })} - ${formatTime(event.endsAt, { timeZone })}`;
57832
58025
  }
57833
58026
  function formatDayLabel(date) {
57834
- return `${FULL_DAY_NAMES[date.getDay()] ?? ""}, ${MONTH_NAMES[date.getMonth()] ?? ""} ${date.getDate()}`;
58027
+ return `${FULL_DAY_NAMES[getDayOfWeek(date)] ?? ""}, ${MONTH_NAMES[date.month - 1] ?? ""} ${date.day}`;
57835
58028
  }
57836
58029
  function formatShortDayLabel(date) {
57837
- return `${(FULL_DAY_NAMES[date.getDay()] ?? "").slice(0, 3)} ${date.getDate()}`;
58030
+ return `${(FULL_DAY_NAMES[getDayOfWeek(date)] ?? "").slice(0, 3)} ${date.day}`;
57838
58031
  }
57839
58032
  //#endregion
57840
58033
  //#region ../blocks/src/system/runtime/nodes/events/EventCalendar.server.tsx
@@ -57881,15 +58074,15 @@ function renderListSsr(display, prefetchedEvents) {
57881
58074
  renderEventCard: (event) => renderEventCard(event, listDisplay)
57882
58075
  });
57883
58076
  }
57884
- function renderCalendarSsr(display) {
58077
+ function renderCalendarSsr(display, hydration) {
57885
58078
  const calendarView = display.defaultCalendarView;
57886
- const viewDate = /* @__PURE__ */ new Date();
58079
+ const viewDate = hydration.calendarContext.initialToday;
57887
58080
  const viewport = buildCalendarViewport({
57888
58081
  view: calendarView,
57889
58082
  anchorDate: viewDate,
57890
58083
  startOfWeek: display.startOfWeek
57891
58084
  });
57892
- const eventsByDate = groupEventsByDate([...display.events]);
58085
+ const eventsByDate = groupEventsByDate([...display.events], hydration.calendarContext.timeZone);
57893
58086
  const dayNames = getOrderedDayNames(display.startOfWeek);
57894
58087
  return /* @__PURE__ */ jsxs("div", {
57895
58088
  className: clsx("event-calendar", display.className ?? void 0),
@@ -57956,7 +58149,9 @@ function renderCalendarSsr(display) {
57956
58149
  days: viewport.days,
57957
58150
  events: [...display.events],
57958
58151
  emptyMessage: display.emptyMessage,
57959
- showCapacity: display.showCapacity
58152
+ showCapacity: display.showCapacity,
58153
+ calendarTimeZone: hydration.calendarContext.timeZone,
58154
+ today: hydration.calendarContext.initialToday
57960
58155
  }) : /* @__PURE__ */ jsxs("div", {
57961
58156
  className: "event-calendar-container",
57962
58157
  children: [/* @__PURE__ */ jsx("div", {
@@ -57970,13 +58165,13 @@ function renderCalendarSsr(display) {
57970
58165
  children: viewport.days.map((date) => {
57971
58166
  const dateKey = formatDateKey(date);
57972
58167
  const dayEvents = eventsByDate.get(dateKey) || [];
57973
- const isCurrentMonth = date.getMonth() === viewDate.getMonth();
57974
- const today = isToday(date);
58168
+ const isCurrentMonth = date.month === viewDate.month;
58169
+ const today = isToday(date, hydration.calendarContext.initialToday);
57975
58170
  return /* @__PURE__ */ jsxs("div", {
57976
58171
  className: clsx("event-calendar-day", !isCurrentMonth && "event-calendar-day--other-month", today && "event-calendar-day--today"),
57977
58172
  children: [/* @__PURE__ */ jsx("div", {
57978
58173
  className: "event-calendar-day-number",
57979
- children: date.getDate()
58174
+ children: date.day
57980
58175
  }), /* @__PURE__ */ jsxs("div", {
57981
58176
  className: "event-calendar-events",
57982
58177
  children: [dayEvents.slice(0, 3).map((event) => /* @__PURE__ */ jsxs("a", {
@@ -58014,8 +58209,8 @@ function renderCalendarSsr(display) {
58014
58209
  ]
58015
58210
  });
58016
58211
  }
58017
- function renderTimetableSsr(display) {
58018
- const viewDate = /* @__PURE__ */ new Date();
58212
+ function renderTimetableSsr(display, hydration) {
58213
+ const viewDate = hydration.calendarContext.initialToday;
58019
58214
  const viewport = buildCalendarViewport({
58020
58215
  view: "week",
58021
58216
  anchorDate: viewDate,
@@ -58024,7 +58219,8 @@ function renderTimetableSsr(display) {
58024
58219
  const model = buildTimetableModel({
58025
58220
  events: [...display.events],
58026
58221
  viewDate,
58027
- startOfWeek: display.startOfWeek
58222
+ startOfWeek: display.startOfWeek,
58223
+ today: hydration.calendarContext.initialToday
58028
58224
  });
58029
58225
  const selectedDayKey = model.days.find((day) => day.isToday)?.dateKey ?? model.days[0]?.dateKey ?? "";
58030
58226
  return /* @__PURE__ */ jsxs("div", {
@@ -58179,20 +58375,21 @@ function renderTimetableSsr(display) {
58179
58375
  })]
58180
58376
  });
58181
58377
  }
58182
- function renderWeekBoardSsr(display) {
58183
- return /* @__PURE__ */ jsx(WeekBoardView, {
58184
- days: getWeekCalendarDayTuple(/* @__PURE__ */ new Date(), display.startOfWeek),
58185
- events: [...display.events],
58186
- showCapacity: display.showCapacity,
58187
- emptyMessage: display.emptyMessage,
58188
- title: display.boardTitle,
58189
- footerNote: display.footerNote,
58190
- ctaLabel: display.loadMoreText ?? display.buttonText,
58191
- ctaHref: display.seeAllUrl,
58192
- buttonVariant: display.buttonVariant,
58193
- elevated: display.elevated,
58194
- banded: display.banded
58195
- });
58378
+ function renderWeekBoardSsr(display, hydration) {
58379
+ const today = hydration.calendarContext.initialToday;
58380
+ const days = getWeekCalendarDayTuple(today, display.startOfWeek);
58381
+ const navigation = {
58382
+ kind: "static",
58383
+ ...buildWeekBoardNavigationState({
58384
+ days,
58385
+ title: formatCalendarTitle(today, "week", [...days])
58386
+ }, today)
58387
+ };
58388
+ return /* @__PURE__ */ jsx(WeekBoardView, { ...buildWeekBoardViewProps({
58389
+ ...display,
58390
+ calendarTimeZone: hydration.calendarContext.timeZone,
58391
+ today
58392
+ }, days, navigation) });
58196
58393
  }
58197
58394
  function formatHourLabel(hour) {
58198
58395
  if (hour === 0) return "12 AM";
@@ -58218,13 +58415,13 @@ const EventCalendarSSR = (props) => {
58218
58415
  content = renderListSsr(display, hydration.prefetchedEvents);
58219
58416
  break;
58220
58417
  case "timetable":
58221
- content = renderTimetableSsr(display);
58418
+ content = renderTimetableSsr(display, hydration);
58222
58419
  break;
58223
58420
  case "week-board":
58224
- content = renderWeekBoardSsr(display);
58421
+ content = renderWeekBoardSsr(display, hydration);
58225
58422
  break;
58226
58423
  case "calendar":
58227
- content = renderCalendarSsr(display);
58424
+ content = renderCalendarSsr(display, hydration);
58228
58425
  break;
58229
58426
  default: content = assertNeverDisplayMode(display.displayMode);
58230
58427
  }
@@ -61414,36 +61611,9 @@ function buildLegacyHeaderNavLinkStyle(header, contrastTreatment, navTextSize) {
61414
61611
  ...navTextSize ? { textSize: navTextSize } : {}
61415
61612
  };
61416
61613
  if (header.navWeight === "bold" && navStyle === "solid") style.textTransform = "uppercase";
61417
- applyLegacyNavEffects(style, header);
61418
61614
  applyLegacyGlassTreatment(style, header, navStyle);
61419
61615
  return style;
61420
61616
  }
61421
- function applyLegacyNavEffects(style, header) {
61422
- if (!header.navEffects) return;
61423
- const effects = style.effects = {
61424
- ...style.effects,
61425
- hover: [...style.effects?.hover ?? []],
61426
- active: [...style.effects?.active ?? []]
61427
- };
61428
- if (header.navEffects.glow) effects.hover.push({
61429
- effectId: "outer-glow",
61430
- options: { spread: 5 }
61431
- });
61432
- if (header.navEffects.neumorphic) {
61433
- effects.hover.push({
61434
- effectId: "neumorphic-shadow",
61435
- options: { mode: "pressed" }
61436
- });
61437
- effects.hover.push({
61438
- effectId: "text-color-change",
61439
- options: { hoverColorToken: "primary" }
61440
- });
61441
- }
61442
- if (header.navEffects.underlineGradient) effects.hover.push({
61443
- effectId: "border-bottom-grow",
61444
- options: { origin: "center" }
61445
- });
61446
- }
61447
61617
  function applyLegacyGlassTreatment(style, header, navStyle) {
61448
61618
  if (header.navContainer?.type !== "glass" || navStyle !== "minimal") return;
61449
61619
  style.borderRadius = "full";
@@ -61469,19 +61639,6 @@ function glassStateEffects(opacity) {
61469
61639
  //#region ../theme-core/src/header/generateHeaderCss.ts
61470
61640
  const HEADER_BLUR = "blur(12px)";
61471
61641
  const FLOATING_BLUR = "blur(16px)";
61472
- const INSET_SHELL_MARKER_CLASS = "header-bar-frame-inset-shell";
61473
- const INSET_SHELL_EDGE = "1rem";
61474
- const INSET_SHELL_INSET_BLOCK = "0.875rem";
61475
- const INSET_SHELL_RADIUS = "9999px";
61476
- const INSET_SHELL_CONTAINER_MAX = "80rem";
61477
- const INSET_SHELL_INTERIOR_PADDING_X = "1.75rem";
61478
- /**
61479
- * Whether the classic header should render as an inset "brand capsule" shell.
61480
- * The facet is only meaningful for the classic layout; other variants ignore it.
61481
- */
61482
- function usesInsetShell(header) {
61483
- return header.barFrame === "inset-shell" && header.variant === "classic";
61484
- }
61485
61642
  /**
61486
61643
  * Generate complete CSS for header system from theme config
61487
61644
  *
@@ -61559,36 +61716,7 @@ function generateHeaderRootStyles(header, themeId, tokens) {
61559
61716
  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`;
61560
61717
  const scrollTreatmentStyles = generateHeaderScrollTreatmentStyles(header.scrollTreatment, themeId, header.variant, scrolledPaintRules);
61561
61718
  if (isContainedNav || basePaintRules.length === 0) return `${baseBlock}\n${overlayFix}${scrollTreatmentStyles}`;
61562
- return `${baseBlock}\n${renderHeaderPaintTargetRules(getHeaderPaintTargets(header.variant, themeId), basePaintRules)}\n${overlayFix}${usesInsetShell(header) ? generateInsetShellStyles(header, themeId) : ""}${scrollTreatmentStyles}`;
61563
- }
61564
- /**
61565
- * Reshapes the full-bleed header paint layer into a contained brand capsule at
61566
- * the desktop breakpoint. The capsule is centred, capped to the page container
61567
- * width, inset from the top, fully rounded, and carries the header depth so it
61568
- * reads as a floating pill. Root border/shadow are neutralised on desktop so a
61569
- * bordered style does not leave a full-width hairline around the capsule. Sticky
61570
- * positioning is unaffected — the root stays full width and sticky while the
61571
- * ::before paint provides the capsule.
61572
- */
61573
- function generateInsetShellStyles(header, themeId) {
61574
- const scope = `:where([data-theme-scope="${themeId}"])`;
61575
- const shellRootSelector = `${scope} .header-root.${INSET_SHELL_MARKER_CLASS}`;
61576
- const shellBeforeSelector = `${scope} .header-root.${INSET_SHELL_MARKER_CLASS}::before`;
61577
- const layoutSelector = `${scope} .header-root.${INSET_SHELL_MARKER_CLASS} .rb-header-layout`;
61578
- const widthValue = header.maxWidth === "full" ? `calc(100% - (${INSET_SHELL_EDGE} * 2))` : `min(${INSET_SHELL_CONTAINER_MAX}, calc(100% - (${INSET_SHELL_EDGE} * 2)))`;
61579
- const shadowVar = getComponentShadowVar(header.shadow?.elevation ?? "none");
61580
- const rootRules = ["border: none;", "box-shadow: none;"];
61581
- const beforeRules = [
61582
- `inset: ${INSET_SHELL_INSET_BLOCK} auto;`,
61583
- "left: 50%;",
61584
- "right: auto;",
61585
- "transform: translateX(-50%);",
61586
- `width: ${widthValue};`,
61587
- `border-radius: ${INSET_SHELL_RADIUS};`,
61588
- ...shadowVar ? [`box-shadow: ${shadowVar};`] : []
61589
- ];
61590
- const layoutRules = [`padding-inline: ${INSET_SHELL_INTERIOR_PADDING_X};`];
61591
- 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`;
61719
+ return `${baseBlock}\n${renderHeaderPaintTargetRules(getHeaderPaintTargets(header.variant, themeId), basePaintRules)}\n${overlayFix}${scrollTreatmentStyles}`;
61592
61720
  }
61593
61721
  /**
61594
61722
  * Generate logo typography styles
@@ -61662,7 +61790,7 @@ function generateLogoTextBehaviorStyles(logoText, themeId) {
61662
61790
  * Generate navigation link styles based on navStyle and effects
61663
61791
  *
61664
61792
  * Uses the composable NavLinkStyle system with backward compatibility for
61665
- * legacy navStyle, navWeight, navColor, and navEffects settings.
61793
+ * legacy navStyle, navWeight and navColor settings.
61666
61794
  */
61667
61795
  function generateNavLinkStyles(header, themeId, tokens, theme, contrastTreatment, navTextSize) {
61668
61796
  const navPreferences = {
@@ -64299,9 +64427,43 @@ function pageBlockPosition(index, blockCount) {
64299
64427
  return "middle";
64300
64428
  }
64301
64429
  //#endregion
64430
+ //#region ../blocks/src/pageRenderAdmission.ts
64431
+ function toPresentationPage(page) {
64432
+ if (!page) return null;
64433
+ return {
64434
+ ...page,
64435
+ blocks: page.blocks.map((block) => {
64436
+ const presentationMetadata = {
64437
+ id: block.id,
64438
+ kind: block.kind,
64439
+ purpose: block.purpose,
64440
+ ...block.bindings ? { bindings: block.bindings } : {}
64441
+ };
64442
+ return block.admission.kind === "renderable" ? {
64443
+ ...presentationMetadata,
64444
+ content: block.admission.content,
64445
+ presentationAdmission: { kind: "renderable" }
64446
+ } : {
64447
+ ...presentationMetadata,
64448
+ presentationAdmission: {
64449
+ kind: "invalid",
64450
+ error: block.admission.error
64451
+ }
64452
+ };
64453
+ })
64454
+ };
64455
+ }
64456
+ //#endregion
64302
64457
  //#region ../blocks/src/PageRenderer.tsx
64303
64458
  function PageRenderer$1(props) {
64304
- const { page, runtimeBoundaries, usePlaceholders = false, dataContext, wrapBlock, wrapBoundary, registry, routeMap, blockOverrides, sdkConfig, customBlocks, previewAuthoring } = props;
64459
+ const page = React$1.useMemo(() => toPresentationPage(props.page), [props.page]);
64460
+ return /* @__PURE__ */ jsx(PageRendererCore, {
64461
+ ...props,
64462
+ page
64463
+ });
64464
+ }
64465
+ function PageRendererCore(props) {
64466
+ const { page, runtimeBoundaries, dataContext, wrapBlock, wrapBoundary, registry } = props;
64305
64467
  const imageResolveContext = React$1.useMemo(() => resolvePageRendererImageResolveContext(dataContext), [
64306
64468
  dataContext?.imageResolveContext,
64307
64469
  dataContext?.mediaAssets,
@@ -64400,11 +64562,11 @@ function resolvePageRendererImageResolveContext(dataContext) {
64400
64562
  mediaAssets: input?.mediaAssets ?? dataContext?.mediaAssets
64401
64563
  });
64402
64564
  }
64565
+ const resolveBookingTimeZone = (dataContext) => dataContext?.bookingTimeZone;
64403
64566
  function buildBlockSectionProps(input) {
64404
64567
  return {
64405
64568
  themeResources: input.themeResources,
64406
64569
  block: input.block,
64407
- usePlaceholders: input.props.usePlaceholders ?? false,
64408
64570
  dataContext: input.props.dataContext,
64409
64571
  blockKey: input.blockKey,
64410
64572
  registry: input.registry,
@@ -64428,7 +64590,6 @@ function getBlockOverride(blockKind, overrides) {
64428
64590
  if (overrides[shortKind]) return overrides[shortKind];
64429
64591
  }
64430
64592
  const blockComponentCache = /* @__PURE__ */ new WeakMap();
64431
- const manifestValidatorCache = /* @__PURE__ */ new WeakMap();
64432
64593
  const DEFAULT_PERF_SLOW_BLOCK_RENDER_THRESHOLD_MS = 25;
64433
64594
  let cachedPerfSlowBlockRenderThresholdMs = null;
64434
64595
  function getPerfSlowBlockRenderThresholdMs() {
@@ -64446,44 +64607,13 @@ function getCachedBlockComponent(manifest) {
64446
64607
  return created;
64447
64608
  }
64448
64609
  /**
64449
- * Render-time manifest validator — see `.claude/plans/dapper-jingling-emerson.md`
64450
- * Phase 10. One function, two flavours:
64451
- *
64452
- * - `strict` (default): the contract every render surface tries first. No
64453
- * null tolerance, no missing-required tolerance. Production frontends and
64454
- * the dashboard preview both go through this path; after Phases 6-9 the
64455
- * preview satisfies strict structurally.
64456
- * - `relaxed`: editor-mid-edit fallback. Reached via `usePlaceholders` when
64457
- * strict fails. Built on `mode: 'draft'` so empty required fields parse
64458
- * as `undefined` and the user's valid in-flight fields flow through.
64459
- *
64460
- * Per-manifest, per-flavour cached. Adding a third flavour means adding a
64461
- * branch to the `createManifestValidator` call below and a member to
64462
- * `ValidationFlavour` — no per-flavour helper duplication.
64463
- */
64464
- function getCachedValidator(manifest, flavour) {
64465
- let perFlavour = manifestValidatorCache.get(manifest);
64466
- if (!perFlavour) {
64467
- perFlavour = /* @__PURE__ */ new Map();
64468
- manifestValidatorCache.set(manifest, perFlavour);
64469
- }
64470
- const cached = perFlavour.get(flavour);
64471
- if (cached) return cached;
64472
- const created = createManifestValidator(manifest, {
64473
- allowNull: false,
64474
- ...flavour === "relaxed" ? { mode: "draft" } : {}
64475
- });
64476
- perFlavour.set(flavour, created);
64477
- return created;
64478
- }
64479
- /**
64480
64610
  * Memoized block section component.
64481
64611
  *
64482
64612
  * Custom memoization prevents render loops during editing by explicitly checking
64483
64613
  * referential equality of all props that affect rendering. Standard React.memo
64484
64614
  * wouldn't catch all the render triggers from the editor store.
64485
64615
  */
64486
- const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeResources, block, usePlaceholders, dataContext, registry, routeMap, wrapBlock, blockOverrides, sdkConfig, customBlocks, imageResolveContext, previewAuthoring }) {
64616
+ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeResources, block, dataContext, registry, routeMap, wrapBlock, blockOverrides, sdkConfig, customBlocks, imageResolveContext, previewAuthoring }) {
64487
64617
  const perfStart = globalThis.process?.env?.DEBUG_PERF === "1" && typeof window === "undefined" ? Date.now() : 0;
64488
64618
  const fallbackImageResolveContext = getCurrentResolveImageUrlContext();
64489
64619
  const resolvedImageResolveContext = imageResolveContext ?? fallbackImageResolveContext;
@@ -64503,6 +64633,19 @@ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeResources
64503
64633
  } catch {}
64504
64634
  return node;
64505
64635
  }
64636
+ if (block.presentationAdmission.kind === "invalid") {
64637
+ try {
64638
+ if (globalThis.process?.env?.NODE_ENV !== "production") console.warn("[blocks:PageRenderer] block admission failed", {
64639
+ blockId: block.id ?? null,
64640
+ blockKind: block.kind,
64641
+ error: block.presentationAdmission.error
64642
+ });
64643
+ } catch {}
64644
+ return finish(fallback(`Invalid content for block kind "${block.kind}".`), {
64645
+ outcome: "invalidContent",
64646
+ override: false
64647
+ });
64648
+ }
64506
64649
  const OverrideComponent = getBlockOverride(block.kind, blockOverrides);
64507
64650
  requireBlockOverride(themeResources, OverrideComponent, block.kind);
64508
64651
  let definition = getBlockDefinition(block.kind);
@@ -64572,25 +64715,10 @@ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeResources
64572
64715
  });
64573
64716
  }
64574
64717
  const content = getRenderableContent(block, dataContext?.previewStage);
64575
- const parsed = getCachedValidator(definition.manifest, "strict").safeParse(content);
64576
- try {
64577
- if (globalThis.process?.env?.NODE_ENV !== "production" && !parsed.success && !usePlaceholders) console.warn("[blocks:PageRenderer] manifest validation failed", {
64578
- blockId: block.id ?? null,
64579
- blockKind: block.kind,
64580
- content: summarizeValue(content),
64581
- expectedFields: (definition.manifest.fields ?? []).map((f) => ({
64582
- id: f.id,
64583
- type: f.type,
64584
- required: !!f.required
64585
- })),
64586
- issues: parsed.error?.issues ?? null
64587
- });
64588
- } catch {}
64589
- let data;
64590
- if (parsed.success) data = parsed.data;
64591
- else if (usePlaceholders) {
64592
- const relaxed = getCachedValidator(definition.manifest, "relaxed").safeParse(content);
64593
- if (relaxed.success) data = relaxed.data;
64718
+ let data = content;
64719
+ if (block.presentationAdmission.kind === "editor") {
64720
+ const draft = validateManifestDraft(compileManifestContentContract(definition.manifest), content);
64721
+ if (draft.kind === "previewable") data = draft.data;
64594
64722
  else {
64595
64723
  const rendered = fallback(`Unable to render block kind "${block.kind}".`);
64596
64724
  return finish(wrapBlock && block.id ? /* @__PURE__ */ jsx(Fragment, { children: wrapBlock(block.id, rendered) }) : /* @__PURE__ */ jsx(Fragment, { children: rendered }), {
@@ -64598,12 +64726,6 @@ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeResources
64598
64726
  override: false
64599
64727
  });
64600
64728
  }
64601
- } else {
64602
- const rendered = fallback(`Invalid content for block kind "${block.kind}".`);
64603
- return finish(wrapBlock && block.id ? /* @__PURE__ */ jsx(Fragment, { children: wrapBlock(block.id, rendered) }) : /* @__PURE__ */ jsx(Fragment, { children: rendered }), {
64604
- outcome: "invalidContent",
64605
- override: false
64606
- });
64607
64729
  }
64608
64730
  try {
64609
64731
  const routes = routeMap ?? dataContext?.routes;
@@ -64629,6 +64751,7 @@ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeResources
64629
64751
  blockId: block.id ?? null,
64630
64752
  blockKind: block.kind
64631
64753
  };
64754
+ baseProps.bookingTimeZone = resolveBookingTimeZone(dataContext);
64632
64755
  let rendered;
64633
64756
  if (OverrideComponent) rendered = /* @__PURE__ */ jsx(OverrideComponent, { ...baseProps });
64634
64757
  else {
@@ -64675,14 +64798,14 @@ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeResources
64675
64798
  hasResolvedData
64676
64799
  });
64677
64800
  } catch {
64678
- const rendered = usePlaceholders ? fallback(`Unable to render block kind "${block.kind}".`) : fallback(`Invalid content for block kind "${block.kind}".`);
64801
+ const rendered = block.presentationAdmission.kind === "editor" ? fallback(`Unable to render block kind "${block.kind}".`) : fallback(`Invalid content for block kind "${block.kind}".`);
64679
64802
  return finish(wrapBlock && block.id ? /* @__PURE__ */ jsx(Fragment, { children: wrapBlock(block.id, rendered) }) : /* @__PURE__ */ jsx(Fragment, { children: rendered }), {
64680
64803
  outcome: "exception",
64681
64804
  override: false
64682
64805
  });
64683
64806
  }
64684
64807
  }, (prev, next) => {
64685
- 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;
64808
+ 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;
64686
64809
  });
64687
64810
  function fallback(message) {
64688
64811
  return /* @__PURE__ */ jsx("div", {
@@ -64709,32 +64832,6 @@ function getRenderableContent(block, previewStage = "published") {
64709
64832
  if (!isObjectRecord$1(source)) return {};
64710
64833
  return source;
64711
64834
  }
64712
- function summarizeValue(value) {
64713
- try {
64714
- if (value === null || value === void 0) return value;
64715
- if (typeof value === "string") return value.length > 160 ? `${value.slice(0, 160)}…` : value;
64716
- if (typeof value === "number" || typeof value === "boolean") return value;
64717
- if (Array.isArray(value)) return `[array(${value.length})]`;
64718
- if (typeof value === "object") {
64719
- const rec = value;
64720
- const keys = Object.keys(rec);
64721
- const preview = {};
64722
- for (const k of keys.slice(0, 8)) {
64723
- const v = rec[k];
64724
- if (k === "body" || k === "content") preview[k] = !!(v && typeof v === "object" && isObjectRecord$1(v) && v.type === "doc") ? "{type:doc}" : summarizeValue(v);
64725
- else preview[k] = summarizeValue(v);
64726
- }
64727
- return {
64728
- keys,
64729
- preview
64730
- };
64731
- }
64732
- if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint" || typeof value === "symbol") return String(value);
64733
- return "[uninspectable]";
64734
- } catch {
64735
- return "[uninspectable]";
64736
- }
64737
- }
64738
64835
  //#endregion
64739
64836
  //#region ../blocks/src/structure/schema.ts
64740
64837
  const BlockKind = z.string();
@@ -72379,31 +72476,37 @@ const containerResponsiveThemeCss = `/*
72379
72476
  */
72380
72477
 
72381
72478
  /* Main container */
72382
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar {
72479
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-calendar {
72383
72480
  width: 100%;
72384
72481
  }
72385
72482
 
72386
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-container {
72483
+ :where(.theme-scope)
72484
+ :where([data-block='event-calendar'])
72485
+ .event-calendar-container {
72387
72486
  border: 1px solid var(--ec-border);
72388
72487
  border-radius: var(--rb-block-radius);
72389
72488
  overflow: hidden;
72390
72489
  }
72391
72490
 
72392
72491
  /* Calendar navigation */
72393
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-header {
72492
+ :where(.theme-scope)
72493
+ :where([data-block='event-calendar'])
72494
+ .event-calendar-header {
72394
72495
  display: flex;
72395
72496
  align-items: center;
72396
72497
  justify-content: space-between;
72397
72498
  margin-bottom: 1rem;
72398
72499
  }
72399
72500
 
72400
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-nav {
72501
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-calendar-nav {
72401
72502
  display: flex;
72402
72503
  align-items: center;
72403
72504
  gap: 0.5rem;
72404
72505
  }
72405
72506
 
72406
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-nav-btn {
72507
+ :where(.theme-scope)
72508
+ :where([data-block='event-calendar'])
72509
+ .event-calendar-nav-btn {
72407
72510
  display: flex;
72408
72511
  align-items: center;
72409
72512
  justify-content: center;
@@ -72418,11 +72521,15 @@ const containerResponsiveThemeCss = `/*
72418
72521
  transition: background-color var(--rb-block-transition) ease;
72419
72522
  }
72420
72523
 
72421
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-nav-btn:hover {
72524
+ :where(.theme-scope)
72525
+ :where([data-block='event-calendar'])
72526
+ .event-calendar-nav-btn:hover {
72422
72527
  background-color: var(--ec-nav-hover-bg);
72423
72528
  }
72424
72529
 
72425
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-title {
72530
+ :where(.theme-scope)
72531
+ :where([data-block='event-calendar'])
72532
+ .event-calendar-title {
72426
72533
  font-size: 1.125rem;
72427
72534
  font-weight: 600;
72428
72535
  min-width: 200px;
@@ -72430,13 +72537,17 @@ const containerResponsiveThemeCss = `/*
72430
72537
  }
72431
72538
 
72432
72539
  /* Day headers */
72433
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-day-headers {
72540
+ :where(.theme-scope)
72541
+ :where([data-block='event-calendar'])
72542
+ .event-calendar-day-headers {
72434
72543
  display: grid;
72435
72544
  grid-template-columns: repeat(7, minmax(0, 1fr));
72436
72545
  background-color: var(--ec-header-bg);
72437
72546
  }
72438
72547
 
72439
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-day-header {
72548
+ :where(.theme-scope)
72549
+ :where([data-block='event-calendar'])
72550
+ .event-calendar-day-header {
72440
72551
  text-align: center;
72441
72552
  padding: 0.5rem;
72442
72553
  font-size: 0.875rem;
@@ -72446,33 +72557,43 @@ const containerResponsiveThemeCss = `/*
72446
72557
  }
72447
72558
 
72448
72559
  /* Calendar grid */
72449
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-grid {
72560
+ :where(.theme-scope)
72561
+ :where([data-block='event-calendar'])
72562
+ .event-calendar-grid {
72450
72563
  display: grid;
72451
72564
  grid-template-columns: repeat(7, minmax(0, 1fr));
72452
72565
  }
72453
72566
 
72454
72567
  /* Day cells */
72455
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-day {
72568
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-calendar-day {
72456
72569
  min-height: 100px;
72457
72570
  border-bottom: 1px solid var(--ec-border-subtle);
72458
72571
  border-right: 1px solid var(--ec-border-subtle);
72459
72572
  padding: 0.25rem;
72460
72573
  }
72461
72574
 
72462
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-day:nth-child(7n) {
72575
+ :where(.theme-scope)
72576
+ :where([data-block='event-calendar'])
72577
+ .event-calendar-day:nth-child(7n) {
72463
72578
  border-right: none;
72464
72579
  }
72465
72580
 
72466
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-day--today {
72581
+ :where(.theme-scope)
72582
+ :where([data-block='event-calendar'])
72583
+ .event-calendar-day--today {
72467
72584
  background-color: var(--ec-today-bg);
72468
72585
  }
72469
72586
 
72470
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-day--other-month {
72587
+ :where(.theme-scope)
72588
+ :where([data-block='event-calendar'])
72589
+ .event-calendar-day--other-month {
72471
72590
  opacity: var(--ec-other-month-opacity);
72472
72591
  }
72473
72592
 
72474
72593
  /* Day number */
72475
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-day-number {
72594
+ :where(.theme-scope)
72595
+ :where([data-block='event-calendar'])
72596
+ .event-calendar-day-number {
72476
72597
  font-size: 0.875rem;
72477
72598
  font-weight: 500;
72478
72599
  margin-bottom: 0.25rem;
@@ -72480,21 +72601,28 @@ const containerResponsiveThemeCss = `/*
72480
72601
  opacity: var(--ec-day-number-opacity);
72481
72602
  }
72482
72603
 
72483
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-day--today .event-calendar-day-number {
72604
+ :where(.theme-scope)
72605
+ :where([data-block='event-calendar'])
72606
+ .event-calendar-day--today
72607
+ .event-calendar-day-number {
72484
72608
  font-weight: 700;
72485
72609
  opacity: 1;
72486
72610
  color: var(--ec-today-text);
72487
72611
  }
72488
72612
 
72489
72613
  /* Events list */
72490
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-events {
72614
+ :where(.theme-scope)
72615
+ :where([data-block='event-calendar'])
72616
+ .event-calendar-events {
72491
72617
  display: flex;
72492
72618
  flex-direction: column;
72493
72619
  gap: 0.25rem;
72494
72620
  }
72495
72621
 
72496
72622
  /* Event item - solid primary background */
72497
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-event {
72623
+ :where(.theme-scope)
72624
+ :where([data-block='event-calendar'])
72625
+ .event-calendar-event {
72498
72626
  display: flex;
72499
72627
  align-items: center;
72500
72628
  gap: 0.375rem;
@@ -72515,24 +72643,32 @@ const containerResponsiveThemeCss = `/*
72515
72643
  transform var(--rb-block-transition) ease;
72516
72644
  }
72517
72645
 
72518
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-event:hover {
72646
+ :where(.theme-scope)
72647
+ :where([data-block='event-calendar'])
72648
+ .event-calendar-event:hover {
72519
72649
  background-color: var(--ec-event-solid-hover-bg);
72520
72650
  transform: translateY(-1px);
72521
72651
  }
72522
72652
 
72523
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-event:focus-visible {
72653
+ :where(.theme-scope)
72654
+ :where([data-block='event-calendar'])
72655
+ .event-calendar-event:focus-visible {
72524
72656
  outline: 2px solid var(--ec-event-solid-bg);
72525
72657
  outline-offset: 2px;
72526
72658
  }
72527
72659
 
72528
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-event-time {
72660
+ :where(.theme-scope)
72661
+ :where([data-block='event-calendar'])
72662
+ .event-calendar-event-time {
72529
72663
  flex-shrink: 0;
72530
72664
  white-space: nowrap;
72531
72665
  font-weight: 600;
72532
72666
  opacity: 0.9;
72533
72667
  }
72534
72668
 
72535
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-event-title {
72669
+ :where(.theme-scope)
72670
+ :where([data-block='event-calendar'])
72671
+ .event-calendar-event-title {
72536
72672
  min-width: 0;
72537
72673
  overflow: hidden;
72538
72674
  text-overflow: ellipsis;
@@ -72540,7 +72676,9 @@ const containerResponsiveThemeCss = `/*
72540
72676
  }
72541
72677
 
72542
72678
  /* More indicator - clickable button style */
72543
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-more {
72679
+ :where(.theme-scope)
72680
+ :where([data-block='event-calendar'])
72681
+ .event-calendar-more {
72544
72682
  font-size: 0.75rem;
72545
72683
  padding: 0.25rem 0.5rem;
72546
72684
  color: rgb(var(--tb-primary));
@@ -72552,16 +72690,22 @@ const containerResponsiveThemeCss = `/*
72552
72690
  transition: background-color var(--rb-block-transition) ease;
72553
72691
  }
72554
72692
 
72555
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-more:hover {
72693
+ :where(.theme-scope)
72694
+ :where([data-block='event-calendar'])
72695
+ .event-calendar-more:hover {
72556
72696
  background-color: rgba(var(--tb-primary), 0.1);
72557
72697
  }
72558
72698
 
72559
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-more:focus-visible {
72699
+ :where(.theme-scope)
72700
+ :where([data-block='event-calendar'])
72701
+ .event-calendar-more:focus-visible {
72560
72702
  outline: 2px solid rgb(var(--tb-primary));
72561
72703
  outline-offset: 2px;
72562
72704
  }
72563
72705
 
72564
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-empty {
72706
+ :where(.theme-scope)
72707
+ :where([data-block='event-calendar'])
72708
+ .event-calendar-empty {
72565
72709
  text-align: center;
72566
72710
  font-size: 0.875rem;
72567
72711
  opacity: var(--ec-empty-opacity);
@@ -72569,21 +72713,21 @@ const containerResponsiveThemeCss = `/*
72569
72713
  }
72570
72714
 
72571
72715
  /* Filters container */
72572
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-filters {
72716
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-filters {
72573
72717
  display: flex;
72574
72718
  flex-wrap: wrap;
72575
72719
  gap: 1rem;
72576
72720
  margin-bottom: 1.5rem;
72577
72721
  }
72578
72722
 
72579
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-filter {
72723
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-filter {
72580
72724
  display: flex;
72581
72725
  flex-direction: column;
72582
72726
  gap: 0.375rem;
72583
72727
  min-width: 180px;
72584
72728
  }
72585
72729
 
72586
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-filter-label {
72730
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-filter-label {
72587
72731
  font-size: 0.75rem;
72588
72732
  font-weight: 500;
72589
72733
  text-transform: uppercase;
@@ -72592,19 +72736,23 @@ const containerResponsiveThemeCss = `/*
72592
72736
  }
72593
72737
 
72594
72738
  /* Event filter select inherits base styling from .form-select, only block-specific overrides here */
72595
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-filter-select {
72739
+ :where(.theme-scope)
72740
+ :where([data-block='event-calendar'])
72741
+ .event-filter-select {
72596
72742
  /* Use theme input radius instead of block radius for consistency with other form inputs */
72597
72743
  border-radius: var(--rb-input-radius, var(--rb-block-radius));
72598
72744
  }
72599
72745
 
72600
72746
  /* Category filter buttons */
72601
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-category-buttons {
72747
+ :where(.theme-scope)
72748
+ :where([data-block='event-calendar'])
72749
+ .event-category-buttons {
72602
72750
  display: flex;
72603
72751
  flex-wrap: wrap;
72604
72752
  gap: 0.5rem;
72605
72753
  }
72606
72754
 
72607
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-category-btn {
72755
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-category-btn {
72608
72756
  padding: 0.5rem 1rem;
72609
72757
  font-size: 0.875rem;
72610
72758
  font-weight: 500;
@@ -72616,50 +72764,66 @@ const containerResponsiveThemeCss = `/*
72616
72764
  transition: all var(--rb-block-transition) ease;
72617
72765
  }
72618
72766
 
72619
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-category-btn:hover:not(:disabled) {
72767
+ :where(.theme-scope)
72768
+ :where([data-block='event-calendar'])
72769
+ .event-category-btn:hover:not(:disabled) {
72620
72770
  border-color: rgba(var(--tb-primary), 0.5);
72621
72771
  }
72622
72772
 
72623
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-category-btn:focus-visible {
72773
+ :where(.theme-scope)
72774
+ :where([data-block='event-calendar'])
72775
+ .event-category-btn:focus-visible {
72624
72776
  outline: 2px solid rgb(var(--tb-primary));
72625
72777
  outline-offset: 2px;
72626
72778
  }
72627
72779
 
72628
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-category-btn--active {
72780
+ :where(.theme-scope)
72781
+ :where([data-block='event-calendar'])
72782
+ .event-category-btn--active {
72629
72783
  background-color: rgb(var(--tb-primary));
72630
72784
  border-color: rgb(var(--tb-primary));
72631
72785
  color: var(--ec-event-solid-text);
72632
72786
  }
72633
72787
 
72634
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-category-btn:disabled {
72788
+ :where(.theme-scope)
72789
+ :where([data-block='event-calendar'])
72790
+ .event-category-btn:disabled {
72635
72791
  opacity: 0.5;
72636
72792
  cursor: not-allowed;
72637
72793
  }
72638
72794
 
72639
72795
  /* Allow category filter to be wider for button group */
72640
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-filter:has(.event-category-buttons) {
72796
+ :where(.theme-scope)
72797
+ :where([data-block='event-calendar'])
72798
+ .event-filter:has(.event-category-buttons) {
72641
72799
  min-width: auto;
72642
72800
  flex: 1 1 auto;
72643
72801
  }
72644
72802
 
72645
72803
  /* Combined mode container */
72646
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-combined {
72804
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-combined {
72647
72805
  width: 100%;
72648
72806
  }
72649
72807
 
72650
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-combined-content {
72808
+ :where(.theme-scope)
72809
+ :where([data-block='event-calendar'])
72810
+ .event-combined-content {
72651
72811
  display: flex;
72652
72812
  flex-direction: column;
72653
72813
  }
72654
72814
 
72655
72815
  /* Calendar view toggle (Month/Week) in Combined mode */
72656
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-view-toggle {
72816
+ :where(.theme-scope)
72817
+ :where([data-block='event-calendar'])
72818
+ .event-calendar-view-toggle {
72657
72819
  display: flex;
72658
72820
  gap: 0.25rem;
72659
72821
  margin-bottom: 1rem;
72660
72822
  }
72661
72823
 
72662
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-view-btn {
72824
+ :where(.theme-scope)
72825
+ :where([data-block='event-calendar'])
72826
+ .event-calendar-view-btn {
72663
72827
  padding: 0.5rem 1rem;
72664
72828
  font-size: 0.875rem;
72665
72829
  font-weight: 500;
@@ -72672,12 +72836,16 @@ const containerResponsiveThemeCss = `/*
72672
72836
  transition: all var(--rb-block-transition) ease;
72673
72837
  }
72674
72838
 
72675
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-view-btn:hover {
72839
+ :where(.theme-scope)
72840
+ :where([data-block='event-calendar'])
72841
+ .event-calendar-view-btn:hover {
72676
72842
  opacity: 1;
72677
72843
  border-color: rgba(var(--tb-primary), 0.5);
72678
72844
  }
72679
72845
 
72680
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-view-btn--active {
72846
+ :where(.theme-scope)
72847
+ :where([data-block='event-calendar'])
72848
+ .event-calendar-view-btn--active {
72681
72849
  opacity: 1;
72682
72850
  background-color: rgb(var(--tb-primary));
72683
72851
  border-color: rgb(var(--tb-primary));
@@ -72690,29 +72858,35 @@ const containerResponsiveThemeCss = `/*
72690
72858
  * ----------------------------------------------------------------------------- */
72691
72859
 
72692
72860
  /* Agenda week container */
72693
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-week {
72861
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-agenda-week {
72694
72862
  display: flex;
72695
72863
  flex-direction: column;
72696
72864
  gap: 0;
72697
72865
  }
72698
72866
 
72699
72867
  /* Individual day section */
72700
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-day {
72868
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-agenda-day {
72701
72869
  border-bottom: 1px solid var(--ec-border-subtle);
72702
72870
  }
72703
72871
 
72704
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-day:last-child {
72872
+ :where(.theme-scope)
72873
+ :where([data-block='event-calendar'])
72874
+ .event-agenda-day:last-child {
72705
72875
  border-bottom: none;
72706
72876
  }
72707
72877
 
72708
72878
  /* Day header */
72709
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-day-header {
72879
+ :where(.theme-scope)
72880
+ :where([data-block='event-calendar'])
72881
+ .event-agenda-day-header {
72710
72882
  padding: 0.75rem 0;
72711
72883
  background-color: var(--ec-header-bg);
72712
72884
  border-bottom: 1px solid var(--ec-border-subtle);
72713
72885
  }
72714
72886
 
72715
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-day-title {
72887
+ :where(.theme-scope)
72888
+ :where([data-block='event-calendar'])
72889
+ .event-agenda-day-title {
72716
72890
  font-size: 0.875rem;
72717
72891
  font-weight: 600;
72718
72892
  margin: 0;
@@ -72722,7 +72896,9 @@ const containerResponsiveThemeCss = `/*
72722
72896
  }
72723
72897
 
72724
72898
  /* Today badge */
72725
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-day-today-badge {
72899
+ :where(.theme-scope)
72900
+ :where([data-block='event-calendar'])
72901
+ .event-agenda-day-today-badge {
72726
72902
  display: inline-flex;
72727
72903
  align-items: center;
72728
72904
  padding: 0.125rem 0.5rem;
@@ -72736,24 +72912,33 @@ const containerResponsiveThemeCss = `/*
72736
72912
  }
72737
72913
 
72738
72914
  /* Today highlight for entire day section */
72739
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-day--today .event-agenda-day-header {
72915
+ :where(.theme-scope)
72916
+ :where([data-block='event-calendar'])
72917
+ .event-agenda-day--today
72918
+ .event-agenda-day-header {
72740
72919
  background-color: var(--ec-today-bg);
72741
72920
  }
72742
72921
 
72743
72922
  /* Day content area */
72744
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-day-content {
72923
+ :where(.theme-scope)
72924
+ :where([data-block='event-calendar'])
72925
+ .event-agenda-day-content {
72745
72926
  padding: 0.75rem 0;
72746
72927
  }
72747
72928
 
72748
72929
  /* Events list within a day */
72749
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-day-events {
72930
+ :where(.theme-scope)
72931
+ :where([data-block='event-calendar'])
72932
+ .event-agenda-day-events {
72750
72933
  display: flex;
72751
72934
  flex-direction: column;
72752
72935
  gap: 0.5rem;
72753
72936
  }
72754
72937
 
72755
72938
  /* Empty day message */
72756
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-day-empty {
72939
+ :where(.theme-scope)
72940
+ :where([data-block='event-calendar'])
72941
+ .event-agenda-day-empty {
72757
72942
  font-size: 0.875rem;
72758
72943
  opacity: var(--ec-empty-opacity);
72759
72944
  margin: 0;
@@ -72765,7 +72950,7 @@ const containerResponsiveThemeCss = `/*
72765
72950
  * Rich event card for agenda view
72766
72951
  * ----------------------------------------------------------------------------- */
72767
72952
 
72768
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-card {
72953
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-agenda-card {
72769
72954
  display: flex;
72770
72955
  align-items: flex-start;
72771
72956
  gap: 0.75rem;
@@ -72778,13 +72963,17 @@ const containerResponsiveThemeCss = `/*
72778
72963
  transition: all var(--rb-block-transition) ease;
72779
72964
  }
72780
72965
 
72781
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-card:hover {
72966
+ :where(.theme-scope)
72967
+ :where([data-block='event-calendar'])
72968
+ .event-agenda-card:hover {
72782
72969
  border-color: rgba(var(--tb-primary), 0.5);
72783
72970
  background-color: var(--ec-event-bg);
72784
72971
  }
72785
72972
 
72786
72973
  /* Category color indicator */
72787
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-card-indicator {
72974
+ :where(.theme-scope)
72975
+ :where([data-block='event-calendar'])
72976
+ .event-agenda-card-indicator {
72788
72977
  flex-shrink: 0;
72789
72978
  width: 4px;
72790
72979
  align-self: stretch;
@@ -72793,7 +72982,9 @@ const containerResponsiveThemeCss = `/*
72793
72982
  }
72794
72983
 
72795
72984
  /* Card content wrapper */
72796
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-card-content {
72985
+ :where(.theme-scope)
72986
+ :where([data-block='event-calendar'])
72987
+ .event-agenda-card-content {
72797
72988
  flex: 1;
72798
72989
  min-width: 0;
72799
72990
  display: flex;
@@ -72802,28 +72993,36 @@ const containerResponsiveThemeCss = `/*
72802
72993
  }
72803
72994
 
72804
72995
  /* Header row: time + title */
72805
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-card-header {
72996
+ :where(.theme-scope)
72997
+ :where([data-block='event-calendar'])
72998
+ .event-agenda-card-header {
72806
72999
  display: flex;
72807
73000
  align-items: baseline;
72808
73001
  gap: 0.5rem;
72809
73002
  flex-wrap: wrap;
72810
73003
  }
72811
73004
 
72812
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-card-time {
73005
+ :where(.theme-scope)
73006
+ :where([data-block='event-calendar'])
73007
+ .event-agenda-card-time {
72813
73008
  font-size: 0.75rem;
72814
73009
  font-weight: 600;
72815
73010
  opacity: var(--ec-time-opacity);
72816
73011
  white-space: nowrap;
72817
73012
  }
72818
73013
 
72819
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-card-title {
73014
+ :where(.theme-scope)
73015
+ :where([data-block='event-calendar'])
73016
+ .event-agenda-card-title {
72820
73017
  font-size: 0.875rem;
72821
73018
  font-weight: 500;
72822
73019
  line-height: 1.3;
72823
73020
  }
72824
73021
 
72825
73022
  /* Details row: venue, price, capacity */
72826
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-card-details {
73023
+ :where(.theme-scope)
73024
+ :where([data-block='event-calendar'])
73025
+ .event-agenda-card-details {
72827
73026
  display: flex;
72828
73027
  align-items: center;
72829
73028
  gap: 0.75rem;
@@ -72832,26 +73031,36 @@ const containerResponsiveThemeCss = `/*
72832
73031
  opacity: 0.7;
72833
73032
  }
72834
73033
 
72835
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-card-venue {
73034
+ :where(.theme-scope)
73035
+ :where([data-block='event-calendar'])
73036
+ .event-agenda-card-venue {
72836
73037
  display: inline-flex;
72837
73038
  align-items: center;
72838
73039
  gap: 0.25rem;
72839
73040
  }
72840
73041
 
72841
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-card-icon {
73042
+ :where(.theme-scope)
73043
+ :where([data-block='event-calendar'])
73044
+ .event-agenda-card-icon {
72842
73045
  flex-shrink: 0;
72843
73046
  opacity: 0.7;
72844
73047
  }
72845
73048
 
72846
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-card-price {
73049
+ :where(.theme-scope)
73050
+ :where([data-block='event-calendar'])
73051
+ .event-agenda-card-price {
72847
73052
  font-weight: 500;
72848
73053
  }
72849
73054
 
72850
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-card-capacity {
73055
+ :where(.theme-scope)
73056
+ :where([data-block='event-calendar'])
73057
+ .event-agenda-card-capacity {
72851
73058
  font-weight: 500;
72852
73059
  }
72853
73060
 
72854
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-card-capacity--full {
73061
+ :where(.theme-scope)
73062
+ :where([data-block='event-calendar'])
73063
+ .event-agenda-card-capacity--full {
72855
73064
  color: rgb(var(--tb-error, 239 68 68));
72856
73065
  opacity: 1;
72857
73066
  }
@@ -72861,20 +73070,24 @@ const containerResponsiveThemeCss = `/*
72861
73070
  * Time-grid layout for recurring class schedules
72862
73071
  * ----------------------------------------------------------------------------- */
72863
73072
 
72864
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable {
73073
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-timetable {
72865
73074
  display: flex;
72866
73075
  flex-direction: column;
72867
73076
  gap: 0.75rem;
72868
73077
  }
72869
73078
 
72870
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-day-selector {
73079
+ :where(.theme-scope)
73080
+ :where([data-block='event-calendar'])
73081
+ .event-timetable-day-selector {
72871
73082
  display: none;
72872
73083
  gap: 0.375rem;
72873
73084
  overflow-x: auto;
72874
73085
  padding-bottom: 0.125rem;
72875
73086
  }
72876
73087
 
72877
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-day-tab {
73088
+ :where(.theme-scope)
73089
+ :where([data-block='event-calendar'])
73090
+ .event-timetable-day-tab {
72878
73091
  flex: 0 0 auto;
72879
73092
  padding: 0.5rem 0.75rem;
72880
73093
  border: 1px solid var(--ec-border);
@@ -72889,35 +73102,49 @@ const containerResponsiveThemeCss = `/*
72889
73102
  border-color var(--rb-block-transition) ease;
72890
73103
  }
72891
73104
 
72892
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-day-tab--active {
73105
+ :where(.theme-scope)
73106
+ :where([data-block='event-calendar'])
73107
+ .event-timetable-day-tab--active {
72893
73108
  background-color: rgb(var(--tb-primary));
72894
73109
  border-color: rgb(var(--tb-primary));
72895
73110
  color: rgb(var(--tb-primaryText, 255 255 255));
72896
73111
  }
72897
73112
 
72898
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-container {
73113
+ :where(.theme-scope)
73114
+ :where([data-block='event-calendar'])
73115
+ .event-timetable-container {
72899
73116
  border: 1px solid var(--ec-border);
72900
73117
  border-radius: var(--rb-block-radius);
72901
73118
  overflow-x: auto;
72902
73119
  overflow-y: hidden;
72903
73120
  }
72904
73121
 
72905
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-grid {
73122
+ :where(.theme-scope)
73123
+ :where([data-block='event-calendar'])
73124
+ .event-timetable-grid {
72906
73125
  display: grid;
72907
73126
  grid-template-columns: 4.5rem repeat(7, minmax(8rem, 1fr));
72908
73127
  min-width: 62rem;
72909
73128
  }
72910
73129
 
72911
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-time-rail,
72912
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-day {
73130
+ :where(.theme-scope)
73131
+ :where([data-block='event-calendar'])
73132
+ .event-timetable-time-rail,
73133
+ :where(.theme-scope)
73134
+ :where([data-block='event-calendar'])
73135
+ .event-timetable-day {
72913
73136
  border-right: 1px solid var(--ec-border-subtle);
72914
73137
  }
72915
73138
 
72916
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-day:last-child {
73139
+ :where(.theme-scope)
73140
+ :where([data-block='event-calendar'])
73141
+ .event-timetable-day:last-child {
72917
73142
  border-right: none;
72918
73143
  }
72919
73144
 
72920
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-day-heading {
73145
+ :where(.theme-scope)
73146
+ :where([data-block='event-calendar'])
73147
+ .event-timetable-day-heading {
72921
73148
  min-height: 3.25rem;
72922
73149
  margin: 0;
72923
73150
  padding: 0.75rem 0.5rem;
@@ -72932,12 +73159,17 @@ const containerResponsiveThemeCss = `/*
72932
73159
  font-weight: 600;
72933
73160
  }
72934
73161
 
72935
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-day--today .event-timetable-day-heading {
73162
+ :where(.theme-scope)
73163
+ :where([data-block='event-calendar'])
73164
+ .event-timetable-day--today
73165
+ .event-timetable-day-heading {
72936
73166
  background-color: var(--ec-today-bg);
72937
73167
  color: var(--ec-today-text);
72938
73168
  }
72939
73169
 
72940
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-today-badge {
73170
+ :where(.theme-scope)
73171
+ :where([data-block='event-calendar'])
73172
+ .event-timetable-today-badge {
72941
73173
  padding: 0.125rem 0.375rem;
72942
73174
  border-radius: var(--rb-button-radius);
72943
73175
  background-color: rgb(var(--tb-primary));
@@ -72947,17 +73179,29 @@ const containerResponsiveThemeCss = `/*
72947
73179
  text-transform: uppercase;
72948
73180
  }
72949
73181
 
72950
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-time-body,
72951
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-day-body {
73182
+ :where(.theme-scope)
73183
+ :where([data-block='event-calendar'])
73184
+ .event-timetable-time-body,
73185
+ :where(.theme-scope)
73186
+ :where([data-block='event-calendar'])
73187
+ .event-timetable-day-body {
72952
73188
  position: relative;
72953
- height: clamp(34rem, calc(var(--event-timetable-range-minutes, 900) * 0.055rem), 56rem);
73189
+ height: clamp(
73190
+ 34rem,
73191
+ calc(var(--event-timetable-range-minutes, 900) * 0.055rem),
73192
+ 56rem
73193
+ );
72954
73194
  }
72955
73195
 
72956
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-time-body {
73196
+ :where(.theme-scope)
73197
+ :where([data-block='event-calendar'])
73198
+ .event-timetable-time-body {
72957
73199
  background-color: var(--ec-header-bg);
72958
73200
  }
72959
73201
 
72960
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-time-label {
73202
+ :where(.theme-scope)
73203
+ :where([data-block='event-calendar'])
73204
+ .event-timetable-time-label {
72961
73205
  position: absolute;
72962
73206
  left: 0.625rem;
72963
73207
  transform: translateY(-50%);
@@ -72966,14 +73210,18 @@ const containerResponsiveThemeCss = `/*
72966
73210
  white-space: nowrap;
72967
73211
  }
72968
73212
 
72969
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-hour-line {
73213
+ :where(.theme-scope)
73214
+ :where([data-block='event-calendar'])
73215
+ .event-timetable-hour-line {
72970
73216
  position: absolute;
72971
73217
  left: 0;
72972
73218
  right: 0;
72973
73219
  border-top: 1px solid var(--ec-border-subtle);
72974
73220
  }
72975
73221
 
72976
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event {
73222
+ :where(.theme-scope)
73223
+ :where([data-block='event-calendar'])
73224
+ .event-timetable-event {
72977
73225
  position: absolute;
72978
73226
  min-height: 2.75rem;
72979
73227
  padding: 0.375rem 0.5rem;
@@ -72993,21 +73241,35 @@ const containerResponsiveThemeCss = `/*
72993
73241
  transform var(--rb-block-transition) ease;
72994
73242
  }
72995
73243
 
72996
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event:hover {
73244
+ :where(.theme-scope)
73245
+ :where([data-block='event-calendar'])
73246
+ .event-timetable-event:hover {
72997
73247
  box-shadow: 0 4px 12px rgba(var(--tb-text), 0.12);
72998
73248
  transform: translateY(-1px);
72999
73249
  }
73000
73250
 
73001
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event:focus-visible {
73251
+ :where(.theme-scope)
73252
+ :where([data-block='event-calendar'])
73253
+ .event-timetable-event:focus-visible {
73002
73254
  outline: 2px solid rgb(var(--tb-primary));
73003
73255
  outline-offset: 2px;
73004
73256
  }
73005
73257
 
73006
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event-time,
73007
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event-title,
73008
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event-teacher,
73009
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event-meta,
73010
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event-capacity {
73258
+ :where(.theme-scope)
73259
+ :where([data-block='event-calendar'])
73260
+ .event-timetable-event-time,
73261
+ :where(.theme-scope)
73262
+ :where([data-block='event-calendar'])
73263
+ .event-timetable-event-title,
73264
+ :where(.theme-scope)
73265
+ :where([data-block='event-calendar'])
73266
+ .event-timetable-event-teacher,
73267
+ :where(.theme-scope)
73268
+ :where([data-block='event-calendar'])
73269
+ .event-timetable-event-meta,
73270
+ :where(.theme-scope)
73271
+ :where([data-block='event-calendar'])
73272
+ .event-timetable-event-capacity {
73011
73273
  display: block;
73012
73274
  min-width: 0;
73013
73275
  overflow: hidden;
@@ -73015,36 +73277,50 @@ const containerResponsiveThemeCss = `/*
73015
73277
  white-space: nowrap;
73016
73278
  }
73017
73279
 
73018
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event-time {
73280
+ :where(.theme-scope)
73281
+ :where([data-block='event-calendar'])
73282
+ .event-timetable-event-time {
73019
73283
  font-size: 0.6875rem;
73020
73284
  font-weight: 700;
73021
73285
  opacity: var(--ec-time-opacity);
73022
73286
  }
73023
73287
 
73024
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event-title {
73288
+ :where(.theme-scope)
73289
+ :where([data-block='event-calendar'])
73290
+ .event-timetable-event-title {
73025
73291
  font-size: 0.8125rem;
73026
73292
  font-weight: 700;
73027
73293
  line-height: 1.25;
73028
73294
  }
73029
73295
 
73030
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event-teacher,
73031
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event-meta {
73296
+ :where(.theme-scope)
73297
+ :where([data-block='event-calendar'])
73298
+ .event-timetable-event-teacher,
73299
+ :where(.theme-scope)
73300
+ :where([data-block='event-calendar'])
73301
+ .event-timetable-event-meta {
73032
73302
  font-size: 0.6875rem;
73033
73303
  opacity: 0.72;
73034
73304
  }
73035
73305
 
73036
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event-capacity {
73306
+ :where(.theme-scope)
73307
+ :where([data-block='event-calendar'])
73308
+ .event-timetable-event-capacity {
73037
73309
  font-size: 0.6875rem;
73038
73310
  font-weight: 600;
73039
73311
  opacity: 0.85;
73040
73312
  }
73041
73313
 
73042
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event-capacity--full {
73314
+ :where(.theme-scope)
73315
+ :where([data-block='event-calendar'])
73316
+ .event-timetable-event-capacity--full {
73043
73317
  color: rgb(var(--tb-danger, 220 38 38));
73044
73318
  opacity: 1;
73045
73319
  }
73046
73320
 
73047
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-day-empty {
73321
+ :where(.theme-scope)
73322
+ :where([data-block='event-calendar'])
73323
+ .event-timetable-day-empty {
73048
73324
  margin: 0;
73049
73325
  padding: 1rem 0.5rem;
73050
73326
  text-align: center;
@@ -73052,7 +73328,9 @@ const containerResponsiveThemeCss = `/*
73052
73328
  opacity: var(--ec-empty-opacity);
73053
73329
  }
73054
73330
 
73055
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-empty {
73331
+ :where(.theme-scope)
73332
+ :where([data-block='event-calendar'])
73333
+ .event-timetable-empty {
73056
73334
  margin: 0.25rem 0 0;
73057
73335
  text-align: center;
73058
73336
  font-size: 0.875rem;
@@ -73061,32 +73339,46 @@ const containerResponsiveThemeCss = `/*
73061
73339
 
73062
73340
  @container rb-site (max-width: 767px) {
73063
73341
  @scope ([data-rb-responsive-mode="container"]) to (:scope [data-rb-responsive-mode]) {
73064
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-day-selector {
73342
+ :where(.theme-scope)
73343
+ :where([data-block='event-calendar'])
73344
+ .event-timetable-day-selector {
73065
73345
  display: flex;
73066
73346
  }
73067
73347
 
73068
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-container {
73348
+ :where(.theme-scope)
73349
+ :where([data-block='event-calendar'])
73350
+ .event-timetable-container {
73069
73351
  overflow: hidden;
73070
73352
  }
73071
73353
 
73072
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-grid {
73354
+ :where(.theme-scope)
73355
+ :where([data-block='event-calendar'])
73356
+ .event-timetable-grid {
73073
73357
  grid-template-columns: 4rem minmax(0, 1fr);
73074
73358
  min-width: 0;
73075
73359
  }
73076
73360
 
73077
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-day[data-selected="false"] {
73361
+ :where(.theme-scope)
73362
+ :where([data-block='event-calendar'])
73363
+ .event-timetable-day[data-selected='false'] {
73078
73364
  display: none;
73079
73365
  }
73080
73366
 
73081
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-day {
73367
+ :where(.theme-scope)
73368
+ :where([data-block='event-calendar'])
73369
+ .event-timetable-day {
73082
73370
  border-right: none;
73083
73371
  }
73084
73372
 
73085
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-time-rail {
73373
+ :where(.theme-scope)
73374
+ :where([data-block='event-calendar'])
73375
+ .event-timetable-time-rail {
73086
73376
  border-right: 1px solid var(--ec-border-subtle);
73087
73377
  }
73088
73378
 
73089
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-day-heading {
73379
+ :where(.theme-scope)
73380
+ :where([data-block='event-calendar'])
73381
+ .event-timetable-day-heading {
73090
73382
  justify-content: flex-start;
73091
73383
  padding-inline: 0.75rem;
73092
73384
  }
@@ -73099,7 +73391,7 @@ const containerResponsiveThemeCss = `/*
73099
73391
  * three-state availability (available / filling / waitlist), and a footer CTA.
73100
73392
  * ----------------------------------------------------------------------------- */
73101
73393
 
73102
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board {
73394
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-week-board {
73103
73395
  /* Status accent tokens — map the three availability states onto theme colours.
73104
73396
  * available -> secondary, filling -> accent, waitlist -> muted text. */
73105
73397
  --ec-status-available: rgb(var(--tb-secondary));
@@ -73116,17 +73408,20 @@ const containerResponsiveThemeCss = `/*
73116
73408
 
73117
73409
  /* Opt-in raised look: a soft drop shadow so the board lifts off the page.
73118
73410
  * Generic default (no [data-elevated]) stays flat. */
73119
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board[data-elevated] {
73411
+ :where(.theme-scope)
73412
+ :where([data-block='event-calendar'])
73413
+ .event-week-board[data-elevated] {
73120
73414
  box-shadow: 0 14px 34px -24px rgba(var(--tb-text), 0.35);
73121
73415
  }
73122
73416
 
73123
- /* Top bar: title + legend */
73124
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-top {
73125
- display: flex;
73417
+ /* Top bar: authored title + week navigation + legend */
73418
+ :where(.theme-scope)
73419
+ :where([data-block='event-calendar'])
73420
+ .event-week-board-top {
73421
+ display: grid;
73422
+ grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
73126
73423
  align-items: center;
73127
- justify-content: space-between;
73128
73424
  gap: 1rem;
73129
- flex-wrap: wrap;
73130
73425
  padding: 1.1rem 1.5rem;
73131
73426
  /* surfaceAlt gives the header/footer a legible tint against the white day-grid
73132
73427
  * body — the faint \`--ec-header-bg\` (5% text) is invisible on light palettes. */
@@ -73134,7 +73429,10 @@ const containerResponsiveThemeCss = `/*
73134
73429
  border-bottom: 1px solid var(--ec-border-subtle);
73135
73430
  }
73136
73431
 
73137
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-title {
73432
+ :where(.theme-scope)
73433
+ :where([data-block='event-calendar'])
73434
+ .event-week-board-title {
73435
+ grid-column: 1;
73138
73436
  font-size: 0.8125rem;
73139
73437
  font-weight: 600;
73140
73438
  letter-spacing: 0.12em;
@@ -73142,7 +73440,67 @@ const containerResponsiveThemeCss = `/*
73142
73440
  color: rgb(var(--tb-primary));
73143
73441
  }
73144
73442
 
73145
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-legend {
73443
+ :where(.theme-scope)
73444
+ :where([data-block='event-calendar'])
73445
+ .event-week-board-navigation {
73446
+ grid-column: 2;
73447
+ display: flex;
73448
+ align-items: center;
73449
+ justify-content: center;
73450
+ gap: 0.65rem;
73451
+ }
73452
+
73453
+ :where(.theme-scope)
73454
+ :where([data-block='event-calendar'])
73455
+ .event-week-board-nav-button {
73456
+ display: inline-flex;
73457
+ align-items: center;
73458
+ justify-content: center;
73459
+ width: 2.25rem;
73460
+ height: 2.25rem;
73461
+ padding: 0;
73462
+ border: 1px solid var(--ec-border);
73463
+ border-radius: 999px;
73464
+ background: transparent;
73465
+ color: inherit;
73466
+ cursor: pointer;
73467
+ }
73468
+
73469
+ :where(.theme-scope)
73470
+ :where([data-block='event-calendar'])
73471
+ .event-week-board-nav-button:hover {
73472
+ background-color: var(--ec-hover-bg);
73473
+ }
73474
+
73475
+ :where(.theme-scope)
73476
+ :where([data-block='event-calendar'])
73477
+ .event-week-board-nav-button:focus-visible {
73478
+ outline: 2px solid rgb(var(--tb-primary));
73479
+ outline-offset: 2px;
73480
+ }
73481
+
73482
+ :where(.theme-scope)
73483
+ :where([data-block='event-calendar'])
73484
+ .event-week-board-range {
73485
+ min-width: 12rem;
73486
+ margin: 0;
73487
+ text-align: center;
73488
+ font-size: 0.875rem;
73489
+ font-weight: 600;
73490
+ }
73491
+
73492
+ :where(.theme-scope)
73493
+ :where([data-block='event-calendar'])
73494
+ .event-week-board-loading {
73495
+ font-weight: 400;
73496
+ opacity: 0.65;
73497
+ }
73498
+
73499
+ :where(.theme-scope)
73500
+ :where([data-block='event-calendar'])
73501
+ .event-week-board-legend {
73502
+ grid-column: 3;
73503
+ justify-self: end;
73146
73504
  display: flex;
73147
73505
  align-items: center;
73148
73506
  gap: 1.1rem;
@@ -73152,38 +73510,72 @@ const containerResponsiveThemeCss = `/*
73152
73510
  opacity: 0.75;
73153
73511
  }
73154
73512
 
73155
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-legend-item {
73513
+ :where(.theme-scope)
73514
+ :where([data-block='event-calendar'])
73515
+ .event-week-board-error {
73516
+ display: flex;
73517
+ align-items: center;
73518
+ justify-content: center;
73519
+ gap: 0.75rem;
73520
+ padding: 0.75rem 1.5rem;
73521
+ border-bottom: 1px solid var(--ec-border-subtle);
73522
+ color: rgb(var(--tb-error, var(--tb-text)));
73523
+ }
73524
+
73525
+ :where(.theme-scope)
73526
+ :where([data-block='event-calendar'])
73527
+ .event-week-board-error
73528
+ p {
73529
+ margin: 0;
73530
+ font-size: 0.8125rem;
73531
+ }
73532
+
73533
+ :where(.theme-scope)
73534
+ :where([data-block='event-calendar'])
73535
+ .event-week-board-legend-item {
73156
73536
  display: inline-flex;
73157
73537
  align-items: center;
73158
73538
  gap: 0.4rem;
73159
73539
  }
73160
73540
 
73161
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-legend-dot {
73541
+ :where(.theme-scope)
73542
+ :where([data-block='event-calendar'])
73543
+ .event-week-board-legend-dot {
73162
73544
  width: 0.55rem;
73163
73545
  height: 0.55rem;
73164
73546
  border-radius: 50%;
73165
73547
  display: inline-block;
73166
73548
  }
73167
73549
 
73168
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-legend-dot[data-status="available"] {
73550
+ :where(.theme-scope)
73551
+ :where([data-block='event-calendar'])
73552
+ .event-week-board-legend-dot[data-status='available'] {
73169
73553
  background-color: var(--ec-status-available);
73170
73554
  }
73171
73555
 
73172
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-legend-dot[data-status="filling"] {
73556
+ :where(.theme-scope)
73557
+ :where([data-block='event-calendar'])
73558
+ .event-week-board-legend-dot[data-status='filling'] {
73173
73559
  background-color: var(--ec-status-filling);
73174
73560
  }
73175
73561
 
73176
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-legend-dot[data-status="waitlist"] {
73562
+ :where(.theme-scope)
73563
+ :where([data-block='event-calendar'])
73564
+ .event-week-board-legend-dot[data-status='waitlist'] {
73177
73565
  background-color: var(--ec-status-waitlist);
73178
73566
  }
73179
73567
 
73180
73568
  /* Day columns grid */
73181
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-grid {
73569
+ :where(.theme-scope)
73570
+ :where([data-block='event-calendar'])
73571
+ .event-week-board-grid {
73182
73572
  display: grid;
73183
73573
  grid-template-columns: repeat(var(--event-week-board-cols), minmax(0, 1fr));
73184
73574
  }
73185
73575
 
73186
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-day {
73576
+ :where(.theme-scope)
73577
+ :where([data-block='event-calendar'])
73578
+ .event-week-board-day {
73187
73579
  display: flex;
73188
73580
  flex-direction: column;
73189
73581
  min-height: 15rem;
@@ -73193,11 +73585,15 @@ const containerResponsiveThemeCss = `/*
73193
73585
  border-right: var(--rb-border-width, 1px) solid rgb(var(--tb-border));
73194
73586
  }
73195
73587
 
73196
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-day:last-child {
73588
+ :where(.theme-scope)
73589
+ :where([data-block='event-calendar'])
73590
+ .event-week-board-day:last-child {
73197
73591
  border-right: none;
73198
73592
  }
73199
73593
 
73200
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-day-head {
73594
+ :where(.theme-scope)
73595
+ :where([data-block='event-calendar'])
73596
+ .event-week-board-day-head {
73201
73597
  display: flex;
73202
73598
  align-items: baseline;
73203
73599
  gap: 0.4rem;
@@ -73206,11 +73602,16 @@ const containerResponsiveThemeCss = `/*
73206
73602
  border-bottom: var(--rb-border-width, 1px) solid rgb(var(--tb-border));
73207
73603
  }
73208
73604
 
73209
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-day--today .event-week-board-day-head {
73605
+ :where(.theme-scope)
73606
+ :where([data-block='event-calendar'])
73607
+ .event-week-board-day--today
73608
+ .event-week-board-day-head {
73210
73609
  background-color: var(--ec-today-bg);
73211
73610
  }
73212
73611
 
73213
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-day-abbr {
73612
+ :where(.theme-scope)
73613
+ :where([data-block='event-calendar'])
73614
+ .event-week-board-day-abbr {
73214
73615
  font-size: 0.6875rem;
73215
73616
  font-weight: 600;
73216
73617
  letter-spacing: 0.1em;
@@ -73218,18 +73619,25 @@ const containerResponsiveThemeCss = `/*
73218
73619
  opacity: 0.65;
73219
73620
  }
73220
73621
 
73221
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-day--today .event-week-board-day-abbr {
73622
+ :where(.theme-scope)
73623
+ :where([data-block='event-calendar'])
73624
+ .event-week-board-day--today
73625
+ .event-week-board-day-abbr {
73222
73626
  opacity: 1;
73223
73627
  color: var(--ec-today-text);
73224
73628
  }
73225
73629
 
73226
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-day-num {
73630
+ :where(.theme-scope)
73631
+ :where([data-block='event-calendar'])
73632
+ .event-week-board-day-num {
73227
73633
  font-size: 0.8125rem;
73228
73634
  font-weight: 600;
73229
73635
  opacity: 0.5;
73230
73636
  }
73231
73637
 
73232
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-day-body {
73638
+ :where(.theme-scope)
73639
+ :where([data-block='event-calendar'])
73640
+ .event-week-board-day-body {
73233
73641
  display: flex;
73234
73642
  flex-direction: column;
73235
73643
  gap: 0.65rem;
@@ -73238,7 +73646,9 @@ const containerResponsiveThemeCss = `/*
73238
73646
  }
73239
73647
 
73240
73648
  /* Class card */
73241
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-card {
73649
+ :where(.theme-scope)
73650
+ :where([data-block='event-calendar'])
73651
+ .event-week-board-card {
73242
73652
  display: flex;
73243
73653
  flex-direction: column;
73244
73654
  gap: 0.45rem;
@@ -73258,40 +73668,54 @@ const containerResponsiveThemeCss = `/*
73258
73668
  border-color var(--rb-block-transition) ease;
73259
73669
  }
73260
73670
 
73261
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-card[data-status="filling"] {
73671
+ :where(.theme-scope)
73672
+ :where([data-block='event-calendar'])
73673
+ .event-week-board-card[data-status='filling'] {
73262
73674
  border-left-color: var(--ec-status-filling);
73263
73675
  }
73264
73676
 
73265
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-card[data-status="waitlist"] {
73677
+ :where(.theme-scope)
73678
+ :where([data-block='event-calendar'])
73679
+ .event-week-board-card[data-status='waitlist'] {
73266
73680
  border-left-color: var(--ec-status-waitlist);
73267
73681
  }
73268
73682
 
73269
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-card:hover {
73683
+ :where(.theme-scope)
73684
+ :where([data-block='event-calendar'])
73685
+ .event-week-board-card:hover {
73270
73686
  transform: translateY(-2px);
73271
73687
  box-shadow: 0 6px 16px -8px rgba(var(--tb-text), 0.28);
73272
73688
  border-color: rgba(var(--tb-primary), 0.4);
73273
73689
  }
73274
73690
 
73275
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-card:focus-visible {
73691
+ :where(.theme-scope)
73692
+ :where([data-block='event-calendar'])
73693
+ .event-week-board-card:focus-visible {
73276
73694
  outline: 2px solid rgb(var(--tb-primary));
73277
73695
  outline-offset: 2px;
73278
73696
  }
73279
73697
 
73280
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-card-title {
73698
+ :where(.theme-scope)
73699
+ :where([data-block='event-calendar'])
73700
+ .event-week-board-card-title {
73281
73701
  font-family: var(--font-heading, inherit);
73282
73702
  font-size: 0.9375rem;
73283
73703
  font-weight: 600;
73284
73704
  line-height: 1.2;
73285
73705
  }
73286
73706
 
73287
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-card-time {
73707
+ :where(.theme-scope)
73708
+ :where([data-block='event-calendar'])
73709
+ .event-week-board-card-time {
73288
73710
  font-size: 0.75rem;
73289
73711
  letter-spacing: 0.01em;
73290
73712
  opacity: 0.7;
73291
73713
  }
73292
73714
 
73293
73715
  /* Capacity pill */
73294
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-card-pill {
73716
+ :where(.theme-scope)
73717
+ :where([data-block='event-calendar'])
73718
+ .event-week-board-card-pill {
73295
73719
  align-self: flex-start;
73296
73720
  display: inline-flex;
73297
73721
  align-items: center;
@@ -73309,20 +73733,26 @@ const containerResponsiveThemeCss = `/*
73309
73733
  border-color: var(--ec-border);
73310
73734
  }
73311
73735
 
73312
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-card-pill[data-status="filling"] {
73736
+ :where(.theme-scope)
73737
+ :where([data-block='event-calendar'])
73738
+ .event-week-board-card-pill[data-status='filling'] {
73313
73739
  background-color: rgba(var(--tb-accent), 0.14);
73314
73740
  color: var(--ec-status-filling);
73315
73741
  border-color: rgba(var(--tb-accent), 0.32);
73316
73742
  }
73317
73743
 
73318
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-card-pill[data-status="waitlist"] {
73744
+ :where(.theme-scope)
73745
+ :where([data-block='event-calendar'])
73746
+ .event-week-board-card-pill[data-status='waitlist'] {
73319
73747
  background-color: transparent;
73320
73748
  color: rgba(var(--tb-text), 0.6);
73321
73749
  border-color: var(--ec-border);
73322
73750
  }
73323
73751
 
73324
73752
  /* Footer */
73325
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-foot {
73753
+ :where(.theme-scope)
73754
+ :where([data-block='event-calendar'])
73755
+ .event-week-board-foot {
73326
73756
  display: flex;
73327
73757
  align-items: center;
73328
73758
  justify-content: space-between;
@@ -73334,7 +73764,9 @@ const containerResponsiveThemeCss = `/*
73334
73764
  border-top: 1px solid var(--ec-border-subtle);
73335
73765
  }
73336
73766
 
73337
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-foot-note {
73767
+ :where(.theme-scope)
73768
+ :where([data-block='event-calendar'])
73769
+ .event-week-board-foot-note {
73338
73770
  margin: 0;
73339
73771
  font-size: 0.875rem;
73340
73772
  opacity: 0.75;
@@ -73343,36 +73775,69 @@ const containerResponsiveThemeCss = `/*
73343
73775
  /* Responsive: collapse day columns to a stacked list on narrow viewports */
73344
73776
  @container rb-site (max-width: 1023px) {
73345
73777
  @scope ([data-rb-responsive-mode="container"]) to (:scope [data-rb-responsive-mode]) {
73346
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-grid {
73778
+ :where(.theme-scope)
73779
+ :where([data-block='event-calendar'])
73780
+ .event-week-board-top {
73781
+ grid-template-columns: 1fr;
73782
+ }
73783
+
73784
+ :where(.theme-scope)
73785
+ :where([data-block='event-calendar'])
73786
+ .event-week-board-title,
73787
+ :where(.theme-scope)
73788
+ :where([data-block='event-calendar'])
73789
+ .event-week-board-navigation,
73790
+ :where(.theme-scope)
73791
+ :where([data-block='event-calendar'])
73792
+ .event-week-board-legend {
73793
+ grid-column: 1;
73794
+ justify-self: center;
73795
+ }
73796
+
73797
+ :where(.theme-scope)
73798
+ :where([data-block='event-calendar'])
73799
+ .event-week-board-grid {
73347
73800
  grid-template-columns: 1fr;
73348
73801
  }
73349
73802
 
73350
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-day {
73803
+ :where(.theme-scope)
73804
+ :where([data-block='event-calendar'])
73805
+ .event-week-board-day {
73351
73806
  min-height: 0;
73352
73807
  border-right: none;
73353
73808
  border-bottom: var(--rb-border-width, 1px) solid rgb(var(--tb-border));
73354
73809
  }
73355
73810
 
73356
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-day:last-child {
73811
+ :where(.theme-scope)
73812
+ :where([data-block='event-calendar'])
73813
+ .event-week-board-day:last-child {
73357
73814
  border-bottom: none;
73358
73815
  }
73359
73816
 
73360
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-day--empty {
73817
+ :where(.theme-scope)
73818
+ :where([data-block='event-calendar'])
73819
+ .event-week-board-day--empty {
73361
73820
  display: none;
73362
73821
  }
73363
73822
 
73364
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-day-head {
73823
+ :where(.theme-scope)
73824
+ :where([data-block='event-calendar'])
73825
+ .event-week-board-day-head {
73365
73826
  border-bottom: none;
73366
73827
  padding-bottom: 0.25rem;
73367
73828
  }
73368
73829
 
73369
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-day-body {
73830
+ :where(.theme-scope)
73831
+ :where([data-block='event-calendar'])
73832
+ .event-week-board-day-body {
73370
73833
  flex-direction: row;
73371
73834
  flex-wrap: wrap;
73372
73835
  padding-top: 0.35rem;
73373
73836
  }
73374
73837
 
73375
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-card {
73838
+ :where(.theme-scope)
73839
+ :where([data-block='event-calendar'])
73840
+ .event-week-board-card {
73376
73841
  flex: 1 1 14rem;
73377
73842
  }
73378
73843
  }
@@ -73380,11 +73845,37 @@ const containerResponsiveThemeCss = `/*
73380
73845
 
73381
73846
  @container rb-site (max-width: 639px) {
73382
73847
  @scope ([data-rb-responsive-mode="container"]) to (:scope [data-rb-responsive-mode]) {
73383
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-legend {
73848
+ :where(.theme-scope)
73849
+ :where([data-block='event-calendar'])
73850
+ .event-week-board-navigation {
73851
+ display: grid;
73852
+ grid-template-columns: 2.25rem minmax(0, 1fr) 2.25rem;
73853
+ width: 100%;
73854
+ }
73855
+
73856
+ :where(.theme-scope)
73857
+ :where([data-block='event-calendar'])
73858
+ .event-week-board-navigation
73859
+ > :last-child {
73860
+ grid-column: 1 / -1;
73861
+ justify-self: center;
73862
+ }
73863
+
73864
+ :where(.theme-scope)
73865
+ :where([data-block='event-calendar'])
73866
+ .event-week-board-range {
73867
+ min-width: 0;
73868
+ }
73869
+
73870
+ :where(.theme-scope)
73871
+ :where([data-block='event-calendar'])
73872
+ .event-week-board-legend {
73384
73873
  display: none;
73385
73874
  }
73386
73875
 
73387
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-card {
73876
+ :where(.theme-scope)
73877
+ :where([data-block='event-calendar'])
73878
+ .event-week-board-card {
73388
73879
  flex: 1 1 100%;
73389
73880
  }
73390
73881
  }
@@ -73401,8 +73892,9 @@ const containerResponsiveThemeCss = `/*
73401
73892
  * Opt-in only: the band paints when the board root carries [data-banded];
73402
73893
  * the generic default is bandless.
73403
73894
  * ----------------------------------------------------------------------------- */
73404
- :where(.theme-scope) [data-slot="section"]:has(.event-calendar--week-board[data-banded])::before {
73405
- content: "";
73895
+ :where(.theme-scope)
73896
+ [data-slot='section']:has(.event-calendar--week-board[data-banded])::before {
73897
+ content: '';
73406
73898
  position: absolute;
73407
73899
  inset: 0;
73408
73900
  z-index: -9;
@@ -73456,7 +73948,7 @@ const containerResponsiveThemeCss = `/*
73456
73948
  * ----------------------------------------------------------------------------- */
73457
73949
 
73458
73950
  /* Modal overlay */
73459
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal-overlay {
73951
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal-overlay {
73460
73952
  position: fixed;
73461
73953
  inset: 0;
73462
73954
  background: var(--ec-modal-overlay-bg);
@@ -73470,12 +73962,16 @@ const containerResponsiveThemeCss = `/*
73470
73962
  }
73471
73963
 
73472
73964
  @keyframes ec-modal-fade-in {
73473
- from { opacity: 0; }
73474
- to { opacity: 1; }
73965
+ from {
73966
+ opacity: 0;
73967
+ }
73968
+ to {
73969
+ opacity: 1;
73970
+ }
73475
73971
  }
73476
73972
 
73477
73973
  /* Modal dialog */
73478
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal {
73974
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal {
73479
73975
  position: relative;
73480
73976
  background: var(--ec-modal-bg);
73481
73977
  border-radius: var(--rb-block-radius);
@@ -73499,17 +73995,17 @@ const containerResponsiveThemeCss = `/*
73499
73995
  }
73500
73996
 
73501
73997
  /* Event modal - constrained width for card */
73502
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal--event {
73998
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal--event {
73503
73999
  max-width: 26rem;
73504
74000
  }
73505
74001
 
73506
74002
  /* Day modal */
73507
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal--day {
74003
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal--day {
73508
74004
  max-width: 28rem;
73509
74005
  }
73510
74006
 
73511
74007
  /* Close button */
73512
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal-close {
74008
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal-close {
73513
74009
  position: absolute;
73514
74010
  top: 0.75rem;
73515
74011
  right: 0.75rem;
@@ -73530,31 +74026,35 @@ const containerResponsiveThemeCss = `/*
73530
74026
  z-index: 10;
73531
74027
  }
73532
74028
 
73533
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal-close:hover {
74029
+ :where(.theme-scope)
74030
+ :where([data-block='event-calendar'])
74031
+ .ec-modal-close:hover {
73534
74032
  opacity: 1;
73535
74033
  background-color: rgba(var(--tb-text), 0.1);
73536
74034
  }
73537
74035
 
73538
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal-close:focus-visible {
74036
+ :where(.theme-scope)
74037
+ :where([data-block='event-calendar'])
74038
+ .ec-modal-close:focus-visible {
73539
74039
  outline: 2px solid rgb(var(--tb-primary));
73540
74040
  outline-offset: 2px;
73541
74041
  }
73542
74042
 
73543
74043
  /* Modal header (for day modal) */
73544
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal-header {
74044
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal-header {
73545
74045
  padding: 1.5rem 1.5rem 1rem;
73546
74046
  padding-right: 3rem; /* Space for close button */
73547
74047
  border-bottom: 1px solid var(--ec-border);
73548
74048
  }
73549
74049
 
73550
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal-title {
74050
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal-title {
73551
74051
  font-size: 1.125rem;
73552
74052
  font-weight: 600;
73553
74053
  color: var(--ec-text);
73554
74054
  margin: 0;
73555
74055
  }
73556
74056
 
73557
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal-subtitle {
74057
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal-subtitle {
73558
74058
  font-size: 0.875rem;
73559
74059
  color: var(--ec-text);
73560
74060
  opacity: 0.7;
@@ -73562,17 +74062,20 @@ const containerResponsiveThemeCss = `/*
73562
74062
  }
73563
74063
 
73564
74064
  /* Modal content */
73565
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal-content {
74065
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal-content {
73566
74066
  padding: 1rem;
73567
74067
  }
73568
74068
 
73569
74069
  /* Event modal: tighter padding for card */
73570
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal--event .ec-modal-content {
74070
+ :where(.theme-scope)
74071
+ :where([data-block='event-calendar'])
74072
+ .ec-modal--event
74073
+ .ec-modal-content {
73571
74074
  padding: 0.5rem;
73572
74075
  }
73573
74076
 
73574
74077
  /* Day events list */
73575
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-day-events-list {
74078
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-day-events-list {
73576
74079
  display: flex;
73577
74080
  flex-direction: column;
73578
74081
  gap: 0.5rem;
@@ -73580,7 +74083,9 @@ const containerResponsiveThemeCss = `/*
73580
74083
  }
73581
74084
 
73582
74085
  /* AgendaEventCard in button mode inherits most styles, just needs cursor */
73583
- :where(.theme-scope) :where([data-block="event-calendar"]) button.event-agenda-card {
74086
+ :where(.theme-scope)
74087
+ :where([data-block='event-calendar'])
74088
+ button.event-agenda-card {
73584
74089
  cursor: pointer;
73585
74090
  text-align: left;
73586
74091
  font-family: inherit;
@@ -73589,7 +74094,9 @@ const containerResponsiveThemeCss = `/*
73589
74094
  /* Responsive adjustments */
73590
74095
  @container rb-site (max-width: 640px) {
73591
74096
  @scope ([data-rb-responsive-mode="container"]) to (:scope [data-rb-responsive-mode]) {
73592
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-container {
74097
+ :where(.theme-scope)
74098
+ :where([data-block='event-calendar'])
74099
+ .event-calendar-container {
73593
74100
  margin-left: -1.5rem;
73594
74101
  margin-right: -1.5rem;
73595
74102
  border-left: none;
@@ -73597,28 +74104,38 @@ const containerResponsiveThemeCss = `/*
73597
74104
  border-radius: 0;
73598
74105
  }
73599
74106
 
73600
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-day-header {
74107
+ :where(.theme-scope)
74108
+ :where([data-block='event-calendar'])
74109
+ .event-calendar-day-header {
73601
74110
  font-size: 0.75rem;
73602
74111
  padding: 0.375rem 0.125rem;
73603
74112
  }
73604
74113
 
73605
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-day {
74114
+ :where(.theme-scope)
74115
+ :where([data-block='event-calendar'])
74116
+ .event-calendar-day {
73606
74117
  min-height: 88px;
73607
74118
  padding: 0.125rem;
73608
74119
  }
73609
74120
 
73610
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-title {
74121
+ :where(.theme-scope)
74122
+ :where([data-block='event-calendar'])
74123
+ .event-calendar-title {
73611
74124
  font-size: 0.9375rem;
73612
74125
  min-width: 0;
73613
74126
  }
73614
74127
 
73615
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-day-number {
74128
+ :where(.theme-scope)
74129
+ :where([data-block='event-calendar'])
74130
+ .event-calendar-day-number {
73616
74131
  font-size: 0.75rem;
73617
74132
  margin-bottom: 0.125rem;
73618
74133
  padding: 0 0.125rem;
73619
74134
  }
73620
74135
 
73621
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-event {
74136
+ :where(.theme-scope)
74137
+ :where([data-block='event-calendar'])
74138
+ .event-calendar-event {
73622
74139
  justify-content: center;
73623
74140
  gap: 0.25rem;
73624
74141
  padding: 0.1875rem 0.25rem;
@@ -73626,25 +74143,34 @@ const containerResponsiveThemeCss = `/*
73626
74143
  border-radius: calc(var(--rb-block-radius) / 3);
73627
74144
  }
73628
74145
 
73629
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-event-time {
74146
+ :where(.theme-scope)
74147
+ :where([data-block='event-calendar'])
74148
+ .event-calendar-event-time {
73630
74149
  text-align: center;
73631
74150
  font-size: 0.625rem;
73632
74151
  }
73633
74152
 
73634
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-event-title {
74153
+ :where(.theme-scope)
74154
+ :where([data-block='event-calendar'])
74155
+ .event-calendar-event-title {
73635
74156
  display: none;
73636
74157
  }
73637
74158
 
73638
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-more {
74159
+ :where(.theme-scope)
74160
+ :where([data-block='event-calendar'])
74161
+ .event-calendar-more {
73639
74162
  padding: 0.125rem 0.25rem;
73640
74163
  font-size: 0.6875rem;
73641
74164
  }
73642
74165
 
73643
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-header > button {
74166
+ :where(.theme-scope)
74167
+ :where([data-block='event-calendar'])
74168
+ .event-calendar-header
74169
+ > button {
73644
74170
  margin-right: 0.25rem;
73645
74171
  }
73646
74172
 
73647
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal {
74173
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal {
73648
74174
  max-width: 100%;
73649
74175
  max-height: 85vh;
73650
74176
  margin: 0 0.5rem;
@@ -78665,6 +79191,82 @@ const SUPPORTED_LOADER_ENDPOINTS$1 = [
78665
79191
  "getPublicBookingServices",
78666
79192
  "getPublicWeeklySlotAvailability"
78667
79193
  ];
79194
+ function isSupportedLoaderEndpoint$1(endpoint) {
79195
+ return SUPPORTED_LOADER_ENDPOINTS$1.includes(endpoint);
79196
+ }
79197
+ //#endregion
79198
+ //#region ../blocks/src/system/data/publicLoaderCachePolicy.ts
79199
+ /**
79200
+ * Canonical freshness policy for public block-loader data.
79201
+ *
79202
+ * Consumers may implement tagged caching differently, but a loader marked
79203
+ * live here must not be placed in a process-local or durable stale cache.
79204
+ */
79205
+ const PUBLIC_LOADER_CACHE_POLICIES = {
79206
+ listPublishedEntries: {
79207
+ kind: "tagged",
79208
+ tags: ["published_content"]
79209
+ },
79210
+ getPublishedEntryPreview: {
79211
+ kind: "tagged",
79212
+ tags: ["published_content"]
79213
+ },
79214
+ listPublicEvents: {
79215
+ kind: "live",
79216
+ reason: "booking_correctness"
79217
+ },
79218
+ listPublicRecurringSchedule: {
79219
+ kind: "live",
79220
+ reason: "booking_correctness"
79221
+ },
79222
+ getPublicEventDetails: {
79223
+ kind: "live",
79224
+ reason: "booking_correctness"
79225
+ },
79226
+ listPublicWholeSeriesOfferings: {
79227
+ kind: "tagged",
79228
+ tags: ["public_whole_series_offerings"]
79229
+ },
79230
+ getPublicWholeSeriesOffering: {
79231
+ kind: "tagged",
79232
+ tags: ["public_whole_series_offerings"]
79233
+ },
79234
+ listPublicRouteCandidates: {
79235
+ kind: "tagged",
79236
+ tags: ["published_content"]
79237
+ },
79238
+ listPublicTeamMembers: {
79239
+ kind: "tagged",
79240
+ tags: ["public_team_members"]
79241
+ },
79242
+ listPublicProducts: {
79243
+ kind: "tagged",
79244
+ tags: ["public_products"]
79245
+ },
79246
+ listPublicPasses: {
79247
+ kind: "live",
79248
+ reason: "booking_correctness"
79249
+ },
79250
+ listPublicMemberships: {
79251
+ kind: "live",
79252
+ reason: "booking_correctness"
79253
+ },
79254
+ getPublicFormById: {
79255
+ kind: "tagged",
79256
+ tags: ["site_forms"]
79257
+ },
79258
+ getPublicBookingServices: {
79259
+ kind: "live",
79260
+ reason: "booking_correctness"
79261
+ },
79262
+ getPublicWeeklySlotAvailability: {
79263
+ kind: "live",
79264
+ reason: "booking_correctness"
79265
+ }
79266
+ };
79267
+ function getPublicLoaderCachePolicy(endpoint) {
79268
+ return PUBLIC_LOADER_CACHE_POLICIES[endpoint];
79269
+ }
78668
79270
  //#endregion
78669
79271
  //#region ../blocks/src/system/data/batching.ts
78670
79272
  function stableNormalize(value) {
@@ -80744,6 +81346,7 @@ function buildSiteRenderSupport(site, mediaAssets) {
80744
81346
  site: site.site,
80745
81347
  sdkConfig: site.sdkConfig ?? null,
80746
81348
  bookingOfferingPresets: site.bookingOfferingPresets ?? [],
81349
+ bookingTimeZone: site.bookingTimeZone ?? "UTC",
80747
81350
  ...customBlocks ? { customBlocks } : {},
80748
81351
  supabaseUrl: site.supabaseUrl,
80749
81352
  routeMap: site.routes,
@@ -80760,14 +81363,21 @@ function convertPageResponseBlock(block) {
80760
81363
  if (typeof block.id !== "string" && block.id !== null) throw new Error(`Invalid block id in page: expected string or null, got ${typeof block.id}`);
80761
81364
  if (typeof block.kind !== "string") throw new Error(`Invalid block kind in page: expected string, got ${typeof block.kind}`);
80762
81365
  if (typeof block.purpose !== "string") throw new Error(`Invalid block purpose in page: expected string, got ${typeof block.purpose}`);
81366
+ const admission = readInvalidBlockAdmission(block.admission);
80763
81367
  return {
80764
81368
  id: block.id,
80765
81369
  kind: block.kind,
80766
81370
  purpose: block.purpose,
80767
81371
  content: sanitizeSdkRuntimeBlockContent(block.kind, readContentRecord(block.content) ?? {}),
80768
- draftContent: sanitizeNullableSdkRuntimeBlockContent(block.kind, readNestedContentRecord(block.draftContent))
81372
+ draftContent: sanitizeNullableSdkRuntimeBlockContent(block.kind, readNestedContentRecord(block.draftContent)),
81373
+ ...admission ? { admission } : {}
80769
81374
  };
80770
81375
  }
81376
+ function readInvalidBlockAdmission(value) {
81377
+ if (!isRecord$5(value) || value.kind !== "invalid" || !isRecord$5(value.error)) return null;
81378
+ if (value.error.kind !== "invalid_manifest_content" && value.error.kind !== "manifest_unavailable") return null;
81379
+ return value;
81380
+ }
80771
81381
  function buildPageOutline(input) {
80772
81382
  return {
80773
81383
  name: input.name,
@@ -80776,6 +81386,63 @@ function buildPageOutline(input) {
80776
81386
  blocks: input.blocks.map(convertPageResponseBlock)
80777
81387
  };
80778
81388
  }
81389
+ function buildRenderablePageOutline(input) {
81390
+ const page = buildPageOutline(input);
81391
+ return {
81392
+ ...page,
81393
+ blocks: page.blocks.map((block) => admitSdkRuntimePageBlock(block, input.customBlocks))
81394
+ };
81395
+ }
81396
+ function projectRenderablePageOutline(page) {
81397
+ return {
81398
+ ...page,
81399
+ blocks: page.blocks.flatMap((block) => block.admission.kind === "renderable" ? [{
81400
+ id: block.id,
81401
+ kind: block.kind,
81402
+ purpose: block.purpose,
81403
+ content: block.admission.content,
81404
+ ...block.bindings ? { bindings: block.bindings } : {}
81405
+ }] : [])
81406
+ };
81407
+ }
81408
+ function admitSdkRuntimePageBlock(block, customBlocks) {
81409
+ const base = {
81410
+ id: block.id,
81411
+ kind: block.kind,
81412
+ purpose: block.purpose,
81413
+ ...block.bindings ? { bindings: block.bindings } : {}
81414
+ };
81415
+ const transportedAdmission = readInvalidBlockAdmission(block.admission);
81416
+ if (transportedAdmission) return invalidRenderableBlock(base, transportedAdmission.error);
81417
+ const manifest = resolveSdkBlockManifest(block.kind, customBlocks);
81418
+ if (!manifest) return invalidRenderableBlock(base, { kind: "manifest_unavailable" });
81419
+ const content = block.content ?? {};
81420
+ const renderable = admitTransportedRenderableManifestContent(compileManifestContentContract(manifest), content);
81421
+ if (!renderable.ok) return invalidRenderableBlock(base, {
81422
+ kind: "invalid_manifest_content",
81423
+ error: renderable.error
81424
+ });
81425
+ return {
81426
+ ...base,
81427
+ admission: {
81428
+ kind: "renderable",
81429
+ content: renderable.value
81430
+ }
81431
+ };
81432
+ }
81433
+ function resolveSdkBlockManifest(blockKind, customBlocks) {
81434
+ const customBlock = customBlocks?.find((candidate) => candidate.id === blockKind);
81435
+ return customBlock ? parseFieldDefinitions(customBlock.fields) : getBlockDefinition(blockKind)?.manifest ?? null;
81436
+ }
81437
+ function invalidRenderableBlock(block, error) {
81438
+ return {
81439
+ ...block,
81440
+ admission: {
81441
+ kind: "invalid",
81442
+ error
81443
+ }
81444
+ };
81445
+ }
80779
81446
  function isRecord$5(value) {
80780
81447
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
80781
81448
  }
@@ -82089,6 +82756,7 @@ const DEFAULT_TEMPLATE_DEFINITIONS = {
82089
82756
  {
82090
82757
  blockKind: "block.body-text",
82091
82758
  scope: "entry",
82759
+ content: { body: createRichTextDoc([""]) },
82092
82760
  bindings: EVENT_BODY_TEXT_BINDINGS
82093
82761
  },
82094
82762
  {
@@ -82135,6 +82803,7 @@ const DEFAULT_TEMPLATE_DEFINITIONS = {
82135
82803
  }, {
82136
82804
  blockKind: "block.body-text",
82137
82805
  scope: "entry",
82806
+ content: { body: createRichTextDoc([""]) },
82138
82807
  bindings: TEAM_MEMBER_BODY_TEXT_BINDINGS
82139
82808
  }]
82140
82809
  },
@@ -83269,6 +83938,14 @@ const isRecord$1 = isRecord$26;
83269
83938
  const applyBindingsToContent = applyBindingsToContent$1;
83270
83939
  //#endregion
83271
83940
  //#region src/rendering/helpers/templateContent.ts
83941
+ function admitMaterializedSdkTemplateBlockContent(input) {
83942
+ const baseContent = sanitizeSdkRuntimeBlockContent(input.block.blockKind, input.block.content ?? {});
83943
+ const bindings = input.block.bindings ?? {};
83944
+ const materialized = input.block.scope === "entry" && Object.keys(bindings).length > 0 ? applyBindingsToContent(baseContent, bindings, input.bindingContext) : baseContent;
83945
+ const contract = compileManifestContentContract(input.manifestOrFields);
83946
+ const stored = admitStoredManifestContent(contract, materialized);
83947
+ return stored.ok ? deriveRenderableManifestContent(contract, stored.value, (content) => content) : stored;
83948
+ }
83272
83949
  function createTemplateRenderTarget(source, templateId) {
83273
83950
  switch (source.kind) {
83274
83951
  case "entry-template": return {
@@ -83319,7 +83996,12 @@ async function processTemplatePage(input) {
83319
83996
  templatePage: null,
83320
83997
  resolvedData: {}
83321
83998
  };
83322
- const blocks = template.blocks.flatMap((block) => resolveTemplateBlockSequence(block, input.bindingContext, input.slotContent));
83999
+ const blocks = template.blocks.flatMap((block) => resolveTemplateBlockSequence({
84000
+ block,
84001
+ bindingContext: input.bindingContext,
84002
+ slotContent: input.slotContent,
84003
+ customBlocks: input.customBlocks
84004
+ }));
83323
84005
  if (blocks.length === 0) return {
83324
84006
  templatePage: null,
83325
84007
  resolvedData: {}
@@ -83333,7 +84015,7 @@ async function processTemplatePage(input) {
83333
84015
  return {
83334
84016
  templatePage,
83335
84017
  resolvedData: await resolveBlockDataWithDeps(input.deps, {
83336
- page: templatePage,
84018
+ page: projectRenderablePageOutline(templatePage),
83337
84019
  siteId: input.siteId,
83338
84020
  renderTarget: createTemplateRenderTarget(input.renderTargetSource, template.id),
83339
84021
  previewStage: input.previewStage,
@@ -83343,58 +84025,74 @@ async function processTemplatePage(input) {
83343
84025
  })
83344
84026
  };
83345
84027
  }
83346
- function resolveTemplateBlockSequence(block, bindingContext, slotContent) {
84028
+ function resolveTemplateBlockSequence(input) {
84029
+ const { block } = input;
83347
84030
  const slotKey = readEntrySlotKey(block);
83348
84031
  if (slotKey) return selectBlocksForDeclaredEntrySlot({
83349
84032
  declaredSlotKey: slotKey,
83350
- entrySlots: slotContent ?? []
83351
- }).map(mapEntrySlotBlock);
84033
+ entrySlots: input.slotContent ?? []
84034
+ }).map((slotBlock) => admitEntrySlotBlock(slotBlock, input.customBlocks));
83352
84035
  if (block.blockKind === "system.entry-slot") return [];
83353
- return [resolveTemplateBlock(block, bindingContext)];
84036
+ return [resolveTemplateBlock(block, input.bindingContext, input.customBlocks)];
83354
84037
  }
83355
- function resolveTemplateBlock(block, bindingContext) {
83356
- const baseContent = sanitizeSdkRuntimeBlockContent(block.blockKind, block.content ?? {});
83357
- if (block.scope === "template") return {
83358
- id: block.id,
83359
- kind: block.blockKind,
83360
- purpose: "template-layout",
83361
- content: baseContent
83362
- };
83363
- const bindings = block.bindings ?? {};
83364
- const resolvedContent = Object.keys(bindings).length > 0 ? applyBindingsToContent(baseContent, bindings, bindingContext) : baseContent;
83365
- return {
84038
+ function resolveTemplateBlock(block, bindingContext, customBlocks) {
84039
+ const base = {
83366
84040
  id: block.id,
83367
84041
  kind: block.blockKind,
83368
- purpose: "entry-content",
83369
- content: resolvedContent
83370
- };
84042
+ purpose: block.scope === "template" ? "template-layout" : "entry-content",
84043
+ ...isRecord$1(block.bindings) ? { bindings: block.bindings } : {}
84044
+ };
84045
+ const manifest = resolveSdkBlockManifest(block.blockKind, customBlocks);
84046
+ if (manifest === null) return invalidRenderableBlock(base, { kind: "manifest_unavailable" });
84047
+ const admission = admitMaterializedSdkTemplateBlockContent({
84048
+ block,
84049
+ bindingContext,
84050
+ manifestOrFields: manifest
84051
+ });
84052
+ return admission.ok ? {
84053
+ ...base,
84054
+ admission: {
84055
+ kind: "renderable",
84056
+ content: admission.value
84057
+ }
84058
+ } : invalidRenderableBlock(base, {
84059
+ kind: "invalid_manifest_content",
84060
+ error: admission.error
84061
+ });
83371
84062
  }
83372
84063
  function readEntrySlotKey(block) {
83373
84064
  if (block.blockKind !== "system.entry-slot" || block.scope !== "template") return null;
83374
84065
  const parsed = parseSlotKey(block.content?.slotKey);
83375
84066
  return parsed.ok ? parsed.value : null;
83376
84067
  }
83377
- function mapEntrySlotBlock(block) {
83378
- const mapped = {
84068
+ function admitEntrySlotBlock(block, customBlocks) {
84069
+ const base = {
83379
84070
  id: block.id ?? block.blockId ?? null,
83380
84071
  kind: block.kind,
83381
84072
  purpose: block.purpose,
83382
- orderIndex: block.orderIndex ?? null,
83383
- content: normalizeEntrySlotBlockContent(block.content),
83384
- draftContent: normalizeNullableEntrySlotContent(block.draftContent),
83385
- publishedContent: normalizeNullableEntrySlotContent(block.publishedContent)
83386
- };
83387
- return block.bindings == null ? mapped : {
83388
- ...mapped,
83389
- bindings: block.bindings
83390
- };
83391
- }
83392
- function normalizeNullableEntrySlotContent(content) {
83393
- return content == null ? null : normalizeEntrySlotBlockContent(content);
83394
- }
83395
- function normalizeEntrySlotBlockContent(content) {
83396
- const value = content ?? {};
83397
- return isRecord$1(value) ? value : {};
84073
+ ...isRecord$1(block.bindings) ? { bindings: block.bindings } : {}
84074
+ };
84075
+ const transportedAdmission = readInvalidBlockAdmission(block.admission);
84076
+ if (transportedAdmission) return invalidRenderableBlock(base, transportedAdmission.error);
84077
+ const manifest = resolveSdkBlockManifest(block.kind, customBlocks);
84078
+ if (manifest === null) return invalidRenderableBlock(base, { kind: "manifest_unavailable" });
84079
+ const contract = compileManifestContentContract(manifest);
84080
+ const stored = admitStoredManifestContent(contract, block.content ?? {});
84081
+ if (!stored.ok) return invalidRenderableBlock(base, {
84082
+ kind: "invalid_manifest_content",
84083
+ error: stored.error
84084
+ });
84085
+ const renderable = deriveRenderableManifestContent(contract, stored.value, (content) => content);
84086
+ return renderable.ok ? {
84087
+ ...base,
84088
+ admission: {
84089
+ kind: "renderable",
84090
+ content: renderable.value
84091
+ }
84092
+ } : invalidRenderableBlock(base, {
84093
+ kind: "invalid_manifest_content",
84094
+ error: renderable.error
84095
+ });
83398
84096
  }
83399
84097
  //#endregion
83400
84098
  //#region src/rendering/helpers/loadContent.ts
@@ -83423,6 +84121,7 @@ function getRejectedReason(result) {
83423
84121
  function toTemplateContentRenderSupport(support, siteId) {
83424
84122
  return {
83425
84123
  bookingOfferingPresets: support.bookingOfferingPresets,
84124
+ bookingTimeZone: support.bookingTimeZone,
83426
84125
  ...support.customBlocks ? { customBlocks: support.customBlocks } : {},
83427
84126
  entriesByIdentifier: support.entriesByIdentifier,
83428
84127
  ...support.mediaAssets ? { mediaAssets: support.mediaAssets } : {},
@@ -83565,7 +84264,6 @@ async function loadContentFromContentResponseWithDeps(deps, params) {
83565
84264
  entry,
83566
84265
  templatePage,
83567
84266
  resolvedData,
83568
- bookingOfferingPresets: support.bookingOfferingPresets,
83569
84267
  dataContext: { contentEntry: {
83570
84268
  ...entry.content ?? {},
83571
84269
  id: entry.id,
@@ -83634,7 +84332,6 @@ async function loadContentFromContentResponseWithDeps(deps, params) {
83634
84332
  pageSurface,
83635
84333
  templatePage,
83636
84334
  resolvedData,
83637
- bookingOfferingPresets: support.bookingOfferingPresets,
83638
84335
  dataContext: {
83639
84336
  pageSurface: {
83640
84337
  ...pageSurface.content ?? {},
@@ -83653,15 +84350,16 @@ async function loadContentFromContentResponseWithDeps(deps, params) {
83653
84350
  const pageRecord = pageData;
83654
84351
  const canonicalPagePath = pageData.path ?? pageRecord.path ?? "/";
83655
84352
  const draftPagePath = pageRecord.draftPath ?? pageRecord.path ?? canonicalPagePath;
83656
- const pageOutline = buildPageOutline({
84353
+ const pageOutline = buildRenderablePageOutline({
83657
84354
  name: pageData.name,
83658
84355
  path: canonicalPagePath,
83659
84356
  fallbackPath: "/",
83660
84357
  purpose: pageData.purpose,
83661
- blocks: pageData.blocks
84358
+ blocks: pageData.blocks,
84359
+ customBlocks: support.customBlocks
83662
84360
  });
83663
84361
  const resolvedData = await resolveBlockDataWithDeps(deps, {
83664
- page: pageOutline,
84362
+ page: projectRenderablePageOutline(pageOutline),
83665
84363
  siteId,
83666
84364
  renderTarget: {
83667
84365
  kind: "page",
@@ -83697,6 +84395,7 @@ async function loadContentFromContentResponseWithDeps(deps, params) {
83697
84395
  ...support.customBlocks ? { customBlocks: support.customBlocks } : {},
83698
84396
  resolvedData,
83699
84397
  bookingOfferingPresets: support.bookingOfferingPresets,
84398
+ bookingTimeZone: support.bookingTimeZone,
83700
84399
  site: support.site,
83701
84400
  sdkConfig: support.sdkConfig,
83702
84401
  supabaseUrl: support.supabaseUrl,
@@ -83772,16 +84471,21 @@ function toBlocksPageRendererDataContext(dataContext) {
83772
84471
  imageResolveContext: toBlocksImageResolveContextInput(dataContext.imageResolveContext)
83773
84472
  };
83774
84473
  }
83775
- function PageRenderer(props) {
83776
- const blocksSdkConfig = props.sdkConfig ? { customBlocks: normalizeSdkCustomBlocks(props.sdkConfig.customBlocks) } : props.sdkConfig;
83777
- const { rendering: _rendering, theme: _theme, themeTokens: _themeTokens, ...commonProps } = props;
83778
- const commonBlocksProps = {
83779
- ...commonProps,
84474
+ function toBlocksCommonProps(props) {
84475
+ return {
84476
+ page: props.page,
84477
+ runtimeBoundaries: props.runtimeBoundaries,
83780
84478
  dataContext: props.dataContext ? toBlocksPageRendererDataContext(props.dataContext) : void 0,
84479
+ routeMap: props.routeMap,
84480
+ wrapBlock: props.wrapBlock,
84481
+ registry: props.registry,
83781
84482
  blockOverrides: toBlocksBlockOverrides(props.blockOverrides),
83782
- sdkConfig: blocksSdkConfig,
84483
+ sdkConfig: props.sdkConfig ? { customBlocks: normalizeSdkCustomBlocks(props.sdkConfig.customBlocks) } : props.sdkConfig,
83783
84484
  customBlocks: normalizeSdkCustomBlocks(props.customBlocks)
83784
84485
  };
84486
+ }
84487
+ function PageRenderer(props) {
84488
+ const commonBlocksProps = toBlocksCommonProps(props);
83785
84489
  const blocksProps = isOverrideOnlyPageRenderer(props) ? {
83786
84490
  ...commonBlocksProps,
83787
84491
  rendering: { kind: "overrides-only" },
@@ -83853,12 +84557,14 @@ function toPageHydrationBootstrapConfig(props) {
83853
84557
  mediaAssets: props.mediaAssets
83854
84558
  };
83855
84559
  }
84560
+ function resolveSdkBookingTimeZone(timeZone) {
84561
+ return timeZone ?? "UTC";
84562
+ }
83856
84563
  function PageContent(props) {
83857
- const { page, runtimeBoundaries, siteId, resolvedData, bookingOfferingPresets, routeMap, pagesByIdentifier, entriesByIdentifier, wrapBlock, registry, usePlaceholders = false, blockOverrides, sdkConfig, customBlocks, supabaseUrl, mediaAssets, apiBaseUrl, portalToken, previewToken, dataContext } = props;
84564
+ const { page, runtimeBoundaries, siteId, resolvedData, bookingOfferingPresets, bookingTimeZone, routeMap, pagesByIdentifier, entriesByIdentifier, wrapBlock, registry, blockOverrides, sdkConfig, customBlocks, supabaseUrl, mediaAssets, apiBaseUrl, portalToken, previewToken, dataContext } = props;
83858
84565
  const rendererCommonProps = {
83859
84566
  page,
83860
84567
  runtimeBoundaries,
83861
- usePlaceholders,
83862
84568
  dataContext: {
83863
84569
  siteId,
83864
84570
  apiBaseUrl,
@@ -83866,6 +84572,7 @@ function PageContent(props) {
83866
84572
  previewToken,
83867
84573
  resolvedData,
83868
84574
  bookingOfferingPresets: bookingOfferingPresets ?? [],
84575
+ bookingTimeZone: resolveSdkBookingTimeZone(bookingTimeZone),
83869
84576
  routes: routeMap,
83870
84577
  pagesByIdentifier,
83871
84578
  entriesByIdentifier,
@@ -85076,7 +85783,7 @@ var CircuitOpenError = class extends Error {
85076
85783
  * 1. This constant
85077
85784
  * 2. The "version" field in package.json
85078
85785
  */
85079
- const SDK_VERSION = "0.135.1";
85786
+ const SDK_VERSION = "0.136.0";
85080
85787
  //#endregion
85081
85788
  //#region src/next/content-load-failure.ts
85082
85789
  const SdkContentLoadError = RiverbankContentLoadError;
@@ -85341,6 +86048,7 @@ async function renderPage(input, page, dataContext) {
85341
86048
  portalToken: input.portalToken,
85342
86049
  resolvedData: input.content.resolvedData,
85343
86050
  bookingOfferingPresets: input.content.bookingOfferingPresets,
86051
+ bookingTimeZone: input.content.bookingTimeZone,
85344
86052
  sdkConfig: input.content.sdkConfig,
85345
86053
  supabaseUrl: input.content.supabaseUrl,
85346
86054
  mediaAssets: input.content.mediaAssets,
@@ -86249,6 +86957,11 @@ function resolveKnownEndpointPolicy(endpoint, params) {
86249
86957
  endpoint,
86250
86958
  reason: "force_refresh"
86251
86959
  };
86960
+ if (isSupportedLoaderEndpoint$1(endpoint) && getPublicLoaderCachePolicy(endpoint).kind === "live") return {
86961
+ kind: "live-only",
86962
+ endpoint,
86963
+ reason: "safety_sensitive_booking"
86964
+ };
86252
86965
  const override = RUNTIME_CACHE_DURABILITY_OVERRIDES[endpoint];
86253
86966
  if (override.kind === "live-only") return {
86254
86967
  kind: "live-only",
@@ -86463,6 +87176,17 @@ function combineAbortSignals(...signals) {
86463
87176
  return controller.signal;
86464
87177
  }
86465
87178
  //#endregion
87179
+ //#region src/client/publicLoaderCacheAccess.ts
87180
+ function shouldWrite(cacheEnabled, force) {
87181
+ return cacheEnabled && !force;
87182
+ }
87183
+ function liveLoaderOptions(endpoint, signal) {
87184
+ return {
87185
+ force: getPublicLoaderCachePolicy(endpoint).kind === "live",
87186
+ signal
87187
+ };
87188
+ }
87189
+ //#endregion
86466
87190
  //#region src/client/index.ts
86467
87191
  let prebuildModule = null;
86468
87192
  function tryRequire(modulePath) {
@@ -86930,7 +87654,7 @@ function createRiverbankClientWithDeps(deps, config) {
86930
87654
  } catch (error) {
86931
87655
  convertToTypedError(error);
86932
87656
  }
86933
- if (cacheEnabled) cache.set(cacheKey, data);
87657
+ if (shouldWrite(cacheEnabled, options.force)) cache.set(cacheKey, data);
86934
87658
  if (allowFallbacks && !isPreview) await writePublishedRuntimeCache(options.publishedRuntimeCache, data);
86935
87659
  return emitStatus("live", data, statusDetails());
86936
87660
  } catch (error) {
@@ -87168,7 +87892,7 @@ function createRiverbankClientWithDeps(deps, config) {
87168
87892
  },
87169
87893
  options: { signal: sig }
87170
87894
  });
87171
- }, { signal });
87895
+ }, liveLoaderOptions("listPublicEvents", signal));
87172
87896
  },
87173
87897
  async getPublicEventDetails(params) {
87174
87898
  const { siteId, limit, from, to, afterStartsAt, afterId, stage, categoryIds, venueId, staffMemberId, kind, eventSurface, eventPresets, scheduleScope, seriesId, includeOccurrenceId, signal } = params;
@@ -87203,7 +87927,7 @@ function createRiverbankClientWithDeps(deps, config) {
87203
87927
  }] },
87204
87928
  options: { signal: sig }
87205
87929
  }), requestId);
87206
- }, { signal });
87930
+ }, liveLoaderOptions("getPublicEventDetails", signal));
87207
87931
  },
87208
87932
  async listPublicTeamMembers(params) {
87209
87933
  const { siteId, stage, signal } = params;