@estiva-app/ui 0.16.1 → 0.18.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 (60) 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/CommandPalette.d.ts.map +1 -1
  6. package/dist/FilePicker.d.ts +22 -0
  7. package/dist/FilePicker.d.ts.map +1 -0
  8. package/dist/Form.d.ts +49 -0
  9. package/dist/Form.d.ts.map +1 -0
  10. package/dist/IconButton.d.ts.map +1 -1
  11. package/dist/SearchInput.d.ts.map +1 -1
  12. package/dist/TextInput.d.ts.map +1 -1
  13. package/dist/Textarea.d.ts.map +1 -1
  14. package/dist/eslint/index.d.ts +1 -1
  15. package/dist/eslint/index.d.ts.map +1 -1
  16. package/dist/eslint/index.js +88 -8
  17. package/dist/eslint/index.js.map +4 -4
  18. package/dist/eslint/no-raw-element.d.ts +88 -0
  19. package/dist/eslint/no-raw-element.d.ts.map +1 -0
  20. package/dist/formBusy.d.ts +15 -0
  21. package/dist/formBusy.d.ts.map +1 -0
  22. package/dist/index.d.ts +2 -0
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +479 -350
  25. package/dist/index.js.map +4 -4
  26. package/package.json +1 -1
  27. package/src/Button.tsx +4 -1
  28. package/src/Checkbox.mdx +19 -1
  29. package/src/Checkbox.stories.tsx +12 -0
  30. package/src/Checkbox.test.tsx +54 -0
  31. package/src/Checkbox.tsx +40 -3
  32. package/src/CommandPalette.mdx +6 -2
  33. package/src/CommandPalette.stories.tsx +6 -3
  34. package/src/CommandPalette.test.tsx +15 -0
  35. package/src/CommandPalette.tsx +34 -46
  36. package/src/FilePicker.mdx +49 -0
  37. package/src/FilePicker.stories.tsx +61 -0
  38. package/src/FilePicker.test.tsx +79 -0
  39. package/src/FilePicker.tsx +40 -0
  40. package/src/Form.mdx +78 -0
  41. package/src/Form.stories.tsx +68 -0
  42. package/src/Form.test.tsx +385 -0
  43. package/src/Form.tsx +173 -0
  44. package/src/IconButton.tsx +4 -1
  45. package/src/SearchInput.mdx +2 -2
  46. package/src/SearchInput.tsx +3 -1
  47. package/src/TextInput.mdx +2 -2
  48. package/src/TextInput.test.tsx +7 -0
  49. package/src/TextInput.tsx +4 -1
  50. package/src/Textarea.tsx +4 -1
  51. package/src/eslint/index.test.ts +24 -15
  52. package/src/eslint/index.ts +6 -5
  53. package/src/eslint/{no-raw-button.test.ts → no-raw-element.test.ts} +53 -8
  54. package/src/eslint/no-raw-element.ts +180 -0
  55. package/src/formBusy.ts +19 -0
  56. package/src/index.ts +2 -0
  57. package/stories/Choosing.mdx +3 -0
  58. package/dist/eslint/no-raw-button.d.ts +0 -11
  59. package/dist/eslint/no-raw-button.d.ts.map +0 -1
  60. 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,12 +814,12 @@ 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
- useLayoutEffect as useLayoutEffect2,
820
+ useLayoutEffect as useLayoutEffect3,
798
821
  useMemo as useMemo2,
799
- useRef as useRef2,
822
+ useRef as useRef3,
800
823
  useState as useState3
801
824
  } from "react";
802
825
  import { Dialog } from "@base-ui/react/dialog";
@@ -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
  }
@@ -1232,39 +1255,129 @@ function FieldLine({ tone = "helper", children, className }) {
1232
1255
  return /* @__PURE__ */ jsx20("p", { role: tone === "error" ? "alert" : "status", className: cn(LINE_STYLES[tone], className), children });
1233
1256
  }
1234
1257
 
1258
+ // src/Form.tsx
1259
+ import { useLayoutEffect as useLayoutEffect2, useRef as useRef2 } from "react";
1260
+ import { Fieldset } from "@base-ui/react/fieldset";
1261
+ import { Form as BaseForm } from "@base-ui/react/form";
1262
+ import { jsx as jsx21 } from "react/jsx-runtime";
1263
+ var CONTROL = 'input:not([type="hidden"]), textarea, select, button, [role="checkbox"], [role="combobox"], [tabindex]:not([tabindex="-1"])';
1264
+ var ONE_LINE = /* @__PURE__ */ new Set(["", "text", "search", "email", "url", "tel", "password", "number"]);
1265
+ function usable(element) {
1266
+ return element instanceof HTMLElement && element.isConnected && element.matches(CONTROL) && !element.matches(":disabled") && element.getAttribute("aria-disabled") !== "true";
1267
+ }
1268
+ function firstInvalid(form) {
1269
+ for (const marked of form.querySelectorAll("[data-invalid]")) {
1270
+ if (usable(marked)) return marked;
1271
+ const inside = Array.from(marked.querySelectorAll(CONTROL)).find(usable);
1272
+ if (inside) return inside;
1273
+ }
1274
+ return void 0;
1275
+ }
1276
+ function Form({ onSubmit, busy: ownBusy = false, enterSends = true, className, children, ...props }) {
1277
+ const outerBusy = useFormBusy();
1278
+ const busy = ownBusy || outerBusy;
1279
+ const form = useRef2(null);
1280
+ const busyNow = useRef2(busy);
1281
+ busyNow.current = busy;
1282
+ const sender = useRef2(null);
1283
+ const holding = useRef2(false);
1284
+ const lastInside = useRef2(null);
1285
+ useLayoutEffect2(() => {
1286
+ const element = form.current;
1287
+ if (!element) return;
1288
+ if (busy) {
1289
+ const active = document.activeElement;
1290
+ const from = active && active !== element && element.contains(active) ? active : !active || active === document.body ? lastInside.current : null;
1291
+ if (from?.isConnected) {
1292
+ sender.current = from;
1293
+ holding.current = true;
1294
+ element.focus();
1295
+ }
1296
+ return;
1297
+ }
1298
+ if (!holding.current) return;
1299
+ holding.current = false;
1300
+ if (document.activeElement !== element && document.activeElement !== document.body) return;
1301
+ const target = firstInvalid(element) ?? (usable(sender.current) ? sender.current : Array.from(element.querySelectorAll(CONTROL)).find(usable));
1302
+ sender.current = null;
1303
+ target?.focus();
1304
+ }, [busy]);
1305
+ const onKeyDown = (event) => {
1306
+ props.onKeyDown?.(event);
1307
+ if (event.key !== "Enter" || event.defaultPrevented || event.nativeEvent.isComposing) return;
1308
+ const target = event.target;
1309
+ const inInput = target instanceof HTMLInputElement;
1310
+ if (inInput) event.preventDefault();
1311
+ if (event.altKey || event.shiftKey) return;
1312
+ if (event.ctrlKey || event.metaKey) {
1313
+ event.preventDefault();
1314
+ form.current?.requestSubmit();
1315
+ return;
1316
+ }
1317
+ if (!inInput) return;
1318
+ const oneLine = ONE_LINE.has((target.getAttribute("type") ?? "").toLowerCase()) && target.getAttribute("role") !== "combobox";
1319
+ if (enterSends && oneLine) form.current?.requestSubmit();
1320
+ };
1321
+ return /* @__PURE__ */ jsx21(
1322
+ BaseForm,
1323
+ {
1324
+ ref: form,
1325
+ ...props,
1326
+ tabIndex: busy ? -1 : props.tabIndex,
1327
+ className: cn("outline-none", className),
1328
+ onFocus: (event) => {
1329
+ if (event.target !== form.current) lastInside.current = event.target;
1330
+ props.onFocus?.(event);
1331
+ },
1332
+ onBlur: (event) => {
1333
+ const next = event.relatedTarget;
1334
+ if (next && !form.current?.contains(next)) lastInside.current = null;
1335
+ props.onBlur?.(event);
1336
+ },
1337
+ onKeyDown,
1338
+ onSubmit: (event) => {
1339
+ event.preventDefault();
1340
+ if (busyNow.current) return;
1341
+ void onSubmit();
1342
+ },
1343
+ children: /* @__PURE__ */ jsx21(Fieldset.Root, { disabled: busy, className: "contents", children: /* @__PURE__ */ jsx21(FormBusyContext.Provider, { value: busy, children }) })
1344
+ }
1345
+ );
1346
+ }
1347
+
1235
1348
  // src/Skeleton.tsx
1236
- import { jsx as jsx21, jsxs as jsxs14 } from "react/jsx-runtime";
1349
+ import { jsx as jsx22, jsxs as jsxs15 } from "react/jsx-runtime";
1237
1350
  function SkeletonBar({ className, style }) {
1238
- return /* @__PURE__ */ jsx21("div", { className: cn("bg-bg-inset rounded-sm animate-pulse", className), style });
1351
+ return /* @__PURE__ */ jsx22("div", { className: cn("bg-bg-inset rounded-sm animate-pulse", className), style });
1239
1352
  }
1240
1353
  var ROW_BAR_WIDTHS = [150, 100, 170, 120, 90, 140, 110, 160];
1241
1354
  function SkeletonRow({ barWidth = 130 }) {
1242
- return /* @__PURE__ */ jsxs14("div", { className: "flex items-center gap-2 px-2 h-[32px] rounded-lg", children: [
1243
- /* @__PURE__ */ jsx21(SkeletonBar, { className: "w-4 h-4 shrink-0" }),
1244
- /* @__PURE__ */ jsx21(SkeletonBar, { className: "h-3.5", style: { width: barWidth } })
1355
+ return /* @__PURE__ */ jsxs15("div", { className: "flex items-center gap-2 px-2 h-[32px] rounded-lg", children: [
1356
+ /* @__PURE__ */ jsx22(SkeletonBar, { className: "w-4 h-4 shrink-0" }),
1357
+ /* @__PURE__ */ jsx22(SkeletonBar, { className: "h-3.5", style: { width: barWidth } })
1245
1358
  ] });
1246
1359
  }
1247
1360
  function SkeletonList({ rows = 8, className }) {
1248
- return /* @__PURE__ */ jsx21("div", { className: cn("flex flex-col gap-0.5 animate-skeleton-in", className), "aria-hidden": true, children: Array.from({ length: rows }, (_, i) => /* @__PURE__ */ jsx21(SkeletonRow, { barWidth: ROW_BAR_WIDTHS[i % ROW_BAR_WIDTHS.length] }, i)) });
1361
+ return /* @__PURE__ */ jsx22("div", { className: cn("flex flex-col gap-0.5 animate-skeleton-in", className), "aria-hidden": true, children: Array.from({ length: rows }, (_, i) => /* @__PURE__ */ jsx22(SkeletonRow, { barWidth: ROW_BAR_WIDTHS[i % ROW_BAR_WIDTHS.length] }, i)) });
1249
1362
  }
1250
1363
 
1251
1364
  // src/CommandPalette.tsx
1252
- import { Fragment as Fragment3, jsx as jsx22, jsxs as jsxs15 } from "react/jsx-runtime";
1253
- var PaletteContext = createContext2(null);
1365
+ import { Fragment as Fragment3, jsx as jsx23, jsxs as jsxs16 } from "react/jsx-runtime";
1366
+ var PaletteContext = createContext3(null);
1254
1367
  function usePalette(part) {
1255
- const palette = useContext2(PaletteContext);
1368
+ const palette = useContext3(PaletteContext);
1256
1369
  if (!palette) throw new Error(`[@estiva-app/ui] ${part} must be inside a CommandPalette.`);
1257
1370
  return palette;
1258
1371
  }
1259
- var CONTROL = 'input:not([type="hidden"]):not([tabindex="-1"]), textarea, button:not([tabindex="-1"]), [role="combobox"]';
1372
+ var CONTROL2 = 'input:not([type="hidden"]):not([tabindex="-1"]), textarea, button:not([tabindex="-1"]), [role="combobox"]';
1260
1373
  function firstControl(popup) {
1261
1374
  if (!popup) return null;
1262
1375
  const field = popup.querySelector("[data-command-palette-field]");
1263
1376
  if (field) return field;
1264
- return popup.querySelector("[data-command-palette-fields]")?.querySelector(CONTROL) ?? null;
1377
+ return popup.querySelector("[data-command-palette-fields]")?.querySelector(CONTROL2) ?? null;
1265
1378
  }
1266
1379
  function CommandPalette({ open, onOpenChange, label, where, modKey = "Ctrl", children }) {
1267
- const popupRef = useRef2(null);
1380
+ const popupRef = useRef3(null);
1268
1381
  useEffect(() => {
1269
1382
  if (!open) return;
1270
1383
  const frame = requestAnimationFrame(() => {
@@ -1275,9 +1388,9 @@ function CommandPalette({ open, onOpenChange, label, where, modKey = "Ctrl", chi
1275
1388
  return () => cancelAnimationFrame(frame);
1276
1389
  });
1277
1390
  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: [
1279
- /* @__PURE__ */ jsx22(Dialog.Backdrop, { className: "fixed inset-0 z-40 bg-scrim" }),
1280
- /* @__PURE__ */ jsx22(Dialog.Viewport, { className: "fixed inset-0 z-50 flex items-start justify-center pt-[16vh]", children: /* @__PURE__ */ jsx22(
1391
+ return /* @__PURE__ */ jsx23(Dialog.Root, { open, onOpenChange: (next) => onOpenChange(next), children: /* @__PURE__ */ jsxs16(Dialog.Portal, { children: [
1392
+ /* @__PURE__ */ jsx23(Dialog.Backdrop, { className: "fixed inset-0 z-40 bg-scrim" }),
1393
+ /* @__PURE__ */ jsx23(Dialog.Viewport, { className: "fixed inset-0 z-50 flex items-start justify-center pt-[16vh]", children: /* @__PURE__ */ jsx23(
1281
1394
  Dialog.Popup,
1282
1395
  {
1283
1396
  ref: popupRef,
@@ -1287,13 +1400,13 @@ function CommandPalette({ open, onOpenChange, label, where, modKey = "Ctrl", chi
1287
1400
  if (e.target === popupRef.current) firstControl(popupRef.current)?.focus();
1288
1401
  },
1289
1402
  className: "flex w-[658px] max-w-[calc(100vw-32px)] flex-col overflow-hidden rounded-lg border border-border-default bg-bg-elevated shadow-lg outline-none",
1290
- children: /* @__PURE__ */ jsx22(PaletteContext.Provider, { value: context, children })
1403
+ children: /* @__PURE__ */ jsx23(PaletteContext.Provider, { value: context, children })
1291
1404
  }
1292
1405
  ) })
1293
1406
  ] }) });
1294
1407
  }
1295
1408
  function LevelChip({ chip, onBack }) {
1296
- return /* @__PURE__ */ jsx22(InputChip, { label: chip.label, leading: chip.leading, onRemove: onBack, removeLabel: `Leave ${chip.label}`, truncate: true, className: "max-w-[272px] shrink-0" });
1409
+ return /* @__PURE__ */ jsx23(InputChip, { label: chip.label, leading: chip.leading, onRemove: onBack, removeLabel: `Leave ${chip.label}`, truncate: true, className: "max-w-[272px] shrink-0" });
1297
1410
  }
1298
1411
  function useBack(chip, popupRef) {
1299
1412
  return () => {
@@ -1304,10 +1417,10 @@ function useBack(chip, popupRef) {
1304
1417
  }
1305
1418
  function Footer({ keys }) {
1306
1419
  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: [
1308
- /* @__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: [
1310
- /* @__PURE__ */ jsx22(Kbd, { children: key }),
1420
+ 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: [
1421
+ /* @__PURE__ */ jsx23("span", { className: "min-w-0 flex-1 truncate", children: where }),
1422
+ keys.map(([key, word]) => /* @__PURE__ */ jsxs16("span", { className: "flex shrink-0 items-center gap-1.5", children: [
1423
+ /* @__PURE__ */ jsx23(Kbd, { children: key }),
1311
1424
  " ",
1312
1425
  word
1313
1426
  ] }, key))
@@ -1321,11 +1434,11 @@ function CommandPaletteSearch({ query, onQueryChange, placeholder, groups, chip,
1321
1434
  const rows = items.flatMap((g) => g.items);
1322
1435
  const [litId, setLitId] = useState3();
1323
1436
  const lit = litId === void 0 ? void 0 : rows.find((r) => r.id === litId);
1324
- const inputRef = useRef2(null);
1325
- const reported = useRef2({});
1326
- const settled = useRef2(null);
1327
- const moved = useRef2(false);
1328
- useLayoutEffect2(() => {
1437
+ const inputRef = useRef3(null);
1438
+ const reported = useRef3({});
1439
+ const settled = useRef3(null);
1440
+ const moved = useRef3(false);
1441
+ useLayoutEffect3(() => {
1329
1442
  const before = settled.current;
1330
1443
  const now = reported.current;
1331
1444
  const sameLevel = before?.query === query && before?.level === chip?.label;
@@ -1384,7 +1497,7 @@ function CommandPaletteSearch({ query, onQueryChange, placeholder, groups, chip,
1384
1497
  ...chip && query === "" ? [["Backspace", "back"]] : [],
1385
1498
  ["Esc", "close"]
1386
1499
  ];
1387
- return /* @__PURE__ */ jsxs15(
1500
+ return /* @__PURE__ */ jsxs16(
1388
1501
  Autocomplete.Root,
1389
1502
  {
1390
1503
  items,
@@ -1407,10 +1520,10 @@ function CommandPaletteSearch({ query, onQueryChange, placeholder, groups, chip,
1407
1520
  setLitId(id);
1408
1521
  },
1409
1522
  children: [
1410
- /* @__PURE__ */ jsxs15("div", { className: "flex h-12 shrink-0 items-center gap-3 border-b border-border-subtle px-5", children: [
1411
- /* @__PURE__ */ jsx22(IconSearch, { size: 16, stroke: 1.5, className: "shrink-0 text-text-secondary" }),
1412
- chip && /* @__PURE__ */ jsx22(LevelChip, { chip, onBack: back }),
1413
- /* @__PURE__ */ jsx22(
1523
+ /* @__PURE__ */ jsxs16("div", { className: "flex h-12 shrink-0 items-center gap-3 border-b border-border-subtle px-5", children: [
1524
+ /* @__PURE__ */ jsx23(IconSearch, { size: 16, stroke: 1.5, className: "shrink-0 text-text-secondary" }),
1525
+ chip && /* @__PURE__ */ jsx23(LevelChip, { chip, onBack: back }),
1526
+ /* @__PURE__ */ jsx23(
1414
1527
  Autocomplete.Input,
1415
1528
  {
1416
1529
  ref: inputRef,
@@ -1422,43 +1535,43 @@ function CommandPaletteSearch({ query, onQueryChange, placeholder, groups, chip,
1422
1535
  }
1423
1536
  )
1424
1537
  ] }),
1425
- /* @__PURE__ */ jsxs15(ScrollArea, { viewportClassName: "max-h-[420px]", contentClassName: "flex flex-col p-2", children: [
1426
- 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: [
1428
- /* @__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
- /* @__PURE__ */ jsx22(Autocomplete.Collection, { children: (row) => (
1538
+ /* @__PURE__ */ jsxs16(ScrollArea, { viewportClassName: "max-h-[420px]", contentClassName: "flex flex-col p-2", children: [
1539
+ children != null && /* @__PURE__ */ jsx23("div", { className: "flex flex-col gap-2 px-3 pb-2 pt-3", children }),
1540
+ /* @__PURE__ */ jsx23(Autocomplete.List, { className: "flex flex-col", children: (group) => /* @__PURE__ */ jsxs16(Autocomplete.Group, { items: group.items, className: "flex flex-col", children: [
1541
+ /* @__PURE__ */ jsx23(Autocomplete.GroupLabel, { className: "flex h-7 shrink-0 items-center px-3", children: /* @__PURE__ */ jsx23(SectionLabel, { className: "text-text-secondary", children: group.value }) }),
1542
+ /* @__PURE__ */ jsx23(Autocomplete.Collection, { children: (row) => (
1430
1543
  /* The menu row, as the list's own option — the way Select
1431
1544
  puts it on `Select.Item`. One row, two parts. */
1432
- /* @__PURE__ */ jsx22(Autocomplete.Item, { value: row, onClick: () => row.onSelect(), className: menuItemClassName({ size: "tall" }), children: /* @__PURE__ */ jsx22(
1545
+ /* @__PURE__ */ jsx23(Autocomplete.Item, { value: row, onClick: () => row.onSelect(), className: menuItemClassName({ size: "tall" }), children: /* @__PURE__ */ jsx23(
1433
1546
  MenuItemBody,
1434
1547
  {
1435
1548
  size: "tall",
1436
1549
  label: row.label,
1437
1550
  description: row.description,
1438
- leading: /* @__PURE__ */ jsx22(RowLeading, { row }),
1551
+ leading: /* @__PURE__ */ jsx23(RowLeading, { row }),
1439
1552
  submenu: !!row.onGoIn,
1440
- hint: row.onGoIn ? /* @__PURE__ */ jsx22(Kbd, { children: "Tab" }) : /* @__PURE__ */ jsx22(EnterHint, {})
1553
+ hint: row.onGoIn ? /* @__PURE__ */ jsx23(Kbd, { children: "Tab" }) : /* @__PURE__ */ jsx23(EnterHint, {})
1441
1554
  }
1442
1555
  ) }, row.id)
1443
1556
  ) })
1444
1557
  ] }, 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: [
1446
- /* @__PURE__ */ jsx22(IconLoader22, { size: 12, stroke: 1.5, className: "shrink-0 animate-spin text-text-muted" }),
1447
- /* @__PURE__ */ jsx22("span", { className: "text-caption text-text-muted", children: pending })
1558
+ /* @__PURE__ */ jsx23(Autocomplete.Status, { className: "flex items-center gap-2 px-3 [&:not(:empty)]:h-8", children: pending && /* @__PURE__ */ jsxs16(Fragment3, { children: [
1559
+ /* @__PURE__ */ jsx23(IconLoader22, { size: 12, stroke: 1.5, className: "shrink-0 animate-spin text-text-muted" }),
1560
+ /* @__PURE__ */ jsx23("span", { className: "text-caption text-text-muted", children: pending })
1448
1561
  ] }) }),
1449
- notes.map((note) => /* @__PURE__ */ jsx22("div", { className: "flex min-h-8 items-center px-3", children: /* @__PURE__ */ jsx22(FieldLine, { children: note }) }, note)),
1450
- /* @__PURE__ */ jsx22(Autocomplete.Empty, { className: "flex items-center px-3 [&:not(:empty)]:min-h-10", children: empty && /* @__PURE__ */ jsx22(EmptyState, { scope: "section", message: empty }) })
1562
+ notes.map((note) => /* @__PURE__ */ jsx23("div", { className: "flex min-h-8 items-center px-3", children: /* @__PURE__ */ jsx23(FieldLine, { children: note }) }, note)),
1563
+ /* @__PURE__ */ jsx23(Autocomplete.Empty, { className: "flex items-center px-3 [&:not(:empty)]:min-h-10", children: empty && /* @__PURE__ */ jsx23(EmptyState, { scope: "section", message: empty }) })
1451
1564
  ] }),
1452
- /* @__PURE__ */ jsx22(Footer, { keys })
1565
+ /* @__PURE__ */ jsx23(Footer, { keys })
1453
1566
  ]
1454
1567
  }
1455
1568
  );
1456
1569
  }
1457
1570
  function RowLeading({ row }) {
1458
1571
  if (row.icon != null) {
1459
- return /* @__PURE__ */ jsx22("span", { className: "flex size-8 items-center justify-center rounded-sm bg-bg-inset text-text-secondary", children: row.icon });
1572
+ return /* @__PURE__ */ jsx23("span", { className: "flex size-8 items-center justify-center rounded-sm bg-bg-inset text-text-secondary", children: row.icon });
1460
1573
  }
1461
- return /* @__PURE__ */ jsx22("span", { className: "flex size-8 items-center justify-center", children: row.leading });
1574
+ return /* @__PURE__ */ jsx23("span", { className: "flex size-8 items-center justify-center", children: row.leading });
1462
1575
  }
1463
1576
  var TEXT_TYPES = /* @__PURE__ */ new Set(["", "text", "search", "email", "url", "tel", "password", "number"]);
1464
1577
  function isTextField(el) {
@@ -1468,31 +1581,18 @@ function isTextField(el) {
1468
1581
  function CommandPaletteForm({ chip, icon, submitLabel, onSubmit, submitWaits, working, error, children }) {
1469
1582
  const { modKey, popupRef } = usePalette("CommandPaletteForm");
1470
1583
  const back = useBack(chip, popupRef);
1471
- const frameRef = useRef2(null);
1584
+ const frameRef = useRef3(null);
1472
1585
  const busy = !!working;
1473
- const busyRef = useRef2(busy);
1586
+ const busyRef = useRef3(busy);
1474
1587
  busyRef.current = busy;
1475
- const returnTo = useRef2(null);
1476
- const firstInvalid = () => frameRef.current?.querySelector("[data-invalid]")?.querySelector(CONTROL) ?? null;
1588
+ const firstInvalid2 = () => frameRef.current?.querySelector("[data-invalid]")?.querySelector(CONTROL2) ?? null;
1477
1589
  const submit = () => {
1478
1590
  if (busyRef.current || submitWaits) return;
1479
- const active = document.activeElement;
1480
- returnTo.current = active instanceof HTMLElement && frameRef.current?.contains(active) ? active : null;
1481
1591
  onSubmit();
1482
1592
  requestAnimationFrame(() => {
1483
- if (!busyRef.current) firstInvalid()?.focus();
1593
+ if (!busyRef.current) firstInvalid2()?.focus();
1484
1594
  });
1485
1595
  };
1486
- useLayoutEffect2(() => {
1487
- if (busy) {
1488
- frameRef.current?.focus();
1489
- return;
1490
- }
1491
- if (document.activeElement !== frameRef.current) return;
1492
- const was = returnTo.current;
1493
- const target = firstInvalid() ?? (was?.isConnected && !was.disabled ? was : null) ?? firstControl(popupRef.current);
1494
- target?.focus();
1495
- }, [busy]);
1496
1596
  const backWorksFrom = (el) => {
1497
1597
  const frame = frameRef.current;
1498
1598
  if (!frame || busy || !el || !frame.contains(el)) return false;
@@ -1501,13 +1601,8 @@ function CommandPaletteForm({ chip, icon, submitLabel, onSubmit, submitWaits, wo
1501
1601
  };
1502
1602
  const [backNamed, setBackNamed] = useState3(false);
1503
1603
  const measure = () => setBackNamed(backWorksFrom(document.activeElement));
1504
- useLayoutEffect2(measure);
1604
+ useLayoutEffect3(measure);
1505
1605
  const onKeyDown = (e) => {
1506
- if (e.key === "Enter" && (e.ctrlKey || e.metaKey)) {
1507
- e.preventDefault();
1508
- submit();
1509
- return;
1510
- }
1511
1606
  if (e.key === "Backspace" && !e.ctrlKey && !e.metaKey && !e.altKey && backWorksFrom(e.target)) {
1512
1607
  e.preventDefault();
1513
1608
  back();
@@ -1518,54 +1613,56 @@ function CommandPaletteForm({ chip, icon, submitLabel, onSubmit, submitWaits, wo
1518
1613
  ...backNamed ? [["Backspace", "back"]] : [],
1519
1614
  ["Esc", "close"]
1520
1615
  ];
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: [
1523
- icon != null && /* @__PURE__ */ jsx22("span", { className: "flex shrink-0 items-center text-text-secondary", children: icon }),
1524
- /* @__PURE__ */ jsx22(LevelChip, { chip, onBack: back })
1616
+ 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: [
1617
+ /* @__PURE__ */ jsxs16("div", { className: "flex h-12 shrink-0 items-center gap-3 border-b border-border-subtle px-5", children: [
1618
+ icon != null && /* @__PURE__ */ jsx23("span", { className: "flex shrink-0 items-center text-text-secondary", children: icon }),
1619
+ /* @__PURE__ */ jsx23(LevelChip, { chip, onBack: back })
1525
1620
  ] }),
1526
- /* @__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: [
1528
- /* @__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
- /* @__PURE__ */ jsx22(
1530
- Button,
1531
- {
1532
- variant: "primary",
1533
- onClick: submit,
1534
- disabled: busy,
1535
- disabledReason: busy ? void 0 : submitWaits,
1536
- leadingIcon: busy ? /* @__PURE__ */ jsx22(IconLoader22, { size: 16, stroke: 1.5, className: "animate-spin" }) : void 0,
1537
- children: working ? working.button : submitLabel
1538
- }
1539
- )
1621
+ /* @__PURE__ */ jsxs16(Form, { "data-command-palette-fields": "", busy, enterSends: false, onSubmit: submit, className: "flex min-h-0 flex-col", children: [
1622
+ /* @__PURE__ */ jsx23(ScrollArea, { viewportClassName: "max-h-[420px]", contentClassName: "flex flex-col px-5 py-4", children: /* @__PURE__ */ jsx23("div", { className: "flex flex-col gap-4", children }) }),
1623
+ /* @__PURE__ */ jsxs16("div", { className: "flex shrink-0 items-center gap-3 px-5 pb-4", children: [
1624
+ /* @__PURE__ */ jsx23("div", { className: "min-w-0 flex-1", children: working ? /* @__PURE__ */ jsx23(FieldLine, { children: working.line }) : error ? /* @__PURE__ */ jsx23(FieldLine, { tone: "error", children: error }) : null }),
1625
+ /* @__PURE__ */ jsx23(
1626
+ Button,
1627
+ {
1628
+ type: "submit",
1629
+ variant: "primary",
1630
+ disabled: busy,
1631
+ disabledReason: busy ? void 0 : submitWaits,
1632
+ leadingIcon: busy ? /* @__PURE__ */ jsx23(IconLoader22, { size: 16, stroke: 1.5, className: "animate-spin" }) : void 0,
1633
+ children: working ? working.button : submitLabel
1634
+ }
1635
+ )
1636
+ ] })
1540
1637
  ] }),
1541
- /* @__PURE__ */ jsx22(Footer, { keys })
1638
+ /* @__PURE__ */ jsx23(Footer, { keys })
1542
1639
  ] });
1543
1640
  }
1544
1641
  var BAR_WIDTHS = ["w-4/5", "w-3/5", "w-2/3"];
1545
1642
  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: [
1548
- /* @__PURE__ */ jsx22(IconLoader22, { size: 14, stroke: 1.5, className: "shrink-0 animate-spin" }),
1643
+ return /* @__PURE__ */ jsxs16("div", { role: "status", className: "flex flex-col gap-2", children: [
1644
+ /* @__PURE__ */ jsxs16("span", { className: "flex items-center gap-2 text-caption text-text-secondary", children: [
1645
+ /* @__PURE__ */ jsx23(IconLoader22, { size: 14, stroke: 1.5, className: "shrink-0 animate-spin" }),
1549
1646
  children
1550
1647
  ] }),
1551
- BAR_WIDTHS.slice(0, bars).map((width) => /* @__PURE__ */ jsx22(SkeletonBar, { className: cn("h-3", width) }, width))
1648
+ BAR_WIDTHS.slice(0, bars).map((width) => /* @__PURE__ */ jsx23(SkeletonBar, { className: cn("h-3", width) }, width))
1552
1649
  ] });
1553
1650
  }
1554
1651
  function CommandPaletteAnswer({ children, note }) {
1555
1652
  const paragraphs = children.split(/\n\s*\n/).filter((p) => p.trim() !== "");
1556
- return /* @__PURE__ */ jsxs15("div", { className: "flex flex-col gap-2", children: [
1557
- paragraphs.map((paragraph, i) => /* @__PURE__ */ jsx22("p", { className: "whitespace-pre-wrap text-body-2 text-text-primary", children: paragraph.split(/\s*(\[\d+\])/).map(
1558
- (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
1653
+ return /* @__PURE__ */ jsxs16("div", { className: "flex flex-col gap-2", children: [
1654
+ paragraphs.map((paragraph, i) => /* @__PURE__ */ jsx23("p", { className: "whitespace-pre-wrap text-body-2 text-text-primary", children: paragraph.split(/\s*(\[\d+\])/).map(
1655
+ (part, j) => /^\[\d+\]$/.test(part) ? /* @__PURE__ */ jsx23("sup", { className: "ml-0.5 font-mono text-small text-accent-primary", children: part.slice(1, -1) }, j) : part
1559
1656
  ) }, i)),
1560
- note && /* @__PURE__ */ jsx22(FieldLine, { children: note })
1657
+ note && /* @__PURE__ */ jsx23(FieldLine, { children: note })
1561
1658
  ] });
1562
1659
  }
1563
1660
  function CommandPaletteQuote({ children }) {
1564
- return /* @__PURE__ */ jsx22("p", { className: "whitespace-pre-wrap border-l-2 border-border-default pl-3 text-body-2 text-text-primary", children });
1661
+ return /* @__PURE__ */ jsx23("p", { className: "whitespace-pre-wrap border-l-2 border-border-default pl-3 text-body-2 text-text-primary", children });
1565
1662
  }
1566
1663
 
1567
1664
  // src/InlineChip.tsx
1568
- import { Fragment as Fragment4, jsx as jsx23, jsxs as jsxs16 } from "react/jsx-runtime";
1665
+ import { Fragment as Fragment4, jsx as jsx24, jsxs as jsxs17 } from "react/jsx-runtime";
1569
1666
  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
1667
  var INLINE_CHIP_TONE_CLASSES = {
1571
1668
  /** A thing or a place — anything that is not a person. */
@@ -1587,41 +1684,41 @@ function inlineChipClassName(tone, className) {
1587
1684
  return cn(INLINE_CHIP_CLASSES, INLINE_CHIP_TONE_CLASSES[tone], className);
1588
1685
  }
1589
1686
  function InlineChip({ tone = "neutral", icon, href, className, children, ...props }) {
1590
- const body = /* @__PURE__ */ jsxs16(Fragment4, { children: [
1591
- icon && /* @__PURE__ */ jsx23("span", { className: "flex size-4 shrink-0 items-center justify-center text-text-secondary", children: icon }),
1687
+ const body = /* @__PURE__ */ jsxs17(Fragment4, { children: [
1688
+ icon && /* @__PURE__ */ jsx24("span", { className: "flex size-4 shrink-0 items-center justify-center text-text-secondary", children: icon }),
1592
1689
  children
1593
1690
  ] });
1594
1691
  const classes = inlineChipClassName(tone, className);
1595
1692
  if (href === void 0) {
1596
- return /* @__PURE__ */ jsx23("span", { className: classes, ...props, children: body });
1693
+ return /* @__PURE__ */ jsx24("span", { className: classes, ...props, children: body });
1597
1694
  }
1598
- return /* @__PURE__ */ jsx23("a", { href, className: classes, ...props, children: body });
1695
+ return /* @__PURE__ */ jsx24("a", { href, className: classes, ...props, children: body });
1599
1696
  }
1600
1697
 
1601
1698
  // src/IdentityMenu.tsx
1602
- import { useCallback, useRef as useRef3 } from "react";
1699
+ import { useCallback, useRef as useRef4 } from "react";
1603
1700
 
1604
1701
  // src/Divider.tsx
1605
1702
  import { Separator } from "@base-ui/react/separator";
1606
- import { jsx as jsx24, jsxs as jsxs17 } from "react/jsx-runtime";
1703
+ import { jsx as jsx25, jsxs as jsxs18 } from "react/jsx-runtime";
1607
1704
  function Divider({ orientation = "horizontal", label, tone = "default", className }) {
1608
1705
  if (label && orientation === "horizontal") {
1609
1706
  const line = tone === "warning" ? "bg-warning-muted" : "bg-border-subtle";
1610
- return /* @__PURE__ */ jsxs17(
1707
+ return /* @__PURE__ */ jsxs18(
1611
1708
  Separator,
1612
1709
  {
1613
1710
  orientation: "horizontal",
1614
1711
  "aria-label": label,
1615
1712
  className: cn("flex shrink-0 items-center gap-2 mx-3", className),
1616
1713
  children: [
1617
- /* @__PURE__ */ jsx24("span", { "aria-hidden": "true", className: cn("h-px flex-1", line) }),
1618
- /* @__PURE__ */ jsx24("span", { className: cn("shrink-0 text-caption", tone === "warning" ? "text-warning-default" : "text-text-muted"), children: label }),
1619
- /* @__PURE__ */ jsx24("span", { "aria-hidden": "true", className: cn("h-px flex-1", line) })
1714
+ /* @__PURE__ */ jsx25("span", { "aria-hidden": "true", className: cn("h-px flex-1", line) }),
1715
+ /* @__PURE__ */ jsx25("span", { className: cn("shrink-0 text-caption", tone === "warning" ? "text-warning-default" : "text-text-muted"), children: label }),
1716
+ /* @__PURE__ */ jsx25("span", { "aria-hidden": "true", className: cn("h-px flex-1", line) })
1620
1717
  ]
1621
1718
  }
1622
1719
  );
1623
1720
  }
1624
- return /* @__PURE__ */ jsx24(
1721
+ return /* @__PURE__ */ jsx25(
1625
1722
  Separator,
1626
1723
  {
1627
1724
  orientation,
@@ -1631,15 +1728,15 @@ function Divider({ orientation = "horizontal", label, tone = "default", classNam
1631
1728
  }
1632
1729
 
1633
1730
  // src/Person.tsx
1634
- import { jsx as jsx25, jsxs as jsxs18 } from "react/jsx-runtime";
1731
+ import { jsx as jsx26, jsxs as jsxs19 } from "react/jsx-runtime";
1635
1732
  function Person({ name, picture, fallback = "\u2014", size = 20, className }) {
1636
1733
  return (
1637
1734
  // gap-2: the face-to-name distance is one rule (8px) wherever a person
1638
1735
  // appears — Katerina, 2026-09-01, set on Person so PersonTrigger and every
1639
1736
  // row agree by construction.
1640
- /* @__PURE__ */ jsxs18("span", { className: cn("flex min-w-0 items-center gap-2", className), children: [
1641
- /* @__PURE__ */ jsx25(Avatar, { name, src: picture, size }),
1642
- /* @__PURE__ */ jsx25("span", { className: cn("truncate", !name && "text-text-muted"), children: name ?? fallback })
1737
+ /* @__PURE__ */ jsxs19("span", { className: cn("flex min-w-0 items-center gap-2", className), children: [
1738
+ /* @__PURE__ */ jsx26(Avatar, { name, src: picture, size }),
1739
+ /* @__PURE__ */ jsx26("span", { className: cn("truncate", !name && "text-text-muted"), children: name ?? fallback })
1643
1740
  ] })
1644
1741
  );
1645
1742
  }
@@ -1647,10 +1744,10 @@ function Person({ name, picture, fallback = "\u2014", size = 20, className }) {
1647
1744
  // src/PersonTrigger.tsx
1648
1745
  import { Button as BaseButton5 } from "@base-ui/react/button";
1649
1746
  import { IconChevronDown } from "@tabler/icons-react";
1650
- import { jsx as jsx26, jsxs as jsxs19 } from "react/jsx-runtime";
1747
+ import { jsx as jsx27, jsxs as jsxs20 } from "react/jsx-runtime";
1651
1748
  function PersonTrigger({ name, picture, fallback, size, open = false, compact = false, className, ...props }) {
1652
1749
  if (compact) {
1653
- return /* @__PURE__ */ jsx26(
1750
+ return /* @__PURE__ */ jsx27(
1654
1751
  BaseButton5,
1655
1752
  {
1656
1753
  type: "button",
@@ -1659,11 +1756,11 @@ function PersonTrigger({ name, picture, fallback, size, open = false, compact =
1659
1756
  "aria-label": props["aria-label"] ?? name ?? fallback,
1660
1757
  className: cn("cursor-pointer rounded-full", className),
1661
1758
  ...props,
1662
- children: /* @__PURE__ */ jsx26(Avatar, { name, src: picture, size: size ?? 36 })
1759
+ children: /* @__PURE__ */ jsx27(Avatar, { name, src: picture, size: size ?? 36 })
1663
1760
  }
1664
1761
  );
1665
1762
  }
1666
- return /* @__PURE__ */ jsxs19(
1763
+ return /* @__PURE__ */ jsxs20(
1667
1764
  BaseButton5,
1668
1765
  {
1669
1766
  type: "button",
@@ -1681,18 +1778,18 @@ function PersonTrigger({ name, picture, fallback, size, open = false, compact =
1681
1778
  ),
1682
1779
  ...props,
1683
1780
  children: [
1684
- /* @__PURE__ */ jsx26(Person, { name, picture, fallback, size: size ?? 22 }),
1685
- /* @__PURE__ */ jsx26(IconChevronDown, { size: 14, stroke: 1.5, className: "shrink-0 text-text-muted" })
1781
+ /* @__PURE__ */ jsx27(Person, { name, picture, fallback, size: size ?? 22 }),
1782
+ /* @__PURE__ */ jsx27(IconChevronDown, { size: 14, stroke: 1.5, className: "shrink-0 text-text-muted" })
1686
1783
  ]
1687
1784
  }
1688
1785
  );
1689
1786
  }
1690
1787
 
1691
1788
  // src/IdentityMenu.tsx
1692
- import { Fragment as Fragment5, jsx as jsx27, jsxs as jsxs20 } from "react/jsx-runtime";
1789
+ import { Fragment as Fragment5, jsx as jsx28, jsxs as jsxs21 } from "react/jsx-runtime";
1693
1790
  function IdentityPanel({ className, onClose = () => {
1694
1791
  }, ...rest }) {
1695
- return /* @__PURE__ */ jsx27(MenuPanel, { className: cn("w-72", className), children: /* @__PURE__ */ jsx27(IdentityRows, { ...rest, onClose }) });
1792
+ return /* @__PURE__ */ jsx28(MenuPanel, { className: cn("w-72", className), children: /* @__PURE__ */ jsx28(IdentityRows, { ...rest, onClose }) });
1696
1793
  }
1697
1794
  function IdentityRows({ me, signedIn, relayUrl, idBase, onCopyKey, onSignOut, onClose, children }) {
1698
1795
  const act = (action) => () => {
@@ -1700,53 +1797,53 @@ function IdentityRows({ me, signedIn, relayUrl, idBase, onCopyKey, onSignOut, on
1700
1797
  action();
1701
1798
  };
1702
1799
  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: [
1705
- /* @__PURE__ */ jsx27(MenuRow, { children: /* @__PURE__ */ jsx27(Person, { name: me.name, picture: me.picture, fallback: "Anonymous", size: 28, className: "text-body-2-strong" }) }),
1706
- /* @__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: [
1800
+ return /* @__PURE__ */ jsxs21(Fragment5, { children: [
1801
+ /* @__PURE__ */ jsxs21(MenuSection, { label: signedIn ? "Signed in as" : "Acting as", children: [
1802
+ /* @__PURE__ */ jsx28(MenuRow, { children: /* @__PURE__ */ jsx28(Person, { name: me.name, picture: me.picture, fallback: "Anonymous", size: 28, className: "text-body-2-strong" }) }),
1803
+ /* @__PURE__ */ jsx28(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." }),
1804
+ me.email && /* @__PURE__ */ jsxs21(Note, { children: [
1708
1805
  me.email,
1709
1806
  " \xB7 known to Estiva, never published to the relay"
1710
1807
  ] })
1711
1808
  ] }),
1712
- relayUrl && /* @__PURE__ */ jsxs20(Fragment5, { children: [
1713
- /* @__PURE__ */ jsx27(Divider, { className: "mx-0 my-2" }),
1714
- /* @__PURE__ */ jsxs20(MenuSection, { label: "Workspace", children: [
1715
- /* @__PURE__ */ jsx27(MenuRow, { children: /* @__PURE__ */ jsx27("span", { className: "break-all font-mono text-caption text-text-primary", children: relayUrl }) }),
1716
- /* @__PURE__ */ jsx27(Note, { children: "Everyone on this relay shares this workspace, in every app." })
1809
+ relayUrl && /* @__PURE__ */ jsxs21(Fragment5, { children: [
1810
+ /* @__PURE__ */ jsx28(Divider, { className: "mx-0 my-2" }),
1811
+ /* @__PURE__ */ jsxs21(MenuSection, { label: "Workspace", children: [
1812
+ /* @__PURE__ */ jsx28(MenuRow, { children: /* @__PURE__ */ jsx28("span", { className: "break-all font-mono text-caption text-text-primary", children: relayUrl }) }),
1813
+ /* @__PURE__ */ jsx28(Note, { children: "Everyone on this relay shares this workspace, in every app." })
1717
1814
  ] })
1718
1815
  ] }),
1719
- appRows && /* @__PURE__ */ jsxs20(Fragment5, { children: [
1720
- /* @__PURE__ */ jsx27(Divider, { className: "mx-0 my-2" }),
1816
+ appRows && /* @__PURE__ */ jsxs21(Fragment5, { children: [
1817
+ /* @__PURE__ */ jsx28(Divider, { className: "mx-0 my-2" }),
1721
1818
  appRows
1722
1819
  ] }),
1723
- signedIn && idBase || onCopyKey || idBase && onSignOut ? /* @__PURE__ */ jsx27(Divider, { className: "mx-0 my-2" }) : null,
1724
- signedIn && idBase && /* @__PURE__ */ jsx27(
1820
+ signedIn && idBase || onCopyKey || idBase && onSignOut ? /* @__PURE__ */ jsx28(Divider, { className: "mx-0 my-2" }) : null,
1821
+ signedIn && idBase && /* @__PURE__ */ jsx28(
1725
1822
  MenuItem,
1726
1823
  {
1727
1824
  label: "Edit your profile in Estiva ID",
1728
1825
  onClick: act(() => window.open(idBase, "_blank", "noopener,noreferrer"))
1729
1826
  }
1730
1827
  ),
1731
- onCopyKey && /* @__PURE__ */ jsx27(MenuItem, { label: "Copy public key", onClick: act(onCopyKey) }),
1732
- idBase && onSignOut && /* @__PURE__ */ jsx27(MenuItem, { label: "Sign out", onClick: act(onSignOut) })
1828
+ onCopyKey && /* @__PURE__ */ jsx28(MenuItem, { label: "Copy public key", onClick: act(onCopyKey) }),
1829
+ idBase && onSignOut && /* @__PURE__ */ jsx28(MenuItem, { label: "Sign out", onClick: act(onSignOut) })
1733
1830
  ] });
1734
1831
  }
1735
1832
  function IdentityMenu({ me, signedIn, relayUrl, idBase, onCopyKey, onSignOut, compact = false, className, children }) {
1736
- const actions = useRef3(null);
1833
+ const actions = useRef4(null);
1737
1834
  const close = useCallback(() => actions.current?.close(), []);
1738
1835
  return (
1739
1836
  /* The wrapper carries the caller's `className` and nothing else. It used
1740
1837
  to be `relative`, because the panel was positioned against it; the panel
1741
1838
  hangs from the trigger and portals now, so a positioning context here
1742
1839
  would only be a lie about what this box does. */
1743
- /* @__PURE__ */ jsx27("div", { className, children: /* @__PURE__ */ jsx27(
1840
+ /* @__PURE__ */ jsx28("div", { className, children: /* @__PURE__ */ jsx28(
1744
1841
  Menu,
1745
1842
  {
1746
1843
  align: "right",
1747
1844
  actionsRef: actions,
1748
1845
  className: "w-72",
1749
- trigger: /* @__PURE__ */ jsx27(
1846
+ trigger: /* @__PURE__ */ jsx28(
1750
1847
  PersonTrigger,
1751
1848
  {
1752
1849
  name: me.name,
@@ -1757,7 +1854,7 @@ function IdentityMenu({ me, signedIn, relayUrl, idBase, onCopyKey, onSignOut, co
1757
1854
  "aria-label": compact ? "Account menu" : void 0
1758
1855
  }
1759
1856
  ),
1760
- children: /* @__PURE__ */ jsx27(
1857
+ children: /* @__PURE__ */ jsx28(
1761
1858
  IdentityRows,
1762
1859
  {
1763
1860
  me,
@@ -1775,18 +1872,40 @@ function IdentityMenu({ me, signedIn, relayUrl, idBase, onCopyKey, onSignOut, co
1775
1872
  );
1776
1873
  }
1777
1874
  function Note({ children }) {
1778
- return /* @__PURE__ */ jsx27("span", { className: "px-2 pb-1.5 text-caption text-text-secondary", children });
1875
+ return /* @__PURE__ */ jsx28("span", { className: "px-2 pb-1.5 text-caption text-text-secondary", children });
1779
1876
  }
1780
1877
 
1878
+ // src/FilePicker.tsx
1879
+ import { forwardRef } from "react";
1880
+ import { jsx as jsx29 } from "react/jsx-runtime";
1881
+ var FilePicker = forwardRef(function FilePicker2({ onPick, ...props }, ref) {
1882
+ return /* @__PURE__ */ jsx29(
1883
+ "input",
1884
+ {
1885
+ ref,
1886
+ type: "file",
1887
+ "aria-hidden": "true",
1888
+ tabIndex: -1,
1889
+ className: "hidden",
1890
+ ...props,
1891
+ onChange: (event) => {
1892
+ const files = Array.from(event.target.files ?? []);
1893
+ event.target.value = "";
1894
+ if (files.length > 0) onPick(files);
1895
+ }
1896
+ }
1897
+ );
1898
+ });
1899
+
1781
1900
  // src/Select.tsx
1782
1901
  import { IconCheck as IconCheck2, IconChevronDown as IconChevronDown2 } from "@tabler/icons-react";
1783
1902
  import { Select as BaseSelect } from "@base-ui/react/select";
1784
- import { jsx as jsx28, jsxs as jsxs21 } from "react/jsx-runtime";
1903
+ import { jsx as jsx30, jsxs as jsxs22 } from "react/jsx-runtime";
1785
1904
  var GAP4 = 4;
1786
1905
  var VIEWPORT_PAD4 = 8;
1787
1906
  function Select({ value, onChange, options, size = "default", ariaLabel, placeholder = "Select\u2026", disabled, className, ...aria }) {
1788
1907
  const selected = options.find((o) => o.value === value);
1789
- return /* @__PURE__ */ jsxs21(
1908
+ return /* @__PURE__ */ jsxs22(
1790
1909
  BaseSelect.Root,
1791
1910
  {
1792
1911
  value,
@@ -1794,7 +1913,7 @@ function Select({ value, onChange, options, size = "default", ariaLabel, placeho
1794
1913
  disabled,
1795
1914
  modal: false,
1796
1915
  children: [
1797
- /* @__PURE__ */ jsxs21(
1916
+ /* @__PURE__ */ jsxs22(
1798
1917
  BaseSelect.Trigger,
1799
1918
  {
1800
1919
  "aria-label": ariaLabel,
@@ -1821,20 +1940,20 @@ function Select({ value, onChange, options, size = "default", ariaLabel, placeho
1821
1940
  className
1822
1941
  ),
1823
1942
  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 })
1943
+ /* @__PURE__ */ jsxs22("span", { className: cn("flex min-w-0 items-center gap-2", !selected && "text-text-muted"), children: [
1944
+ selected?.leading && /* @__PURE__ */ jsx30("span", { className: "flex shrink-0 items-center", children: selected.leading }),
1945
+ /* @__PURE__ */ jsx30(BaseSelect.Value, { className: "truncate", children: () => selected?.label ?? placeholder })
1827
1946
  ] }),
1828
- /* @__PURE__ */ jsx28(
1947
+ /* @__PURE__ */ jsx30(
1829
1948
  BaseSelect.Icon,
1830
1949
  {
1831
- render: /* @__PURE__ */ jsx28(IconChevronDown2, { size: size === "small" ? 14 : 16, stroke: 1.5, className: "shrink-0 text-text-secondary" })
1950
+ render: /* @__PURE__ */ jsx30(IconChevronDown2, { size: size === "small" ? 14 : 16, stroke: 1.5, className: "shrink-0 text-text-secondary" })
1832
1951
  }
1833
1952
  )
1834
1953
  ]
1835
1954
  }
1836
1955
  ),
1837
- /* @__PURE__ */ jsx28(BaseSelect.Portal, { children: /* @__PURE__ */ jsx28(
1956
+ /* @__PURE__ */ jsx30(BaseSelect.Portal, { children: /* @__PURE__ */ jsx30(
1838
1957
  BaseSelect.Positioner,
1839
1958
  {
1840
1959
  side: "bottom",
@@ -1843,25 +1962,25 @@ function Select({ value, onChange, options, size = "default", ariaLabel, placeho
1843
1962
  collisionPadding: VIEWPORT_PAD4,
1844
1963
  alignItemWithTrigger: false,
1845
1964
  className: "z-50 data-[anchor-hidden]:hidden",
1846
- children: /* @__PURE__ */ jsx28(
1965
+ children: /* @__PURE__ */ jsx30(
1847
1966
  BaseSelect.Popup,
1848
1967
  {
1849
- render: /* @__PURE__ */ jsx28(MenuPanel, {}),
1968
+ render: /* @__PURE__ */ jsx30(MenuPanel, {}),
1850
1969
  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(
1970
+ 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
1971
  BaseSelect.Item,
1853
1972
  {
1854
1973
  value: option.value,
1855
1974
  className: cn(menuItemClassName({ size: "default" }), "justify-between data-[selected]:font-medium"),
1856
1975
  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 })
1976
+ /* @__PURE__ */ jsxs22("span", { className: "flex min-w-0 items-center gap-2", children: [
1977
+ option.leading && /* @__PURE__ */ jsx30("span", { className: "flex shrink-0 items-center", children: option.leading }),
1978
+ /* @__PURE__ */ jsx30(BaseSelect.ItemText, { className: "truncate text-body-2 text-text-primary", children: option.label })
1860
1979
  ] }),
1861
- /* @__PURE__ */ jsx28(
1980
+ /* @__PURE__ */ jsx30(
1862
1981
  BaseSelect.ItemIndicator,
1863
1982
  {
1864
- render: /* @__PURE__ */ jsx28(IconCheck2, { size: 16, stroke: 1.5, className: "shrink-0 text-text-secondary" })
1983
+ render: /* @__PURE__ */ jsx30(IconCheck2, { size: 16, stroke: 1.5, className: "shrink-0 text-text-secondary" })
1865
1984
  }
1866
1985
  )
1867
1986
  ]
@@ -1878,17 +1997,20 @@ function Select({ value, onChange, options, size = "default", ariaLabel, placeho
1878
1997
  }
1879
1998
 
1880
1999
  // src/TextInput.tsx
1881
- import { forwardRef } from "react";
2000
+ import { forwardRef as forwardRef2 } from "react";
1882
2001
  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(
2002
+ import { jsx as jsx31 } from "react/jsx-runtime";
2003
+ var TextInput = forwardRef2(function TextInput2({ className, type = "text", size = "default", ...props }, ref) {
2004
+ return /* @__PURE__ */ jsx31(
1886
2005
  Input,
1887
2006
  {
1888
2007
  ref,
1889
2008
  type,
1890
2009
  className: cn(
1891
- "bg-bg-inset border border-border-default focus:border-border-focus rounded-lg",
2010
+ // The border strengthens on hover, as Select's and ChipInput's do (Katerina, 16 September:
2011
+ // "aren't there hover states in text input and text area?"). Focus comes after hover in
2012
+ // Tailwind's order, so a focused field keeps the focus border under the pointer.
2013
+ "bg-bg-inset border border-border-default hover:border-border-strong focus:border-border-focus rounded-lg",
1892
2014
  // The small size is the small Select's trigger, class for class.
1893
2015
  size === "default" && "px-3 py-2 text-input-value",
1894
2016
  size === "small" && "h-6 px-2 text-caption",
@@ -1904,17 +2026,20 @@ var TextInput = forwardRef(function TextInput2({ className, type = "text", size
1904
2026
  });
1905
2027
 
1906
2028
  // 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,
2029
+ import { forwardRef as forwardRef3 } from "react";
2030
+ import { Field as BaseField3 } from "@base-ui/react/field";
2031
+ import { jsx as jsx32 } from "react/jsx-runtime";
2032
+ var Textarea = forwardRef3(function Textarea2({ className, ...props }, ref) {
2033
+ return /* @__PURE__ */ jsx32(
2034
+ BaseField3.Control,
1913
2035
  {
1914
2036
  ref,
1915
- render: /* @__PURE__ */ jsx30("textarea", {}),
2037
+ render: /* @__PURE__ */ jsx32("textarea", {}),
1916
2038
  className: cn(
1917
- "bg-bg-inset border border-border-default focus:border-border-focus rounded-lg px-3 py-2",
2039
+ // The border strengthens on hover, as Select's and ChipInput's do (Katerina, 16 September:
2040
+ // "aren't there hover states in text input and text area?"). Focus comes after hover in
2041
+ // Tailwind's order, so a focused field keeps the focus border under the pointer.
2042
+ "bg-bg-inset border border-border-default hover:border-border-strong focus:border-border-focus rounded-lg px-3 py-2",
1918
2043
  "text-input-value text-text-primary placeholder:text-text-muted",
1919
2044
  "resize-none outline-none transition-colors",
1920
2045
  "disabled:pointer-events-none disabled:bg-bg-disabled disabled:text-text-disabled",
@@ -1930,24 +2055,24 @@ var Textarea = forwardRef2(function Textarea2({ className, ...props }, ref) {
1930
2055
  import { useState as useState4 } from "react";
1931
2056
 
1932
2057
  // src/DialogShell.tsx
1933
- import { useRef as useRef4 } from "react";
2058
+ import { useRef as useRef5 } from "react";
1934
2059
  import { Dialog as Dialog2 } from "@base-ui/react/dialog";
1935
2060
  import { AlertDialog } from "@base-ui/react/alert-dialog";
1936
2061
  import { IconX as IconX4 } from "@tabler/icons-react";
1937
- import { jsx as jsx31, jsxs as jsxs22 } from "react/jsx-runtime";
2062
+ import { jsx as jsx33, jsxs as jsxs23 } from "react/jsx-runtime";
1938
2063
  function DialogShell({ title, onClose, headerContent, footer, children, bodyClassName, bodyMaxHeight, width = 502, alert = false }) {
1939
2064
  const Parts = alert ? AlertDialog : Dialog2;
1940
- const popupRef = useRef4(null);
1941
- return /* @__PURE__ */ jsx31(
2065
+ const popupRef = useRef5(null);
2066
+ return /* @__PURE__ */ jsx33(
1942
2067
  Parts.Root,
1943
2068
  {
1944
2069
  open: true,
1945
2070
  onOpenChange: (open) => {
1946
2071
  if (!open) onClose();
1947
2072
  },
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(
2073
+ children: /* @__PURE__ */ jsxs23(Parts.Portal, { children: [
2074
+ /* @__PURE__ */ jsx33(Parts.Backdrop, { className: "fixed inset-0 z-40 bg-scrim" }),
2075
+ /* @__PURE__ */ jsx33("div", { className: "fixed inset-0 z-50 flex items-center justify-center pointer-events-none", children: /* @__PURE__ */ jsxs23(
1951
2076
  Parts.Popup,
1952
2077
  {
1953
2078
  ref: popupRef,
@@ -1956,16 +2081,16 @@ function DialogShell({ title, onClose, headerContent, footer, children, bodyClas
1956
2081
  className: "bg-bg-elevated border border-border-subtle rounded-lg shadow-lg pointer-events-auto flex flex-col overflow-hidden outline-none",
1957
2082
  style: { width },
1958
2083
  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(
2084
+ /* @__PURE__ */ jsxs23("div", { className: "h-12 flex items-center justify-between pl-5 pr-4 border-b border-border-subtle shrink-0", children: [
2085
+ headerContent ?? /* @__PURE__ */ jsx33(Parts.Title, { className: "text-h4 text-text-primary", render: /* @__PURE__ */ jsx33("span", {}), children: title }),
2086
+ /* @__PURE__ */ jsx33(
1962
2087
  Parts.Close,
1963
2088
  {
1964
- render: /* @__PURE__ */ jsx31(IconButton, { tooltip: "Close", "aria-label": "Close", children: /* @__PURE__ */ jsx31(IconX4, { size: 16, stroke: 1.5 }) })
2089
+ render: /* @__PURE__ */ jsx33(IconButton, { tooltip: "Close", "aria-label": "Close", children: /* @__PURE__ */ jsx33(IconX4, { size: 16, stroke: 1.5 }) })
1965
2090
  }
1966
2091
  )
1967
2092
  ] }),
1968
- bodyMaxHeight ? /* @__PURE__ */ jsx31(
2093
+ bodyMaxHeight ? /* @__PURE__ */ jsx33(
1969
2094
  ScrollArea,
1970
2095
  {
1971
2096
  className: cn(footer != null && "border-b border-border-subtle"),
@@ -1973,8 +2098,8 @@ function DialogShell({ title, onClose, headerContent, footer, children, bodyClas
1973
2098
  contentClassName: cn("pl-5 pr-4 py-4", bodyClassName),
1974
2099
  children
1975
2100
  }
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 })
2101
+ ) : /* @__PURE__ */ jsx33("div", { className: cn("pl-5 pr-4 py-4", footer != null && "border-b border-border-subtle", bodyClassName), children }),
2102
+ footer != null && /* @__PURE__ */ jsx33("div", { className: "h-12 flex items-center justify-end gap-2 pl-5 pr-4 shrink-0", children: footer })
1978
2103
  ]
1979
2104
  }
1980
2105
  ) })
@@ -1984,7 +2109,7 @@ function DialogShell({ title, onClose, headerContent, footer, children, bodyClas
1984
2109
  }
1985
2110
 
1986
2111
  // src/ConfirmDialog.tsx
1987
- import { Fragment as Fragment6, jsx as jsx32, jsxs as jsxs23 } from "react/jsx-runtime";
2112
+ import { Fragment as Fragment6, jsx as jsx34, jsxs as jsxs24 } from "react/jsx-runtime";
1988
2113
  function ConfirmDialog({ title, children, confirmLabel, destructive = false, onConfirm, onClose }) {
1989
2114
  const [busy, setBusy] = useState4(false);
1990
2115
  const confirm = async () => {
@@ -1996,16 +2121,16 @@ function ConfirmDialog({ title, children, confirmLabel, destructive = false, onC
1996
2121
  setBusy(false);
1997
2122
  }
1998
2123
  };
1999
- return /* @__PURE__ */ jsx32(
2124
+ return /* @__PURE__ */ jsx34(
2000
2125
  DialogShell,
2001
2126
  {
2002
2127
  alert: true,
2003
2128
  title,
2004
2129
  onClose,
2005
2130
  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 })
2131
+ footer: /* @__PURE__ */ jsxs24(Fragment6, { children: [
2132
+ /* @__PURE__ */ jsx34(Button, { variant: "muted", onClick: onClose, disabled: busy, children: "Cancel" }),
2133
+ /* @__PURE__ */ jsx34(Button, { variant: destructive ? "destructive" : "primary", onClick: () => void confirm(), disabled: busy, children: confirmLabel })
2009
2134
  ] }),
2010
2135
  children
2011
2136
  }
@@ -2013,15 +2138,15 @@ function ConfirmDialog({ title, children, confirmLabel, destructive = false, onC
2013
2138
  }
2014
2139
 
2015
2140
  // 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";
2141
+ import { useEffect as useEffect2, useRef as useRef6, useState as useState5 } from "react";
2142
+ import { Field as BaseField4 } from "@base-ui/react/field";
2018
2143
  import { Input as Input2 } from "@base-ui/react/input";
2019
- import { jsx as jsx33 } from "react/jsx-runtime";
2144
+ import { jsx as jsx35 } from "react/jsx-runtime";
2020
2145
  function EditableText({ value, display, displayNode, placeholder, onCommit, multiline = false, className, label, readOnly = false }) {
2021
2146
  const [editing, setEditing] = useState5(false);
2022
2147
  const [draft, setDraft] = useState5(value);
2023
2148
  const [busy, setBusy] = useState5(false);
2024
- const fieldRef = useRef5(null);
2149
+ const fieldRef = useRef6(null);
2025
2150
  useEffect2(() => {
2026
2151
  if (editing) {
2027
2152
  fieldRef.current?.focus();
@@ -2074,7 +2199,7 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
2074
2199
  written and never read. Read-only, this is a line of text: whatever
2075
2200
  names the region around it (a `Field`, a `Property`) names this too.
2076
2201
  */
2077
- /* @__PURE__ */ jsx33(
2202
+ /* @__PURE__ */ jsx35(
2078
2203
  "div",
2079
2204
  {
2080
2205
  className: cn("w-full px-2 py-1", multiline && !displayNode && "whitespace-pre-wrap", display ?? value ? "text-text-primary" : "text-text-muted", className),
@@ -2084,11 +2209,11 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
2084
2209
  );
2085
2210
  }
2086
2211
  if (editing) {
2087
- return multiline ? /* @__PURE__ */ jsx33(
2088
- BaseField3.Control,
2212
+ return multiline ? /* @__PURE__ */ jsx35(
2213
+ BaseField4.Control,
2089
2214
  {
2090
2215
  ref: fieldRef,
2091
- render: /* @__PURE__ */ jsx33("textarea", { rows: 4 }),
2216
+ render: /* @__PURE__ */ jsx35("textarea", { rows: 4 }),
2092
2217
  "aria-label": label,
2093
2218
  value: draft,
2094
2219
  disabled: busy,
@@ -2097,7 +2222,7 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
2097
2222
  onBlur: () => void commit(),
2098
2223
  className: fieldClass
2099
2224
  }
2100
- ) : /* @__PURE__ */ jsx33(
2225
+ ) : /* @__PURE__ */ jsx35(
2101
2226
  Input2,
2102
2227
  {
2103
2228
  ref: fieldRef,
@@ -2111,7 +2236,7 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
2111
2236
  }
2112
2237
  );
2113
2238
  }
2114
- return /* @__PURE__ */ jsx33(
2239
+ return /* @__PURE__ */ jsx35(
2115
2240
  "button",
2116
2241
  {
2117
2242
  type: "button",
@@ -2130,7 +2255,7 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
2130
2255
 
2131
2256
  // src/ProgressBar.tsx
2132
2257
  import { Progress } from "@base-ui/react/progress";
2133
- import { jsx as jsx34 } from "react/jsx-runtime";
2258
+ import { jsx as jsx36 } from "react/jsx-runtime";
2134
2259
  var TRACK_CLASSES = {
2135
2260
  default: "h-1.5 w-full overflow-hidden rounded-full bg-bg-inset",
2136
2261
  // 4px, Katerina's ruling of 14 September; Peek's own bar is 3px until it takes this one.
@@ -2143,16 +2268,16 @@ var INDICATOR_CLASSES = {
2143
2268
  function ProgressBar({ value, max, label, variant = "default", className }) {
2144
2269
  return (
2145
2270
  // `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] }) }) })
2271
+ /* @__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
2272
  );
2148
2273
  }
2149
2274
 
2150
2275
  // 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";
2276
+ import { Fragment as Fragment7, useCallback as useCallback2, useLayoutEffect as useLayoutEffect4, useRef as useRef7, useState as useState6 } from "react";
2277
+ import { jsx as jsx37, jsxs as jsxs25 } from "react/jsx-runtime";
2153
2278
  function Breadcrumb({ items, className }) {
2154
- const navRef = useRef6(null);
2155
- const labelRefs = useRef6([]);
2279
+ const navRef = useRef7(null);
2280
+ const labelRefs = useRef7([]);
2156
2281
  const [truncated, setTruncated] = useState6(/* @__PURE__ */ new Set());
2157
2282
  const measure = useCallback2(() => {
2158
2283
  const next = /* @__PURE__ */ new Set();
@@ -2161,7 +2286,7 @@ function Breadcrumb({ items, className }) {
2161
2286
  });
2162
2287
  setTruncated((prev) => prev.size === next.size && [...next].every((i) => prev.has(i)) ? prev : next);
2163
2288
  }, []);
2164
- useLayoutEffect3(() => {
2289
+ useLayoutEffect4(() => {
2165
2290
  measure();
2166
2291
  const nav = navRef.current;
2167
2292
  if (!nav || typeof ResizeObserver === "undefined") return;
@@ -2169,7 +2294,7 @@ function Breadcrumb({ items, className }) {
2169
2294
  observer.observe(nav);
2170
2295
  return () => observer.disconnect();
2171
2296
  }, [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) => {
2297
+ 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
2298
  const last = index === items.length - 1;
2174
2299
  const tone = item.muted || last && item.mono ? "text-text-muted" : last ? "text-text-primary" : "text-text-secondary";
2175
2300
  const text = cn(
@@ -2187,25 +2312,25 @@ function Breadcrumb({ items, className }) {
2187
2312
  // `plain` adds no look of its own: a crumb keeps the trail's size and
2188
2313
  // tone, and brightens on hover. The package's own Link, so a trail
2189
2314
  // 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 }),
2315
+ /* @__PURE__ */ jsx37(Link, { ref: setLabelRef, variant: "plain", href: item.href, onClick: item.onClick, className: cn(text, "hover:text-text-primary"), children: item.label })
2316
+ ) : /* @__PURE__ */ jsx37("span", { ref: setLabelRef, className: text, "aria-current": last ? "page" : void 0, children: item.label });
2317
+ return /* @__PURE__ */ jsxs25(Fragment7, { children: [
2318
+ index > 0 && /* @__PURE__ */ jsx37("span", { "aria-hidden": "true", className: "shrink-0 text-text-muted", children: "/" }),
2319
+ item.icon && /* @__PURE__ */ jsx37("span", { "aria-hidden": "true", className: cn("flex shrink-0", tone), children: item.icon }),
2195
2320
  truncated.has(index) ? (
2196
2321
  // `min-w-0 shrink` undoes the wrapper's own shrink-0 — the crumb
2197
2322
  // must keep truncating inside it, or wrapping it would widen the
2198
2323
  // trail and the tooltip would never be needed again.
2199
- /* @__PURE__ */ jsx35(WithTooltip, { label: item.label, wrapperClassName: "min-w-0 shrink", children: crumb })
2324
+ /* @__PURE__ */ jsx37(WithTooltip, { label: item.label, wrapperClassName: "min-w-0 shrink", children: crumb })
2200
2325
  ) : crumb
2201
2326
  ] }, `${item.label}-${index}`);
2202
2327
  }) });
2203
2328
  }
2204
2329
 
2205
2330
  // src/NavItem.tsx
2206
- import { jsx as jsx36, jsxs as jsxs25 } from "react/jsx-runtime";
2331
+ import { jsx as jsx38, jsxs as jsxs26 } from "react/jsx-runtime";
2207
2332
  function NavItem({ label, href, count, countLabel, active = false, icon, className, ...props }) {
2208
- return /* @__PURE__ */ jsxs25(
2333
+ return /* @__PURE__ */ jsxs26(
2209
2334
  "a",
2210
2335
  {
2211
2336
  href,
@@ -2220,9 +2345,9 @@ function NavItem({ label, href, count, countLabel, active = false, icon, classNa
2220
2345
  ),
2221
2346
  ...props,
2222
2347
  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
2348
+ icon && /* @__PURE__ */ jsx38("span", { className: "flex shrink-0 items-center", children: icon }),
2349
+ /* @__PURE__ */ jsx38("span", { className: "flex-1 truncate", children: label }),
2350
+ 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
2351
  ]
2227
2352
  }
2228
2353
  );
@@ -2231,7 +2356,7 @@ function NavItem({ label, href, count, countLabel, active = false, icon, classNa
2231
2356
  // src/Popover.tsx
2232
2357
  import { useMemo as useMemo3 } from "react";
2233
2358
  import { Popover as BasePopover } from "@base-ui/react/popover";
2234
- import { jsx as jsx37, jsxs as jsxs26 } from "react/jsx-runtime";
2359
+ import { jsx as jsx39, jsxs as jsxs27 } from "react/jsx-runtime";
2235
2360
  var GAP5 = 4;
2236
2361
  var VIEWPORT_PAD5 = 8;
2237
2362
  function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpenChange, finalFocus, actionsRef, ariaLabel, children, className, contentClassName, maxHeight }) {
@@ -2240,7 +2365,7 @@ function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpe
2240
2365
  if (anchor instanceof Element) return anchor;
2241
2366
  return { getBoundingClientRect: () => anchor };
2242
2367
  }, [anchor]);
2243
- return /* @__PURE__ */ jsxs26(
2368
+ return /* @__PURE__ */ jsxs27(
2244
2369
  BasePopover.Root,
2245
2370
  {
2246
2371
  open,
@@ -2248,8 +2373,8 @@ function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpe
2248
2373
  actionsRef,
2249
2374
  modal: false,
2250
2375
  children: [
2251
- trigger && /* @__PURE__ */ jsx37(BasePopover.Trigger, { render: trigger, disabled: triggerDisabled(trigger) }),
2252
- /* @__PURE__ */ jsx37(BasePopover.Portal, { children: /* @__PURE__ */ jsx37(
2376
+ trigger && /* @__PURE__ */ jsx39(BasePopover.Trigger, { render: trigger, disabled: triggerDisabled(trigger) }),
2377
+ /* @__PURE__ */ jsx39(BasePopover.Portal, { children: /* @__PURE__ */ jsx39(
2253
2378
  BasePopover.Positioner,
2254
2379
  {
2255
2380
  anchor: anchorTarget,
@@ -2258,15 +2383,15 @@ function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpe
2258
2383
  sideOffset: GAP5,
2259
2384
  collisionPadding: VIEWPORT_PAD5,
2260
2385
  className: "z-50 data-[anchor-hidden]:hidden",
2261
- children: /* @__PURE__ */ jsx37(
2386
+ children: /* @__PURE__ */ jsx39(
2262
2387
  BasePopover.Popup,
2263
2388
  {
2264
2389
  "aria-label": ariaLabel,
2265
2390
  initialFocus: trigger ? void 0 : false,
2266
2391
  finalFocus,
2267
2392
  className: cn("min-w-[180px] outline-none p-0", className),
2268
- render: /* @__PURE__ */ jsx37(MenuPanel, {}),
2269
- children: /* @__PURE__ */ jsx37(
2393
+ render: /* @__PURE__ */ jsx39(MenuPanel, {}),
2394
+ children: /* @__PURE__ */ jsx39(
2270
2395
  ScrollArea,
2271
2396
  {
2272
2397
  viewportClassName: maxHeight ?? "max-h-[var(--available-height)]",
@@ -2285,9 +2410,9 @@ function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpe
2285
2410
 
2286
2411
  // src/Toolbar.tsx
2287
2412
  import { Toolbar as BaseToolbar } from "@base-ui/react/toolbar";
2288
- import { jsx as jsx38 } from "react/jsx-runtime";
2413
+ import { jsx as jsx40 } from "react/jsx-runtime";
2289
2414
  function Toolbar({ "aria-label": ariaLabel, orientation = "horizontal", loopFocus = true, surface = true, children, className }) {
2290
- const strip = /* @__PURE__ */ jsx38(
2415
+ const strip = /* @__PURE__ */ jsx40(
2291
2416
  BaseToolbar.Root,
2292
2417
  {
2293
2418
  "aria-label": ariaLabel,
@@ -2298,24 +2423,24 @@ function Toolbar({ "aria-label": ariaLabel, orientation = "horizontal", loopFocu
2298
2423
  }
2299
2424
  );
2300
2425
  if (!surface) return strip;
2301
- return /* @__PURE__ */ jsx38(MenuPanel, { className: "w-fit p-1", children: strip });
2426
+ return /* @__PURE__ */ jsx40(MenuPanel, { className: "w-fit p-1", children: strip });
2302
2427
  }
2303
2428
  function ToolbarButton({ ref, disabled, disabledReason, ...props }) {
2304
- return /* @__PURE__ */ jsx38(
2429
+ return /* @__PURE__ */ jsx40(
2305
2430
  BaseToolbar.Button,
2306
2431
  {
2307
2432
  ref,
2308
2433
  disabled: disabled || !!disabledReason,
2309
2434
  focusableWhenDisabled: true,
2310
- render: /* @__PURE__ */ jsx38(IconButton, { disabled, disabledReason, ...props })
2435
+ render: /* @__PURE__ */ jsx40(IconButton, { disabled, disabledReason, ...props })
2311
2436
  }
2312
2437
  );
2313
2438
  }
2314
2439
  function ToolbarInput({ size, ...props }) {
2315
- return /* @__PURE__ */ jsx38(BaseToolbar.Input, { render: /* @__PURE__ */ jsx38(TextInput, { size }), ...props });
2440
+ return /* @__PURE__ */ jsx40(BaseToolbar.Input, { render: /* @__PURE__ */ jsx40(TextInput, { size }), ...props });
2316
2441
  }
2317
2442
  function ToolbarSeparator({ className }) {
2318
- return /* @__PURE__ */ jsx38(
2443
+ return /* @__PURE__ */ jsx40(
2319
2444
  BaseToolbar.Separator,
2320
2445
  {
2321
2446
  orientation: "vertical",
@@ -2325,9 +2450,9 @@ function ToolbarSeparator({ className }) {
2325
2450
  }
2326
2451
 
2327
2452
  // src/ReactionPicker.tsx
2328
- import { jsx as jsx39 } from "react/jsx-runtime";
2453
+ import { jsx as jsx41 } from "react/jsx-runtime";
2329
2454
  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) => (
2455
+ return /* @__PURE__ */ jsx41(Toolbar, { "aria-label": ariaLabel, surface, className: cn("gap-0.5", className), children: options.map((option) => (
2331
2456
  /*
2332
2457
  A `ToolbarButton`, not a button in a tooltip wrapper. The wrapper
2333
2458
  would become the toolbar's item and the button inside it would never
@@ -2337,14 +2462,14 @@ function ReactionPicker({ options, onSelect, "aria-label": ariaLabel = "Reaction
2337
2462
  The tooltip names it for a pointer, `aria-label` for everything else,
2338
2463
  and both say the meaning rather than the glyph.
2339
2464
  */
2340
- /* @__PURE__ */ jsx39(
2465
+ /* @__PURE__ */ jsx41(
2341
2466
  ToolbarButton,
2342
2467
  {
2343
2468
  "aria-label": option.label,
2344
2469
  tooltip: option.label,
2345
2470
  onClick: () => onSelect(option.emoji),
2346
2471
  className: "size-7 text-h3 leading-none",
2347
- children: /* @__PURE__ */ jsx39("span", { "aria-hidden": "true", children: option.emoji })
2472
+ children: /* @__PURE__ */ jsx41("span", { "aria-hidden": "true", children: option.emoji })
2348
2473
  },
2349
2474
  option.emoji
2350
2475
  )
@@ -2353,23 +2478,23 @@ function ReactionPicker({ options, onSelect, "aria-label": ariaLabel = "Reaction
2353
2478
 
2354
2479
  // src/PreviewCard.tsx
2355
2480
  import { PreviewCard as BasePreviewCard } from "@base-ui/react/preview-card";
2356
- import { jsx as jsx40, jsxs as jsxs27 } from "react/jsx-runtime";
2481
+ import { jsx as jsx42, jsxs as jsxs28 } from "react/jsx-runtime";
2357
2482
  var GAP6 = 12;
2358
2483
  var VIEWPORT_PAD6 = 8;
2359
2484
  var OPEN_DELAY2 = 350;
2360
2485
  var CLOSE_DELAY = 200;
2361
2486
  function PreviewCard({ content, children, side = "right", delay = OPEN_DELAY2, closeDelay = CLOSE_DELAY, className, wrapperClassName }) {
2362
- return /* @__PURE__ */ jsxs27(BasePreviewCard.Root, { children: [
2363
- /* @__PURE__ */ jsx40(
2487
+ return /* @__PURE__ */ jsxs28(BasePreviewCard.Root, { children: [
2488
+ /* @__PURE__ */ jsx42(
2364
2489
  BasePreviewCard.Trigger,
2365
2490
  {
2366
2491
  delay,
2367
2492
  closeDelay,
2368
- render: /* @__PURE__ */ jsx40("span", { className: cn("inline-flex", wrapperClassName) }),
2493
+ render: /* @__PURE__ */ jsx42("span", { className: cn("inline-flex", wrapperClassName) }),
2369
2494
  children
2370
2495
  }
2371
2496
  ),
2372
- /* @__PURE__ */ jsx40(BasePreviewCard.Portal, { children: /* @__PURE__ */ jsx40(
2497
+ /* @__PURE__ */ jsx42(BasePreviewCard.Portal, { children: /* @__PURE__ */ jsx42(
2373
2498
  BasePreviewCard.Positioner,
2374
2499
  {
2375
2500
  side,
@@ -2377,12 +2502,12 @@ function PreviewCard({ content, children, side = "right", delay = OPEN_DELAY2, c
2377
2502
  sideOffset: GAP6,
2378
2503
  collisionPadding: VIEWPORT_PAD6,
2379
2504
  className: "z-50 data-[anchor-hidden]:hidden",
2380
- children: /* @__PURE__ */ jsx40(
2505
+ children: /* @__PURE__ */ jsx42(
2381
2506
  BasePreviewCard.Popup,
2382
2507
  {
2383
2508
  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 })
2509
+ render: /* @__PURE__ */ jsx42(MenuPanel, {}),
2510
+ 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
2511
  }
2387
2512
  )
2388
2513
  }
@@ -2391,15 +2516,15 @@ function PreviewCard({ content, children, side = "right", delay = OPEN_DELAY2, c
2391
2516
  }
2392
2517
 
2393
2518
  // src/Rail.tsx
2394
- import { jsx as jsx41 } from "react/jsx-runtime";
2519
+ import { jsx as jsx43 } from "react/jsx-runtime";
2395
2520
  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 });
2521
+ 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
2522
  }
2398
2523
 
2399
2524
  // src/RailItem.tsx
2400
- import { jsx as jsx42, jsxs as jsxs28 } from "react/jsx-runtime";
2525
+ import { jsx as jsx44, jsxs as jsxs29 } from "react/jsx-runtime";
2401
2526
  function RailItem({ href, icon, label, active = false, className, ...props }) {
2402
- return /* @__PURE__ */ jsxs28(
2527
+ return /* @__PURE__ */ jsxs29(
2403
2528
  "a",
2404
2529
  {
2405
2530
  href,
@@ -2407,14 +2532,14 @@ function RailItem({ href, icon, label, active = false, className, ...props }) {
2407
2532
  className: cn("group flex w-full shrink-0 flex-col items-center gap-0.5 px-2 py-0.5", className),
2408
2533
  ...props,
2409
2534
  children: [
2410
- /* @__PURE__ */ jsx42(
2535
+ /* @__PURE__ */ jsx44(
2411
2536
  "div",
2412
2537
  {
2413
2538
  className: cn(
2414
2539
  "flex items-center justify-center rounded-lg p-2 transition-colors",
2415
2540
  active ? "bg-bg-selected" : "group-hover:bg-bg-hover"
2416
2541
  ),
2417
- children: /* @__PURE__ */ jsx42(
2542
+ children: /* @__PURE__ */ jsx44(
2418
2543
  "span",
2419
2544
  {
2420
2545
  className: cn(
@@ -2426,27 +2551,27 @@ function RailItem({ href, icon, label, active = false, className, ...props }) {
2426
2551
  )
2427
2552
  }
2428
2553
  ),
2429
- /* @__PURE__ */ jsx42("span", { className: cn("text-center text-menu", active ? "text-text-primary" : "text-text-secondary"), children: label })
2554
+ /* @__PURE__ */ jsx44("span", { className: cn("text-center text-menu", active ? "text-text-primary" : "text-text-secondary"), children: label })
2430
2555
  ]
2431
2556
  }
2432
2557
  );
2433
2558
  }
2434
2559
 
2435
2560
  // src/Sidebar.tsx
2436
- import { jsx as jsx43 } from "react/jsx-runtime";
2561
+ import { jsx as jsx45 } from "react/jsx-runtime";
2437
2562
  function Sidebar({ "aria-label": ariaLabel = "Workspace", children, className }) {
2438
- return /* @__PURE__ */ jsx43(
2563
+ return /* @__PURE__ */ jsx45(
2439
2564
  "nav",
2440
2565
  {
2441
2566
  "aria-label": ariaLabel,
2442
2567
  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 })
2568
+ children: /* @__PURE__ */ jsx45(ScrollArea, { className: "min-h-0 flex-1", contentClassName: "flex flex-col gap-px px-2.5 py-3", children })
2444
2569
  }
2445
2570
  );
2446
2571
  }
2447
2572
 
2448
2573
  // src/Property.tsx
2449
- import { jsx as jsx44, jsxs as jsxs29 } from "react/jsx-runtime";
2574
+ import { jsx as jsx46, jsxs as jsxs30 } from "react/jsx-runtime";
2450
2575
  var VALUE_CLASSES = "contents";
2451
2576
  function Property({ label, layout = "row", children, className }) {
2452
2577
  if (layout === "stacked") {
@@ -2454,23 +2579,23 @@ function Property({ label, layout = "row", children, className }) {
2454
2579
  // gap-3 — the one label-above-content distance (Katerina, 2026-09-01):
2455
2580
  // Peek's topic-details sections already sit at 12px, Ship's rail was
2456
2581
  // 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 })
2582
+ /* @__PURE__ */ jsxs30("dl", { className: cn("flex flex-col gap-3", className), children: [
2583
+ /* @__PURE__ */ jsx46("dt", { className: "text-menu uppercase tracking-widest text-text-secondary", children: label }),
2584
+ /* @__PURE__ */ jsx46("dd", { className: VALUE_CLASSES, children })
2460
2585
  ] })
2461
2586
  );
2462
2587
  }
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 })
2588
+ return /* @__PURE__ */ jsxs30("dl", { className: cn("flex items-center gap-2", className), children: [
2589
+ /* @__PURE__ */ jsx46("dt", { className: "w-[68px] shrink-0 text-caption text-text-secondary", children: label }),
2590
+ /* @__PURE__ */ jsx46("dd", { className: VALUE_CLASSES, children })
2466
2591
  ] });
2467
2592
  }
2468
2593
 
2469
2594
  // src/Reaction.tsx
2470
2595
  import { Toggle } from "@base-ui/react/toggle";
2471
- import { jsx as jsx45, jsxs as jsxs30 } from "react/jsx-runtime";
2596
+ import { jsx as jsx47, jsxs as jsxs31 } from "react/jsx-runtime";
2472
2597
  function Reaction({ emoji, count, pressed = false, className, ...props }) {
2473
- return /* @__PURE__ */ jsxs30(
2598
+ return /* @__PURE__ */ jsxs31(
2474
2599
  Toggle,
2475
2600
  {
2476
2601
  pressed,
@@ -2492,8 +2617,8 @@ function Reaction({ emoji, count, pressed = false, className, ...props }) {
2492
2617
  ),
2493
2618
  ...props,
2494
2619
  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 })
2620
+ /* @__PURE__ */ jsx47("span", { "aria-hidden": "true", className: "shrink-0 text-body-1 leading-none", children: emoji }),
2621
+ /* @__PURE__ */ jsx47("span", { className: "text-chip signal:font-mono signal:text-small signal:font-semibold signal:tabular-nums", children: count })
2497
2622
  ]
2498
2623
  }
2499
2624
  );
@@ -2502,19 +2627,21 @@ function Reaction({ emoji, count, pressed = false, className, ...props }) {
2502
2627
  // src/SearchInput.tsx
2503
2628
  import "react";
2504
2629
  import { Input as Input3 } from "@base-ui/react/input";
2505
- import { jsx as jsx46, jsxs as jsxs31 } from "react/jsx-runtime";
2630
+ import { jsx as jsx48, jsxs as jsxs32 } from "react/jsx-runtime";
2506
2631
  function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...props }) {
2507
- return /* @__PURE__ */ jsxs31(
2632
+ return /* @__PURE__ */ jsxs32(
2508
2633
  "div",
2509
2634
  {
2510
2635
  className: cn(
2511
2636
  "flex gap-2 items-center px-3 py-2 rounded-lg",
2512
2637
  "bg-bg-inset border border-border-default",
2513
- "focus-within:border-border-strong transition-colors",
2638
+ // Hover strengthens the border as it does on every other field (16 September). Here that
2639
+ // is also the focus look, which was the stronger border before hover existed.
2640
+ "hover:border-border-strong focus-within:border-border-strong transition-colors",
2514
2641
  className
2515
2642
  ),
2516
2643
  children: [
2517
- /* @__PURE__ */ jsx46(
2644
+ /* @__PURE__ */ jsx48(
2518
2645
  Input3,
2519
2646
  {
2520
2647
  className: "flex-1 min-w-0 bg-transparent text-input-value text-text-primary placeholder:text-text-muted outline-none",
@@ -2522,7 +2649,7 @@ function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...pro
2522
2649
  ...props
2523
2650
  }
2524
2651
  ),
2525
- shortcut && /* @__PURE__ */ jsx46(Kbd, { children: shortcut })
2652
+ shortcut && /* @__PURE__ */ jsx48(Kbd, { children: shortcut })
2526
2653
  ]
2527
2654
  }
2528
2655
  );
@@ -2531,17 +2658,17 @@ function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...pro
2531
2658
  // src/SectionHeader.tsx
2532
2659
  import { IconChevronRight as IconChevronRight2 } from "@tabler/icons-react";
2533
2660
  import { useRender } from "@base-ui/react/use-render";
2534
- import { Fragment as Fragment8, jsx as jsx47, jsxs as jsxs32 } from "react/jsx-runtime";
2661
+ import { Fragment as Fragment8, jsx as jsx49, jsxs as jsxs33 } from "react/jsx-runtime";
2535
2662
  function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, trailing, actions, showActions = "hover", render, className }) {
2536
2663
  const titleElement = useRender({
2537
- render: render ?? (chevron ? /* @__PURE__ */ jsx47("button", { type: "button", onClick: onToggle, "aria-expanded": isExpanded }) : /* @__PURE__ */ jsx47("span", {})),
2664
+ render: render ?? (chevron ? /* @__PURE__ */ jsx49("button", { type: "button", onClick: onToggle, "aria-expanded": isExpanded }) : /* @__PURE__ */ jsx49("span", {})),
2538
2665
  props: {
2539
2666
  // `text-left`: a button centres its text. `h-full` and `flex-1`: the
2540
2667
  // whole row up to the actions is the hit target, as it was when the
2541
2668
  // row itself carried the click.
2542
2669
  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(
2670
+ children: /* @__PURE__ */ jsxs33(Fragment8, { children: [
2671
+ chevron && /* @__PURE__ */ jsx49(
2545
2672
  IconChevronRight2,
2546
2673
  {
2547
2674
  size: 12,
@@ -2549,11 +2676,11 @@ function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, tr
2549
2676
  className: cn("shrink-0 text-text-secondary transition-transform duration-150", isExpanded && "rotate-90")
2550
2677
  }
2551
2678
  ),
2552
- /* @__PURE__ */ jsx47(SectionLabel, { children: title })
2679
+ /* @__PURE__ */ jsx49(SectionLabel, { children: title })
2553
2680
  ] })
2554
2681
  }
2555
2682
  });
2556
- return /* @__PURE__ */ jsxs32(
2683
+ return /* @__PURE__ */ jsxs33(
2557
2684
  "div",
2558
2685
  {
2559
2686
  className: cn(
@@ -2566,15 +2693,15 @@ function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, tr
2566
2693
  ),
2567
2694
  children: [
2568
2695
  titleElement,
2569
- trailing != null && /* @__PURE__ */ jsx47("div", { className: "flex shrink-0 items-center", children: trailing }),
2570
- actions && actions.length > 0 && /* @__PURE__ */ jsx47(
2696
+ trailing != null && /* @__PURE__ */ jsx49("div", { className: "flex shrink-0 items-center", children: trailing }),
2697
+ actions && actions.length > 0 && /* @__PURE__ */ jsx49(
2571
2698
  "div",
2572
2699
  {
2573
2700
  className: cn(
2574
2701
  "-mr-1 flex shrink-0 items-center gap-1",
2575
2702
  showActions === "hover" && "opacity-0 transition-opacity focus-within:opacity-100 group-hover:opacity-100"
2576
2703
  ),
2577
- children: actions.map((action) => /* @__PURE__ */ jsx47(IconButton, { tooltip: action.tooltip, "aria-label": action.tooltip, onClick: action.onClick, children: action.icon }, action.tooltip))
2704
+ children: actions.map((action) => /* @__PURE__ */ jsx49(IconButton, { tooltip: action.tooltip, "aria-label": action.tooltip, onClick: action.onClick, children: action.icon }, action.tooltip))
2578
2705
  }
2579
2706
  )
2580
2707
  ]
@@ -2585,7 +2712,7 @@ function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, tr
2585
2712
  // src/CollapsibleSection.tsx
2586
2713
  import { useState as useState7 } from "react";
2587
2714
  import { Collapsible } from "@base-ui/react/collapsible";
2588
- import { jsx as jsx48, jsxs as jsxs33 } from "react/jsx-runtime";
2715
+ import { jsx as jsx50, jsxs as jsxs34 } from "react/jsx-runtime";
2589
2716
  var OPEN = "open";
2590
2717
  var CLOSED = "closed";
2591
2718
  function readStored(key) {
@@ -2612,14 +2739,14 @@ function CollapsibleSection({ title, defaultOpen = true, open: openProp, onOpenC
2612
2739
  writeStored(storageKey, next);
2613
2740
  onOpenChange?.(next);
2614
2741
  };
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(
2742
+ return /* @__PURE__ */ jsxs34(Collapsible.Root, { open, onOpenChange: setOpen, className: cn("flex flex-col", className), children: [
2743
+ /* @__PURE__ */ jsx50(SectionHeader, { title, chevron: true, isExpanded: open, trailing, actions, showActions, className: "shrink-0", render: /* @__PURE__ */ jsx50(Collapsible.Trigger, {}) }),
2744
+ /* @__PURE__ */ jsx50(
2618
2745
  Collapsible.Panel,
2619
2746
  {
2620
2747
  hiddenUntilFound: true,
2621
2748
  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 })
2749
+ children: /* @__PURE__ */ jsx50("div", { className: cn("flex flex-col", contentClassName), children })
2623
2750
  }
2624
2751
  )
2625
2752
  ] });
@@ -2627,9 +2754,9 @@ function CollapsibleSection({ title, defaultOpen = true, open: openProp, onOpenC
2627
2754
 
2628
2755
  // src/Tabs.tsx
2629
2756
  import { Tabs as BaseTabs } from "@base-ui/react/tabs";
2630
- import { jsx as jsx49, jsxs as jsxs34 } from "react/jsx-runtime";
2757
+ import { jsx as jsx51, jsxs as jsxs35 } from "react/jsx-runtime";
2631
2758
  function Tabs({ tabs, active, onChange, size = "default", className, ...aria }) {
2632
- return /* @__PURE__ */ jsx49(
2759
+ return /* @__PURE__ */ jsx51(
2633
2760
  BaseTabs.Root,
2634
2761
  {
2635
2762
  value: active,
@@ -2637,14 +2764,14 @@ function Tabs({ tabs, active, onChange, size = "default", className, ...aria })
2637
2764
  if (details.reason === "none") onChange(value);
2638
2765
  },
2639
2766
  className,
2640
- children: /* @__PURE__ */ jsx49(
2767
+ children: /* @__PURE__ */ jsx51(
2641
2768
  BaseTabs.List,
2642
2769
  {
2643
2770
  activateOnFocus: true,
2644
2771
  "aria-label": aria["aria-label"],
2645
2772
  "aria-labelledby": aria["aria-labelledby"],
2646
2773
  className: "flex items-center gap-2",
2647
- children: tabs.map((tab) => /* @__PURE__ */ jsxs34(
2774
+ children: tabs.map((tab) => /* @__PURE__ */ jsxs35(
2648
2775
  BaseTabs.Tab,
2649
2776
  {
2650
2777
  value: tab.id,
@@ -2657,9 +2784,9 @@ function Tabs({ tabs, active, onChange, size = "default", className, ...aria })
2657
2784
  ),
2658
2785
  children: [
2659
2786
  tab.icon,
2660
- /* @__PURE__ */ jsxs34("span", { className: "flex items-baseline", children: [
2787
+ /* @__PURE__ */ jsxs35("span", { className: "flex items-baseline", children: [
2661
2788
  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
2789
+ 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
2790
  ] })
2664
2791
  ]
2665
2792
  },
@@ -2672,10 +2799,10 @@ function Tabs({ tabs, active, onChange, size = "default", className, ...aria })
2672
2799
  }
2673
2800
 
2674
2801
  // src/Toast.tsx
2675
- import { createContext as createContext3, useContext as useContext3, useMemo as useMemo4 } from "react";
2802
+ import { createContext as createContext4, useContext as useContext4, useMemo as useMemo4 } from "react";
2676
2803
  import { Toast as BaseToast } from "@base-ui/react/toast";
2677
2804
  import { IconAlertCircle as IconAlertCircle2, IconCircleCheck, IconCircleX } from "@tabler/icons-react";
2678
- import { jsx as jsx50, jsxs as jsxs35 } from "react/jsx-runtime";
2805
+ import { jsx as jsx52, jsxs as jsxs36 } from "react/jsx-runtime";
2679
2806
  var SURFACE_STYLES = {
2680
2807
  success: "bg-success-muted signal:bg-bg-inset signal:border signal:border-border-default signal:shadow-md",
2681
2808
  brand: "bg-accent-muted signal:bg-bg-inset signal:border signal:border-border-default signal:shadow-md",
@@ -2711,19 +2838,19 @@ var pillClassName = (type, hasAction, className) => cn(
2711
2838
  );
2712
2839
  function LeadingIcon({ type }) {
2713
2840
  const Icon = ICONS[type];
2714
- return /* @__PURE__ */ jsx50(Icon, { size: 16, stroke: 1.5, className: cn("text-text-primary shrink-0", ICON_STYLES[type]) });
2841
+ return /* @__PURE__ */ jsx52(Icon, { size: 16, stroke: 1.5, className: cn("text-text-primary shrink-0", ICON_STYLES[type]) });
2715
2842
  }
2716
2843
  function Toast({ label, type = "neutral", leadingIcon = true, actionLabel, onAction, className }) {
2717
2844
  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 })
2845
+ return /* @__PURE__ */ jsxs36("div", { className: pillClassName(type, hasAction, className), children: [
2846
+ /* @__PURE__ */ jsxs36("div", { className: "flex items-center gap-2 shrink-0", children: [
2847
+ leadingIcon && /* @__PURE__ */ jsx52(LeadingIcon, { type }),
2848
+ /* @__PURE__ */ jsx52("span", { className: LABEL_CLASSES, children: label })
2722
2849
  ] }),
2723
- hasAction && /* @__PURE__ */ jsx50(Button, { variant: "outlined", size: "small", onClick: onAction, children: actionLabel })
2850
+ hasAction && /* @__PURE__ */ jsx52(Button, { variant: "outlined", size: "small", onClick: onAction, children: actionLabel })
2724
2851
  ] });
2725
2852
  }
2726
- var ToastContext = createContext3(null);
2853
+ var ToastContext = createContext4(null);
2727
2854
  var VISIBLE_TOASTS = 3;
2728
2855
  function ToastProvider({ children }) {
2729
2856
  const manager = useMemo4(() => BaseToast.createToastManager(), []);
@@ -2741,9 +2868,9 @@ function ToastProvider({ children }) {
2741
2868
  }),
2742
2869
  [manager]
2743
2870
  );
2744
- return /* @__PURE__ */ jsx50(ToastContext.Provider, { value, children: /* @__PURE__ */ jsxs35(BaseToast.Provider, { toastManager: manager, limit: VISIBLE_TOASTS, children: [
2871
+ return /* @__PURE__ */ jsx52(ToastContext.Provider, { value, children: /* @__PURE__ */ jsxs36(BaseToast.Provider, { toastManager: manager, limit: VISIBLE_TOASTS, children: [
2745
2872
  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, {}) }) })
2873
+ /* @__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
2874
  ] }) });
2748
2875
  }
2749
2876
  function ToastList() {
@@ -2751,25 +2878,25 @@ function ToastList() {
2751
2878
  return toasts.map((toast) => {
2752
2879
  const type = toast.type ?? "neutral";
2753
2880
  const { leadingIcon = true, actionLabel, onAction } = toast.data ?? {};
2754
- return /* @__PURE__ */ jsxs35(
2881
+ return /* @__PURE__ */ jsxs36(
2755
2882
  BaseToast.Root,
2756
2883
  {
2757
2884
  toast,
2758
2885
  swipeDirection: ["left", "down"],
2759
2886
  className: pillClassName(type, !!actionLabel, "pointer-events-auto data-[limited]:hidden"),
2760
2887
  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 })
2888
+ /* @__PURE__ */ jsxs36("div", { className: "flex items-center gap-2 shrink-0", children: [
2889
+ leadingIcon && /* @__PURE__ */ jsx52(LeadingIcon, { type }),
2890
+ /* @__PURE__ */ jsx52(BaseToast.Title, { render: /* @__PURE__ */ jsx52("span", {}), className: LABEL_CLASSES })
2764
2891
  ] }),
2765
- actionLabel && /* @__PURE__ */ jsx50(
2892
+ actionLabel && /* @__PURE__ */ jsx52(
2766
2893
  BaseToast.Action,
2767
2894
  {
2768
2895
  onClick: () => {
2769
2896
  onAction?.();
2770
2897
  close(toast.id);
2771
2898
  },
2772
- render: /* @__PURE__ */ jsx50(Button, { variant: "outlined", size: "small", children: actionLabel })
2899
+ render: /* @__PURE__ */ jsx52(Button, { variant: "outlined", size: "small", children: actionLabel })
2773
2900
  }
2774
2901
  )
2775
2902
  ]
@@ -2779,7 +2906,7 @@ function ToastList() {
2779
2906
  });
2780
2907
  }
2781
2908
  function useToast() {
2782
- const ctx = useContext3(ToastContext);
2909
+ const ctx = useContext4(ToastContext);
2783
2910
  if (!ctx) throw new Error("useToast must be used within ToastProvider");
2784
2911
  return ctx;
2785
2912
  }
@@ -2810,6 +2937,8 @@ export {
2810
2937
  EnterHint,
2811
2938
  Field,
2812
2939
  FieldLine,
2940
+ FilePicker,
2941
+ Form,
2813
2942
  INLINE_CHIP_CLASSES,
2814
2943
  INLINE_CHIP_TONE_CLASSES,
2815
2944
  IconButton,