@riverbankcms/sdk 0.108.0 → 0.109.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 (189) hide show
  1. package/README.md +21 -1
  2. package/dist/{PreviewEditorSidebar-BBT-kZAM.mjs → PreviewEditorSidebar-DWqwfy3_.mjs} +7 -22
  3. package/dist/{PreviewEditorUI-D69xNKT2.mjs → PreviewEditorUI-B7OL4sfR.mjs} +3 -3
  4. package/dist/{PreviewQueryProvider-RRu7wyQ5.mjs → PreviewQueryProvider-D0y2l8JN.mjs} +1 -1
  5. package/dist/{SdkPreviewModeRuntime-CuDjXH6o.mjs → SdkPreviewModeRuntime-D8Gt9Gbe.mjs} +212 -153
  6. package/dist/{SiteChromeCustomizeContext-BQUY2dEk.mjs → SiteChromeCustomizeContext-DUpalEdL.mjs} +1919 -1032
  7. package/dist/_dts/ai/src/contracts/proposals.d.ts +11244 -10741
  8. package/dist/_dts/api/src/bookingAdjustments.d.ts +5 -0
  9. package/dist/_dts/api/src/bookingOperations.d.ts +4 -0
  10. package/dist/_dts/api/src/bookingRecords.d.ts +2 -17
  11. package/dist/_dts/api/src/bookingRefundOutcomes.d.ts +6 -6
  12. package/dist/_dts/api/src/common/envelope.d.ts +7 -0
  13. package/dist/_dts/api/src/courses.d.ts +1 -0
  14. package/dist/_dts/api/src/customerMembershipOutcomes.d.ts +5 -5
  15. package/dist/_dts/api/src/endpoints.d.ts +35 -0
  16. package/dist/_dts/api/src/index.d.ts +2 -2
  17. package/dist/_dts/api/src/participantMessaging.d.ts +18 -12
  18. package/dist/_dts/api/src/publicExperienceEndpoints.d.ts +1 -0
  19. package/dist/_dts/api/src/sdkContracts.d.ts +247 -1
  20. package/dist/_dts/api/src/siteInfrastructure.d.ts +13 -0
  21. package/dist/_dts/api/src/siteManagementEndpoints.d.ts +1 -5
  22. package/dist/_dts/api/src/sitePlatformEndpoints.d.ts +29 -1
  23. package/dist/_dts/api/src/siteRuntimeEndpoints.d.ts +33 -27
  24. package/dist/_dts/block-form/src/widgets/BackgroundGradientWidget/BackgroundGradientField.d.ts +9 -0
  25. package/dist/_dts/block-form/src/widgets/BackgroundGradientWidget/BackgroundGradientWidget.d.ts +3 -4
  26. package/dist/_dts/blocks/src/contracts/proof-block-islands.d.ts +4 -4
  27. package/dist/_dts/blocks/src/index.d.ts +1 -1
  28. package/dist/_dts/blocks/src/system/blocks/audio-player.d.ts +3 -0
  29. package/dist/_dts/blocks/src/system/blocks/body-text.d.ts +3 -0
  30. package/dist/_dts/blocks/src/system/blocks/contact-newsletter.d.ts +3 -0
  31. package/dist/_dts/blocks/src/system/blocks/course-registration.d.ts +1 -22
  32. package/dist/_dts/blocks/src/system/blocks/cta-full.d.ts +3 -0
  33. package/dist/_dts/blocks/src/system/blocks/event-registration.d.ts +1 -22
  34. package/dist/_dts/blocks/src/system/blocks/file-download.d.ts +3 -0
  35. package/dist/_dts/blocks/src/system/blocks/form.d.ts +3 -0
  36. package/dist/_dts/blocks/src/system/blocks/image-gallery.d.ts +3 -0
  37. package/dist/_dts/blocks/src/system/blocks/media-text.d.ts +3 -0
  38. package/dist/_dts/blocks/src/system/blocks/newsletter-signup.d.ts +3 -0
  39. package/dist/_dts/blocks/src/system/blocks/site-header.d.ts +3 -0
  40. package/dist/_dts/blocks/src/system/blocks/team-members.d.ts +3 -0
  41. package/dist/_dts/blocks/src/system/blocks/testimonials.d.ts +3 -0
  42. package/dist/_dts/blocks/src/system/blocks/video-grid.d.ts +3 -0
  43. package/dist/_dts/blocks/src/system/constants/background.d.ts +1 -1
  44. package/dist/_dts/blocks/src/system/customize/backgrounds.d.ts +16 -6
  45. package/dist/_dts/blocks/src/system/defineBlock.d.ts +9 -1
  46. package/dist/_dts/blocks/src/system/fields/ctas.d.ts +8 -0
  47. package/dist/_dts/blocks/src/system/manifest/schema.d.ts +31 -0
  48. package/dist/_dts/blocks/src/system/runtime/components/registry.client.d.ts +6 -6
  49. package/dist/_dts/blocks/src/system/runtime/components/runtime-backed-blocks.d.ts +3 -3
  50. package/dist/_dts/blocks/src/system/runtime/nodes/shared/contract-schemas.d.ts +1 -1
  51. package/dist/_dts/content-model/src/content-types/entryValidation.d.ts +31 -0
  52. package/dist/_dts/content-model/src/content-types/scaffold.d.ts +58 -0
  53. package/dist/_dts/content-model/src/content-types/sentinels.d.ts +36 -0
  54. package/dist/_dts/content-model/src/index.d.ts +3 -0
  55. package/dist/_dts/core/src/booking-date-time.d.ts +8 -0
  56. package/dist/_dts/db/src/generated/supabase/database.types.d.ts +3071 -3157
  57. package/dist/_dts/media-core/src/fileMimeDetection.d.ts +16 -0
  58. package/dist/_dts/media-core/src/fileStorage.d.ts +8 -0
  59. package/dist/_dts/media-core/src/storagePathDomain.d.ts +2 -0
  60. package/dist/_dts/media-core/src/uploadVerificationContract.d.ts +3 -0
  61. package/dist/_dts/preview-next/src/client/blocks/BlockToolbar.d.ts +2 -0
  62. package/dist/_dts/preview-next/src/client/preview/StyleConfigurator.state.d.ts +1 -0
  63. package/dist/_dts/preview-next/src/client/preview/styleConfiguratorApplyPayload.d.ts +1 -1
  64. package/dist/_dts/sdk/src/cli/commands/audit.d.ts +1 -1
  65. package/dist/_dts/sdk/src/cli/commands/compare.d.ts +1 -1
  66. package/dist/_dts/sdk/src/cli/commands/deploy.d.ts +1 -1
  67. package/dist/_dts/sdk/src/cli/commands/drafts.d.ts +18 -0
  68. package/dist/_dts/sdk/src/cli/commands/entry.d.ts +15 -0
  69. package/dist/_dts/sdk/src/cli/commands/init-docs.d.ts +2 -2
  70. package/dist/_dts/sdk/src/cli/commands/publish-all.d.ts +1 -1
  71. package/dist/_dts/sdk/src/cli/commands/pull.d.ts +1 -0
  72. package/dist/_dts/sdk/src/cli/commands/push/execute/diff.d.ts +1 -1
  73. package/dist/_dts/sdk/src/cli/commands/push/options.d.ts +3 -0
  74. package/dist/_dts/sdk/src/cli/commands/push-execute.d.ts +12 -1
  75. package/dist/_dts/sdk/src/cli/commands/setup.d.ts +1 -0
  76. package/dist/_dts/sdk/src/cli/commands/verify.d.ts +1 -0
  77. package/dist/_dts/sdk/src/cli/helpers.d.ts +22 -1
  78. package/dist/_dts/sdk/src/cli/index.d.ts +4 -0
  79. package/dist/_dts/sdk/src/cli/output.d.ts +88 -0
  80. package/dist/_dts/sdk/src/cli/program.d.ts +29 -0
  81. package/dist/_dts/sdk/src/cli/push-config.d.ts +1 -1
  82. package/dist/_dts/sdk/src/client/management/catalog.d.ts +10 -0
  83. package/dist/_dts/sdk/src/client/management/http.d.ts +7 -1
  84. package/dist/_dts/sdk/src/client/management/index.d.ts +1 -1
  85. package/dist/_dts/sdk/src/client/management/types.d.ts +43 -19
  86. package/dist/_dts/sdk/src/date-time/index.d.ts +68 -0
  87. package/dist/_dts/sdk/src/public-api/contracts.d.ts +2 -0
  88. package/dist/_dts/sdk/src/version.d.ts +1 -1
  89. package/dist/_dts/site-commands/src/commands.d.ts +893 -823
  90. package/dist/_dts/theme-core/src/accordions/types.d.ts +1 -1
  91. package/dist/_dts/theme-core/src/buttons/core.d.ts +15 -46
  92. package/dist/_dts/theme-core/src/buttons/effectClassification.d.ts +147 -0
  93. package/dist/_dts/theme-core/src/buttons/effects/types.d.ts +2 -3
  94. package/dist/_dts/theme-core/src/buttons/generateDefaultButtonSystem.d.ts +1 -1
  95. package/dist/_dts/theme-core/src/buttons/index.d.ts +1 -0
  96. package/dist/_dts/theme-core/src/buttons/personalities/types.d.ts +44 -32
  97. package/dist/_dts/theme-core/src/buttons/presets.d.ts +4 -25
  98. package/dist/_dts/theme-core/src/buttons/resolveButtonColourStates.d.ts +100 -0
  99. package/dist/_dts/theme-core/src/buttons/resolvedButtonCss.d.ts +16 -0
  100. package/dist/_dts/theme-core/src/buttons/types.d.ts +101 -83
  101. package/dist/_dts/theme-core/src/cards/types.d.ts +16 -16
  102. package/dist/_dts/theme-core/src/generated/containerResponsiveThemeCss.d.ts +1 -1
  103. package/dist/_dts/theme-core/src/gradients/presets.d.ts +200 -8
  104. package/dist/_dts/theme-core/src/gradients/utils.d.ts +6 -2
  105. package/dist/_dts/theme-core/src/mock-themes/all.d.ts +87 -126
  106. package/dist/_dts/theme-core/src/mock-themes/modern-minimal.d.ts +1 -1
  107. package/dist/_dts/theme-core/src/navigation/types.d.ts +2 -2
  108. package/dist/_dts/theme-core/src/palette/curated/index.d.ts +2 -2
  109. package/dist/_dts/theme-core/src/palette/curated/types.d.ts +5 -8
  110. package/dist/_dts/theme-core/src/palette/index.d.ts +0 -1
  111. package/dist/_dts/theme-core/src/schema.d.ts +112 -138
  112. package/dist/_dts/theme-core/src/site-styles/backgroundAppearance.d.ts +2 -2
  113. package/dist/_dts/theme-core/src/site-styles/designState.d.ts +10 -10
  114. package/dist/_dts/theme-core/src/site-styles/pageDesignEditorModel.d.ts +3 -2
  115. package/dist/_dts/theme-core/src/site-styles/pageDesignIntent.d.ts +13 -6
  116. package/dist/_dts/theme-core/src/site-styles/runtimeCompiler.d.ts +29 -8
  117. package/dist/_dts/theme-core/src/site-styles/styleTags.d.ts +2 -2
  118. package/dist/cli/index.mjs +67956 -66745
  119. package/dist/cli/init-docs/content/cli-reference.md +50 -7
  120. package/dist/cli/init-docs/content/content-management.md +7 -4
  121. package/dist/cli/init-docs/content/workflow-publish.md +5 -1
  122. package/dist/client/{DiscountCodeDisclosure-D6TOf6Hi.mjs → DiscountCodeDisclosure-DU1ygxU2.mjs} +1 -1
  123. package/dist/client/{EventCombined.client-Dao3zxRk.mjs → EventCombined.client-DB5zagCo.mjs} +3 -3
  124. package/dist/client/{EventListing.client-B2NNt4y1.mjs → EventListing.client-CTX9JHBL.mjs} +2 -2
  125. package/dist/client/{LeafletStaticMap-BhwFo16w.mjs → LeafletStaticMap-BYImhgiB.mjs} +1 -1
  126. package/dist/client/{MagicLinkForm-BWnB7cMR.mjs → MagicLinkForm-CRkw_M3l.mjs} +2 -2
  127. package/dist/client/{StepIndicator-TzRiQ0BY.mjs → StepIndicator-BnmVBJJh.mjs} +2 -2
  128. package/dist/client/{accordion-BPy-AJ4_.mjs → accordion-CeGreumd.mjs} +1 -1
  129. package/dist/client/{bookingForm-BL4PGZds.mjs → bookingForm-CSzFNrpN.mjs} +6 -6
  130. package/dist/client/bookings.mjs +512 -252
  131. package/dist/client/{buttons-EBjyslaX.mjs → buttons-DoFV7KDL.mjs} +493 -230
  132. package/dist/client/{carousel-C2b7Cn9-.mjs → carousel-B2jDtogf.mjs} +1 -1
  133. package/dist/client/{cart-BQcbXIVD.mjs → cart-D-jZ-vaY.mjs} +3 -3
  134. package/dist/client/{checkout-DEmpGRJu.mjs → checkout-Dza-LA7N.mjs} +3 -3
  135. package/dist/client/client.mjs +1673 -785
  136. package/dist/client/{colorStyles-jZS6KfkP.mjs → colorStyles-CrgzoXsm.mjs} +1 -30
  137. package/dist/client/{courseRegistration-BqRZPmsq.mjs → courseRegistration-TYkNychb.mjs} +7 -7
  138. package/dist/client/{eventCalendar-B8N_tSl5.mjs → eventCalendar-BI_90SsT.mjs} +5 -5
  139. package/dist/client/{eventCombined-Gjn6gtq7.mjs → eventCombined-mNrpryE9.mjs} +2 -2
  140. package/dist/client/{eventDetails-M-VCxA-r.mjs → eventDetails-D4GVlCIY.mjs} +3 -3
  141. package/dist/client/{eventListing-DR19hqYi.mjs → eventListing-YhKN018y.mjs} +2 -2
  142. package/dist/client/{eventRegistration-BR02a0k3.mjs → eventRegistration-CdHGtilr.mjs} +7 -7
  143. package/dist/client/foregroundContract-xICPq59x.mjs +31 -0
  144. package/dist/client/{form-LY2xIbwg.mjs → form-AcAL45rA.mjs} +2 -2
  145. package/dist/client/{headerSection-CYwwXJfh.mjs → headerSection-uEC52ueD.mjs} +3 -3
  146. package/dist/client/hooks.mjs +890 -497
  147. package/dist/client/{locationMap-DWnBXrFq.mjs → locationMap-_wJDSUYe.mjs} +3 -3
  148. package/dist/client/{media-DHtSxS5V.mjs → media-BK0O3b-U.mjs} +3 -2
  149. package/dist/client/{newsletterForm-D9s-fQ2P.mjs → newsletterForm-DrArsb2B.mjs} +2 -2
  150. package/dist/client/{pricing-DDq80oYc.mjs → pricing-BSYVghwo.mjs} +1 -1
  151. package/dist/client/{productDetail-B0SbWd45.mjs → productDetail-Dyk90sMs.mjs} +3 -3
  152. package/dist/client/{productList-PwYlZn0y.mjs → productList-BCKThwAI.mjs} +3 -3
  153. package/dist/client/{propsDecoder-BRWBiH7i.mjs → propsDecoder-CkXxkdSR.mjs} +63 -24
  154. package/dist/client/rendering/client.mjs +1034 -486
  155. package/dist/client/rendering/islands.mjs +19 -19
  156. package/dist/client/rendering.mjs +1832 -760
  157. package/dist/client/{shop-CMwZPYME.mjs → shop-DeltVH10.mjs} +6 -6
  158. package/dist/client/{shop-commerce-BuxsFate.mjs → shop-commerce-BD9Jsm2Z.mjs} +6 -6
  159. package/dist/client/{shop-commerce-store-boYlEJ91.mjs → shop-commerce-store-CmXD6FDS.mjs} +1 -1
  160. package/dist/client/{shopShared-D2naaOes.mjs → shopShared-B8v-lH_F.mjs} +2 -2
  161. package/dist/client/{useDiscountCodeUi-D9RHpVoj.mjs → useDiscountCodeUi-DbWJN8ld.mjs} +1 -1
  162. package/dist/client/{useEventFilters-igGiK1re.mjs → useEventFilters-EJIMUnqT.mjs} +46 -69
  163. package/dist/client/{usePolling-CI7MbsFB.mjs → usePolling-Cmh14fc7.mjs} +2 -2
  164. package/dist/preview-next/before-render.mjs +35 -0
  165. package/dist/preview-next/client/runtime.mjs +4 -4
  166. package/dist/preview-next/middleware.mjs +35 -0
  167. package/dist/{previewAuthStore-a_cBD28m.mjs → previewAuthStore-CTO7CRPk.mjs} +35 -0
  168. package/dist/{sdk-runtime-MBzD-GmP.mjs → sdk-runtime-Dou0GAav.mjs} +2 -2
  169. package/dist/{separator-5ahRBC85.mjs → separator-CI5wZNXT.mjs} +1 -1
  170. package/dist/server/components.mjs +1832 -784
  171. package/dist/server/config-validation.mjs +890 -497
  172. package/dist/server/config.mjs +890 -497
  173. package/dist/server/data.mjs +890 -497
  174. package/dist/server/date-time.mjs +386 -0
  175. package/dist/server/index.mjs +36 -1
  176. package/dist/server/next.mjs +1868 -785
  177. package/dist/server/page-converter.mjs +849 -285
  178. package/dist/server/prebuild.mjs +1 -1
  179. package/dist/server/rendering/server.mjs +1553 -718
  180. package/dist/server/rendering.mjs +1832 -784
  181. package/dist/server/routing.mjs +933 -522
  182. package/dist/server/server.mjs +929 -501
  183. package/dist/server/theme-bridge.mjs +1408 -392
  184. package/dist/server/theme.mjs +471 -228
  185. package/dist/styles/index.css +5 -0
  186. package/package.json +7 -1
  187. package/dist/_dts/theme-core/src/buttons/presets/types.d.ts +0 -88
  188. package/dist/_dts/theme-core/src/buttons/utils/contrast.d.ts +0 -38
  189. package/dist/_dts/theme-core/src/palette/themePaletteCompatibility.d.ts +0 -57
@@ -272,19 +272,29 @@ function isRecord$16(value) {
272
272
  //#region ../core/src/booking-date-time.ts
273
273
  const DEFAULT_LOCALE = "en-US";
274
274
  const FALLBACK_TIMEZONE = "UTC";
275
+ const DATE_TIME_FORMATTER_CACHE_LIMIT = 100;
276
+ const dateTimeFormatterCache = /* @__PURE__ */ new Map();
277
+ const timeZoneValidityCache = /* @__PURE__ */ new Map();
275
278
  function isValidTimeZone$1(timeZone) {
279
+ const cached = timeZoneValidityCache.get(timeZone);
280
+ if (cached !== void 0) return cached;
281
+ let isValid;
276
282
  try {
277
283
  new Intl.DateTimeFormat(DEFAULT_LOCALE, { timeZone }).format(/* @__PURE__ */ new Date());
278
- return true;
284
+ isValid = true;
279
285
  } catch {
280
- return false;
286
+ isValid = false;
281
287
  }
288
+ if (timeZoneValidityCache.size >= DATE_TIME_FORMATTER_CACHE_LIMIT) timeZoneValidityCache.clear();
289
+ timeZoneValidityCache.set(timeZone, isValid);
290
+ return isValid;
282
291
  }
283
292
  function getSafeTimeZone(timeZone) {
284
293
  const normalized = typeof timeZone === "string" ? timeZone.trim() : "";
285
294
  return normalized.length > 0 && isValidTimeZone$1(normalized) ? normalized : FALLBACK_TIMEZONE;
286
295
  }
287
296
  function parseStrictBookingTimeZone(timeZone) {
297
+ if (typeof timeZone !== "string") return null;
288
298
  const normalized = timeZone.trim();
289
299
  if (normalized.length === 0 || !isValidTimeZone$1(normalized)) return null;
290
300
  return normalized;
@@ -297,10 +307,19 @@ function formatParseError(error) {
297
307
  }
298
308
  }
299
309
  function formatToPartsLookup(date, locale, timeZone, format) {
300
- return new Map(new Intl.DateTimeFormat(locale, {
310
+ return new Map(getCachedDateTimeFormatter(locale, timeZone, format).formatToParts(date).map((part) => [part.type, part.value]));
311
+ }
312
+ function getCachedDateTimeFormatter(locale, timeZone, format) {
313
+ const key = `${locale}\u0000${timeZone}\u0000${JSON.stringify(Object.entries(format).sort(([left], [right]) => left.localeCompare(right)))}`;
314
+ const cached = dateTimeFormatterCache.get(key);
315
+ if (cached !== void 0) return cached;
316
+ const formatter = new Intl.DateTimeFormat(locale, {
301
317
  ...format,
302
318
  timeZone
303
- }).formatToParts(date).map((part) => [part.type, part.value]));
319
+ });
320
+ if (dateTimeFormatterCache.size >= DATE_TIME_FORMATTER_CACHE_LIMIT) dateTimeFormatterCache.clear();
321
+ dateTimeFormatterCache.set(key, formatter);
322
+ return formatter;
304
323
  }
305
324
  function getZonedDateTimeParts(date, timeZone) {
306
325
  const parts = formatToPartsLookup(date, "en-GB", timeZone, {
@@ -346,23 +365,9 @@ function toUtcIsoDateTimeString(value) {
346
365
  return parsed.value;
347
366
  }
348
367
  function parseScheduledBookingDateTime(input) {
368
+ let startsAt;
349
369
  try {
350
- const startsAt = toUtcIsoDateTimeString(input.startsAt);
351
- const timeZone = parseStrictBookingTimeZone(input.timeZone);
352
- if (timeZone === null) return {
353
- ok: false,
354
- field: "timeZone",
355
- reason: "invalid_time_zone",
356
- value: input.timeZone
357
- };
358
- return {
359
- ok: true,
360
- value: {
361
- startsAt,
362
- timeZone,
363
- locale: input.locale
364
- }
365
- };
370
+ startsAt = toUtcIsoDateTimeString(input.startsAt);
366
371
  } catch {
367
372
  return {
368
373
  ok: false,
@@ -371,6 +376,21 @@ function parseScheduledBookingDateTime(input) {
371
376
  value: input.startsAt
372
377
  };
373
378
  }
379
+ const timeZone = parseStrictBookingTimeZone(input.timeZone);
380
+ if (timeZone === null) return {
381
+ ok: false,
382
+ field: "timeZone",
383
+ reason: "invalid_time_zone",
384
+ value: typeof input.timeZone === "string" ? input.timeZone : ""
385
+ };
386
+ return {
387
+ ok: true,
388
+ value: {
389
+ startsAt,
390
+ timeZone,
391
+ locale: input.locale
392
+ }
393
+ };
374
394
  }
375
395
  function parseScheduledBookingDateRange(input) {
376
396
  const start = parseScheduledBookingDateTime(input);
@@ -409,10 +429,7 @@ function toScheduledBookingDateRange(input) {
409
429
  function formatBookingInstant(isoString, options) {
410
430
  const date = new Date(isoString);
411
431
  if (Number.isNaN(date.getTime())) return isoString;
412
- return new Intl.DateTimeFormat(options.locale ?? DEFAULT_LOCALE, {
413
- ...options.format,
414
- timeZone: getSafeTimeZone(options.timeZone)
415
- }).format(date);
432
+ return getCachedDateTimeFormatter(options.locale ?? DEFAULT_LOCALE, getSafeTimeZone(options.timeZone), options.format).format(date);
416
433
  }
417
434
  function formatBookingDate(input, format = {
418
435
  weekday: "long",
@@ -551,7 +568,8 @@ function validateRelativeStoragePath(value) {
551
568
  if (value.startsWith("sites/")) return fail({ tag: "SITE_SCOPED_PATH" });
552
569
  if (value.startsWith("/")) return fail({ tag: "LEADING_SLASH" });
553
570
  if (value.includes("//")) return fail({ tag: "DOUBLE_SLASH" });
554
- if (value.split("/").some((segment) => segment === "..")) return fail({ tag: "TRAVERSAL" });
571
+ if (value.includes("%")) return fail({ tag: "PERCENT_ENCODING" });
572
+ if (value.split("/").some((segment) => segment === "." || segment === "..")) return fail({ tag: "TRAVERSAL" });
555
573
  return ok(value);
556
574
  }
557
575
  function brandRelativeStoragePath(value) {
@@ -1642,6 +1660,20 @@ const blockCategoryEnum = z$1.enum([
1642
1660
  "layout",
1643
1661
  "interactive"
1644
1662
  ]);
1663
+ const blockContentSourceSchema = z$1.object({
1664
+ kind: z$1.enum([
1665
+ "inline",
1666
+ "entries",
1667
+ "mixed"
1668
+ ]),
1669
+ contentType: z$1.string().min(1).optional()
1670
+ }).superRefine((value, ctx) => {
1671
+ if (value.kind === "inline" && value.contentType) ctx.addIssue({
1672
+ code: z$1.ZodIssueCode.custom,
1673
+ path: ["contentType"],
1674
+ message: "contentType is not allowed when contentSource.kind is \"inline\""
1675
+ });
1676
+ });
1645
1677
  z$1.object({
1646
1678
  name: z$1.string().min(1),
1647
1679
  version: z$1.string().min(1),
@@ -1672,6 +1704,12 @@ z$1.object({
1672
1704
  }).optional()).optional(),
1673
1705
  category: blockCategoryEnum.optional(),
1674
1706
  contentTypes: z$1.array(z$1.string()).optional(),
1707
+ /**
1708
+ * Explicit content-source classification (inline / entries / mixed). Optional at the
1709
+ * schema level for backward compatibility with SDK-defined custom blocks, but every
1710
+ * registered SYSTEM block must declare it (enforced by a registry-wide test).
1711
+ */
1712
+ contentSource: blockContentSourceSchema.optional(),
1675
1713
  tags: z$1.array(z$1.string()).optional(),
1676
1714
  icon: z$1.string().optional()
1677
1715
  });
@@ -3211,7 +3249,7 @@ function normalizeStoredObjectChildren(children, value, ctx) {
3211
3249
  return normalized;
3212
3250
  }
3213
3251
  function normalizeStoredRepeaterItems(plan, value, ctx) {
3214
- if (!isUnknownArray$1(value)) return value;
3252
+ if (!isUnknownArray$2(value)) return value;
3215
3253
  return value.map((item) => {
3216
3254
  if (!item || typeof item !== "object" || Array.isArray(item)) return item;
3217
3255
  const itemRecord = item;
@@ -3266,7 +3304,7 @@ function getAtFieldPath(source, path) {
3266
3304
  }, source);
3267
3305
  }
3268
3306
  function normalizeRepeaterItems(plan, value, ctx) {
3269
- if (!isUnknownArray$1(value)) return value;
3307
+ if (!isUnknownArray$2(value)) return value;
3270
3308
  return value.map((item) => {
3271
3309
  if (!item || typeof item !== "object" || Array.isArray(item)) return item;
3272
3310
  const itemRecord = item;
@@ -3641,7 +3679,7 @@ function isEmptyValue(value) {
3641
3679
  function isPlainObject$4(value) {
3642
3680
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
3643
3681
  }
3644
- function isUnknownArray$1(value) {
3682
+ function isUnknownArray$2(value) {
3645
3683
  return Array.isArray(value);
3646
3684
  }
3647
3685
  function isValidRichTextDoc(value) {
@@ -3863,6 +3901,14 @@ function relativeLuminance(r, g, b) {
3863
3901
  const R = srgbToLinear(r), G = srgbToLinear(g), B = srgbToLinear(b);
3864
3902
  return .2126 * R + .7152 * G + .0722 * B;
3865
3903
  }
3904
+ function contrastRatio(hex1, hex2) {
3905
+ const { r: r1, g: g1, b: b1 } = hexToRgb(hex1);
3906
+ const { r: r2, g: g2, b: b2 } = hexToRgb(hex2);
3907
+ const L1 = relativeLuminance(r1, g1, b1);
3908
+ const L2 = relativeLuminance(r2, g2, b2);
3909
+ const [hi, lo] = L1 >= L2 ? [L1, L2] : [L2, L1];
3910
+ return (hi + .05) / (lo + .05);
3911
+ }
3866
3912
  //#endregion
3867
3913
  //#region ../theme-core/src/palette/utils/onColor.ts
3868
3914
  const BACKGROUND_ROLE_NAMES = /* @__PURE__ */ new Set([
@@ -4854,6 +4900,10 @@ const modernMinimalTheme = {
4854
4900
  name: "primary",
4855
4901
  hex: "#1f2937"
4856
4902
  },
4903
+ {
4904
+ name: "primaryForeground",
4905
+ hex: "#ffffff"
4906
+ },
4857
4907
  {
4858
4908
  name: "secondary",
4859
4909
  hex: "#6b7280"
@@ -4882,6 +4932,14 @@ const modernMinimalTheme = {
4882
4932
  name: "surface",
4883
4933
  hex: "#ffffff"
4884
4934
  },
4935
+ {
4936
+ name: "surfaceAlt",
4937
+ hex: "#f9fafb"
4938
+ },
4939
+ {
4940
+ name: "muted",
4941
+ hex: "#f3f4f6"
4942
+ },
4885
4943
  {
4886
4944
  name: "text",
4887
4945
  hex: "#1f2937"
@@ -8295,6 +8353,111 @@ function boundaryKey$1(previousBlockId, nextBlockId) {
8295
8353
  return makeBoundaryId(previousBlockId, nextBlockId);
8296
8354
  }
8297
8355
  //#endregion
8356
+ //#region ../theme-core/src/buttons/effectClassification.ts
8357
+ /**
8358
+ * Exhaustive live policy for every registered effect id.
8359
+ *
8360
+ * The resolver consumes the transition payload directly, so adding an effect
8361
+ * cannot update classification without also defining its runtime behavior.
8362
+ */
8363
+ const BUTTON_EFFECT_POLICIES = {
8364
+ "darken-background": {
8365
+ classification: "colour-transition",
8366
+ transition: {
8367
+ kind: "adjust-shade",
8368
+ direction: "darker"
8369
+ }
8370
+ },
8371
+ "lighten-background": {
8372
+ classification: "colour-transition",
8373
+ transition: {
8374
+ kind: "adjust-shade",
8375
+ direction: "lighter"
8376
+ }
8377
+ },
8378
+ "background-on-hover": {
8379
+ classification: "colour-transition",
8380
+ transition: { kind: "replace-background" }
8381
+ },
8382
+ "background-on-hover-alpha": {
8383
+ classification: "unsupported-colour",
8384
+ reason: "alpha_requires_surface"
8385
+ },
8386
+ "fade-background": {
8387
+ classification: "unsupported-colour",
8388
+ reason: "changes_element_opacity"
8389
+ },
8390
+ "opacity-reduce": {
8391
+ classification: "unsupported-colour",
8392
+ reason: "changes_element_opacity"
8393
+ },
8394
+ "gradient-text": {
8395
+ classification: "unsupported-colour",
8396
+ reason: "changes_foreground"
8397
+ },
8398
+ "text-color-change": {
8399
+ classification: "unsupported-colour",
8400
+ reason: "changes_foreground"
8401
+ },
8402
+ "border-color-change": {
8403
+ classification: "unsupported-colour",
8404
+ reason: "changes_border"
8405
+ },
8406
+ "aurora-glow": {
8407
+ classification: "unsupported-background-overlay",
8408
+ reason: "unresolved_background_overlay"
8409
+ },
8410
+ "cosmic-stardust": {
8411
+ classification: "unsupported-background-overlay",
8412
+ reason: "unresolved_background_overlay"
8413
+ },
8414
+ "gradient-border-fill": {
8415
+ classification: "unsupported-background-overlay",
8416
+ reason: "unresolved_background_overlay"
8417
+ },
8418
+ "animated-gradient-border-fill": {
8419
+ classification: "unsupported-background-overlay",
8420
+ reason: "unresolved_background_overlay"
8421
+ },
8422
+ "nav-underline": {
8423
+ classification: "not-button",
8424
+ reason: "not_button_effect"
8425
+ },
8426
+ "nav-frosted-base": {
8427
+ classification: "not-button",
8428
+ reason: "not_button_effect"
8429
+ },
8430
+ "nav-frosted-hover": {
8431
+ classification: "not-button",
8432
+ reason: "not_button_effect"
8433
+ },
8434
+ "nav-frosted-active": {
8435
+ classification: "not-button",
8436
+ reason: "not_button_effect"
8437
+ },
8438
+ "animated-gradient": { classification: "non-colour" },
8439
+ "border-glow": { classification: "non-colour" },
8440
+ "drop-shadow": { classification: "non-colour" },
8441
+ "inner-shadow": { classification: "non-colour" },
8442
+ "neumorphic-shadow": { classification: "non-colour" },
8443
+ "outer-glow": { classification: "non-colour" },
8444
+ "retro-3d-shadow": { classification: "non-colour" },
8445
+ "scale-up": { classification: "non-colour" },
8446
+ "scale-down": { classification: "non-colour" },
8447
+ lift: { classification: "non-colour" },
8448
+ "press-down": { classification: "non-colour" },
8449
+ pop: { classification: "non-colour" },
8450
+ "border-bottom-grow": { classification: "non-colour" },
8451
+ "sketchy-border": { classification: "non-colour" },
8452
+ "pulse-animation": { classification: "non-colour" }
8453
+ };
8454
+ function getButtonEffectPolicy(effectId) {
8455
+ return Object.prototype.hasOwnProperty.call(BUTTON_EFFECT_POLICIES, effectId) ? BUTTON_EFFECT_POLICIES[effectId] : null;
8456
+ }
8457
+ function classifyButtonEffectId(effectId) {
8458
+ return getButtonEffectPolicy(effectId)?.classification ?? "unknown";
8459
+ }
8460
+ //#endregion
8298
8461
  //#region ../theme-core/src/buttons/types.ts
8299
8462
  /**
8300
8463
  * Standard semantic variant roles a theme exposes.
@@ -8324,6 +8487,20 @@ function asSpecialVariantId(value) {
8324
8487
  * Shared between generator and renderer so neither side hard-codes the string.
8325
8488
  */
8326
8489
  const DEFAULT_VARIANT_ALIAS_ID = "default";
8490
+ function parseOpaqueButtonColourToken(value) {
8491
+ const token = parseThemeColorToken(value);
8492
+ if (token === null) return null;
8493
+ const parts = parseColorTokenParts(token);
8494
+ return parts.kind === "token" && parts.opacityPercent === null ? token : null;
8495
+ }
8496
+ function unsafeAsOpaqueButtonColourToken(value) {
8497
+ return value;
8498
+ }
8499
+ const opaqueButtonColourTokenSchema = themeColorTokenSchema.refine((value) => parseOpaqueButtonColourToken(value) !== null, "Button colour tokens must be opaque").transform((value) => {
8500
+ const token = parseOpaqueButtonColourToken(value);
8501
+ if (token === null) throw new Error("Invariant: opaque button token passed its schema");
8502
+ return token;
8503
+ });
8327
8504
  const cornerStyleSchema = z$1.enum([
8328
8505
  "square",
8329
8506
  "rounded",
@@ -8425,7 +8602,7 @@ const buttonSizesSchema = z$1.object({
8425
8602
  lg,
8426
8603
  xl: xl ?? lg
8427
8604
  }));
8428
- const buttonGlobalSettingsSchema = z$1.object({
8605
+ const canonicalButtonGlobalSettingsSchema = z$1.object({
8429
8606
  cornerStyle: cornerStyleSchema,
8430
8607
  cornerRadius: z$1.number().min(0).max(24).optional(),
8431
8608
  /**
@@ -8456,11 +8633,12 @@ const buttonGlobalSettingsSchema = z$1.object({
8456
8633
  paddingPreset: buttonPaddingPresetSchema.optional(),
8457
8634
  hoverTransform: hoverTransformSchema,
8458
8635
  hoverColor: hoverColorSchema,
8459
- hoverColorToken: themeColorTokenSchema.optional(),
8636
+ hoverColorToken: opaqueButtonColourTokenSchema.optional(),
8460
8637
  gradientStyle: gradientStyleSchema.optional(),
8461
8638
  gradientAngle: z$1.number().min(0).max(360).optional(),
8462
8639
  gradientSharpness: gradientSharpnessSchema.optional()
8463
8640
  });
8641
+ const buttonGlobalSettingsSchema = z$1.preprocess(normalizeLegacyButtonGlobalInput, canonicalButtonGlobalSettingsSchema);
8464
8642
  const gradientDirectionSchema$1 = z$1.enum([
8465
8643
  "to-r",
8466
8644
  "to-l",
@@ -8474,27 +8652,33 @@ const gradientDirectionSchema$1 = z$1.enum([
8474
8652
  const buttonBackgroundSchema = z$1.discriminatedUnion("type", [
8475
8653
  z$1.object({
8476
8654
  type: z$1.literal("solid"),
8477
- colorToken: themeColorTokenSchema
8655
+ colorToken: opaqueButtonColourTokenSchema
8478
8656
  }),
8479
8657
  z$1.object({
8480
8658
  type: z$1.literal("gradient"),
8481
- stops: z$1.array(themeColorTokenSchema).min(2),
8482
- direction: gradientDirectionSchema$1
8659
+ stops: z$1.array(opaqueButtonColourTokenSchema).min(2).transform((stops) => {
8660
+ const [first, second, ...rest] = stops;
8661
+ if (first === void 0 || second === void 0) throw new Error("Invariant: gradient stops passed the minimum length schema");
8662
+ return [
8663
+ first,
8664
+ second,
8665
+ ...rest
8666
+ ];
8667
+ }),
8668
+ direction: gradientDirectionSchema$1,
8669
+ foregroundToken: opaqueButtonColourTokenSchema
8483
8670
  }),
8484
- z$1.object({ type: z$1.literal("transparent") })
8671
+ z$1.object({
8672
+ type: z$1.literal("surface"),
8673
+ role: z$1.literal("link")
8674
+ })
8485
8675
  ]);
8486
8676
  const effectApplicationSchema$1 = z$1.object({
8487
8677
  effectId: z$1.string(),
8488
- options: z$1.record(z$1.string(), z$1.any()).optional()
8489
- });
8490
- const buttonBorderSchema = z$1.object({
8491
- widthClass: z$1.string(),
8492
- colorToken: themeColorTokenSchema
8493
- });
8494
- const buttonVariantAffordanceSchema = z$1.object({
8495
- iconId: z$1.string().min(1),
8496
- colorToken: themeColorTokenSchema.optional()
8678
+ options: z$1.record(z$1.string(), z$1.json()).optional()
8497
8679
  });
8680
+ const buttonBorderSchema = z$1.object({ widthClass: z$1.string() });
8681
+ const buttonVariantAffordanceSchema = z$1.object({ iconId: z$1.string().min(1) });
8498
8682
  const variantShadowSchema = z$1.object({
8499
8683
  elevation: z$1.enum([
8500
8684
  "none",
@@ -8535,27 +8719,170 @@ const variantSizeOverridesSchema = z$1.object({
8535
8719
  * default (e.g. link-style variants declaring zero horizontal padding at
8536
8720
  * every size).
8537
8721
  */
8538
- const buttonVariantSchema = z$1.object({
8722
+ const canonicalButtonVariantSchema = z$1.object({
8539
8723
  id: z$1.string(),
8540
8724
  name: z$1.string().min(1).max(20),
8541
8725
  enabled: z$1.boolean(),
8542
8726
  priority: prioritySchema,
8543
8727
  background: buttonBackgroundSchema,
8544
- textColorToken: themeColorTokenSchema,
8545
8728
  /** Tailwind radius token (e.g. `'rounded-md'`). Omit to inherit from `global.cornerStyle`. */
8546
8729
  borderRadius: z$1.string().optional(),
8547
8730
  shadow: variantShadowSchema.optional(),
8548
8731
  border: buttonBorderSchema.optional(),
8549
- hoverBackgroundToken: z$1.string().optional(),
8732
+ hoverBackgroundToken: opaqueButtonColourTokenSchema.optional(),
8550
8733
  effects: variantEffectsSchema.optional(),
8551
8734
  sizes: variantSizeOverridesSchema.optional(),
8552
8735
  affordance: buttonVariantAffordanceSchema.optional()
8553
8736
  });
8737
+ /**
8738
+ * Temporary persisted-theme admission boundary for issue #1206.
8739
+ *
8740
+ * Production inventory on 2026-07-22 found 22 rows using the old independent
8741
+ * `textColorToken`/border colour shape. New source and all downstream code use
8742
+ * only the canonical relationship. Delete this preprocessor after the reviewed
8743
+ * production rewrite reports zero legacy rows.
8744
+ */
8745
+ const buttonVariantSchema = z$1.preprocess(normalizeLegacyButtonVariantInput, canonicalButtonVariantSchema);
8554
8746
  const buttonSystemSchema = z$1.object({
8555
8747
  global: buttonGlobalSettingsSchema,
8556
8748
  variants: z$1.array(buttonVariantSchema).min(1).max(6),
8557
8749
  sizes: buttonSizesSchema.optional()
8558
8750
  });
8751
+ function normalizeLegacyButtonVariantInput(input) {
8752
+ if (!isUnknownRecord(input)) return input;
8753
+ const background = input.background;
8754
+ if (!isUnknownRecord(background)) return input;
8755
+ 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;
8756
+ const { textColorToken, ...withoutLegacyText } = input;
8757
+ const normalizedBorder = isUnknownRecord(input.border) && typeof input.border.widthClass === "string" ? { widthClass: input.border.widthClass } : input.border;
8758
+ const normalizedAffordance = isUnknownRecord(input.affordance) && typeof input.affordance.iconId === "string" ? { iconId: input.affordance.iconId } : input.affordance;
8759
+ const normalizedEffects = normalizeLegacyButtonEffects(input.effects, background.type);
8760
+ const hoverBackgroundToken = stripLegacyTokenAlpha(input.hoverBackgroundToken);
8761
+ if (background.type === "transparent") return {
8762
+ ...withoutLegacyText,
8763
+ background: {
8764
+ type: "surface",
8765
+ role: "link"
8766
+ },
8767
+ border: normalizedBorder,
8768
+ affordance: normalizedAffordance,
8769
+ effects: normalizedEffects,
8770
+ hoverBackgroundToken
8771
+ };
8772
+ if (background.type === "gradient") {
8773
+ const stops = Array.isArray(background.stops) ? background.stops.map(stripLegacyTokenAlpha) : background.stops;
8774
+ return {
8775
+ ...withoutLegacyText,
8776
+ background: {
8777
+ ...background,
8778
+ stops,
8779
+ foregroundToken: stripLegacyTokenAlpha(background.foregroundToken ?? textColorToken)
8780
+ },
8781
+ border: normalizedBorder,
8782
+ affordance: normalizedAffordance,
8783
+ effects: normalizedEffects,
8784
+ hoverBackgroundToken
8785
+ };
8786
+ }
8787
+ return {
8788
+ ...withoutLegacyText,
8789
+ background: background.type === "solid" ? {
8790
+ ...background,
8791
+ colorToken: stripLegacyTokenAlpha(background.colorToken)
8792
+ } : background,
8793
+ border: normalizedBorder,
8794
+ affordance: normalizedAffordance,
8795
+ effects: normalizedEffects,
8796
+ hoverBackgroundToken
8797
+ };
8798
+ }
8799
+ function normalizeLegacyButtonGlobalInput(input) {
8800
+ if (!isUnknownRecord(input)) return input;
8801
+ const hoverColorToken = stripLegacyTokenAlpha(input.hoverColorToken);
8802
+ return hoverColorToken === input.hoverColorToken ? input : {
8803
+ ...input,
8804
+ hoverColorToken
8805
+ };
8806
+ }
8807
+ function hasLegacyAlphaToken(input, background) {
8808
+ const stops = isUnknownArray$1(background.stops) ? background.stops : [];
8809
+ return [
8810
+ input.hoverBackgroundToken,
8811
+ background.colorToken,
8812
+ background.foregroundToken,
8813
+ ...stops
8814
+ ].some((token) => stripLegacyTokenAlpha(token) !== token);
8815
+ }
8816
+ function stripLegacyTokenAlpha(value) {
8817
+ if (typeof value !== "string") return value;
8818
+ const slashIndex = value.indexOf("/");
8819
+ return slashIndex < 0 ? value : value.slice(0, slashIndex);
8820
+ }
8821
+ function hasLegacyButtonEffects(input) {
8822
+ if (!isUnknownRecord(input)) return false;
8823
+ return [
8824
+ "base",
8825
+ "hover",
8826
+ "active",
8827
+ "focus"
8828
+ ].some((state) => {
8829
+ const effects = input[state];
8830
+ return Array.isArray(effects) && effects.some((effect) => {
8831
+ if (!isUnknownRecord(effect) || typeof effect.effectId !== "string") return true;
8832
+ const classification = classifyButtonEffectId(effect.effectId);
8833
+ if (classification !== "colour-transition" && classification !== "non-colour") return true;
8834
+ return effect.effectId === "background-on-hover" && isUnknownRecord(effect.options) && stripLegacyTokenAlpha(effect.options.colorToken) !== effect.options.colorToken;
8835
+ });
8836
+ });
8837
+ }
8838
+ function normalizeLegacyButtonEffects(input, backgroundType) {
8839
+ if (!isUnknownRecord(input)) return input;
8840
+ const normalized = {};
8841
+ for (const state of [
8842
+ "base",
8843
+ "hover",
8844
+ "active",
8845
+ "focus"
8846
+ ]) {
8847
+ const effects = input[state];
8848
+ if (!Array.isArray(effects)) continue;
8849
+ const safeEffects = effects.flatMap((effect) => {
8850
+ if (!isUnknownRecord(effect) || typeof effect.effectId !== "string") return [];
8851
+ const classification = classifyButtonEffectId(effect.effectId);
8852
+ if (classification === "non-colour") return [effect];
8853
+ if (classification !== "colour-transition") return [];
8854
+ if (effect.effectId === "background-on-hover") {
8855
+ const options = isUnknownRecord(effect.options) ? effect.options : null;
8856
+ const colorToken = options === null ? null : parseOpaqueButtonColourToken(stripLegacyTokenAlpha(options.colorToken));
8857
+ return colorToken === null ? [] : [{
8858
+ ...effect,
8859
+ options: {
8860
+ ...options,
8861
+ colorToken
8862
+ }
8863
+ }];
8864
+ }
8865
+ if (backgroundType !== "solid") return [];
8866
+ const rawAmount = isUnknownRecord(effect.options) ? effect.options.amount : void 0;
8867
+ const amount = typeof rawAmount === "number" && rawAmount > 0 ? Math.max(100, Math.round(rawAmount / 100) * 100) : 100;
8868
+ return [{
8869
+ ...effect,
8870
+ options: {
8871
+ ...isUnknownRecord(effect.options) ? effect.options : {},
8872
+ amount
8873
+ }
8874
+ }];
8875
+ });
8876
+ if (safeEffects.length > 0) normalized[state] = safeEffects;
8877
+ }
8878
+ return Object.keys(normalized).length === 0 ? void 0 : normalized;
8879
+ }
8880
+ function isUnknownRecord(value) {
8881
+ return typeof value === "object" && value !== null && !Array.isArray(value);
8882
+ }
8883
+ function isUnknownArray$1(value) {
8884
+ return Array.isArray(value);
8885
+ }
8559
8886
  //#endregion
8560
8887
  //#region ../theme-core/src/buttons/personalities/types.ts
8561
8888
  function asButtonPersonalityId(value) {
@@ -8581,7 +8908,7 @@ function defineButtonPersonality(input) {
8581
8908
  name: input.name,
8582
8909
  description: input.description,
8583
8910
  tags: input.tags,
8584
- buttonSystem: input.buttonSystem
8911
+ buttonSystem: buttonSystemSchema.parse(input.buttonSystem)
8585
8912
  };
8586
8913
  }
8587
8914
  //#endregion
@@ -8634,19 +8961,15 @@ const brushedWash = defineButtonPersonality({
8634
8961
  background: {
8635
8962
  type: "gradient",
8636
8963
  stops: ["primary", "accent"],
8637
- direction: "to-r"
8964
+ direction: "to-r",
8965
+ foregroundToken: "primaryForeground"
8638
8966
  },
8639
- textColorToken: "primaryForeground",
8640
8967
  borderRadius: "rounded-lg",
8641
8968
  shadow: {
8642
8969
  elevation: "low",
8643
8970
  softness: "soft",
8644
8971
  position: "bottom"
8645
- },
8646
- effects: { hover: [{
8647
- effectId: "opacity-reduce",
8648
- options: { reduction: -15 }
8649
- }] }
8972
+ }
8650
8973
  },
8651
8974
  {
8652
8975
  id: "secondary",
@@ -8656,32 +8979,27 @@ const brushedWash = defineButtonPersonality({
8656
8979
  background: {
8657
8980
  type: "gradient",
8658
8981
  stops: ["secondary", "accent"],
8659
- direction: "to-br"
8982
+ direction: "to-br",
8983
+ foregroundToken: "primaryForeground"
8660
8984
  },
8661
- textColorToken: "primaryForeground",
8662
8985
  borderRadius: "rounded-lg",
8663
8986
  shadow: {
8664
8987
  elevation: "low",
8665
8988
  softness: "soft",
8666
8989
  position: "bottom"
8667
- },
8668
- effects: { hover: [{
8669
- effectId: "opacity-reduce",
8670
- options: { reduction: -15 }
8671
- }] }
8990
+ }
8672
8991
  },
8673
8992
  {
8674
8993
  id: "outline",
8675
8994
  name: "Outline",
8676
8995
  enabled: true,
8677
8996
  priority: 3,
8678
- background: { type: "transparent" },
8679
- textColorToken: "primary",
8680
- borderRadius: "rounded-lg",
8681
- border: {
8682
- widthClass: "border",
8683
- colorToken: "primary"
8997
+ background: {
8998
+ type: "surface",
8999
+ role: "link"
8684
9000
  },
9001
+ borderRadius: "rounded-lg",
9002
+ border: { widthClass: "border" },
8685
9003
  effects: { hover: [{
8686
9004
  effectId: "background-on-hover",
8687
9005
  options: { colorToken: "surface" }
@@ -8692,8 +9010,10 @@ const brushedWash = defineButtonPersonality({
8692
9010
  name: "Ghost",
8693
9011
  enabled: true,
8694
9012
  priority: 3,
8695
- background: { type: "transparent" },
8696
- textColorToken: "text",
9013
+ background: {
9014
+ type: "surface",
9015
+ role: "link"
9016
+ },
8697
9017
  borderRadius: "rounded-lg",
8698
9018
  effects: { hover: [{
8699
9019
  effectId: "background-on-hover",
@@ -8739,7 +9059,6 @@ const confidentChip = defineButtonPersonality({
8739
9059
  type: "solid",
8740
9060
  colorToken: "primary"
8741
9061
  },
8742
- textColorToken: "primaryForeground",
8743
9062
  borderRadius: "rounded-md",
8744
9063
  shadow: {
8745
9064
  elevation: "medium",
@@ -8749,7 +9068,7 @@ const confidentChip = defineButtonPersonality({
8749
9068
  effects: {
8750
9069
  hover: [{
8751
9070
  effectId: "darken-background",
8752
- options: { amount: 60 }
9071
+ options: { amount: 100 }
8753
9072
  }],
8754
9073
  active: [{
8755
9074
  effectId: "scale-down",
@@ -8766,12 +9085,8 @@ const confidentChip = defineButtonPersonality({
8766
9085
  type: "solid",
8767
9086
  colorToken: "surface"
8768
9087
  },
8769
- textColorToken: "text",
8770
9088
  borderRadius: "rounded-md",
8771
- border: {
8772
- widthClass: "border",
8773
- colorToken: "border"
8774
- },
9089
+ border: { widthClass: "border" },
8775
9090
  effects: { hover: [{
8776
9091
  effectId: "background-on-hover",
8777
9092
  options: { colorToken: "background" }
@@ -8782,13 +9097,12 @@ const confidentChip = defineButtonPersonality({
8782
9097
  name: "Outline",
8783
9098
  enabled: true,
8784
9099
  priority: 3,
8785
- background: { type: "transparent" },
8786
- textColorToken: "primary",
8787
- borderRadius: "rounded-md",
8788
- border: {
8789
- widthClass: "border",
8790
- colorToken: "primary"
9100
+ background: {
9101
+ type: "surface",
9102
+ role: "link"
8791
9103
  },
9104
+ borderRadius: "rounded-md",
9105
+ border: { widthClass: "border" },
8792
9106
  effects: { hover: [{
8793
9107
  effectId: "background-on-hover",
8794
9108
  options: { colorToken: "surface" }
@@ -8799,8 +9113,10 @@ const confidentChip = defineButtonPersonality({
8799
9113
  name: "Ghost",
8800
9114
  enabled: true,
8801
9115
  priority: 3,
8802
- background: { type: "transparent" },
8803
- textColorToken: "primary",
9116
+ background: {
9117
+ type: "surface",
9118
+ role: "link"
9119
+ },
8804
9120
  borderRadius: "rounded-md",
8805
9121
  effects: { hover: [{
8806
9122
  effectId: "background-on-hover",
@@ -8863,7 +9179,6 @@ const earthPill = defineButtonPersonality({
8863
9179
  type: "solid",
8864
9180
  colorToken: "primary"
8865
9181
  },
8866
- textColorToken: "primaryForeground",
8867
9182
  borderRadius: "rounded-full",
8868
9183
  shadow: {
8869
9184
  elevation: "low",
@@ -8889,13 +9204,12 @@ const earthPill = defineButtonPersonality({
8889
9204
  name: "Secondary",
8890
9205
  enabled: true,
8891
9206
  priority: 2,
8892
- background: { type: "transparent" },
8893
- textColorToken: "primary",
8894
- borderRadius: "rounded-full",
8895
- border: {
8896
- widthClass: "border",
8897
- colorToken: "primary"
9207
+ background: {
9208
+ type: "surface",
9209
+ role: "link"
8898
9210
  },
9211
+ borderRadius: "rounded-full",
9212
+ border: { widthClass: "border" },
8899
9213
  effects: { hover: [{
8900
9214
  effectId: "background-on-hover",
8901
9215
  options: { colorToken: "muted" }
@@ -8906,13 +9220,12 @@ const earthPill = defineButtonPersonality({
8906
9220
  name: "Outline",
8907
9221
  enabled: true,
8908
9222
  priority: 3,
8909
- background: { type: "transparent" },
8910
- textColorToken: "text",
8911
- borderRadius: "rounded-full",
8912
- border: {
8913
- widthClass: "border",
8914
- colorToken: "border"
9223
+ background: {
9224
+ type: "surface",
9225
+ role: "link"
8915
9226
  },
9227
+ borderRadius: "rounded-full",
9228
+ border: { widthClass: "border" },
8916
9229
  effects: { hover: [{
8917
9230
  effectId: "background-on-hover",
8918
9231
  options: { colorToken: "surfaceAlt" }
@@ -8923,8 +9236,10 @@ const earthPill = defineButtonPersonality({
8923
9236
  name: "Ghost",
8924
9237
  enabled: true,
8925
9238
  priority: 3,
8926
- background: { type: "transparent" },
8927
- textColorToken: "primary",
9239
+ background: {
9240
+ type: "surface",
9241
+ role: "link"
9242
+ },
8928
9243
  borderRadius: "rounded-full",
8929
9244
  shadow: {
8930
9245
  elevation: "none",
@@ -8945,11 +9260,7 @@ const earthPill = defineButtonPersonality({
8945
9260
  padding: "0.625rem 0",
8946
9261
  fontSize: "text-xl"
8947
9262
  }
8948
- },
8949
- effects: { hover: [{
8950
- effectId: "opacity-reduce",
8951
- options: { reduction: 25 }
8952
- }] }
9263
+ }
8953
9264
  }
8954
9265
  ]
8955
9266
  }
@@ -8985,8 +9296,10 @@ const editorialLink = defineButtonPersonality({
8985
9296
  name: "Primary",
8986
9297
  enabled: true,
8987
9298
  priority: 1,
8988
- background: { type: "transparent" },
8989
- textColorToken: "text",
9299
+ background: {
9300
+ type: "surface",
9301
+ role: "link"
9302
+ },
8990
9303
  borderRadius: "rounded-none",
8991
9304
  sizes: {
8992
9305
  sm: { padding: "0.25rem 0" },
@@ -9008,8 +9321,10 @@ const editorialLink = defineButtonPersonality({
9008
9321
  name: "Secondary",
9009
9322
  enabled: true,
9010
9323
  priority: 2,
9011
- background: { type: "transparent" },
9012
- textColorToken: "mutedText",
9324
+ background: {
9325
+ type: "surface",
9326
+ role: "link"
9327
+ },
9013
9328
  borderRadius: "rounded-none",
9014
9329
  sizes: {
9015
9330
  sm: { padding: "0.25rem 0" },
@@ -9031,8 +9346,10 @@ const editorialLink = defineButtonPersonality({
9031
9346
  name: "Outline",
9032
9347
  enabled: true,
9033
9348
  priority: 3,
9034
- background: { type: "transparent" },
9035
- textColorToken: "accent",
9349
+ background: {
9350
+ type: "surface",
9351
+ role: "link"
9352
+ },
9036
9353
  borderRadius: "rounded-none",
9037
9354
  sizes: {
9038
9355
  sm: { padding: "0.25rem 0" },
@@ -9054,19 +9371,17 @@ const editorialLink = defineButtonPersonality({
9054
9371
  name: "Ghost",
9055
9372
  enabled: true,
9056
9373
  priority: 3,
9057
- background: { type: "transparent" },
9058
- textColorToken: "mutedText",
9374
+ background: {
9375
+ type: "surface",
9376
+ role: "link"
9377
+ },
9059
9378
  borderRadius: "rounded-none",
9060
9379
  sizes: {
9061
9380
  sm: { padding: "0.25rem 0" },
9062
9381
  md: { padding: "0.5rem 0" },
9063
9382
  lg: { padding: "0.625rem 0" },
9064
9383
  xl: { padding: "0.75rem 0" }
9065
- },
9066
- effects: { hover: [{
9067
- effectId: "opacity-reduce",
9068
- options: { reduction: -20 }
9069
- }] }
9384
+ }
9070
9385
  }
9071
9386
  ]
9072
9387
  }
@@ -9128,12 +9443,8 @@ const flatInk = defineButtonPersonality({
9128
9443
  type: "solid",
9129
9444
  colorToken: "primary"
9130
9445
  },
9131
- textColorToken: "primaryForeground",
9132
9446
  borderRadius: "rounded-lg",
9133
- affordance: {
9134
- iconId: "ArrowRight",
9135
- colorToken: "accent"
9136
- },
9447
+ affordance: { iconId: "ArrowRight" },
9137
9448
  effects: { hover: [{
9138
9449
  effectId: "lift",
9139
9450
  options: { translateY: "-2px" }
@@ -9147,13 +9458,12 @@ const flatInk = defineButtonPersonality({
9147
9458
  name: "Secondary",
9148
9459
  enabled: true,
9149
9460
  priority: 2,
9150
- background: { type: "transparent" },
9151
- textColorToken: "primary",
9152
- borderRadius: "rounded-lg",
9153
- border: {
9154
- widthClass: "border",
9155
- colorToken: "border"
9461
+ background: {
9462
+ type: "surface",
9463
+ role: "link"
9156
9464
  },
9465
+ borderRadius: "rounded-lg",
9466
+ border: { widthClass: "border" },
9157
9467
  effects: { hover: [{
9158
9468
  effectId: "lift",
9159
9469
  options: { translateY: "-2px" }
@@ -9171,12 +9481,8 @@ const flatInk = defineButtonPersonality({
9171
9481
  type: "solid",
9172
9482
  colorToken: "accent"
9173
9483
  },
9174
- textColorToken: "accentForeground",
9175
9484
  borderRadius: "rounded-lg",
9176
- affordance: {
9177
- iconId: "ArrowRight",
9178
- colorToken: "accentForeground"
9179
- },
9485
+ affordance: { iconId: "ArrowRight" },
9180
9486
  effects: { hover: [{
9181
9487
  effectId: "lift",
9182
9488
  options: { translateY: "-2px" }
@@ -9239,7 +9545,6 @@ const inkStamp = defineButtonPersonality({
9239
9545
  type: "solid",
9240
9546
  colorToken: "primary"
9241
9547
  },
9242
- textColorToken: "primaryForeground",
9243
9548
  borderRadius: "rounded-md",
9244
9549
  effects: {
9245
9550
  hover: [{
@@ -9260,13 +9565,12 @@ const inkStamp = defineButtonPersonality({
9260
9565
  name: "Secondary",
9261
9566
  enabled: true,
9262
9567
  priority: 2,
9263
- background: { type: "transparent" },
9264
- textColorToken: "primary",
9265
- borderRadius: "rounded-md",
9266
- border: {
9267
- widthClass: "border-2",
9268
- colorToken: "primary"
9568
+ background: {
9569
+ type: "surface",
9570
+ role: "link"
9269
9571
  },
9572
+ borderRadius: "rounded-md",
9573
+ border: { widthClass: "border-2" },
9270
9574
  effects: { hover: [{
9271
9575
  effectId: "background-on-hover",
9272
9576
  options: { colorToken: "surface" }
@@ -9277,13 +9581,12 @@ const inkStamp = defineButtonPersonality({
9277
9581
  name: "Outline",
9278
9582
  enabled: true,
9279
9583
  priority: 3,
9280
- background: { type: "transparent" },
9281
- textColorToken: "text",
9282
- borderRadius: "rounded-md",
9283
- border: {
9284
- widthClass: "border-2",
9285
- colorToken: "border"
9584
+ background: {
9585
+ type: "surface",
9586
+ role: "link"
9286
9587
  },
9588
+ borderRadius: "rounded-md",
9589
+ border: { widthClass: "border-2" },
9287
9590
  effects: { hover: [{
9288
9591
  effectId: "background-on-hover",
9289
9592
  options: { colorToken: "surface" }
@@ -9294,8 +9597,10 @@ const inkStamp = defineButtonPersonality({
9294
9597
  name: "Ghost",
9295
9598
  enabled: true,
9296
9599
  priority: 3,
9297
- background: { type: "transparent" },
9298
- textColorToken: "accent",
9600
+ background: {
9601
+ type: "surface",
9602
+ role: "link"
9603
+ },
9299
9604
  borderRadius: "rounded-none",
9300
9605
  sizes: {
9301
9606
  sm: {
@@ -9388,7 +9693,6 @@ const joyStamp = defineButtonPersonality({
9388
9693
  type: "solid",
9389
9694
  colorToken: "primary"
9390
9695
  },
9391
- textColorToken: "primaryForeground",
9392
9696
  borderRadius: "rounded-full",
9393
9697
  shadow: {
9394
9698
  elevation: "high",
@@ -9402,13 +9706,12 @@ const joyStamp = defineButtonPersonality({
9402
9706
  name: "Secondary",
9403
9707
  enabled: true,
9404
9708
  priority: 2,
9405
- background: { type: "transparent" },
9406
- textColorToken: "text",
9407
- borderRadius: "rounded-full",
9408
- border: {
9409
- widthClass: "border-2",
9410
- colorToken: "text"
9709
+ background: {
9710
+ type: "surface",
9711
+ role: "link"
9411
9712
  },
9713
+ borderRadius: "rounded-full",
9714
+ border: { widthClass: "border-2" },
9412
9715
  shadow: {
9413
9716
  elevation: "high",
9414
9717
  softness: "hard",
@@ -9473,12 +9776,8 @@ const ornateRitual = defineButtonPersonality({
9473
9776
  type: "solid",
9474
9777
  colorToken: "primary"
9475
9778
  },
9476
- textColorToken: "primaryForeground",
9477
9779
  borderRadius: "rounded-md",
9478
- border: {
9479
- widthClass: "border",
9480
- colorToken: "primary"
9481
- },
9780
+ border: { widthClass: "border" },
9482
9781
  effects: {
9483
9782
  hover: [{
9484
9783
  effectId: "background-on-hover",
@@ -9499,12 +9798,8 @@ const ornateRitual = defineButtonPersonality({
9499
9798
  type: "solid",
9500
9799
  colorToken: "secondary"
9501
9800
  },
9502
- textColorToken: "primaryForeground",
9503
9801
  borderRadius: "rounded-md",
9504
- border: {
9505
- widthClass: "border",
9506
- colorToken: "primary"
9507
- },
9802
+ border: { widthClass: "border" },
9508
9803
  effects: { hover: [{
9509
9804
  effectId: "background-on-hover",
9510
9805
  options: { colorToken: "surface" }
@@ -9515,13 +9810,12 @@ const ornateRitual = defineButtonPersonality({
9515
9810
  name: "Outline",
9516
9811
  enabled: true,
9517
9812
  priority: 3,
9518
- background: { type: "transparent" },
9519
- textColorToken: "primary",
9520
- borderRadius: "rounded-md",
9521
- border: {
9522
- widthClass: "border",
9523
- colorToken: "primary"
9813
+ background: {
9814
+ type: "surface",
9815
+ role: "link"
9524
9816
  },
9817
+ borderRadius: "rounded-md",
9818
+ border: { widthClass: "border" },
9525
9819
  effects: { hover: [{
9526
9820
  effectId: "background-on-hover",
9527
9821
  options: { colorToken: "muted" }
@@ -9532,8 +9826,10 @@ const ornateRitual = defineButtonPersonality({
9532
9826
  name: "Ghost",
9533
9827
  enabled: true,
9534
9828
  priority: 3,
9535
- background: { type: "transparent" },
9536
- textColorToken: "accent",
9829
+ background: {
9830
+ type: "surface",
9831
+ role: "link"
9832
+ },
9537
9833
  borderRadius: "rounded-none",
9538
9834
  sizes: {
9539
9835
  sm: {
@@ -9615,14 +9911,10 @@ const pebble = defineButtonPersonality({
9615
9911
  type: "solid",
9616
9912
  colorToken: "primary"
9617
9913
  },
9618
- textColorToken: "primaryForeground",
9619
9914
  borderRadius: "rounded-full",
9620
9915
  effects: { hover: [{
9621
- effectId: "background-on-hover-alpha",
9622
- options: {
9623
- colorToken: "primary",
9624
- opacity: 88
9625
- }
9916
+ effectId: "darken-background",
9917
+ options: { amount: 100 }
9626
9918
  }] }
9627
9919
  },
9628
9920
  {
@@ -9630,13 +9922,12 @@ const pebble = defineButtonPersonality({
9630
9922
  name: "Secondary",
9631
9923
  enabled: true,
9632
9924
  priority: 2,
9633
- background: { type: "transparent" },
9634
- textColorToken: "primary",
9635
- borderRadius: "rounded-full",
9636
- border: {
9637
- widthClass: "border-2",
9638
- colorToken: "accent"
9925
+ background: {
9926
+ type: "surface",
9927
+ role: "link"
9639
9928
  },
9929
+ borderRadius: "rounded-full",
9930
+ border: { widthClass: "border-2" },
9640
9931
  effects: { hover: [{
9641
9932
  effectId: "background-on-hover",
9642
9933
  options: { colorToken: "accent" }
@@ -9647,13 +9938,12 @@ const pebble = defineButtonPersonality({
9647
9938
  name: "Outline",
9648
9939
  enabled: true,
9649
9940
  priority: 3,
9650
- background: { type: "transparent" },
9651
- textColorToken: "text",
9652
- borderRadius: "rounded-full",
9653
- border: {
9654
- widthClass: "border",
9655
- colorToken: "border"
9941
+ background: {
9942
+ type: "surface",
9943
+ role: "link"
9656
9944
  },
9945
+ borderRadius: "rounded-full",
9946
+ border: { widthClass: "border" },
9657
9947
  effects: { hover: [{
9658
9948
  effectId: "background-on-hover",
9659
9949
  options: { colorToken: "surface" }
@@ -9664,8 +9954,10 @@ const pebble = defineButtonPersonality({
9664
9954
  name: "Ghost",
9665
9955
  enabled: true,
9666
9956
  priority: 3,
9667
- background: { type: "transparent" },
9668
- textColorToken: "primary",
9957
+ background: {
9958
+ type: "surface",
9959
+ role: "link"
9960
+ },
9669
9961
  borderRadius: "rounded-full",
9670
9962
  sizes: {
9671
9963
  sm: {
@@ -9681,11 +9973,7 @@ const pebble = defineButtonPersonality({
9681
9973
  padding: "0.75rem 1.5rem",
9682
9974
  fontSize: "text-xl"
9683
9975
  }
9684
- },
9685
- effects: { hover: [{
9686
- effectId: "opacity-reduce",
9687
- options: { reduction: 30 }
9688
- }] }
9976
+ }
9689
9977
  }
9690
9978
  ]
9691
9979
  }
@@ -9747,15 +10035,11 @@ const quietArrow = defineButtonPersonality({
9747
10035
  type: "solid",
9748
10036
  colorToken: "primary"
9749
10037
  },
9750
- textColorToken: "primaryForeground",
9751
10038
  borderRadius: "rounded-xl",
9752
10039
  affordance: { iconId: "ArrowRight" },
9753
10040
  effects: { hover: [{
9754
- effectId: "background-on-hover-alpha",
9755
- options: {
9756
- colorToken: "primary",
9757
- opacity: 90
9758
- }
10041
+ effectId: "darken-background",
10042
+ options: { amount: 100 }
9759
10043
  }] }
9760
10044
  },
9761
10045
  {
@@ -9763,13 +10047,12 @@ const quietArrow = defineButtonPersonality({
9763
10047
  name: "Secondary",
9764
10048
  enabled: true,
9765
10049
  priority: 2,
9766
- background: { type: "transparent" },
9767
- textColorToken: "primary",
9768
- borderRadius: "rounded-xl",
9769
- border: {
9770
- widthClass: "border",
9771
- colorToken: "primary"
10050
+ background: {
10051
+ type: "surface",
10052
+ role: "link"
9772
10053
  },
10054
+ borderRadius: "rounded-xl",
10055
+ border: { widthClass: "border" },
9773
10056
  affordance: { iconId: "ArrowRight" },
9774
10057
  effects: { hover: [{
9775
10058
  effectId: "background-on-hover",
@@ -9781,21 +10064,22 @@ const quietArrow = defineButtonPersonality({
9781
10064
  name: "Outline",
9782
10065
  enabled: true,
9783
10066
  priority: 3,
9784
- background: { type: "transparent" },
9785
- textColorToken: "primary",
10067
+ background: {
10068
+ type: "surface",
10069
+ role: "link"
10070
+ },
9786
10071
  borderRadius: "rounded-xl",
9787
- border: {
9788
- widthClass: "border",
9789
- colorToken: "primary"
9790
- }
10072
+ border: { widthClass: "border" }
9791
10073
  },
9792
10074
  {
9793
10075
  id: "ghost",
9794
10076
  name: "Ghost",
9795
10077
  enabled: true,
9796
10078
  priority: 3,
9797
- background: { type: "transparent" },
9798
- textColorToken: "primary",
10079
+ background: {
10080
+ type: "surface",
10081
+ role: "link"
10082
+ },
9799
10083
  borderRadius: "rounded-xl"
9800
10084
  }
9801
10085
  ]
@@ -9859,7 +10143,6 @@ const showtimePill = defineButtonPersonality({
9859
10143
  type: "solid",
9860
10144
  colorToken: "primary"
9861
10145
  },
9862
- textColorToken: "background",
9863
10146
  borderRadius: "rounded-full",
9864
10147
  effects: { hover: [{ effectId: "pop" }] }
9865
10148
  },
@@ -9868,13 +10151,12 @@ const showtimePill = defineButtonPersonality({
9868
10151
  name: "Secondary",
9869
10152
  enabled: true,
9870
10153
  priority: 2,
9871
- background: { type: "transparent" },
9872
- textColorToken: "primary",
9873
- borderRadius: "rounded-full",
9874
- border: {
9875
- widthClass: "border-2",
9876
- colorToken: "primary"
10154
+ background: {
10155
+ type: "surface",
10156
+ role: "link"
9877
10157
  },
10158
+ borderRadius: "rounded-full",
10159
+ border: { widthClass: "border-2" },
9878
10160
  effects: { hover: [{ effectId: "pop" }] }
9879
10161
  },
9880
10162
  {
@@ -9886,7 +10168,6 @@ const showtimePill = defineButtonPersonality({
9886
10168
  type: "solid",
9887
10169
  colorToken: "secondary"
9888
10170
  },
9889
- textColorToken: "primary",
9890
10171
  borderRadius: "rounded-full",
9891
10172
  effects: { hover: [{ effectId: "pop" }] }
9892
10173
  },
@@ -9899,12 +10180,8 @@ const showtimePill = defineButtonPersonality({
9899
10180
  type: "solid",
9900
10181
  colorToken: "background"
9901
10182
  },
9902
- textColorToken: "primary",
9903
10183
  borderRadius: "rounded-full",
9904
- border: {
9905
- widthClass: "border-2",
9906
- colorToken: "primary"
9907
- },
10184
+ border: { widthClass: "border-2" },
9908
10185
  effects: { hover: [{
9909
10186
  effectId: "background-on-hover",
9910
10187
  options: { colorToken: "surface" }
@@ -9915,13 +10192,12 @@ const showtimePill = defineButtonPersonality({
9915
10192
  name: "Outline",
9916
10193
  enabled: true,
9917
10194
  priority: 3,
9918
- background: { type: "transparent" },
9919
- textColorToken: "primary",
9920
- borderRadius: "rounded-full",
9921
- border: {
9922
- widthClass: "border-2",
9923
- colorToken: "primary"
10195
+ background: {
10196
+ type: "surface",
10197
+ role: "link"
9924
10198
  },
10199
+ borderRadius: "rounded-full",
10200
+ border: { widthClass: "border-2" },
9925
10201
  effects: { hover: [{
9926
10202
  effectId: "background-on-hover",
9927
10203
  options: { colorToken: "background" }
@@ -9932,8 +10208,10 @@ const showtimePill = defineButtonPersonality({
9932
10208
  name: "Ghost",
9933
10209
  enabled: true,
9934
10210
  priority: 3,
9935
- background: { type: "transparent" },
9936
- textColorToken: "primary",
10211
+ background: {
10212
+ type: "surface",
10213
+ role: "link"
10214
+ },
9937
10215
  borderRadius: "rounded-full",
9938
10216
  effects: { hover: [{
9939
10217
  effectId: "background-on-hover",
@@ -9979,7 +10257,6 @@ const softPill = defineButtonPersonality({
9979
10257
  type: "solid",
9980
10258
  colorToken: "primary"
9981
10259
  },
9982
- textColorToken: "primaryForeground",
9983
10260
  borderRadius: "rounded-full",
9984
10261
  shadow: {
9985
10262
  elevation: "low",
@@ -10002,13 +10279,12 @@ const softPill = defineButtonPersonality({
10002
10279
  name: "Secondary",
10003
10280
  enabled: true,
10004
10281
  priority: 2,
10005
- background: { type: "transparent" },
10006
- textColorToken: "primary",
10007
- borderRadius: "rounded-full",
10008
- border: {
10009
- widthClass: "border-2",
10010
- colorToken: "primary"
10282
+ background: {
10283
+ type: "surface",
10284
+ role: "link"
10011
10285
  },
10286
+ borderRadius: "rounded-full",
10287
+ border: { widthClass: "border-2" },
10012
10288
  effects: { hover: [{
10013
10289
  effectId: "background-on-hover",
10014
10290
  options: { colorToken: "surface" }
@@ -10019,13 +10295,12 @@ const softPill = defineButtonPersonality({
10019
10295
  name: "Outline",
10020
10296
  enabled: true,
10021
10297
  priority: 3,
10022
- background: { type: "transparent" },
10023
- textColorToken: "text",
10024
- borderRadius: "rounded-full",
10025
- border: {
10026
- widthClass: "border",
10027
- colorToken: "border"
10298
+ background: {
10299
+ type: "surface",
10300
+ role: "link"
10028
10301
  },
10302
+ borderRadius: "rounded-full",
10303
+ border: { widthClass: "border" },
10029
10304
  effects: { hover: [{
10030
10305
  effectId: "background-on-hover",
10031
10306
  options: { colorToken: "surface" }
@@ -10036,8 +10311,10 @@ const softPill = defineButtonPersonality({
10036
10311
  name: "Ghost",
10037
10312
  enabled: true,
10038
10313
  priority: 3,
10039
- background: { type: "transparent" },
10040
- textColorToken: "text",
10314
+ background: {
10315
+ type: "surface",
10316
+ role: "link"
10317
+ },
10041
10318
  borderRadius: "rounded-full",
10042
10319
  effects: { hover: [{
10043
10320
  effectId: "background-on-hover",
@@ -10056,9 +10333,8 @@ const solidSecondary = {
10056
10333
  priority: 2,
10057
10334
  background: {
10058
10335
  type: "solid",
10059
- colorToken: "secondary"
10336
+ colorToken: unsafeAsOpaqueButtonColourToken("secondary")
10060
10337
  },
10061
- textColorToken: "onSecondary",
10062
10338
  borderRadius: "rounded-full",
10063
10339
  shadow: {
10064
10340
  elevation: "none",
@@ -10491,6 +10767,282 @@ const serifDisplayQuote = { style: "serif-display" };
10491
10767
  /** Punchy quotation mark in the secondary accent colour. Bold / accent styles. */
10492
10768
  const accentGlyphQuote = { style: "accent-glyph" };
10493
10769
  //#endregion
10770
+ //#region ../theme-core/src/gradients/types.ts
10771
+ /**
10772
+ * Gradient configuration types and schemas
10773
+ */
10774
+ /**
10775
+ * Gradient color stop
10776
+ */
10777
+ const gradientStopSchema = z$1.object({
10778
+ color: themeColorTokenSchema,
10779
+ position: z$1.number().min(0).max(100)
10780
+ });
10781
+ /**
10782
+ * Radial gradient shape. Optional; defaults to `circle` (the historical shape)
10783
+ * so existing radial gradients are byte-identical.
10784
+ *
10785
+ * Named `RadialGradientShape` to avoid clashing with `styles/gradients.ts`'s
10786
+ * `GradientShape` (which names the gradient *kind*: linear/radial/conic).
10787
+ */
10788
+ const radialGradientShapeSchema = z$1.enum(["circle", "ellipse"]);
10789
+ /**
10790
+ * Gradient configuration.
10791
+ *
10792
+ * `type` is optional and defaults to `'linear'` so gradients persisted without a
10793
+ * type (or with an explicit `'linear'`) render exactly as before. `'radial'` and
10794
+ * `'conic'` are additive kinds:
10795
+ * - linear: `angle` (degrees)
10796
+ * - radial: optional `shape` (circle/ellipse) + `position`
10797
+ * - conic: optional `angle` (from-angle, degrees) + `position`
10798
+ */
10799
+ const gradientConfigSchema = z$1.object({
10800
+ type: z$1.enum([
10801
+ "linear",
10802
+ "radial",
10803
+ "conic"
10804
+ ]).default("linear"),
10805
+ angle: z$1.number().min(0).max(360).optional(),
10806
+ shape: radialGradientShapeSchema.optional(),
10807
+ position: z$1.string().optional(),
10808
+ stops: z$1.array(gradientStopSchema).min(2)
10809
+ });
10810
+ /**
10811
+ * Curated library of gradient presets.
10812
+ * All gradients use theme color tokens, so they adapt to the site's palette.
10813
+ */
10814
+ const GRADIENT_PRESETS = [
10815
+ {
10816
+ id: "primary-secondary",
10817
+ name: "Primary to Secondary",
10818
+ description: "Blend your primary and secondary brand colors",
10819
+ type: "linear",
10820
+ angle: 135,
10821
+ stops: [{
10822
+ color: "primary-500",
10823
+ position: 0
10824
+ }, {
10825
+ color: "secondary-500",
10826
+ position: 100
10827
+ }]
10828
+ },
10829
+ {
10830
+ id: "primary-accent",
10831
+ name: "Primary to Accent",
10832
+ description: "Energetic gradient from primary to accent",
10833
+ type: "linear",
10834
+ angle: 135,
10835
+ stops: [{
10836
+ color: "primary-500",
10837
+ position: 0
10838
+ }, {
10839
+ color: "accent-500",
10840
+ position: 100
10841
+ }]
10842
+ },
10843
+ {
10844
+ id: "secondary-accent",
10845
+ name: "Secondary to Accent",
10846
+ description: "Vibrant secondary to accent blend",
10847
+ type: "linear",
10848
+ angle: 135,
10849
+ stops: [{
10850
+ color: "secondary-500",
10851
+ position: 0
10852
+ }, {
10853
+ color: "accent-500",
10854
+ position: 100
10855
+ }]
10856
+ },
10857
+ {
10858
+ id: "primary-light-dark",
10859
+ name: "Primary Light to Dark",
10860
+ description: "Subtle primary color fade",
10861
+ type: "linear",
10862
+ angle: 180,
10863
+ stops: [{
10864
+ color: "primary-500",
10865
+ position: 0
10866
+ }, {
10867
+ color: "primary-900",
10868
+ position: 100
10869
+ }]
10870
+ },
10871
+ {
10872
+ id: "primary-dark-light",
10873
+ name: "Primary Dark to Light",
10874
+ description: "Reverse primary fade",
10875
+ type: "linear",
10876
+ angle: 180,
10877
+ stops: [{
10878
+ color: "primary-900",
10879
+ position: 0
10880
+ }, {
10881
+ color: "primary-50",
10882
+ position: 100
10883
+ }]
10884
+ },
10885
+ {
10886
+ id: "secondary-light-dark",
10887
+ name: "Secondary Light to Dark",
10888
+ description: "Subtle secondary color fade",
10889
+ type: "linear",
10890
+ angle: 180,
10891
+ stops: [{
10892
+ color: "secondary-500",
10893
+ position: 0
10894
+ }, {
10895
+ color: "secondary-900",
10896
+ position: 100
10897
+ }]
10898
+ },
10899
+ {
10900
+ id: "accent-light-dark",
10901
+ name: "Accent Light to Dark",
10902
+ description: "Accent color depth fade",
10903
+ type: "linear",
10904
+ angle: 180,
10905
+ stops: [{
10906
+ color: "accent-500",
10907
+ position: 0
10908
+ }, {
10909
+ color: "accent-900",
10910
+ position: 100
10911
+ }]
10912
+ },
10913
+ {
10914
+ id: "background-surface",
10915
+ name: "Background to Surface",
10916
+ description: "Subtle depth using base colors",
10917
+ type: "linear",
10918
+ angle: 180,
10919
+ stops: [{
10920
+ color: "background",
10921
+ position: 0
10922
+ }, {
10923
+ color: "surface",
10924
+ position: 100
10925
+ }]
10926
+ },
10927
+ {
10928
+ id: "neutral-fade",
10929
+ name: "Neutral Gradient",
10930
+ description: "Elegant neutral color fade",
10931
+ type: "linear",
10932
+ angle: 180,
10933
+ stops: [{
10934
+ color: "neutral-900",
10935
+ position: 0
10936
+ }, {
10937
+ color: "neutral-50",
10938
+ position: 100
10939
+ }]
10940
+ },
10941
+ {
10942
+ id: "primary-glow",
10943
+ name: "Primary glow",
10944
+ description: "A soft top-centred glow using your primary palette",
10945
+ type: "radial",
10946
+ shape: "ellipse",
10947
+ position: "top center",
10948
+ stops: [{
10949
+ color: "primary-900",
10950
+ position: 0
10951
+ }, {
10952
+ color: "primary-950",
10953
+ position: 100
10954
+ }],
10955
+ foreground: {
10956
+ textColor: "onPrimary900",
10957
+ headingColor: "onPrimary900",
10958
+ linkColor: "onPrimary900",
10959
+ supportingColor: "onPrimary900"
10960
+ }
10961
+ },
10962
+ {
10963
+ id: "accent-glow",
10964
+ name: "Accent glow",
10965
+ description: "A soft top-centred glow using your accent palette",
10966
+ type: "radial",
10967
+ shape: "ellipse",
10968
+ position: "top center",
10969
+ stops: [{
10970
+ color: "accent-900",
10971
+ position: 0
10972
+ }, {
10973
+ color: "accent-950",
10974
+ position: 100
10975
+ }],
10976
+ foreground: {
10977
+ textColor: "onAccent900",
10978
+ headingColor: "onAccent900",
10979
+ linkColor: "onAccent900",
10980
+ supportingColor: "onAccent900"
10981
+ }
10982
+ },
10983
+ {
10984
+ id: "primary-secondary-accent",
10985
+ name: "Brand Trio",
10986
+ description: "All three brand colors in harmony",
10987
+ type: "linear",
10988
+ angle: 135,
10989
+ stops: [
10990
+ {
10991
+ color: "primary-500",
10992
+ position: 0
10993
+ },
10994
+ {
10995
+ color: "secondary-500",
10996
+ position: 50
10997
+ },
10998
+ {
10999
+ color: "accent-500",
11000
+ position: 100
11001
+ }
11002
+ ]
11003
+ }
11004
+ ].map((preset) => ({
11005
+ ...preset,
11006
+ id: preset.id,
11007
+ stops: preset.stops
11008
+ }));
11009
+ const GRADIENT_PRESET_IDS = GRADIENT_PRESETS.map((preset) => preset.id);
11010
+ const gradientPresetIdSet = new Set(GRADIENT_PRESET_IDS);
11011
+ const gradientPresetById = Object.fromEntries(GRADIENT_PRESETS.map((preset) => [preset.id, preset]));
11012
+ function parseGradientPresetId(value) {
11013
+ if (typeof value !== "string") return null;
11014
+ const normalized = value.trim();
11015
+ if (!gradientPresetIdSet.has(normalized)) return null;
11016
+ return normalized;
11017
+ }
11018
+ function getGradientPreset(id) {
11019
+ return gradientPresetById[id];
11020
+ }
11021
+ //#endregion
11022
+ //#region ../theme-core/src/gradients/utils.ts
11023
+ /**
11024
+ * Convert a GradientConfig to a CSS gradient string
11025
+ *
11026
+ * @param config - The gradient configuration using theme tokens
11027
+ * @param tokens - Map of theme color tokens to hex values
11028
+ * @returns CSS gradient string (e.g., "linear-gradient(180deg, #3b82f6 0%, #f59e0b 100%)")
11029
+ */
11030
+ function gradientToCss(config, tokens) {
11031
+ const stops = config.stops.map((stop) => {
11032
+ return `${tokens[stop.color] ?? "#000000"} ${stop.position}%`;
11033
+ }).join(", ");
11034
+ const type = config.type ?? "linear";
11035
+ if (type === "radial") {
11036
+ const position = config.position ?? "center";
11037
+ return `radial-gradient(${config.shape ?? "circle"} at ${position}, ${stops})`;
11038
+ }
11039
+ if (type === "conic") {
11040
+ const position = config.position ?? "center";
11041
+ return `conic-gradient(from ${config.angle ?? 0}deg at ${position}, ${stops})`;
11042
+ }
11043
+ return `linear-gradient(${config.angle ?? 180}deg, ${stops})`;
11044
+ }
11045
+ //#endregion
10494
11046
  //#region ../theme-core/src/site-styles/logoBranding.ts
10495
11047
  const logoTextConfidenceValues = [
10496
11048
  "low",
@@ -12816,14 +13368,12 @@ const backgroundOnHoverEffect = {
12816
13368
  ]
12817
13369
  },
12818
13370
  generateCSS: (ctx) => {
12819
- const { themeId, variantId, options, tokens } = ctx;
13371
+ const { themeId, variantId, options, tokens, buttonConfig } = ctx;
12820
13372
  const colorToken = options.colorToken || "neutral-800";
12821
- const color = tokens.getColor(colorToken);
12822
- const textColorToken = typeof options.textColorToken === "string" ? options.textColorToken : null;
12823
13373
  return `
12824
13374
  /* Add background on hover */
12825
13375
  :where([data-theme-scope="${themeId}"]) .${variantId}:hover {
12826
- background-color: ${color};${textColorToken ? `\n color: ${tokens.getColor(textColorToken)};` : ""}
13376
+ background-color: ${tokens.getColor(colorToken)};${"textColorToken" in buttonConfig && typeof options.textColorToken === "string" ? `\n color: ${tokens.getColor(options.textColorToken)};` : ""}
12827
13377
  }
12828
13378
  `;
12829
13379
  }
@@ -12847,10 +13397,10 @@ const backgroundOnHoverAlphaEffect = {
12847
13397
  default: 50
12848
13398
  },
12849
13399
  generateCSS: (ctx) => {
12850
- const { themeId, variantId, stateGroup, options, buttonConfig } = ctx;
13400
+ const { themeId, variantId, stateGroup, options } = ctx;
12851
13401
  const rawOpacity = options.opacity;
12852
13402
  const clampedOpacity = Math.max(0, Math.min(100, typeof rawOpacity === "number" && !Number.isNaN(rawOpacity) ? rawOpacity : 50));
12853
- const cssVar = `var(--tb-${options.colorToken || buttonConfig.textColorToken || "neutral-800"})`;
13403
+ const cssVar = `var(--tb-${options.colorToken || "neutral-800"})`;
12854
13404
  return `
12855
13405
  /* Add semi-transparent background (${stateGroup}) */
12856
13406
  :where([data-theme-scope="${themeId}"]) .${variantId}${stateGroup === "base" ? "" : `:${stateGroup}`} {
@@ -13063,7 +13613,7 @@ const outerGlowEffect = {
13063
13613
  const spread = options.spread || 10;
13064
13614
  let glowColor;
13065
13615
  if (options.glowColorToken && typeof options.glowColorToken === "string") glowColor = tokens.getColor(options.glowColorToken);
13066
- else if (buttonConfig.border?.colorToken) glowColor = tokens.getColor(buttonConfig.border.colorToken);
13616
+ else if (buttonConfig.border) glowColor = "colorToken" in buttonConfig.border ? tokens.getColor(buttonConfig.border.colorToken) : "currentColor";
13067
13617
  else if (buttonConfig.background.type === "solid") glowColor = tokens.getColor(buttonConfig.background.colorToken ?? "primary-400");
13068
13618
  else glowColor = tokens.getColor("primary-400");
13069
13619
  return `
@@ -14053,31 +14603,6 @@ function generateSingleEffectCSS(themeId, variantId, stateGroup, effectApp, elem
14053
14603
  return effectPreset.generateCSS(ctx);
14054
14604
  }
14055
14605
  //#endregion
14056
- //#region ../theme-core/src/buttons/utils/contrast.ts
14057
- /**
14058
- * Get contrasting text color for a button background
14059
- *
14060
- * This function returns theme-aware text colors using the neutral scale,
14061
- * which is guaranteed to exist in every theme and harmonizes with the design.
14062
- *
14063
- * Uses neutral-50 (lightest) for dark backgrounds and neutral-950 (darkest)
14064
- * for light backgrounds. This ensures excellent contrast while respecting
14065
- * the theme's neutral palette (warm/cool tinting).
14066
- *
14067
- * For solid backgrounds with primary/secondary/neutral colors:
14068
- * - Dark backgrounds (shade >= 500): neutral-50 (very light)
14069
- * - Light backgrounds (shade < 500): neutral-950 (very dark)
14070
- */
14071
- function getContrastingTextColorToken(backgroundToken, theme) {
14072
- const isLightTheme = theme.palette.meta.mode === "light";
14073
- if (backgroundToken.startsWith("primary-") || backgroundToken.startsWith("secondary-")) return "neutral-50";
14074
- if (backgroundToken.startsWith("neutral-")) {
14075
- const match = backgroundToken.match(/neutral-(\d+)/);
14076
- if (match?.[1]) return parseInt(match[1], 10) >= 500 ? "neutral-50" : "neutral-950";
14077
- }
14078
- return isLightTheme ? "neutral-50" : "neutral-950";
14079
- }
14080
- //#endregion
14081
14606
  //#region ../theme-core/src/buttons/generateDefaultButtonSystem.ts
14082
14607
  /**
14083
14608
  * Map border width to border width class
@@ -14134,13 +14659,8 @@ function generateDefaultButtonSystem(theme) {
14134
14659
  priority: 1,
14135
14660
  background: {
14136
14661
  type: "solid",
14137
- colorToken: "primary"
14138
- },
14139
- textColorToken: getContrastingTextColorToken("primary", theme),
14140
- effects: { hover: [{
14141
- effectId: "opacity-reduce",
14142
- options: { reduction: 15 }
14143
- }] }
14662
+ colorToken: unsafeAsOpaqueButtonColourToken("primary")
14663
+ }
14144
14664
  },
14145
14665
  {
14146
14666
  id: "secondary",
@@ -14149,51 +14669,39 @@ function generateDefaultButtonSystem(theme) {
14149
14669
  priority: 2,
14150
14670
  background: {
14151
14671
  type: "solid",
14152
- colorToken: "neutral-700"
14153
- },
14154
- textColorToken: getContrastingTextColorToken("neutral-700", theme),
14155
- effects: { hover: [{
14156
- effectId: "opacity-reduce",
14157
- options: { reduction: 15 }
14158
- }] }
14672
+ colorToken: unsafeAsOpaqueButtonColourToken("neutral-700")
14673
+ }
14159
14674
  },
14160
14675
  {
14161
14676
  id: "outline",
14162
14677
  name: "Outline",
14163
14678
  enabled: true,
14164
14679
  priority: 3,
14165
- background: { type: "transparent" },
14166
- textColorToken: "primary",
14680
+ background: {
14681
+ type: "surface",
14682
+ role: "link"
14683
+ },
14167
14684
  shadow: {
14168
14685
  elevation: "none",
14169
14686
  softness: null,
14170
14687
  position: "bottom"
14171
14688
  },
14172
- border: {
14173
- colorToken: "primary",
14174
- widthClass: borderWidthClass
14175
- },
14176
- effects: { hover: [{
14177
- effectId: "opacity-reduce",
14178
- options: { reduction: 15 }
14179
- }] }
14689
+ border: { widthClass: borderWidthClass }
14180
14690
  },
14181
14691
  {
14182
14692
  id: "ghost",
14183
14693
  name: "Ghost",
14184
14694
  enabled: true,
14185
14695
  priority: 3,
14186
- background: { type: "transparent" },
14187
- textColorToken: "primary",
14696
+ background: {
14697
+ type: "surface",
14698
+ role: "link"
14699
+ },
14188
14700
  shadow: {
14189
14701
  elevation: "none",
14190
14702
  softness: null,
14191
14703
  position: "bottom"
14192
- },
14193
- effects: { hover: [{
14194
- effectId: "opacity-reduce",
14195
- options: { reduction: 15 }
14196
- }] }
14704
+ }
14197
14705
  }
14198
14706
  ];
14199
14707
  return {
@@ -14249,6 +14757,472 @@ function affordanceIconMaskUrl(iconId) {
14249
14757
  return `data:image/svg+xml,${`<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'>${paths.map((d) => `<path d='${d}'/>`).join("")}</svg>`.replace(/"/g, "'").replace(/#/g, "%23").replace(/</g, "%3C").replace(/>/g, "%3E").replace(/\s+/g, " ")}`;
14250
14758
  }
14251
14759
  //#endregion
14760
+ //#region ../theme-core/src/surfaces/foregroundRoles.ts
14761
+ const SURFACE_FOREGROUND_ROLES = [
14762
+ "text",
14763
+ "heading",
14764
+ "link",
14765
+ "supporting"
14766
+ ];
14767
+ //#endregion
14768
+ //#region ../theme-core/src/surfaces/foregroundContract.ts
14769
+ const SURFACE_FOREGROUND_CSS_VARS = {
14770
+ text: "--rb-surface-text-color",
14771
+ heading: "--rb-surface-heading-color",
14772
+ link: "--rb-surface-link-color",
14773
+ supporting: "--rb-surface-supporting-color"
14774
+ };
14775
+ const DEFAULT_SURFACE_TEXT_COLOR = "rgb(var(--tb-text, 17 24 39))";
14776
+ const DEFAULT_ROLE_FALLBACKS = {
14777
+ text: DEFAULT_SURFACE_TEXT_COLOR,
14778
+ heading: DEFAULT_SURFACE_TEXT_COLOR,
14779
+ link: "rgb(var(--tb-primary, var(--tb-text, 17 24 39)))",
14780
+ supporting: "rgb(var(--tb-mutedText, 100 116 139))"
14781
+ };
14782
+ function requireSurfaceColorValue(role, value) {
14783
+ const normalized = value.trim();
14784
+ if (normalized.length === 0) throw new RangeError(`Surface foreground ${role} must be a non-empty CSS color.`);
14785
+ return normalized;
14786
+ }
14787
+ function completeSurfaceForegrounds(input) {
14788
+ const text = requireSurfaceColorValue("text", input.text);
14789
+ return {
14790
+ text,
14791
+ heading: input.heading === void 0 ? text : requireSurfaceColorValue("heading", input.heading),
14792
+ link: input.link === void 0 ? text : requireSurfaceColorValue("link", input.link),
14793
+ supporting: input.supporting === void 0 ? text : requireSurfaceColorValue("supporting", input.supporting)
14794
+ };
14795
+ }
14796
+ function surfaceForegroundValue(role, outsideProviderFallback = DEFAULT_ROLE_FALLBACKS[role]) {
14797
+ const roleVariable = SURFACE_FOREGROUND_CSS_VARS[role];
14798
+ const fallback = requireSurfaceColorValue("fallback", outsideProviderFallback);
14799
+ if (role === "text") return `var(${roleVariable}, ${fallback})`;
14800
+ return `var(${roleVariable}, var(${SURFACE_FOREGROUND_CSS_VARS.text}, ${fallback}))`;
14801
+ }
14802
+ function surfaceForegroundValueWithOpacity(role, opacityPercent) {
14803
+ if (!Number.isFinite(opacityPercent) || opacityPercent < 0 || opacityPercent > 100) throw new RangeError("Surface foreground opacity must be between 0 and 100.");
14804
+ return `color-mix(in srgb, ${surfaceForegroundValue(role)} ${opacityPercent}%, transparent)`;
14805
+ }
14806
+ function surfaceForegroundStyle(input) {
14807
+ const foregrounds = completeSurfaceForegrounds(input);
14808
+ return {
14809
+ color: foregrounds.text,
14810
+ [SURFACE_FOREGROUND_CSS_VARS.text]: foregrounds.text,
14811
+ [SURFACE_FOREGROUND_CSS_VARS.heading]: foregrounds.heading,
14812
+ [SURFACE_FOREGROUND_CSS_VARS.link]: foregrounds.link,
14813
+ [SURFACE_FOREGROUND_CSS_VARS.supporting]: foregrounds.supporting
14814
+ };
14815
+ }
14816
+ function surfaceForegroundDeclarations(input) {
14817
+ const foregrounds = completeSurfaceForegrounds(input);
14818
+ return [`color: ${foregrounds.text}`, ...SURFACE_FOREGROUND_ROLES.map((role) => `${SURFACE_FOREGROUND_CSS_VARS[role]}: ${foregrounds[role]}`)];
14819
+ }
14820
+ //#endregion
14821
+ //#region ../theme-core/src/buttons/resolveButtonColourStates.ts
14822
+ const BUTTON_VISUAL_STATES = [
14823
+ "base",
14824
+ "hover",
14825
+ "focus",
14826
+ "active",
14827
+ "disabled"
14828
+ ];
14829
+ const BUTTON_CONTRAST_POLICY = {
14830
+ textMinimumRatio: 4.5,
14831
+ nonTextMinimumRatio: 3,
14832
+ gradientSamplesPerSegment: 20,
14833
+ alphaBackgrounds: "reject-without-known-surface",
14834
+ disabled: "retain-full-colour-contract"
14835
+ };
14836
+ function compileButtonColourStates(input) {
14837
+ const baseTransition = applyColourEffects({
14838
+ variantId: input.variant.id,
14839
+ state: "base",
14840
+ treatment: input.variant.background,
14841
+ effects: input.variant.effects?.base,
14842
+ palette: input.palette
14843
+ });
14844
+ if (!baseTransition.ok) return baseTransition;
14845
+ const stateTreatments = {
14846
+ base: baseTransition.treatment,
14847
+ hover: hoverTreatment(input.variant, input.global, baseTransition.treatment),
14848
+ focus: baseTransition.treatment,
14849
+ active: baseTransition.treatment,
14850
+ disabled: baseTransition.treatment
14851
+ };
14852
+ const nonColourEffects = { ...baseTransition.nonColourEffects.length > 0 ? { base: [...baseTransition.nonColourEffects] } : {} };
14853
+ for (const state of [
14854
+ "hover",
14855
+ "focus",
14856
+ "active"
14857
+ ]) {
14858
+ const transition = applyColourEffects({
14859
+ variantId: input.variant.id,
14860
+ state,
14861
+ treatment: stateTreatments[state],
14862
+ effects: input.variant.effects?.[state],
14863
+ palette: input.palette
14864
+ });
14865
+ if (!transition.ok) return transition;
14866
+ stateTreatments[state] = transition.treatment;
14867
+ if (transition.nonColourEffects.length > 0) nonColourEffects[state] = [...transition.nonColourEffects];
14868
+ }
14869
+ const resolved = {};
14870
+ for (const state of BUTTON_VISUAL_STATES) {
14871
+ const result = resolveTreatment$1({
14872
+ variantId: input.variant.id,
14873
+ state,
14874
+ treatment: stateTreatments[state],
14875
+ palette: input.palette
14876
+ });
14877
+ if (!result.ok) return result;
14878
+ resolved[state] = result.colour;
14879
+ }
14880
+ return {
14881
+ ok: true,
14882
+ states: resolved,
14883
+ focusIndicator: resolveFocusIndicator(resolved.focus),
14884
+ nonColourEffects
14885
+ };
14886
+ }
14887
+ function formatButtonColourContractError(error) {
14888
+ switch (error.tag) {
14889
+ case "unknown_palette_token": return `Button "${error.variantId}" ${error.state} state uses unknown palette token "${error.token}".`;
14890
+ case "missing_on_colour": return `Button "${error.variantId}" ${error.state} state cannot derive ${error.foregroundToken} from ${error.backgroundToken}.`;
14891
+ case "insufficient_contrast": return `Button "${error.variantId}" ${error.state} state has ${error.ratio.toFixed(2)}:1 contrast (${error.requiredRatio}:1 required).`;
14892
+ case "unsupported_colour_effect": return `Button "${error.variantId}" ${error.state} effect "${error.effectId}" is not contrast-safe (${error.reason}).`;
14893
+ case "invalid_colour_effect_options": return `Button "${error.variantId}" ${error.state} effect "${error.effectId}" has an invalid ${error.option} option.`;
14894
+ case "inapplicable_colour_effect": return `Button "${error.variantId}" ${error.state} effect "${error.effectId}" cannot apply to a ${error.treatment} treatment.`;
14895
+ case "unknown_button_effect": return `Button "${error.variantId}" ${error.state} uses unknown effect "${error.effectId}".`;
14896
+ }
14897
+ }
14898
+ function hoverTreatment(variant, global, fallback) {
14899
+ const token = variant.hoverBackgroundToken ?? (global.hoverColor === "token" ? global.hoverColorToken : void 0);
14900
+ return token === void 0 ? fallback : {
14901
+ type: "solid",
14902
+ colorToken: token
14903
+ };
14904
+ }
14905
+ function applyColourEffects(input) {
14906
+ let treatment = input.treatment;
14907
+ const nonColourEffects = [];
14908
+ for (const effect of input.effects ?? []) {
14909
+ const policy = getButtonEffectPolicy(effect.effectId);
14910
+ if (policy === null) return unknownEffect(input, effect);
14911
+ switch (policy.classification) {
14912
+ case "non-colour":
14913
+ nonColourEffects.push(effect);
14914
+ break;
14915
+ case "unsupported-colour":
14916
+ case "unsupported-background-overlay":
14917
+ case "not-button": return unsupportedEffect(input, effect, policy.reason);
14918
+ case "colour-transition":
14919
+ if (policy.transition.kind === "adjust-shade") {
14920
+ if (treatment.type !== "solid") return inapplicableEffect(input, effect, treatment);
14921
+ const amount = readShadeAmount(effect);
14922
+ if (amount === null) return invalidEffectOption(input, effect, "amount");
14923
+ const signedAmount = policy.transition.direction === "darker" ? amount : -amount;
14924
+ treatment = {
14925
+ type: "solid",
14926
+ colorToken: adjustShade(treatment.colorToken, signedAmount, input.palette)
14927
+ };
14928
+ break;
14929
+ }
14930
+ if (policy.transition.kind === "replace-background") {
14931
+ const colorToken = readOpaqueToken(effect, "colorToken", "neutral-800");
14932
+ if (colorToken === null) return invalidEffectOption(input, effect, "colorToken");
14933
+ treatment = {
14934
+ type: "solid",
14935
+ colorToken
14936
+ };
14937
+ break;
14938
+ }
14939
+ return unknownEffect(input, effect);
14940
+ }
14941
+ }
14942
+ return {
14943
+ ok: true,
14944
+ treatment,
14945
+ nonColourEffects
14946
+ };
14947
+ }
14948
+ function resolveTreatment$1(input) {
14949
+ const treatment = input.treatment;
14950
+ switch (treatment.type) {
14951
+ case "surface": return {
14952
+ ok: true,
14953
+ colour: {
14954
+ kind: "surface",
14955
+ role: treatment.role,
14956
+ backgroundCss: "transparent",
14957
+ foregroundCss: surfaceForegroundValue(treatment.role)
14958
+ }
14959
+ };
14960
+ case "solid": return resolveSolid(input, treatment.colorToken);
14961
+ case "gradient": return resolveGradient(input, treatment);
14962
+ }
14963
+ }
14964
+ function resolveFocusIndicator(colour) {
14965
+ switch (colour.kind) {
14966
+ case "solid": return {
14967
+ kind: "two-tone",
14968
+ innerCss: colour.foregroundCss,
14969
+ outerCss: colour.backgroundCss,
14970
+ minimumPairContrast: BUTTON_CONTRAST_POLICY.textMinimumRatio
14971
+ };
14972
+ case "gradient": return {
14973
+ kind: "two-tone",
14974
+ innerCss: colour.foregroundCss,
14975
+ outerCss: tokenCss(colour.backgroundTokens[0]),
14976
+ minimumPairContrast: BUTTON_CONTRAST_POLICY.textMinimumRatio
14977
+ };
14978
+ case "surface": return {
14979
+ kind: "surface-role",
14980
+ colorCss: colour.foregroundCss,
14981
+ minimumSurfaceContrast: BUTTON_CONTRAST_POLICY.nonTextMinimumRatio
14982
+ };
14983
+ }
14984
+ }
14985
+ function resolveSolid(input, backgroundToken) {
14986
+ const backgroundHex = paletteHex(input, backgroundToken);
14987
+ if (!backgroundHex.ok) return backgroundHex;
14988
+ const foregroundToken = unsafeAsOpaqueButtonColourToken(onColorTokenName(backgroundToken));
14989
+ const foregroundHex = input.palette[foregroundToken];
14990
+ if (typeof foregroundHex !== "string") return {
14991
+ ok: false,
14992
+ error: {
14993
+ tag: "missing_on_colour",
14994
+ variantId: input.variantId,
14995
+ state: input.state,
14996
+ backgroundToken,
14997
+ foregroundToken
14998
+ }
14999
+ };
15000
+ const contrast = validateContrast({
15001
+ ...input,
15002
+ background: backgroundToken,
15003
+ backgroundHex: backgroundHex.hex,
15004
+ foreground: foregroundToken,
15005
+ foregroundHex
15006
+ });
15007
+ if (!contrast.ok) return contrast;
15008
+ return {
15009
+ ok: true,
15010
+ colour: {
15011
+ kind: "solid",
15012
+ backgroundToken,
15013
+ foregroundToken,
15014
+ backgroundCss: tokenCss(backgroundToken),
15015
+ foregroundCss: tokenCss(foregroundToken)
15016
+ }
15017
+ };
15018
+ }
15019
+ function resolveGradient(input, treatment) {
15020
+ const foregroundHex = paletteHex(input, treatment.foregroundToken);
15021
+ if (!foregroundHex.ok) return foregroundHex;
15022
+ const stopHexes = [];
15023
+ for (const token of treatment.stops) {
15024
+ const stop = paletteHex(input, token);
15025
+ if (!stop.ok) return stop;
15026
+ stopHexes.push(stop.hex);
15027
+ }
15028
+ for (let segment = 0; segment < stopHexes.length - 1; segment += 1) {
15029
+ const start = stopHexes[segment];
15030
+ const end = stopHexes[segment + 1];
15031
+ const startToken = treatment.stops[segment];
15032
+ const endToken = treatment.stops[segment + 1];
15033
+ if (start === void 0 || end === void 0 || startToken === void 0 || endToken === void 0) continue;
15034
+ for (let sample = 0; sample <= BUTTON_CONTRAST_POLICY.gradientSamplesPerSegment; sample += 1) {
15035
+ const position = sample / BUTTON_CONTRAST_POLICY.gradientSamplesPerSegment;
15036
+ const sampleHex = interpolateHex(start, end, position);
15037
+ const contrast = validateContrast({
15038
+ ...input,
15039
+ background: `${startToken}→${endToken}@${position.toFixed(2)}`,
15040
+ backgroundHex: sampleHex,
15041
+ foreground: treatment.foregroundToken,
15042
+ foregroundHex: foregroundHex.hex
15043
+ });
15044
+ if (!contrast.ok) return contrast;
15045
+ }
15046
+ }
15047
+ const direction = GRADIENT_DIRECTION_MAP$1[treatment.direction] ?? "to right";
15048
+ return {
15049
+ ok: true,
15050
+ colour: {
15051
+ kind: "gradient",
15052
+ backgroundTokens: treatment.stops,
15053
+ foregroundToken: treatment.foregroundToken,
15054
+ backgroundCss: `linear-gradient(${direction}, ${treatment.stops.map(tokenCss).join(", ")})`,
15055
+ foregroundCss: tokenCss(treatment.foregroundToken)
15056
+ }
15057
+ };
15058
+ }
15059
+ function paletteHex(input, token) {
15060
+ const hex = input.palette[token];
15061
+ return typeof hex === "string" ? {
15062
+ ok: true,
15063
+ hex
15064
+ } : {
15065
+ ok: false,
15066
+ error: {
15067
+ tag: "unknown_palette_token",
15068
+ variantId: input.variantId,
15069
+ state: input.state,
15070
+ token
15071
+ }
15072
+ };
15073
+ }
15074
+ function validateContrast(input) {
15075
+ const ratio = contrastRatio(input.backgroundHex, input.foregroundHex);
15076
+ return ratio >= BUTTON_CONTRAST_POLICY.textMinimumRatio ? { ok: true } : {
15077
+ ok: false,
15078
+ error: {
15079
+ tag: "insufficient_contrast",
15080
+ variantId: input.variantId,
15081
+ state: input.state,
15082
+ background: input.background,
15083
+ foreground: input.foreground,
15084
+ ratio,
15085
+ requiredRatio: BUTTON_CONTRAST_POLICY.textMinimumRatio
15086
+ }
15087
+ };
15088
+ }
15089
+ function tokenCss(token) {
15090
+ return `rgb(var(--tb-${token}))`;
15091
+ }
15092
+ function adjustShade(token, amount, palette) {
15093
+ const match = token.match(/^(.*)-(\d{2,3})$/);
15094
+ const base = match?.[1] ?? token;
15095
+ const currentShade = match?.[2] === void 0 ? 500 : Number(match[2]);
15096
+ const availableShades = [
15097
+ 50,
15098
+ 100,
15099
+ 200,
15100
+ 300,
15101
+ 400,
15102
+ 500,
15103
+ 600,
15104
+ 700,
15105
+ 800,
15106
+ 900,
15107
+ 950
15108
+ ].filter((shade) => typeof palette[`${base}-${shade}`] === "string");
15109
+ if (availableShades.length === 0) return token;
15110
+ const firstShade = availableShades[0];
15111
+ if (firstShade === void 0) return token;
15112
+ const exactIndex = availableShades.indexOf(currentShade);
15113
+ const startingIndex = exactIndex >= 0 ? exactIndex : availableShades.indexOf(availableShades.reduce((closestShade, shade) => Math.abs(shade - currentShade) < Math.abs(closestShade - currentShade) ? shade : closestShade, firstShade));
15114
+ const stepCount = Math.abs(amount) / 100;
15115
+ const direction = amount < 0 ? -1 : 1;
15116
+ const targetShade = availableShades[Math.max(0, Math.min(availableShades.length - 1, startingIndex + direction * stepCount))];
15117
+ return targetShade === void 0 ? token : unsafeAsOpaqueButtonColourToken(`${base}-${targetShade}`);
15118
+ }
15119
+ function readShadeAmount(effect) {
15120
+ const value = effect.options?.amount ?? 100;
15121
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 && value % 100 === 0 ? value : null;
15122
+ }
15123
+ function readOpaqueToken(effect, key, fallback) {
15124
+ return parseOpaqueButtonColourToken(effect.options?.[key] ?? fallback);
15125
+ }
15126
+ function unsupportedEffect(input, effect, reason) {
15127
+ return {
15128
+ ok: false,
15129
+ error: {
15130
+ tag: "unsupported_colour_effect",
15131
+ variantId: input.variantId,
15132
+ state: input.state,
15133
+ effectId: effect.effectId,
15134
+ reason
15135
+ }
15136
+ };
15137
+ }
15138
+ function invalidEffectOption(input, effect, option) {
15139
+ return {
15140
+ ok: false,
15141
+ error: {
15142
+ tag: "invalid_colour_effect_options",
15143
+ variantId: input.variantId,
15144
+ state: input.state,
15145
+ effectId: effect.effectId,
15146
+ option
15147
+ }
15148
+ };
15149
+ }
15150
+ function inapplicableEffect(input, effect, treatment) {
15151
+ return {
15152
+ ok: false,
15153
+ error: {
15154
+ tag: "inapplicable_colour_effect",
15155
+ variantId: input.variantId,
15156
+ state: input.state,
15157
+ effectId: effect.effectId,
15158
+ treatment: treatment.type
15159
+ }
15160
+ };
15161
+ }
15162
+ function unknownEffect(input, effect) {
15163
+ return {
15164
+ ok: false,
15165
+ error: {
15166
+ tag: "unknown_button_effect",
15167
+ variantId: input.variantId,
15168
+ state: input.state,
15169
+ effectId: effect.effectId
15170
+ }
15171
+ };
15172
+ }
15173
+ function interpolateHex(startHex, endHex, position) {
15174
+ const start = hexToRgb(startHex);
15175
+ const end = hexToRgb(endHex);
15176
+ const channel = (from, to) => Math.round(from + (to - from) * position).toString(16).padStart(2, "0");
15177
+ return `#${channel(start.r, end.r)}${channel(start.g, end.g)}${channel(start.b, end.b)}`;
15178
+ }
15179
+ //#endregion
15180
+ //#region ../theme-core/src/buttons/resolvedButtonCss.ts
15181
+ /**
15182
+ * Canonical colour declaration mapping shared by full themes and ThemeBridge.
15183
+ * Both background properties are always emitted so transitions cannot retain
15184
+ * a stale gradient or solid layer.
15185
+ */
15186
+ function resolvedButtonColourDeclarations(colour) {
15187
+ switch (colour.kind) {
15188
+ case "solid": return [
15189
+ ["background-color", colour.backgroundCss],
15190
+ ["background-image", "none"],
15191
+ ["color", colour.foregroundCss]
15192
+ ];
15193
+ case "gradient": return [
15194
+ ["background-color", "transparent"],
15195
+ ["background-image", colour.backgroundCss],
15196
+ ["color", colour.foregroundCss]
15197
+ ];
15198
+ case "surface": return [
15199
+ ["background-color", colour.backgroundCss],
15200
+ ["background-image", "none"],
15201
+ ["color", colour.foregroundCss]
15202
+ ];
15203
+ }
15204
+ }
15205
+ function resolvedButtonFocusDeclarations(indicator) {
15206
+ return indicator.kind === "two-tone" ? [
15207
+ ["outline", `2px solid ${indicator.innerCss}`],
15208
+ ["outline-offset", "2px"],
15209
+ ["box-shadow", `0 0 0 4px ${indicator.outerCss}`]
15210
+ ] : [["outline", `3px solid ${indicator.colorCss}`], ["outline-offset", "3px"]];
15211
+ }
15212
+ /**
15213
+ * Disabled buttons retain their validated colour pair and add a non-layout
15214
+ * visual affordance. `currentColor` keeps the cue inside the same contrast
15215
+ * relationship, while retaining pointer events lets the not-allowed cursor
15216
+ * remain observable.
15217
+ */
15218
+ const RESOLVED_BUTTON_DISABLED_DECLARATIONS = [
15219
+ ["cursor", "not-allowed"],
15220
+ ["transform", "none"],
15221
+ ["box-shadow", "none"],
15222
+ ["outline", "2px dashed currentColor"],
15223
+ ["outline-offset", "-4px"]
15224
+ ];
15225
+ //#endregion
14252
15226
  //#region ../theme-core/src/buttons/generateButtonCss.ts
14253
15227
  /**
14254
15228
  * Class the `button` runtime node adds when it renders its own trailing icon,
@@ -14315,6 +15289,7 @@ const STRUCTURAL_DECLARATIONS = [
14315
15289
  function generateButtonCss(options) {
14316
15290
  const { themeId, theme, buttonSystem: providedButtonSystem } = options;
14317
15291
  const tokens = new TokenResolver(theme);
15292
+ const palette = expandPalette(theme.palette);
14318
15293
  const buttonSystem = providedButtonSystem ?? generateDefaultButtonSystem(theme);
14319
15294
  const themeSizes = {
14320
15295
  ...DEFAULT_BUTTON_SIZES,
@@ -14323,34 +15298,109 @@ function generateButtonCss(options) {
14323
15298
  const enabledVariants = buttonSystem.variants.filter((v) => v.enabled);
14324
15299
  const aliasSource = resolveAliasSource(enabledVariants);
14325
15300
  const chunks = [];
14326
- for (const variant of enabledVariants) chunks.push(...variantChunks(variant, buttonSystem.global, themeSizes, themeId, tokens, theme));
15301
+ for (const variant of enabledVariants) {
15302
+ const compiled = compileRuntimeVariant(variant, buttonSystem.global, palette);
15303
+ if (compiled.fallbackError) chunks.push({ raw: `/* ${formatButtonColourContractError(compiled.fallbackError)} Using contrast-safe surface fallback. */` });
15304
+ chunks.push(...variantChunks(compiled.variant, compiled.global, themeSizes, themeId, tokens, theme, compiled.colours, compiled.focusIndicator, compiled.nonColourEffects));
15305
+ }
14327
15306
  if (aliasSource) {
14328
- const alias = {
15307
+ const compiled = compileRuntimeVariant({
14329
15308
  ...aliasSource,
14330
15309
  id: DEFAULT_VARIANT_ALIAS_ID,
14331
15310
  name: "Default"
14332
- };
14333
- chunks.push(...variantChunks(alias, buttonSystem.global, themeSizes, themeId, tokens, theme));
15311
+ }, buttonSystem.global, palette);
15312
+ if (compiled.fallbackError) chunks.push({ raw: `/* ${formatButtonColourContractError(compiled.fallbackError)} Using contrast-safe surface fallback. */` });
15313
+ chunks.push(...variantChunks(compiled.variant, compiled.global, themeSizes, themeId, tokens, theme, compiled.colours, compiled.focusIndicator, compiled.nonColourEffects));
14334
15314
  }
14335
15315
  return chunks.map(renderChunk).join("\n\n");
14336
15316
  }
15317
+ function compileRuntimeVariant(variant, global, palette) {
15318
+ const result = compileButtonColourStates({
15319
+ variant,
15320
+ global,
15321
+ palette
15322
+ });
15323
+ if (result.ok) return {
15324
+ variant,
15325
+ global,
15326
+ colours: result.states,
15327
+ focusIndicator: result.focusIndicator,
15328
+ nonColourEffects: result.nonColourEffects
15329
+ };
15330
+ const fallbackVariant = {
15331
+ ...variant,
15332
+ background: {
15333
+ type: "surface",
15334
+ role: "link"
15335
+ },
15336
+ hoverBackgroundToken: void 0,
15337
+ effects: void 0
15338
+ };
15339
+ const fallbackGlobal = {
15340
+ ...global,
15341
+ hoverColor: "none",
15342
+ hoverColorToken: void 0
15343
+ };
15344
+ const fallback = compileButtonColourStates({
15345
+ variant: fallbackVariant,
15346
+ global: fallbackGlobal,
15347
+ palette
15348
+ });
15349
+ if (!fallback.ok) {
15350
+ const colour = {
15351
+ kind: "surface",
15352
+ role: "link",
15353
+ backgroundCss: "transparent",
15354
+ foregroundCss: surfaceForegroundValue("link")
15355
+ };
15356
+ return {
15357
+ variant: fallbackVariant,
15358
+ global: fallbackGlobal,
15359
+ colours: {
15360
+ base: colour,
15361
+ hover: colour,
15362
+ focus: colour,
15363
+ active: colour,
15364
+ disabled: colour
15365
+ },
15366
+ focusIndicator: {
15367
+ kind: "surface-role",
15368
+ colorCss: colour.foregroundCss,
15369
+ minimumSurfaceContrast: BUTTON_CONTRAST_POLICY.nonTextMinimumRatio
15370
+ },
15371
+ nonColourEffects: {},
15372
+ fallbackError: result.error
15373
+ };
15374
+ }
15375
+ return {
15376
+ variant: fallbackVariant,
15377
+ global: fallbackGlobal,
15378
+ colours: fallback.states,
15379
+ focusIndicator: fallback.focusIndicator,
15380
+ nonColourEffects: fallback.nonColourEffects,
15381
+ fallbackError: result.error
15382
+ };
15383
+ }
14337
15384
  /** Pick the highest-priority variant whose role we'll alias to `.default`. */
14338
15385
  function resolveAliasSource(enabled) {
14339
15386
  if (enabled.some((v) => v.id === "default")) return null;
14340
15387
  return enabled.slice().sort((a, b) => a.priority - b.priority)[0] ?? null;
14341
15388
  }
14342
- function variantChunks(variant, global, themeSizes, themeId, tokens, theme) {
15389
+ function variantChunks(variant, global, themeSizes, themeId, tokens, theme, colours, focusIndicator, nonColourEffects) {
14343
15390
  const out = [];
14344
15391
  const variantId = parseButtonVariantIdForCss(variant.id);
14345
15392
  const selector = `:where([data-theme-scope="${themeId}"]) ${themeButtonSelector(variantId)}`;
14346
- out.push(variantBaseRule(variant, selector, global, tokens, theme));
15393
+ out.push(variantBaseRule(variant, selector, global, tokens, theme, colours.base));
14347
15394
  out.push({ raw: generateInteractiveChildInheritanceCSS(selector) });
14348
- const hoverBg = variantHoverBackgroundRule(variant, variantId, global, themeId, tokens);
14349
- if (hoverBg) out.push(hoverBg);
14350
- out.push(variantFocusVisibleRule(variantId, themeId));
14351
- const effects = variantEffectsCss(variant, themeId, tokens, theme);
15395
+ for (const state of [
15396
+ "hover",
15397
+ "focus",
15398
+ "active"
15399
+ ]) if (!resolvedColoursEqual(colours.base, colours[state])) out.push(variantStateColourRule(variantId, themeId, state, colours[state]));
15400
+ const effects = variantEffectsCss(variant, nonColourEffects, themeId, tokens, theme);
14352
15401
  if (effects) out.push({ raw: effects });
14353
- const affordance = variantAffordanceRule(variant, selector, tokens);
15402
+ out.push(variantFocusVisibleRule(variantId, themeId, focusIndicator));
15403
+ const affordance = variantAffordanceRule(variant, selector);
14354
15404
  if (affordance) out.push(affordance);
14355
15405
  out.push(...variantDisabledRules(variantId, themeId));
14356
15406
  out.push(...variantSizeRules(variant, variantId, themeSizes, themeId));
@@ -14365,12 +15415,11 @@ function variantChunks(variant, global, themeSizes, themeId, tokens, theme) {
14365
15415
  * one (node overrides personality). Colour comes from the affordance token, or
14366
15416
  * `currentColor` (the button text colour) when no token is given.
14367
15417
  */
14368
- function variantAffordanceRule(variant, selector, tokens) {
15418
+ function variantAffordanceRule(variant, selector) {
14369
15419
  const affordance = variant.affordance;
14370
15420
  if (!affordance) return null;
14371
15421
  const maskUrl = affordanceIconMaskUrl(affordance.iconId);
14372
15422
  if (!maskUrl) return null;
14373
- const color = affordance.colorToken ? variant.background.type === "transparent" ? surfaceLinkColor(tokens.getColor(affordance.colorToken)) : tokens.getColor(affordance.colorToken) : "currentColor";
14374
15423
  const mask = `url("${maskUrl}") no-repeat center / contain`;
14375
15424
  return rule(`${selector}:not(.${AFFORDANCE_SUPPRESS_CLASS})::after`, [
14376
15425
  ["content", "\"\""],
@@ -14379,7 +15428,7 @@ function variantAffordanceRule(variant, selector, tokens) {
14379
15428
  ["height", "1em"],
14380
15429
  ["margin-inline-start", "0.5em"],
14381
15430
  ["flex", "0 0 auto"],
14382
- ["background-color", color],
15431
+ ["background-color", "currentColor"],
14383
15432
  ["-webkit-mask", mask],
14384
15433
  ["mask", mask]
14385
15434
  ]);
@@ -14389,7 +15438,7 @@ function parseButtonVariantIdForCss(value) {
14389
15438
  if (!variantId) throw new Error("Button variant id must be a non-empty string");
14390
15439
  return variantId;
14391
15440
  }
14392
- function variantBaseRule(variant, selector, global, tokens, theme) {
15441
+ function variantBaseRule(variant, selector, global, tokens, theme, colour) {
14393
15442
  const decls = [];
14394
15443
  decls.push(["font-weight", String(global.fontWeight)]);
14395
15444
  decls.push(["font-family", resolveFontFamily(global)]);
@@ -14401,18 +15450,10 @@ function variantBaseRule(variant, selector, global, tokens, theme) {
14401
15450
  for (const decl of STRUCTURAL_DECLARATIONS) decls.push(decl);
14402
15451
  decls.push(["border-radius", resolveBorderRadius(variant, global)]);
14403
15452
  decls.push(["box-shadow", resolveBoxShadow(variant, global, theme, tokens)]);
14404
- if (variant.background.type === "solid") decls.push(["background-color", tokens.getColor(variant.background.colorToken)]);
14405
- else if (variant.background.type === "gradient") {
14406
- const colors = variant.background.stops.map((stop) => tokens.getColor(stop)).join(", ");
14407
- const direction = GRADIENT_DIRECTION_MAP$1[variant.background.direction] || "to right";
14408
- decls.push(["background-image", `linear-gradient(${direction}, ${colors})`]);
14409
- } else decls.push(["background-color", "transparent"]);
14410
- const foregroundColor = variant.background.type === "transparent" ? surfaceLinkColor(tokens.getColor(variant.textColorToken)) : tokens.getColor(variant.textColorToken);
14411
- decls.push(["color", foregroundColor]);
15453
+ decls.push(...resolvedButtonColourDeclarations(colour));
14412
15454
  if (variant.border) {
14413
15455
  const borderWidth = BORDER_WIDTH_MAP[variant.border.widthClass] || "1px";
14414
- const borderColor = variant.background.type === "transparent" ? surfaceLinkColor(tokens.getColor(variant.border.colorToken)) : tokens.getColor(variant.border.colorToken);
14415
- decls.push(["border", `${borderWidth} solid ${borderColor}`]);
15456
+ decls.push(["border", `${borderWidth} solid currentColor`]);
14416
15457
  }
14417
15458
  return rule(selector, decls);
14418
15459
  }
@@ -14423,30 +15464,22 @@ function variantBaseRule(variant, selector, global, tokens, theme) {
14423
15464
  * token fallback keeps buttons usable in contexts that do not provide that
14424
15465
  * contract (and preserves the existing theme behaviour there).
14425
15466
  */
14426
- function surfaceLinkColor(fallbackColor) {
14427
- return `var(--rb-surface-link-color, ${fallbackColor})`;
14428
- }
14429
- function variantHoverBackgroundRule(variant, variantId, global, themeId, tokens) {
14430
- let hoverToken = variant.hoverBackgroundToken;
14431
- if (!hoverToken && global.hoverColor === "token" && global.hoverColorToken) hoverToken = global.hoverColorToken;
14432
- if (!hoverToken) return null;
14433
- return rule(`:where([data-theme-scope="${themeId}"]) ${themeButtonSelector(variantId)}:hover`, [["background-color", tokens.getColor(hoverToken)]]);
15467
+ function variantStateColourRule(variantId, themeId, state, colour) {
15468
+ return rule(`:where([data-theme-scope="${themeId}"]) ${themeButtonSelector(variantId)}:${state}`, resolvedButtonColourDeclarations(colour));
14434
15469
  }
14435
- function variantFocusVisibleRule(variantId, themeId) {
14436
- return rule(`:where([data-theme-scope="${themeId}"]) ${themeButtonSelector(variantId)}:focus-visible`, [["outline", "2px solid currentColor"], ["outline-offset", "3px"]]);
15470
+ function variantFocusVisibleRule(variantId, themeId, focusIndicator) {
15471
+ return rule(`:where([data-theme-scope="${themeId}"]) ${themeButtonSelector(variantId)}:focus-visible`, resolvedButtonFocusDeclarations(focusIndicator));
14437
15472
  }
14438
- function variantEffectsCss(variant, themeId, tokens, theme) {
14439
- if (!variant.effects) return "";
15473
+ function variantEffectsCss(variant, effects, themeId, tokens, theme) {
15474
+ if (!effects) return "";
14440
15475
  const elementConfig = {
14441
- background: variant.background,
14442
- textColorToken: variant.textColorToken,
14443
- border: variant.border ? { colorToken: variant.border.colorToken } : void 0,
15476
+ background: variant.background.type === "surface" ? { type: "transparent" } : variant.background,
14444
15477
  shadow: variant.shadow
14445
15478
  };
14446
15479
  return generateEffectsCSS({
14447
15480
  themeId,
14448
15481
  variantId: variant.id,
14449
- effects: variant.effects,
15482
+ effects,
14450
15483
  elementConfig,
14451
15484
  tokens,
14452
15485
  theme
@@ -14461,18 +15494,15 @@ function variantDisabledRules(variantId, themeId) {
14461
15494
  `${base}:focus`
14462
15495
  ];
14463
15496
  const pseudoSelectors = [`${base}::before`, `${base}::after`];
14464
- return [rule(disabledSelectors, [
14465
- ["opacity", "0.5"],
14466
- ["cursor", "not-allowed"],
14467
- ["pointer-events", "none"],
14468
- ["transform", "none"],
14469
- ["box-shadow", "none"]
14470
- ]), rule(pseudoSelectors, [
15497
+ return [rule(disabledSelectors, [...RESOLVED_BUTTON_DISABLED_DECLARATIONS]), rule(pseudoSelectors, [
14471
15498
  ["opacity", "0"],
14472
15499
  ["animation", "none"],
14473
15500
  ["pointer-events", "none"]
14474
15501
  ])];
14475
15502
  }
15503
+ function resolvedColoursEqual(left, right) {
15504
+ return JSON.stringify(left) === JSON.stringify(right);
15505
+ }
14476
15506
  function variantSizeRules(variant, variantId, themeSizes, themeId) {
14477
15507
  const borderWidth = variant.border ? BORDER_WIDTH_MAP[variant.border.widthClass] || "1px" : "0px";
14478
15508
  const rules = [];
@@ -14540,6 +15570,27 @@ function resolveBoxShadow(variant, global, theme, tokens) {
14540
15570
  const color = shadowConfig.colorToken ? tokens.getColor(shadowConfig.colorToken) : void 0;
14541
15571
  return generateShadowValue$1(shadowConfig.elevation, shadowConfig.softness, shadowConfig.position ?? "bottom", color);
14542
15572
  }
15573
+ buttonPersonalities.map((personality) => ({
15574
+ id: personality.id,
15575
+ name: personality.name,
15576
+ description: personality.description,
15577
+ category: presetCategory(personality),
15578
+ buttonSystem: personality.buttonSystem,
15579
+ compatibility: {
15580
+ ...personality.tags.tone ? { tones: [personality.tags.tone] } : {},
15581
+ ...personality.tags.energy ? { energies: [personality.tags.energy] } : {}
15582
+ }
15583
+ }));
15584
+ function presetCategory(personality) {
15585
+ switch (personality.tags.era) {
15586
+ case "retro": return "retro";
15587
+ case "editorial": return "minimal";
15588
+ case "organic": return "artistic";
15589
+ case "modern": return personality.tags.tone === "bold" ? "modern" : "technical";
15590
+ case "technical": return "technical";
15591
+ case void 0: return "modern";
15592
+ }
15593
+ }
14543
15594
  //#endregion
14544
15595
  //#region ../theme-core/src/cards/types.ts
14545
15596
  const cardVariantRoleValues = ["default", "alternative"];
@@ -14776,67 +15827,6 @@ function generateDefaultCardSystem(theme) {
14776
15827
  return { variants: [defaultVariant, alternativeVariant] };
14777
15828
  }
14778
15829
  //#endregion
14779
- //#region ../theme-core/src/surfaces/foregroundRoles.ts
14780
- const SURFACE_FOREGROUND_ROLES = [
14781
- "text",
14782
- "heading",
14783
- "link",
14784
- "supporting"
14785
- ];
14786
- //#endregion
14787
- //#region ../theme-core/src/surfaces/foregroundContract.ts
14788
- const SURFACE_FOREGROUND_CSS_VARS = {
14789
- text: "--rb-surface-text-color",
14790
- heading: "--rb-surface-heading-color",
14791
- link: "--rb-surface-link-color",
14792
- supporting: "--rb-surface-supporting-color"
14793
- };
14794
- const DEFAULT_SURFACE_TEXT_COLOR = "rgb(var(--tb-text, 17 24 39))";
14795
- const DEFAULT_ROLE_FALLBACKS = {
14796
- text: DEFAULT_SURFACE_TEXT_COLOR,
14797
- heading: DEFAULT_SURFACE_TEXT_COLOR,
14798
- link: "rgb(var(--tb-primary, var(--tb-text, 17 24 39)))",
14799
- supporting: "rgb(var(--tb-mutedText, 100 116 139))"
14800
- };
14801
- function requireSurfaceColorValue(role, value) {
14802
- const normalized = value.trim();
14803
- if (normalized.length === 0) throw new RangeError(`Surface foreground ${role} must be a non-empty CSS color.`);
14804
- return normalized;
14805
- }
14806
- function completeSurfaceForegrounds(input) {
14807
- const text = requireSurfaceColorValue("text", input.text);
14808
- return {
14809
- text,
14810
- heading: input.heading === void 0 ? text : requireSurfaceColorValue("heading", input.heading),
14811
- link: input.link === void 0 ? text : requireSurfaceColorValue("link", input.link),
14812
- supporting: input.supporting === void 0 ? text : requireSurfaceColorValue("supporting", input.supporting)
14813
- };
14814
- }
14815
- function surfaceForegroundValue(role, outsideProviderFallback = DEFAULT_ROLE_FALLBACKS[role]) {
14816
- const roleVariable = SURFACE_FOREGROUND_CSS_VARS[role];
14817
- const fallback = requireSurfaceColorValue("fallback", outsideProviderFallback);
14818
- if (role === "text") return `var(${roleVariable}, ${fallback})`;
14819
- return `var(${roleVariable}, var(${SURFACE_FOREGROUND_CSS_VARS.text}, ${fallback}))`;
14820
- }
14821
- function surfaceForegroundValueWithOpacity(role, opacityPercent) {
14822
- if (!Number.isFinite(opacityPercent) || opacityPercent < 0 || opacityPercent > 100) throw new RangeError("Surface foreground opacity must be between 0 and 100.");
14823
- return `color-mix(in srgb, ${surfaceForegroundValue(role)} ${opacityPercent}%, transparent)`;
14824
- }
14825
- function surfaceForegroundStyle(input) {
14826
- const foregrounds = completeSurfaceForegrounds(input);
14827
- return {
14828
- color: foregrounds.text,
14829
- [SURFACE_FOREGROUND_CSS_VARS.text]: foregrounds.text,
14830
- [SURFACE_FOREGROUND_CSS_VARS.heading]: foregrounds.heading,
14831
- [SURFACE_FOREGROUND_CSS_VARS.link]: foregrounds.link,
14832
- [SURFACE_FOREGROUND_CSS_VARS.supporting]: foregrounds.supporting
14833
- };
14834
- }
14835
- function surfaceForegroundDeclarations(input) {
14836
- const foregrounds = completeSurfaceForegrounds(input);
14837
- return [`color: ${foregrounds.text}`, ...SURFACE_FOREGROUND_ROLES.map((role) => `${SURFACE_FOREGROUND_CSS_VARS[role]}: ${foregrounds[role]}`)];
14838
- }
14839
- //#endregion
14840
15830
  //#region ../theme-core/src/cards/generateCardCss.ts
14841
15831
  const PER_CORNER_RADIUS_MAP = {
14842
15832
  square: "0",
@@ -15273,47 +16263,6 @@ const FONT_WEIGHT_MAP = {
15273
16263
  black: "800"
15274
16264
  };
15275
16265
  //#endregion
15276
- //#region ../theme-core/src/gradients/types.ts
15277
- /**
15278
- * Gradient configuration types and schemas
15279
- */
15280
- /**
15281
- * Gradient color stop
15282
- */
15283
- const gradientStopSchema = z$1.object({
15284
- color: themeColorTokenSchema,
15285
- position: z$1.number().min(0).max(100)
15286
- });
15287
- /**
15288
- * Radial gradient shape. Optional; defaults to `circle` (the historical shape)
15289
- * so existing radial gradients are byte-identical.
15290
- *
15291
- * Named `RadialGradientShape` to avoid clashing with `styles/gradients.ts`'s
15292
- * `GradientShape` (which names the gradient *kind*: linear/radial/conic).
15293
- */
15294
- const radialGradientShapeSchema = z$1.enum(["circle", "ellipse"]);
15295
- /**
15296
- * Gradient configuration.
15297
- *
15298
- * `type` is optional and defaults to `'linear'` so gradients persisted without a
15299
- * type (or with an explicit `'linear'`) render exactly as before. `'radial'` and
15300
- * `'conic'` are additive kinds:
15301
- * - linear: `angle` (degrees)
15302
- * - radial: optional `shape` (circle/ellipse) + `position`
15303
- * - conic: optional `angle` (from-angle, degrees) + `position`
15304
- */
15305
- const gradientConfigSchema = z$1.object({
15306
- type: z$1.enum([
15307
- "linear",
15308
- "radial",
15309
- "conic"
15310
- ]).default("linear"),
15311
- angle: z$1.number().min(0).max(360).optional(),
15312
- shape: radialGradientShapeSchema.optional(),
15313
- position: z$1.string().optional(),
15314
- stops: z$1.array(gradientStopSchema).min(2)
15315
- });
15316
- //#endregion
15317
16266
  //#region ../theme-core/src/interactive/baseSchema.ts
15318
16267
  /**
15319
16268
  * Shared Base Schemas for Interactive Elements
@@ -17066,6 +18015,19 @@ z$1.object({
17066
18015
  }).strict();
17067
18016
  //#endregion
17068
18017
  //#region ../theme-core/src/site-styles/runtimeCompiler.ts
18018
+ function defineSectionForegroundRuntimeTokens(input) {
18019
+ return {
18020
+ textColor: requireThemeColorToken(input.textColor),
18021
+ headingColor: requireThemeColorToken(input.headingColor),
18022
+ linkColor: requireThemeColorToken(input.linkColor),
18023
+ supportingColor: requireThemeColorToken(input.supportingColor)
18024
+ };
18025
+ }
18026
+ function requireThemeColorToken(value) {
18027
+ const token = parseThemeColorToken(value);
18028
+ if (!token) throw new Error(`Invalid section foreground Theme color token: ${String(value)}`);
18029
+ return token;
18030
+ }
17069
18031
  function defineDesignRuntimeRules(rules) {
17070
18032
  return rules;
17071
18033
  }
@@ -17336,24 +18298,24 @@ const kirtanOrnateDesignRuntimeRules = defineDesignRuntimeRules({
17336
18298
  type: "color",
17337
18299
  color: "muted"
17338
18300
  },
17339
- foreground: {
18301
+ foreground: defineSectionForegroundRuntimeTokens({
17340
18302
  textColor: "text",
17341
18303
  headingColor: "primary",
17342
18304
  linkColor: "primary",
17343
18305
  supportingColor: "text"
17344
- }
18306
+ })
17345
18307
  },
17346
18308
  "brand-depth-band": {
17347
18309
  background: {
17348
18310
  type: "color",
17349
18311
  color: "primary-800"
17350
18312
  },
17351
- foreground: {
18313
+ foreground: defineSectionForegroundRuntimeTokens({
17352
18314
  textColor: "text",
17353
18315
  headingColor: "primary",
17354
18316
  linkColor: "primary",
17355
18317
  supportingColor: "text"
17356
- }
18318
+ })
17357
18319
  },
17358
18320
  "hero-image": {
17359
18321
  background: {
@@ -17361,12 +18323,32 @@ const kirtanOrnateDesignRuntimeRules = defineDesignRuntimeRules({
17361
18323
  opacity: 1,
17362
18324
  position: "center center"
17363
18325
  },
17364
- foreground: {
18326
+ foreground: defineSectionForegroundRuntimeTokens({
17365
18327
  textColor: "text",
17366
18328
  headingColor: "primary",
17367
18329
  linkColor: "primary",
17368
18330
  supportingColor: "text"
17369
- }
18331
+ })
18332
+ }
18333
+ }
18334
+ });
18335
+ const primaryGlowGradientPresetId = parseGradientPresetId("primary-glow");
18336
+ if (!primaryGlowGradientPresetId) throw new Error("Expected primary-glow in the Theme Core gradient catalog");
18337
+ const fulcrumDesignRuntimeRules = defineDesignRuntimeRules({
18338
+ ...defaultDesignRuntimeRules,
18339
+ sectionSurfaces: {
18340
+ ...defaultDesignRuntimeRules.sectionSurfaces,
18341
+ "accent-band": {
18342
+ background: {
18343
+ type: "gradient",
18344
+ gradientPresetId: primaryGlowGradientPresetId
18345
+ },
18346
+ foreground: defineSectionForegroundRuntimeTokens({
18347
+ textColor: "primaryForeground",
18348
+ headingColor: "primaryForeground",
18349
+ linkColor: "primaryForeground",
18350
+ supportingColor: "primaryForeground"
18351
+ })
17370
18352
  }
17371
18353
  }
17372
18354
  });
@@ -18754,6 +19736,8 @@ const curatedSiteStyles = [
18754
19736
  },
18755
19737
  compositionBudget: quietBudget,
18756
19738
  typography: fulcrumTypography,
19739
+ designRuntimeRules: fulcrumDesignRuntimeRules,
19740
+ recommendedAppearancePresetIds: ["cta-accent-band"],
18757
19741
  themeOverrides: {
18758
19742
  shadow: { colorToken: "primary" },
18759
19743
  accordions: {
@@ -22139,9 +23123,15 @@ function createButtonGroup(options = {}) {
22139
23123
  //#endregion
22140
23124
  //#region ../blocks/src/system/fields/ctas.ts
22141
23125
  function createCtasRepeater(options = {}) {
22142
- const { id = "ctas", label = "Calls to action", itemLabel = "CTA", minItems = 0, maxItems, button } = options;
23126
+ const { id = "ctas", label = "Calls to action", itemLabel = "CTA", minItems = 0, maxItems, button, defaultValue } = options;
23127
+ const fieldId = id;
23128
+ const buttonField = createButtonGroup({
23129
+ showGroupLabel: false,
23130
+ ...button ?? {},
23131
+ flattenInRepeater: true
23132
+ });
22143
23133
  return {
22144
- id,
23134
+ id: fieldId,
22145
23135
  type: "repeater",
22146
23136
  label,
22147
23137
  itemLabel,
@@ -22150,11 +23140,8 @@ function createCtasRepeater(options = {}) {
22150
23140
  maxItems,
22151
23141
  required: false,
22152
23142
  allowConversion: true,
22153
- schema: { fields: [createButtonGroup({
22154
- showGroupLabel: false,
22155
- ...button ?? {},
22156
- flattenInRepeater: true
22157
- })] }
23143
+ ...defaultValue !== void 0 ? { defaultValue: [...defaultValue] } : {},
23144
+ schema: { fields: [buttonField] }
22158
23145
  };
22159
23146
  }
22160
23147
  //#endregion
@@ -22204,6 +23191,7 @@ const heroCtaRowFragment = defineFragment({
22204
23191
  label: "Calls to action",
22205
23192
  itemLabel: "CTA",
22206
23193
  maxItems: 3,
23194
+ defaultValue: [],
22207
23195
  button: {
22208
23196
  variants: [
22209
23197
  {
@@ -22271,7 +23259,7 @@ const ctaCopyFragment = defineFragment({
22271
23259
  eyebrowPath: "content.eyebrow",
22272
23260
  titlePath: "content.title",
22273
23261
  className: "cta-heading"
22274
- }), richText({ className: "cta-content rb-prose rb-mx-auto rb-max-w-none" }, when("content.content"), bind("content.content"))]
23262
+ }), richText({ className: "cta-content rb-prose rb-mx-auto rb-max-w-none" }, when("content"), bind("content"))]
22275
23263
  });
22276
23264
  //#endregion
22277
23265
  //#region ../blocks/src/system/fragments/library/testimonialsHeading.ts
@@ -24295,6 +25283,7 @@ function createBlockManifest(config) {
24295
25283
  previewCustomize: config.previewCustomize,
24296
25284
  category: config.category,
24297
25285
  contentTypes: config.contentTypes ? [...config.contentTypes] : void 0,
25286
+ contentSource: config.contentSource,
24298
25287
  tags: config.tags ? [...config.tags] : [],
24299
25288
  icon: config.icon ?? "Box",
24300
25289
  layout,
@@ -24440,6 +25429,7 @@ const heroBlockDefinition = { manifest: createBlockManifest({
24440
25429
  title: "Hero",
24441
25430
  titleSource: "headline",
24442
25431
  category: "layout",
25432
+ contentSource: { kind: "inline" },
24443
25433
  includeContainerStyles: true,
24444
25434
  promotedFields: ["_sectionStyles.background.image"],
24445
25435
  fragments: [
@@ -24713,6 +25703,7 @@ const introBlockDefinition = { manifest: createBlockManifest({
24713
25703
  id: "block.intro",
24714
25704
  title: "Intro",
24715
25705
  category: "layout",
25706
+ contentSource: { kind: "inline" },
24716
25707
  includeContainerStyles: true,
24717
25708
  titleSource: "title",
24718
25709
  previewCustomize: { quickFieldPriority: [
@@ -24898,6 +25889,7 @@ const bodyTextBlockDefinition = { manifest: createBlockManifest({
24898
25889
  title: "Body Text",
24899
25890
  titleSource: "heading",
24900
25891
  category: "content",
25892
+ contentSource: { kind: "inline" },
24901
25893
  fragments: [{
24902
25894
  fragment: bodyCopyFragment,
24903
25895
  fieldPriority: 0
@@ -24954,6 +25946,10 @@ const blogPostBlockDefinition = {
24954
25946
  description: "Highlights a single blog post with title, image, and excerpt.",
24955
25947
  category: "blog",
24956
25948
  contentTypes: ["post"],
25949
+ contentSource: {
25950
+ kind: "entries",
25951
+ contentType: "post"
25952
+ },
24957
25953
  tags: [
24958
25954
  "blog",
24959
25955
  "post",
@@ -25251,6 +26247,10 @@ const blogListingManifest = createBlockManifest({
25251
26247
  ],
25252
26248
  description: "Display a collection of blog posts in grid or stack layout.",
25253
26249
  contentTypes: ["post"],
26250
+ contentSource: {
26251
+ kind: "entries",
26252
+ contentType: "post"
26253
+ },
25254
26254
  tags: [
25255
26255
  "blog",
25256
26256
  "posts",
@@ -25293,6 +26293,7 @@ const ctaFullBlockDefinition = { manifest: createBlockManifest({
25293
26293
  id: "block.cta-full",
25294
26294
  title: "Full-width CTA",
25295
26295
  category: "marketing",
26296
+ contentSource: { kind: "inline" },
25296
26297
  fragments: [{
25297
26298
  fragment: ctaCopyFragment,
25298
26299
  fieldPriority: 0
@@ -25326,6 +26327,7 @@ const singleButtonBlockDefinition = { manifest: createBlockManifest({
25326
26327
  id: "block.single-button",
25327
26328
  title: "Single Button",
25328
26329
  category: "marketing",
26330
+ contentSource: { kind: "inline" },
25329
26331
  fragments: [{
25330
26332
  fragment: singleButtonFragment,
25331
26333
  fieldPriority: 0
@@ -25608,6 +26610,7 @@ const formManifest = createBlockManifest({
25608
26610
  paletteHidden: false
25609
26611
  },
25610
26612
  category: "interactive",
26613
+ contentSource: { kind: "inline" },
25611
26614
  tags: [
25612
26615
  "form",
25613
26616
  "contact",
@@ -25670,6 +26673,7 @@ const contactNewsletterBlockDefinition = {
25670
26673
  titleSource: "contactTitle",
25671
26674
  description: "Two-column newsletter signup and contact form section.",
25672
26675
  category: "interactive",
26676
+ contentSource: { kind: "inline" },
25673
26677
  layout: contactNewsletterLayout,
25674
26678
  defaultVariant: "default",
25675
26679
  variants: { default: contactNewsletterLayout },
@@ -25873,6 +26877,7 @@ const faqBlockDefinition = { manifest: createBlockManifest({
25873
26877
  title: "FAQ",
25874
26878
  titleSource: "title",
25875
26879
  category: "content",
26880
+ contentSource: { kind: "inline" },
25876
26881
  includeContainerStyles: true,
25877
26882
  fragments: [{
25878
26883
  fragment: faqHeadingFragment,
@@ -27609,6 +28614,7 @@ const siteHeaderManifest = createBlockManifest({
27609
28614
  id: "block.site-header",
27610
28615
  title: "Site Header",
27611
28616
  category: "layout",
28617
+ contentSource: { kind: "inline" },
27612
28618
  additionalFields: [{
27613
28619
  id: "mode",
27614
28620
  type: "select",
@@ -27814,6 +28820,7 @@ const siteFooterManifest = createBlockManifest({
27814
28820
  id: "block.site-footer",
27815
28821
  title: "Site Footer",
27816
28822
  category: "layout",
28823
+ contentSource: { kind: "inline" },
27817
28824
  skipSectionStyles: true,
27818
28825
  layout: section({
27819
28826
  background: "background",
@@ -27964,6 +28971,7 @@ const testimonialsBlockDefinition = {
27964
28971
  id: "block.testimonials",
27965
28972
  title: "Testimonials",
27966
28973
  category: "marketing",
28974
+ contentSource: { kind: "inline" },
27967
28975
  includeContainerStyles: true,
27968
28976
  previewCustomize: { quickFieldPriority: [
27969
28977
  "avatarLayout",
@@ -28122,6 +29130,7 @@ const columnsBlockDefinition = { manifest: createBlockManifest({
28122
29130
  id: "block.columns",
28123
29131
  title: "Columns",
28124
29132
  category: "layout",
29133
+ contentSource: { kind: "inline" },
28125
29134
  additionalFields: [
28126
29135
  parseFieldDefinition({
28127
29136
  id: "equalHeight",
@@ -28355,6 +29364,7 @@ const collectionBlockDefinition = { manifest: createBlockManifest({
28355
29364
  id: "block.collection",
28356
29365
  title: "Collection",
28357
29366
  category: "layout",
29367
+ contentSource: { kind: "inline" },
28358
29368
  additionalFields: [
28359
29369
  parseFieldDefinition({
28360
29370
  id: "layout",
@@ -28632,6 +29642,7 @@ const featureCardsBlockDefinition = { manifest: createBlockManifest({
28632
29642
  id: "block.feature-cards",
28633
29643
  title: "Feature Cards",
28634
29644
  category: "layout",
29645
+ contentSource: { kind: "inline" },
28635
29646
  includeContainerStyles: true,
28636
29647
  titleSource: "title",
28637
29648
  additionalFields: [
@@ -29015,6 +30026,7 @@ const mediaTextBlockDefinition = { manifest: createBlockManifest({
29015
30026
  id: "block.media-text",
29016
30027
  title: "Media and Text",
29017
30028
  category: "layout",
30029
+ contentSource: { kind: "inline" },
29018
30030
  includeContainerStyles: true,
29019
30031
  titleSource: "title",
29020
30032
  previewCustomize: { quickFieldPriority: [
@@ -29415,6 +30427,7 @@ const appointmentBookingBlockDefinition = {
29415
30427
  paletteHidden: false
29416
30428
  },
29417
30429
  category: "interactive",
30430
+ contentSource: { kind: "inline" },
29418
30431
  tags: [
29419
30432
  "booking",
29420
30433
  "appointment",
@@ -29579,6 +30592,7 @@ const weeklySlotAvailabilityManifest = createBlockManifest({
29579
30592
  paletteHidden: false
29580
30593
  },
29581
30594
  category: "interactive",
30595
+ contentSource: { kind: "inline" },
29582
30596
  tags: [
29583
30597
  "booking",
29584
30598
  "appointment",
@@ -31277,6 +32291,7 @@ const eventRegistrationBlockDefinition = {
31277
32291
  titleSource: "heading",
31278
32292
  description: "Multi-step event registration form",
31279
32293
  category: "interactive",
32294
+ contentSource: { kind: "inline" },
31280
32295
  tags: [
31281
32296
  "events",
31282
32297
  "registration",
@@ -31383,15 +32398,9 @@ const eventRegistrationBlockDefinition = {
31383
32398
  defaultValue: "Complete Registration",
31384
32399
  maxLength: 40
31385
32400
  },
31386
- {
31387
- id: "buttonVariant",
31388
- type: "select",
31389
- label: "Button style",
32401
+ createButtonVariantField({
31390
32402
  description: "Choose a button style from your theme",
31391
- required: false,
31392
- multiple: false,
31393
- defaultValue: "primary",
31394
- options: [
32403
+ variants: [
31395
32404
  {
31396
32405
  value: "primary",
31397
32406
  label: "Primary"
@@ -31404,9 +32413,8 @@ const eventRegistrationBlockDefinition = {
31404
32413
  value: "outline",
31405
32414
  label: "Outline"
31406
32415
  }
31407
- ],
31408
- ui: { intent: "style" }
31409
- }
32416
+ ]
32417
+ })
31410
32418
  ],
31411
32419
  layout: [styledSection({
31412
32420
  baseClass: "",
@@ -31781,6 +32789,7 @@ const courseRegistrationBlockDefinition = {
31781
32789
  titleSource: "heading",
31782
32790
  description: "Enrollment form for multi-session courses",
31783
32791
  category: "interactive",
32792
+ contentSource: { kind: "inline" },
31784
32793
  tags: [
31785
32794
  "courses",
31786
32795
  "enrollment",
@@ -31894,15 +32903,9 @@ const courseRegistrationBlockDefinition = {
31894
32903
  defaultValue: "Sign up",
31895
32904
  maxLength: 40
31896
32905
  },
31897
- {
31898
- id: "buttonVariant",
31899
- type: "select",
31900
- label: "Button style",
32906
+ createButtonVariantField({
31901
32907
  description: "Choose a button style from your theme",
31902
- required: false,
31903
- multiple: false,
31904
- defaultValue: "primary",
31905
- options: [
32908
+ variants: [
31906
32909
  {
31907
32910
  value: "primary",
31908
32911
  label: "Primary"
@@ -31915,9 +32918,8 @@ const courseRegistrationBlockDefinition = {
31915
32918
  value: "outline",
31916
32919
  label: "Outline"
31917
32920
  }
31918
- ],
31919
- ui: { intent: "style" }
31920
- }
32921
+ ]
32922
+ })
31921
32923
  ],
31922
32924
  layout: [styledSection({
31923
32925
  baseClass: "",
@@ -31997,6 +32999,7 @@ const eventDetailsManifest = createBlockManifest({
31997
32999
  titleSource: "heading",
31998
33000
  description: "Date/time, venue, map, and other dates for an event",
31999
33001
  category: "content",
33002
+ contentSource: { kind: "entries" },
32000
33003
  tags: [
32001
33004
  "events",
32002
33005
  "venue",
@@ -32202,6 +33205,7 @@ const courseDetailsBlockDefinition = {
32202
33205
  titleSource: "heading",
32203
33206
  description: "Schedule, venue, price, and enrollment status for a course",
32204
33207
  category: "content",
33208
+ contentSource: { kind: "entries" },
32205
33209
  tags: [
32206
33210
  "courses",
32207
33211
  "schedule",
@@ -32493,6 +33497,7 @@ const eventSpotlightBlockDefinition = {
32493
33497
  paletteHidden: false
32494
33498
  },
32495
33499
  category: "content",
33500
+ contentSource: { kind: "entries" },
32496
33501
  tags: [
32497
33502
  "events",
32498
33503
  "featured",
@@ -35306,6 +36311,7 @@ const eventListingBlockDefinition = {
35306
36311
  paletteHidden: true
35307
36312
  },
35308
36313
  category: "interactive",
36314
+ contentSource: { kind: "entries" },
35309
36315
  tags: [
35310
36316
  "events",
35311
36317
  "listing",
@@ -36511,6 +37517,7 @@ const eventCalendarBlockDefinition = {
36511
37517
  paletteHidden: false
36512
37518
  },
36513
37519
  category: "interactive",
37520
+ contentSource: { kind: "entries" },
36514
37521
  tags: [
36515
37522
  "events",
36516
37523
  "calendar",
@@ -36908,6 +37915,7 @@ const recurringScheduleBlockDefinition = {
36908
37915
  titleSource: "heading",
36909
37916
  description: "A compact weekly schedule with one row per recurring series.",
36910
37917
  category: "interactive",
37918
+ contentSource: { kind: "entries" },
36911
37919
  icon: "CalendarDays",
36912
37920
  tags: [
36913
37921
  "schedule",
@@ -37538,7 +38546,10 @@ const offeringsPreviewFields = [
37538
38546
  label: "Link"
37539
38547
  }
37540
38548
  ],
37541
- ui: { intent: "display" }
38549
+ ui: {
38550
+ intent: "display",
38551
+ widget: "buttonVariant"
38552
+ }
37542
38553
  },
37543
38554
  {
37544
38555
  id: "buttonText",
@@ -37591,6 +38602,7 @@ const offeringsPreviewManifest = createBlockManifest({
37591
38602
  paletteHidden: false
37592
38603
  },
37593
38604
  category: "content",
38605
+ contentSource: { kind: "mixed" },
37594
38606
  tags: [
37595
38607
  "offerings",
37596
38608
  "events",
@@ -37759,6 +38771,7 @@ const embedManifest = createBlockManifest({
37759
38771
  id: "block.embed",
37760
38772
  title: "Embed Content",
37761
38773
  category: "content",
38774
+ contentSource: { kind: "entries" },
37762
38775
  titleSource: "heading",
37763
38776
  additionalFields: [
37764
38777
  parseFieldDefinition({
@@ -38246,6 +39259,7 @@ const imageGalleryBlockDefinition = { manifest: createBlockManifest({
38246
39259
  id: "block.image-gallery",
38247
39260
  title: "Image Gallery",
38248
39261
  category: "content",
39262
+ contentSource: { kind: "inline" },
38249
39263
  previewCustomize: { quickFieldPriority: [
38250
39264
  "aspectRatio",
38251
39265
  "slidesToShow",
@@ -38898,6 +39912,7 @@ const videoGridBlockDefinition = { manifest: createBlockManifest({
38898
39912
  id: "block.video-grid",
38899
39913
  title: "Video Grid",
38900
39914
  category: "media",
39915
+ contentSource: { kind: "inline" },
38901
39916
  skipSectionStyles: true,
38902
39917
  additionalFields: parseFieldDefinitions([
38903
39918
  {
@@ -39068,6 +40083,7 @@ const audioPlayerBlockDefinition = { manifest: createBlockManifest({
39068
40083
  title: "Audio Player",
39069
40084
  titleSource: "title",
39070
40085
  category: "media",
40086
+ contentSource: { kind: "inline" },
39071
40087
  description: "Add a branded audio player for a single track.",
39072
40088
  tags: [
39073
40089
  "audio",
@@ -39179,6 +40195,7 @@ const fileDownloadBlockDefinition = { manifest: createBlockManifest({
39179
40195
  title: "File Download",
39180
40196
  titleSource: ["title", "file.filename"],
39181
40197
  category: "media",
40198
+ contentSource: { kind: "inline" },
39182
40199
  description: "Add a simple public download link for a document, ZIP, or audio file.",
39183
40200
  tags: [
39184
40201
  "file",
@@ -40198,6 +41215,7 @@ const shopBlockDefinition = {
40198
41215
  paletteHidden: false
40199
41216
  },
40200
41217
  category: "interactive",
41218
+ contentSource: { kind: "entries" },
40201
41219
  tags: [
40202
41220
  "shop",
40203
41221
  "passes",
@@ -40397,6 +41415,7 @@ const productListBlockDefinition = {
40397
41415
  paletteHidden: false
40398
41416
  },
40399
41417
  category: "interactive",
41418
+ contentSource: { kind: "entries" },
40400
41419
  tags: [
40401
41420
  "shop",
40402
41421
  "products",
@@ -40538,6 +41557,7 @@ const productDetailBlockDefinition = {
40538
41557
  paletteHidden: false
40539
41558
  },
40540
41559
  category: "interactive",
41560
+ contentSource: { kind: "entries" },
40541
41561
  tags: [
40542
41562
  "shop",
40543
41563
  "product",
@@ -40654,6 +41674,7 @@ const cartBlockDefinition = {
40654
41674
  paletteHidden: false
40655
41675
  },
40656
41676
  category: "interactive",
41677
+ contentSource: { kind: "inline" },
40657
41678
  tags: [
40658
41679
  "shop",
40659
41680
  "cart",
@@ -40736,6 +41757,7 @@ const checkoutBlockDefinition = {
40736
41757
  paletteHidden: false
40737
41758
  },
40738
41759
  category: "interactive",
41760
+ contentSource: { kind: "inline" },
40739
41761
  tags: [
40740
41762
  "shop",
40741
41763
  "checkout",
@@ -40950,6 +41972,7 @@ const giftingBlockDefinition = {
40950
41972
  paletteHidden: false
40951
41973
  },
40952
41974
  category: "interactive",
41975
+ contentSource: { kind: "entries" },
40953
41976
  tags: [
40954
41977
  "gifting",
40955
41978
  "gift cards",
@@ -41304,6 +42327,7 @@ const newsletterSignupBlockDefinition = {
41304
42327
  titleSource: "title",
41305
42328
  description: "Newsletter subscription form with configurable field presets.",
41306
42329
  category: "interactive",
42330
+ contentSource: { kind: "inline" },
41307
42331
  fragments: [{
41308
42332
  fragment: newsletterCopyFragment,
41309
42333
  fieldPriority: 0
@@ -41485,6 +42509,7 @@ const teamMembersBlockDefinition = {
41485
42509
  id: "block.team-members",
41486
42510
  title: "Team Members",
41487
42511
  category: "content",
42512
+ contentSource: { kind: "mixed" },
41488
42513
  titleSource: "heading",
41489
42514
  additionalFields: [
41490
42515
  parseFieldDefinition({
@@ -41925,6 +42950,7 @@ const locationMapBlockDefinition = {
41925
42950
  titleSource: "heading",
41926
42951
  description: "Show a business location with an interactive map and directions link.",
41927
42952
  category: "content",
42953
+ contentSource: { kind: "inline" },
41928
42954
  tags: [
41929
42955
  "map",
41930
42956
  "location",
@@ -42931,213 +43957,6 @@ function getBlockDefinition(name) {
42931
43957
  return blockStore.get(name);
42932
43958
  }
42933
43959
  //#endregion
42934
- //#region ../theme-core/src/gradients/presets.ts
42935
- /**
42936
- * Curated library of gradient presets
42937
- * All gradients use theme color tokens, so they adapt to the site's palette
42938
- */
42939
- const GRADIENT_PRESETS = [
42940
- {
42941
- id: "primary-secondary",
42942
- name: "Primary to Secondary",
42943
- description: "Blend your primary and secondary brand colors",
42944
- type: "linear",
42945
- angle: 135,
42946
- stops: [{
42947
- color: "primary-500",
42948
- position: 0
42949
- }, {
42950
- color: "secondary-500",
42951
- position: 100
42952
- }]
42953
- },
42954
- {
42955
- id: "primary-accent",
42956
- name: "Primary to Accent",
42957
- description: "Energetic gradient from primary to accent",
42958
- type: "linear",
42959
- angle: 135,
42960
- stops: [{
42961
- color: "primary-500",
42962
- position: 0
42963
- }, {
42964
- color: "accent-500",
42965
- position: 100
42966
- }]
42967
- },
42968
- {
42969
- id: "secondary-accent",
42970
- name: "Secondary to Accent",
42971
- description: "Vibrant secondary to accent blend",
42972
- type: "linear",
42973
- angle: 135,
42974
- stops: [{
42975
- color: "secondary-500",
42976
- position: 0
42977
- }, {
42978
- color: "accent-500",
42979
- position: 100
42980
- }]
42981
- },
42982
- {
42983
- id: "primary-light-dark",
42984
- name: "Primary Light to Dark",
42985
- description: "Subtle primary color fade",
42986
- type: "linear",
42987
- angle: 180,
42988
- stops: [{
42989
- color: "primary-500",
42990
- position: 0
42991
- }, {
42992
- color: "primary-900",
42993
- position: 100
42994
- }]
42995
- },
42996
- {
42997
- id: "primary-dark-light",
42998
- name: "Primary Dark to Light",
42999
- description: "Reverse primary fade",
43000
- type: "linear",
43001
- angle: 180,
43002
- stops: [{
43003
- color: "primary-900",
43004
- position: 0
43005
- }, {
43006
- color: "primary-50",
43007
- position: 100
43008
- }]
43009
- },
43010
- {
43011
- id: "secondary-light-dark",
43012
- name: "Secondary Light to Dark",
43013
- description: "Subtle secondary color fade",
43014
- type: "linear",
43015
- angle: 180,
43016
- stops: [{
43017
- color: "secondary-500",
43018
- position: 0
43019
- }, {
43020
- color: "secondary-900",
43021
- position: 100
43022
- }]
43023
- },
43024
- {
43025
- id: "accent-light-dark",
43026
- name: "Accent Light to Dark",
43027
- description: "Accent color depth fade",
43028
- type: "linear",
43029
- angle: 180,
43030
- stops: [{
43031
- color: "accent-500",
43032
- position: 0
43033
- }, {
43034
- color: "accent-900",
43035
- position: 100
43036
- }]
43037
- },
43038
- {
43039
- id: "background-surface",
43040
- name: "Background to Surface",
43041
- description: "Subtle depth using base colors",
43042
- type: "linear",
43043
- angle: 180,
43044
- stops: [{
43045
- color: "background",
43046
- position: 0
43047
- }, {
43048
- color: "surface",
43049
- position: 100
43050
- }]
43051
- },
43052
- {
43053
- id: "neutral-fade",
43054
- name: "Neutral Gradient",
43055
- description: "Elegant neutral color fade",
43056
- type: "linear",
43057
- angle: 180,
43058
- stops: [{
43059
- color: "neutral-900",
43060
- position: 0
43061
- }, {
43062
- color: "neutral-50",
43063
- position: 100
43064
- }]
43065
- },
43066
- {
43067
- id: "primary-radial",
43068
- name: "Primary Spotlight",
43069
- description: "Radial primary gradient from center",
43070
- type: "radial",
43071
- position: "center",
43072
- stops: [{
43073
- color: "primary-500",
43074
- position: 0
43075
- }, {
43076
- color: "primary-900",
43077
- position: 100
43078
- }]
43079
- },
43080
- {
43081
- id: "accent-radial",
43082
- name: "Accent Spotlight",
43083
- description: "Radial accent gradient from center",
43084
- type: "radial",
43085
- position: "center",
43086
- stops: [{
43087
- color: "accent-500",
43088
- position: 0
43089
- }, {
43090
- color: "accent-900",
43091
- position: 100
43092
- }]
43093
- },
43094
- {
43095
- id: "primary-secondary-accent",
43096
- name: "Brand Trio",
43097
- description: "All three brand colors in harmony",
43098
- type: "linear",
43099
- angle: 135,
43100
- stops: [
43101
- {
43102
- color: "primary-500",
43103
- position: 0
43104
- },
43105
- {
43106
- color: "secondary-500",
43107
- position: 50
43108
- },
43109
- {
43110
- color: "accent-500",
43111
- position: 100
43112
- }
43113
- ]
43114
- }
43115
- ];
43116
- //#endregion
43117
- //#region ../theme-core/src/gradients/utils.ts
43118
- /**
43119
- * Convert a GradientConfig to a CSS gradient string
43120
- *
43121
- * @param config - The gradient configuration using theme tokens
43122
- * @param tokens - Map of theme color tokens to hex values
43123
- * @returns CSS gradient string (e.g., "linear-gradient(180deg, #3b82f6 0%, #f59e0b 100%)")
43124
- */
43125
- function gradientToCss(config, tokens) {
43126
- const stops = config.stops.map((stop) => {
43127
- return `${tokens[stop.color] ?? "#000000"} ${stop.position}%`;
43128
- }).join(", ");
43129
- const type = config.type ?? "linear";
43130
- if (type === "radial") {
43131
- const position = config.position ?? "center";
43132
- return `radial-gradient(${config.shape ?? "circle"} at ${position}, ${stops})`;
43133
- }
43134
- if (type === "conic") {
43135
- const position = config.position ?? "center";
43136
- return `conic-gradient(from ${config.angle ?? 0}deg at ${position}, ${stops})`;
43137
- }
43138
- return `linear-gradient(${config.angle ?? 180}deg, ${stops})`;
43139
- }
43140
- //#endregion
43141
43960
  //#region ../blocks/src/system/helpers/backgroundMedia.ts
43142
43961
  function resolveBackgroundMedia(input) {
43143
43962
  const parsedMedia = mediaSchema.safeParse(input.image);
@@ -43175,9 +43994,9 @@ function appendBackgroundMediaClasses(baseClassName, input) {
43175
43994
  ].filter(Boolean).join(" ");
43176
43995
  }
43177
43996
  function gradientPresetCss(value) {
43178
- if (!isString(value)) return null;
43179
- const preset = GRADIENT_PRESETS.find((candidate) => candidate.id === value.trim());
43180
- if (!preset) return null;
43997
+ const presetId = parseGradientPresetId(value);
43998
+ if (!presetId) return null;
43999
+ const preset = getGradientPreset(presetId);
43181
44000
  return gradientToCss(preset, Object.fromEntries(preset.stops.map((stop) => [stop.color, `rgb(var(--tb-${stop.color}))`])));
43182
44001
  }
43183
44002
  const backgroundTransforms = [
@@ -54153,6 +54972,8 @@ function buildThemeCssVars(theme) {
54153
54972
  const inputRadius = mapInputRadius(inputSystem.base.corners, theme.corners);
54154
54973
  return {
54155
54974
  ...generateCssVars(theme.palette),
54975
+ ["--tb-secondaryForeground"]: "var(--tb-onSecondary)",
54976
+ ["--tb-accentForeground"]: "var(--tb-onAccent)",
54156
54977
  ["--tb-scrim"]: "0 0 0",
54157
54978
  ["--tb-shadow"]: "0 0 0",
54158
54979
  ...generateShadowCssVars(theme),
@@ -62833,6 +63654,11 @@ const containerResponsiveThemeCss = `/*
62833
63654
  flex-wrap: wrap;
62834
63655
  }
62835
63656
 
63657
+ /* Text-style CTA actions belong to the section foreground contract. */
63658
+ :where(.theme-scope) [data-block="cta-full"] .cta-row .button-link {
63659
+ color: var(--rb-surface-link-color, var(--rb-surface-text-color, rgb(var(--tb-primary))));
63660
+ }
63661
+
62836
63662
  /* =============================================================================
62837
63663
  * Block: Body Text (content block, Phase 2)
62838
63664
  *
@@ -70072,6 +70898,7 @@ const CANONICAL_REFUND_PLANNER_ERROR_CODES = [
70072
70898
  "already_refunded",
70073
70899
  "idempotency_amount_mismatch",
70074
70900
  "idempotency_method_mismatch",
70901
+ "idempotency_receipt_mismatch",
70075
70902
  "refund_in_progress"
70076
70903
  ],
70077
70904
  "invalid_amount",
@@ -70084,7 +70911,12 @@ const CANONICAL_ADMIN_REFUND_FAILURE_CODES = [
70084
70911
  "payment_intent_not_found",
70085
70912
  "stripe_error",
70086
70913
  "stale_pending_missing_context",
70087
- "non_refundable_deposit_remaining"
70914
+ "non_refundable_deposit_remaining",
70915
+ "deposit_refund_override_required",
70916
+ "refund_revoke_requires_full_line_refund",
70917
+ "payment_receipt_not_found",
70918
+ "payment_receipt_not_refundable",
70919
+ "payment_receipt_attribution_required"
70088
70920
  ];
70089
70921
  [...CANONICAL_REFUND_PLANNER_ERROR_CODES];
70090
70922
  //#endregion
@@ -70097,7 +70929,10 @@ const STANDARD_LINE_ITEM_REFUND_INVALID_CODES = [
70097
70929
  "missing_credit_customer",
70098
70930
  "deposit_refund_override_required",
70099
70931
  "refund_revoke_requires_full_line_refund",
70100
- "unified_order_link_required"
70932
+ "unified_order_link_required",
70933
+ "payment_receipt_not_found",
70934
+ "payment_receipt_not_refundable",
70935
+ "payment_receipt_attribution_required"
70101
70936
  ];
70102
70937
  const EVENT_ATTENDEE_REFUND_INVALID_CODES = ["manual_booking_not_refundable", ...STANDARD_LINE_ITEM_REFUND_INVALID_CODES];
70103
70938
  [...CANONICAL_ADMIN_REFUND_FAILURE_CODES];