@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.js CHANGED
@@ -134,7 +134,26 @@ function Spinner({ className, label }) {
134
134
  );
135
135
  }
136
136
  function Skeleton({ className, ...props }) {
137
- return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-ui": "skeleton", className: cn("animate-pulse rounded-lg bg-muted", className), ...props });
137
+ return /* @__PURE__ */ jsxRuntime.jsx(
138
+ "div",
139
+ {
140
+ "data-ui": "skeleton",
141
+ className: cn("animate-pulse rounded-lg bg-[var(--oca-skeleton)]", className),
142
+ ...props
143
+ }
144
+ );
145
+ }
146
+ function useTimedOut(active, ms = 12e3) {
147
+ const [timedOut, setTimedOut] = react.useState(false);
148
+ react.useEffect(() => {
149
+ if (!active) {
150
+ setTimedOut(false);
151
+ return;
152
+ }
153
+ const t = setTimeout(() => setTimedOut(true), ms);
154
+ return () => clearTimeout(t);
155
+ }, [active, ms]);
156
+ return timedOut;
138
157
  }
139
158
  var Separator = react.forwardRef(function Separator2({ className, orientation = "horizontal", decorative = true, ...props }, ref) {
140
159
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -207,7 +226,10 @@ var buttonVariants = classVarianceAuthority.cva(
207
226
  "inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-full font-medium",
208
227
  "transition-[background-color,border-color,color,box-shadow,transform] duration-150",
209
228
  "outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
210
- "active:translate-y-px disabled:pointer-events-none disabled:opacity-45",
229
+ "active:translate-y-px disabled:pointer-events-none",
230
+ // Disabled is one look for every variant: a quiet grey pill, never a
231
+ // faded black or orange slab that reads as broken.
232
+ "disabled:border disabled:border-border disabled:bg-muted disabled:text-oca-subtle disabled:shadow-none",
211
233
  "[&_svg]:pointer-events-none [&_svg]:size-[1.1em] [&_svg]:shrink-0"
212
234
  ],
213
235
  {
@@ -253,6 +275,7 @@ var Button = react.forwardRef(function Button2({ className, variant, size, asChi
253
275
  }
254
276
  );
255
277
  });
278
+ var GOOD_DOT = "border-border bg-card text-foreground before:size-1.5 before:shrink-0 before:rounded-full before:bg-success before:content-['']";
256
279
  var badgeVariants = classVarianceAuthority.cva(
257
280
  "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",
258
281
  {
@@ -261,10 +284,13 @@ var badgeVariants = classVarianceAuthority.cva(
261
284
  neutral: "border-border bg-card text-foreground",
262
285
  muted: "border-transparent bg-muted text-muted-foreground",
263
286
  brand: "border-transparent bg-[color-mix(in_oklab,var(--oca-orange)_12%,var(--card))] text-oca-accent-ink",
264
- success: "border-transparent bg-[color-mix(in_oklab,var(--success)_12%,var(--card))] text-success",
265
- warning: "border-transparent bg-[color-mix(in_oklab,var(--warning)_14%,var(--card))] text-warning",
266
287
  danger: "border-transparent bg-[color-mix(in_oklab,var(--destructive)_12%,var(--card))] text-destructive",
267
- info: "border-transparent bg-[color-mix(in_oklab,var(--info)_12%,var(--card))] text-info",
288
+ // A good state is a neutral pill with a green dot, not a green pill.
289
+ success: GOOD_DOT,
290
+ // Aliases kept so older call sites keep compiling: attention is
291
+ // the brand accent, information is neutral.
292
+ warning: "border-transparent bg-[color-mix(in_oklab,var(--oca-orange)_12%,var(--card))] text-oca-accent-ink",
293
+ info: "border-border bg-card text-foreground",
268
294
  ink: "border-transparent bg-oca-ink text-oca-ink-foreground",
269
295
  onInk: "border-white/15 bg-white/5 text-white/90"
270
296
  }
@@ -375,7 +401,7 @@ var Label = react.forwardRef(function Label2({ className, ...props }, ref) {
375
401
  }
376
402
  );
377
403
  });
378
- function Field({ label, hint, error, children, className, hideLabel }) {
404
+ function Field({ label, hint, optional, error, children, className, hideLabel }) {
379
405
  const id = react.useId();
380
406
  const hintId = hint ? `${id}-hint` : void 0;
381
407
  const errorId = error ? `${id}-error` : void 0;
@@ -386,9 +412,12 @@ function Field({ label, hint, error, children, className, hideLabel }) {
386
412
  "aria-invalid": error ? true : void 0
387
413
  }) : children;
388
414
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-col gap-2", className), children: [
389
- /* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: id, className: hideLabel ? "sr-only" : void 0, children: label }),
390
- hint ? /* @__PURE__ */ jsxRuntime.jsx("p", { id: hintId, className: "text-[0.8125rem] leading-snug text-muted-foreground", children: hint }) : null,
415
+ /* @__PURE__ */ jsxRuntime.jsxs(Label, { htmlFor: id, className: hideLabel ? "sr-only" : "flex items-baseline gap-2", children: [
416
+ label,
417
+ optional ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[0.8125rem] font-normal text-muted-foreground", children: "Optional" }) : null
418
+ ] }),
391
419
  control,
420
+ hint ? /* @__PURE__ */ jsxRuntime.jsx("p", { id: hintId, className: "text-[0.8125rem] leading-snug text-muted-foreground", children: hint }) : null,
392
421
  error ? /* @__PURE__ */ jsxRuntime.jsx("p", { id: errorId, role: "alert", className: "text-[0.8125rem] leading-snug text-destructive", children: error }) : null
393
422
  ] });
394
423
  }
@@ -665,23 +694,69 @@ var DropdownMenuLabel = react.forwardRef(function DropdownMenuLabel2({ className
665
694
  var DropdownMenuSeparator = react.forwardRef(function DropdownMenuSeparator2({ className, ...props }, ref) {
666
695
  return /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuPrimitive__namespace.Separator, { ref, className: cn("my-1.5 h-px bg-border", className), ...props });
667
696
  });
697
+ function ScrollFade({ fade = "var(--card)", className, innerClassName, children, ...props }) {
698
+ const ref = react.useRef(null);
699
+ const [edges, setEdges] = react.useState({ left: false, right: false });
700
+ const measure = react.useCallback(() => {
701
+ const el = ref.current;
702
+ if (!el) return;
703
+ const left = el.scrollLeft > 1;
704
+ const right = el.scrollLeft + el.clientWidth < el.scrollWidth - 1;
705
+ setEdges((e) => e.left === left && e.right === right ? e : { left, right });
706
+ }, []);
707
+ react.useEffect(() => {
708
+ const el = ref.current;
709
+ if (!el) return;
710
+ measure();
711
+ if (typeof ResizeObserver === "undefined") return;
712
+ const ro = new ResizeObserver(measure);
713
+ ro.observe(el);
714
+ if (el.firstElementChild) ro.observe(el.firstElementChild);
715
+ return () => ro.disconnect();
716
+ }, [measure]);
717
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("relative min-w-0", className), ...props, children: [
718
+ /* @__PURE__ */ jsxRuntime.jsx("div", { ref, onScroll: measure, className: cn("overflow-x-auto overscroll-x-contain", innerClassName), children }),
719
+ /* @__PURE__ */ jsxRuntime.jsx(
720
+ "span",
721
+ {
722
+ "aria-hidden": true,
723
+ className: cn(
724
+ "pointer-events-none absolute inset-y-0 left-0 w-8 transition-opacity duration-150",
725
+ edges.left ? "opacity-100" : "opacity-0"
726
+ ),
727
+ style: { background: `linear-gradient(to right, ${fade}, transparent)` }
728
+ }
729
+ ),
730
+ /* @__PURE__ */ jsxRuntime.jsx(
731
+ "span",
732
+ {
733
+ "aria-hidden": true,
734
+ className: cn(
735
+ "pointer-events-none absolute inset-y-0 right-0 w-10 transition-opacity duration-150",
736
+ edges.right ? "opacity-100" : "opacity-0"
737
+ ),
738
+ style: { background: `linear-gradient(to left, ${fade}, transparent)` }
739
+ }
740
+ )
741
+ ] });
742
+ }
668
743
  var LookContext = react.createContext("pill");
669
744
  var Tabs = react.forwardRef(function Tabs2({ look = "pill", ...props }, ref) {
670
745
  return /* @__PURE__ */ jsxRuntime.jsx(LookContext.Provider, { value: look, children: /* @__PURE__ */ jsxRuntime.jsx(TabsPrimitive__namespace.Root, { ref, ...props }) });
671
746
  });
672
747
  var TabsList = react.forwardRef(function TabsList2({ className, ...props }, ref) {
673
748
  const look = react.useContext(LookContext);
674
- return /* @__PURE__ */ jsxRuntime.jsx(
749
+ return /* @__PURE__ */ jsxRuntime.jsx(ScrollFade, { fade: "var(--background)", className: look === "pill" ? "w-fit max-w-full" : "w-full", children: /* @__PURE__ */ jsxRuntime.jsx(
675
750
  TabsPrimitive__namespace.List,
676
751
  {
677
752
  ref,
678
753
  className: cn(
679
- 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",
754
+ 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",
680
755
  className
681
756
  ),
682
757
  ...props
683
758
  }
684
- );
759
+ ) });
685
760
  });
686
761
  var TabsTrigger = react.forwardRef(function TabsTrigger2({ className, ...props }, ref) {
687
762
  const look = react.useContext(LookContext);
@@ -887,7 +962,7 @@ function Prose({ className, ...props }) {
887
962
  {
888
963
  className: cn(
889
964
  "max-w-[42rem] text-[1.0625rem] leading-[1.7] text-muted-foreground",
890
- "[&_h2]:oca-display-3 [&_h2]:mb-4 [&_h2]:mt-14 [&_h2]:text-foreground",
965
+ "[&_h2]:oca-display-3 [&_h2]:mb-4 [&_h2]:mt-14 [&_h2]:scroll-mt-24 [&_h2]:text-foreground",
891
966
  "[&_h3]:oca-title [&_h3]:mb-3 [&_h3]:mt-10 [&_h3]:text-foreground",
892
967
  "[&_p]:my-4 [&_strong]:font-medium [&_strong]:text-foreground",
893
968
  "[&_a]:text-foreground [&_a]:underline [&_a]:decoration-border [&_a]:underline-offset-4 hover:[&_a]:decoration-foreground",
@@ -903,7 +978,9 @@ var sectionVariants = classVarianceAuthority.cva("relative w-full overflow-x-cli
903
978
  tone: {
904
979
  canvas: "bg-background text-foreground",
905
980
  card: "bg-card text-card-foreground",
906
- ink: "bg-oca-ink text-oca-ink-foreground",
981
+ // The band line is transparent in light; in dark it keeps the ink
982
+ // band from melting into the canvas.
983
+ ink: "border-y border-[var(--oca-band-line)] bg-oca-ink text-oca-ink-foreground",
907
984
  brand: "bg-brand text-brand-foreground"
908
985
  },
909
986
  space: {
@@ -938,6 +1015,120 @@ function SectionIntro({
938
1015
  }
939
1016
  );
940
1017
  }
1018
+ function PageHero({
1019
+ eyebrow,
1020
+ title,
1021
+ lead,
1022
+ actions,
1023
+ art,
1024
+ meta,
1025
+ children,
1026
+ variant = "page",
1027
+ size = "lg",
1028
+ className
1029
+ }) {
1030
+ if (variant === "document") {
1031
+ return /* @__PURE__ */ jsxRuntime.jsx(Section, { space: "none", className: cn("pb-12 pt-12 md:pb-16 md:pt-20", className), children: /* @__PURE__ */ jsxRuntime.jsx(DocHeader, { className: "mx-auto max-w-[42rem]", ...{ eyebrow, title, lead, meta, actions }, children }) });
1032
+ }
1033
+ return /* @__PURE__ */ jsxRuntime.jsx(Section, { space: "none", className: cn("pb-14 pt-12 md:pb-20 md:pt-20", className), children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("grid grid-cols-1 gap-10", art && "items-center md:grid-cols-12"), children: [
1034
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-col items-start gap-6", art ? "md:col-span-7" : "max-w-[52rem]"), children: [
1035
+ eyebrow ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "oca-eyebrow", children: eyebrow }) : null,
1036
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { className: size === "xl" ? "oca-display-1" : "oca-display-2", children: title }),
1037
+ lead ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "oca-lead max-w-[38rem]", children: lead }) : null,
1038
+ meta ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[0.875rem] text-muted-foreground", children: meta }) : null,
1039
+ actions ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-3", children: actions }) : null,
1040
+ children
1041
+ ] }),
1042
+ art ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "md:col-span-5", children: art }) : null
1043
+ ] }) });
1044
+ }
1045
+ function DocHeader({
1046
+ eyebrow,
1047
+ title,
1048
+ lead,
1049
+ meta,
1050
+ actions,
1051
+ children,
1052
+ className
1053
+ }) {
1054
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-col gap-5", className), children: [
1055
+ eyebrow ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "oca-eyebrow", children: eyebrow }) : null,
1056
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "oca-display-2", children: title }),
1057
+ lead ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "oca-lead", children: lead }) : null,
1058
+ meta ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[0.875rem] text-muted-foreground", children: meta }) : null,
1059
+ actions ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 flex flex-wrap gap-3", children: actions }) : null,
1060
+ children
1061
+ ] });
1062
+ }
1063
+ function useActiveHeading(ids) {
1064
+ const [active, setActive] = react.useState(ids[0]);
1065
+ const key = ids.join("|");
1066
+ react.useEffect(() => {
1067
+ const els = key.split("|").map((id) => document.getElementById(id)).filter((el) => el !== null);
1068
+ if (els.length === 0 || typeof IntersectionObserver === "undefined") return;
1069
+ const io = new IntersectionObserver(
1070
+ (entries) => {
1071
+ const hit = entries.filter((e) => e.isIntersecting).sort((a, b) => a.boundingClientRect.top - b.boundingClientRect.top)[0];
1072
+ if (hit) setActive(hit.target.id);
1073
+ },
1074
+ { rootMargin: "-80px 0px -65% 0px" }
1075
+ );
1076
+ els.forEach((el) => io.observe(el));
1077
+ return () => io.disconnect();
1078
+ }, [key]);
1079
+ return active;
1080
+ }
1081
+ function DocLayout({
1082
+ toc,
1083
+ header,
1084
+ children,
1085
+ className
1086
+ }) {
1087
+ const active = useActiveHeading(toc?.map((t) => t.id) ?? []);
1088
+ const links = () => toc?.map((t) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx(
1089
+ "a",
1090
+ {
1091
+ href: `#${t.id}`,
1092
+ "aria-current": active === t.id ? "location" : void 0,
1093
+ className: cn(
1094
+ "block border-l py-1.5 pl-4 text-[0.875rem] leading-snug transition-colors",
1095
+ active === t.id ? "border-foreground text-foreground" : "border-border text-muted-foreground hover:text-foreground"
1096
+ ),
1097
+ children: t.label
1098
+ }
1099
+ ) }, t.id));
1100
+ const hasToc = !!toc && toc.length > 0;
1101
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("oca-container pb-24", header ? "pt-12 md:pt-20" : null, className), children: /* @__PURE__ */ jsxRuntime.jsxs(
1102
+ "div",
1103
+ {
1104
+ className: cn(
1105
+ "mx-auto grid grid-cols-1 gap-8",
1106
+ 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]"
1107
+ ),
1108
+ children: [
1109
+ header ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn(hasToc && "lg:col-start-2", "pb-4"), children: header }) : null,
1110
+ hasToc ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1111
+ /* @__PURE__ */ jsxRuntime.jsxs(
1112
+ "nav",
1113
+ {
1114
+ "aria-label": "On this page",
1115
+ className: cn("sticky top-24 hidden self-start lg:block", header && "lg:row-start-2"),
1116
+ children: [
1117
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mb-3 text-[0.875rem] font-medium", children: "On this page" }),
1118
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { children: links() })
1119
+ ]
1120
+ }
1121
+ ),
1122
+ /* @__PURE__ */ jsxRuntime.jsxs("details", { className: "group rounded-2xl border border-border bg-card px-4 py-3 lg:hidden", children: [
1123
+ /* @__PURE__ */ jsxRuntime.jsx("summary", { className: "cursor-pointer list-none text-[0.9375rem] font-medium marker:hidden", children: "On this page" }),
1124
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "mt-3", children: links() })
1125
+ ] })
1126
+ ] }) : null,
1127
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("min-w-0", hasToc && "lg:col-start-2", hasToc && header && "lg:row-start-2"), children })
1128
+ ]
1129
+ }
1130
+ ) });
1131
+ }
941
1132
  var pad = (n) => String(n + 1).padStart(2, "0");
942
1133
  function StepGrid({ items, look = "cards", className }) {
943
1134
  const cols = items.length >= 3 ? "md:grid-cols-3" : items.length === 2 ? "md:grid-cols-2" : "";
@@ -965,322 +1156,299 @@ function StepGrid({ items, look = "cards", className }) {
965
1156
  ] }) }, i)
966
1157
  ) });
967
1158
  }
968
- var KIND = {
969
- package: "text-oca-code-package",
970
- tag: "text-oca-code-tag",
971
- link: "text-oca-code-link"
1159
+ var ShellContext = react.createContext({});
1160
+ function useShellPlace() {
1161
+ return react.useContext(ShellContext);
1162
+ }
1163
+ function PageHeader({
1164
+ eyebrow,
1165
+ title,
1166
+ description,
1167
+ actions,
1168
+ className
1169
+ }) {
1170
+ const place = useShellPlace();
1171
+ const eb = eyebrow === void 0 ? place.section : eyebrow;
1172
+ return /* @__PURE__ */ jsxRuntime.jsxs("header", { className: cn("flex flex-col gap-5 md:flex-row md:items-end md:justify-between", className), children: [
1173
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 max-w-[44rem] flex-col gap-2.5", children: [
1174
+ eb ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "oca-eyebrow", children: eb }) : null,
1175
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "oca-display-3", children: title }),
1176
+ description ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "oca-body max-w-[40rem] text-[1.0625rem]", children: description }) : null
1177
+ ] }),
1178
+ actions ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap items-center gap-2.5 md:shrink-0 md:justify-end", children: actions }) : null
1179
+ ] });
1180
+ }
1181
+ var InStatGrid = react.createContext(false);
1182
+ function StatCard({ label, value, hint, className }) {
1183
+ const inGrid = react.useContext(InStatGrid);
1184
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1185
+ "div",
1186
+ {
1187
+ "data-ui": "stat",
1188
+ className: cn(
1189
+ "rounded-[1.25rem] border border-border bg-card p-5 md:p-6",
1190
+ // In a grid, label, value and hint each share a row with their
1191
+ // neighbours, so values line up whatever wraps above them.
1192
+ inGrid ? "row-span-3 grid grid-rows-subgrid gap-1.5" : "flex flex-col gap-2",
1193
+ className
1194
+ ),
1195
+ children: [
1196
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[0.875rem] leading-snug text-muted-foreground", children: label }),
1197
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "self-end break-words oca-tabular text-[1.5rem] leading-tight tracking-[-0.02em] md:text-[1.75rem]", children: value }),
1198
+ hint ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[0.8125rem] leading-snug text-muted-foreground", children: hint }) : inGrid ? /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true }) : null
1199
+ ]
1200
+ }
1201
+ );
1202
+ }
1203
+ var MD_COLS = {
1204
+ 1: "md:grid-cols-1",
1205
+ 2: "md:grid-cols-2",
1206
+ 3: "md:grid-cols-3",
1207
+ 4: "md:grid-cols-4"
972
1208
  };
973
- function PackageCard({ items, className }) {
1209
+ var LG_COLS = {
1210
+ 1: "lg:grid-cols-1",
1211
+ 2: "lg:grid-cols-2",
1212
+ 3: "lg:grid-cols-3",
1213
+ 4: "lg:grid-cols-4",
1214
+ 5: "lg:grid-cols-5"
1215
+ };
1216
+ var MD_SPAN = {
1217
+ 1: "md:col-span-1",
1218
+ 2: "md:col-span-2",
1219
+ 3: "md:col-span-3",
1220
+ 4: "md:col-span-4"
1221
+ };
1222
+ var LG_SPAN = {
1223
+ 1: "lg:col-span-1",
1224
+ 2: "lg:col-span-2",
1225
+ 3: "lg:col-span-3",
1226
+ 4: "lg:col-span-4"
1227
+ };
1228
+ function statColumns(n) {
1229
+ if (n <= 5) return Math.max(1, n);
1230
+ if (n % 4 === 0) return 4;
1231
+ if (n % 3 === 0) return 3;
1232
+ return 4;
1233
+ }
1234
+ function lastSpan(n, cols) {
1235
+ const rest = n % cols;
1236
+ return rest === 0 ? 1 : cols - rest + 1;
1237
+ }
1238
+ function EmptyLine({ children, className }) {
974
1239
  return /* @__PURE__ */ jsxRuntime.jsx(
1240
+ "p",
1241
+ {
1242
+ className: cn(
1243
+ "rounded-[1.25rem] border border-dashed border-oca-hairline-strong px-5 py-4 text-[0.9375rem] text-muted-foreground",
1244
+ className
1245
+ ),
1246
+ children
1247
+ }
1248
+ );
1249
+ }
1250
+ function StatGrid({ columns, empty, isEmpty, className, children, ...props }) {
1251
+ const items = react.Children.toArray(children).filter(react.isValidElement);
1252
+ const n = items.length;
1253
+ const allZero = n > 0 && items.every((el) => "raw" in el.props && (el.props.raw === 0 || el.props.raw === null));
1254
+ if (isEmpty ?? allZero) return /* @__PURE__ */ jsxRuntime.jsx(EmptyLine, { className, children: empty ?? "Nothing here yet." });
1255
+ const lg = columns ?? statColumns(n);
1256
+ const md = lg > 4 ? 3 : lg;
1257
+ const mdSpan = lastSpan(n, md);
1258
+ const lgSpan = lastSpan(n, lg);
1259
+ return /* @__PURE__ */ jsxRuntime.jsx(InStatGrid.Provider, { value: true, children: /* @__PURE__ */ jsxRuntime.jsx(
975
1260
  "div",
976
1261
  {
977
1262
  className: cn(
978
- "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",
1263
+ "grid gap-3 md:gap-4",
1264
+ n === 1 ? "grid-cols-1" : "grid-cols-2",
1265
+ MD_COLS[md],
1266
+ LG_COLS[lg],
979
1267
  className
980
1268
  ),
981
- children: items.map((it, i) => {
982
- const code = /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("text-[0.9375rem]", KIND[it.kind ?? "package"]), children: it.code });
983
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-col gap-1.5", children: [
984
- /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-[1.125rem] font-semibold tracking-[-0.01em] text-oca-ink-title", children: it.title }),
985
- it.href ? /* @__PURE__ */ jsxRuntime.jsx("a", { href: it.href, className: "w-fit underline decoration-transparent underline-offset-4 hover:decoration-current", children: code }) : code,
986
- it.note ? /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-[0.9375rem] leading-relaxed text-oca-ink-subtle", children: [
987
- /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, children: "// " }),
988
- it.note
989
- ] }) : null
990
- ] }, i);
1269
+ ...props,
1270
+ children: items.map((el, i) => {
1271
+ if (i !== n - 1) return el;
1272
+ const span = cn(
1273
+ n % 2 === 1 && n > 1 && "max-md:col-span-2",
1274
+ (mdSpan > 1 || lgSpan > 1) && MD_SPAN[mdSpan],
1275
+ (mdSpan > 1 || lgSpan > 1) && LG_SPAN[lgSpan]
1276
+ );
1277
+ return span ? react.cloneElement(el, { className: cn(el.props.className, span) }) : el;
991
1278
  })
992
1279
  }
993
- );
1280
+ ) });
994
1281
  }
995
- function CodeBlock({
996
- code,
1282
+ function KeyValueList({ items, className }) {
1283
+ return /* @__PURE__ */ jsxRuntime.jsx("dl", { className: cn("divide-y divide-border rounded-[1.25rem] border border-border bg-card", className), children: items.map((it, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1 px-5 py-3.5 sm:flex-row sm:items-baseline sm:gap-6", children: [
1284
+ /* @__PURE__ */ jsxRuntime.jsx("dt", { className: "shrink-0 text-[0.875rem] text-muted-foreground sm:w-48", children: it.label }),
1285
+ /* @__PURE__ */ jsxRuntime.jsx("dd", { className: cn("min-w-0 break-words text-[0.9375rem]", it.mono && "font-mono text-[0.875rem]"), children: it.value })
1286
+ ] }, i)) });
1287
+ }
1288
+ function DataTable({
1289
+ columns,
1290
+ rows,
1291
+ rowKey,
1292
+ empty,
997
1293
  caption,
1294
+ phone = "cards",
998
1295
  className
999
1296
  }) {
1000
- return /* @__PURE__ */ jsxRuntime.jsxs("figure", { className: cn("overflow-hidden rounded-[1.25rem] border border-oca-ink-line bg-oca-ink-card", className), children: [
1001
- caption ? /* @__PURE__ */ jsxRuntime.jsx("figcaption", { className: "border-b border-oca-ink-line px-5 py-3 text-[0.8125rem] text-oca-ink-subtle", children: caption }) : null,
1002
- /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "overflow-x-auto p-5 font-mono text-[0.875rem] leading-relaxed text-oca-ink-muted", children: /* @__PURE__ */ jsxRuntime.jsx("code", { children: code }) })
1297
+ if (rows.length === 0 && empty) return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: empty });
1298
+ const primary = columns.find((c) => c.primary) ?? columns[0];
1299
+ const right = (c) => c.numeric || c.align === "end";
1300
+ const table = /* @__PURE__ */ jsxRuntime.jsx(
1301
+ "div",
1302
+ {
1303
+ className: cn(
1304
+ "overflow-hidden rounded-[1.25rem] border border-border bg-card",
1305
+ phone === "cards" && "max-sm:hidden",
1306
+ className
1307
+ ),
1308
+ children: /* @__PURE__ */ jsxRuntime.jsx(ScrollFade, { fade: "var(--card)", children: /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "w-full border-collapse text-left text-[0.9375rem]", children: [
1309
+ caption ? /* @__PURE__ */ jsxRuntime.jsx("caption", { className: "sr-only", children: caption }) : null,
1310
+ /* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsx("tr", { className: "border-b border-border", children: columns.map((c) => /* @__PURE__ */ jsxRuntime.jsx(
1311
+ "th",
1312
+ {
1313
+ scope: "col",
1314
+ style: { width: c.width, minWidth: c.minWidth },
1315
+ className: cn(
1316
+ "whitespace-nowrap px-5 py-3 text-[0.8125rem] font-medium text-muted-foreground",
1317
+ right(c) && "text-right",
1318
+ c.wide && "hidden md:table-cell"
1319
+ ),
1320
+ children: c.header
1321
+ },
1322
+ c.key
1323
+ )) }) }),
1324
+ /* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "divide-y divide-border", children: rows.map((r, i) => /* @__PURE__ */ jsxRuntime.jsx("tr", { className: "transition-colors hover:bg-accent/60", children: columns.map((c) => /* @__PURE__ */ jsxRuntime.jsx(
1325
+ "td",
1326
+ {
1327
+ style: { minWidth: c.minWidth },
1328
+ className: cn(
1329
+ "px-5 py-3.5 align-middle",
1330
+ right(c) && "text-right",
1331
+ c.numeric && "whitespace-nowrap oca-tabular",
1332
+ c.wide && "hidden md:table-cell"
1333
+ ),
1334
+ children: c.truncate ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "truncate", style: { maxWidth: c.width ?? "16rem" }, children: c.cell(r) }) : c.cell(r)
1335
+ },
1336
+ c.key
1337
+ )) }, rowKey(r, i))) })
1338
+ ] }) })
1339
+ }
1340
+ );
1341
+ if (phone !== "cards") return table;
1342
+ const rest = columns.filter((c) => c !== primary && !c.hideOnPhone);
1343
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1344
+ table,
1345
+ /* @__PURE__ */ jsxRuntime.jsx(
1346
+ "ul",
1347
+ {
1348
+ "aria-label": caption,
1349
+ className: cn("divide-y divide-border rounded-[1.25rem] border border-border bg-card sm:hidden", className),
1350
+ children: rows.map((r, i) => /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex flex-col gap-2.5 px-4 py-4", children: [
1351
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-w-0 break-words text-[0.9375rem] font-medium", children: primary?.cell(r) }),
1352
+ rest.length > 0 ? /* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsxs("div", { className: "contents", children: [
1353
+ /* @__PURE__ */ jsxRuntime.jsx("dt", { className: "text-muted-foreground", children: c.header }),
1354
+ /* @__PURE__ */ jsxRuntime.jsx("dd", { className: cn("min-w-0 break-words", c.numeric && "oca-tabular"), children: c.cell(r) })
1355
+ ] }, c.key)) }) : null
1356
+ ] }, rowKey(r, i)))
1357
+ }
1358
+ )
1003
1359
  ] });
1004
1360
  }
1005
- function SplitBar({
1006
- segments,
1007
- caption,
1361
+ function EmptyState({
1362
+ title,
1363
+ children,
1364
+ action,
1365
+ icon,
1008
1366
  className
1009
1367
  }) {
1010
- return /* @__PURE__ */ jsxRuntime.jsxs("figure", { className: cn("flex flex-col gap-5", className), children: [
1011
- caption ? /* @__PURE__ */ jsxRuntime.jsx("figcaption", { className: "text-[0.9375rem]", children: caption }) : null,
1012
- /* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsx(
1013
- "div",
1014
- {
1015
- className: cn(
1016
- "flex min-w-[4.25rem] items-end rounded-[1rem] px-3 pb-2.5 md:px-4 md:pb-3",
1017
- s.tone === "card" ? "bg-white text-oca-ink" : "bg-oca-ink text-white"
1018
- ),
1019
- style: { flexBasis: `${s.pct}%` },
1020
- children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "oca-tabular text-[1.25rem] leading-none tracking-[-0.02em] md:text-[1.875rem]", children: [
1021
- s.pct,
1022
- "%"
1023
- ] })
1024
- },
1025
- i
1026
- )) }),
1027
- /* @__PURE__ */ jsxRuntime.jsx("dl", { className: "grid gap-x-8 gap-y-2 sm:grid-cols-2", children: segments.map((s, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-baseline gap-2.5", children: [
1028
- /* @__PURE__ */ jsxRuntime.jsxs("dt", { className: "sr-only", children: [
1029
- s.pct,
1030
- "%"
1031
- ] }),
1032
- /* @__PURE__ */ jsxRuntime.jsx(
1033
- "span",
1034
- {
1035
- "aria-hidden": true,
1036
- className: cn(
1037
- "inline-block size-2.5 shrink-0 translate-y-[-1px] rounded-full",
1038
- s.tone === "card" ? "bg-white" : "bg-oca-ink"
1039
- )
1040
- }
1368
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1369
+ "div",
1370
+ {
1371
+ className: cn(
1372
+ "flex flex-col items-center gap-3 rounded-[1.25rem] border border-dashed border-oca-hairline-strong px-6 py-10 text-center",
1373
+ className
1041
1374
  ),
1042
- /* @__PURE__ */ jsxRuntime.jsx("dd", { className: "text-[0.9375rem] leading-snug", children: s.label })
1043
- ] }, i)) })
1044
- ] });
1375
+ children: [
1376
+ icon ? /* @__PURE__ */ jsxRuntime.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,
1377
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "oca-title-sm", children: title }),
1378
+ children ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "oca-body max-w-md text-[0.9375rem]", children }) : null,
1379
+ action ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2 flex flex-wrap justify-center gap-3", children: action }) : null
1380
+ ]
1381
+ }
1382
+ );
1045
1383
  }
1046
- var LABEL = {
1047
- yes: "Yes",
1048
- testing: "In testing",
1049
- "not-yet": "Not yet",
1050
- no: "No"
1051
- };
1052
- var TONE = {
1053
- yes: "text-oca-accent-ink",
1054
- testing: "text-foreground",
1055
- "not-yet": "text-muted-foreground",
1056
- no: "text-muted-foreground"
1384
+ var NOTICE_KIND = {
1385
+ neutral: "neutral",
1386
+ info: "neutral",
1387
+ success: "neutral",
1388
+ brand: "brand",
1389
+ warning: "brand",
1390
+ danger: "danger"
1057
1391
  };
1058
- function TruthTable({
1059
- rows,
1060
- statusHeading = "Status",
1061
- whatHeading = "What",
1392
+ function Notice({
1393
+ tone = "neutral",
1394
+ title,
1395
+ children,
1396
+ action,
1062
1397
  className
1063
1398
  }) {
1064
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("overflow-hidden rounded-xl border border-oca-hairline-strong", className), children: /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "w-full border-collapse text-left text-[0.9375rem] md:text-[1rem]", children: [
1065
- /* @__PURE__ */ jsxRuntime.jsx("thead", { className: "bg-oca-table-head", children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
1066
- /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", className: "w-[30%] border-b border-oca-hairline-strong px-4 py-3 font-semibold md:w-[22%]", children: statusHeading }),
1067
- /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", className: "border-b border-l border-oca-hairline-strong px-4 py-3 font-semibold", children: whatHeading })
1068
- ] }) }),
1069
- /* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "bg-card", children: rows.map((r, i) => /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "align-top", children: [
1070
- /* @__PURE__ */ jsxRuntime.jsx(
1071
- "td",
1072
- {
1073
- className: cn(
1074
- "border-t border-oca-hairline-strong px-4 py-3 font-medium",
1075
- i === 0 && "border-t-0",
1076
- TONE[r.status]
1077
- ),
1078
- children: LABEL[r.status]
1079
- }
1080
- ),
1081
- /* @__PURE__ */ jsxRuntime.jsx(
1082
- "td",
1083
- {
1084
- className: cn(
1085
- "border-l border-t border-oca-hairline-strong px-4 py-3 leading-relaxed",
1086
- i === 0 && "border-t-0"
1087
- ),
1088
- children: r.what
1089
- }
1090
- )
1091
- ] }, i)) })
1092
- ] }) });
1093
- }
1094
- var INT = new Intl.NumberFormat("en-US", { maximumFractionDigits: 0 });
1095
- var COMPACT = new Intl.NumberFormat("en-US", { notation: "compact", maximumFractionDigits: 1 });
1096
- function satsText(value, opts = {}) {
1097
- if (value == null || !Number.isFinite(value)) return null;
1098
- const whole = Math.trunc(value);
1099
- const body = (opts.compact ? COMPACT : INT).format(Math.abs(whole));
1100
- const sign = whole < 0 ? "\u2212" : opts.signed && whole > 0 ? "+" : "";
1101
- const unit = opts.unit === "none" ? "" : whole === 1 || whole === -1 ? " sat" : " sats";
1102
- return `${sign}${body}${unit}`;
1103
- }
1104
- function Sats({ value, unit, compact, signed, unknown = "\u2014", className, ...props }) {
1105
- const text = satsText(value, { unit, compact, signed });
1106
- if (text === null) {
1107
- return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn("oca-tabular text-muted-foreground", className), ...props, children: [
1108
- /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, children: unknown }),
1109
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "unknown" })
1110
- ] });
1111
- }
1112
- return /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("oca-tabular whitespace-nowrap", className), ...props, children: text });
1113
- }
1114
- function UsdApprox({
1115
- sats,
1116
- usdPerBtc,
1117
- className
1118
- }) {
1119
- if (sats == null || usdPerBtc == null || !Number.isFinite(sats) || !Number.isFinite(usdPerBtc)) return null;
1120
- const usd = sats / 1e8 * usdPerBtc;
1121
- const text = new Intl.NumberFormat("en-US", {
1122
- style: "currency",
1123
- currency: "USD",
1124
- maximumFractionDigits: usd < 1 ? 4 : 2
1125
- }).format(usd);
1126
- return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn("oca-tabular text-muted-foreground", className), children: [
1127
- "\u2248 ",
1128
- text
1129
- ] });
1130
- }
1131
- function SatsFigure({
1132
- label,
1133
- value,
1134
- hint,
1135
- className
1136
- }) {
1137
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-col gap-1.5", className), children: [
1138
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[0.9375rem] text-muted-foreground", children: label }),
1139
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "oca-display-3 oca-tabular", children: [
1140
- /* @__PURE__ */ jsxRuntime.jsx(Sats, { value, unit: "none" }),
1141
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-2 text-[0.5em] tracking-normal text-muted-foreground", children: "sats" })
1142
- ] }),
1143
- hint ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[0.875rem] text-muted-foreground", children: hint }) : null
1144
- ] });
1145
- }
1146
- function PageHeader({
1147
- eyebrow,
1148
- title,
1149
- description,
1150
- actions,
1151
- className
1152
- }) {
1153
- return /* @__PURE__ */ jsxRuntime.jsxs("header", { className: cn("flex flex-col gap-5 md:flex-row md:items-end md:justify-between", className), children: [
1154
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex max-w-[44rem] flex-col gap-3", children: [
1155
- eyebrow ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "oca-eyebrow", children: eyebrow }) : null,
1156
- /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "oca-display-3", children: title }),
1157
- description ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "oca-body text-[1.0625rem]", children: description }) : null
1158
- ] }),
1159
- actions ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex shrink-0 flex-wrap items-center gap-3", children: actions }) : null
1160
- ] });
1161
- }
1162
- function StatCard({
1163
- label,
1164
- value,
1165
- hint,
1166
- className
1167
- }) {
1168
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-col gap-2 rounded-[1.25rem] border border-border bg-card p-5 md:p-6", className), children: [
1169
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[0.875rem] text-muted-foreground", children: label }),
1170
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "oca-tabular text-[1.75rem] leading-tight tracking-[-0.02em]", children: value }),
1171
- hint ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[0.8125rem] leading-snug text-muted-foreground", children: hint }) : null
1172
- ] });
1173
- }
1174
- function StatGrid({ className, ...props }) {
1175
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("grid grid-cols-2 gap-3 md:grid-cols-4 md:gap-4", className), ...props });
1176
- }
1177
- function KeyValueList({ items, className }) {
1178
- return /* @__PURE__ */ jsxRuntime.jsx("dl", { className: cn("divide-y divide-border rounded-[1.25rem] border border-border bg-card", className), children: items.map((it, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1 px-5 py-3.5 sm:flex-row sm:items-baseline sm:gap-6", children: [
1179
- /* @__PURE__ */ jsxRuntime.jsx("dt", { className: "shrink-0 text-[0.875rem] text-muted-foreground sm:w-48", children: it.label }),
1180
- /* @__PURE__ */ jsxRuntime.jsx("dd", { className: cn("min-w-0 break-words text-[0.9375rem]", it.mono && "font-mono text-[0.875rem]"), children: it.value })
1181
- ] }, i)) });
1182
- }
1183
- function DataTable({
1184
- columns,
1185
- rows,
1186
- rowKey,
1187
- empty,
1188
- caption,
1189
- className
1190
- }) {
1191
- if (rows.length === 0 && empty) return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: empty });
1192
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("overflow-x-auto rounded-[1.25rem] border border-border bg-card", className), children: /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "w-full border-collapse text-left text-[0.9375rem]", children: [
1193
- caption ? /* @__PURE__ */ jsxRuntime.jsx("caption", { className: "sr-only", children: caption }) : null,
1194
- /* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsx("tr", { className: "border-b border-border", children: columns.map((c) => /* @__PURE__ */ jsxRuntime.jsx(
1195
- "th",
1196
- {
1197
- scope: "col",
1198
- className: cn(
1199
- "whitespace-nowrap px-5 py-3 text-[0.8125rem] font-medium text-muted-foreground",
1200
- c.align === "end" && "text-right",
1201
- c.wide && "hidden md:table-cell"
1202
- ),
1203
- children: c.header
1204
- },
1205
- c.key
1206
- )) }) }),
1207
- /* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "divide-y divide-border", children: rows.map((r, i) => /* @__PURE__ */ jsxRuntime.jsx("tr", { className: "transition-colors hover:bg-accent/60", children: columns.map((c) => /* @__PURE__ */ jsxRuntime.jsx(
1208
- "td",
1209
- {
1210
- className: cn(
1211
- "px-5 py-3.5 align-middle",
1212
- c.align === "end" && "text-right",
1213
- c.wide && "hidden md:table-cell"
1214
- ),
1215
- children: c.cell(r)
1216
- },
1217
- c.key
1218
- )) }, rowKey(r, i))) })
1219
- ] }) });
1220
- }
1221
- function EmptyState({
1222
- title,
1223
- children,
1224
- action,
1225
- className
1226
- }) {
1227
- return /* @__PURE__ */ jsxRuntime.jsxs(
1228
- "div",
1229
- {
1230
- className: cn(
1231
- "flex flex-col items-center gap-4 rounded-[1.25rem] border border-dashed border-oca-hairline-strong px-6 py-12 text-center",
1232
- className
1399
+ const kind = NOTICE_KIND[tone];
1400
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1401
+ "div",
1402
+ {
1403
+ role: tone === "danger" || tone === "warning" ? "alert" : "note",
1404
+ "data-tone": kind,
1405
+ className: cn(
1406
+ "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",
1407
+ kind === "danger" && "border-[color-mix(in_oklab,var(--destructive)_40%,var(--border))]",
1408
+ className
1233
1409
  ),
1234
1410
  children: [
1235
- /* @__PURE__ */ jsxRuntime.jsx(Mark, { size: 56 }),
1236
- /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "oca-title-sm", children: title }),
1237
- children ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "oca-body max-w-md text-[0.9375rem]", children }) : null,
1238
- action ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 flex flex-wrap justify-center gap-3", children: action }) : null
1411
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 gap-3", children: [
1412
+ kind !== "neutral" ? /* @__PURE__ */ jsxRuntime.jsx(
1413
+ "span",
1414
+ {
1415
+ "aria-hidden": true,
1416
+ className: cn(
1417
+ "mt-[0.45rem] size-2 shrink-0 rounded-full",
1418
+ kind === "brand" ? "bg-oca-orange" : "bg-destructive"
1419
+ )
1420
+ }
1421
+ ) : null,
1422
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-col gap-1", children: [
1423
+ title ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: cn("text-[0.9375rem] font-medium", kind === "danger" && "text-destructive"), children: title }) : null,
1424
+ children ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-[0.9375rem] leading-relaxed text-muted-foreground", children }) : null
1425
+ ] })
1426
+ ] }),
1427
+ action ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0", children: action }) : null
1239
1428
  ]
1240
1429
  }
1241
1430
  );
1242
1431
  }
1243
- var NOTICE = {
1244
- neutral: "border-border bg-card",
1245
- info: "border-[color-mix(in_oklab,var(--info)_30%,var(--border))] bg-[color-mix(in_oklab,var(--info)_6%,var(--card))]",
1246
- success: "border-[color-mix(in_oklab,var(--success)_30%,var(--border))] bg-[color-mix(in_oklab,var(--success)_6%,var(--card))]",
1247
- warning: "border-[color-mix(in_oklab,var(--warning)_35%,var(--border))] bg-[color-mix(in_oklab,var(--warning)_7%,var(--card))]",
1248
- danger: "border-[color-mix(in_oklab,var(--destructive)_32%,var(--border))] bg-[color-mix(in_oklab,var(--destructive)_6%,var(--card))]",
1249
- brand: "border-[color-mix(in_oklab,var(--oca-orange)_35%,var(--border))] bg-[color-mix(in_oklab,var(--oca-orange)_7%,var(--card))]"
1250
- };
1251
- var NOTICE_TITLE = {
1252
- neutral: "text-foreground",
1253
- info: "text-info",
1254
- success: "text-success",
1255
- warning: "text-warning",
1256
- danger: "text-destructive",
1257
- brand: "text-oca-accent-ink"
1258
- };
1259
- function Notice({
1260
- tone = "neutral",
1261
- title,
1262
- children,
1263
- action,
1432
+ function LoadingBlock({
1433
+ rows = 3,
1434
+ timeoutMs = 12e3,
1435
+ onRetry,
1436
+ label = "Loading",
1264
1437
  className
1265
1438
  }) {
1266
- return /* @__PURE__ */ jsxRuntime.jsxs(
1267
- "div",
1268
- {
1269
- role: tone === "danger" || tone === "warning" ? "alert" : "note",
1270
- className: cn(
1271
- "flex flex-col gap-3 rounded-2xl border px-5 py-4 sm:flex-row sm:items-start sm:justify-between",
1272
- NOTICE[tone],
1273
- className
1274
- ),
1275
- children: [
1276
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-col gap-1", children: [
1277
- title ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: cn("text-[0.9375rem] font-medium", NOTICE_TITLE[tone]), children: title }) : null,
1278
- children ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-[0.9375rem] leading-relaxed text-foreground/85", children }) : null
1279
- ] }),
1280
- action ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0", children: action }) : null
1281
- ]
1282
- }
1283
- );
1439
+ const timedOut = useTimedOut(true, timeoutMs);
1440
+ if (timedOut) {
1441
+ return /* @__PURE__ */ jsxRuntime.jsx(
1442
+ Notice,
1443
+ {
1444
+ className,
1445
+ title: "This is taking longer than it should.",
1446
+ action: /* @__PURE__ */ jsxRuntime.jsx(Button, { size: "sm", variant: "secondary", onClick: onRetry ?? (() => window.location.reload()), children: "Try again" }),
1447
+ children: "Check your connection, then try again."
1448
+ }
1449
+ );
1450
+ }
1451
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { role: "status", "aria-label": label, className: cn("flex flex-col gap-3", className), children: Array.from({ length: rows }, (_, i) => /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { className: "h-16 rounded-2xl" }, i)) });
1284
1452
  }
1285
1453
  function middle(v, head, tail) {
1286
1454
  return v.length <= head + tail + 1 ? v : `${v.slice(0, head)}\u2026${v.slice(-tail)}`;
@@ -1387,6 +1555,252 @@ function ActivityList({ items, empty, className }) {
1387
1555
  return /* @__PURE__ */ jsxRuntime.jsx("li", { children: it.href ? /* @__PURE__ */ jsxRuntime.jsx("a", { href: it.href, className: "block transition-colors hover:bg-accent/60", children: body }) : body }, it.id);
1388
1556
  }) });
1389
1557
  }
1558
+ var KIND = {
1559
+ package: "text-oca-code-package",
1560
+ tag: "text-oca-code-tag",
1561
+ link: "text-oca-code-link"
1562
+ };
1563
+ function PackageCard({ items, className }) {
1564
+ return /* @__PURE__ */ jsxRuntime.jsx(
1565
+ "div",
1566
+ {
1567
+ className: cn(
1568
+ "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",
1569
+ className
1570
+ ),
1571
+ children: items.map((it, i) => {
1572
+ const code = /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("text-[0.9375rem]", KIND[it.kind ?? "package"]), children: it.code });
1573
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-col gap-1.5", children: [
1574
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-[1.125rem] font-semibold tracking-[-0.01em] text-oca-ink-title", children: it.title }),
1575
+ it.href ? /* @__PURE__ */ jsxRuntime.jsx("a", { href: it.href, className: "w-fit underline decoration-transparent underline-offset-4 hover:decoration-current", children: code }) : code,
1576
+ it.note ? /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-[0.9375rem] leading-relaxed text-oca-ink-subtle", children: [
1577
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, children: "// " }),
1578
+ it.note
1579
+ ] }) : null
1580
+ ] }, i);
1581
+ })
1582
+ }
1583
+ );
1584
+ }
1585
+ function CodeBlock({
1586
+ code,
1587
+ caption,
1588
+ copy = true,
1589
+ maxLines,
1590
+ className
1591
+ }) {
1592
+ const lines = code.split("\n").length;
1593
+ const foldable = maxLines !== void 0 && lines > maxLines + 2;
1594
+ const [open, setOpen] = react.useState(false);
1595
+ const folded = foldable && !open;
1596
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1597
+ "figure",
1598
+ {
1599
+ className: cn(
1600
+ "overflow-hidden rounded-[1.25rem] border border-[var(--oca-code-line)] bg-[var(--oca-code-surface)]",
1601
+ className
1602
+ ),
1603
+ children: [
1604
+ /* @__PURE__ */ jsxRuntime.jsxs("figcaption", { className: "flex h-11 items-center justify-between gap-3 border-b border-[var(--oca-code-line)] pl-5 pr-2", children: [
1605
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-[0.8125rem] text-oca-ink-subtle", children: caption ?? "Code" }),
1606
+ copy ? /* @__PURE__ */ jsxRuntime.jsx(
1607
+ CopyButton,
1608
+ {
1609
+ value: code,
1610
+ label: "Copy code",
1611
+ className: "text-oca-ink-subtle hover:bg-white/10 hover:text-white"
1612
+ }
1613
+ ) : null
1614
+ ] }),
1615
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
1616
+ /* @__PURE__ */ jsxRuntime.jsx(
1617
+ "div",
1618
+ {
1619
+ className: cn(folded && "overflow-hidden"),
1620
+ style: folded ? { maxHeight: `calc(${maxLines} * 1.625em + 2.5rem)` } : void 0,
1621
+ children: /* @__PURE__ */ jsxRuntime.jsx(ScrollFade, { fade: "var(--oca-code-surface)", children: /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "w-max min-w-full p-5 font-mono text-[0.875rem] leading-[1.625] text-oca-ink-muted", children: /* @__PURE__ */ jsxRuntime.jsx("code", { children: code }) }) })
1622
+ }
1623
+ ),
1624
+ foldable ? /* @__PURE__ */ jsxRuntime.jsx(
1625
+ "div",
1626
+ {
1627
+ className: cn(
1628
+ "flex justify-center px-5 pb-4",
1629
+ folded && "absolute inset-x-0 bottom-0 pt-16"
1630
+ ),
1631
+ style: folded ? { background: "linear-gradient(to top, var(--oca-code-surface) 40%, transparent)" } : void 0,
1632
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1633
+ "button",
1634
+ {
1635
+ type: "button",
1636
+ onClick: () => setOpen((v) => !v),
1637
+ className: "rounded-full border border-white/20 px-4 py-1.5 text-[0.8125rem] text-white transition-colors hover:bg-white/10",
1638
+ children: open ? "Show less" : `Show all ${lines} lines`
1639
+ }
1640
+ )
1641
+ }
1642
+ ) : null
1643
+ ] })
1644
+ ]
1645
+ }
1646
+ );
1647
+ }
1648
+ function SplitBar({
1649
+ segments,
1650
+ caption,
1651
+ className
1652
+ }) {
1653
+ return /* @__PURE__ */ jsxRuntime.jsxs("figure", { className: cn("flex flex-col gap-5", className), children: [
1654
+ caption ? /* @__PURE__ */ jsxRuntime.jsx("figcaption", { className: "text-[0.9375rem]", children: caption }) : null,
1655
+ /* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsx(
1656
+ "div",
1657
+ {
1658
+ className: cn(
1659
+ "flex min-w-[4.25rem] items-end rounded-[1rem] px-3 pb-2.5 md:px-4 md:pb-3",
1660
+ s.tone === "card" ? "bg-white text-oca-ink" : "bg-oca-ink text-white"
1661
+ ),
1662
+ style: { flexBasis: `${s.pct}%` },
1663
+ children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "oca-tabular text-[1.25rem] leading-none tracking-[-0.02em] md:text-[1.875rem]", children: [
1664
+ s.pct,
1665
+ "%"
1666
+ ] })
1667
+ },
1668
+ i
1669
+ )) }),
1670
+ /* @__PURE__ */ jsxRuntime.jsx("dl", { className: "grid gap-x-8 gap-y-2 sm:grid-cols-2", children: segments.map((s, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-baseline gap-2.5", children: [
1671
+ /* @__PURE__ */ jsxRuntime.jsxs("dt", { className: "sr-only", children: [
1672
+ s.pct,
1673
+ "%"
1674
+ ] }),
1675
+ /* @__PURE__ */ jsxRuntime.jsx(
1676
+ "span",
1677
+ {
1678
+ "aria-hidden": true,
1679
+ className: cn(
1680
+ "inline-block size-2.5 shrink-0 translate-y-[-1px] rounded-full",
1681
+ s.tone === "card" ? "bg-white" : "bg-oca-ink"
1682
+ )
1683
+ }
1684
+ ),
1685
+ /* @__PURE__ */ jsxRuntime.jsx("dd", { className: "text-[0.9375rem] leading-snug", children: s.label })
1686
+ ] }, i)) })
1687
+ ] });
1688
+ }
1689
+ var LABEL = {
1690
+ yes: "Yes",
1691
+ testing: "In testing",
1692
+ "not-yet": "Not yet",
1693
+ no: "No"
1694
+ };
1695
+ var TONE = {
1696
+ yes: "text-oca-accent-ink",
1697
+ testing: "text-foreground",
1698
+ "not-yet": "text-muted-foreground",
1699
+ no: "text-muted-foreground"
1700
+ };
1701
+ function TruthTable({
1702
+ rows,
1703
+ statusHeading = "Status",
1704
+ whatHeading = "What",
1705
+ className
1706
+ }) {
1707
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1708
+ /* @__PURE__ */ jsxRuntime.jsx(
1709
+ "ul",
1710
+ {
1711
+ className: cn(
1712
+ "divide-y divide-oca-hairline-strong overflow-hidden rounded-xl border border-oca-hairline-strong bg-card sm:hidden",
1713
+ className
1714
+ ),
1715
+ children: rows.map((r, i) => /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex flex-col gap-1.5 px-4 py-3.5", children: [
1716
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("text-[0.875rem] font-medium", TONE[r.status]), children: LABEL[r.status] }),
1717
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[0.9375rem] leading-relaxed", children: r.what })
1718
+ ] }, i))
1719
+ }
1720
+ ),
1721
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("overflow-hidden rounded-xl border border-oca-hairline-strong max-sm:hidden", className), children: /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "w-full border-collapse text-left text-[0.9375rem] md:text-[1rem]", children: [
1722
+ /* @__PURE__ */ jsxRuntime.jsx("thead", { className: "bg-oca-table-head", children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
1723
+ /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", className: "w-[30%] border-b border-oca-hairline-strong px-4 py-3 font-semibold md:w-[22%]", children: statusHeading }),
1724
+ /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", className: "border-b border-l border-oca-hairline-strong px-4 py-3 font-semibold", children: whatHeading })
1725
+ ] }) }),
1726
+ /* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "bg-card", children: rows.map((r, i) => /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "align-top", children: [
1727
+ /* @__PURE__ */ jsxRuntime.jsx(
1728
+ "td",
1729
+ {
1730
+ className: cn(
1731
+ "border-t border-oca-hairline-strong px-4 py-3 font-medium",
1732
+ i === 0 && "border-t-0",
1733
+ TONE[r.status]
1734
+ ),
1735
+ children: LABEL[r.status]
1736
+ }
1737
+ ),
1738
+ /* @__PURE__ */ jsxRuntime.jsx(
1739
+ "td",
1740
+ {
1741
+ className: cn(
1742
+ "border-l border-t border-oca-hairline-strong px-4 py-3 leading-relaxed",
1743
+ i === 0 && "border-t-0"
1744
+ ),
1745
+ children: r.what
1746
+ }
1747
+ )
1748
+ ] }, i)) })
1749
+ ] }) })
1750
+ ] });
1751
+ }
1752
+ var INT = new Intl.NumberFormat("en-US", { maximumFractionDigits: 0 });
1753
+ var COMPACT = new Intl.NumberFormat("en-US", { notation: "compact", maximumFractionDigits: 1 });
1754
+ function satsText(value, opts = {}) {
1755
+ if (value == null || !Number.isFinite(value)) return null;
1756
+ const whole = Math.trunc(value);
1757
+ const body = (opts.compact ? COMPACT : INT).format(Math.abs(whole));
1758
+ const sign = whole < 0 ? "\u2212" : opts.signed && whole > 0 ? "+" : "";
1759
+ const unit = opts.unit === "none" ? "" : whole === 1 || whole === -1 ? " sat" : " sats";
1760
+ return `${sign}${body}${unit}`;
1761
+ }
1762
+ function Sats({ value, unit, compact, signed, unknown = "\u2014", className, ...props }) {
1763
+ const text = satsText(value, { unit, compact, signed });
1764
+ if (text === null) {
1765
+ return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn("oca-tabular text-muted-foreground", className), ...props, children: [
1766
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, children: unknown }),
1767
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "unknown" })
1768
+ ] });
1769
+ }
1770
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("oca-tabular whitespace-nowrap", className), ...props, children: text });
1771
+ }
1772
+ function UsdApprox({
1773
+ sats,
1774
+ usdPerBtc,
1775
+ className
1776
+ }) {
1777
+ if (sats == null || usdPerBtc == null || !Number.isFinite(sats) || !Number.isFinite(usdPerBtc)) return null;
1778
+ const usd = sats / 1e8 * usdPerBtc;
1779
+ const text = new Intl.NumberFormat("en-US", {
1780
+ style: "currency",
1781
+ currency: "USD",
1782
+ maximumFractionDigits: usd < 1 ? 4 : 2
1783
+ }).format(usd);
1784
+ return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn("oca-tabular text-muted-foreground", className), children: [
1785
+ "\u2248 ",
1786
+ text
1787
+ ] });
1788
+ }
1789
+ function SatsFigure({
1790
+ label,
1791
+ value,
1792
+ hint,
1793
+ className
1794
+ }) {
1795
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-col gap-1.5", className), children: [
1796
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[0.9375rem] text-muted-foreground", children: label }),
1797
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "oca-display-3 oca-tabular", children: [
1798
+ /* @__PURE__ */ jsxRuntime.jsx(Sats, { value, unit: "none" }),
1799
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-2 text-[0.5em] tracking-normal text-muted-foreground", children: "sats" })
1800
+ ] }),
1801
+ hint ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[0.875rem] text-muted-foreground", children: hint }) : null
1802
+ ] });
1803
+ }
1390
1804
  function NavLink({ item, className, onNavigate }) {
1391
1805
  const cls = cn(
1392
1806
  "rounded-full px-3 py-2 text-[0.9375rem] transition-colors",
@@ -1452,12 +1866,12 @@ function SiteFooter({
1452
1866
  className
1453
1867
  }) {
1454
1868
  return /* @__PURE__ */ jsxRuntime.jsxs("footer", { className: cn("border-t border-border bg-background", className), children: [
1455
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "oca-container grid gap-10 py-14 md:grid-cols-[1.3fr_repeat(3,1fr)] md:py-16", children: [
1456
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-4", children: [
1869
+ /* @__PURE__ */ jsxRuntime.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: [
1870
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "col-span-2 flex flex-col gap-4 md:col-span-1", children: [
1457
1871
  /* @__PURE__ */ jsxRuntime.jsx(Lockup, { size: 26 }),
1458
1872
  fineprint ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "max-w-xs text-[0.9375rem] leading-relaxed text-muted-foreground", children: fineprint }) : null
1459
1873
  ] }),
1460
- columns.map((col) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [
1874
+ columns.map((col) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-col gap-1", children: [
1461
1875
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mb-2 text-[0.875rem] font-medium", children: col.heading }),
1462
1876
  col.links.map((l) => /* @__PURE__ */ jsxRuntime.jsx(
1463
1877
  NavLink,
@@ -1473,8 +1887,8 @@ function SiteFooter({
1473
1887
  ] });
1474
1888
  }
1475
1889
  function SideNav({ groups, onNavigate }) {
1476
- return /* @__PURE__ */ jsxRuntime.jsx("nav", { "aria-label": "Sections", className: "flex flex-col gap-6", children: groups.map((g, gi) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-0.5", children: [
1477
- g.label ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "px-3 pb-1.5 text-[0.8125rem] text-muted-foreground", children: g.label }) : null,
1890
+ return /* @__PURE__ */ jsxRuntime.jsx("nav", { "aria-label": "Pages", className: "flex flex-col gap-5", children: groups.map((g, gi) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-0.5", children: [
1891
+ g.label ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "px-3 pb-1 text-[0.8125rem] text-muted-foreground", children: g.label }) : null,
1478
1892
  g.items.map((it) => /* @__PURE__ */ jsxRuntime.jsxs(
1479
1893
  Link2__default.default,
1480
1894
  {
@@ -1482,8 +1896,8 @@ function SideNav({ groups, onNavigate }) {
1482
1896
  onClick: onNavigate,
1483
1897
  "aria-current": it.active ? "page" : void 0,
1484
1898
  className: cn(
1485
- "flex h-10 items-center gap-3 rounded-xl px-3 text-[0.9375rem] transition-colors",
1486
- "[&_svg]:size-[1.125rem] [&_svg]:shrink-0",
1899
+ "flex h-9 items-center gap-3 rounded-xl px-3 text-[0.9375rem] transition-colors",
1900
+ "[&_svg]:size-[1.0625rem] [&_svg]:shrink-0",
1487
1901
  it.active ? "bg-card text-foreground shadow-sm ring-1 ring-border [&_svg]:text-foreground" : "text-muted-foreground hover:bg-accent hover:text-foreground"
1488
1902
  ),
1489
1903
  children: [
@@ -1496,8 +1910,56 @@ function SideNav({ groups, onNavigate }) {
1496
1910
  ))
1497
1911
  ] }, g.label ?? gi)) });
1498
1912
  }
1913
+ function SectionSwitch({
1914
+ sections,
1915
+ current,
1916
+ onNavigate
1917
+ }) {
1918
+ const cols = sections.length <= 3 ? sections.length : 2;
1919
+ return /* @__PURE__ */ jsxRuntime.jsx(
1920
+ "nav",
1921
+ {
1922
+ "aria-label": "Sections",
1923
+ className: cn("grid gap-1 bg-muted p-1", cols === sections.length ? "rounded-full" : "rounded-[1.25rem]"),
1924
+ style: { gridTemplateColumns: `repeat(${cols}, minmax(0, 1fr))` },
1925
+ children: sections.map((sec) => {
1926
+ const on = sec.id === current.id;
1927
+ return /* @__PURE__ */ jsxRuntime.jsx(
1928
+ Link2__default.default,
1929
+ {
1930
+ href: sec.href,
1931
+ onClick: onNavigate,
1932
+ "aria-current": on ? "true" : void 0,
1933
+ className: cn(
1934
+ "flex h-8 min-w-0 items-center justify-center rounded-full px-1.5 text-[0.8125rem] font-medium transition-colors",
1935
+ on ? "bg-card text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"
1936
+ ),
1937
+ children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: sec.label })
1938
+ },
1939
+ sec.id
1940
+ );
1941
+ })
1942
+ }
1943
+ );
1944
+ }
1945
+ var activeItem = (groups) => groups.flatMap((g) => g.items).find((it) => it.active);
1946
+ var warned = /* @__PURE__ */ new Set();
1947
+ function warnDuplicateLabels(groups) {
1948
+ if (typeof process === "undefined" || process.env.NODE_ENV === "production") return;
1949
+ const seen = /* @__PURE__ */ new Set();
1950
+ for (const it of groups.flatMap((g) => g.items)) {
1951
+ if (seen.has(it.label) && !warned.has(it.label)) {
1952
+ warned.add(it.label);
1953
+ console.warn(`AppShell: two pages are labelled "${it.label}"; give each its own name.`);
1954
+ }
1955
+ seen.add(it.label);
1956
+ }
1957
+ }
1499
1958
  function AppShell({
1500
1959
  nav,
1960
+ sections,
1961
+ activeSection,
1962
+ persistent = [],
1501
1963
  home = "/",
1502
1964
  account,
1503
1965
  banner,
@@ -1506,38 +1968,59 @@ function AppShell({
1506
1968
  className
1507
1969
  }) {
1508
1970
  const [open, setOpen] = react.useState(false);
1509
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("min-h-dvh bg-background", className), children: [
1510
- /* @__PURE__ */ jsxRuntime.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: [
1511
- /* @__PURE__ */ jsxRuntime.jsxs(Sheet, { open, onOpenChange: setOpen, children: [
1512
- /* @__PURE__ */ jsxRuntime.jsx(
1513
- SheetTrigger,
1514
- {
1515
- className: "inline-flex size-10 items-center justify-center rounded-full hover:bg-accent",
1516
- "aria-label": "Open navigation",
1517
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Menu, { className: "size-5" })
1518
- }
1519
- ),
1520
- /* @__PURE__ */ jsxRuntime.jsxs(SheetContent, { side: "left", className: "p-4 pt-16", children: [
1521
- /* @__PURE__ */ jsxRuntime.jsx(SheetTitle, { className: "sr-only", children: "Navigation" }),
1522
- /* @__PURE__ */ jsxRuntime.jsx(SideNav, { groups: nav, onNavigate: () => setOpen(false) })
1523
- ] })
1971
+ const current = sections && sections.length > 0 ? sections.find((sec) => sec.id === activeSection) ?? sections.find((sec) => activeItem(sec.groups)) ?? sections[0] : void 0;
1972
+ const groups = current ? [...current.groups, ...persistent] : [...nav ?? [], ...persistent];
1973
+ warnDuplicateLabels(groups);
1974
+ const page = activeItem(groups);
1975
+ const place = react.useMemo(
1976
+ () => ({ section: current ? current.title ?? current.label : void 0, page: page?.label }),
1977
+ [current, page?.label]
1978
+ );
1979
+ const switcher = sections && current && sections.length > 1 ? /* @__PURE__ */ jsxRuntime.jsx(SectionSwitch, { sections, current, onNavigate: () => setOpen(false) }) : null;
1980
+ return /* @__PURE__ */ jsxRuntime.jsx(ShellContext.Provider, { value: place, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("min-h-dvh bg-background", className), children: [
1981
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sticky top-0 z-40 border-b border-border bg-background/90 backdrop-blur-md lg:hidden", children: [
1982
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-14 items-center gap-2 px-3", children: [
1983
+ /* @__PURE__ */ jsxRuntime.jsxs(Sheet, { open, onOpenChange: setOpen, children: [
1984
+ /* @__PURE__ */ jsxRuntime.jsx(
1985
+ SheetTrigger,
1986
+ {
1987
+ className: "inline-flex size-10 items-center justify-center rounded-full hover:bg-accent",
1988
+ "aria-label": "Open navigation",
1989
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Menu, { className: "size-5" })
1990
+ }
1991
+ ),
1992
+ /* @__PURE__ */ jsxRuntime.jsxs(SheetContent, { side: "left", className: "flex flex-col gap-6 overflow-y-auto p-4 pt-16", children: [
1993
+ /* @__PURE__ */ jsxRuntime.jsx(SheetTitle, { className: "sr-only", children: "Navigation" }),
1994
+ switcher,
1995
+ /* @__PURE__ */ jsxRuntime.jsx(SideNav, { groups, onNavigate: () => setOpen(false) }),
1996
+ footer ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-auto flex flex-col gap-3", children: footer }) : null
1997
+ ] })
1998
+ ] }),
1999
+ /* @__PURE__ */ jsxRuntime.jsx(Link2__default.default, { href: home, "aria-label": "Home", className: "rounded-lg p-1", children: /* @__PURE__ */ jsxRuntime.jsx(Lockup, { size: 22 }) }),
2000
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ml-auto flex items-center", children: account })
1524
2001
  ] }),
1525
- /* @__PURE__ */ jsxRuntime.jsx(Link2__default.default, { href: home, "aria-label": "Home", children: /* @__PURE__ */ jsxRuntime.jsx(AppIcon, { size: 28 }) }),
1526
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center", children: account })
2002
+ place.page ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-9 items-center gap-1.5 border-t border-border px-4 text-[0.875rem]", children: [
2003
+ place.section ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2004
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 text-muted-foreground", children: place.section }),
2005
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { "aria-hidden": true, className: "size-3.5 shrink-0 text-muted-foreground" })
2006
+ ] }) : null,
2007
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate font-medium", children: place.page })
2008
+ ] }) : null
1527
2009
  ] }),
1528
2010
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mx-auto flex w-full max-w-[90rem]", children: [
1529
- /* @__PURE__ */ jsxRuntime.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: [
2011
+ /* @__PURE__ */ jsxRuntime.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: [
1530
2012
  /* @__PURE__ */ jsxRuntime.jsx(Link2__default.default, { href: home, className: "px-2", "aria-label": "Home", children: /* @__PURE__ */ jsxRuntime.jsx(Lockup, { size: 26 }) }),
1531
- /* @__PURE__ */ jsxRuntime.jsx(SideNav, { groups: nav }),
2013
+ switcher,
2014
+ /* @__PURE__ */ jsxRuntime.jsx(SideNav, { groups }),
1532
2015
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-auto flex flex-col gap-3", children: footer })
1533
2016
  ] }),
1534
2017
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-1 flex-col", children: [
1535
2018
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden h-[4.5rem] items-center justify-end gap-3 px-8 lg:flex", children: account }),
1536
2019
  banner ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 pb-2 pt-4 md:px-8 lg:pt-0", children: banner }) : null,
1537
- /* @__PURE__ */ jsxRuntime.jsx("main", { id: "main-content", className: "flex-1 px-4 pb-16 pt-6 md:px-8 lg:pt-2", children })
2020
+ /* @__PURE__ */ jsxRuntime.jsx("main", { id: "main-content", className: "flex-1 px-4 pb-16 pt-6 md:px-8 lg:pt-2", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-auto w-full max-w-[72rem]", children }) })
1538
2021
  ] })
1539
2022
  ] })
1540
- ] });
2023
+ ] }) });
1541
2024
  }
1542
2025
  function AccountMenu({
1543
2026
  name,
@@ -1549,11 +2032,11 @@ function AccountMenu({
1549
2032
  /* @__PURE__ */ jsxRuntime.jsxs(
1550
2033
  DropdownMenuTrigger,
1551
2034
  {
1552
- 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",
2035
+ 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",
1553
2036
  "aria-label": `Account: ${name}`,
1554
2037
  children: [
1555
2038
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex size-8 items-center justify-center rounded-full bg-foreground text-[0.8125rem] font-medium text-background", children: initial }),
1556
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "max-w-[10rem] truncate", children: name })
2039
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "max-w-[10rem] truncate max-sm:hidden", children: name })
1557
2040
  ]
1558
2041
  }
1559
2042
  ),
@@ -1633,6 +2116,8 @@ exports.DialogHeader = DialogHeader;
1633
2116
  exports.DialogTitle = DialogTitle;
1634
2117
  exports.DialogTrigger = DialogTrigger;
1635
2118
  exports.Display = Display;
2119
+ exports.DocHeader = DocHeader;
2120
+ exports.DocLayout = DocLayout;
1636
2121
  exports.DropdownMenu = DropdownMenu;
1637
2122
  exports.DropdownMenuContent = DropdownMenuContent;
1638
2123
  exports.DropdownMenuGroup = DropdownMenuGroup;
@@ -1640,6 +2125,7 @@ exports.DropdownMenuItem = DropdownMenuItem;
1640
2125
  exports.DropdownMenuLabel = DropdownMenuLabel;
1641
2126
  exports.DropdownMenuSeparator = DropdownMenuSeparator;
1642
2127
  exports.DropdownMenuTrigger = DropdownMenuTrigger;
2128
+ exports.EmptyLine = EmptyLine;
1643
2129
  exports.EmptyState = EmptyState;
1644
2130
  exports.Eyebrow = Eyebrow;
1645
2131
  exports.Field = Field;
@@ -1652,12 +2138,14 @@ exports.Kbd = Kbd;
1652
2138
  exports.KeyValueList = KeyValueList;
1653
2139
  exports.Label = Label;
1654
2140
  exports.Lead = Lead;
2141
+ exports.LoadingBlock = LoadingBlock;
1655
2142
  exports.Lockup = Lockup;
1656
2143
  exports.MARK_FACES = MARK_FACES;
1657
2144
  exports.Mark = Mark;
1658
2145
  exports.Notice = Notice;
1659
2146
  exports.PackageCard = PackageCard;
1660
2147
  exports.PageHeader = PageHeader;
2148
+ exports.PageHero = PageHero;
1661
2149
  exports.Popover = Popover;
1662
2150
  exports.PopoverAnchor = PopoverAnchor;
1663
2151
  exports.PopoverContent = PopoverContent;
@@ -1669,6 +2157,7 @@ exports.RadioGroupItem = RadioGroupItem;
1669
2157
  exports.SPHERE_GRADIENT = SPHERE_GRADIENT;
1670
2158
  exports.Sats = Sats;
1671
2159
  exports.SatsFigure = SatsFigure;
2160
+ exports.ScrollFade = ScrollFade;
1672
2161
  exports.Section = Section;
1673
2162
  exports.SectionIntro = SectionIntro;
1674
2163
  exports.Select = Select;
@@ -1684,6 +2173,7 @@ exports.SheetContent = SheetContent;
1684
2173
  exports.SheetDescription = SheetDescription;
1685
2174
  exports.SheetTitle = SheetTitle;
1686
2175
  exports.SheetTrigger = SheetTrigger;
2176
+ exports.ShellContext = ShellContext;
1687
2177
  exports.SiteFooter = SiteFooter;
1688
2178
  exports.SiteHeader = SiteHeader;
1689
2179
  exports.Skeleton = Skeleton;
@@ -1717,5 +2207,7 @@ exports.cn = cn;
1717
2207
  exports.satsText = satsText;
1718
2208
  exports.sectionVariants = sectionVariants;
1719
2209
  exports.useCopy = useCopy;
2210
+ exports.useShellPlace = useShellPlace;
2211
+ exports.useTimedOut = useTimedOut;
1720
2212
  //# sourceMappingURL=index.js.map
1721
2213
  //# sourceMappingURL=index.js.map