@riverbankcms/sdk 0.135.0 → 0.136.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (153) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/README.md +4 -8
  3. package/dist/{PreviewEditorSidebar-roNY0GVy.mjs → PreviewEditorSidebar-BU5ZlhQR.mjs} +4 -4
  4. package/dist/{PreviewEditorUI-KboDbEh_.mjs → PreviewEditorUI-9XkHL-bC.mjs} +3 -3
  5. package/dist/{PreviewQueryProvider-DcgaESkm.mjs → PreviewQueryProvider-wbEpXryy.mjs} +1 -1
  6. package/dist/{SdkPreviewModeRuntime-DBrF7Caa.mjs → SdkPreviewModeRuntime-CnWmj-2B.mjs} +50 -99
  7. package/dist/{SiteChromeCustomizeContext-DrIEpJKn.mjs → SiteChromeCustomizeContext-B6d5zkog.mjs} +2334 -1173
  8. package/dist/_dts/ai/src/contracts/proposals.d.ts +8 -554
  9. package/dist/_dts/ai/src/contracts/siteStyleProposalSchemas.d.ts +401 -2312
  10. package/dist/_dts/api/src/contentRuntime.d.ts +6 -0
  11. package/dist/_dts/api/src/endpoints.d.ts +7 -0
  12. package/dist/_dts/api/src/index.d.ts +1 -0
  13. package/dist/_dts/api/src/publicEventEndpointDefinitions.d.ts +7 -0
  14. package/dist/_dts/api/src/publicExperience/eventEndpoints.d.ts +26 -0
  15. package/dist/_dts/api/src/sdkBlockContentAdmission.d.ts +5 -0
  16. package/dist/_dts/api/src/sdkThemeWire.d.ts +6 -432
  17. package/dist/_dts/block-form/src/blockDraftSaveability.d.ts +2 -3
  18. package/dist/_dts/block-form/src/utils/slug.d.ts +6 -0
  19. package/dist/_dts/blocks/src/PageRenderer.d.ts +12 -6
  20. package/dist/_dts/blocks/src/contracts/proof-block-islands.d.ts +48 -0
  21. package/dist/_dts/blocks/src/definitions.d.ts +14 -0
  22. package/dist/_dts/blocks/src/index.d.ts +4 -3
  23. package/dist/_dts/blocks/src/pageRenderAdmission.d.ts +40 -0
  24. package/dist/_dts/blocks/src/server.d.ts +2 -2
  25. package/dist/_dts/blocks/src/system/blocks/events/shared/schemas.d.ts +25 -0
  26. package/dist/_dts/blocks/src/system/data/index.d.ts +2 -0
  27. package/dist/_dts/blocks/src/system/data/publicLoaderCachePolicy.d.ts +78 -0
  28. package/dist/_dts/blocks/src/system/manifest/fieldValidation/index.d.ts +2 -18
  29. package/dist/_dts/blocks/src/system/manifest/validation.d.ts +103 -16
  30. package/dist/_dts/blocks/src/system/node/validation-constants.d.ts +1 -1
  31. package/dist/_dts/blocks/src/system/runtime/api/client.d.ts +2 -1
  32. package/dist/_dts/blocks/src/system/runtime/api/endpoints.d.ts +8 -0
  33. package/dist/_dts/blocks/src/system/runtime/api/index.d.ts +1 -1
  34. package/dist/_dts/blocks/src/system/runtime/api/types/events.d.ts +19 -0
  35. package/dist/_dts/blocks/src/system/runtime/components/registry.client.d.ts +52 -0
  36. package/dist/_dts/blocks/src/system/runtime/components/runtime-backed-blocks.d.ts +24 -0
  37. package/dist/_dts/blocks/src/system/runtime/hooks/useCalendarEvents.d.ts +44 -18
  38. package/dist/_dts/blocks/src/system/runtime/hooks/useCalendarEvents.state.d.ts +20 -3
  39. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/VerifyingTimeoutStep.d.ts +3 -1
  40. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/useEventRegistrationStripeReturn.d.ts +1 -0
  41. package/dist/_dts/blocks/src/system/runtime/nodes/events/EventCalendar.client.d.ts +2 -2
  42. package/dist/_dts/blocks/src/system/runtime/nodes/events/EventCalendar.interactive.d.ts +40 -0
  43. package/dist/_dts/blocks/src/system/runtime/nodes/events/EventCombined.client.d.ts +2 -0
  44. package/dist/_dts/blocks/src/system/runtime/nodes/events/EventCombined.interactive.d.ts +43 -0
  45. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/CalendarDayCell.d.ts +3 -1
  46. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/CalendarNavigationChevron.d.ts +4 -0
  47. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/DayEventsModal.d.ts +2 -1
  48. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/EventModalContext.d.ts +3 -2
  49. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/WeekAgendaView.d.ts +3 -0
  50. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/WeekBoardView.d.ts +31 -3
  51. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/WeekTimetableView.d.ts +3 -1
  52. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/eventCollectionContract.d.ts +19 -1
  53. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/timetableModel.d.ts +4 -3
  54. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/utils.d.ts +3 -3
  55. package/dist/_dts/blocks/src/system/transforms/registry/layout.d.ts +0 -1
  56. package/dist/_dts/calendar/src/grid.d.ts +24 -66
  57. package/dist/_dts/calendar/src/index.d.ts +2 -2
  58. package/dist/_dts/calendar/src/timetable.d.ts +5 -9
  59. package/dist/_dts/commerce/src/purchase/allocation.d.ts +11 -0
  60. package/dist/_dts/commerce/src/purchase/index.d.ts +2 -0
  61. package/dist/_dts/commerce/src/purchase/settlement.d.ts +33 -0
  62. package/dist/_dts/commerce/src/purchase/stripeCheckoutReturnUrl.d.ts +8 -0
  63. package/dist/_dts/content-model/src/templates/defaults.d.ts +6 -0
  64. package/dist/_dts/core/src/slug.d.ts +20 -5
  65. package/dist/_dts/preview-next/src/client/blocks/EditablePageRenderer.d.ts +1 -1
  66. package/dist/_dts/preview-next/src/client/preview/headerInteractionPaletteSurfaceState.d.ts +2 -1
  67. package/dist/_dts/sdk/src/client/publicLoaderCacheAccess.d.ts +6 -0
  68. package/dist/_dts/sdk/src/public-api/contracts.d.ts +5 -1
  69. package/dist/_dts/sdk/src/rendering/blocks-page-renderer.d.ts +10 -6
  70. package/dist/_dts/sdk/src/rendering/components/Block.shared.d.ts +0 -1
  71. package/dist/_dts/sdk/src/rendering/components/pageShared.d.ts +4 -4
  72. package/dist/_dts/sdk/src/rendering/helpers/footerPageOutline.d.ts +3 -0
  73. package/dist/_dts/sdk/src/rendering/helpers/loadContent.d.ts +3 -0
  74. package/dist/_dts/sdk/src/rendering/helpers/loadPage.d.ts +1 -1
  75. package/dist/_dts/sdk/src/rendering/helpers/pageRuntimeSupport.d.ts +17 -0
  76. package/dist/_dts/sdk/src/rendering/helpers/templateContent.d.ts +9 -3
  77. package/dist/_dts/sdk/src/rendering/hooks/usePage.d.ts +1 -1
  78. package/dist/_dts/sdk/src/rendering/index.d.ts +2 -2
  79. package/dist/_dts/sdk/src/rendering/overrideResolution.d.ts +7 -4
  80. package/dist/_dts/sdk/src/version.d.ts +1 -1
  81. package/dist/_dts/theme-core/src/cards/types.d.ts +8 -8
  82. package/dist/_dts/theme-core/src/data.d.ts +12 -0
  83. package/dist/_dts/theme-core/src/generated/containerResponsiveThemeCss.d.ts +1 -1
  84. package/dist/_dts/theme-core/src/header/legacyHeaderVariant.d.ts +2 -6
  85. package/dist/_dts/theme-core/src/mock-themes/all.d.ts +6 -807
  86. package/dist/_dts/theme-core/src/schema.d.ts +452 -1278
  87. package/dist/_dts/theme-core/src/site-styles/curatedSiteStyles.d.ts +213 -1
  88. package/dist/_dts/theme-core/src/site-styles/headerLayoutCatalog.d.ts +0 -29
  89. package/dist/_dts/theme-core/src/site-styles/headerLayoutStyles.d.ts +10 -0
  90. package/dist/_dts/theme-core/src/site-styles/headerLayoutTypes.d.ts +8 -5
  91. package/dist/_dts/theme-core/src/site-styles/headerOpeningForeground.d.ts +4 -4
  92. package/dist/_dts/theme-core/src/site-styles/headerStyleCompiler.d.ts +16 -2
  93. package/dist/_dts/theme-core/src/site-styles/headerStyleDefaults.d.ts +465 -0
  94. package/dist/_dts/theme-core/src/site-styles/headerStyleRecipe.d.ts +161 -0
  95. package/dist/client/{BookingConsentAgreement-BQqwi8Oa.mjs → BookingConsentAgreement-DCch21a6.mjs} +2 -2
  96. package/dist/client/{DiscountCodeDisclosure-B97aMo0V.mjs → DiscountCodeDisclosure-DIj1T59K.mjs} +1 -1
  97. package/dist/client/{EventCombined.client-Bs2Iw9Q6.mjs → EventCombined.client-BWVNlXTx.mjs} +226 -206
  98. package/dist/client/{EventListing.client-C4QUQdmg.mjs → EventListing.client-DVFCDe3i.mjs} +2 -2
  99. package/dist/client/{LeafletStaticMap-CwWRk69M.mjs → LeafletStaticMap-BY5mIHw9.mjs} +1 -1
  100. package/dist/client/{accordion-BA0j8Mpw.mjs → accordion-CK29E8rG.mjs} +1 -1
  101. package/dist/client/{bookingForm-Br2e41H0.mjs → bookingForm-DFvnet-N.mjs} +5 -5
  102. package/dist/client/bookings.mjs +87 -47
  103. package/dist/client/{carousel-B4dmwnpD.mjs → carousel-BVU5NQlb.mjs} +1 -1
  104. package/dist/client/{cart-B_ckGW4b.mjs → cart-BNItcZVa.mjs} +3 -3
  105. package/dist/client/{checkout-DAyspHdf.mjs → checkout-Bu6iCdkP.mjs} +3 -3
  106. package/dist/client/client.mjs +1985 -1055
  107. package/dist/client/{context-DljQn8L5.mjs → context-BImarOAq.mjs} +12 -0
  108. package/dist/client/{eventCalendar-pJu3FUod.mjs → eventCalendar-DS2h-UXD.mjs} +256 -114
  109. package/dist/client/{eventCombined-B6Kacm9F.mjs → eventCombined-Drt4Oq9p.mjs} +3 -3
  110. package/dist/client/{eventDetails-CaX9z1pv.mjs → eventDetails-Bl2vWgTX.mjs} +4 -3
  111. package/dist/client/{eventListing-B9aXPO-I.mjs → eventListing-CS7PHY7v.mjs} +3 -3
  112. package/dist/client/{eventRegistration-CBSovBkg.mjs → eventRegistration-D-j8eNy2.mjs} +85 -41
  113. package/dist/client/{form-Cm0tu_7o.mjs → form-RMpoLTyr.mjs} +2 -2
  114. package/dist/client/{headerSection-OgRtHeKS.mjs → headerSection-BYE3Lb3k.mjs} +2 -2
  115. package/dist/client/hooks.mjs +2254 -298
  116. package/dist/client/{locationMap-DmjcYqNM.mjs → locationMap-BxSr7Kkh.mjs} +2 -2
  117. package/dist/client/{newsletterForm-D08OZQAC.mjs → newsletterForm-DerbXwFC.mjs} +2 -2
  118. package/dist/client/{productDetail-BqZeu2P4.mjs → productDetail-4SZCLhAf.mjs} +3 -3
  119. package/dist/client/{productList-mNyIF9FG.mjs → productList-D7AP4GNq.mjs} +3 -3
  120. package/dist/client/{propsDecoder-DwHXRm9X.mjs → propsDecoder-pzBeCh14.mjs} +123 -46
  121. package/dist/client/rendering/client.mjs +793 -488
  122. package/dist/client/rendering/islands.mjs +17 -17
  123. package/dist/client/rendering.mjs +2161 -1268
  124. package/dist/client/{scrollToBlock-DtmdM3v-.mjs → scrollToBlock-CduAKf8T.mjs} +1 -1
  125. package/dist/client/{shop-CNjZK16F.mjs → shop-Cp5p_kGe.mjs} +6 -6
  126. package/dist/client/{shop-commerce-DkNNao1J.mjs → shop-commerce-DicXYaYX.mjs} +5 -5
  127. package/dist/client/{shop-commerce-store-9WA--zuW.mjs → shop-commerce-store-CGWnpY4K.mjs} +1 -1
  128. package/dist/client/{shopShared-CHCVfccY.mjs → shopShared-BDf9ljkm.mjs} +3 -3
  129. package/dist/client/{useEventFilters-DvuaB4ZN.mjs → useEventFilters-DeeyGYuk.mjs} +3 -3
  130. package/dist/preview-next/before-render.mjs +7 -0
  131. package/dist/preview-next/client/runtime.mjs +4 -4
  132. package/dist/preview-next/keepAlive.mjs +7 -0
  133. package/dist/preview-next/middleware.mjs +7 -0
  134. package/dist/{previewAuthStore-C7ksxt5b.mjs → previewAuthStore-DbqBol0V.mjs} +7 -0
  135. package/dist/{sdk-runtime-3GhW4knb.mjs → sdk-runtime-19MO27F0.mjs} +2 -2
  136. package/dist/{separator-D3bCWYYb.mjs → separator-DaPLtJ1f.mjs} +1 -1
  137. package/dist/server/components.mjs +1562 -917
  138. package/dist/server/config-validation.mjs +94 -135
  139. package/dist/server/config.mjs +94 -135
  140. package/dist/server/data.mjs +94 -134
  141. package/dist/server/index.mjs +122 -4
  142. package/dist/server/manifest.mjs +0 -1
  143. package/dist/server/next.mjs +1467 -732
  144. package/dist/server/page-converter.mjs +87 -113
  145. package/dist/server/prebuild.mjs +1 -1
  146. package/dist/server/rendering/server.mjs +1717 -939
  147. package/dist/server/rendering.mjs +1729 -1044
  148. package/dist/server/routing.mjs +3229 -1835
  149. package/dist/server/server.mjs +21739 -19801
  150. package/dist/server/theme-bridge.mjs +656 -264
  151. package/dist/server/theme.mjs +2 -17
  152. package/dist/styles/index.css +609 -181
  153. package/package.json +1 -1
@@ -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
+ };
22712
22753
  }
22713
- function createManifestValidatorFromPlans(plans, options, normalize) {
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
+ };
22768
+ }
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
@@ -40431,6 +40503,7 @@ const publicWholeSeriesPriceDisplaySchema = z$1.discriminatedUnion("kind", [
40431
40503
  freePriceDisplaySchema,
40432
40504
  exactPriceDisplaySchema,
40433
40505
  fromPriceDisplaySchema,
40506
+ rangePriceDisplaySchema,
40434
40507
  unavailablePriceDisplaySchema
40435
40508
  ]);
40436
40509
  z$1.discriminatedUnion("kind", [
@@ -41557,13 +41630,16 @@ function buildEventRegistrationShellStepLabels(source) {
41557
41630
  }) : false).map((step) => shellLabelForRegistrationStep(step, scopedEvents));
41558
41631
  }
41559
41632
  function scopeEventRegistrationEvents(source) {
41633
+ return toRegistrationEvents(scopeEventRegistrationSourceEvents(source));
41634
+ }
41635
+ function scopeEventRegistrationSourceEvents(source) {
41560
41636
  const scope = planEventRegistrationScope({
41561
- events: toRegistrationEvents(source.events ?? []),
41637
+ events: source.events ?? [],
41562
41638
  wholeSeriesOffering: source.wholeSeriesOffering,
41563
41639
  occurrenceContext: source.occurrenceContext,
41564
41640
  subject: source.subject
41565
41641
  });
41566
- return scope.kind === "invalidSelectedRun" ? [] : scope.events;
41642
+ return scope.kind === "invalidSelectedRun" ? [] : [...scope.events];
41567
41643
  }
41568
41644
  function shellLabelForRegistrationStep(step, events) {
41569
41645
  switch (step) {
@@ -41595,26 +41671,29 @@ const eventRegistrationBlockRuntime = defineClientOwnedBlockRuntime({
41595
41671
  source: createZodCodec(eventRegistrationSourceSchema),
41596
41672
  render: createZodCodec(eventRegistrationRenderSchema)
41597
41673
  },
41598
- buildRender: (source) => ({
41599
- display: buildEventRegistrationDisplay(source),
41600
- hydration: {
41601
- occurrenceContext: source.occurrenceContext ?? null,
41602
- subject: source.subject ?? null,
41603
- events: source.events ?? null,
41604
- wholeSeriesOfferings: source.wholeSeriesOfferings ?? null,
41605
- wholeSeriesOffering: resolveWholeSeriesOffering(source),
41606
- maxTickets: source.maxTickets ?? void 0,
41607
- showVenue: source.showVenue,
41608
- showCapacity: source.showCapacity,
41609
- successMessage: source.successMessage,
41610
- buttonVariant: source.buttonVariant,
41611
- overlayEnabled: source.overlayEnabled,
41612
- spamProtectionEnabled: source.spamProtectionEnabled,
41613
- supportEmail: source.supportEmail,
41614
- sitePasses: source.sitePasses ?? null,
41615
- siteMemberships: source.siteMemberships ?? null
41616
- }
41617
- })
41674
+ buildRender: (source) => {
41675
+ const events = source.events == null ? null : scopeEventRegistrationSourceEvents(source);
41676
+ return {
41677
+ display: buildEventRegistrationDisplay(source),
41678
+ hydration: {
41679
+ occurrenceContext: source.occurrenceContext ?? null,
41680
+ subject: source.subject ?? null,
41681
+ events,
41682
+ wholeSeriesOfferings: source.wholeSeriesOfferings ?? null,
41683
+ wholeSeriesOffering: resolveWholeSeriesOffering(source),
41684
+ maxTickets: source.maxTickets ?? void 0,
41685
+ showVenue: source.showVenue,
41686
+ showCapacity: source.showCapacity,
41687
+ successMessage: source.successMessage,
41688
+ buttonVariant: source.buttonVariant,
41689
+ overlayEnabled: source.overlayEnabled,
41690
+ spamProtectionEnabled: source.spamProtectionEnabled,
41691
+ supportEmail: source.supportEmail,
41692
+ sitePasses: source.sitePasses ?? null,
41693
+ siteMemberships: source.siteMemberships ?? null
41694
+ }
41695
+ };
41696
+ }
41618
41697
  });
41619
41698
  function normalizeEventRegistrationEventInput(value) {
41620
41699
  if (!isRecord$21(value)) return value;
@@ -42315,67 +42394,49 @@ const MONTH_NAMES = [
42315
42394
  "November",
42316
42395
  "December"
42317
42396
  ];
42318
- /** Format a date as YYYY-MM-DD using the runtime's local timezone. */
42319
42397
  function formatDateKey(date) {
42320
- 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")}`;
42321
42399
  }
42322
- /**
42323
- * True when `date` and `now` are the same local calendar day.
42324
- * `now` defaults to `new Date()` so casual callers don't need to thread it,
42325
- * but tests and snapshot-rendering should pass an explicit value.
42326
- */
42327
- function isToday(date, now = /* @__PURE__ */ new Date()) {
42328
- return isSameLocalDay(date, now);
42400
+ function isToday(date, today) {
42401
+ return isSameCalendarDay(date, today);
42329
42402
  }
42330
- /** True when two dates fall on the same local calendar day. */
42331
- function isSameLocalDay(left, right) {
42332
- 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
+ };
42333
42413
  }
42334
- /**
42335
- * Build the calendar days for a month view. Returns 42 dates (6 rows × 7
42336
- * days) including padding from prior/next months for a stable grid.
42337
- */
42338
42414
  function getMonthCalendarDays(year, month, startOfWeek) {
42339
- const firstDayOfMonth = new Date(year, month, 1);
42340
- const lastDayOfMonth = new Date(year, month + 1, 0);
42341
- let startOffset = firstDayOfMonth.getDay();
42342
- if (startOfWeek === "monday") startOffset = startOffset === 0 ? 6 : startOffset - 1;
42343
- const days = [];
42344
- for (let i = startOffset - 1; i >= 0; i--) days.push(new Date(year, month, -i));
42345
- for (let day = 1; day <= lastDayOfMonth.getDate(); day++) days.push(new Date(year, month, day));
42346
- while (days.length < 42) {
42347
- const nextDay = days.length - startOffset - lastDayOfMonth.getDate() + 1;
42348
- days.push(new Date(year, month + 1, nextDay));
42349
- }
42350
- 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));
42351
42423
  }
42352
- /** Build the 7 dates of the week containing `baseDate`. */
42353
42424
  function getWeekCalendarDays(baseDate, startOfWeek) {
42354
- const days = [];
42355
- const dayOfWeek = baseDate.getDay();
42356
- const daysToStart = startOfWeek === "monday" ? dayOfWeek === 0 ? 6 : dayOfWeek - 1 : dayOfWeek;
42357
- const weekStart = new Date(baseDate);
42358
- weekStart.setDate(baseDate.getDate() - daysToStart);
42359
- for (let i = 0; i < 7; i++) {
42360
- const date = new Date(weekStart);
42361
- date.setDate(weekStart.getDate() + i);
42362
- days.push(date);
42363
- }
42364
- 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();
42365
42431
  }
42366
- /** Build the 7 dates of the week containing `baseDate` as a fixed-width tuple. */
42367
42432
  function getWeekCalendarDayTuple(baseDate, startOfWeek) {
42368
42433
  const days = getWeekCalendarDays(baseDate, startOfWeek);
42369
42434
  assertWeekCalendarDays(days);
42370
42435
  return days;
42371
42436
  }
42372
42437
  function assertWeekCalendarDays(days) {
42373
- 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");
42374
42439
  }
42375
- /**
42376
- * Day-name labels reordered for the chosen week start. Pass a custom
42377
- * `dayNames` array (length 7, Sunday-first) to localize.
42378
- */
42379
42440
  function getOrderedDayNames(startOfWeek, dayNames = DAY_NAMES) {
42380
42441
  if (startOfWeek === "monday") {
42381
42442
  const sunday = dayNames[0] ?? "Sun";
@@ -42383,22 +42444,17 @@ function getOrderedDayNames(startOfWeek, dayNames = DAY_NAMES) {
42383
42444
  }
42384
42445
  return [...dayNames];
42385
42446
  }
42386
- /**
42387
- * Header title for a calendar view.
42388
- * - month: "January 2025"
42389
- * - week: "January 5 - 11, 2025" or "December 30 - January 5, 2025"
42390
- */
42391
42447
  function formatCalendarTitle(viewDate, view, days, monthNames = MONTH_NAMES) {
42392
42448
  if (view === "week") {
42393
42449
  const weekStart = days[0];
42394
42450
  const weekEnd = days[6];
42395
- if (weekStart === void 0 || weekEnd === void 0) return `${monthNames[viewDate.getMonth()] ?? ""} ${viewDate.getFullYear()}`;
42396
- const startMonth = monthNames[weekStart.getMonth()] ?? "";
42397
- const endMonth = monthNames[weekEnd.getMonth()] ?? "";
42398
- if (weekStart.getMonth() === weekEnd.getMonth()) return `${startMonth} ${weekStart.getDate()} - ${weekEnd.getDate()}, ${weekEnd.getFullYear()}`;
42399
- 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}`;
42400
42456
  }
42401
- return `${monthNames[viewDate.getMonth()] ?? ""} ${viewDate.getFullYear()}`;
42457
+ return `${monthNames[viewDate.month - 1] ?? ""} ${viewDate.year}`;
42402
42458
  }
42403
42459
  function buildCalendarViewport(input) {
42404
42460
  const monthNames = input.monthNames ?? MONTH_NAMES;
@@ -42408,10 +42464,10 @@ function buildCalendarViewport(input) {
42408
42464
  kind: "week",
42409
42465
  anchorDate: input.anchorDate,
42410
42466
  days,
42411
- title: formatCalendarTitle(input.anchorDate, "week", [...days], monthNames)
42467
+ title: formatCalendarTitle(input.anchorDate, "week", days, monthNames)
42412
42468
  };
42413
42469
  }
42414
- const days = getMonthCalendarDays(input.anchorDate.getFullYear(), input.anchorDate.getMonth(), input.startOfWeek);
42470
+ const days = getMonthCalendarDays(input.anchorDate.year, input.anchorDate.month, input.startOfWeek);
42415
42471
  return {
42416
42472
  kind: "month",
42417
42473
  anchorDate: input.anchorDate,
@@ -42559,13 +42615,12 @@ function buildTimetableModel$1(input) {
42559
42615
  const bounds = resolveBounds(input.bounds);
42560
42616
  const viewportDays = getTimetableDays(input.viewDate, input.view ?? "week", input.startOfWeek);
42561
42617
  const viewportKeys = new Set(viewportDays.map(formatDateKey));
42562
- const now = input.now ?? /* @__PURE__ */ new Date();
42563
42618
  const parsed = parseAllItems(input.items, input);
42564
42619
  const inViewport = deriveVisibleSegments(parsed.drafts, viewportKeys);
42565
42620
  const hourRange = resolveHourRange(inViewport, bounds);
42566
42621
  const laid = layoutCellsByDate(inViewport, hourRange, bounds);
42567
42622
  return {
42568
- days: assembleDays(viewportDays, laid.cellsByDate, now),
42623
+ days: assembleDays(viewportDays, laid.cellsByDate, input.today),
42569
42624
  hourTicks: buildHourTicks(hourRange.startHour, hourRange.endHour),
42570
42625
  startHour: hourRange.startHour,
42571
42626
  endHour: hourRange.endHour,
@@ -42622,13 +42677,13 @@ function layoutCellsByDate(segments, hourRange, bounds) {
42622
42677
  diagnostics
42623
42678
  };
42624
42679
  }
42625
- function assembleDays(viewportDays, cellsByDate, now) {
42680
+ function assembleDays(viewportDays, cellsByDate, today) {
42626
42681
  return viewportDays.map((date) => {
42627
42682
  const dateKey = formatDateKey(date);
42628
42683
  return {
42629
42684
  date,
42630
42685
  dateKey,
42631
- isToday: isSameLocalDay(date, now),
42686
+ isToday: isSameCalendarDay(date, today),
42632
42687
  cells: cellsByDate.get(dateKey) ?? []
42633
42688
  };
42634
42689
  });
@@ -42780,13 +42835,12 @@ function getTimetableDays(viewDate, view, startOfWeek) {
42780
42835
  function enumerateDateKeys(startDateKey, endDateKey) {
42781
42836
  if (startDateKey > endDateKey) throw new Error(`Invalid timetable date range: ${startDateKey} is after ${endDateKey}`);
42782
42837
  const start = parseDateKey(startDateKey);
42783
- const end = parseDateKey(endDateKey);
42838
+ parseDateKey(endDateKey);
42784
42839
  const keys = [];
42785
- const cursor = new Date(start.year, start.month - 1, start.day);
42786
- const endDate = new Date(end.year, end.month - 1, end.day);
42787
- while (cursor.getTime() <= endDate.getTime()) {
42840
+ let cursor = start;
42841
+ while (formatDateKey(cursor) <= endDateKey) {
42788
42842
  keys.push(formatDateKey(cursor));
42789
- cursor.setDate(cursor.getDate() + 1);
42843
+ cursor = addDays(cursor, 1);
42790
42844
  }
42791
42845
  return keys;
42792
42846
  }
@@ -43011,10 +43065,10 @@ function formatEventTeacherLine(event) {
43011
43065
  * timezone). Thin domain wrapper over `groupItemsByDate` from the calendar
43012
43066
  * package; preserves the historical `Map<string, PublicEvent[]>` shape.
43013
43067
  */
43014
- function groupEventsByDate(events) {
43068
+ function groupEventsByDate(events, calendarTimeZone) {
43015
43069
  const grouped = groupItemsByDate(events, {
43016
43070
  getStartsAt: (event) => event.startsAt,
43017
- getTimeZone: (event) => event.timeZone ?? "UTC"
43071
+ getTimeZone: () => calendarTimeZone
43018
43072
  });
43019
43073
  const map = /* @__PURE__ */ new Map();
43020
43074
  for (const [dateKey, bucket] of grouped) map.set(dateKey, [...bucket]);
@@ -44775,7 +44829,8 @@ const eventCollectionSourceSchemaShape = {
44775
44829
  buttonVariant: eventButtonVariantSchema.optional(),
44776
44830
  buttonText: z$1.string().optional(),
44777
44831
  emptyMessage: z$1.string().optional(),
44778
- className: z$1.string().optional()
44832
+ className: z$1.string().optional(),
44833
+ bookingTimeZone: z$1.string().optional()
44779
44834
  };
44780
44835
  const eventCollectionDisplaySchemaShape = {
44781
44836
  events: z$1.array(publicEventSchema),
@@ -44810,7 +44865,15 @@ const eventCollectionHydrationSchema = z$1.object({
44810
44865
  prefetchedEvents: z$1.boolean(),
44811
44866
  eventSurface: eventSurfaceScopeSchema$1,
44812
44867
  filterEventPresets: z$1.string().nullable(),
44813
- 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
+ })
44814
44877
  });
44815
44878
  function buildEventCollectionDisplay(source) {
44816
44879
  return {
@@ -44855,14 +44918,19 @@ function buildEventCollectionPresentationDisplay(source) {
44855
44918
  emptyMessage: source.emptyMessage ?? "No upcoming events scheduled."
44856
44919
  };
44857
44920
  }
44858
- function buildEventCollectionHydration(source) {
44921
+ function buildEventCollectionHydration(source, now = /* @__PURE__ */ new Date()) {
44922
+ const timeZone = toBookingTimeZone(source.bookingTimeZone);
44859
44923
  return {
44860
44924
  siteId: source.siteId,
44861
44925
  stage: source.stage,
44862
44926
  prefetchedEvents: source.events != null,
44863
44927
  eventSurface: normalizeEventSurfaceScope(source.eventSurface),
44864
44928
  filterEventPresets: normalizeEventSurfacePresetsCsv(source.filterEventPresets),
44865
- scheduleScope: normalizeEventScheduleScope(source.scheduleScope)
44929
+ scheduleScope: normalizeEventScheduleScope(source.scheduleScope),
44930
+ calendarContext: {
44931
+ timeZone,
44932
+ initialToday: getLocalScheduleDate(now, timeZone)
44933
+ }
44866
44934
  };
44867
44935
  }
44868
44936
  function buildEventCollectionListingDisplay(display, prefetchedEvents, className) {
@@ -55443,7 +55511,8 @@ function isOrdinaryEvent(event) {
55443
55511
  function deriveWholeSeriesPhase(sessions, nowIso) {
55444
55512
  const now = Date.parse(nowIso);
55445
55513
  if (now < Date.parse(sessions[0].startsAt)) return "upcoming";
55446
- 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";
55447
55516
  }
55448
55517
  function selectRelatedDates(input) {
55449
55518
  if (!input.seriesId) return [];
@@ -55841,9 +55910,13 @@ function EventDetailsSSR(props) {
55841
55910
  const { blockId, occurrenceContext = null, subject, events = null, className, children } = props;
55842
55911
  const nowIso = (/* @__PURE__ */ new Date()).toISOString();
55843
55912
  const normalizedSubject = normalizeEventRegistrationPageSurfaceSubject(subject);
55913
+ const scopedEvents = events === null ? null : resolveEventRegistrationScopedEvents(events, {
55914
+ occurrenceContext,
55915
+ subject: normalizedSubject
55916
+ });
55844
55917
  const presentation = resolveEventDetailsPresentation({
55845
55918
  ...props,
55846
- events,
55919
+ events: scopedEvents,
55847
55920
  occurrenceContext,
55848
55921
  subject: normalizedSubject,
55849
55922
  nowIso
@@ -55856,7 +55929,7 @@ function EventDetailsSSR(props) {
55856
55929
  /* @__PURE__ */ jsx(IslandPropsScript, { value: {
55857
55930
  occurrenceContext,
55858
55931
  subject: normalizedSubject,
55859
- events,
55932
+ events: scopedEvents,
55860
55933
  showVenue: presentation.showVenue,
55861
55934
  showMap: presentation.showMap,
55862
55935
  showOtherDates: presentation.showOtherDates,
@@ -57538,9 +57611,9 @@ const FULL_DAY_NAMES$1 = [
57538
57611
  * @returns "Monday, January 13"
57539
57612
  */
57540
57613
  function formatAgendaDayHeader(date) {
57541
- const dayName = FULL_DAY_NAMES$1[date.getDay()];
57542
- const monthName = MONTH_NAMES[date.getMonth()];
57543
- 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}`;
57544
57617
  }
57545
57618
  /**
57546
57619
  * WeekAgendaView Component
@@ -57548,14 +57621,14 @@ function formatAgendaDayHeader(date) {
57548
57621
  * Displays a week of events in an agenda/list style with rich event details.
57549
57622
  * Shows all 7 days with date headers, empty days show "No events scheduled".
57550
57623
  */
57551
- const WeekAgendaView = ({ days, events, showCapacity, emptyMessage = "No events scheduled" }) => {
57552
- const eventsByDate = groupEventsByDate(events);
57624
+ const WeekAgendaView = ({ days, events, showCapacity, emptyMessage = "No events scheduled", calendarTimeZone, today: currentDate }) => {
57625
+ const eventsByDate = groupEventsByDate(events, calendarTimeZone);
57553
57626
  return /* @__PURE__ */ jsx("div", {
57554
57627
  className: "event-agenda-week",
57555
57628
  children: days.map((date) => {
57556
57629
  const dateKey = formatDateKey(date);
57557
57630
  const dayEvents = eventsByDate.get(dateKey) || [];
57558
- const today = isToday(date);
57631
+ const today = isToday(date, currentDate);
57559
57632
  return /* @__PURE__ */ jsxs("div", {
57560
57633
  className: `event-agenda-day ${today ? "event-agenda-day--today" : ""}`,
57561
57634
  children: [/* @__PURE__ */ jsx("div", {
@@ -57584,6 +57657,50 @@ const WeekAgendaView = ({ days, events, showCapacity, emptyMessage = "No events
57584
57657
  })
57585
57658
  });
57586
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
+ }
57587
57704
  const SHORT_DAY_NAMES = [
57588
57705
  "Sun",
57589
57706
  "Mon",
@@ -57645,6 +57762,114 @@ const WeekBoardCard = ({ event, showCapacity }) => {
57645
57762
  ]
57646
57763
  });
57647
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
+ };
57648
57873
  /**
57649
57874
  * WeekBoardView
57650
57875
  *
@@ -57653,18 +57878,21 @@ const WeekBoardCard = ({ event, showCapacity }) => {
57653
57878
  * to a stacked list on mobile. Repurposes the week-grouped agenda data as a
57654
57879
  * board rather than an hour-positioned timetable grid.
57655
57880
  */
57656
- 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 }) => {
57657
- 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);
57658
57883
  const hasAnyEvents = days.some((date) => (eventsByDate.get(formatDateKey(date)) ?? []).length > 0);
57659
57884
  const ctaClassName = themeButtonClassName({
57660
57885
  variant: buttonVariant,
57661
57886
  size: "sm"
57662
57887
  });
57888
+ const todayClassName = themeButtonClassName({
57889
+ variant: buttonVariant,
57890
+ size: "sm"
57891
+ });
57663
57892
  const hasTitle = typeof title === "string" && title.length > 0;
57664
57893
  const hasFooterNote = typeof footerNote === "string" && footerNote.length > 0;
57665
- const hasCta = typeof ctaHref === "string" && ctaHref.length > 0;
57666
57894
  const footerNoteText = hasAnyEvents ? hasFooterNote ? footerNote : null : emptyMessage;
57667
- const showFooter = hasCta || footerNoteText !== null;
57895
+ const resolvedCtaHref = typeof ctaHref === "string" && ctaHref.length > 0 ? ctaHref : null;
57668
57896
  return /* @__PURE__ */ jsx("div", {
57669
57897
  className: "event-calendar event-calendar--week-board",
57670
57898
  "data-block": "event-calendar",
@@ -57676,59 +57904,34 @@ const WeekBoardView = ({ days, events, showCapacity, emptyMessage = "No classes
57676
57904
  children: [
57677
57905
  /* @__PURE__ */ jsxs("div", {
57678
57906
  className: "event-week-board-top",
57679
- children: [hasTitle ? /* @__PURE__ */ jsx("span", {
57680
- className: "event-week-board-title",
57681
- children: title
57682
- }) : null, /* @__PURE__ */ jsx("div", {
57683
- className: "event-week-board-legend",
57684
- "aria-hidden": "true",
57685
- children: LEGEND_ITEMS.map((item) => /* @__PURE__ */ jsxs("span", {
57686
- className: "event-week-board-legend-item",
57687
- children: [/* @__PURE__ */ jsx("i", {
57688
- className: "event-week-board-legend-dot",
57689
- "data-status": item.status
57690
- }), item.label]
57691
- }, item.status))
57692
- })]
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
+ ]
57693
57918
  }),
57694
- /* @__PURE__ */ jsx("div", {
57695
- className: "event-week-board-grid",
57696
- children: days.map((date) => {
57697
- const dateKey = formatDateKey(date);
57698
- const dayEvents = eventsByDate.get(dateKey) ?? [];
57699
- const today = isToday(date);
57700
- return /* @__PURE__ */ jsxs("div", {
57701
- className: clsx("event-week-board-day", dayEvents.length === 0 && "event-week-board-day--empty", today && "event-week-board-day--today"),
57702
- children: [/* @__PURE__ */ jsxs("div", {
57703
- className: "event-week-board-day-head",
57704
- children: [/* @__PURE__ */ jsx("span", {
57705
- className: "event-week-board-day-abbr",
57706
- children: SHORT_DAY_NAMES[date.getDay()]
57707
- }), /* @__PURE__ */ jsx("span", {
57708
- className: "event-week-board-day-num",
57709
- children: date.getDate()
57710
- })]
57711
- }), /* @__PURE__ */ jsx("div", {
57712
- className: "event-week-board-day-body",
57713
- children: dayEvents.map((event) => /* @__PURE__ */ jsx(WeekBoardCard, {
57714
- event,
57715
- showCapacity
57716
- }, event.occurrenceId || event.id))
57717
- })]
57718
- }, dateKey);
57719
- })
57919
+ /* @__PURE__ */ jsx(WeekBoardLoadError, {
57920
+ navigation,
57921
+ buttonClassName: todayClassName
57720
57922
  }),
57721
- showFooter ? /* @__PURE__ */ jsxs("div", {
57722
- className: "event-week-board-foot",
57723
- children: [footerNoteText !== null ? /* @__PURE__ */ jsx("p", {
57724
- className: "event-week-board-foot-note",
57725
- children: footerNoteText
57726
- }) : null, hasCta ? /* @__PURE__ */ jsx("a", {
57727
- className: ctaClassName,
57728
- href: ctaHref ?? void 0,
57729
- children: ctaLabel
57730
- }) : null]
57731
- }) : 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
+ })
57732
57935
  ]
57733
57936
  })
57734
57937
  });
@@ -57759,6 +57962,7 @@ function buildTimetableModel(input) {
57759
57962
  items: input.events,
57760
57963
  viewDate: input.viewDate,
57761
57964
  startOfWeek: input.startOfWeek,
57965
+ today: input.today,
57762
57966
  getId: (event) => event.id,
57763
57967
  getStartsAt: (event) => event.startsAt,
57764
57968
  getEndsAt: (event) => event.endsAt,
@@ -57820,10 +58024,10 @@ function formatEventTimeRange(event) {
57820
58024
  return `${formatTime(event.startsAt, { timeZone })} - ${formatTime(event.endsAt, { timeZone })}`;
57821
58025
  }
57822
58026
  function formatDayLabel(date) {
57823
- 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}`;
57824
58028
  }
57825
58029
  function formatShortDayLabel(date) {
57826
- return `${(FULL_DAY_NAMES[date.getDay()] ?? "").slice(0, 3)} ${date.getDate()}`;
58030
+ return `${(FULL_DAY_NAMES[getDayOfWeek(date)] ?? "").slice(0, 3)} ${date.day}`;
57827
58031
  }
57828
58032
  //#endregion
57829
58033
  //#region ../blocks/src/system/runtime/nodes/events/EventCalendar.server.tsx
@@ -57870,15 +58074,15 @@ function renderListSsr(display, prefetchedEvents) {
57870
58074
  renderEventCard: (event) => renderEventCard(event, listDisplay)
57871
58075
  });
57872
58076
  }
57873
- function renderCalendarSsr(display) {
58077
+ function renderCalendarSsr(display, hydration) {
57874
58078
  const calendarView = display.defaultCalendarView;
57875
- const viewDate = /* @__PURE__ */ new Date();
58079
+ const viewDate = hydration.calendarContext.initialToday;
57876
58080
  const viewport = buildCalendarViewport({
57877
58081
  view: calendarView,
57878
58082
  anchorDate: viewDate,
57879
58083
  startOfWeek: display.startOfWeek
57880
58084
  });
57881
- const eventsByDate = groupEventsByDate([...display.events]);
58085
+ const eventsByDate = groupEventsByDate([...display.events], hydration.calendarContext.timeZone);
57882
58086
  const dayNames = getOrderedDayNames(display.startOfWeek);
57883
58087
  return /* @__PURE__ */ jsxs("div", {
57884
58088
  className: clsx("event-calendar", display.className ?? void 0),
@@ -57945,7 +58149,9 @@ function renderCalendarSsr(display) {
57945
58149
  days: viewport.days,
57946
58150
  events: [...display.events],
57947
58151
  emptyMessage: display.emptyMessage,
57948
- showCapacity: display.showCapacity
58152
+ showCapacity: display.showCapacity,
58153
+ calendarTimeZone: hydration.calendarContext.timeZone,
58154
+ today: hydration.calendarContext.initialToday
57949
58155
  }) : /* @__PURE__ */ jsxs("div", {
57950
58156
  className: "event-calendar-container",
57951
58157
  children: [/* @__PURE__ */ jsx("div", {
@@ -57959,13 +58165,13 @@ function renderCalendarSsr(display) {
57959
58165
  children: viewport.days.map((date) => {
57960
58166
  const dateKey = formatDateKey(date);
57961
58167
  const dayEvents = eventsByDate.get(dateKey) || [];
57962
- const isCurrentMonth = date.getMonth() === viewDate.getMonth();
57963
- const today = isToday(date);
58168
+ const isCurrentMonth = date.month === viewDate.month;
58169
+ const today = isToday(date, hydration.calendarContext.initialToday);
57964
58170
  return /* @__PURE__ */ jsxs("div", {
57965
58171
  className: clsx("event-calendar-day", !isCurrentMonth && "event-calendar-day--other-month", today && "event-calendar-day--today"),
57966
58172
  children: [/* @__PURE__ */ jsx("div", {
57967
58173
  className: "event-calendar-day-number",
57968
- children: date.getDate()
58174
+ children: date.day
57969
58175
  }), /* @__PURE__ */ jsxs("div", {
57970
58176
  className: "event-calendar-events",
57971
58177
  children: [dayEvents.slice(0, 3).map((event) => /* @__PURE__ */ jsxs("a", {
@@ -58003,8 +58209,8 @@ function renderCalendarSsr(display) {
58003
58209
  ]
58004
58210
  });
58005
58211
  }
58006
- function renderTimetableSsr(display) {
58007
- const viewDate = /* @__PURE__ */ new Date();
58212
+ function renderTimetableSsr(display, hydration) {
58213
+ const viewDate = hydration.calendarContext.initialToday;
58008
58214
  const viewport = buildCalendarViewport({
58009
58215
  view: "week",
58010
58216
  anchorDate: viewDate,
@@ -58013,7 +58219,8 @@ function renderTimetableSsr(display) {
58013
58219
  const model = buildTimetableModel({
58014
58220
  events: [...display.events],
58015
58221
  viewDate,
58016
- startOfWeek: display.startOfWeek
58222
+ startOfWeek: display.startOfWeek,
58223
+ today: hydration.calendarContext.initialToday
58017
58224
  });
58018
58225
  const selectedDayKey = model.days.find((day) => day.isToday)?.dateKey ?? model.days[0]?.dateKey ?? "";
58019
58226
  return /* @__PURE__ */ jsxs("div", {
@@ -58168,20 +58375,21 @@ function renderTimetableSsr(display) {
58168
58375
  })]
58169
58376
  });
58170
58377
  }
58171
- function renderWeekBoardSsr(display) {
58172
- return /* @__PURE__ */ jsx(WeekBoardView, {
58173
- days: getWeekCalendarDayTuple(/* @__PURE__ */ new Date(), display.startOfWeek),
58174
- events: [...display.events],
58175
- showCapacity: display.showCapacity,
58176
- emptyMessage: display.emptyMessage,
58177
- title: display.boardTitle,
58178
- footerNote: display.footerNote,
58179
- ctaLabel: display.loadMoreText ?? display.buttonText,
58180
- ctaHref: display.seeAllUrl,
58181
- buttonVariant: display.buttonVariant,
58182
- elevated: display.elevated,
58183
- banded: display.banded
58184
- });
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) });
58185
58393
  }
58186
58394
  function formatHourLabel(hour) {
58187
58395
  if (hour === 0) return "12 AM";
@@ -58207,13 +58415,13 @@ const EventCalendarSSR = (props) => {
58207
58415
  content = renderListSsr(display, hydration.prefetchedEvents);
58208
58416
  break;
58209
58417
  case "timetable":
58210
- content = renderTimetableSsr(display);
58418
+ content = renderTimetableSsr(display, hydration);
58211
58419
  break;
58212
58420
  case "week-board":
58213
- content = renderWeekBoardSsr(display);
58421
+ content = renderWeekBoardSsr(display, hydration);
58214
58422
  break;
58215
58423
  case "calendar":
58216
- content = renderCalendarSsr(display);
58424
+ content = renderCalendarSsr(display, hydration);
58217
58425
  break;
58218
58426
  default: content = assertNeverDisplayMode(display.displayMode);
58219
58427
  }
@@ -61403,36 +61611,9 @@ function buildLegacyHeaderNavLinkStyle(header, contrastTreatment, navTextSize) {
61403
61611
  ...navTextSize ? { textSize: navTextSize } : {}
61404
61612
  };
61405
61613
  if (header.navWeight === "bold" && navStyle === "solid") style.textTransform = "uppercase";
61406
- applyLegacyNavEffects(style, header);
61407
61614
  applyLegacyGlassTreatment(style, header, navStyle);
61408
61615
  return style;
61409
61616
  }
61410
- function applyLegacyNavEffects(style, header) {
61411
- if (!header.navEffects) return;
61412
- const effects = style.effects = {
61413
- ...style.effects,
61414
- hover: [...style.effects?.hover ?? []],
61415
- active: [...style.effects?.active ?? []]
61416
- };
61417
- if (header.navEffects.glow) effects.hover.push({
61418
- effectId: "outer-glow",
61419
- options: { spread: 5 }
61420
- });
61421
- if (header.navEffects.neumorphic) {
61422
- effects.hover.push({
61423
- effectId: "neumorphic-shadow",
61424
- options: { mode: "pressed" }
61425
- });
61426
- effects.hover.push({
61427
- effectId: "text-color-change",
61428
- options: { hoverColorToken: "primary" }
61429
- });
61430
- }
61431
- if (header.navEffects.underlineGradient) effects.hover.push({
61432
- effectId: "border-bottom-grow",
61433
- options: { origin: "center" }
61434
- });
61435
- }
61436
61617
  function applyLegacyGlassTreatment(style, header, navStyle) {
61437
61618
  if (header.navContainer?.type !== "glass" || navStyle !== "minimal") return;
61438
61619
  style.borderRadius = "full";
@@ -61458,19 +61639,6 @@ function glassStateEffects(opacity) {
61458
61639
  //#region ../theme-core/src/header/generateHeaderCss.ts
61459
61640
  const HEADER_BLUR = "blur(12px)";
61460
61641
  const FLOATING_BLUR = "blur(16px)";
61461
- const INSET_SHELL_MARKER_CLASS = "header-bar-frame-inset-shell";
61462
- const INSET_SHELL_EDGE = "1rem";
61463
- const INSET_SHELL_INSET_BLOCK = "0.875rem";
61464
- const INSET_SHELL_RADIUS = "9999px";
61465
- const INSET_SHELL_CONTAINER_MAX = "80rem";
61466
- const INSET_SHELL_INTERIOR_PADDING_X = "1.75rem";
61467
- /**
61468
- * Whether the classic header should render as an inset "brand capsule" shell.
61469
- * The facet is only meaningful for the classic layout; other variants ignore it.
61470
- */
61471
- function usesInsetShell(header) {
61472
- return header.barFrame === "inset-shell" && header.variant === "classic";
61473
- }
61474
61642
  /**
61475
61643
  * Generate complete CSS for header system from theme config
61476
61644
  *
@@ -61548,36 +61716,7 @@ function generateHeaderRootStyles(header, themeId, tokens) {
61548
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`;
61549
61717
  const scrollTreatmentStyles = generateHeaderScrollTreatmentStyles(header.scrollTreatment, themeId, header.variant, scrolledPaintRules);
61550
61718
  if (isContainedNav || basePaintRules.length === 0) return `${baseBlock}\n${overlayFix}${scrollTreatmentStyles}`;
61551
- return `${baseBlock}\n${renderHeaderPaintTargetRules(getHeaderPaintTargets(header.variant, themeId), basePaintRules)}\n${overlayFix}${usesInsetShell(header) ? generateInsetShellStyles(header, themeId) : ""}${scrollTreatmentStyles}`;
61552
- }
61553
- /**
61554
- * Reshapes the full-bleed header paint layer into a contained brand capsule at
61555
- * the desktop breakpoint. The capsule is centred, capped to the page container
61556
- * width, inset from the top, fully rounded, and carries the header depth so it
61557
- * reads as a floating pill. Root border/shadow are neutralised on desktop so a
61558
- * bordered style does not leave a full-width hairline around the capsule. Sticky
61559
- * positioning is unaffected — the root stays full width and sticky while the
61560
- * ::before paint provides the capsule.
61561
- */
61562
- function generateInsetShellStyles(header, themeId) {
61563
- const scope = `:where([data-theme-scope="${themeId}"])`;
61564
- const shellRootSelector = `${scope} .header-root.${INSET_SHELL_MARKER_CLASS}`;
61565
- const shellBeforeSelector = `${scope} .header-root.${INSET_SHELL_MARKER_CLASS}::before`;
61566
- const layoutSelector = `${scope} .header-root.${INSET_SHELL_MARKER_CLASS} .rb-header-layout`;
61567
- const widthValue = header.maxWidth === "full" ? `calc(100% - (${INSET_SHELL_EDGE} * 2))` : `min(${INSET_SHELL_CONTAINER_MAX}, calc(100% - (${INSET_SHELL_EDGE} * 2)))`;
61568
- const shadowVar = getComponentShadowVar(header.shadow?.elevation ?? "none");
61569
- const rootRules = ["border: none;", "box-shadow: none;"];
61570
- const beforeRules = [
61571
- `inset: ${INSET_SHELL_INSET_BLOCK} auto;`,
61572
- "left: 50%;",
61573
- "right: auto;",
61574
- "transform: translateX(-50%);",
61575
- `width: ${widthValue};`,
61576
- `border-radius: ${INSET_SHELL_RADIUS};`,
61577
- ...shadowVar ? [`box-shadow: ${shadowVar};`] : []
61578
- ];
61579
- const layoutRules = [`padding-inline: ${INSET_SHELL_INTERIOR_PADDING_X};`];
61580
- 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}`;
61581
61720
  }
61582
61721
  /**
61583
61722
  * Generate logo typography styles
@@ -61651,7 +61790,7 @@ function generateLogoTextBehaviorStyles(logoText, themeId) {
61651
61790
  * Generate navigation link styles based on navStyle and effects
61652
61791
  *
61653
61792
  * Uses the composable NavLinkStyle system with backward compatibility for
61654
- * legacy navStyle, navWeight, navColor, and navEffects settings.
61793
+ * legacy navStyle, navWeight and navColor settings.
61655
61794
  */
61656
61795
  function generateNavLinkStyles(header, themeId, tokens, theme, contrastTreatment, navTextSize) {
61657
61796
  const navPreferences = {
@@ -64288,9 +64427,43 @@ function pageBlockPosition(index, blockCount) {
64288
64427
  return "middle";
64289
64428
  }
64290
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
64291
64457
  //#region ../blocks/src/PageRenderer.tsx
64292
64458
  function PageRenderer$1(props) {
64293
- 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;
64294
64467
  const imageResolveContext = React$1.useMemo(() => resolvePageRendererImageResolveContext(dataContext), [
64295
64468
  dataContext?.imageResolveContext,
64296
64469
  dataContext?.mediaAssets,
@@ -64389,11 +64562,11 @@ function resolvePageRendererImageResolveContext(dataContext) {
64389
64562
  mediaAssets: input?.mediaAssets ?? dataContext?.mediaAssets
64390
64563
  });
64391
64564
  }
64565
+ const resolveBookingTimeZone = (dataContext) => dataContext?.bookingTimeZone;
64392
64566
  function buildBlockSectionProps(input) {
64393
64567
  return {
64394
64568
  themeResources: input.themeResources,
64395
64569
  block: input.block,
64396
- usePlaceholders: input.props.usePlaceholders ?? false,
64397
64570
  dataContext: input.props.dataContext,
64398
64571
  blockKey: input.blockKey,
64399
64572
  registry: input.registry,
@@ -64417,7 +64590,6 @@ function getBlockOverride(blockKind, overrides) {
64417
64590
  if (overrides[shortKind]) return overrides[shortKind];
64418
64591
  }
64419
64592
  const blockComponentCache = /* @__PURE__ */ new WeakMap();
64420
- const manifestValidatorCache = /* @__PURE__ */ new WeakMap();
64421
64593
  const DEFAULT_PERF_SLOW_BLOCK_RENDER_THRESHOLD_MS = 25;
64422
64594
  let cachedPerfSlowBlockRenderThresholdMs = null;
64423
64595
  function getPerfSlowBlockRenderThresholdMs() {
@@ -64435,44 +64607,13 @@ function getCachedBlockComponent(manifest) {
64435
64607
  return created;
64436
64608
  }
64437
64609
  /**
64438
- * Render-time manifest validator — see `.claude/plans/dapper-jingling-emerson.md`
64439
- * Phase 10. One function, two flavours:
64440
- *
64441
- * - `strict` (default): the contract every render surface tries first. No
64442
- * null tolerance, no missing-required tolerance. Production frontends and
64443
- * the dashboard preview both go through this path; after Phases 6-9 the
64444
- * preview satisfies strict structurally.
64445
- * - `relaxed`: editor-mid-edit fallback. Reached via `usePlaceholders` when
64446
- * strict fails. Built on `mode: 'draft'` so empty required fields parse
64447
- * as `undefined` and the user's valid in-flight fields flow through.
64448
- *
64449
- * Per-manifest, per-flavour cached. Adding a third flavour means adding a
64450
- * branch to the `createManifestValidator` call below and a member to
64451
- * `ValidationFlavour` — no per-flavour helper duplication.
64452
- */
64453
- function getCachedValidator(manifest, flavour) {
64454
- let perFlavour = manifestValidatorCache.get(manifest);
64455
- if (!perFlavour) {
64456
- perFlavour = /* @__PURE__ */ new Map();
64457
- manifestValidatorCache.set(manifest, perFlavour);
64458
- }
64459
- const cached = perFlavour.get(flavour);
64460
- if (cached) return cached;
64461
- const created = createManifestValidator(manifest, {
64462
- allowNull: false,
64463
- ...flavour === "relaxed" ? { mode: "draft" } : {}
64464
- });
64465
- perFlavour.set(flavour, created);
64466
- return created;
64467
- }
64468
- /**
64469
64610
  * Memoized block section component.
64470
64611
  *
64471
64612
  * Custom memoization prevents render loops during editing by explicitly checking
64472
64613
  * referential equality of all props that affect rendering. Standard React.memo
64473
64614
  * wouldn't catch all the render triggers from the editor store.
64474
64615
  */
64475
- 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 }) {
64476
64617
  const perfStart = globalThis.process?.env?.DEBUG_PERF === "1" && typeof window === "undefined" ? Date.now() : 0;
64477
64618
  const fallbackImageResolveContext = getCurrentResolveImageUrlContext();
64478
64619
  const resolvedImageResolveContext = imageResolveContext ?? fallbackImageResolveContext;
@@ -64492,6 +64633,19 @@ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeResources
64492
64633
  } catch {}
64493
64634
  return node;
64494
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
+ }
64495
64649
  const OverrideComponent = getBlockOverride(block.kind, blockOverrides);
64496
64650
  requireBlockOverride(themeResources, OverrideComponent, block.kind);
64497
64651
  let definition = getBlockDefinition(block.kind);
@@ -64561,25 +64715,10 @@ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeResources
64561
64715
  });
64562
64716
  }
64563
64717
  const content = getRenderableContent(block, dataContext?.previewStage);
64564
- const parsed = getCachedValidator(definition.manifest, "strict").safeParse(content);
64565
- try {
64566
- if (globalThis.process?.env?.NODE_ENV !== "production" && !parsed.success && !usePlaceholders) console.warn("[blocks:PageRenderer] manifest validation failed", {
64567
- blockId: block.id ?? null,
64568
- blockKind: block.kind,
64569
- content: summarizeValue(content),
64570
- expectedFields: (definition.manifest.fields ?? []).map((f) => ({
64571
- id: f.id,
64572
- type: f.type,
64573
- required: !!f.required
64574
- })),
64575
- issues: parsed.error?.issues ?? null
64576
- });
64577
- } catch {}
64578
- let data;
64579
- if (parsed.success) data = parsed.data;
64580
- else if (usePlaceholders) {
64581
- const relaxed = getCachedValidator(definition.manifest, "relaxed").safeParse(content);
64582
- 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;
64583
64722
  else {
64584
64723
  const rendered = fallback(`Unable to render block kind "${block.kind}".`);
64585
64724
  return finish(wrapBlock && block.id ? /* @__PURE__ */ jsx(Fragment, { children: wrapBlock(block.id, rendered) }) : /* @__PURE__ */ jsx(Fragment, { children: rendered }), {
@@ -64587,12 +64726,6 @@ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeResources
64587
64726
  override: false
64588
64727
  });
64589
64728
  }
64590
- } else {
64591
- const rendered = fallback(`Invalid content for block kind "${block.kind}".`);
64592
- return finish(wrapBlock && block.id ? /* @__PURE__ */ jsx(Fragment, { children: wrapBlock(block.id, rendered) }) : /* @__PURE__ */ jsx(Fragment, { children: rendered }), {
64593
- outcome: "invalidContent",
64594
- override: false
64595
- });
64596
64729
  }
64597
64730
  try {
64598
64731
  const routes = routeMap ?? dataContext?.routes;
@@ -64618,6 +64751,7 @@ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeResources
64618
64751
  blockId: block.id ?? null,
64619
64752
  blockKind: block.kind
64620
64753
  };
64754
+ baseProps.bookingTimeZone = resolveBookingTimeZone(dataContext);
64621
64755
  let rendered;
64622
64756
  if (OverrideComponent) rendered = /* @__PURE__ */ jsx(OverrideComponent, { ...baseProps });
64623
64757
  else {
@@ -64664,14 +64798,14 @@ const MemoBlockSection = React$1.memo(function MemoBlockSection({ themeResources
64664
64798
  hasResolvedData
64665
64799
  });
64666
64800
  } catch {
64667
- 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}".`);
64668
64802
  return finish(wrapBlock && block.id ? /* @__PURE__ */ jsx(Fragment, { children: wrapBlock(block.id, rendered) }) : /* @__PURE__ */ jsx(Fragment, { children: rendered }), {
64669
64803
  outcome: "exception",
64670
64804
  override: false
64671
64805
  });
64672
64806
  }
64673
64807
  }, (prev, next) => {
64674
- 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;
64675
64809
  });
64676
64810
  function fallback(message) {
64677
64811
  return /* @__PURE__ */ jsx("div", {
@@ -64698,32 +64832,6 @@ function getRenderableContent(block, previewStage = "published") {
64698
64832
  if (!isObjectRecord$1(source)) return {};
64699
64833
  return source;
64700
64834
  }
64701
- function summarizeValue(value) {
64702
- try {
64703
- if (value === null || value === void 0) return value;
64704
- if (typeof value === "string") return value.length > 160 ? `${value.slice(0, 160)}…` : value;
64705
- if (typeof value === "number" || typeof value === "boolean") return value;
64706
- if (Array.isArray(value)) return `[array(${value.length})]`;
64707
- if (typeof value === "object") {
64708
- const rec = value;
64709
- const keys = Object.keys(rec);
64710
- const preview = {};
64711
- for (const k of keys.slice(0, 8)) {
64712
- const v = rec[k];
64713
- if (k === "body" || k === "content") preview[k] = !!(v && typeof v === "object" && isObjectRecord$1(v) && v.type === "doc") ? "{type:doc}" : summarizeValue(v);
64714
- else preview[k] = summarizeValue(v);
64715
- }
64716
- return {
64717
- keys,
64718
- preview
64719
- };
64720
- }
64721
- if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint" || typeof value === "symbol") return String(value);
64722
- return "[uninspectable]";
64723
- } catch {
64724
- return "[uninspectable]";
64725
- }
64726
- }
64727
64835
  //#endregion
64728
64836
  //#region ../blocks/src/structure/schema.ts
64729
64837
  const BlockKind = z.string();
@@ -72368,31 +72476,37 @@ const containerResponsiveThemeCss = `/*
72368
72476
  */
72369
72477
 
72370
72478
  /* Main container */
72371
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar {
72479
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-calendar {
72372
72480
  width: 100%;
72373
72481
  }
72374
72482
 
72375
- :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 {
72376
72486
  border: 1px solid var(--ec-border);
72377
72487
  border-radius: var(--rb-block-radius);
72378
72488
  overflow: hidden;
72379
72489
  }
72380
72490
 
72381
72491
  /* Calendar navigation */
72382
- :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 {
72383
72495
  display: flex;
72384
72496
  align-items: center;
72385
72497
  justify-content: space-between;
72386
72498
  margin-bottom: 1rem;
72387
72499
  }
72388
72500
 
72389
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-nav {
72501
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-calendar-nav {
72390
72502
  display: flex;
72391
72503
  align-items: center;
72392
72504
  gap: 0.5rem;
72393
72505
  }
72394
72506
 
72395
- :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 {
72396
72510
  display: flex;
72397
72511
  align-items: center;
72398
72512
  justify-content: center;
@@ -72407,11 +72521,15 @@ const containerResponsiveThemeCss = `/*
72407
72521
  transition: background-color var(--rb-block-transition) ease;
72408
72522
  }
72409
72523
 
72410
- :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 {
72411
72527
  background-color: var(--ec-nav-hover-bg);
72412
72528
  }
72413
72529
 
72414
- :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 {
72415
72533
  font-size: 1.125rem;
72416
72534
  font-weight: 600;
72417
72535
  min-width: 200px;
@@ -72419,13 +72537,17 @@ const containerResponsiveThemeCss = `/*
72419
72537
  }
72420
72538
 
72421
72539
  /* Day headers */
72422
- :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 {
72423
72543
  display: grid;
72424
72544
  grid-template-columns: repeat(7, minmax(0, 1fr));
72425
72545
  background-color: var(--ec-header-bg);
72426
72546
  }
72427
72547
 
72428
- :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 {
72429
72551
  text-align: center;
72430
72552
  padding: 0.5rem;
72431
72553
  font-size: 0.875rem;
@@ -72435,33 +72557,43 @@ const containerResponsiveThemeCss = `/*
72435
72557
  }
72436
72558
 
72437
72559
  /* Calendar grid */
72438
- :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 {
72439
72563
  display: grid;
72440
72564
  grid-template-columns: repeat(7, minmax(0, 1fr));
72441
72565
  }
72442
72566
 
72443
72567
  /* Day cells */
72444
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-calendar-day {
72568
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-calendar-day {
72445
72569
  min-height: 100px;
72446
72570
  border-bottom: 1px solid var(--ec-border-subtle);
72447
72571
  border-right: 1px solid var(--ec-border-subtle);
72448
72572
  padding: 0.25rem;
72449
72573
  }
72450
72574
 
72451
- :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) {
72452
72578
  border-right: none;
72453
72579
  }
72454
72580
 
72455
- :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 {
72456
72584
  background-color: var(--ec-today-bg);
72457
72585
  }
72458
72586
 
72459
- :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 {
72460
72590
  opacity: var(--ec-other-month-opacity);
72461
72591
  }
72462
72592
 
72463
72593
  /* Day number */
72464
- :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 {
72465
72597
  font-size: 0.875rem;
72466
72598
  font-weight: 500;
72467
72599
  margin-bottom: 0.25rem;
@@ -72469,21 +72601,28 @@ const containerResponsiveThemeCss = `/*
72469
72601
  opacity: var(--ec-day-number-opacity);
72470
72602
  }
72471
72603
 
72472
- :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 {
72473
72608
  font-weight: 700;
72474
72609
  opacity: 1;
72475
72610
  color: var(--ec-today-text);
72476
72611
  }
72477
72612
 
72478
72613
  /* Events list */
72479
- :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 {
72480
72617
  display: flex;
72481
72618
  flex-direction: column;
72482
72619
  gap: 0.25rem;
72483
72620
  }
72484
72621
 
72485
72622
  /* Event item - solid primary background */
72486
- :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 {
72487
72626
  display: flex;
72488
72627
  align-items: center;
72489
72628
  gap: 0.375rem;
@@ -72504,24 +72643,32 @@ const containerResponsiveThemeCss = `/*
72504
72643
  transform var(--rb-block-transition) ease;
72505
72644
  }
72506
72645
 
72507
- :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 {
72508
72649
  background-color: var(--ec-event-solid-hover-bg);
72509
72650
  transform: translateY(-1px);
72510
72651
  }
72511
72652
 
72512
- :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 {
72513
72656
  outline: 2px solid var(--ec-event-solid-bg);
72514
72657
  outline-offset: 2px;
72515
72658
  }
72516
72659
 
72517
- :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 {
72518
72663
  flex-shrink: 0;
72519
72664
  white-space: nowrap;
72520
72665
  font-weight: 600;
72521
72666
  opacity: 0.9;
72522
72667
  }
72523
72668
 
72524
- :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 {
72525
72672
  min-width: 0;
72526
72673
  overflow: hidden;
72527
72674
  text-overflow: ellipsis;
@@ -72529,7 +72676,9 @@ const containerResponsiveThemeCss = `/*
72529
72676
  }
72530
72677
 
72531
72678
  /* More indicator - clickable button style */
72532
- :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 {
72533
72682
  font-size: 0.75rem;
72534
72683
  padding: 0.25rem 0.5rem;
72535
72684
  color: rgb(var(--tb-primary));
@@ -72541,16 +72690,22 @@ const containerResponsiveThemeCss = `/*
72541
72690
  transition: background-color var(--rb-block-transition) ease;
72542
72691
  }
72543
72692
 
72544
- :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 {
72545
72696
  background-color: rgba(var(--tb-primary), 0.1);
72546
72697
  }
72547
72698
 
72548
- :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 {
72549
72702
  outline: 2px solid rgb(var(--tb-primary));
72550
72703
  outline-offset: 2px;
72551
72704
  }
72552
72705
 
72553
- :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 {
72554
72709
  text-align: center;
72555
72710
  font-size: 0.875rem;
72556
72711
  opacity: var(--ec-empty-opacity);
@@ -72558,21 +72713,21 @@ const containerResponsiveThemeCss = `/*
72558
72713
  }
72559
72714
 
72560
72715
  /* Filters container */
72561
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-filters {
72716
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-filters {
72562
72717
  display: flex;
72563
72718
  flex-wrap: wrap;
72564
72719
  gap: 1rem;
72565
72720
  margin-bottom: 1.5rem;
72566
72721
  }
72567
72722
 
72568
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-filter {
72723
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-filter {
72569
72724
  display: flex;
72570
72725
  flex-direction: column;
72571
72726
  gap: 0.375rem;
72572
72727
  min-width: 180px;
72573
72728
  }
72574
72729
 
72575
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-filter-label {
72730
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-filter-label {
72576
72731
  font-size: 0.75rem;
72577
72732
  font-weight: 500;
72578
72733
  text-transform: uppercase;
@@ -72581,19 +72736,23 @@ const containerResponsiveThemeCss = `/*
72581
72736
  }
72582
72737
 
72583
72738
  /* Event filter select inherits base styling from .form-select, only block-specific overrides here */
72584
- :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 {
72585
72742
  /* Use theme input radius instead of block radius for consistency with other form inputs */
72586
72743
  border-radius: var(--rb-input-radius, var(--rb-block-radius));
72587
72744
  }
72588
72745
 
72589
72746
  /* Category filter buttons */
72590
- :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 {
72591
72750
  display: flex;
72592
72751
  flex-wrap: wrap;
72593
72752
  gap: 0.5rem;
72594
72753
  }
72595
72754
 
72596
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-category-btn {
72755
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-category-btn {
72597
72756
  padding: 0.5rem 1rem;
72598
72757
  font-size: 0.875rem;
72599
72758
  font-weight: 500;
@@ -72605,50 +72764,66 @@ const containerResponsiveThemeCss = `/*
72605
72764
  transition: all var(--rb-block-transition) ease;
72606
72765
  }
72607
72766
 
72608
- :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) {
72609
72770
  border-color: rgba(var(--tb-primary), 0.5);
72610
72771
  }
72611
72772
 
72612
- :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 {
72613
72776
  outline: 2px solid rgb(var(--tb-primary));
72614
72777
  outline-offset: 2px;
72615
72778
  }
72616
72779
 
72617
- :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 {
72618
72783
  background-color: rgb(var(--tb-primary));
72619
72784
  border-color: rgb(var(--tb-primary));
72620
72785
  color: var(--ec-event-solid-text);
72621
72786
  }
72622
72787
 
72623
- :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 {
72624
72791
  opacity: 0.5;
72625
72792
  cursor: not-allowed;
72626
72793
  }
72627
72794
 
72628
72795
  /* Allow category filter to be wider for button group */
72629
- :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) {
72630
72799
  min-width: auto;
72631
72800
  flex: 1 1 auto;
72632
72801
  }
72633
72802
 
72634
72803
  /* Combined mode container */
72635
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-combined {
72804
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-combined {
72636
72805
  width: 100%;
72637
72806
  }
72638
72807
 
72639
- :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 {
72640
72811
  display: flex;
72641
72812
  flex-direction: column;
72642
72813
  }
72643
72814
 
72644
72815
  /* Calendar view toggle (Month/Week) in Combined mode */
72645
- :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 {
72646
72819
  display: flex;
72647
72820
  gap: 0.25rem;
72648
72821
  margin-bottom: 1rem;
72649
72822
  }
72650
72823
 
72651
- :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 {
72652
72827
  padding: 0.5rem 1rem;
72653
72828
  font-size: 0.875rem;
72654
72829
  font-weight: 500;
@@ -72661,12 +72836,16 @@ const containerResponsiveThemeCss = `/*
72661
72836
  transition: all var(--rb-block-transition) ease;
72662
72837
  }
72663
72838
 
72664
- :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 {
72665
72842
  opacity: 1;
72666
72843
  border-color: rgba(var(--tb-primary), 0.5);
72667
72844
  }
72668
72845
 
72669
- :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 {
72670
72849
  opacity: 1;
72671
72850
  background-color: rgb(var(--tb-primary));
72672
72851
  border-color: rgb(var(--tb-primary));
@@ -72679,29 +72858,35 @@ const containerResponsiveThemeCss = `/*
72679
72858
  * ----------------------------------------------------------------------------- */
72680
72859
 
72681
72860
  /* Agenda week container */
72682
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-week {
72861
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-agenda-week {
72683
72862
  display: flex;
72684
72863
  flex-direction: column;
72685
72864
  gap: 0;
72686
72865
  }
72687
72866
 
72688
72867
  /* Individual day section */
72689
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-day {
72868
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-agenda-day {
72690
72869
  border-bottom: 1px solid var(--ec-border-subtle);
72691
72870
  }
72692
72871
 
72693
- :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 {
72694
72875
  border-bottom: none;
72695
72876
  }
72696
72877
 
72697
72878
  /* Day header */
72698
- :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 {
72699
72882
  padding: 0.75rem 0;
72700
72883
  background-color: var(--ec-header-bg);
72701
72884
  border-bottom: 1px solid var(--ec-border-subtle);
72702
72885
  }
72703
72886
 
72704
- :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 {
72705
72890
  font-size: 0.875rem;
72706
72891
  font-weight: 600;
72707
72892
  margin: 0;
@@ -72711,7 +72896,9 @@ const containerResponsiveThemeCss = `/*
72711
72896
  }
72712
72897
 
72713
72898
  /* Today badge */
72714
- :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 {
72715
72902
  display: inline-flex;
72716
72903
  align-items: center;
72717
72904
  padding: 0.125rem 0.5rem;
@@ -72725,24 +72912,33 @@ const containerResponsiveThemeCss = `/*
72725
72912
  }
72726
72913
 
72727
72914
  /* Today highlight for entire day section */
72728
- :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 {
72729
72919
  background-color: var(--ec-today-bg);
72730
72920
  }
72731
72921
 
72732
72922
  /* Day content area */
72733
- :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 {
72734
72926
  padding: 0.75rem 0;
72735
72927
  }
72736
72928
 
72737
72929
  /* Events list within a day */
72738
- :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 {
72739
72933
  display: flex;
72740
72934
  flex-direction: column;
72741
72935
  gap: 0.5rem;
72742
72936
  }
72743
72937
 
72744
72938
  /* Empty day message */
72745
- :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 {
72746
72942
  font-size: 0.875rem;
72747
72943
  opacity: var(--ec-empty-opacity);
72748
72944
  margin: 0;
@@ -72754,7 +72950,7 @@ const containerResponsiveThemeCss = `/*
72754
72950
  * Rich event card for agenda view
72755
72951
  * ----------------------------------------------------------------------------- */
72756
72952
 
72757
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-agenda-card {
72953
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-agenda-card {
72758
72954
  display: flex;
72759
72955
  align-items: flex-start;
72760
72956
  gap: 0.75rem;
@@ -72767,13 +72963,17 @@ const containerResponsiveThemeCss = `/*
72767
72963
  transition: all var(--rb-block-transition) ease;
72768
72964
  }
72769
72965
 
72770
- :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 {
72771
72969
  border-color: rgba(var(--tb-primary), 0.5);
72772
72970
  background-color: var(--ec-event-bg);
72773
72971
  }
72774
72972
 
72775
72973
  /* Category color indicator */
72776
- :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 {
72777
72977
  flex-shrink: 0;
72778
72978
  width: 4px;
72779
72979
  align-self: stretch;
@@ -72782,7 +72982,9 @@ const containerResponsiveThemeCss = `/*
72782
72982
  }
72783
72983
 
72784
72984
  /* Card content wrapper */
72785
- :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 {
72786
72988
  flex: 1;
72787
72989
  min-width: 0;
72788
72990
  display: flex;
@@ -72791,28 +72993,36 @@ const containerResponsiveThemeCss = `/*
72791
72993
  }
72792
72994
 
72793
72995
  /* Header row: time + title */
72794
- :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 {
72795
72999
  display: flex;
72796
73000
  align-items: baseline;
72797
73001
  gap: 0.5rem;
72798
73002
  flex-wrap: wrap;
72799
73003
  }
72800
73004
 
72801
- :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 {
72802
73008
  font-size: 0.75rem;
72803
73009
  font-weight: 600;
72804
73010
  opacity: var(--ec-time-opacity);
72805
73011
  white-space: nowrap;
72806
73012
  }
72807
73013
 
72808
- :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 {
72809
73017
  font-size: 0.875rem;
72810
73018
  font-weight: 500;
72811
73019
  line-height: 1.3;
72812
73020
  }
72813
73021
 
72814
73022
  /* Details row: venue, price, capacity */
72815
- :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 {
72816
73026
  display: flex;
72817
73027
  align-items: center;
72818
73028
  gap: 0.75rem;
@@ -72821,26 +73031,36 @@ const containerResponsiveThemeCss = `/*
72821
73031
  opacity: 0.7;
72822
73032
  }
72823
73033
 
72824
- :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 {
72825
73037
  display: inline-flex;
72826
73038
  align-items: center;
72827
73039
  gap: 0.25rem;
72828
73040
  }
72829
73041
 
72830
- :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 {
72831
73045
  flex-shrink: 0;
72832
73046
  opacity: 0.7;
72833
73047
  }
72834
73048
 
72835
- :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 {
72836
73052
  font-weight: 500;
72837
73053
  }
72838
73054
 
72839
- :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 {
72840
73058
  font-weight: 500;
72841
73059
  }
72842
73060
 
72843
- :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 {
72844
73064
  color: rgb(var(--tb-error, 239 68 68));
72845
73065
  opacity: 1;
72846
73066
  }
@@ -72850,20 +73070,24 @@ const containerResponsiveThemeCss = `/*
72850
73070
  * Time-grid layout for recurring class schedules
72851
73071
  * ----------------------------------------------------------------------------- */
72852
73072
 
72853
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable {
73073
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-timetable {
72854
73074
  display: flex;
72855
73075
  flex-direction: column;
72856
73076
  gap: 0.75rem;
72857
73077
  }
72858
73078
 
72859
- :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 {
72860
73082
  display: none;
72861
73083
  gap: 0.375rem;
72862
73084
  overflow-x: auto;
72863
73085
  padding-bottom: 0.125rem;
72864
73086
  }
72865
73087
 
72866
- :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 {
72867
73091
  flex: 0 0 auto;
72868
73092
  padding: 0.5rem 0.75rem;
72869
73093
  border: 1px solid var(--ec-border);
@@ -72878,35 +73102,49 @@ const containerResponsiveThemeCss = `/*
72878
73102
  border-color var(--rb-block-transition) ease;
72879
73103
  }
72880
73104
 
72881
- :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 {
72882
73108
  background-color: rgb(var(--tb-primary));
72883
73109
  border-color: rgb(var(--tb-primary));
72884
73110
  color: rgb(var(--tb-primaryText, 255 255 255));
72885
73111
  }
72886
73112
 
72887
- :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 {
72888
73116
  border: 1px solid var(--ec-border);
72889
73117
  border-radius: var(--rb-block-radius);
72890
73118
  overflow-x: auto;
72891
73119
  overflow-y: hidden;
72892
73120
  }
72893
73121
 
72894
- :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 {
72895
73125
  display: grid;
72896
73126
  grid-template-columns: 4.5rem repeat(7, minmax(8rem, 1fr));
72897
73127
  min-width: 62rem;
72898
73128
  }
72899
73129
 
72900
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-time-rail,
72901
- :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 {
72902
73136
  border-right: 1px solid var(--ec-border-subtle);
72903
73137
  }
72904
73138
 
72905
- :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 {
72906
73142
  border-right: none;
72907
73143
  }
72908
73144
 
72909
- :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 {
72910
73148
  min-height: 3.25rem;
72911
73149
  margin: 0;
72912
73150
  padding: 0.75rem 0.5rem;
@@ -72921,12 +73159,17 @@ const containerResponsiveThemeCss = `/*
72921
73159
  font-weight: 600;
72922
73160
  }
72923
73161
 
72924
- :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 {
72925
73166
  background-color: var(--ec-today-bg);
72926
73167
  color: var(--ec-today-text);
72927
73168
  }
72928
73169
 
72929
- :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 {
72930
73173
  padding: 0.125rem 0.375rem;
72931
73174
  border-radius: var(--rb-button-radius);
72932
73175
  background-color: rgb(var(--tb-primary));
@@ -72936,17 +73179,29 @@ const containerResponsiveThemeCss = `/*
72936
73179
  text-transform: uppercase;
72937
73180
  }
72938
73181
 
72939
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-time-body,
72940
- :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 {
72941
73188
  position: relative;
72942
- 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
+ );
72943
73194
  }
72944
73195
 
72945
- :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 {
72946
73199
  background-color: var(--ec-header-bg);
72947
73200
  }
72948
73201
 
72949
- :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 {
72950
73205
  position: absolute;
72951
73206
  left: 0.625rem;
72952
73207
  transform: translateY(-50%);
@@ -72955,14 +73210,18 @@ const containerResponsiveThemeCss = `/*
72955
73210
  white-space: nowrap;
72956
73211
  }
72957
73212
 
72958
- :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 {
72959
73216
  position: absolute;
72960
73217
  left: 0;
72961
73218
  right: 0;
72962
73219
  border-top: 1px solid var(--ec-border-subtle);
72963
73220
  }
72964
73221
 
72965
- :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 {
72966
73225
  position: absolute;
72967
73226
  min-height: 2.75rem;
72968
73227
  padding: 0.375rem 0.5rem;
@@ -72982,21 +73241,35 @@ const containerResponsiveThemeCss = `/*
72982
73241
  transform var(--rb-block-transition) ease;
72983
73242
  }
72984
73243
 
72985
- :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 {
72986
73247
  box-shadow: 0 4px 12px rgba(var(--tb-text), 0.12);
72987
73248
  transform: translateY(-1px);
72988
73249
  }
72989
73250
 
72990
- :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 {
72991
73254
  outline: 2px solid rgb(var(--tb-primary));
72992
73255
  outline-offset: 2px;
72993
73256
  }
72994
73257
 
72995
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event-time,
72996
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event-title,
72997
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event-teacher,
72998
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event-meta,
72999
- :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 {
73000
73273
  display: block;
73001
73274
  min-width: 0;
73002
73275
  overflow: hidden;
@@ -73004,36 +73277,50 @@ const containerResponsiveThemeCss = `/*
73004
73277
  white-space: nowrap;
73005
73278
  }
73006
73279
 
73007
- :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 {
73008
73283
  font-size: 0.6875rem;
73009
73284
  font-weight: 700;
73010
73285
  opacity: var(--ec-time-opacity);
73011
73286
  }
73012
73287
 
73013
- :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 {
73014
73291
  font-size: 0.8125rem;
73015
73292
  font-weight: 700;
73016
73293
  line-height: 1.25;
73017
73294
  }
73018
73295
 
73019
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-timetable-event-teacher,
73020
- :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 {
73021
73302
  font-size: 0.6875rem;
73022
73303
  opacity: 0.72;
73023
73304
  }
73024
73305
 
73025
- :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 {
73026
73309
  font-size: 0.6875rem;
73027
73310
  font-weight: 600;
73028
73311
  opacity: 0.85;
73029
73312
  }
73030
73313
 
73031
- :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 {
73032
73317
  color: rgb(var(--tb-danger, 220 38 38));
73033
73318
  opacity: 1;
73034
73319
  }
73035
73320
 
73036
- :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 {
73037
73324
  margin: 0;
73038
73325
  padding: 1rem 0.5rem;
73039
73326
  text-align: center;
@@ -73041,7 +73328,9 @@ const containerResponsiveThemeCss = `/*
73041
73328
  opacity: var(--ec-empty-opacity);
73042
73329
  }
73043
73330
 
73044
- :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 {
73045
73334
  margin: 0.25rem 0 0;
73046
73335
  text-align: center;
73047
73336
  font-size: 0.875rem;
@@ -73050,32 +73339,46 @@ const containerResponsiveThemeCss = `/*
73050
73339
 
73051
73340
  @container rb-site (max-width: 767px) {
73052
73341
  @scope ([data-rb-responsive-mode="container"]) to (:scope [data-rb-responsive-mode]) {
73053
- :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 {
73054
73345
  display: flex;
73055
73346
  }
73056
73347
 
73057
- :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 {
73058
73351
  overflow: hidden;
73059
73352
  }
73060
73353
 
73061
- :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 {
73062
73357
  grid-template-columns: 4rem minmax(0, 1fr);
73063
73358
  min-width: 0;
73064
73359
  }
73065
73360
 
73066
- :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'] {
73067
73364
  display: none;
73068
73365
  }
73069
73366
 
73070
- :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 {
73071
73370
  border-right: none;
73072
73371
  }
73073
73372
 
73074
- :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 {
73075
73376
  border-right: 1px solid var(--ec-border-subtle);
73076
73377
  }
73077
73378
 
73078
- :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 {
73079
73382
  justify-content: flex-start;
73080
73383
  padding-inline: 0.75rem;
73081
73384
  }
@@ -73088,7 +73391,7 @@ const containerResponsiveThemeCss = `/*
73088
73391
  * three-state availability (available / filling / waitlist), and a footer CTA.
73089
73392
  * ----------------------------------------------------------------------------- */
73090
73393
 
73091
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board {
73394
+ :where(.theme-scope) :where([data-block='event-calendar']) .event-week-board {
73092
73395
  /* Status accent tokens — map the three availability states onto theme colours.
73093
73396
  * available -> secondary, filling -> accent, waitlist -> muted text. */
73094
73397
  --ec-status-available: rgb(var(--tb-secondary));
@@ -73105,17 +73408,20 @@ const containerResponsiveThemeCss = `/*
73105
73408
 
73106
73409
  /* Opt-in raised look: a soft drop shadow so the board lifts off the page.
73107
73410
  * Generic default (no [data-elevated]) stays flat. */
73108
- :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] {
73109
73414
  box-shadow: 0 14px 34px -24px rgba(var(--tb-text), 0.35);
73110
73415
  }
73111
73416
 
73112
- /* Top bar: title + legend */
73113
- :where(.theme-scope) :where([data-block="event-calendar"]) .event-week-board-top {
73114
- 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);
73115
73423
  align-items: center;
73116
- justify-content: space-between;
73117
73424
  gap: 1rem;
73118
- flex-wrap: wrap;
73119
73425
  padding: 1.1rem 1.5rem;
73120
73426
  /* surfaceAlt gives the header/footer a legible tint against the white day-grid
73121
73427
  * body — the faint \`--ec-header-bg\` (5% text) is invisible on light palettes. */
@@ -73123,7 +73429,10 @@ const containerResponsiveThemeCss = `/*
73123
73429
  border-bottom: 1px solid var(--ec-border-subtle);
73124
73430
  }
73125
73431
 
73126
- :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;
73127
73436
  font-size: 0.8125rem;
73128
73437
  font-weight: 600;
73129
73438
  letter-spacing: 0.12em;
@@ -73131,7 +73440,67 @@ const containerResponsiveThemeCss = `/*
73131
73440
  color: rgb(var(--tb-primary));
73132
73441
  }
73133
73442
 
73134
- :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;
73135
73504
  display: flex;
73136
73505
  align-items: center;
73137
73506
  gap: 1.1rem;
@@ -73141,38 +73510,72 @@ const containerResponsiveThemeCss = `/*
73141
73510
  opacity: 0.75;
73142
73511
  }
73143
73512
 
73144
- :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 {
73145
73536
  display: inline-flex;
73146
73537
  align-items: center;
73147
73538
  gap: 0.4rem;
73148
73539
  }
73149
73540
 
73150
- :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 {
73151
73544
  width: 0.55rem;
73152
73545
  height: 0.55rem;
73153
73546
  border-radius: 50%;
73154
73547
  display: inline-block;
73155
73548
  }
73156
73549
 
73157
- :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'] {
73158
73553
  background-color: var(--ec-status-available);
73159
73554
  }
73160
73555
 
73161
- :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'] {
73162
73559
  background-color: var(--ec-status-filling);
73163
73560
  }
73164
73561
 
73165
- :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'] {
73166
73565
  background-color: var(--ec-status-waitlist);
73167
73566
  }
73168
73567
 
73169
73568
  /* Day columns grid */
73170
- :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 {
73171
73572
  display: grid;
73172
73573
  grid-template-columns: repeat(var(--event-week-board-cols), minmax(0, 1fr));
73173
73574
  }
73174
73575
 
73175
- :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 {
73176
73579
  display: flex;
73177
73580
  flex-direction: column;
73178
73581
  min-height: 15rem;
@@ -73182,11 +73585,15 @@ const containerResponsiveThemeCss = `/*
73182
73585
  border-right: var(--rb-border-width, 1px) solid rgb(var(--tb-border));
73183
73586
  }
73184
73587
 
73185
- :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 {
73186
73591
  border-right: none;
73187
73592
  }
73188
73593
 
73189
- :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 {
73190
73597
  display: flex;
73191
73598
  align-items: baseline;
73192
73599
  gap: 0.4rem;
@@ -73195,11 +73602,16 @@ const containerResponsiveThemeCss = `/*
73195
73602
  border-bottom: var(--rb-border-width, 1px) solid rgb(var(--tb-border));
73196
73603
  }
73197
73604
 
73198
- :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 {
73199
73609
  background-color: var(--ec-today-bg);
73200
73610
  }
73201
73611
 
73202
- :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 {
73203
73615
  font-size: 0.6875rem;
73204
73616
  font-weight: 600;
73205
73617
  letter-spacing: 0.1em;
@@ -73207,18 +73619,25 @@ const containerResponsiveThemeCss = `/*
73207
73619
  opacity: 0.65;
73208
73620
  }
73209
73621
 
73210
- :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 {
73211
73626
  opacity: 1;
73212
73627
  color: var(--ec-today-text);
73213
73628
  }
73214
73629
 
73215
- :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 {
73216
73633
  font-size: 0.8125rem;
73217
73634
  font-weight: 600;
73218
73635
  opacity: 0.5;
73219
73636
  }
73220
73637
 
73221
- :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 {
73222
73641
  display: flex;
73223
73642
  flex-direction: column;
73224
73643
  gap: 0.65rem;
@@ -73227,7 +73646,9 @@ const containerResponsiveThemeCss = `/*
73227
73646
  }
73228
73647
 
73229
73648
  /* Class card */
73230
- :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 {
73231
73652
  display: flex;
73232
73653
  flex-direction: column;
73233
73654
  gap: 0.45rem;
@@ -73247,40 +73668,54 @@ const containerResponsiveThemeCss = `/*
73247
73668
  border-color var(--rb-block-transition) ease;
73248
73669
  }
73249
73670
 
73250
- :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'] {
73251
73674
  border-left-color: var(--ec-status-filling);
73252
73675
  }
73253
73676
 
73254
- :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'] {
73255
73680
  border-left-color: var(--ec-status-waitlist);
73256
73681
  }
73257
73682
 
73258
- :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 {
73259
73686
  transform: translateY(-2px);
73260
73687
  box-shadow: 0 6px 16px -8px rgba(var(--tb-text), 0.28);
73261
73688
  border-color: rgba(var(--tb-primary), 0.4);
73262
73689
  }
73263
73690
 
73264
- :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 {
73265
73694
  outline: 2px solid rgb(var(--tb-primary));
73266
73695
  outline-offset: 2px;
73267
73696
  }
73268
73697
 
73269
- :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 {
73270
73701
  font-family: var(--font-heading, inherit);
73271
73702
  font-size: 0.9375rem;
73272
73703
  font-weight: 600;
73273
73704
  line-height: 1.2;
73274
73705
  }
73275
73706
 
73276
- :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 {
73277
73710
  font-size: 0.75rem;
73278
73711
  letter-spacing: 0.01em;
73279
73712
  opacity: 0.7;
73280
73713
  }
73281
73714
 
73282
73715
  /* Capacity pill */
73283
- :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 {
73284
73719
  align-self: flex-start;
73285
73720
  display: inline-flex;
73286
73721
  align-items: center;
@@ -73298,20 +73733,26 @@ const containerResponsiveThemeCss = `/*
73298
73733
  border-color: var(--ec-border);
73299
73734
  }
73300
73735
 
73301
- :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'] {
73302
73739
  background-color: rgba(var(--tb-accent), 0.14);
73303
73740
  color: var(--ec-status-filling);
73304
73741
  border-color: rgba(var(--tb-accent), 0.32);
73305
73742
  }
73306
73743
 
73307
- :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'] {
73308
73747
  background-color: transparent;
73309
73748
  color: rgba(var(--tb-text), 0.6);
73310
73749
  border-color: var(--ec-border);
73311
73750
  }
73312
73751
 
73313
73752
  /* Footer */
73314
- :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 {
73315
73756
  display: flex;
73316
73757
  align-items: center;
73317
73758
  justify-content: space-between;
@@ -73323,7 +73764,9 @@ const containerResponsiveThemeCss = `/*
73323
73764
  border-top: 1px solid var(--ec-border-subtle);
73324
73765
  }
73325
73766
 
73326
- :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 {
73327
73770
  margin: 0;
73328
73771
  font-size: 0.875rem;
73329
73772
  opacity: 0.75;
@@ -73332,36 +73775,69 @@ const containerResponsiveThemeCss = `/*
73332
73775
  /* Responsive: collapse day columns to a stacked list on narrow viewports */
73333
73776
  @container rb-site (max-width: 1023px) {
73334
73777
  @scope ([data-rb-responsive-mode="container"]) to (:scope [data-rb-responsive-mode]) {
73335
- :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 {
73336
73800
  grid-template-columns: 1fr;
73337
73801
  }
73338
73802
 
73339
- :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 {
73340
73806
  min-height: 0;
73341
73807
  border-right: none;
73342
73808
  border-bottom: var(--rb-border-width, 1px) solid rgb(var(--tb-border));
73343
73809
  }
73344
73810
 
73345
- :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 {
73346
73814
  border-bottom: none;
73347
73815
  }
73348
73816
 
73349
- :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 {
73350
73820
  display: none;
73351
73821
  }
73352
73822
 
73353
- :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 {
73354
73826
  border-bottom: none;
73355
73827
  padding-bottom: 0.25rem;
73356
73828
  }
73357
73829
 
73358
- :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 {
73359
73833
  flex-direction: row;
73360
73834
  flex-wrap: wrap;
73361
73835
  padding-top: 0.35rem;
73362
73836
  }
73363
73837
 
73364
- :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 {
73365
73841
  flex: 1 1 14rem;
73366
73842
  }
73367
73843
  }
@@ -73369,11 +73845,37 @@ const containerResponsiveThemeCss = `/*
73369
73845
 
73370
73846
  @container rb-site (max-width: 639px) {
73371
73847
  @scope ([data-rb-responsive-mode="container"]) to (:scope [data-rb-responsive-mode]) {
73372
- :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 {
73373
73873
  display: none;
73374
73874
  }
73375
73875
 
73376
- :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 {
73377
73879
  flex: 1 1 100%;
73378
73880
  }
73379
73881
  }
@@ -73390,8 +73892,9 @@ const containerResponsiveThemeCss = `/*
73390
73892
  * Opt-in only: the band paints when the board root carries [data-banded];
73391
73893
  * the generic default is bandless.
73392
73894
  * ----------------------------------------------------------------------------- */
73393
- :where(.theme-scope) [data-slot="section"]:has(.event-calendar--week-board[data-banded])::before {
73394
- content: "";
73895
+ :where(.theme-scope)
73896
+ [data-slot='section']:has(.event-calendar--week-board[data-banded])::before {
73897
+ content: '';
73395
73898
  position: absolute;
73396
73899
  inset: 0;
73397
73900
  z-index: -9;
@@ -73445,7 +73948,7 @@ const containerResponsiveThemeCss = `/*
73445
73948
  * ----------------------------------------------------------------------------- */
73446
73949
 
73447
73950
  /* Modal overlay */
73448
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal-overlay {
73951
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal-overlay {
73449
73952
  position: fixed;
73450
73953
  inset: 0;
73451
73954
  background: var(--ec-modal-overlay-bg);
@@ -73459,12 +73962,16 @@ const containerResponsiveThemeCss = `/*
73459
73962
  }
73460
73963
 
73461
73964
  @keyframes ec-modal-fade-in {
73462
- from { opacity: 0; }
73463
- to { opacity: 1; }
73965
+ from {
73966
+ opacity: 0;
73967
+ }
73968
+ to {
73969
+ opacity: 1;
73970
+ }
73464
73971
  }
73465
73972
 
73466
73973
  /* Modal dialog */
73467
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal {
73974
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal {
73468
73975
  position: relative;
73469
73976
  background: var(--ec-modal-bg);
73470
73977
  border-radius: var(--rb-block-radius);
@@ -73488,17 +73995,17 @@ const containerResponsiveThemeCss = `/*
73488
73995
  }
73489
73996
 
73490
73997
  /* Event modal - constrained width for card */
73491
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal--event {
73998
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal--event {
73492
73999
  max-width: 26rem;
73493
74000
  }
73494
74001
 
73495
74002
  /* Day modal */
73496
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal--day {
74003
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal--day {
73497
74004
  max-width: 28rem;
73498
74005
  }
73499
74006
 
73500
74007
  /* Close button */
73501
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal-close {
74008
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal-close {
73502
74009
  position: absolute;
73503
74010
  top: 0.75rem;
73504
74011
  right: 0.75rem;
@@ -73519,31 +74026,35 @@ const containerResponsiveThemeCss = `/*
73519
74026
  z-index: 10;
73520
74027
  }
73521
74028
 
73522
- :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 {
73523
74032
  opacity: 1;
73524
74033
  background-color: rgba(var(--tb-text), 0.1);
73525
74034
  }
73526
74035
 
73527
- :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 {
73528
74039
  outline: 2px solid rgb(var(--tb-primary));
73529
74040
  outline-offset: 2px;
73530
74041
  }
73531
74042
 
73532
74043
  /* Modal header (for day modal) */
73533
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal-header {
74044
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal-header {
73534
74045
  padding: 1.5rem 1.5rem 1rem;
73535
74046
  padding-right: 3rem; /* Space for close button */
73536
74047
  border-bottom: 1px solid var(--ec-border);
73537
74048
  }
73538
74049
 
73539
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal-title {
74050
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal-title {
73540
74051
  font-size: 1.125rem;
73541
74052
  font-weight: 600;
73542
74053
  color: var(--ec-text);
73543
74054
  margin: 0;
73544
74055
  }
73545
74056
 
73546
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal-subtitle {
74057
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal-subtitle {
73547
74058
  font-size: 0.875rem;
73548
74059
  color: var(--ec-text);
73549
74060
  opacity: 0.7;
@@ -73551,17 +74062,20 @@ const containerResponsiveThemeCss = `/*
73551
74062
  }
73552
74063
 
73553
74064
  /* Modal content */
73554
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal-content {
74065
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal-content {
73555
74066
  padding: 1rem;
73556
74067
  }
73557
74068
 
73558
74069
  /* Event modal: tighter padding for card */
73559
- :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 {
73560
74074
  padding: 0.5rem;
73561
74075
  }
73562
74076
 
73563
74077
  /* Day events list */
73564
- :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 {
73565
74079
  display: flex;
73566
74080
  flex-direction: column;
73567
74081
  gap: 0.5rem;
@@ -73569,7 +74083,9 @@ const containerResponsiveThemeCss = `/*
73569
74083
  }
73570
74084
 
73571
74085
  /* AgendaEventCard in button mode inherits most styles, just needs cursor */
73572
- :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 {
73573
74089
  cursor: pointer;
73574
74090
  text-align: left;
73575
74091
  font-family: inherit;
@@ -73578,7 +74094,9 @@ const containerResponsiveThemeCss = `/*
73578
74094
  /* Responsive adjustments */
73579
74095
  @container rb-site (max-width: 640px) {
73580
74096
  @scope ([data-rb-responsive-mode="container"]) to (:scope [data-rb-responsive-mode]) {
73581
- :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 {
73582
74100
  margin-left: -1.5rem;
73583
74101
  margin-right: -1.5rem;
73584
74102
  border-left: none;
@@ -73586,28 +74104,38 @@ const containerResponsiveThemeCss = `/*
73586
74104
  border-radius: 0;
73587
74105
  }
73588
74106
 
73589
- :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 {
73590
74110
  font-size: 0.75rem;
73591
74111
  padding: 0.375rem 0.125rem;
73592
74112
  }
73593
74113
 
73594
- :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 {
73595
74117
  min-height: 88px;
73596
74118
  padding: 0.125rem;
73597
74119
  }
73598
74120
 
73599
- :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 {
73600
74124
  font-size: 0.9375rem;
73601
74125
  min-width: 0;
73602
74126
  }
73603
74127
 
73604
- :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 {
73605
74131
  font-size: 0.75rem;
73606
74132
  margin-bottom: 0.125rem;
73607
74133
  padding: 0 0.125rem;
73608
74134
  }
73609
74135
 
73610
- :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 {
73611
74139
  justify-content: center;
73612
74140
  gap: 0.25rem;
73613
74141
  padding: 0.1875rem 0.25rem;
@@ -73615,25 +74143,34 @@ const containerResponsiveThemeCss = `/*
73615
74143
  border-radius: calc(var(--rb-block-radius) / 3);
73616
74144
  }
73617
74145
 
73618
- :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 {
73619
74149
  text-align: center;
73620
74150
  font-size: 0.625rem;
73621
74151
  }
73622
74152
 
73623
- :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 {
73624
74156
  display: none;
73625
74157
  }
73626
74158
 
73627
- :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 {
73628
74162
  padding: 0.125rem 0.25rem;
73629
74163
  font-size: 0.6875rem;
73630
74164
  }
73631
74165
 
73632
- :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 {
73633
74170
  margin-right: 0.25rem;
73634
74171
  }
73635
74172
 
73636
- :where(.theme-scope) :where([data-block="event-calendar"]) .ec-modal {
74173
+ :where(.theme-scope) :where([data-block='event-calendar']) .ec-modal {
73637
74174
  max-width: 100%;
73638
74175
  max-height: 85vh;
73639
74176
  margin: 0 0.5rem;
@@ -78654,6 +79191,82 @@ const SUPPORTED_LOADER_ENDPOINTS$1 = [
78654
79191
  "getPublicBookingServices",
78655
79192
  "getPublicWeeklySlotAvailability"
78656
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
+ }
78657
79270
  //#endregion
78658
79271
  //#region ../blocks/src/system/data/batching.ts
78659
79272
  function stableNormalize(value) {
@@ -80733,6 +81346,7 @@ function buildSiteRenderSupport(site, mediaAssets) {
80733
81346
  site: site.site,
80734
81347
  sdkConfig: site.sdkConfig ?? null,
80735
81348
  bookingOfferingPresets: site.bookingOfferingPresets ?? [],
81349
+ bookingTimeZone: site.bookingTimeZone ?? "UTC",
80736
81350
  ...customBlocks ? { customBlocks } : {},
80737
81351
  supabaseUrl: site.supabaseUrl,
80738
81352
  routeMap: site.routes,
@@ -80749,14 +81363,21 @@ function convertPageResponseBlock(block) {
80749
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}`);
80750
81364
  if (typeof block.kind !== "string") throw new Error(`Invalid block kind in page: expected string, got ${typeof block.kind}`);
80751
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);
80752
81367
  return {
80753
81368
  id: block.id,
80754
81369
  kind: block.kind,
80755
81370
  purpose: block.purpose,
80756
81371
  content: sanitizeSdkRuntimeBlockContent(block.kind, readContentRecord(block.content) ?? {}),
80757
- draftContent: sanitizeNullableSdkRuntimeBlockContent(block.kind, readNestedContentRecord(block.draftContent))
81372
+ draftContent: sanitizeNullableSdkRuntimeBlockContent(block.kind, readNestedContentRecord(block.draftContent)),
81373
+ ...admission ? { admission } : {}
80758
81374
  };
80759
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
+ }
80760
81381
  function buildPageOutline(input) {
80761
81382
  return {
80762
81383
  name: input.name,
@@ -80765,6 +81386,63 @@ function buildPageOutline(input) {
80765
81386
  blocks: input.blocks.map(convertPageResponseBlock)
80766
81387
  };
80767
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
+ }
80768
81446
  function isRecord$5(value) {
80769
81447
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
80770
81448
  }
@@ -82078,6 +82756,7 @@ const DEFAULT_TEMPLATE_DEFINITIONS = {
82078
82756
  {
82079
82757
  blockKind: "block.body-text",
82080
82758
  scope: "entry",
82759
+ content: { body: createRichTextDoc([""]) },
82081
82760
  bindings: EVENT_BODY_TEXT_BINDINGS
82082
82761
  },
82083
82762
  {
@@ -82124,6 +82803,7 @@ const DEFAULT_TEMPLATE_DEFINITIONS = {
82124
82803
  }, {
82125
82804
  blockKind: "block.body-text",
82126
82805
  scope: "entry",
82806
+ content: { body: createRichTextDoc([""]) },
82127
82807
  bindings: TEAM_MEMBER_BODY_TEXT_BINDINGS
82128
82808
  }]
82129
82809
  },
@@ -83258,6 +83938,14 @@ const isRecord$1 = isRecord$26;
83258
83938
  const applyBindingsToContent = applyBindingsToContent$1;
83259
83939
  //#endregion
83260
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
+ }
83261
83949
  function createTemplateRenderTarget(source, templateId) {
83262
83950
  switch (source.kind) {
83263
83951
  case "entry-template": return {
@@ -83308,7 +83996,12 @@ async function processTemplatePage(input) {
83308
83996
  templatePage: null,
83309
83997
  resolvedData: {}
83310
83998
  };
83311
- 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
+ }));
83312
84005
  if (blocks.length === 0) return {
83313
84006
  templatePage: null,
83314
84007
  resolvedData: {}
@@ -83322,7 +84015,7 @@ async function processTemplatePage(input) {
83322
84015
  return {
83323
84016
  templatePage,
83324
84017
  resolvedData: await resolveBlockDataWithDeps(input.deps, {
83325
- page: templatePage,
84018
+ page: projectRenderablePageOutline(templatePage),
83326
84019
  siteId: input.siteId,
83327
84020
  renderTarget: createTemplateRenderTarget(input.renderTargetSource, template.id),
83328
84021
  previewStage: input.previewStage,
@@ -83332,58 +84025,74 @@ async function processTemplatePage(input) {
83332
84025
  })
83333
84026
  };
83334
84027
  }
83335
- function resolveTemplateBlockSequence(block, bindingContext, slotContent) {
84028
+ function resolveTemplateBlockSequence(input) {
84029
+ const { block } = input;
83336
84030
  const slotKey = readEntrySlotKey(block);
83337
84031
  if (slotKey) return selectBlocksForDeclaredEntrySlot({
83338
84032
  declaredSlotKey: slotKey,
83339
- entrySlots: slotContent ?? []
83340
- }).map(mapEntrySlotBlock);
84033
+ entrySlots: input.slotContent ?? []
84034
+ }).map((slotBlock) => admitEntrySlotBlock(slotBlock, input.customBlocks));
83341
84035
  if (block.blockKind === "system.entry-slot") return [];
83342
- return [resolveTemplateBlock(block, bindingContext)];
84036
+ return [resolveTemplateBlock(block, input.bindingContext, input.customBlocks)];
83343
84037
  }
83344
- function resolveTemplateBlock(block, bindingContext) {
83345
- const baseContent = sanitizeSdkRuntimeBlockContent(block.blockKind, block.content ?? {});
83346
- if (block.scope === "template") return {
83347
- id: block.id,
83348
- kind: block.blockKind,
83349
- purpose: "template-layout",
83350
- content: baseContent
83351
- };
83352
- const bindings = block.bindings ?? {};
83353
- const resolvedContent = Object.keys(bindings).length > 0 ? applyBindingsToContent(baseContent, bindings, bindingContext) : baseContent;
83354
- return {
84038
+ function resolveTemplateBlock(block, bindingContext, customBlocks) {
84039
+ const base = {
83355
84040
  id: block.id,
83356
84041
  kind: block.blockKind,
83357
- purpose: "entry-content",
83358
- content: resolvedContent
83359
- };
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
+ });
83360
84062
  }
83361
84063
  function readEntrySlotKey(block) {
83362
84064
  if (block.blockKind !== "system.entry-slot" || block.scope !== "template") return null;
83363
84065
  const parsed = parseSlotKey(block.content?.slotKey);
83364
84066
  return parsed.ok ? parsed.value : null;
83365
84067
  }
83366
- function mapEntrySlotBlock(block) {
83367
- const mapped = {
84068
+ function admitEntrySlotBlock(block, customBlocks) {
84069
+ const base = {
83368
84070
  id: block.id ?? block.blockId ?? null,
83369
84071
  kind: block.kind,
83370
84072
  purpose: block.purpose,
83371
- orderIndex: block.orderIndex ?? null,
83372
- content: normalizeEntrySlotBlockContent(block.content),
83373
- draftContent: normalizeNullableEntrySlotContent(block.draftContent),
83374
- publishedContent: normalizeNullableEntrySlotContent(block.publishedContent)
83375
- };
83376
- return block.bindings == null ? mapped : {
83377
- ...mapped,
83378
- bindings: block.bindings
83379
- };
83380
- }
83381
- function normalizeNullableEntrySlotContent(content) {
83382
- return content == null ? null : normalizeEntrySlotBlockContent(content);
83383
- }
83384
- function normalizeEntrySlotBlockContent(content) {
83385
- const value = content ?? {};
83386
- 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
+ });
83387
84096
  }
83388
84097
  //#endregion
83389
84098
  //#region src/rendering/helpers/loadContent.ts
@@ -83412,6 +84121,7 @@ function getRejectedReason(result) {
83412
84121
  function toTemplateContentRenderSupport(support, siteId) {
83413
84122
  return {
83414
84123
  bookingOfferingPresets: support.bookingOfferingPresets,
84124
+ bookingTimeZone: support.bookingTimeZone,
83415
84125
  ...support.customBlocks ? { customBlocks: support.customBlocks } : {},
83416
84126
  entriesByIdentifier: support.entriesByIdentifier,
83417
84127
  ...support.mediaAssets ? { mediaAssets: support.mediaAssets } : {},
@@ -83554,7 +84264,6 @@ async function loadContentFromContentResponseWithDeps(deps, params) {
83554
84264
  entry,
83555
84265
  templatePage,
83556
84266
  resolvedData,
83557
- bookingOfferingPresets: support.bookingOfferingPresets,
83558
84267
  dataContext: { contentEntry: {
83559
84268
  ...entry.content ?? {},
83560
84269
  id: entry.id,
@@ -83623,7 +84332,6 @@ async function loadContentFromContentResponseWithDeps(deps, params) {
83623
84332
  pageSurface,
83624
84333
  templatePage,
83625
84334
  resolvedData,
83626
- bookingOfferingPresets: support.bookingOfferingPresets,
83627
84335
  dataContext: {
83628
84336
  pageSurface: {
83629
84337
  ...pageSurface.content ?? {},
@@ -83642,15 +84350,16 @@ async function loadContentFromContentResponseWithDeps(deps, params) {
83642
84350
  const pageRecord = pageData;
83643
84351
  const canonicalPagePath = pageData.path ?? pageRecord.path ?? "/";
83644
84352
  const draftPagePath = pageRecord.draftPath ?? pageRecord.path ?? canonicalPagePath;
83645
- const pageOutline = buildPageOutline({
84353
+ const pageOutline = buildRenderablePageOutline({
83646
84354
  name: pageData.name,
83647
84355
  path: canonicalPagePath,
83648
84356
  fallbackPath: "/",
83649
84357
  purpose: pageData.purpose,
83650
- blocks: pageData.blocks
84358
+ blocks: pageData.blocks,
84359
+ customBlocks: support.customBlocks
83651
84360
  });
83652
84361
  const resolvedData = await resolveBlockDataWithDeps(deps, {
83653
- page: pageOutline,
84362
+ page: projectRenderablePageOutline(pageOutline),
83654
84363
  siteId,
83655
84364
  renderTarget: {
83656
84365
  kind: "page",
@@ -83686,6 +84395,7 @@ async function loadContentFromContentResponseWithDeps(deps, params) {
83686
84395
  ...support.customBlocks ? { customBlocks: support.customBlocks } : {},
83687
84396
  resolvedData,
83688
84397
  bookingOfferingPresets: support.bookingOfferingPresets,
84398
+ bookingTimeZone: support.bookingTimeZone,
83689
84399
  site: support.site,
83690
84400
  sdkConfig: support.sdkConfig,
83691
84401
  supabaseUrl: support.supabaseUrl,
@@ -83761,16 +84471,21 @@ function toBlocksPageRendererDataContext(dataContext) {
83761
84471
  imageResolveContext: toBlocksImageResolveContextInput(dataContext.imageResolveContext)
83762
84472
  };
83763
84473
  }
83764
- function PageRenderer(props) {
83765
- const blocksSdkConfig = props.sdkConfig ? { customBlocks: normalizeSdkCustomBlocks(props.sdkConfig.customBlocks) } : props.sdkConfig;
83766
- const { rendering: _rendering, theme: _theme, themeTokens: _themeTokens, ...commonProps } = props;
83767
- const commonBlocksProps = {
83768
- ...commonProps,
84474
+ function toBlocksCommonProps(props) {
84475
+ return {
84476
+ page: props.page,
84477
+ runtimeBoundaries: props.runtimeBoundaries,
83769
84478
  dataContext: props.dataContext ? toBlocksPageRendererDataContext(props.dataContext) : void 0,
84479
+ routeMap: props.routeMap,
84480
+ wrapBlock: props.wrapBlock,
84481
+ registry: props.registry,
83770
84482
  blockOverrides: toBlocksBlockOverrides(props.blockOverrides),
83771
- sdkConfig: blocksSdkConfig,
84483
+ sdkConfig: props.sdkConfig ? { customBlocks: normalizeSdkCustomBlocks(props.sdkConfig.customBlocks) } : props.sdkConfig,
83772
84484
  customBlocks: normalizeSdkCustomBlocks(props.customBlocks)
83773
84485
  };
84486
+ }
84487
+ function PageRenderer(props) {
84488
+ const commonBlocksProps = toBlocksCommonProps(props);
83774
84489
  const blocksProps = isOverrideOnlyPageRenderer(props) ? {
83775
84490
  ...commonBlocksProps,
83776
84491
  rendering: { kind: "overrides-only" },
@@ -83842,12 +84557,14 @@ function toPageHydrationBootstrapConfig(props) {
83842
84557
  mediaAssets: props.mediaAssets
83843
84558
  };
83844
84559
  }
84560
+ function resolveSdkBookingTimeZone(timeZone) {
84561
+ return timeZone ?? "UTC";
84562
+ }
83845
84563
  function PageContent(props) {
83846
- 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;
83847
84565
  const rendererCommonProps = {
83848
84566
  page,
83849
84567
  runtimeBoundaries,
83850
- usePlaceholders,
83851
84568
  dataContext: {
83852
84569
  siteId,
83853
84570
  apiBaseUrl,
@@ -83855,6 +84572,7 @@ function PageContent(props) {
83855
84572
  previewToken,
83856
84573
  resolvedData,
83857
84574
  bookingOfferingPresets: bookingOfferingPresets ?? [],
84575
+ bookingTimeZone: resolveSdkBookingTimeZone(bookingTimeZone),
83858
84576
  routes: routeMap,
83859
84577
  pagesByIdentifier,
83860
84578
  entriesByIdentifier,
@@ -85065,7 +85783,7 @@ var CircuitOpenError = class extends Error {
85065
85783
  * 1. This constant
85066
85784
  * 2. The "version" field in package.json
85067
85785
  */
85068
- const SDK_VERSION = "0.135.0";
85786
+ const SDK_VERSION = "0.136.0";
85069
85787
  //#endregion
85070
85788
  //#region src/next/content-load-failure.ts
85071
85789
  const SdkContentLoadError = RiverbankContentLoadError;
@@ -85330,6 +86048,7 @@ async function renderPage(input, page, dataContext) {
85330
86048
  portalToken: input.portalToken,
85331
86049
  resolvedData: input.content.resolvedData,
85332
86050
  bookingOfferingPresets: input.content.bookingOfferingPresets,
86051
+ bookingTimeZone: input.content.bookingTimeZone,
85333
86052
  sdkConfig: input.content.sdkConfig,
85334
86053
  supabaseUrl: input.content.supabaseUrl,
85335
86054
  mediaAssets: input.content.mediaAssets,
@@ -86238,6 +86957,11 @@ function resolveKnownEndpointPolicy(endpoint, params) {
86238
86957
  endpoint,
86239
86958
  reason: "force_refresh"
86240
86959
  };
86960
+ if (isSupportedLoaderEndpoint$1(endpoint) && getPublicLoaderCachePolicy(endpoint).kind === "live") return {
86961
+ kind: "live-only",
86962
+ endpoint,
86963
+ reason: "safety_sensitive_booking"
86964
+ };
86241
86965
  const override = RUNTIME_CACHE_DURABILITY_OVERRIDES[endpoint];
86242
86966
  if (override.kind === "live-only") return {
86243
86967
  kind: "live-only",
@@ -86452,6 +87176,17 @@ function combineAbortSignals(...signals) {
86452
87176
  return controller.signal;
86453
87177
  }
86454
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
86455
87190
  //#region src/client/index.ts
86456
87191
  let prebuildModule = null;
86457
87192
  function tryRequire(modulePath) {
@@ -86919,7 +87654,7 @@ function createRiverbankClientWithDeps(deps, config) {
86919
87654
  } catch (error) {
86920
87655
  convertToTypedError(error);
86921
87656
  }
86922
- if (cacheEnabled) cache.set(cacheKey, data);
87657
+ if (shouldWrite(cacheEnabled, options.force)) cache.set(cacheKey, data);
86923
87658
  if (allowFallbacks && !isPreview) await writePublishedRuntimeCache(options.publishedRuntimeCache, data);
86924
87659
  return emitStatus("live", data, statusDetails());
86925
87660
  } catch (error) {
@@ -87157,7 +87892,7 @@ function createRiverbankClientWithDeps(deps, config) {
87157
87892
  },
87158
87893
  options: { signal: sig }
87159
87894
  });
87160
- }, { signal });
87895
+ }, liveLoaderOptions("listPublicEvents", signal));
87161
87896
  },
87162
87897
  async getPublicEventDetails(params) {
87163
87898
  const { siteId, limit, from, to, afterStartsAt, afterId, stage, categoryIds, venueId, staffMemberId, kind, eventSurface, eventPresets, scheduleScope, seriesId, includeOccurrenceId, signal } = params;
@@ -87192,7 +87927,7 @@ function createRiverbankClientWithDeps(deps, config) {
87192
87927
  }] },
87193
87928
  options: { signal: sig }
87194
87929
  }), requestId);
87195
- }, { signal });
87930
+ }, liveLoaderOptions("getPublicEventDetails", signal));
87196
87931
  },
87197
87932
  async listPublicTeamMembers(params) {
87198
87933
  const { siteId, stage, signal } = params;