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