@orangecheck/app-design 0.2.1 → 0.3.1

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,69 @@ 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
+ if (typeof ResizeObserver === "undefined") return;
678
+ const ro = new ResizeObserver(measure);
679
+ ro.observe(el);
680
+ if (el.firstElementChild) ro.observe(el.firstElementChild);
681
+ return () => ro.disconnect();
682
+ }, [measure]);
683
+ return /* @__PURE__ */ jsxs("div", { className: cn("relative min-w-0", className), ...props, children: [
684
+ /* @__PURE__ */ jsx("div", { ref, onScroll: measure, className: cn("overflow-x-auto overscroll-x-contain", innerClassName), children }),
685
+ /* @__PURE__ */ jsx(
686
+ "span",
687
+ {
688
+ "aria-hidden": true,
689
+ className: cn(
690
+ "pointer-events-none absolute inset-y-0 left-0 w-8 transition-opacity duration-150",
691
+ edges.left ? "opacity-100" : "opacity-0"
692
+ ),
693
+ style: { background: `linear-gradient(to right, ${fade}, transparent)` }
694
+ }
695
+ ),
696
+ /* @__PURE__ */ jsx(
697
+ "span",
698
+ {
699
+ "aria-hidden": true,
700
+ className: cn(
701
+ "pointer-events-none absolute inset-y-0 right-0 w-10 transition-opacity duration-150",
702
+ edges.right ? "opacity-100" : "opacity-0"
703
+ ),
704
+ style: { background: `linear-gradient(to left, ${fade}, transparent)` }
705
+ }
706
+ )
707
+ ] });
708
+ }
634
709
  var LookContext = createContext("pill");
635
710
  var Tabs = forwardRef(function Tabs2({ look = "pill", ...props }, ref) {
636
711
  return /* @__PURE__ */ jsx(LookContext.Provider, { value: look, children: /* @__PURE__ */ jsx(TabsPrimitive.Root, { ref, ...props }) });
637
712
  });
638
713
  var TabsList = forwardRef(function TabsList2({ className, ...props }, ref) {
639
714
  const look = useContext(LookContext);
640
- return /* @__PURE__ */ jsx(
715
+ return /* @__PURE__ */ jsx(ScrollFade, { fade: "var(--background)", className: look === "pill" ? "w-fit max-w-full" : "w-full", children: /* @__PURE__ */ jsx(
641
716
  TabsPrimitive.List,
642
717
  {
643
718
  ref,
644
719
  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",
720
+ 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
721
  className
647
722
  ),
648
723
  ...props
649
724
  }
650
- );
725
+ ) });
651
726
  });
652
727
  var TabsTrigger = forwardRef(function TabsTrigger2({ className, ...props }, ref) {
653
728
  const look = useContext(LookContext);
@@ -853,7 +928,7 @@ function Prose({ className, ...props }) {
853
928
  {
854
929
  className: cn(
855
930
  "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",
931
+ "[&_h2]:oca-display-3 [&_h2]:mb-4 [&_h2]:mt-14 [&_h2]:scroll-mt-24 [&_h2]:text-foreground",
857
932
  "[&_h3]:oca-title [&_h3]:mb-3 [&_h3]:mt-10 [&_h3]:text-foreground",
858
933
  "[&_p]:my-4 [&_strong]:font-medium [&_strong]:text-foreground",
859
934
  "[&_a]:text-foreground [&_a]:underline [&_a]:decoration-border [&_a]:underline-offset-4 hover:[&_a]:decoration-foreground",
@@ -869,7 +944,9 @@ var sectionVariants = cva("relative w-full overflow-x-clip", {
869
944
  tone: {
870
945
  canvas: "bg-background text-foreground",
871
946
  card: "bg-card text-card-foreground",
872
- ink: "bg-oca-ink text-oca-ink-foreground",
947
+ // The band line is transparent in light; in dark it keeps the ink
948
+ // band from melting into the canvas.
949
+ ink: "border-y border-[var(--oca-band-line)] bg-oca-ink text-oca-ink-foreground",
873
950
  brand: "bg-brand text-brand-foreground"
874
951
  },
875
952
  space: {
@@ -904,6 +981,120 @@ function SectionIntro({
904
981
  }
905
982
  );
906
983
  }
984
+ function PageHero({
985
+ eyebrow,
986
+ title,
987
+ lead,
988
+ actions,
989
+ art,
990
+ meta,
991
+ children,
992
+ variant = "page",
993
+ size = "lg",
994
+ className
995
+ }) {
996
+ if (variant === "document") {
997
+ 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 }) });
998
+ }
999
+ 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: [
1000
+ /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col items-start gap-6", art ? "md:col-span-7" : "max-w-[52rem]"), children: [
1001
+ eyebrow ? /* @__PURE__ */ jsx("p", { className: "oca-eyebrow", children: eyebrow }) : null,
1002
+ /* @__PURE__ */ jsx("h1", { className: size === "xl" ? "oca-display-1" : "oca-display-2", children: title }),
1003
+ lead ? /* @__PURE__ */ jsx("p", { className: "oca-lead max-w-[38rem]", children: lead }) : null,
1004
+ meta ? /* @__PURE__ */ jsx("p", { className: "text-[0.875rem] text-muted-foreground", children: meta }) : null,
1005
+ actions ? /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-3", children: actions }) : null,
1006
+ children
1007
+ ] }),
1008
+ art ? /* @__PURE__ */ jsx("div", { className: "md:col-span-5", children: art }) : null
1009
+ ] }) });
1010
+ }
1011
+ function DocHeader({
1012
+ eyebrow,
1013
+ title,
1014
+ lead,
1015
+ meta,
1016
+ actions,
1017
+ children,
1018
+ className
1019
+ }) {
1020
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-5", className), children: [
1021
+ eyebrow ? /* @__PURE__ */ jsx("p", { className: "oca-eyebrow", children: eyebrow }) : null,
1022
+ /* @__PURE__ */ jsx("h1", { className: "oca-display-2", children: title }),
1023
+ lead ? /* @__PURE__ */ jsx("p", { className: "oca-lead", children: lead }) : null,
1024
+ meta ? /* @__PURE__ */ jsx("p", { className: "text-[0.875rem] text-muted-foreground", children: meta }) : null,
1025
+ actions ? /* @__PURE__ */ jsx("div", { className: "mt-1 flex flex-wrap gap-3", children: actions }) : null,
1026
+ children
1027
+ ] });
1028
+ }
1029
+ function useActiveHeading(ids) {
1030
+ const [active, setActive] = useState(ids[0]);
1031
+ const key = ids.join("|");
1032
+ useEffect(() => {
1033
+ const els = key.split("|").map((id) => document.getElementById(id)).filter((el) => el !== null);
1034
+ if (els.length === 0 || typeof IntersectionObserver === "undefined") return;
1035
+ const io = new IntersectionObserver(
1036
+ (entries) => {
1037
+ const hit = entries.filter((e) => e.isIntersecting).sort((a, b) => a.boundingClientRect.top - b.boundingClientRect.top)[0];
1038
+ if (hit) setActive(hit.target.id);
1039
+ },
1040
+ { rootMargin: "-80px 0px -65% 0px" }
1041
+ );
1042
+ els.forEach((el) => io.observe(el));
1043
+ return () => io.disconnect();
1044
+ }, [key]);
1045
+ return active;
1046
+ }
1047
+ function DocLayout({
1048
+ toc,
1049
+ header,
1050
+ children,
1051
+ className
1052
+ }) {
1053
+ const active = useActiveHeading(toc?.map((t) => t.id) ?? []);
1054
+ const links = () => toc?.map((t) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
1055
+ "a",
1056
+ {
1057
+ href: `#${t.id}`,
1058
+ "aria-current": active === t.id ? "location" : void 0,
1059
+ className: cn(
1060
+ "block border-l py-1.5 pl-4 text-[0.875rem] leading-snug transition-colors",
1061
+ active === t.id ? "border-foreground text-foreground" : "border-border text-muted-foreground hover:text-foreground"
1062
+ ),
1063
+ children: t.label
1064
+ }
1065
+ ) }, t.id));
1066
+ const hasToc = !!toc && toc.length > 0;
1067
+ return /* @__PURE__ */ jsx("div", { className: cn("oca-container pb-24", header ? "pt-12 md:pt-20" : null, className), children: /* @__PURE__ */ jsxs(
1068
+ "div",
1069
+ {
1070
+ className: cn(
1071
+ "mx-auto grid grid-cols-1 gap-8",
1072
+ 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]"
1073
+ ),
1074
+ children: [
1075
+ header ? /* @__PURE__ */ jsx("div", { className: cn(hasToc && "lg:col-start-2", "pb-4"), children: header }) : null,
1076
+ hasToc ? /* @__PURE__ */ jsxs(Fragment, { children: [
1077
+ /* @__PURE__ */ jsxs(
1078
+ "nav",
1079
+ {
1080
+ "aria-label": "On this page",
1081
+ className: cn("sticky top-24 hidden self-start lg:block", header && "lg:row-start-2"),
1082
+ children: [
1083
+ /* @__PURE__ */ jsx("p", { className: "mb-3 text-[0.875rem] font-medium", children: "On this page" }),
1084
+ /* @__PURE__ */ jsx("ul", { children: links() })
1085
+ ]
1086
+ }
1087
+ ),
1088
+ /* @__PURE__ */ jsxs("details", { className: "group rounded-2xl border border-border bg-card px-4 py-3 lg:hidden", children: [
1089
+ /* @__PURE__ */ jsx("summary", { className: "cursor-pointer list-none text-[0.9375rem] font-medium marker:hidden", children: "On this page" }),
1090
+ /* @__PURE__ */ jsx("ul", { className: "mt-3", children: links() })
1091
+ ] })
1092
+ ] }) : null,
1093
+ /* @__PURE__ */ jsx("div", { className: cn("min-w-0", hasToc && "lg:col-start-2", hasToc && header && "lg:row-start-2"), children })
1094
+ ]
1095
+ }
1096
+ ) });
1097
+ }
907
1098
  var pad = (n) => String(n + 1).padStart(2, "0");
908
1099
  function StepGrid({ items, look = "cards", className }) {
909
1100
  const cols = items.length >= 3 ? "md:grid-cols-3" : items.length === 2 ? "md:grid-cols-2" : "";
@@ -931,322 +1122,299 @@ function StepGrid({ items, look = "cards", className }) {
931
1122
  ] }) }, i)
932
1123
  ) });
933
1124
  }
934
- var KIND = {
935
- package: "text-oca-code-package",
936
- tag: "text-oca-code-tag",
937
- link: "text-oca-code-link"
1125
+ var ShellContext = createContext({});
1126
+ function useShellPlace() {
1127
+ return useContext(ShellContext);
1128
+ }
1129
+ function PageHeader({
1130
+ eyebrow,
1131
+ title,
1132
+ description,
1133
+ actions,
1134
+ className
1135
+ }) {
1136
+ const place = useShellPlace();
1137
+ const eb = eyebrow === void 0 ? place.section : eyebrow;
1138
+ return /* @__PURE__ */ jsxs("header", { className: cn("flex flex-col gap-5 md:flex-row md:items-end md:justify-between", className), children: [
1139
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 max-w-[44rem] flex-col gap-2.5", children: [
1140
+ eb ? /* @__PURE__ */ jsx("p", { className: "oca-eyebrow", children: eb }) : null,
1141
+ /* @__PURE__ */ jsx("h1", { className: "oca-display-3", children: title }),
1142
+ description ? /* @__PURE__ */ jsx("p", { className: "oca-body max-w-[40rem] text-[1.0625rem]", children: description }) : null
1143
+ ] }),
1144
+ actions ? /* @__PURE__ */ jsx("div", { className: "flex flex-wrap items-center gap-2.5 md:shrink-0 md:justify-end", children: actions }) : null
1145
+ ] });
1146
+ }
1147
+ var InStatGrid = createContext(false);
1148
+ function StatCard({ label, value, hint, className }) {
1149
+ const inGrid = useContext(InStatGrid);
1150
+ return /* @__PURE__ */ jsxs(
1151
+ "div",
1152
+ {
1153
+ "data-ui": "stat",
1154
+ className: cn(
1155
+ "rounded-[1.25rem] border border-border bg-card p-5 md:p-6",
1156
+ // In a grid, label, value and hint each share a row with their
1157
+ // neighbours, so values line up whatever wraps above them.
1158
+ inGrid ? "row-span-3 grid grid-rows-subgrid gap-1.5" : "flex flex-col gap-2",
1159
+ className
1160
+ ),
1161
+ children: [
1162
+ /* @__PURE__ */ jsx("span", { className: "text-[0.875rem] leading-snug text-muted-foreground", children: label }),
1163
+ /* @__PURE__ */ jsx("span", { className: "self-end break-words oca-tabular text-[1.5rem] leading-tight tracking-[-0.02em] md:text-[1.75rem]", children: value }),
1164
+ hint ? /* @__PURE__ */ jsx("span", { className: "text-[0.8125rem] leading-snug text-muted-foreground", children: hint }) : inGrid ? /* @__PURE__ */ jsx("span", { "aria-hidden": true }) : null
1165
+ ]
1166
+ }
1167
+ );
1168
+ }
1169
+ var MD_COLS = {
1170
+ 1: "md:grid-cols-1",
1171
+ 2: "md:grid-cols-2",
1172
+ 3: "md:grid-cols-3",
1173
+ 4: "md:grid-cols-4"
938
1174
  };
939
- function PackageCard({ items, className }) {
1175
+ var LG_COLS = {
1176
+ 1: "lg:grid-cols-1",
1177
+ 2: "lg:grid-cols-2",
1178
+ 3: "lg:grid-cols-3",
1179
+ 4: "lg:grid-cols-4",
1180
+ 5: "lg:grid-cols-5"
1181
+ };
1182
+ var MD_SPAN = {
1183
+ 1: "md:col-span-1",
1184
+ 2: "md:col-span-2",
1185
+ 3: "md:col-span-3",
1186
+ 4: "md:col-span-4"
1187
+ };
1188
+ var LG_SPAN = {
1189
+ 1: "lg:col-span-1",
1190
+ 2: "lg:col-span-2",
1191
+ 3: "lg:col-span-3",
1192
+ 4: "lg:col-span-4"
1193
+ };
1194
+ function statColumns(n) {
1195
+ if (n <= 5) return Math.max(1, n);
1196
+ if (n % 4 === 0) return 4;
1197
+ if (n % 3 === 0) return 3;
1198
+ return 4;
1199
+ }
1200
+ function lastSpan(n, cols) {
1201
+ const rest = n % cols;
1202
+ return rest === 0 ? 1 : cols - rest + 1;
1203
+ }
1204
+ function EmptyLine({ children, className }) {
940
1205
  return /* @__PURE__ */ jsx(
1206
+ "p",
1207
+ {
1208
+ className: cn(
1209
+ "rounded-[1.25rem] border border-dashed border-oca-hairline-strong px-5 py-4 text-[0.9375rem] text-muted-foreground",
1210
+ className
1211
+ ),
1212
+ children
1213
+ }
1214
+ );
1215
+ }
1216
+ function StatGrid({ columns, empty, isEmpty, className, children, ...props }) {
1217
+ const items = Children.toArray(children).filter(isValidElement);
1218
+ const n = items.length;
1219
+ const allZero = n > 0 && items.every((el) => "raw" in el.props && (el.props.raw === 0 || el.props.raw === null));
1220
+ if (isEmpty ?? allZero) return /* @__PURE__ */ jsx(EmptyLine, { className, children: empty ?? "Nothing here yet." });
1221
+ const lg = columns ?? statColumns(n);
1222
+ const md = lg > 4 ? 3 : lg;
1223
+ const mdSpan = lastSpan(n, md);
1224
+ const lgSpan = lastSpan(n, lg);
1225
+ return /* @__PURE__ */ jsx(InStatGrid.Provider, { value: true, children: /* @__PURE__ */ jsx(
941
1226
  "div",
942
1227
  {
943
1228
  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",
1229
+ "grid gap-3 md:gap-4",
1230
+ n === 1 ? "grid-cols-1" : "grid-cols-2",
1231
+ MD_COLS[md],
1232
+ LG_COLS[lg],
945
1233
  className
946
1234
  ),
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);
1235
+ ...props,
1236
+ children: items.map((el, i) => {
1237
+ if (i !== n - 1) return el;
1238
+ const span = cn(
1239
+ n % 2 === 1 && n > 1 && "max-md:col-span-2",
1240
+ (mdSpan > 1 || lgSpan > 1) && MD_SPAN[mdSpan],
1241
+ (mdSpan > 1 || lgSpan > 1) && LG_SPAN[lgSpan]
1242
+ );
1243
+ return span ? cloneElement(el, { className: cn(el.props.className, span) }) : el;
957
1244
  })
958
1245
  }
959
- );
1246
+ ) });
960
1247
  }
961
- function CodeBlock({
962
- code,
1248
+ function KeyValueList({ items, className }) {
1249
+ 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: [
1250
+ /* @__PURE__ */ jsx("dt", { className: "shrink-0 text-[0.875rem] text-muted-foreground sm:w-48", children: it.label }),
1251
+ /* @__PURE__ */ jsx("dd", { className: cn("min-w-0 break-words text-[0.9375rem]", it.mono && "font-mono text-[0.875rem]"), children: it.value })
1252
+ ] }, i)) });
1253
+ }
1254
+ function DataTable({
1255
+ columns,
1256
+ rows,
1257
+ rowKey,
1258
+ empty,
963
1259
  caption,
1260
+ phone = "cards",
964
1261
  className
965
1262
  }) {
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 }) })
1263
+ if (rows.length === 0 && empty) return /* @__PURE__ */ jsx(Fragment, { children: empty });
1264
+ const primary = columns.find((c) => c.primary) ?? columns[0];
1265
+ const right = (c) => c.numeric || c.align === "end";
1266
+ const table = /* @__PURE__ */ jsx(
1267
+ "div",
1268
+ {
1269
+ className: cn(
1270
+ "overflow-hidden rounded-[1.25rem] border border-border bg-card",
1271
+ phone === "cards" && "max-sm:hidden",
1272
+ className
1273
+ ),
1274
+ children: /* @__PURE__ */ jsx(ScrollFade, { fade: "var(--card)", children: /* @__PURE__ */ jsxs("table", { className: "w-full border-collapse text-left text-[0.9375rem]", children: [
1275
+ caption ? /* @__PURE__ */ jsx("caption", { className: "sr-only", children: caption }) : null,
1276
+ /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsx("tr", { className: "border-b border-border", children: columns.map((c) => /* @__PURE__ */ jsx(
1277
+ "th",
1278
+ {
1279
+ scope: "col",
1280
+ style: { width: c.width, minWidth: c.minWidth },
1281
+ className: cn(
1282
+ "whitespace-nowrap px-5 py-3 text-[0.8125rem] font-medium text-muted-foreground",
1283
+ right(c) && "text-right",
1284
+ c.wide && "hidden md:table-cell"
1285
+ ),
1286
+ children: c.header
1287
+ },
1288
+ c.key
1289
+ )) }) }),
1290
+ /* @__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(
1291
+ "td",
1292
+ {
1293
+ style: { minWidth: c.minWidth },
1294
+ className: cn(
1295
+ "px-5 py-3.5 align-middle",
1296
+ right(c) && "text-right",
1297
+ c.numeric && "whitespace-nowrap oca-tabular",
1298
+ c.wide && "hidden md:table-cell"
1299
+ ),
1300
+ children: c.truncate ? /* @__PURE__ */ jsx("div", { className: "truncate", style: { maxWidth: c.width ?? "16rem" }, children: c.cell(r) }) : c.cell(r)
1301
+ },
1302
+ c.key
1303
+ )) }, rowKey(r, i))) })
1304
+ ] }) })
1305
+ }
1306
+ );
1307
+ if (phone !== "cards") return table;
1308
+ const rest = columns.filter((c) => c !== primary && !c.hideOnPhone);
1309
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
1310
+ table,
1311
+ /* @__PURE__ */ jsx(
1312
+ "ul",
1313
+ {
1314
+ "aria-label": caption,
1315
+ className: cn("divide-y divide-border rounded-[1.25rem] border border-border bg-card sm:hidden", className),
1316
+ children: rows.map((r, i) => /* @__PURE__ */ jsxs("li", { className: "flex flex-col gap-2.5 px-4 py-4", children: [
1317
+ /* @__PURE__ */ jsx("div", { className: "min-w-0 break-words text-[0.9375rem] font-medium", children: primary?.cell(r) }),
1318
+ 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: [
1319
+ /* @__PURE__ */ jsx("dt", { className: "text-muted-foreground", children: c.header }),
1320
+ /* @__PURE__ */ jsx("dd", { className: cn("min-w-0 break-words", c.numeric && "oca-tabular"), children: c.cell(r) })
1321
+ ] }, c.key)) }) : null
1322
+ ] }, rowKey(r, i)))
1323
+ }
1324
+ )
969
1325
  ] });
970
1326
  }
971
- function SplitBar({
972
- segments,
973
- caption,
1327
+ function EmptyState({
1328
+ title,
1329
+ children,
1330
+ action,
1331
+ icon,
974
1332
  className
975
1333
  }) {
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
- }
1334
+ return /* @__PURE__ */ jsxs(
1335
+ "div",
1336
+ {
1337
+ className: cn(
1338
+ "flex flex-col items-center gap-3 rounded-[1.25rem] border border-dashed border-oca-hairline-strong px-6 py-10 text-center",
1339
+ className
1007
1340
  ),
1008
- /* @__PURE__ */ jsx("dd", { className: "text-[0.9375rem] leading-snug", children: s.label })
1009
- ] }, i)) })
1010
- ] });
1341
+ children: [
1342
+ 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,
1343
+ /* @__PURE__ */ jsx("h3", { className: "oca-title-sm", children: title }),
1344
+ children ? /* @__PURE__ */ jsx("div", { className: "oca-body max-w-md text-[0.9375rem]", children }) : null,
1345
+ action ? /* @__PURE__ */ jsx("div", { className: "mt-2 flex flex-wrap justify-center gap-3", children: action }) : null
1346
+ ]
1347
+ }
1348
+ );
1011
1349
  }
1012
- var LABEL = {
1013
- yes: "Yes",
1014
- testing: "In testing",
1015
- "not-yet": "Not yet",
1016
- no: "No"
1350
+ var NOTICE_KIND = {
1351
+ neutral: "neutral",
1352
+ info: "neutral",
1353
+ success: "neutral",
1354
+ brand: "brand",
1355
+ warning: "brand",
1356
+ danger: "danger"
1017
1357
  };
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",
1358
+ function Notice({
1359
+ tone = "neutral",
1360
+ title,
1361
+ children,
1362
+ action,
1028
1363
  className
1029
1364
  }) {
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
1365
+ const kind = NOTICE_KIND[tone];
1366
+ return /* @__PURE__ */ jsxs(
1367
+ "div",
1368
+ {
1369
+ role: tone === "danger" || tone === "warning" ? "alert" : "note",
1370
+ "data-tone": kind,
1371
+ className: cn(
1372
+ "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",
1373
+ kind === "danger" && "border-[color-mix(in_oklab,var(--destructive)_40%,var(--border))]",
1374
+ className
1199
1375
  ),
1200
1376
  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
1377
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 gap-3", children: [
1378
+ kind !== "neutral" ? /* @__PURE__ */ jsx(
1379
+ "span",
1380
+ {
1381
+ "aria-hidden": true,
1382
+ className: cn(
1383
+ "mt-[0.45rem] size-2 shrink-0 rounded-full",
1384
+ kind === "brand" ? "bg-oca-orange" : "bg-destructive"
1385
+ )
1386
+ }
1387
+ ) : null,
1388
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col gap-1", children: [
1389
+ title ? /* @__PURE__ */ jsx("p", { className: cn("text-[0.9375rem] font-medium", kind === "danger" && "text-destructive"), children: title }) : null,
1390
+ children ? /* @__PURE__ */ jsx("div", { className: "text-[0.9375rem] leading-relaxed text-muted-foreground", children }) : null
1391
+ ] })
1392
+ ] }),
1393
+ action ? /* @__PURE__ */ jsx("div", { className: "shrink-0", children: action }) : null
1205
1394
  ]
1206
1395
  }
1207
1396
  );
1208
1397
  }
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,
1398
+ function LoadingBlock({
1399
+ rows = 3,
1400
+ timeoutMs = 12e3,
1401
+ onRetry,
1402
+ label = "Loading",
1230
1403
  className
1231
1404
  }) {
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
- );
1405
+ const timedOut = useTimedOut(true, timeoutMs);
1406
+ if (timedOut) {
1407
+ return /* @__PURE__ */ jsx(
1408
+ Notice,
1409
+ {
1410
+ className,
1411
+ title: "This is taking longer than it should.",
1412
+ action: /* @__PURE__ */ jsx(Button, { size: "sm", variant: "secondary", onClick: onRetry ?? (() => window.location.reload()), children: "Try again" }),
1413
+ children: "Check your connection, then try again."
1414
+ }
1415
+ );
1416
+ }
1417
+ 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
1418
  }
1251
1419
  function middle(v, head, tail) {
1252
1420
  return v.length <= head + tail + 1 ? v : `${v.slice(0, head)}\u2026${v.slice(-tail)}`;
@@ -1353,6 +1521,252 @@ function ActivityList({ items, empty, className }) {
1353
1521
  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
1522
  }) });
1355
1523
  }
1524
+ var KIND = {
1525
+ package: "text-oca-code-package",
1526
+ tag: "text-oca-code-tag",
1527
+ link: "text-oca-code-link"
1528
+ };
1529
+ function PackageCard({ items, className }) {
1530
+ return /* @__PURE__ */ jsx(
1531
+ "div",
1532
+ {
1533
+ className: cn(
1534
+ "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",
1535
+ className
1536
+ ),
1537
+ children: items.map((it, i) => {
1538
+ const code = /* @__PURE__ */ jsx("span", { className: cn("text-[0.9375rem]", KIND[it.kind ?? "package"]), children: it.code });
1539
+ return /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col gap-1.5", children: [
1540
+ /* @__PURE__ */ jsx("h3", { className: "text-[1.125rem] font-semibold tracking-[-0.01em] text-oca-ink-title", children: it.title }),
1541
+ it.href ? /* @__PURE__ */ jsx("a", { href: it.href, className: "w-fit underline decoration-transparent underline-offset-4 hover:decoration-current", children: code }) : code,
1542
+ it.note ? /* @__PURE__ */ jsxs("p", { className: "text-[0.9375rem] leading-relaxed text-oca-ink-subtle", children: [
1543
+ /* @__PURE__ */ jsx("span", { "aria-hidden": true, children: "// " }),
1544
+ it.note
1545
+ ] }) : null
1546
+ ] }, i);
1547
+ })
1548
+ }
1549
+ );
1550
+ }
1551
+ function CodeBlock({
1552
+ code,
1553
+ caption,
1554
+ copy = true,
1555
+ maxLines,
1556
+ className
1557
+ }) {
1558
+ const lines = code.split("\n").length;
1559
+ const foldable = maxLines !== void 0 && lines > maxLines + 2;
1560
+ const [open, setOpen] = useState(false);
1561
+ const folded = foldable && !open;
1562
+ return /* @__PURE__ */ jsxs(
1563
+ "figure",
1564
+ {
1565
+ className: cn(
1566
+ "overflow-hidden rounded-[1.25rem] border border-[var(--oca-code-line)] bg-[var(--oca-code-surface)]",
1567
+ className
1568
+ ),
1569
+ children: [
1570
+ /* @__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: [
1571
+ /* @__PURE__ */ jsx("span", { className: "truncate text-[0.8125rem] text-oca-ink-subtle", children: caption ?? "Code" }),
1572
+ copy ? /* @__PURE__ */ jsx(
1573
+ CopyButton,
1574
+ {
1575
+ value: code,
1576
+ label: "Copy code",
1577
+ className: "text-oca-ink-subtle hover:bg-white/10 hover:text-white"
1578
+ }
1579
+ ) : null
1580
+ ] }),
1581
+ /* @__PURE__ */ jsxs("div", { className: "relative", children: [
1582
+ /* @__PURE__ */ jsx(
1583
+ "div",
1584
+ {
1585
+ className: cn(folded && "overflow-hidden"),
1586
+ style: folded ? { maxHeight: `calc(${maxLines} * 1.625em + 2.5rem)` } : void 0,
1587
+ 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 }) }) })
1588
+ }
1589
+ ),
1590
+ foldable ? /* @__PURE__ */ jsx(
1591
+ "div",
1592
+ {
1593
+ className: cn(
1594
+ "flex justify-center px-5 pb-4",
1595
+ folded && "absolute inset-x-0 bottom-0 pt-16"
1596
+ ),
1597
+ style: folded ? { background: "linear-gradient(to top, var(--oca-code-surface) 40%, transparent)" } : void 0,
1598
+ children: /* @__PURE__ */ jsx(
1599
+ "button",
1600
+ {
1601
+ type: "button",
1602
+ onClick: () => setOpen((v) => !v),
1603
+ className: "rounded-full border border-white/20 px-4 py-1.5 text-[0.8125rem] text-white transition-colors hover:bg-white/10",
1604
+ children: open ? "Show less" : `Show all ${lines} lines`
1605
+ }
1606
+ )
1607
+ }
1608
+ ) : null
1609
+ ] })
1610
+ ]
1611
+ }
1612
+ );
1613
+ }
1614
+ function SplitBar({
1615
+ segments,
1616
+ caption,
1617
+ className
1618
+ }) {
1619
+ return /* @__PURE__ */ jsxs("figure", { className: cn("flex flex-col gap-5", className), children: [
1620
+ caption ? /* @__PURE__ */ jsx("figcaption", { className: "text-[0.9375rem]", children: caption }) : null,
1621
+ /* @__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(
1622
+ "div",
1623
+ {
1624
+ className: cn(
1625
+ "flex min-w-[4.25rem] items-end rounded-[1rem] px-3 pb-2.5 md:px-4 md:pb-3",
1626
+ s.tone === "card" ? "bg-white text-oca-ink" : "bg-oca-ink text-white"
1627
+ ),
1628
+ style: { flexBasis: `${s.pct}%` },
1629
+ children: /* @__PURE__ */ jsxs("span", { className: "oca-tabular text-[1.25rem] leading-none tracking-[-0.02em] md:text-[1.875rem]", children: [
1630
+ s.pct,
1631
+ "%"
1632
+ ] })
1633
+ },
1634
+ i
1635
+ )) }),
1636
+ /* @__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: [
1637
+ /* @__PURE__ */ jsxs("dt", { className: "sr-only", children: [
1638
+ s.pct,
1639
+ "%"
1640
+ ] }),
1641
+ /* @__PURE__ */ jsx(
1642
+ "span",
1643
+ {
1644
+ "aria-hidden": true,
1645
+ className: cn(
1646
+ "inline-block size-2.5 shrink-0 translate-y-[-1px] rounded-full",
1647
+ s.tone === "card" ? "bg-white" : "bg-oca-ink"
1648
+ )
1649
+ }
1650
+ ),
1651
+ /* @__PURE__ */ jsx("dd", { className: "text-[0.9375rem] leading-snug", children: s.label })
1652
+ ] }, i)) })
1653
+ ] });
1654
+ }
1655
+ var LABEL = {
1656
+ yes: "Yes",
1657
+ testing: "In testing",
1658
+ "not-yet": "Not yet",
1659
+ no: "No"
1660
+ };
1661
+ var TONE = {
1662
+ yes: "text-oca-accent-ink",
1663
+ testing: "text-foreground",
1664
+ "not-yet": "text-muted-foreground",
1665
+ no: "text-muted-foreground"
1666
+ };
1667
+ function TruthTable({
1668
+ rows,
1669
+ statusHeading = "Status",
1670
+ whatHeading = "What",
1671
+ className
1672
+ }) {
1673
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
1674
+ /* @__PURE__ */ jsx(
1675
+ "ul",
1676
+ {
1677
+ className: cn(
1678
+ "divide-y divide-oca-hairline-strong overflow-hidden rounded-xl border border-oca-hairline-strong bg-card sm:hidden",
1679
+ className
1680
+ ),
1681
+ children: rows.map((r, i) => /* @__PURE__ */ jsxs("li", { className: "flex flex-col gap-1.5 px-4 py-3.5", children: [
1682
+ /* @__PURE__ */ jsx("span", { className: cn("text-[0.875rem] font-medium", TONE[r.status]), children: LABEL[r.status] }),
1683
+ /* @__PURE__ */ jsx("span", { className: "text-[0.9375rem] leading-relaxed", children: r.what })
1684
+ ] }, i))
1685
+ }
1686
+ ),
1687
+ /* @__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: [
1688
+ /* @__PURE__ */ jsx("thead", { className: "bg-oca-table-head", children: /* @__PURE__ */ jsxs("tr", { children: [
1689
+ /* @__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 }),
1690
+ /* @__PURE__ */ jsx("th", { scope: "col", className: "border-b border-l border-oca-hairline-strong px-4 py-3 font-semibold", children: whatHeading })
1691
+ ] }) }),
1692
+ /* @__PURE__ */ jsx("tbody", { className: "bg-card", children: rows.map((r, i) => /* @__PURE__ */ jsxs("tr", { className: "align-top", children: [
1693
+ /* @__PURE__ */ jsx(
1694
+ "td",
1695
+ {
1696
+ className: cn(
1697
+ "border-t border-oca-hairline-strong px-4 py-3 font-medium",
1698
+ i === 0 && "border-t-0",
1699
+ TONE[r.status]
1700
+ ),
1701
+ children: LABEL[r.status]
1702
+ }
1703
+ ),
1704
+ /* @__PURE__ */ jsx(
1705
+ "td",
1706
+ {
1707
+ className: cn(
1708
+ "border-l border-t border-oca-hairline-strong px-4 py-3 leading-relaxed",
1709
+ i === 0 && "border-t-0"
1710
+ ),
1711
+ children: r.what
1712
+ }
1713
+ )
1714
+ ] }, i)) })
1715
+ ] }) })
1716
+ ] });
1717
+ }
1718
+ var INT = new Intl.NumberFormat("en-US", { maximumFractionDigits: 0 });
1719
+ var COMPACT = new Intl.NumberFormat("en-US", { notation: "compact", maximumFractionDigits: 1 });
1720
+ function satsText(value, opts = {}) {
1721
+ if (value == null || !Number.isFinite(value)) return null;
1722
+ const whole = Math.trunc(value);
1723
+ const body = (opts.compact ? COMPACT : INT).format(Math.abs(whole));
1724
+ const sign = whole < 0 ? "\u2212" : opts.signed && whole > 0 ? "+" : "";
1725
+ const unit = opts.unit === "none" ? "" : whole === 1 || whole === -1 ? " sat" : " sats";
1726
+ return `${sign}${body}${unit}`;
1727
+ }
1728
+ function Sats({ value, unit, compact, signed, unknown = "\u2014", className, ...props }) {
1729
+ const text = satsText(value, { unit, compact, signed });
1730
+ if (text === null) {
1731
+ return /* @__PURE__ */ jsxs("span", { className: cn("oca-tabular text-muted-foreground", className), ...props, children: [
1732
+ /* @__PURE__ */ jsx("span", { "aria-hidden": true, children: unknown }),
1733
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: "unknown" })
1734
+ ] });
1735
+ }
1736
+ return /* @__PURE__ */ jsx("span", { className: cn("oca-tabular whitespace-nowrap", className), ...props, children: text });
1737
+ }
1738
+ function UsdApprox({
1739
+ sats,
1740
+ usdPerBtc,
1741
+ className
1742
+ }) {
1743
+ if (sats == null || usdPerBtc == null || !Number.isFinite(sats) || !Number.isFinite(usdPerBtc)) return null;
1744
+ const usd = sats / 1e8 * usdPerBtc;
1745
+ const text = new Intl.NumberFormat("en-US", {
1746
+ style: "currency",
1747
+ currency: "USD",
1748
+ maximumFractionDigits: usd < 1 ? 4 : 2
1749
+ }).format(usd);
1750
+ return /* @__PURE__ */ jsxs("span", { className: cn("oca-tabular text-muted-foreground", className), children: [
1751
+ "\u2248 ",
1752
+ text
1753
+ ] });
1754
+ }
1755
+ function SatsFigure({
1756
+ label,
1757
+ value,
1758
+ hint,
1759
+ className
1760
+ }) {
1761
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-1.5", className), children: [
1762
+ /* @__PURE__ */ jsx("span", { className: "text-[0.9375rem] text-muted-foreground", children: label }),
1763
+ /* @__PURE__ */ jsxs("span", { className: "oca-display-3 oca-tabular", children: [
1764
+ /* @__PURE__ */ jsx(Sats, { value, unit: "none" }),
1765
+ /* @__PURE__ */ jsx("span", { className: "ml-2 text-[0.5em] tracking-normal text-muted-foreground", children: "sats" })
1766
+ ] }),
1767
+ hint ? /* @__PURE__ */ jsx("span", { className: "text-[0.875rem] text-muted-foreground", children: hint }) : null
1768
+ ] });
1769
+ }
1356
1770
  function NavLink({ item, className, onNavigate }) {
1357
1771
  const cls = cn(
1358
1772
  "rounded-full px-3 py-2 text-[0.9375rem] transition-colors",
@@ -1418,12 +1832,12 @@ function SiteFooter({
1418
1832
  className
1419
1833
  }) {
1420
1834
  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: [
1835
+ /* @__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: [
1836
+ /* @__PURE__ */ jsxs("div", { className: "col-span-2 flex flex-col gap-4 md:col-span-1", children: [
1423
1837
  /* @__PURE__ */ jsx(Lockup, { size: 26 }),
1424
1838
  fineprint ? /* @__PURE__ */ jsx("p", { className: "max-w-xs text-[0.9375rem] leading-relaxed text-muted-foreground", children: fineprint }) : null
1425
1839
  ] }),
1426
- columns.map((col) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
1840
+ columns.map((col) => /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col gap-1", children: [
1427
1841
  /* @__PURE__ */ jsx("p", { className: "mb-2 text-[0.875rem] font-medium", children: col.heading }),
1428
1842
  col.links.map((l) => /* @__PURE__ */ jsx(
1429
1843
  NavLink,
@@ -1439,8 +1853,8 @@ function SiteFooter({
1439
1853
  ] });
1440
1854
  }
1441
1855
  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,
1856
+ 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: [
1857
+ g.label ? /* @__PURE__ */ jsx("p", { className: "px-3 pb-1 text-[0.8125rem] text-muted-foreground", children: g.label }) : null,
1444
1858
  g.items.map((it) => /* @__PURE__ */ jsxs(
1445
1859
  Link2,
1446
1860
  {
@@ -1448,8 +1862,8 @@ function SideNav({ groups, onNavigate }) {
1448
1862
  onClick: onNavigate,
1449
1863
  "aria-current": it.active ? "page" : void 0,
1450
1864
  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",
1865
+ "flex h-9 items-center gap-3 rounded-xl px-3 text-[0.9375rem] transition-colors",
1866
+ "[&_svg]:size-[1.0625rem] [&_svg]:shrink-0",
1453
1867
  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
1868
  ),
1455
1869
  children: [
@@ -1462,8 +1876,56 @@ function SideNav({ groups, onNavigate }) {
1462
1876
  ))
1463
1877
  ] }, g.label ?? gi)) });
1464
1878
  }
1879
+ function SectionSwitch({
1880
+ sections,
1881
+ current,
1882
+ onNavigate
1883
+ }) {
1884
+ const cols = sections.length <= 3 ? sections.length : 2;
1885
+ return /* @__PURE__ */ jsx(
1886
+ "nav",
1887
+ {
1888
+ "aria-label": "Sections",
1889
+ className: cn("grid gap-1 bg-muted p-1", cols === sections.length ? "rounded-full" : "rounded-[1.25rem]"),
1890
+ style: { gridTemplateColumns: `repeat(${cols}, minmax(0, 1fr))` },
1891
+ children: sections.map((sec) => {
1892
+ const on = sec.id === current.id;
1893
+ return /* @__PURE__ */ jsx(
1894
+ Link2,
1895
+ {
1896
+ href: sec.href,
1897
+ onClick: onNavigate,
1898
+ "aria-current": on ? "true" : void 0,
1899
+ className: cn(
1900
+ "flex h-8 min-w-0 items-center justify-center rounded-full px-1.5 text-[0.8125rem] font-medium transition-colors",
1901
+ on ? "bg-card text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"
1902
+ ),
1903
+ children: /* @__PURE__ */ jsx("span", { className: "truncate", children: sec.label })
1904
+ },
1905
+ sec.id
1906
+ );
1907
+ })
1908
+ }
1909
+ );
1910
+ }
1911
+ var activeItem = (groups) => groups.flatMap((g) => g.items).find((it) => it.active);
1912
+ var warned = /* @__PURE__ */ new Set();
1913
+ function warnDuplicateLabels(groups) {
1914
+ if (typeof process === "undefined" || process.env.NODE_ENV === "production") return;
1915
+ const seen = /* @__PURE__ */ new Set();
1916
+ for (const it of groups.flatMap((g) => g.items)) {
1917
+ if (seen.has(it.label) && !warned.has(it.label)) {
1918
+ warned.add(it.label);
1919
+ console.warn(`AppShell: two pages are labelled "${it.label}"; give each its own name.`);
1920
+ }
1921
+ seen.add(it.label);
1922
+ }
1923
+ }
1465
1924
  function AppShell({
1466
1925
  nav,
1926
+ sections,
1927
+ activeSection,
1928
+ persistent = [],
1467
1929
  home = "/",
1468
1930
  account,
1469
1931
  banner,
@@ -1472,38 +1934,59 @@ function AppShell({
1472
1934
  className
1473
1935
  }) {
1474
1936
  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
- ] })
1937
+ const current = sections && sections.length > 0 ? sections.find((sec) => sec.id === activeSection) ?? sections.find((sec) => activeItem(sec.groups)) ?? sections[0] : void 0;
1938
+ const groups = current ? [...current.groups, ...persistent] : [...nav ?? [], ...persistent];
1939
+ warnDuplicateLabels(groups);
1940
+ const page = activeItem(groups);
1941
+ const place = useMemo(
1942
+ () => ({ section: current ? current.title ?? current.label : void 0, page: page?.label }),
1943
+ [current, page?.label]
1944
+ );
1945
+ const switcher = sections && current && sections.length > 1 ? /* @__PURE__ */ jsx(SectionSwitch, { sections, current, onNavigate: () => setOpen(false) }) : null;
1946
+ return /* @__PURE__ */ jsx(ShellContext.Provider, { value: place, children: /* @__PURE__ */ jsxs("div", { className: cn("min-h-dvh bg-background", className), children: [
1947
+ /* @__PURE__ */ jsxs("div", { className: "sticky top-0 z-40 border-b border-border bg-background/90 backdrop-blur-md lg:hidden", children: [
1948
+ /* @__PURE__ */ jsxs("div", { className: "flex h-14 items-center gap-2 px-3", children: [
1949
+ /* @__PURE__ */ jsxs(Sheet, { open, onOpenChange: setOpen, children: [
1950
+ /* @__PURE__ */ jsx(
1951
+ SheetTrigger,
1952
+ {
1953
+ className: "inline-flex size-10 items-center justify-center rounded-full hover:bg-accent",
1954
+ "aria-label": "Open navigation",
1955
+ children: /* @__PURE__ */ jsx(Menu, { className: "size-5" })
1956
+ }
1957
+ ),
1958
+ /* @__PURE__ */ jsxs(SheetContent, { side: "left", className: "flex flex-col gap-6 overflow-y-auto p-4 pt-16", children: [
1959
+ /* @__PURE__ */ jsx(SheetTitle, { className: "sr-only", children: "Navigation" }),
1960
+ switcher,
1961
+ /* @__PURE__ */ jsx(SideNav, { groups, onNavigate: () => setOpen(false) }),
1962
+ footer ? /* @__PURE__ */ jsx("div", { className: "mt-auto flex flex-col gap-3", children: footer }) : null
1963
+ ] })
1964
+ ] }),
1965
+ /* @__PURE__ */ jsx(Link2, { href: home, "aria-label": "Home", className: "rounded-lg p-1", children: /* @__PURE__ */ jsx(Lockup, { size: 22 }) }),
1966
+ /* @__PURE__ */ jsx("div", { className: "ml-auto flex items-center", children: account })
1490
1967
  ] }),
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 })
1968
+ place.page ? /* @__PURE__ */ jsxs("div", { className: "flex h-9 items-center gap-1.5 border-t border-border px-4 text-[0.875rem]", children: [
1969
+ place.section ? /* @__PURE__ */ jsxs(Fragment, { children: [
1970
+ /* @__PURE__ */ jsx("span", { className: "shrink-0 text-muted-foreground", children: place.section }),
1971
+ /* @__PURE__ */ jsx(ChevronRight, { "aria-hidden": true, className: "size-3.5 shrink-0 text-muted-foreground" })
1972
+ ] }) : null,
1973
+ /* @__PURE__ */ jsx("span", { className: "truncate font-medium", children: place.page })
1974
+ ] }) : null
1493
1975
  ] }),
1494
1976
  /* @__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: [
1977
+ /* @__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
1978
  /* @__PURE__ */ jsx(Link2, { href: home, className: "px-2", "aria-label": "Home", children: /* @__PURE__ */ jsx(Lockup, { size: 26 }) }),
1497
- /* @__PURE__ */ jsx(SideNav, { groups: nav }),
1979
+ switcher,
1980
+ /* @__PURE__ */ jsx(SideNav, { groups }),
1498
1981
  /* @__PURE__ */ jsx("div", { className: "mt-auto flex flex-col gap-3", children: footer })
1499
1982
  ] }),
1500
1983
  /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 flex-col", children: [
1501
1984
  /* @__PURE__ */ jsx("div", { className: "hidden h-[4.5rem] items-center justify-end gap-3 px-8 lg:flex", children: account }),
1502
1985
  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 })
1986
+ /* @__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
1987
  ] })
1505
1988
  ] })
1506
- ] });
1989
+ ] }) });
1507
1990
  }
1508
1991
  function AccountMenu({
1509
1992
  name,
@@ -1515,11 +1998,11 @@ function AccountMenu({
1515
1998
  /* @__PURE__ */ jsxs(
1516
1999
  DropdownMenuTrigger,
1517
2000
  {
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",
2001
+ 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
2002
  "aria-label": `Account: ${name}`,
1520
2003
  children: [
1521
2004
  /* @__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 })
2005
+ /* @__PURE__ */ jsx("span", { className: "max-w-[10rem] truncate max-sm:hidden", children: name })
1523
2006
  ]
1524
2007
  }
1525
2008
  ),
@@ -1564,6 +2047,6 @@ function ThemeToggle({ className }) {
1564
2047
  );
1565
2048
  }
1566
2049
 
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 };
2050
+ 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
2051
  //# sourceMappingURL=index.mjs.map
1569
2052
  //# sourceMappingURL=index.mjs.map