@orangecheck/app-design 0.2.1 → 0.3.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.
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Slot } from '@radix-ui/react-slot';
2
2
  import { cva } from 'class-variance-authority';
3
- import { forwardRef, createContext, useContext, useId, isValidElement, cloneElement, createElement, useState, useRef, useEffect, useCallback } from 'react';
3
+ import { forwardRef, createContext, useContext, useRef, useState, useCallback, useEffect, useId, isValidElement, cloneElement, createElement, Children, useMemo } from 'react';
4
4
  import { clsx } from 'clsx';
5
5
  import { extendTailwindMerge } from 'tailwind-merge';
6
6
  import * as SeparatorPrimitive from '@radix-ui/react-separator';
@@ -12,7 +12,7 @@ import * as LabelPrimitive from '@radix-ui/react-label';
12
12
  import * as RadioGroupPrimitive from '@radix-ui/react-radio-group';
13
13
  import * as SelectPrimitive from '@radix-ui/react-select';
14
14
  import * as SwitchPrimitive from '@radix-ui/react-switch';
15
- import { ChevronDown, Check, X, Copy, Menu, Sun, Moon, SunMoon } from 'lucide-react';
15
+ import { ChevronDown, Check, X, Copy, Menu, ChevronRight, Sun, Moon, SunMoon } from 'lucide-react';
16
16
  import * as DialogPrimitive from '@radix-ui/react-dialog';
17
17
  import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
18
18
  import * as PopoverPrimitive from '@radix-ui/react-popover';
@@ -100,7 +100,26 @@ function Spinner({ className, label }) {
100
100
  );
101
101
  }
102
102
  function Skeleton({ className, ...props }) {
103
- return /* @__PURE__ */ jsx("div", { "data-ui": "skeleton", className: cn("animate-pulse rounded-lg bg-muted", className), ...props });
103
+ return /* @__PURE__ */ jsx(
104
+ "div",
105
+ {
106
+ "data-ui": "skeleton",
107
+ className: cn("animate-pulse rounded-lg bg-[var(--oca-skeleton)]", className),
108
+ ...props
109
+ }
110
+ );
111
+ }
112
+ function useTimedOut(active, ms = 12e3) {
113
+ const [timedOut, setTimedOut] = useState(false);
114
+ useEffect(() => {
115
+ if (!active) {
116
+ setTimedOut(false);
117
+ return;
118
+ }
119
+ const t = setTimeout(() => setTimedOut(true), ms);
120
+ return () => clearTimeout(t);
121
+ }, [active, ms]);
122
+ return timedOut;
104
123
  }
105
124
  var Separator = forwardRef(function Separator2({ className, orientation = "horizontal", decorative = true, ...props }, ref) {
106
125
  return /* @__PURE__ */ jsx(
@@ -173,7 +192,10 @@ var buttonVariants = cva(
173
192
  "inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-full font-medium",
174
193
  "transition-[background-color,border-color,color,box-shadow,transform] duration-150",
175
194
  "outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
176
- "active:translate-y-px disabled:pointer-events-none disabled:opacity-45",
195
+ "active:translate-y-px disabled:pointer-events-none",
196
+ // Disabled is one look for every variant: a quiet grey pill, never a
197
+ // faded black or orange slab that reads as broken.
198
+ "disabled:border disabled:border-border disabled:bg-muted disabled:text-oca-subtle disabled:shadow-none",
177
199
  "[&_svg]:pointer-events-none [&_svg]:size-[1.1em] [&_svg]:shrink-0"
178
200
  ],
179
201
  {
@@ -219,6 +241,7 @@ var Button = forwardRef(function Button2({ className, variant, size, asChild = f
219
241
  }
220
242
  );
221
243
  });
244
+ var GOOD_DOT = "border-border bg-card text-foreground before:size-1.5 before:shrink-0 before:rounded-full before:bg-success before:content-['']";
222
245
  var badgeVariants = cva(
223
246
  "inline-flex h-6 shrink-0 items-center gap-1.5 whitespace-nowrap rounded-full border px-2.5 text-[0.8125rem] font-medium leading-none",
224
247
  {
@@ -227,10 +250,13 @@ var badgeVariants = cva(
227
250
  neutral: "border-border bg-card text-foreground",
228
251
  muted: "border-transparent bg-muted text-muted-foreground",
229
252
  brand: "border-transparent bg-[color-mix(in_oklab,var(--oca-orange)_12%,var(--card))] text-oca-accent-ink",
230
- success: "border-transparent bg-[color-mix(in_oklab,var(--success)_12%,var(--card))] text-success",
231
- warning: "border-transparent bg-[color-mix(in_oklab,var(--warning)_14%,var(--card))] text-warning",
232
253
  danger: "border-transparent bg-[color-mix(in_oklab,var(--destructive)_12%,var(--card))] text-destructive",
233
- info: "border-transparent bg-[color-mix(in_oklab,var(--info)_12%,var(--card))] text-info",
254
+ // A good state is a neutral pill with a green dot, not a green pill.
255
+ success: GOOD_DOT,
256
+ // Aliases kept so older call sites keep compiling: attention is
257
+ // the brand accent, information is neutral.
258
+ warning: "border-transparent bg-[color-mix(in_oklab,var(--oca-orange)_12%,var(--card))] text-oca-accent-ink",
259
+ info: "border-border bg-card text-foreground",
234
260
  ink: "border-transparent bg-oca-ink text-oca-ink-foreground",
235
261
  onInk: "border-white/15 bg-white/5 text-white/90"
236
262
  }
@@ -341,7 +367,7 @@ var Label = forwardRef(function Label2({ className, ...props }, ref) {
341
367
  }
342
368
  );
343
369
  });
344
- function Field({ label, hint, error, children, className, hideLabel }) {
370
+ function Field({ label, hint, optional, error, children, className, hideLabel }) {
345
371
  const id = useId();
346
372
  const hintId = hint ? `${id}-hint` : void 0;
347
373
  const errorId = error ? `${id}-error` : void 0;
@@ -352,9 +378,12 @@ function Field({ label, hint, error, children, className, hideLabel }) {
352
378
  "aria-invalid": error ? true : void 0
353
379
  }) : children;
354
380
  return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-2", className), children: [
355
- /* @__PURE__ */ jsx(Label, { htmlFor: id, className: hideLabel ? "sr-only" : void 0, children: label }),
356
- hint ? /* @__PURE__ */ jsx("p", { id: hintId, className: "text-[0.8125rem] leading-snug text-muted-foreground", children: hint }) : null,
381
+ /* @__PURE__ */ jsxs(Label, { htmlFor: id, className: hideLabel ? "sr-only" : "flex items-baseline gap-2", children: [
382
+ label,
383
+ optional ? /* @__PURE__ */ jsx("span", { className: "text-[0.8125rem] font-normal text-muted-foreground", children: "Optional" }) : null
384
+ ] }),
357
385
  control,
386
+ hint ? /* @__PURE__ */ jsx("p", { id: hintId, className: "text-[0.8125rem] leading-snug text-muted-foreground", children: hint }) : null,
358
387
  error ? /* @__PURE__ */ jsx("p", { id: errorId, role: "alert", className: "text-[0.8125rem] leading-snug text-destructive", children: error }) : null
359
388
  ] });
360
389
  }
@@ -631,23 +660,68 @@ var DropdownMenuLabel = forwardRef(function DropdownMenuLabel2({ className, ...p
631
660
  var DropdownMenuSeparator = forwardRef(function DropdownMenuSeparator2({ className, ...props }, ref) {
632
661
  return /* @__PURE__ */ jsx(DropdownMenuPrimitive.Separator, { ref, className: cn("my-1.5 h-px bg-border", className), ...props });
633
662
  });
663
+ function ScrollFade({ fade = "var(--card)", className, innerClassName, children, ...props }) {
664
+ const ref = useRef(null);
665
+ const [edges, setEdges] = useState({ left: false, right: false });
666
+ const measure = useCallback(() => {
667
+ const el = ref.current;
668
+ if (!el) return;
669
+ const left = el.scrollLeft > 1;
670
+ const right = el.scrollLeft + el.clientWidth < el.scrollWidth - 1;
671
+ setEdges((e) => e.left === left && e.right === right ? e : { left, right });
672
+ }, []);
673
+ useEffect(() => {
674
+ const el = ref.current;
675
+ if (!el) return;
676
+ measure();
677
+ const ro = new ResizeObserver(measure);
678
+ ro.observe(el);
679
+ if (el.firstElementChild) ro.observe(el.firstElementChild);
680
+ return () => ro.disconnect();
681
+ }, [measure]);
682
+ return /* @__PURE__ */ jsxs("div", { className: cn("relative min-w-0", className), ...props, children: [
683
+ /* @__PURE__ */ jsx("div", { ref, onScroll: measure, className: cn("overflow-x-auto overscroll-x-contain", innerClassName), children }),
684
+ /* @__PURE__ */ jsx(
685
+ "span",
686
+ {
687
+ "aria-hidden": true,
688
+ className: cn(
689
+ "pointer-events-none absolute inset-y-0 left-0 w-8 transition-opacity duration-150",
690
+ edges.left ? "opacity-100" : "opacity-0"
691
+ ),
692
+ style: { background: `linear-gradient(to right, ${fade}, transparent)` }
693
+ }
694
+ ),
695
+ /* @__PURE__ */ jsx(
696
+ "span",
697
+ {
698
+ "aria-hidden": true,
699
+ className: cn(
700
+ "pointer-events-none absolute inset-y-0 right-0 w-10 transition-opacity duration-150",
701
+ edges.right ? "opacity-100" : "opacity-0"
702
+ ),
703
+ style: { background: `linear-gradient(to left, ${fade}, transparent)` }
704
+ }
705
+ )
706
+ ] });
707
+ }
634
708
  var LookContext = createContext("pill");
635
709
  var Tabs = forwardRef(function Tabs2({ look = "pill", ...props }, ref) {
636
710
  return /* @__PURE__ */ jsx(LookContext.Provider, { value: look, children: /* @__PURE__ */ jsx(TabsPrimitive.Root, { ref, ...props }) });
637
711
  });
638
712
  var TabsList = forwardRef(function TabsList2({ className, ...props }, ref) {
639
713
  const look = useContext(LookContext);
640
- return /* @__PURE__ */ jsx(
714
+ return /* @__PURE__ */ jsx(ScrollFade, { fade: "var(--background)", className: look === "pill" ? "w-fit max-w-full" : "w-full", children: /* @__PURE__ */ jsx(
641
715
  TabsPrimitive.List,
642
716
  {
643
717
  ref,
644
718
  className: cn(
645
- look === "pill" ? "inline-flex max-w-full items-center gap-1 overflow-x-auto rounded-full bg-muted p-1" : "flex max-w-full items-center gap-6 overflow-x-auto border-b border-border",
719
+ look === "pill" ? "inline-flex w-max items-center gap-1 rounded-full bg-muted p-1" : "flex w-max min-w-full items-center gap-6 border-b border-border",
646
720
  className
647
721
  ),
648
722
  ...props
649
723
  }
650
- );
724
+ ) });
651
725
  });
652
726
  var TabsTrigger = forwardRef(function TabsTrigger2({ className, ...props }, ref) {
653
727
  const look = useContext(LookContext);
@@ -853,7 +927,7 @@ function Prose({ className, ...props }) {
853
927
  {
854
928
  className: cn(
855
929
  "max-w-[42rem] text-[1.0625rem] leading-[1.7] text-muted-foreground",
856
- "[&_h2]:oca-display-3 [&_h2]:mb-4 [&_h2]:mt-14 [&_h2]:text-foreground",
930
+ "[&_h2]:oca-display-3 [&_h2]:mb-4 [&_h2]:mt-14 [&_h2]:scroll-mt-24 [&_h2]:text-foreground",
857
931
  "[&_h3]:oca-title [&_h3]:mb-3 [&_h3]:mt-10 [&_h3]:text-foreground",
858
932
  "[&_p]:my-4 [&_strong]:font-medium [&_strong]:text-foreground",
859
933
  "[&_a]:text-foreground [&_a]:underline [&_a]:decoration-border [&_a]:underline-offset-4 hover:[&_a]:decoration-foreground",
@@ -869,7 +943,9 @@ var sectionVariants = cva("relative w-full overflow-x-clip", {
869
943
  tone: {
870
944
  canvas: "bg-background text-foreground",
871
945
  card: "bg-card text-card-foreground",
872
- ink: "bg-oca-ink text-oca-ink-foreground",
946
+ // The band line is transparent in light; in dark it keeps the ink
947
+ // band from melting into the canvas.
948
+ ink: "border-y border-[var(--oca-band-line)] bg-oca-ink text-oca-ink-foreground",
873
949
  brand: "bg-brand text-brand-foreground"
874
950
  },
875
951
  space: {
@@ -904,6 +980,120 @@ function SectionIntro({
904
980
  }
905
981
  );
906
982
  }
983
+ function PageHero({
984
+ eyebrow,
985
+ title,
986
+ lead,
987
+ actions,
988
+ art,
989
+ meta,
990
+ children,
991
+ variant = "page",
992
+ size = "lg",
993
+ className
994
+ }) {
995
+ if (variant === "document") {
996
+ return /* @__PURE__ */ jsx(Section, { space: "none", className: cn("pb-12 pt-12 md:pb-16 md:pt-20", className), children: /* @__PURE__ */ jsx(DocHeader, { className: "mx-auto max-w-[42rem]", ...{ eyebrow, title, lead, meta, actions }, children }) });
997
+ }
998
+ return /* @__PURE__ */ jsx(Section, { space: "none", className: cn("pb-14 pt-12 md:pb-20 md:pt-20", className), children: /* @__PURE__ */ jsxs("div", { className: cn("grid grid-cols-1 gap-10", art && "items-center md:grid-cols-12"), children: [
999
+ /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col items-start gap-6", art ? "md:col-span-7" : "max-w-[52rem]"), children: [
1000
+ eyebrow ? /* @__PURE__ */ jsx("p", { className: "oca-eyebrow", children: eyebrow }) : null,
1001
+ /* @__PURE__ */ jsx("h1", { className: size === "xl" ? "oca-display-1" : "oca-display-2", children: title }),
1002
+ lead ? /* @__PURE__ */ jsx("p", { className: "oca-lead max-w-[38rem]", children: lead }) : null,
1003
+ meta ? /* @__PURE__ */ jsx("p", { className: "text-[0.875rem] text-muted-foreground", children: meta }) : null,
1004
+ actions ? /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-3", children: actions }) : null,
1005
+ children
1006
+ ] }),
1007
+ art ? /* @__PURE__ */ jsx("div", { className: "md:col-span-5", children: art }) : null
1008
+ ] }) });
1009
+ }
1010
+ function DocHeader({
1011
+ eyebrow,
1012
+ title,
1013
+ lead,
1014
+ meta,
1015
+ actions,
1016
+ children,
1017
+ className
1018
+ }) {
1019
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-5", className), children: [
1020
+ eyebrow ? /* @__PURE__ */ jsx("p", { className: "oca-eyebrow", children: eyebrow }) : null,
1021
+ /* @__PURE__ */ jsx("h1", { className: "oca-display-2", children: title }),
1022
+ lead ? /* @__PURE__ */ jsx("p", { className: "oca-lead", children: lead }) : null,
1023
+ meta ? /* @__PURE__ */ jsx("p", { className: "text-[0.875rem] text-muted-foreground", children: meta }) : null,
1024
+ actions ? /* @__PURE__ */ jsx("div", { className: "mt-1 flex flex-wrap gap-3", children: actions }) : null,
1025
+ children
1026
+ ] });
1027
+ }
1028
+ function useActiveHeading(ids) {
1029
+ const [active, setActive] = useState(ids[0]);
1030
+ const key = ids.join("|");
1031
+ useEffect(() => {
1032
+ const els = key.split("|").map((id) => document.getElementById(id)).filter((el) => el !== null);
1033
+ if (els.length === 0) return;
1034
+ const io = new IntersectionObserver(
1035
+ (entries) => {
1036
+ const hit = entries.filter((e) => e.isIntersecting).sort((a, b) => a.boundingClientRect.top - b.boundingClientRect.top)[0];
1037
+ if (hit) setActive(hit.target.id);
1038
+ },
1039
+ { rootMargin: "-80px 0px -65% 0px" }
1040
+ );
1041
+ els.forEach((el) => io.observe(el));
1042
+ return () => io.disconnect();
1043
+ }, [key]);
1044
+ return active;
1045
+ }
1046
+ function DocLayout({
1047
+ toc,
1048
+ header,
1049
+ children,
1050
+ className
1051
+ }) {
1052
+ const active = useActiveHeading(toc?.map((t) => t.id) ?? []);
1053
+ const links = () => toc?.map((t) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
1054
+ "a",
1055
+ {
1056
+ href: `#${t.id}`,
1057
+ "aria-current": active === t.id ? "location" : void 0,
1058
+ className: cn(
1059
+ "block border-l py-1.5 pl-4 text-[0.875rem] leading-snug transition-colors",
1060
+ active === t.id ? "border-foreground text-foreground" : "border-border text-muted-foreground hover:text-foreground"
1061
+ ),
1062
+ children: t.label
1063
+ }
1064
+ ) }, t.id));
1065
+ const hasToc = !!toc && toc.length > 0;
1066
+ return /* @__PURE__ */ jsx("div", { className: cn("oca-container pb-24", header ? "pt-12 md:pt-20" : null, className), children: /* @__PURE__ */ jsxs(
1067
+ "div",
1068
+ {
1069
+ className: cn(
1070
+ "mx-auto grid grid-cols-1 gap-8",
1071
+ hasToc ? "max-w-[42rem] lg:max-w-[64rem] lg:grid-cols-[13rem_minmax(0,42rem)] lg:gap-x-16 lg:gap-y-10" : "max-w-[42rem]"
1072
+ ),
1073
+ children: [
1074
+ header ? /* @__PURE__ */ jsx("div", { className: cn(hasToc && "lg:col-start-2", "pb-4"), children: header }) : null,
1075
+ hasToc ? /* @__PURE__ */ jsxs(Fragment, { children: [
1076
+ /* @__PURE__ */ jsxs(
1077
+ "nav",
1078
+ {
1079
+ "aria-label": "On this page",
1080
+ className: cn("sticky top-24 hidden self-start lg:block", header && "lg:row-start-2"),
1081
+ children: [
1082
+ /* @__PURE__ */ jsx("p", { className: "mb-3 text-[0.875rem] font-medium", children: "On this page" }),
1083
+ /* @__PURE__ */ jsx("ul", { children: links() })
1084
+ ]
1085
+ }
1086
+ ),
1087
+ /* @__PURE__ */ jsxs("details", { className: "group rounded-2xl border border-border bg-card px-4 py-3 lg:hidden", children: [
1088
+ /* @__PURE__ */ jsx("summary", { className: "cursor-pointer list-none text-[0.9375rem] font-medium marker:hidden", children: "On this page" }),
1089
+ /* @__PURE__ */ jsx("ul", { className: "mt-3", children: links() })
1090
+ ] })
1091
+ ] }) : null,
1092
+ /* @__PURE__ */ jsx("div", { className: cn("min-w-0", hasToc && "lg:col-start-2", hasToc && header && "lg:row-start-2"), children })
1093
+ ]
1094
+ }
1095
+ ) });
1096
+ }
907
1097
  var pad = (n) => String(n + 1).padStart(2, "0");
908
1098
  function StepGrid({ items, look = "cards", className }) {
909
1099
  const cols = items.length >= 3 ? "md:grid-cols-3" : items.length === 2 ? "md:grid-cols-2" : "";
@@ -931,322 +1121,299 @@ function StepGrid({ items, look = "cards", className }) {
931
1121
  ] }) }, i)
932
1122
  ) });
933
1123
  }
934
- var KIND = {
935
- package: "text-oca-code-package",
936
- tag: "text-oca-code-tag",
937
- link: "text-oca-code-link"
1124
+ var ShellContext = createContext({});
1125
+ function useShellPlace() {
1126
+ return useContext(ShellContext);
1127
+ }
1128
+ function PageHeader({
1129
+ eyebrow,
1130
+ title,
1131
+ description,
1132
+ actions,
1133
+ className
1134
+ }) {
1135
+ const place = useShellPlace();
1136
+ const eb = eyebrow === void 0 ? place.section : eyebrow;
1137
+ return /* @__PURE__ */ jsxs("header", { className: cn("flex flex-col gap-5 md:flex-row md:items-end md:justify-between", className), children: [
1138
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 max-w-[44rem] flex-col gap-2.5", children: [
1139
+ eb ? /* @__PURE__ */ jsx("p", { className: "oca-eyebrow", children: eb }) : null,
1140
+ /* @__PURE__ */ jsx("h1", { className: "oca-display-3", children: title }),
1141
+ description ? /* @__PURE__ */ jsx("p", { className: "oca-body max-w-[40rem] text-[1.0625rem]", children: description }) : null
1142
+ ] }),
1143
+ actions ? /* @__PURE__ */ jsx("div", { className: "flex flex-wrap items-center gap-2.5 md:shrink-0 md:justify-end", children: actions }) : null
1144
+ ] });
1145
+ }
1146
+ var InStatGrid = createContext(false);
1147
+ function StatCard({ label, value, hint, className }) {
1148
+ const inGrid = useContext(InStatGrid);
1149
+ return /* @__PURE__ */ jsxs(
1150
+ "div",
1151
+ {
1152
+ "data-ui": "stat",
1153
+ className: cn(
1154
+ "rounded-[1.25rem] border border-border bg-card p-5 md:p-6",
1155
+ // In a grid, label, value and hint each share a row with their
1156
+ // neighbours, so values line up whatever wraps above them.
1157
+ inGrid ? "row-span-3 grid grid-rows-subgrid gap-1.5" : "flex flex-col gap-2",
1158
+ className
1159
+ ),
1160
+ children: [
1161
+ /* @__PURE__ */ jsx("span", { className: "text-[0.875rem] leading-snug text-muted-foreground", children: label }),
1162
+ /* @__PURE__ */ jsx("span", { className: "self-end break-words oca-tabular text-[1.5rem] leading-tight tracking-[-0.02em] md:text-[1.75rem]", children: value }),
1163
+ hint ? /* @__PURE__ */ jsx("span", { className: "text-[0.8125rem] leading-snug text-muted-foreground", children: hint }) : inGrid ? /* @__PURE__ */ jsx("span", { "aria-hidden": true }) : null
1164
+ ]
1165
+ }
1166
+ );
1167
+ }
1168
+ var MD_COLS = {
1169
+ 1: "md:grid-cols-1",
1170
+ 2: "md:grid-cols-2",
1171
+ 3: "md:grid-cols-3",
1172
+ 4: "md:grid-cols-4"
938
1173
  };
939
- function PackageCard({ items, className }) {
1174
+ var LG_COLS = {
1175
+ 1: "lg:grid-cols-1",
1176
+ 2: "lg:grid-cols-2",
1177
+ 3: "lg:grid-cols-3",
1178
+ 4: "lg:grid-cols-4",
1179
+ 5: "lg:grid-cols-5"
1180
+ };
1181
+ var MD_SPAN = {
1182
+ 1: "md:col-span-1",
1183
+ 2: "md:col-span-2",
1184
+ 3: "md:col-span-3",
1185
+ 4: "md:col-span-4"
1186
+ };
1187
+ var LG_SPAN = {
1188
+ 1: "lg:col-span-1",
1189
+ 2: "lg:col-span-2",
1190
+ 3: "lg:col-span-3",
1191
+ 4: "lg:col-span-4"
1192
+ };
1193
+ function statColumns(n) {
1194
+ if (n <= 5) return Math.max(1, n);
1195
+ if (n % 4 === 0) return 4;
1196
+ if (n % 3 === 0) return 3;
1197
+ return 4;
1198
+ }
1199
+ function lastSpan(n, cols) {
1200
+ const rest = n % cols;
1201
+ return rest === 0 ? 1 : cols - rest + 1;
1202
+ }
1203
+ function EmptyLine({ children, className }) {
940
1204
  return /* @__PURE__ */ jsx(
1205
+ "p",
1206
+ {
1207
+ className: cn(
1208
+ "rounded-[1.25rem] border border-dashed border-oca-hairline-strong px-5 py-4 text-[0.9375rem] text-muted-foreground",
1209
+ className
1210
+ ),
1211
+ children
1212
+ }
1213
+ );
1214
+ }
1215
+ function StatGrid({ columns, empty, isEmpty, className, children, ...props }) {
1216
+ const items = Children.toArray(children).filter(isValidElement);
1217
+ const n = items.length;
1218
+ const allZero = n > 0 && items.every((el) => "raw" in el.props && (el.props.raw === 0 || el.props.raw === null));
1219
+ if (isEmpty ?? allZero) return /* @__PURE__ */ jsx(EmptyLine, { className, children: empty ?? "Nothing here yet." });
1220
+ const lg = columns ?? statColumns(n);
1221
+ const md = lg > 4 ? 3 : lg;
1222
+ const mdSpan = lastSpan(n, md);
1223
+ const lgSpan = lastSpan(n, lg);
1224
+ return /* @__PURE__ */ jsx(InStatGrid.Provider, { value: true, children: /* @__PURE__ */ jsx(
941
1225
  "div",
942
1226
  {
943
1227
  className: cn(
944
- "grid gap-x-10 gap-y-7 rounded-[1.25rem] border border-oca-ink-line bg-oca-ink-card p-6 text-oca-ink-foreground md:grid-cols-2 md:p-9",
1228
+ "grid gap-3 md:gap-4",
1229
+ n === 1 ? "grid-cols-1" : "grid-cols-2",
1230
+ MD_COLS[md],
1231
+ LG_COLS[lg],
945
1232
  className
946
1233
  ),
947
- children: items.map((it, i) => {
948
- const code = /* @__PURE__ */ jsx("span", { className: cn("text-[0.9375rem]", KIND[it.kind ?? "package"]), children: it.code });
949
- return /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col gap-1.5", children: [
950
- /* @__PURE__ */ jsx("h3", { className: "text-[1.125rem] font-semibold tracking-[-0.01em] text-oca-ink-title", children: it.title }),
951
- it.href ? /* @__PURE__ */ jsx("a", { href: it.href, className: "w-fit underline decoration-transparent underline-offset-4 hover:decoration-current", children: code }) : code,
952
- it.note ? /* @__PURE__ */ jsxs("p", { className: "text-[0.9375rem] leading-relaxed text-oca-ink-subtle", children: [
953
- /* @__PURE__ */ jsx("span", { "aria-hidden": true, children: "// " }),
954
- it.note
955
- ] }) : null
956
- ] }, i);
1234
+ ...props,
1235
+ children: items.map((el, i) => {
1236
+ if (i !== n - 1) return el;
1237
+ const span = cn(
1238
+ n % 2 === 1 && n > 1 && "max-md:col-span-2",
1239
+ (mdSpan > 1 || lgSpan > 1) && MD_SPAN[mdSpan],
1240
+ (mdSpan > 1 || lgSpan > 1) && LG_SPAN[lgSpan]
1241
+ );
1242
+ return span ? cloneElement(el, { className: cn(el.props.className, span) }) : el;
957
1243
  })
958
1244
  }
959
- );
1245
+ ) });
960
1246
  }
961
- function CodeBlock({
962
- code,
1247
+ function KeyValueList({ items, className }) {
1248
+ return /* @__PURE__ */ jsx("dl", { className: cn("divide-y divide-border rounded-[1.25rem] border border-border bg-card", className), children: items.map((it, i) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1 px-5 py-3.5 sm:flex-row sm:items-baseline sm:gap-6", children: [
1249
+ /* @__PURE__ */ jsx("dt", { className: "shrink-0 text-[0.875rem] text-muted-foreground sm:w-48", children: it.label }),
1250
+ /* @__PURE__ */ jsx("dd", { className: cn("min-w-0 break-words text-[0.9375rem]", it.mono && "font-mono text-[0.875rem]"), children: it.value })
1251
+ ] }, i)) });
1252
+ }
1253
+ function DataTable({
1254
+ columns,
1255
+ rows,
1256
+ rowKey,
1257
+ empty,
963
1258
  caption,
1259
+ phone = "cards",
964
1260
  className
965
1261
  }) {
966
- return /* @__PURE__ */ jsxs("figure", { className: cn("overflow-hidden rounded-[1.25rem] border border-oca-ink-line bg-oca-ink-card", className), children: [
967
- caption ? /* @__PURE__ */ jsx("figcaption", { className: "border-b border-oca-ink-line px-5 py-3 text-[0.8125rem] text-oca-ink-subtle", children: caption }) : null,
968
- /* @__PURE__ */ jsx("pre", { className: "overflow-x-auto p-5 font-mono text-[0.875rem] leading-relaxed text-oca-ink-muted", children: /* @__PURE__ */ jsx("code", { children: code }) })
1262
+ if (rows.length === 0 && empty) return /* @__PURE__ */ jsx(Fragment, { children: empty });
1263
+ const primary = columns.find((c) => c.primary) ?? columns[0];
1264
+ const right = (c) => c.numeric || c.align === "end";
1265
+ const table = /* @__PURE__ */ jsx(
1266
+ "div",
1267
+ {
1268
+ className: cn(
1269
+ "overflow-hidden rounded-[1.25rem] border border-border bg-card",
1270
+ phone === "cards" && "max-sm:hidden",
1271
+ className
1272
+ ),
1273
+ children: /* @__PURE__ */ jsx(ScrollFade, { fade: "var(--card)", children: /* @__PURE__ */ jsxs("table", { className: "w-full border-collapse text-left text-[0.9375rem]", children: [
1274
+ caption ? /* @__PURE__ */ jsx("caption", { className: "sr-only", children: caption }) : null,
1275
+ /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsx("tr", { className: "border-b border-border", children: columns.map((c) => /* @__PURE__ */ jsx(
1276
+ "th",
1277
+ {
1278
+ scope: "col",
1279
+ style: { width: c.width, minWidth: c.minWidth },
1280
+ className: cn(
1281
+ "whitespace-nowrap px-5 py-3 text-[0.8125rem] font-medium text-muted-foreground",
1282
+ right(c) && "text-right",
1283
+ c.wide && "hidden md:table-cell"
1284
+ ),
1285
+ children: c.header
1286
+ },
1287
+ c.key
1288
+ )) }) }),
1289
+ /* @__PURE__ */ jsx("tbody", { className: "divide-y divide-border", children: rows.map((r, i) => /* @__PURE__ */ jsx("tr", { className: "transition-colors hover:bg-accent/60", children: columns.map((c) => /* @__PURE__ */ jsx(
1290
+ "td",
1291
+ {
1292
+ style: { minWidth: c.minWidth },
1293
+ className: cn(
1294
+ "px-5 py-3.5 align-middle",
1295
+ right(c) && "text-right",
1296
+ c.numeric && "whitespace-nowrap oca-tabular",
1297
+ c.wide && "hidden md:table-cell"
1298
+ ),
1299
+ children: c.truncate ? /* @__PURE__ */ jsx("div", { className: "truncate", style: { maxWidth: c.width ?? "16rem" }, children: c.cell(r) }) : c.cell(r)
1300
+ },
1301
+ c.key
1302
+ )) }, rowKey(r, i))) })
1303
+ ] }) })
1304
+ }
1305
+ );
1306
+ if (phone !== "cards") return table;
1307
+ const rest = columns.filter((c) => c !== primary && !c.hideOnPhone);
1308
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
1309
+ table,
1310
+ /* @__PURE__ */ jsx(
1311
+ "ul",
1312
+ {
1313
+ "aria-label": caption,
1314
+ className: cn("divide-y divide-border rounded-[1.25rem] border border-border bg-card sm:hidden", className),
1315
+ children: rows.map((r, i) => /* @__PURE__ */ jsxs("li", { className: "flex flex-col gap-2.5 px-4 py-4", children: [
1316
+ /* @__PURE__ */ jsx("div", { className: "min-w-0 break-words text-[0.9375rem] font-medium", children: primary?.cell(r) }),
1317
+ rest.length > 0 ? /* @__PURE__ */ jsx("dl", { className: "grid grid-cols-[minmax(5.5rem,auto)_minmax(0,1fr)] gap-x-4 gap-y-1.5 text-[0.875rem]", children: rest.map((c) => /* @__PURE__ */ jsxs("div", { className: "contents", children: [
1318
+ /* @__PURE__ */ jsx("dt", { className: "text-muted-foreground", children: c.header }),
1319
+ /* @__PURE__ */ jsx("dd", { className: cn("min-w-0 break-words", c.numeric && "oca-tabular"), children: c.cell(r) })
1320
+ ] }, c.key)) }) : null
1321
+ ] }, rowKey(r, i)))
1322
+ }
1323
+ )
969
1324
  ] });
970
1325
  }
971
- function SplitBar({
972
- segments,
973
- caption,
1326
+ function EmptyState({
1327
+ title,
1328
+ children,
1329
+ action,
1330
+ icon,
974
1331
  className
975
1332
  }) {
976
- return /* @__PURE__ */ jsxs("figure", { className: cn("flex flex-col gap-5", className), children: [
977
- caption ? /* @__PURE__ */ jsx("figcaption", { className: "text-[0.9375rem]", children: caption }) : null,
978
- /* @__PURE__ */ jsx("div", { className: "flex h-16 w-full gap-1.5 overflow-hidden rounded-[1.25rem] md:h-20", children: segments.map((s, i) => /* @__PURE__ */ jsx(
979
- "div",
980
- {
981
- className: cn(
982
- "flex min-w-[4.25rem] items-end rounded-[1rem] px-3 pb-2.5 md:px-4 md:pb-3",
983
- s.tone === "card" ? "bg-white text-oca-ink" : "bg-oca-ink text-white"
984
- ),
985
- style: { flexBasis: `${s.pct}%` },
986
- children: /* @__PURE__ */ jsxs("span", { className: "oca-tabular text-[1.25rem] leading-none tracking-[-0.02em] md:text-[1.875rem]", children: [
987
- s.pct,
988
- "%"
989
- ] })
990
- },
991
- i
992
- )) }),
993
- /* @__PURE__ */ jsx("dl", { className: "grid gap-x-8 gap-y-2 sm:grid-cols-2", children: segments.map((s, i) => /* @__PURE__ */ jsxs("div", { className: "flex items-baseline gap-2.5", children: [
994
- /* @__PURE__ */ jsxs("dt", { className: "sr-only", children: [
995
- s.pct,
996
- "%"
997
- ] }),
998
- /* @__PURE__ */ jsx(
999
- "span",
1000
- {
1001
- "aria-hidden": true,
1002
- className: cn(
1003
- "inline-block size-2.5 shrink-0 translate-y-[-1px] rounded-full",
1004
- s.tone === "card" ? "bg-white" : "bg-oca-ink"
1005
- )
1006
- }
1333
+ return /* @__PURE__ */ jsxs(
1334
+ "div",
1335
+ {
1336
+ className: cn(
1337
+ "flex flex-col items-center gap-3 rounded-[1.25rem] border border-dashed border-oca-hairline-strong px-6 py-10 text-center",
1338
+ className
1007
1339
  ),
1008
- /* @__PURE__ */ jsx("dd", { className: "text-[0.9375rem] leading-snug", children: s.label })
1009
- ] }, i)) })
1010
- ] });
1340
+ children: [
1341
+ icon ? /* @__PURE__ */ jsx("span", { className: "mb-1 flex size-11 items-center justify-center rounded-full bg-muted text-muted-foreground [&_svg]:size-5", children: icon }) : null,
1342
+ /* @__PURE__ */ jsx("h3", { className: "oca-title-sm", children: title }),
1343
+ children ? /* @__PURE__ */ jsx("div", { className: "oca-body max-w-md text-[0.9375rem]", children }) : null,
1344
+ action ? /* @__PURE__ */ jsx("div", { className: "mt-2 flex flex-wrap justify-center gap-3", children: action }) : null
1345
+ ]
1346
+ }
1347
+ );
1011
1348
  }
1012
- var LABEL = {
1013
- yes: "Yes",
1014
- testing: "In testing",
1015
- "not-yet": "Not yet",
1016
- no: "No"
1349
+ var NOTICE_KIND = {
1350
+ neutral: "neutral",
1351
+ info: "neutral",
1352
+ success: "neutral",
1353
+ brand: "brand",
1354
+ warning: "brand",
1355
+ danger: "danger"
1017
1356
  };
1018
- var TONE = {
1019
- yes: "text-oca-accent-ink",
1020
- testing: "text-foreground",
1021
- "not-yet": "text-muted-foreground",
1022
- no: "text-muted-foreground"
1023
- };
1024
- function TruthTable({
1025
- rows,
1026
- statusHeading = "Status",
1027
- whatHeading = "What",
1357
+ function Notice({
1358
+ tone = "neutral",
1359
+ title,
1360
+ children,
1361
+ action,
1028
1362
  className
1029
1363
  }) {
1030
- return /* @__PURE__ */ jsx("div", { className: cn("overflow-hidden rounded-xl border border-oca-hairline-strong", className), children: /* @__PURE__ */ jsxs("table", { className: "w-full border-collapse text-left text-[0.9375rem] md:text-[1rem]", children: [
1031
- /* @__PURE__ */ jsx("thead", { className: "bg-oca-table-head", children: /* @__PURE__ */ jsxs("tr", { children: [
1032
- /* @__PURE__ */ jsx("th", { scope: "col", className: "w-[30%] border-b border-oca-hairline-strong px-4 py-3 font-semibold md:w-[22%]", children: statusHeading }),
1033
- /* @__PURE__ */ jsx("th", { scope: "col", className: "border-b border-l border-oca-hairline-strong px-4 py-3 font-semibold", children: whatHeading })
1034
- ] }) }),
1035
- /* @__PURE__ */ jsx("tbody", { className: "bg-card", children: rows.map((r, i) => /* @__PURE__ */ jsxs("tr", { className: "align-top", children: [
1036
- /* @__PURE__ */ jsx(
1037
- "td",
1038
- {
1039
- className: cn(
1040
- "border-t border-oca-hairline-strong px-4 py-3 font-medium",
1041
- i === 0 && "border-t-0",
1042
- TONE[r.status]
1043
- ),
1044
- children: LABEL[r.status]
1045
- }
1046
- ),
1047
- /* @__PURE__ */ jsx(
1048
- "td",
1049
- {
1050
- className: cn(
1051
- "border-l border-t border-oca-hairline-strong px-4 py-3 leading-relaxed",
1052
- i === 0 && "border-t-0"
1053
- ),
1054
- children: r.what
1055
- }
1056
- )
1057
- ] }, i)) })
1058
- ] }) });
1059
- }
1060
- var INT = new Intl.NumberFormat("en-US", { maximumFractionDigits: 0 });
1061
- var COMPACT = new Intl.NumberFormat("en-US", { notation: "compact", maximumFractionDigits: 1 });
1062
- function satsText(value, opts = {}) {
1063
- if (value == null || !Number.isFinite(value)) return null;
1064
- const whole = Math.trunc(value);
1065
- const body = (opts.compact ? COMPACT : INT).format(Math.abs(whole));
1066
- const sign = whole < 0 ? "\u2212" : opts.signed && whole > 0 ? "+" : "";
1067
- const unit = opts.unit === "none" ? "" : whole === 1 || whole === -1 ? " sat" : " sats";
1068
- return `${sign}${body}${unit}`;
1069
- }
1070
- function Sats({ value, unit, compact, signed, unknown = "\u2014", className, ...props }) {
1071
- const text = satsText(value, { unit, compact, signed });
1072
- if (text === null) {
1073
- return /* @__PURE__ */ jsxs("span", { className: cn("oca-tabular text-muted-foreground", className), ...props, children: [
1074
- /* @__PURE__ */ jsx("span", { "aria-hidden": true, children: unknown }),
1075
- /* @__PURE__ */ jsx("span", { className: "sr-only", children: "unknown" })
1076
- ] });
1077
- }
1078
- return /* @__PURE__ */ jsx("span", { className: cn("oca-tabular whitespace-nowrap", className), ...props, children: text });
1079
- }
1080
- function UsdApprox({
1081
- sats,
1082
- usdPerBtc,
1083
- className
1084
- }) {
1085
- if (sats == null || usdPerBtc == null || !Number.isFinite(sats) || !Number.isFinite(usdPerBtc)) return null;
1086
- const usd = sats / 1e8 * usdPerBtc;
1087
- const text = new Intl.NumberFormat("en-US", {
1088
- style: "currency",
1089
- currency: "USD",
1090
- maximumFractionDigits: usd < 1 ? 4 : 2
1091
- }).format(usd);
1092
- return /* @__PURE__ */ jsxs("span", { className: cn("oca-tabular text-muted-foreground", className), children: [
1093
- "\u2248 ",
1094
- text
1095
- ] });
1096
- }
1097
- function SatsFigure({
1098
- label,
1099
- value,
1100
- hint,
1101
- className
1102
- }) {
1103
- return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-1.5", className), children: [
1104
- /* @__PURE__ */ jsx("span", { className: "text-[0.9375rem] text-muted-foreground", children: label }),
1105
- /* @__PURE__ */ jsxs("span", { className: "oca-display-3 oca-tabular", children: [
1106
- /* @__PURE__ */ jsx(Sats, { value, unit: "none" }),
1107
- /* @__PURE__ */ jsx("span", { className: "ml-2 text-[0.5em] tracking-normal text-muted-foreground", children: "sats" })
1108
- ] }),
1109
- hint ? /* @__PURE__ */ jsx("span", { className: "text-[0.875rem] text-muted-foreground", children: hint }) : null
1110
- ] });
1111
- }
1112
- function PageHeader({
1113
- eyebrow,
1114
- title,
1115
- description,
1116
- actions,
1117
- className
1118
- }) {
1119
- return /* @__PURE__ */ jsxs("header", { className: cn("flex flex-col gap-5 md:flex-row md:items-end md:justify-between", className), children: [
1120
- /* @__PURE__ */ jsxs("div", { className: "flex max-w-[44rem] flex-col gap-3", children: [
1121
- eyebrow ? /* @__PURE__ */ jsx("p", { className: "oca-eyebrow", children: eyebrow }) : null,
1122
- /* @__PURE__ */ jsx("h1", { className: "oca-display-3", children: title }),
1123
- description ? /* @__PURE__ */ jsx("p", { className: "oca-body text-[1.0625rem]", children: description }) : null
1124
- ] }),
1125
- actions ? /* @__PURE__ */ jsx("div", { className: "flex shrink-0 flex-wrap items-center gap-3", children: actions }) : null
1126
- ] });
1127
- }
1128
- function StatCard({
1129
- label,
1130
- value,
1131
- hint,
1132
- className
1133
- }) {
1134
- return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-2 rounded-[1.25rem] border border-border bg-card p-5 md:p-6", className), children: [
1135
- /* @__PURE__ */ jsx("span", { className: "text-[0.875rem] text-muted-foreground", children: label }),
1136
- /* @__PURE__ */ jsx("span", { className: "oca-tabular text-[1.75rem] leading-tight tracking-[-0.02em]", children: value }),
1137
- hint ? /* @__PURE__ */ jsx("span", { className: "text-[0.8125rem] leading-snug text-muted-foreground", children: hint }) : null
1138
- ] });
1139
- }
1140
- function StatGrid({ className, ...props }) {
1141
- return /* @__PURE__ */ jsx("div", { className: cn("grid grid-cols-2 gap-3 md:grid-cols-4 md:gap-4", className), ...props });
1142
- }
1143
- function KeyValueList({ items, className }) {
1144
- return /* @__PURE__ */ jsx("dl", { className: cn("divide-y divide-border rounded-[1.25rem] border border-border bg-card", className), children: items.map((it, i) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1 px-5 py-3.5 sm:flex-row sm:items-baseline sm:gap-6", children: [
1145
- /* @__PURE__ */ jsx("dt", { className: "shrink-0 text-[0.875rem] text-muted-foreground sm:w-48", children: it.label }),
1146
- /* @__PURE__ */ jsx("dd", { className: cn("min-w-0 break-words text-[0.9375rem]", it.mono && "font-mono text-[0.875rem]"), children: it.value })
1147
- ] }, i)) });
1148
- }
1149
- function DataTable({
1150
- columns,
1151
- rows,
1152
- rowKey,
1153
- empty,
1154
- caption,
1155
- className
1156
- }) {
1157
- if (rows.length === 0 && empty) return /* @__PURE__ */ jsx(Fragment, { children: empty });
1158
- return /* @__PURE__ */ jsx("div", { className: cn("overflow-x-auto rounded-[1.25rem] border border-border bg-card", className), children: /* @__PURE__ */ jsxs("table", { className: "w-full border-collapse text-left text-[0.9375rem]", children: [
1159
- caption ? /* @__PURE__ */ jsx("caption", { className: "sr-only", children: caption }) : null,
1160
- /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsx("tr", { className: "border-b border-border", children: columns.map((c) => /* @__PURE__ */ jsx(
1161
- "th",
1162
- {
1163
- scope: "col",
1164
- className: cn(
1165
- "whitespace-nowrap px-5 py-3 text-[0.8125rem] font-medium text-muted-foreground",
1166
- c.align === "end" && "text-right",
1167
- c.wide && "hidden md:table-cell"
1168
- ),
1169
- children: c.header
1170
- },
1171
- c.key
1172
- )) }) }),
1173
- /* @__PURE__ */ jsx("tbody", { className: "divide-y divide-border", children: rows.map((r, i) => /* @__PURE__ */ jsx("tr", { className: "transition-colors hover:bg-accent/60", children: columns.map((c) => /* @__PURE__ */ jsx(
1174
- "td",
1175
- {
1176
- className: cn(
1177
- "px-5 py-3.5 align-middle",
1178
- c.align === "end" && "text-right",
1179
- c.wide && "hidden md:table-cell"
1180
- ),
1181
- children: c.cell(r)
1182
- },
1183
- c.key
1184
- )) }, rowKey(r, i))) })
1185
- ] }) });
1186
- }
1187
- function EmptyState({
1188
- title,
1189
- children,
1190
- action,
1191
- className
1192
- }) {
1193
- return /* @__PURE__ */ jsxs(
1194
- "div",
1195
- {
1196
- className: cn(
1197
- "flex flex-col items-center gap-4 rounded-[1.25rem] border border-dashed border-oca-hairline-strong px-6 py-12 text-center",
1198
- className
1364
+ const kind = NOTICE_KIND[tone];
1365
+ return /* @__PURE__ */ jsxs(
1366
+ "div",
1367
+ {
1368
+ role: tone === "danger" || tone === "warning" ? "alert" : "note",
1369
+ "data-tone": kind,
1370
+ className: cn(
1371
+ "flex flex-col gap-3 rounded-2xl border border-border bg-card px-5 py-4 sm:flex-row sm:items-start sm:justify-between",
1372
+ kind === "danger" && "border-[color-mix(in_oklab,var(--destructive)_40%,var(--border))]",
1373
+ className
1199
1374
  ),
1200
1375
  children: [
1201
- /* @__PURE__ */ jsx(Mark, { size: 56 }),
1202
- /* @__PURE__ */ jsx("h3", { className: "oca-title-sm", children: title }),
1203
- children ? /* @__PURE__ */ jsx("div", { className: "oca-body max-w-md text-[0.9375rem]", children }) : null,
1204
- action ? /* @__PURE__ */ jsx("div", { className: "mt-1 flex flex-wrap justify-center gap-3", children: action }) : null
1376
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 gap-3", children: [
1377
+ kind !== "neutral" ? /* @__PURE__ */ jsx(
1378
+ "span",
1379
+ {
1380
+ "aria-hidden": true,
1381
+ className: cn(
1382
+ "mt-[0.45rem] size-2 shrink-0 rounded-full",
1383
+ kind === "brand" ? "bg-oca-orange" : "bg-destructive"
1384
+ )
1385
+ }
1386
+ ) : null,
1387
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col gap-1", children: [
1388
+ title ? /* @__PURE__ */ jsx("p", { className: cn("text-[0.9375rem] font-medium", kind === "danger" && "text-destructive"), children: title }) : null,
1389
+ children ? /* @__PURE__ */ jsx("div", { className: "text-[0.9375rem] leading-relaxed text-muted-foreground", children }) : null
1390
+ ] })
1391
+ ] }),
1392
+ action ? /* @__PURE__ */ jsx("div", { className: "shrink-0", children: action }) : null
1205
1393
  ]
1206
1394
  }
1207
1395
  );
1208
1396
  }
1209
- var NOTICE = {
1210
- neutral: "border-border bg-card",
1211
- info: "border-[color-mix(in_oklab,var(--info)_30%,var(--border))] bg-[color-mix(in_oklab,var(--info)_6%,var(--card))]",
1212
- success: "border-[color-mix(in_oklab,var(--success)_30%,var(--border))] bg-[color-mix(in_oklab,var(--success)_6%,var(--card))]",
1213
- warning: "border-[color-mix(in_oklab,var(--warning)_35%,var(--border))] bg-[color-mix(in_oklab,var(--warning)_7%,var(--card))]",
1214
- danger: "border-[color-mix(in_oklab,var(--destructive)_32%,var(--border))] bg-[color-mix(in_oklab,var(--destructive)_6%,var(--card))]",
1215
- brand: "border-[color-mix(in_oklab,var(--oca-orange)_35%,var(--border))] bg-[color-mix(in_oklab,var(--oca-orange)_7%,var(--card))]"
1216
- };
1217
- var NOTICE_TITLE = {
1218
- neutral: "text-foreground",
1219
- info: "text-info",
1220
- success: "text-success",
1221
- warning: "text-warning",
1222
- danger: "text-destructive",
1223
- brand: "text-oca-accent-ink"
1224
- };
1225
- function Notice({
1226
- tone = "neutral",
1227
- title,
1228
- children,
1229
- action,
1397
+ function LoadingBlock({
1398
+ rows = 3,
1399
+ timeoutMs = 12e3,
1400
+ onRetry,
1401
+ label = "Loading",
1230
1402
  className
1231
1403
  }) {
1232
- return /* @__PURE__ */ jsxs(
1233
- "div",
1234
- {
1235
- role: tone === "danger" || tone === "warning" ? "alert" : "note",
1236
- className: cn(
1237
- "flex flex-col gap-3 rounded-2xl border px-5 py-4 sm:flex-row sm:items-start sm:justify-between",
1238
- NOTICE[tone],
1239
- className
1240
- ),
1241
- children: [
1242
- /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col gap-1", children: [
1243
- title ? /* @__PURE__ */ jsx("p", { className: cn("text-[0.9375rem] font-medium", NOTICE_TITLE[tone]), children: title }) : null,
1244
- children ? /* @__PURE__ */ jsx("div", { className: "text-[0.9375rem] leading-relaxed text-foreground/85", children }) : null
1245
- ] }),
1246
- action ? /* @__PURE__ */ jsx("div", { className: "shrink-0", children: action }) : null
1247
- ]
1248
- }
1249
- );
1404
+ const timedOut = useTimedOut(true, timeoutMs);
1405
+ if (timedOut) {
1406
+ return /* @__PURE__ */ jsx(
1407
+ Notice,
1408
+ {
1409
+ className,
1410
+ title: "This is taking longer than it should.",
1411
+ action: /* @__PURE__ */ jsx(Button, { size: "sm", variant: "secondary", onClick: onRetry ?? (() => window.location.reload()), children: "Try again" }),
1412
+ children: "Check your connection, then try again."
1413
+ }
1414
+ );
1415
+ }
1416
+ return /* @__PURE__ */ jsx("div", { role: "status", "aria-label": label, className: cn("flex flex-col gap-3", className), children: Array.from({ length: rows }, (_, i) => /* @__PURE__ */ jsx(Skeleton, { className: "h-16 rounded-2xl" }, i)) });
1250
1417
  }
1251
1418
  function middle(v, head, tail) {
1252
1419
  return v.length <= head + tail + 1 ? v : `${v.slice(0, head)}\u2026${v.slice(-tail)}`;
@@ -1353,6 +1520,252 @@ function ActivityList({ items, empty, className }) {
1353
1520
  return /* @__PURE__ */ jsx("li", { children: it.href ? /* @__PURE__ */ jsx("a", { href: it.href, className: "block transition-colors hover:bg-accent/60", children: body }) : body }, it.id);
1354
1521
  }) });
1355
1522
  }
1523
+ var KIND = {
1524
+ package: "text-oca-code-package",
1525
+ tag: "text-oca-code-tag",
1526
+ link: "text-oca-code-link"
1527
+ };
1528
+ function PackageCard({ items, className }) {
1529
+ return /* @__PURE__ */ jsx(
1530
+ "div",
1531
+ {
1532
+ className: cn(
1533
+ "grid gap-x-10 gap-y-7 rounded-[1.25rem] border border-oca-ink-line bg-oca-ink-card p-6 text-oca-ink-foreground md:grid-cols-2 md:p-9",
1534
+ className
1535
+ ),
1536
+ children: items.map((it, i) => {
1537
+ const code = /* @__PURE__ */ jsx("span", { className: cn("text-[0.9375rem]", KIND[it.kind ?? "package"]), children: it.code });
1538
+ return /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col gap-1.5", children: [
1539
+ /* @__PURE__ */ jsx("h3", { className: "text-[1.125rem] font-semibold tracking-[-0.01em] text-oca-ink-title", children: it.title }),
1540
+ it.href ? /* @__PURE__ */ jsx("a", { href: it.href, className: "w-fit underline decoration-transparent underline-offset-4 hover:decoration-current", children: code }) : code,
1541
+ it.note ? /* @__PURE__ */ jsxs("p", { className: "text-[0.9375rem] leading-relaxed text-oca-ink-subtle", children: [
1542
+ /* @__PURE__ */ jsx("span", { "aria-hidden": true, children: "// " }),
1543
+ it.note
1544
+ ] }) : null
1545
+ ] }, i);
1546
+ })
1547
+ }
1548
+ );
1549
+ }
1550
+ function CodeBlock({
1551
+ code,
1552
+ caption,
1553
+ copy = true,
1554
+ maxLines,
1555
+ className
1556
+ }) {
1557
+ const lines = code.split("\n").length;
1558
+ const foldable = maxLines !== void 0 && lines > maxLines + 2;
1559
+ const [open, setOpen] = useState(false);
1560
+ const folded = foldable && !open;
1561
+ return /* @__PURE__ */ jsxs(
1562
+ "figure",
1563
+ {
1564
+ className: cn(
1565
+ "overflow-hidden rounded-[1.25rem] border border-[var(--oca-code-line)] bg-[var(--oca-code-surface)]",
1566
+ className
1567
+ ),
1568
+ children: [
1569
+ /* @__PURE__ */ jsxs("figcaption", { className: "flex h-11 items-center justify-between gap-3 border-b border-[var(--oca-code-line)] pl-5 pr-2", children: [
1570
+ /* @__PURE__ */ jsx("span", { className: "truncate text-[0.8125rem] text-oca-ink-subtle", children: caption ?? "Code" }),
1571
+ copy ? /* @__PURE__ */ jsx(
1572
+ CopyButton,
1573
+ {
1574
+ value: code,
1575
+ label: "Copy code",
1576
+ className: "text-oca-ink-subtle hover:bg-white/10 hover:text-white"
1577
+ }
1578
+ ) : null
1579
+ ] }),
1580
+ /* @__PURE__ */ jsxs("div", { className: "relative", children: [
1581
+ /* @__PURE__ */ jsx(
1582
+ "div",
1583
+ {
1584
+ className: cn(folded && "overflow-hidden"),
1585
+ style: folded ? { maxHeight: `calc(${maxLines} * 1.625em + 2.5rem)` } : void 0,
1586
+ children: /* @__PURE__ */ jsx(ScrollFade, { fade: "var(--oca-code-surface)", children: /* @__PURE__ */ jsx("pre", { className: "w-max min-w-full p-5 font-mono text-[0.875rem] leading-[1.625] text-oca-ink-muted", children: /* @__PURE__ */ jsx("code", { children: code }) }) })
1587
+ }
1588
+ ),
1589
+ foldable ? /* @__PURE__ */ jsx(
1590
+ "div",
1591
+ {
1592
+ className: cn(
1593
+ "flex justify-center px-5 pb-4",
1594
+ folded && "absolute inset-x-0 bottom-0 pt-16"
1595
+ ),
1596
+ style: folded ? { background: "linear-gradient(to top, var(--oca-code-surface) 40%, transparent)" } : void 0,
1597
+ children: /* @__PURE__ */ jsx(
1598
+ "button",
1599
+ {
1600
+ type: "button",
1601
+ onClick: () => setOpen((v) => !v),
1602
+ className: "rounded-full border border-white/20 px-4 py-1.5 text-[0.8125rem] text-white transition-colors hover:bg-white/10",
1603
+ children: open ? "Show less" : `Show all ${lines} lines`
1604
+ }
1605
+ )
1606
+ }
1607
+ ) : null
1608
+ ] })
1609
+ ]
1610
+ }
1611
+ );
1612
+ }
1613
+ function SplitBar({
1614
+ segments,
1615
+ caption,
1616
+ className
1617
+ }) {
1618
+ return /* @__PURE__ */ jsxs("figure", { className: cn("flex flex-col gap-5", className), children: [
1619
+ caption ? /* @__PURE__ */ jsx("figcaption", { className: "text-[0.9375rem]", children: caption }) : null,
1620
+ /* @__PURE__ */ jsx("div", { className: "flex h-16 w-full gap-1.5 overflow-hidden rounded-[1.25rem] md:h-20", children: segments.map((s, i) => /* @__PURE__ */ jsx(
1621
+ "div",
1622
+ {
1623
+ className: cn(
1624
+ "flex min-w-[4.25rem] items-end rounded-[1rem] px-3 pb-2.5 md:px-4 md:pb-3",
1625
+ s.tone === "card" ? "bg-white text-oca-ink" : "bg-oca-ink text-white"
1626
+ ),
1627
+ style: { flexBasis: `${s.pct}%` },
1628
+ children: /* @__PURE__ */ jsxs("span", { className: "oca-tabular text-[1.25rem] leading-none tracking-[-0.02em] md:text-[1.875rem]", children: [
1629
+ s.pct,
1630
+ "%"
1631
+ ] })
1632
+ },
1633
+ i
1634
+ )) }),
1635
+ /* @__PURE__ */ jsx("dl", { className: "grid gap-x-8 gap-y-2 sm:grid-cols-2", children: segments.map((s, i) => /* @__PURE__ */ jsxs("div", { className: "flex items-baseline gap-2.5", children: [
1636
+ /* @__PURE__ */ jsxs("dt", { className: "sr-only", children: [
1637
+ s.pct,
1638
+ "%"
1639
+ ] }),
1640
+ /* @__PURE__ */ jsx(
1641
+ "span",
1642
+ {
1643
+ "aria-hidden": true,
1644
+ className: cn(
1645
+ "inline-block size-2.5 shrink-0 translate-y-[-1px] rounded-full",
1646
+ s.tone === "card" ? "bg-white" : "bg-oca-ink"
1647
+ )
1648
+ }
1649
+ ),
1650
+ /* @__PURE__ */ jsx("dd", { className: "text-[0.9375rem] leading-snug", children: s.label })
1651
+ ] }, i)) })
1652
+ ] });
1653
+ }
1654
+ var LABEL = {
1655
+ yes: "Yes",
1656
+ testing: "In testing",
1657
+ "not-yet": "Not yet",
1658
+ no: "No"
1659
+ };
1660
+ var TONE = {
1661
+ yes: "text-oca-accent-ink",
1662
+ testing: "text-foreground",
1663
+ "not-yet": "text-muted-foreground",
1664
+ no: "text-muted-foreground"
1665
+ };
1666
+ function TruthTable({
1667
+ rows,
1668
+ statusHeading = "Status",
1669
+ whatHeading = "What",
1670
+ className
1671
+ }) {
1672
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
1673
+ /* @__PURE__ */ jsx(
1674
+ "ul",
1675
+ {
1676
+ className: cn(
1677
+ "divide-y divide-oca-hairline-strong overflow-hidden rounded-xl border border-oca-hairline-strong bg-card sm:hidden",
1678
+ className
1679
+ ),
1680
+ children: rows.map((r, i) => /* @__PURE__ */ jsxs("li", { className: "flex flex-col gap-1.5 px-4 py-3.5", children: [
1681
+ /* @__PURE__ */ jsx("span", { className: cn("text-[0.875rem] font-medium", TONE[r.status]), children: LABEL[r.status] }),
1682
+ /* @__PURE__ */ jsx("span", { className: "text-[0.9375rem] leading-relaxed", children: r.what })
1683
+ ] }, i))
1684
+ }
1685
+ ),
1686
+ /* @__PURE__ */ jsx("div", { className: cn("overflow-hidden rounded-xl border border-oca-hairline-strong max-sm:hidden", className), children: /* @__PURE__ */ jsxs("table", { className: "w-full border-collapse text-left text-[0.9375rem] md:text-[1rem]", children: [
1687
+ /* @__PURE__ */ jsx("thead", { className: "bg-oca-table-head", children: /* @__PURE__ */ jsxs("tr", { children: [
1688
+ /* @__PURE__ */ jsx("th", { scope: "col", className: "w-[30%] border-b border-oca-hairline-strong px-4 py-3 font-semibold md:w-[22%]", children: statusHeading }),
1689
+ /* @__PURE__ */ jsx("th", { scope: "col", className: "border-b border-l border-oca-hairline-strong px-4 py-3 font-semibold", children: whatHeading })
1690
+ ] }) }),
1691
+ /* @__PURE__ */ jsx("tbody", { className: "bg-card", children: rows.map((r, i) => /* @__PURE__ */ jsxs("tr", { className: "align-top", children: [
1692
+ /* @__PURE__ */ jsx(
1693
+ "td",
1694
+ {
1695
+ className: cn(
1696
+ "border-t border-oca-hairline-strong px-4 py-3 font-medium",
1697
+ i === 0 && "border-t-0",
1698
+ TONE[r.status]
1699
+ ),
1700
+ children: LABEL[r.status]
1701
+ }
1702
+ ),
1703
+ /* @__PURE__ */ jsx(
1704
+ "td",
1705
+ {
1706
+ className: cn(
1707
+ "border-l border-t border-oca-hairline-strong px-4 py-3 leading-relaxed",
1708
+ i === 0 && "border-t-0"
1709
+ ),
1710
+ children: r.what
1711
+ }
1712
+ )
1713
+ ] }, i)) })
1714
+ ] }) })
1715
+ ] });
1716
+ }
1717
+ var INT = new Intl.NumberFormat("en-US", { maximumFractionDigits: 0 });
1718
+ var COMPACT = new Intl.NumberFormat("en-US", { notation: "compact", maximumFractionDigits: 1 });
1719
+ function satsText(value, opts = {}) {
1720
+ if (value == null || !Number.isFinite(value)) return null;
1721
+ const whole = Math.trunc(value);
1722
+ const body = (opts.compact ? COMPACT : INT).format(Math.abs(whole));
1723
+ const sign = whole < 0 ? "\u2212" : opts.signed && whole > 0 ? "+" : "";
1724
+ const unit = opts.unit === "none" ? "" : whole === 1 || whole === -1 ? " sat" : " sats";
1725
+ return `${sign}${body}${unit}`;
1726
+ }
1727
+ function Sats({ value, unit, compact, signed, unknown = "\u2014", className, ...props }) {
1728
+ const text = satsText(value, { unit, compact, signed });
1729
+ if (text === null) {
1730
+ return /* @__PURE__ */ jsxs("span", { className: cn("oca-tabular text-muted-foreground", className), ...props, children: [
1731
+ /* @__PURE__ */ jsx("span", { "aria-hidden": true, children: unknown }),
1732
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: "unknown" })
1733
+ ] });
1734
+ }
1735
+ return /* @__PURE__ */ jsx("span", { className: cn("oca-tabular whitespace-nowrap", className), ...props, children: text });
1736
+ }
1737
+ function UsdApprox({
1738
+ sats,
1739
+ usdPerBtc,
1740
+ className
1741
+ }) {
1742
+ if (sats == null || usdPerBtc == null || !Number.isFinite(sats) || !Number.isFinite(usdPerBtc)) return null;
1743
+ const usd = sats / 1e8 * usdPerBtc;
1744
+ const text = new Intl.NumberFormat("en-US", {
1745
+ style: "currency",
1746
+ currency: "USD",
1747
+ maximumFractionDigits: usd < 1 ? 4 : 2
1748
+ }).format(usd);
1749
+ return /* @__PURE__ */ jsxs("span", { className: cn("oca-tabular text-muted-foreground", className), children: [
1750
+ "\u2248 ",
1751
+ text
1752
+ ] });
1753
+ }
1754
+ function SatsFigure({
1755
+ label,
1756
+ value,
1757
+ hint,
1758
+ className
1759
+ }) {
1760
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-1.5", className), children: [
1761
+ /* @__PURE__ */ jsx("span", { className: "text-[0.9375rem] text-muted-foreground", children: label }),
1762
+ /* @__PURE__ */ jsxs("span", { className: "oca-display-3 oca-tabular", children: [
1763
+ /* @__PURE__ */ jsx(Sats, { value, unit: "none" }),
1764
+ /* @__PURE__ */ jsx("span", { className: "ml-2 text-[0.5em] tracking-normal text-muted-foreground", children: "sats" })
1765
+ ] }),
1766
+ hint ? /* @__PURE__ */ jsx("span", { className: "text-[0.875rem] text-muted-foreground", children: hint }) : null
1767
+ ] });
1768
+ }
1356
1769
  function NavLink({ item, className, onNavigate }) {
1357
1770
  const cls = cn(
1358
1771
  "rounded-full px-3 py-2 text-[0.9375rem] transition-colors",
@@ -1418,12 +1831,12 @@ function SiteFooter({
1418
1831
  className
1419
1832
  }) {
1420
1833
  return /* @__PURE__ */ jsxs("footer", { className: cn("border-t border-border bg-background", className), children: [
1421
- /* @__PURE__ */ jsxs("div", { className: "oca-container grid gap-10 py-14 md:grid-cols-[1.3fr_repeat(3,1fr)] md:py-16", children: [
1422
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
1834
+ /* @__PURE__ */ jsxs("div", { className: "oca-container grid grid-cols-2 gap-x-6 gap-y-10 py-14 md:grid-cols-[1.3fr_repeat(3,1fr)] md:py-16", children: [
1835
+ /* @__PURE__ */ jsxs("div", { className: "col-span-2 flex flex-col gap-4 md:col-span-1", children: [
1423
1836
  /* @__PURE__ */ jsx(Lockup, { size: 26 }),
1424
1837
  fineprint ? /* @__PURE__ */ jsx("p", { className: "max-w-xs text-[0.9375rem] leading-relaxed text-muted-foreground", children: fineprint }) : null
1425
1838
  ] }),
1426
- columns.map((col) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
1839
+ columns.map((col) => /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col gap-1", children: [
1427
1840
  /* @__PURE__ */ jsx("p", { className: "mb-2 text-[0.875rem] font-medium", children: col.heading }),
1428
1841
  col.links.map((l) => /* @__PURE__ */ jsx(
1429
1842
  NavLink,
@@ -1439,8 +1852,8 @@ function SiteFooter({
1439
1852
  ] });
1440
1853
  }
1441
1854
  function SideNav({ groups, onNavigate }) {
1442
- return /* @__PURE__ */ jsx("nav", { "aria-label": "Sections", className: "flex flex-col gap-6", children: groups.map((g, gi) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5", children: [
1443
- g.label ? /* @__PURE__ */ jsx("p", { className: "px-3 pb-1.5 text-[0.8125rem] text-muted-foreground", children: g.label }) : null,
1855
+ return /* @__PURE__ */ jsx("nav", { "aria-label": "Pages", className: "flex flex-col gap-5", children: groups.map((g, gi) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5", children: [
1856
+ g.label ? /* @__PURE__ */ jsx("p", { className: "px-3 pb-1 text-[0.8125rem] text-muted-foreground", children: g.label }) : null,
1444
1857
  g.items.map((it) => /* @__PURE__ */ jsxs(
1445
1858
  Link2,
1446
1859
  {
@@ -1448,8 +1861,8 @@ function SideNav({ groups, onNavigate }) {
1448
1861
  onClick: onNavigate,
1449
1862
  "aria-current": it.active ? "page" : void 0,
1450
1863
  className: cn(
1451
- "flex h-10 items-center gap-3 rounded-xl px-3 text-[0.9375rem] transition-colors",
1452
- "[&_svg]:size-[1.125rem] [&_svg]:shrink-0",
1864
+ "flex h-9 items-center gap-3 rounded-xl px-3 text-[0.9375rem] transition-colors",
1865
+ "[&_svg]:size-[1.0625rem] [&_svg]:shrink-0",
1453
1866
  it.active ? "bg-card text-foreground shadow-sm ring-1 ring-border [&_svg]:text-foreground" : "text-muted-foreground hover:bg-accent hover:text-foreground"
1454
1867
  ),
1455
1868
  children: [
@@ -1462,8 +1875,56 @@ function SideNav({ groups, onNavigate }) {
1462
1875
  ))
1463
1876
  ] }, g.label ?? gi)) });
1464
1877
  }
1878
+ function SectionSwitch({
1879
+ sections,
1880
+ current,
1881
+ onNavigate
1882
+ }) {
1883
+ const cols = sections.length <= 3 ? sections.length : 2;
1884
+ return /* @__PURE__ */ jsx(
1885
+ "nav",
1886
+ {
1887
+ "aria-label": "Sections",
1888
+ className: cn("grid gap-1 bg-muted p-1", cols === sections.length ? "rounded-full" : "rounded-[1.25rem]"),
1889
+ style: { gridTemplateColumns: `repeat(${cols}, minmax(0, 1fr))` },
1890
+ children: sections.map((sec) => {
1891
+ const on = sec.id === current.id;
1892
+ return /* @__PURE__ */ jsx(
1893
+ Link2,
1894
+ {
1895
+ href: sec.href,
1896
+ onClick: onNavigate,
1897
+ "aria-current": on ? "true" : void 0,
1898
+ className: cn(
1899
+ "flex h-8 min-w-0 items-center justify-center rounded-full px-1.5 text-[0.8125rem] font-medium transition-colors",
1900
+ on ? "bg-card text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"
1901
+ ),
1902
+ children: /* @__PURE__ */ jsx("span", { className: "truncate", children: sec.label })
1903
+ },
1904
+ sec.id
1905
+ );
1906
+ })
1907
+ }
1908
+ );
1909
+ }
1910
+ var activeItem = (groups) => groups.flatMap((g) => g.items).find((it) => it.active);
1911
+ var warned = /* @__PURE__ */ new Set();
1912
+ function warnDuplicateLabels(groups) {
1913
+ if (typeof process === "undefined" || process.env.NODE_ENV === "production") return;
1914
+ const seen = /* @__PURE__ */ new Set();
1915
+ for (const it of groups.flatMap((g) => g.items)) {
1916
+ if (seen.has(it.label) && !warned.has(it.label)) {
1917
+ warned.add(it.label);
1918
+ console.warn(`AppShell: two pages are labelled "${it.label}"; give each its own name.`);
1919
+ }
1920
+ seen.add(it.label);
1921
+ }
1922
+ }
1465
1923
  function AppShell({
1466
1924
  nav,
1925
+ sections,
1926
+ activeSection,
1927
+ persistent = [],
1467
1928
  home = "/",
1468
1929
  account,
1469
1930
  banner,
@@ -1472,38 +1933,59 @@ function AppShell({
1472
1933
  className
1473
1934
  }) {
1474
1935
  const [open, setOpen] = useState(false);
1475
- return /* @__PURE__ */ jsxs("div", { className: cn("min-h-dvh bg-background", className), children: [
1476
- /* @__PURE__ */ jsxs("div", { className: "sticky top-0 z-40 flex h-14 items-center justify-between border-b border-border bg-background/85 px-4 backdrop-blur-md lg:hidden", children: [
1477
- /* @__PURE__ */ jsxs(Sheet, { open, onOpenChange: setOpen, children: [
1478
- /* @__PURE__ */ jsx(
1479
- SheetTrigger,
1480
- {
1481
- className: "inline-flex size-10 items-center justify-center rounded-full hover:bg-accent",
1482
- "aria-label": "Open navigation",
1483
- children: /* @__PURE__ */ jsx(Menu, { className: "size-5" })
1484
- }
1485
- ),
1486
- /* @__PURE__ */ jsxs(SheetContent, { side: "left", className: "p-4 pt-16", children: [
1487
- /* @__PURE__ */ jsx(SheetTitle, { className: "sr-only", children: "Navigation" }),
1488
- /* @__PURE__ */ jsx(SideNav, { groups: nav, onNavigate: () => setOpen(false) })
1489
- ] })
1936
+ const current = sections && sections.length > 0 ? sections.find((sec) => sec.id === activeSection) ?? sections.find((sec) => activeItem(sec.groups)) ?? sections[0] : void 0;
1937
+ const groups = current ? [...current.groups, ...persistent] : [...nav ?? [], ...persistent];
1938
+ warnDuplicateLabels(groups);
1939
+ const page = activeItem(groups);
1940
+ const place = useMemo(
1941
+ () => ({ section: current ? current.title ?? current.label : void 0, page: page?.label }),
1942
+ [current, page?.label]
1943
+ );
1944
+ const switcher = sections && current && sections.length > 1 ? /* @__PURE__ */ jsx(SectionSwitch, { sections, current, onNavigate: () => setOpen(false) }) : null;
1945
+ return /* @__PURE__ */ jsx(ShellContext.Provider, { value: place, children: /* @__PURE__ */ jsxs("div", { className: cn("min-h-dvh bg-background", className), children: [
1946
+ /* @__PURE__ */ jsxs("div", { className: "sticky top-0 z-40 border-b border-border bg-background/90 backdrop-blur-md lg:hidden", children: [
1947
+ /* @__PURE__ */ jsxs("div", { className: "flex h-14 items-center gap-2 px-3", children: [
1948
+ /* @__PURE__ */ jsxs(Sheet, { open, onOpenChange: setOpen, children: [
1949
+ /* @__PURE__ */ jsx(
1950
+ SheetTrigger,
1951
+ {
1952
+ className: "inline-flex size-10 items-center justify-center rounded-full hover:bg-accent",
1953
+ "aria-label": "Open navigation",
1954
+ children: /* @__PURE__ */ jsx(Menu, { className: "size-5" })
1955
+ }
1956
+ ),
1957
+ /* @__PURE__ */ jsxs(SheetContent, { side: "left", className: "flex flex-col gap-6 overflow-y-auto p-4 pt-16", children: [
1958
+ /* @__PURE__ */ jsx(SheetTitle, { className: "sr-only", children: "Navigation" }),
1959
+ switcher,
1960
+ /* @__PURE__ */ jsx(SideNav, { groups, onNavigate: () => setOpen(false) }),
1961
+ footer ? /* @__PURE__ */ jsx("div", { className: "mt-auto flex flex-col gap-3", children: footer }) : null
1962
+ ] })
1963
+ ] }),
1964
+ /* @__PURE__ */ jsx(Link2, { href: home, "aria-label": "Home", className: "rounded-lg p-1", children: /* @__PURE__ */ jsx(Lockup, { size: 22 }) }),
1965
+ /* @__PURE__ */ jsx("div", { className: "ml-auto flex items-center", children: account })
1490
1966
  ] }),
1491
- /* @__PURE__ */ jsx(Link2, { href: home, "aria-label": "Home", children: /* @__PURE__ */ jsx(AppIcon, { size: 28 }) }),
1492
- /* @__PURE__ */ jsx("div", { className: "flex items-center", children: account })
1967
+ place.page ? /* @__PURE__ */ jsxs("div", { className: "flex h-9 items-center gap-1.5 border-t border-border px-4 text-[0.875rem]", children: [
1968
+ place.section ? /* @__PURE__ */ jsxs(Fragment, { children: [
1969
+ /* @__PURE__ */ jsx("span", { className: "shrink-0 text-muted-foreground", children: place.section }),
1970
+ /* @__PURE__ */ jsx(ChevronRight, { "aria-hidden": true, className: "size-3.5 shrink-0 text-muted-foreground" })
1971
+ ] }) : null,
1972
+ /* @__PURE__ */ jsx("span", { className: "truncate font-medium", children: place.page })
1973
+ ] }) : null
1493
1974
  ] }),
1494
1975
  /* @__PURE__ */ jsxs("div", { className: "mx-auto flex w-full max-w-[90rem]", children: [
1495
- /* @__PURE__ */ jsxs("aside", { className: "sticky top-0 hidden h-dvh w-64 shrink-0 flex-col gap-8 overflow-y-auto px-4 py-6 lg:flex", children: [
1976
+ /* @__PURE__ */ jsxs("aside", { className: "sticky top-0 hidden h-dvh w-[17rem] shrink-0 flex-col gap-6 overflow-y-auto px-4 py-6 lg:flex", children: [
1496
1977
  /* @__PURE__ */ jsx(Link2, { href: home, className: "px-2", "aria-label": "Home", children: /* @__PURE__ */ jsx(Lockup, { size: 26 }) }),
1497
- /* @__PURE__ */ jsx(SideNav, { groups: nav }),
1978
+ switcher,
1979
+ /* @__PURE__ */ jsx(SideNav, { groups }),
1498
1980
  /* @__PURE__ */ jsx("div", { className: "mt-auto flex flex-col gap-3", children: footer })
1499
1981
  ] }),
1500
1982
  /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 flex-col", children: [
1501
1983
  /* @__PURE__ */ jsx("div", { className: "hidden h-[4.5rem] items-center justify-end gap-3 px-8 lg:flex", children: account }),
1502
1984
  banner ? /* @__PURE__ */ jsx("div", { className: "px-4 pb-2 pt-4 md:px-8 lg:pt-0", children: banner }) : null,
1503
- /* @__PURE__ */ jsx("main", { id: "main-content", className: "flex-1 px-4 pb-16 pt-6 md:px-8 lg:pt-2", children })
1985
+ /* @__PURE__ */ jsx("main", { id: "main-content", className: "flex-1 px-4 pb-16 pt-6 md:px-8 lg:pt-2", children: /* @__PURE__ */ jsx("div", { className: "mx-auto w-full max-w-[72rem]", children }) })
1504
1986
  ] })
1505
1987
  ] })
1506
- ] });
1988
+ ] }) });
1507
1989
  }
1508
1990
  function AccountMenu({
1509
1991
  name,
@@ -1515,11 +1997,11 @@ function AccountMenu({
1515
1997
  /* @__PURE__ */ jsxs(
1516
1998
  DropdownMenuTrigger,
1517
1999
  {
1518
- className: "inline-flex h-10 items-center gap-2.5 rounded-full border border-border bg-card pl-1 pr-3.5 text-[0.9375rem] outline-none transition-colors hover:border-oca-hairline-strong focus-visible:ring-2 focus-visible:ring-ring",
2000
+ className: "inline-flex h-10 items-center gap-2.5 rounded-full border border-border bg-card pl-1 pr-1 text-[0.9375rem] outline-none transition-colors hover:border-oca-hairline-strong focus-visible:ring-2 focus-visible:ring-ring sm:pr-3.5",
1519
2001
  "aria-label": `Account: ${name}`,
1520
2002
  children: [
1521
2003
  /* @__PURE__ */ jsx("span", { className: "flex size-8 items-center justify-center rounded-full bg-foreground text-[0.8125rem] font-medium text-background", children: initial }),
1522
- /* @__PURE__ */ jsx("span", { className: "max-w-[10rem] truncate", children: name })
2004
+ /* @__PURE__ */ jsx("span", { className: "max-w-[10rem] truncate max-sm:hidden", children: name })
1523
2005
  ]
1524
2006
  }
1525
2007
  ),
@@ -1564,6 +2046,6 @@ function ThemeToggle({ className }) {
1564
2046
  );
1565
2047
  }
1566
2048
 
1567
- export { APP_ATTRIBUTE, APP_ID, Accent, AccountMenu, ActivityList, AppIcon, AppShell, Badge, Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardNumeral, CardTitle, Checkbox, CodeBlock, Container, CopyButton, Crowd, DataTable, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, Display, DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, EmptyState, Eyebrow, Field, Footnote, HalftoneSphere, HashChip, Input, IsoCheck, Kbd, KeyValueList, Label, Lead, Lockup, MARK_FACES, Mark, Notice, PackageCard, PageHeader, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, ProgressSteps, Prose, RadioGroup, RadioGroupItem, SPHERE_GRADIENT, Sats, SatsFigure, Section, SectionIntro, Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue, Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetTitle, SheetTrigger, SiteFooter, SiteHeader, Skeleton, Spinner, SplitBar, StatCard, StatGrid, StatusDot, StatusPill, StepGrid, Switch, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, ThemeToggle, Toaster, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, TruthTable, UsdApprox, appColors, appFonts, badgeVariants, buttonVariants, cardVariants, cn, satsText, sectionVariants, useCopy };
2049
+ export { APP_ATTRIBUTE, APP_ID, Accent, AccountMenu, ActivityList, AppIcon, AppShell, Badge, Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardNumeral, CardTitle, Checkbox, CodeBlock, Container, CopyButton, Crowd, DataTable, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, Display, DocHeader, DocLayout, DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, EmptyLine, EmptyState, Eyebrow, Field, Footnote, HalftoneSphere, HashChip, Input, IsoCheck, Kbd, KeyValueList, Label, Lead, LoadingBlock, Lockup, MARK_FACES, Mark, Notice, PackageCard, PageHeader, PageHero, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, ProgressSteps, Prose, RadioGroup, RadioGroupItem, SPHERE_GRADIENT, Sats, SatsFigure, ScrollFade, Section, SectionIntro, Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue, Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetTitle, SheetTrigger, ShellContext, SiteFooter, SiteHeader, Skeleton, Spinner, SplitBar, StatCard, StatGrid, StatusDot, StatusPill, StepGrid, Switch, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, ThemeToggle, Toaster, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, TruthTable, UsdApprox, appColors, appFonts, badgeVariants, buttonVariants, cardVariants, cn, satsText, sectionVariants, useCopy, useShellPlace, useTimedOut };
1568
2050
  //# sourceMappingURL=index.mjs.map
1569
2051
  //# sourceMappingURL=index.mjs.map