@orangecheck/app-design 1.4.0 → 1.5.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 (43) hide show
  1. package/dist/chrome.d.mts +5 -4
  2. package/dist/chrome.d.ts +5 -4
  3. package/dist/chrome.js +171 -40
  4. package/dist/chrome.js.map +1 -1
  5. package/dist/chrome.mjs +172 -41
  6. package/dist/chrome.mjs.map +1 -1
  7. package/dist/components.d.mts +46 -9
  8. package/dist/components.d.ts +46 -9
  9. package/dist/components.js +334 -167
  10. package/dist/components.js.map +1 -1
  11. package/dist/components.mjs +333 -170
  12. package/dist/components.mjs.map +1 -1
  13. package/dist/{docs-BB9gK4KF.d.ts → docs-ByUx4t-D.d.ts} +2 -1
  14. package/dist/{docs-D-T-nHiu.d.mts → docs-CFE5mU_6.d.mts} +2 -1
  15. package/dist/index.d.mts +4 -4
  16. package/dist/index.d.ts +4 -4
  17. package/dist/index.js +572 -244
  18. package/dist/index.js.map +1 -1
  19. package/dist/index.mjs +570 -246
  20. package/dist/index.mjs.map +1 -1
  21. package/dist/mdx.d.mts +1 -1
  22. package/dist/mdx.d.ts +1 -1
  23. package/dist/mdx.js +7 -2
  24. package/dist/mdx.js.map +1 -1
  25. package/dist/mdx.mjs +7 -2
  26. package/dist/mdx.mjs.map +1 -1
  27. package/dist/primitives.d.mts +4 -3
  28. package/dist/primitives.d.ts +4 -3
  29. package/dist/primitives.js +37 -1
  30. package/dist/primitives.js.map +1 -1
  31. package/dist/primitives.mjs +37 -1
  32. package/dist/primitives.mjs.map +1 -1
  33. package/dist/session.d.mts +3 -3
  34. package/dist/session.d.ts +3 -3
  35. package/dist/session.js +1 -1
  36. package/dist/session.js.map +1 -1
  37. package/dist/session.mjs +1 -1
  38. package/dist/session.mjs.map +1 -1
  39. package/dist/{tool-shell-D8Q8XX11.d.mts → tool-shell-CQZNRUgH.d.mts} +8 -4
  40. package/dist/{tool-shell-gmlj47Ie.d.ts → tool-shell-CRmceGrV.d.ts} +8 -4
  41. package/dist/{tools-DFIxIj5p.d.mts → tools-Bg1gi2HO.d.mts} +1 -1
  42. package/dist/{tools-BggNN5DV.d.ts → tools-Bw7RhO92.d.ts} +1 -1
  43. package/package.json +3 -2
package/dist/index.js CHANGED
@@ -6,6 +6,7 @@ var react = require('react');
6
6
  var clsx = require('clsx');
7
7
  var tailwindMerge = require('tailwind-merge');
8
8
  var SeparatorPrimitive = require('@radix-ui/react-separator');
9
+ var nextThemes = require('next-themes');
9
10
  var sonner = require('sonner');
10
11
  var jsxRuntime = require('react/jsx-runtime');
11
12
  var CheckboxPrimitive = require('@radix-ui/react-checkbox');
@@ -22,7 +23,6 @@ var TabsPrimitive = require('@radix-ui/react-tabs');
22
23
  var QRCode = require('qrcode');
23
24
  var Link6 = require('next/link');
24
25
  var router = require('next/compat/router');
25
- var nextThemes = require('next-themes');
26
26
 
27
27
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
28
28
 
@@ -208,10 +208,18 @@ function StatusDot({
208
208
  }
209
209
  );
210
210
  }
211
- function Toaster(props) {
211
+ var TOAST_COLOURS = {
212
+ "--normal-bg": "var(--popover)",
213
+ "--normal-text": "var(--popover-foreground)",
214
+ "--normal-border": "var(--border)"
215
+ };
216
+ function Toaster({ style, ...props }) {
217
+ const { resolvedTheme } = nextThemes.useTheme();
212
218
  return /* @__PURE__ */ jsxRuntime.jsx(
213
219
  sonner.Toaster,
214
220
  {
221
+ theme: resolvedTheme === "dark" ? "dark" : resolvedTheme === "light" ? "light" : "system",
222
+ style: { ...TOAST_COLOURS, ...style },
215
223
  position: "bottom-right",
216
224
  toastOptions: {
217
225
  classNames: {
@@ -958,7 +966,9 @@ var none = () => null;
958
966
  function PromptBody({ ask: a }) {
959
967
  const o = a.options;
960
968
  const [value, setValue] = react.useState(o.defaultValue ?? "");
969
+ const [again, setAgain] = react.useState("");
961
970
  const [error, setError] = react.useState(null);
971
+ const [mismatch, setMismatch] = react.useState(false);
962
972
  const submit = (e) => {
963
973
  e.preventDefault();
964
974
  if (o.minLength && value.length < o.minLength) {
@@ -970,6 +980,10 @@ function PromptBody({ ask: a }) {
970
980
  setError(refused);
971
981
  return;
972
982
  }
983
+ if (o.confirmField && again !== value) {
984
+ setMismatch(true);
985
+ return;
986
+ }
973
987
  a.settle(value);
974
988
  done();
975
989
  };
@@ -985,9 +999,30 @@ function PromptBody({ ask: a }) {
985
999
  onChange: (e) => {
986
1000
  setValue(e.target.value);
987
1001
  setError(null);
1002
+ setMismatch(false);
988
1003
  }
989
1004
  }
990
1005
  ) }),
1006
+ o.confirmField ? /* @__PURE__ */ jsxRuntime.jsx(
1007
+ Field,
1008
+ {
1009
+ label: o.confirmField === true ? "Type it again" : o.confirmField,
1010
+ error: mismatch ? "The two do not match." : null,
1011
+ className: "mt-4",
1012
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1013
+ Input,
1014
+ {
1015
+ type: o.secret ? "password" : "text",
1016
+ autoComplete: o.secret ? "new-password" : "off",
1017
+ value: again,
1018
+ onChange: (e) => {
1019
+ setAgain(e.target.value);
1020
+ setMismatch(false);
1021
+ }
1022
+ }
1023
+ )
1024
+ }
1025
+ ) : null,
991
1026
  /* @__PURE__ */ jsxRuntime.jsxs(DialogFooter, { children: [
992
1027
  /* @__PURE__ */ jsxRuntime.jsx(
993
1028
  Button,
@@ -2028,7 +2063,7 @@ var JS_TAG = /<\/?(?=[A-Za-z])/y;
2028
2063
  var JS_TAG_NAME = /[A-Za-z][\w$.:-]*/y;
2029
2064
  var JS_PUNCT = /=>|\.\.\.|[{}()[\];,.<>=+\-*/%!?:&|^~#]/y;
2030
2065
  var JSX_BEFORE = /* @__PURE__ */ new Set(["(", ",", "=", "?", ":", "{", "[", ";", ">", "&&", "||", "=>", "return"]);
2031
- function scanJs(src, emit2, jsx50) {
2066
+ function scanJs(src, emit2, jsx51) {
2032
2067
  let i = 0;
2033
2068
  let prev = "";
2034
2069
  let tagDepth = 0;
@@ -2054,7 +2089,7 @@ function scanJs(src, emit2, jsx50) {
2054
2089
  sig('"');
2055
2090
  continue;
2056
2091
  }
2057
- if (jsx50 && tagDepth === 0 && (m = at(JS_TAG, src, i)) && (prev === "" || JSX_BEFORE.has(prev))) {
2092
+ if (jsx51 && tagDepth === 0 && (m = at(JS_TAG, src, i)) && (prev === "" || JSX_BEFORE.has(prev))) {
2058
2093
  const name = at(JS_TAG_NAME, src, i + m.length);
2059
2094
  if (name) {
2060
2095
  emit2(m);
@@ -2066,7 +2101,7 @@ function scanJs(src, emit2, jsx50) {
2066
2101
  continue;
2067
2102
  }
2068
2103
  }
2069
- if (jsx50 && tagDepth > 0 && braceInTag === 0) {
2104
+ if (jsx51 && tagDepth > 0 && braceInTag === 0) {
2070
2105
  if (src.startsWith("/>", i) || src[i] === ">") {
2071
2106
  const close = src[i] === ">" ? ">" : "/>";
2072
2107
  emit2(close);
@@ -2086,7 +2121,7 @@ function scanJs(src, emit2, jsx50) {
2086
2121
  continue;
2087
2122
  }
2088
2123
  if (src[i] === "{") braceInTag = 1;
2089
- } else if (jsx50 && tagDepth > 0 && braceInTag > 0) {
2124
+ } else if (jsx51 && tagDepth > 0 && braceInTag > 0) {
2090
2125
  if (src[i] === "{") braceInTag++;
2091
2126
  else if (src[i] === "}") braceInTag--;
2092
2127
  }
@@ -3035,7 +3070,8 @@ function Well({
3035
3070
  lines,
3036
3071
  maxLines,
3037
3072
  diff,
3038
- lineNumbers
3073
+ lineNumbers,
3074
+ wrap
3039
3075
  }) {
3040
3076
  const foldable = maxLines !== void 0 && lines > maxLines + 2;
3041
3077
  const [open, setOpen] = react.useState(false);
@@ -3054,7 +3090,8 @@ function Well({
3054
3090
  "data-diff": diff ? "" : void 0,
3055
3091
  "data-line-numbers": lineNumbers ? "" : void 0,
3056
3092
  className: cn(
3057
- "oca-code w-max min-w-full py-4 font-mono text-[0.875rem] leading-[1.625] text-oca-ink-muted [font-variant-ligatures:none]",
3093
+ "oca-code py-4 font-mono text-[0.875rem] leading-[1.625] text-oca-ink-muted [font-variant-ligatures:none]",
3094
+ wrap ? "whitespace-pre-wrap break-all" : "w-max min-w-full",
3058
3095
  !lined && "px-5"
3059
3096
  ),
3060
3097
  children: lined ? /* @__PURE__ */ jsxRuntime.jsx("code", { className: "block", "data-lang": lang, dangerouslySetInnerHTML: { __html: html } }) : /* @__PURE__ */ jsxRuntime.jsx("code", { className: "block", "data-lang": lang, children })
@@ -3096,6 +3133,7 @@ function CodeBlock({
3096
3133
  highlight: marks,
3097
3134
  diff,
3098
3135
  lineNumbers,
3136
+ wrap,
3099
3137
  actions,
3100
3138
  className
3101
3139
  }) {
@@ -3127,6 +3165,7 @@ function CodeBlock({
3127
3165
  maxLines,
3128
3166
  diff: prepared ? prepared.diff : isDiff,
3129
3167
  lineNumbers,
3168
+ wrap,
3130
3169
  children
3131
3170
  }
3132
3171
  )
@@ -3591,6 +3630,169 @@ var ErrorBoundary = class extends react.Component {
3591
3630
  ) });
3592
3631
  }
3593
3632
  };
3633
+
3634
+ // src/family/index.ts
3635
+ var OCHK_IO = "https://ochk.io";
3636
+ var DOCS_HREF = `${OCHK_IO}/docs`;
3637
+ function protocol(slug, verb, line, kinds) {
3638
+ return {
3639
+ slug,
3640
+ label: slug,
3641
+ href: `${OCHK_IO}/${slug}`,
3642
+ group: "protocol",
3643
+ line,
3644
+ status: "live",
3645
+ verb,
3646
+ pageHref: `${OCHK_IO}/${slug}`,
3647
+ toolHref: `https://${slug}.ochk.io`,
3648
+ specHref: `https://github.com/orangecheck/oc-${slug}-protocol`,
3649
+ kinds
3650
+ };
3651
+ }
3652
+ var PROTOCOLS = [
3653
+ protocol("attest", "identity", "Show that an address holds bitcoin, and for how long.", "30078"),
3654
+ protocol("lock", "confidentiality", "Encrypt to a Bitcoin address, so only its holder can open it.", "30078"),
3655
+ protocol("vote", "legitimacy", "Polls weighed in sats, that anyone can tally.", "30080\u201330082"),
3656
+ protocol("stamp", "provenance", "Prove who signed something, and when.", "30083"),
3657
+ protocol("agent", "authority", "Give software scoped, revocable permission to act for you.", "30083\u201330086"),
3658
+ protocol("pledge", "commitment", "Make a promise with bitcoin behind it, on a public record.", "30078")
3659
+ ];
3660
+ var PROTOCOL_ORDER = PROTOCOLS.map((p) => p.slug);
3661
+ var FAMILY = [
3662
+ {
3663
+ slug: "home",
3664
+ label: "ochk.io",
3665
+ href: OCHK_IO,
3666
+ group: "orangecheck",
3667
+ line: "The open protocols, and the company behind them.",
3668
+ status: "live"
3669
+ },
3670
+ {
3671
+ slug: "me",
3672
+ label: "ochk.app",
3673
+ href: "https://ochk.app",
3674
+ group: "orangecheck",
3675
+ line: "One account, with Bitcoin behind it.",
3676
+ status: "testing"
3677
+ },
3678
+ {
3679
+ slug: "docs",
3680
+ label: "docs",
3681
+ href: DOCS_HREF,
3682
+ group: "orangecheck",
3683
+ line: "Specs, SDKs and guides for every protocol.",
3684
+ status: "live"
3685
+ },
3686
+ ...PROTOCOLS,
3687
+ {
3688
+ slug: "vault",
3689
+ label: "vault",
3690
+ href: "https://vault.ochk.io",
3691
+ group: "app",
3692
+ line: "A password manager, encrypted in your browser.",
3693
+ status: "live",
3694
+ protocols: ["lock"]
3695
+ },
3696
+ {
3697
+ slug: "chat",
3698
+ label: "chat",
3699
+ href: "https://chat.ochk.io",
3700
+ group: "app",
3701
+ line: "Messages only the holder of a Bitcoin address can read.",
3702
+ status: "testing",
3703
+ protocols: ["lock"]
3704
+ },
3705
+ {
3706
+ slug: "cosign",
3707
+ label: "cosign",
3708
+ href: "https://cosign.ochk.io",
3709
+ group: "app",
3710
+ line: "Builders find co-founders and backers.",
3711
+ status: "testing",
3712
+ // Signs in with an orangecheck account and a wallet; uses none of the six directly.
3713
+ protocols: []
3714
+ },
3715
+ {
3716
+ slug: "me-demo",
3717
+ // "demo", not the made-up app's own name, so nobody takes it for ours.
3718
+ label: "demo",
3719
+ href: "https://me-demo.ochk.io",
3720
+ group: "app",
3721
+ line: "Lumen Notes, a made-up app that signs in with orangecheck.",
3722
+ status: "live"
3723
+ },
3724
+ {
3725
+ slug: "globe",
3726
+ label: "globe",
3727
+ href: "https://globe.ochk.io",
3728
+ group: "public-good",
3729
+ line: "The Bitcoin network, live, on a globe.",
3730
+ status: "live"
3731
+ },
3732
+ {
3733
+ slug: "btc",
3734
+ label: "btc",
3735
+ href: "https://btc.ochk.io",
3736
+ group: "public-good",
3737
+ line: "A free desk for reading the Bitcoin market.",
3738
+ status: "live"
3739
+ }
3740
+ ];
3741
+ var FAMILY_GROUPS = [
3742
+ { id: "orangecheck", label: "orangecheck" },
3743
+ { id: "protocol", label: "Protocols" },
3744
+ { id: "app", label: "Apps" },
3745
+ { id: "public-good", label: "Public goods" }
3746
+ ];
3747
+ var BY_SLUG = new Map(FAMILY.map((s) => [s.slug, s]));
3748
+ function familySite(slug) {
3749
+ return BY_SLUG.get(slug);
3750
+ }
3751
+ function protocolSite(slug) {
3752
+ return BY_SLUG.get(slug);
3753
+ }
3754
+ function familyByGroup() {
3755
+ return FAMILY_GROUPS.map((g) => ({ ...g, sites: FAMILY.filter((s) => s.group === g.id) }));
3756
+ }
3757
+ var LEGAL_LINKS = [
3758
+ { href: `${OCHK_IO}/privacy`, label: "Privacy" },
3759
+ { href: `${OCHK_IO}/terms`, label: "Terms" },
3760
+ { href: `${OCHK_IO}/security`, label: "Security" },
3761
+ { href: `${OCHK_IO}/trademark`, label: "Trademarks" },
3762
+ { href: `${OCHK_IO}/contact`, label: "Contact" }
3763
+ ];
3764
+ var SELF_HOSTED_LEGAL_LINKS = [
3765
+ { href: "/privacy", label: "Privacy" },
3766
+ { href: "/terms", label: "Terms" },
3767
+ { href: "/security", label: "Security" },
3768
+ { href: `${OCHK_IO}/trademark`, label: "Trademarks" },
3769
+ { href: "/contact", label: "Contact" }
3770
+ ];
3771
+ var OCHK_IO_NAV = [
3772
+ {
3773
+ href: `${OCHK_IO}/protocols`,
3774
+ label: "Protocols",
3775
+ children: PROTOCOLS.map((p) => ({ href: p.pageHref, label: p.label, description: p.line }))
3776
+ },
3777
+ { href: `${OCHK_IO}/apps`, label: "Apps" },
3778
+ { href: DOCS_HREF, label: "Docs" },
3779
+ { href: `${OCHK_IO}/trust`, label: "Trust" },
3780
+ { href: `${OCHK_IO}/about`, label: "About" }
3781
+ ];
3782
+ var OCHK_IO_FOOTER = [
3783
+ {
3784
+ heading: "Company",
3785
+ links: [
3786
+ { href: `${OCHK_IO}/about`, label: "About" },
3787
+ { href: `${OCHK_IO}/trust`, label: "Trust" },
3788
+ { href: "https://github.com/orangecheck", label: "GitHub", external: true }
3789
+ ]
3790
+ }
3791
+ ];
3792
+ var SiteHomeContext = sharedContext("site-home", void 0);
3793
+ function useSiteHome() {
3794
+ return react.useContext(SiteHomeContext);
3795
+ }
3594
3796
  var WORDS = {
3595
3797
  404: {
3596
3798
  name: "Not found",
@@ -3608,10 +3810,13 @@ function ErrorPage({
3608
3810
  title,
3609
3811
  detail,
3610
3812
  actions,
3611
- home = "/",
3813
+ home,
3814
+ protocol: protocol2,
3612
3815
  art,
3613
3816
  className
3614
3817
  }) {
3818
+ const shellHome = useSiteHome();
3819
+ const homeHref = home ?? (protocol2 ? protocolSite(protocol2).pageHref : shellHome ?? OCHK_IO);
3615
3820
  const words = WORDS[code] ?? (code >= 500 ? WORDS[500] : WORDS[404]);
3616
3821
  const server = code >= 500;
3617
3822
  return /* @__PURE__ */ jsxRuntime.jsx(Section, { space: "none", className: cn("flex min-h-[min(40rem,72dvh)] items-center py-16 md:py-24", className), children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 items-center gap-12 md:grid-cols-12", children: [
@@ -3625,12 +3830,137 @@ function ErrorPage({
3625
3830
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "oca-lead oca-enter [--enter-delay:150ms]", children: detail ?? words.detail }),
3626
3831
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "oca-enter flex flex-wrap gap-3 [--enter-delay:230ms]", children: actions ?? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3627
3832
  server ? /* @__PURE__ */ jsxRuntime.jsx(Button, { onClick: () => window.location.reload(), children: "Try again" }) : null,
3628
- /* @__PURE__ */ jsxRuntime.jsx(Button, { asChild: true, variant: server ? "secondary" : "primary", children: /* @__PURE__ */ jsxRuntime.jsx(Link6__default.default, { href: home, children: "Go home" }) })
3833
+ /* @__PURE__ */ jsxRuntime.jsx(Button, { asChild: true, variant: server ? "secondary" : "primary", children: /* @__PURE__ */ jsxRuntime.jsx(Link6__default.default, { href: homeHref, children: "Go home" }) })
3629
3834
  ] }) })
3630
3835
  ] }),
3631
3836
  art !== null ? /* @__PURE__ */ jsxRuntime.jsx("div", { "aria-hidden": true, className: "oca-enter hidden justify-center md:col-span-5 md:flex [--enter-delay:120ms]", children: art ?? /* @__PURE__ */ jsxRuntime.jsx(MarkOutline, { className: "w-full max-w-[20rem] text-oca-hairline-strong" }) }) : null
3632
3837
  ] }) });
3633
3838
  }
3839
+ function onSecond(tick) {
3840
+ const id = setInterval(tick, 1e3);
3841
+ return () => clearInterval(id);
3842
+ }
3843
+ var nowSeconds = () => Math.floor(Date.now() / 1e3);
3844
+ function CountdownRing({
3845
+ period,
3846
+ remaining,
3847
+ warnAt = 5,
3848
+ size = 18,
3849
+ showSeconds = true,
3850
+ className
3851
+ }) {
3852
+ const now = react.useSyncExternalStore(onSecond, nowSeconds, () => null);
3853
+ const left = remaining ?? (now === null ? null : period - now % period);
3854
+ const share = left === null ? 1 : Math.max(0, Math.min(1, left / period));
3855
+ const warn = left !== null && left <= warnAt;
3856
+ const r = size / 2 - 1.5;
3857
+ const c = 2 * Math.PI * r;
3858
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3859
+ "span",
3860
+ {
3861
+ role: "timer",
3862
+ "aria-label": left === null ? void 0 : `${left} second${left === 1 ? "" : "s"} left`,
3863
+ className: cn("inline-flex items-center gap-1.5", warn ? "text-destructive" : "text-muted-foreground", className),
3864
+ children: [
3865
+ /* @__PURE__ */ jsxRuntime.jsxs("svg", { "aria-hidden": true, width: size, height: size, viewBox: `0 0 ${size} ${size}`, className: "-rotate-90", children: [
3866
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: size / 2, cy: size / 2, r, fill: "none", stroke: "var(--border)", strokeWidth: 2 }),
3867
+ /* @__PURE__ */ jsxRuntime.jsx(
3868
+ "circle",
3869
+ {
3870
+ cx: size / 2,
3871
+ cy: size / 2,
3872
+ r,
3873
+ fill: "none",
3874
+ stroke: "currentColor",
3875
+ strokeWidth: 2,
3876
+ strokeLinecap: "round",
3877
+ strokeDasharray: c,
3878
+ strokeDashoffset: c * (1 - share),
3879
+ className: cn(left !== null && left < period && "transition-[stroke-dashoffset] duration-1000 ease-linear motion-reduce:transition-none")
3880
+ }
3881
+ )
3882
+ ] }),
3883
+ showSeconds && left !== null ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-[0.8125rem] oca-tabular", children: [
3884
+ left,
3885
+ "s"
3886
+ ] }) : null
3887
+ ]
3888
+ }
3889
+ );
3890
+ }
3891
+ function PlanCard({
3892
+ name,
3893
+ subtitle,
3894
+ price,
3895
+ period,
3896
+ footnote,
3897
+ features = [],
3898
+ action,
3899
+ badge,
3900
+ badgeTone = "neutral",
3901
+ highlight: highlight2 = false,
3902
+ className
3903
+ }) {
3904
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3905
+ "section",
3906
+ {
3907
+ className: cn(
3908
+ "flex h-full flex-col gap-5 rounded-[1.25rem] border bg-card p-6",
3909
+ highlight2 ? "border-foreground shadow-sm ring-1 ring-foreground" : "border-border",
3910
+ className
3911
+ ),
3912
+ children: [
3913
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1.5", children: [
3914
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-3", children: [
3915
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-[1.0625rem] font-medium leading-snug", children: name }),
3916
+ badge ? /* @__PURE__ */ jsxRuntime.jsx(Badge, { tone: badgeTone, children: badge }) : null
3917
+ ] }),
3918
+ subtitle ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[0.875rem] leading-snug text-muted-foreground", children: subtitle }) : null
3919
+ ] }),
3920
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [
3921
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "flex flex-wrap items-baseline gap-x-1.5", children: [
3922
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "oca-display-3 oca-tabular", children: price }),
3923
+ period ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[0.9375rem] text-muted-foreground", children: period }) : null
3924
+ ] }),
3925
+ footnote ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[0.8125rem] text-muted-foreground", children: footnote }) : null
3926
+ ] }),
3927
+ features.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "flex flex-col gap-2.5 text-[0.9375rem]", children: features.map((f, i) => /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex items-start gap-2.5", children: [
3928
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { "aria-hidden": true, className: "mt-1 size-4 shrink-0 text-muted-foreground" }),
3929
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0", children: f })
3930
+ ] }, i)) }) : null,
3931
+ action ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-auto flex flex-col pt-1 [&>*]:w-full", children: action }) : null
3932
+ ]
3933
+ }
3934
+ );
3935
+ }
3936
+ function LockedPreview({
3937
+ title,
3938
+ description,
3939
+ action,
3940
+ children,
3941
+ className
3942
+ }) {
3943
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("relative", className), children: [
3944
+ children ? /* @__PURE__ */ jsxRuntime.jsx(
3945
+ "div",
3946
+ {
3947
+ inert: true,
3948
+ "aria-hidden": true,
3949
+ "data-oca-locked": "",
3950
+ className: "pointer-events-none max-h-[28rem] select-none overflow-hidden [mask-image:linear-gradient(to_bottom,#000_25%,transparent_85%)]",
3951
+ children
3952
+ }
3953
+ ) : null,
3954
+ /* @__PURE__ */ jsxRuntime.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: [
3955
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: "flex size-10 items-center justify-center rounded-full bg-muted text-foreground", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Lock, { className: "size-[1.125rem]" }) }),
3956
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1.5", children: [
3957
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[1.0625rem] font-medium leading-snug", children: title }),
3958
+ description ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[0.9375rem] leading-snug text-muted-foreground", children: description }) : null
3959
+ ] }),
3960
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap justify-center gap-2", children: action })
3961
+ ] })
3962
+ ] });
3963
+ }
3634
3964
  function SectionHeading({
3635
3965
  eyebrow,
3636
3966
  title,
@@ -3871,165 +4201,6 @@ function LegalDocument({ doc, className }) {
3871
4201
  }
3872
4202
  );
3873
4203
  }
3874
-
3875
- // src/family/index.ts
3876
- var OCHK_IO = "https://ochk.io";
3877
- var DOCS_HREF = `${OCHK_IO}/docs`;
3878
- function protocol(slug, verb, line, kinds) {
3879
- return {
3880
- slug,
3881
- label: slug,
3882
- href: `${OCHK_IO}/${slug}`,
3883
- group: "protocol",
3884
- line,
3885
- status: "live",
3886
- verb,
3887
- pageHref: `${OCHK_IO}/${slug}`,
3888
- toolHref: `https://${slug}.ochk.io`,
3889
- specHref: `https://github.com/orangecheck/oc-${slug}-protocol`,
3890
- kinds
3891
- };
3892
- }
3893
- var PROTOCOLS = [
3894
- protocol("attest", "identity", "Show that an address holds bitcoin, and for how long.", "30078"),
3895
- protocol("lock", "confidentiality", "Encrypt to a Bitcoin address, so only its holder can open it.", "30078"),
3896
- protocol("vote", "legitimacy", "Polls weighed in sats, that anyone can tally.", "30080\u201330082"),
3897
- protocol("stamp", "provenance", "Prove who signed something, and when.", "30083"),
3898
- protocol("agent", "authority", "Give software scoped, revocable permission to act for you.", "30083\u201330086"),
3899
- protocol("pledge", "commitment", "Make a promise with bitcoin behind it, on a public record.", "30078")
3900
- ];
3901
- var PROTOCOL_ORDER = PROTOCOLS.map((p) => p.slug);
3902
- var FAMILY = [
3903
- {
3904
- slug: "home",
3905
- label: "ochk.io",
3906
- href: OCHK_IO,
3907
- group: "orangecheck",
3908
- line: "The open protocols, and the company behind them.",
3909
- status: "live"
3910
- },
3911
- {
3912
- slug: "me",
3913
- label: "ochk.app",
3914
- href: "https://ochk.app",
3915
- group: "orangecheck",
3916
- line: "One account, with Bitcoin behind it.",
3917
- status: "testing"
3918
- },
3919
- {
3920
- slug: "docs",
3921
- label: "docs",
3922
- href: DOCS_HREF,
3923
- group: "orangecheck",
3924
- line: "Specs, SDKs and guides for every protocol.",
3925
- status: "live"
3926
- },
3927
- ...PROTOCOLS,
3928
- {
3929
- slug: "vault",
3930
- label: "vault",
3931
- href: "https://vault.ochk.io",
3932
- group: "app",
3933
- line: "A password manager, encrypted in your browser.",
3934
- status: "live",
3935
- protocols: ["lock"]
3936
- },
3937
- {
3938
- slug: "chat",
3939
- label: "chat",
3940
- href: "https://chat.ochk.io",
3941
- group: "app",
3942
- line: "Messages only the holder of a Bitcoin address can read.",
3943
- status: "testing",
3944
- protocols: ["lock"]
3945
- },
3946
- {
3947
- slug: "cosign",
3948
- label: "cosign",
3949
- href: "https://cosign.ochk.io",
3950
- group: "app",
3951
- line: "Builders find co-founders and backers.",
3952
- status: "testing",
3953
- // Signs in with an orangecheck account and a wallet; uses none of the six directly.
3954
- protocols: []
3955
- },
3956
- {
3957
- slug: "me-demo",
3958
- // "demo", not the made-up app's own name, so nobody takes it for ours.
3959
- label: "demo",
3960
- href: "https://me-demo.ochk.io",
3961
- group: "app",
3962
- line: "Lumen Notes, a made-up app that signs in with orangecheck.",
3963
- status: "live"
3964
- },
3965
- {
3966
- slug: "globe",
3967
- label: "globe",
3968
- href: "https://globe.ochk.io",
3969
- group: "public-good",
3970
- line: "The Bitcoin network, live, on a globe.",
3971
- status: "live"
3972
- },
3973
- {
3974
- slug: "btc",
3975
- label: "btc",
3976
- href: "https://btc.ochk.io",
3977
- group: "public-good",
3978
- line: "A free desk for reading the Bitcoin market.",
3979
- status: "live"
3980
- }
3981
- ];
3982
- var FAMILY_GROUPS = [
3983
- { id: "orangecheck", label: "orangecheck" },
3984
- { id: "protocol", label: "Protocols" },
3985
- { id: "app", label: "Apps" },
3986
- { id: "public-good", label: "Public goods" }
3987
- ];
3988
- var BY_SLUG = new Map(FAMILY.map((s) => [s.slug, s]));
3989
- function familySite(slug) {
3990
- return BY_SLUG.get(slug);
3991
- }
3992
- function protocolSite(slug) {
3993
- return BY_SLUG.get(slug);
3994
- }
3995
- function familyByGroup() {
3996
- return FAMILY_GROUPS.map((g) => ({ ...g, sites: FAMILY.filter((s) => s.group === g.id) }));
3997
- }
3998
- var LEGAL_LINKS = [
3999
- { href: `${OCHK_IO}/privacy`, label: "Privacy" },
4000
- { href: `${OCHK_IO}/terms`, label: "Terms" },
4001
- { href: `${OCHK_IO}/security`, label: "Security" },
4002
- { href: `${OCHK_IO}/trademark`, label: "Trademarks" },
4003
- { href: `${OCHK_IO}/contact`, label: "Contact" }
4004
- ];
4005
- var SELF_HOSTED_LEGAL_LINKS = [
4006
- { href: "/privacy", label: "Privacy" },
4007
- { href: "/terms", label: "Terms" },
4008
- { href: "/security", label: "Security" },
4009
- { href: `${OCHK_IO}/trademark`, label: "Trademarks" },
4010
- { href: "/contact", label: "Contact" }
4011
- ];
4012
- var OCHK_IO_NAV = [
4013
- {
4014
- href: `${OCHK_IO}/protocols`,
4015
- label: "Protocols",
4016
- children: PROTOCOLS.map((p) => ({ href: p.pageHref, label: p.label, description: p.line }))
4017
- },
4018
- { href: `${OCHK_IO}/apps`, label: "Apps" },
4019
- { href: DOCS_HREF, label: "Docs" },
4020
- { href: `${OCHK_IO}/trust`, label: "Trust" },
4021
- { href: `${OCHK_IO}/about`, label: "About" }
4022
- ];
4023
- var OCHK_IO_FOOTER = [
4024
- {
4025
- heading: "Company",
4026
- links: [
4027
- { href: `${OCHK_IO}/about`, label: "About" },
4028
- { href: `${OCHK_IO}/trust`, label: "Trust" },
4029
- { href: "https://github.com/orangecheck", label: "GitHub", external: true }
4030
- ]
4031
- }
4032
- ];
4033
4204
  var InDocsContext = sharedContext("in-docs", false);
4034
4205
  function useInDocs() {
4035
4206
  return react.useContext(InDocsContext);
@@ -4846,6 +5017,7 @@ function SignMessage({
4846
5017
  error,
4847
5018
  submitLabel = "Confirm",
4848
5019
  secondary,
5020
+ scheme = "bip322",
4849
5021
  onSignature,
4850
5022
  className
4851
5023
  }) {
@@ -4860,7 +5032,7 @@ function SignMessage({
4860
5032
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "h-px flex-1 bg-border" })
4861
5033
  ] })
4862
5034
  ] }) : null,
4863
- /* @__PURE__ */ jsxRuntime.jsx(CodeBlock, { code: message, caption: "Message to sign" }),
5035
+ /* @__PURE__ */ jsxRuntime.jsx(CodeBlock, { code: message, caption: "Message to sign", wrap: true }),
4864
5036
  /* @__PURE__ */ jsxRuntime.jsxs(
4865
5037
  "form",
4866
5038
  {
@@ -4876,7 +5048,9 @@ function SignMessage({
4876
5048
  label: "Signature",
4877
5049
  error,
4878
5050
  hint: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4879
- "From your wallet\u2019s \u201Csign message\u201D (BIP-322), signed by",
5051
+ "From your wallet\u2019s \u201Csign message\u201D (",
5052
+ scheme === "legacy" ? "legacy, BIP-137" : "BIP-322",
5053
+ "), signed by",
4880
5054
  " ",
4881
5055
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "break-all font-mono", children: address }),
4882
5056
  "."
@@ -4944,6 +5118,7 @@ function SearchDialog({
4944
5118
  idle,
4945
5119
  defaultQuery = "",
4946
5120
  debounceMs = 120,
5121
+ browse = false,
4947
5122
  className
4948
5123
  }) {
4949
5124
  const [own, setOwn] = react.useState(false);
@@ -4980,7 +5155,7 @@ function SearchDialog({
4980
5155
  }, [hotkey]);
4981
5156
  react.useEffect(() => {
4982
5157
  const q = query.trim();
4983
- if (!q) {
5158
+ if (!q && !(browse && open)) {
4984
5159
  setGroups([]);
4985
5160
  setState("idle");
4986
5161
  return;
@@ -5002,14 +5177,15 @@ function SearchDialog({
5002
5177
  clearTimeout(t);
5003
5178
  ctl.abort();
5004
5179
  };
5005
- }, [query, debounceMs]);
5180
+ }, [query, debounceMs, browse, open]);
5006
5181
  react.useEffect(() => {
5007
5182
  listRef.current?.querySelector('[aria-selected="true"]')?.scrollIntoView({ block: "nearest" });
5008
5183
  }, [active]);
5009
5184
  const choose = (r) => {
5010
5185
  setOpen(false);
5011
- if (onSelect) onSelect(r);
5012
- else window.location.assign(r.href);
5186
+ if (r.run) r.run();
5187
+ else if (onSelect) onSelect(r);
5188
+ else if (r.href) window.location.assign(r.href);
5013
5189
  };
5014
5190
  const optionId = (i) => `${listId}-o${i}`;
5015
5191
  const showList = state === "done" && flat.length > 0;
@@ -5080,25 +5256,28 @@ function SearchDialog({
5080
5256
  index++;
5081
5257
  const i = index;
5082
5258
  const on = i === active;
5259
+ const Option = r.href ? "a" : "div";
5083
5260
  return /* @__PURE__ */ jsxRuntime.jsxs(
5084
- "a",
5261
+ Option,
5085
5262
  {
5086
5263
  id: optionId(i),
5087
- href: r.href,
5264
+ ...r.href ? { href: r.href } : {},
5088
5265
  role: "option",
5089
5266
  "aria-selected": on,
5090
5267
  tabIndex: -1,
5091
5268
  onMouseMove: () => setActive(i),
5092
5269
  onClick: (e) => {
5093
- if (e.metaKey || e.ctrlKey || e.shiftKey) return;
5270
+ if (r.href && (e.metaKey || e.ctrlKey || e.shiftKey)) return;
5094
5271
  e.preventDefault();
5095
5272
  choose(r);
5096
5273
  },
5097
5274
  className: cn(
5098
5275
  "flex items-start gap-3 rounded-xl px-3 py-2.5 transition-colors",
5099
- on ? "bg-accent" : "hover:bg-accent"
5276
+ on ? "bg-accent" : "hover:bg-accent",
5277
+ !r.href && "cursor-pointer"
5100
5278
  ),
5101
5279
  children: [
5280
+ r.icon ? /* @__PURE__ */ jsxRuntime.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,
5102
5281
  /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-1 flex-col gap-0.5", children: [
5103
5282
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-[0.9375rem] font-medium text-foreground", children: r.title }),
5104
5283
  r.section ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-[0.8125rem] text-muted-foreground", children: r.section }) : null,
@@ -5110,6 +5289,7 @@ function SearchDialog({
5110
5289
  }
5111
5290
  ) : r.excerpt ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "line-clamp-2 text-[0.875rem] leading-snug text-muted-foreground", children: r.excerpt }) : null
5112
5291
  ] }),
5292
+ r.meta ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mt-0.5 shrink-0 text-[0.8125rem] text-muted-foreground", children: r.meta }) : null,
5113
5293
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CornerDownLeft, { "aria-hidden": true, className: cn("mt-1 size-4 shrink-0 text-muted-foreground", !on && "invisible") })
5114
5294
  ]
5115
5295
  },
@@ -5118,11 +5298,11 @@ function SearchDialog({
5118
5298
  })
5119
5299
  ] }, gi)) }),
5120
5300
  state === "idle" ? /* @__PURE__ */ jsxRuntime.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,
5121
- state === "done" && flat.length === 0 ? /* @__PURE__ */ jsxRuntime.jsxs("p", { role: "status", className: "px-3 py-6 text-[0.9375rem] text-muted-foreground", children: [
5301
+ state === "done" && flat.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("p", { role: "status", className: "px-3 py-6 text-[0.9375rem] text-muted-foreground", children: query.trim() ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
5122
5302
  "No results for \u201C",
5123
5303
  query.trim(),
5124
5304
  "\u201D."
5125
- ] }) : null,
5305
+ ] }) : "Nothing here yet." }) : null,
5126
5306
  state === "error" ? /* @__PURE__ */ jsxRuntime.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
5127
5307
  ] }),
5128
5308
  /* @__PURE__ */ jsxRuntime.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: [
@@ -5147,6 +5327,13 @@ function SearchDialog({
5147
5327
  ] }) })
5148
5328
  ] });
5149
5329
  }
5330
+ function CommandDialog({
5331
+ label = "Commands",
5332
+ placeholder = "Search, or run a command",
5333
+ ...props
5334
+ }) {
5335
+ return /* @__PURE__ */ jsxRuntime.jsx(SearchDialog, { ...props, label, placeholder, button: false, browse: true });
5336
+ }
5150
5337
  function pretty(content) {
5151
5338
  try {
5152
5339
  return JSON.stringify(JSON.parse(content), null, 2);
@@ -5388,7 +5575,7 @@ function FormSection({
5388
5575
  "aria-current": status === "current" ? "step" : void 0,
5389
5576
  className: cn("scroll-mt-24 rounded-[1.25rem] border border-border bg-card", className),
5390
5577
  children: [
5391
- /* @__PURE__ */ jsxRuntime.jsxs("header", { className: cn("flex items-start gap-3.5", tight ? "px-5 pt-5" : "px-6 pt-6"), children: [
5578
+ /* @__PURE__ */ jsxRuntime.jsxs("header", { className: cn("flex flex-wrap items-start gap-x-3.5 gap-y-3", tight ? "px-5 pt-5" : "px-6 pt-6"), children: [
5392
5579
  n !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(
5393
5580
  "span",
5394
5581
  {
@@ -5415,7 +5602,7 @@ function FormSection({
5415
5602
  ] }),
5416
5603
  hint ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[0.875rem] leading-snug text-muted-foreground", children: hint }) : null
5417
5604
  ] }),
5418
- action ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0", children: action }) : null
5605
+ action ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("shrink-0 max-sm:basis-full", n !== void 0 && "max-sm:pl-[2.625rem]"), children: action }) : null
5419
5606
  ] }),
5420
5607
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex flex-col", tight ? "gap-4 p-5" : "gap-5 p-6", n !== void 0 && (tight ? "sm:pl-[3.875rem]" : "sm:pl-[4.125rem]")), children })
5421
5608
  ]
@@ -5575,6 +5762,13 @@ function BlockCountdown({
5575
5762
  ] }) : null
5576
5763
  ] });
5577
5764
  }
5765
+ var METER_FILL = {
5766
+ ink: "bg-foreground",
5767
+ brand: "bg-oca-orange-deep",
5768
+ good: "bg-success",
5769
+ caution: "bg-warning",
5770
+ bad: "bg-destructive"
5771
+ };
5578
5772
  function Meter({
5579
5773
  value,
5580
5774
  max,
@@ -5609,7 +5803,7 @@ function Meter({
5609
5803
  /* @__PURE__ */ jsxRuntime.jsx(
5610
5804
  "div",
5611
5805
  {
5612
- className: cn("h-full shrink-0 rounded-full", tone === "brand" ? "bg-oca-orange-deep" : "bg-foreground"),
5806
+ className: cn("h-full shrink-0 rounded-full", METER_FILL[tone]),
5613
5807
  style: { width: `${v * 100}%` }
5614
5808
  }
5615
5809
  ),
@@ -5645,27 +5839,30 @@ function FilterChips({
5645
5839
  onChange(cur.includes(v) ? cur.filter((x) => x !== v) : [...cur, v]);
5646
5840
  } else onChange(v);
5647
5841
  };
5648
- return /* @__PURE__ */ jsxRuntime.jsx(ScrollFade, { fade: "var(--background)", className: cn("w-full", className), children: /* @__PURE__ */ jsxRuntime.jsx("div", { role: "group", "aria-label": label, className: "flex w-max items-center gap-2 py-0.5", children: options.map((o) => {
5649
- const on = isOn(o.value);
5650
- return /* @__PURE__ */ jsxRuntime.jsxs(
5651
- "button",
5652
- {
5653
- type: "button",
5654
- "aria-pressed": on,
5655
- onClick: () => press(o.value),
5656
- className: cn(
5657
- "inline-flex shrink-0 items-center gap-1.5 rounded-full border px-3.5 text-[0.875rem] transition-colors",
5658
- tight ? "h-8" : "h-9",
5659
- on ? "border-foreground bg-foreground text-background" : "border-border bg-card text-muted-foreground hover:border-oca-hairline-strong hover:text-foreground"
5660
- ),
5661
- children: [
5662
- o.label,
5663
- o.count !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "oca-tabular", children: o.count.toLocaleString("en-US") }) : null
5664
- ]
5665
- },
5666
- o.value
5667
- );
5668
- }) }) });
5842
+ return (
5843
+ // Wraps rather than scrolls: every filter stays in view on a phone.
5844
+ /* @__PURE__ */ jsxRuntime.jsx("div", { role: "group", "aria-label": label, className: cn("flex flex-wrap items-center gap-2 py-0.5", className), children: options.map((o) => {
5845
+ const on = isOn(o.value);
5846
+ return /* @__PURE__ */ jsxRuntime.jsxs(
5847
+ "button",
5848
+ {
5849
+ type: "button",
5850
+ "aria-pressed": on,
5851
+ onClick: () => press(o.value),
5852
+ className: cn(
5853
+ "inline-flex shrink-0 items-center gap-1.5 rounded-full border px-3.5 text-[0.875rem] transition-colors",
5854
+ tight ? "h-8" : "h-9",
5855
+ on ? "border-foreground bg-foreground text-background" : "border-border bg-card text-muted-foreground hover:border-oca-hairline-strong hover:text-foreground"
5856
+ ),
5857
+ children: [
5858
+ o.label,
5859
+ o.count !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "oca-tabular", children: o.count.toLocaleString("en-US") }) : null
5860
+ ]
5861
+ },
5862
+ o.value
5863
+ );
5864
+ }) })
5865
+ );
5669
5866
  }
5670
5867
  function ToolGrid({
5671
5868
  tools,
@@ -5853,48 +6050,106 @@ function SectionSwitch({
5853
6050
  }
5854
6051
  );
5855
6052
  }
6053
+ function NavBadge({ badge, className }) {
6054
+ if (typeof badge === "number") {
6055
+ return /* @__PURE__ */ jsxRuntime.jsx(
6056
+ "span",
6057
+ {
6058
+ "aria-hidden": true,
6059
+ className: cn(
6060
+ "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",
6061
+ className
6062
+ ),
6063
+ children: badge > 99 ? "99+" : badge
6064
+ }
6065
+ );
6066
+ }
6067
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: cn("absolute size-2 rounded-full bg-oca-orange-deep ring-2 ring-background", className) });
6068
+ }
6069
+ 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";
6070
+ function TabFace({ icon, label, badge, active }) {
6071
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
6072
+ /* @__PURE__ */ jsxRuntime.jsxs(
6073
+ "span",
6074
+ {
6075
+ className: cn(
6076
+ "relative flex h-7 w-12 items-center justify-center rounded-full transition-[background-color,box-shadow] duration-200",
6077
+ "[&_svg]:size-[1.125rem] [&_svg]:shrink-0",
6078
+ active ? "bg-card shadow-sm ring-1 ring-border [&_svg]:stroke-2" : "[&_svg]:stroke-[1.75]"
6079
+ ),
6080
+ children: [
6081
+ icon,
6082
+ badge ? /* @__PURE__ */ jsxRuntime.jsx(NavBadge, { badge, className: typeof badge === "number" ? "-top-1 right-0.5" : "right-2.5 top-0.5" }) : null
6083
+ ]
6084
+ }
6085
+ ),
6086
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "max-w-full truncate px-0.5", children: label }),
6087
+ badge ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: badge }) : null
6088
+ ] });
6089
+ }
5856
6090
  function TabBar({ items }) {
6091
+ const [more, setMore] = react.useState(false);
6092
+ const overflow = items.length > 5;
6093
+ const shown = overflow ? items.slice(0, 4) : items;
6094
+ const rest = overflow ? items.slice(4) : [];
6095
+ const restBadge = rest.find((it) => it.badge)?.badge;
5857
6096
  return /* @__PURE__ */ jsxRuntime.jsx(
5858
6097
  "nav",
5859
6098
  {
5860
6099
  "aria-label": "Pages",
5861
6100
  "data-oca-tabbar": "",
5862
6101
  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",
5863
- children: /* @__PURE__ */ jsxRuntime.jsx(
6102
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
5864
6103
  "div",
5865
6104
  {
5866
6105
  className: "mx-auto grid h-14 max-w-[32rem] px-1.5",
5867
- style: { gridTemplateColumns: `repeat(${items.length}, minmax(0, 1fr))` },
5868
- children: items.map((it) => /* @__PURE__ */ jsxRuntime.jsxs(
5869
- Link6__default.default,
5870
- {
5871
- href: it.href,
5872
- "aria-current": it.active ? "page" : void 0,
5873
- className: cn(
5874
- "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",
5875
- it.active ? "text-foreground" : "text-muted-foreground hover:text-foreground"
6106
+ style: { gridTemplateColumns: `repeat(${shown.length + (overflow ? 1 : 0)}, minmax(0, 1fr))` },
6107
+ children: [
6108
+ shown.map((it) => /* @__PURE__ */ jsxRuntime.jsx(
6109
+ Link6__default.default,
6110
+ {
6111
+ href: it.href,
6112
+ "aria-current": it.active ? "page" : void 0,
6113
+ className: cn(TAB, it.active ? "text-foreground" : "text-muted-foreground hover:text-foreground"),
6114
+ children: /* @__PURE__ */ jsxRuntime.jsx(TabFace, { icon: it.icon, label: it.label, badge: it.badge, active: it.active })
6115
+ },
6116
+ it.href
6117
+ )),
6118
+ overflow ? /* @__PURE__ */ jsxRuntime.jsxs(Sheet, { open: more, onOpenChange: setMore, children: [
6119
+ /* @__PURE__ */ jsxRuntime.jsx(
6120
+ SheetTrigger,
6121
+ {
6122
+ className: cn(TAB, rest.some((it) => it.active) ? "text-foreground" : "text-muted-foreground hover:text-foreground"),
6123
+ children: /* @__PURE__ */ jsxRuntime.jsx(TabFace, { icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Ellipsis, {}), label: "More", badge: restBadge ? true : void 0, active: rest.some((it) => it.active) })
6124
+ }
5876
6125
  ),
5877
- children: [
5878
- /* @__PURE__ */ jsxRuntime.jsxs(
5879
- "span",
6126
+ /* @__PURE__ */ jsxRuntime.jsxs(SheetContent, { side: "bottom", className: "pb-[calc(1.5rem+env(safe-area-inset-bottom))]", children: [
6127
+ /* @__PURE__ */ jsxRuntime.jsx(SheetTitle, { className: "px-1 text-[1.0625rem] font-medium", children: "More" }),
6128
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-4 grid grid-cols-3 gap-2", children: rest.map((it) => /* @__PURE__ */ jsxRuntime.jsxs(
6129
+ Link6__default.default,
5880
6130
  {
6131
+ href: it.href,
6132
+ onClick: () => setMore(false),
6133
+ "aria-current": it.active ? "page" : void 0,
5881
6134
  className: cn(
5882
- "relative flex h-7 w-12 items-center justify-center rounded-full transition-[background-color,box-shadow] duration-200",
5883
- "[&_svg]:size-[1.125rem] [&_svg]:shrink-0",
5884
- it.active ? "bg-card shadow-sm ring-1 ring-border [&_svg]:stroke-2" : "[&_svg]:stroke-[1.75]"
6135
+ "flex min-h-20 flex-col items-center justify-center gap-2 rounded-2xl border px-2 text-center text-[0.8125rem] transition-colors",
6136
+ "[&_svg]:size-5",
6137
+ it.active ? "border-foreground bg-card text-foreground" : "border-border text-muted-foreground hover:text-foreground"
5885
6138
  ),
5886
6139
  children: [
5887
- it.icon,
5888
- it.badge ? /* @__PURE__ */ jsxRuntime.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
6140
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "relative", children: [
6141
+ it.icon,
6142
+ it.badge ? /* @__PURE__ */ jsxRuntime.jsx(NavBadge, { badge: it.badge, className: typeof it.badge === "number" ? "-right-3 -top-2" : "-right-1 -top-0.5" }) : null
6143
+ ] }),
6144
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "max-w-full truncate", children: it.label }),
6145
+ it.badge ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: it.badge }) : null
5889
6146
  ]
5890
- }
5891
- ),
5892
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "max-w-full truncate px-0.5", children: it.label }),
5893
- it.badge ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: it.badge }) : null
5894
- ]
5895
- },
5896
- it.href
5897
- ))
6147
+ },
6148
+ it.href
6149
+ )) })
6150
+ ] })
6151
+ ] }) : null
6152
+ ]
5898
6153
  }
5899
6154
  )
5900
6155
  }
@@ -5902,7 +6157,11 @@ function TabBar({ items }) {
5902
6157
  }
5903
6158
  function tabsFor(groups) {
5904
6159
  const items = groups.flatMap((g) => g.items);
5905
- return items.length >= 2 && items.length <= 5 && items.every((it) => it.icon) ? items : null;
6160
+ return items.length >= 2 && items.every((it) => it.icon) ? items : null;
6161
+ }
6162
+ function sectionTabs(sections, current2) {
6163
+ if (!sections || !current2 || sections.length < 2 || !sections.every((sec) => sec.icon)) return null;
6164
+ return sections.map((sec) => ({ href: sec.href, label: sec.label, icon: sec.icon, active: sec.id === current2.id }));
5906
6165
  }
5907
6166
  var activeItem = (groups) => groups.flatMap((g) => g.items).find((it) => it.active);
5908
6167
  var warned = /* @__PURE__ */ new Set();
@@ -5917,7 +6176,10 @@ function warnDuplicateLabels(groups) {
5917
6176
  seen.add(it.label);
5918
6177
  }
5919
6178
  }
5920
- function AppShell({
6179
+ function AppShell(props) {
6180
+ return props.variant === "rail" ? /* @__PURE__ */ jsxRuntime.jsx(RailShell, { ...props }) : /* @__PURE__ */ jsxRuntime.jsx(SidebarShell, { ...props });
6181
+ }
6182
+ function SidebarShell({
5921
6183
  nav,
5922
6184
  sections,
5923
6185
  activeSection,
@@ -5935,7 +6197,8 @@ function AppShell({
5935
6197
  const current2 = sections && sections.length > 0 ? sections.find((sec) => sec.id === activeSection) ?? sections.find((sec) => activeItem(sec.groups)) ?? sections[0] : void 0;
5936
6198
  const groups = current2 ? [...current2.groups, ...persistent] : [...nav ?? [], ...persistent];
5937
6199
  warnDuplicateLabels(groups);
5938
- const tabs = current2 ? null : tabsFor(groups);
6200
+ const sectionTabsFor = sectionTabs(sections, current2);
6201
+ const tabs = current2 ? sectionTabsFor : tabsFor(groups);
5939
6202
  const page = activeItem(groups);
5940
6203
  const place = react.useMemo(
5941
6204
  () => ({
@@ -5963,8 +6226,8 @@ function AppShell({
5963
6226
  {
5964
6227
  className: cn(
5965
6228
  "inline-flex size-10 items-center justify-center rounded-full hover:bg-accent",
5966
- // The tab bar holds every page; the sheet is left for a footer.
5967
- tabs && !footer && "max-md:hidden"
6229
+ // The tab bar holds every page; the sheet is left for a footer. Section tabs leave the pages here.
6230
+ tabs && !sectionTabsFor && !footer && "max-md:hidden"
5968
6231
  ),
5969
6232
  "aria-label": "Open navigation",
5970
6233
  children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Menu, { className: "size-5" })
@@ -5972,8 +6235,8 @@ function AppShell({
5972
6235
  ),
5973
6236
  /* @__PURE__ */ jsxRuntime.jsxs(SheetContent, { side: "left", className: "flex flex-col gap-6 overflow-y-auto p-4 pt-16", children: [
5974
6237
  /* @__PURE__ */ jsxRuntime.jsx(SheetTitle, { className: "sr-only", children: "Navigation" }),
5975
- switcher,
5976
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: tabs ? "max-md:hidden" : void 0, children: /* @__PURE__ */ jsxRuntime.jsx(SideNav, { groups, onNavigate: () => setOpen(false) }) }),
6238
+ switcher ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: sectionTabsFor ? "max-md:hidden" : void 0, children: switcher }) : null,
6239
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: tabs && !sectionTabsFor ? "max-md:hidden" : void 0, children: /* @__PURE__ */ jsxRuntime.jsx(SideNav, { groups, onNavigate: () => setOpen(false) }) }),
5977
6240
  footer ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-auto flex flex-col gap-3", children: footer }) : null
5978
6241
  ] })
5979
6242
  ] }),
@@ -5987,7 +6250,7 @@ function AppShell({
5987
6250
  className: cn(
5988
6251
  "flex h-9 items-center gap-1.5 border-t border-border px-4 text-[0.875rem]",
5989
6252
  // The active tab already names the page.
5990
- tabs && !pageOverride && "max-md:hidden"
6253
+ tabs && !sectionTabsFor && !pageOverride && "max-md:hidden"
5991
6254
  ),
5992
6255
  children: [
5993
6256
  place.section ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
@@ -6020,6 +6283,64 @@ function AppShell({
6020
6283
  }
6021
6284
  ) });
6022
6285
  }
6286
+ function RailItem({ item }) {
6287
+ return /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
6288
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
6289
+ Link6__default.default,
6290
+ {
6291
+ href: item.href,
6292
+ "aria-current": item.active ? "page" : void 0,
6293
+ className: cn(
6294
+ "relative flex size-10 items-center justify-center rounded-xl outline-none transition-colors focus-visible:ring-2 focus-visible:ring-ring",
6295
+ "[&_svg]:size-5 [&_svg]:shrink-0",
6296
+ item.active ? "bg-card text-foreground shadow-sm ring-1 ring-border" : "text-muted-foreground hover:bg-accent hover:text-foreground"
6297
+ ),
6298
+ children: [
6299
+ item.icon,
6300
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "sr-only", children: [
6301
+ item.label,
6302
+ item.badge ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
6303
+ ", ",
6304
+ item.badge
6305
+ ] }) : null
6306
+ ] }),
6307
+ item.badge ? /* @__PURE__ */ jsxRuntime.jsx(NavBadge, { badge: item.badge, className: typeof item.badge === "number" ? "-right-1 -top-1" : "right-1 top-1" }) : null
6308
+ ]
6309
+ }
6310
+ ) }),
6311
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { side: "right", children: item.label })
6312
+ ] });
6313
+ }
6314
+ function RailShell({ nav = [], persistent = [], page: pageOverride, header, account, banner, children, className }) {
6315
+ const main = nav.flatMap((g) => g.items);
6316
+ const foot = persistent.flatMap((g) => g.items);
6317
+ warnDuplicateLabels([...nav, ...persistent]);
6318
+ const tabs = tabsFor([{ items: [...main, ...foot] }]);
6319
+ const active = activeItem([...nav, ...persistent]);
6320
+ const place = react.useMemo(() => ({ page: pageOverride ?? active?.label }), [pageOverride, active?.label]);
6321
+ return /* @__PURE__ */ jsxRuntime.jsx(ShellContext.Provider, { value: place, children: /* @__PURE__ */ jsxRuntime.jsx(TooltipProvider, { delayDuration: 300, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex h-dvh flex-col overflow-hidden bg-background", className), children: [
6322
+ header,
6323
+ banner,
6324
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-h-0 flex-1", children: [
6325
+ /* @__PURE__ */ jsxRuntime.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: [
6326
+ main.map((it) => /* @__PURE__ */ jsxRuntime.jsx(RailItem, { item: it }, it.href)),
6327
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-auto flex flex-col items-center gap-1", children: [
6328
+ foot.map((it) => /* @__PURE__ */ jsxRuntime.jsx(RailItem, { item: it }, it.href)),
6329
+ account
6330
+ ] })
6331
+ ] }),
6332
+ /* @__PURE__ */ jsxRuntime.jsx(
6333
+ "main",
6334
+ {
6335
+ id: "main-content",
6336
+ 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))]"),
6337
+ children
6338
+ }
6339
+ )
6340
+ ] }),
6341
+ tabs ? /* @__PURE__ */ jsxRuntime.jsx(TabBar, { items: tabs }) : null
6342
+ ] }) }) });
6343
+ }
6023
6344
  function AccountMenu({
6024
6345
  name,
6025
6346
  detail,
@@ -6420,12 +6741,14 @@ function SignInFrame({
6420
6741
  error,
6421
6742
  fineprint,
6422
6743
  brand,
6423
- home = "/",
6744
+ home,
6745
+ protocol: protocol2,
6424
6746
  back,
6425
6747
  art,
6426
6748
  caption,
6427
6749
  className
6428
6750
  }) {
6751
+ const homeHref = home ?? (protocol2 ? protocolSite(protocol2).pageHref : OCHK_IO);
6429
6752
  return /* @__PURE__ */ jsxRuntime.jsxs(
6430
6753
  "main",
6431
6754
  {
@@ -6434,14 +6757,14 @@ function SignInFrame({
6434
6757
  children: [
6435
6758
  /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "flex flex-col px-4 pb-8 pt-5 sm:px-8 lg:px-14 lg:pt-8", children: [
6436
6759
  /* @__PURE__ */ jsxRuntime.jsxs("header", { className: "flex items-center justify-between gap-4", children: [
6437
- /* @__PURE__ */ jsxRuntime.jsxs(Link6__default.default, { href: home, className: "w-fit rounded-lg", children: [
6760
+ /* @__PURE__ */ jsxRuntime.jsxs(Link6__default.default, { href: homeHref, className: "w-fit rounded-lg", children: [
6438
6761
  brand ?? /* @__PURE__ */ jsxRuntime.jsx(Lockup, { size: 28 }),
6439
6762
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: " home" })
6440
6763
  ] }),
6441
6764
  back === void 0 ? /* @__PURE__ */ jsxRuntime.jsx(
6442
6765
  Link6__default.default,
6443
6766
  {
6444
- href: home,
6767
+ href: homeHref,
6445
6768
  className: "text-[0.9375rem] text-muted-foreground underline-offset-4 hover:text-foreground hover:underline",
6446
6769
  children: "Back to home"
6447
6770
  }
@@ -6690,6 +7013,7 @@ function ToolShell({
6690
7013
  children
6691
7014
  }) {
6692
7015
  const p = protocolSite(protocol2);
7016
+ const homeHref = home ?? p.pageHref;
6693
7017
  const app = variant === "app";
6694
7018
  const tabs = app ? null : tabsFor([{ items: [...tools] }]);
6695
7019
  const about = /* @__PURE__ */ jsxRuntime.jsxs(
@@ -6719,7 +7043,7 @@ function ToolShell({
6719
7043
  SiteHeader,
6720
7044
  {
6721
7045
  variant: "tool",
6722
- home: home ?? p.pageHref,
7046
+ home: homeHref,
6723
7047
  product: p.label,
6724
7048
  family: protocol2,
6725
7049
  nav: tools.map((t) => ({ href: t.href, label: t.label, active: t.active })),
@@ -6744,7 +7068,7 @@ function ToolShell({
6744
7068
  {
6745
7069
  id: "main-content",
6746
7070
  className: cn("min-w-0 flex-1", app ? "flex min-h-0 flex-col" : "px-4 pb-16 pt-8 md:px-8 md:pt-10"),
6747
- children: app ? children : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-auto w-full max-w-[72rem]", children })
7071
+ children: /* @__PURE__ */ jsxRuntime.jsx(SiteHomeContext.Provider, { value: homeHref, children: app ? children : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-auto w-full max-w-[72rem]", children }) })
6748
7072
  }
6749
7073
  )
6750
7074
  ] }),
@@ -6961,9 +7285,11 @@ exports.Checkbox = Checkbox;
6961
7285
  exports.Closing = Closing;
6962
7286
  exports.CodeBlock = CodeBlock;
6963
7287
  exports.CodeTabs = CodeTabs;
7288
+ exports.CommandDialog = CommandDialog;
6964
7289
  exports.ComparisonTable = ComparisonTable;
6965
7290
  exports.Container = Container;
6966
7291
  exports.CopyButton = CopyButton;
7292
+ exports.CountdownRing = CountdownRing;
6967
7293
  exports.Crowd = Crowd;
6968
7294
  exports.DOCS_HEADER_NAV = DOCS_HEADER_NAV;
6969
7295
  exports.DOCS_HREF = DOCS_HREF;
@@ -7025,6 +7351,7 @@ exports.Lead = Lead;
7025
7351
  exports.LegalDocument = LegalDocument;
7026
7352
  exports.LinkCard = LinkCard;
7027
7353
  exports.LoadingBlock = LoadingBlock;
7354
+ exports.LockedPreview = LockedPreview;
7028
7355
  exports.Lockup = Lockup;
7029
7356
  exports.MARK_FACES = MARK_FACES;
7030
7357
  exports.Mark = Mark;
@@ -7045,6 +7372,7 @@ exports.PageHeader = PageHeader;
7045
7372
  exports.PageHero = PageHero;
7046
7373
  exports.Pagination = Pagination;
7047
7374
  exports.PhoneFrame = PhoneFrame;
7375
+ exports.PlanCard = PlanCard;
7048
7376
  exports.Popover = Popover;
7049
7377
  exports.PopoverAnchor = PopoverAnchor;
7050
7378
  exports.PopoverContent = PopoverContent;