@assure-one/design-system 1.39.0 → 1.41.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.
Files changed (54) hide show
  1. package/README.md +48 -28
  2. package/codemods/README.md +24 -7
  3. package/codemods/lib/registry.mjs +27 -0
  4. package/codemods/lib/runner.mjs +8 -3
  5. package/codemods/run.mjs +27 -5
  6. package/codemods/transforms/cm-15-dom-selectors.mjs +16 -9
  7. package/dist/brand-scope-BOHId6BY.d.ts +58 -0
  8. package/dist/{brand-theme-B6rem2II.d.ts → brand-theme-ZYM867Jz.d.ts} +1 -1
  9. package/dist/chunk-CPOGSNXS.js +389 -0
  10. package/dist/chunk-CPOGSNXS.js.map +1 -0
  11. package/dist/chunk-EUHGZA6Q.js +313 -0
  12. package/dist/chunk-EUHGZA6Q.js.map +1 -0
  13. package/dist/chunk-KUSY7BLL.js +441 -0
  14. package/dist/chunk-KUSY7BLL.js.map +1 -0
  15. package/dist/chunk-NBI7E3VT.js +3754 -0
  16. package/dist/chunk-NBI7E3VT.js.map +1 -0
  17. package/dist/chunk-PTI4B2OI.js +5527 -0
  18. package/dist/chunk-PTI4B2OI.js.map +1 -0
  19. package/dist/chunk-X76J4QSJ.js +164 -0
  20. package/dist/chunk-X76J4QSJ.js.map +1 -0
  21. package/dist/chunk-XV2VSEA5.js +4339 -0
  22. package/dist/chunk-XV2VSEA5.js.map +1 -0
  23. package/dist/css/components.css +1 -1
  24. package/dist/css/legacy-aliases.css +2 -0
  25. package/dist/css/tailwind.css +2 -0
  26. package/dist/css/tokens.css +2 -0
  27. package/dist/data-table-view-ep8al7P9.d.ts +1132 -0
  28. package/dist/{design-system-provider-BM_F1C13.d.ts → design-system-provider-CfD2g2lY.d.ts} +11 -12
  29. package/dist/icons/index.d.ts +189 -140
  30. package/dist/icons/index.js +2 -1835
  31. package/dist/icons/index.js.map +1 -1
  32. package/dist/index.d.ts +374 -389
  33. package/dist/index.js +8688 -24271
  34. package/dist/index.js.map +1 -1
  35. package/dist/legacy/index.d.ts +1462 -7
  36. package/dist/legacy/index.js +5 -1
  37. package/dist/legacy/index.js.map +1 -1
  38. package/dist/next/index.d.ts +2 -2
  39. package/dist/styles.css +2 -1
  40. package/dist/suite/index.d.ts +991 -4
  41. package/dist/suite/index.js +6 -1
  42. package/dist/suite/index.js.map +1 -1
  43. package/dist/testing/index.cjs +3 -2
  44. package/dist/testing/index.js +3 -2
  45. package/dist/tokens/index.d.ts +1 -1
  46. package/dist/tokens/index.js +3 -856
  47. package/dist/tokens/index.js.map +1 -1
  48. package/dist/{types-k_kjwipx.d.ts → types-Coqw8iaS.d.ts} +28 -1
  49. package/docs/components.md +56 -56
  50. package/docs/components.registry.json +7 -7
  51. package/docs/for-ai-agents.md +12 -6
  52. package/package.json +8 -5
  53. package/dist/index-BAAuIQqP.d.ts +0 -2579
  54. package/dist/index-DxBjmBBp.d.ts +0 -1038
@@ -0,0 +1,4339 @@
1
+ import { stateAttributes, slot, chipAnatomy, Pressable, CONTROL_GAP_CLASSES, EN_MESSAGES, microInteractions, listItemClasses, groupHeadingClasses, useDsMessages, withPortalContainer, Backdrop, sheetAnatomy, deprecate, OverlaySurface, DismissButton, DEFAULT_OVERLAY_MESSAGES, DISMISS_GLYPH_CLASSES, OverlayBody, OverlayTitle, OverlayDescription, Input, Textarea, Select, FileUpload, FileChip, Button, Checkbox, Tooltip, TooltipTrigger, TooltipContent, TooltipProvider, sidebarAnatomy, Slot, Avatar, DropdownMenu, DropdownMenuTrigger, sidebarBrandSwitcherAnatomy, DropdownMenuContent, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuItem, buttonBase, CONTROL_SIZE_CLASSES, useFieldControl, useId as useId$1, useControllableState, useMergedRefs, Popover, PopoverAnchor, comboboxAnatomy, Spinner, IconButton, PopoverContent, LIST_SEPARATOR, listItemAttributes, optionElementId, FormBridge, useLinkComponent, useImageComponent, OverlayHeader, OverlayFooter, LIST_ITEM_INDICATOR_WELL } from './chunk-NBI7E3VT.js';
2
+ import { cn, XIcon, CheckIcon, EyeIcon, DownloadIcon, PhoneIcon, MailIcon, GlobeIcon, HomeIcon, ChevronLeftIcon, ChevronRightIcon, ReceiptIcon, RotateCcwIcon, CreditCardIcon, LockIcon, FileTextIcon, PlayIcon, InfoIcon, ClockIcon, PenSignIcon, TrashIcon, PlusIcon, CheckCircleSolidIcon, HelpCircleIcon, MinusIcon, PanelLeftCloseIcon, PanelLeftIcon, ChevronDownIcon } from './chunk-KUSY7BLL.js';
3
+ import { parseHexColor, contrastRatio, WHITE, formatHexColor, darkenUntilContrast } from './chunk-EUHGZA6Q.js';
4
+ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
5
+ import * as React6 from 'react';
6
+ import { forwardRef, useId, useState, Fragment as Fragment$1, createContext, useContext } from 'react';
7
+ import { RemoveScroll } from 'react-remove-scroll';
8
+ import * as CollapsiblePrimitive from '@radix-ui/react-collapsible';
9
+ import * as SheetPrimitive from '@radix-ui/react-dialog';
10
+ import { cva } from 'class-variance-authority';
11
+
12
+ var BRAND_BASE_FILL = "#070707";
13
+ var BRAND_BASE_PATH = "M43.8298 23.829C46.9635 23.7428 50.7456 23.9675 54.0114 23.9437L91.3493 23.8048C97.6806 23.7927 101.727 24.9883 106.302 29.5107C107.671 30.864 108.443 32.0751 109.418 33.7063C112.332 38.5806 112.037 42.6442 112.003 48.0679L112.02 56.4922C108.427 57.4911 101.053 57.2229 96.9953 57.2944C87.0232 57.47 76.9072 57.2055 66.9345 57.4014C66.7192 66.474 66.9079 75.8103 66.8438 84.9327C66.7469 92.0668 67.2878 101.738 66.6431 108.599C60.7359 108.871 54.5467 108.479 48.6135 108.641C40.5834 108.86 34.2651 108.559 28.1575 102.692C20.618 95.4486 21.8015 86.9701 21.8025 77.474L21.8166 59.8481L21.8312 49.597C21.8372 47.075 21.7515 43.5009 22.2502 41.142C22.9069 38.0359 25.4258 33.4304 27.6724 31.1548C32.4002 26.3658 37.1772 24.0905 43.8298 23.829Z";
14
+ var BRAND_ACCENT_PATH = "M83.7555 72.8376C85.3789 72.6548 90.5991 72.7708 92.4304 72.7692L100.779 72.7802C102.529 72.7903 104.546 72.7296 106.26 73.0259C108.43 73.422 111.61 75.5699 111.737 77.9539C112.107 84.8649 111.986 91.8555 111.974 98.7715C111.969 101.35 111.928 103.109 110.232 105.149C108.61 107.101 107.07 108.323 104.518 108.621C99.7602 108.503 95.0005 108.467 90.2413 108.513C87.5612 108.531 84.6034 108.799 81.9937 108.434C78.4024 107.933 76.1145 105.214 76.0317 101.618C75.9281 97.1186 75.8903 92.669 75.9646 88.174C76.0209 84.7695 75.8279 81.2851 76.3134 77.921C76.3993 77.3266 77.1785 76.1903 77.6286 75.7193C79.6145 73.6412 80.9496 73.0158 83.7555 72.8376Z";
15
+ function BrandIcon({
16
+ size = 24,
17
+ accent,
18
+ title,
19
+ className,
20
+ ...props
21
+ }) {
22
+ return /* @__PURE__ */ jsxs(
23
+ "svg",
24
+ {
25
+ width: size,
26
+ height: size,
27
+ viewBox: "0 0 136 137",
28
+ fill: "none",
29
+ xmlns: "http://www.w3.org/2000/svg",
30
+ className: cn("ds:shrink-0", className),
31
+ role: "img",
32
+ "aria-label": title,
33
+ ...props,
34
+ children: [
35
+ /* @__PURE__ */ jsx("path", { d: BRAND_BASE_PATH, fill: BRAND_BASE_FILL }),
36
+ /* @__PURE__ */ jsx("path", { d: BRAND_ACCENT_PATH, fill: accent })
37
+ ]
38
+ }
39
+ );
40
+ }
41
+ function AssureProBrandIcon({ size = 24, ...props }) {
42
+ return /* @__PURE__ */ jsx(BrandIcon, { size, accent: "var(--ds-ref-brand-pro-seed, var(--color-brand-pro))", title: "Assure Pro", ...props });
43
+ }
44
+ function AssureAuditBrandIcon({ size = 24, ...props }) {
45
+ return /* @__PURE__ */ jsx(BrandIcon, { size, accent: "var(--ds-ref-brand-audit-seed, var(--color-brand-audit))", title: "Assure Audit", ...props });
46
+ }
47
+ function AssureBooksBrandIcon({ size = 24, ...props }) {
48
+ return /* @__PURE__ */ jsx(BrandIcon, { size, accent: "var(--ds-ref-brand-books-seed, var(--color-brand-books))", title: "Assure Books", ...props });
49
+ }
50
+ function AssureTaxBrandIcon({ size = 24, ...props }) {
51
+ return /* @__PURE__ */ jsx(BrandIcon, { size, accent: "var(--ds-ref-brand-tax-seed, var(--color-brand-tax))", title: "Assure Tax", ...props });
52
+ }
53
+ function chipVariants({
54
+ variant,
55
+ intent,
56
+ size,
57
+ pressed,
58
+ className
59
+ } = {}) {
60
+ const { look } = resolveChipStyle({ variant, intent, pressed });
61
+ return cn(
62
+ buttonBase({ look, size: null }),
63
+ "ds:rounded-full ds:shrink-0",
64
+ CONTROL_SIZE_CLASSES[size ?? "sm"],
65
+ className
66
+ );
67
+ }
68
+ function resolveChipStyle({
69
+ variant,
70
+ intent,
71
+ pressed
72
+ }) {
73
+ const emphasis = variant ?? "soft";
74
+ const requested = intent === "destructive" ? "danger" : intent;
75
+ const family = requested ?? (pressed ? "brand" : "neutral");
76
+ return { variant: emphasis, intent: family, look: `${emphasis}/${family}` };
77
+ }
78
+ var REMOVE_HOVER = {
79
+ brand: "ds:hover:bg-brand-bg-active",
80
+ neutral: "ds:hover:bg-control-active-bg",
81
+ success: "ds:hover:bg-success-line",
82
+ danger: "ds:hover:bg-danger-line"
83
+ };
84
+ var Chip = forwardRef(function Chip2({
85
+ children,
86
+ icon,
87
+ count,
88
+ variant,
89
+ intent,
90
+ size = "sm",
91
+ pressed,
92
+ onPressedChange,
93
+ onClick,
94
+ onRemove,
95
+ removeLabel,
96
+ disabled,
97
+ className,
98
+ ...props
99
+ }, ref) {
100
+ const isToggle = pressed !== void 0 || onPressedChange !== void 0;
101
+ const pressedValue = isToggle ? Boolean(pressed) : void 0;
102
+ const interactive = isToggle || onClick !== void 0;
103
+ const style = resolveChipStyle({ variant, intent, pressed: pressedValue });
104
+ const resolvedRemoveLabel = removeLabel ?? (typeof children === "string" ? `Remove ${children}` : void 0);
105
+ if (process.env.NODE_ENV !== "production" && onRemove && resolvedRemoveLabel === void 0) {
106
+ throw new Error(
107
+ "[Chip] `removeLabel` is required when `onRemove` is set and the label is not a string: the remove button needs an accessible name."
108
+ );
109
+ }
110
+ const handleClick = (event) => {
111
+ onClick?.(event);
112
+ if (event.defaultPrevented) return;
113
+ if (isToggle) onPressedChange?.(!pressedValue);
114
+ };
115
+ const state = stateAttributes({
116
+ variant: style.variant,
117
+ intent: style.intent,
118
+ size,
119
+ disabled,
120
+ pressed: pressedValue
121
+ });
122
+ const content = /* @__PURE__ */ jsxs(Fragment, { children: [
123
+ icon && /* @__PURE__ */ jsx(
124
+ "span",
125
+ {
126
+ ...slot(chipAnatomy, "icon"),
127
+ className: "ds:inline-flex ds:shrink-0",
128
+ "aria-hidden": "true",
129
+ children: icon
130
+ }
131
+ ),
132
+ /* @__PURE__ */ jsx("span", { ...slot(chipAnatomy, "label"), children }),
133
+ typeof count === "number" && /* @__PURE__ */ jsx("span", { ...slot(chipAnatomy, "count"), className: "ds:font-normal ds:tabular-nums", children: count })
134
+ ] });
135
+ if (!onRemove) {
136
+ return /* @__PURE__ */ jsx(
137
+ Pressable,
138
+ {
139
+ ref,
140
+ pressed: pressedValue,
141
+ disabled,
142
+ onClick: handleClick,
143
+ ...slot(chipAnatomy, "root"),
144
+ ...state,
145
+ className: chipVariants({ variant, intent, size, pressed: pressedValue, className }),
146
+ ...props,
147
+ children: content
148
+ }
149
+ );
150
+ }
151
+ return /* @__PURE__ */ jsxs(
152
+ "span",
153
+ {
154
+ ref,
155
+ "aria-disabled": disabled || void 0,
156
+ ...slot(chipAnatomy, "root"),
157
+ ...state,
158
+ className: cn(
159
+ chipVariants({ variant, intent, size, pressed: pressedValue }),
160
+ // The remove button ends the row in its own 24px box (a hit target of
161
+ // its own, WCAG 2.5.8), so the end padding is the box's, not the text's.
162
+ "ds:pe-1",
163
+ !interactive && "ds:cursor-default",
164
+ disabled && "ds:pointer-events-none ds:bg-bg-disabled ds:text-fg-disabled",
165
+ className
166
+ ),
167
+ ...props,
168
+ children: [
169
+ interactive ? /* @__PURE__ */ jsx(
170
+ Pressable,
171
+ {
172
+ pressed: pressedValue,
173
+ disabled,
174
+ onClick: handleClick,
175
+ className: cn(
176
+ "ds:inline-flex ds:h-full ds:min-w-0 ds:items-center ds:rounded-full ds:bg-transparent ds:p-0 ds:text-inherit",
177
+ CONTROL_GAP_CLASSES[size]
178
+ ),
179
+ children: content
180
+ }
181
+ ) : /* @__PURE__ */ jsx(
182
+ "span",
183
+ {
184
+ className: cn("ds:inline-flex ds:min-w-0 ds:items-center", CONTROL_GAP_CLASSES[size]),
185
+ children: content
186
+ }
187
+ ),
188
+ /* @__PURE__ */ jsx(
189
+ Pressable,
190
+ {
191
+ ...slot(chipAnatomy, "remove"),
192
+ "aria-label": resolvedRemoveLabel,
193
+ disabled,
194
+ onClick: onRemove,
195
+ className: cn(
196
+ "ds:inline-flex ds:size-6 ds:shrink-0 ds:items-center ds:justify-center ds:rounded-full ds:bg-transparent ds:p-0 ds:text-inherit",
197
+ "ds:transition-colors ds:duration-[var(--motion-duration-feedback)] ds:motion-reduce:transition-none",
198
+ REMOVE_HOVER[style.intent]
199
+ ),
200
+ children: /* @__PURE__ */ jsx(XIcon, { "aria-hidden": "true" })
201
+ }
202
+ )
203
+ ]
204
+ }
205
+ );
206
+ });
207
+ Chip.displayName = "Chip";
208
+
209
+ // src/primitives/behavior/collection/option.ts
210
+ function isOption(item) {
211
+ return typeof item === "object" && item !== null && typeof item.value === "string" && typeof item.label === "string";
212
+ }
213
+ var optionAccessors = {
214
+ getOptionValue: (option) => option.value,
215
+ getOptionLabel: (option) => option.label,
216
+ getOptionDisabled: (option) => option.disabled === true,
217
+ getOptionGroup: (option) => option.group,
218
+ getOptionKeywords: (option) => option.keywords
219
+ };
220
+ var stringOptionAccessors = {
221
+ getOptionValue: (item) => item,
222
+ getOptionLabel: (item) => item
223
+ };
224
+ function resolveAccessors(item, accessors) {
225
+ if (accessors !== void 0) return accessors;
226
+ if (typeof item === "string") {
227
+ return stringOptionAccessors;
228
+ }
229
+ if (isOption(item)) {
230
+ return optionAccessors;
231
+ }
232
+ throw new TypeError(
233
+ "collection: an item that is neither a string nor an Option needs accessors (getOptionValue/getOptionLabel)"
234
+ );
235
+ }
236
+ function toOption(item, accessors) {
237
+ const read = resolveAccessors(item, accessors);
238
+ if (accessors === void 0 && isOption(item)) {
239
+ return item;
240
+ }
241
+ const base = isOption(item) ? { ...item } : { value: read.getOptionValue(item), label: read.getOptionLabel(item) };
242
+ base.value = read.getOptionValue(item);
243
+ base.label = read.getOptionLabel(item);
244
+ const disabled = read.getOptionDisabled?.(item);
245
+ if (disabled !== void 0) base.disabled = disabled;
246
+ const group = read.getOptionGroup?.(item);
247
+ if (group !== void 0) base.group = group;
248
+ const keywords = read.getOptionKeywords?.(item);
249
+ if (keywords !== void 0) base.keywords = keywords;
250
+ if (!isOption(item) && typeof item !== "string") base.meta = item;
251
+ return base;
252
+ }
253
+ function toOptions(items, accessors) {
254
+ const options = items.map((item) => toOption(item, accessors));
255
+ if (process.env.NODE_ENV !== "production") {
256
+ const seen = /* @__PURE__ */ new Set();
257
+ for (const option of options) {
258
+ if (option.value === "") {
259
+ throw new TypeError(
260
+ `collection: option ${JSON.stringify(option.label)} has an empty value; emptiness is value === null on the control, not a row`
261
+ );
262
+ }
263
+ if (seen.has(option.value)) {
264
+ throw new TypeError(
265
+ `collection: option value ${JSON.stringify(option.value)} appears twice; values must be unique`
266
+ );
267
+ }
268
+ seen.add(option.value);
269
+ }
270
+ }
271
+ return options;
272
+ }
273
+ function findOption(options, value) {
274
+ if (value === null || value === void 0) return void 0;
275
+ return options.find((option) => option.value === value);
276
+ }
277
+ function groupOptions(options) {
278
+ const buckets = /* @__PURE__ */ new Map();
279
+ const ordered = [];
280
+ for (const option of options) {
281
+ let bucket = buckets.get(option.group);
282
+ if (!bucket) {
283
+ bucket = { group: option.group, options: [] };
284
+ buckets.set(option.group, bucket);
285
+ ordered.push(bucket);
286
+ }
287
+ bucket.options.push(option);
288
+ }
289
+ return ordered;
290
+ }
291
+ function foldForMatch(text) {
292
+ return text.normalize("NFD").replace(/[̀-ͯ]/g, "").toLowerCase().replace(/\s+/g, " ").trim();
293
+ }
294
+ function optionMatches(option, query) {
295
+ const needle = foldForMatch(query);
296
+ if (needle === "") return true;
297
+ if (foldForMatch(option.label).includes(needle)) return true;
298
+ if (option.group !== void 0 && foldForMatch(option.group).includes(needle)) return true;
299
+ return option.keywords?.some((keyword) => foldForMatch(keyword).includes(needle)) ?? false;
300
+ }
301
+ function filterOptions(options, query) {
302
+ return options.filter((option) => optionMatches(option, query));
303
+ }
304
+ function normalizeSingleValue(value) {
305
+ return value === void 0 || value === null || value === "" ? null : value;
306
+ }
307
+ function normalizeMultipleValue(value) {
308
+ if (value === void 0 || value === null) return [];
309
+ return value.filter((entry) => entry !== "");
310
+ }
311
+ function toggleValue(selection, optionValue) {
312
+ return selection.includes(optionValue) ? selection.filter((entry) => entry !== optionValue) : [...selection, optionValue];
313
+ }
314
+
315
+ // src/primitives/behavior/collection/keyboard.ts
316
+ function firstEnabledIndex(rows, from = 0) {
317
+ for (let index = Math.max(0, from); index < rows.length; index += 1) {
318
+ if (!rows[index]?.disabled) return index;
319
+ }
320
+ return null;
321
+ }
322
+ function lastEnabledIndex(rows, from = rows.length - 1) {
323
+ for (let index = Math.min(rows.length - 1, from); index >= 0; index -= 1) {
324
+ if (!rows[index]?.disabled) return index;
325
+ }
326
+ return null;
327
+ }
328
+ function stepEnabledIndex(rows, from, direction, { loop = false, steps = 1 } = {}) {
329
+ if (rows.length === 0) return null;
330
+ if (from === null) {
331
+ return direction === 1 ? firstEnabledIndex(rows) : lastEnabledIndex(rows);
332
+ }
333
+ let current = from;
334
+ for (let taken = 0; taken < steps; taken += 1) {
335
+ const candidate = direction === 1 ? firstEnabledIndex(rows, current + 1) : lastEnabledIndex(rows, current - 1);
336
+ if (candidate === null) {
337
+ if (loop && taken === 0) {
338
+ const wrapped = direction === 1 ? firstEnabledIndex(rows) : lastEnabledIndex(rows);
339
+ return wrapped ?? from;
340
+ }
341
+ break;
342
+ }
343
+ current = candidate;
344
+ }
345
+ return current;
346
+ }
347
+ var NAVIGATION_KEYS = /* @__PURE__ */ new Set([
348
+ "ArrowDown",
349
+ "ArrowUp",
350
+ "ArrowRight",
351
+ "ArrowLeft",
352
+ "Home",
353
+ "End",
354
+ "PageDown",
355
+ "PageUp"
356
+ ]);
357
+ function isListNavigationKey(key, orientation = "vertical") {
358
+ if (!NAVIGATION_KEYS.has(key)) return false;
359
+ if (orientation === "vertical") return key !== "ArrowRight" && key !== "ArrowLeft";
360
+ return key !== "ArrowDown" && key !== "ArrowUp";
361
+ }
362
+ function nextHighlightedIndex(rows, highlighted, key, { loop = false, pageSize = 10, orientation = "vertical" } = {}) {
363
+ if (!isListNavigationKey(key, orientation)) return void 0;
364
+ switch (key) {
365
+ case "ArrowDown":
366
+ case "ArrowRight":
367
+ return stepEnabledIndex(rows, highlighted, 1, { loop });
368
+ case "ArrowUp":
369
+ case "ArrowLeft":
370
+ return stepEnabledIndex(rows, highlighted, -1, { loop });
371
+ case "Home":
372
+ return firstEnabledIndex(rows);
373
+ case "End":
374
+ return lastEnabledIndex(rows);
375
+ case "PageDown":
376
+ return stepEnabledIndex(rows, highlighted, 1, { steps: pageSize });
377
+ case "PageUp":
378
+ return stepEnabledIndex(rows, highlighted, -1, { steps: pageSize });
379
+ default:
380
+ return void 0;
381
+ }
382
+ }
383
+ function reconcileHighlight(rows, highlightedValue, fallback = "first") {
384
+ if (highlightedValue !== null) {
385
+ const kept = rows.find((row) => row.value === highlightedValue && !row.disabled);
386
+ if (kept) return kept.value;
387
+ }
388
+ if (fallback === "none") return null;
389
+ const first = firstEnabledIndex(rows);
390
+ return first === null ? null : rows[first]?.value ?? null;
391
+ }
392
+ function indexOfValue(rows, value) {
393
+ if (value === null) return null;
394
+ const index = rows.findIndex((row) => row.value === value);
395
+ return index === -1 ? null : index;
396
+ }
397
+ function activeDescendantId(listId, rows, highlighted) {
398
+ if (highlighted === null || highlighted < 0 || highlighted >= rows.length) return void 0;
399
+ const row = rows[highlighted];
400
+ return row ? optionElementId(listId, row.value) : void 0;
401
+ }
402
+ function NestedScrollLock({
403
+ active = true,
404
+ children
405
+ }) {
406
+ if (!active) return /* @__PURE__ */ jsx(Fragment, { children });
407
+ return /* @__PURE__ */ jsx(RemoveScroll, { removeScrollBar: false, className: "ds:contents", children });
408
+ }
409
+ var DEFAULT_COMBOBOX_MESSAGES = EN_MESSAGES.combobox;
410
+ var CONTROL_SIZE = {
411
+ xs: "ds:min-h-(--control-height-xs) ds:ps-(--control-padding-x-xs) ds:text-(length:--control-font-size-xs) ds:gap-(--control-gap-xs) ds:[&_svg]:size-(--control-icon-xs)",
412
+ sm: "ds:min-h-(--control-height-sm) ds:ps-(--control-padding-x-sm) ds:text-(length:--control-font-size-sm) ds:gap-(--control-gap-sm) ds:[&_svg]:size-(--control-icon-sm)",
413
+ md: "ds:min-h-(--control-height-md) ds:ps-(--control-padding-x-md) ds:text-(length:--control-font-size-md) ds:gap-(--control-gap-md) ds:[&_svg]:size-(--control-icon-md)",
414
+ lg: "ds:min-h-(--control-height-lg) ds:ps-(--control-padding-x-lg) ds:text-(length:--control-font-size-lg) ds:gap-(--control-gap-lg) ds:[&_svg]:size-(--control-icon-lg)",
415
+ xl: "ds:min-h-(--control-height-xl) ds:ps-(--control-padding-x-xl) ds:text-(length:--control-font-size-xl) ds:gap-(--control-gap-xl) ds:[&_svg]:size-(--control-icon-xl)"
416
+ };
417
+ var BUTTON_SIZE = {
418
+ xs: "xs",
419
+ sm: "xs",
420
+ md: "xs",
421
+ lg: "sm",
422
+ xl: "md"
423
+ };
424
+ var CONTROL_FRAME = [
425
+ "ds:relative ds:flex ds:w-full ds:flex-wrap ds:items-center ds:rounded-input ds:border ds:border-field-border ds:bg-surface ds:font-body ds:text-fg ds:pe-1",
426
+ microInteractions.control,
427
+ "ds:not-data-disabled:hover:border-field-border-hover",
428
+ "ds:focus-within:[border-color:var(--focus-ring-border)] ds:focus-within:[box-shadow:var(--shadow-focus-ring-field)]",
429
+ "ds:data-[invalid]:border-field-border-invalid ds:data-[invalid]:focus-within:border-danger-fg",
430
+ "ds:data-[invalid]:focus-within:[box-shadow:0_0_0_2px_var(--color-danger-bg)]",
431
+ "ds:data-[disabled]:cursor-not-allowed ds:data-[disabled]:bg-bg-disabled ds:data-[disabled]:text-fg-disabled"
432
+ ].join(" ");
433
+ var INPUT_CLASSES = "ds:min-w-16 ds:flex-1 ds:self-stretch ds:bg-transparent ds:py-0 ds:[font:inherit] ds:text-inherit ds:outline-none ds:placeholder:text-fg-4 ds:disabled:cursor-not-allowed ds:read-only:cursor-default";
434
+ var LABEL_SIZE = "ds:text-(length:--control-font-size-md)";
435
+ var SMALL_TEXT = "ds:text-(length:--control-font-size-xs)";
436
+ var ITEM_CLASSES = listItemClasses({
437
+ frame: "select",
438
+ labelSize: LABEL_SIZE,
439
+ palette: "neutral",
440
+ highlight: "data-highlighted",
441
+ selected: "aria-selected"
442
+ });
443
+ var CREATE_ITEM_CLASSES = cn(
444
+ ITEM_CLASSES,
445
+ "ds:text-brand ds:data-[highlighted]:bg-brand-bg ds:data-[highlighted]:text-brand"
446
+ );
447
+ var GROUP_HEADING_CLASSES = groupHeadingClasses({ palette: "neutral", labelSize: SMALL_TEXT });
448
+ var STATE_CLASSES = cn("ds:text-fg-3 ds:px-3 ds:py-2", SMALL_TEXT);
449
+ var CREATE_ROW = "\0create";
450
+ var CmdkCompatContext = React6.createContext(false);
451
+ function Combobox(props) {
452
+ const {
453
+ options: items,
454
+ getOptionValue,
455
+ getOptionLabel,
456
+ getOptionDisabled,
457
+ getOptionGroup,
458
+ getOptionKeywords,
459
+ id: idProp,
460
+ name: nameProp,
461
+ form,
462
+ required: requiredProp,
463
+ disabled: disabledProp,
464
+ readOnly: readOnlyProp,
465
+ invalid: invalidProp,
466
+ "aria-label": ariaLabel,
467
+ "aria-labelledby": ariaLabelledBy,
468
+ "aria-describedby": ariaDescribedBy,
469
+ placeholder,
470
+ size = "md",
471
+ icon,
472
+ clearable = true,
473
+ openOnFocus = false,
474
+ avoidCollisions = true,
475
+ open: openProp,
476
+ defaultOpen = false,
477
+ onOpenChange,
478
+ search: searchProp,
479
+ defaultSearch = "",
480
+ onSearchChange,
481
+ shouldFilter = true,
482
+ loading = false,
483
+ emptyState,
484
+ loadingState,
485
+ header,
486
+ footer,
487
+ onCreate,
488
+ renderOption,
489
+ messages: messagesProp,
490
+ className,
491
+ classNames,
492
+ ref
493
+ } = props;
494
+ const multiple = props.multiple === true;
495
+ const closeOnSelect = props.closeOnSelect ?? !multiple;
496
+ const hideSelected = props.multiple === true && props.hideSelected === true;
497
+ const messages = useDsMessages("combobox", messagesProp);
498
+ const accessors = React6.useMemo(() => {
499
+ if (!getOptionValue || !getOptionLabel) return void 0;
500
+ return {
501
+ getOptionValue,
502
+ getOptionLabel,
503
+ getOptionDisabled,
504
+ getOptionGroup,
505
+ getOptionKeywords
506
+ };
507
+ }, [getOptionValue, getOptionLabel, getOptionDisabled, getOptionGroup, getOptionKeywords]);
508
+ const options = React6.useMemo(() => toOptions(items, accessors), [items, accessors]);
509
+ const wiring = useFieldControl({
510
+ id: idProp,
511
+ name: nameProp,
512
+ invalid: invalidProp,
513
+ required: requiredProp,
514
+ disabled: disabledProp,
515
+ readOnly: readOnlyProp,
516
+ "aria-labelledby": ariaLabelledBy,
517
+ "aria-describedby": ariaDescribedBy,
518
+ native: false
519
+ });
520
+ const disabled = wiring.disabled ?? false;
521
+ const readOnly = wiring.readOnly ?? false;
522
+ const inert = disabled || readOnly;
523
+ const listId = useId$1(void 0, `${wiring.id}-list`);
524
+ const toSelection = (raw) => {
525
+ if (raw === void 0) return void 0;
526
+ if (multiple) return normalizeMultipleValue(raw);
527
+ const single = normalizeSingleValue(raw);
528
+ return single === null ? [] : [single];
529
+ };
530
+ const defaultSelection = React6.useMemo(
531
+ () => toSelection(props.defaultValue) ?? [],
532
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- read once, like a default should be
533
+ []
534
+ );
535
+ const [selection, setSelectionState] = useControllableState({
536
+ prop: toSelection(props.value),
537
+ defaultProp: defaultSelection
538
+ });
539
+ const value = multiple ? null : selection[0] ?? null;
540
+ const [openState, setOpenState] = useControllableState({
541
+ prop: openProp,
542
+ defaultProp: defaultOpen,
543
+ onChange: onOpenChange
544
+ });
545
+ const open = openState && !inert;
546
+ const [search, setSearchState] = useControllableState({
547
+ prop: searchProp,
548
+ defaultProp: defaultSearch,
549
+ onChange: onSearchChange
550
+ });
551
+ const selectedOption = React6.useMemo(() => findOption(options, value), [options, value]);
552
+ const selectedOptions = React6.useMemo(
553
+ () => selection.map((entry) => findOption(options, entry)).filter((option) => option !== void 0),
554
+ [options, selection]
555
+ );
556
+ const inputRef = React6.useRef(null);
557
+ const controlRef = React6.useRef(null);
558
+ const mergedInputRef = useMergedRefs(inputRef, ref, wiring.ref);
559
+ const commitSelection = React6.useCallback(
560
+ (next, option) => {
561
+ setSelectionState(next);
562
+ const changed = next.length !== selection.length || next.some((entry, index) => entry !== selection[index]);
563
+ if (!changed) return;
564
+ if (props.multiple === true) props.onValueChange?.(next, { option });
565
+ else props.onValueChange?.(next[0] ?? null, { option });
566
+ },
567
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- `props` is read for the discriminant
568
+ [setSelectionState, selection, props.multiple, props.onValueChange]
569
+ );
570
+ const setValue = React6.useCallback(
571
+ (next) => commitSelection(next === null ? [] : [next], findOption(options, next) ?? null),
572
+ [commitSelection, options]
573
+ );
574
+ const removeValue = React6.useCallback(
575
+ (entry) => commitSelection(
576
+ selection.filter((current) => current !== entry),
577
+ findOption(options, entry) ?? null
578
+ ),
579
+ [commitSelection, selection, options]
580
+ );
581
+ const setOpen = React6.useCallback(
582
+ (next) => {
583
+ if (next && inert) return;
584
+ setOpenState(next);
585
+ if (!next) setSearchState("");
586
+ },
587
+ [inert, setOpenState, setSearchState]
588
+ );
589
+ const trimmed = search.trim();
590
+ const visibleOptions = React6.useMemo(() => {
591
+ const filtered = shouldFilter ? filterOptions(options, search) : options;
592
+ return hideSelected ? filtered.filter((option) => !selection.includes(option.value)) : filtered;
593
+ }, [options, search, shouldFilter, hideSelected, selection]);
594
+ const showCreate = onCreate !== void 0 && trimmed.length > 0 && !options.some((option) => foldForMatch(option.label) === foldForMatch(trimmed));
595
+ const groups = React6.useMemo(() => groupOptions(visibleOptions), [visibleOptions]);
596
+ const hasGroups = groups.some((group) => group.group !== void 0);
597
+ const rows = React6.useMemo(() => {
598
+ const list = groups.flatMap((group) => group.options);
599
+ if (showCreate) list.push({ value: CREATE_ROW, label: messages.create(trimmed) });
600
+ return list;
601
+ }, [groups, showCreate, messages, trimmed]);
602
+ const [highlightedValue, setHighlightedValue] = React6.useState(null);
603
+ const highlightedIndex = indexOfValue(rows, highlightedValue);
604
+ React6.useEffect(() => {
605
+ if (!open) return;
606
+ setHighlightedValue((current) => reconcileHighlight(rows, current, "first"));
607
+ }, [open, rows]);
608
+ const openList = React6.useCallback(() => {
609
+ if (open) return;
610
+ setHighlightedValue(value !== null && findOption(rows, value) ? value : null);
611
+ setOpen(true);
612
+ }, [open, rows, setOpen, value]);
613
+ const scrollHighlightedIntoView = React6.useCallback(() => {
614
+ const id = activeDescendantId(listId, rows, highlightedIndex);
615
+ if (!id) return;
616
+ document.getElementById(id)?.scrollIntoView({ block: "nearest" });
617
+ }, [listId, rows, highlightedIndex]);
618
+ React6.useEffect(() => {
619
+ if (open) scrollHighlightedIntoView();
620
+ }, [open, scrollHighlightedIntoView]);
621
+ const focusInput = () => inputRef.current?.focus();
622
+ const activateRow = React6.useCallback(
623
+ (option) => {
624
+ if (option.disabled) return;
625
+ if (option.value === CREATE_ROW) {
626
+ onCreate?.(trimmed);
627
+ setOpen(false);
628
+ return;
629
+ }
630
+ if (multiple) commitSelection(toggleValue(selection, option.value), option);
631
+ else setValue(clearable && option.value === value ? null : option.value);
632
+ if (closeOnSelect) setOpen(false);
633
+ else setSearchState("");
634
+ },
635
+ [
636
+ onCreate,
637
+ trimmed,
638
+ setOpen,
639
+ multiple,
640
+ commitSelection,
641
+ selection,
642
+ setValue,
643
+ clearable,
644
+ value,
645
+ closeOnSelect,
646
+ setSearchState
647
+ ]
648
+ );
649
+ const clear = () => {
650
+ commitSelection([], null);
651
+ setSearchState("");
652
+ focusInput();
653
+ };
654
+ const onKeyDown = (event) => {
655
+ if (inert) return;
656
+ if (event.key === "Escape") {
657
+ if (!open) return;
658
+ event.preventDefault();
659
+ event.stopPropagation();
660
+ setOpen(false);
661
+ return;
662
+ }
663
+ if (event.key === "Tab") {
664
+ if (open) setOpen(false);
665
+ return;
666
+ }
667
+ if (event.key === "Backspace" && multiple && event.currentTarget.value === "") {
668
+ const last = selection[selection.length - 1];
669
+ if (last !== void 0) {
670
+ event.preventDefault();
671
+ removeValue(last);
672
+ }
673
+ return;
674
+ }
675
+ if (event.key === "Enter") {
676
+ if (!open) return;
677
+ event.preventDefault();
678
+ const row = highlightedIndex === null ? void 0 : rows[highlightedIndex];
679
+ if (row) activateRow(row);
680
+ return;
681
+ }
682
+ if (!open && (event.key === "ArrowDown" || event.key === "ArrowUp")) {
683
+ event.preventDefault();
684
+ openList();
685
+ return;
686
+ }
687
+ if (!open) return;
688
+ const next = nextHighlightedIndex(rows, highlightedIndex, event.key);
689
+ if (next === void 0) return;
690
+ event.preventDefault();
691
+ setHighlightedValue(next === null ? null : rows[next]?.value ?? null);
692
+ };
693
+ const displayValue = open || multiple ? search : selectedOption?.label ?? "";
694
+ const singleRenderValue = props.multiple === true ? void 0 : props.renderValue;
695
+ const showValueNode = !open && !multiple && selectedOption !== void 0 && singleRenderValue !== void 0;
696
+ const chips = props.multiple === true ? props.renderValue ? props.renderValue(selectedOptions, { remove: removeValue }) : selectedOptions.map((option) => /* @__PURE__ */ jsx(
697
+ Chip,
698
+ {
699
+ size: "xs",
700
+ disabled,
701
+ className: classNames?.chip,
702
+ removeLabel: messages.remove(option.label),
703
+ onRemove: readOnly ? void 0 : () => removeValue(option.value),
704
+ children: option.label
705
+ },
706
+ option.value
707
+ )) : null;
708
+ const hasChips = props.multiple === true && selectedOptions.length > 0;
709
+ const cmdkCompat = React6.useContext(CmdkCompatContext);
710
+ const buttonSize = BUTTON_SIZE[size];
711
+ const indexByValue = new Map(rows.map((row, index) => [row.value, index]));
712
+ const renderRow = (option) => {
713
+ const index = indexByValue.get(option.value) ?? -1;
714
+ const highlighted = highlightedIndex === index;
715
+ const selected = selection.includes(option.value);
716
+ const isDisabled = option.disabled === true;
717
+ const attributes = listItemAttributes(comboboxAnatomy, {
718
+ id: optionElementId(listId, option.value),
719
+ highlighted,
720
+ selected,
721
+ disabled: isDisabled,
722
+ cmdkCompat
723
+ });
724
+ return (
725
+ // The row is `role="option"` (in `attributes`), operated from the input
726
+ // through `aria-activedescendant`: it is never a focus stop of its own.
727
+ // eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions
728
+ /* @__PURE__ */ jsxs(
729
+ "div",
730
+ {
731
+ ...attributes,
732
+ className: cn(ITEM_CLASSES, classNames?.item),
733
+ onPointerMove: () => {
734
+ if (!isDisabled && highlightedValue !== option.value) setHighlightedValue(option.value);
735
+ },
736
+ onMouseDown: (event) => event.preventDefault(),
737
+ onClick: () => activateRow(option),
738
+ children: [
739
+ renderOption ? renderOption(option, { selected, highlighted, disabled: isDisabled }) : /* @__PURE__ */ jsxs(Fragment, { children: [
740
+ option.icon !== void 0 && /* @__PURE__ */ jsx("span", { className: "ds:inline-flex ds:shrink-0", "aria-hidden": "true", children: option.icon }),
741
+ /* @__PURE__ */ jsxs("span", { className: "ds:min-w-0 ds:flex-1", children: [
742
+ /* @__PURE__ */ jsx("span", { className: "ds:block ds:truncate", children: option.label }),
743
+ option.description !== void 0 && /* @__PURE__ */ jsx("span", { className: cn("ds:text-fg-4 ds:block ds:truncate", SMALL_TEXT), children: option.description })
744
+ ] })
745
+ ] }),
746
+ selected && /* @__PURE__ */ jsx(
747
+ "span",
748
+ {
749
+ ...slot(comboboxAnatomy, "item-indicator"),
750
+ className: LIST_ITEM_INDICATOR_WELL.end,
751
+ children: /* @__PURE__ */ jsx(CheckIcon, { "aria-hidden": "true" })
752
+ }
753
+ )
754
+ ]
755
+ },
756
+ option.value
757
+ )
758
+ );
759
+ };
760
+ const createIndex = rows.length - 1;
761
+ const createHighlighted = showCreate && highlightedIndex === createIndex;
762
+ return /* @__PURE__ */ jsxs(
763
+ "div",
764
+ {
765
+ ...slot(comboboxAnatomy, "root"),
766
+ ...stateAttributes({
767
+ state: open ? "open" : "closed",
768
+ disabled,
769
+ invalid: wiring["aria-invalid"] === true,
770
+ size
771
+ }),
772
+ className: cn("ds:relative ds:w-full", className, classNames?.root),
773
+ children: [
774
+ /* @__PURE__ */ jsxs(Popover, { open, onOpenChange: setOpen, children: [
775
+ /* @__PURE__ */ jsx(PopoverAnchor, { asChild: true, children: /* @__PURE__ */ jsxs(
776
+ "div",
777
+ {
778
+ ref: controlRef,
779
+ ...slot(comboboxAnatomy, "control"),
780
+ className: cn(CONTROL_FRAME, CONTROL_SIZE[size], classNames?.control),
781
+ onPointerDown: (event) => {
782
+ const target = event.target;
783
+ if (inert || target === inputRef.current || target.closest("button")) return;
784
+ event.preventDefault();
785
+ focusInput();
786
+ openList();
787
+ },
788
+ children: [
789
+ icon !== void 0 && /* @__PURE__ */ jsx(
790
+ "span",
791
+ {
792
+ ...slot(comboboxAnatomy, "icon"),
793
+ className: "ds:text-fg-4 ds:inline-flex ds:shrink-0",
794
+ "aria-hidden": "true",
795
+ children: icon
796
+ }
797
+ ),
798
+ showValueNode && // The custom value takes the input's place in the row; the input
799
+ // keeps the label as its value for assistive technology and
800
+ // collapses to a point until the list opens.
801
+ /* @__PURE__ */ jsx(
802
+ "span",
803
+ {
804
+ ...slot(comboboxAnatomy, "value"),
805
+ className: "ds:pointer-events-none ds:flex ds:min-w-0 ds:flex-1 ds:items-center ds:gap-2 ds:truncate",
806
+ "aria-hidden": "true",
807
+ children: singleRenderValue(selectedOption)
808
+ }
809
+ ),
810
+ hasChips && chips !== null && /* @__PURE__ */ jsx(
811
+ "span",
812
+ {
813
+ ...slot(comboboxAnatomy, "chips"),
814
+ className: "ds:flex ds:min-w-0 ds:flex-wrap ds:items-center ds:gap-1 ds:py-1",
815
+ children: chips
816
+ }
817
+ ),
818
+ /* @__PURE__ */ jsx(
819
+ "input",
820
+ {
821
+ ...slot(comboboxAnatomy, "input"),
822
+ ref: mergedInputRef,
823
+ id: wiring.id,
824
+ type: "text",
825
+ role: "combobox",
826
+ autoComplete: "off",
827
+ spellCheck: false,
828
+ "aria-autocomplete": "list",
829
+ "aria-expanded": open,
830
+ "aria-controls": open ? listId : void 0,
831
+ "aria-activedescendant": open ? activeDescendantId(listId, rows, highlightedIndex) : void 0,
832
+ "aria-label": ariaLabel,
833
+ "aria-labelledby": wiring["aria-labelledby"],
834
+ "aria-describedby": wiring["aria-describedby"],
835
+ "aria-invalid": wiring["aria-invalid"],
836
+ "aria-required": wiring["aria-required"],
837
+ "aria-busy": loading || void 0,
838
+ "data-invalid": wiring["data-invalid"],
839
+ "data-disabled": wiring["data-disabled"],
840
+ disabled,
841
+ readOnly,
842
+ placeholder: selectedOption || hasChips ? void 0 : placeholder,
843
+ value: displayValue,
844
+ className: cn(
845
+ INPUT_CLASSES,
846
+ showValueNode && "ds:absolute ds:size-px ds:min-w-0 ds:flex-none ds:opacity-0",
847
+ classNames?.input
848
+ ),
849
+ onChange: (event) => {
850
+ if (inert) return;
851
+ setSearchState(event.target.value);
852
+ if (!open) openList();
853
+ },
854
+ onFocus: () => {
855
+ if (openOnFocus) openList();
856
+ },
857
+ onClick: () => openList(),
858
+ onKeyDown
859
+ }
860
+ ),
861
+ loading && /* @__PURE__ */ jsx(Spinner, { size: "xs", intent: "neutral", "aria-hidden": "true" }),
862
+ clearable && selection.length > 0 && !inert && /* @__PURE__ */ jsx(
863
+ IconButton,
864
+ {
865
+ ...slot(comboboxAnatomy, "clear"),
866
+ label: messages.clear,
867
+ tooltip: false,
868
+ variant: "ghost",
869
+ intent: "neutral",
870
+ size: buttonSize,
871
+ icon: /* @__PURE__ */ jsx(XIcon, {}),
872
+ onClick: clear
873
+ }
874
+ ),
875
+ /* @__PURE__ */ jsx(
876
+ IconButton,
877
+ {
878
+ ...slot(comboboxAnatomy, "toggle"),
879
+ className: "ds:[&:disabled:not([data-loading=true])]:bg-transparent",
880
+ label: messages.toggle,
881
+ tooltip: false,
882
+ variant: "ghost",
883
+ intent: "neutral",
884
+ size: buttonSize,
885
+ tabIndex: -1,
886
+ "aria-expanded": open,
887
+ "aria-controls": open ? listId : void 0,
888
+ disabled: inert,
889
+ icon: /* @__PURE__ */ jsx(
890
+ ChevronDownIcon,
891
+ {
892
+ className: cn(
893
+ "ds:transition-transform ds:duration-[var(--motion-duration-feedback)] ds:motion-reduce:transition-none",
894
+ open && "ds:rotate-180"
895
+ )
896
+ }
897
+ ),
898
+ onMouseDown: (event) => event.preventDefault(),
899
+ onClick: () => {
900
+ focusInput();
901
+ if (open) setOpen(false);
902
+ else openList();
903
+ }
904
+ }
905
+ )
906
+ ]
907
+ }
908
+ ) }),
909
+ /* @__PURE__ */ jsx(
910
+ PopoverContent,
911
+ {
912
+ ...slot(comboboxAnatomy, "content"),
913
+ role: "presentation",
914
+ align: "start",
915
+ sideOffset: 4,
916
+ avoidCollisions,
917
+ onOpenAutoFocus: (event) => event.preventDefault(),
918
+ onCloseAutoFocus: (event) => event.preventDefault(),
919
+ onInteractOutside: (event) => {
920
+ if (controlRef.current?.contains(event.target)) event.preventDefault();
921
+ },
922
+ style: {
923
+ width: "var(--radix-popover-trigger-width)",
924
+ maxHeight: "var(--radix-popover-content-available-height)"
925
+ },
926
+ className: cn(
927
+ "ds:flex ds:min-w-48 ds:flex-col ds:overflow-hidden ds:p-0",
928
+ classNames?.content
929
+ ),
930
+ children: /* @__PURE__ */ jsxs(NestedScrollLock, { children: [
931
+ header !== void 0 && /* @__PURE__ */ jsx(
932
+ "div",
933
+ {
934
+ ...slot(comboboxAnatomy, "header"),
935
+ className: "ds:border-rule ds:shrink-0 ds:border-b",
936
+ children: header
937
+ }
938
+ ),
939
+ /* @__PURE__ */ jsxs(
940
+ "div",
941
+ {
942
+ ...slot(comboboxAnatomy, "list"),
943
+ id: listId,
944
+ role: "listbox",
945
+ "aria-multiselectable": multiple || void 0,
946
+ "aria-labelledby": wiring["aria-labelledby"],
947
+ "aria-label": wiring["aria-labelledby"] ? void 0 : ariaLabel,
948
+ className: cn(
949
+ "ds:scrollbar-thin ds:min-h-0 ds:flex-1 ds:max-h-[min(20rem,60vh)] ds:overflow-y-auto ds:p-1",
950
+ classNames?.list
951
+ ),
952
+ children: [
953
+ hasGroups ? groups.map((group, groupIndex) => {
954
+ const headingId = group.group === void 0 ? void 0 : `${listId}-group-${groupIndex}`;
955
+ return /* @__PURE__ */ jsxs(
956
+ "div",
957
+ {
958
+ ...slot(comboboxAnatomy, "group"),
959
+ role: "group",
960
+ "aria-labelledby": headingId,
961
+ children: [
962
+ group.group !== void 0 && /* @__PURE__ */ jsx(
963
+ "div",
964
+ {
965
+ ...slot(comboboxAnatomy, "group-heading"),
966
+ id: headingId,
967
+ role: "presentation",
968
+ className: GROUP_HEADING_CLASSES,
969
+ children: group.group
970
+ }
971
+ ),
972
+ group.options.map(renderRow)
973
+ ]
974
+ },
975
+ group.group ?? `ungrouped-${groupIndex}`
976
+ );
977
+ }) : visibleOptions.map(renderRow),
978
+ showCreate && /* @__PURE__ */ jsxs(Fragment, { children: [
979
+ visibleOptions.length > 0 && /* @__PURE__ */ jsx("div", { className: LIST_SEPARATOR.neutral, role: "presentation" }),
980
+ /* @__PURE__ */ jsxs(
981
+ "div",
982
+ {
983
+ ...listItemAttributes(comboboxAnatomy, {
984
+ id: optionElementId(listId, CREATE_ROW),
985
+ highlighted: createHighlighted,
986
+ selected: false,
987
+ cmdkCompat
988
+ }),
989
+ ...slot(comboboxAnatomy, "create"),
990
+ className: CREATE_ITEM_CLASSES,
991
+ onPointerMove: () => {
992
+ if (highlightedValue !== CREATE_ROW)
993
+ setHighlightedValue(CREATE_ROW);
994
+ },
995
+ onMouseDown: (event) => event.preventDefault(),
996
+ onClick: () => {
997
+ const row = rows[createIndex];
998
+ if (row) activateRow(row);
999
+ },
1000
+ children: [
1001
+ /* @__PURE__ */ jsx(PlusIcon, { "aria-hidden": "true" }),
1002
+ /* @__PURE__ */ jsx("span", { className: "ds:min-w-0 ds:flex-1 ds:truncate", children: messages.create(trimmed) })
1003
+ ]
1004
+ }
1005
+ )
1006
+ ] })
1007
+ ]
1008
+ }
1009
+ ),
1010
+ loading && /* @__PURE__ */ jsx("div", { ...slot(comboboxAnatomy, "loading"), role: "status", className: STATE_CLASSES, children: loadingState ?? messages.loading }),
1011
+ !loading && rows.length === 0 && /* @__PURE__ */ jsx("div", { ...slot(comboboxAnatomy, "empty"), role: "status", className: STATE_CLASSES, children: emptyState ?? messages.empty }),
1012
+ footer !== void 0 && /* @__PURE__ */ jsx(
1013
+ "div",
1014
+ {
1015
+ ...slot(comboboxAnatomy, "footer"),
1016
+ className: "ds:border-rule ds:shrink-0 ds:border-t",
1017
+ children: footer
1018
+ }
1019
+ )
1020
+ ] })
1021
+ }
1022
+ )
1023
+ ] }),
1024
+ /* @__PURE__ */ jsx(
1025
+ FormBridge,
1026
+ {
1027
+ name: wiring.name,
1028
+ value: multiple ? selection : value,
1029
+ form,
1030
+ disabled,
1031
+ required: wiring["aria-required"] === true,
1032
+ focusTarget: inputRef,
1033
+ onReset: () => commitSelection(defaultSelection, null)
1034
+ }
1035
+ )
1036
+ ]
1037
+ }
1038
+ );
1039
+ }
1040
+ Combobox.displayName = "Combobox";
1041
+ function ClientSelect({
1042
+ clients,
1043
+ value,
1044
+ onChange,
1045
+ name = "client_id",
1046
+ error,
1047
+ className,
1048
+ placeholder = "Select a client..."
1049
+ }) {
1050
+ const options = React6.useMemo(
1051
+ () => clients.map((client) => ({
1052
+ value: client.id,
1053
+ label: client.label,
1054
+ keywords: client.email ? [client.email] : void 0,
1055
+ meta: client
1056
+ })),
1057
+ [clients]
1058
+ );
1059
+ return /* @__PURE__ */ jsxs("div", { className: cn("ds:relative ds:w-full", className), children: [
1060
+ /* @__PURE__ */ jsx(
1061
+ Combobox,
1062
+ {
1063
+ options,
1064
+ name,
1065
+ value,
1066
+ onValueChange: (next) => onChange(next),
1067
+ "aria-label": placeholder,
1068
+ placeholder,
1069
+ invalid: Boolean(error),
1070
+ messages: clients.length === 0 ? { empty: "No clients yet" } : void 0,
1071
+ renderValue: (option) => option.label,
1072
+ renderOption: (option) => {
1073
+ const email = option.meta?.email;
1074
+ return /* @__PURE__ */ jsxs("span", { className: "ds:flex ds:min-w-0 ds:flex-col", children: [
1075
+ /* @__PURE__ */ jsx("span", { className: "ds:text-fg ds:line-clamp-1 ds:text-[13px] ds:font-medium", children: option.label }),
1076
+ email && /* @__PURE__ */ jsx("span", { className: "ds:text-fg-3 ds:line-clamp-1 ds:text-xs", children: email })
1077
+ ] });
1078
+ }
1079
+ }
1080
+ ),
1081
+ error && /* @__PURE__ */ jsx("p", { role: "alert", className: "ds:text-danger-fg ds:mt-1.5 ds:text-xs", children: error })
1082
+ ] });
1083
+ }
1084
+ ClientSelect.displayName = "ClientSelect";
1085
+ var Collapsible = React6.forwardRef(function Collapsible2({ className, ...props }, ref) {
1086
+ return /* @__PURE__ */ jsx(CollapsiblePrimitive.Root, { ref, className: cn(className), ...props });
1087
+ });
1088
+ Collapsible.displayName = CollapsiblePrimitive.Root.displayName;
1089
+ var CollapsibleTrigger = React6.forwardRef(function CollapsibleTrigger2({ className, ...props }, ref) {
1090
+ return /* @__PURE__ */ jsx(
1091
+ CollapsiblePrimitive.Trigger,
1092
+ {
1093
+ ref,
1094
+ className: cn(
1095
+ "ds:flex ds:w-full ds:items-center",
1096
+ "ds:focus-visible:[box-shadow:var(--shadow-focus-ring)] ds:focus-visible:outline-none",
1097
+ className
1098
+ ),
1099
+ ...props
1100
+ }
1101
+ );
1102
+ });
1103
+ CollapsibleTrigger.displayName = CollapsiblePrimitive.Trigger.displayName;
1104
+ var CollapsibleContent = React6.forwardRef(function CollapsibleContent2({ className, ...props }, ref) {
1105
+ return /* @__PURE__ */ jsx(
1106
+ CollapsiblePrimitive.Content,
1107
+ {
1108
+ ref,
1109
+ className: cn(
1110
+ "ds:overflow-hidden",
1111
+ "ds:data-[state=closed]:animate-[collapsible-up_var(--duration-overlay)_var(--ease-out-quart)]",
1112
+ "ds:data-[state=open]:animate-[collapsible-down_var(--duration-overlay)_var(--ease-out-quart)]",
1113
+ "ds:motion-reduce:animate-none",
1114
+ className
1115
+ ),
1116
+ ...props
1117
+ }
1118
+ );
1119
+ });
1120
+ CollapsibleContent.displayName = CollapsiblePrimitive.Content.displayName;
1121
+ var ComingSoon = forwardRef(function ComingSoon2({ icon, title, description, features, className, messages: messagesProp, ...props }, ref) {
1122
+ const messages = useDsMessages("comingSoon", messagesProp);
1123
+ return /* @__PURE__ */ jsx(
1124
+ "div",
1125
+ {
1126
+ ref,
1127
+ className: cn("ds:flex ds:items-center ds:justify-center ds:px-6 ds:py-16", className),
1128
+ ...props,
1129
+ children: /* @__PURE__ */ jsxs(
1130
+ "div",
1131
+ {
1132
+ className: cn(
1133
+ "ds:rounded-card ds:border-rule-strong ds:w-full ds:max-w-lg ds:border ds:border-dashed",
1134
+ "ds:bg-surface ds:shadow-quiet ds:p-10 ds:text-center"
1135
+ ),
1136
+ children: [
1137
+ /* @__PURE__ */ jsx("div", { className: "ds:text-brand ds:mb-5 ds:font-mono ds:text-[11px] ds:font-normal ds:tracking-[0.14em] ds:uppercase", children: messages.eyebrow }),
1138
+ /* @__PURE__ */ jsx(
1139
+ "div",
1140
+ {
1141
+ className: cn(
1142
+ "ds:mx-auto ds:mb-4 ds:flex ds:size-12 ds:items-center ds:justify-center",
1143
+ "ds:rounded-icon ds:bg-brand-bg ds:text-brand ds:[&>svg]:size-6"
1144
+ ),
1145
+ children: icon
1146
+ }
1147
+ ),
1148
+ /* @__PURE__ */ jsx("h1", { className: "ds:font-display ds:text-fg ds:text-xl ds:font-medium ds:tracking-[-0.022em]", children: title }),
1149
+ /* @__PURE__ */ jsx("p", { className: "ds:text-fg-3 ds:mt-1.5 ds:text-sm", children: description }),
1150
+ /* @__PURE__ */ jsx("ul", { className: "ds:mt-6 ds:space-y-2 ds:text-left", children: features.map((feature) => /* @__PURE__ */ jsxs("li", { className: "ds:text-fg-2 ds:flex ds:items-center ds:gap-2 ds:text-sm", children: [
1151
+ /* @__PURE__ */ jsx(
1152
+ CheckIcon,
1153
+ {
1154
+ className: "ds:text-success-fg ds:size-3.5 ds:shrink-0",
1155
+ strokeWidth: 2.5,
1156
+ "aria-hidden": "true"
1157
+ }
1158
+ ),
1159
+ feature
1160
+ ] }, feature)) }),
1161
+ /* @__PURE__ */ jsx("div", { className: "ds:mt-6", children: /* @__PURE__ */ jsx(
1162
+ "span",
1163
+ {
1164
+ className: cn(
1165
+ "ds:rounded-pill ds:inline-flex ds:items-center ds:border ds:px-2.5 ds:py-0.5",
1166
+ "ds:text-xs ds:font-medium",
1167
+ "ds:bg-brand-bg ds:text-brand ds:border-[color:var(--color-brand-bg-active)]"
1168
+ ),
1169
+ children: messages.badge
1170
+ }
1171
+ ) })
1172
+ ]
1173
+ }
1174
+ )
1175
+ }
1176
+ );
1177
+ });
1178
+ ComingSoon.displayName = "ComingSoon";
1179
+
1180
+ // src/lib/asset-base.ts
1181
+ var basePath = "/";
1182
+ function setAssetBasePath(base) {
1183
+ const trimmed = (base ?? "").replace(/\/+$/, "");
1184
+ basePath = trimmed === "" ? "/" : `${trimmed.startsWith("/") ? "" : "/"}${trimmed}/`;
1185
+ }
1186
+ function getAssetBasePath() {
1187
+ return basePath;
1188
+ }
1189
+ function assetPath(path) {
1190
+ return `${basePath}${path.replace(/^\/+/, "")}`;
1191
+ }
1192
+ function PlainLink({ ref, children, ...props }) {
1193
+ return /* @__PURE__ */ jsx("a", { ref, ...props, children });
1194
+ }
1195
+ function PlainImage({ priority, alt, ...props }) {
1196
+ return /* @__PURE__ */ jsx(
1197
+ "img",
1198
+ {
1199
+ alt,
1200
+ ...priority ? { loading: "eager", fetchPriority: "high" } : {},
1201
+ ...props
1202
+ }
1203
+ );
1204
+ }
1205
+ var sizeStyles = {
1206
+ sm: { icon: 20, text: "ds:text-sm", gap: "ds:gap-2", assetHeight: 24 },
1207
+ md: { icon: 24, text: "ds:text-[17px]", gap: "ds:gap-2.5", assetHeight: 30 },
1208
+ lg: { icon: 32, text: "ds:text-xl", gap: "ds:gap-3", assetHeight: 40 },
1209
+ xl: { icon: 40, text: "ds:text-2xl", gap: "ds:gap-3.5", assetHeight: 48 }
1210
+ };
1211
+ var productLogoAssets = {
1212
+ Pro: { src: "/brand/assure-pro.svg", width: 384, height: 90 },
1213
+ Audit: { src: "/brand/assure-audit.svg", width: 441, height: 90 },
1214
+ Books: { src: "/brand/assure-books.svg", width: 470, height: 90 },
1215
+ Tax: { src: "/brand/assure-tax.svg", width: 374, height: 90 },
1216
+ Teams: { src: "/brand/mycpe-teams.svg", width: 221, height: 49 }
1217
+ };
1218
+ var productMarkAssets = {
1219
+ Pro: { src: "/brand/assure-pro-mark.svg", width: 55, height: 48 },
1220
+ Audit: { src: "/brand/assure-audit-mark.svg", width: 55, height: 48 },
1221
+ Books: { src: "/brand/assure-books-mark.svg", width: 55, height: 48 },
1222
+ Tax: { src: "/brand/assure-tax-mark.svg", width: 55, height: 48 },
1223
+ Teams: { src: "/brand/mycpe-teams-mark.svg", width: 26, height: 31 }
1224
+ };
1225
+ var productGlyphs = {
1226
+ Pro: AssureProBrandIcon,
1227
+ Audit: AssureAuditBrandIcon,
1228
+ Books: AssureBooksBrandIcon,
1229
+ Tax: AssureTaxBrandIcon
1230
+ };
1231
+ var standaloneBrands = {
1232
+ Teams: "myCPE Teams"
1233
+ };
1234
+ function Logo({
1235
+ size = "md",
1236
+ href = "/",
1237
+ showText = true,
1238
+ className,
1239
+ iconClassName,
1240
+ textClassName,
1241
+ productName = "Pro",
1242
+ inverted = false
1243
+ }) {
1244
+ const RouterLink = useLinkComponent() ?? PlainLink;
1245
+ const Img = useImageComponent() ?? PlainImage;
1246
+ const [artworkFailed, setArtworkFailed] = React6.useState(false);
1247
+ const s = sizeStyles[size];
1248
+ const standaloneLabel = productName ? standaloneBrands[productName] : void 0;
1249
+ const isStandalone = Boolean(standaloneLabel);
1250
+ const ariaLabel = standaloneLabel ?? (productName ? `Assure ${productName}` : "Assure");
1251
+ const asset = productName ? productLogoAssets[productName] : void 0;
1252
+ const markAsset = productName ? productMarkAssets[productName] : void 0;
1253
+ const Glyph = productName ? productGlyphs[productName] : void 0;
1254
+ const wordmark = artworkFailed || !showText ? void 0 : asset;
1255
+ const mark = artworkFailed || wordmark ? void 0 : markAsset;
1256
+ const wrapperClassName = cn("ds:inline-flex ds:items-center", s.gap, className);
1257
+ const content = /* @__PURE__ */ jsxs(Fragment, { children: [
1258
+ wordmark ? /* @__PURE__ */ jsx(
1259
+ Img,
1260
+ {
1261
+ src: assetPath(wordmark.src),
1262
+ alt: "",
1263
+ width: wordmark.width,
1264
+ height: wordmark.height,
1265
+ priority: true,
1266
+ onError: () => setArtworkFailed(true),
1267
+ className: cn(
1268
+ "ds:h-auto ds:flex-shrink-0",
1269
+ inverted && "ds:brightness-0 ds:invert",
1270
+ iconClassName
1271
+ ),
1272
+ style: { width: Math.round(wordmark.width / wordmark.height * s.assetHeight) }
1273
+ }
1274
+ ) : mark ? /* @__PURE__ */ jsx(
1275
+ Img,
1276
+ {
1277
+ src: assetPath(mark.src),
1278
+ alt: "",
1279
+ width: mark.width,
1280
+ height: mark.height,
1281
+ priority: true,
1282
+ onError: () => setArtworkFailed(true),
1283
+ className: cn(
1284
+ "ds:h-auto ds:flex-shrink-0",
1285
+ inverted && "ds:brightness-0 ds:invert",
1286
+ iconClassName
1287
+ ),
1288
+ style: { width: Math.round(mark.width / mark.height * s.icon) }
1289
+ }
1290
+ ) : /* @__PURE__ */ jsx(Fragment, { children: Glyph ? /* @__PURE__ */ jsx(Glyph, { size: s.icon, "aria-hidden": "true", className: iconClassName }) : /* @__PURE__ */ jsx(
1291
+ "span",
1292
+ {
1293
+ "aria-hidden": "true",
1294
+ className: cn(
1295
+ "ds:bg-pro-fg ds:grid ds:shrink-0 ds:place-items-center ds:rounded-[5px] ds:text-[10px] ds:font-bold ds:text-white",
1296
+ iconClassName
1297
+ ),
1298
+ style: { width: s.icon, height: s.icon },
1299
+ children: "A"
1300
+ }
1301
+ ) }),
1302
+ showText && /* @__PURE__ */ jsx(
1303
+ "span",
1304
+ {
1305
+ className: cn(
1306
+ "ds:font-display ds:font-semibold ds:tracking-[-0.025em]",
1307
+ s.text,
1308
+ inverted ? "ds:text-white" : "ds:text-fg",
1309
+ wordmark && "ds:sr-only",
1310
+ textClassName
1311
+ ),
1312
+ children: isStandalone ? /* @__PURE__ */ jsx("span", { children: standaloneLabel }) : /* @__PURE__ */ jsxs(Fragment, { children: [
1313
+ /* @__PURE__ */ jsx("span", { children: "Assure" }),
1314
+ productName && /* @__PURE__ */ jsxs(Fragment, { children: [
1315
+ " ",
1316
+ /* @__PURE__ */ jsx(
1317
+ "span",
1318
+ {
1319
+ className: cn(
1320
+ "ds:font-medium",
1321
+ inverted ? "ds:text-[#d8cfff]" : "ds:text-pro-fg"
1322
+ ),
1323
+ children: productName
1324
+ }
1325
+ )
1326
+ ] })
1327
+ ] })
1328
+ }
1329
+ )
1330
+ ] });
1331
+ if (href === null) {
1332
+ return /* @__PURE__ */ jsx("span", { className: wrapperClassName, children: content });
1333
+ }
1334
+ return /* @__PURE__ */ jsx(RouterLink, { href, className: wrapperClassName, "aria-label": ariaLabel, children: content });
1335
+ }
1336
+ var SheetSideContext = React6.createContext({});
1337
+ var Sheet = ({ side, children, ...props }) => /* @__PURE__ */ jsx(SheetPrimitive.Root, { ...props, children: /* @__PURE__ */ jsx(SheetSideContext, { value: { side }, children }) });
1338
+ Sheet.displayName = "Sheet";
1339
+ var SheetTrigger = SheetPrimitive.Trigger;
1340
+ var SheetClose = SheetPrimitive.Close;
1341
+ var SheetPortal = withPortalContainer(SheetPrimitive.Portal);
1342
+ var SheetOverlay = React6.forwardRef((props, ref) => /* @__PURE__ */ jsx(
1343
+ Backdrop,
1344
+ {
1345
+ as: SheetPrimitive.Overlay,
1346
+ anatomy: sheetAnatomy,
1347
+ motion: "legacy",
1348
+ ref,
1349
+ ...props
1350
+ }
1351
+ ));
1352
+ SheetOverlay.displayName = SheetPrimitive.Overlay.displayName;
1353
+ var SHEET_SIZES = {
1354
+ sm: "ds:w-[95vw] ds:max-w-[95vw] ds:sm:w-[var(--ds-sheet-width,420px)]",
1355
+ md: "ds:w-[95vw] ds:max-w-[95vw] ds:sm:w-[var(--ds-sheet-width,520px)]",
1356
+ lg: "ds:w-[95vw] ds:max-w-[95vw] ds:sm:w-[var(--ds-sheet-width,640px)]",
1357
+ xl: "ds:w-[95vw] ds:max-w-[95vw] ds:sm:w-[var(--ds-sheet-width,760px)]",
1358
+ full: "ds:w-full ds:max-w-none"
1359
+ };
1360
+ var SheetContent = React6.forwardRef(
1361
+ ({
1362
+ side,
1363
+ size,
1364
+ width,
1365
+ customWidth,
1366
+ className,
1367
+ children,
1368
+ showCloseButton = true,
1369
+ closeLabel,
1370
+ messages,
1371
+ style,
1372
+ ...props
1373
+ }, ref) => {
1374
+ const ctx = React6.use(SheetSideContext);
1375
+ const resolvedSide = side ?? ctx.side ?? "right";
1376
+ const supportsWidth = resolvedSide === "left" || resolvedSide === "right";
1377
+ if (width !== void 0) {
1378
+ deprecate(
1379
+ "C-SHEET-WIDTH",
1380
+ "width",
1381
+ "SheetContent `width` is deprecated; pass `size` (the same steps) instead."
1382
+ );
1383
+ }
1384
+ if (customWidth !== void 0) {
1385
+ deprecate(
1386
+ "C-SHEET-WIDTH",
1387
+ "customWidth",
1388
+ "SheetContent `customWidth` is deprecated; set the `--ds-sheet-width` custom property instead."
1389
+ );
1390
+ }
1391
+ const resolvedSize = size ?? (width === void 0 || width === "default" ? void 0 : width);
1392
+ const sizeRow = supportsWidth && resolvedSize ? SHEET_SIZES[resolvedSize] : null;
1393
+ const widthStyle = supportsWidth && customWidth ? { width: customWidth, maxWidth: "95vw", ...style } : style;
1394
+ return /* @__PURE__ */ jsxs(SheetPortal, { children: [
1395
+ /* @__PURE__ */ jsx(SheetOverlay, {}),
1396
+ /* @__PURE__ */ jsxs(
1397
+ OverlaySurface,
1398
+ {
1399
+ as: SheetPrimitive.Content,
1400
+ anatomy: sheetAnatomy,
1401
+ placement: resolvedSide,
1402
+ motion: "legacy",
1403
+ ref,
1404
+ ...stateAttributes({ size: resolvedSize ?? "default" }),
1405
+ rows: [sizeRow],
1406
+ className,
1407
+ style: widthStyle,
1408
+ ...props,
1409
+ children: [
1410
+ children,
1411
+ showCloseButton && /* @__PURE__ */ jsx(
1412
+ DismissButton,
1413
+ {
1414
+ as: SheetPrimitive.Close,
1415
+ anatomy: sheetAnatomy,
1416
+ label: closeLabel ?? messages?.close ?? DEFAULT_OVERLAY_MESSAGES.close,
1417
+ children: /* @__PURE__ */ jsx(XIcon, { className: DISMISS_GLYPH_CLASSES, "aria-hidden": "true" })
1418
+ }
1419
+ )
1420
+ ]
1421
+ }
1422
+ )
1423
+ ] });
1424
+ }
1425
+ );
1426
+ SheetContent.displayName = SheetPrimitive.Content.displayName;
1427
+ var SheetHeader = (props) => /* @__PURE__ */ jsx(OverlayHeader, { anatomy: sheetAnatomy, layout: "padded", dismissGutter: true, ...props });
1428
+ SheetHeader.displayName = "SheetHeader";
1429
+ var SheetBody = React6.forwardRef(
1430
+ ({ padding = "md", ...props }, ref) => /* @__PURE__ */ jsx(OverlayBody, { anatomy: sheetAnatomy, layout: "padded", padding, ref, ...props })
1431
+ );
1432
+ SheetBody.displayName = "SheetBody";
1433
+ var SheetFooter = (props) => /* @__PURE__ */ jsx(OverlayFooter, { anatomy: sheetAnatomy, layout: "padded", ...props });
1434
+ SheetFooter.displayName = "SheetFooter";
1435
+ var SheetTitle = React6.forwardRef((props, ref) => /* @__PURE__ */ jsx(OverlayTitle, { as: SheetPrimitive.Title, anatomy: sheetAnatomy, ref, ...props }));
1436
+ SheetTitle.displayName = SheetPrimitive.Title.displayName;
1437
+ var SheetDescription = React6.forwardRef((props, ref) => /* @__PURE__ */ jsx(OverlayDescription, { as: SheetPrimitive.Description, anatomy: sheetAnatomy, ref, ...props }));
1438
+ SheetDescription.displayName = SheetPrimitive.Description.displayName;
1439
+ var ICON_BTN = cn(
1440
+ "ds:inline-flex ds:size-9 ds:shrink-0 ds:items-center ds:justify-center ds:rounded-[9px]",
1441
+ "ds:border-rule-strong ds:bg-surface ds:text-fg-3 ds:border",
1442
+ "ds:transition-colors ds:duration-[var(--duration-fast)] ds:ease-[var(--ease-out-quart)] ds:motion-reduce:transition-none",
1443
+ "ds:hover:bg-surface-hover ds:hover:text-fg",
1444
+ "ds:focus-visible:[box-shadow:var(--shadow-focus-ring)] ds:focus-visible:outline-none"
1445
+ );
1446
+ var MIN_ACCENT_CONTRAST = 4.5;
1447
+ function legibleAccent(accent) {
1448
+ const rgb = parseHexColor(accent);
1449
+ if (!rgb || contrastRatio(rgb, WHITE) >= MIN_ACCENT_CONTRAST) return accent;
1450
+ return formatHexColor(darkenUntilContrast(rgb, WHITE, MIN_ACCENT_CONTRAST));
1451
+ }
1452
+ var AgreementViewer = forwardRef(
1453
+ function AgreementViewer2({
1454
+ title,
1455
+ overline = "Signed agreement",
1456
+ steps,
1457
+ firm,
1458
+ status = "signed",
1459
+ banner,
1460
+ accent,
1461
+ coverRail = true,
1462
+ step,
1463
+ defaultStep = 0,
1464
+ onStepChange,
1465
+ onDownload,
1466
+ onClose,
1467
+ headerActions,
1468
+ nextDisabled = false,
1469
+ nextDisabledReason,
1470
+ footer,
1471
+ className
1472
+ }, ref) {
1473
+ const reasonId = useId();
1474
+ const [internalStep, setInternalStep] = useState(defaultStep);
1475
+ const current = step ?? internalStep;
1476
+ const isControlled = step !== void 0;
1477
+ const lastIndex = steps.length - 1;
1478
+ const goTo = (n) => {
1479
+ if (n < 0 || n > lastIndex || n === current) return;
1480
+ if (!isControlled) setInternalStep(n);
1481
+ onStepChange?.(n);
1482
+ };
1483
+ const isCover = current === 0;
1484
+ const monogram = firm.initials ?? firm.name.charAt(0);
1485
+ const bannerContent = banner === void 0 ? status === "signed" ? "Showing the services your client accepted, at the prices locked in at signing." : "Review each section at your pace, then sign whenever you're ready." : banner;
1486
+ return /* @__PURE__ */ jsxs(
1487
+ "div",
1488
+ {
1489
+ ref,
1490
+ "data-slot": "agreement-viewer",
1491
+ "data-status": status,
1492
+ "data-view": isCover ? "cover" : "inner",
1493
+ style: accent ? { "--av-accent": legibleAccent(accent) } : void 0,
1494
+ className: cn(
1495
+ // Fills its container's height so the content pane scrolls internally
1496
+ // while the header, rail, and footer stay fixed — give the parent a
1497
+ // height (e.g. h-screen / a fixed card height). Falls back to a 600px
1498
+ // floor so it never collapses when dropped in an unsized container.
1499
+ // Responsive via CONTAINER queries (@container/agreement), not viewport:
1500
+ // the side rails + generous padding only appear when the viewer's own
1501
+ // container is wide (≥64rem). In a phone frame or a narrow panel it
1502
+ // collapses to the single-column compact layout regardless of the
1503
+ // browser viewport.
1504
+ "ds:group/agreement ds:@container/agreement ds:bg-bg ds:text-fg ds:flex ds:h-full ds:min-h-[600px] ds:flex-col ds:font-sans",
1505
+ className
1506
+ ),
1507
+ children: [
1508
+ /* @__PURE__ */ jsxs("header", { className: "ds:flex ds:items-center ds:gap-2.5 ds:px-4 ds:pt-4 ds:pb-3 ds:@5xl/agreement:gap-3.5 ds:@5xl/agreement:px-7", children: [
1509
+ /* @__PURE__ */ jsx(
1510
+ "span",
1511
+ {
1512
+ "aria-hidden": "true",
1513
+ className: "ds:rounded-icon ds:flex ds:size-9 ds:shrink-0 ds:items-center ds:justify-center ds:bg-[var(--av-accent-tint)] ds:text-[var(--av-accent)]",
1514
+ children: /* @__PURE__ */ jsx(EyeIcon, { className: "ds:size-4.5" })
1515
+ }
1516
+ ),
1517
+ /* @__PURE__ */ jsxs("div", { className: "ds:flex ds:min-w-0 ds:flex-col", children: [
1518
+ /* @__PURE__ */ jsx("span", { className: "ds:text-fg-3 ds:text-[11.5px] ds:leading-tight ds:font-semibold", children: overline }),
1519
+ /* @__PURE__ */ jsx("span", { className: "ds:font-display ds:text-fg ds:truncate ds:text-[17px] ds:leading-tight ds:font-semibold ds:tracking-tight", children: title })
1520
+ ] }),
1521
+ /* @__PURE__ */ jsxs("div", { className: "ds:ml-auto ds:flex ds:items-center ds:gap-2", children: [
1522
+ !isCover && /* @__PURE__ */ jsxs("span", { className: "ds:border-rule ds:bg-bg-2 ds:text-fg-2 ds:shrink-0 ds:rounded-md ds:border ds:px-2.5 ds:py-1 ds:text-xs ds:font-semibold ds:whitespace-nowrap", children: [
1523
+ "Step ",
1524
+ current + 1,
1525
+ " of ",
1526
+ steps.length
1527
+ ] }),
1528
+ headerActions,
1529
+ onDownload && /* @__PURE__ */ jsxs(
1530
+ "button",
1531
+ {
1532
+ type: "button",
1533
+ onClick: onDownload,
1534
+ "aria-label": "Download PDF",
1535
+ className: cn(
1536
+ "ds:inline-flex ds:h-9 ds:shrink-0 ds:items-center ds:gap-1.5 ds:rounded-[9px] ds:px-2.5 ds:text-[13px] ds:font-medium ds:whitespace-nowrap ds:@5xl/agreement:px-3.5",
1537
+ "ds:border-rule-strong ds:bg-surface ds:text-fg ds:border",
1538
+ "ds:transition-colors ds:duration-[var(--duration-fast)] ds:ease-[var(--ease-out-quart)] ds:motion-reduce:transition-none",
1539
+ "ds:hover:bg-surface-hover",
1540
+ "ds:focus-visible:[box-shadow:var(--shadow-focus-ring)] ds:focus-visible:outline-none"
1541
+ ),
1542
+ children: [
1543
+ /* @__PURE__ */ jsx(DownloadIcon, { className: "ds:size-4", "aria-hidden": "true" }),
1544
+ /* @__PURE__ */ jsx("span", { className: "ds:hidden ds:@5xl/agreement:inline", children: "Download PDF" })
1545
+ ]
1546
+ }
1547
+ ),
1548
+ onClose && /* @__PURE__ */ jsx("button", { type: "button", onClick: onClose, "aria-label": "Close", className: ICON_BTN, children: /* @__PURE__ */ jsx(XIcon, { className: "ds:size-4", "aria-hidden": "true" }) })
1549
+ ] })
1550
+ ] }),
1551
+ bannerContent != null && /* @__PURE__ */ jsxs(
1552
+ "div",
1553
+ {
1554
+ className: cn(
1555
+ "ds:mx-4 ds:flex ds:items-center ds:gap-2.5 ds:rounded-[11px] ds:border ds:px-4 ds:py-2.5 ds:text-[13.5px] ds:font-medium ds:@5xl/agreement:mx-7",
1556
+ status === "signed" ? "ds:border-success-line ds:bg-success-bg ds:text-success-fg" : "ds:border-[var(--av-accent-tint2)] ds:bg-[var(--av-accent-tint)] ds:text-[var(--av-accent-soft)]"
1557
+ ),
1558
+ children: [
1559
+ /* @__PURE__ */ jsx(CheckIcon, { className: "ds:size-4 ds:shrink-0", "aria-hidden": "true" }),
1560
+ /* @__PURE__ */ jsx("span", { children: bannerContent })
1561
+ ]
1562
+ }
1563
+ ),
1564
+ /* @__PURE__ */ jsxs("div", { className: "ds:flex ds:min-h-0 ds:flex-1 ds:flex-col ds:px-4 ds:pt-3 ds:pb-5 ds:@5xl/agreement:px-7 ds:@5xl/agreement:pb-8", children: [
1565
+ /* @__PURE__ */ jsxs("div", { className: "ds:border-rule ds:bg-surface ds:shadow-card ds:flex ds:min-h-0 ds:flex-1 ds:overflow-hidden ds:rounded-[18px] ds:border", children: [
1566
+ coverRail && /* @__PURE__ */ jsxs(
1567
+ "aside",
1568
+ {
1569
+ className: "ds:hidden ds:w-[340px] ds:shrink-0 ds:flex-col ds:overflow-y-auto ds:p-8 ds:text-white ds:@5xl/agreement:group-data-[view=cover]/agreement:flex",
1570
+ style: {
1571
+ backgroundImage: "linear-gradient(166deg, var(--av-accent-light) 0%, var(--av-accent) 50%, var(--av-accent-deep) 100%)"
1572
+ },
1573
+ children: [
1574
+ /* @__PURE__ */ jsx(
1575
+ "span",
1576
+ {
1577
+ "aria-hidden": "true",
1578
+ className: "ds:rounded-card ds:flex ds:size-[54px] ds:items-center ds:justify-center ds:bg-white ds:text-[17px] ds:font-semibold ds:text-[var(--av-accent)] ds:shadow-raised",
1579
+ children: monogram
1580
+ }
1581
+ ),
1582
+ /* @__PURE__ */ jsx("div", { className: "ds:mt-4 ds:text-[21px] ds:leading-tight ds:font-semibold", children: firm.name }),
1583
+ firm.tagline && /* @__PURE__ */ jsx("div", { className: "ds:mt-1.5 ds:text-[13px] ds:leading-snug ds:text-white/80", children: firm.tagline }),
1584
+ firm.contact && /* @__PURE__ */ jsxs("div", { className: "ds:mt-auto ds:pt-7", children: [
1585
+ /* @__PURE__ */ jsx("div", { className: "ds:mb-4 ds:h-px ds:bg-white/20" }),
1586
+ /* @__PURE__ */ jsxs("div", { className: "ds:flex ds:flex-col ds:gap-3 ds:text-[12.5px] ds:text-white/90", children: [
1587
+ firm.contact.phone && /* @__PURE__ */ jsxs("span", { className: "ds:flex ds:items-center ds:gap-2.5", children: [
1588
+ /* @__PURE__ */ jsx(PhoneIcon, { className: "ds:size-4 ds:shrink-0 ds:opacity-85", "aria-hidden": "true" }),
1589
+ firm.contact.phone
1590
+ ] }),
1591
+ firm.contact.email && /* @__PURE__ */ jsxs("span", { className: "ds:flex ds:items-center ds:gap-2.5", children: [
1592
+ /* @__PURE__ */ jsx(MailIcon, { className: "ds:size-4 ds:shrink-0 ds:opacity-85", "aria-hidden": "true" }),
1593
+ firm.contact.email
1594
+ ] }),
1595
+ firm.contact.website && /* @__PURE__ */ jsxs("span", { className: "ds:flex ds:items-center ds:gap-2.5", children: [
1596
+ /* @__PURE__ */ jsx(GlobeIcon, { className: "ds:size-4 ds:shrink-0 ds:opacity-85", "aria-hidden": "true" }),
1597
+ firm.contact.website
1598
+ ] })
1599
+ ] })
1600
+ ] })
1601
+ ]
1602
+ }
1603
+ ),
1604
+ /* @__PURE__ */ jsxs("aside", { className: "ds:border-rule ds:bg-surface-2 ds:hidden ds:w-[300px] ds:shrink-0 ds:flex-col ds:overflow-y-auto ds:border-r ds:px-6 ds:py-7 ds:@5xl/agreement:group-data-[view=inner]/agreement:flex", children: [
1605
+ /* @__PURE__ */ jsxs("div", { className: "ds:flex ds:items-center ds:gap-3", children: [
1606
+ /* @__PURE__ */ jsx(
1607
+ "span",
1608
+ {
1609
+ "aria-hidden": "true",
1610
+ className: "ds:rounded-icon ds:flex ds:size-10 ds:shrink-0 ds:items-center ds:justify-center ds:bg-[var(--av-accent)] ds:text-[13px] ds:font-bold ds:text-[var(--av-accent-contrast)]",
1611
+ children: monogram
1612
+ }
1613
+ ),
1614
+ /* @__PURE__ */ jsxs("div", { className: "ds:min-w-0", children: [
1615
+ /* @__PURE__ */ jsx("div", { className: "ds:text-fg ds:truncate ds:text-sm ds:font-semibold", children: firm.name }),
1616
+ /* @__PURE__ */ jsx("div", { className: "ds:text-fg-4 ds:text-[11.5px]", children: firm.subtitle ?? "Your proposal" })
1617
+ ] })
1618
+ ] }),
1619
+ /* @__PURE__ */ jsx("div", { className: "ds:text-fg-4 ds:mt-6 ds:text-[11.5px] ds:font-semibold ds:tracking-wide", children: "Sections" }),
1620
+ /* @__PURE__ */ jsx("nav", { "aria-label": "Agreement sections", className: "ds:mt-3 ds:flex ds:flex-col ds:gap-0.5", children: steps.map((s, i) => {
1621
+ const on = i === current;
1622
+ const done = status === "signed" ? i !== current && i !== 0 : i < current;
1623
+ return /* @__PURE__ */ jsxs(
1624
+ "button",
1625
+ {
1626
+ type: "button",
1627
+ onClick: () => goTo(i),
1628
+ "aria-current": on ? "step" : void 0,
1629
+ "data-on": on || void 0,
1630
+ "data-done": done || void 0,
1631
+ "data-first": i === 0 || void 0,
1632
+ className: cn(
1633
+ "ds:group/step ds:text-fg-3 ds:relative ds:z-[calc(var(--z-base)+1)] ds:flex ds:w-full ds:items-center ds:gap-3.5 ds:rounded-[12px] ds:py-2.5 ds:pr-3.5 ds:pl-2 ds:text-left ds:text-[13.5px] ds:font-medium",
1634
+ "ds:transition-colors ds:duration-[var(--duration-normal)] ds:ease-[var(--ease-out-quart)] ds:motion-reduce:transition-none",
1635
+ "ds:hover:bg-surface-hover",
1636
+ "ds:data-[on]:bg-[var(--av-accent-tint)] ds:data-[on]:font-semibold ds:data-[on]:text-[var(--av-accent-soft)]",
1637
+ "ds:focus-visible:[box-shadow:var(--shadow-focus-ring)] ds:focus-visible:outline-none"
1638
+ ),
1639
+ children: [
1640
+ /* @__PURE__ */ jsx(
1641
+ "span",
1642
+ {
1643
+ "aria-hidden": "true",
1644
+ className: cn(
1645
+ "ds:relative ds:flex ds:size-7 ds:shrink-0 ds:items-center ds:justify-center ds:rounded-full ds:border-[1.5px] ds:text-[12.5px] ds:font-semibold",
1646
+ "ds:border-[var(--av-accent-tint2)] ds:bg-[var(--color-surface)] ds:text-[var(--av-accent)]",
1647
+ "ds:transition-colors ds:duration-[var(--duration-normal)] ds:ease-[var(--ease-out-quart)] ds:motion-reduce:transition-none",
1648
+ // connector to the node above (skipped on the first step)
1649
+ "ds:before:absolute ds:before:bottom-full ds:before:left-1/2 ds:before:h-[18px] ds:before:w-[2.5px] ds:before:-translate-x-1/2 ds:before:rounded-full ds:before:bg-[var(--av-accent-tint2)] ds:before:transition-colors ds:before:content-['']",
1650
+ "ds:group-data-[first]/step:before:hidden",
1651
+ "ds:group-data-[done]/step:border-[var(--av-accent)] ds:group-data-[done]/step:bg-[var(--av-accent)] ds:group-data-[done]/step:text-[var(--av-accent-contrast)] ds:group-data-[done]/step:before:bg-[var(--av-accent)]",
1652
+ "ds:group-data-[on]/step:border-[var(--av-accent)] ds:group-data-[on]/step:bg-[var(--av-accent)] ds:group-data-[on]/step:text-[var(--av-accent-contrast)] ds:group-data-[on]/step:before:bg-[var(--av-accent)]"
1653
+ ),
1654
+ children: s.icon ?? (i === 0 ? /* @__PURE__ */ jsx(HomeIcon, { className: "ds:size-3.5" }) : done ? /* @__PURE__ */ jsx(CheckIcon, { className: "ds:size-3.5" }) : i)
1655
+ }
1656
+ ),
1657
+ /* @__PURE__ */ jsx("span", { className: "ds:truncate", children: s.label })
1658
+ ]
1659
+ },
1660
+ s.id
1661
+ );
1662
+ }) })
1663
+ ] }),
1664
+ /* @__PURE__ */ jsx(
1665
+ "section",
1666
+ {
1667
+ "data-bleed": steps[current]?.bleed || void 0,
1668
+ className: cn(
1669
+ "ds:@container/pane ds:scrollbar-thin ds:flex ds:min-w-0 ds:flex-1 ds:flex-col ds:overflow-y-auto",
1670
+ // `bleed` steps own their own padding so a cover can reach the
1671
+ // card edges — this replaces the app-side
1672
+ // `*:has(> [data-esign-cover]) { padding: 0 }` global rule.
1673
+ steps[current]?.bleed ? "ds:p-0" : "ds:px-5 ds:py-7 ds:@5xl/agreement:px-[52px] ds:@5xl/agreement:py-11"
1674
+ ),
1675
+ children: steps[current]?.content
1676
+ }
1677
+ )
1678
+ ] }),
1679
+ /* @__PURE__ */ jsxs("div", { className: "ds:mt-4 ds:flex ds:items-center ds:justify-between", children: [
1680
+ /* @__PURE__ */ jsxs(
1681
+ "button",
1682
+ {
1683
+ type: "button",
1684
+ onClick: () => goTo(current - 1),
1685
+ disabled: current === 0,
1686
+ className: cn(
1687
+ "ds:inline-flex ds:h-[42px] ds:items-center ds:gap-1.5 ds:rounded-[11px] ds:px-4 ds:text-sm ds:font-medium",
1688
+ "ds:border-rule-strong ds:bg-surface ds:text-fg-2 ds:border",
1689
+ "ds:transition-colors ds:duration-[var(--duration-fast)] ds:ease-[var(--ease-out-quart)] ds:motion-reduce:transition-none",
1690
+ "ds:hover:bg-surface-hover",
1691
+ "ds:disabled:border-rule ds:disabled:text-fg-disabled ds:disabled:cursor-default ds:disabled:bg-transparent",
1692
+ "ds:focus-visible:[box-shadow:var(--shadow-focus-ring)] ds:focus-visible:outline-none"
1693
+ ),
1694
+ children: [
1695
+ /* @__PURE__ */ jsx(ChevronLeftIcon, { className: "ds:size-4", "aria-hidden": "true" }),
1696
+ "Previous"
1697
+ ]
1698
+ }
1699
+ ),
1700
+ /* @__PURE__ */ jsx("div", { className: "ds:flex ds:items-center ds:gap-1.5", children: steps.map((s, i) => /* @__PURE__ */ jsx(
1701
+ "button",
1702
+ {
1703
+ type: "button",
1704
+ onClick: () => goTo(i),
1705
+ "aria-label": `Go to ${s.label}`,
1706
+ "aria-current": i === current ? "step" : void 0,
1707
+ className: cn(
1708
+ "ds:bg-rule-strong ds:h-2 ds:rounded-full",
1709
+ "ds:transition-[width,background-color] ds:duration-[var(--duration-normal)] ds:ease-[var(--ease-out-quart)] ds:motion-reduce:transition-none",
1710
+ "ds:focus-visible:[box-shadow:var(--shadow-focus-ring)] ds:focus-visible:outline-none",
1711
+ i === current ? "ds:w-[22px] ds:bg-[var(--av-accent)]" : "ds:w-2"
1712
+ )
1713
+ },
1714
+ s.id
1715
+ )) }),
1716
+ /* @__PURE__ */ jsxs(
1717
+ "button",
1718
+ {
1719
+ type: "button",
1720
+ onClick: () => goTo(current + 1),
1721
+ disabled: nextDisabled,
1722
+ "aria-describedby": nextDisabled && nextDisabledReason != null ? reasonId : void 0,
1723
+ style: current === lastIndex ? { visibility: "hidden" } : void 0,
1724
+ className: cn(
1725
+ "ds:inline-flex ds:h-[42px] ds:items-center ds:gap-2 ds:rounded-[11px] ds:px-5 ds:text-sm ds:font-semibold",
1726
+ "ds:bg-[var(--av-accent)] ds:text-[var(--av-accent-contrast)]",
1727
+ "ds:transition-[filter] ds:duration-[var(--duration-fast)] ds:ease-[var(--ease-out-quart)] ds:motion-reduce:transition-none",
1728
+ "ds:hover:brightness-105",
1729
+ "ds:focus-visible:[box-shadow:var(--shadow-focus-ring)] ds:focus-visible:outline-none",
1730
+ "ds:disabled:border-rule ds:disabled:bg-bg-disabled ds:disabled:text-fg-disabled ds:disabled:cursor-not-allowed ds:disabled:border ds:disabled:hover:brightness-100"
1731
+ ),
1732
+ children: [
1733
+ "Next",
1734
+ /* @__PURE__ */ jsx(ChevronRightIcon, { className: "ds:size-4", "aria-hidden": "true" })
1735
+ ]
1736
+ }
1737
+ )
1738
+ ] }),
1739
+ footer && /* @__PURE__ */ jsx("div", { className: "ds:mt-4", children: footer }),
1740
+ nextDisabledReason != null && /* @__PURE__ */ jsx(
1741
+ "p",
1742
+ {
1743
+ id: reasonId,
1744
+ role: "status",
1745
+ "aria-live": "polite",
1746
+ "aria-atomic": "true",
1747
+ className: "ds:text-fg-3 ds:mt-1.5 ds:min-h-5 ds:text-right ds:text-sm",
1748
+ children: nextDisabled ? nextDisabledReason : null
1749
+ }
1750
+ )
1751
+ ] })
1752
+ ]
1753
+ }
1754
+ );
1755
+ }
1756
+ );
1757
+ AgreementViewer.displayName = "AgreementViewer";
1758
+ var AgreementPaneHeading = forwardRef(
1759
+ function AgreementPaneHeading2({ overline, title, subtitle, className, ...props }, ref) {
1760
+ return /* @__PURE__ */ jsxs("div", { ref, className: cn("ds:mb-6", className), ...props, children: [
1761
+ overline && /* @__PURE__ */ jsx("div", { className: "ds:mb-1.5 ds:text-xs ds:font-semibold ds:tracking-wide ds:text-[var(--av-accent-soft)]", children: overline }),
1762
+ /* @__PURE__ */ jsx("h2", { className: "ds:font-display ds:text-fg ds:text-[27px] ds:leading-tight ds:font-bold ds:tracking-tight", children: title }),
1763
+ subtitle && /* @__PURE__ */ jsx("p", { className: "ds:text-fg-3 ds:mt-2 ds:text-sm ds:leading-relaxed", children: subtitle })
1764
+ ] });
1765
+ }
1766
+ );
1767
+ AgreementPaneHeading.displayName = "AgreementPaneHeading";
1768
+ var ProposalServiceRow = forwardRef(
1769
+ function ProposalServiceRow2({ name, description, price, originalPrice, marker = "check", className, ...props }, ref) {
1770
+ return /* @__PURE__ */ jsxs("div", { ref, className: cn("ds:flex ds:items-start ds:gap-2.5 ds:py-1.5", className), ...props, children: [
1771
+ marker === "check" && /* @__PURE__ */ jsx(
1772
+ CheckIcon,
1773
+ {
1774
+ className: "ds:mt-0.5 ds:size-3.5 ds:shrink-0 ds:text-[var(--av-accent,var(--color-accent))]",
1775
+ "aria-hidden": "true"
1776
+ }
1777
+ ),
1778
+ /* @__PURE__ */ jsxs("div", { className: "ds:min-w-0 ds:flex-1", children: [
1779
+ /* @__PURE__ */ jsx("div", { className: "ds:text-fg-2 ds:text-[12.5px] ds:leading-snug", children: name }),
1780
+ description && /* @__PURE__ */ jsx("div", { className: "ds:text-fg-4 ds:mt-0.5 ds:text-[11.5px] ds:leading-snug", children: description })
1781
+ ] }),
1782
+ (price != null || originalPrice != null) && /* @__PURE__ */ jsxs("div", { className: "ds:flex ds:shrink-0 ds:items-baseline ds:gap-1.5 ds:text-xs", children: [
1783
+ originalPrice != null && /* @__PURE__ */ jsx("span", { className: "ds:text-fg-4 ds:line-through", children: originalPrice }),
1784
+ price != null && /* @__PURE__ */ jsx("span", { className: "ds:text-fg-3 ds:tabular", children: price })
1785
+ ] })
1786
+ ] });
1787
+ }
1788
+ );
1789
+ ProposalServiceRow.displayName = "ProposalServiceRow";
1790
+ var CONTROL_LABEL = {
1791
+ choice: ["Selected", "Select package"],
1792
+ addon: ["Added", "Add to proposal"],
1793
+ included: ["Included", "Included"]
1794
+ };
1795
+ var ProposalPackageCard = forwardRef(
1796
+ function ProposalPackageCard2({
1797
+ name,
1798
+ summary,
1799
+ price,
1800
+ priceCaption,
1801
+ originalPrice,
1802
+ savings,
1803
+ mode = "choice",
1804
+ selected = false,
1805
+ badge,
1806
+ servicesLabel = "Included services",
1807
+ children,
1808
+ servicesMaxHeight,
1809
+ onSelect,
1810
+ disabled = false,
1811
+ className,
1812
+ ...props
1813
+ }, ref) {
1814
+ const interactive = mode !== "included" && !!onSelect;
1815
+ const [onLabel, offLabel] = CONTROL_LABEL[mode];
1816
+ const servicesLabelId = useId();
1817
+ return /* @__PURE__ */ jsxs(
1818
+ "div",
1819
+ {
1820
+ ref,
1821
+ "data-selected": selected || void 0,
1822
+ className: cn(
1823
+ "ds:border-rule ds:bg-surface ds:relative ds:flex ds:flex-col ds:rounded-[14px] ds:border ds:p-4",
1824
+ "ds:data-[selected]:border-[var(--av-accent,var(--color-accent))] ds:data-[selected]:shadow-[0_0_0_1px_var(--av-accent,var(--color-accent))]",
1825
+ className
1826
+ ),
1827
+ ...props,
1828
+ children: [
1829
+ (badge || selected) && /* @__PURE__ */ jsxs("span", { className: "ds:rounded-pill ds:absolute ds:-top-2.5 ds:left-4 ds:flex ds:items-center ds:gap-1 ds:bg-[var(--av-accent,var(--color-accent))] ds:px-2 ds:py-1 ds:text-[10px] ds:font-bold ds:tracking-wide ds:text-[var(--av-accent-contrast,var(--color-fg-on-accent))]", children: [
1830
+ selected && /* @__PURE__ */ jsx(CheckIcon, { className: "ds:size-3", "aria-hidden": "true" }),
1831
+ badge ?? (selected ? onLabel : null)
1832
+ ] }),
1833
+ /* @__PURE__ */ jsx("div", { className: "ds:text-fg ds:text-[15px] ds:font-semibold", children: name }),
1834
+ summary && /* @__PURE__ */ jsx("div", { className: "ds:text-fg-4 ds:mt-0.5 ds:text-xs", children: summary }),
1835
+ price != null && /* @__PURE__ */ jsxs("div", { className: "ds:mt-2.5", children: [
1836
+ /* @__PURE__ */ jsxs("div", { className: "ds:flex ds:items-baseline ds:gap-2", children: [
1837
+ originalPrice != null && /* @__PURE__ */ jsx("span", { className: "ds:text-fg-4 ds:text-base ds:line-through", children: originalPrice }),
1838
+ /* @__PURE__ */ jsx("span", { className: "ds:text-fg ds:text-[23px] ds:font-bold ds:tracking-tight ds:tabular", children: price })
1839
+ ] }),
1840
+ priceCaption && /* @__PURE__ */ jsx("div", { className: "ds:text-fg-4 ds:text-[11.5px]", children: priceCaption }),
1841
+ savings && /* @__PURE__ */ jsx("div", { className: "ds:text-success-fg ds:mt-1 ds:text-[11.5px] ds:font-semibold", children: savings })
1842
+ ] }),
1843
+ children && /* @__PURE__ */ jsxs(Fragment, { children: [
1844
+ /* @__PURE__ */ jsx(
1845
+ "div",
1846
+ {
1847
+ id: servicesLabelId,
1848
+ className: "ds:text-fg-3 ds:mt-4 ds:mb-1 ds:text-[11.5px] ds:font-semibold ds:tracking-wide",
1849
+ children: servicesLabel
1850
+ }
1851
+ ),
1852
+ /* @__PURE__ */ jsx(
1853
+ "div",
1854
+ {
1855
+ ...servicesMaxHeight ? { role: "region", "aria-labelledby": servicesLabelId, tabIndex: 0 } : {},
1856
+ className: cn(
1857
+ servicesMaxHeight && [
1858
+ "ds:min-h-0 ds:overflow-y-auto",
1859
+ "ds:focus-visible:[box-shadow:var(--shadow-focus-ring)] ds:focus-visible:outline-none",
1860
+ // pr-3 keeps the rail off the service text; -mr-1 gives that
1861
+ // padding back to the card so the rail still sits near its
1862
+ // edge rather than floating in from it.
1863
+ "ds:-mr-1 ds:pr-3",
1864
+ // A 2px hairline. `scrollbar-thin` is 8px, and on
1865
+ // Chrome-for-Windows an unstyled bar also carries stepper
1866
+ // arrows, which is most of what made it read as heavy.
1867
+ "ds:[scrollbar-width:thin]",
1868
+ "ds:[&::-webkit-scrollbar]:w-[2px]",
1869
+ "ds:[&::-webkit-scrollbar-button]:hidden",
1870
+ "ds:[&::-webkit-scrollbar-track]:bg-transparent",
1871
+ "ds:[&::-webkit-scrollbar-thumb]:rounded-full",
1872
+ "ds:[&::-webkit-scrollbar-thumb]:bg-rule-strong"
1873
+ ]
1874
+ ),
1875
+ style: servicesMaxHeight ? { maxHeight: servicesMaxHeight } : void 0,
1876
+ children
1877
+ }
1878
+ )
1879
+ ] }),
1880
+ /* @__PURE__ */ jsx("div", { className: "ds:mt-auto ds:pt-4", children: interactive ? /* @__PURE__ */ jsx(
1881
+ "button",
1882
+ {
1883
+ type: "button",
1884
+ role: mode === "addon" ? "checkbox" : "radio",
1885
+ "aria-checked": selected,
1886
+ disabled,
1887
+ onClick: onSelect,
1888
+ className: cn(
1889
+ "ds:rounded-input ds:flex ds:h-10 ds:w-full ds:items-center ds:justify-center ds:text-[13.5px] ds:font-semibold",
1890
+ "ds:transition-colors ds:duration-[var(--duration-fast)] ds:ease-[var(--ease-out-quart)] ds:motion-reduce:transition-none",
1891
+ "ds:focus-visible:[box-shadow:var(--shadow-focus-ring)] ds:focus-visible:outline-none",
1892
+ selected ? "ds:bg-[var(--av-accent,var(--color-accent))] ds:text-[var(--av-accent-contrast,var(--color-fg-on-accent))]" : "ds:border-rule-strong ds:text-fg ds:hover:bg-surface-hover ds:border",
1893
+ "ds:disabled:cursor-not-allowed ds:disabled:opacity-60"
1894
+ ),
1895
+ children: selected ? onLabel : offLabel
1896
+ }
1897
+ ) : /* @__PURE__ */ jsxs(
1898
+ "div",
1899
+ {
1900
+ className: cn(
1901
+ "ds:rounded-input ds:flex ds:h-10 ds:w-full ds:items-center ds:justify-center ds:gap-1.5 ds:text-[13.5px] ds:font-semibold",
1902
+ mode === "included" ? "ds:bg-[var(--av-accent-tint,var(--color-accent-tint))] ds:text-[var(--av-accent-soft,var(--color-accent-2))]" : "ds:border-rule ds:text-fg-3 ds:border"
1903
+ ),
1904
+ children: [
1905
+ mode === "included" && /* @__PURE__ */ jsx(CheckIcon, { className: "ds:size-3.5", "aria-hidden": "true" }),
1906
+ selected ? onLabel : offLabel
1907
+ ]
1908
+ }
1909
+ ) })
1910
+ ]
1911
+ }
1912
+ );
1913
+ }
1914
+ );
1915
+ ProposalPackageCard.displayName = "ProposalPackageCard";
1916
+ var BILLING_ICON = {
1917
+ now: CreditCardIcon,
1918
+ auto: RotateCcwIcon,
1919
+ review: EyeIcon,
1920
+ manual: ReceiptIcon,
1921
+ onetime: CheckIcon
1922
+ };
1923
+ var ProposalBillingTerms = forwardRef(
1924
+ function ProposalBillingTerms2({ title = "How billing works", rows, locked = true, className, ...props }, ref) {
1925
+ return /* @__PURE__ */ jsxs(
1926
+ "div",
1927
+ {
1928
+ ref,
1929
+ className: cn("ds:border-rule ds:overflow-hidden ds:rounded-[14px] ds:border", className),
1930
+ ...props,
1931
+ children: [
1932
+ title && /* @__PURE__ */ jsx("div", { className: "ds:border-rule ds:bg-surface-2 ds:text-fg ds:border-b ds:px-5 ds:py-3 ds:text-[13px] ds:font-semibold", children: title }),
1933
+ /* @__PURE__ */ jsx("div", { className: "ds:divide-rule-soft ds:divide-y", children: rows.map((r, i) => {
1934
+ const Icon = BILLING_ICON[r.mode ?? "now"];
1935
+ return /* @__PURE__ */ jsxs("div", { className: "ds:flex ds:items-start ds:gap-3.5 ds:px-5 ds:py-3.5", children: [
1936
+ /* @__PURE__ */ jsx(
1937
+ "span",
1938
+ {
1939
+ "aria-hidden": "true",
1940
+ className: "ds:rounded-icon ds:mt-0.5 ds:flex ds:size-9 ds:shrink-0 ds:items-center ds:justify-center ds:bg-[var(--av-accent-tint,var(--color-accent-tint))] ds:text-[var(--av-accent,var(--color-accent))]",
1941
+ children: /* @__PURE__ */ jsx(Icon, { className: "ds:size-4.5" })
1942
+ }
1943
+ ),
1944
+ /* @__PURE__ */ jsxs("div", { className: "ds:min-w-0 ds:flex-1", children: [
1945
+ /* @__PURE__ */ jsxs("div", { className: "ds:flex ds:items-baseline ds:justify-between ds:gap-3", children: [
1946
+ /* @__PURE__ */ jsx("span", { className: "ds:text-fg ds:text-sm ds:font-semibold", children: r.label }),
1947
+ r.amount != null && /* @__PURE__ */ jsxs("span", { className: "ds:text-fg ds:shrink-0 ds:text-sm ds:font-semibold ds:tabular", children: [
1948
+ r.amount,
1949
+ r.cadence && /* @__PURE__ */ jsx("small", { className: "ds:text-fg-4 ds:ml-0.5 ds:text-xs ds:font-medium", children: r.cadence })
1950
+ ] })
1951
+ ] }),
1952
+ /* @__PURE__ */ jsx("div", { className: "ds:text-fg-3 ds:mt-0.5 ds:text-[13px] ds:leading-snug", children: r.detail })
1953
+ ] })
1954
+ ] }, i);
1955
+ }) }),
1956
+ locked && /* @__PURE__ */ jsxs("div", { className: "ds:border-rule ds:bg-surface-2 ds:text-fg-4 ds:flex ds:items-center ds:gap-2 ds:border-t ds:px-5 ds:py-2.5 ds:text-[12px]", children: [
1957
+ /* @__PURE__ */ jsx(LockIcon, { className: "ds:size-3.5 ds:shrink-0", "aria-hidden": "true" }),
1958
+ "Set by your firm \u2014 you can review these terms, but not change them."
1959
+ ] })
1960
+ ]
1961
+ }
1962
+ );
1963
+ }
1964
+ );
1965
+ ProposalBillingTerms.displayName = "ProposalBillingTerms";
1966
+ var ProposalAddOn = forwardRef(
1967
+ function ProposalAddOn2({ name, description, price, cadence, selected = false, onToggle, disabled, className, ...props }, ref) {
1968
+ return /* @__PURE__ */ jsxs(
1969
+ "button",
1970
+ {
1971
+ ref,
1972
+ type: "button",
1973
+ role: "checkbox",
1974
+ "aria-checked": selected,
1975
+ disabled,
1976
+ onClick: onToggle,
1977
+ "data-selected": selected || void 0,
1978
+ className: cn(
1979
+ "ds:group/addon ds:flex ds:w-full ds:items-center ds:gap-3.5 ds:rounded-[12px] ds:border ds:p-4 ds:text-left",
1980
+ "ds:border-rule ds:bg-surface",
1981
+ "ds:transition-colors ds:duration-[var(--duration-fast)] ds:ease-[var(--ease-out-quart)] ds:motion-reduce:transition-none",
1982
+ "ds:hover:bg-surface-hover",
1983
+ "ds:data-[selected]:border-[var(--av-accent,var(--color-accent))] ds:data-[selected]:bg-[var(--av-accent-tint,var(--color-accent-tint))]",
1984
+ "ds:focus-visible:[box-shadow:var(--shadow-focus-ring)] ds:focus-visible:outline-none",
1985
+ "ds:disabled:cursor-not-allowed ds:disabled:opacity-60",
1986
+ className
1987
+ ),
1988
+ ...props,
1989
+ children: [
1990
+ /* @__PURE__ */ jsx(
1991
+ "span",
1992
+ {
1993
+ "aria-hidden": "true",
1994
+ className: cn(
1995
+ "ds:flex ds:size-5 ds:shrink-0 ds:items-center ds:justify-center ds:rounded-md ds:border-[1.5px] ds:text-transparent",
1996
+ "ds:border-rule-strong",
1997
+ "ds:group-data-[selected]/addon:border-[var(--av-accent,var(--color-accent))] ds:group-data-[selected]/addon:bg-[var(--av-accent,var(--color-accent))] ds:group-data-[selected]/addon:text-[var(--av-accent-contrast,var(--color-fg-on-accent))]"
1998
+ ),
1999
+ children: /* @__PURE__ */ jsx(CheckIcon, { className: "ds:size-3.5" })
2000
+ }
2001
+ ),
2002
+ /* @__PURE__ */ jsxs("div", { className: "ds:min-w-0 ds:flex-1", children: [
2003
+ /* @__PURE__ */ jsx("div", { className: "ds:text-fg ds:text-sm ds:font-semibold", children: name }),
2004
+ description && /* @__PURE__ */ jsx("div", { className: "ds:text-fg-4 ds:group-data-[selected]/addon:text-fg-3 ds:text-xs", children: description })
2005
+ ] }),
2006
+ (price != null || cadence != null) && /* @__PURE__ */ jsxs("div", { className: "ds:shrink-0 ds:text-right", children: [
2007
+ price != null && /* @__PURE__ */ jsx("div", { className: "ds:text-fg ds:text-[15px] ds:font-bold ds:tabular", children: price }),
2008
+ cadence != null && /* @__PURE__ */ jsx("div", { className: "ds:text-fg-4 ds:group-data-[selected]/addon:text-fg-3 ds:text-[11.5px]", children: cadence })
2009
+ ] })
2010
+ ]
2011
+ }
2012
+ );
2013
+ }
2014
+ );
2015
+ ProposalAddOn.displayName = "ProposalAddOn";
2016
+ var ProposalPricingSummary = forwardRef(
2017
+ function ProposalPricingSummary2({
2018
+ children,
2019
+ billing,
2020
+ savings,
2021
+ tax,
2022
+ taxLabel = "Tax",
2023
+ originalTotal,
2024
+ total,
2025
+ cadence,
2026
+ totalLabel = "Total due",
2027
+ schedule,
2028
+ className,
2029
+ ...props
2030
+ }, ref) {
2031
+ return /* @__PURE__ */ jsxs("div", { ref, className: cn("ds:@container/summary ds:flex ds:flex-col", className), ...props, children: [
2032
+ children && /* @__PURE__ */ jsx("div", { className: "ds:border-rule ds:grid ds:grid-cols-1 ds:gap-x-6 ds:gap-y-1 ds:rounded-[14px] ds:border ds:p-6 ds:@md/summary:grid-cols-2", children }),
2033
+ billing && /* @__PURE__ */ jsxs("div", { className: "ds:mt-4 ds:rounded-[14px] ds:border ds:border-[var(--av-accent-tint2,var(--color-accent-tint))] ds:bg-[var(--av-accent-tint,var(--color-accent-tint))] ds:p-5", children: [
2034
+ /* @__PURE__ */ jsxs("div", { className: "ds:flex ds:items-center ds:justify-between", children: [
2035
+ /* @__PURE__ */ jsx("b", { className: "ds:text-[13.5px] ds:font-semibold ds:text-[var(--av-accent-soft,var(--color-accent-2))]", children: billing.title ?? "Billing schedule" }),
2036
+ billing.caption && /* @__PURE__ */ jsx("span", { className: "ds:text-[11.5px] ds:text-[var(--av-accent-soft,var(--color-accent-2))]", children: billing.caption })
2037
+ ] }),
2038
+ billing.rows?.map((r, i) => /* @__PURE__ */ jsxs(
2039
+ "div",
2040
+ {
2041
+ className: "ds:text-fg-2 ds:mt-2.5 ds:flex ds:items-center ds:justify-between ds:gap-3 ds:text-[13.5px]",
2042
+ children: [
2043
+ /* @__PURE__ */ jsx("span", { children: r.label }),
2044
+ /* @__PURE__ */ jsx("b", { className: "ds:font-semibold ds:tabular", children: r.value })
2045
+ ]
2046
+ },
2047
+ i
2048
+ ))
2049
+ ] }),
2050
+ (savings || tax != null) && /* @__PURE__ */ jsxs("div", { className: "ds:mt-4 ds:space-y-2", children: [
2051
+ savings && /* @__PURE__ */ jsxs("div", { className: "ds:text-success-fg ds:flex ds:items-center ds:justify-between ds:text-[13.5px] ds:font-medium", children: [
2052
+ /* @__PURE__ */ jsx("span", { children: "Discount" }),
2053
+ /* @__PURE__ */ jsx("span", { className: "ds:tabular", children: savings })
2054
+ ] }),
2055
+ tax != null && /* @__PURE__ */ jsxs("div", { className: "ds:text-fg-3 ds:flex ds:items-center ds:justify-between ds:text-[13.5px]", children: [
2056
+ /* @__PURE__ */ jsx("span", { children: taxLabel }),
2057
+ /* @__PURE__ */ jsx("span", { className: "ds:tabular", children: tax })
2058
+ ] })
2059
+ ] }),
2060
+ schedule ? /* @__PURE__ */ jsxs("div", { className: "ds:border-rule ds:mt-4 ds:border-t ds:pt-4", children: [
2061
+ /* @__PURE__ */ jsxs("div", { className: "ds:flex ds:items-baseline ds:justify-between ds:gap-3", children: [
2062
+ /* @__PURE__ */ jsxs("div", { children: [
2063
+ /* @__PURE__ */ jsx("div", { className: "ds:text-fg ds:text-[15px] ds:font-semibold", children: schedule.dueTodayLabel ?? "Due today" }),
2064
+ schedule.dueTodayCaption && /* @__PURE__ */ jsx("div", { className: "ds:text-fg-4 ds:text-xs", children: schedule.dueTodayCaption })
2065
+ ] }),
2066
+ /* @__PURE__ */ jsx("span", { className: "ds:text-fg ds:text-[26px] ds:font-bold ds:tabular", children: schedule.dueToday })
2067
+ ] }),
2068
+ schedule.then && schedule.then.length > 0 && /* @__PURE__ */ jsx("div", { className: "ds:border-rule-soft ds:mt-3 ds:space-y-1.5 ds:border-t ds:pt-3", children: schedule.then.map((t, i) => /* @__PURE__ */ jsxs(
2069
+ "div",
2070
+ {
2071
+ className: "ds:text-fg-3 ds:flex ds:items-baseline ds:justify-between ds:gap-3 ds:text-[13.5px]",
2072
+ children: [
2073
+ /* @__PURE__ */ jsx("span", { children: t.label ?? "Then" }),
2074
+ /* @__PURE__ */ jsxs("span", { className: "ds:tabular", children: [
2075
+ /* @__PURE__ */ jsx("b", { className: "ds:text-fg-2 ds:font-semibold", children: t.amount }),
2076
+ t.cadence && /* @__PURE__ */ jsx("small", { className: "ds:text-fg-4 ds:ml-1 ds:text-[12px] ds:font-medium", children: t.cadence })
2077
+ ] })
2078
+ ]
2079
+ },
2080
+ i
2081
+ )) })
2082
+ ] }) : total != null && /* @__PURE__ */ jsxs("div", { className: "ds:border-rule ds:mt-4 ds:flex ds:items-center ds:justify-between ds:border-t ds:pt-4", children: [
2083
+ /* @__PURE__ */ jsx("span", { className: "ds:text-fg ds:text-[15px] ds:font-semibold", children: totalLabel }),
2084
+ /* @__PURE__ */ jsxs("span", { className: "ds:flex ds:items-baseline ds:gap-2", children: [
2085
+ originalTotal != null && /* @__PURE__ */ jsx("span", { className: "ds:text-fg-4 ds:text-base ds:line-through", children: originalTotal }),
2086
+ /* @__PURE__ */ jsx("span", { className: "ds:text-fg ds:text-[22px] ds:font-bold ds:tabular", children: total }),
2087
+ cadence && /* @__PURE__ */ jsx("small", { className: "ds:text-fg-4 ds:text-[13px] ds:font-medium", children: cadence })
2088
+ ] })
2089
+ ] })
2090
+ ] });
2091
+ }
2092
+ );
2093
+ ProposalPricingSummary.displayName = "ProposalPricingSummary";
2094
+ var KIND_META = {
2095
+ video: { label: "Video", icon: PlayIcon },
2096
+ pdf: { label: "Document", icon: FileTextIcon },
2097
+ text: { label: "Read", icon: FileTextIcon }
2098
+ };
2099
+ var ProposalCustomPage = forwardRef(
2100
+ function ProposalCustomPage2({ kind, title, caption, label, poster, onPlay, children, className, ...props }, ref) {
2101
+ const meta = KIND_META[kind];
2102
+ const Icon = meta.icon;
2103
+ return /* @__PURE__ */ jsxs("div", { ref, className: cn("ds:flex ds:flex-col", className), ...props, children: [
2104
+ /* @__PURE__ */ jsxs("div", { className: "ds:mb-1.5 ds:flex ds:items-center ds:gap-1.5 ds:text-xs ds:font-semibold ds:tracking-wide ds:text-[var(--av-accent-soft,var(--color-accent-2))]", children: [
2105
+ /* @__PURE__ */ jsx(Icon, { className: "ds:size-3.5", "aria-hidden": "true" }),
2106
+ label ?? meta.label
2107
+ ] }),
2108
+ /* @__PURE__ */ jsx("h2", { className: "ds:font-display ds:text-fg ds:text-[27px] ds:leading-tight ds:font-bold ds:tracking-tight", children: title }),
2109
+ caption && /* @__PURE__ */ jsx("p", { className: "ds:text-fg-3 ds:mt-2 ds:text-sm ds:leading-relaxed", children: caption }),
2110
+ /* @__PURE__ */ jsx("div", { className: "ds:mt-5", children: kind === "video" && !children ? /* @__PURE__ */ jsx(PlayablePoster, { poster, onPlay, title }) : children })
2111
+ ] });
2112
+ }
2113
+ );
2114
+ ProposalCustomPage.displayName = "ProposalCustomPage";
2115
+ function PlayablePoster({
2116
+ poster,
2117
+ onPlay,
2118
+ title
2119
+ }) {
2120
+ const inner = /* @__PURE__ */ jsxs(Fragment, { children: [
2121
+ /* @__PURE__ */ jsx(
2122
+ "span",
2123
+ {
2124
+ "aria-hidden": "true",
2125
+ className: "ds:bg-bg-3 ds:absolute ds:inset-0 ds:bg-cover ds:bg-center",
2126
+ style: poster ? { backgroundImage: `url(${poster})` } : void 0
2127
+ }
2128
+ ),
2129
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "ds:absolute ds:inset-0 ds:bg-black/15" }),
2130
+ /* @__PURE__ */ jsx(
2131
+ "span",
2132
+ {
2133
+ "aria-hidden": "true",
2134
+ className: "ds:rounded-full ds:relative ds:flex ds:size-16 ds:items-center ds:justify-center ds:bg-white/90 ds:text-[var(--av-accent,var(--color-accent))] ds:shadow-raised",
2135
+ children: /* @__PURE__ */ jsx(PlayIcon, { className: "ds:size-7" })
2136
+ }
2137
+ )
2138
+ ] });
2139
+ const cls = "ds:relative ds:flex ds:aspect-video ds:w-full ds:items-center ds:justify-center ds:overflow-hidden ds:rounded-[14px] ds:border-rule ds:border";
2140
+ return onPlay ? /* @__PURE__ */ jsx(
2141
+ "button",
2142
+ {
2143
+ type: "button",
2144
+ onClick: onPlay,
2145
+ "aria-label": typeof title === "string" ? `Play ${title}` : "Play video",
2146
+ className: cn(
2147
+ cls,
2148
+ "ds:transition-[filter] ds:duration-[var(--duration-fast)] ds:ease-[var(--ease-out-quart)] ds:motion-reduce:transition-none ds:hover:brightness-105",
2149
+ "ds:focus-visible:[box-shadow:var(--shadow-focus-ring)] ds:focus-visible:outline-none"
2150
+ ),
2151
+ children: inner
2152
+ }
2153
+ ) : /* @__PURE__ */ jsx("div", { className: cls, children: inner });
2154
+ }
2155
+ var ProposalNote = forwardRef(
2156
+ function ProposalNote2({ title, children, tone = "accent", icon, className, ...props }, ref) {
2157
+ return /* @__PURE__ */ jsxs(
2158
+ "div",
2159
+ {
2160
+ ref,
2161
+ className: cn(
2162
+ "ds:flex ds:gap-3 ds:rounded-[12px] ds:border ds:p-4 ds:text-[13.5px] ds:leading-relaxed",
2163
+ tone === "accent" ? "ds:border-[var(--av-accent-tint2,var(--color-accent-tint))] ds:bg-[var(--av-accent-tint,var(--color-accent-tint))] ds:text-[var(--av-accent-soft,var(--color-accent-2))]" : "ds:border-rule ds:bg-bg-2 ds:text-fg-2",
2164
+ className
2165
+ ),
2166
+ ...props,
2167
+ children: [
2168
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "ds:mt-0.5 ds:shrink-0", children: icon ?? /* @__PURE__ */ jsx(InfoIcon, { className: "ds:size-4" }) }),
2169
+ /* @__PURE__ */ jsxs("div", { className: "ds:min-w-0", children: [
2170
+ title && /* @__PURE__ */ jsx("div", { className: "ds:text-fg ds:font-semibold", children: title }),
2171
+ /* @__PURE__ */ jsx("div", { className: cn(title && "ds:mt-0.5"), children })
2172
+ ] })
2173
+ ]
2174
+ }
2175
+ );
2176
+ }
2177
+ );
2178
+ ProposalNote.displayName = "ProposalNote";
2179
+ var STATUS_META = {
2180
+ signed: {
2181
+ label: "Signed",
2182
+ icon: CheckIcon,
2183
+ className: "ds:text-success-fg ds:bg-success-bg ds:border-success-line"
2184
+ },
2185
+ viewed: {
2186
+ label: "Viewed",
2187
+ icon: EyeIcon,
2188
+ className: "ds:text-[var(--av-accent-soft,var(--color-accent-2))] ds:bg-[var(--av-accent-tint,var(--color-accent-tint))] ds:border-[var(--av-accent-tint2,var(--color-accent-tint))]"
2189
+ },
2190
+ pending: { label: "Pending", icon: ClockIcon, className: "ds:text-fg-3 ds:bg-bg-2 ds:border-rule" }
2191
+ };
2192
+ var ProposalSignerList = forwardRef(
2193
+ function ProposalSignerList2({ signers, title = "Recipients", className, ...props }, ref) {
2194
+ return /* @__PURE__ */ jsxs("div", { ref, className: cn("ds:flex ds:flex-col", className), ...props, children: [
2195
+ title && /* @__PURE__ */ jsx("div", { className: "ds:text-fg-3 ds:mb-2 ds:text-[11.5px] ds:font-semibold ds:tracking-wide", children: title }),
2196
+ /* @__PURE__ */ jsx("div", { className: "ds:border-rule ds:divide-rule ds:divide-y ds:overflow-hidden ds:rounded-[12px] ds:border", children: signers.map((s, i) => {
2197
+ const status = s.status ? STATUS_META[s.status] : null;
2198
+ const StatusIcon = status?.icon;
2199
+ const initials = s.name.split(" ").map((w) => w[0]).slice(0, 2).join("").toUpperCase();
2200
+ return /* @__PURE__ */ jsxs("div", { className: "ds:flex ds:items-center ds:gap-3 ds:px-4 ds:py-3", children: [
2201
+ /* @__PURE__ */ jsx(
2202
+ "span",
2203
+ {
2204
+ "aria-hidden": "true",
2205
+ className: "ds:flex ds:size-9 ds:shrink-0 ds:items-center ds:justify-center ds:rounded-full ds:bg-[var(--av-accent-tint,var(--color-accent-tint))] ds:text-[12.5px] ds:font-semibold ds:text-[var(--av-accent-soft,var(--color-accent-2))]",
2206
+ children: initials
2207
+ }
2208
+ ),
2209
+ /* @__PURE__ */ jsxs("div", { className: "ds:min-w-0 ds:flex-1", children: [
2210
+ /* @__PURE__ */ jsxs("div", { className: "ds:text-fg ds:truncate ds:text-sm ds:font-medium", children: [
2211
+ s.name,
2212
+ s.role && /* @__PURE__ */ jsx("span", { className: "ds:text-fg-4 ds:ml-2 ds:text-xs ds:font-normal", children: s.role })
2213
+ ] }),
2214
+ s.email && /* @__PURE__ */ jsx("div", { className: "ds:text-fg-4 ds:truncate ds:text-xs", children: s.email })
2215
+ ] }),
2216
+ status && StatusIcon && /* @__PURE__ */ jsxs("div", { className: "ds:flex ds:shrink-0 ds:flex-col ds:items-end ds:gap-1", children: [
2217
+ /* @__PURE__ */ jsxs(
2218
+ "span",
2219
+ {
2220
+ className: cn(
2221
+ "ds:inline-flex ds:items-center ds:gap-1 ds:rounded-full ds:border ds:px-2 ds:py-0.5 ds:text-[11px] ds:font-medium",
2222
+ status.className
2223
+ ),
2224
+ children: [
2225
+ /* @__PURE__ */ jsx(StatusIcon, { className: "ds:size-3", "aria-hidden": "true" }),
2226
+ status.label
2227
+ ]
2228
+ }
2229
+ ),
2230
+ s.at != null && /* @__PURE__ */ jsx("span", { className: "ds:text-fg-4 ds:text-[11px]", children: s.at })
2231
+ ] })
2232
+ ] }, i);
2233
+ }) })
2234
+ ] });
2235
+ }
2236
+ );
2237
+ ProposalSignerList.displayName = "ProposalSignerList";
2238
+ function deriveInitials(name) {
2239
+ return name.trim().split(/\s+/).filter(Boolean).map((w) => w[0]).slice(0, 2).join("").toUpperCase();
2240
+ }
2241
+ var ProposalSignatureBlock = forwardRef(
2242
+ function ProposalSignatureBlock2({
2243
+ signed = false,
2244
+ name = "",
2245
+ initials,
2246
+ defaultName = "",
2247
+ onChange,
2248
+ placeholder = "Type your full name",
2249
+ signatureFont = "Georgia, serif",
2250
+ footer,
2251
+ hideModeTabs = false,
2252
+ className,
2253
+ ...props
2254
+ }, ref) {
2255
+ const [nameVal, setNameVal] = useState(defaultName);
2256
+ const [initialsVal, setInitialsVal] = useState("");
2257
+ const [initialsTouched, setInitialsTouched] = useState(false);
2258
+ const displayName = signed ? name : nameVal;
2259
+ const displayInitials = signed ? initials ?? deriveInitials(name) : initialsTouched ? initialsVal : deriveInitials(nameVal);
2260
+ const emitChange = (n, i) => onChange?.({ name: n, initials: i });
2261
+ const handleName = (v) => {
2262
+ setNameVal(v);
2263
+ emitChange(v, initialsTouched ? initialsVal : deriveInitials(v));
2264
+ };
2265
+ const handleInitials = (v) => {
2266
+ setInitialsTouched(true);
2267
+ setInitialsVal(v);
2268
+ emitChange(nameVal, v);
2269
+ };
2270
+ return /* @__PURE__ */ jsxs(
2271
+ "div",
2272
+ {
2273
+ ref,
2274
+ className: cn("ds:@container/signature ds:flex ds:flex-col", className),
2275
+ ...props,
2276
+ children: [
2277
+ !hideModeTabs && /* @__PURE__ */ jsxs("div", { className: "ds:border-rule ds:mb-4 ds:flex ds:gap-6 ds:border-b", children: [
2278
+ /* @__PURE__ */ jsx("span", { className: "ds:border-[var(--av-accent,var(--color-accent))] ds:text-fg ds:-mb-px ds:border-b-2 ds:pb-2.5 ds:text-sm ds:font-medium", children: "Type" }),
2279
+ /* @__PURE__ */ jsx("span", { className: "ds:text-fg-4 ds:pb-2.5 ds:text-sm ds:font-medium", children: "Draw" })
2280
+ ] }),
2281
+ /* @__PURE__ */ jsxs("div", { className: "ds:flex ds:flex-col ds:gap-4 ds:@2xl/signature:flex-row", children: [
2282
+ /* @__PURE__ */ jsx("div", { className: "ds:border-rule ds:bg-surface-2 ds:flex ds:h-[84px] ds:flex-none ds:items-center ds:overflow-hidden ds:rounded-[12px] ds:border ds:px-4 ds:@2xl/signature:h-[118px] ds:@2xl/signature:flex-1 ds:@2xl/signature:px-7", children: /* @__PURE__ */ jsx(
2283
+ "span",
2284
+ {
2285
+ className: cn("ds:text-3xl ds:leading-none ds:font-semibold ds:@2xl/signature:text-[46px]", displayName ? "ds:text-fg" : "ds:text-fg-4"),
2286
+ style: { fontFamily: signatureFont },
2287
+ children: displayName || placeholder
2288
+ }
2289
+ ) }),
2290
+ /* @__PURE__ */ jsx("div", { className: "ds:border-rule ds:bg-surface-2 ds:flex ds:h-[84px] ds:w-full ds:shrink-0 ds:items-center ds:justify-center ds:rounded-[12px] ds:border ds:@2xl/signature:h-[118px] ds:@2xl/signature:w-[168px]", children: /* @__PURE__ */ jsx(
2291
+ "span",
2292
+ {
2293
+ className: cn("ds:text-2xl ds:leading-none ds:@2xl/signature:text-[34px]", displayInitials ? "ds:text-fg-3" : "ds:text-fg-4"),
2294
+ style: { fontFamily: signatureFont },
2295
+ children: displayInitials || "\u2014"
2296
+ }
2297
+ ) })
2298
+ ] }),
2299
+ /* @__PURE__ */ jsxs(
2300
+ "div",
2301
+ {
2302
+ className: "ds:mt-5 ds:grid ds:grid-cols-1 ds:gap-3.5 ds:@2xl/signature:grid-cols-[1fr_120px]",
2303
+ children: [
2304
+ /* @__PURE__ */ jsxs("label", { className: "ds:flex ds:flex-col ds:gap-1.5", children: [
2305
+ /* @__PURE__ */ jsx("span", { className: "ds:text-fg-3 ds:text-xs ds:font-medium", children: "Your legal name" }),
2306
+ /* @__PURE__ */ jsx(
2307
+ "input",
2308
+ {
2309
+ value: displayName,
2310
+ readOnly: signed,
2311
+ onChange: (e) => handleName(e.target.value),
2312
+ placeholder: signed ? void 0 : placeholder,
2313
+ "aria-label": "Your legal name",
2314
+ className: "ds:border-rule-strong ds:rounded-input ds:text-fg-2 ds:bg-surface ds:h-10 ds:border ds:px-3 ds:text-sm ds:read-only:bg-[var(--color-bg-2)]"
2315
+ }
2316
+ )
2317
+ ] }),
2318
+ /* @__PURE__ */ jsxs("label", { className: "ds:flex ds:flex-col ds:gap-1.5", children: [
2319
+ /* @__PURE__ */ jsx("span", { className: "ds:text-fg-3 ds:text-xs ds:font-medium", children: "Initials" }),
2320
+ /* @__PURE__ */ jsx(
2321
+ "input",
2322
+ {
2323
+ value: displayInitials,
2324
+ readOnly: signed,
2325
+ onChange: (e) => handleInitials(e.target.value),
2326
+ placeholder: signed ? void 0 : "\u2014",
2327
+ "aria-label": "Initials",
2328
+ className: "ds:border-rule-strong ds:rounded-input ds:text-fg-2 ds:bg-surface ds:h-10 ds:border ds:px-3 ds:text-sm ds:read-only:bg-[var(--color-bg-2)]"
2329
+ }
2330
+ )
2331
+ ] })
2332
+ ]
2333
+ }
2334
+ ),
2335
+ footer && /* @__PURE__ */ jsx("div", { className: "ds:mt-6", children: footer })
2336
+ ]
2337
+ }
2338
+ );
2339
+ }
2340
+ );
2341
+ ProposalSignatureBlock.displayName = "ProposalSignatureBlock";
2342
+ var ProposalConsentGate = forwardRef(
2343
+ function ProposalConsentGate2({ children, checked = false, onCheckedChange, signed = false, signedNote, onSign, signLabel = "Sign & approve", disabled = false, className, ...props }, ref) {
2344
+ return /* @__PURE__ */ jsxs("div", { ref, className: cn("ds:flex ds:flex-col ds:gap-4", className), ...props, children: [
2345
+ !signed && /* @__PURE__ */ jsxs("label", { className: "ds:flex ds:cursor-pointer ds:items-start ds:gap-2.5 ds:text-[13.5px] ds:leading-relaxed", children: [
2346
+ /* @__PURE__ */ jsx(
2347
+ "input",
2348
+ {
2349
+ type: "checkbox",
2350
+ checked,
2351
+ onChange: (e) => onCheckedChange?.(e.target.checked),
2352
+ className: "ds:mt-0.5 ds:size-4 ds:shrink-0 ds:rounded ds:accent-[var(--av-accent,var(--color-accent))]"
2353
+ }
2354
+ ),
2355
+ /* @__PURE__ */ jsx("span", { className: "ds:text-fg-2", children })
2356
+ ] }),
2357
+ /* @__PURE__ */ jsxs("div", { className: "ds:flex ds:items-center ds:justify-between ds:gap-4", children: [
2358
+ signed ? /* @__PURE__ */ jsxs("span", { className: "ds:text-success-fg ds:flex ds:items-center ds:gap-2 ds:text-[13px] ds:font-medium", children: [
2359
+ /* @__PURE__ */ jsx(CheckIcon, { className: "ds:size-4 ds:shrink-0", "aria-hidden": "true" }),
2360
+ signedNote ?? "This agreement has been signed."
2361
+ ] }) : /* @__PURE__ */ jsxs("span", { className: "ds:text-fg-4 ds:flex ds:items-center ds:gap-1.5 ds:text-[12.5px]", children: [
2362
+ /* @__PURE__ */ jsx(LockIcon, { className: "ds:size-3.5", "aria-hidden": "true" }),
2363
+ " Secure e-signature"
2364
+ ] }),
2365
+ onSign && /* @__PURE__ */ jsxs(
2366
+ "button",
2367
+ {
2368
+ type: "button",
2369
+ onClick: onSign,
2370
+ disabled: signed || !checked || disabled,
2371
+ className: cn(
2372
+ "ds:inline-flex ds:h-[46px] ds:items-center ds:gap-2 ds:rounded-[12px] ds:px-5 ds:text-[14.5px] ds:font-semibold",
2373
+ "ds:transition-[filter] ds:duration-[var(--duration-fast)] ds:ease-[var(--ease-out-quart)] ds:motion-reduce:transition-none",
2374
+ "ds:focus-visible:[box-shadow:var(--shadow-focus-ring)] ds:focus-visible:outline-none",
2375
+ "ds:bg-[var(--av-accent,var(--color-accent))] ds:text-[var(--av-accent-contrast,var(--color-fg-on-accent))] ds:hover:brightness-105",
2376
+ "ds:disabled:bg-bg-disabled ds:disabled:text-fg-disabled ds:disabled:cursor-not-allowed ds:disabled:brightness-100"
2377
+ ),
2378
+ children: [
2379
+ /* @__PURE__ */ jsx(PenSignIcon, { className: "ds:size-4", "aria-hidden": "true" }),
2380
+ signLabel
2381
+ ]
2382
+ }
2383
+ )
2384
+ ] })
2385
+ ] });
2386
+ }
2387
+ );
2388
+ ProposalConsentGate.displayName = "ProposalConsentGate";
2389
+ var ProposalPaymentCapture = forwardRef(
2390
+ function ProposalPaymentCapture2({ title = "Payment at signing", amount, caption, method = "card", capturedLast4, children, className, ...props }, ref) {
2391
+ return /* @__PURE__ */ jsxs(
2392
+ "div",
2393
+ {
2394
+ ref,
2395
+ className: cn("ds:border-rule ds:rounded-[14px] ds:border ds:p-5", className),
2396
+ ...props,
2397
+ children: [
2398
+ /* @__PURE__ */ jsxs("div", { className: "ds:flex ds:items-center ds:gap-3", children: [
2399
+ /* @__PURE__ */ jsx(
2400
+ "span",
2401
+ {
2402
+ "aria-hidden": "true",
2403
+ className: "ds:rounded-card ds:flex ds:size-10 ds:shrink-0 ds:items-center ds:justify-center ds:bg-[var(--av-accent-tint,var(--color-accent-tint))] ds:text-[var(--av-accent,var(--color-accent))]",
2404
+ children: /* @__PURE__ */ jsx(CreditCardIcon, { className: "ds:size-5" })
2405
+ }
2406
+ ),
2407
+ /* @__PURE__ */ jsxs("div", { className: "ds:flex-1", children: [
2408
+ /* @__PURE__ */ jsx("div", { className: "ds:text-fg ds:text-sm ds:font-semibold", children: title }),
2409
+ caption && /* @__PURE__ */ jsx("div", { className: "ds:text-fg-4 ds:text-xs", children: caption })
2410
+ ] }),
2411
+ amount != null && /* @__PURE__ */ jsx("div", { className: "ds:text-fg ds:text-lg ds:font-bold ds:tabular", children: amount })
2412
+ ] }),
2413
+ /* @__PURE__ */ jsx("div", { className: "ds:mt-4", children: children ?? (capturedLast4 ? /* @__PURE__ */ jsxs("div", { className: "ds:border-rule ds:flex ds:items-center ds:gap-2.5 ds:rounded-[10px] ds:border ds:px-3.5 ds:py-3", children: [
2414
+ /* @__PURE__ */ jsx(CreditCardIcon, { className: "ds:text-fg-4 ds:size-4", "aria-hidden": "true" }),
2415
+ /* @__PURE__ */ jsxs("span", { className: "ds:text-fg-2 ds:text-sm ds:font-medium ds:tabular", children: [
2416
+ method === "bank" ? "Bank account" : "Card",
2417
+ " \u2022\u2022\u2022\u2022 ",
2418
+ capturedLast4
2419
+ ] }),
2420
+ /* @__PURE__ */ jsx(CheckIcon, { className: "ds:text-success-fg ds:ml-auto ds:size-4", "aria-hidden": "true" })
2421
+ ] }) : /* @__PURE__ */ jsx("div", { className: "ds:border-rule ds:text-fg-4 ds:flex ds:h-11 ds:items-center ds:rounded-[10px] ds:border ds:border-dashed ds:px-3.5 ds:text-sm", children: method === "bank" ? "Bank account details" : "Card number" })) })
2422
+ ]
2423
+ }
2424
+ );
2425
+ }
2426
+ );
2427
+ ProposalPaymentCapture.displayName = "ProposalPaymentCapture";
2428
+ var Grid = forwardRef(function Grid2({
2429
+ columns,
2430
+ rows,
2431
+ value,
2432
+ onChange,
2433
+ ariaLabel,
2434
+ rowHeaderLabel,
2435
+ currencySymbol = "$",
2436
+ minWidth = 560,
2437
+ disabled = false,
2438
+ className,
2439
+ ...props
2440
+ }, ref) {
2441
+ const updateCell = (rowKey, colKey, nextValue) => {
2442
+ onChange({
2443
+ ...value,
2444
+ [rowKey]: { ...value[rowKey] ?? {}, [colKey]: nextValue }
2445
+ });
2446
+ };
2447
+ return /* @__PURE__ */ jsx("div", { ref, className: cn("ds:overflow-x-auto", className), ...props, children: /* @__PURE__ */ jsxs(
2448
+ "div",
2449
+ {
2450
+ role: "group",
2451
+ "aria-label": ariaLabel,
2452
+ className: "ds:grid ds:gap-2",
2453
+ style: {
2454
+ minWidth: `${minWidth}px`,
2455
+ gridTemplateColumns: `minmax(120px,max-content) ${columns.map((column) => `minmax(0, ${column.width ?? 1}fr)`).join(" ")}`
2456
+ },
2457
+ children: [
2458
+ rowHeaderLabel ? /* @__PURE__ */ jsx("span", { className: "ds:text-fg-3 ds:flex ds:items-end ds:px-1 ds:text-[12px] ds:font-semibold", children: rowHeaderLabel }) : /* @__PURE__ */ jsx("span", { "aria-hidden": "true" }),
2459
+ columns.map((column) => /* @__PURE__ */ jsx("span", { className: "ds:text-fg-3 ds:flex ds:items-end ds:px-1 ds:text-[12px] ds:font-semibold", children: column.label }, column.key)),
2460
+ rows.map((row) => /* @__PURE__ */ jsxs(Fragment$1, { children: [
2461
+ /* @__PURE__ */ jsx("span", { className: "ds:text-fg ds:flex ds:items-center ds:text-[13px] ds:font-semibold", children: row.label }),
2462
+ columns.map((column) => /* @__PURE__ */ jsx(
2463
+ Input,
2464
+ {
2465
+ type: column.inputType === "date" ? "date" : "text",
2466
+ value: value[row.key]?.[column.key] ?? "",
2467
+ onChange: (event) => updateCell(row.key, column.key, event.target.value),
2468
+ placeholder: column.placeholder,
2469
+ "aria-label": [ariaLabel, row.label, column.label].filter(Boolean).join(" "),
2470
+ disabled,
2471
+ className: "ds:h-11 ds:rounded-[12px] ds:text-[14px]",
2472
+ inputMode: column.inputType === "number" || column.inputType === "currency" ? "decimal" : void 0,
2473
+ prefixIcon: column.inputType === "currency" ? /* @__PURE__ */ jsx("span", { className: "ds:text-xs ds:font-semibold", children: currencySymbol }) : void 0
2474
+ },
2475
+ column.key
2476
+ ))
2477
+ ] }, row.key))
2478
+ ]
2479
+ }
2480
+ ) });
2481
+ });
2482
+ Grid.displayName = "Grid";
2483
+ var QUESTION_TYPE_CONTRACT_VERSION = 1;
2484
+ var QUESTION_TYPES = [
2485
+ "short-text",
2486
+ "long-text",
2487
+ "email",
2488
+ "phone",
2489
+ "ssn-sin",
2490
+ "date",
2491
+ "number",
2492
+ "currency",
2493
+ "percentage",
2494
+ "single-choice",
2495
+ "multi-choice",
2496
+ "yes-no",
2497
+ "dropdown",
2498
+ "multi-select",
2499
+ "address",
2500
+ "file-upload",
2501
+ "table",
2502
+ "repeater",
2503
+ "signature",
2504
+ "section-header",
2505
+ "consent-checkbox",
2506
+ "name",
2507
+ "labeled-table",
2508
+ "number-stepper"
2509
+ ];
2510
+ var defaultOptions = [
2511
+ { value: "yes", label: "Yes" },
2512
+ { value: "no", label: "No" },
2513
+ { value: "not-sure", label: "Not sure" }
2514
+ ];
2515
+ var Questions = forwardRef(function Questions2({
2516
+ index,
2517
+ title,
2518
+ description,
2519
+ type = "short-text",
2520
+ required = false,
2521
+ chrome = "card",
2522
+ sectionLabel,
2523
+ hideHeader = false,
2524
+ options = defaultOptions,
2525
+ value = "",
2526
+ values = [],
2527
+ placeholder,
2528
+ help,
2529
+ addressValue = {},
2530
+ nameValue = {},
2531
+ showSuffix = true,
2532
+ tableColumns = [],
2533
+ tableRows = [],
2534
+ labeledColumns = [],
2535
+ labeledRows = [],
2536
+ labeledValue = {},
2537
+ files = [],
2538
+ accept,
2539
+ maxSize,
2540
+ multiple,
2541
+ currencySymbol = "$",
2542
+ min = 0,
2543
+ max,
2544
+ step = 1,
2545
+ countLabel,
2546
+ itemNoun,
2547
+ onValueChange,
2548
+ onValuesChange,
2549
+ onAddressChange,
2550
+ onNameChange,
2551
+ onLabeledChange,
2552
+ onTableRowsChange,
2553
+ onFilesSelected,
2554
+ onFileRemove,
2555
+ className,
2556
+ ...props
2557
+ }, ref) {
2558
+ const humanIndex = typeof index === "number" ? index + 1 : void 0;
2559
+ const isSectionHeader = type === "section-header";
2560
+ const isPlain = chrome === "plain" || isSectionHeader;
2561
+ const showHeader = isSectionHeader || !hideHeader;
2562
+ const toggleOption = (optionValue, checked) => {
2563
+ const nextValues = checked ? Array.from(/* @__PURE__ */ new Set([...values, optionValue])) : values.filter((item) => item !== optionValue);
2564
+ onValuesChange?.(nextValues);
2565
+ };
2566
+ const updateAddress = (key, nextValue) => {
2567
+ onAddressChange?.({ ...addressValue, [key]: nextValue });
2568
+ };
2569
+ const updateName = (key, nextValue) => {
2570
+ onNameChange?.({ ...nameValue, [key]: nextValue });
2571
+ };
2572
+ const updateRow = (rowIndex, key, nextValue) => {
2573
+ onTableRowsChange?.(
2574
+ tableRows.map((row, index2) => index2 === rowIndex ? { ...row, [key]: nextValue } : row)
2575
+ );
2576
+ };
2577
+ const emptyRow = () => tableColumns.reduce((row, column) => ({ ...row, [column.key]: "" }), {});
2578
+ const addRow = () => {
2579
+ onTableRowsChange?.([...tableRows, emptyRow()]);
2580
+ };
2581
+ const removeRow = (rowIndex) => {
2582
+ onTableRowsChange?.(tableRows.filter((_, index2) => index2 !== rowIndex));
2583
+ };
2584
+ const setRowCount = (nextCount) => {
2585
+ const clamped = Math.max(min, max != null ? Math.min(nextCount, max) : nextCount);
2586
+ if (clamped > tableRows.length) {
2587
+ const added = Array.from({ length: clamped - tableRows.length }, emptyRow);
2588
+ onTableRowsChange?.([...tableRows, ...added]);
2589
+ } else if (clamped < tableRows.length) {
2590
+ onTableRowsChange?.(tableRows.slice(0, clamped));
2591
+ }
2592
+ };
2593
+ return /* @__PURE__ */ jsxs(
2594
+ "section",
2595
+ {
2596
+ ref,
2597
+ className: cn(
2598
+ "ds:font-body",
2599
+ isPlain ? "ds:bg-transparent" : "ds:border-rule ds:bg-surface ds:shadow-card ds:rounded-[18px] ds:border ds:p-5",
2600
+ className
2601
+ ),
2602
+ ...props,
2603
+ children: [
2604
+ showHeader && /* @__PURE__ */ jsxs("div", { className: cn("ds:flex ds:items-start ds:gap-3", !isSectionHeader && "ds:mb-4"), children: [
2605
+ humanIndex && !isPlain && /* @__PURE__ */ jsx(
2606
+ "span",
2607
+ {
2608
+ "aria-hidden": "true",
2609
+ className: "ds:bg-brand-bg ds:text-brand ds:grid ds:size-7 ds:shrink-0 ds:place-items-center ds:rounded-full ds:text-xs ds:font-bold",
2610
+ children: humanIndex
2611
+ }
2612
+ ),
2613
+ /* @__PURE__ */ jsxs("div", { className: "ds:min-w-0 ds:flex-1", children: [
2614
+ (sectionLabel || isSectionHeader) && /* @__PURE__ */ jsx("p", { className: "ds:text-brand ds:mb-1 ds:text-[11px] ds:font-bold ds:tracking-[0.12em] ds:uppercase", children: sectionLabel }),
2615
+ /* @__PURE__ */ jsxs("div", { className: "ds:flex ds:flex-wrap ds:items-center ds:gap-2", children: [
2616
+ /* @__PURE__ */ jsx(
2617
+ "h3",
2618
+ {
2619
+ className: cn(
2620
+ "ds:text-fg",
2621
+ isSectionHeader ? "ds:text-[22px] ds:leading-7 ds:font-bold" : "ds:text-[14px] ds:leading-5 ds:font-bold"
2622
+ ),
2623
+ children: title
2624
+ }
2625
+ ),
2626
+ help && /* @__PURE__ */ jsx(HelpTip, { title: help.title ?? title, body: help.body }),
2627
+ required && /* @__PURE__ */ jsx("span", { className: "ds:bg-brand-bg ds:text-brand ds:rounded-full ds:px-2 ds:py-0.5 ds:text-[11px] ds:font-bold", children: "Required" })
2628
+ ] }),
2629
+ description && type !== "consent-checkbox" && /* @__PURE__ */ jsx("p", { className: "ds:text-fg-3 ds:mt-1 ds:text-[13px] ds:leading-5", children: description })
2630
+ ] })
2631
+ ] }),
2632
+ type === "section-header" && null,
2633
+ type === "short-text" && /* @__PURE__ */ jsx(
2634
+ Input,
2635
+ {
2636
+ value,
2637
+ onChange: (event) => onValueChange?.(event.target.value),
2638
+ placeholder: placeholder ?? "Type your answer",
2639
+ "aria-label": title,
2640
+ className: "ds:h-11 ds:rounded-[12px] ds:text-[14px]"
2641
+ }
2642
+ ),
2643
+ type === "email" && /* @__PURE__ */ jsx(
2644
+ Input,
2645
+ {
2646
+ type: "email",
2647
+ value,
2648
+ onChange: (event) => onValueChange?.(event.target.value),
2649
+ placeholder: placeholder ?? "client@example.com",
2650
+ "aria-label": title,
2651
+ className: "ds:h-11 ds:rounded-[12px] ds:text-[14px]"
2652
+ }
2653
+ ),
2654
+ type === "phone" && /* @__PURE__ */ jsx(
2655
+ Input,
2656
+ {
2657
+ type: "tel",
2658
+ value,
2659
+ onChange: (event) => onValueChange?.(event.target.value),
2660
+ placeholder: placeholder ?? "(555) 123-4567",
2661
+ "aria-label": title,
2662
+ className: "ds:h-11 ds:rounded-[12px] ds:text-[14px]"
2663
+ }
2664
+ ),
2665
+ type === "ssn-sin" && /* @__PURE__ */ jsx(
2666
+ Input,
2667
+ {
2668
+ value,
2669
+ onChange: (event) => onValueChange?.(event.target.value),
2670
+ placeholder: placeholder ?? "Enter SSN or SIN",
2671
+ "aria-label": title,
2672
+ inputMode: "numeric",
2673
+ className: "ds:h-11 ds:rounded-[12px] ds:text-[14px]"
2674
+ }
2675
+ ),
2676
+ type === "date" && /* @__PURE__ */ jsx(
2677
+ Input,
2678
+ {
2679
+ type: "date",
2680
+ value,
2681
+ onChange: (event) => onValueChange?.(event.target.value),
2682
+ "aria-label": title,
2683
+ className: "ds:h-11 ds:rounded-[12px] ds:text-[14px]"
2684
+ }
2685
+ ),
2686
+ type === "number" && /* @__PURE__ */ jsx(
2687
+ Input,
2688
+ {
2689
+ type: "number",
2690
+ value,
2691
+ onChange: (event) => onValueChange?.(event.target.value),
2692
+ placeholder: placeholder ?? "0",
2693
+ "aria-label": title,
2694
+ className: "ds:h-11 ds:rounded-[12px] ds:text-[14px]"
2695
+ }
2696
+ ),
2697
+ type === "number-stepper" && /* @__PURE__ */ jsx(
2698
+ NumberStepper,
2699
+ {
2700
+ value: Number(value) || 0,
2701
+ onValueChange: (next) => onValueChange?.(String(next)),
2702
+ min,
2703
+ max,
2704
+ step,
2705
+ ariaLabel: title
2706
+ }
2707
+ ),
2708
+ type === "currency" && /* @__PURE__ */ jsx(
2709
+ Input,
2710
+ {
2711
+ value,
2712
+ onChange: (event) => onValueChange?.(event.target.value),
2713
+ placeholder: placeholder ?? "0.00",
2714
+ "aria-label": title,
2715
+ inputMode: "decimal",
2716
+ prefixIcon: /* @__PURE__ */ jsx("span", { className: "ds:text-xs ds:font-semibold", children: currencySymbol }),
2717
+ className: "ds:h-11 ds:rounded-[12px] ds:text-[14px]"
2718
+ }
2719
+ ),
2720
+ type === "percentage" && /* @__PURE__ */ jsx(
2721
+ Input,
2722
+ {
2723
+ value,
2724
+ onChange: (event) => onValueChange?.(event.target.value),
2725
+ placeholder: placeholder ?? "0",
2726
+ "aria-label": title,
2727
+ inputMode: "decimal",
2728
+ suffixIcon: /* @__PURE__ */ jsx("span", { className: "ds:text-xs ds:font-semibold", children: "%" }),
2729
+ className: "ds:h-11 ds:rounded-[12px] ds:text-[14px]"
2730
+ }
2731
+ ),
2732
+ type === "long-text" && /* @__PURE__ */ jsx(
2733
+ Textarea,
2734
+ {
2735
+ value,
2736
+ onChange: (event) => onValueChange?.(event.target.value),
2737
+ placeholder: placeholder ?? "Write a detailed answer",
2738
+ "aria-label": title,
2739
+ autoResize: true,
2740
+ className: "ds:rounded-[12px] ds:text-[14px]"
2741
+ }
2742
+ ),
2743
+ (type === "single-choice" || type === "yes-no") && /* @__PURE__ */ jsx(
2744
+ "div",
2745
+ {
2746
+ className: cn(
2747
+ "ds:grid ds:gap-3",
2748
+ type === "yes-no" ? "ds:grid-cols-[repeat(auto-fit,minmax(78px,max-content))]" : ""
2749
+ ),
2750
+ role: "radiogroup",
2751
+ "aria-label": title,
2752
+ children: (type === "yes-no" ? [
2753
+ { value: "yes", label: "Yes" },
2754
+ { value: "no", label: "No" }
2755
+ ] : options).map((option) => /* @__PURE__ */ jsx(
2756
+ QuestionOptionButton,
2757
+ {
2758
+ option,
2759
+ selected: value === option.value,
2760
+ compact: type === "yes-no",
2761
+ role: "radio",
2762
+ "aria-checked": value === option.value,
2763
+ onClick: () => onValueChange?.(option.value)
2764
+ },
2765
+ option.value
2766
+ ))
2767
+ }
2768
+ ),
2769
+ type === "dropdown" && /* @__PURE__ */ jsx(
2770
+ Select,
2771
+ {
2772
+ options,
2773
+ value,
2774
+ onValueChange,
2775
+ placeholder: placeholder ?? "Select an option",
2776
+ "aria-label": title
2777
+ }
2778
+ ),
2779
+ (type === "multi-choice" || type === "multi-select") && /* @__PURE__ */ jsx("div", { className: "ds:grid ds:gap-3", role: "group", "aria-label": title, children: options.map((option) => /* @__PURE__ */ jsx(
2780
+ QuestionOptionButton,
2781
+ {
2782
+ option,
2783
+ selected: values.includes(option.value),
2784
+ role: "checkbox",
2785
+ "aria-checked": values.includes(option.value),
2786
+ onClick: () => toggleOption(option.value, !values.includes(option.value))
2787
+ },
2788
+ option.value
2789
+ )) }),
2790
+ type === "address" && /* @__PURE__ */ jsxs("div", { className: "ds:grid ds:gap-3 ds:sm:grid-cols-2", children: [
2791
+ /* @__PURE__ */ jsx(
2792
+ Input,
2793
+ {
2794
+ value: addressValue.line1 ?? "",
2795
+ onChange: (event) => updateAddress("line1", event.target.value),
2796
+ placeholder: "Street address",
2797
+ "aria-label": `${title} street address`,
2798
+ className: "ds:h-11 ds:rounded-[12px] ds:text-[14px] ds:sm:col-span-2"
2799
+ }
2800
+ ),
2801
+ /* @__PURE__ */ jsx(
2802
+ Input,
2803
+ {
2804
+ value: addressValue.line2 ?? "",
2805
+ onChange: (event) => updateAddress("line2", event.target.value),
2806
+ placeholder: "Apt, suite, unit",
2807
+ "aria-label": `${title} address line 2`,
2808
+ className: "ds:h-11 ds:rounded-[12px] ds:text-[14px] ds:sm:col-span-2"
2809
+ }
2810
+ ),
2811
+ /* @__PURE__ */ jsx(
2812
+ Input,
2813
+ {
2814
+ value: addressValue.city ?? "",
2815
+ onChange: (event) => updateAddress("city", event.target.value),
2816
+ placeholder: "City",
2817
+ "aria-label": `${title} city`,
2818
+ className: "ds:h-11 ds:rounded-[12px] ds:text-[14px]"
2819
+ }
2820
+ ),
2821
+ /* @__PURE__ */ jsx(
2822
+ Input,
2823
+ {
2824
+ value: addressValue.region ?? "",
2825
+ onChange: (event) => updateAddress("region", event.target.value),
2826
+ placeholder: "State / Province",
2827
+ "aria-label": `${title} state or province`,
2828
+ className: "ds:h-11 ds:rounded-[12px] ds:text-[14px]"
2829
+ }
2830
+ ),
2831
+ /* @__PURE__ */ jsx(
2832
+ Input,
2833
+ {
2834
+ value: addressValue.postalCode ?? "",
2835
+ onChange: (event) => updateAddress("postalCode", event.target.value),
2836
+ placeholder: "ZIP / Postal code",
2837
+ "aria-label": `${title} zip or postal code`,
2838
+ className: "ds:h-11 ds:rounded-[12px] ds:text-[14px]"
2839
+ }
2840
+ ),
2841
+ /* @__PURE__ */ jsx(
2842
+ Input,
2843
+ {
2844
+ value: addressValue.country ?? "",
2845
+ onChange: (event) => updateAddress("country", event.target.value),
2846
+ placeholder: "Country",
2847
+ "aria-label": `${title} country`,
2848
+ className: "ds:h-11 ds:rounded-[12px] ds:text-[14px]"
2849
+ }
2850
+ )
2851
+ ] }),
2852
+ type === "name" && /* @__PURE__ */ jsxs("div", { className: "ds:grid ds:gap-3 ds:sm:grid-cols-6", children: [
2853
+ /* @__PURE__ */ jsx(
2854
+ Input,
2855
+ {
2856
+ value: nameValue.first ?? "",
2857
+ onChange: (event) => updateName("first", event.target.value),
2858
+ placeholder: "First name",
2859
+ "aria-label": `${title} first name`,
2860
+ className: "ds:h-11 ds:rounded-[12px] ds:text-[14px] ds:sm:col-span-2"
2861
+ }
2862
+ ),
2863
+ /* @__PURE__ */ jsx(
2864
+ Input,
2865
+ {
2866
+ value: nameValue.middle ?? "",
2867
+ onChange: (event) => updateName("middle", event.target.value),
2868
+ placeholder: "Middle",
2869
+ "aria-label": `${title} middle name`,
2870
+ className: "ds:h-11 ds:rounded-[12px] ds:text-[14px] ds:sm:col-span-1"
2871
+ }
2872
+ ),
2873
+ /* @__PURE__ */ jsx(
2874
+ Input,
2875
+ {
2876
+ value: nameValue.last ?? "",
2877
+ onChange: (event) => updateName("last", event.target.value),
2878
+ placeholder: "Last name",
2879
+ "aria-label": `${title} last name`,
2880
+ className: cn(
2881
+ "ds:h-11 ds:rounded-[12px] ds:text-[14px]",
2882
+ showSuffix ? "ds:sm:col-span-2" : "ds:sm:col-span-3"
2883
+ )
2884
+ }
2885
+ ),
2886
+ showSuffix && /* @__PURE__ */ jsx(
2887
+ Input,
2888
+ {
2889
+ value: nameValue.suffix ?? "",
2890
+ onChange: (event) => updateName("suffix", event.target.value),
2891
+ placeholder: "Suffix",
2892
+ "aria-label": `${title} suffix`,
2893
+ className: "ds:h-11 ds:rounded-[12px] ds:text-[14px] ds:sm:col-span-1"
2894
+ }
2895
+ )
2896
+ ] }),
2897
+ type === "labeled-table" && /* @__PURE__ */ jsx(
2898
+ Grid,
2899
+ {
2900
+ ariaLabel: title,
2901
+ currencySymbol,
2902
+ columns: labeledColumns.map((column) => ({
2903
+ key: column.key,
2904
+ label: column.title,
2905
+ inputType: column.inputType,
2906
+ width: column.width
2907
+ })),
2908
+ rows: labeledRows.map((row) => ({ key: row.key, label: row.title })),
2909
+ value: labeledValue,
2910
+ onChange: (next) => onLabeledChange?.(next)
2911
+ }
2912
+ ),
2913
+ type === "file-upload" && /* @__PURE__ */ jsxs("div", { className: "ds:grid ds:gap-3", children: [
2914
+ /* @__PURE__ */ jsx(
2915
+ FileUpload,
2916
+ {
2917
+ accept,
2918
+ maxSize,
2919
+ multiple,
2920
+ onFilesSelected
2921
+ }
2922
+ ),
2923
+ files.length > 0 && /* @__PURE__ */ jsx("div", { className: "ds:grid ds:gap-2", children: files.map((file, fileIndex) => /* @__PURE__ */ jsx(
2924
+ FileChip,
2925
+ {
2926
+ name: file.name,
2927
+ meta: file.size ? formatBytes(file.size) : void 0,
2928
+ kind: file.kind ?? "doc",
2929
+ action: onFileRemove ? /* @__PURE__ */ jsx(
2930
+ Button,
2931
+ {
2932
+ type: "button",
2933
+ variant: "ghost",
2934
+ size: "icon-sm",
2935
+ onClick: () => onFileRemove(file, fileIndex),
2936
+ "aria-label": `Remove ${file.name}`,
2937
+ className: "ds:hover:text-danger-fg",
2938
+ children: /* @__PURE__ */ jsx(TrashIcon, { size: 14, "aria-hidden": "true" })
2939
+ }
2940
+ ) : void 0
2941
+ },
2942
+ `${file.name}-${file.size ?? "unknown"}`
2943
+ )) })
2944
+ ] }),
2945
+ (type === "table" || type === "repeater") && /* @__PURE__ */ jsxs("div", { className: "ds:grid ds:gap-3", children: [
2946
+ countLabel && /* @__PURE__ */ jsxs("div", { className: "ds:flex ds:flex-wrap ds:items-center ds:justify-between ds:gap-3", children: [
2947
+ /* @__PURE__ */ jsx("span", { className: "ds:text-fg ds:text-[13px] ds:font-semibold", children: countLabel }),
2948
+ /* @__PURE__ */ jsx(
2949
+ NumberStepper,
2950
+ {
2951
+ value: tableRows.length,
2952
+ onValueChange: setRowCount,
2953
+ min,
2954
+ max,
2955
+ step,
2956
+ ariaLabel: countLabel
2957
+ }
2958
+ )
2959
+ ] }),
2960
+ tableRows.map((row, rowIndex) => /* @__PURE__ */ jsxs("div", { className: "ds:border-rule ds:bg-surface-2 ds:rounded-[16px] ds:border ds:p-4", children: [
2961
+ /* @__PURE__ */ jsxs("div", { className: "ds:mb-3 ds:flex ds:items-center ds:justify-between ds:gap-3", children: [
2962
+ /* @__PURE__ */ jsxs("span", { className: "ds:text-fg ds:text-[13px] ds:font-semibold", children: [
2963
+ type === "repeater" ? itemNoun ?? "Item" : "Row",
2964
+ " ",
2965
+ rowIndex + 1
2966
+ ] }),
2967
+ !countLabel && tableRows.length > 1 && /* @__PURE__ */ jsx(
2968
+ Button,
2969
+ {
2970
+ type: "button",
2971
+ variant: "ghost",
2972
+ size: "icon-sm",
2973
+ onClick: () => removeRow(rowIndex),
2974
+ "aria-label": `Remove row ${rowIndex + 1}`,
2975
+ children: /* @__PURE__ */ jsx(TrashIcon, { size: 14, "aria-hidden": "true" })
2976
+ }
2977
+ )
2978
+ ] }),
2979
+ /* @__PURE__ */ jsx("div", { className: "ds:grid ds:gap-3 ds:sm:grid-cols-2", children: tableColumns.map((column) => /* @__PURE__ */ jsx(
2980
+ Input,
2981
+ {
2982
+ type: column.inputType === "date" ? "date" : "text",
2983
+ value: row[column.key] ?? "",
2984
+ onChange: (event) => updateRow(rowIndex, column.key, event.target.value),
2985
+ placeholder: column.placeholder ?? column.label,
2986
+ "aria-label": `${title} ${column.label} row ${rowIndex + 1}`,
2987
+ className: "ds:h-11 ds:rounded-[12px] ds:text-[14px]",
2988
+ inputMode: column.inputType === "number" || column.inputType === "currency" ? "decimal" : void 0,
2989
+ prefixIcon: column.inputType === "currency" ? /* @__PURE__ */ jsx("span", { className: "ds:text-xs ds:font-semibold", children: currencySymbol }) : void 0
2990
+ },
2991
+ column.key
2992
+ )) })
2993
+ ] }, rowIndex)),
2994
+ !countLabel && /* @__PURE__ */ jsxs(
2995
+ Button,
2996
+ {
2997
+ type: "button",
2998
+ variant: "dashed",
2999
+ size: "sm",
3000
+ onClick: addRow,
3001
+ iconLeft: /* @__PURE__ */ jsx(PlusIcon, { size: 14 }),
3002
+ children: [
3003
+ "Add ",
3004
+ type === "repeater" ? "item" : "row"
3005
+ ]
3006
+ }
3007
+ )
3008
+ ] }),
3009
+ type === "signature" && /* @__PURE__ */ jsxs("div", { className: "ds:border-rule-strong ds:bg-surface-2 ds:rounded-[16px] ds:border ds:border-dashed ds:p-5", children: [
3010
+ /* @__PURE__ */ jsxs("div", { className: "ds:text-fg-2 ds:mb-3 ds:flex ds:items-center ds:gap-2", children: [
3011
+ /* @__PURE__ */ jsx(PenSignIcon, { size: 18, "aria-hidden": "true" }),
3012
+ /* @__PURE__ */ jsx("span", { className: "ds:text-[13px] ds:font-semibold", children: "Signature" })
3013
+ ] }),
3014
+ /* @__PURE__ */ jsx(
3015
+ Input,
3016
+ {
3017
+ value,
3018
+ onChange: (event) => onValueChange?.(event.target.value),
3019
+ placeholder: placeholder ?? "Type full legal name",
3020
+ "aria-label": title,
3021
+ className: "ds:h-11 ds:rounded-[12px] ds:text-[14px]"
3022
+ }
3023
+ )
3024
+ ] }),
3025
+ type === "consent-checkbox" && /* @__PURE__ */ jsx(
3026
+ Checkbox,
3027
+ {
3028
+ label: description ?? title,
3029
+ checked: value === "true",
3030
+ onCheckedChange: (checked) => onValueChange?.(checked === true ? "true" : "false")
3031
+ }
3032
+ )
3033
+ ]
3034
+ }
3035
+ );
3036
+ });
3037
+ Questions.displayName = "Questions";
3038
+ function QuestionOptionButton({
3039
+ option,
3040
+ selected,
3041
+ compact,
3042
+ className,
3043
+ ...props
3044
+ }) {
3045
+ return /* @__PURE__ */ jsxs(
3046
+ "button",
3047
+ {
3048
+ type: "button",
3049
+ disabled: option.disabled,
3050
+ className: cn(
3051
+ "ds:group ds:bg-surface ds:flex ds:w-full ds:items-center ds:gap-3 ds:border ds:text-left",
3052
+ "ds:transition-[border-color,background-color,color,box-shadow,transform] ds:duration-[var(--duration-fast)] ds:ease-[var(--ease-out-quart)]",
3053
+ "ds:motion-reduce:transition-none",
3054
+ "ds:focus-visible:[box-shadow:var(--shadow-focus-ring)] ds:focus-visible:outline-none",
3055
+ "ds:disabled:bg-bg-disabled ds:disabled:text-fg-disabled ds:disabled:cursor-not-allowed",
3056
+ compact ? "ds:h-10 ds:max-w-max ds:rounded-[10px] ds:px-3" : "ds:min-h-16 ds:rounded-[12px] ds:px-7 ds:py-4",
3057
+ selected ? compact ? "ds:border-brand ds:bg-brand-bg ds:text-brand ds:shadow-xs" : "ds:border-brand-line ds:bg-brand-bg ds:text-brand ds:hover:bg-brand-bg-hover ds:shadow-xs" : "ds:border-rule-strong ds:text-fg ds:hover:border-brand-line ds:hover:bg-brand-bg/40",
3058
+ className
3059
+ ),
3060
+ ...props,
3061
+ children: [
3062
+ /* @__PURE__ */ jsx(
3063
+ "span",
3064
+ {
3065
+ "aria-hidden": "true",
3066
+ className: cn(
3067
+ "ds:grid ds:shrink-0 ds:place-items-center ds:rounded-full ds:border ds:transition-colors ds:duration-[var(--duration-fast)] ds:motion-reduce:transition-none",
3068
+ compact ? "ds:size-5" : "ds:size-4",
3069
+ selected ? "ds:border-brand ds:bg-brand ds:text-fg-on-brand" : "ds:border-rule-strong ds:bg-surface ds:group-hover:border-brand-line ds:text-transparent"
3070
+ ),
3071
+ children: selected && /* @__PURE__ */ jsx(CheckCircleSolidIcon, { size: compact ? 18 : 14 })
3072
+ }
3073
+ ),
3074
+ /* @__PURE__ */ jsxs("span", { className: "ds:flex ds:min-w-0 ds:flex-1 ds:items-center ds:gap-1.5", children: [
3075
+ /* @__PURE__ */ jsx("span", { className: cn("ds:truncate ds:font-bold", compact ? "ds:text-[13px]" : "ds:text-[15px]"), children: option.label }),
3076
+ option.helpText && /* @__PURE__ */ jsx(HelpTip, { title: option.label, body: option.helpText })
3077
+ ] }),
3078
+ option.formLabel && !compact && /* @__PURE__ */ jsx(
3079
+ "span",
3080
+ {
3081
+ className: cn(
3082
+ "ds:ml-auto ds:shrink-0 ds:text-right ds:text-[13px] ds:font-semibold",
3083
+ selected ? "ds:text-brand" : "ds:text-fg-3"
3084
+ ),
3085
+ children: option.formLabel
3086
+ }
3087
+ )
3088
+ ]
3089
+ }
3090
+ );
3091
+ }
3092
+ function formatBytes(bytes) {
3093
+ if (bytes < 1024) return `${bytes} B`;
3094
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
3095
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
3096
+ }
3097
+ function HelpTip({ title, body }) {
3098
+ return /* @__PURE__ */ jsxs(Tooltip, { children: [
3099
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx("span", { className: "ds:text-brand ds:inline-flex ds:shrink-0 ds:cursor-help", children: /* @__PURE__ */ jsx(HelpCircleIcon, { size: 14, "aria-hidden": "true" }) }) }),
3100
+ /* @__PURE__ */ jsxs(
3101
+ TooltipContent,
3102
+ {
3103
+ side: "top",
3104
+ align: "center",
3105
+ sideOffset: 12,
3106
+ className: cn(
3107
+ "ds:border-rule ds:bg-surface ds:shadow-pop ds:relative ds:max-w-[352px] ds:rounded-[7px] ds:p-5 ds:text-left",
3108
+ "ds:after:border-rule ds:after:bg-surface ds:after:absolute ds:after:top-full ds:after:left-1/2 ds:after:size-4 ds:after:-translate-x-1/2 ds:after:-translate-y-1/2 ds:after:rotate-45 ds:after:border-r ds:after:border-b ds:after:content-['']"
3109
+ ),
3110
+ children: [
3111
+ /* @__PURE__ */ jsx("div", { className: "ds:text-fg ds:text-[15px] ds:leading-5 ds:font-bold", children: title }),
3112
+ /* @__PURE__ */ jsx("p", { className: "ds:text-fg-2 ds:mt-3 ds:text-[14px] ds:leading-6", children: body })
3113
+ ]
3114
+ }
3115
+ )
3116
+ ] });
3117
+ }
3118
+ function NumberStepper({
3119
+ value,
3120
+ onValueChange,
3121
+ min = 0,
3122
+ max,
3123
+ step = 1,
3124
+ ariaLabel
3125
+ }) {
3126
+ const clamp = (next) => Math.max(min, max != null ? Math.min(next, max) : next);
3127
+ const current = clamp(Number.isFinite(value) ? value : min);
3128
+ const atMin = current <= min;
3129
+ const atMax = max != null && current >= max;
3130
+ return /* @__PURE__ */ jsxs(
3131
+ "div",
3132
+ {
3133
+ className: "ds:inline-flex ds:items-center ds:gap-2",
3134
+ role: "spinbutton",
3135
+ "aria-valuenow": current,
3136
+ "aria-valuemin": min,
3137
+ "aria-valuemax": max,
3138
+ "aria-label": ariaLabel,
3139
+ children: [
3140
+ /* @__PURE__ */ jsx(
3141
+ Button,
3142
+ {
3143
+ type: "button",
3144
+ variant: "secondary",
3145
+ size: "icon-sm",
3146
+ onClick: () => onValueChange(clamp(current - step)),
3147
+ disabled: atMin,
3148
+ "aria-label": "Decrease",
3149
+ children: /* @__PURE__ */ jsx(MinusIcon, { size: 14, "aria-hidden": "true" })
3150
+ }
3151
+ ),
3152
+ /* @__PURE__ */ jsx(
3153
+ Input,
3154
+ {
3155
+ value: String(current),
3156
+ onChange: (event) => {
3157
+ const parsed = Number(event.target.value.replace(/[^0-9-]/g, ""));
3158
+ onValueChange(clamp(Number.isFinite(parsed) ? parsed : min));
3159
+ },
3160
+ inputMode: "numeric",
3161
+ "aria-label": ariaLabel,
3162
+ className: "ds:h-11 ds:w-14 ds:rounded-[12px] ds:text-center ds:text-[14px] ds:tabular-nums"
3163
+ }
3164
+ ),
3165
+ /* @__PURE__ */ jsx(
3166
+ Button,
3167
+ {
3168
+ type: "button",
3169
+ variant: "secondary",
3170
+ size: "icon-sm",
3171
+ onClick: () => onValueChange(clamp(current + step)),
3172
+ disabled: atMax,
3173
+ "aria-label": "Increase",
3174
+ children: /* @__PURE__ */ jsx(PlusIcon, { size: 14, "aria-hidden": "true" })
3175
+ }
3176
+ )
3177
+ ]
3178
+ }
3179
+ );
3180
+ }
3181
+ var SidebarContext = React6.createContext(null);
3182
+ var NOOP_CONTEXT = {
3183
+ state: "expanded",
3184
+ setState: () => {
3185
+ },
3186
+ toggle: () => {
3187
+ },
3188
+ collapsible: false,
3189
+ peekLockCount: 0,
3190
+ acquirePeekLock: () => () => {
3191
+ }
3192
+ };
3193
+ function useSidebarState() {
3194
+ return React6.useContext(SidebarContext) ?? NOOP_CONTEXT;
3195
+ }
3196
+ var DEFAULT_SHORTCUT = "Mod+\\";
3197
+ var asState = (value) => value === "rail" || value === "expanded" ? value : null;
3198
+ function readStorage(key, storage) {
3199
+ if (!key || typeof document === "undefined") return null;
3200
+ try {
3201
+ if (storage === "cookie") {
3202
+ const match = document.cookie.match(
3203
+ new RegExp(`(?:^|;\\s*)${key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}=([^;]*)`)
3204
+ );
3205
+ return asState(match ? decodeURIComponent(match[1] ?? "") : null);
3206
+ }
3207
+ return asState(window.localStorage.getItem(key));
3208
+ } catch {
3209
+ return null;
3210
+ }
3211
+ }
3212
+ function writeStorage(key, storage, next) {
3213
+ if (typeof document === "undefined") return;
3214
+ try {
3215
+ if (storage === "cookie") {
3216
+ document.cookie = `${key}=${next}; path=/; max-age=31536000; samesite=lax`;
3217
+ return;
3218
+ }
3219
+ window.localStorage.setItem(key, next);
3220
+ } catch {
3221
+ }
3222
+ }
3223
+ function SidebarProvider({
3224
+ children,
3225
+ state: controlled,
3226
+ defaultState = "expanded",
3227
+ onStateChange,
3228
+ storageKey,
3229
+ storage = "localStorage",
3230
+ shortcut = DEFAULT_SHORTCUT
3231
+ }) {
3232
+ const [uncontrolled, setUncontrolled] = React6.useState(
3233
+ controlled ?? defaultState
3234
+ );
3235
+ React6.useEffect(() => {
3236
+ if (controlled !== void 0) return;
3237
+ const stored = readStorage(storageKey, storage);
3238
+ if (stored && stored !== uncontrolled) setUncontrolled(stored);
3239
+ }, []);
3240
+ const state = controlled ?? uncontrolled;
3241
+ const setState = React6.useCallback(
3242
+ (next) => {
3243
+ if (controlled === void 0) setUncontrolled(next);
3244
+ onStateChange?.(next);
3245
+ if (storageKey) writeStorage(storageKey, storage, next);
3246
+ },
3247
+ [controlled, onStateChange, storageKey, storage]
3248
+ );
3249
+ const toggle = React6.useCallback(() => {
3250
+ setState(state === "expanded" ? "rail" : "expanded");
3251
+ }, [state, setState]);
3252
+ const [peekLockCount, setPeekLockCount] = React6.useState(0);
3253
+ const acquirePeekLock = React6.useCallback(() => {
3254
+ setPeekLockCount((n) => n + 1);
3255
+ let released = false;
3256
+ return () => {
3257
+ if (released) return;
3258
+ released = true;
3259
+ setPeekLockCount((n) => Math.max(0, n - 1));
3260
+ };
3261
+ }, []);
3262
+ React6.useEffect(() => {
3263
+ if (!shortcut) return;
3264
+ const parts = shortcut.split("+");
3265
+ const key = parts.pop() ?? "";
3266
+ const wantMod = parts.includes("Mod");
3267
+ const wantShift = parts.includes("Shift");
3268
+ const wantAlt = parts.includes("Alt");
3269
+ function onKey(e) {
3270
+ const isMac = typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform);
3271
+ const mod = isMac ? e.metaKey : e.ctrlKey;
3272
+ if (e.key.toLowerCase() !== key.toLowerCase()) return;
3273
+ if (wantMod !== mod) return;
3274
+ if (wantShift !== e.shiftKey) return;
3275
+ if (wantAlt !== e.altKey) return;
3276
+ e.preventDefault();
3277
+ toggle();
3278
+ }
3279
+ window.addEventListener("keydown", onKey);
3280
+ return () => window.removeEventListener("keydown", onKey);
3281
+ }, [shortcut, toggle]);
3282
+ const value = React6.useMemo(
3283
+ () => ({ state, setState, toggle, collapsible: true, peekLockCount, acquirePeekLock }),
3284
+ [state, setState, toggle, peekLockCount, acquirePeekLock]
3285
+ );
3286
+ return /* @__PURE__ */ jsx(SidebarContext.Provider, { value, children });
3287
+ }
3288
+ SidebarProvider.displayName = "SidebarProvider";
3289
+ var PEEK_ENTER_DELAY_MS = 100;
3290
+ var PEEK_LEAVE_DELAY_MS = 200;
3291
+ var SidebarLabelsHiddenContext = React6.createContext(false);
3292
+ var SidebarPeekEnabledContext = React6.createContext(true);
3293
+ function useCollapsedAttribute() {
3294
+ return React6.useContext(SidebarLabelsHiddenContext) ? { "data-collapsed": "true" } : {};
3295
+ }
3296
+ var Sidebar = React6.forwardRef(function Sidebar2({
3297
+ className,
3298
+ collapsible = false,
3299
+ variant = "classic",
3300
+ peek: peekEnabled = true,
3301
+ onMouseEnter,
3302
+ onMouseLeave,
3303
+ style,
3304
+ children,
3305
+ ...props
3306
+ }, ref) {
3307
+ const isFloating = variant === "floating";
3308
+ const ctx = React6.useContext(SidebarContext);
3309
+ const state = collapsible && ctx ? ctx.state : "expanded";
3310
+ const peekLockCount = collapsible && ctx && peekEnabled ? ctx.peekLockCount : 0;
3311
+ const [peek, setPeek] = React6.useState(false);
3312
+ const enterTimer = React6.useRef(null);
3313
+ const leaveTimer = React6.useRef(null);
3314
+ const clearTimers = React6.useCallback(() => {
3315
+ if (enterTimer.current != null) {
3316
+ window.clearTimeout(enterTimer.current);
3317
+ enterTimer.current = null;
3318
+ }
3319
+ if (leaveTimer.current != null) {
3320
+ window.clearTimeout(leaveTimer.current);
3321
+ leaveTimer.current = null;
3322
+ }
3323
+ }, []);
3324
+ React6.useEffect(() => () => clearTimers(), [clearTimers]);
3325
+ React6.useEffect(() => {
3326
+ if (state === "expanded") {
3327
+ clearTimers();
3328
+ setPeek(false);
3329
+ }
3330
+ }, [state, clearTimers]);
3331
+ const handleEnter = (e) => {
3332
+ onMouseEnter?.(e);
3333
+ if (!peekEnabled) return;
3334
+ if (!collapsible || state !== "rail") return;
3335
+ if (leaveTimer.current != null) {
3336
+ window.clearTimeout(leaveTimer.current);
3337
+ leaveTimer.current = null;
3338
+ }
3339
+ if (peek) return;
3340
+ enterTimer.current = window.setTimeout(() => setPeek(true), PEEK_ENTER_DELAY_MS);
3341
+ };
3342
+ const handleLeave = (e) => {
3343
+ onMouseLeave?.(e);
3344
+ if (!peekEnabled) return;
3345
+ if (!collapsible) return;
3346
+ if (enterTimer.current != null) {
3347
+ window.clearTimeout(enterTimer.current);
3348
+ enterTimer.current = null;
3349
+ }
3350
+ if (!peek) return;
3351
+ leaveTimer.current = window.setTimeout(() => setPeek(false), PEEK_LEAVE_DELAY_MS);
3352
+ };
3353
+ const overlay = state === "rail" && (peek || peekLockCount > 0);
3354
+ const labelsHidden = state === "rail" && !peek && peekLockCount === 0;
3355
+ const effectiveWidth = labelsHidden ? "var(--ds-layout-shell-sidebar-rail-width, var(--shell-sidebar-w-rail))" : "var(--ds-layout-shell-sidebar-width, var(--shell-sidebar-w))";
3356
+ return (
3357
+ // Hover-peek is *enhancement only*: the canonical way to toggle the
3358
+ // sidebar is <SidebarTrigger> (button) or the Mod+\ shortcut, both
3359
+ // fully keyboard- and screen-reader-accessible. The mouse handlers
3360
+ // here exist to widen the column on pointer hover, which has no
3361
+ // keyboard analogue and intentionally so.
3362
+ // eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions
3363
+ /* @__PURE__ */ jsx(
3364
+ "aside",
3365
+ {
3366
+ ref,
3367
+ "data-state": state,
3368
+ "data-peek": peek ? "true" : void 0,
3369
+ "data-overlay": overlay ? "true" : void 0,
3370
+ "data-labels": labelsHidden ? "hide" : "show",
3371
+ "data-collapsible": collapsible ? "true" : void 0,
3372
+ "data-variant": variant,
3373
+ ...slot(sidebarAnatomy, "root"),
3374
+ onMouseEnter: handleEnter,
3375
+ onMouseLeave: handleLeave,
3376
+ style: { width: effectiveWidth, ...style },
3377
+ className: cn(
3378
+ "ds:group/sidebar group/sidebar ds:scrollbar-thin ds:flex ds:shrink-0 ds:flex-col ds:overflow-y-auto ds:px-3 ds:pt-4 ds:pb-4",
3379
+ // Classic: full-height column flush to the left edge with a right
3380
+ // rule. The legacy look.
3381
+ !isFloating && "ds:h-dvh ds:border-rule ds:bg-bg-2 ds:border-r",
3382
+ // Floating: a detached, rounded card inset from the viewport with a
3383
+ // soft shadow — the modern SaaS pattern. The clear figure/ground gap
3384
+ // (Aesthetic-Usability) reads as its own surface above the canvas.
3385
+ isFloating && "ds:border-rule ds:bg-surface ds:shadow-card ds:m-2.5 ds:h-[calc(100dvh-1.25rem)] ds:rounded-2xl ds:border",
3386
+ // 220ms feels right for a ~192px width sweep — slower than the
3387
+ // 150ms `--duration-fast` (which reads as a snap on this size of
3388
+ // movement) but well short of `--duration-slow` (which feels
3389
+ // sluggish). `will-change` hints the compositor so the column
3390
+ // doesn't repaint every frame mid-transition.
3391
+ "ds:transition-[width,box-shadow] ds:duration-[var(--motion-duration-spatial)] ds:ease-[var(--motion-ease-move)] ds:motion-reduce:transition-none",
3392
+ "ds:[will-change:width]",
3393
+ // Overlay (hover-peek OR programmatic peek-lock): float above the
3394
+ // canvas without reflowing layout. Driven by `data-overlay` so a
3395
+ // single rule handles both transient sources.
3396
+ "ds:data-[overlay=true]:fixed ds:data-[overlay=true]:top-0 ds:data-[overlay=true]:left-0",
3397
+ "ds:data-[overlay=true]:z-[var(--z-overlay)] ds:data-[overlay=true]:shadow-pop",
3398
+ // Padding is held constant across states so icons keep their
3399
+ // horizontal anchor when the column widens — peek expands the
3400
+ // labels rightward rather than shifting the icons leftward.
3401
+ className
3402
+ ),
3403
+ ...props,
3404
+ children: /* @__PURE__ */ jsx(SidebarPeekEnabledContext.Provider, { value: peekEnabled, children: /* @__PURE__ */ jsx(SidebarLabelsHiddenContext.Provider, { value: labelsHidden, children: collapsible && !peekEnabled ? /* @__PURE__ */ jsx(TooltipProvider, { delayDuration: 200, children }) : children }) })
3405
+ }
3406
+ )
3407
+ );
3408
+ });
3409
+ Sidebar.displayName = "Sidebar";
3410
+ var SidebarTrigger = React6.forwardRef(
3411
+ function SidebarTrigger2({
3412
+ className,
3413
+ expandLabel,
3414
+ collapseLabel,
3415
+ onClick,
3416
+ ...props
3417
+ }, ref) {
3418
+ const messages = useDsMessages("sidebar");
3419
+ const ctx = React6.useContext(SidebarContext);
3420
+ if (!ctx) return null;
3421
+ const { state, toggle } = ctx;
3422
+ const label = state === "expanded" ? collapseLabel ?? messages.collapse : expandLabel ?? messages.expand;
3423
+ return /* @__PURE__ */ jsx(
3424
+ "button",
3425
+ {
3426
+ ref,
3427
+ type: "button",
3428
+ "aria-label": label,
3429
+ "aria-expanded": state === "expanded",
3430
+ onClick: (e) => {
3431
+ onClick?.(e);
3432
+ if (!e.defaultPrevented) toggle();
3433
+ },
3434
+ ...slot(sidebarAnatomy, "trigger"),
3435
+ className: cn(
3436
+ "ds:inline-flex ds:size-7 ds:shrink-0 ds:items-center ds:justify-center ds:rounded-md",
3437
+ "ds:text-fg-3 ds:hover:bg-bg-3 ds:hover:text-fg",
3438
+ "ds:transition-colors ds:duration-[var(--duration-fast)] ds:ease-[var(--ease-out-quart)] ds:motion-reduce:transition-none",
3439
+ "ds:focus-visible:[box-shadow:var(--shadow-focus-ring)] ds:focus-visible:outline-none",
3440
+ "ds:[&_svg]:size-4",
3441
+ className
3442
+ ),
3443
+ ...props,
3444
+ children: state === "expanded" ? /* @__PURE__ */ jsx(PanelLeftCloseIcon, {}) : /* @__PURE__ */ jsx(PanelLeftIcon, {})
3445
+ }
3446
+ );
3447
+ }
3448
+ );
3449
+ SidebarTrigger.displayName = "SidebarTrigger";
3450
+ function useSidebarPeekLock(active) {
3451
+ const ctx = React6.useContext(SidebarContext);
3452
+ React6.useEffect(() => {
3453
+ if (!active || !ctx) return;
3454
+ const release = ctx.acquirePeekLock();
3455
+ return release;
3456
+ }, [active, ctx]);
3457
+ }
3458
+ var SidebarPinButton = React6.forwardRef(
3459
+ function SidebarPinButton2({
3460
+ pinLabel,
3461
+ unpinLabel,
3462
+ className,
3463
+ onClick,
3464
+ ...props
3465
+ }, ref) {
3466
+ const messages = useDsMessages("sidebar");
3467
+ const ctx = React6.useContext(SidebarContext);
3468
+ if (!ctx || !ctx.collapsible) return null;
3469
+ const { state, setState } = ctx;
3470
+ const isPinned = state === "expanded";
3471
+ return /* @__PURE__ */ jsx(
3472
+ "button",
3473
+ {
3474
+ ref,
3475
+ type: "button",
3476
+ "aria-label": isPinned ? unpinLabel ?? messages.unpin : pinLabel ?? messages.pin,
3477
+ "aria-pressed": isPinned,
3478
+ onClick: (e) => {
3479
+ onClick?.(e);
3480
+ if (!e.defaultPrevented) setState(isPinned ? "rail" : "expanded");
3481
+ },
3482
+ ...slot(sidebarAnatomy, "pin"),
3483
+ ...stateAttributes({ selected: isPinned }),
3484
+ className: cn(
3485
+ "ds:inline-flex ds:size-7 ds:shrink-0 ds:items-center ds:justify-center ds:rounded-md",
3486
+ "ds:text-fg-4 ds:hover:bg-bg-3 ds:hover:text-fg ds:aria-pressed:text-fg",
3487
+ "ds:transition-colors ds:duration-[var(--duration-fast)] ds:ease-[var(--ease-out-quart)] ds:motion-reduce:transition-none",
3488
+ "ds:focus-visible:outline-none ds:focus-visible:[box-shadow:var(--shadow-focus-ring)]",
3489
+ // Hidden when labels are hidden (rail-no-peek-no-lock). Visible
3490
+ // in every overlay state so users can pin during hover or while
3491
+ // a dropdown holds the column open.
3492
+ "ds:group-data-[labels=hide]/sidebar:hidden",
3493
+ className
3494
+ ),
3495
+ ...props,
3496
+ children: /* @__PURE__ */ jsx(PinGlyph, { size: 14, filled: isPinned, className: "ds:rotate-45" })
3497
+ }
3498
+ );
3499
+ }
3500
+ );
3501
+ SidebarPinButton.displayName = "SidebarPinButton";
3502
+ function PinGlyph({
3503
+ size = 16,
3504
+ filled = false,
3505
+ className
3506
+ }) {
3507
+ return /* @__PURE__ */ jsxs(
3508
+ "svg",
3509
+ {
3510
+ xmlns: "http://www.w3.org/2000/svg",
3511
+ width: size,
3512
+ height: size,
3513
+ viewBox: "0 0 24 24",
3514
+ fill: "none",
3515
+ stroke: "currentColor",
3516
+ strokeWidth: 2,
3517
+ strokeLinecap: "round",
3518
+ strokeLinejoin: "round",
3519
+ "aria-hidden": "true",
3520
+ className,
3521
+ children: [
3522
+ /* @__PURE__ */ jsx("path", { d: "M12 17v5" }),
3523
+ /* @__PURE__ */ jsx(
3524
+ "path",
3525
+ {
3526
+ d: "M9 10.76a2 2 0 0 1-1.11 1.79l-1.78.9A2 2 0 0 0 5 15.24V16a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-.76a2 2 0 0 0-1.11-1.79l-1.78-.9A2 2 0 0 1 15 10.76V7a1 1 0 0 1 1-1 2 2 0 0 0 0-4H8a2 2 0 0 0 0 4 1 1 0 0 1 1 1z",
3527
+ fill: filled ? "currentColor" : "none"
3528
+ }
3529
+ )
3530
+ ]
3531
+ }
3532
+ );
3533
+ }
3534
+ var SidebarBrand = React6.forwardRef(
3535
+ function SidebarBrand2({ className, ...props }, ref) {
3536
+ return /* @__PURE__ */ jsx(
3537
+ "div",
3538
+ {
3539
+ ref,
3540
+ ...slot(sidebarAnatomy, "brand"),
3541
+ className: cn(
3542
+ "ds:flex ds:min-w-0 ds:items-center ds:gap-2 ds:px-2.5 ds:pt-1 ds:pb-4",
3543
+ className
3544
+ ),
3545
+ ...props
3546
+ }
3547
+ );
3548
+ }
3549
+ );
3550
+ SidebarBrand.displayName = "SidebarBrand";
3551
+ var SidebarBrandText = React6.forwardRef(
3552
+ function SidebarBrandText2({ className, ...props }, ref) {
3553
+ const collapsed = useCollapsedAttribute();
3554
+ return /* @__PURE__ */ jsx(
3555
+ "span",
3556
+ {
3557
+ ref,
3558
+ "aria-hidden": "false",
3559
+ ...slot(sidebarAnatomy, "brand-text"),
3560
+ ...collapsed,
3561
+ className: cn(
3562
+ // line-clamp-1 (not `truncate`) so multi-word wordmarks clip at a
3563
+ // word boundary instead of mid-word when the rail is narrow.
3564
+ "ds:min-w-0 ds:line-clamp-1",
3565
+ // Smooth fade + width collapse on rail. Keeps the wordmark
3566
+ // legible up to the moment the column reaches rail width, then
3567
+ // fully drops out (visibility:hidden cuts hit-testing).
3568
+ "ds:transition-[opacity,max-width] ds:duration-[var(--motion-duration-spatial)] ds:ease-[var(--motion-ease-move)] ds:motion-reduce:transition-none",
3569
+ "ds:max-w-[160px] ds:opacity-100",
3570
+ "ds:group-data-[labels=hide]/sidebar:max-w-0 ds:group-data-[labels=hide]/sidebar:opacity-0 ds:group-data-[labels=hide]/sidebar:invisible",
3571
+ className
3572
+ ),
3573
+ ...props
3574
+ }
3575
+ );
3576
+ }
3577
+ );
3578
+ SidebarBrandText.displayName = "SidebarBrandText";
3579
+ var SidebarGroupScopeContext = React6.createContext(null);
3580
+ var SidebarSection = React6.forwardRef(
3581
+ function SidebarSection2({ label, tone = "pro", headerActions, className, children, ...props }, ref) {
3582
+ const collapsed = useCollapsedAttribute();
3583
+ const ariaLabel = typeof label === "string" ? label : typeof label === "number" ? String(label) : void 0;
3584
+ const [exclusiveId, setExclusiveIdState] = React6.useState(null);
3585
+ const setExclusive = React6.useCallback(
3586
+ (id) => setExclusiveIdState(id),
3587
+ []
3588
+ );
3589
+ const scope = React6.useMemo(
3590
+ () => ({ exclusiveId, setExclusive }),
3591
+ [exclusiveId, setExclusive]
3592
+ );
3593
+ return /* @__PURE__ */ jsx(SidebarGroupScopeContext.Provider, { value: scope, children: /* @__PURE__ */ jsxs(
3594
+ "div",
3595
+ {
3596
+ ref,
3597
+ role: ariaLabel ? "group" : void 0,
3598
+ "aria-label": ariaLabel,
3599
+ ...slot(sidebarAnatomy, "section"),
3600
+ ...collapsed,
3601
+ className: cn(
3602
+ "ds:mb-4",
3603
+ // In rail, the visible section labels disappear and the only
3604
+ // grouping cue is a thin rule. No extra mb/pb — the border
3605
+ // itself separates groups, so inter-section spacing matches
3606
+ // intra-section spacing and the rail stays dense.
3607
+ "ds:group-data-[labels=hide]/sidebar:mb-0 ds:group-data-[labels=hide]/sidebar:border-b ds:group-data-[labels=hide]/sidebar:border-rule ds:group-data-[labels=hide]/sidebar:pb-0 ds:group-data-[labels=hide]/sidebar:last:border-b-0",
3608
+ className
3609
+ ),
3610
+ ...props,
3611
+ children: [
3612
+ (label != null || headerActions != null) && /* @__PURE__ */ jsxs(
3613
+ "div",
3614
+ {
3615
+ ...slot(sidebarAnatomy, "section-header"),
3616
+ ...collapsed,
3617
+ className: cn(
3618
+ "ds:mb-1 ds:flex ds:items-center ds:justify-between ds:px-2.5 ds:py-1",
3619
+ "ds:transition-opacity ds:duration-[var(--motion-duration-spatial)] ds:ease-[var(--motion-ease-move)] ds:motion-reduce:transition-none",
3620
+ "ds:opacity-100",
3621
+ "ds:group-data-[labels=hide]/sidebar:invisible ds:group-data-[labels=hide]/sidebar:opacity-0"
3622
+ ),
3623
+ children: [
3624
+ label != null && /* @__PURE__ */ jsx(
3625
+ "span",
3626
+ {
3627
+ ...slot(sidebarAnatomy, "section-label"),
3628
+ className: cn(
3629
+ "ds:font-mono ds:text-[11px] ds:tracking-[0.14em] ds:uppercase",
3630
+ tone === "muted" ? "ds:text-fg-3" : "ds:text-brand"
3631
+ ),
3632
+ children: label
3633
+ }
3634
+ ),
3635
+ headerActions
3636
+ ]
3637
+ }
3638
+ ),
3639
+ children
3640
+ ]
3641
+ }
3642
+ ) });
3643
+ }
3644
+ );
3645
+ SidebarSection.displayName = "SidebarSection";
3646
+ function getTextContent(node) {
3647
+ if (node == null || typeof node === "boolean") return "";
3648
+ if (typeof node === "string" || typeof node === "number") return String(node);
3649
+ if (Array.isArray(node)) return node.map(getTextContent).filter(Boolean).join(" ");
3650
+ if (React6.isValidElement(node)) {
3651
+ return getTextContent(node.props.children);
3652
+ }
3653
+ return "";
3654
+ }
3655
+ var SidebarLink = React6.forwardRef(
3656
+ function SidebarLink2({ href, icon, active = false, asChild, className, children, "aria-label": ariaLabel, ...props }, ref) {
3657
+ const Comp = asChild ? Slot : "a";
3658
+ const accessibleLabel = ariaLabel ?? (asChild ? void 0 : getTextContent(children) || void 0);
3659
+ const labelsHidden = React6.useContext(SidebarLabelsHiddenContext);
3660
+ const peekEnabled = React6.useContext(SidebarPeekEnabledContext);
3661
+ const tooltipLabel = ariaLabel ?? (getTextContent(children) || void 0);
3662
+ const showTooltip = labelsHidden && !peekEnabled && Boolean(tooltipLabel);
3663
+ const link = /* @__PURE__ */ jsx(
3664
+ Comp,
3665
+ {
3666
+ ref,
3667
+ ...asChild ? {} : { href },
3668
+ "data-active": active ? "true" : void 0,
3669
+ "aria-current": active ? "page" : void 0,
3670
+ "aria-label": accessibleLabel,
3671
+ ...slot(sidebarAnatomy, "link"),
3672
+ className: cn(
3673
+ "ds:group/link ds:relative ds:mb-px ds:flex ds:items-center ds:gap-2.5 ds:rounded-md ds:px-2.5 ds:py-1.5",
3674
+ "ds:text-fg-2 ds:text-[13px] ds:font-normal ds:no-underline",
3675
+ "ds:transition-colors ds:duration-[var(--duration-fast)] ds:ease-[var(--ease-out-quart)]",
3676
+ "ds:motion-reduce:transition-none",
3677
+ "ds:hover:bg-bg-3 ds:hover:text-fg",
3678
+ "ds:focus-visible:[box-shadow:var(--shadow-focus-ring)] ds:focus-visible:outline-none",
3679
+ "ds:data-[active=true]:bg-brand-bg ds:data-[active=true]:text-brand ds:data-[active=true]:font-medium",
3680
+ // In rail, the icon itself carries the active state rather
3681
+ // than just the rule bar — color is more legible than a 2px
3682
+ // vertical mark at the column's left edge when labels are
3683
+ // hidden. The full-opacity icon override (`opacity-100`)
3684
+ // counters the default `[&_svg]:opacity-85` so the active
3685
+ // icon doesn't read as "still inactive but darker".
3686
+ "ds:group-data-[labels=hide]/sidebar:data-[active=true]:[&_svg]:text-brand ds:group-data-[labels=hide]/sidebar:data-[active=true]:[&_svg]:opacity-100",
3687
+ // Active rail: 2px wide, 16px tall, anchored to the link's
3688
+ // own left edge — no parent-padding dependency. Continues
3689
+ // working unchanged when the aside narrows to a rail.
3690
+ "ds:data-[active=true]:before:absolute ds:data-[active=true]:before:content-['']",
3691
+ "ds:data-[active=true]:before:top-1/2 ds:data-[active=true]:before:left-0",
3692
+ "ds:data-[active=true]:before:h-4 ds:data-[active=true]:before:w-[2px] ds:data-[active=true]:before:-translate-y-1/2",
3693
+ "ds:data-[active=true]:before:bg-brand ds:data-[active=true]:before:rounded-r-full",
3694
+ // Padding/gap stay constant so the icon stays under the cursor
3695
+ // when the column widens during peek. The label simply collapses
3696
+ // to width 0 via <SidebarLinkLabel>.
3697
+ "ds:[&_svg]:size-3.5 ds:[&_svg]:shrink-0 ds:[&_svg]:opacity-85",
3698
+ // Floating variant: softer corners + a taller hit area (Fitts's
3699
+ // law — a larger target is faster and lower-error to acquire), and
3700
+ // a full pill highlight for active instead of the left rail bar.
3701
+ "ds:group-data-[variant=floating]/sidebar:gap-3 ds:group-data-[variant=floating]/sidebar:rounded-lg ds:group-data-[variant=floating]/sidebar:py-2",
3702
+ "ds:group-data-[variant=floating]/sidebar:data-[active=true]:before:hidden",
3703
+ className
3704
+ ),
3705
+ ...props,
3706
+ children: asChild ? children : /* @__PURE__ */ jsxs(Fragment, { children: [
3707
+ icon,
3708
+ /* @__PURE__ */ jsx(
3709
+ "span",
3710
+ {
3711
+ ...slot(sidebarAnatomy, "link-label"),
3712
+ ...labelsHidden ? { "data-collapsed": "true" } : {},
3713
+ className: cn(
3714
+ // Flex row so a trailing <SidebarLinkBadge> (ml-auto) aligns
3715
+ // to the right edge with a gap from the label, instead of
3716
+ // butting against it. A line-clamp box swallows the badge's
3717
+ // auto margin, which is why "Billing$48k" rendered glued.
3718
+ // Single-line label clips via overflow; badge stays put.
3719
+ "ds:flex ds:min-w-0 ds:flex-1 ds:items-center ds:gap-1.5 ds:overflow-hidden ds:whitespace-nowrap",
3720
+ "ds:transition-[opacity,max-width] ds:duration-[var(--motion-duration-spatial)] ds:ease-[var(--motion-ease-move)] ds:motion-reduce:transition-none",
3721
+ "ds:max-w-full ds:opacity-100",
3722
+ "ds:group-data-[labels=hide]/sidebar:max-w-0 ds:group-data-[labels=hide]/sidebar:opacity-0 ds:group-data-[labels=hide]/sidebar:invisible"
3723
+ ),
3724
+ children
3725
+ }
3726
+ )
3727
+ ] })
3728
+ }
3729
+ );
3730
+ if (!showTooltip) return link;
3731
+ return /* @__PURE__ */ jsxs(Tooltip, { children: [
3732
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: link }),
3733
+ /* @__PURE__ */ jsx(TooltipContent, { side: "right", children: tooltipLabel })
3734
+ ] });
3735
+ }
3736
+ );
3737
+ SidebarLink.displayName = "SidebarLink";
3738
+ var SidebarLinkLabel = React6.forwardRef(
3739
+ function SidebarLinkLabel2({ className, ...props }, ref) {
3740
+ const collapsed = useCollapsedAttribute();
3741
+ return /* @__PURE__ */ jsx(
3742
+ "span",
3743
+ {
3744
+ ref,
3745
+ ...slot(sidebarAnatomy, "link-label"),
3746
+ ...collapsed,
3747
+ className: cn(
3748
+ // line-clamp-1 (not `truncate`) so multi-word labels clip at a
3749
+ // word boundary; collapses cleanly with the rail-mode max-width
3750
+ // animation since both rules only constrain visible content.
3751
+ "ds:min-w-0 ds:flex-1 ds:line-clamp-1",
3752
+ // Fade + collapse instead of hard display:none so a single
3753
+ // 180ms opacity tween covers all labels in lockstep with the
3754
+ // 220ms aside-width transition — no snap on the last frame.
3755
+ "ds:transition-[opacity,max-width] ds:duration-[var(--motion-duration-spatial)] ds:ease-[var(--motion-ease-move)] ds:motion-reduce:transition-none",
3756
+ "ds:max-w-full ds:opacity-100",
3757
+ "ds:group-data-[labels=hide]/sidebar:max-w-0 ds:group-data-[labels=hide]/sidebar:opacity-0 ds:group-data-[labels=hide]/sidebar:invisible",
3758
+ className
3759
+ ),
3760
+ ...props
3761
+ }
3762
+ );
3763
+ }
3764
+ );
3765
+ SidebarLinkLabel.displayName = "SidebarLinkLabel";
3766
+ var SidebarLinkAction = React6.forwardRef(
3767
+ function SidebarLinkAction2({ className, ...props }, ref) {
3768
+ const collapsed = useCollapsedAttribute();
3769
+ return /* @__PURE__ */ jsx(
3770
+ "span",
3771
+ {
3772
+ ref,
3773
+ ...slot(sidebarAnatomy, "link-action"),
3774
+ ...collapsed,
3775
+ className: cn(
3776
+ "ds:transition-opacity ds:duration-[var(--motion-duration-spatial)] ds:ease-[var(--motion-ease-move)] ds:motion-reduce:transition-none",
3777
+ "ds:opacity-100",
3778
+ "ds:group-data-[labels=hide]/sidebar:invisible ds:group-data-[labels=hide]/sidebar:opacity-0",
3779
+ className
3780
+ ),
3781
+ ...props
3782
+ }
3783
+ );
3784
+ }
3785
+ );
3786
+ SidebarLinkAction.displayName = "SidebarLinkAction";
3787
+ var sidebarLinkBadgeVariants = cva(
3788
+ "ds:ml-auto ds:inline-flex ds:shrink-0 ds:items-center ds:justify-center ds:font-mono ds:tabular-nums ds:group-data-[labels=hide]/sidebar:hidden",
3789
+ {
3790
+ variants: {
3791
+ tone: {
3792
+ default: "ds:text-[10.5px] ds:text-fg-4 ds:group-data-[active=true]/link:text-brand",
3793
+ danger: "ds:rounded-pill ds:bg-danger-bg ds:px-1.5 ds:py-0.5 ds:text-[10.5px] ds:text-danger-fg",
3794
+ warning: "ds:rounded-pill ds:bg-warning-bg ds:px-1.5 ds:py-0.5 ds:text-[10.5px] ds:text-warning-fg",
3795
+ neutral: "ds:rounded-pill ds:bg-bg-3 ds:px-1.5 ds:py-0.5 ds:text-[10.5px] ds:text-fg-2"
3796
+ }
3797
+ },
3798
+ defaultVariants: { tone: "default" }
3799
+ }
3800
+ );
3801
+ var SidebarLinkBadge = React6.forwardRef(
3802
+ function SidebarLinkBadge2({ tone, className, ...props }, ref) {
3803
+ return /* @__PURE__ */ jsx(
3804
+ "span",
3805
+ {
3806
+ ref,
3807
+ ...slot(sidebarAnatomy, "link-badge"),
3808
+ className: cn(sidebarLinkBadgeVariants({ tone }), className),
3809
+ ...props
3810
+ }
3811
+ );
3812
+ }
3813
+ );
3814
+ SidebarLinkBadge.displayName = "SidebarLinkBadge";
3815
+ var SidebarLinkGroup = React6.forwardRef(
3816
+ function SidebarLinkGroup2({
3817
+ id: idProp,
3818
+ icon,
3819
+ label,
3820
+ href,
3821
+ active = false,
3822
+ defaultOpen = false,
3823
+ open: controlled,
3824
+ onOpenChange,
3825
+ onActivate,
3826
+ classNames,
3827
+ className,
3828
+ children,
3829
+ ...props
3830
+ }, ref) {
3831
+ const messages = useDsMessages("sidebar");
3832
+ const collapsed = useCollapsedAttribute();
3833
+ const reactId = React6.useId();
3834
+ const id = idProp ?? reactId;
3835
+ const scope = React6.useContext(SidebarGroupScopeContext);
3836
+ const [uncontrolledOpen, setUncontrolledOpen] = React6.useState(defaultOpen);
3837
+ const open = controlled ?? uncontrolledOpen;
3838
+ const setOpen = React6.useCallback(
3839
+ (next) => {
3840
+ if (controlled === void 0) setUncontrolledOpen(next);
3841
+ onOpenChange?.(next);
3842
+ },
3843
+ [controlled, onOpenChange]
3844
+ );
3845
+ React6.useEffect(() => {
3846
+ if (scope?.exclusiveId && scope.exclusiveId !== id && open) {
3847
+ setOpen(false);
3848
+ }
3849
+ }, [scope?.exclusiveId, id, open, setOpen]);
3850
+ const handleBodyClick = (e) => {
3851
+ onActivate?.(e);
3852
+ if (e.defaultPrevented) return;
3853
+ scope?.setExclusive(id);
3854
+ setOpen(true);
3855
+ };
3856
+ const handleChevronClick = (e) => {
3857
+ e.preventDefault();
3858
+ e.stopPropagation();
3859
+ setOpen(!open);
3860
+ };
3861
+ const contentId = `${id}-content`;
3862
+ const bodyClassName = cn(
3863
+ "ds:group/link ds:relative ds:flex ds:flex-1 ds:items-center ds:gap-2.5 ds:rounded-md ds:px-2.5 ds:py-1.5",
3864
+ "ds:text-fg-2 ds:text-[13px] ds:font-normal ds:no-underline",
3865
+ "ds:transition-colors ds:duration-[var(--duration-fast)] ds:ease-[var(--ease-out-quart)]",
3866
+ "ds:motion-reduce:transition-none",
3867
+ "ds:hover:bg-bg-3 ds:hover:text-fg",
3868
+ "ds:focus-visible:[box-shadow:var(--shadow-focus-ring)] ds:focus-visible:outline-none",
3869
+ "ds:data-[active=true]:bg-brand-bg ds:data-[active=true]:text-brand ds:data-[active=true]:font-medium",
3870
+ // In rail, color carries active state since the chevron is hidden.
3871
+ "ds:group-data-[labels=hide]/sidebar:data-[active=true]:[&_svg]:text-brand ds:group-data-[labels=hide]/sidebar:data-[active=true]:[&_svg]:opacity-100",
3872
+ // Active rail mark — anchored to body row's left edge.
3873
+ "ds:data-[active=true]:before:absolute ds:data-[active=true]:before:content-['']",
3874
+ "ds:data-[active=true]:before:top-1/2 ds:data-[active=true]:before:left-0",
3875
+ "ds:data-[active=true]:before:h-4 ds:data-[active=true]:before:w-[2px] ds:data-[active=true]:before:-translate-y-1/2",
3876
+ "ds:data-[active=true]:before:bg-brand ds:data-[active=true]:before:rounded-r-full",
3877
+ "ds:[&_svg]:size-3.5 ds:[&_svg]:shrink-0 ds:[&_svg]:opacity-85",
3878
+ // Floating variant — match SidebarLink: taller hit area, pill active.
3879
+ "ds:group-data-[variant=floating]/sidebar:gap-3 ds:group-data-[variant=floating]/sidebar:rounded-lg ds:group-data-[variant=floating]/sidebar:py-2",
3880
+ "ds:group-data-[variant=floating]/sidebar:data-[active=true]:before:hidden",
3881
+ classNames?.link
3882
+ );
3883
+ const labelSpan = /* @__PURE__ */ jsx(
3884
+ "span",
3885
+ {
3886
+ ...slot(sidebarAnatomy, "link-label"),
3887
+ ...collapsed,
3888
+ className: cn(
3889
+ // line-clamp-1 (not `truncate`) so multi-word labels clip at a
3890
+ // word boundary; collapses cleanly with the rail-mode max-width
3891
+ // animation since both rules only constrain visible content.
3892
+ "ds:min-w-0 ds:flex-1 ds:line-clamp-1",
3893
+ "ds:transition-[opacity,max-width] ds:duration-[var(--motion-duration-spatial)] ds:ease-[var(--motion-ease-move)] ds:motion-reduce:transition-none",
3894
+ "ds:max-w-full ds:opacity-100",
3895
+ "ds:group-data-[labels=hide]/sidebar:max-w-0 ds:group-data-[labels=hide]/sidebar:opacity-0 ds:group-data-[labels=hide]/sidebar:invisible"
3896
+ ),
3897
+ children: label
3898
+ }
3899
+ );
3900
+ return /* @__PURE__ */ jsx(
3901
+ "div",
3902
+ {
3903
+ ref,
3904
+ ...slot(sidebarAnatomy, "group"),
3905
+ ...stateAttributes({ state: open ? "open" : "closed" }),
3906
+ className: cn("ds:mb-px", className),
3907
+ ...props,
3908
+ children: /* @__PURE__ */ jsxs(Collapsible, { open, onOpenChange: setOpen, children: [
3909
+ /* @__PURE__ */ jsxs("div", { className: cn("ds:flex ds:items-stretch", classNames?.row), children: [
3910
+ /* @__PURE__ */ jsxs(
3911
+ "a",
3912
+ {
3913
+ href,
3914
+ "data-active": active ? "true" : void 0,
3915
+ "aria-current": active ? "page" : void 0,
3916
+ "aria-label": getTextContent(label) || void 0,
3917
+ onClick: handleBodyClick,
3918
+ ...slot(sidebarAnatomy, "group-link"),
3919
+ className: bodyClassName,
3920
+ children: [
3921
+ icon,
3922
+ labelSpan
3923
+ ]
3924
+ }
3925
+ ),
3926
+ /* @__PURE__ */ jsx(
3927
+ "button",
3928
+ {
3929
+ type: "button",
3930
+ "aria-expanded": open,
3931
+ "aria-controls": contentId,
3932
+ "aria-label": open ? messages.collapseSection : messages.expandSection,
3933
+ onClick: handleChevronClick,
3934
+ ...slot(sidebarAnatomy, "group-trigger"),
3935
+ className: cn(
3936
+ "ds:ml-px ds:inline-flex ds:size-7 ds:shrink-0 ds:items-center ds:justify-center ds:rounded-md",
3937
+ "ds:text-fg-4 ds:hover:bg-bg-3 ds:hover:text-fg-2",
3938
+ "ds:transition-colors ds:duration-[var(--duration-fast)] ds:ease-[var(--ease-out-quart)] ds:motion-reduce:transition-none",
3939
+ "ds:focus-visible:[box-shadow:var(--shadow-focus-ring)] ds:focus-visible:outline-none",
3940
+ "ds:[&_svg]:size-3.5 ds:[&_svg]:shrink-0 ds:[&_svg]:transition-transform ds:[&_svg]:duration-[var(--duration-fast)] ds:[&_svg]:ease-[var(--ease-out-quart)] ds:motion-reduce:[&_svg]:transition-none",
3941
+ // Hide in rail — content tree is hidden too, so the
3942
+ // affordance has nothing to control.
3943
+ "ds:group-data-[labels=hide]/sidebar:hidden"
3944
+ ),
3945
+ children: /* @__PURE__ */ jsx(ChevronDownIcon, { className: open ? "" : "ds:-rotate-90" })
3946
+ }
3947
+ )
3948
+ ] }),
3949
+ /* @__PURE__ */ jsx(
3950
+ CollapsibleContent,
3951
+ {
3952
+ id: contentId,
3953
+ ...slot(sidebarAnatomy, "group-content"),
3954
+ className: cn(
3955
+ // Indent column + connecting rule. Children render as
3956
+ // standard <SidebarLink>s and keep their own active-rail
3957
+ // indicator, which lands flush at the indented column's
3958
+ // left edge.
3959
+ "ds:group-data-[labels=hide]/sidebar:hidden"
3960
+ ),
3961
+ children: /* @__PURE__ */ jsx("div", { className: "ds:border-rule ds:mt-px ds:ml-[18px] ds:border-l ds:pl-2", children })
3962
+ }
3963
+ )
3964
+ ] })
3965
+ }
3966
+ );
3967
+ }
3968
+ );
3969
+ SidebarLinkGroup.displayName = "SidebarLinkGroup";
3970
+ var SidebarFooter = React6.forwardRef(
3971
+ function SidebarFooter2({ className, ...props }, ref) {
3972
+ return /* @__PURE__ */ jsx(
3973
+ "div",
3974
+ {
3975
+ ref,
3976
+ ...slot(sidebarAnatomy, "footer"),
3977
+ className: cn(
3978
+ "ds:border-rule ds:mt-auto ds:flex ds:items-center ds:gap-2.5 ds:border-t ds:px-2 ds:pt-2.5 ds:pb-1",
3979
+ "ds:text-fg-3 ds:text-xs",
3980
+ className
3981
+ ),
3982
+ ...props
3983
+ }
3984
+ );
3985
+ }
3986
+ );
3987
+ SidebarFooter.displayName = "SidebarFooter";
3988
+ var SidebarUser = React6.forwardRef(function SidebarUser2({ name, subtitle, avatarSrc, className, ...props }, ref) {
3989
+ const collapsed = useCollapsedAttribute();
3990
+ return /* @__PURE__ */ jsxs(
3991
+ "div",
3992
+ {
3993
+ ref,
3994
+ ...slot(sidebarAnatomy, "user"),
3995
+ ...collapsed,
3996
+ className: cn("ds:flex ds:min-w-0 ds:items-center ds:gap-2.5", className),
3997
+ ...props,
3998
+ children: [
3999
+ /* @__PURE__ */ jsx(Avatar, { size: "sm", variant: "branded", name, src: avatarSrc ?? void 0 }),
4000
+ /* @__PURE__ */ jsxs(
4001
+ "div",
4002
+ {
4003
+ className: cn(
4004
+ "ds:min-w-0 ds:leading-tight",
4005
+ "ds:transition-[opacity,max-width] ds:duration-[var(--motion-duration-spatial)] ds:ease-[var(--motion-ease-move)] ds:motion-reduce:transition-none",
4006
+ "ds:max-w-full ds:opacity-100",
4007
+ "ds:group-data-[labels=hide]/sidebar:max-w-0 ds:group-data-[labels=hide]/sidebar:opacity-0 ds:group-data-[labels=hide]/sidebar:invisible"
4008
+ ),
4009
+ children: [
4010
+ /* @__PURE__ */ jsx(
4011
+ "div",
4012
+ {
4013
+ ...slot(sidebarAnatomy, "user-name"),
4014
+ className: "ds:text-fg ds:line-clamp-1 ds:text-[13px] ds:font-medium",
4015
+ children: name
4016
+ }
4017
+ ),
4018
+ subtitle != null && /* @__PURE__ */ jsx(
4019
+ "div",
4020
+ {
4021
+ ...slot(sidebarAnatomy, "user-subtitle"),
4022
+ className: "ds:text-fg-4 ds:line-clamp-1 ds:font-mono ds:text-[10.5px]",
4023
+ children: subtitle
4024
+ }
4025
+ )
4026
+ ]
4027
+ }
4028
+ )
4029
+ ]
4030
+ }
4031
+ );
4032
+ });
4033
+ SidebarUser.displayName = "SidebarUser";
4034
+ function SidebarDrawer({
4035
+ open,
4036
+ defaultOpen,
4037
+ onOpenChange,
4038
+ label,
4039
+ className,
4040
+ children
4041
+ }) {
4042
+ const messages = useDsMessages("sidebar");
4043
+ return /* @__PURE__ */ jsx(
4044
+ Sheet,
4045
+ {
4046
+ ...open !== void 0 && { open },
4047
+ ...defaultOpen !== void 0 && { defaultOpen },
4048
+ ...onOpenChange !== void 0 && { onOpenChange },
4049
+ children: /* @__PURE__ */ jsxs(
4050
+ SheetContent,
4051
+ {
4052
+ side: "left",
4053
+ "data-mode": "mobile",
4054
+ "data-labels": "show",
4055
+ style: { width: "var(--ds-layout-shell-sidebar-width, var(--shell-sidebar-w))" },
4056
+ className: cn(
4057
+ "ds:group/sidebar group/sidebar ds:scrollbar-thin ds:bg-bg-2 ds:flex ds:flex-col ds:overflow-y-auto ds:px-3 ds:pt-4 ds:pb-4",
4058
+ className
4059
+ ),
4060
+ children: [
4061
+ /* @__PURE__ */ jsx(SheetTitle, { className: "ds:sr-only", children: label ?? messages.navigation }),
4062
+ children
4063
+ ]
4064
+ }
4065
+ )
4066
+ }
4067
+ );
4068
+ }
4069
+ SidebarDrawer.displayName = "SidebarDrawer";
4070
+ var SidebarBrandSwitcher = React6.forwardRef(
4071
+ function SidebarBrandSwitcher2({
4072
+ brand,
4073
+ label,
4074
+ current,
4075
+ items,
4076
+ onLaunch,
4077
+ extras,
4078
+ isLaunching,
4079
+ currentSectionLabel = "Currently using",
4080
+ switchSectionLabel = "Switch to",
4081
+ menuLabel = "Suite",
4082
+ currentBadge = "Current",
4083
+ unavailableBadge = "Soon",
4084
+ triggerLabel = "Switch product",
4085
+ className,
4086
+ triggerClassName,
4087
+ contentClassName,
4088
+ iconClassName,
4089
+ rowClassName,
4090
+ trailing
4091
+ }, ref) {
4092
+ const [open, setOpen] = React6.useState(false);
4093
+ useSidebarPeekLock(open);
4094
+ const others = items.filter((p) => p.id !== current.id);
4095
+ return (
4096
+ // Geometry mirrors <SidebarBrand>: `px-2.5 pt-1 pb-4 gap-2`. This is
4097
+ // deliberate — the switcher replaces SidebarBrand, so the brand
4098
+ // glyph must land at the same column x-position that direct children
4099
+ // of <SidebarBrand> sit at, which in turn matches the 10px left
4100
+ // padding of <SidebarLink> icons below.
4101
+ /* @__PURE__ */ jsxs(
4102
+ "div",
4103
+ {
4104
+ ref,
4105
+ ...slot(sidebarBrandSwitcherAnatomy, "root"),
4106
+ className: cn("ds:flex ds:min-w-0 ds:items-center ds:gap-2 ds:px-2.5 ds:pt-1 ds:pb-4", className),
4107
+ children: [
4108
+ /* @__PURE__ */ jsxs(DropdownMenu, { open, onOpenChange: setOpen, children: [
4109
+ /* @__PURE__ */ jsxs(
4110
+ DropdownMenuTrigger,
4111
+ {
4112
+ "aria-label": triggerLabel,
4113
+ ...slot(sidebarBrandSwitcherAnatomy, "trigger"),
4114
+ className: cn(
4115
+ // Negative left margin pulls the trigger's hover-bg toward
4116
+ // the column edge while the inner padding holds the brand
4117
+ // glyph at the same x-position as direct <SidebarBrand>
4118
+ // children — same hover affordance, no glyph drift.
4119
+ "ds:group/brand-trigger ds:-ml-2 ds:flex ds:min-w-0 ds:flex-1 ds:items-center ds:gap-2 ds:rounded-md ds:py-1.5 ds:pr-1.5 ds:pl-2",
4120
+ "ds:text-fg ds:transition-colors ds:duration-[var(--duration-fast)] ds:ease-[var(--ease-out-quart)] ds:motion-reduce:transition-none",
4121
+ "ds:hover:bg-bg-3 ds:data-[state=open]:bg-bg-3",
4122
+ "ds:focus-visible:outline-none ds:focus-visible:[box-shadow:var(--shadow-focus-ring)]",
4123
+ triggerClassName
4124
+ ),
4125
+ children: [
4126
+ brand,
4127
+ /* @__PURE__ */ jsx(SidebarBrandText, { className: "ds:font-display ds:text-fg ds:text-[17px] ds:font-semibold ds:tracking-tight", children: label }),
4128
+ /* @__PURE__ */ jsx(
4129
+ ChevronDownIcon,
4130
+ {
4131
+ ...slot(sidebarBrandSwitcherAnatomy, "icon"),
4132
+ className: cn(
4133
+ "ds:ml-auto ds:size-3.5 ds:shrink-0 ds:text-fg-4",
4134
+ "ds:transition-transform ds:duration-[var(--duration-fast)] ds:ease-[var(--ease-out-quart)] ds:motion-reduce:transition-none",
4135
+ "ds:group-data-[state=open]/brand-trigger:rotate-180",
4136
+ "ds:group-data-[labels=hide]/sidebar:hidden",
4137
+ iconClassName
4138
+ )
4139
+ }
4140
+ )
4141
+ ]
4142
+ }
4143
+ ),
4144
+ /* @__PURE__ */ jsxs(
4145
+ DropdownMenuContent,
4146
+ {
4147
+ side: "right",
4148
+ align: "start",
4149
+ sideOffset: 12,
4150
+ className: cn("ds:w-72 ds:p-1", contentClassName),
4151
+ children: [
4152
+ /* @__PURE__ */ jsx(DropdownMenuLabel, { className: "ds:px-2 ds:pt-1 ds:pb-1.5", children: menuLabel }),
4153
+ /* @__PURE__ */ jsx(SidebarBrandSwitcherSectionLabel, { children: currentSectionLabel }),
4154
+ /* @__PURE__ */ jsx(
4155
+ SidebarBrandSwitcherCurrentRow,
4156
+ {
4157
+ item: current,
4158
+ badge: currentBadge,
4159
+ rowClassName
4160
+ }
4161
+ ),
4162
+ /* @__PURE__ */ jsx(DropdownMenuSeparator, { className: "ds:my-1.5" }),
4163
+ /* @__PURE__ */ jsx(SidebarBrandSwitcherSectionLabel, { children: switchSectionLabel }),
4164
+ others.map((p) => /* @__PURE__ */ jsx(
4165
+ SidebarBrandSwitcherOtherRow,
4166
+ {
4167
+ item: p,
4168
+ onLaunch,
4169
+ unavailableBadge,
4170
+ rowClassName,
4171
+ isLaunching
4172
+ },
4173
+ p.id
4174
+ )),
4175
+ extras?.map((extra) => /* @__PURE__ */ jsx(
4176
+ SidebarBrandSwitcherExtraRow,
4177
+ {
4178
+ extra,
4179
+ rowClassName
4180
+ },
4181
+ extra.id
4182
+ ))
4183
+ ]
4184
+ }
4185
+ )
4186
+ ] }),
4187
+ trailing
4188
+ ]
4189
+ }
4190
+ )
4191
+ );
4192
+ }
4193
+ );
4194
+ SidebarBrandSwitcher.displayName = "SidebarBrandSwitcher";
4195
+ function SidebarBrandSwitcherSectionLabel({ children }) {
4196
+ return /* @__PURE__ */ jsx("div", { className: "ds:px-2 ds:pt-1 ds:pb-0.5 ds:text-[10px] ds:tracking-wider ds:uppercase ds:text-fg-4", children });
4197
+ }
4198
+ function SidebarBrandSwitcherTile({ item }) {
4199
+ if (item.glyph) return /* @__PURE__ */ jsx(Fragment, { children: item.glyph });
4200
+ const initial = (item.short ?? item.name).charAt(0).toUpperCase();
4201
+ return /* @__PURE__ */ jsx(
4202
+ "span",
4203
+ {
4204
+ "aria-hidden": true,
4205
+ className: cn(
4206
+ "ds:inline-flex ds:size-6 ds:shrink-0 ds:items-center ds:justify-center ds:rounded-md",
4207
+ "ds:text-[11px] ds:font-semibold ds:text-white",
4208
+ item.tone
4209
+ ),
4210
+ children: initial
4211
+ }
4212
+ );
4213
+ }
4214
+ function SidebarBrandSwitcherIdentity({ item }) {
4215
+ if (item.identity) {
4216
+ return /* @__PURE__ */ jsxs("div", { className: "ds:flex ds:min-w-0 ds:flex-1 ds:flex-col ds:gap-0.5", children: [
4217
+ item.identity,
4218
+ item.tagline && /* @__PURE__ */ jsx("span", { className: "ds:text-fg-3 ds:text-[11px] ds:leading-tight", children: item.tagline })
4219
+ ] });
4220
+ }
4221
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
4222
+ /* @__PURE__ */ jsx(SidebarBrandSwitcherTile, { item }),
4223
+ /* @__PURE__ */ jsxs("div", { className: "ds:flex ds:min-w-0 ds:flex-1 ds:flex-col", children: [
4224
+ /* @__PURE__ */ jsx("span", { className: "ds:text-fg ds:text-[13px] ds:font-medium", children: item.name }),
4225
+ item.tagline && /* @__PURE__ */ jsx("span", { className: "ds:text-fg-3 ds:text-[11px]", children: item.tagline })
4226
+ ] })
4227
+ ] });
4228
+ }
4229
+ function SidebarBrandSwitcherCurrentRow({
4230
+ item,
4231
+ badge,
4232
+ rowClassName
4233
+ }) {
4234
+ return /* @__PURE__ */ jsxs(
4235
+ "div",
4236
+ {
4237
+ className: cn(
4238
+ "ds:mx-0 ds:flex ds:cursor-default ds:items-center ds:gap-2.5 ds:rounded-md ds:bg-bg-2 ds:px-2 ds:py-1.5",
4239
+ rowClassName
4240
+ ),
4241
+ children: [
4242
+ /* @__PURE__ */ jsx(SidebarBrandSwitcherIdentity, { item }),
4243
+ badge && /* @__PURE__ */ jsx("span", { className: "ds:rounded-sm ds:px-1.5 ds:py-0.5 ds:text-[10px] ds:font-medium ds:tracking-wider ds:uppercase ds:text-pro-fg ds:ring-1 ds:ring-pro-fg/30", children: badge })
4244
+ ]
4245
+ }
4246
+ );
4247
+ }
4248
+ function SidebarBrandSwitcherOtherRow({
4249
+ item,
4250
+ onLaunch,
4251
+ unavailableBadge,
4252
+ rowClassName,
4253
+ isLaunching
4254
+ }) {
4255
+ const reachable = item.available !== false;
4256
+ const [launching, setLaunching] = React6.useState(false);
4257
+ const externalLaunching = isLaunching?.(item) ?? false;
4258
+ const busy = launching || externalLaunching;
4259
+ const handleSelect = async () => {
4260
+ if (!reachable || busy || !onLaunch) return;
4261
+ setLaunching(true);
4262
+ try {
4263
+ await onLaunch(item);
4264
+ } finally {
4265
+ setLaunching(false);
4266
+ }
4267
+ };
4268
+ return /* @__PURE__ */ jsxs(
4269
+ DropdownMenuItem,
4270
+ {
4271
+ disabled: !reachable,
4272
+ onSelect: (e) => {
4273
+ if (!reachable) {
4274
+ e.preventDefault();
4275
+ return;
4276
+ }
4277
+ void handleSelect();
4278
+ },
4279
+ "data-item": item.dataAttr ?? item.id,
4280
+ className: cn("ds:flex ds:items-center ds:gap-2.5 ds:rounded-md ds:px-2 ds:py-1.5", rowClassName),
4281
+ children: [
4282
+ /* @__PURE__ */ jsx(SidebarBrandSwitcherIdentity, { item }),
4283
+ !reachable && unavailableBadge && /* @__PURE__ */ jsx("span", { className: "ds:rounded-sm ds:bg-bg-3 ds:px-1.5 ds:py-0.5 ds:text-[10px] ds:font-medium ds:tracking-wider ds:uppercase ds:text-fg-4", children: unavailableBadge }),
4284
+ reachable && busy && /* @__PURE__ */ jsx("span", { className: "ds:rounded-sm ds:bg-bg-3 ds:px-1.5 ds:py-0.5 ds:text-[10px] ds:font-medium ds:tracking-wider ds:uppercase ds:text-fg-4", children: "Opening\u2026" })
4285
+ ]
4286
+ }
4287
+ );
4288
+ }
4289
+ function SidebarBrandSwitcherExtraRow({
4290
+ extra,
4291
+ rowClassName
4292
+ }) {
4293
+ return /* @__PURE__ */ jsx(
4294
+ DropdownMenuItem,
4295
+ {
4296
+ onSelect: () => extra.onSelect(),
4297
+ "data-item": extra.dataAttr ?? extra.id,
4298
+ className: cn("ds:flex ds:items-center ds:gap-2.5 ds:rounded-md ds:px-2 ds:py-1.5", rowClassName),
4299
+ children: extra.identity ? /* @__PURE__ */ jsxs("div", { className: "ds:flex ds:min-w-0 ds:flex-1 ds:flex-col ds:gap-0.5", children: [
4300
+ extra.identity,
4301
+ extra.tagline && /* @__PURE__ */ jsx("span", { className: "ds:text-fg-3 ds:text-[11px] ds:leading-tight", children: extra.tagline })
4302
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
4303
+ extra.glyph,
4304
+ /* @__PURE__ */ jsxs("div", { className: "ds:flex ds:min-w-0 ds:flex-1 ds:flex-col", children: [
4305
+ /* @__PURE__ */ jsx("span", { className: "ds:text-fg ds:text-[13px] ds:font-medium", children: extra.name }),
4306
+ extra.tagline && /* @__PURE__ */ jsx("span", { className: "ds:text-fg-3 ds:text-[11px]", children: extra.tagline })
4307
+ ] })
4308
+ ] })
4309
+ }
4310
+ );
4311
+ }
4312
+ function brandScope(product) {
4313
+ return { "data-brand": product };
4314
+ }
4315
+ var BRAND_PRODUCTS = ["pro", "audit", "books", "tax"];
4316
+ var brandLabel = {
4317
+ pro: "Pro",
4318
+ audit: "Audit",
4319
+ books: "Books",
4320
+ tax: "Tax"
4321
+ };
4322
+ var BrandScopeContext = createContext("pro");
4323
+ function BrandScopeProvider({
4324
+ product,
4325
+ children
4326
+ }) {
4327
+ return /* @__PURE__ */ jsx(BrandScopeContext.Provider, { value: product, children });
4328
+ }
4329
+ function useBrandScope() {
4330
+ return useContext(BrandScopeContext);
4331
+ }
4332
+ var BrandScope = forwardRef(function BrandScope2({ product, children, ...props }, ref) {
4333
+ return /* @__PURE__ */ jsx(BrandScopeProvider, { product, children: /* @__PURE__ */ jsx("div", { ref, "data-brand": product, ...props, children }) });
4334
+ });
4335
+ BrandScope.displayName = "BrandScope";
4336
+
4337
+ export { AgreementPaneHeading, AgreementViewer, AssureAuditBrandIcon, AssureBooksBrandIcon, AssureProBrandIcon, AssureTaxBrandIcon, BRAND_PRODUCTS, BrandScope, BrandScopeProvider, Chip, ClientSelect, CmdkCompatContext, Collapsible, CollapsibleContent, CollapsibleTrigger, Combobox, ComingSoon, DEFAULT_COMBOBOX_MESSAGES, Grid, Logo, PlainLink, ProposalAddOn, ProposalBillingTerms, ProposalConsentGate, ProposalCustomPage, ProposalNote, ProposalPackageCard, ProposalPaymentCapture, ProposalPricingSummary, ProposalServiceRow, ProposalSignatureBlock, ProposalSignerList, QUESTION_TYPES, QUESTION_TYPE_CONTRACT_VERSION, Questions, Sheet, SheetBody, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, Sidebar, SidebarBrand, SidebarBrandSwitcher, SidebarBrandSwitcherTile, SidebarBrandText, SidebarDrawer, SidebarFooter, SidebarLink, SidebarLinkAction, SidebarLinkBadge, SidebarLinkGroup, SidebarLinkLabel, SidebarPinButton, SidebarProvider, SidebarSection, SidebarTrigger, SidebarUser, assetPath, brandLabel, brandScope, chipVariants, getAssetBasePath, resolveChipStyle, setAssetBasePath, sidebarLinkBadgeVariants, useBrandScope, useSidebarPeekLock, useSidebarState };
4338
+ //# sourceMappingURL=chunk-XV2VSEA5.js.map
4339
+ //# sourceMappingURL=chunk-XV2VSEA5.js.map