@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
@@ -8,6 +8,19 @@ const footerModeSchema = z.enum([
8
8
  "default+blocks",
9
9
  "none"
10
10
  ]);
11
+ z.object({
12
+ variant: z.enum([
13
+ "simple",
14
+ "columns",
15
+ "split",
16
+ "centred"
17
+ ]),
18
+ showLogoText: z.boolean().optional(),
19
+ logo: z.object({
20
+ showLogo: z.boolean().optional(),
21
+ showLogoText: z.boolean().optional()
22
+ }).optional()
23
+ });
11
24
  //#endregion
12
25
  //#region ../api/src/defineEndpointDefinitions.ts
13
26
  /**
@@ -1731,12 +1744,14 @@ const unsafeAsSiteId = (id) => id;
1731
1744
  const unsafeAsApiKeyId = (id) => id;
1732
1745
  const unsafeAsEventOfferingId = (id) => id;
1733
1746
  const unsafeAsEventSeriesId = (id) => id;
1747
+ const unsafeAsMediaAssetId = (id) => id;
1734
1748
  const unsafeAsUserId = (id) => id;
1735
1749
  const unsafeAsContentVersionId = (id) => id;
1736
1750
  const parseSiteId = (value) => parseUuidBrand(value, unsafeAsSiteId);
1737
1751
  const parseApiKeyId = (value) => parseUuidBrand(value, unsafeAsApiKeyId);
1738
1752
  const parseEventOfferingId = (value) => parseUuidBrand(value, unsafeAsEventOfferingId);
1739
1753
  const parseUserId = (value) => parseUuidBrand(value, unsafeAsUserId);
1754
+ const parseMediaAssetId = (value) => parseUuidBrand(value, unsafeAsMediaAssetId);
1740
1755
  const parseContentVersionId = (value) => parseUuidBrand(value, unsafeAsContentVersionId);
1741
1756
  const parseEventSeriesId = (value) => parseUuidBrand(value, unsafeAsEventSeriesId);
1742
1757
  //#endregion
@@ -2079,6 +2094,25 @@ function validateBookingPaymentOptionKinds(kinds) {
2079
2094
  return ok(void 0);
2080
2095
  }
2081
2096
  //#endregion
2097
+ //#region ../core/src/date-time-formatter.ts
2098
+ /** Shared Intl engine, internal to core's date presentation owners. */
2099
+ const FORMATTER_CACHE_LIMIT = 100;
2100
+ const dateTimeFormatterCache = /* @__PURE__ */ new Map();
2101
+ function getDateTimeFormatter(locale, timeZone, format) {
2102
+ const key = `${locale}\u0000${timeZone}\u0000${JSON.stringify(Object.entries(format).sort(([left], [right]) => left.localeCompare(right)))}`;
2103
+ const cached = dateTimeFormatterCache.get(key);
2104
+ if (cached !== void 0) return cached;
2105
+ if (typeof locale !== "string" || Intl.DateTimeFormat.supportedLocalesOf([locale]).length === 0) throw new RangeError("An explicit supported locale is required");
2106
+ if (typeof timeZone !== "string" || timeZone.length === 0) throw new RangeError("An explicit time zone is required");
2107
+ const formatter = new Intl.DateTimeFormat(locale, {
2108
+ ...format,
2109
+ timeZone
2110
+ });
2111
+ if (dateTimeFormatterCache.size >= FORMATTER_CACHE_LIMIT) dateTimeFormatterCache.clear();
2112
+ dateTimeFormatterCache.set(key, formatter);
2113
+ return formatter;
2114
+ }
2115
+ //#endregion
2082
2116
  //#region ../core/src/booking-time-zone.ts
2083
2117
  const TIME_ZONE_VALIDITY_CACHE_LIMIT = 100;
2084
2118
  const timeZoneValidityCache = /* @__PURE__ */ new Map();
@@ -2115,8 +2149,6 @@ const START_OF_DAY = {
2115
2149
  second: 0
2116
2150
  };
2117
2151
  const LOCAL_DATE_PATTERN = /^(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})$/u;
2118
- const DATE_TIME_FORMATTER_CACHE_LIMIT = 100;
2119
- const dateTimeFormatterCache = /* @__PURE__ */ new Map();
2120
2152
  function getSafeTimeZone(timeZone) {
2121
2153
  const normalized = typeof timeZone === "string" ? timeZone.trim() : "";
2122
2154
  return normalized.length > 0 && isValidBookingTimeZone(normalized) ? normalized : FALLBACK_TIMEZONE;
@@ -2133,19 +2165,7 @@ function formatParseError(error) {
2133
2165
  }
2134
2166
  }
2135
2167
  function formatToPartsLookup(date, locale, timeZone, format) {
2136
- return new Map(getCachedDateTimeFormatter(locale, timeZone, format).formatToParts(date).map((part) => [part.type, part.value]));
2137
- }
2138
- function getCachedDateTimeFormatter(locale, timeZone, format) {
2139
- const key = `${locale}\u0000${timeZone}\u0000${JSON.stringify(Object.entries(format).sort(([left], [right]) => left.localeCompare(right)))}`;
2140
- const cached = dateTimeFormatterCache.get(key);
2141
- if (cached !== void 0) return cached;
2142
- const formatter = new Intl.DateTimeFormat(locale, {
2143
- ...format,
2144
- timeZone
2145
- });
2146
- if (dateTimeFormatterCache.size >= DATE_TIME_FORMATTER_CACHE_LIMIT) dateTimeFormatterCache.clear();
2147
- dateTimeFormatterCache.set(key, formatter);
2148
- return formatter;
2168
+ return new Map(getDateTimeFormatter(locale, timeZone, format).formatToParts(date).map((part) => [part.type, part.value]));
2149
2169
  }
2150
2170
  function getZonedDateTimeParts(date, timeZone) {
2151
2171
  const parts = formatToPartsLookup(date, "en-GB", timeZone, {
@@ -2233,7 +2253,7 @@ function toScheduledBookingDateTime(input) {
2233
2253
  function formatBookingInstant(isoString, options) {
2234
2254
  const date = new Date(isoString);
2235
2255
  if (Number.isNaN(date.getTime())) return isoString;
2236
- return getCachedDateTimeFormatter(options.locale ?? DEFAULT_LOCALE, getSafeTimeZone(options.timeZone), options.format).format(date);
2256
+ return getDateTimeFormatter(options.locale ?? DEFAULT_LOCALE, getSafeTimeZone(options.timeZone), options.format).format(date);
2237
2257
  }
2238
2258
  function formatBookingDate(input, format = {
2239
2259
  weekday: "long",
@@ -2358,6 +2378,17 @@ function localScheduleDateTimeToUtcDate(localDate, localTime, timeZone) {
2358
2378
  return new Date(guess);
2359
2379
  }
2360
2380
  //#endregion
2381
+ //#region ../core/src/date-display.ts
2382
+ /** Site-language policy, shared by customer emails and public event adapters. */
2383
+ function inferSiteDateLocale(siteTimeZone) {
2384
+ if (siteTimeZone === null || siteTimeZone === void 0 || siteTimeZone === "") return "en-US";
2385
+ if (siteTimeZone === "Europe/Dublin") return "en-IE";
2386
+ if (siteTimeZone.startsWith("Europe/")) return "en-GB";
2387
+ if (siteTimeZone.startsWith("Australia/")) return "en-AU";
2388
+ if (siteTimeZone === "Pacific/Auckland" || siteTimeZone === "Pacific/Chatham") return "en-NZ";
2389
+ return "en-US";
2390
+ }
2391
+ //#endregion
2361
2392
  //#region ../core/src/location.ts
2362
2393
  function normalizeLocationAddressText(value) {
2363
2394
  if (typeof value !== "string") return null;
@@ -2387,7 +2418,7 @@ function parsePositiveInteger(value) {
2387
2418
  return typeof value === "number" && Number.isSafeInteger(value) && value > 0 ? value : null;
2388
2419
  }
2389
2420
  function parseNewsletterListId(value) {
2390
- return parseTrimmedMatchingString(value, UUID_PATTERN);
2421
+ return parseTrimmedMatchingString(typeof value === "string" ? value.toLowerCase() : value, UUID_PATTERN);
2391
2422
  }
2392
2423
  function parseMailchimpAccountId(value) {
2393
2424
  return parseTrimmedMatchingString(value, OPAQUE_ID_PATTERN);
@@ -2429,8 +2460,15 @@ function parseMailingListProviderScope(value) {
2429
2460
  }
2430
2461
  return err("invalid_mailing_list_provider_scope");
2431
2462
  }
2432
- //#endregion
2433
- //#region ../core/src/mailing-list-setup-parser.ts
2463
+ z.unknown().transform((value, ctx) => {
2464
+ const parsed = parseNewsletterAudience(value);
2465
+ if (parsed.ok) return parsed.value;
2466
+ ctx.addIssue({
2467
+ code: "custom",
2468
+ message: "Choose a valid newsletter audience."
2469
+ });
2470
+ return z.NEVER;
2471
+ });
2434
2472
  function parseMailingListGlobalForm(value) {
2435
2473
  if (!isRecord$9(value)) return formError("shape");
2436
2474
  const fields = parseGlobalFields(value.fields);
@@ -2450,6 +2488,16 @@ function parseMailingListGlobalForm(value) {
2450
2488
  privacyNote
2451
2489
  });
2452
2490
  }
2491
+ function parseNewsletterAudience(value) {
2492
+ if (!isRecord$9(value)) return err("invalid_newsletter_audience");
2493
+ if (value.kind === "general" && Object.keys(value).length === 1) return ok({ kind: "general" });
2494
+ if (value.kind !== "topic" || Object.keys(value).some((key) => key !== "kind" && key !== "topicId")) return err("invalid_newsletter_audience");
2495
+ const topicId = parseNewsletterListId(value.topicId);
2496
+ return topicId === null ? err("invalid_newsletter_audience") : ok({
2497
+ kind: "topic",
2498
+ topicId
2499
+ });
2500
+ }
2453
2501
  function parseGlobalFields(value) {
2454
2502
  if (!isRecord$9(value) || typeof value.preset !== "string") return null;
2455
2503
  switch (value.preset) {
@@ -2458,6 +2506,10 @@ function parseGlobalFields(value) {
2458
2506
  preset: "emailName",
2459
2507
  name: value.name
2460
2508
  } : null;
2509
+ case "emailFirstName": return isRequirement(value.firstName) ? {
2510
+ preset: "emailFirstName",
2511
+ firstName: value.firstName
2512
+ } : null;
2461
2513
  case "emailFirstLast": return isRequirement(value.firstName) && isRequirement(value.lastName) ? {
2462
2514
  preset: "emailFirstLast",
2463
2515
  firstName: value.firstName,
@@ -2502,54 +2554,49 @@ function formError(field) {
2502
2554
  const DEFAULT_MAILING_LIST_TARGETING = { mode: "default" };
2503
2555
  function mailingListTargetingChoiceIds(targeting) {
2504
2556
  switch (targeting.provider) {
2505
- case "native": return targeting.selection.tag === "fixed" ? targeting.selection.topicIds : targeting.selection.offeredTopicIds;
2557
+ case "native": return targeting.selection.tag === "general" ? [] : targeting.selection.tag === "fixed" ? targeting.selection.topicIds : targeting.selection.offeredTopicIds;
2506
2558
  case "brevo": return targeting.selection.tag === "fixed" ? targeting.selection.listIds : targeting.selection.offeredListIds;
2507
2559
  case "mailchimp": return targeting.selection.tag === "fixed" ? targeting.selection.interestIds : targeting.selection.offeredInterestIds;
2508
2560
  }
2509
2561
  }
2510
2562
  function planMailingListChoicePresentation(targeting) {
2511
- if (targeting.mode === "default" || targeting.selection.tag === "fixed") return { tag: "hidden" };
2563
+ if (targeting.mode === "default" || targeting.selection.tag === "fixed" || targeting.selection.tag === "general") return { tag: "hidden" };
2512
2564
  switch (targeting.provider) {
2513
- case "native": return targeting.selection.offeredTopicIds.length === 1 ? {
2514
- tag: "automatic",
2515
- selection: {
2516
- provider: "native",
2517
- topicIds: targeting.selection.offeredTopicIds
2518
- }
2519
- } : {
2520
- tag: "visitor_choice",
2565
+ case "native": return presentVisitorSelection({
2521
2566
  provider: "native",
2522
- optionCount: targeting.selection.offeredTopicIds.length
2523
- };
2524
- case "brevo": return targeting.selection.offeredListIds.length === 1 ? {
2525
- tag: "automatic",
2526
- selection: {
2527
- provider: "brevo",
2528
- listIds: targeting.selection.offeredListIds
2529
- }
2530
- } : {
2531
- tag: "visitor_choice",
2567
+ topicIds: targeting.selection.offeredTopicIds
2568
+ }, targeting.selection.offeredTopicIds.length);
2569
+ case "brevo": return presentVisitorSelection({
2532
2570
  provider: "brevo",
2533
- optionCount: targeting.selection.offeredListIds.length
2534
- };
2535
- case "mailchimp": return targeting.selection.offeredInterestIds.length === 1 ? {
2536
- tag: "automatic",
2537
- selection: {
2538
- provider: "mailchimp",
2539
- interestIds: targeting.selection.offeredInterestIds
2540
- }
2541
- } : {
2542
- tag: "visitor_choice",
2571
+ listIds: targeting.selection.offeredListIds
2572
+ }, targeting.selection.offeredListIds.length);
2573
+ case "mailchimp": return presentVisitorSelection({
2543
2574
  provider: "mailchimp",
2544
- optionCount: targeting.selection.offeredInterestIds.length
2545
- };
2575
+ interestIds: targeting.selection.offeredInterestIds
2576
+ }, targeting.selection.offeredInterestIds.length);
2546
2577
  }
2547
2578
  }
2579
+ function presentVisitorSelection(selection, optionCount) {
2580
+ return optionCount === 1 ? {
2581
+ tag: "automatic",
2582
+ selection
2583
+ } : {
2584
+ tag: "visitor_choice",
2585
+ provider: selection.provider,
2586
+ optionCount
2587
+ };
2588
+ }
2548
2589
  //#endregion
2549
2590
  //#region ../core/src/mailing-list-targeting-availability.ts
2550
2591
  function resolveMailingListDefaultDestination(provider) {
2551
2592
  switch (provider.provider) {
2552
- case "native": return provider.topics.find((item) => item.id === provider.defaultTopicId) ?? null;
2593
+ case "native": {
2594
+ const audience = provider.defaultAudience;
2595
+ return audience.kind === "general" ? {
2596
+ id: "general",
2597
+ name: "General mailing list"
2598
+ } : provider.topics.find((item) => item.id === audience.topicId) ?? null;
2599
+ }
2553
2600
  case "brevo": return provider.lists.find((item) => item.id === provider.defaultListId) ?? null;
2554
2601
  case "mailchimp": return provider.audiences.find((item) => item.id === provider.defaultAudienceId) ?? null;
2555
2602
  }
@@ -2687,11 +2734,12 @@ function parseRuntimeProvider(value) {
2687
2734
  }
2688
2735
  }
2689
2736
  function parseNativeRuntimeProvider(value) {
2690
- const defaultTopicId = parseNewsletterListId(value.defaultTopicId);
2737
+ if ("defaultTopicId" in value) return null;
2738
+ const defaultAudience = parseNewsletterAudience(value.defaultAudience);
2691
2739
  const topics = parseNamedItems(value.topics, parseNewsletterListId);
2692
- return defaultTopicId !== null && topics !== null ? {
2740
+ return defaultAudience.ok && topics !== null ? {
2693
2741
  provider: "native",
2694
- defaultTopicId,
2742
+ defaultAudience: defaultAudience.value,
2695
2743
  topics
2696
2744
  } : null;
2697
2745
  }
@@ -2776,6 +2824,11 @@ function parseMailingListPlacementTargeting(value) {
2776
2824
  }
2777
2825
  }
2778
2826
  function parseNativeTargeting(selection) {
2827
+ if (selection.tag === "general") return Object.keys(selection).length === 1 ? ok({
2828
+ mode: "custom",
2829
+ provider: "native",
2830
+ selection: { tag: "general" }
2831
+ }) : targetingError("selection");
2779
2832
  if (selection.tag === "fixed") {
2780
2833
  const topicIds = parseNonEmptyUniqueIds(selection.topicIds, parseNewsletterListId);
2781
2834
  return topicIds.ok ? ok({
@@ -4193,6 +4246,129 @@ const BILLING_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
4193
4246
  tags: ["billing"],
4194
4247
  auth: "user",
4195
4248
  responseKind: "json"
4249
+ },
4250
+ stripeConnectSetupStart: {
4251
+ path: "/sites/{siteId}/billing/connect/setup",
4252
+ method: "POST",
4253
+ tags: ["site-{siteId}", "stripe-connect"],
4254
+ auth: "user",
4255
+ responseKind: "json",
4256
+ errors: [
4257
+ "validation:invalid_input",
4258
+ "auth:forbidden",
4259
+ "resource:conflict",
4260
+ "server:internal_error"
4261
+ ]
4262
+ },
4263
+ stripeConnectSetupDiscard: {
4264
+ path: "/sites/{siteId}/billing/connect/setup",
4265
+ method: "DELETE",
4266
+ tags: ["site-{siteId}", "stripe-connect"],
4267
+ auth: "user",
4268
+ responseKind: "json",
4269
+ errors: [
4270
+ "validation:invalid_input",
4271
+ "auth:forbidden",
4272
+ "resource:conflict",
4273
+ "server:internal_error"
4274
+ ]
4275
+ },
4276
+ stripeConnectSetupSave: {
4277
+ path: "/sites/{siteId}/billing/connect/setup/save",
4278
+ method: "POST",
4279
+ tags: ["site-{siteId}", "stripe-connect"],
4280
+ auth: "user",
4281
+ responseKind: "json",
4282
+ errors: [
4283
+ "validation:invalid_input",
4284
+ "auth:forbidden",
4285
+ "resource:conflict",
4286
+ "server:internal_error"
4287
+ ]
4288
+ },
4289
+ stripeConnectAccountSession: {
4290
+ path: "/sites/{siteId}/billing/connect/session",
4291
+ method: "POST",
4292
+ tags: ["site-{siteId}", "stripe-connect"],
4293
+ auth: "user",
4294
+ responseKind: "json",
4295
+ errors: [
4296
+ "validation:invalid_input",
4297
+ "auth:forbidden",
4298
+ "resource:conflict",
4299
+ "server:internal_error"
4300
+ ]
4301
+ },
4302
+ stripeConnectStart: {
4303
+ path: "/sites/{siteId}/billing/connect/start",
4304
+ method: "POST",
4305
+ tags: ["site-{siteId}", "stripe-connect"],
4306
+ auth: "user",
4307
+ responseKind: "json",
4308
+ errors: [
4309
+ "validation:invalid_input",
4310
+ "auth:forbidden",
4311
+ "resource:conflict",
4312
+ "server:internal_error"
4313
+ ]
4314
+ },
4315
+ stripeConnectStatus: {
4316
+ path: "/sites/{siteId}/billing/connect/status",
4317
+ method: "GET",
4318
+ tags: ["site-{siteId}", "stripe-connect"],
4319
+ auth: "user",
4320
+ responseKind: "json",
4321
+ errors: [
4322
+ "validation:invalid_input",
4323
+ "auth:forbidden",
4324
+ "resource:conflict",
4325
+ "server:internal_error"
4326
+ ]
4327
+ },
4328
+ stripeAutomaticTaxUpdate: {
4329
+ path: "/sites/{siteId}/billing/automatic-tax",
4330
+ method: "POST",
4331
+ tags: [
4332
+ "site-{siteId}",
4333
+ "billing",
4334
+ "stripe-tax"
4335
+ ],
4336
+ auth: "user",
4337
+ responseKind: "json",
4338
+ errors: [
4339
+ "validation:invalid_input",
4340
+ "auth:forbidden",
4341
+ "resource:not_found",
4342
+ "server:unavailable",
4343
+ "server:internal_error"
4344
+ ]
4345
+ },
4346
+ stripeConnectDisconnect: {
4347
+ path: "/sites/{siteId}/billing/connect/disconnect",
4348
+ method: "DELETE",
4349
+ tags: ["site-{siteId}", "stripe-connect"],
4350
+ auth: "user",
4351
+ responseKind: "json",
4352
+ errors: [
4353
+ "validation:invalid_input",
4354
+ "auth:forbidden",
4355
+ "resource:conflict",
4356
+ "server:internal_error"
4357
+ ]
4358
+ },
4359
+ billingConnectReturn: {
4360
+ path: "/billing/connect/return",
4361
+ method: "GET",
4362
+ auth: "user",
4363
+ responseKind: "void",
4364
+ errors: []
4365
+ },
4366
+ billingConnectRefresh: {
4367
+ path: "/billing/connect/refresh",
4368
+ method: "GET",
4369
+ auth: "user",
4370
+ responseKind: "void",
4371
+ errors: []
4196
4372
  }
4197
4373
  });
4198
4374
  //#endregion
@@ -4357,6 +4533,14 @@ const PAGE_SURFACE_EDITOR_ENDPOINT_DEFINITIONS = {
4357
4533
  * person when nothing is attached to them.
4358
4534
  */
4359
4535
  const BOOKING_PEOPLE_ENDPOINT_DEFINITIONS = defineEndpointDefinitions({
4536
+ getBookingPerson: {
4537
+ path: "/sites/{siteId}/bookings/people/{personId}",
4538
+ method: "GET",
4539
+ tags: ["site-{siteId}", "customers-{siteId}"],
4540
+ auth: "user",
4541
+ responseKind: "json",
4542
+ errors: ["resource:not_found", "server:internal_error"]
4543
+ },
4360
4544
  listPeople: {
4361
4545
  path: "/sites/{siteId}/bookings/people",
4362
4546
  method: "GET",
@@ -7860,7 +8044,96 @@ const themeLookMetadataSchema = z.object({
7860
8044
  skinMarks: skinMarksSchema.optional()
7861
8045
  });
7862
8046
  //#endregion
7863
- //#region ../theme-core/src/lib/media.ts
8047
+ //#region ../media-core/src/identifiers.ts
8048
+ function slugifyMediaIdentifier(value) {
8049
+ return value.toLowerCase().trim().replace(/[^a-z0-9\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-");
8050
+ }
8051
+ function parseMediaIdentifier(value) {
8052
+ if (typeof value !== "string") return err({ kind: "not_string" });
8053
+ const trimmed = value.trim();
8054
+ if (trimmed.length === 0) return err({ kind: "empty_identifier" });
8055
+ const normalized = slugifyMediaIdentifier(trimmed);
8056
+ if (normalized.length === 0) return err({
8057
+ kind: "empty_after_normalization",
8058
+ value
8059
+ });
8060
+ return ok(normalized);
8061
+ }
8062
+ /**
8063
+ * Admits identifiers read from trusted persistence without repairing dirty data in memory.
8064
+ * User input should use parseMediaIdentifier, which intentionally canonicalizes it.
8065
+ */
8066
+ function parseCanonicalMediaIdentifier(value) {
8067
+ if (typeof value !== "string") return err({ kind: "not_string" });
8068
+ const parsed = parseMediaIdentifier(value);
8069
+ if (!parsed.ok) return parsed;
8070
+ if (value !== parsed.value) return err({
8071
+ kind: "non_canonical_identifier",
8072
+ value,
8073
+ canonical: parsed.value
8074
+ });
8075
+ return parsed;
8076
+ }
8077
+ //#endregion
8078
+ //#region ../media-core/src/mediaIdentifierSchema.ts
8079
+ /** Strict stored-reference admission delegates the canonical identifier decision. */
8080
+ const mediaIdentifierSchema = z.string().transform((value, context) => {
8081
+ const parsed = parseCanonicalMediaIdentifier(value);
8082
+ if (parsed.ok) return parsed.value;
8083
+ context.addIssue({
8084
+ code: "custom",
8085
+ message: "Expected a canonical media identifier"
8086
+ });
8087
+ return z.NEVER;
8088
+ });
8089
+ //#endregion
8090
+ //#region ../media-core/src/mediaKinds.ts
8091
+ const mediaTypeDiscriminants = [
8092
+ "image",
8093
+ "video",
8094
+ "audio",
8095
+ "document",
8096
+ "spreadsheet",
8097
+ "archive"
8098
+ ];
8099
+ //#endregion
8100
+ //#region ../media-core/src/renderableMediaAsset.ts
8101
+ /** A portable reference never uses an incidental UUID, URL or storage snapshot for identity. */
8102
+ function resolveManagedMediaReference(reference, index) {
8103
+ const asset = index?.byIdentifier.get(reference.identifier);
8104
+ return asset ? {
8105
+ kind: "resolved",
8106
+ reference,
8107
+ asset
8108
+ } : {
8109
+ kind: "missing",
8110
+ reference
8111
+ };
8112
+ }
8113
+ //#endregion
8114
+ //#region ../media-core/src/renderableMediaAssetAdmission.ts
8115
+ const mediaAssetIdSchema = z.string().transform((value, context) => {
8116
+ const parsed = parseMediaAssetId(value);
8117
+ if (parsed.ok) return parsed.value;
8118
+ context.addIssue({
8119
+ code: "custom",
8120
+ message: "Expected a media asset ID"
8121
+ });
8122
+ return z.NEVER;
8123
+ });
8124
+ const nonemptyStorageValue = z.string().refine((value) => value.trim().length > 0);
8125
+ const renderableMediaAssetSchema = z.object({
8126
+ id: mediaAssetIdSchema,
8127
+ identifier: mediaIdentifierSchema,
8128
+ storageBucket: nonemptyStorageValue,
8129
+ storagePath: nonemptyStorageValue,
8130
+ mimeType: nonemptyStorageValue,
8131
+ filename: z.string().optional(),
8132
+ width: z.number().positive().nullable(),
8133
+ height: z.number().positive().nullable()
8134
+ });
8135
+ //#endregion
8136
+ //#region ../media-core/src/media.ts
7864
8137
  const hotspotSchema = z.object({
7865
8138
  x: z.number().min(0).max(1),
7866
8139
  y: z.number().min(0).max(1),
@@ -7894,56 +8167,149 @@ const transformSchema = z.object({
7894
8167
  rotation: rotationSchema.optional()
7895
8168
  });
7896
8169
  const mediaPosterSchema = z.discriminatedUnion("tag", [z.object({
7897
- tag: z.literal("storage"),
7898
- assetId: z.string().optional(),
7899
- storageBucket: z.string().min(1),
7900
- storagePath: z.string().min(1)
7901
- }), z.object({
8170
+ tag: z.literal("media"),
8171
+ identifier: mediaIdentifierSchema
8172
+ }).strict(), z.object({
7902
8173
  tag: z.literal("external-src"),
7903
- assetId: z.string().optional(),
7904
8174
  src: z.string().url()
7905
- })]);
7906
- const mediaBaseSchema = z.object({
8175
+ }).strict()]);
8176
+ const mediaUsageShape = {
7907
8177
  purpose: z.string().optional(),
7908
8178
  placeholder: z.boolean().default(true).optional(),
7909
- assetId: z.string().optional(),
7910
- identifier: z.string().optional(),
7911
- src: z.string().optional(),
7912
8179
  alt: z.string().optional(),
7913
8180
  filename: z.string().optional(),
7914
- mimeType: z.string().optional(),
7915
8181
  width: z.number().optional(),
7916
8182
  height: z.number().optional(),
7917
- storageBucket: z.string().optional(),
7918
- storagePath: z.string().optional(),
7919
8183
  poster: mediaPosterSchema.optional(),
7920
8184
  transform: transformSchema.optional()
7921
- });
7922
- const mediaIdentifierSchema = z.string().trim().min(1).brand();
8185
+ };
8186
+ const environmentExclusions = {
8187
+ assetId: z.never().optional(),
8188
+ id: z.never().optional(),
8189
+ src: z.never().optional(),
8190
+ storageBucket: z.never().optional(),
8191
+ storagePath: z.never().optional(),
8192
+ mimeType: z.never().optional()
8193
+ };
8194
+ const mediaBaseSchema = z.object({
8195
+ ...mediaUsageShape,
8196
+ ...environmentExclusions,
8197
+ identifier: mediaIdentifierSchema
8198
+ }).strict();
7923
8199
  const imageMediaSchema = mediaBaseSchema.extend({ type: z.literal("image") });
7924
8200
  const videoMediaSchema = mediaBaseSchema.extend({ type: z.literal("video") });
7925
- const audioMediaSchema = mediaBaseSchema.extend({ type: z.literal("audio") });
7926
- const documentMediaSchema = mediaBaseSchema.extend({ type: z.literal("document") });
7927
- const spreadsheetMediaSchema = mediaBaseSchema.extend({ type: z.literal("spreadsheet") });
7928
- const archiveMediaSchema = mediaBaseSchema.extend({ type: z.literal("archive") });
7929
- const mediaSchema = z.discriminatedUnion("type", [
7930
- imageMediaSchema,
7931
- videoMediaSchema,
7932
- audioMediaSchema,
7933
- documentMediaSchema,
7934
- spreadsheetMediaSchema,
7935
- archiveMediaSchema
7936
- ]);
7937
- const persistableMediaBaseSchema = mediaBaseSchema.extend({ identifier: mediaIdentifierSchema });
7938
- z.discriminatedUnion("type", [
7939
- persistableMediaBaseSchema.extend({ type: z.literal("image") }),
7940
- persistableMediaBaseSchema.extend({ type: z.literal("video") }),
7941
- persistableMediaBaseSchema.extend({ type: z.literal("audio") }),
7942
- persistableMediaBaseSchema.extend({ type: z.literal("document") }),
7943
- persistableMediaBaseSchema.extend({ type: z.literal("spreadsheet") }),
7944
- persistableMediaBaseSchema.extend({ type: z.literal("archive") })
8201
+ const mediaSchema = mediaBaseSchema.extend({ type: z.enum(mediaTypeDiscriminants) });
8202
+ const externalMediaSchema = z.object({
8203
+ ...mediaUsageShape,
8204
+ ...environmentExclusions,
8205
+ type: z.enum(mediaTypeDiscriminants),
8206
+ src: z.string().min(1),
8207
+ identifier: z.never().optional()
8208
+ }).strict();
8209
+ const assetMediaSchema = z.object({
8210
+ ...mediaUsageShape,
8211
+ ...environmentExclusions,
8212
+ type: z.enum(mediaTypeDiscriminants),
8213
+ asset: renderableMediaAssetSchema,
8214
+ identifier: z.never().optional()
8215
+ }).strict();
8216
+ const runtimeMediaSchema = z.union([
8217
+ mediaSchema,
8218
+ externalMediaSchema,
8219
+ assetMediaSchema
7945
8220
  ]);
7946
8221
  //#endregion
8222
+ //#region ../media-core/src/transformRect.ts
8223
+ function isValidTransformRectStructure(rect) {
8224
+ if (!Array.isArray(rect) || rect.length !== 4) return false;
8225
+ const [left, top, width, height] = rect;
8226
+ return Number.isFinite(left) && Number.isFinite(top) && Number.isFinite(width) && Number.isFinite(height) && left >= 0 && top >= 0 && width > 0 && height > 0;
8227
+ }
8228
+ //#endregion
8229
+ //#region ../media-core/src/aspectTransforms.ts
8230
+ const DEFAULT_RECT_EPSILON = .5;
8231
+ function parseAspectRatioValue(value) {
8232
+ if (typeof value === "number") return Number.isFinite(value) && value > 0 ? value : void 0;
8233
+ if (typeof value !== "string") return void 0;
8234
+ const normalized = value.trim();
8235
+ if (!normalized) return void 0;
8236
+ if (normalized === "auto") return void 0;
8237
+ if (normalized.includes(":") || normalized.includes("/")) {
8238
+ const delimiter = normalized.includes(":") ? ":" : "/";
8239
+ const [wRaw, hRaw] = normalized.split(delimiter);
8240
+ const width = Number(wRaw?.trim());
8241
+ const height = Number(hRaw?.trim());
8242
+ if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) return;
8243
+ return width / height;
8244
+ }
8245
+ const numeric = Number(normalized);
8246
+ if (!Number.isFinite(numeric) || numeric <= 0) return void 0;
8247
+ return numeric;
8248
+ }
8249
+ const MAX_ASPECT_DISTANCE = .25;
8250
+ function resolveMediaTransformForAspect(transform, targetAspect) {
8251
+ if (!transform) return {};
8252
+ const base = {
8253
+ rect: transform.rect,
8254
+ hotspot: transform.hotspot,
8255
+ rotation: transform.rotation
8256
+ };
8257
+ const target = parseAspectRatioValue(targetAspect);
8258
+ const crops = transform.aspectCrops;
8259
+ if (!target || !crops || Object.keys(crops).length === 0) return base;
8260
+ let best = null;
8261
+ let bestDistance = Number.POSITIVE_INFINITY;
8262
+ for (const [key, candidate] of Object.entries(crops)) {
8263
+ const candidateAspect = parseAspectRatioValue(candidate.aspect ?? key);
8264
+ if (!candidateAspect) continue;
8265
+ const distance = Math.abs(Math.log(candidateAspect / target));
8266
+ if (distance < bestDistance) {
8267
+ best = candidate;
8268
+ bestDistance = distance;
8269
+ }
8270
+ }
8271
+ if (!best) return base;
8272
+ if (bestDistance > MAX_ASPECT_DISTANCE) return base;
8273
+ return {
8274
+ rect: best.rect ?? base.rect,
8275
+ hotspot: best.hotspot ?? base.hotspot,
8276
+ rotation: best.rotation ?? base.rotation
8277
+ };
8278
+ }
8279
+ function isValidTransformRect(rect) {
8280
+ return isValidTransformRectStructure(rect);
8281
+ }
8282
+ function isExplicitRectCrop(rect, sourceWidth, sourceHeight, epsilon = DEFAULT_RECT_EPSILON) {
8283
+ if (!isValidTransformRect(rect)) return false;
8284
+ if (!(typeof sourceWidth === "number" && Number.isFinite(sourceWidth) && sourceWidth > 0 && typeof sourceHeight === "number" && Number.isFinite(sourceHeight) && sourceHeight > 0)) return true;
8285
+ const [x, y, width, height] = rect;
8286
+ return !(Math.abs(x) <= epsilon && Math.abs(y) <= epsilon && Math.abs(width - sourceWidth) <= epsilon && Math.abs(height - sourceHeight) <= epsilon);
8287
+ }
8288
+ //#endregion
8289
+ //#region ../media-core/src/rotation.ts
8290
+ function rotateNormalizedPoint(point, rotation) {
8291
+ const x = point.x;
8292
+ const y = point.y;
8293
+ switch (rotation) {
8294
+ case 0: return {
8295
+ x,
8296
+ y
8297
+ };
8298
+ case 90: return {
8299
+ x: 1 - y,
8300
+ y: x
8301
+ };
8302
+ case 180: return {
8303
+ x: 1 - x,
8304
+ y: 1 - y
8305
+ };
8306
+ case 270: return {
8307
+ x: y,
8308
+ y: 1 - x
8309
+ };
8310
+ }
8311
+ }
8312
+ //#endregion
7947
8313
  //#region ../theme-core/src/palette/schema.ts
7948
8314
  const colourHexString = z.string().regex(/^#([0-9A-Fa-f]{3}){1,2}$/);
7949
8315
  const paletteColorSchema = z.object({
@@ -7972,6 +8338,29 @@ const paletteSchema = z.object({
7972
8338
  };
7973
8339
  });
7974
8340
  //#endregion
8341
+ //#region ../theme-core/src/buttons/typography.ts
8342
+ const textTransformSchema = z.enum([
8343
+ "none",
8344
+ "uppercase",
8345
+ "lowercase",
8346
+ "capitalize"
8347
+ ]);
8348
+ const fontWeightSchema = z.union([
8349
+ z.literal(400),
8350
+ z.literal(500),
8351
+ z.literal(600),
8352
+ z.literal(700),
8353
+ z.literal(800)
8354
+ ]);
8355
+ const buttonTypographySchema = z.enum(["body", "heading"]);
8356
+ const letterSpacingSchema = z.enum([
8357
+ "tight",
8358
+ "normal",
8359
+ "slight",
8360
+ "loose",
8361
+ "wide"
8362
+ ]);
8363
+ //#endregion
7975
8364
  //#region ../theme-core/src/buttons/types.ts
7976
8365
  /**
7977
8366
  * Standard semantic variant roles a theme exposes.
@@ -8087,6 +8476,7 @@ const buttonEffectApplicationSchema = z.discriminatedUnion("effectId", [
8087
8476
  z.strictObject({
8088
8477
  effectId: z.literal("lift"),
8089
8478
  options: z.strictObject({ amount: z.enum([
8479
+ "0.125",
8090
8480
  "0.25",
8091
8481
  "0.5",
8092
8482
  "1"
@@ -8133,24 +8523,6 @@ const shadowSizeSchema = z.enum([
8133
8523
  "medium",
8134
8524
  "high"
8135
8525
  ]);
8136
- const textTransformSchema = z.enum([
8137
- "none",
8138
- "uppercase",
8139
- "lowercase",
8140
- "capitalize"
8141
- ]);
8142
- const fontWeightSchema = z.union([
8143
- z.literal(500),
8144
- z.literal(600),
8145
- z.literal(700),
8146
- z.literal(800)
8147
- ]);
8148
- const buttonTypographySchema = z.enum(["body", "heading"]);
8149
- const letterSpacingSchema = z.enum([
8150
- "tight",
8151
- "normal",
8152
- "loose"
8153
- ]);
8154
8526
  const hoverTransformSchema = z.enum([
8155
8527
  "none",
8156
8528
  "lift",
@@ -8222,7 +8594,8 @@ const paddingShorthandSchema = z.string().refine((value) => {
8222
8594
  }, { message: "Padding must be two space-separated CSS length tokens (e.g. \"0.5rem 1rem\"). Use `0` for zero." });
8223
8595
  const buttonSizeConfigSchema = z.object({
8224
8596
  padding: paddingShorthandSchema,
8225
- fontSize: z.string().optional()
8597
+ fontSize: z.string().optional(),
8598
+ borderRadius: z.string().optional()
8226
8599
  });
8227
8600
  /**
8228
8601
  * `xl` is optional on the wire so themes persisted before the `xl` size was
@@ -8345,12 +8718,20 @@ const buttonVisualAppearanceSchema = z.strictObject({
8345
8718
  textTransform: textTransformSchema
8346
8719
  }),
8347
8720
  effects: z.array(buttonEffectApplicationSchema),
8721
+ transform: z.literal("none").optional(),
8348
8722
  contextualHover: contextualButtonHoverSchema.optional()
8349
8723
  });
8350
8724
  const buttonVisualStatesSchema = z.strictObject({
8351
8725
  base: buttonVisualAppearanceSchema.extend({ shadow: variantShadowSchema }),
8352
8726
  hover: buttonVisualAppearanceSchema.extend({ shadow: variantShadowSchema }),
8353
- focus: buttonVisualAppearanceSchema.extend({ shadow: z.literal("focus-indicator") }),
8727
+ focus: buttonVisualAppearanceSchema.extend({
8728
+ shadow: z.literal("focus-indicator"),
8729
+ indicator: z.strictObject({
8730
+ kind: z.literal("surface-ink"),
8731
+ width: z.union([z.literal(2), z.literal(3)]),
8732
+ offset: z.union([z.literal(3), z.literal(4)])
8733
+ }).optional()
8734
+ }),
8354
8735
  active: buttonVisualAppearanceSchema.extend({ shadow: variantShadowSchema }),
8355
8736
  disabled: buttonVisualAppearanceSchema.extend({ shadow: variantShadowSchema })
8356
8737
  });
@@ -8817,6 +9198,10 @@ function validateButtonTextContrast(input) {
8817
9198
  }
8818
9199
  };
8819
9200
  }
9201
+ /** A text-token slab inverts the palette's text/background pair, including text shades. */
9202
+ function solidForegroundToken(backgroundToken) {
9203
+ return /^text(?:-\d+)?$/.test(backgroundToken) ? "background" : onColorTokenName(backgroundToken);
9204
+ }
8820
9205
  //#endregion
8821
9206
  //#region ../theme-core/src/buttons/contextualHover.ts
8822
9207
  function resolveContextualHoverPreference(input) {
@@ -8914,7 +9299,7 @@ function candidate(family, shade, currentShade, direction, seedHex, palette) {
8914
9299
  }
8915
9300
  function hasSafeTextContrast(token, palette) {
8916
9301
  const background = palette[token];
8917
- const foreground = palette[onColorTokenName(token)];
9302
+ const foreground = palette[solidForegroundToken(token)];
8918
9303
  return typeof background === "string" && typeof foreground === "string" && contrastRatio(background, foreground) >= BUTTON_CONTRAST_POLICY.textMinimumRatio;
8919
9304
  }
8920
9305
  function isSafeCandidate(token, palette, surface) {
@@ -9009,6 +9394,13 @@ function compileDeclaredVisualStates(input, states) {
9009
9394
  const colours = collectStateColours(mapVisualStates((state) => compileDeclaredVisualState(input, states, state, state === "hover" ? hover.treatment : states[state].background)));
9010
9395
  return colours.ok ? {
9011
9396
  ...colours,
9397
+ focusIndicator: states.focus.indicator ? {
9398
+ kind: "surface-role",
9399
+ colorCss: input.surface?.foregroundCss ?? surfaceForegroundValue("text"),
9400
+ width: states.focus.indicator.width,
9401
+ offset: states.focus.indicator.offset,
9402
+ minimumSurfaceContrast: BUTTON_CONTRAST_POLICY.nonTextMinimumRatio
9403
+ } : colours.focusIndicator,
9012
9404
  contextualHoverRepair: hover.repair
9013
9405
  } : colours;
9014
9406
  }
@@ -9146,7 +9538,7 @@ function resolveFocusIndicator(colour) {
9146
9538
  function resolveSolid(input, backgroundToken, edge) {
9147
9539
  const backgroundHex = paletteHex(input, backgroundToken);
9148
9540
  if (!backgroundHex.ok) return backgroundHex;
9149
- const foregroundToken = unsafeAsOpaqueButtonColourToken(onColorTokenName(backgroundToken));
9541
+ const foregroundToken = unsafeAsOpaqueButtonColourToken(solidForegroundToken(backgroundToken));
9150
9542
  const foregroundHex = input.palette[foregroundToken];
9151
9543
  if (typeof foregroundHex !== "string") return {
9152
9544
  ok: false,
@@ -10320,6 +10712,287 @@ function normalizeAppearance(appearance) {
10320
10712
  };
10321
10713
  }
10322
10714
  //#endregion
10715
+ //#region ../theme-core/src/buttons/styles/recipes/lanternRecipes.ts
10716
+ const flatShadow = {
10717
+ elevation: "none",
10718
+ softness: null,
10719
+ position: "bottom"
10720
+ };
10721
+ const lift$1 = {
10722
+ effectId: "lift",
10723
+ options: { amount: "0.125" }
10724
+ };
10725
+ const tags = {
10726
+ tone: "classic",
10727
+ energy: "calm",
10728
+ motion: "subtle",
10729
+ era: "editorial"
10730
+ };
10731
+ /** Each role supplies complete states, including a flat surface-ink focus ring. */
10732
+ function states(base, hover, offset = 4, width = 2) {
10733
+ return {
10734
+ base,
10735
+ hover,
10736
+ focus: {
10737
+ ...base,
10738
+ shadow: "focus-indicator",
10739
+ indicator: {
10740
+ kind: "surface-ink",
10741
+ width,
10742
+ offset
10743
+ }
10744
+ },
10745
+ active: {
10746
+ ...base,
10747
+ transform: "none"
10748
+ },
10749
+ disabled: {
10750
+ ...base,
10751
+ effects: []
10752
+ }
10753
+ };
10754
+ }
10755
+ const gilt = {
10756
+ text: "treatment",
10757
+ border: "none",
10758
+ borderRadius: "rounded-10px",
10759
+ shadow: flatShadow,
10760
+ sizes: {
10761
+ sm: {
10762
+ padding: "10px 20px",
10763
+ fontSize: "text-base",
10764
+ borderRadius: "rounded-lg"
10765
+ },
10766
+ md: {
10767
+ padding: "18px 36px",
10768
+ fontSize: "text-19px"
10769
+ },
10770
+ lg: {
10771
+ padding: "18px 36px",
10772
+ fontSize: "text-19px"
10773
+ },
10774
+ xl: {
10775
+ padding: "18px 36px",
10776
+ fontSize: "text-19px"
10777
+ }
10778
+ },
10779
+ typography: {
10780
+ fontWeight: 400,
10781
+ typography: "heading",
10782
+ fontSize: "text-19px",
10783
+ letterSpacing: "slight",
10784
+ italic: false,
10785
+ textTransform: "none"
10786
+ },
10787
+ effects: []
10788
+ };
10789
+ const giltPrimary = {
10790
+ ...gilt,
10791
+ background: {
10792
+ type: "gradient",
10793
+ stops: ["accent", "primary"],
10794
+ direction: "to-br",
10795
+ foregroundToken: "onAccent"
10796
+ }
10797
+ };
10798
+ const giltPrimaryHover = {
10799
+ ...giltPrimary,
10800
+ background: {
10801
+ ...giltPrimary.background,
10802
+ stops: ["accent-400", "primary-400"],
10803
+ foregroundToken: "secondary-950"
10804
+ },
10805
+ effects: [lift$1]
10806
+ };
10807
+ const giltSecondary = {
10808
+ ...gilt,
10809
+ background: {
10810
+ type: "solid",
10811
+ colorToken: "text"
10812
+ }
10813
+ };
10814
+ const giltSecondaryHover = {
10815
+ ...giltSecondary,
10816
+ effects: [lift$1],
10817
+ contextualHover: {
10818
+ kind: "shade-shift",
10819
+ seedToken: unsafeAsOpaqueButtonColourToken("text"),
10820
+ fallbackDirection: "lighter"
10821
+ }
10822
+ };
10823
+ const giltPrimaryStates = states(giltPrimary, giltPrimaryHover);
10824
+ const giltSecondaryStates = states(giltSecondary, giltSecondaryHover);
10825
+ const giltSlabRecipe = defineStaticButtonStyleRecipe({
10826
+ id: "gilt-slab",
10827
+ accessibilityLabel: "Gilt slab",
10828
+ tags,
10829
+ system: { roles: {
10830
+ primary: { states: giltPrimaryStates },
10831
+ secondary: { states: giltSecondaryStates },
10832
+ outline: { states: giltSecondaryStates },
10833
+ ghost: { states: giltSecondaryStates },
10834
+ accent: { states: giltPrimaryStates }
10835
+ } }
10836
+ });
10837
+ const hairline = {
10838
+ text: "treatment",
10839
+ borderRadius: "rounded-3px",
10840
+ shadow: flatShadow,
10841
+ sizes: {
10842
+ sm: {
10843
+ padding: "9px 16px",
10844
+ fontSize: "text-xs"
10845
+ },
10846
+ md: {
10847
+ padding: "15px 28px",
10848
+ fontSize: "text-13px"
10849
+ },
10850
+ lg: {
10851
+ padding: "15px 28px",
10852
+ fontSize: "text-13px"
10853
+ },
10854
+ xl: {
10855
+ padding: "15px 28px",
10856
+ fontSize: "text-13px"
10857
+ }
10858
+ },
10859
+ typography: {
10860
+ fontWeight: 700,
10861
+ typography: "body",
10862
+ fontSize: "text-13px",
10863
+ letterSpacing: "wide",
10864
+ italic: false,
10865
+ textTransform: "uppercase"
10866
+ },
10867
+ effects: []
10868
+ };
10869
+ const hairlinePrimary = {
10870
+ ...hairline,
10871
+ background: {
10872
+ type: "solid",
10873
+ colorToken: "primary"
10874
+ },
10875
+ border: {
10876
+ widthClass: "border",
10877
+ boundaryInk: unsafeAsOpaqueButtonColourToken("primary")
10878
+ }
10879
+ };
10880
+ const hairlineOutline = {
10881
+ ...hairline,
10882
+ background: {
10883
+ type: "surface",
10884
+ role: "link"
10885
+ },
10886
+ border: {
10887
+ widthClass: "border",
10888
+ boundaryInk: unsafeAsOpaqueButtonColourToken("primary")
10889
+ }
10890
+ };
10891
+ const hairlineSecondary = {
10892
+ ...hairlineOutline,
10893
+ border: {
10894
+ widthClass: "border",
10895
+ boundaryInk: unsafeAsOpaqueButtonColourToken("accent")
10896
+ }
10897
+ };
10898
+ const hairlineFilled = {
10899
+ ...hairlineSecondary,
10900
+ background: {
10901
+ type: "solid",
10902
+ colorToken: "accent"
10903
+ }
10904
+ };
10905
+ const hairlinePrimaryStates = states(hairlinePrimary, hairlineOutline, 3);
10906
+ const hairlineSecondaryStates = states(hairlineSecondary, hairlineFilled, 3);
10907
+ const hairlineTabRecipe = defineStaticButtonStyleRecipe({
10908
+ id: "hairline-tab",
10909
+ accessibilityLabel: "Hairline tab",
10910
+ tags,
10911
+ system: { roles: {
10912
+ primary: { states: hairlinePrimaryStates },
10913
+ secondary: { states: hairlineSecondaryStates },
10914
+ outline: { states: hairlineSecondaryStates },
10915
+ ghost: { states: hairlineSecondaryStates },
10916
+ accent: { states: states(hairlineFilled, hairlineSecondary, 3) }
10917
+ } }
10918
+ });
10919
+ const marqueeAccent = {
10920
+ text: "treatment",
10921
+ borderRadius: "rounded-none",
10922
+ shadow: flatShadow,
10923
+ sizes: {
10924
+ sm: {
10925
+ padding: "8px 17px",
10926
+ fontSize: "text-15px"
10927
+ },
10928
+ md: {
10929
+ padding: "14px 25px",
10930
+ fontSize: "text-17px"
10931
+ },
10932
+ lg: {
10933
+ padding: "14px 25px",
10934
+ fontSize: "text-17px"
10935
+ },
10936
+ xl: {
10937
+ padding: "14px 25px",
10938
+ fontSize: "text-17px"
10939
+ }
10940
+ },
10941
+ typography: {
10942
+ fontWeight: 800,
10943
+ typography: "body",
10944
+ fontSize: "text-17px",
10945
+ letterSpacing: "loose",
10946
+ italic: false,
10947
+ textTransform: "uppercase"
10948
+ },
10949
+ effects: [],
10950
+ background: {
10951
+ type: "solid",
10952
+ colorToken: "accent"
10953
+ },
10954
+ border: {
10955
+ widthClass: "border-2",
10956
+ boundaryInk: unsafeAsOpaqueButtonColourToken("accent")
10957
+ }
10958
+ };
10959
+ const marqueePrimary = {
10960
+ ...marqueeAccent,
10961
+ background: {
10962
+ type: "solid",
10963
+ colorToken: "primary"
10964
+ },
10965
+ border: {
10966
+ widthClass: "border-2",
10967
+ boundaryInk: unsafeAsOpaqueButtonColourToken("primary")
10968
+ }
10969
+ };
10970
+ const marqueeSecondary = {
10971
+ ...marqueeAccent,
10972
+ background: {
10973
+ type: "solid",
10974
+ colorToken: "text"
10975
+ },
10976
+ border: {
10977
+ widthClass: "border-2",
10978
+ boundaryInk: unsafeAsOpaqueButtonColourToken("text")
10979
+ }
10980
+ };
10981
+ const marqueePrimaryStates = states(marqueeAccent, marqueePrimary, 4, 3);
10982
+ const marqueeSecondaryStates = states(marqueeSecondary, marqueeAccent, 4, 3);
10983
+ const marqueeRecipe = defineStaticButtonStyleRecipe({
10984
+ id: "marquee",
10985
+ accessibilityLabel: "Marquee",
10986
+ tags,
10987
+ system: { roles: {
10988
+ primary: { states: marqueePrimaryStates },
10989
+ secondary: { states: marqueeSecondaryStates },
10990
+ outline: { states: marqueeSecondaryStates },
10991
+ ghost: { states: marqueeSecondaryStates },
10992
+ accent: { states: marqueePrimaryStates }
10993
+ } }
10994
+ });
10995
+ //#endregion
10323
10996
  //#region ../theme-core/src/buttons/styles/recipes/fulcrumRecipe.ts
10324
10997
  const fulcrumSizes = {
10325
10998
  sm: {
@@ -11061,7 +11734,10 @@ const BUTTON_STYLE_IDS = [
11061
11734
  "offset-block",
11062
11735
  "ringed-pill",
11063
11736
  "square-outline",
11064
- "fulcrum"
11737
+ "fulcrum",
11738
+ "gilt-slab",
11739
+ "hairline-tab",
11740
+ "marquee"
11065
11741
  ];
11066
11742
  const quietArrowParametersSchema = z.object({ secondaryTreatment: z.enum(["outlined", "solid-accent"]) }).strict();
11067
11743
  const flatInkHoverTreatmentSchema = z.enum([
@@ -11098,7 +11774,10 @@ const buttonStyleSelectionSchema = z.discriminatedUnion("styleId", [
11098
11774
  selectionBranch("offset-block", emptyParametersSchema),
11099
11775
  selectionBranch("ringed-pill", emptyParametersSchema),
11100
11776
  selectionBranch("square-outline", emptyParametersSchema),
11101
- selectionBranch("fulcrum", emptyParametersSchema)
11777
+ selectionBranch("fulcrum", emptyParametersSchema),
11778
+ selectionBranch("gilt-slab", emptyParametersSchema),
11779
+ selectionBranch("hairline-tab", emptyParametersSchema),
11780
+ selectionBranch("marquee", emptyParametersSchema)
11102
11781
  ]);
11103
11782
  //#endregion
11104
11783
  //#region ../theme-core/src/buttons/styles/recipes/quietArrow.ts
@@ -14614,7 +15293,10 @@ const buttonStyleRecipes = [
14614
15293
  offsetBlockRecipe,
14615
15294
  ringedPillRecipe,
14616
15295
  squareOutlineRecipe,
14617
- fulcrumRecipe
15296
+ fulcrumRecipe,
15297
+ giltSlabRecipe,
15298
+ hairlineTabRecipe,
15299
+ marqueeRecipe
14618
15300
  ];
14619
15301
  const recipesById = new Map(buttonStyleRecipes.map((recipe) => [recipe.id, recipe]));
14620
15302
  function findButtonStyleRecipe(id) {
@@ -14630,6 +15312,9 @@ function resolveButtonStyleSelection(selection) {
14630
15312
  case "editorial-link": return resolveButtonStyleRecipe(editorialLinkRecipe, selection.parameters);
14631
15313
  case "pebble": return resolveButtonStyleRecipe(pebbleRecipe, selection.parameters);
14632
15314
  case "ink-stamp": return resolveButtonStyleRecipe(inkStampRecipe, selection.parameters);
15315
+ case "gilt-slab": return resolveButtonStyleRecipe(giltSlabRecipe, selection.parameters);
15316
+ case "hairline-tab": return resolveButtonStyleRecipe(hairlineTabRecipe, selection.parameters);
15317
+ case "marquee": return resolveButtonStyleRecipe(marqueeRecipe, selection.parameters);
14633
15318
  case "fulcrum": return resolveButtonStyleRecipe(fulcrumRecipe, selection.parameters);
14634
15319
  case "flat-ink": return resolveButtonStyleRecipe(flatInkRecipe, selection.parameters);
14635
15320
  case "brushed-wash": return resolveButtonStyleRecipe(brushedWashRecipe, selection.parameters);
@@ -16492,6 +17177,21 @@ const boxBackgroundSchema = z.discriminatedUnion("type", [
16492
17177
  showVideoOnMobile: z.boolean().nullable().optional()
16493
17178
  })
16494
17179
  ]);
17180
+ /** Application rendering sources are admitted separately from saved references. */
17181
+ const runtimeBoxBackgroundSchema = z.discriminatedUnion("type", [
17182
+ boxBackgroundSchema.options[0],
17183
+ boxBackgroundSchema.options[1],
17184
+ boxBackgroundSchema.options[2].extend({ image: z.union([
17185
+ imageMediaSchema,
17186
+ externalMediaSchema.extend({ type: z.literal("image") }),
17187
+ assetMediaSchema.extend({ type: z.literal("image") })
17188
+ ]).nullable().optional() }),
17189
+ boxBackgroundSchema.options[3].extend({ image: z.union([
17190
+ videoMediaSchema,
17191
+ externalMediaSchema.extend({ type: z.literal("video") }),
17192
+ assetMediaSchema.extend({ type: z.literal("video") })
17193
+ ]).nullable().optional() })
17194
+ ]);
16495
17195
  function normalizeAuthoringOpacity(value) {
16496
17196
  if (!isRecord$6(value)) return value;
16497
17197
  return {
@@ -16846,20 +17546,15 @@ const headerSchema = z.object({
16846
17546
  const footerVariant = z.enum([
16847
17547
  "simple",
16848
17548
  "columns",
16849
- "split"
16850
- ]);
17549
+ "split",
17550
+ "centred"
17551
+ ]).transform((value) => value === "columns" ? "simple" : value);
16851
17552
  const footerMaxWidth = z.enum(["container", "full"]);
16852
17553
  const footerNavLayoutMode = z.enum([
16853
17554
  "stack",
16854
17555
  "inline",
16855
17556
  "inline-wrap"
16856
17557
  ]);
16857
- const footerNavLayoutAlign = z.enum([
16858
- "start",
16859
- "center",
16860
- "end",
16861
- "space-between"
16862
- ]);
16863
17558
  const footerSpacing = z.enum([
16864
17559
  "none",
16865
17560
  "tight",
@@ -16868,12 +17563,6 @@ const footerSpacing = z.enum([
16868
17563
  "relaxed",
16869
17564
  "spacious"
16870
17565
  ]);
16871
- const footerLogoPlacement = z.enum([
16872
- "left",
16873
- "right",
16874
- "above",
16875
- "below"
16876
- ]);
16877
17566
  const footerLogoSize = z.enum([
16878
17567
  "sm",
16879
17568
  "md",
@@ -16914,17 +17603,8 @@ const footerBottomBarSchema = z.object({
16914
17603
  ]).optional()
16915
17604
  }).optional()
16916
17605
  });
16917
- const footerNavLayoutSchema = z.object({
16918
- layout: footerNavLayoutMode.optional(),
16919
- align: footerNavLayoutAlign.optional(),
16920
- gapX: footerSpacing.optional(),
16921
- gapY: footerSpacing.optional(),
16922
- columns: z.number().int().min(1).max(6).optional()
16923
- });
17606
+ const footerNavLayoutSchema = z.object({ layout: footerNavLayoutMode.optional() });
16924
17607
  const footerLogoSchema = z.object({
16925
- showLogo: z.boolean().default(true),
16926
- showLogoText: z.boolean().optional(),
16927
- placement: footerLogoPlacement.optional(),
16928
17608
  size: footerLogoSize.optional(),
16929
17609
  maxHeight: footerLogoMaxHeight.optional(),
16930
17610
  align: z.enum([
@@ -16934,15 +17614,8 @@ const footerLogoSchema = z.object({
16934
17614
  ]).optional()
16935
17615
  });
16936
17616
  const footerSchema = z.object({
16937
- /**
16938
- * SDK-only footer rendering mode.
16939
- *
16940
- * Historical persisted field; SDK rendering mode now lives in layout.footerMode.
16941
- */
16942
- mode: footerModeSchema.optional(),
16943
17617
  variant: footerVariant,
16944
17618
  maxWidth: footerMaxWidth,
16945
- showLogoText: z.boolean().optional(),
16946
17619
  background: headerBackgroundSchema.default({
16947
17620
  type: "color",
16948
17621
  color: "surface"
@@ -17125,7 +17798,9 @@ const cardListKnobBlocks = [...cardListFamilyBlocks, "block.event-calendar"];
17125
17798
  const lookKnobBlocks = {
17126
17799
  actionStyle: cardListKnobBlocks,
17127
17800
  titleSize: "block.hero",
17128
- imagePosition: "block.hero",
17801
+ imagePosition: ["block.hero", "block.media-text"],
17802
+ imageShape: "block.media-text",
17803
+ aspectRatio: "block.media-text",
17129
17804
  stickerLine: "block.hero",
17130
17805
  smallCaption: "block.hero",
17131
17806
  candleGlow: "block.hero",
@@ -17135,7 +17810,11 @@ const lookKnobBlocks = {
17135
17810
  dates: "block.offerings-preview",
17136
17811
  showCapacity: "block.event-calendar",
17137
17812
  quoteCount: "block.testimonials",
17138
- archFrame: "block.testimonials",
17813
+ archFrame: [
17814
+ "block.testimonials",
17815
+ "block.newsletter-signup",
17816
+ "block.form"
17817
+ ],
17139
17818
  tilt: "block.testimonials"
17140
17819
  };
17141
17820
  function isArrangementAppearancePreset(preset) {
@@ -17162,13 +17841,25 @@ function cardListKnobDefaults(block, arrangement, knobs, defaults) {
17162
17841
  }
17163
17842
  };
17164
17843
  }
17844
+ const arrangementLookTargets = {
17845
+ hero: "hero",
17846
+ "feature-cards": "feature-cards",
17847
+ "event-calendar": "events",
17848
+ testimonials: "testimonials",
17849
+ "event-details": "events",
17850
+ "media-text": "media-text",
17851
+ "image-gallery": "image-gallery",
17852
+ "newsletter-signup": "newsletter",
17853
+ form: "contact-form",
17854
+ "body-text": "body-text"
17855
+ };
17165
17856
  function defineArrangementLook(id, block, name, arrangement, knobs, input = {}) {
17166
17857
  const mode = block === "event-calendar" ? "list" : null;
17167
17858
  return {
17168
17859
  id: asAppearancePresetId(id),
17169
17860
  blockKinds: [`block.${block}`],
17170
17861
  label: name,
17171
- target: block === "event-calendar" || block === "event-details" ? "events" : block === "hero" ? "hero" : block === "testimonials" ? "testimonials" : "feature-cards",
17862
+ target: arrangementLookTargets[block],
17172
17863
  structure: {
17173
17864
  kind: "arrangement",
17174
17865
  byMode: { [mode ?? "default"]: arrangement },
@@ -17988,6 +18679,15 @@ const appearancePresets = [
17988
18679
  eyebrowTreatment: "accent"
17989
18680
  }
17990
18681
  }),
18682
+ defineArrangementLook("body-text-reading-column", "body-text", "Reading column", "prose", []),
18683
+ defineArrangementLook("form-beside-introduction-arched-panel", "form", "Introduction beside an arched form", "two-column", [], { slotRoles: { panel: "card" } }),
18684
+ defineArrangementLook("newsletter-signup-in-arch", "newsletter-signup", "Signup in an arch", "arch", []),
18685
+ defineArrangementLook("image-gallery-square-tiles", "image-gallery", "Square tiles", "tiles", []),
18686
+ defineArrangementLook("image-gallery-arched-captions", "image-gallery", "Arched photos with captions", "tiles", [], { styleFallback: [id$1("image-gallery-square-tiles")] }),
18687
+ defineArrangementLook("media-text-circle-beside-text", "media-text", "Circle beside the text", "circle-beside", ["imagePosition"], { forcedKnobs: {
18688
+ imageShape: "circle",
18689
+ aspectRatio: "1/1"
18690
+ } }),
17991
18691
  defineArrangementLook("hero-photo-beside-text", "hero", "Photo beside the text", "split", heroKnobs, { slotRoles: { sticker: "highlight" } }),
17992
18692
  defineArrangementLook("hero-headline-row", "hero", "Big headline, then text and photo", "headline-row", heroKnobs, {
17993
18693
  slotRoles: { sticker: "highlight" },
@@ -18573,6 +19273,49 @@ function requireThemeColorToken$1(value) {
18573
19273
  return token;
18574
19274
  }
18575
19275
  //#endregion
19276
+ //#region ../theme-core/src/header/rootPaint.ts
19277
+ /** The nav container takes precedence when a floating header also has one. */
19278
+ function headerRootPaint(header) {
19279
+ const navContainerType = header?.navContainer?.type ?? "none";
19280
+ if (navContainerType === "glass" || navContainerType === "pill") return "contained-nav";
19281
+ return header?.variant === "floating" ? "overlay" : "own-surface";
19282
+ }
19283
+ //#endregion
19284
+ //#region ../theme-core/src/site-styles/siteChromeBackgrounds.ts
19285
+ const siteChromeBackgroundColorTokens = toSiteChromeBackgroundColorTokens(backgroundAppearanceColorTokenNames);
19286
+ const quickSiteChromeBackgroundColorTokens = toSiteChromeBackgroundColorTokens(backgroundAppearanceQuickColorTokenNames);
19287
+ siteChromeBackgroundColorTokens.filter((token) => !quickSiteChromeBackgroundColorTokens.includes(token));
19288
+ function parseSiteChromeBackgroundColorToken(value) {
19289
+ const token = parseBackgroundAppearanceColorToken(value);
19290
+ return token ? token : null;
19291
+ }
19292
+ function toSiteChromeBackgroundColorTokens(tokenNames) {
19293
+ return tokenNames.flatMap((name) => {
19294
+ const token = parseSiteChromeBackgroundColorToken(name);
19295
+ return token ? [token] : [];
19296
+ });
19297
+ }
19298
+ const backgroundColorTokenSchema = z.unknown().transform((value, ctx) => {
19299
+ const token = parseSiteChromeBackgroundColorToken(value);
19300
+ if (token === null) {
19301
+ ctx.addIssue({
19302
+ code: "custom",
19303
+ message: "Unknown site chrome background colour token"
19304
+ });
19305
+ return z.NEVER;
19306
+ }
19307
+ return token;
19308
+ });
19309
+ const siteChromeBackgroundOverrideSchema = z.discriminatedUnion("kind", [z.object({ kind: z.literal("default") }).strict(), z.object({
19310
+ kind: z.literal("color"),
19311
+ token: backgroundColorTokenSchema
19312
+ }).strict()]);
19313
+ z.object({
19314
+ background: siteChromeBackgroundOverrideSchema,
19315
+ navigationLayout: z.enum(["inline-wrap", "stack"])
19316
+ }).strict();
19317
+ z.object({ background: siteChromeBackgroundOverrideSchema }).strict();
19318
+ //#endregion
18576
19319
  //#region ../theme-core/src/site-styles/compilationPlan.ts
18577
19320
  const defaultHeaderBrandPreferences = {
18578
19321
  brandDisplay: "auto",
@@ -18733,6 +19476,9 @@ function fallbackEndsAtOffer(entry, mode, style, catalogue, visited) {
18733
19476
  appearancePresets.filter(isArrangementAppearancePreset);
18734
19477
  /** Closed structural hooks shared by block arrangements and bounded skins. */
18735
19478
  const arrangementSlotNames = [
19479
+ "contact",
19480
+ "social",
19481
+ "base",
18736
19482
  "section",
18737
19483
  "stack",
18738
19484
  "inline",
@@ -18819,6 +19565,238 @@ function validateOfferKnobs(style, catalogue) {
18819
19565
  });
18820
19566
  }
18821
19567
  //#endregion
19568
+ //#region ../theme-core/src/site-styles/footerLookDefaults.ts
19569
+ const defaultFooterLookRecipes = {
19570
+ "footer-centred-name": {
19571
+ arrangement: "centred",
19572
+ ground: {
19573
+ kind: "token",
19574
+ token: "surface"
19575
+ },
19576
+ nav: {
19577
+ weight: "regular",
19578
+ colorToken: "text",
19579
+ hoverColorToken: "primary",
19580
+ typography: "body"
19581
+ },
19582
+ legal: {
19583
+ kind: "separate",
19584
+ bar: null
19585
+ },
19586
+ brandAlign: "center"
19587
+ },
19588
+ "footer-links-row": {
19589
+ arrangement: "simple",
19590
+ ground: {
19591
+ kind: "token",
19592
+ token: "surface"
19593
+ },
19594
+ nav: {
19595
+ weight: "regular",
19596
+ colorToken: "text",
19597
+ hoverColorToken: "primary",
19598
+ typography: "body"
19599
+ },
19600
+ legal: { kind: "integrated" },
19601
+ brandAlign: "start"
19602
+ }
19603
+ };
19604
+ /** A whole authored recipe replaces the default; facets are never deep-merged. */
19605
+ function resolveFooterLookRecipe(style, id) {
19606
+ return style?.footerLookRecipes?.[id] ?? defaultFooterLookRecipes[id];
19607
+ }
19608
+ //#endregion
19609
+ //#region ../theme-core/src/navigation/presets.ts
19610
+ /**
19611
+ * Built-in nav link style presets
19612
+ *
19613
+ * Each preset uses composable effects to achieve its look.
19614
+ */
19615
+ const NAV_LINK_PRESETS = {
19616
+ /**
19617
+ * Minimal - subtle color change on hover
19618
+ */
19619
+ minimal: {
19620
+ name: "Minimal",
19621
+ typography: "body",
19622
+ fontWeight: "medium",
19623
+ textTransform: "none",
19624
+ italic: false,
19625
+ colorToken: "text",
19626
+ hoverColorToken: "primary",
19627
+ padding: "none",
19628
+ borderRadius: "none",
19629
+ effects: { hover: [{
19630
+ effectId: "text-color-change",
19631
+ options: { hoverColorToken: "primary" }
19632
+ }] }
19633
+ },
19634
+ /**
19635
+ * Underline - static underline appears on hover
19636
+ */
19637
+ underline: {
19638
+ name: "Underline",
19639
+ typography: "body",
19640
+ fontWeight: "medium",
19641
+ textTransform: "none",
19642
+ italic: false,
19643
+ colorToken: "text",
19644
+ padding: "none",
19645
+ borderRadius: "none",
19646
+ effects: { hover: [{
19647
+ effectId: "nav-underline",
19648
+ options: { style: "static" }
19649
+ }] }
19650
+ },
19651
+ /**
19652
+ * Underline Grow - animated underline grows from center on hover
19653
+ */
19654
+ "underline-grow": {
19655
+ name: "Underline Grow",
19656
+ typography: "body",
19657
+ fontWeight: "medium",
19658
+ textTransform: "none",
19659
+ italic: false,
19660
+ colorToken: "text",
19661
+ padding: "none",
19662
+ borderRadius: "none",
19663
+ effects: { hover: [{
19664
+ effectId: "nav-underline",
19665
+ options: { style: "grow" }
19666
+ }] }
19667
+ },
19668
+ /**
19669
+ * Capsule - pill-shaped background on hover
19670
+ */
19671
+ capsule: {
19672
+ name: "Capsule",
19673
+ typography: "body",
19674
+ fontWeight: "medium",
19675
+ textTransform: "none",
19676
+ italic: false,
19677
+ colorToken: "text",
19678
+ padding: "compact",
19679
+ borderRadius: "full",
19680
+ effects: {
19681
+ hover: [{
19682
+ effectId: "background-on-hover-alpha",
19683
+ options: {
19684
+ colorToken: "primary",
19685
+ opacity: 10
19686
+ }
19687
+ }],
19688
+ active: [{
19689
+ effectId: "background-on-hover-alpha",
19690
+ options: {
19691
+ colorToken: "primary",
19692
+ opacity: 15
19693
+ }
19694
+ }]
19695
+ }
19696
+ },
19697
+ /**
19698
+ * Solid - solid background color on hover
19699
+ */
19700
+ solid: {
19701
+ name: "Solid",
19702
+ typography: "body",
19703
+ fontWeight: "medium",
19704
+ textTransform: "none",
19705
+ italic: false,
19706
+ colorToken: "text",
19707
+ padding: "compact",
19708
+ borderRadius: "none",
19709
+ effects: {
19710
+ hover: [{
19711
+ effectId: "background-on-hover",
19712
+ options: {
19713
+ colorToken: "primary",
19714
+ textColorToken: "primaryForeground"
19715
+ }
19716
+ }],
19717
+ active: [{
19718
+ effectId: "background-on-hover",
19719
+ options: {
19720
+ colorToken: "primary",
19721
+ textColorToken: "primaryForeground"
19722
+ }
19723
+ }]
19724
+ }
19725
+ },
19726
+ /**
19727
+ * Scale - gentle scale-up on hover
19728
+ */
19729
+ scale: {
19730
+ name: "Scale",
19731
+ typography: "body",
19732
+ fontWeight: "medium",
19733
+ textTransform: "none",
19734
+ italic: false,
19735
+ colorToken: "text",
19736
+ padding: "none",
19737
+ borderRadius: "none",
19738
+ effects: { hover: [{
19739
+ effectId: "scale-up",
19740
+ options: { scale: 1.05 }
19741
+ }] }
19742
+ },
19743
+ /**
19744
+ * Frosted - semi-transparent glass-like background
19745
+ */
19746
+ frosted: {
19747
+ name: "Frosted",
19748
+ typography: "body",
19749
+ fontWeight: "medium",
19750
+ textTransform: "none",
19751
+ italic: false,
19752
+ colorToken: "text",
19753
+ padding: "compact",
19754
+ borderRadius: "md",
19755
+ effects: {
19756
+ base: [{ effectId: "nav-frosted-base" }],
19757
+ hover: [{ effectId: "nav-frosted-hover" }],
19758
+ active: [{ effectId: "nav-frosted-active" }]
19759
+ }
19760
+ }
19761
+ };
19762
+ /**
19763
+ * Get a nav link style preset by ID
19764
+ */
19765
+ function getNavLinkPreset(presetId) {
19766
+ return NAV_LINK_PRESETS[presetId];
19767
+ }
19768
+ Object.keys(NAV_LINK_PRESETS);
19769
+ //#endregion
19770
+ //#region ../theme-core/src/footer/effectiveNavLinkStyle.ts
19771
+ function effectiveFooterNavLinkStyle(footer) {
19772
+ if (!footer) return null;
19773
+ if (footer.navLinkStyle) return footer.navLinkStyle;
19774
+ const basePreset = getNavLinkPreset(footer.navStyle ?? "minimal");
19775
+ if (!basePreset) return null;
19776
+ return {
19777
+ ...basePreset,
19778
+ fontWeight: footer.navWeight ?? basePreset.fontWeight,
19779
+ colorToken: footer.navColor?.trim() || basePreset.colorToken
19780
+ };
19781
+ }
19782
+ function footerForegroundCandidates(footer, proseHoverCandidate) {
19783
+ if (!footer) return {};
19784
+ const style = effectiveFooterNavLinkStyle(footer);
19785
+ return {
19786
+ text: footer.background?.textColor ?? (footer.variant === "centred" ? "text" : void 0),
19787
+ link: style?.colorToken ?? footer.navColor ?? footer.background?.textColor,
19788
+ linkHover: navLinkOwnsHoverForeground(style) ? proseHoverCandidate : navLinkHoverColorCandidate(style)
19789
+ };
19790
+ }
19791
+ //#endregion
19792
+ //#region ../theme-core/src/site-styles/footerLookRecipe.ts
19793
+ /** Reject undeclared references when the curated catalogue is loaded, before rendering. */
19794
+ function validateFooterRecipeSurfaces(style, recipe) {
19795
+ [recipe.ground, ...recipe.legal.kind === "separate" && recipe.legal.bar ? [recipe.legal.bar.background] : []].forEach((ground) => {
19796
+ if (ground.kind === "style-surface" && (style.looks.kind !== "offers" || !style.looks.surfaces[ground.surface])) throw new Error(`Undeclared footer surface: ${ground.surface}`);
19797
+ });
19798
+ }
19799
+ //#endregion
18822
19800
  //#region ../theme-core/src/accordions/siteStyleDefaults.ts
18823
19801
  /**
18824
19802
  * Reusable accordion "looks" for curated site styles.
@@ -19546,52 +20524,14 @@ defineLookOptionGroup({
19546
20524
  function asFooterLookId(value) {
19547
20525
  return value;
19548
20526
  }
19549
- function quietFooterLinks(theme) {
19550
- return {
19551
- ...theme.footer,
19552
- navStyle: "minimal",
19553
- navWeight: "regular",
19554
- navColor: "text",
19555
- navLinkStyle: {
19556
- typography: "body",
19557
- fontWeight: "regular",
19558
- textTransform: "none",
19559
- italic: false,
19560
- colorToken: "text",
19561
- hoverColorToken: "primary",
19562
- padding: "none",
19563
- borderRadius: "none"
19564
- }
19565
- };
19566
- }
19567
- function emphasizedFooterLinks(theme) {
19568
- return {
19569
- ...theme.footer,
19570
- navStyle: "minimal",
19571
- navWeight: "medium",
19572
- navColor: "text",
19573
- navLinkStyle: {
19574
- typography: "body",
19575
- fontWeight: "medium",
19576
- textTransform: "none",
19577
- italic: false,
19578
- colorToken: "text",
19579
- hoverColorToken: "primary",
19580
- padding: "none",
19581
- borderRadius: "none"
19582
- }
19583
- };
19584
- }
19585
20527
  const footerLookCatalog = defineExactCatalog()([{
19586
- id: asFooterLookId("footer-links-quiet"),
19587
- label: "Quiet links",
19588
- description: "Regular-weight footer navigation with a restrained hover.",
19589
- compile: quietFooterLinks
20528
+ id: asFooterLookId("footer-links-row"),
20529
+ label: "Links in a row",
20530
+ description: "Your links in a row, with the other footer sections in columns beside them."
19590
20531
  }, {
19591
- id: asFooterLookId("footer-links-emphasized"),
19592
- label: "Emphasized links",
19593
- description: "Medium-weight footer navigation with a clearer emphasis.",
19594
- compile: emphasizedFooterLinks
20532
+ id: asFooterLookId("footer-centred-name"),
20533
+ label: "Centred name, links beneath",
20534
+ description: "Your site name centred, with your links, contact details and social links beneath it."
19595
20535
  }]);
19596
20536
  new Map(footerLookCatalog.map((look) => [look.id, look]));
19597
20537
  //#endregion
@@ -21008,6 +21948,7 @@ function defineCuratedSiteStyle(input) {
21008
21948
  recommendedAppearancePresetIds
21009
21949
  },
21010
21950
  headerCuration: headerCurationBySiteStyle[input.id],
21951
+ footerLookRecipes: input.footerLookRecipes,
21011
21952
  recommendedFooterLookIds: (input.recommendedFooterLookIds ?? []).map(asFooterLookId),
21012
21953
  buttonStyleChoices: input.buttonStyleChoices,
21013
21954
  paletteRecommendations: input.paletteRecommendations,
@@ -21493,7 +22434,11 @@ const lanternLooks = {
21493
22434
  margin: "40px"
21494
22435
  },
21495
22436
  fontLoading: {
21496
- extraBodyFontWeights: [500, 700],
22437
+ extraBodyFontWeights: [
22438
+ 500,
22439
+ 700,
22440
+ 800
22441
+ ],
21497
22442
  italicBodyFontWeights: [400]
21498
22443
  },
21499
22444
  surfaces: {
@@ -21543,6 +22488,38 @@ const lanternLooks = {
21543
22488
  ]
21544
22489
  },
21545
22490
  offers: [
22491
+ {
22492
+ id: id("body-text-reading-column"),
22493
+ treatment: "reading-column",
22494
+ roleMap: lanternRoles
22495
+ },
22496
+ {
22497
+ id: id("form-beside-introduction-arched-panel"),
22498
+ treatment: "arched-panel",
22499
+ addKnobs: ["archFrame"],
22500
+ roleMap: lanternRoles
22501
+ },
22502
+ {
22503
+ id: id("newsletter-signup-in-arch"),
22504
+ treatment: "signup-arch",
22505
+ addKnobs: ["archFrame"],
22506
+ roleMap: lanternRoles
22507
+ },
22508
+ {
22509
+ id: id("image-gallery-square-tiles"),
22510
+ treatment: "square-tiles",
22511
+ roleMap: lanternRoles
22512
+ },
22513
+ {
22514
+ id: id("image-gallery-arched-captions"),
22515
+ treatment: "arched-captions",
22516
+ roleMap: lanternRoles
22517
+ },
22518
+ {
22519
+ id: id("media-text-circle-beside-text"),
22520
+ treatment: "circle-beside",
22521
+ roleMap: lanternRoles
22522
+ },
21546
22523
  {
21547
22524
  id: id("event-details-panel"),
21548
22525
  treatment: "quiet",
@@ -21981,7 +22958,7 @@ const curatedSiteStyles = [
21981
22958
  "faq-contained-help",
21982
22959
  "contact-form-panel"
21983
22960
  ],
21984
- recommendedFooterLookIds: ["footer-links-quiet"],
22961
+ recommendedFooterLookIds: ["footer-links-row"],
21985
22962
  buttonStyleChoices: [
21986
22963
  buttonChoice("soft-pill"),
21987
22964
  buttonChoice("pebble"),
@@ -22100,7 +23077,7 @@ const curatedSiteStyles = [
22100
23077
  "testimonials-non-carded",
22101
23078
  "contact-form-panel"
22102
23079
  ],
22103
- recommendedFooterLookIds: ["footer-links-quiet", "footer-links-emphasized"],
23080
+ recommendedFooterLookIds: ["footer-links-row"],
22104
23081
  buttonStyleChoices: [
22105
23082
  buttonChoice("earth-pill"),
22106
23083
  buttonChoice("soft-pill"),
@@ -22155,7 +23132,41 @@ const curatedSiteStyles = [
22155
23132
  "testimonials-brand-statement-cards",
22156
23133
  "contact-form-panel"
22157
23134
  ],
22158
- recommendedFooterLookIds: ["footer-links-emphasized", "footer-links-quiet"],
23135
+ footerLookRecipes: { "footer-links-row": {
23136
+ arrangement: "split",
23137
+ ground: {
23138
+ kind: "token",
23139
+ token: "primary-800"
23140
+ },
23141
+ nav: {
23142
+ weight: "medium",
23143
+ colorToken: "primaryForeground",
23144
+ hoverColorToken: "secondary",
23145
+ typography: "body"
23146
+ },
23147
+ legal: {
23148
+ kind: "separate",
23149
+ bar: {
23150
+ fullBleed: true,
23151
+ background: {
23152
+ kind: "token",
23153
+ token: "primary-900"
23154
+ },
23155
+ textColor: "primaryForeground",
23156
+ textAlign: "center",
23157
+ paddingY: "compact",
23158
+ paddingX: "default",
23159
+ borderTop: { width: "none" }
23160
+ },
23161
+ linkStyle: {
23162
+ colorToken: "secondary",
23163
+ decorationColorToken: "secondary"
23164
+ }
23165
+ },
23166
+ brandAlign: "start",
23167
+ brandLogoSize: "sm"
23168
+ } },
23169
+ recommendedFooterLookIds: ["footer-links-row"],
22159
23170
  buttonStyleChoices: [
22160
23171
  buttonChoice("showtime-pill"),
22161
23172
  buttonChoice("confident-chip"),
@@ -22226,7 +23237,7 @@ const curatedSiteStyles = [
22226
23237
  "testimonials-statement-cards",
22227
23238
  "contact-form-panel"
22228
23239
  ],
22229
- recommendedFooterLookIds: ["footer-links-emphasized", "footer-links-quiet"],
23240
+ recommendedFooterLookIds: ["footer-links-row"],
22230
23241
  buttonStyleChoices: [
22231
23242
  buttonChoice("ornate-ritual"),
22232
23243
  buttonChoice("joy-stamp"),
@@ -22273,7 +23284,22 @@ const curatedSiteStyles = [
22273
23284
  } }
22274
23285
  },
22275
23286
  recommendedAppearancePresetIds: ["feature-cards-bold-colors", "testimonials-statement-cards"],
22276
- recommendedFooterLookIds: ["footer-links-emphasized", "footer-links-quiet"],
23287
+ footerLookRecipes: { "footer-links-row": {
23288
+ arrangement: "simple",
23289
+ ground: {
23290
+ kind: "token",
23291
+ token: "surface"
23292
+ },
23293
+ nav: {
23294
+ weight: "medium",
23295
+ colorToken: "text",
23296
+ hoverColorToken: "primary",
23297
+ typography: "body"
23298
+ },
23299
+ legal: { kind: "integrated" },
23300
+ brandAlign: "start"
23301
+ } },
23302
+ recommendedFooterLookIds: ["footer-links-row"],
22277
23303
  buttonStyleChoices: [
22278
23304
  buttonChoice("joy-stamp"),
22279
23305
  buttonChoice("ink-stamp"),
@@ -22325,7 +23351,7 @@ const curatedSiteStyles = [
22325
23351
  },
22326
23352
  testimonialQuote: serifDisplayQuote
22327
23353
  },
22328
- recommendedFooterLookIds: ["footer-links-quiet"],
23354
+ recommendedFooterLookIds: ["footer-links-row"],
22329
23355
  buttonStyleChoices: [
22330
23356
  buttonChoice("fulcrum"),
22331
23357
  buttonChoice("editorial-link"),
@@ -22402,7 +23428,7 @@ const curatedSiteStyles = [
22402
23428
  "faq-base-accordion",
22403
23429
  "booking-brand-band"
22404
23430
  ],
22405
- recommendedFooterLookIds: ["footer-links-quiet"],
23431
+ recommendedFooterLookIds: ["footer-links-row"],
22406
23432
  buttonStyleChoices: [
22407
23433
  buttonChoice("quiet-arrow", void 0, { secondaryTreatment: "solid-accent" }),
22408
23434
  buttonChoice("flat-ink"),
@@ -22440,7 +23466,22 @@ const curatedSiteStyles = [
22440
23466
  accordions: boldBorderedAccordionSystem,
22441
23467
  testimonialQuote: accentGlyphQuote
22442
23468
  },
22443
- recommendedFooterLookIds: ["footer-links-emphasized"],
23469
+ footerLookRecipes: { "footer-links-row": {
23470
+ arrangement: "simple",
23471
+ ground: {
23472
+ kind: "token",
23473
+ token: "surface"
23474
+ },
23475
+ nav: {
23476
+ weight: "medium",
23477
+ colorToken: "text",
23478
+ hoverColorToken: "primary",
23479
+ typography: "body"
23480
+ },
23481
+ legal: { kind: "integrated" },
23482
+ brandAlign: "start"
23483
+ } },
23484
+ recommendedFooterLookIds: ["footer-links-row"],
22444
23485
  buttonStyleChoices: [
22445
23486
  buttonChoice("offset-block"),
22446
23487
  buttonChoice("ink-stamp"),
@@ -22479,8 +23520,29 @@ const curatedSiteStyles = [
22479
23520
  accordions: warmInsetAccordionSystem,
22480
23521
  testimonialQuote: serifDisplayQuote
22481
23522
  },
22482
- recommendedFooterLookIds: ["footer-links-quiet"],
23523
+ footerLookRecipes: { "footer-centred-name": {
23524
+ arrangement: "centred",
23525
+ ground: {
23526
+ kind: "style-surface",
23527
+ surface: "deep"
23528
+ },
23529
+ nav: {
23530
+ weight: "regular",
23531
+ colorToken: "text",
23532
+ hoverColorToken: "primary",
23533
+ typography: "heading"
23534
+ },
23535
+ legal: {
23536
+ kind: "separate",
23537
+ bar: null
23538
+ },
23539
+ brandAlign: "center"
23540
+ } },
23541
+ recommendedFooterLookIds: ["footer-centred-name", "footer-links-row"],
22483
23542
  buttonStyleChoices: [
23543
+ buttonChoice("gilt-slab"),
23544
+ buttonChoice("hairline-tab"),
23545
+ buttonChoice("marquee"),
22484
23546
  buttonChoice("ringed-pill"),
22485
23547
  buttonChoice("earth-pill"),
22486
23548
  buttonChoice("editorial-link")
@@ -22515,7 +23577,7 @@ const curatedSiteStyles = [
22515
23577
  accordions: editorialDividedAccordionSystem,
22516
23578
  testimonialQuote: serifDisplayQuote
22517
23579
  },
22518
- recommendedFooterLookIds: ["footer-links-quiet"],
23580
+ recommendedFooterLookIds: ["footer-links-row"],
22519
23581
  buttonStyleChoices: [
22520
23582
  buttonChoice("flat-ink", void 0, { corners: "square" }),
22521
23583
  buttonChoice("editorial-link"),
@@ -22543,6 +23605,7 @@ function curatedStyleTemplate(input) {
22543
23605
  }
22544
23606
  curatedSiteStyles.forEach((style) => {
22545
23607
  if (style.looks.kind === "offers") validateLookFallbacks(style.looks);
23608
+ (/* @__PURE__ */ new Set([...Object.values(style.footerLookRecipes ?? {}), ...style.recommendedFooterLookIds.map((id) => resolveFooterLookRecipe(style, id))])).forEach((recipe) => validateFooterRecipeSurfaces(style, recipe));
22546
23609
  });
22547
23610
  //#endregion
22548
23611
  //#region ../theme-core/src/site-styles/effectiveArrangement.ts
@@ -22618,29 +23681,6 @@ const blockDesignFallback = {
22618
23681
  };
22619
23682
  blockDesignFallback.sectionSurface, blockDesignFallback.contentFrame, blockDesignFallback.sectionHeight, blockDesignFallback.heroLegibility, blockDesignFallback.imageSurfaceTreatment, blockDesignFallback.imageSurfaceMotion, blockDesignFallback.tileTreatment, blockDesignFallback.eventListTreatment, blockDesignFallback.eyebrowTreatment, blockDesignFallback.accordionIconTreatment, blockDesignFallback.composition;
22620
23683
  //#endregion
22621
- //#region ../theme-core/src/header/rootPaint.ts
22622
- /** The nav container takes precedence when a floating header also has one. */
22623
- function headerRootPaint(header) {
22624
- const navContainerType = header?.navContainer?.type ?? "none";
22625
- if (navContainerType === "glass" || navContainerType === "pill") return "contained-nav";
22626
- return header?.variant === "floating" ? "overlay" : "own-surface";
22627
- }
22628
- //#endregion
22629
- //#region ../theme-core/src/site-styles/siteChromeBackgrounds.ts
22630
- const siteChromeBackgroundColorTokens = toSiteChromeBackgroundColorTokens(backgroundAppearanceColorTokenNames);
22631
- const quickSiteChromeBackgroundColorTokens = toSiteChromeBackgroundColorTokens(backgroundAppearanceQuickColorTokenNames);
22632
- siteChromeBackgroundColorTokens.filter((token) => !quickSiteChromeBackgroundColorTokens.includes(token));
22633
- function parseSiteChromeBackgroundColorToken(value) {
22634
- const token = parseBackgroundAppearanceColorToken(value);
22635
- return token ? token : null;
22636
- }
22637
- function toSiteChromeBackgroundColorTokens(tokenNames) {
22638
- return tokenNames.flatMap((name) => {
22639
- const token = parseSiteChromeBackgroundColorToken(name);
22640
- return token ? [token] : [];
22641
- });
22642
- }
22643
- //#endregion
22644
23684
  //#region ../theme-core/src/site-styles/siteChromeNavPreferences.ts
22645
23685
  const headerNavTypographyPreferenceValues = [
22646
23686
  "inherit",
@@ -22756,21 +23796,6 @@ z.object({
22756
23796
  }).strict();
22757
23797
  //#endregion
22758
23798
  //#region ../theme-core/src/site-styles/headerPreferencesPersistence.ts
22759
- const backgroundColorTokenSchema = z.unknown().transform((value, ctx) => {
22760
- const token = parseSiteChromeBackgroundColorToken(value);
22761
- if (token === null) {
22762
- ctx.addIssue({
22763
- code: "custom",
22764
- message: "Unknown site chrome background colour token"
22765
- });
22766
- return z.NEVER;
22767
- }
22768
- return token;
22769
- });
22770
- const backgroundOverrideSchema = z.discriminatedUnion("kind", [z.object({ kind: z.literal("default") }).strict(), z.object({
22771
- kind: z.literal("color"),
22772
- token: backgroundColorTokenSchema
22773
- }).strict()]);
22774
23799
  const logoTextIntentSchema = z.object({
22775
23800
  mobileMaxWidth: z.enum([
22776
23801
  "xs",
@@ -22796,7 +23821,7 @@ const headerPreferencesShape = {
22796
23821
  navFontRole: z.enum(headerNavTypographyPreferenceValues),
22797
23822
  navTextSize: z.enum(headerNavFontSizePreferenceValues),
22798
23823
  interactionPalette: z.union([z.literal("recommended"), z.enum(headerInteractionPaletteValues)]),
22799
- background: backgroundOverrideSchema,
23824
+ background: siteChromeBackgroundOverrideSchema,
22800
23825
  structure: structureSchema
22801
23826
  };
22802
23827
  z.object(headerPreferencesShape).strict();
@@ -22805,167 +23830,6 @@ z.object(headerPreferencesShape).omit({
22805
23830
  structure: true
22806
23831
  }).strict();
22807
23832
  //#endregion
22808
- //#region ../theme-core/src/navigation/presets.ts
22809
- /**
22810
- * Built-in nav link style presets
22811
- *
22812
- * Each preset uses composable effects to achieve its look.
22813
- */
22814
- const NAV_LINK_PRESETS = {
22815
- /**
22816
- * Minimal - subtle color change on hover
22817
- */
22818
- minimal: {
22819
- name: "Minimal",
22820
- typography: "body",
22821
- fontWeight: "medium",
22822
- textTransform: "none",
22823
- italic: false,
22824
- colorToken: "text",
22825
- hoverColorToken: "primary",
22826
- padding: "none",
22827
- borderRadius: "none",
22828
- effects: { hover: [{
22829
- effectId: "text-color-change",
22830
- options: { hoverColorToken: "primary" }
22831
- }] }
22832
- },
22833
- /**
22834
- * Underline - static underline appears on hover
22835
- */
22836
- underline: {
22837
- name: "Underline",
22838
- typography: "body",
22839
- fontWeight: "medium",
22840
- textTransform: "none",
22841
- italic: false,
22842
- colorToken: "text",
22843
- padding: "none",
22844
- borderRadius: "none",
22845
- effects: { hover: [{
22846
- effectId: "nav-underline",
22847
- options: { style: "static" }
22848
- }] }
22849
- },
22850
- /**
22851
- * Underline Grow - animated underline grows from center on hover
22852
- */
22853
- "underline-grow": {
22854
- name: "Underline Grow",
22855
- typography: "body",
22856
- fontWeight: "medium",
22857
- textTransform: "none",
22858
- italic: false,
22859
- colorToken: "text",
22860
- padding: "none",
22861
- borderRadius: "none",
22862
- effects: { hover: [{
22863
- effectId: "nav-underline",
22864
- options: { style: "grow" }
22865
- }] }
22866
- },
22867
- /**
22868
- * Capsule - pill-shaped background on hover
22869
- */
22870
- capsule: {
22871
- name: "Capsule",
22872
- typography: "body",
22873
- fontWeight: "medium",
22874
- textTransform: "none",
22875
- italic: false,
22876
- colorToken: "text",
22877
- padding: "compact",
22878
- borderRadius: "full",
22879
- effects: {
22880
- hover: [{
22881
- effectId: "background-on-hover-alpha",
22882
- options: {
22883
- colorToken: "primary",
22884
- opacity: 10
22885
- }
22886
- }],
22887
- active: [{
22888
- effectId: "background-on-hover-alpha",
22889
- options: {
22890
- colorToken: "primary",
22891
- opacity: 15
22892
- }
22893
- }]
22894
- }
22895
- },
22896
- /**
22897
- * Solid - solid background color on hover
22898
- */
22899
- solid: {
22900
- name: "Solid",
22901
- typography: "body",
22902
- fontWeight: "medium",
22903
- textTransform: "none",
22904
- italic: false,
22905
- colorToken: "text",
22906
- padding: "compact",
22907
- borderRadius: "none",
22908
- effects: {
22909
- hover: [{
22910
- effectId: "background-on-hover",
22911
- options: {
22912
- colorToken: "primary",
22913
- textColorToken: "primaryForeground"
22914
- }
22915
- }],
22916
- active: [{
22917
- effectId: "background-on-hover",
22918
- options: {
22919
- colorToken: "primary",
22920
- textColorToken: "primaryForeground"
22921
- }
22922
- }]
22923
- }
22924
- },
22925
- /**
22926
- * Scale - gentle scale-up on hover
22927
- */
22928
- scale: {
22929
- name: "Scale",
22930
- typography: "body",
22931
- fontWeight: "medium",
22932
- textTransform: "none",
22933
- italic: false,
22934
- colorToken: "text",
22935
- padding: "none",
22936
- borderRadius: "none",
22937
- effects: { hover: [{
22938
- effectId: "scale-up",
22939
- options: { scale: 1.05 }
22940
- }] }
22941
- },
22942
- /**
22943
- * Frosted - semi-transparent glass-like background
22944
- */
22945
- frosted: {
22946
- name: "Frosted",
22947
- typography: "body",
22948
- fontWeight: "medium",
22949
- textTransform: "none",
22950
- italic: false,
22951
- colorToken: "text",
22952
- padding: "compact",
22953
- borderRadius: "md",
22954
- effects: {
22955
- base: [{ effectId: "nav-frosted-base" }],
22956
- hover: [{ effectId: "nav-frosted-hover" }],
22957
- active: [{ effectId: "nav-frosted-active" }]
22958
- }
22959
- }
22960
- };
22961
- /**
22962
- * Get a nav link style preset by ID
22963
- */
22964
- function getNavLinkPreset(presetId) {
22965
- return NAV_LINK_PRESETS[presetId];
22966
- }
22967
- Object.keys(NAV_LINK_PRESETS);
22968
- //#endregion
22969
23833
  //#region ../theme-core/src/header/legacyNavLinkStyle.ts
22970
23834
  function buildLegacyHeaderNavLinkStyle(header, contrastTreatment, navTextSize) {
22971
23835
  const navStyle = header.navStyle ?? "minimal";
@@ -23210,28 +24074,6 @@ z.object({
23210
24074
  motion: z.enum(themeTokenRecipeOptions.motion)
23211
24075
  });
23212
24076
  //#endregion
23213
- //#region ../theme-core/src/footer/effectiveNavLinkStyle.ts
23214
- function effectiveFooterNavLinkStyle(footer) {
23215
- if (!footer) return null;
23216
- if (footer.navLinkStyle) return footer.navLinkStyle;
23217
- const basePreset = getNavLinkPreset(footer.navStyle ?? "minimal");
23218
- if (!basePreset) return null;
23219
- return {
23220
- ...basePreset,
23221
- fontWeight: footer.navWeight ?? basePreset.fontWeight,
23222
- colorToken: footer.navColor?.trim() || basePreset.colorToken
23223
- };
23224
- }
23225
- function footerForegroundCandidates(footer, proseHoverCandidate) {
23226
- if (!footer) return {};
23227
- const style = effectiveFooterNavLinkStyle(footer);
23228
- return {
23229
- text: footer.background?.textColor,
23230
- link: style?.colorToken ?? footer.navColor ?? footer.background?.textColor,
23231
- linkHover: navLinkOwnsHoverForeground(style) ? proseHoverCandidate : navLinkHoverColorCandidate(style)
23232
- };
23233
- }
23234
- //#endregion
23235
24077
  //#region ../theme-core/src/siteChromeOverlayClearance.ts
23236
24078
  const SITE_CHROME_VISIBLE_HEADER_ATTR = "data-site-chrome-visible-header";
23237
24079
  //#endregion
@@ -23341,97 +24183,6 @@ function registerManifest(manifest) {
23341
24183
  return manifest;
23342
24184
  }
23343
24185
  //#endregion
23344
- //#region ../media-core/src/transformRect.ts
23345
- function isValidTransformRectStructure(rect) {
23346
- if (!Array.isArray(rect) || rect.length !== 4) return false;
23347
- const [left, top, width, height] = rect;
23348
- return Number.isFinite(left) && Number.isFinite(top) && Number.isFinite(width) && Number.isFinite(height) && left >= 0 && top >= 0 && width > 0 && height > 0;
23349
- }
23350
- //#endregion
23351
- //#region ../media-core/src/aspectTransforms.ts
23352
- const DEFAULT_RECT_EPSILON = .5;
23353
- function parseAspectRatioValue(value) {
23354
- if (typeof value === "number") return Number.isFinite(value) && value > 0 ? value : void 0;
23355
- if (typeof value !== "string") return void 0;
23356
- const normalized = value.trim();
23357
- if (!normalized) return void 0;
23358
- if (normalized === "auto") return void 0;
23359
- if (normalized.includes(":") || normalized.includes("/")) {
23360
- const delimiter = normalized.includes(":") ? ":" : "/";
23361
- const [wRaw, hRaw] = normalized.split(delimiter);
23362
- const width = Number(wRaw?.trim());
23363
- const height = Number(hRaw?.trim());
23364
- if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) return;
23365
- return width / height;
23366
- }
23367
- const numeric = Number(normalized);
23368
- if (!Number.isFinite(numeric) || numeric <= 0) return void 0;
23369
- return numeric;
23370
- }
23371
- const MAX_ASPECT_DISTANCE = .25;
23372
- function resolveMediaTransformForAspect(transform, targetAspect) {
23373
- if (!transform) return {};
23374
- const base = {
23375
- rect: transform.rect,
23376
- hotspot: transform.hotspot,
23377
- rotation: transform.rotation
23378
- };
23379
- const target = parseAspectRatioValue(targetAspect);
23380
- const crops = transform.aspectCrops;
23381
- if (!target || !crops || Object.keys(crops).length === 0) return base;
23382
- let best = null;
23383
- let bestDistance = Number.POSITIVE_INFINITY;
23384
- for (const [key, candidate] of Object.entries(crops)) {
23385
- const candidateAspect = parseAspectRatioValue(candidate.aspect ?? key);
23386
- if (!candidateAspect) continue;
23387
- const distance = Math.abs(Math.log(candidateAspect / target));
23388
- if (distance < bestDistance) {
23389
- best = candidate;
23390
- bestDistance = distance;
23391
- }
23392
- }
23393
- if (!best) return base;
23394
- if (bestDistance > MAX_ASPECT_DISTANCE) return base;
23395
- return {
23396
- rect: best.rect ?? base.rect,
23397
- hotspot: best.hotspot ?? base.hotspot,
23398
- rotation: best.rotation ?? base.rotation
23399
- };
23400
- }
23401
- function isValidTransformRect(rect) {
23402
- return isValidTransformRectStructure(rect);
23403
- }
23404
- function isExplicitRectCrop(rect, sourceWidth, sourceHeight, epsilon = DEFAULT_RECT_EPSILON) {
23405
- if (!isValidTransformRect(rect)) return false;
23406
- if (!(typeof sourceWidth === "number" && Number.isFinite(sourceWidth) && sourceWidth > 0 && typeof sourceHeight === "number" && Number.isFinite(sourceHeight) && sourceHeight > 0)) return true;
23407
- const [x, y, width, height] = rect;
23408
- return !(Math.abs(x) <= epsilon && Math.abs(y) <= epsilon && Math.abs(width - sourceWidth) <= epsilon && Math.abs(height - sourceHeight) <= epsilon);
23409
- }
23410
- //#endregion
23411
- //#region ../media-core/src/rotation.ts
23412
- function rotateNormalizedPoint(point, rotation) {
23413
- const x = point.x;
23414
- const y = point.y;
23415
- switch (rotation) {
23416
- case 0: return {
23417
- x,
23418
- y
23419
- };
23420
- case 90: return {
23421
- x: 1 - y,
23422
- y: x
23423
- };
23424
- case 180: return {
23425
- x: 1 - x,
23426
- y: 1 - y
23427
- };
23428
- case 270: return {
23429
- x: y,
23430
- y: 1 - x
23431
- };
23432
- }
23433
- }
23434
- //#endregion
23435
24186
  //#region ../blocks/src/system/node/schema.ts
23436
24187
  const transformStepSchema = z.object({
23437
24188
  id: z.string().min(1, "Transform requires an identifier"),
@@ -26357,6 +27108,12 @@ function parseBackgroundOverlay(value) {
26357
27108
  const result = boxBackgroundOverlaySchema.safeParse(value);
26358
27109
  return result.success ? result.data : void 0;
26359
27110
  }
27111
+ /** Rendering accepts explicit application sources separately from stored references. */
27112
+ const runtimeBackgroundContentSchema = runtimeBoxBackgroundSchema;
27113
+ function parseRuntimeBackgroundContent(value) {
27114
+ const result = runtimeBackgroundContentSchema.safeParse(value);
27115
+ return result.success ? result.data : null;
27116
+ }
26360
27117
  //#endregion
26361
27118
  //#region ../blocks/src/system/transforms/registry/_utils/themeColorResolution.ts
26362
27119
  function resolveBackgroundColorValue(value, context) {
@@ -26412,7 +27169,12 @@ function resolveRuntimeSectionSurface(value, context, options) {
26412
27169
  }
26413
27170
  function arrangementSurfaceInk(foreground, context) {
26414
27171
  if (context.data?._lookSlots === void 0) return {};
26415
- const decorations = surfaceDecorationColors(foreground, context.theme.palette);
27172
+ return surfaceInkStyles(foreground, context.theme.palette);
27173
+ }
27174
+ /** Decoration roles already resolved by the surface owner, shared with footer arrangements. */
27175
+ function surfaceInkStyles(foreground, palette) {
27176
+ if (foreground.kind === "unknown") return {};
27177
+ const decorations = surfaceDecorationColors(foreground, palette);
26416
27178
  return {
26417
27179
  "--rb-surface-muted-color": foreground.roles.muted ?? foreground.roles.text,
26418
27180
  ...decorations ? {
@@ -27023,48 +27785,50 @@ const boxStylesTransforms = [
27023
27785
  ];
27024
27786
  //#endregion
27025
27787
  //#region ../blocks/src/system/node/fragments/responsiveTwoColumn.ts
27026
- 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" }) {
27027
- const baseClass = !gapFrom ? `${containerClassName} ${gapClassName}`.trim() : containerClassName;
27028
- const props = { className: { $bind: {
27029
- from: imagePositionFrom,
27030
- transforms: [{
27031
- id: "ui.twoColumnContainerClass",
27032
- options: {
27033
- base: baseClass,
27034
- reverseClass: "rb-md-flex-row-reverse"
27035
- }
27036
- }],
27037
- fallback: baseClass
27038
- } } };
27039
- if (gapFrom) props.style = { gap: { $bind: {
27040
- from: gapFrom,
27041
- transforms: [{
27042
- id: "boxStyles.semanticGapValue",
27043
- options: { fallback: gapFallback }
27044
- }],
27045
- fallback: GAP_VALUE_MAP[gapFallback]
27046
- } } };
27047
- return el("div", props, [el("div", {
27048
- className: imageWrapperClassName,
27049
- style: { flexBasis: { $bind: {
27050
- from: ratioFrom,
27788
+ /** The shared two-column shell keeps Look hooks opt-in and absent for legacy content. */
27789
+ function responsiveTwoColumn(config) {
27790
+ return el("div", twoColumnProps(config), [twoColumnWrapper(config, "image", config.image), twoColumnWrapper(config, "text", config.text)]);
27791
+ }
27792
+ function twoColumnProps(config) {
27793
+ const base = `${config.containerClassName ?? "rb-flex rb-flex-col rb-md-flex-row"} ${config.gapFrom ? "" : config.gapClassName ?? "rb-gap-6"}`.trim();
27794
+ const fallback = config.gapFallback ?? "comfortable";
27795
+ return {
27796
+ ...config.lookSlots ? lookSlot("frame") : {},
27797
+ className: { $bind: {
27798
+ from: config.imagePositionFrom,
27051
27799
  transforms: [{
27052
- id: "ui.twoColumnFlexBasis",
27053
- options: { side: "image" }
27800
+ id: "ui.twoColumnContainerClass",
27801
+ options: {
27802
+ base,
27803
+ reverseClass: "rb-md-flex-row-reverse"
27804
+ }
27054
27805
  }],
27055
- fallback: "50%"
27056
- } } }
27057
- }, [image]), el("div", {
27058
- className: textWrapperClassName,
27806
+ fallback: base
27807
+ } },
27808
+ ...config.gapFrom ? { style: { gap: { $bind: {
27809
+ from: config.gapFrom,
27810
+ transforms: [{
27811
+ id: "boxStyles.semanticGapValue",
27812
+ options: { fallback }
27813
+ }],
27814
+ fallback: GAP_VALUE_MAP[fallback]
27815
+ } } } } : {}
27816
+ };
27817
+ }
27818
+ function twoColumnWrapper(config, side, child) {
27819
+ const className = side === "image" ? config.imageWrapperClassName ?? "rb-w-full rb-shrink-0" : config.textWrapperClassName ?? "rb-w-full rb-min-w-0 rb-flex-1";
27820
+ return el("div", {
27821
+ ...config.lookSlots ? lookSlot(side === "image" ? "media" : "copy") : {},
27822
+ className,
27059
27823
  style: { flexBasis: { $bind: {
27060
- from: ratioFrom,
27824
+ from: config.ratioFrom,
27061
27825
  transforms: [{
27062
27826
  id: "ui.twoColumnFlexBasis",
27063
- options: { side: "text" }
27827
+ options: { side }
27064
27828
  }],
27065
27829
  fallback: "50%"
27066
27830
  } } }
27067
- }, [text])]);
27831
+ }, [child]);
27068
27832
  }
27069
27833
  //#endregion
27070
27834
  //#region ../blocks/src/system/node/fragments/styledCard.ts
@@ -27251,6 +28015,47 @@ function sectionState(opts) {
27251
28015
  })]);
27252
28016
  }
27253
28017
  //#endregion
28018
+ //#region ../blocks/src/system/node/fragments/sectionHead.ts
28019
+ const recoverEmptyHeadingWhenActive = {
28020
+ kind: "recover-empty-when-active",
28021
+ placeholder: "Add heading"
28022
+ };
28023
+ const recoverEmptyDescriptionWhenActive = {
28024
+ kind: "recover-empty-when-active",
28025
+ placeholder: "Add description"
28026
+ };
28027
+ function sectionHeaderLayoutNodes(options = {}) {
28028
+ const headingNode = text({
28029
+ as: "h2",
28030
+ ...lookSlot("heading")
28031
+ }, bind("content.heading"), when("content.heading", { authoringPresence: recoverEmptyHeadingWhenActive }));
28032
+ const descriptionNode = richText({
28033
+ className: "rb-prose rb-max-w-none",
28034
+ ...lookSlot("intro")
28035
+ }, bind("content.description"), when("content.description", { authoringPresence: recoverEmptyDescriptionWhenActive }));
28036
+ if (options.splitClassName) return [el("div", {
28037
+ className: options.splitClassName,
28038
+ ...lookSlot("head")
28039
+ }, [headingNode, descriptionNode])];
28040
+ return [headingNode, descriptionNode];
28041
+ }
28042
+ /** Shared optional section copy. Existing consumers keep their description ID. */
28043
+ const sectionHeaderFields = (defaultHeading, introLabel = "Description") => [{
28044
+ id: "heading",
28045
+ type: "text",
28046
+ label: "Heading",
28047
+ description: "Main heading for the section",
28048
+ required: false,
28049
+ multiline: false,
28050
+ ...defaultHeading === void 0 ? {} : { defaultValue: defaultHeading }
28051
+ }, {
28052
+ id: "description",
28053
+ type: "richText",
28054
+ label: introLabel,
28055
+ description: "Optional introductory text",
28056
+ required: false
28057
+ }];
28058
+ //#endregion
27254
28059
  //#region ../blocks/src/system/fragments/types.ts
27255
28060
  const FRAGMENT_ID_PATTERN = /^[a-z0-9](?:[a-z0-9._-]*[a-z0-9])?$/i;
27256
28061
  const FIELD_ID_PATTERN = /^[a-z][a-zA-Z0-9_-]*$/;
@@ -27583,6 +28388,7 @@ const bodyCopyFragment = defineFragment({
27583
28388
  ],
27584
28389
  layout: stack({
27585
28390
  gap: "md",
28391
+ ...lookSlot("copy"),
27586
28392
  className: "body-copy-container",
27587
28393
  align: { $bind: {
27588
28394
  from: "content.alignment",
@@ -27591,6 +28397,7 @@ const bodyCopyFragment = defineFragment({
27591
28397
  } }
27592
28398
  }, [text({
27593
28399
  as: "h2",
28400
+ ...lookSlot("heading"),
27594
28401
  className: { $bind: {
27595
28402
  from: "content.alignment",
27596
28403
  transforms: [{
@@ -27599,14 +28406,22 @@ const bodyCopyFragment = defineFragment({
27599
28406
  }],
27600
28407
  fallback: "body-copy-heading"
27601
28408
  } }
27602
- }, when("content.heading"), bind("content.heading")), richText({ className: { $bind: {
27603
- from: "content.alignment",
27604
- transforms: [{
27605
- id: "ui.bodyClassFromAlignment",
27606
- options: { base: "body-copy-body rb-prose rb-max-w-none" }
27607
- }],
27608
- fallback: "body-copy-body rb-prose rb-max-w-none"
27609
- } } }, bind("content.body"))])
28409
+ }, when("content.heading", { authoringPresence: {
28410
+ kind: "recover-empty-when-active",
28411
+ placeholder: "Add heading"
28412
+ } }), bind("content.heading")), richText({
28413
+ ...lookSlot("item-body"),
28414
+ leadParagraphSlot: { $bind: { from: "content._lookSlots.lede" } },
28415
+ lookSlots: { $bind: { from: "content._lookSlots" } },
28416
+ className: { $bind: {
28417
+ from: "content.alignment",
28418
+ transforms: [{
28419
+ id: "ui.bodyClassFromAlignment",
28420
+ options: { base: "body-copy-body rb-prose rb-max-w-none" }
28421
+ }],
28422
+ fallback: "body-copy-body rb-prose rb-max-w-none"
28423
+ } }
28424
+ }, bind("content.body"))])
27610
28425
  });
27611
28426
  //#endregion
27612
28427
  //#region ../blocks/src/system/fragments/library/heroCopy.ts
@@ -28622,8 +29437,19 @@ const formCopyFragment = defineFragment({
28622
29437
  }],
28623
29438
  layout: [text({
28624
29439
  as: "h2",
29440
+ ...lookSlot("heading"),
28625
29441
  className: "form-copy-title"
28626
- }, when("content.title"), bind("content.title")), richText({ className: "form-copy-intro rb-prose rb-max-w-none" }, when("content.intro"), bind("content.intro"))]
29442
+ }, when("content.title", { authoringPresence: {
29443
+ kind: "recover-empty-when-active",
29444
+ placeholder: "Add heading"
29445
+ } }), bind("content.title")), richText({
29446
+ className: "form-copy-intro rb-prose rb-max-w-none",
29447
+ ...lookSlot("intro"),
29448
+ leadParagraphSlot: { $bind: { from: "content._lookSlots.lede" } }
29449
+ }, when("content.intro", { authoringPresence: {
29450
+ kind: "recover-empty-when-active",
29451
+ placeholder: "Add introduction"
29452
+ } }), bind("content.intro"))]
28627
29453
  });
28628
29454
  //#endregion
28629
29455
  //#region ../blocks/src/system/helpers/api-bindings.ts
@@ -28672,6 +29498,7 @@ const formEmbedFragment = defineFragment({
28672
29498
  }
28673
29499
  ],
28674
29500
  layout: [form(withApiBindings({
29501
+ lookSlots: { $bind: { from: "content._lookSlots" } },
28675
29502
  spamProtectionEnabled: { $bind: { from: "$root.spamProtectionEnabled" } },
28676
29503
  submitLabel: { $bind: { from: "submitLabel" } },
28677
29504
  successMessage: { $bind: { from: "successMessage" } }
@@ -28925,8 +29752,18 @@ const newsletterCopyFragment = defineFragment({
28925
29752
  }],
28926
29753
  layout: [text({
28927
29754
  as: "h2",
28928
- className: "newsletter-copy-title"
28929
- }, when("content.title"), bind("content.title")), richText({ className: "newsletter-copy-subtitle rb-prose rb-max-w-none" }, when("content.subtitle"), bind("content.subtitle"))]
29755
+ className: "newsletter-copy-title",
29756
+ ...lookSlot("heading")
29757
+ }, when("content.title", { authoringPresence: {
29758
+ kind: "recover-empty-when-active",
29759
+ placeholder: "Add heading"
29760
+ } }), bind("content.title")), richText({
29761
+ className: "newsletter-copy-subtitle rb-prose rb-max-w-none",
29762
+ ...lookSlot("intro")
29763
+ }, when("content.subtitle", { authoringPresence: {
29764
+ kind: "recover-empty-when-active",
29765
+ placeholder: "Add introduction"
29766
+ } }), bind("content.subtitle"))]
28930
29767
  });
28931
29768
  //#endregion
28932
29769
  //#region ../blocks/src/system/fragments/library/newsletterForm.ts
@@ -28994,6 +29831,7 @@ const newsletterFormFragment = defineFragment({
28994
29831
  }
28995
29832
  ],
28996
29833
  layout: [el("newsletter-form", withApiBindings({
29834
+ lookSlots: { $bind: { from: "content._lookSlots" } },
28997
29835
  source: { $bind: {
28998
29836
  from: "mailingListSource",
28999
29837
  fallback: "block"
@@ -30486,18 +31324,11 @@ const introBlockDefinition = { manifest: createBlockManifest({
30486
31324
  //#endregion
30487
31325
  //#region ../blocks/src/system/blocks/body-text.ts
30488
31326
  const bodyCopyComposition = composeFragments([{ fragment: bodyCopyFragment }]);
30489
- const proseLayout = styledSection({
30490
- children: stack({ className: "rb-container" }, bodyCopyComposition.layout),
30491
- spacing: "medium",
30492
- baseClass: ""
30493
- });
30494
- const introLayout = styledSection({
30495
- children: stack({ className: "rb-container" }, bodyCopyComposition.layout),
30496
- spacing: "medium",
30497
- baseClass: ""
30498
- });
30499
- const narrowLayout = styledSection({
30500
- children: stack({ className: "rb-container" }, bodyCopyComposition.layout),
31327
+ const bodyTextLayout = styledSection({
31328
+ children: stack({
31329
+ className: "rb-container",
31330
+ ...lookSlot("frame")
31331
+ }, bodyCopyComposition.layout),
30501
31332
  spacing: "medium",
30502
31333
  baseClass: ""
30503
31334
  });
@@ -30511,11 +31342,11 @@ const bodyTextBlockDefinition = { manifest: createBlockManifest({
30511
31342
  fragment: bodyCopyFragment,
30512
31343
  fieldPriority: 0
30513
31344
  }],
30514
- layout: proseLayout,
31345
+ layout: bodyTextLayout,
30515
31346
  variants: {
30516
- prose: proseLayout,
30517
- intro: introLayout,
30518
- narrow: narrowLayout
31347
+ prose: bodyTextLayout,
31348
+ intro: bodyTextLayout,
31349
+ narrow: bodyTextLayout
30519
31350
  },
30520
31351
  variantMeaning: { kind: "arrangement" },
30521
31352
  defaultVariant: "prose",
@@ -30963,6 +31794,52 @@ const singleButtonBlockDefinition = { manifest: createBlockManifest({
30963
31794
  styleTokens: { spacing: "md" }
30964
31795
  }) };
30965
31796
  //#endregion
31797
+ //#region ../blocks/src/system/runtime/lookSurfaces.ts
31798
+ const isPlainObject$1 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
31799
+ const lookListPresentationSchemaShape = {
31800
+ sectionAction: z.object({
31801
+ label: z.string(),
31802
+ href: z.string()
31803
+ }).optional(),
31804
+ actionSize: z.enum([
31805
+ "sm",
31806
+ "md",
31807
+ "lg"
31808
+ ]).optional(),
31809
+ itemActionStyle: z.enum(["button", "link"]).optional(),
31810
+ itemRoles: z.object({
31811
+ container: z.enum([
31812
+ "card",
31813
+ "statement",
31814
+ "highlight"
31815
+ ]).optional(),
31816
+ items: z.enum([
31817
+ "card",
31818
+ "statement",
31819
+ "highlight"
31820
+ ]).optional(),
31821
+ at: z.partialRecord(z.enum([
31822
+ "first",
31823
+ "last",
31824
+ "middle",
31825
+ "odd",
31826
+ "even"
31827
+ ]), z.enum([
31828
+ "card",
31829
+ "statement",
31830
+ "highlight"
31831
+ ])).optional()
31832
+ }).optional(),
31833
+ roleSurfaces: z.record(z.enum([
31834
+ "card",
31835
+ "statement",
31836
+ "highlight"
31837
+ ]), z.custom((value) => isPlainObject$1(value) && (value.kind === "inherit" || value.kind === "owned"))).optional(),
31838
+ panelHeading: z.string().optional(),
31839
+ lookSlots: z.partialRecord(z.enum(arrangementSlotNames), z.enum(arrangementSlotNames)).optional(),
31840
+ itemSurfaces: z.record(z.string(), z.custom((value) => isPlainObject$1(value) && (value.kind === "inherit" || value.kind === "owned"))).optional()
31841
+ };
31842
+ //#endregion
30966
31843
  //#region ../blocks/src/contracts/runtime.ts
30967
31844
  function decodeSuccess(value) {
30968
31845
  return {
@@ -31069,6 +31946,7 @@ const formFieldGroupSchema = z.discriminatedUnion("type", [z.object({
31069
31946
  fields: z.tuple([formFieldSchema, formFieldSchema])
31070
31947
  })]);
31071
31948
  const formSourceSchema = z.object({
31949
+ lookSlots: lookListPresentationSchemaShape.lookSlots,
31072
31950
  value: formRecordSchema.optional(),
31073
31951
  siteId: z.string().optional(),
31074
31952
  apiBaseUrl: z.string().optional(),
@@ -31078,6 +31956,7 @@ const formSourceSchema = z.object({
31078
31956
  spamProtectionEnabled: z.boolean().optional()
31079
31957
  });
31080
31958
  const formDisplaySchema = z.object({
31959
+ lookSlots: lookListPresentationSchemaShape.lookSlots,
31081
31960
  kind: z.literal("form"),
31082
31961
  state: z.enum(["missing", "ready"]),
31083
31962
  className: z.string().nullable(),
@@ -31098,17 +31977,30 @@ z.object({
31098
31977
  });
31099
31978
  function buildFormDisplay(source) {
31100
31979
  const form = source.value ?? null;
31101
- const fields = form?.schemaJson?.fields;
31102
- const groups = Array.isArray(fields) ? groupFormFields(fields) : [];
31980
+ const fields = formDisplayFields(form);
31103
31981
  return {
31104
31982
  kind: "form",
31105
- state: form ? "ready" : "missing",
31983
+ ...source.lookSlots ? { lookSlots: source.lookSlots } : {},
31984
+ state: fields.state,
31106
31985
  className: source.className ?? null,
31107
- formId: form?.id ?? null,
31986
+ formId: fields.formId,
31108
31987
  submitLabel: source.submitLabel?.trim() || "Submit",
31109
31988
  successMessage: source.successMessage ?? null,
31110
31989
  form,
31111
- groups
31990
+ groups: fields.groups
31991
+ };
31992
+ }
31993
+ function formDisplayFields(form) {
31994
+ if (!form) return {
31995
+ state: "missing",
31996
+ formId: null,
31997
+ groups: []
31998
+ };
31999
+ const fields = form.schemaJson?.fields;
32000
+ return {
32001
+ state: "ready",
32002
+ formId: form.id,
32003
+ groups: Array.isArray(fields) ? groupFormFields(fields) : []
31112
32004
  };
31113
32005
  }
31114
32006
  const formBlockRuntime = defineProgressiveBlockRuntime({
@@ -31131,18 +32023,27 @@ function fragmentLayoutNode$1(layout) {
31131
32023
  function isNodeDefinitionArray$1(layout) {
31132
32024
  return Array.isArray(layout);
31133
32025
  }
31134
- const copyLayout = fragmentLayoutNode$1(formCopyFragment.layout);
32026
+ const copyLayout = props(lookSlot("head"))(fragmentLayoutNode$1(formCopyFragment.layout));
32027
+ const embedLayout$1 = fragmentLayoutNode$1(formEmbedFragment.layout);
31135
32028
  const formSurface = styledContainer({
32029
+ rootProps: lookSlot("panel"),
31136
32030
  bindFrom: "_containerStyles",
31137
32031
  constrainWidth: false,
31138
32032
  baseClassName: "rb-form-surface rb-relative rb-isolate rb-overflow-visible",
31139
- children: fragmentLayoutNode$1(formEmbedFragment.layout)
32033
+ children: embedLayout$1
31140
32034
  });
31141
32035
  function createFormLayout(variant) {
31142
32036
  if (variant === "two-column") return styledSection({
31143
- 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({
32037
+ children: el("div", {
32038
+ className: "rb-container",
32039
+ ...lookSlot("layout")
32040
+ }, [el("div", {
32041
+ className: "rb-form-two-column rb-grid rb-grid-cols-1 rb-gap-8 rb-lg-grid-cols-2 rb-lg-items-start",
32042
+ ...lookSlot("frame")
32043
+ }, [stack({
31144
32044
  gap: "md",
31145
- className: "rb-form-copy-column"
32045
+ className: "rb-form-copy-column",
32046
+ ...lookSlot("copy")
31146
32047
  }, [copyLayout]), formSurface])]),
31147
32048
  baseClass: "",
31148
32049
  spacing: "medium",
@@ -31170,6 +32071,15 @@ const formManifest = createBlockManifest({
31170
32071
  description: "Renders a saved form definition with server-side submit.",
31171
32072
  includeContainerStyles: true,
31172
32073
  fragments: [{ fragment: formCopyFragment }, { fragment: formEmbedFragment }],
32074
+ additionalFields: [{
32075
+ id: "archFrame",
32076
+ type: "boolean",
32077
+ label: "Arch frame",
32078
+ ui: {
32079
+ intent: "display",
32080
+ hidden: true
32081
+ }
32082
+ }],
31173
32083
  layout: formLayout,
31174
32084
  variants: {
31175
32085
  default: formLayout,
@@ -31925,7 +32835,7 @@ const heroTitleLengthThresholds = {
31925
32835
  maxWords: 11
31926
32836
  }
31927
32837
  };
31928
- function isPlainObject$1(value) {
32838
+ function isPlainObject(value) {
31929
32839
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
31930
32840
  }
31931
32841
  function readString(obj, key) {
@@ -31934,7 +32844,7 @@ function readString(obj, key) {
31934
32844
  }
31935
32845
  function resolveGeneratedHeroLayoutStyles(content) {
31936
32846
  const raw = content._heroLayoutStyles;
31937
- return isPlainObject$1(raw) ? raw : null;
32847
+ return isPlainObject(raw) ? raw : null;
31938
32848
  }
31939
32849
  function readHeroLayoutString(content, generatedKey, fallbackKey = generatedKey) {
31940
32850
  const explicitValue = readString(content, fallbackKey);
@@ -31992,7 +32902,7 @@ const heroContentWrapperClassTransform = {
31992
32902
  summary: "Resolve hero content wrapper className from alignment + max width controls",
31993
32903
  schema: z.object({ base: z.string().optional() }),
31994
32904
  run: (value, options, context) => {
31995
- const content = isPlainObject$1(value) ? value : isPlainObject$1(context.data) ? context.data : {};
32905
+ const content = isPlainObject(value) ? value : isPlainObject(context.data) ? context.data : {};
31996
32906
  const alignment = resolveHeroContentAlignment(content);
31997
32907
  const maxWidth = resolveHeroContentMaxWidth(content);
31998
32908
  const typographyScale = resolveHeroTypographyScale(content);
@@ -32014,7 +32924,7 @@ const heroCtaJustifyTransform = {
32014
32924
  kind: "string",
32015
32925
  summary: "Map hero contentAlignment to CTA row justify value",
32016
32926
  run: (value, _options, context) => {
32017
- const alignment = resolveHeroContentAlignment(isPlainObject$1(value) ? value : isPlainObject$1(context.data) ? context.data : {});
32927
+ const alignment = resolveHeroContentAlignment(isPlainObject(value) ? value : isPlainObject(context.data) ? context.data : {});
32018
32928
  return alignment === "left" ? "start" : alignment === "right" ? "end" : "center";
32019
32929
  }
32020
32930
  };
@@ -32023,7 +32933,7 @@ const heroStackJustifyFromVerticalAlignmentTransform = {
32023
32933
  kind: "string",
32024
32934
  summary: "Map hero verticalAlignment to stack justify value",
32025
32935
  run: (value, _options, context) => {
32026
- const vertical = resolveHeroVerticalAlignment(isPlainObject$1(value) ? value : isPlainObject$1(context.data) ? context.data : {});
32936
+ const vertical = resolveHeroVerticalAlignment(isPlainObject(value) ? value : isPlainObject(context.data) ? context.data : {});
32027
32937
  return vertical === "top" ? "start" : vertical === "bottom" ? "end" : "center";
32028
32938
  }
32029
32939
  };
@@ -32033,7 +32943,7 @@ const heroGridClassFromVerticalAlignmentTransform = {
32033
32943
  summary: "Append align-items class for hero split layouts based on verticalAlignment",
32034
32944
  schema: z.object({ base: z.string() }),
32035
32945
  run: (value, options, context) => {
32036
- const vertical = resolveHeroVerticalAlignment(isPlainObject$1(value) ? value : isPlainObject$1(context.data) ? context.data : {});
32946
+ const vertical = resolveHeroVerticalAlignment(isPlainObject(value) ? value : isPlainObject(context.data) ? context.data : {});
32037
32947
  const itemsClass = vertical === "top" ? "rb-items-start" : vertical === "bottom" ? "rb-items-end" : "rb-items-center";
32038
32948
  return joinClasses$1([options.base, itemsClass]);
32039
32949
  }
@@ -32321,6 +33231,25 @@ function heroHeadlineText(content, policy) {
32321
33231
  return policy === "look" ? inlineTextToPlainText(coerceInlineTextWithFallback(content.headlineInline, plain)).trim() : plain?.trim() ?? "";
32322
33232
  }
32323
33233
  //#endregion
33234
+ //#region ../blocks/src/system/transforms/registry/footerArrangement.ts
33235
+ const footerBrandArrangementTransform = {
33236
+ id: "layout.footerBrandArrangement",
33237
+ kind: "string",
33238
+ run: (value) => {
33239
+ const module = asPartialObject(value);
33240
+ return module?.kind === "brand" ? module.slots ? "centred" : "row" : void 0;
33241
+ }
33242
+ };
33243
+ const footerModuleInkStyleTransform = {
33244
+ id: "layout.footerModuleInkStyle",
33245
+ kind: "formatter",
33246
+ run: (value, options) => value === "centred" ? void 0 : textColorStyle(asPartialObject(options)?.opacity === 70 ? "text/70" : "text/80")
33247
+ };
33248
+ /** A centred base without authored bar paint inherits its measured surface line. */
33249
+ function footerBottomBarBorderColorStyle(footer) {
33250
+ return footer?.variant === "centred" && !footer.bottomBar ? { borderColor: "var(--rb-surface-line-color)" } : borderColorStyle(footer?.bottomBar?.borderTop?.colorToken ?? "border");
33251
+ }
33252
+ //#endregion
32324
33253
  //#region ../blocks/src/system/runtime/header/runtimeContract.ts
32325
33254
  const headerScrollRuntimeSchema = z.discriminatedUnion("kind", [z.object({ kind: z.literal("none") }), z.object({ kind: z.literal("threshold") })]);
32326
33255
  z.object({ scroll: headerScrollRuntimeSchema });
@@ -32552,6 +33481,7 @@ const footerRootStyleTransform = {
32552
33481
  }
32553
33482
  }
32554
33483
  styleParts.push(resolvedForegroundStyle(resolveFooterRootForeground(footer, context.theme.palette, context.proseHoverCandidate)));
33484
+ if (footer?.variant === "centred") styleParts.push(surfaceInkStyles(resolveFooterRootForeground(footer, context.theme.palette, context.proseHoverCandidate), context.theme.palette));
32555
33485
  styleParts.push(borderColorStyle("border"));
32556
33486
  return mergeStyles(...styleParts);
32557
33487
  }
@@ -32613,7 +33543,7 @@ const footerBottomBarStyleTransform = {
32613
33543
  run: (value, _options, context) => {
32614
33544
  const footer = asPartialObject(value);
32615
33545
  const bottomBar = footer?.bottomBar;
32616
- 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));
33546
+ return mergeStyles(bottomBar?.background?.type === "color" ? backgroundColorStyle(bottomBar.background.color ?? "surface") : void 0, footerBottomBarBorderColorStyle(footer), footerBottomBarBorderWidthStyle(bottomBar?.borderTop?.width), footerBottomBarForegroundStyle(footer, context.theme.palette));
32617
33547
  }
32618
33548
  };
32619
33549
  function footerBottomBarForegroundStyle(footer, palette) {
@@ -32635,62 +33565,15 @@ function measuredFooterBackdrop(footer, palette) {
32635
33565
  const foreground = resolveFooterRootForeground(footer, palette);
32636
33566
  return foreground.kind === "known" && foreground.provenance.kind === "measured" ? foreground.provenance.backdropHex : null;
32637
33567
  }
32638
- const footerSplitMainClassTransform = {
32639
- id: "layout.footerSplitMainClass",
32640
- kind: "string",
32641
- summary: "Compose split-footer main row classes from footer logo placement",
32642
- schema: z.object({
32643
- base: z.string().optional(),
32644
- reverseClass: z.string().optional()
32645
- }),
32646
- run: (value, options) => {
32647
- const placement = asPartialObject(value)?.placement ?? "right";
32648
- const shouldPlaceLogoFirst = placement === "left" || placement === "above";
32649
- 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";
32650
- return joinClasses([options.base ?? baseClass, shouldPlaceLogoFirst ? options.reverseClass ?? "rb-md-flex-row-reverse" : null]);
32651
- }
32652
- };
32653
33568
  const footerLogoClassTransform = {
32654
33569
  id: "layout.footerLogoClass",
32655
33570
  kind: "string",
32656
33571
  summary: "Compose split-footer logo wrapper classes from footer.logo controls",
32657
- schema: z.object({
32658
- base: z.string().optional(),
32659
- requireExplicitShow: z.boolean().optional()
32660
- }),
33572
+ schema: z.object({ base: z.string().optional() }),
32661
33573
  run: (value, options) => {
32662
- const logo = asPartialObject(value);
32663
- const align = logo?.align ?? "end";
32664
- const hiddenClass = options.requireExplicitShow ? logo?.showLogo === true ? null : "rb-hidden" : logo?.showLogo === false ? "rb-hidden" : null;
33574
+ const align = asPartialObject(value)?.align ?? "end";
32665
33575
  const selfAlignClass = align === "start" ? "rb-self-start rb-text-left" : align === "center" ? "rb-self-center rb-text-center" : "rb-self-end rb-text-right";
32666
- return joinClasses([
32667
- 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",
32668
- selfAlignClass,
32669
- hiddenClass
32670
- ]);
32671
- }
32672
- };
32673
- const footerLogoMediaClassTransform = {
32674
- id: "layout.footerLogoMediaClass",
32675
- kind: "string",
32676
- summary: "Compose footer logo image classes from size controls",
32677
- schema: z.object({ base: z.string().optional() }),
32678
- run: (_value, options) => {
32679
- return joinClasses([options.base ?? "rb-w-auto"]);
32680
- }
32681
- };
32682
- function shouldShowFooterLogoText(footer) {
32683
- if (!footer) return false;
32684
- const explicit = footer.logo?.showLogoText;
32685
- const legacy = footer.showLogoText === true;
32686
- return explicit === true || explicit === void 0 && legacy;
32687
- }
32688
- const footerLogoTextVisibleTransform = {
32689
- id: "layout.footerLogoTextVisible",
32690
- kind: "formatter",
32691
- summary: "Return whether footer logo text should render",
32692
- run: (value) => {
32693
- return shouldShowFooterLogoText(asPartialObject(value));
33576
+ 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]);
32694
33577
  }
32695
33578
  };
32696
33579
  function extractBackgroundColorToken(background, fallback) {
@@ -32709,13 +33592,12 @@ const layoutTransforms = [
32709
33592
  headerRootStyleTransform,
32710
33593
  headerSectionBackgroundTransform,
32711
33594
  footerRootStyleTransform,
33595
+ footerModuleInkStyleTransform,
33596
+ footerBrandArrangementTransform,
32712
33597
  footerBottomBarClassTransform,
32713
33598
  footerBottomBarContainerClassTransform,
32714
33599
  footerBottomBarStyleTransform,
32715
- footerSplitMainClassTransform,
32716
- footerLogoClassTransform,
32717
- footerLogoMediaClassTransform,
32718
- footerLogoTextVisibleTransform
33600
+ footerLogoClassTransform
32719
33601
  ];
32720
33602
  //#endregion
32721
33603
  //#region ../blocks/src/system/transforms/registry/chromeLogo.ts
@@ -33211,7 +34093,14 @@ const footerNavGroupsLayout = stack({
33211
34093
  }, [text({
33212
34094
  as: "h3",
33213
34095
  className: "rb-label",
33214
- style: textColorStyle("text/70")
34096
+ "data-slot": { $bind: { from: "content.footerRuntime.slots.group-label" } },
34097
+ style: { $bind: {
34098
+ from: "content.footerRuntime.arrangement",
34099
+ transforms: [{
34100
+ id: "layout.footerModuleInkStyle",
34101
+ options: { opacity: 70 }
34102
+ }]
34103
+ } }
33215
34104
  }, when("group.label"), bind("group.label")), stack({
33216
34105
  gap: "sm",
33217
34106
  align: "start",
@@ -33241,6 +34130,14 @@ const footerMailingListBindings = {
33241
34130
  targeting: { $bind: { from: "module.engagement.runtime.targeting" } }
33242
34131
  };
33243
34132
  const footerSpamProtectionBinding = { spamProtectionEnabled: { $bind: { from: "$root.spamProtectionEnabled" } } };
34133
+ const brandMedia = media({ className: "rb-h-10 rb-w-auto" }, when("module.showLogo", { equals: true }), when("content.logo"), bind("content", { transforms: [{
34134
+ id: "layout.chromeLogo",
34135
+ options: { surface: "footer-root" }
34136
+ }] }));
34137
+ const brandTitle = text({
34138
+ as: "strong",
34139
+ className: "footer-logo-text rb-nav-text"
34140
+ }, when("module.showTitle", { equals: true }), bind("site.title", { fallback: "Your Site" }));
33244
34141
  const brandLogo = link({
33245
34142
  href: "/",
33246
34143
  className: { $bind: {
@@ -33251,20 +34148,39 @@ const brandLogo = link({
33251
34148
  }],
33252
34149
  fallback: "footer-logo rb-inline-flex rb-items-center rb-gap-3 rb-no-underline"
33253
34150
  } }
33254
- }, [media({ className: { $bind: {
33255
- from: "$root.theme.footer.logo",
33256
- transforms: [{
33257
- id: "layout.footerLogoMediaClass",
33258
- options: { base: "rb-h-10 rb-w-auto" }
33259
- }],
33260
- fallback: "rb-h-10 rb-w-auto"
33261
- } } }, when("module.showLogo", { equals: true }), when("content.logo"), bind("content", { transforms: [{
33262
- id: "layout.chromeLogo",
33263
- options: { surface: "footer-root" }
33264
- }] })), text({
33265
- as: "strong",
33266
- className: "footer-logo-text rb-nav-text"
33267
- }, when("module.showTitle", { equals: true }), bind("site.title", { fallback: "Your Site" }))], when("module.kind", { equals: "brand" }));
34151
+ }, [brandMedia, brandTitle], (node) => ({
34152
+ ...node,
34153
+ $when: {
34154
+ when: {
34155
+ from: "module",
34156
+ transforms: [{ id: "layout.footerBrandArrangement" }]
34157
+ },
34158
+ equals: "row"
34159
+ }
34160
+ }));
34161
+ const centredBrand = stack({
34162
+ gap: "md",
34163
+ align: "center"
34164
+ }, [link({
34165
+ href: "/",
34166
+ "data-slot": { $bind: { from: "module.slots.media" } },
34167
+ className: "footer-logo rb-inline-flex rb-items-center rb-no-underline"
34168
+ }, [brandMedia], when("module.slots.media")), {
34169
+ ...brandTitle,
34170
+ props: {
34171
+ ...brandTitle.props,
34172
+ "data-slot": { $bind: { from: "module.slots.heading" } }
34173
+ }
34174
+ }], (node) => ({
34175
+ ...node,
34176
+ $when: {
34177
+ when: {
34178
+ from: "module",
34179
+ transforms: [{ id: "layout.footerBrandArrangement" }]
34180
+ },
34181
+ equals: "centred"
34182
+ }
34183
+ }));
33268
34184
  const navigation = stack({
33269
34185
  gap: "md",
33270
34186
  className: "rb-w-full"
@@ -33289,14 +34205,18 @@ const address = text({
33289
34205
  }, when("module.kind", { equals: "business-address" }), bind("module.address"));
33290
34206
  const contact = stack({
33291
34207
  gap: "sm",
33292
- className: "rb-items-start"
34208
+ className: { $bind: {
34209
+ from: "module.contactClassName",
34210
+ fallback: "rb-items-start"
34211
+ } }
33293
34212
  }, [link({
33294
34213
  href: { $bind: { from: "contactLink.href" } },
33295
34214
  className: "rb-nav-text rb-break-words transition-theme-standard"
33296
34215
  }, [text({ as: "span" }, bind("contactLink.label"))], repeat("module.contactLinks", "contactLink"))], when("module.kind", { equals: "contact" }));
33297
34216
  const hours = stack({
33298
34217
  gap: "sm",
33299
- className: "rb-w-full"
34218
+ className: "rb-w-full",
34219
+ "data-slot": { $bind: { from: "module.slots.schedule" } }
33300
34220
  }, [inline({ className: "rb-flex rb-w-full rb-justify-between rb-gap-4" }, [text({
33301
34221
  as: "span",
33302
34222
  className: "rb-label"
@@ -33307,7 +34227,10 @@ const hours = stack({
33307
34227
  as: "p",
33308
34228
  className: "rb-caption rb-opacity-70"
33309
34229
  }, bind("module.timeZone"), when("module.timeZone"))], when("module.kind", { equals: "opening-hours" }));
33310
- const socials = inline({ className: "rb-footer-socials" }, [link({
34230
+ const socials = inline({
34231
+ className: "rb-footer-socials",
34232
+ "data-slot": { $bind: { from: "module.slots.social" } }
34233
+ }, [link({
33311
34234
  href: { $bind: { from: "social.href" } },
33312
34235
  target: "_blank",
33313
34236
  rel: "noreferrer noopener",
@@ -33316,7 +34239,14 @@ const socials = inline({ className: "rb-footer-socials" }, [link({
33316
34239
  }, [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" }));
33317
34240
  const authoredCopy = richText({
33318
34241
  className: "rb-prose rb-prose-sm rb-max-w-none",
33319
- style: textColorStyle("text/80")
34242
+ "data-slot": { $bind: { from: "module.slots.copy" } },
34243
+ style: { $bind: {
34244
+ from: "content.footerRuntime.arrangement",
34245
+ transforms: [{
34246
+ id: "layout.footerModuleInkStyle",
34247
+ options: { opacity: 80 }
34248
+ }]
34249
+ } }
33320
34250
  }, when("module.content"), bind("module.content", { transforms: [{
33321
34251
  id: "content.interpolateRichTextTokens",
33322
34252
  options: { tokens: ["year", "site_name"] }
@@ -33354,27 +34284,44 @@ const platformAttribution = el("div", {
33354
34284
  ], when("module.kind", { equals: "attribution" }));
33355
34285
  const footerGroup = stack({
33356
34286
  gap: "md",
33357
- align: "stretch",
34287
+ align: { $bind: {
34288
+ from: "group.align",
34289
+ fallback: "stretch"
34290
+ } },
33358
34291
  className: { $bind: {
33359
34292
  from: "group.className",
33360
34293
  fallback: "rb-min-w-0"
33361
34294
  } },
34295
+ "data-slot": { $bind: { from: "group.slot" } },
33362
34296
  "data-footer-group": { $bind: { from: "group.kind" } }
33363
34297
  }, [stack({
33364
34298
  gap: "md",
33365
- align: "start",
34299
+ align: { $bind: {
34300
+ from: "module.align",
34301
+ fallback: "start"
34302
+ } },
34303
+ className: { $bind: { from: "module.className" } },
33366
34304
  "data-preview-footer-module-id": { $bind: { from: "module.id" } }
33367
34305
  }, [
33368
34306
  text({
33369
34307
  as: "h2",
33370
34308
  className: "rb-label",
33371
- style: textColorStyle("text/70")
34309
+ "data-slot": { $bind: { from: "module.slots.group-label" } },
34310
+ style: { $bind: {
34311
+ from: "content.footerRuntime.arrangement",
34312
+ transforms: [{
34313
+ id: "layout.footerModuleInkStyle",
34314
+ options: { opacity: 70 }
34315
+ }]
34316
+ } }
33372
34317
  }, bind("module.heading"), when("module.heading")),
33373
34318
  brandLogo,
34319
+ centredBrand,
33374
34320
  navigation,
33375
34321
  stack({
33376
34322
  gap: "sm",
33377
- className: "rb-w-full"
34323
+ className: "rb-w-full",
34324
+ "data-slot": { $bind: { from: "module.slots.navigation" } }
33378
34325
  }, [legalNavigation], when("module.kind", { equals: "legal-navigation" })),
33379
34326
  address,
33380
34327
  contact,
@@ -33387,10 +34334,12 @@ const footerGroup = stack({
33387
34334
  ], repeat("group.modules", "module"))], repeat("region.groups", "group"));
33388
34335
  const footerMainRegion = stack({
33389
34336
  className: { $bind: { from: "region.className" } },
34337
+ "data-slot": { $bind: { from: "region.slot" } },
33390
34338
  "data-footer-region": { $bind: { from: "region.kind" } }
33391
34339
  }, [footerGroup], when("region.kind", { equals: "main" }), repeat("content.footerRuntime.regions", "region"));
33392
34340
  const footerEngagementRegion = stack({
33393
34341
  className: { $bind: { from: "region.className" } },
34342
+ "data-slot": { $bind: { from: "region.slot" } },
33394
34343
  "data-footer-region": "engagement-row"
33395
34344
  }, [footerGroup], when("region.kind", { equals: "engagement-row" }), repeat("content.footerRuntime.regions", "region"));
33396
34345
  const footerBottomRegion = stack({ className: { $bind: {
@@ -33407,6 +34356,7 @@ const footerBottomRegion = stack({ className: { $bind: {
33407
34356
  from: "$root.theme.footer",
33408
34357
  transforms: [{ id: "layout.footerBottomBarStyle" }]
33409
34358
  } },
34359
+ "data-slot": { $bind: { from: "region.slot" } },
33410
34360
  "data-footer-region": "bottom"
33411
34361
  }, [footerGroup])], when("region.kind", { equals: "bottom" }), repeat("content.footerRuntime.regions", "region"));
33412
34362
  const siteFooterBlockDefinition = { manifest: createBlockManifest({
@@ -33428,6 +34378,7 @@ const siteFooterBlockDefinition = { manifest: createBlockManifest({
33428
34378
  transforms: [{ id: "layout.footerRootStyle" }],
33429
34379
  fallback: mergeStyles(backgroundColorStyle("surface"), surfaceForegroundStyle({ text: "rgb(var(--tb-text))" }), borderColorStyle("border"))
33430
34380
  } },
34381
+ "data-arrangement": { $bind: { from: "content.footerRuntime.arrangementHook" } },
33431
34382
  "data-footer-membership": { $bind: { from: "content.footerRuntime.membershipKey" } }
33432
34383
  }, [
33433
34384
  footerEngagementRegion,
@@ -35029,17 +35980,30 @@ const mediaTextBlockDefinition = { manifest: createBlockManifest({
35029
35980
  }],
35030
35981
  fallback: ""
35031
35982
  } };
35032
- const copyHeading = el("div", { className: titleClassNameFromAlignment }, [text({
35983
+ const copyHeading = el("div", {
35984
+ className: titleClassNameFromAlignment,
35985
+ ...lookSlot("head")
35986
+ }, [text({
35033
35987
  as: "p",
35034
- className: eyebrowClassName("rb-eyebrow heading-eyebrow")
35035
- }, when("content.eyebrow"), bind("content.eyebrow")), text({ as: "h2" }, bind("content.title"))], when("content.title"));
35036
- 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"))]);
35037
- 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" }, [
35038
- copyHeading,
35039
- styledCard([richText({ className: bodyClassNameFromAlignment }, bind("content.text"))], mediaTextCardOptions, when("content.wrapTextInCard")),
35040
- richText({ className: bodyClassNameFromAlignment }, when("content.wrapTextInCard", { not: true }), bind("content.text"))
35041
- ]);
35988
+ className: eyebrowClassName("rb-eyebrow heading-eyebrow"),
35989
+ ...lookSlot("eyebrow")
35990
+ }, when("content.eyebrow"), bind("content.eyebrow")), text({
35991
+ as: "h2",
35992
+ ...lookSlot("heading")
35993
+ }, bind("content.title"))], when("content.title"));
35994
+ const textContentNodes = (className) => {
35995
+ const props = {
35996
+ className,
35997
+ ...lookSlot("intro"),
35998
+ leadParagraphSlot: { $bind: { from: "content._lookSlots.lede" } },
35999
+ lookSlots: { $bind: { from: "content._lookSlots" } }
36000
+ };
36001
+ return [styledCard([richText(props, bind("content.text"))], mediaTextCardOptions, when("content.wrapTextInCard")), richText(props, when("content.wrapTextInCard", { not: true }), bind("content.text"))];
36002
+ };
36003
+ const defaultTextColumn = el("div", {}, textContentNodes("rb-prose rb-max-w-none"));
36004
+ 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)]);
35042
36005
  const defaultImageCommonProps = {
36006
+ ...lookSlot("photo"),
35043
36007
  className: { $bind: {
35044
36008
  from: "content.imageShape",
35045
36009
  transforms: [{
@@ -35079,6 +36043,7 @@ const mediaTextBlockDefinition = { manifest: createBlockManifest({
35079
36043
  slidesToShow: 1
35080
36044
  }, [media(defaultImageCommonProps, bind("item.image"), repeat("content.images", "item"))]);
35081
36045
  const defaultImagesLayout = el("div", {}, [responsiveTwoColumn({
36046
+ lookSlots: true,
35082
36047
  image: el("div", {}, [el("div", {}, [defaultSingleImage], whenImagesLength(1)), el("div", {}, [defaultCarouselImages], whenImagesLength(1, { not: true }))]),
35083
36048
  text: defaultTextColumn,
35084
36049
  ratioFrom: "content.ratio",
@@ -35090,6 +36055,7 @@ const mediaTextBlockDefinition = { manifest: createBlockManifest({
35090
36055
  textWrapperClassName: "rb-w-full rb-min-w-0 rb-flex-1"
35091
36056
  })], whenImagesLength(0, { not: true }));
35092
36057
  const bioImagesLayout = el("div", {}, [responsiveTwoColumn({
36058
+ lookSlots: true,
35093
36059
  image: el("div", {}, [el("div", {}, [defaultSingleImage], whenImagesLength(1)), el("div", {}, [defaultCarouselImages], whenImagesLength(1, { not: true }))]),
35094
36060
  text: bioTextColumn,
35095
36061
  ratioFrom: "content.ratio",
@@ -35100,15 +36066,15 @@ const mediaTextBlockDefinition = { manifest: createBlockManifest({
35100
36066
  imageWrapperClassName: "rb-w-full rb-shrink-0",
35101
36067
  textWrapperClassName: "rb-w-full rb-min-w-0 rb-flex-1 rb-self-stretch"
35102
36068
  })], whenImagesLength(0, { not: true }));
35103
- 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));
35104
- const bioTextOnlyLayout = el("div", { className: "rb-flex rb-w-full rb-max-w-prose rb-flex-col rb-gap-5" }, [
35105
- text({
35106
- as: "h2",
35107
- className: titleClassNameFromAlignment
35108
- }, when("content.title"), bind("content.title")),
35109
- styledCard([richText({ className: bodyClassNameFromAlignment }, bind("content.text"))], mediaTextCardOptions, when("content.wrapTextInCard")),
35110
- richText({ className: bodyClassNameFromAlignment }, when("content.wrapTextInCard", { not: true }), bind("content.text"))
35111
- ], whenImagesLength(0));
36069
+ const defaultTextOnlyLayout = el("div", lookSlot("copy"), textContentNodes("rb-prose rb-max-w-none"), whenImagesLength(0));
36070
+ const bioTextOnlyLayout = el("div", {
36071
+ className: "rb-flex rb-w-full rb-max-w-prose rb-flex-col rb-gap-5",
36072
+ ...lookSlot("copy")
36073
+ }, [text({
36074
+ as: "h2",
36075
+ className: titleClassNameFromAlignment,
36076
+ ...lookSlot("heading")
36077
+ }, when("content.title"), bind("content.title")), ...textContentNodes(bodyClassNameFromAlignment)], whenImagesLength(0));
35112
36078
  const defaultInner = el("div", {}, [defaultImagesLayout, defaultTextOnlyLayout]);
35113
36079
  const bioInner = el("div", {}, [bioImagesLayout, bioTextOnlyLayout]);
35114
36080
  const defaultLayout = styledSection({
@@ -35132,9 +36098,31 @@ const mediaTextBlockDefinition = { manifest: createBlockManifest({
35132
36098
  }),
35133
36099
  baseClass: "",
35134
36100
  spacing: "medium"
36101
+ }),
36102
+ "circle-beside": styledSection({
36103
+ baseClass: "",
36104
+ spacing: "medium",
36105
+ children: styledContainer({ children: el("div", lookSlot("frame"), [el("div", lookSlot("media"), [
36106
+ el("div", {}, [when("content.images[0].image")(defaultSingleImage)], whenImagesLength(1)),
36107
+ el("div", {}, [el("div", {}, [defaultCarouselImages], whenImagesLength(1, { not: true }))], whenImagesLength(0, { not: true })),
36108
+ el("div", {}, [when("content.images[0].image")(defaultSingleImage)], whenImagesLength(0))
36109
+ ]), el("div", lookSlot("copy"), [el("div", lookSlot("head"), [text({
36110
+ as: "p",
36111
+ className: eyebrowClassName("rb-eyebrow heading-eyebrow"),
36112
+ ...lookSlot("eyebrow")
36113
+ }, when("content.eyebrow"), bind("content.eyebrow")), text({
36114
+ as: "h2",
36115
+ ...lookSlot("heading")
36116
+ }, bind("content.title"), when("content.title", { authoringPresence: {
36117
+ kind: "recover-empty-when-active",
36118
+ placeholder: "Add heading"
36119
+ } }))]), defaultTextColumn])]) })
35135
36120
  })
35136
36121
  },
35137
- variantMeaning: { kind: "arrangement" },
36122
+ variantMeaning: {
36123
+ kind: "arrangement",
36124
+ lookOnlyKeys: ["circle-beside"]
36125
+ },
35138
36126
  defaultVariant: "default",
35139
36127
  variantOptions: {
35140
36128
  default: { label: "Default" },
@@ -35615,14 +36603,6 @@ const weeklySlotAvailabilityBlockDefinition = {
35615
36603
  } }
35616
36604
  };
35617
36605
  //#endregion
35618
- //#region ../blocks/src/lib/media.ts
35619
- const PUBLIC_DOWNLOAD_MEDIA_TYPES = [
35620
- "document",
35621
- "spreadsheet",
35622
- "archive",
35623
- "audio"
35624
- ];
35625
- //#endregion
35626
36606
  //#region ../blocks/src/system/manifest/richTextSchema.ts
35627
36607
  /**
35628
36608
  * Shared Rich Text Schema
@@ -36058,7 +37038,7 @@ const publicEventBaseSchema = z.object({
36058
37038
  content: z.object({ body: RichTextDocSchema.nullable().optional() }).optional(),
36059
37039
  presentation: z.object({
36060
37040
  summary: z.string().nullable().optional(),
36061
- image: mediaSchema.nullable().optional()
37041
+ image: runtimeMediaSchema.nullable().optional()
36062
37042
  }).optional(),
36063
37043
  slug: z.string(),
36064
37044
  path: z.string().nullable(),
@@ -36238,24 +37218,6 @@ const emptyStateField = {
36238
37218
  ui: { intent: "display" }
36239
37219
  };
36240
37220
  /**
36241
- * Section heading and description fields
36242
- */
36243
- const sectionHeaderFields = (defaultHeading) => [{
36244
- id: "heading",
36245
- type: "text",
36246
- label: "Heading",
36247
- description: "Main heading for the events section",
36248
- required: false,
36249
- multiline: false,
36250
- defaultValue: defaultHeading
36251
- }, {
36252
- id: "description",
36253
- type: "richText",
36254
- label: "Description",
36255
- description: "Optional introductory text",
36256
- required: false
36257
- }];
36258
- /**
36259
37221
  * Layout selection field with grid/stack options
36260
37222
  */
36261
37223
  const layoutField = {
@@ -36368,31 +37330,6 @@ function normalizeEventStaffMemberId(value) {
36368
37330
  return trimmed ? trimmed : null;
36369
37331
  }
36370
37332
  //#endregion
36371
- //#region ../blocks/src/system/blocks/events/shared/layout.ts
36372
- const recoverEmptyHeadingWhenActive = {
36373
- kind: "recover-empty-when-active",
36374
- placeholder: "Add heading"
36375
- };
36376
- const recoverEmptyDescriptionWhenActive = {
36377
- kind: "recover-empty-when-active",
36378
- placeholder: "Add description"
36379
- };
36380
- function eventSectionHeaderLayoutNodes(options = {}) {
36381
- const headingNode = text({
36382
- as: "h2",
36383
- ...lookSlot("heading")
36384
- }, bind("content.heading"), when("content.heading", { authoringPresence: recoverEmptyHeadingWhenActive }));
36385
- const descriptionNode = richText({
36386
- className: "rb-prose rb-max-w-none",
36387
- ...lookSlot("intro")
36388
- }, bind("content.description"), when("content.description", { authoringPresence: recoverEmptyDescriptionWhenActive }));
36389
- if (options.splitClassName) return [el("div", {
36390
- className: options.splitClassName,
36391
- ...lookSlot("head")
36392
- }, [headingNode, descriptionNode])];
36393
- return [headingNode, descriptionNode];
36394
- }
36395
- //#endregion
36396
37333
  //#region ../blocks/src/system/blocks/shop.shared.ts
36397
37334
  /**
36398
37335
  * Public pass product for shop display
@@ -36817,19 +37754,14 @@ function buildCalendarViewport(input) {
36817
37754
  *
36818
37755
  * Sites don't store a locale, and every public word around a date is English,
36819
37756
  * so the only open question is which English conventions to follow: day or
36820
- * month first, and a 24 or 12-hour clock. The site's time zone is the one
37757
+ * month first. The site's time zone is the one
36821
37758
  * fact every site carries about where it is. It is the site's, never an
36822
37759
  * event's: a venue left at UTC must not turn a UK site's dates American.
36823
37760
  * Anywhere this can't place (UTC, the Americas, Asia) keeps US English, which
36824
37761
  * is what these helpers wrote before sites were placed at all.
36825
37762
  */
36826
37763
  function eventDateLocale(siteTimeZone) {
36827
- if (!siteTimeZone) return "en-US";
36828
- if (siteTimeZone === "Europe/Dublin") return "en-IE";
36829
- if (siteTimeZone.startsWith("Europe/")) return "en-GB";
36830
- if (siteTimeZone.startsWith("Australia/")) return "en-AU";
36831
- if (siteTimeZone === "Pacific/Auckland" || siteTimeZone === "Pacific/Chatham") return "en-NZ";
36832
- return "en-US";
37764
+ return inferSiteDateLocale(siteTimeZone);
36833
37765
  }
36834
37766
  function formatEventCompactDateRail(isoTimestamp, options, letterCase = "capitals") {
36835
37767
  const locale = options?.locale ?? "en-US";
@@ -38537,7 +39469,7 @@ const eventSpotlightBlockDefinition = {
38537
39469
  ],
38538
39470
  icon: "Star",
38539
39471
  layout: [styledSection({
38540
- children: sectionContainer([...eventSectionHeaderLayoutNodes(), el("event-spotlight", {
39472
+ children: sectionContainer([...sectionHeaderLayoutNodes(), el("event-spotlight", {
38541
39473
  events: { $bind: { from: "data.events" } },
38542
39474
  layout: { $bind: {
38543
39475
  from: "content.layout",
@@ -38593,52 +39525,6 @@ const eventSpotlightBlockDefinition = {
38593
39525
  } }
38594
39526
  };
38595
39527
  //#endregion
38596
- //#region ../blocks/src/system/runtime/lookSurfaces.ts
38597
- const isPlainObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
38598
- const lookListPresentationSchemaShape = {
38599
- sectionAction: z.object({
38600
- label: z.string(),
38601
- href: z.string()
38602
- }).optional(),
38603
- actionSize: z.enum([
38604
- "sm",
38605
- "md",
38606
- "lg"
38607
- ]).optional(),
38608
- itemActionStyle: z.enum(["button", "link"]).optional(),
38609
- itemRoles: z.object({
38610
- container: z.enum([
38611
- "card",
38612
- "statement",
38613
- "highlight"
38614
- ]).optional(),
38615
- items: z.enum([
38616
- "card",
38617
- "statement",
38618
- "highlight"
38619
- ]).optional(),
38620
- at: z.partialRecord(z.enum([
38621
- "first",
38622
- "last",
38623
- "middle",
38624
- "odd",
38625
- "even"
38626
- ]), z.enum([
38627
- "card",
38628
- "statement",
38629
- "highlight"
38630
- ])).optional()
38631
- }).optional(),
38632
- roleSurfaces: z.record(z.enum([
38633
- "card",
38634
- "statement",
38635
- "highlight"
38636
- ]), z.custom((value) => isPlainObject(value) && (value.kind === "inherit" || value.kind === "owned"))).optional(),
38637
- panelHeading: z.string().optional(),
38638
- lookSlots: z.partialRecord(z.enum(arrangementSlotNames), z.enum(arrangementSlotNames)).optional(),
38639
- itemSurfaces: z.record(z.string(), z.custom((value) => isPlainObject(value) && (value.kind === "inherit" || value.kind === "owned"))).optional()
38640
- };
38641
- //#endregion
38642
39528
  //#region ../blocks/src/system/blocks/events/shared/eventSelection.ts
38643
39529
  /** Invalid saved selections fail closed rather than widening discovery. */
38644
39530
  function resolveEventSelection(mode, value) {
@@ -39413,7 +40299,7 @@ const eventListingBlockDefinition = {
39413
40299
  children: styledContainer({
39414
40300
  rootType: "stack",
39415
40301
  rootProps: { gap: "lg" },
39416
- children: [...eventSectionHeaderLayoutNodes(), el("event-listing", withApiBindings({
40302
+ children: [...sectionHeaderLayoutNodes(), el("event-listing", withApiBindings({
39417
40303
  readAuthority: { $bind: { from: "$root.readAuthority" } },
39418
40304
  events: { $bind: { from: "data.events" } },
39419
40305
  stage: { $bind: {
@@ -39853,7 +40739,7 @@ const eventCalendarLayout = [styledSection({
39853
40739
  gap: "lg",
39854
40740
  ...lookSlot("layout")
39855
40741
  },
39856
- children: [...eventSectionHeaderLayoutNodes({ splitClassName: "event-section-head event-section-head--split" }), el("event-calendar", withApiBindings({
40742
+ children: [...sectionHeaderLayoutNodes({ splitClassName: "event-section-head event-section-head--split" }), el("event-calendar", withApiBindings({
39857
40743
  readAuthority: { $bind: { from: "$root.readAuthority" } },
39858
40744
  events: { $bind: { from: "data.events" } },
39859
40745
  effectiveListArrangementKey: { $bind: { from: "$root.effectiveListArrangementKey" } },
@@ -41809,6 +42695,511 @@ const embedBlockDefinition = {
41809
42695
  } }
41810
42696
  };
41811
42697
  //#endregion
42698
+ //#region ../blocks/src/system/blocks/image-gallery/fields.ts
42699
+ const imageGalleryFields = parseFieldDefinitions([
42700
+ ...sectionHeaderFields(void 0, "Intro"),
42701
+ {
42702
+ id: "images",
42703
+ type: "repeater",
42704
+ label: "Images",
42705
+ itemLabel: "Image",
42706
+ minItems: 0,
42707
+ maxItems: 24,
42708
+ ui: {
42709
+ repeaterPreset: "thumbnailGrid",
42710
+ thumbnailField: "image",
42711
+ thumbnailAltField: "caption",
42712
+ thumbnailLabelField: "caption",
42713
+ thumbnailCardDensity: "compact"
42714
+ },
42715
+ schema: { fields: [{
42716
+ id: "image",
42717
+ type: "media",
42718
+ label: "Image",
42719
+ required: true,
42720
+ mediaKinds: ["image"]
42721
+ }, {
42722
+ id: "caption",
42723
+ type: "text",
42724
+ label: "Caption",
42725
+ description: "Optional caption displayed below the image and used as the editor card label",
42726
+ maxLength: 200
42727
+ }] }
42728
+ },
42729
+ {
42730
+ id: "fullBleed",
42731
+ type: "boolean",
42732
+ label: "Full bleed",
42733
+ description: "Extend the gallery edge-to-edge by removing section side padding and container max-width.",
42734
+ defaultValue: false,
42735
+ ui: {
42736
+ intent: "display",
42737
+ visibleWhen: {
42738
+ field: "variant",
42739
+ notIn: ["marquee"]
42740
+ }
42741
+ }
42742
+ },
42743
+ {
42744
+ id: "aspectRatio",
42745
+ type: "select",
42746
+ label: "Aspect ratio",
42747
+ description: "Crop images to a consistent aspect ratio.",
42748
+ defaultValue: "1/1",
42749
+ options: [
42750
+ {
42751
+ value: "auto",
42752
+ label: "Original"
42753
+ },
42754
+ {
42755
+ value: "1/1",
42756
+ label: "1:1 (Square)"
42757
+ },
42758
+ {
42759
+ value: "4/3",
42760
+ label: "4:3 (Standard)"
42761
+ },
42762
+ {
42763
+ value: "16/9",
42764
+ label: "16:9 (Widescreen)"
42765
+ },
42766
+ {
42767
+ value: "3/2",
42768
+ label: "3:2 (Classic)"
42769
+ },
42770
+ {
42771
+ value: "3/4",
42772
+ label: "3:4 (Portrait)"
42773
+ }
42774
+ ],
42775
+ ui: {
42776
+ intent: "display",
42777
+ visibleWhen: {
42778
+ field: "variant",
42779
+ notIn: ["masonry", "marquee"]
42780
+ }
42781
+ }
42782
+ },
42783
+ {
42784
+ id: "slidesToShow",
42785
+ type: "select",
42786
+ label: "Images per view (mobile)",
42787
+ description: "Number of images visible at once on small screens.",
42788
+ defaultValue: "1",
42789
+ options: [
42790
+ {
42791
+ value: "1",
42792
+ label: "One at a time"
42793
+ },
42794
+ {
42795
+ value: "2",
42796
+ label: "Two at a time"
42797
+ },
42798
+ {
42799
+ value: "3",
42800
+ label: "Three at a time"
42801
+ }
42802
+ ],
42803
+ ui: {
42804
+ intent: "display",
42805
+ visibleWhen: {
42806
+ field: "variant",
42807
+ equals: "carousel"
42808
+ }
42809
+ }
42810
+ },
42811
+ {
42812
+ id: "slidesToShowTablet",
42813
+ type: "select",
42814
+ label: "Images per view (tablet)",
42815
+ description: "Number of images visible on medium screens.",
42816
+ options: [
42817
+ {
42818
+ value: "",
42819
+ label: "Same as mobile"
42820
+ },
42821
+ {
42822
+ value: "1",
42823
+ label: "One at a time"
42824
+ },
42825
+ {
42826
+ value: "2",
42827
+ label: "Two at a time"
42828
+ },
42829
+ {
42830
+ value: "3",
42831
+ label: "Three at a time"
42832
+ }
42833
+ ],
42834
+ ui: {
42835
+ intent: "display",
42836
+ visibleWhen: {
42837
+ field: "variant",
42838
+ equals: "carousel"
42839
+ }
42840
+ }
42841
+ },
42842
+ {
42843
+ id: "slidesToShowDesktop",
42844
+ type: "select",
42845
+ label: "Images per view (desktop)",
42846
+ description: "Number of images visible on large screens.",
42847
+ options: [
42848
+ {
42849
+ value: "",
42850
+ label: "Same as tablet"
42851
+ },
42852
+ {
42853
+ value: "1",
42854
+ label: "One at a time"
42855
+ },
42856
+ {
42857
+ value: "2",
42858
+ label: "Two at a time"
42859
+ },
42860
+ {
42861
+ value: "3",
42862
+ label: "Three at a time"
42863
+ }
42864
+ ],
42865
+ ui: {
42866
+ intent: "display",
42867
+ visibleWhen: {
42868
+ field: "variant",
42869
+ equals: "carousel"
42870
+ }
42871
+ }
42872
+ },
42873
+ {
42874
+ id: "transition",
42875
+ type: "select",
42876
+ label: "Transition",
42877
+ description: "Animation style between slides.",
42878
+ defaultValue: "slide",
42879
+ options: [{
42880
+ value: "slide",
42881
+ label: "Slide"
42882
+ }, {
42883
+ value: "fade",
42884
+ label: "Fade"
42885
+ }],
42886
+ ui: {
42887
+ intent: "display",
42888
+ visibleWhen: {
42889
+ field: "variant",
42890
+ equals: "carousel"
42891
+ }
42892
+ }
42893
+ },
42894
+ {
42895
+ id: "showControls",
42896
+ type: "boolean",
42897
+ label: "Show arrows",
42898
+ defaultValue: true,
42899
+ ui: {
42900
+ intent: "behavior",
42901
+ visibleWhen: {
42902
+ field: "variant",
42903
+ equals: "carousel"
42904
+ }
42905
+ }
42906
+ },
42907
+ {
42908
+ id: "showDots",
42909
+ type: "boolean",
42910
+ label: "Show dots",
42911
+ defaultValue: false,
42912
+ ui: {
42913
+ intent: "behavior",
42914
+ visibleWhen: {
42915
+ field: "variant",
42916
+ equals: "carousel"
42917
+ }
42918
+ }
42919
+ },
42920
+ {
42921
+ id: "autoplay",
42922
+ type: "boolean",
42923
+ label: "Autoplay",
42924
+ defaultValue: false,
42925
+ ui: {
42926
+ intent: "behavior",
42927
+ visibleWhen: {
42928
+ field: "variant",
42929
+ equals: "carousel"
42930
+ }
42931
+ }
42932
+ },
42933
+ {
42934
+ id: "autoplayDelay",
42935
+ type: "select",
42936
+ label: "Autoplay delay",
42937
+ defaultValue: "5000",
42938
+ options: [
42939
+ {
42940
+ value: "3000",
42941
+ label: "3 seconds"
42942
+ },
42943
+ {
42944
+ value: "5000",
42945
+ label: "5 seconds"
42946
+ },
42947
+ {
42948
+ value: "7000",
42949
+ label: "7 seconds"
42950
+ },
42951
+ {
42952
+ value: "10000",
42953
+ label: "10 seconds"
42954
+ }
42955
+ ],
42956
+ ui: {
42957
+ intent: "behavior",
42958
+ visibleWhen: {
42959
+ field: "variant",
42960
+ equals: "carousel"
42961
+ }
42962
+ }
42963
+ },
42964
+ {
42965
+ id: "arrowVisibility",
42966
+ type: "select",
42967
+ label: "Arrow visibility",
42968
+ defaultValue: "always",
42969
+ options: [{
42970
+ value: "always",
42971
+ label: "Always visible"
42972
+ }, {
42973
+ value: "hover",
42974
+ label: "Show on hover"
42975
+ }],
42976
+ ui: {
42977
+ intent: "behavior",
42978
+ visibleWhen: {
42979
+ field: "variant",
42980
+ equals: "carousel"
42981
+ }
42982
+ }
42983
+ },
42984
+ {
42985
+ id: "loop",
42986
+ type: "boolean",
42987
+ label: "Loop slides",
42988
+ defaultValue: true,
42989
+ ui: {
42990
+ intent: "behavior",
42991
+ visibleWhen: {
42992
+ field: "variant",
42993
+ equals: "carousel"
42994
+ }
42995
+ }
42996
+ },
42997
+ {
42998
+ id: "marqueeDirection",
42999
+ type: "select",
43000
+ label: "Scroll direction",
43001
+ options: [{
43002
+ value: "left",
43003
+ label: "Left"
43004
+ }, {
43005
+ value: "right",
43006
+ label: "Right"
43007
+ }],
43008
+ defaultValue: "left",
43009
+ ui: {
43010
+ intent: "display",
43011
+ visibleWhen: {
43012
+ field: "variant",
43013
+ equals: "marquee"
43014
+ }
43015
+ }
43016
+ },
43017
+ {
43018
+ id: "marqueeSpeed",
43019
+ type: "select",
43020
+ label: "Scroll speed",
43021
+ options: [
43022
+ {
43023
+ value: "slow",
43024
+ label: "Slow (60s)"
43025
+ },
43026
+ {
43027
+ value: "medium",
43028
+ label: "Medium (40s)"
43029
+ },
43030
+ {
43031
+ value: "fast",
43032
+ label: "Fast (20s)"
43033
+ }
43034
+ ],
43035
+ defaultValue: "medium",
43036
+ ui: {
43037
+ intent: "display",
43038
+ visibleWhen: {
43039
+ field: "variant",
43040
+ equals: "marquee"
43041
+ }
43042
+ }
43043
+ },
43044
+ {
43045
+ id: "marqueePauseOnHover",
43046
+ type: "boolean",
43047
+ label: "Pause on hover",
43048
+ defaultValue: true,
43049
+ ui: {
43050
+ intent: "behavior",
43051
+ visibleWhen: {
43052
+ field: "variant",
43053
+ equals: "marquee"
43054
+ }
43055
+ }
43056
+ },
43057
+ {
43058
+ id: "marqueeImageSize",
43059
+ type: "select",
43060
+ label: "Image size",
43061
+ options: [
43062
+ {
43063
+ value: "sm",
43064
+ label: "Small (200px)"
43065
+ },
43066
+ {
43067
+ value: "md",
43068
+ label: "Medium (256px)"
43069
+ },
43070
+ {
43071
+ value: "lg",
43072
+ label: "Large (320px)"
43073
+ },
43074
+ {
43075
+ value: "xl",
43076
+ label: "Extra large (400px)"
43077
+ }
43078
+ ],
43079
+ defaultValue: "md",
43080
+ ui: {
43081
+ intent: "display",
43082
+ visibleWhen: {
43083
+ field: "variant",
43084
+ equals: "marquee"
43085
+ }
43086
+ }
43087
+ },
43088
+ {
43089
+ id: "imageFilter",
43090
+ type: "select",
43091
+ label: "Image filter",
43092
+ options: [
43093
+ {
43094
+ value: "none",
43095
+ label: "None"
43096
+ },
43097
+ {
43098
+ value: "grayscale",
43099
+ label: "Grayscale"
43100
+ },
43101
+ {
43102
+ value: "grayscale-hover-reveal",
43103
+ label: "Grayscale (color on hover)"
43104
+ },
43105
+ {
43106
+ value: "sepia",
43107
+ label: "Sepia"
43108
+ }
43109
+ ],
43110
+ defaultValue: "grayscale-hover-reveal",
43111
+ ui: { intent: "style" }
43112
+ },
43113
+ {
43114
+ id: "imageBorder",
43115
+ type: "group",
43116
+ label: "Image border",
43117
+ schema: { fields: [
43118
+ {
43119
+ id: "enabled",
43120
+ type: "boolean",
43121
+ label: "Show border",
43122
+ defaultValue: true
43123
+ },
43124
+ {
43125
+ id: "colorToken",
43126
+ type: "text",
43127
+ label: "Border color",
43128
+ defaultValue: "accent",
43129
+ ui: { widget: "backgroundColor" }
43130
+ },
43131
+ {
43132
+ id: "opacity",
43133
+ type: "number",
43134
+ label: "Border opacity",
43135
+ defaultValue: 30,
43136
+ ui: {
43137
+ min: 0,
43138
+ max: 100
43139
+ }
43140
+ },
43141
+ {
43142
+ id: "width",
43143
+ type: "select",
43144
+ label: "Border width",
43145
+ options: [
43146
+ {
43147
+ value: "1",
43148
+ label: "Thin (1px)"
43149
+ },
43150
+ {
43151
+ value: "2",
43152
+ label: "Medium (2px)"
43153
+ },
43154
+ {
43155
+ value: "3",
43156
+ label: "Thick (3px)"
43157
+ }
43158
+ ],
43159
+ defaultValue: "2"
43160
+ }
43161
+ ] },
43162
+ ui: { intent: "style" }
43163
+ },
43164
+ {
43165
+ id: "imageCorners",
43166
+ type: "select",
43167
+ label: "Image corners",
43168
+ options: [
43169
+ {
43170
+ value: "none",
43171
+ label: "Square"
43172
+ },
43173
+ {
43174
+ value: "sm",
43175
+ label: "Slightly rounded"
43176
+ },
43177
+ {
43178
+ value: "md",
43179
+ label: "Rounded"
43180
+ },
43181
+ {
43182
+ value: "lg",
43183
+ label: "More rounded"
43184
+ },
43185
+ {
43186
+ value: "xl",
43187
+ label: "Very rounded"
43188
+ },
43189
+ {
43190
+ value: "2xl",
43191
+ label: "Extra rounded"
43192
+ },
43193
+ {
43194
+ value: "3xl",
43195
+ label: "Maximum rounded"
43196
+ }
43197
+ ],
43198
+ defaultValue: "3xl",
43199
+ ui: { intent: "style" }
43200
+ }
43201
+ ]);
43202
+ //#endregion
41812
43203
  //#region ../blocks/src/system/blocks/image-gallery.ts
41813
43204
  const grid$1 = (props, children, ...mods) => el("grid", props ?? void 0, children ?? void 0, ...mods);
41814
43205
  const galleryContainer = (children, opts) => {
@@ -42023,7 +43414,11 @@ const emptyState$1 = {
42023
43414
  }
42024
43415
  };
42025
43416
  const wrapVariant$1 = (layout, opts) => styledSection({
42026
- children: galleryContainer([layout, emptyState$1], {
43417
+ children: galleryContainer([
43418
+ ...sectionHeaderLayoutNodes(),
43419
+ layout,
43420
+ emptyState$1
43421
+ ], {
42027
43422
  gap: "md",
42028
43423
  fullWidth: opts?.fullWidth,
42029
43424
  className: opts?.className
@@ -42032,6 +43427,28 @@ const wrapVariant$1 = (layout, opts) => styledSection({
42032
43427
  spacing: "medium",
42033
43428
  background: "background"
42034
43429
  });
43430
+ 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({
43431
+ as: "figcaption",
43432
+ ...lookSlot("caption")
43433
+ }, bind(captionFrom), when(captionFrom))])], ...mods);
43434
+ const tilesLayout = styledSection({
43435
+ children: el("div", {
43436
+ className: "rb-container",
43437
+ ...lookSlot("layout")
43438
+ }, [...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) => ({
43439
+ ...node,
43440
+ $when: {
43441
+ when: {
43442
+ from: "content.images",
43443
+ transforms: [{ id: "array.length" }]
43444
+ },
43445
+ equals: 0
43446
+ }
43447
+ }))])]),
43448
+ baseClass: "",
43449
+ spacing: "medium",
43450
+ background: "background"
43451
+ });
42035
43452
  const imageGalleryBlockDefinition = { manifest: createBlockManifest({
42036
43453
  id: "block.image-gallery",
42037
43454
  title: "Image Gallery",
@@ -42044,510 +43461,10 @@ const imageGalleryBlockDefinition = { manifest: createBlockManifest({
42044
43461
  "marqueeSpeed",
42045
43462
  "marqueePauseOnHover"
42046
43463
  ] },
42047
- additionalFields: parseFieldDefinitions([
42048
- {
42049
- id: "images",
42050
- type: "repeater",
42051
- label: "Images",
42052
- itemLabel: "Image",
42053
- minItems: 0,
42054
- maxItems: 24,
42055
- ui: {
42056
- repeaterPreset: "thumbnailGrid",
42057
- thumbnailField: "image",
42058
- thumbnailAltField: "caption",
42059
- thumbnailLabelField: "caption",
42060
- thumbnailCardDensity: "compact"
42061
- },
42062
- schema: { fields: [{
42063
- id: "image",
42064
- type: "media",
42065
- label: "Image",
42066
- required: true,
42067
- mediaKinds: ["image"]
42068
- }, {
42069
- id: "caption",
42070
- type: "text",
42071
- label: "Caption",
42072
- description: "Optional caption displayed below the image and used as the editor card label",
42073
- maxLength: 200
42074
- }] }
42075
- },
42076
- {
42077
- id: "fullBleed",
42078
- type: "boolean",
42079
- label: "Full bleed",
42080
- description: "Extend the gallery edge-to-edge by removing section side padding and container max-width.",
42081
- defaultValue: false,
42082
- ui: {
42083
- intent: "display",
42084
- visibleWhen: {
42085
- field: "variant",
42086
- notIn: ["marquee"]
42087
- }
42088
- }
42089
- },
42090
- {
42091
- id: "aspectRatio",
42092
- type: "select",
42093
- label: "Aspect ratio",
42094
- description: "Crop images to a consistent aspect ratio.",
42095
- defaultValue: "1/1",
42096
- options: [
42097
- {
42098
- value: "auto",
42099
- label: "Original"
42100
- },
42101
- {
42102
- value: "1/1",
42103
- label: "1:1 (Square)"
42104
- },
42105
- {
42106
- value: "4/3",
42107
- label: "4:3 (Standard)"
42108
- },
42109
- {
42110
- value: "16/9",
42111
- label: "16:9 (Widescreen)"
42112
- },
42113
- {
42114
- value: "3/2",
42115
- label: "3:2 (Classic)"
42116
- },
42117
- {
42118
- value: "3/4",
42119
- label: "3:4 (Portrait)"
42120
- }
42121
- ],
42122
- ui: {
42123
- intent: "display",
42124
- visibleWhen: {
42125
- field: "variant",
42126
- notIn: ["masonry", "marquee"]
42127
- }
42128
- }
42129
- },
42130
- {
42131
- id: "slidesToShow",
42132
- type: "select",
42133
- label: "Images per view (mobile)",
42134
- description: "Number of images visible at once on small screens.",
42135
- defaultValue: "1",
42136
- options: [
42137
- {
42138
- value: "1",
42139
- label: "One at a time"
42140
- },
42141
- {
42142
- value: "2",
42143
- label: "Two at a time"
42144
- },
42145
- {
42146
- value: "3",
42147
- label: "Three at a time"
42148
- }
42149
- ],
42150
- ui: {
42151
- intent: "display",
42152
- visibleWhen: {
42153
- field: "variant",
42154
- equals: "carousel"
42155
- }
42156
- }
42157
- },
42158
- {
42159
- id: "slidesToShowTablet",
42160
- type: "select",
42161
- label: "Images per view (tablet)",
42162
- description: "Number of images visible on medium screens.",
42163
- options: [
42164
- {
42165
- value: "",
42166
- label: "Same as mobile"
42167
- },
42168
- {
42169
- value: "1",
42170
- label: "One at a time"
42171
- },
42172
- {
42173
- value: "2",
42174
- label: "Two at a time"
42175
- },
42176
- {
42177
- value: "3",
42178
- label: "Three at a time"
42179
- }
42180
- ],
42181
- ui: {
42182
- intent: "display",
42183
- visibleWhen: {
42184
- field: "variant",
42185
- equals: "carousel"
42186
- }
42187
- }
42188
- },
42189
- {
42190
- id: "slidesToShowDesktop",
42191
- type: "select",
42192
- label: "Images per view (desktop)",
42193
- description: "Number of images visible on large screens.",
42194
- options: [
42195
- {
42196
- value: "",
42197
- label: "Same as tablet"
42198
- },
42199
- {
42200
- value: "1",
42201
- label: "One at a time"
42202
- },
42203
- {
42204
- value: "2",
42205
- label: "Two at a time"
42206
- },
42207
- {
42208
- value: "3",
42209
- label: "Three at a time"
42210
- }
42211
- ],
42212
- ui: {
42213
- intent: "display",
42214
- visibleWhen: {
42215
- field: "variant",
42216
- equals: "carousel"
42217
- }
42218
- }
42219
- },
42220
- {
42221
- id: "transition",
42222
- type: "select",
42223
- label: "Transition",
42224
- description: "Animation style between slides.",
42225
- defaultValue: "slide",
42226
- options: [{
42227
- value: "slide",
42228
- label: "Slide"
42229
- }, {
42230
- value: "fade",
42231
- label: "Fade"
42232
- }],
42233
- ui: {
42234
- intent: "display",
42235
- visibleWhen: {
42236
- field: "variant",
42237
- equals: "carousel"
42238
- }
42239
- }
42240
- },
42241
- {
42242
- id: "showControls",
42243
- type: "boolean",
42244
- label: "Show arrows",
42245
- defaultValue: true,
42246
- ui: {
42247
- intent: "behavior",
42248
- visibleWhen: {
42249
- field: "variant",
42250
- equals: "carousel"
42251
- }
42252
- }
42253
- },
42254
- {
42255
- id: "showDots",
42256
- type: "boolean",
42257
- label: "Show dots",
42258
- defaultValue: false,
42259
- ui: {
42260
- intent: "behavior",
42261
- visibleWhen: {
42262
- field: "variant",
42263
- equals: "carousel"
42264
- }
42265
- }
42266
- },
42267
- {
42268
- id: "autoplay",
42269
- type: "boolean",
42270
- label: "Autoplay",
42271
- defaultValue: false,
42272
- ui: {
42273
- intent: "behavior",
42274
- visibleWhen: {
42275
- field: "variant",
42276
- equals: "carousel"
42277
- }
42278
- }
42279
- },
42280
- {
42281
- id: "autoplayDelay",
42282
- type: "select",
42283
- label: "Autoplay delay",
42284
- defaultValue: "5000",
42285
- options: [
42286
- {
42287
- value: "3000",
42288
- label: "3 seconds"
42289
- },
42290
- {
42291
- value: "5000",
42292
- label: "5 seconds"
42293
- },
42294
- {
42295
- value: "7000",
42296
- label: "7 seconds"
42297
- },
42298
- {
42299
- value: "10000",
42300
- label: "10 seconds"
42301
- }
42302
- ],
42303
- ui: {
42304
- intent: "behavior",
42305
- visibleWhen: {
42306
- field: "variant",
42307
- equals: "carousel"
42308
- }
42309
- }
42310
- },
42311
- {
42312
- id: "arrowVisibility",
42313
- type: "select",
42314
- label: "Arrow visibility",
42315
- defaultValue: "always",
42316
- options: [{
42317
- value: "always",
42318
- label: "Always visible"
42319
- }, {
42320
- value: "hover",
42321
- label: "Show on hover"
42322
- }],
42323
- ui: {
42324
- intent: "behavior",
42325
- visibleWhen: {
42326
- field: "variant",
42327
- equals: "carousel"
42328
- }
42329
- }
42330
- },
42331
- {
42332
- id: "loop",
42333
- type: "boolean",
42334
- label: "Loop slides",
42335
- defaultValue: true,
42336
- ui: {
42337
- intent: "behavior",
42338
- visibleWhen: {
42339
- field: "variant",
42340
- equals: "carousel"
42341
- }
42342
- }
42343
- },
42344
- {
42345
- id: "marqueeDirection",
42346
- type: "select",
42347
- label: "Scroll direction",
42348
- options: [{
42349
- value: "left",
42350
- label: "Left"
42351
- }, {
42352
- value: "right",
42353
- label: "Right"
42354
- }],
42355
- defaultValue: "left",
42356
- ui: {
42357
- intent: "display",
42358
- visibleWhen: {
42359
- field: "variant",
42360
- equals: "marquee"
42361
- }
42362
- }
42363
- },
42364
- {
42365
- id: "marqueeSpeed",
42366
- type: "select",
42367
- label: "Scroll speed",
42368
- options: [
42369
- {
42370
- value: "slow",
42371
- label: "Slow (60s)"
42372
- },
42373
- {
42374
- value: "medium",
42375
- label: "Medium (40s)"
42376
- },
42377
- {
42378
- value: "fast",
42379
- label: "Fast (20s)"
42380
- }
42381
- ],
42382
- defaultValue: "medium",
42383
- ui: {
42384
- intent: "display",
42385
- visibleWhen: {
42386
- field: "variant",
42387
- equals: "marquee"
42388
- }
42389
- }
42390
- },
42391
- {
42392
- id: "marqueePauseOnHover",
42393
- type: "boolean",
42394
- label: "Pause on hover",
42395
- defaultValue: true,
42396
- ui: {
42397
- intent: "behavior",
42398
- visibleWhen: {
42399
- field: "variant",
42400
- equals: "marquee"
42401
- }
42402
- }
42403
- },
42404
- {
42405
- id: "marqueeImageSize",
42406
- type: "select",
42407
- label: "Image size",
42408
- options: [
42409
- {
42410
- value: "sm",
42411
- label: "Small (200px)"
42412
- },
42413
- {
42414
- value: "md",
42415
- label: "Medium (256px)"
42416
- },
42417
- {
42418
- value: "lg",
42419
- label: "Large (320px)"
42420
- },
42421
- {
42422
- value: "xl",
42423
- label: "Extra large (400px)"
42424
- }
42425
- ],
42426
- defaultValue: "md",
42427
- ui: {
42428
- intent: "display",
42429
- visibleWhen: {
42430
- field: "variant",
42431
- equals: "marquee"
42432
- }
42433
- }
42434
- },
42435
- {
42436
- id: "imageFilter",
42437
- type: "select",
42438
- label: "Image filter",
42439
- options: [
42440
- {
42441
- value: "none",
42442
- label: "None"
42443
- },
42444
- {
42445
- value: "grayscale",
42446
- label: "Grayscale"
42447
- },
42448
- {
42449
- value: "grayscale-hover-reveal",
42450
- label: "Grayscale (color on hover)"
42451
- },
42452
- {
42453
- value: "sepia",
42454
- label: "Sepia"
42455
- }
42456
- ],
42457
- defaultValue: "grayscale-hover-reveal",
42458
- ui: { intent: "style" }
42459
- },
42460
- {
42461
- id: "imageBorder",
42462
- type: "group",
42463
- label: "Image border",
42464
- schema: { fields: [
42465
- {
42466
- id: "enabled",
42467
- type: "boolean",
42468
- label: "Show border",
42469
- defaultValue: true
42470
- },
42471
- {
42472
- id: "colorToken",
42473
- type: "text",
42474
- label: "Border color",
42475
- defaultValue: "accent",
42476
- ui: { widget: "backgroundColor" }
42477
- },
42478
- {
42479
- id: "opacity",
42480
- type: "number",
42481
- label: "Border opacity",
42482
- defaultValue: 30,
42483
- ui: {
42484
- min: 0,
42485
- max: 100
42486
- }
42487
- },
42488
- {
42489
- id: "width",
42490
- type: "select",
42491
- label: "Border width",
42492
- options: [
42493
- {
42494
- value: "1",
42495
- label: "Thin (1px)"
42496
- },
42497
- {
42498
- value: "2",
42499
- label: "Medium (2px)"
42500
- },
42501
- {
42502
- value: "3",
42503
- label: "Thick (3px)"
42504
- }
42505
- ],
42506
- defaultValue: "2"
42507
- }
42508
- ] },
42509
- ui: { intent: "style" }
42510
- },
42511
- {
42512
- id: "imageCorners",
42513
- type: "select",
42514
- label: "Image corners",
42515
- options: [
42516
- {
42517
- value: "none",
42518
- label: "Square"
42519
- },
42520
- {
42521
- value: "sm",
42522
- label: "Slightly rounded"
42523
- },
42524
- {
42525
- value: "md",
42526
- label: "Rounded"
42527
- },
42528
- {
42529
- value: "lg",
42530
- label: "More rounded"
42531
- },
42532
- {
42533
- value: "xl",
42534
- label: "Very rounded"
42535
- },
42536
- {
42537
- value: "2xl",
42538
- label: "Extra rounded"
42539
- },
42540
- {
42541
- value: "3xl",
42542
- label: "Maximum rounded"
42543
- }
42544
- ],
42545
- defaultValue: "3xl",
42546
- ui: { intent: "style" }
42547
- }
42548
- ]),
43464
+ additionalFields: imageGalleryFields,
42549
43465
  layout: wrapVariant$1(gridLayout),
42550
43466
  variants: {
43467
+ tiles: tilesLayout,
42551
43468
  grid: wrapVariant$1(gridLayout),
42552
43469
  carousel: wrapVariant$1(carouselLayout),
42553
43470
  masonry: wrapVariant$1(masonryLayout),
@@ -42556,7 +43473,10 @@ const imageGalleryBlockDefinition = { manifest: createBlockManifest({
42556
43473
  className: "rb-image-gallery-marquee-container"
42557
43474
  })
42558
43475
  },
42559
- variantMeaning: { kind: "arrangement" },
43476
+ variantMeaning: {
43477
+ kind: "arrangement",
43478
+ lookOnlyKeys: ["tiles"]
43479
+ },
42560
43480
  defaultVariant: "grid",
42561
43481
  variantOptions: {
42562
43482
  grid: {
@@ -42949,6 +43869,14 @@ const audioPlayerBlockDefinition = { manifest: createBlockManifest({
42949
43869
  }
42950
43870
  }) };
42951
43871
  //#endregion
43872
+ //#region ../blocks/src/lib/media.ts
43873
+ const PUBLIC_DOWNLOAD_MEDIA_TYPES = [
43874
+ "document",
43875
+ "spreadsheet",
43876
+ "archive",
43877
+ "audio"
43878
+ ];
43879
+ //#endregion
42952
43880
  //#region ../blocks/src/system/blocks/file-download.ts
42953
43881
  const bound = (from) => ({ $bind: { from } });
42954
43882
  const fileDownloadLayout = styledSection({
@@ -44768,76 +45696,74 @@ const giftingBlockDefinition = {
44768
45696
  /**
44769
45697
  * Get form fields based on preset configuration.
44770
45698
  */
44771
- function getGlobalFormFields(form) {
44772
- const includePhone = form.includeOptionalPhone;
44773
- switch (form.fields.preset) {
44774
- case "emailOnly": return withOptionalPhone([{
44775
- id: "email",
44776
- type: "email",
44777
- label: "Email",
44778
- required: true,
44779
- placeholder: "your@email.com"
44780
- }], includePhone);
44781
- case "emailName": return withOptionalPhone([{
44782
- id: "email",
44783
- type: "email",
44784
- label: "Email",
44785
- required: true,
44786
- placeholder: "your@email.com"
44787
- }, {
45699
+ function getGlobalFormFields(form, presentation = {}) {
45700
+ const fields = withOptionalPhone(newsletterPresetFields(form.fields), form.includeOptionalPhone);
45701
+ return presentation.lookSlots ? fields.map((field) => ({
45702
+ ...field,
45703
+ label: lookFieldLabel(field)
45704
+ })) : fields;
45705
+ }
45706
+ function lookFieldLabel(field) {
45707
+ switch (field.id) {
45708
+ case "firstName": return "First name";
45709
+ case "lastName": return "Last name";
45710
+ default: return field.label;
45711
+ }
45712
+ }
45713
+ const emailField = {
45714
+ id: "email",
45715
+ type: "email",
45716
+ label: "Email",
45717
+ required: true,
45718
+ placeholder: "your@email.com"
45719
+ };
45720
+ const firstNameField = (required) => ({
45721
+ id: "firstName",
45722
+ type: "text",
45723
+ label: "First Name",
45724
+ required,
45725
+ placeholder: "First name"
45726
+ });
45727
+ function newsletterPresetFields(fields) {
45728
+ switch (fields.preset) {
45729
+ case "emailOnly": return [emailField];
45730
+ case "emailName": return [emailField, {
44788
45731
  id: "name",
44789
45732
  type: "text",
44790
45733
  label: "Name",
44791
- required: form.fields.name === "required",
45734
+ required: fields.name === "required",
44792
45735
  placeholder: "Your name"
44793
- }], includePhone);
44794
- case "emailFirstLast": return withOptionalPhone([
44795
- {
44796
- id: "email",
44797
- type: "email",
44798
- label: "Email",
44799
- required: true,
44800
- placeholder: "your@email.com"
44801
- },
44802
- {
44803
- id: "firstName",
44804
- type: "text",
44805
- label: "First Name",
44806
- required: form.fields.firstName === "required",
44807
- placeholder: "First name"
44808
- },
45736
+ }];
45737
+ case "emailFirstName": return [emailField, firstNameField(fields.firstName === "required")];
45738
+ case "emailFirstLast": return [
45739
+ emailField,
45740
+ firstNameField(fields.firstName === "required"),
44809
45741
  {
44810
45742
  id: "lastName",
44811
45743
  type: "text",
44812
45744
  label: "Last Name",
44813
- required: form.fields.lastName === "required",
45745
+ required: fields.lastName === "required",
44814
45746
  placeholder: "Last name"
44815
45747
  }
44816
- ], includePhone);
44817
- case "emailNameCompany": return withOptionalPhone([
44818
- {
44819
- id: "email",
44820
- type: "email",
44821
- label: "Email",
44822
- required: true,
44823
- placeholder: "your@email.com"
44824
- },
45748
+ ];
45749
+ case "emailNameCompany": return [
45750
+ emailField,
44825
45751
  {
44826
45752
  id: "name",
44827
45753
  type: "text",
44828
45754
  label: "Name",
44829
- required: form.fields.name === "required",
45755
+ required: fields.name === "required",
44830
45756
  placeholder: "Your name"
44831
45757
  },
44832
45758
  {
44833
45759
  id: "company",
44834
45760
  type: "text",
44835
45761
  label: "Company",
44836
- required: form.fields.company === "required",
45762
+ required: fields.company === "required",
44837
45763
  placeholder: "Company name"
44838
45764
  }
44839
- ], includePhone);
44840
- default: throw new Error("Unknown newsletter preset");
45765
+ ];
45766
+ default: return assertNever$2(fields);
44841
45767
  }
44842
45768
  }
44843
45769
  function withOptionalPhone(fields, includePhone) {
@@ -44899,6 +45825,7 @@ const mailingListSignupBlockSourceRefSchema = z.object({
44899
45825
  });
44900
45826
  const signedMailingListSourceTokenSchema = z.string().trim().min(1).transform(parseRequiredMailingListSignedSourceToken);
44901
45827
  const newsletterSourceCommonSchema = z.object({
45828
+ lookSlots: lookListPresentationSchemaShape.lookSlots,
44902
45829
  siteId: z.string().optional(),
44903
45830
  apiBaseUrl: z.string().optional(),
44904
45831
  mailingList: mailingListContextSchema.optional(),
@@ -44931,6 +45858,7 @@ const newsletterSourceSchema = z.discriminatedUnion("source", [
44931
45858
  newsletterSourceCommonSchema.extend({ source: z.literal("preview") })
44932
45859
  ]);
44933
45860
  const newsletterDisplaySchema = z.object({
45861
+ lookSlots: lookListPresentationSchemaShape.lookSlots,
44934
45862
  kind: z.literal("newsletter-form"),
44935
45863
  availability: z.enum(["ready", "unavailable"]),
44936
45864
  className: z.string().nullable(),
@@ -44997,13 +45925,14 @@ function buildNewsletterDisplay(source) {
44997
45925
  const choices = resolveRuntimeChoices(assessment);
44998
45926
  return {
44999
45927
  kind: "newsletter-form",
45928
+ ...source.lookSlots ? { lookSlots: source.lookSlots } : {},
45000
45929
  availability: assessment.tag === "available" ? "ready" : "unavailable",
45001
45930
  className: source.className ?? null,
45002
45931
  buttonLabel: form.buttonLabel,
45003
45932
  successMessage: form.successMessage,
45004
45933
  buttonVariant: source.buttonVariant ?? "primary",
45005
45934
  privacyNote: form.privacyNote,
45006
- fields: getGlobalFormFields(form),
45935
+ fields: getGlobalFormFields(form, source),
45007
45936
  choices
45008
45937
  };
45009
45938
  }
@@ -45075,32 +46004,50 @@ function parseRequiredMailingListSignedSourceToken(value) {
45075
46004
  //#region ../blocks/src/system/blocks/newsletter-signup.ts
45076
46005
  const stackedComposition = composeFragments([{ fragment: newsletterCopyFragment }, { fragment: newsletterFormFragment }]);
45077
46006
  const stackedLayout = styledSection({
45078
- children: sectionContainer(stackedComposition.layout, {
46007
+ children: props(lookSlot("layout"))(sectionContainer(stackedComposition.layout, {
45079
46008
  gap: "md",
45080
46009
  className: "rb-text-center newsletter-stacked"
45081
- }),
46010
+ })),
45082
46011
  baseClass: "",
45083
46012
  spacing: "medium",
45084
46013
  background: "surface"
45085
46014
  });
45086
46015
  const inlineLayout = styledSection({
45087
- children: sectionContainer(stackedComposition.layout, {
46016
+ children: props(lookSlot("layout"))(sectionContainer(stackedComposition.layout, {
45088
46017
  gap: "md",
45089
46018
  className: "newsletter-inline"
45090
- }),
46019
+ })),
45091
46020
  baseClass: "",
45092
46021
  spacing: "medium",
45093
46022
  background: "surface"
45094
46023
  });
45095
46024
  const editorialSplitLayout = styledSection({
45096
- children: sectionContainer([el("div", { className: "newsletter-editorial-split-copy" }, newsletterCopyFragment.layout), el("div", { className: "newsletter-editorial-split-form" }, newsletterFormFragment.layout)], {
46025
+ children: props(lookSlot("layout"))(sectionContainer([el("div", {
46026
+ className: "newsletter-editorial-split-copy",
46027
+ ...lookSlot("head")
46028
+ }, newsletterCopyFragment.layout), el("div", {
46029
+ className: "newsletter-editorial-split-form",
46030
+ ...lookSlot("panel")
46031
+ }, newsletterFormFragment.layout)], {
45097
46032
  gap: "lg",
45098
46033
  className: "newsletter-editorial-split"
45099
- }),
46034
+ })),
45100
46035
  baseClass: "",
45101
46036
  spacing: "comfortable",
45102
46037
  background: "surface"
45103
46038
  });
46039
+ const archLayout = styledSection({
46040
+ children: el("div", {
46041
+ className: "rb-container",
46042
+ ...lookSlot("layout")
46043
+ }, [el("div", lookSlot("frame"), [el("div", {
46044
+ className: "rb-grid",
46045
+ ...lookSlot("head")
46046
+ }, newsletterCopyFragment.layout), ...newsletterFormFragment.layout])]),
46047
+ baseClass: "",
46048
+ spacing: "medium",
46049
+ background: "surface"
46050
+ });
45104
46051
  const newsletterSignupManifest = createBlockManifest({
45105
46052
  id: "block.newsletter-signup",
45106
46053
  title: "Newsletter Signup",
@@ -45115,13 +46062,26 @@ const newsletterSignupManifest = createBlockManifest({
45115
46062
  fragment: newsletterFormFragment,
45116
46063
  fieldPriority: 1
45117
46064
  }],
46065
+ additionalFields: [{
46066
+ id: "archFrame",
46067
+ type: "boolean",
46068
+ label: "Arch frame",
46069
+ ui: {
46070
+ intent: "display",
46071
+ hidden: true
46072
+ }
46073
+ }],
45118
46074
  layout: stackedLayout,
45119
46075
  variants: {
46076
+ arch: archLayout,
45120
46077
  stacked: stackedLayout,
45121
46078
  inline: inlineLayout,
45122
46079
  "editorial-split": editorialSplitLayout
45123
46080
  },
45124
- variantMeaning: { kind: "arrangement" },
46081
+ variantMeaning: {
46082
+ kind: "arrangement",
46083
+ lookOnlyKeys: ["arch"]
46084
+ },
45125
46085
  defaultVariant: "stacked",
45126
46086
  variantOptions: {
45127
46087
  stacked: {
@@ -45194,7 +46154,7 @@ const memberPhotoClassName = (baseClass) => cardRoleChildClass({
45194
46154
  baseClass,
45195
46155
  stylesFrom: "content._cardStyles"
45196
46156
  });
45197
- const teamMemberPhotoSchema = mediaSchema.refine((media) => media.type === "image", { message: "Team member photos must be image media" }).nullable();
46157
+ const teamMemberPhotoSchema = runtimeMediaSchema.refine((media) => media.type === "image", { message: "Team member photos must be image media" }).nullable();
45198
46158
  const teamMemberDataSchema = z.object({
45199
46159
  _type: z.literal("teamMember"),
45200
46160
  id: z.string(),
@@ -46208,7 +47168,7 @@ const systemBlockDefinitions = [
46208
47168
  })
46209
47169
  ]
46210
47170
  })),
46211
- withDesignCapability("block.body-text", bodyTextBlockDefinition, sectionOnly(), defineBlockDesignMetadata({
47171
+ withDesignCapability("block.body-text", bodyTextBlockDefinition, withLookCapability(sectionOnly()), defineBlockDesignMetadata({
46212
47172
  flow: bodyFlow,
46213
47173
  layoutProfiles: [
46214
47174
  layoutProfile({
@@ -46583,7 +47543,7 @@ const systemBlockDefinitions = [
46583
47543
  weight: "quiet"
46584
47544
  })]
46585
47545
  })),
46586
- withDesignCapability("block.image-gallery", imageGalleryBlockDefinition, sectionOnly(), defineBlockDesignMetadata({
47546
+ withDesignCapability("block.image-gallery", imageGalleryBlockDefinition, withLookCapability(sectionOnly()), defineBlockDesignMetadata({
46587
47547
  flow: mediaFlow,
46588
47548
  layoutProfiles: [
46589
47549
  layoutProfile({
@@ -46672,7 +47632,7 @@ const systemBlockDefinitions = [
46672
47632
  weight: "standard"
46673
47633
  })]
46674
47634
  })),
46675
- withDesignCapability("block.newsletter-signup", newsletterSignupBlockDefinition, sectionOnly(), defineBlockDesignMetadata({
47635
+ withDesignCapability("block.newsletter-signup", newsletterSignupBlockDefinition, withLookCapability(sectionOnly()), defineBlockDesignMetadata({
46676
47636
  flow: conversionFlow,
46677
47637
  layoutProfiles: [
46678
47638
  layoutProfile({
@@ -46736,11 +47696,14 @@ const offeringsPreviewDatesReadEnabled = {
46736
47696
  //#endregion
46737
47697
  //#region ../blocks/src/system/helpers/backgroundMedia.ts
46738
47698
  function resolveBackgroundMedia(input) {
46739
- const parsedMedia = mediaSchema.safeParse(input.image);
47699
+ const parsedMedia = runtimeMediaSchema.safeParse(input.image);
46740
47700
  if (!parsedMedia.success) return null;
46741
47701
  switch (parsedMedia.data.type) {
46742
47702
  case "image":
46743
- case "video": return parsedMedia.data;
47703
+ case "video": return {
47704
+ ...parsedMedia.data,
47705
+ type: parsedMedia.data.type
47706
+ };
46744
47707
  case "audio":
46745
47708
  case "document":
46746
47709
  case "spreadsheet":
@@ -46752,6 +47715,75 @@ function backgroundVideoMobileClassNames(input) {
46752
47715
  return input.showVideoOnMobile === true ? "" : "rb-hidden rb-md-block";
46753
47716
  }
46754
47717
  //#endregion
47718
+ //#region ../blocks/src/system/runtime/nodes/mediaContext.ts
47719
+ /**
47720
+ * Server-side: AsyncLocalStorage for request isolation.
47721
+ * Prevents race conditions when multiple requests are processed concurrently.
47722
+ *
47723
+ * Lazy initialization to avoid issues in environments that don't support async_hooks.
47724
+ */
47725
+ const serverStorageState = {
47726
+ storage: null,
47727
+ checked: false
47728
+ };
47729
+ function getServerStorage() {
47730
+ if (typeof window !== "undefined") return null;
47731
+ if (serverStorageState.checked) return serverStorageState.storage;
47732
+ serverStorageState.checked = true;
47733
+ try {
47734
+ const globalWithNonWebpackRequire = globalThis;
47735
+ const AsyncLocalStorage = (typeof globalWithNonWebpackRequire.__non_webpack_require__ === "function" ? globalWithNonWebpackRequire.__non_webpack_require__ : new Function("id", "return require(id)"))("async_hooks").AsyncLocalStorage;
47736
+ if (AsyncLocalStorage) {
47737
+ serverStorageState.storage = new AsyncLocalStorage();
47738
+ return serverStorageState.storage;
47739
+ }
47740
+ return null;
47741
+ } catch {
47742
+ if (process.env.NODE_ENV !== "production") console.warn("[blocks] AsyncLocalStorage not available - using module-level state");
47743
+ return null;
47744
+ }
47745
+ }
47746
+ /**
47747
+ * Client-side context storage.
47748
+ * Safe because browsers are single-threaded per tab.
47749
+ *
47750
+ * IMPORTANT: This must be shared across bundles.
47751
+ * SDK preview mode can load multiple independently-bundled entrypoints
47752
+ * (e.g. `@riverbankcms/sdk/rendering` + `@riverbankcms/sdk/preview-next/client`),
47753
+ * which can otherwise each get their own module-scoped singleton.
47754
+ */
47755
+ const RB_MEDIA_CONTEXT_KEY = Symbol.for("riverbankcms.blocks.mediaContext");
47756
+ function getClientContextStore() {
47757
+ const g = globalThis;
47758
+ const existing = g[RB_MEDIA_CONTEXT_KEY];
47759
+ if (existing && typeof existing === "object") return existing;
47760
+ const next = {};
47761
+ g[RB_MEDIA_CONTEXT_KEY] = next;
47762
+ return next;
47763
+ }
47764
+ /**
47765
+ * Get the current media context.
47766
+ * Server-side: Uses AsyncLocalStorage for request isolation.
47767
+ * Client-side: Uses module-level state (safe in single-threaded browser).
47768
+ */
47769
+ function getMediaContext() {
47770
+ const storage = getServerStorage();
47771
+ if (storage) return storage.getStore() ?? {};
47772
+ return getClientContextStore();
47773
+ }
47774
+ function getCurrentResolveImageUrlContext() {
47775
+ const context = getMediaContext();
47776
+ if (!context.supabaseUrl && !context.siteId && !context.mediaAssetIndex) return;
47777
+ return {
47778
+ supabaseUrl: context.supabaseUrl,
47779
+ siteId: context.siteId,
47780
+ mediaAssetIndex: context.mediaAssetIndex
47781
+ };
47782
+ }
47783
+ function getMediaAssetIndex(context) {
47784
+ return context?.mediaAssetIndex ?? getMediaContext().mediaAssetIndex;
47785
+ }
47786
+ //#endregion
46755
47787
  //#region ../blocks/src/system/runtime/nodes/media.tsx
46756
47788
  function getValidSourceDimension(value) {
46757
47789
  return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : void 0;
@@ -46787,41 +47819,72 @@ function applyRectTransform(existingStyle, patch) {
46787
47819
  if (patch.transform) next.transform = appendTransform(existingStyle?.transform, patch.transform);
46788
47820
  return next;
46789
47821
  }
46790
- function computeMediaTransformStyle(value, style, targetAspectRatio, options) {
47822
+ /** Resolve portable content without exposing runtime metadata as saved values. */
47823
+ function resolveMediaWithContext(reference, context) {
47824
+ return resolveManagedMediaReference(reference, getMediaAssetIndex(context ?? void 0));
47825
+ }
47826
+ function sourceFromAsset(value, asset) {
47827
+ return {
47828
+ type: value.type,
47829
+ alt: value.alt,
47830
+ filename: value.filename,
47831
+ purpose: value.purpose,
47832
+ placeholder: value.placeholder,
47833
+ transform: value.transform,
47834
+ poster: value.poster,
47835
+ identifier: asset.identifier,
47836
+ assetId: asset.id,
47837
+ storageBucket: asset.storageBucket,
47838
+ storagePath: asset.storagePath,
47839
+ mimeType: asset.mimeType,
47840
+ width: asset.width,
47841
+ height: asset.height
47842
+ };
47843
+ }
47844
+ function resolveRuntimeMedia(value, context) {
47845
+ if ("asset" in value && value.asset) return sourceFromAsset(value, value.asset);
47846
+ if ("src" in value && value.src) return value;
47847
+ if (!value.identifier) return void 0;
47848
+ const resolved = resolveMediaWithContext(value, context);
47849
+ return resolved.kind === "resolved" ? sourceFromAsset(resolved.reference, resolved.asset) : void 0;
47850
+ }
47851
+ function usesProxyFraming(source, transform) {
47852
+ if (!source?.assetId || !isExplicitCropProxyEnabled()) return false;
47853
+ return Boolean(transform.rotation) || isExplicitRectCrop(transform.rect, getValidSourceDimension(source.width), getValidSourceDimension(source.height));
47854
+ }
47855
+ function rectFramingPatch(source, rect, proxy, style) {
47856
+ if (!source || !rect || proxy) return {};
47857
+ const patch = buildCssRectStylePatch(source, rect);
47858
+ return patch ? applyRectTransform(style, patch) : {};
47859
+ }
47860
+ function hotspotFramingPatch(transform, proxy, rectPatch, style) {
47861
+ if (!transform.hotspot || rectPatch.objectPosition !== void 0) return {};
47862
+ const fit = style?.objectFit;
47863
+ if (fit && fit !== "cover" && fit !== "contain") return {};
47864
+ const point = proxy && transform.rotation ? rotateNormalizedPoint(transform.hotspot, transform.rotation) : transform.hotspot;
47865
+ return { objectPosition: `${point.x * 100}% ${point.y * 100}%` };
47866
+ }
47867
+ function rotationFramingPatch(rotation, proxy, rectPatch, style) {
47868
+ if (!rotation || proxy) return {};
47869
+ return {
47870
+ transform: appendTransform(rectPatch.transform ?? style?.transform, `rotate(${rotation}deg)`),
47871
+ transformOrigin: rectPatch.transformOrigin ?? "center"
47872
+ };
47873
+ }
47874
+ /** CSS framing is a pure projection of the resolved source and per-use transform. */
47875
+ function deriveMediaFramingStyle(source, transform, proxy, style) {
47876
+ if (!transform.rect && !transform.hotspot && !transform.rotation) return style;
47877
+ const rectPatch = rectFramingPatch(source, transform.rect, proxy, style);
47878
+ return mergeStyles(style, {
47879
+ ...rectPatch,
47880
+ ...hotspotFramingPatch(transform, proxy, rectPatch, style),
47881
+ ...rotationFramingPatch(transform.rotation, proxy, rectPatch, style)
47882
+ });
47883
+ }
47884
+ function computeMediaTransformStyle(value, style, targetAspectRatio, options, context) {
47885
+ const source = resolveRuntimeMedia(value, context ?? getCurrentResolveImageUrlContext());
46791
47886
  const transform = options?.resolvedTransform ?? resolveMediaTransformForAspect(value.transform, targetAspectRatio);
46792
- const rect = transform.rect;
46793
- const hotspot = transform.hotspot;
46794
- const rotation = transform.rotation;
46795
- if (!rect && !hotspot && !rotation) return style;
46796
- const stylePatch = {};
46797
- const heuristicSuppressCss = Boolean(isExplicitCropProxyEnabled() && value.assetId && (typeof rotation === "number" && rotation !== 0 || isExplicitRectCrop(rect, getValidSourceDimension(value.width), getValidSourceDimension(value.height))));
46798
- const shouldSuppressCss = options?.isProxy ?? heuristicSuppressCss;
46799
- if (rect && !shouldSuppressCss) {
46800
- const rectPatch = buildCssRectStylePatch(value, rect);
46801
- if (rectPatch) {
46802
- const mergedRect = applyRectTransform(style, rectPatch);
46803
- Object.assign(stylePatch, mergedRect);
46804
- }
46805
- }
46806
- if (hotspot) {
46807
- const effectiveObjectFit = stylePatch.objectFit ?? style?.objectFit;
46808
- if ((!effectiveObjectFit || effectiveObjectFit === "cover" || effectiveObjectFit === "contain") && stylePatch.objectPosition === void 0) {
46809
- const resolved = shouldSuppressCss && rotation ? rotateNormalizedPoint({
46810
- x: hotspot.x,
46811
- y: hotspot.y
46812
- }, rotation) : {
46813
- x: hotspot.x,
46814
- y: hotspot.y
46815
- };
46816
- stylePatch.objectPosition = `${resolved.x * 100}% ${resolved.y * 100}%`;
46817
- }
46818
- }
46819
- if (rotation && !shouldSuppressCss) {
46820
- const existingTransform = stylePatch.transform ?? style?.transform;
46821
- stylePatch.transform = existingTransform ? `${existingTransform} rotate(${rotation}deg)` : `rotate(${rotation}deg)`;
46822
- if (!stylePatch.transformOrigin) stylePatch.transformOrigin = "center";
46823
- }
46824
- return mergeStyles(style, stylePatch);
47887
+ return deriveMediaFramingStyle(source, transform, options?.isProxy ?? usesProxyFraming(source, transform), style);
46825
47888
  }
46826
47889
  //#endregion
46827
47890
  //#region ../blocks/src/system/transforms/registry/background.ts
@@ -46970,11 +48033,11 @@ const backgroundTransforms = [
46970
48033
  }
46971
48034
  ];
46972
48035
  function parseMediaBackground(value) {
46973
- const background = parseBackgroundContent(value);
48036
+ const background = parseRuntimeBackgroundContent(value);
46974
48037
  return background?.type === "image" || background?.type === "video" ? background : null;
46975
48038
  }
46976
48039
  function resolveBackgroundLayerStyle(value, fallbackToken, context) {
46977
- const background = parseBackgroundContent(value);
48040
+ const background = parseRuntimeBackgroundContent(value);
46978
48041
  const style = {};
46979
48042
  const gradient = background?.type === "gradient" ? isString(background.gradient) ? background.gradient.trim() : gradientPresetCss(background.gradientPresetId) : null;
46980
48043
  const color = background?.type === "color" && isString(background.color) ? background.color.trim() : null;