gridsmith-ui 0.27.0 → 0.29.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 (62) hide show
  1. package/CHANGELOG.md +63 -1
  2. package/dist/charts.d.ts +2 -2
  3. package/dist/charts.js +2 -2
  4. package/dist/charts.js.map +1 -1
  5. package/dist/chat.js +5 -5
  6. package/dist/chat.js.map +1 -1
  7. package/dist/{chunk-64TXZ4L7.js → chunk-2ROVDVLZ.js} +3 -3
  8. package/dist/{chunk-64TXZ4L7.js.map → chunk-2ROVDVLZ.js.map} +1 -1
  9. package/dist/chunk-66JJCQU3.js +46 -0
  10. package/dist/chunk-66JJCQU3.js.map +1 -0
  11. package/dist/chunk-7RKC5C7G.js +35 -0
  12. package/dist/chunk-7RKC5C7G.js.map +1 -0
  13. package/dist/{chunk-OTCEJN64.js → chunk-BRAXJEEP.js} +7 -6
  14. package/dist/chunk-BRAXJEEP.js.map +1 -0
  15. package/dist/{chunk-IXR4UEF4.js → chunk-DQCHCLEJ.js} +9 -8
  16. package/dist/chunk-DQCHCLEJ.js.map +1 -0
  17. package/dist/{chunk-5TUVX4B2.js → chunk-EIWXVICU.js} +3 -3
  18. package/dist/{chunk-5TUVX4B2.js.map → chunk-EIWXVICU.js.map} +1 -1
  19. package/dist/{chunk-SFY2KMHG.js → chunk-FD4YED7O.js} +5 -4
  20. package/dist/chunk-FD4YED7O.js.map +1 -0
  21. package/dist/{chunk-MD2EFMES.js → chunk-GXMTS3YD.js} +3 -3
  22. package/dist/{chunk-MD2EFMES.js.map → chunk-GXMTS3YD.js.map} +1 -1
  23. package/dist/chunk-HTXP5BMM.js +38 -0
  24. package/dist/chunk-HTXP5BMM.js.map +1 -0
  25. package/dist/{chunk-R5NFCEZ3.js → chunk-OPFJEL3Z.js} +52 -24
  26. package/dist/chunk-OPFJEL3Z.js.map +1 -0
  27. package/dist/{chunk-EKBWWA6P.js → chunk-R4GXKH4U.js} +7 -7
  28. package/dist/chunk-R4GXKH4U.js.map +1 -0
  29. package/dist/{chunk-PO65I3MQ.js → chunk-TRDXWHD2.js} +6 -6
  30. package/dist/chunk-TRDXWHD2.js.map +1 -0
  31. package/dist/{chunk-2CKSSWYG.js → chunk-YUTF2X6B.js} +39 -20
  32. package/dist/chunk-YUTF2X6B.js.map +1 -0
  33. package/dist/data-grid.js +18 -11
  34. package/dist/data-grid.js.map +1 -1
  35. package/dist/editor-mentions.js +2 -2
  36. package/dist/editor.js +44 -24
  37. package/dist/editor.js.map +1 -1
  38. package/dist/index.d.ts +46 -24
  39. package/dist/index.js +404 -295
  40. package/dist/index.js.map +1 -1
  41. package/dist/kanban.js +18 -11
  42. package/dist/kanban.js.map +1 -1
  43. package/dist/resizable.js +20 -15
  44. package/dist/resizable.js.map +1 -1
  45. package/dist/roots.css +91 -15
  46. package/dist/tokens.css +111 -26
  47. package/dist/utils.d.ts +47 -5
  48. package/dist/utils.js +15 -5
  49. package/dist/utils.js.map +1 -1
  50. package/dist/virtualized.js +17 -11
  51. package/dist/virtualized.js.map +1 -1
  52. package/dist-static/tokens.css +111 -26
  53. package/package.json +2 -2
  54. package/dist/chunk-2CKSSWYG.js.map +0 -1
  55. package/dist/chunk-EKBWWA6P.js.map +0 -1
  56. package/dist/chunk-IXR4UEF4.js.map +0 -1
  57. package/dist/chunk-M2QRNBDQ.js +0 -42
  58. package/dist/chunk-M2QRNBDQ.js.map +0 -1
  59. package/dist/chunk-OTCEJN64.js.map +0 -1
  60. package/dist/chunk-PO65I3MQ.js.map +0 -1
  61. package/dist/chunk-R5NFCEZ3.js.map +0 -1
  62. package/dist/chunk-SFY2KMHG.js.map +0 -1
package/dist/index.js CHANGED
@@ -1,37 +1,41 @@
1
1
  "use client";
2
- import { useAppShell, REACT_VERSION_PROBLEM, Breadcrumbs, useCrumbFollow, crumbGoes, useOverlayMark, useDirtyGuard, useScrollbarInset, DrawerFooterCtx, OverlayMarkScope, OverlayCloseCtx, insetLessScrollbar, DiscardConfirm, OVERLAY_ROOT_ATTR, OverlayMarkCtx, useCompact, useElementWidth, DrawerPanel, useCloseSettle, Drawer, useRememberedWidth, pxOf, ResizeEdge, defaultMaxWidth } from './chunk-R5NFCEZ3.js';
3
- export { AppShell, Breadcrumbs, Drawer, SkipLink, useAppShell, useUnsavedChanges } from './chunk-R5NFCEZ3.js';
4
- import { Skeleton, TITLE_TEXT, useFormatLocale, useHydrated, useToday, LocaleContext } from './chunk-64TXZ4L7.js';
5
- export { Skeleton, useFormatLocale, useHydrated } from './chunk-64TXZ4L7.js';
2
+ import { useAppShell, REACT_VERSION_PROBLEM, Breadcrumbs, useCrumbFollow, crumbGoes, useOverlayMark, useDirtyGuard, useScrollbarInset, DrawerFooterCtx, OverlayMarkScope, OverlayCloseCtx, insetLessScrollbar, DiscardConfirm, OVERLAY_ROOT_ATTR, OverlayMarkCtx, useCompact, useElementWidth, DrawerPanel, useCloseSettle, Drawer, useRememberedWidth, pxOf, ResizeEdge, defaultMaxWidth } from './chunk-OPFJEL3Z.js';
3
+ export { AppShell, Breadcrumbs, Drawer, SkipLink, useAppShell, useUnsavedChanges } from './chunk-OPFJEL3Z.js';
4
+ import { Skeleton, TITLE_TEXT, useFormatLocale, useHydrated, useToday, LocaleContext } from './chunk-2ROVDVLZ.js';
5
+ export { Skeleton, useFormatLocale, useHydrated } from './chunk-2ROVDVLZ.js';
6
6
  import { useScrollEdges, EDGE_FADE } from './chunk-3BRQRKDO.js';
7
- import { Avatar, foldForSearch, useActiveOptionInView, shownMentions, matchMentions, mentionOptionId, MentionList, initialsOf } from './chunk-5TUVX4B2.js';
8
- export { Avatar } from './chunk-5TUVX4B2.js';
9
- import { Link } from './chunk-IXR4UEF4.js';
10
- export { CodeBlock, Divider, Link } from './chunk-IXR4UEF4.js';
11
- import { useFillHeight, FillContext, useKeyboardScroll, FOCUS_INSET } from './chunk-SFY2KMHG.js';
12
- import { Badge } from './chunk-PO65I3MQ.js';
13
- export { Badge } from './chunk-PO65I3MQ.js';
14
- import { inferColumnKinds, useCardsSwitch, CARDS_BELOW, kindOfRenderedText, CardValue } from './chunk-OTCEJN64.js';
15
- import { useWholeListCheck, pagerPart, Pagination, Input, CHECK_FILL, Dropdown, FilterRowContext, SWITCH_KNOB_ON, SWITCH_KNOB_OFF, SWITCH_KNOB_MOTION, SWITCH_TRACK_ON, SWITCH_TRACK_OFF, useFieldControl, useField, OutsideField, NumberInput, InlineFieldError, Label, AddAnotherRowCtx, Field } from './chunk-2CKSSWYG.js';
16
- export { Dropdown, Field, InlineFieldError, Input, Label, NumberInput, Pagination, Popover, Textarea, Toggle, usePagination } from './chunk-2CKSSWYG.js';
17
- import { Button, ControlSizeContext, triggerType, Spinner, useShellPreferences, PREFERENCE_HOUSE_DEFAULTS, formatRelativeTime, thresholdOf, toMillis, formatFullTime, preferenceActionKey, DAY, HOUR, MINUTE } from './chunk-EKBWWA6P.js';
18
- export { Button, ButtonSizeContext, ControlSizeContext, PreferencesContext, Spinner, formatFullTime, formatRelativeTime, preferenceActionKey, usePreferences } from './chunk-EKBWWA6P.js';
7
+ import { Avatar, foldForSearch, useActiveOptionInView, shownMentions, matchMentions, mentionOptionId, MentionList, initialsOf } from './chunk-EIWXVICU.js';
8
+ export { Avatar } from './chunk-EIWXVICU.js';
9
+ import { Link } from './chunk-DQCHCLEJ.js';
10
+ export { CodeBlock, Divider, Link } from './chunk-DQCHCLEJ.js';
11
+ import { useFillHeight, FillContext, useKeyboardScroll } from './chunk-FD4YED7O.js';
12
+ import { Badge } from './chunk-TRDXWHD2.js';
13
+ export { Badge } from './chunk-TRDXWHD2.js';
14
+ import { inferColumnKinds, useCardsSwitch, CARDS_BELOW, kindOfRenderedText, CardValue } from './chunk-BRAXJEEP.js';
15
+ import { useWholeListCheck, pagerPart, Pagination, Input, CHECK_FILL, Dropdown, FilterRowContext, SWITCH_KNOB_ON, SWITCH_KNOB_OFF, SWITCH_KNOB_MOTION, SWITCH_TRACK_ON, SWITCH_TRACK_OFF, useFieldControl, useField, OutsideField, NumberInput, InlineFieldError, Label, AddAnotherRowCtx, Field } from './chunk-YUTF2X6B.js';
16
+ export { Dropdown, Field, InlineFieldError, Input, Label, NumberInput, Pagination, Popover, Textarea, Toggle, usePagination } from './chunk-YUTF2X6B.js';
17
+ import { Button, ControlSizeContext, triggerType, Spinner, useShellPreferences, PREFERENCE_HOUSE_DEFAULTS, formatRelativeTime, thresholdOf, toMillis, formatFullTime, preferenceActionKey, DAY, HOUR, MINUTE } from './chunk-R4GXKH4U.js';
18
+ export { Button, ButtonSizeContext, ControlSizeContext, PreferencesContext, Spinner, formatFullTime, formatRelativeTime, preferenceActionKey, usePreferences } from './chunk-R4GXKH4U.js';
19
19
  import { elementType, formatLocale, localeChoice } from './chunk-OYNUU346.js';
20
+ import { useInputModality } from './chunk-7RKC5C7G.js';
21
+ export { INPUT_MODALITY_ATTR, inputModality, installInputModality, useInputModality } from './chunk-7RKC5C7G.js';
20
22
  import { useBreakpoint, readBreakpointPx } from './chunk-CRQ6KCRD.js';
21
23
  export { BreakpointWidthProvider, useBreakpoint } from './chunk-CRQ6KCRD.js';
22
24
  import { FormChangeCtx, useReportedChange, useOptionalFormContext, FormCtx } from './chunk-XVB55M3N.js';
23
25
  export { useFormContext } from './chunk-XVB55M3N.js';
24
26
  import { CardSurfaceCtx, useScrollsInside, SplitPaneCtx, RowsCtx, PageActionsCtx, SurfaceBoundary, useFramesItself, TableCardCtx } from './chunk-QM4SJKWV.js';
27
+ import { useRevealFocus } from './chunk-HTXP5BMM.js';
28
+ export { useRevealFocus } from './chunk-HTXP5BMM.js';
25
29
  import { FOCUSABLE, usePopupFocus, FIELD, ZOOM_KEYS, useOverlayLayer, useFocusTrap, useFocusBeforeOpen, rememberFocus, focusInitial, OVERLAY_CLOSE_ATTR, rovingTabStop, useGridKeyboard, focusAfterRemoval, useNonModalDialog, useReturnFocus } from './chunk-ZI3OQDET.js';
26
30
  export { useGridKeyboard } from './chunk-ZI3OQDET.js';
27
- import { useTextOverflow, Tooltip } from './chunk-MD2EFMES.js';
28
- export { Tooltip, useTextOverflow } from './chunk-MD2EFMES.js';
31
+ import { useTextOverflow, Tooltip } from './chunk-GXMTS3YD.js';
32
+ export { Tooltip, useTextOverflow } from './chunk-GXMTS3YD.js';
29
33
  import { mergeRefs, Slot } from './chunk-7Q46JXSK.js';
30
34
  import { Icon, slotIcon, warnOnce } from './chunk-TJEV7YAY.js';
31
35
  import { usePosition } from './chunk-HP7WUZPK.js';
32
36
  import { useLatest } from './chunk-WH2FUFAC.js';
33
- import { cn, GLASS_SURFACE, GLASS_BACKDROP, GLASS_DROPDOWN, lockBodyScroll, unlockBodyScroll, OVERLAY_SURFACE, GLASS_OVERLAY, ERROR_HAS_FOCUS_RING, HAS_FOCUS_RING, ACTIVE_RING, ERROR_ACTIVE_RING, ERROR_FOCUS_RING, FOCUS_RING, FOCUS_WITHIN_RING } from './chunk-M2QRNBDQ.js';
34
- import { createContext, forwardRef, useState, useRef, useCallback, useLayoutEffect, useMemo, useContext, isValidElement, useId, memo, useEffect, useImperativeHandle, Children, Fragment as Fragment$1, cloneElement, useSyncExternalStore } from 'react';
37
+ import { cn, FOCUS_RING, GLASS_SURFACE, FOCUS_INSET, PEER_FOCUS_RING, GLASS_BACKDROP, GLASS_DROPDOWN, lockBodyScroll, unlockBodyScroll, OVERLAY_SURFACE, GLASS_OVERLAY, ERROR_HAS_FOCUS_RING, FIELD_HAS_FOCUS_RING, GROUP_FOCUS_RING, ERROR_ACTIVE_RING, ACTIVE_RING, ERROR_FOCUS_WITHIN_RING, FIELD_FOCUS_WITHIN_RING, ERROR_FOCUS_RING, FIELD_FOCUS_RING } from './chunk-66JJCQU3.js';
38
+ import { createContext, forwardRef, useState, useRef, useCallback, useLayoutEffect, useMemo, useContext, isValidElement, useId, memo, useImperativeHandle, useEffect, Children, Fragment as Fragment$1, cloneElement, useSyncExternalStore } from 'react';
35
39
  import { createPortal, flushSync } from 'react-dom';
36
40
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
37
41
 
@@ -114,7 +118,8 @@ function DropdownMenu({ trigger, items, align = "end", className, container }) {
114
118
  "data-gs": "menu",
115
119
  onKeyDown: handleMenuKeyDown,
116
120
  className: cn(
117
- "fixed z-[var(--ds-z-popover)] min-w-[180px] p-ds-1",
121
+ // the items' outline has its 4 px of room at any density (Sprint 30, P3)
122
+ "fixed z-[var(--ds-z-popover)] min-w-[180px] p-[max(var(--ds-space-1),4px)]",
118
123
  "bg-[var(--ds-bg-surface-elevated)]",
119
124
  GLASS_DROPDOWN,
120
125
  "border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]",
@@ -145,8 +150,8 @@ function DropdownMenu({ trigger, items, align = "end", className, container }) {
145
150
  className: cn(
146
151
  "flex items-center gap-ds-2 w-full text-left px-ds-3 py-ds-2 text-sm cursor-pointer",
147
152
  "transition-colors rounded-[var(--ds-radius-sm)]",
148
- "focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
149
- item.disabled ? "opacity-disabled cursor-not-allowed" : item.variant === "destructive" ? "text-[var(--ds-status-error)] hover:bg-[var(--ds-status-error-bg)] focus-visible:bg-[var(--ds-status-error-bg)]" : "text-[var(--ds-text-primary)] hover:bg-[var(--ds-bg-emphasis)] focus-visible:bg-[var(--ds-bg-emphasis)]"
153
+ FOCUS_RING,
154
+ item.disabled ? "opacity-disabled cursor-not-allowed" : item.variant === "destructive" ? "text-[var(--ds-status-error-text)] hover:bg-[var(--ds-status-error-bg)] focus-visible:bg-[var(--ds-status-error-bg)]" : "text-[var(--ds-text-primary)] hover:bg-[var(--ds-bg-emphasis)] focus-visible:bg-[var(--ds-bg-emphasis)]"
150
155
  ),
151
156
  children: [
152
157
  item.icon && /* @__PURE__ */ jsx(Icon, { name: item.icon, size: 16, className: "shrink-0" }),
@@ -176,7 +181,7 @@ function BulkActionBar({ selectedCount, actions, onClearSelection, className })
176
181
  {
177
182
  className: cn(
178
183
  "flex items-center gap-ds-3 rounded-[var(--ds-radius-md)]",
179
- "bg-[var(--ds-bg-surface-elevated)] border-[length:var(--ds-border-width)] border-[var(--ds-accent-primary)]",
184
+ "bg-[var(--ds-bg-surface-elevated)] border-[length:var(--ds-border-width)] border-[var(--ds-accent-ink)]",
180
185
  "shadow-[var(--ds-shadow-dropdown),var(--ds-glass-inset)]",
181
186
  "[backdrop-filter:var(--ds-glass-filter)] [-webkit-backdrop-filter:var(--ds-glass-filter)]",
182
187
  className
@@ -185,7 +190,7 @@ function BulkActionBar({ selectedCount, actions, onClearSelection, className })
185
190
  role: "toolbar",
186
191
  "aria-label": `${selectedCount} items selected`,
187
192
  children: [
188
- /* @__PURE__ */ jsxs("span", { className: "text-sm font-medium text-[var(--ds-accent-primary)] tabular-nums whitespace-nowrap", children: [
193
+ /* @__PURE__ */ jsxs("span", { className: "text-sm font-medium text-[var(--ds-accent-ink)] tabular-nums whitespace-nowrap", children: [
189
194
  selectedCount,
190
195
  " selected"
191
196
  ] }),
@@ -213,7 +218,7 @@ function BulkActionBar({ selectedCount, actions, onClearSelection, className })
213
218
  {
214
219
  type: "button",
215
220
  onClick: onClearSelection,
216
- className: "ml-auto text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] transition-colors cursor-pointer",
221
+ className: cn("ml-auto text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] transition-colors cursor-pointer", FOCUS_RING),
217
222
  "aria-label": "Clear selection",
218
223
  children: /* @__PURE__ */ jsx(Icon, { name: "close", size: 16 })
219
224
  }
@@ -234,6 +239,7 @@ var TEXT_SIZE = {
234
239
  };
235
240
  function Combobox({ value, onChange: onChangeProp, options, placeholder = "Search\u2026", disabled, loading = false, className, ref, container, error = false, size: sizeProp, "aria-label": ariaLabel, ...wiring }) {
236
241
  const onChange = useReportedChange(onChangeProp, value);
242
+ useInputModality();
237
243
  const contextSize = useContext(ControlSizeContext);
238
244
  const control = useFieldControl({ ...wiring, error: error || void 0 });
239
245
  const size = sizeProp ?? contextSize ?? "md";
@@ -352,7 +358,7 @@ function Combobox({ value, onChange: onChangeProp, options, placeholder = "Searc
352
358
  "shadow-[var(--ds-input-shadow)]",
353
359
  "transition-colors duration-[var(--ds-transition-speed)]",
354
360
  !control.invalid && !disabled && "hover:border-[var(--ds-input-border-hover)]",
355
- control.invalid ? ERROR_HAS_FOCUS_RING : HAS_FOCUS_RING,
361
+ control.invalid ? ERROR_HAS_FOCUS_RING : FIELD_HAS_FOCUS_RING,
356
362
  disabled && "opacity-disabled pointer-events-none"
357
363
  ),
358
364
  children: [
@@ -405,7 +411,7 @@ function Combobox({ value, onChange: onChangeProp, options, placeholder = "Searc
405
411
  onChange("");
406
412
  setQuery("");
407
413
  },
408
- className: "mr-ds-2 text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] cursor-pointer",
414
+ className: cn("mr-ds-2 rounded-[var(--ds-radius-sm)] text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] cursor-pointer", FOCUS_RING),
409
415
  tabIndex: -1,
410
416
  "aria-label": "Clear",
411
417
  children: /* @__PURE__ */ jsx(Icon, { name: "close", size: 14 })
@@ -449,7 +455,7 @@ function Combobox({ value, onChange: onChangeProp, options, placeholder = "Searc
449
455
  ),
450
456
  children: [
451
457
  /* @__PURE__ */ jsx("span", { className: "flex-1", children: opt.label }),
452
- opt.value === value && /* @__PURE__ */ jsx(Icon, { name: "check", size: 14, className: "text-[var(--ds-accent-primary)]" })
458
+ opt.value === value && /* @__PURE__ */ jsx(Icon, { name: "check", size: 14, className: "text-[var(--ds-accent-ink)]" })
453
459
  ]
454
460
  },
455
461
  opt.value
@@ -620,7 +626,7 @@ function RelativeTimeAt({ at, hours, className }) {
620
626
  dateTime: new Date(at).toISOString(),
621
627
  "data-relative-time": "",
622
628
  suppressHydrationWarning: true,
623
- className: cn("rounded-[var(--ds-radius-sm)] focus-visible:outline-2 focus-visible:outline-[var(--ds-accent-primary)] focus-visible:outline-offset-2", className),
629
+ className: cn("rounded-[var(--ds-radius-sm)]", FOCUS_RING, className),
624
630
  children: [
625
631
  formatRelativeTime(at, { thresholdHours: hours, now, locale }),
626
632
  /* @__PURE__ */ jsx("span", { className: "sr-only", suppressHydrationWarning: true, children: `, ${full}` })
@@ -686,7 +692,7 @@ function Checkbox({ checked, onChange: onChangeProp, label, size = "md", disable
686
692
  "rounded-[calc(var(--ds-radius-sm)*0.6)]",
687
693
  "border-[2px]",
688
694
  "transition-all",
689
- "peer-focus-visible:shadow-[var(--ds-shadow-focus)]",
695
+ PEER_FOCUS_RING,
690
696
  filled ? cn(CHECK_FILL, "border-[var(--ds-check-border)]") : "bg-[var(--ds-input-bg)] border-[var(--ds-input-border)]",
691
697
  disabled && "pointer-events-none"
692
698
  ),
@@ -715,10 +721,10 @@ var CheckboxGroupContext = createContext(null);
715
721
  function CheckboxGroup({ value, onChange, children, className }) {
716
722
  return /* @__PURE__ */ jsx(CheckboxGroupContext, { value: { value, onChange }, children: /* @__PURE__ */ jsx("div", { role: "group", className: cn("flex flex-col gap-ds-2", className), children }) });
717
723
  }
718
- function CheckboxGroupItem({ value, label, disabled, groupValue, onGroupChange }) {
724
+ function CheckboxGroupItem({ value, label, disabled }) {
719
725
  const ctx = useContext(CheckboxGroupContext);
720
- const resolvedValue = ctx?.value ?? groupValue ?? [];
721
- const resolvedOnChange = ctx?.onChange ?? onGroupChange;
726
+ const resolvedValue = ctx?.value ?? [];
727
+ const resolvedOnChange = ctx?.onChange;
722
728
  const checked = resolvedValue.includes(value);
723
729
  return /* @__PURE__ */ jsx(
724
730
  Checkbox,
@@ -808,7 +814,8 @@ function RadioGroup({ value, onChange: onChangeProp, options, orientation = "ver
808
814
  "bg-[var(--ds-input-bg)]",
809
815
  "transition-colors",
810
816
  selected && "border-[var(--ds-check-border)]",
811
- "group-focus-visible:shadow-[var(--ds-shadow-focus)]"
817
+ // keyboard focus is drawn on the radio, not round its label: the button draws none of its own
818
+ GROUP_FOCUS_RING
812
819
  ),
813
820
  children: selected && // Sprint 25.14 A20: the checked colour, as a checkbox's fill (a preset whose accent falls short of 3:1 sets it)
814
821
  /* @__PURE__ */ jsx("span", { className: cn("h-2.5 w-2.5 rounded-[var(--ds-radius-full)]", CHECK_FILL) })
@@ -1320,6 +1327,7 @@ function DatePicker({ value, onChange: onChangeProp, placeholder = "Pick a date"
1320
1327
  const gridRef = useRef(null);
1321
1328
  const generatedId = useId();
1322
1329
  const control = useFieldControl({ ...wiring, id, error: error || void 0 }, { requiredInDescription: true });
1330
+ useInputModality();
1323
1331
  const inputId = control.id ?? generatedId;
1324
1332
  const pos = usePosition(triggerRef, panelRef, open, { side: "bottom", align: "start", offset: 4, flip: true });
1325
1333
  const year = viewDate.getFullYear();
@@ -1535,8 +1543,10 @@ function DatePicker({ value, onChange: onChangeProp, placeholder = "Pick a date"
1535
1543
  "shadow-[var(--ds-input-shadow)]",
1536
1544
  "transition-colors",
1537
1545
  "px-ds-3 py-ds-2",
1538
- !control.invalid && !disabled && !open && "hover:border-[var(--ds-input-border-hover)] focus-within:border-[var(--ds-input-border-hover)]",
1539
- open && ACTIVE_RING,
1546
+ !control.invalid && !disabled && !open && "hover:border-[var(--ds-input-border-hover)]",
1547
+ open && (control.invalid || typedInvalid ? ERROR_ACTIVE_RING : ACTIVE_RING),
1548
+ // the segments mark which part has focus (their tint); the field draws the focus (a hover keeps its border)
1549
+ control.invalid || typedInvalid ? ERROR_FOCUS_WITHIN_RING : FIELD_FOCUS_WITHIN_RING,
1540
1550
  disabled && "opacity-disabled cursor-not-allowed",
1541
1551
  "text-[var(--ds-text-primary)]"
1542
1552
  ),
@@ -1562,7 +1572,7 @@ function DatePicker({ value, onChange: onChangeProp, placeholder = "Pick a date"
1562
1572
  "aria-valuetext": drawn[k] === null ? "empty" : String(drawn[k]),
1563
1573
  onKeyDown: (e) => onSegmentKeyDown(e, i, spec),
1564
1574
  onClick: (e) => e.stopPropagation(),
1565
- className: cn("rounded-[var(--ds-radius-sm)] px-[2px] outline-none focus:bg-[var(--ds-accent-subtle)] focus:text-[var(--ds-accent-primary)] cursor-text", drawn[k] === null && !buffers[k] && "text-[var(--ds-text-muted)]"),
1575
+ className: cn("rounded-[var(--ds-radius-sm)] px-[2px] outline-none focus:bg-[var(--ds-accent-subtle)] focus:text-[var(--ds-accent-ink)] cursor-text", drawn[k] === null && !buffers[k] && "text-[var(--ds-text-muted)]"),
1566
1576
  children: shown(spec)
1567
1577
  }
1568
1578
  )
@@ -1578,7 +1588,7 @@ function DatePicker({ value, onChange: onChangeProp, placeholder = "Pick a date"
1578
1588
  "aria-expanded": open,
1579
1589
  onClick: () => !disabled && setOpen(!open),
1580
1590
  disabled,
1581
- className: "shrink-0 -mr-ds-1 rounded-[var(--ds-radius-sm)] text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] focus-visible:outline-2 focus-visible:outline-[var(--ds-accent-primary)] disabled:cursor-not-allowed",
1591
+ className: cn("shrink-0 -mr-ds-1 rounded-[var(--ds-radius-sm)] text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] disabled:cursor-not-allowed", FOCUS_RING),
1582
1592
  children: /* @__PURE__ */ jsx(Icon, { name: "chevron-down", size: 14 })
1583
1593
  }
1584
1594
  )
@@ -1622,11 +1632,11 @@ function DatePicker({ value, onChange: onChangeProp, placeholder = "Pick a date"
1622
1632
  role: "grid",
1623
1633
  "aria-label": formatMonthYear(viewDate),
1624
1634
  onKeyDown: grid.onKeyDown,
1625
- className: "flex flex-col gap-ds-0.5 tabular-nums",
1635
+ className: "flex flex-col gap-[4px] tabular-nums",
1626
1636
  style: { padding: "var(--ds-space-2) var(--ds-space-3)" },
1627
1637
  children: [
1628
- /* @__PURE__ */ jsx("div", { role: "row", className: "grid grid-cols-7 gap-ds-0.5 mb-ds-0.5", children: weekdayNames(weekStartsOn, "narrow").map((d, i) => /* @__PURE__ */ jsx("div", { role: "columnheader", "aria-label": weekdayNames(weekStartsOn, "long")[i], className: "text-center text-2xs font-medium text-[var(--ds-text-muted)] py-ds-1", children: d }, i)) }),
1629
- weeks.map((week, w) => /* @__PURE__ */ jsx("div", { role: "row", className: "grid grid-cols-7 gap-ds-0.5", onMouseLeave: () => setHover(null), children: week.map((day, i) => {
1638
+ /* @__PURE__ */ jsx("div", { role: "row", className: "grid grid-cols-7 gap-[4px] mb-ds-0.5", children: weekdayNames(weekStartsOn, "narrow").map((d, i) => /* @__PURE__ */ jsx("div", { role: "columnheader", "aria-label": weekdayNames(weekStartsOn, "long")[i], className: "text-center text-2xs font-medium text-[var(--ds-text-muted)] py-ds-1", children: d }, i)) }),
1639
+ weeks.map((week, w) => /* @__PURE__ */ jsx("div", { role: "row", className: "grid grid-cols-7 gap-[4px]", onMouseLeave: () => setHover(null), children: week.map((day, i) => {
1630
1640
  if (day === null) return /* @__PURE__ */ jsx("div", { role: "gridcell" }, `empty-${i}`);
1631
1641
  const dateObj = new Date(year, month, day);
1632
1642
  const isSelected = !!value && isSameDay2(dateObj, value);
@@ -1653,8 +1663,8 @@ function DatePicker({ value, onChange: onChangeProp, placeholder = "Pick a date"
1653
1663
  className: cn(
1654
1664
  "w-full aspect-square flex items-center justify-center text-xs",
1655
1665
  "transition-colors cursor-pointer",
1656
- "focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
1657
- isSelected ? "bg-[var(--ds-accent-primary)] text-[var(--ds-text-on-primary)] font-bold rounded-[var(--ds-radius-sm)]" : isOtherEnd ? "bg-[var(--ds-accent-muted)] text-[var(--ds-accent-subtle-text)] font-semibold rounded-[var(--ds-radius-sm)]" : between ? "bg-[var(--ds-accent-subtle)] text-[var(--ds-accent-subtle-text)] rounded-none" : isToday ? "border-[length:var(--ds-border-width)] border-[var(--ds-accent-primary)] text-[var(--ds-accent-primary)] font-medium rounded-[var(--ds-radius-sm)]" : "text-[var(--ds-text-secondary)] hover:bg-[var(--ds-bg-emphasis)] rounded-[var(--ds-radius-sm)]",
1666
+ FOCUS_RING,
1667
+ isSelected ? "bg-[var(--ds-accent-primary)] text-[var(--ds-text-on-primary)] font-bold rounded-[var(--ds-radius-sm)]" : isOtherEnd ? "bg-[var(--ds-accent-muted)] text-[var(--ds-accent-subtle-text)] font-semibold rounded-[var(--ds-radius-sm)]" : between ? "bg-[var(--ds-accent-subtle)] text-[var(--ds-accent-subtle-text)] rounded-none" : isToday ? "border-[length:var(--ds-border-width)] border-[var(--ds-accent-ink)] text-[var(--ds-accent-ink)] font-medium rounded-[var(--ds-radius-sm)]" : "text-[var(--ds-text-secondary)] hover:bg-[var(--ds-bg-emphasis)] rounded-[var(--ds-radius-sm)]",
1658
1668
  dis && "opacity-disabled cursor-not-allowed hover:bg-transparent"
1659
1669
  ),
1660
1670
  children: day
@@ -1769,6 +1779,7 @@ function DateRangePicker({
1769
1779
  const panelRef = useRef(null);
1770
1780
  const generatedId = useId();
1771
1781
  const control = useFieldControl({ ...wiring, id, error: error || void 0 }, { requiredInDescription: true });
1782
+ useInputModality();
1772
1783
  const triggerId = control.id ?? generatedId;
1773
1784
  const labelledBy = control.labelId ? `${control.labelId} ${triggerId}` : void 0;
1774
1785
  const pos = usePosition(triggerRef, panelRef, open, { side: "bottom", align: "start", offset: 4, flip: true });
@@ -1881,7 +1892,7 @@ function DateRangePicker({
1881
1892
  "px-ds-3 py-ds-2",
1882
1893
  !control.invalid && !disabled && !open && "hover:border-[var(--ds-input-border-hover)]",
1883
1894
  open && (control.invalid ? ERROR_ACTIVE_RING : ACTIVE_RING),
1884
- control.invalid ? ERROR_FOCUS_RING : FOCUS_RING,
1895
+ control.invalid ? ERROR_FOCUS_RING : FIELD_FOCUS_RING,
1885
1896
  disabled && "opacity-disabled cursor-not-allowed",
1886
1897
  summary ? "text-[var(--ds-text-primary)]" : "text-[var(--ds-text-muted)]"
1887
1898
  ),
@@ -1922,9 +1933,9 @@ function DateRangePicker({
1922
1933
  /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-[var(--ds-text-primary)]", children: formatMonthRange(months[0], months[1]) }),
1923
1934
  /* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "icon-sm", onClick: () => pageMonths(1), "aria-label": "Next month", children: /* @__PURE__ */ jsx(Icon, { name: "chevron-right", size: 14 }) })
1924
1935
  ] }),
1925
- /* @__PURE__ */ jsx("div", { ref: gridRef, onKeyDown: grid.onKeyDown, className: "flex gap-ds-4 px-ds-3 py-ds-2", onMouseLeave: () => setHover(null), children: months.map((m) => /* @__PURE__ */ jsxs("div", { role: "grid", "aria-label": formatMonthYear(m), className: "w-[224px] flex flex-col gap-ds-0.5", children: [
1926
- /* @__PURE__ */ jsx("div", { role: "row", className: "grid grid-cols-7 gap-ds-0.5 mb-ds-0.5", children: dayNames.map((d, i) => /* @__PURE__ */ jsx("div", { role: "columnheader", "aria-label": dayNamesLong[i], className: "text-center text-2xs font-medium text-[var(--ds-text-muted)] py-ds-1", children: d }, i)) }),
1927
- getMonthGrid(m.getFullYear(), m.getMonth(), weekStartsOn).map((week, w) => /* @__PURE__ */ jsx("div", { role: "row", className: "grid grid-cols-7 gap-ds-0.5", children: week.map((d) => {
1936
+ /* @__PURE__ */ jsx("div", { ref: gridRef, onKeyDown: grid.onKeyDown, className: "flex gap-ds-4 px-ds-3 py-ds-2", onMouseLeave: () => setHover(null), children: months.map((m) => /* @__PURE__ */ jsxs("div", { role: "grid", "aria-label": formatMonthYear(m), className: "w-[224px] flex flex-col gap-[4px]", children: [
1937
+ /* @__PURE__ */ jsx("div", { role: "row", className: "grid grid-cols-7 gap-[4px] mb-ds-0.5", children: dayNames.map((d, i) => /* @__PURE__ */ jsx("div", { role: "columnheader", "aria-label": dayNamesLong[i], className: "text-center text-2xs font-medium text-[var(--ds-text-muted)] py-ds-1", children: d }, i)) }),
1938
+ getMonthGrid(m.getFullYear(), m.getMonth(), weekStartsOn).map((week, w) => /* @__PURE__ */ jsx("div", { role: "row", className: "grid grid-cols-7 gap-[4px]", children: week.map((d) => {
1928
1939
  if (!isSameMonth(d, m)) return /* @__PURE__ */ jsx("div", { role: "gridcell" }, d.toISOString());
1929
1940
  const isStart = !!rangeStart && isSameDay(d, rangeStart);
1930
1941
  const isEnd = !!rangeEnd2 && isSameDay(d, rangeEnd2);
@@ -1949,8 +1960,8 @@ function DateRangePicker({
1949
1960
  className: cn(
1950
1961
  "w-full aspect-square flex items-center justify-center text-xs",
1951
1962
  "transition-colors cursor-pointer",
1952
- "focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
1953
- isStart || isEnd ? "bg-[var(--ds-accent-primary)] text-[var(--ds-text-on-primary)] font-bold rounded-[var(--ds-radius-sm)]" : between ? "bg-[var(--ds-accent-subtle)] text-[var(--ds-accent-subtle-text)] rounded-none" : today !== null && isSameDay(d, today) ? "border-[length:var(--ds-border-width)] border-[var(--ds-accent-primary)] text-[var(--ds-accent-primary)] font-medium rounded-[var(--ds-radius-sm)]" : "text-[var(--ds-text-secondary)] hover:bg-[var(--ds-bg-emphasis)] rounded-[var(--ds-radius-sm)]",
1963
+ FOCUS_RING,
1964
+ isStart || isEnd ? "bg-[var(--ds-accent-primary)] text-[var(--ds-text-on-primary)] font-bold rounded-[var(--ds-radius-sm)]" : between ? "bg-[var(--ds-accent-subtle)] text-[var(--ds-accent-subtle-text)] rounded-none" : today !== null && isSameDay(d, today) ? "border-[length:var(--ds-border-width)] border-[var(--ds-accent-ink)] text-[var(--ds-accent-ink)] font-medium rounded-[var(--ds-radius-sm)]" : "text-[var(--ds-text-secondary)] hover:bg-[var(--ds-bg-emphasis)] rounded-[var(--ds-radius-sm)]",
1954
1965
  dis && "opacity-disabled cursor-not-allowed hover:bg-transparent"
1955
1966
  ),
1956
1967
  children: d.getDate()
@@ -2641,8 +2652,8 @@ function RecurrencePicker({ value, onChange: onChangeProp, start, label, weekSta
2641
2652
  onClick: () => edit({ weekdays: (on ? (custom.weekdays ?? []).filter((x) => x !== d) : [...custom.weekdays ?? [], d]).sort((a, b) => a - b) }),
2642
2653
  className: cn(
2643
2654
  "inline-flex h-8 min-w-8 items-center justify-center px-ds-2 rounded-[var(--ds-radius-full)] text-xs font-medium",
2644
- "border-[length:var(--ds-border-width)] cursor-pointer select-none outline-none transition-colors",
2645
- "focus-visible:shadow-[var(--ds-shadow-focus)]",
2655
+ "border-[length:var(--ds-border-width)] cursor-pointer select-none transition-colors",
2656
+ FOCUS_RING,
2646
2657
  // chosen: the accent's readable pair, so its text reads 4.5:1 in every theme (the house's one way
2647
2658
  // to colour text on a colour, as the Calendar's accent events), and the checked border at 3:1
2648
2659
  // marking the state; the tick colour on the checked fill read 3.2:1 in three themes
@@ -2875,7 +2886,7 @@ function Dialog({ open, onClose: onCloseProp, title, description, children, foot
2875
2886
  type: "button",
2876
2887
  onClick: onClose,
2877
2888
  ...{ [OVERLAY_CLOSE_ATTR]: "" },
2878
- className: "shrink-0 text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] transition-colors cursor-pointer",
2889
+ className: cn("shrink-0 text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] transition-colors cursor-pointer", FOCUS_RING),
2879
2890
  "aria-label": "Close",
2880
2891
  children: /* @__PURE__ */ jsx(Icon, { name: "close", size: 18 })
2881
2892
  }
@@ -3114,6 +3125,7 @@ function FileUpload({ onFiles, files, upload, onCancel, onRetry, onRemove, accep
3114
3125
  const uploadRef = useLatest(upload);
3115
3126
  const overlayMark = useContext(OverlayMarkCtx);
3116
3127
  const reportChange = useContext(FormChangeCtx);
3128
+ useInputModality();
3117
3129
  const field = useField();
3118
3130
  const ownId = useId();
3119
3131
  const inputId = id ?? `${ownId}-input`;
@@ -3309,7 +3321,7 @@ function FileUpload({ onFiles, files, upload, onCancel, onRetry, onRemove, accep
3309
3321
  "transition-colors",
3310
3322
  // The real file input is visually hidden inside; Tab lands on it and
3311
3323
  // Enter/Space open the picker natively, so the zone shows its focus.
3312
- invalid ? ERROR_HAS_FOCUS_RING : HAS_FOCUS_RING,
3324
+ invalid ? ERROR_HAS_FOCUS_RING : FIELD_HAS_FOCUS_RING,
3313
3325
  dragOver ? `${ACTIVE_RING} bg-[var(--ds-accent-whisper)]` : invalid ? "border-[var(--ds-status-error)]" : "border-[var(--ds-input-border)] hover:border-[var(--ds-accent-primary)] hover:bg-[var(--ds-accent-whisper)]"
3314
3326
  ),
3315
3327
  style: { padding: "var(--ds-space-8) var(--ds-space-4)" },
@@ -3317,7 +3329,7 @@ function FileUpload({ onFiles, files, upload, onCancel, onRetry, onRemove, accep
3317
3329
  /* @__PURE__ */ jsx("div", { className: cn(
3318
3330
  "flex items-center justify-center w-10 h-10 rounded-[var(--ds-radius-full)] transition-colors",
3319
3331
  "bg-[var(--ds-bg-muted)] group-hover:bg-[var(--ds-accent-subtle)]"
3320
- ), children: /* @__PURE__ */ jsx(Icon, { name: "plus", size: 20, className: "text-[var(--ds-text-muted)] group-hover:text-[var(--ds-accent-primary)] transition-colors" }) }),
3332
+ ), children: /* @__PURE__ */ jsx(Icon, { name: "plus", size: 20, className: "text-[var(--ds-text-muted)] group-hover:text-[var(--ds-accent-subtle-text)] transition-colors" }) }),
3321
3333
  /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
3322
3334
  /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-[var(--ds-text-primary)]", children: multiple ? "Drop files here or browse" : "Drop a file here or browse" }),
3323
3335
  constraints && /* @__PURE__ */ jsx("p", { id: constraintsId, className: "text-xs text-[var(--ds-text-muted)] mt-ds-1", children: constraints })
@@ -3370,7 +3382,7 @@ function FileUpload({ onFiles, files, upload, onCancel, onRetry, onRemove, accep
3370
3382
  /* @__PURE__ */ jsx(TruncFileName, { className: "text-[var(--ds-text-primary)]", children: item.name }),
3371
3383
  (item.size != null || words) && /* @__PURE__ */ jsx("p", { className: "text-xs text-[var(--ds-text-muted)]", children: [item.size != null ? formatSize(item.size) : null, words].filter(Boolean).join(" \xB7 ") }),
3372
3384
  item.status === "uploading" && /* @__PURE__ */ jsx(Progress, { value: progress, size: "sm", label: `Uploading ${item.name}`, className: "mt-ds-1" }),
3373
- item.status === "error" && /* @__PURE__ */ jsx("p", { className: "mt-ds-1 text-xs text-[var(--ds-status-error)]", children: item.error ?? "The upload didn't work." })
3385
+ item.status === "error" && /* @__PURE__ */ jsx("p", { className: "mt-ds-1 text-xs text-[var(--ds-status-error-text)]", children: item.error ?? "The upload didn't work." })
3374
3386
  ] }),
3375
3387
  item.status === "done" && /* @__PURE__ */ jsx(Icon, { name: "check", size: 16, className: "text-[var(--ds-status-success)] shrink-0", "aria-hidden": "true" }),
3376
3388
  running(item) && canCancel && // the visible word starts the name, which says which file (WCAG 2.5.3)
@@ -3511,7 +3523,7 @@ function SliderRange({
3511
3523
  error ? "border-[var(--ds-status-error)]" : "border-[var(--ds-check-border)]",
3512
3524
  "shadow-[var(--ds-shadow-sm)]",
3513
3525
  "transition-[shadow,transform] duration-200 ease-out",
3514
- "focus-visible:shadow-[var(--ds-shadow-focus)]",
3526
+ FOCUS_RING,
3515
3527
  !disabled && "cursor-grab active:cursor-grabbing hover:scale-125 active:scale-150"
3516
3528
  ),
3517
3529
  style: { left: `${pct(low)}%` }
@@ -3537,7 +3549,7 @@ function SliderRange({
3537
3549
  error ? "border-[var(--ds-status-error)]" : "border-[var(--ds-check-border)]",
3538
3550
  "shadow-[var(--ds-shadow-sm)]",
3539
3551
  "transition-[shadow,transform] duration-200 ease-out",
3540
- "focus-visible:shadow-[var(--ds-shadow-focus)]",
3552
+ FOCUS_RING,
3541
3553
  !disabled && "cursor-grab active:cursor-grabbing hover:scale-125 active:scale-150"
3542
3554
  ),
3543
3555
  style: { left: `${pct(high)}%` }
@@ -3623,11 +3635,14 @@ function TimePicker({
3623
3635
  const onChange = useReportedChange(onChangeProp, value);
3624
3636
  const contextSize = useContext(ControlSizeContext);
3625
3637
  const control = useFieldControl({ ...wiring, id, error: error || void 0 }, { requiredInDescription: true });
3638
+ useInputModality();
3626
3639
  const size = sizeProp ?? contextSize ?? "md";
3627
3640
  const [open, setOpen] = useState(false);
3628
3641
  const triggerRef = useRef(null);
3629
3642
  const buttonRef = useRef(null);
3630
3643
  const panelRef = useRef(null);
3644
+ const [columns, setColumns] = useState(null);
3645
+ useRevealFocus(columns);
3631
3646
  const listboxId = useId();
3632
3647
  const pos = usePosition(triggerRef, panelRef, open, { side: "bottom", align: "start", offset: 4, flip: true });
3633
3648
  const parsed = parseTime(value);
@@ -3662,9 +3677,9 @@ function TimePicker({
3662
3677
  if (e.key === "ArrowDown") next = current.nextElementSibling;
3663
3678
  else if (e.key === "ArrowUp") next = current.previousElementSibling;
3664
3679
  else if (e.key === "ArrowRight" || e.key === "ArrowLeft") {
3665
- const columns = Array.from(panelRef.current?.querySelectorAll("[data-column]") ?? []);
3666
- const idx = columns.indexOf(column);
3667
- const target = columns[idx + (e.key === "ArrowRight" ? 1 : -1)];
3680
+ const columns2 = Array.from(panelRef.current?.querySelectorAll("[data-column]") ?? []);
3681
+ const idx = columns2.indexOf(column);
3682
+ const target = columns2[idx + (e.key === "ArrowRight" ? 1 : -1)];
3668
3683
  next = target?.querySelector('[data-selected="true"]') ?? target?.querySelector("button") ?? null;
3669
3684
  } else return;
3670
3685
  if (next instanceof HTMLElement) {
@@ -3835,8 +3850,10 @@ function TimePicker({
3835
3850
  "shadow-[var(--ds-input-shadow)]",
3836
3851
  "transition-colors",
3837
3852
  "px-ds-3 py-ds-2",
3838
- !control.invalid && !disabled && !open && "hover:border-[var(--ds-input-border-hover)] focus-within:border-[var(--ds-input-border-hover)]",
3839
- open && ACTIVE_RING,
3853
+ !control.invalid && !disabled && !open && "hover:border-[var(--ds-input-border-hover)]",
3854
+ open && (control.invalid ? ERROR_ACTIVE_RING : ACTIVE_RING),
3855
+ // the segments mark which part has focus (their tint); the field draws the focus (a hover keeps its border)
3856
+ control.invalid ? ERROR_FOCUS_WITHIN_RING : FIELD_FOCUS_WITHIN_RING,
3840
3857
  disabled && "opacity-disabled cursor-not-allowed",
3841
3858
  "text-[var(--ds-text-primary)]"
3842
3859
  ),
@@ -3863,7 +3880,7 @@ function TimePicker({
3863
3880
  "aria-valuetext": segs[k] === null ? "empty" : pad2(segs[k]),
3864
3881
  onKeyDown: (e) => onSegmentKeyDown(e, i, spec),
3865
3882
  onClick: (e) => e.stopPropagation(),
3866
- className: cn("rounded-[var(--ds-radius-sm)] px-[2px] outline-none focus:bg-[var(--ds-accent-subtle)] focus:text-[var(--ds-accent-primary)] cursor-text", segs[k] === null && !buffers[k] && "text-[var(--ds-text-muted)]"),
3883
+ className: cn("rounded-[var(--ds-radius-sm)] px-[2px] outline-none focus:bg-[var(--ds-accent-subtle)] focus:text-[var(--ds-accent-ink)] cursor-text", segs[k] === null && !buffers[k] && "text-[var(--ds-text-muted)]"),
3867
3884
  children: shown(k, spec)
3868
3885
  }
3869
3886
  )
@@ -3885,7 +3902,7 @@ function TimePicker({
3885
3902
  "aria-valuetext": segs.period ?? "empty",
3886
3903
  onKeyDown: (e) => onSegmentKeyDown(e, specs.length, null),
3887
3904
  onClick: (e) => e.stopPropagation(),
3888
- className: cn("ml-ds-1 rounded-[var(--ds-radius-sm)] px-[2px] outline-none focus:bg-[var(--ds-accent-subtle)] focus:text-[var(--ds-accent-primary)] cursor-text", segs.period === null && "text-[var(--ds-text-muted)]"),
3905
+ className: cn("ml-ds-1 rounded-[var(--ds-radius-sm)] px-[2px] outline-none focus:bg-[var(--ds-accent-subtle)] focus:text-[var(--ds-accent-ink)] cursor-text", segs.period === null && "text-[var(--ds-text-muted)]"),
3889
3906
  children: segs.period ?? "--"
3890
3907
  }
3891
3908
  )
@@ -3901,7 +3918,7 @@ function TimePicker({
3901
3918
  "aria-controls": open ? listboxId : void 0,
3902
3919
  onClick: () => !disabled && setOpen(!open),
3903
3920
  disabled,
3904
- className: "shrink-0 -mr-ds-1 rounded-[var(--ds-radius-sm)] text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] focus-visible:outline-2 focus-visible:outline-[var(--ds-accent-primary)] disabled:cursor-not-allowed",
3921
+ className: cn("shrink-0 -mr-ds-1 rounded-[var(--ds-radius-sm)] text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] disabled:cursor-not-allowed", FOCUS_RING),
3905
3922
  children: /* @__PURE__ */ jsx(Icon, { name: "chevron-down", size: 14 })
3906
3923
  }
3907
3924
  )
@@ -3926,8 +3943,8 @@ function TimePicker({
3926
3943
  "rounded-[var(--ds-radius-md)]"
3927
3944
  ),
3928
3945
  style: { top: pos.top, left: pos.left },
3929
- children: /* @__PURE__ */ jsxs("div", { className: "inline-flex p-ds-1 gap-ds-1 tabular-nums", children: [
3930
- /* @__PURE__ */ jsx("div", { "data-column": true, className: "max-h-48 overflow-y-auto w-ds-10", children: hours.map((h, i) => /* @__PURE__ */ jsx(
3946
+ children: /* @__PURE__ */ jsxs("div", { ref: setColumns, className: "inline-flex p-ds-1 gap-ds-1 tabular-nums", children: [
3947
+ /* @__PURE__ */ jsx("div", { "data-column": true, className: "flex max-h-48 w-[calc(var(--ds-space-10)+8px)] flex-col gap-[4px] overflow-y-auto p-[4px] scroll-p-[4px]", children: hours.map((h, i) => /* @__PURE__ */ jsx(
3931
3948
  "button",
3932
3949
  {
3933
3950
  type: "button",
@@ -3938,7 +3955,8 @@ function TimePicker({
3938
3955
  onClick: () => emitChange(h, parsed.minute, parsed.period),
3939
3956
  className: cn(
3940
3957
  "w-full text-center text-sm py-ds-1 rounded-[var(--ds-radius-sm)] cursor-pointer",
3941
- "transition-colors focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
3958
+ "transition-colors",
3959
+ FOCUS_RING,
3942
3960
  (use24Hour ? h === parseInt(value) : h === parsed.hour) ? "bg-[var(--ds-accent-primary)] text-[var(--ds-text-on-primary)]" : "text-[var(--ds-text-secondary)] hover:bg-[var(--ds-bg-emphasis)]"
3943
3961
  ),
3944
3962
  children: pad3(h)
@@ -3946,7 +3964,7 @@ function TimePicker({
3946
3964
  h
3947
3965
  )) }),
3948
3966
  /* @__PURE__ */ jsx("div", { className: "w-px bg-[var(--ds-border-subtle)]" }),
3949
- /* @__PURE__ */ jsx("div", { "data-column": true, className: "max-h-48 overflow-y-auto w-ds-10", children: minutes.map((m, i) => /* @__PURE__ */ jsx(
3967
+ /* @__PURE__ */ jsx("div", { "data-column": true, className: "flex max-h-48 w-[calc(var(--ds-space-10)+8px)] flex-col gap-[4px] overflow-y-auto p-[4px] scroll-p-[4px]", children: minutes.map((m, i) => /* @__PURE__ */ jsx(
3950
3968
  "button",
3951
3969
  {
3952
3970
  type: "button",
@@ -3957,7 +3975,8 @@ function TimePicker({
3957
3975
  onClick: () => emitChange(parsed.hour, m, parsed.period),
3958
3976
  className: cn(
3959
3977
  "w-full text-center text-sm py-ds-1 rounded-[var(--ds-radius-sm)] cursor-pointer",
3960
- "transition-colors focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
3978
+ "transition-colors",
3979
+ FOCUS_RING,
3961
3980
  m === parsed.minute ? "bg-[var(--ds-accent-primary)] text-[var(--ds-text-on-primary)]" : "text-[var(--ds-text-secondary)] hover:bg-[var(--ds-bg-emphasis)]"
3962
3981
  ),
3963
3982
  children: pad3(m)
@@ -3966,7 +3985,7 @@ function TimePicker({
3966
3985
  )) }),
3967
3986
  !use24Hour && /* @__PURE__ */ jsxs(Fragment, { children: [
3968
3987
  /* @__PURE__ */ jsx("div", { className: "w-px bg-[var(--ds-border-subtle)]" }),
3969
- /* @__PURE__ */ jsx("div", { "data-column": true, className: "flex flex-col gap-ds-1 w-ds-10", children: ["AM", "PM"].map((p, i) => /* @__PURE__ */ jsx(
3988
+ /* @__PURE__ */ jsx("div", { "data-column": true, className: "flex flex-col gap-[4px] w-ds-10", children: ["AM", "PM"].map((p, i) => /* @__PURE__ */ jsx(
3970
3989
  "button",
3971
3990
  {
3972
3991
  type: "button",
@@ -3977,7 +3996,8 @@ function TimePicker({
3977
3996
  onClick: () => emitChange(parsed.hour, parsed.minute, p),
3978
3997
  className: cn(
3979
3998
  "text-xs font-medium py-ds-1 rounded-[var(--ds-radius-sm)] cursor-pointer",
3980
- "transition-colors text-center focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
3999
+ "transition-colors text-center",
4000
+ FOCUS_RING,
3981
4001
  p === parsed.period ? "bg-[var(--ds-accent-primary)] text-[var(--ds-text-on-primary)]" : "text-[var(--ds-text-secondary)] hover:bg-[var(--ds-bg-emphasis)]"
3982
4002
  ),
3983
4003
  children: p
@@ -3995,9 +4015,9 @@ function TimePicker({
3995
4015
  var variantStyles = {
3996
4016
  default: "bg-[var(--ds-bg-emphasis)] text-[var(--ds-text-primary)]",
3997
4017
  subtle: "bg-[var(--ds-bg-muted)] text-[var(--ds-text-secondary)]",
3998
- success: "bg-[var(--ds-status-success-bg)] text-[var(--ds-status-success)] border-[length:var(--ds-border-width)] border-[var(--ds-status-success)]/[0.2]",
4018
+ success: "bg-[var(--ds-status-success-bg)] text-[var(--ds-status-success-text)] border-[length:var(--ds-border-width)] border-[var(--ds-status-success)]/[0.2]",
3999
4019
  warning: "bg-[var(--ds-status-warning-bg)] text-[var(--ds-status-warning-text)] border-[length:var(--ds-border-width)] border-[var(--ds-status-warning)]/[0.2]",
4000
- error: "bg-[var(--ds-status-error-bg)] text-[var(--ds-status-error)] border-[length:var(--ds-border-width)] border-[var(--ds-status-error)]/[0.2]",
4020
+ error: "bg-[var(--ds-status-error-bg)] text-[var(--ds-status-error-text)] border-[length:var(--ds-border-width)] border-[var(--ds-status-error)]/[0.2]",
4001
4021
  outline: "bg-transparent text-[var(--ds-text-primary)] border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]"
4002
4022
  };
4003
4023
  var sizeStyles = {
@@ -4071,7 +4091,7 @@ var Tag = forwardRef(function Tag2({
4071
4091
  "transition-colors duration-[var(--ds-transition-speed)]",
4072
4092
  sizeStyles[size],
4073
4093
  colorClasses,
4074
- onClick && !disabled && "cursor-pointer select-none hover:opacity-80",
4094
+ onClick && !disabled && cn("cursor-pointer select-none hover:opacity-80", FOCUS_RING),
4075
4095
  disabled && "opacity-disabled cursor-not-allowed",
4076
4096
  className
4077
4097
  ),
@@ -4090,7 +4110,7 @@ var Tag = forwardRef(function Tag2({
4090
4110
  "rounded-[var(--ds-radius-sm)]",
4091
4111
  "opacity-60 hover:opacity-100",
4092
4112
  "transition-opacity duration-[var(--ds-transition-speed)] cursor-pointer",
4093
- "focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]"
4113
+ FOCUS_RING
4094
4114
  ),
4095
4115
  children: /* @__PURE__ */ jsx(Icon, { name: "close", size: size === "sm" ? 10 : 12 })
4096
4116
  }
@@ -4115,6 +4135,7 @@ function TagInput({
4115
4135
  "aria-label": ariaLabel
4116
4136
  }) {
4117
4137
  const onChange = useReportedChange(onChangeProp, value);
4138
+ useInputModality();
4118
4139
  const [input, setInput] = useState("");
4119
4140
  const inputRef = useRef(null);
4120
4141
  const addTag = useCallback(
@@ -4187,7 +4208,7 @@ function TagInput({
4187
4208
  "shadow-[var(--ds-input-shadow)]",
4188
4209
  "transition-colors duration-[var(--ds-transition-speed)] cursor-text",
4189
4210
  !error && !disabled && "hover:border-[var(--ds-input-border-hover)]",
4190
- error ? ERROR_HAS_FOCUS_RING : HAS_FOCUS_RING,
4211
+ error ? ERROR_HAS_FOCUS_RING : FIELD_HAS_FOCUS_RING,
4191
4212
  disabled && "opacity-disabled cursor-not-allowed",
4192
4213
  className
4193
4214
  ),
@@ -4250,6 +4271,7 @@ function PinInput({
4250
4271
  id
4251
4272
  }) {
4252
4273
  const onChange = useReportedChange(onChangeProp, value);
4274
+ useInputModality();
4253
4275
  const contextSize = useContext(ControlSizeContext);
4254
4276
  const size = sizeProp ?? contextSize ?? "md";
4255
4277
  const inputsRef = useRef([]);
@@ -4335,7 +4357,7 @@ function PinInput({
4335
4357
  "shadow-[var(--ds-input-shadow)]",
4336
4358
  "transition-colors",
4337
4359
  !error && !disabled && "hover:border-[var(--ds-input-border-hover)]",
4338
- error ? ERROR_FOCUS_RING : FOCUS_RING,
4360
+ error ? ERROR_FOCUS_RING : FIELD_FOCUS_RING,
4339
4361
  "placeholder:text-[var(--ds-text-muted)]",
4340
4362
  sizes[size],
4341
4363
  disabled && "opacity-disabled cursor-not-allowed"
@@ -4435,7 +4457,7 @@ function Rating({
4435
4457
  const starClass = cn(
4436
4458
  "inline-flex transition-colors",
4437
4459
  filled || half ? "text-[var(--ds-status-warning)]" : "text-[var(--ds-text-muted)]",
4438
- !readOnly && "hover:scale-110 transition-transform cursor-pointer rounded-[var(--ds-radius-sm)] focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]"
4460
+ !readOnly && ["hover:scale-110 transition-transform cursor-pointer rounded-[var(--ds-radius-sm)]", FOCUS_RING]
4439
4461
  );
4440
4462
  if (readOnly) {
4441
4463
  return /* @__PURE__ */ jsx("span", { className: starClass, children: /* @__PURE__ */ jsx(StarIcon, { filled, half, size: iconSize }) }, i);
@@ -4556,6 +4578,7 @@ function ColorPicker({
4556
4578
  error = false
4557
4579
  }) {
4558
4580
  const onChange = useReportedChange(onChangeProp, value);
4581
+ useInputModality();
4559
4582
  const [hsl, setHsl] = useState(() => hexToHsl(value));
4560
4583
  const [hexInput, setHexInput] = useState(value);
4561
4584
  const satLightRef = useRef(null);
@@ -4665,7 +4688,7 @@ function ColorPicker({
4665
4688
  max: 360,
4666
4689
  value: hsl.h,
4667
4690
  onChange: (e) => emitChange({ ...hsl, h: Number(e.target.value) }),
4668
- className: "w-full h-3.5 rounded-[var(--ds-radius-full)] cursor-pointer appearance-none touch-none [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:w-5 [&::-webkit-slider-thumb]:h-5 [&::-webkit-slider-thumb]:rounded-[var(--ds-radius-full)] [&::-webkit-slider-thumb]:border-2 [&::-webkit-slider-thumb]:border-white [&::-webkit-slider-thumb]:shadow-md [&::-webkit-slider-thumb]:cursor-pointer [&::-moz-range-thumb]:w-5 [&::-moz-range-thumb]:h-5 [&::-moz-range-thumb]:rounded-[var(--ds-radius-full)] [&::-moz-range-thumb]:border-2 [&::-moz-range-thumb]:border-white [&::-moz-range-thumb]:shadow-md [&::-moz-range-thumb]:cursor-pointer [&::-moz-range-thumb]:appearance-none",
4691
+ className: cn("w-full h-3.5 rounded-[var(--ds-radius-full)] cursor-pointer appearance-none touch-none [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:w-5 [&::-webkit-slider-thumb]:h-5 [&::-webkit-slider-thumb]:rounded-[var(--ds-radius-full)] [&::-webkit-slider-thumb]:border-2 [&::-webkit-slider-thumb]:border-white [&::-webkit-slider-thumb]:shadow-md [&::-webkit-slider-thumb]:cursor-pointer [&::-moz-range-thumb]:w-5 [&::-moz-range-thumb]:h-5 [&::-moz-range-thumb]:rounded-[var(--ds-radius-full)] [&::-moz-range-thumb]:border-2 [&::-moz-range-thumb]:border-white [&::-moz-range-thumb]:shadow-md [&::-moz-range-thumb]:cursor-pointer [&::-moz-range-thumb]:appearance-none", FOCUS_RING),
4669
4692
  style: {
4670
4693
  background: "linear-gradient(to right, #f00, #ff0, #0f0, #0ff, #00f, #f0f, #f00)"
4671
4694
  }
@@ -4680,7 +4703,7 @@ function ColorPicker({
4680
4703
  max: 100,
4681
4704
  value: Math.round(hsl.a * 100),
4682
4705
  onChange: (e) => emitChange({ ...hsl, a: Number(e.target.value) / 100 }),
4683
- className: "w-full h-3.5 rounded-[var(--ds-radius-full)] cursor-pointer appearance-none touch-none [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:w-5 [&::-webkit-slider-thumb]:h-5 [&::-webkit-slider-thumb]:rounded-[var(--ds-radius-full)] [&::-webkit-slider-thumb]:border-2 [&::-webkit-slider-thumb]:border-white [&::-webkit-slider-thumb]:shadow-md [&::-webkit-slider-thumb]:cursor-pointer [&::-moz-range-thumb]:w-5 [&::-moz-range-thumb]:h-5 [&::-moz-range-thumb]:rounded-[var(--ds-radius-full)] [&::-moz-range-thumb]:border-2 [&::-moz-range-thumb]:border-white [&::-moz-range-thumb]:shadow-md [&::-moz-range-thumb]:cursor-pointer [&::-moz-range-thumb]:appearance-none",
4706
+ className: cn("w-full h-3.5 rounded-[var(--ds-radius-full)] cursor-pointer appearance-none touch-none [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:w-5 [&::-webkit-slider-thumb]:h-5 [&::-webkit-slider-thumb]:rounded-[var(--ds-radius-full)] [&::-webkit-slider-thumb]:border-2 [&::-webkit-slider-thumb]:border-white [&::-webkit-slider-thumb]:shadow-md [&::-webkit-slider-thumb]:cursor-pointer [&::-moz-range-thumb]:w-5 [&::-moz-range-thumb]:h-5 [&::-moz-range-thumb]:rounded-[var(--ds-radius-full)] [&::-moz-range-thumb]:border-2 [&::-moz-range-thumb]:border-white [&::-moz-range-thumb]:shadow-md [&::-moz-range-thumb]:cursor-pointer [&::-moz-range-thumb]:appearance-none", FOCUS_RING),
4684
4707
  style: {
4685
4708
  background: `linear-gradient(to right, transparent, ${hslToHex({ ...hsl, a: 1 })})`
4686
4709
  }
@@ -4707,7 +4730,7 @@ function ColorPicker({
4707
4730
  "border-[length:var(--ds-border-width)] border-[var(--ds-input-border)]",
4708
4731
  "rounded-[var(--ds-radius-sm)]",
4709
4732
  "hover:border-[var(--ds-input-border-hover)]",
4710
- FOCUS_RING
4733
+ FIELD_FOCUS_RING
4711
4734
  )
4712
4735
  }
4713
4736
  )
@@ -4724,8 +4747,9 @@ function ColorPicker({
4724
4747
  "w-7 h-7 rounded-[var(--ds-radius-sm)] cursor-pointer",
4725
4748
  "border-[length:var(--ds-border-width)]",
4726
4749
  "hover:scale-110 transition-transform",
4727
- "focus-visible:shadow-[var(--ds-shadow-focus)] outline-none",
4728
- swatch.toLowerCase() === value.toLowerCase() ? ACTIVE_RING : "border-[var(--ds-border-default)]"
4750
+ FOCUS_RING,
4751
+ // selected is a choice's look: the accent border, never the halo (that is active's) or an outline
4752
+ swatch.toLowerCase() === value.toLowerCase() ? "border-[var(--ds-accent-ink)]" : "border-[var(--ds-border-default)]"
4729
4753
  ),
4730
4754
  style: { backgroundColor: swatch },
4731
4755
  "aria-label": swatch
@@ -4749,10 +4773,11 @@ var indicators = {
4749
4773
  error: "bg-[var(--ds-status-error)]"
4750
4774
  };
4751
4775
  var actionColorsByVariant = {
4752
- info: "text-[var(--ds-accent-primary)] hover:bg-[var(--ds-accent-muted)]",
4753
- success: "text-[var(--ds-status-success)] hover:bg-[color-mix(in_srgb,var(--ds-status-success)_12%,transparent)]",
4754
- warning: "text-[var(--ds-status-warning)] hover:bg-[color-mix(in_srgb,var(--ds-status-warning)_15%,transparent)]",
4755
- error: "text-[var(--ds-status-error)] hover:bg-[color-mix(in_srgb,var(--ds-status-error)_12%,transparent)]"
4776
+ // words on the alert's ground: the accent's tint takes its pair's words (D5), a status's soft background its words
4777
+ info: "text-[var(--ds-accent-subtle-text)] hover:bg-[var(--ds-accent-muted)]",
4778
+ success: "text-[var(--ds-status-success-text)] hover:bg-[color-mix(in_srgb,var(--ds-status-success)_12%,transparent)]",
4779
+ warning: "text-[var(--ds-status-warning-text)] hover:bg-[color-mix(in_srgb,var(--ds-status-warning)_15%,transparent)]",
4780
+ error: "text-[var(--ds-status-error-text)] hover:bg-[color-mix(in_srgb,var(--ds-status-error)_12%,transparent)]"
4756
4781
  };
4757
4782
  var Alert = forwardRef(function Alert2({
4758
4783
  variant,
@@ -4801,7 +4826,8 @@ var Alert = forwardRef(function Alert2({
4801
4826
  "shrink-0 text-xs font-medium px-ds-2.5 py-ds-1 rounded-[var(--ds-radius-sm)]",
4802
4827
  "transition-colors cursor-pointer",
4803
4828
  "border-[length:var(--ds-border-width)] border-current",
4804
- actionColorsByVariant[variant]
4829
+ actionColorsByVariant[variant],
4830
+ FOCUS_RING
4805
4831
  ),
4806
4832
  children: /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-ds-1", children: [
4807
4833
  /* @__PURE__ */ jsx(Icon, { name: "more-vertical", size: 12 }),
@@ -4826,7 +4852,8 @@ var Alert = forwardRef(function Alert2({
4826
4852
  className: cn(
4827
4853
  "shrink-0 text-xs font-medium px-ds-2.5 py-ds-1 rounded-[var(--ds-radius-sm)]",
4828
4854
  "transition-colors cursor-pointer",
4829
- isAccent ? cn("border-[length:var(--ds-border-width)] border-current", actionColorsByVariant[variant]) : cn("border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]", "text-[var(--ds-text-secondary)] hover:text-[var(--ds-text-primary)] hover:bg-[var(--ds-tab-hover-bg)]")
4855
+ isAccent ? cn("border-[length:var(--ds-border-width)] border-current", actionColorsByVariant[variant]) : cn("border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]", "text-[var(--ds-text-secondary)] hover:text-[var(--ds-text-primary)] hover:bg-[var(--ds-tab-hover-bg)]"),
4856
+ FOCUS_RING
4830
4857
  ),
4831
4858
  children: [
4832
4859
  a.iconLeft && /* @__PURE__ */ jsx("span", { className: "inline-flex mr-ds-1", children: slotIcon(a.iconLeft, 14, "an Alert action's iconLeft") }),
@@ -4849,7 +4876,8 @@ var Alert = forwardRef(function Alert2({
4849
4876
  "inline-flex items-center gap-ds-1 text-xs font-medium cursor-pointer",
4850
4877
  "transition-colors duration-[var(--ds-transition-speed)]",
4851
4878
  actionColorsByVariant[variant],
4852
- "rounded-[var(--ds-radius-sm)] px-ds-1.5 py-ds-0.5"
4879
+ "rounded-[var(--ds-radius-sm)] px-ds-1.5 py-ds-0.5",
4880
+ FOCUS_RING
4853
4881
  ),
4854
4882
  children: [
4855
4883
  /* @__PURE__ */ jsx(
@@ -4872,7 +4900,7 @@ var Alert = forwardRef(function Alert2({
4872
4900
  {
4873
4901
  type: "button",
4874
4902
  onClick: onDismiss,
4875
- className: "shrink-0 text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] transition-colors cursor-pointer",
4903
+ className: cn("shrink-0 text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] transition-colors cursor-pointer", FOCUS_RING),
4876
4904
  "aria-label": "Dismiss",
4877
4905
  children: /* @__PURE__ */ jsx(Icon, { name: "close", size: 16 })
4878
4906
  }
@@ -5066,13 +5094,13 @@ function FormWrapper({ onSubmit, validationMode: validationModeProp, children, a
5066
5094
  }
5067
5095
  };
5068
5096
  const summaryNode = errorSummary && summary.length >= 2 ? typeof errorSummary === "function" ? errorSummary(summary) : /* @__PURE__ */ jsx(Alert, { variant: "error", title: `${summary.length} fields need attention`, className: "mb-ds-4", children: /* @__PURE__ */ jsx("ul", { className: "list-disc pl-ds-5 flex flex-col gap-ds-1", children: summary.map((f) => /* @__PURE__ */ jsxs("li", { children: [
5069
- /* @__PURE__ */ jsx("a", { href: f.id ? `#${f.id}` : void 0, onClick: focusField(f.id), className: "underline underline-offset-2 text-[var(--ds-text-primary)]", children: f.label }),
5097
+ /* @__PURE__ */ jsx("a", { href: f.id ? `#${f.id}` : void 0, onClick: focusField(f.id), className: cn("underline underline-offset-2 text-[var(--ds-text-primary)]", FOCUS_RING), children: f.label }),
5070
5098
  ": ",
5071
5099
  f.message
5072
5100
  ] }, f.id || f.label)) }) }) : null;
5073
5101
  const actionsNode = actions && !drawerFooter ? /* @__PURE__ */ jsx("div", { "data-form-actions": "", className: cn("flex flex-wrap items-center gap-ds-2 pt-ds-2", actionsAlign === "end" ? "justify-end" : "justify-start"), children: actions }) : null;
5074
5102
  return /* @__PURE__ */ jsx(FormCtx.Provider, { value: { errors, setError, clearErrors, validationMode, submitted, register }, children: /* @__PURE__ */ jsx(FormChangeCtx.Provider, { value: reportChange, children: /* @__PURE__ */ jsxs("form", { ref: setRefs, id: drawerFooter ? formId : void 0, onSubmit: handleSubmit, onFocusCapture: userActed, onInputCapture: userActed, className: cn("flex flex-col gap-ds-5 max-w-[var(--ds-form-max,calc(var(--ds-bp-md)_-_2*var(--ds-space-6)))]", className), style: fullWidth ? { "--ds-form-max": "none" } : void 0, noValidate: true, children: [
5075
- summaryNode && /* @__PURE__ */ jsx("div", { ref: summaryRef, "data-form-error-summary": "", tabIndex: -1, className: "rounded-[var(--ds-radius-md)] outline-none focus-visible:shadow-[var(--ds-shadow-focus)]", children: summaryNode }),
5103
+ summaryNode && /* @__PURE__ */ jsx("div", { ref: summaryRef, "data-form-error-summary": "", tabIndex: -1, className: cn("rounded-[var(--ds-radius-md)] focus-visible:*:shadow-none", FOCUS_RING), children: summaryNode }),
5076
5104
  children,
5077
5105
  actionsNode
5078
5106
  ] }) }) });
@@ -5292,10 +5320,13 @@ var actionButtonClass = [
5292
5320
  "bg-[var(--ds-bg-surface)] text-[var(--ds-text-primary)]",
5293
5321
  "transition-colors cursor-pointer",
5294
5322
  "hover:bg-[var(--ds-bg-muted)]",
5295
- "focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
5323
+ FOCUS_RING,
5296
5324
  "disabled:opacity-disabled disabled:pointer-events-none"
5297
5325
  ].join(" ");
5298
5326
  function Panel({ title, items, totalCount, checked, onToggle, onToggleAll, search, onSearchChange, stacked }) {
5327
+ useInputModality();
5328
+ const [list2, setList] = useState(null);
5329
+ useRevealFocus(list2);
5299
5330
  const enabledItems = items.filter((i) => !i.disabled);
5300
5331
  const allChecked = enabledItems.length > 0 && enabledItems.every((i) => checked.has(i.id));
5301
5332
  const someChecked = enabledItems.some((i) => checked.has(i.id));
@@ -5319,7 +5350,7 @@ function Panel({ title, items, totalCount, checked, onToggle, onToggleAll, searc
5319
5350
  totalCount
5320
5351
  ] })
5321
5352
  ] }),
5322
- onSearchChange && /* @__PURE__ */ jsx("div", { className: "px-ds-2 py-ds-1.5 border-b-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-ds-1.5 px-ds-2 py-ds-1 bg-[var(--ds-bg-muted)] rounded-[var(--ds-radius-sm)]", children: [
5353
+ onSearchChange && /* @__PURE__ */ jsx("div", { className: "px-ds-2 py-ds-1.5 border-b-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]", children: /* @__PURE__ */ jsxs("div", { className: cn("flex items-center gap-ds-1.5 px-ds-2 py-ds-1 bg-[var(--ds-bg-muted)] rounded-[var(--ds-radius-sm)]", FIELD_HAS_FOCUS_RING), children: [
5323
5354
  /* @__PURE__ */ jsx(Icon, { name: "search", size: 12, className: "shrink-0 text-[var(--ds-text-muted)]" }),
5324
5355
  /* @__PURE__ */ jsx(
5325
5356
  "input",
@@ -5332,7 +5363,7 @@ function Panel({ title, items, totalCount, checked, onToggle, onToggleAll, searc
5332
5363
  }
5333
5364
  )
5334
5365
  ] }) }),
5335
- /* @__PURE__ */ jsxs("div", { className: cn("flex-1 overflow-y-auto", stacked ? "max-h-[160px]" : "max-h-[240px]"), style: { padding: "var(--ds-space-1)" }, children: [
5366
+ /* @__PURE__ */ jsxs("div", { ref: setList, className: cn("flex-1 overflow-y-auto scroll-p-[4px]", stacked ? "max-h-[160px]" : "max-h-[240px]"), style: { padding: "max(var(--ds-space-1), 4px)" }, children: [
5336
5367
  items.length === 0 && /* @__PURE__ */ jsx("p", { className: "text-xs text-[var(--ds-text-muted)] text-center py-ds-6", children: "No items" }),
5337
5368
  items.map((item) => /* @__PURE__ */ jsxs(
5338
5369
  "label",
@@ -5375,7 +5406,8 @@ function PanelCheckbox({ checked, indeterminate, onClick, label }) {
5375
5406
  },
5376
5407
  className: cn(
5377
5408
  "flex items-center justify-center shrink-0 h-[18px] w-[18px] rounded-[calc(var(--ds-radius-sm)*0.6)] border-[2px] transition-all cursor-pointer",
5378
- filled ? "bg-[var(--ds-check-bg)] border-[var(--ds-check-border)]" : "bg-[var(--ds-input-bg)] border-[var(--ds-input-border)]"
5409
+ filled ? "bg-[var(--ds-check-bg)] border-[var(--ds-check-border)]" : "bg-[var(--ds-input-bg)] border-[var(--ds-input-border)]",
5410
+ FOCUS_RING
5379
5411
  ),
5380
5412
  children: /* @__PURE__ */ jsx("svg", { width: "10", height: "10", viewBox: "0 0 12 12", fill: "none", className: cn("text-[var(--ds-check-fg)] transition-opacity", filled ? "opacity-100" : "opacity-0"), children: indeterminate ? /* @__PURE__ */ jsx("path", { d: "M3 6H9", stroke: "currentColor", strokeWidth: "1.75", strokeLinecap: "round" }) : /* @__PURE__ */ jsx("path", { d: "M2.5 6L5 8.5L9.5 3.5", stroke: "currentColor", strokeWidth: "1.75", strokeLinecap: "round", strokeLinejoin: "round" }) })
5381
5413
  }
@@ -5394,6 +5426,7 @@ function MentionInput({
5394
5426
  ...wiring
5395
5427
  }) {
5396
5428
  const control = useFieldControl({ ...wiring, error: error || void 0 });
5429
+ useInputModality();
5397
5430
  const [internalValue, setInternalValue] = useState("");
5398
5431
  const value = controlledValue ?? internalValue;
5399
5432
  const onChange = useReportedChange(onChangeProp, value);
@@ -5533,7 +5566,7 @@ function MentionInput({
5533
5566
  "rounded-[var(--ds-radius-md)]",
5534
5567
  "shadow-[var(--ds-input-shadow)]",
5535
5568
  "placeholder:text-[var(--ds-text-muted)]",
5536
- control.invalid ? ERROR_FOCUS_RING : FOCUS_RING,
5569
+ control.invalid ? ERROR_FOCUS_RING : FIELD_FOCUS_RING,
5537
5570
  "disabled:cursor-not-allowed disabled:opacity-disabled disabled:hover:border-[var(--ds-input-border)]",
5538
5571
  "transition-colors duration-[var(--ds-transition-speed)]"
5539
5572
  )
@@ -5777,7 +5810,8 @@ var Card = forwardRef(function Card2({
5777
5810
  ref: checkboxRef,
5778
5811
  "data-card-checkbox": "",
5779
5812
  className: cn(
5780
- "rounded-[calc(var(--ds-radius-sm)*0.6)] focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
5813
+ "rounded-[calc(var(--ds-radius-sm)*0.6)]",
5814
+ FOCUS_RING,
5781
5815
  disabled ? "cursor-not-allowed" : "cursor-pointer"
5782
5816
  ),
5783
5817
  onClick: handleCheckableClick,
@@ -5837,11 +5871,14 @@ var Card = forwardRef(function Card2({
5837
5871
  variantStyles3[variant],
5838
5872
  isSelectable && !disabled && "cursor-pointer select-none transition-all duration-[var(--ds-transition-speed)] ease-[var(--ds-transition-ease)]",
5839
5873
  isSelectable && !disabled && !selected && "hover:border-[var(--ds-accent-primary)]",
5840
- isButton && "focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
5841
- // Selected is the accent border, with the accent-subtle fill on a card with a selectType. No ring: a ring round the
5842
- // whole card is the focus state (focus-visible:shadow-[var(--ds-shadow-focus)] above), and the active halo other
5843
- // controls take (ACTIVE_RING, since Sprint 20.6) made a selected card look focused (the owner, 27 September 2026).
5844
- isSelectable && selected && "border-[var(--ds-border-focus)]",
5874
+ // keyboard focus: the shared outline round the card, its own shadow stepping aside while it shows (Sprint 30); a card
5875
+ // that holds controls draws it round itself for its action too (CardTitle), so its shadow steps aside for that
5876
+ isButton && FOCUS_RING,
5877
+ holdsControls && "has-[[data-card-action]:focus-visible]:shadow-none",
5878
+ // Selected is the accent border (--ds-accent-ink, Sprint 30), with the accent-subtle fill on a card with a
5879
+ // selectType. Never an outline or a halo: the outline round the whole card is keyboard focus (FOCUS_RING above),
5880
+ // and the active halo (ACTIVE_RING) made a selected card look focused (the owner, 27 September 2026).
5881
+ isSelectable && selected && "border-[var(--ds-accent-ink)]",
5845
5882
  hasSelectType && selected && "bg-[var(--ds-accent-subtle)]",
5846
5883
  disabled && "opacity-disabled cursor-not-allowed",
5847
5884
  className
@@ -5920,7 +5957,8 @@ var CardHeader = forwardRef(function CardHeader2(allProps, ref) {
5920
5957
  className: cn(
5921
5958
  "inline-flex items-center justify-center h-8 w-8 rounded-[var(--ds-radius-md)]",
5922
5959
  "text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] hover:bg-[var(--ds-bg-muted)]",
5923
- "transition-colors duration-[var(--ds-transition-speed)]"
5960
+ "transition-colors duration-[var(--ds-transition-speed)]",
5961
+ FOCUS_RING
5924
5962
  ),
5925
5963
  onClick: (e) => e.stopPropagation(),
5926
5964
  children: /* @__PURE__ */ jsx(Icon, { name: "more-horizontal", size: 16 })
@@ -5998,8 +6036,9 @@ var CardTitle = forwardRef(function CardTitle2({ className, children, lines: lin
5998
6036
  ...props,
5999
6037
  children: action ? (
6000
6038
  // The card's action when the card holds controls of its own (Sprint 25.7): a real button, which a click
6001
- // elsewhere on the card also runs. Its ::after spans the card to draw the card's focus ring, taking no clicks.
6002
- // The clamp moves inside, since a button lays out its own lines.
6039
+ // elsewhere on the card also runs. Its ::after spans the card, taking no clicks, and draws keyboard focus round the
6040
+ // whole card, which is what a click runs: FOCUS_RING's outline on that layer, the card's shadow stepping aside
6041
+ // (the card's has-[]). The clamp moves inside, since a button lays out its own lines.
6003
6042
  /* @__PURE__ */ jsx(
6004
6043
  "button",
6005
6044
  {
@@ -6009,7 +6048,8 @@ var CardTitle = forwardRef(function CardTitle2({ className, children, lines: lin
6009
6048
  onClick: action.activate,
6010
6049
  className: cn(
6011
6050
  "block w-full text-left cursor-pointer [text-overflow:inherit] focus-visible:outline-none disabled:cursor-not-allowed",
6012
- "after:absolute after:inset-0 after:rounded-[var(--ds-radius-md)] after:pointer-events-none focus-visible:after:shadow-[var(--ds-shadow-focus)]"
6051
+ "after:absolute after:inset-0 after:rounded-[var(--ds-radius-md)] after:pointer-events-none",
6052
+ "focus-visible:after:outline-2 focus-visible:after:outline-solid focus-visible:after:outline-offset-2 focus-visible:after:outline-[var(--ds-focus)]"
6013
6053
  ),
6014
6054
  children: /* @__PURE__ */ jsx("span", { ref: (node) => overflowRef(lines > 0 ? node : null), className: cn("block [text-overflow:inherit]", lines > 0 && [lineClampClass, WHOLE_ON_KEYBOARD]), children })
6015
6055
  }
@@ -6080,6 +6120,8 @@ function StatsCard({ value, label, trend, icon, layout = "card", interactive, on
6080
6120
  "hover:scale-[var(--ds-ambient-hover-scale)] hover:-translate-y-[var(--ds-ambient-hover-lift)]"
6081
6121
  ],
6082
6122
  GLASS_SURFACE,
6123
+ // a clickable card is a Tab stop
6124
+ onClick && FOCUS_RING,
6083
6125
  className
6084
6126
  ),
6085
6127
  onClick,
@@ -6109,8 +6151,8 @@ function StatsCard({ value, label, trend, icon, layout = "card", interactive, on
6109
6151
  }
6110
6152
  function TrendBadge({ trend }) {
6111
6153
  const colors = {
6112
- positive: "text-[var(--ds-status-success)] bg-[var(--ds-status-success-bg)]",
6113
- negative: "text-[var(--ds-status-error)] bg-[var(--ds-status-error-bg)]",
6154
+ positive: "text-[var(--ds-status-success-text)] bg-[var(--ds-status-success-bg)]",
6155
+ negative: "text-[var(--ds-status-error-text)] bg-[var(--ds-status-error-bg)]",
6114
6156
  neutral: "text-[var(--ds-text-muted)] bg-[var(--ds-bg-muted)]"
6115
6157
  };
6116
6158
  const defaultSentiment = { up: "positive", down: "negative", flat: "neutral" };
@@ -6452,8 +6494,9 @@ function Accordion({ items, type = "single", defaultOpen = [], open: controlledO
6452
6494
  className: cn(
6453
6495
  "flex w-full items-center justify-between text-left cursor-pointer",
6454
6496
  "text-sm font-medium text-[var(--ds-text-primary)]",
6455
- "hover:text-[var(--ds-accent-primary)] transition-colors",
6456
- "focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)] focus-visible:rounded-[var(--ds-radius-sm)]"
6497
+ "hover:text-[var(--ds-accent-ink)] transition-colors",
6498
+ FOCUS_RING,
6499
+ "focus-visible:rounded-[var(--ds-radius-sm)]"
6457
6500
  ),
6458
6501
  style: { padding: "var(--ds-space-4) 0" },
6459
6502
  children: [
@@ -6545,6 +6588,10 @@ var FRAME_CLASSES = cn(
6545
6588
  GLASS_SURFACE,
6546
6589
  "bg-[var(--ds-bg-surface)]"
6547
6590
  );
6591
+ var FRAME_FOCUS_RING = "has-[>[data-table-scroll]:focus-visible]:outline-2 has-[>[data-table-scroll]:focus-visible]:outline-solid has-[>[data-table-scroll]:focus-visible]:outline-offset-2 has-[>[data-table-scroll]:focus-visible]:outline-[var(--ds-focus)] has-[>[data-table-scroll]:focus-visible]:shadow-none";
6592
+ var PIN_FOCUS = "[tr:focus-visible>&]:after:pointer-events-none [tr:focus-visible>&]:after:absolute [tr:focus-visible>&]:after:inset-x-0 [tr:focus-visible>&]:after:inset-y-[3px] [tr:focus-visible>&]:after:border-y-2 [tr:focus-visible>&]:after:border-[var(--ds-focus)] [tr:focus-visible>&]:after:content-['']";
6593
+ var PIN_FOCUS_START = "[tr:focus-visible>&]:after:left-[3px] [tr:focus-visible>&]:after:border-l-2";
6594
+ var PIN_FOCUS_END = "[tr:focus-visible>&]:after:right-[3px] [tr:focus-visible>&]:after:border-r-2";
6548
6595
  var PINNED_BACKGROUND = "linear-gradient(var(--gs-row-tint, transparent), var(--gs-row-tint, transparent)), linear-gradient(var(--gs-pinned-surface), var(--gs-pinned-surface)), var(--gs-pinned-canvas)";
6549
6596
  var PINNED_LAYERS = cn(
6550
6597
  "[--gs-pinned-surface:var(--ds-bg-surface)] [--gs-pinned-canvas:var(--ds-bg-canvas)]",
@@ -6823,6 +6870,7 @@ function Table({
6823
6870
  const mobileBreakpoint = mobileBreakpointProp ?? preferences.tableToCardsBreakpoint ?? "md";
6824
6871
  const narrowScreen = useBreakpoint(mobileBreakpoint);
6825
6872
  const { cards: isMobile, rootRef } = useCardsSwitch(narrowScreen, cardsBelow, title);
6873
+ useRevealFocus(rootRef, isMobile);
6826
6874
  const setRoot = useCallback((node) => {
6827
6875
  rootRef.current = node;
6828
6876
  if (typeof ref === "function") ref(node);
@@ -6888,6 +6936,11 @@ function Table({
6888
6936
  }
6889
6937
  return void 0;
6890
6938
  };
6939
+ const pinFocus = (position, total) => {
6940
+ if (!onRowClick || !pinStyle(position, total)) return void 0;
6941
+ const fromEnd = total - 1 - position;
6942
+ return cn(PIN_FOCUS, position === 0 && PIN_FOCUS_START, fromEnd === 0 && PIN_FOCUS_END);
6943
+ };
6891
6944
  const fade = fadeProps;
6892
6945
  const [renderedKinds, setRenderedKinds] = useState(() => /* @__PURE__ */ new Map());
6893
6946
  useLayoutEffect(() => {
@@ -6988,7 +7041,7 @@ function Table({
6988
7041
  if (title) return titledCards(/* @__PURE__ */ jsx("div", { className: "py-ds-10 text-center text-sm text-[var(--ds-text-muted)]", children: emptyState }));
6989
7042
  return /* @__PURE__ */ jsx("div", { ref: setRoot, "data-ds-list": "", "data-gs": "table", className: cn("py-ds-10 text-center text-sm text-[var(--ds-text-muted)]", className), children: emptyState });
6990
7043
  }
6991
- const cards = /* @__PURE__ */ jsx(TableCardCtx, { value: true, children: /* @__PURE__ */ jsx(RowsCtx, { value: true, children: /* @__PURE__ */ jsxs("div", { ref: title ? void 0 : listRoot, "data-ds-list": title ? void 0 : "", "data-gs": title ? void 0 : "table", className: cn("flex flex-col gap-ds-3 overflow-y-auto", title ? "min-h-0" : listClass), onFocus: title ? void 0 : noteFocus, onBlur: title ? void 0 : forgetFocus, children: [
7044
+ const cards = /* @__PURE__ */ jsx(TableCardCtx, { value: true, children: /* @__PURE__ */ jsx(RowsCtx, { value: true, children: /* @__PURE__ */ jsxs("div", { ref: title ? void 0 : listRoot, "data-ds-list": title ? void 0 : "", "data-gs": title ? void 0 : "table", className: cn("flex flex-col gap-ds-3 overflow-y-auto -m-[4px] p-[4px] scroll-p-[4px]", title ? "min-h-0" : listClass), onFocus: title ? void 0 : noteFocus, onBlur: title ? void 0 : forgetFocus, children: [
6992
7045
  selectable && /* @__PURE__ */ jsx("span", { hidden: true, id: `${headingId}-select`, children: "Select" }),
6993
7046
  drawn.map(({ row, originalIdx }) => {
6994
7047
  const isSelected = selectedSet.has(originalIdx);
@@ -7010,8 +7063,9 @@ function Table({
7010
7063
  "border-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]",
7011
7064
  "rounded-[var(--ds-radius-md)] bg-[var(--ds-bg-surface)]",
7012
7065
  "p-ds-4 space-y-ds-3",
7013
- isSelected && ACTIVE_RING,
7014
- onRowClick && "cursor-pointer hover:bg-[var(--ds-bg-muted)] focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
7066
+ // selected is chosen, not active (D2): the accent border, never the halo
7067
+ isSelected && "border-[var(--ds-accent-ink)]",
7068
+ onRowClick && ["cursor-pointer hover:bg-[var(--ds-bg-muted)]", FOCUS_RING],
7015
7069
  // with no onRowClick a tap on the card opens and closes it, as a click on the row does; the toggle is the
7016
7070
  // keyboard's way
7017
7071
  !onRowClick && canOpenByClick && "cursor-pointer"
@@ -7054,9 +7108,9 @@ function Table({
7054
7108
  // at least 24 px tall: the card around it is a target too, so its own box must meet the size (WCAG 2.5.8)
7055
7109
  "inline-flex min-h-[24px] items-center gap-ds-1 text-xs font-medium cursor-pointer",
7056
7110
  "transition-colors duration-[var(--ds-transition-speed)]",
7057
- "text-[var(--ds-accent-primary)] hover:bg-[var(--ds-accent-muted)]",
7111
+ "text-[var(--ds-accent-ink)] hover:bg-[var(--ds-accent-muted)]",
7058
7112
  "rounded-[var(--ds-radius-sm)] px-ds-1.5 py-ds-0.5 -mx-ds-1.5",
7059
- "focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]"
7113
+ FOCUS_RING
7060
7114
  ),
7061
7115
  children: [
7062
7116
  /* @__PURE__ */ jsx(Icon, { name: "chevron-right", size: 12, className: cn("transition-transform duration-[var(--ds-transition-speed)]", isExpanded && "rotate-90") }),
@@ -7116,7 +7170,8 @@ function Table({
7116
7170
  className: cn(
7117
7171
  "inline-flex items-center gap-ds-1 uppercase tracking-wider cursor-pointer select-none",
7118
7172
  "[font:inherit] text-inherit hover:text-[var(--ds-text-primary)]",
7119
- "rounded-[var(--ds-radius-sm)] focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]"
7173
+ "rounded-[var(--ds-radius-sm)]",
7174
+ FOCUS_RING
7120
7175
  ),
7121
7176
  children: [
7122
7177
  col.header,
@@ -7173,9 +7228,9 @@ function Table({
7173
7228
  // the row's tint, as a variable too, so its pinned cells draw it over their solid ground (A35)
7174
7229
  isSelected ? "bg-[var(--ds-accent-subtle)] [--gs-row-tint:var(--ds-accent-subtle)]" : striped && i % 2 === 1 ? "bg-[var(--ds-bg-muted)]/50 [--gs-row-tint:color-mix(in_oklab,var(--ds-bg-muted)_50%,transparent)]" : "hover:bg-[var(--ds-bg-muted)] hover:[--gs-row-tint:var(--ds-bg-muted)]",
7175
7230
  clickable && "cursor-pointer",
7176
- // an outline inside the row: it shows over the pinned cells, whose solid ground hid the inset
7177
- // shadow the row drew before (the review of 30 September)
7178
- onRowClick && "focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-[var(--ds-border-focus)]"
7231
+ // an outline inside the row, clear of the frame's rounded corners (D8): it shows over the pinned
7232
+ // cells, whose solid ground hid the inset shadow the row drew before (the review of 30 September)
7233
+ onRowClick && FOCUS_INSET
7179
7234
  ),
7180
7235
  onClick: clickable ? (e) => {
7181
7236
  if (!clickIsRows(e)) return;
@@ -7191,13 +7246,13 @@ function Table({
7191
7246
  }
7192
7247
  } : void 0,
7193
7248
  children: [
7194
- selectable && /* @__PURE__ */ jsx("td", { className: cn("w-10", density === "compact" ? "px-ds-2 py-ds-2" : "px-ds-3 py-ds-3"), style: pinStyle(0, cellCount), children: /* @__PURE__ */ jsx(Checkbox, { checked: isSelected, onChange: () => toggleRow(originalIdx), "aria-labelledby": nameIndex >= 0 ? `${headingId}-select ${headingId}-name-${idPart(id)}` : `${headingId}-select` }) }),
7195
- expandable && /* @__PURE__ */ jsx("td", { className: cn("w-8", density === "compact" ? "px-ds-1 py-ds-2" : "px-ds-2 py-ds-3"), style: pinStyle(selectable ? 1 : 0, cellCount), children: /* @__PURE__ */ jsx(
7249
+ selectable && /* @__PURE__ */ jsx("td", { className: cn("w-10", density === "compact" ? "px-ds-2 py-ds-2" : "px-ds-3 py-ds-3", pinFocus(0, cellCount)), style: pinStyle(0, cellCount), children: /* @__PURE__ */ jsx(Checkbox, { checked: isSelected, onChange: () => toggleRow(originalIdx), "aria-labelledby": nameIndex >= 0 ? `${headingId}-select ${headingId}-name-${idPart(id)}` : `${headingId}-select` }) }),
7250
+ expandable && /* @__PURE__ */ jsx("td", { className: cn("w-8", density === "compact" ? "px-ds-1 py-ds-2" : "px-ds-2 py-ds-3", pinFocus(selectable ? 1 : 0, cellCount)), style: pinStyle(selectable ? 1 : 0, cellCount), children: /* @__PURE__ */ jsx(
7196
7251
  "button",
7197
7252
  {
7198
7253
  type: "button",
7199
7254
  onClick: () => toggleExpand(id),
7200
- className: "text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] cursor-pointer",
7255
+ className: cn("text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] cursor-pointer", FOCUS_RING),
7201
7256
  "aria-expanded": isExpanded,
7202
7257
  ...nameIndex >= 0 ? { "aria-labelledby": `${headingId}-details ${headingId}-name-${idPart(id)}` } : { "aria-label": "Details" },
7203
7258
  children: /* @__PURE__ */ jsx(
@@ -7240,7 +7295,8 @@ function Table({
7240
7295
  alignClass,
7241
7296
  shrink && "w-px whitespace-nowrap",
7242
7297
  whole2 && "whitespace-nowrap",
7243
- kind === "identifier" && "[overflow-wrap:anywhere]"
7298
+ kind === "identifier" && "[overflow-wrap:anywhere]",
7299
+ pinFocus(lead + c, cellCount)
7244
7300
  ),
7245
7301
  style: col.maxWidth || col.width || col.minWidth || c + lead < pinnedStart || c >= columns.length - endCount ? { maxWidth: col.maxWidth, width: col.width, minWidth: col.minWidth, ...pinStyle(lead + c, cellCount) } : void 0,
7246
7302
  children: inner
@@ -7279,7 +7335,7 @@ function Table({
7279
7335
  ref: listRoot,
7280
7336
  "data-ds-list": "",
7281
7337
  "data-gs": "table",
7282
- className: cn("w-full min-w-0 flex flex-col", FRAME_CLASSES, "has-[>[data-table-scroll]:focus-visible]:shadow-[var(--ds-shadow-focus)]", control && "min-h-0", listClass),
7338
+ className: cn("w-full min-w-0 flex flex-col", FRAME_CLASSES, FRAME_FOCUS_RING, control && "min-h-0", listClass),
7283
7339
  onFocus: noteFocus,
7284
7340
  onBlur: forgetFocus,
7285
7341
  children: [
@@ -7495,9 +7551,11 @@ function SegmentedControl({
7495
7551
  // The selected segment is a kind of button, so it takes a secondary button's surface and edge, as the frame
7496
7552
  // takes a button's edge (the owner, 3 October 2026: the 3:1 strong edge it kept from Sprint 25.14 drew the
7497
7553
  // darker outline 25.19 took off the fields). It shows its state as the raised surface on the muted track, with
7498
- // the default variant's shadow and its label's stronger colour
7554
+ // the default variant's shadow and its label's stronger colour. While its segment has keyboard focus the shadow
7555
+ // steps aside, as a button's does, so the segment's outline sits clear (Sprint 30, D7)
7499
7556
  "border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]",
7500
7557
  variant === "default" && "shadow-[var(--ds-shadow-sm)]",
7558
+ "[[role=radiogroup]:has([aria-checked=true]:focus-visible)_&]:shadow-none",
7501
7559
  "transition-all motion-reduce:transition-none"
7502
7560
  ),
7503
7561
  "data-animate": animate ? "true" : "false",
@@ -7529,7 +7587,7 @@ function SegmentedControl({
7529
7587
  fullWidth && "flex-1",
7530
7588
  "rounded-[var(--ds-segment-radius)]",
7531
7589
  "transition-colors cursor-pointer",
7532
- "focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
7590
+ FOCUS_RING,
7533
7591
  sizes2[size],
7534
7592
  opt.value === value ? "text-[var(--ds-text-primary)]" : "text-[var(--ds-text-muted)] hover:text-[var(--ds-text-secondary)]",
7535
7593
  opt.disabled && "opacity-disabled cursor-not-allowed"
@@ -7599,7 +7657,7 @@ function EventBar({ event, category, compact, onOpen, inert, showTime = true, co
7599
7657
  {
7600
7658
  ref,
7601
7659
  type: "button",
7602
- className: cn("w-1.5 h-1.5 rounded-[var(--ds-radius-full)] shrink-0 cursor-pointer", className),
7660
+ className: cn("w-1.5 h-1.5 rounded-[var(--ds-radius-full)] shrink-0 cursor-pointer", FOCUS_RING, className),
7603
7661
  style: { backgroundColor: colours.edge },
7604
7662
  onClick: (e) => {
7605
7663
  e.stopPropagation();
@@ -7619,7 +7677,7 @@ function EventBar({ event, category, compact, onOpen, inert, showTime = true, co
7619
7677
  "w-full text-left text-xs leading-tight px-ds-1.5 py-ds-0.5",
7620
7678
  look,
7621
7679
  "truncate cursor-pointer transition-[filter] hover:brightness-95",
7622
- "focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
7680
+ FOCUS_RING,
7623
7681
  className
7624
7682
  ),
7625
7683
  style: paint,
@@ -7751,7 +7809,7 @@ function EventCard({ event, category, anchor, actions, onClose, fallbackFocus, r
7751
7809
  /* @__PURE__ */ jsx("span", { className: "min-w-0 break-words", children: event.location })
7752
7810
  ] }),
7753
7811
  event.description && /* @__PURE__ */ jsx("p", { className: "text-xs text-[var(--ds-text-secondary)] whitespace-pre-line break-words", children: event.description }),
7754
- event.attendees && event.attendees.length > 0 && /* @__PURE__ */ jsx("div", { ref: setAttendeeScroll, className: cn("max-h-32 overflow-y-auto -mx-[2px] p-[2px]", FOCUS_INSET), children: /* @__PURE__ */ jsx("ul", { "aria-label": "Attendees", className: "space-y-ds-1", children: event.attendees.map((person, i) => /* @__PURE__ */ jsxs("li", { className: "flex items-center gap-ds-2 text-xs text-[var(--ds-text-primary)]", children: [
7812
+ event.attendees && event.attendees.length > 0 && /* @__PURE__ */ jsx("div", { ref: setAttendeeScroll, className: cn("max-h-32 overflow-y-auto -mx-[calc(var(--ds-focus-inset)+1px)] p-[calc(var(--ds-focus-inset)+1px)]", FOCUS_INSET), children: /* @__PURE__ */ jsx("ul", { "aria-label": "Attendees", className: "space-y-ds-1", children: event.attendees.map((person, i) => /* @__PURE__ */ jsxs("li", { className: "flex items-center gap-ds-2 text-xs text-[var(--ds-text-primary)]", children: [
7755
7813
  /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "shrink-0", children: /* @__PURE__ */ jsx(Avatar, { size: "sm", initials: person.initials ?? person.name }) }),
7756
7814
  /* @__PURE__ */ jsx("span", { className: "min-w-0 truncate", children: person.name })
7757
7815
  ] }, `${person.name}-${i}`)) }) }),
@@ -7904,7 +7962,8 @@ function MonthView({ date, events, categories, selectedDate, onDayClick, canStar
7904
7962
  "relative min-h-[80px] sm:min-h-[100px] border-[var(--ds-border-subtle)]",
7905
7963
  !lastRow && "border-b-[length:var(--ds-divider-width)]",
7906
7964
  di < 6 && "border-r-[length:var(--ds-divider-width)]",
7907
- "p-ds-1 flex flex-col cursor-pointer transition-colors",
7965
+ // the day's outline sits inside its edge (D8, --ds-focus-inset): its number and events keep clear of it
7966
+ "p-[max(var(--ds-space-1),calc(var(--ds-focus-inset)+1px))] flex flex-col cursor-pointer transition-colors",
7908
7967
  FOCUS_INSET,
7909
7968
  "hover:bg-[var(--ds-bg-muted)]",
7910
7969
  !isCurrentMonth && "[&>.gs-day-number]:opacity-40",
@@ -7947,7 +8006,7 @@ function MonthView({ date, events, categories, selectedDate, onDayClick, canStar
7947
8006
  type: "button",
7948
8007
  "aria-haspopup": "dialog",
7949
8008
  "aria-expanded": !!list2 && isSameDay(list2.day, day),
7950
- className: "absolute z-[1] text-2xs text-[var(--ds-accent-text,var(--ds-accent-primary))] font-medium cursor-pointer hover:underline px-ds-1.5 rounded-[var(--ds-radius-sm)] focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
8009
+ className: cn("absolute z-[1] text-2xs text-[var(--ds-accent-text,var(--ds-accent-primary))] font-medium cursor-pointer hover:underline px-ds-1.5 rounded-[var(--ds-radius-sm)]", FOCUS_RING),
7951
8010
  style: { top: NUMBER_ROW + (LANES - 1) * (LANE_H + LANE_GAP), left: INSET, height: LANE_H },
7952
8011
  onClick: (e) => {
7953
8012
  e.stopPropagation();
@@ -8036,7 +8095,9 @@ function TimedEvent({ placed, category, onOpen, onFocusEvent }) {
8036
8095
  "border-[length:var(--ds-border-width)] border-solid rounded-[var(--ds-radius-sm)]",
8037
8096
  cutTop && "rounded-t-none border-t-0",
8038
8097
  cutBottom && "rounded-b-none border-b-0",
8039
- "focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)] focus-visible:z-[3]"
8098
+ // a week event: the outline inside its edge (P3), raised over the now line and its neighbours while it shows
8099
+ FOCUS_INSET,
8100
+ "focus-visible:z-[3]"
8040
8101
  ),
8041
8102
  style: {
8042
8103
  top: drawnTop,
@@ -8244,7 +8305,7 @@ function WeekView({ date, events, categories, selectedDate, onDayClick, onOpenEv
8244
8305
  type: "button",
8245
8306
  "aria-haspopup": "dialog",
8246
8307
  "aria-expanded": !!list2 && isSameDay(list2.day, day),
8247
- className: "absolute z-[1] text-2xs text-[var(--ds-accent-text,var(--ds-accent-primary))] font-medium cursor-pointer hover:underline px-ds-1.5 rounded-[var(--ds-radius-sm)] focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
8308
+ className: cn("absolute z-[1] text-2xs text-[var(--ds-accent-text,var(--ds-accent-primary))] font-medium cursor-pointer hover:underline px-ds-1.5 rounded-[var(--ds-radius-sm)]", FOCUS_RING),
8248
8309
  style: { top: 2 + (ALL_DAY_LANES - 1) * (LANE_H2 + LANE_GAP2), left: 2, height: LANE_H2 },
8249
8310
  onClick: (e) => {
8250
8311
  e.stopPropagation();
@@ -8422,7 +8483,7 @@ function MonthRow({
8422
8483
  "aria-label": `${words.monthName(month, "short")} ${year}`,
8423
8484
  className: cn(
8424
8485
  "sticky left-0 z-10 flex items-center justify-center px-ds-2 text-xs font-semibold text-[var(--ds-text-primary)]",
8425
- "bg-[var(--ds-bg-muted)] cursor-pointer hover:text-[var(--ds-accent-primary)] transition-colors",
8486
+ "bg-[var(--ds-bg-muted)] cursor-pointer hover:text-[var(--ds-accent-ink)] transition-colors",
8426
8487
  "border-r-[length:var(--ds-divider-width)] border-b-[length:var(--ds-divider-width)] border-[var(--ds-border-subtle)]",
8427
8488
  FOCUS_INSET
8428
8489
  ),
@@ -8559,7 +8620,9 @@ function CompactMonthView({ date, events, categories, selectedDate, onDayClick,
8559
8620
  },
8560
8621
  className: cn(
8561
8622
  "flex flex-col items-center justify-center py-ds-1.5 rounded-[var(--ds-radius-sm)] cursor-pointer transition-colors",
8562
- "focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
8623
+ // a day cell, edge to edge with its neighbours and never filled solid: its outline sits inside its
8624
+ // edge, as the month view's days do
8625
+ FOCUS_INSET,
8563
8626
  !isCurrentMonth && "opacity-30",
8564
8627
  selected && "bg-[var(--ds-accent-subtle)]",
8565
8628
  !selected && "hover:bg-[var(--ds-bg-muted)]"
@@ -8671,8 +8734,9 @@ function MonthDropdown({
8671
8734
  onClick: () => setOpen(!open),
8672
8735
  className: cn(
8673
8736
  "flex items-center gap-ds-1 text-sm font-[var(--ds-weight-heading)] text-[var(--ds-text-primary)] cursor-pointer",
8674
- "hover:text-[var(--ds-accent-primary)] transition-colors",
8675
- "focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)] rounded-[var(--ds-radius-sm)]",
8737
+ "hover:text-[var(--ds-accent-ink)] transition-colors",
8738
+ "rounded-[var(--ds-radius-sm)]",
8739
+ FOCUS_RING,
8676
8740
  "pl-ds-3 pr-ds-2 py-ds-1"
8677
8741
  ),
8678
8742
  children: [
@@ -8701,7 +8765,7 @@ function MonthDropdown({
8701
8765
  /* @__PURE__ */ jsx(
8702
8766
  "button",
8703
8767
  {
8704
- className: "p-ds-1 rounded-[var(--ds-radius-sm)] hover:bg-[var(--ds-bg-emphasis)] cursor-pointer text-[var(--ds-text-secondary)]",
8768
+ className: cn("p-ds-1 rounded-[var(--ds-radius-sm)] hover:bg-[var(--ds-bg-emphasis)] cursor-pointer text-[var(--ds-text-secondary)]", FOCUS_RING),
8705
8769
  onClick: () => setBrowseYear(browseYear - 1),
8706
8770
  "aria-label": "Previous year",
8707
8771
  children: /* @__PURE__ */ jsx(Icon, { name: "chevron-right", size: 14, className: "rotate-180" })
@@ -8711,7 +8775,7 @@ function MonthDropdown({
8711
8775
  /* @__PURE__ */ jsx(
8712
8776
  "button",
8713
8777
  {
8714
- className: "p-ds-1 rounded-[var(--ds-radius-sm)] hover:bg-[var(--ds-bg-emphasis)] cursor-pointer text-[var(--ds-text-secondary)]",
8778
+ className: cn("p-ds-1 rounded-[var(--ds-radius-sm)] hover:bg-[var(--ds-bg-emphasis)] cursor-pointer text-[var(--ds-text-secondary)]", FOCUS_RING),
8715
8779
  onClick: () => setBrowseYear(browseYear + 1),
8716
8780
  "aria-label": "Next year",
8717
8781
  children: /* @__PURE__ */ jsx(Icon, { name: "chevron-right", size: 14 })
@@ -8725,7 +8789,7 @@ function MonthDropdown({
8725
8789
  {
8726
8790
  className: cn(
8727
8791
  "px-ds-2 py-ds-1.5 text-xs font-medium rounded-[var(--ds-radius-sm)] cursor-pointer transition-colors",
8728
- "focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
8792
+ FOCUS_RING,
8729
8793
  isActive2 ? "bg-[var(--ds-accent-primary)] text-[var(--ds-text-on-primary)]" : "text-[var(--ds-text-secondary)] hover:bg-[var(--ds-bg-emphasis)] hover:text-[var(--ds-text-primary)]"
8730
8794
  ),
8731
8795
  "data-current": isActive2 || void 0,
@@ -8802,8 +8866,9 @@ function YearDropdown({
8802
8866
  onClick: () => setOpen(!open),
8803
8867
  className: cn(
8804
8868
  "flex items-center gap-ds-1 text-sm font-[var(--ds-weight-heading)] text-[var(--ds-text-primary)] cursor-pointer",
8805
- "hover:text-[var(--ds-accent-primary)] transition-colors",
8806
- "focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)] rounded-[var(--ds-radius-sm)]",
8869
+ "hover:text-[var(--ds-accent-ink)] transition-colors",
8870
+ "rounded-[var(--ds-radius-sm)]",
8871
+ FOCUS_RING,
8807
8872
  "pl-ds-3 pr-ds-2 py-ds-1"
8808
8873
  ),
8809
8874
  children: [
@@ -8832,7 +8897,7 @@ function YearDropdown({
8832
8897
  /* @__PURE__ */ jsx(
8833
8898
  "button",
8834
8899
  {
8835
- className: "p-ds-1 rounded-[var(--ds-radius-sm)] hover:bg-[var(--ds-bg-emphasis)] cursor-pointer text-[var(--ds-text-secondary)]",
8900
+ className: cn("p-ds-1 rounded-[var(--ds-radius-sm)] hover:bg-[var(--ds-bg-emphasis)] cursor-pointer text-[var(--ds-text-secondary)]", FOCUS_RING),
8836
8901
  onClick: () => setRangeStart(rangeStart - 9),
8837
8902
  "aria-label": "Previous years",
8838
8903
  children: /* @__PURE__ */ jsx(Icon, { name: "chevron-right", size: 14, className: "rotate-180" })
@@ -8846,7 +8911,7 @@ function YearDropdown({
8846
8911
  /* @__PURE__ */ jsx(
8847
8912
  "button",
8848
8913
  {
8849
- className: "p-ds-1 rounded-[var(--ds-radius-sm)] hover:bg-[var(--ds-bg-emphasis)] cursor-pointer text-[var(--ds-text-secondary)]",
8914
+ className: cn("p-ds-1 rounded-[var(--ds-radius-sm)] hover:bg-[var(--ds-bg-emphasis)] cursor-pointer text-[var(--ds-text-secondary)]", FOCUS_RING),
8850
8915
  onClick: () => setRangeStart(rangeStart + 9),
8851
8916
  "aria-label": "Next years",
8852
8917
  children: /* @__PURE__ */ jsx(Icon, { name: "chevron-right", size: 14 })
@@ -8858,7 +8923,7 @@ function YearDropdown({
8858
8923
  {
8859
8924
  className: cn(
8860
8925
  "px-ds-2 py-ds-1.5 text-xs font-medium rounded-[var(--ds-radius-sm)] cursor-pointer transition-colors",
8861
- "focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
8926
+ FOCUS_RING,
8862
8927
  y === currentYear ? "bg-[var(--ds-accent-primary)] text-[var(--ds-text-on-primary)]" : "text-[var(--ds-text-secondary)] hover:bg-[var(--ds-bg-emphasis)] hover:text-[var(--ds-text-primary)]"
8863
8928
  ),
8864
8929
  "data-current": y === currentYear || void 0,
@@ -9181,7 +9246,7 @@ function Calendar({
9181
9246
  "button",
9182
9247
  {
9183
9248
  onClick: () => navigate(-1),
9184
- className: "flex items-center justify-center w-8 h-8 rounded-[var(--ds-radius-sm)] text-[var(--ds-text-secondary)] hover:bg-[var(--ds-bg-surface)] hover:text-[var(--ds-text-primary)] transition-colors cursor-pointer",
9249
+ className: cn("flex items-center justify-center w-8 h-8 rounded-[var(--ds-radius-sm)] text-[var(--ds-text-secondary)] hover:bg-[var(--ds-bg-surface)] hover:text-[var(--ds-text-primary)] transition-colors cursor-pointer", FOCUS_RING),
9185
9250
  "aria-label": "Previous month",
9186
9251
  children: /* @__PURE__ */ jsx(Icon, { name: "chevron-left", size: 16 })
9187
9252
  }
@@ -9190,7 +9255,7 @@ function Calendar({
9190
9255
  "button",
9191
9256
  {
9192
9257
  onClick: goToToday,
9193
- className: "text-sm font-medium text-[var(--ds-text-primary)] hover:text-[var(--ds-accent-primary)] transition-colors cursor-pointer px-ds-2",
9258
+ className: cn("text-sm font-medium text-[var(--ds-text-primary)] hover:text-[var(--ds-accent-ink)] transition-colors cursor-pointer px-ds-2", FOCUS_RING),
9194
9259
  children: formatMonthYear(currentDate)
9195
9260
  }
9196
9261
  ),
@@ -9198,7 +9263,7 @@ function Calendar({
9198
9263
  "button",
9199
9264
  {
9200
9265
  onClick: () => navigate(1),
9201
- className: "flex items-center justify-center w-8 h-8 rounded-[var(--ds-radius-sm)] text-[var(--ds-text-secondary)] hover:bg-[var(--ds-bg-surface)] hover:text-[var(--ds-text-primary)] transition-colors cursor-pointer",
9266
+ className: cn("flex items-center justify-center w-8 h-8 rounded-[var(--ds-radius-sm)] text-[var(--ds-text-secondary)] hover:bg-[var(--ds-bg-surface)] hover:text-[var(--ds-text-primary)] transition-colors cursor-pointer", FOCUS_RING),
9202
9267
  "aria-label": "Next month",
9203
9268
  children: /* @__PURE__ */ jsx(Icon, { name: "chevron-right", size: 16 })
9204
9269
  }
@@ -9395,7 +9460,7 @@ function AvatarGroup({ items, max = 4, size = "sm", ring = "canvas", onOverflowC
9395
9460
  );
9396
9461
  return item.name ? /* @__PURE__ */ jsx(Tooltip, { content: item.name, children: avatar }, i) : avatar;
9397
9462
  }),
9398
- counter && (onOverflowClick ? /* @__PURE__ */ jsx("button", { type: "button", onClick: onOverflowClick, "aria-label": `Show ${hidden.length} more`, className: "inline-flex rounded-[var(--ds-radius-full)] focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]", children: hiddenNames ? /* @__PURE__ */ jsx(Tooltip, { content: hiddenNames, children: counter }) : counter }) : hiddenNames ? /* @__PURE__ */ jsx(Tooltip, { content: hiddenNames, children: counter }) : counter)
9463
+ counter && (onOverflowClick ? /* @__PURE__ */ jsx("button", { type: "button", onClick: onOverflowClick, "aria-label": `Show ${hidden.length} more`, className: cn("inline-flex rounded-[var(--ds-radius-full)]", FOCUS_RING), children: hiddenNames ? /* @__PURE__ */ jsx(Tooltip, { content: hiddenNames, children: counter }) : counter }) : hiddenNames ? /* @__PURE__ */ jsx(Tooltip, { content: hiddenNames, children: counter }) : counter)
9399
9464
  ] });
9400
9465
  }
9401
9466
  var defaultIcons = {
@@ -9615,6 +9680,8 @@ function ExpandableDescription({ children, className }) {
9615
9680
  "text-xs text-[var(--ds-text-muted)] mt-ds-0.5",
9616
9681
  !expanded && "line-clamp-2",
9617
9682
  isTruncated && !expanded && "cursor-pointer",
9683
+ // a button while it's clamped: a Tab stop that shows the outline
9684
+ FOCUS_RING,
9618
9685
  className
9619
9686
  ),
9620
9687
  onClick: isTruncated && !expanded ? () => setExpanded(true) : void 0,
@@ -9768,7 +9835,7 @@ function CollapsibleTrigger({ children, className }) {
9768
9835
  }
9769
9836
  });
9770
9837
  }
9771
- return /* @__PURE__ */ jsx("button", { type: "button", className: cn("text-left cursor-pointer", className), onClick: toggle, "aria-expanded": isOpen, children });
9838
+ return /* @__PURE__ */ jsx("button", { type: "button", className: cn("text-left cursor-pointer", FOCUS_RING, className), onClick: toggle, "aria-expanded": isOpen, children });
9772
9839
  }
9773
9840
  function CollapsibleContent({ children, className }) {
9774
9841
  const { isOpen } = useCollapsible();
@@ -10035,12 +10102,12 @@ function TreeNodeRow({
10035
10102
  tabIndex: 0,
10036
10103
  className: cn(
10037
10104
  "flex items-center gap-ds-2 py-ds-1.5 px-ds-2 rounded-[var(--ds-radius-md)] cursor-pointer transition-colors",
10038
- "focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
10105
+ FOCUS_RING,
10039
10106
  // Active style comes from the theme's --ds-tree-* tokens (rail / tint;
10040
10107
  // pill degrades to tint). Every row carries the rail width as a
10041
10108
  // transparent placeholder so content never shifts on selection.
10042
10109
  "border-l-[length:var(--ds-tree-active-rail)]",
10043
- isSelected ? "bg-[var(--ds-tree-active-bg)] text-[var(--ds-tree-active-text)] font-medium border-[var(--ds-accent-primary)]" : "border-transparent text-[var(--ds-text-primary)] hover:bg-[var(--ds-tab-hover-bg)] hover:text-[var(--ds-text-primary)]",
10110
+ isSelected ? "bg-[var(--ds-tree-active-bg)] text-[var(--ds-tree-active-text)] font-medium border-[var(--ds-accent-ink)]" : "border-transparent text-[var(--ds-text-primary)] hover:bg-[var(--ds-tab-hover-bg)] hover:text-[var(--ds-text-primary)]",
10044
10111
  // A folder holding the selection, as SidebarNav draws a parent of the current page (Sprint 25.16 A18): no
10045
10112
  // fill, so it reads the plain tokens, never the active set (pill's on-primary text would vanish here).
10046
10113
  holdsSelection && "font-medium",
@@ -10070,7 +10137,7 @@ function TreeNodeRow({
10070
10137
  {
10071
10138
  name: "chevron-right",
10072
10139
  size: 14,
10073
- className: cn(isSelected ? "text-[var(--ds-tree-active-muted)]" : holdsSelection ? "text-[var(--ds-accent-primary)]" : "text-[var(--ds-text-muted)]", "transition-transform", isExpanded && "rotate-90")
10140
+ className: cn(isSelected ? "text-[var(--ds-tree-active-muted)]" : holdsSelection ? "text-[var(--ds-accent-ink)]" : "text-[var(--ds-text-muted)]", "transition-transform", isExpanded && "rotate-90")
10074
10141
  }
10075
10142
  )
10076
10143
  }
@@ -10085,7 +10152,7 @@ function TreeNodeRow({
10085
10152
  }
10086
10153
  }
10087
10154
  ),
10088
- node.icon && /* @__PURE__ */ jsx(Icon, { name: node.icon, size: 16, className: cn("shrink-0", isSelected ? "text-[var(--ds-tree-active-text)]" : holdsSelection ? "text-[var(--ds-accent-primary)]" : "text-[var(--ds-text-muted)]") }),
10155
+ node.icon && /* @__PURE__ */ jsx(Icon, { name: node.icon, size: 16, className: cn("shrink-0", isSelected ? "text-[var(--ds-tree-active-text)]" : holdsSelection ? "text-[var(--ds-accent-ink)]" : "text-[var(--ds-text-muted)]") }),
10089
10156
  /* @__PURE__ */ jsx(TruncLabel2, { children: node.label })
10090
10157
  ]
10091
10158
  }
@@ -10246,7 +10313,7 @@ function Carousel({
10246
10313
  "bg-[var(--ds-bg-surface-elevated)] border-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]",
10247
10314
  "text-[var(--ds-text-primary)] shadow-[var(--ds-shadow-sm)]",
10248
10315
  "transition-opacity cursor-pointer hover:bg-[var(--ds-bg-muted)]",
10249
- "focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
10316
+ FOCUS_RING,
10250
10317
  !canPrev && "opacity-0 pointer-events-none"
10251
10318
  ),
10252
10319
  children: /* @__PURE__ */ jsx(Icon, { name: "chevron-right", size: 16, className: "rotate-180" })
@@ -10266,7 +10333,7 @@ function Carousel({
10266
10333
  "bg-[var(--ds-bg-surface-elevated)] border-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]",
10267
10334
  "text-[var(--ds-text-primary)] shadow-[var(--ds-shadow-sm)]",
10268
10335
  "transition-opacity cursor-pointer hover:bg-[var(--ds-bg-muted)]",
10269
- "focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
10336
+ FOCUS_RING,
10270
10337
  !canNext && "opacity-0 pointer-events-none"
10271
10338
  ),
10272
10339
  children: /* @__PURE__ */ jsx(Icon, { name: "chevron-right", size: 16 })
@@ -10281,7 +10348,7 @@ function Carousel({
10281
10348
  "aria-label": `Go to slide ${i + 1}`,
10282
10349
  className: cn(
10283
10350
  "w-2 h-2 rounded-[var(--ds-radius-full)] transition-all cursor-pointer",
10284
- "focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
10351
+ FOCUS_RING,
10285
10352
  i === current ? "bg-[var(--ds-accent-primary)] w-6" : "bg-[var(--ds-text-muted)] opacity-50 hover:opacity-75"
10286
10353
  )
10287
10354
  },
@@ -10370,7 +10437,7 @@ function SourcesRow({ sources }) {
10370
10437
  ] }, s.href + i))
10371
10438
  ] });
10372
10439
  }
10373
- var StreamingCaret = () => /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "ml-ds-0.5 inline-block animate-pulse text-[var(--ds-accent-primary)]", children: "\u258D" });
10440
+ var StreamingCaret = () => /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "ml-ds-0.5 inline-block animate-pulse text-[var(--ds-accent-ink)]", children: "\u258D" });
10374
10441
  var ChatMessageItem = memo(function ChatMessageItem2({ message: msg, grouped, spaced, layout, onAction, renderContent }) {
10375
10442
  const locale = useFormatLocale();
10376
10443
  const hydrated = useHydrated();
@@ -10440,6 +10507,7 @@ var ChatMessageItem = memo(function ChatMessageItem2({ message: msg, grouped, sp
10440
10507
  function ChatInputBar({ onSend, busy, onStop, onAttach, onVoice, placeholder }) {
10441
10508
  const [text, setText] = useState("");
10442
10509
  const isMobile = useBreakpoint("sm");
10510
+ useInputModality();
10443
10511
  const handleSend = () => {
10444
10512
  if (busy || !text.trim()) return;
10445
10513
  onSend?.(text.trim());
@@ -10463,7 +10531,7 @@ function ChatInputBar({ onSend, busy, onStop, onAttach, onVoice, placeholder })
10463
10531
  "border-[length:var(--ds-border-width)] border-[var(--ds-input-border)]",
10464
10532
  "bg-[var(--ds-input-bg)]",
10465
10533
  "shadow-[var(--ds-input-shadow)]",
10466
- FOCUS_WITHIN_RING,
10534
+ FIELD_FOCUS_WITHIN_RING,
10467
10535
  "transition-colors duration-[var(--ds-transition-speed)]"
10468
10536
  ),
10469
10537
  children: [
@@ -10543,6 +10611,12 @@ function ChatMessageList({
10543
10611
  }) {
10544
10612
  const scrollRef = useRef(null);
10545
10613
  const columnRef = useRef(null);
10614
+ const [scroller, setScroller] = useState(null);
10615
+ const setScroll = useCallback((node) => {
10616
+ scrollRef.current = node;
10617
+ setScroller(node);
10618
+ }, []);
10619
+ useRevealFocus(scroller);
10546
10620
  const atBottomRef = useRef(true);
10547
10621
  const [showJump, setShowJump] = useState(false);
10548
10622
  const [prevMessages, setPrevMessages] = useState(messages);
@@ -10586,7 +10660,7 @@ function ChatMessageList({
10586
10660
  return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col flex-1 min-h-0", className), children: [
10587
10661
  /* @__PURE__ */ jsx("div", { role: "status", "aria-live": "polite", className: "sr-only", children: announcement }),
10588
10662
  /* @__PURE__ */ jsxs("div", { className: "relative flex-1 min-h-0", children: [
10589
- /* @__PURE__ */ jsx("div", { ref: scrollRef, onScroll, className: "h-full overflow-y-auto", children: empty ? /* @__PURE__ */ jsxs("div", { className: "flex h-full flex-col items-center justify-center gap-ds-6 px-ds-4 py-ds-8 text-center", children: [
10663
+ /* @__PURE__ */ jsx("div", { ref: setScroll, onScroll, className: "h-full overflow-y-auto scroll-p-[4px]", children: empty ? /* @__PURE__ */ jsxs("div", { className: "flex h-full flex-col items-center justify-center gap-ds-6 px-ds-4 py-ds-8 text-center", children: [
10590
10664
  emptyState ?? /* @__PURE__ */ jsx(
10591
10665
  EmptyState,
10592
10666
  {
@@ -11048,28 +11122,18 @@ function TruncText({ children, className }) {
11048
11122
  if (!isTruncated) return text;
11049
11123
  return /* @__PURE__ */ jsx(Tooltip, { content: children, children: text });
11050
11124
  }
11051
- var warnedLegacyProps = false;
11052
11125
  var StackedList = forwardRef(function StackedList2({
11053
11126
  items,
11054
11127
  divided = true,
11055
- variant: variantProp,
11128
+ variant = "list",
11056
11129
  selectedId,
11057
11130
  className,
11058
- flush,
11059
- hover,
11060
11131
  pager
11061
11132
  }, ref) {
11062
11133
  useScrollsInside();
11063
11134
  const isPhone = useBreakpoint("sm");
11064
11135
  const inCard = useContext(CardSurfaceCtx);
11065
11136
  const inPane = !!useContext(SplitPaneCtx);
11066
- const variant = variantProp ?? (flush || hover === "title" ? "articles" : "list");
11067
- const legacy = flush !== void 0 || hover !== void 0;
11068
- useEffect(() => {
11069
- if (!legacy || warnedLegacyProps) return;
11070
- warnedLegacyProps = true;
11071
- console.warn('StackedList: `flush` and `hover` are deprecated \u2014 pass variant="articles" for an article list; the default variant takes its inset from the pane or card it sits in.');
11072
- }, [legacy]);
11073
11137
  const articles = variant === "articles";
11074
11138
  useWholeListCheck("StackedList", items.length, pager);
11075
11139
  const shown = pagerPart(items, pager);
@@ -11119,7 +11183,9 @@ var StackedList = forwardRef(function StackedList2({
11119
11183
  inset,
11120
11184
  interactive && [
11121
11185
  "cursor-pointer [transition:var(--ds-transition-interactive)]",
11122
- "focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]"
11186
+ // in a pane the rows run to its edges, which clip: the outline sits inside (D8), and on the selected
11187
+ // row in the row's own text colour, which reads on its fill, the pill style's solid one too (P1)
11188
+ inPane ? cn(FOCUS_INSET, isSelected && "[--ds-focus:var(--ds-nav-v-active-text)]") : FOCUS_RING
11123
11189
  ],
11124
11190
  // list: same colours as the vertical Tabs item — the theme's in-page vertical style decides rail, tint
11125
11191
  // or pill via the --ds-nav-v-* tokens — but a list row is a full-width band: no radius, ever, and a
@@ -11128,7 +11194,7 @@ var StackedList = forwardRef(function StackedList2({
11128
11194
  // articles: no rail, no tint; the title answers the pointer and the current row.
11129
11195
  // The placeholder exists only where a selection can appear, so a plain canvas list aligns exactly with its heading.
11130
11196
  !articles && selectable && "border-l-[length:calc(var(--ds-nav-v-active-rail)*1.5)]",
11131
- !articles && (isSelected ? "bg-[var(--ds-nav-v-active-bg)] text-[var(--ds-nav-v-active-text)] border-[var(--ds-accent-primary)]" : cn("border-transparent", interactive && "hover:bg-[var(--ds-tab-hover-bg)]")),
11197
+ !articles && (isSelected ? "bg-[var(--ds-nav-v-active-bg)] text-[var(--ds-nav-v-active-text)] border-[var(--ds-accent-ink)]" : cn("border-transparent", interactive && "hover:bg-[var(--ds-tab-hover-bg)]")),
11132
11198
  articles && interactive && "group/row"
11133
11199
  ),
11134
11200
  onClick: item.onClick,
@@ -11150,9 +11216,9 @@ var StackedList = forwardRef(function StackedList2({
11150
11216
  {
11151
11217
  className: cn(
11152
11218
  "text-sm",
11153
- isSelected ? articles ? "font-medium text-[var(--ds-accent-primary)]" : "font-medium text-[var(--ds-nav-v-active-text)]" : hasEmphasis && !item.unread ? "text-[var(--ds-text-secondary)]" : "font-medium text-[var(--ds-text-primary)]",
11219
+ isSelected ? articles ? "font-medium text-[var(--ds-accent-ink)]" : "font-medium text-[var(--ds-nav-v-active-text)]" : hasEmphasis && !item.unread ? "text-[var(--ds-text-secondary)]" : "font-medium text-[var(--ds-text-primary)]",
11154
11220
  // articles: the title answers the pointer (accent, underline) instead of the row's background
11155
- articles && interactive && !isSelected && "transition-colors group-hover/row:text-[var(--ds-accent-primary)] group-hover/row:underline underline-offset-2"
11221
+ articles && interactive && !isSelected && "transition-colors group-hover/row:text-[var(--ds-accent-ink)] group-hover/row:underline underline-offset-2"
11156
11222
  ),
11157
11223
  children: item.title
11158
11224
  }
@@ -11817,8 +11883,8 @@ var TimeViewport = forwardRef(function TimeViewport2({
11817
11883
  const { labelWidth: lw, headerHeight } = latest.current;
11818
11884
  const box = el.getBoundingClientRect();
11819
11885
  const r = target.getBoundingClientRect();
11820
- const top = box.top + headerHeight;
11821
- const bottom = box.top + el.clientHeight;
11886
+ const top = box.top + headerHeight + 4;
11887
+ const bottom = box.top + el.clientHeight - 4;
11822
11888
  if (r.top < top) el.scrollTop -= top - r.top;
11823
11889
  else if (r.bottom > bottom) el.scrollTop += Math.min(r.bottom - bottom, r.top - top);
11824
11890
  const x0 = r.left - box.left - lw + el.scrollLeft;
@@ -11994,7 +12060,7 @@ var TimeViewport = forwardRef(function TimeViewport2({
11994
12060
  tabIndex: tabStop ? 0 : void 0,
11995
12061
  onScroll,
11996
12062
  className: "peer h-full overflow-auto isolate outline-none",
11997
- style: { scrollPaddingInlineStart: pinnedWidth, scrollPaddingTop: frame.header },
12063
+ style: { scrollPaddingInlineStart: pinnedWidth + 4, scrollPaddingInlineEnd: 4, scrollPaddingTop: frame.header + 4, scrollPaddingBottom: 4 },
11998
12064
  children: /* @__PURE__ */ jsxs("div", { className: "flex min-h-full flex-col", style: { width: pinnedWidth + drawn.width }, children: [
11999
12065
  hasHeader && /* @__PURE__ */ jsxs("div", { ref: headerRef, className: cn("sticky top-0 z-[3] flex shrink-0 bg-[var(--ds-bg-surface)] border-b-[length:var(--ds-border-width)]", border), children: [
12000
12066
  /* @__PURE__ */ jsx(
@@ -12031,7 +12097,7 @@ var TimeViewport = forwardRef(function TimeViewport2({
12031
12097
  ] })
12032
12098
  }
12033
12099
  ),
12034
- /* @__PURE__ */ jsx("div", { "aria-hidden": "true", className: "pointer-events-none absolute inset-0 peer-focus-visible:shadow-[inset_0_0_0_2px_var(--ds-border-focus)] peer-focus-visible:outline-2 peer-focus-visible:-outline-offset-2 peer-focus-visible:outline-transparent" })
12100
+ /* @__PURE__ */ jsx("div", { "aria-hidden": "true", className: cn("pointer-events-none absolute inset-0", PEER_FOCUS_RING, "peer-focus-visible:-outline-offset-[var(--ds-focus-inset)]") })
12035
12101
  ] })
12036
12102
  ] }) }) })
12037
12103
  );
@@ -12089,7 +12155,7 @@ function TimeBar({ start, end, minWidth = 0, labels, children, className, style,
12089
12155
  ...props,
12090
12156
  ref: barRef,
12091
12157
  "data-gs-clip": "",
12092
- className: cn("absolute top-ds-2 bottom-ds-2 flex items-center overflow-clip rounded-[var(--ds-radius-sm)] outline-none focus-visible:outline-hidden focus-visible:shadow-[var(--ds-shadow-focus)]", className),
12158
+ className: cn("absolute top-ds-2 bottom-ds-2 flex items-center overflow-clip rounded-[var(--ds-radius-sm)]", FOCUS_RING, className),
12093
12159
  style: { insetInlineStart: x, width: drawnWidth, ...style },
12094
12160
  children: label
12095
12161
  }
@@ -12233,7 +12299,7 @@ var NO_DATES = "no dates";
12233
12299
  var KNOCKOUT = 2;
12234
12300
  var EDGE = "border-[length:1px] border-transparent";
12235
12301
  var EDGE_WIDTH = 1;
12236
- var SELECTED = "outline-solid outline-2 outline-offset-2 outline-[var(--ds-text-primary)]";
12302
+ var SELECTED = "border-[var(--ds-accent-ink)]";
12237
12303
  var UNDATED_INSET = 16;
12238
12304
  var NO_GROUPS = [];
12239
12305
  var NO_STATUSES = {};
@@ -12279,7 +12345,7 @@ function NoDates({ cue, selected, className, ...props }) {
12279
12345
  "data-gantt-shape": "undated",
12280
12346
  className: cn(
12281
12347
  "sticky flex cursor-pointer items-center gap-ds-1 whitespace-nowrap rounded-[var(--ds-radius-sm)] border-[length:1px] border-dashed border-[var(--ds-border-default)] px-ds-1.5 py-ds-0.5 text-xs text-[var(--ds-text-secondary)]",
12282
- "outline-none focus-visible:outline-hidden focus-visible:shadow-[var(--ds-shadow-focus)]",
12348
+ FOCUS_RING,
12283
12349
  selected && SELECTED,
12284
12350
  className
12285
12351
  ),
@@ -12535,8 +12601,8 @@ function Gantt({
12535
12601
  /* @__PURE__ */ jsx("span", { className: "truncate", children: item.title })
12536
12602
  ] });
12537
12603
  const shapeBox = shape.kind === "milestone" ? (
12538
- // the target's own outline is its focus indicator in forced colours, which drop the diamond's shadow ring
12539
- /* @__PURE__ */ jsx("div", { ...treeitem(row), "aria-selected": isSelected, className: "group absolute grid cursor-pointer place-items-center outline-none focus-visible:outline-hidden", style: { insetInlineStart: (shape.x0 + shape.x1) / 2 - TARGET / 2, top: (ROW_HEIGHT2 - TARGET) / 2, width: TARGET, height: TARGET }, children: /* @__PURE__ */ jsx("span", { "data-gantt-shape": "milestone", "data-item": item.id, className: cn("block rotate-45 rounded-[2px] group-focus-visible:shadow-[var(--ds-shadow-focus)]", EDGE, tone.fill, isSelected && SELECTED), style: { width: DIAMOND, height: DIAMOND } }) })
12604
+ // the diamond draws the target's focus: its outline, which forced colours keep, so the target draws none of its own
12605
+ /* @__PURE__ */ jsx("div", { ...treeitem(row), "aria-selected": isSelected, className: "group absolute grid cursor-pointer place-items-center outline-none", style: { insetInlineStart: (shape.x0 + shape.x1) / 2 - TARGET / 2, top: (ROW_HEIGHT2 - TARGET) / 2, width: TARGET, height: TARGET }, children: /* @__PURE__ */ jsx("span", { "data-gantt-shape": "milestone", "data-item": item.id, className: cn("block rotate-45 rounded-[2px]", GROUP_FOCUS_RING, EDGE, tone.fill, isSelected && SELECTED), style: { width: DIAMOND, height: DIAMOND } }) })
12540
12606
  ) : (
12541
12607
  // TimeBar keeps the title in view beside the pinned column while the bar's start is scrolled away
12542
12608
  /* @__PURE__ */ jsx(
@@ -12558,12 +12624,16 @@ function Gantt({
12558
12624
  return /* @__PURE__ */ jsxs(Fragment, { children: [
12559
12625
  shapeBox,
12560
12626
  place !== "inside" && // Beside the bar, past the turn an arrow makes; its own background keeps lines that cross the row off the
12561
- // text. Once it is partly under the pinned column or past the view's end it is hidden, never a fragment.
12627
+ // text. Once it is partly under the pinned column or past the view's end it is hidden, never a fragment. On the
12628
+ // selected row its background takes the row's tint, as the label's does.
12562
12629
  /* @__PURE__ */ jsx(
12563
12630
  "span",
12564
12631
  {
12565
12632
  "aria-hidden": "true",
12566
- className: "pointer-events-none absolute top-1/2 flex -translate-y-1/2 items-center gap-ds-1 whitespace-nowrap rounded-[var(--ds-radius-sm)] bg-[var(--ds-bg-surface)] text-xs font-medium leading-4 text-[var(--ds-text-primary)]",
12633
+ className: cn(
12634
+ "pointer-events-none absolute top-1/2 flex -translate-y-1/2 items-center gap-ds-1 whitespace-nowrap rounded-[var(--ds-radius-sm)] bg-[var(--ds-bg-surface)] text-xs font-medium leading-4 text-[var(--ds-text-primary)]",
12635
+ isSelected && "bg-[image:linear-gradient(var(--ds-accent-subtle),var(--ds-accent-subtle))]"
12636
+ ),
12567
12637
  style: { insetInlineStart: beside, paddingInline: KNOCKOUT, opacity: `clamp(0, calc(min(${beside} - var(--time-scroll, 0), var(--time-view-end, 1e9) - ${beside + textWidth}) * 1000), 1)` },
12568
12638
  children: title
12569
12639
  }
@@ -12633,7 +12703,7 @@ function Gantt({
12633
12703
  children: /* @__PURE__ */ jsxs("div", { ref: treeRef, role: "tree", "aria-label": ariaLabel, className: "relative", onKeyDown, onFocus: () => setFocusWithin(true), onBlur: onTreeBlur, children: [
12634
12704
  /* @__PURE__ */ jsx("span", { ref: probeRef, "aria-hidden": "true", className: "pointer-events-none invisible absolute whitespace-nowrap text-xs font-medium", children: "0" }),
12635
12705
  /* @__PURE__ */ jsx(GanttArrows, { arrows, width: scale.width, height: rows.length * ROW_HEIGHT2 }),
12636
- rows.map((row) => /* @__PURE__ */ jsx(
12706
+ rows.map((row) => /* @__PURE__ */ jsxs(
12637
12707
  TimeRow,
12638
12708
  {
12639
12709
  "data-row-key": row.key,
@@ -12645,7 +12715,10 @@ function Gantt({
12645
12715
  row.item && row.item.id === selected && "bg-[image:linear-gradient(var(--ds-accent-subtle),var(--ds-accent-subtle))] text-[var(--ds-accent-subtle-text)]"
12646
12716
  ),
12647
12717
  onClick: () => onRowClick(row),
12648
- children: row.group ? renderGroup(row, row.group) : renderItem(row, row.item)
12718
+ children: [
12719
+ row.item && row.item.id === selected && /* @__PURE__ */ jsx("div", { "aria-hidden": "true", className: "absolute inset-0 bg-[var(--ds-accent-subtle)]" }),
12720
+ row.group ? renderGroup(row, row.group) : renderItem(row, row.item)
12721
+ ]
12649
12722
  },
12650
12723
  row.key
12651
12724
  ))
@@ -12700,7 +12773,7 @@ var BUTTON_ELEVATION_SHADOW_ONLY = "shadow-[var(--ds-shadow-button)] active:shad
12700
12773
  var CORNER_SHAPE = cn(BUTTON_ELEVATION, "hover:-translate-y-[var(--ds-hover-lift)]");
12701
12774
  var LAUNCHER_RADIUS = "calc(var(--ds-radius-base) * 4)";
12702
12775
  var ACCENT_GLYPH = cn(
12703
- "text-[var(--ds-accent-primary)]",
12776
+ "text-[var(--ds-accent-ink)]",
12704
12777
  "[&_svg]:[stroke:url(#gs-launcher-gradient)]",
12705
12778
  "[&_svg[fill=currentColor]]:[fill:url(#gs-launcher-gradient-fill)] [&_svg[fill=currentColor]]:[stroke:none]"
12706
12779
  );
@@ -12864,7 +12937,9 @@ function Launcher({
12864
12937
  className: cn(
12865
12938
  container ? "absolute" : "fixed",
12866
12939
  "z-[var(--ds-z-sticky)] inline-flex items-center justify-center cursor-pointer select-none font-medium",
12867
- FOCUS_RING,
12940
+ // a ribbon is flush with the window's edge, where an outline outside it would be cut off: its outline sits inside
12941
+ // (D8), in its own text colour, which reads on its fill as the bold band's does (Sprint 30, P1)
12942
+ isRibbon ? cn(FOCUS_INSET, "[--ds-focus:currentColor]") : FOCUS_RING,
12868
12943
  "transition-[transform,filter,opacity,background-color] duration-[var(--ds-transition-speed)] ease-[var(--ds-transition-ease)]",
12869
12944
  hidden && "invisible pointer-events-none",
12870
12945
  TONE_SURFACE[tone],
@@ -13024,7 +13099,19 @@ function useScrollTrack(activeTab, enabled) {
13024
13099
  ...fadeProps
13025
13100
  };
13026
13101
  }
13027
- var SCROLL_TRACK = "overflow-x-auto overflow-y-hidden [scrollbar-width:none] [&::-webkit-scrollbar]:hidden max-w-full";
13102
+ var SCROLL_TRACK = "overflow-x-auto overflow-y-hidden [scrollbar-width:none] [&::-webkit-scrollbar]:hidden";
13103
+ function TabStrip({ overflow, fullWidth, track, className, children }) {
13104
+ const scrolls = overflow === "scroll";
13105
+ return /* @__PURE__ */ jsx("div", { className: cn("min-w-0 max-w-full", fullWidth && "w-full", className), children: /* @__PURE__ */ jsx(
13106
+ "div",
13107
+ {
13108
+ ...scrolls ? track : {},
13109
+ "data-gs-clip": scrolls ? void 0 : "",
13110
+ className: cn("relative -m-[4px] p-[4px] scroll-px-[4px]", scrolls ? SCROLL_TRACK : "overflow-hidden"),
13111
+ children: /* @__PURE__ */ jsx("div", { role: "tablist", className: cn(trackClasses("horizontal"), scrolls ? "w-max min-w-full" : "w-full"), children })
13112
+ }
13113
+ ) });
13114
+ }
13028
13115
  function getTabsFromDOM(el) {
13029
13116
  const tablist = el.closest('[role="tablist"]');
13030
13117
  if (!tablist) return [];
@@ -13108,11 +13195,11 @@ function TabButton({
13108
13195
  disabled ? "cursor-not-allowed opacity-disabled" : "cursor-pointer",
13109
13196
  "rounded-[var(--ds-nav-v-item-radius)]",
13110
13197
  "transition-colors duration-[var(--ds-transition-speed)]",
13111
- "focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
13198
+ FOCUS_RING,
13112
13199
  // Every item carries the rail width as a transparent placeholder so the
13113
13200
  // label does not shift when the rail appears on the active item.
13114
13201
  "border-l-[length:var(--ds-nav-v-active-rail)]",
13115
- isActive2 ? "bg-[var(--ds-nav-v-active-bg)] text-[var(--ds-nav-v-active-text)] border-[var(--ds-accent-primary)]" : "border-transparent text-[var(--ds-text-secondary)] hover:text-[var(--ds-text-primary)] hover:bg-[var(--ds-tab-hover-bg)]",
13202
+ isActive2 ? "bg-[var(--ds-nav-v-active-bg)] text-[var(--ds-nav-v-active-text)] border-[var(--ds-accent-ink)]" : "border-transparent text-[var(--ds-text-secondary)] hover:text-[var(--ds-text-primary)] hover:bg-[var(--ds-tab-hover-bg)]",
13116
13203
  className
13117
13204
  ),
13118
13205
  children: [
@@ -13148,11 +13235,11 @@ function TabButton({
13148
13235
  !fullWidth && !truncate && "shrink-0 whitespace-nowrap",
13149
13236
  disabled ? "cursor-not-allowed opacity-disabled" : "cursor-pointer",
13150
13237
  "transition-colors duration-[var(--ds-transition-speed)]",
13151
- "focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
13238
+ FOCUS_RING,
13152
13239
  fullWidth && "flex-1",
13153
13240
  truncate && "flex-1 min-w-0 justify-start",
13154
13241
  "rounded-[var(--ds-nav-h-item-radius)]",
13155
- isActive2 ? "bg-[var(--ds-nav-h-active-bg)] text-[var(--ds-nav-h-active-text)] border-[var(--ds-accent-primary)]" : "text-[var(--ds-nav-h-inactive-text)] hover:text-[var(--ds-text-primary)] hover:bg-[var(--ds-nav-h-hover-bg)]",
13242
+ isActive2 ? "bg-[var(--ds-nav-h-active-bg)] text-[var(--ds-nav-h-active-text)] border-[var(--ds-accent-ink)]" : "text-[var(--ds-nav-h-inactive-text)] hover:text-[var(--ds-text-primary)] hover:bg-[var(--ds-nav-h-hover-bg)]",
13156
13243
  className
13157
13244
  ),
13158
13245
  style: isActive2 ? { borderBottomWidth: "var(--ds-nav-h-indicator)", marginBottom: "calc(var(--ds-nav-h-track-border) * -1)" } : void 0,
@@ -13184,22 +13271,7 @@ function TabsList({ children, className }) {
13184
13271
  }
13185
13272
  );
13186
13273
  }
13187
- return /* @__PURE__ */ jsx(
13188
- "div",
13189
- {
13190
- role: "tablist",
13191
- ...overflow === "scroll" ? track : {},
13192
- "data-gs-clip": overflow === "scroll" ? void 0 : "",
13193
- className: cn(
13194
- trackClasses("horizontal"),
13195
- "max-w-full",
13196
- overflow === "hidden" ? "overflow-hidden" : overflow === "truncate" ? "overflow-hidden" : SCROLL_TRACK,
13197
- fullWidth && "w-full",
13198
- className
13199
- ),
13200
- children
13201
- }
13202
- );
13274
+ return /* @__PURE__ */ jsx(TabStrip, { overflow, fullWidth, track, className, children });
13203
13275
  }
13204
13276
  function TabsTrigger({ value, children, count, icon, disabled, truncate, className }) {
13205
13277
  const { activeTab, onTabChange, orientation, fullWidth, overflow } = useTabsCtx();
@@ -13231,7 +13303,7 @@ function TabsContent({ value, children, className }) {
13231
13303
  role: "tabpanel",
13232
13304
  "aria-labelledby": `ds-tab-${value}`,
13233
13305
  tabIndex: 0,
13234
- className,
13306
+ className: cn(FOCUS_RING, className),
13235
13307
  children
13236
13308
  }
13237
13309
  );
@@ -13291,22 +13363,7 @@ function TabsRoot(props) {
13291
13363
  }
13292
13364
  );
13293
13365
  }
13294
- const effectiveOverflow = arrayOverflow;
13295
- return /* @__PURE__ */ jsx(
13296
- "div",
13297
- {
13298
- role: "tablist",
13299
- ...effectiveOverflow === "scroll" ? track : {},
13300
- "data-gs-clip": effectiveOverflow === "scroll" ? void 0 : "",
13301
- className: cn(
13302
- trackClasses("horizontal"),
13303
- effectiveOverflow === "scroll" ? SCROLL_TRACK : "overflow-hidden",
13304
- fullWidth && "w-full",
13305
- className
13306
- ),
13307
- children: tabs.map((tab) => /* @__PURE__ */ jsx(TabButton, { hasPanel: false, ...tab, orientation: effectiveOrientation, activeTab, onTabChange, fullWidth, onKeyDown: (e) => handleTabKeyDown(e, tab.id, () => tabs, effectiveOrientation, onTabChange) }, tab.id))
13308
- }
13309
- );
13366
+ return /* @__PURE__ */ jsx(TabStrip, { overflow: arrayOverflow, fullWidth, track, className, children: tabs.map((tab) => /* @__PURE__ */ jsx(TabButton, { hasPanel: false, ...tab, orientation: effectiveOrientation, activeTab, onTabChange, fullWidth, onKeyDown: (e) => handleTabKeyDown(e, tab.id, () => tabs, effectiveOrientation, onTabChange) }, tab.id)) });
13310
13367
  }
13311
13368
  return /* @__PURE__ */ jsx(TabsContext.Provider, { value: { activeTab, onTabChange, orientation: effectiveOrientation, fullWidth, overflow }, children: /* @__PURE__ */ jsx("div", { className, children: props.children }) });
13312
13369
  }
@@ -13454,7 +13511,7 @@ function Stepper({ steps, currentStep, onStepChange, orientation = "horizontal",
13454
13511
  {
13455
13512
  className: cn(
13456
13513
  "text-xs font-medium",
13457
- status === "current" ? "text-[var(--ds-accent-primary)]" : kindOf2(step) === "locked" ? "text-[var(--ds-text-muted)]" : "text-[var(--ds-text-primary)]"
13514
+ status === "current" ? "text-[var(--ds-accent-ink)]" : kindOf2(step) === "locked" ? "text-[var(--ds-text-muted)]" : "text-[var(--ds-text-primary)]"
13458
13515
  ),
13459
13516
  children: step.label
13460
13517
  }
@@ -13487,7 +13544,7 @@ function Stepper({ steps, currentStep, onStepChange, orientation = "horizontal",
13487
13544
  {
13488
13545
  className: cn(
13489
13546
  "text-xs font-medium leading-8",
13490
- status === "current" ? "text-[var(--ds-accent-primary)]" : kindOf2(step) === "locked" ? "text-[var(--ds-text-muted)]" : "text-[var(--ds-text-primary)]"
13547
+ status === "current" ? "text-[var(--ds-accent-ink)]" : kindOf2(step) === "locked" ? "text-[var(--ds-text-muted)]" : "text-[var(--ds-text-primary)]"
13491
13548
  ),
13492
13549
  children: step.label
13493
13550
  }
@@ -13534,7 +13591,7 @@ function Stepper({ steps, currentStep, onStepChange, orientation = "horizontal",
13534
13591
  {
13535
13592
  className: cn(
13536
13593
  "text-xs font-medium",
13537
- status === "current" ? "text-[var(--ds-accent-primary)]" : kindOf2(step) === "locked" ? "text-[var(--ds-text-muted)]" : "text-[var(--ds-text-primary)]"
13594
+ status === "current" ? "text-[var(--ds-accent-ink)]" : kindOf2(step) === "locked" ? "text-[var(--ds-text-muted)]" : "text-[var(--ds-text-primary)]"
13538
13595
  ),
13539
13596
  children: step.label
13540
13597
  }
@@ -13552,9 +13609,10 @@ function StepCircle({ status, index, label, kind, onClick }) {
13552
13609
  const look = cn(
13553
13610
  "flex items-center justify-center shrink-0 w-8 h-8 rounded-[var(--ds-radius-full)] text-xs font-bold transition-colors",
13554
13611
  status === "complete" && "bg-[var(--ds-accent-primary)] [background-image:var(--ds-gradient)] text-[var(--ds-text-on-primary)]",
13555
- status === "current" && `border-2 ${ACTIVE_RING} text-[var(--ds-accent-primary)] bg-[var(--ds-bg-surface)]`,
13612
+ // the current step is chosen, not active (D2): the accent border, never the halo
13613
+ status === "current" && "border-2 border-[var(--ds-accent-ink)] text-[var(--ds-accent-ink)] bg-[var(--ds-bg-surface)]",
13556
13614
  status === "error" && "bg-[var(--ds-status-error)] text-[var(--ds-text-on-error)]",
13557
- status === "loading" && `border-2 ${ACTIVE_RING} text-[var(--ds-accent-primary)] bg-[var(--ds-bg-surface)] animate-pulse`,
13615
+ status === "loading" && "border-2 border-[var(--ds-accent-ink)] text-[var(--ds-accent-ink)] bg-[var(--ds-bg-surface)] animate-pulse",
13558
13616
  status === "upcoming" && "border-[length:var(--ds-border-width)] border-[var(--ds-border-default)] text-[var(--ds-text-muted)] bg-[var(--ds-bg-surface)]"
13559
13617
  );
13560
13618
  const glyph = status === "complete" ? /* @__PURE__ */ jsx(Icon, { name: "check", size: 14 }) : status === "error" ? /* @__PURE__ */ jsx(Icon, { name: "warning", size: 14 }) : index + 1;
@@ -13571,10 +13629,10 @@ function StepCircle({ status, index, label, kind, onClick }) {
13571
13629
  "aria-current": status === "current" ? "step" : void 0,
13572
13630
  className: cn(
13573
13631
  look,
13574
- "focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
13632
+ FOCUS_RING,
13575
13633
  kind === "open" ? "cursor-pointer" : "cursor-not-allowed opacity-disabled",
13576
13634
  // a step reached but not done (the user went back) can be gone to: it answers the pointer as the done ones do
13577
- status === "upcoming" && kind === "open" && "hover:border-[var(--ds-accent-primary)] hover:text-[var(--ds-accent-primary)]"
13635
+ status === "upcoming" && kind === "open" && "hover:border-[var(--ds-accent-ink)] hover:text-[var(--ds-accent-ink)]"
13578
13636
  ),
13579
13637
  children: glyph
13580
13638
  }
@@ -13588,6 +13646,12 @@ function ScrollArea({
13588
13646
  maxWidth
13589
13647
  }) {
13590
13648
  const viewportRef = useRef(null);
13649
+ const [viewport, setViewport] = useState(null);
13650
+ useRevealFocus(viewport);
13651
+ const viewportRefs = useCallback((node) => {
13652
+ viewportRef.current = node;
13653
+ setViewport(node);
13654
+ }, []);
13591
13655
  const [thumbY, setThumbY] = useState({ top: 0, height: 0, visible: false });
13592
13656
  const [thumbX, setThumbX] = useState({ left: 0, width: 0, visible: false });
13593
13657
  const [hovering, setHovering] = useState(false);
@@ -13675,10 +13739,10 @@ function ScrollArea({
13675
13739
  /* @__PURE__ */ jsx(
13676
13740
  "div",
13677
13741
  {
13678
- ref: viewportRef,
13742
+ ref: viewportRefs,
13679
13743
  onScroll: updateThumbs,
13680
13744
  className: cn(
13681
- "h-full w-full",
13745
+ "h-full w-full scroll-p-[4px]",
13682
13746
  orientation === "vertical" && "overflow-y-auto overflow-x-hidden",
13683
13747
  orientation === "horizontal" && "overflow-x-auto overflow-y-hidden",
13684
13748
  orientation === "both" && "overflow-auto",
@@ -13802,6 +13866,8 @@ var Sidebar = forwardRef(function Sidebar2({
13802
13866
  "flex flex-col shrink-0 h-full",
13803
13867
  isFloating ? cn("rounded-[var(--ds-radius-md)] border-[length:var(--ds-border-width)] border-[var(--ds-sidebar-border)]", GLASS_SURFACE) : !isMinimal && "border-r-[length:var(--ds-border-width)] border-[var(--ds-sidebar-border)]",
13804
13868
  "text-[var(--ds-sidebar-text)]",
13869
+ // keyboard focus in the sidebar's own focus colour, derived against its background (Sprint 30, P2)
13870
+ "[--ds-focus:var(--ds-sidebar-focus)]",
13805
13871
  isMinimal ? "bg-transparent" : "bg-[var(--ds-sidebar-bg)]",
13806
13872
  !isMinimal && !isFloating && GLASS_BACKDROP,
13807
13873
  !isFloating && "transition-[width] duration-[var(--ds-transition-speed)] ease-[var(--ds-transition-ease)]",
@@ -13840,7 +13906,7 @@ var Sidebar = forwardRef(function Sidebar2({
13840
13906
  isSm ? "py-ds-1.5 text-xs" : "py-ds-2 text-sm",
13841
13907
  "transition-colors cursor-pointer",
13842
13908
  "text-[var(--ds-sidebar-text-muted)] hover:bg-[var(--ds-sidebar-item-hover)] hover:text-[var(--ds-sidebar-text)]",
13843
- "focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
13909
+ FOCUS_RING,
13844
13910
  collapsed ? "justify-center px-0" : "px-ds-3"
13845
13911
  ),
13846
13912
  style: { marginBottom: "var(--ds-space-3)" },
@@ -14004,6 +14070,7 @@ function CompactFlyout({
14004
14070
  },
14005
14071
  className: cn(
14006
14072
  "flex items-center gap-ds-2 px-ds-2 py-ds-1.5 text-xs rounded-[var(--ds-radius-sm)] transition-colors cursor-pointer",
14073
+ FOCUS_RING,
14007
14074
  child.active ? "bg-[var(--ds-sidebar-active-bg)] [background-image:var(--ds-sidebar-active-image)] text-[var(--ds-sidebar-active-accent)] font-medium" : "text-[var(--ds-sidebar-text-secondary)] hover:bg-[var(--ds-sidebar-item-hover)] hover:text-[var(--ds-sidebar-text)]"
14008
14075
  ),
14009
14076
  children: [
@@ -14102,6 +14169,7 @@ function SidebarNav({
14102
14169
  },
14103
14170
  className: cn(
14104
14171
  "flex items-center gap-ds-2 transition-colors cursor-pointer",
14172
+ FOCUS_RING,
14105
14173
  isRoot ? cn(rootPy, rootText, isMinimal ? "rounded-[var(--ds-radius-full)]" : "rounded-[var(--ds-radius-md)]") : cn(childPy, "text-xs rounded-[var(--ds-radius-sm)]"),
14106
14174
  isRoot ? collapsed ? "justify-center px-0" : "px-ds-3" : "px-ds-2",
14107
14175
  // Active style comes from the theme's --ds-sidebar-active-* tokens
@@ -14188,6 +14256,7 @@ function SidebarNav({
14188
14256
  "aria-expanded": isExpanded,
14189
14257
  className: cn(
14190
14258
  "flex items-center gap-ds-2 w-full text-left transition-colors cursor-pointer",
14259
+ FOCUS_RING,
14191
14260
  isRoot ? cn(rootPy, rootText, isMinimal ? "rounded-[var(--ds-radius-full)]" : "rounded-[var(--ds-radius-md)]") : cn(childPy, "text-xs rounded-[var(--ds-radius-sm)]"),
14192
14261
  isRoot ? collapsed ? "justify-center px-0" : "px-ds-3" : "px-ds-2",
14193
14262
  // This row has no fill, so its label, icon and chevron keep the plain
@@ -14201,7 +14270,7 @@ function SidebarNav({
14201
14270
  {
14202
14271
  name: item.icon,
14203
14272
  size: isRoot ? rootIconSize : childIconSize,
14204
- className: cn("shrink-0", (item.active || childActive) && "text-[var(--ds-sidebar-accent)]")
14273
+ className: cn("shrink-0", (item.active || childActive) && "text-[var(--ds-sidebar-accent-ink)]")
14205
14274
  }
14206
14275
  ),
14207
14276
  !collapsed && /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -14214,7 +14283,7 @@ function SidebarNav({
14214
14283
  size: 12,
14215
14284
  className: cn(
14216
14285
  "shrink-0 transition-transform",
14217
- item.active || childActive ? "text-[var(--ds-sidebar-accent)]" : "text-[var(--ds-sidebar-text-muted)]",
14286
+ item.active || childActive ? "text-[var(--ds-sidebar-accent-ink)]" : "text-[var(--ds-sidebar-text-muted)]",
14218
14287
  isExpanded && "rotate-90"
14219
14288
  )
14220
14289
  }
@@ -14307,7 +14376,7 @@ function SidebarNav({
14307
14376
  /* @__PURE__ */ jsx(
14308
14377
  "nav",
14309
14378
  {
14310
- className: "flex-1 flex flex-col",
14379
+ className: "flex-1 flex flex-col [--ds-focus:var(--ds-sidebar-focus)]",
14311
14380
  style: { padding: "var(--ds-space-3) var(--ds-space-2)", gap: "var(--ds-space-3)" },
14312
14381
  children: navContent
14313
14382
  }
@@ -14322,6 +14391,8 @@ function SidebarNav({
14322
14391
  "flex items-center gap-ds-2 mx-ds-2 rounded-[var(--ds-radius-md)] transition-colors cursor-pointer",
14323
14392
  isSm ? "py-ds-1.5 text-xs" : "py-ds-2 text-sm",
14324
14393
  "text-[var(--ds-sidebar-text-muted)] hover:bg-[var(--ds-sidebar-item-hover)] hover:text-[var(--ds-sidebar-text)]",
14394
+ "[--ds-focus:var(--ds-sidebar-focus)]",
14395
+ FOCUS_RING,
14325
14396
  collapsed ? "justify-center px-0" : "px-ds-3"
14326
14397
  ),
14327
14398
  style: { marginBottom: "var(--ds-space-3)" },
@@ -14398,6 +14469,7 @@ function CompactNavItem({
14398
14469
  "aria-controls": !mobile && hasChildren && isOpen ? flyoutId : void 0,
14399
14470
  className: cn(
14400
14471
  "relative flex flex-col items-center justify-center gap-[3px] w-full py-ds-3 px-ds-1 rounded-[var(--ds-radius-md)] transition-colors cursor-pointer",
14472
+ FOCUS_RING,
14401
14473
  // Compact tiles have no edge to stroke: they read the fill and text
14402
14474
  // tokens only, never --ds-sidebar-active-rail.
14403
14475
  item.active || childActive ? "bg-[var(--ds-sidebar-active-bg)] [background-image:var(--ds-sidebar-active-image)] text-[var(--ds-sidebar-active-accent)]" : "text-[var(--ds-sidebar-text-secondary)] hover:bg-[var(--ds-sidebar-item-hover)] hover:text-[var(--ds-sidebar-text)]"
@@ -14449,6 +14521,7 @@ function CompactNavItem({
14449
14521
  onClick: () => onItemClick?.(child, ci),
14450
14522
  className: cn(
14451
14523
  "flex items-center gap-ds-2 px-ds-3 py-ds-1.5 text-[length:var(--ds-font-size-xs)] rounded-[var(--ds-radius-sm)] transition-colors cursor-pointer w-full",
14524
+ FOCUS_RING,
14452
14525
  child.active ? "bg-[var(--ds-sidebar-active-bg)] [background-image:var(--ds-sidebar-active-image)] text-[var(--ds-sidebar-active-accent)] font-medium" : "text-[var(--ds-sidebar-text-muted)] hover:bg-[var(--ds-sidebar-item-hover)] hover:text-[var(--ds-sidebar-text)]"
14453
14526
  ),
14454
14527
  children: [
@@ -14466,6 +14539,12 @@ var variantStyles4 = {
14466
14539
  warning: "border-[var(--ds-status-warning)] bg-[var(--ds-status-warning-bg)]",
14467
14540
  error: "border-[var(--ds-status-error)] bg-[var(--ds-status-error-bg)]"
14468
14541
  };
14542
+ var actionStyles = {
14543
+ default: "text-[var(--ds-accent-ink)]",
14544
+ success: "text-[var(--ds-status-success-text)]",
14545
+ warning: "text-[var(--ds-status-warning-text)]",
14546
+ error: "text-[var(--ds-status-error-text)]"
14547
+ };
14469
14548
  var variantIcons = {
14470
14549
  default: { name: "info", className: "text-[var(--ds-text-muted)]" },
14471
14550
  success: { name: "check", className: "text-[var(--ds-status-success)]" },
@@ -14573,7 +14652,7 @@ function Toast({ variant = "default", message, visible, onDismiss, duration = 5e
14573
14652
  {
14574
14653
  type: "button",
14575
14654
  onClick: pressAction,
14576
- className: "shrink-0 text-xs font-semibold text-[var(--ds-accent-primary)] hover:underline cursor-pointer",
14655
+ className: cn("shrink-0 text-xs font-semibold hover:underline cursor-pointer", actionStyles[variant], FOCUS_RING),
14577
14656
  children: action.label
14578
14657
  }
14579
14658
  ),
@@ -14583,7 +14662,7 @@ function Toast({ variant = "default", message, visible, onDismiss, duration = 5e
14583
14662
  type: "button",
14584
14663
  onClick: onDismiss,
14585
14664
  "aria-label": "Dismiss notification",
14586
- className: "text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] transition-colors cursor-pointer shrink-0",
14665
+ className: cn("text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] transition-colors cursor-pointer shrink-0", FOCUS_RING),
14587
14666
  children: /* @__PURE__ */ jsx(Icon, { name: "close", size: 16 })
14588
14667
  }
14589
14668
  )
@@ -14961,7 +15040,7 @@ function ToastProvider({ children, maxVisible = 3, position = "bottom-right", du
14961
15040
  waiting,
14962
15041
  /* @__PURE__ */ jsx("span", { className: "sr-only", children: " more waiting" })
14963
15042
  ] }),
14964
- /* @__PURE__ */ jsx("button", { type: "button", onClick: dismissAll, className: "font-medium text-[var(--ds-text-secondary)] hover:text-[var(--ds-text-primary)] hover:underline cursor-pointer", children: "Clear all" })
15043
+ /* @__PURE__ */ jsx("button", { type: "button", onClick: dismissAll, className: cn("font-medium text-[var(--ds-text-secondary)] hover:text-[var(--ds-text-primary)] hover:underline cursor-pointer", FOCUS_RING), children: "Clear all" })
14965
15044
  ] })
14966
15045
  ]
14967
15046
  }
@@ -15014,7 +15093,9 @@ function BottomNav({ items, onItemClick, maxVisible = 5, className, ref }) {
15014
15093
  className: cn(
15015
15094
  "flex flex-col items-center justify-center gap-ds-0.5 w-full h-full",
15016
15095
  "text-2xs font-medium transition-colors cursor-pointer",
15017
- overflowHasActive || overflowOpen ? "text-[var(--ds-accent-primary)]" : "text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)]"
15096
+ // flush with the window's edge, as every bar item is: the outline sits inside (D8)
15097
+ FOCUS_INSET,
15098
+ overflowHasActive || overflowOpen ? "text-[var(--ds-accent-ink)]" : "text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)]"
15018
15099
  ),
15019
15100
  children: [
15020
15101
  /* @__PURE__ */ jsx(Icon, { name: "grip-vertical", size: 20 }),
@@ -15043,9 +15124,11 @@ function BottomNav({ items, onItemClick, maxVisible = 5, className, ref }) {
15043
15124
  },
15044
15125
  className: cn(
15045
15126
  "flex items-center gap-ds-2 w-full px-ds-3 py-ds-2 text-sm transition-colors cursor-pointer",
15046
- // The panel clips, so focus is a row tint (never an outline that the corner would trim).
15047
- "focus-visible:outline-none focus-visible:bg-[var(--ds-bg-muted)] focus-visible:text-[var(--ds-text-primary)]",
15048
- item.active ? "text-[var(--ds-accent-primary)] font-medium bg-[var(--ds-bg-muted)]" : "text-[var(--ds-text-secondary)] hover:bg-[var(--ds-bg-muted)] hover:text-[var(--ds-text-primary)]"
15127
+ // Keyboard focus keeps the row tint and adds the shared outline, inside the row: the menu clips its
15128
+ // full-width rows, which are never filled solid (Sprint 30, P3)
15129
+ "focus-visible:bg-[var(--ds-bg-muted)] focus-visible:text-[var(--ds-text-primary)]",
15130
+ FOCUS_INSET,
15131
+ item.active ? "text-[var(--ds-accent-ink)] font-medium bg-[var(--ds-bg-muted)]" : "text-[var(--ds-text-secondary)] hover:bg-[var(--ds-bg-muted)] hover:text-[var(--ds-text-primary)]"
15049
15132
  ),
15050
15133
  children: [
15051
15134
  /* @__PURE__ */ jsx(Icon, { name: item.icon, size: 16 }),
@@ -15070,7 +15153,9 @@ function NavButton({ item, onClick }) {
15070
15153
  className: cn(
15071
15154
  "flex flex-col items-center justify-center gap-ds-0.5 flex-1 h-full",
15072
15155
  "text-2xs font-medium transition-colors cursor-pointer",
15073
- item.active ? "text-[var(--ds-accent-primary)]" : "text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)]"
15156
+ // flush with the window's edge (the bar's foot and its ends): the outline sits inside, where it shows whole (D8)
15157
+ FOCUS_INSET,
15158
+ item.active ? "text-[var(--ds-accent-ink)]" : "text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)]"
15074
15159
  ),
15075
15160
  children: [
15076
15161
  /* @__PURE__ */ jsx(Icon, { name: item.icon, size: 20 }),
@@ -15401,7 +15486,7 @@ function outerHeight(el) {
15401
15486
  function Breadcrumbs2({ items, onLight, onTint, pill, separator = "chevron" }) {
15402
15487
  const follow2 = useCrumbFollow();
15403
15488
  if (!items.length) return null;
15404
- const mutedCls = onLight ? "text-[var(--ds-text-on-primary)]/40" : onTint ? "text-[var(--ds-text-muted-on-tint)]" : "text-[var(--ds-text-secondary)]";
15489
+ const mutedCls = onLight ? "text-[var(--ds-text-on-primary-muted)]" : onTint ? "text-[var(--ds-text-muted-on-tint)]" : "text-[var(--ds-text-secondary)]";
15405
15490
  const sepEl = (key) => {
15406
15491
  const cls = cn("select-none flex items-center", mutedCls);
15407
15492
  if (separator === "slash") return /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: cls, children: "/" }, `s${key}`);
@@ -15425,13 +15510,15 @@ function Breadcrumbs2({ items, onLight, onTint, pill, separator = "chevron" }) {
15425
15510
  onClick: (e) => follow2(e, item),
15426
15511
  className: cn(
15427
15512
  "transition-colors duration-[var(--ds-transition-speed)]",
15428
- onLight ? "text-[var(--ds-text-on-primary)]/60 hover:text-[var(--ds-text-on-primary)]/90" : cn(mutedCls, "hover:text-[var(--ds-text-primary)]"),
15429
- pillCls
15513
+ // on the band, the band's quieter text, its full text on hover (the quieter text can be 90%)
15514
+ onLight ? "text-[var(--ds-text-on-primary-muted)] hover:text-[var(--ds-text-on-primary)]" : cn(mutedCls, "hover:text-[var(--ds-text-primary)]"),
15515
+ pillCls,
15516
+ FOCUS_RING
15430
15517
  ),
15431
15518
  children: item.label
15432
15519
  }
15433
15520
  ) : /* @__PURE__ */ jsx("span", { "aria-current": isCurrent ? "page" : void 0, className: cn(
15434
- isCurrent ? cn("font-medium", onLight ? "text-[var(--ds-text-on-primary)]/80" : "text-[var(--ds-text-primary)]") : onLight ? "text-[var(--ds-text-on-primary)]/60" : mutedCls,
15521
+ isCurrent ? cn("font-medium", onLight ? "text-[var(--ds-text-on-primary-muted)]" : "text-[var(--ds-text-primary)]") : onLight ? "text-[var(--ds-text-on-primary-muted)]" : mutedCls,
15435
15522
  pillCls
15436
15523
  ), children: item.label })
15437
15524
  ] }, i);
@@ -15462,8 +15549,8 @@ function BackButton({ onLight, onClick }) {
15462
15549
  "flex items-center justify-center shrink-0 cursor-pointer",
15463
15550
  "w-[var(--ds-control-height-sm)] h-[var(--ds-control-height-sm)] rounded-[var(--ds-radius-md)]",
15464
15551
  "transition-colors duration-[var(--ds-transition-speed)]",
15465
- "focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
15466
- onLight ? "bg-[var(--ds-text-on-primary)]/10 text-[var(--ds-text-on-primary)]/80 hover:bg-[var(--ds-text-on-primary)]/20 hover:text-[var(--ds-text-on-primary)]" : [
15552
+ FOCUS_RING,
15553
+ onLight ? "bg-[var(--ds-text-on-primary)]/10 text-[var(--ds-text-on-primary-muted)] hover:bg-[var(--ds-text-on-primary)]/20 hover:text-[var(--ds-text-on-primary)]" : [
15467
15554
  "bg-[var(--ds-bg-surface)] text-[var(--ds-text-secondary)]",
15468
15555
  "border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]",
15469
15556
  "hover:text-[var(--ds-text-primary)] hover:bg-[var(--ds-bg-muted)]"
@@ -15481,8 +15568,9 @@ function BackLink({ onClick, onLight }) {
15481
15568
  onClick,
15482
15569
  className: cn(
15483
15570
  "inline-flex items-center gap-ds-1 mb-ds-3 text-sm underline underline-offset-4 cursor-pointer",
15484
- "rounded-[var(--ds-radius-sm)] focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
15485
- onLight ? "text-[var(--ds-text-on-primary)]" : "text-[var(--ds-text-primary)] hover:text-[var(--ds-accent-primary)]"
15571
+ "rounded-[var(--ds-radius-sm)]",
15572
+ FOCUS_RING,
15573
+ onLight ? "text-[var(--ds-text-on-primary)]" : "text-[var(--ds-text-primary)] hover:text-[var(--ds-accent-ink)]"
15486
15574
  ),
15487
15575
  children: [
15488
15576
  /* @__PURE__ */ jsx(Icon, { name: "chevron-left", size: 14 }),
@@ -15494,11 +15582,13 @@ function BackLink({ onClick, onLight }) {
15494
15582
  function Caption({ children, onLight, onTint }) {
15495
15583
  return /* @__PURE__ */ jsx("p", { className: cn(
15496
15584
  "mb-ds-1 text-sm font-medium",
15497
- onLight ? "text-[var(--ds-text-on-primary)]/80" : onTint ? "text-[var(--ds-text-muted-on-tint)]" : "text-[var(--ds-text-secondary)]"
15585
+ onLight ? "text-[var(--ds-text-on-primary-muted)]" : onTint ? "text-[var(--ds-text-muted-on-tint)]" : "text-[var(--ds-text-secondary)]"
15498
15586
  ), children });
15499
15587
  }
15500
15588
  var ON_BAND_STRIP = cn(
15501
15589
  "rounded-[var(--ds-radius-md)] px-ds-3 py-ds-2 border-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]",
15590
+ // on the surface, the page's focus colour again, which the band kept for it (Sprint 30, P2)
15591
+ "[--ds-focus:var(--gs-page-focus)]",
15502
15592
  "bg-[var(--ds-bg-surface)] supports-[color:oklch(from_red_l_c_h)]:bg-[oklch(from_var(--ds-bg-surface)_l_c_h_/_max(alpha,min(1,alpha*1000)*0.6))]",
15503
15593
  GLASS_SURFACE
15504
15594
  );
@@ -15875,7 +15965,7 @@ function ColourfulHeader({
15875
15965
  className: cn(
15876
15966
  "relative overflow-hidden w-full",
15877
15967
  !isFloating && !overlapActive && !noBottomMargin && "mb-ds-6",
15878
- isBold ? "bg-[var(--ds-accent-primary)] [background-image:var(--ds-gradient)] [background-origin:border-box]" : "bg-[var(--ds-tint-base)]",
15968
+ isBold ? "bg-[var(--ds-accent-primary)] [background-image:var(--ds-gradient)] [background-origin:border-box] [--gs-page-focus:var(--ds-focus)]" : "bg-[var(--ds-tint-base)]",
15879
15969
  isFloating ? cn(
15880
15970
  "rounded-[var(--ds-radius-md)]",
15881
15971
  "border-[length:var(--ds-border-width)]",
@@ -15906,7 +15996,9 @@ function ColourfulHeader({
15906
15996
  className: cn(
15907
15997
  "relative z-10 w-full mx-auto pb-ds-6",
15908
15998
  gutter && "px-ds-6",
15909
- hasBreadcrumbs ? "pt-ds-3" : "pt-ds-6"
15999
+ hasBreadcrumbs ? "pt-ds-3" : "pt-ds-6",
16000
+ // on the band, keyboard focus is the band's text colour, the one colour proven against all it paints (P1, P2)
16001
+ isBold && "[--ds-focus:var(--ds-text-on-primary)]"
15910
16002
  ),
15911
16003
  style: {
15912
16004
  maxWidth: gutter ? contentMaxWidth ?? "var(--ds-bp-xl)" : void 0,
@@ -15936,7 +16028,7 @@ function ColourfulHeader({
15936
16028
  ] }),
15937
16029
  description && /* @__PURE__ */ jsx(ClampedText, { className: cn(
15938
16030
  "mt-ds-1 text-sm",
15939
- isBold ? "text-[var(--ds-text-on-primary)]/70" : "text-[var(--ds-text-secondary)]"
16031
+ isBold ? "text-[var(--ds-text-on-primary-muted)]" : "text-[var(--ds-text-secondary)]"
15940
16032
  ), children: description })
15941
16033
  ] })
15942
16034
  ] }),
@@ -16090,11 +16182,11 @@ function SnappingHeader({
16090
16182
  "relative overflow-hidden",
16091
16183
  "rounded-[var(--ds-radius-md)]",
16092
16184
  "border-[length:var(--ds-border-width)]",
16093
- isBoldColourful ? "border-[color-mix(in_srgb,var(--ds-accent-primary)_70%,black)] bg-[var(--ds-accent-primary)] [background-image:var(--ds-gradient)] [background-origin:border-box]" : cn("border-[var(--ds-border-subtle)] bg-[var(--ds-tint-base)]", GLASS_SURFACE)
16185
+ isBoldColourful ? "border-[color-mix(in_srgb,var(--ds-accent-primary)_70%,black)] bg-[var(--ds-accent-primary)] [background-image:var(--ds-gradient)] [background-origin:border-box] [--gs-page-focus:var(--ds-focus)]" : cn("border-[var(--ds-border-subtle)] bg-[var(--ds-tint-base)]", GLASS_SURFACE)
16094
16186
  ] : [
16095
16187
  "relative overflow-hidden",
16096
16188
  !overlapActive && !wrapperHasCard && "mb-ds-6",
16097
- isBoldColourful ? "bg-[var(--ds-accent-primary)] [background-image:var(--ds-gradient)] [background-origin:border-box] border-b-[2px] border-[color-mix(in_srgb,var(--ds-accent-primary)_70%,black)]" : "bg-[var(--ds-tint-base)] border-b-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]"
16189
+ isBoldColourful ? "bg-[var(--ds-accent-primary)] [background-image:var(--ds-gradient)] [background-origin:border-box] border-b-[2px] border-[color-mix(in_srgb,var(--ds-accent-primary)_70%,black)] [--gs-page-focus:var(--ds-focus)]" : "bg-[var(--ds-tint-base)] border-b-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]"
16098
16190
  ]),
16099
16191
  !collapsed && !isColourful && isFloating && !wrapperHasCard && FLOATING_HEADER,
16100
16192
  className
@@ -16137,6 +16229,8 @@ function SnappingHeader({
16137
16229
  className: cn(
16138
16230
  "transition-all duration-[var(--ds-transition-speed)] ease-[var(--ds-transition-ease)]",
16139
16231
  isColourful && !collapsed && "relative z-10",
16232
+ // on the band, keyboard focus is the band's text colour, as the colourful header's (P1, P2)
16233
+ onLight && "[--ds-focus:var(--ds-text-on-primary)]",
16140
16234
  collapsed ? cn("flex items-center justify-between gap-ds-4 py-ds-2", !effectiveMaxWidth && "px-ds-4") : [
16141
16235
  (!isColourful || !overlapActive) && "pb-ds-6",
16142
16236
  hasBreadcrumbs && !hideExpandedBreadcrumbs ? "pt-ds-3" : "pt-ds-6"
@@ -16171,7 +16265,7 @@ function SnappingHeader({
16171
16265
  } : {},
16172
16266
  className: cn(
16173
16267
  "text-sm hidden @sm:inline-flex items-center gap-ds-1",
16174
- isClickable ? "text-[var(--ds-text-secondary)] hover:text-[var(--ds-text-primary)] transition-colors duration-[var(--ds-transition-speed)] cursor-pointer" : "text-[var(--ds-text-secondary)]"
16268
+ isClickable ? cn("text-[var(--ds-text-secondary)] hover:text-[var(--ds-text-primary)] transition-colors duration-[var(--ds-transition-speed)] cursor-pointer", FOCUS_RING) : "text-[var(--ds-text-secondary)]"
16175
16269
  ),
16176
16270
  children: [
16177
16271
  lastCrumb?.label,
@@ -16188,7 +16282,7 @@ function SnappingHeader({
16188
16282
  ] }),
16189
16283
  !collapsed && description && /* @__PURE__ */ jsx(ClampedText, { className: cn(
16190
16284
  "mt-ds-1 text-sm",
16191
- onLight ? "text-[var(--ds-text-on-primary)]/70" : "text-[var(--ds-text-secondary)]"
16285
+ onLight ? "text-[var(--ds-text-on-primary-muted)]" : "text-[var(--ds-text-secondary)]"
16192
16286
  ), children: description })
16193
16287
  ] })
16194
16288
  ] }),
@@ -16382,7 +16476,7 @@ function Dock({
16382
16476
  "border-[length:var(--ds-border-width)] border-[var(--ds-border-default)]",
16383
16477
  "shadow-[var(--ds-shadow-button)]",
16384
16478
  "cursor-pointer origin-bottom",
16385
- "focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]"
16479
+ FOCUS_RING
16386
16480
  ),
16387
16481
  style: {
16388
16482
  width: baseSize,
@@ -16431,8 +16525,9 @@ function Dock({
16431
16525
  }
16432
16526
  );
16433
16527
  }
16528
+ var NAV_ITEM_TYPES = /* @__PURE__ */ new Set(["tint", "underline", "minimal", "pill"]);
16434
16529
  function resolveNavItemType(type) {
16435
- return type === "default" ? "tint" : type;
16530
+ return type !== void 0 && NAV_ITEM_TYPES.has(type) ? type : "tint";
16436
16531
  }
16437
16532
  var NavbarTypeContext = createContext("tint");
16438
16533
  var NavItem = forwardRef(function NavItem2({ label, icon, active = false, href, onClick, type: typeProp, className, children }, ref) {
@@ -16442,7 +16537,7 @@ var NavItem = forwardRef(function NavItem2({ label, icon, active = false, href,
16442
16537
  "inline-flex items-center gap-ds-2 cursor-pointer select-none whitespace-nowrap",
16443
16538
  // one line: the navbar measures each link (round 12)
16444
16539
  "transition-colors duration-[var(--ds-transition-speed)] ease-[var(--ds-transition-ease)]",
16445
- "focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
16540
+ FOCUS_RING,
16446
16541
  "text-[length:var(--ds-font-size-sm)]"
16447
16542
  );
16448
16543
  const typeClasses = getTypeClasses(type, active);
@@ -16477,12 +16572,12 @@ function getTypeClasses(type, active) {
16477
16572
  case "minimal":
16478
16573
  return cn(
16479
16574
  "px-ds-2 py-ds-1",
16480
- active ? "text-[var(--ds-accent-primary)] font-medium" : "text-[var(--ds-text-muted)] hover:text-[var(--ds-text-secondary)]"
16575
+ active ? "text-[var(--ds-accent-ink)] font-medium" : "text-[var(--ds-text-muted)] hover:text-[var(--ds-text-secondary)]"
16481
16576
  );
16482
16577
  case "tint":
16483
16578
  return cn(
16484
16579
  "px-ds-2 py-ds-1 rounded-[var(--ds-radius-sm)]",
16485
- active ? "bg-[var(--ds-accent-subtle)] text-[var(--ds-accent-primary)] font-[var(--ds-weight-heading)]" : "text-[var(--ds-text-secondary)] hover:text-[var(--ds-text-primary)] hover:bg-[var(--ds-bg-muted)]"
16580
+ active ? "bg-[var(--ds-accent-subtle)] text-[var(--ds-accent-ink)] font-[var(--ds-weight-heading)]" : "text-[var(--ds-text-secondary)] hover:text-[var(--ds-text-primary)] hover:bg-[var(--ds-bg-muted)]"
16486
16581
  );
16487
16582
  }
16488
16583
  }
@@ -16562,7 +16657,7 @@ function NavMenu({
16562
16657
  const triggerClasses = cn(
16563
16658
  "inline-flex items-center gap-ds-1 cursor-pointer select-none whitespace-nowrap",
16564
16659
  "transition-colors duration-[var(--ds-transition-speed)] ease-[var(--ds-transition-ease)]",
16565
- "focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
16660
+ FOCUS_RING,
16566
16661
  navItemClasses(type, hasActiveChild),
16567
16662
  className
16568
16663
  );
@@ -16651,9 +16746,10 @@ function NavMenuItemRow({
16651
16746
  },
16652
16747
  className: cn(
16653
16748
  "flex items-center gap-ds-2 mx-ds-1 px-ds-2 py-ds-1.5 rounded-[var(--ds-radius-sm)] transition-colors cursor-pointer",
16749
+ FOCUS_RING,
16654
16750
  // The active row takes the accent tint like an active NavItem; it marks
16655
16751
  // the current page, not a hover.
16656
- item.active ? "bg-[var(--ds-accent-subtle)] text-[var(--ds-accent-primary)] font-medium" : "text-[var(--ds-text-secondary)] hover:bg-[var(--ds-bg-muted)] hover:text-[var(--ds-text-primary)]"
16752
+ item.active ? "bg-[var(--ds-accent-subtle)] text-[var(--ds-accent-ink)] font-medium" : "text-[var(--ds-text-secondary)] hover:bg-[var(--ds-bg-muted)] hover:text-[var(--ds-text-primary)]"
16657
16753
  ),
16658
16754
  children: [
16659
16755
  item.icon && /* @__PURE__ */ jsx(
@@ -16661,7 +16757,7 @@ function NavMenuItemRow({
16661
16757
  {
16662
16758
  name: item.icon,
16663
16759
  size: 16,
16664
- className: cn("shrink-0", item.active && "text-[var(--ds-accent-primary)]")
16760
+ className: cn("shrink-0", item.active && "text-[var(--ds-accent-ink)]")
16665
16761
  }
16666
16762
  ),
16667
16763
  /* @__PURE__ */ jsxs("div", { className: "flex flex-col min-w-0", children: [
@@ -16710,7 +16806,7 @@ function HamburgerButton({ onClick, open, className: cls }) {
16710
16806
  "w-10 h-10 rounded-[var(--ds-radius-md)]",
16711
16807
  "text-[var(--ds-text-secondary)] hover:text-[var(--ds-text-primary)]",
16712
16808
  "hover:bg-[var(--ds-bg-muted)] transition-colors",
16713
- "focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]",
16809
+ FOCUS_RING,
16714
16810
  "cursor-pointer",
16715
16811
  cls
16716
16812
  ),
@@ -16923,7 +17019,7 @@ var Navbar = forwardRef(function Navbar2({
16923
17019
  showHamburger && /* @__PURE__ */ jsx(HamburgerButton, { onClick: handleHamburger, open: appShell?.sidebarOpen }),
16924
17020
  logo && /* @__PURE__ */ jsx("div", { className: "flex items-center shrink-0 whitespace-nowrap", children: logo })
16925
17021
  ] }),
16926
- navLinks && !hideNavLinks ? /* @__PURE__ */ jsx(NavbarTypeContext.Provider, { value: type, children: /* @__PURE__ */ jsx("nav", { ref: navRef, className: "flex items-center gap-ds-2 min-w-0 overflow-x-clip justify-center", "data-navbar-type": type, children: linkRow }) }) : /* @__PURE__ */ jsx("div", { "data-navbar-spacer": "" }),
17022
+ navLinks && !hideNavLinks ? /* @__PURE__ */ jsx(NavbarTypeContext.Provider, { value: type, children: /* @__PURE__ */ jsx("nav", { ref: navRef, className: "flex items-center gap-ds-2 min-w-0 overflow-x-clip px-[4px] -mx-[4px] justify-center", "data-navbar-type": type, children: linkRow }) }) : /* @__PURE__ */ jsx("div", { "data-navbar-spacer": "" }),
16927
17023
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-ds-4 justify-end", children: [
16928
17024
  shownSearch && /* @__PURE__ */ jsx("div", { className: "flex items-center shrink-0", children: shownSearch }),
16929
17025
  actions && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-ds-2 shrink-0", children: actions }),
@@ -16951,7 +17047,7 @@ var Navbar = forwardRef(function Navbar2({
16951
17047
  showHamburger && /* @__PURE__ */ jsx(HamburgerButton, { onClick: handleHamburger, open: appShell?.sidebarOpen }),
16952
17048
  logo && /* @__PURE__ */ jsx("div", { className: "flex items-center shrink-0 whitespace-nowrap", children: logo }),
16953
17049
  align === "right" && /* @__PURE__ */ jsx("div", { "data-navbar-spacer": "", className: "flex-1" }),
16954
- navLinks && !hideNavLinks && /* @__PURE__ */ jsx(NavbarTypeContext.Provider, { value: type, children: /* @__PURE__ */ jsx("nav", { ref: navRef, className: cn("flex items-center gap-ds-2 min-w-0 overflow-x-clip", align === "left" && "flex-1"), "data-navbar-type": type, children: linkRow }) }),
17050
+ navLinks && !hideNavLinks && /* @__PURE__ */ jsx(NavbarTypeContext.Provider, { value: type, children: /* @__PURE__ */ jsx("nav", { ref: navRef, className: cn("flex items-center gap-ds-2 min-w-0 overflow-x-clip px-[4px] -mx-[4px]", align === "left" && "flex-1"), "data-navbar-type": type, children: linkRow }) }),
16955
17051
  (!navLinks || hideNavLinks) && /* @__PURE__ */ jsx("div", { "data-navbar-spacer": "", className: "flex-1" }),
16956
17052
  shownSearch && /* @__PURE__ */ jsx("div", { className: "flex items-center shrink-0", children: shownSearch }),
16957
17053
  actions && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-ds-2 shrink-0", children: actions }),
@@ -17009,6 +17105,7 @@ function MobileMenuItem({
17009
17105
  className: cn(
17010
17106
  "flex items-center gap-ds-3 px-ds-3 py-ds-3 text-sm relative cursor-pointer w-full text-left",
17011
17107
  "transition-colors duration-[var(--ds-transition-speed)]",
17108
+ FOCUS_RING,
17012
17109
  "border-b-[length:var(--ds-border-width)] border-[var(--ds-border-subtle)]",
17013
17110
  item.active ? "text-[var(--ds-text-primary)] font-[var(--ds-weight-heading)]" : "text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)]"
17014
17111
  ),
@@ -17034,7 +17131,8 @@ function MobileMenuItem({
17034
17131
  className: cn(
17035
17132
  "flex items-center gap-ds-3 px-ds-3 py-ds-2.5 text-sm cursor-pointer w-full text-left",
17036
17133
  "transition-colors duration-[var(--ds-transition-speed)]",
17037
- item.active ? "text-[var(--ds-accent-primary)] font-[var(--ds-weight-heading)]" : "text-[var(--ds-text-muted)] hover:text-[var(--ds-text-secondary)]"
17134
+ FOCUS_RING,
17135
+ item.active ? "text-[var(--ds-accent-ink)] font-[var(--ds-weight-heading)]" : "text-[var(--ds-text-muted)] hover:text-[var(--ds-text-secondary)]"
17038
17136
  ),
17039
17137
  children: [
17040
17138
  item.icon && /* @__PURE__ */ jsx(Icon, { name: item.icon, size: 18, className: "shrink-0" }),
@@ -17052,6 +17150,7 @@ function MobileMenuItem({
17052
17150
  className: cn(
17053
17151
  "flex items-center gap-ds-3 px-ds-3 py-ds-2.5 text-sm rounded-[var(--ds-radius-md)] cursor-pointer w-full text-left",
17054
17152
  "transition-colors duration-[var(--ds-transition-speed)]",
17153
+ FOCUS_RING,
17055
17154
  item.active ? "bg-[var(--ds-accent-primary)] text-[var(--ds-text-on-primary)] font-[var(--ds-weight-heading)]" : "text-[var(--ds-text-secondary)] hover:text-[var(--ds-text-primary)] hover:bg-[var(--ds-bg-muted)]"
17056
17155
  ),
17057
17156
  children: [
@@ -17069,7 +17168,8 @@ function MobileMenuItem({
17069
17168
  className: cn(
17070
17169
  "flex items-center gap-ds-3 px-ds-3 py-ds-2.5 text-sm rounded-[var(--ds-radius-md)] cursor-pointer w-full text-left",
17071
17170
  "transition-colors duration-[var(--ds-transition-speed)]",
17072
- item.active ? "bg-[var(--ds-accent-subtle)] text-[var(--ds-accent-primary)] font-[var(--ds-weight-heading)]" : "text-[var(--ds-text-secondary)] hover:text-[var(--ds-text-primary)] hover:bg-[var(--ds-bg-muted)]"
17171
+ FOCUS_RING,
17172
+ item.active ? "bg-[var(--ds-accent-subtle)] text-[var(--ds-accent-ink)] font-[var(--ds-weight-heading)]" : "text-[var(--ds-text-secondary)] hover:text-[var(--ds-text-primary)] hover:bg-[var(--ds-bg-muted)]"
17073
17173
  ),
17074
17174
  children: [
17075
17175
  item.icon && /* @__PURE__ */ jsx(Icon, { name: item.icon, size: 18, className: "shrink-0" }),
@@ -17197,6 +17297,7 @@ function CommandPalette({ open, onOpenChange, commands, placeholder = "Type a co
17197
17297
  onChange: (e) => setQuery(e.target.value),
17198
17298
  onKeyDown: handleKeyDown,
17199
17299
  placeholder,
17300
+ "data-popup-search": "",
17200
17301
  className: "flex-1 bg-transparent text-sm text-[var(--ds-text-primary)] placeholder:text-[var(--ds-text-muted)] outline-none"
17201
17302
  }
17202
17303
  ),
@@ -17388,6 +17489,7 @@ function ContextMenu({ items, children, className, ref, container }) {
17388
17489
  else if (ref) ref.current = node;
17389
17490
  },
17390
17491
  onContextMenu: handleContextMenu,
17492
+ "data-context-menu": "",
17391
17493
  className,
17392
17494
  children: [
17393
17495
  children,
@@ -17428,9 +17530,11 @@ function ContextMenu({ items, children, className, ref, container }) {
17428
17530
  className: cn(
17429
17531
  "flex items-center w-full text-left text-sm cursor-pointer",
17430
17532
  "px-ds-3 py-ds-1.5 gap-ds-3",
17431
- "transition-colors focus-visible:outline-none focus-visible:bg-[var(--ds-bg-muted)]",
17533
+ "transition-colors focus-visible:bg-[var(--ds-bg-muted)]",
17534
+ // full-width rows in a panel that clips, never filled solid: the outline sits inside (Sprint 30, P3)
17535
+ FOCUS_INSET,
17432
17536
  item.disabled && "opacity-disabled cursor-not-allowed",
17433
- item.destructive ? "text-[var(--ds-status-error)]" : "text-[var(--ds-text-primary)]",
17537
+ item.destructive ? "text-[var(--ds-status-error-text)]" : "text-[var(--ds-text-primary)]",
17434
17538
  isHighlighted && "bg-[var(--ds-bg-muted)]"
17435
17539
  ),
17436
17540
  children: [
@@ -17487,6 +17591,8 @@ function NotificationCenter({
17487
17591
  }, [isControlled, onOpenChangeRef]);
17488
17592
  const triggerRef = useRef(null);
17489
17593
  const panelRef = useRef(null);
17594
+ const [list2, setList] = useState(null);
17595
+ useRevealFocus(list2);
17490
17596
  const pos = usePosition(triggerRef, panelRef, open, { side: "bottom", align: "end", offset: 8, flip: true });
17491
17597
  const filter = controlledFilter ?? internalFilter;
17492
17598
  const setFilter = onFilterChange ?? setInternalFilter;
@@ -17528,7 +17634,7 @@ function NotificationCenter({
17528
17634
  {
17529
17635
  type: "button",
17530
17636
  onClick: onMarkAllRead,
17531
- className: "text-sm text-[var(--ds-accent-primary)] hover:underline cursor-pointer",
17637
+ className: cn("text-sm text-[var(--ds-accent-ink)] hover:underline cursor-pointer", FOCUS_RING),
17532
17638
  children: "Mark all read"
17533
17639
  }
17534
17640
  ) })
@@ -17541,6 +17647,7 @@ function NotificationCenter({
17541
17647
  onClick: () => setFilter("all"),
17542
17648
  className: cn(
17543
17649
  "px-ds-3 py-ds-1.5 text-sm rounded-[var(--ds-radius-md)] transition-colors cursor-pointer",
17650
+ FOCUS_RING,
17544
17651
  filter === "all" ? "bg-[var(--ds-accent-primary)] text-[var(--ds-text-on-primary)]" : "text-[var(--ds-text-secondary)] hover:bg-[var(--ds-bg-muted)]"
17545
17652
  ),
17546
17653
  children: "All"
@@ -17553,6 +17660,7 @@ function NotificationCenter({
17553
17660
  onClick: () => setFilter("unread"),
17554
17661
  className: cn(
17555
17662
  "px-ds-3 py-ds-1.5 text-sm rounded-[var(--ds-radius-md)] transition-colors cursor-pointer",
17663
+ FOCUS_RING,
17556
17664
  filter === "unread" ? "bg-[var(--ds-accent-primary)] text-[var(--ds-text-on-primary)]" : "text-[var(--ds-text-secondary)] hover:bg-[var(--ds-bg-muted)]"
17557
17665
  ),
17558
17666
  children: [
@@ -17602,7 +17710,7 @@ function NotificationCenter({
17602
17710
  type: "button",
17603
17711
  onClick: () => onMarkRead(n.id),
17604
17712
  "aria-label": "Mark as read",
17605
- className: "text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] transition-colors cursor-pointer p-ds-0.5",
17713
+ className: cn("text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] transition-colors cursor-pointer p-ds-0.5", FOCUS_RING),
17606
17714
  children: /* @__PURE__ */ jsx(Icon, { name: "check", size: 14 })
17607
17715
  }
17608
17716
  ),
@@ -17612,7 +17720,7 @@ function NotificationCenter({
17612
17720
  type: "button",
17613
17721
  onClick: () => onDismiss(n.id),
17614
17722
  "aria-label": "Dismiss",
17615
- className: "text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] transition-colors cursor-pointer p-ds-0.5",
17723
+ className: cn("text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] transition-colors cursor-pointer p-ds-0.5", FOCUS_RING),
17616
17724
  children: /* @__PURE__ */ jsx(Icon, { name: "close", size: 14 })
17617
17725
  }
17618
17726
  )
@@ -17639,7 +17747,7 @@ function NotificationCenter({
17639
17747
  "rounded-[var(--ds-radius-md)]",
17640
17748
  "text-[var(--ds-text-secondary)] hover:text-[var(--ds-text-primary)] hover:bg-[var(--ds-bg-muted)]",
17641
17749
  "transition-colors cursor-pointer",
17642
- "focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]"
17750
+ FOCUS_RING
17643
17751
  ),
17644
17752
  children: [
17645
17753
  /* @__PURE__ */ jsx(Icon, { name: "bell", size: 18 }),
@@ -17670,12 +17778,12 @@ function NotificationCenter({
17670
17778
  {
17671
17779
  type: "button",
17672
17780
  onClick: onMarkAllRead,
17673
- className: "text-xs text-[var(--ds-accent-primary)] hover:underline cursor-pointer",
17781
+ className: cn("text-xs text-[var(--ds-accent-ink)] hover:underline cursor-pointer", FOCUS_RING),
17674
17782
  children: "Mark all read"
17675
17783
  }
17676
17784
  )
17677
17785
  ] }),
17678
- /* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto", children: [
17786
+ /* @__PURE__ */ jsxs("div", { ref: setList, className: "flex-1 overflow-y-auto pb-[4px] scroll-p-[4px]", children: [
17679
17787
  notifications.length === 0 && /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center py-ds-12 text-[var(--ds-text-muted)]", children: [
17680
17788
  /* @__PURE__ */ jsx(Icon, { name: "bell", size: 32, className: "opacity-30 mb-ds-2" }),
17681
17789
  /* @__PURE__ */ jsx("p", { className: "text-sm", children: "No notifications" })
@@ -17716,7 +17824,7 @@ function NotificationCenter({
17716
17824
  type: "button",
17717
17825
  onClick: () => onMarkRead(n.id),
17718
17826
  "aria-label": "Mark as read",
17719
- className: "text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] transition-colors cursor-pointer p-ds-0.5",
17827
+ className: cn("text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] transition-colors cursor-pointer p-ds-0.5", FOCUS_RING),
17720
17828
  children: /* @__PURE__ */ jsx(Icon, { name: "check", size: 14 })
17721
17829
  }
17722
17830
  ),
@@ -17726,7 +17834,7 @@ function NotificationCenter({
17726
17834
  type: "button",
17727
17835
  onClick: () => onDismiss(n.id),
17728
17836
  "aria-label": "Dismiss",
17729
- className: "text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] transition-colors cursor-pointer p-ds-0.5",
17837
+ className: cn("text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] transition-colors cursor-pointer p-ds-0.5", FOCUS_RING),
17730
17838
  children: /* @__PURE__ */ jsx(Icon, { name: "close", size: 14 })
17731
17839
  }
17732
17840
  )
@@ -17889,7 +17997,7 @@ function Tour({ steps, open, onClose, onComplete, container }) {
17889
17997
  {
17890
17998
  type: "button",
17891
17999
  onClick: onClose,
17892
- className: "shrink-0 text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] transition-colors cursor-pointer -mt-ds-0.5",
18000
+ className: cn("shrink-0 text-[var(--ds-text-muted)] hover:text-[var(--ds-text-primary)] transition-colors cursor-pointer -mt-ds-0.5", FOCUS_RING),
17893
18001
  "aria-label": "Close tour",
17894
18002
  children: /* @__PURE__ */ jsx(Icon, { name: "close", size: 16 })
17895
18003
  }
@@ -17913,7 +18021,7 @@ function Tour({ steps, open, onClose, onComplete, container }) {
17913
18021
  "px-ds-3 py-ds-1.5 text-xs font-medium rounded-[var(--ds-radius-sm)]",
17914
18022
  "text-[var(--ds-text-secondary)] hover:bg-[var(--ds-bg-emphasis)]",
17915
18023
  "transition-colors cursor-pointer",
17916
- "focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]"
18024
+ FOCUS_RING
17917
18025
  ),
17918
18026
  children: "Back"
17919
18027
  }
@@ -17928,7 +18036,7 @@ function Tour({ steps, open, onClose, onComplete, container }) {
17928
18036
  "px-ds-3 py-ds-1.5 text-xs font-medium rounded-[var(--ds-radius-sm)]",
17929
18037
  "bg-[var(--ds-accent-primary)] text-[var(--ds-text-on-primary)]",
17930
18038
  "transition-colors cursor-pointer",
17931
- "focus-visible:outline-none focus-visible:shadow-[var(--ds-shadow-focus)]"
18039
+ FOCUS_RING
17932
18040
  ),
17933
18041
  children: current < steps.length - 1 ? "Next" : "Done"
17934
18042
  }
@@ -18090,6 +18198,7 @@ function focusHeading() {
18090
18198
  const heading = document.querySelector("main h1") ?? document.querySelector("main");
18091
18199
  if (!heading) return;
18092
18200
  if (!heading.hasAttribute("tabindex")) heading.setAttribute("tabindex", "-1");
18201
+ heading.style.outline = "none";
18093
18202
  heading.focus({ preventScroll: false });
18094
18203
  }
18095
18204
  function focusAfterLeaving() {