@riverbankcms/sdk 0.152.0 → 0.154.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 (303) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/{EventEmbeddedCheckoutStep-DVQXWFm6.mjs → EventEmbeddedCheckoutStep-ba9npQtb.mjs} +1 -1
  3. package/dist/{PreviewEditorSidebar-Dr4NJi3Q.mjs → PreviewEditorSidebar-C7FiaxlF.mjs} +194 -22
  4. package/dist/{PreviewEditorUI-DSZXQbyh.mjs → PreviewEditorUI-DFst50q1.mjs} +20 -44
  5. package/dist/{SdkPreviewModeRuntime-Dl4GyMc3.mjs → SdkPreviewModeRuntime-BUNV_YHZ.mjs} +266 -143
  6. package/dist/{SiteChromeCustomizeContext-DgBe-FlM.mjs → SiteChromeCustomizeContext-DEj7qppF.mjs} +5340 -4329
  7. package/dist/{ThemedButton-B8ViBnLK.mjs → ThemedButton-C8kzu0hY.mjs} +610 -116
  8. package/dist/_dts/ai/src/contracts/proposals.d.ts +416 -182
  9. package/dist/_dts/ai/src/contracts/siteStyleProposalSchemas.d.ts +3270 -8214
  10. package/dist/_dts/api/src/billing.d.ts +2 -0
  11. package/dist/_dts/api/src/billingEndpointDefinitions.d.ts +78 -0
  12. package/dist/_dts/api/src/bookingAdjustments.d.ts +3 -2
  13. package/dist/_dts/api/src/bookingOperations.d.ts +7 -2
  14. package/dist/_dts/api/src/bookingPeople.d.ts +19 -0
  15. package/dist/_dts/api/src/bookingPeopleEndpointDefinitions.d.ts +8 -0
  16. package/dist/_dts/api/src/bookingRecords.d.ts +4 -106
  17. package/dist/_dts/api/src/bookings.d.ts +2 -3
  18. package/dist/_dts/api/src/communications.d.ts +19 -5
  19. package/dist/_dts/api/src/contentRuntime.d.ts +1 -0
  20. package/dist/_dts/api/src/endpoints.d.ts +88 -43
  21. package/dist/_dts/api/src/index.d.ts +4 -2
  22. package/dist/_dts/api/src/indexCoreTypes.d.ts +1 -0
  23. package/dist/_dts/api/src/indexExtendedTypes.d.ts +1 -1
  24. package/dist/_dts/api/src/moneyPayments.d.ts +116 -0
  25. package/dist/_dts/api/src/onboarding/surfaceData.d.ts +2 -0
  26. package/dist/_dts/api/src/sdk-event-upsert.d.ts +2 -2
  27. package/dist/_dts/api/src/sdkThemeWire.d.ts +348 -1537
  28. package/dist/_dts/api/src/shared-contracts.d.ts +10 -0
  29. package/dist/_dts/api/src/siteInfrastructure.d.ts +2 -1
  30. package/dist/_dts/api/src/sitePlatformEndpoints.d.ts +18 -0
  31. package/dist/_dts/api/src/siteRuntimeEndpoints.d.ts +17 -16
  32. package/dist/_dts/api/src/siteSettings.d.ts +1 -0
  33. package/dist/_dts/api/src/stripeConnectSetup.d.ts +90 -0
  34. package/dist/_dts/api/src/teamMembers.d.ts +2 -27
  35. package/dist/_dts/api/src/types.d.ts +11 -31
  36. package/dist/_dts/api/src/wholeSeriesRuns.d.ts +2 -4
  37. package/dist/_dts/block-form/src/widgets/RepeaterField/components/layoutGridDomain.d.ts +3 -13
  38. package/dist/_dts/blocks/src/client/site-chrome.d.ts +1 -1
  39. package/dist/_dts/blocks/src/contracts/index.d.ts +1 -0
  40. package/dist/_dts/blocks/src/contracts/proof-block-islands.d.ts +8 -96
  41. package/dist/_dts/blocks/src/index.d.ts +1 -0
  42. package/dist/_dts/blocks/src/lib/media.d.ts +1 -0
  43. package/dist/_dts/blocks/src/lib/picsum.d.ts +2 -2
  44. package/dist/_dts/blocks/src/pageRendererContracts.d.ts +2 -1
  45. package/dist/_dts/blocks/src/primitives/content/components/RichText.d.ts +1 -1
  46. package/dist/_dts/blocks/src/primitives/content/primitives.d.ts +4 -1
  47. package/dist/_dts/blocks/src/primitives/layout/Section.d.ts +1 -0
  48. package/dist/_dts/blocks/src/system/blocks/events/event-calendar.d.ts +1 -1
  49. package/dist/_dts/blocks/src/system/blocks/events/eventSelectionFields.d.ts +2 -2
  50. package/dist/_dts/blocks/src/system/blocks/events/shared/fields.d.ts +0 -4
  51. package/dist/_dts/blocks/src/system/blocks/events/shared/index.d.ts +0 -1
  52. package/dist/_dts/blocks/src/system/blocks/events/shared/schemas.d.ts +276 -884
  53. package/dist/_dts/blocks/src/system/blocks/events/shared/types.d.ts +2 -2
  54. package/dist/_dts/blocks/src/system/blocks/form.d.ts +10 -0
  55. package/dist/_dts/blocks/src/system/blocks/image-gallery/fields.d.ts +1 -0
  56. package/dist/_dts/blocks/src/system/blocks/image-gallery.d.ts +6 -1
  57. package/dist/_dts/blocks/src/system/blocks/location-map.d.ts +2 -2
  58. package/dist/_dts/blocks/src/system/blocks/media-text.d.ts +92 -90
  59. package/dist/_dts/blocks/src/system/blocks/newsletter-signup.d.ts +12 -0
  60. package/dist/_dts/blocks/src/system/blocks/shared/teamMembers.d.ts +4 -7
  61. package/dist/_dts/blocks/src/system/blocks/site-footer-runtime-layout.d.ts +23 -0
  62. package/dist/_dts/blocks/src/system/blocks/site-footer-runtime-profile.d.ts +20 -0
  63. package/dist/_dts/blocks/src/system/blocks/site-footer-runtime.d.ts +17 -16
  64. package/dist/_dts/blocks/src/system/blocks/site-footer.d.ts +1 -1
  65. package/dist/_dts/blocks/src/system/blocks/team-members.d.ts +2 -2
  66. package/dist/_dts/blocks/src/system/customize/backgrounds.d.ts +6 -6
  67. package/dist/_dts/blocks/src/system/customize/facets.d.ts +75 -9
  68. package/dist/_dts/blocks/src/system/fields/backgroundContent.d.ts +377 -1
  69. package/dist/_dts/blocks/src/system/helpers/backgroundMedia.d.ts +6 -2
  70. package/dist/_dts/blocks/src/system/helpers/resolveBackground.d.ts +3 -3
  71. package/dist/_dts/blocks/src/system/layout/repeaterGrid.d.ts +12 -5
  72. package/dist/_dts/blocks/src/system/manifest/fieldValidation/index.d.ts +3 -3
  73. package/dist/_dts/blocks/src/system/manifest/schema.d.ts +48 -48
  74. package/dist/_dts/blocks/src/system/manifest/validation.d.ts +2 -0
  75. package/dist/_dts/blocks/src/system/node/fragments/index.d.ts +1 -0
  76. package/dist/_dts/blocks/src/system/node/fragments/lookSlot.d.ts +1 -1
  77. package/dist/_dts/blocks/src/system/node/fragments/responsiveTwoColumn.d.ts +3 -1
  78. package/dist/_dts/blocks/src/system/node/fragments/sectionHead.d.ts +15 -0
  79. package/dist/_dts/blocks/src/system/runtime/components/registry.client.d.ts +18 -198
  80. package/dist/_dts/blocks/src/system/runtime/components/runtime-backed-blocks.d.ts +9 -99
  81. package/dist/_dts/blocks/src/system/runtime/hooks/useBookingFlowController.d.ts +1 -1
  82. package/dist/_dts/blocks/src/system/runtime/hooks/useHeadlessBookingFlow.d.ts +2 -0
  83. package/dist/_dts/blocks/src/system/runtime/lookSurfaces.d.ts +18 -6
  84. package/dist/_dts/blocks/src/system/runtime/nodes/ImageResolveContext.d.ts +1 -1
  85. package/dist/_dts/blocks/src/system/runtime/nodes/appointment-services.d.ts +50 -202
  86. package/dist/_dts/blocks/src/system/runtime/nodes/basic.d.ts +2 -1
  87. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.headless.state.d.ts +28 -1
  88. package/dist/_dts/blocks/src/system/runtime/nodes/event-details/lookPresentation.d.ts +12 -6
  89. package/dist/_dts/blocks/src/system/runtime/nodes/event-details/presentation.d.ts +1 -1
  90. package/dist/_dts/blocks/src/system/runtime/nodes/events/domain/dates.d.ts +1 -1
  91. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/CardListItem.d.ts +1 -1
  92. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/eventCollectionContract.d.ts +289 -885
  93. package/dist/_dts/blocks/src/system/runtime/nodes/file-download.d.ts +3 -2
  94. package/dist/_dts/blocks/src/system/runtime/nodes/form.fields.d.ts +5 -2
  95. package/dist/_dts/blocks/src/system/runtime/nodes/form.interactive.d.ts +11 -79
  96. package/dist/_dts/blocks/src/system/runtime/nodes/form.parts.d.ts +7 -0
  97. package/dist/_dts/blocks/src/system/runtime/nodes/form.server.d.ts +2 -13
  98. package/dist/_dts/blocks/src/system/runtime/nodes/media.d.ts +22 -90
  99. package/dist/_dts/blocks/src/system/runtime/nodes/mediaContext.d.ts +69 -0
  100. package/dist/_dts/blocks/src/system/runtime/nodes/newsletter-form.interactive.d.ts +8 -72
  101. package/dist/_dts/blocks/src/system/runtime/nodes/newsletter-form.parts.d.ts +6 -6
  102. package/dist/_dts/blocks/src/system/runtime/nodes/newsletter-form.types.d.ts +3 -2
  103. package/dist/_dts/blocks/src/system/runtime/nodes/shared/contract-schemas.d.ts +2 -2
  104. package/dist/_dts/blocks/src/system/transforms/registry/_utils/surfaceForegroundStyles.d.ts +3 -0
  105. package/dist/_dts/blocks/src/system/transforms/registry/footerArrangement.d.ts +6 -0
  106. package/dist/_dts/blocks/src/system/transforms/registry/index.d.ts +1 -0
  107. package/dist/_dts/blocks/src/system/transforms/registry/layout.d.ts +0 -11
  108. package/dist/_dts/blocks/src/system/transforms/registry/links.d.ts +3 -3
  109. package/dist/_dts/blocks/src/system/transforms/typed.d.ts +1 -10
  110. package/dist/_dts/commerce/src/purchase/orderConfirmationPlanning.d.ts +1 -0
  111. package/dist/_dts/content-editor/src/FooterComposerOverview.d.ts +5 -2
  112. package/dist/_dts/content-editor/src/FooterComposerPanel.d.ts +1 -1
  113. package/dist/_dts/content-editor/src/FooterNavigationLayoutControl.d.ts +6 -3
  114. package/dist/_dts/content-editor/src/controller/editorLeaseParticipation.d.ts +1 -1
  115. package/dist/_dts/content-editor/src/footerComposer.d.ts +2 -1
  116. package/dist/_dts/content-editor/src/footerComposerPanelTypes.d.ts +3 -1
  117. package/dist/_dts/content-editor/src/footerNavigationLayoutState.d.ts +56 -0
  118. package/dist/_dts/content-editor/src/footerPreviewRuntime.d.ts +2 -1
  119. package/dist/_dts/content-editor/src/useFooterComposerState.d.ts +3 -4
  120. package/dist/_dts/content-editor/src/useFooterNavigationLayout.d.ts +11 -8
  121. package/dist/_dts/content-model/src/content-types/schema.d.ts +3 -3
  122. package/dist/_dts/core/src/booking-refunds.d.ts +2 -0
  123. package/dist/_dts/core/src/date-display.d.ts +85 -0
  124. package/dist/_dts/core/src/date-time-formatter.d.ts +2 -0
  125. package/dist/_dts/core/src/footer-arrangement.d.ts +8 -1
  126. package/dist/_dts/core/src/footer-composition-types.d.ts +6 -1
  127. package/dist/_dts/core/src/footer-composition.d.ts +1 -1
  128. package/dist/_dts/core/src/footer-navigation-layout.d.ts +3 -0
  129. package/dist/_dts/core/src/index.d.ts +2 -0
  130. package/dist/_dts/core/src/mailing-list-runtime.d.ts +2 -2
  131. package/dist/_dts/core/src/mailing-list-setup-parser.d.ts +9 -1
  132. package/dist/_dts/core/src/mailing-list-setup.d.ts +12 -1
  133. package/dist/_dts/core/src/mailing-list-submission.d.ts +7 -2
  134. package/dist/_dts/core/src/mailing-list-targeting.d.ts +9 -1
  135. package/dist/_dts/core/src/public-profile.d.ts +3 -1
  136. package/dist/_dts/core/src/scheduled-date-time.d.ts +69 -0
  137. package/dist/_dts/db/src/generated/supabase/database.types.d.ts +105 -13
  138. package/dist/_dts/db/src/schemas/forms.d.ts +16 -16
  139. package/dist/_dts/editor-blocks/src/index.d.ts +1 -0
  140. package/dist/_dts/editor-blocks/src/media/MediaField.d.ts +2 -2
  141. package/dist/_dts/editor-blocks/src/media/admitEditorMediaField.d.ts +4 -0
  142. package/dist/_dts/editor-blocks/src/widgets/mailing-list-targeting/targetingState.d.ts +2 -2
  143. package/dist/_dts/media-core/src/assetsInUseSummary.d.ts +6 -0
  144. package/dist/_dts/media-core/src/contentMediaAudit.d.ts +3 -2
  145. package/dist/_dts/media-core/src/index.d.ts +4 -0
  146. package/dist/_dts/media-core/src/media.d.ts +406 -0
  147. package/dist/_dts/media-core/src/mediaIdentifierSchema.d.ts +3 -0
  148. package/dist/_dts/media-core/src/mediaKinds.d.ts +2 -0
  149. package/dist/_dts/media-core/src/mediaUsageProjection.d.ts +13 -1
  150. package/dist/_dts/media-core/src/mediaWriteNormalizer.d.ts +2 -6
  151. package/dist/_dts/media-core/src/portableMediaReferences.d.ts +8 -21
  152. package/dist/_dts/media-core/src/renderableMediaAsset.d.ts +28 -14
  153. package/dist/_dts/media-core/src/renderableMediaAssetAdmission.d.ts +15 -0
  154. package/dist/_dts/media-editor/src/CropDialog.d.ts +6 -3
  155. package/dist/_dts/media-editor/src/MediaEditor.d.ts +2 -1
  156. package/dist/_dts/media-editor/src/MediaPreview.d.ts +3 -3
  157. package/dist/_dts/media-editor/src/cropEditorSource.d.ts +5 -7
  158. package/dist/_dts/media-editor/src/editorMediaState.d.ts +29 -0
  159. package/dist/_dts/media-editor/src/mediaSelection.d.ts +1 -2
  160. package/dist/_dts/media-editor/src/runtimeMediaAssetState.d.ts +4 -5
  161. package/dist/_dts/media-editor/src/types.d.ts +1 -1
  162. package/dist/_dts/media-editor/src/utils.d.ts +0 -1
  163. package/dist/_dts/media-react/src/components/cropChangePolicy.d.ts +4 -1
  164. package/dist/_dts/media-react/src/components/cropGeometry.d.ts +1 -0
  165. package/dist/_dts/media-react/src/components/useImageCropperController.d.ts +1 -0
  166. package/dist/_dts/preview-next/src/client/blocks/ArrangementBlockToolbar.d.ts +2 -1
  167. package/dist/_dts/preview-next/src/client/blocks/BlockBackgroundChooser.d.ts +2 -1
  168. package/dist/_dts/preview-next/src/client/blocks/previewCustomizeSelectedMedia.d.ts +11 -12
  169. package/dist/_dts/preview-next/src/client/preview/PreviewShell.d.ts +1 -0
  170. package/dist/_dts/preview-next/src/client/preview/PreviewShellLayout.d.ts +1 -0
  171. package/dist/_dts/preview-next/src/client/preview/SiteChromeCustomizeContext.d.ts +4 -1
  172. package/dist/_dts/preview-next/src/client/preview/siteChromeSavePlan.d.ts +27 -5
  173. package/dist/_dts/preview-next/src/client/preview/siteStylePreviewPlanner.d.ts +2 -0
  174. package/dist/_dts/preview-next/src/client/preview/useConfirmedPreferenceRecord.d.ts +12 -0
  175. package/dist/_dts/preview-next/src/client/preview/usePersistedFooterPreferences.d.ts +26 -0
  176. package/dist/_dts/preview-next/src/client/preview/usePersistedHeaderPreferences.d.ts +40 -2
  177. package/dist/_dts/sdk/src/config/validation.d.ts +3 -3
  178. package/dist/_dts/sdk/src/contracts/content.d.ts +2 -45
  179. package/dist/_dts/sdk/src/contracts/index.d.ts +1 -1
  180. package/dist/_dts/sdk/src/contracts/rendering.d.ts +3 -3
  181. package/dist/_dts/sdk/src/contracts/system-block-content.d.ts +4 -46
  182. package/dist/_dts/sdk/src/date-time/index.d.ts +2 -68
  183. package/dist/_dts/sdk/src/index.d.ts +1 -0
  184. package/dist/_dts/sdk/src/public-api/contracts.d.ts +1 -0
  185. package/dist/_dts/sdk/src/rendering/image.d.ts +5 -5
  186. package/dist/_dts/sdk/src/rendering/index.d.ts +2 -1
  187. package/dist/_dts/sdk/src/rendering/islands/types.d.ts +1 -1
  188. package/dist/_dts/sdk/src/rendering/link.d.ts +3 -7
  189. package/dist/_dts/sdk/src/rendering/mediaAssets.d.ts +2 -4
  190. package/dist/_dts/sdk/src/version.d.ts +1 -1
  191. package/dist/_dts/theme-core/src/accordions/types.d.ts +1 -1
  192. package/dist/_dts/theme-core/src/boxBackgroundSchema.d.ts +397 -26
  193. package/dist/_dts/theme-core/src/buttons/buttonColourContract.d.ts +2 -0
  194. package/dist/_dts/theme-core/src/buttons/resolveButtonColourStates.d.ts +2 -0
  195. package/dist/_dts/theme-core/src/buttons/styles/recipes/lanternRecipes.d.ts +60 -0
  196. package/dist/_dts/theme-core/src/buttons/styles/registry.d.ts +57 -0
  197. package/dist/_dts/theme-core/src/buttons/styles/selection.d.ts +10 -1
  198. package/dist/_dts/theme-core/src/buttons/types.d.ts +378 -66
  199. package/dist/_dts/theme-core/src/buttons/typography.d.ts +24 -0
  200. package/dist/_dts/theme-core/src/cards/types.d.ts +42 -42
  201. package/dist/_dts/theme-core/src/footer/effectiveNavLinkStyle.d.ts +1 -1
  202. package/dist/_dts/theme-core/src/footer/generateFooterCss.d.ts +4 -1
  203. package/dist/_dts/theme-core/src/footer/mode.d.ts +2 -11
  204. package/dist/_dts/theme-core/src/generated/containerResponsiveThemeCss.d.ts +1 -1
  205. package/dist/_dts/theme-core/src/inputs/types.d.ts +3 -3
  206. package/dist/_dts/theme-core/src/lib/media.d.ts +2 -616
  207. package/dist/_dts/theme-core/src/mock-themes/all.d.ts +495 -2766
  208. package/dist/_dts/theme-core/src/navigation/types.d.ts +4 -4
  209. package/dist/_dts/theme-core/src/palette/curated/types.d.ts +1 -1
  210. package/dist/_dts/theme-core/src/schema.d.ts +838 -3369
  211. package/dist/_dts/theme-core/src/site-styles/appearancePresetTypes.d.ts +23 -7
  212. package/dist/_dts/theme-core/src/site-styles/backgroundAppearance.d.ts +2 -2
  213. package/dist/_dts/theme-core/src/site-styles/compilationPlan.d.ts +4 -6
  214. package/dist/_dts/theme-core/src/site-styles/compileFooterAgainstRow.d.ts +121 -0
  215. package/dist/_dts/theme-core/src/site-styles/curatedSiteStyles.d.ts +25 -0
  216. package/dist/_dts/theme-core/src/site-styles/footerLookDefaults.d.ts +45 -0
  217. package/dist/_dts/theme-core/src/site-styles/footerLookRecipe.d.ts +50 -0
  218. package/dist/_dts/theme-core/src/site-styles/footerLooks.d.ts +9 -35
  219. package/dist/_dts/theme-core/src/site-styles/footerPreferences.d.ts +29 -0
  220. package/dist/_dts/theme-core/src/site-styles/headerPreferencesPersistence.d.ts +2 -3
  221. package/dist/_dts/theme-core/src/site-styles/index.d.ts +4 -0
  222. package/dist/_dts/theme-core/src/site-styles/lookResolution.d.ts +2 -2
  223. package/dist/_dts/theme-core/src/site-styles/previewCompiler.d.ts +1 -1
  224. package/dist/_dts/theme-core/src/site-styles/runtimeBackgroundResolution.d.ts +9 -9
  225. package/dist/_dts/theme-core/src/site-styles/siteChromeBackgrounds.d.ts +8 -0
  226. package/dist/_dts/theme-core/src/site-styles/styleTags.d.ts +1 -1
  227. package/dist/_dts/theme-core/src/site-styles/themeParity.d.ts +1 -1
  228. package/dist/_dts/theme-core/src/site-styles/tokenRecipes.d.ts +2 -2
  229. package/dist/_dts/theme-core/src/styles/skinTokens.d.ts +2 -2
  230. package/dist/_dts/theme-core/src/typography/schema.d.ts +2 -2
  231. package/dist/_dts/ui/src/card.d.ts +1 -1
  232. package/dist/client/{BookingMailingListNote-CBuMKN0w.mjs → BookingMailingListNote-CNoSqFtf.mjs} +2 -2
  233. package/dist/client/{CardListItem-Dc9XTXhB.mjs → CardListItem-BkTkqBkh.mjs} +5 -4
  234. package/dist/client/{CheckboxChoice-CIqx_o0E.mjs → CheckboxChoice-CHJpsty4.mjs} +1 -1
  235. package/dist/client/{DemoBookingPortalAccess-D3VQ_kLj.mjs → DemoBookingPortalAccess-C7KQKFNt.mjs} +2 -2
  236. package/dist/client/{EventCombined.client-BHGEKise.mjs → EventCombined.client-BgeYMjHJ.mjs} +5 -6
  237. package/dist/client/{EventEmbeddedCheckoutStep-Bo1Cm23R.mjs → EventEmbeddedCheckoutStep-BTc_lTkM.mjs} +2 -2
  238. package/dist/client/{EventListing.client-D5OQgVPr.mjs → EventListing.client-ChRs9Hl2.mjs} +2 -2
  239. package/dist/client/{LeafletStaticMap-CLL5cWrr.mjs → LeafletStaticMap-C_dNQgd0.mjs} +1 -1
  240. package/dist/client/{RichText-BoDmnopf.mjs → RichText-BI9bzbjo.mjs} +106 -60
  241. package/dist/client/{ThemedButton-Ciltp0IK.mjs → ThemedButton-wl3Z3wkH.mjs} +1 -2
  242. package/dist/client/{accordion-DOkRS64-.mjs → accordion-6Yz8Wd83.mjs} +1 -1
  243. package/dist/client/{bookingForm-wlMVwo9h.mjs → bookingForm-i_pKIGiY.mjs} +42 -15
  244. package/dist/client/bookings.mjs +118357 -22833
  245. package/dist/client/{carousel-CGWk-Z0u.mjs → carousel-DNqd_PjC.mjs} +2 -2
  246. package/dist/client/{carousel.client-kX5mN1Eg.mjs → carousel.client-BUgjPbb6.mjs} +1 -1
  247. package/dist/client/{cart-OBBPlaH4.mjs → cart-D8OBHuF4.mjs} +3 -3
  248. package/dist/client/{checkout-Bmw2WjQX.mjs → checkout-F3-9IGLU.mjs} +3 -3
  249. package/dist/client/client.mjs +20785 -19238
  250. package/dist/client/{context-BI77UFAn.mjs → context-Dg4ZrxDD.mjs} +1 -1
  251. package/dist/client/{eventCalendar-qkej2Edn.mjs → eventCalendar-BUc7YIBM.mjs} +8 -9
  252. package/dist/client/{eventCombined-DApKHvat.mjs → eventCombined-BwfShk2a.mjs} +4 -4
  253. package/dist/client/{eventDetails-BQyUDPH0.mjs → eventDetails-BMOVC3go.mjs} +3 -3
  254. package/dist/client/{eventListing-CeAnshlZ.mjs → eventListing-BwE9PM-t.mjs} +4 -4
  255. package/dist/client/{eventRegistration-C3A3NyBO.mjs → eventRegistration-CCWPYDc7.mjs} +10 -10
  256. package/dist/client/{form-DW8rU7jO.mjs → form-CXFr0Gd5.mjs} +115 -52
  257. package/dist/client/{headerSection-CkIhsoNm.mjs → headerSection-BX8qw8kH.mjs} +3 -3
  258. package/dist/client/hooks.mjs +17908 -16797
  259. package/dist/client/{locationMap-D4O8wbli.mjs → locationMap-B3La71m0.mjs} +3 -4
  260. package/dist/client/{media-C5K_0xPd.mjs → media-B1Cbv721.mjs} +183 -362
  261. package/dist/client/mediaContext-CwbbimYB.mjs +135 -0
  262. package/dist/client/{newsletterForm-B7IxSPuz.mjs → newsletterForm-DnGyR0x7.mjs} +51 -15
  263. package/dist/client/{productDetail-Bqxpwy5N.mjs → productDetail-BVgTqvkb.mjs} +3 -3
  264. package/dist/client/{productList-u9Lz8V15.mjs → productList-CcO7kUQw.mjs} +3 -3
  265. package/dist/client/{propsDecoder-Bf1jucUp.mjs → propsDecoder-B1OeWavE.mjs} +2193 -374
  266. package/dist/client/renderableMediaAssetAdmission-CHkXYDC_.mjs +143 -0
  267. package/dist/client/rendering/client.mjs +22424 -21488
  268. package/dist/client/rendering/islands.mjs +20 -23
  269. package/dist/client/rendering.mjs +21025 -19413
  270. package/dist/client/{routeIslandApiConfig-BgP-aPMl.mjs → routeIslandApiConfig-Dl4vglJm.mjs} +1 -1
  271. package/dist/client/{shop-B_eykR-_.mjs → shop-P72nX5Fs.mjs} +7 -7
  272. package/dist/client/{shop-commerce-CT0APkFV.mjs → shop-commerce-Bt7uraDx.mjs} +8 -8
  273. package/dist/client/{shop-commerce-store-DcvZxdEK.mjs → shop-commerce-store-C1-mxSye.mjs} +1 -1
  274. package/dist/client/{shopShared-BVJOiUiJ.mjs → shopShared-Db-cRGu3.mjs} +5 -5
  275. package/dist/client/{useDiscountCodeUi-DPmYDunz.mjs → useDiscountCodeUi-jvAiUoUX.mjs} +1 -1
  276. package/dist/client/{useEventPagination-8-U55vH5.mjs → useEventPagination-BdWpCniq.mjs} +6 -7
  277. package/dist/preview-next/before-render.mjs +222 -55
  278. package/dist/preview-next/client/runtime.mjs +3 -3
  279. package/dist/preview-next/editor-chrome.css +5 -2
  280. package/dist/preview-next/keepAlive.mjs +133 -51
  281. package/dist/preview-next/middleware.mjs +133 -51
  282. package/dist/{sdk-runtime-C5jPdSrk.mjs → sdk-runtime-DLhjF2Nw.mjs} +1 -1
  283. package/dist/server/components.mjs +21541 -20118
  284. package/dist/server/config-validation.mjs +2466 -1403
  285. package/dist/server/config.mjs +2466 -1403
  286. package/dist/server/data.mjs +17842 -16759
  287. package/dist/server/date-time.mjs +258 -116
  288. package/dist/server/index.mjs +360 -53
  289. package/dist/server/next.mjs +21913 -20539
  290. package/dist/server/page-converter.mjs +8121 -7322
  291. package/dist/server/prebuild.mjs +1 -1
  292. package/dist/server/rendering/server.mjs +21196 -19760
  293. package/dist/server/rendering.mjs +21554 -20123
  294. package/dist/server/routing.mjs +19806 -18607
  295. package/dist/server/server.mjs +2907 -1845
  296. package/dist/server/theme-bridge.mjs +991 -160
  297. package/dist/server/theme.mjs +501 -100
  298. package/dist/{spinner-B-ab2rJp.mjs → spinner-MTooKfck.mjs} +1 -1
  299. package/dist/styles/index.css +254 -1
  300. package/package.json +1 -1
  301. package/dist/_dts/blocks/src/system/blocks/events/shared/layout.d.ts +0 -12
  302. package/dist/client/aspectTransforms-D-TnDdq4.mjs +0 -93
  303. package/dist/client/colorStyles-ECDNPE_P.mjs +0 -1253
@@ -53,6 +53,19 @@ const footerModeSchema = z.enum([
53
53
  "default+blocks",
54
54
  "none"
55
55
  ]);
56
+ z.object({
57
+ variant: z.enum([
58
+ "simple",
59
+ "columns",
60
+ "split",
61
+ "centred"
62
+ ]),
63
+ showLogoText: z.boolean().optional(),
64
+ logo: z.object({
65
+ showLogo: z.boolean().optional(),
66
+ showLogoText: z.boolean().optional()
67
+ }).optional()
68
+ });
56
69
  //#endregion
57
70
  //#region ../api/src/defineEndpointDefinitions.ts
58
71
  /**
@@ -1776,12 +1789,14 @@ const unsafeAsSiteId = (id) => id;
1776
1789
  const unsafeAsApiKeyId = (id) => id;
1777
1790
  const unsafeAsEventOfferingId = (id) => id;
1778
1791
  const unsafeAsEventSeriesId = (id) => id;
1792
+ const unsafeAsMediaAssetId = (id) => id;
1779
1793
  const unsafeAsUserId = (id) => id;
1780
1794
  const unsafeAsContentVersionId = (id) => id;
1781
1795
  const parseSiteId = (value) => parseUuidBrand(value, unsafeAsSiteId);
1782
1796
  const parseApiKeyId = (value) => parseUuidBrand(value, unsafeAsApiKeyId);
1783
1797
  const parseEventOfferingId = (value) => parseUuidBrand(value, unsafeAsEventOfferingId);
1784
1798
  const parseUserId = (value) => parseUuidBrand(value, unsafeAsUserId);
1799
+ const parseMediaAssetId = (value) => parseUuidBrand(value, unsafeAsMediaAssetId);
1785
1800
  const parseContentVersionId = (value) => parseUuidBrand(value, unsafeAsContentVersionId);
1786
1801
  const parseEventSeriesId = (value) => parseUuidBrand(value, unsafeAsEventSeriesId);
1787
1802
  //#endregion
@@ -2124,6 +2139,25 @@ function validateBookingPaymentOptionKinds(kinds) {
2124
2139
  return ok(void 0);
2125
2140
  }
2126
2141
  //#endregion
2142
+ //#region ../core/src/date-time-formatter.ts
2143
+ /** Shared Intl engine, internal to core's date presentation owners. */
2144
+ const FORMATTER_CACHE_LIMIT = 100;
2145
+ const dateTimeFormatterCache = /* @__PURE__ */ new Map();
2146
+ function getDateTimeFormatter(locale, timeZone, format) {
2147
+ const key = `${locale}\u0000${timeZone}\u0000${JSON.stringify(Object.entries(format).sort(([left], [right]) => left.localeCompare(right)))}`;
2148
+ const cached = dateTimeFormatterCache.get(key);
2149
+ if (cached !== void 0) return cached;
2150
+ if (typeof locale !== "string" || Intl.DateTimeFormat.supportedLocalesOf([locale]).length === 0) throw new RangeError("An explicit supported locale is required");
2151
+ if (typeof timeZone !== "string" || timeZone.length === 0) throw new RangeError("An explicit time zone is required");
2152
+ const formatter = new Intl.DateTimeFormat(locale, {
2153
+ ...format,
2154
+ timeZone
2155
+ });
2156
+ if (dateTimeFormatterCache.size >= FORMATTER_CACHE_LIMIT) dateTimeFormatterCache.clear();
2157
+ dateTimeFormatterCache.set(key, formatter);
2158
+ return formatter;
2159
+ }
2160
+ //#endregion
2127
2161
  //#region ../core/src/booking-time-zone.ts
2128
2162
  const TIME_ZONE_VALIDITY_CACHE_LIMIT = 100;
2129
2163
  const timeZoneValidityCache = /* @__PURE__ */ new Map();
@@ -2160,8 +2194,6 @@ const START_OF_DAY = {
2160
2194
  second: 0
2161
2195
  };
2162
2196
  const LOCAL_DATE_PATTERN = /^(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})$/u;
2163
- const DATE_TIME_FORMATTER_CACHE_LIMIT = 100;
2164
- const dateTimeFormatterCache = /* @__PURE__ */ new Map();
2165
2197
  function getSafeTimeZone(timeZone) {
2166
2198
  const normalized = typeof timeZone === "string" ? timeZone.trim() : "";
2167
2199
  return normalized.length > 0 && isValidBookingTimeZone(normalized) ? normalized : FALLBACK_TIMEZONE;
@@ -2178,19 +2210,7 @@ function formatParseError(error) {
2178
2210
  }
2179
2211
  }
2180
2212
  function formatToPartsLookup(date, locale, timeZone, format) {
2181
- return new Map(getCachedDateTimeFormatter(locale, timeZone, format).formatToParts(date).map((part) => [part.type, part.value]));
2182
- }
2183
- function getCachedDateTimeFormatter(locale, timeZone, format) {
2184
- const key = `${locale}\u0000${timeZone}\u0000${JSON.stringify(Object.entries(format).sort(([left], [right]) => left.localeCompare(right)))}`;
2185
- const cached = dateTimeFormatterCache.get(key);
2186
- if (cached !== void 0) return cached;
2187
- const formatter = new Intl.DateTimeFormat(locale, {
2188
- ...format,
2189
- timeZone
2190
- });
2191
- if (dateTimeFormatterCache.size >= DATE_TIME_FORMATTER_CACHE_LIMIT) dateTimeFormatterCache.clear();
2192
- dateTimeFormatterCache.set(key, formatter);
2193
- return formatter;
2213
+ return new Map(getDateTimeFormatter(locale, timeZone, format).formatToParts(date).map((part) => [part.type, part.value]));
2194
2214
  }
2195
2215
  function getZonedDateTimeParts(date, timeZone) {
2196
2216
  const parts = formatToPartsLookup(date, "en-GB", timeZone, {
@@ -2278,7 +2298,7 @@ function toScheduledBookingDateTime(input) {
2278
2298
  function formatBookingInstant(isoString, options) {
2279
2299
  const date = new Date(isoString);
2280
2300
  if (Number.isNaN(date.getTime())) return isoString;
2281
- return getCachedDateTimeFormatter(options.locale ?? DEFAULT_LOCALE, getSafeTimeZone(options.timeZone), options.format).format(date);
2301
+ return getDateTimeFormatter(options.locale ?? DEFAULT_LOCALE, getSafeTimeZone(options.timeZone), options.format).format(date);
2282
2302
  }
2283
2303
  function formatBookingDate(input, format = {
2284
2304
  weekday: "long",
@@ -2403,6 +2423,17 @@ function localScheduleDateTimeToUtcDate(localDate, localTime, timeZone) {
2403
2423
  return new Date(guess);
2404
2424
  }
2405
2425
  //#endregion
2426
+ //#region ../core/src/date-display.ts
2427
+ /** Site-language policy, shared by customer emails and public event adapters. */
2428
+ function inferSiteDateLocale(siteTimeZone) {
2429
+ if (siteTimeZone === null || siteTimeZone === void 0 || siteTimeZone === "") return "en-US";
2430
+ if (siteTimeZone === "Europe/Dublin") return "en-IE";
2431
+ if (siteTimeZone.startsWith("Europe/")) return "en-GB";
2432
+ if (siteTimeZone.startsWith("Australia/")) return "en-AU";
2433
+ if (siteTimeZone === "Pacific/Auckland" || siteTimeZone === "Pacific/Chatham") return "en-NZ";
2434
+ return "en-US";
2435
+ }
2436
+ //#endregion
2406
2437
  //#region ../core/src/location.ts
2407
2438
  function normalizeLocationAddressText(value) {
2408
2439
  if (typeof value !== "string") return null;
@@ -2464,7 +2495,7 @@ function parsePositiveInteger(value) {
2464
2495
  return typeof value === "number" && Number.isSafeInteger(value) && value > 0 ? value : null;
2465
2496
  }
2466
2497
  function parseNewsletterListId(value) {
2467
- return parseTrimmedMatchingString(value, UUID_PATTERN);
2498
+ return parseTrimmedMatchingString(typeof value === "string" ? value.toLowerCase() : value, UUID_PATTERN);
2468
2499
  }
2469
2500
  function parseMailchimpAccountId(value) {
2470
2501
  return parseTrimmedMatchingString(value, OPAQUE_ID_PATTERN);
@@ -2506,8 +2537,15 @@ function parseMailingListProviderScope(value) {
2506
2537
  }
2507
2538
  return err("invalid_mailing_list_provider_scope");
2508
2539
  }
2509
- //#endregion
2510
- //#region ../core/src/mailing-list-setup-parser.ts
2540
+ z.unknown().transform((value, ctx) => {
2541
+ const parsed = parseNewsletterAudience(value);
2542
+ if (parsed.ok) return parsed.value;
2543
+ ctx.addIssue({
2544
+ code: "custom",
2545
+ message: "Choose a valid newsletter audience."
2546
+ });
2547
+ return z.NEVER;
2548
+ });
2511
2549
  function parseMailingListGlobalForm(value) {
2512
2550
  if (!isRecord$9(value)) return formError("shape");
2513
2551
  const fields = parseGlobalFields(value.fields);
@@ -2527,6 +2565,16 @@ function parseMailingListGlobalForm(value) {
2527
2565
  privacyNote
2528
2566
  });
2529
2567
  }
2568
+ function parseNewsletterAudience(value) {
2569
+ if (!isRecord$9(value)) return err("invalid_newsletter_audience");
2570
+ if (value.kind === "general" && Object.keys(value).length === 1) return ok({ kind: "general" });
2571
+ if (value.kind !== "topic" || Object.keys(value).some((key) => key !== "kind" && key !== "topicId")) return err("invalid_newsletter_audience");
2572
+ const topicId = parseNewsletterListId(value.topicId);
2573
+ return topicId === null ? err("invalid_newsletter_audience") : ok({
2574
+ kind: "topic",
2575
+ topicId
2576
+ });
2577
+ }
2530
2578
  function parseGlobalFields(value) {
2531
2579
  if (!isRecord$9(value) || typeof value.preset !== "string") return null;
2532
2580
  switch (value.preset) {
@@ -2535,6 +2583,10 @@ function parseGlobalFields(value) {
2535
2583
  preset: "emailName",
2536
2584
  name: value.name
2537
2585
  } : null;
2586
+ case "emailFirstName": return isRequirement(value.firstName) ? {
2587
+ preset: "emailFirstName",
2588
+ firstName: value.firstName
2589
+ } : null;
2538
2590
  case "emailFirstLast": return isRequirement(value.firstName) && isRequirement(value.lastName) ? {
2539
2591
  preset: "emailFirstLast",
2540
2592
  firstName: value.firstName,
@@ -2579,54 +2631,49 @@ function formError(field) {
2579
2631
  const DEFAULT_MAILING_LIST_TARGETING = { mode: "default" };
2580
2632
  function mailingListTargetingChoiceIds(targeting) {
2581
2633
  switch (targeting.provider) {
2582
- case "native": return targeting.selection.tag === "fixed" ? targeting.selection.topicIds : targeting.selection.offeredTopicIds;
2634
+ case "native": return targeting.selection.tag === "general" ? [] : targeting.selection.tag === "fixed" ? targeting.selection.topicIds : targeting.selection.offeredTopicIds;
2583
2635
  case "brevo": return targeting.selection.tag === "fixed" ? targeting.selection.listIds : targeting.selection.offeredListIds;
2584
2636
  case "mailchimp": return targeting.selection.tag === "fixed" ? targeting.selection.interestIds : targeting.selection.offeredInterestIds;
2585
2637
  }
2586
2638
  }
2587
2639
  function planMailingListChoicePresentation(targeting) {
2588
- if (targeting.mode === "default" || targeting.selection.tag === "fixed") return { tag: "hidden" };
2640
+ if (targeting.mode === "default" || targeting.selection.tag === "fixed" || targeting.selection.tag === "general") return { tag: "hidden" };
2589
2641
  switch (targeting.provider) {
2590
- case "native": return targeting.selection.offeredTopicIds.length === 1 ? {
2591
- tag: "automatic",
2592
- selection: {
2593
- provider: "native",
2594
- topicIds: targeting.selection.offeredTopicIds
2595
- }
2596
- } : {
2597
- tag: "visitor_choice",
2642
+ case "native": return presentVisitorSelection({
2598
2643
  provider: "native",
2599
- optionCount: targeting.selection.offeredTopicIds.length
2600
- };
2601
- case "brevo": return targeting.selection.offeredListIds.length === 1 ? {
2602
- tag: "automatic",
2603
- selection: {
2604
- provider: "brevo",
2605
- listIds: targeting.selection.offeredListIds
2606
- }
2607
- } : {
2608
- tag: "visitor_choice",
2644
+ topicIds: targeting.selection.offeredTopicIds
2645
+ }, targeting.selection.offeredTopicIds.length);
2646
+ case "brevo": return presentVisitorSelection({
2609
2647
  provider: "brevo",
2610
- optionCount: targeting.selection.offeredListIds.length
2611
- };
2612
- case "mailchimp": return targeting.selection.offeredInterestIds.length === 1 ? {
2613
- tag: "automatic",
2614
- selection: {
2615
- provider: "mailchimp",
2616
- interestIds: targeting.selection.offeredInterestIds
2617
- }
2618
- } : {
2619
- tag: "visitor_choice",
2648
+ listIds: targeting.selection.offeredListIds
2649
+ }, targeting.selection.offeredListIds.length);
2650
+ case "mailchimp": return presentVisitorSelection({
2620
2651
  provider: "mailchimp",
2621
- optionCount: targeting.selection.offeredInterestIds.length
2622
- };
2652
+ interestIds: targeting.selection.offeredInterestIds
2653
+ }, targeting.selection.offeredInterestIds.length);
2623
2654
  }
2624
2655
  }
2656
+ function presentVisitorSelection(selection, optionCount) {
2657
+ return optionCount === 1 ? {
2658
+ tag: "automatic",
2659
+ selection
2660
+ } : {
2661
+ tag: "visitor_choice",
2662
+ provider: selection.provider,
2663
+ optionCount
2664
+ };
2665
+ }
2625
2666
  //#endregion
2626
2667
  //#region ../core/src/mailing-list-targeting-availability.ts
2627
2668
  function resolveMailingListDefaultDestination(provider) {
2628
2669
  switch (provider.provider) {
2629
- case "native": return provider.topics.find((item) => item.id === provider.defaultTopicId) ?? null;
2670
+ case "native": {
2671
+ const audience = provider.defaultAudience;
2672
+ return audience.kind === "general" ? {
2673
+ id: "general",
2674
+ name: "General mailing list"
2675
+ } : provider.topics.find((item) => item.id === audience.topicId) ?? null;
2676
+ }
2630
2677
  case "brevo": return provider.lists.find((item) => item.id === provider.defaultListId) ?? null;
2631
2678
  case "mailchimp": return provider.audiences.find((item) => item.id === provider.defaultAudienceId) ?? null;
2632
2679
  }
@@ -2764,11 +2811,12 @@ function parseRuntimeProvider(value) {
2764
2811
  }
2765
2812
  }
2766
2813
  function parseNativeRuntimeProvider(value) {
2767
- const defaultTopicId = parseNewsletterListId(value.defaultTopicId);
2814
+ if ("defaultTopicId" in value) return null;
2815
+ const defaultAudience = parseNewsletterAudience(value.defaultAudience);
2768
2816
  const topics = parseNamedItems(value.topics, parseNewsletterListId);
2769
- return defaultTopicId !== null && topics !== null ? {
2817
+ return defaultAudience.ok && topics !== null ? {
2770
2818
  provider: "native",
2771
- defaultTopicId,
2819
+ defaultAudience: defaultAudience.value,
2772
2820
  topics
2773
2821
  } : null;
2774
2822
  }
@@ -2853,6 +2901,11 @@ function parseMailingListPlacementTargeting(value) {
2853
2901
  }
2854
2902
  }
2855
2903
  function parseNativeTargeting(selection) {
2904
+ if (selection.tag === "general") return Object.keys(selection).length === 1 ? ok({
2905
+ mode: "custom",
2906
+ provider: "native",
2907
+ selection: { tag: "general" }
2908
+ }) : targetingError("selection");
2856
2909
  if (selection.tag === "fixed") {
2857
2910
  const topicIds = parseNonEmptyUniqueIds(selection.topicIds, parseNewsletterListId);
2858
2911
  return topicIds.ok ? ok({
@@ -4270,6 +4323,129 @@ const BILLING_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
4270
4323
  tags: ["billing"],
4271
4324
  auth: "user",
4272
4325
  responseKind: "json"
4326
+ },
4327
+ stripeConnectSetupStart: {
4328
+ path: "/sites/{siteId}/billing/connect/setup",
4329
+ method: "POST",
4330
+ tags: ["site-{siteId}", "stripe-connect"],
4331
+ auth: "user",
4332
+ responseKind: "json",
4333
+ errors: [
4334
+ "validation:invalid_input",
4335
+ "auth:forbidden",
4336
+ "resource:conflict",
4337
+ "server:internal_error"
4338
+ ]
4339
+ },
4340
+ stripeConnectSetupDiscard: {
4341
+ path: "/sites/{siteId}/billing/connect/setup",
4342
+ method: "DELETE",
4343
+ tags: ["site-{siteId}", "stripe-connect"],
4344
+ auth: "user",
4345
+ responseKind: "json",
4346
+ errors: [
4347
+ "validation:invalid_input",
4348
+ "auth:forbidden",
4349
+ "resource:conflict",
4350
+ "server:internal_error"
4351
+ ]
4352
+ },
4353
+ stripeConnectSetupSave: {
4354
+ path: "/sites/{siteId}/billing/connect/setup/save",
4355
+ method: "POST",
4356
+ tags: ["site-{siteId}", "stripe-connect"],
4357
+ auth: "user",
4358
+ responseKind: "json",
4359
+ errors: [
4360
+ "validation:invalid_input",
4361
+ "auth:forbidden",
4362
+ "resource:conflict",
4363
+ "server:internal_error"
4364
+ ]
4365
+ },
4366
+ stripeConnectAccountSession: {
4367
+ path: "/sites/{siteId}/billing/connect/session",
4368
+ method: "POST",
4369
+ tags: ["site-{siteId}", "stripe-connect"],
4370
+ auth: "user",
4371
+ responseKind: "json",
4372
+ errors: [
4373
+ "validation:invalid_input",
4374
+ "auth:forbidden",
4375
+ "resource:conflict",
4376
+ "server:internal_error"
4377
+ ]
4378
+ },
4379
+ stripeConnectStart: {
4380
+ path: "/sites/{siteId}/billing/connect/start",
4381
+ method: "POST",
4382
+ tags: ["site-{siteId}", "stripe-connect"],
4383
+ auth: "user",
4384
+ responseKind: "json",
4385
+ errors: [
4386
+ "validation:invalid_input",
4387
+ "auth:forbidden",
4388
+ "resource:conflict",
4389
+ "server:internal_error"
4390
+ ]
4391
+ },
4392
+ stripeConnectStatus: {
4393
+ path: "/sites/{siteId}/billing/connect/status",
4394
+ method: "GET",
4395
+ tags: ["site-{siteId}", "stripe-connect"],
4396
+ auth: "user",
4397
+ responseKind: "json",
4398
+ errors: [
4399
+ "validation:invalid_input",
4400
+ "auth:forbidden",
4401
+ "resource:conflict",
4402
+ "server:internal_error"
4403
+ ]
4404
+ },
4405
+ stripeAutomaticTaxUpdate: {
4406
+ path: "/sites/{siteId}/billing/automatic-tax",
4407
+ method: "POST",
4408
+ tags: [
4409
+ "site-{siteId}",
4410
+ "billing",
4411
+ "stripe-tax"
4412
+ ],
4413
+ auth: "user",
4414
+ responseKind: "json",
4415
+ errors: [
4416
+ "validation:invalid_input",
4417
+ "auth:forbidden",
4418
+ "resource:not_found",
4419
+ "server:unavailable",
4420
+ "server:internal_error"
4421
+ ]
4422
+ },
4423
+ stripeConnectDisconnect: {
4424
+ path: "/sites/{siteId}/billing/connect/disconnect",
4425
+ method: "DELETE",
4426
+ tags: ["site-{siteId}", "stripe-connect"],
4427
+ auth: "user",
4428
+ responseKind: "json",
4429
+ errors: [
4430
+ "validation:invalid_input",
4431
+ "auth:forbidden",
4432
+ "resource:conflict",
4433
+ "server:internal_error"
4434
+ ]
4435
+ },
4436
+ billingConnectReturn: {
4437
+ path: "/billing/connect/return",
4438
+ method: "GET",
4439
+ auth: "user",
4440
+ responseKind: "void",
4441
+ errors: []
4442
+ },
4443
+ billingConnectRefresh: {
4444
+ path: "/billing/connect/refresh",
4445
+ method: "GET",
4446
+ auth: "user",
4447
+ responseKind: "void",
4448
+ errors: []
4273
4449
  }
4274
4450
  });
4275
4451
  //#endregion
@@ -4434,6 +4610,14 @@ const PAGE_SURFACE_EDITOR_ENDPOINT_DEFINITIONS = {
4434
4610
  * person when nothing is attached to them.
4435
4611
  */
4436
4612
  const BOOKING_PEOPLE_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
4613
+ getBookingPerson: {
4614
+ path: "/sites/{siteId}/bookings/people/{personId}",
4615
+ method: "GET",
4616
+ tags: ["site-{siteId}", "customers-{siteId}"],
4617
+ auth: "user",
4618
+ responseKind: "json",
4619
+ errors: ["resource:not_found", "server:internal_error"]
4620
+ },
4437
4621
  listPeople: {
4438
4622
  path: "/sites/{siteId}/bookings/people",
4439
4623
  method: "GET",
@@ -7937,7 +8121,96 @@ const themeLookMetadataSchema = z.object({
7937
8121
  skinMarks: skinMarksSchema.optional()
7938
8122
  });
7939
8123
  //#endregion
7940
- //#region ../theme-core/src/lib/media.ts
8124
+ //#region ../media-core/src/identifiers.ts
8125
+ function slugifyMediaIdentifier(value) {
8126
+ return value.toLowerCase().trim().replace(/[^a-z0-9\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-");
8127
+ }
8128
+ function parseMediaIdentifier(value) {
8129
+ if (typeof value !== "string") return err({ kind: "not_string" });
8130
+ const trimmed = value.trim();
8131
+ if (trimmed.length === 0) return err({ kind: "empty_identifier" });
8132
+ const normalized = slugifyMediaIdentifier(trimmed);
8133
+ if (normalized.length === 0) return err({
8134
+ kind: "empty_after_normalization",
8135
+ value
8136
+ });
8137
+ return ok(normalized);
8138
+ }
8139
+ /**
8140
+ * Admits identifiers read from trusted persistence without repairing dirty data in memory.
8141
+ * User input should use parseMediaIdentifier, which intentionally canonicalizes it.
8142
+ */
8143
+ function parseCanonicalMediaIdentifier(value) {
8144
+ if (typeof value !== "string") return err({ kind: "not_string" });
8145
+ const parsed = parseMediaIdentifier(value);
8146
+ if (!parsed.ok) return parsed;
8147
+ if (value !== parsed.value) return err({
8148
+ kind: "non_canonical_identifier",
8149
+ value,
8150
+ canonical: parsed.value
8151
+ });
8152
+ return parsed;
8153
+ }
8154
+ //#endregion
8155
+ //#region ../media-core/src/mediaIdentifierSchema.ts
8156
+ /** Strict stored-reference admission delegates the canonical identifier decision. */
8157
+ const mediaIdentifierSchema = z.string().transform((value, context) => {
8158
+ const parsed = parseCanonicalMediaIdentifier(value);
8159
+ if (parsed.ok) return parsed.value;
8160
+ context.addIssue({
8161
+ code: "custom",
8162
+ message: "Expected a canonical media identifier"
8163
+ });
8164
+ return z.NEVER;
8165
+ });
8166
+ //#endregion
8167
+ //#region ../media-core/src/mediaKinds.ts
8168
+ const mediaTypeDiscriminants = [
8169
+ "image",
8170
+ "video",
8171
+ "audio",
8172
+ "document",
8173
+ "spreadsheet",
8174
+ "archive"
8175
+ ];
8176
+ //#endregion
8177
+ //#region ../media-core/src/renderableMediaAsset.ts
8178
+ /** A portable reference never uses an incidental UUID, URL or storage snapshot for identity. */
8179
+ function resolveManagedMediaReference(reference, index) {
8180
+ const asset = index?.byIdentifier.get(reference.identifier);
8181
+ return asset ? {
8182
+ kind: "resolved",
8183
+ reference,
8184
+ asset
8185
+ } : {
8186
+ kind: "missing",
8187
+ reference
8188
+ };
8189
+ }
8190
+ //#endregion
8191
+ //#region ../media-core/src/renderableMediaAssetAdmission.ts
8192
+ const mediaAssetIdSchema = z.string().transform((value, context) => {
8193
+ const parsed = parseMediaAssetId(value);
8194
+ if (parsed.ok) return parsed.value;
8195
+ context.addIssue({
8196
+ code: "custom",
8197
+ message: "Expected a media asset ID"
8198
+ });
8199
+ return z.NEVER;
8200
+ });
8201
+ const nonemptyStorageValue = z.string().refine((value) => value.trim().length > 0);
8202
+ const renderableMediaAssetSchema = z.object({
8203
+ id: mediaAssetIdSchema,
8204
+ identifier: mediaIdentifierSchema,
8205
+ storageBucket: nonemptyStorageValue,
8206
+ storagePath: nonemptyStorageValue,
8207
+ mimeType: nonemptyStorageValue,
8208
+ filename: z.string().optional(),
8209
+ width: z.number().positive().nullable(),
8210
+ height: z.number().positive().nullable()
8211
+ });
8212
+ //#endregion
8213
+ //#region ../media-core/src/media.ts
7941
8214
  const hotspotSchema = z.object({
7942
8215
  x: z.number().min(0).max(1),
7943
8216
  y: z.number().min(0).max(1),
@@ -7971,56 +8244,149 @@ const transformSchema = z.object({
7971
8244
  rotation: rotationSchema.optional()
7972
8245
  });
7973
8246
  const mediaPosterSchema = z.discriminatedUnion("tag", [z.object({
7974
- tag: z.literal("storage"),
7975
- assetId: z.string().optional(),
7976
- storageBucket: z.string().min(1),
7977
- storagePath: z.string().min(1)
7978
- }), z.object({
8247
+ tag: z.literal("media"),
8248
+ identifier: mediaIdentifierSchema
8249
+ }).strict(), z.object({
7979
8250
  tag: z.literal("external-src"),
7980
- assetId: z.string().optional(),
7981
8251
  src: z.string().url()
7982
- })]);
7983
- const mediaBaseSchema = z.object({
8252
+ }).strict()]);
8253
+ const mediaUsageShape = {
7984
8254
  purpose: z.string().optional(),
7985
8255
  placeholder: z.boolean().default(true).optional(),
7986
- assetId: z.string().optional(),
7987
- identifier: z.string().optional(),
7988
- src: z.string().optional(),
7989
8256
  alt: z.string().optional(),
7990
8257
  filename: z.string().optional(),
7991
- mimeType: z.string().optional(),
7992
8258
  width: z.number().optional(),
7993
8259
  height: z.number().optional(),
7994
- storageBucket: z.string().optional(),
7995
- storagePath: z.string().optional(),
7996
8260
  poster: mediaPosterSchema.optional(),
7997
8261
  transform: transformSchema.optional()
7998
- });
7999
- const mediaIdentifierSchema = z.string().trim().min(1).brand();
8262
+ };
8263
+ const environmentExclusions = {
8264
+ assetId: z.never().optional(),
8265
+ id: z.never().optional(),
8266
+ src: z.never().optional(),
8267
+ storageBucket: z.never().optional(),
8268
+ storagePath: z.never().optional(),
8269
+ mimeType: z.never().optional()
8270
+ };
8271
+ const mediaBaseSchema = z.object({
8272
+ ...mediaUsageShape,
8273
+ ...environmentExclusions,
8274
+ identifier: mediaIdentifierSchema
8275
+ }).strict();
8000
8276
  const imageMediaSchema = mediaBaseSchema.extend({ type: z.literal("image") });
8001
8277
  const videoMediaSchema = mediaBaseSchema.extend({ type: z.literal("video") });
8002
- const audioMediaSchema = mediaBaseSchema.extend({ type: z.literal("audio") });
8003
- const documentMediaSchema = mediaBaseSchema.extend({ type: z.literal("document") });
8004
- const spreadsheetMediaSchema = mediaBaseSchema.extend({ type: z.literal("spreadsheet") });
8005
- const archiveMediaSchema = mediaBaseSchema.extend({ type: z.literal("archive") });
8006
- const mediaSchema = z.discriminatedUnion("type", [
8007
- imageMediaSchema,
8008
- videoMediaSchema,
8009
- audioMediaSchema,
8010
- documentMediaSchema,
8011
- spreadsheetMediaSchema,
8012
- archiveMediaSchema
8013
- ]);
8014
- const persistableMediaBaseSchema = mediaBaseSchema.extend({ identifier: mediaIdentifierSchema });
8015
- z.discriminatedUnion("type", [
8016
- persistableMediaBaseSchema.extend({ type: z.literal("image") }),
8017
- persistableMediaBaseSchema.extend({ type: z.literal("video") }),
8018
- persistableMediaBaseSchema.extend({ type: z.literal("audio") }),
8019
- persistableMediaBaseSchema.extend({ type: z.literal("document") }),
8020
- persistableMediaBaseSchema.extend({ type: z.literal("spreadsheet") }),
8021
- persistableMediaBaseSchema.extend({ type: z.literal("archive") })
8278
+ const mediaSchema = mediaBaseSchema.extend({ type: z.enum(mediaTypeDiscriminants) });
8279
+ const externalMediaSchema = z.object({
8280
+ ...mediaUsageShape,
8281
+ ...environmentExclusions,
8282
+ type: z.enum(mediaTypeDiscriminants),
8283
+ src: z.string().min(1),
8284
+ identifier: z.never().optional()
8285
+ }).strict();
8286
+ const assetMediaSchema = z.object({
8287
+ ...mediaUsageShape,
8288
+ ...environmentExclusions,
8289
+ type: z.enum(mediaTypeDiscriminants),
8290
+ asset: renderableMediaAssetSchema,
8291
+ identifier: z.never().optional()
8292
+ }).strict();
8293
+ const runtimeMediaSchema = z.union([
8294
+ mediaSchema,
8295
+ externalMediaSchema,
8296
+ assetMediaSchema
8022
8297
  ]);
8023
8298
  //#endregion
8299
+ //#region ../media-core/src/transformRect.ts
8300
+ function isValidTransformRectStructure(rect) {
8301
+ if (!Array.isArray(rect) || rect.length !== 4) return false;
8302
+ const [left, top, width, height] = rect;
8303
+ return Number.isFinite(left) && Number.isFinite(top) && Number.isFinite(width) && Number.isFinite(height) && left >= 0 && top >= 0 && width > 0 && height > 0;
8304
+ }
8305
+ //#endregion
8306
+ //#region ../media-core/src/aspectTransforms.ts
8307
+ const DEFAULT_RECT_EPSILON = .5;
8308
+ function parseAspectRatioValue(value) {
8309
+ if (typeof value === "number") return Number.isFinite(value) && value > 0 ? value : void 0;
8310
+ if (typeof value !== "string") return void 0;
8311
+ const normalized = value.trim();
8312
+ if (!normalized) return void 0;
8313
+ if (normalized === "auto") return void 0;
8314
+ if (normalized.includes(":") || normalized.includes("/")) {
8315
+ const delimiter = normalized.includes(":") ? ":" : "/";
8316
+ const [wRaw, hRaw] = normalized.split(delimiter);
8317
+ const width = Number(wRaw?.trim());
8318
+ const height = Number(hRaw?.trim());
8319
+ if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) return;
8320
+ return width / height;
8321
+ }
8322
+ const numeric = Number(normalized);
8323
+ if (!Number.isFinite(numeric) || numeric <= 0) return void 0;
8324
+ return numeric;
8325
+ }
8326
+ const MAX_ASPECT_DISTANCE = .25;
8327
+ function resolveMediaTransformForAspect(transform, targetAspect) {
8328
+ if (!transform) return {};
8329
+ const base = {
8330
+ rect: transform.rect,
8331
+ hotspot: transform.hotspot,
8332
+ rotation: transform.rotation
8333
+ };
8334
+ const target = parseAspectRatioValue(targetAspect);
8335
+ const crops = transform.aspectCrops;
8336
+ if (!target || !crops || Object.keys(crops).length === 0) return base;
8337
+ let best = null;
8338
+ let bestDistance = Number.POSITIVE_INFINITY;
8339
+ for (const [key, candidate] of Object.entries(crops)) {
8340
+ const candidateAspect = parseAspectRatioValue(candidate.aspect ?? key);
8341
+ if (!candidateAspect) continue;
8342
+ const distance = Math.abs(Math.log(candidateAspect / target));
8343
+ if (distance < bestDistance) {
8344
+ best = candidate;
8345
+ bestDistance = distance;
8346
+ }
8347
+ }
8348
+ if (!best) return base;
8349
+ if (bestDistance > MAX_ASPECT_DISTANCE) return base;
8350
+ return {
8351
+ rect: best.rect ?? base.rect,
8352
+ hotspot: best.hotspot ?? base.hotspot,
8353
+ rotation: best.rotation ?? base.rotation
8354
+ };
8355
+ }
8356
+ function isValidTransformRect(rect) {
8357
+ return isValidTransformRectStructure(rect);
8358
+ }
8359
+ function isExplicitRectCrop(rect, sourceWidth, sourceHeight, epsilon = DEFAULT_RECT_EPSILON) {
8360
+ if (!isValidTransformRect(rect)) return false;
8361
+ if (!(typeof sourceWidth === "number" && Number.isFinite(sourceWidth) && sourceWidth > 0 && typeof sourceHeight === "number" && Number.isFinite(sourceHeight) && sourceHeight > 0)) return true;
8362
+ const [x, y, width, height] = rect;
8363
+ return !(Math.abs(x) <= epsilon && Math.abs(y) <= epsilon && Math.abs(width - sourceWidth) <= epsilon && Math.abs(height - sourceHeight) <= epsilon);
8364
+ }
8365
+ //#endregion
8366
+ //#region ../media-core/src/rotation.ts
8367
+ function rotateNormalizedPoint(point, rotation) {
8368
+ const x = point.x;
8369
+ const y = point.y;
8370
+ switch (rotation) {
8371
+ case 0: return {
8372
+ x,
8373
+ y
8374
+ };
8375
+ case 90: return {
8376
+ x: 1 - y,
8377
+ y: x
8378
+ };
8379
+ case 180: return {
8380
+ x: 1 - x,
8381
+ y: 1 - y
8382
+ };
8383
+ case 270: return {
8384
+ x: y,
8385
+ y: 1 - x
8386
+ };
8387
+ }
8388
+ }
8389
+ //#endregion
8024
8390
  //#region ../theme-core/src/palette/schema.ts
8025
8391
  const colourHexString = z.string().regex(/^#([0-9A-Fa-f]{3}){1,2}$/);
8026
8392
  const paletteColorSchema = z.object({
@@ -8049,6 +8415,29 @@ const paletteSchema = z.object({
8049
8415
  };
8050
8416
  });
8051
8417
  //#endregion
8418
+ //#region ../theme-core/src/buttons/typography.ts
8419
+ const textTransformSchema = z.enum([
8420
+ "none",
8421
+ "uppercase",
8422
+ "lowercase",
8423
+ "capitalize"
8424
+ ]);
8425
+ const fontWeightSchema = z.union([
8426
+ z.literal(400),
8427
+ z.literal(500),
8428
+ z.literal(600),
8429
+ z.literal(700),
8430
+ z.literal(800)
8431
+ ]);
8432
+ const buttonTypographySchema = z.enum(["body", "heading"]);
8433
+ const letterSpacingSchema = z.enum([
8434
+ "tight",
8435
+ "normal",
8436
+ "slight",
8437
+ "loose",
8438
+ "wide"
8439
+ ]);
8440
+ //#endregion
8052
8441
  //#region ../theme-core/src/buttons/types.ts
8053
8442
  /**
8054
8443
  * Standard semantic variant roles a theme exposes.
@@ -8164,6 +8553,7 @@ const buttonEffectApplicationSchema = z.discriminatedUnion("effectId", [
8164
8553
  z.strictObject({
8165
8554
  effectId: z.literal("lift"),
8166
8555
  options: z.strictObject({ amount: z.enum([
8556
+ "0.125",
8167
8557
  "0.25",
8168
8558
  "0.5",
8169
8559
  "1"
@@ -8210,24 +8600,6 @@ const shadowSizeSchema = z.enum([
8210
8600
  "medium",
8211
8601
  "high"
8212
8602
  ]);
8213
- const textTransformSchema = z.enum([
8214
- "none",
8215
- "uppercase",
8216
- "lowercase",
8217
- "capitalize"
8218
- ]);
8219
- const fontWeightSchema = z.union([
8220
- z.literal(500),
8221
- z.literal(600),
8222
- z.literal(700),
8223
- z.literal(800)
8224
- ]);
8225
- const buttonTypographySchema = z.enum(["body", "heading"]);
8226
- const letterSpacingSchema = z.enum([
8227
- "tight",
8228
- "normal",
8229
- "loose"
8230
- ]);
8231
8603
  const hoverTransformSchema = z.enum([
8232
8604
  "none",
8233
8605
  "lift",
@@ -8299,7 +8671,8 @@ const paddingShorthandSchema = z.string().refine((value) => {
8299
8671
  }, { message: "Padding must be two space-separated CSS length tokens (e.g. \"0.5rem 1rem\"). Use `0` for zero." });
8300
8672
  const buttonSizeConfigSchema = z.object({
8301
8673
  padding: paddingShorthandSchema,
8302
- fontSize: z.string().optional()
8674
+ fontSize: z.string().optional(),
8675
+ borderRadius: z.string().optional()
8303
8676
  });
8304
8677
  /**
8305
8678
  * `xl` is optional on the wire so themes persisted before the `xl` size was
@@ -8422,12 +8795,20 @@ const buttonVisualAppearanceSchema = z.strictObject({
8422
8795
  textTransform: textTransformSchema
8423
8796
  }),
8424
8797
  effects: z.array(buttonEffectApplicationSchema),
8798
+ transform: z.literal("none").optional(),
8425
8799
  contextualHover: contextualButtonHoverSchema.optional()
8426
8800
  });
8427
8801
  const buttonVisualStatesSchema = z.strictObject({
8428
8802
  base: buttonVisualAppearanceSchema.extend({ shadow: variantShadowSchema }),
8429
8803
  hover: buttonVisualAppearanceSchema.extend({ shadow: variantShadowSchema }),
8430
- focus: buttonVisualAppearanceSchema.extend({ shadow: z.literal("focus-indicator") }),
8804
+ focus: buttonVisualAppearanceSchema.extend({
8805
+ shadow: z.literal("focus-indicator"),
8806
+ indicator: z.strictObject({
8807
+ kind: z.literal("surface-ink"),
8808
+ width: z.union([z.literal(2), z.literal(3)]),
8809
+ offset: z.union([z.literal(3), z.literal(4)])
8810
+ }).optional()
8811
+ }),
8431
8812
  active: buttonVisualAppearanceSchema.extend({ shadow: variantShadowSchema }),
8432
8813
  disabled: buttonVisualAppearanceSchema.extend({ shadow: variantShadowSchema })
8433
8814
  });
@@ -8894,6 +9275,10 @@ function validateButtonTextContrast(input) {
8894
9275
  }
8895
9276
  };
8896
9277
  }
9278
+ /** A text-token slab inverts the palette's text/background pair, including text shades. */
9279
+ function solidForegroundToken(backgroundToken) {
9280
+ return /^text(?:-\d+)?$/.test(backgroundToken) ? "background" : onColorTokenName(backgroundToken);
9281
+ }
8897
9282
  //#endregion
8898
9283
  //#region ../theme-core/src/buttons/contextualHover.ts
8899
9284
  function resolveContextualHoverPreference(input) {
@@ -8991,7 +9376,7 @@ function candidate(family, shade, currentShade, direction, seedHex, palette) {
8991
9376
  }
8992
9377
  function hasSafeTextContrast(token, palette) {
8993
9378
  const background = palette[token];
8994
- const foreground = palette[onColorTokenName(token)];
9379
+ const foreground = palette[solidForegroundToken(token)];
8995
9380
  return typeof background === "string" && typeof foreground === "string" && contrastRatio(background, foreground) >= BUTTON_CONTRAST_POLICY.textMinimumRatio;
8996
9381
  }
8997
9382
  function isSafeCandidate(token, palette, surface) {
@@ -9086,6 +9471,13 @@ function compileDeclaredVisualStates(input, states) {
9086
9471
  const colours = collectStateColours(mapVisualStates((state) => compileDeclaredVisualState(input, states, state, state === "hover" ? hover.treatment : states[state].background)));
9087
9472
  return colours.ok ? {
9088
9473
  ...colours,
9474
+ focusIndicator: states.focus.indicator ? {
9475
+ kind: "surface-role",
9476
+ colorCss: input.surface?.foregroundCss ?? surfaceForegroundValue("text"),
9477
+ width: states.focus.indicator.width,
9478
+ offset: states.focus.indicator.offset,
9479
+ minimumSurfaceContrast: BUTTON_CONTRAST_POLICY.nonTextMinimumRatio
9480
+ } : colours.focusIndicator,
9089
9481
  contextualHoverRepair: hover.repair
9090
9482
  } : colours;
9091
9483
  }
@@ -9223,7 +9615,7 @@ function resolveFocusIndicator(colour) {
9223
9615
  function resolveSolid(input, backgroundToken, edge) {
9224
9616
  const backgroundHex = paletteHex(input, backgroundToken);
9225
9617
  if (!backgroundHex.ok) return backgroundHex;
9226
- const foregroundToken = unsafeAsOpaqueButtonColourToken(onColorTokenName(backgroundToken));
9618
+ const foregroundToken = unsafeAsOpaqueButtonColourToken(solidForegroundToken(backgroundToken));
9227
9619
  const foregroundHex = input.palette[foregroundToken];
9228
9620
  if (typeof foregroundHex !== "string") return {
9229
9621
  ok: false,
@@ -10397,6 +10789,287 @@ function normalizeAppearance(appearance) {
10397
10789
  };
10398
10790
  }
10399
10791
  //#endregion
10792
+ //#region ../theme-core/src/buttons/styles/recipes/lanternRecipes.ts
10793
+ const flatShadow = {
10794
+ elevation: "none",
10795
+ softness: null,
10796
+ position: "bottom"
10797
+ };
10798
+ const lift$1 = {
10799
+ effectId: "lift",
10800
+ options: { amount: "0.125" }
10801
+ };
10802
+ const tags = {
10803
+ tone: "classic",
10804
+ energy: "calm",
10805
+ motion: "subtle",
10806
+ era: "editorial"
10807
+ };
10808
+ /** Each role supplies complete states, including a flat surface-ink focus ring. */
10809
+ function states(base, hover, offset = 4, width = 2) {
10810
+ return {
10811
+ base,
10812
+ hover,
10813
+ focus: {
10814
+ ...base,
10815
+ shadow: "focus-indicator",
10816
+ indicator: {
10817
+ kind: "surface-ink",
10818
+ width,
10819
+ offset
10820
+ }
10821
+ },
10822
+ active: {
10823
+ ...base,
10824
+ transform: "none"
10825
+ },
10826
+ disabled: {
10827
+ ...base,
10828
+ effects: []
10829
+ }
10830
+ };
10831
+ }
10832
+ const gilt = {
10833
+ text: "treatment",
10834
+ border: "none",
10835
+ borderRadius: "rounded-10px",
10836
+ shadow: flatShadow,
10837
+ sizes: {
10838
+ sm: {
10839
+ padding: "10px 20px",
10840
+ fontSize: "text-base",
10841
+ borderRadius: "rounded-lg"
10842
+ },
10843
+ md: {
10844
+ padding: "18px 36px",
10845
+ fontSize: "text-19px"
10846
+ },
10847
+ lg: {
10848
+ padding: "18px 36px",
10849
+ fontSize: "text-19px"
10850
+ },
10851
+ xl: {
10852
+ padding: "18px 36px",
10853
+ fontSize: "text-19px"
10854
+ }
10855
+ },
10856
+ typography: {
10857
+ fontWeight: 400,
10858
+ typography: "heading",
10859
+ fontSize: "text-19px",
10860
+ letterSpacing: "slight",
10861
+ italic: false,
10862
+ textTransform: "none"
10863
+ },
10864
+ effects: []
10865
+ };
10866
+ const giltPrimary = {
10867
+ ...gilt,
10868
+ background: {
10869
+ type: "gradient",
10870
+ stops: ["accent", "primary"],
10871
+ direction: "to-br",
10872
+ foregroundToken: "onAccent"
10873
+ }
10874
+ };
10875
+ const giltPrimaryHover = {
10876
+ ...giltPrimary,
10877
+ background: {
10878
+ ...giltPrimary.background,
10879
+ stops: ["accent-400", "primary-400"],
10880
+ foregroundToken: "secondary-950"
10881
+ },
10882
+ effects: [lift$1]
10883
+ };
10884
+ const giltSecondary = {
10885
+ ...gilt,
10886
+ background: {
10887
+ type: "solid",
10888
+ colorToken: "text"
10889
+ }
10890
+ };
10891
+ const giltSecondaryHover = {
10892
+ ...giltSecondary,
10893
+ effects: [lift$1],
10894
+ contextualHover: {
10895
+ kind: "shade-shift",
10896
+ seedToken: unsafeAsOpaqueButtonColourToken("text"),
10897
+ fallbackDirection: "lighter"
10898
+ }
10899
+ };
10900
+ const giltPrimaryStates = states(giltPrimary, giltPrimaryHover);
10901
+ const giltSecondaryStates = states(giltSecondary, giltSecondaryHover);
10902
+ const giltSlabRecipe = defineStaticButtonStyleRecipe({
10903
+ id: "gilt-slab",
10904
+ accessibilityLabel: "Gilt slab",
10905
+ tags,
10906
+ system: { roles: {
10907
+ primary: { states: giltPrimaryStates },
10908
+ secondary: { states: giltSecondaryStates },
10909
+ outline: { states: giltSecondaryStates },
10910
+ ghost: { states: giltSecondaryStates },
10911
+ accent: { states: giltPrimaryStates }
10912
+ } }
10913
+ });
10914
+ const hairline = {
10915
+ text: "treatment",
10916
+ borderRadius: "rounded-3px",
10917
+ shadow: flatShadow,
10918
+ sizes: {
10919
+ sm: {
10920
+ padding: "9px 16px",
10921
+ fontSize: "text-xs"
10922
+ },
10923
+ md: {
10924
+ padding: "15px 28px",
10925
+ fontSize: "text-13px"
10926
+ },
10927
+ lg: {
10928
+ padding: "15px 28px",
10929
+ fontSize: "text-13px"
10930
+ },
10931
+ xl: {
10932
+ padding: "15px 28px",
10933
+ fontSize: "text-13px"
10934
+ }
10935
+ },
10936
+ typography: {
10937
+ fontWeight: 700,
10938
+ typography: "body",
10939
+ fontSize: "text-13px",
10940
+ letterSpacing: "wide",
10941
+ italic: false,
10942
+ textTransform: "uppercase"
10943
+ },
10944
+ effects: []
10945
+ };
10946
+ const hairlinePrimary = {
10947
+ ...hairline,
10948
+ background: {
10949
+ type: "solid",
10950
+ colorToken: "primary"
10951
+ },
10952
+ border: {
10953
+ widthClass: "border",
10954
+ boundaryInk: unsafeAsOpaqueButtonColourToken("primary")
10955
+ }
10956
+ };
10957
+ const hairlineOutline = {
10958
+ ...hairline,
10959
+ background: {
10960
+ type: "surface",
10961
+ role: "link"
10962
+ },
10963
+ border: {
10964
+ widthClass: "border",
10965
+ boundaryInk: unsafeAsOpaqueButtonColourToken("primary")
10966
+ }
10967
+ };
10968
+ const hairlineSecondary = {
10969
+ ...hairlineOutline,
10970
+ border: {
10971
+ widthClass: "border",
10972
+ boundaryInk: unsafeAsOpaqueButtonColourToken("accent")
10973
+ }
10974
+ };
10975
+ const hairlineFilled = {
10976
+ ...hairlineSecondary,
10977
+ background: {
10978
+ type: "solid",
10979
+ colorToken: "accent"
10980
+ }
10981
+ };
10982
+ const hairlinePrimaryStates = states(hairlinePrimary, hairlineOutline, 3);
10983
+ const hairlineSecondaryStates = states(hairlineSecondary, hairlineFilled, 3);
10984
+ const hairlineTabRecipe = defineStaticButtonStyleRecipe({
10985
+ id: "hairline-tab",
10986
+ accessibilityLabel: "Hairline tab",
10987
+ tags,
10988
+ system: { roles: {
10989
+ primary: { states: hairlinePrimaryStates },
10990
+ secondary: { states: hairlineSecondaryStates },
10991
+ outline: { states: hairlineSecondaryStates },
10992
+ ghost: { states: hairlineSecondaryStates },
10993
+ accent: { states: states(hairlineFilled, hairlineSecondary, 3) }
10994
+ } }
10995
+ });
10996
+ const marqueeAccent = {
10997
+ text: "treatment",
10998
+ borderRadius: "rounded-none",
10999
+ shadow: flatShadow,
11000
+ sizes: {
11001
+ sm: {
11002
+ padding: "8px 17px",
11003
+ fontSize: "text-15px"
11004
+ },
11005
+ md: {
11006
+ padding: "14px 25px",
11007
+ fontSize: "text-17px"
11008
+ },
11009
+ lg: {
11010
+ padding: "14px 25px",
11011
+ fontSize: "text-17px"
11012
+ },
11013
+ xl: {
11014
+ padding: "14px 25px",
11015
+ fontSize: "text-17px"
11016
+ }
11017
+ },
11018
+ typography: {
11019
+ fontWeight: 800,
11020
+ typography: "body",
11021
+ fontSize: "text-17px",
11022
+ letterSpacing: "loose",
11023
+ italic: false,
11024
+ textTransform: "uppercase"
11025
+ },
11026
+ effects: [],
11027
+ background: {
11028
+ type: "solid",
11029
+ colorToken: "accent"
11030
+ },
11031
+ border: {
11032
+ widthClass: "border-2",
11033
+ boundaryInk: unsafeAsOpaqueButtonColourToken("accent")
11034
+ }
11035
+ };
11036
+ const marqueePrimary = {
11037
+ ...marqueeAccent,
11038
+ background: {
11039
+ type: "solid",
11040
+ colorToken: "primary"
11041
+ },
11042
+ border: {
11043
+ widthClass: "border-2",
11044
+ boundaryInk: unsafeAsOpaqueButtonColourToken("primary")
11045
+ }
11046
+ };
11047
+ const marqueeSecondary = {
11048
+ ...marqueeAccent,
11049
+ background: {
11050
+ type: "solid",
11051
+ colorToken: "text"
11052
+ },
11053
+ border: {
11054
+ widthClass: "border-2",
11055
+ boundaryInk: unsafeAsOpaqueButtonColourToken("text")
11056
+ }
11057
+ };
11058
+ const marqueePrimaryStates = states(marqueeAccent, marqueePrimary, 4, 3);
11059
+ const marqueeSecondaryStates = states(marqueeSecondary, marqueeAccent, 4, 3);
11060
+ const marqueeRecipe = defineStaticButtonStyleRecipe({
11061
+ id: "marquee",
11062
+ accessibilityLabel: "Marquee",
11063
+ tags,
11064
+ system: { roles: {
11065
+ primary: { states: marqueePrimaryStates },
11066
+ secondary: { states: marqueeSecondaryStates },
11067
+ outline: { states: marqueeSecondaryStates },
11068
+ ghost: { states: marqueeSecondaryStates },
11069
+ accent: { states: marqueePrimaryStates }
11070
+ } }
11071
+ });
11072
+ //#endregion
10400
11073
  //#region ../theme-core/src/buttons/styles/recipes/fulcrumRecipe.ts
10401
11074
  const fulcrumSizes = {
10402
11075
  sm: {
@@ -11138,7 +11811,10 @@ const BUTTON_STYLE_IDS = [
11138
11811
  "offset-block",
11139
11812
  "ringed-pill",
11140
11813
  "square-outline",
11141
- "fulcrum"
11814
+ "fulcrum",
11815
+ "gilt-slab",
11816
+ "hairline-tab",
11817
+ "marquee"
11142
11818
  ];
11143
11819
  const quietArrowParametersSchema = z.object({ secondaryTreatment: z.enum(["outlined", "solid-accent"]) }).strict();
11144
11820
  const flatInkHoverTreatmentSchema = z.enum([
@@ -11175,7 +11851,10 @@ const buttonStyleSelectionSchema = z.discriminatedUnion("styleId", [
11175
11851
  selectionBranch("offset-block", emptyParametersSchema),
11176
11852
  selectionBranch("ringed-pill", emptyParametersSchema),
11177
11853
  selectionBranch("square-outline", emptyParametersSchema),
11178
- selectionBranch("fulcrum", emptyParametersSchema)
11854
+ selectionBranch("fulcrum", emptyParametersSchema),
11855
+ selectionBranch("gilt-slab", emptyParametersSchema),
11856
+ selectionBranch("hairline-tab", emptyParametersSchema),
11857
+ selectionBranch("marquee", emptyParametersSchema)
11179
11858
  ]);
11180
11859
  //#endregion
11181
11860
  //#region ../theme-core/src/buttons/styles/recipes/quietArrow.ts
@@ -14691,7 +15370,10 @@ const buttonStyleRecipes = [
14691
15370
  offsetBlockRecipe,
14692
15371
  ringedPillRecipe,
14693
15372
  squareOutlineRecipe,
14694
- fulcrumRecipe
15373
+ fulcrumRecipe,
15374
+ giltSlabRecipe,
15375
+ hairlineTabRecipe,
15376
+ marqueeRecipe
14695
15377
  ];
14696
15378
  const recipesById = new Map(buttonStyleRecipes.map((recipe) => [recipe.id, recipe]));
14697
15379
  function findButtonStyleRecipe(id) {
@@ -14707,6 +15389,9 @@ function resolveButtonStyleSelection(selection) {
14707
15389
  case "editorial-link": return resolveButtonStyleRecipe(editorialLinkRecipe, selection.parameters);
14708
15390
  case "pebble": return resolveButtonStyleRecipe(pebbleRecipe, selection.parameters);
14709
15391
  case "ink-stamp": return resolveButtonStyleRecipe(inkStampRecipe, selection.parameters);
15392
+ case "gilt-slab": return resolveButtonStyleRecipe(giltSlabRecipe, selection.parameters);
15393
+ case "hairline-tab": return resolveButtonStyleRecipe(hairlineTabRecipe, selection.parameters);
15394
+ case "marquee": return resolveButtonStyleRecipe(marqueeRecipe, selection.parameters);
14710
15395
  case "fulcrum": return resolveButtonStyleRecipe(fulcrumRecipe, selection.parameters);
14711
15396
  case "flat-ink": return resolveButtonStyleRecipe(flatInkRecipe, selection.parameters);
14712
15397
  case "brushed-wash": return resolveButtonStyleRecipe(brushedWashRecipe, selection.parameters);
@@ -16569,6 +17254,21 @@ const boxBackgroundSchema = z.discriminatedUnion("type", [
16569
17254
  showVideoOnMobile: z.boolean().nullable().optional()
16570
17255
  })
16571
17256
  ]);
17257
+ /** Application rendering sources are admitted separately from saved references. */
17258
+ const runtimeBoxBackgroundSchema = z.discriminatedUnion("type", [
17259
+ boxBackgroundSchema.options[0],
17260
+ boxBackgroundSchema.options[1],
17261
+ boxBackgroundSchema.options[2].extend({ image: z.union([
17262
+ imageMediaSchema,
17263
+ externalMediaSchema.extend({ type: z.literal("image") }),
17264
+ assetMediaSchema.extend({ type: z.literal("image") })
17265
+ ]).nullable().optional() }),
17266
+ boxBackgroundSchema.options[3].extend({ image: z.union([
17267
+ videoMediaSchema,
17268
+ externalMediaSchema.extend({ type: z.literal("video") }),
17269
+ assetMediaSchema.extend({ type: z.literal("video") })
17270
+ ]).nullable().optional() })
17271
+ ]);
16572
17272
  function normalizeAuthoringOpacity(value) {
16573
17273
  if (!isRecord$6(value)) return value;
16574
17274
  return {
@@ -16923,20 +17623,15 @@ const headerSchema = z.object({
16923
17623
  const footerVariant = z.enum([
16924
17624
  "simple",
16925
17625
  "columns",
16926
- "split"
16927
- ]);
17626
+ "split",
17627
+ "centred"
17628
+ ]).transform((value) => value === "columns" ? "simple" : value);
16928
17629
  const footerMaxWidth = z.enum(["container", "full"]);
16929
17630
  const footerNavLayoutMode = z.enum([
16930
17631
  "stack",
16931
17632
  "inline",
16932
17633
  "inline-wrap"
16933
17634
  ]);
16934
- const footerNavLayoutAlign = z.enum([
16935
- "start",
16936
- "center",
16937
- "end",
16938
- "space-between"
16939
- ]);
16940
17635
  const footerSpacing = z.enum([
16941
17636
  "none",
16942
17637
  "tight",
@@ -16945,12 +17640,6 @@ const footerSpacing = z.enum([
16945
17640
  "relaxed",
16946
17641
  "spacious"
16947
17642
  ]);
16948
- const footerLogoPlacement = z.enum([
16949
- "left",
16950
- "right",
16951
- "above",
16952
- "below"
16953
- ]);
16954
17643
  const footerLogoSize = z.enum([
16955
17644
  "sm",
16956
17645
  "md",
@@ -16991,17 +17680,8 @@ const footerBottomBarSchema = z.object({
16991
17680
  ]).optional()
16992
17681
  }).optional()
16993
17682
  });
16994
- const footerNavLayoutSchema = z.object({
16995
- layout: footerNavLayoutMode.optional(),
16996
- align: footerNavLayoutAlign.optional(),
16997
- gapX: footerSpacing.optional(),
16998
- gapY: footerSpacing.optional(),
16999
- columns: z.number().int().min(1).max(6).optional()
17000
- });
17683
+ const footerNavLayoutSchema = z.object({ layout: footerNavLayoutMode.optional() });
17001
17684
  const footerLogoSchema = z.object({
17002
- showLogo: z.boolean().default(true),
17003
- showLogoText: z.boolean().optional(),
17004
- placement: footerLogoPlacement.optional(),
17005
17685
  size: footerLogoSize.optional(),
17006
17686
  maxHeight: footerLogoMaxHeight.optional(),
17007
17687
  align: z.enum([
@@ -17011,15 +17691,8 @@ const footerLogoSchema = z.object({
17011
17691
  ]).optional()
17012
17692
  });
17013
17693
  const footerSchema = z.object({
17014
- /**
17015
- * SDK-only footer rendering mode.
17016
- *
17017
- * Historical persisted field; SDK rendering mode now lives in layout.footerMode.
17018
- */
17019
- mode: footerModeSchema.optional(),
17020
17694
  variant: footerVariant,
17021
17695
  maxWidth: footerMaxWidth,
17022
- showLogoText: z.boolean().optional(),
17023
17696
  background: headerBackgroundSchema.default({
17024
17697
  type: "color",
17025
17698
  color: "surface"
@@ -17202,7 +17875,9 @@ const cardListKnobBlocks = [...cardListFamilyBlocks, "block.event-calendar"];
17202
17875
  const lookKnobBlocks = {
17203
17876
  actionStyle: cardListKnobBlocks,
17204
17877
  titleSize: "block.hero",
17205
- imagePosition: "block.hero",
17878
+ imagePosition: ["block.hero", "block.media-text"],
17879
+ imageShape: "block.media-text",
17880
+ aspectRatio: "block.media-text",
17206
17881
  stickerLine: "block.hero",
17207
17882
  smallCaption: "block.hero",
17208
17883
  candleGlow: "block.hero",
@@ -17212,7 +17887,11 @@ const lookKnobBlocks = {
17212
17887
  dates: "block.offerings-preview",
17213
17888
  showCapacity: "block.event-calendar",
17214
17889
  quoteCount: "block.testimonials",
17215
- archFrame: "block.testimonials",
17890
+ archFrame: [
17891
+ "block.testimonials",
17892
+ "block.newsletter-signup",
17893
+ "block.form"
17894
+ ],
17216
17895
  tilt: "block.testimonials"
17217
17896
  };
17218
17897
  function isArrangementAppearancePreset(preset) {
@@ -17239,13 +17918,25 @@ function cardListKnobDefaults(block, arrangement, knobs, defaults) {
17239
17918
  }
17240
17919
  };
17241
17920
  }
17921
+ const arrangementLookTargets = {
17922
+ hero: "hero",
17923
+ "feature-cards": "feature-cards",
17924
+ "event-calendar": "events",
17925
+ testimonials: "testimonials",
17926
+ "event-details": "events",
17927
+ "media-text": "media-text",
17928
+ "image-gallery": "image-gallery",
17929
+ "newsletter-signup": "newsletter",
17930
+ form: "contact-form",
17931
+ "body-text": "body-text"
17932
+ };
17242
17933
  function defineArrangementLook(id, block, name, arrangement, knobs, input = {}) {
17243
17934
  const mode = block === "event-calendar" ? "list" : null;
17244
17935
  return {
17245
17936
  id: asAppearancePresetId(id),
17246
17937
  blockKinds: [`block.${block}`],
17247
17938
  label: name,
17248
- target: block === "event-calendar" || block === "event-details" ? "events" : block === "hero" ? "hero" : block === "testimonials" ? "testimonials" : "feature-cards",
17939
+ target: arrangementLookTargets[block],
17249
17940
  structure: {
17250
17941
  kind: "arrangement",
17251
17942
  byMode: { [mode ?? "default"]: arrangement },
@@ -18065,6 +18756,15 @@ const appearancePresets = [
18065
18756
  eyebrowTreatment: "accent"
18066
18757
  }
18067
18758
  }),
18759
+ defineArrangementLook("body-text-reading-column", "body-text", "Reading column", "prose", []),
18760
+ defineArrangementLook("form-beside-introduction-arched-panel", "form", "Introduction beside an arched form", "two-column", [], { slotRoles: { panel: "card" } }),
18761
+ defineArrangementLook("newsletter-signup-in-arch", "newsletter-signup", "Signup in an arch", "arch", []),
18762
+ defineArrangementLook("image-gallery-square-tiles", "image-gallery", "Square tiles", "tiles", []),
18763
+ defineArrangementLook("image-gallery-arched-captions", "image-gallery", "Arched photos with captions", "tiles", [], { styleFallback: [id$1("image-gallery-square-tiles")] }),
18764
+ defineArrangementLook("media-text-circle-beside-text", "media-text", "Circle beside the text", "circle-beside", ["imagePosition"], { forcedKnobs: {
18765
+ imageShape: "circle",
18766
+ aspectRatio: "1/1"
18767
+ } }),
18068
18768
  defineArrangementLook("hero-photo-beside-text", "hero", "Photo beside the text", "split", heroKnobs, { slotRoles: { sticker: "highlight" } }),
18069
18769
  defineArrangementLook("hero-headline-row", "hero", "Big headline, then text and photo", "headline-row", heroKnobs, {
18070
18770
  slotRoles: { sticker: "highlight" },
@@ -18650,6 +19350,49 @@ function requireThemeColorToken$1(value) {
18650
19350
  return token;
18651
19351
  }
18652
19352
  //#endregion
19353
+ //#region ../theme-core/src/header/rootPaint.ts
19354
+ /** The nav container takes precedence when a floating header also has one. */
19355
+ function headerRootPaint(header) {
19356
+ const navContainerType = header?.navContainer?.type ?? "none";
19357
+ if (navContainerType === "glass" || navContainerType === "pill") return "contained-nav";
19358
+ return header?.variant === "floating" ? "overlay" : "own-surface";
19359
+ }
19360
+ //#endregion
19361
+ //#region ../theme-core/src/site-styles/siteChromeBackgrounds.ts
19362
+ const siteChromeBackgroundColorTokens = toSiteChromeBackgroundColorTokens(backgroundAppearanceColorTokenNames);
19363
+ const quickSiteChromeBackgroundColorTokens = toSiteChromeBackgroundColorTokens(backgroundAppearanceQuickColorTokenNames);
19364
+ siteChromeBackgroundColorTokens.filter((token) => !quickSiteChromeBackgroundColorTokens.includes(token));
19365
+ function parseSiteChromeBackgroundColorToken(value) {
19366
+ const token = parseBackgroundAppearanceColorToken(value);
19367
+ return token ? token : null;
19368
+ }
19369
+ function toSiteChromeBackgroundColorTokens(tokenNames) {
19370
+ return tokenNames.flatMap((name) => {
19371
+ const token = parseSiteChromeBackgroundColorToken(name);
19372
+ return token ? [token] : [];
19373
+ });
19374
+ }
19375
+ const backgroundColorTokenSchema = z.unknown().transform((value, ctx) => {
19376
+ const token = parseSiteChromeBackgroundColorToken(value);
19377
+ if (token === null) {
19378
+ ctx.addIssue({
19379
+ code: "custom",
19380
+ message: "Unknown site chrome background colour token"
19381
+ });
19382
+ return z.NEVER;
19383
+ }
19384
+ return token;
19385
+ });
19386
+ const siteChromeBackgroundOverrideSchema = z.discriminatedUnion("kind", [z.object({ kind: z.literal("default") }).strict(), z.object({
19387
+ kind: z.literal("color"),
19388
+ token: backgroundColorTokenSchema
19389
+ }).strict()]);
19390
+ z.object({
19391
+ background: siteChromeBackgroundOverrideSchema,
19392
+ navigationLayout: z.enum(["inline-wrap", "stack"])
19393
+ }).strict();
19394
+ z.object({ background: siteChromeBackgroundOverrideSchema }).strict();
19395
+ //#endregion
18653
19396
  //#region ../theme-core/src/site-styles/compilationPlan.ts
18654
19397
  const defaultHeaderBrandPreferences = {
18655
19398
  brandDisplay: "auto",
@@ -18810,6 +19553,9 @@ function fallbackEndsAtOffer(entry, mode, style, catalogue, visited) {
18810
19553
  appearancePresets.filter(isArrangementAppearancePreset);
18811
19554
  /** Closed structural hooks shared by block arrangements and bounded skins. */
18812
19555
  const arrangementSlotNames = [
19556
+ "contact",
19557
+ "social",
19558
+ "base",
18813
19559
  "section",
18814
19560
  "stack",
18815
19561
  "inline",
@@ -18896,6 +19642,238 @@ function validateOfferKnobs(style, catalogue) {
18896
19642
  });
18897
19643
  }
18898
19644
  //#endregion
19645
+ //#region ../theme-core/src/site-styles/footerLookDefaults.ts
19646
+ const defaultFooterLookRecipes = {
19647
+ "footer-centred-name": {
19648
+ arrangement: "centred",
19649
+ ground: {
19650
+ kind: "token",
19651
+ token: "surface"
19652
+ },
19653
+ nav: {
19654
+ weight: "regular",
19655
+ colorToken: "text",
19656
+ hoverColorToken: "primary",
19657
+ typography: "body"
19658
+ },
19659
+ legal: {
19660
+ kind: "separate",
19661
+ bar: null
19662
+ },
19663
+ brandAlign: "center"
19664
+ },
19665
+ "footer-links-row": {
19666
+ arrangement: "simple",
19667
+ ground: {
19668
+ kind: "token",
19669
+ token: "surface"
19670
+ },
19671
+ nav: {
19672
+ weight: "regular",
19673
+ colorToken: "text",
19674
+ hoverColorToken: "primary",
19675
+ typography: "body"
19676
+ },
19677
+ legal: { kind: "integrated" },
19678
+ brandAlign: "start"
19679
+ }
19680
+ };
19681
+ /** A whole authored recipe replaces the default; facets are never deep-merged. */
19682
+ function resolveFooterLookRecipe(style, id) {
19683
+ return style?.footerLookRecipes?.[id] ?? defaultFooterLookRecipes[id];
19684
+ }
19685
+ //#endregion
19686
+ //#region ../theme-core/src/navigation/presets.ts
19687
+ /**
19688
+ * Built-in nav link style presets
19689
+ *
19690
+ * Each preset uses composable effects to achieve its look.
19691
+ */
19692
+ const NAV_LINK_PRESETS = {
19693
+ /**
19694
+ * Minimal - subtle color change on hover
19695
+ */
19696
+ minimal: {
19697
+ name: "Minimal",
19698
+ typography: "body",
19699
+ fontWeight: "medium",
19700
+ textTransform: "none",
19701
+ italic: false,
19702
+ colorToken: "text",
19703
+ hoverColorToken: "primary",
19704
+ padding: "none",
19705
+ borderRadius: "none",
19706
+ effects: { hover: [{
19707
+ effectId: "text-color-change",
19708
+ options: { hoverColorToken: "primary" }
19709
+ }] }
19710
+ },
19711
+ /**
19712
+ * Underline - static underline appears on hover
19713
+ */
19714
+ underline: {
19715
+ name: "Underline",
19716
+ typography: "body",
19717
+ fontWeight: "medium",
19718
+ textTransform: "none",
19719
+ italic: false,
19720
+ colorToken: "text",
19721
+ padding: "none",
19722
+ borderRadius: "none",
19723
+ effects: { hover: [{
19724
+ effectId: "nav-underline",
19725
+ options: { style: "static" }
19726
+ }] }
19727
+ },
19728
+ /**
19729
+ * Underline Grow - animated underline grows from center on hover
19730
+ */
19731
+ "underline-grow": {
19732
+ name: "Underline Grow",
19733
+ typography: "body",
19734
+ fontWeight: "medium",
19735
+ textTransform: "none",
19736
+ italic: false,
19737
+ colorToken: "text",
19738
+ padding: "none",
19739
+ borderRadius: "none",
19740
+ effects: { hover: [{
19741
+ effectId: "nav-underline",
19742
+ options: { style: "grow" }
19743
+ }] }
19744
+ },
19745
+ /**
19746
+ * Capsule - pill-shaped background on hover
19747
+ */
19748
+ capsule: {
19749
+ name: "Capsule",
19750
+ typography: "body",
19751
+ fontWeight: "medium",
19752
+ textTransform: "none",
19753
+ italic: false,
19754
+ colorToken: "text",
19755
+ padding: "compact",
19756
+ borderRadius: "full",
19757
+ effects: {
19758
+ hover: [{
19759
+ effectId: "background-on-hover-alpha",
19760
+ options: {
19761
+ colorToken: "primary",
19762
+ opacity: 10
19763
+ }
19764
+ }],
19765
+ active: [{
19766
+ effectId: "background-on-hover-alpha",
19767
+ options: {
19768
+ colorToken: "primary",
19769
+ opacity: 15
19770
+ }
19771
+ }]
19772
+ }
19773
+ },
19774
+ /**
19775
+ * Solid - solid background color on hover
19776
+ */
19777
+ solid: {
19778
+ name: "Solid",
19779
+ typography: "body",
19780
+ fontWeight: "medium",
19781
+ textTransform: "none",
19782
+ italic: false,
19783
+ colorToken: "text",
19784
+ padding: "compact",
19785
+ borderRadius: "none",
19786
+ effects: {
19787
+ hover: [{
19788
+ effectId: "background-on-hover",
19789
+ options: {
19790
+ colorToken: "primary",
19791
+ textColorToken: "primaryForeground"
19792
+ }
19793
+ }],
19794
+ active: [{
19795
+ effectId: "background-on-hover",
19796
+ options: {
19797
+ colorToken: "primary",
19798
+ textColorToken: "primaryForeground"
19799
+ }
19800
+ }]
19801
+ }
19802
+ },
19803
+ /**
19804
+ * Scale - gentle scale-up on hover
19805
+ */
19806
+ scale: {
19807
+ name: "Scale",
19808
+ typography: "body",
19809
+ fontWeight: "medium",
19810
+ textTransform: "none",
19811
+ italic: false,
19812
+ colorToken: "text",
19813
+ padding: "none",
19814
+ borderRadius: "none",
19815
+ effects: { hover: [{
19816
+ effectId: "scale-up",
19817
+ options: { scale: 1.05 }
19818
+ }] }
19819
+ },
19820
+ /**
19821
+ * Frosted - semi-transparent glass-like background
19822
+ */
19823
+ frosted: {
19824
+ name: "Frosted",
19825
+ typography: "body",
19826
+ fontWeight: "medium",
19827
+ textTransform: "none",
19828
+ italic: false,
19829
+ colorToken: "text",
19830
+ padding: "compact",
19831
+ borderRadius: "md",
19832
+ effects: {
19833
+ base: [{ effectId: "nav-frosted-base" }],
19834
+ hover: [{ effectId: "nav-frosted-hover" }],
19835
+ active: [{ effectId: "nav-frosted-active" }]
19836
+ }
19837
+ }
19838
+ };
19839
+ /**
19840
+ * Get a nav link style preset by ID
19841
+ */
19842
+ function getNavLinkPreset(presetId) {
19843
+ return NAV_LINK_PRESETS[presetId];
19844
+ }
19845
+ Object.keys(NAV_LINK_PRESETS);
19846
+ //#endregion
19847
+ //#region ../theme-core/src/footer/effectiveNavLinkStyle.ts
19848
+ function effectiveFooterNavLinkStyle(footer) {
19849
+ if (!footer) return null;
19850
+ if (footer.navLinkStyle) return footer.navLinkStyle;
19851
+ const basePreset = getNavLinkPreset(footer.navStyle ?? "minimal");
19852
+ if (!basePreset) return null;
19853
+ return {
19854
+ ...basePreset,
19855
+ fontWeight: footer.navWeight ?? basePreset.fontWeight,
19856
+ colorToken: footer.navColor?.trim() || basePreset.colorToken
19857
+ };
19858
+ }
19859
+ function footerForegroundCandidates(footer, proseHoverCandidate) {
19860
+ if (!footer) return {};
19861
+ const style = effectiveFooterNavLinkStyle(footer);
19862
+ return {
19863
+ text: footer.background?.textColor ?? (footer.variant === "centred" ? "text" : void 0),
19864
+ link: style?.colorToken ?? footer.navColor ?? footer.background?.textColor,
19865
+ linkHover: navLinkOwnsHoverForeground(style) ? proseHoverCandidate : navLinkHoverColorCandidate(style)
19866
+ };
19867
+ }
19868
+ //#endregion
19869
+ //#region ../theme-core/src/site-styles/footerLookRecipe.ts
19870
+ /** Reject undeclared references when the curated catalogue is loaded, before rendering. */
19871
+ function validateFooterRecipeSurfaces(style, recipe) {
19872
+ [recipe.ground, ...recipe.legal.kind === "separate" && recipe.legal.bar ? [recipe.legal.bar.background] : []].forEach((ground) => {
19873
+ if (ground.kind === "style-surface" && (style.looks.kind !== "offers" || !style.looks.surfaces[ground.surface])) throw new Error(`Undeclared footer surface: ${ground.surface}`);
19874
+ });
19875
+ }
19876
+ //#endregion
18899
19877
  //#region ../theme-core/src/accordions/siteStyleDefaults.ts
18900
19878
  /**
18901
19879
  * Reusable accordion "looks" for curated site styles.
@@ -19623,52 +20601,14 @@ defineLookOptionGroup({
19623
20601
  function asFooterLookId(value) {
19624
20602
  return value;
19625
20603
  }
19626
- function quietFooterLinks(theme) {
19627
- return {
19628
- ...theme.footer,
19629
- navStyle: "minimal",
19630
- navWeight: "regular",
19631
- navColor: "text",
19632
- navLinkStyle: {
19633
- typography: "body",
19634
- fontWeight: "regular",
19635
- textTransform: "none",
19636
- italic: false,
19637
- colorToken: "text",
19638
- hoverColorToken: "primary",
19639
- padding: "none",
19640
- borderRadius: "none"
19641
- }
19642
- };
19643
- }
19644
- function emphasizedFooterLinks(theme) {
19645
- return {
19646
- ...theme.footer,
19647
- navStyle: "minimal",
19648
- navWeight: "medium",
19649
- navColor: "text",
19650
- navLinkStyle: {
19651
- typography: "body",
19652
- fontWeight: "medium",
19653
- textTransform: "none",
19654
- italic: false,
19655
- colorToken: "text",
19656
- hoverColorToken: "primary",
19657
- padding: "none",
19658
- borderRadius: "none"
19659
- }
19660
- };
19661
- }
19662
20604
  const footerLookCatalog = defineExactCatalog()([{
19663
- id: asFooterLookId("footer-links-quiet"),
19664
- label: "Quiet links",
19665
- description: "Regular-weight footer navigation with a restrained hover.",
19666
- compile: quietFooterLinks
20605
+ id: asFooterLookId("footer-links-row"),
20606
+ label: "Links in a row",
20607
+ description: "Your links in a row, with the other footer sections in columns beside them."
19667
20608
  }, {
19668
- id: asFooterLookId("footer-links-emphasized"),
19669
- label: "Emphasized links",
19670
- description: "Medium-weight footer navigation with a clearer emphasis.",
19671
- compile: emphasizedFooterLinks
20609
+ id: asFooterLookId("footer-centred-name"),
20610
+ label: "Centred name, links beneath",
20611
+ description: "Your site name centred, with your links, contact details and social links beneath it."
19672
20612
  }]);
19673
20613
  new Map(footerLookCatalog.map((look) => [look.id, look]));
19674
20614
  //#endregion
@@ -21085,6 +22025,7 @@ function defineCuratedSiteStyle(input) {
21085
22025
  recommendedAppearancePresetIds
21086
22026
  },
21087
22027
  headerCuration: headerCurationBySiteStyle[input.id],
22028
+ footerLookRecipes: input.footerLookRecipes,
21088
22029
  recommendedFooterLookIds: (input.recommendedFooterLookIds ?? []).map(asFooterLookId),
21089
22030
  buttonStyleChoices: input.buttonStyleChoices,
21090
22031
  paletteRecommendations: input.paletteRecommendations,
@@ -21570,7 +22511,11 @@ const lanternLooks = {
21570
22511
  margin: "40px"
21571
22512
  },
21572
22513
  fontLoading: {
21573
- extraBodyFontWeights: [500, 700],
22514
+ extraBodyFontWeights: [
22515
+ 500,
22516
+ 700,
22517
+ 800
22518
+ ],
21574
22519
  italicBodyFontWeights: [400]
21575
22520
  },
21576
22521
  surfaces: {
@@ -21620,6 +22565,38 @@ const lanternLooks = {
21620
22565
  ]
21621
22566
  },
21622
22567
  offers: [
22568
+ {
22569
+ id: id("body-text-reading-column"),
22570
+ treatment: "reading-column",
22571
+ roleMap: lanternRoles
22572
+ },
22573
+ {
22574
+ id: id("form-beside-introduction-arched-panel"),
22575
+ treatment: "arched-panel",
22576
+ addKnobs: ["archFrame"],
22577
+ roleMap: lanternRoles
22578
+ },
22579
+ {
22580
+ id: id("newsletter-signup-in-arch"),
22581
+ treatment: "signup-arch",
22582
+ addKnobs: ["archFrame"],
22583
+ roleMap: lanternRoles
22584
+ },
22585
+ {
22586
+ id: id("image-gallery-square-tiles"),
22587
+ treatment: "square-tiles",
22588
+ roleMap: lanternRoles
22589
+ },
22590
+ {
22591
+ id: id("image-gallery-arched-captions"),
22592
+ treatment: "arched-captions",
22593
+ roleMap: lanternRoles
22594
+ },
22595
+ {
22596
+ id: id("media-text-circle-beside-text"),
22597
+ treatment: "circle-beside",
22598
+ roleMap: lanternRoles
22599
+ },
21623
22600
  {
21624
22601
  id: id("event-details-panel"),
21625
22602
  treatment: "quiet",
@@ -22058,7 +23035,7 @@ const curatedSiteStyles = [
22058
23035
  "faq-contained-help",
22059
23036
  "contact-form-panel"
22060
23037
  ],
22061
- recommendedFooterLookIds: ["footer-links-quiet"],
23038
+ recommendedFooterLookIds: ["footer-links-row"],
22062
23039
  buttonStyleChoices: [
22063
23040
  buttonChoice("soft-pill"),
22064
23041
  buttonChoice("pebble"),
@@ -22177,7 +23154,7 @@ const curatedSiteStyles = [
22177
23154
  "testimonials-non-carded",
22178
23155
  "contact-form-panel"
22179
23156
  ],
22180
- recommendedFooterLookIds: ["footer-links-quiet", "footer-links-emphasized"],
23157
+ recommendedFooterLookIds: ["footer-links-row"],
22181
23158
  buttonStyleChoices: [
22182
23159
  buttonChoice("earth-pill"),
22183
23160
  buttonChoice("soft-pill"),
@@ -22232,7 +23209,41 @@ const curatedSiteStyles = [
22232
23209
  "testimonials-brand-statement-cards",
22233
23210
  "contact-form-panel"
22234
23211
  ],
22235
- recommendedFooterLookIds: ["footer-links-emphasized", "footer-links-quiet"],
23212
+ footerLookRecipes: { "footer-links-row": {
23213
+ arrangement: "split",
23214
+ ground: {
23215
+ kind: "token",
23216
+ token: "primary-800"
23217
+ },
23218
+ nav: {
23219
+ weight: "medium",
23220
+ colorToken: "primaryForeground",
23221
+ hoverColorToken: "secondary",
23222
+ typography: "body"
23223
+ },
23224
+ legal: {
23225
+ kind: "separate",
23226
+ bar: {
23227
+ fullBleed: true,
23228
+ background: {
23229
+ kind: "token",
23230
+ token: "primary-900"
23231
+ },
23232
+ textColor: "primaryForeground",
23233
+ textAlign: "center",
23234
+ paddingY: "compact",
23235
+ paddingX: "default",
23236
+ borderTop: { width: "none" }
23237
+ },
23238
+ linkStyle: {
23239
+ colorToken: "secondary",
23240
+ decorationColorToken: "secondary"
23241
+ }
23242
+ },
23243
+ brandAlign: "start",
23244
+ brandLogoSize: "sm"
23245
+ } },
23246
+ recommendedFooterLookIds: ["footer-links-row"],
22236
23247
  buttonStyleChoices: [
22237
23248
  buttonChoice("showtime-pill"),
22238
23249
  buttonChoice("confident-chip"),
@@ -22303,7 +23314,7 @@ const curatedSiteStyles = [
22303
23314
  "testimonials-statement-cards",
22304
23315
  "contact-form-panel"
22305
23316
  ],
22306
- recommendedFooterLookIds: ["footer-links-emphasized", "footer-links-quiet"],
23317
+ recommendedFooterLookIds: ["footer-links-row"],
22307
23318
  buttonStyleChoices: [
22308
23319
  buttonChoice("ornate-ritual"),
22309
23320
  buttonChoice("joy-stamp"),
@@ -22350,7 +23361,22 @@ const curatedSiteStyles = [
22350
23361
  } }
22351
23362
  },
22352
23363
  recommendedAppearancePresetIds: ["feature-cards-bold-colors", "testimonials-statement-cards"],
22353
- recommendedFooterLookIds: ["footer-links-emphasized", "footer-links-quiet"],
23364
+ footerLookRecipes: { "footer-links-row": {
23365
+ arrangement: "simple",
23366
+ ground: {
23367
+ kind: "token",
23368
+ token: "surface"
23369
+ },
23370
+ nav: {
23371
+ weight: "medium",
23372
+ colorToken: "text",
23373
+ hoverColorToken: "primary",
23374
+ typography: "body"
23375
+ },
23376
+ legal: { kind: "integrated" },
23377
+ brandAlign: "start"
23378
+ } },
23379
+ recommendedFooterLookIds: ["footer-links-row"],
22354
23380
  buttonStyleChoices: [
22355
23381
  buttonChoice("joy-stamp"),
22356
23382
  buttonChoice("ink-stamp"),
@@ -22402,7 +23428,7 @@ const curatedSiteStyles = [
22402
23428
  },
22403
23429
  testimonialQuote: serifDisplayQuote
22404
23430
  },
22405
- recommendedFooterLookIds: ["footer-links-quiet"],
23431
+ recommendedFooterLookIds: ["footer-links-row"],
22406
23432
  buttonStyleChoices: [
22407
23433
  buttonChoice("fulcrum"),
22408
23434
  buttonChoice("editorial-link"),
@@ -22479,7 +23505,7 @@ const curatedSiteStyles = [
22479
23505
  "faq-base-accordion",
22480
23506
  "booking-brand-band"
22481
23507
  ],
22482
- recommendedFooterLookIds: ["footer-links-quiet"],
23508
+ recommendedFooterLookIds: ["footer-links-row"],
22483
23509
  buttonStyleChoices: [
22484
23510
  buttonChoice("quiet-arrow", void 0, { secondaryTreatment: "solid-accent" }),
22485
23511
  buttonChoice("flat-ink"),
@@ -22517,7 +23543,22 @@ const curatedSiteStyles = [
22517
23543
  accordions: boldBorderedAccordionSystem,
22518
23544
  testimonialQuote: accentGlyphQuote
22519
23545
  },
22520
- recommendedFooterLookIds: ["footer-links-emphasized"],
23546
+ footerLookRecipes: { "footer-links-row": {
23547
+ arrangement: "simple",
23548
+ ground: {
23549
+ kind: "token",
23550
+ token: "surface"
23551
+ },
23552
+ nav: {
23553
+ weight: "medium",
23554
+ colorToken: "text",
23555
+ hoverColorToken: "primary",
23556
+ typography: "body"
23557
+ },
23558
+ legal: { kind: "integrated" },
23559
+ brandAlign: "start"
23560
+ } },
23561
+ recommendedFooterLookIds: ["footer-links-row"],
22521
23562
  buttonStyleChoices: [
22522
23563
  buttonChoice("offset-block"),
22523
23564
  buttonChoice("ink-stamp"),
@@ -22556,8 +23597,29 @@ const curatedSiteStyles = [
22556
23597
  accordions: warmInsetAccordionSystem,
22557
23598
  testimonialQuote: serifDisplayQuote
22558
23599
  },
22559
- recommendedFooterLookIds: ["footer-links-quiet"],
23600
+ footerLookRecipes: { "footer-centred-name": {
23601
+ arrangement: "centred",
23602
+ ground: {
23603
+ kind: "style-surface",
23604
+ surface: "deep"
23605
+ },
23606
+ nav: {
23607
+ weight: "regular",
23608
+ colorToken: "text",
23609
+ hoverColorToken: "primary",
23610
+ typography: "heading"
23611
+ },
23612
+ legal: {
23613
+ kind: "separate",
23614
+ bar: null
23615
+ },
23616
+ brandAlign: "center"
23617
+ } },
23618
+ recommendedFooterLookIds: ["footer-centred-name", "footer-links-row"],
22560
23619
  buttonStyleChoices: [
23620
+ buttonChoice("gilt-slab"),
23621
+ buttonChoice("hairline-tab"),
23622
+ buttonChoice("marquee"),
22561
23623
  buttonChoice("ringed-pill"),
22562
23624
  buttonChoice("earth-pill"),
22563
23625
  buttonChoice("editorial-link")
@@ -22592,7 +23654,7 @@ const curatedSiteStyles = [
22592
23654
  accordions: editorialDividedAccordionSystem,
22593
23655
  testimonialQuote: serifDisplayQuote
22594
23656
  },
22595
- recommendedFooterLookIds: ["footer-links-quiet"],
23657
+ recommendedFooterLookIds: ["footer-links-row"],
22596
23658
  buttonStyleChoices: [
22597
23659
  buttonChoice("flat-ink", void 0, { corners: "square" }),
22598
23660
  buttonChoice("editorial-link"),
@@ -22620,6 +23682,7 @@ function curatedStyleTemplate(input) {
22620
23682
  }
22621
23683
  curatedSiteStyles.forEach((style) => {
22622
23684
  if (style.looks.kind === "offers") validateLookFallbacks(style.looks);
23685
+ (/* @__PURE__ */ new Set([...Object.values(style.footerLookRecipes ?? {}), ...style.recommendedFooterLookIds.map((id) => resolveFooterLookRecipe(style, id))])).forEach((recipe) => validateFooterRecipeSurfaces(style, recipe));
22623
23686
  });
22624
23687
  //#endregion
22625
23688
  //#region ../theme-core/src/site-styles/effectiveArrangement.ts
@@ -22695,29 +23758,6 @@ const blockDesignFallback = {
22695
23758
  };
22696
23759
  blockDesignFallback.sectionSurface, blockDesignFallback.contentFrame, blockDesignFallback.sectionHeight, blockDesignFallback.heroLegibility, blockDesignFallback.imageSurfaceTreatment, blockDesignFallback.imageSurfaceMotion, blockDesignFallback.tileTreatment, blockDesignFallback.eventListTreatment, blockDesignFallback.eyebrowTreatment, blockDesignFallback.accordionIconTreatment, blockDesignFallback.composition;
22697
23760
  //#endregion
22698
- //#region ../theme-core/src/header/rootPaint.ts
22699
- /** The nav container takes precedence when a floating header also has one. */
22700
- function headerRootPaint(header) {
22701
- const navContainerType = header?.navContainer?.type ?? "none";
22702
- if (navContainerType === "glass" || navContainerType === "pill") return "contained-nav";
22703
- return header?.variant === "floating" ? "overlay" : "own-surface";
22704
- }
22705
- //#endregion
22706
- //#region ../theme-core/src/site-styles/siteChromeBackgrounds.ts
22707
- const siteChromeBackgroundColorTokens = toSiteChromeBackgroundColorTokens(backgroundAppearanceColorTokenNames);
22708
- const quickSiteChromeBackgroundColorTokens = toSiteChromeBackgroundColorTokens(backgroundAppearanceQuickColorTokenNames);
22709
- siteChromeBackgroundColorTokens.filter((token) => !quickSiteChromeBackgroundColorTokens.includes(token));
22710
- function parseSiteChromeBackgroundColorToken(value) {
22711
- const token = parseBackgroundAppearanceColorToken(value);
22712
- return token ? token : null;
22713
- }
22714
- function toSiteChromeBackgroundColorTokens(tokenNames) {
22715
- return tokenNames.flatMap((name) => {
22716
- const token = parseSiteChromeBackgroundColorToken(name);
22717
- return token ? [token] : [];
22718
- });
22719
- }
22720
- //#endregion
22721
23761
  //#region ../theme-core/src/site-styles/siteChromeNavPreferences.ts
22722
23762
  const headerNavTypographyPreferenceValues = [
22723
23763
  "inherit",
@@ -22833,21 +23873,6 @@ z.object({
22833
23873
  }).strict();
22834
23874
  //#endregion
22835
23875
  //#region ../theme-core/src/site-styles/headerPreferencesPersistence.ts
22836
- const backgroundColorTokenSchema = z.unknown().transform((value, ctx) => {
22837
- const token = parseSiteChromeBackgroundColorToken(value);
22838
- if (token === null) {
22839
- ctx.addIssue({
22840
- code: "custom",
22841
- message: "Unknown site chrome background colour token"
22842
- });
22843
- return z.NEVER;
22844
- }
22845
- return token;
22846
- });
22847
- const backgroundOverrideSchema = z.discriminatedUnion("kind", [z.object({ kind: z.literal("default") }).strict(), z.object({
22848
- kind: z.literal("color"),
22849
- token: backgroundColorTokenSchema
22850
- }).strict()]);
22851
23876
  const logoTextIntentSchema = z.object({
22852
23877
  mobileMaxWidth: z.enum([
22853
23878
  "xs",
@@ -22873,7 +23898,7 @@ const headerPreferencesShape = {
22873
23898
  navFontRole: z.enum(headerNavTypographyPreferenceValues),
22874
23899
  navTextSize: z.enum(headerNavFontSizePreferenceValues),
22875
23900
  interactionPalette: z.union([z.literal("recommended"), z.enum(headerInteractionPaletteValues)]),
22876
- background: backgroundOverrideSchema,
23901
+ background: siteChromeBackgroundOverrideSchema,
22877
23902
  structure: structureSchema
22878
23903
  };
22879
23904
  z.object(headerPreferencesShape).strict();
@@ -22882,167 +23907,6 @@ z.object(headerPreferencesShape).omit({
22882
23907
  structure: true
22883
23908
  }).strict();
22884
23909
  //#endregion
22885
- //#region ../theme-core/src/navigation/presets.ts
22886
- /**
22887
- * Built-in nav link style presets
22888
- *
22889
- * Each preset uses composable effects to achieve its look.
22890
- */
22891
- const NAV_LINK_PRESETS = {
22892
- /**
22893
- * Minimal - subtle color change on hover
22894
- */
22895
- minimal: {
22896
- name: "Minimal",
22897
- typography: "body",
22898
- fontWeight: "medium",
22899
- textTransform: "none",
22900
- italic: false,
22901
- colorToken: "text",
22902
- hoverColorToken: "primary",
22903
- padding: "none",
22904
- borderRadius: "none",
22905
- effects: { hover: [{
22906
- effectId: "text-color-change",
22907
- options: { hoverColorToken: "primary" }
22908
- }] }
22909
- },
22910
- /**
22911
- * Underline - static underline appears on hover
22912
- */
22913
- underline: {
22914
- name: "Underline",
22915
- typography: "body",
22916
- fontWeight: "medium",
22917
- textTransform: "none",
22918
- italic: false,
22919
- colorToken: "text",
22920
- padding: "none",
22921
- borderRadius: "none",
22922
- effects: { hover: [{
22923
- effectId: "nav-underline",
22924
- options: { style: "static" }
22925
- }] }
22926
- },
22927
- /**
22928
- * Underline Grow - animated underline grows from center on hover
22929
- */
22930
- "underline-grow": {
22931
- name: "Underline Grow",
22932
- typography: "body",
22933
- fontWeight: "medium",
22934
- textTransform: "none",
22935
- italic: false,
22936
- colorToken: "text",
22937
- padding: "none",
22938
- borderRadius: "none",
22939
- effects: { hover: [{
22940
- effectId: "nav-underline",
22941
- options: { style: "grow" }
22942
- }] }
22943
- },
22944
- /**
22945
- * Capsule - pill-shaped background on hover
22946
- */
22947
- capsule: {
22948
- name: "Capsule",
22949
- typography: "body",
22950
- fontWeight: "medium",
22951
- textTransform: "none",
22952
- italic: false,
22953
- colorToken: "text",
22954
- padding: "compact",
22955
- borderRadius: "full",
22956
- effects: {
22957
- hover: [{
22958
- effectId: "background-on-hover-alpha",
22959
- options: {
22960
- colorToken: "primary",
22961
- opacity: 10
22962
- }
22963
- }],
22964
- active: [{
22965
- effectId: "background-on-hover-alpha",
22966
- options: {
22967
- colorToken: "primary",
22968
- opacity: 15
22969
- }
22970
- }]
22971
- }
22972
- },
22973
- /**
22974
- * Solid - solid background color on hover
22975
- */
22976
- solid: {
22977
- name: "Solid",
22978
- typography: "body",
22979
- fontWeight: "medium",
22980
- textTransform: "none",
22981
- italic: false,
22982
- colorToken: "text",
22983
- padding: "compact",
22984
- borderRadius: "none",
22985
- effects: {
22986
- hover: [{
22987
- effectId: "background-on-hover",
22988
- options: {
22989
- colorToken: "primary",
22990
- textColorToken: "primaryForeground"
22991
- }
22992
- }],
22993
- active: [{
22994
- effectId: "background-on-hover",
22995
- options: {
22996
- colorToken: "primary",
22997
- textColorToken: "primaryForeground"
22998
- }
22999
- }]
23000
- }
23001
- },
23002
- /**
23003
- * Scale - gentle scale-up on hover
23004
- */
23005
- scale: {
23006
- name: "Scale",
23007
- typography: "body",
23008
- fontWeight: "medium",
23009
- textTransform: "none",
23010
- italic: false,
23011
- colorToken: "text",
23012
- padding: "none",
23013
- borderRadius: "none",
23014
- effects: { hover: [{
23015
- effectId: "scale-up",
23016
- options: { scale: 1.05 }
23017
- }] }
23018
- },
23019
- /**
23020
- * Frosted - semi-transparent glass-like background
23021
- */
23022
- frosted: {
23023
- name: "Frosted",
23024
- typography: "body",
23025
- fontWeight: "medium",
23026
- textTransform: "none",
23027
- italic: false,
23028
- colorToken: "text",
23029
- padding: "compact",
23030
- borderRadius: "md",
23031
- effects: {
23032
- base: [{ effectId: "nav-frosted-base" }],
23033
- hover: [{ effectId: "nav-frosted-hover" }],
23034
- active: [{ effectId: "nav-frosted-active" }]
23035
- }
23036
- }
23037
- };
23038
- /**
23039
- * Get a nav link style preset by ID
23040
- */
23041
- function getNavLinkPreset(presetId) {
23042
- return NAV_LINK_PRESETS[presetId];
23043
- }
23044
- Object.keys(NAV_LINK_PRESETS);
23045
- //#endregion
23046
23910
  //#region ../theme-core/src/header/legacyNavLinkStyle.ts
23047
23911
  function buildLegacyHeaderNavLinkStyle(header, contrastTreatment, navTextSize) {
23048
23912
  const navStyle = header.navStyle ?? "minimal";
@@ -23287,28 +24151,6 @@ z.object({
23287
24151
  motion: z.enum(themeTokenRecipeOptions.motion)
23288
24152
  });
23289
24153
  //#endregion
23290
- //#region ../theme-core/src/footer/effectiveNavLinkStyle.ts
23291
- function effectiveFooterNavLinkStyle(footer) {
23292
- if (!footer) return null;
23293
- if (footer.navLinkStyle) return footer.navLinkStyle;
23294
- const basePreset = getNavLinkPreset(footer.navStyle ?? "minimal");
23295
- if (!basePreset) return null;
23296
- return {
23297
- ...basePreset,
23298
- fontWeight: footer.navWeight ?? basePreset.fontWeight,
23299
- colorToken: footer.navColor?.trim() || basePreset.colorToken
23300
- };
23301
- }
23302
- function footerForegroundCandidates(footer, proseHoverCandidate) {
23303
- if (!footer) return {};
23304
- const style = effectiveFooterNavLinkStyle(footer);
23305
- return {
23306
- text: footer.background?.textColor,
23307
- link: style?.colorToken ?? footer.navColor ?? footer.background?.textColor,
23308
- linkHover: navLinkOwnsHoverForeground(style) ? proseHoverCandidate : navLinkHoverColorCandidate(style)
23309
- };
23310
- }
23311
- //#endregion
23312
24154
  //#region ../theme-core/src/siteChromeOverlayClearance.ts
23313
24155
  const SITE_CHROME_VISIBLE_HEADER_ATTR = "data-site-chrome-visible-header";
23314
24156
  //#endregion
@@ -23418,97 +24260,6 @@ function registerManifest(manifest) {
23418
24260
  return manifest;
23419
24261
  }
23420
24262
  //#endregion
23421
- //#region ../media-core/src/transformRect.ts
23422
- function isValidTransformRectStructure(rect) {
23423
- if (!Array.isArray(rect) || rect.length !== 4) return false;
23424
- const [left, top, width, height] = rect;
23425
- return Number.isFinite(left) && Number.isFinite(top) && Number.isFinite(width) && Number.isFinite(height) && left >= 0 && top >= 0 && width > 0 && height > 0;
23426
- }
23427
- //#endregion
23428
- //#region ../media-core/src/aspectTransforms.ts
23429
- const DEFAULT_RECT_EPSILON = .5;
23430
- function parseAspectRatioValue(value) {
23431
- if (typeof value === "number") return Number.isFinite(value) && value > 0 ? value : void 0;
23432
- if (typeof value !== "string") return void 0;
23433
- const normalized = value.trim();
23434
- if (!normalized) return void 0;
23435
- if (normalized === "auto") return void 0;
23436
- if (normalized.includes(":") || normalized.includes("/")) {
23437
- const delimiter = normalized.includes(":") ? ":" : "/";
23438
- const [wRaw, hRaw] = normalized.split(delimiter);
23439
- const width = Number(wRaw?.trim());
23440
- const height = Number(hRaw?.trim());
23441
- if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) return;
23442
- return width / height;
23443
- }
23444
- const numeric = Number(normalized);
23445
- if (!Number.isFinite(numeric) || numeric <= 0) return void 0;
23446
- return numeric;
23447
- }
23448
- const MAX_ASPECT_DISTANCE = .25;
23449
- function resolveMediaTransformForAspect(transform, targetAspect) {
23450
- if (!transform) return {};
23451
- const base = {
23452
- rect: transform.rect,
23453
- hotspot: transform.hotspot,
23454
- rotation: transform.rotation
23455
- };
23456
- const target = parseAspectRatioValue(targetAspect);
23457
- const crops = transform.aspectCrops;
23458
- if (!target || !crops || Object.keys(crops).length === 0) return base;
23459
- let best = null;
23460
- let bestDistance = Number.POSITIVE_INFINITY;
23461
- for (const [key, candidate] of Object.entries(crops)) {
23462
- const candidateAspect = parseAspectRatioValue(candidate.aspect ?? key);
23463
- if (!candidateAspect) continue;
23464
- const distance = Math.abs(Math.log(candidateAspect / target));
23465
- if (distance < bestDistance) {
23466
- best = candidate;
23467
- bestDistance = distance;
23468
- }
23469
- }
23470
- if (!best) return base;
23471
- if (bestDistance > MAX_ASPECT_DISTANCE) return base;
23472
- return {
23473
- rect: best.rect ?? base.rect,
23474
- hotspot: best.hotspot ?? base.hotspot,
23475
- rotation: best.rotation ?? base.rotation
23476
- };
23477
- }
23478
- function isValidTransformRect(rect) {
23479
- return isValidTransformRectStructure(rect);
23480
- }
23481
- function isExplicitRectCrop(rect, sourceWidth, sourceHeight, epsilon = DEFAULT_RECT_EPSILON) {
23482
- if (!isValidTransformRect(rect)) return false;
23483
- if (!(typeof sourceWidth === "number" && Number.isFinite(sourceWidth) && sourceWidth > 0 && typeof sourceHeight === "number" && Number.isFinite(sourceHeight) && sourceHeight > 0)) return true;
23484
- const [x, y, width, height] = rect;
23485
- return !(Math.abs(x) <= epsilon && Math.abs(y) <= epsilon && Math.abs(width - sourceWidth) <= epsilon && Math.abs(height - sourceHeight) <= epsilon);
23486
- }
23487
- //#endregion
23488
- //#region ../media-core/src/rotation.ts
23489
- function rotateNormalizedPoint(point, rotation) {
23490
- const x = point.x;
23491
- const y = point.y;
23492
- switch (rotation) {
23493
- case 0: return {
23494
- x,
23495
- y
23496
- };
23497
- case 90: return {
23498
- x: 1 - y,
23499
- y: x
23500
- };
23501
- case 180: return {
23502
- x: 1 - x,
23503
- y: 1 - y
23504
- };
23505
- case 270: return {
23506
- x: y,
23507
- y: 1 - x
23508
- };
23509
- }
23510
- }
23511
- //#endregion
23512
24263
  //#region ../blocks/src/system/node/schema.ts
23513
24264
  const transformStepSchema = z.object({
23514
24265
  id: z.string().min(1, "Transform requires an identifier"),
@@ -26434,6 +27185,12 @@ function parseBackgroundOverlay(value) {
26434
27185
  const result = boxBackgroundOverlaySchema.safeParse(value);
26435
27186
  return result.success ? result.data : void 0;
26436
27187
  }
27188
+ /** Rendering accepts explicit application sources separately from stored references. */
27189
+ const runtimeBackgroundContentSchema = runtimeBoxBackgroundSchema;
27190
+ function parseRuntimeBackgroundContent(value) {
27191
+ const result = runtimeBackgroundContentSchema.safeParse(value);
27192
+ return result.success ? result.data : null;
27193
+ }
26437
27194
  //#endregion
26438
27195
  //#region ../blocks/src/system/transforms/registry/_utils/themeColorResolution.ts
26439
27196
  function resolveBackgroundColorValue(value, context) {
@@ -26489,7 +27246,12 @@ function resolveRuntimeSectionSurface(value, context, options) {
26489
27246
  }
26490
27247
  function arrangementSurfaceInk(foreground, context) {
26491
27248
  if (context.data?._lookSlots === void 0) return {};
26492
- const decorations = surfaceDecorationColors(foreground, context.theme.palette);
27249
+ return surfaceInkStyles(foreground, context.theme.palette);
27250
+ }
27251
+ /** Decoration roles already resolved by the surface owner, shared with footer arrangements. */
27252
+ function surfaceInkStyles(foreground, palette) {
27253
+ if (foreground.kind === "unknown") return {};
27254
+ const decorations = surfaceDecorationColors(foreground, palette);
26493
27255
  return {
26494
27256
  "--rb-surface-muted-color": foreground.roles.muted ?? foreground.roles.text,
26495
27257
  ...decorations ? {
@@ -27100,48 +27862,50 @@ const boxStylesTransforms = [
27100
27862
  ];
27101
27863
  //#endregion
27102
27864
  //#region ../blocks/src/system/node/fragments/responsiveTwoColumn.ts
27103
- function responsiveTwoColumn({ image, text, ratioFrom, imagePositionFrom, gapClassName = "rb-gap-6", gapFrom, gapFallback = "comfortable", containerClassName = "rb-flex rb-flex-col rb-md-flex-row", imageWrapperClassName = "rb-w-full rb-shrink-0", textWrapperClassName = "rb-w-full rb-min-w-0 rb-flex-1" }) {
27104
- const baseClass = !gapFrom ? `${containerClassName} ${gapClassName}`.trim() : containerClassName;
27105
- const props = { className: { $bind: {
27106
- from: imagePositionFrom,
27107
- transforms: [{
27108
- id: "ui.twoColumnContainerClass",
27109
- options: {
27110
- base: baseClass,
27111
- reverseClass: "rb-md-flex-row-reverse"
27112
- }
27113
- }],
27114
- fallback: baseClass
27115
- } } };
27116
- if (gapFrom) props.style = { gap: { $bind: {
27117
- from: gapFrom,
27118
- transforms: [{
27119
- id: "boxStyles.semanticGapValue",
27120
- options: { fallback: gapFallback }
27121
- }],
27122
- fallback: GAP_VALUE_MAP[gapFallback]
27123
- } } };
27124
- return el("div", props, [el("div", {
27125
- className: imageWrapperClassName,
27126
- style: { flexBasis: { $bind: {
27127
- from: ratioFrom,
27865
+ /** The shared two-column shell keeps Look hooks opt-in and absent for legacy content. */
27866
+ function responsiveTwoColumn(config) {
27867
+ return el("div", twoColumnProps(config), [twoColumnWrapper(config, "image", config.image), twoColumnWrapper(config, "text", config.text)]);
27868
+ }
27869
+ function twoColumnProps(config) {
27870
+ const base = `${config.containerClassName ?? "rb-flex rb-flex-col rb-md-flex-row"} ${config.gapFrom ? "" : config.gapClassName ?? "rb-gap-6"}`.trim();
27871
+ const fallback = config.gapFallback ?? "comfortable";
27872
+ return {
27873
+ ...config.lookSlots ? lookSlot("frame") : {},
27874
+ className: { $bind: {
27875
+ from: config.imagePositionFrom,
27128
27876
  transforms: [{
27129
- id: "ui.twoColumnFlexBasis",
27130
- options: { side: "image" }
27877
+ id: "ui.twoColumnContainerClass",
27878
+ options: {
27879
+ base,
27880
+ reverseClass: "rb-md-flex-row-reverse"
27881
+ }
27131
27882
  }],
27132
- fallback: "50%"
27133
- } } }
27134
- }, [image]), el("div", {
27135
- className: textWrapperClassName,
27883
+ fallback: base
27884
+ } },
27885
+ ...config.gapFrom ? { style: { gap: { $bind: {
27886
+ from: config.gapFrom,
27887
+ transforms: [{
27888
+ id: "boxStyles.semanticGapValue",
27889
+ options: { fallback }
27890
+ }],
27891
+ fallback: GAP_VALUE_MAP[fallback]
27892
+ } } } } : {}
27893
+ };
27894
+ }
27895
+ function twoColumnWrapper(config, side, child) {
27896
+ const className = side === "image" ? config.imageWrapperClassName ?? "rb-w-full rb-shrink-0" : config.textWrapperClassName ?? "rb-w-full rb-min-w-0 rb-flex-1";
27897
+ return el("div", {
27898
+ ...config.lookSlots ? lookSlot(side === "image" ? "media" : "copy") : {},
27899
+ className,
27136
27900
  style: { flexBasis: { $bind: {
27137
- from: ratioFrom,
27901
+ from: config.ratioFrom,
27138
27902
  transforms: [{
27139
27903
  id: "ui.twoColumnFlexBasis",
27140
- options: { side: "text" }
27904
+ options: { side }
27141
27905
  }],
27142
27906
  fallback: "50%"
27143
27907
  } } }
27144
- }, [text])]);
27908
+ }, [child]);
27145
27909
  }
27146
27910
  //#endregion
27147
27911
  //#region ../blocks/src/system/node/fragments/styledCard.ts
@@ -27328,6 +28092,47 @@ function sectionState(opts) {
27328
28092
  })]);
27329
28093
  }
27330
28094
  //#endregion
28095
+ //#region ../blocks/src/system/node/fragments/sectionHead.ts
28096
+ const recoverEmptyHeadingWhenActive = {
28097
+ kind: "recover-empty-when-active",
28098
+ placeholder: "Add heading"
28099
+ };
28100
+ const recoverEmptyDescriptionWhenActive = {
28101
+ kind: "recover-empty-when-active",
28102
+ placeholder: "Add description"
28103
+ };
28104
+ function sectionHeaderLayoutNodes(options = {}) {
28105
+ const headingNode = text({
28106
+ as: "h2",
28107
+ ...lookSlot("heading")
28108
+ }, bind("content.heading"), when("content.heading", { authoringPresence: recoverEmptyHeadingWhenActive }));
28109
+ const descriptionNode = richText({
28110
+ className: "rb-prose rb-max-w-none",
28111
+ ...lookSlot("intro")
28112
+ }, bind("content.description"), when("content.description", { authoringPresence: recoverEmptyDescriptionWhenActive }));
28113
+ if (options.splitClassName) return [el("div", {
28114
+ className: options.splitClassName,
28115
+ ...lookSlot("head")
28116
+ }, [headingNode, descriptionNode])];
28117
+ return [headingNode, descriptionNode];
28118
+ }
28119
+ /** Shared optional section copy. Existing consumers keep their description ID. */
28120
+ const sectionHeaderFields = (defaultHeading, introLabel = "Description") => [{
28121
+ id: "heading",
28122
+ type: "text",
28123
+ label: "Heading",
28124
+ description: "Main heading for the section",
28125
+ required: false,
28126
+ multiline: false,
28127
+ ...defaultHeading === void 0 ? {} : { defaultValue: defaultHeading }
28128
+ }, {
28129
+ id: "description",
28130
+ type: "richText",
28131
+ label: introLabel,
28132
+ description: "Optional introductory text",
28133
+ required: false
28134
+ }];
28135
+ //#endregion
27331
28136
  //#region ../blocks/src/system/fragments/types.ts
27332
28137
  const FRAGMENT_ID_PATTERN = /^[a-z0-9](?:[a-z0-9._-]*[a-z0-9])?$/i;
27333
28138
  const FIELD_ID_PATTERN = /^[a-z][a-zA-Z0-9_-]*$/;
@@ -27660,6 +28465,7 @@ const bodyCopyFragment = defineFragment({
27660
28465
  ],
27661
28466
  layout: stack({
27662
28467
  gap: "md",
28468
+ ...lookSlot("copy"),
27663
28469
  className: "body-copy-container",
27664
28470
  align: { $bind: {
27665
28471
  from: "content.alignment",
@@ -27668,6 +28474,7 @@ const bodyCopyFragment = defineFragment({
27668
28474
  } }
27669
28475
  }, [text({
27670
28476
  as: "h2",
28477
+ ...lookSlot("heading"),
27671
28478
  className: { $bind: {
27672
28479
  from: "content.alignment",
27673
28480
  transforms: [{
@@ -27676,14 +28483,22 @@ const bodyCopyFragment = defineFragment({
27676
28483
  }],
27677
28484
  fallback: "body-copy-heading"
27678
28485
  } }
27679
- }, when("content.heading"), bind("content.heading")), richText({ className: { $bind: {
27680
- from: "content.alignment",
27681
- transforms: [{
27682
- id: "ui.bodyClassFromAlignment",
27683
- options: { base: "body-copy-body rb-prose rb-max-w-none" }
27684
- }],
27685
- fallback: "body-copy-body rb-prose rb-max-w-none"
27686
- } } }, bind("content.body"))])
28486
+ }, when("content.heading", { authoringPresence: {
28487
+ kind: "recover-empty-when-active",
28488
+ placeholder: "Add heading"
28489
+ } }), bind("content.heading")), richText({
28490
+ ...lookSlot("item-body"),
28491
+ leadParagraphSlot: { $bind: { from: "content._lookSlots.lede" } },
28492
+ lookSlots: { $bind: { from: "content._lookSlots" } },
28493
+ className: { $bind: {
28494
+ from: "content.alignment",
28495
+ transforms: [{
28496
+ id: "ui.bodyClassFromAlignment",
28497
+ options: { base: "body-copy-body rb-prose rb-max-w-none" }
28498
+ }],
28499
+ fallback: "body-copy-body rb-prose rb-max-w-none"
28500
+ } }
28501
+ }, bind("content.body"))])
27687
28502
  });
27688
28503
  //#endregion
27689
28504
  //#region ../blocks/src/system/fragments/library/heroCopy.ts
@@ -28699,8 +29514,19 @@ const formCopyFragment = defineFragment({
28699
29514
  }],
28700
29515
  layout: [text({
28701
29516
  as: "h2",
29517
+ ...lookSlot("heading"),
28702
29518
  className: "form-copy-title"
28703
- }, when("content.title"), bind("content.title")), richText({ className: "form-copy-intro rb-prose rb-max-w-none" }, when("content.intro"), bind("content.intro"))]
29519
+ }, when("content.title", { authoringPresence: {
29520
+ kind: "recover-empty-when-active",
29521
+ placeholder: "Add heading"
29522
+ } }), bind("content.title")), richText({
29523
+ className: "form-copy-intro rb-prose rb-max-w-none",
29524
+ ...lookSlot("intro"),
29525
+ leadParagraphSlot: { $bind: { from: "content._lookSlots.lede" } }
29526
+ }, when("content.intro", { authoringPresence: {
29527
+ kind: "recover-empty-when-active",
29528
+ placeholder: "Add introduction"
29529
+ } }), bind("content.intro"))]
28704
29530
  });
28705
29531
  //#endregion
28706
29532
  //#region ../blocks/src/system/helpers/api-bindings.ts
@@ -28749,6 +29575,7 @@ const formEmbedFragment = defineFragment({
28749
29575
  }
28750
29576
  ],
28751
29577
  layout: [form(withApiBindings({
29578
+ lookSlots: { $bind: { from: "content._lookSlots" } },
28752
29579
  spamProtectionEnabled: { $bind: { from: "$root.spamProtectionEnabled" } },
28753
29580
  submitLabel: { $bind: { from: "submitLabel" } },
28754
29581
  successMessage: { $bind: { from: "successMessage" } }
@@ -29002,8 +29829,18 @@ const newsletterCopyFragment = defineFragment({
29002
29829
  }],
29003
29830
  layout: [text({
29004
29831
  as: "h2",
29005
- className: "newsletter-copy-title"
29006
- }, when("content.title"), bind("content.title")), richText({ className: "newsletter-copy-subtitle rb-prose rb-max-w-none" }, when("content.subtitle"), bind("content.subtitle"))]
29832
+ className: "newsletter-copy-title",
29833
+ ...lookSlot("heading")
29834
+ }, when("content.title", { authoringPresence: {
29835
+ kind: "recover-empty-when-active",
29836
+ placeholder: "Add heading"
29837
+ } }), bind("content.title")), richText({
29838
+ className: "newsletter-copy-subtitle rb-prose rb-max-w-none",
29839
+ ...lookSlot("intro")
29840
+ }, when("content.subtitle", { authoringPresence: {
29841
+ kind: "recover-empty-when-active",
29842
+ placeholder: "Add introduction"
29843
+ } }), bind("content.subtitle"))]
29007
29844
  });
29008
29845
  //#endregion
29009
29846
  //#region ../blocks/src/system/fragments/library/newsletterForm.ts
@@ -29071,6 +29908,7 @@ const newsletterFormFragment = defineFragment({
29071
29908
  }
29072
29909
  ],
29073
29910
  layout: [el("newsletter-form", withApiBindings({
29911
+ lookSlots: { $bind: { from: "content._lookSlots" } },
29074
29912
  source: { $bind: {
29075
29913
  from: "mailingListSource",
29076
29914
  fallback: "block"
@@ -30563,18 +31401,11 @@ const introBlockDefinition = { manifest: createBlockManifest({
30563
31401
  //#endregion
30564
31402
  //#region ../blocks/src/system/blocks/body-text.ts
30565
31403
  const bodyCopyComposition = composeFragments([{ fragment: bodyCopyFragment }]);
30566
- const proseLayout = styledSection({
30567
- children: stack({ className: "rb-container" }, bodyCopyComposition.layout),
30568
- spacing: "medium",
30569
- baseClass: ""
30570
- });
30571
- const introLayout = styledSection({
30572
- children: stack({ className: "rb-container" }, bodyCopyComposition.layout),
30573
- spacing: "medium",
30574
- baseClass: ""
30575
- });
30576
- const narrowLayout = styledSection({
30577
- children: stack({ className: "rb-container" }, bodyCopyComposition.layout),
31404
+ const bodyTextLayout = styledSection({
31405
+ children: stack({
31406
+ className: "rb-container",
31407
+ ...lookSlot("frame")
31408
+ }, bodyCopyComposition.layout),
30578
31409
  spacing: "medium",
30579
31410
  baseClass: ""
30580
31411
  });
@@ -30588,11 +31419,11 @@ const bodyTextBlockDefinition = { manifest: createBlockManifest({
30588
31419
  fragment: bodyCopyFragment,
30589
31420
  fieldPriority: 0
30590
31421
  }],
30591
- layout: proseLayout,
31422
+ layout: bodyTextLayout,
30592
31423
  variants: {
30593
- prose: proseLayout,
30594
- intro: introLayout,
30595
- narrow: narrowLayout
31424
+ prose: bodyTextLayout,
31425
+ intro: bodyTextLayout,
31426
+ narrow: bodyTextLayout
30596
31427
  },
30597
31428
  variantMeaning: { kind: "arrangement" },
30598
31429
  defaultVariant: "prose",
@@ -31040,6 +31871,52 @@ const singleButtonBlockDefinition = { manifest: createBlockManifest({
31040
31871
  styleTokens: { spacing: "md" }
31041
31872
  }) };
31042
31873
  //#endregion
31874
+ //#region ../blocks/src/system/runtime/lookSurfaces.ts
31875
+ const isPlainObject$1 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
31876
+ const lookListPresentationSchemaShape = {
31877
+ sectionAction: z.object({
31878
+ label: z.string(),
31879
+ href: z.string()
31880
+ }).optional(),
31881
+ actionSize: z.enum([
31882
+ "sm",
31883
+ "md",
31884
+ "lg"
31885
+ ]).optional(),
31886
+ itemActionStyle: z.enum(["button", "link"]).optional(),
31887
+ itemRoles: z.object({
31888
+ container: z.enum([
31889
+ "card",
31890
+ "statement",
31891
+ "highlight"
31892
+ ]).optional(),
31893
+ items: z.enum([
31894
+ "card",
31895
+ "statement",
31896
+ "highlight"
31897
+ ]).optional(),
31898
+ at: z.partialRecord(z.enum([
31899
+ "first",
31900
+ "last",
31901
+ "middle",
31902
+ "odd",
31903
+ "even"
31904
+ ]), z.enum([
31905
+ "card",
31906
+ "statement",
31907
+ "highlight"
31908
+ ])).optional()
31909
+ }).optional(),
31910
+ roleSurfaces: z.record(z.enum([
31911
+ "card",
31912
+ "statement",
31913
+ "highlight"
31914
+ ]), z.custom((value) => isPlainObject$1(value) && (value.kind === "inherit" || value.kind === "owned"))).optional(),
31915
+ panelHeading: z.string().optional(),
31916
+ lookSlots: z.partialRecord(z.enum(arrangementSlotNames), z.enum(arrangementSlotNames)).optional(),
31917
+ itemSurfaces: z.record(z.string(), z.custom((value) => isPlainObject$1(value) && (value.kind === "inherit" || value.kind === "owned"))).optional()
31918
+ };
31919
+ //#endregion
31043
31920
  //#region ../blocks/src/contracts/runtime.ts
31044
31921
  function decodeSuccess(value) {
31045
31922
  return {
@@ -31146,6 +32023,7 @@ const formFieldGroupSchema = z.discriminatedUnion("type", [z.object({
31146
32023
  fields: z.tuple([formFieldSchema, formFieldSchema])
31147
32024
  })]);
31148
32025
  const formSourceSchema = z.object({
32026
+ lookSlots: lookListPresentationSchemaShape.lookSlots,
31149
32027
  value: formRecordSchema.optional(),
31150
32028
  siteId: z.string().optional(),
31151
32029
  apiBaseUrl: z.string().optional(),
@@ -31155,6 +32033,7 @@ const formSourceSchema = z.object({
31155
32033
  spamProtectionEnabled: z.boolean().optional()
31156
32034
  });
31157
32035
  const formDisplaySchema = z.object({
32036
+ lookSlots: lookListPresentationSchemaShape.lookSlots,
31158
32037
  kind: z.literal("form"),
31159
32038
  state: z.enum(["missing", "ready"]),
31160
32039
  className: z.string().nullable(),
@@ -31175,17 +32054,30 @@ z.object({
31175
32054
  });
31176
32055
  function buildFormDisplay(source) {
31177
32056
  const form = source.value ?? null;
31178
- const fields = form?.schemaJson?.fields;
31179
- const groups = Array.isArray(fields) ? groupFormFields(fields) : [];
32057
+ const fields = formDisplayFields(form);
31180
32058
  return {
31181
32059
  kind: "form",
31182
- state: form ? "ready" : "missing",
32060
+ ...source.lookSlots ? { lookSlots: source.lookSlots } : {},
32061
+ state: fields.state,
31183
32062
  className: source.className ?? null,
31184
- formId: form?.id ?? null,
32063
+ formId: fields.formId,
31185
32064
  submitLabel: source.submitLabel?.trim() || "Submit",
31186
32065
  successMessage: source.successMessage ?? null,
31187
32066
  form,
31188
- groups
32067
+ groups: fields.groups
32068
+ };
32069
+ }
32070
+ function formDisplayFields(form) {
32071
+ if (!form) return {
32072
+ state: "missing",
32073
+ formId: null,
32074
+ groups: []
32075
+ };
32076
+ const fields = form.schemaJson?.fields;
32077
+ return {
32078
+ state: "ready",
32079
+ formId: form.id,
32080
+ groups: Array.isArray(fields) ? groupFormFields(fields) : []
31189
32081
  };
31190
32082
  }
31191
32083
  const formBlockRuntime = defineProgressiveBlockRuntime({
@@ -31208,18 +32100,27 @@ function fragmentLayoutNode$1(layout) {
31208
32100
  function isNodeDefinitionArray$1(layout) {
31209
32101
  return Array.isArray(layout);
31210
32102
  }
31211
- const copyLayout = fragmentLayoutNode$1(formCopyFragment.layout);
32103
+ const copyLayout = props(lookSlot("head"))(fragmentLayoutNode$1(formCopyFragment.layout));
32104
+ const embedLayout$1 = fragmentLayoutNode$1(formEmbedFragment.layout);
31212
32105
  const formSurface = styledContainer({
32106
+ rootProps: lookSlot("panel"),
31213
32107
  bindFrom: "_containerStyles",
31214
32108
  constrainWidth: false,
31215
32109
  baseClassName: "rb-form-surface rb-relative rb-isolate rb-overflow-visible",
31216
- children: fragmentLayoutNode$1(formEmbedFragment.layout)
32110
+ children: embedLayout$1
31217
32111
  });
31218
32112
  function createFormLayout(variant) {
31219
32113
  if (variant === "two-column") return styledSection({
31220
- children: el("div", { className: "rb-container" }, [el("div", { className: "rb-form-two-column rb-grid rb-grid-cols-1 rb-gap-8 rb-lg-grid-cols-2 rb-lg-items-start" }, [stack({
32114
+ children: el("div", {
32115
+ className: "rb-container",
32116
+ ...lookSlot("layout")
32117
+ }, [el("div", {
32118
+ className: "rb-form-two-column rb-grid rb-grid-cols-1 rb-gap-8 rb-lg-grid-cols-2 rb-lg-items-start",
32119
+ ...lookSlot("frame")
32120
+ }, [stack({
31221
32121
  gap: "md",
31222
- className: "rb-form-copy-column"
32122
+ className: "rb-form-copy-column",
32123
+ ...lookSlot("copy")
31223
32124
  }, [copyLayout]), formSurface])]),
31224
32125
  baseClass: "",
31225
32126
  spacing: "medium",
@@ -31247,6 +32148,15 @@ const formManifest = createBlockManifest({
31247
32148
  description: "Renders a saved form definition with server-side submit.",
31248
32149
  includeContainerStyles: true,
31249
32150
  fragments: [{ fragment: formCopyFragment }, { fragment: formEmbedFragment }],
32151
+ additionalFields: [{
32152
+ id: "archFrame",
32153
+ type: "boolean",
32154
+ label: "Arch frame",
32155
+ ui: {
32156
+ intent: "display",
32157
+ hidden: true
32158
+ }
32159
+ }],
31250
32160
  layout: formLayout,
31251
32161
  variants: {
31252
32162
  default: formLayout,
@@ -32002,7 +32912,7 @@ const heroTitleLengthThresholds = {
32002
32912
  maxWords: 11
32003
32913
  }
32004
32914
  };
32005
- function isPlainObject$1(value) {
32915
+ function isPlainObject(value) {
32006
32916
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
32007
32917
  }
32008
32918
  function readString(obj, key) {
@@ -32011,7 +32921,7 @@ function readString(obj, key) {
32011
32921
  }
32012
32922
  function resolveGeneratedHeroLayoutStyles(content) {
32013
32923
  const raw = content._heroLayoutStyles;
32014
- return isPlainObject$1(raw) ? raw : null;
32924
+ return isPlainObject(raw) ? raw : null;
32015
32925
  }
32016
32926
  function readHeroLayoutString(content, generatedKey, fallbackKey = generatedKey) {
32017
32927
  const explicitValue = readString(content, fallbackKey);
@@ -32069,7 +32979,7 @@ const heroContentWrapperClassTransform = {
32069
32979
  summary: "Resolve hero content wrapper className from alignment + max width controls",
32070
32980
  schema: z.object({ base: z.string().optional() }),
32071
32981
  run: (value, options, context) => {
32072
- const content = isPlainObject$1(value) ? value : isPlainObject$1(context.data) ? context.data : {};
32982
+ const content = isPlainObject(value) ? value : isPlainObject(context.data) ? context.data : {};
32073
32983
  const alignment = resolveHeroContentAlignment(content);
32074
32984
  const maxWidth = resolveHeroContentMaxWidth(content);
32075
32985
  const typographyScale = resolveHeroTypographyScale(content);
@@ -32091,7 +33001,7 @@ const heroCtaJustifyTransform = {
32091
33001
  kind: "string",
32092
33002
  summary: "Map hero contentAlignment to CTA row justify value",
32093
33003
  run: (value, _options, context) => {
32094
- const alignment = resolveHeroContentAlignment(isPlainObject$1(value) ? value : isPlainObject$1(context.data) ? context.data : {});
33004
+ const alignment = resolveHeroContentAlignment(isPlainObject(value) ? value : isPlainObject(context.data) ? context.data : {});
32095
33005
  return alignment === "left" ? "start" : alignment === "right" ? "end" : "center";
32096
33006
  }
32097
33007
  };
@@ -32100,7 +33010,7 @@ const heroStackJustifyFromVerticalAlignmentTransform = {
32100
33010
  kind: "string",
32101
33011
  summary: "Map hero verticalAlignment to stack justify value",
32102
33012
  run: (value, _options, context) => {
32103
- const vertical = resolveHeroVerticalAlignment(isPlainObject$1(value) ? value : isPlainObject$1(context.data) ? context.data : {});
33013
+ const vertical = resolveHeroVerticalAlignment(isPlainObject(value) ? value : isPlainObject(context.data) ? context.data : {});
32104
33014
  return vertical === "top" ? "start" : vertical === "bottom" ? "end" : "center";
32105
33015
  }
32106
33016
  };
@@ -32110,7 +33020,7 @@ const heroGridClassFromVerticalAlignmentTransform = {
32110
33020
  summary: "Append align-items class for hero split layouts based on verticalAlignment",
32111
33021
  schema: z.object({ base: z.string() }),
32112
33022
  run: (value, options, context) => {
32113
- const vertical = resolveHeroVerticalAlignment(isPlainObject$1(value) ? value : isPlainObject$1(context.data) ? context.data : {});
33023
+ const vertical = resolveHeroVerticalAlignment(isPlainObject(value) ? value : isPlainObject(context.data) ? context.data : {});
32114
33024
  const itemsClass = vertical === "top" ? "rb-items-start" : vertical === "bottom" ? "rb-items-end" : "rb-items-center";
32115
33025
  return joinClasses$1([options.base, itemsClass]);
32116
33026
  }
@@ -32398,6 +33308,25 @@ function heroHeadlineText(content, policy) {
32398
33308
  return policy === "look" ? inlineTextToPlainText(coerceInlineTextWithFallback(content.headlineInline, plain)).trim() : plain?.trim() ?? "";
32399
33309
  }
32400
33310
  //#endregion
33311
+ //#region ../blocks/src/system/transforms/registry/footerArrangement.ts
33312
+ const footerBrandArrangementTransform = {
33313
+ id: "layout.footerBrandArrangement",
33314
+ kind: "string",
33315
+ run: (value) => {
33316
+ const module = asPartialObject(value);
33317
+ return module?.kind === "brand" ? module.slots ? "centred" : "row" : void 0;
33318
+ }
33319
+ };
33320
+ const footerModuleInkStyleTransform = {
33321
+ id: "layout.footerModuleInkStyle",
33322
+ kind: "formatter",
33323
+ run: (value, options) => value === "centred" ? void 0 : textColorStyle(asPartialObject(options)?.opacity === 70 ? "text/70" : "text/80")
33324
+ };
33325
+ /** A centred base without authored bar paint inherits its measured surface line. */
33326
+ function footerBottomBarBorderColorStyle(footer) {
33327
+ return footer?.variant === "centred" && !footer.bottomBar ? { borderColor: "var(--rb-surface-line-color)" } : borderColorStyle(footer?.bottomBar?.borderTop?.colorToken ?? "border");
33328
+ }
33329
+ //#endregion
32401
33330
  //#region ../blocks/src/system/runtime/header/runtimeContract.ts
32402
33331
  const headerScrollRuntimeSchema = z.discriminatedUnion("kind", [z.object({ kind: z.literal("none") }), z.object({ kind: z.literal("threshold") })]);
32403
33332
  z.object({ scroll: headerScrollRuntimeSchema });
@@ -32629,6 +33558,7 @@ const footerRootStyleTransform = {
32629
33558
  }
32630
33559
  }
32631
33560
  styleParts.push(resolvedForegroundStyle(resolveFooterRootForeground(footer, context.theme.palette, context.proseHoverCandidate)));
33561
+ if (footer?.variant === "centred") styleParts.push(surfaceInkStyles(resolveFooterRootForeground(footer, context.theme.palette, context.proseHoverCandidate), context.theme.palette));
32632
33562
  styleParts.push(borderColorStyle("border"));
32633
33563
  return mergeStyles(...styleParts);
32634
33564
  }
@@ -32690,7 +33620,7 @@ const footerBottomBarStyleTransform = {
32690
33620
  run: (value, _options, context) => {
32691
33621
  const footer = asPartialObject(value);
32692
33622
  const bottomBar = footer?.bottomBar;
32693
- return mergeStyles(bottomBar?.background?.type === "color" ? backgroundColorStyle(bottomBar.background.color ?? "surface") : void 0, borderColorStyle(bottomBar?.borderTop?.colorToken ?? "border"), footerBottomBarBorderWidthStyle(bottomBar?.borderTop?.width), footerBottomBarForegroundStyle(footer, context.theme.palette));
33623
+ return mergeStyles(bottomBar?.background?.type === "color" ? backgroundColorStyle(bottomBar.background.color ?? "surface") : void 0, footerBottomBarBorderColorStyle(footer), footerBottomBarBorderWidthStyle(bottomBar?.borderTop?.width), footerBottomBarForegroundStyle(footer, context.theme.palette));
32694
33624
  }
32695
33625
  };
32696
33626
  function footerBottomBarForegroundStyle(footer, palette) {
@@ -32712,62 +33642,15 @@ function measuredFooterBackdrop(footer, palette) {
32712
33642
  const foreground = resolveFooterRootForeground(footer, palette);
32713
33643
  return foreground.kind === "known" && foreground.provenance.kind === "measured" ? foreground.provenance.backdropHex : null;
32714
33644
  }
32715
- const footerSplitMainClassTransform = {
32716
- id: "layout.footerSplitMainClass",
32717
- kind: "string",
32718
- summary: "Compose split-footer main row classes from footer logo placement",
32719
- schema: z.object({
32720
- base: z.string().optional(),
32721
- reverseClass: z.string().optional()
32722
- }),
32723
- run: (value, options) => {
32724
- const placement = asPartialObject(value)?.placement ?? "right";
32725
- const shouldPlaceLogoFirst = placement === "left" || placement === "above";
32726
- const baseClass = shouldPlaceLogoFirst ? "rb-flex rb-w-full rb-flex-col rb-items-start rb-justify-end rb-gap-8 rb-md-flex-row rb-md-items-end" : "rb-flex rb-w-full rb-flex-col rb-items-start rb-justify-between rb-gap-8 rb-md-flex-row rb-md-items-end";
32727
- return joinClasses([options.base ?? baseClass, shouldPlaceLogoFirst ? options.reverseClass ?? "rb-md-flex-row-reverse" : null]);
32728
- }
32729
- };
32730
33645
  const footerLogoClassTransform = {
32731
33646
  id: "layout.footerLogoClass",
32732
33647
  kind: "string",
32733
33648
  summary: "Compose split-footer logo wrapper classes from footer.logo controls",
32734
- schema: z.object({
32735
- base: z.string().optional(),
32736
- requireExplicitShow: z.boolean().optional()
32737
- }),
33649
+ schema: z.object({ base: z.string().optional() }),
32738
33650
  run: (value, options) => {
32739
- const logo = asPartialObject(value);
32740
- const align = logo?.align ?? "end";
32741
- const hiddenClass = options.requireExplicitShow ? logo?.showLogo === true ? null : "rb-hidden" : logo?.showLogo === false ? "rb-hidden" : null;
33651
+ const align = asPartialObject(value)?.align ?? "end";
32742
33652
  const selfAlignClass = align === "start" ? "rb-self-start rb-text-left" : align === "center" ? "rb-self-center rb-text-center" : "rb-self-end rb-text-right";
32743
- return joinClasses([
32744
- options.base ?? "footer-logo rb-inline-flex rb-items-center rb-justify-end rb-gap-3 rb-no-underline rb-transition-opacity rb-hover-opacity-80",
32745
- selfAlignClass,
32746
- hiddenClass
32747
- ]);
32748
- }
32749
- };
32750
- const footerLogoMediaClassTransform = {
32751
- id: "layout.footerLogoMediaClass",
32752
- kind: "string",
32753
- summary: "Compose footer logo image classes from size controls",
32754
- schema: z.object({ base: z.string().optional() }),
32755
- run: (_value, options) => {
32756
- return joinClasses([options.base ?? "rb-w-auto"]);
32757
- }
32758
- };
32759
- function shouldShowFooterLogoText(footer) {
32760
- if (!footer) return false;
32761
- const explicit = footer.logo?.showLogoText;
32762
- const legacy = footer.showLogoText === true;
32763
- return explicit === true || explicit === void 0 && legacy;
32764
- }
32765
- const footerLogoTextVisibleTransform = {
32766
- id: "layout.footerLogoTextVisible",
32767
- kind: "formatter",
32768
- summary: "Return whether footer logo text should render",
32769
- run: (value) => {
32770
- return shouldShowFooterLogoText(asPartialObject(value));
33653
+ return joinClasses([options.base ?? "footer-logo rb-inline-flex rb-items-center rb-justify-end rb-gap-3 rb-no-underline rb-transition-opacity rb-hover-opacity-80", selfAlignClass]);
32771
33654
  }
32772
33655
  };
32773
33656
  function extractBackgroundColorToken(background, fallback) {
@@ -32786,13 +33669,12 @@ const layoutTransforms = [
32786
33669
  headerRootStyleTransform,
32787
33670
  headerSectionBackgroundTransform,
32788
33671
  footerRootStyleTransform,
33672
+ footerModuleInkStyleTransform,
33673
+ footerBrandArrangementTransform,
32789
33674
  footerBottomBarClassTransform,
32790
33675
  footerBottomBarContainerClassTransform,
32791
33676
  footerBottomBarStyleTransform,
32792
- footerSplitMainClassTransform,
32793
- footerLogoClassTransform,
32794
- footerLogoMediaClassTransform,
32795
- footerLogoTextVisibleTransform
33677
+ footerLogoClassTransform
32796
33678
  ];
32797
33679
  //#endregion
32798
33680
  //#region ../blocks/src/system/transforms/registry/chromeLogo.ts
@@ -33288,7 +34170,14 @@ const footerNavGroupsLayout = stack({
33288
34170
  }, [text({
33289
34171
  as: "h3",
33290
34172
  className: "rb-label",
33291
- style: textColorStyle("text/70")
34173
+ "data-slot": { $bind: { from: "content.footerRuntime.slots.group-label" } },
34174
+ style: { $bind: {
34175
+ from: "content.footerRuntime.arrangement",
34176
+ transforms: [{
34177
+ id: "layout.footerModuleInkStyle",
34178
+ options: { opacity: 70 }
34179
+ }]
34180
+ } }
33292
34181
  }, when("group.label"), bind("group.label")), stack({
33293
34182
  gap: "sm",
33294
34183
  align: "start",
@@ -33318,6 +34207,14 @@ const footerMailingListBindings = {
33318
34207
  targeting: { $bind: { from: "module.engagement.runtime.targeting" } }
33319
34208
  };
33320
34209
  const footerSpamProtectionBinding = { spamProtectionEnabled: { $bind: { from: "$root.spamProtectionEnabled" } } };
34210
+ const brandMedia = media({ className: "rb-h-10 rb-w-auto" }, when("module.showLogo", { equals: true }), when("content.logo"), bind("content", { transforms: [{
34211
+ id: "layout.chromeLogo",
34212
+ options: { surface: "footer-root" }
34213
+ }] }));
34214
+ const brandTitle = text({
34215
+ as: "strong",
34216
+ className: "footer-logo-text rb-nav-text"
34217
+ }, when("module.showTitle", { equals: true }), bind("site.title", { fallback: "Your Site" }));
33321
34218
  const brandLogo = link({
33322
34219
  href: "/",
33323
34220
  className: { $bind: {
@@ -33328,20 +34225,39 @@ const brandLogo = link({
33328
34225
  }],
33329
34226
  fallback: "footer-logo rb-inline-flex rb-items-center rb-gap-3 rb-no-underline"
33330
34227
  } }
33331
- }, [media({ className: { $bind: {
33332
- from: "$root.theme.footer.logo",
33333
- transforms: [{
33334
- id: "layout.footerLogoMediaClass",
33335
- options: { base: "rb-h-10 rb-w-auto" }
33336
- }],
33337
- fallback: "rb-h-10 rb-w-auto"
33338
- } } }, when("module.showLogo", { equals: true }), when("content.logo"), bind("content", { transforms: [{
33339
- id: "layout.chromeLogo",
33340
- options: { surface: "footer-root" }
33341
- }] })), text({
33342
- as: "strong",
33343
- className: "footer-logo-text rb-nav-text"
33344
- }, when("module.showTitle", { equals: true }), bind("site.title", { fallback: "Your Site" }))], when("module.kind", { equals: "brand" }));
34228
+ }, [brandMedia, brandTitle], (node) => ({
34229
+ ...node,
34230
+ $when: {
34231
+ when: {
34232
+ from: "module",
34233
+ transforms: [{ id: "layout.footerBrandArrangement" }]
34234
+ },
34235
+ equals: "row"
34236
+ }
34237
+ }));
34238
+ const centredBrand = stack({
34239
+ gap: "md",
34240
+ align: "center"
34241
+ }, [link({
34242
+ href: "/",
34243
+ "data-slot": { $bind: { from: "module.slots.media" } },
34244
+ className: "footer-logo rb-inline-flex rb-items-center rb-no-underline"
34245
+ }, [brandMedia], when("module.slots.media")), {
34246
+ ...brandTitle,
34247
+ props: {
34248
+ ...brandTitle.props,
34249
+ "data-slot": { $bind: { from: "module.slots.heading" } }
34250
+ }
34251
+ }], (node) => ({
34252
+ ...node,
34253
+ $when: {
34254
+ when: {
34255
+ from: "module",
34256
+ transforms: [{ id: "layout.footerBrandArrangement" }]
34257
+ },
34258
+ equals: "centred"
34259
+ }
34260
+ }));
33345
34261
  const navigation = stack({
33346
34262
  gap: "md",
33347
34263
  className: "rb-w-full"
@@ -33366,14 +34282,18 @@ const address = text({
33366
34282
  }, when("module.kind", { equals: "business-address" }), bind("module.address"));
33367
34283
  const contact = stack({
33368
34284
  gap: "sm",
33369
- className: "rb-items-start"
34285
+ className: { $bind: {
34286
+ from: "module.contactClassName",
34287
+ fallback: "rb-items-start"
34288
+ } }
33370
34289
  }, [link({
33371
34290
  href: { $bind: { from: "contactLink.href" } },
33372
34291
  className: "rb-nav-text rb-break-words transition-theme-standard"
33373
34292
  }, [text({ as: "span" }, bind("contactLink.label"))], repeat("module.contactLinks", "contactLink"))], when("module.kind", { equals: "contact" }));
33374
34293
  const hours = stack({
33375
34294
  gap: "sm",
33376
- className: "rb-w-full"
34295
+ className: "rb-w-full",
34296
+ "data-slot": { $bind: { from: "module.slots.schedule" } }
33377
34297
  }, [inline({ className: "rb-flex rb-w-full rb-justify-between rb-gap-4" }, [text({
33378
34298
  as: "span",
33379
34299
  className: "rb-label"
@@ -33384,7 +34304,10 @@ const hours = stack({
33384
34304
  as: "p",
33385
34305
  className: "rb-caption rb-opacity-70"
33386
34306
  }, bind("module.timeZone"), when("module.timeZone"))], when("module.kind", { equals: "opening-hours" }));
33387
- const socials = inline({ className: "rb-footer-socials" }, [link({
34307
+ const socials = inline({
34308
+ className: "rb-footer-socials",
34309
+ "data-slot": { $bind: { from: "module.slots.social" } }
34310
+ }, [link({
33388
34311
  href: { $bind: { from: "social.href" } },
33389
34312
  target: "_blank",
33390
34313
  rel: "noreferrer noopener",
@@ -33393,7 +34316,14 @@ const socials = inline({ className: "rb-footer-socials" }, [link({
33393
34316
  }, [icon({ className: "rb-footer-social-icon" }, bind("social.icon"), when("social.icon")), text({ as: "span" }, bind("social.label"), when("social.icon", { equals: null }))], repeat("module.socialLinks", "social"))], when("module.kind", { equals: "social-links" }));
33394
34317
  const authoredCopy = richText({
33395
34318
  className: "rb-prose rb-prose-sm rb-max-w-none",
33396
- style: textColorStyle("text/80")
34319
+ "data-slot": { $bind: { from: "module.slots.copy" } },
34320
+ style: { $bind: {
34321
+ from: "content.footerRuntime.arrangement",
34322
+ transforms: [{
34323
+ id: "layout.footerModuleInkStyle",
34324
+ options: { opacity: 80 }
34325
+ }]
34326
+ } }
33397
34327
  }, when("module.content"), bind("module.content", { transforms: [{
33398
34328
  id: "content.interpolateRichTextTokens",
33399
34329
  options: { tokens: ["year", "site_name"] }
@@ -33431,27 +34361,44 @@ const platformAttribution = el("div", {
33431
34361
  ], when("module.kind", { equals: "attribution" }));
33432
34362
  const footerGroup = stack({
33433
34363
  gap: "md",
33434
- align: "stretch",
34364
+ align: { $bind: {
34365
+ from: "group.align",
34366
+ fallback: "stretch"
34367
+ } },
33435
34368
  className: { $bind: {
33436
34369
  from: "group.className",
33437
34370
  fallback: "rb-min-w-0"
33438
34371
  } },
34372
+ "data-slot": { $bind: { from: "group.slot" } },
33439
34373
  "data-footer-group": { $bind: { from: "group.kind" } }
33440
34374
  }, [stack({
33441
34375
  gap: "md",
33442
- align: "start",
34376
+ align: { $bind: {
34377
+ from: "module.align",
34378
+ fallback: "start"
34379
+ } },
34380
+ className: { $bind: { from: "module.className" } },
33443
34381
  "data-preview-footer-module-id": { $bind: { from: "module.id" } }
33444
34382
  }, [
33445
34383
  text({
33446
34384
  as: "h2",
33447
34385
  className: "rb-label",
33448
- style: textColorStyle("text/70")
34386
+ "data-slot": { $bind: { from: "module.slots.group-label" } },
34387
+ style: { $bind: {
34388
+ from: "content.footerRuntime.arrangement",
34389
+ transforms: [{
34390
+ id: "layout.footerModuleInkStyle",
34391
+ options: { opacity: 70 }
34392
+ }]
34393
+ } }
33449
34394
  }, bind("module.heading"), when("module.heading")),
33450
34395
  brandLogo,
34396
+ centredBrand,
33451
34397
  navigation,
33452
34398
  stack({
33453
34399
  gap: "sm",
33454
- className: "rb-w-full"
34400
+ className: "rb-w-full",
34401
+ "data-slot": { $bind: { from: "module.slots.navigation" } }
33455
34402
  }, [legalNavigation], when("module.kind", { equals: "legal-navigation" })),
33456
34403
  address,
33457
34404
  contact,
@@ -33464,10 +34411,12 @@ const footerGroup = stack({
33464
34411
  ], repeat("group.modules", "module"))], repeat("region.groups", "group"));
33465
34412
  const footerMainRegion = stack({
33466
34413
  className: { $bind: { from: "region.className" } },
34414
+ "data-slot": { $bind: { from: "region.slot" } },
33467
34415
  "data-footer-region": { $bind: { from: "region.kind" } }
33468
34416
  }, [footerGroup], when("region.kind", { equals: "main" }), repeat("content.footerRuntime.regions", "region"));
33469
34417
  const footerEngagementRegion = stack({
33470
34418
  className: { $bind: { from: "region.className" } },
34419
+ "data-slot": { $bind: { from: "region.slot" } },
33471
34420
  "data-footer-region": "engagement-row"
33472
34421
  }, [footerGroup], when("region.kind", { equals: "engagement-row" }), repeat("content.footerRuntime.regions", "region"));
33473
34422
  const footerBottomRegion = stack({ className: { $bind: {
@@ -33484,6 +34433,7 @@ const footerBottomRegion = stack({ className: { $bind: {
33484
34433
  from: "$root.theme.footer",
33485
34434
  transforms: [{ id: "layout.footerBottomBarStyle" }]
33486
34435
  } },
34436
+ "data-slot": { $bind: { from: "region.slot" } },
33487
34437
  "data-footer-region": "bottom"
33488
34438
  }, [footerGroup])], when("region.kind", { equals: "bottom" }), repeat("content.footerRuntime.regions", "region"));
33489
34439
  const siteFooterBlockDefinition = { manifest: createBlockManifest({
@@ -33505,6 +34455,7 @@ const siteFooterBlockDefinition = { manifest: createBlockManifest({
33505
34455
  transforms: [{ id: "layout.footerRootStyle" }],
33506
34456
  fallback: mergeStyles(backgroundColorStyle("surface"), surfaceForegroundStyle({ text: "rgb(var(--tb-text))" }), borderColorStyle("border"))
33507
34457
  } },
34458
+ "data-arrangement": { $bind: { from: "content.footerRuntime.arrangementHook" } },
33508
34459
  "data-footer-membership": { $bind: { from: "content.footerRuntime.membershipKey" } }
33509
34460
  }, [
33510
34461
  footerEngagementRegion,
@@ -35106,17 +36057,30 @@ const mediaTextBlockDefinition = { manifest: createBlockManifest({
35106
36057
  }],
35107
36058
  fallback: ""
35108
36059
  } };
35109
- const copyHeading = el("div", { className: titleClassNameFromAlignment }, [text({
36060
+ const copyHeading = el("div", {
36061
+ className: titleClassNameFromAlignment,
36062
+ ...lookSlot("head")
36063
+ }, [text({
35110
36064
  as: "p",
35111
- className: eyebrowClassName("rb-eyebrow heading-eyebrow")
35112
- }, when("content.eyebrow"), bind("content.eyebrow")), text({ as: "h2" }, bind("content.title"))], when("content.title"));
35113
- const defaultTextColumn = el("div", {}, [styledCard([richText({ className: "rb-prose rb-max-w-none" }, bind("content.text"))], mediaTextCardOptions, when("content.wrapTextInCard")), richText({ className: "rb-prose rb-max-w-none" }, when("content.wrapTextInCard", { not: true }), bind("content.text"))]);
35114
- const bioTextColumn = el("div", { className: "rb-flex rb-h-full rb-w-full rb-max-w-prose rb-flex-col rb-justify-center rb-gap-5" }, [
35115
- copyHeading,
35116
- styledCard([richText({ className: bodyClassNameFromAlignment }, bind("content.text"))], mediaTextCardOptions, when("content.wrapTextInCard")),
35117
- richText({ className: bodyClassNameFromAlignment }, when("content.wrapTextInCard", { not: true }), bind("content.text"))
35118
- ]);
36065
+ className: eyebrowClassName("rb-eyebrow heading-eyebrow"),
36066
+ ...lookSlot("eyebrow")
36067
+ }, when("content.eyebrow"), bind("content.eyebrow")), text({
36068
+ as: "h2",
36069
+ ...lookSlot("heading")
36070
+ }, bind("content.title"))], when("content.title"));
36071
+ const textContentNodes = (className) => {
36072
+ const props = {
36073
+ className,
36074
+ ...lookSlot("intro"),
36075
+ leadParagraphSlot: { $bind: { from: "content._lookSlots.lede" } },
36076
+ lookSlots: { $bind: { from: "content._lookSlots" } }
36077
+ };
36078
+ return [styledCard([richText(props, bind("content.text"))], mediaTextCardOptions, when("content.wrapTextInCard")), richText(props, when("content.wrapTextInCard", { not: true }), bind("content.text"))];
36079
+ };
36080
+ const defaultTextColumn = el("div", {}, textContentNodes("rb-prose rb-max-w-none"));
36081
+ const bioTextColumn = el("div", { className: "rb-flex rb-h-full rb-w-full rb-max-w-prose rb-flex-col rb-justify-center rb-gap-5" }, [copyHeading, ...textContentNodes(bodyClassNameFromAlignment)]);
35119
36082
  const defaultImageCommonProps = {
36083
+ ...lookSlot("photo"),
35120
36084
  className: { $bind: {
35121
36085
  from: "content.imageShape",
35122
36086
  transforms: [{
@@ -35156,6 +36120,7 @@ const mediaTextBlockDefinition = { manifest: createBlockManifest({
35156
36120
  slidesToShow: 1
35157
36121
  }, [media(defaultImageCommonProps, bind("item.image"), repeat("content.images", "item"))]);
35158
36122
  const defaultImagesLayout = el("div", {}, [responsiveTwoColumn({
36123
+ lookSlots: true,
35159
36124
  image: el("div", {}, [el("div", {}, [defaultSingleImage], whenImagesLength(1)), el("div", {}, [defaultCarouselImages], whenImagesLength(1, { not: true }))]),
35160
36125
  text: defaultTextColumn,
35161
36126
  ratioFrom: "content.ratio",
@@ -35167,6 +36132,7 @@ const mediaTextBlockDefinition = { manifest: createBlockManifest({
35167
36132
  textWrapperClassName: "rb-w-full rb-min-w-0 rb-flex-1"
35168
36133
  })], whenImagesLength(0, { not: true }));
35169
36134
  const bioImagesLayout = el("div", {}, [responsiveTwoColumn({
36135
+ lookSlots: true,
35170
36136
  image: el("div", {}, [el("div", {}, [defaultSingleImage], whenImagesLength(1)), el("div", {}, [defaultCarouselImages], whenImagesLength(1, { not: true }))]),
35171
36137
  text: bioTextColumn,
35172
36138
  ratioFrom: "content.ratio",
@@ -35177,15 +36143,15 @@ const mediaTextBlockDefinition = { manifest: createBlockManifest({
35177
36143
  imageWrapperClassName: "rb-w-full rb-shrink-0",
35178
36144
  textWrapperClassName: "rb-w-full rb-min-w-0 rb-flex-1 rb-self-stretch"
35179
36145
  })], whenImagesLength(0, { not: true }));
35180
- const defaultTextOnlyLayout = el("div", {}, [styledCard([richText({ className: "rb-prose rb-max-w-none" }, bind("content.text"))], mediaTextCardOptions, when("content.wrapTextInCard")), richText({ className: "rb-prose rb-max-w-none" }, when("content.wrapTextInCard", { not: true }), bind("content.text"))], whenImagesLength(0));
35181
- const bioTextOnlyLayout = el("div", { className: "rb-flex rb-w-full rb-max-w-prose rb-flex-col rb-gap-5" }, [
35182
- text({
35183
- as: "h2",
35184
- className: titleClassNameFromAlignment
35185
- }, when("content.title"), bind("content.title")),
35186
- styledCard([richText({ className: bodyClassNameFromAlignment }, bind("content.text"))], mediaTextCardOptions, when("content.wrapTextInCard")),
35187
- richText({ className: bodyClassNameFromAlignment }, when("content.wrapTextInCard", { not: true }), bind("content.text"))
35188
- ], whenImagesLength(0));
36146
+ const defaultTextOnlyLayout = el("div", lookSlot("copy"), textContentNodes("rb-prose rb-max-w-none"), whenImagesLength(0));
36147
+ const bioTextOnlyLayout = el("div", {
36148
+ className: "rb-flex rb-w-full rb-max-w-prose rb-flex-col rb-gap-5",
36149
+ ...lookSlot("copy")
36150
+ }, [text({
36151
+ as: "h2",
36152
+ className: titleClassNameFromAlignment,
36153
+ ...lookSlot("heading")
36154
+ }, when("content.title"), bind("content.title")), ...textContentNodes(bodyClassNameFromAlignment)], whenImagesLength(0));
35189
36155
  const defaultInner = el("div", {}, [defaultImagesLayout, defaultTextOnlyLayout]);
35190
36156
  const bioInner = el("div", {}, [bioImagesLayout, bioTextOnlyLayout]);
35191
36157
  const defaultLayout = styledSection({
@@ -35209,9 +36175,31 @@ const mediaTextBlockDefinition = { manifest: createBlockManifest({
35209
36175
  }),
35210
36176
  baseClass: "",
35211
36177
  spacing: "medium"
36178
+ }),
36179
+ "circle-beside": styledSection({
36180
+ baseClass: "",
36181
+ spacing: "medium",
36182
+ children: styledContainer({ children: el("div", lookSlot("frame"), [el("div", lookSlot("media"), [
36183
+ el("div", {}, [when("content.images[0].image")(defaultSingleImage)], whenImagesLength(1)),
36184
+ el("div", {}, [el("div", {}, [defaultCarouselImages], whenImagesLength(1, { not: true }))], whenImagesLength(0, { not: true })),
36185
+ el("div", {}, [when("content.images[0].image")(defaultSingleImage)], whenImagesLength(0))
36186
+ ]), el("div", lookSlot("copy"), [el("div", lookSlot("head"), [text({
36187
+ as: "p",
36188
+ className: eyebrowClassName("rb-eyebrow heading-eyebrow"),
36189
+ ...lookSlot("eyebrow")
36190
+ }, when("content.eyebrow"), bind("content.eyebrow")), text({
36191
+ as: "h2",
36192
+ ...lookSlot("heading")
36193
+ }, bind("content.title"), when("content.title", { authoringPresence: {
36194
+ kind: "recover-empty-when-active",
36195
+ placeholder: "Add heading"
36196
+ } }))]), defaultTextColumn])]) })
35212
36197
  })
35213
36198
  },
35214
- variantMeaning: { kind: "arrangement" },
36199
+ variantMeaning: {
36200
+ kind: "arrangement",
36201
+ lookOnlyKeys: ["circle-beside"]
36202
+ },
35215
36203
  defaultVariant: "default",
35216
36204
  variantOptions: {
35217
36205
  default: { label: "Default" },
@@ -35692,14 +36680,6 @@ const weeklySlotAvailabilityBlockDefinition = {
35692
36680
  } }
35693
36681
  };
35694
36682
  //#endregion
35695
- //#region ../blocks/src/lib/media.ts
35696
- const PUBLIC_DOWNLOAD_MEDIA_TYPES = [
35697
- "document",
35698
- "spreadsheet",
35699
- "archive",
35700
- "audio"
35701
- ];
35702
- //#endregion
35703
36683
  //#region ../blocks/src/system/manifest/richTextSchema.ts
35704
36684
  /**
35705
36685
  * Shared Rich Text Schema
@@ -36135,7 +37115,7 @@ const publicEventBaseSchema = z.object({
36135
37115
  content: z.object({ body: RichTextDocSchema.nullable().optional() }).optional(),
36136
37116
  presentation: z.object({
36137
37117
  summary: z.string().nullable().optional(),
36138
- image: mediaSchema.nullable().optional()
37118
+ image: runtimeMediaSchema.nullable().optional()
36139
37119
  }).optional(),
36140
37120
  slug: z.string(),
36141
37121
  path: z.string().nullable(),
@@ -36315,24 +37295,6 @@ const emptyStateField = {
36315
37295
  ui: { intent: "display" }
36316
37296
  };
36317
37297
  /**
36318
- * Section heading and description fields
36319
- */
36320
- const sectionHeaderFields = (defaultHeading) => [{
36321
- id: "heading",
36322
- type: "text",
36323
- label: "Heading",
36324
- description: "Main heading for the events section",
36325
- required: false,
36326
- multiline: false,
36327
- defaultValue: defaultHeading
36328
- }, {
36329
- id: "description",
36330
- type: "richText",
36331
- label: "Description",
36332
- description: "Optional introductory text",
36333
- required: false
36334
- }];
36335
- /**
36336
37298
  * Layout selection field with grid/stack options
36337
37299
  */
36338
37300
  const layoutField = {
@@ -36445,31 +37407,6 @@ function normalizeEventStaffMemberId(value) {
36445
37407
  return trimmed ? trimmed : null;
36446
37408
  }
36447
37409
  //#endregion
36448
- //#region ../blocks/src/system/blocks/events/shared/layout.ts
36449
- const recoverEmptyHeadingWhenActive = {
36450
- kind: "recover-empty-when-active",
36451
- placeholder: "Add heading"
36452
- };
36453
- const recoverEmptyDescriptionWhenActive = {
36454
- kind: "recover-empty-when-active",
36455
- placeholder: "Add description"
36456
- };
36457
- function eventSectionHeaderLayoutNodes(options = {}) {
36458
- const headingNode = text({
36459
- as: "h2",
36460
- ...lookSlot("heading")
36461
- }, bind("content.heading"), when("content.heading", { authoringPresence: recoverEmptyHeadingWhenActive }));
36462
- const descriptionNode = richText({
36463
- className: "rb-prose rb-max-w-none",
36464
- ...lookSlot("intro")
36465
- }, bind("content.description"), when("content.description", { authoringPresence: recoverEmptyDescriptionWhenActive }));
36466
- if (options.splitClassName) return [el("div", {
36467
- className: options.splitClassName,
36468
- ...lookSlot("head")
36469
- }, [headingNode, descriptionNode])];
36470
- return [headingNode, descriptionNode];
36471
- }
36472
- //#endregion
36473
37410
  //#region ../blocks/src/system/blocks/shop.shared.ts
36474
37411
  /**
36475
37412
  * Public pass product for shop display
@@ -36894,19 +37831,14 @@ function buildCalendarViewport(input) {
36894
37831
  *
36895
37832
  * Sites don't store a locale, and every public word around a date is English,
36896
37833
  * so the only open question is which English conventions to follow: day or
36897
- * month first, and a 24 or 12-hour clock. The site's time zone is the one
37834
+ * month first. The site's time zone is the one
36898
37835
  * fact every site carries about where it is. It is the site's, never an
36899
37836
  * event's: a venue left at UTC must not turn a UK site's dates American.
36900
37837
  * Anywhere this can't place (UTC, the Americas, Asia) keeps US English, which
36901
37838
  * is what these helpers wrote before sites were placed at all.
36902
37839
  */
36903
37840
  function eventDateLocale(siteTimeZone) {
36904
- if (!siteTimeZone) return "en-US";
36905
- if (siteTimeZone === "Europe/Dublin") return "en-IE";
36906
- if (siteTimeZone.startsWith("Europe/")) return "en-GB";
36907
- if (siteTimeZone.startsWith("Australia/")) return "en-AU";
36908
- if (siteTimeZone === "Pacific/Auckland" || siteTimeZone === "Pacific/Chatham") return "en-NZ";
36909
- return "en-US";
37841
+ return inferSiteDateLocale(siteTimeZone);
36910
37842
  }
36911
37843
  function formatEventCompactDateRail(isoTimestamp, options, letterCase = "capitals") {
36912
37844
  const locale = options?.locale ?? "en-US";
@@ -38614,7 +39546,7 @@ const eventSpotlightBlockDefinition = {
38614
39546
  ],
38615
39547
  icon: "Star",
38616
39548
  layout: [styledSection({
38617
- children: sectionContainer([...eventSectionHeaderLayoutNodes(), el("event-spotlight", {
39549
+ children: sectionContainer([...sectionHeaderLayoutNodes(), el("event-spotlight", {
38618
39550
  events: { $bind: { from: "data.events" } },
38619
39551
  layout: { $bind: {
38620
39552
  from: "content.layout",
@@ -38670,52 +39602,6 @@ const eventSpotlightBlockDefinition = {
38670
39602
  } }
38671
39603
  };
38672
39604
  //#endregion
38673
- //#region ../blocks/src/system/runtime/lookSurfaces.ts
38674
- const isPlainObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
38675
- const lookListPresentationSchemaShape = {
38676
- sectionAction: z.object({
38677
- label: z.string(),
38678
- href: z.string()
38679
- }).optional(),
38680
- actionSize: z.enum([
38681
- "sm",
38682
- "md",
38683
- "lg"
38684
- ]).optional(),
38685
- itemActionStyle: z.enum(["button", "link"]).optional(),
38686
- itemRoles: z.object({
38687
- container: z.enum([
38688
- "card",
38689
- "statement",
38690
- "highlight"
38691
- ]).optional(),
38692
- items: z.enum([
38693
- "card",
38694
- "statement",
38695
- "highlight"
38696
- ]).optional(),
38697
- at: z.partialRecord(z.enum([
38698
- "first",
38699
- "last",
38700
- "middle",
38701
- "odd",
38702
- "even"
38703
- ]), z.enum([
38704
- "card",
38705
- "statement",
38706
- "highlight"
38707
- ])).optional()
38708
- }).optional(),
38709
- roleSurfaces: z.record(z.enum([
38710
- "card",
38711
- "statement",
38712
- "highlight"
38713
- ]), z.custom((value) => isPlainObject(value) && (value.kind === "inherit" || value.kind === "owned"))).optional(),
38714
- panelHeading: z.string().optional(),
38715
- lookSlots: z.partialRecord(z.enum(arrangementSlotNames), z.enum(arrangementSlotNames)).optional(),
38716
- itemSurfaces: z.record(z.string(), z.custom((value) => isPlainObject(value) && (value.kind === "inherit" || value.kind === "owned"))).optional()
38717
- };
38718
- //#endregion
38719
39605
  //#region ../blocks/src/system/blocks/events/shared/eventSelection.ts
38720
39606
  /** Invalid saved selections fail closed rather than widening discovery. */
38721
39607
  function resolveEventSelection(mode, value) {
@@ -39490,7 +40376,7 @@ const eventListingBlockDefinition = {
39490
40376
  children: styledContainer({
39491
40377
  rootType: "stack",
39492
40378
  rootProps: { gap: "lg" },
39493
- children: [...eventSectionHeaderLayoutNodes(), el("event-listing", withApiBindings({
40379
+ children: [...sectionHeaderLayoutNodes(), el("event-listing", withApiBindings({
39494
40380
  readAuthority: { $bind: { from: "$root.readAuthority" } },
39495
40381
  events: { $bind: { from: "data.events" } },
39496
40382
  stage: { $bind: {
@@ -39930,7 +40816,7 @@ const eventCalendarLayout = [styledSection({
39930
40816
  gap: "lg",
39931
40817
  ...lookSlot("layout")
39932
40818
  },
39933
- children: [...eventSectionHeaderLayoutNodes({ splitClassName: "event-section-head event-section-head--split" }), el("event-calendar", withApiBindings({
40819
+ children: [...sectionHeaderLayoutNodes({ splitClassName: "event-section-head event-section-head--split" }), el("event-calendar", withApiBindings({
39934
40820
  readAuthority: { $bind: { from: "$root.readAuthority" } },
39935
40821
  events: { $bind: { from: "data.events" } },
39936
40822
  effectiveListArrangementKey: { $bind: { from: "$root.effectiveListArrangementKey" } },
@@ -41886,6 +42772,511 @@ const embedBlockDefinition = {
41886
42772
  } }
41887
42773
  };
41888
42774
  //#endregion
42775
+ //#region ../blocks/src/system/blocks/image-gallery/fields.ts
42776
+ const imageGalleryFields = parseFieldDefinitions([
42777
+ ...sectionHeaderFields(void 0, "Intro"),
42778
+ {
42779
+ id: "images",
42780
+ type: "repeater",
42781
+ label: "Images",
42782
+ itemLabel: "Image",
42783
+ minItems: 0,
42784
+ maxItems: 24,
42785
+ ui: {
42786
+ repeaterPreset: "thumbnailGrid",
42787
+ thumbnailField: "image",
42788
+ thumbnailAltField: "caption",
42789
+ thumbnailLabelField: "caption",
42790
+ thumbnailCardDensity: "compact"
42791
+ },
42792
+ schema: { fields: [{
42793
+ id: "image",
42794
+ type: "media",
42795
+ label: "Image",
42796
+ required: true,
42797
+ mediaKinds: ["image"]
42798
+ }, {
42799
+ id: "caption",
42800
+ type: "text",
42801
+ label: "Caption",
42802
+ description: "Optional caption displayed below the image and used as the editor card label",
42803
+ maxLength: 200
42804
+ }] }
42805
+ },
42806
+ {
42807
+ id: "fullBleed",
42808
+ type: "boolean",
42809
+ label: "Full bleed",
42810
+ description: "Extend the gallery edge-to-edge by removing section side padding and container max-width.",
42811
+ defaultValue: false,
42812
+ ui: {
42813
+ intent: "display",
42814
+ visibleWhen: {
42815
+ field: "variant",
42816
+ notIn: ["marquee"]
42817
+ }
42818
+ }
42819
+ },
42820
+ {
42821
+ id: "aspectRatio",
42822
+ type: "select",
42823
+ label: "Aspect ratio",
42824
+ description: "Crop images to a consistent aspect ratio.",
42825
+ defaultValue: "1/1",
42826
+ options: [
42827
+ {
42828
+ value: "auto",
42829
+ label: "Original"
42830
+ },
42831
+ {
42832
+ value: "1/1",
42833
+ label: "1:1 (Square)"
42834
+ },
42835
+ {
42836
+ value: "4/3",
42837
+ label: "4:3 (Standard)"
42838
+ },
42839
+ {
42840
+ value: "16/9",
42841
+ label: "16:9 (Widescreen)"
42842
+ },
42843
+ {
42844
+ value: "3/2",
42845
+ label: "3:2 (Classic)"
42846
+ },
42847
+ {
42848
+ value: "3/4",
42849
+ label: "3:4 (Portrait)"
42850
+ }
42851
+ ],
42852
+ ui: {
42853
+ intent: "display",
42854
+ visibleWhen: {
42855
+ field: "variant",
42856
+ notIn: ["masonry", "marquee"]
42857
+ }
42858
+ }
42859
+ },
42860
+ {
42861
+ id: "slidesToShow",
42862
+ type: "select",
42863
+ label: "Images per view (mobile)",
42864
+ description: "Number of images visible at once on small screens.",
42865
+ defaultValue: "1",
42866
+ options: [
42867
+ {
42868
+ value: "1",
42869
+ label: "One at a time"
42870
+ },
42871
+ {
42872
+ value: "2",
42873
+ label: "Two at a time"
42874
+ },
42875
+ {
42876
+ value: "3",
42877
+ label: "Three at a time"
42878
+ }
42879
+ ],
42880
+ ui: {
42881
+ intent: "display",
42882
+ visibleWhen: {
42883
+ field: "variant",
42884
+ equals: "carousel"
42885
+ }
42886
+ }
42887
+ },
42888
+ {
42889
+ id: "slidesToShowTablet",
42890
+ type: "select",
42891
+ label: "Images per view (tablet)",
42892
+ description: "Number of images visible on medium screens.",
42893
+ options: [
42894
+ {
42895
+ value: "",
42896
+ label: "Same as mobile"
42897
+ },
42898
+ {
42899
+ value: "1",
42900
+ label: "One at a time"
42901
+ },
42902
+ {
42903
+ value: "2",
42904
+ label: "Two at a time"
42905
+ },
42906
+ {
42907
+ value: "3",
42908
+ label: "Three at a time"
42909
+ }
42910
+ ],
42911
+ ui: {
42912
+ intent: "display",
42913
+ visibleWhen: {
42914
+ field: "variant",
42915
+ equals: "carousel"
42916
+ }
42917
+ }
42918
+ },
42919
+ {
42920
+ id: "slidesToShowDesktop",
42921
+ type: "select",
42922
+ label: "Images per view (desktop)",
42923
+ description: "Number of images visible on large screens.",
42924
+ options: [
42925
+ {
42926
+ value: "",
42927
+ label: "Same as tablet"
42928
+ },
42929
+ {
42930
+ value: "1",
42931
+ label: "One at a time"
42932
+ },
42933
+ {
42934
+ value: "2",
42935
+ label: "Two at a time"
42936
+ },
42937
+ {
42938
+ value: "3",
42939
+ label: "Three at a time"
42940
+ }
42941
+ ],
42942
+ ui: {
42943
+ intent: "display",
42944
+ visibleWhen: {
42945
+ field: "variant",
42946
+ equals: "carousel"
42947
+ }
42948
+ }
42949
+ },
42950
+ {
42951
+ id: "transition",
42952
+ type: "select",
42953
+ label: "Transition",
42954
+ description: "Animation style between slides.",
42955
+ defaultValue: "slide",
42956
+ options: [{
42957
+ value: "slide",
42958
+ label: "Slide"
42959
+ }, {
42960
+ value: "fade",
42961
+ label: "Fade"
42962
+ }],
42963
+ ui: {
42964
+ intent: "display",
42965
+ visibleWhen: {
42966
+ field: "variant",
42967
+ equals: "carousel"
42968
+ }
42969
+ }
42970
+ },
42971
+ {
42972
+ id: "showControls",
42973
+ type: "boolean",
42974
+ label: "Show arrows",
42975
+ defaultValue: true,
42976
+ ui: {
42977
+ intent: "behavior",
42978
+ visibleWhen: {
42979
+ field: "variant",
42980
+ equals: "carousel"
42981
+ }
42982
+ }
42983
+ },
42984
+ {
42985
+ id: "showDots",
42986
+ type: "boolean",
42987
+ label: "Show dots",
42988
+ defaultValue: false,
42989
+ ui: {
42990
+ intent: "behavior",
42991
+ visibleWhen: {
42992
+ field: "variant",
42993
+ equals: "carousel"
42994
+ }
42995
+ }
42996
+ },
42997
+ {
42998
+ id: "autoplay",
42999
+ type: "boolean",
43000
+ label: "Autoplay",
43001
+ defaultValue: false,
43002
+ ui: {
43003
+ intent: "behavior",
43004
+ visibleWhen: {
43005
+ field: "variant",
43006
+ equals: "carousel"
43007
+ }
43008
+ }
43009
+ },
43010
+ {
43011
+ id: "autoplayDelay",
43012
+ type: "select",
43013
+ label: "Autoplay delay",
43014
+ defaultValue: "5000",
43015
+ options: [
43016
+ {
43017
+ value: "3000",
43018
+ label: "3 seconds"
43019
+ },
43020
+ {
43021
+ value: "5000",
43022
+ label: "5 seconds"
43023
+ },
43024
+ {
43025
+ value: "7000",
43026
+ label: "7 seconds"
43027
+ },
43028
+ {
43029
+ value: "10000",
43030
+ label: "10 seconds"
43031
+ }
43032
+ ],
43033
+ ui: {
43034
+ intent: "behavior",
43035
+ visibleWhen: {
43036
+ field: "variant",
43037
+ equals: "carousel"
43038
+ }
43039
+ }
43040
+ },
43041
+ {
43042
+ id: "arrowVisibility",
43043
+ type: "select",
43044
+ label: "Arrow visibility",
43045
+ defaultValue: "always",
43046
+ options: [{
43047
+ value: "always",
43048
+ label: "Always visible"
43049
+ }, {
43050
+ value: "hover",
43051
+ label: "Show on hover"
43052
+ }],
43053
+ ui: {
43054
+ intent: "behavior",
43055
+ visibleWhen: {
43056
+ field: "variant",
43057
+ equals: "carousel"
43058
+ }
43059
+ }
43060
+ },
43061
+ {
43062
+ id: "loop",
43063
+ type: "boolean",
43064
+ label: "Loop slides",
43065
+ defaultValue: true,
43066
+ ui: {
43067
+ intent: "behavior",
43068
+ visibleWhen: {
43069
+ field: "variant",
43070
+ equals: "carousel"
43071
+ }
43072
+ }
43073
+ },
43074
+ {
43075
+ id: "marqueeDirection",
43076
+ type: "select",
43077
+ label: "Scroll direction",
43078
+ options: [{
43079
+ value: "left",
43080
+ label: "Left"
43081
+ }, {
43082
+ value: "right",
43083
+ label: "Right"
43084
+ }],
43085
+ defaultValue: "left",
43086
+ ui: {
43087
+ intent: "display",
43088
+ visibleWhen: {
43089
+ field: "variant",
43090
+ equals: "marquee"
43091
+ }
43092
+ }
43093
+ },
43094
+ {
43095
+ id: "marqueeSpeed",
43096
+ type: "select",
43097
+ label: "Scroll speed",
43098
+ options: [
43099
+ {
43100
+ value: "slow",
43101
+ label: "Slow (60s)"
43102
+ },
43103
+ {
43104
+ value: "medium",
43105
+ label: "Medium (40s)"
43106
+ },
43107
+ {
43108
+ value: "fast",
43109
+ label: "Fast (20s)"
43110
+ }
43111
+ ],
43112
+ defaultValue: "medium",
43113
+ ui: {
43114
+ intent: "display",
43115
+ visibleWhen: {
43116
+ field: "variant",
43117
+ equals: "marquee"
43118
+ }
43119
+ }
43120
+ },
43121
+ {
43122
+ id: "marqueePauseOnHover",
43123
+ type: "boolean",
43124
+ label: "Pause on hover",
43125
+ defaultValue: true,
43126
+ ui: {
43127
+ intent: "behavior",
43128
+ visibleWhen: {
43129
+ field: "variant",
43130
+ equals: "marquee"
43131
+ }
43132
+ }
43133
+ },
43134
+ {
43135
+ id: "marqueeImageSize",
43136
+ type: "select",
43137
+ label: "Image size",
43138
+ options: [
43139
+ {
43140
+ value: "sm",
43141
+ label: "Small (200px)"
43142
+ },
43143
+ {
43144
+ value: "md",
43145
+ label: "Medium (256px)"
43146
+ },
43147
+ {
43148
+ value: "lg",
43149
+ label: "Large (320px)"
43150
+ },
43151
+ {
43152
+ value: "xl",
43153
+ label: "Extra large (400px)"
43154
+ }
43155
+ ],
43156
+ defaultValue: "md",
43157
+ ui: {
43158
+ intent: "display",
43159
+ visibleWhen: {
43160
+ field: "variant",
43161
+ equals: "marquee"
43162
+ }
43163
+ }
43164
+ },
43165
+ {
43166
+ id: "imageFilter",
43167
+ type: "select",
43168
+ label: "Image filter",
43169
+ options: [
43170
+ {
43171
+ value: "none",
43172
+ label: "None"
43173
+ },
43174
+ {
43175
+ value: "grayscale",
43176
+ label: "Grayscale"
43177
+ },
43178
+ {
43179
+ value: "grayscale-hover-reveal",
43180
+ label: "Grayscale (color on hover)"
43181
+ },
43182
+ {
43183
+ value: "sepia",
43184
+ label: "Sepia"
43185
+ }
43186
+ ],
43187
+ defaultValue: "grayscale-hover-reveal",
43188
+ ui: { intent: "style" }
43189
+ },
43190
+ {
43191
+ id: "imageBorder",
43192
+ type: "group",
43193
+ label: "Image border",
43194
+ schema: { fields: [
43195
+ {
43196
+ id: "enabled",
43197
+ type: "boolean",
43198
+ label: "Show border",
43199
+ defaultValue: true
43200
+ },
43201
+ {
43202
+ id: "colorToken",
43203
+ type: "text",
43204
+ label: "Border color",
43205
+ defaultValue: "accent",
43206
+ ui: { widget: "backgroundColor" }
43207
+ },
43208
+ {
43209
+ id: "opacity",
43210
+ type: "number",
43211
+ label: "Border opacity",
43212
+ defaultValue: 30,
43213
+ ui: {
43214
+ min: 0,
43215
+ max: 100
43216
+ }
43217
+ },
43218
+ {
43219
+ id: "width",
43220
+ type: "select",
43221
+ label: "Border width",
43222
+ options: [
43223
+ {
43224
+ value: "1",
43225
+ label: "Thin (1px)"
43226
+ },
43227
+ {
43228
+ value: "2",
43229
+ label: "Medium (2px)"
43230
+ },
43231
+ {
43232
+ value: "3",
43233
+ label: "Thick (3px)"
43234
+ }
43235
+ ],
43236
+ defaultValue: "2"
43237
+ }
43238
+ ] },
43239
+ ui: { intent: "style" }
43240
+ },
43241
+ {
43242
+ id: "imageCorners",
43243
+ type: "select",
43244
+ label: "Image corners",
43245
+ options: [
43246
+ {
43247
+ value: "none",
43248
+ label: "Square"
43249
+ },
43250
+ {
43251
+ value: "sm",
43252
+ label: "Slightly rounded"
43253
+ },
43254
+ {
43255
+ value: "md",
43256
+ label: "Rounded"
43257
+ },
43258
+ {
43259
+ value: "lg",
43260
+ label: "More rounded"
43261
+ },
43262
+ {
43263
+ value: "xl",
43264
+ label: "Very rounded"
43265
+ },
43266
+ {
43267
+ value: "2xl",
43268
+ label: "Extra rounded"
43269
+ },
43270
+ {
43271
+ value: "3xl",
43272
+ label: "Maximum rounded"
43273
+ }
43274
+ ],
43275
+ defaultValue: "3xl",
43276
+ ui: { intent: "style" }
43277
+ }
43278
+ ]);
43279
+ //#endregion
41889
43280
  //#region ../blocks/src/system/blocks/image-gallery.ts
41890
43281
  const grid$1 = (props, children, ...mods) => el("grid", props ?? void 0, children ?? void 0, ...mods);
41891
43282
  const galleryContainer = (children, opts) => {
@@ -42100,7 +43491,11 @@ const emptyState$1 = {
42100
43491
  }
42101
43492
  };
42102
43493
  const wrapVariant$1 = (layout, opts) => styledSection({
42103
- children: galleryContainer([layout, emptyState$1], {
43494
+ children: galleryContainer([
43495
+ ...sectionHeaderLayoutNodes(),
43496
+ layout,
43497
+ emptyState$1
43498
+ ], {
42104
43499
  gap: "md",
42105
43500
  fullWidth: opts?.fullWidth,
42106
43501
  className: opts?.className
@@ -42109,6 +43504,28 @@ const wrapVariant$1 = (layout, opts) => styledSection({
42109
43504
  spacing: "medium",
42110
43505
  background: "background"
42111
43506
  });
43507
+ const lookGalleryTile = (imageFrom, captionFrom, ...mods) => el("li", lookSlot("item"), [el("figure", lookSlot("figure"), [el("div", lookSlot("media"), [media(lookSlot("photo"), bind(imageFrom), when(imageFrom))]), text({
43508
+ as: "figcaption",
43509
+ ...lookSlot("caption")
43510
+ }, bind(captionFrom), when(captionFrom))])], ...mods);
43511
+ const tilesLayout = styledSection({
43512
+ children: el("div", {
43513
+ className: "rb-container",
43514
+ ...lookSlot("layout")
43515
+ }, [...sectionHeaderLayoutNodes({ splitClassName: "rb-grid" }), el("ol", lookSlot("items"), [lookGalleryTile("item.image", "item.caption", repeat("content.images", "item")), lookGalleryTile("content.images.0.image", "content.images.0.caption", (node) => ({
43516
+ ...node,
43517
+ $when: {
43518
+ when: {
43519
+ from: "content.images",
43520
+ transforms: [{ id: "array.length" }]
43521
+ },
43522
+ equals: 0
43523
+ }
43524
+ }))])]),
43525
+ baseClass: "",
43526
+ spacing: "medium",
43527
+ background: "background"
43528
+ });
42112
43529
  const imageGalleryBlockDefinition = { manifest: createBlockManifest({
42113
43530
  id: "block.image-gallery",
42114
43531
  title: "Image Gallery",
@@ -42121,510 +43538,10 @@ const imageGalleryBlockDefinition = { manifest: createBlockManifest({
42121
43538
  "marqueeSpeed",
42122
43539
  "marqueePauseOnHover"
42123
43540
  ] },
42124
- additionalFields: parseFieldDefinitions([
42125
- {
42126
- id: "images",
42127
- type: "repeater",
42128
- label: "Images",
42129
- itemLabel: "Image",
42130
- minItems: 0,
42131
- maxItems: 24,
42132
- ui: {
42133
- repeaterPreset: "thumbnailGrid",
42134
- thumbnailField: "image",
42135
- thumbnailAltField: "caption",
42136
- thumbnailLabelField: "caption",
42137
- thumbnailCardDensity: "compact"
42138
- },
42139
- schema: { fields: [{
42140
- id: "image",
42141
- type: "media",
42142
- label: "Image",
42143
- required: true,
42144
- mediaKinds: ["image"]
42145
- }, {
42146
- id: "caption",
42147
- type: "text",
42148
- label: "Caption",
42149
- description: "Optional caption displayed below the image and used as the editor card label",
42150
- maxLength: 200
42151
- }] }
42152
- },
42153
- {
42154
- id: "fullBleed",
42155
- type: "boolean",
42156
- label: "Full bleed",
42157
- description: "Extend the gallery edge-to-edge by removing section side padding and container max-width.",
42158
- defaultValue: false,
42159
- ui: {
42160
- intent: "display",
42161
- visibleWhen: {
42162
- field: "variant",
42163
- notIn: ["marquee"]
42164
- }
42165
- }
42166
- },
42167
- {
42168
- id: "aspectRatio",
42169
- type: "select",
42170
- label: "Aspect ratio",
42171
- description: "Crop images to a consistent aspect ratio.",
42172
- defaultValue: "1/1",
42173
- options: [
42174
- {
42175
- value: "auto",
42176
- label: "Original"
42177
- },
42178
- {
42179
- value: "1/1",
42180
- label: "1:1 (Square)"
42181
- },
42182
- {
42183
- value: "4/3",
42184
- label: "4:3 (Standard)"
42185
- },
42186
- {
42187
- value: "16/9",
42188
- label: "16:9 (Widescreen)"
42189
- },
42190
- {
42191
- value: "3/2",
42192
- label: "3:2 (Classic)"
42193
- },
42194
- {
42195
- value: "3/4",
42196
- label: "3:4 (Portrait)"
42197
- }
42198
- ],
42199
- ui: {
42200
- intent: "display",
42201
- visibleWhen: {
42202
- field: "variant",
42203
- notIn: ["masonry", "marquee"]
42204
- }
42205
- }
42206
- },
42207
- {
42208
- id: "slidesToShow",
42209
- type: "select",
42210
- label: "Images per view (mobile)",
42211
- description: "Number of images visible at once on small screens.",
42212
- defaultValue: "1",
42213
- options: [
42214
- {
42215
- value: "1",
42216
- label: "One at a time"
42217
- },
42218
- {
42219
- value: "2",
42220
- label: "Two at a time"
42221
- },
42222
- {
42223
- value: "3",
42224
- label: "Three at a time"
42225
- }
42226
- ],
42227
- ui: {
42228
- intent: "display",
42229
- visibleWhen: {
42230
- field: "variant",
42231
- equals: "carousel"
42232
- }
42233
- }
42234
- },
42235
- {
42236
- id: "slidesToShowTablet",
42237
- type: "select",
42238
- label: "Images per view (tablet)",
42239
- description: "Number of images visible on medium screens.",
42240
- options: [
42241
- {
42242
- value: "",
42243
- label: "Same as mobile"
42244
- },
42245
- {
42246
- value: "1",
42247
- label: "One at a time"
42248
- },
42249
- {
42250
- value: "2",
42251
- label: "Two at a time"
42252
- },
42253
- {
42254
- value: "3",
42255
- label: "Three at a time"
42256
- }
42257
- ],
42258
- ui: {
42259
- intent: "display",
42260
- visibleWhen: {
42261
- field: "variant",
42262
- equals: "carousel"
42263
- }
42264
- }
42265
- },
42266
- {
42267
- id: "slidesToShowDesktop",
42268
- type: "select",
42269
- label: "Images per view (desktop)",
42270
- description: "Number of images visible on large screens.",
42271
- options: [
42272
- {
42273
- value: "",
42274
- label: "Same as tablet"
42275
- },
42276
- {
42277
- value: "1",
42278
- label: "One at a time"
42279
- },
42280
- {
42281
- value: "2",
42282
- label: "Two at a time"
42283
- },
42284
- {
42285
- value: "3",
42286
- label: "Three at a time"
42287
- }
42288
- ],
42289
- ui: {
42290
- intent: "display",
42291
- visibleWhen: {
42292
- field: "variant",
42293
- equals: "carousel"
42294
- }
42295
- }
42296
- },
42297
- {
42298
- id: "transition",
42299
- type: "select",
42300
- label: "Transition",
42301
- description: "Animation style between slides.",
42302
- defaultValue: "slide",
42303
- options: [{
42304
- value: "slide",
42305
- label: "Slide"
42306
- }, {
42307
- value: "fade",
42308
- label: "Fade"
42309
- }],
42310
- ui: {
42311
- intent: "display",
42312
- visibleWhen: {
42313
- field: "variant",
42314
- equals: "carousel"
42315
- }
42316
- }
42317
- },
42318
- {
42319
- id: "showControls",
42320
- type: "boolean",
42321
- label: "Show arrows",
42322
- defaultValue: true,
42323
- ui: {
42324
- intent: "behavior",
42325
- visibleWhen: {
42326
- field: "variant",
42327
- equals: "carousel"
42328
- }
42329
- }
42330
- },
42331
- {
42332
- id: "showDots",
42333
- type: "boolean",
42334
- label: "Show dots",
42335
- defaultValue: false,
42336
- ui: {
42337
- intent: "behavior",
42338
- visibleWhen: {
42339
- field: "variant",
42340
- equals: "carousel"
42341
- }
42342
- }
42343
- },
42344
- {
42345
- id: "autoplay",
42346
- type: "boolean",
42347
- label: "Autoplay",
42348
- defaultValue: false,
42349
- ui: {
42350
- intent: "behavior",
42351
- visibleWhen: {
42352
- field: "variant",
42353
- equals: "carousel"
42354
- }
42355
- }
42356
- },
42357
- {
42358
- id: "autoplayDelay",
42359
- type: "select",
42360
- label: "Autoplay delay",
42361
- defaultValue: "5000",
42362
- options: [
42363
- {
42364
- value: "3000",
42365
- label: "3 seconds"
42366
- },
42367
- {
42368
- value: "5000",
42369
- label: "5 seconds"
42370
- },
42371
- {
42372
- value: "7000",
42373
- label: "7 seconds"
42374
- },
42375
- {
42376
- value: "10000",
42377
- label: "10 seconds"
42378
- }
42379
- ],
42380
- ui: {
42381
- intent: "behavior",
42382
- visibleWhen: {
42383
- field: "variant",
42384
- equals: "carousel"
42385
- }
42386
- }
42387
- },
42388
- {
42389
- id: "arrowVisibility",
42390
- type: "select",
42391
- label: "Arrow visibility",
42392
- defaultValue: "always",
42393
- options: [{
42394
- value: "always",
42395
- label: "Always visible"
42396
- }, {
42397
- value: "hover",
42398
- label: "Show on hover"
42399
- }],
42400
- ui: {
42401
- intent: "behavior",
42402
- visibleWhen: {
42403
- field: "variant",
42404
- equals: "carousel"
42405
- }
42406
- }
42407
- },
42408
- {
42409
- id: "loop",
42410
- type: "boolean",
42411
- label: "Loop slides",
42412
- defaultValue: true,
42413
- ui: {
42414
- intent: "behavior",
42415
- visibleWhen: {
42416
- field: "variant",
42417
- equals: "carousel"
42418
- }
42419
- }
42420
- },
42421
- {
42422
- id: "marqueeDirection",
42423
- type: "select",
42424
- label: "Scroll direction",
42425
- options: [{
42426
- value: "left",
42427
- label: "Left"
42428
- }, {
42429
- value: "right",
42430
- label: "Right"
42431
- }],
42432
- defaultValue: "left",
42433
- ui: {
42434
- intent: "display",
42435
- visibleWhen: {
42436
- field: "variant",
42437
- equals: "marquee"
42438
- }
42439
- }
42440
- },
42441
- {
42442
- id: "marqueeSpeed",
42443
- type: "select",
42444
- label: "Scroll speed",
42445
- options: [
42446
- {
42447
- value: "slow",
42448
- label: "Slow (60s)"
42449
- },
42450
- {
42451
- value: "medium",
42452
- label: "Medium (40s)"
42453
- },
42454
- {
42455
- value: "fast",
42456
- label: "Fast (20s)"
42457
- }
42458
- ],
42459
- defaultValue: "medium",
42460
- ui: {
42461
- intent: "display",
42462
- visibleWhen: {
42463
- field: "variant",
42464
- equals: "marquee"
42465
- }
42466
- }
42467
- },
42468
- {
42469
- id: "marqueePauseOnHover",
42470
- type: "boolean",
42471
- label: "Pause on hover",
42472
- defaultValue: true,
42473
- ui: {
42474
- intent: "behavior",
42475
- visibleWhen: {
42476
- field: "variant",
42477
- equals: "marquee"
42478
- }
42479
- }
42480
- },
42481
- {
42482
- id: "marqueeImageSize",
42483
- type: "select",
42484
- label: "Image size",
42485
- options: [
42486
- {
42487
- value: "sm",
42488
- label: "Small (200px)"
42489
- },
42490
- {
42491
- value: "md",
42492
- label: "Medium (256px)"
42493
- },
42494
- {
42495
- value: "lg",
42496
- label: "Large (320px)"
42497
- },
42498
- {
42499
- value: "xl",
42500
- label: "Extra large (400px)"
42501
- }
42502
- ],
42503
- defaultValue: "md",
42504
- ui: {
42505
- intent: "display",
42506
- visibleWhen: {
42507
- field: "variant",
42508
- equals: "marquee"
42509
- }
42510
- }
42511
- },
42512
- {
42513
- id: "imageFilter",
42514
- type: "select",
42515
- label: "Image filter",
42516
- options: [
42517
- {
42518
- value: "none",
42519
- label: "None"
42520
- },
42521
- {
42522
- value: "grayscale",
42523
- label: "Grayscale"
42524
- },
42525
- {
42526
- value: "grayscale-hover-reveal",
42527
- label: "Grayscale (color on hover)"
42528
- },
42529
- {
42530
- value: "sepia",
42531
- label: "Sepia"
42532
- }
42533
- ],
42534
- defaultValue: "grayscale-hover-reveal",
42535
- ui: { intent: "style" }
42536
- },
42537
- {
42538
- id: "imageBorder",
42539
- type: "group",
42540
- label: "Image border",
42541
- schema: { fields: [
42542
- {
42543
- id: "enabled",
42544
- type: "boolean",
42545
- label: "Show border",
42546
- defaultValue: true
42547
- },
42548
- {
42549
- id: "colorToken",
42550
- type: "text",
42551
- label: "Border color",
42552
- defaultValue: "accent",
42553
- ui: { widget: "backgroundColor" }
42554
- },
42555
- {
42556
- id: "opacity",
42557
- type: "number",
42558
- label: "Border opacity",
42559
- defaultValue: 30,
42560
- ui: {
42561
- min: 0,
42562
- max: 100
42563
- }
42564
- },
42565
- {
42566
- id: "width",
42567
- type: "select",
42568
- label: "Border width",
42569
- options: [
42570
- {
42571
- value: "1",
42572
- label: "Thin (1px)"
42573
- },
42574
- {
42575
- value: "2",
42576
- label: "Medium (2px)"
42577
- },
42578
- {
42579
- value: "3",
42580
- label: "Thick (3px)"
42581
- }
42582
- ],
42583
- defaultValue: "2"
42584
- }
42585
- ] },
42586
- ui: { intent: "style" }
42587
- },
42588
- {
42589
- id: "imageCorners",
42590
- type: "select",
42591
- label: "Image corners",
42592
- options: [
42593
- {
42594
- value: "none",
42595
- label: "Square"
42596
- },
42597
- {
42598
- value: "sm",
42599
- label: "Slightly rounded"
42600
- },
42601
- {
42602
- value: "md",
42603
- label: "Rounded"
42604
- },
42605
- {
42606
- value: "lg",
42607
- label: "More rounded"
42608
- },
42609
- {
42610
- value: "xl",
42611
- label: "Very rounded"
42612
- },
42613
- {
42614
- value: "2xl",
42615
- label: "Extra rounded"
42616
- },
42617
- {
42618
- value: "3xl",
42619
- label: "Maximum rounded"
42620
- }
42621
- ],
42622
- defaultValue: "3xl",
42623
- ui: { intent: "style" }
42624
- }
42625
- ]),
43541
+ additionalFields: imageGalleryFields,
42626
43542
  layout: wrapVariant$1(gridLayout),
42627
43543
  variants: {
43544
+ tiles: tilesLayout,
42628
43545
  grid: wrapVariant$1(gridLayout),
42629
43546
  carousel: wrapVariant$1(carouselLayout),
42630
43547
  masonry: wrapVariant$1(masonryLayout),
@@ -42633,7 +43550,10 @@ const imageGalleryBlockDefinition = { manifest: createBlockManifest({
42633
43550
  className: "rb-image-gallery-marquee-container"
42634
43551
  })
42635
43552
  },
42636
- variantMeaning: { kind: "arrangement" },
43553
+ variantMeaning: {
43554
+ kind: "arrangement",
43555
+ lookOnlyKeys: ["tiles"]
43556
+ },
42637
43557
  defaultVariant: "grid",
42638
43558
  variantOptions: {
42639
43559
  grid: {
@@ -43026,6 +43946,14 @@ const audioPlayerBlockDefinition = { manifest: createBlockManifest({
43026
43946
  }
43027
43947
  }) };
43028
43948
  //#endregion
43949
+ //#region ../blocks/src/lib/media.ts
43950
+ const PUBLIC_DOWNLOAD_MEDIA_TYPES = [
43951
+ "document",
43952
+ "spreadsheet",
43953
+ "archive",
43954
+ "audio"
43955
+ ];
43956
+ //#endregion
43029
43957
  //#region ../blocks/src/system/blocks/file-download.ts
43030
43958
  const bound = (from) => ({ $bind: { from } });
43031
43959
  const fileDownloadLayout = styledSection({
@@ -44845,76 +45773,74 @@ const giftingBlockDefinition = {
44845
45773
  /**
44846
45774
  * Get form fields based on preset configuration.
44847
45775
  */
44848
- function getGlobalFormFields(form) {
44849
- const includePhone = form.includeOptionalPhone;
44850
- switch (form.fields.preset) {
44851
- case "emailOnly": return withOptionalPhone([{
44852
- id: "email",
44853
- type: "email",
44854
- label: "Email",
44855
- required: true,
44856
- placeholder: "your@email.com"
44857
- }], includePhone);
44858
- case "emailName": return withOptionalPhone([{
44859
- id: "email",
44860
- type: "email",
44861
- label: "Email",
44862
- required: true,
44863
- placeholder: "your@email.com"
44864
- }, {
45776
+ function getGlobalFormFields(form, presentation = {}) {
45777
+ const fields = withOptionalPhone(newsletterPresetFields(form.fields), form.includeOptionalPhone);
45778
+ return presentation.lookSlots ? fields.map((field) => ({
45779
+ ...field,
45780
+ label: lookFieldLabel(field)
45781
+ })) : fields;
45782
+ }
45783
+ function lookFieldLabel(field) {
45784
+ switch (field.id) {
45785
+ case "firstName": return "First name";
45786
+ case "lastName": return "Last name";
45787
+ default: return field.label;
45788
+ }
45789
+ }
45790
+ const emailField = {
45791
+ id: "email",
45792
+ type: "email",
45793
+ label: "Email",
45794
+ required: true,
45795
+ placeholder: "your@email.com"
45796
+ };
45797
+ const firstNameField = (required) => ({
45798
+ id: "firstName",
45799
+ type: "text",
45800
+ label: "First Name",
45801
+ required,
45802
+ placeholder: "First name"
45803
+ });
45804
+ function newsletterPresetFields(fields) {
45805
+ switch (fields.preset) {
45806
+ case "emailOnly": return [emailField];
45807
+ case "emailName": return [emailField, {
44865
45808
  id: "name",
44866
45809
  type: "text",
44867
45810
  label: "Name",
44868
- required: form.fields.name === "required",
45811
+ required: fields.name === "required",
44869
45812
  placeholder: "Your name"
44870
- }], includePhone);
44871
- case "emailFirstLast": return withOptionalPhone([
44872
- {
44873
- id: "email",
44874
- type: "email",
44875
- label: "Email",
44876
- required: true,
44877
- placeholder: "your@email.com"
44878
- },
44879
- {
44880
- id: "firstName",
44881
- type: "text",
44882
- label: "First Name",
44883
- required: form.fields.firstName === "required",
44884
- placeholder: "First name"
44885
- },
45813
+ }];
45814
+ case "emailFirstName": return [emailField, firstNameField(fields.firstName === "required")];
45815
+ case "emailFirstLast": return [
45816
+ emailField,
45817
+ firstNameField(fields.firstName === "required"),
44886
45818
  {
44887
45819
  id: "lastName",
44888
45820
  type: "text",
44889
45821
  label: "Last Name",
44890
- required: form.fields.lastName === "required",
45822
+ required: fields.lastName === "required",
44891
45823
  placeholder: "Last name"
44892
45824
  }
44893
- ], includePhone);
44894
- case "emailNameCompany": return withOptionalPhone([
44895
- {
44896
- id: "email",
44897
- type: "email",
44898
- label: "Email",
44899
- required: true,
44900
- placeholder: "your@email.com"
44901
- },
45825
+ ];
45826
+ case "emailNameCompany": return [
45827
+ emailField,
44902
45828
  {
44903
45829
  id: "name",
44904
45830
  type: "text",
44905
45831
  label: "Name",
44906
- required: form.fields.name === "required",
45832
+ required: fields.name === "required",
44907
45833
  placeholder: "Your name"
44908
45834
  },
44909
45835
  {
44910
45836
  id: "company",
44911
45837
  type: "text",
44912
45838
  label: "Company",
44913
- required: form.fields.company === "required",
45839
+ required: fields.company === "required",
44914
45840
  placeholder: "Company name"
44915
45841
  }
44916
- ], includePhone);
44917
- default: throw new Error("Unknown newsletter preset");
45842
+ ];
45843
+ default: return assertNever$2(fields);
44918
45844
  }
44919
45845
  }
44920
45846
  function withOptionalPhone(fields, includePhone) {
@@ -44976,6 +45902,7 @@ const mailingListSignupBlockSourceRefSchema = z.object({
44976
45902
  });
44977
45903
  const signedMailingListSourceTokenSchema = z.string().trim().min(1).transform(parseRequiredMailingListSignedSourceToken);
44978
45904
  const newsletterSourceCommonSchema = z.object({
45905
+ lookSlots: lookListPresentationSchemaShape.lookSlots,
44979
45906
  siteId: z.string().optional(),
44980
45907
  apiBaseUrl: z.string().optional(),
44981
45908
  mailingList: mailingListContextSchema.optional(),
@@ -45008,6 +45935,7 @@ const newsletterSourceSchema = z.discriminatedUnion("source", [
45008
45935
  newsletterSourceCommonSchema.extend({ source: z.literal("preview") })
45009
45936
  ]);
45010
45937
  const newsletterDisplaySchema = z.object({
45938
+ lookSlots: lookListPresentationSchemaShape.lookSlots,
45011
45939
  kind: z.literal("newsletter-form"),
45012
45940
  availability: z.enum(["ready", "unavailable"]),
45013
45941
  className: z.string().nullable(),
@@ -45074,13 +46002,14 @@ function buildNewsletterDisplay(source) {
45074
46002
  const choices = resolveRuntimeChoices(assessment);
45075
46003
  return {
45076
46004
  kind: "newsletter-form",
46005
+ ...source.lookSlots ? { lookSlots: source.lookSlots } : {},
45077
46006
  availability: assessment.tag === "available" ? "ready" : "unavailable",
45078
46007
  className: source.className ?? null,
45079
46008
  buttonLabel: form.buttonLabel,
45080
46009
  successMessage: form.successMessage,
45081
46010
  buttonVariant: source.buttonVariant ?? "primary",
45082
46011
  privacyNote: form.privacyNote,
45083
- fields: getGlobalFormFields(form),
46012
+ fields: getGlobalFormFields(form, source),
45084
46013
  choices
45085
46014
  };
45086
46015
  }
@@ -45152,32 +46081,50 @@ function parseRequiredMailingListSignedSourceToken(value) {
45152
46081
  //#region ../blocks/src/system/blocks/newsletter-signup.ts
45153
46082
  const stackedComposition = composeFragments([{ fragment: newsletterCopyFragment }, { fragment: newsletterFormFragment }]);
45154
46083
  const stackedLayout = styledSection({
45155
- children: sectionContainer(stackedComposition.layout, {
46084
+ children: props(lookSlot("layout"))(sectionContainer(stackedComposition.layout, {
45156
46085
  gap: "md",
45157
46086
  className: "rb-text-center newsletter-stacked"
45158
- }),
46087
+ })),
45159
46088
  baseClass: "",
45160
46089
  spacing: "medium",
45161
46090
  background: "surface"
45162
46091
  });
45163
46092
  const inlineLayout = styledSection({
45164
- children: sectionContainer(stackedComposition.layout, {
46093
+ children: props(lookSlot("layout"))(sectionContainer(stackedComposition.layout, {
45165
46094
  gap: "md",
45166
46095
  className: "newsletter-inline"
45167
- }),
46096
+ })),
45168
46097
  baseClass: "",
45169
46098
  spacing: "medium",
45170
46099
  background: "surface"
45171
46100
  });
45172
46101
  const editorialSplitLayout = styledSection({
45173
- children: sectionContainer([el("div", { className: "newsletter-editorial-split-copy" }, newsletterCopyFragment.layout), el("div", { className: "newsletter-editorial-split-form" }, newsletterFormFragment.layout)], {
46102
+ children: props(lookSlot("layout"))(sectionContainer([el("div", {
46103
+ className: "newsletter-editorial-split-copy",
46104
+ ...lookSlot("head")
46105
+ }, newsletterCopyFragment.layout), el("div", {
46106
+ className: "newsletter-editorial-split-form",
46107
+ ...lookSlot("panel")
46108
+ }, newsletterFormFragment.layout)], {
45174
46109
  gap: "lg",
45175
46110
  className: "newsletter-editorial-split"
45176
- }),
46111
+ })),
45177
46112
  baseClass: "",
45178
46113
  spacing: "comfortable",
45179
46114
  background: "surface"
45180
46115
  });
46116
+ const archLayout = styledSection({
46117
+ children: el("div", {
46118
+ className: "rb-container",
46119
+ ...lookSlot("layout")
46120
+ }, [el("div", lookSlot("frame"), [el("div", {
46121
+ className: "rb-grid",
46122
+ ...lookSlot("head")
46123
+ }, newsletterCopyFragment.layout), ...newsletterFormFragment.layout])]),
46124
+ baseClass: "",
46125
+ spacing: "medium",
46126
+ background: "surface"
46127
+ });
45181
46128
  const newsletterSignupManifest = createBlockManifest({
45182
46129
  id: "block.newsletter-signup",
45183
46130
  title: "Newsletter Signup",
@@ -45192,13 +46139,26 @@ const newsletterSignupManifest = createBlockManifest({
45192
46139
  fragment: newsletterFormFragment,
45193
46140
  fieldPriority: 1
45194
46141
  }],
46142
+ additionalFields: [{
46143
+ id: "archFrame",
46144
+ type: "boolean",
46145
+ label: "Arch frame",
46146
+ ui: {
46147
+ intent: "display",
46148
+ hidden: true
46149
+ }
46150
+ }],
45195
46151
  layout: stackedLayout,
45196
46152
  variants: {
46153
+ arch: archLayout,
45197
46154
  stacked: stackedLayout,
45198
46155
  inline: inlineLayout,
45199
46156
  "editorial-split": editorialSplitLayout
45200
46157
  },
45201
- variantMeaning: { kind: "arrangement" },
46158
+ variantMeaning: {
46159
+ kind: "arrangement",
46160
+ lookOnlyKeys: ["arch"]
46161
+ },
45202
46162
  defaultVariant: "stacked",
45203
46163
  variantOptions: {
45204
46164
  stacked: {
@@ -45271,7 +46231,7 @@ const memberPhotoClassName = (baseClass) => cardRoleChildClass({
45271
46231
  baseClass,
45272
46232
  stylesFrom: "content._cardStyles"
45273
46233
  });
45274
- const teamMemberPhotoSchema = mediaSchema.refine((media) => media.type === "image", { message: "Team member photos must be image media" }).nullable();
46234
+ const teamMemberPhotoSchema = runtimeMediaSchema.refine((media) => media.type === "image", { message: "Team member photos must be image media" }).nullable();
45275
46235
  const teamMemberDataSchema = z.object({
45276
46236
  _type: z.literal("teamMember"),
45277
46237
  id: z.string(),
@@ -46285,7 +47245,7 @@ const systemBlockDefinitions = [
46285
47245
  })
46286
47246
  ]
46287
47247
  })),
46288
- withDesignCapability("block.body-text", bodyTextBlockDefinition, sectionOnly(), defineBlockDesignMetadata({
47248
+ withDesignCapability("block.body-text", bodyTextBlockDefinition, withLookCapability(sectionOnly()), defineBlockDesignMetadata({
46289
47249
  flow: bodyFlow,
46290
47250
  layoutProfiles: [
46291
47251
  layoutProfile({
@@ -46660,7 +47620,7 @@ const systemBlockDefinitions = [
46660
47620
  weight: "quiet"
46661
47621
  })]
46662
47622
  })),
46663
- withDesignCapability("block.image-gallery", imageGalleryBlockDefinition, sectionOnly(), defineBlockDesignMetadata({
47623
+ withDesignCapability("block.image-gallery", imageGalleryBlockDefinition, withLookCapability(sectionOnly()), defineBlockDesignMetadata({
46664
47624
  flow: mediaFlow,
46665
47625
  layoutProfiles: [
46666
47626
  layoutProfile({
@@ -46749,7 +47709,7 @@ const systemBlockDefinitions = [
46749
47709
  weight: "standard"
46750
47710
  })]
46751
47711
  })),
46752
- withDesignCapability("block.newsletter-signup", newsletterSignupBlockDefinition, sectionOnly(), defineBlockDesignMetadata({
47712
+ withDesignCapability("block.newsletter-signup", newsletterSignupBlockDefinition, withLookCapability(sectionOnly()), defineBlockDesignMetadata({
46753
47713
  flow: conversionFlow,
46754
47714
  layoutProfiles: [
46755
47715
  layoutProfile({
@@ -46813,11 +47773,14 @@ const offeringsPreviewDatesReadEnabled = {
46813
47773
  //#endregion
46814
47774
  //#region ../blocks/src/system/helpers/backgroundMedia.ts
46815
47775
  function resolveBackgroundMedia(input) {
46816
- const parsedMedia = mediaSchema.safeParse(input.image);
47776
+ const parsedMedia = runtimeMediaSchema.safeParse(input.image);
46817
47777
  if (!parsedMedia.success) return null;
46818
47778
  switch (parsedMedia.data.type) {
46819
47779
  case "image":
46820
- case "video": return parsedMedia.data;
47780
+ case "video": return {
47781
+ ...parsedMedia.data,
47782
+ type: parsedMedia.data.type
47783
+ };
46821
47784
  case "audio":
46822
47785
  case "document":
46823
47786
  case "spreadsheet":
@@ -46829,6 +47792,75 @@ function backgroundVideoMobileClassNames(input) {
46829
47792
  return input.showVideoOnMobile === true ? "" : "rb-hidden rb-md-block";
46830
47793
  }
46831
47794
  //#endregion
47795
+ //#region ../blocks/src/system/runtime/nodes/mediaContext.ts
47796
+ /**
47797
+ * Server-side: AsyncLocalStorage for request isolation.
47798
+ * Prevents race conditions when multiple requests are processed concurrently.
47799
+ *
47800
+ * Lazy initialization to avoid issues in environments that don't support async_hooks.
47801
+ */
47802
+ const serverStorageState = {
47803
+ storage: null,
47804
+ checked: false
47805
+ };
47806
+ function getServerStorage() {
47807
+ if (typeof window !== "undefined") return null;
47808
+ if (serverStorageState.checked) return serverStorageState.storage;
47809
+ serverStorageState.checked = true;
47810
+ try {
47811
+ const globalWithNonWebpackRequire = globalThis;
47812
+ const AsyncLocalStorage = (typeof globalWithNonWebpackRequire.__non_webpack_require__ === "function" ? globalWithNonWebpackRequire.__non_webpack_require__ : new Function("id", "return require(id)"))("async_hooks").AsyncLocalStorage;
47813
+ if (AsyncLocalStorage) {
47814
+ serverStorageState.storage = new AsyncLocalStorage();
47815
+ return serverStorageState.storage;
47816
+ }
47817
+ return null;
47818
+ } catch {
47819
+ if (process.env.NODE_ENV !== "production") console.warn("[blocks] AsyncLocalStorage not available - using module-level state");
47820
+ return null;
47821
+ }
47822
+ }
47823
+ /**
47824
+ * Client-side context storage.
47825
+ * Safe because browsers are single-threaded per tab.
47826
+ *
47827
+ * IMPORTANT: This must be shared across bundles.
47828
+ * SDK preview mode can load multiple independently-bundled entrypoints
47829
+ * (e.g. `@riverbankcms/sdk/rendering` + `@riverbankcms/sdk/preview-next/client`),
47830
+ * which can otherwise each get their own module-scoped singleton.
47831
+ */
47832
+ const RB_MEDIA_CONTEXT_KEY = Symbol.for("riverbankcms.blocks.mediaContext");
47833
+ function getClientContextStore() {
47834
+ const g = globalThis;
47835
+ const existing = g[RB_MEDIA_CONTEXT_KEY];
47836
+ if (existing && typeof existing === "object") return existing;
47837
+ const next = {};
47838
+ g[RB_MEDIA_CONTEXT_KEY] = next;
47839
+ return next;
47840
+ }
47841
+ /**
47842
+ * Get the current media context.
47843
+ * Server-side: Uses AsyncLocalStorage for request isolation.
47844
+ * Client-side: Uses module-level state (safe in single-threaded browser).
47845
+ */
47846
+ function getMediaContext() {
47847
+ const storage = getServerStorage();
47848
+ if (storage) return storage.getStore() ?? {};
47849
+ return getClientContextStore();
47850
+ }
47851
+ function getCurrentResolveImageUrlContext() {
47852
+ const context = getMediaContext();
47853
+ if (!context.supabaseUrl && !context.siteId && !context.mediaAssetIndex) return;
47854
+ return {
47855
+ supabaseUrl: context.supabaseUrl,
47856
+ siteId: context.siteId,
47857
+ mediaAssetIndex: context.mediaAssetIndex
47858
+ };
47859
+ }
47860
+ function getMediaAssetIndex(context) {
47861
+ return context?.mediaAssetIndex ?? getMediaContext().mediaAssetIndex;
47862
+ }
47863
+ //#endregion
46832
47864
  //#region ../blocks/src/system/runtime/nodes/media.tsx
46833
47865
  function getValidSourceDimension(value) {
46834
47866
  return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : void 0;
@@ -46864,41 +47896,72 @@ function applyRectTransform(existingStyle, patch) {
46864
47896
  if (patch.transform) next.transform = appendTransform(existingStyle?.transform, patch.transform);
46865
47897
  return next;
46866
47898
  }
46867
- function computeMediaTransformStyle(value, style, targetAspectRatio, options) {
47899
+ /** Resolve portable content without exposing runtime metadata as saved values. */
47900
+ function resolveMediaWithContext(reference, context) {
47901
+ return resolveManagedMediaReference(reference, getMediaAssetIndex(context ?? void 0));
47902
+ }
47903
+ function sourceFromAsset(value, asset) {
47904
+ return {
47905
+ type: value.type,
47906
+ alt: value.alt,
47907
+ filename: value.filename,
47908
+ purpose: value.purpose,
47909
+ placeholder: value.placeholder,
47910
+ transform: value.transform,
47911
+ poster: value.poster,
47912
+ identifier: asset.identifier,
47913
+ assetId: asset.id,
47914
+ storageBucket: asset.storageBucket,
47915
+ storagePath: asset.storagePath,
47916
+ mimeType: asset.mimeType,
47917
+ width: asset.width,
47918
+ height: asset.height
47919
+ };
47920
+ }
47921
+ function resolveRuntimeMedia(value, context) {
47922
+ if ("asset" in value && value.asset) return sourceFromAsset(value, value.asset);
47923
+ if ("src" in value && value.src) return value;
47924
+ if (!value.identifier) return void 0;
47925
+ const resolved = resolveMediaWithContext(value, context);
47926
+ return resolved.kind === "resolved" ? sourceFromAsset(resolved.reference, resolved.asset) : void 0;
47927
+ }
47928
+ function usesProxyFraming(source, transform) {
47929
+ if (!source?.assetId || !isExplicitCropProxyEnabled()) return false;
47930
+ return Boolean(transform.rotation) || isExplicitRectCrop(transform.rect, getValidSourceDimension(source.width), getValidSourceDimension(source.height));
47931
+ }
47932
+ function rectFramingPatch(source, rect, proxy, style) {
47933
+ if (!source || !rect || proxy) return {};
47934
+ const patch = buildCssRectStylePatch(source, rect);
47935
+ return patch ? applyRectTransform(style, patch) : {};
47936
+ }
47937
+ function hotspotFramingPatch(transform, proxy, rectPatch, style) {
47938
+ if (!transform.hotspot || rectPatch.objectPosition !== void 0) return {};
47939
+ const fit = style?.objectFit;
47940
+ if (fit && fit !== "cover" && fit !== "contain") return {};
47941
+ const point = proxy && transform.rotation ? rotateNormalizedPoint(transform.hotspot, transform.rotation) : transform.hotspot;
47942
+ return { objectPosition: `${point.x * 100}% ${point.y * 100}%` };
47943
+ }
47944
+ function rotationFramingPatch(rotation, proxy, rectPatch, style) {
47945
+ if (!rotation || proxy) return {};
47946
+ return {
47947
+ transform: appendTransform(rectPatch.transform ?? style?.transform, `rotate(${rotation}deg)`),
47948
+ transformOrigin: rectPatch.transformOrigin ?? "center"
47949
+ };
47950
+ }
47951
+ /** CSS framing is a pure projection of the resolved source and per-use transform. */
47952
+ function deriveMediaFramingStyle(source, transform, proxy, style) {
47953
+ if (!transform.rect && !transform.hotspot && !transform.rotation) return style;
47954
+ const rectPatch = rectFramingPatch(source, transform.rect, proxy, style);
47955
+ return mergeStyles(style, {
47956
+ ...rectPatch,
47957
+ ...hotspotFramingPatch(transform, proxy, rectPatch, style),
47958
+ ...rotationFramingPatch(transform.rotation, proxy, rectPatch, style)
47959
+ });
47960
+ }
47961
+ function computeMediaTransformStyle(value, style, targetAspectRatio, options, context) {
47962
+ const source = resolveRuntimeMedia(value, context ?? getCurrentResolveImageUrlContext());
46868
47963
  const transform = options?.resolvedTransform ?? resolveMediaTransformForAspect(value.transform, targetAspectRatio);
46869
- const rect = transform.rect;
46870
- const hotspot = transform.hotspot;
46871
- const rotation = transform.rotation;
46872
- if (!rect && !hotspot && !rotation) return style;
46873
- const stylePatch = {};
46874
- const heuristicSuppressCss = Boolean(isExplicitCropProxyEnabled() && value.assetId && (typeof rotation === "number" && rotation !== 0 || isExplicitRectCrop(rect, getValidSourceDimension(value.width), getValidSourceDimension(value.height))));
46875
- const shouldSuppressCss = options?.isProxy ?? heuristicSuppressCss;
46876
- if (rect && !shouldSuppressCss) {
46877
- const rectPatch = buildCssRectStylePatch(value, rect);
46878
- if (rectPatch) {
46879
- const mergedRect = applyRectTransform(style, rectPatch);
46880
- Object.assign(stylePatch, mergedRect);
46881
- }
46882
- }
46883
- if (hotspot) {
46884
- const effectiveObjectFit = stylePatch.objectFit ?? style?.objectFit;
46885
- if ((!effectiveObjectFit || effectiveObjectFit === "cover" || effectiveObjectFit === "contain") && stylePatch.objectPosition === void 0) {
46886
- const resolved = shouldSuppressCss && rotation ? rotateNormalizedPoint({
46887
- x: hotspot.x,
46888
- y: hotspot.y
46889
- }, rotation) : {
46890
- x: hotspot.x,
46891
- y: hotspot.y
46892
- };
46893
- stylePatch.objectPosition = `${resolved.x * 100}% ${resolved.y * 100}%`;
46894
- }
46895
- }
46896
- if (rotation && !shouldSuppressCss) {
46897
- const existingTransform = stylePatch.transform ?? style?.transform;
46898
- stylePatch.transform = existingTransform ? `${existingTransform} rotate(${rotation}deg)` : `rotate(${rotation}deg)`;
46899
- if (!stylePatch.transformOrigin) stylePatch.transformOrigin = "center";
46900
- }
46901
- return mergeStyles(style, stylePatch);
47964
+ return deriveMediaFramingStyle(source, transform, options?.isProxy ?? usesProxyFraming(source, transform), style);
46902
47965
  }
46903
47966
  //#endregion
46904
47967
  //#region ../blocks/src/system/transforms/registry/background.ts
@@ -47047,11 +48110,11 @@ const backgroundTransforms = [
47047
48110
  }
47048
48111
  ];
47049
48112
  function parseMediaBackground(value) {
47050
- const background = parseBackgroundContent(value);
48113
+ const background = parseRuntimeBackgroundContent(value);
47051
48114
  return background?.type === "image" || background?.type === "video" ? background : null;
47052
48115
  }
47053
48116
  function resolveBackgroundLayerStyle(value, fallbackToken, context) {
47054
- const background = parseBackgroundContent(value);
48117
+ const background = parseRuntimeBackgroundContent(value);
47055
48118
  const style = {};
47056
48119
  const gradient = background?.type === "gradient" ? isString(background.gradient) ? background.gradient.trim() : gradientPresetCss(background.gradientPresetId) : null;
47057
48120
  const color = background?.type === "color" && isString(background.color) ? background.color.trim() : null;