riverbankcms 0.6.0 → 0.7.1

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.
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { D as isCanonicalRichTextDoc, Ft as ok, G as parseBookingTimeZone, Pt as err, V as parseUtcIsoDateTimeString, b as parseFooterCompositionV1, c as EVENT_PRESET_VALUES, k as isPresent, l as ORDINARY_EVENT_PRESET_VALUES, nt as assertNever, o as resolveSiteVerticalBookingConfig, v as stableJsonStringify, y as footerNavigationLayouts } from "./src-X9oZOIoK.mjs";
2
+ import { A as parseFooterCompositionV1, Ht as ok, K as parseUtcIsoDateTimeString, M as isCanonicalRichTextDoc, P as isPresent, Vt as err, X as parseBookingTimeZone, b as stableJsonStringify, k as footerNavigationLayouts, l as EVENT_PRESET_VALUES, lt as assertNever, s as resolveSiteVerticalBookingConfig, t as NAVIGATION_LOCATIONS, u as ORDINARY_EVENT_PRESET_VALUES } from "./src-B8fOSKJ6.mjs";
3
3
  import "node:module";
4
4
  import { z } from "zod";
5
5
 
@@ -272,16 +272,6 @@ const eventRegistrationStatuses = ["confirmed"];
272
272
 
273
273
  //#endregion
274
274
  //#region ../site-commands/src/commandDomain.ts
275
- const navigationLocations = [
276
- "main",
277
- "header",
278
- "footer"
279
- ];
280
- const navigationMenuRoles = [
281
- "primary",
282
- "footer",
283
- "legal-policy"
284
- ];
285
275
  const offeringVisibilities = [
286
276
  "draft",
287
277
  "unlisted",
@@ -1815,90 +1805,6 @@ function resolveCardRole(theme, cardSystem, role) {
1815
1805
  }
1816
1806
  }
1817
1807
 
1818
- //#endregion
1819
- //#region ../theme-core/src/tokens/resolver.ts
1820
- /**
1821
- * Resolves theme tokens to CSS variables
1822
- *
1823
- * This resolver ensures all button styles use theme tokens (not hardcoded colors)
1824
- * so that changing the palette automatically updates all buttons.
1825
- */
1826
- var TokenResolver = class {
1827
- constructor(theme) {
1828
- this.theme = theme;
1829
- }
1830
- /**
1831
- * Resolve a color token to a CSS variable reference wrapped in rgb()
1832
- *
1833
- * @param token - Token name (e.g., 'primary-500', 'white', 'text-900')
1834
- * @returns CSS rgb() function with var reference (e.g., 'rgb(var(--tb-primary-500))')
1835
- *
1836
- * Note: CSS variables are stored as RGB channels (e.g., "37 99 235") following Tailwind convention,
1837
- * so we must wrap them with rgb() to create a valid color value.
1838
- *
1839
- * @example
1840
- * resolver.getColor('primary-500') // => 'rgb(var(--tb-primary-500))'
1841
- * resolver.getColor('white') // => 'rgb(var(--tb-white))'
1842
- */
1843
- getColor(token) {
1844
- if (!this.tokenExists(token)) {
1845
- console.warn(`[TokenResolver] Color token "${token}" not found in theme palette. Button may render incorrectly.`);
1846
- }
1847
- return `rgb(var(--tb-${token}))`;
1848
- }
1849
- /**
1850
- * Adjust a color token's shade by a given amount
1851
- *
1852
- * @param token - Base token (e.g., 'primary-500')
1853
- * @param amount - Shade adjustment (+100 = darker, -100 = lighter)
1854
- * @returns Adjusted token name (e.g., 'primary-600')
1855
- *
1856
- * @example
1857
- * resolver.adjustShade('primary-500', 100) // => 'primary-600' (darker)
1858
- * resolver.adjustShade('primary-500', -100) // => 'primary-400' (lighter)
1859
- */
1860
- adjustShade(token, amount) {
1861
- const parts = token.split("-");
1862
- if (parts.length < 2) {
1863
- const newShade$1 = Math.max(100, Math.min(900, 500 + amount));
1864
- return `${token}-${newShade$1}`;
1865
- }
1866
- const base = parts.slice(0, -1).join("-");
1867
- const shade = parseInt(parts[parts.length - 1] ?? "", 10);
1868
- if (isNaN(shade)) {
1869
- console.warn(`[TokenResolver] Cannot adjust shade for non-shade token "${token}". Returning original token.`);
1870
- return token;
1871
- }
1872
- const newShade = Math.max(100, Math.min(900, shade + amount));
1873
- return `${base}-${newShade}`;
1874
- }
1875
- /**
1876
- * Check if a token exists in the theme palette
1877
- *
1878
- * @param token - Token name to check
1879
- * @returns True if token exists in theme
1880
- */
1881
- tokenExists(token) {
1882
- const commonTokens = [
1883
- "white",
1884
- "black",
1885
- "transparent"
1886
- ];
1887
- if (commonTokens.includes(token)) {
1888
- return true;
1889
- }
1890
- const parts = token.split("-");
1891
- if (parts.length >= 2) {
1892
- const lastPart = parts[parts.length - 1] ?? "";
1893
- const shade = parseInt(lastPart, 10);
1894
- if (!isNaN(shade) && shade >= 100 && shade <= 900 && shade % 100 === 0) {
1895
- return true;
1896
- }
1897
- }
1898
- return true;
1899
- }
1900
- };
1901
-
1902
1808
  //#endregion
1903
1809
  //#region ../theme-core/src/surfaces/foregroundRoles.ts
1904
1810
  const SURFACE_FOREGROUND_ROLES = [
@@ -2172,156 +2078,452 @@ function raiseContrastText(bgHex, preferred) {
2172
2078
  }
2173
2079
 
2174
2080
  //#endregion
2175
- //#region ../theme-core/src/palette/utils/onColor.ts
2176
- const BACKGROUND_ROLE_NAMES = new Set([
2177
- "primary",
2178
- "secondary",
2179
- "accent",
2180
- "success",
2181
- "warning",
2182
- "destructive",
2183
- "info",
2184
- "background",
2185
- "surface",
2186
- "surfaceAlt",
2187
- "muted",
2188
- "neutral"
2189
- ]);
2190
- function onColorTokenName(backgroundToken) {
2191
- return `on${backgroundToken.split("-").filter((part) => part.length > 0).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("")}`;
2192
- }
2193
- function isOnColorBackgroundCandidateToken(token) {
2194
- const role = token.match(/^(.*?)(?:-\d{2,3})?$/)?.[1] ?? token;
2195
- return BACKGROUND_ROLE_NAMES.has(role);
2196
- }
2197
-
2198
- //#endregion
2199
- //#region ../theme-core/src/palette/utils/opaqueSurfaceColor.ts
2200
- /** Resolve an opaque colour, compositing alpha against an explicit underlay. */
2201
- function resolveOpaqueSurfaceHex(reference, palette, underlayReference) {
2202
- const opaque = resolveConcreteColorHex(reference, palette);
2203
- if (opaque) return opaque;
2204
- if (!underlayReference) return null;
2205
- const underlayHex = resolveConcreteColorHex(underlayReference, palette);
2206
- if (!underlayHex) return null;
2207
- const parts = parseColorTokenParts(reference);
2208
- if (parts.kind === "token" && parts.opacityPercent !== null) {
2209
- const foregroundHex = normalizePaletteHex(palette[parts.token] ?? "");
2210
- return foregroundHex ? compositeHex(foregroundHex, underlayHex, parts.opacityPercent / 100) : null;
2211
- }
2212
- const raw = parts.kind === "raw" ? parts.value : reference;
2213
- const rgba = parseRgba(raw);
2214
- return rgba ? compositeHex(rgbToHex(rgba.r, rgba.g, rgba.b), underlayHex, rgba.alpha) : null;
2215
- }
2216
- /** Resolve a colour reference only when it is already fully opaque. */
2217
- function resolveConcreteColorHex(reference, palette) {
2218
- const literalHex = normalizePaletteHex(reference);
2219
- if (literalHex) return literalHex;
2220
- const parts = parseColorTokenParts(reference);
2221
- if (parts.kind === "token") {
2222
- if (parts.opacityPercent !== null) return null;
2223
- return normalizePaletteHex(palette[parts.token] ?? "");
2224
- }
2225
- const literal = parts.kind === "raw" ? parts.value : reference;
2226
- if (literal.toLowerCase() === "black") return "#000000";
2227
- if (literal.toLowerCase() === "white") return "#ffffff";
2228
- return normalizePaletteHex(literal);
2229
- }
2230
- function compositeHex(foregroundHex, underlayHex, alpha) {
2231
- const foreground = hexToRgb(foregroundHex);
2232
- const underlay = hexToRgb(underlayHex);
2233
- const channel = (foregroundValue, underlayValue) => Math.round(foregroundValue * alpha + underlayValue * (1 - alpha));
2234
- return rgbToHex(channel(foreground.r, underlay.r), channel(foreground.g, underlay.g), channel(foreground.b, underlay.b));
2235
- }
2236
- function parseRgba(value) {
2237
- const match = value.trim().match(/^rgba?\(\s*([\d.]+)(?:\s*,\s*|\s+)([\d.]+)(?:\s*,\s*|\s+)([\d.]+)(?:\s*(?:,|\/)\s*([\d.]+%?))?\s*\)$/i);
2238
- if (!match) return null;
2239
- const [, rSource, gSource, bSource] = match;
2240
- if (!rSource || !gSource || !bSource) return null;
2241
- const r = Number(rSource);
2242
- const g = Number(gSource);
2243
- const b = Number(bSource);
2244
- const alpha = parseAlpha(match[4]);
2245
- if (alpha === null || !isRgbChannel(r) || !isRgbChannel(g) || !isRgbChannel(b)) {
2246
- return null;
2247
- }
2248
- return {
2249
- r,
2250
- g,
2251
- b,
2252
- alpha
2253
- };
2254
- }
2255
- function parseAlpha(source) {
2256
- if (!source) return 1;
2257
- const value = source.endsWith("%") ? Number(source.slice(0, -1)) / 100 : Number(source);
2258
- return Number.isFinite(value) && value >= 0 && value <= 1 ? value : null;
2259
- }
2260
- function isRgbChannel(value) {
2261
- return Number.isFinite(value) && value >= 0 && value <= 255;
2262
- }
2263
-
2264
- //#endregion
2265
- //#region ../theme-core/src/surfaces/resolveSurfaceForeground.ts
2266
- const FALLBACK_TEXT_TOKENS = [
2267
- "text",
2268
- "primaryForeground",
2269
- "secondaryForeground",
2270
- "accentForeground",
2271
- "neutral-950",
2272
- "neutral-50"
2081
+ //#region ../theme-core/src/tokens/tokens.ts
2082
+ const colorTokens = [
2083
+ "background/base",
2084
+ "background/elevated",
2085
+ "surface/base",
2086
+ "surface/subtle",
2087
+ "surface/inverted",
2088
+ "content/primary",
2089
+ "content/secondary",
2090
+ "accent/primary",
2091
+ "accent/secondary",
2092
+ "border/base"
2273
2093
  ];
2274
- const CANONICAL_EQUIVALENT_TOKEN_ORDER = [
2275
- "text",
2276
- "primaryForeground",
2277
- "secondaryForeground",
2278
- "accentForeground",
2279
- "onPrimary",
2280
- "onSecondary",
2281
- "onAccent",
2282
- "onSurface",
2283
- "neutral-950",
2284
- "neutral-50"
2094
+ const typographyTokens = [
2095
+ "display/hero",
2096
+ "display/section",
2097
+ "heading/large",
2098
+ "heading/medium",
2099
+ "heading/small",
2100
+ "body/normal",
2101
+ "body/small",
2102
+ "caption"
2285
2103
  ];
2286
- /**
2287
- * Resolve the complete foreground contract for an effective page/section or
2288
- * site-chrome background.
2289
- *
2290
- * Deterministic colour backgrounds are validated at ordinary-text WCAG AA.
2291
- * Existing image/video/gradient treatments are trusted only when they already
2292
- * carry a usable foreground token; this function deliberately does not claim
2293
- * pixel-level contrast proof for media.
2294
- */
2295
- function resolveSurfaceForeground(background, palette, candidates = {}, options = {}) {
2296
- const authored = foregroundCandidates(background, candidates);
2297
- if (background === null) {
2298
- return resolveDeterministicForeground("background", {
2299
- ...authored,
2300
- text: authored.text ?? "text"
2301
- }, palette);
2302
- }
2303
- if (background.type === "color") {
2304
- const backgroundReference = normalizedReference(background.color);
2305
- if (!backgroundReference || backgroundReference === "transparent") {
2306
- return { kind: "unknown" };
2307
- }
2308
- return resolveDeterministicForeground(backgroundReference, authored, palette, options.compositeBase);
2309
- }
2310
- return resolveTrustedTreatmentForeground(authored, palette);
2311
- }
2312
- function foregroundCandidates(background, overrides) {
2313
- return {
2314
- text: overrides.text ?? background?.textColor ?? null,
2315
- heading: overrides.heading ?? background?.headingColor ?? null,
2316
- link: overrides.link ?? background?.linkColor ?? null,
2317
- supporting: overrides.supporting ?? background?.supportingColor ?? null
2318
- };
2319
- }
2320
- function resolveDeterministicForeground(backgroundReference, candidates, palette, compositeBase) {
2321
- const backgroundHex = resolveOpaqueSurfaceHex(backgroundReference, palette, compositeBase);
2322
- if (!backgroundHex) {
2323
- return resolveTrustedTreatmentForeground(candidates, palette);
2324
- }
2104
+ const spacingTokens = [
2105
+ "none",
2106
+ "3xs",
2107
+ "2xs",
2108
+ "xs",
2109
+ "sm",
2110
+ "md",
2111
+ "lg",
2112
+ "xl",
2113
+ "2xl",
2114
+ "3xl"
2115
+ ];
2116
+ const radiusTokens = [
2117
+ "none",
2118
+ "xs",
2119
+ "sm",
2120
+ "md",
2121
+ "lg",
2122
+ "pill",
2123
+ "full"
2124
+ ];
2125
+ const shadowTokens = [
2126
+ "none",
2127
+ "soft",
2128
+ "medium",
2129
+ "strong"
2130
+ ];
2131
+ const defaultThemeTokens = {
2132
+ color: {
2133
+ "background/base": "#ffffff",
2134
+ "background/elevated": "#f5f5f5",
2135
+ "surface/base": "#ffffff",
2136
+ "surface/subtle": "#f9f9fb",
2137
+ "surface/inverted": "#111111",
2138
+ "content/primary": "#111111",
2139
+ "content/secondary": "#3f3f46",
2140
+ "accent/primary": "#2563eb",
2141
+ "accent/secondary": "#1d4ed8",
2142
+ "border/base": "#e5e7eb"
2143
+ },
2144
+ typography: {
2145
+ "display/hero": {
2146
+ fontSize: "clamp(48px, 8vw, 96px)",
2147
+ lineHeight: "1.05",
2148
+ fontWeight: "700"
2149
+ },
2150
+ "display/section": {
2151
+ fontSize: "clamp(40px, 6vw, 72px)",
2152
+ lineHeight: "1.1",
2153
+ fontWeight: "700"
2154
+ },
2155
+ "heading/large": {
2156
+ fontSize: "clamp(32px, 4vw, 48px)",
2157
+ lineHeight: "1.2",
2158
+ fontWeight: "600"
2159
+ },
2160
+ "heading/medium": {
2161
+ fontSize: "clamp(24px, 3vw, 32px)",
2162
+ lineHeight: "1.25",
2163
+ fontWeight: "600"
2164
+ },
2165
+ "heading/small": {
2166
+ fontSize: "20px",
2167
+ lineHeight: "1.3",
2168
+ fontWeight: "600"
2169
+ },
2170
+ "body/normal": {
2171
+ fontSize: "16px",
2172
+ lineHeight: "1.6",
2173
+ fontWeight: "400"
2174
+ },
2175
+ "body/small": {
2176
+ fontSize: "14px",
2177
+ lineHeight: "1.5",
2178
+ fontWeight: "400"
2179
+ },
2180
+ caption: {
2181
+ fontSize: "12px",
2182
+ lineHeight: "1.4",
2183
+ fontWeight: "500"
2184
+ }
2185
+ },
2186
+ spacing: {
2187
+ none: "0px",
2188
+ "3xs": "4px",
2189
+ "2xs": "8px",
2190
+ xs: "12px",
2191
+ sm: "16px",
2192
+ md: "24px",
2193
+ lg: "32px",
2194
+ xl: "40px",
2195
+ "2xl": "56px",
2196
+ "3xl": "72px"
2197
+ },
2198
+ radius: {
2199
+ none: "0px",
2200
+ xs: "2px",
2201
+ sm: "4px",
2202
+ md: "8px",
2203
+ lg: "12px",
2204
+ pill: "999px",
2205
+ full: "9999px"
2206
+ },
2207
+ shadow: {
2208
+ none: "none",
2209
+ soft: "0px 2px 8px rgba(15, 23, 42, 0.08)",
2210
+ medium: "0px 6px 18px rgba(15, 23, 42, 0.12)",
2211
+ strong: "0px 12px 36px rgba(15, 23, 42, 0.16)"
2212
+ },
2213
+ palette: {
2214
+ surface: "#ffffff",
2215
+ "neutral-50": "#f9fafb",
2216
+ "neutral-900": "#111827",
2217
+ primary: "#2563eb",
2218
+ "primary-50": "#eff6ff",
2219
+ "primary-500": "#2563eb",
2220
+ "primary-900": "#1d4ed8",
2221
+ secondary: "#9333ea",
2222
+ "secondary-50": "#f3e8ff",
2223
+ "secondary-500": "#9333ea",
2224
+ "secondary-900": "#4c1d95",
2225
+ accent: "#f97316",
2226
+ "accent-50": "#fff7ed",
2227
+ "accent-500": "#f97316",
2228
+ "accent-900": "#7c2d12"
2229
+ }
2230
+ };
2231
+ /**
2232
+ * Project the expanded semantic palette into the token buckets consumed by
2233
+ * runtime transforms. Keep this mapping shared by full themes and the
2234
+ * tokens-only hosted-booking runtime so the two paths cannot drift.
2235
+ */
2236
+ function buildThemeTokens(palette) {
2237
+ const tokens = cloneThemeTokens(defaultThemeTokens);
2238
+ const paletteStrings = {};
2239
+ for (const [key, value] of Object.entries(palette)) {
2240
+ if (typeof value === "string" && value.trim().length > 0) {
2241
+ paletteStrings[key] = value;
2242
+ }
2243
+ }
2244
+ tokens.palette = paletteStrings;
2245
+ const resolveColor = (...keys) => {
2246
+ for (const key of keys) {
2247
+ const value = paletteStrings[key];
2248
+ if (value) return value;
2249
+ }
2250
+ return undefined;
2251
+ };
2252
+ const assignColor = (token, ...keys) => {
2253
+ const value = resolveColor(...keys);
2254
+ if (value) tokens.color[token] = value;
2255
+ };
2256
+ assignColor("background/base", "background", "surface", "primary-50");
2257
+ assignColor("background/elevated", "surface", "background");
2258
+ assignColor("surface/base", "surface", "background");
2259
+ assignColor("surface/subtle", "neutral-100", "surface", "background");
2260
+ assignColor("surface/inverted", "neutral-900", "text", "primary-900");
2261
+ assignColor("content/primary", "text", "body", "neutral-900");
2262
+ assignColor("content/secondary", "mutedText", "secondary", "neutral-600");
2263
+ assignColor("accent/primary", "primary", "accent");
2264
+ assignColor("accent/secondary", "accent", "secondary", "primary-400");
2265
+ assignColor("border/base", "border", "neutral-300");
2266
+ return tokens;
2267
+ }
2268
+ function cloneThemeTokens(source) {
2269
+ return JSON.parse(JSON.stringify(source));
2270
+ }
2271
+
2272
+ //#endregion
2273
+ //#region ../theme-core/src/surfaces/foregroundInteraction.ts
2274
+ /**
2275
+ * How far a hover state softens away from its resting foreground, as a
2276
+ * percentage of full opacity.
2277
+ *
2278
+ * Softening — rather than brightening — is forced by the token vocabulary
2279
+ * rather than chosen for taste. A resolved foreground is frequently an
2280
+ * `on*` token, which `expandPalette` emits as pure `#FFFFFF` or `#000000`
2281
+ * with no shade ramp: over a primary-painted section the resolved text role
2282
+ * is `onPrimary`, and white has no headroom left to move further from its
2283
+ * background. Moving *toward* the mid-range always has headroom, whatever
2284
+ * the resting colour, and it keeps the hue exactly.
2285
+ *
2286
+ * 85% is the measured floor, not a round number. Softening costs contrast, and
2287
+ * the binding case is a scrolled overlay header: `contrast-glass` paints 60%
2288
+ * black or white, which composites the backdrop into a known band whatever the
2289
+ * page content underneath happens to be. The lightest backdrop a dark glass can
2290
+ * present is 60% black over white, `#666666`; a white foreground softened to
2291
+ * 85% reads 4.69:1 there, against 4.07:1 at 75%, which fails. Nav links are
2292
+ * 18px regular (`textSize: 'lg'`), so the bar is WCAG AA's 4.5:1 rather than
2293
+ * the large-text 3:1.
2294
+ *
2295
+ * The mirror case — a light glass over dark content, `#999999` — cannot be met
2296
+ * by any softening, because the *resting* colour is already only about 4.6:1
2297
+ * there. That is a property of the glass rather than of this derivation, and
2298
+ * it wants fixing where the glass tone is chosen.
2299
+ */
2300
+ const FOREGROUND_HOVER_OPACITY_PERCENT = 85;
2301
+ /**
2302
+ * Derive the hover foreground that belongs with a resolved resting foreground.
2303
+ *
2304
+ * A resting foreground is chosen to be legible against a known surface. A hover
2305
+ * state derived from it stays within a bounded distance of that colour, so it
2306
+ * inherits most of the resting colour's contrast margin instead of asserting
2307
+ * an unrelated brand colour that no one checked against the surface.
2308
+ *
2309
+ * That bounded-distance property is what lets this be used on a transparent
2310
+ * overlay header, where the backdrop is only partly knowable: the scrolled
2311
+ * state composites a 60% glass tint over arbitrary page content, so no
2312
+ * compile-time contrast proof is available there. Staying near a colour that
2313
+ * is already trusted in both states is a weaker claim than a contrast proof,
2314
+ * and it is one this function can actually keep.
2315
+ *
2316
+ * Returns `null` when the resting token is not a plain palette token — an
2317
+ * already-faded or raw value has no well-defined softening, and the caller
2318
+ * should leave hover alone rather than guess.
2319
+ */
2320
+ function deriveForegroundHoverToken(restingToken) {
2321
+ const parts = parseColorTokenParts(restingToken);
2322
+ if (parts.kind !== "token") return null;
2323
+ if (parts.opacityPercent !== null) return null;
2324
+ return parseThemeColorToken(`${parts.token}/${FOREGROUND_HOVER_OPACITY_PERCENT}`);
2325
+ }
2326
+ /**
2327
+ * The opacity `contrast-glass` paints at. Mirrors the value in
2328
+ * `generateHeaderScrollTreatmentStyles`; the two must agree, because the whole
2329
+ * point of the bound below is that it describes what that treatment can produce.
2330
+ */
2331
+ const CONTRAST_GLASS_ALPHA = .6;
2332
+ /**
2333
+ * The extreme backdrop a glass tone can present, whatever page content happens
2334
+ * to be underneath it.
2335
+ *
2336
+ * A 60% tint clamps the composite into a known band, which is what makes a
2337
+ * conservative check possible at compile time even though the content passing
2338
+ * under a sticky header is not knowable. For a dark glass the composite is
2339
+ * lightest over white; for a light glass it is darkest over black. Those are
2340
+ * the two ends that a foreground has to survive.
2341
+ */
2342
+ function worstCaseGlassBackdrop(tone) {
2343
+ const [over, tint] = tone === "dark" ? ["#ffffff", "#000000"] : ["#000000", "#ffffff"];
2344
+ return compositeHex$1(tint, over, CONTRAST_GLASS_ALPHA);
2345
+ }
2346
+ /** Flatten `foreground` at `alpha` over `background` into an opaque hex. */
2347
+ function compositeHex$1(foreground, background, alpha) {
2348
+ const f = hexToRgb(foreground);
2349
+ const b = hexToRgb(background);
2350
+ return rgbToHex(Math.round(mix$2(b.r, f.r, alpha)), Math.round(mix$2(b.g, f.g, alpha)), Math.round(mix$2(b.b, f.b, alpha)));
2351
+ }
2352
+ /**
2353
+ * Decide whether the resting foreground can safely be softened for hover.
2354
+ *
2355
+ * `glassTone` is the scroll treatment's compiled tone, or `null` when the style
2356
+ * has no glass. Without one there is no bound on what the header can end up
2357
+ * over, so this declines to soften rather than guess.
2358
+ *
2359
+ * The light-glass end cannot be satisfied by any softening: against `#999999`
2360
+ * a dark resting foreground is already close to the 4.5:1 line, so every step
2361
+ * away from it fails. That is why this returns a plan rather than a colour —
2362
+ * the caller has to have a non-colour affordance to fall back on.
2363
+ */
2364
+ function planForegroundHover(restingToken, restingHex, glassTone) {
2365
+ const softened = deriveForegroundHoverToken(restingToken);
2366
+ if (!softened) return { kind: "resting" };
2367
+ if (!restingHex || !glassTone) return { kind: "resting" };
2368
+ const backdrop = worstCaseGlassBackdrop(glassTone);
2369
+ const softenedHex = compositeHex$1(restingHex, backdrop, FOREGROUND_HOVER_OPACITY_PERCENT / 100);
2370
+ return contrastRatio(softenedHex, backdrop) >= ORDINARY_TEXT_MIN_CONTRAST_RATIO ? {
2371
+ kind: "softened",
2372
+ token: softened
2373
+ } : { kind: "resting" };
2374
+ }
2375
+
2376
+ //#endregion
2377
+ //#region ../theme-core/src/palette/utils/onColor.ts
2378
+ const BACKGROUND_ROLE_NAMES = new Set([
2379
+ "primary",
2380
+ "secondary",
2381
+ "accent",
2382
+ "success",
2383
+ "warning",
2384
+ "destructive",
2385
+ "info",
2386
+ "background",
2387
+ "surface",
2388
+ "surfaceAlt",
2389
+ "muted",
2390
+ "neutral"
2391
+ ]);
2392
+ function onColorTokenName(backgroundToken) {
2393
+ return `on${backgroundToken.split("-").filter((part) => part.length > 0).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("")}`;
2394
+ }
2395
+ function isOnColorBackgroundCandidateToken(token) {
2396
+ const role = token.match(/^(.*?)(?:-\d{2,3})?$/)?.[1] ?? token;
2397
+ return BACKGROUND_ROLE_NAMES.has(role);
2398
+ }
2399
+
2400
+ //#endregion
2401
+ //#region ../theme-core/src/palette/utils/opaqueSurfaceColor.ts
2402
+ /** Resolve an opaque colour, compositing alpha against an explicit underlay. */
2403
+ function resolveOpaqueSurfaceHex(reference, palette, underlayReference) {
2404
+ const opaque = resolveConcreteColorHex(reference, palette);
2405
+ if (opaque) return opaque;
2406
+ if (!underlayReference) return null;
2407
+ const underlayHex = resolveConcreteColorHex(underlayReference, palette);
2408
+ if (!underlayHex) return null;
2409
+ const parts = parseColorTokenParts(reference);
2410
+ if (parts.kind === "token" && parts.opacityPercent !== null) {
2411
+ const foregroundHex = normalizePaletteHex(palette[parts.token] ?? "");
2412
+ return foregroundHex ? compositeHex(foregroundHex, underlayHex, parts.opacityPercent / 100) : null;
2413
+ }
2414
+ const raw = parts.kind === "raw" ? parts.value : reference;
2415
+ const rgba = parseRgba(raw);
2416
+ return rgba ? compositeHex(rgbToHex(rgba.r, rgba.g, rgba.b), underlayHex, rgba.alpha) : null;
2417
+ }
2418
+ /** Resolve a colour reference only when it is already fully opaque. */
2419
+ function resolveConcreteColorHex(reference, palette) {
2420
+ const literalHex = normalizePaletteHex(reference);
2421
+ if (literalHex) return literalHex;
2422
+ const parts = parseColorTokenParts(reference);
2423
+ if (parts.kind === "token") {
2424
+ if (parts.opacityPercent !== null) return null;
2425
+ return normalizePaletteHex(palette[parts.token] ?? "");
2426
+ }
2427
+ const literal = parts.kind === "raw" ? parts.value : reference;
2428
+ if (literal.toLowerCase() === "black") return "#000000";
2429
+ if (literal.toLowerCase() === "white") return "#ffffff";
2430
+ return normalizePaletteHex(literal);
2431
+ }
2432
+ function compositeHex(foregroundHex, underlayHex, alpha) {
2433
+ const foreground = hexToRgb(foregroundHex);
2434
+ const underlay = hexToRgb(underlayHex);
2435
+ const channel = (foregroundValue, underlayValue) => Math.round(foregroundValue * alpha + underlayValue * (1 - alpha));
2436
+ return rgbToHex(channel(foreground.r, underlay.r), channel(foreground.g, underlay.g), channel(foreground.b, underlay.b));
2437
+ }
2438
+ function parseRgba(value) {
2439
+ const match = value.trim().match(/^rgba?\(\s*([\d.]+)(?:\s*,\s*|\s+)([\d.]+)(?:\s*,\s*|\s+)([\d.]+)(?:\s*(?:,|\/)\s*([\d.]+%?))?\s*\)$/i);
2440
+ if (!match) return null;
2441
+ const [, rSource, gSource, bSource] = match;
2442
+ if (!rSource || !gSource || !bSource) return null;
2443
+ const r = Number(rSource);
2444
+ const g = Number(gSource);
2445
+ const b = Number(bSource);
2446
+ const alpha = parseAlpha(match[4]);
2447
+ if (alpha === null || !isRgbChannel(r) || !isRgbChannel(g) || !isRgbChannel(b)) {
2448
+ return null;
2449
+ }
2450
+ return {
2451
+ r,
2452
+ g,
2453
+ b,
2454
+ alpha
2455
+ };
2456
+ }
2457
+ function parseAlpha(source) {
2458
+ if (!source) return 1;
2459
+ const value = source.endsWith("%") ? Number(source.slice(0, -1)) / 100 : Number(source);
2460
+ return Number.isFinite(value) && value >= 0 && value <= 1 ? value : null;
2461
+ }
2462
+ function isRgbChannel(value) {
2463
+ return Number.isFinite(value) && value >= 0 && value <= 255;
2464
+ }
2465
+
2466
+ //#endregion
2467
+ //#region ../theme-core/src/surfaces/resolveSurfaceForeground.ts
2468
+ const FALLBACK_TEXT_TOKENS = [
2469
+ "text",
2470
+ "primaryForeground",
2471
+ "secondaryForeground",
2472
+ "accentForeground",
2473
+ "neutral-950",
2474
+ "neutral-50"
2475
+ ];
2476
+ const CANONICAL_EQUIVALENT_TOKEN_ORDER = [
2477
+ "text",
2478
+ "primaryForeground",
2479
+ "secondaryForeground",
2480
+ "accentForeground",
2481
+ "onPrimary",
2482
+ "onSecondary",
2483
+ "onAccent",
2484
+ "onSurface",
2485
+ "neutral-950",
2486
+ "neutral-50"
2487
+ ];
2488
+ /**
2489
+ * Resolve the complete foreground contract for an effective page/section or
2490
+ * site-chrome background.
2491
+ *
2492
+ * Deterministic colour backgrounds are validated at ordinary-text WCAG AA.
2493
+ * Existing image/video/gradient treatments are trusted only when they already
2494
+ * carry a usable foreground token; this function deliberately does not claim
2495
+ * pixel-level contrast proof for media.
2496
+ */
2497
+ function resolveSurfaceForeground(background, palette, candidates = {}, options = {}) {
2498
+ const authored = foregroundCandidates(background, candidates);
2499
+ if (background === null) {
2500
+ return resolveDeterministicForeground("background", {
2501
+ ...authored,
2502
+ text: authored.text ?? "text"
2503
+ }, palette);
2504
+ }
2505
+ if (background.type === "color") {
2506
+ const backgroundReference = normalizedReference(background.color);
2507
+ if (!backgroundReference || backgroundReference === "transparent") {
2508
+ return { kind: "unknown" };
2509
+ }
2510
+ return resolveDeterministicForeground(backgroundReference, authored, palette, options.compositeBase);
2511
+ }
2512
+ return resolveTrustedTreatmentForeground(authored, palette);
2513
+ }
2514
+ function foregroundCandidates(background, overrides) {
2515
+ return {
2516
+ text: overrides.text ?? background?.textColor ?? null,
2517
+ heading: overrides.heading ?? background?.headingColor ?? null,
2518
+ link: overrides.link ?? background?.linkColor ?? null,
2519
+ supporting: overrides.supporting ?? background?.supportingColor ?? null
2520
+ };
2521
+ }
2522
+ function resolveDeterministicForeground(backgroundReference, candidates, palette, compositeBase) {
2523
+ const backgroundHex = resolveOpaqueSurfaceHex(backgroundReference, palette, compositeBase);
2524
+ if (!backgroundHex) {
2525
+ return resolveTrustedTreatmentForeground(candidates, palette);
2526
+ }
2325
2527
  const backgroundToken = paletteToken(backgroundReference);
2326
2528
  const derivedOnToken = backgroundToken ? onColorTokenName(backgroundToken) : null;
2327
2529
  const text = firstSafeToken([
@@ -2338,63 +2540,288 @@ function resolveDeterministicForeground(backgroundReference, candidates, palette
2338
2540
  link: safeTokenOr(candidates.link, text, backgroundHex, palette),
2339
2541
  supporting: safeTokenOr(candidates.supporting, text, backgroundHex, palette)
2340
2542
  }
2341
- };
2342
- }
2343
- function resolveTrustedTreatmentForeground(candidates, palette) {
2344
- const text = canonicalToken(candidates.text, palette);
2345
- if (!text) return { kind: "unknown" };
2346
- return {
2347
- kind: "known",
2348
- roles: {
2349
- text,
2350
- heading: canonicalToken(candidates.heading, palette) ?? text,
2351
- link: canonicalToken(candidates.link, palette) ?? text,
2352
- supporting: canonicalToken(candidates.supporting, palette) ?? text
2543
+ };
2544
+ }
2545
+ function resolveTrustedTreatmentForeground(candidates, palette) {
2546
+ const text = canonicalToken(candidates.text, palette);
2547
+ if (!text) return { kind: "unknown" };
2548
+ return {
2549
+ kind: "known",
2550
+ roles: {
2551
+ text,
2552
+ heading: canonicalToken(candidates.heading, palette) ?? text,
2553
+ link: canonicalToken(candidates.link, palette) ?? text,
2554
+ supporting: canonicalToken(candidates.supporting, palette) ?? text
2555
+ }
2556
+ };
2557
+ }
2558
+ function safeTokenOr(candidate$1, fallback, backgroundHex, palette) {
2559
+ return firstSafeToken([candidate$1], backgroundHex, palette) ?? fallback;
2560
+ }
2561
+ function firstSafeToken(candidates, backgroundHex, palette, preferredEquivalentTokens = []) {
2562
+ const seen = new Set();
2563
+ for (const candidate$1 of candidates) {
2564
+ const token = canonicalToken(candidate$1, palette, preferredEquivalentTokens);
2565
+ if (!token || seen.has(token)) continue;
2566
+ seen.add(token);
2567
+ const foregroundHex = resolveConcreteColorHex(token, palette);
2568
+ if (foregroundHex && contrastRatio(backgroundHex, foregroundHex) >= ORDINARY_TEXT_MIN_CONTRAST_RATIO) {
2569
+ return token;
2570
+ }
2571
+ }
2572
+ return null;
2573
+ }
2574
+ function canonicalToken(reference, palette, preferredEquivalentTokens = []) {
2575
+ const normalized = normalizedReference(reference);
2576
+ if (!normalized || normalized === "transparent") return null;
2577
+ const direct = parseThemeColorToken(normalized);
2578
+ if (direct && resolveConcreteColorHex(direct, palette)) return direct;
2579
+ const referenceHex = resolveConcreteColorHex(normalized, palette);
2580
+ if (!referenceHex) return null;
2581
+ const equivalent = [
2582
+ ...preferredEquivalentTokens,
2583
+ ...CANONICAL_EQUIVALENT_TOKEN_ORDER,
2584
+ ...Object.keys(palette).sort()
2585
+ ].find((token) => {
2586
+ const parsed = parseThemeColorToken(token);
2587
+ return parsed !== null && resolveConcreteColorHex(parsed, palette)?.toLowerCase() === referenceHex.toLowerCase();
2588
+ });
2589
+ return equivalent ? parseThemeColorToken(equivalent) : null;
2590
+ }
2591
+ function paletteToken(reference) {
2592
+ const parts = parseColorTokenParts(reference);
2593
+ return parts.kind === "token" && parts.opacityPercent === null ? parts.token : null;
2594
+ }
2595
+ function normalizedReference(value) {
2596
+ if (typeof value !== "string") return null;
2597
+ const normalized = value.trim();
2598
+ return normalized.length > 0 ? normalized : null;
2599
+ }
2600
+
2601
+ //#endregion
2602
+ //#region ../theme-core/src/utils/colorStyles.ts
2603
+ const COLOR_VAR_PREFIX = "--tb-";
2604
+ function parseToken(source) {
2605
+ const parts = parseColorTokenParts(source);
2606
+ if (parts.kind === "raw") {
2607
+ return {
2608
+ token: source,
2609
+ raw: parts.value
2610
+ };
2611
+ }
2612
+ if (parts.kind === "invalid") {
2613
+ return { token: source };
2614
+ }
2615
+ return {
2616
+ token: parts.token,
2617
+ opacityPercent: parts.opacityPercent === null ? undefined : parts.opacityPercent
2618
+ };
2619
+ }
2620
+ const SURFACE_TEXT_ROLE_BY_TOKEN = {
2621
+ text: "text",
2622
+ heading: "heading",
2623
+ mutedText: "supporting"
2624
+ };
2625
+ function surfaceRoleForTextToken(token) {
2626
+ return Object.prototype.hasOwnProperty.call(SURFACE_TEXT_ROLE_BY_TOKEN, token) ? SURFACE_TEXT_ROLE_BY_TOKEN[token] : null;
2627
+ }
2628
+ /**
2629
+ * Converts a theme color token to a CSS rgb value.
2630
+ * This is the primary function for applying theme colors to CSS properties.
2631
+ *
2632
+ * @param token - Theme color token (semantic, with opacity, or raw)
2633
+ * @returns CSS color value (rgb with optional alpha, or raw CSS value)
2634
+ *
2635
+ * @example
2636
+ * rgbColorValue('primary') // => 'rgb(var(--tb-primary))'
2637
+ * rgbColorValue('surface/95') // => 'rgb(var(--tb-surface) / 0.95)'
2638
+ * rgbColorValue('raw:transparent') // => 'transparent'
2639
+ */
2640
+ function rgbColorValue(token) {
2641
+ const { token: baseToken, opacityPercent, raw } = parseToken(token);
2642
+ if (raw) {
2643
+ return raw;
2644
+ }
2645
+ const cssVar = `${COLOR_VAR_PREFIX}${baseToken}`;
2646
+ if (opacityPercent === undefined) {
2647
+ return `rgb(var(${cssVar}))`;
2648
+ }
2649
+ return `rgb(var(${cssVar}) / ${opacityPercent / 100})`;
2650
+ }
2651
+ /**
2652
+ * Converts a theme color token to a CSS variable reference.
2653
+ * Note: This returns the base variable without rgb() wrapper, ignoring opacity.
2654
+ *
2655
+ * @param token - Theme color token
2656
+ * @returns CSS variable reference
2657
+ *
2658
+ * @example
2659
+ * cssVarValue('primary') // => 'var(--tb-primary)'
2660
+ * cssVarValue('surface/95') // => 'var(--tb-surface)' (opacity ignored)
2661
+ */
2662
+ function cssVarValue(token) {
2663
+ const { token: baseToken } = parseToken(token);
2664
+ return `var(${COLOR_VAR_PREFIX}${baseToken})`;
2665
+ }
2666
+ /**
2667
+ * Creates a backgroundColor style object from a theme token.
2668
+ *
2669
+ * @param token - Theme color token
2670
+ * @returns CSSProperties with backgroundColor
2671
+ */
2672
+ function backgroundColorStyle(token) {
2673
+ return { backgroundColor: rgbColorValue(token) };
2674
+ }
2675
+ /**
2676
+ * Creates a text color style object from a theme token.
2677
+ *
2678
+ * @param token - Theme color token
2679
+ * @returns CSSProperties with color
2680
+ */
2681
+ function textColorStyle(token) {
2682
+ const parsed = parseToken(token);
2683
+ const surfaceRole = parsed.raw ? null : surfaceRoleForTextToken(parsed.token);
2684
+ if (surfaceRole) {
2685
+ return { color: parsed.opacityPercent === undefined ? surfaceForegroundValue(surfaceRole) : surfaceForegroundValueWithOpacity(surfaceRole, parsed.opacityPercent) };
2686
+ }
2687
+ return { color: rgbColorValue(token) };
2688
+ }
2689
+ /**
2690
+ * Creates a border color style object from a theme token.
2691
+ *
2692
+ * @param token - Theme color token
2693
+ * @returns CSSProperties with borderColor
2694
+ */
2695
+ function borderColorStyle(token) {
2696
+ return { borderColor: rgbColorValue(token) };
2697
+ }
2698
+ /**
2699
+ * Creates a linear gradient background from theme tokens.
2700
+ *
2701
+ * @param tokens - Array of theme color tokens for gradient stops
2702
+ * @param direction - CSS gradient direction (default: 'to bottom')
2703
+ * @returns CSSProperties with backgroundImage
2704
+ *
2705
+ * @example
2706
+ * gradientBackgroundStyle(['primary', 'secondary'])
2707
+ * // => { backgroundImage: 'linear-gradient(to bottom, rgb(var(--tb-primary)), rgb(var(--tb-secondary)))' }
2708
+ *
2709
+ * @example
2710
+ * gradientBackgroundStyle(['primary/80', 'secondary/60'], '45deg')
2711
+ * // => { backgroundImage: 'linear-gradient(45deg, rgb(var(--tb-primary) / 0.8), rgb(var(--tb-secondary) / 0.6))' }
2712
+ */
2713
+ function gradientBackgroundStyle(tokens, direction = "to bottom") {
2714
+ const stops = tokens.map((stop) => rgbColorValue(stop)).join(", ");
2715
+ return { backgroundImage: `linear-gradient(${direction}, ${stops})` };
2716
+ }
2717
+ /**
2718
+ * Merges multiple CSSProperties objects into a single object.
2719
+ * Later styles override earlier ones. Undefined values are filtered out.
2720
+ * Returns undefined if the merged result is empty.
2721
+ *
2722
+ * @param styles - Variable number of CSSProperties objects (can be undefined)
2723
+ * @returns Merged CSSProperties object, or undefined if empty
2724
+ *
2725
+ * @example
2726
+ * mergeStyles(
2727
+ * backgroundColorStyle('surface'),
2728
+ * textColorStyle('text'),
2729
+ * borderColorStyle('border')
2730
+ * )
2731
+ * // => { backgroundColor: '...', color: '...', borderColor: '...' }
2732
+ */
2733
+ function mergeStyles(...styles) {
2734
+ const merged = {};
2735
+ for (const style of styles) {
2736
+ if (!style) continue;
2737
+ Object.assign(merged, style);
2738
+ }
2739
+ return Object.keys(merged).length ? merged : undefined;
2740
+ }
2741
+
2742
+ //#endregion
2743
+ //#region ../theme-core/src/tokens/resolver.ts
2744
+ /**
2745
+ * Resolves theme tokens to CSS variables
2746
+ *
2747
+ * This resolver ensures all button styles use theme tokens (not hardcoded colors)
2748
+ * so that changing the palette automatically updates all buttons.
2749
+ */
2750
+ var TokenResolver = class {
2751
+ constructor(theme) {
2752
+ this.theme = theme;
2753
+ }
2754
+ /**
2755
+ * Resolve a color token to a CSS variable reference wrapped in rgb()
2756
+ *
2757
+ * @param token - Token name (e.g., 'primary-500', 'white', 'text-900')
2758
+ * @returns CSS rgb() function with var reference (e.g., 'rgb(var(--tb-primary-500))')
2759
+ *
2760
+ * Note: CSS variables are stored as RGB channels (e.g., "37 99 235") following Tailwind convention,
2761
+ * so we must wrap them with rgb() to create a valid color value.
2762
+ *
2763
+ * @example
2764
+ * resolver.getColor('primary-500') // => 'rgb(var(--tb-primary-500))'
2765
+ * resolver.getColor('white') // => 'rgb(var(--tb-white))'
2766
+ */
2767
+ getColor(token) {
2768
+ if (!this.tokenExists(token)) {
2769
+ console.warn(`[TokenResolver] Color token "${token}" not found in theme palette. Button may render incorrectly.`);
2770
+ }
2771
+ return rgbColorValue(token);
2772
+ }
2773
+ /**
2774
+ * Adjust a color token's shade by a given amount
2775
+ *
2776
+ * @param token - Base token (e.g., 'primary-500')
2777
+ * @param amount - Shade adjustment (+100 = darker, -100 = lighter)
2778
+ * @returns Adjusted token name (e.g., 'primary-600')
2779
+ *
2780
+ * @example
2781
+ * resolver.adjustShade('primary-500', 100) // => 'primary-600' (darker)
2782
+ * resolver.adjustShade('primary-500', -100) // => 'primary-400' (lighter)
2783
+ */
2784
+ adjustShade(token, amount) {
2785
+ const parts = token.split("-");
2786
+ if (parts.length < 2) {
2787
+ const newShade$1 = Math.max(100, Math.min(900, 500 + amount));
2788
+ return `${token}-${newShade$1}`;
2353
2789
  }
2354
- };
2355
- }
2356
- function safeTokenOr(candidate$1, fallback, backgroundHex, palette) {
2357
- return firstSafeToken([candidate$1], backgroundHex, palette) ?? fallback;
2358
- }
2359
- function firstSafeToken(candidates, backgroundHex, palette, preferredEquivalentTokens = []) {
2360
- const seen = new Set();
2361
- for (const candidate$1 of candidates) {
2362
- const token = canonicalToken(candidate$1, palette, preferredEquivalentTokens);
2363
- if (!token || seen.has(token)) continue;
2364
- seen.add(token);
2365
- const foregroundHex = resolveConcreteColorHex(token, palette);
2366
- if (foregroundHex && contrastRatio(backgroundHex, foregroundHex) >= ORDINARY_TEXT_MIN_CONTRAST_RATIO) {
2790
+ const base = parts.slice(0, -1).join("-");
2791
+ const shade = parseInt(parts[parts.length - 1] ?? "", 10);
2792
+ if (isNaN(shade)) {
2793
+ console.warn(`[TokenResolver] Cannot adjust shade for non-shade token "${token}". Returning original token.`);
2367
2794
  return token;
2368
2795
  }
2796
+ const newShade = Math.max(100, Math.min(900, shade + amount));
2797
+ return `${base}-${newShade}`;
2369
2798
  }
2370
- return null;
2371
- }
2372
- function canonicalToken(reference, palette, preferredEquivalentTokens = []) {
2373
- const normalized = normalizedReference(reference);
2374
- if (!normalized || normalized === "transparent") return null;
2375
- const direct = parseThemeColorToken(normalized);
2376
- if (direct && resolveConcreteColorHex(direct, palette)) return direct;
2377
- const referenceHex = resolveConcreteColorHex(normalized, palette);
2378
- if (!referenceHex) return null;
2379
- const equivalent = [
2380
- ...preferredEquivalentTokens,
2381
- ...CANONICAL_EQUIVALENT_TOKEN_ORDER,
2382
- ...Object.keys(palette).sort()
2383
- ].find((token) => {
2384
- const parsed = parseThemeColorToken(token);
2385
- return parsed !== null && resolveConcreteColorHex(parsed, palette)?.toLowerCase() === referenceHex.toLowerCase();
2386
- });
2387
- return equivalent ? parseThemeColorToken(equivalent) : null;
2388
- }
2389
- function paletteToken(reference) {
2390
- const parts = parseColorTokenParts(reference);
2391
- return parts.kind === "token" && parts.opacityPercent === null ? parts.token : null;
2392
- }
2393
- function normalizedReference(value) {
2394
- if (typeof value !== "string") return null;
2395
- const normalized = value.trim();
2396
- return normalized.length > 0 ? normalized : null;
2397
- }
2799
+ /**
2800
+ * Check if a token exists in the theme palette
2801
+ *
2802
+ * @param token - Token name to check
2803
+ * @returns True if token exists in theme
2804
+ */
2805
+ tokenExists(token) {
2806
+ const commonTokens = [
2807
+ "white",
2808
+ "black",
2809
+ "transparent"
2810
+ ];
2811
+ if (commonTokens.includes(token)) {
2812
+ return true;
2813
+ }
2814
+ const parts = token.split("-");
2815
+ if (parts.length >= 2) {
2816
+ const lastPart = parts[parts.length - 1] ?? "";
2817
+ const shade = parseInt(lastPart, 10);
2818
+ if (!isNaN(shade) && shade >= 100 && shade <= 900 && shade % 100 === 0) {
2819
+ return true;
2820
+ }
2821
+ }
2822
+ return true;
2823
+ }
2824
+ };
2398
2825
 
2399
2826
  //#endregion
2400
2827
  //#region ../theme-core/src/cards/generateCardCss.ts
@@ -4076,179 +4503,38 @@ const sizeOrder = {
4076
4503
  standard: 1,
4077
4504
  generous: 2,
4078
4505
  display: 3
4079
- };
4080
- function resolveAccommodationSize(minimumSize, requestedSize) {
4081
- if (!requestedSize || requestedSize === "auto") return minimumSize;
4082
- return sizeOrder[requestedSize] > sizeOrder[minimumSize] ? requestedSize : minimumSize;
4083
- }
4084
-
4085
- //#endregion
4086
- //#region ../theme-core/src/site-styles/rawStyleFields.ts
4087
- const themeV2RuntimeStyleFieldNames = [
4088
- "_frameStyles",
4089
- "_sectionStyles",
4090
- "_containerStyles",
4091
- "_cardStyles",
4092
- "_transitionStyles",
4093
- "styleGroup"
4094
- ];
4095
- const themeV2BlockSpecificRawStyleFieldNames = [
4096
- "_contentCardStyles",
4097
- "_heroLayoutStyles",
4098
- "_textCardStyles"
4099
- ];
4100
- const themeV2NormalEditorRawStyleFieldNames = [...themeV2RuntimeStyleFieldNames, ...themeV2BlockSpecificRawStyleFieldNames];
4101
- const themeV2NormalEditorRawStyleFieldNameSet = new Set(themeV2NormalEditorRawStyleFieldNames);
4102
- const themeV2CompilerOwnedFieldNames = [...themeV2RuntimeStyleFieldNames, ...themeV2BlockSpecificRawStyleFieldNames];
4103
- const pageDesignEditorBackgroundOverrideOwner = "page-design-editor";
4104
- const siteChromeBackgroundOverrideOwner = "site-chrome-editor";
4105
- function isThemeV2NormalEditorRawStyleFieldName(fieldName) {
4106
- return themeV2NormalEditorRawStyleFieldNameSet.has(fieldName);
4107
- }
4108
- function isThemeV2NormalEditorRawStylePath(fieldPath) {
4109
- const rootField = fieldPath.split(".")[0] ?? "";
4110
- return isThemeV2NormalEditorRawStyleFieldName(rootField);
4111
- }
4112
-
4113
- //#endregion
4114
- //#region ../theme-core/src/utils/colorStyles.ts
4115
- const COLOR_VAR_PREFIX = "--tb-";
4116
- function parseToken(source) {
4117
- const parts = parseColorTokenParts(source);
4118
- if (parts.kind === "raw") {
4119
- return {
4120
- token: source,
4121
- raw: parts.value
4122
- };
4123
- }
4124
- if (parts.kind === "invalid") {
4125
- return { token: source };
4126
- }
4127
- return {
4128
- token: parts.token,
4129
- opacityPercent: parts.opacityPercent === null ? undefined : parts.opacityPercent
4130
- };
4131
- }
4132
- const SURFACE_TEXT_ROLE_BY_TOKEN = {
4133
- text: "text",
4134
- heading: "heading",
4135
- mutedText: "supporting"
4136
- };
4137
- function surfaceRoleForTextToken(token) {
4138
- return Object.prototype.hasOwnProperty.call(SURFACE_TEXT_ROLE_BY_TOKEN, token) ? SURFACE_TEXT_ROLE_BY_TOKEN[token] : null;
4139
- }
4140
- /**
4141
- * Converts a theme color token to a CSS rgb value.
4142
- * This is the primary function for applying theme colors to CSS properties.
4143
- *
4144
- * @param token - Theme color token (semantic, with opacity, or raw)
4145
- * @returns CSS color value (rgb with optional alpha, or raw CSS value)
4146
- *
4147
- * @example
4148
- * rgbColorValue('primary') // => 'rgb(var(--tb-primary))'
4149
- * rgbColorValue('surface/95') // => 'rgb(var(--tb-surface) / 0.95)'
4150
- * rgbColorValue('raw:transparent') // => 'transparent'
4151
- */
4152
- function rgbColorValue(token) {
4153
- const { token: baseToken, opacityPercent, raw } = parseToken(token);
4154
- if (raw) {
4155
- return raw;
4156
- }
4157
- const cssVar = `${COLOR_VAR_PREFIX}${baseToken}`;
4158
- if (opacityPercent === undefined) {
4159
- return `rgb(var(${cssVar}))`;
4160
- }
4161
- return `rgb(var(${cssVar}) / ${opacityPercent / 100})`;
4162
- }
4163
- /**
4164
- * Converts a theme color token to a CSS variable reference.
4165
- * Note: This returns the base variable without rgb() wrapper, ignoring opacity.
4166
- *
4167
- * @param token - Theme color token
4168
- * @returns CSS variable reference
4169
- *
4170
- * @example
4171
- * cssVarValue('primary') // => 'var(--tb-primary)'
4172
- * cssVarValue('surface/95') // => 'var(--tb-surface)' (opacity ignored)
4173
- */
4174
- function cssVarValue(token) {
4175
- const { token: baseToken } = parseToken(token);
4176
- return `var(${COLOR_VAR_PREFIX}${baseToken})`;
4177
- }
4178
- /**
4179
- * Creates a backgroundColor style object from a theme token.
4180
- *
4181
- * @param token - Theme color token
4182
- * @returns CSSProperties with backgroundColor
4183
- */
4184
- function backgroundColorStyle(token) {
4185
- return { backgroundColor: rgbColorValue(token) };
4186
- }
4187
- /**
4188
- * Creates a text color style object from a theme token.
4189
- *
4190
- * @param token - Theme color token
4191
- * @returns CSSProperties with color
4192
- */
4193
- function textColorStyle(token) {
4194
- const parsed = parseToken(token);
4195
- const surfaceRole = parsed.raw ? null : surfaceRoleForTextToken(parsed.token);
4196
- if (surfaceRole) {
4197
- return { color: parsed.opacityPercent === undefined ? surfaceForegroundValue(surfaceRole) : surfaceForegroundValueWithOpacity(surfaceRole, parsed.opacityPercent) };
4198
- }
4199
- return { color: rgbColorValue(token) };
4200
- }
4201
- /**
4202
- * Creates a border color style object from a theme token.
4203
- *
4204
- * @param token - Theme color token
4205
- * @returns CSSProperties with borderColor
4206
- */
4207
- function borderColorStyle(token) {
4208
- return { borderColor: rgbColorValue(token) };
4506
+ };
4507
+ function resolveAccommodationSize(minimumSize, requestedSize) {
4508
+ if (!requestedSize || requestedSize === "auto") return minimumSize;
4509
+ return sizeOrder[requestedSize] > sizeOrder[minimumSize] ? requestedSize : minimumSize;
4209
4510
  }
4210
- /**
4211
- * Creates a linear gradient background from theme tokens.
4212
- *
4213
- * @param tokens - Array of theme color tokens for gradient stops
4214
- * @param direction - CSS gradient direction (default: 'to bottom')
4215
- * @returns CSSProperties with backgroundImage
4216
- *
4217
- * @example
4218
- * gradientBackgroundStyle(['primary', 'secondary'])
4219
- * // => { backgroundImage: 'linear-gradient(to bottom, rgb(var(--tb-primary)), rgb(var(--tb-secondary)))' }
4220
- *
4221
- * @example
4222
- * gradientBackgroundStyle(['primary/80', 'secondary/60'], '45deg')
4223
- * // => { backgroundImage: 'linear-gradient(45deg, rgb(var(--tb-primary) / 0.8), rgb(var(--tb-secondary) / 0.6))' }
4224
- */
4225
- function gradientBackgroundStyle(tokens, direction = "to bottom") {
4226
- const stops = tokens.map((stop) => rgbColorValue(stop)).join(", ");
4227
- return { backgroundImage: `linear-gradient(${direction}, ${stops})` };
4511
+
4512
+ //#endregion
4513
+ //#region ../theme-core/src/site-styles/rawStyleFields.ts
4514
+ const themeV2RuntimeStyleFieldNames = [
4515
+ "_frameStyles",
4516
+ "_sectionStyles",
4517
+ "_containerStyles",
4518
+ "_cardStyles",
4519
+ "_transitionStyles",
4520
+ "styleGroup"
4521
+ ];
4522
+ const themeV2BlockSpecificRawStyleFieldNames = [
4523
+ "_contentCardStyles",
4524
+ "_heroLayoutStyles",
4525
+ "_textCardStyles"
4526
+ ];
4527
+ const themeV2NormalEditorRawStyleFieldNames = [...themeV2RuntimeStyleFieldNames, ...themeV2BlockSpecificRawStyleFieldNames];
4528
+ const themeV2NormalEditorRawStyleFieldNameSet = new Set(themeV2NormalEditorRawStyleFieldNames);
4529
+ const themeV2CompilerOwnedFieldNames = [...themeV2RuntimeStyleFieldNames, ...themeV2BlockSpecificRawStyleFieldNames];
4530
+ const pageDesignEditorBackgroundOverrideOwner = "page-design-editor";
4531
+ const siteChromeBackgroundOverrideOwner = "site-chrome-editor";
4532
+ function isThemeV2NormalEditorRawStyleFieldName(fieldName) {
4533
+ return themeV2NormalEditorRawStyleFieldNameSet.has(fieldName);
4228
4534
  }
4229
- /**
4230
- * Merges multiple CSSProperties objects into a single object.
4231
- * Later styles override earlier ones. Undefined values are filtered out.
4232
- * Returns undefined if the merged result is empty.
4233
- *
4234
- * @param styles - Variable number of CSSProperties objects (can be undefined)
4235
- * @returns Merged CSSProperties object, or undefined if empty
4236
- *
4237
- * @example
4238
- * mergeStyles(
4239
- * backgroundColorStyle('surface'),
4240
- * textColorStyle('text'),
4241
- * borderColorStyle('border')
4242
- * )
4243
- * // => { backgroundColor: '...', color: '...', borderColor: '...' }
4244
- */
4245
- function mergeStyles(...styles) {
4246
- const merged = {};
4247
- for (const style of styles) {
4248
- if (!style) continue;
4249
- Object.assign(merged, style);
4250
- }
4251
- return Object.keys(merged).length ? merged : undefined;
4535
+ function isThemeV2NormalEditorRawStylePath(fieldPath) {
4536
+ const rootField = fieldPath.split(".")[0] ?? "";
4537
+ return isThemeV2NormalEditorRawStyleFieldName(rootField);
4252
4538
  }
4253
4539
 
4254
4540
  //#endregion
@@ -4644,8 +4930,14 @@ const headerInteractionPillPaletteValues = [
4644
4930
  "accent"
4645
4931
  ];
4646
4932
  /**
4647
- * "No pill": the nav link keeps whatever hover treatment its recipe compiled,
4648
- * and the palette step writes nothing at all (#1318 Phase 4c decision 2).
4933
+ * "No pill": a colour change on hover rather than a filled background.
4934
+ *
4935
+ * The palette step writes nothing (#1318 Phase 4c decision 2), but on a
4936
+ * foreground-adaptive style that is not the end of the story: the hover colour
4937
+ * is derived from the resolved opening foreground at render time, paired with
4938
+ * the resting colour, so `quiet` resolves to a definite colour rather than to
4939
+ * whatever brand token the recipe happened to name. See
4940
+ * `applyOpeningForeground`.
4649
4941
  *
4650
4942
  * It exists because "a colour change on hover, no filled background" was not
4651
4943
  * expressible in the vocabulary, and it is what
@@ -16009,158 +16301,6 @@ function assertUniqueLayoutProfileKeys(profiles) {
16009
16301
  }
16010
16302
  }
16011
16303
 
16012
- //#endregion
16013
- //#region ../theme-core/src/tokens/tokens.ts
16014
- const colorTokens = [
16015
- "background/base",
16016
- "background/elevated",
16017
- "surface/base",
16018
- "surface/subtle",
16019
- "surface/inverted",
16020
- "content/primary",
16021
- "content/secondary",
16022
- "accent/primary",
16023
- "accent/secondary",
16024
- "border/base"
16025
- ];
16026
- const typographyTokens = [
16027
- "display/hero",
16028
- "display/section",
16029
- "heading/large",
16030
- "heading/medium",
16031
- "heading/small",
16032
- "body/normal",
16033
- "body/small",
16034
- "caption"
16035
- ];
16036
- const spacingTokens = [
16037
- "none",
16038
- "3xs",
16039
- "2xs",
16040
- "xs",
16041
- "sm",
16042
- "md",
16043
- "lg",
16044
- "xl",
16045
- "2xl",
16046
- "3xl"
16047
- ];
16048
- const radiusTokens = [
16049
- "none",
16050
- "xs",
16051
- "sm",
16052
- "md",
16053
- "lg",
16054
- "pill",
16055
- "full"
16056
- ];
16057
- const shadowTokens = [
16058
- "none",
16059
- "soft",
16060
- "medium",
16061
- "strong"
16062
- ];
16063
- const defaultThemeTokens = {
16064
- color: {
16065
- "background/base": "#ffffff",
16066
- "background/elevated": "#f5f5f5",
16067
- "surface/base": "#ffffff",
16068
- "surface/subtle": "#f9f9fb",
16069
- "surface/inverted": "#111111",
16070
- "content/primary": "#111111",
16071
- "content/secondary": "#3f3f46",
16072
- "accent/primary": "#2563eb",
16073
- "accent/secondary": "#1d4ed8",
16074
- "border/base": "#e5e7eb"
16075
- },
16076
- typography: {
16077
- "display/hero": {
16078
- fontSize: "clamp(48px, 8vw, 96px)",
16079
- lineHeight: "1.05",
16080
- fontWeight: "700"
16081
- },
16082
- "display/section": {
16083
- fontSize: "clamp(40px, 6vw, 72px)",
16084
- lineHeight: "1.1",
16085
- fontWeight: "700"
16086
- },
16087
- "heading/large": {
16088
- fontSize: "clamp(32px, 4vw, 48px)",
16089
- lineHeight: "1.2",
16090
- fontWeight: "600"
16091
- },
16092
- "heading/medium": {
16093
- fontSize: "clamp(24px, 3vw, 32px)",
16094
- lineHeight: "1.25",
16095
- fontWeight: "600"
16096
- },
16097
- "heading/small": {
16098
- fontSize: "20px",
16099
- lineHeight: "1.3",
16100
- fontWeight: "600"
16101
- },
16102
- "body/normal": {
16103
- fontSize: "16px",
16104
- lineHeight: "1.6",
16105
- fontWeight: "400"
16106
- },
16107
- "body/small": {
16108
- fontSize: "14px",
16109
- lineHeight: "1.5",
16110
- fontWeight: "400"
16111
- },
16112
- caption: {
16113
- fontSize: "12px",
16114
- lineHeight: "1.4",
16115
- fontWeight: "500"
16116
- }
16117
- },
16118
- spacing: {
16119
- none: "0px",
16120
- "3xs": "4px",
16121
- "2xs": "8px",
16122
- xs: "12px",
16123
- sm: "16px",
16124
- md: "24px",
16125
- lg: "32px",
16126
- xl: "40px",
16127
- "2xl": "56px",
16128
- "3xl": "72px"
16129
- },
16130
- radius: {
16131
- none: "0px",
16132
- xs: "2px",
16133
- sm: "4px",
16134
- md: "8px",
16135
- lg: "12px",
16136
- pill: "999px",
16137
- full: "9999px"
16138
- },
16139
- shadow: {
16140
- none: "none",
16141
- soft: "0px 2px 8px rgba(15, 23, 42, 0.08)",
16142
- medium: "0px 6px 18px rgba(15, 23, 42, 0.12)",
16143
- strong: "0px 12px 36px rgba(15, 23, 42, 0.16)"
16144
- },
16145
- palette: {
16146
- surface: "#ffffff",
16147
- "neutral-50": "#f9fafb",
16148
- "neutral-900": "#111827",
16149
- primary: "#2563eb",
16150
- "primary-50": "#eff6ff",
16151
- "primary-500": "#2563eb",
16152
- "primary-900": "#1d4ed8",
16153
- secondary: "#9333ea",
16154
- "secondary-50": "#f3e8ff",
16155
- "secondary-500": "#9333ea",
16156
- "secondary-900": "#4c1d95",
16157
- accent: "#f97316",
16158
- "accent-50": "#fff7ed",
16159
- "accent-500": "#f97316",
16160
- "accent-900": "#7c2d12"
16161
- }
16162
- };
16163
-
16164
16304
  //#endregion
16165
16305
  //#region ../theme-core/src/site-styles/backgroundAppearance.ts
16166
16306
  const backgroundAppearanceQuickColorTokenNames = [
@@ -28343,6 +28483,10 @@ function compareCompiledHeaders(left, right) {
28343
28483
 
28344
28484
  //#endregion
28345
28485
  //#region ../theme-core/src/site-styles/headerOpeningForeground.ts
28486
+ /** The nav-link hover effect that is a plain colour change. */
28487
+ const TEXT_COLOR_CHANGE_EFFECT_ID = "text-color-change";
28488
+ /** The nav-link hover affordance that does not depend on a colour delta. */
28489
+ const NAV_UNDERLINE_EFFECT_ID = "nav-underline";
28346
28490
  function headerStyleAvailability(recipe, context) {
28347
28491
  if (!recipe.openingForeground) return { kind: "available" };
28348
28492
  return context?.openingForeground?.kind === "known" ? { kind: "available" } : {
@@ -28369,10 +28513,7 @@ function applyOpeningForeground(theme, header, recipe, context) {
28369
28513
  return {
28370
28514
  ...withBrandForeground,
28371
28515
  navColor: foreground.roles.text,
28372
- navLinkStyle: header.navLinkStyle ? {
28373
- ...header.navLinkStyle,
28374
- colorToken: foreground.roles.link
28375
- } : header.navLinkStyle,
28516
+ navLinkStyle: header.navLinkStyle ? adaptNavLinkStyleToForeground(header.navLinkStyle, foreground.roles.link, planForegroundHover(foreground.roles.link, paletteHexForToken(theme, foreground.roles.link), scrollTreatment?.kind === "contrast-glass" ? scrollTreatment.backgroundTone : null)) : header.navLinkStyle,
28376
28517
  border: {
28377
28518
  style: "solid",
28378
28519
  width: "thin",
@@ -28382,6 +28523,79 @@ function applyOpeningForeground(theme, header, recipe, context) {
28382
28523
  ...scrollTreatment ? { scrollTreatment } : {}
28383
28524
  };
28384
28525
  }
28526
+ /**
28527
+ * Give the resolved foreground both the resting and the hover colour.
28528
+ *
28529
+ * Adapting the resting colour alone left hover as whatever the recipe wrote —
28530
+ * for `minimal-surface` a bare `primary`, which is a brand colour no one had
28531
+ * checked against the section the header floats over. On a primary-painted
28532
+ * opening section that resolves to the section's own colour, and the link
28533
+ * disappears on hover.
28534
+ *
28535
+ * The two colours are a pair: the scroll treatment picks its glass tone from
28536
+ * the resting foreground precisely so one colour reads both against the opening
28537
+ * section and against the glass. A hover colour outside that pairing is not
28538
+ * covered by either half of it.
28539
+ *
28540
+ * A pill palette is left alone. It owns hover through `background-on-hover`,
28541
+ * which carries its own paired background and foreground tokens, so hover
28542
+ * legibility there does not depend on the surface underneath at all.
28543
+ */
28544
+ function adaptNavLinkStyleToForeground(navLinkStyle, linkToken, hoverPlan) {
28545
+ const adapted = {
28546
+ ...navLinkStyle,
28547
+ colorToken: linkToken
28548
+ };
28549
+ const hoverEffects = navLinkStyle.effects?.hover ?? [];
28550
+ const hasColorChange = hoverEffects.some(isTextColorChangeEffect);
28551
+ if (!hasColorChange && hoverEffects.length > 0) return adapted;
28552
+ if (!hasColorChange && !navLinkStyle.hoverColorToken) return adapted;
28553
+ const underline = {
28554
+ effectId: NAV_UNDERLINE_EFFECT_ID,
28555
+ options: {
28556
+ style: "grow",
28557
+ colorToken: linkToken
28558
+ }
28559
+ };
28560
+ const withoutColorChange = hoverEffects.filter((effect) => !isTextColorChangeEffect(effect) && !isNavUnderlineEffect(effect));
28561
+ if (hoverPlan.kind === "resting") {
28562
+ return {
28563
+ ...adapted,
28564
+ hoverColorToken: null,
28565
+ effects: {
28566
+ ...adapted.effects,
28567
+ hover: [...withoutColorChange, underline]
28568
+ }
28569
+ };
28570
+ }
28571
+ const hoverColorToken = hoverPlan.token;
28572
+ return {
28573
+ ...adapted,
28574
+ hoverColorToken,
28575
+ effects: {
28576
+ ...adapted.effects,
28577
+ hover: [...hoverEffects.map((effect) => isTextColorChangeEffect(effect) ? {
28578
+ ...effect,
28579
+ options: {
28580
+ ...effect.options,
28581
+ hoverColorToken
28582
+ }
28583
+ } : effect).filter((effect) => !isNavUnderlineEffect(effect)), underline]
28584
+ }
28585
+ };
28586
+ }
28587
+ function isTextColorChangeEffect(effect) {
28588
+ return effect.effectId === TEXT_COLOR_CHANGE_EFFECT_ID;
28589
+ }
28590
+ function isNavUnderlineEffect(effect) {
28591
+ return effect.effectId === NAV_UNDERLINE_EFFECT_ID;
28592
+ }
28593
+ /** Concrete hex behind a plain palette token, or null when it is not one. */
28594
+ function paletteHexForToken(theme, token) {
28595
+ const parts = parseColorTokenParts(token);
28596
+ if (parts.kind !== "token" || parts.opacityPercent !== null) return null;
28597
+ return expandPalette(theme.palette)[parts.token] ?? null;
28598
+ }
28385
28599
  function compileHeaderScrollTreatment(theme, recipe, foregroundToken) {
28386
28600
  if (recipe.scrollTreatment !== "contrast-glass") return undefined;
28387
28601
  const tokenParts = parseColorTokenParts(foregroundToken);
@@ -29768,12 +29982,9 @@ const upsertNavigationMenuCommandSchema = z.object({
29768
29982
  type: z.literal("upsertNavigationMenu"),
29769
29983
  ref: navigationRefSchema,
29770
29984
  input: z.object({
29771
- identifier: z.string().min(1).optional(),
29772
- name: z.string().min(1).optional(),
29773
- location: z.enum(navigationLocations).optional(),
29774
- role: z.enum(navigationMenuRoles).optional(),
29985
+ location: z.enum(NAVIGATION_LOCATIONS),
29775
29986
  items: z.array(navigationItemSchema).readonly()
29776
- }).strict().refine((input) => input.name !== undefined || input.location !== undefined, { message: "Navigation commands require either input.name or input.location." })
29987
+ }).strict()
29777
29988
  }).strict();
29778
29989
  const formFieldSchema = z.object({
29779
29990
  id: z.string().min(1),
@@ -32526,4 +32737,4 @@ function parseSdkEventRunUpsertInput(input, runIndex, options) {
32526
32737
  }
32527
32738
 
32528
32739
  //#endregion
32529
- export { require_jsx_runtime as $, surfaceForegroundStyle as $n, cssVarValue as $t, defaultPaletteForSiteStyle as A, FONT_WEIGHT_MAP$1 as An, typographySchema as At, parsePersistedHeaderLayoutId as B, generateCardCoreCss as Bn, BREAKPOINT_XL as Bt, retargetCompiledBoundaryRuntimeForContentAdjacency as C, parseBlockCustomCssRules as Cn, createNavigationRef as Cr, parseThemeForPersistence as Ct, curatedSiteStyles as D, NAV_LINK_PADDING_MAP as Dn, refSlug as Dr, expandPalette as Dt, concretePaletteToTheme as E, NAV_LINK_LETTER_SPACING_MAP as En, createVenueRef as Er, generateShadowValue as Et, findFooterLook as F, ACCORDION_SPACING_MAP as Fn, getHeaderPaintTargets as Ft, parseGradientPresetId as G, onColorTokenName as Gn, MQ_TABLET_ONLY as Gt, gradientToCss as H, generateCardCss as Hn, MQ_MD_DOWN as Ht, guaranteedFallbackFooterLookId as I, ACCORDION_TRIGGER_FONT_SCALE as In, renderHeaderPaintTargetRules as It, backgroundAppearanceColorTokenNames as J, featuresFromHex as Jn, resolveOnColorForThemeToken as Jt, findCuratedPalette as K, ORDINARY_TEXT_MIN_CONTRAST_RATIO as Kn, headerVariantValues as Kt, parsePersistedFooterLookId as L, ACCORDION_TRIGGER_LETTER_SPACING as Ln, BREAKPOINT_LG as Lt, headerLayoutChoicesForSiteStyle as M, INPUT_SPACING_MAP as Mn, boxBackgroundSchema as Mt, headerStyleChoicesForLayout as N, LABEL_FONT_SIZE_MAP as Nn, generateHeaderScrollTreatmentStyles as Nt, defaultButtonStyleSelectionForSiteStyle as O, NAV_LINK_PADDING_X_MAP as On, slugPart as Or, getTextColorForBackground as Ot, compileTransitionRuntime as P, ACCORDION_OPEN_ACCENT_THICKNESS as Pn, generateMobileOverlayBackdropFilterFix as Pt, defineBlockDesignMetadata as Q, surfaceForegroundDeclarations as Qn, borderColorStyle as Qt, getHeaderLayout as R, ICON_CONFIG as Rn, BREAKPOINT_MD as Rt, eventBookingOfferIntentSchema as S, getComponentShadowVar as Sn, createFormRef as Sr, themeButtonClassName as St, readHeaderNavFontSizePreference as T, NAV_LINK_BORDER_RADIUS_MAP as Tn, createSiteCommandSiteRef as Tr, formatButtonColourContractError as Tt, GRADIENT_PRESET_IDS as U, resolveSurfaceForeground as Un, MQ_SM_DOWN as Ut, parsePersistedHeaderStyleId as V, getDefaultCardVariants as Vn, MQ_LG_UP as Vt, getGradientPreset as W, isOnColorBackgroundCandidateToken as Wn, MQ_SM_UP as Wt, parseBackgroundAppearanceColorToken as X, oklchToHexGamut as Xn, resolveTokenOrCssColorValue as Xt, backgroundAppearanceQuickColorTokenNames as Y, hexToRgb as Yn, resolveThemeColorReferenceValue as Yt, defaultThemeTokens as Z, DEFAULT_SURFACE_TEXT_COLOR as Zn, backgroundColorStyle as Zt, entryIdentifierForCommand as _, offeringsPreviewCompositionTreatmentValues as _n, createCommandRef as _r, generateDefaultButtonSystem as _t, classifySdkEventBookingOffer as a, asDesignBlockId as an, normalizeCardRole as ar, createDefaultButtonStyleSelection as at, pagePathForCommand as b, visibleHeadingDecorationFamilyValues as bn, createEventSeriesRef as br, generateInteractiveChildInheritanceCSS as bt, stableStringify as c, defineBlockDesignCapability as cn, mediaSchema as cr, AFFORDANCE_SUPPRESS_CLASS as ct, mapEventCommandContent as d, eventListTreatmentValues as dn, VARIANT_ROLES as dr, resolvedButtonColourDeclarations as dt, mergeStyles as en, surfaceForegroundValue as er, require_react as et, evaluateSiteCommandBatchExposure as f, eyebrowTreatmentValues as fn, buttonVariantIdSchema as fr, resolvedButtonFocusDeclarations as ft, blockOrderIdentifiersForCommand as g, makeBoundaryId as gn, createBlocksRef as gr, resolveContextualButtonRole as gt, blockIdentifierForCommand as h, introCompositionTreatmentValues as hn, createBlockRef as hr, deriveButtonSurfaceContext as ht, classifySdkEventSchedule as i, asAppearancePresetId as in, cardVariantRoleValues as ir, buttonStyleSelectionSchema as it, getCuratedSiteStyle as j, INPUT_FONT_SIZE_MAP as jn, boxBackgroundOverlaySchema as jt, defaultHeaderSelectionForSiteStyle as k, NAV_LINK_TEXT_SIZE_MAP as kn, __toESM as kr, themeSchema as kt, createDryRunReport as l, defineFrameCapability as ln, mediaTypeDiscriminants as lr, generateButtonCss as lt, getSiteCommandMetadata as m, headingDecorationColorTokenValues as mn, parseBlockColorToken as mr, contextualButtonSurfaceStyles as mt, sdkEventOccurrenceInputSchema as n, textColorStyle as nn, generateShadowValue$1 as nr, generateCssVars as nt, venueManagementFields as o, asSiteStyleId as on, paletteSchema as or, isButtonStyleId as ot, evaluateSiteCommandExposure as p, featureCardCompositionTreatmentValues as pn, unsafeAsOpaqueButtonColourToken as pr, contextualButtonSurfaceResetStyles as pt, boundaryRuntimeMetricsForTransition as q, contrastRatio as qn, isCssColorLiteral as qt, sdkEventUpsertOptionalFieldSchemas as r, pageDesignEditorBackgroundOverrideOwner as rn, cardRoleSchema as rr, findButtonStyleRecipe as rt, sortRecord as s, assertNever$1 as sn, mediaIdentifierSchema as sr, PUBLIC_BUTTON_ROLES as st, classifySdkEventTiming as t, rgbColorValue as tn, TokenResolver as tr, pickShadeTowardBackground as tt, parseAndPlanCommandBatchForTypes as u, defineNoBlockDesignCapability as un, persistableMediaSchema as ur, RESOLVED_BUTTON_DISABLED_DECLARATIONS as ut, pageIdentifierForBlockCommand as v, testimonialsCompositionTreatmentValues as vn, createContentEntryRef as vr, generateEffectsCSS as vt, mergeHeaderNavTypographyPreference as w, parseCustomCssRules as wn, createPageRef as wr, compileButtonColourStates as wt, hasConfiguredBookingVertical as x, getComponentBorderWidthPx as xn, createFooterRef as xr, parseThemeButtonVariantId as xt, pageIdentifierForCommand as y, tileTreatmentValues as yn, createEventCategoryRef as yr, generateBaseInteractiveCSS as yt, getHeaderStyle as z, ICON_SIZE_PX as zn, BREAKPOINT_SM as zt };
32740
+ export { require_react as $, DEFAULT_SURFACE_TEXT_COLOR as $n, asSiteStyleId as $t, defaultPaletteForSiteStyle as A, ACCORDION_TRIGGER_LETTER_SPACING as An, __toESM as Ar, boxBackgroundOverlaySchema as At, parsePersistedHeaderLayoutId as B, mergeStyles as Bn, MQ_LG_UP as Bt, retargetCompiledBoundaryRuntimeForContentAdjacency as C, FONT_WEIGHT_MAP$1 as Cn, createFormRef as Cr, compileButtonColourStates as Ct, curatedSiteStyles as D, ACCORDION_OPEN_ACCENT_THICKNESS as Dn, createVenueRef as Dr, getTextColorForBackground as Dt, concretePaletteToTheme as E, LABEL_FONT_SIZE_MAP as En, createSiteCommandSiteRef as Er, expandPalette as Et, findFooterLook as F, generateCardCss as Fn, renderHeaderPaintTargetRules as Ft, parseGradientPresetId as G, onColorTokenName as Gn, headerVariantValues as Gt, gradientToCss as H, textColorStyle as Hn, MQ_SM_DOWN as Ht, guaranteedFallbackFooterLookId as I, TokenResolver as In, BREAKPOINT_LG as It, backgroundAppearanceColorTokenNames as J, ORDINARY_TEXT_MIN_CONTRAST_RATIO as Jn, resolveThemeColorReferenceValue as Jt, findCuratedPalette as K, buildThemeTokens as Kn, isCssColorLiteral as Kt, parsePersistedFooterLookId as L, backgroundColorStyle as Ln, BREAKPOINT_MD as Lt, headerLayoutChoicesForSiteStyle as M, ICON_SIZE_PX as Mn, generateHeaderScrollTreatmentStyles as Mt, headerStyleChoicesForLayout as N, generateCardCoreCss as Nn, generateMobileOverlayBackdropFilterFix as Nt, defaultButtonStyleSelectionForSiteStyle as O, ACCORDION_SPACING_MAP as On, refSlug as Or, themeSchema as Ot, compileTransitionRuntime as P, getDefaultCardVariants as Pn, getHeaderPaintTargets as Pt, require_jsx_runtime as Q, oklchToHexGamut as Qn, asDesignBlockId as Qt, getHeaderLayout as R, borderColorStyle as Rn, BREAKPOINT_SM as Rt, eventBookingOfferIntentSchema as S, NAV_LINK_TEXT_SIZE_MAP as Sn, createFooterRef as Sr, parseThemeForPersistence as St, readHeaderNavFontSizePreference as T, INPUT_SPACING_MAP as Tn, createPageRef as Tr, generateShadowValue as Tt, GRADIENT_PRESET_IDS as U, resolveSurfaceForeground as Un, MQ_SM_UP as Ut, parsePersistedHeaderStyleId as V, rgbColorValue as Vn, MQ_MD_DOWN as Vt, getGradientPreset as W, isOnColorBackgroundCandidateToken as Wn, MQ_TABLET_ONLY as Wt, parseBackgroundAppearanceColorToken as X, featuresFromHex as Xn, pageDesignEditorBackgroundOverrideOwner as Xt, backgroundAppearanceQuickColorTokenNames as Y, contrastRatio as Yn, resolveTokenOrCssColorValue as Yt, defineBlockDesignMetadata as Z, hexToRgb as Zn, asAppearancePresetId as Zt, entryIdentifierForCommand as _, parseCustomCssRules as _n, createBlocksRef as _r, generateEffectsCSS as _t, classifySdkEventBookingOffer as a, eyebrowTreatmentValues as an, cardVariantRoleValues as ar, isButtonStyleId as at, pagePathForCommand as b, NAV_LINK_PADDING_MAP as bn, createEventCategoryRef as br, parseThemeButtonVariantId as bt, stableStringify as c, introCompositionTreatmentValues as cn, mediaIdentifierSchema as cr, generateButtonCss as ct, mapEventCommandContent as d, testimonialsCompositionTreatmentValues as dn, persistableMediaSchema as dr, resolvedButtonFocusDeclarations as dt, assertNever$1 as en, surfaceForegroundDeclarations as er, pickShadeTowardBackground as et, evaluateSiteCommandBatchExposure as f, tileTreatmentValues as fn, VARIANT_ROLES as fr, contextualButtonSurfaceResetStyles as ft, blockOrderIdentifiersForCommand as g, parseBlockCustomCssRules as gn, createBlockRef as gr, generateDefaultButtonSystem as gt, blockIdentifierForCommand as h, getComponentShadowVar as hn, parseBlockColorToken as hr, resolveContextualButtonRole as ht, classifySdkEventSchedule as i, eventListTreatmentValues as in, cardRoleSchema as ir, createDefaultButtonStyleSelection as it, getCuratedSiteStyle as j, ICON_CONFIG as jn, boxBackgroundSchema as jt, defaultHeaderSelectionForSiteStyle as k, ACCORDION_TRIGGER_FONT_SCALE as kn, slugPart as kr, typographySchema as kt, createDryRunReport as l, makeBoundaryId as ln, mediaSchema as lr, RESOLVED_BUTTON_DISABLED_DECLARATIONS as lt, getSiteCommandMetadata as m, getComponentBorderWidthPx as mn, unsafeAsOpaqueButtonColourToken as mr, deriveButtonSurfaceContext as mt, sdkEventOccurrenceInputSchema as n, defineFrameCapability as nn, surfaceForegroundValue as nr, findButtonStyleRecipe as nt, venueManagementFields as o, featureCardCompositionTreatmentValues as on, normalizeCardRole as or, PUBLIC_BUTTON_ROLES as ot, evaluateSiteCommandExposure as p, visibleHeadingDecorationFamilyValues as pn, buttonVariantIdSchema as pr, contextualButtonSurfaceStyles as pt, boundaryRuntimeMetricsForTransition as q, defaultThemeTokens as qn, resolveOnColorForThemeToken as qt, sdkEventUpsertOptionalFieldSchemas as r, defineNoBlockDesignCapability as rn, generateShadowValue$1 as rr, buttonStyleSelectionSchema as rt, sortRecord as s, headingDecorationColorTokenValues as sn, paletteSchema as sr, AFFORDANCE_SUPPRESS_CLASS as st, classifySdkEventTiming as t, defineBlockDesignCapability as tn, surfaceForegroundStyle as tr, generateCssVars as tt, parseAndPlanCommandBatchForTypes as u, offeringsPreviewCompositionTreatmentValues as un, mediaTypeDiscriminants as ur, resolvedButtonColourDeclarations as ut, pageIdentifierForBlockCommand as v, NAV_LINK_BORDER_RADIUS_MAP as vn, createCommandRef as vr, generateBaseInteractiveCSS as vt, mergeHeaderNavTypographyPreference as w, INPUT_FONT_SIZE_MAP as wn, createNavigationRef as wr, formatButtonColourContractError as wt, hasConfiguredBookingVertical as x, NAV_LINK_PADDING_X_MAP as xn, createEventSeriesRef as xr, themeButtonClassName as xt, pageIdentifierForCommand as y, NAV_LINK_LETTER_SPACING_MAP as yn, createContentEntryRef as yr, generateInteractiveChildInheritanceCSS as yt, getHeaderStyle as z, cssVarValue as zn, BREAKPOINT_XL as zt };