@riverbankcms/sdk 0.111.0 → 0.119.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 (196) hide show
  1. package/dist/{PreviewEditorSidebar-CTR6LUhN.mjs → PreviewEditorSidebar-C7TXFitV.mjs} +4 -4
  2. package/dist/{PreviewEditorUI-DZg15Zip.mjs → PreviewEditorUI-_1JIHTXS.mjs} +3 -3
  3. package/dist/{PreviewQueryProvider-kkmjklLG.mjs → PreviewQueryProvider-nKUT4TL-.mjs} +1 -1
  4. package/dist/{SdkPreviewModeRuntime-DeOTAFvR.mjs → SdkPreviewModeRuntime-CvJTVgWa.mjs} +2579 -34325
  5. package/dist/{SiteChromeCustomizeContext-DOSDLCiJ.mjs → SiteChromeCustomizeContext-66QfCbAS.mjs} +64625 -32791
  6. package/dist/_dts/ai/src/contracts/proposals.d.ts +5211 -639
  7. package/dist/_dts/ai/src/designer/themePatch.d.ts +1 -1
  8. package/dist/_dts/api/src/bookingAdjustments.d.ts +30 -36
  9. package/dist/_dts/api/src/bookingConfig.d.ts +26 -1
  10. package/dist/_dts/api/src/bookingRecords.d.ts +6 -74
  11. package/dist/_dts/api/src/bookingRefundOutcomes.d.ts +3 -3
  12. package/dist/_dts/api/src/contentRuntime.d.ts +5 -1
  13. package/dist/_dts/api/src/customerMembershipOutcomes.d.ts +4 -4
  14. package/dist/_dts/api/src/endpoints.d.ts +35 -0
  15. package/dist/_dts/api/src/event-presentation.d.ts +4 -0
  16. package/dist/_dts/api/src/index.d.ts +4 -4
  17. package/dist/_dts/api/src/navigation/dashboardBookingsNav.d.ts +4 -1
  18. package/dist/_dts/api/src/navigation/dashboardSettingsNav.d.ts +2 -2
  19. package/dist/_dts/api/src/sdk-event-upsert.d.ts +2 -2
  20. package/dist/_dts/api/src/sdkContracts.d.ts +85 -7
  21. package/dist/_dts/api/src/siteBanner.d.ts +8 -8
  22. package/dist/_dts/api/src/siteOperations.d.ts +1 -1
  23. package/dist/_dts/api/src/sitePlatformEndpoints.d.ts +32 -4
  24. package/dist/_dts/block-form/src/widgets/RichTextField/richTextFieldDefaults.d.ts +3 -12
  25. package/dist/_dts/block-form/src/widgets/RichTextField/richTextFieldSchema.d.ts +1 -5
  26. package/dist/_dts/blocks/src/bindings/index.d.ts +1 -10
  27. package/dist/_dts/blocks/src/index.d.ts +3 -6
  28. package/dist/_dts/blocks/src/primitives/content/primitives.d.ts +2 -2
  29. package/dist/_dts/blocks/src/system/blocks/body-text.d.ts +2 -2
  30. package/dist/_dts/blocks/src/system/blocks/events/recurring-schedule.d.ts +2 -2
  31. package/dist/_dts/blocks/src/system/blocks/events/shared/schemas.d.ts +2 -8
  32. package/dist/_dts/blocks/src/system/blocks/feature-card-icons.d.ts +2 -2
  33. package/dist/_dts/blocks/src/system/blocks/feature-cards.d.ts +3 -3
  34. package/dist/_dts/blocks/src/system/blocks/form.d.ts +2 -15
  35. package/dist/_dts/blocks/src/system/blocks/intro.d.ts +2 -2
  36. package/dist/_dts/blocks/src/system/blocks/media-text.d.ts +66 -66
  37. package/dist/_dts/blocks/src/system/blocks/newsletter-signup.d.ts +2 -16
  38. package/dist/_dts/blocks/src/system/blocks/site-footer.d.ts +0 -3
  39. package/dist/_dts/blocks/src/system/fragments/index.d.ts +0 -1
  40. package/dist/_dts/blocks/src/system/manifest/fieldValidation/index.d.ts +19 -2
  41. package/dist/_dts/blocks/src/system/manifest/richTextSchema.d.ts +8 -70
  42. package/dist/_dts/blocks/src/system/manifest/schema.d.ts +1 -0
  43. package/dist/_dts/blocks/src/system/manifest/validation.d.ts +6 -0
  44. package/dist/_dts/blocks/src/system/node/schema.d.ts +4 -4
  45. package/dist/_dts/blocks/src/system/runtime/nodes/basic.d.ts +1 -10
  46. package/dist/_dts/blocks/src/system/runtime/nodes/buttonAffordance.d.ts +5 -21
  47. package/dist/_dts/blocks/src/system/runtime/nodes/richText-coerce.d.ts +14 -2
  48. package/dist/_dts/blocks/src/system/transforms/typed.d.ts +1 -1
  49. package/dist/_dts/content-editor/src/controller/seedDraftBaselinesFromBlocks.d.ts +1 -1
  50. package/dist/_dts/content-editor/src/hooks/useBlockAutosave.d.ts +17 -1
  51. package/dist/_dts/content-editor/src/hooks/useDebouncedLatestSave.d.ts +1 -1
  52. package/dist/_dts/content-editor/src/hooks/useSimpleAutosave.d.ts +1 -1
  53. package/dist/_dts/content-editor/src/ui/editorSnapshot.d.ts +3 -2
  54. package/dist/_dts/content-editor/src/ui/editorUiStore.d.ts +2 -2
  55. package/dist/_dts/content-editor/src/ui/stores/autosaveStore.d.ts +1 -1
  56. package/dist/_dts/content-editor/src/ui/stores/types.d.ts +1 -1
  57. package/dist/_dts/content-model/src/content-types/builtins.d.ts +3 -15
  58. package/dist/_dts/content-model/src/content-types/entryValidation.d.ts +2 -0
  59. package/dist/_dts/content-model/src/content-types/schema.d.ts +1 -1
  60. package/dist/_dts/content-model/src/templates/defaults.d.ts +1 -21
  61. package/dist/_dts/core/src/editor-state.d.ts +14 -1
  62. package/dist/_dts/core/src/footer-composition.d.ts +2 -1
  63. package/dist/_dts/core/src/index.d.ts +1 -0
  64. package/dist/_dts/core/src/rich-text.d.ts +16 -0
  65. package/dist/_dts/db/src/generated/supabase/database.types.d.ts +189 -86
  66. package/dist/_dts/editor/src/index.d.ts +1 -1
  67. package/dist/_dts/editor/src/primitives/rich-text/utils.d.ts +3 -5
  68. package/dist/_dts/editor-blocks/src/BlockEditor.d.ts +1 -1
  69. package/dist/_dts/editor-blocks/src/block-editor/BlockCard.d.ts +2 -1
  70. package/dist/_dts/editor-blocks/src/block-editor/BlockCardHeader.d.ts +2 -1
  71. package/dist/_dts/editor-blocks/src/block-editor/blockDraftBaselineSeed.d.ts +15 -0
  72. package/dist/_dts/editor-blocks/src/block-editor/hooks/useBlockBaselineSync.d.ts +3 -7
  73. package/dist/_dts/editor-blocks/src/block-editor/hooks/useBlockDuplication.d.ts +12 -0
  74. package/dist/_dts/editor-blocks/src/block-editor/types.d.ts +1 -0
  75. package/dist/_dts/editor-blocks/src/block-editor/utils.d.ts +1 -1
  76. package/dist/_dts/editor-blocks/src/index.d.ts +6 -5
  77. package/dist/_dts/editor-blocks/src/widgets/rich-text/RichTextField.d.ts +2 -2
  78. package/dist/_dts/media-core/src/contentMediaAudit.d.ts +104 -0
  79. package/dist/_dts/media-core/src/contentMediaAuditFieldAdapter.d.ts +8 -0
  80. package/dist/_dts/media-core/src/contentMediaSnapshotAudit.d.ts +22 -0
  81. package/dist/_dts/media-core/src/index.d.ts +3 -1
  82. package/dist/_dts/sdk/src/cli/commands/event.d.ts +18 -1
  83. package/dist/_dts/sdk/src/cli/commands/push/execute/theme.d.ts +2 -16
  84. package/dist/_dts/sdk/src/cli/content/reader.d.ts +8 -5
  85. package/dist/_dts/sdk/src/client/management/events.d.ts +2 -1
  86. package/dist/_dts/sdk/src/client/management/index.d.ts +1 -1
  87. package/dist/_dts/sdk/src/client/management/types.d.ts +36 -9
  88. package/dist/_dts/sdk/src/config/typed-entries.d.ts +7 -7
  89. package/dist/_dts/sdk/src/config/validation.d.ts +7 -7
  90. package/dist/_dts/sdk/src/contracts/content.d.ts +5 -15
  91. package/dist/_dts/sdk/src/contracts/index.d.ts +1 -1
  92. package/dist/_dts/sdk/src/contracts/system-block-content.d.ts +12 -25
  93. package/dist/_dts/sdk/src/contracts/theme.d.ts +2 -18
  94. package/dist/_dts/sdk/src/manifest/passes/pass1-fields.d.ts +1 -1
  95. package/dist/_dts/sdk/src/manifest/three-pass-converter.d.ts +4 -4
  96. package/dist/_dts/sdk/src/rendering/helpers/bindings.d.ts +1 -2
  97. package/dist/_dts/sdk/src/rendering/helpers/index.d.ts +1 -1
  98. package/dist/_dts/sdk/src/rendering/islands/types.d.ts +2 -13
  99. package/dist/_dts/sdk/src/theme/index.d.ts +0 -29
  100. package/dist/_dts/sdk/src/version.d.ts +1 -1
  101. package/dist/_dts/site-commands/src/commands.d.ts +31 -18
  102. package/dist/_dts/theme-core/src/buttons/affordanceIcons.d.ts +2 -2
  103. package/dist/_dts/theme-core/src/buttons/core.d.ts +0 -1
  104. package/dist/_dts/theme-core/src/buttons/effectClassification.d.ts +22 -9
  105. package/dist/_dts/theme-core/src/buttons/effects/presets/background.d.ts +1 -2
  106. package/dist/_dts/theme-core/src/buttons/effects/presets/border.d.ts +1 -2
  107. package/dist/_dts/theme-core/src/buttons/effects/presets/overlay.d.ts +3 -1
  108. package/dist/_dts/theme-core/src/buttons/effects/presets/shadow.d.ts +2 -2
  109. package/dist/_dts/theme-core/src/buttons/effects/types.d.ts +8 -18
  110. package/dist/_dts/theme-core/src/buttons/generateButtonCss.d.ts +2 -2
  111. package/dist/_dts/theme-core/src/buttons/generateDefaultButtonSystem.d.ts +5 -5
  112. package/dist/_dts/theme-core/src/buttons/index.d.ts +1 -4
  113. package/dist/_dts/theme-core/src/buttons/parseThemeForPersistence.d.ts +36 -0
  114. package/dist/_dts/theme-core/src/buttons/types.d.ts +1638 -93
  115. package/dist/_dts/theme-core/src/cards/types.d.ts +13 -13
  116. package/dist/_dts/theme-core/src/mock-themes/all.d.ts +969 -69
  117. package/dist/_dts/theme-core/src/navigation/types.d.ts +2 -2
  118. package/dist/_dts/theme-core/src/recommend/generateThemes.d.ts +0 -1
  119. package/dist/_dts/theme-core/src/schema.d.ts +1100 -116
  120. package/dist/_dts/theme-core/src/site-styles/backgroundAppearance.d.ts +2 -2
  121. package/dist/_dts/theme-core/src/site-styles/designState.d.ts +14 -14
  122. package/dist/_dts/theme-core/src/site-styles/generatedSchemas.d.ts +2 -2
  123. package/dist/_dts/theme-core/src/site-styles/pageDesignIntent.d.ts +4 -4
  124. package/dist/_dts/theme-core/src/site-styles/previewCompiler.d.ts +6 -0
  125. package/dist/cli/index.mjs +5706 -4852
  126. package/dist/cli/init-docs/content/cli-reference.md +40 -1
  127. package/dist/cli/init-docs/content/content-management.md +6 -0
  128. package/dist/client/{DiscountCodeDisclosure-C4xvTBux.mjs → DiscountCodeDisclosure-DIWj-P9v.mjs} +1 -1
  129. package/dist/client/{EventCombined.client-Cr7G131j.mjs → EventCombined.client-De8YWBSr.mjs} +2 -2
  130. package/dist/client/{EventListing.client-CAjbseNy.mjs → EventListing.client-seHTjimY.mjs} +2 -2
  131. package/dist/client/{LeafletStaticMap-BMlWfwz3.mjs → LeafletStaticMap-BmQxFcJW.mjs} +1 -1
  132. package/dist/client/{MagicLinkForm-ChdFz96y.mjs → MagicLinkForm-OoJAIUIj.mjs} +1 -1
  133. package/dist/client/{StepIndicator-7D3GaBeM.mjs → StepIndicator-CiZ8kdPk.mjs} +2 -2
  134. package/dist/client/{accordion-D8JTs2Si.mjs → accordion-6lnN__XJ.mjs} +1 -1
  135. package/dist/client/{bookingForm-H3DCRBHs.mjs → bookingForm-5uyqhONU.mjs} +6 -6
  136. package/dist/client/bookings.mjs +2219 -527
  137. package/dist/client/{carousel-DMr_QWlz.mjs → carousel-Dtnifil_.mjs} +1 -1
  138. package/dist/client/{cart-DWMbfBdR.mjs → cart-5Tc5S7NV.mjs} +3 -3
  139. package/dist/client/{checkout-zmfdkXLx.mjs → checkout-CYKKN5Hr.mjs} +3 -3
  140. package/dist/client/client.mjs +2498 -2384
  141. package/dist/client/{colorTokenParts-FSS3al6l.mjs → colorStyles-BWpj_h4C.mjs} +88 -1
  142. package/dist/client/{courseRegistration-Z_mn18jy.mjs → courseRegistration-CxCBybB4.mjs} +6 -6
  143. package/dist/client/{eventCalendar-CYp0YJGF.mjs → eventCalendar-Xj2jZS9X.mjs} +4 -4
  144. package/dist/client/{eventCombined-rKyYZUa9.mjs → eventCombined-CgcMoOgM.mjs} +2 -2
  145. package/dist/client/{eventDetails-X0ZaUuMj.mjs → eventDetails-CEAH8Edc.mjs} +3 -3
  146. package/dist/client/{eventListing-W1SuL7EP.mjs → eventListing-qyPVQ0wP.mjs} +2 -2
  147. package/dist/client/{eventRegistration-ClWricui.mjs → eventRegistration-DDu79CtL.mjs} +6 -6
  148. package/dist/client/{form--eKPwAAD.mjs → form-Bc7JKI7I.mjs} +1 -1
  149. package/dist/client/{headerSection-BSeGr-FS.mjs → headerSection-vTku_LEl.mjs} +2 -2
  150. package/dist/client/hooks.mjs +373 -555
  151. package/dist/client/{locationMap-BpOrtNYn.mjs → locationMap-Bg7X4Jna.mjs} +3 -3
  152. package/dist/client/{media-DoF0dcVx.mjs → media-CNE1Z-wb.mjs} +1 -2
  153. package/dist/client/{newsletterForm-Bt7it7Dy.mjs → newsletterForm-lpylVdp5.mjs} +1 -1
  154. package/dist/client/{pricing-BTjSDDr4.mjs → pricing-DE8fjJiT.mjs} +1 -1
  155. package/dist/client/{productDetail-ICnVTcCg.mjs → productDetail-D7Bo2RMH.mjs} +3 -3
  156. package/dist/client/{productList-ZHr6D604.mjs → productList-VjnZqiqN.mjs} +3 -3
  157. package/dist/client/{propsDecoder-wWN0tBDF.mjs → propsDecoder-DreFXjNP.mjs} +2212 -621
  158. package/dist/client/rendering/client.mjs +21612 -21646
  159. package/dist/client/rendering/islands.mjs +20 -20
  160. package/dist/client/rendering.mjs +1571 -1547
  161. package/dist/client/{shop-C1u_BUn0.mjs → shop-IRsHHbf7.mjs} +5 -5
  162. package/dist/client/{shop-commerce-CleZdRha.mjs → shop-commerce-gnI8PieZ.mjs} +27 -10
  163. package/dist/client/{shop-commerce-store-ycnoB2Ce.mjs → shop-commerce-store-BTbrhObn.mjs} +1 -1
  164. package/dist/client/{shopShared-CPhByt2a.mjs → shopShared-D6KS2_qk.mjs} +3 -3
  165. package/dist/client/{useDiscountCodeUi-cStSQI6C.mjs → useDiscountCodeUi-DCccGCxV.mjs} +1 -1
  166. package/dist/client/{useEventFilters-DKPN7hSY.mjs → useEventFilters-eGs3rPZQ.mjs} +3 -104
  167. package/dist/client/{usePolling-BKAd6pkZ.mjs → usePolling-CvSU2sur.mjs} +2 -2
  168. package/dist/preview-next/before-render.mjs +57 -0
  169. package/dist/preview-next/client/runtime.mjs +4 -4
  170. package/dist/preview-next/middleware.mjs +57 -0
  171. package/dist/{previewAuthStore-BkT1D06A.mjs → previewAuthStore-DN7vcRsv.mjs} +57 -0
  172. package/dist/{sdk-runtime-hu3wr3ng.mjs → sdk-runtime-DaOiA7ct.mjs} +2 -2
  173. package/dist/{separator-Bln8izQ9.mjs → separator-CqRhcCxD.mjs} +1 -1
  174. package/dist/server/components.mjs +4092 -4108
  175. package/dist/server/config-template-validation.mjs +4 -23
  176. package/dist/server/config-validation.mjs +373 -555
  177. package/dist/server/config.mjs +410 -558
  178. package/dist/server/data.mjs +373 -555
  179. package/dist/server/index.mjs +58 -1
  180. package/dist/server/next.mjs +32958 -32926
  181. package/dist/server/page-converter.mjs +369 -526
  182. package/dist/server/prebuild.mjs +1 -1
  183. package/dist/server/rendering/server.mjs +5371 -3174
  184. package/dist/server/rendering.mjs +4099 -4124
  185. package/dist/server/routing.mjs +758 -966
  186. package/dist/server/server.mjs +448 -632
  187. package/dist/server/theme-bridge.mjs +472 -525
  188. package/dist/server/theme.mjs +1074 -392
  189. package/package.json +1 -1
  190. package/dist/_dts/blocks/src/primitives/content/components/Button.d.ts +0 -40
  191. package/dist/_dts/blocks/src/system/fragments/library/footerBottomText.d.ts +0 -19
  192. package/dist/_dts/media-core/src/legacyMediaValue.d.ts +0 -11
  193. package/dist/_dts/theme-core/src/styles/buttons.d.ts +0 -27
  194. package/dist/_dts/theme-core/src/styles/buttonsLibrary.d.ts +0 -2
  195. package/dist/_dts/theme-core/src/styles/glow.d.ts +0 -3
  196. package/dist/client/colorStyles-gcTh5yZT.mjs +0 -89
@@ -2715,151 +2715,6 @@ z$1.discriminatedUnion("kind", [
2715
2715
  })
2716
2716
  ]);
2717
2717
  //#endregion
2718
- //#region ../theme-core/src/surfaces/foregroundContract.ts
2719
- const SURFACE_FOREGROUND_CSS_VARS = {
2720
- text: "--rb-surface-text-color",
2721
- heading: "--rb-surface-heading-color",
2722
- link: "--rb-surface-link-color",
2723
- supporting: "--rb-surface-supporting-color"
2724
- };
2725
- const DEFAULT_SURFACE_TEXT_COLOR = "rgb(var(--tb-text, 17 24 39))";
2726
- const DEFAULT_ROLE_FALLBACKS = {
2727
- text: DEFAULT_SURFACE_TEXT_COLOR,
2728
- heading: DEFAULT_SURFACE_TEXT_COLOR,
2729
- link: "rgb(var(--tb-primary, var(--tb-text, 17 24 39)))",
2730
- supporting: "rgb(var(--tb-mutedText, 100 116 139))"
2731
- };
2732
- function requireSurfaceColorValue(role, value) {
2733
- const normalized = value.trim();
2734
- if (normalized.length === 0) throw new RangeError(`Surface foreground ${role} must be a non-empty CSS color.`);
2735
- return normalized;
2736
- }
2737
- function completeSurfaceForegrounds(input) {
2738
- const text = requireSurfaceColorValue("text", input.text);
2739
- return {
2740
- text,
2741
- heading: input.heading === void 0 ? text : requireSurfaceColorValue("heading", input.heading),
2742
- link: input.link === void 0 ? text : requireSurfaceColorValue("link", input.link),
2743
- supporting: input.supporting === void 0 ? text : requireSurfaceColorValue("supporting", input.supporting)
2744
- };
2745
- }
2746
- function surfaceForegroundValue(role, outsideProviderFallback = DEFAULT_ROLE_FALLBACKS[role]) {
2747
- const roleVariable = SURFACE_FOREGROUND_CSS_VARS[role];
2748
- const fallback = requireSurfaceColorValue("fallback", outsideProviderFallback);
2749
- if (role === "text") return `var(${roleVariable}, ${fallback})`;
2750
- return `var(${roleVariable}, var(${SURFACE_FOREGROUND_CSS_VARS.text}, ${fallback}))`;
2751
- }
2752
- function surfaceForegroundValueWithOpacity(role, opacityPercent) {
2753
- if (!Number.isFinite(opacityPercent) || opacityPercent < 0 || opacityPercent > 100) throw new RangeError("Surface foreground opacity must be between 0 and 100.");
2754
- return `color-mix(in srgb, ${surfaceForegroundValue(role)} ${opacityPercent}%, transparent)`;
2755
- }
2756
- function surfaceForegroundStyle(input) {
2757
- const foregrounds = completeSurfaceForegrounds(input);
2758
- return {
2759
- color: foregrounds.text,
2760
- [SURFACE_FOREGROUND_CSS_VARS.text]: foregrounds.text,
2761
- [SURFACE_FOREGROUND_CSS_VARS.heading]: foregrounds.heading,
2762
- [SURFACE_FOREGROUND_CSS_VARS.link]: foregrounds.link,
2763
- [SURFACE_FOREGROUND_CSS_VARS.supporting]: foregrounds.supporting
2764
- };
2765
- }
2766
- //#endregion
2767
- //#region ../theme-core/src/utils/colorStyles.ts
2768
- const COLOR_VAR_PREFIX = "--tb-";
2769
- function parseToken(source) {
2770
- const parts = parseColorTokenParts(source);
2771
- if (parts.kind === "raw") return {
2772
- token: source,
2773
- raw: parts.value
2774
- };
2775
- if (parts.kind === "invalid") return { token: source };
2776
- return {
2777
- token: parts.token,
2778
- opacityPercent: parts.opacityPercent === null ? void 0 : parts.opacityPercent
2779
- };
2780
- }
2781
- const SURFACE_TEXT_ROLE_BY_TOKEN = {
2782
- text: "text",
2783
- heading: "heading",
2784
- mutedText: "supporting"
2785
- };
2786
- function surfaceRoleForTextToken(token) {
2787
- return Object.prototype.hasOwnProperty.call(SURFACE_TEXT_ROLE_BY_TOKEN, token) ? SURFACE_TEXT_ROLE_BY_TOKEN[token] : null;
2788
- }
2789
- /**
2790
- * Converts a theme color token to a CSS rgb value.
2791
- * This is the primary function for applying theme colors to CSS properties.
2792
- *
2793
- * @param token - Theme color token (semantic, with opacity, or raw)
2794
- * @returns CSS color value (rgb with optional alpha, or raw CSS value)
2795
- *
2796
- * @example
2797
- * rgbColorValue('primary') // => 'rgb(var(--tb-primary))'
2798
- * rgbColorValue('surface/95') // => 'rgb(var(--tb-surface) / 0.95)'
2799
- * rgbColorValue('raw:transparent') // => 'transparent'
2800
- */
2801
- function rgbColorValue(token) {
2802
- const { token: baseToken, opacityPercent, raw } = parseToken(token);
2803
- if (raw) return raw;
2804
- const cssVar = `${COLOR_VAR_PREFIX}${baseToken}`;
2805
- if (opacityPercent === void 0) return `rgb(var(${cssVar}))`;
2806
- return `rgb(var(${cssVar}) / ${opacityPercent / 100})`;
2807
- }
2808
- /**
2809
- * Creates a backgroundColor style object from a theme token.
2810
- *
2811
- * @param token - Theme color token
2812
- * @returns CSSProperties with backgroundColor
2813
- */
2814
- function backgroundColorStyle(token) {
2815
- return { backgroundColor: rgbColorValue(token) };
2816
- }
2817
- /**
2818
- * Creates a text color style object from a theme token.
2819
- *
2820
- * @param token - Theme color token
2821
- * @returns CSSProperties with color
2822
- */
2823
- function textColorStyle(token) {
2824
- const parsed = parseToken(token);
2825
- const surfaceRole = parsed.raw ? null : surfaceRoleForTextToken(parsed.token);
2826
- if (surfaceRole) return { color: parsed.opacityPercent === void 0 ? surfaceForegroundValue(surfaceRole) : surfaceForegroundValueWithOpacity(surfaceRole, parsed.opacityPercent) };
2827
- return { color: rgbColorValue(token) };
2828
- }
2829
- /**
2830
- * Creates a border color style object from a theme token.
2831
- *
2832
- * @param token - Theme color token
2833
- * @returns CSSProperties with borderColor
2834
- */
2835
- function borderColorStyle(token) {
2836
- return { borderColor: rgbColorValue(token) };
2837
- }
2838
- /**
2839
- * Merges multiple CSSProperties objects into a single object.
2840
- * Later styles override earlier ones. Undefined values are filtered out.
2841
- * Returns undefined if the merged result is empty.
2842
- *
2843
- * @param styles - Variable number of CSSProperties objects (can be undefined)
2844
- * @returns Merged CSSProperties object, or undefined if empty
2845
- *
2846
- * @example
2847
- * mergeStyles(
2848
- * backgroundColorStyle('surface'),
2849
- * textColorStyle('text'),
2850
- * borderColorStyle('border')
2851
- * )
2852
- * // => { backgroundColor: '...', color: '...', borderColor: '...' }
2853
- */
2854
- function mergeStyles(...styles) {
2855
- const merged = {};
2856
- for (const style of styles) {
2857
- if (!style) continue;
2858
- Object.assign(merged, style);
2859
- }
2860
- return Object.keys(merged).length ? merged : void 0;
2861
- }
2862
- //#endregion
2863
2718
  //#region ../theme-core/src/lib/media.ts
2864
2719
  const hotspotSchema$1 = z.object({
2865
2720
  x: z.number().min(0).max(1),
@@ -2917,111 +2772,6 @@ const mediaSchema$1 = z.object({
2917
2772
  transform: transformSchema$1.optional()
2918
2773
  });
2919
2774
  //#endregion
2920
- //#region ../theme-core/src/buttons/effectClassification.ts
2921
- /**
2922
- * Exhaustive live policy for every registered effect id.
2923
- *
2924
- * The resolver consumes the transition payload directly, so adding an effect
2925
- * cannot update classification without also defining its runtime behavior.
2926
- */
2927
- const BUTTON_EFFECT_POLICIES = {
2928
- "darken-background": {
2929
- classification: "colour-transition",
2930
- transition: {
2931
- kind: "adjust-shade",
2932
- direction: "darker"
2933
- }
2934
- },
2935
- "lighten-background": {
2936
- classification: "colour-transition",
2937
- transition: {
2938
- kind: "adjust-shade",
2939
- direction: "lighter"
2940
- }
2941
- },
2942
- "background-on-hover": {
2943
- classification: "colour-transition",
2944
- transition: { kind: "replace-background" }
2945
- },
2946
- "background-on-hover-alpha": {
2947
- classification: "unsupported-colour",
2948
- reason: "alpha_requires_surface"
2949
- },
2950
- "fade-background": {
2951
- classification: "unsupported-colour",
2952
- reason: "changes_element_opacity"
2953
- },
2954
- "opacity-reduce": {
2955
- classification: "unsupported-colour",
2956
- reason: "changes_element_opacity"
2957
- },
2958
- "gradient-text": {
2959
- classification: "unsupported-colour",
2960
- reason: "changes_foreground"
2961
- },
2962
- "text-color-change": {
2963
- classification: "unsupported-colour",
2964
- reason: "changes_foreground"
2965
- },
2966
- "border-color-change": {
2967
- classification: "unsupported-colour",
2968
- reason: "changes_border"
2969
- },
2970
- "aurora-glow": {
2971
- classification: "unsupported-background-overlay",
2972
- reason: "unresolved_background_overlay"
2973
- },
2974
- "cosmic-stardust": {
2975
- classification: "unsupported-background-overlay",
2976
- reason: "unresolved_background_overlay"
2977
- },
2978
- "gradient-border-fill": {
2979
- classification: "unsupported-background-overlay",
2980
- reason: "unresolved_background_overlay"
2981
- },
2982
- "animated-gradient-border-fill": {
2983
- classification: "unsupported-background-overlay",
2984
- reason: "unresolved_background_overlay"
2985
- },
2986
- "nav-underline": {
2987
- classification: "not-button",
2988
- reason: "not_button_effect"
2989
- },
2990
- "nav-frosted-base": {
2991
- classification: "not-button",
2992
- reason: "not_button_effect"
2993
- },
2994
- "nav-frosted-hover": {
2995
- classification: "not-button",
2996
- reason: "not_button_effect"
2997
- },
2998
- "nav-frosted-active": {
2999
- classification: "not-button",
3000
- reason: "not_button_effect"
3001
- },
3002
- "animated-gradient": { classification: "non-colour" },
3003
- "border-glow": { classification: "non-colour" },
3004
- "drop-shadow": { classification: "non-colour" },
3005
- "inner-shadow": { classification: "non-colour" },
3006
- "neumorphic-shadow": { classification: "non-colour" },
3007
- "outer-glow": { classification: "non-colour" },
3008
- "retro-3d-shadow": { classification: "non-colour" },
3009
- "scale-up": { classification: "non-colour" },
3010
- "scale-down": { classification: "non-colour" },
3011
- lift: { classification: "non-colour" },
3012
- "press-down": { classification: "non-colour" },
3013
- pop: { classification: "non-colour" },
3014
- "border-bottom-grow": { classification: "non-colour" },
3015
- "sketchy-border": { classification: "non-colour" },
3016
- "pulse-animation": { classification: "non-colour" }
3017
- };
3018
- function getButtonEffectPolicy(effectId) {
3019
- return Object.prototype.hasOwnProperty.call(BUTTON_EFFECT_POLICIES, effectId) ? BUTTON_EFFECT_POLICIES[effectId] : null;
3020
- }
3021
- function classifyButtonEffectId(effectId) {
3022
- return getButtonEffectPolicy(effectId)?.classification ?? "unknown";
3023
- }
3024
- //#endregion
3025
2775
  //#region ../theme-core/src/buttons/types.ts
3026
2776
  /**
3027
2777
  * Standard semantic variant roles a theme exposes.
@@ -3038,6 +2788,13 @@ const VARIANT_ROLES = [
3038
2788
  "tertiary",
3039
2789
  "accent"
3040
2790
  ];
2791
+ /**
2792
+ * Canonical persisted/CSS-safe button variant identifier.
2793
+ *
2794
+ * IDs become class selectors, so keep the contract deliberately narrower than
2795
+ * an arbitrary string and shared with every authoring/runtime boundary.
2796
+ */
2797
+ const buttonVariantIdSchema = z$1.string().min(1).max(50).regex(/^[a-z0-9-]+$/, "Button variant IDs may contain lowercase letters, numbers, and hyphens only");
3041
2798
  function parseOpaqueButtonColourToken(value) {
3042
2799
  const token = parseThemeColorToken(value);
3043
2800
  if (token === null) return null;
@@ -3052,6 +2809,109 @@ const opaqueButtonColourTokenSchema = themeColorTokenSchema.refine((value) => pa
3052
2809
  if (token === null) throw new Error("Invariant: opaque button token passed its schema");
3053
2810
  return token;
3054
2811
  });
2812
+ const buttonShadeAmountSchema = z$1.number().finite().min(0).max(900).multipleOf(100);
2813
+ const buttonShadowIntensitySchema = z$1.enum([
2814
+ "subtle",
2815
+ "medium",
2816
+ "strong"
2817
+ ]);
2818
+ /**
2819
+ * The complete persisted button-effect contract.
2820
+ *
2821
+ * Navigation has its own generic interactive-effect model. Button variants use
2822
+ * this closed union so unsupported effect IDs, unknown option keys, and unsafe
2823
+ * CSS values cannot become representable after the schema boundary.
2824
+ */
2825
+ const buttonEffectApplicationSchema = z$1.discriminatedUnion("effectId", [
2826
+ z$1.strictObject({
2827
+ effectId: z$1.literal("darken-background"),
2828
+ options: z$1.strictObject({ amount: buttonShadeAmountSchema.optional() }).optional()
2829
+ }),
2830
+ z$1.strictObject({
2831
+ effectId: z$1.literal("lighten-background"),
2832
+ options: z$1.strictObject({ amount: buttonShadeAmountSchema.optional() }).optional()
2833
+ }),
2834
+ z$1.strictObject({
2835
+ effectId: z$1.literal("background-on-hover"),
2836
+ options: z$1.strictObject({ colorToken: opaqueButtonColourTokenSchema.optional() }).optional()
2837
+ }),
2838
+ z$1.strictObject({
2839
+ effectId: z$1.literal("animated-gradient"),
2840
+ options: z$1.strictObject({ direction: z$1.enum(["horizontal", "vertical"]).optional() }).optional()
2841
+ }),
2842
+ z$1.strictObject({
2843
+ effectId: z$1.literal("drop-shadow"),
2844
+ options: z$1.strictObject({ intensity: buttonShadowIntensitySchema.optional() }).optional()
2845
+ }),
2846
+ z$1.strictObject({
2847
+ effectId: z$1.literal("inner-shadow"),
2848
+ options: z$1.strictObject({}).optional()
2849
+ }),
2850
+ z$1.strictObject({
2851
+ effectId: z$1.literal("neumorphic-shadow"),
2852
+ options: z$1.strictObject({
2853
+ mode: z$1.enum(["raised", "pressed"]).optional(),
2854
+ intensity: buttonShadowIntensitySchema.optional()
2855
+ }).optional()
2856
+ }),
2857
+ z$1.strictObject({
2858
+ effectId: z$1.literal("retro-3d-shadow"),
2859
+ options: z$1.strictObject({}).optional()
2860
+ }),
2861
+ z$1.strictObject({
2862
+ effectId: z$1.literal("scale-up"),
2863
+ options: z$1.strictObject({ scale: z$1.enum([
2864
+ "1.02",
2865
+ "1.03",
2866
+ "1.05",
2867
+ "1.10"
2868
+ ]).optional() }).optional()
2869
+ }),
2870
+ z$1.strictObject({
2871
+ effectId: z$1.literal("scale-down"),
2872
+ options: z$1.strictObject({ scale: z$1.enum([
2873
+ "0.90",
2874
+ "0.95",
2875
+ "0.97",
2876
+ "0.98"
2877
+ ]).optional() }).optional()
2878
+ }),
2879
+ z$1.strictObject({
2880
+ effectId: z$1.literal("lift"),
2881
+ options: z$1.strictObject({ amount: z$1.enum([
2882
+ "0.25",
2883
+ "0.5",
2884
+ "1"
2885
+ ]).optional() }).optional()
2886
+ }),
2887
+ z$1.strictObject({
2888
+ effectId: z$1.literal("press-down"),
2889
+ options: z$1.strictObject({}).optional()
2890
+ }),
2891
+ z$1.strictObject({
2892
+ effectId: z$1.literal("pop"),
2893
+ options: z$1.strictObject({ intensity: z$1.enum([
2894
+ "subtle",
2895
+ "medium",
2896
+ "dramatic"
2897
+ ]).optional() }).optional()
2898
+ }),
2899
+ z$1.strictObject({
2900
+ effectId: z$1.literal("border-bottom-grow"),
2901
+ options: z$1.strictObject({
2902
+ height: z$1.union([z$1.literal(1), z$1.literal(2)]).optional(),
2903
+ origin: z$1.enum([
2904
+ "left",
2905
+ "center",
2906
+ "right"
2907
+ ]).optional()
2908
+ }).optional()
2909
+ }),
2910
+ z$1.strictObject({
2911
+ effectId: z$1.literal("sketchy-border"),
2912
+ options: z$1.strictObject({ intensity: buttonShadowIntensitySchema.optional() }).optional()
2913
+ })
2914
+ ]);
3055
2915
  const cornerStyleSchema = z$1.enum([
3056
2916
  "square",
3057
2917
  "rounded",
@@ -3086,13 +2946,7 @@ const hoverTransformSchema = z$1.enum([
3086
2946
  "scale",
3087
2947
  "press"
3088
2948
  ]);
3089
- const hoverColorSchema = z$1.enum([
3090
- "none",
3091
- "brighten",
3092
- "darken",
3093
- "saturate",
3094
- "token"
3095
- ]);
2949
+ z$1.enum(["none", "token"]);
3096
2950
  const buttonPaddingPresetSchema = z$1.enum([
3097
2951
  "compact",
3098
2952
  "default",
@@ -3153,7 +3007,7 @@ const buttonSizesSchema = z$1.object({
3153
3007
  lg,
3154
3008
  xl: xl ?? lg
3155
3009
  }));
3156
- const canonicalButtonGlobalSettingsSchema = z$1.object({
3010
+ const buttonGlobalSettingsBaseSchema = z$1.strictObject({
3157
3011
  cornerStyle: cornerStyleSchema,
3158
3012
  cornerRadius: z$1.number().min(0).max(24).optional(),
3159
3013
  /**
@@ -3166,30 +3020,23 @@ const canonicalButtonGlobalSettingsSchema = z$1.object({
3166
3020
  shadow: shadowSizeSchema.optional(),
3167
3021
  textTransform: textTransformSchema,
3168
3022
  fontWeight: fontWeightSchema,
3169
- /**
3170
- * @deprecated Set per-variant via `variant.border.widthClass` instead.
3171
- * Schema field is preserved so existing presets parse; the value is unread
3172
- * by the current generator and will be removed once the legacy
3173
- * `primitives/content/components/Button.tsx` slot exports are deleted.
3174
- */
3175
- borderWidth: z$1.union([
3176
- z$1.literal(1),
3177
- z$1.literal(2),
3178
- z$1.literal(3)
3179
- ]),
3180
3023
  typography: buttonTypographySchema.optional(),
3181
3024
  fontSize: z$1.string().optional(),
3182
3025
  letterSpacing: letterSpacingSchema.optional(),
3183
3026
  italic: z$1.boolean().optional(),
3184
3027
  paddingPreset: buttonPaddingPresetSchema.optional(),
3185
3028
  hoverTransform: hoverTransformSchema,
3186
- hoverColor: hoverColorSchema,
3187
- hoverColorToken: opaqueButtonColourTokenSchema.optional(),
3188
3029
  gradientStyle: gradientStyleSchema.optional(),
3189
3030
  gradientAngle: z$1.number().min(0).max(360).optional(),
3190
3031
  gradientSharpness: gradientSharpnessSchema.optional()
3191
3032
  });
3192
- const buttonGlobalSettingsSchema = z$1.preprocess(normalizeLegacyButtonGlobalInput, canonicalButtonGlobalSettingsSchema);
3033
+ const buttonGlobalSettingsSchema = z$1.discriminatedUnion("hoverColor", [buttonGlobalSettingsBaseSchema.extend({
3034
+ hoverColor: z$1.literal("none"),
3035
+ hoverColorToken: z$1.never().optional()
3036
+ }), buttonGlobalSettingsBaseSchema.extend({
3037
+ hoverColor: z$1.literal("token"),
3038
+ hoverColorToken: opaqueButtonColourTokenSchema
3039
+ })]);
3193
3040
  const gradientDirectionSchema$1 = z$1.enum([
3194
3041
  "to-r",
3195
3042
  "to-l",
@@ -3201,11 +3048,11 @@ const gradientDirectionSchema$1 = z$1.enum([
3201
3048
  "to-bl"
3202
3049
  ]);
3203
3050
  const buttonColourTreatmentSchema = z$1.discriminatedUnion("type", [
3204
- z$1.object({
3051
+ z$1.strictObject({
3205
3052
  type: z$1.literal("solid"),
3206
3053
  colorToken: opaqueButtonColourTokenSchema
3207
3054
  }),
3208
- z$1.object({
3055
+ z$1.strictObject({
3209
3056
  type: z$1.literal("gradient"),
3210
3057
  stops: z$1.array(opaqueButtonColourTokenSchema).min(2).transform((stops) => {
3211
3058
  const [first, second, ...rest] = stops;
@@ -3219,19 +3066,15 @@ const buttonColourTreatmentSchema = z$1.discriminatedUnion("type", [
3219
3066
  direction: gradientDirectionSchema$1,
3220
3067
  foregroundToken: opaqueButtonColourTokenSchema
3221
3068
  }),
3222
- z$1.object({
3069
+ z$1.strictObject({
3223
3070
  type: z$1.literal("surface"),
3224
3071
  role: z$1.literal("link")
3225
3072
  })
3226
3073
  ]);
3227
3074
  const buttonBackgroundSchema = buttonColourTreatmentSchema;
3228
- const effectApplicationSchema$1 = z$1.object({
3229
- effectId: z$1.string(),
3230
- options: z$1.record(z$1.string(), z$1.json()).optional()
3231
- });
3232
- const buttonBorderSchema = z$1.object({ widthClass: z$1.string() });
3233
- const buttonVariantAffordanceSchema = z$1.object({ iconId: z$1.string().min(1) });
3234
- const variantShadowSchema = z$1.object({
3075
+ const buttonBorderSchema = z$1.strictObject({ widthClass: z$1.string() });
3076
+ const buttonVariantAffordanceSchema = z$1.strictObject({ iconId: z$1.string().min(1) });
3077
+ const variantShadowSchema = z$1.strictObject({
3235
3078
  elevation: z$1.enum([
3236
3079
  "none",
3237
3080
  "low",
@@ -3244,13 +3087,13 @@ const variantShadowSchema = z$1.object({
3244
3087
  "hard"
3245
3088
  ]).nullable(),
3246
3089
  position: z$1.enum(["bottom", "bottom-right"]).default("bottom"),
3247
- colorToken: themeColorTokenSchema.optional()
3090
+ colorToken: opaqueButtonColourTokenSchema.optional()
3248
3091
  });
3249
- const variantEffectsSchema = z$1.object({
3250
- base: z$1.array(effectApplicationSchema$1).optional(),
3251
- hover: z$1.array(effectApplicationSchema$1).optional(),
3252
- active: z$1.array(effectApplicationSchema$1).optional(),
3253
- focus: z$1.array(effectApplicationSchema$1).optional()
3092
+ const variantEffectsSchema = z$1.strictObject({
3093
+ base: z$1.array(buttonEffectApplicationSchema).optional(),
3094
+ hover: z$1.array(buttonEffectApplicationSchema).optional(),
3095
+ active: z$1.array(buttonEffectApplicationSchema).optional(),
3096
+ focus: z$1.array(buttonEffectApplicationSchema).optional()
3254
3097
  });
3255
3098
  /**
3256
3099
  * Per-variant size overrides schema — every entry is optional.
@@ -3271,8 +3114,8 @@ const variantSizeOverridesSchema = z$1.object({
3271
3114
  * default (e.g. link-style variants declaring zero horizontal padding at
3272
3115
  * every size).
3273
3116
  */
3274
- const canonicalButtonVariantSchema = z$1.object({
3275
- id: z$1.string(),
3117
+ const buttonVariantSchema = z$1.strictObject({
3118
+ id: buttonVariantIdSchema,
3276
3119
  name: z$1.string().min(1).max(20),
3277
3120
  enabled: z$1.boolean(),
3278
3121
  priority: prioritySchema,
@@ -3286,154 +3129,73 @@ const canonicalButtonVariantSchema = z$1.object({
3286
3129
  sizes: variantSizeOverridesSchema.optional(),
3287
3130
  affordance: buttonVariantAffordanceSchema.optional()
3288
3131
  });
3289
- /**
3290
- * Temporary persisted-theme admission boundary for issue #1206.
3291
- *
3292
- * Production inventory on 2026-07-22 found 22 rows using the old independent
3293
- * `textColorToken`/border colour shape. New source and all downstream code use
3294
- * only the canonical relationship. Delete this preprocessor after the reviewed
3295
- * production rewrite reports zero legacy rows.
3296
- */
3297
- const buttonVariantSchema = z$1.preprocess(normalizeLegacyButtonVariantInput, canonicalButtonVariantSchema);
3298
- const buttonSystemSchema = z$1.object({
3132
+ const buttonSystemSchema = z$1.strictObject({
3299
3133
  global: buttonGlobalSettingsSchema,
3300
3134
  variants: z$1.array(buttonVariantSchema).min(1).max(6),
3301
3135
  sizes: buttonSizesSchema.optional()
3136
+ }).superRefine((system, ctx) => {
3137
+ const seen = /* @__PURE__ */ new Set();
3138
+ system.variants.forEach((variant, index) => {
3139
+ if (seen.has(variant.id)) ctx.addIssue({
3140
+ code: "custom",
3141
+ path: [
3142
+ "variants",
3143
+ index,
3144
+ "id"
3145
+ ],
3146
+ message: `Duplicate button variant ID: ${variant.id}`
3147
+ });
3148
+ seen.add(variant.id);
3149
+ });
3302
3150
  });
3303
- function normalizeLegacyButtonVariantInput(input) {
3304
- if (!isUnknownRecord(input)) return input;
3305
- const background = input.background;
3306
- if (!isUnknownRecord(background)) return input;
3307
- if (!(background.type === "transparent" || Object.prototype.hasOwnProperty.call(input, "textColorToken") || isUnknownRecord(input.border) && Object.prototype.hasOwnProperty.call(input.border, "colorToken") || hasLegacyButtonEffects(input.effects) || hasLegacyAlphaToken(input, background))) return input;
3308
- const { textColorToken, ...withoutLegacyText } = input;
3309
- const normalizedBorder = isUnknownRecord(input.border) && typeof input.border.widthClass === "string" ? { widthClass: input.border.widthClass } : input.border;
3310
- const normalizedAffordance = isUnknownRecord(input.affordance) && typeof input.affordance.iconId === "string" ? { iconId: input.affordance.iconId } : input.affordance;
3311
- const normalizedEffects = normalizeLegacyButtonEffects(input.effects, background.type);
3312
- const hoverBackgroundToken = stripLegacyTokenAlpha(input.hoverBackgroundToken);
3313
- if (background.type === "transparent") return {
3314
- ...withoutLegacyText,
3315
- background: {
3316
- type: "surface",
3317
- role: "link"
3318
- },
3319
- border: normalizedBorder,
3320
- affordance: normalizedAffordance,
3321
- effects: normalizedEffects,
3322
- hoverBackgroundToken
3323
- };
3324
- if (background.type === "gradient") {
3325
- const stops = Array.isArray(background.stops) ? background.stops.map(stripLegacyTokenAlpha) : background.stops;
3326
- return {
3327
- ...withoutLegacyText,
3328
- background: {
3329
- ...background,
3330
- stops,
3331
- foregroundToken: stripLegacyTokenAlpha(background.foregroundToken ?? textColorToken)
3332
- },
3333
- border: normalizedBorder,
3334
- affordance: normalizedAffordance,
3335
- effects: normalizedEffects,
3336
- hoverBackgroundToken
3337
- };
3338
- }
3339
- return {
3340
- ...withoutLegacyText,
3341
- background: background.type === "solid" ? {
3342
- ...background,
3343
- colorToken: stripLegacyTokenAlpha(background.colorToken)
3344
- } : background,
3345
- border: normalizedBorder,
3346
- affordance: normalizedAffordance,
3347
- effects: normalizedEffects,
3348
- hoverBackgroundToken
3349
- };
3151
+ //#endregion
3152
+ //#region ../theme-core/src/surfaces/foregroundContract.ts
3153
+ const SURFACE_FOREGROUND_CSS_VARS = {
3154
+ text: "--rb-surface-text-color",
3155
+ heading: "--rb-surface-heading-color",
3156
+ link: "--rb-surface-link-color",
3157
+ supporting: "--rb-surface-supporting-color"
3158
+ };
3159
+ const DEFAULT_SURFACE_TEXT_COLOR = "rgb(var(--tb-text, 17 24 39))";
3160
+ const DEFAULT_ROLE_FALLBACKS = {
3161
+ text: DEFAULT_SURFACE_TEXT_COLOR,
3162
+ heading: DEFAULT_SURFACE_TEXT_COLOR,
3163
+ link: "rgb(var(--tb-primary, var(--tb-text, 17 24 39)))",
3164
+ supporting: "rgb(var(--tb-mutedText, 100 116 139))"
3165
+ };
3166
+ function requireSurfaceColorValue(role, value) {
3167
+ const normalized = value.trim();
3168
+ if (normalized.length === 0) throw new RangeError(`Surface foreground ${role} must be a non-empty CSS color.`);
3169
+ return normalized;
3350
3170
  }
3351
- function normalizeLegacyButtonGlobalInput(input) {
3352
- if (!isUnknownRecord(input)) return input;
3353
- const hoverColorToken = stripLegacyTokenAlpha(input.hoverColorToken);
3354
- return hoverColorToken === input.hoverColorToken ? input : {
3355
- ...input,
3356
- hoverColorToken
3171
+ function completeSurfaceForegrounds(input) {
3172
+ const text = requireSurfaceColorValue("text", input.text);
3173
+ return {
3174
+ text,
3175
+ heading: input.heading === void 0 ? text : requireSurfaceColorValue("heading", input.heading),
3176
+ link: input.link === void 0 ? text : requireSurfaceColorValue("link", input.link),
3177
+ supporting: input.supporting === void 0 ? text : requireSurfaceColorValue("supporting", input.supporting)
3357
3178
  };
3358
3179
  }
3359
- function hasLegacyAlphaToken(input, background) {
3360
- const stops = isUnknownArray(background.stops) ? background.stops : [];
3361
- return [
3362
- input.hoverBackgroundToken,
3363
- background.colorToken,
3364
- background.foregroundToken,
3365
- ...stops
3366
- ].some((token) => stripLegacyTokenAlpha(token) !== token);
3367
- }
3368
- function stripLegacyTokenAlpha(value) {
3369
- if (typeof value !== "string") return value;
3370
- const slashIndex = value.indexOf("/");
3371
- return slashIndex < 0 ? value : value.slice(0, slashIndex);
3372
- }
3373
- function hasLegacyButtonEffects(input) {
3374
- if (!isUnknownRecord(input)) return false;
3375
- return [
3376
- "base",
3377
- "hover",
3378
- "active",
3379
- "focus"
3380
- ].some((state) => {
3381
- const effects = input[state];
3382
- return Array.isArray(effects) && effects.some((effect) => {
3383
- if (!isUnknownRecord(effect) || typeof effect.effectId !== "string") return true;
3384
- const classification = classifyButtonEffectId(effect.effectId);
3385
- if (classification !== "colour-transition" && classification !== "non-colour") return true;
3386
- return effect.effectId === "background-on-hover" && isUnknownRecord(effect.options) && stripLegacyTokenAlpha(effect.options.colorToken) !== effect.options.colorToken;
3387
- });
3388
- });
3389
- }
3390
- function normalizeLegacyButtonEffects(input, backgroundType) {
3391
- if (!isUnknownRecord(input)) return input;
3392
- const normalized = {};
3393
- for (const state of [
3394
- "base",
3395
- "hover",
3396
- "active",
3397
- "focus"
3398
- ]) {
3399
- const effects = input[state];
3400
- if (!Array.isArray(effects)) continue;
3401
- const safeEffects = effects.flatMap((effect) => {
3402
- if (!isUnknownRecord(effect) || typeof effect.effectId !== "string") return [];
3403
- const classification = classifyButtonEffectId(effect.effectId);
3404
- if (classification === "non-colour") return [effect];
3405
- if (classification !== "colour-transition") return [];
3406
- if (effect.effectId === "background-on-hover") {
3407
- const options = isUnknownRecord(effect.options) ? effect.options : null;
3408
- const colorToken = options === null ? null : parseOpaqueButtonColourToken(stripLegacyTokenAlpha(options.colorToken));
3409
- return colorToken === null ? [] : [{
3410
- ...effect,
3411
- options: {
3412
- ...options,
3413
- colorToken
3414
- }
3415
- }];
3416
- }
3417
- if (backgroundType !== "solid") return [];
3418
- const rawAmount = isUnknownRecord(effect.options) ? effect.options.amount : void 0;
3419
- const amount = typeof rawAmount === "number" && rawAmount > 0 ? Math.max(100, Math.round(rawAmount / 100) * 100) : 100;
3420
- return [{
3421
- ...effect,
3422
- options: {
3423
- ...isUnknownRecord(effect.options) ? effect.options : {},
3424
- amount
3425
- }
3426
- }];
3427
- });
3428
- if (safeEffects.length > 0) normalized[state] = safeEffects;
3429
- }
3430
- return Object.keys(normalized).length === 0 ? void 0 : normalized;
3180
+ function surfaceForegroundValue(role, outsideProviderFallback = DEFAULT_ROLE_FALLBACKS[role]) {
3181
+ const roleVariable = SURFACE_FOREGROUND_CSS_VARS[role];
3182
+ const fallback = requireSurfaceColorValue("fallback", outsideProviderFallback);
3183
+ if (role === "text") return `var(${roleVariable}, ${fallback})`;
3184
+ return `var(${roleVariable}, var(${SURFACE_FOREGROUND_CSS_VARS.text}, ${fallback}))`;
3431
3185
  }
3432
- function isUnknownRecord(value) {
3433
- return typeof value === "object" && value !== null && !Array.isArray(value);
3186
+ function surfaceForegroundValueWithOpacity(role, opacityPercent) {
3187
+ if (!Number.isFinite(opacityPercent) || opacityPercent < 0 || opacityPercent > 100) throw new RangeError("Surface foreground opacity must be between 0 and 100.");
3188
+ return `color-mix(in srgb, ${surfaceForegroundValue(role)} ${opacityPercent}%, transparent)`;
3434
3189
  }
3435
- function isUnknownArray(value) {
3436
- return Array.isArray(value);
3190
+ function surfaceForegroundStyle(input) {
3191
+ const foregrounds = completeSurfaceForegrounds(input);
3192
+ return {
3193
+ color: foregrounds.text,
3194
+ [SURFACE_FOREGROUND_CSS_VARS.text]: foregrounds.text,
3195
+ [SURFACE_FOREGROUND_CSS_VARS.heading]: foregrounds.heading,
3196
+ [SURFACE_FOREGROUND_CSS_VARS.link]: foregrounds.link,
3197
+ [SURFACE_FOREGROUND_CSS_VARS.supporting]: foregrounds.supporting
3198
+ };
3437
3199
  }
3438
3200
  buttonSizeNameSchema.options;
3439
3201
  //#endregion
@@ -3590,7 +3352,6 @@ const quietArrowRecipe = defineButtonStyleRecipe({
3590
3352
  cornerStyle: "rounded",
3591
3353
  textTransform: "uppercase",
3592
3354
  fontWeight: 500,
3593
- borderWidth: 1,
3594
3355
  typography: "body",
3595
3356
  fontSize: "text-sm",
3596
3357
  letterSpacing: "loose",
@@ -3654,7 +3415,7 @@ const quietArrowRecipe = defineButtonStyleRecipe({
3654
3415
  affordance: { iconId: "ArrowRight" },
3655
3416
  effects: { hover: [{
3656
3417
  effectId: "background-on-hover",
3657
- options: { colorToken: "surfaceAlt" }
3418
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surfaceAlt") }
3658
3419
  }] }
3659
3420
  }
3660
3421
  },
@@ -3765,7 +3526,6 @@ const softPillRecipe = defineStaticButtonStyleRecipe({
3765
3526
  shadow: "low",
3766
3527
  textTransform: "none",
3767
3528
  fontWeight: 500,
3768
- borderWidth: 2,
3769
3529
  hoverTransform: "lift",
3770
3530
  hoverColor: "none"
3771
3531
  },
@@ -3784,10 +3544,7 @@ const softPillRecipe = defineStaticButtonStyleRecipe({
3784
3544
  position: "bottom"
3785
3545
  },
3786
3546
  effects: {
3787
- hover: [{
3788
- effectId: "lift",
3789
- options: { translateY: "-1px" }
3790
- }],
3547
+ hover: [{ effectId: "lift" }],
3791
3548
  active: [{
3792
3549
  effectId: "scale-down",
3793
3550
  options: { scale: "0.98" }
@@ -3806,7 +3563,7 @@ const softPillRecipe = defineStaticButtonStyleRecipe({
3806
3563
  border: { widthClass: "border-2" },
3807
3564
  effects: { hover: [{
3808
3565
  effectId: "background-on-hover",
3809
- options: { colorToken: "surface" }
3566
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surface") }
3810
3567
  }] }
3811
3568
  }
3812
3569
  },
@@ -3821,7 +3578,7 @@ const softPillRecipe = defineStaticButtonStyleRecipe({
3821
3578
  border: { widthClass: "border" },
3822
3579
  effects: { hover: [{
3823
3580
  effectId: "background-on-hover",
3824
- options: { colorToken: "surface" }
3581
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surface") }
3825
3582
  }] }
3826
3583
  }
3827
3584
  },
@@ -3835,7 +3592,7 @@ const softPillRecipe = defineStaticButtonStyleRecipe({
3835
3592
  borderRadius: "rounded-full",
3836
3593
  effects: { hover: [{
3837
3594
  effectId: "background-on-hover",
3838
- options: { colorToken: "surface" }
3595
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surface") }
3839
3596
  }] }
3840
3597
  }
3841
3598
  },
@@ -3865,7 +3622,6 @@ const earthPillRecipe = defineStaticButtonStyleRecipe({
3865
3622
  shadow: "low",
3866
3623
  textTransform: "none",
3867
3624
  fontWeight: 500,
3868
- borderWidth: 1,
3869
3625
  hoverTransform: "lift",
3870
3626
  hoverColor: "none",
3871
3627
  typography: "body",
@@ -3901,12 +3657,9 @@ const earthPillRecipe = defineStaticButtonStyleRecipe({
3901
3657
  position: "bottom"
3902
3658
  },
3903
3659
  effects: {
3904
- hover: [{
3905
- effectId: "lift",
3906
- options: { translateY: "-1px" }
3907
- }, {
3660
+ hover: [{ effectId: "lift" }, {
3908
3661
  effectId: "background-on-hover",
3909
- options: { colorToken: "accent" }
3662
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("accent") }
3910
3663
  }],
3911
3664
  active: [{
3912
3665
  effectId: "scale-down",
@@ -3926,7 +3679,7 @@ const earthPillRecipe = defineStaticButtonStyleRecipe({
3926
3679
  border: { widthClass: "border" },
3927
3680
  effects: { hover: [{
3928
3681
  effectId: "background-on-hover",
3929
- options: { colorToken: "muted" }
3682
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("muted") }
3930
3683
  }] }
3931
3684
  }
3932
3685
  },
@@ -3941,7 +3694,7 @@ const earthPillRecipe = defineStaticButtonStyleRecipe({
3941
3694
  border: { widthClass: "border" },
3942
3695
  effects: { hover: [{
3943
3696
  effectId: "background-on-hover",
3944
- options: { colorToken: "surfaceAlt" }
3697
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surfaceAlt") }
3945
3698
  }] }
3946
3699
  }
3947
3700
  },
@@ -4001,7 +3754,6 @@ const confidentChipRecipe = defineStaticButtonStyleRecipe({
4001
3754
  shadow: "medium",
4002
3755
  textTransform: "none",
4003
3756
  fontWeight: 600,
4004
- borderWidth: 1,
4005
3757
  hoverTransform: "none",
4006
3758
  hoverColor: "none"
4007
3759
  },
@@ -4042,7 +3794,7 @@ const confidentChipRecipe = defineStaticButtonStyleRecipe({
4042
3794
  border: { widthClass: "border" },
4043
3795
  effects: { hover: [{
4044
3796
  effectId: "background-on-hover",
4045
- options: { colorToken: "background" }
3797
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("background") }
4046
3798
  }] }
4047
3799
  }
4048
3800
  },
@@ -4057,7 +3809,7 @@ const confidentChipRecipe = defineStaticButtonStyleRecipe({
4057
3809
  border: { widthClass: "border" },
4058
3810
  effects: { hover: [{
4059
3811
  effectId: "background-on-hover",
4060
- options: { colorToken: "surface" }
3812
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surface") }
4061
3813
  }] }
4062
3814
  }
4063
3815
  },
@@ -4071,7 +3823,7 @@ const confidentChipRecipe = defineStaticButtonStyleRecipe({
4071
3823
  borderRadius: "rounded-md",
4072
3824
  effects: { hover: [{
4073
3825
  effectId: "background-on-hover",
4074
- options: { colorToken: "surface" }
3826
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surface") }
4075
3827
  }] }
4076
3828
  }
4077
3829
  },
@@ -4106,7 +3858,6 @@ const editorialLinkRecipe = defineStaticButtonStyleRecipe({
4106
3858
  cornerStyle: "square",
4107
3859
  textTransform: "none",
4108
3860
  fontWeight: 500,
4109
- borderWidth: 1,
4110
3861
  hoverTransform: "none",
4111
3862
  hoverColor: "none"
4112
3863
  },
@@ -4124,7 +3875,6 @@ const editorialLinkRecipe = defineStaticButtonStyleRecipe({
4124
3875
  effectId: "border-bottom-grow",
4125
3876
  options: {
4126
3877
  height: 2,
4127
- colorToken: "text",
4128
3878
  origin: "left"
4129
3879
  }
4130
3880
  }] }
@@ -4143,7 +3893,6 @@ const editorialLinkRecipe = defineStaticButtonStyleRecipe({
4143
3893
  effectId: "border-bottom-grow",
4144
3894
  options: {
4145
3895
  height: 1,
4146
- colorToken: "mutedText",
4147
3896
  origin: "left"
4148
3897
  }
4149
3898
  }] }
@@ -4162,7 +3911,6 @@ const editorialLinkRecipe = defineStaticButtonStyleRecipe({
4162
3911
  effectId: "border-bottom-grow",
4163
3912
  options: {
4164
3913
  height: 1,
4165
- colorToken: "accent",
4166
3914
  origin: "left"
4167
3915
  }
4168
3916
  }] }
@@ -4186,7 +3934,6 @@ const editorialLinkRecipe = defineStaticButtonStyleRecipe({
4186
3934
  effectId: "border-bottom-grow",
4187
3935
  options: {
4188
3936
  height: 2,
4189
- colorToken: "accent",
4190
3937
  origin: "left"
4191
3938
  }
4192
3939
  }] } }
@@ -4208,7 +3955,6 @@ const pebbleRecipe = defineStaticButtonStyleRecipe({
4208
3955
  cornerStyle: "pill",
4209
3956
  textTransform: "none",
4210
3957
  fontWeight: 500,
4211
- borderWidth: 2,
4212
3958
  hoverTransform: "none",
4213
3959
  hoverColor: "none"
4214
3960
  },
@@ -4253,7 +3999,7 @@ const pebbleRecipe = defineStaticButtonStyleRecipe({
4253
3999
  border: { widthClass: "border-2" },
4254
4000
  effects: { hover: [{
4255
4001
  effectId: "background-on-hover",
4256
- options: { colorToken: "accent" }
4002
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("accent") }
4257
4003
  }] }
4258
4004
  }
4259
4005
  },
@@ -4268,7 +4014,7 @@ const pebbleRecipe = defineStaticButtonStyleRecipe({
4268
4014
  border: { widthClass: "border" },
4269
4015
  effects: { hover: [{
4270
4016
  effectId: "background-on-hover",
4271
- options: { colorToken: "surface" }
4017
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surface") }
4272
4018
  }] }
4273
4019
  }
4274
4020
  },
@@ -4323,7 +4069,6 @@ const brushedWashRecipe = defineStaticButtonStyleRecipe({
4323
4069
  shadow: "low",
4324
4070
  textTransform: "none",
4325
4071
  fontWeight: 500,
4326
- borderWidth: 1,
4327
4072
  hoverTransform: "none",
4328
4073
  hoverColor: "none"
4329
4074
  },
@@ -4388,7 +4133,7 @@ const brushedWashRecipe = defineStaticButtonStyleRecipe({
4388
4133
  border: { widthClass: "border" },
4389
4134
  effects: { hover: [{
4390
4135
  effectId: "background-on-hover",
4391
- options: { colorToken: "surface" }
4136
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surface") }
4392
4137
  }] }
4393
4138
  }
4394
4139
  },
@@ -4402,7 +4147,7 @@ const brushedWashRecipe = defineStaticButtonStyleRecipe({
4402
4147
  borderRadius: "rounded-lg",
4403
4148
  effects: { hover: [{
4404
4149
  effectId: "background-on-hover",
4405
- options: { colorToken: "surface" }
4150
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surface") }
4406
4151
  }] }
4407
4152
  }
4408
4153
  },
@@ -4431,7 +4176,6 @@ const inkStampRecipe = defineStaticButtonStyleRecipe({
4431
4176
  cornerStyle: "rounded",
4432
4177
  textTransform: "uppercase",
4433
4178
  fontWeight: 600,
4434
- borderWidth: 1,
4435
4179
  hoverTransform: "none",
4436
4180
  hoverColor: "none",
4437
4181
  letterSpacing: "loose"
@@ -4489,7 +4233,7 @@ const inkStampRecipe = defineStaticButtonStyleRecipe({
4489
4233
  border: { widthClass: "border-2" },
4490
4234
  effects: { hover: [{
4491
4235
  effectId: "background-on-hover",
4492
- options: { colorToken: "surface" }
4236
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surface") }
4493
4237
  }] }
4494
4238
  }
4495
4239
  },
@@ -4504,7 +4248,7 @@ const inkStampRecipe = defineStaticButtonStyleRecipe({
4504
4248
  border: { widthClass: "border-2" },
4505
4249
  effects: { hover: [{
4506
4250
  effectId: "background-on-hover",
4507
- options: { colorToken: "surface" }
4251
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surface") }
4508
4252
  }] }
4509
4253
  }
4510
4254
  },
@@ -4538,7 +4282,6 @@ const inkStampRecipe = defineStaticButtonStyleRecipe({
4538
4282
  effectId: "border-bottom-grow",
4539
4283
  options: {
4540
4284
  height: 1,
4541
- colorToken: "accent",
4542
4285
  origin: "left"
4543
4286
  }
4544
4287
  }] }
@@ -4569,7 +4312,6 @@ const flatInkRecipe = defineStaticButtonStyleRecipe({
4569
4312
  cornerStyle: "rounded",
4570
4313
  textTransform: "none",
4571
4314
  fontWeight: 600,
4572
- borderWidth: 1,
4573
4315
  typography: "body",
4574
4316
  letterSpacing: "tight",
4575
4317
  paddingPreset: "default",
@@ -4601,12 +4343,9 @@ const flatInkRecipe = defineStaticButtonStyleRecipe({
4601
4343
  },
4602
4344
  borderRadius: "rounded-lg",
4603
4345
  affordance: { iconId: "ArrowRight" },
4604
- effects: { hover: [{
4605
- effectId: "lift",
4606
- options: { translateY: "-2px" }
4607
- }, {
4346
+ effects: { hover: [{ effectId: "lift" }, {
4608
4347
  effectId: "background-on-hover",
4609
- options: { colorToken: "secondary" }
4348
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("secondary") }
4610
4349
  }] }
4611
4350
  }
4612
4351
  },
@@ -4619,12 +4358,9 @@ const flatInkRecipe = defineStaticButtonStyleRecipe({
4619
4358
  },
4620
4359
  borderRadius: "rounded-lg",
4621
4360
  border: { widthClass: "border" },
4622
- effects: { hover: [{
4623
- effectId: "lift",
4624
- options: { translateY: "-2px" }
4625
- }, {
4361
+ effects: { hover: [{ effectId: "lift" }, {
4626
4362
  effectId: "background-on-hover",
4627
- options: { colorToken: "surfaceAlt" }
4363
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surfaceAlt") }
4628
4364
  }] }
4629
4365
  }
4630
4366
  },
@@ -4637,12 +4373,9 @@ const flatInkRecipe = defineStaticButtonStyleRecipe({
4637
4373
  },
4638
4374
  borderRadius: "rounded-lg",
4639
4375
  border: { widthClass: "border" },
4640
- effects: { hover: [{
4641
- effectId: "lift",
4642
- options: { translateY: "-2px" }
4643
- }, {
4376
+ effects: { hover: [{ effectId: "lift" }, {
4644
4377
  effectId: "background-on-hover",
4645
- options: { colorToken: "surfaceAlt" }
4378
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surfaceAlt") }
4646
4379
  }] }
4647
4380
  }
4648
4381
  },
@@ -4654,10 +4387,7 @@ const flatInkRecipe = defineStaticButtonStyleRecipe({
4654
4387
  role: "link"
4655
4388
  },
4656
4389
  borderRadius: "rounded-lg",
4657
- effects: { hover: [{
4658
- effectId: "lift",
4659
- options: { translateY: "-2px" }
4660
- }] }
4390
+ effects: { hover: [{ effectId: "lift" }] }
4661
4391
  }
4662
4392
  },
4663
4393
  accent: {
@@ -4669,10 +4399,7 @@ const flatInkRecipe = defineStaticButtonStyleRecipe({
4669
4399
  },
4670
4400
  borderRadius: "rounded-lg",
4671
4401
  affordance: { iconId: "ArrowRight" },
4672
- effects: { hover: [{
4673
- effectId: "lift",
4674
- options: { translateY: "-2px" }
4675
- }] }
4402
+ effects: { hover: [{ effectId: "lift" }] }
4676
4403
  }
4677
4404
  }
4678
4405
  }
@@ -4693,9 +4420,8 @@ const showtimePillRecipe = defineStaticButtonStyleRecipe({
4693
4420
  shadow: "low",
4694
4421
  textTransform: "uppercase",
4695
4422
  fontWeight: 700,
4696
- borderWidth: 2,
4697
4423
  hoverTransform: "lift",
4698
- hoverColor: "darken",
4424
+ hoverColor: "none",
4699
4425
  typography: "body",
4700
4426
  paddingPreset: "spacious",
4701
4427
  italic: false
@@ -4753,7 +4479,7 @@ const showtimePillRecipe = defineStaticButtonStyleRecipe({
4753
4479
  border: { widthClass: "border-2" },
4754
4480
  effects: { hover: [{
4755
4481
  effectId: "background-on-hover",
4756
- options: { colorToken: "background" }
4482
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("background") }
4757
4483
  }] }
4758
4484
  }
4759
4485
  },
@@ -4767,7 +4493,7 @@ const showtimePillRecipe = defineStaticButtonStyleRecipe({
4767
4493
  borderRadius: "rounded-full",
4768
4494
  effects: { hover: [{
4769
4495
  effectId: "background-on-hover",
4770
- options: { colorToken: "surface" }
4496
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surface") }
4771
4497
  }] }
4772
4498
  }
4773
4499
  },
@@ -4802,7 +4528,6 @@ const joyStampRecipe = defineStaticButtonStyleRecipe({
4802
4528
  typography: "heading",
4803
4529
  fontWeight: 700,
4804
4530
  fontSize: "text-lg",
4805
- borderWidth: 2,
4806
4531
  hoverTransform: "none",
4807
4532
  hoverColor: "none"
4808
4533
  },
@@ -4837,7 +4562,7 @@ const joyStampRecipe = defineStaticButtonStyleRecipe({
4837
4562
  elevation: "high",
4838
4563
  softness: "hard",
4839
4564
  position: "bottom-right",
4840
- colorToken: "text"
4565
+ colorToken: unsafeAsOpaqueButtonColourToken("text")
4841
4566
  },
4842
4567
  effects: { hover: [{ effectId: "press-down" }] }
4843
4568
  }
@@ -4855,7 +4580,7 @@ const joyStampRecipe = defineStaticButtonStyleRecipe({
4855
4580
  elevation: "high",
4856
4581
  softness: "hard",
4857
4582
  position: "bottom-right",
4858
- colorToken: "secondary"
4583
+ colorToken: unsafeAsOpaqueButtonColourToken("secondary")
4859
4584
  },
4860
4585
  effects: { hover: [{ effectId: "press-down" }] }
4861
4586
  }
@@ -4900,7 +4625,6 @@ const ornateRitualRecipe = defineStaticButtonStyleRecipe({
4900
4625
  cornerStyle: "rounded",
4901
4626
  textTransform: "uppercase",
4902
4627
  fontWeight: 600,
4903
- borderWidth: 1,
4904
4628
  hoverTransform: "none",
4905
4629
  hoverColor: "none",
4906
4630
  letterSpacing: "loose"
@@ -4936,7 +4660,7 @@ const ornateRitualRecipe = defineStaticButtonStyleRecipe({
4936
4660
  effects: {
4937
4661
  hover: [{
4938
4662
  effectId: "background-on-hover",
4939
- options: { colorToken: "primary-100" }
4663
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("primary-100") }
4940
4664
  }],
4941
4665
  active: [{
4942
4666
  effectId: "scale-down",
@@ -4956,7 +4680,7 @@ const ornateRitualRecipe = defineStaticButtonStyleRecipe({
4956
4680
  border: { widthClass: "border" },
4957
4681
  effects: { hover: [{
4958
4682
  effectId: "background-on-hover",
4959
- options: { colorToken: "surface" }
4683
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surface") }
4960
4684
  }] }
4961
4685
  }
4962
4686
  },
@@ -4971,7 +4695,7 @@ const ornateRitualRecipe = defineStaticButtonStyleRecipe({
4971
4695
  border: { widthClass: "border" },
4972
4696
  effects: { hover: [{
4973
4697
  effectId: "background-on-hover",
4974
- options: { colorToken: "muted" }
4698
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("muted") }
4975
4699
  }] }
4976
4700
  }
4977
4701
  },
@@ -5005,7 +4729,6 @@ const ornateRitualRecipe = defineStaticButtonStyleRecipe({
5005
4729
  effectId: "border-bottom-grow",
5006
4730
  options: {
5007
4731
  height: 1,
5008
- colorToken: "accent",
5009
4732
  origin: "left"
5010
4733
  }
5011
4734
  }] }
@@ -6110,6 +5833,102 @@ new Set(themeV2NormalEditorRawStyleFieldNames);
6110
5833
  const pageDesignEditorBackgroundOverrideOwner = "page-design-editor";
6111
5834
  const siteChromeBackgroundOverrideOwner = "site-chrome-editor";
6112
5835
  //#endregion
5836
+ //#region ../theme-core/src/utils/colorStyles.ts
5837
+ const COLOR_VAR_PREFIX = "--tb-";
5838
+ function parseToken(source) {
5839
+ const parts = parseColorTokenParts(source);
5840
+ if (parts.kind === "raw") return {
5841
+ token: source,
5842
+ raw: parts.value
5843
+ };
5844
+ if (parts.kind === "invalid") return { token: source };
5845
+ return {
5846
+ token: parts.token,
5847
+ opacityPercent: parts.opacityPercent === null ? void 0 : parts.opacityPercent
5848
+ };
5849
+ }
5850
+ const SURFACE_TEXT_ROLE_BY_TOKEN = {
5851
+ text: "text",
5852
+ heading: "heading",
5853
+ mutedText: "supporting"
5854
+ };
5855
+ function surfaceRoleForTextToken(token) {
5856
+ return Object.prototype.hasOwnProperty.call(SURFACE_TEXT_ROLE_BY_TOKEN, token) ? SURFACE_TEXT_ROLE_BY_TOKEN[token] : null;
5857
+ }
5858
+ /**
5859
+ * Converts a theme color token to a CSS rgb value.
5860
+ * This is the primary function for applying theme colors to CSS properties.
5861
+ *
5862
+ * @param token - Theme color token (semantic, with opacity, or raw)
5863
+ * @returns CSS color value (rgb with optional alpha, or raw CSS value)
5864
+ *
5865
+ * @example
5866
+ * rgbColorValue('primary') // => 'rgb(var(--tb-primary))'
5867
+ * rgbColorValue('surface/95') // => 'rgb(var(--tb-surface) / 0.95)'
5868
+ * rgbColorValue('raw:transparent') // => 'transparent'
5869
+ */
5870
+ function rgbColorValue(token) {
5871
+ const { token: baseToken, opacityPercent, raw } = parseToken(token);
5872
+ if (raw) return raw;
5873
+ const cssVar = `${COLOR_VAR_PREFIX}${baseToken}`;
5874
+ if (opacityPercent === void 0) return `rgb(var(${cssVar}))`;
5875
+ return `rgb(var(${cssVar}) / ${opacityPercent / 100})`;
5876
+ }
5877
+ /**
5878
+ * Creates a backgroundColor style object from a theme token.
5879
+ *
5880
+ * @param token - Theme color token
5881
+ * @returns CSSProperties with backgroundColor
5882
+ */
5883
+ function backgroundColorStyle(token) {
5884
+ return { backgroundColor: rgbColorValue(token) };
5885
+ }
5886
+ /**
5887
+ * Creates a text color style object from a theme token.
5888
+ *
5889
+ * @param token - Theme color token
5890
+ * @returns CSSProperties with color
5891
+ */
5892
+ function textColorStyle(token) {
5893
+ const parsed = parseToken(token);
5894
+ const surfaceRole = parsed.raw ? null : surfaceRoleForTextToken(parsed.token);
5895
+ if (surfaceRole) return { color: parsed.opacityPercent === void 0 ? surfaceForegroundValue(surfaceRole) : surfaceForegroundValueWithOpacity(surfaceRole, parsed.opacityPercent) };
5896
+ return { color: rgbColorValue(token) };
5897
+ }
5898
+ /**
5899
+ * Creates a border color style object from a theme token.
5900
+ *
5901
+ * @param token - Theme color token
5902
+ * @returns CSSProperties with borderColor
5903
+ */
5904
+ function borderColorStyle(token) {
5905
+ return { borderColor: rgbColorValue(token) };
5906
+ }
5907
+ /**
5908
+ * Merges multiple CSSProperties objects into a single object.
5909
+ * Later styles override earlier ones. Undefined values are filtered out.
5910
+ * Returns undefined if the merged result is empty.
5911
+ *
5912
+ * @param styles - Variable number of CSSProperties objects (can be undefined)
5913
+ * @returns Merged CSSProperties object, or undefined if empty
5914
+ *
5915
+ * @example
5916
+ * mergeStyles(
5917
+ * backgroundColorStyle('surface'),
5918
+ * textColorStyle('text'),
5919
+ * borderColorStyle('border')
5920
+ * )
5921
+ * // => { backgroundColor: '...', color: '...', borderColor: '...' }
5922
+ */
5923
+ function mergeStyles(...styles) {
5924
+ const merged = {};
5925
+ for (const style of styles) {
5926
+ if (!style) continue;
5927
+ Object.assign(merged, style);
5928
+ }
5929
+ return Object.keys(merged).length ? merged : void 0;
5930
+ }
5931
+ //#endregion
6113
5932
  //#region ../theme-core/src/utils/tokenOrColor.ts
6114
5933
  /**
6115
5934
  * Runtime color-reference fields intentionally accept any string, including
@@ -13103,6 +12922,7 @@ const DISPLAY_MEDIA_KINDS = [
13103
12922
  "video",
13104
12923
  "audio"
13105
12924
  ];
12925
+ const DEFAULT_MEDIA_FIELD_KINDS = ["image"];
13106
12926
  const PUBLIC_FILE_FIELD_KINDS = [
13107
12927
  "document",
13108
12928
  "spreadsheet",
@@ -13303,18 +13123,28 @@ const inlineTextFieldSchema = baseFieldSchema.extend({
13303
13123
  maxLength: z$1.number().int().positive().optional(),
13304
13124
  plainTextField: z$1.string().min(1).optional()
13305
13125
  });
13126
+ function hasMediaDefaultIdentifier(value) {
13127
+ return value !== null && typeof value === "object" && !Array.isArray(value) && typeof value.identifier === "string" && value.identifier.trim().length > 0;
13128
+ }
13129
+ function validateMediaFieldDefault(field, ctx) {
13130
+ if (field.defaultValue !== void 0 && field.defaultValue !== null && !hasMediaDefaultIdentifier(field.defaultValue)) ctx.addIssue({
13131
+ code: z$1.ZodIssueCode.custom,
13132
+ path: ["defaultValue"],
13133
+ message: `${field.type} defaultValue must be null or an object with a non-empty identifier`
13134
+ });
13135
+ }
13306
13136
  const mediaFieldSchema = baseFieldSchema.extend({
13307
13137
  type: z$1.literal("media"),
13308
- mediaKinds: z$1.array(z$1.enum(MEDIA_KINDS)).default(["image"]).transform((kinds) => {
13138
+ mediaKinds: z$1.array(z$1.enum(MEDIA_KINDS)).default([...DEFAULT_MEDIA_FIELD_KINDS]).transform((kinds) => {
13309
13139
  const displayKinds = kinds.filter(isDisplayMediaKind);
13310
- return displayKinds.length > 0 ? displayKinds : ["image"];
13140
+ return displayKinds.length > 0 ? displayKinds : [...DEFAULT_MEDIA_FIELD_KINDS];
13311
13141
  }),
13312
13142
  aspectRatio: z$1.string().optional()
13313
- });
13143
+ }).superRefine(validateMediaFieldDefault);
13314
13144
  const fileFieldSchema = baseFieldSchema.extend({
13315
13145
  type: z$1.literal("file"),
13316
13146
  fileKinds: z$1.array(z$1.enum(PUBLIC_FILE_FIELD_KINDS)).default([...PUBLIC_FILE_FIELD_KINDS])
13317
- });
13147
+ }).superRefine(validateMediaFieldDefault);
13318
13148
  const booleanFieldSchema = baseFieldSchema.extend({ type: z$1.literal("boolean") });
13319
13149
  const dateFieldSchema = baseFieldSchema.extend({ type: z$1.literal("date") });
13320
13150
  const timeFieldSchema = baseFieldSchema.extend({ type: z$1.literal("time") });
@@ -22102,11 +21932,8 @@ const mediaSchema = z.discriminatedUnion("type", [
22102
21932
  * This module provides a single source of truth for TipTap rich text validation
22103
21933
  * across both the block-form editor and the block rendering system.
22104
21934
  *
22105
- * Format compatibility:
22106
- * - Unwrapped format (new): { type: 'doc', content: [...] }
22107
- * - Wrapped format (legacy): { doc: { type: 'doc', content: [...] } }
22108
- *
22109
- * Both formats are supported for backward compatibility during migration.
21935
+ * Rich-text fields use one canonical root shape:
21936
+ * `{ type: 'doc', content: [...] }`.
22110
21937
  */
22111
21938
  /**
22112
21939
  * TipTap document node schema (recursive structure)
@@ -22119,17 +21946,40 @@ const mediaSchema = z.discriminatedUnion("type", [
22119
21946
  * - marks: Text formatting marks (e.g., bold, italic)
22120
21947
  */
22121
21948
  const TipTapMarkSchema = z$1.object({
22122
- type: z$1.string(),
21949
+ type: z$1.string().min(1),
22123
21950
  attrs: z$1.record(z$1.string(), z$1.unknown()).optional()
22124
- });
21951
+ }).strict();
22125
21952
  const TipTapNodeSchema = z$1.lazy(() => z$1.object({
22126
- type: z$1.string(),
21953
+ type: z$1.string().min(1),
22127
21954
  content: z$1.array(TipTapNodeSchema).optional(),
22128
21955
  text: z$1.string().optional(),
22129
21956
  attrs: z$1.record(z$1.string(), z$1.unknown()).optional(),
22130
21957
  marks: z$1.array(TipTapMarkSchema).optional()
21958
+ }).strict().superRefine((node, ctx) => {
21959
+ if (node.type === "doc") ctx.addIssue({
21960
+ code: "custom",
21961
+ path: ["type"],
21962
+ message: "Document nodes are only valid at the rich-text root"
21963
+ });
21964
+ if (node.type === "text") {
21965
+ if (node.text === void 0 || node.text.length === 0) ctx.addIssue({
21966
+ code: "custom",
21967
+ path: ["text"],
21968
+ message: "Text nodes require a non-empty text value"
21969
+ });
21970
+ if (node.content !== void 0) ctx.addIssue({
21971
+ code: "custom",
21972
+ path: ["content"],
21973
+ message: "Text nodes cannot contain child nodes"
21974
+ });
21975
+ return;
21976
+ }
21977
+ if (node.text !== void 0) ctx.addIssue({
21978
+ code: "custom",
21979
+ path: ["text"],
21980
+ message: "Only text nodes can contain a text value"
21981
+ });
22131
21982
  }));
22132
- z$1.union([TipTapNodeSchema, z$1.object({ doc: TipTapNodeSchema })]);
22133
21983
  /**
22134
21984
  * Canonical schema for a TipTap rich-text document root.
22135
21985
  *
@@ -22138,13 +21988,11 @@ z$1.union([TipTapNodeSchema, z$1.object({ doc: TipTapNodeSchema })]);
22138
21988
  * (dummy content, editor output, migrations) must emit, and the shape every
22139
21989
  * non-legacy consumer can rely on.
22140
21990
  *
22141
- * Legacy envelopes are read-tolerated by {@link RichTextValueSchema} but
22142
- * normalised before reaching anywhere typed as `RichTextDoc`.
22143
21991
  */
22144
21992
  const RichTextDocSchema = z$1.object({
22145
21993
  type: z$1.literal("doc"),
22146
21994
  content: z$1.array(TipTapNodeSchema)
22147
- });
21995
+ }).strict();
22148
21996
  function createHardBreakNode() {
22149
21997
  return { type: "hardBreak" };
22150
21998
  }
@@ -34892,17 +34740,12 @@ function stringToTipTapDoc(text) {
34892
34740
  * Handles:
34893
34741
  * - Plain strings → TipTap doc with paragraphs
34894
34742
  * - Already valid TipTap docs → pass through
34895
- * - Legacy { doc: {...} } wrapper → unwrap
34896
34743
  */
34897
34744
  function coerceRichTextDefaultValue(value) {
34898
34745
  if (value === null || value === void 0) return null;
34899
- if (value && typeof value === "object" && "doc" in value) {
34900
- const doc = value.doc;
34901
- if (doc && typeof doc === "object" && "type" in doc) return doc;
34902
- }
34903
34746
  if (typeof value === "string") return stringToTipTapDoc(value);
34904
- if (value && typeof value === "object" && "type" in value) return value;
34905
- return null;
34747
+ const parsed = RichTextDocSchema.safeParse(value);
34748
+ return parsed.success ? parsed.data : null;
34906
34749
  }
34907
34750
  /**
34908
34751
  * Check if a Pass 1 field is a repeater field.
@@ -35977,7 +35820,7 @@ ${fieldList}
35977
35820
 
35978
35821
  1. **Text fields**: Extract plain text content, strip HTML tags
35979
35822
  2. **RichText fields**: Preserve structure as simplified JSON (type: "doc", content: [...])
35980
- 3. **Media fields**: Extract src URL, alt text → { src: "...", alt: "..." }
35823
+ 3. **Media fields**: Use only an existing CMS media identifier → { type: "image", identifier: "...", alt: "..." }. Never emit a URL-only media object or invent an identifier; omit the field if no identifier is available.
35981
35824
  4. **Link fields**: Extract href, label → { href: "...", label: "..." }
35982
35825
  5. **Repeater fields**: Create array of objects with item field values
35983
35826
  6. **Select fields**: Match to one of the allowed options