@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
@@ -9,8 +9,10 @@ var TabsPrimitive = require('@radix-ui/react-tabs');
9
9
  var lucideReact = require('lucide-react');
10
10
  var reactSlot = require('@radix-ui/react-slot');
11
11
  var SeparatorPrimitive = require('@radix-ui/react-separator');
12
+ require('next-themes');
12
13
  require('sonner');
13
14
  var Link = require('next/link');
15
+ var router = require('next/compat/router');
14
16
  var CheckboxPrimitive = require('@radix-ui/react-checkbox');
15
17
  var LabelPrimitive = require('@radix-ui/react-label');
16
18
  var RadioGroupPrimitive = require('@radix-ui/react-radio-group');
@@ -1707,11 +1709,13 @@ function forClipboard(text, lang) {
1707
1709
  if (!lines.some((l) => l.startsWith("$ "))) return text;
1708
1710
  return lines.filter((l) => l.startsWith("$ ")).map((l) => l.slice(2)).join("\n");
1709
1711
  }
1710
- function linesFromDom(pre) {
1712
+ function linesFromDom(pre, newline) {
1711
1713
  if (!pre) return null;
1712
1714
  const lines = pre.querySelectorAll("[data-line]");
1713
1715
  if (lines.length === 0) return pre.textContent ?? "";
1714
- return Array.from(lines).filter((l) => l.getAttribute("data-diff") !== "remove").map((l) => l.textContent ?? "").join("\n");
1716
+ const text = Array.from(lines).filter((l) => l.getAttribute("data-diff") !== "remove").map((l) => l.textContent ?? "").join("\n");
1717
+ return newline ? `${text}
1718
+ ` : text;
1715
1719
  }
1716
1720
  function prepare(code, lang, marks, diff) {
1717
1721
  const d = diff ? readDiff(code) : null;
@@ -1720,7 +1724,8 @@ function prepare(code, lang, marks, diff) {
1720
1724
  const kept = d ? src.split("\n").filter((_, i) => d.diff.get(i + 1) !== "remove") : null;
1721
1725
  return {
1722
1726
  html: linesToHtml(lines, { highlight: parseLineRanges(marks), diff: d?.diff }),
1723
- copy: kept ? kept.join("\n") : src,
1727
+ // Byte for byte, the final newline too: a hash printed beside the code must match a copy of it.
1728
+ copy: kept ? kept.join("\n") + (/\n$/.test(code) ? "\n" : "") : code,
1724
1729
  lines: lines.length,
1725
1730
  diff: !!d
1726
1731
  };
@@ -1733,7 +1738,8 @@ function Well({
1733
1738
  lines,
1734
1739
  maxLines,
1735
1740
  diff,
1736
- lineNumbers
1741
+ lineNumbers,
1742
+ wrap
1737
1743
  }) {
1738
1744
  const foldable = maxLines !== void 0 && lines > maxLines + 2;
1739
1745
  const [open, setOpen] = react.useState(false);
@@ -1752,7 +1758,8 @@ function Well({
1752
1758
  "data-diff": diff ? "" : void 0,
1753
1759
  "data-line-numbers": lineNumbers ? "" : void 0,
1754
1760
  className: cn(
1755
- "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]",
1761
+ "oca-code py-4 font-mono text-[0.875rem] leading-[1.625] text-oca-ink-muted [font-variant-ligatures:none]",
1762
+ wrap ? "whitespace-pre-wrap break-all" : "w-max min-w-full",
1756
1763
  !lined && "px-5"
1757
1764
  ),
1758
1765
  children: lined ? /* @__PURE__ */ jsxRuntime.jsx("code", { className: "block", "data-lang": lang, dangerouslySetInnerHTML: { __html: html } }) : /* @__PURE__ */ jsxRuntime.jsx("code", { className: "block", "data-lang": lang, children })
@@ -1785,6 +1792,7 @@ function CodeBlock({
1785
1792
  code,
1786
1793
  html,
1787
1794
  children,
1795
+ trailingNewline = false,
1788
1796
  lang,
1789
1797
  caption,
1790
1798
  copy = true,
@@ -1793,6 +1801,7 @@ function CodeBlock({
1793
1801
  highlight: marks,
1794
1802
  diff,
1795
1803
  lineNumbers,
1804
+ wrap,
1796
1805
  actions,
1797
1806
  className
1798
1807
  }) {
@@ -1805,7 +1814,7 @@ function CodeBlock({
1805
1814
  );
1806
1815
  const markup = prepared?.html ?? html;
1807
1816
  const lines = prepared?.lines ?? (html !== void 0 ? html.split("\n").length : code?.split("\n").length ?? 0);
1808
- const read = () => forClipboard(prepared?.copy ?? linesFromDom(preRef.current) ?? code ?? "", lang);
1817
+ const read = () => forClipboard(prepared?.copy ?? linesFromDom(preRef.current, trailingNewline) ?? code ?? "", lang);
1809
1818
  return /* @__PURE__ */ jsxRuntime.jsxs("figure", { className: cn(FRAME, className), children: [
1810
1819
  /* @__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: [
1811
1820
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-[0.8125rem] text-oca-ink-subtle", children: caption ?? languageName(lang) ?? "Code" }),
@@ -1824,6 +1833,7 @@ function CodeBlock({
1824
1833
  maxLines,
1825
1834
  diff: prepared ? prepared.diff : isDiff,
1826
1835
  lineNumbers,
1836
+ wrap,
1827
1837
  children
1828
1838
  }
1829
1839
  )
@@ -2326,6 +2336,133 @@ function MarkOutline({ className }) {
2326
2336
  points
2327
2337
  )) });
2328
2338
  }
2339
+
2340
+ // src/family/index.ts
2341
+ var OCHK_IO = "https://ochk.io";
2342
+ var DOCS_HREF = `${OCHK_IO}/docs`;
2343
+ function protocol(slug, verb, line, kinds) {
2344
+ return {
2345
+ slug,
2346
+ label: slug,
2347
+ href: `${OCHK_IO}/${slug}`,
2348
+ group: "protocol",
2349
+ line,
2350
+ status: "live",
2351
+ verb,
2352
+ pageHref: `${OCHK_IO}/${slug}`,
2353
+ toolHref: `https://${slug}.ochk.io`,
2354
+ specHref: `https://github.com/orangecheck/oc-${slug}-protocol`,
2355
+ kinds
2356
+ };
2357
+ }
2358
+ var PROTOCOLS = [
2359
+ protocol("attest", "identity", "Show that an address holds bitcoin, and for how long.", "30078"),
2360
+ protocol("lock", "confidentiality", "Encrypt to a Bitcoin address, so only its holder can open it.", "30078"),
2361
+ protocol("vote", "legitimacy", "Polls weighed in sats, that anyone can tally.", "30080\u201330082"),
2362
+ protocol("stamp", "provenance", "Prove who signed something, and when.", "30083"),
2363
+ protocol("agent", "authority", "Give software scoped, revocable permission to act for you.", "30083\u201330086"),
2364
+ protocol("pledge", "commitment", "Make a promise with bitcoin behind it, on a public record.", "30078")
2365
+ ];
2366
+ var PROTOCOL_ORDER = PROTOCOLS.map((p) => p.slug);
2367
+ var FAMILY = [
2368
+ {
2369
+ slug: "home",
2370
+ label: "ochk.io",
2371
+ href: OCHK_IO,
2372
+ group: "orangecheck",
2373
+ line: "The open protocols, and the company behind them.",
2374
+ status: "live"
2375
+ },
2376
+ {
2377
+ slug: "me",
2378
+ label: "ochk.app",
2379
+ href: "https://ochk.app",
2380
+ group: "orangecheck",
2381
+ line: "One account, with Bitcoin behind it.",
2382
+ status: "testing"
2383
+ },
2384
+ {
2385
+ slug: "docs",
2386
+ label: "docs",
2387
+ href: DOCS_HREF,
2388
+ group: "orangecheck",
2389
+ line: "Specs, SDKs and guides for every protocol.",
2390
+ status: "live"
2391
+ },
2392
+ ...PROTOCOLS,
2393
+ {
2394
+ slug: "vault",
2395
+ label: "vault",
2396
+ href: "https://vault.ochk.io",
2397
+ group: "app",
2398
+ line: "A password manager, encrypted in your browser.",
2399
+ status: "live",
2400
+ protocols: ["lock"]
2401
+ },
2402
+ {
2403
+ slug: "chat",
2404
+ label: "chat",
2405
+ href: "https://chat.ochk.io",
2406
+ group: "app",
2407
+ line: "Messages only the holder of a Bitcoin address can read.",
2408
+ status: "testing",
2409
+ protocols: ["lock"]
2410
+ },
2411
+ {
2412
+ slug: "cosign",
2413
+ label: "cosign",
2414
+ href: "https://cosign.ochk.io",
2415
+ group: "app",
2416
+ line: "Builders find co-founders and backers.",
2417
+ status: "testing",
2418
+ // Signs in with an orangecheck account and a wallet; uses none of the six directly.
2419
+ protocols: []
2420
+ },
2421
+ {
2422
+ slug: "me-demo",
2423
+ // "demo", not the made-up app's own name, so nobody takes it for ours.
2424
+ label: "demo",
2425
+ href: "https://me-demo.ochk.io",
2426
+ group: "app",
2427
+ line: "Lumen Notes, a made-up app that signs in with orangecheck.",
2428
+ status: "live"
2429
+ },
2430
+ {
2431
+ slug: "globe",
2432
+ label: "globe",
2433
+ href: "https://globe.ochk.io",
2434
+ group: "public-good",
2435
+ line: "The Bitcoin network, live, on a globe.",
2436
+ status: "live"
2437
+ },
2438
+ {
2439
+ slug: "btc",
2440
+ label: "btc",
2441
+ href: "https://btc.ochk.io",
2442
+ group: "public-good",
2443
+ line: "A free desk for reading the Bitcoin market.",
2444
+ status: "live"
2445
+ }
2446
+ ];
2447
+ var BY_SLUG = new Map(FAMILY.map((s) => [s.slug, s]));
2448
+ function protocolSite(slug) {
2449
+ return BY_SLUG.get(slug);
2450
+ }
2451
+ [
2452
+ {
2453
+ href: `${OCHK_IO}/protocols`,
2454
+ label: "Protocols",
2455
+ children: PROTOCOLS.map((p) => ({ href: p.pageHref, label: p.label, description: p.line }))
2456
+ },
2457
+ { href: `${OCHK_IO}/apps`, label: "Apps" },
2458
+ { href: DOCS_HREF, label: "Docs" },
2459
+ { href: `${OCHK_IO}/trust`, label: "Trust" },
2460
+ { href: `${OCHK_IO}/about`, label: "About" }
2461
+ ];
2462
+ var SiteHomeContext = sharedContext("site-home", void 0);
2463
+ function useSiteHome() {
2464
+ return react.useContext(SiteHomeContext);
2465
+ }
2329
2466
  var WORDS = {
2330
2467
  404: {
2331
2468
  name: "Not found",
@@ -2343,10 +2480,13 @@ function ErrorPage({
2343
2480
  title,
2344
2481
  detail,
2345
2482
  actions,
2346
- home = "/",
2483
+ home,
2484
+ protocol: protocol2,
2347
2485
  art,
2348
2486
  className
2349
2487
  }) {
2488
+ const shellHome = useSiteHome();
2489
+ const homeHref = home ?? (protocol2 ? protocolSite(protocol2).pageHref : shellHome ?? OCHK_IO);
2350
2490
  const words = WORDS[code] ?? (code >= 500 ? WORDS[500] : WORDS[404]);
2351
2491
  const server = code >= 500;
2352
2492
  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: [
@@ -2360,7 +2500,7 @@ function ErrorPage({
2360
2500
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "oca-lead oca-enter [--enter-delay:150ms]", children: detail ?? words.detail }),
2361
2501
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "oca-enter flex flex-wrap gap-3 [--enter-delay:230ms]", children: actions ?? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2362
2502
  server ? /* @__PURE__ */ jsxRuntime.jsx(Button, { onClick: () => window.location.reload(), children: "Try again" }) : null,
2363
- /* @__PURE__ */ jsxRuntime.jsx(Button, { asChild: true, variant: server ? "secondary" : "primary", children: /* @__PURE__ */ jsxRuntime.jsx(Link__default.default, { href: home, children: "Go home" }) })
2503
+ /* @__PURE__ */ jsxRuntime.jsx(Button, { asChild: true, variant: server ? "secondary" : "primary", children: /* @__PURE__ */ jsxRuntime.jsx(Link__default.default, { href: homeHref, children: "Go home" }) })
2364
2504
  ] }) })
2365
2505
  ] }),
2366
2506
  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
@@ -2584,12 +2724,21 @@ function Faq({
2584
2724
  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)) });
2585
2725
  }
2586
2726
  var LINK = "text-foreground underline decoration-foreground/35 underline-offset-4 transition-colors hover:decoration-foreground";
2727
+ var SCHEME = /^[a-z][a-z\d+.-]*:/i;
2728
+ function useResolved(href) {
2729
+ const router$1 = router.useRouter();
2730
+ if (!router$1 || !href || href.startsWith("/") || href.startsWith("#") || href.startsWith("?") || SCHEME.test(href)) return href;
2731
+ const here = router$1.asPath.split(/[?#]/)[0] || "/";
2732
+ const url = new URL(href, `https://page.invalid${here}`);
2733
+ return url.pathname + url.search + url.hash;
2734
+ }
2587
2735
  function TextLink({
2588
- href,
2736
+ href: written,
2589
2737
  children,
2590
2738
  external,
2591
2739
  className
2592
2740
  }) {
2741
+ const href = useResolved(written);
2593
2742
  const internal = href.startsWith("/") && !href.startsWith("/api/") && !href.startsWith("/.well-known/");
2594
2743
  const offsite = external ?? /^https?:\/\//.test(href);
2595
2744
  if (internal && !offsite) {
@@ -2702,129 +2851,10 @@ function LegalDocument({ doc, className }) {
2702
2851
  }
2703
2852
  );
2704
2853
  }
2705
-
2706
- // src/family/index.ts
2707
- var OCHK_IO = "https://ochk.io";
2708
- var DOCS_HREF = `${OCHK_IO}/docs`;
2709
- function protocol(slug, verb, line, kinds) {
2710
- return {
2711
- slug,
2712
- label: slug,
2713
- href: `${OCHK_IO}/${slug}`,
2714
- group: "protocol",
2715
- line,
2716
- status: "live",
2717
- verb,
2718
- pageHref: `${OCHK_IO}/${slug}`,
2719
- toolHref: `https://${slug}.ochk.io`,
2720
- specHref: `https://github.com/orangecheck/oc-${slug}-protocol`,
2721
- kinds
2722
- };
2723
- }
2724
- var PROTOCOLS = [
2725
- protocol("attest", "identity", "Show that an address holds bitcoin, and for how long.", "30078"),
2726
- protocol("lock", "confidentiality", "Encrypt to a Bitcoin address, so only its holder can open it.", "30078"),
2727
- protocol("vote", "legitimacy", "Polls weighed in sats, that anyone can tally.", "30080\u201330082"),
2728
- protocol("stamp", "provenance", "Prove who signed something, and when.", "30083"),
2729
- protocol("agent", "authority", "Give software scoped, revocable permission to act for you.", "30083\u201330086"),
2730
- protocol("pledge", "commitment", "Make a promise with bitcoin behind it, on a public record.", "30078")
2731
- ];
2732
- var PROTOCOL_ORDER = PROTOCOLS.map((p) => p.slug);
2733
- var FAMILY = [
2734
- {
2735
- slug: "home",
2736
- label: "ochk.io",
2737
- href: OCHK_IO,
2738
- group: "orangecheck",
2739
- line: "The open protocols, and the company behind them.",
2740
- status: "live"
2741
- },
2742
- {
2743
- slug: "me",
2744
- label: "ochk.app",
2745
- href: "https://ochk.app",
2746
- group: "orangecheck",
2747
- line: "One account, with Bitcoin behind it.",
2748
- status: "testing"
2749
- },
2750
- {
2751
- slug: "docs",
2752
- label: "docs",
2753
- href: DOCS_HREF,
2754
- group: "orangecheck",
2755
- line: "Specs, SDKs and guides for every protocol.",
2756
- status: "live"
2757
- },
2758
- ...PROTOCOLS,
2759
- {
2760
- slug: "vault",
2761
- label: "vault",
2762
- href: "https://vault.ochk.io",
2763
- group: "app",
2764
- line: "A password manager, encrypted in your browser.",
2765
- status: "live",
2766
- protocols: ["lock"]
2767
- },
2768
- {
2769
- slug: "chat",
2770
- label: "chat",
2771
- href: "https://chat.ochk.io",
2772
- group: "app",
2773
- line: "Messages only the holder of a Bitcoin address can read.",
2774
- status: "testing",
2775
- protocols: ["lock"]
2776
- },
2777
- {
2778
- slug: "cosign",
2779
- label: "cosign",
2780
- href: "https://cosign.ochk.io",
2781
- group: "app",
2782
- line: "Builders find co-founders and backers.",
2783
- status: "testing",
2784
- // Signs in with an orangecheck account and a wallet; uses none of the six directly.
2785
- protocols: []
2786
- },
2787
- {
2788
- slug: "me-demo",
2789
- // "demo", not the made-up app's own name, so nobody takes it for ours.
2790
- label: "demo",
2791
- href: "https://me-demo.ochk.io",
2792
- group: "app",
2793
- line: "Lumen Notes, a made-up app that signs in with orangecheck.",
2794
- status: "live"
2795
- },
2796
- {
2797
- slug: "globe",
2798
- label: "globe",
2799
- href: "https://globe.ochk.io",
2800
- group: "public-good",
2801
- line: "The Bitcoin network, live, on a globe.",
2802
- status: "live"
2803
- },
2804
- {
2805
- slug: "btc",
2806
- label: "btc",
2807
- href: "https://btc.ochk.io",
2808
- group: "public-good",
2809
- line: "A free desk for reading the Bitcoin market.",
2810
- status: "live"
2811
- }
2812
- ];
2813
- var BY_SLUG = new Map(FAMILY.map((s) => [s.slug, s]));
2814
- function protocolSite(slug) {
2815
- return BY_SLUG.get(slug);
2854
+ var InDocsContext = sharedContext("in-docs", false);
2855
+ function useInDocs() {
2856
+ return react.useContext(InDocsContext);
2816
2857
  }
2817
- [
2818
- {
2819
- href: `${OCHK_IO}/protocols`,
2820
- label: "Protocols",
2821
- children: PROTOCOLS.map((p) => ({ href: p.pageHref, label: p.label, description: p.line }))
2822
- },
2823
- { href: `${OCHK_IO}/apps`, label: "Apps" },
2824
- { href: DOCS_HREF, label: "Docs" },
2825
- { href: `${OCHK_IO}/trust`, label: "Trust" },
2826
- { href: `${OCHK_IO}/about`, label: "About" }
2827
- ];
2828
2858
  var WORD = {
2829
2859
  live: "Live",
2830
2860
  testing: "In testing",
@@ -2854,6 +2884,7 @@ function ProtocolGrid({
2854
2884
  link = "page",
2855
2885
  className
2856
2886
  }) {
2887
+ const inDocs = useInDocs();
2857
2888
  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) => {
2858
2889
  const p = protocolSite(slug);
2859
2890
  const i = PROTOCOL_ORDER.indexOf(slug);
@@ -2866,7 +2897,7 @@ function ProtocolGrid({
2866
2897
  ] }),
2867
2898
  p.status !== "live" ? /* @__PURE__ */ jsxRuntime.jsx(StatusBadge, { status: p.status }) : null
2868
2899
  ] }),
2869
- /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "oca-display-3", children: /* @__PURE__ */ jsxRuntime.jsx(
2900
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "oca-display-3", children: link === "docs" && inDocs ? /* @__PURE__ */ jsxRuntime.jsx(Link__default.default, { href: `/${p.slug}`, className: STRETCH, children: p.label }) : /* @__PURE__ */ jsxRuntime.jsx(
2870
2901
  "a",
2871
2902
  {
2872
2903
  href: link === "tool" ? p.toolHref : link === "docs" ? `${DOCS_HREF}/${p.slug}` : p.pageHref,
@@ -3114,371 +3145,6 @@ react.forwardRef(function RadioGroupItem2({ className, ...props }, ref) {
3114
3145
  }
3115
3146
  );
3116
3147
  });
3117
- function ProtocolHero({
3118
- protocol: protocol2,
3119
- title,
3120
- lead,
3121
- actions,
3122
- art,
3123
- children,
3124
- className
3125
- }) {
3126
- const p = protocolSite(protocol2);
3127
- return /* @__PURE__ */ jsxRuntime.jsx(
3128
- PageHero,
3129
- {
3130
- className,
3131
- eyebrow: `Protocol \xB7 ${p.verb}`,
3132
- title,
3133
- lead,
3134
- actions,
3135
- art,
3136
- children: p.status !== "live" || children ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-start gap-4", children: [
3137
- p.status !== "live" ? /* @__PURE__ */ jsxRuntime.jsx(StatusBadge, { status: p.status }) : null,
3138
- children
3139
- ] }) : null
3140
- }
3141
- );
3142
- }
3143
- function ProtocolNav({
3144
- current,
3145
- link = "page",
3146
- className
3147
- }) {
3148
- 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) => {
3149
- const on = p.slug === current;
3150
- return /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx(
3151
- "a",
3152
- {
3153
- href: link === "tool" ? p.toolHref : p.pageHref,
3154
- "aria-current": on ? "page" : void 0,
3155
- className: cn(
3156
- "-mb-px inline-flex h-11 items-center border-b-2 text-[0.9375rem] transition-colors",
3157
- on ? "border-foreground text-foreground" : "border-transparent text-muted-foreground hover:text-foreground"
3158
- ),
3159
- children: p.label
3160
- }
3161
- ) }, p.slug);
3162
- }) }) }) });
3163
- }
3164
- function SpecCard({
3165
- protocol: protocol2,
3166
- version,
3167
- license,
3168
- vectors,
3169
- size = "md",
3170
- className
3171
- }) {
3172
- const p = protocolSite(protocol2);
3173
- const repo = `oc-${p.slug}-protocol`;
3174
- const facts = [
3175
- ["Version", version],
3176
- ...license ? [["Licence", license]] : [],
3177
- ["Nostr kind", p.kinds],
3178
- ...vectors !== void 0 ? [["Test vectors", String(vectors)]] : []
3179
- ];
3180
- if (size === "sm") {
3181
- return /* @__PURE__ */ jsxRuntime.jsxs(
3182
- "a",
3183
- {
3184
- href: p.specHref,
3185
- className: cn(
3186
- "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",
3187
- className
3188
- ),
3189
- children: [
3190
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono text-[0.8125rem] text-foreground", children: repo }),
3191
- /* @__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 ") }),
3192
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "ml-auto flex items-center gap-1 text-muted-foreground group-hover:text-foreground", children: [
3193
- "Read the spec ",
3194
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUpRight, { "aria-hidden": true, className: "size-4" })
3195
- ] })
3196
- ]
3197
- }
3198
- );
3199
- }
3200
- 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: [
3201
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-4", children: [
3202
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-col gap-1.5", children: [
3203
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[0.875rem] text-muted-foreground", children: "The spec" }),
3204
- /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "oca-title break-all font-mono text-[1.0625rem] tracking-normal", children: repo })
3205
- ] }),
3206
- p.status !== "live" ? /* @__PURE__ */ jsxRuntime.jsx(StatusBadge, { status: p.status }) : null
3207
- ] }),
3208
- /* @__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: [
3209
- /* @__PURE__ */ jsxRuntime.jsx("dt", { className: "text-[0.8125rem] text-muted-foreground", children: k }),
3210
- /* @__PURE__ */ jsxRuntime.jsx("dd", { className: "oca-tabular text-[1.0625rem]", children: v })
3211
- ] }, k)) }),
3212
- /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(Button, { asChild: true, variant: "secondary", size: "sm", children: /* @__PURE__ */ jsxRuntime.jsxs("a", { href: p.specHref, children: [
3213
- "Read the spec ",
3214
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUpRight, { "aria-hidden": true })
3215
- ] }) }) })
3216
- ] });
3217
- }
3218
- function VerifyBox({
3219
- action,
3220
- param = "q",
3221
- title,
3222
- description,
3223
- label = "Id, envelope or link",
3224
- placeholder,
3225
- hint,
3226
- submitLabel = "Verify",
3227
- multiline = false,
3228
- onVerify,
3229
- className
3230
- }) {
3231
- const [value, setValue] = react.useState("");
3232
- const submit = (e) => {
3233
- if (!onVerify) return;
3234
- e.preventDefault();
3235
- if (value.trim()) onVerify(value.trim());
3236
- };
3237
- const button = /* @__PURE__ */ jsxRuntime.jsx(Button, { type: "submit", className: multiline ? void 0 : "w-full sm:w-auto", children: submitLabel });
3238
- return /* @__PURE__ */ jsxRuntime.jsxs(
3239
- "form",
3240
- {
3241
- action,
3242
- method: "get",
3243
- onSubmit: submit,
3244
- className: cn("flex flex-col gap-5 rounded-[1.25rem] border border-border bg-card p-6 md:p-8", className),
3245
- children: [
3246
- title || description ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
3247
- title ? /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "oca-title", children: title }) : null,
3248
- description ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "oca-body text-[0.9375rem]", children: description }) : null
3249
- ] }) : null,
3250
- multiline ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3251
- /* @__PURE__ */ jsxRuntime.jsx(Field, { label, hint, children: /* @__PURE__ */ jsxRuntime.jsx(
3252
- Textarea,
3253
- {
3254
- name: param,
3255
- required: true,
3256
- value,
3257
- onChange: (e) => setValue(e.target.value),
3258
- placeholder,
3259
- spellCheck: false,
3260
- className: "min-h-32 font-mono text-base md:text-[0.8125rem]"
3261
- }
3262
- ) }),
3263
- /* @__PURE__ */ jsxRuntime.jsx("div", { children: button })
3264
- ] }) : /* @__PURE__ */ jsxRuntime.jsx(Field, { label, hint, action: button, children: /* @__PURE__ */ jsxRuntime.jsx(
3265
- Input,
3266
- {
3267
- name: param,
3268
- required: true,
3269
- value,
3270
- onChange: (e) => setValue(e.target.value),
3271
- placeholder,
3272
- spellCheck: false,
3273
- autoComplete: "off",
3274
- className: "font-mono text-base md:text-[0.875rem]"
3275
- }
3276
- ) })
3277
- ]
3278
- }
3279
- );
3280
- }
3281
- var TINT = "bg-[color-mix(in_oklab,var(--oca-orange)_9%,var(--card))]";
3282
- function ComparisonTable({
3283
- columns,
3284
- rows,
3285
- label,
3286
- propertyHeading = "Property",
3287
- className
3288
- }) {
3289
- const wide = columns.length > 3;
3290
- const grid = wide ? "lg:grid lg:grid-cols-[var(--oca-compare)]" : "md:grid md:grid-cols-[var(--oca-compare)]";
3291
- const desk = wide ? "lg" : "md";
3292
- const style = {
3293
- // The argued-for column gets a little more room: its answers carry the page.
3294
- "--oca-compare": ["minmax(0, 1.4fr)", ...columns.map((c) => c.highlight ? "minmax(0, 1.3fr)" : "minmax(0, 1fr)")].join(" ")
3295
- };
3296
- const ordered = [...columns].sort((a, b) => Number(Boolean(b.highlight)) - Number(Boolean(a.highlight)));
3297
- 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: [
3298
- /* @__PURE__ */ jsxRuntime.jsxs(
3299
- "li",
3300
- {
3301
- "aria-hidden": true,
3302
- className: cn(
3303
- "hidden gap-5 px-5 py-4 text-[0.875rem] font-medium text-muted-foreground",
3304
- wide ? "lg:grid lg:px-8" : "md:grid md:px-8",
3305
- grid
3306
- ),
3307
- children: [
3308
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: propertyHeading }),
3309
- 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))
3310
- ]
3311
- }
3312
- ),
3313
- 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: [
3314
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-col gap-1", children: [
3315
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "oca-title-sm", children: r.label }),
3316
- r.note ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[0.875rem] leading-snug text-muted-foreground", children: r.note }) : null
3317
- ] }),
3318
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("grid grid-cols-2 gap-1", desk === "lg" ? "lg:contents" : "md:contents"), children: columns.map((c) => {
3319
- return /* @__PURE__ */ jsxRuntime.jsxs(
3320
- "div",
3321
- {
3322
- style: { "--oca-order": ordered.indexOf(c) },
3323
- className: cn(
3324
- // Two rows of the pair's grid (name, answer), so answers line up
3325
- // across a pair even when one name wraps.
3326
- "order-[var(--oca-order)] row-span-2 grid min-w-0 grid-rows-subgrid gap-1 rounded-xl px-3 py-2.5",
3327
- desk === "lg" ? "lg:order-none lg:row-span-1 lg:flex lg:flex-col" : "md:order-none md:row-span-1 md:flex md:flex-col",
3328
- c.highlight ? cn(
3329
- TINT,
3330
- "col-span-2",
3331
- desk === "lg" ? "lg:col-span-1 lg:-my-5 lg:self-stretch lg:rounded-none lg:px-4 lg:py-5" : "md:col-span-1 md:-my-5 md:self-stretch md:rounded-none md:px-4 md:py-5"
3332
- ) : desk === "lg" ? "lg:p-0" : "md:p-0"
3333
- ),
3334
- children: [
3335
- /* @__PURE__ */ jsxRuntime.jsx(
3336
- "span",
3337
- {
3338
- className: cn(
3339
- "text-[0.8125rem]",
3340
- c.highlight ? "text-oca-accent-ink" : "text-muted-foreground",
3341
- desk === "lg" ? "lg:sr-only" : "md:sr-only"
3342
- ),
3343
- children: c.label
3344
- }
3345
- ),
3346
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("text-[0.9375rem]", c.highlight && "font-medium"), children: r.values[c.key] ?? "\u2014" })
3347
- ]
3348
- },
3349
- c.key
3350
- );
3351
- }) })
3352
- ] }, ri))
3353
- ] });
3354
- }
3355
- var CHECK = {
3356
- ok: { word: "Passed", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CircleCheck, {}), tone: "text-success" },
3357
- fail: { word: "Failed", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CircleX, {}), tone: "text-destructive" },
3358
- pending: { word: "Pending", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Clock, {}), tone: "text-oca-accent-ink" },
3359
- none: { word: "None", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CircleSlash, {}), tone: "text-muted-foreground" },
3360
- skipped: { word: "Skipped", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CircleMinus, {}), tone: "text-muted-foreground" },
3361
- unchecked: { word: "Not checked", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CircleDashed, {}), tone: "text-oca-subtle" }
3362
- };
3363
- function VerifyReport({
3364
- verdict,
3365
- title,
3366
- summary,
3367
- checks,
3368
- facts,
3369
- notChecked,
3370
- actions,
3371
- as: Heading = "h2",
3372
- className
3373
- }) {
3374
- return /* @__PURE__ */ jsxRuntime.jsxs(
3375
- "section",
3376
- {
3377
- "aria-label": "Verification result",
3378
- className: cn("overflow-hidden rounded-[1.25rem] border border-border bg-card", className),
3379
- children: [
3380
- /* @__PURE__ */ jsxRuntime.jsxs("header", { className: "flex flex-col items-start gap-3 p-6 md:p-8", children: [
3381
- /* @__PURE__ */ jsxRuntime.jsx(StatusBadge, { status: verdict }),
3382
- /* @__PURE__ */ jsxRuntime.jsx(Heading, { className: "oca-display-3 [overflow-wrap:anywhere]", children: title }),
3383
- summary ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "oca-body max-w-[40rem] [overflow-wrap:anywhere]", children: summary }) : null
3384
- ] }),
3385
- /* @__PURE__ */ jsxRuntime.jsx("ul", { "aria-label": "Checks", className: "divide-y divide-border border-t border-border", children: checks.map((c, i) => {
3386
- const k = CHECK[c.state];
3387
- return /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex items-start gap-3 px-6 py-3.5 md:px-8", children: [
3388
- /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: cn("mt-0.5 shrink-0 [&_svg]:size-[1.125rem]", k.tone), children: k.icon }),
3389
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-0.5 sm:flex-row sm:items-baseline sm:justify-between sm:gap-6", children: [
3390
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-col gap-0.5", children: [
3391
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[0.9375rem]", children: c.label }),
3392
- c.note ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "break-words text-[0.8125rem] leading-snug text-muted-foreground", children: c.note }) : null
3393
- ] }),
3394
- /* @__PURE__ */ jsxRuntime.jsx(
3395
- "span",
3396
- {
3397
- className: cn(
3398
- "shrink-0 text-[0.8125rem]",
3399
- c.state === "fail" ? "text-destructive" : "text-muted-foreground"
3400
- ),
3401
- children: k.word
3402
- }
3403
- )
3404
- ] })
3405
- ] }, i);
3406
- }) }),
3407
- facts && facts.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(KeyValueList, { items: facts, className: "rounded-none border-x-0 border-b-0 bg-transparent [&>div]:px-6 md:[&>div]:px-8" }) : null,
3408
- notChecked && notChecked.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2 border-t border-border bg-muted/50 px-6 py-5 md:px-8", children: [
3409
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[0.875rem] font-medium", children: "What this did not check" }),
3410
- /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "flex list-disc flex-col gap-1 pl-5 text-[0.875rem] leading-relaxed text-muted-foreground", children: notChecked.map((n, i) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: n }, i)) })
3411
- ] }) : null,
3412
- actions ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-3 border-t border-border px-6 py-5 md:px-8", children: actions }) : null
3413
- ]
3414
- }
3415
- );
3416
- }
3417
- function SignMessage({
3418
- lead,
3419
- address,
3420
- message,
3421
- wallets,
3422
- busy = false,
3423
- error,
3424
- submitLabel = "Confirm",
3425
- secondary,
3426
- onSignature,
3427
- className
3428
- }) {
3429
- const [pasted, setPasted] = react.useState("");
3430
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-col gap-5", className), children: [
3431
- lead ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[0.9375rem] leading-relaxed", children: lead }) : null,
3432
- wallets ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3433
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-2", children: wallets }),
3434
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 text-[0.8125rem] text-muted-foreground", children: [
3435
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "h-px flex-1 bg-border" }),
3436
- "or sign it in any wallet",
3437
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "h-px flex-1 bg-border" })
3438
- ] })
3439
- ] }) : null,
3440
- /* @__PURE__ */ jsxRuntime.jsx(CodeBlock, { code: message, caption: "Message to sign" }),
3441
- /* @__PURE__ */ jsxRuntime.jsxs(
3442
- "form",
3443
- {
3444
- className: "flex flex-col gap-4",
3445
- onSubmit: (e) => {
3446
- e.preventDefault();
3447
- if (pasted.trim()) onSignature(pasted.trim());
3448
- },
3449
- children: [
3450
- /* @__PURE__ */ jsxRuntime.jsx(
3451
- Field,
3452
- {
3453
- label: "Signature",
3454
- error,
3455
- hint: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3456
- "From your wallet\u2019s \u201Csign message\u201D (BIP-322), signed by",
3457
- " ",
3458
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "break-all font-mono", children: address }),
3459
- "."
3460
- ] }),
3461
- children: /* @__PURE__ */ jsxRuntime.jsx(
3462
- Textarea,
3463
- {
3464
- value: pasted,
3465
- onChange: (e) => setPasted(e.target.value),
3466
- rows: 3,
3467
- spellCheck: false,
3468
- className: "min-h-24 font-mono text-base md:text-[0.8125rem]"
3469
- }
3470
- )
3471
- }
3472
- ),
3473
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-2", children: [
3474
- /* @__PURE__ */ jsxRuntime.jsx(Button, { type: "submit", loading: busy, disabled: !pasted.trim(), children: submitLabel }),
3475
- secondary
3476
- ] })
3477
- ]
3478
- }
3479
- )
3480
- ] });
3481
- }
3482
3148
  var isInternal = (href) => href.startsWith("/") || href.startsWith("#");
3483
3149
  function DocLink({ href, className, children, ...rest }) {
3484
3150
  return isInternal(href) ? /* @__PURE__ */ jsxRuntime.jsx(Link__default.default, { href, className, ...rest, children }) : /* @__PURE__ */ jsxRuntime.jsx("a", { href, className, ...rest, children });
@@ -3667,6 +3333,7 @@ function MdxTable({ className, ...props }) {
3667
3333
  }
3668
3334
  ) }) });
3669
3335
  }
3336
+ var said = (n) => n !== void 0 && n !== null && n !== false && n !== "";
3670
3337
  function ApiTable({
3671
3338
  rows,
3672
3339
  caption,
@@ -3674,43 +3341,42 @@ function ApiTable({
3674
3341
  className
3675
3342
  }) {
3676
3343
  const hasDefault = rows.some((r) => r.default !== void 0);
3677
- const marks = (r) => /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3678
- r.required ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[0.75rem] text-oca-accent-ink", children: "Required" }) : null,
3679
- r.deprecated ? /* @__PURE__ */ jsxRuntime.jsx(Badge, { tone: "muted", children: "Deprecated" }) : null,
3680
- r.status ? /* @__PURE__ */ jsxRuntime.jsx(StatusBadge, { status: r.status }) : null
3681
- ] });
3682
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("not-prose my-6", className), children: [
3683
- /* @__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: [
3684
- caption ? /* @__PURE__ */ jsxRuntime.jsx("caption", { className: "sr-only", children: caption }) : null,
3685
- /* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "border-b border-oca-hairline-strong bg-oca-table-head text-[0.8125rem]", children: [
3686
- /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", className: "px-4 py-2.5 font-medium", children: nameHeader }),
3687
- /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", className: "px-4 py-2.5 font-medium", children: "Type" }),
3688
- hasDefault ? /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", className: "px-4 py-2.5 font-medium", children: "Default" }) : null,
3689
- /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", className: "px-4 py-2.5 font-medium", children: "Description" })
3690
- ] }) }),
3691
- /* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "divide-y divide-border", children: rows.map((r) => /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "align-top", children: [
3692
- /* @__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: [
3693
- /* @__PURE__ */ jsxRuntime.jsx("code", { className: cn("font-mono text-[0.8125rem] text-foreground", r.deprecated && "line-through decoration-oca-subtle"), children: r.name }),
3694
- marks(r)
3695
- ] }) }),
3696
- /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3 font-mono text-[0.8125rem] text-muted-foreground", children: r.type ?? "\u2014" }),
3697
- hasDefault ? /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3 font-mono text-[0.8125rem] text-muted-foreground", children: r.default ?? "\u2014" }) : null,
3698
- /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3 leading-relaxed text-muted-foreground", children: r.description })
3699
- ] }, r.name)) })
3700
- ] }) }) }),
3701
- /* @__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: [
3702
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex flex-wrap items-baseline gap-x-2 gap-y-1", children: [
3703
- /* @__PURE__ */ jsxRuntime.jsx("code", { className: cn("font-mono text-[0.875rem] text-foreground", r.deprecated && "line-through decoration-oca-subtle"), children: r.name }),
3704
- r.type ? /* @__PURE__ */ jsxRuntime.jsx("code", { className: "break-all font-mono text-[0.8125rem] text-muted-foreground", children: r.type }) : null
3705
- ] }),
3706
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex flex-wrap items-center gap-2 empty:hidden", children: marks(r) }),
3707
- r.description ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[0.875rem] leading-relaxed text-muted-foreground", children: r.description }) : null,
3708
- r.default !== void 0 ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-[0.8125rem] text-muted-foreground", children: [
3709
- "Default ",
3710
- /* @__PURE__ */ jsxRuntime.jsx("code", { className: "font-mono text-foreground", children: r.default })
3711
- ] }) : null
3712
- ] }, r.name)) })
3713
- ] });
3344
+ const hasDescription = rows.some((r) => said(r.description));
3345
+ const hasSource = rows.some((r) => said(r.source));
3346
+ const cell = "px-4 py-3 max-sm:p-0";
3347
+ 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: [
3348
+ caption ? /* @__PURE__ */ jsxRuntime.jsx("caption", { className: "sr-only", children: caption }) : null,
3349
+ /* @__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: [
3350
+ /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", className: "px-4 py-2.5 font-medium", children: nameHeader }),
3351
+ /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", className: "px-4 py-2.5 font-medium", children: "Type" }),
3352
+ hasDefault ? /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", className: "px-4 py-2.5 font-medium", children: "Default" }) : null,
3353
+ hasDescription ? /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", className: "px-4 py-2.5 font-medium", children: "Description" }) : null,
3354
+ hasSource ? /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", className: "px-4 py-2.5 font-medium", children: "Defined in" }) : null
3355
+ ] }) }),
3356
+ /* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "divide-y divide-border max-sm:block", children: rows.map((r) => /* @__PURE__ */ jsxRuntime.jsxs(
3357
+ "tr",
3358
+ {
3359
+ id: r.id,
3360
+ 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",
3361
+ children: [
3362
+ /* @__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: [
3363
+ /* @__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 }),
3364
+ r.required ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[0.75rem] text-oca-accent-ink", children: "Required" }) : null,
3365
+ r.deprecated ? /* @__PURE__ */ jsxRuntime.jsx(Badge, { tone: "muted", children: "Deprecated" }) : null,
3366
+ r.status ? /* @__PURE__ */ jsxRuntime.jsx(StatusBadge, { status: r.status }) : null
3367
+ ] }) }),
3368
+ /* @__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" }),
3369
+ 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: [
3370
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-sans sm:hidden", children: "Default " }),
3371
+ r.default ?? "\u2014"
3372
+ ] }) : null,
3373
+ hasDescription ? /* @__PURE__ */ jsxRuntime.jsx("td", { className: cn(cell, "leading-relaxed text-muted-foreground", !said(r.description) && "max-sm:hidden"), children: r.description }) : null,
3374
+ 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
3375
+ ]
3376
+ },
3377
+ r.id ?? r.name
3378
+ )) })
3379
+ ] }) }) });
3714
3380
  }
3715
3381
  function useDarkMode() {
3716
3382
  const [dark, setDark] = react.useState(false);
@@ -3772,79 +3438,490 @@ function mermaidTheme(el) {
3772
3438
  sequenceNumberColor: card
3773
3439
  };
3774
3440
  }
3441
+ var FIT = 4 / 3;
3775
3442
  function naturalSize(svg) {
3776
3443
  const w = svg.match(/viewBox="[\d.-]+ [\d.-]+ ([\d.]+) [\d.]+"/)?.[1];
3777
- if (!w) return svg;
3778
- return svg.replace(/<svg([^>]*?)\swidth="100%"/, `<svg$1 width="${Math.ceil(Number(w))}"`).replace(/max-width:\s*[\d.]+px;?/, "");
3444
+ if (!w) return { svg, width: null };
3445
+ const width = Math.ceil(Number(w));
3446
+ return {
3447
+ svg: svg.replace(/<svg([^>]*?)\swidth="100%"/, `<svg$1 width="${width}"`).replace(/max-width:\s*[\d.]+px;?/, ""),
3448
+ width
3449
+ };
3450
+ }
3451
+ function useInnerWidth(ref, padding) {
3452
+ const [width, setWidth] = react.useState(null);
3453
+ react.useEffect(() => {
3454
+ const el = ref.current;
3455
+ if (!el) return;
3456
+ const ro = new ResizeObserver(() => setWidth(el.clientWidth - padding));
3457
+ ro.observe(el);
3458
+ return () => ro.disconnect();
3459
+ }, [ref, padding]);
3460
+ return width;
3461
+ }
3462
+ function Diagram({ chart, caption, load, className }) {
3463
+ const ref = react.useRef(null);
3464
+ const dark = useDarkMode();
3465
+ const raw = react.useId();
3466
+ const [drawn, setDrawn] = react.useState(null);
3467
+ const [failed, setFailed] = react.useState(false);
3468
+ const room = useInnerWidth(ref, 48);
3469
+ const fits = drawn?.width != null && room != null && drawn.width <= room * FIT;
3470
+ react.useEffect(() => {
3471
+ let live = true;
3472
+ const el = ref.current;
3473
+ if (!el) return;
3474
+ (async () => {
3475
+ try {
3476
+ const mod = await load();
3477
+ const mermaid = "default" in mod ? mod.default : mod;
3478
+ mermaid.initialize({ startOnLoad: false, securityLevel: "strict", theme: "base", themeVariables: mermaidTheme(el) });
3479
+ const { svg } = await mermaid.render(`oca-diagram-${raw.replace(/[^a-zA-Z0-9]/g, "")}-${dark ? "d" : "l"}`, chart);
3480
+ if (live) {
3481
+ setDrawn(naturalSize(svg));
3482
+ setFailed(false);
3483
+ }
3484
+ } catch {
3485
+ if (live) setFailed(true);
3486
+ }
3487
+ })();
3488
+ return () => {
3489
+ live = false;
3490
+ };
3491
+ }, [chart, dark, load, raw]);
3492
+ if (failed) return /* @__PURE__ */ jsxRuntime.jsx(CodeBlock, { code: chart, caption: "Diagram (shown as its source)", className: cn("my-6", className) });
3493
+ return /* @__PURE__ */ jsxRuntime.jsxs("figure", { ref, className: cn("not-prose my-6 overflow-hidden rounded-[1.25rem] border border-border bg-card", className), children: [
3494
+ drawn ? /* @__PURE__ */ jsxRuntime.jsx(ScrollFade, { fade: "var(--card)", children: /* @__PURE__ */ jsxRuntime.jsx(
3495
+ "div",
3496
+ {
3497
+ "data-fit": fits ? "" : void 0,
3498
+ className: cn(
3499
+ "flex justify-center p-6 [&_svg]:h-auto",
3500
+ fits ? "w-full [&_svg]:max-w-full" : "w-max min-w-full [&_svg]:max-w-none"
3501
+ ),
3502
+ role: "img",
3503
+ "aria-label": typeof caption === "string" ? caption : "Diagram",
3504
+ dangerouslySetInnerHTML: { __html: drawn.svg }
3505
+ }
3506
+ ) }) : /* @__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" }) }),
3507
+ caption ? /* @__PURE__ */ jsxRuntime.jsx("figcaption", { className: "border-t border-border px-5 py-3 text-[0.8125rem] text-muted-foreground", children: caption }) : null
3508
+ ] });
3509
+ }
3510
+ var HEADING = {
3511
+ h1: "oca-display-3 mb-4 text-foreground",
3512
+ h2: "mb-3 mt-12 text-[1.375rem] font-medium leading-tight tracking-[-0.015em] text-foreground md:text-[1.5rem]",
3513
+ h3: "mb-2 mt-9 text-[1.125rem] font-medium leading-snug tracking-[-0.01em] text-foreground",
3514
+ h4: "mb-2 mt-7 text-[1rem] font-medium leading-snug text-foreground"
3515
+ };
3516
+ function DocsHeading({
3517
+ as: Tag,
3518
+ id,
3519
+ children,
3520
+ className,
3521
+ ...props
3522
+ }) {
3523
+ return /* @__PURE__ */ jsxRuntime.jsxs(Tag, { id, className: cn("group scroll-mt-28", HEADING[Tag], className), ...props, children: [
3524
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "data-heading-text": "", children }),
3525
+ id && Tag !== "h1" ? /* @__PURE__ */ jsxRuntime.jsxs(
3526
+ "a",
3527
+ {
3528
+ href: `#${id}`,
3529
+ 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",
3530
+ children: [
3531
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, children: "#" }),
3532
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Link to this section" })
3533
+ ]
3534
+ }
3535
+ ) : null
3536
+ ] });
3537
+ }
3538
+ function ProtocolHero({
3539
+ protocol: protocol2,
3540
+ title,
3541
+ lead,
3542
+ actions,
3543
+ art,
3544
+ children,
3545
+ className
3546
+ }) {
3547
+ const p = protocolSite(protocol2);
3548
+ return /* @__PURE__ */ jsxRuntime.jsx(
3549
+ PageHero,
3550
+ {
3551
+ className,
3552
+ eyebrow: `Protocol \xB7 ${p.verb}`,
3553
+ title,
3554
+ lead,
3555
+ actions,
3556
+ art,
3557
+ children: p.status !== "live" || children ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-start gap-4", children: [
3558
+ p.status !== "live" ? /* @__PURE__ */ jsxRuntime.jsx(StatusBadge, { status: p.status }) : null,
3559
+ children
3560
+ ] }) : null
3561
+ }
3562
+ );
3563
+ }
3564
+ function ProtocolNav({
3565
+ current,
3566
+ link = "page",
3567
+ className
3568
+ }) {
3569
+ 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) => {
3570
+ const on = p.slug === current;
3571
+ return /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx(
3572
+ "a",
3573
+ {
3574
+ href: link === "tool" ? p.toolHref : p.pageHref,
3575
+ "aria-current": on ? "page" : void 0,
3576
+ className: cn(
3577
+ "-mb-px inline-flex h-11 items-center border-b-2 text-[0.9375rem] transition-colors",
3578
+ on ? "border-foreground text-foreground" : "border-transparent text-muted-foreground hover:text-foreground"
3579
+ ),
3580
+ children: p.label
3581
+ }
3582
+ ) }, p.slug);
3583
+ }) }) }) });
3584
+ }
3585
+ var SPEC_FILE = {
3586
+ spec: {
3587
+ file: "SPEC.md",
3588
+ title: "Normative source",
3589
+ note: "This page is a human-readable summary. The authoritative copy lives in the spec repo. If the two ever drift, the repo wins."
3590
+ },
3591
+ security: {
3592
+ file: "SECURITY.md",
3593
+ title: "Normative threat model",
3594
+ note: "This page is the short form. The authoritative, numbered threat model lives in the spec repo."
3595
+ },
3596
+ rationale: {
3597
+ file: "WHY.md",
3598
+ title: "Design rationale",
3599
+ note: "This page is the short version. The full rationale and the rejected-design log live in the spec repo."
3600
+ }
3601
+ };
3602
+ function SpecCard(props) {
3603
+ return props.repo !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(SpecFileNote, { ...props }) : /* @__PURE__ */ jsxRuntime.jsx(ProtocolSpecCard, { ...props });
3604
+ }
3605
+ function SpecFileNote({ repo, file, kind = "spec", version, note, className }) {
3606
+ const d = SPEC_FILE[kind];
3607
+ const f = file ?? d.file;
3608
+ return /* @__PURE__ */ jsxRuntime.jsxs(Callout, { title: version ? `${d.title} \xB7 ${version}` : d.title, className, children: [
3609
+ /* @__PURE__ */ jsxRuntime.jsx("p", { children: note ?? d.note }),
3610
+ /* @__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}` }) })
3611
+ ] });
3612
+ }
3613
+ function ProtocolSpecCard({ protocol: protocol2, version, license, vectors, size = "md", className }) {
3614
+ const p = protocolSite(protocol2);
3615
+ const repo = `oc-${p.slug}-protocol`;
3616
+ const facts = [
3617
+ ["Version", version],
3618
+ ...license ? [["Licence", license]] : [],
3619
+ ["Nostr kind", p.kinds],
3620
+ ...vectors !== void 0 ? [["Test vectors", String(vectors)]] : []
3621
+ ];
3622
+ if (size === "sm") {
3623
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3624
+ "a",
3625
+ {
3626
+ href: p.specHref,
3627
+ className: cn(
3628
+ "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",
3629
+ className
3630
+ ),
3631
+ children: [
3632
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono text-[0.8125rem] text-foreground", children: repo }),
3633
+ /* @__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 ") }),
3634
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "ml-auto flex items-center gap-1 text-muted-foreground group-hover:text-foreground", children: [
3635
+ "Read the spec ",
3636
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUpRight, { "aria-hidden": true, className: "size-4" })
3637
+ ] })
3638
+ ]
3639
+ }
3640
+ );
3641
+ }
3642
+ 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: [
3643
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-4", children: [
3644
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-col gap-1.5", children: [
3645
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[0.875rem] text-muted-foreground", children: "The spec" }),
3646
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "oca-title break-all font-mono text-[1.0625rem] tracking-normal", children: repo })
3647
+ ] }),
3648
+ p.status !== "live" ? /* @__PURE__ */ jsxRuntime.jsx(StatusBadge, { status: p.status }) : null
3649
+ ] }),
3650
+ /* @__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: [
3651
+ /* @__PURE__ */ jsxRuntime.jsx("dt", { className: "text-[0.8125rem] text-muted-foreground", children: k }),
3652
+ /* @__PURE__ */ jsxRuntime.jsx("dd", { className: "oca-tabular text-[1.0625rem]", children: v })
3653
+ ] }, k)) }),
3654
+ /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(Button, { asChild: true, variant: "secondary", size: "sm", children: /* @__PURE__ */ jsxRuntime.jsxs("a", { href: p.specHref, children: [
3655
+ "Read the spec ",
3656
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUpRight, { "aria-hidden": true })
3657
+ ] }) }) })
3658
+ ] });
3659
+ }
3660
+ function VerifyBox({
3661
+ action,
3662
+ param = "q",
3663
+ title,
3664
+ description,
3665
+ label = "Id, envelope or link",
3666
+ placeholder,
3667
+ hint,
3668
+ submitLabel = "Verify",
3669
+ multiline = false,
3670
+ onVerify,
3671
+ className
3672
+ }) {
3673
+ const [value, setValue] = react.useState("");
3674
+ const submit = (e) => {
3675
+ if (!onVerify) return;
3676
+ e.preventDefault();
3677
+ if (value.trim()) onVerify(value.trim());
3678
+ };
3679
+ const button = /* @__PURE__ */ jsxRuntime.jsx(Button, { type: "submit", className: multiline ? void 0 : "w-full sm:w-auto", children: submitLabel });
3680
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3681
+ "form",
3682
+ {
3683
+ action,
3684
+ method: "get",
3685
+ onSubmit: submit,
3686
+ className: cn("flex flex-col gap-5 rounded-[1.25rem] border border-border bg-card p-6 md:p-8", className),
3687
+ children: [
3688
+ title || description ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
3689
+ title ? /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "oca-title", children: title }) : null,
3690
+ description ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "oca-body text-[0.9375rem]", children: description }) : null
3691
+ ] }) : null,
3692
+ multiline ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3693
+ /* @__PURE__ */ jsxRuntime.jsx(Field, { label, hint, children: /* @__PURE__ */ jsxRuntime.jsx(
3694
+ Textarea,
3695
+ {
3696
+ name: param,
3697
+ required: true,
3698
+ value,
3699
+ onChange: (e) => setValue(e.target.value),
3700
+ placeholder,
3701
+ spellCheck: false,
3702
+ className: "min-h-32 font-mono text-base md:text-[0.8125rem]"
3703
+ }
3704
+ ) }),
3705
+ /* @__PURE__ */ jsxRuntime.jsx("div", { children: button })
3706
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx(Field, { label, hint, action: button, children: /* @__PURE__ */ jsxRuntime.jsx(
3707
+ Input,
3708
+ {
3709
+ name: param,
3710
+ required: true,
3711
+ value,
3712
+ onChange: (e) => setValue(e.target.value),
3713
+ placeholder,
3714
+ spellCheck: false,
3715
+ autoComplete: "off",
3716
+ className: "font-mono text-base md:text-[0.875rem]"
3717
+ }
3718
+ ) })
3719
+ ]
3720
+ }
3721
+ );
3779
3722
  }
3780
- function Diagram({ chart, caption, load, className }) {
3781
- const ref = react.useRef(null);
3782
- const dark = useDarkMode();
3783
- const raw = react.useId();
3784
- const [svg, setSvg] = react.useState(null);
3785
- const [failed, setFailed] = react.useState(false);
3786
- react.useEffect(() => {
3787
- let live = true;
3788
- const el = ref.current;
3789
- if (!el) return;
3790
- (async () => {
3791
- try {
3792
- const mod = await load();
3793
- const mermaid = "default" in mod ? mod.default : mod;
3794
- mermaid.initialize({ startOnLoad: false, securityLevel: "strict", theme: "base", themeVariables: mermaidTheme(el) });
3795
- const { svg: drawn } = await mermaid.render(`oca-diagram-${raw.replace(/[^a-zA-Z0-9]/g, "")}-${dark ? "d" : "l"}`, chart);
3796
- if (live) {
3797
- setSvg(naturalSize(drawn));
3798
- setFailed(false);
3799
- }
3800
- } catch {
3801
- if (live) setFailed(true);
3802
- }
3803
- })();
3804
- return () => {
3805
- live = false;
3806
- };
3807
- }, [chart, dark, load, raw]);
3808
- if (failed) return /* @__PURE__ */ jsxRuntime.jsx(CodeBlock, { code: chart, caption: "Diagram (shown as its source)", className: cn("my-6", className) });
3809
- return /* @__PURE__ */ jsxRuntime.jsxs("figure", { ref, className: cn("not-prose my-6 overflow-hidden rounded-[1.25rem] border border-border bg-card", className), children: [
3810
- svg ? /* @__PURE__ */ jsxRuntime.jsx(ScrollFade, { fade: "var(--card)", children: /* @__PURE__ */ jsxRuntime.jsx(
3811
- "div",
3723
+ var TINT = "bg-[color-mix(in_oklab,var(--oca-orange)_9%,var(--card))]";
3724
+ function ComparisonTable({
3725
+ columns,
3726
+ rows,
3727
+ label,
3728
+ propertyHeading = "Property",
3729
+ className
3730
+ }) {
3731
+ const wide = columns.length > 3;
3732
+ const grid = wide ? "lg:grid lg:grid-cols-[var(--oca-compare)]" : "md:grid md:grid-cols-[var(--oca-compare)]";
3733
+ const desk = wide ? "lg" : "md";
3734
+ const style = {
3735
+ // The argued-for column gets a little more room: its answers carry the page.
3736
+ "--oca-compare": ["minmax(0, 1.4fr)", ...columns.map((c) => c.highlight ? "minmax(0, 1.3fr)" : "minmax(0, 1fr)")].join(" ")
3737
+ };
3738
+ const ordered = [...columns].sort((a, b) => Number(Boolean(b.highlight)) - Number(Boolean(a.highlight)));
3739
+ 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: [
3740
+ /* @__PURE__ */ jsxRuntime.jsxs(
3741
+ "li",
3812
3742
  {
3813
- className: "flex w-max min-w-full justify-center p-6 [&_svg]:h-auto [&_svg]:max-w-none",
3814
- role: "img",
3815
- "aria-label": typeof caption === "string" ? caption : "Diagram",
3816
- dangerouslySetInnerHTML: { __html: svg }
3743
+ "aria-hidden": true,
3744
+ className: cn(
3745
+ "hidden gap-5 px-5 py-4 text-[0.875rem] font-medium text-muted-foreground",
3746
+ wide ? "lg:grid lg:px-8" : "md:grid md:px-8",
3747
+ grid
3748
+ ),
3749
+ children: [
3750
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: propertyHeading }),
3751
+ 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))
3752
+ ]
3817
3753
  }
3818
- ) }) : /* @__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" }) }),
3819
- caption ? /* @__PURE__ */ jsxRuntime.jsx("figcaption", { className: "border-t border-border px-5 py-3 text-[0.8125rem] text-muted-foreground", children: caption }) : null
3754
+ ),
3755
+ 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: [
3756
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-col gap-1", children: [
3757
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "oca-title-sm", children: r.label }),
3758
+ r.note ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[0.875rem] leading-snug text-muted-foreground", children: r.note }) : null
3759
+ ] }),
3760
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("grid grid-cols-2 gap-1", desk === "lg" ? "lg:contents" : "md:contents"), children: columns.map((c) => {
3761
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3762
+ "div",
3763
+ {
3764
+ style: { "--oca-order": ordered.indexOf(c) },
3765
+ className: cn(
3766
+ // Two rows of the pair's grid (name, answer), so answers line up
3767
+ // across a pair even when one name wraps.
3768
+ "order-[var(--oca-order)] row-span-2 grid min-w-0 grid-rows-subgrid gap-1 rounded-xl px-3 py-2.5",
3769
+ desk === "lg" ? "lg:order-none lg:row-span-1 lg:flex lg:flex-col" : "md:order-none md:row-span-1 md:flex md:flex-col",
3770
+ c.highlight ? cn(
3771
+ TINT,
3772
+ "col-span-2",
3773
+ desk === "lg" ? "lg:col-span-1 lg:-my-5 lg:self-stretch lg:rounded-none lg:px-4 lg:py-5" : "md:col-span-1 md:-my-5 md:self-stretch md:rounded-none md:px-4 md:py-5"
3774
+ ) : desk === "lg" ? "lg:p-0" : "md:p-0"
3775
+ ),
3776
+ children: [
3777
+ /* @__PURE__ */ jsxRuntime.jsx(
3778
+ "span",
3779
+ {
3780
+ className: cn(
3781
+ "text-[0.8125rem]",
3782
+ c.highlight ? "text-oca-accent-ink" : "text-muted-foreground",
3783
+ desk === "lg" ? "lg:sr-only" : "md:sr-only"
3784
+ ),
3785
+ children: c.label
3786
+ }
3787
+ ),
3788
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("text-[0.9375rem]", c.highlight && "font-medium"), children: r.values[c.key] ?? "\u2014" })
3789
+ ]
3790
+ },
3791
+ c.key
3792
+ );
3793
+ }) })
3794
+ ] }, ri))
3820
3795
  ] });
3821
3796
  }
3822
- var HEADING = {
3823
- h1: "oca-display-3 mb-4 text-foreground",
3824
- h2: "mb-3 mt-12 text-[1.375rem] font-medium leading-tight tracking-[-0.015em] text-foreground md:text-[1.5rem]",
3825
- h3: "mb-2 mt-9 text-[1.125rem] font-medium leading-snug tracking-[-0.01em] text-foreground",
3826
- h4: "mb-2 mt-7 text-[1rem] font-medium leading-snug text-foreground"
3797
+ var CHECK = {
3798
+ ok: { word: "Passed", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CircleCheck, {}), tone: "text-success" },
3799
+ fail: { word: "Failed", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CircleX, {}), tone: "text-destructive" },
3800
+ pending: { word: "Pending", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Clock, {}), tone: "text-oca-accent-ink" },
3801
+ none: { word: "None", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CircleSlash, {}), tone: "text-muted-foreground" },
3802
+ skipped: { word: "Skipped", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CircleMinus, {}), tone: "text-muted-foreground" },
3803
+ unchecked: { word: "Not checked", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CircleDashed, {}), tone: "text-oca-subtle" }
3827
3804
  };
3828
- function DocsHeading({
3829
- as: Tag,
3830
- id,
3831
- children,
3832
- className,
3833
- ...props
3805
+ function VerifyReport({
3806
+ verdict,
3807
+ title,
3808
+ summary,
3809
+ checks,
3810
+ facts,
3811
+ notChecked,
3812
+ actions,
3813
+ as: Heading = "h2",
3814
+ className
3834
3815
  }) {
3835
- return /* @__PURE__ */ jsxRuntime.jsxs(Tag, { id, className: cn("group scroll-mt-28", HEADING[Tag], className), ...props, children: [
3836
- /* @__PURE__ */ jsxRuntime.jsx("span", { "data-heading-text": "", children }),
3837
- id && Tag !== "h1" ? /* @__PURE__ */ jsxRuntime.jsxs(
3838
- "a",
3816
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3817
+ "section",
3818
+ {
3819
+ "aria-label": "Verification result",
3820
+ className: cn("overflow-hidden rounded-[1.25rem] border border-border bg-card", className),
3821
+ children: [
3822
+ /* @__PURE__ */ jsxRuntime.jsxs("header", { className: "flex flex-col items-start gap-3 p-6 md:p-8", children: [
3823
+ /* @__PURE__ */ jsxRuntime.jsx(StatusBadge, { status: verdict }),
3824
+ /* @__PURE__ */ jsxRuntime.jsx(Heading, { className: "oca-display-3 [overflow-wrap:anywhere]", children: title }),
3825
+ summary ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "oca-body max-w-[40rem] [overflow-wrap:anywhere]", children: summary }) : null
3826
+ ] }),
3827
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { "aria-label": "Checks", className: "divide-y divide-border border-t border-border", children: checks.map((c, i) => {
3828
+ const k = CHECK[c.state];
3829
+ return /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex items-start gap-3 px-6 py-3.5 md:px-8", children: [
3830
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: cn("mt-0.5 shrink-0 [&_svg]:size-[1.125rem]", k.tone), children: k.icon }),
3831
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-0.5 sm:flex-row sm:items-baseline sm:justify-between sm:gap-6", children: [
3832
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-col gap-0.5", children: [
3833
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[0.9375rem]", children: c.label }),
3834
+ c.note ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "break-words text-[0.8125rem] leading-snug text-muted-foreground", children: c.note }) : null
3835
+ ] }),
3836
+ /* @__PURE__ */ jsxRuntime.jsx(
3837
+ "span",
3838
+ {
3839
+ className: cn(
3840
+ "shrink-0 text-[0.8125rem]",
3841
+ c.state === "fail" ? "text-destructive" : "text-muted-foreground"
3842
+ ),
3843
+ children: k.word
3844
+ }
3845
+ )
3846
+ ] })
3847
+ ] }, i);
3848
+ }) }),
3849
+ facts && facts.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(KeyValueList, { items: facts, className: "rounded-none border-x-0 border-b-0 bg-transparent [&>div]:px-6 md:[&>div]:px-8" }) : null,
3850
+ notChecked && notChecked.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2 border-t border-border bg-muted/50 px-6 py-5 md:px-8", children: [
3851
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[0.875rem] font-medium", children: "What this did not check" }),
3852
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "flex list-disc flex-col gap-1 pl-5 text-[0.875rem] leading-relaxed text-muted-foreground", children: notChecked.map((n, i) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: n }, i)) })
3853
+ ] }) : null,
3854
+ actions ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-3 border-t border-border px-6 py-5 md:px-8", children: actions }) : null
3855
+ ]
3856
+ }
3857
+ );
3858
+ }
3859
+ function SignMessage({
3860
+ lead,
3861
+ address,
3862
+ message,
3863
+ wallets,
3864
+ busy = false,
3865
+ error,
3866
+ submitLabel = "Confirm",
3867
+ secondary,
3868
+ scheme = "bip322",
3869
+ onSignature,
3870
+ className
3871
+ }) {
3872
+ const [pasted, setPasted] = react.useState("");
3873
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-col gap-5", className), children: [
3874
+ lead ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[0.9375rem] leading-relaxed", children: lead }) : null,
3875
+ wallets ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3876
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-2", children: wallets }),
3877
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 text-[0.8125rem] text-muted-foreground", children: [
3878
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "h-px flex-1 bg-border" }),
3879
+ "or sign it in any wallet",
3880
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "h-px flex-1 bg-border" })
3881
+ ] })
3882
+ ] }) : null,
3883
+ /* @__PURE__ */ jsxRuntime.jsx(CodeBlock, { code: message, caption: "Message to sign", wrap: true }),
3884
+ /* @__PURE__ */ jsxRuntime.jsxs(
3885
+ "form",
3839
3886
  {
3840
- href: `#${id}`,
3841
- 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",
3887
+ className: "flex flex-col gap-4",
3888
+ onSubmit: (e) => {
3889
+ e.preventDefault();
3890
+ if (pasted.trim()) onSignature(pasted.trim());
3891
+ },
3842
3892
  children: [
3843
- /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, children: "#" }),
3844
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Link to this section" })
3893
+ /* @__PURE__ */ jsxRuntime.jsx(
3894
+ Field,
3895
+ {
3896
+ label: "Signature",
3897
+ error,
3898
+ hint: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3899
+ "From your wallet\u2019s \u201Csign message\u201D (",
3900
+ scheme === "legacy" ? "legacy, BIP-137" : "BIP-322",
3901
+ "), signed by",
3902
+ " ",
3903
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "break-all font-mono", children: address }),
3904
+ "."
3905
+ ] }),
3906
+ children: /* @__PURE__ */ jsxRuntime.jsx(
3907
+ Textarea,
3908
+ {
3909
+ value: pasted,
3910
+ onChange: (e) => setPasted(e.target.value),
3911
+ rows: 3,
3912
+ spellCheck: false,
3913
+ className: "min-h-24 font-mono text-base md:text-[0.8125rem]"
3914
+ }
3915
+ )
3916
+ }
3917
+ ),
3918
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-2", children: [
3919
+ /* @__PURE__ */ jsxRuntime.jsx(Button, { type: "submit", loading: busy, disabled: !pasted.trim(), children: submitLabel }),
3920
+ secondary
3921
+ ] })
3845
3922
  ]
3846
3923
  }
3847
- ) : null
3924
+ )
3848
3925
  ] });
3849
3926
  }
3850
3927
  function useMacKeys() {
@@ -4333,7 +4410,7 @@ function FormSection({
4333
4410
  "aria-current": status === "current" ? "step" : void 0,
4334
4411
  className: cn("scroll-mt-24 rounded-[1.25rem] border border-border bg-card", className),
4335
4412
  children: [
4336
- /* @__PURE__ */ jsxRuntime.jsxs("header", { className: cn("flex items-start gap-3.5", tight ? "px-5 pt-5" : "px-6 pt-6"), children: [
4413
+ /* @__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: [
4337
4414
  n !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(
4338
4415
  "span",
4339
4416
  {
@@ -4360,7 +4437,7 @@ function FormSection({
4360
4437
  ] }),
4361
4438
  hint ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[0.875rem] leading-snug text-muted-foreground", children: hint }) : null
4362
4439
  ] }),
4363
- action ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0", children: action }) : null
4440
+ action ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("shrink-0 max-sm:basis-full", n !== void 0 && "max-sm:pl-[2.625rem]"), children: action }) : null
4364
4441
  ] }),
4365
4442
  /* @__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 })
4366
4443
  ]
@@ -4590,27 +4667,30 @@ function FilterChips({
4590
4667
  onChange(cur.includes(v) ? cur.filter((x) => x !== v) : [...cur, v]);
4591
4668
  } else onChange(v);
4592
4669
  };
4593
- 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) => {
4594
- const on = isOn(o.value);
4595
- return /* @__PURE__ */ jsxRuntime.jsxs(
4596
- "button",
4597
- {
4598
- type: "button",
4599
- "aria-pressed": on,
4600
- onClick: () => press(o.value),
4601
- className: cn(
4602
- "inline-flex shrink-0 items-center gap-1.5 rounded-full border px-3.5 text-[0.875rem] transition-colors",
4603
- tight ? "h-8" : "h-9",
4604
- on ? "border-foreground bg-foreground text-background" : "border-border bg-card text-muted-foreground hover:border-oca-hairline-strong hover:text-foreground"
4605
- ),
4606
- children: [
4607
- o.label,
4608
- o.count !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "oca-tabular", children: o.count.toLocaleString("en-US") }) : null
4609
- ]
4610
- },
4611
- o.value
4612
- );
4613
- }) }) });
4670
+ return (
4671
+ // Wraps rather than scrolls: every filter stays in view on a phone.
4672
+ /* @__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) => {
4673
+ const on = isOn(o.value);
4674
+ return /* @__PURE__ */ jsxRuntime.jsxs(
4675
+ "button",
4676
+ {
4677
+ type: "button",
4678
+ "aria-pressed": on,
4679
+ onClick: () => press(o.value),
4680
+ className: cn(
4681
+ "inline-flex shrink-0 items-center gap-1.5 rounded-full border px-3.5 text-[0.875rem] transition-colors",
4682
+ tight ? "h-8" : "h-9",
4683
+ on ? "border-foreground bg-foreground text-background" : "border-border bg-card text-muted-foreground hover:border-oca-hairline-strong hover:text-foreground"
4684
+ ),
4685
+ children: [
4686
+ o.label,
4687
+ o.count !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "oca-tabular", children: o.count.toLocaleString("en-US") }) : null
4688
+ ]
4689
+ },
4690
+ o.value
4691
+ );
4692
+ }) })
4693
+ );
4614
4694
  }
4615
4695
  function ToolGrid({
4616
4696
  tools,