@nswds/app 1.103.0 → 1.105.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -40,8 +40,8 @@ var LabelPrimitive = require('@radix-ui/react-label');
40
40
  var RadioGroupPrimitive = require('@radix-ui/react-radio-group');
41
41
  var TabsPrimitives = require('@radix-ui/react-tabs');
42
42
  var CollapsiblePrimitive = require('@radix-ui/react-collapsible');
43
+ var SheetPrimitive = require('@radix-ui/react-dialog');
43
44
  var cmdk = require('cmdk');
44
- var DialogPrimitive = require('@radix-ui/react-dialog');
45
45
  var ContextMenuPrimitive = require('@radix-ui/react-context-menu');
46
46
  var reactTable = require('@tanstack/react-table');
47
47
  var SeparatorPrimitive = require('@radix-ui/react-separator');
@@ -110,7 +110,7 @@ var LabelPrimitive__namespace = /*#__PURE__*/_interopNamespace(LabelPrimitive);
110
110
  var RadioGroupPrimitive__namespace = /*#__PURE__*/_interopNamespace(RadioGroupPrimitive);
111
111
  var TabsPrimitives__namespace = /*#__PURE__*/_interopNamespace(TabsPrimitives);
112
112
  var CollapsiblePrimitive__namespace = /*#__PURE__*/_interopNamespace(CollapsiblePrimitive);
113
- var DialogPrimitive__namespace = /*#__PURE__*/_interopNamespace(DialogPrimitive);
113
+ var SheetPrimitive__namespace = /*#__PURE__*/_interopNamespace(SheetPrimitive);
114
114
  var ContextMenuPrimitive__namespace = /*#__PURE__*/_interopNamespace(ContextMenuPrimitive);
115
115
  var SeparatorPrimitive__namespace = /*#__PURE__*/_interopNamespace(SeparatorPrimitive);
116
116
  var ToggleGroupPrimitive__namespace = /*#__PURE__*/_interopNamespace(ToggleGroupPrimitive);
@@ -16914,18 +16914,35 @@ function ColorPairingToolV2Content({ visibleFormats }) {
16914
16914
  initialState.selectedBackgroundToken
16915
16915
  );
16916
16916
  const [selectedPairId, setSelectedPairId] = React5.useState(initialState.selectedPairId);
16917
- const themeFamilies = getPairingFamilies(themeCategory);
16918
- const context = getPairingContext(themeCategory, primaryFamilyKey, accentFamilyKey);
16919
- const selectableFamilies = themeFamilies.filter((family) => family.key !== context.grey.key);
16920
- const selectableAccentFamilies = selectableFamilies.filter(
16921
- (family) => family.key !== context.primary.key
16922
- );
16923
- const selectedBackground = context.backgrounds.find((background) => background.token === selectedBackgroundToken) ?? context.backgrounds[0] ?? null;
16924
- const selectedBackgroundPairs = selectedBackground ? context.pairsByBackground[selectedBackground.token] ?? [] : [];
16925
- const selectedPair = getPreferredPairForBackground2(selectedBackgroundPairs, selectedPairId);
16917
+ const themeFamilies = React5.useMemo(() => getPairingFamilies(themeCategory), [themeCategory]);
16918
+ const context = React5.useMemo(
16919
+ () => getPairingContext(themeCategory, primaryFamilyKey, accentFamilyKey),
16920
+ [themeCategory, primaryFamilyKey, accentFamilyKey]
16921
+ );
16922
+ const selectableFamilies = React5.useMemo(
16923
+ () => themeFamilies.filter((family) => family.key !== context.grey.key),
16924
+ [themeFamilies, context.grey.key]
16925
+ );
16926
+ const selectableAccentFamilies = React5.useMemo(
16927
+ () => selectableFamilies.filter((family) => family.key !== context.primary.key),
16928
+ [selectableFamilies, context.primary.key]
16929
+ );
16930
+ const selectedBackground = React5.useMemo(
16931
+ () => context.backgrounds.find((background) => background.token === selectedBackgroundToken) ?? context.backgrounds[0] ?? null,
16932
+ [context.backgrounds, selectedBackgroundToken]
16933
+ );
16934
+ const selectedBackgroundPairs = React5.useMemo(
16935
+ () => selectedBackground ? context.pairsByBackground[selectedBackground.token] ?? [] : [],
16936
+ [context.pairsByBackground, selectedBackground]
16937
+ );
16938
+ const selectedPair = React5.useMemo(
16939
+ () => getPreferredPairForBackground2(selectedBackgroundPairs, selectedPairId),
16940
+ [selectedBackgroundPairs, selectedPairId]
16941
+ );
16926
16942
  const detailForeground = selectedPair?.foreground ?? null;
16927
- const familySummary = [context.primary.label, context.accent.label, context.grey.label].join(
16928
- " + "
16943
+ const familySummary = React5.useMemo(
16944
+ () => [context.primary.label, context.accent.label, context.grey.label].join(" + "),
16945
+ [context.primary.label, context.accent.label, context.grey.label]
16929
16946
  );
16930
16947
  const updateUrlParams = (nextThemeCategory, nextPrimaryKey, nextAccentKey, nextSelectedBackgroundToken, nextSelectedPairId) => {
16931
16948
  const params = new URLSearchParams(window.location.search);
@@ -16944,289 +16961,3626 @@ function ColorPairingToolV2Content({ visibleFormats }) {
16944
16961
  "",
16945
16962
  `${window.location.pathname}?${params.toString()}${window.location.hash}`
16946
16963
  );
16947
- };
16948
- const syncSelection = (nextThemeCategory, nextPrimaryKey, nextAccentKey, preferredBackgroundToken, preferredPairId) => {
16949
- const nextContext = getPairingContext(nextThemeCategory, nextPrimaryKey, nextAccentKey);
16950
- const nextSelectedBackgroundToken = resolveBackgroundToken2(
16951
- nextContext,
16952
- preferredBackgroundToken,
16953
- getToneFromToken2(preferredBackgroundToken)
16954
- );
16955
- const nextSelectedPairId = getPreferredPairForBackground2(
16956
- nextContext.pairsByBackground[nextSelectedBackgroundToken] ?? [],
16957
- preferredPairId
16958
- )?.id ?? "";
16959
- setThemeCategory(nextThemeCategory);
16960
- setPrimaryFamilyKey(nextContext.primary.key);
16961
- setAccentFamilyKey(nextContext.accent.key);
16962
- setSelectedBackgroundToken(nextSelectedBackgroundToken);
16963
- setSelectedPairId(nextSelectedPairId);
16964
- updateUrlParams(
16965
- nextThemeCategory,
16966
- nextContext.primary.key,
16967
- nextContext.accent.key,
16968
- nextSelectedBackgroundToken,
16969
- nextSelectedPairId
16970
- );
16971
- };
16964
+ };
16965
+ const syncSelection = (nextThemeCategory, nextPrimaryKey, nextAccentKey, preferredBackgroundToken, preferredPairId) => {
16966
+ const nextContext = getPairingContext(nextThemeCategory, nextPrimaryKey, nextAccentKey);
16967
+ const nextSelectedBackgroundToken = resolveBackgroundToken2(
16968
+ nextContext,
16969
+ preferredBackgroundToken,
16970
+ getToneFromToken2(preferredBackgroundToken)
16971
+ );
16972
+ const nextSelectedPairId = getPreferredPairForBackground2(
16973
+ nextContext.pairsByBackground[nextSelectedBackgroundToken] ?? [],
16974
+ preferredPairId
16975
+ )?.id ?? "";
16976
+ setThemeCategory(nextThemeCategory);
16977
+ setPrimaryFamilyKey(nextContext.primary.key);
16978
+ setAccentFamilyKey(nextContext.accent.key);
16979
+ setSelectedBackgroundToken(nextSelectedBackgroundToken);
16980
+ setSelectedPairId(nextSelectedPairId);
16981
+ updateUrlParams(
16982
+ nextThemeCategory,
16983
+ nextContext.primary.key,
16984
+ nextContext.accent.key,
16985
+ nextSelectedBackgroundToken,
16986
+ nextSelectedPairId
16987
+ );
16988
+ };
16989
+ const handleThemeCategoryChange = (nextThemeCategory) => {
16990
+ syncSelection(
16991
+ nextThemeCategory,
16992
+ primaryFamilyKey,
16993
+ accentFamilyKey,
16994
+ selectedBackgroundToken,
16995
+ selectedPairId
16996
+ );
16997
+ };
16998
+ const handlePrimaryColorChange = (nextPrimaryKey) => {
16999
+ const nextAccentKey = nextPrimaryKey === accentFamilyKey ? getDefaultAccentFamilyKey(themeCategory, nextPrimaryKey) : accentFamilyKey;
17000
+ syncSelection(
17001
+ themeCategory,
17002
+ nextPrimaryKey,
17003
+ nextAccentKey,
17004
+ selectedBackgroundToken,
17005
+ selectedPairId
17006
+ );
17007
+ };
17008
+ const handleAccentColorChange = (nextAccentKey) => {
17009
+ if (nextAccentKey === primaryFamilyKey) return;
17010
+ syncSelection(
17011
+ themeCategory,
17012
+ primaryFamilyKey,
17013
+ nextAccentKey,
17014
+ selectedBackgroundToken,
17015
+ selectedPairId
17016
+ );
17017
+ };
17018
+ const handleBackgroundChange = (nextSelectedBackgroundToken) => {
17019
+ const nextSelectedPairId = getPreferredPairForBackground2(
17020
+ context.pairsByBackground[nextSelectedBackgroundToken] ?? [],
17021
+ selectedPairId
17022
+ )?.id ?? "";
17023
+ setSelectedBackgroundToken(nextSelectedBackgroundToken);
17024
+ setSelectedPairId(nextSelectedPairId);
17025
+ updateUrlParams(
17026
+ themeCategory,
17027
+ context.primary.key,
17028
+ context.accent.key,
17029
+ nextSelectedBackgroundToken,
17030
+ nextSelectedPairId
17031
+ );
17032
+ };
17033
+ const handlePairChange = (nextSelectedPairId) => {
17034
+ if (!selectedBackground) return;
17035
+ setSelectedPairId(nextSelectedPairId);
17036
+ updateUrlParams(
17037
+ themeCategory,
17038
+ context.primary.key,
17039
+ context.accent.key,
17040
+ selectedBackground.token,
17041
+ nextSelectedPairId
17042
+ );
17043
+ };
17044
+ if (!selectedBackground) {
17045
+ return /* @__PURE__ */ jsxRuntime.jsx(Card, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-6", children: [
17046
+ /* @__PURE__ */ jsxRuntime.jsx(Heading, { level: 3, size: 5, className: "text-foreground", trim: "normal", children: "No approved background tones available" }),
17047
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-3 text-base text-muted-foreground", children: "No approved tones are available for the current palette." })
17048
+ ] }) });
17049
+ }
17050
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-8 lg:grid-cols-[18rem_minmax(0,1fr)]", children: [
17051
+ /* @__PURE__ */ jsxRuntime.jsx("aside", { className: "bg-grey-50/60 p-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-8", children: [
17052
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
17053
+ /* @__PURE__ */ jsxRuntime.jsx(Heading, { level: 3, size: 5, className: "text-foreground", trim: "normal", children: "Configuration" }),
17054
+ /* @__PURE__ */ jsxRuntime.jsx(Text, { size: 2, children: "Choose a palette, set your primary and accent families, then select an approved background." })
17055
+ ] }),
17056
+ /* @__PURE__ */ jsxRuntime.jsx(SidebarStep, { step: 1, title: "Select your palette", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid gap-2", children: ["brand", "aboriginal"].map((palette) => {
17057
+ const isSelected = themeCategory === palette;
17058
+ const label = palette === "brand" ? "Brand palette" : "Aboriginal palette";
17059
+ return /* @__PURE__ */ jsxRuntime.jsx(
17060
+ "button",
17061
+ {
17062
+ type: "button",
17063
+ "aria-label": `Select ${label}`,
17064
+ "aria-pressed": isSelected,
17065
+ onClick: () => handleThemeCategoryChange(palette),
17066
+ className: cn(
17067
+ "rounded-sm border px-3 py-2.5 text-left text-sm font-semibold transition-colors",
17068
+ isSelected ? "border-primary-800 bg-primary-800 text-white" : "border-grey-300 bg-background text-foreground hover:border-primary-800 hover:bg-primary-50"
17069
+ ),
17070
+ children: label
17071
+ },
17072
+ palette
17073
+ );
17074
+ }) }) }),
17075
+ /* @__PURE__ */ jsxRuntime.jsx(
17076
+ SidebarStep,
17077
+ {
17078
+ step: 2,
17079
+ title: "Choose your colours",
17080
+ description: "Grey is added automatically from the selected palette.",
17081
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-5", children: [
17082
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
17083
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-semibold text-foreground", children: "Primary colour" }),
17084
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-3 gap-2", children: selectableFamilies.map((family) => {
17085
+ const swatchTone = 800;
17086
+ const isSelected = family.key === context.primary.key;
17087
+ const label = getFamilySelectorLabel2(family, themeCategory, "primary colour");
17088
+ return /* @__PURE__ */ jsxRuntime.jsx(
17089
+ "button",
17090
+ {
17091
+ type: "button",
17092
+ "aria-label": `Select ${label} as primary colour`,
17093
+ "aria-pressed": isSelected,
17094
+ onClick: () => handlePrimaryColorChange(family.key),
17095
+ className: cn(
17096
+ "min-h-11 rounded-sm border px-2 py-2 text-center text-[0.8rem] leading-5 font-semibold transition-transform",
17097
+ isSelected ? "ring-2 ring-primary-700 ring-offset-2 ring-offset-grey-50/60" : "hover:-translate-y-px"
17098
+ ),
17099
+ style: {
17100
+ backgroundColor: getFamilySwatchColor2(family, swatchTone),
17101
+ color: getReadableTextColor(swatchTone),
17102
+ borderColor: "rgba(0, 0, 0, 0.12)"
17103
+ },
17104
+ title: label,
17105
+ children: label
17106
+ },
17107
+ family.key
17108
+ );
17109
+ }) })
17110
+ ] }),
17111
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
17112
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-semibold text-foreground", children: "Accent colour" }),
17113
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-3 gap-2", children: selectableAccentFamilies.map((family) => {
17114
+ const swatchTone = 600;
17115
+ const isSelected = family.key === context.accent.key;
17116
+ const label = getFamilySelectorLabel2(family, themeCategory, "accent colour");
17117
+ return /* @__PURE__ */ jsxRuntime.jsx(
17118
+ "button",
17119
+ {
17120
+ type: "button",
17121
+ "aria-label": `Select ${label} as accent colour`,
17122
+ "aria-pressed": isSelected,
17123
+ onClick: () => handleAccentColorChange(family.key),
17124
+ className: cn(
17125
+ "min-h-11 rounded-sm border px-2 py-2 text-center text-[0.8rem] leading-5 font-semibold transition-transform",
17126
+ isSelected ? "ring-2 ring-primary-700 ring-offset-2 ring-offset-grey-50/60" : "hover:-translate-y-px"
17127
+ ),
17128
+ style: {
17129
+ backgroundColor: getFamilySwatchColor2(family, swatchTone),
17130
+ color: getReadableTextColor(swatchTone),
17131
+ borderColor: "rgba(0, 0, 0, 0.12)"
17132
+ },
17133
+ title: label,
17134
+ children: label
17135
+ },
17136
+ family.key
17137
+ );
17138
+ }) })
17139
+ ] })
17140
+ ] })
17141
+ }
17142
+ ),
17143
+ /* @__PURE__ */ jsxRuntime.jsx(SidebarStep, { step: 3, title: "Pick a background", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
17144
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm text-muted-foreground", children: [
17145
+ "Selected:",
17146
+ " ",
17147
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold text-foreground", children: selectedBackground.token })
17148
+ ] }),
17149
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-4 gap-2", children: context.backgrounds.map((background) => {
17150
+ const hasPairs = (context.pairsByBackground[background.token]?.length ?? 0) > 0;
17151
+ const isSelected = selectedBackground.token === background.token;
17152
+ return /* @__PURE__ */ jsxRuntime.jsx(
17153
+ "button",
17154
+ {
17155
+ type: "button",
17156
+ "aria-label": hasPairs ? `Select ${background.token} background` : `Select ${background.token} background with no AAA pairings`,
17157
+ "aria-pressed": isSelected,
17158
+ onClick: () => handleBackgroundChange(background.token),
17159
+ className: cn(
17160
+ "relative aspect-square rounded-sm border transition-transform",
17161
+ isSelected ? "ring-2 ring-primary-700 ring-offset-2 ring-offset-grey-50/60" : "hover:-translate-y-px",
17162
+ !hasPairs && "opacity-80"
17163
+ ),
17164
+ style: {
17165
+ backgroundColor: background.hex,
17166
+ borderColor: "rgba(0, 0, 0, 0.14)"
17167
+ },
17168
+ title: background.token,
17169
+ children: !hasPairs ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute top-1/2 left-1/2 h-0.5 w-5 -translate-x-1/2 -translate-y-1/2 rotate-45 rounded-full bg-white shadow-[0_0_0_1px_rgba(0,0,0,0.28)]" }) : null
17170
+ },
17171
+ background.token
17172
+ );
17173
+ }) })
17174
+ ] }) })
17175
+ ] }) }),
17176
+ /* @__PURE__ */ jsxRuntime.jsxs("main", { className: "space-y-8", children: [
17177
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
17178
+ /* @__PURE__ */ jsxRuntime.jsx(Heading, { level: 3, size: 5, className: "text-foreground", trim: "normal", children: "Live Preview & Results" }),
17179
+ /* @__PURE__ */ jsxRuntime.jsx(Text, { size: 2, children: "Review the selected pairing in context, then compare the available AAA combinations for your chosen background." })
17180
+ ] }),
17181
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-5", children: [
17182
+ selectedPair ? /* @__PURE__ */ jsxRuntime.jsx(
17183
+ PreviewHeroCard,
17184
+ {
17185
+ familySummary,
17186
+ isRecommended: Boolean(selectedPair),
17187
+ pair: selectedPair
17188
+ }
17189
+ ) : /* @__PURE__ */ jsxRuntime.jsx(PreviewFallbackCard2, { background: selectedBackground }),
17190
+ /* @__PURE__ */ jsxRuntime.jsx(AccessibilityScoreCard, { pair: selectedPair })
17191
+ ] }),
17192
+ /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "space-y-4", children: [
17193
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
17194
+ /* @__PURE__ */ jsxRuntime.jsx(Heading, { level: 3, size: 5, className: "text-foreground", trim: "normal", children: "Recommended Combinations" }),
17195
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-base text-muted-foreground", children: [
17196
+ "AAA-recommended foregrounds for",
17197
+ " ",
17198
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold text-foreground", children: selectedBackground.token }),
17199
+ "."
17200
+ ] })
17201
+ ] }),
17202
+ selectedBackgroundPairs.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid gap-4 md:grid-cols-2 xl:grid-cols-3", children: selectedBackgroundPairs.map((pair) => /* @__PURE__ */ jsxRuntime.jsx(
17203
+ RecommendedPairCard,
17204
+ {
17205
+ pair,
17206
+ isSelected: selectedPair?.id === pair.id,
17207
+ onSelect: () => handlePairChange(pair.id)
17208
+ },
17209
+ pair.id
17210
+ )) }) : /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "gap-0 py-0", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-6 py-6", children: [
17211
+ /* @__PURE__ */ jsxRuntime.jsx(Heading, { level: 4, size: 6, className: "text-foreground", trim: "normal", children: "No recommended combinations" }),
17212
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-3 text-base text-muted-foreground", children: "Choose another approved background tone to review available AAA pairings." })
17213
+ ] }) })
17214
+ ] }),
17215
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-4 lg:grid-cols-2", children: [
17216
+ /* @__PURE__ */ jsxRuntime.jsx(
17217
+ PairDetailCard2,
17218
+ {
17219
+ color: selectedBackground,
17220
+ role: "Background",
17221
+ visibleFormats
17222
+ }
17223
+ ),
17224
+ detailForeground ? /* @__PURE__ */ jsxRuntime.jsx(
17225
+ PairDetailCard2,
17226
+ {
17227
+ color: detailForeground,
17228
+ role: "Foreground",
17229
+ visibleFormats
17230
+ }
17231
+ ) : /* @__PURE__ */ jsxRuntime.jsxs(Card, { className: "gap-4", children: [
17232
+ /* @__PURE__ */ jsxRuntime.jsx(CardHeader, { className: "gap-3 border-b", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
17233
+ /* @__PURE__ */ jsxRuntime.jsx(CardTitle, { children: "Foreground" }),
17234
+ /* @__PURE__ */ jsxRuntime.jsx(CardDescription, { children: "No recommended foreground available" })
17235
+ ] }) }),
17236
+ /* @__PURE__ */ jsxRuntime.jsx(CardContent, { children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: "Choose another approved tone or review the recommended foregrounds for the same background." }) })
17237
+ ] })
17238
+ ] })
17239
+ ] })
17240
+ ] });
17241
+ }
17242
+ function ColorPairingToolV2({
17243
+ visibleFormats = DEFAULT_VISIBLE_FORMATS2
17244
+ } = {}) {
17245
+ const normalizedVisibleFormats = [...new Set(visibleFormats)];
17246
+ return /* @__PURE__ */ jsxRuntime.jsx(React5.Suspense, { fallback: /* @__PURE__ */ jsxRuntime.jsx(ColorPairingToolV2Loading, {}), children: /* @__PURE__ */ jsxRuntime.jsx(ColorPairingToolV2Content, { visibleFormats: normalizedVisibleFormats }) });
17247
+ }
17248
+ function Sheet({ ...props }) {
17249
+ return /* @__PURE__ */ jsxRuntime.jsx(SheetPrimitive__namespace.Root, { "data-slot": "sheet", ...props });
17250
+ }
17251
+ function SheetTrigger({ ...props }) {
17252
+ return /* @__PURE__ */ jsxRuntime.jsx(SheetPrimitive__namespace.Trigger, { "data-slot": "sheet-trigger", ...props });
17253
+ }
17254
+ function SheetClose({ ...props }) {
17255
+ return /* @__PURE__ */ jsxRuntime.jsx(SheetPrimitive__namespace.Close, { "data-slot": "sheet-close", ...props });
17256
+ }
17257
+ function SheetPortal({ ...props }) {
17258
+ return /* @__PURE__ */ jsxRuntime.jsx(SheetPrimitive__namespace.Portal, { "data-slot": "sheet-portal", ...props });
17259
+ }
17260
+ function SheetOverlay({
17261
+ className,
17262
+ ...props
17263
+ }) {
17264
+ return /* @__PURE__ */ jsxRuntime.jsx(
17265
+ SheetPrimitive__namespace.Overlay,
17266
+ {
17267
+ "data-slot": "sheet-overlay",
17268
+ className: cn(
17269
+ "fixed inset-0 z-50 bg-black/50 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:animate-in data-[state=open]:fade-in-0",
17270
+ className
17271
+ ),
17272
+ ...props
17273
+ }
17274
+ );
17275
+ }
17276
+ function SheetContent({
17277
+ className,
17278
+ children,
17279
+ side = "right",
17280
+ showClose = true,
17281
+ ...props
17282
+ }) {
17283
+ return /* @__PURE__ */ jsxRuntime.jsxs(SheetPortal, { children: [
17284
+ /* @__PURE__ */ jsxRuntime.jsx(SheetOverlay, {}),
17285
+ /* @__PURE__ */ jsxRuntime.jsxs(
17286
+ SheetPrimitive__namespace.Content,
17287
+ {
17288
+ "data-slot": "sheet-content",
17289
+ className: cn(
17290
+ "fixed z-50 flex flex-col gap-4 bg-background shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=closed]:animate-out data-[state=open]:duration-500 data-[state=open]:animate-in",
17291
+ side === "right" && "inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm",
17292
+ side === "left" && "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm",
17293
+ side === "top" && "inset-x-0 top-0 h-auto border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",
17294
+ side === "bottom" && "inset-x-0 bottom-0 h-auto border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",
17295
+ className
17296
+ ),
17297
+ ...props,
17298
+ children: [
17299
+ children,
17300
+ showClose && /* @__PURE__ */ jsxRuntime.jsx(SheetPrimitive__namespace.Close, { "data-slot": "sheet-close", className: "absolute top-4 right-4", asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(Button2, { variant: "ghost", size: "icon", children: [
17301
+ /* @__PURE__ */ jsxRuntime.jsx(Icons.close, { className: "size-6", "aria-hidden": "true" }),
17302
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Close" })
17303
+ ] }) })
17304
+ ]
17305
+ }
17306
+ )
17307
+ ] });
17308
+ }
17309
+ function SheetHeader({ className, ...props }) {
17310
+ return /* @__PURE__ */ jsxRuntime.jsx(
17311
+ "div",
17312
+ {
17313
+ "data-slot": "sheet-header",
17314
+ className: cn("flex flex-col gap-1.5 p-4", className),
17315
+ ...props
17316
+ }
17317
+ );
17318
+ }
17319
+ function SheetFooter({ className, ...props }) {
17320
+ return /* @__PURE__ */ jsxRuntime.jsx(
17321
+ "div",
17322
+ {
17323
+ "data-slot": "sheet-footer",
17324
+ className: cn("mt-auto flex flex-col gap-2 p-4", className),
17325
+ ...props
17326
+ }
17327
+ );
17328
+ }
17329
+ function SheetTitle({ className, ...props }) {
17330
+ return /* @__PURE__ */ jsxRuntime.jsx(
17331
+ SheetPrimitive__namespace.Title,
17332
+ {
17333
+ "data-slot": "sheet-title",
17334
+ className: cn("font-semibold text-foreground", className),
17335
+ ...props
17336
+ }
17337
+ );
17338
+ }
17339
+ function SheetDescription({
17340
+ className,
17341
+ ...props
17342
+ }) {
17343
+ return /* @__PURE__ */ jsxRuntime.jsx(
17344
+ SheetPrimitive__namespace.Description,
17345
+ {
17346
+ "data-slot": "sheet-description",
17347
+ className: cn("text-sm text-muted-foreground", className),
17348
+ ...props
17349
+ }
17350
+ );
17351
+ }
17352
+ function useSelectorHeight(selector = "header") {
17353
+ const [height, setHeight] = React5.useState(0);
17354
+ const elementRef = React5.useRef(null);
17355
+ const resizeObserverRef = React5.useRef(null);
17356
+ React5.useEffect(() => {
17357
+ const element = document.querySelector(selector);
17358
+ if (!element) return;
17359
+ elementRef.current = element;
17360
+ const resizeObserver = new ResizeObserver((entries) => {
17361
+ const entry = entries[0];
17362
+ const target = entry?.target ?? elementRef.current;
17363
+ if (!target) return;
17364
+ setHeight(target.offsetHeight);
17365
+ });
17366
+ resizeObserverRef.current = resizeObserver;
17367
+ resizeObserver.observe(element);
17368
+ return () => {
17369
+ resizeObserverRef.current?.disconnect();
17370
+ };
17371
+ }, [selector]);
17372
+ return height;
17373
+ }
17374
+
17375
+ // src/hooks/useStickyOffset.ts
17376
+ function useStickyOffset(extraPadding = 0) {
17377
+ const headerHeight = useSelectorHeight("#nsw-header");
17378
+ const navigationHeight = useSelectorHeight("#nsw-main-navigation");
17379
+ return React5.useMemo(() => {
17380
+ const total = headerHeight + navigationHeight + extraPadding;
17381
+ return total > 0 ? total : 0;
17382
+ }, [extraPadding, headerHeight, navigationHeight]);
17383
+ }
17384
+ var PREFERRED_BACKGROUND_TONES3 = [400, 600, 200, 800, 100, 50];
17385
+ var DEFAULT_VISIBLE_FORMATS3 = ["hex", "rgb", "hsl", "oklch"];
17386
+ var DEFAULT_INITIAL_BACKGROUND_TOKEN3 = "nsw-blue-800";
17387
+ var DEFAULT_INITIAL_PAIR_ID3 = "nsw-blue-800:nsw-blue-200";
17388
+ var COLOR_PAIRING_TOOL_V3_PATH = "/core/colour/colour-pairing-tool-3";
17389
+ var AAA_NORMAL_TEXT_THRESHOLD2 = "7.0:1 for text below the WCAG large-text threshold. Sentence-case body copy should generally stay at 16px+ unless it is microcopy.";
17390
+ var AAA_LARGE_TEXT_THRESHOLD2 = "4.5:1 for WCAG large text: 24px+, or 18.5px+ bold";
17391
+ var MOBILE_RESULT_SCROLL_QUERY = "(max-width: 1023px)";
17392
+ var PERSISTENT_DRAWER_MIN_WIDTH_QUERY = "(min-width: 1280px)";
17393
+ var COLOR_PAIRING_TOOL_DRAWER_STEPS = [
17394
+ {
17395
+ id: "colours",
17396
+ title: "Choose colours",
17397
+ eyebrow: "Step 1 of 3",
17398
+ description: "Select the palette, primary family, and accent family."
17399
+ },
17400
+ {
17401
+ id: "backgrounds",
17402
+ title: "Choose background",
17403
+ eyebrow: "Step 2 of 3",
17404
+ description: "Pick the background tone that you want to pair."
17405
+ },
17406
+ {
17407
+ id: "combinations",
17408
+ title: "Choose recommended combinations",
17409
+ eyebrow: "Step 3 of 3",
17410
+ description: "Select the foreground pairing that should drive the example."
17411
+ }
17412
+ ];
17413
+ var COLOR_PAIRING_TOOL_V3_ANALYTICS_EVENT = "nsw-colour-pairing-tool-v3";
17414
+ function getToneFromToken3(token) {
17415
+ if (!token) return null;
17416
+ const match = token.match(/-(\d+)$/);
17417
+ return match ? Number.parseInt(match[1], 10) : null;
17418
+ }
17419
+ function getFamilySwatchColor3(family, preferredTone = 600) {
17420
+ const exactMatch = family.colors.find((color2) => color2.tone === preferredTone);
17421
+ if (exactMatch) {
17422
+ return exactMatch.hex;
17423
+ }
17424
+ const closestMatch = [...family.colors].sort(
17425
+ (left, right) => Math.abs(left.tone - preferredTone) - Math.abs(right.tone - preferredTone)
17426
+ )[0];
17427
+ return closestMatch?.hex ?? "transparent";
17428
+ }
17429
+ function getFamilySelectorLabel3(family, themeCategory, selectionRole) {
17430
+ if (themeCategory !== "aboriginal") {
17431
+ return family.label;
17432
+ }
17433
+ const preferredTone = selectionRole === "primary colour" ? 800 : 600;
17434
+ return family.colors.find((color2) => color2.tone === preferredTone)?.name ?? family.label;
17435
+ }
17436
+ function getPairingColorDisplayName3(color2) {
17437
+ return color2.name ?? `${color2.familyLabel} ${color2.tone}`;
17438
+ }
17439
+ function isWhiteForegroundPair3(pair) {
17440
+ return pair.foreground.token === "white";
17441
+ }
17442
+ function isLargeTextOnlyPair(pair) {
17443
+ return pair.passes.aaaLarge && !pair.passes.aaaText;
17444
+ }
17445
+ function getWhiteForegroundGuidance3(pair) {
17446
+ if (pair.passes.aaaText) {
17447
+ return "White is approved for headings, body copy, and calls to action on this background.";
17448
+ }
17449
+ if (pair.passes.aaaLarge) {
17450
+ return "Use white only for WCAG large text on this background, such as headings at 24px+ or bold text at 18.5px+. Keep sentence-case body copy at 16px+ and use a darker recommended foreground instead.";
17451
+ }
17452
+ return "Do not use white on this background. Choose one of the recommended foregrounds below instead.";
17453
+ }
17454
+ function getPreviewGuidance3(pair, isRecommended) {
17455
+ if (!isWhiteForegroundPair3(pair)) {
17456
+ return "Use only AAA-recommended combinations across your selected primary, accent, and grey families.";
17457
+ }
17458
+ if (isRecommended) {
17459
+ return "Use white text on dark colour only when it meets AAA for headings, body copy, and calls to action.";
17460
+ }
17461
+ return getWhiteForegroundGuidance3(pair);
17462
+ }
17463
+ function getPreferredPairForBackground3(pairs, preferredPairId) {
17464
+ if (preferredPairId) {
17465
+ const preferredPair = pairs.find((pair) => pair.id === preferredPairId);
17466
+ if (preferredPair) {
17467
+ return preferredPair;
17468
+ }
17469
+ }
17470
+ return pairs.find((pair) => !isWhiteForegroundPair3(pair)) ?? pairs[0] ?? null;
17471
+ }
17472
+ function getDefaultBackgroundToken3(context) {
17473
+ for (const tone of PREFERRED_BACKGROUND_TONES3) {
17474
+ for (const group of context.backgroundGroups) {
17475
+ const match = group.backgrounds.find(
17476
+ (background) => background.tone === tone && (context.pairsByBackground[background.token]?.length ?? 0) > 0
17477
+ );
17478
+ if (match) {
17479
+ return match.token;
17480
+ }
17481
+ }
17482
+ }
17483
+ for (const tone of PREFERRED_BACKGROUND_TONES3) {
17484
+ for (const group of context.backgroundGroups) {
17485
+ const match = group.backgrounds.find((background) => background.tone === tone);
17486
+ if (match) {
17487
+ return match.token;
17488
+ }
17489
+ }
17490
+ }
17491
+ return context.backgrounds[0]?.token ?? "";
17492
+ }
17493
+ function resolveBackgroundToken3(context, preferredToken, preferredTone) {
17494
+ if (preferredToken && context.backgrounds.some((background) => background.token === preferredToken)) {
17495
+ return preferredToken;
17496
+ }
17497
+ if (preferredTone !== null && preferredTone !== void 0) {
17498
+ for (const group of context.backgroundGroups) {
17499
+ const match = group.backgrounds.find((background) => background.tone === preferredTone);
17500
+ if (match) {
17501
+ return match.token;
17502
+ }
17503
+ }
17504
+ }
17505
+ return getDefaultBackgroundToken3(context);
17506
+ }
17507
+ function getInitialPairingState3(searchParams) {
17508
+ const paletteParam = searchParams.get("palette");
17509
+ const primaryParam = searchParams.get("primary");
17510
+ const accentParam = searchParams.get("accent");
17511
+ const pairParam = searchParams.get("pair");
17512
+ const backgroundParam = searchParams.get("background");
17513
+ const themeCategory = paletteParam === "brand" || paletteParam === "aboriginal" ? paletteParam : "brand";
17514
+ const context = getPairingContext(themeCategory, primaryParam, accentParam);
17515
+ const shouldUseDefaultBrandExample = !backgroundParam && !pairParam && themeCategory === "brand" && context.primary.key === "blue" && context.accent.key === "red";
17516
+ const defaultBackgroundToken = shouldUseDefaultBrandExample ? context.backgrounds.some(
17517
+ (background) => background.token === DEFAULT_INITIAL_BACKGROUND_TOKEN3
17518
+ ) ? DEFAULT_INITIAL_BACKGROUND_TOKEN3 : null : null;
17519
+ const defaultPairId = shouldUseDefaultBrandExample && defaultBackgroundToken && context.pairsByBackground[defaultBackgroundToken]?.some(
17520
+ (pair) => pair.id === DEFAULT_INITIAL_PAIR_ID3
17521
+ ) ? DEFAULT_INITIAL_PAIR_ID3 : null;
17522
+ const pairBackgroundToken = context.recommendedPairs.find((pair) => pair.id === pairParam)?.background.token ?? null;
17523
+ const selectedBackgroundToken = resolveBackgroundToken3(
17524
+ context,
17525
+ backgroundParam ?? pairBackgroundToken ?? defaultBackgroundToken,
17526
+ getToneFromToken3(backgroundParam ?? pairBackgroundToken ?? defaultBackgroundToken)
17527
+ );
17528
+ const selectedPairId = getPreferredPairForBackground3(
17529
+ context.pairsByBackground[selectedBackgroundToken] ?? [],
17530
+ pairParam ?? defaultPairId
17531
+ )?.id ?? "";
17532
+ return {
17533
+ accentKey: context.accent.key,
17534
+ primaryKey: context.primary.key,
17535
+ selectedBackgroundToken,
17536
+ selectedPairId,
17537
+ themeCategory
17538
+ };
17539
+ }
17540
+ function getReadableTextColor2(tone) {
17541
+ return tone >= 600 ? "#ffffff" : "#002664";
17542
+ }
17543
+ function getBackgroundOptionName(background) {
17544
+ return background.name ?? `${background.familyLabel} ${background.tone}`;
17545
+ }
17546
+ function getResultExplanation(pair, bestPair) {
17547
+ if (!pair) {
17548
+ return "No AAA-compliant foreground options available for this selection.";
17549
+ }
17550
+ if (pair.id === bestPair?.id) {
17551
+ return "Meets AAA for normal and large text. This is the NSW-recommended starting point for this background.";
17552
+ }
17553
+ if (isWhiteForegroundPair3(pair) && isLargeTextOnlyPair(pair)) {
17554
+ return "White meets AAA for large text on this background only. Use a darker foreground for standard body copy and smaller interface text.";
17555
+ }
17556
+ if (isWhiteForegroundPair3(pair) && !pair.passes.aaaLarge) {
17557
+ return "White does not meet AAA for normal or large text on this background. Use another approved background or a darker foreground where one is available.";
17558
+ }
17559
+ return "Meets AAA for normal and large text. This is a valid alternative, while the recommended pairing remains the clearest default.";
17560
+ }
17561
+ function getBestRecommendationReason(pair, context) {
17562
+ if (isWhiteForegroundPair3(pair)) {
17563
+ return "Recommended because this background is dark enough to support white text at AAA contrast.";
17564
+ }
17565
+ if (pair.foreground.familyKey === pair.background.familyKey) {
17566
+ return "Recommended because it stays within the same colour family while keeping clear AAA contrast.";
17567
+ }
17568
+ if (pair.foreground.familyKey === context.grey.key) {
17569
+ return "Recommended because grey provides a strong neutral contrast without competing with the background.";
17570
+ }
17571
+ if (pair.foreground.familyKey === context.accent.key) {
17572
+ return "Recommended because the selected accent family adds emphasis while preserving AAA contrast.";
17573
+ }
17574
+ if (pair.foreground.familyKey === context.primary.key) {
17575
+ return "Recommended because the selected primary family gives the clearest AAA-compliant contrast for this background.";
17576
+ }
17577
+ return "Recommended because it is the clearest NSW-approved AAA pairing for this background.";
17578
+ }
17579
+ function getRecommendationCategory(pair, bestPair, context) {
17580
+ if (pair.id === bestPair?.id) return "best";
17581
+ if (isWhiteForegroundPair3(pair)) return "white";
17582
+ if (pair.foreground.familyKey === pair.background.familyKey) return "same-family";
17583
+ if (pair.foreground.familyKey === context.accent.key) return "accent-family";
17584
+ if (pair.foreground.familyKey === context.grey.key) return "grey-option";
17585
+ if (pair.foreground.familyKey === context.primary.key) return "primary-family";
17586
+ return "approved";
17587
+ }
17588
+ function getRecommendationCategoryLabel(category) {
17589
+ switch (category) {
17590
+ case "best":
17591
+ return "Best recommended";
17592
+ case "same-family":
17593
+ return "Same family";
17594
+ case "accent-family":
17595
+ return "Accent family";
17596
+ case "grey-option":
17597
+ return "Grey option";
17598
+ case "primary-family":
17599
+ return "Primary family";
17600
+ case "white":
17601
+ return "White";
17602
+ default:
17603
+ return "Approved option";
17604
+ }
17605
+ }
17606
+ function getRecommendationSortRank(category) {
17607
+ switch (category) {
17608
+ case "best":
17609
+ return 0;
17610
+ case "same-family":
17611
+ return 1;
17612
+ case "accent-family":
17613
+ return 2;
17614
+ case "grey-option":
17615
+ return 3;
17616
+ case "white":
17617
+ return 4;
17618
+ case "primary-family":
17619
+ return 5;
17620
+ default:
17621
+ return 6;
17622
+ }
17623
+ }
17624
+ function getAvailabilityMeta(isSelected, hasPairs) {
17625
+ if (isSelected && hasPairs) {
17626
+ return {
17627
+ description: "Selected background with AAA foreground options.",
17628
+ icon: Icons.check_circle,
17629
+ label: "Selected",
17630
+ tone: "selected"
17631
+ };
17632
+ }
17633
+ if (isSelected) {
17634
+ return {
17635
+ description: "Selected background with no AAA foreground options.",
17636
+ icon: Icons.warning,
17637
+ label: "Selected, no AAA",
17638
+ tone: "unavailable"
17639
+ };
17640
+ }
17641
+ if (hasPairs) {
17642
+ return {
17643
+ description: "AAA foreground options available.",
17644
+ icon: Icons.radio_button_checked,
17645
+ label: "Available",
17646
+ tone: "available"
17647
+ };
17648
+ }
17649
+ return {
17650
+ description: "No AAA foreground available.",
17651
+ icon: Icons.close,
17652
+ label: "No AAA",
17653
+ tone: "unavailable"
17654
+ };
17655
+ }
17656
+ function getPairingCopyText(pair) {
17657
+ return [
17658
+ `Background: ${pair.background.token} (${pair.background.hex})`,
17659
+ `Foreground: ${pair.foreground.token} (${pair.foreground.hex})`,
17660
+ `Contrast ratio: ${pair.contrastRatio.toFixed(2)}:1`,
17661
+ "Accessibility: Meets AAA for normal and large text"
17662
+ ].join("\n");
17663
+ }
17664
+ function getLiveAnnouncement(pair, background) {
17665
+ if (!background) {
17666
+ return "No approved background tones available.";
17667
+ }
17668
+ if (!pair) {
17669
+ return `${background.token} selected. No AAA-compliant foreground options available for this selection.`;
17670
+ }
17671
+ if (isWhiteForegroundPair3(pair) && isLargeTextOnlyPair(pair)) {
17672
+ return `${background.token} with white. Contrast ratio ${pair.contrastRatio.toFixed(2)} to 1. Meets AAA for large text only.`;
17673
+ }
17674
+ if (isWhiteForegroundPair3(pair) && !pair.passes.aaaLarge) {
17675
+ return `${background.token} with white. Contrast ratio ${pair.contrastRatio.toFixed(2)} to 1. Fails AAA for normal and large text.`;
17676
+ }
17677
+ return `${background.token} with ${pair.foreground.token}. Contrast ratio ${pair.contrastRatio.toFixed(2)} to 1. Meets AAA for normal and large text.`;
17678
+ }
17679
+ function formatValueRows(color2, visibleFormats) {
17680
+ const hasDisplayTone = color2.token !== "white";
17681
+ return [
17682
+ { key: "token", label: "Token", value: color2.token, copyable: true },
17683
+ {
17684
+ key: "tone",
17685
+ label: "Tone",
17686
+ value: hasDisplayTone ? String(color2.tone) : "Not applicable",
17687
+ copyable: hasDisplayTone
17688
+ },
17689
+ ...visibleFormats.map((format) => ({
17690
+ key: format,
17691
+ label: format.toUpperCase(),
17692
+ value: color2[format],
17693
+ copyable: true
17694
+ }))
17695
+ ];
17696
+ }
17697
+ function SelectorButton({
17698
+ description,
17699
+ isSelected,
17700
+ label,
17701
+ onClick,
17702
+ swatch
17703
+ }) {
17704
+ return /* @__PURE__ */ jsxRuntime.jsx(
17705
+ "button",
17706
+ {
17707
+ type: "button",
17708
+ "aria-pressed": isSelected,
17709
+ onClick,
17710
+ className: cn(
17711
+ "w-full rounded-sm border px-3 py-3 text-left transition-colors focus-visible:ring-2 focus-visible:ring-primary-700 focus-visible:ring-offset-2 focus-visible:outline-hidden",
17712
+ isSelected ? "border-primary-800 bg-primary-50" : "border-grey-300 bg-white hover:border-primary-500 hover:bg-grey-50"
17713
+ ),
17714
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-3", children: [
17715
+ swatch ? /* @__PURE__ */ jsxRuntime.jsx(
17716
+ "span",
17717
+ {
17718
+ "aria-hidden": "true",
17719
+ className: "mt-0.5 size-4 shrink-0 rounded-full border border-black/10",
17720
+ style: { backgroundColor: swatch }
17721
+ }
17722
+ ) : null,
17723
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 space-y-1", children: [
17724
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-semibold text-foreground", children: label }),
17725
+ description ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs/5 text-muted-foreground", children: description }) : null
17726
+ ] })
17727
+ ] })
17728
+ }
17729
+ );
17730
+ }
17731
+ function BackgroundSwatchButton({
17732
+ background,
17733
+ hasPairs,
17734
+ isSelected,
17735
+ onClick
17736
+ }) {
17737
+ const status = getAvailabilityMeta(isSelected, hasPairs);
17738
+ const StatusIcon = status.icon;
17739
+ return /* @__PURE__ */ jsxRuntime.jsxs(
17740
+ "button",
17741
+ {
17742
+ type: "button",
17743
+ "aria-pressed": isSelected,
17744
+ "aria-label": `Select ${background.token} background. ${status.description}`,
17745
+ onClick,
17746
+ className: cn(
17747
+ "w-full rounded-sm border bg-white p-3 text-left transition-colors focus-visible:ring-2 focus-visible:ring-primary-700 focus-visible:ring-offset-2 focus-visible:outline-hidden",
17748
+ isSelected ? "border-primary-800 bg-primary-50" : hasPairs ? "border-grey-300 hover:border-primary-500 hover:bg-grey-50" : "border-grey-300 hover:border-grey-500"
17749
+ ),
17750
+ children: [
17751
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-3", children: [
17752
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0", children: [
17753
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-semibold text-foreground", children: getBackgroundOptionName(background) }),
17754
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 font-mono text-[0.72rem] break-all text-muted-foreground", children: background.token })
17755
+ ] }),
17756
+ /* @__PURE__ */ jsxRuntime.jsxs(
17757
+ "span",
17758
+ {
17759
+ className: cn(
17760
+ "inline-flex items-center gap-1 rounded-sm border px-2 py-1 text-[0.68rem] font-semibold uppercase",
17761
+ status.tone === "selected" && "border-primary-800 bg-primary-800 text-white dark:border-primary-500 dark:bg-primary-500",
17762
+ status.tone === "available" && "border-grey-300 bg-grey-50 text-foreground",
17763
+ status.tone === "unavailable" && "border-danger-300 bg-danger-50 text-danger-900 dark:border-danger-800 dark:bg-danger-950/20 dark:text-danger-200"
17764
+ ),
17765
+ children: [
17766
+ /* @__PURE__ */ jsxRuntime.jsx(StatusIcon, { "data-slot": "icon", className: "size-4" }),
17767
+ status.label
17768
+ ]
17769
+ }
17770
+ )
17771
+ ] }),
17772
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-3 overflow-hidden rounded-[2px] border border-black/10", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-14 w-full", style: { backgroundColor: background.hex } }) }),
17773
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-3 text-xs/5 text-muted-foreground", children: status.description })
17774
+ ]
17775
+ }
17776
+ );
17777
+ }
17778
+ function ResultSummaryTile({
17779
+ children,
17780
+ className,
17781
+ label
17782
+ }) {
17783
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("rounded-sm border border-grey-200 bg-white px-4 py-4 sm:px-5", className), children: [
17784
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-semibold text-grey-700", children: label }),
17785
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-3", children })
17786
+ ] });
17787
+ }
17788
+ function AccessibilityCheckTile({
17789
+ className,
17790
+ label,
17791
+ passes,
17792
+ threshold
17793
+ }) {
17794
+ const status = passes === null ? "unavailable" : passes ? "pass" : "fail";
17795
+ return /* @__PURE__ */ jsxRuntime.jsx(
17796
+ "div",
17797
+ {
17798
+ className: cn(
17799
+ "rounded-sm border px-4 py-4 sm:px-5",
17800
+ className,
17801
+ status === "pass" && "border-success-200 bg-success-50",
17802
+ status === "fail" && "border-danger-200 bg-danger-50",
17803
+ status === "unavailable" && "border-grey-200 bg-white"
17804
+ ),
17805
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between sm:gap-4", children: [
17806
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
17807
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-semibold text-foreground", children: label }),
17808
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm/6 text-muted-foreground", children: status === "unavailable" ? "No contrast ratio available for this result." : threshold })
17809
+ ] }),
17810
+ /* @__PURE__ */ jsxRuntime.jsxs(
17811
+ "span",
17812
+ {
17813
+ className: cn(
17814
+ "inline-flex items-center gap-1 rounded-sm px-2.5 py-1 text-[0.72rem] font-semibold tracking-[0.12em] uppercase",
17815
+ status === "pass" && "bg-success-700 text-white",
17816
+ status === "fail" && "bg-danger-700 text-white",
17817
+ status === "unavailable" && "bg-grey-100 text-foreground"
17818
+ ),
17819
+ children: [
17820
+ status === "pass" ? /* @__PURE__ */ jsxRuntime.jsx(Icons.check, { "data-slot": "icon", className: "size-4" }) : status === "fail" ? /* @__PURE__ */ jsxRuntime.jsx(Icons.close, { "data-slot": "icon", className: "size-4" }) : /* @__PURE__ */ jsxRuntime.jsx(Icons.info, { "data-slot": "icon", className: "size-4" }),
17821
+ status === "pass" ? "Pass" : status === "fail" ? "Fail" : "Unavailable"
17822
+ ]
17823
+ }
17824
+ )
17825
+ ] })
17826
+ }
17827
+ );
17828
+ }
17829
+ function ResultColorSummary({
17830
+ color: color2,
17831
+ fallbackLabel
17832
+ }) {
17833
+ if (!color2) {
17834
+ return /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: fallbackLabel ?? "Not available" });
17835
+ }
17836
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-4", children: [
17837
+ /* @__PURE__ */ jsxRuntime.jsx(
17838
+ "span",
17839
+ {
17840
+ "aria-hidden": "true",
17841
+ className: "mt-1 size-6 shrink-0 rounded-full border border-black/10",
17842
+ style: { backgroundColor: color2.hex }
17843
+ }
17844
+ ),
17845
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0", children: [
17846
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "leading-7 font-semibold text-foreground", children: getPairingColorDisplayName3(color2) }),
17847
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 font-mono text-sm break-all text-muted-foreground", children: color2.token })
17848
+ ] })
17849
+ ] });
17850
+ }
17851
+ function CurrentResultCard({
17852
+ bestPair,
17853
+ familySummary,
17854
+ pair,
17855
+ selectedBackground
17856
+ }) {
17857
+ const previewForeground = pair?.foreground.hex ?? getReadableTextColor2(selectedBackground.tone);
17858
+ const isRecommended = pair ? pair.id === bestPair?.id : false;
17859
+ const whiteForeground = pair ? isWhiteForegroundPair3(pair) : false;
17860
+ const statusLabel = pair ? pair.passes.aaaText ? "Pass" : pair.passes.aaaLarge ? "Large text only" : "Example only" : "No recommendation";
17861
+ const fauxButtonStyle = pair ? {
17862
+ "--btn-bg": pair.foreground.hex,
17863
+ "--btn-border": pair.foreground.hex,
17864
+ "--btn-text": pair.background.hex,
17865
+ "--btn-icon": pair.background.hex,
17866
+ "--btn-hover-overlay": pair.background.hex
17867
+ } : null;
17868
+ return /* @__PURE__ */ jsxRuntime.jsxs(Card, { className: "gap-0 overflow-hidden py-0", children: [
17869
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-b border-grey-200 px-4 py-4 sm:px-6 sm:py-5", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
17870
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
17871
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[0.72rem] font-semibold tracking-[0.12em] text-muted-foreground uppercase", children: "Current result" }),
17872
+ /* @__PURE__ */ jsxRuntime.jsx(Heading, { level: 2, size: 4, className: "text-foreground", trim: "normal", children: pair ? `${getPairingColorDisplayName3(pair.foreground)} on ${getPairingColorDisplayName3(pair.background)}` : `${getPairingColorDisplayName3(selectedBackground)} selected` })
17873
+ ] }),
17874
+ /* @__PURE__ */ jsxRuntime.jsx(Text, { size: 2, className: "max-w-3xl text-grey-700", children: getResultExplanation(pair, bestPair) })
17875
+ ] }) }),
17876
+ /* @__PURE__ */ jsxRuntime.jsx(
17877
+ "div",
17878
+ {
17879
+ className: "p-4 sm:min-h-[26rem] sm:p-8",
17880
+ style: {
17881
+ backgroundColor: selectedBackground.hex,
17882
+ color: previewForeground
17883
+ },
17884
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-h-[18rem] flex-col justify-between gap-6 sm:min-h-[22rem] sm:gap-8", children: [
17885
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
17886
+ /* @__PURE__ */ jsxRuntime.jsxs(
17887
+ "span",
17888
+ {
17889
+ className: "inline-flex items-center gap-2 rounded-full border px-3 py-1 text-[0.68rem] font-semibold tracking-[0.16em] uppercase sm:text-[0.72rem]",
17890
+ style: {
17891
+ borderColor: pair ? pair.foreground.hex : "currentColor",
17892
+ backgroundColor: pair ? pair.foreground.hex : "transparent",
17893
+ color: pair ? pair.background.hex : "currentColor"
17894
+ },
17895
+ children: [
17896
+ /* @__PURE__ */ jsxRuntime.jsx(Icons.palette, { "data-slot": "icon", className: "size-4" }),
17897
+ familySummary
17898
+ ]
17899
+ }
17900
+ ),
17901
+ pair ? /* @__PURE__ */ jsxRuntime.jsxs(
17902
+ "span",
17903
+ {
17904
+ className: "inline-flex rounded-full border px-3 py-1 text-[0.68rem] font-semibold tracking-[0.16em] uppercase sm:text-[0.72rem]",
17905
+ style: {
17906
+ borderColor: pair.foreground.hex
17907
+ },
17908
+ children: [
17909
+ pair.rating,
17910
+ " ",
17911
+ pair.contrastRatio.toFixed(2),
17912
+ ":1"
17913
+ ]
17914
+ }
17915
+ ) : null
17916
+ ] }),
17917
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "max-w-xl space-y-4 pb-8 sm:pb-16", children: [
17918
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-semibold tracking-[0.22em] uppercase", children: pair ? whiteForeground && !isRecommended ? "White on colour example" : whiteForeground ? "White on colour" : "Colour on colour" : "Approved background" }),
17919
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
17920
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "max-w-lg text-3xl leading-tight font-bold text-current sm:text-5xl sm:leading-none", children: "Pair colour with confidence." }),
17921
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "max-w-full text-base/6 sm:max-w-md sm:text-base/7", children: pair ? getPreviewGuidance3(pair, isRecommended) : "This approved background tone does not currently have a recommended AAA foreground in this tool. Choose another approved background tone to continue." }),
17922
+ pair && fauxButtonStyle ? /* @__PURE__ */ jsxRuntime.jsx(
17923
+ "span",
17924
+ {
17925
+ "aria-hidden": "true",
17926
+ "data-variant": "solid",
17927
+ className: cn(
17928
+ buttonVariants({ variant: "solid", size: "default" }),
17929
+ "pointer-events-none cursor-default px-6 text-[16px] font-[700] select-none sm:px-6 sm:text-[16px] sm:font-[700]"
17930
+ ),
17931
+ style: fauxButtonStyle,
17932
+ children: "Get started"
17933
+ }
17934
+ ) : null
17935
+ ] })
17936
+ ] }),
17937
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-3", children: [
17938
+ /* @__PURE__ */ jsxRuntime.jsxs(
17939
+ "span",
17940
+ {
17941
+ className: "inline-flex items-center gap-2 rounded-full px-4 py-2 text-sm font-semibold",
17942
+ style: pair ? {
17943
+ backgroundColor: pair.foreground.hex,
17944
+ color: pair.background.hex
17945
+ } : {
17946
+ backgroundColor: "rgb(255 255 255 / 0.14)",
17947
+ color: "currentColor"
17948
+ },
17949
+ children: [
17950
+ statusLabel,
17951
+ pair && pair.passes.aaaText ? /* @__PURE__ */ jsxRuntime.jsx(Icons.check, { "data-slot": "icon", className: "size-4" }) : /* @__PURE__ */ jsxRuntime.jsx(Icons.info, { "data-slot": "icon", className: "size-4" })
17952
+ ]
17953
+ }
17954
+ ),
17955
+ /* @__PURE__ */ jsxRuntime.jsx(
17956
+ "span",
17957
+ {
17958
+ className: "inline-flex max-w-full rounded-full border px-4 py-2 text-[0.82rem] break-all sm:text-sm",
17959
+ style: {
17960
+ borderColor: pair ? pair.foreground.hex : "currentColor"
17961
+ },
17962
+ children: pair ? `${pair.background.token} / ${pair.foreground.token}` : selectedBackground.token
17963
+ }
17964
+ )
17965
+ ] })
17966
+ ] })
17967
+ }
17968
+ ),
17969
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-5 border-t border-grey-200 bg-grey-50 px-4 py-5 sm:px-6 sm:py-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-4 lg:grid-cols-2", children: [
17970
+ /* @__PURE__ */ jsxRuntime.jsx(ResultSummaryTile, { label: "Background", children: /* @__PURE__ */ jsxRuntime.jsx(ResultColorSummary, { color: selectedBackground }) }),
17971
+ /* @__PURE__ */ jsxRuntime.jsx(ResultSummaryTile, { label: "Foreground", children: /* @__PURE__ */ jsxRuntime.jsx(
17972
+ ResultColorSummary,
17973
+ {
17974
+ color: pair?.foreground,
17975
+ fallbackLabel: "No AAA foreground available"
17976
+ }
17977
+ ) }),
17978
+ /* @__PURE__ */ jsxRuntime.jsxs(ResultSummaryTile, { label: "Contrast ratio", className: "lg:col-span-2", children: [
17979
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-4xl leading-none font-bold text-foreground", children: pair ? `${pair.contrastRatio.toFixed(2)}:1` : "N/A" }),
17980
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: pair ? pair.passes.aaaText ? "Meets AAA accessibility" : pair.passes.aaaLarge ? "Meets AAA for large text only" : "Does not meet accessibility requirements" : "Does not meet accessibility requirements" })
17981
+ ] }),
17982
+ /* @__PURE__ */ jsxRuntime.jsx(
17983
+ AccessibilityCheckTile,
17984
+ {
17985
+ className: "lg:col-span-2",
17986
+ label: "AAA normal text",
17987
+ passes: pair ? pair.passes.aaaText : null,
17988
+ threshold: AAA_NORMAL_TEXT_THRESHOLD2
17989
+ }
17990
+ ),
17991
+ /* @__PURE__ */ jsxRuntime.jsx(
17992
+ AccessibilityCheckTile,
17993
+ {
17994
+ className: "lg:col-span-2",
17995
+ label: "AAA large text",
17996
+ passes: pair ? pair.passes.aaaLarge : null,
17997
+ threshold: AAA_LARGE_TEXT_THRESHOLD2
17998
+ }
17999
+ )
18000
+ ] }) })
18001
+ ] });
18002
+ }
18003
+ function BestRecommendationCard({
18004
+ copiedKey,
18005
+ isCurrentSelection,
18006
+ onCopyPairing,
18007
+ onUsePairing,
18008
+ pair,
18009
+ reason
18010
+ }) {
18011
+ return /* @__PURE__ */ jsxRuntime.jsxs(Card, { className: "gap-5 border-primary-200 bg-primary-50/60 px-6 py-6", children: [
18012
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-5", children: [
18013
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
18014
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
18015
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-2 rounded-sm bg-primary-800 px-3 py-1 text-[0.72rem] font-semibold tracking-[0.12em] text-white uppercase", children: [
18016
+ /* @__PURE__ */ jsxRuntime.jsx(Icons.check_circle, { "data-slot": "icon", className: "size-4" }),
18017
+ "Best recommended pairing"
18018
+ ] }),
18019
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex rounded-sm border border-primary-300 px-3 py-1 text-[0.72rem] font-semibold tracking-[0.12em] text-primary-900 uppercase", children: [
18020
+ pair.contrastRatio.toFixed(2),
18021
+ ":1"
18022
+ ] })
18023
+ ] }),
18024
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
18025
+ /* @__PURE__ */ jsxRuntime.jsxs(Heading, { level: 2, size: 5, className: "text-foreground", trim: "normal", children: [
18026
+ pair.background.token,
18027
+ " / ",
18028
+ pair.foreground.token
18029
+ ] }),
18030
+ /* @__PURE__ */ jsxRuntime.jsx(Text, { size: 2, className: "max-w-3xl text-grey-700", children: reason })
18031
+ ] })
18032
+ ] }),
18033
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3 sm:flex-row sm:flex-wrap sm:items-center", children: [
18034
+ isCurrentSelection ? null : /* @__PURE__ */ jsxRuntime.jsx(
18035
+ Button2,
18036
+ {
18037
+ className: "w-full justify-center sm:w-auto sm:min-w-56",
18038
+ color: "primary",
18039
+ onClick: onUsePairing,
18040
+ "aria-label": `Use ${pair.foreground.token} on ${pair.background.token}`,
18041
+ children: "Use best recommendation"
18042
+ }
18043
+ ),
18044
+ /* @__PURE__ */ jsxRuntime.jsxs(
18045
+ Button2,
18046
+ {
18047
+ className: "w-full justify-center sm:w-auto sm:min-w-48",
18048
+ variant: "outline",
18049
+ color: "grey",
18050
+ onClick: onCopyPairing,
18051
+ children: [
18052
+ /* @__PURE__ */ jsxRuntime.jsx(Icons.content_copy, { "data-slot": "icon", className: "size-5" }),
18053
+ copiedKey === "best-pairing" ? "Pairing copied" : "Copy pairing"
18054
+ ]
18055
+ }
18056
+ )
18057
+ ] })
18058
+ ] }),
18059
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-4 md:grid-cols-2", children: [
18060
+ /* @__PURE__ */ jsxRuntime.jsx(ResultSummaryTile, { label: "Background", children: /* @__PURE__ */ jsxRuntime.jsx(ResultColorSummary, { color: pair.background }) }),
18061
+ /* @__PURE__ */ jsxRuntime.jsx(ResultSummaryTile, { label: "Foreground", children: /* @__PURE__ */ jsxRuntime.jsx(ResultColorSummary, { color: pair.foreground }) }),
18062
+ /* @__PURE__ */ jsxRuntime.jsxs(ResultSummaryTile, { label: "Accessibility", className: "md:col-span-2", children: [
18063
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xl leading-8 font-semibold text-foreground", children: "Meets AAA accessibility" }),
18064
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-3 text-base/7 text-muted-foreground", children: "Best NSW default for this background." })
18065
+ ] })
18066
+ ] })
18067
+ ] });
18068
+ }
18069
+ function RecommendationCard({
18070
+ copiedKey,
18071
+ isSelected,
18072
+ item,
18073
+ onCopyPairing,
18074
+ onSelect
18075
+ }) {
18076
+ const { pair } = item;
18077
+ return /* @__PURE__ */ jsxRuntime.jsxs(
18078
+ "div",
18079
+ {
18080
+ className: cn(
18081
+ "relative rounded-sm border bg-white p-4 text-left transition-colors focus-visible:ring-2 focus-visible:ring-primary-700 focus-visible:ring-offset-2 focus-visible:outline-hidden",
18082
+ isSelected ? "border-primary-800 bg-primary-50/50" : "border-grey-200 hover:border-primary-500 hover:bg-grey-50"
18083
+ ),
18084
+ children: [
18085
+ /* @__PURE__ */ jsxRuntime.jsx(
18086
+ "button",
18087
+ {
18088
+ type: "button",
18089
+ "aria-pressed": isSelected,
18090
+ "aria-label": `Use ${pair.foreground.token} on ${pair.background.token}`,
18091
+ onClick: onSelect,
18092
+ className: "absolute inset-0 rounded-sm focus-visible:ring-2 focus-visible:ring-primary-700 focus-visible:ring-offset-2 focus-visible:outline-hidden"
18093
+ }
18094
+ ),
18095
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pointer-events-none relative z-10", children: [
18096
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-start gap-3 sm:flex-row sm:items-start sm:justify-between", children: [
18097
+ /* @__PURE__ */ jsxRuntime.jsxs(
18098
+ "span",
18099
+ {
18100
+ className: cn(
18101
+ "inline-flex items-center gap-2 rounded-sm px-2.5 py-1 text-[0.68rem] font-semibold tracking-[0.12em] uppercase",
18102
+ item.category === "best" ? "bg-primary-800 text-white" : "border border-grey-300 bg-grey-50 text-foreground"
18103
+ ),
18104
+ children: [
18105
+ item.category === "best" ? /* @__PURE__ */ jsxRuntime.jsx(Icons.check_circle, { "data-slot": "icon", className: "size-4" }) : /* @__PURE__ */ jsxRuntime.jsx(Icons.info, { "data-slot": "icon", className: "size-4" }),
18106
+ item.categoryLabel
18107
+ ]
18108
+ }
18109
+ ),
18110
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pointer-events-auto shrink-0 self-start", children: /* @__PURE__ */ jsxRuntime.jsxs(
18111
+ Button2,
18112
+ {
18113
+ variant: "ghost",
18114
+ color: "grey",
18115
+ size: "sm",
18116
+ onClick: onCopyPairing,
18117
+ "aria-label": `Copy pairing ${pair.background.token} and ${pair.foreground.token}`,
18118
+ children: [
18119
+ /* @__PURE__ */ jsxRuntime.jsx(Icons.content_copy, { "data-slot": "icon", className: "size-5" }),
18120
+ copiedKey === `pair:${pair.id}` ? "Copied" : "Copy"
18121
+ ]
18122
+ }
18123
+ ) })
18124
+ ] }),
18125
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-4", children: [
18126
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-4 sm:grid-cols-[4rem_minmax(0,1fr)]", children: [
18127
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "overflow-hidden rounded-[2px] border border-black/10", children: [
18128
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-16 w-full", style: { backgroundColor: pair.background.hex } }),
18129
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-4 w-full", style: { backgroundColor: pair.foreground.hex } })
18130
+ ] }),
18131
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 space-y-2", children: [
18132
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
18133
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-base font-semibold text-foreground", children: getPairingColorDisplayName3(pair.foreground) }),
18134
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 font-mono text-[0.74rem] break-all text-muted-foreground", children: pair.foreground.token })
18135
+ ] }),
18136
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm text-muted-foreground", children: [
18137
+ pair.foreground.familyLabel,
18138
+ " on ",
18139
+ pair.background.familyLabel
18140
+ ] })
18141
+ ] })
18142
+ ] }),
18143
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-4 flex flex-col items-start gap-3 sm:flex-row sm:flex-wrap sm:items-center sm:justify-between", children: [
18144
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
18145
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex rounded-sm border border-grey-300 px-2.5 py-1 text-sm font-semibold text-foreground", children: [
18146
+ pair.contrastRatio.toFixed(2),
18147
+ ":1"
18148
+ ] }),
18149
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex rounded-sm bg-success-700 px-2.5 py-1 text-[0.72rem] font-semibold tracking-[0.12em] text-white uppercase", children: "AAA" })
18150
+ ] }),
18151
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-semibold text-primary-800", children: isSelected ? "Selected" : "Use pairing" })
18152
+ ] })
18153
+ ] })
18154
+ ] })
18155
+ ]
18156
+ }
18157
+ );
18158
+ }
18159
+ function TechnicalDetailsPanel({
18160
+ color: color2,
18161
+ copiedKey,
18162
+ onCopyValue,
18163
+ title,
18164
+ visibleFormats
18165
+ }) {
18166
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-sm border border-grey-200 bg-white", children: [
18167
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-b border-grey-200 px-4 py-4 sm:px-5", children: [
18168
+ /* @__PURE__ */ jsxRuntime.jsx(Heading, { level: 3, size: 6, className: "text-foreground", trim: "normal", children: title }),
18169
+ color2 ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
18170
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: getPairingColorDisplayName3(color2) }),
18171
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-4 overflow-hidden rounded-sm border border-black/10 bg-white", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-20 w-full sm:h-24", style: { backgroundColor: color2.hex } }) })
18172
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: "No AAA foreground available." })
18173
+ ] }),
18174
+ color2 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "divide-y divide-grey-200", children: formatValueRows(color2, visibleFormats).map((row) => {
18175
+ const copyKey = `${title}-${row.key}`;
18176
+ return /* @__PURE__ */ jsxRuntime.jsxs(
18177
+ "div",
18178
+ {
18179
+ className: "flex flex-col items-start gap-3 px-4 py-4 sm:flex-row sm:items-start sm:justify-between sm:gap-4 sm:px-5",
18180
+ children: [
18181
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
18182
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[0.72rem] font-semibold tracking-[0.12em] text-muted-foreground uppercase", children: row.label }),
18183
+ /* @__PURE__ */ jsxRuntime.jsx(
18184
+ "p",
18185
+ {
18186
+ className: cn(
18187
+ "mt-2 text-sm text-foreground",
18188
+ row.key !== "tone" && "font-mono break-all"
18189
+ ),
18190
+ children: row.value
18191
+ }
18192
+ )
18193
+ ] }),
18194
+ row.copyable ? /* @__PURE__ */ jsxRuntime.jsx(
18195
+ Button2,
18196
+ {
18197
+ variant: "ghost",
18198
+ color: "grey",
18199
+ size: "sm",
18200
+ className: "self-start",
18201
+ onClick: () => onCopyValue(copyKey, row.value, `${row.label} copied`),
18202
+ "aria-label": `Copy ${title.toLowerCase()} ${row.label.toLowerCase()}`,
18203
+ children: copiedKey === copyKey ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
18204
+ /* @__PURE__ */ jsxRuntime.jsx(Icons.check_circle, { "data-slot": "icon", className: "size-5" }),
18205
+ "Copied"
18206
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
18207
+ /* @__PURE__ */ jsxRuntime.jsx(Icons.content_copy, { "data-slot": "icon", className: "size-5" }),
18208
+ "Copy"
18209
+ ] })
18210
+ }
18211
+ ) : null
18212
+ ]
18213
+ },
18214
+ row.key
18215
+ );
18216
+ }) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-5 py-5", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: "No technical values are shown because there is no AAA-compliant foreground for this background." }) })
18217
+ ] });
18218
+ }
18219
+ function resolveSelectionState(nextThemeCategory, nextPrimaryKey, nextAccentKey, preferredBackgroundToken, preferredPairId) {
18220
+ const context = getPairingContext(nextThemeCategory, nextPrimaryKey, nextAccentKey);
18221
+ const selectedBackgroundToken = resolveBackgroundToken3(
18222
+ context,
18223
+ preferredBackgroundToken,
18224
+ getToneFromToken3(preferredBackgroundToken)
18225
+ );
18226
+ const selectedPairId = getPreferredPairForBackground3(
18227
+ context.pairsByBackground[selectedBackgroundToken] ?? [],
18228
+ preferredPairId
18229
+ )?.id ?? "";
18230
+ return {
18231
+ accentKey: context.accent.key,
18232
+ context,
18233
+ primaryKey: context.primary.key,
18234
+ selectedBackgroundToken,
18235
+ selectedPairId,
18236
+ themeCategory: nextThemeCategory
18237
+ };
18238
+ }
18239
+ function ColorPairingToolV3Loading() {
18240
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-8 xl:grid-cols-[minmax(18rem,24rem)_minmax(0,1fr)]", children: [
18241
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-6", children: [
18242
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-52 rounded-sm border border-grey-200 bg-grey-50" }),
18243
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-[32rem] rounded-sm border border-grey-200 bg-grey-50" })
18244
+ ] }),
18245
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-6", children: [
18246
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-96 rounded-sm border border-grey-200 bg-grey-50" }),
18247
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-64 rounded-sm border border-grey-200 bg-grey-50" }),
18248
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-72 rounded-sm border border-grey-200 bg-grey-50" })
18249
+ ] })
18250
+ ] });
18251
+ }
18252
+ function ColorPairingToolV3Content({
18253
+ onAnalyticsEvent,
18254
+ visibleFormats
18255
+ }) {
18256
+ const searchParams = navigation.useSearchParams();
18257
+ const stickyOffset = useStickyOffset(24);
18258
+ const [initialState] = React5.useState(() => getInitialPairingState3(searchParams));
18259
+ const [themeCategory, setThemeCategory] = React5.useState(initialState.themeCategory);
18260
+ const [primaryFamilyKey, setPrimaryFamilyKey] = React5.useState(initialState.primaryKey);
18261
+ const [accentFamilyKey, setAccentFamilyKey] = React5.useState(initialState.accentKey);
18262
+ const [selectedBackgroundToken, setSelectedBackgroundToken] = React5.useState(
18263
+ initialState.selectedBackgroundToken
18264
+ );
18265
+ const [selectedPairId, setSelectedPairId] = React5.useState(initialState.selectedPairId);
18266
+ const [drawerStepIndex, setDrawerStepIndex] = React5.useState(0);
18267
+ const [isCompactControlsOpen, setIsCompactControlsOpen] = React5.useState(false);
18268
+ const [, copyToClipboardRaw] = usehooks.useCopyToClipboard();
18269
+ const [copiedKey, setCopiedKey] = React5.useState(null);
18270
+ const copiedKeyTimeoutRef = React5.useRef(null);
18271
+ const resultSectionRef = React5.useRef(null);
18272
+ const technicalDetailsSectionRef = React5.useRef(null);
18273
+ const noValidStateRef = React5.useRef(/* @__PURE__ */ new Set());
18274
+ const technicalDetailsViewedRef = React5.useRef(false);
18275
+ const emitAnalyticsEvent = React5.useCallback(
18276
+ (event) => {
18277
+ onAnalyticsEvent(event);
18278
+ if (typeof window !== "undefined") {
18279
+ window.dispatchEvent(
18280
+ new CustomEvent(COLOR_PAIRING_TOOL_V3_ANALYTICS_EVENT, {
18281
+ detail: event
18282
+ })
18283
+ );
18284
+ }
18285
+ },
18286
+ [onAnalyticsEvent]
18287
+ );
18288
+ React5.useEffect(() => {
18289
+ return () => {
18290
+ if (copiedKeyTimeoutRef.current) {
18291
+ clearTimeout(copiedKeyTimeoutRef.current);
18292
+ }
18293
+ };
18294
+ }, []);
18295
+ React5.useEffect(() => {
18296
+ if (typeof window === "undefined") {
18297
+ return;
18298
+ }
18299
+ const mediaQuery = window.matchMedia(PERSISTENT_DRAWER_MIN_WIDTH_QUERY);
18300
+ const handleChange = (event) => {
18301
+ if (event?.matches ?? mediaQuery.matches) {
18302
+ setIsCompactControlsOpen(false);
18303
+ }
18304
+ };
18305
+ handleChange();
18306
+ mediaQuery.addEventListener("change", handleChange);
18307
+ return () => {
18308
+ mediaQuery.removeEventListener("change", handleChange);
18309
+ };
18310
+ }, []);
18311
+ const themeFamilies = React5.useMemo(() => getPairingFamilies(themeCategory), [themeCategory]);
18312
+ const context = React5.useMemo(
18313
+ () => getPairingContext(themeCategory, primaryFamilyKey, accentFamilyKey),
18314
+ [themeCategory, primaryFamilyKey, accentFamilyKey]
18315
+ );
18316
+ const selectableFamilies = React5.useMemo(
18317
+ () => themeFamilies.filter((family) => family.key !== context.grey.key),
18318
+ [themeFamilies, context.grey.key]
18319
+ );
18320
+ const selectableAccentFamilies = React5.useMemo(
18321
+ () => selectableFamilies.filter((family) => family.key !== context.primary.key),
18322
+ [selectableFamilies, context.primary.key]
18323
+ );
18324
+ const selectedBackground = React5.useMemo(
18325
+ () => context.backgrounds.find((background) => background.token === selectedBackgroundToken) ?? context.backgrounds[0] ?? null,
18326
+ [context.backgrounds, selectedBackgroundToken]
18327
+ );
18328
+ const selectedBackgroundPairs = React5.useMemo(
18329
+ () => selectedBackground ? context.pairsByBackground[selectedBackground.token] ?? [] : [],
18330
+ [context.pairsByBackground, selectedBackground]
18331
+ );
18332
+ const bestRecommendedPair = React5.useMemo(
18333
+ () => getPreferredPairForBackground3(selectedBackgroundPairs),
18334
+ [selectedBackgroundPairs]
18335
+ );
18336
+ const selectedPair = React5.useMemo(
18337
+ () => getPreferredPairForBackground3(selectedBackgroundPairs, selectedPairId),
18338
+ [selectedBackgroundPairs, selectedPairId]
18339
+ );
18340
+ const whiteForegroundExample = React5.useMemo(
18341
+ () => selectedBackground && supportsWhiteForegroundPreview(selectedBackground) ? getWhiteForegroundPair(selectedBackground) : null,
18342
+ [selectedBackground]
18343
+ );
18344
+ const previewPair = selectedPair ?? whiteForegroundExample ?? null;
18345
+ const detailForeground = selectedPair?.foreground ?? whiteForegroundExample?.foreground ?? null;
18346
+ const familySummary = React5.useMemo(
18347
+ () => [context.primary.label, context.accent.label, context.grey.label].join(" + "),
18348
+ [context.accent.label, context.grey.label, context.primary.label]
18349
+ );
18350
+ const recommendationItems = React5.useMemo(() => {
18351
+ return selectedBackgroundPairs.map((pair) => {
18352
+ const category = getRecommendationCategory(pair, bestRecommendedPair, context);
18353
+ return {
18354
+ category,
18355
+ categoryLabel: getRecommendationCategoryLabel(category),
18356
+ pair
18357
+ };
18358
+ }).sort(
18359
+ (left, right) => getRecommendationSortRank(left.category) - getRecommendationSortRank(right.category)
18360
+ );
18361
+ }, [bestRecommendedPair, context, selectedBackgroundPairs]);
18362
+ const liveAnnouncement = React5.useMemo(
18363
+ () => getLiveAnnouncement(previewPair, selectedBackground),
18364
+ [previewPair, selectedBackground]
18365
+ );
18366
+ const shareBackgroundToken = selectedBackground?.token ?? selectedBackgroundToken;
18367
+ const shareUrl = React5.useMemo(() => {
18368
+ const params = new URLSearchParams();
18369
+ params.set("palette", themeCategory);
18370
+ params.set("primary", context.primary.key);
18371
+ params.set("accent", context.accent.key);
18372
+ if (shareBackgroundToken) {
18373
+ params.set("background", shareBackgroundToken);
18374
+ }
18375
+ if (selectedPairId) {
18376
+ params.set("pair", selectedPairId);
18377
+ }
18378
+ const query = params.toString();
18379
+ return `${COLOR_PAIRING_TOOL_V3_PATH}${query ? `?${query}` : ""}`;
18380
+ }, [context.accent.key, context.primary.key, shareBackgroundToken, selectedPairId, themeCategory]);
18381
+ const activeDrawerStep = COLOR_PAIRING_TOOL_DRAWER_STEPS[drawerStepIndex];
18382
+ const isFirstDrawerStep = drawerStepIndex === 0;
18383
+ const isLastDrawerStep = drawerStepIndex === COLOR_PAIRING_TOOL_DRAWER_STEPS.length - 1;
18384
+ const desktopSidebarStyle = React5.useMemo(
18385
+ () => ({
18386
+ "--tool-sidebar-max-height": `calc(100vh - ${stickyOffset}px)`,
18387
+ "--tool-sidebar-top": `${stickyOffset}px`
18388
+ }),
18389
+ [stickyOffset]
18390
+ );
18391
+ const goToDrawerStep = React5.useCallback((stepIndex) => {
18392
+ setDrawerStepIndex(Math.max(0, Math.min(stepIndex, COLOR_PAIRING_TOOL_DRAWER_STEPS.length - 1)));
18393
+ }, []);
18394
+ const goToNextDrawerStep = React5.useCallback(() => {
18395
+ setDrawerStepIndex(
18396
+ (currentStep) => Math.min(currentStep + 1, COLOR_PAIRING_TOOL_DRAWER_STEPS.length - 1)
18397
+ );
18398
+ }, []);
18399
+ const goToPreviousDrawerStep = React5.useCallback(() => {
18400
+ setDrawerStepIndex((currentStep) => Math.max(currentStep - 1, 0));
18401
+ }, []);
18402
+ const updateUrlParams = React5.useCallback((nextState) => {
18403
+ const params = new URLSearchParams(window.location.search);
18404
+ params.delete("family");
18405
+ params.set("palette", nextState.themeCategory);
18406
+ params.set("primary", nextState.primaryKey);
18407
+ params.set("accent", nextState.accentKey);
18408
+ params.set("background", nextState.selectedBackgroundToken);
18409
+ if (nextState.selectedPairId) {
18410
+ params.set("pair", nextState.selectedPairId);
18411
+ } else {
18412
+ params.delete("pair");
18413
+ }
18414
+ window.history.replaceState(
18415
+ null,
18416
+ "",
18417
+ `${window.location.pathname}?${params.toString()}${window.location.hash}`
18418
+ );
18419
+ }, []);
18420
+ const applyResolvedSelection = React5.useCallback(
18421
+ (nextState) => {
18422
+ setThemeCategory(nextState.themeCategory);
18423
+ setPrimaryFamilyKey(nextState.primaryKey);
18424
+ setAccentFamilyKey(nextState.accentKey);
18425
+ setSelectedBackgroundToken(nextState.selectedBackgroundToken);
18426
+ setSelectedPairId(nextState.selectedPairId);
18427
+ updateUrlParams(nextState);
18428
+ },
18429
+ [updateUrlParams]
18430
+ );
18431
+ const buildAnalyticsContext = React5.useCallback(
18432
+ (overrides) => ({
18433
+ accentKey: context.accent.key,
18434
+ backgroundToken: selectedBackground?.token,
18435
+ foregroundToken: selectedPair?.foreground.token,
18436
+ pairId: selectedPair?.id,
18437
+ palette: themeCategory,
18438
+ primaryKey: context.primary.key,
18439
+ ...overrides
18440
+ }),
18441
+ [context.accent.key, context.primary.key, selectedBackground, selectedPair, themeCategory]
18442
+ );
18443
+ const copyValue = React5.useCallback(
18444
+ (copyKey, value, toastLabel, analyticsEvent) => {
18445
+ copyToClipboardRaw(value);
18446
+ setCopiedKey(copyKey);
18447
+ sonner.toast(toastLabel, { duration: 2e3 });
18448
+ if (analyticsEvent) {
18449
+ emitAnalyticsEvent(analyticsEvent);
18450
+ }
18451
+ if (copiedKeyTimeoutRef.current) {
18452
+ clearTimeout(copiedKeyTimeoutRef.current);
18453
+ }
18454
+ copiedKeyTimeoutRef.current = setTimeout(() => {
18455
+ setCopiedKey(null);
18456
+ copiedKeyTimeoutRef.current = null;
18457
+ }, 2e3);
18458
+ },
18459
+ [copyToClipboardRaw, emitAnalyticsEvent]
18460
+ );
18461
+ const handleThemeCategoryChange = (nextThemeCategory) => {
18462
+ const nextState = resolveSelectionState(
18463
+ nextThemeCategory,
18464
+ primaryFamilyKey,
18465
+ accentFamilyKey,
18466
+ selectedBackgroundToken,
18467
+ selectedPairId
18468
+ );
18469
+ applyResolvedSelection(nextState);
18470
+ emitAnalyticsEvent({
18471
+ name: "palette_change",
18472
+ accentKey: nextState.accentKey,
18473
+ backgroundToken: nextState.selectedBackgroundToken,
18474
+ pairId: nextState.selectedPairId,
18475
+ palette: nextState.themeCategory,
18476
+ primaryKey: nextState.primaryKey
18477
+ });
18478
+ };
18479
+ const handlePrimaryColorChange = (nextPrimaryKey) => {
18480
+ const nextAccentKey = nextPrimaryKey === accentFamilyKey ? getDefaultAccentFamilyKey(themeCategory, nextPrimaryKey) : accentFamilyKey;
18481
+ const nextState = resolveSelectionState(
18482
+ themeCategory,
18483
+ nextPrimaryKey,
18484
+ nextAccentKey,
18485
+ selectedBackgroundToken,
18486
+ selectedPairId
18487
+ );
18488
+ applyResolvedSelection(nextState);
18489
+ emitAnalyticsEvent({
18490
+ name: "primary_change",
18491
+ accentKey: nextState.accentKey,
18492
+ backgroundToken: nextState.selectedBackgroundToken,
18493
+ pairId: nextState.selectedPairId,
18494
+ palette: nextState.themeCategory,
18495
+ primaryKey: nextState.primaryKey
18496
+ });
18497
+ };
18498
+ const handleAccentColorChange = (nextAccentKey) => {
18499
+ if (nextAccentKey === primaryFamilyKey) return;
18500
+ const nextState = resolveSelectionState(
18501
+ themeCategory,
18502
+ primaryFamilyKey,
18503
+ nextAccentKey,
18504
+ selectedBackgroundToken,
18505
+ selectedPairId
18506
+ );
18507
+ applyResolvedSelection(nextState);
18508
+ emitAnalyticsEvent({
18509
+ name: "accent_change",
18510
+ accentKey: nextState.accentKey,
18511
+ backgroundToken: nextState.selectedBackgroundToken,
18512
+ pairId: nextState.selectedPairId,
18513
+ palette: nextState.themeCategory,
18514
+ primaryKey: nextState.primaryKey
18515
+ });
18516
+ };
18517
+ const handleBackgroundChange = (nextSelectedBackgroundToken) => {
18518
+ const nextSelectedPairId = getPreferredPairForBackground3(
18519
+ context.pairsByBackground[nextSelectedBackgroundToken] ?? [],
18520
+ selectedPairId
18521
+ )?.id ?? "";
18522
+ const nextState = {
18523
+ accentKey: context.accent.key,
18524
+ context,
18525
+ primaryKey: context.primary.key,
18526
+ selectedBackgroundToken: nextSelectedBackgroundToken,
18527
+ selectedPairId: nextSelectedPairId,
18528
+ themeCategory
18529
+ };
18530
+ applyResolvedSelection(nextState);
18531
+ emitAnalyticsEvent({
18532
+ name: "background_selection",
18533
+ ...buildAnalyticsContext({
18534
+ backgroundToken: nextSelectedBackgroundToken,
18535
+ foregroundToken: context.pairsByBackground[nextSelectedBackgroundToken]?.find(
18536
+ (pair) => pair.id === nextSelectedPairId
18537
+ )?.foreground.token,
18538
+ pairId: nextSelectedPairId
18539
+ })
18540
+ });
18541
+ if (typeof window !== "undefined" && window.matchMedia(MOBILE_RESULT_SCROLL_QUERY).matches) {
18542
+ requestAnimationFrame(() => {
18543
+ resultSectionRef.current?.scrollIntoView({ behavior: "smooth", block: "start" });
18544
+ });
18545
+ }
18546
+ };
18547
+ const handlePairChange = (nextSelectedPairId, source) => {
18548
+ if (!selectedBackground) return;
18549
+ const nextPair = selectedBackgroundPairs.find((pair) => pair.id === nextSelectedPairId) ?? null;
18550
+ setSelectedPairId(nextSelectedPairId);
18551
+ updateUrlParams({
18552
+ accentKey: context.accent.key,
18553
+ context,
18554
+ primaryKey: context.primary.key,
18555
+ selectedBackgroundToken: selectedBackground.token,
18556
+ selectedPairId: nextSelectedPairId,
18557
+ themeCategory
18558
+ });
18559
+ emitAnalyticsEvent({
18560
+ name: "foreground_selection",
18561
+ ...buildAnalyticsContext({
18562
+ foregroundToken: nextPair?.foreground.token,
18563
+ pairId: nextSelectedPairId,
18564
+ source
18565
+ })
18566
+ });
18567
+ if (bestRecommendedPair && nextSelectedPairId !== bestRecommendedPair.id) {
18568
+ emitAnalyticsEvent({
18569
+ name: "alternative_combination_selected",
18570
+ ...buildAnalyticsContext({
18571
+ foregroundToken: nextPair?.foreground.token,
18572
+ pairId: nextSelectedPairId,
18573
+ source
18574
+ })
18575
+ });
18576
+ }
18577
+ };
18578
+ React5.useEffect(() => {
18579
+ if (!selectedBackground || selectedBackgroundPairs.length > 0) {
18580
+ return;
18581
+ }
18582
+ const key = `${themeCategory}:${context.primary.key}:${context.accent.key}:${selectedBackground.token}`;
18583
+ if (noValidStateRef.current.has(key)) {
18584
+ return;
18585
+ }
18586
+ noValidStateRef.current.add(key);
18587
+ emitAnalyticsEvent({
18588
+ name: "no_valid_combination_state",
18589
+ ...buildAnalyticsContext({
18590
+ backgroundToken: selectedBackground.token
18591
+ })
18592
+ });
18593
+ }, [
18594
+ buildAnalyticsContext,
18595
+ context.accent.key,
18596
+ context.primary.key,
18597
+ emitAnalyticsEvent,
18598
+ selectedBackground,
18599
+ selectedBackgroundPairs.length,
18600
+ themeCategory
18601
+ ]);
18602
+ React5.useEffect(() => {
18603
+ if (technicalDetailsViewedRef.current) {
18604
+ return;
18605
+ }
18606
+ const section = technicalDetailsSectionRef.current;
18607
+ if (!section) {
18608
+ return;
18609
+ }
18610
+ const emitViewedEvent = () => {
18611
+ if (technicalDetailsViewedRef.current) {
18612
+ return;
18613
+ }
18614
+ technicalDetailsViewedRef.current = true;
18615
+ emitAnalyticsEvent({
18616
+ name: "technical_details_viewed",
18617
+ ...buildAnalyticsContext({
18618
+ source: "details"
18619
+ })
18620
+ });
18621
+ };
18622
+ if (typeof IntersectionObserver === "undefined") {
18623
+ const rect = section.getBoundingClientRect();
18624
+ const viewportHeight = window.innerHeight || document.documentElement.clientHeight;
18625
+ if (rect.top < viewportHeight && rect.bottom > 0) {
18626
+ emitViewedEvent();
18627
+ }
18628
+ return;
18629
+ }
18630
+ const observer = new IntersectionObserver(
18631
+ (entries) => {
18632
+ const [entry] = entries;
18633
+ if (entry?.isIntersecting) {
18634
+ emitViewedEvent();
18635
+ observer.disconnect();
18636
+ }
18637
+ },
18638
+ {
18639
+ threshold: 0.2
18640
+ }
18641
+ );
18642
+ observer.observe(section);
18643
+ return () => {
18644
+ observer.disconnect();
18645
+ };
18646
+ }, [buildAnalyticsContext, emitAnalyticsEvent]);
18647
+ if (!selectedBackground) {
18648
+ return /* @__PURE__ */ jsxRuntime.jsxs(Card, { className: "px-6 py-6", children: [
18649
+ /* @__PURE__ */ jsxRuntime.jsx(Heading, { level: 2, size: 5, className: "text-foreground", trim: "normal", children: "No approved background tones available" }),
18650
+ /* @__PURE__ */ jsxRuntime.jsx(Text, { size: 2, className: "mt-3", children: "No approved tones are available for the current palette and colour selection." })
18651
+ ] });
18652
+ }
18653
+ const compactControlsSummary = `${themeCategory === "brand" ? "Brand" : "Aboriginal"} palette, ${context.primary.label} primary, ${context.accent.label} accent, ${getPairingColorDisplayName3(
18654
+ selectedBackground
18655
+ )} background.`;
18656
+ const renderControlsPanel = (isOverlay = false) => /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
18657
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-b border-grey-200 px-5 py-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-4", children: [
18658
+ /* @__PURE__ */ jsxRuntime.jsx(Heading, { level: 2, size: 5, className: "text-foreground", trim: "normal", children: "Configuration" }),
18659
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
18660
+ !isFirstDrawerStep ? /* @__PURE__ */ jsxRuntime.jsxs(Button2, { variant: "ghost", color: "grey", size: "sm", onClick: goToPreviousDrawerStep, children: [
18661
+ /* @__PURE__ */ jsxRuntime.jsx(Icons.west, { "data-slot": "icon", className: "size-5" }),
18662
+ "Back"
18663
+ ] }) : null,
18664
+ isOverlay ? /* @__PURE__ */ jsxRuntime.jsx(
18665
+ Button2,
18666
+ {
18667
+ variant: "ghost",
18668
+ color: "grey",
18669
+ size: "icon",
18670
+ onClick: () => setIsCompactControlsOpen(false),
18671
+ "aria-label": "Close configuration",
18672
+ children: /* @__PURE__ */ jsxRuntime.jsx(Icons.close, { "data-slot": "icon", className: "size-5" })
18673
+ }
18674
+ ) : null
18675
+ ] })
18676
+ ] }) }),
18677
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-b border-grey-200 px-5 py-4", children: [
18678
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
18679
+ COLOR_PAIRING_TOOL_DRAWER_STEPS.map((step, index) => /* @__PURE__ */ jsxRuntime.jsx(
18680
+ "button",
18681
+ {
18682
+ type: "button",
18683
+ "aria-current": index === drawerStepIndex ? "step" : void 0,
18684
+ "aria-label": `${step.eyebrow}: ${step.title}`,
18685
+ onClick: () => goToDrawerStep(index),
18686
+ className: "flex-1 rounded-sm focus-visible:ring-2 focus-visible:ring-primary-700 focus-visible:ring-offset-2 focus-visible:outline-hidden",
18687
+ children: /* @__PURE__ */ jsxRuntime.jsx(
18688
+ "span",
18689
+ {
18690
+ className: cn(
18691
+ "block h-1.5 rounded-full transition-colors",
18692
+ index <= drawerStepIndex ? "bg-primary-800" : "bg-grey-200"
18693
+ )
18694
+ }
18695
+ )
18696
+ },
18697
+ step.id
18698
+ )),
18699
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mt-2 basis-full text-[0.68rem] font-semibold tracking-[0.12em] text-primary-800 uppercase sm:mt-0 sm:ml-2 sm:basis-auto sm:text-[0.72rem]", children: activeDrawerStep.eyebrow })
18700
+ ] }),
18701
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-4 space-y-2", children: [
18702
+ /* @__PURE__ */ jsxRuntime.jsx(Heading, { level: 3, size: 5, className: "text-foreground", trim: "normal", children: activeDrawerStep.title }),
18703
+ /* @__PURE__ */ jsxRuntime.jsx(Text, { size: 2, children: activeDrawerStep.description })
18704
+ ] })
18705
+ ] }),
18706
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative flex-1 overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsxs(
18707
+ "div",
18708
+ {
18709
+ className: "flex h-full transition-transform duration-300 ease-out",
18710
+ style: { transform: `translateX(-${drawerStepIndex * 100}%)` },
18711
+ children: [
18712
+ /* @__PURE__ */ jsxRuntime.jsx("section", { className: "h-full w-full shrink-0 overflow-y-auto px-5 py-5", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-6 pr-1", children: [
18713
+ /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "space-y-3", children: [
18714
+ /* @__PURE__ */ jsxRuntime.jsx(Heading, { level: 4, size: 6, className: "mb-3 text-foreground", trim: "normal", children: "Palette" }),
18715
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 gap-2 sm:grid-cols-2", children: ["brand", "aboriginal"].map((palette) => {
18716
+ const isSelected = themeCategory === palette;
18717
+ const label = palette === "brand" ? "Brand palette" : "Aboriginal palette";
18718
+ return /* @__PURE__ */ jsxRuntime.jsx(
18719
+ SelectorButton,
18720
+ {
18721
+ label,
18722
+ isSelected,
18723
+ onClick: () => handleThemeCategoryChange(palette)
18724
+ },
18725
+ palette
18726
+ );
18727
+ }) })
18728
+ ] }),
18729
+ /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "space-y-3", children: [
18730
+ /* @__PURE__ */ jsxRuntime.jsx(Heading, { level: 4, size: 6, className: "mb-3 text-foreground", trim: "normal", children: "Primary colour family" }),
18731
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 gap-2 sm:grid-cols-2", children: selectableFamilies.map((family) => {
18732
+ const label = getFamilySelectorLabel3(family, themeCategory, "primary colour");
18733
+ return /* @__PURE__ */ jsxRuntime.jsx(
18734
+ SelectorButton,
18735
+ {
18736
+ label,
18737
+ isSelected: family.key === context.primary.key,
18738
+ onClick: () => handlePrimaryColorChange(family.key),
18739
+ swatch: getFamilySwatchColor3(family, 800)
18740
+ },
18741
+ family.key
18742
+ );
18743
+ }) })
18744
+ ] }),
18745
+ /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "space-y-3", children: [
18746
+ /* @__PURE__ */ jsxRuntime.jsx(Heading, { level: 4, size: 6, className: "mb-3 text-foreground", trim: "normal", children: "Accent colour family" }),
18747
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 gap-2 sm:grid-cols-2", children: selectableAccentFamilies.map((family) => {
18748
+ const label = getFamilySelectorLabel3(family, themeCategory, "accent colour");
18749
+ return /* @__PURE__ */ jsxRuntime.jsx(
18750
+ SelectorButton,
18751
+ {
18752
+ label,
18753
+ isSelected: family.key === context.accent.key,
18754
+ onClick: () => handleAccentColorChange(family.key),
18755
+ swatch: getFamilySwatchColor3(family, 600)
18756
+ },
18757
+ family.key
18758
+ );
18759
+ }) })
18760
+ ] }),
18761
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-t border-grey-200 pt-4", children: [
18762
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-semibold text-foreground", children: "Grey is always included" }),
18763
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: "Neutral grey options are automatically added so every selection includes a practical fallback family." })
18764
+ ] })
18765
+ ] }) }),
18766
+ /* @__PURE__ */ jsxRuntime.jsx("section", { className: "h-full w-full shrink-0 overflow-y-auto px-5 py-5", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-6 pr-1", children: context.backgroundGroups.map((group, index) => /* @__PURE__ */ jsxRuntime.jsxs(
18767
+ "section",
18768
+ {
18769
+ className: cn("space-y-3", index > 0 && "border-t border-grey-200 pt-6"),
18770
+ children: [
18771
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
18772
+ /* @__PURE__ */ jsxRuntime.jsxs(Heading, { level: 4, size: 6, className: "text-foreground", trim: "normal", children: [
18773
+ group.family.label,
18774
+ " backgrounds"
18775
+ ] }),
18776
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: group.label })
18777
+ ] }),
18778
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid gap-3", children: group.backgrounds.map((background) => /* @__PURE__ */ jsxRuntime.jsx(
18779
+ BackgroundSwatchButton,
18780
+ {
18781
+ background,
18782
+ hasPairs: (context.pairsByBackground[background.token]?.length ?? 0) > 0,
18783
+ isSelected: selectedBackground.token === background.token,
18784
+ onClick: () => handleBackgroundChange(background.token)
18785
+ },
18786
+ background.token
18787
+ )) })
18788
+ ]
18789
+ },
18790
+ group.key
18791
+ )) }) }),
18792
+ /* @__PURE__ */ jsxRuntime.jsx("section", { className: "h-full w-full shrink-0 overflow-y-auto px-5 py-5", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-4 pr-1", children: recommendationItems.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-3", children: recommendationItems.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
18793
+ RecommendationCard,
18794
+ {
18795
+ copiedKey,
18796
+ item,
18797
+ isSelected: item.pair.id === selectedPair?.id,
18798
+ onCopyPairing: () => copyValue(
18799
+ `pair:${item.pair.id}`,
18800
+ getPairingCopyText(item.pair),
18801
+ "Pairing copied",
18802
+ item.pair.id === bestRecommendedPair?.id ? {
18803
+ name: "best_recommendation_copied",
18804
+ ...buildAnalyticsContext({
18805
+ foregroundToken: item.pair.foreground.token,
18806
+ pairId: item.pair.id,
18807
+ source: "recommendations-list"
18808
+ })
18809
+ } : void 0
18810
+ ),
18811
+ onSelect: () => handlePairChange(item.pair.id, "recommendations-list")
18812
+ },
18813
+ item.pair.id
18814
+ )) }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-sm border border-grey-200 bg-white px-5 py-5", children: [
18815
+ /* @__PURE__ */ jsxRuntime.jsx(Heading, { level: 4, size: 6, className: "text-foreground", trim: "normal", children: "No valid combinations available" }),
18816
+ /* @__PURE__ */ jsxRuntime.jsx(Text, { size: 2, className: "mt-3", children: "No AAA-compliant foreground options are available for this background." })
18817
+ ] }) }) })
18818
+ ]
18819
+ }
18820
+ ) }),
18821
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t border-grey-200 px-5 py-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between", children: [
18822
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-10 flex-1", children: isLastDrawerStep ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: "Select a combination to update the result immediately." }) : null }),
18823
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex w-full items-center gap-2 sm:w-auto sm:flex-none", children: [
18824
+ isOverlay && isLastDrawerStep ? /* @__PURE__ */ jsxRuntime.jsx(
18825
+ Button2,
18826
+ {
18827
+ color: "primary",
18828
+ className: "w-full sm:w-auto sm:min-w-40",
18829
+ onClick: () => setIsCompactControlsOpen(false),
18830
+ children: "Review result"
18831
+ }
18832
+ ) : null,
18833
+ !isLastDrawerStep ? /* @__PURE__ */ jsxRuntime.jsxs(Button2, { color: "primary", className: "w-full sm:w-auto", onClick: goToNextDrawerStep, children: [
18834
+ "Continue",
18835
+ /* @__PURE__ */ jsxRuntime.jsx(Icons.east, { "data-slot": "icon", className: "size-5" })
18836
+ ] }) : null
18837
+ ] })
18838
+ ] }) })
18839
+ ] });
18840
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-8 xl:grid-cols-[minmax(18rem,24rem)_minmax(0,1fr)]", children: [
18841
+ /* @__PURE__ */ jsxRuntime.jsx(
18842
+ "div",
18843
+ {
18844
+ "data-slot": "tool-sidebar",
18845
+ className: "hidden xl:sticky xl:top-[var(--tool-sidebar-top)] xl:block xl:self-start",
18846
+ style: desktopSidebarStyle,
18847
+ children: /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "h-[40rem] max-h-[40rem] gap-0 overflow-hidden py-0 sm:h-[44rem] sm:max-h-[44rem] xl:h-[var(--tool-sidebar-max-height)] xl:max-h-[var(--tool-sidebar-max-height)]", children: renderControlsPanel() })
18848
+ }
18849
+ ),
18850
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-slot": "tool-results", className: "space-y-6", children: [
18851
+ /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "space-y-4 xl:hidden", children: [
18852
+ /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "gap-4 px-5 py-5", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-4 sm:flex-row sm:items-end sm:justify-between", children: [
18853
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
18854
+ /* @__PURE__ */ jsxRuntime.jsx(Heading, { level: 2, size: 5, className: "text-foreground", trim: "normal", children: "Configuration" }),
18855
+ /* @__PURE__ */ jsxRuntime.jsx(Text, { size: 2, children: "Open the colour pairing drawer to change palette, background, and recommended combinations." }),
18856
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: compactControlsSummary })
18857
+ ] }),
18858
+ /* @__PURE__ */ jsxRuntime.jsxs(
18859
+ Button2,
18860
+ {
18861
+ color: "primary",
18862
+ className: "w-full sm:w-auto",
18863
+ onClick: () => setIsCompactControlsOpen(true),
18864
+ children: [
18865
+ /* @__PURE__ */ jsxRuntime.jsx(Icons.edit_square, { "data-slot": "icon", className: "size-5" }),
18866
+ "Open configuration"
18867
+ ]
18868
+ }
18869
+ )
18870
+ ] }) }),
18871
+ /* @__PURE__ */ jsxRuntime.jsx(Sheet, { open: isCompactControlsOpen, onOpenChange: setIsCompactControlsOpen, children: /* @__PURE__ */ jsxRuntime.jsxs(
18872
+ SheetContent,
18873
+ {
18874
+ side: "left",
18875
+ showClose: false,
18876
+ className: "w-[30rem] max-w-[90vw] overflow-hidden p-0",
18877
+ children: [
18878
+ /* @__PURE__ */ jsxRuntime.jsx(SheetTitle, { className: "sr-only", children: "Colour pairing configuration" }),
18879
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-full flex-col bg-background", children: renderControlsPanel(true) })
18880
+ ]
18881
+ }
18882
+ ) })
18883
+ ] }),
18884
+ /* @__PURE__ */ jsxRuntime.jsxs("section", { ref: resultSectionRef, className: "space-y-6", "aria-label": "Current result", children: [
18885
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "sr-only", "aria-live": "polite", children: liveAnnouncement }),
18886
+ /* @__PURE__ */ jsxRuntime.jsx(
18887
+ CurrentResultCard,
18888
+ {
18889
+ bestPair: bestRecommendedPair,
18890
+ familySummary,
18891
+ pair: previewPair,
18892
+ selectedBackground
18893
+ }
18894
+ )
18895
+ ] }),
18896
+ bestRecommendedPair ? /* @__PURE__ */ jsxRuntime.jsx("section", { className: "space-y-4", children: /* @__PURE__ */ jsxRuntime.jsx(
18897
+ BestRecommendationCard,
18898
+ {
18899
+ copiedKey,
18900
+ isCurrentSelection: selectedPair?.id === bestRecommendedPair.id,
18901
+ pair: bestRecommendedPair,
18902
+ reason: getBestRecommendationReason(bestRecommendedPair, context),
18903
+ onCopyPairing: () => copyValue(
18904
+ "best-pairing",
18905
+ getPairingCopyText(bestRecommendedPair),
18906
+ "Pairing copied",
18907
+ {
18908
+ name: "best_recommendation_copied",
18909
+ ...buildAnalyticsContext({
18910
+ foregroundToken: bestRecommendedPair.foreground.token,
18911
+ pairId: bestRecommendedPair.id,
18912
+ source: "best-recommendation"
18913
+ })
18914
+ }
18915
+ ),
18916
+ onUsePairing: () => handlePairChange(bestRecommendedPair.id, "best-recommendation")
18917
+ }
18918
+ ) }) : /* @__PURE__ */ jsxRuntime.jsxs(Card, { className: "px-6 py-6", children: [
18919
+ /* @__PURE__ */ jsxRuntime.jsx(Heading, { level: 2, size: 5, className: "text-foreground", trim: "normal", children: "Best recommended pairing" }),
18920
+ /* @__PURE__ */ jsxRuntime.jsx(Text, { size: 2, className: "mt-3", children: "No AAA-compliant foreground options available for this selection." })
18921
+ ] }),
18922
+ /* @__PURE__ */ jsxRuntime.jsxs("section", { ref: technicalDetailsSectionRef, className: "space-y-4", children: [
18923
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
18924
+ /* @__PURE__ */ jsxRuntime.jsx(Heading, { level: 2, size: 5, className: "text-foreground", trim: "normal", children: "Technical colour values" }),
18925
+ /* @__PURE__ */ jsxRuntime.jsx(Text, { size: 2, children: "Token, tone, HEX, RGB, HSL, and OKLCH values for the current selection." })
18926
+ ] }),
18927
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-4 lg:grid-cols-2", children: [
18928
+ /* @__PURE__ */ jsxRuntime.jsx(
18929
+ TechnicalDetailsPanel,
18930
+ {
18931
+ title: "Background values",
18932
+ color: selectedBackground,
18933
+ visibleFormats,
18934
+ copiedKey,
18935
+ onCopyValue: (copyKey, value, toastLabel) => copyValue(copyKey, value, toastLabel)
18936
+ }
18937
+ ),
18938
+ /* @__PURE__ */ jsxRuntime.jsx(
18939
+ TechnicalDetailsPanel,
18940
+ {
18941
+ title: "Foreground values",
18942
+ color: detailForeground,
18943
+ visibleFormats,
18944
+ copiedKey,
18945
+ onCopyValue: (copyKey, value, toastLabel) => copyValue(copyKey, value, toastLabel)
18946
+ }
18947
+ )
18948
+ ] }),
18949
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
18950
+ /* @__PURE__ */ jsxRuntime.jsx(Heading, { level: 3, size: 6, className: "mb-3 text-foreground", trim: "normal", children: "Share colour pairing" }),
18951
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-sm border border-grey-200 bg-white p-4", children: [
18952
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-start gap-3 sm:flex-row sm:items-start sm:justify-between", children: [
18953
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: "Copy this URL to share your current colour pairing:" }),
18954
+ /* @__PURE__ */ jsxRuntime.jsx(
18955
+ Button2,
18956
+ {
18957
+ variant: "ghost",
18958
+ color: "grey",
18959
+ size: "sm",
18960
+ className: "shrink-0",
18961
+ onClick: () => copyValue(
18962
+ "share-url",
18963
+ typeof window === "undefined" ? shareUrl : new URL(shareUrl, window.location.origin).toString(),
18964
+ "Colour pairing link copied"
18965
+ ),
18966
+ "aria-label": copiedKey === "share-url" ? "Colour pairing URL copied to clipboard" : "Copy colour pairing URL to clipboard",
18967
+ title: copiedKey === "share-url" ? "Copied" : "Copy URL",
18968
+ children: copiedKey === "share-url" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
18969
+ /* @__PURE__ */ jsxRuntime.jsx(Icons.check, { "data-slot": "icon", className: "size-5" }),
18970
+ "Copied"
18971
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
18972
+ /* @__PURE__ */ jsxRuntime.jsx(Icons.content_copy, { "data-slot": "icon", className: "size-5" }),
18973
+ "Copy URL"
18974
+ ] })
18975
+ }
18976
+ )
18977
+ ] }),
18978
+ /* @__PURE__ */ jsxRuntime.jsx("code", { className: "mt-3 block w-full rounded-sm border border-grey-200 bg-background px-3 py-2 font-mono text-[11px] break-all text-foreground sm:text-xs", children: shareUrl })
18979
+ ] })
18980
+ ] })
18981
+ ] })
18982
+ ] })
18983
+ ] });
18984
+ }
18985
+ function ColorPairingToolV3({
18986
+ onAnalyticsEvent = () => {
18987
+ },
18988
+ visibleFormats = DEFAULT_VISIBLE_FORMATS3
18989
+ } = {}) {
18990
+ const normalizedVisibleFormats = [...new Set(visibleFormats)];
18991
+ return /* @__PURE__ */ jsxRuntime.jsx(React5.Suspense, { fallback: /* @__PURE__ */ jsxRuntime.jsx(ColorPairingToolV3Loading, {}), children: /* @__PURE__ */ jsxRuntime.jsx(
18992
+ ColorPairingToolV3Content,
18993
+ {
18994
+ onAnalyticsEvent,
18995
+ visibleFormats: normalizedVisibleFormats
18996
+ }
18997
+ ) });
18998
+ }
18999
+ var PREFERRED_BACKGROUND_TONES4 = [400, 600, 200, 800, 100, 50];
19000
+ var DEFAULT_VISIBLE_FORMATS4 = ["hex", "rgb", "hsl", "oklch"];
19001
+ var DEFAULT_INITIAL_BACKGROUND_TOKEN4 = "nsw-blue-800";
19002
+ var DEFAULT_INITIAL_PAIR_ID4 = "nsw-blue-800:nsw-blue-200";
19003
+ var COLOR_PAIRING_TOOL_V4_PATH = "/core/colour/colour-pairing-tool-4";
19004
+ var MOBILE_RESULT_SCROLL_QUERY2 = "(max-width: 1023px)";
19005
+ var PERSISTENT_DRAWER_MIN_WIDTH_QUERY2 = "(min-width: 1280px)";
19006
+ var COLOR_PAIRING_TOOL_DRAWER_STEPS2 = [
19007
+ {
19008
+ id: "colours",
19009
+ title: "Choose colours",
19010
+ eyebrow: "Step 1 of 3",
19011
+ description: "Select the palette, primary family, and accent family."
19012
+ },
19013
+ {
19014
+ id: "backgrounds",
19015
+ title: "Choose background",
19016
+ eyebrow: "Step 2 of 3",
19017
+ description: "Pick the background tone that you want to pair."
19018
+ },
19019
+ {
19020
+ id: "refine",
19021
+ title: "Refine or override recommendation",
19022
+ eyebrow: "Step 3 of 3",
19023
+ description: "Use the result panel to review the NSW default pairing and override it only when a different approved option is needed."
19024
+ }
19025
+ ];
19026
+ var COLOR_PAIRING_TOOL_V4_ANALYTICS_EVENT = "nsw-colour-pairing-tool-v4";
19027
+ function getToneFromToken4(token) {
19028
+ if (!token) return null;
19029
+ const match = token.match(/-(\d+)$/);
19030
+ return match ? Number.parseInt(match[1], 10) : null;
19031
+ }
19032
+ function getFamilySwatchColor4(family, preferredTone = 600) {
19033
+ const exactMatch = family.colors.find((color2) => color2.tone === preferredTone);
19034
+ if (exactMatch) {
19035
+ return exactMatch.hex;
19036
+ }
19037
+ const closestMatch = [...family.colors].sort(
19038
+ (left, right) => Math.abs(left.tone - preferredTone) - Math.abs(right.tone - preferredTone)
19039
+ )[0];
19040
+ return closestMatch?.hex ?? "transparent";
19041
+ }
19042
+ function getFamilySelectorLabel4(family, themeCategory, selectionRole) {
19043
+ if (themeCategory !== "aboriginal") {
19044
+ return family.label;
19045
+ }
19046
+ const preferredTone = selectionRole === "primary colour" ? 800 : 600;
19047
+ return family.colors.find((color2) => color2.tone === preferredTone)?.name ?? family.label;
19048
+ }
19049
+ function getPairingColorDisplayName4(color2) {
19050
+ return color2.name ?? `${color2.familyLabel} ${color2.tone}`;
19051
+ }
19052
+ function isWhiteForegroundPair4(pair) {
19053
+ return pair.foreground.token === "white";
19054
+ }
19055
+ function isLargeTextOnlyPair2(pair) {
19056
+ return pair.passes.aaaLarge && !pair.passes.aaaText;
19057
+ }
19058
+ function getWhiteForegroundGuidance4(pair) {
19059
+ if (pair.passes.aaaText) {
19060
+ return "White is approved for headings, body copy, and calls to action on this background.";
19061
+ }
19062
+ if (pair.passes.aaaLarge) {
19063
+ return "Use white only for WCAG large text on this background, such as headings at 24px+ or bold text at 18.5px+. Keep sentence-case body copy at 16px+ and use a darker recommended foreground instead.";
19064
+ }
19065
+ return "Do not use white on this background. Choose one of the recommended foregrounds below instead.";
19066
+ }
19067
+ function getPreviewGuidance4(pair, isRecommended) {
19068
+ if (!isWhiteForegroundPair4(pair)) {
19069
+ return "Use only AAA-recommended combinations across your selected primary, accent, and grey families.";
19070
+ }
19071
+ if (isRecommended) {
19072
+ return "Use white text on dark colour only when it meets AAA for headings, body copy, and calls to action.";
19073
+ }
19074
+ return getWhiteForegroundGuidance4(pair);
19075
+ }
19076
+ function getPreferredPairForBackground4(pairs, preferredPairId) {
19077
+ if (preferredPairId) {
19078
+ const preferredPair = pairs.find((pair) => pair.id === preferredPairId);
19079
+ if (preferredPair) {
19080
+ return preferredPair;
19081
+ }
19082
+ }
19083
+ return pairs.find((pair) => !isWhiteForegroundPair4(pair)) ?? pairs[0] ?? null;
19084
+ }
19085
+ function getDefaultBackgroundToken4(context) {
19086
+ for (const tone of PREFERRED_BACKGROUND_TONES4) {
19087
+ for (const group of context.backgroundGroups) {
19088
+ const match = group.backgrounds.find(
19089
+ (background) => background.tone === tone && (context.pairsByBackground[background.token]?.length ?? 0) > 0
19090
+ );
19091
+ if (match) {
19092
+ return match.token;
19093
+ }
19094
+ }
19095
+ }
19096
+ for (const tone of PREFERRED_BACKGROUND_TONES4) {
19097
+ for (const group of context.backgroundGroups) {
19098
+ const match = group.backgrounds.find((background) => background.tone === tone);
19099
+ if (match) {
19100
+ return match.token;
19101
+ }
19102
+ }
19103
+ }
19104
+ return context.backgrounds[0]?.token ?? "";
19105
+ }
19106
+ function resolveBackgroundToken4(context, preferredToken, preferredTone) {
19107
+ if (preferredToken && context.backgrounds.some((background) => background.token === preferredToken)) {
19108
+ return preferredToken;
19109
+ }
19110
+ if (preferredTone !== null && preferredTone !== void 0) {
19111
+ for (const group of context.backgroundGroups) {
19112
+ const match = group.backgrounds.find((background) => background.tone === preferredTone);
19113
+ if (match) {
19114
+ return match.token;
19115
+ }
19116
+ }
19117
+ }
19118
+ return getDefaultBackgroundToken4(context);
19119
+ }
19120
+ function getInitialPairingState4(searchParams) {
19121
+ const paletteParam = searchParams.get("palette");
19122
+ const primaryParam = searchParams.get("primary");
19123
+ const accentParam = searchParams.get("accent");
19124
+ const pairParam = searchParams.get("pair");
19125
+ const backgroundParam = searchParams.get("background");
19126
+ const themeCategory = paletteParam === "brand" || paletteParam === "aboriginal" ? paletteParam : "brand";
19127
+ const context = getPairingContext(themeCategory, primaryParam, accentParam);
19128
+ const shouldUseDefaultBrandExample = !backgroundParam && !pairParam && themeCategory === "brand" && context.primary.key === "blue" && context.accent.key === "red";
19129
+ const defaultBackgroundToken = shouldUseDefaultBrandExample ? context.backgrounds.some(
19130
+ (background) => background.token === DEFAULT_INITIAL_BACKGROUND_TOKEN4
19131
+ ) ? DEFAULT_INITIAL_BACKGROUND_TOKEN4 : null : null;
19132
+ const defaultPairId = shouldUseDefaultBrandExample && defaultBackgroundToken && context.pairsByBackground[defaultBackgroundToken]?.some(
19133
+ (pair) => pair.id === DEFAULT_INITIAL_PAIR_ID4
19134
+ ) ? DEFAULT_INITIAL_PAIR_ID4 : null;
19135
+ const pairBackgroundToken = context.recommendedPairs.find((pair) => pair.id === pairParam)?.background.token ?? null;
19136
+ const selectedBackgroundToken = resolveBackgroundToken4(
19137
+ context,
19138
+ backgroundParam ?? pairBackgroundToken ?? defaultBackgroundToken,
19139
+ getToneFromToken4(backgroundParam ?? pairBackgroundToken ?? defaultBackgroundToken)
19140
+ );
19141
+ const selectedPairId = getPreferredPairForBackground4(
19142
+ context.pairsByBackground[selectedBackgroundToken] ?? [],
19143
+ pairParam ?? defaultPairId
19144
+ )?.id ?? "";
19145
+ return {
19146
+ accentKey: context.accent.key,
19147
+ primaryKey: context.primary.key,
19148
+ selectedBackgroundToken,
19149
+ selectedPairId,
19150
+ themeCategory
19151
+ };
19152
+ }
19153
+ function getReadableTextColor3(tone) {
19154
+ return tone >= 600 ? "#ffffff" : "#002664";
19155
+ }
19156
+ function getBackgroundOptionName2(background) {
19157
+ return background.name ?? `${background.familyLabel} ${background.tone}`;
19158
+ }
19159
+ function getMainPairingLabel(pair, bestPair) {
19160
+ if (!pair) {
19161
+ return "No AAA pairing available";
19162
+ }
19163
+ if (pair.id === bestPair?.id) {
19164
+ return "NSW recommended pairing";
19165
+ }
19166
+ if (isWhiteForegroundPair4(pair) && isLargeTextOnlyPair2(pair)) {
19167
+ return "Large-text example only";
19168
+ }
19169
+ if (isWhiteForegroundPair4(pair) && !pair.passes.aaaLarge) {
19170
+ return "Example only";
19171
+ }
19172
+ return "Approved alternative";
19173
+ }
19174
+ function getMainPairingSupportCopy(pair, bestPair, context) {
19175
+ if (!pair) {
19176
+ return "No AAA-compliant foreground available for this background.";
19177
+ }
19178
+ if (pair.id === bestPair?.id) {
19179
+ return getBestRecommendationReason2(pair, context);
19180
+ }
19181
+ if (isWhiteForegroundPair4(pair) && isLargeTextOnlyPair2(pair)) {
19182
+ return "White works here for large text only. Use the NSW default for standard body copy and smaller interface text.";
19183
+ }
19184
+ if (isWhiteForegroundPair4(pair) && !pair.passes.aaaLarge) {
19185
+ return "White does not meet AAA on this background. Choose a different approved background or foreground.";
19186
+ }
19187
+ return "Approved AAA alternative when a different tone or emphasis is needed.";
19188
+ }
19189
+ function getBestRecommendationReason2(pair, context) {
19190
+ if (isWhiteForegroundPair4(pair)) {
19191
+ return "Recommended because this background is dark enough to support white text at AAA contrast.";
19192
+ }
19193
+ if (pair.foreground.familyKey === pair.background.familyKey) {
19194
+ return "Recommended because it stays within the same colour family while keeping clear AAA contrast.";
19195
+ }
19196
+ if (pair.foreground.familyKey === context.grey.key) {
19197
+ return "Recommended because grey provides a strong neutral contrast without competing with the background.";
19198
+ }
19199
+ if (pair.foreground.familyKey === context.accent.key) {
19200
+ return "Recommended because the selected accent family adds emphasis while preserving AAA contrast.";
19201
+ }
19202
+ if (pair.foreground.familyKey === context.primary.key) {
19203
+ return "Recommended because the selected primary family gives the clearest AAA-compliant contrast for this background.";
19204
+ }
19205
+ return "Recommended because it is the clearest NSW-approved AAA pairing for this background.";
19206
+ }
19207
+ function getRecommendationCategory2(pair, bestPair, context) {
19208
+ if (pair.id === bestPair?.id) return "best";
19209
+ if (isWhiteForegroundPair4(pair)) return "white";
19210
+ if (pair.foreground.familyKey === pair.background.familyKey) return "same-family";
19211
+ if (pair.foreground.familyKey === context.accent.key) return "accent-family";
19212
+ if (pair.foreground.familyKey === context.grey.key) return "grey-option";
19213
+ if (pair.foreground.familyKey === context.primary.key) return "primary-family";
19214
+ return "approved";
19215
+ }
19216
+ function getRecommendationCategoryLabel2(category) {
19217
+ switch (category) {
19218
+ case "best":
19219
+ return "Best recommended";
19220
+ case "same-family":
19221
+ return "Same family";
19222
+ case "accent-family":
19223
+ return "Accent family";
19224
+ case "grey-option":
19225
+ return "Grey option";
19226
+ case "primary-family":
19227
+ return "Primary family";
19228
+ case "white":
19229
+ return "White";
19230
+ default:
19231
+ return "Approved option";
19232
+ }
19233
+ }
19234
+ function getRecommendationSortRank2(category) {
19235
+ switch (category) {
19236
+ case "best":
19237
+ return 0;
19238
+ case "same-family":
19239
+ return 1;
19240
+ case "accent-family":
19241
+ return 2;
19242
+ case "grey-option":
19243
+ return 3;
19244
+ case "white":
19245
+ return 4;
19246
+ case "primary-family":
19247
+ return 5;
19248
+ default:
19249
+ return 6;
19250
+ }
19251
+ }
19252
+ function getRecommendationGroupId(category) {
19253
+ switch (category) {
19254
+ case "best":
19255
+ case "same-family":
19256
+ case "accent-family":
19257
+ case "grey-option":
19258
+ case "primary-family":
19259
+ return "good-alternatives";
19260
+ case "white":
19261
+ case "approved":
19262
+ return "edge-options";
19263
+ default:
19264
+ return null;
19265
+ }
19266
+ }
19267
+ function buildRecommendationGroups(items) {
19268
+ const groupedItems = items.reduce(
19269
+ (accumulator, item) => {
19270
+ const groupId = getRecommendationGroupId(item.category);
19271
+ if (!groupId) {
19272
+ return accumulator;
19273
+ }
19274
+ accumulator[groupId].push(item);
19275
+ return accumulator;
19276
+ },
19277
+ {
19278
+ "edge-options": [],
19279
+ "good-alternatives": []
19280
+ }
19281
+ );
19282
+ const groups = [
19283
+ {
19284
+ id: "good-alternatives",
19285
+ title: "Good alternatives",
19286
+ description: "These pairings still meet AAA and stay close to the NSW recommendation in tone, neutrality, or emphasis.",
19287
+ items: groupedItems["good-alternatives"]
19288
+ },
19289
+ {
19290
+ id: "edge-options",
19291
+ title: "Edge and less common options",
19292
+ description: "These are valid AAA pairings, but they are less typical NSW defaults and should be used more deliberately.",
19293
+ items: groupedItems["edge-options"]
19294
+ }
19295
+ ];
19296
+ return groups.filter((group) => group.items.length > 0);
19297
+ }
19298
+ function getAvailabilityMeta2(isSelected, hasPairs) {
19299
+ if (isSelected && hasPairs) {
19300
+ return {
19301
+ description: "Selected background with AAA foreground options.",
19302
+ icon: Icons.check_circle,
19303
+ label: "Selected",
19304
+ tone: "selected"
19305
+ };
19306
+ }
19307
+ if (isSelected) {
19308
+ return {
19309
+ description: "Selected background with no AAA-compliant foreground available.",
19310
+ icon: Icons.warning,
19311
+ label: "Selected, no AAA",
19312
+ tone: "unavailable"
19313
+ };
19314
+ }
19315
+ if (hasPairs) {
19316
+ return {
19317
+ description: "AAA foreground options available.",
19318
+ icon: Icons.radio_button_checked,
19319
+ label: "Available",
19320
+ tone: "available"
19321
+ };
19322
+ }
19323
+ return {
19324
+ description: "No AAA-compliant foreground available for this background.",
19325
+ icon: Icons.close,
19326
+ label: "No AAA",
19327
+ tone: "unavailable"
19328
+ };
19329
+ }
19330
+ function getPairingCopyText2(pair) {
19331
+ const accessibilityLine = pair.passes.aaaText ? "Accessibility: Meets AAA for normal and large text" : pair.passes.aaaLarge ? "Accessibility: Meets AAA for large text only" : "Accessibility: Fails AAA for normal and large text";
19332
+ return [
19333
+ `Background: ${pair.background.token} (${pair.background.hex})`,
19334
+ `Foreground: ${pair.foreground.token} (${pair.foreground.hex})`,
19335
+ `Contrast ratio: ${pair.contrastRatio.toFixed(2)}:1`,
19336
+ accessibilityLine
19337
+ ].join("\n");
19338
+ }
19339
+ function getLiveAnnouncement2(pair, background) {
19340
+ if (!background) {
19341
+ return "No approved background tones available.";
19342
+ }
19343
+ if (!pair) {
19344
+ return `${background.token} selected. No AAA-compliant foreground options available for this selection.`;
19345
+ }
19346
+ if (isWhiteForegroundPair4(pair) && isLargeTextOnlyPair2(pair)) {
19347
+ return `${background.token} with white. Contrast ratio ${pair.contrastRatio.toFixed(2)} to 1. Meets AAA for large text only.`;
19348
+ }
19349
+ if (isWhiteForegroundPair4(pair) && !pair.passes.aaaLarge) {
19350
+ return `${background.token} with white. Contrast ratio ${pair.contrastRatio.toFixed(2)} to 1. Fails AAA for normal and large text.`;
19351
+ }
19352
+ return `${background.token} with ${pair.foreground.token}. Contrast ratio ${pair.contrastRatio.toFixed(2)} to 1. Meets AAA for normal and large text.`;
19353
+ }
19354
+ function formatValueRows2(color2, visibleFormats) {
19355
+ const hasDisplayTone = color2.token !== "white";
19356
+ return [
19357
+ { key: "token", label: "Token", value: color2.token, copyable: true },
19358
+ {
19359
+ key: "tone",
19360
+ label: "Tone",
19361
+ value: hasDisplayTone ? String(color2.tone) : "Not applicable",
19362
+ copyable: hasDisplayTone
19363
+ },
19364
+ ...visibleFormats.map((format) => ({
19365
+ key: format,
19366
+ label: format.toUpperCase(),
19367
+ value: color2[format],
19368
+ copyable: true
19369
+ }))
19370
+ ];
19371
+ }
19372
+ function SelectorButton2({
19373
+ description,
19374
+ isSelected,
19375
+ label,
19376
+ onClick,
19377
+ swatch
19378
+ }) {
19379
+ return /* @__PURE__ */ jsxRuntime.jsx(
19380
+ "button",
19381
+ {
19382
+ type: "button",
19383
+ "aria-pressed": isSelected,
19384
+ onClick,
19385
+ className: cn(
19386
+ "w-full rounded-sm border px-3 py-3 text-left transition-colors focus-visible:ring-2 focus-visible:ring-primary-700 focus-visible:ring-offset-2 focus-visible:outline-hidden",
19387
+ isSelected ? "border-primary-800 bg-primary-50" : "border-grey-300 bg-white hover:border-primary-500 hover:bg-grey-50"
19388
+ ),
19389
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-3", children: [
19390
+ swatch ? /* @__PURE__ */ jsxRuntime.jsx(
19391
+ "span",
19392
+ {
19393
+ "aria-hidden": "true",
19394
+ className: "mt-0.5 size-4 shrink-0 rounded-full border border-black/10",
19395
+ style: { backgroundColor: swatch }
19396
+ }
19397
+ ) : null,
19398
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 space-y-1", children: [
19399
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-semibold text-foreground", children: label }),
19400
+ description ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs/5 text-muted-foreground", children: description }) : null
19401
+ ] })
19402
+ ] })
19403
+ }
19404
+ );
19405
+ }
19406
+ function BackgroundSwatchButton2({
19407
+ background,
19408
+ hasPairs,
19409
+ isSelected,
19410
+ onClick
19411
+ }) {
19412
+ const status = getAvailabilityMeta2(isSelected, hasPairs);
19413
+ const StatusIcon = status.icon;
19414
+ return /* @__PURE__ */ jsxRuntime.jsxs(
19415
+ "button",
19416
+ {
19417
+ type: "button",
19418
+ "aria-pressed": isSelected,
19419
+ "aria-label": `Select ${background.token} background. ${status.description}`,
19420
+ onClick,
19421
+ className: cn(
19422
+ "w-full rounded-sm border bg-white p-3 text-left transition-colors focus-visible:ring-2 focus-visible:ring-primary-700 focus-visible:ring-offset-2 focus-visible:outline-hidden",
19423
+ isSelected ? "border-primary-800 bg-primary-50" : hasPairs ? "border-grey-300 hover:border-primary-500 hover:bg-grey-50" : "border-grey-300 hover:border-grey-500"
19424
+ ),
19425
+ children: [
19426
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-3", children: [
19427
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0", children: [
19428
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-semibold text-foreground", children: getBackgroundOptionName2(background) }),
19429
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 font-mono text-[0.72rem] break-all text-muted-foreground", children: background.token })
19430
+ ] }),
19431
+ /* @__PURE__ */ jsxRuntime.jsxs(
19432
+ "span",
19433
+ {
19434
+ className: cn(
19435
+ "inline-flex items-center gap-1 rounded-sm border px-2 py-1 text-[0.68rem] font-semibold uppercase",
19436
+ status.tone === "selected" && "border-primary-800 bg-primary-800 text-white dark:border-primary-500 dark:bg-primary-500",
19437
+ status.tone === "available" && "border-grey-300 bg-grey-50 text-foreground",
19438
+ status.tone === "unavailable" && "border-danger-300 bg-danger-50 text-danger-900 dark:border-danger-800 dark:bg-danger-950/20 dark:text-danger-200"
19439
+ ),
19440
+ children: [
19441
+ /* @__PURE__ */ jsxRuntime.jsx(StatusIcon, { "data-slot": "icon", className: "size-4" }),
19442
+ status.label
19443
+ ]
19444
+ }
19445
+ )
19446
+ ] }),
19447
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-3 overflow-hidden rounded-[2px] border border-black/10", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-14 w-full", style: { backgroundColor: background.hex } }) }),
19448
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-3 text-xs/5 text-muted-foreground", children: status.description })
19449
+ ]
19450
+ }
19451
+ );
19452
+ }
19453
+ function CompactAccessibilityStatus({ label, passes }) {
19454
+ const status = passes === null ? "unavailable" : passes ? "pass" : "fail";
19455
+ return /* @__PURE__ */ jsxRuntime.jsxs(
19456
+ "div",
19457
+ {
19458
+ className: cn(
19459
+ "flex items-center justify-between gap-3 rounded-sm border px-4 py-3",
19460
+ status === "pass" && "border-success-200 bg-success-50",
19461
+ status === "fail" && "border-danger-200 bg-danger-50",
19462
+ status === "unavailable" && "border-grey-200 bg-white"
19463
+ ),
19464
+ children: [
19465
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-semibold text-foreground", children: label }),
19466
+ /* @__PURE__ */ jsxRuntime.jsxs(
19467
+ "span",
19468
+ {
19469
+ className: cn(
19470
+ "inline-flex items-center gap-1 rounded-sm px-2.5 py-1 text-[0.72rem] font-semibold tracking-[0.12em] uppercase",
19471
+ status === "pass" && "bg-success-700 text-white",
19472
+ status === "fail" && "bg-danger-700 text-white",
19473
+ status === "unavailable" && "bg-grey-100 text-foreground"
19474
+ ),
19475
+ children: [
19476
+ status === "pass" ? /* @__PURE__ */ jsxRuntime.jsx(Icons.check, { "data-slot": "icon", className: "size-4" }) : status === "fail" ? /* @__PURE__ */ jsxRuntime.jsx(Icons.close, { "data-slot": "icon", className: "size-4" }) : /* @__PURE__ */ jsxRuntime.jsx(Icons.info, { "data-slot": "icon", className: "size-4" }),
19477
+ status === "pass" ? "Pass" : status === "fail" ? "Fail" : "Unavailable"
19478
+ ]
19479
+ }
19480
+ )
19481
+ ]
19482
+ }
19483
+ );
19484
+ }
19485
+ function AccessibilitySummaryCard({ pair }) {
19486
+ return /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "gap-4 px-5 py-5", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-5 lg:flex-row lg:items-start lg:justify-between", children: [
19487
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
19488
+ /* @__PURE__ */ jsxRuntime.jsx(Heading, { level: 2, size: 6, className: "text-foreground", trim: "normal", children: "Accessibility summary" }),
19489
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
19490
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-semibold text-grey-700", children: "Contrast ratio" }),
19491
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-4xl leading-none font-bold text-foreground", children: pair ? `${pair.contrastRatio.toFixed(2)}:1` : "N/A" })
19492
+ ] })
19493
+ ] }),
19494
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-3 lg:max-w-[26rem] lg:min-w-[22rem]", children: [
19495
+ /* @__PURE__ */ jsxRuntime.jsx(
19496
+ CompactAccessibilityStatus,
19497
+ {
19498
+ label: "AAA normal text",
19499
+ passes: pair ? pair.passes.aaaText : null
19500
+ }
19501
+ ),
19502
+ /* @__PURE__ */ jsxRuntime.jsx(
19503
+ CompactAccessibilityStatus,
19504
+ {
19505
+ label: "AAA large text",
19506
+ passes: pair ? pair.passes.aaaLarge : null
19507
+ }
19508
+ )
19509
+ ] })
19510
+ ] }) });
19511
+ }
19512
+ function CurrentResultCard2({
19513
+ bestPair,
19514
+ copiedKey,
19515
+ onCopyPairing,
19516
+ pair,
19517
+ supportText,
19518
+ selectedBackground
19519
+ }) {
19520
+ const previewForeground = pair?.foreground.hex ?? getReadableTextColor3(selectedBackground.tone);
19521
+ const isRecommended = pair ? pair.id === bestPair?.id : false;
19522
+ const whiteForeground = pair ? isWhiteForegroundPair4(pair) : false;
19523
+ const pairingLabel = getMainPairingLabel(pair, bestPair);
19524
+ const fauxButtonStyle = pair ? {
19525
+ "--btn-bg": pair.foreground.hex,
19526
+ "--btn-border": pair.foreground.hex,
19527
+ "--btn-text": pair.background.hex,
19528
+ "--btn-icon": pair.background.hex,
19529
+ "--btn-hover-overlay": pair.background.hex
19530
+ } : null;
19531
+ return /* @__PURE__ */ jsxRuntime.jsxs(Card, { className: cn("gap-0 overflow-hidden py-0", isRecommended && "border-primary-200"), children: [
19532
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-b border-grey-200 px-4 py-4 sm:px-6 sm:py-5", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between", children: [
19533
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 space-y-3", children: [
19534
+ /* @__PURE__ */ jsxRuntime.jsxs(
19535
+ "span",
19536
+ {
19537
+ className: cn(
19538
+ "inline-flex items-center gap-2 rounded-sm px-3 py-1 text-[0.72rem] font-semibold tracking-[0.12em] uppercase",
19539
+ isRecommended ? "bg-primary-800 text-white" : "border border-grey-300 bg-grey-50 text-foreground"
19540
+ ),
19541
+ children: [
19542
+ isRecommended ? /* @__PURE__ */ jsxRuntime.jsx(Icons.check_circle, { "data-slot": "icon", className: "size-4" }) : /* @__PURE__ */ jsxRuntime.jsx(Icons.info, { "data-slot": "icon", className: "size-4" }),
19543
+ pairingLabel
19544
+ ]
19545
+ }
19546
+ ),
19547
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
19548
+ /* @__PURE__ */ jsxRuntime.jsx(Heading, { level: 2, size: 4, className: "text-foreground", trim: "normal", children: pair ? `${getPairingColorDisplayName4(pair.foreground)} on ${getPairingColorDisplayName4(pair.background)}` : `${getPairingColorDisplayName4(selectedBackground)} selected` }),
19549
+ /* @__PURE__ */ jsxRuntime.jsx(Text, { size: 2, className: "max-w-3xl text-grey-700", children: supportText })
19550
+ ] })
19551
+ ] }),
19552
+ pair ? /* @__PURE__ */ jsxRuntime.jsx(
19553
+ Button2,
19554
+ {
19555
+ color: "primary",
19556
+ className: "w-full justify-center lg:w-auto lg:min-w-48",
19557
+ onClick: onCopyPairing,
19558
+ children: copiedKey === "current-pairing" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
19559
+ /* @__PURE__ */ jsxRuntime.jsx(Icons.check, { "data-slot": "icon", className: "size-5" }),
19560
+ "Pairing copied"
19561
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
19562
+ /* @__PURE__ */ jsxRuntime.jsx(Icons.content_copy, { "data-slot": "icon", className: "size-5" }),
19563
+ "Copy pairing"
19564
+ ] })
19565
+ }
19566
+ ) : null
19567
+ ] }) }),
19568
+ /* @__PURE__ */ jsxRuntime.jsx(
19569
+ "div",
19570
+ {
19571
+ className: "p-4 sm:min-h-[26rem] sm:p-8",
19572
+ style: {
19573
+ backgroundColor: selectedBackground.hex,
19574
+ color: previewForeground
19575
+ },
19576
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex min-h-[18rem] flex-col justify-center gap-6 sm:min-h-[22rem]", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "max-w-xl space-y-4", children: [
19577
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-semibold tracking-[0.22em] uppercase", children: pair ? whiteForeground && !isRecommended ? "White on colour example" : whiteForeground ? "White on colour" : "Colour on colour" : "Approved background" }),
19578
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
19579
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "max-w-lg text-3xl leading-tight font-bold text-current sm:text-5xl sm:leading-none", children: "Pair colour with confidence." }),
19580
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "max-w-full text-base/6 sm:max-w-md sm:text-base/7", children: pair ? getPreviewGuidance4(pair, isRecommended) : "This approved background tone does not currently have a recommended AAA foreground in this tool. Choose another approved background tone to continue." }),
19581
+ pair && fauxButtonStyle ? /* @__PURE__ */ jsxRuntime.jsx(
19582
+ "span",
19583
+ {
19584
+ "aria-hidden": "true",
19585
+ "data-variant": "solid",
19586
+ className: cn(
19587
+ buttonVariants({ variant: "solid", size: "default" }),
19588
+ "pointer-events-none cursor-default px-6 text-[16px] font-[700] select-none sm:px-6 sm:text-[16px] sm:font-[700]"
19589
+ ),
19590
+ style: fauxButtonStyle,
19591
+ children: "Get started"
19592
+ }
19593
+ ) : null
19594
+ ] })
19595
+ ] }) })
19596
+ }
19597
+ )
19598
+ ] });
19599
+ }
19600
+ function RecommendationCard2({
19601
+ copiedKey,
19602
+ isSelected,
19603
+ item,
19604
+ onCopyPairing,
19605
+ onSelect
19606
+ }) {
19607
+ const { pair } = item;
19608
+ return /* @__PURE__ */ jsxRuntime.jsxs(
19609
+ "div",
19610
+ {
19611
+ className: cn(
19612
+ "relative rounded-sm border bg-white p-4 text-left transition-colors focus-visible:ring-2 focus-visible:ring-primary-700 focus-visible:ring-offset-2 focus-visible:outline-hidden",
19613
+ isSelected ? "border-primary-800 bg-primary-50/60 ring-1 ring-primary-700" : "border-grey-200 hover:border-primary-500 hover:bg-grey-50"
19614
+ ),
19615
+ children: [
19616
+ /* @__PURE__ */ jsxRuntime.jsx(
19617
+ "button",
19618
+ {
19619
+ type: "button",
19620
+ "aria-pressed": isSelected,
19621
+ "aria-label": `Use ${pair.foreground.token} on ${pair.background.token}`,
19622
+ onClick: onSelect,
19623
+ className: "absolute inset-0 rounded-sm focus-visible:ring-2 focus-visible:ring-primary-700 focus-visible:ring-offset-2 focus-visible:outline-hidden"
19624
+ }
19625
+ ),
19626
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pointer-events-none relative z-10", children: [
19627
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-start gap-3 sm:flex-row sm:items-start sm:justify-between", children: [
19628
+ /* @__PURE__ */ jsxRuntime.jsxs(
19629
+ "span",
19630
+ {
19631
+ className: cn(
19632
+ "inline-flex items-center gap-2 rounded-sm px-2.5 py-1 text-[0.68rem] font-semibold tracking-[0.12em] uppercase",
19633
+ item.category === "best" ? "bg-primary-800 text-white" : "border border-grey-300 bg-grey-50 text-foreground"
19634
+ ),
19635
+ children: [
19636
+ item.category === "best" ? /* @__PURE__ */ jsxRuntime.jsx(Icons.check_circle, { "data-slot": "icon", className: "size-4" }) : /* @__PURE__ */ jsxRuntime.jsx(Icons.info, { "data-slot": "icon", className: "size-4" }),
19637
+ item.categoryLabel
19638
+ ]
19639
+ }
19640
+ ),
19641
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pointer-events-auto shrink-0 self-start", children: /* @__PURE__ */ jsxRuntime.jsxs(
19642
+ Button2,
19643
+ {
19644
+ variant: "ghost",
19645
+ color: "grey",
19646
+ size: "sm",
19647
+ onClick: onCopyPairing,
19648
+ "aria-label": `Copy pairing ${pair.background.token} and ${pair.foreground.token}`,
19649
+ children: [
19650
+ /* @__PURE__ */ jsxRuntime.jsx(Icons.content_copy, { "data-slot": "icon", className: "size-5" }),
19651
+ copiedKey === `pair:${pair.id}` ? "Copied" : "Copy"
19652
+ ]
19653
+ }
19654
+ ) })
19655
+ ] }),
19656
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-4", children: [
19657
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-4 sm:grid-cols-[7.5rem_minmax(0,1fr)]", children: [
19658
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "overflow-hidden rounded-[2px] border border-black/10", children: [
19659
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-20 w-full", style: { backgroundColor: pair.background.hex } }),
19660
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-6 w-full", style: { backgroundColor: pair.foreground.hex } })
19661
+ ] }),
19662
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 space-y-2", children: [
19663
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
19664
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-base font-semibold text-foreground", children: getPairingColorDisplayName4(pair.foreground) }),
19665
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 font-mono text-[0.74rem] break-all text-muted-foreground", children: pair.foreground.token })
19666
+ ] }),
19667
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm text-muted-foreground", children: [
19668
+ pair.foreground.familyLabel,
19669
+ " on ",
19670
+ pair.background.familyLabel
19671
+ ] })
19672
+ ] })
19673
+ ] }),
19674
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-4 flex flex-col items-start gap-3 sm:flex-row sm:flex-wrap sm:items-center sm:justify-between", children: [
19675
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
19676
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex rounded-sm border border-grey-300 px-2.5 py-1 text-sm font-semibold text-foreground", children: [
19677
+ pair.contrastRatio.toFixed(2),
19678
+ ":1"
19679
+ ] }),
19680
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex rounded-sm bg-success-700 px-2.5 py-1 text-[0.72rem] font-semibold tracking-[0.12em] text-white uppercase", children: "AAA" })
19681
+ ] }),
19682
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-semibold text-primary-800", children: isSelected ? "Selected answer" : "Use pairing" })
19683
+ ] })
19684
+ ] })
19685
+ ] })
19686
+ ]
19687
+ }
19688
+ );
19689
+ }
19690
+ function RecommendationGroupSection({
19691
+ children,
19692
+ description,
19693
+ title
19694
+ }) {
19695
+ return /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "space-y-3", children: [
19696
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
19697
+ /* @__PURE__ */ jsxRuntime.jsx(Heading, { level: 3, size: 6, className: "text-foreground", trim: "normal", children: title }),
19698
+ /* @__PURE__ */ jsxRuntime.jsx(Text, { size: 2, children: description })
19699
+ ] }),
19700
+ children
19701
+ ] });
19702
+ }
19703
+ function DrawerSummaryItem({ label, value }) {
19704
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1 border-t border-grey-200 pt-3 first:border-t-0 first:pt-0", children: [
19705
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[0.72rem] font-semibold tracking-[0.12em] text-muted-foreground uppercase", children: label }),
19706
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-semibold text-foreground", children: value })
19707
+ ] });
19708
+ }
19709
+ function TechnicalDetailsPanel2({
19710
+ color: color2,
19711
+ copiedKey,
19712
+ onCopyValue,
19713
+ title,
19714
+ visibleFormats
19715
+ }) {
19716
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-sm border border-grey-200 bg-white", children: [
19717
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-b border-grey-200 px-4 py-4 sm:px-5", children: [
19718
+ /* @__PURE__ */ jsxRuntime.jsx(Heading, { level: 3, size: 6, className: "text-foreground", trim: "normal", children: title }),
19719
+ color2 ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
19720
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: getPairingColorDisplayName4(color2) }),
19721
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-4 overflow-hidden rounded-sm border border-black/10 bg-white", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-20 w-full sm:h-24", style: { backgroundColor: color2.hex } }) })
19722
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: "No AAA foreground available." })
19723
+ ] }),
19724
+ color2 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "divide-y divide-grey-200", children: formatValueRows2(color2, visibleFormats).map((row) => {
19725
+ const copyKey = `${title}-${row.key}`;
19726
+ return /* @__PURE__ */ jsxRuntime.jsxs(
19727
+ "div",
19728
+ {
19729
+ className: "flex flex-col items-start gap-3 px-4 py-4 sm:flex-row sm:items-start sm:justify-between sm:gap-4 sm:px-5",
19730
+ children: [
19731
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
19732
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[0.72rem] font-semibold tracking-[0.12em] text-muted-foreground uppercase", children: row.label }),
19733
+ /* @__PURE__ */ jsxRuntime.jsx(
19734
+ "p",
19735
+ {
19736
+ className: cn(
19737
+ "mt-2 text-sm text-foreground",
19738
+ row.key !== "tone" && "font-mono break-all"
19739
+ ),
19740
+ children: row.value
19741
+ }
19742
+ )
19743
+ ] }),
19744
+ row.copyable ? /* @__PURE__ */ jsxRuntime.jsx(
19745
+ Button2,
19746
+ {
19747
+ variant: "ghost",
19748
+ color: "grey",
19749
+ size: "sm",
19750
+ className: "self-start",
19751
+ onClick: () => onCopyValue(copyKey, row.value, `${row.label} copied`),
19752
+ "aria-label": `Copy ${title.toLowerCase()} ${row.label.toLowerCase()}`,
19753
+ children: copiedKey === copyKey ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
19754
+ /* @__PURE__ */ jsxRuntime.jsx(Icons.check_circle, { "data-slot": "icon", className: "size-5" }),
19755
+ "Copied"
19756
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
19757
+ /* @__PURE__ */ jsxRuntime.jsx(Icons.content_copy, { "data-slot": "icon", className: "size-5" }),
19758
+ "Copy"
19759
+ ] })
19760
+ }
19761
+ ) : null
19762
+ ]
19763
+ },
19764
+ row.key
19765
+ );
19766
+ }) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-5 py-5", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: "No technical values are shown because there is no AAA-compliant foreground for this background." }) })
19767
+ ] });
19768
+ }
19769
+ function resolveSelectionState2(nextThemeCategory, nextPrimaryKey, nextAccentKey, preferredBackgroundToken, preferredPairId) {
19770
+ const context = getPairingContext(nextThemeCategory, nextPrimaryKey, nextAccentKey);
19771
+ const selectedBackgroundToken = resolveBackgroundToken4(
19772
+ context,
19773
+ preferredBackgroundToken,
19774
+ getToneFromToken4(preferredBackgroundToken)
19775
+ );
19776
+ const selectedPairId = getPreferredPairForBackground4(
19777
+ context.pairsByBackground[selectedBackgroundToken] ?? [],
19778
+ preferredPairId
19779
+ )?.id ?? "";
19780
+ return {
19781
+ accentKey: context.accent.key,
19782
+ context,
19783
+ primaryKey: context.primary.key,
19784
+ selectedBackgroundToken,
19785
+ selectedPairId,
19786
+ themeCategory: nextThemeCategory
19787
+ };
19788
+ }
19789
+ function ColorPairingToolV4Loading() {
19790
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-8 xl:grid-cols-[minmax(18rem,24rem)_minmax(0,1fr)]", children: [
19791
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-6", children: [
19792
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-52 rounded-sm border border-grey-200 bg-grey-50" }),
19793
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-[32rem] rounded-sm border border-grey-200 bg-grey-50" })
19794
+ ] }),
19795
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-6", children: [
19796
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-96 rounded-sm border border-grey-200 bg-grey-50" }),
19797
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-64 rounded-sm border border-grey-200 bg-grey-50" }),
19798
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-72 rounded-sm border border-grey-200 bg-grey-50" })
19799
+ ] })
19800
+ ] });
19801
+ }
19802
+ function ColorPairingToolV4Content({
19803
+ onAnalyticsEvent,
19804
+ visibleFormats
19805
+ }) {
19806
+ const searchParams = navigation.useSearchParams();
19807
+ const stickyOffset = useStickyOffset(24);
19808
+ const [initialState] = React5.useState(() => getInitialPairingState4(searchParams));
19809
+ const [themeCategory, setThemeCategory] = React5.useState(initialState.themeCategory);
19810
+ const [primaryFamilyKey, setPrimaryFamilyKey] = React5.useState(initialState.primaryKey);
19811
+ const [accentFamilyKey, setAccentFamilyKey] = React5.useState(initialState.accentKey);
19812
+ const [selectedBackgroundToken, setSelectedBackgroundToken] = React5.useState(
19813
+ initialState.selectedBackgroundToken
19814
+ );
19815
+ const [selectedPairId, setSelectedPairId] = React5.useState(initialState.selectedPairId);
19816
+ const [drawerStepIndex, setDrawerStepIndex] = React5.useState(0);
19817
+ const [isCompactControlsOpen, setIsCompactControlsOpen] = React5.useState(false);
19818
+ const [, copyToClipboardRaw] = usehooks.useCopyToClipboard();
19819
+ const [copiedKey, setCopiedKey] = React5.useState(null);
19820
+ const copiedKeyTimeoutRef = React5.useRef(null);
19821
+ const resultSectionRef = React5.useRef(null);
19822
+ const technicalDetailsSectionRef = React5.useRef(null);
19823
+ const noValidStateRef = React5.useRef(/* @__PURE__ */ new Set());
19824
+ const technicalDetailsViewedRef = React5.useRef(false);
19825
+ const emitAnalyticsEvent = React5.useCallback(
19826
+ (event) => {
19827
+ onAnalyticsEvent(event);
19828
+ if (typeof window !== "undefined") {
19829
+ window.dispatchEvent(
19830
+ new CustomEvent(COLOR_PAIRING_TOOL_V4_ANALYTICS_EVENT, {
19831
+ detail: event
19832
+ })
19833
+ );
19834
+ }
19835
+ },
19836
+ [onAnalyticsEvent]
19837
+ );
19838
+ React5.useEffect(() => {
19839
+ return () => {
19840
+ if (copiedKeyTimeoutRef.current) {
19841
+ clearTimeout(copiedKeyTimeoutRef.current);
19842
+ }
19843
+ };
19844
+ }, []);
19845
+ React5.useEffect(() => {
19846
+ if (typeof window === "undefined") {
19847
+ return;
19848
+ }
19849
+ const mediaQuery = window.matchMedia(PERSISTENT_DRAWER_MIN_WIDTH_QUERY2);
19850
+ const handleChange = (event) => {
19851
+ if (event?.matches ?? mediaQuery.matches) {
19852
+ setIsCompactControlsOpen(false);
19853
+ }
19854
+ };
19855
+ handleChange();
19856
+ mediaQuery.addEventListener("change", handleChange);
19857
+ return () => {
19858
+ mediaQuery.removeEventListener("change", handleChange);
19859
+ };
19860
+ }, []);
19861
+ const themeFamilies = React5.useMemo(() => getPairingFamilies(themeCategory), [themeCategory]);
19862
+ const context = React5.useMemo(
19863
+ () => getPairingContext(themeCategory, primaryFamilyKey, accentFamilyKey),
19864
+ [themeCategory, primaryFamilyKey, accentFamilyKey]
19865
+ );
19866
+ const selectableFamilies = React5.useMemo(
19867
+ () => themeFamilies.filter((family) => family.key !== context.grey.key),
19868
+ [themeFamilies, context.grey.key]
19869
+ );
19870
+ const selectableAccentFamilies = React5.useMemo(
19871
+ () => selectableFamilies.filter((family) => family.key !== context.primary.key),
19872
+ [selectableFamilies, context.primary.key]
19873
+ );
19874
+ const selectedBackground = React5.useMemo(
19875
+ () => context.backgrounds.find((background) => background.token === selectedBackgroundToken) ?? context.backgrounds[0] ?? null,
19876
+ [context.backgrounds, selectedBackgroundToken]
19877
+ );
19878
+ const selectedBackgroundPairs = React5.useMemo(
19879
+ () => selectedBackground ? context.pairsByBackground[selectedBackground.token] ?? [] : [],
19880
+ [context.pairsByBackground, selectedBackground]
19881
+ );
19882
+ const bestRecommendedPair = React5.useMemo(
19883
+ () => getPreferredPairForBackground4(selectedBackgroundPairs),
19884
+ [selectedBackgroundPairs]
19885
+ );
19886
+ const selectedPair = React5.useMemo(
19887
+ () => getPreferredPairForBackground4(selectedBackgroundPairs, selectedPairId),
19888
+ [selectedBackgroundPairs, selectedPairId]
19889
+ );
19890
+ const whiteForegroundExample = React5.useMemo(
19891
+ () => selectedBackground && supportsWhiteForegroundPreview(selectedBackground) ? getWhiteForegroundPair(selectedBackground) : null,
19892
+ [selectedBackground]
19893
+ );
19894
+ const previewPair = selectedPair ?? whiteForegroundExample ?? null;
19895
+ const detailForeground = selectedPair?.foreground ?? whiteForegroundExample?.foreground ?? null;
19896
+ const currentPairSupportText = React5.useMemo(
19897
+ () => getMainPairingSupportCopy(previewPair, bestRecommendedPair, context),
19898
+ [bestRecommendedPair, context, previewPair]
19899
+ );
19900
+ const recommendationItems = React5.useMemo(() => {
19901
+ return selectedBackgroundPairs.map((pair) => {
19902
+ const category = getRecommendationCategory2(pair, bestRecommendedPair, context);
19903
+ return {
19904
+ category,
19905
+ categoryLabel: getRecommendationCategoryLabel2(category),
19906
+ pair
19907
+ };
19908
+ }).sort(
19909
+ (left, right) => getRecommendationSortRank2(left.category) - getRecommendationSortRank2(right.category)
19910
+ );
19911
+ }, [bestRecommendedPair, context, selectedBackgroundPairs]);
19912
+ const alternativeRecommendationGroups = React5.useMemo(
19913
+ () => buildRecommendationGroups(
19914
+ recommendationItems.filter((item) => item.pair.id !== selectedPair?.id)
19915
+ ),
19916
+ [recommendationItems, selectedPair?.id]
19917
+ );
19918
+ const liveAnnouncement = React5.useMemo(
19919
+ () => getLiveAnnouncement2(previewPair, selectedBackground),
19920
+ [previewPair, selectedBackground]
19921
+ );
19922
+ const shareBackgroundToken = selectedBackground?.token ?? selectedBackgroundToken;
19923
+ const shareUrl = React5.useMemo(() => {
19924
+ const params = new URLSearchParams();
19925
+ params.set("palette", themeCategory);
19926
+ params.set("primary", context.primary.key);
19927
+ params.set("accent", context.accent.key);
19928
+ if (shareBackgroundToken) {
19929
+ params.set("background", shareBackgroundToken);
19930
+ }
19931
+ if (selectedPairId) {
19932
+ params.set("pair", selectedPairId);
19933
+ }
19934
+ const query = params.toString();
19935
+ return `${COLOR_PAIRING_TOOL_V4_PATH}${query ? `?${query}` : ""}`;
19936
+ }, [context.accent.key, context.primary.key, shareBackgroundToken, selectedPairId, themeCategory]);
19937
+ const activeDrawerStep = COLOR_PAIRING_TOOL_DRAWER_STEPS2[drawerStepIndex];
19938
+ const isFirstDrawerStep = drawerStepIndex === 0;
19939
+ const isLastDrawerStep = drawerStepIndex === COLOR_PAIRING_TOOL_DRAWER_STEPS2.length - 1;
19940
+ const desktopSidebarStyle = React5.useMemo(
19941
+ () => ({
19942
+ "--tool-sidebar-max-height": `calc(100vh - ${stickyOffset}px)`,
19943
+ "--tool-sidebar-top": `${stickyOffset}px`
19944
+ }),
19945
+ [stickyOffset]
19946
+ );
19947
+ const goToDrawerStep = React5.useCallback((stepIndex) => {
19948
+ setDrawerStepIndex(Math.max(0, Math.min(stepIndex, COLOR_PAIRING_TOOL_DRAWER_STEPS2.length - 1)));
19949
+ }, []);
19950
+ const goToNextDrawerStep = React5.useCallback(() => {
19951
+ setDrawerStepIndex(
19952
+ (currentStep) => Math.min(currentStep + 1, COLOR_PAIRING_TOOL_DRAWER_STEPS2.length - 1)
19953
+ );
19954
+ }, []);
19955
+ const goToPreviousDrawerStep = React5.useCallback(() => {
19956
+ setDrawerStepIndex((currentStep) => Math.max(currentStep - 1, 0));
19957
+ }, []);
19958
+ const updateUrlParams = React5.useCallback((nextState) => {
19959
+ const params = new URLSearchParams(window.location.search);
19960
+ params.delete("family");
19961
+ params.set("palette", nextState.themeCategory);
19962
+ params.set("primary", nextState.primaryKey);
19963
+ params.set("accent", nextState.accentKey);
19964
+ params.set("background", nextState.selectedBackgroundToken);
19965
+ if (nextState.selectedPairId) {
19966
+ params.set("pair", nextState.selectedPairId);
19967
+ } else {
19968
+ params.delete("pair");
19969
+ }
19970
+ window.history.replaceState(
19971
+ null,
19972
+ "",
19973
+ `${window.location.pathname}?${params.toString()}${window.location.hash}`
19974
+ );
19975
+ }, []);
19976
+ const applyResolvedSelection = React5.useCallback(
19977
+ (nextState) => {
19978
+ setThemeCategory(nextState.themeCategory);
19979
+ setPrimaryFamilyKey(nextState.primaryKey);
19980
+ setAccentFamilyKey(nextState.accentKey);
19981
+ setSelectedBackgroundToken(nextState.selectedBackgroundToken);
19982
+ setSelectedPairId(nextState.selectedPairId);
19983
+ updateUrlParams(nextState);
19984
+ },
19985
+ [updateUrlParams]
19986
+ );
19987
+ const buildAnalyticsContext = React5.useCallback(
19988
+ (overrides) => ({
19989
+ accentKey: context.accent.key,
19990
+ backgroundToken: selectedBackground?.token,
19991
+ foregroundToken: selectedPair?.foreground.token,
19992
+ pairId: selectedPair?.id,
19993
+ palette: themeCategory,
19994
+ primaryKey: context.primary.key,
19995
+ ...overrides
19996
+ }),
19997
+ [context.accent.key, context.primary.key, selectedBackground, selectedPair, themeCategory]
19998
+ );
19999
+ const copyValue = React5.useCallback(
20000
+ (copyKey, value, toastLabel, analyticsEvent) => {
20001
+ copyToClipboardRaw(value);
20002
+ setCopiedKey(copyKey);
20003
+ sonner.toast(toastLabel, { duration: 2e3 });
20004
+ if (analyticsEvent) {
20005
+ emitAnalyticsEvent(analyticsEvent);
20006
+ }
20007
+ if (copiedKeyTimeoutRef.current) {
20008
+ clearTimeout(copiedKeyTimeoutRef.current);
20009
+ }
20010
+ copiedKeyTimeoutRef.current = setTimeout(() => {
20011
+ setCopiedKey(null);
20012
+ copiedKeyTimeoutRef.current = null;
20013
+ }, 2e3);
20014
+ },
20015
+ [copyToClipboardRaw, emitAnalyticsEvent]
20016
+ );
16972
20017
  const handleThemeCategoryChange = (nextThemeCategory) => {
16973
- syncSelection(
20018
+ const nextState = resolveSelectionState2(
16974
20019
  nextThemeCategory,
16975
20020
  primaryFamilyKey,
16976
20021
  accentFamilyKey,
16977
20022
  selectedBackgroundToken,
16978
- selectedPairId
20023
+ null
16979
20024
  );
20025
+ applyResolvedSelection(nextState);
20026
+ emitAnalyticsEvent({
20027
+ name: "palette_change",
20028
+ accentKey: nextState.accentKey,
20029
+ backgroundToken: nextState.selectedBackgroundToken,
20030
+ pairId: nextState.selectedPairId,
20031
+ palette: nextState.themeCategory,
20032
+ primaryKey: nextState.primaryKey
20033
+ });
16980
20034
  };
16981
20035
  const handlePrimaryColorChange = (nextPrimaryKey) => {
16982
20036
  const nextAccentKey = nextPrimaryKey === accentFamilyKey ? getDefaultAccentFamilyKey(themeCategory, nextPrimaryKey) : accentFamilyKey;
16983
- syncSelection(
20037
+ const nextState = resolveSelectionState2(
16984
20038
  themeCategory,
16985
20039
  nextPrimaryKey,
16986
20040
  nextAccentKey,
16987
20041
  selectedBackgroundToken,
16988
- selectedPairId
20042
+ null
16989
20043
  );
20044
+ applyResolvedSelection(nextState);
20045
+ emitAnalyticsEvent({
20046
+ name: "primary_change",
20047
+ accentKey: nextState.accentKey,
20048
+ backgroundToken: nextState.selectedBackgroundToken,
20049
+ pairId: nextState.selectedPairId,
20050
+ palette: nextState.themeCategory,
20051
+ primaryKey: nextState.primaryKey
20052
+ });
16990
20053
  };
16991
20054
  const handleAccentColorChange = (nextAccentKey) => {
16992
20055
  if (nextAccentKey === primaryFamilyKey) return;
16993
- syncSelection(
20056
+ const nextState = resolveSelectionState2(
16994
20057
  themeCategory,
16995
20058
  primaryFamilyKey,
16996
20059
  nextAccentKey,
16997
20060
  selectedBackgroundToken,
16998
- selectedPairId
20061
+ null
16999
20062
  );
20063
+ applyResolvedSelection(nextState);
20064
+ emitAnalyticsEvent({
20065
+ name: "accent_change",
20066
+ accentKey: nextState.accentKey,
20067
+ backgroundToken: nextState.selectedBackgroundToken,
20068
+ pairId: nextState.selectedPairId,
20069
+ palette: nextState.themeCategory,
20070
+ primaryKey: nextState.primaryKey
20071
+ });
17000
20072
  };
17001
20073
  const handleBackgroundChange = (nextSelectedBackgroundToken) => {
17002
- const nextSelectedPairId = getPreferredPairForBackground2(
17003
- context.pairsByBackground[nextSelectedBackgroundToken] ?? [],
17004
- selectedPairId
17005
- )?.id ?? "";
17006
- setSelectedBackgroundToken(nextSelectedBackgroundToken);
17007
- setSelectedPairId(nextSelectedPairId);
17008
- updateUrlParams(
17009
- themeCategory,
17010
- context.primary.key,
17011
- context.accent.key,
17012
- nextSelectedBackgroundToken,
17013
- nextSelectedPairId
17014
- );
20074
+ const nextSelectedPairId = getPreferredPairForBackground4(context.pairsByBackground[nextSelectedBackgroundToken] ?? [])?.id ?? "";
20075
+ const nextState = {
20076
+ accentKey: context.accent.key,
20077
+ context,
20078
+ primaryKey: context.primary.key,
20079
+ selectedBackgroundToken: nextSelectedBackgroundToken,
20080
+ selectedPairId: nextSelectedPairId,
20081
+ themeCategory
20082
+ };
20083
+ applyResolvedSelection(nextState);
20084
+ emitAnalyticsEvent({
20085
+ name: "background_selection",
20086
+ ...buildAnalyticsContext({
20087
+ backgroundToken: nextSelectedBackgroundToken,
20088
+ foregroundToken: context.pairsByBackground[nextSelectedBackgroundToken]?.find(
20089
+ (pair) => pair.id === nextSelectedPairId
20090
+ )?.foreground.token,
20091
+ pairId: nextSelectedPairId
20092
+ })
20093
+ });
20094
+ if (typeof window !== "undefined" && window.matchMedia(MOBILE_RESULT_SCROLL_QUERY2).matches) {
20095
+ requestAnimationFrame(() => {
20096
+ resultSectionRef.current?.scrollIntoView({ behavior: "smooth", block: "start" });
20097
+ });
20098
+ }
17015
20099
  };
17016
- const handlePairChange = (nextSelectedPairId) => {
20100
+ const handlePairChange = (nextSelectedPairId, source) => {
17017
20101
  if (!selectedBackground) return;
20102
+ const nextPair = selectedBackgroundPairs.find((pair) => pair.id === nextSelectedPairId) ?? null;
17018
20103
  setSelectedPairId(nextSelectedPairId);
17019
- updateUrlParams(
17020
- themeCategory,
17021
- context.primary.key,
17022
- context.accent.key,
17023
- selectedBackground.token,
17024
- nextSelectedPairId
17025
- );
20104
+ updateUrlParams({
20105
+ accentKey: context.accent.key,
20106
+ context,
20107
+ primaryKey: context.primary.key,
20108
+ selectedBackgroundToken: selectedBackground.token,
20109
+ selectedPairId: nextSelectedPairId,
20110
+ themeCategory
20111
+ });
20112
+ emitAnalyticsEvent({
20113
+ name: "foreground_selection",
20114
+ ...buildAnalyticsContext({
20115
+ foregroundToken: nextPair?.foreground.token,
20116
+ pairId: nextSelectedPairId,
20117
+ source
20118
+ })
20119
+ });
20120
+ if (bestRecommendedPair && nextSelectedPairId !== bestRecommendedPair.id) {
20121
+ emitAnalyticsEvent({
20122
+ name: "alternative_combination_selected",
20123
+ ...buildAnalyticsContext({
20124
+ foregroundToken: nextPair?.foreground.token,
20125
+ pairId: nextSelectedPairId,
20126
+ source
20127
+ })
20128
+ });
20129
+ }
17026
20130
  };
20131
+ React5.useEffect(() => {
20132
+ if (!selectedBackground || selectedBackgroundPairs.length > 0) {
20133
+ return;
20134
+ }
20135
+ const key = `${themeCategory}:${context.primary.key}:${context.accent.key}:${selectedBackground.token}`;
20136
+ if (noValidStateRef.current.has(key)) {
20137
+ return;
20138
+ }
20139
+ noValidStateRef.current.add(key);
20140
+ emitAnalyticsEvent({
20141
+ name: "no_valid_combination_state",
20142
+ ...buildAnalyticsContext({
20143
+ backgroundToken: selectedBackground.token
20144
+ })
20145
+ });
20146
+ }, [
20147
+ buildAnalyticsContext,
20148
+ context.accent.key,
20149
+ context.primary.key,
20150
+ emitAnalyticsEvent,
20151
+ selectedBackground,
20152
+ selectedBackgroundPairs.length,
20153
+ themeCategory
20154
+ ]);
20155
+ React5.useEffect(() => {
20156
+ if (technicalDetailsViewedRef.current) {
20157
+ return;
20158
+ }
20159
+ const section = technicalDetailsSectionRef.current;
20160
+ if (!section) {
20161
+ return;
20162
+ }
20163
+ const emitViewedEvent = () => {
20164
+ if (technicalDetailsViewedRef.current) {
20165
+ return;
20166
+ }
20167
+ technicalDetailsViewedRef.current = true;
20168
+ emitAnalyticsEvent({
20169
+ name: "technical_details_viewed",
20170
+ ...buildAnalyticsContext({
20171
+ source: "details"
20172
+ })
20173
+ });
20174
+ };
20175
+ if (typeof IntersectionObserver === "undefined") {
20176
+ const rect = section.getBoundingClientRect();
20177
+ const viewportHeight = window.innerHeight || document.documentElement.clientHeight;
20178
+ if (rect.top < viewportHeight && rect.bottom > 0) {
20179
+ emitViewedEvent();
20180
+ }
20181
+ return;
20182
+ }
20183
+ const observer = new IntersectionObserver(
20184
+ (entries) => {
20185
+ const [entry] = entries;
20186
+ if (entry?.isIntersecting) {
20187
+ emitViewedEvent();
20188
+ observer.disconnect();
20189
+ }
20190
+ },
20191
+ {
20192
+ threshold: 0.2
20193
+ }
20194
+ );
20195
+ observer.observe(section);
20196
+ return () => {
20197
+ observer.disconnect();
20198
+ };
20199
+ }, [buildAnalyticsContext, emitAnalyticsEvent]);
17027
20200
  if (!selectedBackground) {
17028
- return /* @__PURE__ */ jsxRuntime.jsx(Card, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-6", children: [
17029
- /* @__PURE__ */ jsxRuntime.jsx(Heading, { level: 3, size: 5, className: "text-foreground", trim: "normal", children: "No approved background tones available" }),
17030
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-3 text-base text-muted-foreground", children: "No approved tones are available for the current palette." })
17031
- ] }) });
20201
+ return /* @__PURE__ */ jsxRuntime.jsxs(Card, { className: "px-6 py-6", children: [
20202
+ /* @__PURE__ */ jsxRuntime.jsx(Heading, { level: 2, size: 5, className: "text-foreground", trim: "normal", children: "No approved background tones available" }),
20203
+ /* @__PURE__ */ jsxRuntime.jsx(Text, { size: 2, className: "mt-3", children: "No approved tones are available for the current palette and colour selection." })
20204
+ ] });
17032
20205
  }
17033
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-8 lg:grid-cols-[18rem_minmax(0,1fr)]", children: [
17034
- /* @__PURE__ */ jsxRuntime.jsx("aside", { className: "bg-grey-50/60 p-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-8", children: [
17035
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
17036
- /* @__PURE__ */ jsxRuntime.jsx(Heading, { level: 3, size: 5, className: "text-foreground", trim: "normal", children: "Configuration" }),
17037
- /* @__PURE__ */ jsxRuntime.jsx(Text, { size: 2, children: "Choose a palette, set your primary and accent families, then select an approved background." })
17038
- ] }),
17039
- /* @__PURE__ */ jsxRuntime.jsx(SidebarStep, { step: 1, title: "Select your palette", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid gap-2", children: ["brand", "aboriginal"].map((palette) => {
17040
- const isSelected = themeCategory === palette;
17041
- const label = palette === "brand" ? "Brand palette" : "Aboriginal palette";
17042
- return /* @__PURE__ */ jsxRuntime.jsx(
20206
+ const compactControlsSummary = `${themeCategory === "brand" ? "Brand" : "Aboriginal"} palette, ${context.primary.label} primary, ${context.accent.label} accent, ${getPairingColorDisplayName4(
20207
+ selectedBackground
20208
+ )} background.`;
20209
+ const renderControlsPanel = (isOverlay = false) => /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
20210
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-b border-grey-200 px-5 py-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-4", children: [
20211
+ /* @__PURE__ */ jsxRuntime.jsx(Heading, { level: 2, size: 5, className: "text-foreground", trim: "normal", children: "Configuration" }),
20212
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
20213
+ !isFirstDrawerStep ? /* @__PURE__ */ jsxRuntime.jsxs(Button2, { variant: "ghost", color: "grey", size: "sm", onClick: goToPreviousDrawerStep, children: [
20214
+ /* @__PURE__ */ jsxRuntime.jsx(Icons.west, { "data-slot": "icon", className: "size-5" }),
20215
+ "Back"
20216
+ ] }) : null,
20217
+ isOverlay ? /* @__PURE__ */ jsxRuntime.jsx(
20218
+ Button2,
20219
+ {
20220
+ variant: "ghost",
20221
+ color: "grey",
20222
+ size: "icon",
20223
+ onClick: () => setIsCompactControlsOpen(false),
20224
+ "aria-label": "Close configuration",
20225
+ children: /* @__PURE__ */ jsxRuntime.jsx(Icons.close, { "data-slot": "icon", className: "size-5" })
20226
+ }
20227
+ ) : null
20228
+ ] })
20229
+ ] }) }),
20230
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-b border-grey-200 px-5 py-4", children: [
20231
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
20232
+ COLOR_PAIRING_TOOL_DRAWER_STEPS2.map((step, index) => /* @__PURE__ */ jsxRuntime.jsx(
17043
20233
  "button",
17044
20234
  {
17045
20235
  type: "button",
17046
- "aria-label": `Select ${label}`,
17047
- "aria-pressed": isSelected,
17048
- onClick: () => handleThemeCategoryChange(palette),
17049
- className: cn(
17050
- "rounded-sm border px-3 py-2.5 text-left text-sm font-semibold transition-colors",
17051
- isSelected ? "border-primary-800 bg-primary-800 text-white" : "border-grey-300 bg-background text-foreground hover:border-primary-800 hover:bg-primary-50"
17052
- ),
17053
- children: label
20236
+ "aria-current": index === drawerStepIndex ? "step" : void 0,
20237
+ "aria-label": `${step.eyebrow}: ${step.title}`,
20238
+ onClick: () => goToDrawerStep(index),
20239
+ className: "flex-1 rounded-sm focus-visible:ring-2 focus-visible:ring-primary-700 focus-visible:ring-offset-2 focus-visible:outline-hidden",
20240
+ children: /* @__PURE__ */ jsxRuntime.jsx(
20241
+ "span",
20242
+ {
20243
+ className: cn(
20244
+ "block h-1.5 rounded-full transition-colors",
20245
+ index <= drawerStepIndex ? "bg-primary-800" : "bg-grey-200"
20246
+ )
20247
+ }
20248
+ )
17054
20249
  },
17055
- palette
17056
- );
17057
- }) }) }),
17058
- /* @__PURE__ */ jsxRuntime.jsx(
17059
- SidebarStep,
17060
- {
17061
- step: 2,
17062
- title: "Choose your colours",
17063
- description: "Grey is added automatically from the selected palette.",
17064
- children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-5", children: [
17065
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
17066
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-semibold text-foreground", children: "Primary colour" }),
17067
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-3 gap-2", children: selectableFamilies.map((family) => {
17068
- const swatchTone = 800;
17069
- const isSelected = family.key === context.primary.key;
17070
- const label = getFamilySelectorLabel2(family, themeCategory, "primary colour");
20250
+ step.id
20251
+ )),
20252
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mt-2 basis-full text-[0.68rem] font-semibold tracking-[0.12em] text-primary-800 uppercase sm:mt-0 sm:ml-2 sm:basis-auto sm:text-[0.72rem]", children: activeDrawerStep.eyebrow })
20253
+ ] }),
20254
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-4 space-y-2", children: [
20255
+ /* @__PURE__ */ jsxRuntime.jsx(Heading, { level: 3, size: 5, className: "text-foreground", trim: "normal", children: activeDrawerStep.title }),
20256
+ /* @__PURE__ */ jsxRuntime.jsx(Text, { size: 2, children: activeDrawerStep.description })
20257
+ ] })
20258
+ ] }),
20259
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative flex-1 overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsxs(
20260
+ "div",
20261
+ {
20262
+ className: "flex h-full transition-transform duration-300 ease-out",
20263
+ style: { transform: `translateX(-${drawerStepIndex * 100}%)` },
20264
+ children: [
20265
+ /* @__PURE__ */ jsxRuntime.jsx("section", { className: "h-full w-full shrink-0 overflow-y-auto px-5 py-5", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-6 pr-1", children: [
20266
+ /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "space-y-3", children: [
20267
+ /* @__PURE__ */ jsxRuntime.jsx(Heading, { level: 4, size: 6, className: "mb-3 text-foreground", trim: "normal", children: "Palette" }),
20268
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 gap-2 sm:grid-cols-2", children: ["brand", "aboriginal"].map((palette) => {
20269
+ const isSelected = themeCategory === palette;
20270
+ const label = palette === "brand" ? "Brand palette" : "Aboriginal palette";
17071
20271
  return /* @__PURE__ */ jsxRuntime.jsx(
17072
- "button",
20272
+ SelectorButton2,
17073
20273
  {
17074
- type: "button",
17075
- "aria-label": `Select ${label} as primary colour`,
17076
- "aria-pressed": isSelected,
20274
+ label,
20275
+ isSelected,
20276
+ onClick: () => handleThemeCategoryChange(palette)
20277
+ },
20278
+ palette
20279
+ );
20280
+ }) })
20281
+ ] }),
20282
+ /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "space-y-3", children: [
20283
+ /* @__PURE__ */ jsxRuntime.jsx(Heading, { level: 4, size: 6, className: "mb-3 text-foreground", trim: "normal", children: "Primary colour family" }),
20284
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 gap-2 sm:grid-cols-2", children: selectableFamilies.map((family) => {
20285
+ const label = getFamilySelectorLabel4(family, themeCategory, "primary colour");
20286
+ return /* @__PURE__ */ jsxRuntime.jsx(
20287
+ SelectorButton2,
20288
+ {
20289
+ label,
20290
+ isSelected: family.key === context.primary.key,
17077
20291
  onClick: () => handlePrimaryColorChange(family.key),
17078
- className: cn(
17079
- "min-h-11 rounded-sm border px-2 py-2 text-center text-[0.8rem] leading-5 font-semibold transition-transform",
17080
- isSelected ? "ring-2 ring-primary-700 ring-offset-2 ring-offset-grey-50/60" : "hover:-translate-y-px"
17081
- ),
17082
- style: {
17083
- backgroundColor: getFamilySwatchColor2(family, swatchTone),
17084
- color: getReadableTextColor(swatchTone),
17085
- borderColor: "rgba(0, 0, 0, 0.12)"
17086
- },
17087
- title: label,
17088
- children: label
20292
+ swatch: getFamilySwatchColor4(family, 800)
17089
20293
  },
17090
20294
  family.key
17091
20295
  );
17092
20296
  }) })
17093
20297
  ] }),
17094
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
17095
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-semibold text-foreground", children: "Accent colour" }),
17096
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-3 gap-2", children: selectableAccentFamilies.map((family) => {
17097
- const swatchTone = 600;
17098
- const isSelected = family.key === context.accent.key;
17099
- const label = getFamilySelectorLabel2(family, themeCategory, "accent colour");
20298
+ /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "space-y-3", children: [
20299
+ /* @__PURE__ */ jsxRuntime.jsx(Heading, { level: 4, size: 6, className: "mb-3 text-foreground", trim: "normal", children: "Accent colour family" }),
20300
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 gap-2 sm:grid-cols-2", children: selectableAccentFamilies.map((family) => {
20301
+ const label = getFamilySelectorLabel4(family, themeCategory, "accent colour");
17100
20302
  return /* @__PURE__ */ jsxRuntime.jsx(
17101
- "button",
20303
+ SelectorButton2,
17102
20304
  {
17103
- type: "button",
17104
- "aria-label": `Select ${label} as accent colour`,
17105
- "aria-pressed": isSelected,
20305
+ label,
20306
+ isSelected: family.key === context.accent.key,
17106
20307
  onClick: () => handleAccentColorChange(family.key),
17107
- className: cn(
17108
- "min-h-11 rounded-sm border px-2 py-2 text-center text-[0.8rem] leading-5 font-semibold transition-transform",
17109
- isSelected ? "ring-2 ring-primary-700 ring-offset-2 ring-offset-grey-50/60" : "hover:-translate-y-px"
17110
- ),
17111
- style: {
17112
- backgroundColor: getFamilySwatchColor2(family, swatchTone),
17113
- color: getReadableTextColor(swatchTone),
17114
- borderColor: "rgba(0, 0, 0, 0.12)"
17115
- },
17116
- title: label,
17117
- children: label
20308
+ swatch: getFamilySwatchColor4(family, 600)
17118
20309
  },
17119
20310
  family.key
17120
20311
  );
17121
20312
  }) })
20313
+ ] }),
20314
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-t border-grey-200 pt-4", children: [
20315
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-semibold text-foreground", children: "Grey is always included" }),
20316
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: "Neutral grey options are automatically added so every selection includes a practical fallback family." })
17122
20317
  ] })
17123
- ] })
17124
- }
17125
- ),
17126
- /* @__PURE__ */ jsxRuntime.jsx(SidebarStep, { step: 3, title: "Pick a background", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
17127
- /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm text-muted-foreground", children: [
17128
- "Selected:",
17129
- " ",
17130
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold text-foreground", children: selectedBackground.token })
17131
- ] }),
17132
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-4 gap-2", children: context.backgrounds.map((background) => {
17133
- const hasPairs = (context.pairsByBackground[background.token]?.length ?? 0) > 0;
17134
- const isSelected = selectedBackground.token === background.token;
17135
- return /* @__PURE__ */ jsxRuntime.jsx(
17136
- "button",
20318
+ ] }) }),
20319
+ /* @__PURE__ */ jsxRuntime.jsx("section", { className: "h-full w-full shrink-0 overflow-y-auto px-5 py-5", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-6 pr-1", children: context.backgroundGroups.map((group, index) => /* @__PURE__ */ jsxRuntime.jsxs(
20320
+ "section",
17137
20321
  {
17138
- type: "button",
17139
- "aria-label": hasPairs ? `Select ${background.token} background` : `Select ${background.token} background with no AAA pairings`,
17140
- "aria-pressed": isSelected,
17141
- onClick: () => handleBackgroundChange(background.token),
17142
- className: cn(
17143
- "relative aspect-square rounded-sm border transition-transform",
17144
- isSelected ? "ring-2 ring-primary-700 ring-offset-2 ring-offset-grey-50/60" : "hover:-translate-y-px",
17145
- !hasPairs && "opacity-80"
17146
- ),
17147
- style: {
17148
- backgroundColor: background.hex,
17149
- borderColor: "rgba(0, 0, 0, 0.14)"
17150
- },
17151
- title: background.token,
17152
- children: !hasPairs ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute top-1/2 left-1/2 h-0.5 w-5 -translate-x-1/2 -translate-y-1/2 rotate-45 rounded-full bg-white shadow-[0_0_0_1px_rgba(0,0,0,0.28)]" }) : null
20322
+ className: cn("space-y-3", index > 0 && "border-t border-grey-200 pt-6"),
20323
+ children: [
20324
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
20325
+ /* @__PURE__ */ jsxRuntime.jsxs(Heading, { level: 4, size: 6, className: "text-foreground", trim: "normal", children: [
20326
+ group.family.label,
20327
+ " backgrounds"
20328
+ ] }),
20329
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: group.label })
20330
+ ] }),
20331
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid gap-3", children: group.backgrounds.map((background) => /* @__PURE__ */ jsxRuntime.jsx(
20332
+ BackgroundSwatchButton2,
20333
+ {
20334
+ background,
20335
+ hasPairs: (context.pairsByBackground[background.token]?.length ?? 0) > 0,
20336
+ isSelected: selectedBackground.token === background.token,
20337
+ onClick: () => handleBackgroundChange(background.token)
20338
+ },
20339
+ background.token
20340
+ )) })
20341
+ ]
17153
20342
  },
17154
- background.token
17155
- );
17156
- }) })
17157
- ] }) })
17158
- ] }) }),
17159
- /* @__PURE__ */ jsxRuntime.jsxs("main", { className: "space-y-8", children: [
17160
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
17161
- /* @__PURE__ */ jsxRuntime.jsx(Heading, { level: 3, size: 5, className: "text-foreground", trim: "normal", children: "Live Preview & Results" }),
17162
- /* @__PURE__ */ jsxRuntime.jsx(Text, { size: 2, children: "Review the selected pairing in context, then compare the available AAA combinations for your chosen background." })
17163
- ] }),
17164
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-5", children: [
17165
- selectedPair ? /* @__PURE__ */ jsxRuntime.jsx(
17166
- PreviewHeroCard,
20343
+ group.key
20344
+ )) }) }),
20345
+ /* @__PURE__ */ jsxRuntime.jsx("section", { className: "h-full w-full shrink-0 overflow-y-auto px-5 py-5", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-6 pr-1", children: [
20346
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-sm border border-grey-200 bg-white px-4 py-4", children: [
20347
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
20348
+ /* @__PURE__ */ jsxRuntime.jsx(Heading, { level: 4, size: 6, className: "text-foreground", trim: "normal", children: "Current configuration" }),
20349
+ /* @__PURE__ */ jsxRuntime.jsx(Text, { size: 2, children: "The drawer only sets the palette, families, and background. The result panel is where the pairing is shown and, if needed, overridden." })
20350
+ ] }),
20351
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-5 space-y-3", children: [
20352
+ /* @__PURE__ */ jsxRuntime.jsx(
20353
+ DrawerSummaryItem,
20354
+ {
20355
+ label: "Palette",
20356
+ value: themeCategory === "brand" ? "Brand palette" : "Aboriginal palette"
20357
+ }
20358
+ ),
20359
+ /* @__PURE__ */ jsxRuntime.jsx(DrawerSummaryItem, { label: "Primary family", value: context.primary.label }),
20360
+ /* @__PURE__ */ jsxRuntime.jsx(DrawerSummaryItem, { label: "Accent family", value: context.accent.label }),
20361
+ /* @__PURE__ */ jsxRuntime.jsx(
20362
+ DrawerSummaryItem,
20363
+ {
20364
+ label: "Background",
20365
+ value: getPairingColorDisplayName4(selectedBackground)
20366
+ }
20367
+ )
20368
+ ] })
20369
+ ] }),
20370
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-sm border border-grey-200 bg-grey-50 px-4 py-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
20371
+ /* @__PURE__ */ jsxRuntime.jsx(Heading, { level: 4, size: 6, className: "text-foreground", trim: "normal", children: "Review the result on the right" }),
20372
+ /* @__PURE__ */ jsxRuntime.jsx(Text, { size: 2, children: "The right panel always shows the current NSW default pairing for this selection. Alternative AAA options stay there as a secondary override path." })
20373
+ ] }) })
20374
+ ] }) })
20375
+ ]
20376
+ }
20377
+ ) }),
20378
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t border-grey-200 px-5 py-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between", children: [
20379
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-10 flex-1", children: isLastDrawerStep ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: "Review the NSW recommendation in the result panel. Use alternatives there only if you need a different approved treatment." }) : null }),
20380
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex w-full items-center gap-2 sm:w-auto sm:flex-none", children: [
20381
+ isOverlay && isLastDrawerStep ? /* @__PURE__ */ jsxRuntime.jsx(
20382
+ Button2,
17167
20383
  {
17168
- familySummary,
17169
- isRecommended: Boolean(selectedPair),
17170
- pair: selectedPair
20384
+ color: "primary",
20385
+ className: "w-full sm:w-auto sm:min-w-40",
20386
+ onClick: () => setIsCompactControlsOpen(false),
20387
+ children: "Review result"
17171
20388
  }
17172
- ) : /* @__PURE__ */ jsxRuntime.jsx(PreviewFallbackCard2, { background: selectedBackground }),
17173
- /* @__PURE__ */ jsxRuntime.jsx(AccessibilityScoreCard, { pair: selectedPair })
17174
- ] }),
17175
- /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "space-y-4", children: [
17176
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
17177
- /* @__PURE__ */ jsxRuntime.jsx(Heading, { level: 3, size: 5, className: "text-foreground", trim: "normal", children: "Recommended Combinations" }),
17178
- /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-base text-muted-foreground", children: [
17179
- "AAA-recommended foregrounds for",
17180
- " ",
17181
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold text-foreground", children: selectedBackground.token }),
17182
- "."
17183
- ] })
17184
- ] }),
17185
- selectedBackgroundPairs.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid gap-4 md:grid-cols-2 xl:grid-cols-3", children: selectedBackgroundPairs.map((pair) => /* @__PURE__ */ jsxRuntime.jsx(
17186
- RecommendedPairCard,
20389
+ ) : null,
20390
+ !isLastDrawerStep ? /* @__PURE__ */ jsxRuntime.jsxs(Button2, { color: "primary", className: "w-full sm:w-auto", onClick: goToNextDrawerStep, children: [
20391
+ "Continue",
20392
+ /* @__PURE__ */ jsxRuntime.jsx(Icons.east, { "data-slot": "icon", className: "size-5" })
20393
+ ] }) : null
20394
+ ] })
20395
+ ] }) })
20396
+ ] });
20397
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-8 xl:grid-cols-[minmax(18rem,24rem)_minmax(0,1fr)]", children: [
20398
+ /* @__PURE__ */ jsxRuntime.jsx(
20399
+ "div",
20400
+ {
20401
+ "data-slot": "tool-sidebar",
20402
+ className: "hidden xl:sticky xl:top-[var(--tool-sidebar-top)] xl:block xl:self-start",
20403
+ style: desktopSidebarStyle,
20404
+ children: /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "h-[40rem] max-h-[40rem] gap-0 overflow-hidden border-grey-200 bg-grey-50/60 py-0 sm:h-[44rem] sm:max-h-[44rem] xl:h-[var(--tool-sidebar-max-height)] xl:max-h-[var(--tool-sidebar-max-height)]", children: renderControlsPanel() })
20405
+ }
20406
+ ),
20407
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-slot": "tool-results", className: "space-y-6", children: [
20408
+ /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "space-y-4 xl:hidden", children: [
20409
+ /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "gap-4 px-5 py-5", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-4 sm:flex-row sm:items-end sm:justify-between", children: [
20410
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
20411
+ /* @__PURE__ */ jsxRuntime.jsx(Heading, { level: 2, size: 5, className: "text-foreground", trim: "normal", children: "Configuration" }),
20412
+ /* @__PURE__ */ jsxRuntime.jsx(Text, { size: 2, children: "Open the drawer to change palette, colour families, or background. The result panel always shows the current NSW pairing for this selection." }),
20413
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: compactControlsSummary })
20414
+ ] }),
20415
+ /* @__PURE__ */ jsxRuntime.jsxs(
20416
+ Button2,
20417
+ {
20418
+ color: "primary",
20419
+ className: "w-full sm:w-auto",
20420
+ onClick: () => setIsCompactControlsOpen(true),
20421
+ children: [
20422
+ /* @__PURE__ */ jsxRuntime.jsx(Icons.edit_square, { "data-slot": "icon", className: "size-5" }),
20423
+ "Open configuration"
20424
+ ]
20425
+ }
20426
+ )
20427
+ ] }) }),
20428
+ /* @__PURE__ */ jsxRuntime.jsx(Sheet, { open: isCompactControlsOpen, onOpenChange: setIsCompactControlsOpen, children: /* @__PURE__ */ jsxRuntime.jsxs(
20429
+ SheetContent,
17187
20430
  {
17188
- pair,
17189
- isSelected: selectedPair?.id === pair.id,
17190
- onSelect: () => handlePairChange(pair.id)
17191
- },
17192
- pair.id
17193
- )) }) : /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "gap-0 py-0", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-6 py-6", children: [
17194
- /* @__PURE__ */ jsxRuntime.jsx(Heading, { level: 4, size: 6, className: "text-foreground", trim: "normal", children: "No recommended combinations" }),
17195
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-3 text-base text-muted-foreground", children: "Choose another approved background tone to review available AAA pairings." })
17196
- ] }) })
20431
+ side: "left",
20432
+ showClose: false,
20433
+ className: "w-[30rem] max-w-[90vw] overflow-hidden p-0",
20434
+ children: [
20435
+ /* @__PURE__ */ jsxRuntime.jsx(SheetTitle, { className: "sr-only", children: "Colour pairing configuration" }),
20436
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-full flex-col bg-background", children: renderControlsPanel(true) })
20437
+ ]
20438
+ }
20439
+ ) })
17197
20440
  ] }),
17198
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-4 lg:grid-cols-2", children: [
20441
+ /* @__PURE__ */ jsxRuntime.jsxs("section", { ref: resultSectionRef, className: "space-y-6", "aria-label": "Current result", children: [
20442
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "sr-only", "aria-live": "polite", children: liveAnnouncement }),
17199
20443
  /* @__PURE__ */ jsxRuntime.jsx(
17200
- PairDetailCard2,
20444
+ CurrentResultCard2,
17201
20445
  {
17202
- color: selectedBackground,
17203
- role: "Background",
17204
- visibleFormats
20446
+ bestPair: bestRecommendedPair,
20447
+ copiedKey,
20448
+ onCopyPairing: () => previewPair ? copyValue(
20449
+ "current-pairing",
20450
+ getPairingCopyText2(previewPair),
20451
+ "Pairing copied",
20452
+ previewPair.id === bestRecommendedPair?.id ? {
20453
+ name: "best_recommendation_copied",
20454
+ ...buildAnalyticsContext({
20455
+ foregroundToken: previewPair.foreground.token,
20456
+ pairId: previewPair.id,
20457
+ source: "current-result"
20458
+ })
20459
+ } : void 0
20460
+ ) : void 0,
20461
+ pair: previewPair,
20462
+ supportText: currentPairSupportText,
20463
+ selectedBackground
17205
20464
  }
17206
- ),
17207
- detailForeground ? /* @__PURE__ */ jsxRuntime.jsx(
17208
- PairDetailCard2,
20465
+ )
20466
+ ] }),
20467
+ /* @__PURE__ */ jsxRuntime.jsx("section", { children: /* @__PURE__ */ jsxRuntime.jsx(AccessibilitySummaryCard, { pair: previewPair }) }),
20468
+ bestRecommendedPair || alternativeRecommendationGroups.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "space-y-6", children: [
20469
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
20470
+ /* @__PURE__ */ jsxRuntime.jsx(Heading, { level: 2, size: 5, className: "text-foreground", trim: "normal", children: "Alternative AAA options" }),
20471
+ /* @__PURE__ */ jsxRuntime.jsx(Text, { size: 2, children: "These approved alternatives can be used when a different tone, stronger emphasis, or a more neutral system treatment is needed." })
20472
+ ] }),
20473
+ alternativeRecommendationGroups.length > 0 ? alternativeRecommendationGroups.map((group) => /* @__PURE__ */ jsxRuntime.jsx(
20474
+ RecommendationGroupSection,
17209
20475
  {
17210
- color: detailForeground,
17211
- role: "Foreground",
17212
- visibleFormats
17213
- }
17214
- ) : /* @__PURE__ */ jsxRuntime.jsxs(Card, { className: "gap-4", children: [
17215
- /* @__PURE__ */ jsxRuntime.jsx(CardHeader, { className: "gap-3 border-b", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
17216
- /* @__PURE__ */ jsxRuntime.jsx(CardTitle, { children: "Foreground" }),
17217
- /* @__PURE__ */ jsxRuntime.jsx(CardDescription, { children: "No recommended foreground available" })
17218
- ] }) }),
17219
- /* @__PURE__ */ jsxRuntime.jsx(CardContent, { children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: "Choose another approved tone or review the recommended foregrounds for the same background." }) })
20476
+ title: group.title,
20477
+ description: group.description,
20478
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-3", children: group.items.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
20479
+ RecommendationCard2,
20480
+ {
20481
+ copiedKey,
20482
+ item,
20483
+ isSelected: item.pair.id === selectedPair?.id,
20484
+ onCopyPairing: () => copyValue(
20485
+ `pair:${item.pair.id}`,
20486
+ getPairingCopyText2(item.pair),
20487
+ "Pairing copied",
20488
+ item.pair.id === bestRecommendedPair?.id ? {
20489
+ name: "best_recommendation_copied",
20490
+ ...buildAnalyticsContext({
20491
+ foregroundToken: item.pair.foreground.token,
20492
+ pairId: item.pair.id,
20493
+ source: "recommendations-list"
20494
+ })
20495
+ } : void 0
20496
+ ),
20497
+ onSelect: () => handlePairChange(item.pair.id, "recommendations-list")
20498
+ },
20499
+ item.pair.id
20500
+ )) })
20501
+ },
20502
+ group.id
20503
+ )) : /* @__PURE__ */ jsxRuntime.jsxs(Card, { className: "px-6 py-6", children: [
20504
+ /* @__PURE__ */ jsxRuntime.jsx(Heading, { level: 3, size: 6, className: "text-foreground", trim: "normal", children: "No other AAA alternatives" }),
20505
+ /* @__PURE__ */ jsxRuntime.jsx(Text, { size: 2, className: "mt-3", children: "The NSW recommended pairing is the only AAA-compliant foreground option for this background." })
20506
+ ] })
20507
+ ] }) : null,
20508
+ /* @__PURE__ */ jsxRuntime.jsx("section", { ref: technicalDetailsSectionRef, className: "space-y-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-sm border border-grey-200 bg-white", children: [
20509
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2 border-b border-grey-200 px-4 py-4 sm:px-5", children: [
20510
+ /* @__PURE__ */ jsxRuntime.jsx(Heading, { level: 2, size: 5, className: "text-foreground", trim: "normal", children: "Technical colour values" }),
20511
+ /* @__PURE__ */ jsxRuntime.jsx(Text, { size: 2, children: "Token, tone, HEX, RGB, HSL, and OKLCH values for the current selection." })
20512
+ ] }),
20513
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 py-4 sm:px-5", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-4 lg:grid-cols-2", children: [
20514
+ /* @__PURE__ */ jsxRuntime.jsx(
20515
+ TechnicalDetailsPanel2,
20516
+ {
20517
+ title: "Background values",
20518
+ color: selectedBackground,
20519
+ visibleFormats,
20520
+ copiedKey,
20521
+ onCopyValue: (copyKey, value, toastLabel) => copyValue(copyKey, value, toastLabel)
20522
+ }
20523
+ ),
20524
+ /* @__PURE__ */ jsxRuntime.jsx(
20525
+ TechnicalDetailsPanel2,
20526
+ {
20527
+ title: "Foreground values",
20528
+ color: detailForeground,
20529
+ visibleFormats,
20530
+ copiedKey,
20531
+ onCopyValue: (copyKey, value, toastLabel) => copyValue(copyKey, value, toastLabel)
20532
+ }
20533
+ )
20534
+ ] }) })
20535
+ ] }) }),
20536
+ /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "space-y-3", children: [
20537
+ /* @__PURE__ */ jsxRuntime.jsx(Heading, { level: 3, size: 6, className: "mb-4 text-foreground", trim: "normal", children: "Share colour pairing" }),
20538
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-sm border border-grey-200 bg-white p-4", children: [
20539
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-row items-center justify-between", children: [
20540
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: "Copy this URL to share your current colour pairing:" }),
20541
+ /* @__PURE__ */ jsxRuntime.jsx(
20542
+ Button2,
20543
+ {
20544
+ variant: "ghost",
20545
+ color: "grey",
20546
+ size: "sm",
20547
+ className: "shrink-0 self-center",
20548
+ onClick: () => copyValue(
20549
+ "share-url",
20550
+ typeof window === "undefined" ? shareUrl : new URL(shareUrl, window.location.origin).toString(),
20551
+ "Colour pairing link copied"
20552
+ ),
20553
+ "aria-label": copiedKey === "share-url" ? "Colour pairing URL copied to clipboard" : "Copy colour pairing URL to clipboard",
20554
+ title: copiedKey === "share-url" ? "Copied" : "Copy URL",
20555
+ children: copiedKey === "share-url" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
20556
+ /* @__PURE__ */ jsxRuntime.jsx(Icons.check, { "data-slot": "icon", className: "size-5" }),
20557
+ "Copied"
20558
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
20559
+ /* @__PURE__ */ jsxRuntime.jsx(Icons.content_copy, { "data-slot": "icon", className: "size-5" }),
20560
+ "Copy URL"
20561
+ ] })
20562
+ }
20563
+ )
20564
+ ] }),
20565
+ /* @__PURE__ */ jsxRuntime.jsx("code", { className: "mt-3 block w-full rounded-sm border border-grey-200 bg-background px-3 py-2 font-mono text-[11px] break-all text-foreground sm:text-xs", children: shareUrl })
17220
20566
  ] })
17221
20567
  ] })
17222
20568
  ] })
17223
20569
  ] });
17224
20570
  }
17225
- function ColorPairingToolV2({
17226
- visibleFormats = DEFAULT_VISIBLE_FORMATS2
20571
+ function ColorPairingToolV4({
20572
+ onAnalyticsEvent = () => {
20573
+ },
20574
+ visibleFormats = DEFAULT_VISIBLE_FORMATS4
17227
20575
  } = {}) {
17228
20576
  const normalizedVisibleFormats = [...new Set(visibleFormats)];
17229
- return /* @__PURE__ */ jsxRuntime.jsx(React5.Suspense, { fallback: /* @__PURE__ */ jsxRuntime.jsx(ColorPairingToolV2Loading, {}), children: /* @__PURE__ */ jsxRuntime.jsx(ColorPairingToolV2Content, { visibleFormats: normalizedVisibleFormats }) });
20577
+ return /* @__PURE__ */ jsxRuntime.jsx(React5.Suspense, { fallback: /* @__PURE__ */ jsxRuntime.jsx(ColorPairingToolV4Loading, {}), children: /* @__PURE__ */ jsxRuntime.jsx(
20578
+ ColorPairingToolV4Content,
20579
+ {
20580
+ onAnalyticsEvent,
20581
+ visibleFormats: normalizedVisibleFormats
20582
+ }
20583
+ ) });
17230
20584
  }
17231
20585
  function ColorSwatches({ theme: theme2, format, viewMode }) {
17232
20586
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -18141,23 +21495,23 @@ var ComboChart = React5__namespace.default.forwardRef((props, forwardedRef) => {
18141
21495
  });
18142
21496
  ComboChart.displayName = "ComboChart";
18143
21497
  function Dialog({ ...props }) {
18144
- return /* @__PURE__ */ jsxRuntime.jsx(DialogPrimitive__namespace.Root, { "data-slot": "dialog", ...props });
21498
+ return /* @__PURE__ */ jsxRuntime.jsx(SheetPrimitive__namespace.Root, { "data-slot": "dialog", ...props });
18145
21499
  }
18146
21500
  function DialogTrigger({ ...props }) {
18147
- return /* @__PURE__ */ jsxRuntime.jsx(DialogPrimitive__namespace.Trigger, { "data-slot": "dialog-trigger", ...props });
21501
+ return /* @__PURE__ */ jsxRuntime.jsx(SheetPrimitive__namespace.Trigger, { "data-slot": "dialog-trigger", ...props });
18148
21502
  }
18149
21503
  function DialogPortal({ ...props }) {
18150
- return /* @__PURE__ */ jsxRuntime.jsx(DialogPrimitive__namespace.Portal, { "data-slot": "dialog-portal", ...props });
21504
+ return /* @__PURE__ */ jsxRuntime.jsx(SheetPrimitive__namespace.Portal, { "data-slot": "dialog-portal", ...props });
18151
21505
  }
18152
21506
  function DialogClose({ ...props }) {
18153
- return /* @__PURE__ */ jsxRuntime.jsx(DialogPrimitive__namespace.Close, { "data-slot": "dialog-close", ...props });
21507
+ return /* @__PURE__ */ jsxRuntime.jsx(SheetPrimitive__namespace.Close, { "data-slot": "dialog-close", ...props });
18154
21508
  }
18155
21509
  function DialogOverlay({
18156
21510
  className,
18157
21511
  ...props
18158
21512
  }) {
18159
21513
  return /* @__PURE__ */ jsxRuntime.jsx(
18160
- DialogPrimitive__namespace.Overlay,
21514
+ SheetPrimitive__namespace.Overlay,
18161
21515
  {
18162
21516
  "data-slot": "dialog-overlay",
18163
21517
  className: cn(
@@ -18177,7 +21531,7 @@ function DialogContent({
18177
21531
  return /* @__PURE__ */ jsxRuntime.jsxs(DialogPortal, { "data-slot": "dialog-portal", children: [
18178
21532
  /* @__PURE__ */ jsxRuntime.jsx(DialogOverlay, {}),
18179
21533
  /* @__PURE__ */ jsxRuntime.jsxs(
18180
- DialogPrimitive__namespace.Content,
21534
+ SheetPrimitive__namespace.Content,
18181
21535
  {
18182
21536
  "data-slot": "dialog-content",
18183
21537
  className: cn(
@@ -18187,7 +21541,7 @@ function DialogContent({
18187
21541
  ...props,
18188
21542
  children: [
18189
21543
  children,
18190
- showClose && /* @__PURE__ */ jsxRuntime.jsx(DialogPrimitive__namespace.Close, { className: "absolute top-1 right-1", asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(Button2, { variant: "ghost", size: "icon", children: [
21544
+ showClose && /* @__PURE__ */ jsxRuntime.jsx(SheetPrimitive__namespace.Close, { className: "absolute top-1 right-1", asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(Button2, { variant: "ghost", size: "icon", children: [
18191
21545
  /* @__PURE__ */ jsxRuntime.jsx(Icons.close, { className: "size-6", "aria-hidden": "true" }),
18192
21546
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Close" })
18193
21547
  ] }) })
@@ -18218,7 +21572,7 @@ function DialogFooter({ className, ...props }) {
18218
21572
  }
18219
21573
  function DialogTitle({ className, ...props }) {
18220
21574
  return /* @__PURE__ */ jsxRuntime.jsx(
18221
- DialogPrimitive__namespace.Title,
21575
+ SheetPrimitive__namespace.Title,
18222
21576
  {
18223
21577
  "data-slot": "dialog-title",
18224
21578
  className: cn("text-lg leading-none font-semibold", className),
@@ -18231,7 +21585,7 @@ function DialogDescription({
18231
21585
  ...props
18232
21586
  }) {
18233
21587
  return /* @__PURE__ */ jsxRuntime.jsx(
18234
- DialogPrimitive__namespace.Description,
21588
+ SheetPrimitive__namespace.Description,
18235
21589
  {
18236
21590
  "data-slot": "dialog-description",
18237
21591
  className: cn("text-sm text-muted-foreground", className),
@@ -19500,7 +22854,7 @@ function FieldLabel({
19500
22854
  }
19501
22855
  );
19502
22856
  }
19503
- function Description4({
22857
+ function Description5({
19504
22858
  className,
19505
22859
  ...props
19506
22860
  }) {
@@ -19852,7 +23206,7 @@ function FormatToggle({ format, setFormat }) {
19852
23206
 
19853
23207
  // package.json
19854
23208
  var package_default = {
19855
- version: "1.102.0"};
23209
+ version: "1.104.0"};
19856
23210
  function Logo(props) {
19857
23211
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
19858
23212
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "NSW Government" }),
@@ -21124,28 +24478,6 @@ function Loading() {
21124
24478
  /* @__PURE__ */ jsxRuntime.jsx(Text, { children: "Loading..." })
21125
24479
  ] });
21126
24480
  }
21127
- function useSelectorHeight(selector = "header") {
21128
- const [height, setHeight] = React5.useState(0);
21129
- const elementRef = React5.useRef(null);
21130
- const resizeObserverRef = React5.useRef(null);
21131
- React5.useEffect(() => {
21132
- const element = document.querySelector(selector);
21133
- if (!element) return;
21134
- elementRef.current = element;
21135
- const resizeObserver = new ResizeObserver((entries) => {
21136
- const entry = entries[0];
21137
- const target = entry?.target ?? elementRef.current;
21138
- if (!target) return;
21139
- setHeight(target.offsetHeight);
21140
- });
21141
- resizeObserverRef.current = resizeObserver;
21142
- resizeObserver.observe(element);
21143
- return () => {
21144
- resizeObserverRef.current?.disconnect();
21145
- };
21146
- }, [selector]);
21147
- return height;
21148
- }
21149
24481
  function MainNavigation({ navigation }) {
21150
24482
  const headerHeight = useSelectorHeight();
21151
24483
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -30910,110 +34242,6 @@ function ResizableHandle({
30910
34242
  }
30911
34243
  );
30912
34244
  }
30913
- function Sheet({ ...props }) {
30914
- return /* @__PURE__ */ jsxRuntime.jsx(DialogPrimitive__namespace.Root, { "data-slot": "sheet", ...props });
30915
- }
30916
- function SheetTrigger({ ...props }) {
30917
- return /* @__PURE__ */ jsxRuntime.jsx(DialogPrimitive__namespace.Trigger, { "data-slot": "sheet-trigger", ...props });
30918
- }
30919
- function SheetClose({ ...props }) {
30920
- return /* @__PURE__ */ jsxRuntime.jsx(DialogPrimitive__namespace.Close, { "data-slot": "sheet-close", ...props });
30921
- }
30922
- function SheetPortal({ ...props }) {
30923
- return /* @__PURE__ */ jsxRuntime.jsx(DialogPrimitive__namespace.Portal, { "data-slot": "sheet-portal", ...props });
30924
- }
30925
- function SheetOverlay({
30926
- className,
30927
- ...props
30928
- }) {
30929
- return /* @__PURE__ */ jsxRuntime.jsx(
30930
- DialogPrimitive__namespace.Overlay,
30931
- {
30932
- "data-slot": "sheet-overlay",
30933
- className: cn(
30934
- "fixed inset-0 z-50 bg-black/50 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:animate-in data-[state=open]:fade-in-0",
30935
- className
30936
- ),
30937
- ...props
30938
- }
30939
- );
30940
- }
30941
- function SheetContent({
30942
- className,
30943
- children,
30944
- side = "right",
30945
- showClose = true,
30946
- ...props
30947
- }) {
30948
- return /* @__PURE__ */ jsxRuntime.jsxs(SheetPortal, { children: [
30949
- /* @__PURE__ */ jsxRuntime.jsx(SheetOverlay, {}),
30950
- /* @__PURE__ */ jsxRuntime.jsxs(
30951
- DialogPrimitive__namespace.Content,
30952
- {
30953
- "data-slot": "sheet-content",
30954
- className: cn(
30955
- "fixed z-50 flex flex-col gap-4 bg-background shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=closed]:animate-out data-[state=open]:duration-500 data-[state=open]:animate-in",
30956
- side === "right" && "inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm",
30957
- side === "left" && "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm",
30958
- side === "top" && "inset-x-0 top-0 h-auto border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",
30959
- side === "bottom" && "inset-x-0 bottom-0 h-auto border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",
30960
- className
30961
- ),
30962
- ...props,
30963
- children: [
30964
- children,
30965
- showClose && /* @__PURE__ */ jsxRuntime.jsx(DialogPrimitive__namespace.Close, { "data-slot": "sheet-close", className: "absolute top-4 right-4", asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(Button2, { variant: "ghost", size: "icon", children: [
30966
- /* @__PURE__ */ jsxRuntime.jsx(Icons.close, { className: "size-6", "aria-hidden": "true" }),
30967
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Close" })
30968
- ] }) })
30969
- ]
30970
- }
30971
- )
30972
- ] });
30973
- }
30974
- function SheetHeader({ className, ...props }) {
30975
- return /* @__PURE__ */ jsxRuntime.jsx(
30976
- "div",
30977
- {
30978
- "data-slot": "sheet-header",
30979
- className: cn("flex flex-col gap-1.5 p-4", className),
30980
- ...props
30981
- }
30982
- );
30983
- }
30984
- function SheetFooter({ className, ...props }) {
30985
- return /* @__PURE__ */ jsxRuntime.jsx(
30986
- "div",
30987
- {
30988
- "data-slot": "sheet-footer",
30989
- className: cn("mt-auto flex flex-col gap-2 p-4", className),
30990
- ...props
30991
- }
30992
- );
30993
- }
30994
- function SheetTitle({ className, ...props }) {
30995
- return /* @__PURE__ */ jsxRuntime.jsx(
30996
- DialogPrimitive__namespace.Title,
30997
- {
30998
- "data-slot": "sheet-title",
30999
- className: cn("font-semibold text-foreground", className),
31000
- ...props
31001
- }
31002
- );
31003
- }
31004
- function SheetDescription({
31005
- className,
31006
- ...props
31007
- }) {
31008
- return /* @__PURE__ */ jsxRuntime.jsx(
31009
- DialogPrimitive__namespace.Description,
31010
- {
31011
- "data-slot": "sheet-description",
31012
- className: cn("text-sm text-muted-foreground", className),
31013
- ...props
31014
- }
31015
- );
31016
- }
31017
34245
  function Skeleton({ className, ...props }) {
31018
34246
  return /* @__PURE__ */ jsxRuntime.jsx(
31019
34247
  "div",
@@ -35741,13 +38969,36 @@ function getHeadings(slugify$1 = slugify.slugifyWithCounter()) {
35741
38969
  });
35742
38970
  return result;
35743
38971
  }
35744
- function usePageHeadings() {
38972
+ function areHeadingNodesEqual(left, right) {
38973
+ if (left.level !== right.level || left.id !== right.id || left.title !== right.title) {
38974
+ return false;
38975
+ }
38976
+ if (left.children.length !== right.children.length) {
38977
+ return false;
38978
+ }
38979
+ return left.children.every((child, index) => areHeadingNodesEqual(child, right.children[index]));
38980
+ }
38981
+ function areHeadingTreesEqual(left, right) {
38982
+ if (left.length !== right.length) {
38983
+ return false;
38984
+ }
38985
+ return left.every((heading, index) => areHeadingNodesEqual(heading, right[index]));
38986
+ }
38987
+ function usePageHeadings(enabled = true) {
35745
38988
  const [headings, setHeadings] = React5.useState([]);
35746
38989
  const pathname = navigation.usePathname();
35747
38990
  const observerRef = React5.useRef(null);
35748
38991
  const observedElRef = React5.useRef(null);
35749
38992
  React5.useEffect(() => {
35750
- const update = () => setHeadings(getHeadings());
38993
+ if (!enabled) {
38994
+ return;
38995
+ }
38996
+ const update = () => {
38997
+ const nextHeadings = getHeadings();
38998
+ setHeadings(
38999
+ (currentHeadings) => areHeadingTreesEqual(currentHeadings, nextHeadings) ? currentHeadings : nextHeadings
39000
+ );
39001
+ };
35751
39002
  const attachToCurrentArticle = () => {
35752
39003
  const article = document.querySelector("article");
35753
39004
  if (!article || observedElRef.current === article) return;
@@ -35794,16 +39045,8 @@ function usePageHeadings() {
35794
39045
  observerRef.current = null;
35795
39046
  observedElRef.current = null;
35796
39047
  };
35797
- }, [pathname]);
35798
- return headings;
35799
- }
35800
- function useStickyOffset(extraPadding = 0) {
35801
- const headerHeight = useSelectorHeight("#nsw-header");
35802
- const navigationHeight = useSelectorHeight("#nsw-main-navigation");
35803
- return React5.useMemo(() => {
35804
- const total = headerHeight + navigationHeight + extraPadding;
35805
- return total > 0 ? total : 0;
35806
- }, [extraPadding, headerHeight, navigationHeight]);
39048
+ }, [enabled, pathname]);
39049
+ return enabled ? headings : [];
35807
39050
  }
35808
39051
  function createFormStore(opts) {
35809
39052
  const { storageKey, initialFormData, initialFormStatus } = opts;
@@ -35945,6 +39188,8 @@ exports.CollapsibleTrigger = CollapsibleTrigger2;
35945
39188
  exports.ColorCard = ColorCard;
35946
39189
  exports.ColorPairingTool = ColorPairingTool;
35947
39190
  exports.ColorPairingToolV2 = ColorPairingToolV2;
39191
+ exports.ColorPairingToolV3 = ColorPairingToolV3;
39192
+ exports.ColorPairingToolV4 = ColorPairingToolV4;
35948
39193
  exports.ColorSwatches = ColorSwatches;
35949
39194
  exports.ColourScale = ColourScale;
35950
39195
  exports.ComboChart = ComboChart;
@@ -35992,7 +39237,7 @@ exports.DataTableFacetedFilter = DataTableFacetedFilter;
35992
39237
  exports.DataTablePagination = DataTablePagination;
35993
39238
  exports.DataTableToolbar = DataTableToolbar;
35994
39239
  exports.DataTableViewOptions = DataTableViewOptions;
35995
- exports.Description = Description4;
39240
+ exports.Description = Description5;
35996
39241
  exports.DescriptionDetails = DescriptionDetails;
35997
39242
  exports.DescriptionList = DescriptionList;
35998
39243
  exports.DescriptionTerm = DescriptionTerm;