@estiva-app/ui 0.13.0 → 0.14.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 (76) hide show
  1. package/dist/Avatar.d.ts +1 -1
  2. package/dist/Avatar.d.ts.map +1 -1
  3. package/dist/AvatarGroup.d.ts.map +1 -1
  4. package/dist/Card.d.ts +7 -1
  5. package/dist/Card.d.ts.map +1 -1
  6. package/dist/Divider.d.ts +5 -2
  7. package/dist/Divider.d.ts.map +1 -1
  8. package/dist/EmptyState.d.ts +3 -0
  9. package/dist/EmptyState.d.ts.map +1 -1
  10. package/dist/Property.d.ts +7 -0
  11. package/dist/Property.d.ts.map +1 -1
  12. package/dist/Reaction.d.ts +12 -6
  13. package/dist/Reaction.d.ts.map +1 -1
  14. package/dist/TextInput.d.ts +10 -1
  15. package/dist/TextInput.d.ts.map +1 -1
  16. package/dist/Toast.d.ts +19 -6
  17. package/dist/Toast.d.ts.map +1 -1
  18. package/dist/Toolbar.d.ts +1 -1
  19. package/dist/Toolbar.d.ts.map +1 -1
  20. package/dist/index.js +283 -246
  21. package/dist/index.js.map +3 -3
  22. package/package.json +1 -1
  23. package/src/AttachmentCard.tsx +14 -14
  24. package/src/Avatar.mdx +7 -2
  25. package/src/Avatar.picture.test.tsx +60 -0
  26. package/src/Avatar.stories.tsx +1 -1
  27. package/src/Avatar.tsx +50 -14
  28. package/src/AvatarGroup.tsx +1 -0
  29. package/src/Breadcrumb.tsx +2 -2
  30. package/src/Card.mdx +9 -3
  31. package/src/Card.stories.tsx +3 -0
  32. package/src/Card.test.tsx +41 -0
  33. package/src/Card.tsx +19 -1
  34. package/src/Checkbox.tsx +1 -1
  35. package/src/Chip.tsx +1 -1
  36. package/src/DialogShell.stories.tsx +1 -1
  37. package/src/Divider.mdx +3 -2
  38. package/src/Divider.test.tsx +15 -0
  39. package/src/Divider.tsx +11 -9
  40. package/src/EditableText.stories.tsx +2 -2
  41. package/src/EmptyState.mdx +3 -2
  42. package/src/EmptyState.stories.tsx +7 -3
  43. package/src/EmptyState.test.tsx +15 -0
  44. package/src/EmptyState.tsx +4 -1
  45. package/src/IconButton.stories.tsx +1 -1
  46. package/src/Kbd.tsx +3 -3
  47. package/src/Menu.stories.tsx +2 -2
  48. package/src/Menu.tsx +3 -3
  49. package/src/Popover.stories.tsx +1 -1
  50. package/src/PreviewCard.stories.tsx +5 -5
  51. package/src/Property.mdx +8 -0
  52. package/src/Property.stories.tsx +4 -4
  53. package/src/Property.test.tsx +44 -0
  54. package/src/Property.tsx +23 -8
  55. package/src/RailItem.tsx +1 -1
  56. package/src/Reaction.mdx +14 -3
  57. package/src/Reaction.test.tsx +62 -0
  58. package/src/Reaction.tsx +21 -12
  59. package/src/ReactionPicker.tsx +1 -1
  60. package/src/SectionLabel.stories.tsx +1 -1
  61. package/src/SectionLabel.tsx +1 -1
  62. package/src/Select.tsx +3 -3
  63. package/src/TextInput.mdx +6 -0
  64. package/src/TextInput.stories.tsx +45 -0
  65. package/src/TextInput.test.tsx +38 -0
  66. package/src/TextInput.tsx +16 -4
  67. package/src/Textarea.tsx +1 -1
  68. package/src/Toast.mdx +28 -4
  69. package/src/Toast.stories.tsx +12 -1
  70. package/src/Toast.test.tsx +137 -0
  71. package/src/Toast.tsx +127 -83
  72. package/src/Toolbar.tsx +4 -2
  73. package/src/cn.ts +1 -1
  74. package/stories/Choosing.mdx +1 -0
  75. package/stories/TokensPage.tsx +6 -1
  76. package/tailwind-preset.js +7 -0
package/dist/index.js CHANGED
@@ -17,7 +17,8 @@ var FONT_SIZE_TOKENS = [
17
17
  "input-label",
18
18
  "input-value",
19
19
  "input-helper",
20
- "chip"
20
+ "chip",
21
+ "small"
21
22
  ];
22
23
  var BOX_SHADOW_TOKENS = ["sm", "md", "lg", "focus-ring", "glow-warning", "glow-success", "glow-accent", "highlight-inset"];
23
24
  var DROP_SHADOW_TOKENS = ["glow-success", "glow-accent", "glow-warning"];
@@ -189,6 +190,12 @@ var HAIRLINE_HOVER_CLASSES = {
189
190
  inset: "hover:border-border-default",
190
191
  none: "hover:border-border-default"
191
192
  };
193
+ var HAIRLINE_HELD_CLASSES = {
194
+ surface: "border-border-strong",
195
+ elevated: "border-border-strong",
196
+ inset: "border-border-default",
197
+ none: "border-border-default"
198
+ };
192
199
  var ATTENTION_CLASSES = {
193
200
  accent: "border-accent-muted hover:border-accent-muted",
194
201
  warning: "border-warning-muted hover:border-warning-muted"
@@ -198,6 +205,7 @@ function Card({
198
205
  href,
199
206
  hover = href ? "hairline" : "none",
200
207
  quietUntilHover = false,
208
+ hovered = false,
201
209
  selected = false,
202
210
  active = false,
203
211
  attention,
@@ -215,7 +223,10 @@ function Card({
215
223
  quietUntilHover && "border-transparent",
216
224
  !still && hover === "hairline" && HAIRLINE_HOVER_CLASSES[fill],
217
225
  !still && hover === "fill" && "hover:bg-bg-hover hover:border-border-default",
218
- !still && hover !== "none" && !href && props.onClick && "cursor-pointer",
226
+ !still && hovered && hover === "hairline" && HAIRLINE_HELD_CLASSES[fill],
227
+ !still && hovered && hover === "fill" && "bg-bg-hover border-border-default",
228
+ // The one you are on can still be clicked (it opens again); the one being changed cannot.
229
+ !active && hover !== "none" && !href && props.onClick && "cursor-pointer",
219
230
  selected && "bg-bg-selected border-border-subtle",
220
231
  active && "bg-bg-selected border-accent-primary",
221
232
  !active && attention && ATTENTION_CLASSES[attention],
@@ -243,9 +254,9 @@ function Kbd({ children, className }) {
243
254
  "kbd",
244
255
  {
245
256
  className: cn(
246
- "inline-flex shrink-0 items-center justify-center whitespace-nowrap rounded-sm border border-border-strong bg-bg-inset px-1 py-px font-sans text-[12px] leading-[120%] font-normal text-text-secondary",
247
- "signal:border-b-2 signal:pt-[2px] signal:pb-px signal:bg-bg-wash signal:font-mono signal:text-[10px]",
248
- "ship:border-b-2 ship:pt-[2px] ship:pb-px ship:bg-bg-wash ship:font-mono ship:text-[10px]",
257
+ "inline-flex shrink-0 items-center justify-center whitespace-nowrap rounded-sm border border-border-strong bg-bg-inset px-1 py-px font-sans text-caption text-text-secondary",
258
+ "signal:border-b-2 signal:pt-[2px] signal:pb-px signal:bg-bg-wash signal:font-mono signal:text-small",
259
+ "ship:border-b-2 ship:pt-[2px] ship:pb-px ship:bg-bg-wash ship:font-mono ship:text-small",
249
260
  className
250
261
  ),
251
262
  children
@@ -400,9 +411,9 @@ var formatBytes = (bytes) => {
400
411
  return `${(kb / 1024).toFixed(1)} MB`;
401
412
  };
402
413
  var typeLabelOf = (name) => extensionOf(name).toUpperCase() || "FILE";
403
- var TILE = "size-9 rounded-md bg-bg-active flex items-center justify-center shrink-0 text-text-secondary";
404
- var NAME = "text-[12px] font-medium leading-[1.3] text-text-primary truncate";
405
- var NOTE = "text-[10px] leading-[1.2] truncate";
414
+ var TILE_CLASSES = "size-9 rounded-md bg-bg-active flex items-center justify-center shrink-0 text-text-secondary";
415
+ var NAME_CLASSES = "text-caption font-medium text-text-primary truncate";
416
+ var NOTE_CLASSES = "text-small tracking-wide leading-tight truncate";
406
417
  function TypeIcon({ name }) {
407
418
  const Icon = ICON_BY_EXTENSION[extensionOf(name)] ?? IconFile;
408
419
  return /* @__PURE__ */ jsx9(Icon, { size: 20, stroke: 1.5 });
@@ -459,15 +470,15 @@ function AttachmentCard({
459
470
  className: cn("group relative flex items-center gap-2 w-[200px] p-1.5 pr-3", failed ? "border-error-default" : warning && "border-warning-default", className),
460
471
  ...props,
461
472
  children: [
462
- /* @__PURE__ */ jsx9("div", { className: cn(TILE, "overflow-hidden"), children: state === "uploading" ? /* @__PURE__ */ jsx9(IconLoader2, { size: 16, stroke: 1.5, className: "animate-spin" }) : failed ? /* @__PURE__ */ jsx9(IconAlertCircle, { size: 16, stroke: 1.5, className: "text-error-default" }) : warning ? /* @__PURE__ */ jsx9(IconAlertTriangle, { size: 16, stroke: 1.5, className: "text-warning-default" }) : image && src ? /* @__PURE__ */ jsx9("img", { src, alt: name, className: "size-full object-cover" }) : /* @__PURE__ */ jsx9("span", { className: "text-[9px] font-semibold", children: typeLabelOf(name) }) }),
473
+ /* @__PURE__ */ jsx9("div", { className: cn(TILE_CLASSES, "overflow-hidden"), children: state === "uploading" ? /* @__PURE__ */ jsx9(IconLoader2, { size: 16, stroke: 1.5, className: "animate-spin" }) : failed ? /* @__PURE__ */ jsx9(IconAlertCircle, { size: 16, stroke: 1.5, className: "text-error-default" }) : warning ? /* @__PURE__ */ jsx9(IconAlertTriangle, { size: 16, stroke: 1.5, className: "text-warning-default" }) : image && src ? /* @__PURE__ */ jsx9("img", { src, alt: name, className: "size-full object-cover" }) : /* @__PURE__ */ jsx9("span", { className: "text-menu font-semibold", children: typeLabelOf(name) }) }),
463
474
  /* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-[1px] min-w-0", children: [
464
- /* @__PURE__ */ jsx9(Truncating, { text: name, className: NAME }),
475
+ /* @__PURE__ */ jsx9(Truncating, { text: name, className: NAME_CLASSES }),
465
476
  /* @__PURE__ */ jsx9(
466
477
  Truncating,
467
478
  {
468
479
  text: (failed || warning ? note : state === "uploading" ? note ?? "Uploading\u2026" : note ?? sizeText) ?? "",
469
480
  hint: noteHint,
470
- className: cn(NOTE, failed ? "text-error-default" : warning ? "text-warning-default" : "text-text-secondary")
481
+ className: cn(NOTE_CLASSES, failed ? "text-error-default" : warning ? "text-warning-default" : "text-text-secondary")
471
482
  }
472
483
  )
473
484
  ] }),
@@ -511,10 +522,10 @@ function AttachmentCard({
511
522
  }
512
523
  if (state === "unreadable") {
513
524
  return /* @__PURE__ */ jsxs5(Card, { fill: "inset", unreadable: true, className: cn("flex items-center gap-2 w-[240px] p-1.5 opacity-70", className), ...props, children: [
514
- /* @__PURE__ */ jsx9("div", { className: TILE, children: /* @__PURE__ */ jsx9(TypeIcon, { name }) }),
525
+ /* @__PURE__ */ jsx9("div", { className: TILE_CLASSES, children: /* @__PURE__ */ jsx9(TypeIcon, { name }) }),
515
526
  /* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-[1px] min-w-0 text-left", children: [
516
- /* @__PURE__ */ jsx9(Truncating, { text: name, className: NAME }),
517
- /* @__PURE__ */ jsx9("span", { className: cn(NOTE, "text-text-secondary"), children: note ?? "Could not be loaded" })
527
+ /* @__PURE__ */ jsx9(Truncating, { text: name, className: NAME_CLASSES }),
528
+ /* @__PURE__ */ jsx9("span", { className: cn(NOTE_CLASSES, "text-text-secondary"), children: note ?? "Could not be loaded" })
518
529
  ] })
519
530
  ] });
520
531
  }
@@ -535,16 +546,16 @@ function AttachmentCard({
535
546
  }
536
547
  ) : /* @__PURE__ */ jsx9("div", { className: "block w-full", children: picture }),
537
548
  /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-1 pl-2 pr-1 py-1 min-w-0", children: [
538
- /* @__PURE__ */ jsx9(Truncating, { text: name, className: "flex-1 text-[12px] leading-[1.3] text-text-primary truncate", wrapperClassName: "flex-1" }),
549
+ /* @__PURE__ */ jsx9(Truncating, { text: name, className: "flex-1 text-caption text-text-primary truncate", wrapperClassName: "flex-1" }),
539
550
  download
540
551
  ] })
541
552
  ] });
542
553
  }
543
554
  const body = /* @__PURE__ */ jsxs5(Fragment, { children: [
544
- /* @__PURE__ */ jsx9("div", { className: TILE, children: /* @__PURE__ */ jsx9(TypeIcon, { name }) }),
555
+ /* @__PURE__ */ jsx9("div", { className: TILE_CLASSES, children: /* @__PURE__ */ jsx9(TypeIcon, { name }) }),
545
556
  /* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-[1px] min-w-0 text-left", children: [
546
- /* @__PURE__ */ jsx9(Truncating, { text: name, className: NAME }),
547
- /* @__PURE__ */ jsx9("span", { className: cn(NOTE, "text-text-secondary"), children: note ?? `${typeLabelOf(name)} \xB7 ${sizeText}` })
557
+ /* @__PURE__ */ jsx9(Truncating, { text: name, className: NAME_CLASSES }),
558
+ /* @__PURE__ */ jsx9("span", { className: cn(NOTE_CLASSES, "text-text-secondary"), children: note ?? `${typeLabelOf(name)} \xB7 ${sizeText}` })
548
559
  ] })
549
560
  ] });
550
561
  return /* @__PURE__ */ jsxs5(Card, { fill: "inset", hover: href ? "hairline" : "none", className: cn("group flex items-center gap-2 w-[240px] p-1.5 pr-1", !href && "opacity-70", className), ...props, children: [
@@ -554,9 +565,9 @@ function AttachmentCard({
554
565
  }
555
566
 
556
567
  // src/Avatar.tsx
557
- import { useState as useState2 } from "react";
568
+ import { Avatar as BaseAvatar } from "@base-ui/react/avatar";
558
569
  import { IconUserFilled } from "@tabler/icons-react";
559
- import { jsx as jsx10 } from "react/jsx-runtime";
570
+ import { jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
560
571
  var HUES = ["#56c8ff", "#ff8f6b", "#4ade8c", "#b18cff", "#ffc94d", "#ff7eb0", "#7ea8ff", "#5fdfd6"];
561
572
  var hueFor = (key) => {
562
573
  let h = 0;
@@ -569,30 +580,45 @@ var initialsFor = (name) => {
569
580
  return initials.toUpperCase();
570
581
  };
571
582
  function Avatar({ src, name, alt = "", size = 36, label: spoken, className }) {
572
- const [broken, setBroken] = useState2(false);
573
583
  const label = name || alt;
574
- const picture = src && !broken ? src : void 0;
575
- return /* @__PURE__ */ jsx10(
576
- "div",
584
+ return /* @__PURE__ */ jsxs6(
585
+ BaseAvatar.Root,
577
586
  {
587
+ render: /* @__PURE__ */ jsx10("div", {}),
578
588
  ...spoken ? { role: "img", "aria-label": spoken } : { "aria-hidden": true },
579
589
  className: cn("rounded-sm overflow-hidden shrink-0 bg-bg-inset", className),
580
590
  style: { width: size, height: size },
581
- children: picture ? /* @__PURE__ */ jsx10("img", { src: picture, alt: "", className: "w-full h-full object-cover", onError: () => setBroken(true) }) : label ? /* @__PURE__ */ jsx10(
582
- "div",
583
- {
584
- className: "w-full h-full flex items-center justify-center font-semibold leading-none",
585
- style: {
586
- // The one ink colour that reads on all eight hues, which are a
587
- // palette rather than tokens (see the note at the top) — so its
588
- // ink cannot be a token either.
589
- color: "#08121c",
590
- fontSize: Math.round(size * 0.36),
591
- background: `linear-gradient(160deg, color-mix(in srgb, ${hueFor(label)} 92%, #fff) 0%, color-mix(in srgb, ${hueFor(label)} 70%, #0b0d11) 100%)`
592
- },
593
- children: initialsFor(label)
594
- }
595
- ) : /* @__PURE__ */ jsx10("div", { className: "w-full h-full bg-accent-muted flex items-center justify-center text-text-muted", children: /* @__PURE__ */ jsx10(IconUserFilled, { size: Math.round(size * 0.5) }) })
591
+ children: [
592
+ src && /* @__PURE__ */ jsx10(
593
+ BaseAvatar.Image,
594
+ {
595
+ src,
596
+ alt: "",
597
+ keepMounted: true,
598
+ className: "w-full h-full object-cover data-[error]:hidden"
599
+ }
600
+ ),
601
+ label ? /* @__PURE__ */ jsx10(
602
+ BaseAvatar.Fallback,
603
+ {
604
+ render: /* @__PURE__ */ jsx10("div", {}),
605
+ className: "w-full h-full flex items-center justify-center font-semibold leading-none",
606
+ style: {
607
+ /* eslint-disable no-restricted-syntax -- the per-person palette (the note at
608
+ the top): eight hues picked from the name, the one ink that reads on all
609
+ of them, and a size that follows `size`. None of it can be a token. */
610
+ // The one ink colour that reads on all eight hues, which are a
611
+ // palette rather than tokens (see the note at the top) — so its
612
+ // ink cannot be a token either.
613
+ color: "#08121c",
614
+ fontSize: Math.round(size * 0.36),
615
+ background: `linear-gradient(160deg, color-mix(in srgb, ${hueFor(label)} 92%, #fff) 0%, color-mix(in srgb, ${hueFor(label)} 70%, #0b0d11) 100%)`
616
+ /* eslint-enable no-restricted-syntax */
617
+ },
618
+ children: /* @__PURE__ */ jsx10("span", { className: "[text-box:trim-both_cap_alphabetic]", children: initialsFor(label) })
619
+ }
620
+ ) : /* @__PURE__ */ jsx10(BaseAvatar.Fallback, { render: /* @__PURE__ */ jsx10("div", {}), className: "w-full h-full bg-accent-muted flex items-center justify-center text-text-muted", children: /* @__PURE__ */ jsx10(IconUserFilled, { size: Math.round(size * 0.5) }) })
621
+ ]
596
622
  }
597
623
  );
598
624
  }
@@ -623,7 +649,7 @@ function AvatarGroup({ members, size = 24 }) {
623
649
 
624
650
  // src/Banner.tsx
625
651
  import { IconX as IconX2 } from "@tabler/icons-react";
626
- import { jsx as jsx12, jsxs as jsxs6 } from "react/jsx-runtime";
652
+ import { jsx as jsx12, jsxs as jsxs7 } from "react/jsx-runtime";
627
653
  var TONE_STYLES = {
628
654
  ok: "bg-success-muted text-success-default",
629
655
  error: "bg-error-muted text-error-default",
@@ -635,7 +661,7 @@ function Banner({ tone, children, onDismiss, dismissLabel = "Dismiss", className
635
661
  if (!onDismiss) {
636
662
  return /* @__PURE__ */ jsx12("div", { role, className: cn("px-4 py-2 text-body-2", TONE_STYLES[tone], className), children });
637
663
  }
638
- return /* @__PURE__ */ jsxs6("div", { role, className: cn("flex items-center gap-3 px-4 py-2 text-body-2", TONE_STYLES[tone], className), children: [
664
+ return /* @__PURE__ */ jsxs7("div", { role, className: cn("flex items-center gap-3 px-4 py-2 text-body-2", TONE_STYLES[tone], className), children: [
639
665
  /* @__PURE__ */ jsx12("span", { className: "min-w-0 flex-1", children }),
640
666
  /* @__PURE__ */ jsx12(IconButton, { "aria-label": dismissLabel, onClick: onDismiss, className: "-mr-1 shrink-0 text-current hover:text-current", children: /* @__PURE__ */ jsx12(IconX2, { size: 16, stroke: 1.5 }) })
641
667
  ] });
@@ -643,7 +669,7 @@ function Banner({ tone, children, onDismiss, dismissLabel = "Dismiss", className
643
669
 
644
670
  // src/Button.tsx
645
671
  import { Button as BaseButton3 } from "@base-ui/react/button";
646
- import { jsx as jsx13, jsxs as jsxs7 } from "react/jsx-runtime";
672
+ import { jsx as jsx13, jsxs as jsxs8 } from "react/jsx-runtime";
647
673
  function Button({
648
674
  variant = "muted",
649
675
  size = "default",
@@ -656,7 +682,7 @@ function Button({
656
682
  ...props
657
683
  }) {
658
684
  const hasLeadingIcon = !!leadingIcon;
659
- const button = /* @__PURE__ */ jsxs7(
685
+ const button = /* @__PURE__ */ jsxs8(
660
686
  BaseButton3,
661
687
  {
662
688
  type,
@@ -710,7 +736,7 @@ import { IconCheck } from "@tabler/icons-react";
710
736
  import { jsx as jsx14 } from "react/jsx-runtime";
711
737
  function squareClasses(checked, disabled, interactive, className) {
712
738
  return cn(
713
- "inline-flex items-center justify-center size-4 shrink-0 rounded-[4px] border transition-colors",
739
+ "inline-flex items-center justify-center size-4 shrink-0 rounded-sm border transition-colors",
714
740
  checked ? "bg-accent-primary border-accent-primary text-text-inverse" : "bg-transparent border-border-strong hover:border-text-muted",
715
741
  disabled && "opacity-50 pointer-events-none",
716
742
  interactive ? "cursor-pointer" : "pointer-events-none",
@@ -738,7 +764,7 @@ function Checkbox({ checked, onChange, disabled = false, className, ...aria }) {
738
764
  }
739
765
 
740
766
  // src/Chip.tsx
741
- import { jsx as jsx15, jsxs as jsxs8 } from "react/jsx-runtime";
767
+ import { jsx as jsx15, jsxs as jsxs9 } from "react/jsx-runtime";
742
768
  var typeStyles = {
743
769
  neutral: "bg-bg-inset text-text-primary",
744
770
  brand: "bg-accent-muted text-accent-primary signal:border signal:border-accent-outline",
@@ -748,7 +774,7 @@ var typeStyles = {
748
774
  error: "bg-error-muted text-error-default signal:border signal:border-error-outline"
749
775
  };
750
776
  function Chip({ type = "neutral", label, leadingIcon, trailingIcon, className }) {
751
- return /* @__PURE__ */ jsxs8("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: [
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: [
752
778
  leadingIcon && /* @__PURE__ */ jsx15("span", { className: "flex size-3 shrink-0 items-center justify-center", children: leadingIcon }),
753
779
  label && // A chip given a `max-w-*` cuts a long label with an ellipsis instead
754
780
  // of growing past it — Ship's project chip on an issue row
@@ -758,13 +784,13 @@ function Chip({ type = "neutral", label, leadingIcon, trailingIcon, className })
758
784
  // the screenshot diff caught every descender cut off. `clip` is the
759
785
  // one overflow that leaves the other axis visible. A chip with no cap
760
786
  // draws exactly as before.
761
- /* @__PURE__ */ jsx15("span", { className: "min-w-0 overflow-x-clip text-ellipsis whitespace-nowrap text-chip signal:font-mono signal:text-[10px] signal:font-semibold signal:tracking-[0.02em] signal:tabular-nums", children: label }),
787
+ /* @__PURE__ */ jsx15("span", { className: "min-w-0 overflow-x-clip text-ellipsis whitespace-nowrap text-chip signal:font-mono signal:text-small signal:font-semibold signal:tracking-wide signal:tabular-nums", children: label }),
762
788
  trailingIcon && /* @__PURE__ */ jsx15("span", { className: "flex size-3 shrink-0 items-center justify-center", children: trailingIcon })
763
789
  ] });
764
790
  }
765
791
 
766
792
  // src/ChipInput.tsx
767
- import { useMemo, useState as useState3 } from "react";
793
+ import { useMemo, useState as useState2 } from "react";
768
794
  import { Button as BaseButton4 } from "@base-ui/react/button";
769
795
  import { Combobox } from "@base-ui/react/combobox";
770
796
  import { IconX as IconX3 } from "@tabler/icons-react";
@@ -787,7 +813,7 @@ function SectionLabel({ children, className }) {
787
813
  "span",
788
814
  {
789
815
  className: cn(
790
- "text-[12px] leading-[12px] font-medium text-text-primary signal:font-mono signal:text-[10px] signal:uppercase signal:tracking-[0.14em]",
816
+ "text-h5 leading-3 text-text-primary signal:font-mono signal:text-small signal:uppercase signal:tracking-widest",
791
817
  className
792
818
  ),
793
819
  children
@@ -796,7 +822,7 @@ function SectionLabel({ children, className }) {
796
822
  }
797
823
 
798
824
  // src/Menu.tsx
799
- import { Fragment as Fragment2, jsx as jsx17, jsxs as jsxs9 } from "react/jsx-runtime";
825
+ import { Fragment as Fragment2, jsx as jsx17, jsxs as jsxs10 } from "react/jsx-runtime";
800
826
  var MenuContext = createContext(null);
801
827
  function MenuPanel({ children, className, ...props }) {
802
828
  return /* @__PURE__ */ jsx17(
@@ -829,7 +855,7 @@ var VIEWPORT_PAD2 = 8;
829
855
  var HOVER_OPEN_DELAY = 0;
830
856
  var HOVER_CLOSE_DELAY = 150;
831
857
  function Menu({ trigger, align = "left", openOnHover = false, open, onOpenChange, actionsRef, children, className, contentClassName }) {
832
- return /* @__PURE__ */ jsxs9(
858
+ return /* @__PURE__ */ jsxs10(
833
859
  BaseMenu.Root,
834
860
  {
835
861
  open,
@@ -877,7 +903,7 @@ function MenuSub({ label, leading, selected, children, className }) {
877
903
  '[@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".'
878
904
  );
879
905
  }
880
- return /* @__PURE__ */ jsxs9(BaseMenu.SubmenuRoot, { children: [
906
+ return /* @__PURE__ */ jsxs10(BaseMenu.SubmenuRoot, { children: [
881
907
  /* @__PURE__ */ jsx17(
882
908
  BaseMenu.SubmenuTrigger,
883
909
  {
@@ -934,17 +960,17 @@ function menuItemClassName({ size, selected, className }) {
934
960
  }
935
961
  function MenuItemBody({ label, children, size = "default", description, leading, trailing, hint, shortcut, submenu, destructive, selected }) {
936
962
  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);
937
- return /* @__PURE__ */ jsxs9(Fragment2, { children: [
963
+ return /* @__PURE__ */ jsxs10(Fragment2, { children: [
938
964
  leading && /* @__PURE__ */ jsx17("span", { className: "flex shrink-0 items-center", children: leading }),
939
- children ?? /* @__PURE__ */ jsxs9("span", { className: cn("flex min-w-0 flex-1 flex-col", size === "tall" && "gap-[2px]"), children: [
940
- /* @__PURE__ */ jsx17("span", { className: cn("truncate text-[14px] leading-[140%]", destructive ? "text-error-default" : "text-text-primary"), children: label }),
941
- description && /* @__PURE__ */ jsx17("span", { className: "truncate text-[12px] leading-[120%] text-text-secondary", children: description })
965
+ children ?? /* @__PURE__ */ jsxs10("span", { className: cn("flex min-w-0 flex-1 flex-col", size === "tall" && "gap-[2px]"), children: [
966
+ /* @__PURE__ */ jsx17("span", { className: cn("truncate text-body-2", destructive ? "text-error-default" : "text-text-primary"), children: label }),
967
+ description && /* @__PURE__ */ jsx17("span", { className: "truncate text-caption text-text-secondary", children: description })
942
968
  ] }),
943
969
  (edge || hint) && // One grid cell holding both, right-aligned: the slot is as wide as
944
970
  // the wider of the two and never changes, so revealing the hint moves
945
971
  // nothing. No transition here either — the hint switches on the same
946
972
  // :hover / `selected` as the fill, in the same frame.
947
- /* @__PURE__ */ jsxs9("span", { className: "grid shrink-0 items-center justify-items-end [&>*]:col-start-1 [&>*]:row-start-1", children: [
973
+ /* @__PURE__ */ jsxs10("span", { className: "grid shrink-0 items-center justify-items-end [&>*]:col-start-1 [&>*]:row-start-1", children: [
948
974
  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 }),
949
975
  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 })
950
976
  ] })
@@ -983,21 +1009,21 @@ function MenuItem({ label, children, size = "default", description, leading, tra
983
1009
  );
984
1010
  }
985
1011
  function EnterHint({ target }) {
986
- return /* @__PURE__ */ jsxs9("span", { className: "flex shrink-0 items-center gap-1.5 text-text-muted", children: [
1012
+ return /* @__PURE__ */ jsxs10("span", { className: "flex shrink-0 items-center gap-1.5 text-text-muted", children: [
987
1013
  /* @__PURE__ */ jsx17(Kbd, { children: "\u21A9 Enter" }),
988
- target && /* @__PURE__ */ jsx17("span", { className: "text-[9px] font-medium leading-[115%] signal:font-mono signal:text-[9.5px] signal:tracking-[0.04em]", children: target })
1014
+ target && /* @__PURE__ */ jsx17("span", { className: "text-menu signal:font-mono signal:text-small signal:tracking-wider", children: target })
989
1015
  ] });
990
1016
  }
991
1017
  function MenuSection({ label, children, className }) {
992
1018
  const inMenu = useContext(MenuContext) !== null;
993
1019
  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 }) });
994
1020
  if (!inMenu) {
995
- return /* @__PURE__ */ jsxs9("div", { className: "flex flex-col", children: [
1021
+ return /* @__PURE__ */ jsxs10("div", { className: "flex flex-col", children: [
996
1022
  heading,
997
1023
  children
998
1024
  ] });
999
1025
  }
1000
- return /* @__PURE__ */ jsxs9(BaseMenu.Group, { className: "flex flex-col", children: [
1026
+ return /* @__PURE__ */ jsxs10(BaseMenu.Group, { className: "flex flex-col", children: [
1001
1027
  /* @__PURE__ */ jsx17(BaseMenu.GroupLabel, { render: heading }),
1002
1028
  children
1003
1029
  ] });
@@ -1007,7 +1033,7 @@ function MenuRow({ children, className }) {
1007
1033
  }
1008
1034
 
1009
1035
  // src/ChipInput.tsx
1010
- import { jsx as jsx18, jsxs as jsxs10 } from "react/jsx-runtime";
1036
+ import { jsx as jsx18, jsxs as jsxs11 } from "react/jsx-runtime";
1011
1037
  var CHIP_BOX = (
1012
1038
  // Curved, not a pill (Katerina, 2026-09-01): the Avatar keeps its own
1013
1039
  // rounded-sm corners — never a forced circle — and the chip's corner
@@ -1018,7 +1044,7 @@ var CHIP_LABEL = "text-caption font-medium text-text-primary";
1018
1044
  var CHIP_REMOVE = "size-4 flex items-center justify-center rounded-full hover:bg-bg-hover text-text-secondary";
1019
1045
  var chipPadding = (leading, removable) => cn(leading ? "pl-[2px]" : "pl-2", removable ? "pr-1" : "pr-2");
1020
1046
  function InputChip({ label, leading, onRemove, className }) {
1021
- return /* @__PURE__ */ jsxs10("div", { className: cn(CHIP_BOX, chipPadding(!!leading, !!onRemove), className), children: [
1047
+ return /* @__PURE__ */ jsxs11("div", { className: cn(CHIP_BOX, chipPadding(!!leading, !!onRemove), className), children: [
1022
1048
  leading && /* @__PURE__ */ jsx18("span", { className: "flex shrink-0 items-center", children: leading }),
1023
1049
  /* @__PURE__ */ jsx18("span", { className: CHIP_LABEL, children: label }),
1024
1050
  onRemove && /* @__PURE__ */ jsx18(
@@ -1047,8 +1073,8 @@ function ChipInput({
1047
1073
  rowLeading,
1048
1074
  ...aria
1049
1075
  }) {
1050
- const [query, setQuery] = useState3("");
1051
- const [box, setBox] = useState3(null);
1076
+ const [query, setQuery] = useState2("");
1077
+ const [box, setBox] = useState2(null);
1052
1078
  const available = useMemo(() => {
1053
1079
  const chosen = new Set(value.map((o) => o.id));
1054
1080
  const excluded = new Set(excludeIds);
@@ -1084,7 +1110,7 @@ function ChipInput({
1084
1110
  setQuery("");
1085
1111
  }
1086
1112
  }
1087
- return /* @__PURE__ */ jsxs10(
1113
+ return /* @__PURE__ */ jsxs11(
1088
1114
  Combobox.Root,
1089
1115
  {
1090
1116
  multiple: true,
@@ -1101,8 +1127,8 @@ function ChipInput({
1101
1127
  filter,
1102
1128
  itemToStringLabel: (option) => option.label,
1103
1129
  children: [
1104
- /* @__PURE__ */ jsxs10(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: [
1105
- value.map((option) => /* @__PURE__ */ jsxs10(Combobox.Chip, { className: cn(CHIP_BOX, chipPadding(!!chipLeading, true)), children: [
1130
+ /* @__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: [
1131
+ value.map((option) => /* @__PURE__ */ jsxs11(Combobox.Chip, { className: cn(CHIP_BOX, chipPadding(!!chipLeading, true)), children: [
1106
1132
  chipLeading && /* @__PURE__ */ jsx18("span", { className: "flex shrink-0 items-center", children: chipLeading(option) }),
1107
1133
  /* @__PURE__ */ jsx18("span", { className: CHIP_LABEL, children: option.label }),
1108
1134
  /* @__PURE__ */ jsx18(Combobox.ChipRemove, { className: CHIP_REMOVE, "aria-label": `Remove ${option.label}`, children: /* @__PURE__ */ jsx18(IconX3, { size: 10, stroke: 1.5 }) })
@@ -1152,7 +1178,7 @@ var GAP3 = 4;
1152
1178
  var VIEWPORT_PAD3 = 8;
1153
1179
 
1154
1180
  // src/InlineChip.tsx
1155
- import { Fragment as Fragment3, jsx as jsx19, jsxs as jsxs11 } from "react/jsx-runtime";
1181
+ import { Fragment as Fragment3, jsx as jsx19, jsxs as jsxs12 } from "react/jsx-runtime";
1156
1182
  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";
1157
1183
  var INLINE_CHIP_TONE_CLASSES = {
1158
1184
  /** A thing or a place — anything that is not a person. */
@@ -1174,7 +1200,7 @@ function inlineChipClassName(tone, className) {
1174
1200
  return cn(INLINE_CHIP_CLASSES, INLINE_CHIP_TONE_CLASSES[tone], className);
1175
1201
  }
1176
1202
  function InlineChip({ tone = "neutral", icon, href, className, children, ...props }) {
1177
- const body = /* @__PURE__ */ jsxs11(Fragment3, { children: [
1203
+ const body = /* @__PURE__ */ jsxs12(Fragment3, { children: [
1178
1204
  icon && /* @__PURE__ */ jsx19("span", { className: "flex size-4 shrink-0 items-center justify-center text-text-secondary", children: icon }),
1179
1205
  children
1180
1206
  ] });
@@ -1189,15 +1215,15 @@ function InlineChip({ tone = "neutral", icon, href, className, children, ...prop
1189
1215
  import { useCallback, useRef as useRef2 } from "react";
1190
1216
 
1191
1217
  // src/Divider.tsx
1192
- import { jsx as jsx20, jsxs as jsxs12 } from "react/jsx-runtime";
1218
+ import { Separator } from "@base-ui/react/separator";
1219
+ import { jsx as jsx20, jsxs as jsxs13 } from "react/jsx-runtime";
1193
1220
  function Divider({ orientation = "horizontal", label, tone = "default", className }) {
1194
1221
  if (label && orientation === "horizontal") {
1195
1222
  const line = tone === "warning" ? "bg-warning-muted" : "bg-border-subtle";
1196
- return /* @__PURE__ */ jsxs12(
1197
- "div",
1223
+ return /* @__PURE__ */ jsxs13(
1224
+ Separator,
1198
1225
  {
1199
- role: "separator",
1200
- "aria-orientation": "horizontal",
1226
+ orientation: "horizontal",
1201
1227
  "aria-label": label,
1202
1228
  className: cn("flex shrink-0 items-center gap-2 mx-3", className),
1203
1229
  children: [
@@ -1209,23 +1235,22 @@ function Divider({ orientation = "horizontal", label, tone = "default", classNam
1209
1235
  );
1210
1236
  }
1211
1237
  return /* @__PURE__ */ jsx20(
1212
- "div",
1238
+ Separator,
1213
1239
  {
1214
- role: "separator",
1215
- "aria-orientation": orientation,
1240
+ orientation,
1216
1241
  className: cn("shrink-0 bg-border-subtle", orientation === "horizontal" ? "h-px mx-3" : "w-px self-stretch", className)
1217
1242
  }
1218
1243
  );
1219
1244
  }
1220
1245
 
1221
1246
  // src/Person.tsx
1222
- import { jsx as jsx21, jsxs as jsxs13 } from "react/jsx-runtime";
1247
+ import { jsx as jsx21, jsxs as jsxs14 } from "react/jsx-runtime";
1223
1248
  function Person({ name, picture, fallback = "\u2014", size = 20, className }) {
1224
1249
  return (
1225
1250
  // gap-2: the face-to-name distance is one rule (8px) wherever a person
1226
1251
  // appears — Katerina, 2026-09-01, set on Person so PersonTrigger and every
1227
1252
  // row agree by construction.
1228
- /* @__PURE__ */ jsxs13("span", { className: cn("flex min-w-0 items-center gap-2", className), children: [
1253
+ /* @__PURE__ */ jsxs14("span", { className: cn("flex min-w-0 items-center gap-2", className), children: [
1229
1254
  /* @__PURE__ */ jsx21(Avatar, { name, src: picture, size }),
1230
1255
  /* @__PURE__ */ jsx21("span", { className: cn("truncate", !name && "text-text-muted"), children: name ?? fallback })
1231
1256
  ] })
@@ -1235,7 +1260,7 @@ function Person({ name, picture, fallback = "\u2014", size = 20, className }) {
1235
1260
  // src/PersonTrigger.tsx
1236
1261
  import { Button as BaseButton5 } from "@base-ui/react/button";
1237
1262
  import { IconChevronDown } from "@tabler/icons-react";
1238
- import { jsx as jsx22, jsxs as jsxs14 } from "react/jsx-runtime";
1263
+ import { jsx as jsx22, jsxs as jsxs15 } from "react/jsx-runtime";
1239
1264
  function PersonTrigger({ name, picture, fallback, size, open = false, compact = false, className, ...props }) {
1240
1265
  if (compact) {
1241
1266
  return /* @__PURE__ */ jsx22(
@@ -1251,7 +1276,7 @@ function PersonTrigger({ name, picture, fallback, size, open = false, compact =
1251
1276
  }
1252
1277
  );
1253
1278
  }
1254
- return /* @__PURE__ */ jsxs14(
1279
+ return /* @__PURE__ */ jsxs15(
1255
1280
  BaseButton5,
1256
1281
  {
1257
1282
  type: "button",
@@ -1277,7 +1302,7 @@ function PersonTrigger({ name, picture, fallback, size, open = false, compact =
1277
1302
  }
1278
1303
 
1279
1304
  // src/IdentityMenu.tsx
1280
- import { Fragment as Fragment4, jsx as jsx23, jsxs as jsxs15 } from "react/jsx-runtime";
1305
+ import { Fragment as Fragment4, jsx as jsx23, jsxs as jsxs16 } from "react/jsx-runtime";
1281
1306
  function IdentityPanel({ className, onClose = () => {
1282
1307
  }, ...rest }) {
1283
1308
  return /* @__PURE__ */ jsx23(MenuPanel, { className: cn("w-72", className), children: /* @__PURE__ */ jsx23(IdentityRows, { ...rest, onClose }) });
@@ -1288,23 +1313,23 @@ function IdentityRows({ me, signedIn, relayUrl, idBase, onCopyKey, onSignOut, on
1288
1313
  action();
1289
1314
  };
1290
1315
  const appRows = typeof children === "function" ? children(onClose) : children;
1291
- return /* @__PURE__ */ jsxs15(Fragment4, { children: [
1292
- /* @__PURE__ */ jsxs15(MenuSection, { label: signedIn ? "Signed in as" : "Acting as", children: [
1316
+ return /* @__PURE__ */ jsxs16(Fragment4, { children: [
1317
+ /* @__PURE__ */ jsxs16(MenuSection, { label: signedIn ? "Signed in as" : "Acting as", children: [
1293
1318
  /* @__PURE__ */ jsx23(MenuRow, { children: /* @__PURE__ */ jsx23(Person, { name: me.name, picture: me.picture, fallback: "Anonymous", size: 28, className: "text-body-2-strong" }) }),
1294
1319
  /* @__PURE__ */ jsx23(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." }),
1295
- me.email && /* @__PURE__ */ jsxs15(Note, { children: [
1320
+ me.email && /* @__PURE__ */ jsxs16(Note, { children: [
1296
1321
  me.email,
1297
1322
  " \xB7 known to Estiva, never published to the relay"
1298
1323
  ] })
1299
1324
  ] }),
1300
- relayUrl && /* @__PURE__ */ jsxs15(Fragment4, { children: [
1325
+ relayUrl && /* @__PURE__ */ jsxs16(Fragment4, { children: [
1301
1326
  /* @__PURE__ */ jsx23(Divider, { className: "mx-0 my-2" }),
1302
- /* @__PURE__ */ jsxs15(MenuSection, { label: "Workspace", children: [
1327
+ /* @__PURE__ */ jsxs16(MenuSection, { label: "Workspace", children: [
1303
1328
  /* @__PURE__ */ jsx23(MenuRow, { children: /* @__PURE__ */ jsx23("span", { className: "break-all font-mono text-caption text-text-primary", children: relayUrl }) }),
1304
1329
  /* @__PURE__ */ jsx23(Note, { children: "Everyone on this relay shares this workspace, in every app." })
1305
1330
  ] })
1306
1331
  ] }),
1307
- appRows && /* @__PURE__ */ jsxs15(Fragment4, { children: [
1332
+ appRows && /* @__PURE__ */ jsxs16(Fragment4, { children: [
1308
1333
  /* @__PURE__ */ jsx23(Divider, { className: "mx-0 my-2" }),
1309
1334
  appRows
1310
1335
  ] }),
@@ -1369,7 +1394,7 @@ function Note({ children }) {
1369
1394
  // src/Field.tsx
1370
1395
  import { cloneElement, isValidElement } from "react";
1371
1396
  import { Field as BaseField } from "@base-ui/react/field";
1372
- import { jsx as jsx24, jsxs as jsxs16 } from "react/jsx-runtime";
1397
+ import { jsx as jsx24, jsxs as jsxs17 } from "react/jsx-runtime";
1373
1398
  var LINE_STYLES = {
1374
1399
  helper: "text-caption text-text-muted",
1375
1400
  warning: "text-caption text-warning-default",
@@ -1379,12 +1404,12 @@ function Field({ label, required = false, helper, error, children }) {
1379
1404
  const control = required && isValidElement(children) ? cloneElement(children, {
1380
1405
  "aria-required": children.props["aria-required"] ?? true
1381
1406
  }) : children;
1382
- return /* @__PURE__ */ jsxs16(BaseField.Root, { invalid: !!error, className: "flex flex-col gap-2", children: [
1383
- /* @__PURE__ */ jsxs16(BaseField.Label, { className: cn("text-input-label text-text-primary", required && "flex items-center"), children: [
1407
+ return /* @__PURE__ */ jsxs17(BaseField.Root, { invalid: !!error, className: "flex flex-col gap-2", children: [
1408
+ /* @__PURE__ */ jsxs17(BaseField.Label, { className: cn("text-input-label text-text-primary", required && "flex items-center"), children: [
1384
1409
  label,
1385
1410
  required && /* @__PURE__ */ jsx24("span", { "aria-hidden": "true", className: "text-error-default ml-0.5", children: "*" })
1386
1411
  ] }),
1387
- /* @__PURE__ */ jsxs16("div", { className: "flex flex-col gap-1.5", children: [
1412
+ /* @__PURE__ */ jsxs17("div", { className: "flex flex-col gap-1.5", children: [
1388
1413
  control,
1389
1414
  error != null ? /* @__PURE__ */ jsx24(BaseField.Error, { match: true, className: LINE_STYLES.error, children: error }) : helper != null ? /* @__PURE__ */ jsx24(BaseField.Description, { className: LINE_STYLES.helper, children: helper }) : null
1390
1415
  ] })
@@ -1397,12 +1422,12 @@ function FieldLine({ tone = "helper", children, className }) {
1397
1422
  // src/Select.tsx
1398
1423
  import { IconCheck as IconCheck2, IconChevronDown as IconChevronDown2 } from "@tabler/icons-react";
1399
1424
  import { Select as BaseSelect } from "@base-ui/react/select";
1400
- import { jsx as jsx25, jsxs as jsxs17 } from "react/jsx-runtime";
1425
+ import { jsx as jsx25, jsxs as jsxs18 } from "react/jsx-runtime";
1401
1426
  var GAP4 = 4;
1402
1427
  var VIEWPORT_PAD4 = 8;
1403
1428
  function Select({ value, onChange, options, size = "default", ariaLabel, placeholder = "Select\u2026", disabled, className, ...aria }) {
1404
1429
  const selected = options.find((o) => o.value === value);
1405
- return /* @__PURE__ */ jsxs17(
1430
+ return /* @__PURE__ */ jsxs18(
1406
1431
  BaseSelect.Root,
1407
1432
  {
1408
1433
  value,
@@ -1410,7 +1435,7 @@ function Select({ value, onChange, options, size = "default", ariaLabel, placeho
1410
1435
  disabled,
1411
1436
  modal: false,
1412
1437
  children: [
1413
- /* @__PURE__ */ jsxs17(
1438
+ /* @__PURE__ */ jsxs18(
1414
1439
  BaseSelect.Trigger,
1415
1440
  {
1416
1441
  "aria-label": ariaLabel,
@@ -1432,12 +1457,12 @@ function Select({ value, onChange, options, size = "default", ariaLabel, placeho
1432
1457
  "hover:border-border-strong focus-visible:hover:border-border-focus aria-expanded:hover:border-border-focus disabled:pointer-events-none disabled:bg-bg-disabled disabled:text-text-disabled",
1433
1458
  "focus-visible:border-border-focus aria-expanded:border-border-focus",
1434
1459
  "signal:transition-shadow signal:focus-visible:shadow-focus-ring",
1435
- size === "default" && "px-3 py-2 text-[14px] leading-[1.4] font-normal",
1436
- size === "small" && "h-6 px-2 text-[12px] leading-[1.4] font-normal",
1460
+ size === "default" && "px-3 py-2 text-input-value",
1461
+ size === "small" && "h-6 px-2 text-caption",
1437
1462
  className
1438
1463
  ),
1439
1464
  children: [
1440
- /* @__PURE__ */ jsxs17("span", { className: cn("flex min-w-0 items-center gap-2", !selected && "text-text-muted"), children: [
1465
+ /* @__PURE__ */ jsxs18("span", { className: cn("flex min-w-0 items-center gap-2", !selected && "text-text-muted"), children: [
1441
1466
  selected?.leading && /* @__PURE__ */ jsx25("span", { className: "flex shrink-0 items-center", children: selected.leading }),
1442
1467
  /* @__PURE__ */ jsx25(BaseSelect.Value, { className: "truncate", children: () => selected?.label ?? placeholder })
1443
1468
  ] }),
@@ -1464,15 +1489,15 @@ function Select({ value, onChange, options, size = "default", ariaLabel, placeho
1464
1489
  {
1465
1490
  render: /* @__PURE__ */ jsx25(MenuPanel, {}),
1466
1491
  className: "min-w-[var(--anchor-width)] p-0",
1467
- children: /* @__PURE__ */ jsx25(ScrollArea, { viewportClassName: "max-h-[min(288px,var(--available-height))]", contentClassName: "flex flex-col p-2", children: options.map((option) => /* @__PURE__ */ jsxs17(
1492
+ children: /* @__PURE__ */ jsx25(ScrollArea, { viewportClassName: "max-h-[min(288px,var(--available-height))]", contentClassName: "flex flex-col p-2", children: options.map((option) => /* @__PURE__ */ jsxs18(
1468
1493
  BaseSelect.Item,
1469
1494
  {
1470
1495
  value: option.value,
1471
1496
  className: cn(menuItemClassName({ size: "default" }), "justify-between data-[selected]:font-medium"),
1472
1497
  children: [
1473
- /* @__PURE__ */ jsxs17("span", { className: "flex min-w-0 items-center gap-2", children: [
1498
+ /* @__PURE__ */ jsxs18("span", { className: "flex min-w-0 items-center gap-2", children: [
1474
1499
  option.leading && /* @__PURE__ */ jsx25("span", { className: "flex shrink-0 items-center", children: option.leading }),
1475
- /* @__PURE__ */ jsx25(BaseSelect.ItemText, { className: "truncate text-[14px] leading-[140%] text-text-primary", children: option.label })
1500
+ /* @__PURE__ */ jsx25(BaseSelect.ItemText, { className: "truncate text-body-2 text-text-primary", children: option.label })
1476
1501
  ] }),
1477
1502
  /* @__PURE__ */ jsx25(
1478
1503
  BaseSelect.ItemIndicator,
@@ -1497,15 +1522,18 @@ function Select({ value, onChange, options, size = "default", ariaLabel, placeho
1497
1522
  import { forwardRef } from "react";
1498
1523
  import { Input } from "@base-ui/react/input";
1499
1524
  import { jsx as jsx26 } from "react/jsx-runtime";
1500
- var TextInput = forwardRef(function TextInput2({ className, type = "text", ...props }, ref) {
1525
+ var TextInput = forwardRef(function TextInput2({ className, type = "text", size = "default", ...props }, ref) {
1501
1526
  return /* @__PURE__ */ jsx26(
1502
1527
  Input,
1503
1528
  {
1504
1529
  ref,
1505
1530
  type,
1506
1531
  className: cn(
1507
- "bg-bg-inset border border-border-default focus:border-border-focus rounded-lg px-3 py-2",
1508
- "text-[14px] leading-[1.4] font-normal text-text-primary placeholder:text-text-muted",
1532
+ "bg-bg-inset border border-border-default focus:border-border-focus rounded-lg",
1533
+ // The small size is the small Select's trigger, class for class.
1534
+ size === "default" && "px-3 py-2 text-input-value",
1535
+ size === "small" && "h-6 px-2 text-caption",
1536
+ "text-text-primary placeholder:text-text-muted",
1509
1537
  "outline-none transition-colors",
1510
1538
  "disabled:pointer-events-none disabled:bg-bg-disabled disabled:text-text-disabled",
1511
1539
  "signal:transition-shadow signal:focus:shadow-focus-ring",
@@ -1528,7 +1556,7 @@ var Textarea = forwardRef2(function Textarea2({ className, ...props }, ref) {
1528
1556
  render: /* @__PURE__ */ jsx27("textarea", {}),
1529
1557
  className: cn(
1530
1558
  "bg-bg-inset border border-border-default focus:border-border-focus rounded-lg px-3 py-2",
1531
- "text-[14px] leading-[1.4] font-normal text-text-primary placeholder:text-text-muted",
1559
+ "text-input-value text-text-primary placeholder:text-text-muted",
1532
1560
  "resize-none outline-none transition-colors",
1533
1561
  "disabled:pointer-events-none disabled:bg-bg-disabled disabled:text-text-disabled",
1534
1562
  "signal:transition-shadow signal:focus:shadow-focus-ring",
@@ -1540,14 +1568,14 @@ var Textarea = forwardRef2(function Textarea2({ className, ...props }, ref) {
1540
1568
  });
1541
1569
 
1542
1570
  // src/ConfirmDialog.tsx
1543
- import { useState as useState4 } from "react";
1571
+ import { useState as useState3 } from "react";
1544
1572
 
1545
1573
  // src/DialogShell.tsx
1546
1574
  import { useRef as useRef3 } from "react";
1547
1575
  import { Dialog } from "@base-ui/react/dialog";
1548
1576
  import { AlertDialog } from "@base-ui/react/alert-dialog";
1549
1577
  import { IconX as IconX4 } from "@tabler/icons-react";
1550
- import { jsx as jsx28, jsxs as jsxs18 } from "react/jsx-runtime";
1578
+ import { jsx as jsx28, jsxs as jsxs19 } from "react/jsx-runtime";
1551
1579
  function DialogShell({ title, onClose, headerContent, footer, children, bodyClassName, bodyMaxHeight, width = 502, alert = false }) {
1552
1580
  const Parts = alert ? AlertDialog : Dialog;
1553
1581
  const popupRef = useRef3(null);
@@ -1558,9 +1586,9 @@ function DialogShell({ title, onClose, headerContent, footer, children, bodyClas
1558
1586
  onOpenChange: (open) => {
1559
1587
  if (!open) onClose();
1560
1588
  },
1561
- children: /* @__PURE__ */ jsxs18(Parts.Portal, { children: [
1589
+ children: /* @__PURE__ */ jsxs19(Parts.Portal, { children: [
1562
1590
  /* @__PURE__ */ jsx28(Parts.Backdrop, { className: "fixed inset-0 z-40 bg-scrim" }),
1563
- /* @__PURE__ */ jsx28("div", { className: "fixed inset-0 z-50 flex items-center justify-center pointer-events-none", children: /* @__PURE__ */ jsxs18(
1591
+ /* @__PURE__ */ jsx28("div", { className: "fixed inset-0 z-50 flex items-center justify-center pointer-events-none", children: /* @__PURE__ */ jsxs19(
1564
1592
  Parts.Popup,
1565
1593
  {
1566
1594
  ref: popupRef,
@@ -1569,7 +1597,7 @@ function DialogShell({ title, onClose, headerContent, footer, children, bodyClas
1569
1597
  className: "bg-bg-elevated border border-border-subtle rounded-lg shadow-lg pointer-events-auto flex flex-col overflow-hidden outline-none",
1570
1598
  style: { width },
1571
1599
  children: [
1572
- /* @__PURE__ */ jsxs18("div", { className: "h-12 flex items-center justify-between pl-5 pr-4 border-b border-border-subtle shrink-0", children: [
1600
+ /* @__PURE__ */ jsxs19("div", { className: "h-12 flex items-center justify-between pl-5 pr-4 border-b border-border-subtle shrink-0", children: [
1573
1601
  headerContent ?? /* @__PURE__ */ jsx28(Parts.Title, { className: "text-h4 text-text-primary", render: /* @__PURE__ */ jsx28("span", {}), children: title }),
1574
1602
  /* @__PURE__ */ jsx28(
1575
1603
  Parts.Close,
@@ -1597,9 +1625,9 @@ function DialogShell({ title, onClose, headerContent, footer, children, bodyClas
1597
1625
  }
1598
1626
 
1599
1627
  // src/ConfirmDialog.tsx
1600
- import { Fragment as Fragment5, jsx as jsx29, jsxs as jsxs19 } from "react/jsx-runtime";
1628
+ import { Fragment as Fragment5, jsx as jsx29, jsxs as jsxs20 } from "react/jsx-runtime";
1601
1629
  function ConfirmDialog({ title, children, confirmLabel, destructive = false, onConfirm, onClose }) {
1602
- const [busy, setBusy] = useState4(false);
1630
+ const [busy, setBusy] = useState3(false);
1603
1631
  const confirm = async () => {
1604
1632
  setBusy(true);
1605
1633
  try {
@@ -1616,7 +1644,7 @@ function ConfirmDialog({ title, children, confirmLabel, destructive = false, onC
1616
1644
  title,
1617
1645
  onClose,
1618
1646
  bodyClassName: "flex flex-col gap-3 text-body-2 text-text-primary",
1619
- footer: /* @__PURE__ */ jsxs19(Fragment5, { children: [
1647
+ footer: /* @__PURE__ */ jsxs20(Fragment5, { children: [
1620
1648
  /* @__PURE__ */ jsx29(Button, { variant: "muted", onClick: onClose, disabled: busy, children: "Cancel" }),
1621
1649
  /* @__PURE__ */ jsx29(Button, { variant: destructive ? "destructive" : "primary", onClick: () => void confirm(), disabled: busy, children: confirmLabel })
1622
1650
  ] }),
@@ -1626,14 +1654,14 @@ function ConfirmDialog({ title, children, confirmLabel, destructive = false, onC
1626
1654
  }
1627
1655
 
1628
1656
  // src/EditableText.tsx
1629
- import { useEffect, useRef as useRef4, useState as useState5 } from "react";
1657
+ import { useEffect, useRef as useRef4, useState as useState4 } from "react";
1630
1658
  import { Field as BaseField3 } from "@base-ui/react/field";
1631
1659
  import { Input as Input2 } from "@base-ui/react/input";
1632
1660
  import { jsx as jsx30 } from "react/jsx-runtime";
1633
1661
  function EditableText({ value, display, displayNode, placeholder, onCommit, multiline = false, className, label, readOnly = false }) {
1634
- const [editing, setEditing] = useState5(false);
1635
- const [draft, setDraft] = useState5(value);
1636
- const [busy, setBusy] = useState5(false);
1662
+ const [editing, setEditing] = useState4(false);
1663
+ const [draft, setDraft] = useState4(value);
1664
+ const [busy, setBusy] = useState4(false);
1637
1665
  const fieldRef = useRef4(null);
1638
1666
  useEffect(() => {
1639
1667
  if (editing) {
@@ -1743,12 +1771,12 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
1743
1771
 
1744
1772
  // src/EmptyState.tsx
1745
1773
  import { IconMessage2 } from "@tabler/icons-react";
1746
- import { jsx as jsx31, jsxs as jsxs20 } from "react/jsx-runtime";
1774
+ import { jsx as jsx31, jsxs as jsxs21 } from "react/jsx-runtime";
1747
1775
  function EmptyState({ icon, message, scope = "page", className }) {
1748
1776
  if (scope === "section") {
1749
- return /* @__PURE__ */ jsx31("p", { className: cn("text-body-2 text-text-secondary", className), children: message });
1777
+ return /* @__PURE__ */ jsx31("p", { className: cn("text-caption text-text-muted", className), children: message });
1750
1778
  }
1751
- return /* @__PURE__ */ jsxs20("div", { className: cn("flex flex-1 flex-col items-center justify-center gap-2", className), children: [
1779
+ return /* @__PURE__ */ jsxs21("div", { className: cn("flex flex-1 flex-col items-center justify-center gap-2", className), children: [
1752
1780
  /* @__PURE__ */ jsx31("span", { className: "text-text-secondary", children: icon ?? /* @__PURE__ */ jsx31(IconMessage2, { size: 16, stroke: 1.5 }) }),
1753
1781
  /* @__PURE__ */ jsx31("p", { className: "text-body-2 text-text-secondary text-center", children: message })
1754
1782
  ] });
@@ -1774,13 +1802,13 @@ function ProgressBar({ value, max, label, variant = "default", className }) {
1774
1802
  }
1775
1803
 
1776
1804
  // src/Skeleton.tsx
1777
- import { jsx as jsx33, jsxs as jsxs21 } from "react/jsx-runtime";
1805
+ import { jsx as jsx33, jsxs as jsxs22 } from "react/jsx-runtime";
1778
1806
  function SkeletonBar({ className, style }) {
1779
1807
  return /* @__PURE__ */ jsx33("div", { className: cn("bg-bg-inset rounded-sm animate-pulse", className), style });
1780
1808
  }
1781
1809
  var ROW_BAR_WIDTHS = [150, 100, 170, 120, 90, 140, 110, 160];
1782
1810
  function SkeletonRow({ barWidth = 130 }) {
1783
- return /* @__PURE__ */ jsxs21("div", { className: "flex items-center gap-2 px-2 h-[32px] rounded-lg", children: [
1811
+ return /* @__PURE__ */ jsxs22("div", { className: "flex items-center gap-2 px-2 h-[32px] rounded-lg", children: [
1784
1812
  /* @__PURE__ */ jsx33(SkeletonBar, { className: "w-4 h-4 shrink-0" }),
1785
1813
  /* @__PURE__ */ jsx33(SkeletonBar, { className: "h-3.5", style: { width: barWidth } })
1786
1814
  ] });
@@ -1790,12 +1818,12 @@ function SkeletonList({ rows = 8, className }) {
1790
1818
  }
1791
1819
 
1792
1820
  // src/Breadcrumb.tsx
1793
- import { Fragment as Fragment6, useCallback as useCallback2, useLayoutEffect as useLayoutEffect2, useRef as useRef5, useState as useState6 } from "react";
1794
- import { jsx as jsx34, jsxs as jsxs22 } from "react/jsx-runtime";
1821
+ import { Fragment as Fragment6, useCallback as useCallback2, useLayoutEffect as useLayoutEffect2, useRef as useRef5, useState as useState5 } from "react";
1822
+ import { jsx as jsx34, jsxs as jsxs23 } from "react/jsx-runtime";
1795
1823
  function Breadcrumb({ items, className }) {
1796
1824
  const navRef = useRef5(null);
1797
1825
  const labelRefs = useRef5([]);
1798
- const [truncated, setTruncated] = useState6(/* @__PURE__ */ new Set());
1826
+ const [truncated, setTruncated] = useState5(/* @__PURE__ */ new Set());
1799
1827
  const measure = useCallback2(() => {
1800
1828
  const next = /* @__PURE__ */ new Set();
1801
1829
  labelRefs.current.forEach((el, index) => {
@@ -1811,7 +1839,7 @@ function Breadcrumb({ items, className }) {
1811
1839
  observer.observe(nav);
1812
1840
  return () => observer.disconnect();
1813
1841
  }, [measure, items]);
1814
- return /* @__PURE__ */ jsx34("nav", { ref: navRef, "aria-label": "Breadcrumb", className: cn("flex min-w-0 items-center gap-1.5 text-[14px] leading-[140%]", className), children: items.map((item, index) => {
1842
+ return /* @__PURE__ */ jsx34("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) => {
1815
1843
  const last = index === items.length - 1;
1816
1844
  const tone = item.muted || last && item.mono ? "text-text-muted" : last ? "text-text-primary" : "text-text-secondary";
1817
1845
  const text = cn(
@@ -1819,14 +1847,14 @@ function Breadcrumb({ items, className }) {
1819
1847
  // A mono crumb is a ref — the identity. It never gives up width to a
1820
1848
  // long name beside it (the LongName story always claimed "the ref
1821
1849
  // stays"; flexbox was squeezing it anyway until this line).
1822
- item.mono && "shrink-0 font-mono text-[12px] leading-[120%]",
1850
+ item.mono && "shrink-0 font-mono text-caption",
1823
1851
  tone
1824
1852
  );
1825
1853
  const setLabelRef = (el) => {
1826
1854
  labelRefs.current[index] = el;
1827
1855
  };
1828
1856
  const crumb = item.href ? /* @__PURE__ */ jsx34("a", { ref: setLabelRef, href: item.href, onClick: item.onClick, className: cn(text, "hover:text-text-primary"), children: item.label }) : /* @__PURE__ */ jsx34("span", { ref: setLabelRef, className: text, "aria-current": last ? "page" : void 0, children: item.label });
1829
- return /* @__PURE__ */ jsxs22(Fragment6, { children: [
1857
+ return /* @__PURE__ */ jsxs23(Fragment6, { children: [
1830
1858
  index > 0 && /* @__PURE__ */ jsx34("span", { "aria-hidden": "true", className: "shrink-0 text-text-muted", children: "/" }),
1831
1859
  item.icon && /* @__PURE__ */ jsx34("span", { "aria-hidden": "true", className: cn("flex shrink-0", tone), children: item.icon }),
1832
1860
  truncated.has(index) ? (
@@ -1840,9 +1868,9 @@ function Breadcrumb({ items, className }) {
1840
1868
  }
1841
1869
 
1842
1870
  // src/NavItem.tsx
1843
- import { jsx as jsx35, jsxs as jsxs23 } from "react/jsx-runtime";
1871
+ import { jsx as jsx35, jsxs as jsxs24 } from "react/jsx-runtime";
1844
1872
  function NavItem({ label, href, count, countLabel, active = false, icon, className, ...props }) {
1845
- return /* @__PURE__ */ jsxs23(
1873
+ return /* @__PURE__ */ jsxs24(
1846
1874
  "a",
1847
1875
  {
1848
1876
  href,
@@ -1868,7 +1896,7 @@ function NavItem({ label, href, count, countLabel, active = false, icon, classNa
1868
1896
  // src/Popover.tsx
1869
1897
  import { useMemo as useMemo2 } from "react";
1870
1898
  import { Popover as BasePopover } from "@base-ui/react/popover";
1871
- import { jsx as jsx36, jsxs as jsxs24 } from "react/jsx-runtime";
1899
+ import { jsx as jsx36, jsxs as jsxs25 } from "react/jsx-runtime";
1872
1900
  var GAP5 = 4;
1873
1901
  var VIEWPORT_PAD5 = 8;
1874
1902
  function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpenChange, finalFocus, actionsRef, ariaLabel, children, className, contentClassName, maxHeight }) {
@@ -1877,7 +1905,7 @@ function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpe
1877
1905
  if (anchor instanceof Element) return anchor;
1878
1906
  return { getBoundingClientRect: () => anchor };
1879
1907
  }, [anchor]);
1880
- return /* @__PURE__ */ jsxs24(
1908
+ return /* @__PURE__ */ jsxs25(
1881
1909
  BasePopover.Root,
1882
1910
  {
1883
1911
  open,
@@ -1948,8 +1976,8 @@ function ToolbarButton({ ref, disabled, disabledReason, ...props }) {
1948
1976
  }
1949
1977
  );
1950
1978
  }
1951
- function ToolbarInput(props) {
1952
- return /* @__PURE__ */ jsx37(BaseToolbar.Input, { render: /* @__PURE__ */ jsx37(TextInput, {}), ...props });
1979
+ function ToolbarInput({ size, ...props }) {
1980
+ return /* @__PURE__ */ jsx37(BaseToolbar.Input, { render: /* @__PURE__ */ jsx37(TextInput, { size }), ...props });
1953
1981
  }
1954
1982
  function ToolbarSeparator({ className }) {
1955
1983
  return /* @__PURE__ */ jsx37(
@@ -1980,7 +2008,7 @@ function ReactionPicker({ options, onSelect, "aria-label": ariaLabel = "Reaction
1980
2008
  "aria-label": option.label,
1981
2009
  tooltip: option.label,
1982
2010
  onClick: () => onSelect(option.emoji),
1983
- className: "size-7 text-[18px] leading-none",
2011
+ className: "size-7 text-h3 leading-none",
1984
2012
  children: /* @__PURE__ */ jsx38("span", { "aria-hidden": "true", children: option.emoji })
1985
2013
  },
1986
2014
  option.emoji
@@ -1990,13 +2018,13 @@ function ReactionPicker({ options, onSelect, "aria-label": ariaLabel = "Reaction
1990
2018
 
1991
2019
  // src/PreviewCard.tsx
1992
2020
  import { PreviewCard as BasePreviewCard } from "@base-ui/react/preview-card";
1993
- import { jsx as jsx39, jsxs as jsxs25 } from "react/jsx-runtime";
2021
+ import { jsx as jsx39, jsxs as jsxs26 } from "react/jsx-runtime";
1994
2022
  var GAP6 = 12;
1995
2023
  var VIEWPORT_PAD6 = 8;
1996
2024
  var OPEN_DELAY2 = 350;
1997
2025
  var CLOSE_DELAY = 200;
1998
2026
  function PreviewCard({ content, children, side = "right", delay = OPEN_DELAY2, closeDelay = CLOSE_DELAY, className, wrapperClassName }) {
1999
- return /* @__PURE__ */ jsxs25(BasePreviewCard.Root, { children: [
2027
+ return /* @__PURE__ */ jsxs26(BasePreviewCard.Root, { children: [
2000
2028
  /* @__PURE__ */ jsx39(
2001
2029
  BasePreviewCard.Trigger,
2002
2030
  {
@@ -2034,9 +2062,9 @@ function Rail({ "aria-label": ariaLabel = "Navigation", children, className }) {
2034
2062
  }
2035
2063
 
2036
2064
  // src/RailItem.tsx
2037
- import { jsx as jsx41, jsxs as jsxs26 } from "react/jsx-runtime";
2065
+ import { jsx as jsx41, jsxs as jsxs27 } from "react/jsx-runtime";
2038
2066
  function RailItem({ href, icon, label, active = false, className, ...props }) {
2039
- return /* @__PURE__ */ jsxs26(
2067
+ return /* @__PURE__ */ jsxs27(
2040
2068
  "a",
2041
2069
  {
2042
2070
  href,
@@ -2063,7 +2091,7 @@ function RailItem({ href, icon, label, active = false, className, ...props }) {
2063
2091
  )
2064
2092
  }
2065
2093
  ),
2066
- /* @__PURE__ */ jsx41("span", { className: cn("text-center text-[9px] font-medium leading-[115%]", active ? "text-text-primary" : "text-text-secondary"), children: label })
2094
+ /* @__PURE__ */ jsx41("span", { className: cn("text-center text-menu", active ? "text-text-primary" : "text-text-secondary"), children: label })
2067
2095
  ]
2068
2096
  }
2069
2097
  );
@@ -2083,33 +2111,34 @@ function Sidebar({ "aria-label": ariaLabel = "Workspace", children, className })
2083
2111
  }
2084
2112
 
2085
2113
  // src/Property.tsx
2086
- import { jsx as jsx43, jsxs as jsxs27 } from "react/jsx-runtime";
2114
+ import { jsx as jsx43, jsxs as jsxs28 } from "react/jsx-runtime";
2115
+ var VALUE_CLASSES = "contents";
2087
2116
  function Property({ label, layout = "row", children, className }) {
2088
2117
  if (layout === "stacked") {
2089
2118
  return (
2090
2119
  // gap-3 — the one label-above-content distance (Katerina, 2026-09-01):
2091
2120
  // Peek's topic-details sections already sit at 12px, Ship's rail was
2092
2121
  // 6px, and unifying means the bigger, calmer one.
2093
- /* @__PURE__ */ jsxs27("div", { className: cn("flex flex-col gap-3", className), children: [
2094
- /* @__PURE__ */ jsx43("span", { className: "text-menu uppercase tracking-[0.08em] text-text-secondary", children: label }),
2095
- children
2122
+ /* @__PURE__ */ jsxs28("dl", { className: cn("flex flex-col gap-3", className), children: [
2123
+ /* @__PURE__ */ jsx43("dt", { className: "text-menu uppercase tracking-widest text-text-secondary", children: label }),
2124
+ /* @__PURE__ */ jsx43("dd", { className: VALUE_CLASSES, children })
2096
2125
  ] })
2097
2126
  );
2098
2127
  }
2099
- return /* @__PURE__ */ jsxs27("div", { className: cn("flex items-center gap-2", className), children: [
2100
- /* @__PURE__ */ jsx43("span", { className: "w-[68px] shrink-0 text-caption text-text-secondary", children: label }),
2101
- children
2128
+ return /* @__PURE__ */ jsxs28("dl", { className: cn("flex items-center gap-2", className), children: [
2129
+ /* @__PURE__ */ jsx43("dt", { className: "w-[68px] shrink-0 text-caption text-text-secondary", children: label }),
2130
+ /* @__PURE__ */ jsx43("dd", { className: VALUE_CLASSES, children })
2102
2131
  ] });
2103
2132
  }
2104
2133
 
2105
2134
  // src/Reaction.tsx
2106
- import { jsx as jsx44, jsxs as jsxs28 } from "react/jsx-runtime";
2107
- function Reaction({ emoji, count, pressed = false, className, type, ...props }) {
2108
- return /* @__PURE__ */ jsxs28(
2109
- "button",
2135
+ import { Toggle } from "@base-ui/react/toggle";
2136
+ import { jsx as jsx44, jsxs as jsxs29 } from "react/jsx-runtime";
2137
+ function Reaction({ emoji, count, pressed = false, className, ...props }) {
2138
+ return /* @__PURE__ */ jsxs29(
2139
+ Toggle,
2110
2140
  {
2111
- type: type ?? "button",
2112
- "aria-pressed": pressed,
2141
+ pressed,
2113
2142
  className: cn(
2114
2143
  // Chip's pill at a control's height, so a reaction and a status chip
2115
2144
  // read as the same family — 24px matches Button `small`.
@@ -2128,8 +2157,8 @@ function Reaction({ emoji, count, pressed = false, className, type, ...props })
2128
2157
  ),
2129
2158
  ...props,
2130
2159
  children: [
2131
- /* @__PURE__ */ jsx44("span", { "aria-hidden": "true", className: "shrink-0 text-[16px] leading-none", children: emoji }),
2132
- /* @__PURE__ */ jsx44("span", { className: "text-chip signal:font-mono signal:text-[10px] signal:font-semibold signal:tabular-nums", children: count })
2160
+ /* @__PURE__ */ jsx44("span", { "aria-hidden": "true", className: "shrink-0 text-body-1 leading-none", children: emoji }),
2161
+ /* @__PURE__ */ jsx44("span", { className: "text-chip signal:font-mono signal:text-small signal:font-semibold signal:tabular-nums", children: count })
2133
2162
  ]
2134
2163
  }
2135
2164
  );
@@ -2138,9 +2167,9 @@ function Reaction({ emoji, count, pressed = false, className, type, ...props })
2138
2167
  // src/SearchInput.tsx
2139
2168
  import "react";
2140
2169
  import { Input as Input3 } from "@base-ui/react/input";
2141
- import { jsx as jsx45, jsxs as jsxs29 } from "react/jsx-runtime";
2170
+ import { jsx as jsx45, jsxs as jsxs30 } from "react/jsx-runtime";
2142
2171
  function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...props }) {
2143
- return /* @__PURE__ */ jsxs29(
2172
+ return /* @__PURE__ */ jsxs30(
2144
2173
  "div",
2145
2174
  {
2146
2175
  className: cn(
@@ -2167,7 +2196,7 @@ function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...pro
2167
2196
  // src/SectionHeader.tsx
2168
2197
  import { IconChevronRight as IconChevronRight2 } from "@tabler/icons-react";
2169
2198
  import { useRender } from "@base-ui/react/use-render";
2170
- import { Fragment as Fragment7, jsx as jsx46, jsxs as jsxs30 } from "react/jsx-runtime";
2199
+ import { Fragment as Fragment7, jsx as jsx46, jsxs as jsxs31 } from "react/jsx-runtime";
2171
2200
  function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, trailing, actions, showActions = "hover", render, className }) {
2172
2201
  const titleElement = useRender({
2173
2202
  render: render ?? (chevron ? /* @__PURE__ */ jsx46("button", { type: "button", onClick: onToggle, "aria-expanded": isExpanded }) : /* @__PURE__ */ jsx46("span", {})),
@@ -2176,7 +2205,7 @@ function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, tr
2176
2205
  // whole row up to the actions is the hit target, as it was when the
2177
2206
  // row itself carried the click.
2178
2207
  className: "flex h-full min-w-0 flex-1 items-center gap-1 text-left",
2179
- children: /* @__PURE__ */ jsxs30(Fragment7, { children: [
2208
+ children: /* @__PURE__ */ jsxs31(Fragment7, { children: [
2180
2209
  chevron && /* @__PURE__ */ jsx46(
2181
2210
  IconChevronRight2,
2182
2211
  {
@@ -2189,7 +2218,7 @@ function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, tr
2189
2218
  ] })
2190
2219
  }
2191
2220
  });
2192
- return /* @__PURE__ */ jsxs30(
2221
+ return /* @__PURE__ */ jsxs31(
2193
2222
  "div",
2194
2223
  {
2195
2224
  className: cn(
@@ -2219,9 +2248,9 @@ function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, tr
2219
2248
  }
2220
2249
 
2221
2250
  // src/CollapsibleSection.tsx
2222
- import { useState as useState7 } from "react";
2251
+ import { useState as useState6 } from "react";
2223
2252
  import { Collapsible } from "@base-ui/react/collapsible";
2224
- import { jsx as jsx47, jsxs as jsxs31 } from "react/jsx-runtime";
2253
+ import { jsx as jsx47, jsxs as jsxs32 } from "react/jsx-runtime";
2225
2254
  var OPEN = "open";
2226
2255
  var CLOSED = "closed";
2227
2256
  function readStored(key) {
@@ -2241,14 +2270,14 @@ function writeStored(key, open) {
2241
2270
  }
2242
2271
  }
2243
2272
  function CollapsibleSection({ title, defaultOpen = true, open: openProp, onOpenChange, storageKey, trailing, actions, showActions, children, className, contentClassName }) {
2244
- const [openState, setOpenState] = useState7(() => readStored(storageKey) ?? defaultOpen);
2273
+ const [openState, setOpenState] = useState6(() => readStored(storageKey) ?? defaultOpen);
2245
2274
  const open = openProp ?? openState;
2246
2275
  const setOpen = (next) => {
2247
2276
  setOpenState(next);
2248
2277
  writeStored(storageKey, next);
2249
2278
  onOpenChange?.(next);
2250
2279
  };
2251
- return /* @__PURE__ */ jsxs31(Collapsible.Root, { open, onOpenChange: setOpen, className: cn("flex flex-col", className), children: [
2280
+ return /* @__PURE__ */ jsxs32(Collapsible.Root, { open, onOpenChange: setOpen, className: cn("flex flex-col", className), children: [
2252
2281
  /* @__PURE__ */ jsx47(SectionHeader, { title, chevron: true, isExpanded: open, trailing, actions, showActions, className: "shrink-0", render: /* @__PURE__ */ jsx47(Collapsible.Trigger, {}) }),
2253
2282
  /* @__PURE__ */ jsx47(
2254
2283
  Collapsible.Panel,
@@ -2263,7 +2292,7 @@ function CollapsibleSection({ title, defaultOpen = true, open: openProp, onOpenC
2263
2292
 
2264
2293
  // src/Tabs.tsx
2265
2294
  import { Tabs as BaseTabs } from "@base-ui/react/tabs";
2266
- import { jsx as jsx48, jsxs as jsxs32 } from "react/jsx-runtime";
2295
+ import { jsx as jsx48, jsxs as jsxs33 } from "react/jsx-runtime";
2267
2296
  function Tabs({ tabs, active, onChange, size = "default", className, ...aria }) {
2268
2297
  return /* @__PURE__ */ jsx48(
2269
2298
  BaseTabs.Root,
@@ -2280,7 +2309,7 @@ function Tabs({ tabs, active, onChange, size = "default", className, ...aria })
2280
2309
  "aria-label": aria["aria-label"],
2281
2310
  "aria-labelledby": aria["aria-labelledby"],
2282
2311
  className: "flex items-center gap-2",
2283
- children: tabs.map((tab) => /* @__PURE__ */ jsxs32(
2312
+ children: tabs.map((tab) => /* @__PURE__ */ jsxs33(
2284
2313
  BaseTabs.Tab,
2285
2314
  {
2286
2315
  value: tab.id,
@@ -2293,7 +2322,7 @@ function Tabs({ tabs, active, onChange, size = "default", className, ...aria })
2293
2322
  ),
2294
2323
  children: [
2295
2324
  tab.icon,
2296
- /* @__PURE__ */ jsxs32("span", { className: "flex items-baseline", children: [
2325
+ /* @__PURE__ */ jsxs33("span", { className: "flex items-baseline", children: [
2297
2326
  tab.label,
2298
2327
  tab.count !== void 0 ? /* @__PURE__ */ jsx48("span", { className: "ml-2.5 font-mono text-caption tabular-nums text-text-secondary", children: tab.count }) : null
2299
2328
  ] })
@@ -2308,16 +2337,16 @@ function Tabs({ tabs, active, onChange, size = "default", className, ...aria })
2308
2337
  }
2309
2338
 
2310
2339
  // src/Toast.tsx
2311
- import { createContext as createContext2, useCallback as useCallback3, useContext as useContext2, useEffect as useEffect2, useMemo as useMemo3, useState as useState8 } from "react";
2312
- import { createPortal } from "react-dom";
2340
+ import { createContext as createContext2, useContext as useContext2, useMemo as useMemo3 } from "react";
2341
+ import { Toast as BaseToast } from "@base-ui/react/toast";
2313
2342
  import { IconAlertCircle as IconAlertCircle2, IconCircleCheck, IconCircleX } from "@tabler/icons-react";
2314
- import { jsx as jsx49, jsxs as jsxs33 } from "react/jsx-runtime";
2343
+ import { jsx as jsx49, jsxs as jsxs34 } from "react/jsx-runtime";
2315
2344
  var SURFACE_STYLES = {
2316
- success: "bg-success-muted signal:bg-bg-inset signal:border signal:border-border-default signal:shadow-[shadow:var(--shadow-md)]",
2317
- brand: "bg-accent-muted signal:bg-bg-inset signal:border signal:border-border-default signal:shadow-[shadow:var(--shadow-md)]",
2318
- neutral: "bg-bg-inset border border-border-subtle signal:border-border-default signal:shadow-[shadow:var(--shadow-md)]",
2319
- warning: "bg-warning-muted signal:bg-bg-inset signal:border signal:border-border-default signal:shadow-[shadow:var(--shadow-md)]",
2320
- error: "bg-error-muted signal:bg-bg-inset signal:border signal:border-border-default signal:shadow-[shadow:var(--shadow-md)]"
2345
+ success: "bg-success-muted signal:bg-bg-inset signal:border signal:border-border-default signal:shadow-md",
2346
+ brand: "bg-accent-muted signal:bg-bg-inset signal:border signal:border-border-default signal:shadow-md",
2347
+ neutral: "bg-bg-inset border border-border-subtle signal:border-border-default signal:shadow-md",
2348
+ warning: "bg-warning-muted signal:bg-bg-inset signal:border signal:border-border-default signal:shadow-md",
2349
+ error: "bg-error-muted signal:bg-bg-inset signal:border signal:border-border-default signal:shadow-md"
2321
2350
  };
2322
2351
  var ICONS = {
2323
2352
  success: IconCircleCheck,
@@ -2343,82 +2372,90 @@ var ACTION_BORDER_STYLES = {
2343
2372
  warning: "signal:border signal:border-border-default signal:hover:border-border-strong",
2344
2373
  error: "signal:border signal:border-border-default signal:hover:border-border-strong"
2345
2374
  };
2375
+ var LABEL_CLASSES = "text-body-2 text-text-primary whitespace-nowrap";
2376
+ var pillClassName = (type, hasAction, className) => cn(
2377
+ "inline-flex items-center min-h-[32px] pl-2 py-1 rounded-lg shadow-lg",
2378
+ // Without an action the label needs real right padding; the action
2379
+ // button brings its own edge, so the tight pr-1 only applies there.
2380
+ hasAction ? "pr-1 gap-[46px]" : "pr-3",
2381
+ SURFACE_STYLES[type],
2382
+ className
2383
+ );
2384
+ var actionClassName = (type) => cn(
2385
+ "h-6 flex items-center justify-center gap-1 px-1 py-1 rounded-md shrink-0 transition-colors",
2386
+ ACTION_BORDER_STYLES[type],
2387
+ type === "neutral" ? "hover:border-border-strong" : "hover:opacity-80"
2388
+ );
2389
+ function LeadingIcon({ type }) {
2390
+ const Icon = ICONS[type];
2391
+ return /* @__PURE__ */ jsx49(Icon, { size: 16, stroke: 1.5, className: cn("text-text-primary shrink-0", ICON_STYLES[type]) });
2392
+ }
2393
+ var ACTION_LABEL_CLASSES = "text-btn-small text-text-primary whitespace-nowrap";
2346
2394
  function Toast({ label, type = "neutral", leadingIcon = true, actionLabel, onAction, className }) {
2347
2395
  const hasAction = !!(actionLabel && onAction);
2348
- const LeadingIcon = ICONS[type];
2349
- return /* @__PURE__ */ jsxs33(
2350
- "div",
2351
- {
2352
- className: cn(
2353
- "inline-flex items-center min-h-[32px] pl-2 py-1 rounded-lg shadow-lg",
2354
- // Without an action the label needs real right padding; the action
2355
- // button brings its own edge, so the tight pr-1 only applies there.
2356
- hasAction ? "pr-1 gap-[46px]" : "pr-3",
2357
- SURFACE_STYLES[type],
2358
- className
2359
- ),
2360
- children: [
2361
- /* @__PURE__ */ jsxs33("div", { className: "flex items-center gap-2 shrink-0", children: [
2362
- leadingIcon && /* @__PURE__ */ jsx49(LeadingIcon, { size: 16, stroke: 1.5, className: cn("text-text-primary shrink-0", ICON_STYLES[type]) }),
2363
- /* @__PURE__ */ jsx49("span", { className: "font-normal text-[14px] leading-[1.4] text-text-primary whitespace-nowrap", children: label })
2364
- ] }),
2365
- hasAction && /* @__PURE__ */ jsx49(
2366
- "button",
2367
- {
2368
- type: "button",
2369
- onClick: onAction,
2370
- className: cn(
2371
- "h-6 flex items-center justify-center gap-1 px-1 py-1 rounded-md shrink-0 transition-colors",
2372
- ACTION_BORDER_STYLES[type],
2373
- type === "neutral" ? "hover:border-border-strong" : "hover:opacity-80"
2374
- ),
2375
- children: /* @__PURE__ */ jsx49("span", { className: "font-medium text-[12px] leading-[12px] text-text-primary whitespace-nowrap", children: actionLabel })
2376
- }
2377
- )
2378
- ]
2379
- }
2380
- );
2396
+ return /* @__PURE__ */ jsxs34("div", { className: pillClassName(type, hasAction, className), children: [
2397
+ /* @__PURE__ */ jsxs34("div", { className: "flex items-center gap-2 shrink-0", children: [
2398
+ leadingIcon && /* @__PURE__ */ jsx49(LeadingIcon, { type }),
2399
+ /* @__PURE__ */ jsx49("span", { className: LABEL_CLASSES, children: label })
2400
+ ] }),
2401
+ hasAction && /* @__PURE__ */ jsx49("button", { type: "button", onClick: onAction, className: actionClassName(type), children: /* @__PURE__ */ jsx49("span", { className: ACTION_LABEL_CLASSES, children: actionLabel }) })
2402
+ ] });
2381
2403
  }
2382
2404
  var ToastContext = createContext2(null);
2383
- var toastSeq = 0;
2405
+ var VISIBLE_TOASTS = 3;
2384
2406
  function ToastProvider({ children }) {
2385
- const [toast, setToast] = useState8(null);
2386
- const showToast = useCallback3((opts) => {
2387
- setToast({ ...opts, id: ++toastSeq });
2388
- }, []);
2389
- const dismissToast = useCallback3(() => {
2390
- setToast(null);
2391
- }, []);
2392
- useEffect2(() => {
2393
- if (!toast) return;
2394
- const duration = toast.durationMs ?? 5e3;
2395
- if (duration <= 0) return;
2396
- const timer = setTimeout(() => {
2397
- setToast((current) => current?.id === toast.id ? null : current);
2398
- }, duration);
2399
- return () => clearTimeout(timer);
2400
- }, [toast]);
2401
- const value = useMemo3(() => ({ showToast, dismissToast }), [showToast, dismissToast]);
2402
- return /* @__PURE__ */ jsxs33(ToastContext.Provider, { value, children: [
2407
+ const manager = useMemo3(() => BaseToast.createToastManager(), []);
2408
+ const value = useMemo3(
2409
+ () => ({
2410
+ showToast: ({ label, type = "neutral", leadingIcon = true, actionLabel, onAction, durationMs = 5e3 }) => manager.add({
2411
+ title: label,
2412
+ type,
2413
+ timeout: durationMs,
2414
+ // A failure interrupts; everything else waits for a pause.
2415
+ priority: type === "error" ? "high" : "low",
2416
+ data: { leadingIcon, actionLabel, onAction }
2417
+ }),
2418
+ dismissToast: (id) => manager.close(id)
2419
+ }),
2420
+ [manager]
2421
+ );
2422
+ return /* @__PURE__ */ jsx49(ToastContext.Provider, { value, children: /* @__PURE__ */ jsxs34(BaseToast.Provider, { toastManager: manager, limit: VISIBLE_TOASTS, children: [
2403
2423
  children,
2404
- toast && createPortal(
2405
- /* @__PURE__ */ jsx49("div", { className: "fixed bottom-4 left-4 z-[100] pointer-events-none", children: /* @__PURE__ */ jsx49(
2406
- Toast,
2407
- {
2408
- className: "pointer-events-auto",
2409
- label: toast.label,
2410
- type: toast.type ?? "neutral",
2411
- leadingIcon: toast.leadingIcon ?? true,
2412
- actionLabel: toast.actionLabel,
2413
- onAction: toast.onAction ? () => {
2414
- toast.onAction?.();
2415
- dismissToast();
2416
- } : void 0
2417
- }
2418
- ) }),
2419
- document.body
2420
- )
2421
- ] });
2424
+ /* @__PURE__ */ jsx49(BaseToast.Portal, { children: /* @__PURE__ */ jsx49(BaseToast.Viewport, { className: "fixed bottom-4 left-4 z-[100] flex flex-col-reverse items-start gap-2 pointer-events-none", children: /* @__PURE__ */ jsx49(ToastList, {}) }) })
2425
+ ] }) });
2426
+ }
2427
+ function ToastList() {
2428
+ const { toasts, close } = BaseToast.useToastManager();
2429
+ return toasts.map((toast) => {
2430
+ const type = toast.type ?? "neutral";
2431
+ const { leadingIcon = true, actionLabel, onAction } = toast.data ?? {};
2432
+ return /* @__PURE__ */ jsxs34(
2433
+ BaseToast.Root,
2434
+ {
2435
+ toast,
2436
+ swipeDirection: ["left", "down"],
2437
+ className: pillClassName(type, !!actionLabel, "pointer-events-auto data-[limited]:hidden"),
2438
+ children: [
2439
+ /* @__PURE__ */ jsxs34("div", { className: "flex items-center gap-2 shrink-0", children: [
2440
+ leadingIcon && /* @__PURE__ */ jsx49(LeadingIcon, { type }),
2441
+ /* @__PURE__ */ jsx49(BaseToast.Title, { render: /* @__PURE__ */ jsx49("span", {}), className: LABEL_CLASSES })
2442
+ ] }),
2443
+ actionLabel && /* @__PURE__ */ jsx49(
2444
+ BaseToast.Action,
2445
+ {
2446
+ onClick: () => {
2447
+ onAction?.();
2448
+ close(toast.id);
2449
+ },
2450
+ className: actionClassName(type),
2451
+ children: /* @__PURE__ */ jsx49("span", { className: ACTION_LABEL_CLASSES, children: actionLabel })
2452
+ }
2453
+ )
2454
+ ]
2455
+ },
2456
+ toast.id
2457
+ );
2458
+ });
2422
2459
  }
2423
2460
  function useToast() {
2424
2461
  const ctx = useContext2(ToastContext);