@estiva-app/ui 0.16.1 → 0.17.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 (55) hide show
  1. package/README.md +3 -1
  2. package/dist/Button.d.ts.map +1 -1
  3. package/dist/Checkbox.d.ts +14 -1
  4. package/dist/Checkbox.d.ts.map +1 -1
  5. package/dist/FilePicker.d.ts +22 -0
  6. package/dist/FilePicker.d.ts.map +1 -0
  7. package/dist/Form.d.ts +34 -0
  8. package/dist/Form.d.ts.map +1 -0
  9. package/dist/IconButton.d.ts.map +1 -1
  10. package/dist/SearchInput.d.ts.map +1 -1
  11. package/dist/TextInput.d.ts.map +1 -1
  12. package/dist/Textarea.d.ts.map +1 -1
  13. package/dist/eslint/index.d.ts +1 -1
  14. package/dist/eslint/index.d.ts.map +1 -1
  15. package/dist/eslint/index.js +88 -8
  16. package/dist/eslint/index.js.map +4 -4
  17. package/dist/eslint/no-raw-element.d.ts +88 -0
  18. package/dist/eslint/no-raw-element.d.ts.map +1 -0
  19. package/dist/formBusy.d.ts +15 -0
  20. package/dist/formBusy.d.ts.map +1 -0
  21. package/dist/index.d.ts +2 -0
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +356 -239
  24. package/dist/index.js.map +4 -4
  25. package/package.json +1 -1
  26. package/src/Button.tsx +4 -1
  27. package/src/Checkbox.mdx +19 -1
  28. package/src/Checkbox.stories.tsx +12 -0
  29. package/src/Checkbox.test.tsx +54 -0
  30. package/src/Checkbox.tsx +40 -3
  31. package/src/FilePicker.mdx +49 -0
  32. package/src/FilePicker.stories.tsx +61 -0
  33. package/src/FilePicker.test.tsx +79 -0
  34. package/src/FilePicker.tsx +40 -0
  35. package/src/Form.mdx +68 -0
  36. package/src/Form.stories.tsx +68 -0
  37. package/src/Form.test.tsx +282 -0
  38. package/src/Form.tsx +113 -0
  39. package/src/IconButton.tsx +4 -1
  40. package/src/SearchInput.mdx +2 -2
  41. package/src/SearchInput.tsx +3 -1
  42. package/src/TextInput.mdx +2 -2
  43. package/src/TextInput.test.tsx +7 -0
  44. package/src/TextInput.tsx +4 -1
  45. package/src/Textarea.tsx +4 -1
  46. package/src/eslint/index.test.ts +24 -15
  47. package/src/eslint/index.ts +6 -5
  48. package/src/eslint/{no-raw-button.test.ts → no-raw-element.test.ts} +53 -8
  49. package/src/eslint/no-raw-element.ts +180 -0
  50. package/src/formBusy.ts +19 -0
  51. package/src/index.ts +2 -0
  52. package/stories/Choosing.mdx +3 -0
  53. package/dist/eslint/no-raw-button.d.ts +0 -11
  54. package/dist/eslint/no-raw-button.d.ts.map +0 -1
  55. package/src/eslint/no-raw-button.ts +0 -39
package/dist/index.js CHANGED
@@ -244,6 +244,13 @@ function Card({
244
244
  // src/IconButton.tsx
245
245
  import { Button as BaseButton } from "@base-ui/react/button";
246
246
 
247
+ // src/formBusy.ts
248
+ import { createContext, useContext } from "react";
249
+ var FormBusyContext = createContext(false);
250
+ function useFormBusy() {
251
+ return useContext(FormBusyContext);
252
+ }
253
+
247
254
  // src/Tooltip.tsx
248
255
  import { Tooltip as BaseTooltip } from "@base-ui/react/tooltip";
249
256
 
@@ -337,11 +344,12 @@ function IconButton({
337
344
  type = "button",
338
345
  ...props
339
346
  }) {
347
+ const formBusy = useFormBusy();
340
348
  const button = /* @__PURE__ */ jsx8(
341
349
  BaseButton,
342
350
  {
343
351
  type,
344
- disabled: disabled || !!disabledReason,
352
+ disabled: disabled || !!disabledReason || formBusy,
345
353
  focusableWhenDisabled: !!disabledReason,
346
354
  className: (state) => cn(
347
355
  // `shrink-0` stops a flex parent squashing the button; `self-center`
@@ -682,11 +690,12 @@ function Button({
682
690
  ...props
683
691
  }) {
684
692
  const hasLeadingIcon = !!leadingIcon;
693
+ const formBusy = useFormBusy();
685
694
  const button = /* @__PURE__ */ jsxs8(
686
695
  BaseButton3,
687
696
  {
688
697
  type,
689
- disabled: disabled || !!disabledReason,
698
+ disabled: disabled || !!disabledReason || formBusy,
690
699
  focusableWhenDisabled: !!disabledReason,
691
700
  className: (state) => cn(
692
701
  // No `self-center` here, deliberately — `IconButton` needs it and this
@@ -732,8 +741,9 @@ function Button({
732
741
 
733
742
  // src/Checkbox.tsx
734
743
  import { Checkbox as BaseCheckbox } from "@base-ui/react/checkbox";
744
+ import { Field as BaseField } from "@base-ui/react/field";
735
745
  import { IconCheck } from "@tabler/icons-react";
736
- import { jsx as jsx14 } from "react/jsx-runtime";
746
+ import { jsx as jsx14, jsxs as jsxs9 } from "react/jsx-runtime";
737
747
  function squareClasses(checked, disabled, interactive, className) {
738
748
  return cn(
739
749
  "inline-flex items-center justify-center size-4 shrink-0 rounded-sm border transition-colors",
@@ -744,11 +754,19 @@ function squareClasses(checked, disabled, interactive, className) {
744
754
  );
745
755
  }
746
756
  var tickClasses = (checked) => cn("flex", !checked && "invisible");
747
- function Checkbox({ checked, onChange, disabled = false, className, ...aria }) {
757
+ var WORDS_CLASSES = "text-body-2 text-text-primary";
758
+ function Checkbox({ checked, onChange, disabled: ownDisabled = false, label, className, ...aria }) {
759
+ const formBusy = useFormBusy();
760
+ const disabled = ownDisabled || formBusy;
748
761
  if (!onChange) {
749
- return /* @__PURE__ */ jsx14("span", { "aria-hidden": "true", className: squareClasses(checked, disabled, false, className), children: /* @__PURE__ */ jsx14("span", { className: tickClasses(checked), children: /* @__PURE__ */ jsx14(IconCheck, { size: 12, stroke: 3 }) }) });
762
+ const picture = /* @__PURE__ */ jsx14("span", { "aria-hidden": "true", className: squareClasses(checked, disabled, false, className), children: /* @__PURE__ */ jsx14("span", { className: tickClasses(checked), children: /* @__PURE__ */ jsx14(IconCheck, { size: 12, stroke: 3 }) }) });
763
+ if (label === void 0) return picture;
764
+ return /* @__PURE__ */ jsxs9("span", { className: "flex items-center gap-2", children: [
765
+ picture,
766
+ /* @__PURE__ */ jsx14("span", { className: WORDS_CLASSES, children: label })
767
+ ] });
750
768
  }
751
- return /* @__PURE__ */ jsx14(
769
+ const box = /* @__PURE__ */ jsx14(
752
770
  BaseCheckbox.Root,
753
771
  {
754
772
  checked,
@@ -761,10 +779,15 @@ function Checkbox({ checked, onChange, disabled = false, className, ...aria }) {
761
779
  children: /* @__PURE__ */ jsx14(BaseCheckbox.Indicator, { keepMounted: true, className: (state) => tickClasses(state.checked), children: /* @__PURE__ */ jsx14(IconCheck, { size: 12, stroke: 3 }) })
762
780
  }
763
781
  );
782
+ if (label === void 0) return box;
783
+ return /* @__PURE__ */ jsx14(BaseField.Root, { disabled, children: /* @__PURE__ */ jsxs9(BaseField.Label, { className: cn("flex items-center gap-2", !disabled && "cursor-pointer"), children: [
784
+ box,
785
+ /* @__PURE__ */ jsx14("span", { className: WORDS_CLASSES, children: label })
786
+ ] }) });
764
787
  }
765
788
 
766
789
  // src/Chip.tsx
767
- import { jsx as jsx15, jsxs as jsxs9 } from "react/jsx-runtime";
790
+ import { jsx as jsx15, jsxs as jsxs10 } from "react/jsx-runtime";
768
791
  var typeStyles = {
769
792
  neutral: "bg-bg-inset text-text-primary",
770
793
  brand: "bg-accent-muted text-accent-primary signal:border signal:border-accent-outline",
@@ -774,7 +797,7 @@ var typeStyles = {
774
797
  error: "bg-error-muted text-error-default signal:border signal:border-error-outline"
775
798
  };
776
799
  function Chip({ type = "neutral", label, leadingIcon, trailingIcon, className }) {
777
- return /* @__PURE__ */ jsxs9("div", { className: cn("inline-flex min-w-0 items-center justify-center gap-1.5 rounded-full max-h-[20px] px-2 py-1", typeStyles[type], className), children: [
800
+ return /* @__PURE__ */ jsxs10("div", { className: cn("inline-flex min-w-0 items-center justify-center gap-1.5 rounded-full max-h-[20px] px-2 py-1", typeStyles[type], className), children: [
778
801
  leadingIcon && /* @__PURE__ */ jsx15("span", { className: "flex size-3 shrink-0 items-center justify-center", children: leadingIcon }),
779
802
  label && // A chip given a `max-w-*` cuts a long label with an ellipsis instead
780
803
  // of growing past it — Ship's project chip on an issue row
@@ -791,8 +814,8 @@ function Chip({ type = "neutral", label, leadingIcon, trailingIcon, className })
791
814
 
792
815
  // src/CommandPalette.tsx
793
816
  import {
794
- createContext as createContext2,
795
- useContext as useContext2,
817
+ createContext as createContext3,
818
+ useContext as useContext3,
796
819
  useEffect,
797
820
  useLayoutEffect as useLayoutEffect2,
798
821
  useMemo as useMemo2,
@@ -810,7 +833,7 @@ import { Combobox } from "@base-ui/react/combobox";
810
833
  import { IconX as IconX3 } from "@tabler/icons-react";
811
834
 
812
835
  // src/Menu.tsx
813
- import { createContext, useContext } from "react";
836
+ import { createContext as createContext2, useContext as useContext2 } from "react";
814
837
  import { IconChevronRight } from "@tabler/icons-react";
815
838
  import { Menu as BaseMenu } from "@base-ui/react/menu";
816
839
 
@@ -836,8 +859,8 @@ function SectionLabel({ children, className }) {
836
859
  }
837
860
 
838
861
  // src/Menu.tsx
839
- import { Fragment as Fragment2, jsx as jsx17, jsxs as jsxs10 } from "react/jsx-runtime";
840
- var MenuContext = createContext(null);
862
+ import { Fragment as Fragment2, jsx as jsx17, jsxs as jsxs11 } from "react/jsx-runtime";
863
+ var MenuContext = createContext2(null);
841
864
  function MenuPanel({ children, className, ...props }) {
842
865
  return /* @__PURE__ */ jsx17(
843
866
  "div",
@@ -869,7 +892,7 @@ var VIEWPORT_PAD2 = 8;
869
892
  var HOVER_OPEN_DELAY = 0;
870
893
  var HOVER_CLOSE_DELAY = 150;
871
894
  function Menu({ trigger, align = "left", openOnHover = false, open, onOpenChange, actionsRef, children, className, contentClassName }) {
872
- return /* @__PURE__ */ jsxs10(
895
+ return /* @__PURE__ */ jsxs11(
873
896
  BaseMenu.Root,
874
897
  {
875
898
  open,
@@ -911,13 +934,13 @@ function Menu({ trigger, align = "left", openOnHover = false, open, onOpenChange
911
934
  );
912
935
  }
913
936
  function MenuSub({ label, leading, selected, children, className }) {
914
- const menu = useContext(MenuContext);
937
+ const menu = useContext2(MenuContext);
915
938
  if (!isProduction() && menu?.openOnHover) {
916
939
  console.error(
917
940
  '[@estiva-app/ui] Menu: `openOnHover` and `MenuSub` cannot be used together \u2014 leaving the submenu panel strands the menu open. Open this menu on a press instead. See Menu.mdx, "Hover-opened menus".'
918
941
  );
919
942
  }
920
- return /* @__PURE__ */ jsxs10(BaseMenu.SubmenuRoot, { children: [
943
+ return /* @__PURE__ */ jsxs11(BaseMenu.SubmenuRoot, { children: [
921
944
  /* @__PURE__ */ jsx17(
922
945
  BaseMenu.SubmenuTrigger,
923
946
  {
@@ -974,9 +997,9 @@ function menuItemClassName({ size, selected, className }) {
974
997
  }
975
998
  function MenuItemBody({ label, children, size = "default", description, leading, trailing, hint, shortcut, submenu, destructive, selected }) {
976
999
  const edge = trailing ?? (shortcut ? /* @__PURE__ */ jsx17(Kbd, { children: shortcut }) : submenu ? /* @__PURE__ */ jsx17(IconChevronRight, { size: 16, stroke: 1.5, className: "shrink-0 text-text-muted" }) : null);
977
- return /* @__PURE__ */ jsxs10(Fragment2, { children: [
1000
+ return /* @__PURE__ */ jsxs11(Fragment2, { children: [
978
1001
  leading && /* @__PURE__ */ jsx17("span", { className: "flex shrink-0 items-center", children: leading }),
979
- children ?? /* @__PURE__ */ jsxs10("span", { className: cn("flex min-w-0 flex-1 flex-col", size === "tall" && "gap-[2px]"), children: [
1002
+ children ?? /* @__PURE__ */ jsxs11("span", { className: cn("flex min-w-0 flex-1 flex-col", size === "tall" && "gap-[2px]"), children: [
980
1003
  /* @__PURE__ */ jsx17("span", { className: cn("truncate text-body-2", destructive ? "text-error-default" : "text-text-primary"), children: label }),
981
1004
  description && /* @__PURE__ */ jsx17("span", { className: "truncate text-caption text-text-secondary", children: description })
982
1005
  ] }),
@@ -984,7 +1007,7 @@ function MenuItemBody({ label, children, size = "default", description, leading,
984
1007
  // the wider of the two and never changes, so revealing the hint moves
985
1008
  // nothing. No transition here either — the hint switches on the same
986
1009
  // :hover / `selected` as the fill, in the same frame.
987
- /* @__PURE__ */ jsxs10("span", { className: "grid shrink-0 items-center justify-items-end [&>*]:col-start-1 [&>*]:row-start-1", children: [
1010
+ /* @__PURE__ */ jsxs11("span", { className: "grid shrink-0 items-center justify-items-end [&>*]:col-start-1 [&>*]:row-start-1", children: [
988
1011
  edge && /* @__PURE__ */ jsx17("span", { className: cn("flex items-center", hint && "group-hover:opacity-0 group-data-[highlighted]:opacity-0", hint && selected && "opacity-0"), children: edge }),
989
1012
  hint && /* @__PURE__ */ jsx17("span", { className: cn("flex items-center opacity-0 group-hover:opacity-100 group-data-[highlighted]:opacity-100", selected && "opacity-100"), children: hint })
990
1013
  ] })
@@ -1008,7 +1031,7 @@ function MenuItem({ label, children, size = "default", description, leading, tra
1008
1031
  }
1009
1032
  );
1010
1033
  const rowClassName = menuItemClassName({ size, selected, className });
1011
- if (!useContext(MenuContext)) {
1034
+ if (!useContext2(MenuContext)) {
1012
1035
  return /* @__PURE__ */ jsx17("button", { type: "button", className: rowClassName, ...props, children: body });
1013
1036
  }
1014
1037
  return /* @__PURE__ */ jsx17(
@@ -1023,21 +1046,21 @@ function MenuItem({ label, children, size = "default", description, leading, tra
1023
1046
  );
1024
1047
  }
1025
1048
  function EnterHint({ target }) {
1026
- return /* @__PURE__ */ jsxs10("span", { className: "flex shrink-0 items-center gap-1.5 text-text-muted", children: [
1049
+ return /* @__PURE__ */ jsxs11("span", { className: "flex shrink-0 items-center gap-1.5 text-text-muted", children: [
1027
1050
  /* @__PURE__ */ jsx17(Kbd, { children: "\u21A9 Enter" }),
1028
1051
  target && /* @__PURE__ */ jsx17("span", { className: "text-menu signal:font-mono signal:text-small signal:tracking-wider", children: target })
1029
1052
  ] });
1030
1053
  }
1031
1054
  function MenuSection({ label, children, className }) {
1032
- const inMenu = useContext(MenuContext) !== null;
1055
+ const inMenu = useContext2(MenuContext) !== null;
1033
1056
  const heading = /* @__PURE__ */ jsx17("div", { className: cn("flex h-8 items-center px-2", className), children: /* @__PURE__ */ jsx17(SectionLabel, { className: "text-text-secondary", children: label }) });
1034
1057
  if (!inMenu) {
1035
- return /* @__PURE__ */ jsxs10("div", { className: "flex flex-col", children: [
1058
+ return /* @__PURE__ */ jsxs11("div", { className: "flex flex-col", children: [
1036
1059
  heading,
1037
1060
  children
1038
1061
  ] });
1039
1062
  }
1040
- return /* @__PURE__ */ jsxs10(BaseMenu.Group, { className: "flex flex-col", children: [
1063
+ return /* @__PURE__ */ jsxs11(BaseMenu.Group, { className: "flex flex-col", children: [
1041
1064
  /* @__PURE__ */ jsx17(BaseMenu.GroupLabel, { render: heading }),
1042
1065
  children
1043
1066
  ] });
@@ -1047,7 +1070,7 @@ function MenuRow({ children, className }) {
1047
1070
  }
1048
1071
 
1049
1072
  // src/ChipInput.tsx
1050
- import { jsx as jsx18, jsxs as jsxs11 } from "react/jsx-runtime";
1073
+ import { jsx as jsx18, jsxs as jsxs12 } from "react/jsx-runtime";
1051
1074
  var CHIP_BOX = (
1052
1075
  // Curved, not a pill (Katerina, 2026-09-01): the Avatar keeps its own
1053
1076
  // rounded-sm corners — never a forced circle — and the chip's corner
@@ -1058,7 +1081,7 @@ var CHIP_LABEL = "text-caption font-medium text-text-primary";
1058
1081
  var CHIP_REMOVE = "size-4 flex items-center justify-center rounded-full hover:bg-bg-hover text-text-secondary";
1059
1082
  var chipPadding = (leading, removable) => cn(leading ? "pl-[2px]" : "pl-2", removable ? "pr-1" : "pr-2");
1060
1083
  function InputChip({ label, leading, onRemove, removeLabel, truncate, className }) {
1061
- return /* @__PURE__ */ jsxs11("div", { className: cn(CHIP_BOX, chipPadding(!!leading, !!onRemove), className), children: [
1084
+ return /* @__PURE__ */ jsxs12("div", { className: cn(CHIP_BOX, chipPadding(!!leading, !!onRemove), className), children: [
1062
1085
  leading && /* @__PURE__ */ jsx18("span", { className: "flex shrink-0 items-center", children: leading }),
1063
1086
  /* @__PURE__ */ jsx18("span", { className: cn(CHIP_LABEL, truncate && "min-w-0 truncate"), children: label }),
1064
1087
  onRemove && /* @__PURE__ */ jsx18(
@@ -1124,7 +1147,7 @@ function ChipInput({
1124
1147
  setQuery("");
1125
1148
  }
1126
1149
  }
1127
- return /* @__PURE__ */ jsxs11(
1150
+ return /* @__PURE__ */ jsxs12(
1128
1151
  Combobox.Root,
1129
1152
  {
1130
1153
  multiple: true,
@@ -1141,8 +1164,8 @@ function ChipInput({
1141
1164
  filter,
1142
1165
  itemToStringLabel: (option) => option.label,
1143
1166
  children: [
1144
- /* @__PURE__ */ jsxs11(Combobox.Chips, { ref: setBox, className: "bg-bg-inset border border-border-default hover:border-border-strong focus-within:border-border-focus focus-within:hover:border-border-focus rounded-lg px-3 py-1.5 flex flex-wrap items-center gap-1.5 transition-colors min-h-[38px] cursor-text signal:transition-shadow signal:focus-within:shadow-focus-ring", children: [
1145
- value.map((option) => /* @__PURE__ */ jsxs11(Combobox.Chip, { className: cn(CHIP_BOX, chipPadding(!!chipLeading, true)), children: [
1167
+ /* @__PURE__ */ jsxs12(Combobox.Chips, { ref: setBox, className: "bg-bg-inset border border-border-default hover:border-border-strong focus-within:border-border-focus focus-within:hover:border-border-focus rounded-lg px-3 py-1.5 flex flex-wrap items-center gap-1.5 transition-colors min-h-[38px] cursor-text signal:transition-shadow signal:focus-within:shadow-focus-ring", children: [
1168
+ value.map((option) => /* @__PURE__ */ jsxs12(Combobox.Chip, { className: cn(CHIP_BOX, chipPadding(!!chipLeading, true)), children: [
1146
1169
  chipLeading && /* @__PURE__ */ jsx18("span", { className: "flex shrink-0 items-center", children: chipLeading(option) }),
1147
1170
  /* @__PURE__ */ jsx18("span", { className: CHIP_LABEL, children: option.label }),
1148
1171
  /* @__PURE__ */ jsx18(Combobox.ChipRemove, { className: CHIP_REMOVE, "aria-label": `Remove ${option.label}`, children: /* @__PURE__ */ jsx18(IconX3, { size: 10, stroke: 1.5 }) })
@@ -1193,12 +1216,12 @@ var VIEWPORT_PAD3 = 8;
1193
1216
 
1194
1217
  // src/EmptyState.tsx
1195
1218
  import { IconMessage2 } from "@tabler/icons-react";
1196
- import { jsx as jsx19, jsxs as jsxs12 } from "react/jsx-runtime";
1219
+ import { jsx as jsx19, jsxs as jsxs13 } from "react/jsx-runtime";
1197
1220
  function EmptyState({ icon, message, scope = "page", className }) {
1198
1221
  if (scope === "section") {
1199
1222
  return /* @__PURE__ */ jsx19("p", { className: cn("text-caption text-text-muted", className), children: message });
1200
1223
  }
1201
- return /* @__PURE__ */ jsxs12("div", { className: cn("flex flex-1 flex-col items-center justify-center gap-2", className), children: [
1224
+ return /* @__PURE__ */ jsxs13("div", { className: cn("flex flex-1 flex-col items-center justify-center gap-2", className), children: [
1202
1225
  /* @__PURE__ */ jsx19("span", { className: "text-text-secondary", children: icon ?? /* @__PURE__ */ jsx19(IconMessage2, { size: 16, stroke: 1.5 }) }),
1203
1226
  /* @__PURE__ */ jsx19("p", { className: "text-body-2 text-text-secondary text-center", children: message })
1204
1227
  ] });
@@ -1206,8 +1229,8 @@ function EmptyState({ icon, message, scope = "page", className }) {
1206
1229
 
1207
1230
  // src/Field.tsx
1208
1231
  import { cloneElement, isValidElement } from "react";
1209
- import { Field as BaseField } from "@base-ui/react/field";
1210
- import { jsx as jsx20, jsxs as jsxs13 } from "react/jsx-runtime";
1232
+ import { Field as BaseField2 } from "@base-ui/react/field";
1233
+ import { jsx as jsx20, jsxs as jsxs14 } from "react/jsx-runtime";
1211
1234
  var LINE_STYLES = {
1212
1235
  helper: "text-caption text-text-muted",
1213
1236
  warning: "text-caption text-warning-default",
@@ -1217,14 +1240,14 @@ function Field({ label, required = false, helper, error, children }) {
1217
1240
  const control = required && isValidElement(children) ? cloneElement(children, {
1218
1241
  "aria-required": children.props["aria-required"] ?? true
1219
1242
  }) : children;
1220
- return /* @__PURE__ */ jsxs13(BaseField.Root, { invalid: !!error, className: "flex flex-col gap-2", children: [
1221
- /* @__PURE__ */ jsxs13(BaseField.Label, { className: cn("text-input-label text-text-primary", required && "flex items-center"), children: [
1243
+ return /* @__PURE__ */ jsxs14(BaseField2.Root, { invalid: !!error, className: "flex flex-col gap-2", children: [
1244
+ /* @__PURE__ */ jsxs14(BaseField2.Label, { className: cn("text-input-label text-text-primary", required && "flex items-center"), children: [
1222
1245
  label,
1223
1246
  required && /* @__PURE__ */ jsx20("span", { "aria-hidden": "true", className: "text-error-default ml-0.5", children: "*" })
1224
1247
  ] }),
1225
- /* @__PURE__ */ jsxs13("div", { className: "flex flex-col gap-1.5", children: [
1248
+ /* @__PURE__ */ jsxs14("div", { className: "flex flex-col gap-1.5", children: [
1226
1249
  control,
1227
- error != null ? /* @__PURE__ */ jsx20(BaseField.Error, { match: true, className: LINE_STYLES.error, children: error }) : helper != null ? /* @__PURE__ */ jsx20(BaseField.Description, { className: LINE_STYLES.helper, children: helper }) : null
1250
+ error != null ? /* @__PURE__ */ jsx20(BaseField2.Error, { match: true, className: LINE_STYLES.error, children: error }) : helper != null ? /* @__PURE__ */ jsx20(BaseField2.Description, { className: LINE_STYLES.helper, children: helper }) : null
1228
1251
  ] })
1229
1252
  ] });
1230
1253
  }
@@ -1233,13 +1256,13 @@ function FieldLine({ tone = "helper", children, className }) {
1233
1256
  }
1234
1257
 
1235
1258
  // src/Skeleton.tsx
1236
- import { jsx as jsx21, jsxs as jsxs14 } from "react/jsx-runtime";
1259
+ import { jsx as jsx21, jsxs as jsxs15 } from "react/jsx-runtime";
1237
1260
  function SkeletonBar({ className, style }) {
1238
1261
  return /* @__PURE__ */ jsx21("div", { className: cn("bg-bg-inset rounded-sm animate-pulse", className), style });
1239
1262
  }
1240
1263
  var ROW_BAR_WIDTHS = [150, 100, 170, 120, 90, 140, 110, 160];
1241
1264
  function SkeletonRow({ barWidth = 130 }) {
1242
- return /* @__PURE__ */ jsxs14("div", { className: "flex items-center gap-2 px-2 h-[32px] rounded-lg", children: [
1265
+ return /* @__PURE__ */ jsxs15("div", { className: "flex items-center gap-2 px-2 h-[32px] rounded-lg", children: [
1243
1266
  /* @__PURE__ */ jsx21(SkeletonBar, { className: "w-4 h-4 shrink-0" }),
1244
1267
  /* @__PURE__ */ jsx21(SkeletonBar, { className: "h-3.5", style: { width: barWidth } })
1245
1268
  ] });
@@ -1249,10 +1272,10 @@ function SkeletonList({ rows = 8, className }) {
1249
1272
  }
1250
1273
 
1251
1274
  // src/CommandPalette.tsx
1252
- import { Fragment as Fragment3, jsx as jsx22, jsxs as jsxs15 } from "react/jsx-runtime";
1253
- var PaletteContext = createContext2(null);
1275
+ import { Fragment as Fragment3, jsx as jsx22, jsxs as jsxs16 } from "react/jsx-runtime";
1276
+ var PaletteContext = createContext3(null);
1254
1277
  function usePalette(part) {
1255
- const palette = useContext2(PaletteContext);
1278
+ const palette = useContext3(PaletteContext);
1256
1279
  if (!palette) throw new Error(`[@estiva-app/ui] ${part} must be inside a CommandPalette.`);
1257
1280
  return palette;
1258
1281
  }
@@ -1275,7 +1298,7 @@ function CommandPalette({ open, onOpenChange, label, where, modKey = "Ctrl", chi
1275
1298
  return () => cancelAnimationFrame(frame);
1276
1299
  });
1277
1300
  const context = useMemo2(() => ({ where, modKey, popupRef }), [where, modKey]);
1278
- return /* @__PURE__ */ jsx22(Dialog.Root, { open, onOpenChange: (next) => onOpenChange(next), children: /* @__PURE__ */ jsxs15(Dialog.Portal, { children: [
1301
+ return /* @__PURE__ */ jsx22(Dialog.Root, { open, onOpenChange: (next) => onOpenChange(next), children: /* @__PURE__ */ jsxs16(Dialog.Portal, { children: [
1279
1302
  /* @__PURE__ */ jsx22(Dialog.Backdrop, { className: "fixed inset-0 z-40 bg-scrim" }),
1280
1303
  /* @__PURE__ */ jsx22(Dialog.Viewport, { className: "fixed inset-0 z-50 flex items-start justify-center pt-[16vh]", children: /* @__PURE__ */ jsx22(
1281
1304
  Dialog.Popup,
@@ -1304,9 +1327,9 @@ function useBack(chip, popupRef) {
1304
1327
  }
1305
1328
  function Footer({ keys }) {
1306
1329
  const { where } = usePalette("The footer");
1307
- return /* @__PURE__ */ jsxs15("div", { className: "flex h-9 shrink-0 items-center gap-4 border-t border-border-subtle px-5 text-caption text-text-secondary signal:font-mono signal:text-small signal:text-text-muted", children: [
1330
+ return /* @__PURE__ */ jsxs16("div", { className: "flex h-9 shrink-0 items-center gap-4 border-t border-border-subtle px-5 text-caption text-text-secondary signal:font-mono signal:text-small signal:text-text-muted", children: [
1308
1331
  /* @__PURE__ */ jsx22("span", { className: "min-w-0 flex-1 truncate", children: where }),
1309
- keys.map(([key, word]) => /* @__PURE__ */ jsxs15("span", { className: "flex shrink-0 items-center gap-1.5", children: [
1332
+ keys.map(([key, word]) => /* @__PURE__ */ jsxs16("span", { className: "flex shrink-0 items-center gap-1.5", children: [
1310
1333
  /* @__PURE__ */ jsx22(Kbd, { children: key }),
1311
1334
  " ",
1312
1335
  word
@@ -1384,7 +1407,7 @@ function CommandPaletteSearch({ query, onQueryChange, placeholder, groups, chip,
1384
1407
  ...chip && query === "" ? [["Backspace", "back"]] : [],
1385
1408
  ["Esc", "close"]
1386
1409
  ];
1387
- return /* @__PURE__ */ jsxs15(
1410
+ return /* @__PURE__ */ jsxs16(
1388
1411
  Autocomplete.Root,
1389
1412
  {
1390
1413
  items,
@@ -1407,7 +1430,7 @@ function CommandPaletteSearch({ query, onQueryChange, placeholder, groups, chip,
1407
1430
  setLitId(id);
1408
1431
  },
1409
1432
  children: [
1410
- /* @__PURE__ */ jsxs15("div", { className: "flex h-12 shrink-0 items-center gap-3 border-b border-border-subtle px-5", children: [
1433
+ /* @__PURE__ */ jsxs16("div", { className: "flex h-12 shrink-0 items-center gap-3 border-b border-border-subtle px-5", children: [
1411
1434
  /* @__PURE__ */ jsx22(IconSearch, { size: 16, stroke: 1.5, className: "shrink-0 text-text-secondary" }),
1412
1435
  chip && /* @__PURE__ */ jsx22(LevelChip, { chip, onBack: back }),
1413
1436
  /* @__PURE__ */ jsx22(
@@ -1422,9 +1445,9 @@ function CommandPaletteSearch({ query, onQueryChange, placeholder, groups, chip,
1422
1445
  }
1423
1446
  )
1424
1447
  ] }),
1425
- /* @__PURE__ */ jsxs15(ScrollArea, { viewportClassName: "max-h-[420px]", contentClassName: "flex flex-col p-2", children: [
1448
+ /* @__PURE__ */ jsxs16(ScrollArea, { viewportClassName: "max-h-[420px]", contentClassName: "flex flex-col p-2", children: [
1426
1449
  children != null && /* @__PURE__ */ jsx22("div", { className: "flex flex-col gap-2 px-3 pb-2 pt-3", children }),
1427
- /* @__PURE__ */ jsx22(Autocomplete.List, { className: "flex flex-col", children: (group) => /* @__PURE__ */ jsxs15(Autocomplete.Group, { items: group.items, className: "flex flex-col", children: [
1450
+ /* @__PURE__ */ jsx22(Autocomplete.List, { className: "flex flex-col", children: (group) => /* @__PURE__ */ jsxs16(Autocomplete.Group, { items: group.items, className: "flex flex-col", children: [
1428
1451
  /* @__PURE__ */ jsx22(Autocomplete.GroupLabel, { className: "flex h-7 shrink-0 items-center px-3", children: /* @__PURE__ */ jsx22(SectionLabel, { className: "text-text-secondary", children: group.value }) }),
1429
1452
  /* @__PURE__ */ jsx22(Autocomplete.Collection, { children: (row) => (
1430
1453
  /* The menu row, as the list's own option — the way Select
@@ -1442,7 +1465,7 @@ function CommandPaletteSearch({ query, onQueryChange, placeholder, groups, chip,
1442
1465
  ) }, row.id)
1443
1466
  ) })
1444
1467
  ] }, group.value) }),
1445
- /* @__PURE__ */ jsx22(Autocomplete.Status, { className: "flex items-center gap-2 px-3 [&:not(:empty)]:h-8", children: pending && /* @__PURE__ */ jsxs15(Fragment3, { children: [
1468
+ /* @__PURE__ */ jsx22(Autocomplete.Status, { className: "flex items-center gap-2 px-3 [&:not(:empty)]:h-8", children: pending && /* @__PURE__ */ jsxs16(Fragment3, { children: [
1446
1469
  /* @__PURE__ */ jsx22(IconLoader22, { size: 12, stroke: 1.5, className: "shrink-0 animate-spin text-text-muted" }),
1447
1470
  /* @__PURE__ */ jsx22("span", { className: "text-caption text-text-muted", children: pending })
1448
1471
  ] }) }),
@@ -1518,13 +1541,13 @@ function CommandPaletteForm({ chip, icon, submitLabel, onSubmit, submitWaits, wo
1518
1541
  ...backNamed ? [["Backspace", "back"]] : [],
1519
1542
  ["Esc", "close"]
1520
1543
  ];
1521
- return /* @__PURE__ */ jsxs15("div", { ref: frameRef, tabIndex: -1, onKeyDown, onFocus: measure, onBlur: measure, onInput: measure, className: "flex min-h-0 flex-col outline-none", children: [
1522
- /* @__PURE__ */ jsxs15("div", { className: "flex h-12 shrink-0 items-center gap-3 border-b border-border-subtle px-5", children: [
1544
+ return /* @__PURE__ */ jsxs16("div", { ref: frameRef, tabIndex: -1, onKeyDown, onFocus: measure, onBlur: measure, onInput: measure, className: "flex min-h-0 flex-col outline-none", children: [
1545
+ /* @__PURE__ */ jsxs16("div", { className: "flex h-12 shrink-0 items-center gap-3 border-b border-border-subtle px-5", children: [
1523
1546
  icon != null && /* @__PURE__ */ jsx22("span", { className: "flex shrink-0 items-center text-text-secondary", children: icon }),
1524
1547
  /* @__PURE__ */ jsx22(LevelChip, { chip, onBack: back })
1525
1548
  ] }),
1526
1549
  /* @__PURE__ */ jsx22(ScrollArea, { viewportClassName: "max-h-[420px]", contentClassName: "flex flex-col px-5 py-4", children: /* @__PURE__ */ jsx22("fieldset", { "data-command-palette-fields": "", disabled: busy, className: "contents", children: /* @__PURE__ */ jsx22("div", { className: "flex flex-col gap-4", children }) }) }),
1527
- /* @__PURE__ */ jsxs15("div", { className: "flex shrink-0 items-center gap-3 px-5 pb-4", children: [
1550
+ /* @__PURE__ */ jsxs16("div", { className: "flex shrink-0 items-center gap-3 px-5 pb-4", children: [
1528
1551
  /* @__PURE__ */ jsx22("div", { className: "min-w-0 flex-1", children: working ? /* @__PURE__ */ jsx22(FieldLine, { children: working.line }) : error ? /* @__PURE__ */ jsx22(FieldLine, { tone: "error", children: error }) : null }),
1529
1552
  /* @__PURE__ */ jsx22(
1530
1553
  Button,
@@ -1543,8 +1566,8 @@ function CommandPaletteForm({ chip, icon, submitLabel, onSubmit, submitWaits, wo
1543
1566
  }
1544
1567
  var BAR_WIDTHS = ["w-4/5", "w-3/5", "w-2/3"];
1545
1568
  function CommandPaletteWorking({ children, bars = 2 }) {
1546
- return /* @__PURE__ */ jsxs15("div", { role: "status", className: "flex flex-col gap-2", children: [
1547
- /* @__PURE__ */ jsxs15("span", { className: "flex items-center gap-2 text-caption text-text-secondary", children: [
1569
+ return /* @__PURE__ */ jsxs16("div", { role: "status", className: "flex flex-col gap-2", children: [
1570
+ /* @__PURE__ */ jsxs16("span", { className: "flex items-center gap-2 text-caption text-text-secondary", children: [
1548
1571
  /* @__PURE__ */ jsx22(IconLoader22, { size: 14, stroke: 1.5, className: "shrink-0 animate-spin" }),
1549
1572
  children
1550
1573
  ] }),
@@ -1553,7 +1576,7 @@ function CommandPaletteWorking({ children, bars = 2 }) {
1553
1576
  }
1554
1577
  function CommandPaletteAnswer({ children, note }) {
1555
1578
  const paragraphs = children.split(/\n\s*\n/).filter((p) => p.trim() !== "");
1556
- return /* @__PURE__ */ jsxs15("div", { className: "flex flex-col gap-2", children: [
1579
+ return /* @__PURE__ */ jsxs16("div", { className: "flex flex-col gap-2", children: [
1557
1580
  paragraphs.map((paragraph, i) => /* @__PURE__ */ jsx22("p", { className: "whitespace-pre-wrap text-body-2 text-text-primary", children: paragraph.split(/\s*(\[\d+\])/).map(
1558
1581
  (part, j) => /^\[\d+\]$/.test(part) ? /* @__PURE__ */ jsx22("sup", { className: "ml-0.5 font-mono text-small text-accent-primary", children: part.slice(1, -1) }, j) : part
1559
1582
  ) }, i)),
@@ -1565,7 +1588,7 @@ function CommandPaletteQuote({ children }) {
1565
1588
  }
1566
1589
 
1567
1590
  // src/InlineChip.tsx
1568
- import { Fragment as Fragment4, jsx as jsx23, jsxs as jsxs16 } from "react/jsx-runtime";
1591
+ import { Fragment as Fragment4, jsx as jsx23, jsxs as jsxs17 } from "react/jsx-runtime";
1569
1592
  var INLINE_CHIP_CLASSES = "inline-flex h-[1.4em] items-center gap-1 rounded-sm px-1 mx-0.5 align-top text-body-2 font-normal select-none";
1570
1593
  var INLINE_CHIP_TONE_CLASSES = {
1571
1594
  /** A thing or a place — anything that is not a person. */
@@ -1587,7 +1610,7 @@ function inlineChipClassName(tone, className) {
1587
1610
  return cn(INLINE_CHIP_CLASSES, INLINE_CHIP_TONE_CLASSES[tone], className);
1588
1611
  }
1589
1612
  function InlineChip({ tone = "neutral", icon, href, className, children, ...props }) {
1590
- const body = /* @__PURE__ */ jsxs16(Fragment4, { children: [
1613
+ const body = /* @__PURE__ */ jsxs17(Fragment4, { children: [
1591
1614
  icon && /* @__PURE__ */ jsx23("span", { className: "flex size-4 shrink-0 items-center justify-center text-text-secondary", children: icon }),
1592
1615
  children
1593
1616
  ] });
@@ -1603,11 +1626,11 @@ import { useCallback, useRef as useRef3 } from "react";
1603
1626
 
1604
1627
  // src/Divider.tsx
1605
1628
  import { Separator } from "@base-ui/react/separator";
1606
- import { jsx as jsx24, jsxs as jsxs17 } from "react/jsx-runtime";
1629
+ import { jsx as jsx24, jsxs as jsxs18 } from "react/jsx-runtime";
1607
1630
  function Divider({ orientation = "horizontal", label, tone = "default", className }) {
1608
1631
  if (label && orientation === "horizontal") {
1609
1632
  const line = tone === "warning" ? "bg-warning-muted" : "bg-border-subtle";
1610
- return /* @__PURE__ */ jsxs17(
1633
+ return /* @__PURE__ */ jsxs18(
1611
1634
  Separator,
1612
1635
  {
1613
1636
  orientation: "horizontal",
@@ -1631,13 +1654,13 @@ function Divider({ orientation = "horizontal", label, tone = "default", classNam
1631
1654
  }
1632
1655
 
1633
1656
  // src/Person.tsx
1634
- import { jsx as jsx25, jsxs as jsxs18 } from "react/jsx-runtime";
1657
+ import { jsx as jsx25, jsxs as jsxs19 } from "react/jsx-runtime";
1635
1658
  function Person({ name, picture, fallback = "\u2014", size = 20, className }) {
1636
1659
  return (
1637
1660
  // gap-2: the face-to-name distance is one rule (8px) wherever a person
1638
1661
  // appears — Katerina, 2026-09-01, set on Person so PersonTrigger and every
1639
1662
  // row agree by construction.
1640
- /* @__PURE__ */ jsxs18("span", { className: cn("flex min-w-0 items-center gap-2", className), children: [
1663
+ /* @__PURE__ */ jsxs19("span", { className: cn("flex min-w-0 items-center gap-2", className), children: [
1641
1664
  /* @__PURE__ */ jsx25(Avatar, { name, src: picture, size }),
1642
1665
  /* @__PURE__ */ jsx25("span", { className: cn("truncate", !name && "text-text-muted"), children: name ?? fallback })
1643
1666
  ] })
@@ -1647,7 +1670,7 @@ function Person({ name, picture, fallback = "\u2014", size = 20, className }) {
1647
1670
  // src/PersonTrigger.tsx
1648
1671
  import { Button as BaseButton5 } from "@base-ui/react/button";
1649
1672
  import { IconChevronDown } from "@tabler/icons-react";
1650
- import { jsx as jsx26, jsxs as jsxs19 } from "react/jsx-runtime";
1673
+ import { jsx as jsx26, jsxs as jsxs20 } from "react/jsx-runtime";
1651
1674
  function PersonTrigger({ name, picture, fallback, size, open = false, compact = false, className, ...props }) {
1652
1675
  if (compact) {
1653
1676
  return /* @__PURE__ */ jsx26(
@@ -1663,7 +1686,7 @@ function PersonTrigger({ name, picture, fallback, size, open = false, compact =
1663
1686
  }
1664
1687
  );
1665
1688
  }
1666
- return /* @__PURE__ */ jsxs19(
1689
+ return /* @__PURE__ */ jsxs20(
1667
1690
  BaseButton5,
1668
1691
  {
1669
1692
  type: "button",
@@ -1689,7 +1712,7 @@ function PersonTrigger({ name, picture, fallback, size, open = false, compact =
1689
1712
  }
1690
1713
 
1691
1714
  // src/IdentityMenu.tsx
1692
- import { Fragment as Fragment5, jsx as jsx27, jsxs as jsxs20 } from "react/jsx-runtime";
1715
+ import { Fragment as Fragment5, jsx as jsx27, jsxs as jsxs21 } from "react/jsx-runtime";
1693
1716
  function IdentityPanel({ className, onClose = () => {
1694
1717
  }, ...rest }) {
1695
1718
  return /* @__PURE__ */ jsx27(MenuPanel, { className: cn("w-72", className), children: /* @__PURE__ */ jsx27(IdentityRows, { ...rest, onClose }) });
@@ -1700,23 +1723,23 @@ function IdentityRows({ me, signedIn, relayUrl, idBase, onCopyKey, onSignOut, on
1700
1723
  action();
1701
1724
  };
1702
1725
  const appRows = typeof children === "function" ? children(onClose) : children;
1703
- return /* @__PURE__ */ jsxs20(Fragment5, { children: [
1704
- /* @__PURE__ */ jsxs20(MenuSection, { label: signedIn ? "Signed in as" : "Acting as", children: [
1726
+ return /* @__PURE__ */ jsxs21(Fragment5, { children: [
1727
+ /* @__PURE__ */ jsxs21(MenuSection, { label: signedIn ? "Signed in as" : "Acting as", children: [
1705
1728
  /* @__PURE__ */ jsx27(MenuRow, { children: /* @__PURE__ */ jsx27(Person, { name: me.name, picture: me.picture, fallback: "Anonymous", size: 28, className: "text-body-2-strong" }) }),
1706
1729
  /* @__PURE__ */ jsx27(Note, { children: signedIn ? "Your Estiva ID. The same person you are in every Estiva app." : "A key held by this browser only. Nobody else knows who you are." }),
1707
- me.email && /* @__PURE__ */ jsxs20(Note, { children: [
1730
+ me.email && /* @__PURE__ */ jsxs21(Note, { children: [
1708
1731
  me.email,
1709
1732
  " \xB7 known to Estiva, never published to the relay"
1710
1733
  ] })
1711
1734
  ] }),
1712
- relayUrl && /* @__PURE__ */ jsxs20(Fragment5, { children: [
1735
+ relayUrl && /* @__PURE__ */ jsxs21(Fragment5, { children: [
1713
1736
  /* @__PURE__ */ jsx27(Divider, { className: "mx-0 my-2" }),
1714
- /* @__PURE__ */ jsxs20(MenuSection, { label: "Workspace", children: [
1737
+ /* @__PURE__ */ jsxs21(MenuSection, { label: "Workspace", children: [
1715
1738
  /* @__PURE__ */ jsx27(MenuRow, { children: /* @__PURE__ */ jsx27("span", { className: "break-all font-mono text-caption text-text-primary", children: relayUrl }) }),
1716
1739
  /* @__PURE__ */ jsx27(Note, { children: "Everyone on this relay shares this workspace, in every app." })
1717
1740
  ] })
1718
1741
  ] }),
1719
- appRows && /* @__PURE__ */ jsxs20(Fragment5, { children: [
1742
+ appRows && /* @__PURE__ */ jsxs21(Fragment5, { children: [
1720
1743
  /* @__PURE__ */ jsx27(Divider, { className: "mx-0 my-2" }),
1721
1744
  appRows
1722
1745
  ] }),
@@ -1778,15 +1801,99 @@ function Note({ children }) {
1778
1801
  return /* @__PURE__ */ jsx27("span", { className: "px-2 pb-1.5 text-caption text-text-secondary", children });
1779
1802
  }
1780
1803
 
1804
+ // src/FilePicker.tsx
1805
+ import { forwardRef } from "react";
1806
+ import { jsx as jsx28 } from "react/jsx-runtime";
1807
+ var FilePicker = forwardRef(function FilePicker2({ onPick, ...props }, ref) {
1808
+ return /* @__PURE__ */ jsx28(
1809
+ "input",
1810
+ {
1811
+ ref,
1812
+ type: "file",
1813
+ "aria-hidden": "true",
1814
+ tabIndex: -1,
1815
+ className: "hidden",
1816
+ ...props,
1817
+ onChange: (event) => {
1818
+ const files = Array.from(event.target.files ?? []);
1819
+ event.target.value = "";
1820
+ if (files.length > 0) onPick(files);
1821
+ }
1822
+ }
1823
+ );
1824
+ });
1825
+
1826
+ // src/Form.tsx
1827
+ import { useLayoutEffect as useLayoutEffect3, useRef as useRef4 } from "react";
1828
+ import { Fieldset } from "@base-ui/react/fieldset";
1829
+ import { Form as BaseForm } from "@base-ui/react/form";
1830
+ import { jsx as jsx29 } from "react/jsx-runtime";
1831
+ var CONTROL2 = 'input:not([type="hidden"]), textarea, select, button, [role="checkbox"], [role="combobox"], [tabindex]:not([tabindex="-1"])';
1832
+ function usable(element) {
1833
+ return element instanceof HTMLElement && element.isConnected && element.matches(CONTROL2) && !element.matches(":disabled") && element.getAttribute("aria-disabled") !== "true";
1834
+ }
1835
+ function Form({ onSubmit, busy: ownBusy = false, className, children, ...props }) {
1836
+ const outerBusy = useFormBusy();
1837
+ const busy = ownBusy || outerBusy;
1838
+ const form = useRef4(null);
1839
+ const sender = useRef4(null);
1840
+ const holding = useRef4(false);
1841
+ const lastInside = useRef4(null);
1842
+ useLayoutEffect3(() => {
1843
+ const element = form.current;
1844
+ if (!element) return;
1845
+ if (busy) {
1846
+ const active = document.activeElement;
1847
+ const from = active && active !== element && element.contains(active) ? active : !active || active === document.body ? lastInside.current : null;
1848
+ if (from?.isConnected) {
1849
+ sender.current = from;
1850
+ holding.current = true;
1851
+ element.focus();
1852
+ }
1853
+ return;
1854
+ }
1855
+ if (!holding.current) return;
1856
+ holding.current = false;
1857
+ if (document.activeElement !== element && document.activeElement !== document.body) return;
1858
+ const invalid = Array.from(element.querySelectorAll("[data-invalid]")).find(usable);
1859
+ const target = invalid ?? (usable(sender.current) ? sender.current : Array.from(element.querySelectorAll(CONTROL2)).find(usable));
1860
+ sender.current = null;
1861
+ target?.focus();
1862
+ }, [busy]);
1863
+ return /* @__PURE__ */ jsx29(
1864
+ BaseForm,
1865
+ {
1866
+ ref: form,
1867
+ ...props,
1868
+ tabIndex: busy ? -1 : props.tabIndex,
1869
+ className: cn("outline-none", className),
1870
+ onFocus: (event) => {
1871
+ if (event.target !== form.current) lastInside.current = event.target;
1872
+ props.onFocus?.(event);
1873
+ },
1874
+ onBlur: (event) => {
1875
+ const next = event.relatedTarget;
1876
+ if (next && !form.current?.contains(next)) lastInside.current = null;
1877
+ props.onBlur?.(event);
1878
+ },
1879
+ onSubmit: (event) => {
1880
+ event.preventDefault();
1881
+ void onSubmit();
1882
+ },
1883
+ children: /* @__PURE__ */ jsx29(Fieldset.Root, { disabled: busy, className: "contents", children: /* @__PURE__ */ jsx29(FormBusyContext.Provider, { value: busy, children }) })
1884
+ }
1885
+ );
1886
+ }
1887
+
1781
1888
  // src/Select.tsx
1782
1889
  import { IconCheck as IconCheck2, IconChevronDown as IconChevronDown2 } from "@tabler/icons-react";
1783
1890
  import { Select as BaseSelect } from "@base-ui/react/select";
1784
- import { jsx as jsx28, jsxs as jsxs21 } from "react/jsx-runtime";
1891
+ import { jsx as jsx30, jsxs as jsxs22 } from "react/jsx-runtime";
1785
1892
  var GAP4 = 4;
1786
1893
  var VIEWPORT_PAD4 = 8;
1787
1894
  function Select({ value, onChange, options, size = "default", ariaLabel, placeholder = "Select\u2026", disabled, className, ...aria }) {
1788
1895
  const selected = options.find((o) => o.value === value);
1789
- return /* @__PURE__ */ jsxs21(
1896
+ return /* @__PURE__ */ jsxs22(
1790
1897
  BaseSelect.Root,
1791
1898
  {
1792
1899
  value,
@@ -1794,7 +1901,7 @@ function Select({ value, onChange, options, size = "default", ariaLabel, placeho
1794
1901
  disabled,
1795
1902
  modal: false,
1796
1903
  children: [
1797
- /* @__PURE__ */ jsxs21(
1904
+ /* @__PURE__ */ jsxs22(
1798
1905
  BaseSelect.Trigger,
1799
1906
  {
1800
1907
  "aria-label": ariaLabel,
@@ -1821,20 +1928,20 @@ function Select({ value, onChange, options, size = "default", ariaLabel, placeho
1821
1928
  className
1822
1929
  ),
1823
1930
  children: [
1824
- /* @__PURE__ */ jsxs21("span", { className: cn("flex min-w-0 items-center gap-2", !selected && "text-text-muted"), children: [
1825
- selected?.leading && /* @__PURE__ */ jsx28("span", { className: "flex shrink-0 items-center", children: selected.leading }),
1826
- /* @__PURE__ */ jsx28(BaseSelect.Value, { className: "truncate", children: () => selected?.label ?? placeholder })
1931
+ /* @__PURE__ */ jsxs22("span", { className: cn("flex min-w-0 items-center gap-2", !selected && "text-text-muted"), children: [
1932
+ selected?.leading && /* @__PURE__ */ jsx30("span", { className: "flex shrink-0 items-center", children: selected.leading }),
1933
+ /* @__PURE__ */ jsx30(BaseSelect.Value, { className: "truncate", children: () => selected?.label ?? placeholder })
1827
1934
  ] }),
1828
- /* @__PURE__ */ jsx28(
1935
+ /* @__PURE__ */ jsx30(
1829
1936
  BaseSelect.Icon,
1830
1937
  {
1831
- render: /* @__PURE__ */ jsx28(IconChevronDown2, { size: size === "small" ? 14 : 16, stroke: 1.5, className: "shrink-0 text-text-secondary" })
1938
+ render: /* @__PURE__ */ jsx30(IconChevronDown2, { size: size === "small" ? 14 : 16, stroke: 1.5, className: "shrink-0 text-text-secondary" })
1832
1939
  }
1833
1940
  )
1834
1941
  ]
1835
1942
  }
1836
1943
  ),
1837
- /* @__PURE__ */ jsx28(BaseSelect.Portal, { children: /* @__PURE__ */ jsx28(
1944
+ /* @__PURE__ */ jsx30(BaseSelect.Portal, { children: /* @__PURE__ */ jsx30(
1838
1945
  BaseSelect.Positioner,
1839
1946
  {
1840
1947
  side: "bottom",
@@ -1843,25 +1950,25 @@ function Select({ value, onChange, options, size = "default", ariaLabel, placeho
1843
1950
  collisionPadding: VIEWPORT_PAD4,
1844
1951
  alignItemWithTrigger: false,
1845
1952
  className: "z-50 data-[anchor-hidden]:hidden",
1846
- children: /* @__PURE__ */ jsx28(
1953
+ children: /* @__PURE__ */ jsx30(
1847
1954
  BaseSelect.Popup,
1848
1955
  {
1849
- render: /* @__PURE__ */ jsx28(MenuPanel, {}),
1956
+ render: /* @__PURE__ */ jsx30(MenuPanel, {}),
1850
1957
  className: "min-w-[var(--anchor-width)] p-0",
1851
- children: /* @__PURE__ */ jsx28(ScrollArea, { viewportClassName: "max-h-[min(288px,var(--available-height))]", contentClassName: "flex flex-col p-2", children: options.map((option) => /* @__PURE__ */ jsxs21(
1958
+ children: /* @__PURE__ */ jsx30(ScrollArea, { viewportClassName: "max-h-[min(288px,var(--available-height))]", contentClassName: "flex flex-col p-2", children: options.map((option) => /* @__PURE__ */ jsxs22(
1852
1959
  BaseSelect.Item,
1853
1960
  {
1854
1961
  value: option.value,
1855
1962
  className: cn(menuItemClassName({ size: "default" }), "justify-between data-[selected]:font-medium"),
1856
1963
  children: [
1857
- /* @__PURE__ */ jsxs21("span", { className: "flex min-w-0 items-center gap-2", children: [
1858
- option.leading && /* @__PURE__ */ jsx28("span", { className: "flex shrink-0 items-center", children: option.leading }),
1859
- /* @__PURE__ */ jsx28(BaseSelect.ItemText, { className: "truncate text-body-2 text-text-primary", children: option.label })
1964
+ /* @__PURE__ */ jsxs22("span", { className: "flex min-w-0 items-center gap-2", children: [
1965
+ option.leading && /* @__PURE__ */ jsx30("span", { className: "flex shrink-0 items-center", children: option.leading }),
1966
+ /* @__PURE__ */ jsx30(BaseSelect.ItemText, { className: "truncate text-body-2 text-text-primary", children: option.label })
1860
1967
  ] }),
1861
- /* @__PURE__ */ jsx28(
1968
+ /* @__PURE__ */ jsx30(
1862
1969
  BaseSelect.ItemIndicator,
1863
1970
  {
1864
- render: /* @__PURE__ */ jsx28(IconCheck2, { size: 16, stroke: 1.5, className: "shrink-0 text-text-secondary" })
1971
+ render: /* @__PURE__ */ jsx30(IconCheck2, { size: 16, stroke: 1.5, className: "shrink-0 text-text-secondary" })
1865
1972
  }
1866
1973
  )
1867
1974
  ]
@@ -1878,17 +1985,20 @@ function Select({ value, onChange, options, size = "default", ariaLabel, placeho
1878
1985
  }
1879
1986
 
1880
1987
  // src/TextInput.tsx
1881
- import { forwardRef } from "react";
1988
+ import { forwardRef as forwardRef2 } from "react";
1882
1989
  import { Input } from "@base-ui/react/input";
1883
- import { jsx as jsx29 } from "react/jsx-runtime";
1884
- var TextInput = forwardRef(function TextInput2({ className, type = "text", size = "default", ...props }, ref) {
1885
- return /* @__PURE__ */ jsx29(
1990
+ import { jsx as jsx31 } from "react/jsx-runtime";
1991
+ var TextInput = forwardRef2(function TextInput2({ className, type = "text", size = "default", ...props }, ref) {
1992
+ return /* @__PURE__ */ jsx31(
1886
1993
  Input,
1887
1994
  {
1888
1995
  ref,
1889
1996
  type,
1890
1997
  className: cn(
1891
- "bg-bg-inset border border-border-default focus:border-border-focus rounded-lg",
1998
+ // The border strengthens on hover, as Select's and ChipInput's do (Katerina, 16 September:
1999
+ // "aren't there hover states in text input and text area?"). Focus comes after hover in
2000
+ // Tailwind's order, so a focused field keeps the focus border under the pointer.
2001
+ "bg-bg-inset border border-border-default hover:border-border-strong focus:border-border-focus rounded-lg",
1892
2002
  // The small size is the small Select's trigger, class for class.
1893
2003
  size === "default" && "px-3 py-2 text-input-value",
1894
2004
  size === "small" && "h-6 px-2 text-caption",
@@ -1904,17 +2014,20 @@ var TextInput = forwardRef(function TextInput2({ className, type = "text", size
1904
2014
  });
1905
2015
 
1906
2016
  // src/Textarea.tsx
1907
- import { forwardRef as forwardRef2 } from "react";
1908
- import { Field as BaseField2 } from "@base-ui/react/field";
1909
- import { jsx as jsx30 } from "react/jsx-runtime";
1910
- var Textarea = forwardRef2(function Textarea2({ className, ...props }, ref) {
1911
- return /* @__PURE__ */ jsx30(
1912
- BaseField2.Control,
2017
+ import { forwardRef as forwardRef3 } from "react";
2018
+ import { Field as BaseField3 } from "@base-ui/react/field";
2019
+ import { jsx as jsx32 } from "react/jsx-runtime";
2020
+ var Textarea = forwardRef3(function Textarea2({ className, ...props }, ref) {
2021
+ return /* @__PURE__ */ jsx32(
2022
+ BaseField3.Control,
1913
2023
  {
1914
2024
  ref,
1915
- render: /* @__PURE__ */ jsx30("textarea", {}),
2025
+ render: /* @__PURE__ */ jsx32("textarea", {}),
1916
2026
  className: cn(
1917
- "bg-bg-inset border border-border-default focus:border-border-focus rounded-lg px-3 py-2",
2027
+ // The border strengthens on hover, as Select's and ChipInput's do (Katerina, 16 September:
2028
+ // "aren't there hover states in text input and text area?"). Focus comes after hover in
2029
+ // Tailwind's order, so a focused field keeps the focus border under the pointer.
2030
+ "bg-bg-inset border border-border-default hover:border-border-strong focus:border-border-focus rounded-lg px-3 py-2",
1918
2031
  "text-input-value text-text-primary placeholder:text-text-muted",
1919
2032
  "resize-none outline-none transition-colors",
1920
2033
  "disabled:pointer-events-none disabled:bg-bg-disabled disabled:text-text-disabled",
@@ -1930,24 +2043,24 @@ var Textarea = forwardRef2(function Textarea2({ className, ...props }, ref) {
1930
2043
  import { useState as useState4 } from "react";
1931
2044
 
1932
2045
  // src/DialogShell.tsx
1933
- import { useRef as useRef4 } from "react";
2046
+ import { useRef as useRef5 } from "react";
1934
2047
  import { Dialog as Dialog2 } from "@base-ui/react/dialog";
1935
2048
  import { AlertDialog } from "@base-ui/react/alert-dialog";
1936
2049
  import { IconX as IconX4 } from "@tabler/icons-react";
1937
- import { jsx as jsx31, jsxs as jsxs22 } from "react/jsx-runtime";
2050
+ import { jsx as jsx33, jsxs as jsxs23 } from "react/jsx-runtime";
1938
2051
  function DialogShell({ title, onClose, headerContent, footer, children, bodyClassName, bodyMaxHeight, width = 502, alert = false }) {
1939
2052
  const Parts = alert ? AlertDialog : Dialog2;
1940
- const popupRef = useRef4(null);
1941
- return /* @__PURE__ */ jsx31(
2053
+ const popupRef = useRef5(null);
2054
+ return /* @__PURE__ */ jsx33(
1942
2055
  Parts.Root,
1943
2056
  {
1944
2057
  open: true,
1945
2058
  onOpenChange: (open) => {
1946
2059
  if (!open) onClose();
1947
2060
  },
1948
- children: /* @__PURE__ */ jsxs22(Parts.Portal, { children: [
1949
- /* @__PURE__ */ jsx31(Parts.Backdrop, { className: "fixed inset-0 z-40 bg-scrim" }),
1950
- /* @__PURE__ */ jsx31("div", { className: "fixed inset-0 z-50 flex items-center justify-center pointer-events-none", children: /* @__PURE__ */ jsxs22(
2061
+ children: /* @__PURE__ */ jsxs23(Parts.Portal, { children: [
2062
+ /* @__PURE__ */ jsx33(Parts.Backdrop, { className: "fixed inset-0 z-40 bg-scrim" }),
2063
+ /* @__PURE__ */ jsx33("div", { className: "fixed inset-0 z-50 flex items-center justify-center pointer-events-none", children: /* @__PURE__ */ jsxs23(
1951
2064
  Parts.Popup,
1952
2065
  {
1953
2066
  ref: popupRef,
@@ -1956,16 +2069,16 @@ function DialogShell({ title, onClose, headerContent, footer, children, bodyClas
1956
2069
  className: "bg-bg-elevated border border-border-subtle rounded-lg shadow-lg pointer-events-auto flex flex-col overflow-hidden outline-none",
1957
2070
  style: { width },
1958
2071
  children: [
1959
- /* @__PURE__ */ jsxs22("div", { className: "h-12 flex items-center justify-between pl-5 pr-4 border-b border-border-subtle shrink-0", children: [
1960
- headerContent ?? /* @__PURE__ */ jsx31(Parts.Title, { className: "text-h4 text-text-primary", render: /* @__PURE__ */ jsx31("span", {}), children: title }),
1961
- /* @__PURE__ */ jsx31(
2072
+ /* @__PURE__ */ jsxs23("div", { className: "h-12 flex items-center justify-between pl-5 pr-4 border-b border-border-subtle shrink-0", children: [
2073
+ headerContent ?? /* @__PURE__ */ jsx33(Parts.Title, { className: "text-h4 text-text-primary", render: /* @__PURE__ */ jsx33("span", {}), children: title }),
2074
+ /* @__PURE__ */ jsx33(
1962
2075
  Parts.Close,
1963
2076
  {
1964
- render: /* @__PURE__ */ jsx31(IconButton, { tooltip: "Close", "aria-label": "Close", children: /* @__PURE__ */ jsx31(IconX4, { size: 16, stroke: 1.5 }) })
2077
+ render: /* @__PURE__ */ jsx33(IconButton, { tooltip: "Close", "aria-label": "Close", children: /* @__PURE__ */ jsx33(IconX4, { size: 16, stroke: 1.5 }) })
1965
2078
  }
1966
2079
  )
1967
2080
  ] }),
1968
- bodyMaxHeight ? /* @__PURE__ */ jsx31(
2081
+ bodyMaxHeight ? /* @__PURE__ */ jsx33(
1969
2082
  ScrollArea,
1970
2083
  {
1971
2084
  className: cn(footer != null && "border-b border-border-subtle"),
@@ -1973,8 +2086,8 @@ function DialogShell({ title, onClose, headerContent, footer, children, bodyClas
1973
2086
  contentClassName: cn("pl-5 pr-4 py-4", bodyClassName),
1974
2087
  children
1975
2088
  }
1976
- ) : /* @__PURE__ */ jsx31("div", { className: cn("pl-5 pr-4 py-4", footer != null && "border-b border-border-subtle", bodyClassName), children }),
1977
- footer != null && /* @__PURE__ */ jsx31("div", { className: "h-12 flex items-center justify-end gap-2 pl-5 pr-4 shrink-0", children: footer })
2089
+ ) : /* @__PURE__ */ jsx33("div", { className: cn("pl-5 pr-4 py-4", footer != null && "border-b border-border-subtle", bodyClassName), children }),
2090
+ footer != null && /* @__PURE__ */ jsx33("div", { className: "h-12 flex items-center justify-end gap-2 pl-5 pr-4 shrink-0", children: footer })
1978
2091
  ]
1979
2092
  }
1980
2093
  ) })
@@ -1984,7 +2097,7 @@ function DialogShell({ title, onClose, headerContent, footer, children, bodyClas
1984
2097
  }
1985
2098
 
1986
2099
  // src/ConfirmDialog.tsx
1987
- import { Fragment as Fragment6, jsx as jsx32, jsxs as jsxs23 } from "react/jsx-runtime";
2100
+ import { Fragment as Fragment6, jsx as jsx34, jsxs as jsxs24 } from "react/jsx-runtime";
1988
2101
  function ConfirmDialog({ title, children, confirmLabel, destructive = false, onConfirm, onClose }) {
1989
2102
  const [busy, setBusy] = useState4(false);
1990
2103
  const confirm = async () => {
@@ -1996,16 +2109,16 @@ function ConfirmDialog({ title, children, confirmLabel, destructive = false, onC
1996
2109
  setBusy(false);
1997
2110
  }
1998
2111
  };
1999
- return /* @__PURE__ */ jsx32(
2112
+ return /* @__PURE__ */ jsx34(
2000
2113
  DialogShell,
2001
2114
  {
2002
2115
  alert: true,
2003
2116
  title,
2004
2117
  onClose,
2005
2118
  bodyClassName: "flex flex-col gap-3 text-body-2 text-text-primary",
2006
- footer: /* @__PURE__ */ jsxs23(Fragment6, { children: [
2007
- /* @__PURE__ */ jsx32(Button, { variant: "muted", onClick: onClose, disabled: busy, children: "Cancel" }),
2008
- /* @__PURE__ */ jsx32(Button, { variant: destructive ? "destructive" : "primary", onClick: () => void confirm(), disabled: busy, children: confirmLabel })
2119
+ footer: /* @__PURE__ */ jsxs24(Fragment6, { children: [
2120
+ /* @__PURE__ */ jsx34(Button, { variant: "muted", onClick: onClose, disabled: busy, children: "Cancel" }),
2121
+ /* @__PURE__ */ jsx34(Button, { variant: destructive ? "destructive" : "primary", onClick: () => void confirm(), disabled: busy, children: confirmLabel })
2009
2122
  ] }),
2010
2123
  children
2011
2124
  }
@@ -2013,15 +2126,15 @@ function ConfirmDialog({ title, children, confirmLabel, destructive = false, onC
2013
2126
  }
2014
2127
 
2015
2128
  // src/EditableText.tsx
2016
- import { useEffect as useEffect2, useRef as useRef5, useState as useState5 } from "react";
2017
- import { Field as BaseField3 } from "@base-ui/react/field";
2129
+ import { useEffect as useEffect2, useRef as useRef6, useState as useState5 } from "react";
2130
+ import { Field as BaseField4 } from "@base-ui/react/field";
2018
2131
  import { Input as Input2 } from "@base-ui/react/input";
2019
- import { jsx as jsx33 } from "react/jsx-runtime";
2132
+ import { jsx as jsx35 } from "react/jsx-runtime";
2020
2133
  function EditableText({ value, display, displayNode, placeholder, onCommit, multiline = false, className, label, readOnly = false }) {
2021
2134
  const [editing, setEditing] = useState5(false);
2022
2135
  const [draft, setDraft] = useState5(value);
2023
2136
  const [busy, setBusy] = useState5(false);
2024
- const fieldRef = useRef5(null);
2137
+ const fieldRef = useRef6(null);
2025
2138
  useEffect2(() => {
2026
2139
  if (editing) {
2027
2140
  fieldRef.current?.focus();
@@ -2074,7 +2187,7 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
2074
2187
  written and never read. Read-only, this is a line of text: whatever
2075
2188
  names the region around it (a `Field`, a `Property`) names this too.
2076
2189
  */
2077
- /* @__PURE__ */ jsx33(
2190
+ /* @__PURE__ */ jsx35(
2078
2191
  "div",
2079
2192
  {
2080
2193
  className: cn("w-full px-2 py-1", multiline && !displayNode && "whitespace-pre-wrap", display ?? value ? "text-text-primary" : "text-text-muted", className),
@@ -2084,11 +2197,11 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
2084
2197
  );
2085
2198
  }
2086
2199
  if (editing) {
2087
- return multiline ? /* @__PURE__ */ jsx33(
2088
- BaseField3.Control,
2200
+ return multiline ? /* @__PURE__ */ jsx35(
2201
+ BaseField4.Control,
2089
2202
  {
2090
2203
  ref: fieldRef,
2091
- render: /* @__PURE__ */ jsx33("textarea", { rows: 4 }),
2204
+ render: /* @__PURE__ */ jsx35("textarea", { rows: 4 }),
2092
2205
  "aria-label": label,
2093
2206
  value: draft,
2094
2207
  disabled: busy,
@@ -2097,7 +2210,7 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
2097
2210
  onBlur: () => void commit(),
2098
2211
  className: fieldClass
2099
2212
  }
2100
- ) : /* @__PURE__ */ jsx33(
2213
+ ) : /* @__PURE__ */ jsx35(
2101
2214
  Input2,
2102
2215
  {
2103
2216
  ref: fieldRef,
@@ -2111,7 +2224,7 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
2111
2224
  }
2112
2225
  );
2113
2226
  }
2114
- return /* @__PURE__ */ jsx33(
2227
+ return /* @__PURE__ */ jsx35(
2115
2228
  "button",
2116
2229
  {
2117
2230
  type: "button",
@@ -2130,7 +2243,7 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
2130
2243
 
2131
2244
  // src/ProgressBar.tsx
2132
2245
  import { Progress } from "@base-ui/react/progress";
2133
- import { jsx as jsx34 } from "react/jsx-runtime";
2246
+ import { jsx as jsx36 } from "react/jsx-runtime";
2134
2247
  var TRACK_CLASSES = {
2135
2248
  default: "h-1.5 w-full overflow-hidden rounded-full bg-bg-inset",
2136
2249
  // 4px, Katerina's ruling of 14 September; Peek's own bar is 3px until it takes this one.
@@ -2143,16 +2256,16 @@ var INDICATOR_CLASSES = {
2143
2256
  function ProgressBar({ value, max, label, variant = "default", className }) {
2144
2257
  return (
2145
2258
  // `max={0}` needs no guard: Base UI reads the 0/0 share as an empty bar.
2146
- /* @__PURE__ */ jsx34(Progress.Root, { value, max, "aria-label": label, className, children: /* @__PURE__ */ jsx34(Progress.Track, { className: TRACK_CLASSES[variant], children: /* @__PURE__ */ jsx34(Progress.Indicator, { className: INDICATOR_CLASSES[variant] }) }) })
2259
+ /* @__PURE__ */ jsx36(Progress.Root, { value, max, "aria-label": label, className, children: /* @__PURE__ */ jsx36(Progress.Track, { className: TRACK_CLASSES[variant], children: /* @__PURE__ */ jsx36(Progress.Indicator, { className: INDICATOR_CLASSES[variant] }) }) })
2147
2260
  );
2148
2261
  }
2149
2262
 
2150
2263
  // src/Breadcrumb.tsx
2151
- import { Fragment as Fragment7, useCallback as useCallback2, useLayoutEffect as useLayoutEffect3, useRef as useRef6, useState as useState6 } from "react";
2152
- import { jsx as jsx35, jsxs as jsxs24 } from "react/jsx-runtime";
2264
+ import { Fragment as Fragment7, useCallback as useCallback2, useLayoutEffect as useLayoutEffect4, useRef as useRef7, useState as useState6 } from "react";
2265
+ import { jsx as jsx37, jsxs as jsxs25 } from "react/jsx-runtime";
2153
2266
  function Breadcrumb({ items, className }) {
2154
- const navRef = useRef6(null);
2155
- const labelRefs = useRef6([]);
2267
+ const navRef = useRef7(null);
2268
+ const labelRefs = useRef7([]);
2156
2269
  const [truncated, setTruncated] = useState6(/* @__PURE__ */ new Set());
2157
2270
  const measure = useCallback2(() => {
2158
2271
  const next = /* @__PURE__ */ new Set();
@@ -2161,7 +2274,7 @@ function Breadcrumb({ items, className }) {
2161
2274
  });
2162
2275
  setTruncated((prev) => prev.size === next.size && [...next].every((i) => prev.has(i)) ? prev : next);
2163
2276
  }, []);
2164
- useLayoutEffect3(() => {
2277
+ useLayoutEffect4(() => {
2165
2278
  measure();
2166
2279
  const nav = navRef.current;
2167
2280
  if (!nav || typeof ResizeObserver === "undefined") return;
@@ -2169,7 +2282,7 @@ function Breadcrumb({ items, className }) {
2169
2282
  observer.observe(nav);
2170
2283
  return () => observer.disconnect();
2171
2284
  }, [measure, items]);
2172
- return /* @__PURE__ */ jsx35("nav", { ref: navRef, "aria-label": "Breadcrumb", className: cn("flex min-w-0 items-center gap-1.5 text-body-2", className), children: items.map((item, index) => {
2285
+ return /* @__PURE__ */ jsx37("nav", { ref: navRef, "aria-label": "Breadcrumb", className: cn("flex min-w-0 items-center gap-1.5 text-body-2", className), children: items.map((item, index) => {
2173
2286
  const last = index === items.length - 1;
2174
2287
  const tone = item.muted || last && item.mono ? "text-text-muted" : last ? "text-text-primary" : "text-text-secondary";
2175
2288
  const text = cn(
@@ -2187,25 +2300,25 @@ function Breadcrumb({ items, className }) {
2187
2300
  // `plain` adds no look of its own: a crumb keeps the trail's size and
2188
2301
  // tone, and brightens on hover. The package's own Link, so a trail
2189
2302
  // follows whatever a link learns to do (UIG-5).
2190
- /* @__PURE__ */ jsx35(Link, { ref: setLabelRef, variant: "plain", href: item.href, onClick: item.onClick, className: cn(text, "hover:text-text-primary"), children: item.label })
2191
- ) : /* @__PURE__ */ jsx35("span", { ref: setLabelRef, className: text, "aria-current": last ? "page" : void 0, children: item.label });
2192
- return /* @__PURE__ */ jsxs24(Fragment7, { children: [
2193
- index > 0 && /* @__PURE__ */ jsx35("span", { "aria-hidden": "true", className: "shrink-0 text-text-muted", children: "/" }),
2194
- item.icon && /* @__PURE__ */ jsx35("span", { "aria-hidden": "true", className: cn("flex shrink-0", tone), children: item.icon }),
2303
+ /* @__PURE__ */ jsx37(Link, { ref: setLabelRef, variant: "plain", href: item.href, onClick: item.onClick, className: cn(text, "hover:text-text-primary"), children: item.label })
2304
+ ) : /* @__PURE__ */ jsx37("span", { ref: setLabelRef, className: text, "aria-current": last ? "page" : void 0, children: item.label });
2305
+ return /* @__PURE__ */ jsxs25(Fragment7, { children: [
2306
+ index > 0 && /* @__PURE__ */ jsx37("span", { "aria-hidden": "true", className: "shrink-0 text-text-muted", children: "/" }),
2307
+ item.icon && /* @__PURE__ */ jsx37("span", { "aria-hidden": "true", className: cn("flex shrink-0", tone), children: item.icon }),
2195
2308
  truncated.has(index) ? (
2196
2309
  // `min-w-0 shrink` undoes the wrapper's own shrink-0 — the crumb
2197
2310
  // must keep truncating inside it, or wrapping it would widen the
2198
2311
  // trail and the tooltip would never be needed again.
2199
- /* @__PURE__ */ jsx35(WithTooltip, { label: item.label, wrapperClassName: "min-w-0 shrink", children: crumb })
2312
+ /* @__PURE__ */ jsx37(WithTooltip, { label: item.label, wrapperClassName: "min-w-0 shrink", children: crumb })
2200
2313
  ) : crumb
2201
2314
  ] }, `${item.label}-${index}`);
2202
2315
  }) });
2203
2316
  }
2204
2317
 
2205
2318
  // src/NavItem.tsx
2206
- import { jsx as jsx36, jsxs as jsxs25 } from "react/jsx-runtime";
2319
+ import { jsx as jsx38, jsxs as jsxs26 } from "react/jsx-runtime";
2207
2320
  function NavItem({ label, href, count, countLabel, active = false, icon, className, ...props }) {
2208
- return /* @__PURE__ */ jsxs25(
2321
+ return /* @__PURE__ */ jsxs26(
2209
2322
  "a",
2210
2323
  {
2211
2324
  href,
@@ -2220,9 +2333,9 @@ function NavItem({ label, href, count, countLabel, active = false, icon, classNa
2220
2333
  ),
2221
2334
  ...props,
2222
2335
  children: [
2223
- icon && /* @__PURE__ */ jsx36("span", { className: "flex shrink-0 items-center", children: icon }),
2224
- /* @__PURE__ */ jsx36("span", { className: "flex-1 truncate", children: label }),
2225
- count ? /* @__PURE__ */ jsx36(WithTooltip, { label: countLabel ?? `${count} open`, children: /* @__PURE__ */ jsx36("span", { className: "min-w-4 shrink-0 text-center font-mono text-caption tabular-nums text-text-muted", children: count }) }) : null
2336
+ icon && /* @__PURE__ */ jsx38("span", { className: "flex shrink-0 items-center", children: icon }),
2337
+ /* @__PURE__ */ jsx38("span", { className: "flex-1 truncate", children: label }),
2338
+ count ? /* @__PURE__ */ jsx38(WithTooltip, { label: countLabel ?? `${count} open`, children: /* @__PURE__ */ jsx38("span", { className: "min-w-4 shrink-0 text-center font-mono text-caption tabular-nums text-text-muted", children: count }) }) : null
2226
2339
  ]
2227
2340
  }
2228
2341
  );
@@ -2231,7 +2344,7 @@ function NavItem({ label, href, count, countLabel, active = false, icon, classNa
2231
2344
  // src/Popover.tsx
2232
2345
  import { useMemo as useMemo3 } from "react";
2233
2346
  import { Popover as BasePopover } from "@base-ui/react/popover";
2234
- import { jsx as jsx37, jsxs as jsxs26 } from "react/jsx-runtime";
2347
+ import { jsx as jsx39, jsxs as jsxs27 } from "react/jsx-runtime";
2235
2348
  var GAP5 = 4;
2236
2349
  var VIEWPORT_PAD5 = 8;
2237
2350
  function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpenChange, finalFocus, actionsRef, ariaLabel, children, className, contentClassName, maxHeight }) {
@@ -2240,7 +2353,7 @@ function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpe
2240
2353
  if (anchor instanceof Element) return anchor;
2241
2354
  return { getBoundingClientRect: () => anchor };
2242
2355
  }, [anchor]);
2243
- return /* @__PURE__ */ jsxs26(
2356
+ return /* @__PURE__ */ jsxs27(
2244
2357
  BasePopover.Root,
2245
2358
  {
2246
2359
  open,
@@ -2248,8 +2361,8 @@ function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpe
2248
2361
  actionsRef,
2249
2362
  modal: false,
2250
2363
  children: [
2251
- trigger && /* @__PURE__ */ jsx37(BasePopover.Trigger, { render: trigger, disabled: triggerDisabled(trigger) }),
2252
- /* @__PURE__ */ jsx37(BasePopover.Portal, { children: /* @__PURE__ */ jsx37(
2364
+ trigger && /* @__PURE__ */ jsx39(BasePopover.Trigger, { render: trigger, disabled: triggerDisabled(trigger) }),
2365
+ /* @__PURE__ */ jsx39(BasePopover.Portal, { children: /* @__PURE__ */ jsx39(
2253
2366
  BasePopover.Positioner,
2254
2367
  {
2255
2368
  anchor: anchorTarget,
@@ -2258,15 +2371,15 @@ function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpe
2258
2371
  sideOffset: GAP5,
2259
2372
  collisionPadding: VIEWPORT_PAD5,
2260
2373
  className: "z-50 data-[anchor-hidden]:hidden",
2261
- children: /* @__PURE__ */ jsx37(
2374
+ children: /* @__PURE__ */ jsx39(
2262
2375
  BasePopover.Popup,
2263
2376
  {
2264
2377
  "aria-label": ariaLabel,
2265
2378
  initialFocus: trigger ? void 0 : false,
2266
2379
  finalFocus,
2267
2380
  className: cn("min-w-[180px] outline-none p-0", className),
2268
- render: /* @__PURE__ */ jsx37(MenuPanel, {}),
2269
- children: /* @__PURE__ */ jsx37(
2381
+ render: /* @__PURE__ */ jsx39(MenuPanel, {}),
2382
+ children: /* @__PURE__ */ jsx39(
2270
2383
  ScrollArea,
2271
2384
  {
2272
2385
  viewportClassName: maxHeight ?? "max-h-[var(--available-height)]",
@@ -2285,9 +2398,9 @@ function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpe
2285
2398
 
2286
2399
  // src/Toolbar.tsx
2287
2400
  import { Toolbar as BaseToolbar } from "@base-ui/react/toolbar";
2288
- import { jsx as jsx38 } from "react/jsx-runtime";
2401
+ import { jsx as jsx40 } from "react/jsx-runtime";
2289
2402
  function Toolbar({ "aria-label": ariaLabel, orientation = "horizontal", loopFocus = true, surface = true, children, className }) {
2290
- const strip = /* @__PURE__ */ jsx38(
2403
+ const strip = /* @__PURE__ */ jsx40(
2291
2404
  BaseToolbar.Root,
2292
2405
  {
2293
2406
  "aria-label": ariaLabel,
@@ -2298,24 +2411,24 @@ function Toolbar({ "aria-label": ariaLabel, orientation = "horizontal", loopFocu
2298
2411
  }
2299
2412
  );
2300
2413
  if (!surface) return strip;
2301
- return /* @__PURE__ */ jsx38(MenuPanel, { className: "w-fit p-1", children: strip });
2414
+ return /* @__PURE__ */ jsx40(MenuPanel, { className: "w-fit p-1", children: strip });
2302
2415
  }
2303
2416
  function ToolbarButton({ ref, disabled, disabledReason, ...props }) {
2304
- return /* @__PURE__ */ jsx38(
2417
+ return /* @__PURE__ */ jsx40(
2305
2418
  BaseToolbar.Button,
2306
2419
  {
2307
2420
  ref,
2308
2421
  disabled: disabled || !!disabledReason,
2309
2422
  focusableWhenDisabled: true,
2310
- render: /* @__PURE__ */ jsx38(IconButton, { disabled, disabledReason, ...props })
2423
+ render: /* @__PURE__ */ jsx40(IconButton, { disabled, disabledReason, ...props })
2311
2424
  }
2312
2425
  );
2313
2426
  }
2314
2427
  function ToolbarInput({ size, ...props }) {
2315
- return /* @__PURE__ */ jsx38(BaseToolbar.Input, { render: /* @__PURE__ */ jsx38(TextInput, { size }), ...props });
2428
+ return /* @__PURE__ */ jsx40(BaseToolbar.Input, { render: /* @__PURE__ */ jsx40(TextInput, { size }), ...props });
2316
2429
  }
2317
2430
  function ToolbarSeparator({ className }) {
2318
- return /* @__PURE__ */ jsx38(
2431
+ return /* @__PURE__ */ jsx40(
2319
2432
  BaseToolbar.Separator,
2320
2433
  {
2321
2434
  orientation: "vertical",
@@ -2325,9 +2438,9 @@ function ToolbarSeparator({ className }) {
2325
2438
  }
2326
2439
 
2327
2440
  // src/ReactionPicker.tsx
2328
- import { jsx as jsx39 } from "react/jsx-runtime";
2441
+ import { jsx as jsx41 } from "react/jsx-runtime";
2329
2442
  function ReactionPicker({ options, onSelect, "aria-label": ariaLabel = "Reactions", surface = true, className }) {
2330
- return /* @__PURE__ */ jsx39(Toolbar, { "aria-label": ariaLabel, surface, className: cn("gap-0.5", className), children: options.map((option) => (
2443
+ return /* @__PURE__ */ jsx41(Toolbar, { "aria-label": ariaLabel, surface, className: cn("gap-0.5", className), children: options.map((option) => (
2331
2444
  /*
2332
2445
  A `ToolbarButton`, not a button in a tooltip wrapper. The wrapper
2333
2446
  would become the toolbar's item and the button inside it would never
@@ -2337,14 +2450,14 @@ function ReactionPicker({ options, onSelect, "aria-label": ariaLabel = "Reaction
2337
2450
  The tooltip names it for a pointer, `aria-label` for everything else,
2338
2451
  and both say the meaning rather than the glyph.
2339
2452
  */
2340
- /* @__PURE__ */ jsx39(
2453
+ /* @__PURE__ */ jsx41(
2341
2454
  ToolbarButton,
2342
2455
  {
2343
2456
  "aria-label": option.label,
2344
2457
  tooltip: option.label,
2345
2458
  onClick: () => onSelect(option.emoji),
2346
2459
  className: "size-7 text-h3 leading-none",
2347
- children: /* @__PURE__ */ jsx39("span", { "aria-hidden": "true", children: option.emoji })
2460
+ children: /* @__PURE__ */ jsx41("span", { "aria-hidden": "true", children: option.emoji })
2348
2461
  },
2349
2462
  option.emoji
2350
2463
  )
@@ -2353,23 +2466,23 @@ function ReactionPicker({ options, onSelect, "aria-label": ariaLabel = "Reaction
2353
2466
 
2354
2467
  // src/PreviewCard.tsx
2355
2468
  import { PreviewCard as BasePreviewCard } from "@base-ui/react/preview-card";
2356
- import { jsx as jsx40, jsxs as jsxs27 } from "react/jsx-runtime";
2469
+ import { jsx as jsx42, jsxs as jsxs28 } from "react/jsx-runtime";
2357
2470
  var GAP6 = 12;
2358
2471
  var VIEWPORT_PAD6 = 8;
2359
2472
  var OPEN_DELAY2 = 350;
2360
2473
  var CLOSE_DELAY = 200;
2361
2474
  function PreviewCard({ content, children, side = "right", delay = OPEN_DELAY2, closeDelay = CLOSE_DELAY, className, wrapperClassName }) {
2362
- return /* @__PURE__ */ jsxs27(BasePreviewCard.Root, { children: [
2363
- /* @__PURE__ */ jsx40(
2475
+ return /* @__PURE__ */ jsxs28(BasePreviewCard.Root, { children: [
2476
+ /* @__PURE__ */ jsx42(
2364
2477
  BasePreviewCard.Trigger,
2365
2478
  {
2366
2479
  delay,
2367
2480
  closeDelay,
2368
- render: /* @__PURE__ */ jsx40("span", { className: cn("inline-flex", wrapperClassName) }),
2481
+ render: /* @__PURE__ */ jsx42("span", { className: cn("inline-flex", wrapperClassName) }),
2369
2482
  children
2370
2483
  }
2371
2484
  ),
2372
- /* @__PURE__ */ jsx40(BasePreviewCard.Portal, { children: /* @__PURE__ */ jsx40(
2485
+ /* @__PURE__ */ jsx42(BasePreviewCard.Portal, { children: /* @__PURE__ */ jsx42(
2373
2486
  BasePreviewCard.Positioner,
2374
2487
  {
2375
2488
  side,
@@ -2377,12 +2490,12 @@ function PreviewCard({ content, children, side = "right", delay = OPEN_DELAY2, c
2377
2490
  sideOffset: GAP6,
2378
2491
  collisionPadding: VIEWPORT_PAD6,
2379
2492
  className: "z-50 data-[anchor-hidden]:hidden",
2380
- children: /* @__PURE__ */ jsx40(
2493
+ children: /* @__PURE__ */ jsx42(
2381
2494
  BasePreviewCard.Popup,
2382
2495
  {
2383
2496
  className: cn("w-[360px] p-3 outline-none", className),
2384
- render: /* @__PURE__ */ jsx40(MenuPanel, {}),
2385
- children: /* @__PURE__ */ jsx40(ScrollArea, { viewportClassName: "max-h-[calc(min(300px,var(--available-height))_-_1.5rem)]", contentClassName: "flex flex-col gap-3 [&>*]:shrink-0", children: content })
2497
+ render: /* @__PURE__ */ jsx42(MenuPanel, {}),
2498
+ children: /* @__PURE__ */ jsx42(ScrollArea, { viewportClassName: "max-h-[calc(min(300px,var(--available-height))_-_1.5rem)]", contentClassName: "flex flex-col gap-3 [&>*]:shrink-0", children: content })
2386
2499
  }
2387
2500
  )
2388
2501
  }
@@ -2391,15 +2504,15 @@ function PreviewCard({ content, children, side = "right", delay = OPEN_DELAY2, c
2391
2504
  }
2392
2505
 
2393
2506
  // src/Rail.tsx
2394
- import { jsx as jsx41 } from "react/jsx-runtime";
2507
+ import { jsx as jsx43 } from "react/jsx-runtime";
2395
2508
  function Rail({ "aria-label": ariaLabel = "Navigation", children, className }) {
2396
- return /* @__PURE__ */ jsx41("nav", { "aria-label": ariaLabel, className: cn("flex w-16 shrink-0 flex-col items-start gap-2 px-2 py-3", className), children });
2509
+ return /* @__PURE__ */ jsx43("nav", { "aria-label": ariaLabel, className: cn("flex w-16 shrink-0 flex-col items-start gap-2 px-2 py-3", className), children });
2397
2510
  }
2398
2511
 
2399
2512
  // src/RailItem.tsx
2400
- import { jsx as jsx42, jsxs as jsxs28 } from "react/jsx-runtime";
2513
+ import { jsx as jsx44, jsxs as jsxs29 } from "react/jsx-runtime";
2401
2514
  function RailItem({ href, icon, label, active = false, className, ...props }) {
2402
- return /* @__PURE__ */ jsxs28(
2515
+ return /* @__PURE__ */ jsxs29(
2403
2516
  "a",
2404
2517
  {
2405
2518
  href,
@@ -2407,14 +2520,14 @@ function RailItem({ href, icon, label, active = false, className, ...props }) {
2407
2520
  className: cn("group flex w-full shrink-0 flex-col items-center gap-0.5 px-2 py-0.5", className),
2408
2521
  ...props,
2409
2522
  children: [
2410
- /* @__PURE__ */ jsx42(
2523
+ /* @__PURE__ */ jsx44(
2411
2524
  "div",
2412
2525
  {
2413
2526
  className: cn(
2414
2527
  "flex items-center justify-center rounded-lg p-2 transition-colors",
2415
2528
  active ? "bg-bg-selected" : "group-hover:bg-bg-hover"
2416
2529
  ),
2417
- children: /* @__PURE__ */ jsx42(
2530
+ children: /* @__PURE__ */ jsx44(
2418
2531
  "span",
2419
2532
  {
2420
2533
  className: cn(
@@ -2426,27 +2539,27 @@ function RailItem({ href, icon, label, active = false, className, ...props }) {
2426
2539
  )
2427
2540
  }
2428
2541
  ),
2429
- /* @__PURE__ */ jsx42("span", { className: cn("text-center text-menu", active ? "text-text-primary" : "text-text-secondary"), children: label })
2542
+ /* @__PURE__ */ jsx44("span", { className: cn("text-center text-menu", active ? "text-text-primary" : "text-text-secondary"), children: label })
2430
2543
  ]
2431
2544
  }
2432
2545
  );
2433
2546
  }
2434
2547
 
2435
2548
  // src/Sidebar.tsx
2436
- import { jsx as jsx43 } from "react/jsx-runtime";
2549
+ import { jsx as jsx45 } from "react/jsx-runtime";
2437
2550
  function Sidebar({ "aria-label": ariaLabel = "Workspace", children, className }) {
2438
- return /* @__PURE__ */ jsx43(
2551
+ return /* @__PURE__ */ jsx45(
2439
2552
  "nav",
2440
2553
  {
2441
2554
  "aria-label": ariaLabel,
2442
2555
  className: cn("flex w-60 shrink-0 flex-col border-r border-border-default bg-bg-surface", className),
2443
- children: /* @__PURE__ */ jsx43(ScrollArea, { className: "min-h-0 flex-1", contentClassName: "flex flex-col gap-px px-2.5 py-3", children })
2556
+ children: /* @__PURE__ */ jsx45(ScrollArea, { className: "min-h-0 flex-1", contentClassName: "flex flex-col gap-px px-2.5 py-3", children })
2444
2557
  }
2445
2558
  );
2446
2559
  }
2447
2560
 
2448
2561
  // src/Property.tsx
2449
- import { jsx as jsx44, jsxs as jsxs29 } from "react/jsx-runtime";
2562
+ import { jsx as jsx46, jsxs as jsxs30 } from "react/jsx-runtime";
2450
2563
  var VALUE_CLASSES = "contents";
2451
2564
  function Property({ label, layout = "row", children, className }) {
2452
2565
  if (layout === "stacked") {
@@ -2454,23 +2567,23 @@ function Property({ label, layout = "row", children, className }) {
2454
2567
  // gap-3 — the one label-above-content distance (Katerina, 2026-09-01):
2455
2568
  // Peek's topic-details sections already sit at 12px, Ship's rail was
2456
2569
  // 6px, and unifying means the bigger, calmer one.
2457
- /* @__PURE__ */ jsxs29("dl", { className: cn("flex flex-col gap-3", className), children: [
2458
- /* @__PURE__ */ jsx44("dt", { className: "text-menu uppercase tracking-widest text-text-secondary", children: label }),
2459
- /* @__PURE__ */ jsx44("dd", { className: VALUE_CLASSES, children })
2570
+ /* @__PURE__ */ jsxs30("dl", { className: cn("flex flex-col gap-3", className), children: [
2571
+ /* @__PURE__ */ jsx46("dt", { className: "text-menu uppercase tracking-widest text-text-secondary", children: label }),
2572
+ /* @__PURE__ */ jsx46("dd", { className: VALUE_CLASSES, children })
2460
2573
  ] })
2461
2574
  );
2462
2575
  }
2463
- return /* @__PURE__ */ jsxs29("dl", { className: cn("flex items-center gap-2", className), children: [
2464
- /* @__PURE__ */ jsx44("dt", { className: "w-[68px] shrink-0 text-caption text-text-secondary", children: label }),
2465
- /* @__PURE__ */ jsx44("dd", { className: VALUE_CLASSES, children })
2576
+ return /* @__PURE__ */ jsxs30("dl", { className: cn("flex items-center gap-2", className), children: [
2577
+ /* @__PURE__ */ jsx46("dt", { className: "w-[68px] shrink-0 text-caption text-text-secondary", children: label }),
2578
+ /* @__PURE__ */ jsx46("dd", { className: VALUE_CLASSES, children })
2466
2579
  ] });
2467
2580
  }
2468
2581
 
2469
2582
  // src/Reaction.tsx
2470
2583
  import { Toggle } from "@base-ui/react/toggle";
2471
- import { jsx as jsx45, jsxs as jsxs30 } from "react/jsx-runtime";
2584
+ import { jsx as jsx47, jsxs as jsxs31 } from "react/jsx-runtime";
2472
2585
  function Reaction({ emoji, count, pressed = false, className, ...props }) {
2473
- return /* @__PURE__ */ jsxs30(
2586
+ return /* @__PURE__ */ jsxs31(
2474
2587
  Toggle,
2475
2588
  {
2476
2589
  pressed,
@@ -2492,8 +2605,8 @@ function Reaction({ emoji, count, pressed = false, className, ...props }) {
2492
2605
  ),
2493
2606
  ...props,
2494
2607
  children: [
2495
- /* @__PURE__ */ jsx45("span", { "aria-hidden": "true", className: "shrink-0 text-body-1 leading-none", children: emoji }),
2496
- /* @__PURE__ */ jsx45("span", { className: "text-chip signal:font-mono signal:text-small signal:font-semibold signal:tabular-nums", children: count })
2608
+ /* @__PURE__ */ jsx47("span", { "aria-hidden": "true", className: "shrink-0 text-body-1 leading-none", children: emoji }),
2609
+ /* @__PURE__ */ jsx47("span", { className: "text-chip signal:font-mono signal:text-small signal:font-semibold signal:tabular-nums", children: count })
2497
2610
  ]
2498
2611
  }
2499
2612
  );
@@ -2502,19 +2615,21 @@ function Reaction({ emoji, count, pressed = false, className, ...props }) {
2502
2615
  // src/SearchInput.tsx
2503
2616
  import "react";
2504
2617
  import { Input as Input3 } from "@base-ui/react/input";
2505
- import { jsx as jsx46, jsxs as jsxs31 } from "react/jsx-runtime";
2618
+ import { jsx as jsx48, jsxs as jsxs32 } from "react/jsx-runtime";
2506
2619
  function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...props }) {
2507
- return /* @__PURE__ */ jsxs31(
2620
+ return /* @__PURE__ */ jsxs32(
2508
2621
  "div",
2509
2622
  {
2510
2623
  className: cn(
2511
2624
  "flex gap-2 items-center px-3 py-2 rounded-lg",
2512
2625
  "bg-bg-inset border border-border-default",
2513
- "focus-within:border-border-strong transition-colors",
2626
+ // Hover strengthens the border as it does on every other field (16 September). Here that
2627
+ // is also the focus look, which was the stronger border before hover existed.
2628
+ "hover:border-border-strong focus-within:border-border-strong transition-colors",
2514
2629
  className
2515
2630
  ),
2516
2631
  children: [
2517
- /* @__PURE__ */ jsx46(
2632
+ /* @__PURE__ */ jsx48(
2518
2633
  Input3,
2519
2634
  {
2520
2635
  className: "flex-1 min-w-0 bg-transparent text-input-value text-text-primary placeholder:text-text-muted outline-none",
@@ -2522,7 +2637,7 @@ function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...pro
2522
2637
  ...props
2523
2638
  }
2524
2639
  ),
2525
- shortcut && /* @__PURE__ */ jsx46(Kbd, { children: shortcut })
2640
+ shortcut && /* @__PURE__ */ jsx48(Kbd, { children: shortcut })
2526
2641
  ]
2527
2642
  }
2528
2643
  );
@@ -2531,17 +2646,17 @@ function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...pro
2531
2646
  // src/SectionHeader.tsx
2532
2647
  import { IconChevronRight as IconChevronRight2 } from "@tabler/icons-react";
2533
2648
  import { useRender } from "@base-ui/react/use-render";
2534
- import { Fragment as Fragment8, jsx as jsx47, jsxs as jsxs32 } from "react/jsx-runtime";
2649
+ import { Fragment as Fragment8, jsx as jsx49, jsxs as jsxs33 } from "react/jsx-runtime";
2535
2650
  function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, trailing, actions, showActions = "hover", render, className }) {
2536
2651
  const titleElement = useRender({
2537
- render: render ?? (chevron ? /* @__PURE__ */ jsx47("button", { type: "button", onClick: onToggle, "aria-expanded": isExpanded }) : /* @__PURE__ */ jsx47("span", {})),
2652
+ render: render ?? (chevron ? /* @__PURE__ */ jsx49("button", { type: "button", onClick: onToggle, "aria-expanded": isExpanded }) : /* @__PURE__ */ jsx49("span", {})),
2538
2653
  props: {
2539
2654
  // `text-left`: a button centres its text. `h-full` and `flex-1`: the
2540
2655
  // whole row up to the actions is the hit target, as it was when the
2541
2656
  // row itself carried the click.
2542
2657
  className: "flex h-full min-w-0 flex-1 items-center gap-1 text-left",
2543
- children: /* @__PURE__ */ jsxs32(Fragment8, { children: [
2544
- chevron && /* @__PURE__ */ jsx47(
2658
+ children: /* @__PURE__ */ jsxs33(Fragment8, { children: [
2659
+ chevron && /* @__PURE__ */ jsx49(
2545
2660
  IconChevronRight2,
2546
2661
  {
2547
2662
  size: 12,
@@ -2549,11 +2664,11 @@ function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, tr
2549
2664
  className: cn("shrink-0 text-text-secondary transition-transform duration-150", isExpanded && "rotate-90")
2550
2665
  }
2551
2666
  ),
2552
- /* @__PURE__ */ jsx47(SectionLabel, { children: title })
2667
+ /* @__PURE__ */ jsx49(SectionLabel, { children: title })
2553
2668
  ] })
2554
2669
  }
2555
2670
  });
2556
- return /* @__PURE__ */ jsxs32(
2671
+ return /* @__PURE__ */ jsxs33(
2557
2672
  "div",
2558
2673
  {
2559
2674
  className: cn(
@@ -2566,15 +2681,15 @@ function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, tr
2566
2681
  ),
2567
2682
  children: [
2568
2683
  titleElement,
2569
- trailing != null && /* @__PURE__ */ jsx47("div", { className: "flex shrink-0 items-center", children: trailing }),
2570
- actions && actions.length > 0 && /* @__PURE__ */ jsx47(
2684
+ trailing != null && /* @__PURE__ */ jsx49("div", { className: "flex shrink-0 items-center", children: trailing }),
2685
+ actions && actions.length > 0 && /* @__PURE__ */ jsx49(
2571
2686
  "div",
2572
2687
  {
2573
2688
  className: cn(
2574
2689
  "-mr-1 flex shrink-0 items-center gap-1",
2575
2690
  showActions === "hover" && "opacity-0 transition-opacity focus-within:opacity-100 group-hover:opacity-100"
2576
2691
  ),
2577
- children: actions.map((action) => /* @__PURE__ */ jsx47(IconButton, { tooltip: action.tooltip, "aria-label": action.tooltip, onClick: action.onClick, children: action.icon }, action.tooltip))
2692
+ children: actions.map((action) => /* @__PURE__ */ jsx49(IconButton, { tooltip: action.tooltip, "aria-label": action.tooltip, onClick: action.onClick, children: action.icon }, action.tooltip))
2578
2693
  }
2579
2694
  )
2580
2695
  ]
@@ -2585,7 +2700,7 @@ function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, tr
2585
2700
  // src/CollapsibleSection.tsx
2586
2701
  import { useState as useState7 } from "react";
2587
2702
  import { Collapsible } from "@base-ui/react/collapsible";
2588
- import { jsx as jsx48, jsxs as jsxs33 } from "react/jsx-runtime";
2703
+ import { jsx as jsx50, jsxs as jsxs34 } from "react/jsx-runtime";
2589
2704
  var OPEN = "open";
2590
2705
  var CLOSED = "closed";
2591
2706
  function readStored(key) {
@@ -2612,14 +2727,14 @@ function CollapsibleSection({ title, defaultOpen = true, open: openProp, onOpenC
2612
2727
  writeStored(storageKey, next);
2613
2728
  onOpenChange?.(next);
2614
2729
  };
2615
- return /* @__PURE__ */ jsxs33(Collapsible.Root, { open, onOpenChange: setOpen, className: cn("flex flex-col", className), children: [
2616
- /* @__PURE__ */ jsx48(SectionHeader, { title, chevron: true, isExpanded: open, trailing, actions, showActions, className: "shrink-0", render: /* @__PURE__ */ jsx48(Collapsible.Trigger, {}) }),
2617
- /* @__PURE__ */ jsx48(
2730
+ return /* @__PURE__ */ jsxs34(Collapsible.Root, { open, onOpenChange: setOpen, className: cn("flex flex-col", className), children: [
2731
+ /* @__PURE__ */ jsx50(SectionHeader, { title, chevron: true, isExpanded: open, trailing, actions, showActions, className: "shrink-0", render: /* @__PURE__ */ jsx50(Collapsible.Trigger, {}) }),
2732
+ /* @__PURE__ */ jsx50(
2618
2733
  Collapsible.Panel,
2619
2734
  {
2620
2735
  hiddenUntilFound: true,
2621
2736
  className: "h-[var(--collapsible-panel-height)] overflow-hidden transition-[height] duration-150 ease-out motion-reduce:transition-none data-[starting-style]:h-0 data-[ending-style]:h-0",
2622
- children: /* @__PURE__ */ jsx48("div", { className: cn("flex flex-col", contentClassName), children })
2737
+ children: /* @__PURE__ */ jsx50("div", { className: cn("flex flex-col", contentClassName), children })
2623
2738
  }
2624
2739
  )
2625
2740
  ] });
@@ -2627,9 +2742,9 @@ function CollapsibleSection({ title, defaultOpen = true, open: openProp, onOpenC
2627
2742
 
2628
2743
  // src/Tabs.tsx
2629
2744
  import { Tabs as BaseTabs } from "@base-ui/react/tabs";
2630
- import { jsx as jsx49, jsxs as jsxs34 } from "react/jsx-runtime";
2745
+ import { jsx as jsx51, jsxs as jsxs35 } from "react/jsx-runtime";
2631
2746
  function Tabs({ tabs, active, onChange, size = "default", className, ...aria }) {
2632
- return /* @__PURE__ */ jsx49(
2747
+ return /* @__PURE__ */ jsx51(
2633
2748
  BaseTabs.Root,
2634
2749
  {
2635
2750
  value: active,
@@ -2637,14 +2752,14 @@ function Tabs({ tabs, active, onChange, size = "default", className, ...aria })
2637
2752
  if (details.reason === "none") onChange(value);
2638
2753
  },
2639
2754
  className,
2640
- children: /* @__PURE__ */ jsx49(
2755
+ children: /* @__PURE__ */ jsx51(
2641
2756
  BaseTabs.List,
2642
2757
  {
2643
2758
  activateOnFocus: true,
2644
2759
  "aria-label": aria["aria-label"],
2645
2760
  "aria-labelledby": aria["aria-labelledby"],
2646
2761
  className: "flex items-center gap-2",
2647
- children: tabs.map((tab) => /* @__PURE__ */ jsxs34(
2762
+ children: tabs.map((tab) => /* @__PURE__ */ jsxs35(
2648
2763
  BaseTabs.Tab,
2649
2764
  {
2650
2765
  value: tab.id,
@@ -2657,9 +2772,9 @@ function Tabs({ tabs, active, onChange, size = "default", className, ...aria })
2657
2772
  ),
2658
2773
  children: [
2659
2774
  tab.icon,
2660
- /* @__PURE__ */ jsxs34("span", { className: "flex items-baseline", children: [
2775
+ /* @__PURE__ */ jsxs35("span", { className: "flex items-baseline", children: [
2661
2776
  tab.label,
2662
- tab.count !== void 0 ? /* @__PURE__ */ jsx49("span", { className: "ml-2.5 font-mono text-caption tabular-nums text-text-secondary", children: tab.count }) : null
2777
+ tab.count !== void 0 ? /* @__PURE__ */ jsx51("span", { className: "ml-2.5 font-mono text-caption tabular-nums text-text-secondary", children: tab.count }) : null
2663
2778
  ] })
2664
2779
  ]
2665
2780
  },
@@ -2672,10 +2787,10 @@ function Tabs({ tabs, active, onChange, size = "default", className, ...aria })
2672
2787
  }
2673
2788
 
2674
2789
  // src/Toast.tsx
2675
- import { createContext as createContext3, useContext as useContext3, useMemo as useMemo4 } from "react";
2790
+ import { createContext as createContext4, useContext as useContext4, useMemo as useMemo4 } from "react";
2676
2791
  import { Toast as BaseToast } from "@base-ui/react/toast";
2677
2792
  import { IconAlertCircle as IconAlertCircle2, IconCircleCheck, IconCircleX } from "@tabler/icons-react";
2678
- import { jsx as jsx50, jsxs as jsxs35 } from "react/jsx-runtime";
2793
+ import { jsx as jsx52, jsxs as jsxs36 } from "react/jsx-runtime";
2679
2794
  var SURFACE_STYLES = {
2680
2795
  success: "bg-success-muted signal:bg-bg-inset signal:border signal:border-border-default signal:shadow-md",
2681
2796
  brand: "bg-accent-muted signal:bg-bg-inset signal:border signal:border-border-default signal:shadow-md",
@@ -2711,19 +2826,19 @@ var pillClassName = (type, hasAction, className) => cn(
2711
2826
  );
2712
2827
  function LeadingIcon({ type }) {
2713
2828
  const Icon = ICONS[type];
2714
- return /* @__PURE__ */ jsx50(Icon, { size: 16, stroke: 1.5, className: cn("text-text-primary shrink-0", ICON_STYLES[type]) });
2829
+ return /* @__PURE__ */ jsx52(Icon, { size: 16, stroke: 1.5, className: cn("text-text-primary shrink-0", ICON_STYLES[type]) });
2715
2830
  }
2716
2831
  function Toast({ label, type = "neutral", leadingIcon = true, actionLabel, onAction, className }) {
2717
2832
  const hasAction = !!(actionLabel && onAction);
2718
- return /* @__PURE__ */ jsxs35("div", { className: pillClassName(type, hasAction, className), children: [
2719
- /* @__PURE__ */ jsxs35("div", { className: "flex items-center gap-2 shrink-0", children: [
2720
- leadingIcon && /* @__PURE__ */ jsx50(LeadingIcon, { type }),
2721
- /* @__PURE__ */ jsx50("span", { className: LABEL_CLASSES, children: label })
2833
+ return /* @__PURE__ */ jsxs36("div", { className: pillClassName(type, hasAction, className), children: [
2834
+ /* @__PURE__ */ jsxs36("div", { className: "flex items-center gap-2 shrink-0", children: [
2835
+ leadingIcon && /* @__PURE__ */ jsx52(LeadingIcon, { type }),
2836
+ /* @__PURE__ */ jsx52("span", { className: LABEL_CLASSES, children: label })
2722
2837
  ] }),
2723
- hasAction && /* @__PURE__ */ jsx50(Button, { variant: "outlined", size: "small", onClick: onAction, children: actionLabel })
2838
+ hasAction && /* @__PURE__ */ jsx52(Button, { variant: "outlined", size: "small", onClick: onAction, children: actionLabel })
2724
2839
  ] });
2725
2840
  }
2726
- var ToastContext = createContext3(null);
2841
+ var ToastContext = createContext4(null);
2727
2842
  var VISIBLE_TOASTS = 3;
2728
2843
  function ToastProvider({ children }) {
2729
2844
  const manager = useMemo4(() => BaseToast.createToastManager(), []);
@@ -2741,9 +2856,9 @@ function ToastProvider({ children }) {
2741
2856
  }),
2742
2857
  [manager]
2743
2858
  );
2744
- return /* @__PURE__ */ jsx50(ToastContext.Provider, { value, children: /* @__PURE__ */ jsxs35(BaseToast.Provider, { toastManager: manager, limit: VISIBLE_TOASTS, children: [
2859
+ return /* @__PURE__ */ jsx52(ToastContext.Provider, { value, children: /* @__PURE__ */ jsxs36(BaseToast.Provider, { toastManager: manager, limit: VISIBLE_TOASTS, children: [
2745
2860
  children,
2746
- /* @__PURE__ */ jsx50(BaseToast.Portal, { children: /* @__PURE__ */ jsx50(BaseToast.Viewport, { className: "fixed bottom-4 left-4 z-[100] flex flex-col-reverse items-start gap-2 pointer-events-none", children: /* @__PURE__ */ jsx50(ToastList, {}) }) })
2861
+ /* @__PURE__ */ jsx52(BaseToast.Portal, { children: /* @__PURE__ */ jsx52(BaseToast.Viewport, { className: "fixed bottom-4 left-4 z-[100] flex flex-col-reverse items-start gap-2 pointer-events-none", children: /* @__PURE__ */ jsx52(ToastList, {}) }) })
2747
2862
  ] }) });
2748
2863
  }
2749
2864
  function ToastList() {
@@ -2751,25 +2866,25 @@ function ToastList() {
2751
2866
  return toasts.map((toast) => {
2752
2867
  const type = toast.type ?? "neutral";
2753
2868
  const { leadingIcon = true, actionLabel, onAction } = toast.data ?? {};
2754
- return /* @__PURE__ */ jsxs35(
2869
+ return /* @__PURE__ */ jsxs36(
2755
2870
  BaseToast.Root,
2756
2871
  {
2757
2872
  toast,
2758
2873
  swipeDirection: ["left", "down"],
2759
2874
  className: pillClassName(type, !!actionLabel, "pointer-events-auto data-[limited]:hidden"),
2760
2875
  children: [
2761
- /* @__PURE__ */ jsxs35("div", { className: "flex items-center gap-2 shrink-0", children: [
2762
- leadingIcon && /* @__PURE__ */ jsx50(LeadingIcon, { type }),
2763
- /* @__PURE__ */ jsx50(BaseToast.Title, { render: /* @__PURE__ */ jsx50("span", {}), className: LABEL_CLASSES })
2876
+ /* @__PURE__ */ jsxs36("div", { className: "flex items-center gap-2 shrink-0", children: [
2877
+ leadingIcon && /* @__PURE__ */ jsx52(LeadingIcon, { type }),
2878
+ /* @__PURE__ */ jsx52(BaseToast.Title, { render: /* @__PURE__ */ jsx52("span", {}), className: LABEL_CLASSES })
2764
2879
  ] }),
2765
- actionLabel && /* @__PURE__ */ jsx50(
2880
+ actionLabel && /* @__PURE__ */ jsx52(
2766
2881
  BaseToast.Action,
2767
2882
  {
2768
2883
  onClick: () => {
2769
2884
  onAction?.();
2770
2885
  close(toast.id);
2771
2886
  },
2772
- render: /* @__PURE__ */ jsx50(Button, { variant: "outlined", size: "small", children: actionLabel })
2887
+ render: /* @__PURE__ */ jsx52(Button, { variant: "outlined", size: "small", children: actionLabel })
2773
2888
  }
2774
2889
  )
2775
2890
  ]
@@ -2779,7 +2894,7 @@ function ToastList() {
2779
2894
  });
2780
2895
  }
2781
2896
  function useToast() {
2782
- const ctx = useContext3(ToastContext);
2897
+ const ctx = useContext4(ToastContext);
2783
2898
  if (!ctx) throw new Error("useToast must be used within ToastProvider");
2784
2899
  return ctx;
2785
2900
  }
@@ -2810,6 +2925,8 @@ export {
2810
2925
  EnterHint,
2811
2926
  Field,
2812
2927
  FieldLine,
2928
+ FilePicker,
2929
+ Form,
2813
2930
  INLINE_CHIP_CLASSES,
2814
2931
  INLINE_CHIP_TONE_CLASSES,
2815
2932
  IconButton,