@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
@@ -3248,151 +3248,6 @@ z$1.discriminatedUnion("kind", [
3248
3248
  })
3249
3249
  ]);
3250
3250
  //#endregion
3251
- //#region ../theme-core/src/surfaces/foregroundContract.ts
3252
- const SURFACE_FOREGROUND_CSS_VARS = {
3253
- text: "--rb-surface-text-color",
3254
- heading: "--rb-surface-heading-color",
3255
- link: "--rb-surface-link-color",
3256
- supporting: "--rb-surface-supporting-color"
3257
- };
3258
- const DEFAULT_SURFACE_TEXT_COLOR = "rgb(var(--tb-text, 17 24 39))";
3259
- const DEFAULT_ROLE_FALLBACKS = {
3260
- text: DEFAULT_SURFACE_TEXT_COLOR,
3261
- heading: DEFAULT_SURFACE_TEXT_COLOR,
3262
- link: "rgb(var(--tb-primary, var(--tb-text, 17 24 39)))",
3263
- supporting: "rgb(var(--tb-mutedText, 100 116 139))"
3264
- };
3265
- function requireSurfaceColorValue(role, value) {
3266
- const normalized = value.trim();
3267
- if (normalized.length === 0) throw new RangeError(`Surface foreground ${role} must be a non-empty CSS color.`);
3268
- return normalized;
3269
- }
3270
- function completeSurfaceForegrounds(input) {
3271
- const text = requireSurfaceColorValue("text", input.text);
3272
- return {
3273
- text,
3274
- heading: input.heading === void 0 ? text : requireSurfaceColorValue("heading", input.heading),
3275
- link: input.link === void 0 ? text : requireSurfaceColorValue("link", input.link),
3276
- supporting: input.supporting === void 0 ? text : requireSurfaceColorValue("supporting", input.supporting)
3277
- };
3278
- }
3279
- function surfaceForegroundValue(role, outsideProviderFallback = DEFAULT_ROLE_FALLBACKS[role]) {
3280
- const roleVariable = SURFACE_FOREGROUND_CSS_VARS[role];
3281
- const fallback = requireSurfaceColorValue("fallback", outsideProviderFallback);
3282
- if (role === "text") return `var(${roleVariable}, ${fallback})`;
3283
- return `var(${roleVariable}, var(${SURFACE_FOREGROUND_CSS_VARS.text}, ${fallback}))`;
3284
- }
3285
- function surfaceForegroundValueWithOpacity(role, opacityPercent) {
3286
- if (!Number.isFinite(opacityPercent) || opacityPercent < 0 || opacityPercent > 100) throw new RangeError("Surface foreground opacity must be between 0 and 100.");
3287
- return `color-mix(in srgb, ${surfaceForegroundValue(role)} ${opacityPercent}%, transparent)`;
3288
- }
3289
- function surfaceForegroundStyle(input) {
3290
- const foregrounds = completeSurfaceForegrounds(input);
3291
- return {
3292
- color: foregrounds.text,
3293
- [SURFACE_FOREGROUND_CSS_VARS.text]: foregrounds.text,
3294
- [SURFACE_FOREGROUND_CSS_VARS.heading]: foregrounds.heading,
3295
- [SURFACE_FOREGROUND_CSS_VARS.link]: foregrounds.link,
3296
- [SURFACE_FOREGROUND_CSS_VARS.supporting]: foregrounds.supporting
3297
- };
3298
- }
3299
- //#endregion
3300
- //#region ../theme-core/src/utils/colorStyles.ts
3301
- const COLOR_VAR_PREFIX = "--tb-";
3302
- function parseToken(source) {
3303
- const parts = parseColorTokenParts(source);
3304
- if (parts.kind === "raw") return {
3305
- token: source,
3306
- raw: parts.value
3307
- };
3308
- if (parts.kind === "invalid") return { token: source };
3309
- return {
3310
- token: parts.token,
3311
- opacityPercent: parts.opacityPercent === null ? void 0 : parts.opacityPercent
3312
- };
3313
- }
3314
- const SURFACE_TEXT_ROLE_BY_TOKEN = {
3315
- text: "text",
3316
- heading: "heading",
3317
- mutedText: "supporting"
3318
- };
3319
- function surfaceRoleForTextToken(token) {
3320
- return Object.prototype.hasOwnProperty.call(SURFACE_TEXT_ROLE_BY_TOKEN, token) ? SURFACE_TEXT_ROLE_BY_TOKEN[token] : null;
3321
- }
3322
- /**
3323
- * Converts a theme color token to a CSS rgb value.
3324
- * This is the primary function for applying theme colors to CSS properties.
3325
- *
3326
- * @param token - Theme color token (semantic, with opacity, or raw)
3327
- * @returns CSS color value (rgb with optional alpha, or raw CSS value)
3328
- *
3329
- * @example
3330
- * rgbColorValue('primary') // => 'rgb(var(--tb-primary))'
3331
- * rgbColorValue('surface/95') // => 'rgb(var(--tb-surface) / 0.95)'
3332
- * rgbColorValue('raw:transparent') // => 'transparent'
3333
- */
3334
- function rgbColorValue(token) {
3335
- const { token: baseToken, opacityPercent, raw } = parseToken(token);
3336
- if (raw) return raw;
3337
- const cssVar = `${COLOR_VAR_PREFIX}${baseToken}`;
3338
- if (opacityPercent === void 0) return `rgb(var(${cssVar}))`;
3339
- return `rgb(var(${cssVar}) / ${opacityPercent / 100})`;
3340
- }
3341
- /**
3342
- * Creates a backgroundColor style object from a theme token.
3343
- *
3344
- * @param token - Theme color token
3345
- * @returns CSSProperties with backgroundColor
3346
- */
3347
- function backgroundColorStyle(token) {
3348
- return { backgroundColor: rgbColorValue(token) };
3349
- }
3350
- /**
3351
- * Creates a text color style object from a theme token.
3352
- *
3353
- * @param token - Theme color token
3354
- * @returns CSSProperties with color
3355
- */
3356
- function textColorStyle(token) {
3357
- const parsed = parseToken(token);
3358
- const surfaceRole = parsed.raw ? null : surfaceRoleForTextToken(parsed.token);
3359
- if (surfaceRole) return { color: parsed.opacityPercent === void 0 ? surfaceForegroundValue(surfaceRole) : surfaceForegroundValueWithOpacity(surfaceRole, parsed.opacityPercent) };
3360
- return { color: rgbColorValue(token) };
3361
- }
3362
- /**
3363
- * Creates a border color style object from a theme token.
3364
- *
3365
- * @param token - Theme color token
3366
- * @returns CSSProperties with borderColor
3367
- */
3368
- function borderColorStyle(token) {
3369
- return { borderColor: rgbColorValue(token) };
3370
- }
3371
- /**
3372
- * Merges multiple CSSProperties objects into a single object.
3373
- * Later styles override earlier ones. Undefined values are filtered out.
3374
- * Returns undefined if the merged result is empty.
3375
- *
3376
- * @param styles - Variable number of CSSProperties objects (can be undefined)
3377
- * @returns Merged CSSProperties object, or undefined if empty
3378
- *
3379
- * @example
3380
- * mergeStyles(
3381
- * backgroundColorStyle('surface'),
3382
- * textColorStyle('text'),
3383
- * borderColorStyle('border')
3384
- * )
3385
- * // => { backgroundColor: '...', color: '...', borderColor: '...' }
3386
- */
3387
- function mergeStyles(...styles) {
3388
- const merged = {};
3389
- for (const style of styles) {
3390
- if (!style) continue;
3391
- Object.assign(merged, style);
3392
- }
3393
- return Object.keys(merged).length ? merged : void 0;
3394
- }
3395
- //#endregion
3396
3251
  //#region ../theme-core/src/lib/media.ts
3397
3252
  const hotspotSchema$1 = z.object({
3398
3253
  x: z.number().min(0).max(1),
@@ -3450,111 +3305,6 @@ const mediaSchema$1 = z.object({
3450
3305
  transform: transformSchema$1.optional()
3451
3306
  });
3452
3307
  //#endregion
3453
- //#region ../theme-core/src/buttons/effectClassification.ts
3454
- /**
3455
- * Exhaustive live policy for every registered effect id.
3456
- *
3457
- * The resolver consumes the transition payload directly, so adding an effect
3458
- * cannot update classification without also defining its runtime behavior.
3459
- */
3460
- const BUTTON_EFFECT_POLICIES = {
3461
- "darken-background": {
3462
- classification: "colour-transition",
3463
- transition: {
3464
- kind: "adjust-shade",
3465
- direction: "darker"
3466
- }
3467
- },
3468
- "lighten-background": {
3469
- classification: "colour-transition",
3470
- transition: {
3471
- kind: "adjust-shade",
3472
- direction: "lighter"
3473
- }
3474
- },
3475
- "background-on-hover": {
3476
- classification: "colour-transition",
3477
- transition: { kind: "replace-background" }
3478
- },
3479
- "background-on-hover-alpha": {
3480
- classification: "unsupported-colour",
3481
- reason: "alpha_requires_surface"
3482
- },
3483
- "fade-background": {
3484
- classification: "unsupported-colour",
3485
- reason: "changes_element_opacity"
3486
- },
3487
- "opacity-reduce": {
3488
- classification: "unsupported-colour",
3489
- reason: "changes_element_opacity"
3490
- },
3491
- "gradient-text": {
3492
- classification: "unsupported-colour",
3493
- reason: "changes_foreground"
3494
- },
3495
- "text-color-change": {
3496
- classification: "unsupported-colour",
3497
- reason: "changes_foreground"
3498
- },
3499
- "border-color-change": {
3500
- classification: "unsupported-colour",
3501
- reason: "changes_border"
3502
- },
3503
- "aurora-glow": {
3504
- classification: "unsupported-background-overlay",
3505
- reason: "unresolved_background_overlay"
3506
- },
3507
- "cosmic-stardust": {
3508
- classification: "unsupported-background-overlay",
3509
- reason: "unresolved_background_overlay"
3510
- },
3511
- "gradient-border-fill": {
3512
- classification: "unsupported-background-overlay",
3513
- reason: "unresolved_background_overlay"
3514
- },
3515
- "animated-gradient-border-fill": {
3516
- classification: "unsupported-background-overlay",
3517
- reason: "unresolved_background_overlay"
3518
- },
3519
- "nav-underline": {
3520
- classification: "not-button",
3521
- reason: "not_button_effect"
3522
- },
3523
- "nav-frosted-base": {
3524
- classification: "not-button",
3525
- reason: "not_button_effect"
3526
- },
3527
- "nav-frosted-hover": {
3528
- classification: "not-button",
3529
- reason: "not_button_effect"
3530
- },
3531
- "nav-frosted-active": {
3532
- classification: "not-button",
3533
- reason: "not_button_effect"
3534
- },
3535
- "animated-gradient": { classification: "non-colour" },
3536
- "border-glow": { classification: "non-colour" },
3537
- "drop-shadow": { classification: "non-colour" },
3538
- "inner-shadow": { classification: "non-colour" },
3539
- "neumorphic-shadow": { classification: "non-colour" },
3540
- "outer-glow": { classification: "non-colour" },
3541
- "retro-3d-shadow": { classification: "non-colour" },
3542
- "scale-up": { classification: "non-colour" },
3543
- "scale-down": { classification: "non-colour" },
3544
- lift: { classification: "non-colour" },
3545
- "press-down": { classification: "non-colour" },
3546
- pop: { classification: "non-colour" },
3547
- "border-bottom-grow": { classification: "non-colour" },
3548
- "sketchy-border": { classification: "non-colour" },
3549
- "pulse-animation": { classification: "non-colour" }
3550
- };
3551
- function getButtonEffectPolicy(effectId) {
3552
- return Object.prototype.hasOwnProperty.call(BUTTON_EFFECT_POLICIES, effectId) ? BUTTON_EFFECT_POLICIES[effectId] : null;
3553
- }
3554
- function classifyButtonEffectId(effectId) {
3555
- return getButtonEffectPolicy(effectId)?.classification ?? "unknown";
3556
- }
3557
- //#endregion
3558
3308
  //#region ../theme-core/src/buttons/types.ts
3559
3309
  /**
3560
3310
  * Standard semantic variant roles a theme exposes.
@@ -3571,6 +3321,13 @@ const VARIANT_ROLES = [
3571
3321
  "tertiary",
3572
3322
  "accent"
3573
3323
  ];
3324
+ /**
3325
+ * Canonical persisted/CSS-safe button variant identifier.
3326
+ *
3327
+ * IDs become class selectors, so keep the contract deliberately narrower than
3328
+ * an arbitrary string and shared with every authoring/runtime boundary.
3329
+ */
3330
+ const buttonVariantIdSchema = z$1.string().min(1).max(50).regex(/^[a-z0-9-]+$/, "Button variant IDs may contain lowercase letters, numbers, and hyphens only");
3574
3331
  function parseOpaqueButtonColourToken(value) {
3575
3332
  const token = parseThemeColorToken(value);
3576
3333
  if (token === null) return null;
@@ -3585,6 +3342,109 @@ const opaqueButtonColourTokenSchema = themeColorTokenSchema.refine((value) => pa
3585
3342
  if (token === null) throw new Error("Invariant: opaque button token passed its schema");
3586
3343
  return token;
3587
3344
  });
3345
+ const buttonShadeAmountSchema = z$1.number().finite().min(0).max(900).multipleOf(100);
3346
+ const buttonShadowIntensitySchema = z$1.enum([
3347
+ "subtle",
3348
+ "medium",
3349
+ "strong"
3350
+ ]);
3351
+ /**
3352
+ * The complete persisted button-effect contract.
3353
+ *
3354
+ * Navigation has its own generic interactive-effect model. Button variants use
3355
+ * this closed union so unsupported effect IDs, unknown option keys, and unsafe
3356
+ * CSS values cannot become representable after the schema boundary.
3357
+ */
3358
+ const buttonEffectApplicationSchema = z$1.discriminatedUnion("effectId", [
3359
+ z$1.strictObject({
3360
+ effectId: z$1.literal("darken-background"),
3361
+ options: z$1.strictObject({ amount: buttonShadeAmountSchema.optional() }).optional()
3362
+ }),
3363
+ z$1.strictObject({
3364
+ effectId: z$1.literal("lighten-background"),
3365
+ options: z$1.strictObject({ amount: buttonShadeAmountSchema.optional() }).optional()
3366
+ }),
3367
+ z$1.strictObject({
3368
+ effectId: z$1.literal("background-on-hover"),
3369
+ options: z$1.strictObject({ colorToken: opaqueButtonColourTokenSchema.optional() }).optional()
3370
+ }),
3371
+ z$1.strictObject({
3372
+ effectId: z$1.literal("animated-gradient"),
3373
+ options: z$1.strictObject({ direction: z$1.enum(["horizontal", "vertical"]).optional() }).optional()
3374
+ }),
3375
+ z$1.strictObject({
3376
+ effectId: z$1.literal("drop-shadow"),
3377
+ options: z$1.strictObject({ intensity: buttonShadowIntensitySchema.optional() }).optional()
3378
+ }),
3379
+ z$1.strictObject({
3380
+ effectId: z$1.literal("inner-shadow"),
3381
+ options: z$1.strictObject({}).optional()
3382
+ }),
3383
+ z$1.strictObject({
3384
+ effectId: z$1.literal("neumorphic-shadow"),
3385
+ options: z$1.strictObject({
3386
+ mode: z$1.enum(["raised", "pressed"]).optional(),
3387
+ intensity: buttonShadowIntensitySchema.optional()
3388
+ }).optional()
3389
+ }),
3390
+ z$1.strictObject({
3391
+ effectId: z$1.literal("retro-3d-shadow"),
3392
+ options: z$1.strictObject({}).optional()
3393
+ }),
3394
+ z$1.strictObject({
3395
+ effectId: z$1.literal("scale-up"),
3396
+ options: z$1.strictObject({ scale: z$1.enum([
3397
+ "1.02",
3398
+ "1.03",
3399
+ "1.05",
3400
+ "1.10"
3401
+ ]).optional() }).optional()
3402
+ }),
3403
+ z$1.strictObject({
3404
+ effectId: z$1.literal("scale-down"),
3405
+ options: z$1.strictObject({ scale: z$1.enum([
3406
+ "0.90",
3407
+ "0.95",
3408
+ "0.97",
3409
+ "0.98"
3410
+ ]).optional() }).optional()
3411
+ }),
3412
+ z$1.strictObject({
3413
+ effectId: z$1.literal("lift"),
3414
+ options: z$1.strictObject({ amount: z$1.enum([
3415
+ "0.25",
3416
+ "0.5",
3417
+ "1"
3418
+ ]).optional() }).optional()
3419
+ }),
3420
+ z$1.strictObject({
3421
+ effectId: z$1.literal("press-down"),
3422
+ options: z$1.strictObject({}).optional()
3423
+ }),
3424
+ z$1.strictObject({
3425
+ effectId: z$1.literal("pop"),
3426
+ options: z$1.strictObject({ intensity: z$1.enum([
3427
+ "subtle",
3428
+ "medium",
3429
+ "dramatic"
3430
+ ]).optional() }).optional()
3431
+ }),
3432
+ z$1.strictObject({
3433
+ effectId: z$1.literal("border-bottom-grow"),
3434
+ options: z$1.strictObject({
3435
+ height: z$1.union([z$1.literal(1), z$1.literal(2)]).optional(),
3436
+ origin: z$1.enum([
3437
+ "left",
3438
+ "center",
3439
+ "right"
3440
+ ]).optional()
3441
+ }).optional()
3442
+ }),
3443
+ z$1.strictObject({
3444
+ effectId: z$1.literal("sketchy-border"),
3445
+ options: z$1.strictObject({ intensity: buttonShadowIntensitySchema.optional() }).optional()
3446
+ })
3447
+ ]);
3588
3448
  const cornerStyleSchema = z$1.enum([
3589
3449
  "square",
3590
3450
  "rounded",
@@ -3619,13 +3479,7 @@ const hoverTransformSchema = z$1.enum([
3619
3479
  "scale",
3620
3480
  "press"
3621
3481
  ]);
3622
- const hoverColorSchema = z$1.enum([
3623
- "none",
3624
- "brighten",
3625
- "darken",
3626
- "saturate",
3627
- "token"
3628
- ]);
3482
+ z$1.enum(["none", "token"]);
3629
3483
  const buttonPaddingPresetSchema = z$1.enum([
3630
3484
  "compact",
3631
3485
  "default",
@@ -3686,7 +3540,7 @@ const buttonSizesSchema = z$1.object({
3686
3540
  lg,
3687
3541
  xl: xl ?? lg
3688
3542
  }));
3689
- const canonicalButtonGlobalSettingsSchema = z$1.object({
3543
+ const buttonGlobalSettingsBaseSchema = z$1.strictObject({
3690
3544
  cornerStyle: cornerStyleSchema,
3691
3545
  cornerRadius: z$1.number().min(0).max(24).optional(),
3692
3546
  /**
@@ -3699,30 +3553,23 @@ const canonicalButtonGlobalSettingsSchema = z$1.object({
3699
3553
  shadow: shadowSizeSchema.optional(),
3700
3554
  textTransform: textTransformSchema,
3701
3555
  fontWeight: fontWeightSchema,
3702
- /**
3703
- * @deprecated Set per-variant via `variant.border.widthClass` instead.
3704
- * Schema field is preserved so existing presets parse; the value is unread
3705
- * by the current generator and will be removed once the legacy
3706
- * `primitives/content/components/Button.tsx` slot exports are deleted.
3707
- */
3708
- borderWidth: z$1.union([
3709
- z$1.literal(1),
3710
- z$1.literal(2),
3711
- z$1.literal(3)
3712
- ]),
3713
3556
  typography: buttonTypographySchema.optional(),
3714
3557
  fontSize: z$1.string().optional(),
3715
3558
  letterSpacing: letterSpacingSchema.optional(),
3716
3559
  italic: z$1.boolean().optional(),
3717
3560
  paddingPreset: buttonPaddingPresetSchema.optional(),
3718
3561
  hoverTransform: hoverTransformSchema,
3719
- hoverColor: hoverColorSchema,
3720
- hoverColorToken: opaqueButtonColourTokenSchema.optional(),
3721
3562
  gradientStyle: gradientStyleSchema.optional(),
3722
3563
  gradientAngle: z$1.number().min(0).max(360).optional(),
3723
3564
  gradientSharpness: gradientSharpnessSchema.optional()
3724
3565
  });
3725
- const buttonGlobalSettingsSchema = z$1.preprocess(normalizeLegacyButtonGlobalInput, canonicalButtonGlobalSettingsSchema);
3566
+ const buttonGlobalSettingsSchema = z$1.discriminatedUnion("hoverColor", [buttonGlobalSettingsBaseSchema.extend({
3567
+ hoverColor: z$1.literal("none"),
3568
+ hoverColorToken: z$1.never().optional()
3569
+ }), buttonGlobalSettingsBaseSchema.extend({
3570
+ hoverColor: z$1.literal("token"),
3571
+ hoverColorToken: opaqueButtonColourTokenSchema
3572
+ })]);
3726
3573
  const gradientDirectionSchema$1 = z$1.enum([
3727
3574
  "to-r",
3728
3575
  "to-l",
@@ -3734,11 +3581,11 @@ const gradientDirectionSchema$1 = z$1.enum([
3734
3581
  "to-bl"
3735
3582
  ]);
3736
3583
  const buttonColourTreatmentSchema = z$1.discriminatedUnion("type", [
3737
- z$1.object({
3584
+ z$1.strictObject({
3738
3585
  type: z$1.literal("solid"),
3739
3586
  colorToken: opaqueButtonColourTokenSchema
3740
3587
  }),
3741
- z$1.object({
3588
+ z$1.strictObject({
3742
3589
  type: z$1.literal("gradient"),
3743
3590
  stops: z$1.array(opaqueButtonColourTokenSchema).min(2).transform((stops) => {
3744
3591
  const [first, second, ...rest] = stops;
@@ -3752,19 +3599,15 @@ const buttonColourTreatmentSchema = z$1.discriminatedUnion("type", [
3752
3599
  direction: gradientDirectionSchema$1,
3753
3600
  foregroundToken: opaqueButtonColourTokenSchema
3754
3601
  }),
3755
- z$1.object({
3602
+ z$1.strictObject({
3756
3603
  type: z$1.literal("surface"),
3757
3604
  role: z$1.literal("link")
3758
3605
  })
3759
3606
  ]);
3760
3607
  const buttonBackgroundSchema = buttonColourTreatmentSchema;
3761
- const effectApplicationSchema$1 = z$1.object({
3762
- effectId: z$1.string(),
3763
- options: z$1.record(z$1.string(), z$1.json()).optional()
3764
- });
3765
- const buttonBorderSchema = z$1.object({ widthClass: z$1.string() });
3766
- const buttonVariantAffordanceSchema = z$1.object({ iconId: z$1.string().min(1) });
3767
- const variantShadowSchema = z$1.object({
3608
+ const buttonBorderSchema = z$1.strictObject({ widthClass: z$1.string() });
3609
+ const buttonVariantAffordanceSchema = z$1.strictObject({ iconId: z$1.string().min(1) });
3610
+ const variantShadowSchema = z$1.strictObject({
3768
3611
  elevation: z$1.enum([
3769
3612
  "none",
3770
3613
  "low",
@@ -3777,13 +3620,13 @@ const variantShadowSchema = z$1.object({
3777
3620
  "hard"
3778
3621
  ]).nullable(),
3779
3622
  position: z$1.enum(["bottom", "bottom-right"]).default("bottom"),
3780
- colorToken: themeColorTokenSchema.optional()
3623
+ colorToken: opaqueButtonColourTokenSchema.optional()
3781
3624
  });
3782
- const variantEffectsSchema = z$1.object({
3783
- base: z$1.array(effectApplicationSchema$1).optional(),
3784
- hover: z$1.array(effectApplicationSchema$1).optional(),
3785
- active: z$1.array(effectApplicationSchema$1).optional(),
3786
- focus: z$1.array(effectApplicationSchema$1).optional()
3625
+ const variantEffectsSchema = z$1.strictObject({
3626
+ base: z$1.array(buttonEffectApplicationSchema).optional(),
3627
+ hover: z$1.array(buttonEffectApplicationSchema).optional(),
3628
+ active: z$1.array(buttonEffectApplicationSchema).optional(),
3629
+ focus: z$1.array(buttonEffectApplicationSchema).optional()
3787
3630
  });
3788
3631
  /**
3789
3632
  * Per-variant size overrides schema — every entry is optional.
@@ -3804,8 +3647,8 @@ const variantSizeOverridesSchema = z$1.object({
3804
3647
  * default (e.g. link-style variants declaring zero horizontal padding at
3805
3648
  * every size).
3806
3649
  */
3807
- const canonicalButtonVariantSchema = z$1.object({
3808
- id: z$1.string(),
3650
+ const buttonVariantSchema = z$1.strictObject({
3651
+ id: buttonVariantIdSchema,
3809
3652
  name: z$1.string().min(1).max(20),
3810
3653
  enabled: z$1.boolean(),
3811
3654
  priority: prioritySchema,
@@ -3819,154 +3662,73 @@ const canonicalButtonVariantSchema = z$1.object({
3819
3662
  sizes: variantSizeOverridesSchema.optional(),
3820
3663
  affordance: buttonVariantAffordanceSchema.optional()
3821
3664
  });
3822
- /**
3823
- * Temporary persisted-theme admission boundary for issue #1206.
3824
- *
3825
- * Production inventory on 2026-07-22 found 22 rows using the old independent
3826
- * `textColorToken`/border colour shape. New source and all downstream code use
3827
- * only the canonical relationship. Delete this preprocessor after the reviewed
3828
- * production rewrite reports zero legacy rows.
3829
- */
3830
- const buttonVariantSchema = z$1.preprocess(normalizeLegacyButtonVariantInput, canonicalButtonVariantSchema);
3831
- const buttonSystemSchema = z$1.object({
3665
+ const buttonSystemSchema = z$1.strictObject({
3832
3666
  global: buttonGlobalSettingsSchema,
3833
3667
  variants: z$1.array(buttonVariantSchema).min(1).max(6),
3834
3668
  sizes: buttonSizesSchema.optional()
3669
+ }).superRefine((system, ctx) => {
3670
+ const seen = /* @__PURE__ */ new Set();
3671
+ system.variants.forEach((variant, index) => {
3672
+ if (seen.has(variant.id)) ctx.addIssue({
3673
+ code: "custom",
3674
+ path: [
3675
+ "variants",
3676
+ index,
3677
+ "id"
3678
+ ],
3679
+ message: `Duplicate button variant ID: ${variant.id}`
3680
+ });
3681
+ seen.add(variant.id);
3682
+ });
3835
3683
  });
3836
- function normalizeLegacyButtonVariantInput(input) {
3837
- if (!isUnknownRecord(input)) return input;
3838
- const background = input.background;
3839
- if (!isUnknownRecord(background)) return input;
3840
- 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;
3841
- const { textColorToken, ...withoutLegacyText } = input;
3842
- const normalizedBorder = isUnknownRecord(input.border) && typeof input.border.widthClass === "string" ? { widthClass: input.border.widthClass } : input.border;
3843
- const normalizedAffordance = isUnknownRecord(input.affordance) && typeof input.affordance.iconId === "string" ? { iconId: input.affordance.iconId } : input.affordance;
3844
- const normalizedEffects = normalizeLegacyButtonEffects(input.effects, background.type);
3845
- const hoverBackgroundToken = stripLegacyTokenAlpha(input.hoverBackgroundToken);
3846
- if (background.type === "transparent") return {
3847
- ...withoutLegacyText,
3848
- background: {
3849
- type: "surface",
3850
- role: "link"
3851
- },
3852
- border: normalizedBorder,
3853
- affordance: normalizedAffordance,
3854
- effects: normalizedEffects,
3855
- hoverBackgroundToken
3856
- };
3857
- if (background.type === "gradient") {
3858
- const stops = Array.isArray(background.stops) ? background.stops.map(stripLegacyTokenAlpha) : background.stops;
3859
- return {
3860
- ...withoutLegacyText,
3861
- background: {
3862
- ...background,
3863
- stops,
3864
- foregroundToken: stripLegacyTokenAlpha(background.foregroundToken ?? textColorToken)
3865
- },
3866
- border: normalizedBorder,
3867
- affordance: normalizedAffordance,
3868
- effects: normalizedEffects,
3869
- hoverBackgroundToken
3870
- };
3871
- }
3872
- return {
3873
- ...withoutLegacyText,
3874
- background: background.type === "solid" ? {
3875
- ...background,
3876
- colorToken: stripLegacyTokenAlpha(background.colorToken)
3877
- } : background,
3878
- border: normalizedBorder,
3879
- affordance: normalizedAffordance,
3880
- effects: normalizedEffects,
3881
- hoverBackgroundToken
3882
- };
3684
+ //#endregion
3685
+ //#region ../theme-core/src/surfaces/foregroundContract.ts
3686
+ const SURFACE_FOREGROUND_CSS_VARS = {
3687
+ text: "--rb-surface-text-color",
3688
+ heading: "--rb-surface-heading-color",
3689
+ link: "--rb-surface-link-color",
3690
+ supporting: "--rb-surface-supporting-color"
3691
+ };
3692
+ const DEFAULT_SURFACE_TEXT_COLOR = "rgb(var(--tb-text, 17 24 39))";
3693
+ const DEFAULT_ROLE_FALLBACKS = {
3694
+ text: DEFAULT_SURFACE_TEXT_COLOR,
3695
+ heading: DEFAULT_SURFACE_TEXT_COLOR,
3696
+ link: "rgb(var(--tb-primary, var(--tb-text, 17 24 39)))",
3697
+ supporting: "rgb(var(--tb-mutedText, 100 116 139))"
3698
+ };
3699
+ function requireSurfaceColorValue(role, value) {
3700
+ const normalized = value.trim();
3701
+ if (normalized.length === 0) throw new RangeError(`Surface foreground ${role} must be a non-empty CSS color.`);
3702
+ return normalized;
3883
3703
  }
3884
- function normalizeLegacyButtonGlobalInput(input) {
3885
- if (!isUnknownRecord(input)) return input;
3886
- const hoverColorToken = stripLegacyTokenAlpha(input.hoverColorToken);
3887
- return hoverColorToken === input.hoverColorToken ? input : {
3888
- ...input,
3889
- hoverColorToken
3704
+ function completeSurfaceForegrounds(input) {
3705
+ const text = requireSurfaceColorValue("text", input.text);
3706
+ return {
3707
+ text,
3708
+ heading: input.heading === void 0 ? text : requireSurfaceColorValue("heading", input.heading),
3709
+ link: input.link === void 0 ? text : requireSurfaceColorValue("link", input.link),
3710
+ supporting: input.supporting === void 0 ? text : requireSurfaceColorValue("supporting", input.supporting)
3890
3711
  };
3891
3712
  }
3892
- function hasLegacyAlphaToken(input, background) {
3893
- const stops = isUnknownArray(background.stops) ? background.stops : [];
3894
- return [
3895
- input.hoverBackgroundToken,
3896
- background.colorToken,
3897
- background.foregroundToken,
3898
- ...stops
3899
- ].some((token) => stripLegacyTokenAlpha(token) !== token);
3900
- }
3901
- function stripLegacyTokenAlpha(value) {
3902
- if (typeof value !== "string") return value;
3903
- const slashIndex = value.indexOf("/");
3904
- return slashIndex < 0 ? value : value.slice(0, slashIndex);
3905
- }
3906
- function hasLegacyButtonEffects(input) {
3907
- if (!isUnknownRecord(input)) return false;
3908
- return [
3909
- "base",
3910
- "hover",
3911
- "active",
3912
- "focus"
3913
- ].some((state) => {
3914
- const effects = input[state];
3915
- return Array.isArray(effects) && effects.some((effect) => {
3916
- if (!isUnknownRecord(effect) || typeof effect.effectId !== "string") return true;
3917
- const classification = classifyButtonEffectId(effect.effectId);
3918
- if (classification !== "colour-transition" && classification !== "non-colour") return true;
3919
- return effect.effectId === "background-on-hover" && isUnknownRecord(effect.options) && stripLegacyTokenAlpha(effect.options.colorToken) !== effect.options.colorToken;
3920
- });
3921
- });
3922
- }
3923
- function normalizeLegacyButtonEffects(input, backgroundType) {
3924
- if (!isUnknownRecord(input)) return input;
3925
- const normalized = {};
3926
- for (const state of [
3927
- "base",
3928
- "hover",
3929
- "active",
3930
- "focus"
3931
- ]) {
3932
- const effects = input[state];
3933
- if (!Array.isArray(effects)) continue;
3934
- const safeEffects = effects.flatMap((effect) => {
3935
- if (!isUnknownRecord(effect) || typeof effect.effectId !== "string") return [];
3936
- const classification = classifyButtonEffectId(effect.effectId);
3937
- if (classification === "non-colour") return [effect];
3938
- if (classification !== "colour-transition") return [];
3939
- if (effect.effectId === "background-on-hover") {
3940
- const options = isUnknownRecord(effect.options) ? effect.options : null;
3941
- const colorToken = options === null ? null : parseOpaqueButtonColourToken(stripLegacyTokenAlpha(options.colorToken));
3942
- return colorToken === null ? [] : [{
3943
- ...effect,
3944
- options: {
3945
- ...options,
3946
- colorToken
3947
- }
3948
- }];
3949
- }
3950
- if (backgroundType !== "solid") return [];
3951
- const rawAmount = isUnknownRecord(effect.options) ? effect.options.amount : void 0;
3952
- const amount = typeof rawAmount === "number" && rawAmount > 0 ? Math.max(100, Math.round(rawAmount / 100) * 100) : 100;
3953
- return [{
3954
- ...effect,
3955
- options: {
3956
- ...isUnknownRecord(effect.options) ? effect.options : {},
3957
- amount
3958
- }
3959
- }];
3960
- });
3961
- if (safeEffects.length > 0) normalized[state] = safeEffects;
3962
- }
3963
- return Object.keys(normalized).length === 0 ? void 0 : normalized;
3713
+ function surfaceForegroundValue(role, outsideProviderFallback = DEFAULT_ROLE_FALLBACKS[role]) {
3714
+ const roleVariable = SURFACE_FOREGROUND_CSS_VARS[role];
3715
+ const fallback = requireSurfaceColorValue("fallback", outsideProviderFallback);
3716
+ if (role === "text") return `var(${roleVariable}, ${fallback})`;
3717
+ return `var(${roleVariable}, var(${SURFACE_FOREGROUND_CSS_VARS.text}, ${fallback}))`;
3964
3718
  }
3965
- function isUnknownRecord(value) {
3966
- return typeof value === "object" && value !== null && !Array.isArray(value);
3719
+ function surfaceForegroundValueWithOpacity(role, opacityPercent) {
3720
+ if (!Number.isFinite(opacityPercent) || opacityPercent < 0 || opacityPercent > 100) throw new RangeError("Surface foreground opacity must be between 0 and 100.");
3721
+ return `color-mix(in srgb, ${surfaceForegroundValue(role)} ${opacityPercent}%, transparent)`;
3967
3722
  }
3968
- function isUnknownArray(value) {
3969
- return Array.isArray(value);
3723
+ function surfaceForegroundStyle(input) {
3724
+ const foregrounds = completeSurfaceForegrounds(input);
3725
+ return {
3726
+ color: foregrounds.text,
3727
+ [SURFACE_FOREGROUND_CSS_VARS.text]: foregrounds.text,
3728
+ [SURFACE_FOREGROUND_CSS_VARS.heading]: foregrounds.heading,
3729
+ [SURFACE_FOREGROUND_CSS_VARS.link]: foregrounds.link,
3730
+ [SURFACE_FOREGROUND_CSS_VARS.supporting]: foregrounds.supporting
3731
+ };
3970
3732
  }
3971
3733
  buttonSizeNameSchema.options;
3972
3734
  //#endregion
@@ -4123,7 +3885,6 @@ const quietArrowRecipe = defineButtonStyleRecipe({
4123
3885
  cornerStyle: "rounded",
4124
3886
  textTransform: "uppercase",
4125
3887
  fontWeight: 500,
4126
- borderWidth: 1,
4127
3888
  typography: "body",
4128
3889
  fontSize: "text-sm",
4129
3890
  letterSpacing: "loose",
@@ -4187,7 +3948,7 @@ const quietArrowRecipe = defineButtonStyleRecipe({
4187
3948
  affordance: { iconId: "ArrowRight" },
4188
3949
  effects: { hover: [{
4189
3950
  effectId: "background-on-hover",
4190
- options: { colorToken: "surfaceAlt" }
3951
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surfaceAlt") }
4191
3952
  }] }
4192
3953
  }
4193
3954
  },
@@ -4298,7 +4059,6 @@ const softPillRecipe = defineStaticButtonStyleRecipe({
4298
4059
  shadow: "low",
4299
4060
  textTransform: "none",
4300
4061
  fontWeight: 500,
4301
- borderWidth: 2,
4302
4062
  hoverTransform: "lift",
4303
4063
  hoverColor: "none"
4304
4064
  },
@@ -4317,10 +4077,7 @@ const softPillRecipe = defineStaticButtonStyleRecipe({
4317
4077
  position: "bottom"
4318
4078
  },
4319
4079
  effects: {
4320
- hover: [{
4321
- effectId: "lift",
4322
- options: { translateY: "-1px" }
4323
- }],
4080
+ hover: [{ effectId: "lift" }],
4324
4081
  active: [{
4325
4082
  effectId: "scale-down",
4326
4083
  options: { scale: "0.98" }
@@ -4339,7 +4096,7 @@ const softPillRecipe = defineStaticButtonStyleRecipe({
4339
4096
  border: { widthClass: "border-2" },
4340
4097
  effects: { hover: [{
4341
4098
  effectId: "background-on-hover",
4342
- options: { colorToken: "surface" }
4099
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surface") }
4343
4100
  }] }
4344
4101
  }
4345
4102
  },
@@ -4354,7 +4111,7 @@ const softPillRecipe = defineStaticButtonStyleRecipe({
4354
4111
  border: { widthClass: "border" },
4355
4112
  effects: { hover: [{
4356
4113
  effectId: "background-on-hover",
4357
- options: { colorToken: "surface" }
4114
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surface") }
4358
4115
  }] }
4359
4116
  }
4360
4117
  },
@@ -4368,7 +4125,7 @@ const softPillRecipe = defineStaticButtonStyleRecipe({
4368
4125
  borderRadius: "rounded-full",
4369
4126
  effects: { hover: [{
4370
4127
  effectId: "background-on-hover",
4371
- options: { colorToken: "surface" }
4128
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surface") }
4372
4129
  }] }
4373
4130
  }
4374
4131
  },
@@ -4398,7 +4155,6 @@ const earthPillRecipe = defineStaticButtonStyleRecipe({
4398
4155
  shadow: "low",
4399
4156
  textTransform: "none",
4400
4157
  fontWeight: 500,
4401
- borderWidth: 1,
4402
4158
  hoverTransform: "lift",
4403
4159
  hoverColor: "none",
4404
4160
  typography: "body",
@@ -4434,12 +4190,9 @@ const earthPillRecipe = defineStaticButtonStyleRecipe({
4434
4190
  position: "bottom"
4435
4191
  },
4436
4192
  effects: {
4437
- hover: [{
4438
- effectId: "lift",
4439
- options: { translateY: "-1px" }
4440
- }, {
4193
+ hover: [{ effectId: "lift" }, {
4441
4194
  effectId: "background-on-hover",
4442
- options: { colorToken: "accent" }
4195
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("accent") }
4443
4196
  }],
4444
4197
  active: [{
4445
4198
  effectId: "scale-down",
@@ -4459,7 +4212,7 @@ const earthPillRecipe = defineStaticButtonStyleRecipe({
4459
4212
  border: { widthClass: "border" },
4460
4213
  effects: { hover: [{
4461
4214
  effectId: "background-on-hover",
4462
- options: { colorToken: "muted" }
4215
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("muted") }
4463
4216
  }] }
4464
4217
  }
4465
4218
  },
@@ -4474,7 +4227,7 @@ const earthPillRecipe = defineStaticButtonStyleRecipe({
4474
4227
  border: { widthClass: "border" },
4475
4228
  effects: { hover: [{
4476
4229
  effectId: "background-on-hover",
4477
- options: { colorToken: "surfaceAlt" }
4230
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surfaceAlt") }
4478
4231
  }] }
4479
4232
  }
4480
4233
  },
@@ -4534,7 +4287,6 @@ const confidentChipRecipe = defineStaticButtonStyleRecipe({
4534
4287
  shadow: "medium",
4535
4288
  textTransform: "none",
4536
4289
  fontWeight: 600,
4537
- borderWidth: 1,
4538
4290
  hoverTransform: "none",
4539
4291
  hoverColor: "none"
4540
4292
  },
@@ -4575,7 +4327,7 @@ const confidentChipRecipe = defineStaticButtonStyleRecipe({
4575
4327
  border: { widthClass: "border" },
4576
4328
  effects: { hover: [{
4577
4329
  effectId: "background-on-hover",
4578
- options: { colorToken: "background" }
4330
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("background") }
4579
4331
  }] }
4580
4332
  }
4581
4333
  },
@@ -4590,7 +4342,7 @@ const confidentChipRecipe = defineStaticButtonStyleRecipe({
4590
4342
  border: { widthClass: "border" },
4591
4343
  effects: { hover: [{
4592
4344
  effectId: "background-on-hover",
4593
- options: { colorToken: "surface" }
4345
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surface") }
4594
4346
  }] }
4595
4347
  }
4596
4348
  },
@@ -4604,7 +4356,7 @@ const confidentChipRecipe = defineStaticButtonStyleRecipe({
4604
4356
  borderRadius: "rounded-md",
4605
4357
  effects: { hover: [{
4606
4358
  effectId: "background-on-hover",
4607
- options: { colorToken: "surface" }
4359
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surface") }
4608
4360
  }] }
4609
4361
  }
4610
4362
  },
@@ -4639,7 +4391,6 @@ const editorialLinkRecipe = defineStaticButtonStyleRecipe({
4639
4391
  cornerStyle: "square",
4640
4392
  textTransform: "none",
4641
4393
  fontWeight: 500,
4642
- borderWidth: 1,
4643
4394
  hoverTransform: "none",
4644
4395
  hoverColor: "none"
4645
4396
  },
@@ -4657,7 +4408,6 @@ const editorialLinkRecipe = defineStaticButtonStyleRecipe({
4657
4408
  effectId: "border-bottom-grow",
4658
4409
  options: {
4659
4410
  height: 2,
4660
- colorToken: "text",
4661
4411
  origin: "left"
4662
4412
  }
4663
4413
  }] }
@@ -4676,7 +4426,6 @@ const editorialLinkRecipe = defineStaticButtonStyleRecipe({
4676
4426
  effectId: "border-bottom-grow",
4677
4427
  options: {
4678
4428
  height: 1,
4679
- colorToken: "mutedText",
4680
4429
  origin: "left"
4681
4430
  }
4682
4431
  }] }
@@ -4695,7 +4444,6 @@ const editorialLinkRecipe = defineStaticButtonStyleRecipe({
4695
4444
  effectId: "border-bottom-grow",
4696
4445
  options: {
4697
4446
  height: 1,
4698
- colorToken: "accent",
4699
4447
  origin: "left"
4700
4448
  }
4701
4449
  }] }
@@ -4719,7 +4467,6 @@ const editorialLinkRecipe = defineStaticButtonStyleRecipe({
4719
4467
  effectId: "border-bottom-grow",
4720
4468
  options: {
4721
4469
  height: 2,
4722
- colorToken: "accent",
4723
4470
  origin: "left"
4724
4471
  }
4725
4472
  }] } }
@@ -4741,7 +4488,6 @@ const pebbleRecipe = defineStaticButtonStyleRecipe({
4741
4488
  cornerStyle: "pill",
4742
4489
  textTransform: "none",
4743
4490
  fontWeight: 500,
4744
- borderWidth: 2,
4745
4491
  hoverTransform: "none",
4746
4492
  hoverColor: "none"
4747
4493
  },
@@ -4786,7 +4532,7 @@ const pebbleRecipe = defineStaticButtonStyleRecipe({
4786
4532
  border: { widthClass: "border-2" },
4787
4533
  effects: { hover: [{
4788
4534
  effectId: "background-on-hover",
4789
- options: { colorToken: "accent" }
4535
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("accent") }
4790
4536
  }] }
4791
4537
  }
4792
4538
  },
@@ -4801,7 +4547,7 @@ const pebbleRecipe = defineStaticButtonStyleRecipe({
4801
4547
  border: { widthClass: "border" },
4802
4548
  effects: { hover: [{
4803
4549
  effectId: "background-on-hover",
4804
- options: { colorToken: "surface" }
4550
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surface") }
4805
4551
  }] }
4806
4552
  }
4807
4553
  },
@@ -4856,7 +4602,6 @@ const brushedWashRecipe = defineStaticButtonStyleRecipe({
4856
4602
  shadow: "low",
4857
4603
  textTransform: "none",
4858
4604
  fontWeight: 500,
4859
- borderWidth: 1,
4860
4605
  hoverTransform: "none",
4861
4606
  hoverColor: "none"
4862
4607
  },
@@ -4921,7 +4666,7 @@ const brushedWashRecipe = defineStaticButtonStyleRecipe({
4921
4666
  border: { widthClass: "border" },
4922
4667
  effects: { hover: [{
4923
4668
  effectId: "background-on-hover",
4924
- options: { colorToken: "surface" }
4669
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surface") }
4925
4670
  }] }
4926
4671
  }
4927
4672
  },
@@ -4935,7 +4680,7 @@ const brushedWashRecipe = defineStaticButtonStyleRecipe({
4935
4680
  borderRadius: "rounded-lg",
4936
4681
  effects: { hover: [{
4937
4682
  effectId: "background-on-hover",
4938
- options: { colorToken: "surface" }
4683
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surface") }
4939
4684
  }] }
4940
4685
  }
4941
4686
  },
@@ -4964,7 +4709,6 @@ const inkStampRecipe = defineStaticButtonStyleRecipe({
4964
4709
  cornerStyle: "rounded",
4965
4710
  textTransform: "uppercase",
4966
4711
  fontWeight: 600,
4967
- borderWidth: 1,
4968
4712
  hoverTransform: "none",
4969
4713
  hoverColor: "none",
4970
4714
  letterSpacing: "loose"
@@ -5022,7 +4766,7 @@ const inkStampRecipe = defineStaticButtonStyleRecipe({
5022
4766
  border: { widthClass: "border-2" },
5023
4767
  effects: { hover: [{
5024
4768
  effectId: "background-on-hover",
5025
- options: { colorToken: "surface" }
4769
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surface") }
5026
4770
  }] }
5027
4771
  }
5028
4772
  },
@@ -5037,7 +4781,7 @@ const inkStampRecipe = defineStaticButtonStyleRecipe({
5037
4781
  border: { widthClass: "border-2" },
5038
4782
  effects: { hover: [{
5039
4783
  effectId: "background-on-hover",
5040
- options: { colorToken: "surface" }
4784
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surface") }
5041
4785
  }] }
5042
4786
  }
5043
4787
  },
@@ -5071,7 +4815,6 @@ const inkStampRecipe = defineStaticButtonStyleRecipe({
5071
4815
  effectId: "border-bottom-grow",
5072
4816
  options: {
5073
4817
  height: 1,
5074
- colorToken: "accent",
5075
4818
  origin: "left"
5076
4819
  }
5077
4820
  }] }
@@ -5102,7 +4845,6 @@ const flatInkRecipe = defineStaticButtonStyleRecipe({
5102
4845
  cornerStyle: "rounded",
5103
4846
  textTransform: "none",
5104
4847
  fontWeight: 600,
5105
- borderWidth: 1,
5106
4848
  typography: "body",
5107
4849
  letterSpacing: "tight",
5108
4850
  paddingPreset: "default",
@@ -5134,12 +4876,9 @@ const flatInkRecipe = defineStaticButtonStyleRecipe({
5134
4876
  },
5135
4877
  borderRadius: "rounded-lg",
5136
4878
  affordance: { iconId: "ArrowRight" },
5137
- effects: { hover: [{
5138
- effectId: "lift",
5139
- options: { translateY: "-2px" }
5140
- }, {
4879
+ effects: { hover: [{ effectId: "lift" }, {
5141
4880
  effectId: "background-on-hover",
5142
- options: { colorToken: "secondary" }
4881
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("secondary") }
5143
4882
  }] }
5144
4883
  }
5145
4884
  },
@@ -5152,12 +4891,9 @@ const flatInkRecipe = defineStaticButtonStyleRecipe({
5152
4891
  },
5153
4892
  borderRadius: "rounded-lg",
5154
4893
  border: { widthClass: "border" },
5155
- effects: { hover: [{
5156
- effectId: "lift",
5157
- options: { translateY: "-2px" }
5158
- }, {
4894
+ effects: { hover: [{ effectId: "lift" }, {
5159
4895
  effectId: "background-on-hover",
5160
- options: { colorToken: "surfaceAlt" }
4896
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surfaceAlt") }
5161
4897
  }] }
5162
4898
  }
5163
4899
  },
@@ -5170,12 +4906,9 @@ const flatInkRecipe = defineStaticButtonStyleRecipe({
5170
4906
  },
5171
4907
  borderRadius: "rounded-lg",
5172
4908
  border: { widthClass: "border" },
5173
- effects: { hover: [{
5174
- effectId: "lift",
5175
- options: { translateY: "-2px" }
5176
- }, {
4909
+ effects: { hover: [{ effectId: "lift" }, {
5177
4910
  effectId: "background-on-hover",
5178
- options: { colorToken: "surfaceAlt" }
4911
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surfaceAlt") }
5179
4912
  }] }
5180
4913
  }
5181
4914
  },
@@ -5187,10 +4920,7 @@ const flatInkRecipe = defineStaticButtonStyleRecipe({
5187
4920
  role: "link"
5188
4921
  },
5189
4922
  borderRadius: "rounded-lg",
5190
- effects: { hover: [{
5191
- effectId: "lift",
5192
- options: { translateY: "-2px" }
5193
- }] }
4923
+ effects: { hover: [{ effectId: "lift" }] }
5194
4924
  }
5195
4925
  },
5196
4926
  accent: {
@@ -5202,10 +4932,7 @@ const flatInkRecipe = defineStaticButtonStyleRecipe({
5202
4932
  },
5203
4933
  borderRadius: "rounded-lg",
5204
4934
  affordance: { iconId: "ArrowRight" },
5205
- effects: { hover: [{
5206
- effectId: "lift",
5207
- options: { translateY: "-2px" }
5208
- }] }
4935
+ effects: { hover: [{ effectId: "lift" }] }
5209
4936
  }
5210
4937
  }
5211
4938
  }
@@ -5226,9 +4953,8 @@ const showtimePillRecipe = defineStaticButtonStyleRecipe({
5226
4953
  shadow: "low",
5227
4954
  textTransform: "uppercase",
5228
4955
  fontWeight: 700,
5229
- borderWidth: 2,
5230
4956
  hoverTransform: "lift",
5231
- hoverColor: "darken",
4957
+ hoverColor: "none",
5232
4958
  typography: "body",
5233
4959
  paddingPreset: "spacious",
5234
4960
  italic: false
@@ -5286,7 +5012,7 @@ const showtimePillRecipe = defineStaticButtonStyleRecipe({
5286
5012
  border: { widthClass: "border-2" },
5287
5013
  effects: { hover: [{
5288
5014
  effectId: "background-on-hover",
5289
- options: { colorToken: "background" }
5015
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("background") }
5290
5016
  }] }
5291
5017
  }
5292
5018
  },
@@ -5300,7 +5026,7 @@ const showtimePillRecipe = defineStaticButtonStyleRecipe({
5300
5026
  borderRadius: "rounded-full",
5301
5027
  effects: { hover: [{
5302
5028
  effectId: "background-on-hover",
5303
- options: { colorToken: "surface" }
5029
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surface") }
5304
5030
  }] }
5305
5031
  }
5306
5032
  },
@@ -5335,7 +5061,6 @@ const joyStampRecipe = defineStaticButtonStyleRecipe({
5335
5061
  typography: "heading",
5336
5062
  fontWeight: 700,
5337
5063
  fontSize: "text-lg",
5338
- borderWidth: 2,
5339
5064
  hoverTransform: "none",
5340
5065
  hoverColor: "none"
5341
5066
  },
@@ -5370,7 +5095,7 @@ const joyStampRecipe = defineStaticButtonStyleRecipe({
5370
5095
  elevation: "high",
5371
5096
  softness: "hard",
5372
5097
  position: "bottom-right",
5373
- colorToken: "text"
5098
+ colorToken: unsafeAsOpaqueButtonColourToken("text")
5374
5099
  },
5375
5100
  effects: { hover: [{ effectId: "press-down" }] }
5376
5101
  }
@@ -5388,7 +5113,7 @@ const joyStampRecipe = defineStaticButtonStyleRecipe({
5388
5113
  elevation: "high",
5389
5114
  softness: "hard",
5390
5115
  position: "bottom-right",
5391
- colorToken: "secondary"
5116
+ colorToken: unsafeAsOpaqueButtonColourToken("secondary")
5392
5117
  },
5393
5118
  effects: { hover: [{ effectId: "press-down" }] }
5394
5119
  }
@@ -5433,7 +5158,6 @@ const ornateRitualRecipe = defineStaticButtonStyleRecipe({
5433
5158
  cornerStyle: "rounded",
5434
5159
  textTransform: "uppercase",
5435
5160
  fontWeight: 600,
5436
- borderWidth: 1,
5437
5161
  hoverTransform: "none",
5438
5162
  hoverColor: "none",
5439
5163
  letterSpacing: "loose"
@@ -5469,7 +5193,7 @@ const ornateRitualRecipe = defineStaticButtonStyleRecipe({
5469
5193
  effects: {
5470
5194
  hover: [{
5471
5195
  effectId: "background-on-hover",
5472
- options: { colorToken: "primary-100" }
5196
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("primary-100") }
5473
5197
  }],
5474
5198
  active: [{
5475
5199
  effectId: "scale-down",
@@ -5489,7 +5213,7 @@ const ornateRitualRecipe = defineStaticButtonStyleRecipe({
5489
5213
  border: { widthClass: "border" },
5490
5214
  effects: { hover: [{
5491
5215
  effectId: "background-on-hover",
5492
- options: { colorToken: "surface" }
5216
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("surface") }
5493
5217
  }] }
5494
5218
  }
5495
5219
  },
@@ -5504,7 +5228,7 @@ const ornateRitualRecipe = defineStaticButtonStyleRecipe({
5504
5228
  border: { widthClass: "border" },
5505
5229
  effects: { hover: [{
5506
5230
  effectId: "background-on-hover",
5507
- options: { colorToken: "muted" }
5231
+ options: { colorToken: unsafeAsOpaqueButtonColourToken("muted") }
5508
5232
  }] }
5509
5233
  }
5510
5234
  },
@@ -5538,7 +5262,6 @@ const ornateRitualRecipe = defineStaticButtonStyleRecipe({
5538
5262
  effectId: "border-bottom-grow",
5539
5263
  options: {
5540
5264
  height: 1,
5541
- colorToken: "accent",
5542
5265
  origin: "left"
5543
5266
  }
5544
5267
  }] }
@@ -6647,6 +6370,102 @@ new Set(themeV2NormalEditorRawStyleFieldNames);
6647
6370
  const pageDesignEditorBackgroundOverrideOwner = "page-design-editor";
6648
6371
  const siteChromeBackgroundOverrideOwner = "site-chrome-editor";
6649
6372
  //#endregion
6373
+ //#region ../theme-core/src/utils/colorStyles.ts
6374
+ const COLOR_VAR_PREFIX = "--tb-";
6375
+ function parseToken(source) {
6376
+ const parts = parseColorTokenParts(source);
6377
+ if (parts.kind === "raw") return {
6378
+ token: source,
6379
+ raw: parts.value
6380
+ };
6381
+ if (parts.kind === "invalid") return { token: source };
6382
+ return {
6383
+ token: parts.token,
6384
+ opacityPercent: parts.opacityPercent === null ? void 0 : parts.opacityPercent
6385
+ };
6386
+ }
6387
+ const SURFACE_TEXT_ROLE_BY_TOKEN = {
6388
+ text: "text",
6389
+ heading: "heading",
6390
+ mutedText: "supporting"
6391
+ };
6392
+ function surfaceRoleForTextToken(token) {
6393
+ return Object.prototype.hasOwnProperty.call(SURFACE_TEXT_ROLE_BY_TOKEN, token) ? SURFACE_TEXT_ROLE_BY_TOKEN[token] : null;
6394
+ }
6395
+ /**
6396
+ * Converts a theme color token to a CSS rgb value.
6397
+ * This is the primary function for applying theme colors to CSS properties.
6398
+ *
6399
+ * @param token - Theme color token (semantic, with opacity, or raw)
6400
+ * @returns CSS color value (rgb with optional alpha, or raw CSS value)
6401
+ *
6402
+ * @example
6403
+ * rgbColorValue('primary') // => 'rgb(var(--tb-primary))'
6404
+ * rgbColorValue('surface/95') // => 'rgb(var(--tb-surface) / 0.95)'
6405
+ * rgbColorValue('raw:transparent') // => 'transparent'
6406
+ */
6407
+ function rgbColorValue(token) {
6408
+ const { token: baseToken, opacityPercent, raw } = parseToken(token);
6409
+ if (raw) return raw;
6410
+ const cssVar = `${COLOR_VAR_PREFIX}${baseToken}`;
6411
+ if (opacityPercent === void 0) return `rgb(var(${cssVar}))`;
6412
+ return `rgb(var(${cssVar}) / ${opacityPercent / 100})`;
6413
+ }
6414
+ /**
6415
+ * Creates a backgroundColor style object from a theme token.
6416
+ *
6417
+ * @param token - Theme color token
6418
+ * @returns CSSProperties with backgroundColor
6419
+ */
6420
+ function backgroundColorStyle(token) {
6421
+ return { backgroundColor: rgbColorValue(token) };
6422
+ }
6423
+ /**
6424
+ * Creates a text color style object from a theme token.
6425
+ *
6426
+ * @param token - Theme color token
6427
+ * @returns CSSProperties with color
6428
+ */
6429
+ function textColorStyle(token) {
6430
+ const parsed = parseToken(token);
6431
+ const surfaceRole = parsed.raw ? null : surfaceRoleForTextToken(parsed.token);
6432
+ if (surfaceRole) return { color: parsed.opacityPercent === void 0 ? surfaceForegroundValue(surfaceRole) : surfaceForegroundValueWithOpacity(surfaceRole, parsed.opacityPercent) };
6433
+ return { color: rgbColorValue(token) };
6434
+ }
6435
+ /**
6436
+ * Creates a border color style object from a theme token.
6437
+ *
6438
+ * @param token - Theme color token
6439
+ * @returns CSSProperties with borderColor
6440
+ */
6441
+ function borderColorStyle(token) {
6442
+ return { borderColor: rgbColorValue(token) };
6443
+ }
6444
+ /**
6445
+ * Merges multiple CSSProperties objects into a single object.
6446
+ * Later styles override earlier ones. Undefined values are filtered out.
6447
+ * Returns undefined if the merged result is empty.
6448
+ *
6449
+ * @param styles - Variable number of CSSProperties objects (can be undefined)
6450
+ * @returns Merged CSSProperties object, or undefined if empty
6451
+ *
6452
+ * @example
6453
+ * mergeStyles(
6454
+ * backgroundColorStyle('surface'),
6455
+ * textColorStyle('text'),
6456
+ * borderColorStyle('border')
6457
+ * )
6458
+ * // => { backgroundColor: '...', color: '...', borderColor: '...' }
6459
+ */
6460
+ function mergeStyles(...styles) {
6461
+ const merged = {};
6462
+ for (const style of styles) {
6463
+ if (!style) continue;
6464
+ Object.assign(merged, style);
6465
+ }
6466
+ return Object.keys(merged).length ? merged : void 0;
6467
+ }
6468
+ //#endregion
6650
6469
  //#region ../theme-core/src/utils/tokenOrColor.ts
6651
6470
  /**
6652
6471
  * Runtime color-reference fields intentionally accept any string, including
@@ -13546,6 +13365,7 @@ const DISPLAY_MEDIA_KINDS = [
13546
13365
  "video",
13547
13366
  "audio"
13548
13367
  ];
13368
+ const DEFAULT_MEDIA_FIELD_KINDS = ["image"];
13549
13369
  const PUBLIC_FILE_FIELD_KINDS = [
13550
13370
  "document",
13551
13371
  "spreadsheet",
@@ -13746,18 +13566,28 @@ const inlineTextFieldSchema = baseFieldSchema.extend({
13746
13566
  maxLength: z$1.number().int().positive().optional(),
13747
13567
  plainTextField: z$1.string().min(1).optional()
13748
13568
  });
13569
+ function hasMediaDefaultIdentifier(value) {
13570
+ return value !== null && typeof value === "object" && !Array.isArray(value) && typeof value.identifier === "string" && value.identifier.trim().length > 0;
13571
+ }
13572
+ function validateMediaFieldDefault(field, ctx) {
13573
+ if (field.defaultValue !== void 0 && field.defaultValue !== null && !hasMediaDefaultIdentifier(field.defaultValue)) ctx.addIssue({
13574
+ code: z$1.ZodIssueCode.custom,
13575
+ path: ["defaultValue"],
13576
+ message: `${field.type} defaultValue must be null or an object with a non-empty identifier`
13577
+ });
13578
+ }
13749
13579
  const mediaFieldSchema = baseFieldSchema.extend({
13750
13580
  type: z$1.literal("media"),
13751
- mediaKinds: z$1.array(z$1.enum(MEDIA_KINDS)).default(["image"]).transform((kinds) => {
13581
+ mediaKinds: z$1.array(z$1.enum(MEDIA_KINDS)).default([...DEFAULT_MEDIA_FIELD_KINDS]).transform((kinds) => {
13752
13582
  const displayKinds = kinds.filter(isDisplayMediaKind);
13753
- return displayKinds.length > 0 ? displayKinds : ["image"];
13583
+ return displayKinds.length > 0 ? displayKinds : [...DEFAULT_MEDIA_FIELD_KINDS];
13754
13584
  }),
13755
13585
  aspectRatio: z$1.string().optional()
13756
- });
13586
+ }).superRefine(validateMediaFieldDefault);
13757
13587
  const fileFieldSchema = baseFieldSchema.extend({
13758
13588
  type: z$1.literal("file"),
13759
13589
  fileKinds: z$1.array(z$1.enum(PUBLIC_FILE_FIELD_KINDS)).default([...PUBLIC_FILE_FIELD_KINDS])
13760
- });
13590
+ }).superRefine(validateMediaFieldDefault);
13761
13591
  const booleanFieldSchema = baseFieldSchema.extend({ type: z$1.literal("boolean") });
13762
13592
  const dateFieldSchema = baseFieldSchema.extend({ type: z$1.literal("date") });
13763
13593
  const timeFieldSchema = baseFieldSchema.extend({ type: z$1.literal("time") });
@@ -22042,20 +21872,10 @@ function visitRichTextNode(node, allowedTokens, tokenValues) {
22042
21872
  }
22043
21873
  function interpolateRichTextTokens(value, options, context) {
22044
21874
  if (!isRecord$6(value)) return value;
22045
- const allowedTokens = new Set(options.tokens);
22046
- const tokenValues = {
21875
+ return visitRichTextNode(value, new Set(options.tokens), {
22047
21876
  year: String((/* @__PURE__ */ new Date()).getFullYear()),
22048
21877
  site_name: getSiteName(context)
22049
- };
22050
- if (isRecord$6(value.doc)) {
22051
- const nextDoc = visitRichTextNode(value.doc, allowedTokens, tokenValues);
22052
- if (nextDoc === value.doc) return value;
22053
- return {
22054
- ...value,
22055
- doc: nextDoc
22056
- };
22057
- }
22058
- return visitRichTextNode(value, allowedTokens, tokenValues);
21878
+ });
22059
21879
  }
22060
21880
  const contentTransforms = [{
22061
21881
  id: "content.interpolateRichTextTokens",
@@ -24438,11 +24258,8 @@ const mediaSchema = z.discriminatedUnion("type", [
24438
24258
  * This module provides a single source of truth for TipTap rich text validation
24439
24259
  * across both the block-form editor and the block rendering system.
24440
24260
  *
24441
- * Format compatibility:
24442
- * - Unwrapped format (new): { type: 'doc', content: [...] }
24443
- * - Wrapped format (legacy): { doc: { type: 'doc', content: [...] } }
24444
- *
24445
- * Both formats are supported for backward compatibility during migration.
24261
+ * Rich-text fields use one canonical root shape:
24262
+ * `{ type: 'doc', content: [...] }`.
24446
24263
  */
24447
24264
  /**
24448
24265
  * TipTap document node schema (recursive structure)
@@ -24455,17 +24272,40 @@ const mediaSchema = z.discriminatedUnion("type", [
24455
24272
  * - marks: Text formatting marks (e.g., bold, italic)
24456
24273
  */
24457
24274
  const TipTapMarkSchema = z$1.object({
24458
- type: z$1.string(),
24275
+ type: z$1.string().min(1),
24459
24276
  attrs: z$1.record(z$1.string(), z$1.unknown()).optional()
24460
- });
24277
+ }).strict();
24461
24278
  const TipTapNodeSchema = z$1.lazy(() => z$1.object({
24462
- type: z$1.string(),
24279
+ type: z$1.string().min(1),
24463
24280
  content: z$1.array(TipTapNodeSchema).optional(),
24464
24281
  text: z$1.string().optional(),
24465
24282
  attrs: z$1.record(z$1.string(), z$1.unknown()).optional(),
24466
24283
  marks: z$1.array(TipTapMarkSchema).optional()
24284
+ }).strict().superRefine((node, ctx) => {
24285
+ if (node.type === "doc") ctx.addIssue({
24286
+ code: "custom",
24287
+ path: ["type"],
24288
+ message: "Document nodes are only valid at the rich-text root"
24289
+ });
24290
+ if (node.type === "text") {
24291
+ if (node.text === void 0 || node.text.length === 0) ctx.addIssue({
24292
+ code: "custom",
24293
+ path: ["text"],
24294
+ message: "Text nodes require a non-empty text value"
24295
+ });
24296
+ if (node.content !== void 0) ctx.addIssue({
24297
+ code: "custom",
24298
+ path: ["content"],
24299
+ message: "Text nodes cannot contain child nodes"
24300
+ });
24301
+ return;
24302
+ }
24303
+ if (node.text !== void 0) ctx.addIssue({
24304
+ code: "custom",
24305
+ path: ["text"],
24306
+ message: "Only text nodes can contain a text value"
24307
+ });
24467
24308
  }));
24468
- z$1.union([TipTapNodeSchema, z$1.object({ doc: TipTapNodeSchema })]);
24469
24309
  /**
24470
24310
  * Canonical schema for a TipTap rich-text document root.
24471
24311
  *
@@ -24474,13 +24314,11 @@ z$1.union([TipTapNodeSchema, z$1.object({ doc: TipTapNodeSchema })]);
24474
24314
  * (dummy content, editor output, migrations) must emit, and the shape every
24475
24315
  * non-legacy consumer can rely on.
24476
24316
  *
24477
- * Legacy envelopes are read-tolerated by {@link RichTextValueSchema} but
24478
- * normalised before reaching anywhere typed as `RichTextDoc`.
24479
24317
  */
24480
24318
  const RichTextDocSchema = z$1.object({
24481
24319
  type: z$1.literal("doc"),
24482
24320
  content: z$1.array(TipTapNodeSchema)
24483
- });
24321
+ }).strict();
24484
24322
  //#endregion
24485
24323
  //#region ../blocks/src/system/blocks/shared/bookingPaymentTerms.ts
24486
24324
  const bookingDepositRefundPolicySchema = z$1.enum(["refundable", "non_refundable"]);
@@ -35158,6 +34996,7 @@ const CANONICAL_REFUND_PLANNER_ERROR_CODES = [
35158
34996
  "idempotency_amount_mismatch",
35159
34997
  "idempotency_method_mismatch",
35160
34998
  "idempotency_receipt_mismatch",
34999
+ "idempotency_scope_mismatch",
35161
35000
  "refund_in_progress"
35162
35001
  ],
35163
35002
  "invalid_amount",
@@ -35544,7 +35383,7 @@ const SITE_BANNER_TONE_VALUES = [
35544
35383
  ];
35545
35384
  const siteBannerScopeSchema = z$1.enum(SITE_BANNER_SCOPE_VALUES);
35546
35385
  const siteBannerToneSchema = z$1.enum(SITE_BANNER_TONE_VALUES);
35547
- const siteBannerBodySchema = z$1.unknown().transform(unwrapRichTextValue);
35386
+ const siteBannerBodySchema = RichTextDocSchema;
35548
35387
  const siteBannerCtaSchema = z$1.object({
35549
35388
  label: z$1.string().trim().min(1),
35550
35389
  link: linkPayloadSchema
@@ -35572,7 +35411,8 @@ const EMPTY_SITE_BANNER_BODY = {
35572
35411
  }]
35573
35412
  };
35574
35413
  function analyzeSiteBannerBody(body) {
35575
- const sanitizedBody = sanitizeSiteBannerBodyInternal(body, { limitParagraphs: false });
35414
+ const parsed = RichTextDocSchema.safeParse(body);
35415
+ const sanitizedBody = parsed.success ? sanitizeSiteBannerBodyInternal(parsed.data, { limitParagraphs: false }) : EMPTY_SITE_BANNER_BODY;
35576
35416
  const paragraphs = collectParagraphs(sanitizedBody);
35577
35417
  const textLength = paragraphs.reduce((total, paragraph) => total + paragraphTextLength(paragraph), 0);
35578
35418
  const issues = [];
@@ -35594,7 +35434,7 @@ function siteBannerBodyIssueMessage(issue) {
35594
35434
  }
35595
35435
  }
35596
35436
  function sanitizeSiteBannerBodyInternal(input, options) {
35597
- const content = normalizeTopLevelNodes(unwrapRichTextValue(input).content ?? [], options);
35437
+ const content = normalizeTopLevelNodes(input.content, options);
35598
35438
  return {
35599
35439
  type: "doc",
35600
35440
  content: content.length > 0 ? content : EMPTY_SITE_BANNER_BODY.content
@@ -35675,28 +35515,6 @@ function sanitizeMarks(marks) {
35675
35515
  });
35676
35516
  return sanitized.length > 0 ? sanitized : void 0;
35677
35517
  }
35678
- function unwrapRichTextValue(value) {
35679
- if (isRecord(value) && isRecord(value.doc)) return unwrapRichTextValue(value.doc);
35680
- if (isRecord(value) && value.type === "doc") return {
35681
- type: "doc",
35682
- content: Array.isArray(value.content) ? value.content.filter(isTipTapNodeLike).map(coerceTipTapNode) : []
35683
- };
35684
- return EMPTY_SITE_BANNER_BODY;
35685
- }
35686
- function isTipTapNodeLike(value) {
35687
- return isRecord(value) && typeof value.type === "string";
35688
- }
35689
- function coerceTipTapNode(value) {
35690
- return {
35691
- type: value.type,
35692
- ...Array.isArray(value.content) ? { content: value.content.filter(isTipTapNodeLike).map(coerceTipTapNode) } : {},
35693
- ...typeof value.text === "string" ? { text: value.text } : {},
35694
- ...Array.isArray(value.marks) ? { marks: value.marks.filter((mark) => isRecord(mark) && typeof mark.type === "string").map((mark) => ({
35695
- type: mark.type,
35696
- ...isRecord(mark.attrs) ? { attrs: mark.attrs } : {}
35697
- })) } : {}
35698
- };
35699
- }
35700
35518
  function paragraphTextLength(paragraph) {
35701
35519
  return collectText(paragraph).length;
35702
35520
  }