@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
@@ -3254,151 +3254,6 @@ z$1.discriminatedUnion("kind", [
3254
3254
  })
3255
3255
  ]);
3256
3256
  //#endregion
3257
- //#region ../theme-core/src/surfaces/foregroundContract.ts
3258
- const SURFACE_FOREGROUND_CSS_VARS = {
3259
- text: "--rb-surface-text-color",
3260
- heading: "--rb-surface-heading-color",
3261
- link: "--rb-surface-link-color",
3262
- supporting: "--rb-surface-supporting-color"
3263
- };
3264
- const DEFAULT_SURFACE_TEXT_COLOR = "rgb(var(--tb-text, 17 24 39))";
3265
- const DEFAULT_ROLE_FALLBACKS = {
3266
- text: DEFAULT_SURFACE_TEXT_COLOR,
3267
- heading: DEFAULT_SURFACE_TEXT_COLOR,
3268
- link: "rgb(var(--tb-primary, var(--tb-text, 17 24 39)))",
3269
- supporting: "rgb(var(--tb-mutedText, 100 116 139))"
3270
- };
3271
- function requireSurfaceColorValue(role, value) {
3272
- const normalized = value.trim();
3273
- if (normalized.length === 0) throw new RangeError(`Surface foreground ${role} must be a non-empty CSS color.`);
3274
- return normalized;
3275
- }
3276
- function completeSurfaceForegrounds(input) {
3277
- const text = requireSurfaceColorValue("text", input.text);
3278
- return {
3279
- text,
3280
- heading: input.heading === void 0 ? text : requireSurfaceColorValue("heading", input.heading),
3281
- link: input.link === void 0 ? text : requireSurfaceColorValue("link", input.link),
3282
- supporting: input.supporting === void 0 ? text : requireSurfaceColorValue("supporting", input.supporting)
3283
- };
3284
- }
3285
- function surfaceForegroundValue(role, outsideProviderFallback = DEFAULT_ROLE_FALLBACKS[role]) {
3286
- const roleVariable = SURFACE_FOREGROUND_CSS_VARS[role];
3287
- const fallback = requireSurfaceColorValue("fallback", outsideProviderFallback);
3288
- if (role === "text") return `var(${roleVariable}, ${fallback})`;
3289
- return `var(${roleVariable}, var(${SURFACE_FOREGROUND_CSS_VARS.text}, ${fallback}))`;
3290
- }
3291
- function surfaceForegroundValueWithOpacity(role, opacityPercent) {
3292
- if (!Number.isFinite(opacityPercent) || opacityPercent < 0 || opacityPercent > 100) throw new RangeError("Surface foreground opacity must be between 0 and 100.");
3293
- return `color-mix(in srgb, ${surfaceForegroundValue(role)} ${opacityPercent}%, transparent)`;
3294
- }
3295
- function surfaceForegroundStyle(input) {
3296
- const foregrounds = completeSurfaceForegrounds(input);
3297
- return {
3298
- color: foregrounds.text,
3299
- [SURFACE_FOREGROUND_CSS_VARS.text]: foregrounds.text,
3300
- [SURFACE_FOREGROUND_CSS_VARS.heading]: foregrounds.heading,
3301
- [SURFACE_FOREGROUND_CSS_VARS.link]: foregrounds.link,
3302
- [SURFACE_FOREGROUND_CSS_VARS.supporting]: foregrounds.supporting
3303
- };
3304
- }
3305
- //#endregion
3306
- //#region ../theme-core/src/utils/colorStyles.ts
3307
- const COLOR_VAR_PREFIX = "--tb-";
3308
- function parseToken(source) {
3309
- const parts = parseColorTokenParts(source);
3310
- if (parts.kind === "raw") return {
3311
- token: source,
3312
- raw: parts.value
3313
- };
3314
- if (parts.kind === "invalid") return { token: source };
3315
- return {
3316
- token: parts.token,
3317
- opacityPercent: parts.opacityPercent === null ? void 0 : parts.opacityPercent
3318
- };
3319
- }
3320
- const SURFACE_TEXT_ROLE_BY_TOKEN = {
3321
- text: "text",
3322
- heading: "heading",
3323
- mutedText: "supporting"
3324
- };
3325
- function surfaceRoleForTextToken(token) {
3326
- return Object.prototype.hasOwnProperty.call(SURFACE_TEXT_ROLE_BY_TOKEN, token) ? SURFACE_TEXT_ROLE_BY_TOKEN[token] : null;
3327
- }
3328
- /**
3329
- * Converts a theme color token to a CSS rgb value.
3330
- * This is the primary function for applying theme colors to CSS properties.
3331
- *
3332
- * @param token - Theme color token (semantic, with opacity, or raw)
3333
- * @returns CSS color value (rgb with optional alpha, or raw CSS value)
3334
- *
3335
- * @example
3336
- * rgbColorValue('primary') // => 'rgb(var(--tb-primary))'
3337
- * rgbColorValue('surface/95') // => 'rgb(var(--tb-surface) / 0.95)'
3338
- * rgbColorValue('raw:transparent') // => 'transparent'
3339
- */
3340
- function rgbColorValue(token) {
3341
- const { token: baseToken, opacityPercent, raw } = parseToken(token);
3342
- if (raw) return raw;
3343
- const cssVar = `${COLOR_VAR_PREFIX}${baseToken}`;
3344
- if (opacityPercent === void 0) return `rgb(var(${cssVar}))`;
3345
- return `rgb(var(${cssVar}) / ${opacityPercent / 100})`;
3346
- }
3347
- /**
3348
- * Creates a backgroundColor style object from a theme token.
3349
- *
3350
- * @param token - Theme color token
3351
- * @returns CSSProperties with backgroundColor
3352
- */
3353
- function backgroundColorStyle(token) {
3354
- return { backgroundColor: rgbColorValue(token) };
3355
- }
3356
- /**
3357
- * Creates a text color style object from a theme token.
3358
- *
3359
- * @param token - Theme color token
3360
- * @returns CSSProperties with color
3361
- */
3362
- function textColorStyle(token) {
3363
- const parsed = parseToken(token);
3364
- const surfaceRole = parsed.raw ? null : surfaceRoleForTextToken(parsed.token);
3365
- if (surfaceRole) return { color: parsed.opacityPercent === void 0 ? surfaceForegroundValue(surfaceRole) : surfaceForegroundValueWithOpacity(surfaceRole, parsed.opacityPercent) };
3366
- return { color: rgbColorValue(token) };
3367
- }
3368
- /**
3369
- * Creates a border color style object from a theme token.
3370
- *
3371
- * @param token - Theme color token
3372
- * @returns CSSProperties with borderColor
3373
- */
3374
- function borderColorStyle(token) {
3375
- return { borderColor: rgbColorValue(token) };
3376
- }
3377
- /**
3378
- * Merges multiple CSSProperties objects into a single object.
3379
- * Later styles override earlier ones. Undefined values are filtered out.
3380
- * Returns undefined if the merged result is empty.
3381
- *
3382
- * @param styles - Variable number of CSSProperties objects (can be undefined)
3383
- * @returns Merged CSSProperties object, or undefined if empty
3384
- *
3385
- * @example
3386
- * mergeStyles(
3387
- * backgroundColorStyle('surface'),
3388
- * textColorStyle('text'),
3389
- * borderColorStyle('border')
3390
- * )
3391
- * // => { backgroundColor: '...', color: '...', borderColor: '...' }
3392
- */
3393
- function mergeStyles(...styles) {
3394
- const merged = {};
3395
- for (const style of styles) {
3396
- if (!style) continue;
3397
- Object.assign(merged, style);
3398
- }
3399
- return Object.keys(merged).length ? merged : void 0;
3400
- }
3401
- //#endregion
3402
3257
  //#region ../theme-core/src/lib/media.ts
3403
3258
  const hotspotSchema$1 = z.object({
3404
3259
  x: z.number().min(0).max(1),
@@ -3456,111 +3311,6 @@ const mediaSchema$1 = z.object({
3456
3311
  transform: transformSchema$1.optional()
3457
3312
  });
3458
3313
  //#endregion
3459
- //#region ../theme-core/src/buttons/effectClassification.ts
3460
- /**
3461
- * Exhaustive live policy for every registered effect id.
3462
- *
3463
- * The resolver consumes the transition payload directly, so adding an effect
3464
- * cannot update classification without also defining its runtime behavior.
3465
- */
3466
- const BUTTON_EFFECT_POLICIES = {
3467
- "darken-background": {
3468
- classification: "colour-transition",
3469
- transition: {
3470
- kind: "adjust-shade",
3471
- direction: "darker"
3472
- }
3473
- },
3474
- "lighten-background": {
3475
- classification: "colour-transition",
3476
- transition: {
3477
- kind: "adjust-shade",
3478
- direction: "lighter"
3479
- }
3480
- },
3481
- "background-on-hover": {
3482
- classification: "colour-transition",
3483
- transition: { kind: "replace-background" }
3484
- },
3485
- "background-on-hover-alpha": {
3486
- classification: "unsupported-colour",
3487
- reason: "alpha_requires_surface"
3488
- },
3489
- "fade-background": {
3490
- classification: "unsupported-colour",
3491
- reason: "changes_element_opacity"
3492
- },
3493
- "opacity-reduce": {
3494
- classification: "unsupported-colour",
3495
- reason: "changes_element_opacity"
3496
- },
3497
- "gradient-text": {
3498
- classification: "unsupported-colour",
3499
- reason: "changes_foreground"
3500
- },
3501
- "text-color-change": {
3502
- classification: "unsupported-colour",
3503
- reason: "changes_foreground"
3504
- },
3505
- "border-color-change": {
3506
- classification: "unsupported-colour",
3507
- reason: "changes_border"
3508
- },
3509
- "aurora-glow": {
3510
- classification: "unsupported-background-overlay",
3511
- reason: "unresolved_background_overlay"
3512
- },
3513
- "cosmic-stardust": {
3514
- classification: "unsupported-background-overlay",
3515
- reason: "unresolved_background_overlay"
3516
- },
3517
- "gradient-border-fill": {
3518
- classification: "unsupported-background-overlay",
3519
- reason: "unresolved_background_overlay"
3520
- },
3521
- "animated-gradient-border-fill": {
3522
- classification: "unsupported-background-overlay",
3523
- reason: "unresolved_background_overlay"
3524
- },
3525
- "nav-underline": {
3526
- classification: "not-button",
3527
- reason: "not_button_effect"
3528
- },
3529
- "nav-frosted-base": {
3530
- classification: "not-button",
3531
- reason: "not_button_effect"
3532
- },
3533
- "nav-frosted-hover": {
3534
- classification: "not-button",
3535
- reason: "not_button_effect"
3536
- },
3537
- "nav-frosted-active": {
3538
- classification: "not-button",
3539
- reason: "not_button_effect"
3540
- },
3541
- "animated-gradient": { classification: "non-colour" },
3542
- "border-glow": { classification: "non-colour" },
3543
- "drop-shadow": { classification: "non-colour" },
3544
- "inner-shadow": { classification: "non-colour" },
3545
- "neumorphic-shadow": { classification: "non-colour" },
3546
- "outer-glow": { classification: "non-colour" },
3547
- "retro-3d-shadow": { classification: "non-colour" },
3548
- "scale-up": { classification: "non-colour" },
3549
- "scale-down": { classification: "non-colour" },
3550
- lift: { classification: "non-colour" },
3551
- "press-down": { classification: "non-colour" },
3552
- pop: { classification: "non-colour" },
3553
- "border-bottom-grow": { classification: "non-colour" },
3554
- "sketchy-border": { classification: "non-colour" },
3555
- "pulse-animation": { classification: "non-colour" }
3556
- };
3557
- function getButtonEffectPolicy(effectId) {
3558
- return Object.prototype.hasOwnProperty.call(BUTTON_EFFECT_POLICIES, effectId) ? BUTTON_EFFECT_POLICIES[effectId] : null;
3559
- }
3560
- function classifyButtonEffectId(effectId) {
3561
- return getButtonEffectPolicy(effectId)?.classification ?? "unknown";
3562
- }
3563
- //#endregion
3564
3314
  //#region ../theme-core/src/buttons/types.ts
3565
3315
  /**
3566
3316
  * Standard semantic variant roles a theme exposes.
@@ -3577,6 +3327,13 @@ const VARIANT_ROLES = [
3577
3327
  "tertiary",
3578
3328
  "accent"
3579
3329
  ];
3330
+ /**
3331
+ * Canonical persisted/CSS-safe button variant identifier.
3332
+ *
3333
+ * IDs become class selectors, so keep the contract deliberately narrower than
3334
+ * an arbitrary string and shared with every authoring/runtime boundary.
3335
+ */
3336
+ const buttonVariantIdSchema = z$1.string().min(1).max(50).regex(/^[a-z0-9-]+$/, "Button variant IDs may contain lowercase letters, numbers, and hyphens only");
3580
3337
  function parseOpaqueButtonColourToken(value) {
3581
3338
  const token = parseThemeColorToken(value);
3582
3339
  if (token === null) return null;
@@ -3591,6 +3348,109 @@ const opaqueButtonColourTokenSchema = themeColorTokenSchema.refine((value) => pa
3591
3348
  if (token === null) throw new Error("Invariant: opaque button token passed its schema");
3592
3349
  return token;
3593
3350
  });
3351
+ const buttonShadeAmountSchema = z$1.number().finite().min(0).max(900).multipleOf(100);
3352
+ const buttonShadowIntensitySchema = z$1.enum([
3353
+ "subtle",
3354
+ "medium",
3355
+ "strong"
3356
+ ]);
3357
+ /**
3358
+ * The complete persisted button-effect contract.
3359
+ *
3360
+ * Navigation has its own generic interactive-effect model. Button variants use
3361
+ * this closed union so unsupported effect IDs, unknown option keys, and unsafe
3362
+ * CSS values cannot become representable after the schema boundary.
3363
+ */
3364
+ const buttonEffectApplicationSchema = z$1.discriminatedUnion("effectId", [
3365
+ z$1.strictObject({
3366
+ effectId: z$1.literal("darken-background"),
3367
+ options: z$1.strictObject({ amount: buttonShadeAmountSchema.optional() }).optional()
3368
+ }),
3369
+ z$1.strictObject({
3370
+ effectId: z$1.literal("lighten-background"),
3371
+ options: z$1.strictObject({ amount: buttonShadeAmountSchema.optional() }).optional()
3372
+ }),
3373
+ z$1.strictObject({
3374
+ effectId: z$1.literal("background-on-hover"),
3375
+ options: z$1.strictObject({ colorToken: opaqueButtonColourTokenSchema.optional() }).optional()
3376
+ }),
3377
+ z$1.strictObject({
3378
+ effectId: z$1.literal("animated-gradient"),
3379
+ options: z$1.strictObject({ direction: z$1.enum(["horizontal", "vertical"]).optional() }).optional()
3380
+ }),
3381
+ z$1.strictObject({
3382
+ effectId: z$1.literal("drop-shadow"),
3383
+ options: z$1.strictObject({ intensity: buttonShadowIntensitySchema.optional() }).optional()
3384
+ }),
3385
+ z$1.strictObject({
3386
+ effectId: z$1.literal("inner-shadow"),
3387
+ options: z$1.strictObject({}).optional()
3388
+ }),
3389
+ z$1.strictObject({
3390
+ effectId: z$1.literal("neumorphic-shadow"),
3391
+ options: z$1.strictObject({
3392
+ mode: z$1.enum(["raised", "pressed"]).optional(),
3393
+ intensity: buttonShadowIntensitySchema.optional()
3394
+ }).optional()
3395
+ }),
3396
+ z$1.strictObject({
3397
+ effectId: z$1.literal("retro-3d-shadow"),
3398
+ options: z$1.strictObject({}).optional()
3399
+ }),
3400
+ z$1.strictObject({
3401
+ effectId: z$1.literal("scale-up"),
3402
+ options: z$1.strictObject({ scale: z$1.enum([
3403
+ "1.02",
3404
+ "1.03",
3405
+ "1.05",
3406
+ "1.10"
3407
+ ]).optional() }).optional()
3408
+ }),
3409
+ z$1.strictObject({
3410
+ effectId: z$1.literal("scale-down"),
3411
+ options: z$1.strictObject({ scale: z$1.enum([
3412
+ "0.90",
3413
+ "0.95",
3414
+ "0.97",
3415
+ "0.98"
3416
+ ]).optional() }).optional()
3417
+ }),
3418
+ z$1.strictObject({
3419
+ effectId: z$1.literal("lift"),
3420
+ options: z$1.strictObject({ amount: z$1.enum([
3421
+ "0.25",
3422
+ "0.5",
3423
+ "1"
3424
+ ]).optional() }).optional()
3425
+ }),
3426
+ z$1.strictObject({
3427
+ effectId: z$1.literal("press-down"),
3428
+ options: z$1.strictObject({}).optional()
3429
+ }),
3430
+ z$1.strictObject({
3431
+ effectId: z$1.literal("pop"),
3432
+ options: z$1.strictObject({ intensity: z$1.enum([
3433
+ "subtle",
3434
+ "medium",
3435
+ "dramatic"
3436
+ ]).optional() }).optional()
3437
+ }),
3438
+ z$1.strictObject({
3439
+ effectId: z$1.literal("border-bottom-grow"),
3440
+ options: z$1.strictObject({
3441
+ height: z$1.union([z$1.literal(1), z$1.literal(2)]).optional(),
3442
+ origin: z$1.enum([
3443
+ "left",
3444
+ "center",
3445
+ "right"
3446
+ ]).optional()
3447
+ }).optional()
3448
+ }),
3449
+ z$1.strictObject({
3450
+ effectId: z$1.literal("sketchy-border"),
3451
+ options: z$1.strictObject({ intensity: buttonShadowIntensitySchema.optional() }).optional()
3452
+ })
3453
+ ]);
3594
3454
  const cornerStyleSchema = z$1.enum([
3595
3455
  "square",
3596
3456
  "rounded",
@@ -3625,13 +3485,7 @@ const hoverTransformSchema = z$1.enum([
3625
3485
  "scale",
3626
3486
  "press"
3627
3487
  ]);
3628
- const hoverColorSchema = z$1.enum([
3629
- "none",
3630
- "brighten",
3631
- "darken",
3632
- "saturate",
3633
- "token"
3634
- ]);
3488
+ z$1.enum(["none", "token"]);
3635
3489
  const buttonPaddingPresetSchema = z$1.enum([
3636
3490
  "compact",
3637
3491
  "default",
@@ -3692,7 +3546,7 @@ const buttonSizesSchema = z$1.object({
3692
3546
  lg,
3693
3547
  xl: xl ?? lg
3694
3548
  }));
3695
- const canonicalButtonGlobalSettingsSchema = z$1.object({
3549
+ const buttonGlobalSettingsBaseSchema = z$1.strictObject({
3696
3550
  cornerStyle: cornerStyleSchema,
3697
3551
  cornerRadius: z$1.number().min(0).max(24).optional(),
3698
3552
  /**
@@ -3705,30 +3559,23 @@ const canonicalButtonGlobalSettingsSchema = z$1.object({
3705
3559
  shadow: shadowSizeSchema.optional(),
3706
3560
  textTransform: textTransformSchema,
3707
3561
  fontWeight: fontWeightSchema,
3708
- /**
3709
- * @deprecated Set per-variant via `variant.border.widthClass` instead.
3710
- * Schema field is preserved so existing presets parse; the value is unread
3711
- * by the current generator and will be removed once the legacy
3712
- * `primitives/content/components/Button.tsx` slot exports are deleted.
3713
- */
3714
- borderWidth: z$1.union([
3715
- z$1.literal(1),
3716
- z$1.literal(2),
3717
- z$1.literal(3)
3718
- ]),
3719
3562
  typography: buttonTypographySchema.optional(),
3720
3563
  fontSize: z$1.string().optional(),
3721
3564
  letterSpacing: letterSpacingSchema.optional(),
3722
3565
  italic: z$1.boolean().optional(),
3723
3566
  paddingPreset: buttonPaddingPresetSchema.optional(),
3724
3567
  hoverTransform: hoverTransformSchema,
3725
- hoverColor: hoverColorSchema,
3726
- hoverColorToken: opaqueButtonColourTokenSchema.optional(),
3727
3568
  gradientStyle: gradientStyleSchema.optional(),
3728
3569
  gradientAngle: z$1.number().min(0).max(360).optional(),
3729
3570
  gradientSharpness: gradientSharpnessSchema.optional()
3730
3571
  });
3731
- const buttonGlobalSettingsSchema = z$1.preprocess(normalizeLegacyButtonGlobalInput, canonicalButtonGlobalSettingsSchema);
3572
+ const buttonGlobalSettingsSchema = z$1.discriminatedUnion("hoverColor", [buttonGlobalSettingsBaseSchema.extend({
3573
+ hoverColor: z$1.literal("none"),
3574
+ hoverColorToken: z$1.never().optional()
3575
+ }), buttonGlobalSettingsBaseSchema.extend({
3576
+ hoverColor: z$1.literal("token"),
3577
+ hoverColorToken: opaqueButtonColourTokenSchema
3578
+ })]);
3732
3579
  const gradientDirectionSchema$1 = z$1.enum([
3733
3580
  "to-r",
3734
3581
  "to-l",
@@ -3740,11 +3587,11 @@ const gradientDirectionSchema$1 = z$1.enum([
3740
3587
  "to-bl"
3741
3588
  ]);
3742
3589
  const buttonColourTreatmentSchema = z$1.discriminatedUnion("type", [
3743
- z$1.object({
3590
+ z$1.strictObject({
3744
3591
  type: z$1.literal("solid"),
3745
3592
  colorToken: opaqueButtonColourTokenSchema
3746
3593
  }),
3747
- z$1.object({
3594
+ z$1.strictObject({
3748
3595
  type: z$1.literal("gradient"),
3749
3596
  stops: z$1.array(opaqueButtonColourTokenSchema).min(2).transform((stops) => {
3750
3597
  const [first, second, ...rest] = stops;
@@ -3758,19 +3605,15 @@ const buttonColourTreatmentSchema = z$1.discriminatedUnion("type", [
3758
3605
  direction: gradientDirectionSchema$1,
3759
3606
  foregroundToken: opaqueButtonColourTokenSchema
3760
3607
  }),
3761
- z$1.object({
3608
+ z$1.strictObject({
3762
3609
  type: z$1.literal("surface"),
3763
3610
  role: z$1.literal("link")
3764
3611
  })
3765
3612
  ]);
3766
3613
  const buttonBackgroundSchema = buttonColourTreatmentSchema;
3767
- const effectApplicationSchema$1 = z$1.object({
3768
- effectId: z$1.string(),
3769
- options: z$1.record(z$1.string(), z$1.json()).optional()
3770
- });
3771
- const buttonBorderSchema = z$1.object({ widthClass: z$1.string() });
3772
- const buttonVariantAffordanceSchema = z$1.object({ iconId: z$1.string().min(1) });
3773
- const variantShadowSchema = z$1.object({
3614
+ const buttonBorderSchema = z$1.strictObject({ widthClass: z$1.string() });
3615
+ const buttonVariantAffordanceSchema = z$1.strictObject({ iconId: z$1.string().min(1) });
3616
+ const variantShadowSchema = z$1.strictObject({
3774
3617
  elevation: z$1.enum([
3775
3618
  "none",
3776
3619
  "low",
@@ -3783,13 +3626,13 @@ const variantShadowSchema = z$1.object({
3783
3626
  "hard"
3784
3627
  ]).nullable(),
3785
3628
  position: z$1.enum(["bottom", "bottom-right"]).default("bottom"),
3786
- colorToken: themeColorTokenSchema.optional()
3629
+ colorToken: opaqueButtonColourTokenSchema.optional()
3787
3630
  });
3788
- const variantEffectsSchema = z$1.object({
3789
- base: z$1.array(effectApplicationSchema$1).optional(),
3790
- hover: z$1.array(effectApplicationSchema$1).optional(),
3791
- active: z$1.array(effectApplicationSchema$1).optional(),
3792
- focus: z$1.array(effectApplicationSchema$1).optional()
3631
+ const variantEffectsSchema = z$1.strictObject({
3632
+ base: z$1.array(buttonEffectApplicationSchema).optional(),
3633
+ hover: z$1.array(buttonEffectApplicationSchema).optional(),
3634
+ active: z$1.array(buttonEffectApplicationSchema).optional(),
3635
+ focus: z$1.array(buttonEffectApplicationSchema).optional()
3793
3636
  });
3794
3637
  /**
3795
3638
  * Per-variant size overrides schema — every entry is optional.
@@ -3810,8 +3653,8 @@ const variantSizeOverridesSchema = z$1.object({
3810
3653
  * default (e.g. link-style variants declaring zero horizontal padding at
3811
3654
  * every size).
3812
3655
  */
3813
- const canonicalButtonVariantSchema = z$1.object({
3814
- id: z$1.string(),
3656
+ const buttonVariantSchema = z$1.strictObject({
3657
+ id: buttonVariantIdSchema,
3815
3658
  name: z$1.string().min(1).max(20),
3816
3659
  enabled: z$1.boolean(),
3817
3660
  priority: prioritySchema,
@@ -3825,154 +3668,73 @@ const canonicalButtonVariantSchema = z$1.object({
3825
3668
  sizes: variantSizeOverridesSchema.optional(),
3826
3669
  affordance: buttonVariantAffordanceSchema.optional()
3827
3670
  });
3828
- /**
3829
- * Temporary persisted-theme admission boundary for issue #1206.
3830
- *
3831
- * Production inventory on 2026-07-22 found 22 rows using the old independent
3832
- * `textColorToken`/border colour shape. New source and all downstream code use
3833
- * only the canonical relationship. Delete this preprocessor after the reviewed
3834
- * production rewrite reports zero legacy rows.
3835
- */
3836
- const buttonVariantSchema = z$1.preprocess(normalizeLegacyButtonVariantInput, canonicalButtonVariantSchema);
3837
- const buttonSystemSchema = z$1.object({
3671
+ const buttonSystemSchema = z$1.strictObject({
3838
3672
  global: buttonGlobalSettingsSchema,
3839
3673
  variants: z$1.array(buttonVariantSchema).min(1).max(6),
3840
3674
  sizes: buttonSizesSchema.optional()
3675
+ }).superRefine((system, ctx) => {
3676
+ const seen = /* @__PURE__ */ new Set();
3677
+ system.variants.forEach((variant, index) => {
3678
+ if (seen.has(variant.id)) ctx.addIssue({
3679
+ code: "custom",
3680
+ path: [
3681
+ "variants",
3682
+ index,
3683
+ "id"
3684
+ ],
3685
+ message: `Duplicate button variant ID: ${variant.id}`
3686
+ });
3687
+ seen.add(variant.id);
3688
+ });
3841
3689
  });
3842
- function normalizeLegacyButtonVariantInput(input) {
3843
- if (!isUnknownRecord(input)) return input;
3844
- const background = input.background;
3845
- if (!isUnknownRecord(background)) return input;
3846
- 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;
3847
- const { textColorToken, ...withoutLegacyText } = input;
3848
- const normalizedBorder = isUnknownRecord(input.border) && typeof input.border.widthClass === "string" ? { widthClass: input.border.widthClass } : input.border;
3849
- const normalizedAffordance = isUnknownRecord(input.affordance) && typeof input.affordance.iconId === "string" ? { iconId: input.affordance.iconId } : input.affordance;
3850
- const normalizedEffects = normalizeLegacyButtonEffects(input.effects, background.type);
3851
- const hoverBackgroundToken = stripLegacyTokenAlpha(input.hoverBackgroundToken);
3852
- if (background.type === "transparent") return {
3853
- ...withoutLegacyText,
3854
- background: {
3855
- type: "surface",
3856
- role: "link"
3857
- },
3858
- border: normalizedBorder,
3859
- affordance: normalizedAffordance,
3860
- effects: normalizedEffects,
3861
- hoverBackgroundToken
3862
- };
3863
- if (background.type === "gradient") {
3864
- const stops = Array.isArray(background.stops) ? background.stops.map(stripLegacyTokenAlpha) : background.stops;
3865
- return {
3866
- ...withoutLegacyText,
3867
- background: {
3868
- ...background,
3869
- stops,
3870
- foregroundToken: stripLegacyTokenAlpha(background.foregroundToken ?? textColorToken)
3871
- },
3872
- border: normalizedBorder,
3873
- affordance: normalizedAffordance,
3874
- effects: normalizedEffects,
3875
- hoverBackgroundToken
3876
- };
3877
- }
3878
- return {
3879
- ...withoutLegacyText,
3880
- background: background.type === "solid" ? {
3881
- ...background,
3882
- colorToken: stripLegacyTokenAlpha(background.colorToken)
3883
- } : background,
3884
- border: normalizedBorder,
3885
- affordance: normalizedAffordance,
3886
- effects: normalizedEffects,
3887
- hoverBackgroundToken
3888
- };
3690
+ //#endregion
3691
+ //#region ../theme-core/src/surfaces/foregroundContract.ts
3692
+ const SURFACE_FOREGROUND_CSS_VARS = {
3693
+ text: "--rb-surface-text-color",
3694
+ heading: "--rb-surface-heading-color",
3695
+ link: "--rb-surface-link-color",
3696
+ supporting: "--rb-surface-supporting-color"
3697
+ };
3698
+ const DEFAULT_SURFACE_TEXT_COLOR = "rgb(var(--tb-text, 17 24 39))";
3699
+ const DEFAULT_ROLE_FALLBACKS = {
3700
+ text: DEFAULT_SURFACE_TEXT_COLOR,
3701
+ heading: DEFAULT_SURFACE_TEXT_COLOR,
3702
+ link: "rgb(var(--tb-primary, var(--tb-text, 17 24 39)))",
3703
+ supporting: "rgb(var(--tb-mutedText, 100 116 139))"
3704
+ };
3705
+ function requireSurfaceColorValue(role, value) {
3706
+ const normalized = value.trim();
3707
+ if (normalized.length === 0) throw new RangeError(`Surface foreground ${role} must be a non-empty CSS color.`);
3708
+ return normalized;
3889
3709
  }
3890
- function normalizeLegacyButtonGlobalInput(input) {
3891
- if (!isUnknownRecord(input)) return input;
3892
- const hoverColorToken = stripLegacyTokenAlpha(input.hoverColorToken);
3893
- return hoverColorToken === input.hoverColorToken ? input : {
3894
- ...input,
3895
- hoverColorToken
3710
+ function completeSurfaceForegrounds(input) {
3711
+ const text = requireSurfaceColorValue("text", input.text);
3712
+ return {
3713
+ text,
3714
+ heading: input.heading === void 0 ? text : requireSurfaceColorValue("heading", input.heading),
3715
+ link: input.link === void 0 ? text : requireSurfaceColorValue("link", input.link),
3716
+ supporting: input.supporting === void 0 ? text : requireSurfaceColorValue("supporting", input.supporting)
3896
3717
  };
3897
3718
  }
3898
- function hasLegacyAlphaToken(input, background) {
3899
- const stops = isUnknownArray(background.stops) ? background.stops : [];
3900
- return [
3901
- input.hoverBackgroundToken,
3902
- background.colorToken,
3903
- background.foregroundToken,
3904
- ...stops
3905
- ].some((token) => stripLegacyTokenAlpha(token) !== token);
3906
- }
3907
- function stripLegacyTokenAlpha(value) {
3908
- if (typeof value !== "string") return value;
3909
- const slashIndex = value.indexOf("/");
3910
- return slashIndex < 0 ? value : value.slice(0, slashIndex);
3911
- }
3912
- function hasLegacyButtonEffects(input) {
3913
- if (!isUnknownRecord(input)) return false;
3914
- return [
3915
- "base",
3916
- "hover",
3917
- "active",
3918
- "focus"
3919
- ].some((state) => {
3920
- const effects = input[state];
3921
- return Array.isArray(effects) && effects.some((effect) => {
3922
- if (!isUnknownRecord(effect) || typeof effect.effectId !== "string") return true;
3923
- const classification = classifyButtonEffectId(effect.effectId);
3924
- if (classification !== "colour-transition" && classification !== "non-colour") return true;
3925
- return effect.effectId === "background-on-hover" && isUnknownRecord(effect.options) && stripLegacyTokenAlpha(effect.options.colorToken) !== effect.options.colorToken;
3926
- });
3927
- });
3928
- }
3929
- function normalizeLegacyButtonEffects(input, backgroundType) {
3930
- if (!isUnknownRecord(input)) return input;
3931
- const normalized = {};
3932
- for (const state of [
3933
- "base",
3934
- "hover",
3935
- "active",
3936
- "focus"
3937
- ]) {
3938
- const effects = input[state];
3939
- if (!Array.isArray(effects)) continue;
3940
- const safeEffects = effects.flatMap((effect) => {
3941
- if (!isUnknownRecord(effect) || typeof effect.effectId !== "string") return [];
3942
- const classification = classifyButtonEffectId(effect.effectId);
3943
- if (classification === "non-colour") return [effect];
3944
- if (classification !== "colour-transition") return [];
3945
- if (effect.effectId === "background-on-hover") {
3946
- const options = isUnknownRecord(effect.options) ? effect.options : null;
3947
- const colorToken = options === null ? null : parseOpaqueButtonColourToken(stripLegacyTokenAlpha(options.colorToken));
3948
- return colorToken === null ? [] : [{
3949
- ...effect,
3950
- options: {
3951
- ...options,
3952
- colorToken
3953
- }
3954
- }];
3955
- }
3956
- if (backgroundType !== "solid") return [];
3957
- const rawAmount = isUnknownRecord(effect.options) ? effect.options.amount : void 0;
3958
- const amount = typeof rawAmount === "number" && rawAmount > 0 ? Math.max(100, Math.round(rawAmount / 100) * 100) : 100;
3959
- return [{
3960
- ...effect,
3961
- options: {
3962
- ...isUnknownRecord(effect.options) ? effect.options : {},
3963
- amount
3964
- }
3965
- }];
3966
- });
3967
- if (safeEffects.length > 0) normalized[state] = safeEffects;
3968
- }
3969
- return Object.keys(normalized).length === 0 ? void 0 : normalized;
3719
+ function surfaceForegroundValue(role, outsideProviderFallback = DEFAULT_ROLE_FALLBACKS[role]) {
3720
+ const roleVariable = SURFACE_FOREGROUND_CSS_VARS[role];
3721
+ const fallback = requireSurfaceColorValue("fallback", outsideProviderFallback);
3722
+ if (role === "text") return `var(${roleVariable}, ${fallback})`;
3723
+ return `var(${roleVariable}, var(${SURFACE_FOREGROUND_CSS_VARS.text}, ${fallback}))`;
3970
3724
  }
3971
- function isUnknownRecord(value) {
3972
- return typeof value === "object" && value !== null && !Array.isArray(value);
3725
+ function surfaceForegroundValueWithOpacity(role, opacityPercent) {
3726
+ if (!Number.isFinite(opacityPercent) || opacityPercent < 0 || opacityPercent > 100) throw new RangeError("Surface foreground opacity must be between 0 and 100.");
3727
+ return `color-mix(in srgb, ${surfaceForegroundValue(role)} ${opacityPercent}%, transparent)`;
3973
3728
  }
3974
- function isUnknownArray(value) {
3975
- return Array.isArray(value);
3729
+ function surfaceForegroundStyle(input) {
3730
+ const foregrounds = completeSurfaceForegrounds(input);
3731
+ return {
3732
+ color: foregrounds.text,
3733
+ [SURFACE_FOREGROUND_CSS_VARS.text]: foregrounds.text,
3734
+ [SURFACE_FOREGROUND_CSS_VARS.heading]: foregrounds.heading,
3735
+ [SURFACE_FOREGROUND_CSS_VARS.link]: foregrounds.link,
3736
+ [SURFACE_FOREGROUND_CSS_VARS.supporting]: foregrounds.supporting
3737
+ };
3976
3738
  }
3977
3739
  buttonSizeNameSchema.options;
3978
3740
  //#endregion
@@ -4129,7 +3891,6 @@ const quietArrowRecipe = defineButtonStyleRecipe({
4129
3891
  cornerStyle: "rounded",
4130
3892
  textTransform: "uppercase",
4131
3893
  fontWeight: 500,
4132
- borderWidth: 1,
4133
3894
  typography: "body",
4134
3895
  fontSize: "text-sm",
4135
3896
  letterSpacing: "loose",
@@ -4193,7 +3954,7 @@ const quietArrowRecipe = defineButtonStyleRecipe({
4193
3954
  affordance: { iconId: "ArrowRight" },
4194
3955
  effects: { hover: [{
4195
3956
  effectId: "background-on-hover",
4196
- options: { colorToken: "surfaceAlt" }
3957
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surfaceAlt") }
4197
3958
  }] }
4198
3959
  }
4199
3960
  },
@@ -4304,7 +4065,6 @@ const softPillRecipe = defineStaticButtonStyleRecipe({
4304
4065
  shadow: "low",
4305
4066
  textTransform: "none",
4306
4067
  fontWeight: 500,
4307
- borderWidth: 2,
4308
4068
  hoverTransform: "lift",
4309
4069
  hoverColor: "none"
4310
4070
  },
@@ -4323,10 +4083,7 @@ const softPillRecipe = defineStaticButtonStyleRecipe({
4323
4083
  position: "bottom"
4324
4084
  },
4325
4085
  effects: {
4326
- hover: [{
4327
- effectId: "lift",
4328
- options: { translateY: "-1px" }
4329
- }],
4086
+ hover: [{ effectId: "lift" }],
4330
4087
  active: [{
4331
4088
  effectId: "scale-down",
4332
4089
  options: { scale: "0.98" }
@@ -4345,7 +4102,7 @@ const softPillRecipe = defineStaticButtonStyleRecipe({
4345
4102
  border: { widthClass: "border-2" },
4346
4103
  effects: { hover: [{
4347
4104
  effectId: "background-on-hover",
4348
- options: { colorToken: "surface" }
4105
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surface") }
4349
4106
  }] }
4350
4107
  }
4351
4108
  },
@@ -4360,7 +4117,7 @@ const softPillRecipe = defineStaticButtonStyleRecipe({
4360
4117
  border: { widthClass: "border" },
4361
4118
  effects: { hover: [{
4362
4119
  effectId: "background-on-hover",
4363
- options: { colorToken: "surface" }
4120
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surface") }
4364
4121
  }] }
4365
4122
  }
4366
4123
  },
@@ -4374,7 +4131,7 @@ const softPillRecipe = defineStaticButtonStyleRecipe({
4374
4131
  borderRadius: "rounded-full",
4375
4132
  effects: { hover: [{
4376
4133
  effectId: "background-on-hover",
4377
- options: { colorToken: "surface" }
4134
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surface") }
4378
4135
  }] }
4379
4136
  }
4380
4137
  },
@@ -4404,7 +4161,6 @@ const earthPillRecipe = defineStaticButtonStyleRecipe({
4404
4161
  shadow: "low",
4405
4162
  textTransform: "none",
4406
4163
  fontWeight: 500,
4407
- borderWidth: 1,
4408
4164
  hoverTransform: "lift",
4409
4165
  hoverColor: "none",
4410
4166
  typography: "body",
@@ -4440,12 +4196,9 @@ const earthPillRecipe = defineStaticButtonStyleRecipe({
4440
4196
  position: "bottom"
4441
4197
  },
4442
4198
  effects: {
4443
- hover: [{
4444
- effectId: "lift",
4445
- options: { translateY: "-1px" }
4446
- }, {
4199
+ hover: [{ effectId: "lift" }, {
4447
4200
  effectId: "background-on-hover",
4448
- options: { colorToken: "accent" }
4201
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("accent") }
4449
4202
  }],
4450
4203
  active: [{
4451
4204
  effectId: "scale-down",
@@ -4465,7 +4218,7 @@ const earthPillRecipe = defineStaticButtonStyleRecipe({
4465
4218
  border: { widthClass: "border" },
4466
4219
  effects: { hover: [{
4467
4220
  effectId: "background-on-hover",
4468
- options: { colorToken: "muted" }
4221
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("muted") }
4469
4222
  }] }
4470
4223
  }
4471
4224
  },
@@ -4480,7 +4233,7 @@ const earthPillRecipe = defineStaticButtonStyleRecipe({
4480
4233
  border: { widthClass: "border" },
4481
4234
  effects: { hover: [{
4482
4235
  effectId: "background-on-hover",
4483
- options: { colorToken: "surfaceAlt" }
4236
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surfaceAlt") }
4484
4237
  }] }
4485
4238
  }
4486
4239
  },
@@ -4540,7 +4293,6 @@ const confidentChipRecipe = defineStaticButtonStyleRecipe({
4540
4293
  shadow: "medium",
4541
4294
  textTransform: "none",
4542
4295
  fontWeight: 600,
4543
- borderWidth: 1,
4544
4296
  hoverTransform: "none",
4545
4297
  hoverColor: "none"
4546
4298
  },
@@ -4581,7 +4333,7 @@ const confidentChipRecipe = defineStaticButtonStyleRecipe({
4581
4333
  border: { widthClass: "border" },
4582
4334
  effects: { hover: [{
4583
4335
  effectId: "background-on-hover",
4584
- options: { colorToken: "background" }
4336
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("background") }
4585
4337
  }] }
4586
4338
  }
4587
4339
  },
@@ -4596,7 +4348,7 @@ const confidentChipRecipe = defineStaticButtonStyleRecipe({
4596
4348
  border: { widthClass: "border" },
4597
4349
  effects: { hover: [{
4598
4350
  effectId: "background-on-hover",
4599
- options: { colorToken: "surface" }
4351
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surface") }
4600
4352
  }] }
4601
4353
  }
4602
4354
  },
@@ -4610,7 +4362,7 @@ const confidentChipRecipe = defineStaticButtonStyleRecipe({
4610
4362
  borderRadius: "rounded-md",
4611
4363
  effects: { hover: [{
4612
4364
  effectId: "background-on-hover",
4613
- options: { colorToken: "surface" }
4365
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surface") }
4614
4366
  }] }
4615
4367
  }
4616
4368
  },
@@ -4645,7 +4397,6 @@ const editorialLinkRecipe = defineStaticButtonStyleRecipe({
4645
4397
  cornerStyle: "square",
4646
4398
  textTransform: "none",
4647
4399
  fontWeight: 500,
4648
- borderWidth: 1,
4649
4400
  hoverTransform: "none",
4650
4401
  hoverColor: "none"
4651
4402
  },
@@ -4663,7 +4414,6 @@ const editorialLinkRecipe = defineStaticButtonStyleRecipe({
4663
4414
  effectId: "border-bottom-grow",
4664
4415
  options: {
4665
4416
  height: 2,
4666
- colorToken: "text",
4667
4417
  origin: "left"
4668
4418
  }
4669
4419
  }] }
@@ -4682,7 +4432,6 @@ const editorialLinkRecipe = defineStaticButtonStyleRecipe({
4682
4432
  effectId: "border-bottom-grow",
4683
4433
  options: {
4684
4434
  height: 1,
4685
- colorToken: "mutedText",
4686
4435
  origin: "left"
4687
4436
  }
4688
4437
  }] }
@@ -4701,7 +4450,6 @@ const editorialLinkRecipe = defineStaticButtonStyleRecipe({
4701
4450
  effectId: "border-bottom-grow",
4702
4451
  options: {
4703
4452
  height: 1,
4704
- colorToken: "accent",
4705
4453
  origin: "left"
4706
4454
  }
4707
4455
  }] }
@@ -4725,7 +4473,6 @@ const editorialLinkRecipe = defineStaticButtonStyleRecipe({
4725
4473
  effectId: "border-bottom-grow",
4726
4474
  options: {
4727
4475
  height: 2,
4728
- colorToken: "accent",
4729
4476
  origin: "left"
4730
4477
  }
4731
4478
  }] } }
@@ -4747,7 +4494,6 @@ const pebbleRecipe = defineStaticButtonStyleRecipe({
4747
4494
  cornerStyle: "pill",
4748
4495
  textTransform: "none",
4749
4496
  fontWeight: 500,
4750
- borderWidth: 2,
4751
4497
  hoverTransform: "none",
4752
4498
  hoverColor: "none"
4753
4499
  },
@@ -4792,7 +4538,7 @@ const pebbleRecipe = defineStaticButtonStyleRecipe({
4792
4538
  border: { widthClass: "border-2" },
4793
4539
  effects: { hover: [{
4794
4540
  effectId: "background-on-hover",
4795
- options: { colorToken: "accent" }
4541
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("accent") }
4796
4542
  }] }
4797
4543
  }
4798
4544
  },
@@ -4807,7 +4553,7 @@ const pebbleRecipe = defineStaticButtonStyleRecipe({
4807
4553
  border: { widthClass: "border" },
4808
4554
  effects: { hover: [{
4809
4555
  effectId: "background-on-hover",
4810
- options: { colorToken: "surface" }
4556
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surface") }
4811
4557
  }] }
4812
4558
  }
4813
4559
  },
@@ -4862,7 +4608,6 @@ const brushedWashRecipe = defineStaticButtonStyleRecipe({
4862
4608
  shadow: "low",
4863
4609
  textTransform: "none",
4864
4610
  fontWeight: 500,
4865
- borderWidth: 1,
4866
4611
  hoverTransform: "none",
4867
4612
  hoverColor: "none"
4868
4613
  },
@@ -4927,7 +4672,7 @@ const brushedWashRecipe = defineStaticButtonStyleRecipe({
4927
4672
  border: { widthClass: "border" },
4928
4673
  effects: { hover: [{
4929
4674
  effectId: "background-on-hover",
4930
- options: { colorToken: "surface" }
4675
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surface") }
4931
4676
  }] }
4932
4677
  }
4933
4678
  },
@@ -4941,7 +4686,7 @@ const brushedWashRecipe = defineStaticButtonStyleRecipe({
4941
4686
  borderRadius: "rounded-lg",
4942
4687
  effects: { hover: [{
4943
4688
  effectId: "background-on-hover",
4944
- options: { colorToken: "surface" }
4689
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surface") }
4945
4690
  }] }
4946
4691
  }
4947
4692
  },
@@ -4970,7 +4715,6 @@ const inkStampRecipe = defineStaticButtonStyleRecipe({
4970
4715
  cornerStyle: "rounded",
4971
4716
  textTransform: "uppercase",
4972
4717
  fontWeight: 600,
4973
- borderWidth: 1,
4974
4718
  hoverTransform: "none",
4975
4719
  hoverColor: "none",
4976
4720
  letterSpacing: "loose"
@@ -5028,7 +4772,7 @@ const inkStampRecipe = defineStaticButtonStyleRecipe({
5028
4772
  border: { widthClass: "border-2" },
5029
4773
  effects: { hover: [{
5030
4774
  effectId: "background-on-hover",
5031
- options: { colorToken: "surface" }
4775
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surface") }
5032
4776
  }] }
5033
4777
  }
5034
4778
  },
@@ -5043,7 +4787,7 @@ const inkStampRecipe = defineStaticButtonStyleRecipe({
5043
4787
  border: { widthClass: "border-2" },
5044
4788
  effects: { hover: [{
5045
4789
  effectId: "background-on-hover",
5046
- options: { colorToken: "surface" }
4790
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surface") }
5047
4791
  }] }
5048
4792
  }
5049
4793
  },
@@ -5077,7 +4821,6 @@ const inkStampRecipe = defineStaticButtonStyleRecipe({
5077
4821
  effectId: "border-bottom-grow",
5078
4822
  options: {
5079
4823
  height: 1,
5080
- colorToken: "accent",
5081
4824
  origin: "left"
5082
4825
  }
5083
4826
  }] }
@@ -5108,7 +4851,6 @@ const flatInkRecipe = defineStaticButtonStyleRecipe({
5108
4851
  cornerStyle: "rounded",
5109
4852
  textTransform: "none",
5110
4853
  fontWeight: 600,
5111
- borderWidth: 1,
5112
4854
  typography: "body",
5113
4855
  letterSpacing: "tight",
5114
4856
  paddingPreset: "default",
@@ -5140,12 +4882,9 @@ const flatInkRecipe = defineStaticButtonStyleRecipe({
5140
4882
  },
5141
4883
  borderRadius: "rounded-lg",
5142
4884
  affordance: { iconId: "ArrowRight" },
5143
- effects: { hover: [{
5144
- effectId: "lift",
5145
- options: { translateY: "-2px" }
5146
- }, {
4885
+ effects: { hover: [{ effectId: "lift" }, {
5147
4886
  effectId: "background-on-hover",
5148
- options: { colorToken: "secondary" }
4887
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("secondary") }
5149
4888
  }] }
5150
4889
  }
5151
4890
  },
@@ -5158,12 +4897,9 @@ const flatInkRecipe = defineStaticButtonStyleRecipe({
5158
4897
  },
5159
4898
  borderRadius: "rounded-lg",
5160
4899
  border: { widthClass: "border" },
5161
- effects: { hover: [{
5162
- effectId: "lift",
5163
- options: { translateY: "-2px" }
5164
- }, {
4900
+ effects: { hover: [{ effectId: "lift" }, {
5165
4901
  effectId: "background-on-hover",
5166
- options: { colorToken: "surfaceAlt" }
4902
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surfaceAlt") }
5167
4903
  }] }
5168
4904
  }
5169
4905
  },
@@ -5176,12 +4912,9 @@ const flatInkRecipe = defineStaticButtonStyleRecipe({
5176
4912
  },
5177
4913
  borderRadius: "rounded-lg",
5178
4914
  border: { widthClass: "border" },
5179
- effects: { hover: [{
5180
- effectId: "lift",
5181
- options: { translateY: "-2px" }
5182
- }, {
4915
+ effects: { hover: [{ effectId: "lift" }, {
5183
4916
  effectId: "background-on-hover",
5184
- options: { colorToken: "surfaceAlt" }
4917
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surfaceAlt") }
5185
4918
  }] }
5186
4919
  }
5187
4920
  },
@@ -5193,10 +4926,7 @@ const flatInkRecipe = defineStaticButtonStyleRecipe({
5193
4926
  role: "link"
5194
4927
  },
5195
4928
  borderRadius: "rounded-lg",
5196
- effects: { hover: [{
5197
- effectId: "lift",
5198
- options: { translateY: "-2px" }
5199
- }] }
4929
+ effects: { hover: [{ effectId: "lift" }] }
5200
4930
  }
5201
4931
  },
5202
4932
  accent: {
@@ -5208,10 +4938,7 @@ const flatInkRecipe = defineStaticButtonStyleRecipe({
5208
4938
  },
5209
4939
  borderRadius: "rounded-lg",
5210
4940
  affordance: { iconId: "ArrowRight" },
5211
- effects: { hover: [{
5212
- effectId: "lift",
5213
- options: { translateY: "-2px" }
5214
- }] }
4941
+ effects: { hover: [{ effectId: "lift" }] }
5215
4942
  }
5216
4943
  }
5217
4944
  }
@@ -5232,9 +4959,8 @@ const showtimePillRecipe = defineStaticButtonStyleRecipe({
5232
4959
  shadow: "low",
5233
4960
  textTransform: "uppercase",
5234
4961
  fontWeight: 700,
5235
- borderWidth: 2,
5236
4962
  hoverTransform: "lift",
5237
- hoverColor: "darken",
4963
+ hoverColor: "none",
5238
4964
  typography: "body",
5239
4965
  paddingPreset: "spacious",
5240
4966
  italic: false
@@ -5292,7 +5018,7 @@ const showtimePillRecipe = defineStaticButtonStyleRecipe({
5292
5018
  border: { widthClass: "border-2" },
5293
5019
  effects: { hover: [{
5294
5020
  effectId: "background-on-hover",
5295
- options: { colorToken: "background" }
5021
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("background") }
5296
5022
  }] }
5297
5023
  }
5298
5024
  },
@@ -5306,7 +5032,7 @@ const showtimePillRecipe = defineStaticButtonStyleRecipe({
5306
5032
  borderRadius: "rounded-full",
5307
5033
  effects: { hover: [{
5308
5034
  effectId: "background-on-hover",
5309
- options: { colorToken: "surface" }
5035
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surface") }
5310
5036
  }] }
5311
5037
  }
5312
5038
  },
@@ -5341,7 +5067,6 @@ const joyStampRecipe = defineStaticButtonStyleRecipe({
5341
5067
  typography: "heading",
5342
5068
  fontWeight: 700,
5343
5069
  fontSize: "text-lg",
5344
- borderWidth: 2,
5345
5070
  hoverTransform: "none",
5346
5071
  hoverColor: "none"
5347
5072
  },
@@ -5376,7 +5101,7 @@ const joyStampRecipe = defineStaticButtonStyleRecipe({
5376
5101
  elevation: "high",
5377
5102
  softness: "hard",
5378
5103
  position: "bottom-right",
5379
- colorToken: "text"
5104
+ colorToken: unsafeAsOpaqueButtonColourToken("text")
5380
5105
  },
5381
5106
  effects: { hover: [{ effectId: "press-down" }] }
5382
5107
  }
@@ -5394,7 +5119,7 @@ const joyStampRecipe = defineStaticButtonStyleRecipe({
5394
5119
  elevation: "high",
5395
5120
  softness: "hard",
5396
5121
  position: "bottom-right",
5397
- colorToken: "secondary"
5122
+ colorToken: unsafeAsOpaqueButtonColourToken("secondary")
5398
5123
  },
5399
5124
  effects: { hover: [{ effectId: "press-down" }] }
5400
5125
  }
@@ -5439,7 +5164,6 @@ const ornateRitualRecipe = defineStaticButtonStyleRecipe({
5439
5164
  cornerStyle: "rounded",
5440
5165
  textTransform: "uppercase",
5441
5166
  fontWeight: 600,
5442
- borderWidth: 1,
5443
5167
  hoverTransform: "none",
5444
5168
  hoverColor: "none",
5445
5169
  letterSpacing: "loose"
@@ -5475,7 +5199,7 @@ const ornateRitualRecipe = defineStaticButtonStyleRecipe({
5475
5199
  effects: {
5476
5200
  hover: [{
5477
5201
  effectId: "background-on-hover",
5478
- options: { colorToken: "primary-100" }
5202
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("primary-100") }
5479
5203
  }],
5480
5204
  active: [{
5481
5205
  effectId: "scale-down",
@@ -5495,7 +5219,7 @@ const ornateRitualRecipe = defineStaticButtonStyleRecipe({
5495
5219
  border: { widthClass: "border" },
5496
5220
  effects: { hover: [{
5497
5221
  effectId: "background-on-hover",
5498
- options: { colorToken: "surface" }
5222
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surface") }
5499
5223
  }] }
5500
5224
  }
5501
5225
  },
@@ -5510,7 +5234,7 @@ const ornateRitualRecipe = defineStaticButtonStyleRecipe({
5510
5234
  border: { widthClass: "border" },
5511
5235
  effects: { hover: [{
5512
5236
  effectId: "background-on-hover",
5513
- options: { colorToken: "muted" }
5237
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("muted") }
5514
5238
  }] }
5515
5239
  }
5516
5240
  },
@@ -5544,7 +5268,6 @@ const ornateRitualRecipe = defineStaticButtonStyleRecipe({
5544
5268
  effectId: "border-bottom-grow",
5545
5269
  options: {
5546
5270
  height: 1,
5547
- colorToken: "accent",
5548
5271
  origin: "left"
5549
5272
  }
5550
5273
  }] }
@@ -6653,6 +6376,102 @@ new Set(themeV2NormalEditorRawStyleFieldNames);
6653
6376
  const pageDesignEditorBackgroundOverrideOwner = "page-design-editor";
6654
6377
  const siteChromeBackgroundOverrideOwner = "site-chrome-editor";
6655
6378
  //#endregion
6379
+ //#region ../theme-core/src/utils/colorStyles.ts
6380
+ const COLOR_VAR_PREFIX = "--tb-";
6381
+ function parseToken(source) {
6382
+ const parts = parseColorTokenParts(source);
6383
+ if (parts.kind === "raw") return {
6384
+ token: source,
6385
+ raw: parts.value
6386
+ };
6387
+ if (parts.kind === "invalid") return { token: source };
6388
+ return {
6389
+ token: parts.token,
6390
+ opacityPercent: parts.opacityPercent === null ? void 0 : parts.opacityPercent
6391
+ };
6392
+ }
6393
+ const SURFACE_TEXT_ROLE_BY_TOKEN = {
6394
+ text: "text",
6395
+ heading: "heading",
6396
+ mutedText: "supporting"
6397
+ };
6398
+ function surfaceRoleForTextToken(token) {
6399
+ return Object.prototype.hasOwnProperty.call(SURFACE_TEXT_ROLE_BY_TOKEN, token) ? SURFACE_TEXT_ROLE_BY_TOKEN[token] : null;
6400
+ }
6401
+ /**
6402
+ * Converts a theme color token to a CSS rgb value.
6403
+ * This is the primary function for applying theme colors to CSS properties.
6404
+ *
6405
+ * @param token - Theme color token (semantic, with opacity, or raw)
6406
+ * @returns CSS color value (rgb with optional alpha, or raw CSS value)
6407
+ *
6408
+ * @example
6409
+ * rgbColorValue('primary') // => 'rgb(var(--tb-primary))'
6410
+ * rgbColorValue('surface/95') // => 'rgb(var(--tb-surface) / 0.95)'
6411
+ * rgbColorValue('raw:transparent') // => 'transparent'
6412
+ */
6413
+ function rgbColorValue(token) {
6414
+ const { token: baseToken, opacityPercent, raw } = parseToken(token);
6415
+ if (raw) return raw;
6416
+ const cssVar = `${COLOR_VAR_PREFIX}${baseToken}`;
6417
+ if (opacityPercent === void 0) return `rgb(var(${cssVar}))`;
6418
+ return `rgb(var(${cssVar}) / ${opacityPercent / 100})`;
6419
+ }
6420
+ /**
6421
+ * Creates a backgroundColor style object from a theme token.
6422
+ *
6423
+ * @param token - Theme color token
6424
+ * @returns CSSProperties with backgroundColor
6425
+ */
6426
+ function backgroundColorStyle(token) {
6427
+ return { backgroundColor: rgbColorValue(token) };
6428
+ }
6429
+ /**
6430
+ * Creates a text color style object from a theme token.
6431
+ *
6432
+ * @param token - Theme color token
6433
+ * @returns CSSProperties with color
6434
+ */
6435
+ function textColorStyle(token) {
6436
+ const parsed = parseToken(token);
6437
+ const surfaceRole = parsed.raw ? null : surfaceRoleForTextToken(parsed.token);
6438
+ if (surfaceRole) return { color: parsed.opacityPercent === void 0 ? surfaceForegroundValue(surfaceRole) : surfaceForegroundValueWithOpacity(surfaceRole, parsed.opacityPercent) };
6439
+ return { color: rgbColorValue(token) };
6440
+ }
6441
+ /**
6442
+ * Creates a border color style object from a theme token.
6443
+ *
6444
+ * @param token - Theme color token
6445
+ * @returns CSSProperties with borderColor
6446
+ */
6447
+ function borderColorStyle(token) {
6448
+ return { borderColor: rgbColorValue(token) };
6449
+ }
6450
+ /**
6451
+ * Merges multiple CSSProperties objects into a single object.
6452
+ * Later styles override earlier ones. Undefined values are filtered out.
6453
+ * Returns undefined if the merged result is empty.
6454
+ *
6455
+ * @param styles - Variable number of CSSProperties objects (can be undefined)
6456
+ * @returns Merged CSSProperties object, or undefined if empty
6457
+ *
6458
+ * @example
6459
+ * mergeStyles(
6460
+ * backgroundColorStyle('surface'),
6461
+ * textColorStyle('text'),
6462
+ * borderColorStyle('border')
6463
+ * )
6464
+ * // => { backgroundColor: '...', color: '...', borderColor: '...' }
6465
+ */
6466
+ function mergeStyles(...styles) {
6467
+ const merged = {};
6468
+ for (const style of styles) {
6469
+ if (!style) continue;
6470
+ Object.assign(merged, style);
6471
+ }
6472
+ return Object.keys(merged).length ? merged : void 0;
6473
+ }
6474
+ //#endregion
6656
6475
  //#region ../theme-core/src/utils/tokenOrColor.ts
6657
6476
  /**
6658
6477
  * Runtime color-reference fields intentionally accept any string, including
@@ -13533,6 +13352,7 @@ const DISPLAY_MEDIA_KINDS = [
13533
13352
  "video",
13534
13353
  "audio"
13535
13354
  ];
13355
+ const DEFAULT_MEDIA_FIELD_KINDS = ["image"];
13536
13356
  const PUBLIC_FILE_FIELD_KINDS = [
13537
13357
  "document",
13538
13358
  "spreadsheet",
@@ -13733,18 +13553,28 @@ const inlineTextFieldSchema = baseFieldSchema.extend({
13733
13553
  maxLength: z$1.number().int().positive().optional(),
13734
13554
  plainTextField: z$1.string().min(1).optional()
13735
13555
  });
13556
+ function hasMediaDefaultIdentifier(value) {
13557
+ return value !== null && typeof value === "object" && !Array.isArray(value) && typeof value.identifier === "string" && value.identifier.trim().length > 0;
13558
+ }
13559
+ function validateMediaFieldDefault(field, ctx) {
13560
+ if (field.defaultValue !== void 0 && field.defaultValue !== null && !hasMediaDefaultIdentifier(field.defaultValue)) ctx.addIssue({
13561
+ code: z$1.ZodIssueCode.custom,
13562
+ path: ["defaultValue"],
13563
+ message: `${field.type} defaultValue must be null or an object with a non-empty identifier`
13564
+ });
13565
+ }
13736
13566
  const mediaFieldSchema = baseFieldSchema.extend({
13737
13567
  type: z$1.literal("media"),
13738
- mediaKinds: z$1.array(z$1.enum(MEDIA_KINDS)).default(["image"]).transform((kinds) => {
13568
+ mediaKinds: z$1.array(z$1.enum(MEDIA_KINDS)).default([...DEFAULT_MEDIA_FIELD_KINDS]).transform((kinds) => {
13739
13569
  const displayKinds = kinds.filter(isDisplayMediaKind);
13740
- return displayKinds.length > 0 ? displayKinds : ["image"];
13570
+ return displayKinds.length > 0 ? displayKinds : [...DEFAULT_MEDIA_FIELD_KINDS];
13741
13571
  }),
13742
13572
  aspectRatio: z$1.string().optional()
13743
- });
13573
+ }).superRefine(validateMediaFieldDefault);
13744
13574
  const fileFieldSchema = baseFieldSchema.extend({
13745
13575
  type: z$1.literal("file"),
13746
13576
  fileKinds: z$1.array(z$1.enum(PUBLIC_FILE_FIELD_KINDS)).default([...PUBLIC_FILE_FIELD_KINDS])
13747
- });
13577
+ }).superRefine(validateMediaFieldDefault);
13748
13578
  const booleanFieldSchema = baseFieldSchema.extend({ type: z$1.literal("boolean") });
13749
13579
  const dateFieldSchema = baseFieldSchema.extend({ type: z$1.literal("date") });
13750
13580
  const timeFieldSchema = baseFieldSchema.extend({ type: z$1.literal("time") });
@@ -22044,20 +21874,10 @@ function visitRichTextNode(node, allowedTokens, tokenValues) {
22044
21874
  }
22045
21875
  function interpolateRichTextTokens(value, options, context) {
22046
21876
  if (!isRecord$8(value)) return value;
22047
- const allowedTokens = new Set(options.tokens);
22048
- const tokenValues = {
21877
+ return visitRichTextNode(value, new Set(options.tokens), {
22049
21878
  year: String((/* @__PURE__ */ new Date()).getFullYear()),
22050
21879
  site_name: getSiteName(context)
22051
- };
22052
- if (isRecord$8(value.doc)) {
22053
- const nextDoc = visitRichTextNode(value.doc, allowedTokens, tokenValues);
22054
- if (nextDoc === value.doc) return value;
22055
- return {
22056
- ...value,
22057
- doc: nextDoc
22058
- };
22059
- }
22060
- return visitRichTextNode(value, allowedTokens, tokenValues);
21880
+ });
22061
21881
  }
22062
21882
  const contentTransforms = [{
22063
21883
  id: "content.interpolateRichTextTokens",
@@ -24440,11 +24260,8 @@ const mediaSchema = z.discriminatedUnion("type", [
24440
24260
  * This module provides a single source of truth for TipTap rich text validation
24441
24261
  * across both the block-form editor and the block rendering system.
24442
24262
  *
24443
- * Format compatibility:
24444
- * - Unwrapped format (new): { type: 'doc', content: [...] }
24445
- * - Wrapped format (legacy): { doc: { type: 'doc', content: [...] } }
24446
- *
24447
- * Both formats are supported for backward compatibility during migration.
24263
+ * Rich-text fields use one canonical root shape:
24264
+ * `{ type: 'doc', content: [...] }`.
24448
24265
  */
24449
24266
  /**
24450
24267
  * TipTap document node schema (recursive structure)
@@ -24457,17 +24274,40 @@ const mediaSchema = z.discriminatedUnion("type", [
24457
24274
  * - marks: Text formatting marks (e.g., bold, italic)
24458
24275
  */
24459
24276
  const TipTapMarkSchema = z$1.object({
24460
- type: z$1.string(),
24277
+ type: z$1.string().min(1),
24461
24278
  attrs: z$1.record(z$1.string(), z$1.unknown()).optional()
24462
- });
24279
+ }).strict();
24463
24280
  const TipTapNodeSchema = z$1.lazy(() => z$1.object({
24464
- type: z$1.string(),
24281
+ type: z$1.string().min(1),
24465
24282
  content: z$1.array(TipTapNodeSchema).optional(),
24466
24283
  text: z$1.string().optional(),
24467
24284
  attrs: z$1.record(z$1.string(), z$1.unknown()).optional(),
24468
24285
  marks: z$1.array(TipTapMarkSchema).optional()
24286
+ }).strict().superRefine((node, ctx) => {
24287
+ if (node.type === "doc") ctx.addIssue({
24288
+ code: "custom",
24289
+ path: ["type"],
24290
+ message: "Document nodes are only valid at the rich-text root"
24291
+ });
24292
+ if (node.type === "text") {
24293
+ if (node.text === void 0 || node.text.length === 0) ctx.addIssue({
24294
+ code: "custom",
24295
+ path: ["text"],
24296
+ message: "Text nodes require a non-empty text value"
24297
+ });
24298
+ if (node.content !== void 0) ctx.addIssue({
24299
+ code: "custom",
24300
+ path: ["content"],
24301
+ message: "Text nodes cannot contain child nodes"
24302
+ });
24303
+ return;
24304
+ }
24305
+ if (node.text !== void 0) ctx.addIssue({
24306
+ code: "custom",
24307
+ path: ["text"],
24308
+ message: "Only text nodes can contain a text value"
24309
+ });
24469
24310
  }));
24470
- z$1.union([TipTapNodeSchema, z$1.object({ doc: TipTapNodeSchema })]);
24471
24311
  /**
24472
24312
  * Canonical schema for a TipTap rich-text document root.
24473
24313
  *
@@ -24476,13 +24316,11 @@ z$1.union([TipTapNodeSchema, z$1.object({ doc: TipTapNodeSchema })]);
24476
24316
  * (dummy content, editor output, migrations) must emit, and the shape every
24477
24317
  * non-legacy consumer can rely on.
24478
24318
  *
24479
- * Legacy envelopes are read-tolerated by {@link RichTextValueSchema} but
24480
- * normalised before reaching anywhere typed as `RichTextDoc`.
24481
24319
  */
24482
24320
  const RichTextDocSchema = z$1.object({
24483
24321
  type: z$1.literal("doc"),
24484
24322
  content: z$1.array(TipTapNodeSchema)
24485
- });
24323
+ }).strict();
24486
24324
  //#endregion
24487
24325
  //#region ../blocks/src/system/blocks/shared/bookingPaymentTerms.ts
24488
24326
  const bookingDepositRefundPolicySchema = z$1.enum(["refundable", "non_refundable"]);
@@ -35832,6 +35670,7 @@ const CANONICAL_REFUND_PLANNER_ERROR_CODES = [
35832
35670
  "idempotency_amount_mismatch",
35833
35671
  "idempotency_method_mismatch",
35834
35672
  "idempotency_receipt_mismatch",
35673
+ "idempotency_scope_mismatch",
35835
35674
  "refund_in_progress"
35836
35675
  ],
35837
35676
  "invalid_amount",
@@ -36218,7 +36057,7 @@ const SITE_BANNER_TONE_VALUES = [
36218
36057
  ];
36219
36058
  const siteBannerScopeSchema = z$1.enum(SITE_BANNER_SCOPE_VALUES);
36220
36059
  const siteBannerToneSchema = z$1.enum(SITE_BANNER_TONE_VALUES);
36221
- const siteBannerBodySchema = z$1.unknown().transform(unwrapRichTextValue);
36060
+ const siteBannerBodySchema = RichTextDocSchema;
36222
36061
  const siteBannerCtaSchema = z$1.object({
36223
36062
  label: z$1.string().trim().min(1),
36224
36063
  link: linkPayloadSchema
@@ -36246,7 +36085,8 @@ const EMPTY_SITE_BANNER_BODY = {
36246
36085
  }]
36247
36086
  };
36248
36087
  function analyzeSiteBannerBody(body) {
36249
- const sanitizedBody = sanitizeSiteBannerBodyInternal(body, { limitParagraphs: false });
36088
+ const parsed = RichTextDocSchema.safeParse(body);
36089
+ const sanitizedBody = parsed.success ? sanitizeSiteBannerBodyInternal(parsed.data, { limitParagraphs: false }) : EMPTY_SITE_BANNER_BODY;
36250
36090
  const paragraphs = collectParagraphs(sanitizedBody);
36251
36091
  const textLength = paragraphs.reduce((total, paragraph) => total + paragraphTextLength(paragraph), 0);
36252
36092
  const issues = [];
@@ -36268,7 +36108,7 @@ function siteBannerBodyIssueMessage(issue) {
36268
36108
  }
36269
36109
  }
36270
36110
  function sanitizeSiteBannerBodyInternal(input, options) {
36271
- const content = normalizeTopLevelNodes(unwrapRichTextValue(input).content ?? [], options);
36111
+ const content = normalizeTopLevelNodes(input.content, options);
36272
36112
  return {
36273
36113
  type: "doc",
36274
36114
  content: content.length > 0 ? content : EMPTY_SITE_BANNER_BODY.content
@@ -36349,28 +36189,6 @@ function sanitizeMarks(marks) {
36349
36189
  });
36350
36190
  return sanitized.length > 0 ? sanitized : void 0;
36351
36191
  }
36352
- function unwrapRichTextValue(value) {
36353
- if (isRecord$1(value) && isRecord$1(value.doc)) return unwrapRichTextValue(value.doc);
36354
- if (isRecord$1(value) && value.type === "doc") return {
36355
- type: "doc",
36356
- content: Array.isArray(value.content) ? value.content.filter(isTipTapNodeLike).map(coerceTipTapNode) : []
36357
- };
36358
- return EMPTY_SITE_BANNER_BODY;
36359
- }
36360
- function isTipTapNodeLike(value) {
36361
- return isRecord$1(value) && typeof value.type === "string";
36362
- }
36363
- function coerceTipTapNode(value) {
36364
- return {
36365
- type: value.type,
36366
- ...Array.isArray(value.content) ? { content: value.content.filter(isTipTapNodeLike).map(coerceTipTapNode) } : {},
36367
- ...typeof value.text === "string" ? { text: value.text } : {},
36368
- ...Array.isArray(value.marks) ? { marks: value.marks.filter((mark) => isRecord$1(mark) && typeof mark.type === "string").map((mark) => ({
36369
- type: mark.type,
36370
- ...isRecord$1(mark.attrs) ? { attrs: mark.attrs } : {}
36371
- })) } : {}
36372
- };
36373
- }
36374
36192
  function paragraphTextLength(paragraph) {
36375
36193
  return collectText(paragraph).length;
36376
36194
  }