@riverbankcms/sdk 0.130.0 → 0.130.2

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 (244) hide show
  1. package/CHANGELOG.md +85 -0
  2. package/README.md +1 -1
  3. package/dist/{PreviewEditorSidebar-DiEpbOdw.mjs → PreviewEditorSidebar-BY-1QdE2.mjs} +18 -15
  4. package/dist/{PreviewEditorUI-C6MvxnIa.mjs → PreviewEditorUI-BS34jI9_.mjs} +3 -3
  5. package/dist/{PreviewQueryProvider-C2rnoPz6.mjs → PreviewQueryProvider-BD0kOjtI.mjs} +1 -1
  6. package/dist/{SdkPreviewModeRuntime-DRXA_m5L.mjs → SdkPreviewModeRuntime-B1pWnhu-.mjs} +48 -21
  7. package/dist/{SiteChromeCustomizeContext-BTHdv5_-.mjs → SiteChromeCustomizeContext-BhUG_72i.mjs} +6180 -5076
  8. package/dist/_dts/ai/src/contracts/proposals.d.ts +309 -32
  9. package/dist/_dts/ai/src/contracts/siteStyleProposalSchemas.d.ts +969 -112
  10. package/dist/_dts/api/src/accountApi.d.ts +213 -0
  11. package/dist/_dts/api/src/accountEndpointDefinitions.d.ts +30 -0
  12. package/dist/_dts/api/src/accountEndpoints.d.ts +254 -0
  13. package/dist/_dts/api/src/apiCallParams.d.ts +60 -0
  14. package/dist/_dts/api/src/bookingConfig.d.ts +10 -20
  15. package/dist/_dts/api/src/bookingManagementEndpoints.d.ts +4 -5
  16. package/dist/_dts/api/src/bookingManagementEventEndpointTypes.d.ts +15 -0
  17. package/dist/_dts/api/src/bookingSettingsSections.d.ts +9 -0
  18. package/dist/_dts/api/src/bookingVerticals.d.ts +2 -2
  19. package/dist/_dts/api/src/commercePortalEndpoints.d.ts +2 -0
  20. package/dist/_dts/api/src/endpoints.d.ts +1253 -1209
  21. package/dist/_dts/api/src/event-destination-policy.d.ts +1 -1
  22. package/dist/_dts/api/src/eventManagementContracts.d.ts +83 -7
  23. package/dist/_dts/api/src/eventManagementEndpointDefinitions.d.ts +26 -0
  24. package/dist/_dts/api/src/eventSeriesPresentationPreset.d.ts +12 -0
  25. package/dist/_dts/api/src/index.d.ts +11 -3
  26. package/dist/_dts/api/src/indexCoreTypes.d.ts +1 -0
  27. package/dist/_dts/api/src/indexExtendedTypes.d.ts +1 -0
  28. package/dist/_dts/api/src/oauth.d.ts +8 -0
  29. package/dist/_dts/api/src/preview-auth.d.ts +26 -0
  30. package/dist/_dts/api/src/publicExperience/eventEndpoints.d.ts +5 -5
  31. package/dist/_dts/api/src/publicExperience/wholeSeriesEndpoints.d.ts +0 -1
  32. package/dist/_dts/api/src/sdk-event-upsert.d.ts +2 -0
  33. package/dist/_dts/api/src/sdkBlockUpsertContracts.d.ts +48 -0
  34. package/dist/_dts/api/src/sdkContracts.d.ts +5 -13
  35. package/dist/_dts/api/src/sdkEventCategoryContracts.d.ts +9 -0
  36. package/dist/_dts/api/src/sdkThemeWire.d.ts +40 -8
  37. package/dist/_dts/api/src/settings/permissions.d.ts +2 -2
  38. package/dist/_dts/api/src/siteApiKeyEndpointDefinitions.d.ts +66 -0
  39. package/dist/_dts/api/src/siteInfrastructure.d.ts +3 -3
  40. package/dist/_dts/api/src/siteOperations.d.ts +1 -1
  41. package/dist/_dts/api/src/sitePlatformEndpoints.d.ts +12 -4
  42. package/dist/_dts/api/src/types.d.ts +7 -59
  43. package/dist/_dts/block-form/src/client/index.d.ts +15 -23
  44. package/dist/_dts/block-form/src/index.d.ts +23 -22
  45. package/dist/_dts/blocks/src/primitives/layout/Grid.d.ts +18 -1
  46. package/dist/_dts/blocks/src/system/blocks/appointment-booking.d.ts +1 -0
  47. package/dist/_dts/blocks/src/system/blocks/events/shared/filtering.d.ts +1 -1
  48. package/dist/_dts/blocks/src/system/blocks/events/shared/schemas.d.ts +61 -0
  49. package/dist/_dts/blocks/src/system/blocks/events/shared/types.d.ts +24 -22
  50. package/dist/_dts/blocks/src/system/blocks/feature-cards.d.ts +25 -1
  51. package/dist/_dts/blocks/src/system/blocks/media-text.d.ts +7 -30
  52. package/dist/_dts/blocks/src/system/blocks/site-header.d.ts +0 -1
  53. package/dist/_dts/blocks/src/system/blocks/team-members.d.ts +4 -63
  54. package/dist/_dts/blocks/src/system/customize/backgrounds.d.ts +1 -3
  55. package/dist/_dts/blocks/src/system/fields/boxStyles.d.ts +13 -1
  56. package/dist/_dts/blocks/src/system/fields/gridLayout.d.ts +20 -0
  57. package/dist/_dts/blocks/src/system/node/fragments/classNameBinding.d.ts +6 -1
  58. package/dist/_dts/blocks/src/system/node/fragments/styledCard.d.ts +31 -0
  59. package/dist/_dts/blocks/src/system/runtime/api/endpoints.d.ts +4 -0
  60. package/dist/_dts/blocks/src/system/runtime/api/types/courses.d.ts +0 -1
  61. package/dist/_dts/blocks/src/system/runtime/api/types/events.d.ts +0 -1
  62. package/dist/_dts/blocks/src/system/runtime/hooks/useHeadlessBookingFlow.state.d.ts +4 -2
  63. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.headless.state.d.ts +24 -8
  64. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.server.d.ts +8 -0
  65. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.validationErrors.d.ts +17 -0
  66. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/event-registration.headless.planning.d.ts +1 -1
  67. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/eventScope.d.ts +1 -1
  68. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration.server.d.ts +1 -1
  69. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/eventCollectionContract.d.ts +42 -0
  70. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/utils.d.ts +4 -1
  71. package/dist/_dts/blocks/src/system/runtime/shared/components/FeedbackMessage.d.ts +17 -1
  72. package/dist/_dts/blocks/src/system/runtime/shared/components/index.d.ts +1 -1
  73. package/dist/_dts/blocks/src/system/spacing.d.ts +1 -1
  74. package/dist/_dts/blocks/src/system/transforms/registry/_utils/boxStyleClassNames.d.ts +90 -0
  75. package/dist/_dts/blocks/src/system/transforms/registry/_utils/surfaceForegroundStyles.d.ts +4 -0
  76. package/dist/_dts/blocks/src/system/transforms/registry/boxStyles.d.ts +26 -0
  77. package/dist/_dts/blocks/src/system/transforms/registry/layout.d.ts +4 -37
  78. package/dist/_dts/content-editor/src/components/ContentFieldsForm.d.ts +2 -2
  79. package/dist/_dts/content-model/src/content-types/builtin-schemas.d.ts +6 -6
  80. package/dist/_dts/content-model/src/content-types/builtins.d.ts +6 -6
  81. package/dist/_dts/core/src/branded.d.ts +4 -0
  82. package/dist/_dts/core/src/event-page-surface-subject.d.ts +25 -4
  83. package/dist/_dts/core/src/index.d.ts +3 -0
  84. package/dist/_dts/core/src/public-event-booking-availability.d.ts +8 -0
  85. package/dist/_dts/core/src/secret.d.ts +44 -0
  86. package/dist/_dts/db/src/generated/supabase/database.types.d.ts +341 -0
  87. package/dist/_dts/editor-blocks/src/BlockEditor.d.ts +2 -1
  88. package/dist/_dts/editor-blocks/src/BlockForm.d.ts +2 -2
  89. package/dist/_dts/editor-blocks/src/block-editor/BlockCard.d.ts +2 -2
  90. package/dist/_dts/editor-blocks/src/block-editor/BlockCardBody.d.ts +1 -1
  91. package/dist/_dts/editor-blocks/src/block-editor/BlockCardHeader.d.ts +1 -1
  92. package/dist/_dts/editor-blocks/src/block-editor/SortableBlockItem.d.ts +1 -1
  93. package/dist/_dts/editor-blocks/src/block-editor/hooks/useBlockValidationManifests.d.ts +1 -1
  94. package/dist/_dts/editor-blocks/src/block-editor/preparedManifest.d.ts +1 -1
  95. package/dist/_dts/editor-blocks/src/blockPayload.d.ts +1 -1
  96. package/dist/_dts/editor-blocks/src/index.d.ts +2 -2
  97. package/dist/_dts/editor-blocks/src/media/MediaField.d.ts +2 -2
  98. package/dist/_dts/editor-blocks/src/widgets/button/ButtonField.d.ts +1 -1
  99. package/dist/_dts/editor-blocks/src/widgets/button/ButtonVariantField.d.ts +1 -1
  100. package/dist/_dts/editor-blocks/src/widgets/button/index.d.ts +1 -1
  101. package/dist/_dts/editor-blocks/src/widgets/content-type-select/ContentTypeSelectField.d.ts +1 -1
  102. package/dist/_dts/editor-blocks/src/widgets/entry-picker/EntryPickerField.d.ts +1 -1
  103. package/dist/_dts/editor-blocks/src/widgets/entry-picker/index.d.ts +1 -1
  104. package/dist/_dts/editor-blocks/src/widgets/icon-picker/IconPickerField.d.ts +1 -1
  105. package/dist/_dts/editor-blocks/src/widgets/inline-text/InlineTextField.d.ts +1 -1
  106. package/dist/_dts/editor-blocks/src/widgets/link/LinkField.d.ts +2 -2
  107. package/dist/_dts/editor-blocks/src/widgets/offerings-preview/OfferingsPreviewGroupOrderField.d.ts +1 -1
  108. package/dist/_dts/editor-blocks/src/widgets/reference/ReferenceField.d.ts +2 -2
  109. package/dist/_dts/editor-blocks/src/widgets/rich-text/RichTextField.d.ts +2 -2
  110. package/dist/_dts/editor-blocks/src/widgets/site-option-picker/SiteOptionPickerField.d.ts +1 -1
  111. package/dist/_dts/editor-blocks/src/widgets/site-option-picker/utils.d.ts +1 -1
  112. package/dist/_dts/preview-next/src/client/blocks/useBlockCustomizeControls.d.ts +1 -1
  113. package/dist/_dts/preview-next/src/client/preview/EntryEditorPanel.d.ts +1 -1
  114. package/dist/_dts/preview-next/src/client/preview/EntrySlotBlockEditorPanel.d.ts +1 -1
  115. package/dist/_dts/preview-next/src/client/preview/PreviewShell.d.ts +2 -0
  116. package/dist/_dts/preview-next/src/client/preview/PreviewSiteFontStorageContext.d.ts +6 -0
  117. package/dist/_dts/preview-next/src/client/preview/siteFontPreview.d.ts +5 -0
  118. package/dist/_dts/preview-next/src/client/sdk/contentStorage.d.ts +10 -0
  119. package/dist/_dts/preview-next/src/client/widgets/widgetOverrides.d.ts +1 -1
  120. package/dist/_dts/preview-next/src/index.d.ts +1 -0
  121. package/dist/_dts/preview-next/src/keepAlive.d.ts +3 -5
  122. package/dist/_dts/preview-next/src/refresh-contract.d.ts +1 -0
  123. package/dist/_dts/preview-next/src/route-contract.d.ts +7 -0
  124. package/dist/_dts/sdk/src/contracts/index.d.ts +1 -1
  125. package/dist/_dts/sdk/src/contracts/system-block-content.d.ts +61 -39
  126. package/dist/_dts/sdk/src/preview-next/keep-alive.d.ts +1 -1
  127. package/dist/_dts/sdk/src/rendering/components/Layout.d.ts +1 -1
  128. package/dist/_dts/sdk/src/rendering/index.d.ts +1 -1
  129. package/dist/_dts/sdk/src/rendering/islands/types.d.ts +9 -1
  130. package/dist/_dts/sdk/src/theme-bridge/types.d.ts +4 -2
  131. package/dist/_dts/sdk/src/version.d.ts +1 -1
  132. package/dist/_dts/theme-core/src/cards/core.d.ts +54 -10
  133. package/dist/_dts/theme-core/src/cards/decorations.d.ts +33 -0
  134. package/dist/_dts/theme-core/src/cards/generateDefaultCardSystem.d.ts +7 -2
  135. package/dist/_dts/theme-core/src/cards/index.d.ts +3 -0
  136. package/dist/_dts/theme-core/src/cards/openCardVariant.d.ts +24 -0
  137. package/dist/_dts/theme-core/src/cards/roles.d.ts +38 -0
  138. package/dist/_dts/theme-core/src/cards/siteStyleDefaults.d.ts +53 -8
  139. package/dist/_dts/theme-core/src/cards/types.d.ts +489 -21
  140. package/dist/_dts/theme-core/src/generated/containerResponsiveThemeCss.d.ts +1 -1
  141. package/dist/_dts/theme-core/src/header/legacyHeaderVariant.d.ts +59 -0
  142. package/dist/_dts/theme-core/src/header/paintTargets.d.ts +2 -2
  143. package/dist/_dts/theme-core/src/header/scrollTreatment.d.ts +3 -2
  144. package/dist/_dts/theme-core/src/mock-themes/all.d.ts +12 -135
  145. package/dist/_dts/theme-core/src/palette/utils/contrast.d.ts +1 -0
  146. package/dist/_dts/theme-core/src/palette/utils/opaqueSurfaceColor.d.ts +6 -0
  147. package/dist/_dts/theme-core/src/runtime/buildThemeRuntimeFromBridge.d.ts +1 -1
  148. package/dist/_dts/theme-core/src/schema.d.ts +301 -94
  149. package/dist/_dts/theme-core/src/site-styles/appearancePresetCatalog.d.ts +84 -102
  150. package/dist/_dts/theme-core/src/site-styles/appearancePresetResolution.d.ts +12 -1
  151. package/dist/_dts/theme-core/src/site-styles/appearancePresetTypes.d.ts +9 -4
  152. package/dist/_dts/theme-core/src/site-styles/backgroundAppearance.d.ts +0 -20
  153. package/dist/_dts/theme-core/src/site-styles/blockAppearancePresets.d.ts +84 -102
  154. package/dist/_dts/theme-core/src/site-styles/cardRoleVocabulary.d.ts +48 -0
  155. package/dist/_dts/theme-core/src/site-styles/designState.d.ts +21 -385
  156. package/dist/_dts/theme-core/src/site-styles/generatedSchemas.d.ts +10 -18
  157. package/dist/_dts/theme-core/src/site-styles/headerLayoutTypes.d.ts +2 -4
  158. package/dist/_dts/theme-core/src/site-styles/headerOpeningForeground.d.ts +2 -9
  159. package/dist/_dts/theme-core/src/site-styles/headerOpeningSection.d.ts +0 -2
  160. package/dist/_dts/theme-core/src/site-styles/index.d.ts +5 -0
  161. package/dist/_dts/theme-core/src/site-styles/pageDesignAppearanceAvailability.d.ts +3 -0
  162. package/dist/_dts/theme-core/src/site-styles/pageDesignEditorCapabilities.d.ts +22 -0
  163. package/dist/_dts/theme-core/src/site-styles/pageDesignEditorModel.d.ts +9 -8
  164. package/dist/_dts/theme-core/src/site-styles/pageDesignIntentEquality.d.ts +3 -0
  165. package/dist/_dts/theme-core/src/site-styles/previewRuntimeCapabilities.d.ts +19 -0
  166. package/dist/_dts/theme-core/src/site-styles/runtimeBackgroundResolution.d.ts +9 -0
  167. package/dist/_dts/theme-core/src/site-styles/runtimeCompiler.d.ts +1 -62
  168. package/dist/_dts/theme-core/src/site-styles/sourceCatalogs.d.ts +13 -12
  169. package/dist/_dts/theme-core/src/site-styles/types.d.ts +50 -39
  170. package/dist/_dts/theme-core/src/siteChromePlanning.d.ts +9 -9
  171. package/dist/_dts/theme-core/src/status/generateStatusCss.d.ts +1 -0
  172. package/dist/_dts/theme-core/src/surfaces/index.d.ts +1 -0
  173. package/dist/_dts/theme-core/src/surfaces/resolveSurfaceForeground.d.ts +39 -0
  174. package/dist/_dts/ui/src/navigation-tabs.d.ts +3 -2
  175. package/dist/client/{CourseRegistrationWizard-Bvtz9G9g.mjs → CourseRegistrationWizard-DGW9F0SQ.mjs} +7 -7
  176. package/dist/client/{DiscountCodeDisclosure-Ur-Xx1U_.mjs → DiscountCodeDisclosure-BPZ-yfGI.mjs} +1 -1
  177. package/dist/client/{EventCombined.client-EhscD4U6.mjs → EventCombined.client-Cjt3kKYR.mjs} +4 -4
  178. package/dist/client/{EventListing.client-Bn26cFTY.mjs → EventListing.client-DY9dn6Fh.mjs} +2 -2
  179. package/dist/client/{FeedbackMessage-ByMrs3cr.mjs → FeedbackMessage-CtLvvS_d.mjs} +15 -3
  180. package/dist/client/{LeafletStaticMap-BUw9Ntzr.mjs → LeafletStaticMap--2c61XYn.mjs} +1 -1
  181. package/dist/client/{StepIndicator-BfbdiVQI.mjs → StepIndicator-CLjQhkDb.mjs} +3 -3
  182. package/dist/client/{accordion-CjIeof73.mjs → accordion-_boYwHHi.mjs} +1 -1
  183. package/dist/client/{bookingForm-DwEeovf_.mjs → bookingForm--AqEfyBX.mjs} +56 -39
  184. package/dist/client/bookings.mjs +393 -192
  185. package/dist/client/{carousel-BMrfgOba.mjs → carousel-CVI2dqZr.mjs} +2 -2
  186. package/dist/client/{carousel.client-CpwTUhIo.mjs → carousel.client-59G_WMr4.mjs} +1 -1
  187. package/dist/client/{cart-rXEdxTdb.mjs → cart-DR6IiPz9.mjs} +3 -3
  188. package/dist/client/{checkout-D3JlSzh3.mjs → checkout-CsrGAfQt.mjs} +3 -3
  189. package/dist/client/client.mjs +4524 -3512
  190. package/dist/client/{colorStyles-BWpj_h4C.mjs → colorStyles-CrxJrPjJ.mjs} +277 -1
  191. package/dist/client/{context-CJz1Vlsz.mjs → context-B83PiNzm.mjs} +6 -21
  192. package/dist/client/{courseRegistration-DO5XvMAA.mjs → courseRegistration-aNJVaLa3.mjs} +3 -3
  193. package/dist/client/{eventCalendar-DO6rTqCn.mjs → eventCalendar-OZ7h59VN.mjs} +6 -6
  194. package/dist/client/{eventCombined-bJ3i_ovU.mjs → eventCombined-BbJ6bFKz.mjs} +3 -3
  195. package/dist/client/{eventDetails-CCbrXE7o.mjs → eventDetails-BLyUBiCT.mjs} +3 -3
  196. package/dist/client/{eventListing-Bdlt9YTm.mjs → eventListing-DuP1yhBS.mjs} +3 -3
  197. package/dist/client/{eventRegistration-B02lt6iY.mjs → eventRegistration-BXyECPa-.mjs} +11 -12
  198. package/dist/client/{form-DrUBAAox.mjs → form-BA4t3kKU.mjs} +4 -4
  199. package/dist/client/{headerSection-MzqvHL6T.mjs → headerSection-CpNaJxhW.mjs} +2 -2
  200. package/dist/client/hooks.mjs +1967 -2059
  201. package/dist/client/{locationMap-DG8BxTBm.mjs → locationMap-3HGMCL7_.mjs} +3 -3
  202. package/dist/client/{media-CNE1Z-wb.mjs → media-BOHuueS5.mjs} +16 -4
  203. package/dist/client/{newsletterForm-BzO-Td3p.mjs → newsletterForm-C2s6Mw67.mjs} +4 -4
  204. package/dist/client/{pricing-NgK7ozkg.mjs → pricing-BiqIMgZk.mjs} +1 -1
  205. package/dist/client/{productDetail-CfQ7rhVK.mjs → productDetail-C9joWhdE.mjs} +3 -3
  206. package/dist/client/{productList-C23rOLUi.mjs → productList-CjzdU3pB.mjs} +3 -3
  207. package/dist/client/{propsDecoder-CAZdhwjs.mjs → propsDecoder-CBPGXEYX.mjs} +395 -402
  208. package/dist/client/rendering/client.mjs +2004 -2856
  209. package/dist/client/rendering/islands.mjs +20 -20
  210. package/dist/client/rendering.mjs +4605 -3496
  211. package/dist/client/{scrollToBlock-DSSqVQr1.mjs → scrollToBlock-DZ73aEX6.mjs} +1 -1
  212. package/dist/client/{shop-BMToKLK7.mjs → shop-CQRai7hj.mjs} +7 -7
  213. package/dist/client/{shop-commerce-DB4JRKmp.mjs → shop-commerce-hP9UboOx.mjs} +8 -8
  214. package/dist/client/{shop-commerce-store-BOqSIOuc.mjs → shop-commerce-store-DiD5a32e.mjs} +1 -1
  215. package/dist/client/{shopShared-B6SK9DZv.mjs → shopShared-DP8DXTkF.mjs} +5 -5
  216. package/dist/client/{useEventFilters-CULOa4nB.mjs → useEventFilters-pF_OJNQP.mjs} +137 -81
  217. package/dist/client/{usePolling-BGG_8-jl.mjs → usePolling-Cls91SD2.mjs} +2 -2
  218. package/dist/preview-next/before-render.mjs +192 -108
  219. package/dist/preview-next/client/runtime.mjs +4 -4
  220. package/dist/preview-next/keepAlive.mjs +7406 -29
  221. package/dist/preview-next/middleware.mjs +186 -107
  222. package/dist/{previewAuthStore-_GXFRg2W.mjs → previewAuthStore-CX1C_KJ4.mjs} +185 -107
  223. package/dist/{sdk-runtime-hhSOMShR.mjs → sdk-runtime-5CcPAI14.mjs} +2 -2
  224. package/dist/{separator-flRaFc14.mjs → separator-BXlYN_gr.mjs} +1 -1
  225. package/dist/server/components.mjs +6363 -4998
  226. package/dist/server/config-validation.mjs +1967 -2059
  227. package/dist/server/config.mjs +1967 -2059
  228. package/dist/server/data.mjs +1967 -2059
  229. package/dist/server/index.mjs +186 -108
  230. package/dist/server/next.mjs +6553 -5285
  231. package/dist/server/page-converter.mjs +1031 -1844
  232. package/dist/server/prebuild.mjs +1 -1
  233. package/dist/server/rendering/server.mjs +3352 -3006
  234. package/dist/server/rendering.mjs +6289 -4924
  235. package/dist/server/routing.mjs +1906 -1036
  236. package/dist/server/server.mjs +1976 -2165
  237. package/dist/server/theme-bridge.mjs +949 -670
  238. package/dist/server/theme.mjs +252 -51
  239. package/dist/styles/index.css +295 -334
  240. package/package.json +3 -2
  241. package/dist/_dts/block-form/src/client/blockDraftSaveability.d.ts +0 -1
  242. package/dist/_dts/block-form/src/widgets/index.d.ts +0 -20
  243. package/dist/_dts/blocks/src/system/runtime/api/requestBody.d.ts +0 -7
  244. package/dist/client/clsx-DgIEfj3H.mjs +0 -16
@@ -1,1041 +1,8 @@
1
1
  import "react/jsx-runtime";
2
2
  import { z } from "zod";
3
+ import "react";
3
4
  import * as fs from "fs/promises";
4
5
  import * as path from "path";
5
- //#region ../../node_modules/.pnpm/@vibrant+image@4.0.4/node_modules/@vibrant/image/dist/esm/histogram.js
6
- var Histogram = class {
7
- constructor(pixels, opts) {
8
- this.pixels = pixels;
9
- this.opts = opts;
10
- const { sigBits } = opts;
11
- const getColorIndex = (r2, g2, b2) => (r2 << 2 * sigBits) + (g2 << sigBits) + b2;
12
- this.getColorIndex = getColorIndex;
13
- const rshift = 8 - sigBits;
14
- const hn = 1 << 3 * sigBits;
15
- const hist = new Uint32Array(hn);
16
- let rmax;
17
- let rmin;
18
- let gmax;
19
- let gmin;
20
- let bmax;
21
- let bmin;
22
- let r;
23
- let g;
24
- let b;
25
- let a;
26
- rmax = gmax = bmax = 0;
27
- rmin = gmin = bmin = Number.MAX_VALUE;
28
- const n = pixels.length / 4;
29
- let i = 0;
30
- while (i < n) {
31
- const offset = i * 4;
32
- i++;
33
- r = pixels[offset + 0];
34
- g = pixels[offset + 1];
35
- b = pixels[offset + 2];
36
- a = pixels[offset + 3];
37
- if (a === 0) continue;
38
- r = r >> rshift;
39
- g = g >> rshift;
40
- b = b >> rshift;
41
- const index = getColorIndex(r, g, b);
42
- if (hist[index] === void 0) hist[index] = 0;
43
- hist[index] += 1;
44
- if (r > rmax) rmax = r;
45
- if (r < rmin) rmin = r;
46
- if (g > gmax) gmax = g;
47
- if (g < gmin) gmin = g;
48
- if (b > bmax) bmax = b;
49
- if (b < bmin) bmin = b;
50
- }
51
- this._colorCount = hist.reduce((total, c) => c > 0 ? total + 1 : total, 0);
52
- this.hist = hist;
53
- this.rmax = rmax;
54
- this.rmin = rmin;
55
- this.gmax = gmax;
56
- this.gmin = gmin;
57
- this.bmax = bmax;
58
- this.bmin = bmin;
59
- }
60
- get colorCount() {
61
- return this._colorCount;
62
- }
63
- };
64
- //#endregion
65
- //#region ../../node_modules/.pnpm/@vibrant+image@4.0.4/node_modules/@vibrant/image/dist/esm/index.js
66
- var ImageBase = class {
67
- scaleDown(opts) {
68
- const width = this.getWidth();
69
- const height = this.getHeight();
70
- let ratio = 1;
71
- if (opts.maxDimension > 0) {
72
- const maxSide = Math.max(width, height);
73
- if (maxSide > opts.maxDimension) ratio = opts.maxDimension / maxSide;
74
- } else ratio = 1 / opts.quality;
75
- if (ratio < 1) this.resize(width * ratio, height * ratio, ratio);
76
- }
77
- };
78
- function applyFilters(imageData, filters) {
79
- if (filters.length > 0) {
80
- const pixels = imageData.data;
81
- const n = pixels.length / 4;
82
- let offset;
83
- let r;
84
- let g;
85
- let b;
86
- let a;
87
- for (let i = 0; i < n; i++) {
88
- offset = i * 4;
89
- r = pixels[offset + 0];
90
- g = pixels[offset + 1];
91
- b = pixels[offset + 2];
92
- a = pixels[offset + 3];
93
- for (let j = 0; j < filters.length; j++) if (!filters[j]?.(r, g, b, a)) {
94
- pixels[offset + 3] = 0;
95
- break;
96
- }
97
- }
98
- }
99
- return imageData;
100
- }
101
- //#endregion
102
- //#region ../../node_modules/.pnpm/@vibrant+image-browser@4.0.4/node_modules/@vibrant/image-browser/dist/esm/index.js
103
- function isRelativeUrl(url) {
104
- const u = new URL(url, location.href);
105
- return u.protocol === location.protocol && u.host === location.host && u.port === location.port;
106
- }
107
- function isSameOrigin(a, b) {
108
- const ua = new URL(a);
109
- const ub = new URL(b);
110
- return ua.protocol === ub.protocol && ua.hostname === ub.hostname && ua.port === ub.port;
111
- }
112
- var BrowserImage = class extends ImageBase {
113
- _getCanvas() {
114
- if (!this._canvas) throw new Error("Canvas is not initialized");
115
- return this._canvas;
116
- }
117
- _getContext() {
118
- if (!this._context) throw new Error("Context is not initialized");
119
- return this._context;
120
- }
121
- _getWidth() {
122
- if (!this._width) throw new Error("Width is not initialized");
123
- return this._width;
124
- }
125
- _getHeight() {
126
- if (!this._height) throw new Error("Height is not initialized");
127
- return this._height;
128
- }
129
- _initCanvas() {
130
- const img = this.image;
131
- if (!img) throw new Error("Image is not initialized");
132
- const canvas = this._canvas = document.createElement("canvas");
133
- const context = canvas.getContext("2d");
134
- if (!context) throw new ReferenceError("Failed to create canvas context");
135
- this._context = context;
136
- canvas.className = "@vibrant/canvas";
137
- canvas.style.display = "none";
138
- this._width = canvas.width = img.width;
139
- this._height = canvas.height = img.height;
140
- context.drawImage(img, 0, 0);
141
- document.body.appendChild(canvas);
142
- }
143
- load(image) {
144
- let img;
145
- let src;
146
- if (typeof image === "string") {
147
- img = document.createElement("img");
148
- src = image;
149
- if (!isRelativeUrl(src) && !isSameOrigin(window.location.href, src)) img.crossOrigin = "anonymous";
150
- img.src = src;
151
- } else if (image instanceof HTMLImageElement) {
152
- img = image;
153
- src = image.src;
154
- } else return Promise.reject(/* @__PURE__ */ new Error(`Cannot load buffer as an image in browser`));
155
- this.image = img;
156
- return new Promise((resolve, reject) => {
157
- const onImageLoad = () => {
158
- this._initCanvas();
159
- resolve(this);
160
- };
161
- if (img.complete) onImageLoad();
162
- else {
163
- img.onload = onImageLoad;
164
- img.onerror = (_e) => reject(/* @__PURE__ */ new Error(`Fail to load image: ${src}`));
165
- }
166
- });
167
- }
168
- clear() {
169
- this._getContext().clearRect(0, 0, this._getWidth(), this._getHeight());
170
- }
171
- update(imageData) {
172
- this._getContext().putImageData(imageData, 0, 0);
173
- }
174
- getWidth() {
175
- return this._getWidth();
176
- }
177
- getHeight() {
178
- return this._getHeight();
179
- }
180
- resize(targetWidth, targetHeight, ratio) {
181
- if (!this.image) throw new Error("Image is not initialized");
182
- this._width = this._getCanvas().width = targetWidth;
183
- this._height = this._getCanvas().height = targetHeight;
184
- this._getContext().scale(ratio, ratio);
185
- this._getContext().drawImage(this.image, 0, 0);
186
- }
187
- getPixelCount() {
188
- return this._getWidth() * this._getHeight();
189
- }
190
- getImageData() {
191
- return this._getContext().getImageData(0, 0, this._getWidth(), this._getHeight());
192
- }
193
- remove() {
194
- if (this._canvas && this._canvas.parentNode) this._canvas.parentNode.removeChild(this._canvas);
195
- }
196
- };
197
- //#endregion
198
- //#region ../../node_modules/.pnpm/@vibrant+core@4.0.4/node_modules/@vibrant/core/dist/esm/utils.js
199
- function assignDeep(target, ...sources) {
200
- sources.forEach((s) => {
201
- if (!s) return;
202
- for (const key in s) if (s.hasOwnProperty(key)) {
203
- const v = s[key];
204
- if (Array.isArray(v)) target[key] = v.slice(0);
205
- else if (typeof v === "object") {
206
- if (!target[key]) target[key] = {};
207
- assignDeep(target[key], v);
208
- } else target[key] = v;
209
- }
210
- });
211
- return target;
212
- }
213
- //#endregion
214
- //#region ../../node_modules/.pnpm/@vibrant+core@4.0.4/node_modules/@vibrant/core/dist/esm/options.js
215
- function buildProcessOptions(opts, override) {
216
- const { colorCount, quantizer, generators, filters } = opts;
217
- const commonQuantizerOpts = { colorCount };
218
- const q = typeof quantizer === "string" ? {
219
- name: quantizer,
220
- options: {}
221
- } : quantizer;
222
- q.options = assignDeep({}, commonQuantizerOpts, q.options);
223
- return assignDeep({}, {
224
- quantizer: q,
225
- generators,
226
- filters
227
- }, override);
228
- }
229
- //#endregion
230
- //#region ../../node_modules/.pnpm/@vibrant+core@4.0.4/node_modules/@vibrant/core/dist/esm/builder.js
231
- var Builder = class {
232
- /**
233
- * Arguments are the same as `Vibrant.constructor`.
234
- */
235
- constructor(src, opts = {}) {
236
- this._src = src;
237
- this._opts = assignDeep({}, Vibrant.DefaultOpts, opts);
238
- }
239
- /**
240
- * Sets `opts.colorCount` to `n`.
241
- * @returns this `Builder` instance.
242
- */
243
- maxColorCount(n) {
244
- this._opts.colorCount = n;
245
- return this;
246
- }
247
- /**
248
- * Sets `opts.maxDimension` to `d`.
249
- * @returns this `Builder` instance.
250
- */
251
- maxDimension(d) {
252
- this._opts.maxDimension = d;
253
- return this;
254
- }
255
- /**
256
- * Adds a filter function
257
- * @returns this `Builder` instance.
258
- */
259
- addFilter(name) {
260
- if (!this._opts.filters) this._opts.filters = [name];
261
- else this._opts.filters.push(name);
262
- return this;
263
- }
264
- /**
265
- * Removes a filter function.
266
- * @returns this `Builder` instance.
267
- */
268
- removeFilter(name) {
269
- if (this._opts.filters) {
270
- const i = this._opts.filters.indexOf(name);
271
- if (i > 0) this._opts.filters.splice(i);
272
- }
273
- return this;
274
- }
275
- /**
276
- * Clear all filters.
277
- * @returns this `Builder` instance.
278
- */
279
- clearFilters() {
280
- this._opts.filters = [];
281
- return this;
282
- }
283
- /**
284
- * Sets `opts.quality` to `q`.
285
- * @returns this `Builder` instance.
286
- */
287
- quality(q) {
288
- this._opts.quality = q;
289
- return this;
290
- }
291
- /**
292
- * Specifies which `Image` implementation class to use.
293
- * @returns this `Builder` instance.
294
- */
295
- useImageClass(imageClass) {
296
- this._opts.ImageClass = imageClass;
297
- return this;
298
- }
299
- /**
300
- * Sets `opts.generator` to `generator`
301
- * @returns this `Builder` instance.
302
- */
303
- useGenerator(generator, options) {
304
- if (!this._opts.generators) this._opts.generators = [];
305
- this._opts.generators.push(options ? {
306
- name: generator,
307
- options
308
- } : generator);
309
- return this;
310
- }
311
- /**
312
- * Specifies which `Quantizer` implementation class to use
313
- * @returns this `Builder` instance.
314
- */
315
- useQuantizer(quantizer, options) {
316
- this._opts.quantizer = options ? {
317
- name: quantizer,
318
- options
319
- } : quantizer;
320
- return this;
321
- }
322
- /**
323
- * Builds and returns a `Vibrant` instance as configured.
324
- */
325
- build() {
326
- return new Vibrant(this._src, this._opts);
327
- }
328
- /**
329
- * Builds a `Vibrant` instance as configured and calls its `getPalette` method.
330
- */
331
- getPalette() {
332
- return this.build().getPalette();
333
- }
334
- };
335
- //#endregion
336
- //#region ../../node_modules/.pnpm/@vibrant+core@4.0.4/node_modules/@vibrant/core/dist/esm/pipeline/index.js
337
- var Stage = class {
338
- constructor(pipeline) {
339
- this.pipeline = pipeline;
340
- this._map = {};
341
- }
342
- names() {
343
- return Object.keys(this._map);
344
- }
345
- has(name) {
346
- return !!this._map[name];
347
- }
348
- get(name) {
349
- return this._map[name];
350
- }
351
- register(name, stageFn) {
352
- this._map[name] = stageFn;
353
- return this.pipeline;
354
- }
355
- };
356
- var BasicPipeline = class {
357
- constructor() {
358
- this.filter = new Stage(this);
359
- this.quantizer = new Stage(this);
360
- this.generator = new Stage(this);
361
- }
362
- _buildProcessTasks({ filters, quantizer, generators }) {
363
- if (generators.length === 1 && generators[0] === "*") generators = this.generator.names();
364
- return {
365
- filters: filters.map((f) => createTask(this.filter, f)),
366
- quantizer: createTask(this.quantizer, quantizer),
367
- generators: generators.map((g) => createTask(this.generator, g))
368
- };
369
- function createTask(stage, o) {
370
- let name;
371
- let options;
372
- if (typeof o === "string") name = o;
373
- else {
374
- name = o.name;
375
- options = o.options;
376
- }
377
- return {
378
- name,
379
- fn: stage.get(name),
380
- options
381
- };
382
- }
383
- }
384
- async process(imageData, opts) {
385
- const { filters, quantizer, generators } = this._buildProcessTasks(opts);
386
- const imageFilterData = await this._filterColors(filters, imageData);
387
- const colors = await this._generateColors(quantizer, imageFilterData);
388
- return {
389
- colors,
390
- palettes: await this._generatePalettes(generators, colors)
391
- };
392
- }
393
- _filterColors(filters, imageData) {
394
- return Promise.resolve(applyFilters(imageData, filters.map(({ fn }) => fn)));
395
- }
396
- _generateColors(quantizer, imageData) {
397
- return Promise.resolve(quantizer.fn(imageData.data, quantizer.options));
398
- }
399
- async _generatePalettes(generators, colors) {
400
- const promiseArr = await Promise.all(generators.map(({ fn, options }) => Promise.resolve(fn(colors, options))));
401
- return Promise.resolve(promiseArr.reduce((promises, promiseVal, i) => {
402
- promises[generators[i].name] = promiseVal;
403
- return promises;
404
- }, {}));
405
- }
406
- };
407
- //#endregion
408
- //#region ../../node_modules/.pnpm/@vibrant+color@4.0.4/node_modules/@vibrant/color/dist/esm/converter.js
409
- function rgbToHex(r, g, b) {
410
- return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1, 7);
411
- }
412
- function rgbToHsl(r, g, b) {
413
- r /= 255;
414
- g /= 255;
415
- b /= 255;
416
- const max = Math.max(r, g, b);
417
- const min = Math.min(r, g, b);
418
- let h = 0;
419
- let s = 0;
420
- const l = (max + min) / 2;
421
- if (max !== min) {
422
- const d = max - min;
423
- s = l > .5 ? d / (2 - max - min) : d / (max + min);
424
- switch (max) {
425
- case r:
426
- h = (g - b) / d + (g < b ? 6 : 0);
427
- break;
428
- case g:
429
- h = (b - r) / d + 2;
430
- break;
431
- case b:
432
- h = (r - g) / d + 4;
433
- break;
434
- }
435
- h /= 6;
436
- }
437
- return [
438
- h,
439
- s,
440
- l
441
- ];
442
- }
443
- function hslToRgb(h, s, l) {
444
- let r;
445
- let g;
446
- let b;
447
- function hue2rgb(p, q, t) {
448
- if (t < 0) t += 1;
449
- if (t > 1) t -= 1;
450
- if (t < 1 / 6) return p + (q - p) * 6 * t;
451
- if (t < 1 / 2) return q;
452
- if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
453
- return p;
454
- }
455
- if (s === 0) r = g = b = l;
456
- else {
457
- const q = l < .5 ? l * (1 + s) : l + s - l * s;
458
- const p = 2 * l - q;
459
- r = hue2rgb(p, q, h + 1 / 3);
460
- g = hue2rgb(p, q, h);
461
- b = hue2rgb(p, q, h - 1 / 3);
462
- }
463
- return [
464
- r * 255,
465
- g * 255,
466
- b * 255
467
- ];
468
- }
469
- //#endregion
470
- //#region ../../node_modules/.pnpm/@vibrant+color@4.0.4/node_modules/@vibrant/color/dist/esm/index.js
471
- var Swatch = class Swatch {
472
- static applyFilters(colors, filters) {
473
- return filters.length > 0 ? colors.filter(({ r, g, b }) => {
474
- for (let j = 0; j < filters.length; j++) if (!filters[j]?.(r, g, b, 255)) return false;
475
- return true;
476
- }) : colors;
477
- }
478
- /**
479
- * Make a value copy of a swatch based on a previous one. Returns a new Swatch instance
480
- * @param {Swatch} swatch
481
- */
482
- static clone(swatch) {
483
- return new Swatch(swatch._rgb, swatch._population);
484
- }
485
- /**
486
- * The red value in the RGB value
487
- */
488
- get r() {
489
- return this._rgb[0];
490
- }
491
- /**
492
- * The green value in the RGB value
493
- */
494
- get g() {
495
- return this._rgb[1];
496
- }
497
- /**
498
- * The blue value in the RGB value
499
- */
500
- get b() {
501
- return this._rgb[2];
502
- }
503
- /**
504
- * The color value as a rgb value
505
- */
506
- get rgb() {
507
- return this._rgb;
508
- }
509
- /**
510
- * The color value as a hsl value
511
- */
512
- get hsl() {
513
- if (!this._hsl) {
514
- const [r, g, b] = this._rgb;
515
- this._hsl = rgbToHsl(r, g, b);
516
- }
517
- return this._hsl;
518
- }
519
- /**
520
- * The color value as a hex string
521
- */
522
- get hex() {
523
- if (!this._hex) {
524
- const [r, g, b] = this._rgb;
525
- this._hex = rgbToHex(r, g, b);
526
- }
527
- return this._hex;
528
- }
529
- get population() {
530
- return this._population;
531
- }
532
- /**
533
- * Get the JSON object for the swatch
534
- */
535
- toJSON() {
536
- return {
537
- rgb: this.rgb,
538
- population: this.population
539
- };
540
- }
541
- getYiq() {
542
- if (!this._yiq) {
543
- const rgb = this._rgb;
544
- this._yiq = (rgb[0] * 299 + rgb[1] * 587 + rgb[2] * 114) / 1e3;
545
- }
546
- return this._yiq;
547
- }
548
- /**
549
- * Returns an appropriate color to use for any 'title' text which is displayed over this Swatch's color.
550
- */
551
- get titleTextColor() {
552
- if (!this._titleTextColor) this._titleTextColor = this.getYiq() < 200 ? "#fff" : "#000";
553
- return this._titleTextColor;
554
- }
555
- /**
556
- * Returns an appropriate color to use for any 'body' text which is displayed over this Swatch's color.
557
- */
558
- get bodyTextColor() {
559
- if (!this._bodyTextColor) this._bodyTextColor = this.getYiq() < 150 ? "#fff" : "#000";
560
- return this._bodyTextColor;
561
- }
562
- /**
563
- * Internal use.
564
- * @param rgb `[r, g, b]`
565
- * @param population Population of the color in an image
566
- */
567
- constructor(rgb, population) {
568
- this._rgb = rgb;
569
- this._population = population;
570
- }
571
- };
572
- //#endregion
573
- //#region ../../node_modules/.pnpm/@vibrant+core@4.0.4/node_modules/@vibrant/core/dist/esm/index.js
574
- const _Vibrant = class _Vibrant {
575
- /**
576
- *
577
- * @param _src Path to image file (supports HTTP/HTTPs)
578
- * @param opts Options (optional)
579
- */
580
- constructor(_src, opts) {
581
- this._src = _src;
582
- this.opts = assignDeep({}, _Vibrant.DefaultOpts, opts);
583
- }
584
- static use(pipeline) {
585
- this._pipeline = pipeline;
586
- }
587
- static from(src) {
588
- return new Builder(src);
589
- }
590
- get result() {
591
- return this._result;
592
- }
593
- _process(image, opts) {
594
- image.scaleDown(this.opts);
595
- const processOpts = buildProcessOptions(this.opts, opts);
596
- return _Vibrant._pipeline.process(image.getImageData(), processOpts);
597
- }
598
- async getPalette() {
599
- const image = new this.opts.ImageClass();
600
- try {
601
- const image1 = await image.load(this._src);
602
- const result1 = await this._process(image1, { generators: ["default"] });
603
- this._result = result1;
604
- const res = result1.palettes["default"];
605
- if (!res) throw new Error(`Something went wrong and a palette was not found, please file a bug against our GitHub repo: https://github.com/vibrant-Colors/node-vibrant/`);
606
- image.remove();
607
- return res;
608
- } catch (err) {
609
- image.remove();
610
- return Promise.reject(err);
611
- }
612
- }
613
- async getPalettes() {
614
- const image = new this.opts.ImageClass();
615
- try {
616
- const image1 = await image.load(this._src);
617
- const result1 = await this._process(image1, { generators: ["*"] });
618
- this._result = result1;
619
- const res = result1.palettes;
620
- image.remove();
621
- return res;
622
- } catch (err) {
623
- image.remove();
624
- return Promise.reject(err);
625
- }
626
- }
627
- };
628
- _Vibrant.DefaultOpts = {
629
- colorCount: 64,
630
- quality: 5,
631
- filters: []
632
- };
633
- let Vibrant = _Vibrant;
634
- //#endregion
635
- //#region ../../node_modules/.pnpm/node-vibrant@4.0.4/node_modules/node-vibrant/dist/esm/configs/config.js
636
- Vibrant.DefaultOpts.quantizer = "mmcq";
637
- Vibrant.DefaultOpts.generators = ["default"];
638
- Vibrant.DefaultOpts.filters = ["default"];
639
- //#endregion
640
- //#region ../../node_modules/.pnpm/node-vibrant@4.0.4/node_modules/node-vibrant/dist/esm/configs/browser.js
641
- Vibrant.DefaultOpts.ImageClass = BrowserImage;
642
- //#endregion
643
- //#region ../../node_modules/.pnpm/@vibrant+quantizer-mmcq@4.0.4/node_modules/@vibrant/quantizer-mmcq/dist/esm/vbox.js
644
- const SIGBITS = 5;
645
- const RSHIFT = 8 - SIGBITS;
646
- var VBox = class VBox {
647
- constructor(r1, r2, g1, g2, b1, b2, histogram) {
648
- this.histogram = histogram;
649
- this._volume = -1;
650
- this._avg = null;
651
- this._count = -1;
652
- this.dimension = {
653
- r1,
654
- r2,
655
- g1,
656
- g2,
657
- b1,
658
- b2
659
- };
660
- }
661
- static build(pixels) {
662
- const h = new Histogram(pixels, { sigBits: SIGBITS });
663
- const { rmin, rmax, gmin, gmax, bmin, bmax } = h;
664
- return new VBox(rmin, rmax, gmin, gmax, bmin, bmax, h);
665
- }
666
- invalidate() {
667
- this._volume = this._count = -1;
668
- this._avg = null;
669
- }
670
- volume() {
671
- if (this._volume < 0) {
672
- const { r1, r2, g1, g2, b1, b2 } = this.dimension;
673
- this._volume = (r2 - r1 + 1) * (g2 - g1 + 1) * (b2 - b1 + 1);
674
- }
675
- return this._volume;
676
- }
677
- count() {
678
- if (this._count < 0) {
679
- const { hist, getColorIndex } = this.histogram;
680
- const { r1, r2, g1, g2, b1, b2 } = this.dimension;
681
- let c = 0;
682
- for (let r = r1; r <= r2; r++) for (let g = g1; g <= g2; g++) for (let b = b1; b <= b2; b++) {
683
- const index = getColorIndex(r, g, b);
684
- if (!hist[index]) continue;
685
- c += hist[index];
686
- }
687
- this._count = c;
688
- }
689
- return this._count;
690
- }
691
- clone() {
692
- const { histogram } = this;
693
- const { r1, r2, g1, g2, b1, b2 } = this.dimension;
694
- return new VBox(r1, r2, g1, g2, b1, b2, histogram);
695
- }
696
- avg() {
697
- if (!this._avg) {
698
- const { hist, getColorIndex } = this.histogram;
699
- const { r1, r2, g1, g2, b1, b2 } = this.dimension;
700
- let ntot = 0;
701
- const mult = 1 << 8 - SIGBITS;
702
- let rsum;
703
- let gsum;
704
- let bsum;
705
- rsum = gsum = bsum = 0;
706
- for (let r = r1; r <= r2; r++) for (let g = g1; g <= g2; g++) for (let b = b1; b <= b2; b++) {
707
- const h = hist[getColorIndex(r, g, b)];
708
- if (!h) continue;
709
- ntot += h;
710
- rsum += h * (r + .5) * mult;
711
- gsum += h * (g + .5) * mult;
712
- bsum += h * (b + .5) * mult;
713
- }
714
- if (ntot) this._avg = [
715
- ~~(rsum / ntot),
716
- ~~(gsum / ntot),
717
- ~~(bsum / ntot)
718
- ];
719
- else this._avg = [
720
- ~~(mult * (r1 + r2 + 1) / 2),
721
- ~~(mult * (g1 + g2 + 1) / 2),
722
- ~~(mult * (b1 + b2 + 1) / 2)
723
- ];
724
- }
725
- return this._avg;
726
- }
727
- contains(rgb) {
728
- let [r, g, b] = rgb;
729
- const { r1, r2, g1, g2, b1, b2 } = this.dimension;
730
- r >>= RSHIFT;
731
- g >>= RSHIFT;
732
- b >>= RSHIFT;
733
- return r >= r1 && r <= r2 && g >= g1 && g <= g2 && b >= b1 && b <= b2;
734
- }
735
- split() {
736
- const { hist, getColorIndex } = this.histogram;
737
- const { r1, r2, g1, g2, b1, b2 } = this.dimension;
738
- const count = this.count();
739
- if (!count) return [];
740
- if (count === 1) return [this.clone()];
741
- const rw = r2 - r1 + 1;
742
- const gw = g2 - g1 + 1;
743
- const bw = b2 - b1 + 1;
744
- const maxw = Math.max(rw, gw, bw);
745
- let accSum = null;
746
- let sum;
747
- let total;
748
- sum = total = 0;
749
- let maxd = null;
750
- if (maxw === rw) {
751
- maxd = "r";
752
- accSum = new Uint32Array(r2 + 1);
753
- for (let r = r1; r <= r2; r++) {
754
- sum = 0;
755
- for (let g = g1; g <= g2; g++) for (let b = b1; b <= b2; b++) {
756
- const index = getColorIndex(r, g, b);
757
- if (!hist[index]) continue;
758
- sum += hist[index];
759
- }
760
- total += sum;
761
- accSum[r] = total;
762
- }
763
- } else if (maxw === gw) {
764
- maxd = "g";
765
- accSum = new Uint32Array(g2 + 1);
766
- for (let g = g1; g <= g2; g++) {
767
- sum = 0;
768
- for (let r = r1; r <= r2; r++) for (let b = b1; b <= b2; b++) {
769
- const index = getColorIndex(r, g, b);
770
- if (!hist[index]) continue;
771
- sum += hist[index];
772
- }
773
- total += sum;
774
- accSum[g] = total;
775
- }
776
- } else {
777
- maxd = "b";
778
- accSum = new Uint32Array(b2 + 1);
779
- for (let b = b1; b <= b2; b++) {
780
- sum = 0;
781
- for (let r = r1; r <= r2; r++) for (let g = g1; g <= g2; g++) {
782
- const index = getColorIndex(r, g, b);
783
- if (!hist[index]) continue;
784
- sum += hist[index];
785
- }
786
- total += sum;
787
- accSum[b] = total;
788
- }
789
- }
790
- let splitPoint = -1;
791
- const reverseSum = new Uint32Array(accSum.length);
792
- for (let i = 0; i < accSum.length; i++) {
793
- const d = accSum[i];
794
- if (!d) continue;
795
- if (splitPoint < 0 && d > total / 2) splitPoint = i;
796
- reverseSum[i] = total - d;
797
- }
798
- const vbox = this;
799
- function doCut(d) {
800
- const dim1 = d + "1";
801
- const dim2 = d + "2";
802
- const d1 = vbox.dimension[dim1];
803
- let d2 = vbox.dimension[dim2];
804
- const vbox1 = vbox.clone();
805
- const vbox2 = vbox.clone();
806
- const left = splitPoint - d1;
807
- const right = d2 - splitPoint;
808
- if (left <= right) {
809
- d2 = Math.min(d2 - 1, ~~(splitPoint + right / 2));
810
- d2 = Math.max(0, d2);
811
- } else {
812
- d2 = Math.max(d1, ~~(splitPoint - 1 - left / 2));
813
- d2 = Math.min(vbox.dimension[dim2], d2);
814
- }
815
- while (!accSum[d2]) d2++;
816
- let c2 = reverseSum[d2];
817
- while (!c2 && accSum[d2 - 1]) c2 = reverseSum[--d2];
818
- vbox1.dimension[dim2] = d2;
819
- vbox2.dimension[dim1] = d2 + 1;
820
- return [vbox1, vbox2];
821
- }
822
- return doCut(maxd);
823
- }
824
- };
825
- //#endregion
826
- //#region ../../node_modules/.pnpm/@vibrant+quantizer-mmcq@4.0.4/node_modules/@vibrant/quantizer-mmcq/dist/esm/pqueue.js
827
- var PQueue = class {
828
- _sort() {
829
- if (!this._sorted) {
830
- this.contents.sort(this._comparator);
831
- this._sorted = true;
832
- }
833
- }
834
- constructor(comparator) {
835
- this._comparator = comparator;
836
- this.contents = [];
837
- this._sorted = false;
838
- }
839
- push(item) {
840
- this.contents.push(item);
841
- this._sorted = false;
842
- }
843
- peek(index) {
844
- this._sort();
845
- index = typeof index === "number" ? index : this.contents.length - 1;
846
- return this.contents[index];
847
- }
848
- pop() {
849
- this._sort();
850
- return this.contents.pop();
851
- }
852
- size() {
853
- return this.contents.length;
854
- }
855
- map(mapper) {
856
- this._sort();
857
- return this.contents.map(mapper);
858
- }
859
- };
860
- //#endregion
861
- //#region ../../node_modules/.pnpm/@vibrant+quantizer-mmcq@4.0.4/node_modules/@vibrant/quantizer-mmcq/dist/esm/index.js
862
- const fractByPopulations = .75;
863
- function _splitBoxes(pq, target) {
864
- let lastSize = pq.size();
865
- while (pq.size() < target) {
866
- const vbox = pq.pop();
867
- if (vbox && vbox.count() > 0) {
868
- const [vbox1, vbox2] = vbox.split();
869
- if (!vbox1) break;
870
- pq.push(vbox1);
871
- if (vbox2 && vbox2.count() > 0) pq.push(vbox2);
872
- if (pq.size() === lastSize) break;
873
- else lastSize = pq.size();
874
- } else break;
875
- }
876
- }
877
- const MMCQ = (pixels, opts) => {
878
- if (pixels.length === 0 || opts.colorCount < 2 || opts.colorCount > 256) throw new Error("Wrong MMCQ parameters");
879
- const vbox = VBox.build(pixels);
880
- vbox.histogram.colorCount;
881
- const pq = new PQueue((a, b) => a.count() - b.count());
882
- pq.push(vbox);
883
- _splitBoxes(pq, fractByPopulations * opts.colorCount);
884
- const pq2 = new PQueue((a, b) => a.count() * a.volume() - b.count() * b.volume());
885
- pq2.contents = pq.contents;
886
- _splitBoxes(pq2, opts.colorCount - pq2.size());
887
- return generateSwatches(pq2);
888
- };
889
- function generateSwatches(pq) {
890
- const swatches = [];
891
- while (pq.size()) {
892
- const v = pq.pop();
893
- const color = v.avg();
894
- const [r, g, b] = color;
895
- swatches.push(new Swatch(color, v.count()));
896
- }
897
- return swatches;
898
- }
899
- //#endregion
900
- //#region ../../node_modules/.pnpm/@vibrant+generator-default@4.0.4/node_modules/@vibrant/generator-default/dist/esm/index.js
901
- const DefaultOpts = {
902
- targetDarkLuma: .26,
903
- maxDarkLuma: .45,
904
- minLightLuma: .55,
905
- targetLightLuma: .74,
906
- minNormalLuma: .3,
907
- targetNormalLuma: .5,
908
- maxNormalLuma: .7,
909
- targetMutesSaturation: .3,
910
- maxMutesSaturation: .4,
911
- targetVibrantSaturation: 1,
912
- minVibrantSaturation: .35,
913
- weightSaturation: 3,
914
- weightLuma: 6.5,
915
- weightPopulation: .5
916
- };
917
- function _findMaxPopulation(swatches) {
918
- let p = 0;
919
- swatches.forEach((s) => {
920
- p = Math.max(p, s.population);
921
- });
922
- return p;
923
- }
924
- function _isAlreadySelected(palette, s) {
925
- return palette.Vibrant === s || palette.DarkVibrant === s || palette.LightVibrant === s || palette.Muted === s || palette.DarkMuted === s || palette.LightMuted === s;
926
- }
927
- function _createComparisonValue(saturation, targetSaturation, luma, targetLuma, population, maxPopulation, opts) {
928
- function weightedMean(...values) {
929
- let sum = 0;
930
- let weightSum = 0;
931
- for (let i = 0; i < values.length; i += 2) {
932
- const value = values[i];
933
- const weight = values[i + 1];
934
- if (!value || !weight) continue;
935
- sum += value * weight;
936
- weightSum += weight;
937
- }
938
- return sum / weightSum;
939
- }
940
- function invertDiff(value, targetValue) {
941
- return 1 - Math.abs(value - targetValue);
942
- }
943
- return weightedMean(invertDiff(saturation, targetSaturation), opts.weightSaturation, invertDiff(luma, targetLuma), opts.weightLuma, population / maxPopulation, opts.weightPopulation);
944
- }
945
- function _findColorVariation(palette, swatches, maxPopulation, targetLuma, minLuma, maxLuma, targetSaturation, minSaturation, maxSaturation, opts) {
946
- let max = null;
947
- let maxValue = 0;
948
- swatches.forEach((swatch) => {
949
- const [, s, l] = swatch.hsl;
950
- if (s >= minSaturation && s <= maxSaturation && l >= minLuma && l <= maxLuma && !_isAlreadySelected(palette, swatch)) {
951
- const value = _createComparisonValue(s, targetSaturation, l, targetLuma, swatch.population, maxPopulation, opts);
952
- if (max === null || value > maxValue) {
953
- max = swatch;
954
- maxValue = value;
955
- }
956
- }
957
- });
958
- return max;
959
- }
960
- function _generateVariationColors(swatches, maxPopulation, opts) {
961
- const palette = {
962
- Vibrant: null,
963
- DarkVibrant: null,
964
- LightVibrant: null,
965
- Muted: null,
966
- DarkMuted: null,
967
- LightMuted: null
968
- };
969
- palette.Vibrant = _findColorVariation(palette, swatches, maxPopulation, opts.targetNormalLuma, opts.minNormalLuma, opts.maxNormalLuma, opts.targetVibrantSaturation, opts.minVibrantSaturation, 1, opts);
970
- palette.LightVibrant = _findColorVariation(palette, swatches, maxPopulation, opts.targetLightLuma, opts.minLightLuma, 1, opts.targetVibrantSaturation, opts.minVibrantSaturation, 1, opts);
971
- palette.DarkVibrant = _findColorVariation(palette, swatches, maxPopulation, opts.targetDarkLuma, 0, opts.maxDarkLuma, opts.targetVibrantSaturation, opts.minVibrantSaturation, 1, opts);
972
- palette.Muted = _findColorVariation(palette, swatches, maxPopulation, opts.targetNormalLuma, opts.minNormalLuma, opts.maxNormalLuma, opts.targetMutesSaturation, 0, opts.maxMutesSaturation, opts);
973
- palette.LightMuted = _findColorVariation(palette, swatches, maxPopulation, opts.targetLightLuma, opts.minLightLuma, 1, opts.targetMutesSaturation, 0, opts.maxMutesSaturation, opts);
974
- palette.DarkMuted = _findColorVariation(palette, swatches, maxPopulation, opts.targetDarkLuma, 0, opts.maxDarkLuma, opts.targetMutesSaturation, 0, opts.maxMutesSaturation, opts);
975
- return palette;
976
- }
977
- function _generateEmptySwatches(palette, _maxPopulation, opts) {
978
- if (!palette.Vibrant && !palette.DarkVibrant && !palette.LightVibrant) {
979
- if (!palette.DarkVibrant && palette.DarkMuted) {
980
- let [h, s, l] = palette.DarkMuted.hsl;
981
- l = opts.targetDarkLuma;
982
- palette.DarkVibrant = new Swatch(hslToRgb(h, s, l), 0);
983
- }
984
- if (!palette.LightVibrant && palette.LightMuted) {
985
- let [h, s, l] = palette.LightMuted.hsl;
986
- l = opts.targetDarkLuma;
987
- palette.DarkVibrant = new Swatch(hslToRgb(h, s, l), 0);
988
- }
989
- }
990
- if (!palette.Vibrant && palette.DarkVibrant) {
991
- let [h, s, l] = palette.DarkVibrant.hsl;
992
- l = opts.targetNormalLuma;
993
- palette.Vibrant = new Swatch(hslToRgb(h, s, l), 0);
994
- } else if (!palette.Vibrant && palette.LightVibrant) {
995
- let [h, s, l] = palette.LightVibrant.hsl;
996
- l = opts.targetNormalLuma;
997
- palette.Vibrant = new Swatch(hslToRgb(h, s, l), 0);
998
- }
999
- if (!palette.DarkVibrant && palette.Vibrant) {
1000
- let [h, s, l] = palette.Vibrant.hsl;
1001
- l = opts.targetDarkLuma;
1002
- palette.DarkVibrant = new Swatch(hslToRgb(h, s, l), 0);
1003
- }
1004
- if (!palette.LightVibrant && palette.Vibrant) {
1005
- let [h, s, l] = palette.Vibrant.hsl;
1006
- l = opts.targetLightLuma;
1007
- palette.LightVibrant = new Swatch(hslToRgb(h, s, l), 0);
1008
- }
1009
- if (!palette.Muted && palette.Vibrant) {
1010
- let [h, s, l] = palette.Vibrant.hsl;
1011
- l = opts.targetMutesSaturation;
1012
- palette.Muted = new Swatch(hslToRgb(h, s, l), 0);
1013
- }
1014
- if (!palette.DarkMuted && palette.DarkVibrant) {
1015
- let [h, s, l] = palette.DarkVibrant.hsl;
1016
- l = opts.targetMutesSaturation;
1017
- palette.DarkMuted = new Swatch(hslToRgb(h, s, l), 0);
1018
- }
1019
- if (!palette.LightMuted && palette.LightVibrant) {
1020
- let [h, s, l] = palette.LightVibrant.hsl;
1021
- l = opts.targetMutesSaturation;
1022
- palette.LightMuted = new Swatch(hslToRgb(h, s, l), 0);
1023
- }
1024
- }
1025
- const DefaultGenerator = ((swatches, opts) => {
1026
- opts = Object.assign({}, DefaultOpts, opts);
1027
- const maxPopulation = _findMaxPopulation(swatches);
1028
- const palette = _generateVariationColors(swatches, maxPopulation, opts);
1029
- _generateEmptySwatches(palette, maxPopulation, opts);
1030
- return palette;
1031
- });
1032
- //#endregion
1033
- //#region ../../node_modules/.pnpm/node-vibrant@4.0.4/node_modules/node-vibrant/dist/esm/pipeline/index.js
1034
- const pipeline = new BasicPipeline().filter.register("default", (r, g, b, a) => a >= 125 && !(r > 250 && g > 250 && b > 250)).quantizer.register("mmcq", MMCQ).generator.register("default", DefaultGenerator);
1035
- //#endregion
1036
- //#region ../../node_modules/.pnpm/node-vibrant@4.0.4/node_modules/node-vibrant/dist/esm/browser.js
1037
- Vibrant.use(pipeline);
1038
- //#endregion
1039
6
  //#region ../theme-core/src/tokens/colorTokenParts.ts
1040
7
  function parseOpacityPercent(source) {
1041
8
  const trimmed = source.trim();
@@ -4984,9 +3951,30 @@ function presetCategory(recipe) {
4984
3951
  //#region ../theme-core/src/cards/types.ts
4985
3952
  const cardVariantRoleValues = ["default", "alternative"];
4986
3953
  const boxlessCardVariantValue = "none";
3954
+ const openCardRoleValue = "open";
3955
+ /**
3956
+ * The roles a site style implements with an actual card variant. `none` is
3957
+ * deliberately absent: it is a role value only, never a variant.
3958
+ */
3959
+ const surfaceCardRoleValues = [...cardVariantRoleValues, openCardRoleValue];
3960
+ /**
3961
+ * The closed card-role vocabulary Looks and blocks address cards by — this is
3962
+ * `BoxStylesCardVariant` widened with `open`, not a parallel enum.
3963
+ *
3964
+ * - `none` — no site-style card surface; the block's own composition and
3965
+ * the author's own card fields govern the item. This is *not*
3966
+ * a promise of visible boxlessness: a block whose base class
3967
+ * draws a border still draws one. It says the Look is not
3968
+ * asking the site style for a card.
3969
+ * - `open` — boxless but marked (a rule or accent edge, no enclosing box)
3970
+ * - `default` — the site's quiet everyday card
3971
+ * - `alternative` — the statement card carrying the site's personality
3972
+ */
3973
+ const cardRoleValues = [...surfaceCardRoleValues, boxlessCardVariantValue];
4987
3974
  const legacyCardVariantRoleAliases = {
4988
3975
  variant1: "alternative",
4989
- variant2: "alternative"
3976
+ variant2: "alternative",
3977
+ statement: "alternative"
4990
3978
  };
4991
3979
  const cardSpacingSchema = z.enum([
4992
3980
  "none",
@@ -4996,6 +3984,17 @@ const cardSpacingSchema = z.enum([
4996
3984
  "comfortable",
4997
3985
  "spacious"
4998
3986
  ]);
3987
+ /** Per-axis padding, for boxless cards whose inline padding differs from block. */
3988
+ const cardSpacingAxesSchema = z.object({
3989
+ block: cardSpacingSchema,
3990
+ inline: cardSpacingSchema
3991
+ });
3992
+ /**
3993
+ * A card's content padding: one value for both axes, or one per axis. Two
3994
+ * fields would let a variant say both and leave the reader to guess, so this is
3995
+ * a union — the legacy `spacingAxes` key is lifted into it on parse.
3996
+ */
3997
+ const cardSpacingValueSchema = z.union([cardSpacingSchema, cardSpacingAxesSchema]);
4999
3998
  const gradientDirectionSchema = z.enum([
5000
3999
  "to-r",
5001
4000
  "to-l",
@@ -5007,7 +4006,13 @@ const gradientDirectionSchema = z.enum([
5007
4006
  "to-bl"
5008
4007
  ]);
5009
4008
  const cardVariantRoleSchema = z.enum(cardVariantRoleValues);
5010
- const boxStylesCardVariantSchema = z.enum([...cardVariantRoleValues, boxlessCardVariantValue]);
4009
+ const surfaceCardRoleSchema = z.enum(surfaceCardRoleValues);
4010
+ const cardRoleSchema = z.enum(cardRoleValues);
4011
+ /**
4012
+ * Historical name for the role vocabulary as it reaches box styles. Widened to
4013
+ * the full `CardRole` set — old values keep parsing, `open` now parses too.
4014
+ */
4015
+ const boxStylesCardVariantSchema = cardRoleSchema;
5011
4016
  function isCardVariantRole(value) {
5012
4017
  return typeof value === "string" && cardVariantRoleValues.includes(value);
5013
4018
  }
@@ -5016,6 +4021,28 @@ function normalizeCardVariantRole(value) {
5016
4021
  if (typeof value !== "string") return null;
5017
4022
  return legacyCardVariantRoleAliases[value] ?? null;
5018
4023
  }
4024
+ /**
4025
+ * The one untrusted-input boundary for the role vocabulary. Legacy alias values
4026
+ * (`variant1`, `variant2`, `statement`) normalize here and nowhere else.
4027
+ */
4028
+ function normalizeCardRole(value) {
4029
+ if (value === "none") return boxlessCardVariantValue;
4030
+ if (value === "open") return openCardRoleValue;
4031
+ return normalizeCardVariantRole(value);
4032
+ }
4033
+ const PRIORITY_ROLE_INFERENCE = {
4034
+ 1: "default",
4035
+ 2: "alternative"
4036
+ };
4037
+ /**
4038
+ * Role inference for legacy card systems authored before variants carried a
4039
+ * `role`. Priority 1 is the everyday card, priority 2 the statement card —
4040
+ * which is how variants are surfaced today. `open` is never inferred: a site
4041
+ * style has to opt into it.
4042
+ */
4043
+ function inferCardVariantRoleFromPriority(priority) {
4044
+ return PRIORITY_ROLE_INFERENCE[priority] ?? null;
4045
+ }
5019
4046
  const cardBackgroundSchema = z.discriminatedUnion("type", [
5020
4047
  z.object({
5021
4048
  type: z.literal("solid"),
@@ -5041,17 +4068,19 @@ const cardCornerValueSchema = z.enum([
5041
4068
  "pill",
5042
4069
  "expressive"
5043
4070
  ]);
4071
+ const cardEdgeSchema = z.enum([
4072
+ "left",
4073
+ "top",
4074
+ "right",
4075
+ "bottom"
4076
+ ]);
5044
4077
  /**
5045
- * A single accented card edge (e.g. a left accent bar). When set, it replaces
5046
- * the full `border` so the card reads as edge-accented rather than outlined.
4078
+ * Legacy single accented card edge (e.g. a left accent bar). Persisted and
4079
+ * curated data may still carry it; it lifts into a one-element `decorations`
4080
+ * list at the parse boundary and has no representation after that.
5047
4081
  */
5048
4082
  const cardAccentEdgeSchema = z.object({
5049
- edge: z.enum([
5050
- "left",
5051
- "top",
5052
- "right",
5053
- "bottom"
5054
- ]),
4083
+ edge: cardEdgeSchema,
5055
4084
  colorToken: themeColorTokenSchema,
5056
4085
  width: z.enum([
5057
4086
  "thin",
@@ -5060,13 +4089,43 @@ const cardAccentEdgeSchema = z.object({
5060
4089
  "heavy"
5061
4090
  ])
5062
4091
  });
4092
+ /** `hairline` (1px) is the widening the boxless `open` role needs. */
4093
+ const cardEdgeRuleWidthSchema = z.enum([
4094
+ "hairline",
4095
+ "thin",
4096
+ "medium",
4097
+ "thick",
4098
+ "heavy"
4099
+ ]);
4100
+ const cardEdgeRuleLengthSchema = z.enum(["full", "short"]);
4101
+ const cardEdgeRuleAlignSchema = z.enum([
4102
+ "start",
4103
+ "center",
4104
+ "end"
4105
+ ]);
4106
+ /**
4107
+ * Decorations are edge rules today. The alias exists so the list can grow into
4108
+ * a discriminated union without every call site changing.
4109
+ */
4110
+ const cardDecorationSchema = z.object({
4111
+ edge: cardEdgeSchema,
4112
+ colorToken: themeColorTokenSchema,
4113
+ width: cardEdgeRuleWidthSchema,
4114
+ /** Defaults to `full`. */
4115
+ length: cardEdgeRuleLengthSchema.optional(),
4116
+ /** Where a `short` rule sits along its edge. Defaults to `start`. */
4117
+ align: cardEdgeRuleAlignSchema.optional(),
4118
+ /** Opacity applied to `colorToken`, 0–1. Scoped here, not on the token. */
4119
+ alpha: z.number().min(0).max(1).optional()
4120
+ });
4121
+ const cardDecorationsSchema = z.array(cardDecorationSchema).max(2);
5063
4122
  const cardCornerRadiiSchema = z.object({
5064
4123
  topLeft: cardCornerValueSchema.optional(),
5065
4124
  topRight: cardCornerValueSchema.optional(),
5066
4125
  bottomLeft: cardCornerValueSchema.optional(),
5067
4126
  bottomRight: cardCornerValueSchema.optional()
5068
4127
  });
5069
- const cardVariantSchema = z.object({
4128
+ const cardVariantInputSchema = z.object({
5070
4129
  id: z.string(),
5071
4130
  name: z.string().min(1).max(20),
5072
4131
  enabled: z.boolean(),
@@ -5075,8 +4134,10 @@ const cardVariantSchema = z.object({
5075
4134
  z.literal(2),
5076
4135
  z.literal(3)
5077
4136
  ]),
4137
+ role: surfaceCardRoleSchema.optional(),
5078
4138
  background: cardBackgroundSchema,
5079
- spacing: cardSpacingSchema,
4139
+ spacing: cardSpacingValueSchema,
4140
+ spacingAxes: cardSpacingAxesSchema.optional(),
5080
4141
  foregroundToken: themeColorTokenSchema.optional(),
5081
4142
  shadow: z.object({
5082
4143
  elevation: z.enum([
@@ -5100,9 +4161,91 @@ const cardVariantSchema = z.object({
5100
4161
  ]).optional(),
5101
4162
  cornerRadii: cardCornerRadiiSchema.optional(),
5102
4163
  border: cardBorderSchema.optional(),
4164
+ decorations: cardDecorationsSchema.optional(),
5103
4165
  accentEdge: cardAccentEdgeSchema.optional()
5104
4166
  });
5105
- const cardSystemSchema = z.object({ variants: z.array(cardVariantSchema).min(1).max(3) });
4167
+ /**
4168
+ * Lift a legacy `accentEdge` into the decoration list. The old emitter reset
4169
+ * `border: 0` implicitly whenever an accent edge was present; conversion drops
4170
+ * the border instead, so the output is unchanged and the data says so.
4171
+ */
4172
+ function normalizeLegacyAccentEdge(variant) {
4173
+ const { accentEdge, ...rest } = normalizeLegacySpacingAxes(variant);
4174
+ if (!accentEdge) return rest;
4175
+ const { border: _droppedByAccentEdgeReset, ...withoutBorder } = rest;
4176
+ return {
4177
+ ...withoutBorder,
4178
+ decorations: [{
4179
+ ...accentEdge,
4180
+ length: "full"
4181
+ }]
4182
+ };
4183
+ }
4184
+ /**
4185
+ * Lift a legacy `spacingAxes` into `spacing`. It always won over the flat value
4186
+ * when both were set, so the lift preserves the emitted padding exactly.
4187
+ */
4188
+ function normalizeLegacySpacingAxes(variant) {
4189
+ const { spacingAxes, ...rest } = variant;
4190
+ return spacingAxes ? {
4191
+ ...rest,
4192
+ spacing: spacingAxes
4193
+ } : variant;
4194
+ }
4195
+ function validateSingleDecorationSource(variant, ctx) {
4196
+ if (!variant.accentEdge || !variant.decorations) return;
4197
+ ctx.addIssue({
4198
+ code: "custom",
4199
+ path: ["decorations"],
4200
+ message: "A card variant carries either the legacy `accentEdge` or `decorations`, never both."
4201
+ });
4202
+ }
4203
+ const cardVariantSchema = cardVariantInputSchema.superRefine(validateSingleDecorationSource).transform(normalizeLegacyAccentEdge);
4204
+ /**
4205
+ * Fill in roles for legacy systems whose variants declare none. Inference is
4206
+ * collision-tolerant on purpose: first claimant wins and a later variant that
4207
+ * would infer a taken role simply gets no role. Legacy data is not obliged to
4208
+ * be well-formed, and a card system that fails to parse takes the whole theme
4209
+ * down with it.
4210
+ */
4211
+ function withInferredRoles(variants) {
4212
+ const claimed = new Set(variants.flatMap((variant) => variant.role ? [variant.role] : []));
4213
+ return variants.map((variant) => {
4214
+ if (variant.role) return variant;
4215
+ const inferred = inferCardVariantRoleFromPriority(variant.priority);
4216
+ if (!inferred || claimed.has(inferred)) return variant;
4217
+ claimed.add(inferred);
4218
+ return {
4219
+ ...variant,
4220
+ role: inferred
4221
+ };
4222
+ });
4223
+ }
4224
+ /**
4225
+ * Only *declared* roles are validated — a site style saying "these two
4226
+ * variants are both the default card" is an authoring error worth rejecting.
4227
+ */
4228
+ function validateUniqueDeclaredCardVariantRoles(system, ctx) {
4229
+ const declared = /* @__PURE__ */ new Set();
4230
+ system.variants.forEach((variant, index) => {
4231
+ const role = variant.role;
4232
+ if (!role) return;
4233
+ if (declared.has(role)) {
4234
+ ctx.addIssue({
4235
+ code: "custom",
4236
+ path: [
4237
+ "variants",
4238
+ index,
4239
+ "role"
4240
+ ],
4241
+ message: `Card role "${role}" is already implemented by another variant.`
4242
+ });
4243
+ return;
4244
+ }
4245
+ declared.add(role);
4246
+ });
4247
+ }
4248
+ const cardSystemSchema = z.object({ variants: z.array(cardVariantSchema).min(1).max(3) }).superRefine(validateUniqueDeclaredCardVariantRoles).transform((system) => ({ variants: withInferredRoles(system.variants) }));
5106
4249
  //#endregion
5107
4250
  //#region ../theme-core/src/accordions/types.ts
5108
4251
  /**
@@ -5874,7 +5017,6 @@ function defineBlockDesignCapability(capability) {
5874
5017
  sectionHeights: capability.sectionHeights ?? ["default"],
5875
5018
  imageSurfaceTreatments: capability.imageSurfaceTreatments ?? ["none"],
5876
5019
  imageSurfaceMotions: capability.imageSurfaceMotions ?? ["static"],
5877
- testimonialCardTreatments: capability.testimonialCardTreatments ?? ["default"],
5878
5020
  tileTreatments: capability.tileTreatments ?? ["default"],
5879
5021
  eventListTreatments: capability.eventListTreatments ?? ["plain"],
5880
5022
  eyebrowTreatments: capability.eyebrowTreatments ?? ["plain"],
@@ -5994,6 +5136,58 @@ new Set(themeV2NormalEditorRawStyleFieldNames);
5994
5136
  [...themeV2RuntimeStyleFieldNames, ...themeV2BlockSpecificRawStyleFieldNames];
5995
5137
  const pageDesignEditorBackgroundOverrideOwner = "page-design-editor";
5996
5138
  const siteChromeBackgroundOverrideOwner = "site-chrome-editor";
5139
+ //#endregion
5140
+ //#region ../theme-core/src/header/legacyHeaderVariant.ts
5141
+ /**
5142
+ * The header variants the system actually renders.
5143
+ *
5144
+ * Each one has a layout row in the site-header block and a paint target in
5145
+ * `paintTargets.ts`. This is the canonical list: the block transform's variant
5146
+ * class allowlist and the AI theme generator's enum both derive from it, so
5147
+ * they cannot drift.
5148
+ */
5149
+ const headerVariantValues = [
5150
+ "classic",
5151
+ "centered",
5152
+ "floating"
5153
+ ];
5154
+ z.enum(headerVariantValues);
5155
+ /**
5156
+ * Header variant spellings that were once authorable but no longer name a
5157
+ * layout of their own, and the variant they read as now.
5158
+ *
5159
+ * `transparent` was an overlay header with no CSS of its own: everything it
5160
+ * did (transparent root background, overlay content flow) is what `floating`
5161
+ * already does, and it had zero persisted usage in production or locally when
5162
+ * it was retired. It survives here as a one-boundary alias so a theme authored
5163
+ * against the old vocabulary still parses.
5164
+ *
5165
+ * This matters because the theme schema is strict and has no per-field
5166
+ * `.catch()`: an out-of-enum variant fails `themeSchema.safeParse` for the
5167
+ * *whole* theme, which silently swaps the site's theme for
5168
+ * `modernMinimalTheme`. Aliasing here keeps that from happening.
5169
+ */
5170
+ const legacyHeaderVariants = { transparent: "floating" };
5171
+ const legacyHeaderVariantValues = Object.keys(legacyHeaderVariants);
5172
+ /**
5173
+ * The header variant boundary for themes that go through `themeSchema`:
5174
+ * canonical variants pass through, legacy spellings normalize to the variant
5175
+ * they meant, everything else fails the parse.
5176
+ *
5177
+ * Deliberately an enum plus a transform rather than a `z.preprocess`, so the
5178
+ * schema's *input* type stays an accurate union (the legacy spelling is still
5179
+ * accepted on the wire) instead of widening to `unknown`. `SdkThemeWire` in
5180
+ * `@riverbankcms/api` is `z.input<typeof themeSchema>`, so a widened input here
5181
+ * would leak straight into a public type.
5182
+ *
5183
+ * Not every read of a persisted theme goes through the schema:
5184
+ * `resolveRuntimeTheme` in
5185
+ * `apps/dashboard/src/server/services/sites/runtimeSiteResponse.ts` returns the
5186
+ * raw database JSON asserted as `Theme` with no parse, so a theme still
5187
+ * carrying a legacy spelling reaches the theme editor un-aliased. That gap
5188
+ * predates this alias and is harmless while persisted usage is zero.
5189
+ */
5190
+ const headerVariantWithLegacyAliasSchema = z.enum([...headerVariantValues, ...legacyHeaderVariantValues]).transform((value) => value in legacyHeaderVariants ? legacyHeaderVariants[value] : value);
5997
5191
  const BREAKPOINT_LG = 1024;
5998
5192
  const BREAKPOINT_XL = 1280;
5999
5193
  const BREAKPOINT_LG_DOWN = BREAKPOINT_LG - 1;
@@ -6310,14 +5504,7 @@ const cardStylesOverrideSchema = z.object({
6310
5504
  spacing: semanticSpacingSchema.nullable().optional(),
6311
5505
  raised: z.boolean().nullable().optional(),
6312
5506
  rounded: boxRoundedSchema.nullable().optional(),
6313
- treatment: z.enum([
6314
- "accent-quote",
6315
- "editorial-rule",
6316
- "soft-panel",
6317
- "editorial-serif-quote",
6318
- "editorial-open",
6319
- "color-blocked"
6320
- ]).nullable().optional(),
5507
+ role: cardRoleSchema.nullable().optional(),
6321
5508
  cardVariant: boxStylesCardVariantSchema.nullable().optional()
6322
5509
  });
6323
5510
  const blockStyleOverridesSchema = z.object({
@@ -6423,30 +5610,6 @@ const motion = z.object({
6423
5610
  ]).nullable()
6424
5611
  });
6425
5612
  z.object({ shape: corners });
6426
- z.object({
6427
- elevation: z.enum([
6428
- "none",
6429
- "low",
6430
- "medium",
6431
- "high"
6432
- ]),
6433
- border: z.enum([
6434
- "none",
6435
- "subtle",
6436
- "defined"
6437
- ]),
6438
- shape: corners,
6439
- headerStyle: z.enum([
6440
- "plain",
6441
- "accentBar",
6442
- "subtleBg"
6443
- ]).nullable(),
6444
- mediaTreatment: z.enum([
6445
- "square",
6446
- "rounded",
6447
- "bleed"
6448
- ]).nullable()
6449
- });
6450
5613
  const inputStyle = z.object({
6451
5614
  shape: corners,
6452
5615
  border: z.enum([
@@ -6461,12 +5624,6 @@ const inputStyle = z.object({
6461
5624
  ]),
6462
5625
  label: z.enum(["inside", "above"])
6463
5626
  });
6464
- const headerVariant = z.enum([
6465
- "classic",
6466
- "centered",
6467
- "transparent",
6468
- "floating"
6469
- ]);
6470
5627
  const headerPositioning = z.enum([
6471
5628
  "static",
6472
5629
  "sticky",
@@ -6610,7 +5767,7 @@ const headerBackgroundSchema = z.object({
6610
5767
  textColor: tokenOrCssColorValueSchema.nullable().optional()
6611
5768
  });
6612
5769
  const headerSchema = z.object({
6613
- variant: headerVariant,
5770
+ variant: headerVariantWithLegacyAliasSchema,
6614
5771
  positioning: headerPositioning,
6615
5772
  shrinkOnScroll: z.boolean(),
6616
5773
  maxWidth: headerMaxWidth,
@@ -6923,12 +6080,33 @@ function assertValidOptionGroups(preset) {
6923
6080
  defineLookOptionGroup(group);
6924
6081
  });
6925
6082
  }
6083
+ /**
6084
+ * Every Look carries a card role. A Look that says nothing about cards renders
6085
+ * none, which is the overwhelming majority of them; the card-bearing ones name
6086
+ * the role they want and the site style owns how it looks.
6087
+ */
6926
6088
  function defineBlockAppearancePreset(preset) {
6927
6089
  assertValidOptionGroups(preset);
6928
- return preset;
6090
+ return {
6091
+ ...preset,
6092
+ design: {
6093
+ ...preset.design,
6094
+ cardRole: preset.design.cardRole ?? "none"
6095
+ }
6096
+ };
6929
6097
  }
6930
6098
  //#endregion
6931
6099
  //#region ../theme-core/src/site-styles/blockAppearancePresets.ts
6100
+ /**
6101
+ * A Look is a composition: which section surface, which content frame, and —
6102
+ * where it wants one — which *card role* it asks the site style for. It never
6103
+ * states how a card looks; that is the site style's identity.
6104
+ *
6105
+ * A Look with no `cardRole` asks the site style for no card at all
6106
+ * (`defineBlockAppearancePreset` defaults it to `none`) — the block's own
6107
+ * composition still governs how its items look. The per-Look rationale for the card-bearing ones lives
6108
+ * in `.project/plans/1297-card-role-contract-site-styles-own-card-surfaces/mapping-table.md`.
6109
+ */
6932
6110
  const brandScrimOptionGroups = [{
6933
6111
  id: "image-surface-treatment",
6934
6112
  label: "Treatment",
@@ -6966,7 +6144,6 @@ defineBlockAppearancePreset({
6966
6144
  design: {
6967
6145
  sectionSurface: "hero-image",
6968
6146
  contentFrame: plainFrame,
6969
- itemSurface: "none",
6970
6147
  sectionHeight: "hero",
6971
6148
  heroComposition: "center",
6972
6149
  heroTypographyScale: "display",
@@ -7009,7 +6186,6 @@ defineBlockAppearancePreset({
7009
6186
  design: {
7010
6187
  sectionSurface: "hero-image",
7011
6188
  contentFrame: panelFrame("raised"),
7012
- itemSurface: "none",
7013
6189
  sectionHeight: "immersive",
7014
6190
  heroComposition: "bottom-left",
7015
6191
  heroTypographyScale: "display",
@@ -7034,7 +6210,6 @@ defineBlockAppearancePreset({
7034
6210
  design: {
7035
6211
  sectionSurface: "hero-image",
7036
6212
  contentFrame: plainFrame,
7037
- itemSurface: "none",
7038
6213
  sectionHeight: "immersive",
7039
6214
  heroComposition: "center",
7040
6215
  heroTypographyScale: "poster",
@@ -7055,7 +6230,6 @@ defineBlockAppearancePreset({
7055
6230
  design: {
7056
6231
  sectionSurface: "hero-image",
7057
6232
  contentFrame: plainFrame,
7058
- itemSurface: "none",
7059
6233
  sectionHeight: "immersive",
7060
6234
  heroComposition: "center",
7061
6235
  heroTypographyScale: "display",
@@ -7075,7 +6249,6 @@ defineBlockAppearancePreset({
7075
6249
  design: {
7076
6250
  sectionSurface: "hero-image",
7077
6251
  contentFrame: plainFrame,
7078
- itemSurface: "none",
7079
6252
  sectionHeight: "immersive",
7080
6253
  heroComposition: "center",
7081
6254
  heroTypographyScale: "display",
@@ -7095,7 +6268,6 @@ defineBlockAppearancePreset({
7095
6268
  design: {
7096
6269
  sectionSurface: "brand-depth-band",
7097
6270
  contentFrame: plainFrame,
7098
- itemSurface: "none",
7099
6271
  heroComposition: "center",
7100
6272
  heroTypographyScale: "editorial",
7101
6273
  eyebrowTreatment: "accent-pill-bounce"
@@ -7108,7 +6280,6 @@ defineBlockAppearancePreset({
7108
6280
  design: {
7109
6281
  sectionSurface: "muted-band",
7110
6282
  contentFrame: panelFrame("inset"),
7111
- itemSurface: "none",
7112
6283
  heroComposition: "center",
7113
6284
  heroTypographyScale: "editorial"
7114
6285
  }
@@ -7121,7 +6292,6 @@ defineBlockAppearancePreset({
7121
6292
  design: {
7122
6293
  sectionSurface: "base",
7123
6294
  contentFrame: plainFrame,
7124
- itemSurface: "none",
7125
6295
  heroTypographyScale: "editorial"
7126
6296
  }
7127
6297
  }), defineBlockAppearancePreset({
@@ -7133,7 +6303,6 @@ defineBlockAppearancePreset({
7133
6303
  design: {
7134
6304
  sectionSurface: "brand-depth-band",
7135
6305
  contentFrame: plainFrame,
7136
- itemSurface: "none",
7137
6306
  heroTypographyScale: "display",
7138
6307
  eyebrowTreatment: "accent-pill-bounce"
7139
6308
  }
@@ -7146,7 +6315,6 @@ defineBlockAppearancePreset({
7146
6315
  design: {
7147
6316
  sectionSurface: "muted-band",
7148
6317
  contentFrame: panelFrame("raised"),
7149
- itemSurface: "none",
7150
6318
  heroTypographyScale: "editorial"
7151
6319
  }
7152
6320
  }), defineBlockAppearancePreset({
@@ -7158,7 +6326,6 @@ defineBlockAppearancePreset({
7158
6326
  design: {
7159
6327
  sectionSurface: "accent-band",
7160
6328
  contentFrame: panelFrame("raised"),
7161
- itemSurface: "none",
7162
6329
  heroTypographyScale: "display"
7163
6330
  }
7164
6331
  }), defineBlockAppearancePreset({
@@ -7170,7 +6337,6 @@ defineBlockAppearancePreset({
7170
6337
  design: {
7171
6338
  sectionSurface: "base",
7172
6339
  contentFrame: plainFrame,
7173
- itemSurface: "none",
7174
6340
  composition: {
7175
6341
  kind: "intro",
7176
6342
  treatment: "editorial-statement"
@@ -7185,7 +6351,6 @@ defineBlockAppearancePreset({
7185
6351
  design: {
7186
6352
  sectionSurface: "base",
7187
6353
  contentFrame: plainFrame,
7188
- itemSurface: "none",
7189
6354
  composition: {
7190
6355
  kind: "intro",
7191
6356
  treatment: "portrait-bio"
@@ -7199,7 +6364,7 @@ defineBlockAppearancePreset({
7199
6364
  design: {
7200
6365
  sectionSurface: "base",
7201
6366
  contentFrame: plainFrame,
7202
- itemSurface: "default"
6367
+ cardRole: "default"
7203
6368
  }
7204
6369
  }), defineBlockAppearancePreset({
7205
6370
  id: "offerings-preview-secondary-cards",
@@ -7209,7 +6374,7 @@ defineBlockAppearancePreset({
7209
6374
  design: {
7210
6375
  sectionSurface: "muted-band",
7211
6376
  contentFrame: plainFrame,
7212
- itemSurface: "inset"
6377
+ cardRole: "alternative"
7213
6378
  }
7214
6379
  }), defineBlockAppearancePreset({
7215
6380
  id: "offerings-preview-non-carded",
@@ -7219,7 +6384,7 @@ defineBlockAppearancePreset({
7219
6384
  design: {
7220
6385
  sectionSurface: "muted-band",
7221
6386
  contentFrame: plainFrame,
7222
- itemSurface: "editorial"
6387
+ cardRole: "open"
7223
6388
  }
7224
6389
  }), defineBlockAppearancePreset({
7225
6390
  id: "offerings-preview-paired-feature-cards",
@@ -7229,8 +6394,7 @@ defineBlockAppearancePreset({
7229
6394
  constraints: { layoutVariantKeys: ["cards"] },
7230
6395
  design: {
7231
6396
  sectionSurface: "base",
7232
- contentFrame: plainFrame,
7233
- itemSurface: "none"
6397
+ contentFrame: plainFrame
7234
6398
  }
7235
6399
  }), defineBlockAppearancePreset({
7236
6400
  id: "offerings-preview-open-editorial-columns",
@@ -7240,8 +6404,7 @@ defineBlockAppearancePreset({
7240
6404
  constraints: { layoutVariantKeys: ["cards"] },
7241
6405
  design: {
7242
6406
  sectionSurface: "base",
7243
- contentFrame: plainFrame,
7244
- itemSurface: "none"
6407
+ contentFrame: plainFrame
7245
6408
  }
7246
6409
  }), defineBlockAppearancePreset({
7247
6410
  id: "offerings-preview-joined-programme-panel",
@@ -7251,8 +6414,7 @@ defineBlockAppearancePreset({
7251
6414
  constraints: { layoutVariantKeys: ["cards"] },
7252
6415
  design: {
7253
6416
  sectionSurface: "base",
7254
- contentFrame: plainFrame,
7255
- itemSurface: "none"
6417
+ contentFrame: plainFrame
7256
6418
  }
7257
6419
  }), defineBlockAppearancePreset({
7258
6420
  id: "feature-cards-raised-rule",
@@ -7262,7 +6424,7 @@ defineBlockAppearancePreset({
7262
6424
  design: {
7263
6425
  sectionSurface: "base",
7264
6426
  contentFrame: plainFrame,
7265
- itemSurface: "raised"
6427
+ cardRole: "default"
7266
6428
  }
7267
6429
  }), defineBlockAppearancePreset({
7268
6430
  id: "feature-cards-bold-colors",
@@ -7272,7 +6434,7 @@ defineBlockAppearancePreset({
7272
6434
  design: {
7273
6435
  sectionSurface: "base",
7274
6436
  contentFrame: plainFrame,
7275
- itemSurface: "color-blocked"
6437
+ cardRole: "alternative"
7276
6438
  }
7277
6439
  }), defineBlockAppearancePreset({
7278
6440
  id: "feature-cards-editorial-columns",
@@ -7280,9 +6442,9 @@ defineBlockAppearancePreset({
7280
6442
  label: "Editorial open columns",
7281
6443
  blockKinds: ["block.feature-cards"],
7282
6444
  design: {
7283
- sectionSurface: "base",
6445
+ sectionSurface: "muted-band",
7284
6446
  contentFrame: plainFrame,
7285
- itemSurface: "editorial"
6447
+ cardRole: "open"
7286
6448
  }
7287
6449
  }), defineBlockAppearancePreset({
7288
6450
  id: "feature-cards-asymmetric-emphasis",
@@ -7293,7 +6455,6 @@ defineBlockAppearancePreset({
7293
6455
  design: {
7294
6456
  sectionSurface: "base",
7295
6457
  contentFrame: plainFrame,
7296
- itemSurface: "none",
7297
6458
  composition: {
7298
6459
  kind: "feature-cards",
7299
6460
  treatment: "asymmetric-emphasis"
@@ -7308,7 +6469,7 @@ defineBlockAppearancePreset({
7308
6469
  design: {
7309
6470
  sectionSurface: "brand-depth-band",
7310
6471
  contentFrame: plainFrame,
7311
- itemSurface: "inset",
6472
+ cardRole: "alternative",
7312
6473
  composition: {
7313
6474
  kind: "feature-cards",
7314
6475
  treatment: "framed-programme"
@@ -7322,7 +6483,7 @@ defineBlockAppearancePreset({
7322
6483
  design: {
7323
6484
  sectionSurface: "base",
7324
6485
  contentFrame: plainFrame,
7325
- itemSurface: "inset"
6486
+ cardRole: "alternative"
7326
6487
  }
7327
6488
  }), defineBlockAppearancePreset({
7328
6489
  id: "feature-cards-editorial-diptych",
@@ -7333,7 +6494,7 @@ defineBlockAppearancePreset({
7333
6494
  design: {
7334
6495
  sectionSurface: "base",
7335
6496
  contentFrame: plainFrame,
7336
- itemSurface: "flat"
6497
+ cardRole: "default"
7337
6498
  }
7338
6499
  }), defineBlockAppearancePreset({
7339
6500
  id: "feature-cards-editorial-pathways",
@@ -7344,7 +6505,7 @@ defineBlockAppearancePreset({
7344
6505
  design: {
7345
6506
  sectionSurface: "base",
7346
6507
  contentFrame: plainFrame,
7347
- itemSurface: "flat"
6508
+ cardRole: "default"
7348
6509
  }
7349
6510
  }), defineBlockAppearancePreset({
7350
6511
  id: "feature-cards-photo-tiles",
@@ -7354,7 +6515,7 @@ defineBlockAppearancePreset({
7354
6515
  design: {
7355
6516
  sectionSurface: "base",
7356
6517
  contentFrame: plainFrame,
7357
- itemSurface: "raised"
6518
+ cardRole: "default"
7358
6519
  }
7359
6520
  }), defineBlockAppearancePreset({
7360
6521
  id: "events-lined-panel",
@@ -7363,8 +6524,7 @@ defineBlockAppearancePreset({
7363
6524
  blockKinds: ["block.event-calendar", "block.event-listing"],
7364
6525
  design: {
7365
6526
  sectionSurface: "base",
7366
- contentFrame: panelFrame("raised"),
7367
- itemSurface: "none"
6527
+ contentFrame: panelFrame("raised")
7368
6528
  }
7369
6529
  }), defineBlockAppearancePreset({
7370
6530
  id: "events-ruled-register",
@@ -7374,7 +6534,6 @@ defineBlockAppearancePreset({
7374
6534
  design: {
7375
6535
  sectionSurface: "brand-depth-band",
7376
6536
  contentFrame: plainFrame,
7377
- itemSurface: "none",
7378
6537
  eventListTreatment: "ruled-register"
7379
6538
  }
7380
6539
  }), defineBlockAppearancePreset({
@@ -7385,7 +6544,6 @@ defineBlockAppearancePreset({
7385
6544
  design: {
7386
6545
  sectionSurface: "base",
7387
6546
  contentFrame: plainFrame,
7388
- itemSurface: "none",
7389
6547
  eventListTreatment: "editorial-register"
7390
6548
  }
7391
6549
  }), defineBlockAppearancePreset({
@@ -7396,7 +6554,6 @@ defineBlockAppearancePreset({
7396
6554
  design: {
7397
6555
  sectionSurface: "accent-band",
7398
6556
  contentFrame: plainFrame,
7399
- itemSurface: "none",
7400
6557
  eventListTreatment: "dense-index"
7401
6558
  }
7402
6559
  }), defineBlockAppearancePreset({
@@ -7407,7 +6564,6 @@ defineBlockAppearancePreset({
7407
6564
  design: {
7408
6565
  sectionSurface: "brand-depth-band",
7409
6566
  contentFrame: plainFrame,
7410
- itemSurface: "none",
7411
6567
  tileTreatment: "brand-depth"
7412
6568
  }
7413
6569
  }), defineBlockAppearancePreset({
@@ -7417,8 +6573,7 @@ defineBlockAppearancePreset({
7417
6573
  blockKinds: ["block.media-text"],
7418
6574
  design: {
7419
6575
  sectionSurface: "muted-band",
7420
- contentFrame: flushPanelFrame({ bleed: "start" }),
7421
- itemSurface: "none"
6576
+ contentFrame: flushPanelFrame({ bleed: "start" })
7422
6577
  }
7423
6578
  }), defineBlockAppearancePreset({
7424
6579
  id: "testimonials-simple-cards",
@@ -7428,7 +6583,7 @@ defineBlockAppearancePreset({
7428
6583
  design: {
7429
6584
  sectionSurface: "base",
7430
6585
  contentFrame: plainFrame,
7431
- itemSurface: "default"
6586
+ cardRole: "default"
7432
6587
  }
7433
6588
  }), defineBlockAppearancePreset({
7434
6589
  id: "testimonials-raised-panel",
@@ -7438,7 +6593,7 @@ defineBlockAppearancePreset({
7438
6593
  design: {
7439
6594
  sectionSurface: "muted-band",
7440
6595
  contentFrame: panelFrame("raised"),
7441
- itemSurface: "raised"
6596
+ cardRole: "default"
7442
6597
  }
7443
6598
  }), defineBlockAppearancePreset({
7444
6599
  id: "testimonials-accent-panel",
@@ -7448,7 +6603,7 @@ defineBlockAppearancePreset({
7448
6603
  design: {
7449
6604
  sectionSurface: "accent-band",
7450
6605
  contentFrame: panelFrame("raised"),
7451
- itemSurface: "raised"
6606
+ cardRole: "default"
7452
6607
  }
7453
6608
  }), defineBlockAppearancePreset({
7454
6609
  id: "testimonials-default-cards",
@@ -7458,8 +6613,7 @@ defineBlockAppearancePreset({
7458
6613
  design: {
7459
6614
  sectionSurface: "base",
7460
6615
  contentFrame: plainFrame,
7461
- itemSurface: "none",
7462
- testimonialCardTreatment: "default"
6616
+ cardRole: "default"
7463
6617
  }
7464
6618
  }), defineBlockAppearancePreset({
7465
6619
  id: "testimonials-statement-cards",
@@ -7469,8 +6623,7 @@ defineBlockAppearancePreset({
7469
6623
  design: {
7470
6624
  sectionSurface: "accent-band",
7471
6625
  contentFrame: plainFrame,
7472
- itemSurface: "raised",
7473
- testimonialCardTreatment: "statement"
6626
+ cardRole: "alternative"
7474
6627
  }
7475
6628
  }), defineBlockAppearancePreset({
7476
6629
  id: "testimonials-brand-statement-cards",
@@ -7480,8 +6633,7 @@ defineBlockAppearancePreset({
7480
6633
  design: {
7481
6634
  sectionSurface: "brand-depth-band",
7482
6635
  contentFrame: plainFrame,
7483
- itemSurface: "raised",
7484
- testimonialCardTreatment: "statement"
6636
+ cardRole: "alternative"
7485
6637
  }
7486
6638
  }), defineBlockAppearancePreset({
7487
6639
  id: "testimonials-non-carded",
@@ -7491,8 +6643,10 @@ defineBlockAppearancePreset({
7491
6643
  design: {
7492
6644
  sectionSurface: "muted-band",
7493
6645
  contentFrame: plainFrame,
7494
- itemSurface: "none",
7495
- testimonialCardTreatment: "non-carded"
6646
+ composition: {
6647
+ kind: "testimonials",
6648
+ treatment: "open-editorial"
6649
+ }
7496
6650
  }
7497
6651
  }), defineBlockAppearancePreset({
7498
6652
  id: "testimonials-evergreen-lead",
@@ -7502,8 +6656,7 @@ defineBlockAppearancePreset({
7502
6656
  constraints: { layoutVariantKeys: ["featured-editorial"] },
7503
6657
  design: {
7504
6658
  sectionSurface: "base",
7505
- contentFrame: plainFrame,
7506
- itemSurface: "none"
6659
+ contentFrame: plainFrame
7507
6660
  }
7508
6661
  }), defineBlockAppearancePreset({
7509
6662
  id: "testimonials-room-and-response",
@@ -7513,8 +6666,7 @@ defineBlockAppearancePreset({
7513
6666
  constraints: { layoutVariantKeys: ["featured-editorial"] },
7514
6667
  design: {
7515
6668
  sectionSurface: "base",
7516
- contentFrame: plainFrame,
7517
- itemSurface: "none"
6669
+ contentFrame: plainFrame
7518
6670
  }
7519
6671
  }), defineBlockAppearancePreset({
7520
6672
  id: "testimonials-open-floor",
@@ -7524,8 +6676,7 @@ defineBlockAppearancePreset({
7524
6676
  constraints: { layoutVariantKeys: ["featured-editorial"] },
7525
6677
  design: {
7526
6678
  sectionSurface: "base",
7527
- contentFrame: plainFrame,
7528
- itemSurface: "none"
6679
+ contentFrame: plainFrame
7529
6680
  }
7530
6681
  }), defineBlockAppearancePreset({
7531
6682
  id: "faq-base-accordion",
@@ -7535,7 +6686,7 @@ defineBlockAppearancePreset({
7535
6686
  design: {
7536
6687
  sectionSurface: "base",
7537
6688
  contentFrame: plainFrame,
7538
- itemSurface: "default"
6689
+ cardRole: "default"
7539
6690
  }
7540
6691
  }), defineBlockAppearancePreset({
7541
6692
  id: "faq-contained-help",
@@ -7545,7 +6696,7 @@ defineBlockAppearancePreset({
7545
6696
  design: {
7546
6697
  sectionSurface: "muted-band",
7547
6698
  contentFrame: panelFrame("inset"),
7548
- itemSurface: "default"
6699
+ cardRole: "default"
7549
6700
  }
7550
6701
  }), defineBlockAppearancePreset({
7551
6702
  id: "contact-form-panel",
@@ -7554,8 +6705,16 @@ defineBlockAppearancePreset({
7554
6705
  blockKinds: ["block.form"],
7555
6706
  design: {
7556
6707
  sectionSurface: "muted-band",
7557
- contentFrame: panelFrame("raised"),
7558
- itemSurface: "none"
6708
+ contentFrame: panelFrame("raised")
6709
+ }
6710
+ }), defineBlockAppearancePreset({
6711
+ id: "booking-brand-band",
6712
+ target: "contact-form",
6713
+ label: "Brand band booking",
6714
+ blockKinds: ["block.appointment-booking"],
6715
+ design: {
6716
+ sectionSurface: "brand-depth-band",
6717
+ contentFrame: plainFrame
7559
6718
  }
7560
6719
  }), defineBlockAppearancePreset({
7561
6720
  id: "cta-accent-band",
@@ -7565,7 +6724,6 @@ defineBlockAppearancePreset({
7565
6724
  design: {
7566
6725
  sectionSurface: "accent-band",
7567
6726
  contentFrame: plainFrame,
7568
- itemSurface: "none",
7569
6727
  eyebrowTreatment: "accent"
7570
6728
  }
7571
6729
  });
@@ -7630,6 +6788,49 @@ function uniqueStrings(values) {
7630
6788
  return Array.from(new Set(values));
7631
6789
  }
7632
6790
  //#endregion
6791
+ //#region ../theme-core/src/site-styles/cardRoleVocabulary.ts
6792
+ /**
6793
+ * The legacy `itemSurface` treatment vocabulary, and how it reads as a card
6794
+ * role.
6795
+ *
6796
+ * `itemSurface` named a *treatment* ("raised", "inset"); a role names *which
6797
+ * card* a Look wants and defers the appearance to the site style. Phase 3
6798
+ * deleted the treatment vocabulary and the recipe table it fed, so this map is
6799
+ * no longer a migration coexistence device — it is the one parse boundary where
6800
+ * persisted design plans written before the cutover still load, normalizing to
6801
+ * the role they meant.
6802
+ *
6803
+ * Per-value rationale is recorded in
6804
+ * `.project/plans/1297-card-role-contract-site-styles-own-card-surfaces/mapping-table.md`.
6805
+ */
6806
+ const legacyItemSurfaceCardRoles = {
6807
+ none: "none",
6808
+ flat: "default",
6809
+ default: "default",
6810
+ outlined: "default",
6811
+ raised: "default",
6812
+ inset: "alternative",
6813
+ editorial: "open",
6814
+ "color-blocked": "alternative"
6815
+ };
6816
+ Object.keys(legacyItemSurfaceCardRoles);
6817
+ /**
6818
+ * Read a card role from untrusted input, accepting the legacy `itemSurface`
6819
+ * vocabulary as aliases. Returns `null` for anything else.
6820
+ */
6821
+ function cardRoleFromLegacyVocabulary(value) {
6822
+ const role = normalizeCardRole(value);
6823
+ if (role) return role;
6824
+ if (typeof value !== "string") return null;
6825
+ return legacyItemSurfaceCardRoles[value] ?? null;
6826
+ }
6827
+ /**
6828
+ * The parse boundary for card roles reaching design intents and persisted
6829
+ * design plans: roles pass through, legacy `itemSurface` values normalize to
6830
+ * the role they meant, everything else fails the parse.
6831
+ */
6832
+ const cardRoleWithLegacyAliasSchema = z.preprocess((value) => cardRoleFromLegacyVocabulary(value) ?? value, cardRoleSchema);
6833
+ //#endregion
7633
6834
  //#region ../theme-core/src/site-styles/sectionTransitions.ts
7634
6835
  function boundaryRuntimeMetrics(family, size, heightExpression) {
7635
6836
  return {
@@ -8040,14 +7241,15 @@ const softEarthAccordionSystem = {
8040
7241
  /**
8041
7242
  * Reusable card systems for curated site styles.
8042
7243
  *
8043
- * generateCardCss emits a `.card-{id}` class per enabled variant. The
8044
- * intended convention (block-level role selection is wired in a follow-up) is
8045
- * a role pair:
7244
+ * generateCardCss emits a `.card-{id}` class per enabled variant, plus stable
7245
+ * `.card-role-{role}` aliases resolved through the fallback chain. Each variant
7246
+ * declares which role it implements:
8046
7247
  * - `default` — the quiet, everyday card (most blocks, most of the time)
8047
7248
  * - `alternative` — the prominent "statement" card for sections that pop
8048
- * A card-heavy site style may add a third; the schema allows up to three
8049
- * variants. The planned fallback when a block references a missing variant is
8050
- * `alternative`, then `default`.
7249
+ * - `open` — boxless but marked; falls back to the generated baseline
7250
+ * The schema allows three variants, one per role. A block asking for a role a
7251
+ * site style does not define falls back per `resolveCardRole`: `alternative` →
7252
+ * `default` → generated baseline.
8051
7253
  *
8052
7254
  * Keep `default` close to the generated baseline so shared consumers (event
8053
7255
  * cards, testimonials) stay stable; put the personality in `alternative`.
@@ -8063,6 +7265,7 @@ const southWestCardSystem = { variants: [{
8063
7265
  name: "Default",
8064
7266
  enabled: true,
8065
7267
  priority: 1,
7268
+ role: "default",
8066
7269
  background: {
8067
7270
  type: "solid",
8068
7271
  colorToken: "surface"
@@ -8080,6 +7283,7 @@ const southWestCardSystem = { variants: [{
8080
7283
  name: "Statement",
8081
7284
  enabled: true,
8082
7285
  priority: 2,
7286
+ role: "alternative",
8083
7287
  background: {
8084
7288
  type: "solid",
8085
7289
  colorToken: "primary-700"
@@ -8091,11 +7295,12 @@ const southWestCardSystem = { variants: [{
8091
7295
  softness: null,
8092
7296
  position: "bottom"
8093
7297
  },
8094
- accentEdge: {
7298
+ decorations: [{
8095
7299
  edge: "left",
8096
7300
  colorToken: "secondary",
8097
- width: "heavy"
8098
- },
7301
+ width: "heavy",
7302
+ length: "full"
7303
+ }],
8099
7304
  cornerRadii: {
8100
7305
  topLeft: "square",
8101
7306
  topRight: "expressive",
@@ -8108,6 +7313,7 @@ const clarityZenCardSystem = { variants: [{
8108
7313
  name: "Default",
8109
7314
  enabled: true,
8110
7315
  priority: 1,
7316
+ role: "default",
8111
7317
  background: {
8112
7318
  type: "solid",
8113
7319
  colorToken: "surface"
@@ -8125,6 +7331,7 @@ const clarityZenCardSystem = { variants: [{
8125
7331
  name: "Statement",
8126
7332
  enabled: true,
8127
7333
  priority: 2,
7334
+ role: "alternative",
8128
7335
  background: {
8129
7336
  type: "solid",
8130
7337
  colorToken: "surfaceAlt"
@@ -8139,6 +7346,117 @@ const clarityZenCardSystem = { variants: [{
8139
7346
  }
8140
7347
  }] };
8141
7348
  /**
7349
+ * Grounded Practice: the first site style to own the `open` role.
7350
+ *
7351
+ * `default` and `alternative` restate the generated baseline this style's token
7352
+ * recipes already produce (soft corners, flat surface card, tinted statement
7353
+ * card, hairline border) so nothing that renders today moves — declaring a card
7354
+ * system means the `.card-{id}` classes must keep existing for event and
7355
+ * offering cards.
7356
+ *
7357
+ * `open` is the change, and it is the one place this style deliberately
7358
+ * diverges from `boxlessOpenCardVariant` (the generated baseline's
7359
+ * hairline-plus-short-accent marking). Grounded Practice takes Luna's
7360
+ * therapy-page card literally
7361
+ * (`apps/dashboard/scripts/design-bakeoff/results/studies/anna-raven-yoga-20260713-115605Z/revisions/005/index.html`,
7362
+ * `.fit__card`: `padding: 1.6rem 1.45rem 1.75rem; border-top: 2px solid
7363
+ * var(--ochre); background: rgba(242,243,235,.72)`):
7364
+ *
7365
+ * - one **full-length 2px** rule in the style's ochre `accent` (`#c69a3c` —
7366
+ * the mockup's `--ochre`); `width: 'thin'` is the 2px step in
7367
+ * `CARD_EDGE_RULE_WIDTH_MAP`. No hairline underneath and no short marker:
7368
+ * the single rule *is* the marking.
7369
+ * - a light solid fill. Card backgrounds take no alpha, so the token that
7370
+ * reads like the mockup's translucent pale tint is `surfaceAlt`
7371
+ * (`#f2ecdb`), which sits one step lighter than the `muted` band the
7372
+ * Look now paints — the same lift Luna gets from `rgba(242,243,235,.72)`
7373
+ * over `--ground-2`.
7374
+ * - comfortable spacing on both axes. The baseline keeps `inline: 'none'`
7375
+ * so a boxless card stays flush with the section; a filled card needs its
7376
+ * padding back or the text touches the fill's edge.
7377
+ *
7378
+ * The baseline `boxlessOpenCardVariant` is unchanged — this divergence is
7379
+ * grounded-practice's alone. See
7380
+ * `.project/plans/1297-card-role-contract-site-styles-own-card-surfaces/decisions.md`
7381
+ * §0.7 and "Phase 2.4".
7382
+ */
7383
+ const groundedPracticeCardSystem = { variants: [
7384
+ {
7385
+ id: "default",
7386
+ name: "Default",
7387
+ enabled: true,
7388
+ priority: 1,
7389
+ role: "default",
7390
+ background: {
7391
+ type: "solid",
7392
+ colorToken: "surface"
7393
+ },
7394
+ foregroundToken: "text",
7395
+ spacing: "comfortable",
7396
+ corners: "soft",
7397
+ shadow: {
7398
+ elevation: "none",
7399
+ softness: null,
7400
+ position: "bottom"
7401
+ },
7402
+ border: {
7403
+ widthClass: "border",
7404
+ colorToken: "border"
7405
+ }
7406
+ },
7407
+ {
7408
+ id: "alternative",
7409
+ name: "Statement",
7410
+ enabled: true,
7411
+ priority: 2,
7412
+ role: "alternative",
7413
+ background: {
7414
+ type: "solid",
7415
+ colorToken: "surfaceAlt"
7416
+ },
7417
+ foregroundToken: "text",
7418
+ spacing: "comfortable",
7419
+ corners: "soft",
7420
+ shadow: {
7421
+ elevation: "low",
7422
+ softness: null,
7423
+ position: "bottom"
7424
+ },
7425
+ border: {
7426
+ widthClass: "border",
7427
+ colorToken: "border"
7428
+ }
7429
+ },
7430
+ {
7431
+ id: "open",
7432
+ name: "Open",
7433
+ enabled: true,
7434
+ priority: 3,
7435
+ role: "open",
7436
+ background: {
7437
+ type: "solid",
7438
+ colorToken: "surfaceAlt"
7439
+ },
7440
+ foregroundToken: "text",
7441
+ spacing: {
7442
+ block: "comfortable",
7443
+ inline: "comfortable"
7444
+ },
7445
+ corners: "square",
7446
+ shadow: {
7447
+ elevation: "none",
7448
+ softness: null,
7449
+ position: "bottom"
7450
+ },
7451
+ decorations: [{
7452
+ edge: "top",
7453
+ colorToken: "accent",
7454
+ width: "thin",
7455
+ length: "full"
7456
+ }]
7457
+ }
7458
+ ] };
7459
+ /**
8142
7460
  * Original Joy: warm, flat, generously rounded cards on the dark clay ground.
8143
7461
  * `default` is a quiet brown surface card with cream text; `alternative` is a
8144
7462
  * burnt-orange statement card for sections that should pop. Both flat (the
@@ -8150,6 +7468,7 @@ const originalJoyCardSystem = { variants: [{
8150
7468
  name: "Default",
8151
7469
  enabled: true,
8152
7470
  priority: 1,
7471
+ role: "default",
8153
7472
  background: {
8154
7473
  type: "solid",
8155
7474
  colorToken: "surface"
@@ -8167,6 +7486,7 @@ const originalJoyCardSystem = { variants: [{
8167
7486
  name: "Statement",
8168
7487
  enabled: true,
8169
7488
  priority: 2,
7489
+ role: "alternative",
8170
7490
  background: {
8171
7491
  type: "solid",
8172
7492
  colorToken: "primary"
@@ -8780,16 +8100,7 @@ const generatedDesignOptionCatalog = {
8780
8100
  "hero-image"
8781
8101
  ],
8782
8102
  contentFrames: generatedContentFrames,
8783
- itemSurfaces: [
8784
- "none",
8785
- "default",
8786
- "flat",
8787
- "outlined",
8788
- "raised",
8789
- "inset",
8790
- "editorial",
8791
- "color-blocked"
8792
- ],
8103
+ cardRoles: cardRoleValues,
8793
8104
  transitions: [
8794
8105
  "none",
8795
8106
  "soft-fade-short",
@@ -8806,7 +8117,7 @@ const userDesignOptionCatalog = {
8806
8117
  source: "user",
8807
8118
  sectionSurfaces: generatedDesignOptionCatalog.sectionSurfaces,
8808
8119
  contentFrames: userContentFrames,
8809
- itemSurfaces: generatedDesignOptionCatalog.itemSurfaces,
8120
+ cardRoles: generatedDesignOptionCatalog.cardRoles,
8810
8121
  transitions: [
8811
8122
  ...generatedDesignOptionCatalog.transitions,
8812
8123
  "soft-fade-expansive",
@@ -8822,7 +8133,7 @@ const userDesignOptionCatalog = {
8822
8133
  emphases: generatedDesignOptionCatalog.emphases,
8823
8134
  detachedCustom: false
8824
8135
  };
8825
- userDesignOptionCatalog.sectionSurfaces, userDesignOptionCatalog.contentFrames, userDesignOptionCatalog.itemSurfaces, userDesignOptionCatalog.transitions, userDesignOptionCatalog.emphases;
8136
+ userDesignOptionCatalog.sectionSurfaces, userDesignOptionCatalog.contentFrames, userDesignOptionCatalog.cardRoles, userDesignOptionCatalog.transitions, userDesignOptionCatalog.emphases;
8826
8137
  //#endregion
8827
8138
  //#region ../theme-core/src/site-styles/siteStyleTypography.ts
8828
8139
  const modernSansTypography = {
@@ -9277,6 +8588,8 @@ function defaultTypographyForRecipe(recipe) {
9277
8588
  case "classic-serif": return classicSerifTypography;
9278
8589
  }
9279
8590
  }
8591
+ //#endregion
8592
+ //#region ../theme-core/src/site-styles/designState.ts
9280
8593
  const designResolutionPolicySchema = z.enum([
9281
8594
  "generated",
9282
8595
  "user",
@@ -9285,108 +8598,6 @@ const designResolutionPolicySchema = z.enum([
9285
8598
  ]);
9286
8599
  const runtimeStyleFieldNameSchema = z.enum(themeV2RuntimeStyleFieldNames);
9287
8600
  const nonEmptyRuntimeStyleFieldNamesSchema = z.array(runtimeStyleFieldNameSchema).min(1).transform((fields) => [fields[0], ...fields.slice(1)]);
9288
- const heroLegibilityStrategySchema = z.enum([
9289
- "none",
9290
- "scrim-gradient",
9291
- "solid-panel"
9292
- ]);
9293
- const heroCompositionIntentSchema = z.enum(["center", "bottom-left"]);
9294
- const heroTypographyScaleIntentSchema = z.enum([
9295
- "quiet",
9296
- "editorial",
9297
- "display",
9298
- "poster"
9299
- ]);
9300
- const sectionHeightIntentSchema = z.enum([
9301
- "default",
9302
- "banner",
9303
- "hero",
9304
- "immersive"
9305
- ]);
9306
- const imageSurfaceTreatmentIntensitySchema = z.enum([
9307
- "soft",
9308
- "balanced",
9309
- "strong"
9310
- ]);
9311
- const imageSurfaceMotionSchema = z.enum(["static", "fixed-frame"]);
9312
- const imageSurfaceTreatmentSchema = z.discriminatedUnion("kind", [
9313
- z.object({ kind: z.literal("none") }).strict(),
9314
- z.object({
9315
- kind: z.literal("brand-scrim"),
9316
- token: z.enum([
9317
- "primary",
9318
- "secondary",
9319
- "accent"
9320
- ]),
9321
- intensity: imageSurfaceTreatmentIntensitySchema.optional()
9322
- }).strict(),
9323
- z.object({
9324
- kind: z.literal("brand-wash"),
9325
- token: z.enum([
9326
- "primary",
9327
- "secondary",
9328
- "accent"
9329
- ]),
9330
- intensity: imageSurfaceTreatmentIntensitySchema.optional()
9331
- }).strict(),
9332
- z.object({
9333
- kind: z.literal("neutral-scrim"),
9334
- intensity: imageSurfaceTreatmentIntensitySchema.optional()
9335
- }).strict(),
9336
- z.object({
9337
- kind: z.literal("neutral-wash"),
9338
- intensity: imageSurfaceTreatmentIntensitySchema.optional()
9339
- }).strict(),
9340
- z.object({
9341
- kind: z.literal("solid-panel"),
9342
- intensity: imageSurfaceTreatmentIntensitySchema.optional()
9343
- }).strict()
9344
- ]);
9345
- const testimonialCardTreatmentSchema = z.enum(["default", "accent-quote"]);
9346
- const tileTreatmentSchema = z.enum(tileTreatmentValues);
9347
- const eventListTreatmentSchema = z.enum(eventListTreatmentValues);
9348
- const eyebrowTreatmentSchema = z.enum(eyebrowTreatmentValues);
9349
- function uniqueNonEmpty$1(values) {
9350
- const uniqueValues = [...new Set(values)];
9351
- const firstValue = uniqueValues[0];
9352
- if (!firstValue) throw new Error("Expected at least one Theme V2 design state option.");
9353
- return [firstValue, ...uniqueValues.slice(1)];
9354
- }
9355
- const userPanelTreatments = uniqueNonEmpty$1(userDesignOptionCatalog.contentFrames.filter((frame) => frame.kind === "panel").map((frame) => frame.treatment));
9356
- const userFlushTreatments = uniqueNonEmpty$1(userDesignOptionCatalog.contentFrames.filter((frame) => frame.kind === "flush-panel").map((frame) => frame.treatment));
9357
- const userFlushBleeds = uniqueNonEmpty$1(userDesignOptionCatalog.contentFrames.filter((frame) => frame.kind === "flush-panel").map((frame) => frame.bleed));
9358
- const contentFrameIntentSchema = z.discriminatedUnion("kind", [
9359
- z.object({ kind: z.literal("plain") }).strict(),
9360
- z.object({
9361
- kind: z.literal("panel"),
9362
- treatment: z.enum(userPanelTreatments)
9363
- }).strict(),
9364
- z.object({
9365
- kind: z.literal("flush-panel"),
9366
- treatment: z.enum(userFlushTreatments),
9367
- bleed: z.enum(userFlushBleeds)
9368
- }).strict()
9369
- ]);
9370
- const blockDesignPlanSchema = z.object({
9371
- blockId: z.string().min(1).transform(asDesignBlockId),
9372
- blockKind: z.string().min(1),
9373
- purpose: z.string().min(1),
9374
- sectionSurface: z.enum(userDesignOptionCatalog.sectionSurfaces),
9375
- contentFrame: contentFrameIntentSchema,
9376
- itemSurface: z.enum(userDesignOptionCatalog.itemSurfaces),
9377
- transitionAfter: z.enum(userDesignOptionCatalog.transitions),
9378
- emphasis: z.enum(userDesignOptionCatalog.emphases),
9379
- sectionHeight: sectionHeightIntentSchema.optional(),
9380
- heroLegibility: heroLegibilityStrategySchema.optional(),
9381
- heroComposition: heroCompositionIntentSchema.optional(),
9382
- heroTypographyScale: heroTypographyScaleIntentSchema.optional(),
9383
- imageSurfaceTreatment: imageSurfaceTreatmentSchema.optional(),
9384
- imageSurfaceMotion: imageSurfaceMotionSchema.optional(),
9385
- testimonialCardTreatment: testimonialCardTreatmentSchema.optional(),
9386
- tileTreatment: tileTreatmentSchema.optional(),
9387
- eventListTreatment: eventListTreatmentSchema.optional(),
9388
- eyebrowTreatment: eyebrowTreatmentSchema.optional()
9389
- }).strict();
9390
8601
  const styleAuthoritySchema = z.discriminatedUnion("kind", [
9391
8602
  z.object({
9392
8603
  kind: z.literal("theme-v2"),
@@ -9405,22 +8616,12 @@ const styleAuthoritySchema = z.discriminatedUnion("kind", [
9405
8616
  reason: z.literal("detached-custom-runtime-fields")
9406
8617
  }).strict()
9407
8618
  ]);
9408
- const blockRuntimeStyleAuthoritySchema = z.object({
8619
+ z.object({
9409
8620
  unit: z.literal("block-runtime-fields"),
9410
8621
  blockId: z.string().min(1).transform(asDesignBlockId),
9411
8622
  fields: nonEmptyRuntimeStyleFieldNamesSchema,
9412
8623
  authority: styleAuthoritySchema
9413
8624
  }).strict();
9414
- z.object({
9415
- schemaVersion: z.literal(1),
9416
- siteStyleId: z.string().min(1).transform(asSiteStyleId),
9417
- templateId: z.string().min(1).transform(asDesignSystemTemplateId),
9418
- templateVersion: z.number().int().nonnegative(),
9419
- resolverVersion: z.number().int().nonnegative(),
9420
- rhythmPresetId: z.string().min(1),
9421
- blocks: z.array(blockDesignPlanSchema),
9422
- styleAuthorities: z.array(blockRuntimeStyleAuthoritySchema)
9423
- }).strict();
9424
8625
  //#endregion
9425
8626
  //#region ../theme-core/src/site-styles/runtimeCompiler.ts
9426
8627
  function defineSectionForegroundRuntimeTokens(input) {
@@ -9524,61 +8725,7 @@ const defaultComponentRuntimeRules = defineComponentRuntimeRules({
9524
8725
  spacing: "none",
9525
8726
  rounded: "none",
9526
8727
  raised: false
9527
- } },
9528
- itemSurfaces: {
9529
- none: null,
9530
- default: {
9531
- spacing: "medium",
9532
- rounded: "lg",
9533
- raised: false
9534
- },
9535
- flat: {
9536
- spacing: "medium",
9537
- rounded: "lg",
9538
- raised: false
9539
- },
9540
- outlined: {
9541
- spacing: "medium",
9542
- rounded: "lg",
9543
- raised: false,
9544
- border: {
9545
- enabled: true,
9546
- width: "1",
9547
- colorToken: "border"
9548
- }
9549
- },
9550
- raised: {
9551
- spacing: "medium",
9552
- rounded: "xl",
9553
- raised: true
9554
- },
9555
- inset: {
9556
- treatment: "soft-panel",
9557
- spacing: "comfortable",
9558
- rounded: "xl",
9559
- raised: false,
9560
- border: { enabled: false },
9561
- background: {
9562
- type: "color",
9563
- color: "surfaceAlt",
9564
- textColor: "text"
9565
- }
9566
- },
9567
- editorial: {
9568
- treatment: "editorial-rule",
9569
- spacing: "none",
9570
- rounded: "none",
9571
- raised: false,
9572
- border: { enabled: false }
9573
- },
9574
- "color-blocked": {
9575
- treatment: "color-blocked",
9576
- spacing: "spacious",
9577
- rounded: "2xl",
9578
- raised: false,
9579
- border: { enabled: false }
9580
- }
9581
- }
8728
+ } }
9582
8729
  });
9583
8730
  function uniformSectionForeground(token) {
9584
8731
  return {
@@ -9664,36 +8811,7 @@ function componentRuntimeRulesForTokenRecipes(recipes) {
9664
8811
  rounded: recipes.radius === "square" ? "none" : cornerTreatment
9665
8812
  }
9666
8813
  },
9667
- flushFrames: defaultComponentRuntimeRules.flushFrames,
9668
- itemSurfaces: {
9669
- none: null,
9670
- default: {
9671
- ...defaultComponentRuntimeRules.itemSurfaces.default,
9672
- rounded: cornerTreatment
9673
- },
9674
- flat: {
9675
- ...defaultComponentRuntimeRules.itemSurfaces.flat,
9676
- rounded: cornerTreatment
9677
- },
9678
- outlined: {
9679
- ...defaultComponentRuntimeRules.itemSurfaces.outlined,
9680
- rounded: cornerTreatment
9681
- },
9682
- raised: {
9683
- ...defaultComponentRuntimeRules.itemSurfaces.raised,
9684
- rounded: cornerTreatment,
9685
- raised
9686
- },
9687
- inset: {
9688
- ...defaultComponentRuntimeRules.itemSurfaces.inset,
9689
- rounded: cornerTreatment
9690
- },
9691
- editorial: defaultComponentRuntimeRules.itemSurfaces.editorial,
9692
- "color-blocked": {
9693
- ...defaultComponentRuntimeRules.itemSurfaces["color-blocked"],
9694
- rounded: cornerTreatment
9695
- }
9696
- }
8814
+ flushFrames: defaultComponentRuntimeRules.flushFrames
9697
8815
  });
9698
8816
  }
9699
8817
  const kirtanOrnateDesignRuntimeRules = defineDesignRuntimeRules({
@@ -10143,7 +9261,6 @@ function defineCuratedSiteStyle(input) {
10143
9261
  compositionBudget: input.compositionBudget,
10144
9262
  supportedSectionSurfaces: generatedDesignOptionCatalog.sectionSurfaces,
10145
9263
  supportedContentFrames: input.supportedContentFrames ?? generatedContentFrameKinds,
10146
- supportedItemSurfaces: input.supportedItemSurfaces ?? generatedDesignOptionCatalog.itemSurfaces,
10147
9264
  supportedTransitions: generatedDesignOptionCatalog.transitions
10148
9265
  },
10149
9266
  headingDecoration: input.headingDecoration ?? noHeadingDecoration,
@@ -11224,6 +10341,7 @@ const curatedSiteStyles = [
11224
10341
  name: "Grounded Practice",
11225
10342
  themeOverrides: {
11226
10343
  accordions: editorialDividedAccordionSystem,
10344
+ cards: groundedPracticeCardSystem,
11227
10345
  testimonialQuote: serifDisplayQuote
11228
10346
  },
11229
10347
  description: "Quiet, grounded editorial design for practitioner-led services, recurring classes, and thoughtful one-to-one work.",
@@ -11278,7 +10396,8 @@ const curatedSiteStyles = [
11278
10396
  "feature-cards-soft-panels",
11279
10397
  "events-lined-panel",
11280
10398
  "testimonials-non-carded",
11281
- "faq-base-accordion"
10399
+ "faq-base-accordion",
10400
+ "booking-brand-band"
11282
10401
  ],
11283
10402
  recommendedFooterLookIds: ["footer-links-quiet"],
11284
10403
  buttonStyleChoices: [
@@ -11304,6 +10423,23 @@ asLayoutVariantKey("micro");
11304
10423
  asBoundaryOptionId("break:wave");
11305
10424
  asPageFlowPresetId("flow:quiet"), noneBoundaryOption.id, asPageFlowPresetId("flow:balanced"), softBoundaryOption.id, asPageFlowPresetId("flow:expressive"), spaciousBoundaryOption.id;
11306
10425
  //#endregion
10426
+ //#region ../theme-core/src/site-styles/resolver.ts
10427
+ const blockDesignFallback = {
10428
+ sectionSurface: "base",
10429
+ contentFrame: plainFrame,
10430
+ transitionAfter: "none",
10431
+ sectionHeight: "default",
10432
+ heroLegibility: "none",
10433
+ imageSurfaceTreatment: { kind: "none" },
10434
+ imageSurfaceMotion: "static",
10435
+ tileTreatment: "default",
10436
+ eventListTreatment: "plain",
10437
+ eyebrowTreatment: "plain",
10438
+ accordionIconTreatment: null,
10439
+ composition: null
10440
+ };
10441
+ blockDesignFallback.sectionSurface, blockDesignFallback.contentFrame, blockDesignFallback.transitionAfter, blockDesignFallback.sectionHeight, blockDesignFallback.heroLegibility, blockDesignFallback.imageSurfaceTreatment, blockDesignFallback.imageSurfaceMotion, blockDesignFallback.tileTreatment, blockDesignFallback.eventListTreatment, blockDesignFallback.eyebrowTreatment, blockDesignFallback.accordionIconTreatment, blockDesignFallback.composition;
10442
+ //#endregion
11307
10443
  //#region ../theme-core/src/site-styles/generatedSchemas.ts
11308
10444
  function uniqueNonEmpty(values) {
11309
10445
  const uniqueValues = [...new Set(values)];
@@ -11342,7 +10478,7 @@ function generatedChoiceSchema(valueSchema) {
11342
10478
  const generatedBlockDesignIntentSchema = z.object({
11343
10479
  sectionSurface: generatedChoiceSchema(z.enum(generatedDesignOptionCatalog.sectionSurfaces)),
11344
10480
  contentFrame: generatedChoiceSchema(generatedContentFrameIntentSchema),
11345
- itemSurface: generatedChoiceSchema(z.enum(generatedDesignOptionCatalog.itemSurfaces)),
10481
+ cardRole: generatedChoiceSchema(cardRoleWithLegacyAliasSchema),
11346
10482
  transitionAfter: generatedChoiceSchema(z.enum(generatedDesignOptionCatalog.transitions)),
11347
10483
  emphasis: generatedChoiceSchema(z.enum(generatedDesignOptionCatalog.emphases))
11348
10484
  }).strict();
@@ -11720,18 +10856,32 @@ function isFreePublicEventPriceDisplay(display) {
11720
10856
  }
11721
10857
  //#endregion
11722
10858
  //#region ../core/src/event-page-surface-subject.ts
10859
+ function createEventSeriesPageSurfaceSubject(eventSeriesId, bookingScope) {
10860
+ return bookingScope === "whole_series" ? {
10861
+ kind: "eventSeries",
10862
+ eventSeriesId,
10863
+ bookingScope,
10864
+ isWholeSeriesBooking: true
10865
+ } : {
10866
+ kind: "eventSeries",
10867
+ eventSeriesId,
10868
+ bookingScope
10869
+ };
10870
+ }
11723
10871
  function parseEventPageSurfaceSubject(value) {
11724
10872
  if (!isRecord$6(value)) return err({ kind: "notObject" });
11725
10873
  switch (value.kind) {
11726
10874
  case "eventSeries": {
11727
10875
  const eventSeriesId = parseEventSeriesId(value.eventSeriesId);
11728
- return eventSeriesId.ok ? ok({
11729
- kind: "eventSeries",
11730
- eventSeriesId: eventSeriesId.value
11731
- }) : err({
10876
+ if (!eventSeriesId.ok) return err({
11732
10877
  kind: "invalidEventSeriesId",
11733
10878
  error: eventSeriesId.error
11734
10879
  });
10880
+ if (value.bookingScope !== "single_occurrence" && value.bookingScope !== "whole_series") return err({
10881
+ kind: "invalidEventSeriesBookingScope",
10882
+ bookingScope: value.bookingScope
10883
+ });
10884
+ return ok(createEventSeriesPageSurfaceSubject(eventSeriesId.value, value.bookingScope));
11735
10885
  }
11736
10886
  case "eventOffering": {
11737
10887
  const eventOfferingId = parseEventOfferingId(value.eventOfferingId);
@@ -14087,6 +13237,37 @@ function styledContainer(config) {
14087
13237
  //#endregion
14088
13238
  //#region ../blocks/src/system/spacing.ts
14089
13239
  /**
13240
+ * Type-safe spacing system for sections and containers.
13241
+ *
13242
+ * This module provides:
13243
+ * - Semantic spacing values (none, compact, cozy, medium, comfortable, spacious)
13244
+ * - Type-safe mappings to CSS class tokens
13245
+ * - Runtime validation via type guards
13246
+ * - Separate handling for section (vertical) vs container (all-sides) spacing
13247
+ *
13248
+ * Type Safety Guarantees:
13249
+ * - Type is derived from data (single source of truth)
13250
+ * - Maps are validated for completeness at compile time
13251
+ * - Runtime validation available via isSemanticSpacing()
13252
+ */
13253
+ /**
13254
+ * Single source of truth for semantic spacing values.
13255
+ * The SemanticSpacing type is derived from this array to ensure they stay in sync.
13256
+ *
13257
+ * Adding a new spacing value:
13258
+ * 1. Add it to this array
13259
+ * 2. TypeScript will error until you update both spacing maps
13260
+ * 3. No way to get out of sync
13261
+ */
13262
+ const SEMANTIC_SPACING_VALUES = [
13263
+ "none",
13264
+ "compact",
13265
+ "cozy",
13266
+ "medium",
13267
+ "comfortable",
13268
+ "spacious"
13269
+ ];
13270
+ /**
14090
13271
  * Default spacing value for sections when not explicitly configured.
14091
13272
  */
14092
13273
  const DEFAULT_SECTION_SPACING = "medium";
@@ -14579,6 +13760,31 @@ function responsiveTwoColumn({ image, text, ratioFrom, imagePositionFrom, gapCla
14579
13760
  }
14580
13761
  //#endregion
14581
13762
  //#region ../blocks/src/system/node/fragments/styledCard.ts
13763
+ /**
13764
+ * The shared child hooks generated card CSS targets (`.card-media`,
13765
+ * `.card-content`). They join the class list only while a card role is in play,
13766
+ * so cards still on the legacy treatment path keep their exact classes.
13767
+ *
13768
+ * Blocks whose items each choose a surface pass `itemRole` so the hook follows
13769
+ * the item's choice; blocks with one surface per block bind from the card
13770
+ * styles themselves (the transform reads the role off `stylesFrom` and ignores
13771
+ * a non-string bound value), which keeps one emission path for both shapes.
13772
+ */
13773
+ function cardRoleChildClass(input) {
13774
+ return { $bind: {
13775
+ from: input.itemRole?.from ?? input.stylesFrom,
13776
+ transforms: [{
13777
+ id: "boxStyles.cardRoleClass",
13778
+ options: {
13779
+ emit: input.emit,
13780
+ baseClass: input.baseClass,
13781
+ stylesPath: input.stylesFrom,
13782
+ ...input.itemRole?.aliases ? { itemRoleAliases: input.itemRole.aliases } : {}
13783
+ }
13784
+ }],
13785
+ fallback: input.baseClass
13786
+ } };
13787
+ }
14582
13788
  function styledCard(children, opts, ...mods) {
14583
13789
  const baseClassName = opts.baseClassName ?? "rb-relative rb-isolate rb-overflow-visible rb-border";
14584
13790
  const defaultBackgroundLayer = el("div", {
@@ -14596,19 +13802,32 @@ function styledCard(children, opts, ...mods) {
14596
13802
  }]
14597
13803
  } }
14598
13804
  };
13805
+ const classNameBinding = opts.itemRole ? { $bind: {
13806
+ from: opts.itemRole.from,
13807
+ transforms: [{
13808
+ id: "boxStyles.cardRoleClass",
13809
+ options: {
13810
+ axis: "all",
13811
+ baseClass: baseClassName,
13812
+ stylesPath: opts.stylesFrom,
13813
+ ...opts.itemRole.aliases ? { itemRoleAliases: opts.itemRole.aliases } : {}
13814
+ }
13815
+ }],
13816
+ fallback: baseClassName
13817
+ } } : { $bind: {
13818
+ from: opts.stylesFrom,
13819
+ transforms: [{
13820
+ id: "boxStyles.all",
13821
+ options: {
13822
+ axis: "all",
13823
+ baseClass: baseClassName
13824
+ }
13825
+ }],
13826
+ fallback: baseClassName
13827
+ } };
14599
13828
  return el("div", {
14600
13829
  ...opts.dataProps ?? {},
14601
- className: { $bind: {
14602
- from: opts.stylesFrom,
14603
- transforms: [{
14604
- id: "boxStyles.all",
14605
- options: {
14606
- axis: "all",
14607
- baseClass: baseClassName
14608
- }
14609
- }],
14610
- fallback: baseClassName
14611
- } },
13830
+ className: classNameBinding,
14612
13831
  ...style ? { style } : {}
14613
13832
  }, [
14614
13833
  defaultBackgroundLayer,
@@ -17127,7 +16346,11 @@ const teamMemberFragment = defineFragment({
17127
16346
  gap: "sm",
17128
16347
  className: "rb-team-member rb-items-center rb-text-center"
17129
16348
  }, [
17130
- el("div", { className: "rb-team-member-photo-wrap rb-w-full" }, [media({
16349
+ el("div", { className: cardRoleChildClass({
16350
+ emit: "media",
16351
+ baseClass: "rb-team-member-photo-wrap rb-w-full",
16352
+ stylesFrom: "content._cardStyles"
16353
+ }) }, [media({
17131
16354
  className: "rb-team-member-photo rb-w-full rb-object-cover",
17132
16355
  style: { aspectRatio: "1 / 1" },
17133
16356
  size: {
@@ -17430,6 +16653,111 @@ const heroBlockDefinition = { manifest: createBlockManifest({
17430
16653
  spacing: "xl"
17431
16654
  }
17432
16655
  }) };
16656
+ /**
16657
+ * Canonical responsive ladder for a user-configured column count: 1 column at
16658
+ * base, 2 from `sm`, 3 from `lg` (when the count allows), and the full count
16659
+ * from `xl`. This matches the events blocks' COLUMN_CLASSES ladder — the two
16660
+ * are derived from this single function.
16661
+ */
16662
+ function gridUserColumnLadder(count) {
16663
+ const capped = Number.isFinite(count) ? Math.max(1, Math.min(4, Math.floor(count))) : 3;
16664
+ const ladder = { base: 1 };
16665
+ if (capped >= 2) ladder.sm = 2;
16666
+ if (capped >= 3) ladder.lg = 3;
16667
+ if (capped >= 4) ladder.xl = capped;
16668
+ return ladder;
16669
+ }
16670
+ /** The ladder as a space-separated `rb-*` utility class string. */
16671
+ function gridUserColumnClasses(count) {
16672
+ const ladder = gridUserColumnLadder(count);
16673
+ return GRID_BREAKPOINTS.flatMap((bp) => {
16674
+ const value = ladder[bp];
16675
+ return typeof value === "number" ? [COL_COUNT_CLASS[bp](value)] : [];
16676
+ }).join(" ");
16677
+ }
16678
+ /** Utility class for a numeric column COUNT at a given breakpoint. */
16679
+ const COL_COUNT_CLASS = {
16680
+ base: (n) => `rb-grid-cols-${n}`,
16681
+ sm: (n) => `rb-sm-grid-cols-${n}`,
16682
+ md: (n) => `rb-md-grid-cols-${n}`,
16683
+ lg: (n) => `rb-lg-grid-cols-${n}`,
16684
+ xl: (n) => `rb-xl-grid-cols-${n}`
16685
+ };
16686
+ const GRID_BREAKPOINTS = [
16687
+ "base",
16688
+ "sm",
16689
+ "md",
16690
+ "lg",
16691
+ "xl"
16692
+ ];
16693
+ //#endregion
16694
+ //#region ../blocks/src/system/fields/gridLayout.ts
16695
+ /**
16696
+ * Grid `userColumns` binding for blocks with a user-configured column count.
16697
+ * The count renders through the canonical responsive ladder — see
16698
+ * {@link gridUserColumnLadder}.
16699
+ */
16700
+ function userColumnsGridBinding() {
16701
+ return { $bind: {
16702
+ from: "content.columns",
16703
+ fallback: 3,
16704
+ coerce: "number"
16705
+ } };
16706
+ }
16707
+ /** Shared "Columns" select (2/3/4) for grid-layout blocks. */
16708
+ function columnsSelectField(options = {}) {
16709
+ return parseFieldDefinition({
16710
+ id: "columns",
16711
+ type: "select",
16712
+ label: options.label ?? "Columns",
16713
+ ...options.description ? { description: options.description } : {},
16714
+ defaultValue: options.defaultValue ?? String(3),
16715
+ options: [
16716
+ {
16717
+ value: "2",
16718
+ label: "2 columns"
16719
+ },
16720
+ {
16721
+ value: "3",
16722
+ label: "3 columns"
16723
+ },
16724
+ {
16725
+ value: "4",
16726
+ label: "4 columns"
16727
+ }
16728
+ ],
16729
+ ui: {
16730
+ intent: "display",
16731
+ ...options.visibleWhen ? { visibleWhen: options.visibleWhen } : {}
16732
+ }
16733
+ });
16734
+ }
16735
+ const SEMANTIC_SPACING_LABELS = {
16736
+ none: "None",
16737
+ compact: "Compact",
16738
+ cozy: "Cozy",
16739
+ medium: "Medium",
16740
+ comfortable: "Comfortable",
16741
+ spacious: "Spacious"
16742
+ };
16743
+ /** Shared semantic "Gap" select for layout blocks. */
16744
+ function gapSelectField(options = {}) {
16745
+ return parseFieldDefinition({
16746
+ id: "gap",
16747
+ type: "select",
16748
+ label: options.label ?? "Gap",
16749
+ ...options.description ? { description: options.description } : {},
16750
+ defaultValue: options.defaultValue ?? "medium",
16751
+ options: SEMANTIC_SPACING_VALUES.map((value) => ({
16752
+ value,
16753
+ label: SEMANTIC_SPACING_LABELS[value]
16754
+ })),
16755
+ ui: {
16756
+ intent: "display",
16757
+ ...options.visibleWhen ? { visibleWhen: options.visibleWhen } : {}
16758
+ }
16759
+ });
16760
+ }
17433
16761
  //#endregion
17434
16762
  //#region ../blocks/src/system/fields/aspectRatio.ts
17435
16763
  const standardAspectRatioOptions = [
@@ -17690,47 +17018,14 @@ const introBlockDefinition = { manifest: createBlockManifest({
17690
17018
  equals: "media-copy"
17691
17019
  }
17692
17020
  }),
17693
- {
17694
- id: "gap",
17695
- type: "select",
17021
+ gapSelectField({
17696
17022
  label: "Gap between media and text",
17697
- required: false,
17698
17023
  defaultValue: "comfortable",
17699
- multiple: false,
17700
- options: [
17701
- {
17702
- value: "none",
17703
- label: "None"
17704
- },
17705
- {
17706
- value: "compact",
17707
- label: "Compact"
17708
- },
17709
- {
17710
- value: "cozy",
17711
- label: "Cozy"
17712
- },
17713
- {
17714
- value: "medium",
17715
- label: "Medium"
17716
- },
17717
- {
17718
- value: "comfortable",
17719
- label: "Comfortable"
17720
- },
17721
- {
17722
- value: "spacious",
17723
- label: "Spacious"
17724
- }
17725
- ],
17726
- ui: {
17727
- intent: "display",
17728
- visibleWhen: {
17729
- field: "variant",
17730
- equals: "media-copy"
17731
- }
17024
+ visibleWhen: {
17025
+ field: "variant",
17026
+ equals: "media-copy"
17732
17027
  }
17733
- },
17028
+ }),
17734
17029
  createImageColSizeField({
17735
17030
  id: "ratio",
17736
17031
  label: "Media column size",
@@ -17977,9 +17272,21 @@ function postReadMore() {
17977
17272
  value: "Read more"
17978
17273
  }, when("content.readMoreText", { not: true }))]);
17979
17274
  }
17275
+ /**
17276
+ * The shared child hooks generated card CSS targets. Blog listing has one card
17277
+ * surface per block, so the hooks read the role straight off the compiled card
17278
+ * styles (Phase 2b).
17279
+ */
17280
+ function postCardChildClass(emit, baseClass) {
17281
+ return cardRoleChildClass({
17282
+ emit,
17283
+ baseClass,
17284
+ stylesFrom: "content._cardStyles"
17285
+ });
17286
+ }
17980
17287
  function postImageLink(className, mediaOptions) {
17981
17288
  return link({
17982
- className: "rb-block rb-overflow-hidden",
17289
+ className: postCardChildClass("media", "rb-block rb-overflow-hidden"),
17983
17290
  href: { $bind: { from: "post.path" } }
17984
17291
  }, [media({ className }, bind("post.image", { transforms: [{
17985
17292
  id: "media.fromUrl",
@@ -18000,7 +17307,7 @@ const gridPostCard = postCard([postImageLink("rb-h-48 rb-w-full rb-object-cover
18000
17307
  resize: "cover"
18001
17308
  }), stack({
18002
17309
  gap: "sm",
18003
- className: "rb-flex-1 rb-p-6"
17310
+ className: postCardChildClass("content", "rb-flex-1 rb-p-6")
18004
17311
  }, [
18005
17312
  postTitle(),
18006
17313
  postDate(),
@@ -18009,7 +17316,7 @@ const gridPostCard = postCard([postImageLink("rb-h-48 rb-w-full rb-object-cover
18009
17316
  ])], repeat("data.posts", "post"));
18010
17317
  const stackPostCard = styledCard([inline({
18011
17318
  gap: "lg",
18012
- className: "rb-flex-col rb-items-stretch rb-sm-flex-row rb-sm-items-start rb-p-5 rb-sm-p-6"
17319
+ className: postCardChildClass("content", "rb-flex-col rb-items-stretch rb-sm-flex-row rb-sm-items-start rb-p-5 rb-sm-p-6")
18013
17320
  }, [postImageLink("rb-h-44 rb-w-full rb-sm-h-32 rb-sm-w-36 rb-object-cover", {
18014
17321
  width: 320,
18015
17322
  height: 240,
@@ -18052,11 +17359,7 @@ function blogListingShell(children) {
18052
17359
  });
18053
17360
  }
18054
17361
  const gridLayout$2 = blogListingShell([grid$3({
18055
- cols: { $bind: {
18056
- from: "content.columns",
18057
- fallback: 3,
18058
- coerce: "number"
18059
- } },
17362
+ userColumns: userColumnsGridBinding(),
18060
17363
  gap: "lg"
18061
17364
  }, [gridPostCard]), emptyState$2]);
18062
17365
  const blogListingManifest = createBlockManifest({
@@ -18084,33 +17387,13 @@ const blogListingManifest = createBlockManifest({
18084
17387
  }
18085
17388
  },
18086
17389
  additionalFields: [
18087
- parseFieldDefinition({
18088
- id: "columns",
18089
- type: "select",
17390
+ columnsSelectField({
18090
17391
  label: "Grid columns",
18091
17392
  description: "Number of columns in the grid layout.",
18092
- defaultValue: "3",
18093
- ui: {
18094
- intent: "display",
18095
- visibleWhen: {
18096
- field: "variant",
18097
- equals: "grid"
18098
- }
18099
- },
18100
- options: [
18101
- {
18102
- value: "2",
18103
- label: "2 columns"
18104
- },
18105
- {
18106
- value: "3",
18107
- label: "3 columns"
18108
- },
18109
- {
18110
- value: "4",
18111
- label: "4 columns"
18112
- }
18113
- ]
17393
+ visibleWhen: {
17394
+ field: "variant",
17395
+ equals: "grid"
17396
+ }
18114
17397
  }),
18115
17398
  parseFieldDefinition({
18116
17399
  id: "postsPerPage",
@@ -18769,7 +18052,7 @@ const defaultLayout = styledSection({
18769
18052
  const twoColumnLayout = styledSection({
18770
18053
  children: styledContainer({
18771
18054
  baseClassName: "rb-relative rb-isolate",
18772
- children: el("div", { className: "rb-faq-split-heading rb-grid rb-grid-cols-1 rb-gap-8 rb-lg-grid-cols-2 rb-lg-items-start" }, [el("div", { className: "rb-faq-split-heading-copy" }, [headingLayout]), el("div", { className: "rb-faq-split-heading-accordion" }, [accordionLayout])])
18055
+ children: el("div", { className: "rb-faq-split-heading rb-grid rb-grid-cols-1 rb-gap-8 rb-lg-grid-cols-2 rb-items-start" }, [el("div", { className: "rb-faq-split-heading-copy" }, [headingLayout]), el("div", { className: "rb-faq-split-heading-accordion" }, [accordionLayout])])
18773
18056
  }),
18774
18057
  baseClass: ""
18775
18058
  });
@@ -18786,7 +18069,7 @@ const questionColumnsLayout = styledSection({
18786
18069
  const splitHeadingColumnsLayout = styledSection({
18787
18070
  children: styledContainer({
18788
18071
  baseClassName: "rb-relative rb-isolate",
18789
- children: el("div", { className: "rb-faq-split-heading-columns rb-grid rb-grid-cols-1 rb-gap-8 rb-lg-grid-cols-2 rb-lg-items-start" }, [el("div", { className: "rb-faq-split-heading-columns-copy" }, [headingLayout]), el("div", { className: "rb-faq-split-heading-columns-accordion" }, [questionColumnsAccordionLayout])])
18072
+ children: el("div", { className: "rb-faq-split-heading-columns rb-grid rb-grid-cols-1 rb-gap-8 rb-lg-grid-cols-2 rb-items-start" }, [el("div", { className: "rb-faq-split-heading-columns-copy" }, [headingLayout]), el("div", { className: "rb-faq-split-heading-columns-accordion" }, [questionColumnsAccordionLayout])])
18790
18073
  }),
18791
18074
  baseClass: ""
18792
18075
  });
@@ -19101,17 +18384,6 @@ const centeredLayout = stack({
19101
18384
  fallback: `rb-container rb-header-layout ${desktopOnlyDisplay("flex")} rb-w-full rb-flex-col rb-items-center rb-gap-5 rb-text-center`
19102
18385
  })
19103
18386
  }, [centeredLogoRow, createNavRow(`${desktopOnlyDisplay("flex")} rb-flex-wrap rb-justify-center rb-gap-x-6 rb-gap-y-3`, "center")], when("$root.theme.header.variant", { equals: "centered" }));
19104
- const transparentLayout = inline({
19105
- className: bindProp("$root.theme.header.maxWidth", {
19106
- transforms: pipe(tx("layout.maxWidthClass", { base: `rb-header-layout ${desktopOnlyDisplay("flex")} rb-w-full rb-items-center rb-gap-6` })),
19107
- fallback: `rb-container rb-header-layout ${desktopOnlyDisplay("flex")} rb-w-full rb-items-center rb-gap-6`
19108
- }),
19109
- align: "center"
19110
- }, [
19111
- logoRow,
19112
- createNavRow(`rb-ml-auto ${desktopOnlyDisplay("flex")} rb-gap-6`),
19113
- headerCta
19114
- ], when("$root.theme.header.variant", { equals: "transparent" }));
19115
18387
  const floatingLayout = inline({
19116
18388
  [SITE_CHROME_VISIBLE_HEADER_ATTR]: "true",
19117
18389
  className: bindProp("$root.theme.header.maxWidth", {
@@ -19170,7 +18442,6 @@ const siteHeaderBlockDefinition = { manifest: createBlockManifest({
19170
18442
  classicLayout,
19171
18443
  classicCenteredNavLayout,
19172
18444
  centeredLayout,
19173
- transparentLayout,
19174
18445
  floatingLayout,
19175
18446
  mobileOverlay
19176
18447
  ], props({ "data-site-header": "true" })),
@@ -19875,26 +19146,20 @@ const repeatedItemsNode = repeaterFragmentLayout({
19875
19146
  itemName: ITEM_NAME$1,
19876
19147
  fragments: collectionFragments,
19877
19148
  itemGap: "md",
19878
- itemClassName: {
19879
- $bind: {
19880
- from: "content._cardStyles",
19881
- transforms: [{
19882
- id: "boxStyles.all",
19883
- options: {
19884
- axis: "all",
19885
- baseClass: "rb-collection-item rb-relative rb-isolate rb-overflow-visible rb-border"
19886
- }
19887
- }]
19888
- },
19149
+ itemClassName: { $bind: {
19150
+ from: "content._cardStyles",
19151
+ transforms: [{
19152
+ id: "boxStyles.all",
19153
+ options: {
19154
+ axis: "all",
19155
+ baseClass: "rb-collection-item rb-relative rb-isolate rb-overflow-visible rb-border"
19156
+ }
19157
+ }],
19889
19158
  fallback: "rb-collection-item"
19890
- }
19159
+ } }
19891
19160
  });
19892
19161
  const gridLayoutNode = el("grid", {
19893
- cols: { $bind: {
19894
- from: "content.columns",
19895
- fallback: 3,
19896
- coerce: "number"
19897
- } },
19162
+ userColumns: userColumnsGridBinding(),
19898
19163
  gap: { $bind: {
19899
19164
  from: "content.gap",
19900
19165
  fallback: "medium"
@@ -19933,79 +19198,26 @@ const collectionBlockDefinition = { manifest: createBlockManifest({
19933
19198
  additionalFields: [
19934
19199
  parseFieldDefinition({
19935
19200
  id: "layout",
19936
- type: "select",
19937
- label: "Layout",
19938
- defaultValue: "grid",
19939
- options: [{
19940
- value: "grid",
19941
- label: "Grid"
19942
- }, {
19943
- value: "stack",
19944
- label: "Stack"
19945
- }],
19946
- ui: { intent: "display" }
19947
- }),
19948
- parseFieldDefinition({
19949
- id: "columns",
19950
- type: "select",
19951
- label: "Columns",
19952
- description: "Number of columns in the grid layout.",
19953
- defaultValue: "3",
19954
- options: [
19955
- {
19956
- value: "2",
19957
- label: "2 columns"
19958
- },
19959
- {
19960
- value: "3",
19961
- label: "3 columns"
19962
- },
19963
- {
19964
- value: "4",
19965
- label: "4 columns"
19966
- }
19967
- ],
19968
- ui: {
19969
- intent: "display",
19970
- visibleWhen: {
19971
- field: "layout",
19972
- equals: "grid"
19973
- }
19974
- }
19975
- }),
19976
- parseFieldDefinition({
19977
- id: "gap",
19978
- type: "select",
19979
- label: "Gap",
19980
- defaultValue: "medium",
19981
- options: [
19982
- {
19983
- value: "none",
19984
- label: "None"
19985
- },
19986
- {
19987
- value: "compact",
19988
- label: "Compact"
19989
- },
19990
- {
19991
- value: "cozy",
19992
- label: "Cozy"
19993
- },
19994
- {
19995
- value: "medium",
19996
- label: "Medium"
19997
- },
19998
- {
19999
- value: "comfortable",
20000
- label: "Comfortable"
20001
- },
20002
- {
20003
- value: "spacious",
20004
- label: "Spacious"
20005
- }
20006
- ],
19201
+ type: "select",
19202
+ label: "Layout",
19203
+ defaultValue: "grid",
19204
+ options: [{
19205
+ value: "grid",
19206
+ label: "Grid"
19207
+ }, {
19208
+ value: "stack",
19209
+ label: "Stack"
19210
+ }],
20007
19211
  ui: { intent: "display" }
20008
19212
  }),
19213
+ columnsSelectField({
19214
+ description: "Number of columns in the grid layout.",
19215
+ visibleWhen: {
19216
+ field: "layout",
19217
+ equals: "grid"
19218
+ }
19219
+ }),
19220
+ gapSelectField(),
20009
19221
  fragmentsToRepeaterField("items", "Items", collectionFragments, {
20010
19222
  minItems: 0,
20011
19223
  maxItems: 50,
@@ -20043,6 +19255,22 @@ const FEATURE_CARD_GENERATED_ICON_SIZE_PX = {
20043
19255
  };
20044
19256
  //#endregion
20045
19257
  //#region ../blocks/src/system/blocks/feature-cards.ts
19258
+ const featureCardItemRole = {
19259
+ from: "card.surfaceRole",
19260
+ aliases: {
19261
+ open: "none",
19262
+ panel: "alternative"
19263
+ }
19264
+ };
19265
+ /** The shared child hooks, bound from this block's per-item surface choice. */
19266
+ function featureCardChildClass(emit, baseClass) {
19267
+ return cardRoleChildClass({
19268
+ emit,
19269
+ baseClass,
19270
+ stylesFrom: "content._cardStyles",
19271
+ itemRole: featureCardItemRole
19272
+ });
19273
+ }
20046
19274
  function grid$2(props, children) {
20047
19275
  return el("grid", props ?? void 0, children ?? void 0);
20048
19276
  }
@@ -20073,12 +19301,12 @@ const editorialSectionHeading = stack({
20073
19301
  style: textColorStyle("mutedText")
20074
19302
  }, when("content.description"), bind("content.description"))
20075
19303
  ]);
20076
- const featureCard = styledCard([el("div", { className: "rb-feature-card-media-frame rb-overflow-hidden rb-w-full" }, [media({
19304
+ const featureCard = styledCard([el("div", { className: featureCardChildClass("media", "rb-feature-card-media-frame rb-overflow-hidden rb-w-full") }, [media({
20077
19305
  className: "rb-feature-card-media rb-w-full rb-h-auto rb-object-cover",
20078
19306
  style: { aspectRatio: { $bind: { from: "card.aspectRatio" } } }
20079
19307
  }, bind("card.media"))], when("card.media")), stack({
20080
19308
  gap: "sm",
20081
- className: "rb-feature-card-content rb-flex-1 rb-p-6"
19309
+ className: featureCardChildClass("content", "rb-feature-card-content rb-flex-1 rb-p-6")
20082
19310
  }, [
20083
19311
  el("feature-card-icon", {
20084
19312
  treatment: { $bind: {
@@ -20114,6 +19342,7 @@ const featureCard = styledCard([el("div", { className: "rb-feature-card-media-fr
20114
19342
  stylesFrom: "content._cardStyles",
20115
19343
  backgroundFrom: "content._cardStyles.background",
20116
19344
  baseClassName: "rb-feature-card rb-relative rb-isolate rb-border rb-flex rb-h-full rb-flex-col",
19345
+ itemRole: featureCardItemRole,
20117
19346
  dataProps: { "data-surface-role": { $bind: {
20118
19347
  from: "card.surfaceRole",
20119
19348
  fallback: "open"
@@ -20129,11 +19358,7 @@ const cardsLayout = styledSection({
20129
19358
  from: "content.cardMarker",
20130
19359
  fallback: "icons"
20131
19360
  } },
20132
- cols: { $bind: {
20133
- from: "content.columns",
20134
- fallback: 3,
20135
- coerce: "number"
20136
- } },
19361
+ userColumns: userColumnsGridBinding(),
20137
19362
  gap: "lg"
20138
19363
  }, [featureCard])]
20139
19364
  }),
@@ -20193,29 +19418,7 @@ const featureCardsBlockDefinition = { manifest: createBlockManifest({
20193
19418
  required: false,
20194
19419
  ui: { richTextVariant: "limited" }
20195
19420
  },
20196
- {
20197
- id: "columns",
20198
- type: "select",
20199
- label: "Columns",
20200
- required: false,
20201
- defaultValue: "3",
20202
- multiple: false,
20203
- options: [
20204
- {
20205
- value: "2",
20206
- label: "2 columns"
20207
- },
20208
- {
20209
- value: "3",
20210
- label: "3 columns"
20211
- },
20212
- {
20213
- value: "4",
20214
- label: "4 columns"
20215
- }
20216
- ],
20217
- ui: { intent: "display" }
20218
- },
19421
+ columnsSelectField(),
20219
19422
  {
20220
19423
  id: "cards",
20221
19424
  type: "repeater",
@@ -20505,6 +19708,19 @@ function createCarouselBehaviorFields(options = {}) {
20505
19708
  }
20506
19709
  ];
20507
19710
  }
19711
+ /**
19712
+ * Media-text's card is an author choice ("wrap text in a card") styled through
19713
+ * `_textCardStyles`, while the Look compiles its card role onto the shared
19714
+ * `_cardStyles`. The role therefore rides in as the per-card override and the
19715
+ * author's own card fields ride along on top, through the one card-class
19716
+ * emission path. Padding stays the author's `Inner spacing` choice, so no
19717
+ * `.card-content` hook is emitted here (Phase 2b).
19718
+ */
19719
+ const mediaTextCardOptions = {
19720
+ stylesFrom: "content._textCardStyles",
19721
+ backgroundFrom: "content._textCardStyles.background",
19722
+ itemRole: { from: "content._cardStyles.role" }
19723
+ };
20508
19724
  const textCardStylesField = (() => {
20509
19725
  const field = cardStylesField({
20510
19726
  id: "_textCardStyles",
@@ -20598,41 +19814,10 @@ const mediaTextBlockDefinition = { manifest: createBlockManifest({
20598
19814
  defaultValue: "left",
20599
19815
  uiIntent: "display"
20600
19816
  }),
20601
- {
20602
- id: "gap",
20603
- type: "select",
19817
+ gapSelectField({
20604
19818
  label: "Gap between media and text",
20605
- required: false,
20606
- defaultValue: "comfortable",
20607
- multiple: false,
20608
- options: [
20609
- {
20610
- value: "none",
20611
- label: "None"
20612
- },
20613
- {
20614
- value: "compact",
20615
- label: "Compact"
20616
- },
20617
- {
20618
- value: "cozy",
20619
- label: "Cozy"
20620
- },
20621
- {
20622
- value: "medium",
20623
- label: "Medium"
20624
- },
20625
- {
20626
- value: "comfortable",
20627
- label: "Comfortable"
20628
- },
20629
- {
20630
- value: "spacious",
20631
- label: "Spacious"
20632
- }
20633
- ],
20634
- ui: { intent: "display" }
20635
- },
19819
+ defaultValue: "comfortable"
19820
+ }),
20636
19821
  { ...createImageColSizeField({
20637
19822
  id: "ratio",
20638
19823
  label: "Image column size",
@@ -20740,16 +19925,10 @@ const mediaTextBlockDefinition = { manifest: createBlockManifest({
20740
19925
  as: "p",
20741
19926
  className: eyebrowClassName("rb-eyebrow heading-eyebrow")
20742
19927
  }, when("content.eyebrow"), bind("content.eyebrow")), text({ as: "h2" }, bind("content.title"))], when("content.title"));
20743
- const defaultTextColumn = el("div", {}, [styledCard([richText({ className: "rb-prose rb-max-w-none" }, bind("content.text"))], {
20744
- stylesFrom: "content._textCardStyles",
20745
- backgroundFrom: "content._textCardStyles.background"
20746
- }, when("content.wrapTextInCard")), richText({ className: "rb-prose rb-max-w-none" }, when("content.wrapTextInCard", { not: true }), bind("content.text"))]);
19928
+ 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"))]);
20747
19929
  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" }, [
20748
19930
  copyHeading,
20749
- styledCard([richText({ className: bodyClassNameFromAlignment }, bind("content.text"))], {
20750
- stylesFrom: "content._textCardStyles",
20751
- backgroundFrom: "content._textCardStyles.background"
20752
- }, when("content.wrapTextInCard")),
19931
+ styledCard([richText({ className: bodyClassNameFromAlignment }, bind("content.text"))], mediaTextCardOptions, when("content.wrapTextInCard")),
20753
19932
  richText({ className: bodyClassNameFromAlignment }, when("content.wrapTextInCard", { not: true }), bind("content.text"))
20754
19933
  ]);
20755
19934
  const defaultImageCommonProps = {
@@ -20813,19 +19992,13 @@ const mediaTextBlockDefinition = { manifest: createBlockManifest({
20813
19992
  imageWrapperClassName: "rb-w-full rb-shrink-0",
20814
19993
  textWrapperClassName: "rb-w-full rb-min-w-0 rb-flex-1 rb-self-stretch"
20815
19994
  })], whenImagesLength(0, { not: true }));
20816
- const defaultTextOnlyLayout = el("div", {}, [styledCard([richText({ className: "rb-prose rb-max-w-none" }, bind("content.text"))], {
20817
- stylesFrom: "content._textCardStyles",
20818
- backgroundFrom: "content._textCardStyles.background"
20819
- }, when("content.wrapTextInCard")), richText({ className: "rb-prose rb-max-w-none" }, when("content.wrapTextInCard", { not: true }), bind("content.text"))], whenImagesLength(0));
19995
+ 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));
20820
19996
  const bioTextOnlyLayout = el("div", { className: "rb-flex rb-w-full rb-max-w-prose rb-flex-col rb-gap-5" }, [
20821
19997
  text({
20822
19998
  as: "h2",
20823
19999
  className: titleClassNameFromAlignment
20824
20000
  }, when("content.title"), bind("content.title")),
20825
- styledCard([richText({ className: bodyClassNameFromAlignment }, bind("content.text"))], {
20826
- stylesFrom: "content._textCardStyles",
20827
- backgroundFrom: "content._textCardStyles.background"
20828
- }, when("content.wrapTextInCard")),
20001
+ styledCard([richText({ className: bodyClassNameFromAlignment }, bind("content.text"))], mediaTextCardOptions, when("content.wrapTextInCard")),
20829
20002
  richText({ className: bodyClassNameFromAlignment }, when("content.wrapTextInCard", { not: true }), bind("content.text"))
20830
20003
  ], whenImagesLength(0));
20831
20004
  const defaultInner = el("div", {}, [defaultImagesLayout, defaultTextOnlyLayout]);
@@ -20875,6 +20048,44 @@ const mediaTextBlockDefinition = { manifest: createBlockManifest({
20875
20048
  ],
20876
20049
  icon: "Columns"
20877
20050
  }) };
20051
+ //#endregion
20052
+ //#region ../blocks/src/system/blocks/appointment-booking.tsx
20053
+ const bookingHeading = text({ as: "h2" }, bind("content.heading"), when("content.heading"));
20054
+ const bookingDescription = richText({}, bind("content.description"), when("content.description"));
20055
+ /**
20056
+ * The wizard island itself. Structure above it may change per variant, but this
20057
+ * node never does — the SSR shell and the hydrated client agree on geometry
20058
+ * because the split lives *outside* the island root, in server-rendered markup
20059
+ * that hydration never rewrites.
20060
+ */
20061
+ const bookingWizard = bookingForm(withApiBindings({
20062
+ portalToken: { $bind: {
20063
+ from: "$root.portalToken",
20064
+ fallback: null
20065
+ } },
20066
+ formId: { $bind: { from: "content.formId" } },
20067
+ form: { $bind: { from: "data.form" } },
20068
+ services: { $bind: { from: "data.services" } }
20069
+ }));
20070
+ /** Both variants sit in the same section shell; only the inner layout differs. */
20071
+ function bookingSection(children) {
20072
+ return styledSection({
20073
+ children: sectionContainer([...children], { gap: "lg" }),
20074
+ baseClass: "",
20075
+ spacing: "spacious"
20076
+ });
20077
+ }
20078
+ /** Heading, description and wizard in one column — the historical layout. */
20079
+ const stackedLayout$1 = bookingSection([
20080
+ bookingHeading,
20081
+ bookingDescription,
20082
+ bookingWizard
20083
+ ]);
20084
+ /**
20085
+ * Section copy beside the booking card. Two columns from `lg` up (roughly 40/60,
20086
+ * giving the wizard the wider side), stacking to the default order below that.
20087
+ */
20088
+ const splitCopyLayout = bookingSection([el("div", { className: "rb-booking-split rb-grid rb-grid-cols-1 rb-gap-8 rb-lg-grid-cols-5 rb-items-start" }, [el("div", { className: "rb-booking-split-copy rb-lg-col-span-2" }, [stack({ gap: "md" }, [bookingHeading, bookingDescription])]), el("div", { className: "rb-booking-split-form rb-lg-col-span-3 rb-min-w-0" }, [bookingWizard])])]);
20878
20089
  const appointmentBookingBlockDefinition = {
20879
20090
  manifest: createBlockManifest({
20880
20091
  id: "block.appointment-booking",
@@ -20936,23 +20147,24 @@ const appointmentBookingBlockDefinition = {
20936
20147
  "reservation"
20937
20148
  ],
20938
20149
  icon: "Calendar",
20939
- layout: [styledSection({
20940
- children: sectionContainer([
20941
- text({ as: "h2" }, bind("content.heading"), when("content.heading")),
20942
- richText({}, bind("content.description"), when("content.description")),
20943
- bookingForm(withApiBindings({
20944
- portalToken: { $bind: {
20945
- from: "$root.portalToken",
20946
- fallback: null
20947
- } },
20948
- formId: { $bind: { from: "content.formId" } },
20949
- form: { $bind: { from: "data.form" } },
20950
- services: { $bind: { from: "data.services" } }
20951
- }))
20952
- ], { gap: "lg" }),
20953
- baseClass: "",
20954
- spacing: "spacious"
20955
- })]
20150
+ layout: [stackedLayout$1],
20151
+ variants: {
20152
+ default: stackedLayout$1,
20153
+ "split-copy": splitCopyLayout
20154
+ },
20155
+ defaultVariant: "default",
20156
+ variantOptions: {
20157
+ default: {
20158
+ label: "Stacked",
20159
+ description: "Heading and description above the booking form.",
20160
+ icon: "Rows2"
20161
+ },
20162
+ "split-copy": {
20163
+ label: "Split copy",
20164
+ description: "Pairs the wizard with your heading and intro copy, side by side; stacks on smaller screens.",
20165
+ icon: "Columns2"
20166
+ }
20167
+ }
20956
20168
  }),
20957
20169
  dataSchemas: { availability: z.object({ slots: z.array(z.object({
20958
20170
  startAt: z.string(),
@@ -21487,6 +20699,7 @@ const eventPresetSchema = z.enum([
21487
20699
  "event",
21488
20700
  "class",
21489
20701
  "course",
20702
+ "term",
21490
20703
  "workshop",
21491
20704
  "retreat",
21492
20705
  "performance"
@@ -21545,57 +20758,49 @@ z.enum([
21545
20758
  */
21546
20759
  const accessRestrictionSchema = z.enum(["none", "category"]);
21547
20760
  z.enum(["single", "ticket_types"]);
20761
+ const freePriceDisplaySchema = z.object({
20762
+ kind: z.literal("free"),
20763
+ currency: z.string()
20764
+ });
20765
+ const exactPriceDisplaySchema = z.object({
20766
+ kind: z.literal("exact"),
20767
+ amount: z.number(),
20768
+ currency: z.string()
20769
+ });
20770
+ const fromPriceDisplaySchema = z.object({
20771
+ kind: z.literal("from"),
20772
+ amount: z.number(),
20773
+ currency: z.string()
20774
+ });
20775
+ const unavailablePriceDisplaySchema = z.object({
20776
+ kind: z.literal("unavailable"),
20777
+ currency: z.string()
20778
+ });
20779
+ const rangePriceDisplaySchema = z.object({
20780
+ kind: z.literal("range"),
20781
+ minAmount: z.number(),
20782
+ maxAmount: z.number(),
20783
+ currency: z.string()
20784
+ });
20785
+ const mixedPriceDisplaySchema = z.object({
20786
+ kind: z.literal("mixed"),
20787
+ paidFromAmount: z.number(),
20788
+ paidToAmount: z.number(),
20789
+ currency: z.string()
20790
+ });
21548
20791
  const publicCoursePriceDisplaySchema = z.discriminatedUnion("kind", [
21549
- z.object({
21550
- kind: z.literal("free"),
21551
- currency: z.string()
21552
- }),
21553
- z.object({
21554
- kind: z.literal("exact"),
21555
- amount: z.number(),
21556
- currency: z.string()
21557
- }),
21558
- z.object({
21559
- kind: z.literal("from"),
21560
- amount: z.number(),
21561
- currency: z.string()
21562
- }),
21563
- z.object({
21564
- kind: z.literal("unavailable"),
21565
- currency: z.string()
21566
- })
20792
+ freePriceDisplaySchema,
20793
+ exactPriceDisplaySchema,
20794
+ fromPriceDisplaySchema,
20795
+ unavailablePriceDisplaySchema
21567
20796
  ]);
21568
20797
  z.discriminatedUnion("kind", [
21569
- z.object({
21570
- kind: z.literal("free"),
21571
- currency: z.string()
21572
- }),
21573
- z.object({
21574
- kind: z.literal("exact"),
21575
- amount: z.number(),
21576
- currency: z.string()
21577
- }),
21578
- z.object({
21579
- kind: z.literal("from"),
21580
- amount: z.number(),
21581
- currency: z.string()
21582
- }),
21583
- z.object({
21584
- kind: z.literal("range"),
21585
- minAmount: z.number(),
21586
- maxAmount: z.number(),
21587
- currency: z.string()
21588
- }),
21589
- z.object({
21590
- kind: z.literal("mixed"),
21591
- paidFromAmount: z.number(),
21592
- paidToAmount: z.number(),
21593
- currency: z.string()
21594
- }),
21595
- z.object({
21596
- kind: z.literal("unavailable"),
21597
- currency: z.string()
21598
- }),
20798
+ freePriceDisplaySchema,
20799
+ exactPriceDisplaySchema,
20800
+ fromPriceDisplaySchema,
20801
+ rangePriceDisplaySchema,
20802
+ mixedPriceDisplaySchema,
20803
+ unavailablePriceDisplaySchema,
21599
20804
  z.object({
21600
20805
  kind: z.literal("external"),
21601
20806
  label: z.string()
@@ -21606,36 +20811,12 @@ z.discriminatedUnion("kind", [
21606
20811
  })
21607
20812
  ]);
21608
20813
  const publicEventTicketTypePriceDisplaySchema = z.union([
21609
- z.object({
21610
- kind: z.literal("free"),
21611
- currency: z.string()
21612
- }),
21613
- z.object({
21614
- kind: z.literal("exact"),
21615
- amount: z.number(),
21616
- currency: z.string()
21617
- }),
21618
- z.object({
21619
- kind: z.literal("from"),
21620
- amount: z.number(),
21621
- currency: z.string()
21622
- }),
21623
- z.object({
21624
- kind: z.literal("range"),
21625
- minAmount: z.number(),
21626
- maxAmount: z.number(),
21627
- currency: z.string()
21628
- }),
21629
- z.object({
21630
- kind: z.literal("mixed"),
21631
- paidFromAmount: z.number(),
21632
- paidToAmount: z.number(),
21633
- currency: z.string()
21634
- }),
21635
- z.object({
21636
- kind: z.literal("unavailable"),
21637
- currency: z.string()
21638
- })
20814
+ freePriceDisplaySchema,
20815
+ exactPriceDisplaySchema,
20816
+ fromPriceDisplaySchema,
20817
+ rangePriceDisplaySchema,
20818
+ mixedPriceDisplaySchema,
20819
+ unavailablePriceDisplaySchema
21639
20820
  ]);
21640
20821
  const publicEventAttendanceModeSchema = z.enum(["in_person", "online"]);
21641
20822
  const publicEventAttendanceModeAvailabilitySchema = z.object({
@@ -21749,6 +20930,22 @@ const publicTeamMemberSummarySchema = z.object({
21749
20930
  summary: z.string().nullable(),
21750
20931
  profilePath: z.string().nullable()
21751
20932
  });
20933
+ const publicEventBookingAvailabilitySchema = z.discriminatedUnion("kind", [z.object({ kind: z.literal("open") }), z.object({
20934
+ kind: z.literal("closed"),
20935
+ reason: z.enum([
20936
+ "occurrence_cancelled",
20937
+ "occurrence_completed",
20938
+ "series_draft",
20939
+ "series_cancelled",
20940
+ "series_completed",
20941
+ "series_archived",
20942
+ "parent_archived",
20943
+ "parent_inconsistent",
20944
+ "not_public",
20945
+ "already_started",
20946
+ "enrollment_closed"
20947
+ ])
20948
+ })]);
21752
20949
  /**
21753
20950
  * Zod schema for public event data
21754
20951
  */
@@ -21773,6 +20970,7 @@ const publicEventSchema = z.object({
21773
20970
  path: z.string().nullable(),
21774
20971
  destination: publicEventDestinationSchema,
21775
20972
  requiresRegistration: z.boolean(),
20973
+ bookingAvailability: publicEventBookingAvailabilitySchema,
21776
20974
  deliveryMode: z.enum([
21777
20975
  "in_person",
21778
20976
  "online",
@@ -21791,6 +20989,8 @@ const publicEventSchema = z.object({
21791
20989
  status: z.enum([
21792
20990
  "active",
21793
20991
  "draft",
20992
+ "cancelled",
20993
+ "completed",
21794
20994
  "archived"
21795
20995
  ]).optional(),
21796
20996
  timeZone: z.string(),
@@ -21970,6 +21170,7 @@ function normalizeIdList(parts) {
21970
21170
  //#region ../blocks/src/system/blocks/events/shared/filtering.ts
21971
21171
  const eventSurfacePresetValues = [
21972
21172
  "course",
21173
+ "term",
21973
21174
  "class",
21974
21175
  "workshop",
21975
21176
  "retreat",
@@ -22103,6 +21304,7 @@ const unsupportedEventRegistrationPageSurfaceSubjectSchema = z.object({
22103
21304
  reason: z.enum([
22104
21305
  "unsupportedSubject",
22105
21306
  "invalidEventSeriesId",
21307
+ "invalidEventSeriesBookingScope",
22106
21308
  "invalidEventOfferingId"
22107
21309
  ])
22108
21310
  });
@@ -22850,6 +22052,10 @@ const eventRegistrationBlockDefinition = {
22850
22052
  },
22851
22053
  wholeSeriesOffering: {
22852
22054
  endpoint: "getPublicWholeSeriesOffering",
22055
+ when: { $bind: {
22056
+ from: "$root.subject.isWholeSeriesBooking",
22057
+ fallback: false
22058
+ } },
22853
22059
  params: {
22854
22060
  siteId: { $bind: { from: "$root.siteId" } },
22855
22061
  eventSeriesId: { $bind: { from: "$root.subject.eventSeriesId" } },
@@ -23683,11 +22889,14 @@ const eventSpotlightBlockDefinition = {
23683
22889
  };
23684
22890
  //#endregion
23685
22891
  //#region ../blocks/src/system/runtime/nodes/events/shared/utils.ts
23686
- /** Column class mappings for grid layouts */
22892
+ /**
22893
+ * Column class mappings for grid layouts, derived from the canonical
22894
+ * responsive column ladder (see gridUserColumnLadder).
22895
+ */
23687
22896
  const COLUMN_CLASSES = {
23688
- "2": "rb-sm-grid-cols-2",
23689
- "3": "rb-sm-grid-cols-2 rb-lg-grid-cols-3",
23690
- "4": "rb-sm-grid-cols-2 rb-lg-grid-cols-3 rb-xl-grid-cols-4"
22897
+ "2": gridUserColumnClasses(2),
22898
+ "3": gridUserColumnClasses(3),
22899
+ "4": gridUserColumnClasses(4)
23691
22900
  };
23692
22901
  /**
23693
22902
  * Build container class based on layout mode
@@ -23699,7 +22908,7 @@ function getContainerClass(layout, columns) {
23699
22908
  if (layout === "compact") return "event-listing-compact-container rb-flex rb-flex-col";
23700
22909
  if (layout === "stack") return "rb-flex rb-flex-col rb-gap-6";
23701
22910
  const fallbackColumnClass = COLUMN_CLASSES["3"] ?? "";
23702
- return `rb-grid rb-items-stretch rb-grid-cols-1 rb-gap-6 ${COLUMN_CLASSES[columns] ?? fallbackColumnClass}`;
22911
+ return `rb-grid rb-items-stretch rb-gap-6 ${COLUMN_CLASSES[columns] ?? fallbackColumnClass}`;
23703
22912
  }
23704
22913
  /**
23705
22914
  * Get card orientation based on layout mode
@@ -27451,8 +26660,8 @@ const audioPlayerBlockDefinition = { manifest: createBlockManifest({
27451
26660
  }
27452
26661
  ],
27453
26662
  layout: styledSection({
27454
- children: stack({ className: "rb-container rb-mx-auto rb-max-w-3xl" }, [el("div", { className: "card-surface rb-overflow-hidden" }, [media({
27455
- className: "rb-aspect-video rb-w-full rb-object-cover",
26663
+ children: stack({ className: "rb-container rb-mx-auto rb-max-w-3xl" }, [el("div", { className: "card-role-default" }, [media({
26664
+ className: "card-media rb-aspect-video rb-w-full rb-object-cover",
27456
26665
  size: {
27457
26666
  width: 960,
27458
26667
  height: 540,
@@ -29655,6 +28864,28 @@ const newsletterSignupBlockDefinition = {
29655
28864
  //#endregion
29656
28865
  //#region ../blocks/src/system/blocks/team-members.ts
29657
28866
  const ITEM_NAME = "member";
28867
+ /**
28868
+ * Team members gains a card surface with the role contract (issue 1297, Phase
28869
+ * 2b): the repeated member wrapper renders whatever card the site style's role
28870
+ * resolves to. No Look assigns the block a role yet, and with no compiled card
28871
+ * styles the binding contributes nothing, so today's rendering is unchanged.
28872
+ */
28873
+ const memberCardClassName = { $bind: {
28874
+ from: "content._cardStyles",
28875
+ transforms: [{
28876
+ id: "boxStyles.all",
28877
+ options: {
28878
+ axis: "all",
28879
+ baseClass: ""
28880
+ }
28881
+ }],
28882
+ fallback: ""
28883
+ } };
28884
+ const memberPhotoClassName = (baseClass) => cardRoleChildClass({
28885
+ emit: "media",
28886
+ baseClass,
28887
+ stylesFrom: "content._cardStyles"
28888
+ });
29658
28889
  const teamMemberPhotoSchema = mediaSchema.refine((media) => media.type === "image", { message: "Team member photos must be image media" }).nullable();
29659
28890
  const teamMemberDataSchema = z.object({
29660
28891
  _type: z.literal("teamMember"),
@@ -29710,7 +28941,7 @@ const wrapVariant = (variantLayout) => styledSection({
29710
28941
  baseClass: "",
29711
28942
  spacing: "comfortable"
29712
28943
  });
29713
- const teamMemberStackLayout = el("div", { className: "rb-team-member rb-team-member--stack rb-flex rb-flex-col rb-md-flex-row rb-items-start rb-gap-3" }, [el("div", { className: "rb-team-member-photo-col rb-w-full rb-shrink-0" }, [el("div", { className: "rb-team-member-photo-wrap rb-w-full" }, [media({
28944
+ const teamMemberStackLayout = el("div", { className: "rb-team-member rb-team-member--stack rb-flex rb-flex-col rb-md-flex-row rb-items-start rb-gap-3" }, [el("div", { className: "rb-team-member-photo-col rb-w-full rb-shrink-0" }, [el("div", { className: memberPhotoClassName("rb-team-member-photo-wrap rb-w-full") }, [media({
29714
28945
  className: "rb-team-member-photo rb-w-full rb-object-cover",
29715
28946
  style: { aspectRatio: "1 / 1" },
29716
28947
  size: {
@@ -29734,27 +28965,27 @@ const teamMemberStackLayout = el("div", { className: "rb-team-member rb-team-mem
29734
28965
  }, when("role"), bind("role")),
29735
28966
  richText({ className: "rb-prose rb-max-w-none" }, when("bio"), bind("bio"))
29736
28967
  ])]);
29737
- const gridVariant = wrapVariant(el("grid", {
29738
- cols: { $bind: {
29739
- from: "content.columns",
29740
- fallback: 3,
29741
- coerce: "number"
29742
- } },
29743
- gap: { $bind: {
29744
- from: "content.gap",
29745
- fallback: "medium"
29746
- } }
29747
- }, [when("content.source", manualSourceWhen)(repeaterFragmentLayout({
28968
+ const manualGridMembersNode = when("content.source", manualSourceWhen)(repeaterFragmentLayout({
29748
28969
  collectionPath: "content.members",
29749
28970
  itemName: ITEM_NAME,
29750
28971
  fragments: { teamMember: teamMemberFragment },
29751
- itemGap: "sm"
29752
- })), when("content.source", dynamicSourceWhen)(repeaterFragmentLayout({
28972
+ itemGap: "sm",
28973
+ itemClassName: memberCardClassName
28974
+ }));
28975
+ const dynamicGridMembersNode = when("content.source", dynamicSourceWhen)(repeaterFragmentLayout({
29753
28976
  collectionPath: "data.members",
29754
28977
  itemName: ITEM_NAME,
29755
28978
  fragments: { teamMember: teamMemberFragment },
29756
- itemGap: "sm"
29757
- }))]));
28979
+ itemGap: "sm",
28980
+ itemClassName: memberCardClassName
28981
+ }));
28982
+ const gridVariant = wrapVariant(el("grid", {
28983
+ userColumns: userColumnsGridBinding(),
28984
+ gap: { $bind: {
28985
+ from: "content.gap",
28986
+ fallback: "medium"
28987
+ } }
28988
+ }, [manualGridMembersNode, dynamicGridMembersNode]));
29758
28989
  const stackVariant = wrapVariant({
29759
28990
  type: "stack",
29760
28991
  props: { gap: { $bind: {
@@ -29766,13 +28997,15 @@ const stackVariant = wrapVariant({
29766
28997
  itemName: ITEM_NAME,
29767
28998
  fragments: { teamMember: teamMemberFragment },
29768
28999
  layoutOverrides: { teamMember: teamMemberStackLayout },
29769
- itemGap: "sm"
29000
+ itemGap: "sm",
29001
+ itemClassName: memberCardClassName
29770
29002
  })), when("content.source", dynamicSourceWhen)(repeaterFragmentLayout({
29771
29003
  collectionPath: "data.members",
29772
29004
  itemName: ITEM_NAME,
29773
29005
  fragments: { teamMember: teamMemberFragment },
29774
29006
  layoutOverrides: { teamMember: teamMemberStackLayout },
29775
- itemGap: "sm"
29007
+ itemGap: "sm",
29008
+ itemClassName: memberCardClassName
29776
29009
  }))]
29777
29010
  });
29778
29011
  const teamMembersBlockDefinition = {
@@ -29922,66 +29155,11 @@ const teamMembersBlockDefinition = {
29922
29155
  }
29923
29156
  }
29924
29157
  }),
29925
- parseFieldDefinition({
29926
- id: "columns",
29927
- type: "select",
29928
- label: "Columns",
29929
- defaultValue: "3",
29930
- options: [
29931
- {
29932
- value: "2",
29933
- label: "2 columns"
29934
- },
29935
- {
29936
- value: "3",
29937
- label: "3 columns"
29938
- },
29939
- {
29940
- value: "4",
29941
- label: "4 columns"
29942
- }
29943
- ],
29944
- ui: {
29945
- intent: "display",
29946
- visibleWhen: {
29947
- field: "variant",
29948
- equals: "grid"
29949
- }
29950
- }
29951
- }),
29952
- parseFieldDefinition({
29953
- id: "gap",
29954
- type: "select",
29955
- label: "Gap",
29956
- defaultValue: "medium",
29957
- options: [
29958
- {
29959
- value: "none",
29960
- label: "None"
29961
- },
29962
- {
29963
- value: "compact",
29964
- label: "Compact"
29965
- },
29966
- {
29967
- value: "cozy",
29968
- label: "Cozy"
29969
- },
29970
- {
29971
- value: "medium",
29972
- label: "Medium"
29973
- },
29974
- {
29975
- value: "comfortable",
29976
- label: "Comfortable"
29977
- },
29978
- {
29979
- value: "spacious",
29980
- label: "Spacious"
29981
- }
29982
- ],
29983
- ui: { intent: "display" }
29984
- }),
29158
+ columnsSelectField({ visibleWhen: {
29159
+ field: "variant",
29160
+ equals: "grid"
29161
+ } }),
29162
+ gapSelectField(),
29985
29163
  {
29986
29164
  ...fragmentsToRepeaterField("members", "Team members", { teamMember: teamMemberFragment }, {
29987
29165
  minItems: 0,
@@ -29997,7 +29175,11 @@ const teamMembersBlockDefinition = {
29997
29175
  equals: "manual"
29998
29176
  }
29999
29177
  }
30000
- }
29178
+ },
29179
+ cardStylesField({
29180
+ id: "_cardStyles",
29181
+ label: "Member card styles"
29182
+ })
30001
29183
  ],
30002
29184
  layout: gridVariant,
30003
29185
  variants: {
@@ -30415,14 +29597,14 @@ function sectionOnly() {
30415
29597
  return declareBlockDesignCapability({
30416
29598
  sectionSurfaces: "supported",
30417
29599
  contentFrames: ["plain"],
30418
- itemSurfaces: "unsupported"
29600
+ cardRoles: "unsupported"
30419
29601
  });
30420
29602
  }
30421
29603
  function panelCapable() {
30422
29604
  return declareBlockDesignCapability({
30423
29605
  sectionSurfaces: "supported",
30424
29606
  contentFrames: ["plain", "panel"],
30425
- itemSurfaces: "unsupported"
29607
+ cardRoles: "unsupported"
30426
29608
  });
30427
29609
  }
30428
29610
  const heroSectionHeights = [
@@ -30460,7 +29642,7 @@ function heroCapable() {
30460
29642
  sectionSurfaces: "supported",
30461
29643
  richBackgrounds: "supported",
30462
29644
  contentFrames: ["plain", "panel"],
30463
- itemSurfaces: "unsupported",
29645
+ cardRoles: "unsupported",
30464
29646
  sectionHeights: heroSectionHeights,
30465
29647
  imageSurfaceTreatments: heroImageSurfaceTreatments,
30466
29648
  imageSurfaceMotions: heroImageSurfaceMotions
@@ -30470,14 +29652,14 @@ function plainItemsCapable() {
30470
29652
  return declareBlockDesignCapability({
30471
29653
  sectionSurfaces: "supported",
30472
29654
  contentFrames: ["plain"],
30473
- itemSurfaces: "supported"
29655
+ cardRoles: "supported"
30474
29656
  });
30475
29657
  }
30476
29658
  function panelAndItemsCapable() {
30477
29659
  return declareBlockDesignCapability({
30478
29660
  sectionSurfaces: "supported",
30479
29661
  contentFrames: ["plain", "panel"],
30480
- itemSurfaces: "supported"
29662
+ cardRoles: "supported"
30481
29663
  });
30482
29664
  }
30483
29665
  function mediaPanelCapable() {
@@ -30488,7 +29670,7 @@ function mediaPanelCapable() {
30488
29670
  "panel",
30489
29671
  "flush-panel"
30490
29672
  ],
30491
- itemSurfaces: "unsupported"
29673
+ cardRoles: "supported"
30492
29674
  });
30493
29675
  }
30494
29676
  const allSectionSurfaces = [
@@ -30521,7 +29703,7 @@ function scheduleDetailsCapable() {
30521
29703
  looks: "supported",
30522
29704
  sectionSurfaces: "supported",
30523
29705
  contentFrames: ["plain"],
30524
- itemSurfaces: "unsupported",
29706
+ cardRoles: "unsupported",
30525
29707
  tileTreatments: scheduleTileTreatments
30526
29708
  });
30527
29709
  }
@@ -30530,7 +29712,7 @@ function eventListCapable() {
30530
29712
  looks: "supported",
30531
29713
  sectionSurfaces: "supported",
30532
29714
  contentFrames: ["plain", "panel"],
30533
- itemSurfaces: "unsupported",
29715
+ cardRoles: "unsupported",
30534
29716
  eventListTreatments
30535
29717
  });
30536
29718
  }
@@ -30539,7 +29721,7 @@ function offeringsPreviewCapable() {
30539
29721
  looks: "supported",
30540
29722
  sectionSurfaces: "supported",
30541
29723
  contentFrames: ["plain"],
30542
- itemSurfaces: "supported"
29724
+ cardRoles: "supported"
30543
29725
  });
30544
29726
  }
30545
29727
  function defaultBoundaryBias(visualWeight) {
@@ -30658,7 +29840,7 @@ const systemBlockDefinitions = [
30658
29840
  looks: "supported",
30659
29841
  sectionSurfaces: "supported",
30660
29842
  contentFrames: ["plain", "panel"],
30661
- itemSurfaces: "unsupported",
29843
+ cardRoles: "unsupported",
30662
29844
  compositions: {
30663
29845
  kind: "intro",
30664
29846
  treatments: ["editorial-statement", "portrait-bio"]
@@ -30785,7 +29967,7 @@ const systemBlockDefinitions = [
30785
29967
  withDesignCapability("block.faq", faqBlockDefinition, withLookCapability(withEyebrowCapability(declareBlockDesignCapability({
30786
29968
  sectionSurfaces: "supported",
30787
29969
  contentFrames: ["plain", "panel"],
30788
- itemSurfaces: "supported",
29970
+ cardRoles: "supported",
30789
29971
  accordionIconSets: [
30790
29972
  "plus",
30791
29973
  "chevron",
@@ -30829,14 +30011,11 @@ const systemBlockDefinitions = [
30829
30011
  looks: "supported",
30830
30012
  sectionSurfaces: "supported",
30831
30013
  contentFrames: ["plain", "panel"],
30832
- itemSurfaces: "supported",
30833
- testimonialCardTreatments: [
30834
- "default",
30835
- "statement",
30836
- "non-carded",
30837
- "accent-quote",
30838
- "editorial-serif-quote"
30839
- ],
30014
+ cardRoles: "supported",
30015
+ compositions: {
30016
+ kind: "testimonials",
30017
+ treatments: ["open-editorial"]
30018
+ },
30840
30019
  headingDecorationCapability: {
30841
30020
  kind: "supported",
30842
30021
  families: ["short-center-rule"]
@@ -30896,7 +30075,7 @@ const systemBlockDefinitions = [
30896
30075
  looks: "supported",
30897
30076
  sectionSurfaces: "supported",
30898
30077
  contentFrames: ["plain", "panel"],
30899
- itemSurfaces: "supported",
30078
+ cardRoles: "supported",
30900
30079
  compositions: {
30901
30080
  kind: "feature-cards",
30902
30081
  treatments: ["asymmetric-emphasis", "framed-programme"]
@@ -30938,12 +30117,16 @@ const systemBlockDefinitions = [
30938
30117
  bias: "soft"
30939
30118
  })]
30940
30119
  })),
30941
- withDesignCapability("block.appointment-booking", appointmentBookingBlockDefinition, sectionOnly(), defineBlockDesignMetadata({
30120
+ withDesignCapability("block.appointment-booking", appointmentBookingBlockDefinition, withLookCapability(sectionOnly()), defineBlockDesignMetadata({
30942
30121
  flow: conversionFlow,
30943
30122
  layoutProfiles: [layoutProfile({
30944
30123
  variantKey: "default",
30945
30124
  family: "form",
30946
30125
  weight: "standard"
30126
+ }), layoutProfile({
30127
+ variantKey: "split-copy",
30128
+ family: "split",
30129
+ weight: "standard"
30947
30130
  })]
30948
30131
  })),
30949
30132
  withDesignCapability("block.weekly-slot-availability", weeklySlotAvailabilityBlockDefinition, sectionOnly(), defineBlockDesignMetadata({
@@ -31048,7 +30231,11 @@ const systemBlockDefinitions = [
31048
30231
  weight: "standard"
31049
30232
  })]
31050
30233
  })),
31051
- withDesignCapability("block.team-members", teamMembersBlockDefinition, sectionOnly(), defineBlockDesignMetadata({
30234
+ withDesignCapability("block.team-members", teamMembersBlockDefinition, declareBlockDesignCapability({
30235
+ sectionSurfaces: "supported",
30236
+ contentFrames: ["plain"],
30237
+ cardRoles: "supported"
30238
+ }), defineBlockDesignMetadata({
31052
30239
  flow: proofFlow,
31053
30240
  layoutProfiles: [layoutProfile({
31054
30241
  variantKey: "grid",