@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
@@ -7,8 +7,10 @@ import * as TabsPrimitive from '@radix-ui/react-tabs';
7
7
  import { ChevronDown, Check, Search, Copy, ArrowUpRight, ArrowRight, ChevronRight, CornerDownLeft, Download, FileText, Upload, ArrowLeft, Lock, CircleDashed, CircleMinus, CircleSlash, Clock, CircleX, CircleCheck } from 'lucide-react';
8
8
  import { Slot } from '@radix-ui/react-slot';
9
9
  import * as SeparatorPrimitive from '@radix-ui/react-separator';
10
+ import 'next-themes';
10
11
  import 'sonner';
11
12
  import Link from 'next/link';
13
+ import { useRouter } from 'next/compat/router';
12
14
  import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
13
15
  import * as LabelPrimitive from '@radix-ui/react-label';
14
16
  import * as RadioGroupPrimitive from '@radix-ui/react-radio-group';
@@ -1675,11 +1677,13 @@ function forClipboard(text, lang) {
1675
1677
  if (!lines.some((l) => l.startsWith("$ "))) return text;
1676
1678
  return lines.filter((l) => l.startsWith("$ ")).map((l) => l.slice(2)).join("\n");
1677
1679
  }
1678
- function linesFromDom(pre) {
1680
+ function linesFromDom(pre, newline) {
1679
1681
  if (!pre) return null;
1680
1682
  const lines = pre.querySelectorAll("[data-line]");
1681
1683
  if (lines.length === 0) return pre.textContent ?? "";
1682
- return Array.from(lines).filter((l) => l.getAttribute("data-diff") !== "remove").map((l) => l.textContent ?? "").join("\n");
1684
+ const text = Array.from(lines).filter((l) => l.getAttribute("data-diff") !== "remove").map((l) => l.textContent ?? "").join("\n");
1685
+ return newline ? `${text}
1686
+ ` : text;
1683
1687
  }
1684
1688
  function prepare(code, lang, marks, diff) {
1685
1689
  const d = diff ? readDiff(code) : null;
@@ -1688,7 +1692,8 @@ function prepare(code, lang, marks, diff) {
1688
1692
  const kept = d ? src.split("\n").filter((_, i) => d.diff.get(i + 1) !== "remove") : null;
1689
1693
  return {
1690
1694
  html: linesToHtml(lines, { highlight: parseLineRanges(marks), diff: d?.diff }),
1691
- copy: kept ? kept.join("\n") : src,
1695
+ // Byte for byte, the final newline too: a hash printed beside the code must match a copy of it.
1696
+ copy: kept ? kept.join("\n") + (/\n$/.test(code) ? "\n" : "") : code,
1692
1697
  lines: lines.length,
1693
1698
  diff: !!d
1694
1699
  };
@@ -1701,7 +1706,8 @@ function Well({
1701
1706
  lines,
1702
1707
  maxLines,
1703
1708
  diff,
1704
- lineNumbers
1709
+ lineNumbers,
1710
+ wrap
1705
1711
  }) {
1706
1712
  const foldable = maxLines !== void 0 && lines > maxLines + 2;
1707
1713
  const [open, setOpen] = useState(false);
@@ -1720,7 +1726,8 @@ function Well({
1720
1726
  "data-diff": diff ? "" : void 0,
1721
1727
  "data-line-numbers": lineNumbers ? "" : void 0,
1722
1728
  className: cn(
1723
- "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]",
1729
+ "oca-code py-4 font-mono text-[0.875rem] leading-[1.625] text-oca-ink-muted [font-variant-ligatures:none]",
1730
+ wrap ? "whitespace-pre-wrap break-all" : "w-max min-w-full",
1724
1731
  !lined && "px-5"
1725
1732
  ),
1726
1733
  children: lined ? /* @__PURE__ */ jsx("code", { className: "block", "data-lang": lang, dangerouslySetInnerHTML: { __html: html } }) : /* @__PURE__ */ jsx("code", { className: "block", "data-lang": lang, children })
@@ -1753,6 +1760,7 @@ function CodeBlock({
1753
1760
  code,
1754
1761
  html,
1755
1762
  children,
1763
+ trailingNewline = false,
1756
1764
  lang,
1757
1765
  caption,
1758
1766
  copy = true,
@@ -1761,6 +1769,7 @@ function CodeBlock({
1761
1769
  highlight: marks,
1762
1770
  diff,
1763
1771
  lineNumbers,
1772
+ wrap,
1764
1773
  actions,
1765
1774
  className
1766
1775
  }) {
@@ -1773,7 +1782,7 @@ function CodeBlock({
1773
1782
  );
1774
1783
  const markup = prepared?.html ?? html;
1775
1784
  const lines = prepared?.lines ?? (html !== void 0 ? html.split("\n").length : code?.split("\n").length ?? 0);
1776
- const read = () => forClipboard(prepared?.copy ?? linesFromDom(preRef.current) ?? code ?? "", lang);
1785
+ const read = () => forClipboard(prepared?.copy ?? linesFromDom(preRef.current, trailingNewline) ?? code ?? "", lang);
1777
1786
  return /* @__PURE__ */ jsxs("figure", { className: cn(FRAME, className), children: [
1778
1787
  /* @__PURE__ */ jsxs("figcaption", { className: "flex h-11 items-center justify-between gap-3 border-b border-[var(--oca-code-line)] pl-5 pr-2", children: [
1779
1788
  /* @__PURE__ */ jsx("span", { className: "truncate text-[0.8125rem] text-oca-ink-subtle", children: caption ?? languageName(lang) ?? "Code" }),
@@ -1792,6 +1801,7 @@ function CodeBlock({
1792
1801
  maxLines,
1793
1802
  diff: prepared ? prepared.diff : isDiff,
1794
1803
  lineNumbers,
1804
+ wrap,
1795
1805
  children
1796
1806
  }
1797
1807
  )
@@ -2294,6 +2304,133 @@ function MarkOutline({ className }) {
2294
2304
  points
2295
2305
  )) });
2296
2306
  }
2307
+
2308
+ // src/family/index.ts
2309
+ var OCHK_IO = "https://ochk.io";
2310
+ var DOCS_HREF = `${OCHK_IO}/docs`;
2311
+ function protocol(slug, verb, line, kinds) {
2312
+ return {
2313
+ slug,
2314
+ label: slug,
2315
+ href: `${OCHK_IO}/${slug}`,
2316
+ group: "protocol",
2317
+ line,
2318
+ status: "live",
2319
+ verb,
2320
+ pageHref: `${OCHK_IO}/${slug}`,
2321
+ toolHref: `https://${slug}.ochk.io`,
2322
+ specHref: `https://github.com/orangecheck/oc-${slug}-protocol`,
2323
+ kinds
2324
+ };
2325
+ }
2326
+ var PROTOCOLS = [
2327
+ protocol("attest", "identity", "Show that an address holds bitcoin, and for how long.", "30078"),
2328
+ protocol("lock", "confidentiality", "Encrypt to a Bitcoin address, so only its holder can open it.", "30078"),
2329
+ protocol("vote", "legitimacy", "Polls weighed in sats, that anyone can tally.", "30080\u201330082"),
2330
+ protocol("stamp", "provenance", "Prove who signed something, and when.", "30083"),
2331
+ protocol("agent", "authority", "Give software scoped, revocable permission to act for you.", "30083\u201330086"),
2332
+ protocol("pledge", "commitment", "Make a promise with bitcoin behind it, on a public record.", "30078")
2333
+ ];
2334
+ var PROTOCOL_ORDER = PROTOCOLS.map((p) => p.slug);
2335
+ var FAMILY = [
2336
+ {
2337
+ slug: "home",
2338
+ label: "ochk.io",
2339
+ href: OCHK_IO,
2340
+ group: "orangecheck",
2341
+ line: "The open protocols, and the company behind them.",
2342
+ status: "live"
2343
+ },
2344
+ {
2345
+ slug: "me",
2346
+ label: "ochk.app",
2347
+ href: "https://ochk.app",
2348
+ group: "orangecheck",
2349
+ line: "One account, with Bitcoin behind it.",
2350
+ status: "testing"
2351
+ },
2352
+ {
2353
+ slug: "docs",
2354
+ label: "docs",
2355
+ href: DOCS_HREF,
2356
+ group: "orangecheck",
2357
+ line: "Specs, SDKs and guides for every protocol.",
2358
+ status: "live"
2359
+ },
2360
+ ...PROTOCOLS,
2361
+ {
2362
+ slug: "vault",
2363
+ label: "vault",
2364
+ href: "https://vault.ochk.io",
2365
+ group: "app",
2366
+ line: "A password manager, encrypted in your browser.",
2367
+ status: "live",
2368
+ protocols: ["lock"]
2369
+ },
2370
+ {
2371
+ slug: "chat",
2372
+ label: "chat",
2373
+ href: "https://chat.ochk.io",
2374
+ group: "app",
2375
+ line: "Messages only the holder of a Bitcoin address can read.",
2376
+ status: "testing",
2377
+ protocols: ["lock"]
2378
+ },
2379
+ {
2380
+ slug: "cosign",
2381
+ label: "cosign",
2382
+ href: "https://cosign.ochk.io",
2383
+ group: "app",
2384
+ line: "Builders find co-founders and backers.",
2385
+ status: "testing",
2386
+ // Signs in with an orangecheck account and a wallet; uses none of the six directly.
2387
+ protocols: []
2388
+ },
2389
+ {
2390
+ slug: "me-demo",
2391
+ // "demo", not the made-up app's own name, so nobody takes it for ours.
2392
+ label: "demo",
2393
+ href: "https://me-demo.ochk.io",
2394
+ group: "app",
2395
+ line: "Lumen Notes, a made-up app that signs in with orangecheck.",
2396
+ status: "live"
2397
+ },
2398
+ {
2399
+ slug: "globe",
2400
+ label: "globe",
2401
+ href: "https://globe.ochk.io",
2402
+ group: "public-good",
2403
+ line: "The Bitcoin network, live, on a globe.",
2404
+ status: "live"
2405
+ },
2406
+ {
2407
+ slug: "btc",
2408
+ label: "btc",
2409
+ href: "https://btc.ochk.io",
2410
+ group: "public-good",
2411
+ line: "A free desk for reading the Bitcoin market.",
2412
+ status: "live"
2413
+ }
2414
+ ];
2415
+ var BY_SLUG = new Map(FAMILY.map((s) => [s.slug, s]));
2416
+ function protocolSite(slug) {
2417
+ return BY_SLUG.get(slug);
2418
+ }
2419
+ [
2420
+ {
2421
+ href: `${OCHK_IO}/protocols`,
2422
+ label: "Protocols",
2423
+ children: PROTOCOLS.map((p) => ({ href: p.pageHref, label: p.label, description: p.line }))
2424
+ },
2425
+ { href: `${OCHK_IO}/apps`, label: "Apps" },
2426
+ { href: DOCS_HREF, label: "Docs" },
2427
+ { href: `${OCHK_IO}/trust`, label: "Trust" },
2428
+ { href: `${OCHK_IO}/about`, label: "About" }
2429
+ ];
2430
+ var SiteHomeContext = sharedContext("site-home", void 0);
2431
+ function useSiteHome() {
2432
+ return useContext(SiteHomeContext);
2433
+ }
2297
2434
  var WORDS = {
2298
2435
  404: {
2299
2436
  name: "Not found",
@@ -2311,10 +2448,13 @@ function ErrorPage({
2311
2448
  title,
2312
2449
  detail,
2313
2450
  actions,
2314
- home = "/",
2451
+ home,
2452
+ protocol: protocol2,
2315
2453
  art,
2316
2454
  className
2317
2455
  }) {
2456
+ const shellHome = useSiteHome();
2457
+ const homeHref = home ?? (protocol2 ? protocolSite(protocol2).pageHref : shellHome ?? OCHK_IO);
2318
2458
  const words = WORDS[code] ?? (code >= 500 ? WORDS[500] : WORDS[404]);
2319
2459
  const server = code >= 500;
2320
2460
  return /* @__PURE__ */ jsx(Section, { space: "none", className: cn("flex min-h-[min(40rem,72dvh)] items-center py-16 md:py-24", className), children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 items-center gap-12 md:grid-cols-12", children: [
@@ -2328,7 +2468,7 @@ function ErrorPage({
2328
2468
  /* @__PURE__ */ jsx("p", { className: "oca-lead oca-enter [--enter-delay:150ms]", children: detail ?? words.detail }),
2329
2469
  /* @__PURE__ */ jsx("div", { className: "oca-enter flex flex-wrap gap-3 [--enter-delay:230ms]", children: actions ?? /* @__PURE__ */ jsxs(Fragment, { children: [
2330
2470
  server ? /* @__PURE__ */ jsx(Button, { onClick: () => window.location.reload(), children: "Try again" }) : null,
2331
- /* @__PURE__ */ jsx(Button, { asChild: true, variant: server ? "secondary" : "primary", children: /* @__PURE__ */ jsx(Link, { href: home, children: "Go home" }) })
2471
+ /* @__PURE__ */ jsx(Button, { asChild: true, variant: server ? "secondary" : "primary", children: /* @__PURE__ */ jsx(Link, { href: homeHref, children: "Go home" }) })
2332
2472
  ] }) })
2333
2473
  ] }),
2334
2474
  art !== null ? /* @__PURE__ */ jsx("div", { "aria-hidden": true, className: "oca-enter hidden justify-center md:col-span-5 md:flex [--enter-delay:120ms]", children: art ?? /* @__PURE__ */ jsx(MarkOutline, { className: "w-full max-w-[20rem] text-oca-hairline-strong" }) }) : null
@@ -2552,12 +2692,21 @@ function Faq({
2552
2692
  return /* @__PURE__ */ jsx(Accordion, { single: true, className, children: items.map((it, i) => /* @__PURE__ */ jsx(AccordionItem, { id: it.id, title: it.q, children: it.a }, it.id ?? i)) });
2553
2693
  }
2554
2694
  var LINK = "text-foreground underline decoration-foreground/35 underline-offset-4 transition-colors hover:decoration-foreground";
2695
+ var SCHEME = /^[a-z][a-z\d+.-]*:/i;
2696
+ function useResolved(href) {
2697
+ const router = useRouter();
2698
+ if (!router || !href || href.startsWith("/") || href.startsWith("#") || href.startsWith("?") || SCHEME.test(href)) return href;
2699
+ const here = router.asPath.split(/[?#]/)[0] || "/";
2700
+ const url = new URL(href, `https://page.invalid${here}`);
2701
+ return url.pathname + url.search + url.hash;
2702
+ }
2555
2703
  function TextLink({
2556
- href,
2704
+ href: written,
2557
2705
  children,
2558
2706
  external,
2559
2707
  className
2560
2708
  }) {
2709
+ const href = useResolved(written);
2561
2710
  const internal = href.startsWith("/") && !href.startsWith("/api/") && !href.startsWith("/.well-known/");
2562
2711
  const offsite = external ?? /^https?:\/\//.test(href);
2563
2712
  if (internal && !offsite) {
@@ -2670,129 +2819,10 @@ function LegalDocument({ doc, className }) {
2670
2819
  }
2671
2820
  );
2672
2821
  }
2673
-
2674
- // src/family/index.ts
2675
- var OCHK_IO = "https://ochk.io";
2676
- var DOCS_HREF = `${OCHK_IO}/docs`;
2677
- function protocol(slug, verb, line, kinds) {
2678
- return {
2679
- slug,
2680
- label: slug,
2681
- href: `${OCHK_IO}/${slug}`,
2682
- group: "protocol",
2683
- line,
2684
- status: "live",
2685
- verb,
2686
- pageHref: `${OCHK_IO}/${slug}`,
2687
- toolHref: `https://${slug}.ochk.io`,
2688
- specHref: `https://github.com/orangecheck/oc-${slug}-protocol`,
2689
- kinds
2690
- };
2691
- }
2692
- var PROTOCOLS = [
2693
- protocol("attest", "identity", "Show that an address holds bitcoin, and for how long.", "30078"),
2694
- protocol("lock", "confidentiality", "Encrypt to a Bitcoin address, so only its holder can open it.", "30078"),
2695
- protocol("vote", "legitimacy", "Polls weighed in sats, that anyone can tally.", "30080\u201330082"),
2696
- protocol("stamp", "provenance", "Prove who signed something, and when.", "30083"),
2697
- protocol("agent", "authority", "Give software scoped, revocable permission to act for you.", "30083\u201330086"),
2698
- protocol("pledge", "commitment", "Make a promise with bitcoin behind it, on a public record.", "30078")
2699
- ];
2700
- var PROTOCOL_ORDER = PROTOCOLS.map((p) => p.slug);
2701
- var FAMILY = [
2702
- {
2703
- slug: "home",
2704
- label: "ochk.io",
2705
- href: OCHK_IO,
2706
- group: "orangecheck",
2707
- line: "The open protocols, and the company behind them.",
2708
- status: "live"
2709
- },
2710
- {
2711
- slug: "me",
2712
- label: "ochk.app",
2713
- href: "https://ochk.app",
2714
- group: "orangecheck",
2715
- line: "One account, with Bitcoin behind it.",
2716
- status: "testing"
2717
- },
2718
- {
2719
- slug: "docs",
2720
- label: "docs",
2721
- href: DOCS_HREF,
2722
- group: "orangecheck",
2723
- line: "Specs, SDKs and guides for every protocol.",
2724
- status: "live"
2725
- },
2726
- ...PROTOCOLS,
2727
- {
2728
- slug: "vault",
2729
- label: "vault",
2730
- href: "https://vault.ochk.io",
2731
- group: "app",
2732
- line: "A password manager, encrypted in your browser.",
2733
- status: "live",
2734
- protocols: ["lock"]
2735
- },
2736
- {
2737
- slug: "chat",
2738
- label: "chat",
2739
- href: "https://chat.ochk.io",
2740
- group: "app",
2741
- line: "Messages only the holder of a Bitcoin address can read.",
2742
- status: "testing",
2743
- protocols: ["lock"]
2744
- },
2745
- {
2746
- slug: "cosign",
2747
- label: "cosign",
2748
- href: "https://cosign.ochk.io",
2749
- group: "app",
2750
- line: "Builders find co-founders and backers.",
2751
- status: "testing",
2752
- // Signs in with an orangecheck account and a wallet; uses none of the six directly.
2753
- protocols: []
2754
- },
2755
- {
2756
- slug: "me-demo",
2757
- // "demo", not the made-up app's own name, so nobody takes it for ours.
2758
- label: "demo",
2759
- href: "https://me-demo.ochk.io",
2760
- group: "app",
2761
- line: "Lumen Notes, a made-up app that signs in with orangecheck.",
2762
- status: "live"
2763
- },
2764
- {
2765
- slug: "globe",
2766
- label: "globe",
2767
- href: "https://globe.ochk.io",
2768
- group: "public-good",
2769
- line: "The Bitcoin network, live, on a globe.",
2770
- status: "live"
2771
- },
2772
- {
2773
- slug: "btc",
2774
- label: "btc",
2775
- href: "https://btc.ochk.io",
2776
- group: "public-good",
2777
- line: "A free desk for reading the Bitcoin market.",
2778
- status: "live"
2779
- }
2780
- ];
2781
- var BY_SLUG = new Map(FAMILY.map((s) => [s.slug, s]));
2782
- function protocolSite(slug) {
2783
- return BY_SLUG.get(slug);
2822
+ var InDocsContext = sharedContext("in-docs", false);
2823
+ function useInDocs() {
2824
+ return useContext(InDocsContext);
2784
2825
  }
2785
- [
2786
- {
2787
- href: `${OCHK_IO}/protocols`,
2788
- label: "Protocols",
2789
- children: PROTOCOLS.map((p) => ({ href: p.pageHref, label: p.label, description: p.line }))
2790
- },
2791
- { href: `${OCHK_IO}/apps`, label: "Apps" },
2792
- { href: DOCS_HREF, label: "Docs" },
2793
- { href: `${OCHK_IO}/trust`, label: "Trust" },
2794
- { href: `${OCHK_IO}/about`, label: "About" }
2795
- ];
2796
2826
  var WORD = {
2797
2827
  live: "Live",
2798
2828
  testing: "In testing",
@@ -2822,6 +2852,7 @@ function ProtocolGrid({
2822
2852
  link = "page",
2823
2853
  className
2824
2854
  }) {
2855
+ const inDocs = useInDocs();
2825
2856
  return /* @__PURE__ */ 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) => {
2826
2857
  const p = protocolSite(slug);
2827
2858
  const i = PROTOCOL_ORDER.indexOf(slug);
@@ -2834,7 +2865,7 @@ function ProtocolGrid({
2834
2865
  ] }),
2835
2866
  p.status !== "live" ? /* @__PURE__ */ jsx(StatusBadge, { status: p.status }) : null
2836
2867
  ] }),
2837
- /* @__PURE__ */ jsx("h3", { className: "oca-display-3", children: /* @__PURE__ */ jsx(
2868
+ /* @__PURE__ */ jsx("h3", { className: "oca-display-3", children: link === "docs" && inDocs ? /* @__PURE__ */ jsx(Link, { href: `/${p.slug}`, className: STRETCH, children: p.label }) : /* @__PURE__ */ jsx(
2838
2869
  "a",
2839
2870
  {
2840
2871
  href: link === "tool" ? p.toolHref : link === "docs" ? `${DOCS_HREF}/${p.slug}` : p.pageHref,
@@ -3082,371 +3113,6 @@ forwardRef(function RadioGroupItem2({ className, ...props }, ref) {
3082
3113
  }
3083
3114
  );
3084
3115
  });
3085
- function ProtocolHero({
3086
- protocol: protocol2,
3087
- title,
3088
- lead,
3089
- actions,
3090
- art,
3091
- children,
3092
- className
3093
- }) {
3094
- const p = protocolSite(protocol2);
3095
- return /* @__PURE__ */ jsx(
3096
- PageHero,
3097
- {
3098
- className,
3099
- eyebrow: `Protocol \xB7 ${p.verb}`,
3100
- title,
3101
- lead,
3102
- actions,
3103
- art,
3104
- children: p.status !== "live" || children ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-start gap-4", children: [
3105
- p.status !== "live" ? /* @__PURE__ */ jsx(StatusBadge, { status: p.status }) : null,
3106
- children
3107
- ] }) : null
3108
- }
3109
- );
3110
- }
3111
- function ProtocolNav({
3112
- current,
3113
- link = "page",
3114
- className
3115
- }) {
3116
- return /* @__PURE__ */ jsx("nav", { "aria-label": "Protocols", className, children: /* @__PURE__ */ jsx(ScrollFade, { fade: "var(--background)", children: /* @__PURE__ */ jsx("ul", { className: "flex w-max min-w-full items-center gap-6 border-b border-border", children: PROTOCOLS.map((p) => {
3117
- const on = p.slug === current;
3118
- return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
3119
- "a",
3120
- {
3121
- href: link === "tool" ? p.toolHref : p.pageHref,
3122
- "aria-current": on ? "page" : void 0,
3123
- className: cn(
3124
- "-mb-px inline-flex h-11 items-center border-b-2 text-[0.9375rem] transition-colors",
3125
- on ? "border-foreground text-foreground" : "border-transparent text-muted-foreground hover:text-foreground"
3126
- ),
3127
- children: p.label
3128
- }
3129
- ) }, p.slug);
3130
- }) }) }) });
3131
- }
3132
- function SpecCard({
3133
- protocol: protocol2,
3134
- version,
3135
- license,
3136
- vectors,
3137
- size = "md",
3138
- className
3139
- }) {
3140
- const p = protocolSite(protocol2);
3141
- const repo = `oc-${p.slug}-protocol`;
3142
- const facts = [
3143
- ["Version", version],
3144
- ...license ? [["Licence", license]] : [],
3145
- ["Nostr kind", p.kinds],
3146
- ...vectors !== void 0 ? [["Test vectors", String(vectors)]] : []
3147
- ];
3148
- if (size === "sm") {
3149
- return /* @__PURE__ */ jsxs(
3150
- "a",
3151
- {
3152
- href: p.specHref,
3153
- className: cn(
3154
- "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",
3155
- className
3156
- ),
3157
- children: [
3158
- /* @__PURE__ */ jsx("span", { className: "font-mono text-[0.8125rem] text-foreground", children: repo }),
3159
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: facts.map(([k, v]) => k === "Version" ? `v${v}` : k === "Nostr kind" ? `kind ${v}` : v).join(" \xB7 ") }),
3160
- /* @__PURE__ */ jsxs("span", { className: "ml-auto flex items-center gap-1 text-muted-foreground group-hover:text-foreground", children: [
3161
- "Read the spec ",
3162
- /* @__PURE__ */ jsx(ArrowUpRight, { "aria-hidden": true, className: "size-4" })
3163
- ] })
3164
- ]
3165
- }
3166
- );
3167
- }
3168
- return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-6 rounded-[1.25rem] border border-border bg-card p-6 md:p-8", className), children: [
3169
- /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-4", children: [
3170
- /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col gap-1.5", children: [
3171
- /* @__PURE__ */ jsx("p", { className: "text-[0.875rem] text-muted-foreground", children: "The spec" }),
3172
- /* @__PURE__ */ jsx("h3", { className: "oca-title break-all font-mono text-[1.0625rem] tracking-normal", children: repo })
3173
- ] }),
3174
- p.status !== "live" ? /* @__PURE__ */ jsx(StatusBadge, { status: p.status }) : null
3175
- ] }),
3176
- /* @__PURE__ */ jsx("dl", { className: "grid grid-cols-2 gap-x-6 gap-y-4 sm:grid-cols-4", children: facts.map(([k, v]) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
3177
- /* @__PURE__ */ jsx("dt", { className: "text-[0.8125rem] text-muted-foreground", children: k }),
3178
- /* @__PURE__ */ jsx("dd", { className: "oca-tabular text-[1.0625rem]", children: v })
3179
- ] }, k)) }),
3180
- /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Button, { asChild: true, variant: "secondary", size: "sm", children: /* @__PURE__ */ jsxs("a", { href: p.specHref, children: [
3181
- "Read the spec ",
3182
- /* @__PURE__ */ jsx(ArrowUpRight, { "aria-hidden": true })
3183
- ] }) }) })
3184
- ] });
3185
- }
3186
- function VerifyBox({
3187
- action,
3188
- param = "q",
3189
- title,
3190
- description,
3191
- label = "Id, envelope or link",
3192
- placeholder,
3193
- hint,
3194
- submitLabel = "Verify",
3195
- multiline = false,
3196
- onVerify,
3197
- className
3198
- }) {
3199
- const [value, setValue] = useState("");
3200
- const submit = (e) => {
3201
- if (!onVerify) return;
3202
- e.preventDefault();
3203
- if (value.trim()) onVerify(value.trim());
3204
- };
3205
- const button = /* @__PURE__ */ jsx(Button, { type: "submit", className: multiline ? void 0 : "w-full sm:w-auto", children: submitLabel });
3206
- return /* @__PURE__ */ jsxs(
3207
- "form",
3208
- {
3209
- action,
3210
- method: "get",
3211
- onSubmit: submit,
3212
- className: cn("flex flex-col gap-5 rounded-[1.25rem] border border-border bg-card p-6 md:p-8", className),
3213
- children: [
3214
- title || description ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
3215
- title ? /* @__PURE__ */ jsx("h3", { className: "oca-title", children: title }) : null,
3216
- description ? /* @__PURE__ */ jsx("p", { className: "oca-body text-[0.9375rem]", children: description }) : null
3217
- ] }) : null,
3218
- multiline ? /* @__PURE__ */ jsxs(Fragment, { children: [
3219
- /* @__PURE__ */ jsx(Field, { label, hint, children: /* @__PURE__ */ jsx(
3220
- Textarea,
3221
- {
3222
- name: param,
3223
- required: true,
3224
- value,
3225
- onChange: (e) => setValue(e.target.value),
3226
- placeholder,
3227
- spellCheck: false,
3228
- className: "min-h-32 font-mono text-base md:text-[0.8125rem]"
3229
- }
3230
- ) }),
3231
- /* @__PURE__ */ jsx("div", { children: button })
3232
- ] }) : /* @__PURE__ */ jsx(Field, { label, hint, action: button, children: /* @__PURE__ */ jsx(
3233
- Input,
3234
- {
3235
- name: param,
3236
- required: true,
3237
- value,
3238
- onChange: (e) => setValue(e.target.value),
3239
- placeholder,
3240
- spellCheck: false,
3241
- autoComplete: "off",
3242
- className: "font-mono text-base md:text-[0.875rem]"
3243
- }
3244
- ) })
3245
- ]
3246
- }
3247
- );
3248
- }
3249
- var TINT = "bg-[color-mix(in_oklab,var(--oca-orange)_9%,var(--card))]";
3250
- function ComparisonTable({
3251
- columns,
3252
- rows,
3253
- label,
3254
- propertyHeading = "Property",
3255
- className
3256
- }) {
3257
- const wide = columns.length > 3;
3258
- const grid = wide ? "lg:grid lg:grid-cols-[var(--oca-compare)]" : "md:grid md:grid-cols-[var(--oca-compare)]";
3259
- const desk = wide ? "lg" : "md";
3260
- const style = {
3261
- // The argued-for column gets a little more room: its answers carry the page.
3262
- "--oca-compare": ["minmax(0, 1.4fr)", ...columns.map((c) => c.highlight ? "minmax(0, 1.3fr)" : "minmax(0, 1fr)")].join(" ")
3263
- };
3264
- const ordered = [...columns].sort((a, b) => Number(Boolean(b.highlight)) - Number(Boolean(a.highlight)));
3265
- return /* @__PURE__ */ jsxs("ul", { "aria-label": label, style, className: cn("divide-y divide-border rounded-[1.25rem] border border-border bg-card", className), children: [
3266
- /* @__PURE__ */ jsxs(
3267
- "li",
3268
- {
3269
- "aria-hidden": true,
3270
- className: cn(
3271
- "hidden gap-5 px-5 py-4 text-[0.875rem] font-medium text-muted-foreground",
3272
- wide ? "lg:grid lg:px-8" : "md:grid md:px-8",
3273
- grid
3274
- ),
3275
- children: [
3276
- /* @__PURE__ */ jsx("span", { children: propertyHeading }),
3277
- columns.map((c) => /* @__PURE__ */ jsx("span", { className: cn(c.highlight && cn(TINT, "-my-4 px-4 py-4 text-oca-accent-ink")), children: c.label }, c.key))
3278
- ]
3279
- }
3280
- ),
3281
- rows.map((r, ri) => /* @__PURE__ */ 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: [
3282
- /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col gap-1", children: [
3283
- /* @__PURE__ */ jsx("span", { className: "oca-title-sm", children: r.label }),
3284
- r.note ? /* @__PURE__ */ jsx("span", { className: "text-[0.875rem] leading-snug text-muted-foreground", children: r.note }) : null
3285
- ] }),
3286
- /* @__PURE__ */ jsx("div", { className: cn("grid grid-cols-2 gap-1", desk === "lg" ? "lg:contents" : "md:contents"), children: columns.map((c) => {
3287
- return /* @__PURE__ */ jsxs(
3288
- "div",
3289
- {
3290
- style: { "--oca-order": ordered.indexOf(c) },
3291
- className: cn(
3292
- // Two rows of the pair's grid (name, answer), so answers line up
3293
- // across a pair even when one name wraps.
3294
- "order-[var(--oca-order)] row-span-2 grid min-w-0 grid-rows-subgrid gap-1 rounded-xl px-3 py-2.5",
3295
- 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",
3296
- c.highlight ? cn(
3297
- TINT,
3298
- "col-span-2",
3299
- 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"
3300
- ) : desk === "lg" ? "lg:p-0" : "md:p-0"
3301
- ),
3302
- children: [
3303
- /* @__PURE__ */ jsx(
3304
- "span",
3305
- {
3306
- className: cn(
3307
- "text-[0.8125rem]",
3308
- c.highlight ? "text-oca-accent-ink" : "text-muted-foreground",
3309
- desk === "lg" ? "lg:sr-only" : "md:sr-only"
3310
- ),
3311
- children: c.label
3312
- }
3313
- ),
3314
- /* @__PURE__ */ jsx("span", { className: cn("text-[0.9375rem]", c.highlight && "font-medium"), children: r.values[c.key] ?? "\u2014" })
3315
- ]
3316
- },
3317
- c.key
3318
- );
3319
- }) })
3320
- ] }, ri))
3321
- ] });
3322
- }
3323
- var CHECK = {
3324
- ok: { word: "Passed", icon: /* @__PURE__ */ jsx(CircleCheck, {}), tone: "text-success" },
3325
- fail: { word: "Failed", icon: /* @__PURE__ */ jsx(CircleX, {}), tone: "text-destructive" },
3326
- pending: { word: "Pending", icon: /* @__PURE__ */ jsx(Clock, {}), tone: "text-oca-accent-ink" },
3327
- none: { word: "None", icon: /* @__PURE__ */ jsx(CircleSlash, {}), tone: "text-muted-foreground" },
3328
- skipped: { word: "Skipped", icon: /* @__PURE__ */ jsx(CircleMinus, {}), tone: "text-muted-foreground" },
3329
- unchecked: { word: "Not checked", icon: /* @__PURE__ */ jsx(CircleDashed, {}), tone: "text-oca-subtle" }
3330
- };
3331
- function VerifyReport({
3332
- verdict,
3333
- title,
3334
- summary,
3335
- checks,
3336
- facts,
3337
- notChecked,
3338
- actions,
3339
- as: Heading = "h2",
3340
- className
3341
- }) {
3342
- return /* @__PURE__ */ jsxs(
3343
- "section",
3344
- {
3345
- "aria-label": "Verification result",
3346
- className: cn("overflow-hidden rounded-[1.25rem] border border-border bg-card", className),
3347
- children: [
3348
- /* @__PURE__ */ jsxs("header", { className: "flex flex-col items-start gap-3 p-6 md:p-8", children: [
3349
- /* @__PURE__ */ jsx(StatusBadge, { status: verdict }),
3350
- /* @__PURE__ */ jsx(Heading, { className: "oca-display-3 [overflow-wrap:anywhere]", children: title }),
3351
- summary ? /* @__PURE__ */ jsx("p", { className: "oca-body max-w-[40rem] [overflow-wrap:anywhere]", children: summary }) : null
3352
- ] }),
3353
- /* @__PURE__ */ jsx("ul", { "aria-label": "Checks", className: "divide-y divide-border border-t border-border", children: checks.map((c, i) => {
3354
- const k = CHECK[c.state];
3355
- return /* @__PURE__ */ jsxs("li", { className: "flex items-start gap-3 px-6 py-3.5 md:px-8", children: [
3356
- /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: cn("mt-0.5 shrink-0 [&_svg]:size-[1.125rem]", k.tone), children: k.icon }),
3357
- /* @__PURE__ */ 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: [
3358
- /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col gap-0.5", children: [
3359
- /* @__PURE__ */ jsx("span", { className: "text-[0.9375rem]", children: c.label }),
3360
- c.note ? /* @__PURE__ */ jsx("span", { className: "break-words text-[0.8125rem] leading-snug text-muted-foreground", children: c.note }) : null
3361
- ] }),
3362
- /* @__PURE__ */ jsx(
3363
- "span",
3364
- {
3365
- className: cn(
3366
- "shrink-0 text-[0.8125rem]",
3367
- c.state === "fail" ? "text-destructive" : "text-muted-foreground"
3368
- ),
3369
- children: k.word
3370
- }
3371
- )
3372
- ] })
3373
- ] }, i);
3374
- }) }),
3375
- facts && facts.length > 0 ? /* @__PURE__ */ jsx(KeyValueList, { items: facts, className: "rounded-none border-x-0 border-b-0 bg-transparent [&>div]:px-6 md:[&>div]:px-8" }) : null,
3376
- notChecked && notChecked.length > 0 ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 border-t border-border bg-muted/50 px-6 py-5 md:px-8", children: [
3377
- /* @__PURE__ */ jsx("p", { className: "text-[0.875rem] font-medium", children: "What this did not check" }),
3378
- /* @__PURE__ */ 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__ */ jsx("li", { children: n }, i)) })
3379
- ] }) : null,
3380
- actions ? /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-3 border-t border-border px-6 py-5 md:px-8", children: actions }) : null
3381
- ]
3382
- }
3383
- );
3384
- }
3385
- function SignMessage({
3386
- lead,
3387
- address,
3388
- message,
3389
- wallets,
3390
- busy = false,
3391
- error,
3392
- submitLabel = "Confirm",
3393
- secondary,
3394
- onSignature,
3395
- className
3396
- }) {
3397
- const [pasted, setPasted] = useState("");
3398
- return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-5", className), children: [
3399
- lead ? /* @__PURE__ */ jsx("p", { className: "text-[0.9375rem] leading-relaxed", children: lead }) : null,
3400
- wallets ? /* @__PURE__ */ jsxs(Fragment, { children: [
3401
- /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2", children: wallets }),
3402
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 text-[0.8125rem] text-muted-foreground", children: [
3403
- /* @__PURE__ */ jsx("span", { className: "h-px flex-1 bg-border" }),
3404
- "or sign it in any wallet",
3405
- /* @__PURE__ */ jsx("span", { className: "h-px flex-1 bg-border" })
3406
- ] })
3407
- ] }) : null,
3408
- /* @__PURE__ */ jsx(CodeBlock, { code: message, caption: "Message to sign" }),
3409
- /* @__PURE__ */ jsxs(
3410
- "form",
3411
- {
3412
- className: "flex flex-col gap-4",
3413
- onSubmit: (e) => {
3414
- e.preventDefault();
3415
- if (pasted.trim()) onSignature(pasted.trim());
3416
- },
3417
- children: [
3418
- /* @__PURE__ */ jsx(
3419
- Field,
3420
- {
3421
- label: "Signature",
3422
- error,
3423
- hint: /* @__PURE__ */ jsxs(Fragment, { children: [
3424
- "From your wallet\u2019s \u201Csign message\u201D (BIP-322), signed by",
3425
- " ",
3426
- /* @__PURE__ */ jsx("span", { className: "break-all font-mono", children: address }),
3427
- "."
3428
- ] }),
3429
- children: /* @__PURE__ */ jsx(
3430
- Textarea,
3431
- {
3432
- value: pasted,
3433
- onChange: (e) => setPasted(e.target.value),
3434
- rows: 3,
3435
- spellCheck: false,
3436
- className: "min-h-24 font-mono text-base md:text-[0.8125rem]"
3437
- }
3438
- )
3439
- }
3440
- ),
3441
- /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-2", children: [
3442
- /* @__PURE__ */ jsx(Button, { type: "submit", loading: busy, disabled: !pasted.trim(), children: submitLabel }),
3443
- secondary
3444
- ] })
3445
- ]
3446
- }
3447
- )
3448
- ] });
3449
- }
3450
3116
  var isInternal = (href) => href.startsWith("/") || href.startsWith("#");
3451
3117
  function DocLink({ href, className, children, ...rest }) {
3452
3118
  return isInternal(href) ? /* @__PURE__ */ jsx(Link, { href, className, ...rest, children }) : /* @__PURE__ */ jsx("a", { href, className, ...rest, children });
@@ -3635,6 +3301,7 @@ function MdxTable({ className, ...props }) {
3635
3301
  }
3636
3302
  ) }) });
3637
3303
  }
3304
+ var said = (n) => n !== void 0 && n !== null && n !== false && n !== "";
3638
3305
  function ApiTable({
3639
3306
  rows,
3640
3307
  caption,
@@ -3642,43 +3309,42 @@ function ApiTable({
3642
3309
  className
3643
3310
  }) {
3644
3311
  const hasDefault = rows.some((r) => r.default !== void 0);
3645
- const marks = (r) => /* @__PURE__ */ jsxs(Fragment, { children: [
3646
- r.required ? /* @__PURE__ */ jsx("span", { className: "text-[0.75rem] text-oca-accent-ink", children: "Required" }) : null,
3647
- r.deprecated ? /* @__PURE__ */ jsx(Badge, { tone: "muted", children: "Deprecated" }) : null,
3648
- r.status ? /* @__PURE__ */ jsx(StatusBadge, { status: r.status }) : null
3649
- ] });
3650
- return /* @__PURE__ */ jsxs("div", { className: cn("not-prose my-6", className), children: [
3651
- /* @__PURE__ */ jsx("div", { className: "overflow-hidden rounded-2xl border border-border bg-card max-sm:hidden", children: /* @__PURE__ */ jsx(ScrollFade, { fade: "var(--card)", children: /* @__PURE__ */ jsxs("table", { className: "w-full border-collapse text-left text-[0.875rem]", children: [
3652
- caption ? /* @__PURE__ */ jsx("caption", { className: "sr-only", children: caption }) : null,
3653
- /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { className: "border-b border-oca-hairline-strong bg-oca-table-head text-[0.8125rem]", children: [
3654
- /* @__PURE__ */ jsx("th", { scope: "col", className: "px-4 py-2.5 font-medium", children: nameHeader }),
3655
- /* @__PURE__ */ jsx("th", { scope: "col", className: "px-4 py-2.5 font-medium", children: "Type" }),
3656
- hasDefault ? /* @__PURE__ */ jsx("th", { scope: "col", className: "px-4 py-2.5 font-medium", children: "Default" }) : null,
3657
- /* @__PURE__ */ jsx("th", { scope: "col", className: "px-4 py-2.5 font-medium", children: "Description" })
3658
- ] }) }),
3659
- /* @__PURE__ */ jsx("tbody", { className: "divide-y divide-border", children: rows.map((r) => /* @__PURE__ */ jsxs("tr", { className: "align-top", children: [
3660
- /* @__PURE__ */ jsx("th", { scope: "row", className: "px-4 py-3 text-left font-normal", children: /* @__PURE__ */ jsxs("span", { className: "flex flex-col items-start gap-1", children: [
3661
- /* @__PURE__ */ jsx("code", { className: cn("font-mono text-[0.8125rem] text-foreground", r.deprecated && "line-through decoration-oca-subtle"), children: r.name }),
3662
- marks(r)
3663
- ] }) }),
3664
- /* @__PURE__ */ jsx("td", { className: "px-4 py-3 font-mono text-[0.8125rem] text-muted-foreground", children: r.type ?? "\u2014" }),
3665
- hasDefault ? /* @__PURE__ */ jsx("td", { className: "px-4 py-3 font-mono text-[0.8125rem] text-muted-foreground", children: r.default ?? "\u2014" }) : null,
3666
- /* @__PURE__ */ jsx("td", { className: "px-4 py-3 leading-relaxed text-muted-foreground", children: r.description })
3667
- ] }, r.name)) })
3668
- ] }) }) }),
3669
- /* @__PURE__ */ jsx("ul", { "aria-label": caption, className: "divide-y divide-border rounded-2xl border border-border bg-card sm:hidden", children: rows.map((r) => /* @__PURE__ */ jsxs("li", { className: "flex flex-col gap-1.5 px-4 py-3.5", children: [
3670
- /* @__PURE__ */ jsxs("span", { className: "flex flex-wrap items-baseline gap-x-2 gap-y-1", children: [
3671
- /* @__PURE__ */ jsx("code", { className: cn("font-mono text-[0.875rem] text-foreground", r.deprecated && "line-through decoration-oca-subtle"), children: r.name }),
3672
- r.type ? /* @__PURE__ */ jsx("code", { className: "break-all font-mono text-[0.8125rem] text-muted-foreground", children: r.type }) : null
3673
- ] }),
3674
- /* @__PURE__ */ jsx("span", { className: "flex flex-wrap items-center gap-2 empty:hidden", children: marks(r) }),
3675
- r.description ? /* @__PURE__ */ jsx("span", { className: "text-[0.875rem] leading-relaxed text-muted-foreground", children: r.description }) : null,
3676
- r.default !== void 0 ? /* @__PURE__ */ jsxs("span", { className: "text-[0.8125rem] text-muted-foreground", children: [
3677
- "Default ",
3678
- /* @__PURE__ */ jsx("code", { className: "font-mono text-foreground", children: r.default })
3679
- ] }) : null
3680
- ] }, r.name)) })
3681
- ] });
3312
+ const hasDescription = rows.some((r) => said(r.description));
3313
+ const hasSource = rows.some((r) => said(r.source));
3314
+ const cell = "px-4 py-3 max-sm:p-0";
3315
+ return /* @__PURE__ */ jsx("div", { className: cn("not-prose my-6 overflow-hidden rounded-2xl border border-border bg-card", className), children: /* @__PURE__ */ jsx(ScrollFade, { fade: "var(--card)", children: /* @__PURE__ */ jsxs("table", { className: "w-full border-collapse text-left text-[0.875rem] max-sm:block", children: [
3316
+ caption ? /* @__PURE__ */ jsx("caption", { className: "sr-only", children: caption }) : null,
3317
+ /* @__PURE__ */ jsx("thead", { className: "max-sm:sr-only", children: /* @__PURE__ */ jsxs("tr", { className: "border-b border-oca-hairline-strong bg-oca-table-head text-[0.8125rem]", children: [
3318
+ /* @__PURE__ */ jsx("th", { scope: "col", className: "px-4 py-2.5 font-medium", children: nameHeader }),
3319
+ /* @__PURE__ */ jsx("th", { scope: "col", className: "px-4 py-2.5 font-medium", children: "Type" }),
3320
+ hasDefault ? /* @__PURE__ */ jsx("th", { scope: "col", className: "px-4 py-2.5 font-medium", children: "Default" }) : null,
3321
+ hasDescription ? /* @__PURE__ */ jsx("th", { scope: "col", className: "px-4 py-2.5 font-medium", children: "Description" }) : null,
3322
+ hasSource ? /* @__PURE__ */ jsx("th", { scope: "col", className: "px-4 py-2.5 font-medium", children: "Defined in" }) : null
3323
+ ] }) }),
3324
+ /* @__PURE__ */ jsx("tbody", { className: "divide-y divide-border max-sm:block", children: rows.map((r) => /* @__PURE__ */ jsxs(
3325
+ "tr",
3326
+ {
3327
+ id: r.id,
3328
+ 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",
3329
+ children: [
3330
+ /* @__PURE__ */ jsx("th", { scope: "row", className: cn(cell, "text-left font-normal"), children: /* @__PURE__ */ 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: [
3331
+ /* @__PURE__ */ 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 }),
3332
+ r.required ? /* @__PURE__ */ jsx("span", { className: "text-[0.75rem] text-oca-accent-ink", children: "Required" }) : null,
3333
+ r.deprecated ? /* @__PURE__ */ jsx(Badge, { tone: "muted", children: "Deprecated" }) : null,
3334
+ r.status ? /* @__PURE__ */ jsx(StatusBadge, { status: r.status }) : null
3335
+ ] }) }),
3336
+ /* @__PURE__ */ 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" }),
3337
+ hasDefault ? /* @__PURE__ */ 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: [
3338
+ /* @__PURE__ */ jsx("span", { className: "font-sans sm:hidden", children: "Default " }),
3339
+ r.default ?? "\u2014"
3340
+ ] }) : null,
3341
+ hasDescription ? /* @__PURE__ */ jsx("td", { className: cn(cell, "leading-relaxed text-muted-foreground", !said(r.description) && "max-sm:hidden"), children: r.description }) : null,
3342
+ hasSource ? /* @__PURE__ */ 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
3343
+ ]
3344
+ },
3345
+ r.id ?? r.name
3346
+ )) })
3347
+ ] }) }) });
3682
3348
  }
3683
3349
  function useDarkMode() {
3684
3350
  const [dark, setDark] = useState(false);
@@ -3740,79 +3406,490 @@ function mermaidTheme(el) {
3740
3406
  sequenceNumberColor: card
3741
3407
  };
3742
3408
  }
3409
+ var FIT = 4 / 3;
3743
3410
  function naturalSize(svg) {
3744
3411
  const w = svg.match(/viewBox="[\d.-]+ [\d.-]+ ([\d.]+) [\d.]+"/)?.[1];
3745
- if (!w) return svg;
3746
- return svg.replace(/<svg([^>]*?)\swidth="100%"/, `<svg$1 width="${Math.ceil(Number(w))}"`).replace(/max-width:\s*[\d.]+px;?/, "");
3412
+ if (!w) return { svg, width: null };
3413
+ const width = Math.ceil(Number(w));
3414
+ return {
3415
+ svg: svg.replace(/<svg([^>]*?)\swidth="100%"/, `<svg$1 width="${width}"`).replace(/max-width:\s*[\d.]+px;?/, ""),
3416
+ width
3417
+ };
3418
+ }
3419
+ function useInnerWidth(ref, padding) {
3420
+ const [width, setWidth] = useState(null);
3421
+ useEffect(() => {
3422
+ const el = ref.current;
3423
+ if (!el) return;
3424
+ const ro = new ResizeObserver(() => setWidth(el.clientWidth - padding));
3425
+ ro.observe(el);
3426
+ return () => ro.disconnect();
3427
+ }, [ref, padding]);
3428
+ return width;
3429
+ }
3430
+ function Diagram({ chart, caption, load, className }) {
3431
+ const ref = useRef(null);
3432
+ const dark = useDarkMode();
3433
+ const raw = useId();
3434
+ const [drawn, setDrawn] = useState(null);
3435
+ const [failed, setFailed] = useState(false);
3436
+ const room = useInnerWidth(ref, 48);
3437
+ const fits = drawn?.width != null && room != null && drawn.width <= room * FIT;
3438
+ useEffect(() => {
3439
+ let live = true;
3440
+ const el = ref.current;
3441
+ if (!el) return;
3442
+ (async () => {
3443
+ try {
3444
+ const mod = await load();
3445
+ const mermaid = "default" in mod ? mod.default : mod;
3446
+ mermaid.initialize({ startOnLoad: false, securityLevel: "strict", theme: "base", themeVariables: mermaidTheme(el) });
3447
+ const { svg } = await mermaid.render(`oca-diagram-${raw.replace(/[^a-zA-Z0-9]/g, "")}-${dark ? "d" : "l"}`, chart);
3448
+ if (live) {
3449
+ setDrawn(naturalSize(svg));
3450
+ setFailed(false);
3451
+ }
3452
+ } catch {
3453
+ if (live) setFailed(true);
3454
+ }
3455
+ })();
3456
+ return () => {
3457
+ live = false;
3458
+ };
3459
+ }, [chart, dark, load, raw]);
3460
+ if (failed) return /* @__PURE__ */ jsx(CodeBlock, { code: chart, caption: "Diagram (shown as its source)", className: cn("my-6", className) });
3461
+ return /* @__PURE__ */ jsxs("figure", { ref, className: cn("not-prose my-6 overflow-hidden rounded-[1.25rem] border border-border bg-card", className), children: [
3462
+ drawn ? /* @__PURE__ */ jsx(ScrollFade, { fade: "var(--card)", children: /* @__PURE__ */ jsx(
3463
+ "div",
3464
+ {
3465
+ "data-fit": fits ? "" : void 0,
3466
+ className: cn(
3467
+ "flex justify-center p-6 [&_svg]:h-auto",
3468
+ fits ? "w-full [&_svg]:max-w-full" : "w-max min-w-full [&_svg]:max-w-none"
3469
+ ),
3470
+ role: "img",
3471
+ "aria-label": typeof caption === "string" ? caption : "Diagram",
3472
+ dangerouslySetInnerHTML: { __html: drawn.svg }
3473
+ }
3474
+ ) }) : /* @__PURE__ */ jsx("div", { role: "status", "aria-label": "Drawing the diagram", className: "p-6", children: /* @__PURE__ */ jsx(Skeleton, { className: "h-40 w-full rounded-xl" }) }),
3475
+ caption ? /* @__PURE__ */ jsx("figcaption", { className: "border-t border-border px-5 py-3 text-[0.8125rem] text-muted-foreground", children: caption }) : null
3476
+ ] });
3477
+ }
3478
+ var HEADING = {
3479
+ h1: "oca-display-3 mb-4 text-foreground",
3480
+ h2: "mb-3 mt-12 text-[1.375rem] font-medium leading-tight tracking-[-0.015em] text-foreground md:text-[1.5rem]",
3481
+ h3: "mb-2 mt-9 text-[1.125rem] font-medium leading-snug tracking-[-0.01em] text-foreground",
3482
+ h4: "mb-2 mt-7 text-[1rem] font-medium leading-snug text-foreground"
3483
+ };
3484
+ function DocsHeading({
3485
+ as: Tag,
3486
+ id,
3487
+ children,
3488
+ className,
3489
+ ...props
3490
+ }) {
3491
+ return /* @__PURE__ */ jsxs(Tag, { id, className: cn("group scroll-mt-28", HEADING[Tag], className), ...props, children: [
3492
+ /* @__PURE__ */ jsx("span", { "data-heading-text": "", children }),
3493
+ id && Tag !== "h1" ? /* @__PURE__ */ jsxs(
3494
+ "a",
3495
+ {
3496
+ href: `#${id}`,
3497
+ 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",
3498
+ children: [
3499
+ /* @__PURE__ */ jsx("span", { "aria-hidden": true, children: "#" }),
3500
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Link to this section" })
3501
+ ]
3502
+ }
3503
+ ) : null
3504
+ ] });
3505
+ }
3506
+ function ProtocolHero({
3507
+ protocol: protocol2,
3508
+ title,
3509
+ lead,
3510
+ actions,
3511
+ art,
3512
+ children,
3513
+ className
3514
+ }) {
3515
+ const p = protocolSite(protocol2);
3516
+ return /* @__PURE__ */ jsx(
3517
+ PageHero,
3518
+ {
3519
+ className,
3520
+ eyebrow: `Protocol \xB7 ${p.verb}`,
3521
+ title,
3522
+ lead,
3523
+ actions,
3524
+ art,
3525
+ children: p.status !== "live" || children ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-start gap-4", children: [
3526
+ p.status !== "live" ? /* @__PURE__ */ jsx(StatusBadge, { status: p.status }) : null,
3527
+ children
3528
+ ] }) : null
3529
+ }
3530
+ );
3531
+ }
3532
+ function ProtocolNav({
3533
+ current,
3534
+ link = "page",
3535
+ className
3536
+ }) {
3537
+ return /* @__PURE__ */ jsx("nav", { "aria-label": "Protocols", className, children: /* @__PURE__ */ jsx(ScrollFade, { fade: "var(--background)", children: /* @__PURE__ */ jsx("ul", { className: "flex w-max min-w-full items-center gap-6 border-b border-border", children: PROTOCOLS.map((p) => {
3538
+ const on = p.slug === current;
3539
+ return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
3540
+ "a",
3541
+ {
3542
+ href: link === "tool" ? p.toolHref : p.pageHref,
3543
+ "aria-current": on ? "page" : void 0,
3544
+ className: cn(
3545
+ "-mb-px inline-flex h-11 items-center border-b-2 text-[0.9375rem] transition-colors",
3546
+ on ? "border-foreground text-foreground" : "border-transparent text-muted-foreground hover:text-foreground"
3547
+ ),
3548
+ children: p.label
3549
+ }
3550
+ ) }, p.slug);
3551
+ }) }) }) });
3552
+ }
3553
+ var SPEC_FILE = {
3554
+ spec: {
3555
+ file: "SPEC.md",
3556
+ title: "Normative source",
3557
+ note: "This page is a human-readable summary. The authoritative copy lives in the spec repo. If the two ever drift, the repo wins."
3558
+ },
3559
+ security: {
3560
+ file: "SECURITY.md",
3561
+ title: "Normative threat model",
3562
+ note: "This page is the short form. The authoritative, numbered threat model lives in the spec repo."
3563
+ },
3564
+ rationale: {
3565
+ file: "WHY.md",
3566
+ title: "Design rationale",
3567
+ note: "This page is the short version. The full rationale and the rejected-design log live in the spec repo."
3568
+ }
3569
+ };
3570
+ function SpecCard(props) {
3571
+ return props.repo !== void 0 ? /* @__PURE__ */ jsx(SpecFileNote, { ...props }) : /* @__PURE__ */ jsx(ProtocolSpecCard, { ...props });
3572
+ }
3573
+ function SpecFileNote({ repo, file, kind = "spec", version, note, className }) {
3574
+ const d = SPEC_FILE[kind];
3575
+ const f = file ?? d.file;
3576
+ return /* @__PURE__ */ jsxs(Callout, { title: version ? `${d.title} \xB7 ${version}` : d.title, className, children: [
3577
+ /* @__PURE__ */ jsx("p", { children: note ?? d.note }),
3578
+ /* @__PURE__ */ jsx("p", { children: /* @__PURE__ */ jsx(TextLink, { href: `https://github.com/orangecheck/${repo}/blob/main/${f}`, className: "break-all font-mono text-[0.875rem]", children: `${repo}/${f}` }) })
3579
+ ] });
3580
+ }
3581
+ function ProtocolSpecCard({ protocol: protocol2, version, license, vectors, size = "md", className }) {
3582
+ const p = protocolSite(protocol2);
3583
+ const repo = `oc-${p.slug}-protocol`;
3584
+ const facts = [
3585
+ ["Version", version],
3586
+ ...license ? [["Licence", license]] : [],
3587
+ ["Nostr kind", p.kinds],
3588
+ ...vectors !== void 0 ? [["Test vectors", String(vectors)]] : []
3589
+ ];
3590
+ if (size === "sm") {
3591
+ return /* @__PURE__ */ jsxs(
3592
+ "a",
3593
+ {
3594
+ href: p.specHref,
3595
+ className: cn(
3596
+ "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",
3597
+ className
3598
+ ),
3599
+ children: [
3600
+ /* @__PURE__ */ jsx("span", { className: "font-mono text-[0.8125rem] text-foreground", children: repo }),
3601
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: facts.map(([k, v]) => k === "Version" ? `v${v}` : k === "Nostr kind" ? `kind ${v}` : v).join(" \xB7 ") }),
3602
+ /* @__PURE__ */ jsxs("span", { className: "ml-auto flex items-center gap-1 text-muted-foreground group-hover:text-foreground", children: [
3603
+ "Read the spec ",
3604
+ /* @__PURE__ */ jsx(ArrowUpRight, { "aria-hidden": true, className: "size-4" })
3605
+ ] })
3606
+ ]
3607
+ }
3608
+ );
3609
+ }
3610
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-6 rounded-[1.25rem] border border-border bg-card p-6 md:p-8", className), children: [
3611
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-4", children: [
3612
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col gap-1.5", children: [
3613
+ /* @__PURE__ */ jsx("p", { className: "text-[0.875rem] text-muted-foreground", children: "The spec" }),
3614
+ /* @__PURE__ */ jsx("h3", { className: "oca-title break-all font-mono text-[1.0625rem] tracking-normal", children: repo })
3615
+ ] }),
3616
+ p.status !== "live" ? /* @__PURE__ */ jsx(StatusBadge, { status: p.status }) : null
3617
+ ] }),
3618
+ /* @__PURE__ */ jsx("dl", { className: "grid grid-cols-2 gap-x-6 gap-y-4 sm:grid-cols-4", children: facts.map(([k, v]) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
3619
+ /* @__PURE__ */ jsx("dt", { className: "text-[0.8125rem] text-muted-foreground", children: k }),
3620
+ /* @__PURE__ */ jsx("dd", { className: "oca-tabular text-[1.0625rem]", children: v })
3621
+ ] }, k)) }),
3622
+ /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Button, { asChild: true, variant: "secondary", size: "sm", children: /* @__PURE__ */ jsxs("a", { href: p.specHref, children: [
3623
+ "Read the spec ",
3624
+ /* @__PURE__ */ jsx(ArrowUpRight, { "aria-hidden": true })
3625
+ ] }) }) })
3626
+ ] });
3627
+ }
3628
+ function VerifyBox({
3629
+ action,
3630
+ param = "q",
3631
+ title,
3632
+ description,
3633
+ label = "Id, envelope or link",
3634
+ placeholder,
3635
+ hint,
3636
+ submitLabel = "Verify",
3637
+ multiline = false,
3638
+ onVerify,
3639
+ className
3640
+ }) {
3641
+ const [value, setValue] = useState("");
3642
+ const submit = (e) => {
3643
+ if (!onVerify) return;
3644
+ e.preventDefault();
3645
+ if (value.trim()) onVerify(value.trim());
3646
+ };
3647
+ const button = /* @__PURE__ */ jsx(Button, { type: "submit", className: multiline ? void 0 : "w-full sm:w-auto", children: submitLabel });
3648
+ return /* @__PURE__ */ jsxs(
3649
+ "form",
3650
+ {
3651
+ action,
3652
+ method: "get",
3653
+ onSubmit: submit,
3654
+ className: cn("flex flex-col gap-5 rounded-[1.25rem] border border-border bg-card p-6 md:p-8", className),
3655
+ children: [
3656
+ title || description ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
3657
+ title ? /* @__PURE__ */ jsx("h3", { className: "oca-title", children: title }) : null,
3658
+ description ? /* @__PURE__ */ jsx("p", { className: "oca-body text-[0.9375rem]", children: description }) : null
3659
+ ] }) : null,
3660
+ multiline ? /* @__PURE__ */ jsxs(Fragment, { children: [
3661
+ /* @__PURE__ */ jsx(Field, { label, hint, children: /* @__PURE__ */ jsx(
3662
+ Textarea,
3663
+ {
3664
+ name: param,
3665
+ required: true,
3666
+ value,
3667
+ onChange: (e) => setValue(e.target.value),
3668
+ placeholder,
3669
+ spellCheck: false,
3670
+ className: "min-h-32 font-mono text-base md:text-[0.8125rem]"
3671
+ }
3672
+ ) }),
3673
+ /* @__PURE__ */ jsx("div", { children: button })
3674
+ ] }) : /* @__PURE__ */ jsx(Field, { label, hint, action: button, children: /* @__PURE__ */ jsx(
3675
+ Input,
3676
+ {
3677
+ name: param,
3678
+ required: true,
3679
+ value,
3680
+ onChange: (e) => setValue(e.target.value),
3681
+ placeholder,
3682
+ spellCheck: false,
3683
+ autoComplete: "off",
3684
+ className: "font-mono text-base md:text-[0.875rem]"
3685
+ }
3686
+ ) })
3687
+ ]
3688
+ }
3689
+ );
3747
3690
  }
3748
- function Diagram({ chart, caption, load, className }) {
3749
- const ref = useRef(null);
3750
- const dark = useDarkMode();
3751
- const raw = useId();
3752
- const [svg, setSvg] = useState(null);
3753
- const [failed, setFailed] = useState(false);
3754
- useEffect(() => {
3755
- let live = true;
3756
- const el = ref.current;
3757
- if (!el) return;
3758
- (async () => {
3759
- try {
3760
- const mod = await load();
3761
- const mermaid = "default" in mod ? mod.default : mod;
3762
- mermaid.initialize({ startOnLoad: false, securityLevel: "strict", theme: "base", themeVariables: mermaidTheme(el) });
3763
- const { svg: drawn } = await mermaid.render(`oca-diagram-${raw.replace(/[^a-zA-Z0-9]/g, "")}-${dark ? "d" : "l"}`, chart);
3764
- if (live) {
3765
- setSvg(naturalSize(drawn));
3766
- setFailed(false);
3767
- }
3768
- } catch {
3769
- if (live) setFailed(true);
3770
- }
3771
- })();
3772
- return () => {
3773
- live = false;
3774
- };
3775
- }, [chart, dark, load, raw]);
3776
- if (failed) return /* @__PURE__ */ jsx(CodeBlock, { code: chart, caption: "Diagram (shown as its source)", className: cn("my-6", className) });
3777
- return /* @__PURE__ */ jsxs("figure", { ref, className: cn("not-prose my-6 overflow-hidden rounded-[1.25rem] border border-border bg-card", className), children: [
3778
- svg ? /* @__PURE__ */ jsx(ScrollFade, { fade: "var(--card)", children: /* @__PURE__ */ jsx(
3779
- "div",
3691
+ var TINT = "bg-[color-mix(in_oklab,var(--oca-orange)_9%,var(--card))]";
3692
+ function ComparisonTable({
3693
+ columns,
3694
+ rows,
3695
+ label,
3696
+ propertyHeading = "Property",
3697
+ className
3698
+ }) {
3699
+ const wide = columns.length > 3;
3700
+ const grid = wide ? "lg:grid lg:grid-cols-[var(--oca-compare)]" : "md:grid md:grid-cols-[var(--oca-compare)]";
3701
+ const desk = wide ? "lg" : "md";
3702
+ const style = {
3703
+ // The argued-for column gets a little more room: its answers carry the page.
3704
+ "--oca-compare": ["minmax(0, 1.4fr)", ...columns.map((c) => c.highlight ? "minmax(0, 1.3fr)" : "minmax(0, 1fr)")].join(" ")
3705
+ };
3706
+ const ordered = [...columns].sort((a, b) => Number(Boolean(b.highlight)) - Number(Boolean(a.highlight)));
3707
+ return /* @__PURE__ */ jsxs("ul", { "aria-label": label, style, className: cn("divide-y divide-border rounded-[1.25rem] border border-border bg-card", className), children: [
3708
+ /* @__PURE__ */ jsxs(
3709
+ "li",
3780
3710
  {
3781
- className: "flex w-max min-w-full justify-center p-6 [&_svg]:h-auto [&_svg]:max-w-none",
3782
- role: "img",
3783
- "aria-label": typeof caption === "string" ? caption : "Diagram",
3784
- dangerouslySetInnerHTML: { __html: svg }
3711
+ "aria-hidden": true,
3712
+ className: cn(
3713
+ "hidden gap-5 px-5 py-4 text-[0.875rem] font-medium text-muted-foreground",
3714
+ wide ? "lg:grid lg:px-8" : "md:grid md:px-8",
3715
+ grid
3716
+ ),
3717
+ children: [
3718
+ /* @__PURE__ */ jsx("span", { children: propertyHeading }),
3719
+ columns.map((c) => /* @__PURE__ */ jsx("span", { className: cn(c.highlight && cn(TINT, "-my-4 px-4 py-4 text-oca-accent-ink")), children: c.label }, c.key))
3720
+ ]
3785
3721
  }
3786
- ) }) : /* @__PURE__ */ jsx("div", { role: "status", "aria-label": "Drawing the diagram", className: "p-6", children: /* @__PURE__ */ jsx(Skeleton, { className: "h-40 w-full rounded-xl" }) }),
3787
- caption ? /* @__PURE__ */ jsx("figcaption", { className: "border-t border-border px-5 py-3 text-[0.8125rem] text-muted-foreground", children: caption }) : null
3722
+ ),
3723
+ rows.map((r, ri) => /* @__PURE__ */ 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: [
3724
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col gap-1", children: [
3725
+ /* @__PURE__ */ jsx("span", { className: "oca-title-sm", children: r.label }),
3726
+ r.note ? /* @__PURE__ */ jsx("span", { className: "text-[0.875rem] leading-snug text-muted-foreground", children: r.note }) : null
3727
+ ] }),
3728
+ /* @__PURE__ */ jsx("div", { className: cn("grid grid-cols-2 gap-1", desk === "lg" ? "lg:contents" : "md:contents"), children: columns.map((c) => {
3729
+ return /* @__PURE__ */ jsxs(
3730
+ "div",
3731
+ {
3732
+ style: { "--oca-order": ordered.indexOf(c) },
3733
+ className: cn(
3734
+ // Two rows of the pair's grid (name, answer), so answers line up
3735
+ // across a pair even when one name wraps.
3736
+ "order-[var(--oca-order)] row-span-2 grid min-w-0 grid-rows-subgrid gap-1 rounded-xl px-3 py-2.5",
3737
+ 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",
3738
+ c.highlight ? cn(
3739
+ TINT,
3740
+ "col-span-2",
3741
+ 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"
3742
+ ) : desk === "lg" ? "lg:p-0" : "md:p-0"
3743
+ ),
3744
+ children: [
3745
+ /* @__PURE__ */ jsx(
3746
+ "span",
3747
+ {
3748
+ className: cn(
3749
+ "text-[0.8125rem]",
3750
+ c.highlight ? "text-oca-accent-ink" : "text-muted-foreground",
3751
+ desk === "lg" ? "lg:sr-only" : "md:sr-only"
3752
+ ),
3753
+ children: c.label
3754
+ }
3755
+ ),
3756
+ /* @__PURE__ */ jsx("span", { className: cn("text-[0.9375rem]", c.highlight && "font-medium"), children: r.values[c.key] ?? "\u2014" })
3757
+ ]
3758
+ },
3759
+ c.key
3760
+ );
3761
+ }) })
3762
+ ] }, ri))
3788
3763
  ] });
3789
3764
  }
3790
- var HEADING = {
3791
- h1: "oca-display-3 mb-4 text-foreground",
3792
- h2: "mb-3 mt-12 text-[1.375rem] font-medium leading-tight tracking-[-0.015em] text-foreground md:text-[1.5rem]",
3793
- h3: "mb-2 mt-9 text-[1.125rem] font-medium leading-snug tracking-[-0.01em] text-foreground",
3794
- h4: "mb-2 mt-7 text-[1rem] font-medium leading-snug text-foreground"
3765
+ var CHECK = {
3766
+ ok: { word: "Passed", icon: /* @__PURE__ */ jsx(CircleCheck, {}), tone: "text-success" },
3767
+ fail: { word: "Failed", icon: /* @__PURE__ */ jsx(CircleX, {}), tone: "text-destructive" },
3768
+ pending: { word: "Pending", icon: /* @__PURE__ */ jsx(Clock, {}), tone: "text-oca-accent-ink" },
3769
+ none: { word: "None", icon: /* @__PURE__ */ jsx(CircleSlash, {}), tone: "text-muted-foreground" },
3770
+ skipped: { word: "Skipped", icon: /* @__PURE__ */ jsx(CircleMinus, {}), tone: "text-muted-foreground" },
3771
+ unchecked: { word: "Not checked", icon: /* @__PURE__ */ jsx(CircleDashed, {}), tone: "text-oca-subtle" }
3795
3772
  };
3796
- function DocsHeading({
3797
- as: Tag,
3798
- id,
3799
- children,
3800
- className,
3801
- ...props
3773
+ function VerifyReport({
3774
+ verdict,
3775
+ title,
3776
+ summary,
3777
+ checks,
3778
+ facts,
3779
+ notChecked,
3780
+ actions,
3781
+ as: Heading = "h2",
3782
+ className
3802
3783
  }) {
3803
- return /* @__PURE__ */ jsxs(Tag, { id, className: cn("group scroll-mt-28", HEADING[Tag], className), ...props, children: [
3804
- /* @__PURE__ */ jsx("span", { "data-heading-text": "", children }),
3805
- id && Tag !== "h1" ? /* @__PURE__ */ jsxs(
3806
- "a",
3784
+ return /* @__PURE__ */ jsxs(
3785
+ "section",
3786
+ {
3787
+ "aria-label": "Verification result",
3788
+ className: cn("overflow-hidden rounded-[1.25rem] border border-border bg-card", className),
3789
+ children: [
3790
+ /* @__PURE__ */ jsxs("header", { className: "flex flex-col items-start gap-3 p-6 md:p-8", children: [
3791
+ /* @__PURE__ */ jsx(StatusBadge, { status: verdict }),
3792
+ /* @__PURE__ */ jsx(Heading, { className: "oca-display-3 [overflow-wrap:anywhere]", children: title }),
3793
+ summary ? /* @__PURE__ */ jsx("p", { className: "oca-body max-w-[40rem] [overflow-wrap:anywhere]", children: summary }) : null
3794
+ ] }),
3795
+ /* @__PURE__ */ jsx("ul", { "aria-label": "Checks", className: "divide-y divide-border border-t border-border", children: checks.map((c, i) => {
3796
+ const k = CHECK[c.state];
3797
+ return /* @__PURE__ */ jsxs("li", { className: "flex items-start gap-3 px-6 py-3.5 md:px-8", children: [
3798
+ /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: cn("mt-0.5 shrink-0 [&_svg]:size-[1.125rem]", k.tone), children: k.icon }),
3799
+ /* @__PURE__ */ 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: [
3800
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col gap-0.5", children: [
3801
+ /* @__PURE__ */ jsx("span", { className: "text-[0.9375rem]", children: c.label }),
3802
+ c.note ? /* @__PURE__ */ jsx("span", { className: "break-words text-[0.8125rem] leading-snug text-muted-foreground", children: c.note }) : null
3803
+ ] }),
3804
+ /* @__PURE__ */ jsx(
3805
+ "span",
3806
+ {
3807
+ className: cn(
3808
+ "shrink-0 text-[0.8125rem]",
3809
+ c.state === "fail" ? "text-destructive" : "text-muted-foreground"
3810
+ ),
3811
+ children: k.word
3812
+ }
3813
+ )
3814
+ ] })
3815
+ ] }, i);
3816
+ }) }),
3817
+ facts && facts.length > 0 ? /* @__PURE__ */ jsx(KeyValueList, { items: facts, className: "rounded-none border-x-0 border-b-0 bg-transparent [&>div]:px-6 md:[&>div]:px-8" }) : null,
3818
+ notChecked && notChecked.length > 0 ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 border-t border-border bg-muted/50 px-6 py-5 md:px-8", children: [
3819
+ /* @__PURE__ */ jsx("p", { className: "text-[0.875rem] font-medium", children: "What this did not check" }),
3820
+ /* @__PURE__ */ 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__ */ jsx("li", { children: n }, i)) })
3821
+ ] }) : null,
3822
+ actions ? /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-3 border-t border-border px-6 py-5 md:px-8", children: actions }) : null
3823
+ ]
3824
+ }
3825
+ );
3826
+ }
3827
+ function SignMessage({
3828
+ lead,
3829
+ address,
3830
+ message,
3831
+ wallets,
3832
+ busy = false,
3833
+ error,
3834
+ submitLabel = "Confirm",
3835
+ secondary,
3836
+ scheme = "bip322",
3837
+ onSignature,
3838
+ className
3839
+ }) {
3840
+ const [pasted, setPasted] = useState("");
3841
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-5", className), children: [
3842
+ lead ? /* @__PURE__ */ jsx("p", { className: "text-[0.9375rem] leading-relaxed", children: lead }) : null,
3843
+ wallets ? /* @__PURE__ */ jsxs(Fragment, { children: [
3844
+ /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2", children: wallets }),
3845
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 text-[0.8125rem] text-muted-foreground", children: [
3846
+ /* @__PURE__ */ jsx("span", { className: "h-px flex-1 bg-border" }),
3847
+ "or sign it in any wallet",
3848
+ /* @__PURE__ */ jsx("span", { className: "h-px flex-1 bg-border" })
3849
+ ] })
3850
+ ] }) : null,
3851
+ /* @__PURE__ */ jsx(CodeBlock, { code: message, caption: "Message to sign", wrap: true }),
3852
+ /* @__PURE__ */ jsxs(
3853
+ "form",
3807
3854
  {
3808
- href: `#${id}`,
3809
- 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",
3855
+ className: "flex flex-col gap-4",
3856
+ onSubmit: (e) => {
3857
+ e.preventDefault();
3858
+ if (pasted.trim()) onSignature(pasted.trim());
3859
+ },
3810
3860
  children: [
3811
- /* @__PURE__ */ jsx("span", { "aria-hidden": true, children: "#" }),
3812
- /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Link to this section" })
3861
+ /* @__PURE__ */ jsx(
3862
+ Field,
3863
+ {
3864
+ label: "Signature",
3865
+ error,
3866
+ hint: /* @__PURE__ */ jsxs(Fragment, { children: [
3867
+ "From your wallet\u2019s \u201Csign message\u201D (",
3868
+ scheme === "legacy" ? "legacy, BIP-137" : "BIP-322",
3869
+ "), signed by",
3870
+ " ",
3871
+ /* @__PURE__ */ jsx("span", { className: "break-all font-mono", children: address }),
3872
+ "."
3873
+ ] }),
3874
+ children: /* @__PURE__ */ jsx(
3875
+ Textarea,
3876
+ {
3877
+ value: pasted,
3878
+ onChange: (e) => setPasted(e.target.value),
3879
+ rows: 3,
3880
+ spellCheck: false,
3881
+ className: "min-h-24 font-mono text-base md:text-[0.8125rem]"
3882
+ }
3883
+ )
3884
+ }
3885
+ ),
3886
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-2", children: [
3887
+ /* @__PURE__ */ jsx(Button, { type: "submit", loading: busy, disabled: !pasted.trim(), children: submitLabel }),
3888
+ secondary
3889
+ ] })
3813
3890
  ]
3814
3891
  }
3815
- ) : null
3892
+ )
3816
3893
  ] });
3817
3894
  }
3818
3895
  function useMacKeys() {
@@ -4301,7 +4378,7 @@ function FormSection({
4301
4378
  "aria-current": status === "current" ? "step" : void 0,
4302
4379
  className: cn("scroll-mt-24 rounded-[1.25rem] border border-border bg-card", className),
4303
4380
  children: [
4304
- /* @__PURE__ */ jsxs("header", { className: cn("flex items-start gap-3.5", tight ? "px-5 pt-5" : "px-6 pt-6"), children: [
4381
+ /* @__PURE__ */ 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: [
4305
4382
  n !== void 0 ? /* @__PURE__ */ jsx(
4306
4383
  "span",
4307
4384
  {
@@ -4328,7 +4405,7 @@ function FormSection({
4328
4405
  ] }),
4329
4406
  hint ? /* @__PURE__ */ jsx("p", { className: "text-[0.875rem] leading-snug text-muted-foreground", children: hint }) : null
4330
4407
  ] }),
4331
- action ? /* @__PURE__ */ jsx("div", { className: "shrink-0", children: action }) : null
4408
+ action ? /* @__PURE__ */ jsx("div", { className: cn("shrink-0 max-sm:basis-full", n !== void 0 && "max-sm:pl-[2.625rem]"), children: action }) : null
4332
4409
  ] }),
4333
4410
  /* @__PURE__ */ 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 })
4334
4411
  ]
@@ -4558,27 +4635,30 @@ function FilterChips({
4558
4635
  onChange(cur.includes(v) ? cur.filter((x) => x !== v) : [...cur, v]);
4559
4636
  } else onChange(v);
4560
4637
  };
4561
- return /* @__PURE__ */ jsx(ScrollFade, { fade: "var(--background)", className: cn("w-full", className), children: /* @__PURE__ */ jsx("div", { role: "group", "aria-label": label, className: "flex w-max items-center gap-2 py-0.5", children: options.map((o) => {
4562
- const on = isOn(o.value);
4563
- return /* @__PURE__ */ jsxs(
4564
- "button",
4565
- {
4566
- type: "button",
4567
- "aria-pressed": on,
4568
- onClick: () => press(o.value),
4569
- className: cn(
4570
- "inline-flex shrink-0 items-center gap-1.5 rounded-full border px-3.5 text-[0.875rem] transition-colors",
4571
- tight ? "h-8" : "h-9",
4572
- on ? "border-foreground bg-foreground text-background" : "border-border bg-card text-muted-foreground hover:border-oca-hairline-strong hover:text-foreground"
4573
- ),
4574
- children: [
4575
- o.label,
4576
- o.count !== void 0 ? /* @__PURE__ */ jsx("span", { className: "oca-tabular", children: o.count.toLocaleString("en-US") }) : null
4577
- ]
4578
- },
4579
- o.value
4580
- );
4581
- }) }) });
4638
+ return (
4639
+ // Wraps rather than scrolls: every filter stays in view on a phone.
4640
+ /* @__PURE__ */ jsx("div", { role: "group", "aria-label": label, className: cn("flex flex-wrap items-center gap-2 py-0.5", className), children: options.map((o) => {
4641
+ const on = isOn(o.value);
4642
+ return /* @__PURE__ */ jsxs(
4643
+ "button",
4644
+ {
4645
+ type: "button",
4646
+ "aria-pressed": on,
4647
+ onClick: () => press(o.value),
4648
+ className: cn(
4649
+ "inline-flex shrink-0 items-center gap-1.5 rounded-full border px-3.5 text-[0.875rem] transition-colors",
4650
+ tight ? "h-8" : "h-9",
4651
+ on ? "border-foreground bg-foreground text-background" : "border-border bg-card text-muted-foreground hover:border-oca-hairline-strong hover:text-foreground"
4652
+ ),
4653
+ children: [
4654
+ o.label,
4655
+ o.count !== void 0 ? /* @__PURE__ */ jsx("span", { className: "oca-tabular", children: o.count.toLocaleString("en-US") }) : null
4656
+ ]
4657
+ },
4658
+ o.value
4659
+ );
4660
+ }) })
4661
+ );
4582
4662
  }
4583
4663
  function ToolGrid({
4584
4664
  tools,