@estiva-app/ui 0.16.0 → 0.17.0

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