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