@riverbankcms/sdk 0.104.1 → 0.104.3

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 (120) hide show
  1. package/dist/{PreviewEditorSidebar-CmaPXdKu.mjs → PreviewEditorSidebar-CBMhU9p_.mjs} +3 -3
  2. package/dist/{PreviewEditorUI-C5xRTh2b.mjs → PreviewEditorUI-C5KEw4M8.mjs} +2 -2
  3. package/dist/{SdkPreviewModeRuntime-Eks51NcN.mjs → SdkPreviewModeRuntime-Iq12HjL7.mjs} +1142 -177
  4. package/dist/{SiteChromeCustomizeContext-Bt8zb3qu.mjs → SiteChromeCustomizeContext-Cx0NMdyv.mjs} +1640 -877
  5. package/dist/_dts/ai/src/contracts/proposals.d.ts +10 -0
  6. package/dist/_dts/blocks/src/primitives/layout/Grid.d.ts +12 -8
  7. package/dist/_dts/blocks/src/system/blocks/events/event-calendar.d.ts +3 -0
  8. package/dist/_dts/blocks/src/system/blocks/events/shared/layout.d.ts +11 -1
  9. package/dist/_dts/blocks/src/system/blocks/testimonials.d.ts +7 -1
  10. package/dist/_dts/blocks/src/system/constants/events.d.ts +1 -1
  11. package/dist/_dts/blocks/src/system/fragments/library/testimonialsCarousel.d.ts +12 -0
  12. package/dist/_dts/blocks/src/system/node/validation-constants.d.ts +2 -2
  13. package/dist/_dts/blocks/src/system/runtime/nodes/basic.d.ts +14 -0
  14. package/dist/_dts/blocks/src/system/runtime/nodes/buttonAffordance.d.ts +33 -0
  15. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/WeekBoardView.d.ts +28 -0
  16. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/eventCapacity.d.ts +32 -0
  17. package/dist/_dts/blocks/src/system/runtime/nodes/shared/contract-schemas.d.ts +1 -0
  18. package/dist/_dts/blocks/src/system/runtime/nodes/svg.d.ts +77 -0
  19. package/dist/_dts/blocks/src/system/transforms/registry/_utils/surfaceForegroundStyles.d.ts +2 -0
  20. package/dist/_dts/blocks/src/system/transforms/registry/boxStyles.d.ts +3 -40
  21. package/dist/_dts/blocks/src/system/transforms/registry/formatting.d.ts +14 -0
  22. package/dist/_dts/blocks/src/system/transforms/registry/layout.d.ts +11 -0
  23. package/dist/_dts/core/src/branded.d.ts +5 -0
  24. package/dist/_dts/db/src/generated/supabase/database.types.d.ts +18 -0
  25. package/dist/_dts/sdk/src/contracts/system-block-content.d.ts +2 -2
  26. package/dist/_dts/sdk/src/version.d.ts +1 -1
  27. package/dist/_dts/theme-core/src/ThemeScope.d.ts +1 -1
  28. package/dist/_dts/theme-core/src/buttons/affordanceIcons.d.ts +29 -0
  29. package/dist/_dts/theme-core/src/buttons/generateButtonCss.d.ts +6 -0
  30. package/dist/_dts/theme-core/src/buttons/index.d.ts +1 -0
  31. package/dist/_dts/theme-core/src/buttons/personalities/flat-ink.d.ts +20 -0
  32. package/dist/_dts/theme-core/src/buttons/personalities/index.d.ts +11 -0
  33. package/dist/_dts/theme-core/src/buttons/personalities/types.d.ts +4 -0
  34. package/dist/_dts/theme-core/src/buttons/types.d.ts +34 -0
  35. package/dist/_dts/theme-core/src/generated/containerResponsiveThemeCss.d.ts +1 -1
  36. package/dist/_dts/theme-core/src/gradients/types.d.ts +27 -3
  37. package/dist/_dts/theme-core/src/mock-themes/all.d.ts +51 -15
  38. package/dist/_dts/theme-core/src/palette/curated/brand-led.d.ts +13 -0
  39. package/dist/_dts/theme-core/src/palette/curated/index.d.ts +12 -0
  40. package/dist/_dts/theme-core/src/palette/historicalThemePalette.d.ts +44 -0
  41. package/dist/_dts/theme-core/src/palette/index.d.ts +1 -0
  42. package/dist/_dts/theme-core/src/palette/legacySelection.d.ts +13 -2
  43. package/dist/_dts/theme-core/src/palette/persistenceReadSource.d.ts +17 -2
  44. package/dist/_dts/theme-core/src/palette/themePaletteCompatibility.d.ts +3 -4
  45. package/dist/_dts/theme-core/src/runtime/themeCssVarNames.d.ts +1 -0
  46. package/dist/_dts/theme-core/src/schema.d.ts +108 -26
  47. package/dist/_dts/theme-core/src/site-styles/accessibleSurfaces.d.ts +2 -1
  48. package/dist/_dts/theme-core/src/site-styles/curatedSiteStyles.d.ts +50 -1
  49. package/dist/_dts/theme-core/src/site-styles/designState.d.ts +2 -2
  50. package/dist/_dts/theme-core/src/site-styles/generatedSchemas.d.ts +4 -2
  51. package/dist/_dts/theme-core/src/site-styles/headerLooks.d.ts +56 -1
  52. package/dist/_dts/theme-core/src/site-styles/typographyPresets.d.ts +16 -1
  53. package/dist/_dts/theme-core/src/status/index.d.ts +0 -1
  54. package/dist/_dts/theme-core/src/surfaces/foregroundContract.d.ts +19 -0
  55. package/dist/_dts/theme-core/src/surfaces/foregroundRoles.d.ts +9 -0
  56. package/dist/_dts/theme-core/src/surfaces/index.d.ts +2 -0
  57. package/dist/_dts/ui/src/button.d.ts +1 -1
  58. package/dist/cli/index.mjs +1558 -468
  59. package/dist/client/{DiscountCodeDisclosure-Dit2aItR.mjs → DiscountCodeDisclosure-BXM73_E5.mjs} +1 -1
  60. package/dist/client/{EventCombined.client-BnREyCjf.mjs → EventCombined.client-DT5elP7j.mjs} +4 -4
  61. package/dist/client/{EventListing.client-0uHld51x.mjs → EventListing.client-pTYGfV9C.mjs} +2 -2
  62. package/dist/client/{LeafletStaticMap-DJcvSfmj.mjs → LeafletStaticMap-dQrhlUe3.mjs} +1 -1
  63. package/dist/client/{MagicLinkForm-EAsIktfw.mjs → MagicLinkForm-u6Dul4j5.mjs} +2 -2
  64. package/dist/client/{StepIndicator-CRR17tYI.mjs → StepIndicator-nWqineJ2.mjs} +2 -2
  65. package/dist/client/{accordion-B47HIuuH.mjs → accordion-CSJcTUyH.mjs} +1 -1
  66. package/dist/client/{bookingForm-I1E-8F9P.mjs → bookingForm-C73wOuVa.mjs} +6 -6
  67. package/dist/client/bookings.mjs +137 -1
  68. package/dist/client/{buttons-BbPn8OKA.mjs → buttons-DfYyqt8C.mjs} +138 -2
  69. package/dist/client/{carousel-OlM7SyBs.mjs → carousel-fMBb0JSc.mjs} +1 -1
  70. package/dist/client/{cart-BKpG5jz6.mjs → cart-BtaCwT3S.mjs} +3 -3
  71. package/dist/client/{checkout-Dmmr6qoU.mjs → checkout-DkTwZSnh.mjs} +3 -3
  72. package/dist/client/client.mjs +2327 -542
  73. package/dist/client/{colorStyles-DuW4Fjqd.mjs → colorStyles-Wyl6JujD.mjs} +45 -4
  74. package/dist/client/{courseRegistration-CflZiqGk.mjs → courseRegistration-DnLmapJu.mjs} +7 -7
  75. package/dist/client/{eventCalendar-BvoLWcp-.mjs → eventCalendar-BvLOc9KY.mjs} +165 -5
  76. package/dist/client/{eventCombined-DsrO8t_t.mjs → eventCombined-kShgJPQr.mjs} +2 -2
  77. package/dist/client/{eventDetails-C3hxgcJm.mjs → eventDetails-C5NTM0Vo.mjs} +3 -3
  78. package/dist/client/{eventListing-C-hb237X.mjs → eventListing-B82ZdKP6.mjs} +2 -2
  79. package/dist/client/{eventRegistration-B0gyzDGi.mjs → eventRegistration-qJVFqBWo.mjs} +7 -7
  80. package/dist/client/{form-C_RUi6oJ.mjs → form-BvAcKiuu.mjs} +2 -2
  81. package/dist/client/{headerSection-IKQiD2U0.mjs → headerSection-NvAiEHAg.mjs} +3 -3
  82. package/dist/client/hooks.mjs +1034 -356
  83. package/dist/client/{locationMap-8ZBrMzRJ.mjs → locationMap-D0j52xfI.mjs} +3 -3
  84. package/dist/client/{media-CZJKL7fi.mjs → media-BCW_g2cQ.mjs} +1 -1
  85. package/dist/client/{newsletterForm-CYk3ucwj.mjs → newsletterForm-B8_i93qH.mjs} +2 -2
  86. package/dist/client/{pricing-B5GmvfIH.mjs → pricing-DIYnyHOk.mjs} +1 -1
  87. package/dist/client/{productDetail-BjS2Dqzo.mjs → productDetail-w0eAHkuQ.mjs} +3 -3
  88. package/dist/client/{productList-BOHvC8My.mjs → productList-Vsguq5Xt.mjs} +3 -3
  89. package/dist/client/{propsDecoder-WS6UEJwZ.mjs → propsDecoder-CD2pJ1WB.mjs} +37 -2
  90. package/dist/client/rendering/client.mjs +1722 -760
  91. package/dist/client/rendering/islands.mjs +19 -19
  92. package/dist/client/rendering.mjs +2303 -518
  93. package/dist/client/{shop-CON03-wN.mjs → shop-Dgxs-Q8F.mjs} +6 -6
  94. package/dist/client/{shop-commerce-DlqrFgH8.mjs → shop-commerce-DJAhsTaT.mjs} +6 -6
  95. package/dist/client/{shop-commerce-store-l74-Kne6.mjs → shop-commerce-store-CfCXltXW.mjs} +1 -1
  96. package/dist/client/{shopShared-CQheEXSg.mjs → shopShared-CmDcPXUt.mjs} +2 -2
  97. package/dist/client/{useDiscountCodeUi-v6OluyWl.mjs → useDiscountCodeUi-CirrT2bM.mjs} +1 -1
  98. package/dist/client/{useEventFilters-BqSTcNOf.mjs → useEventFilters-CNZxlCcO.mjs} +5 -5
  99. package/dist/client/{usePolling-DMfADjIF.mjs → usePolling-Baks_iBI.mjs} +2 -2
  100. package/dist/preview-next/client/runtime.mjs +3 -3
  101. package/dist/{sdk-runtime-BUmJ0DaT.mjs → sdk-runtime-BfNiFeNJ.mjs} +1 -1
  102. package/dist/{separator-Dd-JYok7.mjs → separator-BhAR_Xmf.mjs} +1 -1
  103. package/dist/server/components.mjs +2293 -531
  104. package/dist/server/config-validation.mjs +1040 -357
  105. package/dist/server/config.mjs +1040 -357
  106. package/dist/server/data.mjs +1034 -356
  107. package/dist/server/index.mjs +1 -1
  108. package/dist/server/next.mjs +2296 -534
  109. package/dist/server/page-converter.mjs +1018 -324
  110. package/dist/server/prebuild.mjs +1 -1
  111. package/dist/server/rendering/server.mjs +2278 -521
  112. package/dist/server/rendering.mjs +2293 -531
  113. package/dist/server/routing.mjs +1092 -338
  114. package/dist/server/server.mjs +1016 -338
  115. package/dist/server/theme-bridge.mjs +1240 -77
  116. package/dist/server/theme.mjs +165 -5
  117. package/dist/styles/index.css +617 -34
  118. package/package.json +1 -1
  119. package/dist/_dts/blocks/src/system/transforms/registry/_utils/sectionForegroundStyles.d.ts +0 -2
  120. package/dist/_dts/theme-core/src/status/contextualColors.d.ts +0 -6
@@ -73799,6 +73799,67 @@ function useFieldPreviewResolvers() {
73799
73799
  return useContext(FieldPreviewResolverContext);
73800
73800
  }
73801
73801
  //#endregion
73802
+ //#region ../theme-core/src/surfaces/foregroundRoles.ts
73803
+ const SURFACE_FOREGROUND_ROLES = [
73804
+ "text",
73805
+ "heading",
73806
+ "link",
73807
+ "supporting"
73808
+ ];
73809
+ //#endregion
73810
+ //#region ../theme-core/src/surfaces/foregroundContract.ts
73811
+ const SURFACE_FOREGROUND_CSS_VARS = {
73812
+ text: "--rb-surface-text-color",
73813
+ heading: "--rb-surface-heading-color",
73814
+ link: "--rb-surface-link-color",
73815
+ supporting: "--rb-surface-supporting-color"
73816
+ };
73817
+ const DEFAULT_SURFACE_TEXT_COLOR = "rgb(var(--tb-text, 17 24 39))";
73818
+ const DEFAULT_ROLE_FALLBACKS = {
73819
+ text: DEFAULT_SURFACE_TEXT_COLOR,
73820
+ heading: DEFAULT_SURFACE_TEXT_COLOR,
73821
+ link: "rgb(var(--tb-primary, var(--tb-text, 17 24 39)))",
73822
+ supporting: "rgb(var(--tb-mutedText, 100 116 139))"
73823
+ };
73824
+ function requireSurfaceColorValue(role, value) {
73825
+ const normalized = value.trim();
73826
+ if (normalized.length === 0) throw new RangeError(`Surface foreground ${role} must be a non-empty CSS color.`);
73827
+ return normalized;
73828
+ }
73829
+ function completeSurfaceForegrounds(input) {
73830
+ const text = requireSurfaceColorValue("text", input.text);
73831
+ return {
73832
+ text,
73833
+ heading: input.heading === void 0 ? text : requireSurfaceColorValue("heading", input.heading),
73834
+ link: input.link === void 0 ? text : requireSurfaceColorValue("link", input.link),
73835
+ supporting: input.supporting === void 0 ? text : requireSurfaceColorValue("supporting", input.supporting)
73836
+ };
73837
+ }
73838
+ function surfaceForegroundValue(role, outsideProviderFallback = DEFAULT_ROLE_FALLBACKS[role]) {
73839
+ const roleVariable = SURFACE_FOREGROUND_CSS_VARS[role];
73840
+ const fallback = requireSurfaceColorValue("fallback", outsideProviderFallback);
73841
+ if (role === "text") return `var(${roleVariable}, ${fallback})`;
73842
+ return `var(${roleVariable}, var(${SURFACE_FOREGROUND_CSS_VARS.text}, ${fallback}))`;
73843
+ }
73844
+ function surfaceForegroundValueWithOpacity(role, opacityPercent) {
73845
+ if (!Number.isFinite(opacityPercent) || opacityPercent < 0 || opacityPercent > 100) throw new RangeError("Surface foreground opacity must be between 0 and 100.");
73846
+ return `color-mix(in srgb, ${surfaceForegroundValue(role)} ${opacityPercent}%, transparent)`;
73847
+ }
73848
+ function surfaceForegroundStyle(input) {
73849
+ const foregrounds = completeSurfaceForegrounds(input);
73850
+ return {
73851
+ color: foregrounds.text,
73852
+ [SURFACE_FOREGROUND_CSS_VARS.text]: foregrounds.text,
73853
+ [SURFACE_FOREGROUND_CSS_VARS.heading]: foregrounds.heading,
73854
+ [SURFACE_FOREGROUND_CSS_VARS.link]: foregrounds.link,
73855
+ [SURFACE_FOREGROUND_CSS_VARS.supporting]: foregrounds.supporting
73856
+ };
73857
+ }
73858
+ function surfaceForegroundDeclarations(input) {
73859
+ const foregrounds = completeSurfaceForegrounds(input);
73860
+ return [`color: ${foregrounds.text}`, ...SURFACE_FOREGROUND_ROLES.map((role) => `${SURFACE_FOREGROUND_CSS_VARS[role]}: ${foregrounds[role]}`)];
73861
+ }
73862
+ //#endregion
73802
73863
  //#region ../theme-core/src/tokens/colorTokenParts.ts
73803
73864
  function parseOpacityPercent(source) {
73804
73865
  const trimmed = source.trim();
@@ -73848,9 +73909,17 @@ function parseToken(source) {
73848
73909
  if (parts.kind === "invalid") return { token: source };
73849
73910
  return {
73850
73911
  token: parts.token,
73851
- alpha: parts.opacityPercent === null ? void 0 : parts.opacityPercent / 100
73912
+ opacityPercent: parts.opacityPercent === null ? void 0 : parts.opacityPercent
73852
73913
  };
73853
73914
  }
73915
+ const SURFACE_TEXT_ROLE_BY_TOKEN = {
73916
+ text: "text",
73917
+ heading: "heading",
73918
+ mutedText: "supporting"
73919
+ };
73920
+ function surfaceRoleForTextToken(token) {
73921
+ return Object.prototype.hasOwnProperty.call(SURFACE_TEXT_ROLE_BY_TOKEN, token) ? SURFACE_TEXT_ROLE_BY_TOKEN[token] : null;
73922
+ }
73854
73923
  /**
73855
73924
  * Converts a theme color token to a CSS rgb value.
73856
73925
  * This is the primary function for applying theme colors to CSS properties.
@@ -73864,11 +73933,26 @@ function parseToken(source) {
73864
73933
  * rgbColorValue('raw:transparent') // => 'transparent'
73865
73934
  */
73866
73935
  function rgbColorValue(token) {
73867
- const { token: baseToken, alpha, raw } = parseToken(token);
73936
+ const { token: baseToken, opacityPercent, raw } = parseToken(token);
73868
73937
  if (raw) return raw;
73869
73938
  const cssVar = `${COLOR_VAR_PREFIX}${baseToken}`;
73870
- if (alpha === void 0) return `rgb(var(${cssVar}))`;
73871
- return `rgb(var(${cssVar}) / ${alpha})`;
73939
+ if (opacityPercent === void 0) return `rgb(var(${cssVar}))`;
73940
+ return `rgb(var(${cssVar}) / ${opacityPercent / 100})`;
73941
+ }
73942
+ /**
73943
+ * Converts a theme color token to a CSS variable reference.
73944
+ * Note: This returns the base variable without rgb() wrapper, ignoring opacity.
73945
+ *
73946
+ * @param token - Theme color token
73947
+ * @returns CSS variable reference
73948
+ *
73949
+ * @example
73950
+ * cssVarValue('primary') // => 'var(--tb-primary)'
73951
+ * cssVarValue('surface/95') // => 'var(--tb-surface)' (opacity ignored)
73952
+ */
73953
+ function cssVarValue(token) {
73954
+ const { token: baseToken } = parseToken(token);
73955
+ return `var(${COLOR_VAR_PREFIX}${baseToken})`;
73872
73956
  }
73873
73957
  /**
73874
73958
  * Creates a backgroundColor style object from a theme token.
@@ -73886,6 +73970,9 @@ function backgroundColorStyle(token) {
73886
73970
  * @returns CSSProperties with color
73887
73971
  */
73888
73972
  function textColorStyle(token) {
73973
+ const parsed = parseToken(token);
73974
+ const surfaceRole = parsed.raw ? null : surfaceRoleForTextToken(parsed.token);
73975
+ if (surfaceRole) return { color: parsed.opacityPercent === void 0 ? surfaceForegroundValue(surfaceRole) : surfaceForegroundValueWithOpacity(surfaceRole, parsed.opacityPercent) };
73889
73976
  return { color: rgbColorValue(token) };
73890
73977
  }
73891
73978
  /**
@@ -74220,6 +74307,10 @@ const buttonBorderSchema = z$1.object({
74220
74307
  widthClass: z$1.string(),
74221
74308
  colorToken: themeColorTokenSchema
74222
74309
  });
74310
+ const buttonVariantAffordanceSchema = z$1.object({
74311
+ iconId: z$1.string().min(1),
74312
+ colorToken: themeColorTokenSchema.optional()
74313
+ });
74223
74314
  const variantShadowSchema = z$1.object({
74224
74315
  elevation: z$1.enum([
74225
74316
  "none",
@@ -74273,7 +74364,8 @@ const buttonVariantSchema = z$1.object({
74273
74364
  border: buttonBorderSchema.optional(),
74274
74365
  hoverBackgroundToken: z$1.string().optional(),
74275
74366
  effects: variantEffectsSchema.optional(),
74276
- sizes: variantSizeOverridesSchema.optional()
74367
+ sizes: variantSizeOverridesSchema.optional(),
74368
+ affordance: buttonVariantAffordanceSchema.optional()
74277
74369
  });
74278
74370
  const buttonSystemSchema = z$1.object({
74279
74371
  global: buttonGlobalSettingsSchema,
@@ -76037,7 +76129,53 @@ function generateDefaultButtonSystem(theme) {
76037
76129
  };
76038
76130
  }
76039
76131
  //#endregion
76132
+ //#region ../theme-core/src/buttons/affordanceIcons.ts
76133
+ /**
76134
+ * Affordance icon path data for CSS-emitted button affordances.
76135
+ *
76136
+ * A button variant may declare a trailing `affordance` icon (see
76137
+ * `ButtonVariantAffordance`). The generated button CSS renders that icon as a
76138
+ * masked `::after` pseudo-element, so the personality supplies it to every
76139
+ * button of the variant without per-node authoring.
76140
+ *
76141
+ * Icons live in the `@riverbankcms/blocks` registry, but the button CSS is
76142
+ * generated here in theme-core, so this module carries a small, curated copy of
76143
+ * the *affordance-eligible* icon path data (arrows/chevrons — the action-oriented
76144
+ * subset). The `d` values below are duplicated verbatim from the matching entries
76145
+ * in `blocks/src/system/icons/svg.tsx`; ids match the registry ids exactly so a
76146
+ * node-level `trailingIcon` and a personality `affordance` share one id space.
76147
+ *
76148
+ * Keep this set intentionally tiny. It is not the full CTA icon set — only the
76149
+ * shapes that read as a trailing affordance.
76150
+ */
76151
+ /** Registry icon id → the SVG path `d` fragments composing that icon. */
76152
+ const AFFORDANCE_ICON_PATHS = {
76153
+ ArrowRight: ["M5 12h14", "m13 6 6 6-6 6"],
76154
+ ArrowLeft: ["M19 12H5", "m11 6-6 6 6 6"],
76155
+ ChevronRight: ["m9 18 6-6-6-6"],
76156
+ ChevronLeft: ["m15 18-6-6 6-6"],
76157
+ ChevronDown: ["m6 9 6 6 6-6"],
76158
+ ArrowUpRight: ["M7 17 17 7", "M7 7h10v10"]
76159
+ };
76160
+ /**
76161
+ * Build a `data:image/svg+xml,...` URL for an affordance icon, suitable for use
76162
+ * as a CSS `mask-image`. The stroke is painted solid black so the mask's alpha
76163
+ * traces the icon outline; the visible colour is supplied separately by the
76164
+ * `::after` rule's `background-color`. Returns `null` for unknown ids.
76165
+ */
76166
+ function affordanceIconMaskUrl(iconId) {
76167
+ const paths = AFFORDANCE_ICON_PATHS[iconId];
76168
+ if (!paths || paths.length === 0) return null;
76169
+ 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, " ")}`;
76170
+ }
76171
+ //#endregion
76040
76172
  //#region ../theme-core/src/buttons/generateButtonCss.ts
76173
+ /**
76174
+ * Class the `button` runtime node adds when it renders its own trailing icon,
76175
+ * so a node-level icon suppresses the personality's CSS `::after` affordance
76176
+ * (node overrides personality). Shared so generator and renderer can't drift.
76177
+ */
76178
+ const AFFORDANCE_SUPPRESS_CLASS = "rb-affordance-off";
76041
76179
  const BUTTON_SIZE_NAMES = buttonSizeNameSchema.options;
76042
76180
  /**
76043
76181
  * Letter spacing token → CSS value.
@@ -76132,10 +76270,40 @@ function variantChunks(variant, global, themeSizes, themeId, tokens, theme) {
76132
76270
  out.push(variantFocusVisibleRule(variantId, themeId));
76133
76271
  const effects = variantEffectsCss(variant, themeId, tokens, theme);
76134
76272
  if (effects) out.push({ raw: effects });
76273
+ const affordance = variantAffordanceRule(variant, selector, tokens);
76274
+ if (affordance) out.push(affordance);
76135
76275
  out.push(...variantDisabledRules(variantId, themeId));
76136
76276
  out.push(...variantSizeRules(variant, variantId, themeSizes, themeId));
76137
76277
  return out;
76138
76278
  }
76279
+ /**
76280
+ * Emit the optional trailing affordance icon as a masked `::after`.
76281
+ *
76282
+ * Only variants that declare `affordance` with a known icon id produce a rule —
76283
+ * every other variant is byte-identical to before. The `:not(.rb-affordance-off)`
76284
+ * guard lets a `button` node that renders its own trailing icon suppress this
76285
+ * one (node overrides personality). Colour comes from the affordance token, or
76286
+ * `currentColor` (the button text colour) when no token is given.
76287
+ */
76288
+ function variantAffordanceRule(variant, selector, tokens) {
76289
+ const affordance = variant.affordance;
76290
+ if (!affordance) return null;
76291
+ const maskUrl = affordanceIconMaskUrl(affordance.iconId);
76292
+ if (!maskUrl) return null;
76293
+ const color = affordance.colorToken ? tokens.getColor(affordance.colorToken) : "currentColor";
76294
+ const mask = `url("${maskUrl}") no-repeat center / contain`;
76295
+ return rule(`${selector}:not(.${AFFORDANCE_SUPPRESS_CLASS})::after`, [
76296
+ ["content", "\"\""],
76297
+ ["display", "inline-block"],
76298
+ ["width", "1em"],
76299
+ ["height", "1em"],
76300
+ ["margin-inline-start", "0.5em"],
76301
+ ["flex", "0 0 auto"],
76302
+ ["background-color", color],
76303
+ ["-webkit-mask", mask],
76304
+ ["mask", mask]
76305
+ ]);
76306
+ }
76139
76307
  function parseButtonVariantIdForCss(value) {
76140
76308
  const variantId = parseThemeButtonVariantId(value);
76141
76309
  if (!variantId) throw new Error("Button variant id must be a non-empty string");
@@ -76851,48 +77019,51 @@ const editorialLink = defineButtonPersonality({
76851
77019
  }
76852
77020
  });
76853
77021
  //#endregion
76854
- //#region ../theme-core/src/buttons/personalities/ink-stamp.ts
77022
+ //#region ../theme-core/src/buttons/personalities/flat-ink.ts
76855
77023
  /**
76856
- * Ink Stamp — solid earthy fills with a bordered, hand-stamped block-print
76857
- * feel. Reads as bold and handmade; suits expressive craft brands.
77024
+ * Flat Ink — a solid ink primary, a hairline ghost secondary, and a single
77025
+ * amber accent climax, all completely flat (no drop shadow) with a modest
77026
+ * radius. Reads as grounded, editorial and clinician-precise: the Fulcrum
77027
+ * physiotherapy voice. The primary shifts to the secondary (moss) on hover and
77028
+ * every variant lifts 2px; the amber accent is meant to be used sparingly as
77029
+ * the page's one conversion climax.
76858
77030
  */
76859
- const inkStamp = defineButtonPersonality({
76860
- id: "ink-stamp",
76861
- name: "Ink Stamp",
76862
- description: "Hand-stamped block-print buttons with a slight lift on hover.",
77031
+ const flatInk = defineButtonPersonality({
77032
+ id: "flat-ink",
77033
+ name: "Flat Ink",
77034
+ description: "Flat solid-ink primary, hairline ghost secondary, and a single amber accent climax — modest radius, no shadow.",
76863
77035
  tags: {
76864
- tone: "bold",
76865
- energy: "vibrant",
76866
- motion: "standard",
76867
- era: "organic"
77036
+ tone: "classic",
77037
+ energy: "calm",
77038
+ motion: "subtle",
77039
+ era: "editorial"
76868
77040
  },
76869
77041
  buttonSystem: {
76870
77042
  global: {
76871
77043
  cornerStyle: "rounded",
76872
- shadow: "none",
76873
- textTransform: "uppercase",
77044
+ shadow: "low",
77045
+ textTransform: "none",
76874
77046
  fontWeight: 600,
76875
77047
  borderWidth: 1,
76876
- hoverTransform: "none",
76877
- hoverColor: "none",
76878
- letterSpacing: "loose"
77048
+ typography: "body",
77049
+ letterSpacing: "tight",
77050
+ paddingPreset: "default",
77051
+ hoverTransform: "lift",
77052
+ hoverColor: "none"
76879
77053
  },
76880
77054
  sizes: {
76881
77055
  sm: {
76882
- padding: "0.5rem 1.25rem",
76883
- fontSize: "text-xs"
76884
- },
76885
- md: {
76886
- padding: "0.75rem 1.75rem",
77056
+ padding: "0.625rem 1.125rem",
76887
77057
  fontSize: "text-sm"
76888
77058
  },
77059
+ md: { padding: "0.8125rem 1.375rem" },
76889
77060
  lg: {
76890
- padding: "0.875rem 2.25rem",
76891
- fontSize: "text-base"
77061
+ padding: "0.9375rem 1.625rem",
77062
+ fontSize: "text-lg"
76892
77063
  },
76893
77064
  xl: {
76894
- padding: "1.125rem 2.75rem",
76895
- fontSize: "text-lg"
77065
+ padding: "1.0625rem 2rem",
77066
+ fontSize: "text-xl"
76896
77067
  }
76897
77068
  },
76898
77069
  variants: [
@@ -76906,199 +77077,91 @@ const inkStamp = defineButtonPersonality({
76906
77077
  colorToken: "primary"
76907
77078
  },
76908
77079
  textColorToken: "primaryForeground",
76909
- borderRadius: "rounded-md",
76910
- effects: {
76911
- hover: [{
76912
- effectId: "drop-shadow",
76913
- options: { intensity: "medium" }
76914
- }, {
76915
- effectId: "scale-up",
76916
- options: { scale: "1.02" }
76917
- }],
76918
- active: [{
76919
- effectId: "scale-down",
76920
- options: { scale: "0.98" }
76921
- }]
76922
- }
76923
- },
76924
- {
76925
- id: "secondary",
76926
- name: "Secondary",
76927
- enabled: true,
76928
- priority: 2,
76929
- background: { type: "transparent" },
76930
- textColorToken: "primary",
76931
- borderRadius: "rounded-md",
76932
- border: {
76933
- widthClass: "border-2",
76934
- colorToken: "primary"
77080
+ borderRadius: "rounded-lg",
77081
+ affordance: {
77082
+ iconId: "ArrowRight",
77083
+ colorToken: "accent"
77084
+ },
77085
+ shadow: {
77086
+ elevation: "none",
77087
+ softness: null,
77088
+ position: "bottom"
76935
77089
  },
76936
77090
  effects: { hover: [{
77091
+ effectId: "lift",
77092
+ options: { translateY: "-2px" }
77093
+ }, {
76937
77094
  effectId: "background-on-hover",
76938
- options: { colorToken: "surface" }
77095
+ options: { colorToken: "secondary" }
76939
77096
  }] }
76940
77097
  },
76941
77098
  {
76942
- id: "outline",
76943
- name: "Outline",
77099
+ id: "secondary",
77100
+ name: "Secondary",
76944
77101
  enabled: true,
76945
- priority: 3,
77102
+ priority: 2,
76946
77103
  background: { type: "transparent" },
76947
- textColorToken: "text",
76948
- borderRadius: "rounded-md",
77104
+ textColorToken: "primary",
77105
+ borderRadius: "rounded-lg",
76949
77106
  border: {
76950
- widthClass: "border-2",
77107
+ widthClass: "border",
76951
77108
  colorToken: "border"
76952
77109
  },
77110
+ shadow: {
77111
+ elevation: "none",
77112
+ softness: null,
77113
+ position: "bottom"
77114
+ },
76953
77115
  effects: { hover: [{
77116
+ effectId: "lift",
77117
+ options: { translateY: "-2px" }
77118
+ }, {
76954
77119
  effectId: "background-on-hover",
76955
- options: { colorToken: "surface" }
77120
+ options: { colorToken: "surfaceAlt" }
76956
77121
  }] }
76957
77122
  },
76958
77123
  {
76959
- id: "ghost",
76960
- name: "Ghost",
77124
+ id: "accent",
77125
+ name: "Accent",
76961
77126
  enabled: true,
76962
77127
  priority: 3,
76963
- background: { type: "transparent" },
76964
- textColorToken: "accent",
76965
- borderRadius: "rounded-none",
76966
- sizes: {
76967
- sm: {
76968
- padding: "0.375rem 0",
76969
- fontSize: "text-xs"
76970
- },
76971
- md: {
76972
- padding: "0.5rem 0",
76973
- fontSize: "text-sm"
76974
- },
76975
- lg: {
76976
- padding: "0.625rem 0",
76977
- fontSize: "text-base"
76978
- },
76979
- xl: {
76980
- padding: "0.75rem 0",
76981
- fontSize: "text-lg"
76982
- }
77128
+ background: {
77129
+ type: "solid",
77130
+ colorToken: "accent"
76983
77131
  },
76984
- effects: { base: [{
76985
- effectId: "border-bottom-grow",
76986
- options: {
76987
- height: 1,
76988
- colorToken: "accent",
76989
- origin: "left"
76990
- }
77132
+ textColorToken: "accentForeground",
77133
+ borderRadius: "rounded-lg",
77134
+ shadow: {
77135
+ elevation: "none",
77136
+ softness: null,
77137
+ position: "bottom"
77138
+ },
77139
+ affordance: {
77140
+ iconId: "ArrowRight",
77141
+ colorToken: "accentForeground"
77142
+ },
77143
+ effects: { hover: [{
77144
+ effectId: "lift",
77145
+ options: { translateY: "-2px" }
76991
77146
  }] }
76992
77147
  }
76993
77148
  ]
76994
77149
  }
76995
77150
  });
76996
77151
  //#endregion
76997
- //#region ../theme-core/src/buttons/personalities/joy-stamp.ts
77152
+ //#region ../theme-core/src/buttons/personalities/ink-stamp.ts
76998
77153
  /**
76999
- * Joy Stamp — neo-brutalist pills with a hard, brand-coloured offset shadow
77000
- * that collapses as the button presses into it on hover. Authored for the
77001
- * Original Joy site style: a cream "stamp" shadow under the solid primary, and
77002
- * a brown shadow under the cream outline. Reads as bold, warm, and handmade.
77003
- *
77004
- * The coloured offset shadow relies on the per-variant `shadow.colorToken`
77005
- * extension; the press is the shared `press-down` effect, which matches its
77006
- * translate to each variant's own shadow offset.
77154
+ * Ink Stamp — solid earthy fills with a bordered, hand-stamped block-print
77155
+ * feel. Reads as bold and handmade; suits expressive craft brands.
77007
77156
  */
77008
- const joyStamp = defineButtonPersonality({
77009
- id: "joy-stamp",
77010
- name: "Joy Stamp",
77011
- description: "Pill buttons with a hard, brand-coloured offset shadow that presses in on hover.",
77157
+ const inkStamp = defineButtonPersonality({
77158
+ id: "ink-stamp",
77159
+ name: "Ink Stamp",
77160
+ description: "Hand-stamped block-print buttons with a slight lift on hover.",
77012
77161
  tags: {
77013
77162
  tone: "bold",
77014
77163
  energy: "vibrant",
77015
- motion: "expressive",
77016
- era: "organic"
77017
- },
77018
- buttonSystem: {
77019
- global: {
77020
- cornerStyle: "pill",
77021
- shadow: "high",
77022
- textTransform: "none",
77023
- typography: "heading",
77024
- fontWeight: 700,
77025
- fontSize: "text-lg",
77026
- borderWidth: 2,
77027
- hoverTransform: "none",
77028
- hoverColor: "none"
77029
- },
77030
- sizes: {
77031
- sm: {
77032
- padding: "0.625rem 1.25rem",
77033
- fontSize: "text-base"
77034
- },
77035
- md: {
77036
- padding: "0.875rem 1.75rem",
77037
- fontSize: "text-lg"
77038
- },
77039
- lg: {
77040
- padding: "1.125rem 2.25rem",
77041
- fontSize: "text-xl"
77042
- },
77043
- xl: {
77044
- padding: "1.25rem 2.75rem",
77045
- fontSize: "text-2xl"
77046
- }
77047
- },
77048
- variants: [{
77049
- id: "primary",
77050
- name: "Primary",
77051
- enabled: true,
77052
- priority: 1,
77053
- background: {
77054
- type: "solid",
77055
- colorToken: "primary"
77056
- },
77057
- textColorToken: "primaryForeground",
77058
- borderRadius: "rounded-full",
77059
- shadow: {
77060
- elevation: "high",
77061
- softness: "hard",
77062
- position: "bottom-right",
77063
- colorToken: "text"
77064
- },
77065
- effects: { hover: [{ effectId: "press-down" }] }
77066
- }, {
77067
- id: "secondary",
77068
- name: "Secondary",
77069
- enabled: true,
77070
- priority: 2,
77071
- background: { type: "transparent" },
77072
- textColorToken: "text",
77073
- borderRadius: "rounded-full",
77074
- border: {
77075
- widthClass: "border-2",
77076
- colorToken: "text"
77077
- },
77078
- shadow: {
77079
- elevation: "high",
77080
- softness: "hard",
77081
- position: "bottom-right",
77082
- colorToken: "secondary"
77083
- },
77084
- effects: { hover: [{ effectId: "press-down" }] }
77085
- }]
77086
- }
77087
- });
77088
- //#endregion
77089
- //#region ../theme-core/src/buttons/personalities/ornate-ritual.ts
77090
- /**
77091
- * Ornate Ritual — framed, ceremonial buttons with jewel-toned fills and
77092
- * deliberate spacing. Designed for music, ceremony, and soulful event sites.
77093
- */
77094
- const ornateRitual = defineButtonPersonality({
77095
- id: "ornate-ritual",
77096
- name: "Ornate Ritual",
77097
- description: "Ceremonial framed buttons with jewel-toned fills and quiet color-change hover states.",
77098
- tags: {
77099
- tone: "classic",
77100
- energy: "vibrant",
77101
- motion: "subtle",
77164
+ motion: "standard",
77102
77165
  era: "organic"
77103
77166
  },
77104
77167
  buttonSystem: {
@@ -77114,20 +77177,20 @@ const ornateRitual = defineButtonPersonality({
77114
77177
  },
77115
77178
  sizes: {
77116
77179
  sm: {
77117
- padding: "0.5625rem 1.25rem",
77180
+ padding: "0.5rem 1.25rem",
77118
77181
  fontSize: "text-xs"
77119
77182
  },
77120
77183
  md: {
77121
77184
  padding: "0.75rem 1.75rem",
77122
- fontSize: "text-xs"
77185
+ fontSize: "text-sm"
77123
77186
  },
77124
77187
  lg: {
77125
77188
  padding: "0.875rem 2.25rem",
77126
- fontSize: "text-sm"
77189
+ fontSize: "text-base"
77127
77190
  },
77128
77191
  xl: {
77129
- padding: "1rem 2.75rem",
77130
- fontSize: "text-base"
77192
+ padding: "1.125rem 2.75rem",
77193
+ fontSize: "text-lg"
77131
77194
  }
77132
77195
  },
77133
77196
  variants: [
@@ -77142,19 +77205,13 @@ const ornateRitual = defineButtonPersonality({
77142
77205
  },
77143
77206
  textColorToken: "primaryForeground",
77144
77207
  borderRadius: "rounded-md",
77145
- border: {
77146
- widthClass: "border",
77147
- colorToken: "primary"
77148
- },
77149
- shadow: {
77150
- elevation: "none",
77151
- softness: null,
77152
- position: "bottom"
77153
- },
77154
77208
  effects: {
77155
77209
  hover: [{
77156
- effectId: "background-on-hover",
77157
- options: { colorToken: "primary-100" }
77210
+ effectId: "drop-shadow",
77211
+ options: { intensity: "medium" }
77212
+ }, {
77213
+ effectId: "scale-up",
77214
+ options: { scale: "1.02" }
77158
77215
  }],
77159
77216
  active: [{
77160
77217
  effectId: "scale-down",
@@ -77167,21 +77224,13 @@ const ornateRitual = defineButtonPersonality({
77167
77224
  name: "Secondary",
77168
77225
  enabled: true,
77169
77226
  priority: 2,
77170
- background: {
77171
- type: "solid",
77172
- colorToken: "secondary"
77173
- },
77174
- textColorToken: "primaryForeground",
77227
+ background: { type: "transparent" },
77228
+ textColorToken: "primary",
77175
77229
  borderRadius: "rounded-md",
77176
77230
  border: {
77177
- widthClass: "border",
77231
+ widthClass: "border-2",
77178
77232
  colorToken: "primary"
77179
77233
  },
77180
- shadow: {
77181
- elevation: "none",
77182
- softness: null,
77183
- position: "bottom"
77184
- },
77185
77234
  effects: { hover: [{
77186
77235
  effectId: "background-on-hover",
77187
77236
  options: { colorToken: "surface" }
@@ -77193,20 +77242,269 @@ const ornateRitual = defineButtonPersonality({
77193
77242
  enabled: true,
77194
77243
  priority: 3,
77195
77244
  background: { type: "transparent" },
77196
- textColorToken: "primary",
77245
+ textColorToken: "text",
77197
77246
  borderRadius: "rounded-md",
77198
77247
  border: {
77199
- widthClass: "border",
77200
- colorToken: "primary"
77201
- },
77202
- shadow: {
77203
- elevation: "none",
77204
- softness: null,
77205
- position: "bottom"
77248
+ widthClass: "border-2",
77249
+ colorToken: "border"
77206
77250
  },
77207
77251
  effects: { hover: [{
77208
77252
  effectId: "background-on-hover",
77209
- options: { colorToken: "muted" }
77253
+ options: { colorToken: "surface" }
77254
+ }] }
77255
+ },
77256
+ {
77257
+ id: "ghost",
77258
+ name: "Ghost",
77259
+ enabled: true,
77260
+ priority: 3,
77261
+ background: { type: "transparent" },
77262
+ textColorToken: "accent",
77263
+ borderRadius: "rounded-none",
77264
+ sizes: {
77265
+ sm: {
77266
+ padding: "0.375rem 0",
77267
+ fontSize: "text-xs"
77268
+ },
77269
+ md: {
77270
+ padding: "0.5rem 0",
77271
+ fontSize: "text-sm"
77272
+ },
77273
+ lg: {
77274
+ padding: "0.625rem 0",
77275
+ fontSize: "text-base"
77276
+ },
77277
+ xl: {
77278
+ padding: "0.75rem 0",
77279
+ fontSize: "text-lg"
77280
+ }
77281
+ },
77282
+ effects: { base: [{
77283
+ effectId: "border-bottom-grow",
77284
+ options: {
77285
+ height: 1,
77286
+ colorToken: "accent",
77287
+ origin: "left"
77288
+ }
77289
+ }] }
77290
+ }
77291
+ ]
77292
+ }
77293
+ });
77294
+ //#endregion
77295
+ //#region ../theme-core/src/buttons/personalities/joy-stamp.ts
77296
+ /**
77297
+ * Joy Stamp — neo-brutalist pills with a hard, brand-coloured offset shadow
77298
+ * that collapses as the button presses into it on hover. Authored for the
77299
+ * Original Joy site style: a cream "stamp" shadow under the solid primary, and
77300
+ * a brown shadow under the cream outline. Reads as bold, warm, and handmade.
77301
+ *
77302
+ * The coloured offset shadow relies on the per-variant `shadow.colorToken`
77303
+ * extension; the press is the shared `press-down` effect, which matches its
77304
+ * translate to each variant's own shadow offset.
77305
+ */
77306
+ const joyStamp = defineButtonPersonality({
77307
+ id: "joy-stamp",
77308
+ name: "Joy Stamp",
77309
+ description: "Pill buttons with a hard, brand-coloured offset shadow that presses in on hover.",
77310
+ tags: {
77311
+ tone: "bold",
77312
+ energy: "vibrant",
77313
+ motion: "expressive",
77314
+ era: "organic"
77315
+ },
77316
+ buttonSystem: {
77317
+ global: {
77318
+ cornerStyle: "pill",
77319
+ shadow: "high",
77320
+ textTransform: "none",
77321
+ typography: "heading",
77322
+ fontWeight: 700,
77323
+ fontSize: "text-lg",
77324
+ borderWidth: 2,
77325
+ hoverTransform: "none",
77326
+ hoverColor: "none"
77327
+ },
77328
+ sizes: {
77329
+ sm: {
77330
+ padding: "0.625rem 1.25rem",
77331
+ fontSize: "text-base"
77332
+ },
77333
+ md: {
77334
+ padding: "0.875rem 1.75rem",
77335
+ fontSize: "text-lg"
77336
+ },
77337
+ lg: {
77338
+ padding: "1.125rem 2.25rem",
77339
+ fontSize: "text-xl"
77340
+ },
77341
+ xl: {
77342
+ padding: "1.25rem 2.75rem",
77343
+ fontSize: "text-2xl"
77344
+ }
77345
+ },
77346
+ variants: [{
77347
+ id: "primary",
77348
+ name: "Primary",
77349
+ enabled: true,
77350
+ priority: 1,
77351
+ background: {
77352
+ type: "solid",
77353
+ colorToken: "primary"
77354
+ },
77355
+ textColorToken: "primaryForeground",
77356
+ borderRadius: "rounded-full",
77357
+ shadow: {
77358
+ elevation: "high",
77359
+ softness: "hard",
77360
+ position: "bottom-right",
77361
+ colorToken: "text"
77362
+ },
77363
+ effects: { hover: [{ effectId: "press-down" }] }
77364
+ }, {
77365
+ id: "secondary",
77366
+ name: "Secondary",
77367
+ enabled: true,
77368
+ priority: 2,
77369
+ background: { type: "transparent" },
77370
+ textColorToken: "text",
77371
+ borderRadius: "rounded-full",
77372
+ border: {
77373
+ widthClass: "border-2",
77374
+ colorToken: "text"
77375
+ },
77376
+ shadow: {
77377
+ elevation: "high",
77378
+ softness: "hard",
77379
+ position: "bottom-right",
77380
+ colorToken: "secondary"
77381
+ },
77382
+ effects: { hover: [{ effectId: "press-down" }] }
77383
+ }]
77384
+ }
77385
+ });
77386
+ //#endregion
77387
+ //#region ../theme-core/src/buttons/personalities/ornate-ritual.ts
77388
+ /**
77389
+ * Ornate Ritual — framed, ceremonial buttons with jewel-toned fills and
77390
+ * deliberate spacing. Designed for music, ceremony, and soulful event sites.
77391
+ */
77392
+ const ornateRitual = defineButtonPersonality({
77393
+ id: "ornate-ritual",
77394
+ name: "Ornate Ritual",
77395
+ description: "Ceremonial framed buttons with jewel-toned fills and quiet color-change hover states.",
77396
+ tags: {
77397
+ tone: "classic",
77398
+ energy: "vibrant",
77399
+ motion: "subtle",
77400
+ era: "organic"
77401
+ },
77402
+ buttonSystem: {
77403
+ global: {
77404
+ cornerStyle: "rounded",
77405
+ shadow: "none",
77406
+ textTransform: "uppercase",
77407
+ fontWeight: 600,
77408
+ borderWidth: 1,
77409
+ hoverTransform: "none",
77410
+ hoverColor: "none",
77411
+ letterSpacing: "loose"
77412
+ },
77413
+ sizes: {
77414
+ sm: {
77415
+ padding: "0.5625rem 1.25rem",
77416
+ fontSize: "text-xs"
77417
+ },
77418
+ md: {
77419
+ padding: "0.75rem 1.75rem",
77420
+ fontSize: "text-xs"
77421
+ },
77422
+ lg: {
77423
+ padding: "0.875rem 2.25rem",
77424
+ fontSize: "text-sm"
77425
+ },
77426
+ xl: {
77427
+ padding: "1rem 2.75rem",
77428
+ fontSize: "text-base"
77429
+ }
77430
+ },
77431
+ variants: [
77432
+ {
77433
+ id: "primary",
77434
+ name: "Primary",
77435
+ enabled: true,
77436
+ priority: 1,
77437
+ background: {
77438
+ type: "solid",
77439
+ colorToken: "primary"
77440
+ },
77441
+ textColorToken: "primaryForeground",
77442
+ borderRadius: "rounded-md",
77443
+ border: {
77444
+ widthClass: "border",
77445
+ colorToken: "primary"
77446
+ },
77447
+ shadow: {
77448
+ elevation: "none",
77449
+ softness: null,
77450
+ position: "bottom"
77451
+ },
77452
+ effects: {
77453
+ hover: [{
77454
+ effectId: "background-on-hover",
77455
+ options: { colorToken: "primary-100" }
77456
+ }],
77457
+ active: [{
77458
+ effectId: "scale-down",
77459
+ options: { scale: "0.98" }
77460
+ }]
77461
+ }
77462
+ },
77463
+ {
77464
+ id: "secondary",
77465
+ name: "Secondary",
77466
+ enabled: true,
77467
+ priority: 2,
77468
+ background: {
77469
+ type: "solid",
77470
+ colorToken: "secondary"
77471
+ },
77472
+ textColorToken: "primaryForeground",
77473
+ borderRadius: "rounded-md",
77474
+ border: {
77475
+ widthClass: "border",
77476
+ colorToken: "primary"
77477
+ },
77478
+ shadow: {
77479
+ elevation: "none",
77480
+ softness: null,
77481
+ position: "bottom"
77482
+ },
77483
+ effects: { hover: [{
77484
+ effectId: "background-on-hover",
77485
+ options: { colorToken: "surface" }
77486
+ }] }
77487
+ },
77488
+ {
77489
+ id: "outline",
77490
+ name: "Outline",
77491
+ enabled: true,
77492
+ priority: 3,
77493
+ background: { type: "transparent" },
77494
+ textColorToken: "primary",
77495
+ borderRadius: "rounded-md",
77496
+ border: {
77497
+ widthClass: "border",
77498
+ colorToken: "primary"
77499
+ },
77500
+ shadow: {
77501
+ elevation: "none",
77502
+ softness: null,
77503
+ position: "bottom"
77504
+ },
77505
+ effects: { hover: [{
77506
+ effectId: "background-on-hover",
77507
+ options: { colorToken: "muted" }
77210
77508
  }] }
77211
77509
  },
77212
77510
  {
@@ -77621,6 +77919,7 @@ const buttonPersonalities = [
77621
77919
  editorialLink,
77622
77920
  pebble,
77623
77921
  inkStamp,
77922
+ flatInk,
77624
77923
  brushedWash,
77625
77924
  showtimePill,
77626
77925
  joyStamp,
@@ -79216,419 +79515,6 @@ function scaleCssLengthToken(token, factor) {
79216
79515
  return `${Math.round(scaled * 100) / 100}${unit}`;
79217
79516
  }
79218
79517
  //#endregion
79219
- //#region ../blocks/src/system/inlineText.ts
79220
- const inlineTextAccentTones = [
79221
- "accent",
79222
- "brand",
79223
- "contrast"
79224
- ];
79225
- const inlineTextHighlightTones = [
79226
- "soft",
79227
- "accent",
79228
- "brand"
79229
- ];
79230
- const inlineTextMarkSchema = z$1.discriminatedUnion("kind", [
79231
- z$1.object({ kind: z$1.literal("strong") }),
79232
- z$1.object({ kind: z$1.literal("emphasis") }),
79233
- z$1.object({
79234
- kind: z$1.literal("accent"),
79235
- tone: z$1.enum(inlineTextAccentTones)
79236
- }),
79237
- z$1.object({
79238
- kind: z$1.literal("highlight"),
79239
- tone: z$1.enum(inlineTextHighlightTones)
79240
- })
79241
- ]);
79242
- const inlineTextRunSchema = z$1.object({
79243
- text: z$1.string(),
79244
- marks: z$1.array(inlineTextMarkSchema).optional()
79245
- });
79246
- z$1.array(inlineTextRunSchema);
79247
- const MARK_ORDER = {
79248
- strong: 0,
79249
- emphasis: 1,
79250
- accent: 2,
79251
- highlight: 3
79252
- };
79253
- function plainTextToInlineText(value) {
79254
- return normalizeInlineText(value.length > 0 ? [{ text: value }] : []);
79255
- }
79256
- function inlineTextToPlainText(value) {
79257
- return value.map((run) => run.text).join("");
79258
- }
79259
- function isInlineTextEmpty(value) {
79260
- return inlineTextToPlainText(value).trim().length === 0;
79261
- }
79262
- function coerceInlineTextWithFallback(value, fallbackPlainText) {
79263
- const parsed = parseInlineTextFromUnknown(value);
79264
- if (parsed.ok && !isInlineTextEmpty(parsed.value)) return parsed.value;
79265
- if (fallbackPlainText && fallbackPlainText.length > 0) return plainTextToInlineText(fallbackPlainText);
79266
- return parsed.ok ? parsed.value : [];
79267
- }
79268
- function parseInlineTextFromUnknown(value) {
79269
- if (!Array.isArray(value)) return {
79270
- ok: false,
79271
- error: { kind: "not-array" }
79272
- };
79273
- const runs = [];
79274
- for (let index = 0; index < value.length; index += 1) {
79275
- const parsed = inlineTextRunSchema.safeParse(value[index]);
79276
- if (!parsed.success) return {
79277
- ok: false,
79278
- error: {
79279
- kind: "invalid-run",
79280
- index
79281
- }
79282
- };
79283
- runs.push(parsed.data);
79284
- }
79285
- return {
79286
- ok: true,
79287
- value: normalizeInlineText(runs)
79288
- };
79289
- }
79290
- function normalizeInlineText(value) {
79291
- const normalized = [];
79292
- for (const run of value) {
79293
- if (run.text.length === 0) continue;
79294
- const marks = normalizeInlineTextMarks(run.marks ?? []);
79295
- const nextRun = marks.length > 0 ? {
79296
- text: run.text,
79297
- marks
79298
- } : { text: run.text };
79299
- const previous = normalized[normalized.length - 1];
79300
- if (previous && inlineTextMarksEqual(previous.marks ?? [], nextRun.marks ?? [])) {
79301
- normalized[normalized.length - 1] = previous.marks && previous.marks.length > 0 ? {
79302
- text: previous.text + nextRun.text,
79303
- marks: previous.marks
79304
- } : { text: previous.text + nextRun.text };
79305
- continue;
79306
- }
79307
- normalized.push(nextRun);
79308
- }
79309
- return normalized;
79310
- }
79311
- function normalizeInlineTextMarks(marks) {
79312
- let strong = null;
79313
- let emphasis = null;
79314
- let accent = null;
79315
- let highlight = null;
79316
- for (const mark of marks) switch (mark.kind) {
79317
- case "strong":
79318
- strong = { kind: "strong" };
79319
- break;
79320
- case "emphasis":
79321
- emphasis = { kind: "emphasis" };
79322
- break;
79323
- case "accent":
79324
- accent = {
79325
- kind: "accent",
79326
- tone: mark.tone
79327
- };
79328
- break;
79329
- case "highlight":
79330
- highlight = {
79331
- kind: "highlight",
79332
- tone: mark.tone
79333
- };
79334
- break;
79335
- }
79336
- return [
79337
- strong,
79338
- emphasis,
79339
- accent,
79340
- highlight
79341
- ].filter((mark) => mark !== null).sort((left, right) => MARK_ORDER[left.kind] - MARK_ORDER[right.kind]);
79342
- }
79343
- function inlineTextMarksEqual(left, right) {
79344
- const normalizedLeft = normalizeInlineTextMarks(left);
79345
- const normalizedRight = normalizeInlineTextMarks(right);
79346
- if (normalizedLeft.length !== normalizedRight.length) return false;
79347
- return normalizedLeft.every((mark, index) => inlineTextMarkEqual(mark, normalizedRight[index]));
79348
- }
79349
- function inlineTextEqual(left, right) {
79350
- const normalizedLeft = normalizeInlineText(left);
79351
- const normalizedRight = normalizeInlineText(right);
79352
- if (normalizedLeft.length !== normalizedRight.length) return false;
79353
- return normalizedLeft.every((leftRun, index) => {
79354
- const rightRun = normalizedRight[index];
79355
- return rightRun !== void 0 && leftRun.text === rightRun.text && inlineTextMarksEqual(leftRun.marks ?? [], rightRun.marks ?? []);
79356
- });
79357
- }
79358
- function inlineTextMarkEqual(left, right) {
79359
- if (!right || left.kind !== right.kind) return false;
79360
- switch (left.kind) {
79361
- case "strong":
79362
- case "emphasis": return true;
79363
- case "accent": return right.kind === "accent" && left.tone === right.tone;
79364
- case "highlight": return right.kind === "highlight" && left.tone === right.tone;
79365
- }
79366
- }
79367
- function applyInlineTextMarkToRange(value, range, mark) {
79368
- return mapInlineTextRange(value, range, (marks) => normalizeInlineTextMarks([...marks, mark]));
79369
- }
79370
- function removeInlineTextMarkFromRange(value, range, kind) {
79371
- return mapInlineTextRange(value, range, (marks) => marks.filter((mark) => mark.kind !== kind));
79372
- }
79373
- function replaceInlineTextRange(value, range, replacement) {
79374
- const textLength = inlineTextToPlainText(value).length;
79375
- const start = Math.max(0, Math.min(range.start, range.end, textLength));
79376
- const end = Math.max(0, Math.min(Math.max(range.start, range.end), textLength));
79377
- return normalizeInlineText([
79378
- ...sliceInlineText(value, 0, start),
79379
- ...normalizeInlineText(replacement),
79380
- ...sliceInlineText(value, end, textLength)
79381
- ]);
79382
- }
79383
- function truncateInlineText(value, maxLength) {
79384
- if (typeof maxLength !== "number" || !Number.isFinite(maxLength) || maxLength < 0) return normalizeInlineText(value);
79385
- const next = [];
79386
- let remaining = maxLength;
79387
- for (const run of normalizeInlineText(value)) {
79388
- if (remaining <= 0) break;
79389
- const text = run.text.slice(0, remaining);
79390
- next.push(withMarks(text, run.marks ?? []));
79391
- remaining -= text.length;
79392
- }
79393
- return normalizeInlineText(next);
79394
- }
79395
- function sliceInlineText(value, start, end) {
79396
- if (start >= end) return [];
79397
- const next = [];
79398
- let offset = 0;
79399
- for (const run of normalizeInlineText(value)) {
79400
- const runStart = offset;
79401
- const runEnd = offset + run.text.length;
79402
- offset = runEnd;
79403
- if (runEnd <= start || runStart >= end) continue;
79404
- const localStart = Math.max(0, start - runStart);
79405
- const localEnd = Math.min(run.text.length, end - runStart);
79406
- next.push(withMarks(run.text.slice(localStart, localEnd), run.marks ?? []));
79407
- }
79408
- return normalizeInlineText(next);
79409
- }
79410
- function mapInlineTextRange(value, range, mapMarks) {
79411
- const start = Math.max(0, Math.min(range.start, range.end));
79412
- const end = Math.max(0, Math.max(range.start, range.end));
79413
- if (start === end) return normalizeInlineText(value);
79414
- const next = [];
79415
- let offset = 0;
79416
- for (const run of normalizeInlineText(value)) {
79417
- const runStart = offset;
79418
- const runEnd = offset + run.text.length;
79419
- offset = runEnd;
79420
- if (runEnd <= start || runStart >= end) {
79421
- next.push(run);
79422
- continue;
79423
- }
79424
- const localStart = Math.max(0, start - runStart);
79425
- const localEnd = Math.min(run.text.length, end - runStart);
79426
- const marks = run.marks ?? [];
79427
- if (localStart > 0) next.push(withMarks(run.text.slice(0, localStart), marks));
79428
- next.push(withMarks(run.text.slice(localStart, localEnd), mapMarks(marks)));
79429
- if (localEnd < run.text.length) next.push(withMarks(run.text.slice(localEnd), marks));
79430
- }
79431
- return normalizeInlineText(next);
79432
- }
79433
- function withMarks(text, marks) {
79434
- const normalized = normalizeInlineTextMarks(marks);
79435
- return normalized.length > 0 ? {
79436
- text,
79437
- marks: normalized
79438
- } : { text };
79439
- }
79440
- //#endregion
79441
- //#region ../blocks/src/lib/typeGuards.ts
79442
- /**
79443
- * Strict record guard: excludes null, primitives, and arrays.
79444
- */
79445
- function isRecord$11(value) {
79446
- return typeof value === "object" && value !== null && !Array.isArray(value);
79447
- }
79448
- /**
79449
- * Non-null object guard: includes arrays for behavior parity with legacy helpers.
79450
- *
79451
- * NOTE: This intentionally narrows to UnknownRecord for compatibility with existing
79452
- * callsites even though arrays pass at runtime. Follow-up cleanup should replace
79453
- * this API with a more precise predicate type and migrate consumers.
79454
- */
79455
- function isObjectRecord$1(value) {
79456
- return typeof value === "object" && value !== null;
79457
- }
79458
- //#endregion
79459
- //#region ../blocks/src/system/manifest/richTextSchema.ts
79460
- /**
79461
- * Shared Rich Text Schema
79462
- *
79463
- * This module provides a single source of truth for TipTap rich text validation
79464
- * across both the block-form editor and the block rendering system.
79465
- *
79466
- * Format compatibility:
79467
- * - Unwrapped format (new): { type: 'doc', content: [...] }
79468
- * - Wrapped format (legacy): { doc: { type: 'doc', content: [...] } }
79469
- *
79470
- * Both formats are supported for backward compatibility during migration.
79471
- */
79472
- /**
79473
- * TipTap document node schema (recursive structure)
79474
- *
79475
- * Supports the full TipTap document structure including:
79476
- * - type: Node type (e.g., 'doc', 'paragraph', 'text')
79477
- * - content: Nested array of child nodes
79478
- * - text: Text content for text nodes
79479
- * - attrs: Node attributes (e.g., alignment, color)
79480
- * - marks: Text formatting marks (e.g., bold, italic)
79481
- */
79482
- const TipTapMarkSchema = z$1.object({
79483
- type: z$1.string(),
79484
- attrs: z$1.record(z$1.string(), z$1.unknown()).optional()
79485
- });
79486
- const TipTapNodeSchema = z$1.lazy(() => z$1.object({
79487
- type: z$1.string(),
79488
- content: z$1.array(TipTapNodeSchema).optional(),
79489
- text: z$1.string().optional(),
79490
- attrs: z$1.record(z$1.string(), z$1.unknown()).optional(),
79491
- marks: z$1.array(TipTapMarkSchema).optional()
79492
- }));
79493
- /**
79494
- * Rich text value schema
79495
- *
79496
- * Producers MUST emit the canonical unwrapped form `{ type: 'doc', content: [...] }`.
79497
- * The wrapped form `{ doc: {...} }` is accepted only as a reading tolerance for data
79498
- * that pre-dates the unwrap migration (Supabase migrations `20251029173500_unwrap_richtext_format`
79499
- * and `20251029174000_update_template_bindings_unwrapped`). Do not introduce new
79500
- * producers of the wrapped shape.
79501
- */
79502
- const RichTextValueSchema = z$1.union([TipTapNodeSchema, z$1.object({ doc: TipTapNodeSchema })]);
79503
- /**
79504
- * Canonical schema for a TipTap rich-text document root.
79505
- *
79506
- * Stricter than {@link TipTapNodeSchema}: `type` is literally `'doc'` and
79507
- * `content` is required (possibly empty). This is the shape every producer
79508
- * (dummy content, editor output, migrations) must emit, and the shape every
79509
- * non-legacy consumer can rely on.
79510
- *
79511
- * Legacy envelopes are read-tolerated by {@link RichTextValueSchema} but
79512
- * normalised before reaching anywhere typed as `RichTextDoc`.
79513
- */
79514
- const RichTextDocSchema = z$1.object({
79515
- type: z$1.literal("doc"),
79516
- content: z$1.array(TipTapNodeSchema)
79517
- });
79518
- /**
79519
- * Permissive unwrap for a value known to be the root of a rich-text field.
79520
- *
79521
- * Producers should emit the canonical unwrapped form `{ type: 'doc', content: [...] }`,
79522
- * but two legacy shapes still appear in older data and pre-Phase-1 fixtures:
79523
- *
79524
- * - `{ doc: <typed-doc> }` — pre-migration DB storage.
79525
- * - `{ doc: <typed-doc>, html, plain }` — pre-Phase-1 dummy-content output.
79526
- *
79527
- * This helper is the single right place to tolerate either shape at a known
79528
- * rich-text root (transforms, coercion, validators that operate on rich text).
79529
- * The strictness sits on the inner node's `type === 'doc'`, which prevents
79530
- * misidentifying random objects that happen to carry a field named `doc`.
79531
- *
79532
- * Returns the inner doc node when the input matches a legacy shape, otherwise
79533
- * returns the input unchanged.
79534
- *
79535
- * For deep structural traversal where any nested key might be named `doc`
79536
- * (and unwrapping would be incorrect), use the strict `isDocWrapper` private
79537
- * helper inside `@riverbankcms/blocks/bindings`.
79538
- */
79539
- function unwrapRichTextRoot(value) {
79540
- if (!isRecord$11(value)) return value;
79541
- if (!("doc" in value)) return value;
79542
- const inner = value.doc;
79543
- if (isRecord$11(inner) && inner.type === "doc") return inner;
79544
- return value;
79545
- }
79546
- function createHardBreakNode() {
79547
- return { type: "hardBreak" };
79548
- }
79549
- /**
79550
- * Parse a small markdown subset into TipTap inline nodes.
79551
- *
79552
- * This intentionally supports only bold (`**text**`) because the SDK/content
79553
- * import paths use it for lightweight default content, not full markdown.
79554
- */
79555
- function parseRichTextInlineMarkdown(text) {
79556
- const out = [];
79557
- const pushText = (value, marks) => {
79558
- if (!value) return;
79559
- out.push(marks && marks.length > 0 ? {
79560
- type: "text",
79561
- text: value,
79562
- marks
79563
- } : {
79564
- type: "text",
79565
- text: value
79566
- });
79567
- };
79568
- let rest = text;
79569
- while (rest.length > 0) {
79570
- const start = rest.indexOf("**");
79571
- if (start === -1) {
79572
- pushText(rest);
79573
- break;
79574
- }
79575
- const end = rest.indexOf("**", start + 2);
79576
- if (end === -1) {
79577
- pushText(rest);
79578
- break;
79579
- }
79580
- pushText(rest.slice(0, start));
79581
- pushText(rest.slice(start + 2, end), [{ type: "bold" }]);
79582
- rest = rest.slice(end + 2);
79583
- }
79584
- return out;
79585
- }
79586
- function parseRichTextParagraphInlineMarkdown(text) {
79587
- return text.split("\n").flatMap((line, index) => {
79588
- const lineNodes = parseRichTextInlineMarkdown(line.trim());
79589
- return index === 0 ? lineNodes : [createHardBreakNode(), ...lineNodes];
79590
- });
79591
- }
79592
- /**
79593
- * Convert a plain string with a tiny markdown subset to canonical TipTap JSON.
79594
- *
79595
- * Double newlines create semantic paragraphs. Single newlines remain inside the
79596
- * current paragraph as TipTap `hardBreak` nodes for line-oriented content such
79597
- * as addresses, opening hours, and contact details.
79598
- */
79599
- function createRichTextDocFromMarkdown(markdown) {
79600
- const normalized = markdown.replace(/\r\n/g, "\n").trim();
79601
- if (!normalized) return {
79602
- type: "doc",
79603
- content: []
79604
- };
79605
- return {
79606
- type: "doc",
79607
- content: normalized.split(/\n{2,}/).map((paragraph) => paragraph.trim()).filter(Boolean).map((paragraph) => {
79608
- const inline = parseRichTextParagraphInlineMarkdown(paragraph);
79609
- return inline.length > 0 ? {
79610
- type: "paragraph",
79611
- content: inline
79612
- } : { type: "paragraph" };
79613
- })
79614
- };
79615
- }
79616
- function buildRichTextSchema(options) {
79617
- let schema = RichTextValueSchema;
79618
- if (options?.required) {
79619
- const label = options.label ?? "This field";
79620
- schema = schema.refine((val) => {
79621
- const doc = isRecord$11(val) && "doc" in val ? val.doc : val;
79622
- const content = isRecord$11(doc) ? doc.content : void 0;
79623
- if (!Array.isArray(content) || content.length === 0) return false;
79624
- const first = content[0];
79625
- if (content.length === 1 && isRecord$11(first) && first.type === "paragraph" && (!("content" in first) || first.content == null)) return false;
79626
- return true;
79627
- }, { message: `${label} is required` });
79628
- }
79629
- return schema;
79630
- }
79631
- //#endregion
79632
79518
  //#region ../blocks/src/system/icons/svg.tsx
79633
79519
  function createIcon(displayName, children) {
79634
79520
  const Icon = ({ size = "1em", strokeWidth = 2, title, className, focusable = false, role, ...props }) => /* @__PURE__ */ jsxs("svg", {
@@ -80592,6 +80478,419 @@ function resolveIconPickerPreset(value) {
80592
80478
  return isIconPickerPreset(value) ? value : "cta";
80593
80479
  }
80594
80480
  //#endregion
80481
+ //#region ../blocks/src/system/inlineText.ts
80482
+ const inlineTextAccentTones = [
80483
+ "accent",
80484
+ "brand",
80485
+ "contrast"
80486
+ ];
80487
+ const inlineTextHighlightTones = [
80488
+ "soft",
80489
+ "accent",
80490
+ "brand"
80491
+ ];
80492
+ const inlineTextMarkSchema = z$1.discriminatedUnion("kind", [
80493
+ z$1.object({ kind: z$1.literal("strong") }),
80494
+ z$1.object({ kind: z$1.literal("emphasis") }),
80495
+ z$1.object({
80496
+ kind: z$1.literal("accent"),
80497
+ tone: z$1.enum(inlineTextAccentTones)
80498
+ }),
80499
+ z$1.object({
80500
+ kind: z$1.literal("highlight"),
80501
+ tone: z$1.enum(inlineTextHighlightTones)
80502
+ })
80503
+ ]);
80504
+ const inlineTextRunSchema = z$1.object({
80505
+ text: z$1.string(),
80506
+ marks: z$1.array(inlineTextMarkSchema).optional()
80507
+ });
80508
+ z$1.array(inlineTextRunSchema);
80509
+ const MARK_ORDER = {
80510
+ strong: 0,
80511
+ emphasis: 1,
80512
+ accent: 2,
80513
+ highlight: 3
80514
+ };
80515
+ function plainTextToInlineText(value) {
80516
+ return normalizeInlineText(value.length > 0 ? [{ text: value }] : []);
80517
+ }
80518
+ function inlineTextToPlainText(value) {
80519
+ return value.map((run) => run.text).join("");
80520
+ }
80521
+ function isInlineTextEmpty(value) {
80522
+ return inlineTextToPlainText(value).trim().length === 0;
80523
+ }
80524
+ function coerceInlineTextWithFallback(value, fallbackPlainText) {
80525
+ const parsed = parseInlineTextFromUnknown(value);
80526
+ if (parsed.ok && !isInlineTextEmpty(parsed.value)) return parsed.value;
80527
+ if (fallbackPlainText && fallbackPlainText.length > 0) return plainTextToInlineText(fallbackPlainText);
80528
+ return parsed.ok ? parsed.value : [];
80529
+ }
80530
+ function parseInlineTextFromUnknown(value) {
80531
+ if (!Array.isArray(value)) return {
80532
+ ok: false,
80533
+ error: { kind: "not-array" }
80534
+ };
80535
+ const runs = [];
80536
+ for (let index = 0; index < value.length; index += 1) {
80537
+ const parsed = inlineTextRunSchema.safeParse(value[index]);
80538
+ if (!parsed.success) return {
80539
+ ok: false,
80540
+ error: {
80541
+ kind: "invalid-run",
80542
+ index
80543
+ }
80544
+ };
80545
+ runs.push(parsed.data);
80546
+ }
80547
+ return {
80548
+ ok: true,
80549
+ value: normalizeInlineText(runs)
80550
+ };
80551
+ }
80552
+ function normalizeInlineText(value) {
80553
+ const normalized = [];
80554
+ for (const run of value) {
80555
+ if (run.text.length === 0) continue;
80556
+ const marks = normalizeInlineTextMarks(run.marks ?? []);
80557
+ const nextRun = marks.length > 0 ? {
80558
+ text: run.text,
80559
+ marks
80560
+ } : { text: run.text };
80561
+ const previous = normalized[normalized.length - 1];
80562
+ if (previous && inlineTextMarksEqual(previous.marks ?? [], nextRun.marks ?? [])) {
80563
+ normalized[normalized.length - 1] = previous.marks && previous.marks.length > 0 ? {
80564
+ text: previous.text + nextRun.text,
80565
+ marks: previous.marks
80566
+ } : { text: previous.text + nextRun.text };
80567
+ continue;
80568
+ }
80569
+ normalized.push(nextRun);
80570
+ }
80571
+ return normalized;
80572
+ }
80573
+ function normalizeInlineTextMarks(marks) {
80574
+ let strong = null;
80575
+ let emphasis = null;
80576
+ let accent = null;
80577
+ let highlight = null;
80578
+ for (const mark of marks) switch (mark.kind) {
80579
+ case "strong":
80580
+ strong = { kind: "strong" };
80581
+ break;
80582
+ case "emphasis":
80583
+ emphasis = { kind: "emphasis" };
80584
+ break;
80585
+ case "accent":
80586
+ accent = {
80587
+ kind: "accent",
80588
+ tone: mark.tone
80589
+ };
80590
+ break;
80591
+ case "highlight":
80592
+ highlight = {
80593
+ kind: "highlight",
80594
+ tone: mark.tone
80595
+ };
80596
+ break;
80597
+ }
80598
+ return [
80599
+ strong,
80600
+ emphasis,
80601
+ accent,
80602
+ highlight
80603
+ ].filter((mark) => mark !== null).sort((left, right) => MARK_ORDER[left.kind] - MARK_ORDER[right.kind]);
80604
+ }
80605
+ function inlineTextMarksEqual(left, right) {
80606
+ const normalizedLeft = normalizeInlineTextMarks(left);
80607
+ const normalizedRight = normalizeInlineTextMarks(right);
80608
+ if (normalizedLeft.length !== normalizedRight.length) return false;
80609
+ return normalizedLeft.every((mark, index) => inlineTextMarkEqual(mark, normalizedRight[index]));
80610
+ }
80611
+ function inlineTextEqual(left, right) {
80612
+ const normalizedLeft = normalizeInlineText(left);
80613
+ const normalizedRight = normalizeInlineText(right);
80614
+ if (normalizedLeft.length !== normalizedRight.length) return false;
80615
+ return normalizedLeft.every((leftRun, index) => {
80616
+ const rightRun = normalizedRight[index];
80617
+ return rightRun !== void 0 && leftRun.text === rightRun.text && inlineTextMarksEqual(leftRun.marks ?? [], rightRun.marks ?? []);
80618
+ });
80619
+ }
80620
+ function inlineTextMarkEqual(left, right) {
80621
+ if (!right || left.kind !== right.kind) return false;
80622
+ switch (left.kind) {
80623
+ case "strong":
80624
+ case "emphasis": return true;
80625
+ case "accent": return right.kind === "accent" && left.tone === right.tone;
80626
+ case "highlight": return right.kind === "highlight" && left.tone === right.tone;
80627
+ }
80628
+ }
80629
+ function applyInlineTextMarkToRange(value, range, mark) {
80630
+ return mapInlineTextRange(value, range, (marks) => normalizeInlineTextMarks([...marks, mark]));
80631
+ }
80632
+ function removeInlineTextMarkFromRange(value, range, kind) {
80633
+ return mapInlineTextRange(value, range, (marks) => marks.filter((mark) => mark.kind !== kind));
80634
+ }
80635
+ function replaceInlineTextRange(value, range, replacement) {
80636
+ const textLength = inlineTextToPlainText(value).length;
80637
+ const start = Math.max(0, Math.min(range.start, range.end, textLength));
80638
+ const end = Math.max(0, Math.min(Math.max(range.start, range.end), textLength));
80639
+ return normalizeInlineText([
80640
+ ...sliceInlineText(value, 0, start),
80641
+ ...normalizeInlineText(replacement),
80642
+ ...sliceInlineText(value, end, textLength)
80643
+ ]);
80644
+ }
80645
+ function truncateInlineText(value, maxLength) {
80646
+ if (typeof maxLength !== "number" || !Number.isFinite(maxLength) || maxLength < 0) return normalizeInlineText(value);
80647
+ const next = [];
80648
+ let remaining = maxLength;
80649
+ for (const run of normalizeInlineText(value)) {
80650
+ if (remaining <= 0) break;
80651
+ const text = run.text.slice(0, remaining);
80652
+ next.push(withMarks(text, run.marks ?? []));
80653
+ remaining -= text.length;
80654
+ }
80655
+ return normalizeInlineText(next);
80656
+ }
80657
+ function sliceInlineText(value, start, end) {
80658
+ if (start >= end) return [];
80659
+ const next = [];
80660
+ let offset = 0;
80661
+ for (const run of normalizeInlineText(value)) {
80662
+ const runStart = offset;
80663
+ const runEnd = offset + run.text.length;
80664
+ offset = runEnd;
80665
+ if (runEnd <= start || runStart >= end) continue;
80666
+ const localStart = Math.max(0, start - runStart);
80667
+ const localEnd = Math.min(run.text.length, end - runStart);
80668
+ next.push(withMarks(run.text.slice(localStart, localEnd), run.marks ?? []));
80669
+ }
80670
+ return normalizeInlineText(next);
80671
+ }
80672
+ function mapInlineTextRange(value, range, mapMarks) {
80673
+ const start = Math.max(0, Math.min(range.start, range.end));
80674
+ const end = Math.max(0, Math.max(range.start, range.end));
80675
+ if (start === end) return normalizeInlineText(value);
80676
+ const next = [];
80677
+ let offset = 0;
80678
+ for (const run of normalizeInlineText(value)) {
80679
+ const runStart = offset;
80680
+ const runEnd = offset + run.text.length;
80681
+ offset = runEnd;
80682
+ if (runEnd <= start || runStart >= end) {
80683
+ next.push(run);
80684
+ continue;
80685
+ }
80686
+ const localStart = Math.max(0, start - runStart);
80687
+ const localEnd = Math.min(run.text.length, end - runStart);
80688
+ const marks = run.marks ?? [];
80689
+ if (localStart > 0) next.push(withMarks(run.text.slice(0, localStart), marks));
80690
+ next.push(withMarks(run.text.slice(localStart, localEnd), mapMarks(marks)));
80691
+ if (localEnd < run.text.length) next.push(withMarks(run.text.slice(localEnd), marks));
80692
+ }
80693
+ return normalizeInlineText(next);
80694
+ }
80695
+ function withMarks(text, marks) {
80696
+ const normalized = normalizeInlineTextMarks(marks);
80697
+ return normalized.length > 0 ? {
80698
+ text,
80699
+ marks: normalized
80700
+ } : { text };
80701
+ }
80702
+ //#endregion
80703
+ //#region ../blocks/src/lib/typeGuards.ts
80704
+ /**
80705
+ * Strict record guard: excludes null, primitives, and arrays.
80706
+ */
80707
+ function isRecord$11(value) {
80708
+ return typeof value === "object" && value !== null && !Array.isArray(value);
80709
+ }
80710
+ /**
80711
+ * Non-null object guard: includes arrays for behavior parity with legacy helpers.
80712
+ *
80713
+ * NOTE: This intentionally narrows to UnknownRecord for compatibility with existing
80714
+ * callsites even though arrays pass at runtime. Follow-up cleanup should replace
80715
+ * this API with a more precise predicate type and migrate consumers.
80716
+ */
80717
+ function isObjectRecord$1(value) {
80718
+ return typeof value === "object" && value !== null;
80719
+ }
80720
+ //#endregion
80721
+ //#region ../blocks/src/system/manifest/richTextSchema.ts
80722
+ /**
80723
+ * Shared Rich Text Schema
80724
+ *
80725
+ * This module provides a single source of truth for TipTap rich text validation
80726
+ * across both the block-form editor and the block rendering system.
80727
+ *
80728
+ * Format compatibility:
80729
+ * - Unwrapped format (new): { type: 'doc', content: [...] }
80730
+ * - Wrapped format (legacy): { doc: { type: 'doc', content: [...] } }
80731
+ *
80732
+ * Both formats are supported for backward compatibility during migration.
80733
+ */
80734
+ /**
80735
+ * TipTap document node schema (recursive structure)
80736
+ *
80737
+ * Supports the full TipTap document structure including:
80738
+ * - type: Node type (e.g., 'doc', 'paragraph', 'text')
80739
+ * - content: Nested array of child nodes
80740
+ * - text: Text content for text nodes
80741
+ * - attrs: Node attributes (e.g., alignment, color)
80742
+ * - marks: Text formatting marks (e.g., bold, italic)
80743
+ */
80744
+ const TipTapMarkSchema = z$1.object({
80745
+ type: z$1.string(),
80746
+ attrs: z$1.record(z$1.string(), z$1.unknown()).optional()
80747
+ });
80748
+ const TipTapNodeSchema = z$1.lazy(() => z$1.object({
80749
+ type: z$1.string(),
80750
+ content: z$1.array(TipTapNodeSchema).optional(),
80751
+ text: z$1.string().optional(),
80752
+ attrs: z$1.record(z$1.string(), z$1.unknown()).optional(),
80753
+ marks: z$1.array(TipTapMarkSchema).optional()
80754
+ }));
80755
+ /**
80756
+ * Rich text value schema
80757
+ *
80758
+ * Producers MUST emit the canonical unwrapped form `{ type: 'doc', content: [...] }`.
80759
+ * The wrapped form `{ doc: {...} }` is accepted only as a reading tolerance for data
80760
+ * that pre-dates the unwrap migration (Supabase migrations `20251029173500_unwrap_richtext_format`
80761
+ * and `20251029174000_update_template_bindings_unwrapped`). Do not introduce new
80762
+ * producers of the wrapped shape.
80763
+ */
80764
+ const RichTextValueSchema = z$1.union([TipTapNodeSchema, z$1.object({ doc: TipTapNodeSchema })]);
80765
+ /**
80766
+ * Canonical schema for a TipTap rich-text document root.
80767
+ *
80768
+ * Stricter than {@link TipTapNodeSchema}: `type` is literally `'doc'` and
80769
+ * `content` is required (possibly empty). This is the shape every producer
80770
+ * (dummy content, editor output, migrations) must emit, and the shape every
80771
+ * non-legacy consumer can rely on.
80772
+ *
80773
+ * Legacy envelopes are read-tolerated by {@link RichTextValueSchema} but
80774
+ * normalised before reaching anywhere typed as `RichTextDoc`.
80775
+ */
80776
+ const RichTextDocSchema = z$1.object({
80777
+ type: z$1.literal("doc"),
80778
+ content: z$1.array(TipTapNodeSchema)
80779
+ });
80780
+ /**
80781
+ * Permissive unwrap for a value known to be the root of a rich-text field.
80782
+ *
80783
+ * Producers should emit the canonical unwrapped form `{ type: 'doc', content: [...] }`,
80784
+ * but two legacy shapes still appear in older data and pre-Phase-1 fixtures:
80785
+ *
80786
+ * - `{ doc: <typed-doc> }` — pre-migration DB storage.
80787
+ * - `{ doc: <typed-doc>, html, plain }` — pre-Phase-1 dummy-content output.
80788
+ *
80789
+ * This helper is the single right place to tolerate either shape at a known
80790
+ * rich-text root (transforms, coercion, validators that operate on rich text).
80791
+ * The strictness sits on the inner node's `type === 'doc'`, which prevents
80792
+ * misidentifying random objects that happen to carry a field named `doc`.
80793
+ *
80794
+ * Returns the inner doc node when the input matches a legacy shape, otherwise
80795
+ * returns the input unchanged.
80796
+ *
80797
+ * For deep structural traversal where any nested key might be named `doc`
80798
+ * (and unwrapping would be incorrect), use the strict `isDocWrapper` private
80799
+ * helper inside `@riverbankcms/blocks/bindings`.
80800
+ */
80801
+ function unwrapRichTextRoot(value) {
80802
+ if (!isRecord$11(value)) return value;
80803
+ if (!("doc" in value)) return value;
80804
+ const inner = value.doc;
80805
+ if (isRecord$11(inner) && inner.type === "doc") return inner;
80806
+ return value;
80807
+ }
80808
+ function createHardBreakNode() {
80809
+ return { type: "hardBreak" };
80810
+ }
80811
+ /**
80812
+ * Parse a small markdown subset into TipTap inline nodes.
80813
+ *
80814
+ * This intentionally supports only bold (`**text**`) because the SDK/content
80815
+ * import paths use it for lightweight default content, not full markdown.
80816
+ */
80817
+ function parseRichTextInlineMarkdown(text) {
80818
+ const out = [];
80819
+ const pushText = (value, marks) => {
80820
+ if (!value) return;
80821
+ out.push(marks && marks.length > 0 ? {
80822
+ type: "text",
80823
+ text: value,
80824
+ marks
80825
+ } : {
80826
+ type: "text",
80827
+ text: value
80828
+ });
80829
+ };
80830
+ let rest = text;
80831
+ while (rest.length > 0) {
80832
+ const start = rest.indexOf("**");
80833
+ if (start === -1) {
80834
+ pushText(rest);
80835
+ break;
80836
+ }
80837
+ const end = rest.indexOf("**", start + 2);
80838
+ if (end === -1) {
80839
+ pushText(rest);
80840
+ break;
80841
+ }
80842
+ pushText(rest.slice(0, start));
80843
+ pushText(rest.slice(start + 2, end), [{ type: "bold" }]);
80844
+ rest = rest.slice(end + 2);
80845
+ }
80846
+ return out;
80847
+ }
80848
+ function parseRichTextParagraphInlineMarkdown(text) {
80849
+ return text.split("\n").flatMap((line, index) => {
80850
+ const lineNodes = parseRichTextInlineMarkdown(line.trim());
80851
+ return index === 0 ? lineNodes : [createHardBreakNode(), ...lineNodes];
80852
+ });
80853
+ }
80854
+ /**
80855
+ * Convert a plain string with a tiny markdown subset to canonical TipTap JSON.
80856
+ *
80857
+ * Double newlines create semantic paragraphs. Single newlines remain inside the
80858
+ * current paragraph as TipTap `hardBreak` nodes for line-oriented content such
80859
+ * as addresses, opening hours, and contact details.
80860
+ */
80861
+ function createRichTextDocFromMarkdown(markdown) {
80862
+ const normalized = markdown.replace(/\r\n/g, "\n").trim();
80863
+ if (!normalized) return {
80864
+ type: "doc",
80865
+ content: []
80866
+ };
80867
+ return {
80868
+ type: "doc",
80869
+ content: normalized.split(/\n{2,}/).map((paragraph) => paragraph.trim()).filter(Boolean).map((paragraph) => {
80870
+ const inline = parseRichTextParagraphInlineMarkdown(paragraph);
80871
+ return inline.length > 0 ? {
80872
+ type: "paragraph",
80873
+ content: inline
80874
+ } : { type: "paragraph" };
80875
+ })
80876
+ };
80877
+ }
80878
+ function buildRichTextSchema(options) {
80879
+ let schema = RichTextValueSchema;
80880
+ if (options?.required) {
80881
+ const label = options.label ?? "This field";
80882
+ schema = schema.refine((val) => {
80883
+ const doc = isRecord$11(val) && "doc" in val ? val.doc : val;
80884
+ const content = isRecord$11(doc) ? doc.content : void 0;
80885
+ if (!Array.isArray(content) || content.length === 0) return false;
80886
+ const first = content[0];
80887
+ if (content.length === 1 && isRecord$11(first) && first.type === "paragraph" && (!("content" in first) || first.content == null)) return false;
80888
+ return true;
80889
+ }, { message: `${label} is required` });
80890
+ }
80891
+ return schema;
80892
+ }
80893
+ //#endregion
80595
80894
  //#region ../blocks/src/system/icons/ids.ts
80596
80895
  const GENERATED_ICON_SET_ID_PATTERN = /^generated-icon-set:[a-z0-9][a-z0-9:_-]{0,107}$/u;
80597
80896
  const GENERATED_ICON_ASSET_ID_PATTERN = /^generated-icon-asset:[a-z0-9][a-z0-9:_-]{0,105}$/u;
@@ -81996,6 +82295,40 @@ function getEventAvailability(event) {
81996
82295
  isFull: false
81997
82296
  };
81998
82297
  }
82298
+ /**
82299
+ * Derive the three-state availability status (available / filling / waitlist)
82300
+ * plus a short pill label. Builds on {@link getEventAvailability} so the
82301
+ * capacity math (availableSpots with a `capacity - registeredCount` fallback)
82302
+ * stays consistent with the binary helper used elsewhere.
82303
+ */
82304
+ function getEventAvailabilityStatus(event, options) {
82305
+ const threshold = options?.fillingThreshold ?? 2;
82306
+ const { available, isFull } = getEventAvailability(event);
82307
+ if (available == null) return {
82308
+ status: "available",
82309
+ available: null,
82310
+ isFull: false,
82311
+ label: null
82312
+ };
82313
+ if (isFull) return {
82314
+ status: "waitlist",
82315
+ available: 0,
82316
+ isFull: true,
82317
+ label: event.waitlistEnabled ? "Waitlist" : "Full"
82318
+ };
82319
+ if (available <= threshold) return {
82320
+ status: "filling",
82321
+ available,
82322
+ isFull: false,
82323
+ label: `${available} left`
82324
+ };
82325
+ return {
82326
+ status: "available",
82327
+ available,
82328
+ isFull: false,
82329
+ label: `${available} places`
82330
+ };
82331
+ }
81999
82332
  //#endregion
82000
82333
  //#region ../blocks/src/system/runtime/nodes/events/shared/utils.ts
82001
82334
  /**
@@ -82864,20 +83197,6 @@ function generateDefaultCardSystem(theme) {
82864
83197
  return { variants: [defaultVariant, alternativeVariant] };
82865
83198
  }
82866
83199
  //#endregion
82867
- //#region ../theme-core/src/status/contextualColors.ts
82868
- const STATUS_MUTED_COLOR_VAR = "--rb-status-muted-color";
82869
- const DEFAULT_STATUS_MUTED_COLOR = "rgb(var(--tb-mutedText))";
82870
- const SURFACE_MUTED_STATUS_COLOR = "color-mix(in oklab, currentColor, transparent 18%)";
82871
- function statusMutedColorValue() {
82872
- return `var(${STATUS_MUTED_COLOR_VAR}, ${DEFAULT_STATUS_MUTED_COLOR})`;
82873
- }
82874
- function statusMutedColorDeclaration() {
82875
- return `color: ${statusMutedColorValue()};`;
82876
- }
82877
- function contextualMutedStatusColorDeclaration(value) {
82878
- return `${STATUS_MUTED_COLOR_VAR}: ${value}`;
82879
- }
82880
- //#endregion
82881
83200
  //#region ../theme-core/src/cards/generateCardCss.ts
82882
83201
  const PER_CORNER_RADIUS_MAP = {
82883
83202
  square: "0",
@@ -82962,8 +83281,10 @@ function generateVariantCSS(variant, themeId, tokens, theme) {
82962
83281
  const direction = GRADIENT_DIRECTION_MAP[variant.background.direction] || "to right";
82963
83282
  rules.push(`background: linear-gradient(${direction}, ${fromColor}, ${toColor})`);
82964
83283
  } else rules.push(`background: transparent`);
82965
- if (variant.foregroundToken) rules.push(`color: ${tokens.getColor(variant.foregroundToken)}`);
82966
- rules.push(contextualMutedStatusColorDeclaration(SURFACE_MUTED_STATUS_COLOR));
83284
+ if (variant.background.type !== "transparent") {
83285
+ const foreground = tokens.getColor(variant.foregroundToken ?? "text");
83286
+ rules.push(...surfaceForegroundDeclarations({ text: foreground }));
83287
+ }
82967
83288
  if (variant.accentEdge) {
82968
83289
  const side = ACCENT_EDGE_SIDE_MAP[variant.accentEdge.edge];
82969
83290
  const width = ACCENT_EDGE_WIDTH_MAP[variant.accentEdge.width];
@@ -83934,8 +84255,11 @@ const recoverEmptyDescriptionWhenActive = {
83934
84255
  kind: "recover-empty-when-active",
83935
84256
  placeholder: "Add description"
83936
84257
  };
83937
- function eventSectionHeaderLayoutNodes() {
83938
- return [text({ as: "h2" }, bind$1("content.heading"), when("content.heading", { authoringPresence: recoverEmptyHeadingWhenActive })), richText({ className: "rb-prose rb-max-w-none" }, bind$1("content.description"), when("content.description", { authoringPresence: recoverEmptyDescriptionWhenActive }))];
84258
+ function eventSectionHeaderLayoutNodes(options = {}) {
84259
+ const headingNode = text({ as: "h2" }, bind$1("content.heading"), when("content.heading", { authoringPresence: recoverEmptyHeadingWhenActive }));
84260
+ const descriptionNode = richText({ className: "rb-prose rb-max-w-none" }, bind$1("content.description"), when("content.description", { authoringPresence: recoverEmptyDescriptionWhenActive }));
84261
+ if (options.splitClassName) return [el("div", { className: options.splitClassName }, [headingNode, descriptionNode])];
84262
+ return [headingNode, descriptionNode];
83939
84263
  }
83940
84264
  //#endregion
83941
84265
  //#region ../blocks/src/system/constants/events.ts
@@ -83953,7 +84277,8 @@ const eventCalendarDisplayModeValues = [
83953
84277
  "combined",
83954
84278
  "calendar",
83955
84279
  "list",
83956
- "timetable"
84280
+ "timetable",
84281
+ "week-board"
83957
84282
  ];
83958
84283
  const eventCalendarDefaultViewValues = ["month", "week"];
83959
84284
  const eventCalendarListLayoutValues = [
@@ -86698,6 +87023,115 @@ function expandPalette(palette) {
86698
87023
  return expanded;
86699
87024
  }
86700
87025
  //#endregion
87026
+ //#region ../theme-core/src/palette/colors.ts
87027
+ const HEX_COLOR_REGEX = /^#[0-9a-f]{6}$/;
87028
+ const NORMALIZABLE_HEX_REGEX = /^#(?:[0-9a-f]{3}|[0-9a-f]{6})$/i;
87029
+ const THEME_PALETTE_COLOR_ORDER = [
87030
+ "primary",
87031
+ "secondary",
87032
+ "accent",
87033
+ "success",
87034
+ "warning",
87035
+ "destructive",
87036
+ "background",
87037
+ "surface",
87038
+ "surfaceAlt",
87039
+ "muted",
87040
+ "text",
87041
+ "primaryForeground",
87042
+ "border"
87043
+ ];
87044
+ const hexColorSchema = z$1.string().regex(HEX_COLOR_REGEX, "Hex must be #RRGGBB (lowercase)").transform((value) => value);
87045
+ const paletteModeSchema = z$1.enum(["light", "dark"]);
87046
+ z$1.string().regex(/^[0-9a-f]{64}$/, "Palette hash must be a lowercase SHA-256 value").transform((value) => value);
87047
+ const paletteColorsSchema = z$1.object({
87048
+ primary: hexColorSchema,
87049
+ primaryForeground: hexColorSchema,
87050
+ secondary: hexColorSchema,
87051
+ accent: hexColorSchema,
87052
+ success: hexColorSchema,
87053
+ warning: hexColorSchema,
87054
+ destructive: hexColorSchema,
87055
+ background: hexColorSchema,
87056
+ surface: hexColorSchema,
87057
+ surfaceAlt: hexColorSchema,
87058
+ muted: hexColorSchema,
87059
+ text: hexColorSchema,
87060
+ border: hexColorSchema
87061
+ }).strict().transform((value) => value);
87062
+ function normalizePaletteHex(value) {
87063
+ if (!NORMALIZABLE_HEX_REGEX.test(value)) return null;
87064
+ const normalized = value.toLowerCase();
87065
+ if (normalized.length === 7) return normalized;
87066
+ const triplet = normalized.slice(1);
87067
+ const red = triplet.charAt(0);
87068
+ const green = triplet.charAt(1);
87069
+ const blue = triplet.charAt(2);
87070
+ return `#${red}${red}${green}${green}${blue}${blue}`;
87071
+ }
87072
+ function paletteColorsFromEntries(entries) {
87073
+ const values = {};
87074
+ for (const entry of entries) {
87075
+ const parsedRole = paletteTokenNameSchema.safeParse(entry.name);
87076
+ if (!parsedRole.success) return {
87077
+ ok: false,
87078
+ error: {
87079
+ kind: "unknown-role",
87080
+ role: entry.name
87081
+ }
87082
+ };
87083
+ const role = parsedRole.data;
87084
+ if (values[role] !== void 0) return {
87085
+ ok: false,
87086
+ error: {
87087
+ kind: "duplicate-role",
87088
+ role
87089
+ }
87090
+ };
87091
+ const hex = normalizePaletteHex(entry.hex);
87092
+ if (!hex) return {
87093
+ ok: false,
87094
+ error: {
87095
+ kind: "invalid-color",
87096
+ role,
87097
+ value: entry.hex
87098
+ }
87099
+ };
87100
+ values[role] = hex;
87101
+ }
87102
+ const missing = PALETTE_TOKEN_NAMES.filter((role) => values[role] === void 0);
87103
+ if (missing.length > 0) return {
87104
+ ok: false,
87105
+ error: {
87106
+ kind: "missing-roles",
87107
+ roles: missing
87108
+ }
87109
+ };
87110
+ return {
87111
+ ok: true,
87112
+ colors: paletteColorsSchema.parse(values)
87113
+ };
87114
+ }
87115
+ function requirePaletteColorsFromEntries(entries) {
87116
+ const result = paletteColorsFromEntries(entries);
87117
+ if (result.ok) return result.colors;
87118
+ throw new Error(`Invalid complete palette: ${result.error.kind}`);
87119
+ }
87120
+ function paletteColorEntries(colors) {
87121
+ return THEME_PALETTE_COLOR_ORDER.map((name) => ({
87122
+ name,
87123
+ hex: colors[name]
87124
+ }));
87125
+ }
87126
+ function applyPaletteColorOverrides(colors, overrides) {
87127
+ if (!overrides) return colors;
87128
+ return paletteColorsSchema.parse(Object.fromEntries(PALETTE_TOKEN_NAMES.map((name) => [name, overrides[name] ?? colors[name]])));
87129
+ }
87130
+ function paletteColorsEqual(left, right) {
87131
+ return PALETTE_TOKEN_NAMES.every((name) => left[name] === right[name]);
87132
+ }
87133
+ new Set(PALETTE_TOKEN_NAMES);
87134
+ //#endregion
86701
87135
  //#region ../../node_modules/.pnpm/@vibrant+image@4.0.4/node_modules/@vibrant/image/dist/esm/histogram.js
86702
87136
  var Histogram = class {
86703
87137
  constructor(pixels, opts) {
@@ -87732,119 +88166,10 @@ const pipeline = new BasicPipeline().filter.register("default", (r, g, b, a) =>
87732
88166
  //#region ../../node_modules/.pnpm/node-vibrant@4.0.4/node_modules/node-vibrant/dist/esm/browser.js
87733
88167
  Vibrant.use(pipeline);
87734
88168
  //#endregion
87735
- //#region ../theme-core/src/palette/colors.ts
87736
- const HEX_COLOR_REGEX = /^#[0-9a-f]{6}$/;
87737
- const NORMALIZABLE_HEX_REGEX = /^#(?:[0-9a-f]{3}|[0-9a-f]{6})$/i;
87738
- const THEME_PALETTE_COLOR_ORDER = [
87739
- "primary",
87740
- "secondary",
87741
- "accent",
87742
- "success",
87743
- "warning",
87744
- "destructive",
87745
- "background",
87746
- "surface",
87747
- "surfaceAlt",
87748
- "muted",
87749
- "text",
87750
- "primaryForeground",
87751
- "border"
87752
- ];
87753
- const hexColorSchema = z$1.string().regex(HEX_COLOR_REGEX, "Hex must be #RRGGBB (lowercase)").transform((value) => value);
87754
- const paletteModeSchema = z$1.enum(["light", "dark"]);
87755
- z$1.string().regex(/^[0-9a-f]{64}$/, "Palette hash must be a lowercase SHA-256 value").transform((value) => value);
87756
- const paletteColorsSchema = z$1.object({
87757
- primary: hexColorSchema,
87758
- primaryForeground: hexColorSchema,
87759
- secondary: hexColorSchema,
87760
- accent: hexColorSchema,
87761
- success: hexColorSchema,
87762
- warning: hexColorSchema,
87763
- destructive: hexColorSchema,
87764
- background: hexColorSchema,
87765
- surface: hexColorSchema,
87766
- surfaceAlt: hexColorSchema,
87767
- muted: hexColorSchema,
87768
- text: hexColorSchema,
87769
- border: hexColorSchema
87770
- }).strict().transform((value) => value);
87771
- function normalizePaletteHex(value) {
87772
- if (!NORMALIZABLE_HEX_REGEX.test(value)) return null;
87773
- const normalized = value.toLowerCase();
87774
- if (normalized.length === 7) return normalized;
87775
- const triplet = normalized.slice(1);
87776
- const red = triplet.charAt(0);
87777
- const green = triplet.charAt(1);
87778
- const blue = triplet.charAt(2);
87779
- return `#${red}${red}${green}${green}${blue}${blue}`;
87780
- }
87781
- function paletteColorsFromEntries(entries) {
87782
- const values = {};
87783
- for (const entry of entries) {
87784
- const parsedRole = paletteTokenNameSchema.safeParse(entry.name);
87785
- if (!parsedRole.success) return {
87786
- ok: false,
87787
- error: {
87788
- kind: "unknown-role",
87789
- role: entry.name
87790
- }
87791
- };
87792
- const role = parsedRole.data;
87793
- if (values[role] !== void 0) return {
87794
- ok: false,
87795
- error: {
87796
- kind: "duplicate-role",
87797
- role
87798
- }
87799
- };
87800
- const hex = normalizePaletteHex(entry.hex);
87801
- if (!hex) return {
87802
- ok: false,
87803
- error: {
87804
- kind: "invalid-color",
87805
- role,
87806
- value: entry.hex
87807
- }
87808
- };
87809
- values[role] = hex;
87810
- }
87811
- const missing = PALETTE_TOKEN_NAMES.filter((role) => values[role] === void 0);
87812
- if (missing.length > 0) return {
87813
- ok: false,
87814
- error: {
87815
- kind: "missing-roles",
87816
- roles: missing
87817
- }
87818
- };
87819
- return {
87820
- ok: true,
87821
- colors: paletteColorsSchema.parse(values)
87822
- };
87823
- }
87824
- function requirePaletteColorsFromEntries(entries) {
87825
- const result = paletteColorsFromEntries(entries);
87826
- if (result.ok) return result.colors;
87827
- throw new Error(`Invalid complete palette: ${result.error.kind}`);
87828
- }
87829
- function paletteColorEntries(colors) {
87830
- return THEME_PALETTE_COLOR_ORDER.map((name) => ({
87831
- name,
87832
- hex: colors[name]
87833
- }));
87834
- }
87835
- function applyPaletteColorOverrides(colors, overrides) {
87836
- if (!overrides) return colors;
87837
- return paletteColorsSchema.parse(Object.fromEntries(PALETTE_TOKEN_NAMES.map((name) => [name, overrides[name] ?? colors[name]])));
87838
- }
87839
- function paletteColorsEqual(left, right) {
87840
- return PALETTE_TOKEN_NAMES.every((name) => left[name] === right[name]);
87841
- }
87842
- //#endregion
87843
88169
  //#region ../theme-core/src/palette/themePaletteCompatibility.ts
87844
88170
  /**
87845
- * Parses both current complete Theme palettes and historical sparse palettes.
87846
- * Sparse entries remain sparse so callers can overlay them onto their own
87847
- * authoritative base without silently changing the persisted Theme shape.
88171
+ * Parses current complete Theme palettes and sparse editor payloads. Historical
88172
+ * migration-only completion lives in historicalThemePalette.ts.
87848
88173
  */
87849
88174
  function parseCompatibleThemePalette(theme) {
87850
88175
  const palette = theme.palette;
@@ -88148,6 +88473,71 @@ const brandLedJewel = defineCuratedPalette({
88148
88473
  }
88149
88474
  ]
88150
88475
  });
88476
+ const brandLedSpruce = defineCuratedPalette({
88477
+ id: "brand-led-spruce",
88478
+ name: "Brand-led — Spruce",
88479
+ description: "Spruce-ink primary and moss secondary with an amber accent over a green-mist ground and hairline sage borders.",
88480
+ tags: {
88481
+ tone: "classic",
88482
+ energy: "calm",
88483
+ era: "editorial"
88484
+ },
88485
+ mode: "light",
88486
+ colors: [
88487
+ {
88488
+ name: "primary",
88489
+ hex: "#14312b"
88490
+ },
88491
+ {
88492
+ name: "secondary",
88493
+ hex: "#356a59"
88494
+ },
88495
+ {
88496
+ name: "accent",
88497
+ hex: "#f08a4b"
88498
+ },
88499
+ {
88500
+ name: "success",
88501
+ hex: "#356a59"
88502
+ },
88503
+ {
88504
+ name: "warning",
88505
+ hex: "#f08a4b"
88506
+ },
88507
+ {
88508
+ name: "destructive",
88509
+ hex: "#b5561f"
88510
+ },
88511
+ {
88512
+ name: "background",
88513
+ hex: "#ecefe9"
88514
+ },
88515
+ {
88516
+ name: "surface",
88517
+ hex: "#ffffff"
88518
+ },
88519
+ {
88520
+ name: "surfaceAlt",
88521
+ hex: "#f4f6f1"
88522
+ },
88523
+ {
88524
+ name: "muted",
88525
+ hex: "#5c6a64"
88526
+ },
88527
+ {
88528
+ name: "text",
88529
+ hex: "#1c2a26"
88530
+ },
88531
+ {
88532
+ name: "primaryForeground",
88533
+ hex: "#f4f7f1"
88534
+ },
88535
+ {
88536
+ name: "border",
88537
+ hex: "#d7ddd2"
88538
+ }
88539
+ ]
88540
+ });
88151
88541
  const brandLedBurgundyGold = defineCuratedPalette({
88152
88542
  id: "brand-led-burgundy-gold",
88153
88543
  name: "Brand-led — Burgundy Gold",
@@ -88687,6 +89077,7 @@ const curatedPalettes = [
88687
89077
  brandLedWarm,
88688
89078
  brandLedJewel,
88689
89079
  brandLedBurgundyGold,
89080
+ brandLedSpruce,
88690
89081
  defineCuratedPalette({
88691
89082
  id: "warm-neutral-clay",
88692
89083
  name: "Warm Neutral — Clay",
@@ -90996,6 +91387,13 @@ const legacyHeaderLookAliases = defineExactCatalog()([
90996
91387
  styleId: asHeaderStyleId("minimal")
90997
91388
  }
90998
91389
  },
91390
+ {
91391
+ lookId: asHeaderLookId("classic-centered-nav"),
91392
+ selection: {
91393
+ layoutId: asHeaderLayoutId("classic"),
91394
+ styleId: asHeaderStyleId("fine-line")
91395
+ }
91396
+ },
90999
91397
  {
91000
91398
  lookId: asHeaderLookId("brand-solid"),
91001
91399
  selection: {
@@ -91652,6 +92050,38 @@ function cleanBaseHeader(theme) {
91652
92050
  ctaGap: "default"
91653
92051
  };
91654
92052
  }
92053
+ function classicCenteredNavHeader(theme) {
92054
+ return {
92055
+ ...baseHeader(theme),
92056
+ variant: "classic",
92057
+ navPlacement: "center",
92058
+ positioning: "sticky",
92059
+ shrinkOnScroll: false,
92060
+ background: {
92061
+ type: "color",
92062
+ color: "surface"
92063
+ },
92064
+ textColor: "text",
92065
+ navColor: "text",
92066
+ navStyle: "underline-grow",
92067
+ navWeight: "medium",
92068
+ navLinkStyle: underlineNavLinkStyle("text", "accent"),
92069
+ border: {
92070
+ style: "solid",
92071
+ width: "thin",
92072
+ position: "bottom",
92073
+ colorToken: "border"
92074
+ },
92075
+ ctaTreatment: "primary",
92076
+ ctaVariant: resolveHeaderCtaVariant(theme, "primary"),
92077
+ ctaGap: "default",
92078
+ logoText: {
92079
+ mobileMaxWidth: "sm",
92080
+ mobileWrapLines: 1,
92081
+ hideOnShrink: false
92082
+ }
92083
+ };
92084
+ }
91655
92085
  function serifLineHeader(theme) {
91656
92086
  return {
91657
92087
  ...baseHeader(theme),
@@ -91816,6 +92246,21 @@ const headerLookCatalog = defineExactCatalog()([
91816
92246
  logoAccommodations: inlineClassicLogoAccommodations,
91817
92247
  compile: cleanBaseHeader
91818
92248
  },
92249
+ {
92250
+ id: asHeaderLookId("classic-centered-nav"),
92251
+ label: "Centered nav",
92252
+ visualTreatment: "solid-neutral",
92253
+ layoutBehavior: "sticky",
92254
+ configuration: {
92255
+ structure: "inline-classic",
92256
+ treatment: "solid-neutral",
92257
+ behavior: "sticky"
92258
+ },
92259
+ openingRequirement: "none",
92260
+ maxRecommendedNavItems: 6,
92261
+ logoAccommodations: inlineClassicLogoAccommodations,
92262
+ compile: classicCenteredNavHeader
92263
+ },
91819
92264
  {
91820
92265
  id: asHeaderLookId("brand-solid"),
91821
92266
  label: "Brand solid",
@@ -92551,7 +92996,8 @@ const typographyPresetIdValues = [
92551
92996
  "typography-preset:luxe-contrast",
92552
92997
  "typography-preset:kirtan-ornate",
92553
92998
  "typography-preset:bold-display",
92554
- "typography-preset:original-joy"
92999
+ "typography-preset:original-joy",
93000
+ "typography-preset:fulcrum"
92555
93001
  ];
92556
93002
  const bodyReadablePolicy = {
92557
93003
  recommendedCategories: ["sans-serif", "serif"],
@@ -93175,6 +93621,74 @@ const typographyPresets = [
93175
93621
  }
93176
93622
  }
93177
93623
  }
93624
+ }),
93625
+ defineTypographyPreset({
93626
+ id: "typography-preset:fulcrum",
93627
+ name: "Fulcrum",
93628
+ description: "Newsreader serif headings over an IBM Plex Sans body, with an IBM Plex Mono eyebrow role for uppercase kickers and mono captions.",
93629
+ defaultFonts: {
93630
+ body: "IBM Plex Sans, system-ui, -apple-system, sans-serif",
93631
+ heading: "Newsreader, Georgia, \"Times New Roman\", serif"
93632
+ },
93633
+ recommendedFonts: {
93634
+ body: [
93635
+ "IBM Plex Sans",
93636
+ "Source Sans 3",
93637
+ "Inter"
93638
+ ],
93639
+ heading: [
93640
+ "Newsreader",
93641
+ "Source Serif 4",
93642
+ "Lora"
93643
+ ]
93644
+ },
93645
+ slotPolicies: {
93646
+ body: bodyReadablePolicy,
93647
+ heading: displayHeadingPolicy
93648
+ },
93649
+ typography: {
93650
+ body: {
93651
+ family: "IBM Plex Sans, system-ui, -apple-system, sans-serif",
93652
+ size: "lg",
93653
+ weight: "regular",
93654
+ lineHeight: "relaxed",
93655
+ letterSpacing: "normal"
93656
+ },
93657
+ headings: {
93658
+ default: {
93659
+ family: "Newsreader, Georgia, \"Times New Roman\", serif",
93660
+ weight: "medium",
93661
+ lineHeight: "normal",
93662
+ letterSpacing: "tight",
93663
+ colorToken: "primary",
93664
+ italic: null,
93665
+ case: null
93666
+ },
93667
+ h1: {
93668
+ size: "2xl",
93669
+ weight: "medium",
93670
+ lineHeight: "normal",
93671
+ letterSpacing: "tight",
93672
+ italic: null
93673
+ },
93674
+ h2: {
93675
+ size: "xl",
93676
+ weight: "medium",
93677
+ lineHeight: "normal",
93678
+ letterSpacing: "tight",
93679
+ italic: null
93680
+ },
93681
+ h3: {
93682
+ size: "md",
93683
+ weight: "semibold",
93684
+ lineHeight: "normal",
93685
+ letterSpacing: "normal",
93686
+ italic: null
93687
+ }
93688
+ },
93689
+ scale: "spacious",
93690
+ eyebrow: { family: "IBM Plex Mono, ui-monospace, \"SF Mono\", monospace" }
93691
+ }
93178
93692
  })
93179
93693
  ];
93180
93694
  const typographyPresetsById = new Map(typographyPresets.map((preset) => [preset.id, preset]));
@@ -93473,11 +93987,31 @@ const gradientStopSchema = z$1.object({
93473
93987
  position: z$1.number().min(0).max(100)
93474
93988
  });
93475
93989
  /**
93476
- * Gradient configuration
93990
+ * Radial gradient shape. Optional; defaults to `circle` (the historical shape)
93991
+ * so existing radial gradients are byte-identical.
93992
+ *
93993
+ * Named `RadialGradientShape` to avoid clashing with `styles/gradients.ts`'s
93994
+ * `GradientShape` (which names the gradient *kind*: linear/radial/conic).
93995
+ */
93996
+ const radialGradientShapeSchema = z$1.enum(["circle", "ellipse"]);
93997
+ /**
93998
+ * Gradient configuration.
93999
+ *
94000
+ * `type` is optional and defaults to `'linear'` so gradients persisted without a
94001
+ * type (or with an explicit `'linear'`) render exactly as before. `'radial'` and
94002
+ * `'conic'` are additive kinds:
94003
+ * - linear: `angle` (degrees)
94004
+ * - radial: optional `shape` (circle/ellipse) + `position`
94005
+ * - conic: optional `angle` (from-angle, degrees) + `position`
93477
94006
  */
93478
94007
  const gradientConfigSchema = z$1.object({
93479
- type: z$1.enum(["linear", "radial"]),
94008
+ type: z$1.enum([
94009
+ "linear",
94010
+ "radial",
94011
+ "conic"
94012
+ ]).default("linear"),
93480
94013
  angle: z$1.number().min(0).max(360).optional(),
94014
+ shape: radialGradientShapeSchema.optional(),
93481
94015
  position: z$1.string().optional(),
93482
94016
  stops: z$1.array(gradientStopSchema).min(2)
93483
94017
  });
@@ -94275,6 +94809,7 @@ const typographyScaleSchema = z$1.enum([
94275
94809
  "majorThird",
94276
94810
  "perfectFourth"
94277
94811
  ]);
94812
+ const eyebrowTypographyStyleSchema = z$1.object({ family: z$1.string().min(1) });
94278
94813
  const typographySchema = z$1.object({
94279
94814
  body: bodyTypographyStyleSchema,
94280
94815
  headings: z$1.object({
@@ -94287,7 +94822,8 @@ const typographySchema = z$1.object({
94287
94822
  h6: headingTypographyOverridesSchema.optional()
94288
94823
  }),
94289
94824
  scale: typographyScaleSchema,
94290
- proseLinkStyle: proseLinkStyleSchema.optional()
94825
+ proseLinkStyle: proseLinkStyleSchema.optional(),
94826
+ eyebrow: eyebrowTypographyStyleSchema.optional()
94291
94827
  });
94292
94828
  const spaceSchema = z$1.enum([
94293
94829
  "comfortable",
@@ -94312,7 +94848,8 @@ const shadow = z$1.object({
94312
94848
  "soft",
94313
94849
  "hard"
94314
94850
  ]).nullable(),
94315
- position: z$1.enum(["bottom", "bottom-right"]).default("bottom")
94851
+ position: z$1.enum(["bottom", "bottom-right"]).default("bottom"),
94852
+ colorToken: themeColorTokenSchema.optional()
94316
94853
  });
94317
94854
  const border = z$1.object({
94318
94855
  width: z$1.enum([
@@ -94557,6 +95094,7 @@ const headerSchema = z$1.object({
94557
95094
  navWeight: navFontWeight.default("medium"),
94558
95095
  navTypography: z$1.enum(["body", "heading"]).optional(),
94559
95096
  navTextSize: navLinkStyleSchema.shape.textSize,
95097
+ navPlacement: z$1.enum(["end", "center"]).optional(),
94560
95098
  container: headerContainerSchema,
94561
95099
  border: headerBorderSchema,
94562
95100
  shadow: componentShadowSchema.optional(),
@@ -95969,7 +96507,8 @@ const curatedSiteStyleIdValues = [
95969
96507
  "site-style:bold-launch",
95970
96508
  "site-style:south-west-twerk-school",
95971
96509
  "site-style:kirtan-ornate",
95972
- "site-style:original-joy"
96510
+ "site-style:original-joy",
96511
+ "site-style:fulcrum"
95973
96512
  ];
95974
96513
  const quietBudget = {
95975
96514
  accentDensity: "low",
@@ -97423,6 +97962,104 @@ const curatedSiteStyles = [
97423
97962
  buttonChoice("showtime-pill")
97424
97963
  ],
97425
97964
  paletteRecommendations: [paletteRecommendation("warm-dark-ember")]
97965
+ }),
97966
+ defineCuratedSiteStyle({
97967
+ id: "site-style:fulcrum",
97968
+ name: "Fulcrum",
97969
+ headingDecoration: {
97970
+ family: "short-center-rule",
97971
+ colorToken: "accent"
97972
+ },
97973
+ description: "Spruce-ink and moss with an amber climax, Newsreader serif over IBM Plex Sans, hairline sage borders and flat buttons — a grounded, editorial physiotherapy skin.",
97974
+ generationBrief: "Use a calm, clinician-led voice: precise, reassuring and specific rather than clinical-cold. Lead with the assessment-treatment-rehab journey, mono uppercase eyebrows for practical labels (hours, registrations, appointment windows), Newsreader serif headings over IBM Plex Sans body, and a single amber call to action as the page climax. Keep proof concrete (registrations, same-week appointments, return-to-activity outcomes) and avoid spa or hard-sell wellness language or medical claims.",
97975
+ siteCreatorSelection: {
97976
+ kind: "site_creator_keyword_heuristic",
97977
+ priority: 28
97978
+ },
97979
+ selectionKeywordRules: [
97980
+ {
97981
+ kind: "substring",
97982
+ value: "physiotherap"
97983
+ },
97984
+ {
97985
+ kind: "word",
97986
+ value: "physio"
97987
+ },
97988
+ {
97989
+ kind: "phrase",
97990
+ value: "sports injury"
97991
+ },
97992
+ {
97993
+ kind: "phrase",
97994
+ value: "rehab clinic"
97995
+ },
97996
+ {
97997
+ kind: "substring",
97998
+ value: "musculoskeletal"
97999
+ },
98000
+ {
98001
+ kind: "phrase",
98002
+ value: "sports therapy"
98003
+ }
98004
+ ],
98005
+ tokenRecipes: {
98006
+ palette: "brand-led",
98007
+ contrast: "standard",
98008
+ radius: "rounded",
98009
+ shadow: "subtle",
98010
+ typography: "serif-editorial",
98011
+ spacing: "airy",
98012
+ motion: "subtle"
98013
+ },
98014
+ compositionBudget: quietBudget,
98015
+ typographyPresetChoices: [
98016
+ typographyChoice("typography-preset:fulcrum"),
98017
+ typographyChoice("typography-preset:editorial-serif"),
98018
+ typographyChoice("typography-preset:modern-sans")
98019
+ ],
98020
+ defaultTypographyPresetId: "typography-preset:fulcrum",
98021
+ themeOverrides: {
98022
+ shadow: { colorToken: "primary" },
98023
+ accordions: {
98024
+ background: null,
98025
+ spacing: "comfortable",
98026
+ corners: "square",
98027
+ border: null,
98028
+ shadow: null,
98029
+ icon: {
98030
+ style: "plus-minus",
98031
+ position: "right",
98032
+ size: "md",
98033
+ colorToken: "accent"
98034
+ },
98035
+ trigger: {
98036
+ textColorToken: "primary",
98037
+ fontWeight: "medium",
98038
+ fontFamily: "heading",
98039
+ fontScale: "md"
98040
+ },
98041
+ hover: { textColorToken: "secondary" },
98042
+ content: { textColorToken: "muted" }
98043
+ },
98044
+ testimonialQuote: serifDisplayQuote
98045
+ },
98046
+ recommendedHeaderLookIds: [
98047
+ "classic-centered-nav",
98048
+ "serif-line",
98049
+ "centered-calm",
98050
+ "clean-base"
98051
+ ],
98052
+ recommendedFooterLookIds: ["footer-editorial-columns", "footer-muted-grounding"],
98053
+ buttonPersonalityChoices: [
98054
+ buttonChoice("flat-ink"),
98055
+ buttonChoice("confident-chip"),
98056
+ buttonChoice("editorial-link")
98057
+ ],
98058
+ paletteRecommendations: [
98059
+ paletteRecommendation("brand-led-spruce"),
98060
+ paletteRecommendation("warm-neutral-forest"),
98061
+ paletteRecommendation("soft-natural-sage")
98062
+ ]
97426
98063
  })
97427
98064
  ];
97428
98065
  const curatedSiteStylesById = new Map(curatedSiteStyles.map((style) => [style.id, style]));
@@ -98015,6 +98652,10 @@ function applySiteStyleThemeOverrides(theme, siteStyle) {
98015
98652
  ...overrides.hero ? { hero: mergeHeroOverride(theme, overrides.hero) } : {},
98016
98653
  ...overrides.bodyText ? { bodyText: mergeBodyTextOverride(theme, overrides.bodyText) } : {},
98017
98654
  ...overrides.inputs ? { inputs: overrides.inputs } : {},
98655
+ ...overrides.shadow ? { shadow: {
98656
+ ...theme.shadow,
98657
+ ...overrides.shadow
98658
+ } } : {},
98018
98659
  ...overrides.accordions ? { accordions: overrides.accordions } : {},
98019
98660
  ...overrides.cards ? { cards: overrides.cards } : {},
98020
98661
  ...overrides.testimonialQuote ? { testimonialQuote: overrides.testimonialQuote } : {}
@@ -98904,7 +99545,7 @@ function resolveBackgroundColorValue(value, context) {
98904
99545
  return resolveThemeColorReferenceValue(value, { palette: context.theme?.palette });
98905
99546
  }
98906
99547
  //#endregion
98907
- //#region ../blocks/src/system/transforms/registry/_utils/sectionForegroundStyles.ts
99548
+ //#region ../blocks/src/system/transforms/registry/_utils/surfaceForegroundStyles.ts
98908
99549
  function readColorToken(input, key) {
98909
99550
  const value = input[key];
98910
99551
  return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
@@ -98913,18 +99554,17 @@ function resolveOptionalForegroundColor(value, context) {
98913
99554
  if (!value) return null;
98914
99555
  return resolveBackgroundColorValue(value, context);
98915
99556
  }
98916
- function resolveSectionForegroundStyles(value, context) {
99557
+ function resolveSurfaceForegroundStyles(value, context) {
98917
99558
  if (!value || typeof value !== "object") return {};
98918
99559
  const input = value;
98919
99560
  const resolvedText = resolveOptionalForegroundColor(readColorToken(input, "textColor"), context);
98920
99561
  if (!resolvedText) return {};
98921
- return {
98922
- color: resolvedText,
98923
- "--section-text-color": resolvedText,
98924
- "--section-heading-color": resolveOptionalForegroundColor(readColorToken(input, "headingColor"), context) ?? resolvedText,
98925
- "--section-link-color": resolveOptionalForegroundColor(readColorToken(input, "linkColor"), context) ?? resolvedText,
98926
- "--section-supporting-color": resolveOptionalForegroundColor(readColorToken(input, "supportingColor"), context) ?? resolvedText
98927
- };
99562
+ return { ...surfaceForegroundStyle({
99563
+ text: resolvedText,
99564
+ heading: resolveOptionalForegroundColor(readColorToken(input, "headingColor"), context) ?? void 0,
99565
+ link: resolveOptionalForegroundColor(readColorToken(input, "linkColor"), context) ?? void 0,
99566
+ supporting: resolveOptionalForegroundColor(readColorToken(input, "supportingColor"), context) ?? void 0
99567
+ }) };
98928
99568
  }
98929
99569
  //#endregion
98930
99570
  //#region ../blocks/src/system/transforms/registry/boxStyles.ts
@@ -99258,67 +99898,12 @@ const containerStylesResolveBoxClassName = {
99258
99898
  }
99259
99899
  };
99260
99900
  /**
99261
- * Resolves section text color style object.
99262
- *
99263
- * The value should be the `_sectionStyles.background.textColor` token.
99264
- * Returns an empty object when unset so the section inherits text color.
99265
- *
99266
- * Outputs both `color` and `--section-text-color` CSS variable so that
99267
- * headings (which have explicit color rules in typography CSS) can inherit
99268
- * the section's text color via the CSS variable cascade.
99269
- */
99270
- const sectionTextColorStyleTransform = {
99271
- id: "sectionStyles.resolveTextColorStyle",
99272
- kind: "formatter",
99273
- summary: "Resolve section text color token into a style object",
99274
- run: (value, options, context) => {
99275
- const fallbackToken = options?.fallbackToken;
99276
- if (typeof value === "string" && value.trim()) {
99277
- const colorValue = resolveBackgroundColorValue(value.trim(), context);
99278
- return {
99279
- color: colorValue,
99280
- "--section-text-color": colorValue
99281
- };
99282
- }
99283
- if (typeof fallbackToken === "string" && fallbackToken.trim()) {
99284
- const colorValue = resolveBackgroundColorValue(fallbackToken.trim(), context);
99285
- return {
99286
- color: colorValue,
99287
- "--section-text-color": colorValue
99288
- };
99289
- }
99290
- return {};
99291
- }
99292
- };
99293
- /**
99294
- * Resolves section heading color style object.
99295
- *
99296
- * The value should be the `_sectionStyles.background.headingColor` token.
99297
- * Returns an empty object when unset so headings inherit from textColor or default.
99298
- *
99299
- * Outputs `--section-heading-color` CSS variable which typography CSS can use
99300
- * to style headings differently from body text within a section.
99301
- */
99302
- const sectionHeadingColorStyleTransform = {
99303
- id: "sectionStyles.resolveHeadingColorStyle",
99304
- kind: "formatter",
99305
- summary: "Resolve section heading color token into a style object",
99306
- run: (value, options, context) => {
99307
- const fallbackToken = options?.fallbackToken;
99308
- if (typeof value === "string" && value.trim()) return { "--section-heading-color": resolveBackgroundColorValue(value.trim(), context) };
99309
- if (typeof fallbackToken === "string" && fallbackToken.trim()) return { "--section-heading-color": resolveBackgroundColorValue(fallbackToken.trim(), context) };
99310
- return {};
99311
- }
99312
- };
99313
- /**
99314
- * Resolves section foreground colors from the background object.
99901
+ * Resolves surface foreground colors from the background object.
99315
99902
  *
99316
99903
  * The value should be the full `_sectionStyles.background` object.
99317
99904
  * Outputs:
99318
- * - `color` and `--section-text-color` from background.textColor
99319
- * - `--section-heading-color` from background.headingColor (falls back to textColor if not set)
99320
- * - `--section-link-color` from background.linkColor (falls back to textColor if not set)
99321
- * - `--section-supporting-color` from background.supportingColor (falls back to textColor if not set)
99905
+ * - `color` and the complete `--rb-surface-*-color` contract
99906
+ * - optional roles fall back atomically to background.textColor
99322
99907
  *
99323
99908
  * This combined transform replaces separate foreground color transforms
99324
99909
  * when both need to be applied to the same style prop.
@@ -99326,8 +99911,8 @@ const sectionHeadingColorStyleTransform = {
99326
99911
  const sectionColorsStyleTransform = {
99327
99912
  id: "sectionStyles.resolveColorsStyle",
99328
99913
  kind: "formatter",
99329
- summary: "Resolve section foreground colors into a style object",
99330
- run: (value, _options, context) => resolveSectionForegroundStyles(value, context)
99914
+ summary: "Resolve surface foreground colors into a style object",
99915
+ run: (value, _options, context) => resolveSurfaceForegroundStyles(value, context)
99331
99916
  };
99332
99917
  /**
99333
99918
  * Maps semantic gap values to theme-aware gap classes.
@@ -99366,8 +99951,6 @@ const boxStylesTransforms = [
99366
99951
  sectionClassNameTransform,
99367
99952
  containerStylesResolveClassName,
99368
99953
  containerStylesResolveBoxClassName,
99369
- sectionTextColorStyleTransform,
99370
- sectionHeadingColorStyleTransform,
99371
99954
  sectionColorsStyleTransform,
99372
99955
  {
99373
99956
  id: "boxStyles.semanticGap",
@@ -101696,7 +102279,29 @@ const ctaRowFragment = defineFragment({
101696
102279
  fields: [createCtasRepeater({
101697
102280
  label: "Calls to action",
101698
102281
  itemLabel: "CTA",
101699
- maxItems: 3
102282
+ maxItems: 3,
102283
+ button: { variants: [
102284
+ {
102285
+ value: "primary",
102286
+ label: "Primary"
102287
+ },
102288
+ {
102289
+ value: "secondary",
102290
+ label: "Secondary"
102291
+ },
102292
+ {
102293
+ value: "outline",
102294
+ label: "Outline"
102295
+ },
102296
+ {
102297
+ value: "link",
102298
+ label: "Link"
102299
+ },
102300
+ {
102301
+ value: "accent",
102302
+ label: "Accent"
102303
+ }
102304
+ ] }
101700
102305
  })],
101701
102306
  layout: [ctaRow({
101702
102307
  collectionPath: "content.ctas",
@@ -101977,6 +102582,55 @@ function buildGridCardsLayout(className) {
101977
102582
  return el("div", { className }, buildResponsiveGridCards());
101978
102583
  }
101979
102584
  /**
102585
+ * Build a single "featured editorial" testimonial card.
102586
+ *
102587
+ * This card type deliberately renders NO avatar/headshot: an amber quote mark,
102588
+ * the quote body, then the author name and a context line. Colour + surface
102589
+ * treatment is driven entirely by `variantClass` (see testimonials.css):
102590
+ * - `rb-testimonials-fe-card--feature` → spruce-ink card (dark primary bg)
102591
+ * - `rb-testimonials-fe-card--plain` → white surface card
102592
+ *
102593
+ * Extra modifiers (`repeat`, `when`) are forwarded to the card node so the
102594
+ * caller can drive first-vs-rest branching.
102595
+ */
102596
+ function buildFeaturedEditorialCard(variantClass, ...mods) {
102597
+ const quoteMark = text({
102598
+ as: "span",
102599
+ className: "rb-testimonials-fe-qmark",
102600
+ "aria-hidden": "true"
102601
+ }, props({ value: "“" }));
102602
+ const quote = richText({ className: "rb-testimonials-fe-quote rb-max-w-none" }, bind$1("testimonial.content.body"), when("testimonial.content.body"));
102603
+ const meta = el("div", { className: "rb-testimonials-fe-meta" }, [text({
102604
+ as: "strong",
102605
+ className: "rb-testimonials-fe-name"
102606
+ }, bind$1("testimonial.content.name", { fallback: "Anonymous" })), text({
102607
+ as: "span",
102608
+ className: "rb-testimonials-fe-context"
102609
+ }, when("testimonial.content.jobTitle"), bind$1("testimonial.content.jobTitle"))]);
102610
+ return el("div", { className: `rb-testimonials-fe-card ${variantClass}` }, [
102611
+ quoteMark,
102612
+ quote,
102613
+ meta
102614
+ ], ...mods);
102615
+ }
102616
+ /**
102617
+ * Build the "featured editorial" layout: an asymmetric two-column arrangement
102618
+ * where the FIRST testimonial is a large featured (spruce-ink) card and the
102619
+ * remaining testimonials stack as white cards beside it.
102620
+ *
102621
+ * First-vs-rest branching is done without an offset primitive: the featured
102622
+ * card uses `repeat(..., { limit: 1 })` (entry 0 only), and the rest column
102623
+ * repeats over every entry but skips index 0 via `when("tIndex", { equals: 0,
102624
+ * not: true })`. The `$when` guard is re-evaluated per repeated item with the
102625
+ * index scope in context, so entry 0 produces no node in the rest column.
102626
+ */
102627
+ function buildFeaturedEditorialLayout() {
102628
+ return el("div", { className: "rb-testimonials-fe-grid" }, [buildFeaturedEditorialCard("rb-testimonials-fe-card--feature", repeat("data.entries", "testimonial", { limit: 1 })), el("div", { className: "rb-testimonials-fe-col" }, [buildFeaturedEditorialCard("rb-testimonials-fe-card--plain", repeat("data.entries", "testimonial", { indexName: "tIndex" }), when("tIndex", {
102629
+ equals: 0,
102630
+ not: true
102631
+ }))])]);
102632
+ }
102633
+ /**
101980
102634
  * Fragment definition for testimonials carousel.
101981
102635
  * Provides field definitions and data loader configuration.
101982
102636
  *
@@ -106480,7 +107134,7 @@ const eventCalendarLayout = [styledSection({
106480
107134
  children: styledContainer({
106481
107135
  rootType: "stack",
106482
107136
  rootProps: { gap: "lg" },
106483
- children: [...eventSectionHeaderLayoutNodes(), el("event-calendar", withApiBindings({
107137
+ children: [...eventSectionHeaderLayoutNodes({ splitClassName: "event-section-head event-section-head--split" }), el("event-calendar", withApiBindings({
106484
107138
  events: { $bind: { from: "data.events" } },
106485
107139
  stage: { $bind: {
106486
107140
  from: "$root.previewStage",
@@ -106591,6 +107245,10 @@ const eventCalendarAdditionalFields = [
106591
107245
  value: "timetable",
106592
107246
  label: "Timetable"
106593
107247
  },
107248
+ {
107249
+ value: "week-board",
107250
+ label: "Week board"
107251
+ },
106594
107252
  {
106595
107253
  value: "list",
106596
107254
  label: "List"
@@ -106773,7 +107431,8 @@ const eventCalendarAdditionalFields = [
106773
107431
  oneOf: [
106774
107432
  "combined",
106775
107433
  "calendar",
106776
- "timetable"
107434
+ "timetable",
107435
+ "week-board"
106777
107436
  ]
106778
107437
  }
106779
107438
  }
@@ -106876,7 +107535,8 @@ const eventCalendarAdditionalFields = [
106876
107535
  "combined",
106877
107536
  "calendar",
106878
107537
  "list",
106879
- "timetable"
107538
+ "timetable",
107539
+ "week-board"
106880
107540
  ]
106881
107541
  }
106882
107542
  }
@@ -106911,7 +107571,8 @@ const eventCalendarAdditionalFields = [
106911
107571
  "combined",
106912
107572
  "calendar",
106913
107573
  "list",
106914
- "timetable"
107574
+ "timetable",
107575
+ "week-board"
106915
107576
  ]
106916
107577
  }, {
106917
107578
  field: "showFilters",
@@ -106934,7 +107595,8 @@ const eventCalendarAdditionalFields = [
106934
107595
  "combined",
106935
107596
  "calendar",
106936
107597
  "list",
106937
- "timetable"
107598
+ "timetable",
107599
+ "week-board"
106938
107600
  ]
106939
107601
  }, {
106940
107602
  field: "showFilters",
@@ -106957,7 +107619,8 @@ const eventCalendarAdditionalFields = [
106957
107619
  "combined",
106958
107620
  "calendar",
106959
107621
  "list",
106960
- "timetable"
107622
+ "timetable",
107623
+ "week-board"
106961
107624
  ]
106962
107625
  }, {
106963
107626
  field: "showFilters",
@@ -106979,7 +107642,8 @@ const eventCalendarAdditionalFields = [
106979
107642
  oneOf: [
106980
107643
  "combined",
106981
107644
  "list",
106982
- "timetable"
107645
+ "timetable",
107646
+ "week-board"
106983
107647
  ]
106984
107648
  }, { allOf: [{
106985
107649
  field: "variant",
@@ -107155,6 +107819,7 @@ const eventCalendarVariants = {
107155
107819
  combined: eventCalendarLayout[0],
107156
107820
  calendar: eventCalendarLayout[0],
107157
107821
  timetable: eventCalendarLayout[0],
107822
+ "week-board": eventCalendarLayout[0],
107158
107823
  list: eventCalendarLayout[0]
107159
107824
  };
107160
107825
  const eventCalendarContentShape = {
@@ -107168,6 +107833,7 @@ const eventCalendarContentShape = {
107168
107833
  { value: "combined" },
107169
107834
  { value: "calendar" },
107170
107835
  { value: "timetable" },
107836
+ { value: "week-board" },
107171
107837
  { value: "list" }
107172
107838
  ]
107173
107839
  },
@@ -107234,6 +107900,7 @@ const eventCalendarBlockDefinition = {
107234
107900
  combined: { label: "Combined" },
107235
107901
  calendar: { label: "Calendar" },
107236
107902
  timetable: { label: "Timetable" },
107903
+ "week-board": { label: "Week board" },
107237
107904
  list: { label: "List" }
107238
107905
  }
107239
107906
  }, eventCalendarContentShape),
@@ -111306,7 +111973,7 @@ const defaultLayout = styledSection({
111306
111973
  children: styledContainer({
111307
111974
  baseClassName: "rb-relative rb-isolate",
111308
111975
  children: stack({
111309
- gap: "xl",
111976
+ gap: "lg",
111310
111977
  className: "rb-w-full rb-max-w-4xl rb-mx-auto"
111311
111978
  }, [headingLayout, accordionLayout])
111312
111979
  }),
@@ -111323,7 +111990,7 @@ const questionColumnsLayout = styledSection({
111323
111990
  children: styledContainer({
111324
111991
  baseClassName: "rb-relative rb-isolate",
111325
111992
  children: stack({
111326
- gap: "xl",
111993
+ gap: "lg",
111327
111994
  className: "rb-w-full"
111328
111995
  }, [headingLayout, questionColumnsAccordionLayout])
111329
111996
  }),
@@ -111488,7 +112155,26 @@ const formattingTransforms = [
111488
112155
  arrayLengthTransform,
111489
112156
  jsonArrayTransform,
111490
112157
  csvTransform,
111491
- marqueeLoopTransform
112158
+ marqueeLoopTransform,
112159
+ {
112160
+ id: "value.mapToken",
112161
+ kind: "formatter",
112162
+ summary: "Map a state/enum value to a theme token colour (rgb(var(--tb-<role>)))",
112163
+ schema: z$1.object({
112164
+ /**
112165
+ * Maps an input state/enum value (stringified) to a theme token ROLE name
112166
+ * (e.g. `secondary`, `accent`, `muted`, `border`). The role is wrapped to
112167
+ * `rgb(var(--tb-<role>))` so the result drops straight into a `style` binding.
112168
+ */
112169
+ cases: z$1.record(z$1.string(), z$1.string()),
112170
+ /** Role used when the value matches no case. Omit to yield `undefined`. */
112171
+ fallback: z$1.string().optional()
112172
+ }),
112173
+ run: (value, options) => {
112174
+ const role = options.cases[String(value)] ?? options.fallback;
112175
+ return role ? `rgb(var(--tb-${role}))` : void 0;
112176
+ }
112177
+ }
111492
112178
  ];
111493
112179
  //#endregion
111494
112180
  //#region ../blocks/src/system/transforms/registry/ui.ts
@@ -112072,6 +112758,26 @@ const headerLogoTextVisibleTransform = {
112072
112758
  return resolveHeaderBrandDisplay(asPartialObject(value)) !== "logo-only";
112073
112759
  }
112074
112760
  };
112761
+ /**
112762
+ * Selects which classic-layout nav row should render.
112763
+ *
112764
+ * - `'inline'` → classic variant with the historical logo-left / nav-right row
112765
+ * - `'centered'`→ classic variant with a centred (flex-1) nav and a right CTA
112766
+ * - `'other'` → not a classic variant (centered/floating/transparent handle it)
112767
+ *
112768
+ * Consumed by the site-header block's `$when` gates so the two classic rows are
112769
+ * mutually exclusive without introducing a new top-level header variant.
112770
+ */
112771
+ const classicNavModeTransform = {
112772
+ id: "layout.classicNavMode",
112773
+ kind: "formatter",
112774
+ summary: "Resolve which classic-layout nav row to render",
112775
+ run: (value) => {
112776
+ const header = asPartialObject(value);
112777
+ if (header?.variant !== "classic") return "other";
112778
+ return header?.navPlacement === "center" ? "centered" : "inline";
112779
+ }
112780
+ };
112075
112781
  const maxWidthClassTransform = {
112076
112782
  id: "layout.maxWidthClass",
112077
112783
  kind: "string",
@@ -112254,8 +112960,9 @@ const footerRootStyleTransform = {
112254
112960
  styleParts.push(backgroundColorStyle(token));
112255
112961
  }
112256
112962
  }
112257
- if (visuals.textColorOverride) styleParts.push({ color: visuals.textColorOverride });
112258
- else if (visuals.textColorToken) styleParts.push(textColorStyle(visuals.textColorToken));
112963
+ const foreground = visuals.textColorOverride ?? (visuals.textColorToken ? rgbColorValue(visuals.textColorToken) : null);
112964
+ if (!visuals.isTransparent && foreground) styleParts.push(surfaceForegroundStyle({ text: foreground }));
112965
+ else if (foreground) styleParts.push({ color: foreground });
112259
112966
  styleParts.push(borderColorStyle("border"));
112260
112967
  return mergeStyles(...styleParts);
112261
112968
  }
@@ -112341,18 +113048,16 @@ const footerBottomBarStyleTransform = {
112341
113048
  const styleParts = [];
112342
113049
  const background = bottomBar?.background;
112343
113050
  if (background?.type === "color") styleParts.push(backgroundColorStyle(background.color ?? "surface"));
112344
- if (bottomBar?.textColor) styleParts.push(textColorStyle(bottomBar.textColor));
112345
113051
  const borderColorToken = bottomBar?.borderTop?.colorToken;
112346
113052
  if (borderColorToken) styleParts.push(borderColorStyle(borderColorToken));
112347
113053
  else styleParts.push(borderColorStyle("border"));
112348
113054
  const borderWidth = bottomBar?.borderTop?.width;
112349
113055
  if (borderWidth && borderWidth !== "none") styleParts.push({ borderTopWidth: borderWidth === "thin" ? "1px" : borderWidth === "medium" ? "2px" : "3px" });
112350
113056
  else if (borderWidth === "none") styleParts.push({ borderTopWidth: "0px" });
112351
- if (!bottomBar?.textColor) {
112352
- const visuals = resolveBackgroundVisualStyles(extractBackgroundColorToken(background, "surface"), context.theme);
112353
- if (visuals.textColorOverride) styleParts.push({ color: visuals.textColorOverride });
112354
- else if (visuals.textColorToken) styleParts.push(textColorStyle(visuals.textColorToken));
112355
- }
113057
+ const visuals = resolveBackgroundVisualStyles(extractBackgroundColorToken(background, "surface"), context.theme);
113058
+ const foreground = bottomBar?.textColor ? rgbColorValue(bottomBar.textColor) : visuals.textColorOverride ?? (visuals.textColorToken ? rgbColorValue(visuals.textColorToken) : null);
113059
+ if (background?.type === "color" && foreground) styleParts.push(surfaceForegroundStyle({ text: foreground }));
113060
+ else if (foreground && bottomBar?.textColor) styleParts.push({ color: foreground });
112356
113061
  return mergeStyles(...styleParts);
112357
113062
  }
112358
113063
  };
@@ -112487,6 +113192,7 @@ const layoutTransforms = [
112487
113192
  headerLogoClassTransform,
112488
113193
  headerLogoMediaClassTransform,
112489
113194
  headerLogoTextVisibleTransform,
113195
+ classicNavModeTransform,
112490
113196
  footerRootClassTransform,
112491
113197
  headerRootStyleTransform,
112492
113198
  headerSectionBackgroundTransform,
@@ -112859,7 +113565,18 @@ const classicLayout = inline({
112859
113565
  logoRow,
112860
113566
  createNavRow(`rb-ml-auto ${desktopOnlyDisplay("flex")} rb-gap-6`),
112861
113567
  headerCta
112862
- ], when("$root.theme.header.variant", { equals: "classic" }));
113568
+ ], whenTransformed$1("$root.theme.header", "layout.classicNavMode", "inline"));
113569
+ const classicCenteredNavLayout = inline({
113570
+ className: bindProp("$root.theme.header.maxWidth", {
113571
+ transforms: pipe(tx("layout.maxWidthClass", { base: `rb-header-layout ${desktopOnlyDisplay("flex")} rb-w-full rb-items-center rb-gap-6` })),
113572
+ fallback: `rb-container rb-header-layout ${desktopOnlyDisplay("flex")} rb-w-full rb-items-center rb-gap-6`
113573
+ }),
113574
+ align: "center"
113575
+ }, [
113576
+ logoRow,
113577
+ createNavRow(`rb-flex-1 rb-justify-center ${desktopOnlyDisplay("flex")} rb-gap-6`, "center"),
113578
+ headerCta
113579
+ ], whenTransformed$1("$root.theme.header", "layout.classicNavMode", "centered"));
112863
113580
  const centeredLayout = stack({
112864
113581
  gap: "md",
112865
113582
  align: "center",
@@ -112934,6 +113651,7 @@ const siteHeaderManifest = createBlockManifest({
112934
113651
  }, [
112935
113652
  mobileHeaderBar,
112936
113653
  classicLayout,
113654
+ classicCenteredNavLayout,
112937
113655
  centeredLayout,
112938
113656
  transparentLayout,
112939
113657
  floatingLayout,
@@ -113143,7 +113861,7 @@ const footerLayout = section({
113143
113861
  style: { $bind: {
113144
113862
  from: "$root.theme.footer",
113145
113863
  transforms: [{ id: "layout.footerRootStyle" }],
113146
- fallback: mergeStyles(backgroundColorStyle("surface"), textColorStyle("text"), borderColorStyle("border"))
113864
+ fallback: mergeStyles(backgroundColorStyle("surface"), surfaceForegroundStyle({ text: "rgb(var(--tb-text))" }), borderColorStyle("border"))
113147
113865
  } }
113148
113866
  }, [
113149
113867
  simpleFooterLayout,
@@ -113198,7 +113916,7 @@ const backgroundImageClassName = "rb-absolute rb-inset-0 rb-z-neg-10 rb-h-full r
113198
113916
  */
113199
113917
  const wrapVariant$2 = (variantLayout) => styledSection({
113200
113918
  children: styledContainer({ children: stack({
113201
- gap: "xl",
113919
+ gap: "lg",
113202
113920
  className: "rb-relative"
113203
113921
  }, [...testimonialsHeadingFragment.layout, variantLayout]) }),
113204
113922
  baseClass: "",
@@ -113224,6 +113942,26 @@ const splitGridLayout = styledSection({
113224
113942
  spacing: "comfortable",
113225
113943
  imageClassName: backgroundImageClassName
113226
113944
  });
113945
+ const featuredEditorialLayout = styledSection({
113946
+ children: styledContainer({
113947
+ baseClassName: "rb-relative rb-isolate",
113948
+ children: stack({
113949
+ gap: "lg",
113950
+ className: "rb-relative"
113951
+ }, [el("div", { className: "rb-testimonials-fe-head" }, [text({
113952
+ as: "h2",
113953
+ className: "rb-text-left",
113954
+ headingDecoration: "off"
113955
+ }, when("content.heading"), bind$1("content.heading")), el("div", { className: "rb-testimonials-fe-leadin" }, [text({
113956
+ as: "p",
113957
+ className: "rb-prose",
113958
+ style: textColorStyle("mutedText")
113959
+ }, when("content.subheading"), bind$1("content.subheading"))])]), buildFeaturedEditorialLayout()])
113960
+ }),
113961
+ baseClass: "",
113962
+ spacing: "comfortable",
113963
+ imageClassName: backgroundImageClassName
113964
+ });
113227
113965
  const additionalFields = parseFieldDefinitions([
113228
113966
  ...testimonialsHeadingFragment.fields,
113229
113967
  {
@@ -113311,6 +114049,7 @@ const testimonialsBlockDefinition = {
113311
114049
  carousel: carouselLayout$1,
113312
114050
  grid: gridLayout$1,
113313
114051
  "split-grid": splitGridLayout,
114052
+ "featured-editorial": featuredEditorialLayout,
113314
114053
  highlight: highlightLayout
113315
114054
  },
113316
114055
  defaultVariant: "carousel",
@@ -113330,6 +114069,11 @@ const testimonialsBlockDefinition = {
113330
114069
  description: "Heading on the left with testimonial cards on the right",
113331
114070
  icon: "PanelLeft"
113332
114071
  },
114072
+ "featured-editorial": {
114073
+ label: "Featured editorial",
114074
+ description: "A large featured ink quote beside a column of stacked cards (no avatars)",
114075
+ icon: "Quote"
114076
+ },
113333
114077
  highlight: {
113334
114078
  label: "Highlight",
113335
114079
  description: "A single, centered testimonial with no carousel",
@@ -113789,7 +114533,7 @@ function grid$2(props, children) {
113789
114533
  const cardsLayout = styledSection({
113790
114534
  children: styledContainer({
113791
114535
  rootType: "stack",
113792
- rootProps: { gap: "xl" },
114536
+ rootProps: { gap: "lg" },
113793
114537
  children: [stack({
113794
114538
  gap: "sm",
113795
114539
  className: "rb-feature-cards-heading rb-mx-auto rb-max-w-3xl rb-text-center"
@@ -118382,6 +119126,12 @@ const systemBlockDefinitions = [
118382
119126
  family: "centered",
118383
119127
  weight: "featured",
118384
119128
  bias: "soft"
119129
+ }),
119130
+ layoutProfile({
119131
+ variantKey: "featured-editorial",
119132
+ family: "split",
119133
+ weight: "featured",
119134
+ bias: "soft"
118385
119135
  })
118386
119136
  ]
118387
119137
  })),
@@ -118514,6 +119264,11 @@ const systemBlockDefinitions = [
118514
119264
  variantKey: "timetable",
118515
119265
  family: "stack",
118516
119266
  weight: "standard"
119267
+ }),
119268
+ layoutProfile({
119269
+ variantKey: "week-board",
119270
+ family: "stack",
119271
+ weight: "standard"
118517
119272
  })
118518
119273
  ]
118519
119274
  })),
@@ -118888,7 +119643,15 @@ function gradientToCss(config, tokens) {
118888
119643
  const stops = config.stops.map((stop) => {
118889
119644
  return `${tokens[stop.color] ?? "#000000"} ${stop.position}%`;
118890
119645
  }).join(", ");
118891
- if (config.type === "radial") return `radial-gradient(circle at ${config.position ?? "center"}, ${stops})`;
119646
+ const type = config.type ?? "linear";
119647
+ if (type === "radial") {
119648
+ const position = config.position ?? "center";
119649
+ return `radial-gradient(${config.shape ?? "circle"} at ${position}, ${stops})`;
119650
+ }
119651
+ if (type === "conic") {
119652
+ const position = config.position ?? "center";
119653
+ return `conic-gradient(from ${config.angle ?? 0}deg at ${position}, ${stops})`;
119654
+ }
118892
119655
  return `linear-gradient(${config.angle ?? 180}deg, ${stops})`;
118893
119656
  }
118894
119657
  //#endregion
@@ -133771,7 +134534,7 @@ function readInlineTextSurface(editable, toolbarTone) {
133771
134534
  function readThemeFallbackSurface(root) {
133772
134535
  const themeScope = root.closest(".theme-scope") ?? root;
133773
134536
  const computed = window.getComputedStyle(themeScope);
133774
- const color = readRgbTripletCustomProperty(computed, "--section-bg-color") ?? readRgbTripletCustomProperty(computed, "--tb-background") ?? readRgbTripletCustomProperty(computed, "--tb-surface");
134537
+ const color = readRgbTripletCustomProperty(computed, "--tb-background") ?? readRgbTripletCustomProperty(computed, "--tb-surface");
133775
134538
  return color ? {
133776
134539
  kind: "theme-fallback",
133777
134540
  color: colorToCss(color),
@@ -133810,12 +134573,12 @@ function accentColorValue(tone) {
133810
134573
  switch (tone) {
133811
134574
  case "accent": return "rgb(var(--tb-accent))";
133812
134575
  case "brand": return "rgb(var(--tb-primary))";
133813
- case "contrast": return "var(--section-text-color, rgb(var(--tb-text)))";
134576
+ case "contrast": return surfaceForegroundValue("text");
133814
134577
  }
133815
134578
  }
133816
134579
  function highlightBackgroundValue(tone) {
133817
134580
  switch (tone) {
133818
- case "soft": return "color-mix(in oklab, var(--section-text-color, rgb(var(--tb-text))) 14%, transparent)";
134581
+ case "soft": return `color-mix(in oklab, ${surfaceForegroundValue("text")} 14%, transparent)`;
133819
134582
  case "accent": return "color-mix(in oklab, rgb(var(--tb-accent)) 28%, transparent)";
133820
134583
  case "brand": return "color-mix(in oklab, rgb(var(--tb-primary)) 24%, transparent)";
133821
134584
  }
@@ -158403,4 +159166,4 @@ function useSiteChromeCustomizeOptional() {
158403
159166
  return useContext(SiteChromeCustomizeContext);
158404
159167
  }
158405
159168
  //#endregion
158406
- export { PreviewRichTextEditor as $, previewStageSchema as $a, rgbColorValue as $c, Copy as $d, getFooterLayout as $i, createCollapsibleScope as $l, buildEventCalendarListingRender as $n, EDITABLE_SURFACE_FORWARDING_PROP as $o, ctaCopyFragment as $r, MailIcon as $s, deleteEntrySlotBlock as $t, formatCurrencyAmount as $u, openRow as A, normalizeOfferingsPreviewGroupOrder as Aa, isRotationDimensionSwap as Ac, Pencil as Ad, getCuratedSiteStyle as Ai, Input as Al, SITE_CHROME_VISIBLE_HEADER_SELECTOR as An, formatDate as Ao, formatCommercePrice as Ar, resolveIconPickerPreset as As, createRoutingHelpers as At, clsx as Au, setPaletteColors as B, eventPageSizeSchema as Ba, buttonPersonalities as Bc, ImageOff as Bd, NAV_LINK_LETTER_SPACING_MAP as Bi, Dialog as Bl, isInternalResolvedLinkValue as Bn, resolveEventCta as Bo, augmentManifestWithStyleGroups as Br, ChevronLeftIcon as Bs, ManifestForm as Bt, formatBookingTime as Bu, createStyleConfiguratorState as C, OFFERINGS_PREVIEW_DEFAULT_BUTTON_TEXT as Ca, resolveImageUrlWithContext as Cc, Sparkles as Cd, retargetCompiledBoundaryRuntimeForContentAdjacency as Ci, SelectTrigger as Cl, isSupportedLoaderEndpoint as Cn, resolveOnColorForThemeToken as Co, buildProductDetailInteractiveIslandProps as Cr, getGeneratedBlockIconStyleState as Cs, pushHistoryEntry as Ct, createContextScope as Cu, markApplyFailed as D, buildOfferingsPreviewRenderStates as Da, SECTION_BACKGROUND_MIN_SOURCE_WIDTH as Dc, RotateCcw as Dd, resolveVisiblePromotedFieldPathsForEditorBlock as Di, Popover as Dl, listBlockDescriptors as Dn, buildGoogleMapsDirectionsUrl as Do, buildCartDisplay as Dr, parseGeneratedIconSetId as Ds, recordsEqual as Dt, cva as Du, isPreviewingChange as E, OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS as Ea, setContextResolveImageUrlContext as Ec, Search as Ed, planPageDesignLayoutLookCompatibility as Ei, Badge as El, getBlockDefinition as En, featuresFromHex as Eo, getShopDisplayForItems as Er, parseGeneratedIconAssetId as Es, unsafeAsLinkedContentEntryId as Et, Button$1 as Eu, previewHeaderLayout as F, resolveOfferingsPreviewGroups as Fa, asRecord as Fc, Maximize2 as Fd, getComponentBorderWidthPx as Fi, Content as Fl, mediaTransforms as Fn, formatEventTeacherLine as Fo, deriveCommerceCheckoutState as Fr, ArrowLeftIcon as Fs, PaletteProvider as Ft, unsafeAsEditorBlockValues as Fu, beginAutosaveBatch as G, normalizeCsvString as Ga, generateBaseInteractiveCSS as Gc, FilePlay as Gd, INPUT_FONT_SIZE_MAP as Gi, DialogHeader as Gl, productDetailBlockDefinition as Gn, resolveRuntimeEventPricing as Go, faqHeadingFragment as Gr, ClockIcon as Gs, createStoreBackend as Gt, toBookingTimeZone as Gu, syncStyleConfiguratorState as H, resolveEventCalendarListPageSize as Ha, generateButtonCss as Hc, File as Hd, NAV_LINK_PADDING_X_MAP as Hi, DialogContent as Hl, useImageResolveContextOptional as Hn, getEventAvailability as Ho, headingFragment as Hr, ChevronUpIcon as Hs, createManifestValidation as Ht, getBookingLocalDateKey as Hu, previewHeaderStyle as I, isSemanticSpacing as Ia, getDirectImageUrlForMediaAsset as Ic, LoaderCircle as Id, getComponentShadowVar as Ii, List as Il, layoutTransforms as In, formatTime as Io, parseStoredCommerceCartState as Ir, ArrowRightIcon as Is, usePalette as It, addLocalScheduleDays as Iu, enqueueTransaction as J, columnOptionSchema as Ja, parseThemeButtonVariantId as Jc, Eye as Jd, evaluateTypographyFontSlot as Ji, CollapsibleContent as Jl, eventListingBlockDefinition as Jn, createInteractiveIslandCodec as Jo, footerBottomTextFragment as Jr, FileArchiveIcon as Js, applyPageDesignEditorAction as Jt, publicEventPricingCurrency as Ju, confirmAutosaveBatch as K, normalizeOptionalId as Ka, generateInteractiveChildInheritanceCSS as Kc, FileHeadphone as Kd, INPUT_SPACING_MAP as Ki, DialogTitle as Kl, newsletterSignupBlockDefinition as Kn, blockBookingPaymentTermsSchema as Ko, blogFeaturedPostFragment as Kr, DownloadIcon as Ks, listContentTypes as Kt, toScheduledBookingDateTime as Ku, previewSiteStyle as L, resolveSpacing as La, getImageUrl as Lc, Image as Ld, parseBlockCustomCssRules as Li, Root2$1 as Ll, uiTransforms as Ln, getCardOrientation as Lo, productItemKey as Lr, CalendarIcon as Ls, recoveryConflictCopy as Lt, formatBookingDate as Lu, previewButtonPersonality as M, resolveOfferingsPreviewCoursePath as Ma, formatAspectRatioToken as Mc, Palette as Md, isThemeV2NormalEditorRawStyleFieldName as Mi, TabsContent as Ml, planSiteOverlayHeaderClearance as Mn, formatEventDateParts as Mo, EMPTY_COMMERCE_CART_STATE as Mr, getSemanticIconComponent as Ms, deriveRouteMetadataPresentation as Mt, createEditorRemoveBlockCommand as Mu, previewCuratedPalette as N, resolveOfferingsPreviewGroupCta as Na, parseAspectRatioValue as Nc, Monitor as Nd, isThemeV2NormalEditorRawStylePath as Ni, TabsList as Nl, visibleHeaderClearancePx as Nn, formatEventPrice as No, buildPassCartItem as Nr, isSemanticIconId as Ns, resolvePageRouteSlug as Nt, createEditorReorderBlocksCommand as Nu, markApplySaved as O, inferLegacyOfferingsPreviewGroupOrder as Oa, resolveMediaSlotContract as Oc, Redo2 as Od, curatedSiteStyles as Oi, PopoverContent as Ol, siteFooterManifest as On, normalizeLocationMapProps as Oo, buildProductCardDisplay as Or, parseSiteIconStyleGuideVersionId as Os, useMultiAutosave as Ot, useComposedRefs as Ou, previewFooterLook as P, resolveOfferingsPreviewGroupOrderEntries as Pa, resolveMediaTransformForAspect as Pc, Minus as Pd, pageDesignEditorBackgroundOverrideOwner as Pi, TabsTrigger as Pl, contentTransforms as Pn, formatEventPriceDisplay as Po, buildProductCartItem as Pr, ArrowDownIcon as Ps, resolveContentTitle as Pt, unsafeAsEditorBlockId as Pu, resolvePreviewSidebarTab as Q, filterAutoShowSchema as Qa, mergeStyles as Qc, CreditCard as Qd, findFooterLook as Qi, Trigger$3 as Ql, buildEventCalendarListingDisplay as Qn, defineProgressiveBlockRuntime as Qo, testimonialsHeadingFragment as Qr, InfoIcon as Qs, deleteBlock as Qt, publicEventTicketTypes as Qu, previewTypographyPreset as R, buildEventRuntimeFilters as Ra, getAtPath as Rc, ImageUp as Rd, parseCustomCssRules as Ri, Trigger$2 as Rl, formattingTransforms as Rn, getContainerClass as Ro, reduceCommerceCart as Rr, CheckIcon as Rs, unfinishedBlockCopy as Rt, formatBookingDateTime as Ru, cancelPreview as S, ctaButton as Sa, renderVideo as Sc, Star as Sd, compileEditorModelRuntime as Si, SelectItem as Sl, useUniqueId as Sn, isCssColorLiteral as So, buildCheckoutInteractiveIslandProps as Sr, getBlockIconSemanticId as Ss, createHistoryState as St, useControllableState as Su, dismissWarnings as T, OFFERINGS_PREVIEW_DEFAULT_FAILED_MESSAGE as Ta, resolveMediaStorageUrl as Tc, Settings as Td, normalEditorCuratedPromotedFieldPaths as Ti, Label as Tl, GRADIENT_PRESETS as Tn, getTextColorForBackground as To, buildShopInteractiveIslandProps as Tr, resolveBlockIconRenderValue as Ts, undoHistory as Tt, Primitive as Tu, toggleRow as U, resolveEventListPaginationAction as Ua, generateEffectsCSS as Uc, FileText as Ud, NAV_LINK_TEXT_SIZE_MAP as Ui, DialogDescription as Ul, shopBlockDefinition as Un, getLocalDateKey as Uo, cardFragment as Ur, CircleMinusIcon as Us, FormRenderer as Ut, parseBookingLocalDate as Uu, styleConfiguratorHistoryEntryForPersistedSelection as V, getEventRuntimeFiltersKey as Va, findButtonPersonality as Vc, GripVertical as Vd, NAV_LINK_PADDING_MAP as Vi, DialogClose as Vl, ImageResolveContextProvider as Vn, resolveEventLinkProps as Vo, richTextFragment as Vr, ChevronRightIcon as Vs, createManifestFormAdapter as Vt, formatLocalScheduleDate as Vu, typographySelectionSnapshotFromFlat as W, normalizeCsvIds as Wa, generateShadowValue$1 as Wc, FileSpreadsheet as Wd, FONT_WEIGHT_MAP as Wi, DialogFooter as Wl, productListBlockDefinition as Wn, getLocalMinuteOfDay as Wo, faqAccordionFragment as Wr, CirclePlusIcon as Ws, evaluateVisibility as Wt, resolveBookingTimeZoneId as Wu, rejectAutosaveBatch as X, eventCalendarDefaultViewSchema as Xa, backgroundColorStyle as Xc, EllipsisVertical as Xd, typographyPresets as Xi, Content$1 as Xl, eventCalendarBlockDefinition as Xn, createZodCodec as Xo, formCopyFragment as Xr, FileSpreadsheetIcon as Xs, createBlock as Xt, publicEventPricingType as Xu, idleEditorTransactionQueueState as Y, eventButtonVariantSchema as Ya, themeButtonClassName as Yc, EyeOff as Yd, findTypographyPreset as Yi, CollapsibleTrigger as Yl, buildEventListingInteractiveIslandProps as Yn, defineInteractiveIslandMetaKeys as Yo, formEmbedFragment as Yr, FileAudioIcon as Ys, getPageDesignEditorState as Yt, publicEventPricingMode as Yu, createOptimisticActionRunner as Z, eventLayoutSchema as Za, borderColorStyle as Zc, Crop as Zd, requireEntriesForCuratedChoices as Zi, Root$3 as Zl, buildEventCalendarInteractiveIslandProps as Zn, defineClientOwnedBlockRuntime as Zo, testimonialsCarouselFragment as Zr, FileTextIcon as Zs, createEntrySlotBlock as Zt, publicEventScalarPrice as Zu, usePreviewDesignCoordinator as _, paletteColorsSchema as _a, MediaPlaceholder as _c, Undo2 as _d, __toESM as _f, mergeHeaderNavTypographyPreference as _i, TooltipProvider as _l, useSensors as _n, generateCardCss as _o, courseRegistrationBlockDefinition as _r, resolveFeatureCardGeneratedIconSizePx as _s, useEditorUiStore as _t, __spreadArray as _u, previewDesignHistoryDomainForCommand as a, sectionTransitionFamilyForBoundaryOptionId as aa, ShoppingCartIcon as ac, unsafeAsAppointmentServiceId as ad, ChevronsUpDown as af, PUBLIC_FILE_FIELD_KINDS as ai, isNonEmptyValue as al, DEFAULT_LAUNCH_READINESS_INPUT as an, bindingSchema as ao, findEventByOccurrenceId as ar, assertNever$6 as as, getRichTextImagePositionFromTarget as at, DropdownMenu as au, applyResolvedSelections as b, createTransformRegistry as ba, getCurrentResolveImageUrlContext as bc, Ticket as bd, PAGE_DESIGN_EDITOR_STATE_FETCH_ERROR_MESSAGE as bi, Select$1 as bl, useCombinedRefs as bn, normalizeBoxStylesCardVariant as bo, cartBlockDefinition as br, toFeatureCardIconSuggestionInputs as bs, canRedoHistory as bt, useDirection as bu, selectionSnapshotFromApplySiteStyleSelectionResponse as c, backgroundAppearanceColorTokenNames as ca, createRichTextDocFromMarkdown as cc, unsafeAsMediaAssetId as cd, ChevronLeft as cf, MQ_MD_DOWN as ci, useSdkConfig as cl, DndContext as cn, eventSurfaceScopeValues as co, resolveEventRequiresPayment as cr, ACCORDION_TRIGGER_FONT_SCALE as cs, EditorProvider as ct, DropdownMenuLabel as cu, buildSiteChromeLookModels as d, parseBackgroundAppearanceColorToken as da, isRecord$11 as dc, unsafeAsPositiveSeconds as dd, Box as df, MQ_TABLET_ONLY as di, mapOptionValueForSelect as dl, closestCenter as dn, normalizeEventScheduleScope as do, getStepNumber as dr, ICON_SIZE_PX as ds, useUISelector as dt, __assign as du, getHeaderLayout as ea, MapPinIcon as ec, assertNever$7 as ed, Clock3 as ef, heroCtaRowFragment as ei, textColorStyle as el, listEntryPageContentSlots as en, weekStartSchema as eo, formBlockDefinition as er, composeHeaderSectionWrapperClassName as es, PreviewInlineTextEditor as et, Card as eu, cycleSiteChromeLookId as f, defaultThemeTokens as fa, coerceInlineTextWithFallback as fc, err as fd, ArrowUp as ff, BACKGROUND_POSITION_PRESET_VALUES as fi, unmapValueFromSelect as fl, getClientRect as fn, normalizeEventStaffMemberId as fo, getWizardStepsForContext as fr, PUBLIC_DOWNLOAD_MEDIA_TYPES as fs, EditableBlockProvider as ft, __awaiter as fu, PreviewDesignCoordinatorProvider as g, paletteColorsEqual as ga, ImagePresets as gc, Upload as gd, __exportAll as gf, resolveBackgroundColorValue as gi, TooltipContent as gl, useSensor as gn, publicEventSchema as go, buildGiftingInteractiveIslandProps as gr, getFeatureCardIconCompletion as gs, classifyHistoryShortcut as gt, __rest as gu, planSiteChromeLookSelection as h, paletteColorEntries as ha, parseInlineTextFromUnknown as hc, X as hd, __commonJSMin as hf, resolveSectionForegroundStyles as hi, Tooltip as hl, useDroppable as hn, normalizeEventVenueId as ho, giftingBlockDefinition as hr, createFeatureCardIconKey as hs, useEntryEditorController as ht, __read as hu, usePreviewDesignHistoryOrder as i, sectionTransitionFamilies as ia, PlusIcon as ic, unsafeAsAppointmentResourceId as id, CircleAlert as if, defineFragment as ii, isHeaderField as il, decodePublicProductCategorySelectorQuery as in, when as io, toRegistrationEvents as ir, asDesignBlockId as is, RichTextEditorSurface as it, Surface as iu, paletteMutationCapability as j, normalizeOfferingsPreviewItemLimit as ja, normalizeRightAngle as jc, PenLine as jd, surfaceResolutionContextFromTheme as ji, Tabs as jl, SITE_OVERLAY_HEADER_CLEARANCE_CSS_VAR as jn, formatEventCompactDateRail as jo, formatInterval as jr, SEMANTIC_ICON_DEFINITIONS as js, createSnapshotFromPageRecord as jt, createEditorInsertBlockCommand as ju, markApplySaving as k, isOfferingsPreviewSourceKey as ka, attachRenderableMediaAssetFields as kc, Plus as kd, designRuntimeRulesForTheme as ki, PopoverTrigger as kl, siteHeaderManifest as kn, toLocationMapHydrationProps as ko, buildProductDetailDisplay as kr, isIconPickerPreset as ks, useDebouncedLatestSave as kt, cn$1 as ku, planSiteStylePreviewChange as l, backgroundAppearanceQuickColorTokenNames as la, unwrapRichTextRoot as lc, unsafeAsPassId as ld, ChevronDown as lf, MQ_SM_DOWN as li, hasEmptyOption as ll, KeyboardCode as ln, normalizeEventBlockKind as lo, resolveRegistrationTarget as lr, ACCORDION_TRIGGER_LETTER_SPACING as ls, useEditor$1 as lt, DropdownMenuSeparator as lu, planSiteChromeFooterLayoutSelection as m, findCuratedPalette as ma, isInlineTextEmpty as mc, lucide_react_exports as md, Archive as mf, boxStylesTransforms as mi, useField as ml, useDraggable as mn, normalizeEventSurfaceScope as mo, resolveEventRegistrationScopedEvents as mr, FEATURE_CARD_ICON_TREATMENTS as ms, useEntryController as mt, __generator as mu, useSiteChromeCustomizeOptional as n, boundaryRuntimeMetricsForTransition as na, PhoneIcon as nc, parseMediaAssetId as nd, CircleMinus as nf, heroCopyFragment as ni, getFieldIntent as nl, reorderBlocks as nn, eventCalendarListLayoutOptions as no, eventRegistrationBlockDefinition as nr, splitPositioningClasses as ns, useRichTextEditor as nt, CardHeader as nu, selectPreviewDesignHistoryDomain as o, sectionTransitionVariantForBoundaryOptionId as oa, UploadIcon as oc, unsafeAsCustomerPassId as od, ChevronUp as of, siteOptionSources as oi, useBlockContext as ol, deriveLaunchReadiness as on, eventBlockKindValues as oo, findPreSelectedEvent as or, ACCORDION_OPEN_ACCENT_THICKNESS as os, insertOrReplaceRichTextImage as ot, DropdownMenuContent as ou, cycleableSiteChromeOptions as p, curatedPalettes as pa, inlineTextToPlainText as pc, ok as pd, ArrowDown as pf, getAnchorClasses as pi, FieldFrame as pl, useDndContext as pn, normalizeEventSurfacePresetsCsv as po, normalizeEventRegistrationPageSurfaceSubject as pr, mediaSchema$1 as ps, EntryControllerProvider as pt, __extends as pu, deriveTransactionCapabilities as q, calendarTabViewsSchema as qa, TokenResolver as qc, FileArchive as qd, LABEL_FONT_SIZE_MAP as qi, Collapsible as ql, buildNewsletterFormInteractiveIslandProps as qn, buildInteractiveIslandProps as qo, singleButtonFragment as qr, ExternalLinkIcon as qs, toRoutableLinkPayload as qt, formatBookingPriceDisplay as qu, PreviewDesignHistoryOrderProvider as r, defaultSectionTransitionVariantForFamily as ra, PlayIcon as rc, parseSiteId as rd, CircleCheck as rf, bodyCopyFragment as ri, getModalConfig as rl, reorderEntrySlotBlocks as rn, el as ro, buildEventRegistrationInteractiveIslandProps as rr, planSiteChromePlacement as rs, EMPTY_DOC as rt, CardTitle as ru, buildApplySiteStyleSelectionBody as s, BACKGROUND_BODY_TEXT_MIN_CONTRAST_RATIO as sa, XIcon as sc, unsafeAsFormId as sd, ChevronRight as sf, MQ_LG_UP as si, SdkConfigProvider as sl, AMBIENT_BACKGROUND_ROLES as sn, eventScheduleScopeValues as so, resolveDiscountContext as sr, ACCORDION_SPACING_MAP as ss, InlineTextEditor as st, DropdownMenuItem as su, SiteChromeCustomizeProvider as t, getHeaderStyle as ta, MinusIcon as tc, expectParsedBrandedId as td, CirclePlus as tf, ctaRowFragment as ti, useBackendWatch as tl, mutateBlockContent as tn, eventCalendarListLayoutCompatibleDisplayModeValues as to, buildFormInteractiveIslandProps as tr, markEditableSurfaceForwarding as ts, PreviewTextEditor as tt, CardContent as tu, resolveStyleConfiguratorInitialSnapshot as u, foregroundTokenForBackgroundAppearanceColorToken as ua, isObjectRecord$1 as uc, unsafeAsPositiveByteCount as ud, Check as uf, MQ_SM_UP as ui, mapCurrentValueForSelect as ul, PointerSensor as un, normalizeEventCategoryIdsCsv as uo, WIZARD_STEPS as ur, ICON_CONFIG as us, ContentFieldsForm as ut, DropdownMenuTrigger as uu, PreviewThemeOverlayProvider as v, expandPalette as va, buildResolveImageUrlContext as vc, TriangleAlert as vd, readHeaderNavFontSizePreference as vi, TooltipTrigger as vl, CSS$1 as vn, statusMutedColorDeclaration as vo, buildCourseRegistrationInteractiveIslandProps as vr, shouldReserveFeatureCardIconZone as vs, useEditorUiStoreInstance as vt, __spreadArrays as vu, deriveStyleConfiguratorCapabilities as w, OFFERINGS_PREVIEW_DEFAULT_EMPTY_MESSAGE as wa, resolveMediaNodeResponsiveImage as wc, Smartphone as wd, retargetCompiledRuntimeFieldsForContentAdjacency as wi, SelectValue as wl, gradientToCss as wn, resolveTokenOrCssColorValue as wo, buildProductListInteractiveIslandProps as wr, parseBlockIconValue as ws, redoHistory as wt, composeEventHandlers as wu, applyTypographyDraftPatch as x, runTransforms as xa, renderAudio as xc, Tablet as xd, applyCompiledRuntimeFieldsToContent as xi, SelectContent as xl, useIsomorphicLayoutEffect$1 as xn, normalizeCardVariantRole as xo, buildCartInteractiveIslandProps as xr, buildGeneratedBlockIconRenderAssetLookupFromUnknown as xs, canUndoHistory as xt, createCollection as xu, usePreviewThemeOverlay as y, generateCssVars as ya, computeMediaTransformStyle as yc, Trash2 as yd, formatSiteChromeBackgroundTokenLabel as yi, Textarea as yl, isKeyboardEvent as yn, generateShadowValue as yo, checkoutBlockDefinition as yr, suggestSemanticIconForFeatureCard as ys, useOptionalEditorUiStoreInstance as yt, useId$1 as yu, resetTypographyToSaved as z, eventListPaginationActionSchema as za, siblingPath as zc, ImagePlus as zd, NAV_LINK_BORDER_RADIUS_MAP as zi, ScrollableDialogContent as zl, createManifestValidator as zn, groupEventsByDate as zo, augmentManifest as zr, ChevronDownIcon as zs, validateBlockManifestIssues as zt, formatBookingInstant as zu };
159169
+ export { PreviewRichTextEditor as $, previewStageSchema as $a, cssVarValue as $c, Eye as $d, getFooterLayout as $i, CollapsibleContent as $l, buildEventCalendarListingRender as $n, EDITABLE_SURFACE_FORWARDING_PROP as $o, ctaCopyFragment as $r, ClockIcon as $s, deleteEntrySlotBlock as $t, publicEventPricingCurrency as $u, openRow as A, normalizeOfferingsPreviewGroupOrder as Aa, isRotationDimensionSwap as Ac, Settings as Ad, getCuratedSiteStyle as Ai, Label as Al, SITE_CHROME_VISIBLE_HEADER_SELECTOR as An, formatEventCompactDateRail as Ao, formatCommercePrice as Ar, unwrapRichTextRoot as As, createRoutingHelpers as At, Primitive as Au, setPaletteColors as B, eventPageSizeSchema as Ba, buttonPersonalities as Bc, Maximize2 as Bd, NAV_LINK_LETTER_SPACING_MAP as Bi, Content as Bl, isInternalResolvedLinkValue as Bn, resolveEventLinkProps as Bo, augmentManifestWithStyleGroups as Br, getSemanticIconComponent as Bs, ManifestForm as Bt, unsafeAsEditorBlockValues as Bu, createStyleConfiguratorState as C, OFFERINGS_PREVIEW_DEFAULT_BUTTON_TEXT as Ca, resolveImageUrlWithContext as Cc, TriangleAlert as Cd, retargetCompiledBoundaryRuntimeForContentAdjacency as Ci, TooltipTrigger as Cl, isSupportedLoaderEndpoint as Cn, resolveTokenOrCssColorValue as Co, buildProductDetailInteractiveIslandProps as Cr, getGeneratedBlockIconStyleState as Cs, pushHistoryEntry as Ct, __spreadArrays as Cu, markApplyFailed as D, buildOfferingsPreviewRenderStates as Da, SECTION_BACKGROUND_MIN_SOURCE_WIDTH as Dc, Star as Dd, resolveVisiblePromotedFieldPathsForEditorBlock as Di, SelectItem as Dl, listBlockDescriptors as Dn, normalizeLocationMapProps as Do, buildCartDisplay as Dr, parseGeneratedIconSetId as Ds, recordsEqual as Dt, useControllableState as Du, isPreviewingChange as E, OFFERINGS_PREVIEW_EVENT_PRESET_DEFINITIONS as Ea, setContextResolveImageUrlContext as Ec, Tablet as Ed, planPageDesignLayoutLookCompatibility as Ei, SelectContent as El, getBlockDefinition as En, buildGoogleMapsDirectionsUrl as Eo, getShopDisplayForItems as Er, parseGeneratedIconAssetId as Es, unsafeAsLinkedContentEntryId as Et, createCollection as Eu, previewHeaderLayout as F, resolveOfferingsPreviewGroups as Fa, asRecord as Fc, Pencil as Fd, getComponentBorderWidthPx as Fi, Input as Fl, mediaTransforms as Fn, formatTime as Fo, deriveCommerceCheckoutState as Fr, isInlineTextEmpty as Fs, PaletteProvider as Ft, clsx as Fu, beginAutosaveBatch as G, normalizeCsvString as Ga, generateShadowValue$1 as Gc, ImageOff as Gd, INPUT_FONT_SIZE_MAP as Gi, Dialog as Gl, productDetailBlockDefinition as Gn, resolveRuntimeEventPricing as Go, faqHeadingFragment as Gr, CalendarIcon as Gs, createStoreBackend as Gt, formatBookingTime as Gu, syncStyleConfiguratorState as H, resolveEventCalendarListPageSize as Ha, AFFORDANCE_SUPPRESS_CLASS as Hc, Image as Hd, NAV_LINK_PADDING_X_MAP as Hi, Root2$1 as Hl, useImageResolveContextOptional as Hn, getEventAvailabilityStatus as Ho, headingFragment as Hr, ArrowDownIcon as Hs, createManifestValidation as Ht, formatBookingDate as Hu, previewHeaderStyle as I, isSemanticSpacing as Ia, getDirectImageUrlForMediaAsset as Ic, PenLine as Id, getComponentShadowVar as Ii, Tabs as Il, layoutTransforms as In, getCardOrientation as Io, parseStoredCommerceCartState as Ir, parseInlineTextFromUnknown as Is, usePalette as It, createEditorInsertBlockCommand as Iu, enqueueTransaction as J, columnOptionSchema as Ja, TokenResolver as Jc, FileText as Jd, evaluateTypographyFontSlot as Ji, DialogDescription as Jl, eventListingBlockDefinition as Jn, createInteractiveIslandCodec as Jo, footerBottomTextFragment as Jr, ChevronLeftIcon as Js, applyPageDesignEditorAction as Jt, parseBookingLocalDate as Ju, confirmAutosaveBatch as K, normalizeOptionalId as Ka, generateBaseInteractiveCSS as Kc, GripVertical as Kd, INPUT_SPACING_MAP as Ki, DialogClose as Kl, newsletterSignupBlockDefinition as Kn, blockBookingPaymentTermsSchema as Ko, blogFeaturedPostFragment as Kr, CheckIcon as Ks, listContentTypes as Kt, formatLocalScheduleDate as Ku, previewSiteStyle as L, resolveSpacing as La, getImageUrl as Lc, Palette as Ld, parseBlockCustomCssRules as Li, TabsContent as Ll, uiTransforms as Ln, getContainerClass as Lo, productItemKey as Lr, isIconPickerPreset as Ls, recoveryConflictCopy as Lt, createEditorRemoveBlockCommand as Lu, previewButtonPersonality as M, resolveOfferingsPreviewCoursePath as Ma, formatAspectRatioToken as Mc, RotateCcw as Md, isThemeV2NormalEditorRawStyleFieldName as Mi, Popover as Ml, planSiteOverlayHeaderClearance as Mn, formatEventPrice as Mo, EMPTY_COMMERCE_CART_STATE as Mr, isRecord$11 as Ms, deriveRouteMetadataPresentation as Mt, cva as Mu, previewCuratedPalette as N, resolveOfferingsPreviewGroupCta as Na, parseAspectRatioValue as Nc, Redo2 as Nd, isThemeV2NormalEditorRawStylePath as Ni, PopoverContent as Nl, visibleHeaderClearancePx as Nn, formatEventPriceDisplay as No, buildPassCartItem as Nr, coerceInlineTextWithFallback as Ns, resolvePageRouteSlug as Nt, useComposedRefs as Nu, markApplySaved as O, inferLegacyOfferingsPreviewGroupOrder as Oa, resolveMediaSlotContract as Oc, Sparkles as Od, curatedSiteStyles as Oi, SelectTrigger as Ol, siteFooterManifest as On, toLocationMapHydrationProps as Oo, buildProductCardDisplay as Or, parseSiteIconStyleGuideVersionId as Os, useMultiAutosave as Ot, createContextScope as Ou, previewFooterLook as P, resolveOfferingsPreviewGroupOrderEntries as Pa, resolveMediaTransformForAspect as Pc, Plus as Pd, pageDesignEditorBackgroundOverrideOwner as Pi, PopoverTrigger as Pl, contentTransforms as Pn, formatEventTeacherLine as Po, buildProductCartItem as Pr, inlineTextToPlainText as Ps, resolveContentTitle as Pt, cn$1 as Pu, resolvePreviewSidebarTab as Q, filterAutoShowSchema as Qa, borderColorStyle as Qc, FileArchive as Qd, findFooterLook as Qi, Collapsible as Ql, buildEventCalendarListingDisplay as Qn, defineProgressiveBlockRuntime as Qo, testimonialsHeadingFragment as Qr, CirclePlusIcon as Qs, deleteBlock as Qt, formatBookingPriceDisplay as Qu, previewTypographyPreset as R, buildEventRuntimeFilters as Ra, getAtPath as Rc, Monitor as Rd, parseCustomCssRules as Ri, TabsList as Rl, formattingTransforms as Rn, groupEventsByDate as Ro, reduceCommerceCart as Rr, resolveIconPickerPreset as Rs, unfinishedBlockCopy as Rt, createEditorReorderBlocksCommand as Ru, cancelPreview as S, ctaButton as Sa, renderVideo as Sc, Undo2 as Sd, __toESM as Sf, compileEditorModelRuntime as Si, TooltipProvider as Sl, useUniqueId as Sn, resolveOnColorForThemeToken as So, buildCheckoutInteractiveIslandProps as Sr, getBlockIconSemanticId as Ss, createHistoryState as St, __spreadArray as Su, dismissWarnings as T, OFFERINGS_PREVIEW_DEFAULT_FAILED_MESSAGE as Ta, resolveMediaStorageUrl as Tc, Ticket as Td, normalEditorCuratedPromotedFieldPaths as Ti, Select$1 as Tl, GRADIENT_PRESETS as Tn, featuresFromHex as To, buildShopInteractiveIslandProps as Tr, resolveBlockIconRenderValue as Ts, undoHistory as Tt, useDirection as Tu, toggleRow as U, resolveEventListPaginationAction as Ua, generateButtonCss as Uc, ImageUp as Ud, NAV_LINK_TEXT_SIZE_MAP as Ui, Trigger$2 as Ul, shopBlockDefinition as Un, getLocalDateKey as Uo, cardFragment as Ur, ArrowLeftIcon as Us, FormRenderer as Ut, formatBookingDateTime as Uu, styleConfiguratorHistoryEntryForPersistedSelection as V, getEventRuntimeFiltersKey as Va, findButtonPersonality as Vc, LoaderCircle as Vd, NAV_LINK_PADDING_MAP as Vi, List as Vl, ImageResolveContextProvider as Vn, getEventAvailability as Vo, richTextFragment as Vr, isSemanticIconId as Vs, createManifestFormAdapter as Vt, addLocalScheduleDays as Vu, typographySelectionSnapshotFromFlat as W, normalizeCsvIds as Wa, generateEffectsCSS as Wc, ImagePlus as Wd, FONT_WEIGHT_MAP as Wi, ScrollableDialogContent as Wl, productListBlockDefinition as Wn, getLocalMinuteOfDay as Wo, faqAccordionFragment as Wr, ArrowRightIcon as Ws, evaluateVisibility as Wt, formatBookingInstant as Wu, rejectAutosaveBatch as X, eventCalendarDefaultViewSchema as Xa, themeButtonClassName as Xc, FilePlay as Xd, typographyPresets as Xi, DialogHeader as Xl, eventCalendarBlockDefinition as Xn, createZodCodec as Xo, formCopyFragment as Xr, ChevronUpIcon as Xs, createBlock as Xt, toBookingTimeZone as Xu, idleEditorTransactionQueueState as Y, eventButtonVariantSchema as Ya, parseThemeButtonVariantId as Yc, FileSpreadsheet as Yd, findTypographyPreset as Yi, DialogFooter as Yl, buildEventListingInteractiveIslandProps as Yn, defineInteractiveIslandMetaKeys as Yo, formEmbedFragment as Yr, ChevronRightIcon as Ys, getPageDesignEditorState as Yt, resolveBookingTimeZoneId as Yu, createOptimisticActionRunner as Z, eventLayoutSchema as Za, backgroundColorStyle as Zc, FileHeadphone as Zd, requireEntriesForCuratedChoices as Zi, DialogTitle as Zl, buildEventCalendarInteractiveIslandProps as Zn, defineClientOwnedBlockRuntime as Zo, testimonialsCarouselFragment as Zr, CircleMinusIcon as Zs, createEntrySlotBlock as Zt, toScheduledBookingDateTime as Zu, usePreviewDesignCoordinator as _, paletteColorsSchema as _a, MediaPlaceholder as _c, err as _d, ArrowUp as _f, mergeHeaderNavTypographyPreference as _i, unmapValueFromSelect as _l, useSensors as _n, generateCardCss as _o, courseRegistrationBlockDefinition as _r, resolveFeatureCardGeneratedIconSizePx as _s, useEditorUiStore as _t, __awaiter as _u, previewDesignHistoryDomainForCommand as a, sectionTransitionFamilyForBoundaryOptionId as aa, FileTextIcon as ac, assertNever$7 as ad, Clock3 as af, PUBLIC_FILE_FIELD_KINDS as ai, surfaceForegroundValue as al, DEFAULT_LAUNCH_READINESS_INPUT as an, bindingSchema as ao, findEventByOccurrenceId as ar, assertNever$6 as as, getRichTextImagePositionFromTarget as at, Card as au, applyResolvedSelections as b, createTransformRegistry as ba, getCurrentResolveImageUrlContext as bc, X as bd, __commonJSMin as bf, PAGE_DESIGN_EDITOR_STATE_FETCH_ERROR_MESSAGE as bi, Tooltip as bl, useCombinedRefs as bn, normalizeCardVariantRole as bo, cartBlockDefinition as br, toFeatureCardIconSuggestionInputs as bs, canRedoHistory as bt, __read as bu, selectionSnapshotFromApplySiteStyleSelectionResponse as c, backgroundAppearanceColorTokenNames as ca, MapPinIcon as cc, parseSiteId as cd, CircleCheck as cf, MQ_MD_DOWN as ci, getModalConfig as cl, DndContext as cn, eventSurfaceScopeValues as co, resolveEventRequiresPayment as cr, ACCORDION_TRIGGER_FONT_SCALE as cs, EditorProvider as ct, CardTitle as cu, buildSiteChromeLookModels as d, parseBackgroundAppearanceColorToken as da, PlayIcon as dc, unsafeAsCustomerPassId as dd, ChevronUp as df, MQ_TABLET_ONLY as di, useBlockContext as dl, closestCenter as dn, normalizeEventScheduleScope as do, getStepNumber as dr, ICON_SIZE_PX as ds, useUISelector as dt, DropdownMenuContent as du, getHeaderLayout as ea, DownloadIcon as ec, publicEventPricingMode as ed, EyeOff as ef, heroCtaRowFragment as ei, mergeStyles as el, listEntryPageContentSlots as en, weekStartSchema as eo, formBlockDefinition as er, composeHeaderSectionWrapperClassName as es, PreviewInlineTextEditor as et, CollapsibleTrigger as eu, cycleSiteChromeLookId as f, defaultThemeTokens as fa, PlusIcon as fc, unsafeAsFormId as fd, ChevronRight as ff, BACKGROUND_POSITION_PRESET_VALUES as fi, SdkConfigProvider as fl, getClientRect as fn, normalizeEventStaffMemberId as fo, getWizardStepsForContext as fr, PUBLIC_DOWNLOAD_MEDIA_TYPES as fs, EditableBlockProvider as ft, DropdownMenuItem as fu, PreviewDesignCoordinatorProvider as g, paletteColorsEqual as ga, ImagePresets as gc, unsafeAsPositiveSeconds as gd, Box as gf, resolveBackgroundColorValue as gi, mapOptionValueForSelect as gl, useSensor as gn, publicEventSchema as go, buildGiftingInteractiveIslandProps as gr, getFeatureCardIconCompletion as gs, classifyHistoryShortcut as gt, __assign as gu, planSiteChromeLookSelection as h, paletteColorEntries as ha, XIcon as hc, unsafeAsPositiveByteCount as hd, Check as hf, resolveSurfaceForegroundStyles as hi, mapCurrentValueForSelect as hl, useDroppable as hn, normalizeEventVenueId as ho, giftingBlockDefinition as hr, createFeatureCardIconKey as hs, useEntryEditorController as ht, DropdownMenuTrigger as hu, usePreviewDesignHistoryOrder as i, sectionTransitionFamilies as ia, FileSpreadsheetIcon as ic, formatCurrencyAmount as id, Copy as if, defineFragment as ii, surfaceForegroundDeclarations as il, decodePublicProductCategorySelectorQuery as in, when as io, toRegistrationEvents as ir, asDesignBlockId as is, RichTextEditorSurface as it, createCollapsibleScope as iu, paletteMutationCapability as j, normalizeOfferingsPreviewItemLimit as ja, normalizeRightAngle as jc, Search as jd, surfaceResolutionContextFromTheme as ji, Badge as jl, SITE_OVERLAY_HEADER_CLEARANCE_CSS_VAR as jn, formatEventDateParts as jo, formatInterval as jr, isObjectRecord$1 as js, createSnapshotFromPageRecord as jt, Button$1 as ju, markApplySaving as k, isOfferingsPreviewSourceKey as ka, attachRenderableMediaAssetFields as kc, Smartphone as kd, designRuntimeRulesForTheme as ki, SelectValue as kl, siteHeaderManifest as kn, formatDate as ko, buildProductDetailDisplay as kr, createRichTextDocFromMarkdown as ks, useDebouncedLatestSave as kt, composeEventHandlers as ku, planSiteStylePreviewChange as l, backgroundAppearanceQuickColorTokenNames as la, MinusIcon as lc, unsafeAsAppointmentResourceId as ld, CircleAlert as lf, MQ_SM_DOWN as li, isHeaderField as ll, KeyboardCode as ln, normalizeEventBlockKind as lo, resolveRegistrationTarget as lr, ACCORDION_TRIGGER_LETTER_SPACING as ls, useEditor$1 as lt, Surface as lu, planSiteChromeFooterLayoutSelection as m, findCuratedPalette as ma, UploadIcon as mc, unsafeAsPassId as md, ChevronDown as mf, boxStylesTransforms as mi, hasEmptyOption as ml, useDraggable as mn, normalizeEventSurfaceScope as mo, resolveEventRegistrationScopedEvents as mr, FEATURE_CARD_ICON_TREATMENTS as ms, useEntryController as mt, DropdownMenuSeparator as mu, useSiteChromeCustomizeOptional as n, boundaryRuntimeMetricsForTransition as na, FileArchiveIcon as nc, publicEventScalarPrice as nd, Crop as nf, heroCopyFragment as ni, textColorStyle as nl, reorderBlocks as nn, eventCalendarListLayoutOptions as no, eventRegistrationBlockDefinition as nr, splitPositioningClasses as ns, useRichTextEditor as nt, Root$3 as nu, selectPreviewDesignHistoryDomain as o, sectionTransitionVariantForBoundaryOptionId as oa, InfoIcon as oc, expectParsedBrandedId as od, CirclePlus as of, siteOptionSources as oi, useBackendWatch as ol, deriveLaunchReadiness as on, eventBlockKindValues as oo, findPreSelectedEvent as or, ACCORDION_OPEN_ACCENT_THICKNESS as os, insertOrReplaceRichTextImage as ot, CardContent as ou, cycleableSiteChromeOptions as p, curatedPalettes as pa, ShoppingCartIcon as pc, unsafeAsMediaAssetId as pd, ChevronLeft as pf, getAnchorClasses as pi, useSdkConfig as pl, useDndContext as pn, normalizeEventSurfacePresetsCsv as po, normalizeEventRegistrationPageSurfaceSubject as pr, mediaSchema$1 as ps, EntryControllerProvider as pt, DropdownMenuLabel as pu, deriveTransactionCapabilities as q, calendarTabViewsSchema as qa, generateInteractiveChildInheritanceCSS as qc, File as qd, LABEL_FONT_SIZE_MAP as qi, DialogContent as ql, buildNewsletterFormInteractiveIslandProps as qn, buildInteractiveIslandProps as qo, singleButtonFragment as qr, ChevronDownIcon as qs, toRoutableLinkPayload as qt, getBookingLocalDateKey as qu, PreviewDesignHistoryOrderProvider as r, defaultSectionTransitionVariantForFamily as ra, FileAudioIcon as rc, publicEventTicketTypes as rd, CreditCard as rf, bodyCopyFragment as ri, DEFAULT_SURFACE_TEXT_COLOR as rl, reorderEntrySlotBlocks as rn, el as ro, buildEventRegistrationInteractiveIslandProps as rr, planSiteChromePlacement as rs, EMPTY_DOC as rt, Trigger$3 as ru, buildApplySiteStyleSelectionBody as s, BACKGROUND_BODY_TEXT_MIN_CONTRAST_RATIO as sa, MailIcon as sc, parseMediaAssetId as sd, CircleMinus as sf, MQ_LG_UP as si, getFieldIntent as sl, AMBIENT_BACKGROUND_ROLES as sn, eventScheduleScopeValues as so, resolveDiscountContext as sr, ACCORDION_SPACING_MAP as ss, InlineTextEditor as st, CardHeader as su, SiteChromeCustomizeProvider as t, getHeaderStyle as ta, ExternalLinkIcon as tc, publicEventPricingType as td, EllipsisVertical as tf, ctaRowFragment as ti, rgbColorValue as tl, mutateBlockContent as tn, eventCalendarListLayoutCompatibleDisplayModeValues as to, buildFormInteractiveIslandProps as tr, markEditableSurfaceForwarding as ts, PreviewTextEditor as tt, Content$1 as tu, resolveStyleConfiguratorInitialSnapshot as u, foregroundTokenForBackgroundAppearanceColorToken as ua, PhoneIcon as uc, unsafeAsAppointmentServiceId as ud, ChevronsUpDown as uf, MQ_SM_UP as ui, isNonEmptyValue as ul, PointerSensor as un, normalizeEventCategoryIdsCsv as uo, WIZARD_STEPS as ur, ICON_CONFIG as us, ContentFieldsForm as ut, DropdownMenu as uu, PreviewThemeOverlayProvider as v, expandPalette as va, buildResolveImageUrlContext as vc, ok as vd, ArrowDown as vf, readHeaderNavFontSizePreference as vi, FieldFrame as vl, CSS$1 as vn, generateShadowValue as vo, buildCourseRegistrationInteractiveIslandProps as vr, shouldReserveFeatureCardIconZone as vs, useEditorUiStoreInstance as vt, __extends as vu, deriveStyleConfiguratorCapabilities as w, OFFERINGS_PREVIEW_DEFAULT_EMPTY_MESSAGE as wa, resolveMediaNodeResponsiveImage as wc, Trash2 as wd, retargetCompiledRuntimeFieldsForContentAdjacency as wi, Textarea as wl, gradientToCss as wn, getTextColorForBackground as wo, buildProductListInteractiveIslandProps as wr, parseBlockIconValue as ws, redoHistory as wt, useId$1 as wu, applyTypographyDraftPatch as x, runTransforms as xa, renderAudio as xc, Upload as xd, __exportAll as xf, applyCompiledRuntimeFieldsToContent as xi, TooltipContent as xl, useIsomorphicLayoutEffect$1 as xn, isCssColorLiteral as xo, buildCartInteractiveIslandProps as xr, buildGeneratedBlockIconRenderAssetLookupFromUnknown as xs, canUndoHistory as xt, __rest as xu, usePreviewThemeOverlay as y, generateCssVars as ya, computeMediaTransformStyle as yc, lucide_react_exports as yd, Archive as yf, formatSiteChromeBackgroundTokenLabel as yi, useField as yl, isKeyboardEvent as yn, normalizeBoxStylesCardVariant as yo, checkoutBlockDefinition as yr, suggestSemanticIconForFeatureCard as ys, useOptionalEditorUiStoreInstance as yt, __generator as yu, resetTypographyToSaved as z, eventListPaginationActionSchema as za, siblingPath as zc, Minus as zd, NAV_LINK_BORDER_RADIUS_MAP as zi, TabsTrigger as zl, createManifestValidator as zn, resolveEventCta as zo, augmentManifest as zr, SEMANTIC_ICON_DEFINITIONS as zs, validateBlockManifestIssues as zt, unsafeAsEditorBlockId as zu };