@riverbankcms/sdk 0.144.0 → 0.146.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (228) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/{PreviewEditorSidebar-CQZNnFiM.mjs → PreviewEditorSidebar-kg2r2Fyi.mjs} +4 -4
  3. package/dist/{PreviewEditorUI-DCNxnmI0.mjs → PreviewEditorUI-sWMLp5dT.mjs} +3 -3
  4. package/dist/{PreviewQueryProvider-BCYICImX.mjs → PreviewQueryProvider-Cg51xq1w.mjs} +1 -1
  5. package/dist/{SdkPreviewModeRuntime-BJolUbr1.mjs → SdkPreviewModeRuntime-h2ti3Hch.mjs} +688 -519
  6. package/dist/{SiteChromeCustomizeContext-CKgEpoxi.mjs → SiteChromeCustomizeContext-DEACFH9m.mjs} +3381 -2017
  7. package/dist/_dts/ai/src/contracts/proposals.d.ts +5643 -66
  8. package/dist/_dts/ai/src/contracts/siteStyleProposalSchemas.d.ts +513 -6
  9. package/dist/_dts/api/src/appointmentEndpointDefinitions.d.ts +49 -0
  10. package/dist/_dts/api/src/appointmentServiceCategoryEndpoints.d.ts +75 -0
  11. package/dist/_dts/api/src/appointmentServiceContracts.d.ts +80 -0
  12. package/dist/_dts/api/src/appointmentSetup.d.ts +8 -1
  13. package/dist/_dts/api/src/bookingConfig.d.ts +8 -1
  14. package/dist/_dts/api/src/bookingManagementEndpoints.d.ts +10 -26
  15. package/dist/_dts/api/src/bookingManagementEventEndpointTypes.d.ts +45 -1
  16. package/dist/_dts/api/src/clientErrorReporting.d.ts +50 -0
  17. package/dist/_dts/api/src/communications.d.ts +32 -24
  18. package/dist/_dts/api/src/contentRuntime.d.ts +3 -5
  19. package/dist/_dts/api/src/endpoints.d.ts +316 -134
  20. package/dist/_dts/api/src/event-visibility.d.ts +20 -0
  21. package/dist/_dts/api/src/eventManagementContracts.d.ts +56 -3
  22. package/dist/_dts/api/src/eventManagementEndpointDefinitions.d.ts +24 -0
  23. package/dist/_dts/api/src/eventPageWords.d.ts +19 -0
  24. package/dist/_dts/api/src/eventSeriesRegistrationEndpointDefinitions.d.ts +14 -0
  25. package/dist/_dts/api/src/index.d.ts +7 -1
  26. package/dist/_dts/api/src/indexCoreTypes.d.ts +1 -1
  27. package/dist/_dts/api/src/indexExtendedTypes.d.ts +1 -1
  28. package/dist/_dts/api/src/launchReadiness.d.ts +22 -2
  29. package/dist/_dts/api/src/launchRequirementPriority.d.ts +3 -0
  30. package/dist/_dts/api/src/newsletterCampaignCommandEndpoints.d.ts +13 -0
  31. package/dist/_dts/api/src/newsletterEndpointDefinitions.d.ts +30 -11
  32. package/dist/_dts/api/src/occurrenceScheduling.d.ts +10 -0
  33. package/dist/_dts/api/src/onboarding/confirmationResend.d.ts +3 -0
  34. package/dist/_dts/api/src/pageSurfaceEndpoints.d.ts +44 -0
  35. package/dist/_dts/api/src/participantMessaging.d.ts +11 -1
  36. package/dist/_dts/api/src/publicBookingService.d.ts +35 -1
  37. package/dist/_dts/api/src/publicExperience/newsletterEndpoints.d.ts +13 -0
  38. package/dist/_dts/api/src/publicNewsletterEndpointDefinitions.d.ts +58 -0
  39. package/dist/_dts/api/src/schemas/admin-observability-logs.d.ts +3 -3
  40. package/dist/_dts/api/src/sdk-event-upsert.d.ts +40 -1
  41. package/dist/_dts/api/src/sdkContracts.d.ts +3 -42
  42. package/dist/_dts/api/src/sdkCourseBooking.d.ts +30 -0
  43. package/dist/_dts/api/src/sdkEventEndpointDefinitions.d.ts +76 -0
  44. package/dist/_dts/api/src/sdkEventLifecycle.d.ts +37 -0
  45. package/dist/_dts/api/src/sdkManagedEventContracts.d.ts +18 -0
  46. package/dist/_dts/api/src/sdkPageDesign.d.ts +388 -0
  47. package/dist/_dts/api/src/sdkPageDesignEndpointDefinitions.d.ts +22 -0
  48. package/dist/_dts/api/src/sdkPullEventContracts.d.ts +46 -0
  49. package/dist/_dts/api/src/siteAddressEndpoints.d.ts +29 -0
  50. package/dist/_dts/api/src/siteManagementEndpointDefinitions.d.ts +49 -0
  51. package/dist/_dts/api/src/siteManagementEndpoints.d.ts +4 -38
  52. package/dist/_dts/api/src/siteOnboarding.d.ts +75 -9
  53. package/dist/_dts/api/src/sitePlatformEndpoints.d.ts +1 -1
  54. package/dist/_dts/api/src/types.d.ts +8 -1
  55. package/dist/_dts/api/src/wholeSeriesRuns.d.ts +14 -0
  56. package/dist/_dts/blocks/src/PageRenderer.d.ts +4 -4
  57. package/dist/_dts/blocks/src/bindings/index.d.ts +2 -2
  58. package/dist/_dts/blocks/src/contracts/proof-block-islands.d.ts +24 -0
  59. package/dist/_dts/blocks/src/index.d.ts +3 -1
  60. package/dist/_dts/blocks/src/pageRenderAdmission.d.ts +10 -0
  61. package/dist/_dts/blocks/src/pageRenderJoins.d.ts +68 -0
  62. package/dist/_dts/blocks/src/pageRenderPlan.d.ts +8 -27
  63. package/dist/_dts/blocks/src/pageRenderPreparation.d.ts +7 -4
  64. package/dist/_dts/blocks/src/pageRendererBoundaries.d.ts +40 -23
  65. package/dist/_dts/blocks/src/pageRendererContracts.d.ts +3 -1
  66. package/dist/_dts/blocks/src/server.d.ts +1 -1
  67. package/dist/_dts/blocks/src/system/blocks/appointment-services.d.ts +2 -0
  68. package/dist/_dts/blocks/src/system/blocks/events/eventSelectionFields.d.ts +2 -2
  69. package/dist/_dts/blocks/src/system/blocks/events/shared/calendarWindow.d.ts +1 -1
  70. package/dist/_dts/blocks/src/system/blocks/events/shared/schemas.d.ts +27 -5
  71. package/dist/_dts/blocks/src/system/blocks/events/shared/types.d.ts +14 -1
  72. package/dist/_dts/blocks/src/system/blocks/location-map.d.ts +2 -2
  73. package/dist/_dts/blocks/src/system/blocks/media-text.d.ts +47 -47
  74. package/dist/_dts/blocks/src/system/icons/social.d.ts +1 -1
  75. package/dist/_dts/blocks/src/system/manifest/schema.d.ts +29 -3
  76. package/dist/_dts/blocks/src/system/registry.d.ts +1 -1
  77. package/dist/_dts/blocks/src/system/runtime/hooks/useHeadlessBookingFlow.d.ts +8 -1
  78. package/dist/_dts/blocks/src/system/runtime/nodes/appointment-services.d.ts +22 -2
  79. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.headless.state.d.ts +3 -1
  80. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.interactive.d.ts +57 -2
  81. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.service-categories.d.ts +29 -0
  82. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.service-choices.d.ts +13 -0
  83. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.state.d.ts +3 -3
  84. package/dist/_dts/blocks/src/system/runtime/nodes/booking-runtime-sources.d.ts +13 -1
  85. package/dist/_dts/blocks/src/system/runtime/nodes/event-registration/eventSourceRecovery.d.ts +2 -1
  86. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/eventCollectionContract.d.ts +23 -7
  87. package/dist/_dts/blocks/src/system/runtime/nodes/form.fields.d.ts +5 -0
  88. package/dist/_dts/blocks/src/system/runtime/nodes/newsletter-form.block-submission.d.ts +36 -0
  89. package/dist/_dts/blocks/src/system/runtime/nodes/newsletter-form.client.d.ts +1 -1
  90. package/dist/_dts/blocks/src/system/runtime/nodes/newsletter-form.interactive.d.ts +6 -1
  91. package/dist/_dts/blocks/src/system/runtime/nodes/newsletter-form.parts.d.ts +46 -0
  92. package/dist/_dts/blocks/src/system/runtime/nodes/newsletter-form.submission.d.ts +20 -1
  93. package/dist/_dts/blocks/src/system/runtime/nodes/newsletter-form.types.d.ts +2 -1
  94. package/dist/_dts/blocks/src/system/runtime/resolver.d.ts +2 -1
  95. package/dist/_dts/blocks/src/system/runtime/shared/components/CheckboxChoice.d.ts +18 -0
  96. package/dist/_dts/blocks/src/system/runtime/shared/components/index.d.ts +1 -0
  97. package/dist/_dts/content-editor/src/index.d.ts +1 -0
  98. package/dist/_dts/content-editor/src/primitives/previewEditableOutline.d.ts +2 -0
  99. package/dist/_dts/content-editor/src/ui/editorBlockEquality.d.ts +3 -0
  100. package/dist/_dts/content-editor/src/ui/editorSnapshot.d.ts +3 -3
  101. package/dist/_dts/content-model/src/content-types/schema.d.ts +1 -1
  102. package/dist/_dts/core/src/appointment-service-categories.d.ts +108 -0
  103. package/dist/_dts/core/src/block-content-identity.d.ts +5 -0
  104. package/dist/_dts/core/src/editor-state.d.ts +2 -1
  105. package/dist/_dts/core/src/index.d.ts +2 -0
  106. package/dist/_dts/core/src/mailing-list-submission.d.ts +3 -1
  107. package/dist/_dts/core/src/public-event-booking-availability.d.ts +20 -1
  108. package/dist/_dts/core/src/public-profile.d.ts +12 -1
  109. package/dist/_dts/db/src/generated/supabase/database.types.d.ts +711 -242
  110. package/dist/_dts/editor-blocks/src/BlockEditor.d.ts +3 -0
  111. package/dist/_dts/editor-blocks/src/block-editor/EmptyState.d.ts +13 -1
  112. package/dist/_dts/editor-blocks/src/block-editor/types.d.ts +2 -2
  113. package/dist/_dts/editor-blocks/src/index.d.ts +1 -0
  114. package/dist/_dts/editor-blocks/src/widgets/site-option-picker/loaders.d.ts +16 -1
  115. package/dist/_dts/editor-blocks/src/widgets/site-option-picker/types.d.ts +13 -0
  116. package/dist/_dts/editor-blocks/src/widgets/site-option-picker/utils.d.ts +29 -0
  117. package/dist/_dts/preview-next/src/client/blocks/BoundaryControl.d.ts +7 -2
  118. package/dist/_dts/preview-next/src/client/blocks/composer/mergeDrafts.d.ts +1 -1
  119. package/dist/_dts/preview-next/src/client/blocks/composer/types.d.ts +3 -3
  120. package/dist/_dts/preview-next/src/client/blocks/previewProjection/applyPreviewProjections.d.ts +1 -3
  121. package/dist/_dts/preview-next/src/client/blocks/previewProjection/runtimeContentDecoration.d.ts +2 -2
  122. package/dist/_dts/preview-next/src/client/blocks/previewProjection/types.d.ts +2 -2
  123. package/dist/_dts/preview-next/src/client/preview/PreviewEntryControllerProvider.d.ts +1 -1
  124. package/dist/_dts/sdk/src/client/runtimeCacheKeys.d.ts +8 -0
  125. package/dist/_dts/sdk/src/client/types.d.ts +1 -1
  126. package/dist/_dts/sdk/src/contracts/index.d.ts +1 -1
  127. package/dist/_dts/sdk/src/contracts/page.d.ts +7 -2
  128. package/dist/_dts/sdk/src/contracts/system-block-content.d.ts +5 -0
  129. package/dist/_dts/sdk/src/manifest/passes/pass1-fields.d.ts +2 -2
  130. package/dist/_dts/sdk/src/next/renderSdkContent.d.ts +0 -1
  131. package/dist/_dts/sdk/src/public-api/contracts.d.ts +6 -8
  132. package/dist/_dts/sdk/src/rendering/blocks-page-renderer.d.ts +4 -4
  133. package/dist/_dts/sdk/src/rendering/components/pageShared.d.ts +4 -4
  134. package/dist/_dts/sdk/src/rendering/helpers/loadContent.d.ts +7 -2
  135. package/dist/_dts/sdk/src/rendering/helpers/loadPage.d.ts +5 -2
  136. package/dist/_dts/sdk/src/rendering/helpers/pageRuntimeSupport.d.ts +6 -1
  137. package/dist/_dts/sdk/src/rendering/helpers/templateContent.d.ts +2 -0
  138. package/dist/_dts/sdk/src/rendering/hooks/useContent.d.ts +6 -2
  139. package/dist/_dts/sdk/src/rendering/hooks/usePage.d.ts +5 -1
  140. package/dist/_dts/sdk/src/version.d.ts +1 -1
  141. package/dist/_dts/surfaces/src/index.d.ts +10 -0
  142. package/dist/_dts/theme-core/src/generated/containerResponsiveThemeCss.d.ts +1 -1
  143. package/dist/_dts/theme-core/src/inputs/checkable.d.ts +42 -0
  144. package/dist/_dts/theme-core/src/inputs/inputGroup.d.ts +19 -0
  145. package/dist/_dts/theme-core/src/layout/boundaryCss.d.ts +3 -0
  146. package/dist/_dts/theme-core/src/site-styles/compositionBudget.d.ts +8 -0
  147. package/dist/_dts/theme-core/src/site-styles/contentTemplateRuntimeCompiler.d.ts +3 -2
  148. package/dist/_dts/theme-core/src/site-styles/designState.d.ts +1 -3
  149. package/dist/_dts/theme-core/src/site-styles/generatedDesignPipeline.d.ts +3 -0
  150. package/dist/_dts/theme-core/src/site-styles/index.d.ts +3 -0
  151. package/dist/_dts/theme-core/src/site-styles/joinTreatment.d.ts +132 -0
  152. package/dist/_dts/theme-core/src/site-styles/pageDesignEditorBoundaries.d.ts +31 -0
  153. package/dist/_dts/theme-core/src/site-styles/pageDesignEditorModel.d.ts +33 -29
  154. package/dist/_dts/theme-core/src/site-styles/pageDesignIntent.d.ts +4 -4
  155. package/dist/_dts/theme-core/src/site-styles/pageFlowPresets.d.ts +36 -0
  156. package/dist/_dts/theme-core/src/site-styles/previewCompiler.d.ts +4 -10
  157. package/dist/_dts/theme-core/src/site-styles/rawStyleFields.d.ts +17 -4
  158. package/dist/_dts/theme-core/src/site-styles/runtimeCompiler.d.ts +20 -74
  159. package/dist/_dts/theme-core/src/site-styles/sectionBoundaryComposition.d.ts +95 -0
  160. package/dist/_dts/theme-core/src/site-styles/sectionTransitions.d.ts +80 -518
  161. package/dist/_dts/theme-core/src/site-styles/siteStyleBlockPolicies.d.ts +9 -4
  162. package/dist/_dts/theme-core/src/site-styles/transitionCatalogue.d.ts +320 -0
  163. package/dist/_dts/theme-core/src/site-styles/types.d.ts +3 -18
  164. package/dist/_dts/ui/src/navigation-tabs.d.ts +2 -1
  165. package/dist/client/{BookingConsentAgreement-DoAILrkN.mjs → BookingConsentAgreement-BQKL045f.mjs} +2 -2
  166. package/dist/client/CheckboxChoice--W2n6yKs.mjs +24 -0
  167. package/dist/client/{DiscountCodeDisclosure-X528hUTf.mjs → DiscountCodeDisclosure-CsOtjFY7.mjs} +1 -1
  168. package/dist/client/{EventCombined.client-DSBVwq5m.mjs → EventCombined.client-BdRjVbhH.mjs} +6 -6
  169. package/dist/client/{EventListing.client-DmFAX7Vb.mjs → EventListing.client-DBxC6xOU.mjs} +2 -2
  170. package/dist/client/{LeafletStaticMap-BAqXdfhq.mjs → LeafletStaticMap-mHEJKrTs.mjs} +1 -1
  171. package/dist/client/{ThemedButton-BwNFVwi4.mjs → ThemedButton-CE5KYT6z.mjs} +1 -1
  172. package/dist/client/{accordion-DRhMdkbd.mjs → accordion-BEQNSptH.mjs} +1 -1
  173. package/dist/client/{bookingForm-iJ_nCsNF.mjs → bookingForm-AMr-s5vw.mjs} +168 -95
  174. package/dist/client/bookings.mjs +239 -110
  175. package/dist/client/{carousel-D8zuffZr.mjs → carousel-Bbt_QgJy.mjs} +1 -1
  176. package/dist/client/{cart-DeMGJViN.mjs → cart-CnWi30zJ.mjs} +3 -3
  177. package/dist/client/{checkout-DXc06Km2.mjs → checkout-f3nkWgd4.mjs} +3 -3
  178. package/dist/client/client.mjs +3222 -1612
  179. package/dist/client/{context-CDLCfDep.mjs → context-Bc8T6pCe.mjs} +1 -1
  180. package/dist/client/{dates-ClFx7Epy.mjs → dates-DUsCEzLb.mjs} +2 -3
  181. package/dist/client/{eventCalendar-BaGpnOGN.mjs → eventCalendar-CKwgXui5.mjs} +9 -9
  182. package/dist/client/{eventCombined-ywONOx2m.mjs → eventCombined-CBAOSTGR.mjs} +4 -4
  183. package/dist/client/{eventDetails-B2LlOTYY.mjs → eventDetails-Dh-_WiBD.mjs} +4 -4
  184. package/dist/client/{eventListing-CMgxWpqP.mjs → eventListing-CA3frIH5.mjs} +4 -4
  185. package/dist/client/{eventRegistration-BarLDNHR.mjs → eventRegistration-BHtsgdcg.mjs} +21 -22
  186. package/dist/client/{form-BjqKaBJ7.mjs → form-C2h3YAcg.mjs} +135 -104
  187. package/dist/client/{headerSection-CP4XDwz1.mjs → headerSection-lwMuMTH9.mjs} +3 -3
  188. package/dist/client/hooks.mjs +1023 -148
  189. package/dist/client/{locationMap-C5gW-d-w.mjs → locationMap-DJ2bLODV.mjs} +3 -3
  190. package/dist/client/{newsletterForm-afXlVSA0.mjs → newsletterForm-8Pu5K32g.mjs} +225 -102
  191. package/dist/client/{pricing-Bl1CAl28.mjs → pricing-HHx3IgBz.mjs} +1 -1
  192. package/dist/client/{productDetail-CvQ3jWQe.mjs → productDetail-C_1odnAf.mjs} +3 -3
  193. package/dist/client/{productList-U874PGO7.mjs → productList-CtCv-Nmx.mjs} +3 -3
  194. package/dist/client/{propsDecoder-DPXtCZWP.mjs → propsDecoder-Dcgsncxb.mjs} +111 -55
  195. package/dist/client/rendering/client.mjs +1389 -722
  196. package/dist/client/rendering/islands.mjs +17 -17
  197. package/dist/client/rendering.mjs +3136 -1400
  198. package/dist/client/{routeIslandApiConfig-NGYiUWXu.mjs → routeIslandApiConfig-CWLP7wu3.mjs} +1 -1
  199. package/dist/client/{scrollToBlock-0-C3DVhK.mjs → scrollToBlock-BNgaEUpo.mjs} +1 -1
  200. package/dist/client/{shop-BXjXhM9P.mjs → shop-DQXrQ8kJ.mjs} +7 -7
  201. package/dist/client/{shop-commerce-BZ6UlWJ7.mjs → shop-commerce-B88zmWWo.mjs} +6 -6
  202. package/dist/client/{shop-commerce-store-DlSBXb3D.mjs → shop-commerce-store-DtSfkKuX.mjs} +1 -1
  203. package/dist/client/{shopShared-kkEOiLPA.mjs → shopShared-cuaONpkJ.mjs} +4 -4
  204. package/dist/client/{useEventFilters-zvnnE1ro.mjs → useEventFilters-Bukew6Gb.mjs} +6 -6
  205. package/dist/preview-next/before-render.mjs +500 -165
  206. package/dist/preview-next/client/runtime.mjs +4 -4
  207. package/dist/preview-next/editor-base.css +11 -0
  208. package/dist/preview-next/keepAlive.mjs +460 -165
  209. package/dist/preview-next/middleware.mjs +461 -165
  210. package/dist/{previewAuthStore-JA6-I_sL.mjs → previewAuthStore-h5IgbSp4.mjs} +485 -165
  211. package/dist/{sdk-runtime-DFJlQt3q.mjs → sdk-runtime-DTc1uIXn.mjs} +2 -2
  212. package/dist/{separator-o8GHb1xh.mjs → separator-BpHS1KZK.mjs} +1 -1
  213. package/dist/server/components.mjs +3088 -1307
  214. package/dist/server/config-validation.mjs +927 -109
  215. package/dist/server/config.mjs +927 -109
  216. package/dist/server/data.mjs +939 -110
  217. package/dist/server/index.mjs +513 -169
  218. package/dist/server/next.mjs +2874 -1195
  219. package/dist/server/page-converter.mjs +420 -79
  220. package/dist/server/prebuild.mjs +1 -1
  221. package/dist/server/rendering/server.mjs +3071 -1289
  222. package/dist/server/rendering.mjs +3169 -1350
  223. package/dist/server/routing.mjs +1085 -159
  224. package/dist/server/server.mjs +1042 -291
  225. package/dist/server/theme-bridge.mjs +1658 -137
  226. package/dist/server/theme.mjs +6 -4
  227. package/dist/styles/index.css +186 -65
  228. package/package.json +2 -1
@@ -4809,12 +4809,23 @@ function defineExactCatalog() {
4809
4809
  function asDesignBlockId(value) {
4810
4810
  return brandNonEmptyString(value, "DesignBlockId");
4811
4811
  }
4812
+ function asDesignBoundaryId(value) {
4813
+ const boundaryId = brandNonEmptyString(value, "DesignBoundaryId");
4814
+ if (!boundaryId.startsWith("boundary:")) throw new Error(`DesignBoundaryId must start with "boundary:". Received: ${value}`);
4815
+ return boundaryId;
4816
+ }
4817
+ function asLayoutVariantKey(value) {
4818
+ return brandNonEmptyString(value, "LayoutVariantKey");
4819
+ }
4812
4820
  function asAppearancePresetId(value) {
4813
4821
  return brandNonEmptyString(value, "AppearancePresetId");
4814
4822
  }
4815
4823
  function asBoundaryOptionId(value) {
4816
4824
  return brandNonEmptyString(value, "BoundaryOptionId");
4817
4825
  }
4826
+ function asPageFlowPresetId(value) {
4827
+ return brandNonEmptyString(value, "PageFlowPresetId");
4828
+ }
4818
4829
  function asSiteStyleId(value) {
4819
4830
  const siteStyleId = brandNonEmptyString(value, "SiteStyleId");
4820
4831
  if (!siteStyleId.startsWith("site-style:")) throw new Error(`SiteStyleId must start with "site-style:". Received: ${value}`);
@@ -4823,6 +4834,18 @@ function asSiteStyleId(value) {
4823
4834
  function asDesignSystemTemplateId(value) {
4824
4835
  return brandNonEmptyString(value, "DesignSystemTemplateId");
4825
4836
  }
4837
+ function toNonEmptyReadonlyArray(values) {
4838
+ const [first, ...rest] = values;
4839
+ return first === void 0 ? null : [first, ...rest];
4840
+ }
4841
+ function requireNonEmptyReadonlyArray(values, message = "Expected a non-empty array.") {
4842
+ const result = toNonEmptyReadonlyArray(values);
4843
+ if (!result) throw new Error(message);
4844
+ return result;
4845
+ }
4846
+ function makeBoundaryId(previousBlockId, nextBlockId) {
4847
+ return asDesignBoundaryId(`boundary:${encodeURIComponent(previousBlockId)}:${encodeURIComponent(nextBlockId)}`);
4848
+ }
4826
4849
  function brandNonEmptyString(value, label) {
4827
4850
  if (value.length === 0) throw new Error(`${label} must be a non-empty string.`);
4828
4851
  return value;
@@ -4987,16 +5010,18 @@ const themeV2RuntimeStyleFieldNames = [
4987
5010
  "_frameStyles",
4988
5011
  "_sectionStyles",
4989
5012
  "_containerStyles",
4990
- "_cardStyles",
4991
- "_transitionStyles",
4992
- "styleGroup"
5013
+ "_cardStyles"
4993
5014
  ];
4994
5015
  const themeV2BlockSpecificRawStyleFieldNames = [
4995
5016
  "_contentCardStyles",
4996
5017
  "_heroLayoutStyles",
4997
5018
  "_textCardStyles"
4998
5019
  ];
4999
- const themeV2NormalEditorRawStyleFieldNames = [...themeV2RuntimeStyleFieldNames, ...themeV2BlockSpecificRawStyleFieldNames];
5020
+ const themeV2NormalEditorRawStyleFieldNames = [
5021
+ ...themeV2RuntimeStyleFieldNames,
5022
+ ...themeV2BlockSpecificRawStyleFieldNames,
5023
+ "styleGroup"
5024
+ ];
5000
5025
  new Set(themeV2NormalEditorRawStyleFieldNames);
5001
5026
  [...themeV2RuntimeStyleFieldNames, ...themeV2BlockSpecificRawStyleFieldNames];
5002
5027
  const pageDesignEditorBackgroundOverrideOwner = "page-design-editor";
@@ -8941,6 +8966,261 @@ z.object({
8941
8966
  authority: styleAuthoritySchema
8942
8967
  }).strict();
8943
8968
  //#endregion
8969
+ //#region ../theme-core/src/site-styles/transitionCatalogue.ts
8970
+ /**
8971
+ * Family order for pickers. Entries below are listed family by family in this
8972
+ * same order, so the flat option list and the grouped families agree.
8973
+ */
8974
+ const transitionCatalogueFamilies = [
8975
+ {
8976
+ id: "gradient",
8977
+ label: "Gradient"
8978
+ },
8979
+ {
8980
+ id: "wave",
8981
+ label: "Wave"
8982
+ },
8983
+ {
8984
+ id: "angle",
8985
+ label: "Angle"
8986
+ }
8987
+ ];
8988
+ const mediumHeight = "6rem + 2px";
8989
+ const compactHeight = "4.5rem + 2px";
8990
+ const largeHeight = "7rem + 2px";
8991
+ /**
8992
+ * The single source of transition vocabulary. Order is significant: it is the
8993
+ * order of `boundaryOptions` (after `none`) and of each family's variants,
8994
+ * which persisted pins, page-flow presets and the editor picker all rely on.
8995
+ *
8996
+ * Shapes match what `generateLayoutCss` draws today. Structured
8997
+ * amplitude/frequency treatments (issue 826) extend this list later.
8998
+ */
8999
+ const transitionCatalogueEntries = defineExactCatalog()([
9000
+ {
9001
+ intent: "soft-fade-short",
9002
+ optionId: asBoundaryOptionId("break:soft"),
9003
+ family: "gradient",
9004
+ variantId: "soft",
9005
+ label: "Soft",
9006
+ variantLabel: "Soft",
9007
+ treatment: {
9008
+ kind: "soft-fade",
9009
+ height: "medium",
9010
+ curve: "soft"
9011
+ },
9012
+ size: "medium",
9013
+ heightExpression: mediumHeight,
9014
+ shape: { kind: "fade" }
9015
+ },
9016
+ {
9017
+ intent: "soft-fade-long",
9018
+ optionId: asBoundaryOptionId("break:spacious"),
9019
+ family: "gradient",
9020
+ variantId: "spacious",
9021
+ label: "Spacious",
9022
+ variantLabel: "Spacious",
9023
+ treatment: {
9024
+ kind: "soft-fade",
9025
+ height: "large",
9026
+ curve: "spacious"
9027
+ },
9028
+ size: "spacious",
9029
+ heightExpression: "10rem",
9030
+ shape: { kind: "fade" }
9031
+ },
9032
+ {
9033
+ intent: "soft-fade-expansive",
9034
+ optionId: asBoundaryOptionId("break:expansive"),
9035
+ family: "gradient",
9036
+ variantId: "expansive",
9037
+ label: "Expansive",
9038
+ variantLabel: "Expansive",
9039
+ treatment: {
9040
+ kind: "soft-fade",
9041
+ height: "expansive",
9042
+ curve: "expansive"
9043
+ },
9044
+ size: "expansive",
9045
+ heightExpression: "14rem",
9046
+ shape: { kind: "fade" }
9047
+ },
9048
+ {
9049
+ intent: "wave-edge-balanced",
9050
+ optionId: asBoundaryOptionId("break:wave-balanced"),
9051
+ family: "wave",
9052
+ variantId: "balanced",
9053
+ label: "Balanced wave",
9054
+ variantLabel: "Balanced",
9055
+ treatment: {
9056
+ kind: "wave-edge",
9057
+ height: "medium",
9058
+ amplitude: "balanced",
9059
+ rhythm: "double",
9060
+ symmetry: "symmetrical"
9061
+ },
9062
+ size: "medium",
9063
+ heightExpression: mediumHeight,
9064
+ shape: {
9065
+ kind: "wave",
9066
+ mask: "balanced"
9067
+ }
9068
+ },
9069
+ {
9070
+ intent: "wave-edge",
9071
+ optionId: asBoundaryOptionId("break:wave"),
9072
+ family: "wave",
9073
+ variantId: "classic",
9074
+ label: "Classic wave",
9075
+ variantLabel: "Classic",
9076
+ treatment: {
9077
+ kind: "wave-edge",
9078
+ height: "medium",
9079
+ amplitude: "balanced",
9080
+ rhythm: "double",
9081
+ symmetry: "asymmetrical"
9082
+ },
9083
+ size: "medium",
9084
+ heightExpression: mediumHeight,
9085
+ shape: {
9086
+ kind: "wave",
9087
+ mask: "classic"
9088
+ }
9089
+ },
9090
+ {
9091
+ intent: "wave-edge-gentle",
9092
+ optionId: asBoundaryOptionId("break:wave-gentle"),
9093
+ family: "wave",
9094
+ variantId: "gentle",
9095
+ label: "Gentle wave",
9096
+ variantLabel: "Gentle",
9097
+ treatment: {
9098
+ kind: "wave-edge",
9099
+ height: "compact",
9100
+ amplitude: "subtle",
9101
+ rhythm: "single",
9102
+ symmetry: "symmetrical"
9103
+ },
9104
+ size: "compact",
9105
+ heightExpression: compactHeight,
9106
+ shape: {
9107
+ kind: "wave",
9108
+ mask: "gentle"
9109
+ }
9110
+ },
9111
+ {
9112
+ intent: "wave-edge-bold",
9113
+ optionId: asBoundaryOptionId("break:wave-bold"),
9114
+ family: "wave",
9115
+ variantId: "bold",
9116
+ label: "Bold wave",
9117
+ variantLabel: "Bold",
9118
+ treatment: {
9119
+ kind: "wave-edge",
9120
+ height: "large",
9121
+ amplitude: "bold",
9122
+ rhythm: "double",
9123
+ symmetry: "symmetrical"
9124
+ },
9125
+ size: "large",
9126
+ heightExpression: largeHeight,
9127
+ shape: {
9128
+ kind: "wave",
9129
+ mask: "bold"
9130
+ }
9131
+ },
9132
+ {
9133
+ intent: "wave-edge-drift",
9134
+ optionId: asBoundaryOptionId("break:wave-drift"),
9135
+ family: "wave",
9136
+ variantId: "drift",
9137
+ label: "Drift wave",
9138
+ variantLabel: "Drift",
9139
+ treatment: {
9140
+ kind: "wave-edge",
9141
+ height: "medium",
9142
+ amplitude: "balanced",
9143
+ rhythm: "double",
9144
+ symmetry: "drift"
9145
+ },
9146
+ size: "medium",
9147
+ heightExpression: mediumHeight,
9148
+ shape: {
9149
+ kind: "wave",
9150
+ mask: "drift"
9151
+ }
9152
+ },
9153
+ {
9154
+ intent: "angle-edge-subtle",
9155
+ optionId: asBoundaryOptionId("break:angle-subtle"),
9156
+ family: "angle",
9157
+ variantId: "subtle",
9158
+ label: "Subtle angle",
9159
+ variantLabel: "Subtle",
9160
+ treatment: {
9161
+ kind: "angle-edge",
9162
+ height: "compact",
9163
+ slope: "subtle",
9164
+ direction: "forward"
9165
+ },
9166
+ size: "compact",
9167
+ heightExpression: compactHeight,
9168
+ shape: {
9169
+ kind: "angle",
9170
+ polygon: {
9171
+ startTopPercent: 34,
9172
+ endTopPercent: 18
9173
+ }
9174
+ }
9175
+ },
9176
+ {
9177
+ intent: "angle-edge",
9178
+ optionId: asBoundaryOptionId("break:angle-balanced"),
9179
+ family: "angle",
9180
+ variantId: "balanced",
9181
+ label: "Balanced angle",
9182
+ variantLabel: "Balanced",
9183
+ treatment: {
9184
+ kind: "angle-edge",
9185
+ height: "medium",
9186
+ slope: "balanced",
9187
+ direction: "forward"
9188
+ },
9189
+ size: "medium",
9190
+ heightExpression: mediumHeight,
9191
+ shape: {
9192
+ kind: "angle",
9193
+ polygon: {
9194
+ startTopPercent: 42,
9195
+ endTopPercent: 8
9196
+ }
9197
+ }
9198
+ },
9199
+ {
9200
+ intent: "angle-edge-steep",
9201
+ optionId: asBoundaryOptionId("break:angle-steep"),
9202
+ family: "angle",
9203
+ variantId: "steep",
9204
+ label: "Steep angle",
9205
+ variantLabel: "Steep",
9206
+ treatment: {
9207
+ kind: "angle-edge",
9208
+ height: "large",
9209
+ slope: "steep",
9210
+ direction: "forward"
9211
+ },
9212
+ size: "large",
9213
+ heightExpression: largeHeight,
9214
+ shape: {
9215
+ kind: "angle",
9216
+ polygon: {
9217
+ startTopPercent: 54,
9218
+ endTopPercent: 0
9219
+ }
9220
+ }
9221
+ }
9222
+ ]);
9223
+ //#endregion
8944
9224
  //#region ../theme-core/src/site-styles/sectionTransitions.ts
8945
9225
  function boundaryRuntimeMetrics(family, size, heightExpression) {
8946
9226
  return {
@@ -8950,19 +9230,913 @@ function boundaryRuntimeMetrics(family, size, heightExpression) {
8950
9230
  reserveCss: `calc((${heightExpression}) / 2)`
8951
9231
  };
8952
9232
  }
8953
- boundaryRuntimeMetrics("gradient", "medium", "6rem + 2px"), boundaryRuntimeMetrics("gradient", "spacious", "10rem"), boundaryRuntimeMetrics("gradient", "expansive", "14rem"), boundaryRuntimeMetrics("wave", "medium", "6rem + 2px"), boundaryRuntimeMetrics("wave", "medium", "6rem + 2px"), boundaryRuntimeMetrics("wave", "compact", "4.5rem + 2px"), boundaryRuntimeMetrics("wave", "large", "7rem + 2px"), boundaryRuntimeMetrics("wave", "medium", "6rem + 2px"), boundaryRuntimeMetrics("angle", "medium", "6rem + 2px"), boundaryRuntimeMetrics("angle", "compact", "4.5rem + 2px"), boundaryRuntimeMetrics("angle", "large", "7rem + 2px");
8954
- asBoundaryOptionId("break:none");
8955
- asBoundaryOptionId("break:soft");
8956
- asBoundaryOptionId("break:spacious");
8957
- asBoundaryOptionId("break:expansive");
9233
+ new Map(transitionCatalogueEntries.map((entry) => [entry.intent, entry]));
9234
+ new Map(transitionCatalogueEntries.map((entry) => [entry.intent, boundaryRuntimeMetrics(entry.family, entry.size, entry.heightExpression)]));
9235
+ /**
9236
+ * The catalogue's compile-time coverage check guarantees an entry per
9237
+ * decorative intent, so a miss here is a broken invariant, not bad input.
9238
+ */
9239
+ function requireCatalogueValue(values, intent) {
9240
+ const value = values.get(intent);
9241
+ if (value === void 0) throw new Error(`Transition catalogue has no entry for ${intent}`);
9242
+ return value;
9243
+ }
9244
+ const noneBoundaryOption = {
9245
+ id: asBoundaryOptionId("break:none"),
9246
+ label: "None",
9247
+ transitionAfter: "none",
9248
+ treatment: { kind: "none" }
9249
+ };
9250
+ const boundaryOptionByIntent = new Map(transitionCatalogueEntries.map((entry) => [entry.intent, {
9251
+ id: entry.optionId,
9252
+ label: entry.label,
9253
+ transitionAfter: entry.intent,
9254
+ treatment: entry.treatment
9255
+ }]));
9256
+ function boundaryOptionForTransitionIntent(intent) {
9257
+ return requireCatalogueValue(boundaryOptionByIntent, intent);
9258
+ }
9259
+ const softBoundaryOption = boundaryOptionForTransitionIntent("soft-fade-short");
9260
+ const spaciousBoundaryOption = boundaryOptionForTransitionIntent("soft-fade-long");
9261
+ boundaryOptionForTransitionIntent("soft-fade-expansive");
9262
+ boundaryOptionForTransitionIntent("wave-edge");
9263
+ boundaryOptionForTransitionIntent("wave-edge-balanced");
9264
+ boundaryOptionForTransitionIntent("wave-edge-gentle");
9265
+ boundaryOptionForTransitionIntent("wave-edge-bold");
9266
+ boundaryOptionForTransitionIntent("wave-edge-drift");
9267
+ boundaryOptionForTransitionIntent("angle-edge-subtle");
9268
+ boundaryOptionForTransitionIntent("angle-edge");
9269
+ boundaryOptionForTransitionIntent("angle-edge-steep");
9270
+ /**
9271
+ * Must remain non-empty; downstream code indexes `[0]` as the documented default.
9272
+ */
9273
+ const boundaryOptions = [noneBoundaryOption, ...transitionCatalogueEntries.map((entry) => boundaryOptionForTransitionIntent(entry.intent))];
9274
+ const noneTransitionVariant = {
9275
+ familyId: "none",
9276
+ variantId: "none",
9277
+ label: "None",
9278
+ boundaryOption: noneBoundaryOption
9279
+ };
9280
+ function transitionVariantForEntry(entry) {
9281
+ return {
9282
+ familyId: entry.family,
9283
+ variantId: entry.variantId,
9284
+ label: entry.variantLabel,
9285
+ boundaryOption: boundaryOptionForTransitionIntent(entry.intent)
9286
+ };
9287
+ }
9288
+ const sectionTransitionFamilies = [{
9289
+ id: "none",
9290
+ label: "None",
9291
+ variants: [noneTransitionVariant]
9292
+ }, ...transitionCatalogueFamilies.map((family) => ({
9293
+ id: family.id,
9294
+ label: family.label,
9295
+ variants: requireNonEmptyReadonlyArray(transitionCatalogueEntries.filter((entry) => entry.family === family.id).map(transitionVariantForEntry), `Transition family ${family.id} has no catalogue entries.`)
9296
+ }))];
9297
+ new Map(boundaryOptions.map((option) => [option.id, option]));
9298
+ new Map(boundaryOptions.map((option) => [stableTreatmentKey(option.treatment), option]));
9299
+ new Map(sectionTransitionFamilies.flatMap((family) => family.variants.map((variant) => [variant.boundaryOption.id, variant])));
9300
+ new Map(sectionTransitionFamilies.map((family) => [family.id, family]));
9301
+ function stableTreatmentKey(treatment) {
9302
+ switch (treatment.kind) {
9303
+ case "none": return "none";
9304
+ case "soft-fade": return `${treatment.kind}:${treatment.height}:${treatment.curve}`;
9305
+ case "wave-edge": return [
9306
+ treatment.kind,
9307
+ treatment.height,
9308
+ treatment.amplitude,
9309
+ treatment.rhythm,
9310
+ treatment.symmetry
9311
+ ].join(":");
9312
+ case "angle-edge": return [
9313
+ treatment.kind,
9314
+ treatment.height,
9315
+ treatment.slope,
9316
+ treatment.direction
9317
+ ].join(":");
9318
+ case "legacy-unsupported": return `${treatment.kind}:${treatment.boundaryOptionId}`;
9319
+ }
9320
+ }
9321
+ asPageFlowPresetId("flow:quiet"), noneBoundaryOption.id, asPageFlowPresetId("flow:balanced"), softBoundaryOption.id, asPageFlowPresetId("flow:expressive"), spaciousBoundaryOption.id;
9322
+ asBoundaryOptionId("break:unknown");
9323
+ const pageDesignUserPinnedAppearanceChoiceSchema = z.object({
9324
+ kind: z.literal("user-pinned"),
9325
+ value: z.string().min(1).transform(asAppearancePresetId)
9326
+ }).strict();
9327
+ const pageDesignUserPinnedBoundaryChoiceSchema = z.object({
9328
+ kind: z.literal("user-pinned"),
9329
+ value: z.string().min(1).transform(asBoundaryOptionId)
9330
+ }).strict();
9331
+ const pageDesignBoundaryTreatmentSchema = z.discriminatedUnion("kind", [
9332
+ z.object({ kind: z.literal("none") }).strict(),
9333
+ z.object({
9334
+ kind: z.literal("soft-fade"),
9335
+ height: z.enum([
9336
+ "compact",
9337
+ "medium",
9338
+ "large",
9339
+ "expansive"
9340
+ ]),
9341
+ curve: z.enum([
9342
+ "soft",
9343
+ "spacious",
9344
+ "expansive"
9345
+ ])
9346
+ }).strict(),
9347
+ z.object({
9348
+ kind: z.literal("wave-edge"),
9349
+ height: z.enum([
9350
+ "compact",
9351
+ "medium",
9352
+ "large"
9353
+ ]),
9354
+ amplitude: z.enum([
9355
+ "subtle",
9356
+ "balanced",
9357
+ "bold"
9358
+ ]),
9359
+ rhythm: z.enum(["single", "double"]),
9360
+ symmetry: z.enum([
9361
+ "symmetrical",
9362
+ "asymmetrical",
9363
+ "drift"
9364
+ ])
9365
+ }).strict(),
9366
+ z.object({
9367
+ kind: z.literal("angle-edge"),
9368
+ height: z.enum([
9369
+ "compact",
9370
+ "medium",
9371
+ "large"
9372
+ ]),
9373
+ slope: z.enum([
9374
+ "subtle",
9375
+ "balanced",
9376
+ "steep"
9377
+ ]),
9378
+ direction: z.enum(["forward", "reverse"])
9379
+ }).strict(),
9380
+ z.object({
9381
+ kind: z.literal("legacy-unsupported"),
9382
+ boundaryOptionId: z.string().min(1).transform(asBoundaryOptionId)
9383
+ }).strict()
9384
+ ]);
9385
+ const pageDesignUserPinnedBoundaryTreatmentChoiceSchema = z.object({
9386
+ kind: z.literal("user-pinned"),
9387
+ value: pageDesignBoundaryTreatmentSchema
9388
+ }).strict();
9389
+ const pageDesignBlockLookPinSchema = z.object({
9390
+ blockId: z.string().min(1).transform(asDesignBlockId),
9391
+ blockKind: z.string().min(1),
9392
+ choice: pageDesignUserPinnedAppearanceChoiceSchema
9393
+ }).strict();
9394
+ const pageDesignBoundaryPinSchema = z.object({
9395
+ boundaryId: z.string().min(1).transform(asDesignBoundaryId),
9396
+ previousBlockId: z.string().min(1).transform(asDesignBlockId),
9397
+ nextBlockId: z.string().min(1).transform(asDesignBlockId),
9398
+ choice: pageDesignUserPinnedBoundaryTreatmentChoiceSchema
9399
+ }).strict().superRefine(validateBoundaryPinIdMatchesBlocks);
9400
+ const legacyPageDesignBoundaryPinSchema = z.object({
9401
+ boundaryId: z.string().min(1).transform(asDesignBoundaryId),
9402
+ previousBlockId: z.string().min(1).transform(asDesignBlockId),
9403
+ nextBlockId: z.string().min(1).transform(asDesignBlockId),
9404
+ choice: pageDesignUserPinnedBoundaryChoiceSchema
9405
+ }).strict().superRefine(validateBoundaryPinIdMatchesBlocks);
9406
+ z.object({
9407
+ schemaVersion: z.literal(1),
9408
+ siteStyleId: z.string().min(1).transform(asSiteStyleId),
9409
+ pageFlowPresetId: z.string().min(1).transform(asPageFlowPresetId),
9410
+ blockLookPins: z.array(pageDesignBlockLookPinSchema),
9411
+ boundaryPins: z.array(legacyPageDesignBoundaryPinSchema)
9412
+ }).strict().superRefine(validateUniquePageDesignPins);
9413
+ z.object({
9414
+ schemaVersion: z.literal(2),
9415
+ siteStyleId: z.string().min(1).transform(asSiteStyleId),
9416
+ pageFlowPresetId: z.string().min(1).transform(asPageFlowPresetId),
9417
+ blockLookPins: z.array(pageDesignBlockLookPinSchema),
9418
+ boundaryPins: z.array(pageDesignBoundaryPinSchema)
9419
+ }).strict().superRefine(validateUniquePageDesignPins);
9420
+ function addDuplicateStringIssues(ctx, input) {
9421
+ const seen = /* @__PURE__ */ new Set();
9422
+ const duplicates = /* @__PURE__ */ new Set();
9423
+ for (const value of input.values) {
9424
+ if (seen.has(value)) duplicates.add(value);
9425
+ seen.add(value);
9426
+ }
9427
+ for (const duplicate of duplicates) ctx.addIssue({
9428
+ code: z.ZodIssueCode.custom,
9429
+ path: [...input.path],
9430
+ message: `Duplicate ${input.label}: ${duplicate}.`
9431
+ });
9432
+ }
9433
+ function validateBoundaryPinIdMatchesBlocks(pin, ctx) {
9434
+ const expectedBoundaryId = makeBoundaryId(pin.previousBlockId, pin.nextBlockId);
9435
+ if (pin.boundaryId !== expectedBoundaryId) ctx.addIssue({
9436
+ code: z.ZodIssueCode.custom,
9437
+ path: ["boundaryId"],
9438
+ message: `Boundary id must match previousBlockId and nextBlockId. Expected ${expectedBoundaryId}.`
9439
+ });
9440
+ }
9441
+ function validateUniquePageDesignPins(intent, ctx) {
9442
+ addDuplicateStringIssues(ctx, {
9443
+ values: intent.blockLookPins.map((pin) => pin.blockId),
9444
+ path: ["blockLookPins"],
9445
+ label: "block Look pin"
9446
+ });
9447
+ addDuplicateStringIssues(ctx, {
9448
+ values: intent.boundaryPins.map((pin) => makeBoundaryId(pin.previousBlockId, pin.nextBlockId)),
9449
+ path: ["boundaryPins"],
9450
+ label: "boundary pin"
9451
+ });
9452
+ }
9453
+ //#endregion
9454
+ //#region ../theme-core/src/site-styles/appearancePresetResolution.ts
9455
+ function assertValidOptionGroups(preset) {
9456
+ preset.optionGroups?.forEach((group) => {
9457
+ defineLookOptionGroup(group);
9458
+ });
9459
+ }
9460
+ /**
9461
+ * Every Look carries a card role. A Look that says nothing about cards renders
9462
+ * none, which is the overwhelming majority of them; the card-bearing ones name
9463
+ * the role they want and the site style owns how it looks.
9464
+ */
9465
+ function defineBlockAppearancePreset(preset) {
9466
+ assertValidOptionGroups(preset);
9467
+ return {
9468
+ ...preset,
9469
+ design: {
9470
+ ...preset.design,
9471
+ cardRole: preset.design.cardRole ?? "none"
9472
+ }
9473
+ };
9474
+ }
9475
+ //#endregion
9476
+ //#region ../theme-core/src/site-styles/blockAppearancePresets.ts
9477
+ /**
9478
+ * A Look is a composition: which section surface, which content frame, and —
9479
+ * where it wants one — which *card role* it asks the site style for. It never
9480
+ * states how a card looks; that is the site style's identity.
9481
+ *
9482
+ * A Look with no `cardRole` asks the site style for no card at all
9483
+ * (`defineBlockAppearancePreset` defaults it to `none`) — the block's own
9484
+ * composition still governs how its items look. The per-Look rationale for the card-bearing ones lives
9485
+ * in `.project/plans/1297-card-role-contract-site-styles-own-card-surfaces/mapping-table.md`.
9486
+ */
9487
+ const brandScrimOptionGroups = [{
9488
+ id: "image-surface-treatment",
9489
+ label: "Treatment",
9490
+ defaultOptionId: "brand-scrim-primary",
9491
+ options: [{
9492
+ id: "brand-scrim-primary",
9493
+ label: "Brand scrim",
9494
+ designPatch: { imageSurfaceTreatment: {
9495
+ kind: "brand-scrim",
9496
+ token: "primary"
9497
+ } }
9498
+ }, {
9499
+ id: "neutral-scrim",
9500
+ label: "Neutral scrim",
9501
+ designPatch: { imageSurfaceTreatment: { kind: "neutral-scrim" } }
9502
+ }]
9503
+ }];
9504
+ const microBannerLayoutPatches = [{
9505
+ constraints: { layoutVariantKeys: ["micro"] },
9506
+ designPatch: { sectionHeight: "banner" }
9507
+ }];
9508
+ defineBlockAppearancePreset({
9509
+ id: "hero-immersive-image",
9510
+ target: "hero",
9511
+ label: "Immersive image hero",
9512
+ blockKinds: ["block.hero"],
9513
+ constraints: { layoutFamilies: ["centered", "compact"] },
9514
+ layoutPatches: [{
9515
+ constraints: { layoutVariantKeys: ["micro"] },
9516
+ designPatch: {
9517
+ sectionHeight: "banner",
9518
+ heroTypographyScale: "display"
9519
+ }
9520
+ }],
9521
+ design: {
9522
+ sectionSurface: "hero-image",
9523
+ contentFrame: plainFrame,
9524
+ sectionHeight: "hero",
9525
+ heroComposition: "center",
9526
+ heroTypographyScale: "display",
9527
+ imageSurfaceTreatment: { kind: "neutral-wash" }
9528
+ }
9529
+ }), defineBlockAppearancePreset({
9530
+ id: "hero-bottom-left-panel",
9531
+ target: "hero",
9532
+ label: "Bottom-left panel hero",
9533
+ blockKinds: ["block.hero"],
9534
+ constraints: { layoutFamilies: ["centered", "compact"] },
9535
+ optionGroups: [{
9536
+ id: "image-surface-treatment",
9537
+ label: "Treatment",
9538
+ defaultOptionId: "neutral-scrim",
9539
+ options: [{
9540
+ id: "neutral-scrim",
9541
+ label: "Neutral scrim",
9542
+ designPatch: { imageSurfaceTreatment: {
9543
+ kind: "neutral-scrim",
9544
+ intensity: "balanced"
9545
+ } }
9546
+ }, {
9547
+ id: "brand-scrim-primary",
9548
+ label: "Brand scrim",
9549
+ designPatch: { imageSurfaceTreatment: {
9550
+ kind: "brand-scrim",
9551
+ token: "primary",
9552
+ intensity: "balanced"
9553
+ } }
9554
+ }]
9555
+ }],
9556
+ layoutPatches: [{
9557
+ constraints: { layoutVariantKeys: ["micro"] },
9558
+ designPatch: {
9559
+ sectionHeight: "banner",
9560
+ heroTypographyScale: "editorial"
9561
+ }
9562
+ }],
9563
+ design: {
9564
+ sectionSurface: "hero-image",
9565
+ contentFrame: panelFrame("raised"),
9566
+ sectionHeight: "immersive",
9567
+ heroComposition: "bottom-left",
9568
+ heroTypographyScale: "display",
9569
+ imageSurfaceTreatment: {
9570
+ kind: "neutral-scrim",
9571
+ intensity: "balanced"
9572
+ }
9573
+ }
9574
+ }), defineBlockAppearancePreset({
9575
+ id: "hero-poster-image",
9576
+ target: "hero",
9577
+ label: "Poster image hero",
9578
+ blockKinds: ["block.hero"],
9579
+ constraints: { layoutFamilies: ["centered", "compact"] },
9580
+ layoutPatches: [{
9581
+ constraints: { layoutVariantKeys: ["micro"] },
9582
+ designPatch: {
9583
+ sectionHeight: "banner",
9584
+ heroTypographyScale: "display"
9585
+ }
9586
+ }],
9587
+ design: {
9588
+ sectionSurface: "hero-image",
9589
+ contentFrame: plainFrame,
9590
+ sectionHeight: "immersive",
9591
+ heroComposition: "center",
9592
+ heroTypographyScale: "poster",
9593
+ imageSurfaceTreatment: {
9594
+ kind: "brand-scrim",
9595
+ token: "primary",
9596
+ intensity: "strong"
9597
+ }
9598
+ }
9599
+ }), defineBlockAppearancePreset({
9600
+ id: "hero-brand-scrim",
9601
+ target: "hero",
9602
+ label: "Brand scrim image hero",
9603
+ blockKinds: ["block.hero"],
9604
+ constraints: { layoutFamilies: ["centered", "compact"] },
9605
+ optionGroups: brandScrimOptionGroups,
9606
+ layoutPatches: microBannerLayoutPatches,
9607
+ design: {
9608
+ sectionSurface: "hero-image",
9609
+ contentFrame: plainFrame,
9610
+ sectionHeight: "immersive",
9611
+ heroComposition: "center",
9612
+ heroTypographyScale: "display",
9613
+ imageSurfaceTreatment: {
9614
+ kind: "brand-scrim",
9615
+ token: "primary"
9616
+ }
9617
+ }
9618
+ }), defineBlockAppearancePreset({
9619
+ id: "hero-brand-scrim-fixed-frame",
9620
+ target: "hero",
9621
+ label: "Fixed-frame brand scrim hero",
9622
+ blockKinds: ["block.hero"],
9623
+ constraints: { layoutFamilies: ["centered", "compact"] },
9624
+ optionGroups: brandScrimOptionGroups,
9625
+ layoutPatches: microBannerLayoutPatches,
9626
+ design: {
9627
+ sectionSurface: "hero-image",
9628
+ contentFrame: plainFrame,
9629
+ sectionHeight: "immersive",
9630
+ heroComposition: "center",
9631
+ heroTypographyScale: "display",
9632
+ imageSurfaceTreatment: {
9633
+ kind: "brand-scrim",
9634
+ token: "primary"
9635
+ },
9636
+ imageSurfaceMotion: "fixed-frame",
9637
+ eyebrowTreatment: "accent-pill-bounce"
9638
+ }
9639
+ }), defineBlockAppearancePreset({
9640
+ id: "hero-brand-depth-expressive",
9641
+ target: "hero",
9642
+ label: "Expressive brand-depth hero",
9643
+ blockKinds: ["block.hero"],
9644
+ constraints: { layoutFamilies: ["centered", "compact"] },
9645
+ design: {
9646
+ sectionSurface: "brand-depth-band",
9647
+ contentFrame: plainFrame,
9648
+ heroComposition: "center",
9649
+ heroTypographyScale: "editorial",
9650
+ eyebrowTreatment: "accent-pill-bounce"
9651
+ }
9652
+ }), defineBlockAppearancePreset({
9653
+ id: "hero-contained-intro",
9654
+ target: "hero",
9655
+ label: "Contained intro hero",
9656
+ blockKinds: ["block.hero"],
9657
+ design: {
9658
+ sectionSurface: "muted-band",
9659
+ contentFrame: panelFrame("inset"),
9660
+ heroComposition: "center",
9661
+ heroTypographyScale: "editorial"
9662
+ }
9663
+ }), defineBlockAppearancePreset({
9664
+ id: "hero-split-editorial",
9665
+ target: "hero",
9666
+ label: "Editorial split hero",
9667
+ blockKinds: ["block.hero"],
9668
+ constraints: { layoutFamilies: ["split"] },
9669
+ design: {
9670
+ sectionSurface: "base",
9671
+ contentFrame: plainFrame,
9672
+ heroTypographyScale: "editorial"
9673
+ }
9674
+ }), defineBlockAppearancePreset({
9675
+ id: "hero-split-brand",
9676
+ target: "hero",
9677
+ label: "Brand split hero",
9678
+ blockKinds: ["block.hero"],
9679
+ constraints: { layoutFamilies: ["split"] },
9680
+ design: {
9681
+ sectionSurface: "brand-depth-band",
9682
+ contentFrame: plainFrame,
9683
+ heroTypographyScale: "display",
9684
+ eyebrowTreatment: "accent-pill-bounce"
9685
+ }
9686
+ }), defineBlockAppearancePreset({
9687
+ id: "hero-split-soft-panel",
9688
+ target: "hero",
9689
+ label: "Soft panel split hero",
9690
+ blockKinds: ["block.hero"],
9691
+ constraints: { layoutFamilies: ["split"] },
9692
+ design: {
9693
+ sectionSurface: "muted-band",
9694
+ contentFrame: panelFrame("raised"),
9695
+ heroTypographyScale: "editorial"
9696
+ }
9697
+ }), defineBlockAppearancePreset({
9698
+ id: "hero-split-accent",
9699
+ target: "hero",
9700
+ label: "Accent split hero",
9701
+ blockKinds: ["block.hero"],
9702
+ constraints: { layoutFamilies: ["split"] },
9703
+ design: {
9704
+ sectionSurface: "accent-band",
9705
+ contentFrame: panelFrame("raised"),
9706
+ heroTypographyScale: "display"
9707
+ }
9708
+ }), defineBlockAppearancePreset({
9709
+ id: "intro-editorial-statement",
9710
+ target: "intro",
9711
+ label: "Editorial intro statement",
9712
+ blockKinds: ["block.intro"],
9713
+ constraints: { layoutVariantKeys: ["centered-copy", "statement-copy"] },
9714
+ design: {
9715
+ sectionSurface: "base",
9716
+ contentFrame: plainFrame,
9717
+ composition: {
9718
+ kind: "intro",
9719
+ treatment: "editorial-statement"
9720
+ }
9721
+ }
9722
+ }), defineBlockAppearancePreset({
9723
+ id: "intro-portrait-bio",
9724
+ target: "intro",
9725
+ label: "Portrait and bio",
9726
+ blockKinds: ["block.intro"],
9727
+ constraints: { layoutVariantKeys: ["media-copy"] },
9728
+ design: {
9729
+ sectionSurface: "base",
9730
+ contentFrame: plainFrame,
9731
+ composition: {
9732
+ kind: "intro",
9733
+ treatment: "portrait-bio"
9734
+ }
9735
+ }
9736
+ }), defineBlockAppearancePreset({
9737
+ id: "offerings-preview-default-cards",
9738
+ target: "offerings",
9739
+ label: "Default offering cards",
9740
+ blockKinds: ["block.offerings-preview"],
9741
+ design: {
9742
+ sectionSurface: "base",
9743
+ contentFrame: plainFrame,
9744
+ cardRole: "default"
9745
+ }
9746
+ }), defineBlockAppearancePreset({
9747
+ id: "offerings-preview-secondary-cards",
9748
+ target: "offerings",
9749
+ label: "Secondary offering cards",
9750
+ blockKinds: ["block.offerings-preview"],
9751
+ design: {
9752
+ sectionSurface: "muted-band",
9753
+ contentFrame: plainFrame,
9754
+ cardRole: "alternative"
9755
+ }
9756
+ }), defineBlockAppearancePreset({
9757
+ id: "offerings-preview-non-carded",
9758
+ target: "offerings",
9759
+ label: "Non-carded offerings",
9760
+ blockKinds: ["block.offerings-preview"],
9761
+ design: {
9762
+ sectionSurface: "muted-band",
9763
+ contentFrame: plainFrame,
9764
+ cardRole: "open"
9765
+ }
9766
+ }), defineBlockAppearancePreset({
9767
+ id: "offerings-preview-paired-feature-cards",
9768
+ target: "offerings",
9769
+ label: "Paired feature cards",
9770
+ blockKinds: ["block.offerings-preview"],
9771
+ constraints: { layoutVariantKeys: ["cards"] },
9772
+ design: {
9773
+ sectionSurface: "base",
9774
+ contentFrame: plainFrame,
9775
+ cardRole: "alternative",
9776
+ composition: {
9777
+ kind: "offerings-preview",
9778
+ treatment: "paired-feature-cards"
9779
+ }
9780
+ }
9781
+ }), defineBlockAppearancePreset({
9782
+ id: "offerings-preview-open-editorial-columns",
9783
+ target: "offerings",
9784
+ label: "Open editorial columns",
9785
+ blockKinds: ["block.offerings-preview"],
9786
+ constraints: { layoutVariantKeys: ["cards"] },
9787
+ design: {
9788
+ sectionSurface: "base",
9789
+ contentFrame: plainFrame,
9790
+ cardRole: "open",
9791
+ composition: {
9792
+ kind: "offerings-preview",
9793
+ treatment: "open-editorial-columns"
9794
+ }
9795
+ }
9796
+ }), defineBlockAppearancePreset({
9797
+ id: "offerings-preview-joined-programme-panel",
9798
+ target: "offerings",
9799
+ label: "Joined programme panel",
9800
+ blockKinds: ["block.offerings-preview"],
9801
+ constraints: { layoutVariantKeys: ["cards"] },
9802
+ design: {
9803
+ sectionSurface: "base",
9804
+ contentFrame: plainFrame,
9805
+ cardRole: "default",
9806
+ composition: {
9807
+ kind: "offerings-preview",
9808
+ treatment: "joined-programme-panel"
9809
+ }
9810
+ }
9811
+ }), defineBlockAppearancePreset({
9812
+ id: "feature-cards-raised-rule",
9813
+ target: "feature-cards",
9814
+ label: "Raised cards with rule",
9815
+ blockKinds: ["block.feature-cards"],
9816
+ design: {
9817
+ sectionSurface: "base",
9818
+ contentFrame: plainFrame,
9819
+ cardRole: "default"
9820
+ }
9821
+ }), defineBlockAppearancePreset({
9822
+ id: "feature-cards-bold-colors",
9823
+ target: "feature-cards",
9824
+ label: "Bold colour-blocked cards",
9825
+ blockKinds: ["block.feature-cards"],
9826
+ design: {
9827
+ sectionSurface: "base",
9828
+ contentFrame: plainFrame,
9829
+ cardRole: "alternative"
9830
+ }
9831
+ }), defineBlockAppearancePreset({
9832
+ id: "feature-cards-editorial-columns",
9833
+ target: "feature-cards",
9834
+ label: "Editorial open columns",
9835
+ blockKinds: ["block.feature-cards"],
9836
+ design: {
9837
+ sectionSurface: "muted-band",
9838
+ contentFrame: plainFrame,
9839
+ cardRole: "open"
9840
+ }
9841
+ }), defineBlockAppearancePreset({
9842
+ id: "feature-cards-asymmetric-emphasis",
9843
+ target: "feature-cards",
9844
+ label: "Asymmetric emphasis pair",
9845
+ blockKinds: ["block.feature-cards"],
9846
+ constraints: { layoutFamilies: ["grid"] },
9847
+ design: {
9848
+ sectionSurface: "base",
9849
+ contentFrame: plainFrame,
9850
+ composition: {
9851
+ kind: "feature-cards",
9852
+ treatment: "asymmetric-emphasis"
9853
+ }
9854
+ }
9855
+ }), defineBlockAppearancePreset({
9856
+ id: "feature-cards-framed-programme",
9857
+ target: "feature-cards",
9858
+ label: "Framed programme cards",
9859
+ blockKinds: ["block.feature-cards"],
9860
+ constraints: { layoutFamilies: ["grid"] },
9861
+ design: {
9862
+ sectionSurface: "brand-depth-band",
9863
+ contentFrame: plainFrame,
9864
+ cardRole: "alternative",
9865
+ composition: {
9866
+ kind: "feature-cards",
9867
+ treatment: "framed-programme"
9868
+ }
9869
+ }
9870
+ }), defineBlockAppearancePreset({
9871
+ id: "feature-cards-soft-panels",
9872
+ target: "feature-cards",
9873
+ label: "Soft tinted panels",
9874
+ blockKinds: ["block.feature-cards"],
9875
+ design: {
9876
+ sectionSurface: "base",
9877
+ contentFrame: plainFrame,
9878
+ cardRole: "alternative"
9879
+ }
9880
+ }), defineBlockAppearancePreset({
9881
+ id: "feature-cards-editorial-diptych",
9882
+ target: "feature-cards",
9883
+ label: "Editorial diptych",
9884
+ blockKinds: ["block.feature-cards"],
9885
+ constraints: { layoutVariantKeys: ["editorial-diptych"] },
9886
+ design: {
9887
+ sectionSurface: "base",
9888
+ contentFrame: plainFrame,
9889
+ cardRole: "default"
9890
+ }
9891
+ }), defineBlockAppearancePreset({
9892
+ id: "feature-cards-editorial-pathways",
9893
+ target: "feature-cards",
9894
+ label: "Editorial pathways",
9895
+ blockKinds: ["block.feature-cards"],
9896
+ constraints: { layoutVariantKeys: ["editorial-pathways"] },
9897
+ design: {
9898
+ sectionSurface: "base",
9899
+ contentFrame: plainFrame,
9900
+ cardRole: "default"
9901
+ }
9902
+ }), defineBlockAppearancePreset({
9903
+ id: "feature-cards-photo-tiles",
9904
+ target: "feature-cards",
9905
+ label: "Photo tiles",
9906
+ blockKinds: ["block.feature-cards"],
9907
+ design: {
9908
+ sectionSurface: "base",
9909
+ contentFrame: plainFrame,
9910
+ cardRole: "default"
9911
+ }
9912
+ }), defineBlockAppearancePreset({
9913
+ id: "events-lined-panel",
9914
+ target: "events",
9915
+ label: "Raised event panel",
9916
+ blockKinds: ["block.event-calendar", "block.event-listing"],
9917
+ design: {
9918
+ sectionSurface: "base",
9919
+ contentFrame: panelFrame("raised")
9920
+ }
9921
+ }), defineBlockAppearancePreset({
9922
+ id: "events-ruled-register",
9923
+ target: "events",
9924
+ label: "Ruled event register",
9925
+ blockKinds: ["block.event-calendar", "block.event-listing"],
9926
+ design: {
9927
+ sectionSurface: "brand-depth-band",
9928
+ contentFrame: plainFrame,
9929
+ eventListTreatment: "ruled-register"
9930
+ }
9931
+ }), defineBlockAppearancePreset({
9932
+ id: "events-editorial-register",
9933
+ target: "events",
9934
+ label: "Editorial event register",
9935
+ blockKinds: ["block.event-calendar", "block.event-listing"],
9936
+ design: {
9937
+ sectionSurface: "base",
9938
+ contentFrame: plainFrame,
9939
+ eventListTreatment: "editorial-register"
9940
+ }
9941
+ }), defineBlockAppearancePreset({
9942
+ id: "events-dense-index",
9943
+ target: "events",
9944
+ label: "Dense event index",
9945
+ blockKinds: ["block.event-calendar", "block.event-listing"],
9946
+ design: {
9947
+ sectionSurface: "accent-band",
9948
+ contentFrame: plainFrame,
9949
+ eventListTreatment: "dense-index"
9950
+ }
9951
+ }), defineBlockAppearancePreset({
9952
+ id: "schedule-details-brand-depth",
9953
+ target: "events",
9954
+ label: "Brand-depth schedule details",
9955
+ blockKinds: ["block.event-details"],
9956
+ design: {
9957
+ sectionSurface: "brand-depth-band",
9958
+ contentFrame: plainFrame,
9959
+ tileTreatment: "brand-depth"
9960
+ }
9961
+ }), defineBlockAppearancePreset({
9962
+ id: "media-text-flush-feature",
9963
+ target: "media-text",
9964
+ label: "Flush media feature",
9965
+ blockKinds: ["block.media-text"],
9966
+ design: {
9967
+ sectionSurface: "muted-band",
9968
+ contentFrame: flushPanelFrame({ bleed: "start" })
9969
+ }
9970
+ }), defineBlockAppearancePreset({
9971
+ id: "testimonials-simple-cards",
9972
+ target: "testimonials",
9973
+ label: "Simple testimonial cards",
9974
+ blockKinds: ["block.testimonials"],
9975
+ design: {
9976
+ sectionSurface: "base",
9977
+ contentFrame: plainFrame,
9978
+ cardRole: "default"
9979
+ }
9980
+ }), defineBlockAppearancePreset({
9981
+ id: "testimonials-raised-panel",
9982
+ target: "testimonials",
9983
+ label: "Raised testimonial panel",
9984
+ blockKinds: ["block.testimonials"],
9985
+ design: {
9986
+ sectionSurface: "muted-band",
9987
+ contentFrame: panelFrame("raised"),
9988
+ cardRole: "default"
9989
+ }
9990
+ }), defineBlockAppearancePreset({
9991
+ id: "testimonials-accent-panel",
9992
+ target: "testimonials",
9993
+ label: "Accent testimonial panel",
9994
+ blockKinds: ["block.testimonials"],
9995
+ design: {
9996
+ sectionSurface: "accent-band",
9997
+ contentFrame: panelFrame("raised"),
9998
+ cardRole: "default"
9999
+ }
10000
+ }), defineBlockAppearancePreset({
10001
+ id: "testimonials-default-cards",
10002
+ target: "testimonials",
10003
+ label: "Default cards",
10004
+ blockKinds: ["block.testimonials"],
10005
+ design: {
10006
+ sectionSurface: "base",
10007
+ contentFrame: plainFrame,
10008
+ cardRole: "default"
10009
+ }
10010
+ }), defineBlockAppearancePreset({
10011
+ id: "testimonials-statement-cards",
10012
+ target: "testimonials",
10013
+ label: "Statement cards",
10014
+ blockKinds: ["block.testimonials"],
10015
+ design: {
10016
+ sectionSurface: "accent-band",
10017
+ contentFrame: plainFrame,
10018
+ cardRole: "alternative"
10019
+ }
10020
+ }), defineBlockAppearancePreset({
10021
+ id: "testimonials-brand-statement-cards",
10022
+ target: "testimonials",
10023
+ label: "Brand statement cards",
10024
+ blockKinds: ["block.testimonials"],
10025
+ design: {
10026
+ sectionSurface: "brand-depth-band",
10027
+ contentFrame: plainFrame,
10028
+ cardRole: "alternative"
10029
+ }
10030
+ }), defineBlockAppearancePreset({
10031
+ id: "testimonials-non-carded",
10032
+ target: "testimonials",
10033
+ label: "Non-carded",
10034
+ blockKinds: ["block.testimonials"],
10035
+ design: {
10036
+ sectionSurface: "muted-band",
10037
+ contentFrame: plainFrame,
10038
+ composition: {
10039
+ kind: "testimonials",
10040
+ treatment: "open-editorial"
10041
+ }
10042
+ }
10043
+ }), defineBlockAppearancePreset({
10044
+ id: "testimonials-evergreen-lead",
10045
+ target: "testimonials",
10046
+ label: "Evergreen lead",
10047
+ blockKinds: ["block.testimonials"],
10048
+ constraints: { layoutVariantKeys: ["featured-editorial"] },
10049
+ design: {
10050
+ sectionSurface: "base",
10051
+ contentFrame: plainFrame,
10052
+ composition: {
10053
+ kind: "testimonials",
10054
+ treatment: "evergreen-lead"
10055
+ }
10056
+ }
10057
+ }), defineBlockAppearancePreset({
10058
+ id: "testimonials-room-and-response",
10059
+ target: "testimonials",
10060
+ label: "Room and response",
10061
+ blockKinds: ["block.testimonials"],
10062
+ constraints: { layoutVariantKeys: ["featured-editorial"] },
10063
+ design: {
10064
+ sectionSurface: "base",
10065
+ contentFrame: plainFrame,
10066
+ composition: {
10067
+ kind: "testimonials",
10068
+ treatment: "room-and-response"
10069
+ }
10070
+ }
10071
+ }), defineBlockAppearancePreset({
10072
+ id: "testimonials-open-floor",
10073
+ target: "testimonials",
10074
+ label: "Open floor",
10075
+ blockKinds: ["block.testimonials"],
10076
+ constraints: { layoutVariantKeys: ["featured-editorial"] },
10077
+ design: {
10078
+ sectionSurface: "base",
10079
+ contentFrame: plainFrame,
10080
+ composition: {
10081
+ kind: "testimonials",
10082
+ treatment: "open-floor"
10083
+ }
10084
+ }
10085
+ }), defineBlockAppearancePreset({
10086
+ id: "faq-base-accordion",
10087
+ target: "faq",
10088
+ label: "Base accordion FAQ",
10089
+ blockKinds: ["block.faq"],
10090
+ design: {
10091
+ sectionSurface: "base",
10092
+ contentFrame: plainFrame,
10093
+ cardRole: "default"
10094
+ }
10095
+ }), defineBlockAppearancePreset({
10096
+ id: "faq-contained-help",
10097
+ target: "faq",
10098
+ label: "Contained help panel",
10099
+ blockKinds: ["block.faq"],
10100
+ design: {
10101
+ sectionSurface: "muted-band",
10102
+ contentFrame: panelFrame("inset"),
10103
+ cardRole: "default"
10104
+ }
10105
+ }), defineBlockAppearancePreset({
10106
+ id: "contact-form-panel",
10107
+ target: "contact-form",
10108
+ label: "Raised form panel",
10109
+ blockKinds: ["block.form"],
10110
+ design: {
10111
+ sectionSurface: "muted-band",
10112
+ contentFrame: panelFrame("raised")
10113
+ }
10114
+ }), defineBlockAppearancePreset({
10115
+ id: "booking-brand-band",
10116
+ target: "contact-form",
10117
+ label: "Brand band booking",
10118
+ blockKinds: ["block.appointment-booking"],
10119
+ design: {
10120
+ sectionSurface: "brand-depth-band",
10121
+ contentFrame: plainFrame
10122
+ }
10123
+ }), defineBlockAppearancePreset({
10124
+ id: "cta-accent-band",
10125
+ target: "cta",
10126
+ label: "Accent CTA band",
10127
+ blockKinds: ["block.cta-full"],
10128
+ design: {
10129
+ sectionSurface: "accent-band",
10130
+ contentFrame: plainFrame,
10131
+ eyebrowTreatment: "accent"
10132
+ }
10133
+ });
10134
+ asPageFlowPresetId("generated-default");
10135
+ asSiteStyleId("site-style:south-west-twerk-school");
10136
+ asAppearancePresetId("hero-brand-scrim-fixed-frame");
10137
+ asLayoutVariantKey("classic");
10138
+ asLayoutVariantKey("micro");
8958
10139
  asBoundaryOptionId("break:wave");
8959
- asBoundaryOptionId("break:wave-balanced");
8960
- asBoundaryOptionId("break:wave-gentle");
8961
- asBoundaryOptionId("break:wave-bold");
8962
- asBoundaryOptionId("break:wave-drift");
8963
- asBoundaryOptionId("break:angle-subtle");
8964
- asBoundaryOptionId("break:angle-balanced");
8965
- asBoundaryOptionId("break:angle-steep");
8966
10140
  //#endregion
8967
10141
  //#region ../theme-core/src/site-styles/runtimeCompiler.ts
8968
10142
  function defineSectionForegroundRuntimeTokens(input) {
@@ -8986,7 +10160,7 @@ function defineComponentRuntimeRules(rules) {
8986
10160
  }
8987
10161
  /**
8988
10162
  * Default design rules translate semantic page-level choices into the current
8989
- * runtime's section background and transition style-group vocabulary.
10163
+ * runtime's section background vocabulary.
8990
10164
  */
8991
10165
  const defaultDesignRuntimeRules = defineDesignRuntimeRules({
8992
10166
  sectionSurfaces: {
@@ -9021,8 +10195,7 @@ const defaultDesignRuntimeRules = defineDesignRuntimeRules({
9021
10195
  color: "surface",
9022
10196
  opacity: .88
9023
10197
  }
9024
- },
9025
- transitionClassName: (transition, fromSurface, toSurface) => transition === "none" ? null : `site-style-transition-${transition}-from-${fromSurface}-to-${toSurface}`
10198
+ }
9026
10199
  });
9027
10200
  /**
9028
10201
  * Default component rules translate frame and item-surface semantics into the
@@ -10737,13 +11910,269 @@ const curatedSiteStyles = [
10737
11910
  })
10738
11911
  ];
10739
11912
  new Map(curatedSiteStyles.map((style) => [style.id, style]));
10740
- svgDataUrl("<svg viewBox='0 0 1440 72' xmlns='http://www.w3.org/2000/svg' preserveAspectRatio='none'><path d='M0 72V46C130 55 260 24 420 30C590 36 690 62 860 42C1035 21 1160 47 1305 36C1365 31 1415 33 1440 38V72H0Z' fill='white'/></svg>");
10741
- svgDataUrl("<svg viewBox='0 0 1440 72' xmlns='http://www.w3.org/2000/svg' preserveAspectRatio='none'><path d='M0 72V42C120 24 240 24 360 42C480 60 600 60 720 42C840 24 960 24 1080 42C1200 60 1320 60 1440 42V72H0Z' fill='white'/></svg>");
10742
- svgDataUrl("<svg viewBox='0 0 1440 72' xmlns='http://www.w3.org/2000/svg' preserveAspectRatio='none'><path d='M0 72V43C180 32 300 32 480 43C660 54 780 54 960 43C1140 32 1260 32 1440 43V72H0Z' fill='white'/></svg>");
10743
- svgDataUrl("<svg viewBox='0 0 1440 72' xmlns='http://www.w3.org/2000/svg' preserveAspectRatio='none'><path d='M0 72V44C90 14 270 14 360 44C450 74 630 74 720 44C810 14 990 14 1080 44C1170 74 1350 74 1440 44V72H0Z' fill='white'/></svg>");
10744
- svgDataUrl("<svg viewBox='0 0 1440 72' xmlns='http://www.w3.org/2000/svg' preserveAspectRatio='none'><path d='M0 72V39C115 31 205 54 340 48C505 41 610 16 760 33C920 51 1015 64 1160 44C1280 27 1375 35 1440 50V72H0Z' fill='white'/></svg>");
10745
- function svgDataUrl(svg) {
10746
- return `data:image/svg+xml,${encodeURIComponent(svg)}`;
11913
+ //#endregion
11914
+ //#region ../theme-core/src/inputs/checkable.ts
11915
+ /**
11916
+ * Checkbox and radio CSS shared by the full theme generator and the SDK
11917
+ * theme bridge, so both render the same customer-facing controls.
11918
+ *
11919
+ * Emits:
11920
+ * - .form-checkbox / .form-radio: the controls themselves. The tick and dot
11921
+ * are drawn with ::before so their colour comes from theme tokens rather
11922
+ * than a baked-in SVG.
11923
+ * - .form-check: a label row holding a control and its text. The control
11924
+ * lines up with the first line of text, so long labels wrap cleanly.
11925
+ * - .form-check--tile: a bordered, fully clickable panel for agreements
11926
+ * (booking consent, consent fields) that tints when ticked.
11927
+ */
11928
+ const CHECKABLE_SIZE = "1.375rem";
11929
+ /** Never fully round: a round checkbox reads as a radio. */
11930
+ const CHECKBOX_RADIUS = {
11931
+ square: "0",
11932
+ soft: "0.25rem",
11933
+ rounded: "0.375rem",
11934
+ pill: "0.375rem"
11935
+ };
11936
+ /** Tiles hold wrapping text, so pill themes get a generous radius, not a capsule. */
11937
+ const TILE_RADIUS = {
11938
+ square: "0",
11939
+ soft: "0.5rem",
11940
+ rounded: "0.75rem",
11941
+ pill: "1rem"
11942
+ };
11943
+ const ON_ACCENT_TOKENS = {
11944
+ primary: "onPrimary",
11945
+ secondary: "onSecondary",
11946
+ accent: "onAccent"
11947
+ };
11948
+ /**
11949
+ * Colour for the tick/dot drawn on top of the accent fill. Uses the palette's
11950
+ * matching "on" token where there is one, falling back to white.
11951
+ */
11952
+ /** The accent at full strength: `primary/70` becomes `primary`. */
11953
+ function solidAccentToken(accentToken) {
11954
+ const parsed = parseColorTokenParts(accentToken);
11955
+ return parsed.kind === "token" ? parsed.token : accentToken;
11956
+ }
11957
+ function checkableMarkColor(accentToken) {
11958
+ const parsed = parseColorTokenParts(accentToken);
11959
+ const onToken = parsed.kind === "token" ? ON_ACCENT_TOKENS[parsed.token] : void 0;
11960
+ return onToken ? `rgb(var(--tb-${onToken}, 255 255 255))` : "rgb(255 255 255)";
11961
+ }
11962
+ function checkableSelectors(root) {
11963
+ return {
11964
+ checkbox: `${root} .form-checkbox`,
11965
+ radio: `${root} .form-radio`,
11966
+ check: `${root} .form-check`,
11967
+ tile: `${root} .form-check--tile`
11968
+ };
11969
+ }
11970
+ /** The box and circle themselves, unchecked. */
11971
+ function controlBaseCss(sel, input) {
11972
+ const border = input.borderWidth === "0" ? "1px" : input.borderWidth;
11973
+ return [
11974
+ `${sel.checkbox},
11975
+ ${sel.radio} {
11976
+ appearance: none;
11977
+ display: inline-grid;
11978
+ place-content: center;
11979
+ width: ${CHECKABLE_SIZE};
11980
+ height: ${CHECKABLE_SIZE};
11981
+ margin: 0;
11982
+ flex-shrink: 0;
11983
+ border: ${border} solid ${input.borderColor};
11984
+ background-color: ${input.background};
11985
+ color: inherit;
11986
+ cursor: pointer;
11987
+ transition: background-color 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
11988
+ }`,
11989
+ `${sel.checkbox} {
11990
+ border-radius: ${CHECKBOX_RADIUS[input.corners]};
11991
+ }`,
11992
+ `${sel.radio} {
11993
+ border-radius: 9999px;
11994
+ }`
11995
+ ];
11996
+ }
11997
+ /** The tick and dot, drawn with ::before so their colour is a theme token. */
11998
+ function controlMarkCss(sel, accentToken) {
11999
+ return [
12000
+ `${sel.checkbox}::before,
12001
+ ${sel.radio}::before {
12002
+ content: "";
12003
+ background-color: ${checkableMarkColor(accentToken)};
12004
+ transform: scale(0);
12005
+ transition: transform 0.12s ease;
12006
+ }`,
12007
+ `${sel.checkbox}::before {
12008
+ width: 0.75rem;
12009
+ height: 0.75rem;
12010
+ clip-path: polygon(14% 52%, 0 67%, 38% 100%, 100% 22%, 85% 8%, 37% 70%);
12011
+ }`,
12012
+ `${sel.radio}::before {
12013
+ width: 0.5rem;
12014
+ height: 0.5rem;
12015
+ border-radius: 9999px;
12016
+ }`
12017
+ ];
12018
+ }
12019
+ function controlStateCss(sel, input) {
12020
+ const accent = rgbColorValue(solidAccentToken(input.accentToken));
12021
+ return [
12022
+ `${sel.checkbox}:hover,
12023
+ ${sel.radio}:hover,
12024
+ ${sel.check}:hover > .form-checkbox,
12025
+ ${sel.check}:hover > .form-radio {
12026
+ border-color: ${accent};
12027
+ }`,
12028
+ `${sel.checkbox}:checked,
12029
+ ${sel.radio}:checked {
12030
+ background-color: ${accent};
12031
+ border-color: ${accent};
12032
+ }`,
12033
+ `${sel.checkbox}:checked::before,
12034
+ ${sel.radio}:checked::before {
12035
+ transform: scale(1);
12036
+ }`,
12037
+ `${sel.checkbox}:focus-visible,
12038
+ ${sel.radio}:focus-visible {
12039
+ outline: 2px solid ${accent};
12040
+ outline-offset: 2px;
12041
+ }`,
12042
+ `${sel.checkbox}:disabled,
12043
+ ${sel.radio}:disabled {
12044
+ opacity: 0.5;
12045
+ cursor: not-allowed;
12046
+ }`
12047
+ ];
12048
+ }
12049
+ /** Label row: control lined up with the first line of wrapping text. */
12050
+ function checkRowCss(sel) {
12051
+ return [
12052
+ `${sel.check} {
12053
+ display: flex;
12054
+ align-items: flex-start;
12055
+ gap: 0.75rem;
12056
+ line-height: 1.5;
12057
+ cursor: pointer;
12058
+ }`,
12059
+ `${sel.check} > .form-checkbox,
12060
+ ${sel.check} > .form-radio {
12061
+ margin-top: 0.0625rem;
12062
+ margin-top: max(0px, calc((1lh - ${CHECKABLE_SIZE}) / 2));
12063
+ }`,
12064
+ `${sel.check}:has(> :disabled) {
12065
+ cursor: not-allowed;
12066
+ }`
12067
+ ];
12068
+ }
12069
+ function agreementTileCss(sel, input) {
12070
+ const accent = rgbColorValue(solidAccentToken(input.accentToken));
12071
+ return [
12072
+ `${sel.tile} {
12073
+ padding: 0.875rem 1rem;
12074
+ border: 1px solid color-mix(in srgb, currentColor 22%, transparent);
12075
+ border-radius: ${TILE_RADIUS[input.corners]};
12076
+ transition: border-color 0.15s ease, background-color 0.15s ease;
12077
+ }`,
12078
+ `${sel.tile}:hover {
12079
+ border-color: color-mix(in srgb, ${accent} 55%, transparent);
12080
+ }`,
12081
+ `${sel.tile}:has(> .form-checkbox:checked) {
12082
+ border-color: ${accent};
12083
+ background-color: color-mix(in srgb, ${accent} 7%, transparent);
12084
+ }`,
12085
+ `${sel.tile}:has(> .form-checkbox[aria-invalid="true"]) {
12086
+ border-color: ${input.errorColor};
12087
+ }`
12088
+ ];
12089
+ }
12090
+ function checkableMediaCss(sel) {
12091
+ return [`@media (prefers-reduced-motion: reduce) {
12092
+ ${sel.checkbox}, ${sel.radio}, ${sel.checkbox}::before, ${sel.radio}::before, ${sel.tile} {
12093
+ transition: none;
12094
+ }
12095
+ }`, `@media (forced-colors: active) {
12096
+ ${sel.checkbox}::before,
12097
+ ${sel.radio}::before {
12098
+ background-color: CanvasText;
12099
+ }
12100
+ }`];
12101
+ }
12102
+ /**
12103
+ * Exposes the accent and mark colours so other choice controls (newsletter
12104
+ * topic chips) match the checkboxes without re-deriving the theme tokens.
12105
+ */
12106
+ function checkableVarsCss(input) {
12107
+ return [`${input.root} {
12108
+ --rb-check-accent: ${rgbColorValue(solidAccentToken(input.accentToken))};
12109
+ --rb-check-mark: ${checkableMarkColor(input.accentToken)};
12110
+ }`];
12111
+ }
12112
+ function generateCheckableCss(input) {
12113
+ const sel = checkableSelectors(input.root);
12114
+ return [
12115
+ ...checkableVarsCss(input),
12116
+ ...controlBaseCss(sel, input),
12117
+ ...controlMarkCss(sel, input.accentToken),
12118
+ ...controlStateCss(sel, input),
12119
+ ...checkRowCss(sel),
12120
+ ...agreementTileCss(sel, input),
12121
+ ...checkableMediaCss(sel)
12122
+ ].join("\n\n");
12123
+ }
12124
+ //#endregion
12125
+ //#region ../theme-core/src/inputs/inputGroup.ts
12126
+ /**
12127
+ * Input group: a field and an action (usually a themed button) sharing one
12128
+ * input-styled shell, e.g. the newsletter email + Sign up row.
12129
+ *
12130
+ * The shell `.form-input-group` takes the theme's `.form-input` rules (the
12131
+ * generators add it to that selector list, plus focus and error), so it
12132
+ * follows the site's input background, border, corners and shadow. This file
12133
+ * only adds the layout overrides and the borderless inner field.
12134
+ */
12135
+ const INPUT_GROUP_SELECTOR = ".form-input-group";
12136
+ /** Shell focus ring follows the field only, not the button beside it. */
12137
+ const INPUT_GROUP_FOCUS_SELECTOR = ".form-input-group:has(> .form-input-group-field:focus-visible)";
12138
+ const INPUT_GROUP_ERROR_SELECTOR = ".form-input-group:has(> .form-input-group-field[aria-invalid=\"true\"])";
12139
+ const GROUP_INSET = "0.25rem";
12140
+ /**
12141
+ * @param root - scoped root selector
12142
+ * @param padding - the theme's input padding shorthand (`block inline`), so the
12143
+ * inner field's text sits where a plain input's text would.
12144
+ */
12145
+ function generateInputGroupCss(root, padding) {
12146
+ const [block = padding, inline = block] = padding.trim().split(/\s+/);
12147
+ return `${root} .form-input-group {
12148
+ display: flex;
12149
+ align-items: stretch;
12150
+ gap: ${GROUP_INSET};
12151
+ padding: ${GROUP_INSET};
12152
+ }
12153
+
12154
+ ${root} .form-input-group-field {
12155
+ flex: 1 1 auto;
12156
+ min-width: 0;
12157
+ margin: 0;
12158
+ border: 0;
12159
+ border-radius: 0;
12160
+ background: transparent;
12161
+ box-shadow: none;
12162
+ outline: none;
12163
+ color: inherit;
12164
+ font: inherit;
12165
+ padding: calc(${block} - ${GROUP_INSET}) calc(${inline} - ${GROUP_INSET});
12166
+ }
12167
+
12168
+ ${root} .form-input-group-field::placeholder {
12169
+ color: inherit;
12170
+ opacity: 0.6;
12171
+ }
12172
+
12173
+ ${root} .form-input-group > :not(.form-input-group-field) {
12174
+ flex-shrink: 0;
12175
+ }`;
10747
12176
  }
10748
12177
  //#endregion
10749
12178
  //#region ../theme-core/src/status/generateStatusCss.ts
@@ -12048,6 +13477,9 @@ const containerResponsiveThemeCss = `/*
12048
13477
  .rb-h-4 {
12049
13478
  height: 1rem;
12050
13479
  }
13480
+ .rb-h-5 {
13481
+ height: 1.25rem;
13482
+ }
12051
13483
  .rb-h-8 {
12052
13484
  height: 2rem;
12053
13485
  }
@@ -16013,6 +17445,10 @@ const containerResponsiveThemeCss = `/*
16013
17445
  margin-bottom: 0.25rem;
16014
17446
  }
16015
17447
 
17448
+ :where(.theme-scope) :where([data-block='event-registration']) .er-consent-check {
17449
+ margin-top: 0.75rem;
17450
+ }
17451
+
16016
17452
  :where(.theme-scope) :where([data-block='event-registration']) .er-required {
16017
17453
  color: var(--er-required);
16018
17454
  }
@@ -20732,13 +22168,6 @@ const containerResponsiveThemeCss = `/*
20732
22168
  margin: 0;
20733
22169
  }
20734
22170
 
20735
- /* Inline field (checkbox, radio with label) */
20736
- :where(.theme-scope) :where([data-block="form"]) .fb-inline {
20737
- display: flex;
20738
- align-items: center;
20739
- gap: 0.5rem;
20740
- }
20741
-
20742
22171
  /* Success state */
20743
22172
  :where(.theme-scope) :where([data-block="form"]) .fb-success {
20744
22173
  background-color: var(--fb-success-bg);
@@ -22855,9 +24284,11 @@ const containerResponsiveThemeCss = `/*
22855
24284
  */
22856
24285
 
22857
24286
  /* Newsletter copy styling */
24287
+ /* Size only: weight, family and colour come from the theme's heading styles */
22858
24288
  :where(.theme-scope) :where([data-block="newsletter-signup"]) .newsletter-copy-title {
22859
- font-size: 1.5rem;
22860
- font-weight: 600;
24289
+ font-size: clamp(1.75rem, 1.35rem + 1.6vw, 2.5rem);
24290
+ line-height: 1.15;
24291
+ text-wrap: balance;
22861
24292
  }
22862
24293
 
22863
24294
  :where(.theme-scope) :where([data-block="newsletter-signup"]) .newsletter-copy-subtitle {
@@ -22881,37 +24312,150 @@ const containerResponsiveThemeCss = `/*
22881
24312
  gap: var(--rb-gap-sm, 0.75rem);
22882
24313
  }
22883
24314
 
22884
- /* Individual field styling */
24315
+ /* Extra preset fields (name, company...). Labels are visually hidden, so
24316
+ these sit in a row above the email entry. */
24317
+ :where(.theme-scope) .newsletter-extra-fields {
24318
+ display: grid;
24319
+ grid-template-columns: repeat(auto-fit, minmax(min(12rem, 100%), 1fr));
24320
+ gap: 0.5rem;
24321
+ }
24322
+
22885
24323
  :where(.theme-scope) .newsletter-field {
22886
24324
  display: flex;
22887
24325
  flex-direction: column;
22888
24326
  gap: 0.25rem;
24327
+ text-align: left;
22889
24328
  }
22890
24329
 
22891
- /* Topic choices (visitor picks what to hear about). Same treatment as the
22892
- form block's .fb-fieldset / .fb-inline, defined here because the newsletter
22893
- form also renders inside contact-newsletter and the site footer. */
22894
- :where(.theme-scope) .newsletter-topics {
24330
+ /* Email entry: the email field and the themed submit button share one shell.
24331
+ The shell's look (background, border, corners, focus ring) comes from the
24332
+ theme's input system via .form-input-group; this only handles layout. */
24333
+ :where(.theme-scope) .newsletter-entry {
24334
+ container-type: inline-size;
22895
24335
  display: flex;
22896
24336
  flex-direction: column;
22897
- gap: 0.5rem;
24337
+ gap: 0.375rem;
24338
+ text-align: left;
24339
+ }
24340
+
24341
+ :where(.theme-scope) .newsletter-entry-group > button {
24342
+ white-space: nowrap;
24343
+ }
24344
+
24345
+ /* Too narrow for field and button side by side (phones, footer columns):
24346
+ stack them inside the shell and keep pill themes from turning the taller
24347
+ shell into a capsule. */
24348
+ @container (max-width: 22rem) {
24349
+ :where(.theme-scope) .newsletter-entry .newsletter-entry-group {
24350
+ flex-direction: column;
24351
+ border-radius: min(var(--rb-input-radius, 0.5rem), 1rem);
24352
+ }
24353
+
24354
+ :where(.theme-scope) .newsletter-entry .newsletter-entry-group > button {
24355
+ width: 100%;
24356
+ justify-content: center;
24357
+ }
24358
+ }
24359
+
24360
+ /* Topic choices (visitor picks what to hear about) as toggle chips. Each chip
24361
+ is a real checkbox underneath; the chip is its visible face. */
24362
+ :where(.theme-scope) .newsletter-topics {
22898
24363
  border: none;
22899
24364
  padding: 0;
22900
24365
  margin: 0;
22901
24366
  min-width: 0;
22902
24367
  }
22903
24368
 
22904
- :where(.theme-scope) .newsletter-topics > legend {
24369
+ :where(.theme-scope) .newsletter-topics-legend {
22905
24370
  padding: 0;
22906
- margin-bottom: 0.25rem;
24371
+ margin-bottom: 0.625rem;
24372
+ font-size: 0.9375rem;
24373
+ color: var(--rb-surface-text-color, rgb(var(--tb-text, 17 24 39)));
22907
24374
  }
22908
24375
 
22909
- :where(.theme-scope) .newsletter-topic-choice {
24376
+ :where(.theme-scope) .newsletter-topic-chips {
22910
24377
  display: flex;
22911
- align-items: center;
24378
+ flex-wrap: wrap;
22912
24379
  gap: 0.5rem;
22913
24380
  }
22914
24381
 
24382
+ :where(.theme-scope) .newsletter-stacked .newsletter-topics-legend {
24383
+ width: 100%;
24384
+ }
24385
+
24386
+ :where(.theme-scope) .newsletter-stacked .newsletter-topic-chips {
24387
+ justify-content: center;
24388
+ }
24389
+
24390
+ :where(.theme-scope) .newsletter-topic-chip {
24391
+ position: relative;
24392
+ display: inline-flex;
24393
+ }
24394
+
24395
+ :where(.theme-scope) .newsletter-topic-chip > input {
24396
+ position: absolute;
24397
+ inset: 0;
24398
+ width: 100%;
24399
+ height: 100%;
24400
+ margin: 0;
24401
+ opacity: 0;
24402
+ cursor: pointer;
24403
+ }
24404
+
24405
+ :where(.theme-scope) .newsletter-topic-chip > span {
24406
+ display: inline-flex;
24407
+ align-items: center;
24408
+ gap: 0.375rem;
24409
+ padding: 0.4375rem 0.9375rem;
24410
+ border: 1px solid color-mix(in srgb, currentColor 35%, transparent);
24411
+ border-radius: var(--rb-button-radius, var(--rb-input-radius, 9999px));
24412
+ font-size: 0.9375rem;
24413
+ line-height: 1.3;
24414
+ color: var(--rb-surface-text-color, rgb(var(--tb-text, 17 24 39)));
24415
+ transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
24416
+ }
24417
+
24418
+ /* Tick that grows in when the chip is on */
24419
+ :where(.theme-scope) .newsletter-topic-chip > span::before {
24420
+ content: "";
24421
+ width: 0;
24422
+ height: 0.7em;
24423
+ background-color: currentColor;
24424
+ clip-path: polygon(14% 52%, 0 67%, 38% 100%, 100% 22%, 85% 8%, 37% 70%);
24425
+ transition: width 0.15s ease;
24426
+ }
24427
+
24428
+ :where(.theme-scope) .newsletter-topic-chip:hover > span {
24429
+ border-color: currentColor;
24430
+ }
24431
+
24432
+ /* Same accent and mark colours as the theme's checkboxes */
24433
+ :where(.theme-scope) .newsletter-topic-chip > input:checked + span {
24434
+ background-color: var(--rb-check-accent, rgb(var(--tb-primary)));
24435
+ border-color: var(--rb-check-accent, rgb(var(--tb-primary)));
24436
+ color: var(--rb-check-mark, rgb(var(--tb-onPrimary, 255 255 255)));
24437
+ }
24438
+
24439
+ :where(.theme-scope) .newsletter-topic-chip > input:checked + span::before {
24440
+ width: 0.7em;
24441
+ }
24442
+
24443
+ :where(.theme-scope) .newsletter-topic-chip > input:focus-visible + span {
24444
+ outline: 2px solid var(--rb-check-accent, rgb(var(--tb-primary)));
24445
+ outline-offset: 2px;
24446
+ }
24447
+
24448
+ :where(.theme-scope) .newsletter-topic-chip > input:disabled + span {
24449
+ opacity: 0.6;
24450
+ }
24451
+
24452
+ @media (prefers-reduced-motion: reduce) {
24453
+ :where(.theme-scope) .newsletter-topic-chip > span,
24454
+ :where(.theme-scope) .newsletter-topic-chip > span::before {
24455
+ transition: none;
24456
+ }
24457
+ }
24458
+
22915
24459
  /* Error panel and field notes. The form block scopes these to its own
22916
24460
  data-block, so the newsletter form (which also renders in the footer)
22917
24461
  needs its own copy of the treatment. */
@@ -22929,13 +24473,7 @@ const containerResponsiveThemeCss = `/*
22929
24473
  color: var(--fb-error-text);
22930
24474
  }
22931
24475
 
22932
- /* Required indicator */
22933
- :where(.theme-scope) .newsletter-required {
22934
- color: rgb(var(--tb-primary));
22935
- margin-left: 0.125rem;
22936
- }
22937
-
22938
- /* Submit button container */
24476
+ /* Submit button container (only when a preset has no email field) */
22939
24477
  :where(.theme-scope) .newsletter-submit {
22940
24478
  margin-top: 0.5rem;
22941
24479
  }
@@ -22947,52 +24485,29 @@ const containerResponsiveThemeCss = `/*
22947
24485
  justify-content: center;
22948
24486
  }
22949
24487
 
22950
- /* Privacy note */
24488
+ /* Privacy note: quieter than the intro so the entry row leads */
22951
24489
  :where(.theme-scope) .newsletter-privacy-note {
22952
24490
  margin-top: 0.75rem;
22953
- font-size: 1rem;
22954
- line-height: 1.6;
22955
- color: var(--rb-surface-text-color, rgb(var(--tb-text, 17 24 39)));
24491
+ font-size: 0.8125rem;
24492
+ line-height: 1.5;
24493
+ color: var(--rb-surface-supporting-color, var(--rb-surface-text-color, rgb(var(--tb-text, 17 24 39))));
24494
+ opacity: 0.85;
22956
24495
  text-align: center;
22957
24496
  }
22958
24497
 
22959
24498
  /* =============================================================================
22960
- * Inline Variant - Horizontal layout
24499
+ * Inline Variant - left-aligned, wider entry row
22961
24500
  * =============================================================================
22962
24501
  */
22963
24502
 
22964
- :where(.theme-scope) .newsletter-inline .newsletter-form-fields {
22965
- flex-direction: row;
22966
- align-items: flex-end;
22967
- flex-wrap: wrap;
22968
- gap: var(--rb-gap-sm, 0.75rem);
22969
- }
22970
-
22971
- :where(.theme-scope) .newsletter-inline .newsletter-field {
22972
- flex: 1 1 auto;
22973
- min-width: 10rem;
22974
- }
22975
-
22976
- :where(.theme-scope) .newsletter-inline .newsletter-submit {
22977
- margin-top: 0;
22978
- flex-shrink: 0;
22979
- }
22980
-
22981
- :where(.theme-scope) .newsletter-inline .newsletter-topics {
22982
- flex-basis: 100%;
24503
+ :where(.theme-scope) .newsletter-inline .newsletter-form {
24504
+ max-width: 40rem;
24505
+ margin-left: 0;
24506
+ margin-right: 0;
22983
24507
  }
22984
24508
 
22985
- /* Mobile fallback for inline variant */
22986
- @container rb-site (max-width: 640px) {
22987
- @scope ([data-rb-responsive-mode="container"]) to (:scope [data-rb-responsive-mode]) {
22988
- :where(.theme-scope) .newsletter-inline .newsletter-form-fields {
22989
- flex-direction: column;
22990
- }
22991
-
22992
- :where(.theme-scope) .newsletter-inline .newsletter-field {
22993
- min-width: 100%;
22994
- }
22995
- }
24509
+ :where(.theme-scope) .newsletter-inline .newsletter-privacy-note {
24510
+ text-align: left;
22996
24511
  }
22997
24512
 
22998
24513
  /* =============================================================================
@@ -23130,12 +24645,6 @@ const containerResponsiveThemeCss = `/*
23130
24645
  margin: 0;
23131
24646
  }
23132
24647
 
23133
- :where(.theme-scope) :where([data-block="contact-newsletter"]) .fb-inline {
23134
- display: flex;
23135
- align-items: center;
23136
- gap: 0.5rem;
23137
- }
23138
-
23139
24648
  :where(.theme-scope) :where([data-block="contact-newsletter"]) .fb-success,
23140
24649
  :where(.theme-scope) :where([data-block="contact-newsletter"]) .fb-error,
23141
24650
  :where(.theme-scope) :where([data-block="contact-newsletter"]) .fb-empty {
@@ -25032,6 +26541,44 @@ const containerResponsiveThemeCss = `/*
25032
26541
  flex: 0 0 auto;
25033
26542
  }
25034
26543
  }
26544
+ }
26545
+
26546
+ /* =============================================================================
26547
+ * Site footer: social links
26548
+ *
26549
+ * Icon links get a 40px tap target with a hairline ring drawn from the link's
26550
+ * own colour, so it follows the footer's text colour on any surface. Links
26551
+ * without an icon (unknown platforms) stay plain text.
26552
+ * =============================================================================
26553
+ */
26554
+
26555
+ :where(.theme-scope) .rb-footer-socials {
26556
+ display: flex;
26557
+ flex-wrap: wrap;
26558
+ align-items: center;
26559
+ gap: 0.75rem 1.25rem;
26560
+ }
26561
+
26562
+ :where(.theme-scope) .rb-footer-social-link:has(> .rb-footer-social-icon) {
26563
+ display: inline-grid;
26564
+ place-items: center;
26565
+ width: 2.5rem;
26566
+ height: 2.5rem;
26567
+ border: 1px solid color-mix(in srgb, currentColor 22%, transparent);
26568
+ border-radius: 9999px;
26569
+ }
26570
+
26571
+ :where(.theme-scope) .rb-footer-socials:has(.rb-footer-social-icon) {
26572
+ gap: 0.5rem;
26573
+ }
26574
+
26575
+ :where(.theme-scope) .rb-footer-social-link:has(> .rb-footer-social-icon):hover {
26576
+ border-color: currentColor;
26577
+ }
26578
+
26579
+ :where(.theme-scope) .rb-footer-social-icon {
26580
+ width: 1.5rem;
26581
+ height: 1.5rem;
25035
26582
  }`;
25036
26583
  //#endregion
25037
26584
  //#region ../theme-core/src/ThemeScopeCore.tsx
@@ -25281,6 +26828,7 @@ const BORDER_WIDTH_MAP = {
25281
26828
  medium: "2px",
25282
26829
  thick: "4px"
25283
26830
  };
26831
+ const INPUT_PADDING = "0.5rem 0.75rem";
25284
26832
  const SHADOW_VALUES = {
25285
26833
  none: "none",
25286
26834
  low: "0 1px 2px rgba(0,0,0,0.04)",
@@ -25314,16 +26862,18 @@ function generateInputCoreCss(scopeId, settings) {
25314
26862
  color: rgb(var(--tb-${settings.textToken}));
25315
26863
  border: ${borderWidth} solid rgb(var(--tb-${settings.borderToken}));
25316
26864
  border-radius: ${borderRadius};
25317
- padding: 0.5rem 0.75rem;
26865
+ padding: ${INPUT_PADDING};
25318
26866
  font-size: 1rem;
25319
26867
  width: 100%;
25320
26868
  outline: none;
25321
26869
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
25322
26870
  ${settings.shadow !== "none" ? `box-shadow: ${SHADOW_VALUES[settings.shadow]};` : ""}
25323
26871
  `.trim();
25324
- cssBlocks.push(`${root} .form-input {
26872
+ cssBlocks.push(`${root} .form-input,
26873
+ ${root} ${INPUT_GROUP_SELECTOR} {
25325
26874
  ${sharedInputRules}
25326
26875
  }`);
26876
+ cssBlocks.push(generateInputGroupCss(root, INPUT_PADDING));
25327
26877
  cssBlocks.push(`${root} .form-textarea {
25328
26878
  ${sharedInputRules}
25329
26879
  resize: vertical;
@@ -25340,14 +26890,16 @@ function generateInputCoreCss(scopeId, settings) {
25340
26890
  }`);
25341
26891
  cssBlocks.push(`${root} .form-input:focus-visible,
25342
26892
  ${root} .form-textarea:focus-visible,
25343
- ${root} .form-select:focus-visible {
26893
+ ${root} .form-select:focus-visible,
26894
+ ${root} ${INPUT_GROUP_FOCUS_SELECTOR} {
25344
26895
  outline: none;
25345
26896
  box-shadow: 0 0 0 ${settings.focusRingWidth}px rgb(var(--tb-${settings.focusRingToken}));
25346
26897
  border-color: rgb(var(--tb-${settings.focusRingToken}));
25347
26898
  }`);
25348
26899
  cssBlocks.push(`${root} .form-input[aria-invalid="true"],
25349
26900
  ${root} .form-textarea[aria-invalid="true"],
25350
- ${root} .form-select[aria-invalid="true"] {
26901
+ ${root} .form-select[aria-invalid="true"],
26902
+ ${root} ${INPUT_GROUP_ERROR_SELECTOR} {
25351
26903
  border-color: rgb(var(--tb-${settings.errorBorderToken}));
25352
26904
  color: rgb(var(--tb-${settings.errorTextToken}));
25353
26905
  }`);
@@ -25359,46 +26911,15 @@ ${root} .form-select:disabled {
25359
26911
  opacity: 0.6;
25360
26912
  cursor: not-allowed;
25361
26913
  }`);
25362
- cssBlocks.push(`${root} .form-checkbox {
25363
- appearance: none;
25364
- width: 1.125rem;
25365
- height: 1.125rem;
25366
- flex-shrink: 0;
25367
- border: ${borderWidth} solid rgb(var(--tb-${settings.borderToken}));
25368
- border-radius: 0.25rem;
25369
- background-color: rgb(var(--tb-${settings.backgroundToken}));
25370
- cursor: pointer;
25371
- transition: background-color 0.2s ease, border-color 0.2s ease;
25372
- }`);
25373
- cssBlocks.push(`${root} .form-radio {
25374
- appearance: none;
25375
- width: 1.125rem;
25376
- height: 1.125rem;
25377
- flex-shrink: 0;
25378
- border: ${borderWidth} solid rgb(var(--tb-${settings.borderToken}));
25379
- border-radius: 9999px;
25380
- background-color: rgb(var(--tb-${settings.backgroundToken}));
25381
- cursor: pointer;
25382
- transition: background-color 0.2s ease, border-color 0.2s ease;
25383
- }`);
25384
- cssBlocks.push(`${root} .form-checkbox:checked {
25385
- background-color: rgb(var(--tb-${settings.focusRingToken}));
25386
- border-color: rgb(var(--tb-${settings.focusRingToken}));
25387
- background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e");
25388
- background-size: 100% 100%;
25389
- background-position: center;
25390
- background-repeat: no-repeat;
25391
- }`);
25392
- cssBlocks.push(`${root} .form-radio:checked {
25393
- background-color: rgb(var(--tb-${settings.focusRingToken}));
25394
- border-color: rgb(var(--tb-${settings.focusRingToken}));
25395
- background-image: radial-gradient(circle, white 40%, transparent 40%);
25396
- }`);
25397
- cssBlocks.push(`${root} .form-checkbox:focus-visible,
25398
- ${root} .form-radio:focus-visible {
25399
- outline: none;
25400
- box-shadow: 0 0 0 ${settings.focusRingWidth}px rgb(var(--tb-${settings.focusRingToken}));
25401
- }`);
26914
+ cssBlocks.push(generateCheckableCss({
26915
+ root,
26916
+ borderWidth,
26917
+ borderColor: `rgb(var(--tb-${settings.borderToken}))`,
26918
+ background: `rgb(var(--tb-${settings.backgroundToken}))`,
26919
+ corners: settings.corners,
26920
+ accentToken: settings.focusRingToken,
26921
+ errorColor: `rgb(var(--tb-${settings.errorBorderToken}))`
26922
+ }));
25402
26923
  return cssBlocks.join("\n\n");
25403
26924
  }
25404
26925
  /**