@orangecheck/app-design 1.3.0 → 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/dist/chrome.d.mts +11 -5
  2. package/dist/chrome.d.ts +11 -5
  3. package/dist/chrome.js +985 -952
  4. package/dist/chrome.js.map +1 -1
  5. package/dist/chrome.mjs +986 -954
  6. package/dist/chrome.mjs.map +1 -1
  7. package/dist/code.js +3 -1
  8. package/dist/code.js.map +1 -1
  9. package/dist/code.mjs +3 -1
  10. package/dist/code.mjs.map +1 -1
  11. package/dist/components.d.mts +7 -5
  12. package/dist/components.d.ts +7 -5
  13. package/dist/components.js +697 -617
  14. package/dist/components.js.map +1 -1
  15. package/dist/components.mjs +697 -617
  16. package/dist/components.mjs.map +1 -1
  17. package/dist/{docs-Dxg4Tp_q.d.ts → docs-ByUx4t-D.d.ts} +19 -4
  18. package/dist/{docs-wJBfLS08.d.mts → docs-CFE5mU_6.d.mts} +19 -4
  19. package/dist/index.d.mts +3 -3
  20. package/dist/index.d.ts +3 -3
  21. package/dist/index.js +1665 -1519
  22. package/dist/index.js.map +1 -1
  23. package/dist/index.mjs +1665 -1520
  24. package/dist/index.mjs.map +1 -1
  25. package/dist/mdx.d.mts +6 -2
  26. package/dist/mdx.d.ts +6 -2
  27. package/dist/mdx.js +175 -76
  28. package/dist/mdx.js.map +1 -1
  29. package/dist/mdx.mjs +176 -77
  30. package/dist/mdx.mjs.map +1 -1
  31. package/dist/primitives.d.mts +3 -3
  32. package/dist/primitives.d.ts +3 -3
  33. package/dist/primitives.js +10 -1
  34. package/dist/primitives.js.map +1 -1
  35. package/dist/primitives.mjs +10 -1
  36. package/dist/primitives.mjs.map +1 -1
  37. package/dist/session.d.mts +2 -2
  38. package/dist/session.d.ts +2 -2
  39. package/dist/session.js +1 -1
  40. package/dist/session.js.map +1 -1
  41. package/dist/session.mjs +1 -1
  42. package/dist/session.mjs.map +1 -1
  43. package/dist/styles/swagger.css +252 -0
  44. package/dist/styles/tokens.css +2 -0
  45. package/dist/{tool-shell-zncroOEQ.d.mts → tool-shell-D8Q8XX11.d.mts} +3 -2
  46. package/dist/{tool-shell-Be4Q0cNN.d.ts → tool-shell-gmlj47Ie.d.ts} +3 -2
  47. 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');
@@ -20,9 +21,8 @@ var PopoverPrimitive = require('@radix-ui/react-popover');
20
21
  var TooltipPrimitive = require('@radix-ui/react-tooltip');
21
22
  var TabsPrimitive = require('@radix-ui/react-tabs');
22
23
  var QRCode = require('qrcode');
23
- var Link8 = require('next/link');
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
 
@@ -56,7 +56,7 @@ var PopoverPrimitive__namespace = /*#__PURE__*/_interopNamespace(PopoverPrimitiv
56
56
  var TooltipPrimitive__namespace = /*#__PURE__*/_interopNamespace(TooltipPrimitive);
57
57
  var TabsPrimitive__namespace = /*#__PURE__*/_interopNamespace(TabsPrimitive);
58
58
  var QRCode__default = /*#__PURE__*/_interopDefault(QRCode);
59
- var Link8__default = /*#__PURE__*/_interopDefault(Link8);
59
+ var Link6__default = /*#__PURE__*/_interopDefault(Link6);
60
60
 
61
61
  // src/tokens/index.ts
62
62
  var APP_ATTRIBUTE = "data-oc-app";
@@ -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: {
@@ -3006,11 +3014,13 @@ function forClipboard(text, lang) {
3006
3014
  if (!lines.some((l) => l.startsWith("$ "))) return text;
3007
3015
  return lines.filter((l) => l.startsWith("$ ")).map((l) => l.slice(2)).join("\n");
3008
3016
  }
3009
- function linesFromDom(pre) {
3017
+ function linesFromDom(pre, newline) {
3010
3018
  if (!pre) return null;
3011
3019
  const lines = pre.querySelectorAll("[data-line]");
3012
3020
  if (lines.length === 0) return pre.textContent ?? "";
3013
- return Array.from(lines).filter((l) => l.getAttribute("data-diff") !== "remove").map((l) => l.textContent ?? "").join("\n");
3021
+ const text = Array.from(lines).filter((l) => l.getAttribute("data-diff") !== "remove").map((l) => l.textContent ?? "").join("\n");
3022
+ return newline ? `${text}
3023
+ ` : text;
3014
3024
  }
3015
3025
  function prepare(code, lang, marks, diff) {
3016
3026
  const d = diff ? readDiff(code) : null;
@@ -3019,7 +3029,8 @@ function prepare(code, lang, marks, diff) {
3019
3029
  const kept = d ? src.split("\n").filter((_, i) => d.diff.get(i + 1) !== "remove") : null;
3020
3030
  return {
3021
3031
  html: linesToHtml(lines, { highlight: parseLineRanges(marks), diff: d?.diff }),
3022
- copy: kept ? kept.join("\n") : src,
3032
+ // Byte for byte, the final newline too: a hash printed beside the code must match a copy of it.
3033
+ copy: kept ? kept.join("\n") + (/\n$/.test(code) ? "\n" : "") : code,
3023
3034
  lines: lines.length,
3024
3035
  diff: !!d
3025
3036
  };
@@ -3032,7 +3043,8 @@ function Well({
3032
3043
  lines,
3033
3044
  maxLines,
3034
3045
  diff,
3035
- lineNumbers
3046
+ lineNumbers,
3047
+ wrap
3036
3048
  }) {
3037
3049
  const foldable = maxLines !== void 0 && lines > maxLines + 2;
3038
3050
  const [open, setOpen] = react.useState(false);
@@ -3051,7 +3063,8 @@ function Well({
3051
3063
  "data-diff": diff ? "" : void 0,
3052
3064
  "data-line-numbers": lineNumbers ? "" : void 0,
3053
3065
  className: cn(
3054
- "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]",
3066
+ "oca-code py-4 font-mono text-[0.875rem] leading-[1.625] text-oca-ink-muted [font-variant-ligatures:none]",
3067
+ wrap ? "whitespace-pre-wrap break-all" : "w-max min-w-full",
3055
3068
  !lined && "px-5"
3056
3069
  ),
3057
3070
  children: lined ? /* @__PURE__ */ jsxRuntime.jsx("code", { className: "block", "data-lang": lang, dangerouslySetInnerHTML: { __html: html } }) : /* @__PURE__ */ jsxRuntime.jsx("code", { className: "block", "data-lang": lang, children })
@@ -3084,6 +3097,7 @@ function CodeBlock({
3084
3097
  code,
3085
3098
  html,
3086
3099
  children,
3100
+ trailingNewline = false,
3087
3101
  lang,
3088
3102
  caption,
3089
3103
  copy = true,
@@ -3092,6 +3106,7 @@ function CodeBlock({
3092
3106
  highlight: marks,
3093
3107
  diff,
3094
3108
  lineNumbers,
3109
+ wrap,
3095
3110
  actions,
3096
3111
  className
3097
3112
  }) {
@@ -3104,7 +3119,7 @@ function CodeBlock({
3104
3119
  );
3105
3120
  const markup = prepared?.html ?? html;
3106
3121
  const lines = prepared?.lines ?? (html !== void 0 ? html.split("\n").length : code?.split("\n").length ?? 0);
3107
- const read = () => forClipboard(prepared?.copy ?? linesFromDom(preRef.current) ?? code ?? "", lang);
3122
+ const read = () => forClipboard(prepared?.copy ?? linesFromDom(preRef.current, trailingNewline) ?? code ?? "", lang);
3108
3123
  return /* @__PURE__ */ jsxRuntime.jsxs("figure", { className: cn(FRAME, className), children: [
3109
3124
  /* @__PURE__ */ jsxRuntime.jsxs("figcaption", { className: "flex h-11 items-center justify-between gap-3 border-b border-[var(--oca-code-line)] pl-5 pr-2", children: [
3110
3125
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-[0.8125rem] text-oca-ink-subtle", children: caption ?? languageName(lang) ?? "Code" }),
@@ -3123,6 +3138,7 @@ function CodeBlock({
3123
3138
  maxLines,
3124
3139
  diff: prepared ? prepared.diff : isDiff,
3125
3140
  lineNumbers,
3141
+ wrap,
3126
3142
  children
3127
3143
  }
3128
3144
  )
@@ -3587,6 +3603,169 @@ var ErrorBoundary = class extends react.Component {
3587
3603
  ) });
3588
3604
  }
3589
3605
  };
3606
+
3607
+ // src/family/index.ts
3608
+ var OCHK_IO = "https://ochk.io";
3609
+ var DOCS_HREF = `${OCHK_IO}/docs`;
3610
+ function protocol(slug, verb, line, kinds) {
3611
+ return {
3612
+ slug,
3613
+ label: slug,
3614
+ href: `${OCHK_IO}/${slug}`,
3615
+ group: "protocol",
3616
+ line,
3617
+ status: "live",
3618
+ verb,
3619
+ pageHref: `${OCHK_IO}/${slug}`,
3620
+ toolHref: `https://${slug}.ochk.io`,
3621
+ specHref: `https://github.com/orangecheck/oc-${slug}-protocol`,
3622
+ kinds
3623
+ };
3624
+ }
3625
+ var PROTOCOLS = [
3626
+ protocol("attest", "identity", "Show that an address holds bitcoin, and for how long.", "30078"),
3627
+ protocol("lock", "confidentiality", "Encrypt to a Bitcoin address, so only its holder can open it.", "30078"),
3628
+ protocol("vote", "legitimacy", "Polls weighed in sats, that anyone can tally.", "30080\u201330082"),
3629
+ protocol("stamp", "provenance", "Prove who signed something, and when.", "30083"),
3630
+ protocol("agent", "authority", "Give software scoped, revocable permission to act for you.", "30083\u201330086"),
3631
+ protocol("pledge", "commitment", "Make a promise with bitcoin behind it, on a public record.", "30078")
3632
+ ];
3633
+ var PROTOCOL_ORDER = PROTOCOLS.map((p) => p.slug);
3634
+ var FAMILY = [
3635
+ {
3636
+ slug: "home",
3637
+ label: "ochk.io",
3638
+ href: OCHK_IO,
3639
+ group: "orangecheck",
3640
+ line: "The open protocols, and the company behind them.",
3641
+ status: "live"
3642
+ },
3643
+ {
3644
+ slug: "me",
3645
+ label: "ochk.app",
3646
+ href: "https://ochk.app",
3647
+ group: "orangecheck",
3648
+ line: "One account, with Bitcoin behind it.",
3649
+ status: "testing"
3650
+ },
3651
+ {
3652
+ slug: "docs",
3653
+ label: "docs",
3654
+ href: DOCS_HREF,
3655
+ group: "orangecheck",
3656
+ line: "Specs, SDKs and guides for every protocol.",
3657
+ status: "live"
3658
+ },
3659
+ ...PROTOCOLS,
3660
+ {
3661
+ slug: "vault",
3662
+ label: "vault",
3663
+ href: "https://vault.ochk.io",
3664
+ group: "app",
3665
+ line: "A password manager, encrypted in your browser.",
3666
+ status: "live",
3667
+ protocols: ["lock"]
3668
+ },
3669
+ {
3670
+ slug: "chat",
3671
+ label: "chat",
3672
+ href: "https://chat.ochk.io",
3673
+ group: "app",
3674
+ line: "Messages only the holder of a Bitcoin address can read.",
3675
+ status: "testing",
3676
+ protocols: ["lock"]
3677
+ },
3678
+ {
3679
+ slug: "cosign",
3680
+ label: "cosign",
3681
+ href: "https://cosign.ochk.io",
3682
+ group: "app",
3683
+ line: "Builders find co-founders and backers.",
3684
+ status: "testing",
3685
+ // Signs in with an orangecheck account and a wallet; uses none of the six directly.
3686
+ protocols: []
3687
+ },
3688
+ {
3689
+ slug: "me-demo",
3690
+ // "demo", not the made-up app's own name, so nobody takes it for ours.
3691
+ label: "demo",
3692
+ href: "https://me-demo.ochk.io",
3693
+ group: "app",
3694
+ line: "Lumen Notes, a made-up app that signs in with orangecheck.",
3695
+ status: "live"
3696
+ },
3697
+ {
3698
+ slug: "globe",
3699
+ label: "globe",
3700
+ href: "https://globe.ochk.io",
3701
+ group: "public-good",
3702
+ line: "The Bitcoin network, live, on a globe.",
3703
+ status: "live"
3704
+ },
3705
+ {
3706
+ slug: "btc",
3707
+ label: "btc",
3708
+ href: "https://btc.ochk.io",
3709
+ group: "public-good",
3710
+ line: "A free desk for reading the Bitcoin market.",
3711
+ status: "live"
3712
+ }
3713
+ ];
3714
+ var FAMILY_GROUPS = [
3715
+ { id: "orangecheck", label: "orangecheck" },
3716
+ { id: "protocol", label: "Protocols" },
3717
+ { id: "app", label: "Apps" },
3718
+ { id: "public-good", label: "Public goods" }
3719
+ ];
3720
+ var BY_SLUG = new Map(FAMILY.map((s) => [s.slug, s]));
3721
+ function familySite(slug) {
3722
+ return BY_SLUG.get(slug);
3723
+ }
3724
+ function protocolSite(slug) {
3725
+ return BY_SLUG.get(slug);
3726
+ }
3727
+ function familyByGroup() {
3728
+ return FAMILY_GROUPS.map((g) => ({ ...g, sites: FAMILY.filter((s) => s.group === g.id) }));
3729
+ }
3730
+ var LEGAL_LINKS = [
3731
+ { href: `${OCHK_IO}/privacy`, label: "Privacy" },
3732
+ { href: `${OCHK_IO}/terms`, label: "Terms" },
3733
+ { href: `${OCHK_IO}/security`, label: "Security" },
3734
+ { href: `${OCHK_IO}/trademark`, label: "Trademarks" },
3735
+ { href: `${OCHK_IO}/contact`, label: "Contact" }
3736
+ ];
3737
+ var SELF_HOSTED_LEGAL_LINKS = [
3738
+ { href: "/privacy", label: "Privacy" },
3739
+ { href: "/terms", label: "Terms" },
3740
+ { href: "/security", label: "Security" },
3741
+ { href: `${OCHK_IO}/trademark`, label: "Trademarks" },
3742
+ { href: "/contact", label: "Contact" }
3743
+ ];
3744
+ var OCHK_IO_NAV = [
3745
+ {
3746
+ href: `${OCHK_IO}/protocols`,
3747
+ label: "Protocols",
3748
+ children: PROTOCOLS.map((p) => ({ href: p.pageHref, label: p.label, description: p.line }))
3749
+ },
3750
+ { href: `${OCHK_IO}/apps`, label: "Apps" },
3751
+ { href: DOCS_HREF, label: "Docs" },
3752
+ { href: `${OCHK_IO}/trust`, label: "Trust" },
3753
+ { href: `${OCHK_IO}/about`, label: "About" }
3754
+ ];
3755
+ var OCHK_IO_FOOTER = [
3756
+ {
3757
+ heading: "Company",
3758
+ links: [
3759
+ { href: `${OCHK_IO}/about`, label: "About" },
3760
+ { href: `${OCHK_IO}/trust`, label: "Trust" },
3761
+ { href: "https://github.com/orangecheck", label: "GitHub", external: true }
3762
+ ]
3763
+ }
3764
+ ];
3765
+ var SiteHomeContext = sharedContext("site-home", void 0);
3766
+ function useSiteHome() {
3767
+ return react.useContext(SiteHomeContext);
3768
+ }
3590
3769
  var WORDS = {
3591
3770
  404: {
3592
3771
  name: "Not found",
@@ -3604,10 +3783,13 @@ function ErrorPage({
3604
3783
  title,
3605
3784
  detail,
3606
3785
  actions,
3607
- home = "/",
3786
+ home,
3787
+ protocol: protocol2,
3608
3788
  art,
3609
3789
  className
3610
3790
  }) {
3791
+ const shellHome = useSiteHome();
3792
+ const homeHref = home ?? (protocol2 ? protocolSite(protocol2).pageHref : shellHome ?? OCHK_IO);
3611
3793
  const words = WORDS[code] ?? (code >= 500 ? WORDS[500] : WORDS[404]);
3612
3794
  const server = code >= 500;
3613
3795
  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: [
@@ -3621,7 +3803,7 @@ function ErrorPage({
3621
3803
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "oca-lead oca-enter [--enter-delay:150ms]", children: detail ?? words.detail }),
3622
3804
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "oca-enter flex flex-wrap gap-3 [--enter-delay:230ms]", children: actions ?? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3623
3805
  server ? /* @__PURE__ */ jsxRuntime.jsx(Button, { onClick: () => window.location.reload(), children: "Try again" }) : null,
3624
- /* @__PURE__ */ jsxRuntime.jsx(Button, { asChild: true, variant: server ? "secondary" : "primary", children: /* @__PURE__ */ jsxRuntime.jsx(Link8__default.default, { href: home, children: "Go home" }) })
3806
+ /* @__PURE__ */ jsxRuntime.jsx(Button, { asChild: true, variant: server ? "secondary" : "primary", children: /* @__PURE__ */ jsxRuntime.jsx(Link6__default.default, { href: homeHref, children: "Go home" }) })
3625
3807
  ] }) })
3626
3808
  ] }),
3627
3809
  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
@@ -3740,16 +3922,25 @@ function Faq({
3740
3922
  return /* @__PURE__ */ jsxRuntime.jsx(Accordion, { single: true, className, children: items.map((it, i) => /* @__PURE__ */ jsxRuntime.jsx(AccordionItem, { id: it.id, title: it.q, children: it.a }, it.id ?? i)) });
3741
3923
  }
3742
3924
  var LINK = "text-foreground underline decoration-foreground/35 underline-offset-4 transition-colors hover:decoration-foreground";
3925
+ var SCHEME = /^[a-z][a-z\d+.-]*:/i;
3926
+ function useResolved(href) {
3927
+ const router$1 = router.useRouter();
3928
+ if (!router$1 || !href || href.startsWith("/") || href.startsWith("#") || href.startsWith("?") || SCHEME.test(href)) return href;
3929
+ const here = router$1.asPath.split(/[?#]/)[0] || "/";
3930
+ const url = new URL(href, `https://page.invalid${here}`);
3931
+ return url.pathname + url.search + url.hash;
3932
+ }
3743
3933
  function TextLink({
3744
- href,
3934
+ href: written,
3745
3935
  children,
3746
3936
  external,
3747
3937
  className
3748
3938
  }) {
3939
+ const href = useResolved(written);
3749
3940
  const internal = href.startsWith("/") && !href.startsWith("/api/") && !href.startsWith("/.well-known/");
3750
3941
  const offsite = external ?? /^https?:\/\//.test(href);
3751
3942
  if (internal && !offsite) {
3752
- return /* @__PURE__ */ jsxRuntime.jsx(Link8__default.default, { href, className: cn(LINK, className), children });
3943
+ return /* @__PURE__ */ jsxRuntime.jsx(Link6__default.default, { href, className: cn(LINK, className), children });
3753
3944
  }
3754
3945
  return /* @__PURE__ */ jsxRuntime.jsxs("a", { href, className: cn(LINK, className), ...offsite ? { target: "_blank", rel: "noreferrer" } : {}, children: [
3755
3946
  children,
@@ -3858,165 +4049,10 @@ function LegalDocument({ doc, className }) {
3858
4049
  }
3859
4050
  );
3860
4051
  }
3861
-
3862
- // src/family/index.ts
3863
- var OCHK_IO = "https://ochk.io";
3864
- var DOCS_HREF = `${OCHK_IO}/docs`;
3865
- function protocol(slug, verb, line, kinds) {
3866
- return {
3867
- slug,
3868
- label: slug,
3869
- href: `${OCHK_IO}/${slug}`,
3870
- group: "protocol",
3871
- line,
3872
- status: "live",
3873
- verb,
3874
- pageHref: `${OCHK_IO}/${slug}`,
3875
- toolHref: `https://${slug}.ochk.io`,
3876
- specHref: `https://github.com/orangecheck/oc-${slug}-protocol`,
3877
- kinds
3878
- };
4052
+ var InDocsContext = sharedContext("in-docs", false);
4053
+ function useInDocs() {
4054
+ return react.useContext(InDocsContext);
3879
4055
  }
3880
- var PROTOCOLS = [
3881
- protocol("attest", "identity", "Show that an address holds bitcoin, and for how long.", "30078"),
3882
- protocol("lock", "confidentiality", "Encrypt to a Bitcoin address, so only its holder can open it.", "30078"),
3883
- protocol("vote", "legitimacy", "Polls weighed in sats, that anyone can tally.", "30080\u201330082"),
3884
- protocol("stamp", "provenance", "Prove who signed something, and when.", "30083"),
3885
- protocol("agent", "authority", "Give software scoped, revocable permission to act for you.", "30083\u201330086"),
3886
- protocol("pledge", "commitment", "Make a promise with bitcoin behind it, on a public record.", "30078")
3887
- ];
3888
- var PROTOCOL_ORDER = PROTOCOLS.map((p) => p.slug);
3889
- var FAMILY = [
3890
- {
3891
- slug: "home",
3892
- label: "ochk.io",
3893
- href: OCHK_IO,
3894
- group: "orangecheck",
3895
- line: "The open protocols, and the company behind them.",
3896
- status: "live"
3897
- },
3898
- {
3899
- slug: "me",
3900
- label: "ochk.app",
3901
- href: "https://ochk.app",
3902
- group: "orangecheck",
3903
- line: "One account, with Bitcoin behind it.",
3904
- status: "testing"
3905
- },
3906
- {
3907
- slug: "docs",
3908
- label: "docs",
3909
- href: DOCS_HREF,
3910
- group: "orangecheck",
3911
- line: "Specs, SDKs and guides for every protocol.",
3912
- status: "live"
3913
- },
3914
- ...PROTOCOLS,
3915
- {
3916
- slug: "vault",
3917
- label: "vault",
3918
- href: "https://vault.ochk.io",
3919
- group: "app",
3920
- line: "A password manager, encrypted in your browser.",
3921
- status: "live",
3922
- protocols: ["lock"]
3923
- },
3924
- {
3925
- slug: "chat",
3926
- label: "chat",
3927
- href: "https://chat.ochk.io",
3928
- group: "app",
3929
- line: "Messages only the holder of a Bitcoin address can read.",
3930
- status: "testing",
3931
- protocols: ["lock"]
3932
- },
3933
- {
3934
- slug: "cosign",
3935
- label: "cosign",
3936
- href: "https://cosign.ochk.io",
3937
- group: "app",
3938
- line: "Builders find co-founders and backers.",
3939
- status: "testing",
3940
- // Signs in with an orangecheck account and a wallet; uses none of the six directly.
3941
- protocols: []
3942
- },
3943
- {
3944
- slug: "me-demo",
3945
- // "demo", not the made-up app's own name, so nobody takes it for ours.
3946
- label: "demo",
3947
- href: "https://me-demo.ochk.io",
3948
- group: "app",
3949
- line: "Lumen Notes, a made-up app that signs in with orangecheck.",
3950
- status: "live"
3951
- },
3952
- {
3953
- slug: "globe",
3954
- label: "globe",
3955
- href: "https://globe.ochk.io",
3956
- group: "public-good",
3957
- line: "The Bitcoin network, live, on a globe.",
3958
- status: "live"
3959
- },
3960
- {
3961
- slug: "btc",
3962
- label: "btc",
3963
- href: "https://btc.ochk.io",
3964
- group: "public-good",
3965
- line: "A free desk for reading the Bitcoin market.",
3966
- status: "live"
3967
- }
3968
- ];
3969
- var FAMILY_GROUPS = [
3970
- { id: "orangecheck", label: "orangecheck" },
3971
- { id: "protocol", label: "Protocols" },
3972
- { id: "app", label: "Apps" },
3973
- { id: "public-good", label: "Public goods" }
3974
- ];
3975
- var BY_SLUG = new Map(FAMILY.map((s) => [s.slug, s]));
3976
- function familySite(slug) {
3977
- return BY_SLUG.get(slug);
3978
- }
3979
- function protocolSite(slug) {
3980
- return BY_SLUG.get(slug);
3981
- }
3982
- function familyByGroup() {
3983
- return FAMILY_GROUPS.map((g) => ({ ...g, sites: FAMILY.filter((s) => s.group === g.id) }));
3984
- }
3985
- var LEGAL_LINKS = [
3986
- { href: `${OCHK_IO}/privacy`, label: "Privacy" },
3987
- { href: `${OCHK_IO}/terms`, label: "Terms" },
3988
- { href: `${OCHK_IO}/security`, label: "Security" },
3989
- { href: `${OCHK_IO}/trademark`, label: "Trademarks" },
3990
- { href: `${OCHK_IO}/contact`, label: "Contact" }
3991
- ];
3992
- var SELF_HOSTED_LEGAL_LINKS = [
3993
- { href: "/privacy", label: "Privacy" },
3994
- { href: "/terms", label: "Terms" },
3995
- { href: "/security", label: "Security" },
3996
- { href: `${OCHK_IO}/trademark`, label: "Trademarks" },
3997
- { href: "/contact", label: "Contact" }
3998
- ];
3999
- var OCHK_IO_NAV = [
4000
- {
4001
- href: `${OCHK_IO}/protocols`,
4002
- label: "Protocols",
4003
- children: PROTOCOLS.map((p) => ({ href: p.pageHref, label: p.label, description: p.line }))
4004
- },
4005
- { href: `${OCHK_IO}/apps`, label: "Apps" },
4006
- { href: DOCS_HREF, label: "Docs" },
4007
- { href: `${OCHK_IO}/trust`, label: "Trust" },
4008
- { href: `${OCHK_IO}/about`, label: "About" }
4009
- ];
4010
- var OCHK_IO_FOOTER = [
4011
- {
4012
- heading: "Company",
4013
- links: [
4014
- { href: `${OCHK_IO}/about`, label: "About" },
4015
- { href: `${OCHK_IO}/trust`, label: "Trust" },
4016
- { href: "https://github.com/orangecheck", label: "GitHub", external: true }
4017
- ]
4018
- }
4019
- ];
4020
4056
  var CARD = "group relative flex h-full flex-col rounded-[1.25rem] border border-border bg-card p-6 transition-colors hover:border-oca-hairline-strong md:p-7 has-[a:focus-visible]:ring-2 has-[a:focus-visible]:ring-ring has-[a:focus-visible]:ring-offset-2 has-[a:focus-visible]:ring-offset-background";
4021
4057
  var STRETCH = 'outline-none after:absolute after:inset-0 after:rounded-[1.25rem] after:content-[""]';
4022
4058
  var pad2 = (n) => String(n + 1).padStart(2, "0");
@@ -4025,6 +4061,7 @@ function ProtocolGrid({
4025
4061
  link = "page",
4026
4062
  className
4027
4063
  }) {
4064
+ const inDocs = useInDocs();
4028
4065
  return /* @__PURE__ */ jsxRuntime.jsx("ul", { className: cn("grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 md:gap-5", className), children: protocols.map((slug) => {
4029
4066
  const p = protocolSite(slug);
4030
4067
  const i = PROTOCOL_ORDER.indexOf(slug);
@@ -4037,7 +4074,7 @@ function ProtocolGrid({
4037
4074
  ] }),
4038
4075
  p.status !== "live" ? /* @__PURE__ */ jsxRuntime.jsx(StatusBadge, { status: p.status }) : null
4039
4076
  ] }),
4040
- /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "oca-display-3", children: /* @__PURE__ */ jsxRuntime.jsx(
4077
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "oca-display-3", children: link === "docs" && inDocs ? /* @__PURE__ */ jsxRuntime.jsx(Link6__default.default, { href: `/${p.slug}`, className: STRETCH, children: p.label }) : /* @__PURE__ */ jsxRuntime.jsx(
4041
4078
  "a",
4042
4079
  {
4043
4080
  href: link === "tool" ? p.toolHref : link === "docs" ? `${DOCS_HREF}/${p.slug}` : p.pageHref,
@@ -4095,203 +4132,627 @@ function AppGrid({
4095
4132
  const list = sites ? sites.map((slug) => FAMILY.find((s) => s.slug === slug)).filter((s) => s !== void 0) : FAMILY.filter((s) => s.group === group);
4096
4133
  return /* @__PURE__ */ jsxRuntime.jsx("ul", { className: cn("grid grid-cols-1 gap-4 sm:grid-cols-2 md:gap-5", className), children: list.map((s) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx(AppCard, { name: s.label, line: s.line, href: s.href, protocols: s.protocols, status: s.status }) }, s.slug)) });
4097
4134
  }
4098
- function ProtocolHero({
4099
- protocol: protocol2,
4135
+ var isInternal = (href) => href.startsWith("/") || href.startsWith("#");
4136
+ function DocLink({ href, className, children, ...rest }) {
4137
+ return isInternal(href) ? /* @__PURE__ */ jsxRuntime.jsx(Link6__default.default, { href, className, ...rest, children }) : /* @__PURE__ */ jsxRuntime.jsx("a", { href, className, ...rest, children });
4138
+ }
4139
+ function Breadcrumbs({ items, action, className }) {
4140
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex min-h-11 items-center justify-between gap-4 sm:min-h-0", className), children: [
4141
+ /* @__PURE__ */ jsxRuntime.jsx("nav", { "aria-label": "Breadcrumb", className: "min-w-0", children: /* @__PURE__ */ jsxRuntime.jsx("ol", { className: "flex min-w-0 items-center gap-1.5 text-[0.875rem] text-muted-foreground", children: items.map((c, i) => {
4142
+ const last = i === items.length - 1;
4143
+ return /* @__PURE__ */ jsxRuntime.jsxs("li", { className: cn("flex items-center gap-1.5", last ? "min-w-0" : "shrink-0"), children: [
4144
+ c.href && !last ? /* @__PURE__ */ jsxRuntime.jsx(DocLink, { href: c.href, className: "inline-flex min-h-11 items-center transition-colors hover:text-foreground sm:min-h-0", children: c.label }) : /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-current": last ? "page" : void 0, className: cn("truncate", last && "text-foreground"), children: c.label }),
4145
+ !last ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { "aria-hidden": true, className: "size-3.5 shrink-0 text-oca-subtle" }) : null
4146
+ ] }, i);
4147
+ }) }) }),
4148
+ action ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0 text-[0.875rem]", children: action }) : null
4149
+ ] });
4150
+ }
4151
+ function DocsPager({ prev, next, className }) {
4152
+ if (!prev && !next) return null;
4153
+ const card = (l, dir) => /* @__PURE__ */ jsxRuntime.jsxs(
4154
+ DocLink,
4155
+ {
4156
+ href: l.href,
4157
+ className: cn(
4158
+ "group flex min-h-20 flex-col justify-center gap-1 rounded-2xl border border-border bg-card px-5 py-4 transition-colors hover:border-oca-hairline-strong",
4159
+ dir === "next" && "items-end text-right sm:col-start-2"
4160
+ ),
4161
+ children: [
4162
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-1.5 text-[0.8125rem] text-muted-foreground", children: [
4163
+ dir === "prev" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowLeft, { "aria-hidden": true, className: "size-3.5" }) : null,
4164
+ dir === "prev" ? "Previous" : "Next",
4165
+ l.section ? /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, children: "\xB7" }) : null,
4166
+ l.section ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: l.section }) : null,
4167
+ dir === "next" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowRight, { "aria-hidden": true, className: "size-3.5" }) : null
4168
+ ] }),
4169
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[1rem] font-medium leading-snug text-foreground", children: l.label })
4170
+ ]
4171
+ }
4172
+ );
4173
+ return /* @__PURE__ */ jsxRuntime.jsxs("nav", { "aria-label": "Previous and next page", className: cn("grid grid-cols-1 gap-3 border-t border-border pt-8 sm:grid-cols-2", className), children: [
4174
+ prev ? card(prev, "prev") : null,
4175
+ next ? card(next, "next") : null
4176
+ ] });
4177
+ }
4178
+ function useHeadings(selector = "#docs-content", key) {
4179
+ const [items, setItems] = react.useState([]);
4180
+ react.useEffect(() => {
4181
+ const read = () => {
4182
+ const root = document.querySelector(selector);
4183
+ if (!root) return setItems([]);
4184
+ setItems(
4185
+ Array.from(root.querySelectorAll("h2[id], h3[id]")).map((h) => ({
4186
+ id: h.id,
4187
+ // The anchor link's "#" is not part of the name.
4188
+ label: (h.querySelector("[data-heading-text]") ?? h).textContent?.trim() ?? "",
4189
+ level: h.tagName === "H3" ? 3 : 2
4190
+ }))
4191
+ );
4192
+ };
4193
+ const raf = requestAnimationFrame(read);
4194
+ const t = setTimeout(read, 80);
4195
+ return () => {
4196
+ cancelAnimationFrame(raf);
4197
+ clearTimeout(t);
4198
+ };
4199
+ }, [selector, key]);
4200
+ const activeId = useActiveHeading(items.map((i) => i.id));
4201
+ return { items, activeId };
4202
+ }
4203
+ function OnThisPage({
4204
+ items,
4205
+ activeId,
4206
+ title = "On this page",
4207
+ onNavigate,
4208
+ className
4209
+ }) {
4210
+ const id = react.useId();
4211
+ if (items.length === 0) return null;
4212
+ return (
4213
+ // With no visible title (a folded list under its own summary) the name is still "On this page".
4214
+ /* @__PURE__ */ jsxRuntime.jsxs("nav", { "aria-labelledby": title ? id : void 0, "aria-label": title ? void 0 : "On this page", className, children: [
4215
+ title ? /* @__PURE__ */ jsxRuntime.jsx("p", { id, className: "mb-3 text-[0.875rem] font-medium", children: title }) : null,
4216
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { children: items.map((t) => {
4217
+ const on = t.id === activeId;
4218
+ return /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx(
4219
+ "a",
4220
+ {
4221
+ href: `#${t.id}`,
4222
+ onClick: onNavigate,
4223
+ "aria-current": on ? "location" : void 0,
4224
+ className: cn(
4225
+ "block border-l py-1.5 text-[0.875rem] leading-snug transition-colors",
4226
+ t.level === 3 ? "pl-7" : "pl-4",
4227
+ on ? "border-foreground text-foreground" : "border-border text-muted-foreground hover:text-foreground"
4228
+ ),
4229
+ children: t.label
4230
+ }
4231
+ ) }, t.id);
4232
+ }) })
4233
+ ] })
4234
+ );
4235
+ }
4236
+ var CALLOUT_TONE = { note: "neutral", warning: "brand", danger: "danger" };
4237
+ function Callout({
4238
+ tone = "note",
4100
4239
  title,
4101
- lead,
4102
- actions,
4103
- art,
4104
4240
  children,
4105
4241
  className
4106
4242
  }) {
4107
- const p = protocolSite(protocol2);
4108
4243
  return /* @__PURE__ */ jsxRuntime.jsx(
4109
- PageHero,
4244
+ Notice,
4110
4245
  {
4111
- className,
4112
- eyebrow: `Protocol \xB7 ${p.verb}`,
4246
+ tone: CALLOUT_TONE[tone],
4113
4247
  title,
4114
- lead,
4115
- actions,
4116
- art,
4117
- children: p.status !== "live" || children ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-start gap-4", children: [
4118
- p.status !== "live" ? /* @__PURE__ */ jsxRuntime.jsx(StatusBadge, { status: p.status }) : null,
4119
- children
4120
- ] }) : null
4248
+ role: "note",
4249
+ className: cn("my-6 [&_p]:my-0 [&_p]:text-[0.9375rem] [&_p]:leading-relaxed [&_p+p]:mt-3", className),
4250
+ children
4121
4251
  }
4122
4252
  );
4123
4253
  }
4124
- function ProtocolNav({
4125
- current: current2,
4126
- link = "page",
4127
- className
4128
- }) {
4129
- return /* @__PURE__ */ jsxRuntime.jsx("nav", { "aria-label": "Protocols", className, children: /* @__PURE__ */ jsxRuntime.jsx(ScrollFade, { fade: "var(--background)", children: /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "flex w-max min-w-full items-center gap-6 border-b border-border", children: PROTOCOLS.map((p) => {
4130
- const on = p.slug === current2;
4131
- return /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx(
4132
- "a",
4254
+ function Step({ title, id, children }) {
4255
+ return /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "relative pb-8 pl-11 last:pb-0 [counter-increment:oca-step]", children: [
4256
+ /* @__PURE__ */ jsxRuntime.jsx(
4257
+ "span",
4133
4258
  {
4134
- href: link === "tool" ? p.toolHref : p.pageHref,
4135
- "aria-current": on ? "page" : void 0,
4136
- className: cn(
4137
- "-mb-px inline-flex h-11 items-center border-b-2 text-[0.9375rem] transition-colors",
4138
- on ? "border-foreground text-foreground" : "border-transparent text-muted-foreground hover:text-foreground"
4139
- ),
4140
- children: p.label
4259
+ "aria-hidden": true,
4260
+ className: "absolute left-0 top-0 flex size-7 items-center justify-center rounded-full border border-oca-hairline-strong bg-card text-[0.8125rem] oca-tabular text-foreground before:content-[counter(oca-step)]"
4141
4261
  }
4142
- ) }, p.slug);
4143
- }) }) }) });
4262
+ ),
4263
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: "absolute bottom-1 left-[0.8125rem] top-9 w-px bg-border" }),
4264
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { id, className: "scroll-mt-28 pt-0.5 text-[1.0625rem] font-medium leading-snug tracking-[-0.008em] text-foreground", children: title }),
4265
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2 text-muted-foreground [&>*:first-child]:mt-0 [&>*:last-child]:mb-0", children })
4266
+ ] });
4144
4267
  }
4145
- function SpecCard({
4146
- protocol: protocol2,
4147
- version,
4148
- license,
4149
- vectors,
4150
- size = "md",
4268
+ function Steps({ children, className }) {
4269
+ return /* @__PURE__ */ jsxRuntime.jsx("ol", { className: cn("not-prose my-8 flex flex-col [counter-reset:oca-step] [&>li:last-child>span:nth-child(2)]:hidden", className), children });
4270
+ }
4271
+ function LinkCard({
4272
+ href,
4273
+ title,
4274
+ description,
4275
+ icon,
4276
+ meta,
4151
4277
  className
4152
4278
  }) {
4153
- const p = protocolSite(protocol2);
4154
- const repo = `oc-${p.slug}-protocol`;
4155
- const facts = [
4156
- ["Version", version],
4157
- ...license ? [["Licence", license]] : [],
4158
- ["Nostr kind", p.kinds],
4159
- ...vectors !== void 0 ? [["Test vectors", String(vectors)]] : []
4160
- ];
4161
- if (size === "sm") {
4162
- return /* @__PURE__ */ jsxRuntime.jsxs(
4163
- "a",
4164
- {
4165
- href: p.specHref,
4166
- className: cn(
4167
- "group flex flex-wrap items-center gap-x-4 gap-y-1 rounded-2xl border border-border bg-card px-4 py-3 text-[0.875rem] transition-colors hover:border-oca-hairline-strong",
4168
- className
4169
- ),
4170
- children: [
4171
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono text-[0.8125rem] text-foreground", children: repo }),
4172
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: facts.map(([k, v]) => k === "Version" ? `v${v}` : k === "Nostr kind" ? `kind ${v}` : v).join(" \xB7 ") }),
4173
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "ml-auto flex items-center gap-1 text-muted-foreground group-hover:text-foreground", children: [
4174
- "Read the spec ",
4175
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUpRight, { "aria-hidden": true, className: "size-4" })
4176
- ] })
4177
- ]
4178
- }
4179
- );
4180
- }
4181
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-col gap-6 rounded-[1.25rem] border border-border bg-card p-6 md:p-8", className), children: [
4182
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-4", children: [
4183
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-col gap-1.5", children: [
4184
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[0.875rem] text-muted-foreground", children: "The spec" }),
4185
- /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "oca-title break-all font-mono text-[1.0625rem] tracking-normal", children: repo })
4186
- ] }),
4187
- p.status !== "live" ? /* @__PURE__ */ jsxRuntime.jsx(StatusBadge, { status: p.status }) : null
4188
- ] }),
4189
- /* @__PURE__ */ jsxRuntime.jsx("dl", { className: "grid grid-cols-2 gap-x-6 gap-y-4 sm:grid-cols-4", children: facts.map(([k, v]) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [
4190
- /* @__PURE__ */ jsxRuntime.jsx("dt", { className: "text-[0.8125rem] text-muted-foreground", children: k }),
4191
- /* @__PURE__ */ jsxRuntime.jsx("dd", { className: "oca-tabular text-[1.0625rem]", children: v })
4192
- ] }, k)) }),
4193
- /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(Button, { asChild: true, variant: "secondary", size: "sm", children: /* @__PURE__ */ jsxRuntime.jsxs("a", { href: p.specHref, children: [
4194
- "Read the spec ",
4195
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUpRight, { "aria-hidden": true })
4196
- ] }) }) })
4197
- ] });
4198
- }
4199
- function VerifyBox({
4200
- action,
4201
- param = "q",
4202
- title,
4203
- description,
4204
- label = "Id, envelope or link",
4205
- placeholder,
4206
- hint,
4207
- submitLabel = "Verify",
4208
- multiline = false,
4209
- onVerify,
4210
- className
4211
- }) {
4212
- const [value, setValue] = react.useState("");
4213
- const submit = (e) => {
4214
- if (!onVerify) return;
4215
- e.preventDefault();
4216
- if (value.trim()) onVerify(value.trim());
4217
- };
4218
- const button = /* @__PURE__ */ jsxRuntime.jsx(Button, { type: "submit", className: multiline ? void 0 : "w-full sm:w-auto", children: submitLabel });
4279
+ const Arrow = isInternal(href) ? lucideReact.ArrowRight : lucideReact.ArrowUpRight;
4219
4280
  return /* @__PURE__ */ jsxRuntime.jsxs(
4220
- "form",
4281
+ DocLink,
4221
4282
  {
4222
- action,
4223
- method: "get",
4224
- onSubmit: submit,
4225
- className: cn("flex flex-col gap-5 rounded-[1.25rem] border border-border bg-card p-6 md:p-8", className),
4283
+ href,
4284
+ className: cn(
4285
+ "group flex h-full flex-col gap-3 rounded-[1.25rem] border border-border bg-card p-5 transition-colors hover:border-oca-hairline-strong",
4286
+ className
4287
+ ),
4226
4288
  children: [
4227
- title || description ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
4228
- title ? /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "oca-title", children: title }) : null,
4229
- description ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "oca-body text-[0.9375rem]", children: description }) : null
4230
- ] }) : null,
4231
- multiline ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4232
- /* @__PURE__ */ jsxRuntime.jsx(Field, { label, hint, children: /* @__PURE__ */ jsxRuntime.jsx(
4233
- Textarea,
4234
- {
4235
- name: param,
4236
- required: true,
4237
- value,
4238
- onChange: (e) => setValue(e.target.value),
4239
- placeholder,
4240
- spellCheck: false,
4241
- className: "min-h-32 font-mono text-base md:text-[0.8125rem]"
4242
- }
4243
- ) }),
4244
- /* @__PURE__ */ jsxRuntime.jsx("div", { children: button })
4245
- ] }) : /* @__PURE__ */ jsxRuntime.jsx(Field, { label, hint, action: button, children: /* @__PURE__ */ jsxRuntime.jsx(
4246
- Input,
4247
- {
4248
- name: param,
4249
- required: true,
4250
- value,
4251
- onChange: (e) => setValue(e.target.value),
4252
- placeholder,
4253
- spellCheck: false,
4254
- autoComplete: "off",
4255
- className: "font-mono text-base md:text-[0.875rem]"
4256
- }
4257
- ) })
4289
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-start justify-between gap-3", children: [
4290
+ icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex size-9 shrink-0 items-center justify-center rounded-xl bg-muted text-foreground [&_svg]:size-[1.125rem]", children: icon }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[1rem] font-medium leading-snug text-foreground", children: title }),
4291
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex shrink-0 items-center gap-2", children: [
4292
+ meta,
4293
+ /* @__PURE__ */ jsxRuntime.jsx(Arrow, { "aria-hidden": true, className: "size-4 text-muted-foreground transition-transform group-hover:translate-x-0.5 group-hover:text-foreground" })
4294
+ ] })
4295
+ ] }),
4296
+ icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[1rem] font-medium leading-snug text-foreground", children: title }) : null,
4297
+ description ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[0.9375rem] leading-relaxed text-muted-foreground", children: description }) : null
4258
4298
  ]
4259
4299
  }
4260
4300
  );
4261
4301
  }
4262
- var TINT = "bg-[color-mix(in_oklab,var(--oca-orange)_9%,var(--card))]";
4263
- function ComparisonTable({
4264
- columns,
4302
+ function CardGrid({ columns = 2, children, className }) {
4303
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("not-prose my-6 grid grid-cols-1 gap-3 sm:grid-cols-2", columns === 3 && "lg:grid-cols-3", className), children });
4304
+ }
4305
+ function MdxTable({ className, ...props }) {
4306
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "not-prose my-6 overflow-hidden rounded-2xl border border-border bg-card", children: /* @__PURE__ */ jsxRuntime.jsx(ScrollFade, { fade: "var(--card)", children: /* @__PURE__ */ jsxRuntime.jsx(
4307
+ "table",
4308
+ {
4309
+ className: cn(
4310
+ "w-full border-collapse text-left text-[0.875rem] leading-relaxed",
4311
+ "[&_th]:whitespace-nowrap [&_th]:border-b [&_th]:border-oca-hairline-strong [&_th]:bg-oca-table-head [&_th]:px-4 [&_th]:py-2.5 [&_th]:text-[0.8125rem] [&_th]:font-medium [&_th]:text-foreground",
4312
+ "[&_td]:border-t [&_td]:border-border [&_td]:px-4 [&_td]:py-2.5 [&_td]:align-top [&_td]:text-muted-foreground [&_tbody_tr:first-child_td]:border-t-0",
4313
+ "[&_td_code]:bg-transparent [&_td_code]:p-0 [&_td_code]:text-foreground [&_td:first-child]:text-foreground",
4314
+ "[&_[align=center]]:text-center [&_[align=right]]:text-right",
4315
+ // On a phone a cell keeps a readable width; the table scrolls instead of crushing it.
4316
+ "max-sm:[&_td]:min-w-[9rem]",
4317
+ className
4318
+ ),
4319
+ ...props
4320
+ }
4321
+ ) }) });
4322
+ }
4323
+ var said = (n) => n !== void 0 && n !== null && n !== false && n !== "";
4324
+ function ApiTable({
4265
4325
  rows,
4266
- label,
4267
- propertyHeading = "Property",
4326
+ caption,
4327
+ nameHeader = "Name",
4268
4328
  className
4269
4329
  }) {
4270
- const wide = columns.length > 3;
4271
- const grid = wide ? "lg:grid lg:grid-cols-[var(--oca-compare)]" : "md:grid md:grid-cols-[var(--oca-compare)]";
4272
- const desk = wide ? "lg" : "md";
4273
- const style = {
4274
- // The argued-for column gets a little more room: its answers carry the page.
4275
- "--oca-compare": ["minmax(0, 1.4fr)", ...columns.map((c) => c.highlight ? "minmax(0, 1.3fr)" : "minmax(0, 1fr)")].join(" ")
4330
+ const hasDefault = rows.some((r) => r.default !== void 0);
4331
+ const hasDescription = rows.some((r) => said(r.description));
4332
+ const hasSource = rows.some((r) => said(r.source));
4333
+ const cell = "px-4 py-3 max-sm:p-0";
4334
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("not-prose my-6 overflow-hidden rounded-2xl border border-border bg-card", className), children: /* @__PURE__ */ jsxRuntime.jsx(ScrollFade, { fade: "var(--card)", children: /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "w-full border-collapse text-left text-[0.875rem] max-sm:block", children: [
4335
+ caption ? /* @__PURE__ */ jsxRuntime.jsx("caption", { className: "sr-only", children: caption }) : null,
4336
+ /* @__PURE__ */ jsxRuntime.jsx("thead", { className: "max-sm:sr-only", children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "border-b border-oca-hairline-strong bg-oca-table-head text-[0.8125rem]", children: [
4337
+ /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", className: "px-4 py-2.5 font-medium", children: nameHeader }),
4338
+ /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", className: "px-4 py-2.5 font-medium", children: "Type" }),
4339
+ hasDefault ? /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", className: "px-4 py-2.5 font-medium", children: "Default" }) : null,
4340
+ hasDescription ? /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", className: "px-4 py-2.5 font-medium", children: "Description" }) : null,
4341
+ hasSource ? /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", className: "px-4 py-2.5 font-medium", children: "Defined in" }) : null
4342
+ ] }) }),
4343
+ /* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "divide-y divide-border max-sm:block", children: rows.map((r) => /* @__PURE__ */ jsxRuntime.jsxs(
4344
+ "tr",
4345
+ {
4346
+ id: r.id,
4347
+ className: "scroll-mt-28 align-top target:bg-muted max-sm:flex max-sm:flex-col max-sm:gap-1.5 max-sm:px-4 max-sm:py-3.5",
4348
+ children: [
4349
+ /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "row", className: cn(cell, "text-left font-normal"), children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex flex-col items-start gap-1 max-sm:flex-row max-sm:flex-wrap max-sm:items-baseline max-sm:gap-x-2", children: [
4350
+ /* @__PURE__ */ jsxRuntime.jsx("code", { className: cn("font-mono text-[0.8125rem] text-foreground max-sm:text-[0.875rem]", r.deprecated && "line-through decoration-oca-subtle"), children: r.name }),
4351
+ r.required ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[0.75rem] text-oca-accent-ink", children: "Required" }) : null,
4352
+ r.deprecated ? /* @__PURE__ */ jsxRuntime.jsx(Badge, { tone: "muted", children: "Deprecated" }) : null,
4353
+ r.status ? /* @__PURE__ */ jsxRuntime.jsx(StatusBadge, { status: r.status }) : null
4354
+ ] }) }),
4355
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: cn(cell, "font-mono text-[0.8125rem] text-muted-foreground max-sm:break-all", !said(r.type) && "max-sm:hidden"), children: r.type ?? "\u2014" }),
4356
+ hasDefault ? /* @__PURE__ */ jsxRuntime.jsxs("td", { className: cn(cell, "font-mono text-[0.8125rem] text-muted-foreground max-sm:order-last", r.default === void 0 && "max-sm:hidden"), children: [
4357
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-sans sm:hidden", children: "Default " }),
4358
+ r.default ?? "\u2014"
4359
+ ] }) : null,
4360
+ hasDescription ? /* @__PURE__ */ jsxRuntime.jsx("td", { className: cn(cell, "leading-relaxed text-muted-foreground", !said(r.description) && "max-sm:hidden"), children: r.description }) : null,
4361
+ hasSource ? /* @__PURE__ */ jsxRuntime.jsx("td", { className: cn(cell, "text-[0.8125rem] text-muted-foreground max-sm:order-last max-sm:break-all", !said(r.source) && "max-sm:hidden"), children: r.source }) : null
4362
+ ]
4363
+ },
4364
+ r.id ?? r.name
4365
+ )) })
4366
+ ] }) }) });
4367
+ }
4368
+ function useDarkMode() {
4369
+ const [dark, setDark] = react.useState(false);
4370
+ react.useEffect(() => {
4371
+ const root = document.documentElement;
4372
+ const read = () => setDark(root.classList.contains("dark"));
4373
+ read();
4374
+ const mo = new MutationObserver(read);
4375
+ mo.observe(root, { attributes: true, attributeFilter: ["class"] });
4376
+ return () => mo.disconnect();
4377
+ }, []);
4378
+ return dark;
4379
+ }
4380
+ function mermaidTheme(el) {
4381
+ const css = getComputedStyle(el);
4382
+ const v = (name) => css.getPropertyValue(name).trim();
4383
+ const card = v("--card");
4384
+ const muted = v("--muted");
4385
+ const text = v("--foreground");
4386
+ const subtle = v("--muted-foreground");
4387
+ const line = v("--input");
4388
+ const hair = v("--oca-hairline-strong");
4389
+ return {
4390
+ background: "transparent",
4391
+ fontFamily: css.fontFamily,
4392
+ fontSize: "14px",
4393
+ textColor: text,
4394
+ mainBkg: card,
4395
+ primaryColor: card,
4396
+ primaryTextColor: text,
4397
+ primaryBorderColor: hair,
4398
+ secondaryColor: muted,
4399
+ secondaryTextColor: text,
4400
+ secondaryBorderColor: hair,
4401
+ tertiaryColor: muted,
4402
+ tertiaryTextColor: text,
4403
+ tertiaryBorderColor: hair,
4404
+ nodeBorder: hair,
4405
+ lineColor: line,
4406
+ edgeLabelBackground: card,
4407
+ clusterBkg: muted,
4408
+ clusterBorder: hair,
4409
+ titleColor: text,
4410
+ noteBkgColor: muted,
4411
+ noteTextColor: text,
4412
+ noteBorderColor: hair,
4413
+ actorBkg: card,
4414
+ actorBorder: hair,
4415
+ actorTextColor: text,
4416
+ actorLineColor: line,
4417
+ signalColor: text,
4418
+ signalTextColor: text,
4419
+ labelBoxBkgColor: card,
4420
+ labelBoxBorderColor: hair,
4421
+ labelTextColor: text,
4422
+ loopTextColor: subtle,
4423
+ activationBkgColor: muted,
4424
+ activationBorderColor: hair,
4425
+ sequenceNumberColor: card
4276
4426
  };
4277
- const ordered = [...columns].sort((a, b) => Number(Boolean(b.highlight)) - Number(Boolean(a.highlight)));
4278
- return /* @__PURE__ */ jsxRuntime.jsxs("ul", { "aria-label": label, style, className: cn("divide-y divide-border rounded-[1.25rem] border border-border bg-card", className), children: [
4279
- /* @__PURE__ */ jsxRuntime.jsxs(
4280
- "li",
4427
+ }
4428
+ var FIT = 4 / 3;
4429
+ function naturalSize(svg) {
4430
+ const w = svg.match(/viewBox="[\d.-]+ [\d.-]+ ([\d.]+) [\d.]+"/)?.[1];
4431
+ if (!w) return { svg, width: null };
4432
+ const width = Math.ceil(Number(w));
4433
+ return {
4434
+ svg: svg.replace(/<svg([^>]*?)\swidth="100%"/, `<svg$1 width="${width}"`).replace(/max-width:\s*[\d.]+px;?/, ""),
4435
+ width
4436
+ };
4437
+ }
4438
+ function useInnerWidth(ref, padding) {
4439
+ const [width, setWidth] = react.useState(null);
4440
+ react.useEffect(() => {
4441
+ const el = ref.current;
4442
+ if (!el) return;
4443
+ const ro = new ResizeObserver(() => setWidth(el.clientWidth - padding));
4444
+ ro.observe(el);
4445
+ return () => ro.disconnect();
4446
+ }, [ref, padding]);
4447
+ return width;
4448
+ }
4449
+ function Diagram({ chart, caption, load, className }) {
4450
+ const ref = react.useRef(null);
4451
+ const dark = useDarkMode();
4452
+ const raw = react.useId();
4453
+ const [drawn, setDrawn] = react.useState(null);
4454
+ const [failed, setFailed] = react.useState(false);
4455
+ const room = useInnerWidth(ref, 48);
4456
+ const fits = drawn?.width != null && room != null && drawn.width <= room * FIT;
4457
+ react.useEffect(() => {
4458
+ let live = true;
4459
+ const el = ref.current;
4460
+ if (!el) return;
4461
+ (async () => {
4462
+ try {
4463
+ const mod = await load();
4464
+ const mermaid = "default" in mod ? mod.default : mod;
4465
+ mermaid.initialize({ startOnLoad: false, securityLevel: "strict", theme: "base", themeVariables: mermaidTheme(el) });
4466
+ const { svg } = await mermaid.render(`oca-diagram-${raw.replace(/[^a-zA-Z0-9]/g, "")}-${dark ? "d" : "l"}`, chart);
4467
+ if (live) {
4468
+ setDrawn(naturalSize(svg));
4469
+ setFailed(false);
4470
+ }
4471
+ } catch {
4472
+ if (live) setFailed(true);
4473
+ }
4474
+ })();
4475
+ return () => {
4476
+ live = false;
4477
+ };
4478
+ }, [chart, dark, load, raw]);
4479
+ if (failed) return /* @__PURE__ */ jsxRuntime.jsx(CodeBlock, { code: chart, caption: "Diagram (shown as its source)", className: cn("my-6", className) });
4480
+ return /* @__PURE__ */ jsxRuntime.jsxs("figure", { ref, className: cn("not-prose my-6 overflow-hidden rounded-[1.25rem] border border-border bg-card", className), children: [
4481
+ drawn ? /* @__PURE__ */ jsxRuntime.jsx(ScrollFade, { fade: "var(--card)", children: /* @__PURE__ */ jsxRuntime.jsx(
4482
+ "div",
4281
4483
  {
4282
- "aria-hidden": true,
4484
+ "data-fit": fits ? "" : void 0,
4283
4485
  className: cn(
4284
- "hidden gap-5 px-5 py-4 text-[0.875rem] font-medium text-muted-foreground",
4285
- wide ? "lg:grid lg:px-8" : "md:grid md:px-8",
4286
- grid
4486
+ "flex justify-center p-6 [&_svg]:h-auto",
4487
+ fits ? "w-full [&_svg]:max-w-full" : "w-max min-w-full [&_svg]:max-w-none"
4287
4488
  ),
4288
- children: [
4289
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: propertyHeading }),
4290
- columns.map((c) => /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn(c.highlight && cn(TINT, "-my-4 px-4 py-4 text-oca-accent-ink")), children: c.label }, c.key))
4291
- ]
4489
+ role: "img",
4490
+ "aria-label": typeof caption === "string" ? caption : "Diagram",
4491
+ dangerouslySetInnerHTML: { __html: drawn.svg }
4292
4492
  }
4293
- ),
4294
- rows.map((r, ri) => /* @__PURE__ */ jsxRuntime.jsxs("li", { className: cn("grid grid-cols-1 gap-3 px-5 py-5", wide ? "lg:items-start lg:gap-5 lg:px-8" : "md:items-start md:gap-5 md:px-8", grid), children: [
4493
+ ) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { role: "status", "aria-label": "Drawing the diagram", className: "p-6", children: /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { className: "h-40 w-full rounded-xl" }) }),
4494
+ caption ? /* @__PURE__ */ jsxRuntime.jsx("figcaption", { className: "border-t border-border px-5 py-3 text-[0.8125rem] text-muted-foreground", children: caption }) : null
4495
+ ] });
4496
+ }
4497
+ var HEADING = {
4498
+ h1: "oca-display-3 mb-4 text-foreground",
4499
+ h2: "mb-3 mt-12 text-[1.375rem] font-medium leading-tight tracking-[-0.015em] text-foreground md:text-[1.5rem]",
4500
+ h3: "mb-2 mt-9 text-[1.125rem] font-medium leading-snug tracking-[-0.01em] text-foreground",
4501
+ h4: "mb-2 mt-7 text-[1rem] font-medium leading-snug text-foreground"
4502
+ };
4503
+ function DocsHeading({
4504
+ as: Tag,
4505
+ id,
4506
+ children,
4507
+ className,
4508
+ ...props
4509
+ }) {
4510
+ return /* @__PURE__ */ jsxRuntime.jsxs(Tag, { id, className: cn("group scroll-mt-28", HEADING[Tag], className), ...props, children: [
4511
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "data-heading-text": "", children }),
4512
+ id && Tag !== "h1" ? /* @__PURE__ */ jsxRuntime.jsxs(
4513
+ "a",
4514
+ {
4515
+ href: `#${id}`,
4516
+ className: "ml-2 inline-block rounded-md px-1 align-baseline text-[0.85em] font-normal text-oca-subtle no-underline opacity-0 transition-opacity hover:text-foreground focus-visible:opacity-100 group-hover:opacity-100",
4517
+ children: [
4518
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, children: "#" }),
4519
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Link to this section" })
4520
+ ]
4521
+ }
4522
+ ) : null
4523
+ ] });
4524
+ }
4525
+ function codeText(node) {
4526
+ if (typeof node === "string") return node;
4527
+ if (typeof node === "number") return String(node);
4528
+ if (Array.isArray(node)) return node.map(codeText).join("");
4529
+ if (react.isValidElement(node)) return codeText(node.props.children);
4530
+ return "";
4531
+ }
4532
+ function codeLang(node) {
4533
+ const child = react.Children.toArray(node)[0];
4534
+ if (!react.isValidElement(child)) return void 0;
4535
+ const cls = child.props.className ?? "";
4536
+ return cls.match(/language-([\w+-]+)/)?.[1];
4537
+ }
4538
+ function ProtocolHero({
4539
+ protocol: protocol2,
4540
+ title,
4541
+ lead,
4542
+ actions,
4543
+ art,
4544
+ children,
4545
+ className
4546
+ }) {
4547
+ const p = protocolSite(protocol2);
4548
+ return /* @__PURE__ */ jsxRuntime.jsx(
4549
+ PageHero,
4550
+ {
4551
+ className,
4552
+ eyebrow: `Protocol \xB7 ${p.verb}`,
4553
+ title,
4554
+ lead,
4555
+ actions,
4556
+ art,
4557
+ children: p.status !== "live" || children ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-start gap-4", children: [
4558
+ p.status !== "live" ? /* @__PURE__ */ jsxRuntime.jsx(StatusBadge, { status: p.status }) : null,
4559
+ children
4560
+ ] }) : null
4561
+ }
4562
+ );
4563
+ }
4564
+ function ProtocolNav({
4565
+ current: current2,
4566
+ link = "page",
4567
+ className
4568
+ }) {
4569
+ return /* @__PURE__ */ jsxRuntime.jsx("nav", { "aria-label": "Protocols", className, children: /* @__PURE__ */ jsxRuntime.jsx(ScrollFade, { fade: "var(--background)", children: /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "flex w-max min-w-full items-center gap-6 border-b border-border", children: PROTOCOLS.map((p) => {
4570
+ const on = p.slug === current2;
4571
+ return /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx(
4572
+ "a",
4573
+ {
4574
+ href: link === "tool" ? p.toolHref : p.pageHref,
4575
+ "aria-current": on ? "page" : void 0,
4576
+ className: cn(
4577
+ "-mb-px inline-flex h-11 items-center border-b-2 text-[0.9375rem] transition-colors",
4578
+ on ? "border-foreground text-foreground" : "border-transparent text-muted-foreground hover:text-foreground"
4579
+ ),
4580
+ children: p.label
4581
+ }
4582
+ ) }, p.slug);
4583
+ }) }) }) });
4584
+ }
4585
+ var SPEC_FILE = {
4586
+ spec: {
4587
+ file: "SPEC.md",
4588
+ title: "Normative source",
4589
+ note: "This page is a human-readable summary. The authoritative copy lives in the spec repo. If the two ever drift, the repo wins."
4590
+ },
4591
+ security: {
4592
+ file: "SECURITY.md",
4593
+ title: "Normative threat model",
4594
+ note: "This page is the short form. The authoritative, numbered threat model lives in the spec repo."
4595
+ },
4596
+ rationale: {
4597
+ file: "WHY.md",
4598
+ title: "Design rationale",
4599
+ note: "This page is the short version. The full rationale and the rejected-design log live in the spec repo."
4600
+ }
4601
+ };
4602
+ function SpecCard(props) {
4603
+ return props.repo !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(SpecFileNote, { ...props }) : /* @__PURE__ */ jsxRuntime.jsx(ProtocolSpecCard, { ...props });
4604
+ }
4605
+ function SpecFileNote({ repo, file, kind = "spec", version, note, className }) {
4606
+ const d = SPEC_FILE[kind];
4607
+ const f = file ?? d.file;
4608
+ return /* @__PURE__ */ jsxRuntime.jsxs(Callout, { title: version ? `${d.title} \xB7 ${version}` : d.title, className, children: [
4609
+ /* @__PURE__ */ jsxRuntime.jsx("p", { children: note ?? d.note }),
4610
+ /* @__PURE__ */ jsxRuntime.jsx("p", { children: /* @__PURE__ */ jsxRuntime.jsx(TextLink, { href: `https://github.com/orangecheck/${repo}/blob/main/${f}`, className: "break-all font-mono text-[0.875rem]", children: `${repo}/${f}` }) })
4611
+ ] });
4612
+ }
4613
+ function ProtocolSpecCard({ protocol: protocol2, version, license, vectors, size = "md", className }) {
4614
+ const p = protocolSite(protocol2);
4615
+ const repo = `oc-${p.slug}-protocol`;
4616
+ const facts = [
4617
+ ["Version", version],
4618
+ ...license ? [["Licence", license]] : [],
4619
+ ["Nostr kind", p.kinds],
4620
+ ...vectors !== void 0 ? [["Test vectors", String(vectors)]] : []
4621
+ ];
4622
+ if (size === "sm") {
4623
+ return /* @__PURE__ */ jsxRuntime.jsxs(
4624
+ "a",
4625
+ {
4626
+ href: p.specHref,
4627
+ className: cn(
4628
+ "group flex flex-wrap items-center gap-x-4 gap-y-1 rounded-2xl border border-border bg-card px-4 py-3 text-[0.875rem] transition-colors hover:border-oca-hairline-strong",
4629
+ className
4630
+ ),
4631
+ children: [
4632
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono text-[0.8125rem] text-foreground", children: repo }),
4633
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: facts.map(([k, v]) => k === "Version" ? `v${v}` : k === "Nostr kind" ? `kind ${v}` : v).join(" \xB7 ") }),
4634
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "ml-auto flex items-center gap-1 text-muted-foreground group-hover:text-foreground", children: [
4635
+ "Read the spec ",
4636
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUpRight, { "aria-hidden": true, className: "size-4" })
4637
+ ] })
4638
+ ]
4639
+ }
4640
+ );
4641
+ }
4642
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-col gap-6 rounded-[1.25rem] border border-border bg-card p-6 md:p-8", className), children: [
4643
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-4", children: [
4644
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-col gap-1.5", children: [
4645
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[0.875rem] text-muted-foreground", children: "The spec" }),
4646
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "oca-title break-all font-mono text-[1.0625rem] tracking-normal", children: repo })
4647
+ ] }),
4648
+ p.status !== "live" ? /* @__PURE__ */ jsxRuntime.jsx(StatusBadge, { status: p.status }) : null
4649
+ ] }),
4650
+ /* @__PURE__ */ jsxRuntime.jsx("dl", { className: "grid grid-cols-2 gap-x-6 gap-y-4 sm:grid-cols-4", children: facts.map(([k, v]) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [
4651
+ /* @__PURE__ */ jsxRuntime.jsx("dt", { className: "text-[0.8125rem] text-muted-foreground", children: k }),
4652
+ /* @__PURE__ */ jsxRuntime.jsx("dd", { className: "oca-tabular text-[1.0625rem]", children: v })
4653
+ ] }, k)) }),
4654
+ /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(Button, { asChild: true, variant: "secondary", size: "sm", children: /* @__PURE__ */ jsxRuntime.jsxs("a", { href: p.specHref, children: [
4655
+ "Read the spec ",
4656
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUpRight, { "aria-hidden": true })
4657
+ ] }) }) })
4658
+ ] });
4659
+ }
4660
+ function VerifyBox({
4661
+ action,
4662
+ param = "q",
4663
+ title,
4664
+ description,
4665
+ label = "Id, envelope or link",
4666
+ placeholder,
4667
+ hint,
4668
+ submitLabel = "Verify",
4669
+ multiline = false,
4670
+ onVerify,
4671
+ className
4672
+ }) {
4673
+ const [value, setValue] = react.useState("");
4674
+ const submit = (e) => {
4675
+ if (!onVerify) return;
4676
+ e.preventDefault();
4677
+ if (value.trim()) onVerify(value.trim());
4678
+ };
4679
+ const button = /* @__PURE__ */ jsxRuntime.jsx(Button, { type: "submit", className: multiline ? void 0 : "w-full sm:w-auto", children: submitLabel });
4680
+ return /* @__PURE__ */ jsxRuntime.jsxs(
4681
+ "form",
4682
+ {
4683
+ action,
4684
+ method: "get",
4685
+ onSubmit: submit,
4686
+ className: cn("flex flex-col gap-5 rounded-[1.25rem] border border-border bg-card p-6 md:p-8", className),
4687
+ children: [
4688
+ title || description ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
4689
+ title ? /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "oca-title", children: title }) : null,
4690
+ description ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "oca-body text-[0.9375rem]", children: description }) : null
4691
+ ] }) : null,
4692
+ multiline ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4693
+ /* @__PURE__ */ jsxRuntime.jsx(Field, { label, hint, children: /* @__PURE__ */ jsxRuntime.jsx(
4694
+ Textarea,
4695
+ {
4696
+ name: param,
4697
+ required: true,
4698
+ value,
4699
+ onChange: (e) => setValue(e.target.value),
4700
+ placeholder,
4701
+ spellCheck: false,
4702
+ className: "min-h-32 font-mono text-base md:text-[0.8125rem]"
4703
+ }
4704
+ ) }),
4705
+ /* @__PURE__ */ jsxRuntime.jsx("div", { children: button })
4706
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx(Field, { label, hint, action: button, children: /* @__PURE__ */ jsxRuntime.jsx(
4707
+ Input,
4708
+ {
4709
+ name: param,
4710
+ required: true,
4711
+ value,
4712
+ onChange: (e) => setValue(e.target.value),
4713
+ placeholder,
4714
+ spellCheck: false,
4715
+ autoComplete: "off",
4716
+ className: "font-mono text-base md:text-[0.875rem]"
4717
+ }
4718
+ ) })
4719
+ ]
4720
+ }
4721
+ );
4722
+ }
4723
+ var TINT = "bg-[color-mix(in_oklab,var(--oca-orange)_9%,var(--card))]";
4724
+ function ComparisonTable({
4725
+ columns,
4726
+ rows,
4727
+ label,
4728
+ propertyHeading = "Property",
4729
+ className
4730
+ }) {
4731
+ const wide = columns.length > 3;
4732
+ const grid = wide ? "lg:grid lg:grid-cols-[var(--oca-compare)]" : "md:grid md:grid-cols-[var(--oca-compare)]";
4733
+ const desk = wide ? "lg" : "md";
4734
+ const style = {
4735
+ // The argued-for column gets a little more room: its answers carry the page.
4736
+ "--oca-compare": ["minmax(0, 1.4fr)", ...columns.map((c) => c.highlight ? "minmax(0, 1.3fr)" : "minmax(0, 1fr)")].join(" ")
4737
+ };
4738
+ const ordered = [...columns].sort((a, b) => Number(Boolean(b.highlight)) - Number(Boolean(a.highlight)));
4739
+ return /* @__PURE__ */ jsxRuntime.jsxs("ul", { "aria-label": label, style, className: cn("divide-y divide-border rounded-[1.25rem] border border-border bg-card", className), children: [
4740
+ /* @__PURE__ */ jsxRuntime.jsxs(
4741
+ "li",
4742
+ {
4743
+ "aria-hidden": true,
4744
+ className: cn(
4745
+ "hidden gap-5 px-5 py-4 text-[0.875rem] font-medium text-muted-foreground",
4746
+ wide ? "lg:grid lg:px-8" : "md:grid md:px-8",
4747
+ grid
4748
+ ),
4749
+ children: [
4750
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: propertyHeading }),
4751
+ columns.map((c) => /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn(c.highlight && cn(TINT, "-my-4 px-4 py-4 text-oca-accent-ink")), children: c.label }, c.key))
4752
+ ]
4753
+ }
4754
+ ),
4755
+ rows.map((r, ri) => /* @__PURE__ */ jsxRuntime.jsxs("li", { className: cn("grid grid-cols-1 gap-3 px-5 py-5", wide ? "lg:items-start lg:gap-5 lg:px-8" : "md:items-start md:gap-5 md:px-8", grid), children: [
4295
4756
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-col gap-1", children: [
4296
4757
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "oca-title-sm", children: r.label }),
4297
4758
  r.note ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[0.875rem] leading-snug text-muted-foreground", children: r.note }) : null
@@ -4404,6 +4865,7 @@ function SignMessage({
4404
4865
  error,
4405
4866
  submitLabel = "Confirm",
4406
4867
  secondary,
4868
+ scheme = "bip322",
4407
4869
  onSignature,
4408
4870
  className
4409
4871
  }) {
@@ -4418,7 +4880,7 @@ function SignMessage({
4418
4880
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "h-px flex-1 bg-border" })
4419
4881
  ] })
4420
4882
  ] }) : null,
4421
- /* @__PURE__ */ jsxRuntime.jsx(CodeBlock, { code: message, caption: "Message to sign" }),
4883
+ /* @__PURE__ */ jsxRuntime.jsx(CodeBlock, { code: message, caption: "Message to sign", wrap: true }),
4422
4884
  /* @__PURE__ */ jsxRuntime.jsxs(
4423
4885
  "form",
4424
4886
  {
@@ -4434,7 +4896,9 @@ function SignMessage({
4434
4896
  label: "Signature",
4435
4897
  error,
4436
4898
  hint: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4437
- "From your wallet\u2019s \u201Csign message\u201D (BIP-322), signed by",
4899
+ "From your wallet\u2019s \u201Csign message\u201D (",
4900
+ scheme === "legacy" ? "legacy, BIP-137" : "BIP-322",
4901
+ "), signed by",
4438
4902
  " ",
4439
4903
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "break-all font-mono", children: address }),
4440
4904
  "."
@@ -4460,448 +4924,67 @@ function SignMessage({
4460
4924
  )
4461
4925
  ] });
4462
4926
  }
4463
- var isInternal = (href) => href.startsWith("/") || href.startsWith("#");
4464
- function DocLink({ href, className, children, ...rest }) {
4465
- return isInternal(href) ? /* @__PURE__ */ jsxRuntime.jsx(Link8__default.default, { href, className, ...rest, children }) : /* @__PURE__ */ jsxRuntime.jsx("a", { href, className, ...rest, children });
4927
+ function useMacKeys() {
4928
+ const [mac, setMac] = react.useState(true);
4929
+ react.useEffect(() => {
4930
+ setMac(/Mac|iPhone|iPad/.test(navigator.platform || navigator.userAgent));
4931
+ }, []);
4932
+ return mac;
4466
4933
  }
4467
- function Breadcrumbs({ items, action, className }) {
4468
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex min-h-11 items-center justify-between gap-4 sm:min-h-0", className), children: [
4469
- /* @__PURE__ */ jsxRuntime.jsx("nav", { "aria-label": "Breadcrumb", className: "min-w-0", children: /* @__PURE__ */ jsxRuntime.jsx("ol", { className: "flex min-w-0 items-center gap-1.5 text-[0.875rem] text-muted-foreground", children: items.map((c, i) => {
4470
- const last = i === items.length - 1;
4471
- return /* @__PURE__ */ jsxRuntime.jsxs("li", { className: cn("flex items-center gap-1.5", last ? "min-w-0" : "shrink-0"), children: [
4472
- c.href && !last ? /* @__PURE__ */ jsxRuntime.jsx(DocLink, { href: c.href, className: "inline-flex min-h-11 items-center transition-colors hover:text-foreground sm:min-h-0", children: c.label }) : /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-current": last ? "page" : void 0, className: cn("truncate", last && "text-foreground"), children: c.label }),
4473
- !last ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { "aria-hidden": true, className: "size-3.5 shrink-0 text-oca-subtle" }) : null
4474
- ] }, i);
4475
- }) }) }),
4476
- action ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0 text-[0.875rem]", children: action }) : null
4477
- ] });
4478
- }
4479
- function DocsPager({ prev, next, className }) {
4480
- if (!prev && !next) return null;
4481
- const card = (l, dir) => /* @__PURE__ */ jsxRuntime.jsxs(
4482
- DocLink,
4483
- {
4484
- href: l.href,
4485
- className: cn(
4486
- "group flex min-h-20 flex-col justify-center gap-1 rounded-2xl border border-border bg-card px-5 py-4 transition-colors hover:border-oca-hairline-strong",
4487
- dir === "next" && "items-end text-right sm:col-start-2"
4488
- ),
4489
- children: [
4490
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-1.5 text-[0.8125rem] text-muted-foreground", children: [
4491
- dir === "prev" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowLeft, { "aria-hidden": true, className: "size-3.5" }) : null,
4492
- dir === "prev" ? "Previous" : "Next",
4493
- l.section ? /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, children: "\xB7" }) : null,
4494
- l.section ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: l.section }) : null,
4495
- dir === "next" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowRight, { "aria-hidden": true, className: "size-3.5" }) : null
4496
- ] }),
4497
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[1rem] font-medium leading-snug text-foreground", children: l.label })
4498
- ]
4499
- }
4500
- );
4501
- return /* @__PURE__ */ jsxRuntime.jsxs("nav", { "aria-label": "Previous and next page", className: cn("grid grid-cols-1 gap-3 border-t border-border pt-8 sm:grid-cols-2", className), children: [
4502
- prev ? card(prev, "prev") : null,
4503
- next ? card(next, "next") : null
4504
- ] });
4505
- }
4506
- function useHeadings(selector = "#docs-content", key) {
4507
- const [items, setItems] = react.useState([]);
4508
- react.useEffect(() => {
4509
- const read = () => {
4510
- const root = document.querySelector(selector);
4511
- if (!root) return setItems([]);
4512
- setItems(
4513
- Array.from(root.querySelectorAll("h2[id], h3[id]")).map((h) => ({
4514
- id: h.id,
4515
- // The anchor link's "#" is not part of the name.
4516
- label: (h.querySelector("[data-heading-text]") ?? h).textContent?.trim() ?? "",
4517
- level: h.tagName === "H3" ? 3 : 2
4518
- }))
4519
- );
4520
- };
4521
- const raf = requestAnimationFrame(read);
4522
- const t = setTimeout(read, 80);
4523
- return () => {
4524
- cancelAnimationFrame(raf);
4525
- clearTimeout(t);
4526
- };
4527
- }, [selector, key]);
4528
- const activeId = useActiveHeading(items.map((i) => i.id));
4529
- return { items, activeId };
4530
- }
4531
- function OnThisPage({
4532
- items,
4533
- activeId,
4534
- title = "On this page",
4535
- onNavigate,
4536
- className
4537
- }) {
4538
- const id = react.useId();
4539
- if (items.length === 0) return null;
4540
- return (
4541
- // With no visible title (a folded list under its own summary) the name is still "On this page".
4542
- /* @__PURE__ */ jsxRuntime.jsxs("nav", { "aria-labelledby": title ? id : void 0, "aria-label": title ? void 0 : "On this page", className, children: [
4543
- title ? /* @__PURE__ */ jsxRuntime.jsx("p", { id, className: "mb-3 text-[0.875rem] font-medium", children: title }) : null,
4544
- /* @__PURE__ */ jsxRuntime.jsx("ul", { children: items.map((t) => {
4545
- const on = t.id === activeId;
4546
- return /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx(
4547
- "a",
4548
- {
4549
- href: `#${t.id}`,
4550
- onClick: onNavigate,
4551
- "aria-current": on ? "location" : void 0,
4552
- className: cn(
4553
- "block border-l py-1.5 text-[0.875rem] leading-snug transition-colors",
4554
- t.level === 3 ? "pl-7" : "pl-4",
4555
- on ? "border-foreground text-foreground" : "border-border text-muted-foreground hover:text-foreground"
4556
- ),
4557
- children: t.label
4558
- }
4559
- ) }, t.id);
4560
- }) })
4561
- ] })
4562
- );
4563
- }
4564
- var CALLOUT_TONE = { note: "neutral", warning: "brand", danger: "danger" };
4565
- function Callout({
4566
- tone = "note",
4567
- title,
4568
- children,
4569
- className
4570
- }) {
4571
- return /* @__PURE__ */ jsxRuntime.jsx(
4572
- Notice,
4573
- {
4574
- tone: CALLOUT_TONE[tone],
4575
- title,
4576
- role: "note",
4577
- className: cn("my-6 [&_p]:my-0 [&_p]:text-[0.9375rem] [&_p]:leading-relaxed [&_p+p]:mt-3", className),
4578
- children
4579
- }
4580
- );
4581
- }
4582
- function Step({ title, id, children }) {
4583
- return /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "relative pb-8 pl-11 last:pb-0 [counter-increment:oca-step]", children: [
4584
- /* @__PURE__ */ jsxRuntime.jsx(
4585
- "span",
4586
- {
4587
- "aria-hidden": true,
4588
- className: "absolute left-0 top-0 flex size-7 items-center justify-center rounded-full border border-oca-hairline-strong bg-card text-[0.8125rem] oca-tabular text-foreground before:content-[counter(oca-step)]"
4589
- }
4590
- ),
4591
- /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: "absolute bottom-1 left-[0.8125rem] top-9 w-px bg-border" }),
4592
- /* @__PURE__ */ jsxRuntime.jsx("h3", { id, className: "scroll-mt-28 pt-0.5 text-[1.0625rem] font-medium leading-snug tracking-[-0.008em] text-foreground", children: title }),
4593
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2 text-muted-foreground [&>*:first-child]:mt-0 [&>*:last-child]:mb-0", children })
4594
- ] });
4595
- }
4596
- function Steps({ children, className }) {
4597
- return /* @__PURE__ */ jsxRuntime.jsx("ol", { className: cn("not-prose my-8 flex flex-col [counter-reset:oca-step] [&>li:last-child>span:nth-child(2)]:hidden", className), children });
4598
- }
4599
- function LinkCard({
4600
- href,
4601
- title,
4602
- description,
4603
- icon,
4604
- meta,
4605
- className
4606
- }) {
4607
- const Arrow = isInternal(href) ? lucideReact.ArrowRight : lucideReact.ArrowUpRight;
4934
+ var typing = (el) => el instanceof HTMLElement && (el.isContentEditable || /^(INPUT|TEXTAREA|SELECT)$/.test(el.tagName));
4935
+ var SearchButton = react.forwardRef(function SearchButton2({ label = "Search", onClick, className }, ref) {
4936
+ const mac = useMacKeys();
4608
4937
  return /* @__PURE__ */ jsxRuntime.jsxs(
4609
- DocLink,
4938
+ "button",
4610
4939
  {
4611
- href,
4940
+ ref,
4941
+ type: "button",
4942
+ onClick,
4943
+ "aria-keyshortcuts": mac ? "Meta+K" : "Control+K",
4612
4944
  className: cn(
4613
- "group flex h-full flex-col gap-3 rounded-[1.25rem] border border-border bg-card p-5 transition-colors hover:border-oca-hairline-strong",
4945
+ "inline-flex size-10 items-center justify-center gap-2 rounded-full text-muted-foreground transition-colors hover:bg-accent hover:text-foreground",
4946
+ "md:h-10 md:w-56 md:justify-start md:border md:border-border md:bg-card md:pl-3.5 md:pr-2 md:hover:border-oca-hairline-strong md:hover:bg-card",
4614
4947
  className
4615
4948
  ),
4616
4949
  children: [
4617
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-start justify-between gap-3", children: [
4618
- icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex size-9 shrink-0 items-center justify-center rounded-xl bg-muted text-foreground [&_svg]:size-[1.125rem]", children: icon }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[1rem] font-medium leading-snug text-foreground", children: title }),
4619
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex shrink-0 items-center gap-2", children: [
4620
- meta,
4621
- /* @__PURE__ */ jsxRuntime.jsx(Arrow, { "aria-hidden": true, className: "size-4 text-muted-foreground transition-transform group-hover:translate-x-0.5 group-hover:text-foreground" })
4622
- ] })
4623
- ] }),
4624
- icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[1rem] font-medium leading-snug text-foreground", children: title }) : null,
4625
- description ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[0.9375rem] leading-relaxed text-muted-foreground", children: description }) : null
4950
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Search, { "aria-hidden": true, className: "size-[1.125rem] shrink-0 md:size-4" }),
4951
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only flex-1 text-left text-[0.9375rem] md:not-sr-only", children: label }),
4952
+ /* @__PURE__ */ jsxRuntime.jsx(Kbd, { "aria-hidden": true, className: "hidden md:inline-flex", children: mac ? "\u2318K" : "Ctrl K" })
4626
4953
  ]
4627
4954
  }
4628
4955
  );
4629
- }
4630
- function CardGrid({ columns = 2, children, className }) {
4631
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("not-prose my-6 grid grid-cols-1 gap-3 sm:grid-cols-2", columns === 3 && "lg:grid-cols-3", className), children });
4632
- }
4633
- function MdxTable({ className, ...props }) {
4634
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "not-prose my-6 overflow-hidden rounded-2xl border border-border bg-card", children: /* @__PURE__ */ jsxRuntime.jsx(ScrollFade, { fade: "var(--card)", children: /* @__PURE__ */ jsxRuntime.jsx(
4635
- "table",
4636
- {
4637
- className: cn(
4638
- "w-full border-collapse text-left text-[0.875rem] leading-relaxed",
4639
- "[&_th]:whitespace-nowrap [&_th]:border-b [&_th]:border-oca-hairline-strong [&_th]:bg-oca-table-head [&_th]:px-4 [&_th]:py-2.5 [&_th]:text-[0.8125rem] [&_th]:font-medium [&_th]:text-foreground",
4640
- "[&_td]:border-t [&_td]:border-border [&_td]:px-4 [&_td]:py-2.5 [&_td]:align-top [&_td]:text-muted-foreground [&_tbody_tr:first-child_td]:border-t-0",
4641
- "[&_td_code]:bg-transparent [&_td_code]:p-0 [&_td_code]:text-foreground [&_td:first-child]:text-foreground",
4642
- "[&_[align=center]]:text-center [&_[align=right]]:text-right",
4643
- // On a phone a cell keeps a readable width; the table scrolls instead of crushing it.
4644
- "max-sm:[&_td]:min-w-[9rem]",
4645
- className
4646
- ),
4647
- ...props
4648
- }
4649
- ) }) });
4650
- }
4651
- function ApiTable({
4652
- rows,
4653
- caption,
4654
- nameHeader = "Name",
4956
+ });
4957
+ function SearchDialog({
4958
+ onQuery,
4959
+ open: openProp,
4960
+ onOpenChange,
4961
+ onSelect,
4962
+ button = true,
4963
+ hotkey = true,
4964
+ label = "Search",
4965
+ placeholder = "Search the docs",
4966
+ idle,
4967
+ defaultQuery = "",
4968
+ debounceMs = 120,
4655
4969
  className
4656
4970
  }) {
4657
- const hasDefault = rows.some((r) => r.default !== void 0);
4658
- const marks = (r) => /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4659
- r.required ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[0.75rem] text-oca-accent-ink", children: "Required" }) : null,
4660
- r.deprecated ? /* @__PURE__ */ jsxRuntime.jsx(Badge, { tone: "muted", children: "Deprecated" }) : null,
4661
- r.status ? /* @__PURE__ */ jsxRuntime.jsx(StatusBadge, { status: r.status }) : null
4662
- ] });
4663
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("not-prose my-6", className), children: [
4664
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-hidden rounded-2xl border border-border bg-card max-sm:hidden", children: /* @__PURE__ */ jsxRuntime.jsx(ScrollFade, { fade: "var(--card)", children: /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "w-full border-collapse text-left text-[0.875rem]", children: [
4665
- caption ? /* @__PURE__ */ jsxRuntime.jsx("caption", { className: "sr-only", children: caption }) : null,
4666
- /* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "border-b border-oca-hairline-strong bg-oca-table-head text-[0.8125rem]", children: [
4667
- /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", className: "px-4 py-2.5 font-medium", children: nameHeader }),
4668
- /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", className: "px-4 py-2.5 font-medium", children: "Type" }),
4669
- hasDefault ? /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", className: "px-4 py-2.5 font-medium", children: "Default" }) : null,
4670
- /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", className: "px-4 py-2.5 font-medium", children: "Description" })
4671
- ] }) }),
4672
- /* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "divide-y divide-border", children: rows.map((r) => /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "align-top", children: [
4673
- /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "row", className: "px-4 py-3 text-left font-normal", children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex flex-col items-start gap-1", children: [
4674
- /* @__PURE__ */ jsxRuntime.jsx("code", { className: cn("font-mono text-[0.8125rem] text-foreground", r.deprecated && "line-through decoration-oca-subtle"), children: r.name }),
4675
- marks(r)
4676
- ] }) }),
4677
- /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3 font-mono text-[0.8125rem] text-muted-foreground", children: r.type ?? "\u2014" }),
4678
- hasDefault ? /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3 font-mono text-[0.8125rem] text-muted-foreground", children: r.default ?? "\u2014" }) : null,
4679
- /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3 leading-relaxed text-muted-foreground", children: r.description })
4680
- ] }, r.name)) })
4681
- ] }) }) }),
4682
- /* @__PURE__ */ jsxRuntime.jsx("ul", { "aria-label": caption, className: "divide-y divide-border rounded-2xl border border-border bg-card sm:hidden", children: rows.map((r) => /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex flex-col gap-1.5 px-4 py-3.5", children: [
4683
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex flex-wrap items-baseline gap-x-2 gap-y-1", children: [
4684
- /* @__PURE__ */ jsxRuntime.jsx("code", { className: cn("font-mono text-[0.875rem] text-foreground", r.deprecated && "line-through decoration-oca-subtle"), children: r.name }),
4685
- r.type ? /* @__PURE__ */ jsxRuntime.jsx("code", { className: "break-all font-mono text-[0.8125rem] text-muted-foreground", children: r.type }) : null
4686
- ] }),
4687
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex flex-wrap items-center gap-2 empty:hidden", children: marks(r) }),
4688
- r.description ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[0.875rem] leading-relaxed text-muted-foreground", children: r.description }) : null,
4689
- r.default !== void 0 ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-[0.8125rem] text-muted-foreground", children: [
4690
- "Default ",
4691
- /* @__PURE__ */ jsxRuntime.jsx("code", { className: "font-mono text-foreground", children: r.default })
4692
- ] }) : null
4693
- ] }, r.name)) })
4694
- ] });
4695
- }
4696
- function useDarkMode() {
4697
- const [dark, setDark] = react.useState(false);
4698
- react.useEffect(() => {
4699
- const root = document.documentElement;
4700
- const read = () => setDark(root.classList.contains("dark"));
4701
- read();
4702
- const mo = new MutationObserver(read);
4703
- mo.observe(root, { attributes: true, attributeFilter: ["class"] });
4704
- return () => mo.disconnect();
4705
- }, []);
4706
- return dark;
4707
- }
4708
- function mermaidTheme(el) {
4709
- const css = getComputedStyle(el);
4710
- const v = (name) => css.getPropertyValue(name).trim();
4711
- const card = v("--card");
4712
- const muted = v("--muted");
4713
- const text = v("--foreground");
4714
- const subtle = v("--muted-foreground");
4715
- const line = v("--input");
4716
- const hair = v("--oca-hairline-strong");
4717
- return {
4718
- background: "transparent",
4719
- fontFamily: css.fontFamily,
4720
- fontSize: "14px",
4721
- textColor: text,
4722
- mainBkg: card,
4723
- primaryColor: card,
4724
- primaryTextColor: text,
4725
- primaryBorderColor: hair,
4726
- secondaryColor: muted,
4727
- secondaryTextColor: text,
4728
- secondaryBorderColor: hair,
4729
- tertiaryColor: muted,
4730
- tertiaryTextColor: text,
4731
- tertiaryBorderColor: hair,
4732
- nodeBorder: hair,
4733
- lineColor: line,
4734
- edgeLabelBackground: card,
4735
- clusterBkg: muted,
4736
- clusterBorder: hair,
4737
- titleColor: text,
4738
- noteBkgColor: muted,
4739
- noteTextColor: text,
4740
- noteBorderColor: hair,
4741
- actorBkg: card,
4742
- actorBorder: hair,
4743
- actorTextColor: text,
4744
- actorLineColor: line,
4745
- signalColor: text,
4746
- signalTextColor: text,
4747
- labelBoxBkgColor: card,
4748
- labelBoxBorderColor: hair,
4749
- labelTextColor: text,
4750
- loopTextColor: subtle,
4751
- activationBkgColor: muted,
4752
- activationBorderColor: hair,
4753
- sequenceNumberColor: card
4754
- };
4755
- }
4756
- function naturalSize(svg) {
4757
- const w = svg.match(/viewBox="[\d.-]+ [\d.-]+ ([\d.]+) [\d.]+"/)?.[1];
4758
- if (!w) return svg;
4759
- return svg.replace(/<svg([^>]*?)\swidth="100%"/, `<svg$1 width="${Math.ceil(Number(w))}"`).replace(/max-width:\s*[\d.]+px;?/, "");
4760
- }
4761
- function Diagram({ chart, caption, load, className }) {
4762
- const ref = react.useRef(null);
4763
- const dark = useDarkMode();
4764
- const raw = react.useId();
4765
- const [svg, setSvg] = react.useState(null);
4766
- const [failed, setFailed] = react.useState(false);
4767
- react.useEffect(() => {
4768
- let live = true;
4769
- const el = ref.current;
4770
- if (!el) return;
4771
- (async () => {
4772
- try {
4773
- const mod = await load();
4774
- const mermaid = "default" in mod ? mod.default : mod;
4775
- mermaid.initialize({ startOnLoad: false, securityLevel: "strict", theme: "base", themeVariables: mermaidTheme(el) });
4776
- const { svg: drawn } = await mermaid.render(`oca-diagram-${raw.replace(/[^a-zA-Z0-9]/g, "")}-${dark ? "d" : "l"}`, chart);
4777
- if (live) {
4778
- setSvg(naturalSize(drawn));
4779
- setFailed(false);
4780
- }
4781
- } catch {
4782
- if (live) setFailed(true);
4783
- }
4784
- })();
4785
- return () => {
4786
- live = false;
4787
- };
4788
- }, [chart, dark, load, raw]);
4789
- if (failed) return /* @__PURE__ */ jsxRuntime.jsx(CodeBlock, { code: chart, caption: "Diagram (shown as its source)", className: cn("my-6", className) });
4790
- return /* @__PURE__ */ jsxRuntime.jsxs("figure", { ref, className: cn("not-prose my-6 overflow-hidden rounded-[1.25rem] border border-border bg-card", className), children: [
4791
- svg ? /* @__PURE__ */ jsxRuntime.jsx(ScrollFade, { fade: "var(--card)", children: /* @__PURE__ */ jsxRuntime.jsx(
4792
- "div",
4793
- {
4794
- className: "flex w-max min-w-full justify-center p-6 [&_svg]:h-auto [&_svg]:max-w-none",
4795
- role: "img",
4796
- "aria-label": typeof caption === "string" ? caption : "Diagram",
4797
- dangerouslySetInnerHTML: { __html: svg }
4798
- }
4799
- ) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { role: "status", "aria-label": "Drawing the diagram", className: "p-6", children: /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { className: "h-40 w-full rounded-xl" }) }),
4800
- caption ? /* @__PURE__ */ jsxRuntime.jsx("figcaption", { className: "border-t border-border px-5 py-3 text-[0.8125rem] text-muted-foreground", children: caption }) : null
4801
- ] });
4802
- }
4803
- var HEADING = {
4804
- h1: "oca-display-3 mb-4 text-foreground",
4805
- h2: "mb-3 mt-12 text-[1.375rem] font-medium leading-tight tracking-[-0.015em] text-foreground md:text-[1.5rem]",
4806
- h3: "mb-2 mt-9 text-[1.125rem] font-medium leading-snug tracking-[-0.01em] text-foreground",
4807
- h4: "mb-2 mt-7 text-[1rem] font-medium leading-snug text-foreground"
4808
- };
4809
- function DocsHeading({
4810
- as: Tag,
4811
- id,
4812
- children,
4813
- className,
4814
- ...props
4815
- }) {
4816
- return /* @__PURE__ */ jsxRuntime.jsxs(Tag, { id, className: cn("group scroll-mt-28", HEADING[Tag], className), ...props, children: [
4817
- /* @__PURE__ */ jsxRuntime.jsx("span", { "data-heading-text": "", children }),
4818
- id && Tag !== "h1" ? /* @__PURE__ */ jsxRuntime.jsxs(
4819
- "a",
4820
- {
4821
- href: `#${id}`,
4822
- className: "ml-2 inline-block rounded-md px-1 align-baseline text-[0.85em] font-normal text-oca-subtle no-underline opacity-0 transition-opacity hover:text-foreground focus-visible:opacity-100 group-hover:opacity-100",
4823
- children: [
4824
- /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, children: "#" }),
4825
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Link to this section" })
4826
- ]
4827
- }
4828
- ) : null
4829
- ] });
4830
- }
4831
- function codeText(node) {
4832
- if (typeof node === "string") return node;
4833
- if (typeof node === "number") return String(node);
4834
- if (Array.isArray(node)) return node.map(codeText).join("");
4835
- if (react.isValidElement(node)) return codeText(node.props.children);
4836
- return "";
4837
- }
4838
- function codeLang(node) {
4839
- const child = react.Children.toArray(node)[0];
4840
- if (!react.isValidElement(child)) return void 0;
4841
- const cls = child.props.className ?? "";
4842
- return cls.match(/language-([\w+-]+)/)?.[1];
4843
- }
4844
- function useMacKeys() {
4845
- const [mac, setMac] = react.useState(true);
4846
- react.useEffect(() => {
4847
- setMac(/Mac|iPhone|iPad/.test(navigator.platform || navigator.userAgent));
4848
- }, []);
4849
- return mac;
4850
- }
4851
- var typing = (el) => el instanceof HTMLElement && (el.isContentEditable || /^(INPUT|TEXTAREA|SELECT)$/.test(el.tagName));
4852
- var SearchButton = react.forwardRef(function SearchButton2({ label = "Search", onClick, className }, ref) {
4853
- const mac = useMacKeys();
4854
- return /* @__PURE__ */ jsxRuntime.jsxs(
4855
- "button",
4856
- {
4857
- ref,
4858
- type: "button",
4859
- onClick,
4860
- "aria-keyshortcuts": mac ? "Meta+K" : "Control+K",
4861
- className: cn(
4862
- "inline-flex size-10 items-center justify-center gap-2 rounded-full text-muted-foreground transition-colors hover:bg-accent hover:text-foreground",
4863
- "md:h-10 md:w-56 md:justify-start md:border md:border-border md:bg-card md:pl-3.5 md:pr-2 md:hover:border-oca-hairline-strong md:hover:bg-card",
4864
- className
4865
- ),
4866
- children: [
4867
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Search, { "aria-hidden": true, className: "size-[1.125rem] shrink-0 md:size-4" }),
4868
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only flex-1 text-left text-[0.9375rem] md:not-sr-only", children: label }),
4869
- /* @__PURE__ */ jsxRuntime.jsx(Kbd, { "aria-hidden": true, className: "hidden md:inline-flex", children: mac ? "\u2318K" : "Ctrl K" })
4870
- ]
4871
- }
4872
- );
4873
- });
4874
- function SearchDialog({
4875
- onQuery,
4876
- open: openProp,
4877
- onOpenChange,
4878
- onSelect,
4879
- button = true,
4880
- hotkey = true,
4881
- label = "Search",
4882
- placeholder = "Search the docs",
4883
- idle,
4884
- defaultQuery = "",
4885
- debounceMs = 120,
4886
- className
4887
- }) {
4888
- const [own, setOwn] = react.useState(false);
4889
- const open = openProp ?? own;
4890
- const setOpen = (v) => {
4891
- if (openProp === void 0) setOwn(v);
4892
- onOpenChange?.(v);
4893
- };
4894
- const [query, setQuery] = react.useState(defaultQuery);
4895
- const [groups, setGroups] = react.useState([]);
4896
- const [state, setState] = react.useState("idle");
4897
- const [active, setActive] = react.useState(0);
4898
- const listId = react.useId();
4899
- const listRef = react.useRef(null);
4900
- const buttonRef = react.useRef(null);
4901
- const returnTo = react.useRef(null);
4902
- const flat = react.useMemo(() => groups.flatMap((g) => g.results), [groups]);
4903
- const latest = react.useRef({ open, setOpen, onQuery });
4904
- latest.current = { open, setOpen, onQuery };
4971
+ const [own, setOwn] = react.useState(false);
4972
+ const open = openProp ?? own;
4973
+ const setOpen = (v) => {
4974
+ if (openProp === void 0) setOwn(v);
4975
+ onOpenChange?.(v);
4976
+ };
4977
+ const [query, setQuery] = react.useState(defaultQuery);
4978
+ const [groups, setGroups] = react.useState([]);
4979
+ const [state, setState] = react.useState("idle");
4980
+ const [active, setActive] = react.useState(0);
4981
+ const listId = react.useId();
4982
+ const listRef = react.useRef(null);
4983
+ const buttonRef = react.useRef(null);
4984
+ const returnTo = react.useRef(null);
4985
+ const flat = react.useMemo(() => groups.flatMap((g) => g.results), [groups]);
4986
+ const latest = react.useRef({ open, setOpen, onQuery });
4987
+ latest.current = { open, setOpen, onQuery };
4905
4988
  react.useEffect(() => {
4906
4989
  if (!hotkey) return;
4907
4990
  const onKey = (e) => {
@@ -5327,7 +5410,7 @@ function FormSection({
5327
5410
  "aria-current": status === "current" ? "step" : void 0,
5328
5411
  className: cn("scroll-mt-24 rounded-[1.25rem] border border-border bg-card", className),
5329
5412
  children: [
5330
- /* @__PURE__ */ jsxRuntime.jsxs("header", { className: cn("flex items-start gap-3.5", tight ? "px-5 pt-5" : "px-6 pt-6"), children: [
5413
+ /* @__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: [
5331
5414
  n !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(
5332
5415
  "span",
5333
5416
  {
@@ -5354,7 +5437,7 @@ function FormSection({
5354
5437
  ] }),
5355
5438
  hint ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[0.875rem] leading-snug text-muted-foreground", children: hint }) : null
5356
5439
  ] }),
5357
- action ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0", children: action }) : null
5440
+ action ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("shrink-0 max-sm:basis-full", n !== void 0 && "max-sm:pl-[2.625rem]"), children: action }) : null
5358
5441
  ] }),
5359
5442
  /* @__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 })
5360
5443
  ]
@@ -5584,27 +5667,30 @@ function FilterChips({
5584
5667
  onChange(cur.includes(v) ? cur.filter((x) => x !== v) : [...cur, v]);
5585
5668
  } else onChange(v);
5586
5669
  };
5587
- 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) => {
5588
- const on = isOn(o.value);
5589
- return /* @__PURE__ */ jsxRuntime.jsxs(
5590
- "button",
5591
- {
5592
- type: "button",
5593
- "aria-pressed": on,
5594
- onClick: () => press(o.value),
5595
- className: cn(
5596
- "inline-flex shrink-0 items-center gap-1.5 rounded-full border px-3.5 text-[0.875rem] transition-colors",
5597
- tight ? "h-8" : "h-9",
5598
- on ? "border-foreground bg-foreground text-background" : "border-border bg-card text-muted-foreground hover:border-oca-hairline-strong hover:text-foreground"
5599
- ),
5600
- children: [
5601
- o.label,
5602
- o.count !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "oca-tabular", children: o.count.toLocaleString("en-US") }) : null
5603
- ]
5604
- },
5605
- o.value
5606
- );
5607
- }) }) });
5670
+ return (
5671
+ // Wraps rather than scrolls: every filter stays in view on a phone.
5672
+ /* @__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) => {
5673
+ const on = isOn(o.value);
5674
+ return /* @__PURE__ */ jsxRuntime.jsxs(
5675
+ "button",
5676
+ {
5677
+ type: "button",
5678
+ "aria-pressed": on,
5679
+ onClick: () => press(o.value),
5680
+ className: cn(
5681
+ "inline-flex shrink-0 items-center gap-1.5 rounded-full border px-3.5 text-[0.875rem] transition-colors",
5682
+ tight ? "h-8" : "h-9",
5683
+ on ? "border-foreground bg-foreground text-background" : "border-border bg-card text-muted-foreground hover:border-oca-hairline-strong hover:text-foreground"
5684
+ ),
5685
+ children: [
5686
+ o.label,
5687
+ o.count !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "oca-tabular", children: o.count.toLocaleString("en-US") }) : null
5688
+ ]
5689
+ },
5690
+ o.value
5691
+ );
5692
+ }) })
5693
+ );
5608
5694
  }
5609
5695
  function ToolGrid({
5610
5696
  tools,
@@ -5643,7 +5729,7 @@ function ToolGrid({
5643
5729
  ] }),
5644
5730
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1.5", children: [
5645
5731
  /* @__PURE__ */ jsxRuntime.jsx(Heading, { className: "oca-title-sm", children: /* @__PURE__ */ jsxRuntime.jsx(
5646
- Link8__default.default,
5732
+ Link6__default.default,
5647
5733
  {
5648
5734
  href: t.href,
5649
5735
  className: "outline-none after:absolute after:inset-0 after:rounded-[1.25rem] after:content-['']",
@@ -5736,800 +5822,829 @@ function FamilyMenu({ current: current2, className }) {
5736
5822
  )
5737
5823
  ] });
5738
5824
  }
5739
- function NavLink({
5740
- item,
5741
- className,
5742
- onNavigate,
5743
- line = false
5744
- }) {
5745
- const cls = cn(
5746
- "rounded-full px-3 py-2 text-[0.9375rem] transition-colors",
5747
- item.active ? "text-foreground" : "text-muted-foreground hover:text-foreground",
5748
- line && "relative after:absolute after:inset-x-3 after:-bottom-[0.625rem] after:h-0.5 after:rounded-full",
5749
- line && item.active && "after:bg-foreground",
5750
- className
5751
- );
5752
- if (item.external) {
5753
- return /* @__PURE__ */ jsxRuntime.jsx("a", { href: item.href, className: cls, rel: "noreferrer", onClick: onNavigate, children: item.label });
5754
- }
5755
- return /* @__PURE__ */ jsxRuntime.jsx(Link8__default.default, { href: item.href, className: cls, "aria-current": item.active ? "page" : void 0, onClick: onNavigate, children: item.label });
5756
- }
5757
- function NavRow({ item, onNavigate }) {
5758
- const body = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
5759
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[0.9375rem] font-medium leading-6 text-foreground", children: item.label }),
5760
- item.description ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[0.8125rem] leading-snug text-muted-foreground", children: item.description }) : null
5761
- ] });
5762
- const cls = cn(
5763
- "flex flex-col gap-0.5 rounded-xl px-3 py-2 transition-colors hover:bg-accent",
5764
- item.active && "bg-muted hover:bg-muted dark:bg-white/[0.06]"
5765
- );
5766
- return item.external ? /* @__PURE__ */ jsxRuntime.jsx("a", { href: item.href, className: cls, rel: "noreferrer", onClick: onNavigate, children: body }) : /* @__PURE__ */ jsxRuntime.jsx(Link8__default.default, { href: item.href, className: cls, "aria-current": item.active ? "page" : void 0, onClick: onNavigate, children: body });
5767
- }
5768
- var seeAll = (item) => typeof item.label === "string" ? `All ${item.label.toLowerCase()}` : "See all";
5769
- function NavDropdown({ item }) {
5770
- const [open, setOpen] = react.useState(false);
5771
- const active = item.active || item.children?.some((c) => c.active);
5772
- return /* @__PURE__ */ jsxRuntime.jsxs(Popover, { open, onOpenChange: setOpen, children: [
5773
- /* @__PURE__ */ jsxRuntime.jsxs(
5774
- PopoverTrigger,
5825
+ function SideNav({ groups, onNavigate }) {
5826
+ return /* @__PURE__ */ jsxRuntime.jsx("nav", { "aria-label": "Pages", className: "flex flex-col gap-5", children: groups.map((g, gi) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-0.5", children: [
5827
+ g.label ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "px-3 pb-1 text-[0.8125rem] text-muted-foreground", children: g.label }) : null,
5828
+ g.items.map((it) => /* @__PURE__ */ jsxRuntime.jsxs(
5829
+ Link6__default.default,
5775
5830
  {
5831
+ href: it.href,
5832
+ onClick: onNavigate,
5833
+ "aria-current": it.active ? "page" : void 0,
5776
5834
  className: cn(
5777
- "group inline-flex items-center gap-1 rounded-full py-2 pl-3 pr-2.5 text-[0.9375rem] transition-colors md:max-lg:pl-2.5 md:max-lg:pr-2",
5778
- active ? "text-foreground" : "text-muted-foreground hover:text-foreground data-[state=open]:text-foreground"
5835
+ "flex h-9 items-center gap-3 rounded-xl px-3 text-[0.9375rem] transition-colors",
5836
+ "[&_svg]:size-[1.0625rem] [&_svg]:shrink-0",
5837
+ it.active ? "bg-card text-foreground shadow-sm ring-1 ring-border [&_svg]:text-foreground" : "text-muted-foreground hover:bg-accent hover:text-foreground"
5779
5838
  ),
5780
5839
  children: [
5781
- item.label,
5782
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { "aria-hidden": true, className: "size-3.5 transition-transform duration-200 group-data-[state=open]:rotate-180" })
5840
+ it.icon,
5841
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate", children: it.label }),
5842
+ it.badge ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0", children: it.badge }) : null
5783
5843
  ]
5784
- }
5785
- ),
5786
- /* @__PURE__ */ jsxRuntime.jsxs(PopoverContent, { align: "center", sideOffset: 10, className: "w-[min(calc(100vw-2rem),26rem)] p-2", children: [
5787
- /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "flex flex-col", children: item.children?.map((c) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx(NavRow, { item: c, onNavigate: () => setOpen(false) }) }, c.href)) }),
5788
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1.5 border-t border-border px-1 pt-1.5", children: /* @__PURE__ */ jsxRuntime.jsx(
5789
- NavLink,
5790
- {
5791
- item: { ...item, label: seeAll(item), children: void 0 },
5792
- className: "block rounded-xl px-2 py-2 text-[0.875rem]",
5793
- onNavigate: () => setOpen(false)
5794
- }
5795
- ) })
5796
- ] })
5797
- ] });
5844
+ },
5845
+ it.href
5846
+ ))
5847
+ ] }, g.label ?? gi)) });
5798
5848
  }
5799
- function SiteHeader({
5800
- home = "/",
5801
- brand,
5802
- product,
5803
- family,
5804
- nav = [],
5805
- search,
5806
- actions,
5807
- variant = "site",
5808
- navOnPhone = true,
5809
- menu: menuExtra,
5810
- className
5849
+ function SectionSwitch({
5850
+ sections,
5851
+ current: current2,
5852
+ onNavigate
5811
5853
  }) {
5812
- const [open, setOpen] = react.useState(false);
5813
- const tool = variant === "tool";
5814
- const size = tool ? 24 : 28;
5815
- const current2 = typeof family === "string" ? family : void 0;
5816
- const phoneNav = navOnPhone ? nav : [];
5817
- const menu = phoneNav.length > 0 || Boolean(family) || Boolean(menuExtra);
5818
- const brandNode = brand ?? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center", children: [
5819
- /* @__PURE__ */ jsxRuntime.jsx(Lockup, { size }),
5820
- product ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
5821
- /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: "mx-3 h-5 w-px bg-oca-hairline-strong" }),
5822
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium tracking-[-0.01em]", style: { fontSize: size * 0.56 }, children: product })
5823
- ] }) : null
5824
- ] });
5825
- const navigation = nav.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("nav", { "aria-label": "Main", className: "hidden items-center gap-1 md:flex", children: nav.map(
5826
- (n) => n.children?.length ? /* @__PURE__ */ jsxRuntime.jsx(NavDropdown, { item: n }, n.href) : (
5827
- // Between md and lg the family menu and the actions share the row: tighter.
5828
- /* @__PURE__ */ jsxRuntime.jsx(NavLink, { item: n, line: tool, className: tool ? void 0 : "md:max-lg:px-2.5" }, n.href)
5829
- )
5830
- ) }) : null;
5854
+ const cols = sections.length <= 3 ? sections.length : 2;
5831
5855
  return /* @__PURE__ */ jsxRuntime.jsx(
5832
- "header",
5856
+ "nav",
5833
5857
  {
5834
- className: cn(
5835
- "sticky top-0 z-40 w-full border-b bg-background/95 backdrop-blur-md supports-[backdrop-filter]:bg-background/90",
5836
- tool ? "border-border" : "border-transparent",
5837
- className
5838
- ),
5839
- children: /* @__PURE__ */ jsxRuntime.jsxs(
5858
+ "aria-label": "Sections",
5859
+ className: cn("grid gap-1 bg-muted p-1", cols === sections.length ? "rounded-full" : "rounded-[1.25rem]"),
5860
+ style: { gridTemplateColumns: `repeat(${cols}, minmax(0, 1fr))` },
5861
+ children: sections.map((sec) => {
5862
+ const on = sec.id === current2.id;
5863
+ return /* @__PURE__ */ jsxRuntime.jsx(
5864
+ Link6__default.default,
5865
+ {
5866
+ href: sec.href,
5867
+ onClick: onNavigate,
5868
+ "aria-current": on ? "true" : void 0,
5869
+ className: cn(
5870
+ "flex h-8 min-w-0 items-center justify-center rounded-full px-1.5 text-[0.8125rem] font-medium transition-colors",
5871
+ on ? "bg-card text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"
5872
+ ),
5873
+ children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: sec.label })
5874
+ },
5875
+ sec.id
5876
+ );
5877
+ })
5878
+ }
5879
+ );
5880
+ }
5881
+ function TabBar({ items }) {
5882
+ return /* @__PURE__ */ jsxRuntime.jsx(
5883
+ "nav",
5884
+ {
5885
+ "aria-label": "Pages",
5886
+ "data-oca-tabbar": "",
5887
+ 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",
5888
+ children: /* @__PURE__ */ jsxRuntime.jsx(
5840
5889
  "div",
5841
5890
  {
5842
- className: cn(
5843
- "flex items-center justify-between gap-4",
5844
- tool ? "h-14 px-4 md:px-6" : "oca-container h-16 md:h-[4.5rem] md:max-lg:gap-2",
5845
- // Three columns, the outer two each at least their content: the
5846
- // navigation stays centred whatever the actions hold, so it does
5847
- // not shift when they change (signed out to signed in).
5848
- !tool && nav.length > 0 && "md:grid md:grid-cols-[minmax(max-content,1fr)_auto_minmax(max-content,1fr)]"
5849
- ),
5850
- children: [
5851
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex min-w-0 items-center gap-1", tool ? "md:gap-1" : "justify-self-start"), children: [
5852
- /* @__PURE__ */ jsxRuntime.jsxs(Link8__default.default, { href: home, className: "-ml-1 min-w-0 rounded-lg p-1", children: [
5853
- brandNode,
5854
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: " home" })
5855
- ] }),
5856
- family ? /* @__PURE__ */ jsxRuntime.jsx(FamilyMenu, { current: current2, className: "max-md:hidden" }) : null,
5857
- tool && navigation ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ml-5", children: navigation }) : null
5858
- ] }),
5859
- !tool ? navigation : null,
5860
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 justify-self-end", children: [
5861
- search,
5862
- actions,
5863
- menu ? /* @__PURE__ */ jsxRuntime.jsxs(Sheet, { open, onOpenChange: setOpen, children: [
5864
- /* @__PURE__ */ jsxRuntime.jsx(
5865
- SheetTrigger,
5891
+ className: "mx-auto grid h-14 max-w-[32rem] px-1.5",
5892
+ style: { gridTemplateColumns: `repeat(${items.length}, minmax(0, 1fr))` },
5893
+ children: items.map((it) => /* @__PURE__ */ jsxRuntime.jsxs(
5894
+ Link6__default.default,
5895
+ {
5896
+ href: it.href,
5897
+ "aria-current": it.active ? "page" : void 0,
5898
+ className: cn(
5899
+ "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",
5900
+ it.active ? "text-foreground" : "text-muted-foreground hover:text-foreground"
5901
+ ),
5902
+ children: [
5903
+ /* @__PURE__ */ jsxRuntime.jsxs(
5904
+ "span",
5866
5905
  {
5867
- className: "inline-flex size-10 items-center justify-center rounded-full text-foreground hover:bg-accent md:hidden",
5868
- "aria-label": "Open menu",
5869
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Menu, { className: "size-5" })
5906
+ className: cn(
5907
+ "relative flex h-7 w-12 items-center justify-center rounded-full transition-[background-color,box-shadow] duration-200",
5908
+ "[&_svg]:size-[1.125rem] [&_svg]:shrink-0",
5909
+ it.active ? "bg-card shadow-sm ring-1 ring-border [&_svg]:stroke-2" : "[&_svg]:stroke-[1.75]"
5910
+ ),
5911
+ children: [
5912
+ it.icon,
5913
+ 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
5914
+ ]
5870
5915
  }
5871
5916
  ),
5872
- /* @__PURE__ */ jsxRuntime.jsxs(SheetContent, { side: "right", className: "pt-16", children: [
5873
- /* @__PURE__ */ jsxRuntime.jsx(SheetTitle, { className: "sr-only", children: "Menu" }),
5874
- menuExtra ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex flex-col", (phoneNav.length > 0 || family) && "border-b border-border pb-3"), children: menuExtra }) : null,
5875
- phoneNav.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("nav", { "aria-label": "Main", className: "flex flex-col", children: phoneNav.map(
5876
- (n) => n.children?.length ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col py-2", children: [
5877
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "px-3 pb-1 text-[0.8125rem] text-muted-foreground", children: n.label }),
5878
- n.children.map((c) => /* @__PURE__ */ jsxRuntime.jsx(
5879
- NavLink,
5880
- {
5881
- item: c,
5882
- className: "rounded-xl px-3 py-2.5 text-[1.0625rem]",
5883
- onNavigate: () => setOpen(false)
5884
- },
5885
- c.href
5886
- ))
5887
- ] }, n.href) : /* @__PURE__ */ jsxRuntime.jsx(
5888
- NavLink,
5889
- {
5890
- item: n,
5891
- className: "rounded-xl px-3 py-3 text-[1.0625rem]",
5892
- onNavigate: () => setOpen(false)
5893
- },
5894
- n.href
5895
- )
5896
- ) }) : null,
5897
- family ? /* @__PURE__ */ jsxRuntime.jsxs("details", { className: cn("group", phoneNav.length > 0 && "mt-2 border-t border-border pt-4"), children: [
5898
- /* @__PURE__ */ jsxRuntime.jsxs("summary", { className: "flex cursor-pointer list-none items-center justify-between rounded-xl px-3 py-2.5 text-[1.0625rem] [&::-webkit-details-marker]:hidden", children: [
5899
- "All orangecheck sites",
5900
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { "aria-hidden": true, className: "size-4 text-muted-foreground transition-transform group-open:rotate-180" })
5901
- ] }),
5902
- /* @__PURE__ */ jsxRuntime.jsx(FamilyList, { current: current2, onNavigate: () => setOpen(false), stack: true, className: "mt-2" })
5903
- ] }) : null
5904
- ] })
5905
- ] }) : null
5906
- ] })
5907
- ]
5917
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "max-w-full truncate px-0.5", children: it.label }),
5918
+ it.badge ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: it.badge }) : null
5919
+ ]
5920
+ },
5921
+ it.href
5922
+ ))
5908
5923
  }
5909
5924
  )
5910
5925
  }
5911
5926
  );
5912
5927
  }
5913
- function SkipLink({ href = "#main-content", children = "Skip to content" }) {
5914
- return /* @__PURE__ */ jsxRuntime.jsx(
5915
- "a",
5916
- {
5917
- href,
5918
- className: "sr-only focus:not-sr-only focus:fixed focus:left-4 focus:top-3 focus:z-50 focus:rounded-full focus:border focus:border-border focus:bg-card focus:px-4 focus:py-2 focus:text-[0.9375rem] focus:font-medium focus:text-foreground focus:shadow-md",
5919
- children
5928
+ function tabsFor(groups) {
5929
+ const items = groups.flatMap((g) => g.items);
5930
+ return items.length >= 2 && items.length <= 5 && items.every((it) => it.icon) ? items : null;
5931
+ }
5932
+ var activeItem = (groups) => groups.flatMap((g) => g.items).find((it) => it.active);
5933
+ var warned = /* @__PURE__ */ new Set();
5934
+ function warnDuplicateLabels(groups) {
5935
+ if (typeof process === "undefined" || process.env.NODE_ENV === "production") return;
5936
+ const seen = /* @__PURE__ */ new Set();
5937
+ for (const it of groups.flatMap((g) => g.items)) {
5938
+ if (seen.has(it.label) && !warned.has(it.label)) {
5939
+ warned.add(it.label);
5940
+ console.warn(`AppShell: two pages are labelled "${it.label}"; give each its own name.`);
5920
5941
  }
5921
- );
5942
+ seen.add(it.label);
5943
+ }
5922
5944
  }
5923
- var BANNER_TONE = {
5924
- neutral: "border-border bg-muted",
5925
- brand: "border-[color-mix(in_oklab,var(--oca-orange)_30%,var(--border))] bg-[color-mix(in_oklab,var(--oca-orange)_9%,var(--background))]",
5926
- danger: "border-[color-mix(in_oklab,var(--destructive)_35%,var(--border))] bg-[color-mix(in_oklab,var(--destructive)_8%,var(--background))]"
5927
- };
5928
- function SiteBanner({
5929
- tone = "neutral",
5945
+ function AppShell({
5946
+ nav,
5947
+ sections,
5948
+ activeSection,
5949
+ page: pageOverride,
5950
+ persistent = [],
5951
+ home = "/",
5952
+ family,
5953
+ account,
5954
+ banner,
5955
+ footer,
5930
5956
  children,
5931
- action,
5932
- className
5933
- }) {
5934
- return /* @__PURE__ */ jsxRuntime.jsx("div", { role: "status", "aria-live": "polite", "data-tone": tone, className: cn("border-b text-[0.875rem]", BANNER_TONE[tone], className), children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "oca-container flex flex-wrap items-center justify-between gap-x-4 gap-y-1 py-2.5", children: [
5935
- /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "flex min-w-0 items-baseline gap-2.5 leading-snug", children: [
5936
- tone !== "neutral" ? /* @__PURE__ */ jsxRuntime.jsx(
5937
- "span",
5938
- {
5939
- "aria-hidden": true,
5940
- className: cn(
5941
- "size-2 shrink-0 translate-y-[-0.05em] rounded-full",
5942
- tone === "brand" ? "bg-oca-orange" : "bg-destructive"
5943
- )
5944
- }
5945
- ) : null,
5946
- /* @__PURE__ */ jsxRuntime.jsx("span", { children })
5947
- ] }),
5948
- action ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("shrink-0 font-medium", tone !== "neutral" && "max-sm:pl-[1.125rem]"), children: action }) : null
5949
- ] }) });
5950
- }
5951
- var FOOT_LINK = "inline-flex min-h-11 items-center transition-colors hover:text-foreground md:min-h-0";
5952
- function LegalRow({ links }) {
5953
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-x-6 gap-y-2 sm:flex-row sm:items-center sm:justify-between", children: [
5954
- /* @__PURE__ */ jsxRuntime.jsx("nav", { "aria-label": "Legal", children: /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "flex flex-wrap gap-x-5", children: links.map((l) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: l.href.startsWith("/") ? /* @__PURE__ */ jsxRuntime.jsx(Link8__default.default, { href: l.href, className: FOOT_LINK, children: l.label }) : /* @__PURE__ */ jsxRuntime.jsx("a", { href: l.href, className: FOOT_LINK, children: l.label }) }, l.href)) }) }),
5955
- /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
5956
- "\xA9 ",
5957
- (/* @__PURE__ */ new Date()).getFullYear(),
5958
- " OrangeCheck"
5959
- ] })
5960
- ] });
5961
- }
5962
- function SiteFooter({
5963
- columns = [],
5964
- family = false,
5965
- legal = false,
5966
- compact = false,
5967
- fineprint,
5968
- meta,
5969
- signature = true,
5970
5957
  className
5971
5958
  }) {
5972
- const legalLinks = legal === true ? LEGAL_LINKS : legal || null;
5973
- if (compact) {
5974
- return /* @__PURE__ */ jsxRuntime.jsx("footer", { className: cn("border-t border-border bg-background text-[0.875rem] text-muted-foreground", className), children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "oca-container flex flex-col gap-x-8 gap-y-3 py-5 lg:flex-row lg:items-center lg:justify-between", children: [
5975
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-x-6 gap-y-1", children: [
5976
- /* @__PURE__ */ jsxRuntime.jsx("a", { href: OCHK_IO, className: "rounded-lg text-foreground", children: /* @__PURE__ */ jsxRuntime.jsx(Lockup, { size: 22 }) }),
5977
- family ? /* @__PURE__ */ jsxRuntime.jsx("nav", { "aria-label": "Protocols", children: /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "flex flex-wrap gap-x-4", children: PROTOCOLS.map((p) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx("a", { href: p.pageHref, className: FOOT_LINK, children: p.label }) }, p.slug)) }) }) : null
5978
- ] }),
5979
- legalLinks || meta ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-x-6 gap-y-2 sm:flex-row sm:flex-wrap sm:items-center", children: [
5980
- legalLinks ? /* @__PURE__ */ jsxRuntime.jsx(LegalRow, { links: legalLinks }) : null,
5981
- meta
5982
- ] }) : null
5983
- ] }) });
5984
- }
5985
- const cols = [
5986
- ...columns,
5987
- ...family ? familyByGroup().map((g) => ({
5988
- // The lockup above already says orangecheck.
5989
- heading: g.id === "orangecheck" ? "Start here" : g.label,
5990
- links: g.sites.map((s) => ({ href: s.href, label: s.label, external: true }))
5991
- })) : []
5992
- ];
5993
- const n = cols.length;
5994
- const inline = n <= 5;
5995
- const grid = {
5996
- "--oca-footer-md": `repeat(${Math.max(1, Math.min(n, 4))}, minmax(0, 1fr))`,
5997
- "--oca-footer-lg": inline ? `minmax(0, 1.3fr) repeat(${Math.max(1, n)}, minmax(0, 1fr))` : `repeat(${Math.min(n, 6)}, minmax(0, 1fr))`
5998
- };
5999
- return /* @__PURE__ */ jsxRuntime.jsxs("footer", { className: cn("border-t border-border bg-background", className), children: [
6000
- /* @__PURE__ */ jsxRuntime.jsxs(
6001
- "div",
6002
- {
6003
- style: grid,
6004
- className: "oca-container grid grid-cols-2 gap-x-6 gap-y-10 py-14 md:grid-cols-[var(--oca-footer-md)] md:py-16 lg:grid-cols-[var(--oca-footer-lg)]",
6005
- children: [
6006
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("col-span-full flex flex-col gap-4", inline && "lg:col-span-1"), children: [
6007
- /* @__PURE__ */ jsxRuntime.jsx(Lockup, { size: 26 }),
6008
- fineprint ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "max-w-xs text-[0.9375rem] leading-relaxed text-muted-foreground", children: fineprint }) : null
6009
- ] }),
6010
- cols.map((col, i) => {
6011
- const spans = n % 2 === 1 && i === n - 1;
6012
- return /* @__PURE__ */ jsxRuntime.jsxs(
6013
- "div",
6014
- {
6015
- className: cn("flex min-w-0 flex-col gap-1", spans && "col-span-2 md:col-span-1"),
6016
- children: [
6017
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mb-2 text-[0.875rem] font-medium", children: col.heading }),
6018
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex flex-col gap-1", spans && "grid grid-cols-2 gap-x-6 md:flex md:flex-col"), children: col.links.map((l) => /* @__PURE__ */ jsxRuntime.jsx(
6019
- NavLink,
6020
- {
6021
- item: l,
6022
- className: "-mx-3 py-2.5 text-[0.9375rem] md:py-1.5"
6023
- },
6024
- l.href
6025
- )) })
6026
- ]
6027
- },
6028
- col.heading
6029
- );
6030
- })
6031
- ]
6032
- }
6033
- ),
6034
- signature ? /* @__PURE__ */ jsxRuntime.jsx("div", { "aria-hidden": true, className: "oca-container select-none overflow-hidden pb-8 md:pb-12", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-end gap-[0.18em] text-[clamp(3rem,11.5vw,10rem)] leading-[0.78] tracking-[-0.065em] [font-family:var(--oc-font-display)]", children: [
6035
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mb-[0.06em] inline-block w-[1.1em] shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(Mark, { className: "block h-auto w-full" }) }),
6036
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: "orangecheck" })
6037
- ] }) }) : null,
6038
- legalLinks || meta ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "oca-container", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3 border-t border-border py-6 text-[0.875rem] text-muted-foreground", children: [
6039
- legalLinks ? /* @__PURE__ */ jsxRuntime.jsx(LegalRow, { links: legalLinks }) : null,
6040
- meta
6041
- ] }) }) : null
6042
- ] });
6043
- }
6044
- function SignInFrame({
6045
- title = "Sign in",
6046
- lead,
6047
- children,
6048
- error,
6049
- fineprint,
6050
- brand,
6051
- home = "/",
6052
- back,
6053
- art,
6054
- caption,
6055
- className
6056
- }) {
6057
- return /* @__PURE__ */ jsxRuntime.jsxs(
6058
- "main",
5959
+ const [open, setOpen] = react.useState(false);
5960
+ const current2 = sections && sections.length > 0 ? sections.find((sec) => sec.id === activeSection) ?? sections.find((sec) => activeItem(sec.groups)) ?? sections[0] : void 0;
5961
+ const groups = current2 ? [...current2.groups, ...persistent] : [...nav ?? [], ...persistent];
5962
+ warnDuplicateLabels(groups);
5963
+ const tabs = current2 ? null : tabsFor(groups);
5964
+ const page = activeItem(groups);
5965
+ const place = react.useMemo(
5966
+ () => ({
5967
+ section: current2 ? current2.title ?? current2.label : void 0,
5968
+ page: pageOverride ?? page?.label
5969
+ }),
5970
+ [current2, page?.label, pageOverride]
5971
+ );
5972
+ const familyMenu = family ? /* @__PURE__ */ jsxRuntime.jsx(FamilyMenu, { current: typeof family === "string" ? family : void 0 }) : null;
5973
+ const switcher = sections && current2 && sections.length > 1 ? /* @__PURE__ */ jsxRuntime.jsx(SectionSwitch, { sections, current: current2, onNavigate: () => setOpen(false) }) : null;
5974
+ return /* @__PURE__ */ jsxRuntime.jsx(ShellContext.Provider, { value: place, children: /* @__PURE__ */ jsxRuntime.jsxs(
5975
+ "div",
6059
5976
  {
6060
- id: "main-content",
6061
- className: cn("grid min-h-dvh grid-cols-1 bg-background text-foreground lg:grid-cols-2", className),
5977
+ className: cn(
5978
+ "min-h-dvh bg-background",
5979
+ tabs && "max-md:pb-[calc(3.5rem_+_env(safe-area-inset-bottom))]",
5980
+ className
5981
+ ),
6062
5982
  children: [
6063
- /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "flex flex-col px-4 pb-8 pt-5 sm:px-8 lg:px-14 lg:pt-8", children: [
6064
- /* @__PURE__ */ jsxRuntime.jsxs("header", { className: "flex items-center justify-between gap-4", children: [
6065
- /* @__PURE__ */ jsxRuntime.jsxs(Link8__default.default, { href: home, className: "w-fit rounded-lg", children: [
6066
- brand ?? /* @__PURE__ */ jsxRuntime.jsx(Lockup, { size: 28 }),
6067
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: " home" })
5983
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sticky top-0 z-40 border-b border-border bg-background/90 backdrop-blur-md lg:hidden", children: [
5984
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-14 items-center gap-2 px-3", children: [
5985
+ /* @__PURE__ */ jsxRuntime.jsxs(Sheet, { open, onOpenChange: setOpen, children: [
5986
+ /* @__PURE__ */ jsxRuntime.jsx(
5987
+ SheetTrigger,
5988
+ {
5989
+ className: cn(
5990
+ "inline-flex size-10 items-center justify-center rounded-full hover:bg-accent",
5991
+ // The tab bar holds every page; the sheet is left for a footer.
5992
+ tabs && !footer && "max-md:hidden"
5993
+ ),
5994
+ "aria-label": "Open navigation",
5995
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Menu, { className: "size-5" })
5996
+ }
5997
+ ),
5998
+ /* @__PURE__ */ jsxRuntime.jsxs(SheetContent, { side: "left", className: "flex flex-col gap-6 overflow-y-auto p-4 pt-16", children: [
5999
+ /* @__PURE__ */ jsxRuntime.jsx(SheetTitle, { className: "sr-only", children: "Navigation" }),
6000
+ switcher,
6001
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: tabs ? "max-md:hidden" : void 0, children: /* @__PURE__ */ jsxRuntime.jsx(SideNav, { groups, onNavigate: () => setOpen(false) }) }),
6002
+ footer ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-auto flex flex-col gap-3", children: footer }) : null
6003
+ ] })
6068
6004
  ] }),
6069
- back === void 0 ? /* @__PURE__ */ jsxRuntime.jsx(
6070
- Link8__default.default,
6071
- {
6072
- href: home,
6073
- className: "text-[0.9375rem] text-muted-foreground underline-offset-4 hover:text-foreground hover:underline",
6074
- children: "Back to home"
6075
- }
6076
- ) : back
6005
+ /* @__PURE__ */ jsxRuntime.jsx(Link6__default.default, { href: home, "aria-label": "Home", className: "rounded-lg p-1", children: /* @__PURE__ */ jsxRuntime.jsx(Lockup, { size: 22 }) }),
6006
+ familyMenu,
6007
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ml-auto flex items-center", children: account })
6077
6008
  ] }),
6078
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mx-auto flex w-full max-w-[25rem] flex-1 flex-col justify-center gap-9 py-12", children: [
6079
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3", children: [
6080
- /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "oca-display-2", children: title }),
6081
- lead ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "oca-lead", children: lead }) : null
6009
+ place.page ? /* @__PURE__ */ jsxRuntime.jsxs(
6010
+ "div",
6011
+ {
6012
+ className: cn(
6013
+ "flex h-9 items-center gap-1.5 border-t border-border px-4 text-[0.875rem]",
6014
+ // The active tab already names the page.
6015
+ tabs && !pageOverride && "max-md:hidden"
6016
+ ),
6017
+ children: [
6018
+ place.section ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
6019
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 text-muted-foreground", children: place.section }),
6020
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { "aria-hidden": true, className: "size-3.5 shrink-0 text-muted-foreground" })
6021
+ ] }) : null,
6022
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate font-medium", children: place.page })
6023
+ ]
6024
+ }
6025
+ ) : null
6026
+ ] }),
6027
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mx-auto flex w-full max-w-[90rem]", children: [
6028
+ /* @__PURE__ */ jsxRuntime.jsxs("aside", { className: "sticky top-0 hidden h-dvh w-[17rem] shrink-0 flex-col gap-6 overflow-y-auto px-4 py-6 lg:flex", children: [
6029
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
6030
+ /* @__PURE__ */ jsxRuntime.jsx(Link6__default.default, { href: home, className: "px-2", "aria-label": "Home", children: /* @__PURE__ */ jsxRuntime.jsx(Lockup, { size: 26 }) }),
6031
+ familyMenu
6082
6032
  ] }),
6083
- /* @__PURE__ */ jsxRuntime.jsx("div", { children }),
6084
- error ? /* @__PURE__ */ jsxRuntime.jsx("p", { role: "alert", className: "text-[0.9375rem] text-destructive", children: error }) : null,
6085
- fineprint ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[0.8125rem] leading-relaxed text-muted-foreground", children: fineprint }) : null
6033
+ switcher,
6034
+ /* @__PURE__ */ jsxRuntime.jsx(SideNav, { groups }),
6035
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-auto flex flex-col gap-3", children: footer })
6036
+ ] }),
6037
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-1 flex-col", children: [
6038
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden h-[4.5rem] items-center justify-end gap-3 px-8 lg:flex", children: account }),
6039
+ banner ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 pb-2 pt-4 md:px-8 lg:pt-0", children: banner }) : null,
6040
+ /* @__PURE__ */ jsxRuntime.jsx("main", { id: "main-content", className: "flex-1 px-4 pb-16 pt-6 md:px-8 lg:pt-2", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-auto w-full max-w-[72rem]", children }) })
6086
6041
  ] })
6087
6042
  ] }),
6088
- /* @__PURE__ */ jsxRuntime.jsxs(
6089
- "aside",
6090
- {
6091
- "aria-hidden": true,
6092
- className: "relative hidden flex-col justify-between gap-10 overflow-hidden border-l border-[var(--oca-band-line)] bg-oca-ink p-14 text-oca-ink-foreground lg:flex",
6093
- children: [
6094
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-1 items-center justify-center", children: art ?? /* @__PURE__ */ jsxRuntime.jsx(IsoCheck, { size: 340, settle: true, tilt: true, className: "max-w-full" }) }),
6095
- caption ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex max-w-[24rem] flex-col gap-3", children: caption }) : null
6096
- ]
6097
- }
6098
- )
6043
+ tabs ? /* @__PURE__ */ jsxRuntime.jsx(TabBar, { items: tabs }) : null
6099
6044
  ]
6100
6045
  }
6101
- );
6102
- }
6103
- var STATUS_WORDS = /* @__PURE__ */ new Set(["live", "testing", "not-yet", "paused", "good", "caution", "refused"]);
6104
- var pathOf = (href) => href.split(/[?#]/)[0].replace(/(.)\/$/, "$1");
6105
- function DocsNav({
6106
- sections,
6107
- current: current2,
6108
- onNavigate,
6109
- className
6110
- }) {
6111
- const here = pathOf(current2);
6112
- const activeSection = react.useMemo(
6113
- () => sections.findIndex((s) => s.items.some((i) => pathOf(i.href) === here)),
6114
- [sections, here]
6115
- );
6116
- const [peeked, setPeeked] = react.useState(() => /* @__PURE__ */ new Set());
6117
- react.useEffect(() => setPeeked(/* @__PURE__ */ new Set()), [activeSection]);
6118
- const activeRef = react.useRef(null);
6119
- react.useEffect(() => {
6120
- const id = requestAnimationFrame(() => activeRef.current?.scrollIntoView({ block: "nearest" }));
6121
- return () => cancelAnimationFrame(id);
6122
- }, [here]);
6123
- const base = react.useId();
6124
- return /* @__PURE__ */ jsxRuntime.jsx("nav", { "aria-label": "Docs", className: cn("flex flex-col gap-0.5", className), children: sections.map((section, si) => {
6125
- const isActive = si === activeSection;
6126
- const open = isActive || peeked.has(si);
6127
- const panel = `${base}-s${si}`;
6128
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
6129
- /* @__PURE__ */ jsxRuntime.jsxs(
6130
- "button",
6131
- {
6132
- type: "button",
6133
- "aria-expanded": open,
6134
- "aria-controls": panel,
6135
- onClick: () => {
6136
- if (isActive) return;
6137
- setPeeked((p) => {
6138
- const n = new Set(p);
6139
- if (n.has(si)) n.delete(si);
6140
- else n.add(si);
6141
- return n;
6142
- });
6143
- },
6144
- className: cn(
6145
- "flex min-h-9 w-full items-center justify-between gap-2 rounded-lg px-2.5 py-1.5 text-left text-[0.875rem] transition-colors",
6146
- isActive ? "font-medium text-foreground" : "text-muted-foreground hover:bg-accent hover:text-foreground",
6147
- isActive && "cursor-default"
6148
- ),
6149
- children: [
6150
- section.label,
6151
- /* @__PURE__ */ jsxRuntime.jsx(
6152
- lucideReact.ChevronRight,
6153
- {
6154
- "aria-hidden": true,
6155
- className: cn("size-3.5 shrink-0 text-oca-subtle transition-transform duration-200", open && "rotate-90")
6156
- }
6157
- )
6158
- ]
6159
- }
6160
- ),
6161
- /* @__PURE__ */ jsxRuntime.jsx("ul", { id: panel, hidden: !open, className: "mb-2 ml-2.5 mt-0.5 border-l border-border", children: section.items.map((item) => {
6162
- const on = pathOf(item.href) === here;
6163
- const badge = typeof item.badge === "string" && STATUS_WORDS.has(item.badge) ? /* @__PURE__ */ jsxRuntime.jsx(StatusBadge, { status: item.badge }) : item.badge ? /* @__PURE__ */ jsxRuntime.jsx(Badge, { tone: "muted", children: item.badge }) : null;
6164
- return /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsxs(
6165
- Link8__default.default,
6166
- {
6167
- href: item.href,
6168
- ref: on ? activeRef : void 0,
6169
- onClick: onNavigate,
6170
- "aria-current": on ? "page" : void 0,
6171
- className: cn(
6172
- "-ml-px flex min-h-9 items-center gap-2 border-l-2 py-1.5 pl-3.5 pr-2 text-[0.875rem] leading-snug transition-colors",
6173
- on ? "border-foreground font-medium text-foreground" : "border-transparent text-muted-foreground hover:border-oca-hairline-strong hover:text-foreground"
6174
- ),
6175
- children: [
6176
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1", children: item.label }),
6177
- badge
6178
- ]
6179
- }
6180
- ) }, item.href);
6181
- }) })
6182
- ] }, section.label);
6183
- }) });
6046
+ ) });
6184
6047
  }
6185
- var DOCS_HEADER_NAV = OCHK_IO_NAV.map((n) => n.href === DOCS_HREF ? { ...n, active: true } : n);
6186
- function DocsShell({
6187
- nav,
6188
- current: current2,
6189
- header,
6190
- search,
6191
- actions,
6192
- breadcrumbs,
6193
- toc,
6194
- pager,
6195
- footer,
6196
- children
6048
+ function AccountMenu({
6049
+ name,
6050
+ detail,
6051
+ items,
6052
+ nameFrom = "sm"
6197
6053
  }) {
6198
- const [menu, setMenu] = react.useState(false);
6199
- react.useEffect(() => setMenu(false), [current2]);
6200
- const read = useHeadings("#docs-content", current2);
6201
- const items = toc ?? read.items;
6202
- const activeId = toc ? void 0 : read.activeId;
6203
- const here = pathOf(current2);
6204
- const place = react.useMemo(() => {
6205
- for (const s of nav) {
6206
- const it = s.items.find((i) => pathOf(i.href) === here);
6207
- if (it) return { section: s.label, page: it.label };
6208
- }
6209
- return null;
6210
- }, [nav, here]);
6211
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-h-dvh flex-col bg-background", children: [
6212
- /* @__PURE__ */ jsxRuntime.jsx(SkipLink, {}),
6213
- header ?? /* @__PURE__ */ jsxRuntime.jsx(SiteHeader, { home: OCHK_IO, family: "docs", nav: DOCS_HEADER_NAV, search, actions }),
6214
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "sticky top-16 z-30 border-b border-border bg-background/95 backdrop-blur-md supports-[backdrop-filter]:bg-background/90 md:top-[4.5rem] lg:hidden", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "oca-container flex h-12 items-center gap-2", children: /* @__PURE__ */ jsxRuntime.jsxs(Sheet, { open: menu, onOpenChange: setMenu, children: [
6215
- /* @__PURE__ */ jsxRuntime.jsxs(SheetTrigger, { className: "-ml-2 inline-flex h-10 min-w-0 items-center gap-2 rounded-full px-2.5 text-[0.875rem] hover:bg-accent", children: [
6216
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PanelLeft, { "aria-hidden": true, className: "size-[1.125rem] shrink-0" }),
6217
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Docs menu. " }),
6218
- place ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 items-center gap-1.5", children: [
6219
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 text-muted-foreground", children: place.section }),
6220
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { "aria-hidden": true, className: "size-3.5 shrink-0 text-oca-subtle" }),
6221
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate font-medium", children: place.page })
6222
- ] }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: "Docs" })
6223
- ] }),
6224
- /* @__PURE__ */ jsxRuntime.jsxs(SheetContent, { side: "left", className: "w-[min(88vw,22rem)] gap-0 p-0", children: [
6225
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-b border-border px-5 py-4 pr-14", children: /* @__PURE__ */ jsxRuntime.jsx(SheetTitle, { className: "text-[1.0625rem] font-medium", children: "Docs" }) }),
6226
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-y-auto p-3", children: /* @__PURE__ */ jsxRuntime.jsx(DocsNav, { sections: nav, current: current2, onNavigate: () => setMenu(false) }) })
6227
- ] })
6228
- ] }) }) }),
6229
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "oca-container flex-1", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "lg:grid lg:grid-cols-[13.5rem_minmax(0,1fr)] lg:gap-x-10 xl:grid-cols-[13.5rem_minmax(0,1fr)_11rem]", children: [
6230
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "sticky top-[4.5rem] hidden max-h-[calc(100dvh-4.5rem)] self-start overflow-y-auto overscroll-contain py-8 pr-1 lg:block", children: /* @__PURE__ */ jsxRuntime.jsx(DocsNav, { sections: nav, current: current2 }) }),
6231
- /* @__PURE__ */ jsxRuntime.jsxs("main", { id: "main-content", className: "min-w-0 pb-16 pt-6 md:pt-8", children: [
6232
- breadcrumbs ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-6 max-lg:hidden", children: breadcrumbs }) : null,
6233
- items.length > 1 ? /* @__PURE__ */ jsxRuntime.jsxs("details", { className: "group mb-8 rounded-2xl border border-border bg-card xl:hidden", children: [
6234
- /* @__PURE__ */ jsxRuntime.jsxs("summary", { className: "flex min-h-12 cursor-pointer list-none items-center justify-between px-4 text-[0.9375rem] font-medium [&::-webkit-details-marker]:hidden", children: [
6235
- "On this page",
6236
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { "aria-hidden": true, className: "size-4 text-muted-foreground transition-transform group-open:rotate-180" })
6237
- ] }),
6238
- /* @__PURE__ */ jsxRuntime.jsx(OnThisPage, { items, activeId, title: null, className: "px-4 pb-4" })
6239
- ] }) : null,
6240
- /* @__PURE__ */ jsxRuntime.jsx("article", { id: "docs-content", className: "max-w-[46rem]", children }),
6241
- pager ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-16 max-w-[46rem]", children: pager }) : null
6242
- ] }),
6243
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "sticky top-[4.5rem] hidden max-h-[calc(100dvh-4.5rem)] self-start overflow-y-auto py-10 xl:block", children: items.length > 1 ? /* @__PURE__ */ jsxRuntime.jsx(OnThisPage, { items, activeId }) : null })
6244
- ] }) }),
6245
- footer ?? /* @__PURE__ */ jsxRuntime.jsx(SiteFooter, { columns: OCHK_IO_FOOTER, family: true, legal: true, signature: false })
6246
- ] });
6247
- }
6248
- function SideNav({ groups, onNavigate }) {
6249
- return /* @__PURE__ */ jsxRuntime.jsx("nav", { "aria-label": "Pages", className: "flex flex-col gap-5", children: groups.map((g, gi) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-0.5", children: [
6250
- g.label ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "px-3 pb-1 text-[0.8125rem] text-muted-foreground", children: g.label }) : null,
6251
- g.items.map((it) => /* @__PURE__ */ jsxRuntime.jsxs(
6252
- Link8__default.default,
6054
+ const initial = name.trim().charAt(0).toUpperCase() || "\xB7";
6055
+ return /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenu, { children: [
6056
+ /* @__PURE__ */ jsxRuntime.jsxs(
6057
+ DropdownMenuTrigger,
6253
6058
  {
6254
- href: it.href,
6255
- onClick: onNavigate,
6256
- "aria-current": it.active ? "page" : void 0,
6257
6059
  className: cn(
6258
- "flex h-9 items-center gap-3 rounded-xl px-3 text-[0.9375rem] transition-colors",
6259
- "[&_svg]:size-[1.0625rem] [&_svg]:shrink-0",
6260
- it.active ? "bg-card text-foreground shadow-sm ring-1 ring-border [&_svg]:text-foreground" : "text-muted-foreground hover:bg-accent hover:text-foreground"
6060
+ "inline-flex h-10 items-center gap-2.5 rounded-full border border-border bg-card pl-1 pr-1 text-[0.9375rem] outline-none transition-colors hover:border-oca-hairline-strong focus-visible:ring-2 focus-visible:ring-ring",
6061
+ nameFrom === "lg" ? "lg:pr-3.5" : "sm:pr-3.5"
6261
6062
  ),
6063
+ "aria-label": `${name}, account menu`,
6262
6064
  children: [
6263
- it.icon,
6264
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate", children: it.label }),
6265
- it.badge ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0", children: it.badge }) : null
6065
+ /* @__PURE__ */ jsxRuntime.jsx(
6066
+ "span",
6067
+ {
6068
+ "aria-hidden": true,
6069
+ "data-initial": initial,
6070
+ className: "flex size-8 items-center justify-center rounded-full bg-foreground text-[0.8125rem] font-medium text-background before:content-[attr(data-initial)]"
6071
+ }
6072
+ ),
6073
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("max-w-[10rem] truncate", nameFrom === "lg" ? "max-lg:hidden" : "max-sm:hidden"), children: name })
6266
6074
  ]
6267
- },
6268
- it.href
6269
- ))
6270
- ] }, g.label ?? gi)) });
6075
+ }
6076
+ ),
6077
+ /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenuContent, { align: "end", className: "w-64", children: [
6078
+ /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenuLabel, { className: "flex flex-col gap-0.5", children: [
6079
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-[0.9375rem] font-medium text-foreground", children: name }),
6080
+ detail ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate font-mono text-[0.75rem]", children: detail }) : null
6081
+ ] }),
6082
+ /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuSeparator, {}),
6083
+ items.map(
6084
+ (it, i) => it === "separator" ? /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuSeparator, {}, `sep-${i}`) : it.href ? /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuItem, { asChild: true, destructive: it.destructive, children: /* @__PURE__ */ jsxRuntime.jsxs(Link6__default.default, { href: it.href, children: [
6085
+ it.icon,
6086
+ it.label
6087
+ ] }) }, it.label) : /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenuItem, { onSelect: it.onSelect, destructive: it.destructive, children: [
6088
+ it.icon,
6089
+ it.label
6090
+ ] }, it.label)
6091
+ )
6092
+ ] })
6093
+ ] });
6271
6094
  }
6272
- function SectionSwitch({
6273
- sections,
6274
- current: current2,
6275
- onNavigate
6276
- }) {
6277
- const cols = sections.length <= 3 ? sections.length : 2;
6095
+ function ThemeToggle({ className }) {
6096
+ const { theme, setTheme } = nextThemes.useTheme();
6097
+ const [mounted, setMounted] = react.useState(false);
6098
+ react.useEffect(() => setMounted(true), []);
6099
+ const current2 = mounted ? theme ?? "system" : "system";
6100
+ const next = current2 === "light" ? "dark" : current2 === "dark" ? "system" : "light";
6101
+ const Icon2 = current2 === "light" ? lucideReact.Sun : current2 === "dark" ? lucideReact.Moon : lucideReact.SunMoon;
6278
6102
  return /* @__PURE__ */ jsxRuntime.jsx(
6279
- "nav",
6103
+ "button",
6280
6104
  {
6281
- "aria-label": "Sections",
6282
- className: cn("grid gap-1 bg-muted p-1", cols === sections.length ? "rounded-full" : "rounded-[1.25rem]"),
6283
- style: { gridTemplateColumns: `repeat(${cols}, minmax(0, 1fr))` },
6284
- children: sections.map((sec) => {
6285
- const on = sec.id === current2.id;
6286
- return /* @__PURE__ */ jsxRuntime.jsx(
6287
- Link8__default.default,
6288
- {
6289
- href: sec.href,
6290
- onClick: onNavigate,
6291
- "aria-current": on ? "true" : void 0,
6292
- className: cn(
6293
- "flex h-8 min-w-0 items-center justify-center rounded-full px-1.5 text-[0.8125rem] font-medium transition-colors",
6294
- on ? "bg-card text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"
6295
- ),
6296
- children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: sec.label })
6297
- },
6298
- sec.id
6299
- );
6300
- })
6105
+ type: "button",
6106
+ onClick: () => setTheme(next),
6107
+ "aria-label": `Theme: ${current2}. Switch to ${next}`,
6108
+ title: `Theme: ${current2}`,
6109
+ className: cn(
6110
+ "inline-flex size-10 items-center justify-center rounded-full text-muted-foreground transition-colors hover:bg-accent hover:text-foreground",
6111
+ className
6112
+ ),
6113
+ children: /* @__PURE__ */ jsxRuntime.jsx(Icon2, { className: "size-[1.125rem]" })
6301
6114
  }
6302
6115
  );
6303
6116
  }
6304
- function TabBar({ items }) {
6117
+ function NavLink({
6118
+ item,
6119
+ className,
6120
+ onNavigate,
6121
+ line = false
6122
+ }) {
6123
+ const cls = cn(
6124
+ "rounded-full px-3 py-2 text-[0.9375rem] transition-colors",
6125
+ item.active ? "text-foreground" : "text-muted-foreground hover:text-foreground",
6126
+ line && "relative after:absolute after:inset-x-3 after:-bottom-[0.625rem] after:h-0.5 after:rounded-full",
6127
+ line && item.active && "after:bg-foreground",
6128
+ className
6129
+ );
6130
+ if (item.external) {
6131
+ return /* @__PURE__ */ jsxRuntime.jsx("a", { href: item.href, className: cls, rel: "noreferrer", onClick: onNavigate, children: item.label });
6132
+ }
6133
+ return /* @__PURE__ */ jsxRuntime.jsx(Link6__default.default, { href: item.href, className: cls, "aria-current": item.active ? "page" : void 0, onClick: onNavigate, children: item.label });
6134
+ }
6135
+ function NavRow({ item, onNavigate }) {
6136
+ const body = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
6137
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[0.9375rem] font-medium leading-6 text-foreground", children: item.label }),
6138
+ item.description ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[0.8125rem] leading-snug text-muted-foreground", children: item.description }) : null
6139
+ ] });
6140
+ const cls = cn(
6141
+ "flex flex-col gap-0.5 rounded-xl px-3 py-2 transition-colors hover:bg-accent",
6142
+ item.active && "bg-muted hover:bg-muted dark:bg-white/[0.06]"
6143
+ );
6144
+ return item.external ? /* @__PURE__ */ jsxRuntime.jsx("a", { href: item.href, className: cls, rel: "noreferrer", onClick: onNavigate, children: body }) : /* @__PURE__ */ jsxRuntime.jsx(Link6__default.default, { href: item.href, className: cls, "aria-current": item.active ? "page" : void 0, onClick: onNavigate, children: body });
6145
+ }
6146
+ var seeAll = (item) => typeof item.label === "string" ? `All ${item.label.toLowerCase()}` : "See all";
6147
+ function NavDropdown({ item }) {
6148
+ const [open, setOpen] = react.useState(false);
6149
+ const active = item.active || item.children?.some((c) => c.active);
6150
+ return /* @__PURE__ */ jsxRuntime.jsxs(Popover, { open, onOpenChange: setOpen, children: [
6151
+ /* @__PURE__ */ jsxRuntime.jsxs(
6152
+ PopoverTrigger,
6153
+ {
6154
+ className: cn(
6155
+ "group inline-flex items-center gap-1 rounded-full py-2 pl-3 pr-2.5 text-[0.9375rem] transition-colors md:max-lg:pl-2.5 md:max-lg:pr-2",
6156
+ active ? "text-foreground" : "text-muted-foreground hover:text-foreground data-[state=open]:text-foreground"
6157
+ ),
6158
+ children: [
6159
+ item.label,
6160
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { "aria-hidden": true, className: "size-3.5 transition-transform duration-200 group-data-[state=open]:rotate-180" })
6161
+ ]
6162
+ }
6163
+ ),
6164
+ /* @__PURE__ */ jsxRuntime.jsxs(PopoverContent, { align: "center", sideOffset: 10, className: "w-[min(calc(100vw-2rem),26rem)] p-2", children: [
6165
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "flex flex-col", children: item.children?.map((c) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx(NavRow, { item: c, onNavigate: () => setOpen(false) }) }, c.href)) }),
6166
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1.5 border-t border-border px-1 pt-1.5", children: /* @__PURE__ */ jsxRuntime.jsx(
6167
+ NavLink,
6168
+ {
6169
+ item: { ...item, label: seeAll(item), children: void 0 },
6170
+ className: "block rounded-xl px-2 py-2 text-[0.875rem]",
6171
+ onNavigate: () => setOpen(false)
6172
+ }
6173
+ ) })
6174
+ ] })
6175
+ ] });
6176
+ }
6177
+ function SiteHeader({
6178
+ home = "/",
6179
+ brand,
6180
+ product,
6181
+ family,
6182
+ nav = [],
6183
+ search,
6184
+ actions,
6185
+ variant = "site",
6186
+ navOnPhone = true,
6187
+ menu: menuExtra,
6188
+ className
6189
+ }) {
6190
+ const [open, setOpen] = react.useState(false);
6191
+ const tool = variant === "tool";
6192
+ const size = tool ? 24 : 28;
6193
+ const current2 = typeof family === "string" ? family : void 0;
6194
+ const phoneNav = navOnPhone ? nav : [];
6195
+ const menu = phoneNav.length > 0 || Boolean(family) || Boolean(menuExtra);
6196
+ const brandNode = brand ?? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center", children: [
6197
+ /* @__PURE__ */ jsxRuntime.jsx(Lockup, { size }),
6198
+ product ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
6199
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: "mx-3 h-5 w-px bg-oca-hairline-strong" }),
6200
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium tracking-[-0.01em]", style: { fontSize: size * 0.56 }, children: product })
6201
+ ] }) : null
6202
+ ] });
6203
+ const navigation = nav.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("nav", { "aria-label": "Main", className: "hidden items-center gap-1 md:flex", children: nav.map(
6204
+ (n) => n.children?.length ? /* @__PURE__ */ jsxRuntime.jsx(NavDropdown, { item: n }, n.href) : (
6205
+ // Between md and lg the family menu and the actions share the row: tighter.
6206
+ /* @__PURE__ */ jsxRuntime.jsx(NavLink, { item: n, line: tool, className: tool ? void 0 : "md:max-lg:px-2.5" }, n.href)
6207
+ )
6208
+ ) }) : null;
6305
6209
  return /* @__PURE__ */ jsxRuntime.jsx(
6306
- "nav",
6210
+ "header",
6307
6211
  {
6308
- "aria-label": "Pages",
6309
- "data-oca-tabbar": "",
6310
- 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",
6311
- children: /* @__PURE__ */ jsxRuntime.jsx(
6212
+ className: cn(
6213
+ "sticky top-0 z-40 w-full border-b bg-background/95 backdrop-blur-md supports-[backdrop-filter]:bg-background/90",
6214
+ tool ? "border-border" : "border-transparent",
6215
+ className
6216
+ ),
6217
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
6312
6218
  "div",
6313
6219
  {
6314
- className: "mx-auto grid h-14 max-w-[32rem] px-1.5",
6315
- style: { gridTemplateColumns: `repeat(${items.length}, minmax(0, 1fr))` },
6316
- children: items.map((it) => /* @__PURE__ */ jsxRuntime.jsxs(
6317
- Link8__default.default,
6318
- {
6319
- href: it.href,
6320
- "aria-current": it.active ? "page" : void 0,
6321
- className: cn(
6322
- "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",
6323
- it.active ? "text-foreground" : "text-muted-foreground hover:text-foreground"
6324
- ),
6325
- children: [
6326
- /* @__PURE__ */ jsxRuntime.jsxs(
6327
- "span",
6220
+ className: cn(
6221
+ "flex items-center justify-between gap-4",
6222
+ tool ? "h-14 px-4 md:px-6" : "oca-container h-16 md:h-[4.5rem] md:max-lg:gap-2",
6223
+ // Three columns, the outer two each at least their content: the
6224
+ // navigation stays centred whatever the actions hold, so it does
6225
+ // not shift when they change (signed out to signed in).
6226
+ !tool && nav.length > 0 && "md:grid md:grid-cols-[minmax(max-content,1fr)_auto_minmax(max-content,1fr)]"
6227
+ ),
6228
+ children: [
6229
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex min-w-0 items-center gap-1", tool ? "md:gap-1" : "justify-self-start"), children: [
6230
+ /* @__PURE__ */ jsxRuntime.jsxs(Link6__default.default, { href: home, className: "-ml-1 min-w-0 rounded-lg p-1", children: [
6231
+ brandNode,
6232
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: " home" })
6233
+ ] }),
6234
+ family ? /* @__PURE__ */ jsxRuntime.jsx(FamilyMenu, { current: current2, className: "max-md:hidden" }) : null,
6235
+ tool && navigation ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ml-5", children: navigation }) : null
6236
+ ] }),
6237
+ !tool ? navigation : null,
6238
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 justify-self-end", children: [
6239
+ search,
6240
+ actions,
6241
+ menu ? /* @__PURE__ */ jsxRuntime.jsxs(Sheet, { open, onOpenChange: setOpen, children: [
6242
+ /* @__PURE__ */ jsxRuntime.jsx(
6243
+ SheetTrigger,
6328
6244
  {
6329
- className: cn(
6330
- "relative flex h-7 w-12 items-center justify-center rounded-full transition-[background-color,box-shadow] duration-200",
6331
- "[&_svg]:size-[1.125rem] [&_svg]:shrink-0",
6332
- it.active ? "bg-card shadow-sm ring-1 ring-border [&_svg]:stroke-2" : "[&_svg]:stroke-[1.75]"
6333
- ),
6334
- children: [
6335
- it.icon,
6336
- 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
6337
- ]
6245
+ className: "inline-flex size-10 items-center justify-center rounded-full text-foreground hover:bg-accent md:hidden",
6246
+ "aria-label": "Open menu",
6247
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Menu, { className: "size-5" })
6338
6248
  }
6339
6249
  ),
6340
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "max-w-full truncate px-0.5", children: it.label }),
6341
- it.badge ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: it.badge }) : null
6342
- ]
6343
- },
6344
- it.href
6345
- ))
6250
+ /* @__PURE__ */ jsxRuntime.jsxs(SheetContent, { side: "right", className: "pt-16", children: [
6251
+ /* @__PURE__ */ jsxRuntime.jsx(SheetTitle, { className: "sr-only", children: "Menu" }),
6252
+ menuExtra ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex flex-col", (phoneNav.length > 0 || family) && "border-b border-border pb-3"), children: menuExtra }) : null,
6253
+ phoneNav.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("nav", { "aria-label": "Main", className: "flex flex-col", children: phoneNav.map(
6254
+ (n) => n.children?.length ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col py-2", children: [
6255
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "px-3 pb-1 text-[0.8125rem] text-muted-foreground", children: n.label }),
6256
+ n.children.map((c) => /* @__PURE__ */ jsxRuntime.jsx(
6257
+ NavLink,
6258
+ {
6259
+ item: c,
6260
+ className: "rounded-xl px-3 py-2.5 text-[1.0625rem]",
6261
+ onNavigate: () => setOpen(false)
6262
+ },
6263
+ c.href
6264
+ ))
6265
+ ] }, n.href) : /* @__PURE__ */ jsxRuntime.jsx(
6266
+ NavLink,
6267
+ {
6268
+ item: n,
6269
+ className: "rounded-xl px-3 py-3 text-[1.0625rem]",
6270
+ onNavigate: () => setOpen(false)
6271
+ },
6272
+ n.href
6273
+ )
6274
+ ) }) : null,
6275
+ family ? /* @__PURE__ */ jsxRuntime.jsxs("details", { className: cn("group", phoneNav.length > 0 && "mt-2 border-t border-border pt-4"), children: [
6276
+ /* @__PURE__ */ jsxRuntime.jsxs("summary", { className: "flex cursor-pointer list-none items-center justify-between rounded-xl px-3 py-2.5 text-[1.0625rem] [&::-webkit-details-marker]:hidden", children: [
6277
+ "All orangecheck sites",
6278
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { "aria-hidden": true, className: "size-4 text-muted-foreground transition-transform group-open:rotate-180" })
6279
+ ] }),
6280
+ /* @__PURE__ */ jsxRuntime.jsx(FamilyList, { current: current2, onNavigate: () => setOpen(false), stack: true, className: "mt-2" })
6281
+ ] }) : null
6282
+ ] })
6283
+ ] }) : null
6284
+ ] })
6285
+ ]
6346
6286
  }
6347
6287
  )
6348
6288
  }
6349
6289
  );
6350
6290
  }
6351
- function tabsFor(groups) {
6352
- const items = groups.flatMap((g) => g.items);
6353
- return items.length >= 2 && items.length <= 5 && items.every((it) => it.icon) ? items : null;
6354
- }
6355
- var activeItem = (groups) => groups.flatMap((g) => g.items).find((it) => it.active);
6356
- var warned = /* @__PURE__ */ new Set();
6357
- function warnDuplicateLabels(groups) {
6358
- if (typeof process === "undefined" || process.env.NODE_ENV === "production") return;
6359
- const seen = /* @__PURE__ */ new Set();
6360
- for (const it of groups.flatMap((g) => g.items)) {
6361
- if (seen.has(it.label) && !warned.has(it.label)) {
6362
- warned.add(it.label);
6363
- console.warn(`AppShell: two pages are labelled "${it.label}"; give each its own name.`);
6291
+ function SkipLink({ href = "#main-content", children = "Skip to content" }) {
6292
+ return /* @__PURE__ */ jsxRuntime.jsx(
6293
+ "a",
6294
+ {
6295
+ href,
6296
+ className: "sr-only focus:not-sr-only focus:fixed focus:left-4 focus:top-3 focus:z-50 focus:rounded-full focus:border focus:border-border focus:bg-card focus:px-4 focus:py-2 focus:text-[0.9375rem] focus:font-medium focus:text-foreground focus:shadow-md",
6297
+ children
6364
6298
  }
6365
- seen.add(it.label);
6366
- }
6299
+ );
6367
6300
  }
6368
- function AppShell({
6369
- nav,
6370
- sections,
6371
- activeSection,
6372
- page: pageOverride,
6373
- persistent = [],
6374
- home = "/",
6375
- account,
6376
- banner,
6377
- footer,
6301
+ var BANNER_TONE = {
6302
+ neutral: "border-border bg-muted",
6303
+ brand: "border-[color-mix(in_oklab,var(--oca-orange)_30%,var(--border))] bg-[color-mix(in_oklab,var(--oca-orange)_9%,var(--background))]",
6304
+ danger: "border-[color-mix(in_oklab,var(--destructive)_35%,var(--border))] bg-[color-mix(in_oklab,var(--destructive)_8%,var(--background))]"
6305
+ };
6306
+ function SiteBanner({
6307
+ tone = "neutral",
6378
6308
  children,
6309
+ action,
6379
6310
  className
6380
6311
  }) {
6381
- const [open, setOpen] = react.useState(false);
6382
- const current2 = sections && sections.length > 0 ? sections.find((sec) => sec.id === activeSection) ?? sections.find((sec) => activeItem(sec.groups)) ?? sections[0] : void 0;
6383
- const groups = current2 ? [...current2.groups, ...persistent] : [...nav ?? [], ...persistent];
6384
- warnDuplicateLabels(groups);
6385
- const tabs = current2 ? null : tabsFor(groups);
6386
- const page = activeItem(groups);
6387
- const place = react.useMemo(
6388
- () => ({
6389
- section: current2 ? current2.title ?? current2.label : void 0,
6390
- page: pageOverride ?? page?.label
6391
- }),
6392
- [current2, page?.label, pageOverride]
6393
- );
6394
- const switcher = sections && current2 && sections.length > 1 ? /* @__PURE__ */ jsxRuntime.jsx(SectionSwitch, { sections, current: current2, onNavigate: () => setOpen(false) }) : null;
6395
- return /* @__PURE__ */ jsxRuntime.jsx(ShellContext.Provider, { value: place, children: /* @__PURE__ */ jsxRuntime.jsxs(
6396
- "div",
6397
- {
6398
- className: cn(
6399
- "min-h-dvh bg-background",
6400
- tabs && "max-md:pb-[calc(3.5rem_+_env(safe-area-inset-bottom))]",
6401
- className
6402
- ),
6403
- children: [
6404
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sticky top-0 z-40 border-b border-border bg-background/90 backdrop-blur-md lg:hidden", children: [
6405
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-14 items-center gap-2 px-3", children: [
6406
- /* @__PURE__ */ jsxRuntime.jsxs(Sheet, { open, onOpenChange: setOpen, children: [
6407
- /* @__PURE__ */ jsxRuntime.jsx(
6408
- SheetTrigger,
6409
- {
6410
- className: cn(
6411
- "inline-flex size-10 items-center justify-center rounded-full hover:bg-accent",
6412
- // The tab bar holds every page; the sheet is left for a footer.
6413
- tabs && !footer && "max-md:hidden"
6414
- ),
6415
- "aria-label": "Open navigation",
6416
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Menu, { className: "size-5" })
6417
- }
6418
- ),
6419
- /* @__PURE__ */ jsxRuntime.jsxs(SheetContent, { side: "left", className: "flex flex-col gap-6 overflow-y-auto p-4 pt-16", children: [
6420
- /* @__PURE__ */ jsxRuntime.jsx(SheetTitle, { className: "sr-only", children: "Navigation" }),
6421
- switcher,
6422
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: tabs ? "max-md:hidden" : void 0, children: /* @__PURE__ */ jsxRuntime.jsx(SideNav, { groups, onNavigate: () => setOpen(false) }) }),
6423
- footer ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-auto flex flex-col gap-3", children: footer }) : null
6424
- ] })
6425
- ] }),
6426
- /* @__PURE__ */ jsxRuntime.jsx(Link8__default.default, { href: home, "aria-label": "Home", className: "rounded-lg p-1", children: /* @__PURE__ */ jsxRuntime.jsx(Lockup, { size: 22 }) }),
6427
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ml-auto flex items-center", children: account })
6312
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { role: "status", "aria-live": "polite", "data-tone": tone, className: cn("border-b text-[0.875rem]", BANNER_TONE[tone], className), children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "oca-container flex flex-wrap items-center justify-between gap-x-4 gap-y-1 py-2.5", children: [
6313
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "flex min-w-0 items-baseline gap-2.5 leading-snug", children: [
6314
+ tone !== "neutral" ? /* @__PURE__ */ jsxRuntime.jsx(
6315
+ "span",
6316
+ {
6317
+ "aria-hidden": true,
6318
+ className: cn(
6319
+ "size-2 shrink-0 translate-y-[-0.05em] rounded-full",
6320
+ tone === "brand" ? "bg-oca-orange" : "bg-destructive"
6321
+ )
6322
+ }
6323
+ ) : null,
6324
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children })
6325
+ ] }),
6326
+ action ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("shrink-0 font-medium", tone !== "neutral" && "max-sm:pl-[1.125rem]"), children: action }) : null
6327
+ ] }) });
6328
+ }
6329
+ var FOOT_LINK = "inline-flex min-h-11 items-center transition-colors hover:text-foreground md:min-h-0";
6330
+ function LegalRow({ links }) {
6331
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-x-6 gap-y-2 sm:flex-row sm:items-center sm:justify-between", children: [
6332
+ /* @__PURE__ */ jsxRuntime.jsx("nav", { "aria-label": "Legal", children: /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "flex flex-wrap gap-x-5", children: links.map((l) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: l.href.startsWith("/") ? /* @__PURE__ */ jsxRuntime.jsx(Link6__default.default, { href: l.href, className: FOOT_LINK, children: l.label }) : /* @__PURE__ */ jsxRuntime.jsx("a", { href: l.href, className: FOOT_LINK, children: l.label }) }, l.href)) }) }),
6333
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
6334
+ "\xA9 ",
6335
+ (/* @__PURE__ */ new Date()).getFullYear(),
6336
+ " OrangeCheck"
6337
+ ] })
6338
+ ] });
6339
+ }
6340
+ function SiteFooter({
6341
+ columns = [],
6342
+ family = false,
6343
+ legal = false,
6344
+ compact = false,
6345
+ fineprint,
6346
+ meta,
6347
+ signature = true,
6348
+ className
6349
+ }) {
6350
+ const legalLinks = legal === true ? LEGAL_LINKS : legal || null;
6351
+ if (compact) {
6352
+ return /* @__PURE__ */ jsxRuntime.jsx("footer", { className: cn("border-t border-border bg-background text-[0.875rem] text-muted-foreground", className), children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "oca-container flex flex-col gap-x-8 gap-y-3 py-5 lg:flex-row lg:items-center lg:justify-between", children: [
6353
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-x-6 gap-y-1", children: [
6354
+ /* @__PURE__ */ jsxRuntime.jsx("a", { href: OCHK_IO, className: "rounded-lg text-foreground", children: /* @__PURE__ */ jsxRuntime.jsx(Lockup, { size: 22 }) }),
6355
+ family ? /* @__PURE__ */ jsxRuntime.jsx("nav", { "aria-label": "Protocols", children: /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "flex flex-wrap gap-x-4", children: PROTOCOLS.map((p) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx("a", { href: p.pageHref, className: FOOT_LINK, children: p.label }) }, p.slug)) }) }) : null
6356
+ ] }),
6357
+ legalLinks || meta ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-x-6 gap-y-2 sm:flex-row sm:flex-wrap sm:items-center", children: [
6358
+ legalLinks ? /* @__PURE__ */ jsxRuntime.jsx(LegalRow, { links: legalLinks }) : null,
6359
+ meta
6360
+ ] }) : null
6361
+ ] }) });
6362
+ }
6363
+ const cols = [
6364
+ ...columns,
6365
+ ...family ? familyByGroup().map((g) => ({
6366
+ // The lockup above already says orangecheck.
6367
+ heading: g.id === "orangecheck" ? "Start here" : g.label,
6368
+ links: g.sites.map((s) => ({ href: s.href, label: s.label, external: true }))
6369
+ })) : []
6370
+ ];
6371
+ const n = cols.length;
6372
+ const inline = n <= 5;
6373
+ const grid = {
6374
+ "--oca-footer-md": `repeat(${Math.max(1, Math.min(n, 4))}, minmax(0, 1fr))`,
6375
+ "--oca-footer-lg": inline ? `minmax(0, 1.3fr) repeat(${Math.max(1, n)}, minmax(0, 1fr))` : `repeat(${Math.min(n, 6)}, minmax(0, 1fr))`
6376
+ };
6377
+ return /* @__PURE__ */ jsxRuntime.jsxs("footer", { className: cn("border-t border-border bg-background", className), children: [
6378
+ /* @__PURE__ */ jsxRuntime.jsxs(
6379
+ "div",
6380
+ {
6381
+ style: grid,
6382
+ className: "oca-container grid grid-cols-2 gap-x-6 gap-y-10 py-14 md:grid-cols-[var(--oca-footer-md)] md:py-16 lg:grid-cols-[var(--oca-footer-lg)]",
6383
+ children: [
6384
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("col-span-full flex flex-col gap-4", inline && "lg:col-span-1"), children: [
6385
+ /* @__PURE__ */ jsxRuntime.jsx(Lockup, { size: 26 }),
6386
+ fineprint ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "max-w-xs text-[0.9375rem] leading-relaxed text-muted-foreground", children: fineprint }) : null
6428
6387
  ] }),
6429
- place.page ? /* @__PURE__ */ jsxRuntime.jsxs(
6430
- "div",
6431
- {
6432
- className: cn(
6433
- "flex h-9 items-center gap-1.5 border-t border-border px-4 text-[0.875rem]",
6434
- // The active tab already names the page.
6435
- tabs && !pageOverride && "max-md:hidden"
6436
- ),
6437
- children: [
6438
- place.section ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
6439
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 text-muted-foreground", children: place.section }),
6440
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { "aria-hidden": true, className: "size-3.5 shrink-0 text-muted-foreground" })
6441
- ] }) : null,
6442
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate font-medium", children: place.page })
6443
- ]
6444
- }
6445
- ) : null
6388
+ cols.map((col, i) => {
6389
+ const spans = n % 2 === 1 && i === n - 1;
6390
+ return /* @__PURE__ */ jsxRuntime.jsxs(
6391
+ "div",
6392
+ {
6393
+ className: cn("flex min-w-0 flex-col gap-1", spans && "col-span-2 md:col-span-1"),
6394
+ children: [
6395
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mb-2 text-[0.875rem] font-medium", children: col.heading }),
6396
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex flex-col gap-1", spans && "grid grid-cols-2 gap-x-6 md:flex md:flex-col"), children: col.links.map((l) => /* @__PURE__ */ jsxRuntime.jsx(
6397
+ NavLink,
6398
+ {
6399
+ item: l,
6400
+ className: "-mx-3 py-2.5 text-[0.9375rem] md:py-1.5"
6401
+ },
6402
+ l.href
6403
+ )) })
6404
+ ]
6405
+ },
6406
+ col.heading
6407
+ );
6408
+ })
6409
+ ]
6410
+ }
6411
+ ),
6412
+ signature ? /* @__PURE__ */ jsxRuntime.jsx("div", { "aria-hidden": true, className: "oca-container select-none overflow-hidden pb-8 md:pb-12", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-end gap-[0.18em] text-[clamp(3rem,11.5vw,10rem)] leading-[0.78] tracking-[-0.065em] [font-family:var(--oc-font-display)]", children: [
6413
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mb-[0.06em] inline-block w-[1.1em] shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(Mark, { className: "block h-auto w-full" }) }),
6414
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "orangecheck" })
6415
+ ] }) }) : null,
6416
+ legalLinks || meta ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "oca-container", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3 border-t border-border py-6 text-[0.875rem] text-muted-foreground", children: [
6417
+ legalLinks ? /* @__PURE__ */ jsxRuntime.jsx(LegalRow, { links: legalLinks }) : null,
6418
+ meta
6419
+ ] }) }) : null
6420
+ ] });
6421
+ }
6422
+ function OchkIoFooter({ columns = OCHK_IO_FOOTER, className }) {
6423
+ return /* @__PURE__ */ jsxRuntime.jsx(
6424
+ SiteFooter,
6425
+ {
6426
+ columns,
6427
+ family: true,
6428
+ legal: true,
6429
+ fineprint: "Open protocols on Bitcoin. Anyone can check the result.",
6430
+ meta: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center justify-between gap-4", children: [
6431
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
6432
+ "Open-source work on orangecheck is ",
6433
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "whitespace-nowrap", children: "supported by OpenSats." })
6446
6434
  ] }),
6447
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mx-auto flex w-full max-w-[90rem]", children: [
6448
- /* @__PURE__ */ jsxRuntime.jsxs("aside", { className: "sticky top-0 hidden h-dvh w-[17rem] shrink-0 flex-col gap-6 overflow-y-auto px-4 py-6 lg:flex", children: [
6449
- /* @__PURE__ */ jsxRuntime.jsx(Link8__default.default, { href: home, className: "px-2", "aria-label": "Home", children: /* @__PURE__ */ jsxRuntime.jsx(Lockup, { size: 26 }) }),
6450
- switcher,
6451
- /* @__PURE__ */ jsxRuntime.jsx(SideNav, { groups }),
6452
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-auto flex flex-col gap-3", children: footer })
6435
+ /* @__PURE__ */ jsxRuntime.jsx(ThemeToggle, { className: "-mx-3" })
6436
+ ] }),
6437
+ className
6438
+ }
6439
+ );
6440
+ }
6441
+ function SignInFrame({
6442
+ title = "Sign in",
6443
+ lead,
6444
+ children,
6445
+ error,
6446
+ fineprint,
6447
+ brand,
6448
+ home,
6449
+ protocol: protocol2,
6450
+ back,
6451
+ art,
6452
+ caption,
6453
+ className
6454
+ }) {
6455
+ const homeHref = home ?? (protocol2 ? protocolSite(protocol2).pageHref : OCHK_IO);
6456
+ return /* @__PURE__ */ jsxRuntime.jsxs(
6457
+ "main",
6458
+ {
6459
+ id: "main-content",
6460
+ className: cn("grid min-h-dvh grid-cols-1 bg-background text-foreground lg:grid-cols-2", className),
6461
+ children: [
6462
+ /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "flex flex-col px-4 pb-8 pt-5 sm:px-8 lg:px-14 lg:pt-8", children: [
6463
+ /* @__PURE__ */ jsxRuntime.jsxs("header", { className: "flex items-center justify-between gap-4", children: [
6464
+ /* @__PURE__ */ jsxRuntime.jsxs(Link6__default.default, { href: homeHref, className: "w-fit rounded-lg", children: [
6465
+ brand ?? /* @__PURE__ */ jsxRuntime.jsx(Lockup, { size: 28 }),
6466
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: " home" })
6467
+ ] }),
6468
+ back === void 0 ? /* @__PURE__ */ jsxRuntime.jsx(
6469
+ Link6__default.default,
6470
+ {
6471
+ href: homeHref,
6472
+ className: "text-[0.9375rem] text-muted-foreground underline-offset-4 hover:text-foreground hover:underline",
6473
+ children: "Back to home"
6474
+ }
6475
+ ) : back
6453
6476
  ] }),
6454
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-1 flex-col", children: [
6455
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden h-[4.5rem] items-center justify-end gap-3 px-8 lg:flex", children: account }),
6456
- banner ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 pb-2 pt-4 md:px-8 lg:pt-0", children: banner }) : null,
6457
- /* @__PURE__ */ jsxRuntime.jsx("main", { id: "main-content", className: "flex-1 px-4 pb-16 pt-6 md:px-8 lg:pt-2", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-auto w-full max-w-[72rem]", children }) })
6477
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mx-auto flex w-full max-w-[25rem] flex-1 flex-col justify-center gap-9 py-12", children: [
6478
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3", children: [
6479
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "oca-display-2", children: title }),
6480
+ lead ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "oca-lead", children: lead }) : null
6481
+ ] }),
6482
+ /* @__PURE__ */ jsxRuntime.jsx("div", { children }),
6483
+ error ? /* @__PURE__ */ jsxRuntime.jsx("p", { role: "alert", className: "text-[0.9375rem] text-destructive", children: error }) : null,
6484
+ fineprint ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[0.8125rem] leading-relaxed text-muted-foreground", children: fineprint }) : null
6458
6485
  ] })
6459
6486
  ] }),
6460
- tabs ? /* @__PURE__ */ jsxRuntime.jsx(TabBar, { items: tabs }) : null
6487
+ /* @__PURE__ */ jsxRuntime.jsxs(
6488
+ "aside",
6489
+ {
6490
+ "aria-hidden": true,
6491
+ className: "relative hidden flex-col justify-between gap-10 overflow-hidden border-l border-[var(--oca-band-line)] bg-oca-ink p-14 text-oca-ink-foreground lg:flex",
6492
+ children: [
6493
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-1 items-center justify-center", children: art ?? /* @__PURE__ */ jsxRuntime.jsx(IsoCheck, { size: 340, settle: true, tilt: true, className: "max-w-full" }) }),
6494
+ caption ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex max-w-[24rem] flex-col gap-3", children: caption }) : null
6495
+ ]
6496
+ }
6497
+ )
6461
6498
  ]
6462
6499
  }
6463
- ) });
6500
+ );
6464
6501
  }
6465
- function AccountMenu({
6466
- name,
6467
- detail,
6468
- items,
6469
- nameFrom = "sm"
6502
+ var STATUS_WORDS = /* @__PURE__ */ new Set(["live", "testing", "not-yet", "paused", "good", "caution", "refused"]);
6503
+ var pathOf = (href) => href.split(/[?#]/)[0].replace(/(.)\/$/, "$1");
6504
+ function DocsNav({
6505
+ sections,
6506
+ current: current2,
6507
+ onNavigate,
6508
+ className
6470
6509
  }) {
6471
- const initial = name.trim().charAt(0).toUpperCase() || "\xB7";
6472
- return /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenu, { children: [
6473
- /* @__PURE__ */ jsxRuntime.jsxs(
6474
- DropdownMenuTrigger,
6475
- {
6476
- className: cn(
6477
- "inline-flex h-10 items-center gap-2.5 rounded-full border border-border bg-card pl-1 pr-1 text-[0.9375rem] outline-none transition-colors hover:border-oca-hairline-strong focus-visible:ring-2 focus-visible:ring-ring",
6478
- nameFrom === "lg" ? "lg:pr-3.5" : "sm:pr-3.5"
6479
- ),
6480
- "aria-label": `${name}, account menu`,
6481
- children: [
6482
- /* @__PURE__ */ jsxRuntime.jsx(
6483
- "span",
6484
- {
6485
- "aria-hidden": true,
6486
- "data-initial": initial,
6487
- className: "flex size-8 items-center justify-center rounded-full bg-foreground text-[0.8125rem] font-medium text-background before:content-[attr(data-initial)]"
6488
- }
6510
+ const here = pathOf(current2);
6511
+ const activeSection = react.useMemo(
6512
+ () => sections.findIndex((s) => s.items.some((i) => pathOf(i.href) === here)),
6513
+ [sections, here]
6514
+ );
6515
+ const [peeked, setPeeked] = react.useState(() => /* @__PURE__ */ new Set());
6516
+ react.useEffect(() => setPeeked(/* @__PURE__ */ new Set()), [activeSection]);
6517
+ const activeRef = react.useRef(null);
6518
+ react.useEffect(() => {
6519
+ const id = requestAnimationFrame(() => activeRef.current?.scrollIntoView({ block: "nearest" }));
6520
+ return () => cancelAnimationFrame(id);
6521
+ }, [here]);
6522
+ const base = react.useId();
6523
+ return /* @__PURE__ */ jsxRuntime.jsx("nav", { "aria-label": "Docs", className: cn("flex flex-col gap-0.5", className), children: sections.map((section, si) => {
6524
+ const isActive = si === activeSection;
6525
+ const open = isActive || peeked.has(si);
6526
+ const panel = `${base}-s${si}`;
6527
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
6528
+ /* @__PURE__ */ jsxRuntime.jsxs(
6529
+ "button",
6530
+ {
6531
+ type: "button",
6532
+ "aria-expanded": open,
6533
+ "aria-controls": panel,
6534
+ onClick: () => {
6535
+ if (isActive) return;
6536
+ setPeeked((p) => {
6537
+ const n = new Set(p);
6538
+ if (n.has(si)) n.delete(si);
6539
+ else n.add(si);
6540
+ return n;
6541
+ });
6542
+ },
6543
+ className: cn(
6544
+ "flex min-h-9 w-full items-center justify-between gap-2 rounded-lg px-2.5 py-1.5 text-left text-[0.875rem] transition-colors",
6545
+ isActive ? "font-medium text-foreground" : "text-muted-foreground hover:bg-accent hover:text-foreground",
6546
+ isActive && "cursor-default"
6489
6547
  ),
6490
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("max-w-[10rem] truncate", nameFrom === "lg" ? "max-lg:hidden" : "max-sm:hidden"), children: name })
6491
- ]
6492
- }
6493
- ),
6494
- /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenuContent, { align: "end", className: "w-64", children: [
6495
- /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenuLabel, { className: "flex flex-col gap-0.5", children: [
6496
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-[0.9375rem] font-medium text-foreground", children: name }),
6497
- detail ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate font-mono text-[0.75rem]", children: detail }) : null
6498
- ] }),
6499
- /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuSeparator, {}),
6500
- items.map(
6501
- (it, i) => it === "separator" ? /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuSeparator, {}, `sep-${i}`) : it.href ? /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuItem, { asChild: true, destructive: it.destructive, children: /* @__PURE__ */ jsxRuntime.jsxs(Link8__default.default, { href: it.href, children: [
6502
- it.icon,
6503
- it.label
6504
- ] }) }, it.label) : /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenuItem, { onSelect: it.onSelect, destructive: it.destructive, children: [
6505
- it.icon,
6506
- it.label
6507
- ] }, it.label)
6508
- )
6509
- ] })
6510
- ] });
6511
- }
6512
- function ThemeToggle({ className }) {
6513
- const { theme, setTheme } = nextThemes.useTheme();
6514
- const [mounted, setMounted] = react.useState(false);
6515
- react.useEffect(() => setMounted(true), []);
6516
- const current2 = mounted ? theme ?? "system" : "system";
6517
- const next = current2 === "light" ? "dark" : current2 === "dark" ? "system" : "light";
6518
- const Icon2 = current2 === "light" ? lucideReact.Sun : current2 === "dark" ? lucideReact.Moon : lucideReact.SunMoon;
6519
- return /* @__PURE__ */ jsxRuntime.jsx(
6520
- "button",
6521
- {
6522
- type: "button",
6523
- onClick: () => setTheme(next),
6524
- "aria-label": `Theme: ${current2}. Switch to ${next}`,
6525
- title: `Theme: ${current2}`,
6526
- className: cn(
6527
- "inline-flex size-10 items-center justify-center rounded-full text-muted-foreground transition-colors hover:bg-accent hover:text-foreground",
6528
- className
6548
+ children: [
6549
+ section.label,
6550
+ /* @__PURE__ */ jsxRuntime.jsx(
6551
+ lucideReact.ChevronRight,
6552
+ {
6553
+ "aria-hidden": true,
6554
+ className: cn("size-3.5 shrink-0 text-oca-subtle transition-transform duration-200", open && "rotate-90")
6555
+ }
6556
+ )
6557
+ ]
6558
+ }
6529
6559
  ),
6530
- children: /* @__PURE__ */ jsxRuntime.jsx(Icon2, { className: "size-[1.125rem]" })
6560
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { id: panel, hidden: !open, className: "mb-2 ml-2.5 mt-0.5 border-l border-border", children: section.items.map((item) => {
6561
+ const on = pathOf(item.href) === here;
6562
+ const badge = typeof item.badge === "string" && STATUS_WORDS.has(item.badge) ? /* @__PURE__ */ jsxRuntime.jsx(StatusBadge, { status: item.badge }) : item.badge ? /* @__PURE__ */ jsxRuntime.jsx(Badge, { tone: "muted", children: item.badge }) : null;
6563
+ return /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsxs(
6564
+ Link6__default.default,
6565
+ {
6566
+ href: item.href,
6567
+ ref: on ? activeRef : void 0,
6568
+ onClick: onNavigate,
6569
+ "aria-current": on ? "page" : void 0,
6570
+ className: cn(
6571
+ "-ml-px flex min-h-9 items-center gap-2 border-l-2 py-1.5 pl-3.5 pr-2 text-[0.875rem] leading-snug transition-colors",
6572
+ on ? "border-foreground font-medium text-foreground" : "border-transparent text-muted-foreground hover:border-oca-hairline-strong hover:text-foreground"
6573
+ ),
6574
+ children: [
6575
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1", children: item.label }),
6576
+ badge
6577
+ ]
6578
+ }
6579
+ ) }, item.href);
6580
+ }) })
6581
+ ] }, section.label);
6582
+ }) });
6583
+ }
6584
+ var DOCS_HEADER_NAV = OCHK_IO_NAV.map((n) => n.href === DOCS_HREF ? { ...n, active: true } : n);
6585
+ function DocsShell({
6586
+ nav,
6587
+ current: current2,
6588
+ navCurrent,
6589
+ header,
6590
+ search,
6591
+ actions,
6592
+ breadcrumbs,
6593
+ toc,
6594
+ pager,
6595
+ footer,
6596
+ children
6597
+ }) {
6598
+ const [menu, setMenu] = react.useState(false);
6599
+ react.useEffect(() => setMenu(false), [current2]);
6600
+ const read = useHeadings("#docs-content", current2);
6601
+ const items = toc ?? read.items;
6602
+ const activeId = toc ? void 0 : read.activeId;
6603
+ const marked = navCurrent ?? current2;
6604
+ const here = pathOf(marked);
6605
+ const place = react.useMemo(() => {
6606
+ for (const s of nav) {
6607
+ const it = s.items.find((i) => pathOf(i.href) === here);
6608
+ if (it) return { section: s.label, page: it.label };
6531
6609
  }
6532
- );
6610
+ return null;
6611
+ }, [nav, here]);
6612
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-h-dvh flex-col bg-background", children: [
6613
+ /* @__PURE__ */ jsxRuntime.jsx(SkipLink, {}),
6614
+ header ?? /* @__PURE__ */ jsxRuntime.jsx(SiteHeader, { home: OCHK_IO, family: "docs", nav: DOCS_HEADER_NAV, search, actions }),
6615
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "sticky top-16 z-30 border-b border-border bg-background/95 backdrop-blur-md supports-[backdrop-filter]:bg-background/90 md:top-[4.5rem] lg:hidden", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "oca-container flex h-12 items-center gap-2", children: /* @__PURE__ */ jsxRuntime.jsxs(Sheet, { open: menu, onOpenChange: setMenu, children: [
6616
+ /* @__PURE__ */ jsxRuntime.jsxs(SheetTrigger, { className: "-ml-2 inline-flex h-10 min-w-0 items-center gap-2 rounded-full px-2.5 text-[0.875rem] hover:bg-accent", children: [
6617
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PanelLeft, { "aria-hidden": true, className: "size-[1.125rem] shrink-0" }),
6618
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Docs menu. " }),
6619
+ place ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 items-center gap-1.5", children: [
6620
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 text-muted-foreground", children: place.section }),
6621
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { "aria-hidden": true, className: "size-3.5 shrink-0 text-oca-subtle" }),
6622
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate font-medium", children: place.page })
6623
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: "Docs" })
6624
+ ] }),
6625
+ /* @__PURE__ */ jsxRuntime.jsxs(SheetContent, { side: "left", className: "w-[min(88vw,22rem)] gap-0 p-0", children: [
6626
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-b border-border px-5 py-4 pr-14", children: /* @__PURE__ */ jsxRuntime.jsx(SheetTitle, { className: "text-[1.0625rem] font-medium", children: "Docs" }) }),
6627
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-y-auto p-3", children: /* @__PURE__ */ jsxRuntime.jsx(DocsNav, { sections: nav, current: marked, onNavigate: () => setMenu(false) }) })
6628
+ ] })
6629
+ ] }) }) }),
6630
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "oca-container flex-1", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "lg:grid lg:grid-cols-[13.5rem_minmax(0,1fr)] lg:gap-x-10 xl:grid-cols-[13.5rem_minmax(0,1fr)_11rem]", children: [
6631
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "sticky top-[4.5rem] hidden max-h-[calc(100dvh-4.5rem)] self-start overflow-y-auto overscroll-contain py-8 pr-1 lg:block", children: /* @__PURE__ */ jsxRuntime.jsx(DocsNav, { sections: nav, current: marked }) }),
6632
+ /* @__PURE__ */ jsxRuntime.jsxs("main", { id: "main-content", className: "min-w-0 pb-16 pt-6 md:pt-8", children: [
6633
+ breadcrumbs ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-6 max-lg:hidden", children: breadcrumbs }) : null,
6634
+ items.length > 1 ? /* @__PURE__ */ jsxRuntime.jsxs("details", { className: "group mb-8 rounded-2xl border border-border bg-card xl:hidden", children: [
6635
+ /* @__PURE__ */ jsxRuntime.jsxs("summary", { className: "flex min-h-12 cursor-pointer list-none items-center justify-between px-4 text-[0.9375rem] font-medium [&::-webkit-details-marker]:hidden", children: [
6636
+ "On this page",
6637
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { "aria-hidden": true, className: "size-4 text-muted-foreground transition-transform group-open:rotate-180" })
6638
+ ] }),
6639
+ /* @__PURE__ */ jsxRuntime.jsx(OnThisPage, { items, activeId, title: null, className: "px-4 pb-4" })
6640
+ ] }) : null,
6641
+ /* @__PURE__ */ jsxRuntime.jsx("article", { id: "docs-content", className: "max-w-[46rem]", children: /* @__PURE__ */ jsxRuntime.jsx(InDocsContext.Provider, { value: true, children }) }),
6642
+ pager ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-16 max-w-[46rem]", children: pager }) : null
6643
+ ] }),
6644
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "sticky top-[4.5rem] hidden max-h-[calc(100dvh-4.5rem)] self-start overflow-y-auto py-10 xl:block", children: items.length > 1 ? /* @__PURE__ */ jsxRuntime.jsx(OnThisPage, { items, activeId }) : null })
6645
+ ] }) }),
6646
+ footer ?? /* @__PURE__ */ jsxRuntime.jsx(OchkIoFooter, {})
6647
+ ] });
6533
6648
  }
6534
6649
  var OCHK_APP_ACCOUNT = "https://ochk.app/me/account";
6535
6650
  function onHistory(change) {
@@ -6602,6 +6717,7 @@ function ToolShell({
6602
6717
  children
6603
6718
  }) {
6604
6719
  const p = protocolSite(protocol2);
6720
+ const homeHref = home ?? p.pageHref;
6605
6721
  const app = variant === "app";
6606
6722
  const tabs = app ? null : tabsFor([{ items: [...tools] }]);
6607
6723
  const about = /* @__PURE__ */ jsxRuntime.jsxs(
@@ -6631,7 +6747,7 @@ function ToolShell({
6631
6747
  SiteHeader,
6632
6748
  {
6633
6749
  variant: "tool",
6634
- home: home ?? p.pageHref,
6750
+ home: homeHref,
6635
6751
  product: p.label,
6636
6752
  family: protocol2,
6637
6753
  nav: tools.map((t) => ({ href: t.href, label: t.label, active: t.active })),
@@ -6656,7 +6772,7 @@ function ToolShell({
6656
6772
  {
6657
6773
  id: "main-content",
6658
6774
  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"),
6659
- children: app ? children : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-auto w-full max-w-[72rem]", children })
6775
+ children: /* @__PURE__ */ jsxRuntime.jsx(SiteHomeContext.Provider, { value: homeHref, children: app ? children : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-auto w-full max-w-[72rem]", children }) })
6660
6776
  }
6661
6777
  )
6662
6778
  ] }),
@@ -6691,6 +6807,7 @@ function rehypeCode(options = {}) {
6691
6807
  if (lang && skip.has(lang)) continue;
6692
6808
  const meta = parseCodeMeta(code.data?.meta);
6693
6809
  let source = textOf(code);
6810
+ const newline = /\n$/.test(source);
6694
6811
  const diff = meta.diff || lang === "diff" ? readDiff(source) : null;
6695
6812
  if (diff) source = diff.code;
6696
6813
  const lines = options.tokenize?.(source, lang) ?? highlight(source, lang === "diff" ? void 0 : lang);
@@ -6701,7 +6818,8 @@ function rehypeCode(options = {}) {
6701
6818
  ...lang ? { dataLang: lang } : {},
6702
6819
  ...meta.title ? { dataTitle: meta.title } : {},
6703
6820
  ...diff ? { dataDiff: "" } : {},
6704
- ...meta.lineNumbers ? { dataLineNumbers: "" } : {}
6821
+ ...meta.lineNumbers ? { dataLineNumbers: "" } : {},
6822
+ ...newline ? { dataEol: "" } : {}
6705
6823
  };
6706
6824
  child.children = [];
6707
6825
  continue;
@@ -6722,6 +6840,7 @@ function createMdxComponents({ mermaid } = {}) {
6722
6840
  caption: props["data-title"],
6723
6841
  diff: props["data-diff"] !== void 0,
6724
6842
  lineNumbers: props["data-line-numbers"] !== void 0,
6843
+ trailingNewline: props["data-eol"] !== void 0,
6725
6844
  className: "my-6"
6726
6845
  }
6727
6846
  );
@@ -6748,6 +6867,9 @@ function createMdxComponents({ mermaid } = {}) {
6748
6867
  const heading = (as) => function Heading(props) {
6749
6868
  return /* @__PURE__ */ jsxRuntime.jsx(DocsHeading, { as, ...props });
6750
6869
  };
6870
+ const minor = (Tag) => function Minor({ className, ...props }) {
6871
+ return /* @__PURE__ */ jsxRuntime.jsx(Tag, { className: cn("mb-2 mt-6 scroll-mt-28 text-[0.9375rem] font-medium leading-snug text-foreground", className), ...props });
6872
+ };
6751
6873
  return {
6752
6874
  h1: heading("h1"),
6753
6875
  h2: heading("h2"),
@@ -6756,11 +6878,15 @@ function createMdxComponents({ mermaid } = {}) {
6756
6878
  p: ({ className, ...props }) => /* @__PURE__ */ jsxRuntime.jsx("p", { className: cn("my-4 text-[1rem] leading-[1.75] text-muted-foreground md:text-[1.0625rem]", className), ...props }),
6757
6879
  a: A,
6758
6880
  strong: (props) => /* @__PURE__ */ jsxRuntime.jsx("strong", { className: "font-medium text-foreground", ...props }),
6881
+ h5: minor("h5"),
6882
+ h6: minor("h6"),
6759
6883
  ul: ({ className, ...props }) => /* @__PURE__ */ jsxRuntime.jsx(
6760
6884
  "ul",
6761
6885
  {
6762
6886
  className: cn(
6763
6887
  "my-4 list-disc space-y-1.5 pl-5 text-[1rem] leading-[1.7] text-muted-foreground marker:text-oca-subtle md:text-[1.0625rem]",
6888
+ // A GitHub task list: the box replaces the bullet.
6889
+ className?.includes("contains-task-list") && "list-none pl-0",
6764
6890
  className
6765
6891
  ),
6766
6892
  ...props
@@ -6776,7 +6902,26 @@ function createMdxComponents({ mermaid } = {}) {
6776
6902
  ...props
6777
6903
  }
6778
6904
  ),
6779
- li: ({ className, ...props }) => /* @__PURE__ */ jsxRuntime.jsx("li", { className: cn("pl-1 [&>p]:my-1 [&>ul]:my-1.5 [&>ol]:my-1.5", className), ...props }),
6905
+ li: ({ className, ...props }) => /* @__PURE__ */ jsxRuntime.jsx(
6906
+ "li",
6907
+ {
6908
+ className: cn(
6909
+ "pl-1 [&>p]:my-1 [&>ul]:my-1.5 [&>ol]:my-1.5",
6910
+ // A wrapped task starts under its text, not under the box.
6911
+ className?.includes("task-list-item") && "pl-6 -indent-6",
6912
+ className
6913
+ ),
6914
+ ...props
6915
+ }
6916
+ ),
6917
+ input: (props) => props.type === "checkbox" ? /* @__PURE__ */ jsxRuntime.jsx(
6918
+ "input",
6919
+ {
6920
+ ...props,
6921
+ className: cn("mr-2 size-4 translate-y-[2px] align-baseline accent-foreground", props.className),
6922
+ "aria-label": props.checked ? "Done" : "To do"
6923
+ }
6924
+ ) : /* @__PURE__ */ jsxRuntime.jsx("input", { ...props }),
6780
6925
  blockquote: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx(Callout, { children }),
6781
6926
  hr: () => /* @__PURE__ */ jsxRuntime.jsx("hr", { className: "my-10 border-border" }),
6782
6927
  table: MdxTable,
@@ -6919,6 +7064,7 @@ exports.OCHK_APP_ACCOUNT = OCHK_APP_ACCOUNT;
6919
7064
  exports.OCHK_IO = OCHK_IO;
6920
7065
  exports.OCHK_IO_FOOTER = OCHK_IO_FOOTER;
6921
7066
  exports.OCHK_IO_NAV = OCHK_IO_NAV;
7067
+ exports.OchkIoFooter = OchkIoFooter;
6922
7068
  exports.OnThisPage = OnThisPage;
6923
7069
  exports.PROTOCOLS = PROTOCOLS;
6924
7070
  exports.PROTOCOL_ORDER = PROTOCOL_ORDER;