@orangecheck/app-design 1.4.1 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/dist/chrome.d.mts +2 -2
  2. package/dist/chrome.d.ts +2 -2
  3. package/dist/chrome.js +162 -35
  4. package/dist/chrome.js.map +1 -1
  5. package/dist/chrome.mjs +163 -36
  6. package/dist/chrome.mjs.map +1 -1
  7. package/dist/components.d.mts +99 -6
  8. package/dist/components.d.ts +99 -6
  9. package/dist/components.js +546 -26
  10. package/dist/components.js.map +1 -1
  11. package/dist/components.mjs +535 -28
  12. package/dist/components.mjs.map +1 -1
  13. package/dist/index.d.mts +4 -4
  14. package/dist/index.d.ts +4 -4
  15. package/dist/index.js +737 -82
  16. package/dist/index.js.map +1 -1
  17. package/dist/index.mjs +727 -84
  18. package/dist/index.mjs.map +1 -1
  19. package/dist/mdx.js.map +1 -1
  20. package/dist/mdx.mjs.map +1 -1
  21. package/dist/primitives.d.mts +1 -0
  22. package/dist/primitives.d.ts +1 -0
  23. package/dist/primitives.js +27 -0
  24. package/dist/primitives.js.map +1 -1
  25. package/dist/primitives.mjs +27 -0
  26. package/dist/primitives.mjs.map +1 -1
  27. package/dist/session.d.mts +3 -3
  28. package/dist/session.d.ts +3 -3
  29. package/dist/session.js.map +1 -1
  30. package/dist/session.mjs.map +1 -1
  31. package/dist/styles/chart.css +76 -0
  32. package/dist/styles/theme.css +7 -0
  33. package/dist/styles/tokens.css +18 -0
  34. package/dist/styles.css +1 -0
  35. package/dist/tokens.d.mts +314 -21
  36. package/dist/tokens.d.ts +314 -21
  37. package/dist/tokens.js +166 -26
  38. package/dist/tokens.js.map +1 -1
  39. package/dist/tokens.mjs +165 -27
  40. package/dist/tokens.mjs.map +1 -1
  41. package/dist/{tool-shell-D8Q8XX11.d.mts → tool-shell-CQZNRUgH.d.mts} +8 -4
  42. package/dist/{tool-shell-gmlj47Ie.d.ts → tool-shell-CRmceGrV.d.ts} +8 -4
  43. package/dist/{tools-DFIxIj5p.d.mts → tools-Bg1gi2HO.d.mts} +1 -1
  44. package/dist/{tools-BggNN5DV.d.ts → tools-Bw7RhO92.d.ts} +1 -1
  45. package/package.json +2 -2
package/dist/index.mjs CHANGED
@@ -13,7 +13,7 @@ import * as LabelPrimitive from '@radix-ui/react-label';
13
13
  import * as RadioGroupPrimitive from '@radix-ui/react-radio-group';
14
14
  import * as SelectPrimitive from '@radix-ui/react-select';
15
15
  import * as SwitchPrimitive from '@radix-ui/react-switch';
16
- import { ChevronDown, Check, X, Search, ArrowUpRight, ArrowRight, Copy, ChevronLeft, ChevronRight, CornerDownLeft, Download, FileText, Upload, Menu, Sun, Moon, SunMoon, PanelLeft, CircleUser, LogOut, ArrowLeft, Lock, CircleDashed, CircleMinus, CircleSlash, Clock, CircleX, CircleCheck } from 'lucide-react';
16
+ import { ChevronDown, Check, X, Search, ArrowUpRight, ArrowRight, Copy, ChevronLeft, ChevronRight, Lock, Info, CornerDownLeft, Download, FileText, Upload, Menu, Sun, Moon, SunMoon, PanelLeft, CircleUser, LogOut, ArrowLeft, Maximize2, CircleDashed, CircleMinus, CircleSlash, Clock, CircleX, CircleCheck, Ellipsis } from 'lucide-react';
17
17
  import * as DialogPrimitive from '@radix-ui/react-dialog';
18
18
  import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
19
19
  import * as PopoverPrimitive from '@radix-ui/react-popover';
@@ -23,36 +23,174 @@ import QRCode from 'qrcode';
23
23
  import Link6 from 'next/link';
24
24
  import { useRouter } from 'next/compat/router';
25
25
 
26
+ // src/tokens/palette.ts
27
+ var lightPalette = {
28
+ accent: "#f4f4f4",
29
+ accentDisplay: "#f55819",
30
+ accentForeground: "#0a0a0a",
31
+ accentInk: "#c73f09",
32
+ background: "#fafafa",
33
+ border: "#ececec",
34
+ brand: "#f66d36",
35
+ brandForeground: "#0a0a0a",
36
+ card: "#ffffff",
37
+ cardForeground: "#0a0a0a",
38
+ chart1: "#ea580b",
39
+ chart2: "#2563eb",
40
+ chart3: "#9d2b77",
41
+ chart4: "#92400e",
42
+ chartDown: "#c2262e",
43
+ chartGrid: "#ececec",
44
+ chartNeutral: "#8a8f96",
45
+ chartUp: "#15803d",
46
+ codeAdded: "#86d39b",
47
+ codeAddedLine: "#1a2c20",
48
+ codeComment: "#909397",
49
+ codeFunction: "#9db4ec",
50
+ codeKeyword: "#e3a8c2",
51
+ codeLine: "#2a2a2a",
52
+ codeLink: "#9db4ec",
53
+ codeMark: "#232323",
54
+ codeNumber: "#fcb781",
55
+ codePackage: "#e99a8f",
56
+ codeProperty: "#9db4ec",
57
+ codePunctuation: "#d5d8dc",
58
+ codeRemoved: "#f19a9a",
59
+ codeRemovedLine: "#2f1c1c",
60
+ codeString: "#e99a8f",
61
+ codeSurface: "#161616",
62
+ codeTag: "#e3a8c2",
63
+ codeType: "#8fd0c2",
64
+ destructive: "#c2262e",
65
+ destructiveForeground: "#ffffff",
66
+ foreground: "#0a0a0a",
67
+ hairlineStrong: "#dadada",
68
+ info: "#1d4ed8",
69
+ infoForeground: "#ffffff",
70
+ ink: "#0a0a0a",
71
+ inkCard: "#1e1e1e",
72
+ inkEyebrow: "#f0835a",
73
+ inkForeground: "#ffffff",
74
+ inkLine: "#2a2a2a",
75
+ inkMuted: "#d5d8dc",
76
+ inkSubtle: "#909397",
77
+ inkTitle: "#fcb781",
78
+ input: "#8f8f8f",
79
+ muted: "#f2f2f2",
80
+ mutedForeground: "#54585e",
81
+ ocWalletReady: "#15803d",
82
+ ocWalletSurface: "#ffffff",
83
+ orange: "#f66d36",
84
+ orangeDeep: "#ea580b",
85
+ orangeLight: "#fb933c",
86
+ outline: "#f2cfc3",
87
+ peach: "#fed8ab",
88
+ popover: "#ffffff",
89
+ popoverForeground: "#0a0a0a",
90
+ primary: "#0a0a0a",
91
+ primaryForeground: "#ffffff",
92
+ ring: "#ea580b",
93
+ secondary: "#ffffff",
94
+ secondaryForeground: "#0a0a0a",
95
+ skeleton: "#e8e8e8",
96
+ sphereFrom: "#ff6f33",
97
+ sphereTo: "#ffd9c4",
98
+ subtleForeground: "#686c72",
99
+ success: "#15803d",
100
+ successForeground: "#ffffff",
101
+ tableHead: "#ededed",
102
+ warning: "#a15c07",
103
+ warningForeground: "#ffffff"
104
+ };
105
+ var darkPalette = {
106
+ accent: "#1e1e1e",
107
+ accentDisplay: "#f66d36",
108
+ accentForeground: "#fafafa",
109
+ accentInk: "#f0835a",
110
+ background: "#0a0a0a",
111
+ bandLine: "#262626",
112
+ border: "#2a2a2a",
113
+ brand: "#f66d36",
114
+ brandForeground: "#0a0a0a",
115
+ card: "#161616",
116
+ cardForeground: "#fafafa",
117
+ chart1: "#f66d36",
118
+ chart2: "#3b82f6",
119
+ chart3: "#f9a8d4",
120
+ chart4: "#fde047",
121
+ chartDown: "#f87171",
122
+ chartGrid: "#2a2a2a",
123
+ chartNeutral: "#62676e",
124
+ chartUp: "#4ade80",
125
+ codeAdded: "#86d39b",
126
+ codeAddedLine: "#132519",
127
+ codeComment: "#909397",
128
+ codeFunction: "#9db4ec",
129
+ codeKeyword: "#e3a8c2",
130
+ codeLine: "#2a2a2a",
131
+ codeLink: "#9db4ec",
132
+ codeMark: "#1b1b1b",
133
+ codeNumber: "#fcb781",
134
+ codePackage: "#e99a8f",
135
+ codeProperty: "#9db4ec",
136
+ codePunctuation: "#d5d8dc",
137
+ codeRemoved: "#f19a9a",
138
+ codeRemovedLine: "#271414",
139
+ codeString: "#e99a8f",
140
+ codeSurface: "#0e0e0e",
141
+ codeTag: "#e3a8c2",
142
+ codeType: "#8fd0c2",
143
+ destructive: "#f87171",
144
+ destructiveForeground: "#0a0a0a",
145
+ foreground: "#fafafa",
146
+ hairlineStrong: "#333333",
147
+ iconRing: "#333333",
148
+ iconTile: "#1e1e1e",
149
+ info: "#93c5fd",
150
+ infoForeground: "#0a0a0a",
151
+ ink: "#171717",
152
+ inkCard: "#1e1e1e",
153
+ inkEyebrow: "#f0835a",
154
+ inkForeground: "#ffffff",
155
+ inkLine: "#2a2a2a",
156
+ inkMuted: "#d5d8dc",
157
+ inkSubtle: "#909397",
158
+ inkTitle: "#fcb781",
159
+ input: "#6a6a6a",
160
+ muted: "#1e1e1e",
161
+ mutedForeground: "#a3a6aa",
162
+ ocWalletReady: "#4ade80",
163
+ ocWalletSurface: "#161616",
164
+ orange: "#f66d36",
165
+ orangeDeep: "#ea580b",
166
+ orangeLight: "#fb933c",
167
+ outline: "#3a2a24",
168
+ peach: "#fed8ab",
169
+ popover: "#1a1a1a",
170
+ popoverForeground: "#fafafa",
171
+ primary: "#fafafa",
172
+ primaryForeground: "#0a0a0a",
173
+ ring: "#f66d36",
174
+ secondary: "#1c1c1c",
175
+ secondaryForeground: "#fafafa",
176
+ skeleton: "#222222",
177
+ sphereFrom: "#ff6f33",
178
+ sphereTo: "#ffd9c4",
179
+ subtleForeground: "#8b8e93",
180
+ success: "#4ade80",
181
+ successForeground: "#0a0a0a",
182
+ tableHead: "#1e1e1e",
183
+ warning: "#fbbf24",
184
+ warningForeground: "#0a0a0a"
185
+ };
186
+
26
187
  // src/tokens/index.ts
27
188
  var APP_ATTRIBUTE = "data-oc-app";
28
189
  var APP_ID = "ochk";
29
190
  var appColors = {
30
- light: {
31
- background: "#FAFAFA",
32
- foreground: "#0A0A0A",
33
- card: "#FFFFFF",
34
- muted: "#F2F2F2",
35
- mutedForeground: "#54585E",
36
- subtleForeground: "#686C72",
37
- border: "#ECECEC",
38
- hairlineStrong: "#DADADA",
39
- accentDisplay: "#F55819",
40
- accentInk: "#C73F09",
41
- ring: "#EA580B"
42
- },
43
- dark: {
44
- background: "#0A0A0A",
45
- foreground: "#FAFAFA",
46
- card: "#161616",
47
- muted: "#1E1E1E",
48
- mutedForeground: "#A3A6AA",
49
- subtleForeground: "#8B8E93",
50
- border: "#2A2A2A",
51
- hairlineStrong: "#333333",
52
- accentDisplay: "#F66D36",
53
- accentInk: "#F0835A",
54
- ring: "#F66D36"
55
- },
191
+ /** Every colour token, generated from tokens.css (palette.ts): the chart series, code, ink and status colours too. */
192
+ light: lightPalette,
193
+ dark: darkPalette,
56
194
  brand: {
57
195
  orange: "#F66D36",
58
196
  orangeLight: "#FB933C",
@@ -931,7 +1069,9 @@ var none = () => null;
931
1069
  function PromptBody({ ask: a }) {
932
1070
  const o = a.options;
933
1071
  const [value, setValue] = useState(o.defaultValue ?? "");
1072
+ const [again, setAgain] = useState("");
934
1073
  const [error, setError] = useState(null);
1074
+ const [mismatch, setMismatch] = useState(false);
935
1075
  const submit = (e) => {
936
1076
  e.preventDefault();
937
1077
  if (o.minLength && value.length < o.minLength) {
@@ -943,6 +1083,10 @@ function PromptBody({ ask: a }) {
943
1083
  setError(refused);
944
1084
  return;
945
1085
  }
1086
+ if (o.confirmField && again !== value) {
1087
+ setMismatch(true);
1088
+ return;
1089
+ }
946
1090
  a.settle(value);
947
1091
  done();
948
1092
  };
@@ -958,9 +1102,30 @@ function PromptBody({ ask: a }) {
958
1102
  onChange: (e) => {
959
1103
  setValue(e.target.value);
960
1104
  setError(null);
1105
+ setMismatch(false);
961
1106
  }
962
1107
  }
963
1108
  ) }),
1109
+ o.confirmField ? /* @__PURE__ */ jsx(
1110
+ Field,
1111
+ {
1112
+ label: o.confirmField === true ? "Type it again" : o.confirmField,
1113
+ error: mismatch ? "The two do not match." : null,
1114
+ className: "mt-4",
1115
+ children: /* @__PURE__ */ jsx(
1116
+ Input,
1117
+ {
1118
+ type: o.secret ? "password" : "text",
1119
+ autoComplete: o.secret ? "new-password" : "off",
1120
+ value: again,
1121
+ onChange: (e) => {
1122
+ setAgain(e.target.value);
1123
+ setMismatch(false);
1124
+ }
1125
+ }
1126
+ )
1127
+ }
1128
+ ) : null,
964
1129
  /* @__PURE__ */ jsxs(DialogFooter, { children: [
965
1130
  /* @__PURE__ */ jsx(
966
1131
  Button,
@@ -2001,7 +2166,7 @@ var JS_TAG = /<\/?(?=[A-Za-z])/y;
2001
2166
  var JS_TAG_NAME = /[A-Za-z][\w$.:-]*/y;
2002
2167
  var JS_PUNCT = /=>|\.\.\.|[{}()[\];,.<>=+\-*/%!?:&|^~#]/y;
2003
2168
  var JSX_BEFORE = /* @__PURE__ */ new Set(["(", ",", "=", "?", ":", "{", "[", ";", ">", "&&", "||", "=>", "return"]);
2004
- function scanJs(src, emit2, jsx50) {
2169
+ function scanJs(src, emit2, jsx52) {
2005
2170
  let i = 0;
2006
2171
  let prev = "";
2007
2172
  let tagDepth = 0;
@@ -2027,7 +2192,7 @@ function scanJs(src, emit2, jsx50) {
2027
2192
  sig('"');
2028
2193
  continue;
2029
2194
  }
2030
- if (jsx50 && tagDepth === 0 && (m = at(JS_TAG, src, i)) && (prev === "" || JSX_BEFORE.has(prev))) {
2195
+ if (jsx52 && tagDepth === 0 && (m = at(JS_TAG, src, i)) && (prev === "" || JSX_BEFORE.has(prev))) {
2031
2196
  const name = at(JS_TAG_NAME, src, i + m.length);
2032
2197
  if (name) {
2033
2198
  emit2(m);
@@ -2039,7 +2204,7 @@ function scanJs(src, emit2, jsx50) {
2039
2204
  continue;
2040
2205
  }
2041
2206
  }
2042
- if (jsx50 && tagDepth > 0 && braceInTag === 0) {
2207
+ if (jsx52 && tagDepth > 0 && braceInTag === 0) {
2043
2208
  if (src.startsWith("/>", i) || src[i] === ">") {
2044
2209
  const close = src[i] === ">" ? ">" : "/>";
2045
2210
  emit2(close);
@@ -2059,7 +2224,7 @@ function scanJs(src, emit2, jsx50) {
2059
2224
  continue;
2060
2225
  }
2061
2226
  if (src[i] === "{") braceInTag = 1;
2062
- } else if (jsx50 && tagDepth > 0 && braceInTag > 0) {
2227
+ } else if (jsx52 && tagDepth > 0 && braceInTag > 0) {
2063
2228
  if (src[i] === "{") braceInTag++;
2064
2229
  else if (src[i] === "}") braceInTag--;
2065
2230
  }
@@ -2477,7 +2642,22 @@ function PageHeader({
2477
2642
  ] });
2478
2643
  }
2479
2644
  var InStatGrid = createContext(false);
2480
- function StatCard({ label, value, hint, size, className }) {
2645
+ function Delta({ value, suffix = "", good = "up", label }) {
2646
+ const dir = value > 0 ? "up" : value < 0 ? "down" : "flat";
2647
+ const tone = dir === "flat" ? "text-muted-foreground" : dir === good ? "text-success" : "text-destructive";
2648
+ const sign = value > 0 ? "+" : value < 0 ? "\u2212" : "";
2649
+ return /* @__PURE__ */ jsxs("span", { className: cn("inline-flex items-baseline gap-1 text-[0.8125rem] font-normal tracking-normal oca-tabular", tone), children: [
2650
+ /* @__PURE__ */ jsx("span", { "aria-hidden": true, children: dir === "up" ? "\u2191" : dir === "down" ? "\u2193" : "\xB7" }),
2651
+ sign,
2652
+ Math.abs(value).toLocaleString("en-US", { maximumFractionDigits: 2 }),
2653
+ suffix,
2654
+ label ? /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground", children: [
2655
+ " ",
2656
+ label
2657
+ ] }) : null
2658
+ ] });
2659
+ }
2660
+ function StatCard({ label, value, hint, size, delta, className }) {
2481
2661
  const inGrid = useContext(InStatGrid);
2482
2662
  const density = useDensity();
2483
2663
  const sm = (size ?? (density === "compact" ? "sm" : "md")) === "sm";
@@ -2495,15 +2675,19 @@ function StatCard({ label, value, hint, size, className }) {
2495
2675
  ),
2496
2676
  children: [
2497
2677
  /* @__PURE__ */ jsx("span", { className: cn("leading-snug text-muted-foreground", sm ? "text-[0.8125rem]" : "text-[0.875rem]"), children: label }),
2498
- /* @__PURE__ */ jsx(
2678
+ /* @__PURE__ */ jsxs(
2499
2679
  "span",
2500
2680
  {
2501
2681
  className: cn(
2502
2682
  "break-words oca-tabular leading-tight tracking-[-0.02em]",
2503
2683
  sm ? "text-[1.25rem]" : "text-[1.5rem] md:text-[1.75rem]",
2504
- inGrid && "self-end"
2684
+ inGrid && "self-end",
2685
+ delta && "flex flex-wrap items-baseline gap-x-2"
2505
2686
  ),
2506
- children: value
2687
+ children: [
2688
+ value,
2689
+ delta ? /* @__PURE__ */ jsx(Delta, { ...delta }) : null
2690
+ ]
2507
2691
  }
2508
2692
  ),
2509
2693
  hint ? /* @__PURE__ */ jsx("span", { className: "text-[0.8125rem] leading-snug text-muted-foreground", children: hint }) : inGrid ? /* @__PURE__ */ jsx("span", { "aria-hidden": true }) : null
@@ -2592,6 +2776,13 @@ function StatGrid({ columns, empty, isEmpty, className, children, ...props }) {
2592
2776
  }
2593
2777
  ) });
2594
2778
  }
2779
+ var TONE_TEXT = {
2780
+ good: "text-success",
2781
+ caution: "text-warning",
2782
+ bad: "text-destructive",
2783
+ brand: "text-oca-accent-ink",
2784
+ muted: "text-muted-foreground"
2785
+ };
2595
2786
  function KeyValueList({
2596
2787
  items,
2597
2788
  dense,
@@ -2610,15 +2801,19 @@ function KeyValueList({
2610
2801
  ),
2611
2802
  children: [
2612
2803
  /* @__PURE__ */ jsx("dt", { className: cn("shrink-0 text-muted-foreground", tight ? "text-[0.8125rem] @md:w-36" : "text-[0.875rem] @md:w-48"), children: it.label }),
2613
- /* @__PURE__ */ jsx(
2804
+ /* @__PURE__ */ jsxs(
2614
2805
  "dd",
2615
2806
  {
2616
2807
  className: cn(
2617
2808
  "min-w-0 break-words",
2618
2809
  tight ? "text-[0.875rem]" : "text-[0.9375rem]",
2619
- it.mono && (tight ? "font-mono text-[0.8125rem]" : "font-mono text-[0.875rem]")
2810
+ it.mono && (tight ? "font-mono text-[0.8125rem]" : "font-mono text-[0.875rem]"),
2811
+ it.tone && !it.note && TONE_TEXT[it.tone]
2620
2812
  ),
2621
- children: it.value
2813
+ children: [
2814
+ it.value,
2815
+ it.note ? /* @__PURE__ */ jsx("span", { className: cn("ml-2 font-sans text-[0.8125rem]", TONE_TEXT[it.tone ?? "muted"]), children: it.note }) : null
2816
+ ]
2622
2817
  }
2623
2818
  )
2624
2819
  ]
@@ -3774,6 +3969,310 @@ function ErrorPage({
3774
3969
  art !== null ? /* @__PURE__ */ jsx("div", { "aria-hidden": true, className: "oca-enter hidden justify-center md:col-span-5 md:flex [--enter-delay:120ms]", children: art ?? /* @__PURE__ */ jsx(MarkOutline, { className: "w-full max-w-[20rem] text-oca-hairline-strong" }) }) : null
3775
3970
  ] }) });
3776
3971
  }
3972
+ function onSecond(tick) {
3973
+ const id = setInterval(tick, 1e3);
3974
+ return () => clearInterval(id);
3975
+ }
3976
+ var nowSeconds = () => Math.floor(Date.now() / 1e3);
3977
+ function CountdownRing({
3978
+ period,
3979
+ remaining,
3980
+ warnAt = 5,
3981
+ size = 18,
3982
+ showSeconds = true,
3983
+ className
3984
+ }) {
3985
+ const now = useSyncExternalStore(onSecond, nowSeconds, () => null);
3986
+ const left = remaining ?? (now === null ? null : period - now % period);
3987
+ const share = left === null ? 1 : Math.max(0, Math.min(1, left / period));
3988
+ const warn = left !== null && left <= warnAt;
3989
+ const r = size / 2 - 1.5;
3990
+ const c = 2 * Math.PI * r;
3991
+ return /* @__PURE__ */ jsxs(
3992
+ "span",
3993
+ {
3994
+ role: "timer",
3995
+ "aria-label": left === null ? void 0 : `${left} second${left === 1 ? "" : "s"} left`,
3996
+ className: cn("inline-flex items-center gap-1.5", warn ? "text-destructive" : "text-muted-foreground", className),
3997
+ children: [
3998
+ /* @__PURE__ */ jsxs("svg", { "aria-hidden": true, width: size, height: size, viewBox: `0 0 ${size} ${size}`, className: "-rotate-90", children: [
3999
+ /* @__PURE__ */ jsx("circle", { cx: size / 2, cy: size / 2, r, fill: "none", stroke: "var(--border)", strokeWidth: 2 }),
4000
+ /* @__PURE__ */ jsx(
4001
+ "circle",
4002
+ {
4003
+ cx: size / 2,
4004
+ cy: size / 2,
4005
+ r,
4006
+ fill: "none",
4007
+ stroke: "currentColor",
4008
+ strokeWidth: 2,
4009
+ strokeLinecap: "round",
4010
+ strokeDasharray: c,
4011
+ strokeDashoffset: c * (1 - share),
4012
+ className: cn(left !== null && left < period && "transition-[stroke-dashoffset] duration-1000 ease-linear motion-reduce:transition-none")
4013
+ }
4014
+ )
4015
+ ] }),
4016
+ showSeconds && left !== null ? /* @__PURE__ */ jsxs("span", { className: "text-[0.8125rem] oca-tabular", children: [
4017
+ left,
4018
+ "s"
4019
+ ] }) : null
4020
+ ]
4021
+ }
4022
+ );
4023
+ }
4024
+ function PlanCard({
4025
+ name,
4026
+ subtitle,
4027
+ price,
4028
+ period,
4029
+ footnote,
4030
+ features = [],
4031
+ action,
4032
+ badge,
4033
+ badgeTone = "neutral",
4034
+ highlight: highlight2 = false,
4035
+ className
4036
+ }) {
4037
+ return /* @__PURE__ */ jsxs(
4038
+ "section",
4039
+ {
4040
+ className: cn(
4041
+ "flex h-full flex-col gap-5 rounded-[1.25rem] border bg-card p-6",
4042
+ highlight2 ? "border-foreground shadow-sm ring-1 ring-foreground" : "border-border",
4043
+ className
4044
+ ),
4045
+ children: [
4046
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
4047
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-3", children: [
4048
+ /* @__PURE__ */ jsx("h3", { className: "text-[1.0625rem] font-medium leading-snug", children: name }),
4049
+ badge ? /* @__PURE__ */ jsx(Badge, { tone: badgeTone, children: badge }) : null
4050
+ ] }),
4051
+ subtitle ? /* @__PURE__ */ jsx("p", { className: "text-[0.875rem] leading-snug text-muted-foreground", children: subtitle }) : null
4052
+ ] }),
4053
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
4054
+ /* @__PURE__ */ jsxs("p", { className: "flex flex-wrap items-baseline gap-x-1.5", children: [
4055
+ /* @__PURE__ */ jsx("span", { className: "oca-display-3 oca-tabular", children: price }),
4056
+ period ? /* @__PURE__ */ jsx("span", { className: "text-[0.9375rem] text-muted-foreground", children: period }) : null
4057
+ ] }),
4058
+ footnote ? /* @__PURE__ */ jsx("p", { className: "text-[0.8125rem] text-muted-foreground", children: footnote }) : null
4059
+ ] }),
4060
+ features.length > 0 ? /* @__PURE__ */ jsx("ul", { className: "flex flex-col gap-2.5 text-[0.9375rem]", children: features.map((f, i) => /* @__PURE__ */ jsxs("li", { className: "flex items-start gap-2.5", children: [
4061
+ /* @__PURE__ */ jsx(Check, { "aria-hidden": true, className: "mt-1 size-4 shrink-0 text-muted-foreground" }),
4062
+ /* @__PURE__ */ jsx("span", { className: "min-w-0", children: f })
4063
+ ] }, i)) }) : null,
4064
+ action ? /* @__PURE__ */ jsx("div", { className: "mt-auto flex flex-col pt-1 [&>*]:w-full", children: action }) : null
4065
+ ]
4066
+ }
4067
+ );
4068
+ }
4069
+ function LockedPreview({
4070
+ title,
4071
+ description,
4072
+ action,
4073
+ children,
4074
+ className
4075
+ }) {
4076
+ return /* @__PURE__ */ jsxs("div", { className: cn("relative", className), children: [
4077
+ children ? /* @__PURE__ */ jsx(
4078
+ "div",
4079
+ {
4080
+ inert: true,
4081
+ "aria-hidden": true,
4082
+ "data-oca-locked": "",
4083
+ className: "pointer-events-none max-h-[28rem] select-none overflow-hidden [mask-image:linear-gradient(to_bottom,#000_25%,transparent_85%)]",
4084
+ children
4085
+ }
4086
+ ) : null,
4087
+ /* @__PURE__ */ jsxs("div", { className: cn("relative mx-auto flex max-w-md flex-col items-center gap-4 rounded-[1.25rem] border border-border bg-card px-6 py-7 text-center shadow-sm", children && "-mt-40"), children: [
4088
+ /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "flex size-10 items-center justify-center rounded-full bg-muted text-foreground", children: /* @__PURE__ */ jsx(Lock, { className: "size-[1.125rem]" }) }),
4089
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
4090
+ /* @__PURE__ */ jsx("p", { className: "text-[1.0625rem] font-medium leading-snug", children: title }),
4091
+ description ? /* @__PURE__ */ jsx("p", { className: "text-[0.9375rem] leading-snug text-muted-foreground", children: description }) : null
4092
+ ] }),
4093
+ /* @__PURE__ */ jsx("div", { className: "flex flex-wrap justify-center gap-2", children: action })
4094
+ ] })
4095
+ ] });
4096
+ }
4097
+ function chartColor(series) {
4098
+ if (typeof series === "string") return `var(--oca-chart-${series})`;
4099
+ const n = series >= 1 && series <= 4 && Number.isInteger(series) ? series : (series % 4 + 4) % 4 + 1;
4100
+ return `var(--oca-chart-${n})`;
4101
+ }
4102
+ function ChartFrame({
4103
+ legend,
4104
+ caption,
4105
+ children,
4106
+ className
4107
+ }) {
4108
+ return /* @__PURE__ */ jsxs("figure", { className: cn("oca-chart flex min-w-0 flex-col gap-3", className), children: [
4109
+ legend && legend.length > 0 ? /* @__PURE__ */ jsx("ul", { className: "oca-chart-legend", "aria-label": "Legend", children: legend.map((l, i) => {
4110
+ const c = typeof l.color === "number" || ["neutral", "up", "down"].includes(String(l.color)) ? chartColor(l.color) : String(l.color);
4111
+ return /* @__PURE__ */ jsxs("li", { children: [
4112
+ /* @__PURE__ */ jsx("span", { "aria-hidden": true, "data-swatch": l.dashed ? "dashed" : "", style: { "--swatch": c } }),
4113
+ l.label
4114
+ ] }, i);
4115
+ }) }) : null,
4116
+ /* @__PURE__ */ jsx("div", { className: "relative min-w-0", children }),
4117
+ caption ? /* @__PURE__ */ jsx("figcaption", { className: "text-[0.8125rem] leading-snug text-muted-foreground", children: caption }) : null
4118
+ ] });
4119
+ }
4120
+ function Sparkline({
4121
+ values,
4122
+ label,
4123
+ tone = "ink",
4124
+ area = false,
4125
+ width = 96,
4126
+ height = 24,
4127
+ className
4128
+ }) {
4129
+ const gradient = useId().replace(/[^a-zA-Z0-9]/g, "");
4130
+ const pts = values.filter((v) => Number.isFinite(v));
4131
+ const lo = Math.min(...pts);
4132
+ const hi = Math.max(...pts);
4133
+ const span = hi - lo || 1;
4134
+ const pad3 = 1.5;
4135
+ const x = (i) => pts.length < 2 ? width / 2 : i / (pts.length - 1) * width;
4136
+ const y = (v) => pad3 + (1 - (v - lo) / span) * (height - pad3 * 2);
4137
+ const line = pts.map((v, i) => `${i === 0 ? "M" : "L"}${x(i).toFixed(2)},${y(v).toFixed(2)}`).join(" ");
4138
+ const color = tone === "ink" ? "var(--foreground)" : tone === "muted" ? "var(--muted-foreground)" : tone === "trend" ? chartColor(pts.length > 1 && pts[pts.length - 1] < pts[0] ? "down" : "up") : chartColor(tone);
4139
+ return /* @__PURE__ */ jsx(
4140
+ "svg",
4141
+ {
4142
+ role: "img",
4143
+ "aria-label": label,
4144
+ viewBox: `0 0 ${width} ${height}`,
4145
+ preserveAspectRatio: "none",
4146
+ width,
4147
+ height,
4148
+ className: cn("block overflow-visible", className),
4149
+ style: { color },
4150
+ children: pts.length > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
4151
+ area ? /* @__PURE__ */ jsxs(Fragment, { children: [
4152
+ /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsxs("linearGradient", { id: gradient, x1: "0", y1: "0", x2: "0", y2: "1", children: [
4153
+ /* @__PURE__ */ jsx("stop", { offset: "0", stopColor: "currentColor", stopOpacity: 0.22 }),
4154
+ /* @__PURE__ */ jsx("stop", { offset: "1", stopColor: "currentColor", stopOpacity: 0 })
4155
+ ] }) }),
4156
+ /* @__PURE__ */ jsx("path", { d: `${line} L${x(pts.length - 1).toFixed(2)},${height} L${x(0).toFixed(2)},${height} Z`, fill: `url(#${gradient})` })
4157
+ ] }) : null,
4158
+ /* @__PURE__ */ jsx("path", { d: line, fill: "none", stroke: "currentColor", strokeWidth: 1.5, strokeLinejoin: "round", strokeLinecap: "round", vectorEffect: "non-scaling-stroke" })
4159
+ ] }) : null
4160
+ }
4161
+ );
4162
+ }
4163
+ function SourceNote({ source, href, detail, updated, variant = "popover", className }) {
4164
+ const name = href ? /* @__PURE__ */ jsxs("a", { href, className: "text-foreground underline decoration-foreground/35 underline-offset-4 hover:decoration-foreground", rel: "noreferrer", target: "_blank", children: [
4165
+ source,
4166
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: " (opens in a new tab)" })
4167
+ ] }) : /* @__PURE__ */ jsx("span", { className: "text-foreground", children: source });
4168
+ if (variant === "line") {
4169
+ return /* @__PURE__ */ jsxs("p", { className: cn("text-[0.75rem] leading-snug text-muted-foreground", className), children: [
4170
+ "Source: ",
4171
+ name,
4172
+ updated ? /* @__PURE__ */ jsxs(Fragment, { children: [
4173
+ " \xB7 ",
4174
+ updated
4175
+ ] }) : null
4176
+ ] });
4177
+ }
4178
+ return /* @__PURE__ */ jsxs(Popover, { children: [
4179
+ /* @__PURE__ */ jsxs(
4180
+ PopoverTrigger,
4181
+ {
4182
+ className: cn(
4183
+ "inline-flex h-7 items-center gap-1 rounded-full px-2 text-[0.75rem] text-muted-foreground transition-colors hover:bg-accent hover:text-foreground",
4184
+ className
4185
+ ),
4186
+ children: [
4187
+ /* @__PURE__ */ jsx(Info, { "aria-hidden": true, className: "size-3.5" }),
4188
+ "Source"
4189
+ ]
4190
+ }
4191
+ ),
4192
+ /* @__PURE__ */ jsxs(PopoverContent, { align: "start", className: "flex w-[min(calc(100vw-2rem),20rem)] flex-col gap-2 p-4 text-[0.875rem]", children: [
4193
+ /* @__PURE__ */ jsx("p", { className: "text-[0.75rem] text-muted-foreground", children: "Where this number comes from" }),
4194
+ /* @__PURE__ */ jsx("p", { className: "font-medium", children: name }),
4195
+ detail ? /* @__PURE__ */ jsx("div", { className: "text-[0.8125rem] leading-snug text-muted-foreground [&_code]:font-mono", children: detail }) : null,
4196
+ updated ? /* @__PURE__ */ jsx("p", { className: "text-[0.8125rem] text-muted-foreground", children: updated }) : null
4197
+ ] })
4198
+ ] });
4199
+ }
4200
+ function Panel({
4201
+ title,
4202
+ description,
4203
+ actions,
4204
+ source,
4205
+ expandable = false,
4206
+ children,
4207
+ className
4208
+ }) {
4209
+ const [open, setOpen] = useState(false);
4210
+ const body = (expanded) => typeof children === "function" ? children(expanded) : children;
4211
+ const head = (expanded) => /* @__PURE__ */ jsxs("header", { className: "flex flex-wrap items-start justify-between gap-x-4 gap-y-2", children: [
4212
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col gap-1", children: [
4213
+ expanded ? /* @__PURE__ */ jsx(DialogTitle, { className: "text-[1.0625rem] font-medium leading-snug", children: title }) : /* @__PURE__ */ jsx("h3", { className: "text-[1rem] font-medium leading-snug", children: title }),
4214
+ description ? expanded ? /* @__PURE__ */ jsx(DialogDescription, { className: "text-[0.875rem] leading-snug text-muted-foreground", children: description }) : /* @__PURE__ */ jsx("p", { className: "text-[0.875rem] leading-snug text-muted-foreground", children: description }) : null
4215
+ ] }),
4216
+ /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center gap-1", children: [
4217
+ actions,
4218
+ expandable && !expanded ? /* @__PURE__ */ jsx(
4219
+ "button",
4220
+ {
4221
+ type: "button",
4222
+ onClick: () => setOpen(true),
4223
+ "aria-label": "Open full screen",
4224
+ className: "inline-flex size-8 items-center justify-center rounded-full text-muted-foreground transition-colors hover:bg-accent hover:text-foreground",
4225
+ children: /* @__PURE__ */ jsx(Maximize2, { "aria-hidden": true, className: "size-4" })
4226
+ }
4227
+ ) : null
4228
+ ] })
4229
+ ] });
4230
+ return /* @__PURE__ */ jsxs("section", { className: cn("flex min-w-0 flex-col gap-4 rounded-[1.25rem] border border-border bg-card p-5 md:p-6", className), children: [
4231
+ head(false),
4232
+ /* @__PURE__ */ jsx("div", { className: "min-w-0", children: body(false) }),
4233
+ source ? /* @__PURE__ */ jsx("div", { className: "-mb-1 border-t border-border pt-3", children: source }) : null,
4234
+ expandable ? /* @__PURE__ */ jsx(Dialog, { open, onOpenChange: setOpen, children: /* @__PURE__ */ jsxs(
4235
+ DialogContent,
4236
+ {
4237
+ ...description ? {} : { "aria-describedby": void 0 },
4238
+ className: "flex h-[min(92dvh,56rem)] w-[min(96vw,80rem)] max-w-none flex-col gap-4 overflow-y-auto",
4239
+ children: [
4240
+ head(true),
4241
+ /* @__PURE__ */ jsx("div", { className: "min-h-0 min-w-0 flex-1", children: open ? body(true) : null }),
4242
+ source ? /* @__PURE__ */ jsx("div", { className: "border-t border-border pt-3", children: source }) : null
4243
+ ]
4244
+ }
4245
+ ) }) : null
4246
+ ] });
4247
+ }
4248
+ function HudCard({
4249
+ eyebrow,
4250
+ live = false,
4251
+ title,
4252
+ children,
4253
+ footer,
4254
+ className
4255
+ }) {
4256
+ return /* @__PURE__ */ jsxs(
4257
+ "div",
4258
+ {
4259
+ "data-oca-hud": "",
4260
+ className: cn(
4261
+ "flex w-60 max-w-[calc(100vw-2rem)] flex-col gap-2 rounded-xl border border-border bg-background/85 p-3 text-[0.8125rem] shadow-sm backdrop-blur-md",
4262
+ className
4263
+ ),
4264
+ children: [
4265
+ eyebrow ? /* @__PURE__ */ jsxs("p", { className: "flex items-center gap-1.5 text-[0.75rem] text-muted-foreground", children: [
4266
+ live ? /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "size-1.5 rounded-full bg-oca-orange-deep motion-safe:animate-pulse" }) : null,
4267
+ eyebrow
4268
+ ] }) : null,
4269
+ title ? /* @__PURE__ */ jsx("p", { className: "text-[1.125rem] font-medium leading-tight oca-tabular", children: title }) : null,
4270
+ children,
4271
+ footer ? /* @__PURE__ */ jsx("div", { className: "border-t border-border pt-2", children: footer }) : null
4272
+ ]
4273
+ }
4274
+ );
4275
+ }
3777
4276
  function SectionHeading({
3778
4277
  eyebrow,
3779
4278
  title,
@@ -4931,6 +5430,7 @@ function SearchDialog({
4931
5430
  idle,
4932
5431
  defaultQuery = "",
4933
5432
  debounceMs = 120,
5433
+ browse = false,
4934
5434
  className
4935
5435
  }) {
4936
5436
  const [own, setOwn] = useState(false);
@@ -4967,7 +5467,7 @@ function SearchDialog({
4967
5467
  }, [hotkey]);
4968
5468
  useEffect(() => {
4969
5469
  const q = query.trim();
4970
- if (!q) {
5470
+ if (!q && !(browse && open)) {
4971
5471
  setGroups([]);
4972
5472
  setState("idle");
4973
5473
  return;
@@ -4989,14 +5489,15 @@ function SearchDialog({
4989
5489
  clearTimeout(t);
4990
5490
  ctl.abort();
4991
5491
  };
4992
- }, [query, debounceMs]);
5492
+ }, [query, debounceMs, browse, open]);
4993
5493
  useEffect(() => {
4994
5494
  listRef.current?.querySelector('[aria-selected="true"]')?.scrollIntoView({ block: "nearest" });
4995
5495
  }, [active]);
4996
5496
  const choose = (r) => {
4997
5497
  setOpen(false);
4998
- if (onSelect) onSelect(r);
4999
- else window.location.assign(r.href);
5498
+ if (r.run) r.run();
5499
+ else if (onSelect) onSelect(r);
5500
+ else if (r.href) window.location.assign(r.href);
5000
5501
  };
5001
5502
  const optionId = (i) => `${listId}-o${i}`;
5002
5503
  const showList = state === "done" && flat.length > 0;
@@ -5067,25 +5568,28 @@ function SearchDialog({
5067
5568
  index++;
5068
5569
  const i = index;
5069
5570
  const on = i === active;
5571
+ const Option = r.href ? "a" : "div";
5070
5572
  return /* @__PURE__ */ jsxs(
5071
- "a",
5573
+ Option,
5072
5574
  {
5073
5575
  id: optionId(i),
5074
- href: r.href,
5576
+ ...r.href ? { href: r.href } : {},
5075
5577
  role: "option",
5076
5578
  "aria-selected": on,
5077
5579
  tabIndex: -1,
5078
5580
  onMouseMove: () => setActive(i),
5079
5581
  onClick: (e) => {
5080
- if (e.metaKey || e.ctrlKey || e.shiftKey) return;
5582
+ if (r.href && (e.metaKey || e.ctrlKey || e.shiftKey)) return;
5081
5583
  e.preventDefault();
5082
5584
  choose(r);
5083
5585
  },
5084
5586
  className: cn(
5085
5587
  "flex items-start gap-3 rounded-xl px-3 py-2.5 transition-colors",
5086
- on ? "bg-accent" : "hover:bg-accent"
5588
+ on ? "bg-accent" : "hover:bg-accent",
5589
+ !r.href && "cursor-pointer"
5087
5590
  ),
5088
5591
  children: [
5592
+ r.icon ? /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "mt-0.5 flex size-5 shrink-0 items-center justify-center text-muted-foreground [&_svg]:size-[1.0625rem]", children: r.icon }) : null,
5089
5593
  /* @__PURE__ */ jsxs("span", { className: "flex min-w-0 flex-1 flex-col gap-0.5", children: [
5090
5594
  /* @__PURE__ */ jsx("span", { className: "truncate text-[0.9375rem] font-medium text-foreground", children: r.title }),
5091
5595
  r.section ? /* @__PURE__ */ jsx("span", { className: "truncate text-[0.8125rem] text-muted-foreground", children: r.section }) : null,
@@ -5097,6 +5601,7 @@ function SearchDialog({
5097
5601
  }
5098
5602
  ) : r.excerpt ? /* @__PURE__ */ jsx("span", { className: "line-clamp-2 text-[0.875rem] leading-snug text-muted-foreground", children: r.excerpt }) : null
5099
5603
  ] }),
5604
+ r.meta ? /* @__PURE__ */ jsx("span", { className: "mt-0.5 shrink-0 text-[0.8125rem] text-muted-foreground", children: r.meta }) : null,
5100
5605
  /* @__PURE__ */ jsx(CornerDownLeft, { "aria-hidden": true, className: cn("mt-1 size-4 shrink-0 text-muted-foreground", !on && "invisible") })
5101
5606
  ]
5102
5607
  },
@@ -5105,11 +5610,11 @@ function SearchDialog({
5105
5610
  })
5106
5611
  ] }, gi)) }),
5107
5612
  state === "idle" ? /* @__PURE__ */ jsx("div", { className: "px-3 py-6 text-[0.9375rem] text-muted-foreground", children: idle ?? "Type a word: a protocol, a function, an error." }) : null,
5108
- state === "done" && flat.length === 0 ? /* @__PURE__ */ jsxs("p", { role: "status", className: "px-3 py-6 text-[0.9375rem] text-muted-foreground", children: [
5613
+ state === "done" && flat.length === 0 ? /* @__PURE__ */ jsx("p", { role: "status", className: "px-3 py-6 text-[0.9375rem] text-muted-foreground", children: query.trim() ? /* @__PURE__ */ jsxs(Fragment, { children: [
5109
5614
  "No results for \u201C",
5110
5615
  query.trim(),
5111
5616
  "\u201D."
5112
- ] }) : null,
5617
+ ] }) : "Nothing here yet." }) : null,
5113
5618
  state === "error" ? /* @__PURE__ */ jsx("p", { role: "status", className: "px-3 py-6 text-[0.9375rem] text-muted-foreground", children: "Search is not available right now. Try again in a moment." }) : null
5114
5619
  ] }),
5115
5620
  /* @__PURE__ */ jsxs("div", { "aria-hidden": true, className: "hidden shrink-0 items-center gap-4 border-t border-border px-5 py-2.5 text-[0.75rem] text-muted-foreground sm:flex", children: [
@@ -5134,6 +5639,13 @@ function SearchDialog({
5134
5639
  ] }) })
5135
5640
  ] });
5136
5641
  }
5642
+ function CommandDialog({
5643
+ label = "Commands",
5644
+ placeholder = "Search, or run a command",
5645
+ ...props
5646
+ }) {
5647
+ return /* @__PURE__ */ jsx(SearchDialog, { ...props, label, placeholder, button: false, browse: true });
5648
+ }
5137
5649
  function pretty(content) {
5138
5650
  try {
5139
5651
  return JSON.stringify(JSON.parse(content), null, 2);
@@ -5562,6 +6074,13 @@ function BlockCountdown({
5562
6074
  ] }) : null
5563
6075
  ] });
5564
6076
  }
6077
+ var METER_FILL = {
6078
+ ink: "bg-foreground",
6079
+ brand: "bg-oca-orange-deep",
6080
+ good: "bg-success",
6081
+ caution: "bg-warning",
6082
+ bad: "bg-destructive"
6083
+ };
5565
6084
  function Meter({
5566
6085
  value,
5567
6086
  max,
@@ -5596,7 +6115,7 @@ function Meter({
5596
6115
  /* @__PURE__ */ jsx(
5597
6116
  "div",
5598
6117
  {
5599
- className: cn("h-full shrink-0 rounded-full", tone === "brand" ? "bg-oca-orange-deep" : "bg-foreground"),
6118
+ className: cn("h-full shrink-0 rounded-full", METER_FILL[tone]),
5600
6119
  style: { width: `${v * 100}%` }
5601
6120
  }
5602
6121
  ),
@@ -5843,48 +6362,106 @@ function SectionSwitch({
5843
6362
  }
5844
6363
  );
5845
6364
  }
6365
+ function NavBadge({ badge, className }) {
6366
+ if (typeof badge === "number") {
6367
+ return /* @__PURE__ */ jsx(
6368
+ "span",
6369
+ {
6370
+ "aria-hidden": true,
6371
+ className: cn(
6372
+ "absolute flex h-4 min-w-4 items-center justify-center rounded-full bg-primary px-1 text-[0.625rem] font-medium leading-none text-primary-foreground ring-2 ring-background oca-tabular",
6373
+ className
6374
+ ),
6375
+ children: badge > 99 ? "99+" : badge
6376
+ }
6377
+ );
6378
+ }
6379
+ return /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: cn("absolute size-2 rounded-full bg-oca-orange-deep ring-2 ring-background", className) });
6380
+ }
6381
+ var TAB = "flex min-w-0 flex-col items-center justify-center gap-1 rounded-2xl text-[0.6875rem] leading-none outline-none transition-colors [-webkit-tap-highlight-color:transparent] focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring";
6382
+ function TabFace({ icon, label, badge, active }) {
6383
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
6384
+ /* @__PURE__ */ jsxs(
6385
+ "span",
6386
+ {
6387
+ className: cn(
6388
+ "relative flex h-7 w-12 items-center justify-center rounded-full transition-[background-color,box-shadow] duration-200",
6389
+ "[&_svg]:size-[1.125rem] [&_svg]:shrink-0",
6390
+ active ? "bg-card shadow-sm ring-1 ring-border [&_svg]:stroke-2" : "[&_svg]:stroke-[1.75]"
6391
+ ),
6392
+ children: [
6393
+ icon,
6394
+ badge ? /* @__PURE__ */ jsx(NavBadge, { badge, className: typeof badge === "number" ? "-top-1 right-0.5" : "right-2.5 top-0.5" }) : null
6395
+ ]
6396
+ }
6397
+ ),
6398
+ /* @__PURE__ */ jsx("span", { className: "max-w-full truncate px-0.5", children: label }),
6399
+ badge ? /* @__PURE__ */ jsx("span", { className: "sr-only", children: badge }) : null
6400
+ ] });
6401
+ }
5846
6402
  function TabBar({ items }) {
6403
+ const [more, setMore] = useState(false);
6404
+ const overflow = items.length > 5;
6405
+ const shown = overflow ? items.slice(0, 4) : items;
6406
+ const rest = overflow ? items.slice(4) : [];
6407
+ const restBadge = rest.find((it) => it.badge)?.badge;
5847
6408
  return /* @__PURE__ */ jsx(
5848
6409
  "nav",
5849
6410
  {
5850
6411
  "aria-label": "Pages",
5851
6412
  "data-oca-tabbar": "",
5852
6413
  className: "fixed inset-x-0 bottom-0 z-40 border-t border-border bg-background/90 pb-[env(safe-area-inset-bottom)] backdrop-blur-md md:hidden",
5853
- children: /* @__PURE__ */ jsx(
6414
+ children: /* @__PURE__ */ jsxs(
5854
6415
  "div",
5855
6416
  {
5856
6417
  className: "mx-auto grid h-14 max-w-[32rem] px-1.5",
5857
- style: { gridTemplateColumns: `repeat(${items.length}, minmax(0, 1fr))` },
5858
- children: items.map((it) => /* @__PURE__ */ jsxs(
5859
- Link6,
5860
- {
5861
- href: it.href,
5862
- "aria-current": it.active ? "page" : void 0,
5863
- className: cn(
5864
- "flex min-w-0 flex-col items-center justify-center gap-1 rounded-2xl text-[0.6875rem] leading-none outline-none transition-colors [-webkit-tap-highlight-color:transparent] focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring",
5865
- it.active ? "text-foreground" : "text-muted-foreground hover:text-foreground"
6418
+ style: { gridTemplateColumns: `repeat(${shown.length + (overflow ? 1 : 0)}, minmax(0, 1fr))` },
6419
+ children: [
6420
+ shown.map((it) => /* @__PURE__ */ jsx(
6421
+ Link6,
6422
+ {
6423
+ href: it.href,
6424
+ "aria-current": it.active ? "page" : void 0,
6425
+ className: cn(TAB, it.active ? "text-foreground" : "text-muted-foreground hover:text-foreground"),
6426
+ children: /* @__PURE__ */ jsx(TabFace, { icon: it.icon, label: it.label, badge: it.badge, active: it.active })
6427
+ },
6428
+ it.href
6429
+ )),
6430
+ overflow ? /* @__PURE__ */ jsxs(Sheet, { open: more, onOpenChange: setMore, children: [
6431
+ /* @__PURE__ */ jsx(
6432
+ SheetTrigger,
6433
+ {
6434
+ className: cn(TAB, rest.some((it) => it.active) ? "text-foreground" : "text-muted-foreground hover:text-foreground"),
6435
+ children: /* @__PURE__ */ jsx(TabFace, { icon: /* @__PURE__ */ jsx(Ellipsis, {}), label: "More", badge: restBadge ? true : void 0, active: rest.some((it) => it.active) })
6436
+ }
5866
6437
  ),
5867
- children: [
5868
- /* @__PURE__ */ jsxs(
5869
- "span",
6438
+ /* @__PURE__ */ jsxs(SheetContent, { side: "bottom", className: "pb-[calc(1.5rem+env(safe-area-inset-bottom))]", children: [
6439
+ /* @__PURE__ */ jsx(SheetTitle, { className: "px-1 text-[1.0625rem] font-medium", children: "More" }),
6440
+ /* @__PURE__ */ jsx("div", { className: "mt-4 grid grid-cols-3 gap-2", children: rest.map((it) => /* @__PURE__ */ jsxs(
6441
+ Link6,
5870
6442
  {
6443
+ href: it.href,
6444
+ onClick: () => setMore(false),
6445
+ "aria-current": it.active ? "page" : void 0,
5871
6446
  className: cn(
5872
- "relative flex h-7 w-12 items-center justify-center rounded-full transition-[background-color,box-shadow] duration-200",
5873
- "[&_svg]:size-[1.125rem] [&_svg]:shrink-0",
5874
- it.active ? "bg-card shadow-sm ring-1 ring-border [&_svg]:stroke-2" : "[&_svg]:stroke-[1.75]"
6447
+ "flex min-h-20 flex-col items-center justify-center gap-2 rounded-2xl border px-2 text-center text-[0.8125rem] transition-colors",
6448
+ "[&_svg]:size-5",
6449
+ it.active ? "border-foreground bg-card text-foreground" : "border-border text-muted-foreground hover:text-foreground"
5875
6450
  ),
5876
6451
  children: [
5877
- it.icon,
5878
- it.badge ? /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "absolute right-2.5 top-0.5 size-2 rounded-full bg-oca-orange ring-2 ring-background" }) : null
6452
+ /* @__PURE__ */ jsxs("span", { className: "relative", children: [
6453
+ it.icon,
6454
+ it.badge ? /* @__PURE__ */ jsx(NavBadge, { badge: it.badge, className: typeof it.badge === "number" ? "-right-3 -top-2" : "-right-1 -top-0.5" }) : null
6455
+ ] }),
6456
+ /* @__PURE__ */ jsx("span", { className: "max-w-full truncate", children: it.label }),
6457
+ it.badge ? /* @__PURE__ */ jsx("span", { className: "sr-only", children: it.badge }) : null
5879
6458
  ]
5880
- }
5881
- ),
5882
- /* @__PURE__ */ jsx("span", { className: "max-w-full truncate px-0.5", children: it.label }),
5883
- it.badge ? /* @__PURE__ */ jsx("span", { className: "sr-only", children: it.badge }) : null
5884
- ]
5885
- },
5886
- it.href
5887
- ))
6459
+ },
6460
+ it.href
6461
+ )) })
6462
+ ] })
6463
+ ] }) : null
6464
+ ]
5888
6465
  }
5889
6466
  )
5890
6467
  }
@@ -5892,7 +6469,11 @@ function TabBar({ items }) {
5892
6469
  }
5893
6470
  function tabsFor(groups) {
5894
6471
  const items = groups.flatMap((g) => g.items);
5895
- return items.length >= 2 && items.length <= 5 && items.every((it) => it.icon) ? items : null;
6472
+ return items.length >= 2 && items.every((it) => it.icon) ? items : null;
6473
+ }
6474
+ function sectionTabs(sections, current2) {
6475
+ if (!sections || !current2 || sections.length < 2 || !sections.every((sec) => sec.icon)) return null;
6476
+ return sections.map((sec) => ({ href: sec.href, label: sec.label, icon: sec.icon, active: sec.id === current2.id }));
5896
6477
  }
5897
6478
  var activeItem = (groups) => groups.flatMap((g) => g.items).find((it) => it.active);
5898
6479
  var warned = /* @__PURE__ */ new Set();
@@ -5907,7 +6488,10 @@ function warnDuplicateLabels(groups) {
5907
6488
  seen.add(it.label);
5908
6489
  }
5909
6490
  }
5910
- function AppShell({
6491
+ function AppShell(props) {
6492
+ return props.variant === "rail" ? /* @__PURE__ */ jsx(RailShell, { ...props }) : /* @__PURE__ */ jsx(SidebarShell, { ...props });
6493
+ }
6494
+ function SidebarShell({
5911
6495
  nav,
5912
6496
  sections,
5913
6497
  activeSection,
@@ -5925,7 +6509,8 @@ function AppShell({
5925
6509
  const current2 = sections && sections.length > 0 ? sections.find((sec) => sec.id === activeSection) ?? sections.find((sec) => activeItem(sec.groups)) ?? sections[0] : void 0;
5926
6510
  const groups = current2 ? [...current2.groups, ...persistent] : [...nav ?? [], ...persistent];
5927
6511
  warnDuplicateLabels(groups);
5928
- const tabs = current2 ? null : tabsFor(groups);
6512
+ const sectionTabsFor = sectionTabs(sections, current2);
6513
+ const tabs = current2 ? sectionTabsFor : tabsFor(groups);
5929
6514
  const page = activeItem(groups);
5930
6515
  const place = useMemo(
5931
6516
  () => ({
@@ -5953,8 +6538,8 @@ function AppShell({
5953
6538
  {
5954
6539
  className: cn(
5955
6540
  "inline-flex size-10 items-center justify-center rounded-full hover:bg-accent",
5956
- // The tab bar holds every page; the sheet is left for a footer.
5957
- tabs && !footer && "max-md:hidden"
6541
+ // The tab bar holds every page; the sheet is left for a footer. Section tabs leave the pages here.
6542
+ tabs && !sectionTabsFor && !footer && "max-md:hidden"
5958
6543
  ),
5959
6544
  "aria-label": "Open navigation",
5960
6545
  children: /* @__PURE__ */ jsx(Menu, { className: "size-5" })
@@ -5962,8 +6547,8 @@ function AppShell({
5962
6547
  ),
5963
6548
  /* @__PURE__ */ jsxs(SheetContent, { side: "left", className: "flex flex-col gap-6 overflow-y-auto p-4 pt-16", children: [
5964
6549
  /* @__PURE__ */ jsx(SheetTitle, { className: "sr-only", children: "Navigation" }),
5965
- switcher,
5966
- /* @__PURE__ */ jsx("div", { className: tabs ? "max-md:hidden" : void 0, children: /* @__PURE__ */ jsx(SideNav, { groups, onNavigate: () => setOpen(false) }) }),
6550
+ switcher ? /* @__PURE__ */ jsx("div", { className: sectionTabsFor ? "max-md:hidden" : void 0, children: switcher }) : null,
6551
+ /* @__PURE__ */ jsx("div", { className: tabs && !sectionTabsFor ? "max-md:hidden" : void 0, children: /* @__PURE__ */ jsx(SideNav, { groups, onNavigate: () => setOpen(false) }) }),
5967
6552
  footer ? /* @__PURE__ */ jsx("div", { className: "mt-auto flex flex-col gap-3", children: footer }) : null
5968
6553
  ] })
5969
6554
  ] }),
@@ -5977,7 +6562,7 @@ function AppShell({
5977
6562
  className: cn(
5978
6563
  "flex h-9 items-center gap-1.5 border-t border-border px-4 text-[0.875rem]",
5979
6564
  // The active tab already names the page.
5980
- tabs && !pageOverride && "max-md:hidden"
6565
+ tabs && !sectionTabsFor && !pageOverride && "max-md:hidden"
5981
6566
  ),
5982
6567
  children: [
5983
6568
  place.section ? /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -6010,6 +6595,64 @@ function AppShell({
6010
6595
  }
6011
6596
  ) });
6012
6597
  }
6598
+ function RailItem({ item }) {
6599
+ return /* @__PURE__ */ jsxs(Tooltip, { children: [
6600
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
6601
+ Link6,
6602
+ {
6603
+ href: item.href,
6604
+ "aria-current": item.active ? "page" : void 0,
6605
+ className: cn(
6606
+ "relative flex size-10 items-center justify-center rounded-xl outline-none transition-colors focus-visible:ring-2 focus-visible:ring-ring",
6607
+ "[&_svg]:size-5 [&_svg]:shrink-0",
6608
+ item.active ? "bg-card text-foreground shadow-sm ring-1 ring-border" : "text-muted-foreground hover:bg-accent hover:text-foreground"
6609
+ ),
6610
+ children: [
6611
+ item.icon,
6612
+ /* @__PURE__ */ jsxs("span", { className: "sr-only", children: [
6613
+ item.label,
6614
+ item.badge ? /* @__PURE__ */ jsxs(Fragment, { children: [
6615
+ ", ",
6616
+ item.badge
6617
+ ] }) : null
6618
+ ] }),
6619
+ item.badge ? /* @__PURE__ */ jsx(NavBadge, { badge: item.badge, className: typeof item.badge === "number" ? "-right-1 -top-1" : "right-1 top-1" }) : null
6620
+ ]
6621
+ }
6622
+ ) }),
6623
+ /* @__PURE__ */ jsx(TooltipContent, { side: "right", children: item.label })
6624
+ ] });
6625
+ }
6626
+ function RailShell({ nav = [], persistent = [], page: pageOverride, header, account, banner, children, className }) {
6627
+ const main = nav.flatMap((g) => g.items);
6628
+ const foot = persistent.flatMap((g) => g.items);
6629
+ warnDuplicateLabels([...nav, ...persistent]);
6630
+ const tabs = tabsFor([{ items: [...main, ...foot] }]);
6631
+ const active = activeItem([...nav, ...persistent]);
6632
+ const place = useMemo(() => ({ page: pageOverride ?? active?.label }), [pageOverride, active?.label]);
6633
+ return /* @__PURE__ */ jsx(ShellContext.Provider, { value: place, children: /* @__PURE__ */ jsx(TooltipProvider, { delayDuration: 300, children: /* @__PURE__ */ jsxs("div", { className: cn("flex h-dvh flex-col overflow-hidden bg-background", className), children: [
6634
+ header,
6635
+ banner,
6636
+ /* @__PURE__ */ jsxs("div", { className: "flex min-h-0 flex-1", children: [
6637
+ /* @__PURE__ */ jsxs("nav", { "aria-label": "Pages", className: "hidden w-14 shrink-0 flex-col items-center gap-1 border-r border-border py-3 md:flex", children: [
6638
+ main.map((it) => /* @__PURE__ */ jsx(RailItem, { item: it }, it.href)),
6639
+ /* @__PURE__ */ jsxs("div", { className: "mt-auto flex flex-col items-center gap-1", children: [
6640
+ foot.map((it) => /* @__PURE__ */ jsx(RailItem, { item: it }, it.href)),
6641
+ account
6642
+ ] })
6643
+ ] }),
6644
+ /* @__PURE__ */ jsx(
6645
+ "main",
6646
+ {
6647
+ id: "main-content",
6648
+ className: cn("flex min-h-0 min-w-0 flex-1 flex-col", tabs && "max-md:pb-[calc(3.5rem_+_env(safe-area-inset-bottom))]"),
6649
+ children
6650
+ }
6651
+ )
6652
+ ] }),
6653
+ tabs ? /* @__PURE__ */ jsx(TabBar, { items: tabs }) : null
6654
+ ] }) }) });
6655
+ }
6013
6656
  function AccountMenu({
6014
6657
  name,
6015
6658
  detail,
@@ -6916,6 +7559,6 @@ function createMdxComponents({ mermaid } = {}) {
6916
7559
  }
6917
7560
  var mdxComponents = createMdxComponents();
6918
7561
 
6919
- export { APP_ATTRIBUTE, APP_ID, Accent, Accordion, AccordionItem, AccountMenu, ActivityList, AnchorStatus, ApiTable, AppCard, AppGrid, AppIcon, AppShell, ArtifactView, Badge, BlockCountdown, BlockHeight, Breadcrumbs, BrowserFrame, Button, CODE_LANGS, Callout, Card, CardContent, CardDescription, CardFooter, CardGrid, CardHeader, CardNumeral, CardTitle, Checkbox, Closing, CodeBlock, CodeTabs, ComparisonTable, Container, CopyButton, Crowd, DOCS_HEADER_NAV, DOCS_HREF, DataTable, DensityProvider, Diagram, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogHost, DialogTitle, DialogTrigger, Display, DocHeader, DocLayout, DocsHeading, DocsNav, DocsPager, DocsShell, DropZone, DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, EmptyLine, EmptyState, EndpointList, ErrorBoundary, ErrorPage, Eyebrow, FAMILY, FAMILY_GROUPS, FactBlock, FactRows, FamilyMenu, Faq, Field, FilterChips, FloatChip, Footnote, FormSection, HalftoneCanvas, HalftoneSphere, HashChip, Input, InstallTabs, IsoCheck, Kbd, KeyValueList, LEGAL_LINKS, Label, Lead, LegalDocument, LinkCard, LoadingBlock, Lockup, MARK_FACES, Mark, MdxTable, Meter, Monogram, Notice, OCHK_APP_ACCOUNT, OCHK_IO, OCHK_IO_FOOTER, OCHK_IO_NAV, OchkIoFooter, OnThisPage, PROTOCOLS, PROTOCOL_ORDER, PackageCard, PageHeader, PageHero, Pagination, PhoneFrame, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, ProgressSteps, ProofStrip, Prose, ProtocolGrid, ProtocolHero, ProtocolNav, QrCode, RadioGroup, RadioGroupItem, Reveal, SELF_HOSTED_LEGAL_LINKS, SPHERE_GRADIENT, Sats, SatsFigure, ScrollFade, ScrollStory, SearchButton, SearchDialog, Section, SectionHeading, SectionIntro, Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue, Separator, SessionAccountView, Sheet, SheetClose, SheetContent, SheetDescription, SheetTitle, SheetTrigger, ShellContext, SignInFrame, SignMessage, SiteBanner, SiteFooter, SiteHeader, Skeleton, SkipLink, SpecCard, Spinner, SplitBar, StatCard, StatGrid, StateBadge, StatusBadge, StatusDot, StatusPill, Step, StepGrid, Steps, Switch, TOKEN_CLASS, Tabs, TabsContent, TabsList, TabsTrigger, TextLink, Textarea, ThemeToggle, Ticker, Toaster, ToolGrid, ToolShell, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, TruthTable, UsdApprox, VerifyBox, VerifyReport, appColors, appFonts, badgeVariants, blocksToDuration, buttonVariants, cardVariants, cn, confirm, createMdxComponents, createStateBadge, escapeHtml, explorerUrl, familyByGroup, familySite, formatBlockHeight, formatBytes, formatUtc, grammarOf, highlight, highlightToHtml, languageName, linesToHtml, mdxComponents, monogramGround, monogramLetter, parseCodeMeta, parseLineRanges, portraitTone, prompt, protocolSite, readDiff, rehypeCode, satsText, sectionVariants, shortenMiddle, statusWord, useActiveHeading, useCopy, useDensity, useHeadings, useInView, useShellPlace, useSignInHref, useTimedOut };
7562
+ export { APP_ATTRIBUTE, APP_ID, Accent, Accordion, AccordionItem, AccountMenu, ActivityList, AnchorStatus, ApiTable, AppCard, AppGrid, AppIcon, AppShell, ArtifactView, Badge, BlockCountdown, BlockHeight, Breadcrumbs, BrowserFrame, Button, CODE_LANGS, Callout, Card, CardContent, CardDescription, CardFooter, CardGrid, CardHeader, CardNumeral, CardTitle, ChartFrame, Checkbox, Closing, CodeBlock, CodeTabs, CommandDialog, ComparisonTable, Container, CopyButton, CountdownRing, Crowd, DOCS_HEADER_NAV, DOCS_HREF, DataTable, DensityProvider, Diagram, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogHost, DialogTitle, DialogTrigger, Display, DocHeader, DocLayout, DocsHeading, DocsNav, DocsPager, DocsShell, DropZone, DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, EmptyLine, EmptyState, EndpointList, ErrorBoundary, ErrorPage, Eyebrow, FAMILY, FAMILY_GROUPS, FactBlock, FactRows, FamilyMenu, Faq, Field, FilterChips, FloatChip, Footnote, FormSection, HalftoneCanvas, HalftoneSphere, HashChip, HudCard, Input, InstallTabs, IsoCheck, Kbd, KeyValueList, LEGAL_LINKS, Label, Lead, LegalDocument, LinkCard, LoadingBlock, LockedPreview, Lockup, MARK_FACES, Mark, MdxTable, Meter, Monogram, Notice, OCHK_APP_ACCOUNT, OCHK_IO, OCHK_IO_FOOTER, OCHK_IO_NAV, OchkIoFooter, OnThisPage, PROTOCOLS, PROTOCOL_ORDER, PackageCard, PageHeader, PageHero, Pagination, Panel, PhoneFrame, PlanCard, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, ProgressSteps, ProofStrip, Prose, ProtocolGrid, ProtocolHero, ProtocolNav, QrCode, RadioGroup, RadioGroupItem, Reveal, SELF_HOSTED_LEGAL_LINKS, SPHERE_GRADIENT, Sats, SatsFigure, ScrollFade, ScrollStory, SearchButton, SearchDialog, Section, SectionHeading, SectionIntro, Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue, Separator, SessionAccountView, Sheet, SheetClose, SheetContent, SheetDescription, SheetTitle, SheetTrigger, ShellContext, SignInFrame, SignMessage, SiteBanner, SiteFooter, SiteHeader, Skeleton, SkipLink, SourceNote, Sparkline, SpecCard, Spinner, SplitBar, StatCard, StatGrid, StateBadge, StatusBadge, StatusDot, StatusPill, Step, StepGrid, Steps, Switch, TOKEN_CLASS, Tabs, TabsContent, TabsList, TabsTrigger, TextLink, Textarea, ThemeToggle, Ticker, Toaster, ToolGrid, ToolShell, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, TruthTable, UsdApprox, VerifyBox, VerifyReport, appColors, appFonts, badgeVariants, blocksToDuration, buttonVariants, cardVariants, chartColor, cn, confirm, createMdxComponents, createStateBadge, darkPalette, escapeHtml, explorerUrl, familyByGroup, familySite, formatBlockHeight, formatBytes, formatUtc, grammarOf, highlight, highlightToHtml, languageName, lightPalette, linesToHtml, mdxComponents, monogramGround, monogramLetter, parseCodeMeta, parseLineRanges, portraitTone, prompt, protocolSite, readDiff, rehypeCode, satsText, sectionVariants, shortenMiddle, statusWord, useActiveHeading, useCopy, useDensity, useHeadings, useInView, useShellPlace, useSignInHref, useTimedOut };
6920
7563
  //# sourceMappingURL=index.mjs.map
6921
7564
  //# sourceMappingURL=index.mjs.map