@riverbankcms/sdk 0.104.0 → 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 (129) hide show
  1. package/dist/{PreviewEditorSidebar-ywqcYjTB.mjs → PreviewEditorSidebar-CBMhU9p_.mjs} +3 -3
  2. package/dist/{PreviewEditorUI-DApUNF6g.mjs → PreviewEditorUI-C5KEw4M8.mjs} +2 -2
  3. package/dist/{SdkPreviewModeRuntime-DmHCcIMO.mjs → SdkPreviewModeRuntime-Iq12HjL7.mjs} +1147 -180
  4. package/dist/{SiteChromeCustomizeContext-BV9GU-3C.mjs → SiteChromeCustomizeContext-Cx0NMdyv.mjs} +1818 -951
  5. package/dist/_dts/ai/src/contracts/proposals.d.ts +10 -0
  6. package/dist/_dts/api/src/bookingVerticals.d.ts +64 -1
  7. package/dist/_dts/blocks/src/primitives/layout/Grid.d.ts +12 -8
  8. package/dist/_dts/blocks/src/system/blocks/events/event-calendar.d.ts +3 -0
  9. package/dist/_dts/blocks/src/system/blocks/events/shared/layout.d.ts +11 -1
  10. package/dist/_dts/blocks/src/system/blocks/testimonials.d.ts +7 -1
  11. package/dist/_dts/blocks/src/system/constants/events.d.ts +1 -1
  12. package/dist/_dts/blocks/src/system/fragments/library/testimonialsCarousel.d.ts +12 -0
  13. package/dist/_dts/blocks/src/system/node/validation-constants.d.ts +2 -2
  14. package/dist/_dts/blocks/src/system/runtime/nodes/basic.d.ts +14 -0
  15. package/dist/_dts/blocks/src/system/runtime/nodes/buttonAffordance.d.ts +33 -0
  16. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/WeekBoardView.d.ts +28 -0
  17. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/eventCapacity.d.ts +32 -0
  18. package/dist/_dts/blocks/src/system/runtime/nodes/shared/contract-schemas.d.ts +1 -0
  19. package/dist/_dts/blocks/src/system/runtime/nodes/svg.d.ts +77 -0
  20. package/dist/_dts/blocks/src/system/transforms/registry/_utils/surfaceForegroundStyles.d.ts +2 -0
  21. package/dist/_dts/blocks/src/system/transforms/registry/boxStyles.d.ts +3 -40
  22. package/dist/_dts/blocks/src/system/transforms/registry/formatting.d.ts +14 -0
  23. package/dist/_dts/blocks/src/system/transforms/registry/layout.d.ts +11 -0
  24. package/dist/_dts/core/src/branded.d.ts +5 -0
  25. package/dist/_dts/db/src/generated/supabase/database.types.d.ts +18 -0
  26. package/dist/_dts/editor/src/index.d.ts +3 -1
  27. package/dist/_dts/editor/src/primitives/rich-text/RichTextEditorSurface.d.ts +14 -6
  28. package/dist/_dts/editor/src/primitives/rich-text/RichTextToolbar.d.ts +23 -4
  29. package/dist/_dts/editor/src/primitives/rich-text/config.d.ts +6 -0
  30. package/dist/_dts/editor/src/primitives/rich-text/extensions/RichTextLink.d.ts +1 -0
  31. package/dist/_dts/editor/src/primitives/rich-text/paste.d.ts +10 -0
  32. package/dist/_dts/sdk/src/contracts/system-block-content.d.ts +2 -2
  33. package/dist/_dts/sdk/src/version.d.ts +1 -1
  34. package/dist/_dts/theme-core/src/ThemeScope.d.ts +1 -1
  35. package/dist/_dts/theme-core/src/buttons/affordanceIcons.d.ts +29 -0
  36. package/dist/_dts/theme-core/src/buttons/generateButtonCss.d.ts +6 -0
  37. package/dist/_dts/theme-core/src/buttons/index.d.ts +1 -0
  38. package/dist/_dts/theme-core/src/buttons/personalities/flat-ink.d.ts +20 -0
  39. package/dist/_dts/theme-core/src/buttons/personalities/index.d.ts +11 -0
  40. package/dist/_dts/theme-core/src/buttons/personalities/types.d.ts +4 -0
  41. package/dist/_dts/theme-core/src/buttons/types.d.ts +34 -0
  42. package/dist/_dts/theme-core/src/generated/containerResponsiveThemeCss.d.ts +1 -1
  43. package/dist/_dts/theme-core/src/gradients/types.d.ts +27 -3
  44. package/dist/_dts/theme-core/src/mock-themes/all.d.ts +51 -15
  45. package/dist/_dts/theme-core/src/palette/curated/brand-led.d.ts +13 -0
  46. package/dist/_dts/theme-core/src/palette/curated/index.d.ts +12 -0
  47. package/dist/_dts/theme-core/src/palette/historicalThemePalette.d.ts +44 -0
  48. package/dist/_dts/theme-core/src/palette/index.d.ts +1 -0
  49. package/dist/_dts/theme-core/src/palette/legacyRuntimeProjection.d.ts +23 -6
  50. package/dist/_dts/theme-core/src/palette/legacySelection.d.ts +13 -2
  51. package/dist/_dts/theme-core/src/palette/paletteCompatibilityTransition.d.ts +0 -9
  52. package/dist/_dts/theme-core/src/palette/persistenceReadSource.d.ts +17 -2
  53. package/dist/_dts/theme-core/src/palette/themePaletteCompatibility.d.ts +3 -4
  54. package/dist/_dts/theme-core/src/runtime/themeCssVarNames.d.ts +1 -0
  55. package/dist/_dts/theme-core/src/schema.d.ts +108 -26
  56. package/dist/_dts/theme-core/src/site-styles/accessibleSurfaces.d.ts +2 -1
  57. package/dist/_dts/theme-core/src/site-styles/curatedSiteStyles.d.ts +50 -1
  58. package/dist/_dts/theme-core/src/site-styles/designState.d.ts +2 -2
  59. package/dist/_dts/theme-core/src/site-styles/generatedSchemas.d.ts +4 -2
  60. package/dist/_dts/theme-core/src/site-styles/headerLooks.d.ts +56 -1
  61. package/dist/_dts/theme-core/src/site-styles/typographyPresets.d.ts +16 -1
  62. package/dist/_dts/theme-core/src/status/index.d.ts +0 -1
  63. package/dist/_dts/theme-core/src/surfaces/foregroundContract.d.ts +19 -0
  64. package/dist/_dts/theme-core/src/surfaces/foregroundRoles.d.ts +9 -0
  65. package/dist/_dts/theme-core/src/surfaces/index.d.ts +2 -0
  66. package/dist/_dts/ui/src/button.d.ts +1 -1
  67. package/dist/cli/index.mjs +1567 -470
  68. package/dist/client/{DiscountCodeDisclosure-Dit2aItR.mjs → DiscountCodeDisclosure-BXM73_E5.mjs} +1 -1
  69. package/dist/client/{EventCombined.client-BnREyCjf.mjs → EventCombined.client-DT5elP7j.mjs} +4 -4
  70. package/dist/client/{EventListing.client-0uHld51x.mjs → EventListing.client-pTYGfV9C.mjs} +2 -2
  71. package/dist/client/{LeafletStaticMap-DJcvSfmj.mjs → LeafletStaticMap-dQrhlUe3.mjs} +1 -1
  72. package/dist/client/{MagicLinkForm-EAsIktfw.mjs → MagicLinkForm-u6Dul4j5.mjs} +2 -2
  73. package/dist/client/{StepIndicator-CRR17tYI.mjs → StepIndicator-nWqineJ2.mjs} +2 -2
  74. package/dist/client/{accordion-B47HIuuH.mjs → accordion-CSJcTUyH.mjs} +1 -1
  75. package/dist/client/{bookingForm-I1E-8F9P.mjs → bookingForm-C73wOuVa.mjs} +6 -6
  76. package/dist/client/bookings.mjs +137 -1
  77. package/dist/client/{buttons-BbPn8OKA.mjs → buttons-DfYyqt8C.mjs} +138 -2
  78. package/dist/client/{carousel-OlM7SyBs.mjs → carousel-fMBb0JSc.mjs} +1 -1
  79. package/dist/client/{cart-BKpG5jz6.mjs → cart-BtaCwT3S.mjs} +3 -3
  80. package/dist/client/{checkout-Dmmr6qoU.mjs → checkout-DkTwZSnh.mjs} +3 -3
  81. package/dist/client/client.mjs +2336 -544
  82. package/dist/client/{colorStyles-DuW4Fjqd.mjs → colorStyles-Wyl6JujD.mjs} +45 -4
  83. package/dist/client/{courseRegistration-CflZiqGk.mjs → courseRegistration-DnLmapJu.mjs} +7 -7
  84. package/dist/client/{eventCalendar-BvoLWcp-.mjs → eventCalendar-BvLOc9KY.mjs} +165 -5
  85. package/dist/client/{eventCombined-DsrO8t_t.mjs → eventCombined-kShgJPQr.mjs} +2 -2
  86. package/dist/client/{eventDetails-C3hxgcJm.mjs → eventDetails-C5NTM0Vo.mjs} +3 -3
  87. package/dist/client/{eventListing-C-hb237X.mjs → eventListing-B82ZdKP6.mjs} +2 -2
  88. package/dist/client/{eventRegistration-B0gyzDGi.mjs → eventRegistration-qJVFqBWo.mjs} +7 -7
  89. package/dist/client/{form-C_RUi6oJ.mjs → form-BvAcKiuu.mjs} +2 -2
  90. package/dist/client/{headerSection-IKQiD2U0.mjs → headerSection-NvAiEHAg.mjs} +3 -3
  91. package/dist/client/hooks.mjs +1023 -337
  92. package/dist/client/{locationMap-8ZBrMzRJ.mjs → locationMap-D0j52xfI.mjs} +3 -3
  93. package/dist/client/{media-CZJKL7fi.mjs → media-BCW_g2cQ.mjs} +1 -1
  94. package/dist/client/{newsletterForm-CYk3ucwj.mjs → newsletterForm-B8_i93qH.mjs} +2 -2
  95. package/dist/client/{pricing-B5GmvfIH.mjs → pricing-DIYnyHOk.mjs} +1 -1
  96. package/dist/client/{productDetail-BjS2Dqzo.mjs → productDetail-w0eAHkuQ.mjs} +3 -3
  97. package/dist/client/{productList-BOHvC8My.mjs → productList-Vsguq5Xt.mjs} +3 -3
  98. package/dist/client/{propsDecoder-WS6UEJwZ.mjs → propsDecoder-CD2pJ1WB.mjs} +37 -2
  99. package/dist/client/rendering/client.mjs +1723 -762
  100. package/dist/client/rendering/islands.mjs +19 -19
  101. package/dist/client/rendering.mjs +2312 -520
  102. package/dist/client/{shop-CON03-wN.mjs → shop-Dgxs-Q8F.mjs} +6 -6
  103. package/dist/client/{shop-commerce-DlqrFgH8.mjs → shop-commerce-DJAhsTaT.mjs} +6 -6
  104. package/dist/client/{shop-commerce-store-l74-Kne6.mjs → shop-commerce-store-CfCXltXW.mjs} +1 -1
  105. package/dist/client/{shopShared-CQheEXSg.mjs → shopShared-CmDcPXUt.mjs} +2 -2
  106. package/dist/client/{useDiscountCodeUi-v6OluyWl.mjs → useDiscountCodeUi-CirrT2bM.mjs} +1 -1
  107. package/dist/client/{useEventFilters-BqSTcNOf.mjs → useEventFilters-CNZxlCcO.mjs} +5 -5
  108. package/dist/client/{usePolling-DMfADjIF.mjs → usePolling-Baks_iBI.mjs} +2 -2
  109. package/dist/preview-next/client/runtime.mjs +3 -3
  110. package/dist/{sdk-runtime-DWb08Xaz.mjs → sdk-runtime-BfNiFeNJ.mjs} +1 -1
  111. package/dist/{separator--6yjc914.mjs → separator-BhAR_Xmf.mjs} +1 -1
  112. package/dist/server/components.mjs +2301 -531
  113. package/dist/server/config-validation.mjs +1028 -337
  114. package/dist/server/config.mjs +1028 -337
  115. package/dist/server/data.mjs +1023 -337
  116. package/dist/server/index.mjs +1 -1
  117. package/dist/server/next.mjs +2304 -534
  118. package/dist/server/page-converter.mjs +1018 -324
  119. package/dist/server/prebuild.mjs +1 -1
  120. package/dist/server/rendering/server.mjs +2286 -521
  121. package/dist/server/rendering.mjs +2301 -531
  122. package/dist/server/routing.mjs +1100 -338
  123. package/dist/server/server.mjs +1024 -338
  124. package/dist/server/theme-bridge.mjs +1240 -77
  125. package/dist/server/theme.mjs +165 -5
  126. package/dist/styles/index.css +617 -34
  127. package/package.json +1 -1
  128. package/dist/_dts/blocks/src/system/transforms/registry/_utils/sectionForegroundStyles.d.ts +0 -2
  129. package/dist/_dts/theme-core/src/status/contextualColors.d.ts +0 -6
@@ -509,7 +509,7 @@ function encodePublicProductCategorySelector(selector) {
509
509
  };
510
510
  }
511
511
  }
512
- function isRecord$20(value) {
512
+ function isRecord$22(value) {
513
513
  return typeof value === "object" && value !== null;
514
514
  }
515
515
  function isJsonResponseContentType(contentType) {
@@ -533,8 +533,8 @@ async function parseJsonBody(response) {
533
533
  }
534
534
  }
535
535
  function getBlockApiErrorDetails(data) {
536
- if (!isRecord$20(data)) return {};
537
- const nestedError = isRecord$20(data.error) ? data.error : void 0;
536
+ if (!isRecord$22(data)) return {};
537
+ const nestedError = isRecord$22(data.error) ? data.error : void 0;
538
538
  return {
539
539
  message: typeof nestedError?.message === "string" ? nestedError.message : typeof data.message === "string" ? data.message : void 0,
540
540
  code: typeof nestedError?.code === "string" ? nestedError.code : typeof data.code === "string" ? data.code : void 0
@@ -1308,6 +1308,49 @@ function clsx() {
1308
1308
  return n;
1309
1309
  }
1310
1310
  var init_clsx = __esmMin((() => {}));
1311
+ var init_foregroundRoles = __esmMin((() => {}));
1312
+ //#endregion
1313
+ //#region ../theme-core/src/surfaces/foregroundContract.ts
1314
+ function requireSurfaceColorValue(role, value) {
1315
+ const normalized = value.trim();
1316
+ if (normalized.length === 0) throw new RangeError(`Surface foreground ${role} must be a non-empty CSS color.`);
1317
+ return normalized;
1318
+ }
1319
+ function surfaceForegroundValue(role, outsideProviderFallback = DEFAULT_ROLE_FALLBACKS[role]) {
1320
+ const roleVariable = SURFACE_FOREGROUND_CSS_VARS[role];
1321
+ const fallback = requireSurfaceColorValue("fallback", outsideProviderFallback);
1322
+ if (role === "text") return `var(${roleVariable}, ${fallback})`;
1323
+ return `var(${roleVariable}, var(${SURFACE_FOREGROUND_CSS_VARS.text}, ${fallback}))`;
1324
+ }
1325
+ function surfaceForegroundValueWithOpacity(role, opacityPercent) {
1326
+ if (!Number.isFinite(opacityPercent) || opacityPercent < 0 || opacityPercent > 100) throw new RangeError("Surface foreground opacity must be between 0 and 100.");
1327
+ return `color-mix(in srgb, ${surfaceForegroundValue(role)} ${opacityPercent}%, transparent)`;
1328
+ }
1329
+ var SURFACE_FOREGROUND_CSS_VARS, DEFAULT_SURFACE_TEXT_COLOR, DEFAULT_SURFACE_LINK_COLOR, DEFAULT_SURFACE_SUPPORTING_COLOR, DEFAULT_ROLE_FALLBACKS;
1330
+ var init_foregroundContract = __esmMin((() => {
1331
+ init_foregroundRoles();
1332
+ SURFACE_FOREGROUND_CSS_VARS = {
1333
+ text: "--rb-surface-text-color",
1334
+ heading: "--rb-surface-heading-color",
1335
+ link: "--rb-surface-link-color",
1336
+ supporting: "--rb-surface-supporting-color"
1337
+ };
1338
+ DEFAULT_SURFACE_TEXT_COLOR = "rgb(var(--tb-text, 17 24 39))";
1339
+ DEFAULT_SURFACE_LINK_COLOR = "rgb(var(--tb-primary, var(--tb-text, 17 24 39)))";
1340
+ DEFAULT_SURFACE_SUPPORTING_COLOR = "rgb(var(--tb-mutedText, 100 116 139))";
1341
+ DEFAULT_ROLE_FALLBACKS = {
1342
+ text: DEFAULT_SURFACE_TEXT_COLOR,
1343
+ heading: DEFAULT_SURFACE_TEXT_COLOR,
1344
+ link: DEFAULT_SURFACE_LINK_COLOR,
1345
+ supporting: DEFAULT_SURFACE_SUPPORTING_COLOR
1346
+ };
1347
+ }));
1348
+ //#endregion
1349
+ //#region ../theme-core/src/surfaces/index.ts
1350
+ var init_surfaces = __esmMin((() => {
1351
+ init_foregroundContract();
1352
+ init_foregroundRoles();
1353
+ }));
1311
1354
  //#endregion
1312
1355
  //#region ../theme-core/src/tokens/colorTokenParts.ts
1313
1356
  function parseOpacityPercent(source) {
@@ -1358,9 +1401,12 @@ function parseToken(source) {
1358
1401
  if (parts.kind === "invalid") return { token: source };
1359
1402
  return {
1360
1403
  token: parts.token,
1361
- alpha: parts.opacityPercent === null ? void 0 : parts.opacityPercent / 100
1404
+ opacityPercent: parts.opacityPercent === null ? void 0 : parts.opacityPercent
1362
1405
  };
1363
1406
  }
1407
+ function surfaceRoleForTextToken(token) {
1408
+ return Object.prototype.hasOwnProperty.call(SURFACE_TEXT_ROLE_BY_TOKEN, token) ? SURFACE_TEXT_ROLE_BY_TOKEN[token] : null;
1409
+ }
1364
1410
  /**
1365
1411
  * Converts a theme color token to a CSS rgb value.
1366
1412
  * This is the primary function for applying theme colors to CSS properties.
@@ -1374,11 +1420,11 @@ function parseToken(source) {
1374
1420
  * rgbColorValue('raw:transparent') // => 'transparent'
1375
1421
  */
1376
1422
  function rgbColorValue(token) {
1377
- const { token: baseToken, alpha, raw } = parseToken(token);
1423
+ const { token: baseToken, opacityPercent, raw } = parseToken(token);
1378
1424
  if (raw) return raw;
1379
1425
  const cssVar = `${COLOR_VAR_PREFIX}${baseToken}`;
1380
- if (alpha === void 0) return `rgb(var(${cssVar}))`;
1381
- return `rgb(var(${cssVar}) / ${alpha})`;
1426
+ if (opacityPercent === void 0) return `rgb(var(${cssVar}))`;
1427
+ return `rgb(var(${cssVar}) / ${opacityPercent / 100})`;
1382
1428
  }
1383
1429
  /**
1384
1430
  * Creates a backgroundColor style object from a theme token.
@@ -1396,6 +1442,9 @@ function backgroundColorStyle(token) {
1396
1442
  * @returns CSSProperties with color
1397
1443
  */
1398
1444
  function textColorStyle(token) {
1445
+ const parsed = parseToken(token);
1446
+ const surfaceRole = parsed.raw ? null : surfaceRoleForTextToken(parsed.token);
1447
+ if (surfaceRole) return { color: parsed.opacityPercent === void 0 ? surfaceForegroundValue(surfaceRole) : surfaceForegroundValueWithOpacity(surfaceRole, parsed.opacityPercent) };
1399
1448
  return { color: rgbColorValue(token) };
1400
1449
  }
1401
1450
  /**
@@ -1431,10 +1480,16 @@ function mergeStyles(...styles) {
1431
1480
  }
1432
1481
  return Object.keys(merged).length ? merged : void 0;
1433
1482
  }
1434
- var COLOR_VAR_PREFIX;
1483
+ var COLOR_VAR_PREFIX, SURFACE_TEXT_ROLE_BY_TOKEN;
1435
1484
  var init_colorStyles = __esmMin((() => {
1485
+ init_surfaces();
1436
1486
  init_colorTokenParts();
1437
1487
  COLOR_VAR_PREFIX = "--tb-";
1488
+ SURFACE_TEXT_ROLE_BY_TOKEN = {
1489
+ text: "text",
1490
+ heading: "heading",
1491
+ mutedText: "supporting"
1492
+ };
1438
1493
  }));
1439
1494
  //#endregion
1440
1495
  //#region ../blocks/src/primitives/layout/Section.tsx
@@ -1504,21 +1559,53 @@ function Inline({ as: Comp = "div", gap = "md", align = "center", justify = "sta
1504
1559
  //#endregion
1505
1560
  //#region ../blocks/src/primitives/layout/Grid.tsx
1506
1561
  init_clsx();
1562
+ /** Utility class for a numeric column COUNT at a given breakpoint. */
1563
+ const COL_COUNT_CLASS = {
1564
+ base: (n) => `rb-grid-cols-${n}`,
1565
+ sm: (n) => `rb-sm-grid-cols-${n}`,
1566
+ md: (n) => `rb-md-grid-cols-${n}`,
1567
+ lg: (n) => `rb-lg-grid-cols-${n}`,
1568
+ xl: (n) => `rb-xl-grid-cols-${n}`
1569
+ };
1570
+ /** Inline custom property read by the `.rb-grid-tracks` utility per breakpoint. */
1571
+ const TRACK_VAR = {
1572
+ base: "--rb-gtc-base",
1573
+ sm: "--rb-gtc-sm",
1574
+ md: "--rb-gtc-md",
1575
+ lg: "--rb-gtc-lg",
1576
+ xl: "--rb-gtc-xl"
1577
+ };
1578
+ const GRID_BREAKPOINTS = [
1579
+ "base",
1580
+ "sm",
1581
+ "md",
1582
+ "lg",
1583
+ "xl"
1584
+ ];
1507
1585
  function Grid({ as: Comp = "div", cols = {
1508
1586
  base: 1,
1509
1587
  md: 2
1510
- }, gap = "md", className, children, "data-slot": dataSlot, ...rest }) {
1511
- const colsObj = typeof cols === "number" ? { base: cols } : cols;
1512
- const colClasses = [
1513
- colsObj.base && `rb-grid-cols-${colsObj.base}`,
1514
- colsObj.sm && `rb-sm-grid-cols-${colsObj.sm}`,
1515
- colsObj.md && `rb-md-grid-cols-${colsObj.md}`,
1516
- colsObj.lg && `rb-lg-grid-cols-${colsObj.lg}`,
1517
- colsObj.xl && `rb-xl-grid-cols-${colsObj.xl}`
1518
- ];
1588
+ }, gap = "md", className, style, children, "data-slot": dataSlot, ...rest }) {
1589
+ const colsObj = typeof cols === "number" || typeof cols === "string" ? { base: cols } : cols;
1590
+ const colClasses = [];
1591
+ const trackVars = {};
1592
+ let hasTracks = false;
1593
+ for (const bp of GRID_BREAKPOINTS) {
1594
+ const value = colsObj[bp];
1595
+ if (value == null) continue;
1596
+ if (typeof value === "string") {
1597
+ trackVars[TRACK_VAR[bp]] = value;
1598
+ hasTracks = true;
1599
+ } else colClasses.push(COL_COUNT_CLASS[bp](value));
1600
+ }
1601
+ const mergedStyle = hasTracks ? {
1602
+ ...trackVars,
1603
+ ...style
1604
+ } : style;
1519
1605
  return /* @__PURE__ */ jsx(Comp, {
1520
1606
  ...rest,
1521
- className: clsx("rb-grid", colClasses, {
1607
+ style: mergedStyle,
1608
+ className: clsx("rb-grid", hasTracks && "rb-grid-tracks", colClasses, {
1522
1609
  "rb-gap-0": gap === "none",
1523
1610
  "rb-gap-1": gap === "xs",
1524
1611
  "rb-gap-2": gap === "sm",
@@ -1656,7 +1743,7 @@ function asSpecialVariantId(value) {
1656
1743
  if (value.length === 0) throw new Error("SpecialVariantId must be a non-empty string");
1657
1744
  return value;
1658
1745
  }
1659
- var VARIANT_ROLES, DEFAULT_VARIANT_ALIAS_ID, cornerStyleSchema, shadowSizeSchema, textTransformSchema, fontWeightSchema, buttonTypographySchema, letterSpacingSchema, hoverTransformSchema, hoverColorSchema, buttonPaddingPresetSchema, gradientStyleSchema, gradientSharpnessSchema, prioritySchema, buttonSizeNameSchema, PADDING_TOKEN_PATTERN, paddingShorthandSchema, buttonSizeConfigSchema, buttonSizesSchema, buttonGlobalSettingsSchema, gradientDirectionSchema$1, buttonBackgroundSchema, effectApplicationSchema$1, buttonBorderSchema, variantShadowSchema, variantEffectsSchema, variantSizeOverridesSchema, buttonVariantSchema, buttonSystemSchema;
1746
+ var VARIANT_ROLES, DEFAULT_VARIANT_ALIAS_ID, cornerStyleSchema, shadowSizeSchema, textTransformSchema, fontWeightSchema, buttonTypographySchema, letterSpacingSchema, hoverTransformSchema, hoverColorSchema, buttonPaddingPresetSchema, gradientStyleSchema, gradientSharpnessSchema, prioritySchema, buttonSizeNameSchema, PADDING_TOKEN_PATTERN, paddingShorthandSchema, buttonSizeConfigSchema, buttonSizesSchema, buttonGlobalSettingsSchema, gradientDirectionSchema$1, buttonBackgroundSchema, effectApplicationSchema$1, buttonBorderSchema, buttonVariantAffordanceSchema, variantShadowSchema, variantEffectsSchema, variantSizeOverridesSchema, buttonVariantSchema, buttonSystemSchema;
1660
1747
  var init_types$17 = __esmMin((() => {
1661
1748
  init_themeColorTokens();
1662
1749
  VARIANT_ROLES = [
@@ -1816,6 +1903,10 @@ var init_types$17 = __esmMin((() => {
1816
1903
  widthClass: z$1.string(),
1817
1904
  colorToken: themeColorTokenSchema
1818
1905
  });
1906
+ buttonVariantAffordanceSchema = z$1.object({
1907
+ iconId: z$1.string().min(1),
1908
+ colorToken: themeColorTokenSchema.optional()
1909
+ });
1819
1910
  variantShadowSchema = z$1.object({
1820
1911
  elevation: z$1.enum([
1821
1912
  "none",
@@ -1856,7 +1947,8 @@ var init_types$17 = __esmMin((() => {
1856
1947
  border: buttonBorderSchema.optional(),
1857
1948
  hoverBackgroundToken: z$1.string().optional(),
1858
1949
  effects: variantEffectsSchema.optional(),
1859
- sizes: variantSizeOverridesSchema.optional()
1950
+ sizes: variantSizeOverridesSchema.optional(),
1951
+ affordance: buttonVariantAffordanceSchema.optional()
1860
1952
  });
1861
1953
  buttonSystemSchema = z$1.object({
1862
1954
  global: buttonGlobalSettingsSchema,
@@ -1936,9 +2028,10 @@ var init_registry$1 = __esmMin((() => {
1936
2028
  }));
1937
2029
  var init_generateEffectsCSS = __esmMin((() => {
1938
2030
  init_registry$1();
1939
- })), init_contrast$2 = __esmMin((() => {})), init_generateDefaultButtonSystem = __esmMin((() => {
2031
+ })), init_contrast$2 = __esmMin((() => {}));
2032
+ var init_generateDefaultButtonSystem = __esmMin((() => {
1940
2033
  init_contrast$2();
1941
- }));
2034
+ })), init_affordanceIcons = __esmMin((() => {})), AFFORDANCE_SUPPRESS_CLASS;
1942
2035
  var init_generateButtonCss = __esmMin((() => {
1943
2036
  init_types$17();
1944
2037
  init_classNames();
@@ -1947,6 +2040,8 @@ var init_generateButtonCss = __esmMin((() => {
1947
2040
  init_generateEffectsCSS();
1948
2041
  init_constants$2();
1949
2042
  init_generateDefaultButtonSystem();
2043
+ init_affordanceIcons();
2044
+ AFFORDANCE_SUPPRESS_CLASS = "rb-affordance-off";
1950
2045
  buttonSizeNameSchema.options;
1951
2046
  }));
1952
2047
  var init_presets$1 = __esmMin((() => {}));
@@ -2523,47 +2618,46 @@ var init_editorial_link = __esmMin((() => {
2523
2618
  });
2524
2619
  }));
2525
2620
  //#endregion
2526
- //#region ../theme-core/src/buttons/personalities/ink-stamp.ts
2527
- var inkStamp;
2528
- var init_ink_stamp = __esmMin((() => {
2621
+ //#region ../theme-core/src/buttons/personalities/flat-ink.ts
2622
+ var flatInk;
2623
+ var init_flat_ink = __esmMin((() => {
2529
2624
  init_types$16();
2530
- inkStamp = defineButtonPersonality({
2531
- id: "ink-stamp",
2532
- name: "Ink Stamp",
2533
- description: "Hand-stamped block-print buttons with a slight lift on hover.",
2625
+ flatInk = defineButtonPersonality({
2626
+ id: "flat-ink",
2627
+ name: "Flat Ink",
2628
+ description: "Flat solid-ink primary, hairline ghost secondary, and a single amber accent climax — modest radius, no shadow.",
2534
2629
  tags: {
2535
- tone: "bold",
2536
- energy: "vibrant",
2537
- motion: "standard",
2538
- era: "organic"
2630
+ tone: "classic",
2631
+ energy: "calm",
2632
+ motion: "subtle",
2633
+ era: "editorial"
2539
2634
  },
2540
2635
  buttonSystem: {
2541
2636
  global: {
2542
2637
  cornerStyle: "rounded",
2543
- shadow: "none",
2544
- textTransform: "uppercase",
2638
+ shadow: "low",
2639
+ textTransform: "none",
2545
2640
  fontWeight: 600,
2546
2641
  borderWidth: 1,
2547
- hoverTransform: "none",
2548
- hoverColor: "none",
2549
- letterSpacing: "loose"
2642
+ typography: "body",
2643
+ letterSpacing: "tight",
2644
+ paddingPreset: "default",
2645
+ hoverTransform: "lift",
2646
+ hoverColor: "none"
2550
2647
  },
2551
2648
  sizes: {
2552
2649
  sm: {
2553
- padding: "0.5rem 1.25rem",
2554
- fontSize: "text-xs"
2555
- },
2556
- md: {
2557
- padding: "0.75rem 1.75rem",
2650
+ padding: "0.625rem 1.125rem",
2558
2651
  fontSize: "text-sm"
2559
2652
  },
2653
+ md: { padding: "0.8125rem 1.375rem" },
2560
2654
  lg: {
2561
- padding: "0.875rem 2.25rem",
2562
- fontSize: "text-base"
2655
+ padding: "0.9375rem 1.625rem",
2656
+ fontSize: "text-lg"
2563
2657
  },
2564
2658
  xl: {
2565
- padding: "1.125rem 2.75rem",
2566
- fontSize: "text-lg"
2659
+ padding: "1.0625rem 2rem",
2660
+ fontSize: "text-xl"
2567
2661
  }
2568
2662
  },
2569
2663
  variants: [
@@ -2577,88 +2671,72 @@ var init_ink_stamp = __esmMin((() => {
2577
2671
  colorToken: "primary"
2578
2672
  },
2579
2673
  textColorToken: "primaryForeground",
2580
- borderRadius: "rounded-md",
2581
- effects: {
2582
- hover: [{
2583
- effectId: "drop-shadow",
2584
- options: { intensity: "medium" }
2585
- }, {
2586
- effectId: "scale-up",
2587
- options: { scale: "1.02" }
2588
- }],
2589
- active: [{
2590
- effectId: "scale-down",
2591
- options: { scale: "0.98" }
2592
- }]
2593
- }
2594
- },
2595
- {
2596
- id: "secondary",
2597
- name: "Secondary",
2598
- enabled: true,
2599
- priority: 2,
2600
- background: { type: "transparent" },
2601
- textColorToken: "primary",
2602
- borderRadius: "rounded-md",
2603
- border: {
2604
- widthClass: "border-2",
2605
- colorToken: "primary"
2674
+ borderRadius: "rounded-lg",
2675
+ affordance: {
2676
+ iconId: "ArrowRight",
2677
+ colorToken: "accent"
2678
+ },
2679
+ shadow: {
2680
+ elevation: "none",
2681
+ softness: null,
2682
+ position: "bottom"
2606
2683
  },
2607
2684
  effects: { hover: [{
2685
+ effectId: "lift",
2686
+ options: { translateY: "-2px" }
2687
+ }, {
2608
2688
  effectId: "background-on-hover",
2609
- options: { colorToken: "surface" }
2689
+ options: { colorToken: "secondary" }
2610
2690
  }] }
2611
2691
  },
2612
2692
  {
2613
- id: "outline",
2614
- name: "Outline",
2693
+ id: "secondary",
2694
+ name: "Secondary",
2615
2695
  enabled: true,
2616
- priority: 3,
2696
+ priority: 2,
2617
2697
  background: { type: "transparent" },
2618
- textColorToken: "text",
2619
- borderRadius: "rounded-md",
2698
+ textColorToken: "primary",
2699
+ borderRadius: "rounded-lg",
2620
2700
  border: {
2621
- widthClass: "border-2",
2701
+ widthClass: "border",
2622
2702
  colorToken: "border"
2623
2703
  },
2704
+ shadow: {
2705
+ elevation: "none",
2706
+ softness: null,
2707
+ position: "bottom"
2708
+ },
2624
2709
  effects: { hover: [{
2710
+ effectId: "lift",
2711
+ options: { translateY: "-2px" }
2712
+ }, {
2625
2713
  effectId: "background-on-hover",
2626
- options: { colorToken: "surface" }
2714
+ options: { colorToken: "surfaceAlt" }
2627
2715
  }] }
2628
2716
  },
2629
2717
  {
2630
- id: "ghost",
2631
- name: "Ghost",
2718
+ id: "accent",
2719
+ name: "Accent",
2632
2720
  enabled: true,
2633
2721
  priority: 3,
2634
- background: { type: "transparent" },
2635
- textColorToken: "accent",
2636
- borderRadius: "rounded-none",
2637
- sizes: {
2638
- sm: {
2639
- padding: "0.375rem 0",
2640
- fontSize: "text-xs"
2641
- },
2642
- md: {
2643
- padding: "0.5rem 0",
2644
- fontSize: "text-sm"
2645
- },
2646
- lg: {
2647
- padding: "0.625rem 0",
2648
- fontSize: "text-base"
2649
- },
2650
- xl: {
2651
- padding: "0.75rem 0",
2652
- fontSize: "text-lg"
2653
- }
2722
+ background: {
2723
+ type: "solid",
2724
+ colorToken: "accent"
2654
2725
  },
2655
- effects: { base: [{
2656
- effectId: "border-bottom-grow",
2657
- options: {
2658
- height: 1,
2659
- colorToken: "accent",
2660
- origin: "left"
2661
- }
2726
+ textColorToken: "accentForeground",
2727
+ borderRadius: "rounded-lg",
2728
+ shadow: {
2729
+ elevation: "none",
2730
+ softness: null,
2731
+ position: "bottom"
2732
+ },
2733
+ affordance: {
2734
+ iconId: "ArrowRight",
2735
+ colorToken: "accentForeground"
2736
+ },
2737
+ effects: { hover: [{
2738
+ effectId: "lift",
2739
+ options: { translateY: "-2px" }
2662
2740
  }] }
2663
2741
  }
2664
2742
  ]
@@ -2666,104 +2744,18 @@ var init_ink_stamp = __esmMin((() => {
2666
2744
  });
2667
2745
  }));
2668
2746
  //#endregion
2669
- //#region ../theme-core/src/buttons/personalities/joy-stamp.ts
2670
- var joyStamp;
2671
- var init_joy_stamp = __esmMin((() => {
2747
+ //#region ../theme-core/src/buttons/personalities/ink-stamp.ts
2748
+ var inkStamp;
2749
+ var init_ink_stamp = __esmMin((() => {
2672
2750
  init_types$16();
2673
- joyStamp = defineButtonPersonality({
2674
- id: "joy-stamp",
2675
- name: "Joy Stamp",
2676
- description: "Pill buttons with a hard, brand-coloured offset shadow that presses in on hover.",
2751
+ inkStamp = defineButtonPersonality({
2752
+ id: "ink-stamp",
2753
+ name: "Ink Stamp",
2754
+ description: "Hand-stamped block-print buttons with a slight lift on hover.",
2677
2755
  tags: {
2678
2756
  tone: "bold",
2679
2757
  energy: "vibrant",
2680
- motion: "expressive",
2681
- era: "organic"
2682
- },
2683
- buttonSystem: {
2684
- global: {
2685
- cornerStyle: "pill",
2686
- shadow: "high",
2687
- textTransform: "none",
2688
- typography: "heading",
2689
- fontWeight: 700,
2690
- fontSize: "text-lg",
2691
- borderWidth: 2,
2692
- hoverTransform: "none",
2693
- hoverColor: "none"
2694
- },
2695
- sizes: {
2696
- sm: {
2697
- padding: "0.625rem 1.25rem",
2698
- fontSize: "text-base"
2699
- },
2700
- md: {
2701
- padding: "0.875rem 1.75rem",
2702
- fontSize: "text-lg"
2703
- },
2704
- lg: {
2705
- padding: "1.125rem 2.25rem",
2706
- fontSize: "text-xl"
2707
- },
2708
- xl: {
2709
- padding: "1.25rem 2.75rem",
2710
- fontSize: "text-2xl"
2711
- }
2712
- },
2713
- variants: [{
2714
- id: "primary",
2715
- name: "Primary",
2716
- enabled: true,
2717
- priority: 1,
2718
- background: {
2719
- type: "solid",
2720
- colorToken: "primary"
2721
- },
2722
- textColorToken: "primaryForeground",
2723
- borderRadius: "rounded-full",
2724
- shadow: {
2725
- elevation: "high",
2726
- softness: "hard",
2727
- position: "bottom-right",
2728
- colorToken: "text"
2729
- },
2730
- effects: { hover: [{ effectId: "press-down" }] }
2731
- }, {
2732
- id: "secondary",
2733
- name: "Secondary",
2734
- enabled: true,
2735
- priority: 2,
2736
- background: { type: "transparent" },
2737
- textColorToken: "text",
2738
- borderRadius: "rounded-full",
2739
- border: {
2740
- widthClass: "border-2",
2741
- colorToken: "text"
2742
- },
2743
- shadow: {
2744
- elevation: "high",
2745
- softness: "hard",
2746
- position: "bottom-right",
2747
- colorToken: "secondary"
2748
- },
2749
- effects: { hover: [{ effectId: "press-down" }] }
2750
- }]
2751
- }
2752
- });
2753
- }));
2754
- //#endregion
2755
- //#region ../theme-core/src/buttons/personalities/ornate-ritual.ts
2756
- var ornateRitual;
2757
- var init_ornate_ritual = __esmMin((() => {
2758
- init_types$16();
2759
- ornateRitual = defineButtonPersonality({
2760
- id: "ornate-ritual",
2761
- name: "Ornate Ritual",
2762
- description: "Ceremonial framed buttons with jewel-toned fills and quiet color-change hover states.",
2763
- tags: {
2764
- tone: "classic",
2765
- energy: "vibrant",
2766
- motion: "subtle",
2758
+ motion: "standard",
2767
2759
  era: "organic"
2768
2760
  },
2769
2761
  buttonSystem: {
@@ -2779,20 +2771,20 @@ var init_ornate_ritual = __esmMin((() => {
2779
2771
  },
2780
2772
  sizes: {
2781
2773
  sm: {
2782
- padding: "0.5625rem 1.25rem",
2774
+ padding: "0.5rem 1.25rem",
2783
2775
  fontSize: "text-xs"
2784
2776
  },
2785
2777
  md: {
2786
2778
  padding: "0.75rem 1.75rem",
2787
- fontSize: "text-xs"
2779
+ fontSize: "text-sm"
2788
2780
  },
2789
2781
  lg: {
2790
2782
  padding: "0.875rem 2.25rem",
2791
- fontSize: "text-sm"
2783
+ fontSize: "text-base"
2792
2784
  },
2793
2785
  xl: {
2794
- padding: "1rem 2.75rem",
2795
- fontSize: "text-base"
2786
+ padding: "1.125rem 2.75rem",
2787
+ fontSize: "text-lg"
2796
2788
  }
2797
2789
  },
2798
2790
  variants: [
@@ -2807,19 +2799,13 @@ var init_ornate_ritual = __esmMin((() => {
2807
2799
  },
2808
2800
  textColorToken: "primaryForeground",
2809
2801
  borderRadius: "rounded-md",
2810
- border: {
2811
- widthClass: "border",
2812
- colorToken: "primary"
2813
- },
2814
- shadow: {
2815
- elevation: "none",
2816
- softness: null,
2817
- position: "bottom"
2818
- },
2819
2802
  effects: {
2820
2803
  hover: [{
2821
- effectId: "background-on-hover",
2822
- options: { colorToken: "primary-100" }
2804
+ effectId: "drop-shadow",
2805
+ options: { intensity: "medium" }
2806
+ }, {
2807
+ effectId: "scale-up",
2808
+ options: { scale: "1.02" }
2823
2809
  }],
2824
2810
  active: [{
2825
2811
  effectId: "scale-down",
@@ -2832,21 +2818,13 @@ var init_ornate_ritual = __esmMin((() => {
2832
2818
  name: "Secondary",
2833
2819
  enabled: true,
2834
2820
  priority: 2,
2835
- background: {
2836
- type: "solid",
2837
- colorToken: "secondary"
2838
- },
2839
- textColorToken: "primaryForeground",
2821
+ background: { type: "transparent" },
2822
+ textColorToken: "primary",
2840
2823
  borderRadius: "rounded-md",
2841
2824
  border: {
2842
- widthClass: "border",
2825
+ widthClass: "border-2",
2843
2826
  colorToken: "primary"
2844
2827
  },
2845
- shadow: {
2846
- elevation: "none",
2847
- softness: null,
2848
- position: "bottom"
2849
- },
2850
2828
  effects: { hover: [{
2851
2829
  effectId: "background-on-hover",
2852
2830
  options: { colorToken: "surface" }
@@ -2858,20 +2836,263 @@ var init_ornate_ritual = __esmMin((() => {
2858
2836
  enabled: true,
2859
2837
  priority: 3,
2860
2838
  background: { type: "transparent" },
2861
- textColorToken: "primary",
2839
+ textColorToken: "text",
2862
2840
  borderRadius: "rounded-md",
2863
2841
  border: {
2864
- widthClass: "border",
2865
- colorToken: "primary"
2866
- },
2867
- shadow: {
2868
- elevation: "none",
2869
- softness: null,
2870
- position: "bottom"
2842
+ widthClass: "border-2",
2843
+ colorToken: "border"
2871
2844
  },
2872
2845
  effects: { hover: [{
2873
2846
  effectId: "background-on-hover",
2874
- options: { colorToken: "muted" }
2847
+ options: { colorToken: "surface" }
2848
+ }] }
2849
+ },
2850
+ {
2851
+ id: "ghost",
2852
+ name: "Ghost",
2853
+ enabled: true,
2854
+ priority: 3,
2855
+ background: { type: "transparent" },
2856
+ textColorToken: "accent",
2857
+ borderRadius: "rounded-none",
2858
+ sizes: {
2859
+ sm: {
2860
+ padding: "0.375rem 0",
2861
+ fontSize: "text-xs"
2862
+ },
2863
+ md: {
2864
+ padding: "0.5rem 0",
2865
+ fontSize: "text-sm"
2866
+ },
2867
+ lg: {
2868
+ padding: "0.625rem 0",
2869
+ fontSize: "text-base"
2870
+ },
2871
+ xl: {
2872
+ padding: "0.75rem 0",
2873
+ fontSize: "text-lg"
2874
+ }
2875
+ },
2876
+ effects: { base: [{
2877
+ effectId: "border-bottom-grow",
2878
+ options: {
2879
+ height: 1,
2880
+ colorToken: "accent",
2881
+ origin: "left"
2882
+ }
2883
+ }] }
2884
+ }
2885
+ ]
2886
+ }
2887
+ });
2888
+ }));
2889
+ //#endregion
2890
+ //#region ../theme-core/src/buttons/personalities/joy-stamp.ts
2891
+ var joyStamp;
2892
+ var init_joy_stamp = __esmMin((() => {
2893
+ init_types$16();
2894
+ joyStamp = defineButtonPersonality({
2895
+ id: "joy-stamp",
2896
+ name: "Joy Stamp",
2897
+ description: "Pill buttons with a hard, brand-coloured offset shadow that presses in on hover.",
2898
+ tags: {
2899
+ tone: "bold",
2900
+ energy: "vibrant",
2901
+ motion: "expressive",
2902
+ era: "organic"
2903
+ },
2904
+ buttonSystem: {
2905
+ global: {
2906
+ cornerStyle: "pill",
2907
+ shadow: "high",
2908
+ textTransform: "none",
2909
+ typography: "heading",
2910
+ fontWeight: 700,
2911
+ fontSize: "text-lg",
2912
+ borderWidth: 2,
2913
+ hoverTransform: "none",
2914
+ hoverColor: "none"
2915
+ },
2916
+ sizes: {
2917
+ sm: {
2918
+ padding: "0.625rem 1.25rem",
2919
+ fontSize: "text-base"
2920
+ },
2921
+ md: {
2922
+ padding: "0.875rem 1.75rem",
2923
+ fontSize: "text-lg"
2924
+ },
2925
+ lg: {
2926
+ padding: "1.125rem 2.25rem",
2927
+ fontSize: "text-xl"
2928
+ },
2929
+ xl: {
2930
+ padding: "1.25rem 2.75rem",
2931
+ fontSize: "text-2xl"
2932
+ }
2933
+ },
2934
+ variants: [{
2935
+ id: "primary",
2936
+ name: "Primary",
2937
+ enabled: true,
2938
+ priority: 1,
2939
+ background: {
2940
+ type: "solid",
2941
+ colorToken: "primary"
2942
+ },
2943
+ textColorToken: "primaryForeground",
2944
+ borderRadius: "rounded-full",
2945
+ shadow: {
2946
+ elevation: "high",
2947
+ softness: "hard",
2948
+ position: "bottom-right",
2949
+ colorToken: "text"
2950
+ },
2951
+ effects: { hover: [{ effectId: "press-down" }] }
2952
+ }, {
2953
+ id: "secondary",
2954
+ name: "Secondary",
2955
+ enabled: true,
2956
+ priority: 2,
2957
+ background: { type: "transparent" },
2958
+ textColorToken: "text",
2959
+ borderRadius: "rounded-full",
2960
+ border: {
2961
+ widthClass: "border-2",
2962
+ colorToken: "text"
2963
+ },
2964
+ shadow: {
2965
+ elevation: "high",
2966
+ softness: "hard",
2967
+ position: "bottom-right",
2968
+ colorToken: "secondary"
2969
+ },
2970
+ effects: { hover: [{ effectId: "press-down" }] }
2971
+ }]
2972
+ }
2973
+ });
2974
+ }));
2975
+ //#endregion
2976
+ //#region ../theme-core/src/buttons/personalities/ornate-ritual.ts
2977
+ var ornateRitual;
2978
+ var init_ornate_ritual = __esmMin((() => {
2979
+ init_types$16();
2980
+ ornateRitual = defineButtonPersonality({
2981
+ id: "ornate-ritual",
2982
+ name: "Ornate Ritual",
2983
+ description: "Ceremonial framed buttons with jewel-toned fills and quiet color-change hover states.",
2984
+ tags: {
2985
+ tone: "classic",
2986
+ energy: "vibrant",
2987
+ motion: "subtle",
2988
+ era: "organic"
2989
+ },
2990
+ buttonSystem: {
2991
+ global: {
2992
+ cornerStyle: "rounded",
2993
+ shadow: "none",
2994
+ textTransform: "uppercase",
2995
+ fontWeight: 600,
2996
+ borderWidth: 1,
2997
+ hoverTransform: "none",
2998
+ hoverColor: "none",
2999
+ letterSpacing: "loose"
3000
+ },
3001
+ sizes: {
3002
+ sm: {
3003
+ padding: "0.5625rem 1.25rem",
3004
+ fontSize: "text-xs"
3005
+ },
3006
+ md: {
3007
+ padding: "0.75rem 1.75rem",
3008
+ fontSize: "text-xs"
3009
+ },
3010
+ lg: {
3011
+ padding: "0.875rem 2.25rem",
3012
+ fontSize: "text-sm"
3013
+ },
3014
+ xl: {
3015
+ padding: "1rem 2.75rem",
3016
+ fontSize: "text-base"
3017
+ }
3018
+ },
3019
+ variants: [
3020
+ {
3021
+ id: "primary",
3022
+ name: "Primary",
3023
+ enabled: true,
3024
+ priority: 1,
3025
+ background: {
3026
+ type: "solid",
3027
+ colorToken: "primary"
3028
+ },
3029
+ textColorToken: "primaryForeground",
3030
+ borderRadius: "rounded-md",
3031
+ border: {
3032
+ widthClass: "border",
3033
+ colorToken: "primary"
3034
+ },
3035
+ shadow: {
3036
+ elevation: "none",
3037
+ softness: null,
3038
+ position: "bottom"
3039
+ },
3040
+ effects: {
3041
+ hover: [{
3042
+ effectId: "background-on-hover",
3043
+ options: { colorToken: "primary-100" }
3044
+ }],
3045
+ active: [{
3046
+ effectId: "scale-down",
3047
+ options: { scale: "0.98" }
3048
+ }]
3049
+ }
3050
+ },
3051
+ {
3052
+ id: "secondary",
3053
+ name: "Secondary",
3054
+ enabled: true,
3055
+ priority: 2,
3056
+ background: {
3057
+ type: "solid",
3058
+ colorToken: "secondary"
3059
+ },
3060
+ textColorToken: "primaryForeground",
3061
+ borderRadius: "rounded-md",
3062
+ border: {
3063
+ widthClass: "border",
3064
+ colorToken: "primary"
3065
+ },
3066
+ shadow: {
3067
+ elevation: "none",
3068
+ softness: null,
3069
+ position: "bottom"
3070
+ },
3071
+ effects: { hover: [{
3072
+ effectId: "background-on-hover",
3073
+ options: { colorToken: "surface" }
3074
+ }] }
3075
+ },
3076
+ {
3077
+ id: "outline",
3078
+ name: "Outline",
3079
+ enabled: true,
3080
+ priority: 3,
3081
+ background: { type: "transparent" },
3082
+ textColorToken: "primary",
3083
+ borderRadius: "rounded-md",
3084
+ border: {
3085
+ widthClass: "border",
3086
+ colorToken: "primary"
3087
+ },
3088
+ shadow: {
3089
+ elevation: "none",
3090
+ softness: null,
3091
+ position: "bottom"
3092
+ },
3093
+ effects: { hover: [{
3094
+ effectId: "background-on-hover",
3095
+ options: { colorToken: "muted" }
2875
3096
  }] }
2876
3097
  },
2877
3098
  {
@@ -3289,6 +3510,7 @@ var init_personalities = __esmMin((() => {
3289
3510
  init_confident_chip();
3290
3511
  init_earth_pill();
3291
3512
  init_editorial_link();
3513
+ init_flat_ink();
3292
3514
  init_ink_stamp();
3293
3515
  init_joy_stamp();
3294
3516
  init_ornate_ritual();
@@ -3303,6 +3525,7 @@ var init_personalities = __esmMin((() => {
3303
3525
  editorialLink,
3304
3526
  pebble,
3305
3527
  inkStamp,
3528
+ flatInk,
3306
3529
  brushedWash,
3307
3530
  showtimePill,
3308
3531
  joyStamp,
@@ -3320,6 +3543,7 @@ var init_buttons = __esmMin((() => {
3320
3543
  init_types$17();
3321
3544
  init_classNames();
3322
3545
  init_generateButtonCss();
3546
+ init_affordanceIcons();
3323
3547
  init_generateDefaultButtonSystem();
3324
3548
  init_constants$2();
3325
3549
  init_presets$1();
@@ -3336,11 +3560,11 @@ init_buttons();
3336
3560
  //#region ../path-utils/src/index.ts
3337
3561
  const PATH_SEPARATOR_REGEX = /\./g;
3338
3562
  const BRACKET_ACCESS_REGEX = /\[([^\]]+)\]/g;
3339
- function isRecord$19(value) {
3563
+ function isRecord$21(value) {
3340
3564
  return typeof value === "object" && value !== null && !Array.isArray(value);
3341
3565
  }
3342
3566
  function isPathContainer(value) {
3343
- return Array.isArray(value) || isRecord$19(value);
3567
+ return Array.isArray(value) || isRecord$21(value);
3344
3568
  }
3345
3569
  function getContainerValue(container, segment) {
3346
3570
  if (typeof segment === "number") return Array.isArray(container) ? container[segment] : void 0;
@@ -4220,11 +4444,11 @@ var init_fileStorage = __esmMin((() => {
4220
4444
  var init_fileAssetLegacyProjection = __esmMin((() => {}));
4221
4445
  //#endregion
4222
4446
  //#region ../media-core/src/typeGuards.ts
4223
- function isRecord$17(value) {
4447
+ function isRecord$19(value) {
4224
4448
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
4225
4449
  }
4226
4450
  function asRecord$1(value) {
4227
- return isRecord$17(value) ? value : void 0;
4451
+ return isRecord$19(value) ? value : void 0;
4228
4452
  }
4229
4453
  var init_typeGuards$1 = __esmMin((() => {}));
4230
4454
  function isFileJsonObject(value) {
@@ -4234,7 +4458,7 @@ function isFileJsonValue(value) {
4234
4458
  if (value === null || typeof value === "string" || typeof value === "boolean") return true;
4235
4459
  if (typeof value === "number") return Number.isFinite(value);
4236
4460
  if (Array.isArray(value)) return value.every(isFileJsonValue);
4237
- return isRecord$17(value) && isFileJsonObject(value);
4461
+ return isRecord$19(value) && isFileJsonObject(value);
4238
4462
  }
4239
4463
  var init_filePersistence = __esmMin((() => {
4240
4464
  init_src$3();
@@ -4585,7 +4809,7 @@ function isCmsMediaObjectType(value) {
4585
4809
  return typeof value === "string" && CMS_MEDIA_OBJECT_TYPES.includes(value);
4586
4810
  }
4587
4811
  function isCmsMediaObject(value) {
4588
- if (!isRecord$17(value)) return false;
4812
+ if (!isRecord$19(value)) return false;
4589
4813
  const type = value.type;
4590
4814
  if (!isCmsMediaObjectType(type)) return false;
4591
4815
  if ("attrs" in value) return false;
@@ -4596,7 +4820,7 @@ function collectMediaObjects(value, out, location = "") {
4596
4820
  value.forEach((item, index) => collectMediaObjects(item, out, `${location}[${index}]`));
4597
4821
  return;
4598
4822
  }
4599
- if (!isRecord$17(value)) return;
4823
+ if (!isRecord$19(value)) return;
4600
4824
  if (isCmsMediaObject(value)) out.push({
4601
4825
  obj: value,
4602
4826
  location
@@ -4630,8 +4854,8 @@ function walkAndCollectImageAttrs(value, out, location = "") {
4630
4854
  value.forEach((item, index) => walkAndCollectImageAttrs(item, out, `${location}[${index}]`));
4631
4855
  return;
4632
4856
  }
4633
- if (!isRecord$17(value)) return;
4634
- if (value.type === "image" && isRecord$17(value.attrs)) out.push({
4857
+ if (!isRecord$19(value)) return;
4858
+ if (value.type === "image" && isRecord$19(value.attrs)) out.push({
4635
4859
  attrs: value.attrs,
4636
4860
  location: location ? `${location}.attrs` : "attrs"
4637
4861
  });
@@ -5995,378 +6219,6 @@ function Text$1({ as: Comp = "span", children, className = "", path, maxLength:
5995
6219
  children
5996
6220
  });
5997
6221
  }
5998
- const inlineTextMarkSchema = z$1.discriminatedUnion("kind", [
5999
- z$1.object({ kind: z$1.literal("strong") }),
6000
- z$1.object({ kind: z$1.literal("emphasis") }),
6001
- z$1.object({
6002
- kind: z$1.literal("accent"),
6003
- tone: z$1.enum([
6004
- "accent",
6005
- "brand",
6006
- "contrast"
6007
- ])
6008
- }),
6009
- z$1.object({
6010
- kind: z$1.literal("highlight"),
6011
- tone: z$1.enum([
6012
- "soft",
6013
- "accent",
6014
- "brand"
6015
- ])
6016
- })
6017
- ]);
6018
- const inlineTextRunSchema = z$1.object({
6019
- text: z$1.string(),
6020
- marks: z$1.array(inlineTextMarkSchema).optional()
6021
- });
6022
- z$1.array(inlineTextRunSchema);
6023
- const MARK_ORDER = {
6024
- strong: 0,
6025
- emphasis: 1,
6026
- accent: 2,
6027
- highlight: 3
6028
- };
6029
- function inlineTextToPlainText(value) {
6030
- return value.map((run) => run.text).join("");
6031
- }
6032
- function isInlineTextEmpty(value) {
6033
- return inlineTextToPlainText(value).trim().length === 0;
6034
- }
6035
- function parseInlineTextFromUnknown(value) {
6036
- if (!Array.isArray(value)) return {
6037
- ok: false,
6038
- error: { kind: "not-array" }
6039
- };
6040
- const runs = [];
6041
- for (let index = 0; index < value.length; index += 1) {
6042
- const parsed = inlineTextRunSchema.safeParse(value[index]);
6043
- if (!parsed.success) return {
6044
- ok: false,
6045
- error: {
6046
- kind: "invalid-run",
6047
- index
6048
- }
6049
- };
6050
- runs.push(parsed.data);
6051
- }
6052
- return {
6053
- ok: true,
6054
- value: normalizeInlineText(runs)
6055
- };
6056
- }
6057
- function normalizeInlineText(value) {
6058
- const normalized = [];
6059
- for (const run of value) {
6060
- if (run.text.length === 0) continue;
6061
- const marks = normalizeInlineTextMarks(run.marks ?? []);
6062
- const nextRun = marks.length > 0 ? {
6063
- text: run.text,
6064
- marks
6065
- } : { text: run.text };
6066
- const previous = normalized[normalized.length - 1];
6067
- if (previous && inlineTextMarksEqual(previous.marks ?? [], nextRun.marks ?? [])) {
6068
- normalized[normalized.length - 1] = previous.marks && previous.marks.length > 0 ? {
6069
- text: previous.text + nextRun.text,
6070
- marks: previous.marks
6071
- } : { text: previous.text + nextRun.text };
6072
- continue;
6073
- }
6074
- normalized.push(nextRun);
6075
- }
6076
- return normalized;
6077
- }
6078
- function normalizeInlineTextMarks(marks) {
6079
- let strong = null;
6080
- let emphasis = null;
6081
- let accent = null;
6082
- let highlight = null;
6083
- for (const mark of marks) switch (mark.kind) {
6084
- case "strong":
6085
- strong = { kind: "strong" };
6086
- break;
6087
- case "emphasis":
6088
- emphasis = { kind: "emphasis" };
6089
- break;
6090
- case "accent":
6091
- accent = {
6092
- kind: "accent",
6093
- tone: mark.tone
6094
- };
6095
- break;
6096
- case "highlight":
6097
- highlight = {
6098
- kind: "highlight",
6099
- tone: mark.tone
6100
- };
6101
- break;
6102
- }
6103
- return [
6104
- strong,
6105
- emphasis,
6106
- accent,
6107
- highlight
6108
- ].filter((mark) => mark !== null).sort((left, right) => MARK_ORDER[left.kind] - MARK_ORDER[right.kind]);
6109
- }
6110
- function inlineTextMarksEqual(left, right) {
6111
- const normalizedLeft = normalizeInlineTextMarks(left);
6112
- const normalizedRight = normalizeInlineTextMarks(right);
6113
- if (normalizedLeft.length !== normalizedRight.length) return false;
6114
- return normalizedLeft.every((mark, index) => inlineTextMarkEqual(mark, normalizedRight[index]));
6115
- }
6116
- function inlineTextMarkEqual(left, right) {
6117
- if (!right || left.kind !== right.kind) return false;
6118
- switch (left.kind) {
6119
- case "strong":
6120
- case "emphasis": return true;
6121
- case "accent": return right.kind === "accent" && left.tone === right.tone;
6122
- case "highlight": return right.kind === "highlight" && left.tone === right.tone;
6123
- }
6124
- }
6125
- //#endregion
6126
- //#region ../blocks/src/lib/typeGuards.ts
6127
- /**
6128
- * Strict record guard: excludes null, primitives, and arrays.
6129
- */
6130
- function isRecord$16(value) {
6131
- return typeof value === "object" && value !== null && !Array.isArray(value);
6132
- }
6133
- var init_typeGuards = __esmMin((() => {}));
6134
- /**
6135
- * Permissive unwrap for a value known to be the root of a rich-text field.
6136
- *
6137
- * Producers should emit the canonical unwrapped form `{ type: 'doc', content: [...] }`,
6138
- * but two legacy shapes still appear in older data and pre-Phase-1 fixtures:
6139
- *
6140
- * - `{ doc: <typed-doc> }` — pre-migration DB storage.
6141
- * - `{ doc: <typed-doc>, html, plain }` — pre-Phase-1 dummy-content output.
6142
- *
6143
- * This helper is the single right place to tolerate either shape at a known
6144
- * rich-text root (transforms, coercion, validators that operate on rich text).
6145
- * The strictness sits on the inner node's `type === 'doc'`, which prevents
6146
- * misidentifying random objects that happen to carry a field named `doc`.
6147
- *
6148
- * Returns the inner doc node when the input matches a legacy shape, otherwise
6149
- * returns the input unchanged.
6150
- *
6151
- * For deep structural traversal where any nested key might be named `doc`
6152
- * (and unwrapping would be incorrect), use the strict `isDocWrapper` private
6153
- * helper inside `@riverbankcms/blocks/bindings`.
6154
- */
6155
- function unwrapRichTextRoot(value) {
6156
- if (!isRecord$16(value)) return value;
6157
- if (!("doc" in value)) return value;
6158
- const inner = value.doc;
6159
- if (isRecord$16(inner) && inner.type === "doc") return inner;
6160
- return value;
6161
- }
6162
- function createHardBreakNode() {
6163
- return { type: "hardBreak" };
6164
- }
6165
- /**
6166
- * Parse a small markdown subset into TipTap inline nodes.
6167
- *
6168
- * This intentionally supports only bold (`**text**`) because the SDK/content
6169
- * import paths use it for lightweight default content, not full markdown.
6170
- */
6171
- function parseRichTextInlineMarkdown(text) {
6172
- const out = [];
6173
- const pushText = (value, marks) => {
6174
- if (!value) return;
6175
- out.push(marks && marks.length > 0 ? {
6176
- type: "text",
6177
- text: value,
6178
- marks
6179
- } : {
6180
- type: "text",
6181
- text: value
6182
- });
6183
- };
6184
- let rest = text;
6185
- while (rest.length > 0) {
6186
- const start = rest.indexOf("**");
6187
- if (start === -1) {
6188
- pushText(rest);
6189
- break;
6190
- }
6191
- const end = rest.indexOf("**", start + 2);
6192
- if (end === -1) {
6193
- pushText(rest);
6194
- break;
6195
- }
6196
- pushText(rest.slice(0, start));
6197
- pushText(rest.slice(start + 2, end), [{ type: "bold" }]);
6198
- rest = rest.slice(end + 2);
6199
- }
6200
- return out;
6201
- }
6202
- function parseRichTextParagraphInlineMarkdown(text) {
6203
- return text.split("\n").flatMap((line, index) => {
6204
- const lineNodes = parseRichTextInlineMarkdown(line.trim());
6205
- return index === 0 ? lineNodes : [createHardBreakNode(), ...lineNodes];
6206
- });
6207
- }
6208
- /**
6209
- * Convert a plain string with a tiny markdown subset to canonical TipTap JSON.
6210
- *
6211
- * Double newlines create semantic paragraphs. Single newlines remain inside the
6212
- * current paragraph as TipTap `hardBreak` nodes for line-oriented content such
6213
- * as addresses, opening hours, and contact details.
6214
- */
6215
- function createRichTextDocFromMarkdown(markdown) {
6216
- const normalized = markdown.replace(/\r\n/g, "\n").trim();
6217
- if (!normalized) return {
6218
- type: "doc",
6219
- content: []
6220
- };
6221
- return {
6222
- type: "doc",
6223
- content: normalized.split(/\n{2,}/).map((paragraph) => paragraph.trim()).filter(Boolean).map((paragraph) => {
6224
- const inline = parseRichTextParagraphInlineMarkdown(paragraph);
6225
- return inline.length > 0 ? {
6226
- type: "paragraph",
6227
- content: inline
6228
- } : { type: "paragraph" };
6229
- })
6230
- };
6231
- }
6232
- var TipTapMarkSchema, TipTapNodeSchema, RichTextDocSchema;
6233
- var init_richTextSchema = __esmMin((() => {
6234
- init_typeGuards();
6235
- TipTapMarkSchema = z$1.object({
6236
- type: z$1.string(),
6237
- attrs: z$1.record(z$1.string(), z$1.unknown()).optional()
6238
- });
6239
- TipTapNodeSchema = z$1.lazy(() => z$1.object({
6240
- type: z$1.string(),
6241
- content: z$1.array(TipTapNodeSchema).optional(),
6242
- text: z$1.string().optional(),
6243
- attrs: z$1.record(z$1.string(), z$1.unknown()).optional(),
6244
- marks: z$1.array(TipTapMarkSchema).optional()
6245
- }));
6246
- z$1.union([TipTapNodeSchema, z$1.object({ doc: TipTapNodeSchema })]);
6247
- RichTextDocSchema = z$1.object({
6248
- type: z$1.literal("doc"),
6249
- content: z$1.array(TipTapNodeSchema)
6250
- });
6251
- }));
6252
- //#endregion
6253
- //#region ../blocks/src/system/runtime/nodes/richText-coerce.ts
6254
- function coerceRichTextDoc(value) {
6255
- const raw = unwrapRichTextRoot(value);
6256
- if (typeof raw === "string") return createRichTextDocFromMarkdown(raw);
6257
- if (isRecord$16(raw) && typeof raw.type === "string") return raw;
6258
- return null;
6259
- }
6260
- var init_richText_coerce = __esmMin((() => {
6261
- init_richTextSchema();
6262
- init_typeGuards();
6263
- }));
6264
- //#endregion
6265
- //#region ../blocks/src/system/runtime/nodes/renderInlineText.tsx
6266
- init_richText_coerce();
6267
- function renderInlineText(value) {
6268
- return value.map((run, index) => renderRun(run, index));
6269
- }
6270
- function renderRun(run, key) {
6271
- return (run.marks ?? []).reduceRight((child, mark, index) => renderMark(mark, `${String(key)}-${index}`, child), run.text);
6272
- }
6273
- function renderMark(mark, key, child) {
6274
- switch (mark.kind) {
6275
- case "strong": return /* @__PURE__ */ jsx("strong", { children: child }, key);
6276
- case "emphasis": return /* @__PURE__ */ jsx("em", { children: child }, key);
6277
- case "accent": return /* @__PURE__ */ jsx("span", {
6278
- className: `rb-inline-text-accent rb-inline-text-accent-${mark.tone}`,
6279
- children: child
6280
- }, key);
6281
- case "highlight": return /* @__PURE__ */ jsx("span", {
6282
- className: `rb-inline-text-highlight rb-inline-text-highlight-${mark.tone}`,
6283
- children: child
6284
- }, key);
6285
- }
6286
- }
6287
- //#endregion
6288
- //#region ../blocks/src/system/runtime/nodes/basic.tsx
6289
- const TextNode = ({ value, children, blockId: _blockId, blockKind: _blockKind, blockContent, fragmentRegistry: _fragmentRegistry, pathBase: _pathBase, inlineTextFallbackPath, ...rest }) => {
6290
- const inlineText = parseInlineTextFromUnknown(value);
6291
- if (inlineText.ok && !isInlineTextEmpty(inlineText.value)) return /* @__PURE__ */ jsx(Text$1, {
6292
- ...rest,
6293
- children: renderInlineText(inlineText.value)
6294
- });
6295
- const fallbackValue = inlineTextFallbackPath ? readStringPath(blockContent, inlineTextFallbackPath) : null;
6296
- return /* @__PURE__ */ jsx(Text$1, {
6297
- ...rest,
6298
- children: fallbackValue ?? textNodeContent(value) ?? children
6299
- });
6300
- };
6301
- function textNodeContent(value) {
6302
- if (value === null || value === void 0) return null;
6303
- if (typeof value === "string" || typeof value === "number") return value;
6304
- return null;
6305
- }
6306
- function readStringPath(source, path) {
6307
- const value = getAtPath(source, path);
6308
- return typeof value === "string" ? value : null;
6309
- }
6310
- const RichTextNode = ({ value, blockId: _blockId, blockKind: _blockKind, blockContent: _blockContent, fragmentRegistry: _fragmentRegistry, pathBase: _pathBase, ...rest }) => {
6311
- return /* @__PURE__ */ jsx(RichText, {
6312
- doc: coerceRichTextDoc(value) ?? void 0,
6313
- ...rest
6314
- });
6315
- };
6316
- const ButtonNode = ({ value, children, href, variantId = "primary", size = "md", disabled, type = "button", target, rel, linkRequired = false, blockId: _blockId, blockKind: _blockKind, blockContent: _blockContent, fragmentRegistry: _fragmentRegistry, pathBase: _pathBase, className, ...rest }) => {
6317
- const content = value ?? children;
6318
- if (!content) {
6319
- console.warn("[ButtonNode] No content to render - value and children are both empty");
6320
- return null;
6321
- }
6322
- const resolvedHref = typeof href === "string" ? href.trim() : "";
6323
- if (linkRequired && resolvedHref.length === 0) {
6324
- console.warn("[ButtonNode] Missing href for link-required button");
6325
- return null;
6326
- }
6327
- const resolvedVariantId = parseThemeButtonVariantId(variantId);
6328
- const combinedClassName = resolvedVariantId ? themeButtonClassName({
6329
- variant: resolvedVariantId,
6330
- size,
6331
- extraClassName: className
6332
- }) : className;
6333
- if (resolvedHref) return /* @__PURE__ */ jsx("a", {
6334
- href: resolvedHref,
6335
- target,
6336
- rel,
6337
- className: combinedClassName,
6338
- ...rest,
6339
- children: content
6340
- });
6341
- return /* @__PURE__ */ jsx("button", {
6342
- type,
6343
- disabled,
6344
- className: combinedClassName,
6345
- ...rest,
6346
- children: content
6347
- });
6348
- };
6349
- const LinkNode = ({ href, children, className, target, rel, linkRequired = false, blockId: _blockId, blockKind: _blockKind, blockContent: _blockContent, fragmentRegistry: _fragmentRegistry, pathBase: _pathBase, ...rest }) => {
6350
- if (!children) return null;
6351
- const resolvedHref = typeof href === "string" ? href.trim() : "";
6352
- if (resolvedHref.length === 0) {
6353
- if (linkRequired && true) console.warn("[LinkNode] Missing href for link-required link");
6354
- if (linkRequired) return null;
6355
- return /* @__PURE__ */ jsx("span", {
6356
- className,
6357
- ...rest,
6358
- children
6359
- });
6360
- }
6361
- return /* @__PURE__ */ jsx("a", {
6362
- href: resolvedHref,
6363
- className,
6364
- target,
6365
- rel,
6366
- ...rest,
6367
- children
6368
- });
6369
- };
6370
6222
  //#endregion
6371
6223
  //#region ../blocks/src/system/icons/svg.tsx
6372
6224
  function createIcon(displayName, children) {
@@ -7430,6 +7282,430 @@ function getIconComponent(name) {
7430
7282
  return getCtaIconComponent(name) ?? getSemanticIconComponent(name);
7431
7283
  }
7432
7284
  //#endregion
7285
+ //#region ../blocks/src/system/runtime/nodes/buttonAffordance.ts
7286
+ function normalize(value) {
7287
+ const trimmed = typeof value === "string" ? value.trim() : "";
7288
+ return trimmed.length > 0 ? trimmed : null;
7289
+ }
7290
+ /**
7291
+ * Resolve the trailing affordance a button should render. Node overrides
7292
+ * personality; returns `null` when nothing is configured.
7293
+ */
7294
+ function resolveButtonAffordance(input) {
7295
+ const nodeIcon = normalize(input.trailingIcon);
7296
+ if (nodeIcon) {
7297
+ const colorToken = normalize(input.trailingIconColorToken);
7298
+ return {
7299
+ iconId: nodeIcon,
7300
+ source: "node",
7301
+ ...colorToken ? { colorToken } : {}
7302
+ };
7303
+ }
7304
+ const personality = input.personalityAffordance;
7305
+ const personalityIcon = normalize(personality?.iconId);
7306
+ if (personality && personalityIcon) {
7307
+ const colorToken = normalize(personality.colorToken);
7308
+ return {
7309
+ iconId: personalityIcon,
7310
+ source: "personality",
7311
+ ...colorToken ? { colorToken } : {}
7312
+ };
7313
+ }
7314
+ return null;
7315
+ }
7316
+ const inlineTextMarkSchema = z$1.discriminatedUnion("kind", [
7317
+ z$1.object({ kind: z$1.literal("strong") }),
7318
+ z$1.object({ kind: z$1.literal("emphasis") }),
7319
+ z$1.object({
7320
+ kind: z$1.literal("accent"),
7321
+ tone: z$1.enum([
7322
+ "accent",
7323
+ "brand",
7324
+ "contrast"
7325
+ ])
7326
+ }),
7327
+ z$1.object({
7328
+ kind: z$1.literal("highlight"),
7329
+ tone: z$1.enum([
7330
+ "soft",
7331
+ "accent",
7332
+ "brand"
7333
+ ])
7334
+ })
7335
+ ]);
7336
+ const inlineTextRunSchema = z$1.object({
7337
+ text: z$1.string(),
7338
+ marks: z$1.array(inlineTextMarkSchema).optional()
7339
+ });
7340
+ z$1.array(inlineTextRunSchema);
7341
+ const MARK_ORDER = {
7342
+ strong: 0,
7343
+ emphasis: 1,
7344
+ accent: 2,
7345
+ highlight: 3
7346
+ };
7347
+ function inlineTextToPlainText(value) {
7348
+ return value.map((run) => run.text).join("");
7349
+ }
7350
+ function isInlineTextEmpty(value) {
7351
+ return inlineTextToPlainText(value).trim().length === 0;
7352
+ }
7353
+ function parseInlineTextFromUnknown(value) {
7354
+ if (!Array.isArray(value)) return {
7355
+ ok: false,
7356
+ error: { kind: "not-array" }
7357
+ };
7358
+ const runs = [];
7359
+ for (let index = 0; index < value.length; index += 1) {
7360
+ const parsed = inlineTextRunSchema.safeParse(value[index]);
7361
+ if (!parsed.success) return {
7362
+ ok: false,
7363
+ error: {
7364
+ kind: "invalid-run",
7365
+ index
7366
+ }
7367
+ };
7368
+ runs.push(parsed.data);
7369
+ }
7370
+ return {
7371
+ ok: true,
7372
+ value: normalizeInlineText(runs)
7373
+ };
7374
+ }
7375
+ function normalizeInlineText(value) {
7376
+ const normalized = [];
7377
+ for (const run of value) {
7378
+ if (run.text.length === 0) continue;
7379
+ const marks = normalizeInlineTextMarks(run.marks ?? []);
7380
+ const nextRun = marks.length > 0 ? {
7381
+ text: run.text,
7382
+ marks
7383
+ } : { text: run.text };
7384
+ const previous = normalized[normalized.length - 1];
7385
+ if (previous && inlineTextMarksEqual(previous.marks ?? [], nextRun.marks ?? [])) {
7386
+ normalized[normalized.length - 1] = previous.marks && previous.marks.length > 0 ? {
7387
+ text: previous.text + nextRun.text,
7388
+ marks: previous.marks
7389
+ } : { text: previous.text + nextRun.text };
7390
+ continue;
7391
+ }
7392
+ normalized.push(nextRun);
7393
+ }
7394
+ return normalized;
7395
+ }
7396
+ function normalizeInlineTextMarks(marks) {
7397
+ let strong = null;
7398
+ let emphasis = null;
7399
+ let accent = null;
7400
+ let highlight = null;
7401
+ for (const mark of marks) switch (mark.kind) {
7402
+ case "strong":
7403
+ strong = { kind: "strong" };
7404
+ break;
7405
+ case "emphasis":
7406
+ emphasis = { kind: "emphasis" };
7407
+ break;
7408
+ case "accent":
7409
+ accent = {
7410
+ kind: "accent",
7411
+ tone: mark.tone
7412
+ };
7413
+ break;
7414
+ case "highlight":
7415
+ highlight = {
7416
+ kind: "highlight",
7417
+ tone: mark.tone
7418
+ };
7419
+ break;
7420
+ }
7421
+ return [
7422
+ strong,
7423
+ emphasis,
7424
+ accent,
7425
+ highlight
7426
+ ].filter((mark) => mark !== null).sort((left, right) => MARK_ORDER[left.kind] - MARK_ORDER[right.kind]);
7427
+ }
7428
+ function inlineTextMarksEqual(left, right) {
7429
+ const normalizedLeft = normalizeInlineTextMarks(left);
7430
+ const normalizedRight = normalizeInlineTextMarks(right);
7431
+ if (normalizedLeft.length !== normalizedRight.length) return false;
7432
+ return normalizedLeft.every((mark, index) => inlineTextMarkEqual(mark, normalizedRight[index]));
7433
+ }
7434
+ function inlineTextMarkEqual(left, right) {
7435
+ if (!right || left.kind !== right.kind) return false;
7436
+ switch (left.kind) {
7437
+ case "strong":
7438
+ case "emphasis": return true;
7439
+ case "accent": return right.kind === "accent" && left.tone === right.tone;
7440
+ case "highlight": return right.kind === "highlight" && left.tone === right.tone;
7441
+ }
7442
+ }
7443
+ //#endregion
7444
+ //#region ../blocks/src/lib/typeGuards.ts
7445
+ /**
7446
+ * Strict record guard: excludes null, primitives, and arrays.
7447
+ */
7448
+ function isRecord$18(value) {
7449
+ return typeof value === "object" && value !== null && !Array.isArray(value);
7450
+ }
7451
+ var init_typeGuards = __esmMin((() => {}));
7452
+ /**
7453
+ * Permissive unwrap for a value known to be the root of a rich-text field.
7454
+ *
7455
+ * Producers should emit the canonical unwrapped form `{ type: 'doc', content: [...] }`,
7456
+ * but two legacy shapes still appear in older data and pre-Phase-1 fixtures:
7457
+ *
7458
+ * - `{ doc: <typed-doc> }` — pre-migration DB storage.
7459
+ * - `{ doc: <typed-doc>, html, plain }` — pre-Phase-1 dummy-content output.
7460
+ *
7461
+ * This helper is the single right place to tolerate either shape at a known
7462
+ * rich-text root (transforms, coercion, validators that operate on rich text).
7463
+ * The strictness sits on the inner node's `type === 'doc'`, which prevents
7464
+ * misidentifying random objects that happen to carry a field named `doc`.
7465
+ *
7466
+ * Returns the inner doc node when the input matches a legacy shape, otherwise
7467
+ * returns the input unchanged.
7468
+ *
7469
+ * For deep structural traversal where any nested key might be named `doc`
7470
+ * (and unwrapping would be incorrect), use the strict `isDocWrapper` private
7471
+ * helper inside `@riverbankcms/blocks/bindings`.
7472
+ */
7473
+ function unwrapRichTextRoot(value) {
7474
+ if (!isRecord$18(value)) return value;
7475
+ if (!("doc" in value)) return value;
7476
+ const inner = value.doc;
7477
+ if (isRecord$18(inner) && inner.type === "doc") return inner;
7478
+ return value;
7479
+ }
7480
+ function createHardBreakNode() {
7481
+ return { type: "hardBreak" };
7482
+ }
7483
+ /**
7484
+ * Parse a small markdown subset into TipTap inline nodes.
7485
+ *
7486
+ * This intentionally supports only bold (`**text**`) because the SDK/content
7487
+ * import paths use it for lightweight default content, not full markdown.
7488
+ */
7489
+ function parseRichTextInlineMarkdown(text) {
7490
+ const out = [];
7491
+ const pushText = (value, marks) => {
7492
+ if (!value) return;
7493
+ out.push(marks && marks.length > 0 ? {
7494
+ type: "text",
7495
+ text: value,
7496
+ marks
7497
+ } : {
7498
+ type: "text",
7499
+ text: value
7500
+ });
7501
+ };
7502
+ let rest = text;
7503
+ while (rest.length > 0) {
7504
+ const start = rest.indexOf("**");
7505
+ if (start === -1) {
7506
+ pushText(rest);
7507
+ break;
7508
+ }
7509
+ const end = rest.indexOf("**", start + 2);
7510
+ if (end === -1) {
7511
+ pushText(rest);
7512
+ break;
7513
+ }
7514
+ pushText(rest.slice(0, start));
7515
+ pushText(rest.slice(start + 2, end), [{ type: "bold" }]);
7516
+ rest = rest.slice(end + 2);
7517
+ }
7518
+ return out;
7519
+ }
7520
+ function parseRichTextParagraphInlineMarkdown(text) {
7521
+ return text.split("\n").flatMap((line, index) => {
7522
+ const lineNodes = parseRichTextInlineMarkdown(line.trim());
7523
+ return index === 0 ? lineNodes : [createHardBreakNode(), ...lineNodes];
7524
+ });
7525
+ }
7526
+ /**
7527
+ * Convert a plain string with a tiny markdown subset to canonical TipTap JSON.
7528
+ *
7529
+ * Double newlines create semantic paragraphs. Single newlines remain inside the
7530
+ * current paragraph as TipTap `hardBreak` nodes for line-oriented content such
7531
+ * as addresses, opening hours, and contact details.
7532
+ */
7533
+ function createRichTextDocFromMarkdown(markdown) {
7534
+ const normalized = markdown.replace(/\r\n/g, "\n").trim();
7535
+ if (!normalized) return {
7536
+ type: "doc",
7537
+ content: []
7538
+ };
7539
+ return {
7540
+ type: "doc",
7541
+ content: normalized.split(/\n{2,}/).map((paragraph) => paragraph.trim()).filter(Boolean).map((paragraph) => {
7542
+ const inline = parseRichTextParagraphInlineMarkdown(paragraph);
7543
+ return inline.length > 0 ? {
7544
+ type: "paragraph",
7545
+ content: inline
7546
+ } : { type: "paragraph" };
7547
+ })
7548
+ };
7549
+ }
7550
+ var TipTapMarkSchema, TipTapNodeSchema, RichTextDocSchema;
7551
+ var init_richTextSchema = __esmMin((() => {
7552
+ init_typeGuards();
7553
+ TipTapMarkSchema = z$1.object({
7554
+ type: z$1.string(),
7555
+ attrs: z$1.record(z$1.string(), z$1.unknown()).optional()
7556
+ });
7557
+ TipTapNodeSchema = z$1.lazy(() => z$1.object({
7558
+ type: z$1.string(),
7559
+ content: z$1.array(TipTapNodeSchema).optional(),
7560
+ text: z$1.string().optional(),
7561
+ attrs: z$1.record(z$1.string(), z$1.unknown()).optional(),
7562
+ marks: z$1.array(TipTapMarkSchema).optional()
7563
+ }));
7564
+ z$1.union([TipTapNodeSchema, z$1.object({ doc: TipTapNodeSchema })]);
7565
+ RichTextDocSchema = z$1.object({
7566
+ type: z$1.literal("doc"),
7567
+ content: z$1.array(TipTapNodeSchema)
7568
+ });
7569
+ }));
7570
+ //#endregion
7571
+ //#region ../blocks/src/system/runtime/nodes/richText-coerce.ts
7572
+ function coerceRichTextDoc(value) {
7573
+ const raw = unwrapRichTextRoot(value);
7574
+ if (typeof raw === "string") return createRichTextDocFromMarkdown(raw);
7575
+ if (isRecord$18(raw) && typeof raw.type === "string") return raw;
7576
+ return null;
7577
+ }
7578
+ var init_richText_coerce = __esmMin((() => {
7579
+ init_richTextSchema();
7580
+ init_typeGuards();
7581
+ }));
7582
+ //#endregion
7583
+ //#region ../blocks/src/system/runtime/nodes/renderInlineText.tsx
7584
+ init_richText_coerce();
7585
+ function renderInlineText(value) {
7586
+ return value.map((run, index) => renderRun(run, index));
7587
+ }
7588
+ function renderRun(run, key) {
7589
+ return (run.marks ?? []).reduceRight((child, mark, index) => renderMark(mark, `${String(key)}-${index}`, child), run.text);
7590
+ }
7591
+ function renderMark(mark, key, child) {
7592
+ switch (mark.kind) {
7593
+ case "strong": return /* @__PURE__ */ jsx("strong", { children: child }, key);
7594
+ case "emphasis": return /* @__PURE__ */ jsx("em", { children: child }, key);
7595
+ case "accent": return /* @__PURE__ */ jsx("span", {
7596
+ className: `rb-inline-text-accent rb-inline-text-accent-${mark.tone}`,
7597
+ children: child
7598
+ }, key);
7599
+ case "highlight": return /* @__PURE__ */ jsx("span", {
7600
+ className: `rb-inline-text-highlight rb-inline-text-highlight-${mark.tone}`,
7601
+ children: child
7602
+ }, key);
7603
+ }
7604
+ }
7605
+ //#endregion
7606
+ //#region ../blocks/src/system/runtime/nodes/basic.tsx
7607
+ const TextNode = ({ value, children, blockId: _blockId, blockKind: _blockKind, blockContent, fragmentRegistry: _fragmentRegistry, pathBase: _pathBase, inlineTextFallbackPath, ...rest }) => {
7608
+ const inlineText = parseInlineTextFromUnknown(value);
7609
+ if (inlineText.ok && !isInlineTextEmpty(inlineText.value)) return /* @__PURE__ */ jsx(Text$1, {
7610
+ ...rest,
7611
+ children: renderInlineText(inlineText.value)
7612
+ });
7613
+ const fallbackValue = inlineTextFallbackPath ? readStringPath(blockContent, inlineTextFallbackPath) : null;
7614
+ return /* @__PURE__ */ jsx(Text$1, {
7615
+ ...rest,
7616
+ children: fallbackValue ?? textNodeContent(value) ?? children
7617
+ });
7618
+ };
7619
+ function textNodeContent(value) {
7620
+ if (value === null || value === void 0) return null;
7621
+ if (typeof value === "string" || typeof value === "number") return value;
7622
+ return null;
7623
+ }
7624
+ function readStringPath(source, path) {
7625
+ const value = getAtPath(source, path);
7626
+ return typeof value === "string" ? value : null;
7627
+ }
7628
+ const RichTextNode = ({ value, blockId: _blockId, blockKind: _blockKind, blockContent: _blockContent, fragmentRegistry: _fragmentRegistry, pathBase: _pathBase, ...rest }) => {
7629
+ return /* @__PURE__ */ jsx(RichText, {
7630
+ doc: coerceRichTextDoc(value) ?? void 0,
7631
+ ...rest
7632
+ });
7633
+ };
7634
+ /**
7635
+ * Render the resolved trailing affordance icon. Colour is applied via a theme
7636
+ * CSS var so it recolours with the palette; the icon stroke uses `currentColor`.
7637
+ */
7638
+ function renderTrailingAffordanceIcon(affordance) {
7639
+ if (!affordance) return null;
7640
+ const Icon = getIconComponent(affordance.iconId);
7641
+ if (!Icon) return null;
7642
+ return /* @__PURE__ */ jsx(Icon, {
7643
+ "aria-hidden": true,
7644
+ className: "rb-ml-2 rb-h-4 rb-w-4 rb-inline-block",
7645
+ style: affordance.colorToken ? { color: `rgb(var(--tb-${affordance.colorToken}))` } : void 0
7646
+ });
7647
+ }
7648
+ const ButtonNode = ({ value, children, href, variantId = "primary", size = "md", disabled, type = "button", target, rel, linkRequired = false, trailingIcon, trailingIconColorToken, personalityAffordance, blockId: _blockId, blockKind: _blockKind, blockContent: _blockContent, fragmentRegistry: _fragmentRegistry, pathBase: _pathBase, className, ...rest }) => {
7649
+ const content = value ?? children;
7650
+ if (!content) {
7651
+ console.warn("[ButtonNode] No content to render - value and children are both empty");
7652
+ return null;
7653
+ }
7654
+ const affordanceIcon = renderTrailingAffordanceIcon(resolveButtonAffordance({
7655
+ trailingIcon,
7656
+ trailingIconColorToken,
7657
+ personalityAffordance
7658
+ }));
7659
+ const resolvedHref = typeof href === "string" ? href.trim() : "";
7660
+ if (linkRequired && resolvedHref.length === 0) {
7661
+ console.warn("[ButtonNode] Missing href for link-required button");
7662
+ return null;
7663
+ }
7664
+ const extraClassName = affordanceIcon ? [className, AFFORDANCE_SUPPRESS_CLASS].filter(Boolean).join(" ") : className;
7665
+ const resolvedVariantId = parseThemeButtonVariantId(variantId);
7666
+ const combinedClassName = resolvedVariantId ? themeButtonClassName({
7667
+ variant: resolvedVariantId,
7668
+ size,
7669
+ extraClassName
7670
+ }) : extraClassName;
7671
+ if (resolvedHref) return /* @__PURE__ */ jsxs("a", {
7672
+ href: resolvedHref,
7673
+ target,
7674
+ rel,
7675
+ className: combinedClassName,
7676
+ ...rest,
7677
+ children: [content, affordanceIcon]
7678
+ });
7679
+ return /* @__PURE__ */ jsxs("button", {
7680
+ type,
7681
+ disabled,
7682
+ className: combinedClassName,
7683
+ ...rest,
7684
+ children: [content, affordanceIcon]
7685
+ });
7686
+ };
7687
+ const LinkNode = ({ href, children, className, target, rel, linkRequired = false, blockId: _blockId, blockKind: _blockKind, blockContent: _blockContent, fragmentRegistry: _fragmentRegistry, pathBase: _pathBase, ...rest }) => {
7688
+ if (!children) return null;
7689
+ const resolvedHref = typeof href === "string" ? href.trim() : "";
7690
+ if (resolvedHref.length === 0) {
7691
+ if (linkRequired && true) console.warn("[LinkNode] Missing href for link-required link");
7692
+ if (linkRequired) return null;
7693
+ return /* @__PURE__ */ jsx("span", {
7694
+ className,
7695
+ ...rest,
7696
+ children
7697
+ });
7698
+ }
7699
+ return /* @__PURE__ */ jsx("a", {
7700
+ href: resolvedHref,
7701
+ className,
7702
+ target,
7703
+ rel,
7704
+ ...rest,
7705
+ children
7706
+ });
7707
+ };
7708
+ //#endregion
7433
7709
  //#region ../blocks/src/system/icons/ids.ts
7434
7710
  const GENERATED_ICON_SET_ID_PATTERN = /^generated-icon-set:[a-z0-9][a-z0-9:_-]{0,107}$/u;
7435
7711
  const GENERATED_ICON_ASSET_ID_PATTERN = /^generated-icon-asset:[a-z0-9][a-z0-9:_-]{0,105}$/u;
@@ -7464,7 +7740,7 @@ function parseSiteIconStyleGuideVersionId(value) {
7464
7740
  //#endregion
7465
7741
  //#region ../blocks/src/system/icons/value.ts
7466
7742
  const NO_BLOCK_ICON_VALUE = { kind: "none" };
7467
- function isRecord$15(value) {
7743
+ function isRecord$17(value) {
7468
7744
  return typeof value === "object" && value !== null && !Array.isArray(value);
7469
7745
  }
7470
7746
  function parseBlockIconValue(value) {
@@ -7472,7 +7748,7 @@ function parseBlockIconValue(value) {
7472
7748
  kind: "semantic",
7473
7749
  iconId: value
7474
7750
  };
7475
- if (!isRecord$15(value)) return NO_BLOCK_ICON_VALUE;
7751
+ if (!isRecord$17(value)) return NO_BLOCK_ICON_VALUE;
7476
7752
  switch (value.kind) {
7477
7753
  case "none": return NO_BLOCK_ICON_VALUE;
7478
7754
  case "semantic": return isSemanticIconId(value.iconId) ? {
@@ -7545,7 +7821,7 @@ function buildGeneratedBlockIconRenderAssetLookupFromUnknown(value) {
7545
7821
  if (!Array.isArray(value)) return { kind: "invalid_asset_list" };
7546
7822
  const inputs = [];
7547
7823
  for (const [index, item] of value.entries()) {
7548
- if (!isRecord$15(item)) return {
7824
+ if (!isRecord$17(item)) return {
7549
7825
  kind: "invalid_asset_entry",
7550
7826
  index,
7551
7827
  reason: "not_object"
@@ -7663,11 +7939,11 @@ function resolveFeatureCardGeneratedIconSizePx(value) {
7663
7939
  const parsed = parseFeatureCardGeneratedIconSizePx(value);
7664
7940
  return parsed.ok ? parsed.value : unsafeAsFeatureCardGeneratedIconSizePx(FEATURE_CARD_GENERATED_ICON_SIZE_PX.default);
7665
7941
  }
7666
- function isRecord$14(value) {
7942
+ function isRecord$16(value) {
7667
7943
  return typeof value === "object" && value !== null && !Array.isArray(value);
7668
7944
  }
7669
7945
  function toPlainTextFromTipTap(value) {
7670
- if (!isRecord$14(value)) return "";
7946
+ if (!isRecord$16(value)) return "";
7671
7947
  if (typeof value.text === "string") return value.text;
7672
7948
  const content = value.content;
7673
7949
  if (!Array.isArray(content)) return "";
@@ -8819,6 +9095,78 @@ var init_spinner$1 = __esmMin((() => {
8819
9095
  init_clsx();
8820
9096
  }));
8821
9097
  //#endregion
9098
+ //#region ../blocks/src/system/runtime/nodes/svg.tsx
9099
+ init_spinner$1();
9100
+ /**
9101
+ * Turn paint props into a CSS style object. Colour values pass through as-is so
9102
+ * they may reference theme tokens via `var()`, which only resolves in a CSS
9103
+ * property context (not in a bare presentation attribute).
9104
+ */
9105
+ function paintStyle(shape) {
9106
+ const style = {};
9107
+ if (shape.fill !== void 0) style.fill = shape.fill;
9108
+ if (shape.stroke !== void 0) style.stroke = shape.stroke;
9109
+ if (shape.strokeWidth !== void 0) style.strokeWidth = shape.strokeWidth;
9110
+ if (shape.fillOpacity !== void 0) style.fillOpacity = shape.fillOpacity;
9111
+ if (shape.strokeOpacity !== void 0) style.strokeOpacity = shape.strokeOpacity;
9112
+ if (shape.strokeLinecap !== void 0) style.strokeLinecap = shape.strokeLinecap;
9113
+ if (shape.strokeLinejoin !== void 0) style.strokeLinejoin = shape.strokeLinejoin;
9114
+ if (shape.strokeDasharray !== void 0) style.strokeDasharray = shape.strokeDasharray;
9115
+ return style;
9116
+ }
9117
+ function renderShape(shape, key) {
9118
+ const style = paintStyle(shape);
9119
+ switch (shape.kind) {
9120
+ case "path": return /* @__PURE__ */ jsx("path", {
9121
+ d: shape.d,
9122
+ style
9123
+ }, key);
9124
+ case "ellipse": return /* @__PURE__ */ jsx("ellipse", {
9125
+ cx: shape.cx,
9126
+ cy: shape.cy,
9127
+ rx: shape.rx,
9128
+ ry: shape.ry,
9129
+ style
9130
+ }, key);
9131
+ case "circle": return /* @__PURE__ */ jsx("circle", {
9132
+ cx: shape.cx,
9133
+ cy: shape.cy,
9134
+ r: shape.r,
9135
+ style
9136
+ }, key);
9137
+ case "rect": return /* @__PURE__ */ jsx("rect", {
9138
+ x: shape.x,
9139
+ y: shape.y,
9140
+ width: shape.width,
9141
+ height: shape.height,
9142
+ rx: shape.rx,
9143
+ ry: shape.ry,
9144
+ style
9145
+ }, key);
9146
+ case "line": return /* @__PURE__ */ jsx("line", {
9147
+ x1: shape.x1,
9148
+ y1: shape.y1,
9149
+ x2: shape.x2,
9150
+ y2: shape.y2,
9151
+ style
9152
+ }, key);
9153
+ default: return null;
9154
+ }
9155
+ }
9156
+ const SvgNode = ({ blockId: _blockId, blockKind: _blockKind, blockContent: _blockContent, fragmentRegistry: _fragmentRegistry, pathBase: _pathBase, viewBox, width, height, className, style, ariaHidden = true, shapes }) => {
9157
+ return /* @__PURE__ */ jsx("svg", {
9158
+ viewBox,
9159
+ width,
9160
+ height,
9161
+ className,
9162
+ style,
9163
+ "aria-hidden": ariaHidden,
9164
+ xmlns: "http://www.w3.org/2000/svg",
9165
+ fill: "none",
9166
+ children: (Array.isArray(shapes) ? shapes : []).map((shape, index) => renderShape(shape, index))
9167
+ });
9168
+ };
9169
+ //#endregion
8822
9170
  //#region ../blocks/src/contracts/runtime.ts
8823
9171
  function decodeSuccess(value) {
8824
9172
  return {
@@ -8985,7 +9333,7 @@ function successSubmissionFeedback(message) {
8985
9333
  message
8986
9334
  };
8987
9335
  }
8988
- function isRecord$12(value) {
9336
+ function isRecord$14(value) {
8989
9337
  return typeof value === "object" && value !== null && !Array.isArray(value);
8990
9338
  }
8991
9339
  function deepEqualJsonValue(left, right) {
@@ -8995,8 +9343,8 @@ function deepEqualJsonValue(left, right) {
8995
9343
  if (left.length !== right.length) return false;
8996
9344
  return left.every((item, index) => deepEqualJsonValue(item, right[index]));
8997
9345
  }
8998
- if (isRecord$12(left) || isRecord$12(right)) {
8999
- if (!isRecord$12(left) || !isRecord$12(right)) return false;
9346
+ if (isRecord$14(left) || isRecord$14(right)) {
9347
+ if (!isRecord$14(left) || !isRecord$14(right)) return false;
9000
9348
  const leftKeys = Object.keys(left).sort();
9001
9349
  if (!deepEqualJsonValue(leftKeys, Object.keys(right).sort())) return false;
9002
9350
  return leftKeys.every((key) => deepEqualJsonValue(left[key], right[key]));
@@ -9153,12 +9501,12 @@ function resolveBookingSiteId(siteId, form) {
9153
9501
  return siteId || form?.siteId || "";
9154
9502
  }
9155
9503
  function normalizeBookingFormConfig(form) {
9156
- if (!isRecord$11(form)) return null;
9504
+ if (!isRecord$13(form)) return null;
9157
9505
  const id = readNonEmptyString(form.id);
9158
9506
  const name = readNonEmptyString(form.name);
9159
9507
  if (!id || !name) return null;
9160
- const schemaSource = isRecord$11(form.schema) ? form.schema : isRecord$11(form.schemaJson) ? form.schemaJson : null;
9161
- const settingsSource = isRecord$11(form.settings) ? form.settings : isRecord$11(form.settingsJson) ? form.settingsJson : null;
9508
+ const schemaSource = isRecord$13(form.schema) ? form.schema : isRecord$13(form.schemaJson) ? form.schemaJson : null;
9509
+ const settingsSource = isRecord$13(form.settings) ? form.settings : isRecord$13(form.settingsJson) ? form.settingsJson : null;
9162
9510
  return {
9163
9511
  id,
9164
9512
  name,
@@ -9178,8 +9526,8 @@ function normalizeBookingServices(services) {
9178
9526
  };
9179
9527
  if (!services) return [];
9180
9528
  if (Array.isArray(services)) return services.filter(isBookingFormService).map(normalizeService);
9181
- if (isRecord$11(services) && "services" in services) return Array.isArray(services.services) ? services.services.filter(isBookingFormService).map(normalizeService) : [];
9182
- return isRecord$11(services) ? Object.values(services).filter(isBookingFormService).map(normalizeService) : [];
9529
+ if (isRecord$13(services) && "services" in services) return Array.isArray(services.services) ? services.services.filter(isBookingFormService).map(normalizeService) : [];
9530
+ return isRecord$13(services) ? Object.values(services).filter(isBookingFormService).map(normalizeService) : [];
9183
9531
  }
9184
9532
  function normalizeBookingSchema(value) {
9185
9533
  if (!value) return void 0;
@@ -9190,7 +9538,7 @@ function normalizeBookingSchema(value) {
9190
9538
  };
9191
9539
  }
9192
9540
  function readBookingFormField(value) {
9193
- if (!isRecord$11(value)) return null;
9541
+ if (!isRecord$13(value)) return null;
9194
9542
  const id = readNonEmptyString(value.id);
9195
9543
  const label = readNonEmptyString(value.label);
9196
9544
  const type = readBookingFieldType(value.type);
@@ -9234,7 +9582,7 @@ function readBookingFieldOptions(value) {
9234
9582
  return options.length > 0 ? options : void 0;
9235
9583
  }
9236
9584
  function readBookingFieldOption(value) {
9237
- if (!isRecord$11(value)) return null;
9585
+ if (!isRecord$13(value)) return null;
9238
9586
  const optionValue = readNonEmptyString(value.value);
9239
9587
  const label = readNonEmptyString(value.label);
9240
9588
  return optionValue && label ? {
@@ -9254,7 +9602,7 @@ function normalizeBookingSettings(value) {
9254
9602
  };
9255
9603
  }
9256
9604
  function isBookingFormService(value) {
9257
- return isRecord$11(value) && typeof value.id === "string" && typeof value.siteId === "string" && typeof value.title === "string";
9605
+ return isRecord$13(value) && typeof value.id === "string" && typeof value.siteId === "string" && typeof value.title === "string";
9258
9606
  }
9259
9607
  function collectBookingCustomFields(data) {
9260
9608
  const customFields = {};
@@ -9304,7 +9652,7 @@ function readStringArray(value) {
9304
9652
  const strings = value.filter((item) => typeof item === "string");
9305
9653
  return strings.length > 0 ? strings : void 0;
9306
9654
  }
9307
- function isRecord$11(value) {
9655
+ function isRecord$13(value) {
9308
9656
  return typeof value === "object" && value !== null;
9309
9657
  }
9310
9658
  function getBookingServicePaymentSelectionMode(service) {
@@ -9798,7 +10146,6 @@ var init_booking_form_interactive = __esmMin((() => {
9798
10146
  }));
9799
10147
  //#endregion
9800
10148
  //#region ../blocks/src/system/runtime/nodes/booking-form.server.tsx
9801
- init_spinner$1();
9802
10149
  init_booking_form_interactive();
9803
10150
  /**
9804
10151
  * Server-safe placeholder for booking form.
@@ -10256,11 +10603,11 @@ var init_shared$5 = __esmMin((() => {
10256
10603
  }));
10257
10604
  //#endregion
10258
10605
  //#region ../blocks/src/system/runtime/nodes/events/shared/destination.ts
10259
- function isRecord$10(value) {
10606
+ function isRecord$12(value) {
10260
10607
  return typeof value === "object" && value !== null && !Array.isArray(value);
10261
10608
  }
10262
10609
  function isRuntimeEventDestination(value) {
10263
- if (!isRecord$10(value) || typeof value.kind !== "string") return false;
10610
+ if (!isRecord$12(value) || typeof value.kind !== "string") return false;
10264
10611
  if (value.kind === "native") return (value.mode === "cms-managed" || value.mode === "system-managed") && typeof value.path === "string";
10265
10612
  return value.kind === "external" && typeof value.url === "string" && typeof value.label === "string";
10266
10613
  }
@@ -10323,15 +10670,15 @@ function resolveRuntimeEventPricing(event) {
10323
10670
  function readCurrency(value) {
10324
10671
  return typeof value === "string" && value.trim().length > 0 ? value : DEFAULT_EVENT_CURRENCY$1;
10325
10672
  }
10326
- function isRecord$9(value) {
10673
+ function isRecord$11(value) {
10327
10674
  return typeof value === "object" && value !== null && !Array.isArray(value);
10328
10675
  }
10329
10676
  function isPublicEventPricing(value) {
10330
- if (!isRecord$9(value) || typeof value.kind !== "string") return false;
10677
+ if (!isRecord$11(value) || typeof value.kind !== "string") return false;
10331
10678
  return value.kind === "drop_in" || value.kind === "free_registration" || value.kind === "single_paid" || value.kind === "sliding_scale" || value.kind === "ticket_types" || value.kind === "course" || value.kind === "external";
10332
10679
  }
10333
10680
  function isPublicEventTicketType(value) {
10334
- return isRecord$9(value) && typeof value.id === "string";
10681
+ return isRecord$11(value) && typeof value.id === "string";
10335
10682
  }
10336
10683
  function readTicketTypePriceDisplay(value, currency) {
10337
10684
  const display = readLegacyPriceDisplay(value, currency);
@@ -10341,7 +10688,7 @@ function readTicketTypePriceDisplay(value, currency) {
10341
10688
  } : display;
10342
10689
  }
10343
10690
  function readLegacyPriceDisplay(value, currency) {
10344
- if (!isRecord$9(value) || typeof value.kind !== "string") return {
10691
+ if (!isRecord$11(value) || typeof value.kind !== "string") return {
10345
10692
  kind: "unavailable",
10346
10693
  currency
10347
10694
  };
@@ -10393,7 +10740,7 @@ function readLegacyPriceDisplay(value, currency) {
10393
10740
  kind: "unavailable",
10394
10741
  currency: displayCurrency
10395
10742
  };
10396
- case "course": return isRecord$9(value.display) ? {
10743
+ case "course": return isRecord$11(value.display) ? {
10397
10744
  kind: "course",
10398
10745
  display: readCoursePriceDisplay(value.display, displayCurrency)
10399
10746
  } : {
@@ -11040,6 +11387,40 @@ function getEventAvailability(event) {
11040
11387
  isFull: false
11041
11388
  };
11042
11389
  }
11390
+ /**
11391
+ * Derive the three-state availability status (available / filling / waitlist)
11392
+ * plus a short pill label. Builds on {@link getEventAvailability} so the
11393
+ * capacity math (availableSpots with a `capacity - registeredCount` fallback)
11394
+ * stays consistent with the binary helper used elsewhere.
11395
+ */
11396
+ function getEventAvailabilityStatus(event, options) {
11397
+ const threshold = options?.fillingThreshold ?? 2;
11398
+ const { available, isFull } = getEventAvailability(event);
11399
+ if (available == null) return {
11400
+ status: "available",
11401
+ available: null,
11402
+ isFull: false,
11403
+ label: null
11404
+ };
11405
+ if (isFull) return {
11406
+ status: "waitlist",
11407
+ available: 0,
11408
+ isFull: true,
11409
+ label: event.waitlistEnabled ? "Waitlist" : "Full"
11410
+ };
11411
+ if (available <= threshold) return {
11412
+ status: "filling",
11413
+ available,
11414
+ isFull: false,
11415
+ label: `${available} left`
11416
+ };
11417
+ return {
11418
+ status: "available",
11419
+ available,
11420
+ isFull: false,
11421
+ label: `${available} places`
11422
+ };
11423
+ }
11043
11424
  var init_eventCapacity = __esmMin((() => {}));
11044
11425
  //#endregion
11045
11426
  //#region ../blocks/src/system/runtime/nodes/events/shared/utils.ts
@@ -12472,13 +12853,15 @@ var cardVariantRoleValues, boxlessCardVariantValue, legacyCardVariantRoleAliases
12472
12853
  });
12473
12854
  cardSystemSchema = z$1.object({ variants: z$1.array(cardVariantSchema).min(1).max(3) });
12474
12855
  }));
12475
- var init_constants$1 = __esmMin((() => {})), init_generateDefaultCardSystem = __esmMin((() => {})), init_contextualColors = __esmMin((() => {})), init_generateCardCss = __esmMin((() => {
12856
+ var init_constants$1 = __esmMin((() => {})), init_generateDefaultCardSystem = __esmMin((() => {})), init_generateCardCss = __esmMin((() => {
12476
12857
  init_resolver$1();
12477
12858
  init_constants$1();
12478
12859
  init_generateDefaultCardSystem();
12479
- init_contextualColors();
12860
+ init_surfaces();
12861
+ }));
12862
+ var init_core$1 = __esmMin((() => {
12863
+ init_surfaces();
12480
12864
  }));
12481
- var init_core$1 = __esmMin((() => {}));
12482
12865
  //#endregion
12483
12866
  //#region ../theme-core/src/cards/index.ts
12484
12867
  var init_cards = __esmMin((() => {
@@ -13788,8 +14171,11 @@ var init_builder$2 = __esmMin((() => {
13788
14171
  }));
13789
14172
  //#endregion
13790
14173
  //#region ../blocks/src/system/blocks/events/shared/layout.ts
13791
- function eventSectionHeaderLayoutNodes() {
13792
- return [text({ as: "h2" }, bind("content.heading"), when("content.heading", { authoringPresence: recoverEmptyHeadingWhenActive })), richText({ className: "rb-prose rb-max-w-none" }, bind("content.description"), when("content.description", { authoringPresence: recoverEmptyDescriptionWhenActive }))];
14174
+ function eventSectionHeaderLayoutNodes(options = {}) {
14175
+ const headingNode = text({ as: "h2" }, bind("content.heading"), when("content.heading", { authoringPresence: recoverEmptyHeadingWhenActive }));
14176
+ const descriptionNode = richText({ className: "rb-prose rb-max-w-none" }, bind("content.description"), when("content.description", { authoringPresence: recoverEmptyDescriptionWhenActive }));
14177
+ if (options.splitClassName) return [el("div", { className: options.splitClassName }, [headingNode, descriptionNode])];
14178
+ return [headingNode, descriptionNode];
13793
14179
  }
13794
14180
  var recoverEmptyHeadingWhenActive, recoverEmptyDescriptionWhenActive;
13795
14181
  var init_layout = __esmMin((() => {
@@ -13837,7 +14223,8 @@ var init_events$1 = __esmMin((() => {
13837
14223
  "combined",
13838
14224
  "calendar",
13839
14225
  "list",
13840
- "timetable"
14226
+ "timetable",
14227
+ "week-board"
13841
14228
  ];
13842
14229
  eventCalendarDefaultViewValues = ["month", "week"];
13843
14230
  eventCalendarListLayoutValues = [
@@ -16475,6 +16862,96 @@ var init_all = __esmMin((() => {
16475
16862
  init_PaletteCard();
16476
16863
  }));
16477
16864
  //#endregion
16865
+ //#region ../theme-core/src/palette/colors.ts
16866
+ function normalizePaletteHex(value) {
16867
+ if (!NORMALIZABLE_HEX_REGEX.test(value)) return null;
16868
+ const normalized = value.toLowerCase();
16869
+ if (normalized.length === 7) return normalized;
16870
+ const triplet = normalized.slice(1);
16871
+ const red = triplet.charAt(0);
16872
+ const green = triplet.charAt(1);
16873
+ const blue = triplet.charAt(2);
16874
+ return `#${red}${red}${green}${green}${blue}${blue}`;
16875
+ }
16876
+ function paletteColorsFromEntries(entries) {
16877
+ const values = {};
16878
+ for (const entry of entries) {
16879
+ const parsedRole = paletteTokenNameSchema.safeParse(entry.name);
16880
+ if (!parsedRole.success) return {
16881
+ ok: false,
16882
+ error: {
16883
+ kind: "unknown-role",
16884
+ role: entry.name
16885
+ }
16886
+ };
16887
+ const role = parsedRole.data;
16888
+ if (values[role] !== void 0) return {
16889
+ ok: false,
16890
+ error: {
16891
+ kind: "duplicate-role",
16892
+ role
16893
+ }
16894
+ };
16895
+ const hex = normalizePaletteHex(entry.hex);
16896
+ if (!hex) return {
16897
+ ok: false,
16898
+ error: {
16899
+ kind: "invalid-color",
16900
+ role,
16901
+ value: entry.hex
16902
+ }
16903
+ };
16904
+ values[role] = hex;
16905
+ }
16906
+ const missing = PALETTE_TOKEN_NAMES.filter((role) => values[role] === void 0);
16907
+ if (missing.length > 0) return {
16908
+ ok: false,
16909
+ error: {
16910
+ kind: "missing-roles",
16911
+ roles: missing
16912
+ }
16913
+ };
16914
+ return {
16915
+ ok: true,
16916
+ colors: paletteColorsSchema.parse(values)
16917
+ };
16918
+ }
16919
+ function requirePaletteColorsFromEntries(entries) {
16920
+ const result = paletteColorsFromEntries(entries);
16921
+ if (result.ok) return result.colors;
16922
+ throw new Error(`Invalid complete palette: ${result.error.kind}`);
16923
+ }
16924
+ var HEX_COLOR_REGEX, NORMALIZABLE_HEX_REGEX, hexColorSchema, paletteModeSchema, paletteColorsSchema, init_colors = __esmMin((() => {
16925
+ init_themeColorTokens();
16926
+ HEX_COLOR_REGEX = /^#[0-9a-f]{6}$/;
16927
+ NORMALIZABLE_HEX_REGEX = /^#(?:[0-9a-f]{3}|[0-9a-f]{6})$/i;
16928
+ hexColorSchema = z$1.string().regex(HEX_COLOR_REGEX, "Hex must be #RRGGBB (lowercase)").transform((value) => value);
16929
+ paletteModeSchema = z$1.enum(["light", "dark"]);
16930
+ z$1.string().regex(/^[0-9a-f]{64}$/, "Palette hash must be a lowercase SHA-256 value").transform((value) => value);
16931
+ paletteColorsSchema = z$1.object({
16932
+ primary: hexColorSchema,
16933
+ primaryForeground: hexColorSchema,
16934
+ secondary: hexColorSchema,
16935
+ accent: hexColorSchema,
16936
+ success: hexColorSchema,
16937
+ warning: hexColorSchema,
16938
+ destructive: hexColorSchema,
16939
+ background: hexColorSchema,
16940
+ surface: hexColorSchema,
16941
+ surfaceAlt: hexColorSchema,
16942
+ muted: hexColorSchema,
16943
+ text: hexColorSchema,
16944
+ border: hexColorSchema
16945
+ }).strict().transform((value) => value);
16946
+ }));
16947
+ var init_historicalThemePalette = __esmMin((() => {
16948
+ init_themeColorTokens();
16949
+ init_colors();
16950
+ init_colorConversion();
16951
+ init_textColor();
16952
+ new Set(PALETTE_TOKEN_NAMES);
16953
+ }));
16954
+ //#endregion
16478
16955
  //#region ../theme-core/src/palette/types.ts
16479
16956
  var init_types$7 = __esmMin((() => {}));
16480
16957
  //#endregion
@@ -17601,90 +18078,6 @@ var init_browser = __esmMin((() => {
17601
18078
  var init_extractPalette = __esmMin((() => {
17602
18079
  init_browser();
17603
18080
  }));
17604
- //#endregion
17605
- //#region ../theme-core/src/palette/colors.ts
17606
- function normalizePaletteHex(value) {
17607
- if (!NORMALIZABLE_HEX_REGEX.test(value)) return null;
17608
- const normalized = value.toLowerCase();
17609
- if (normalized.length === 7) return normalized;
17610
- const triplet = normalized.slice(1);
17611
- const red = triplet.charAt(0);
17612
- const green = triplet.charAt(1);
17613
- const blue = triplet.charAt(2);
17614
- return `#${red}${red}${green}${green}${blue}${blue}`;
17615
- }
17616
- function paletteColorsFromEntries(entries) {
17617
- const values = {};
17618
- for (const entry of entries) {
17619
- const parsedRole = paletteTokenNameSchema.safeParse(entry.name);
17620
- if (!parsedRole.success) return {
17621
- ok: false,
17622
- error: {
17623
- kind: "unknown-role",
17624
- role: entry.name
17625
- }
17626
- };
17627
- const role = parsedRole.data;
17628
- if (values[role] !== void 0) return {
17629
- ok: false,
17630
- error: {
17631
- kind: "duplicate-role",
17632
- role
17633
- }
17634
- };
17635
- const hex = normalizePaletteHex(entry.hex);
17636
- if (!hex) return {
17637
- ok: false,
17638
- error: {
17639
- kind: "invalid-color",
17640
- role,
17641
- value: entry.hex
17642
- }
17643
- };
17644
- values[role] = hex;
17645
- }
17646
- const missing = PALETTE_TOKEN_NAMES.filter((role) => values[role] === void 0);
17647
- if (missing.length > 0) return {
17648
- ok: false,
17649
- error: {
17650
- kind: "missing-roles",
17651
- roles: missing
17652
- }
17653
- };
17654
- return {
17655
- ok: true,
17656
- colors: paletteColorsSchema.parse(values)
17657
- };
17658
- }
17659
- function requirePaletteColorsFromEntries(entries) {
17660
- const result = paletteColorsFromEntries(entries);
17661
- if (result.ok) return result.colors;
17662
- throw new Error(`Invalid complete palette: ${result.error.kind}`);
17663
- }
17664
- var HEX_COLOR_REGEX, NORMALIZABLE_HEX_REGEX, hexColorSchema, paletteModeSchema, paletteColorsSchema;
17665
- var init_colors = __esmMin((() => {
17666
- init_themeColorTokens();
17667
- HEX_COLOR_REGEX = /^#[0-9a-f]{6}$/;
17668
- NORMALIZABLE_HEX_REGEX = /^#(?:[0-9a-f]{3}|[0-9a-f]{6})$/i;
17669
- hexColorSchema = z$1.string().regex(HEX_COLOR_REGEX, "Hex must be #RRGGBB (lowercase)").transform((value) => value);
17670
- paletteModeSchema = z$1.enum(["light", "dark"]);
17671
- z$1.string().regex(/^[0-9a-f]{64}$/, "Palette hash must be a lowercase SHA-256 value").transform((value) => value);
17672
- paletteColorsSchema = z$1.object({
17673
- primary: hexColorSchema,
17674
- primaryForeground: hexColorSchema,
17675
- secondary: hexColorSchema,
17676
- accent: hexColorSchema,
17677
- success: hexColorSchema,
17678
- warning: hexColorSchema,
17679
- destructive: hexColorSchema,
17680
- background: hexColorSchema,
17681
- surface: hexColorSchema,
17682
- surfaceAlt: hexColorSchema,
17683
- muted: hexColorSchema,
17684
- text: hexColorSchema,
17685
- border: hexColorSchema
17686
- }).strict().transform((value) => value);
17687
- }));
17688
18081
  var init_editorState = __esmMin((() => {}));
17689
18082
  var init_libraryModel = __esmMin((() => {}));
17690
18083
  var init_themePaletteCompatibility = __esmMin((() => {
@@ -17695,6 +18088,7 @@ var init_legacySelection = __esmMin((() => {
17695
18088
  init_themeColorTokens();
17696
18089
  init_colors();
17697
18090
  init_themePaletteCompatibility();
18091
+ init_historicalThemePalette();
17698
18092
  }));
17699
18093
  //#endregion
17700
18094
  //#region ../theme-core/src/palette/curated/types.ts
@@ -17744,7 +18138,7 @@ var init_types$6 = __esmMin((() => {
17744
18138
  }));
17745
18139
  //#endregion
17746
18140
  //#region ../theme-core/src/palette/curated/brand-led.ts
17747
- var brandLedCool, brandLedWarm, brandLedJewel, brandLedBurgundyGold;
18141
+ var brandLedCool, brandLedWarm, brandLedJewel, brandLedSpruce, brandLedBurgundyGold;
17748
18142
  var init_brand_led = __esmMin((() => {
17749
18143
  init_types$6();
17750
18144
  brandLedCool = defineCuratedPalette({
@@ -17942,6 +18336,71 @@ var init_brand_led = __esmMin((() => {
17942
18336
  }
17943
18337
  ]
17944
18338
  });
18339
+ brandLedSpruce = defineCuratedPalette({
18340
+ id: "brand-led-spruce",
18341
+ name: "Brand-led — Spruce",
18342
+ description: "Spruce-ink primary and moss secondary with an amber accent over a green-mist ground and hairline sage borders.",
18343
+ tags: {
18344
+ tone: "classic",
18345
+ energy: "calm",
18346
+ era: "editorial"
18347
+ },
18348
+ mode: "light",
18349
+ colors: [
18350
+ {
18351
+ name: "primary",
18352
+ hex: "#14312b"
18353
+ },
18354
+ {
18355
+ name: "secondary",
18356
+ hex: "#356a59"
18357
+ },
18358
+ {
18359
+ name: "accent",
18360
+ hex: "#f08a4b"
18361
+ },
18362
+ {
18363
+ name: "success",
18364
+ hex: "#356a59"
18365
+ },
18366
+ {
18367
+ name: "warning",
18368
+ hex: "#f08a4b"
18369
+ },
18370
+ {
18371
+ name: "destructive",
18372
+ hex: "#b5561f"
18373
+ },
18374
+ {
18375
+ name: "background",
18376
+ hex: "#ecefe9"
18377
+ },
18378
+ {
18379
+ name: "surface",
18380
+ hex: "#ffffff"
18381
+ },
18382
+ {
18383
+ name: "surfaceAlt",
18384
+ hex: "#f4f6f1"
18385
+ },
18386
+ {
18387
+ name: "muted",
18388
+ hex: "#5c6a64"
18389
+ },
18390
+ {
18391
+ name: "text",
18392
+ hex: "#1c2a26"
18393
+ },
18394
+ {
18395
+ name: "primaryForeground",
18396
+ hex: "#f4f7f1"
18397
+ },
18398
+ {
18399
+ name: "border",
18400
+ hex: "#d7ddd2"
18401
+ }
18402
+ ]
18403
+ });
17945
18404
  brandLedBurgundyGold = defineCuratedPalette({
17946
18405
  id: "brand-led-burgundy-gold",
17947
18406
  name: "Brand-led — Burgundy Gold",
@@ -18882,8 +19341,7 @@ var init_warm_dark = __esmMin((() => {
18882
19341
  function findCuratedPalette(id) {
18883
19342
  return curatedPalettesById.get(id);
18884
19343
  }
18885
- var curatedPalettes, curatedPalettesById;
18886
- var init_curated = __esmMin((() => {
19344
+ var curatedPalettes, curatedPalettesById, init_curated = __esmMin((() => {
18887
19345
  init_brand_led();
18888
19346
  init_high_contrast();
18889
19347
  init_soft_natural();
@@ -18895,6 +19353,7 @@ var init_curated = __esmMin((() => {
18895
19353
  brandLedWarm,
18896
19354
  brandLedJewel,
18897
19355
  brandLedBurgundyGold,
19356
+ brandLedSpruce,
18898
19357
  warmNeutralClay,
18899
19358
  warmNeutralCream,
18900
19359
  warmNeutralSoftEarth,
@@ -19008,6 +19467,7 @@ var init_fromVibrant = __esmMin((() => {
19008
19467
  init_expandPalette();
19009
19468
  init_generateCssVars();
19010
19469
  init_generateShades();
19470
+ init_historicalThemePalette();
19011
19471
  init_neutralScale();
19012
19472
  init_types$7();
19013
19473
  init_utils$4();
@@ -19744,6 +20204,50 @@ function getCompatibleHeaderStyleIds(layoutId) {
19744
20204
  return isHeaderStyleCompatibleWithLayout(getHeaderStyleOrThrow(styleId), layoutId);
19745
20205
  });
19746
20206
  }
20207
+ function applyNavTypography(style, typography) {
20208
+ switch (typography) {
20209
+ case "plain": return style;
20210
+ case "heading": return {
20211
+ ...style,
20212
+ typography: "heading",
20213
+ fontWeight: "medium",
20214
+ letterSpacing: "wide"
20215
+ };
20216
+ case "quiet-caps": return {
20217
+ ...style,
20218
+ textTransform: "uppercase",
20219
+ textSize: "sm",
20220
+ letterSpacing: "wide"
20221
+ };
20222
+ case "brand-caps": return {
20223
+ ...style,
20224
+ textTransform: "uppercase",
20225
+ textSize: "sm",
20226
+ letterSpacing: "wider"
20227
+ };
20228
+ default: return assertNever$12(typography, "Unhandled header nav typography");
20229
+ }
20230
+ }
20231
+ function underlineNavLinkStyle(colorToken, underlineColorToken, typography = "plain") {
20232
+ return applyNavTypography({
20233
+ name: "Underline grow",
20234
+ typography: "body",
20235
+ fontWeight: "medium",
20236
+ textTransform: "none",
20237
+ italic: false,
20238
+ colorToken,
20239
+ padding: "compact",
20240
+ paddingX: "compact",
20241
+ borderRadius: "none",
20242
+ effects: { hover: [{
20243
+ effectId: "nav-underline",
20244
+ options: {
20245
+ style: "grow",
20246
+ ...underlineColorToken ? { colorToken: underlineColorToken } : {}
20247
+ }
20248
+ }] }
20249
+ }, typography);
20250
+ }
19747
20251
  function themedHeaderShadow(theme) {
19748
20252
  switch (theme.shadow.elevation) {
19749
20253
  case "none": return;
@@ -19843,6 +20347,38 @@ function cleanBaseHeader(theme) {
19843
20347
  ctaGap: "default"
19844
20348
  };
19845
20349
  }
20350
+ function classicCenteredNavHeader(theme) {
20351
+ return {
20352
+ ...baseHeader(theme),
20353
+ variant: "classic",
20354
+ navPlacement: "center",
20355
+ positioning: "sticky",
20356
+ shrinkOnScroll: false,
20357
+ background: {
20358
+ type: "color",
20359
+ color: "surface"
20360
+ },
20361
+ textColor: "text",
20362
+ navColor: "text",
20363
+ navStyle: "underline-grow",
20364
+ navWeight: "medium",
20365
+ navLinkStyle: underlineNavLinkStyle("text", "accent"),
20366
+ border: {
20367
+ style: "solid",
20368
+ width: "thin",
20369
+ position: "bottom",
20370
+ colorToken: "border"
20371
+ },
20372
+ ctaTreatment: "primary",
20373
+ ctaVariant: resolveHeaderCtaVariant(theme, "primary"),
20374
+ ctaGap: "default",
20375
+ logoText: {
20376
+ mobileMaxWidth: "sm",
20377
+ mobileWrapLines: 1,
20378
+ hideOnShrink: false
20379
+ }
20380
+ };
20381
+ }
19846
20382
  function serifLineHeader(theme) {
19847
20383
  return {
19848
20384
  ...baseHeader(theme),
@@ -20421,6 +20957,13 @@ var init_headerLooks = __esmMin((() => {
20421
20957
  styleId: asHeaderStyleId("minimal")
20422
20958
  }
20423
20959
  },
20960
+ {
20961
+ lookId: asHeaderLookId("classic-centered-nav"),
20962
+ selection: {
20963
+ layoutId: asHeaderLayoutId("classic"),
20964
+ styleId: asHeaderStyleId("fine-line")
20965
+ }
20966
+ },
20424
20967
  {
20425
20968
  lookId: asHeaderLookId("brand-solid"),
20426
20969
  selection: {
@@ -20487,6 +21030,21 @@ var init_headerLooks = __esmMin((() => {
20487
21030
  logoAccommodations: inlineClassicLogoAccommodations,
20488
21031
  compile: cleanBaseHeader
20489
21032
  },
21033
+ {
21034
+ id: asHeaderLookId("classic-centered-nav"),
21035
+ label: "Centered nav",
21036
+ visualTreatment: "solid-neutral",
21037
+ layoutBehavior: "sticky",
21038
+ configuration: {
21039
+ structure: "inline-classic",
21040
+ treatment: "solid-neutral",
21041
+ behavior: "sticky"
21042
+ },
21043
+ openingRequirement: "none",
21044
+ maxRecommendedNavItems: 6,
21045
+ logoAccommodations: inlineClassicLogoAccommodations,
21046
+ compile: classicCenteredNavHeader
21047
+ },
20490
21048
  {
20491
21049
  id: asHeaderLookId("brand-solid"),
20492
21050
  label: "Brand solid",
@@ -21047,7 +21605,7 @@ function defineTypographyPreset(preset) {
21047
21605
  id: asTypographyPresetId(preset.id)
21048
21606
  };
21049
21607
  }
21050
- var bodyReadablePolicy, headingFlexiblePolicy, displayHeadingPolicy, modernSansTypography, warmRoundedTypography, editorialSerifTypography, classicSerifTypography, luxeContrastTypography, kirtanOrnateTypography, boldDisplayTypography, originalJoyTypography, typographyPresets;
21608
+ var bodyReadablePolicy, headingFlexiblePolicy, displayHeadingPolicy, modernSansTypography, warmRoundedTypography, editorialSerifTypography, classicSerifTypography, luxeContrastTypography, kirtanOrnateTypography, boldDisplayTypography, originalJoyTypography, fulcrumTypography, typographyPresets;
21051
21609
  var init_typographyPresets = __esmMin((() => {
21052
21610
  bodyReadablePolicy = {
21053
21611
  recommendedCategories: ["sans-serif", "serif"],
@@ -21409,6 +21967,49 @@ var init_typographyPresets = __esmMin((() => {
21409
21967
  },
21410
21968
  scale: "balanced"
21411
21969
  };
21970
+ fulcrumTypography = {
21971
+ body: {
21972
+ family: "IBM Plex Sans, system-ui, -apple-system, sans-serif",
21973
+ size: "lg",
21974
+ weight: "regular",
21975
+ lineHeight: "relaxed",
21976
+ letterSpacing: "normal"
21977
+ },
21978
+ headings: {
21979
+ default: {
21980
+ family: "Newsreader, Georgia, \"Times New Roman\", serif",
21981
+ weight: "medium",
21982
+ lineHeight: "normal",
21983
+ letterSpacing: "tight",
21984
+ colorToken: "primary",
21985
+ italic: null,
21986
+ case: null
21987
+ },
21988
+ h1: {
21989
+ size: "2xl",
21990
+ weight: "medium",
21991
+ lineHeight: "normal",
21992
+ letterSpacing: "tight",
21993
+ italic: null
21994
+ },
21995
+ h2: {
21996
+ size: "xl",
21997
+ weight: "medium",
21998
+ lineHeight: "normal",
21999
+ letterSpacing: "tight",
22000
+ italic: null
22001
+ },
22002
+ h3: {
22003
+ size: "md",
22004
+ weight: "semibold",
22005
+ lineHeight: "normal",
22006
+ letterSpacing: "normal",
22007
+ italic: null
22008
+ }
22009
+ },
22010
+ scale: "spacious",
22011
+ eyebrow: { family: "IBM Plex Mono, ui-monospace, \"SF Mono\", monospace" }
22012
+ };
21412
22013
  typographyPresets = [
21413
22014
  defineTypographyPreset({
21414
22015
  id: "typography-preset:modern-sans",
@@ -21668,6 +22269,32 @@ var init_typographyPresets = __esmMin((() => {
21668
22269
  }
21669
22270
  }
21670
22271
  }
22272
+ }),
22273
+ defineTypographyPreset({
22274
+ id: "typography-preset:fulcrum",
22275
+ name: "Fulcrum",
22276
+ description: "Newsreader serif headings over an IBM Plex Sans body, with an IBM Plex Mono eyebrow role for uppercase kickers and mono captions.",
22277
+ defaultFonts: {
22278
+ body: "IBM Plex Sans, system-ui, -apple-system, sans-serif",
22279
+ heading: "Newsreader, Georgia, \"Times New Roman\", serif"
22280
+ },
22281
+ recommendedFonts: {
22282
+ body: [
22283
+ "IBM Plex Sans",
22284
+ "Source Sans 3",
22285
+ "Inter"
22286
+ ],
22287
+ heading: [
22288
+ "Newsreader",
22289
+ "Source Serif 4",
22290
+ "Lora"
22291
+ ]
22292
+ },
22293
+ slotPolicies: {
22294
+ body: bodyReadablePolicy,
22295
+ heading: displayHeadingPolicy
22296
+ },
22297
+ typography: fulcrumTypography
21671
22298
  })
21672
22299
  ];
21673
22300
  new Map(typographyPresets.map((preset) => [preset.id, preset]));
@@ -21831,16 +22458,22 @@ var init_types$5 = __esmMin((() => {
21831
22458
  /**
21832
22459
  * Gradient configuration types and schemas
21833
22460
  */
21834
- var gradientStopSchema, gradientConfigSchema;
22461
+ var gradientStopSchema, radialGradientShapeSchema, gradientConfigSchema;
21835
22462
  var init_types$4 = __esmMin((() => {
21836
22463
  init_themeColorTokens();
21837
22464
  gradientStopSchema = z$1.object({
21838
22465
  color: themeColorTokenSchema,
21839
22466
  position: z$1.number().min(0).max(100)
21840
22467
  });
22468
+ radialGradientShapeSchema = z$1.enum(["circle", "ellipse"]);
21841
22469
  gradientConfigSchema = z$1.object({
21842
- type: z$1.enum(["linear", "radial"]),
22470
+ type: z$1.enum([
22471
+ "linear",
22472
+ "radial",
22473
+ "conic"
22474
+ ]).default("linear"),
21843
22475
  angle: z$1.number().min(0).max(360).optional(),
22476
+ shape: radialGradientShapeSchema.optional(),
21844
22477
  position: z$1.string().optional(),
21845
22478
  stops: z$1.array(gradientStopSchema).min(2)
21846
22479
  });
@@ -22165,7 +22798,7 @@ var init_rawStyleFields = __esmMin((() => {
22165
22798
  [...themeV2RuntimeStyleFieldNames, ...themeV2BlockSpecificRawStyleFieldNames];
22166
22799
  pageDesignEditorBackgroundOverrideOwner = "page-design-editor";
22167
22800
  siteChromeBackgroundOverrideOwner = "site-chrome-editor";
22168
- })), axesSchema, colourHexString, paletteColorSchema, paletteMetaSchema, paletteSchema, typographyStyleSchema, bodyTypographyStyleSchema, headingSizeSchema, headingTypographyOverridesSchema, headingTypographyStyleSchema, proseLinkUnderlineStyleSchema, proseLinkUnderlineThicknessSchema, proseLinkUnderlineOffsetSchema, proseLinkStyleSchema, semanticSpacingSchema, boxRoundedSchema, boxBackgroundOverlaySchema, boxBackgroundSchema, noHeadingDecorationSchema, visibleHeadingDecorationSchema, headingDecorationSchema, headingDecorationOverrideSchema, accordionIconTreatmentSchema, sectionStylesOverrideSchema, containerStylesOverrideSchema, cardBorderOverrideSchema, cardStylesOverrideSchema, blockStyleOverridesSchema, blockThemeOverrideSchema, typographyScaleSchema, typographySchema, spaceSchema, corners, shadow, border, motion, inputStyle$1, headerVariant, headerPositioning, headerNavStyle, navFontWeight, headerMaxWidth, headerContainerSchema, headerBorderSchema, logoStyleSchema, headerLogoTextSchema, navEffectsSchema, dropdownStyleSchema, headerCtaGapSchema, headerCtaTreatmentSchema, navContainerSchema, headerBackgroundSchema, headerSchema, footerVariant, footerMaxWidth, footerMode, footerNavLayoutMode, footerNavLayoutAlign, footerSpacing, footerLogoPlacement, footerLogoSize, footerLogoMaxHeight, footerBottomTextLinkStyleSchema, footerBottomBarSchema, footerNavLayoutSchema, footerLogoSchema, footerSchema, containerPaddingPresetSchema, layoutSchema, heroTypographySizeSchema, heroTypographyLineHeightSchema, heroResponsiveTypographySchema, heroTypographySchema, heroSchema, bodyTextIntroTypographySizeSchema, bodyTextSchema, gradientsSchema, testimonialQuoteTreatmentSchema, themeSchema;
22801
+ })), axesSchema, colourHexString, paletteColorSchema, paletteMetaSchema, paletteSchema, typographyStyleSchema, bodyTypographyStyleSchema, headingSizeSchema, headingTypographyOverridesSchema, headingTypographyStyleSchema, proseLinkUnderlineStyleSchema, proseLinkUnderlineThicknessSchema, proseLinkUnderlineOffsetSchema, proseLinkStyleSchema, semanticSpacingSchema, boxRoundedSchema, boxBackgroundOverlaySchema, boxBackgroundSchema, noHeadingDecorationSchema, visibleHeadingDecorationSchema, headingDecorationSchema, headingDecorationOverrideSchema, accordionIconTreatmentSchema, sectionStylesOverrideSchema, containerStylesOverrideSchema, cardBorderOverrideSchema, cardStylesOverrideSchema, blockStyleOverridesSchema, blockThemeOverrideSchema, typographyScaleSchema, eyebrowTypographyStyleSchema, typographySchema, spaceSchema, corners, shadow, border, motion, inputStyle$1, headerVariant, headerPositioning, headerNavStyle, navFontWeight, headerMaxWidth, headerContainerSchema, headerBorderSchema, logoStyleSchema, headerLogoTextSchema, navEffectsSchema, dropdownStyleSchema, headerCtaGapSchema, headerCtaTreatmentSchema, navContainerSchema, headerBackgroundSchema, headerSchema, footerVariant, footerMaxWidth, footerMode, footerNavLayoutMode, footerNavLayoutAlign, footerSpacing, footerLogoPlacement, footerLogoSize, footerLogoMaxHeight, footerBottomTextLinkStyleSchema, footerBottomBarSchema, footerNavLayoutSchema, footerLogoSchema, footerSchema, containerPaddingPresetSchema, layoutSchema, heroTypographySizeSchema, heroTypographyLineHeightSchema, heroResponsiveTypographySchema, heroTypographySchema, heroSchema, bodyTextIntroTypographySizeSchema, bodyTextSchema, gradientsSchema, testimonialQuoteTreatmentSchema, themeSchema;
22169
22802
  var init_schema$1 = __esmMin((() => {
22170
22803
  init_media();
22171
22804
  init_buttons();
@@ -22445,6 +23078,7 @@ var init_schema$1 = __esmMin((() => {
22445
23078
  "majorThird",
22446
23079
  "perfectFourth"
22447
23080
  ]);
23081
+ eyebrowTypographyStyleSchema = z$1.object({ family: z$1.string().min(1) });
22448
23082
  typographySchema = z$1.object({
22449
23083
  body: bodyTypographyStyleSchema,
22450
23084
  headings: z$1.object({
@@ -22457,7 +23091,8 @@ var init_schema$1 = __esmMin((() => {
22457
23091
  h6: headingTypographyOverridesSchema.optional()
22458
23092
  }),
22459
23093
  scale: typographyScaleSchema,
22460
- proseLinkStyle: proseLinkStyleSchema.optional()
23094
+ proseLinkStyle: proseLinkStyleSchema.optional(),
23095
+ eyebrow: eyebrowTypographyStyleSchema.optional()
22461
23096
  });
22462
23097
  spaceSchema = z$1.enum([
22463
23098
  "comfortable",
@@ -22482,7 +23117,8 @@ var init_schema$1 = __esmMin((() => {
22482
23117
  "soft",
22483
23118
  "hard"
22484
23119
  ]).nullable(),
22485
- position: z$1.enum(["bottom", "bottom-right"]).default("bottom")
23120
+ position: z$1.enum(["bottom", "bottom-right"]).default("bottom"),
23121
+ colorToken: themeColorTokenSchema.optional()
22486
23122
  });
22487
23123
  border = z$1.object({
22488
23124
  width: z$1.enum([
@@ -22723,6 +23359,7 @@ var init_schema$1 = __esmMin((() => {
22723
23359
  navWeight: navFontWeight.default("medium"),
22724
23360
  navTypography: z$1.enum(["body", "heading"]).optional(),
22725
23361
  navTextSize: navLinkStyleSchema.shape.textSize,
23362
+ navPlacement: z$1.enum(["end", "center"]).optional(),
22726
23363
  container: headerContainerSchema,
22727
23364
  border: headerBorderSchema,
22728
23365
  shadow: componentShadowSchema.optional(),
@@ -23478,7 +24115,8 @@ var init_curatedSiteStyles = __esmMin((() => {
23478
24115
  "site-style:bold-launch",
23479
24116
  "site-style:south-west-twerk-school",
23480
24117
  "site-style:kirtan-ornate",
23481
- "site-style:original-joy"
24118
+ "site-style:original-joy",
24119
+ "site-style:fulcrum"
23482
24120
  ];
23483
24121
  quietBudget = {
23484
24122
  accentDensity: "low",
@@ -24690,6 +25328,104 @@ var init_curatedSiteStyles = __esmMin((() => {
24690
25328
  buttonChoice("showtime-pill")
24691
25329
  ],
24692
25330
  paletteRecommendations: [paletteRecommendation("warm-dark-ember")]
25331
+ }),
25332
+ defineCuratedSiteStyle({
25333
+ id: "site-style:fulcrum",
25334
+ name: "Fulcrum",
25335
+ headingDecoration: {
25336
+ family: "short-center-rule",
25337
+ colorToken: "accent"
25338
+ },
25339
+ 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.",
25340
+ 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.",
25341
+ siteCreatorSelection: {
25342
+ kind: "site_creator_keyword_heuristic",
25343
+ priority: 28
25344
+ },
25345
+ selectionKeywordRules: [
25346
+ {
25347
+ kind: "substring",
25348
+ value: "physiotherap"
25349
+ },
25350
+ {
25351
+ kind: "word",
25352
+ value: "physio"
25353
+ },
25354
+ {
25355
+ kind: "phrase",
25356
+ value: "sports injury"
25357
+ },
25358
+ {
25359
+ kind: "phrase",
25360
+ value: "rehab clinic"
25361
+ },
25362
+ {
25363
+ kind: "substring",
25364
+ value: "musculoskeletal"
25365
+ },
25366
+ {
25367
+ kind: "phrase",
25368
+ value: "sports therapy"
25369
+ }
25370
+ ],
25371
+ tokenRecipes: {
25372
+ palette: "brand-led",
25373
+ contrast: "standard",
25374
+ radius: "rounded",
25375
+ shadow: "subtle",
25376
+ typography: "serif-editorial",
25377
+ spacing: "airy",
25378
+ motion: "subtle"
25379
+ },
25380
+ compositionBudget: quietBudget,
25381
+ typographyPresetChoices: [
25382
+ typographyChoice("typography-preset:fulcrum"),
25383
+ typographyChoice("typography-preset:editorial-serif"),
25384
+ typographyChoice("typography-preset:modern-sans")
25385
+ ],
25386
+ defaultTypographyPresetId: "typography-preset:fulcrum",
25387
+ themeOverrides: {
25388
+ shadow: { colorToken: "primary" },
25389
+ accordions: {
25390
+ background: null,
25391
+ spacing: "comfortable",
25392
+ corners: "square",
25393
+ border: null,
25394
+ shadow: null,
25395
+ icon: {
25396
+ style: "plus-minus",
25397
+ position: "right",
25398
+ size: "md",
25399
+ colorToken: "accent"
25400
+ },
25401
+ trigger: {
25402
+ textColorToken: "primary",
25403
+ fontWeight: "medium",
25404
+ fontFamily: "heading",
25405
+ fontScale: "md"
25406
+ },
25407
+ hover: { textColorToken: "secondary" },
25408
+ content: { textColorToken: "muted" }
25409
+ },
25410
+ testimonialQuote: serifDisplayQuote
25411
+ },
25412
+ recommendedHeaderLookIds: [
25413
+ "classic-centered-nav",
25414
+ "serif-line",
25415
+ "centered-calm",
25416
+ "clean-base"
25417
+ ],
25418
+ recommendedFooterLookIds: ["footer-editorial-columns", "footer-muted-grounding"],
25419
+ buttonPersonalityChoices: [
25420
+ buttonChoice("flat-ink"),
25421
+ buttonChoice("confident-chip"),
25422
+ buttonChoice("editorial-link")
25423
+ ],
25424
+ paletteRecommendations: [
25425
+ paletteRecommendation("brand-led-spruce"),
25426
+ paletteRecommendation("warm-neutral-forest"),
25427
+ paletteRecommendation("soft-natural-sage")
25428
+ ]
24693
25429
  })
24694
25430
  ];
24695
25431
  new Map(curatedSiteStyles.map((style) => [style.id, style]));
@@ -25154,7 +25890,8 @@ var init_site_styles = __esmMin((() => {
25154
25890
  }));
25155
25891
  var init_themeColorResolution = __esmMin((() => {
25156
25892
  init_tokenOrColor();
25157
- })), init_sectionForegroundStyles = __esmMin((() => {
25893
+ })), init_surfaceForegroundStyles = __esmMin((() => {
25894
+ init_surfaces();
25158
25895
  init_themeColorResolution();
25159
25896
  }));
25160
25897
  var init_boxStyles$1 = __esmMin((() => {
@@ -25164,8 +25901,7 @@ var init_boxStyles$1 = __esmMin((() => {
25164
25901
  init_colorStyles();
25165
25902
  init_cards();
25166
25903
  init_blockColorTokens();
25167
- init_themeColorResolution();
25168
- init_sectionForegroundStyles();
25904
+ init_surfaceForegroundStyles();
25169
25905
  new Set(tileTreatmentValues);
25170
25906
  new Set(eventListTreatmentValues);
25171
25907
  }));
@@ -26061,6 +26797,9 @@ var init_validation_constants = __esmMin((() => {
26061
26797
  "richText",
26062
26798
  "media",
26063
26799
  "videoEmbed",
26800
+ "icon",
26801
+ "feature-card-icon",
26802
+ "svg",
26064
26803
  "button",
26065
26804
  "link",
26066
26805
  "carousel",
@@ -26090,11 +26829,13 @@ var init_validation_constants = __esmMin((() => {
26090
26829
  "value.jsonArray",
26091
26830
  "value.csv",
26092
26831
  "array.marqueeLoop",
26832
+ "value.mapToken",
26093
26833
  "layout.maxWidthClass",
26094
26834
  "layout.headerRootClass",
26095
26835
  "layout.footerRootClass",
26096
26836
  "layout.headerRootStyle",
26097
26837
  "layout.headerSectionBackground",
26838
+ "layout.classicNavMode",
26098
26839
  "layout.footerRootStyle",
26099
26840
  "ui.headerNavLinkClass",
26100
26841
  "ui.headingClassFromAlignment",
@@ -27246,7 +27987,29 @@ var init_ctaRow = __esmMin((() => {
27246
27987
  fields: [createCtasRepeater({
27247
27988
  label: "Calls to action",
27248
27989
  itemLabel: "CTA",
27249
- maxItems: 3
27990
+ maxItems: 3,
27991
+ button: { variants: [
27992
+ {
27993
+ value: "primary",
27994
+ label: "Primary"
27995
+ },
27996
+ {
27997
+ value: "secondary",
27998
+ label: "Secondary"
27999
+ },
28000
+ {
28001
+ value: "outline",
28002
+ label: "Outline"
28003
+ },
28004
+ {
28005
+ value: "link",
28006
+ label: "Link"
28007
+ },
28008
+ {
28009
+ value: "accent",
28010
+ label: "Accent"
28011
+ }
28012
+ ] }
27250
28013
  })],
27251
28014
  layout: [ctaRow({
27252
28015
  collectionPath: "content.ctas",
@@ -32452,7 +33215,7 @@ const eventCalendarLayout = [styledSection({
32452
33215
  children: styledContainer({
32453
33216
  rootType: "stack",
32454
33217
  rootProps: { gap: "lg" },
32455
- children: [...eventSectionHeaderLayoutNodes(), el("event-calendar", withApiBindings({
33218
+ children: [...eventSectionHeaderLayoutNodes({ splitClassName: "event-section-head event-section-head--split" }), el("event-calendar", withApiBindings({
32456
33219
  events: { $bind: { from: "data.events" } },
32457
33220
  stage: { $bind: {
32458
33221
  from: "$root.previewStage",
@@ -32563,6 +33326,10 @@ const eventCalendarAdditionalFields = [
32563
33326
  value: "timetable",
32564
33327
  label: "Timetable"
32565
33328
  },
33329
+ {
33330
+ value: "week-board",
33331
+ label: "Week board"
33332
+ },
32566
33333
  {
32567
33334
  value: "list",
32568
33335
  label: "List"
@@ -32745,7 +33512,8 @@ const eventCalendarAdditionalFields = [
32745
33512
  oneOf: [
32746
33513
  "combined",
32747
33514
  "calendar",
32748
- "timetable"
33515
+ "timetable",
33516
+ "week-board"
32749
33517
  ]
32750
33518
  }
32751
33519
  }
@@ -32848,7 +33616,8 @@ const eventCalendarAdditionalFields = [
32848
33616
  "combined",
32849
33617
  "calendar",
32850
33618
  "list",
32851
- "timetable"
33619
+ "timetable",
33620
+ "week-board"
32852
33621
  ]
32853
33622
  }
32854
33623
  }
@@ -32883,7 +33652,8 @@ const eventCalendarAdditionalFields = [
32883
33652
  "combined",
32884
33653
  "calendar",
32885
33654
  "list",
32886
- "timetable"
33655
+ "timetable",
33656
+ "week-board"
32887
33657
  ]
32888
33658
  }, {
32889
33659
  field: "showFilters",
@@ -32906,7 +33676,8 @@ const eventCalendarAdditionalFields = [
32906
33676
  "combined",
32907
33677
  "calendar",
32908
33678
  "list",
32909
- "timetable"
33679
+ "timetable",
33680
+ "week-board"
32910
33681
  ]
32911
33682
  }, {
32912
33683
  field: "showFilters",
@@ -32929,7 +33700,8 @@ const eventCalendarAdditionalFields = [
32929
33700
  "combined",
32930
33701
  "calendar",
32931
33702
  "list",
32932
- "timetable"
33703
+ "timetable",
33704
+ "week-board"
32933
33705
  ]
32934
33706
  }, {
32935
33707
  field: "showFilters",
@@ -32951,7 +33723,8 @@ const eventCalendarAdditionalFields = [
32951
33723
  oneOf: [
32952
33724
  "combined",
32953
33725
  "list",
32954
- "timetable"
33726
+ "timetable",
33727
+ "week-board"
32955
33728
  ]
32956
33729
  }, { allOf: [{
32957
33730
  field: "variant",
@@ -33127,6 +33900,7 @@ const eventCalendarVariants = {
33127
33900
  combined: eventCalendarLayout[0],
33128
33901
  calendar: eventCalendarLayout[0],
33129
33902
  timetable: eventCalendarLayout[0],
33903
+ "week-board": eventCalendarLayout[0],
33130
33904
  list: eventCalendarLayout[0]
33131
33905
  };
33132
33906
  const eventCalendarContentShape = {
@@ -33140,6 +33914,7 @@ const eventCalendarContentShape = {
33140
33914
  { value: "combined" },
33141
33915
  { value: "calendar" },
33142
33916
  { value: "timetable" },
33917
+ { value: "week-board" },
33143
33918
  { value: "list" }
33144
33919
  ]
33145
33920
  },
@@ -33206,6 +33981,7 @@ const eventCalendarBlockDefinition = {
33206
33981
  combined: { label: "Combined" },
33207
33982
  calendar: { label: "Calendar" },
33208
33983
  timetable: { label: "Timetable" },
33984
+ "week-board": { label: "Week board" },
33209
33985
  list: { label: "List" }
33210
33986
  }
33211
33987
  }, eventCalendarContentShape),
@@ -35539,6 +36315,153 @@ var init_WeekAgendaView = __esmMin((() => {
35539
36315
  };
35540
36316
  }));
35541
36317
  //#endregion
36318
+ //#region ../blocks/src/system/runtime/nodes/events/shared/WeekBoardView.tsx
36319
+ /**
36320
+ * Format an event's start–end as a compact range, merging the shared meridiem.
36321
+ * "6:00 PM" + "7:00 PM" -> "6:00 – 7:00 PM"; "9:30 AM" + "10:15 AM" -> "9:30 – 10:15 AM".
36322
+ */
36323
+ function formatCompactTimeRange(event) {
36324
+ const timeZone = event.timeZone ?? null;
36325
+ const start = formatTime$3(event.startsAt, { timeZone });
36326
+ const end = formatTime$3(event.endsAt, { timeZone });
36327
+ const startMeridiem = start.slice(-2);
36328
+ const endMeridiem = end.slice(-2);
36329
+ if ((startMeridiem === "AM" || startMeridiem === "PM") && startMeridiem === endMeridiem) return `${start.slice(0, -3).trim()} – ${end}`;
36330
+ return `${start} – ${end}`;
36331
+ }
36332
+ var SHORT_DAY_NAMES, LEGEND_ITEMS, WeekBoardCard, WeekBoardView;
36333
+ var init_WeekBoardView = __esmMin((() => {
36334
+ init_clsx();
36335
+ init_buttons();
36336
+ init_eventCapacity();
36337
+ init_utils$5();
36338
+ SHORT_DAY_NAMES = [
36339
+ "Sun",
36340
+ "Mon",
36341
+ "Tue",
36342
+ "Wed",
36343
+ "Thu",
36344
+ "Fri",
36345
+ "Sat"
36346
+ ];
36347
+ LEGEND_ITEMS = [
36348
+ {
36349
+ status: "available",
36350
+ label: "Places available"
36351
+ },
36352
+ {
36353
+ status: "filling",
36354
+ label: "Filling up"
36355
+ },
36356
+ {
36357
+ status: "waitlist",
36358
+ label: "Waitlist"
36359
+ }
36360
+ ];
36361
+ WeekBoardCard = ({ event, showCapacity }) => {
36362
+ const linkProps = resolveEventLinkProps(event);
36363
+ const { status, label } = getEventAvailabilityStatus(event);
36364
+ const pill = showCapacity ? label : null;
36365
+ return /* @__PURE__ */ jsxs("a", {
36366
+ ...linkProps,
36367
+ className: "event-week-board-card",
36368
+ "data-status": status,
36369
+ children: [
36370
+ /* @__PURE__ */ jsx("span", {
36371
+ className: "event-week-board-card-title",
36372
+ children: event.title
36373
+ }),
36374
+ /* @__PURE__ */ jsx("span", {
36375
+ className: "event-week-board-card-time",
36376
+ children: formatCompactTimeRange(event)
36377
+ }),
36378
+ pill ? /* @__PURE__ */ jsx("span", {
36379
+ className: "event-week-board-card-pill",
36380
+ "data-status": status,
36381
+ children: pill
36382
+ }) : null
36383
+ ]
36384
+ });
36385
+ };
36386
+ WeekBoardView = ({ days, events, showCapacity, emptyMessage = "No classes scheduled this week", title = "The week ahead", footerNote = "New to a class? We'll check it's right for you first.", ctaLabel = "Reserve a place", ctaHref = null, buttonVariant = "outline" }) => {
36387
+ const eventsByDate = groupEventsByDate(events);
36388
+ const hasAnyEvents = days.some((date) => (eventsByDate.get(formatDateKey(date)) ?? []).length > 0);
36389
+ const ctaClassName = themeButtonClassName({
36390
+ variant: buttonVariant,
36391
+ size: "sm"
36392
+ });
36393
+ return /* @__PURE__ */ jsx("div", {
36394
+ className: "event-calendar event-calendar--week-board",
36395
+ "data-block": "event-calendar",
36396
+ children: /* @__PURE__ */ jsxs("div", {
36397
+ className: "event-week-board",
36398
+ style: { "--event-week-board-cols": String(days.length) },
36399
+ children: [
36400
+ /* @__PURE__ */ jsxs("div", {
36401
+ className: "event-week-board-top",
36402
+ children: [/* @__PURE__ */ jsx("span", {
36403
+ className: "event-week-board-title",
36404
+ children: title
36405
+ }), /* @__PURE__ */ jsx("div", {
36406
+ className: "event-week-board-legend",
36407
+ "aria-hidden": "true",
36408
+ children: LEGEND_ITEMS.map((item) => /* @__PURE__ */ jsxs("span", {
36409
+ className: "event-week-board-legend-item",
36410
+ children: [/* @__PURE__ */ jsx("i", {
36411
+ className: "event-week-board-legend-dot",
36412
+ "data-status": item.status
36413
+ }), item.label]
36414
+ }, item.status))
36415
+ })]
36416
+ }),
36417
+ /* @__PURE__ */ jsx("div", {
36418
+ className: "event-week-board-grid",
36419
+ children: days.map((date) => {
36420
+ const dateKey = formatDateKey(date);
36421
+ const dayEvents = eventsByDate.get(dateKey) ?? [];
36422
+ const today = isToday(date);
36423
+ return /* @__PURE__ */ jsxs("div", {
36424
+ className: clsx("event-week-board-day", dayEvents.length === 0 && "event-week-board-day--empty", today && "event-week-board-day--today"),
36425
+ children: [/* @__PURE__ */ jsxs("div", {
36426
+ className: "event-week-board-day-head",
36427
+ children: [/* @__PURE__ */ jsx("span", {
36428
+ className: "event-week-board-day-abbr",
36429
+ children: SHORT_DAY_NAMES[date.getDay()]
36430
+ }), /* @__PURE__ */ jsx("span", {
36431
+ className: "event-week-board-day-num",
36432
+ children: date.getDate()
36433
+ })]
36434
+ }), /* @__PURE__ */ jsx("div", {
36435
+ className: "event-week-board-day-body",
36436
+ children: dayEvents.map((event) => /* @__PURE__ */ jsx(WeekBoardCard, {
36437
+ event,
36438
+ showCapacity
36439
+ }, event.occurrenceId || event.id))
36440
+ })]
36441
+ }, dateKey);
36442
+ })
36443
+ }),
36444
+ /* @__PURE__ */ jsxs("div", {
36445
+ className: "event-week-board-foot",
36446
+ children: [/* @__PURE__ */ jsx("p", {
36447
+ className: "event-week-board-foot-note",
36448
+ children: hasAnyEvents ? footerNote : emptyMessage
36449
+ }), ctaHref ? /* @__PURE__ */ jsx("a", {
36450
+ className: ctaClassName,
36451
+ href: ctaHref,
36452
+ children: ctaLabel
36453
+ }) : /* @__PURE__ */ jsx("button", {
36454
+ type: "button",
36455
+ className: ctaClassName,
36456
+ children: ctaLabel
36457
+ })]
36458
+ })
36459
+ ]
36460
+ })
36461
+ });
36462
+ };
36463
+ }));
36464
+ //#endregion
35542
36465
  //#region ../blocks/src/system/runtime/nodes/events/shared/timetableModel.ts
35543
36466
  function buildTimetableModel(input) {
35544
36467
  const generic = buildTimetableModel$1({
@@ -35633,6 +36556,7 @@ init_clsx();
35633
36556
  init_EventListing_view();
35634
36557
  init_EventCalendar_interactive();
35635
36558
  init_WeekAgendaView();
36559
+ init_WeekBoardView();
35636
36560
  init_utils$5();
35637
36561
  init_timetableModel();
35638
36562
  init_buttons();
@@ -35977,6 +36901,17 @@ function renderTimetableSsr(display) {
35977
36901
  })]
35978
36902
  });
35979
36903
  }
36904
+ function renderWeekBoardSsr(display) {
36905
+ const days = getWeekCalendarDayTuple(/* @__PURE__ */ new Date(), display.startOfWeek);
36906
+ return /* @__PURE__ */ jsx(WeekBoardView, {
36907
+ days,
36908
+ events: [...display.events],
36909
+ showCapacity: display.showCapacity,
36910
+ emptyMessage: display.emptyMessage,
36911
+ ctaLabel: display.buttonText,
36912
+ buttonVariant: display.buttonVariant
36913
+ });
36914
+ }
35980
36915
  function formatHourLabel$1(hour) {
35981
36916
  if (hour === 0) return "12 AM";
35982
36917
  if (hour === 12) return "12 PM";
@@ -36003,6 +36938,9 @@ const EventCalendarSSR = (props) => {
36003
36938
  case "timetable":
36004
36939
  content = renderTimetableSsr(display);
36005
36940
  break;
36941
+ case "week-board":
36942
+ content = renderWeekBoardSsr(display);
36943
+ break;
36006
36944
  case "calendar":
36007
36945
  content = renderCalendarSsr(display);
36008
36946
  break;
@@ -36611,6 +37549,7 @@ init_media_server();
36611
37549
  const serverComponentRegistry = {
36612
37550
  div: DivNode,
36613
37551
  figure: FigureNode,
37552
+ svg: SvgNode,
36614
37553
  section: SectionNode,
36615
37554
  headerSection: header_section_server_default,
36616
37555
  stack: StackNode,
@@ -104190,7 +105129,7 @@ var init_course_registration_client = __esmMin((() => {
104190
105129
  * Loads Leaflet CSS/JS from CDN to avoid bundling in the blocks package.
104191
105130
  */
104192
105131
  function isLeafletApi(value) {
104193
- if (!isRecord$16(value)) return false;
105132
+ if (!isRecord$18(value)) return false;
104194
105133
  return typeof value.map === "function" && typeof value.tileLayer === "function" && typeof value.marker === "function";
104195
105134
  }
104196
105135
  function loadLeaflet() {
@@ -111962,7 +112901,7 @@ function buildDisplayFilterParams(display) {
111962
112901
  filterVenueId: display.filterVenueId
111963
112902
  });
111964
112903
  }
111965
- var EventCalendarClient, EventCalendarTimetableClient, EventCalendarGridClient, EventCalendarChrome;
112904
+ var EventCalendarClient, EventCalendarWeekBoardClient, EventCalendarTimetableClient, EventCalendarGridClient, EventCalendarChrome;
111966
112905
  var init_EventCalendar_client = __esmMin((() => {
111967
112906
  init_EventCalendar_interactive();
111968
112907
  init_EventListing_client();
@@ -111975,6 +112914,7 @@ var init_EventCalendar_client = __esmMin((() => {
111975
112914
  init_EventModalContext();
111976
112915
  init_EventModals();
111977
112916
  init_WeekAgendaView();
112917
+ init_WeekBoardView();
111978
112918
  init_WeekTimetableView();
111979
112919
  init_buttons();
111980
112920
  init_listOptions();
@@ -112012,8 +112952,20 @@ var init_EventCalendar_client = __esmMin((() => {
112012
112952
  });
112013
112953
  if (display.displayMode === "list") return /* @__PURE__ */ jsx(EventListingController, { render: buildEventCalendarListingRender(render) });
112014
112954
  if (display.displayMode === "timetable") return /* @__PURE__ */ jsx(EventCalendarTimetableClient, { render });
112955
+ if (display.displayMode === "week-board") return /* @__PURE__ */ jsx(EventCalendarWeekBoardClient, { display });
112015
112956
  return /* @__PURE__ */ jsx(EventCalendarGridClient, { render });
112016
112957
  };
112958
+ EventCalendarWeekBoardClient = ({ display }) => {
112959
+ const days = useMemo(() => getWeekCalendarDayTuple(/* @__PURE__ */ new Date(), display.startOfWeek), [display.startOfWeek]);
112960
+ return /* @__PURE__ */ jsx(WeekBoardView, {
112961
+ days,
112962
+ events: [...display.events],
112963
+ showCapacity: display.showCapacity,
112964
+ emptyMessage: display.emptyMessage,
112965
+ ctaLabel: display.buttonText,
112966
+ buttonVariant: display.buttonVariant
112967
+ });
112968
+ };
112017
112969
  EventCalendarTimetableClient = ({ render }) => {
112018
112970
  const { display, hydration } = render;
112019
112971
  const { filtersNode, listFilters } = useEventCalendarFilterState(display);
@@ -113063,10 +114015,14 @@ const clientComponentRegistry$1 = buildClientRegistryFromEntries(serverComponent
113063
114015
  "weekly-slot-availability": defineSourcePropsClientEntry(WeeklySlotAvailabilityClient)
113064
114016
  }, runtimeBackedBlockClientRegistry);
113065
114017
  //#endregion
114018
+ //#region ../theme-core/src/styles/shadow.ts
114019
+ init_colorStyles();
114020
+ //#endregion
113066
114021
  //#region ../theme-core/src/accordions/generateAccordionCss.ts
113067
114022
  init_types$13();
113068
114023
  init_constants$1();
113069
114024
  init_colorStyles();
114025
+ init_surfaces();
113070
114026
  //#endregion
113071
114027
  //#region ../theme-core/src/accordions/defaults.ts
113072
114028
  init_curatedSiteStyles();
@@ -113106,10 +114062,10 @@ function svgDataUrl(svg) {
113106
114062
  }
113107
114063
  //#endregion
113108
114064
  //#region ../theme-core/src/status/generateStatusCss.ts
113109
- init_contextualColors();
114065
+ init_surfaces();
113110
114066
  //#endregion
113111
- //#region ../theme-core/src/status/index.ts
113112
- init_contextualColors();
114067
+ //#region ../theme-core/src/typography/generateTypographyCss.ts
114068
+ init_surfaces();
113113
114069
  //#endregion
113114
114070
  //#region ../theme-core/src/blocks/vars/event-registration.ts
113115
114071
  /**
@@ -113447,6 +114403,7 @@ const THEME_RADIUS_CSS_VARS = {
113447
114403
  block: "--rb-block-radius",
113448
114404
  button: "--rb-button-radius",
113449
114405
  input: "--rb-input-radius",
114406
+ panel: "--rb-panel-radius",
113450
114407
  legacyCard: "--radius-card",
113451
114408
  legacyControl: "--radius-control"
113452
114409
  };
@@ -113528,6 +114485,10 @@ ${`:where([data-theme-scope="${themeId}"]) :where([data-block="customer-portal"]
113528
114485
  /* Modal (shared rb-modal classes) */
113529
114486
  --rb-modal-overlay-bg: rgb(var(--tb-text, 0 0 0) / 0.35);
113530
114487
  --rb-modal-bg: var(--cp-card-bg);
114488
+ --rb-modal-text: var(--cp-text);
114489
+ --rb-modal-heading: var(--cp-text);
114490
+ --rb-modal-link: var(--cp-primary);
114491
+ --rb-modal-supporting: var(--cp-muted);
113531
114492
  --rb-modal-border: var(--cp-card-border);
113532
114493
  --rb-modal-shadow: var(--shadow-lg, var(--shadow-elev));
113533
114494
  --rb-modal-radius: var(--cp-card-radius);