@orangecheck/app-design 1.2.3 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/dist/chrome.d.mts +8 -3
  2. package/dist/chrome.d.ts +8 -3
  3. package/dist/chrome.js +605 -553
  4. package/dist/chrome.js.map +1 -1
  5. package/dist/chrome.mjs +605 -555
  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 +3 -3
  12. package/dist/components.d.ts +3 -3
  13. package/dist/components.js +730 -666
  14. package/dist/components.js.map +1 -1
  15. package/dist/components.mjs +731 -667
  16. package/dist/components.mjs.map +1 -1
  17. package/dist/{docs-Dxg4Tp_q.d.ts → docs-BB9gK4KF.d.ts} +18 -4
  18. package/dist/{docs-wJBfLS08.d.mts → docs-D-T-nHiu.d.mts} +18 -4
  19. package/dist/index.d.mts +4 -4
  20. package/dist/index.d.ts +4 -4
  21. package/dist/index.js +1549 -1406
  22. package/dist/index.js.map +1 -1
  23. package/dist/index.mjs +1548 -1407
  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 +168 -74
  28. package/dist/mdx.js.map +1 -1
  29. package/dist/mdx.mjs +169 -75
  30. package/dist/mdx.mjs.map +1 -1
  31. package/dist/primitives.d.mts +9 -3
  32. package/dist/primitives.d.ts +9 -3
  33. package/dist/primitives.js +7 -6
  34. package/dist/primitives.js.map +1 -1
  35. package/dist/primitives.mjs +7 -6
  36. package/dist/primitives.mjs.map +1 -1
  37. package/dist/session.d.mts +4 -3
  38. package/dist/session.d.ts +4 -3
  39. package/dist/session.js +27 -3
  40. package/dist/session.js.map +1 -1
  41. package/dist/session.mjs +27 -3
  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-kqGWMTep.d.mts → tool-shell-D8Q8XX11.d.mts} +8 -5
  46. package/dist/{tool-shell-DLSwUxTD.d.ts → tool-shell-gmlj47Ie.d.ts} +8 -5
  47. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -20,7 +20,8 @@ var PopoverPrimitive = require('@radix-ui/react-popover');
20
20
  var TooltipPrimitive = require('@radix-ui/react-tooltip');
21
21
  var TabsPrimitive = require('@radix-ui/react-tabs');
22
22
  var QRCode = require('qrcode');
23
- var Link8 = require('next/link');
23
+ var Link6 = require('next/link');
24
+ var router = require('next/compat/router');
24
25
  var nextThemes = require('next-themes');
25
26
 
26
27
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
@@ -55,7 +56,7 @@ var PopoverPrimitive__namespace = /*#__PURE__*/_interopNamespace(PopoverPrimitiv
55
56
  var TooltipPrimitive__namespace = /*#__PURE__*/_interopNamespace(TooltipPrimitive);
56
57
  var TabsPrimitive__namespace = /*#__PURE__*/_interopNamespace(TabsPrimitive);
57
58
  var QRCode__default = /*#__PURE__*/_interopDefault(QRCode);
58
- var Link8__default = /*#__PURE__*/_interopDefault(Link8);
59
+ var Link6__default = /*#__PURE__*/_interopDefault(Link6);
59
60
 
60
61
  // src/tokens/index.ts
61
62
  var APP_ATTRIBUTE = "data-oc-app";
@@ -460,16 +461,17 @@ var Label = react.forwardRef(function Label2({ className, ...props }, ref) {
460
461
  }
461
462
  );
462
463
  });
463
- function Field({ label, hint, optional, error, children, className, hideLabel, action }) {
464
- const id = react.useId();
464
+ function Field({ label, hint, optional, error, children, id: fixedId, className, hideLabel, action }) {
465
+ const generated = react.useId();
466
+ const id = fixedId ?? generated;
465
467
  const hintId = hint ? `${id}-hint` : void 0;
466
468
  const errorId = error ? `${id}-error` : void 0;
467
- const describedBy = [hintId, errorId].filter(Boolean).join(" ") || void 0;
468
- const control = react.isValidElement(children) ? react.cloneElement(children, {
469
+ const wiring = {
469
470
  id,
470
- "aria-describedby": describedBy,
471
+ "aria-describedby": [hintId, errorId].filter(Boolean).join(" ") || void 0,
471
472
  "aria-invalid": error ? true : void 0
472
- }) : children;
473
+ };
474
+ const control = typeof children === "function" ? children(wiring) : react.isValidElement(children) ? react.cloneElement(children, { ...wiring }) : children;
473
475
  const hintNode = hint ? /* @__PURE__ */ jsxRuntime.jsx("p", { id: hintId, className: "text-[0.8125rem] leading-snug text-muted-foreground", children: hint }) : null;
474
476
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-col gap-2", className), children: [
475
477
  /* @__PURE__ */ jsxRuntime.jsxs(Label, { htmlFor: id, className: hideLabel ? "sr-only" : "flex items-baseline gap-2", children: [
@@ -3004,11 +3006,13 @@ function forClipboard(text, lang) {
3004
3006
  if (!lines.some((l) => l.startsWith("$ "))) return text;
3005
3007
  return lines.filter((l) => l.startsWith("$ ")).map((l) => l.slice(2)).join("\n");
3006
3008
  }
3007
- function linesFromDom(pre) {
3009
+ function linesFromDom(pre, newline) {
3008
3010
  if (!pre) return null;
3009
3011
  const lines = pre.querySelectorAll("[data-line]");
3010
3012
  if (lines.length === 0) return pre.textContent ?? "";
3011
- return Array.from(lines).filter((l) => l.getAttribute("data-diff") !== "remove").map((l) => l.textContent ?? "").join("\n");
3013
+ const text = Array.from(lines).filter((l) => l.getAttribute("data-diff") !== "remove").map((l) => l.textContent ?? "").join("\n");
3014
+ return newline ? `${text}
3015
+ ` : text;
3012
3016
  }
3013
3017
  function prepare(code, lang, marks, diff) {
3014
3018
  const d = diff ? readDiff(code) : null;
@@ -3017,7 +3021,8 @@ function prepare(code, lang, marks, diff) {
3017
3021
  const kept = d ? src.split("\n").filter((_, i) => d.diff.get(i + 1) !== "remove") : null;
3018
3022
  return {
3019
3023
  html: linesToHtml(lines, { highlight: parseLineRanges(marks), diff: d?.diff }),
3020
- copy: kept ? kept.join("\n") : src,
3024
+ // Byte for byte, the final newline too: a hash printed beside the code must match a copy of it.
3025
+ copy: kept ? kept.join("\n") + (/\n$/.test(code) ? "\n" : "") : code,
3021
3026
  lines: lines.length,
3022
3027
  diff: !!d
3023
3028
  };
@@ -3082,6 +3087,7 @@ function CodeBlock({
3082
3087
  code,
3083
3088
  html,
3084
3089
  children,
3090
+ trailingNewline = false,
3085
3091
  lang,
3086
3092
  caption,
3087
3093
  copy = true,
@@ -3102,7 +3108,7 @@ function CodeBlock({
3102
3108
  );
3103
3109
  const markup = prepared?.html ?? html;
3104
3110
  const lines = prepared?.lines ?? (html !== void 0 ? html.split("\n").length : code?.split("\n").length ?? 0);
3105
- const read = () => forClipboard(prepared?.copy ?? linesFromDom(preRef.current) ?? code ?? "", lang);
3111
+ const read = () => forClipboard(prepared?.copy ?? linesFromDom(preRef.current, trailingNewline) ?? code ?? "", lang);
3106
3112
  return /* @__PURE__ */ jsxRuntime.jsxs("figure", { className: cn(FRAME, className), children: [
3107
3113
  /* @__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: [
3108
3114
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-[0.8125rem] text-oca-ink-subtle", children: caption ?? languageName(lang) ?? "Code" }),
@@ -3619,7 +3625,7 @@ function ErrorPage({
3619
3625
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "oca-lead oca-enter [--enter-delay:150ms]", children: detail ?? words.detail }),
3620
3626
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "oca-enter flex flex-wrap gap-3 [--enter-delay:230ms]", children: actions ?? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3621
3627
  server ? /* @__PURE__ */ jsxRuntime.jsx(Button, { onClick: () => window.location.reload(), children: "Try again" }) : null,
3622
- /* @__PURE__ */ jsxRuntime.jsx(Button, { asChild: true, variant: server ? "secondary" : "primary", children: /* @__PURE__ */ jsxRuntime.jsx(Link8__default.default, { href: home, children: "Go home" }) })
3628
+ /* @__PURE__ */ jsxRuntime.jsx(Button, { asChild: true, variant: server ? "secondary" : "primary", children: /* @__PURE__ */ jsxRuntime.jsx(Link6__default.default, { href: home, children: "Go home" }) })
3623
3629
  ] }) })
3624
3630
  ] }),
3625
3631
  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
@@ -3738,16 +3744,25 @@ function Faq({
3738
3744
  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)) });
3739
3745
  }
3740
3746
  var LINK = "text-foreground underline decoration-foreground/35 underline-offset-4 transition-colors hover:decoration-foreground";
3747
+ var SCHEME = /^[a-z][a-z\d+.-]*:/i;
3748
+ function useResolved(href) {
3749
+ const router$1 = router.useRouter();
3750
+ if (!router$1 || !href || href.startsWith("/") || href.startsWith("#") || href.startsWith("?") || SCHEME.test(href)) return href;
3751
+ const here = router$1.asPath.split(/[?#]/)[0] || "/";
3752
+ const url = new URL(href, `https://page.invalid${here}`);
3753
+ return url.pathname + url.search + url.hash;
3754
+ }
3741
3755
  function TextLink({
3742
- href,
3756
+ href: written,
3743
3757
  children,
3744
3758
  external,
3745
3759
  className
3746
3760
  }) {
3761
+ const href = useResolved(written);
3747
3762
  const internal = href.startsWith("/") && !href.startsWith("/api/") && !href.startsWith("/.well-known/");
3748
3763
  const offsite = external ?? /^https?:\/\//.test(href);
3749
3764
  if (internal && !offsite) {
3750
- return /* @__PURE__ */ jsxRuntime.jsx(Link8__default.default, { href, className: cn(LINK, className), children });
3765
+ return /* @__PURE__ */ jsxRuntime.jsx(Link6__default.default, { href, className: cn(LINK, className), children });
3751
3766
  }
3752
3767
  return /* @__PURE__ */ jsxRuntime.jsxs("a", { href, className: cn(LINK, className), ...offsite ? { target: "_blank", rel: "noreferrer" } : {}, children: [
3753
3768
  children,
@@ -4015,6 +4030,10 @@ var OCHK_IO_FOOTER = [
4015
4030
  ]
4016
4031
  }
4017
4032
  ];
4033
+ var InDocsContext = sharedContext("in-docs", false);
4034
+ function useInDocs() {
4035
+ return react.useContext(InDocsContext);
4036
+ }
4018
4037
  var CARD = "group relative flex h-full flex-col rounded-[1.25rem] border border-border bg-card p-6 transition-colors hover:border-oca-hairline-strong md:p-7 has-[a:focus-visible]:ring-2 has-[a:focus-visible]:ring-ring has-[a:focus-visible]:ring-offset-2 has-[a:focus-visible]:ring-offset-background";
4019
4038
  var STRETCH = 'outline-none after:absolute after:inset-0 after:rounded-[1.25rem] after:content-[""]';
4020
4039
  var pad2 = (n) => String(n + 1).padStart(2, "0");
@@ -4023,6 +4042,7 @@ function ProtocolGrid({
4023
4042
  link = "page",
4024
4043
  className
4025
4044
  }) {
4045
+ const inDocs = useInDocs();
4026
4046
  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) => {
4027
4047
  const p = protocolSite(slug);
4028
4048
  const i = PROTOCOL_ORDER.indexOf(slug);
@@ -4035,7 +4055,7 @@ function ProtocolGrid({
4035
4055
  ] }),
4036
4056
  p.status !== "live" ? /* @__PURE__ */ jsxRuntime.jsx(StatusBadge, { status: p.status }) : null
4037
4057
  ] }),
4038
- /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "oca-display-3", children: /* @__PURE__ */ jsxRuntime.jsx(
4058
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "oca-display-3", children: link === "docs" && inDocs ? /* @__PURE__ */ jsxRuntime.jsx(Link6__default.default, { href: `/${p.slug}`, className: STRETCH, children: p.label }) : /* @__PURE__ */ jsxRuntime.jsx(
4039
4059
  "a",
4040
4060
  {
4041
4061
  href: link === "tool" ? p.toolHref : link === "docs" ? `${DOCS_HREF}/${p.slug}` : p.pageHref,
@@ -4093,751 +4113,795 @@ function AppGrid({
4093
4113
  const list = sites ? sites.map((slug) => FAMILY.find((s) => s.slug === slug)).filter((s) => s !== void 0) : FAMILY.filter((s) => s.group === group);
4094
4114
  return /* @__PURE__ */ jsxRuntime.jsx("ul", { className: cn("grid grid-cols-1 gap-4 sm:grid-cols-2 md:gap-5", className), children: list.map((s) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx(AppCard, { name: s.label, line: s.line, href: s.href, protocols: s.protocols, status: s.status }) }, s.slug)) });
4095
4115
  }
4096
- function ProtocolHero({
4097
- protocol: protocol2,
4116
+ var isInternal = (href) => href.startsWith("/") || href.startsWith("#");
4117
+ function DocLink({ href, className, children, ...rest }) {
4118
+ return isInternal(href) ? /* @__PURE__ */ jsxRuntime.jsx(Link6__default.default, { href, className, ...rest, children }) : /* @__PURE__ */ jsxRuntime.jsx("a", { href, className, ...rest, children });
4119
+ }
4120
+ function Breadcrumbs({ items, action, className }) {
4121
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex min-h-11 items-center justify-between gap-4 sm:min-h-0", className), children: [
4122
+ /* @__PURE__ */ jsxRuntime.jsx("nav", { "aria-label": "Breadcrumb", className: "min-w-0", children: /* @__PURE__ */ jsxRuntime.jsx("ol", { className: "flex min-w-0 items-center gap-1.5 text-[0.875rem] text-muted-foreground", children: items.map((c, i) => {
4123
+ const last = i === items.length - 1;
4124
+ return /* @__PURE__ */ jsxRuntime.jsxs("li", { className: cn("flex items-center gap-1.5", last ? "min-w-0" : "shrink-0"), children: [
4125
+ c.href && !last ? /* @__PURE__ */ jsxRuntime.jsx(DocLink, { href: c.href, className: "inline-flex min-h-11 items-center transition-colors hover:text-foreground sm:min-h-0", children: c.label }) : /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-current": last ? "page" : void 0, className: cn("truncate", last && "text-foreground"), children: c.label }),
4126
+ !last ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { "aria-hidden": true, className: "size-3.5 shrink-0 text-oca-subtle" }) : null
4127
+ ] }, i);
4128
+ }) }) }),
4129
+ action ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0 text-[0.875rem]", children: action }) : null
4130
+ ] });
4131
+ }
4132
+ function DocsPager({ prev, next, className }) {
4133
+ if (!prev && !next) return null;
4134
+ const card = (l, dir) => /* @__PURE__ */ jsxRuntime.jsxs(
4135
+ DocLink,
4136
+ {
4137
+ href: l.href,
4138
+ className: cn(
4139
+ "group flex min-h-20 flex-col justify-center gap-1 rounded-2xl border border-border bg-card px-5 py-4 transition-colors hover:border-oca-hairline-strong",
4140
+ dir === "next" && "items-end text-right sm:col-start-2"
4141
+ ),
4142
+ children: [
4143
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-1.5 text-[0.8125rem] text-muted-foreground", children: [
4144
+ dir === "prev" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowLeft, { "aria-hidden": true, className: "size-3.5" }) : null,
4145
+ dir === "prev" ? "Previous" : "Next",
4146
+ l.section ? /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, children: "\xB7" }) : null,
4147
+ l.section ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: l.section }) : null,
4148
+ dir === "next" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowRight, { "aria-hidden": true, className: "size-3.5" }) : null
4149
+ ] }),
4150
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[1rem] font-medium leading-snug text-foreground", children: l.label })
4151
+ ]
4152
+ }
4153
+ );
4154
+ return /* @__PURE__ */ jsxRuntime.jsxs("nav", { "aria-label": "Previous and next page", className: cn("grid grid-cols-1 gap-3 border-t border-border pt-8 sm:grid-cols-2", className), children: [
4155
+ prev ? card(prev, "prev") : null,
4156
+ next ? card(next, "next") : null
4157
+ ] });
4158
+ }
4159
+ function useHeadings(selector = "#docs-content", key) {
4160
+ const [items, setItems] = react.useState([]);
4161
+ react.useEffect(() => {
4162
+ const read = () => {
4163
+ const root = document.querySelector(selector);
4164
+ if (!root) return setItems([]);
4165
+ setItems(
4166
+ Array.from(root.querySelectorAll("h2[id], h3[id]")).map((h) => ({
4167
+ id: h.id,
4168
+ // The anchor link's "#" is not part of the name.
4169
+ label: (h.querySelector("[data-heading-text]") ?? h).textContent?.trim() ?? "",
4170
+ level: h.tagName === "H3" ? 3 : 2
4171
+ }))
4172
+ );
4173
+ };
4174
+ const raf = requestAnimationFrame(read);
4175
+ const t = setTimeout(read, 80);
4176
+ return () => {
4177
+ cancelAnimationFrame(raf);
4178
+ clearTimeout(t);
4179
+ };
4180
+ }, [selector, key]);
4181
+ const activeId = useActiveHeading(items.map((i) => i.id));
4182
+ return { items, activeId };
4183
+ }
4184
+ function OnThisPage({
4185
+ items,
4186
+ activeId,
4187
+ title = "On this page",
4188
+ onNavigate,
4189
+ className
4190
+ }) {
4191
+ const id = react.useId();
4192
+ if (items.length === 0) return null;
4193
+ return (
4194
+ // With no visible title (a folded list under its own summary) the name is still "On this page".
4195
+ /* @__PURE__ */ jsxRuntime.jsxs("nav", { "aria-labelledby": title ? id : void 0, "aria-label": title ? void 0 : "On this page", className, children: [
4196
+ title ? /* @__PURE__ */ jsxRuntime.jsx("p", { id, className: "mb-3 text-[0.875rem] font-medium", children: title }) : null,
4197
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { children: items.map((t) => {
4198
+ const on = t.id === activeId;
4199
+ return /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx(
4200
+ "a",
4201
+ {
4202
+ href: `#${t.id}`,
4203
+ onClick: onNavigate,
4204
+ "aria-current": on ? "location" : void 0,
4205
+ className: cn(
4206
+ "block border-l py-1.5 text-[0.875rem] leading-snug transition-colors",
4207
+ t.level === 3 ? "pl-7" : "pl-4",
4208
+ on ? "border-foreground text-foreground" : "border-border text-muted-foreground hover:text-foreground"
4209
+ ),
4210
+ children: t.label
4211
+ }
4212
+ ) }, t.id);
4213
+ }) })
4214
+ ] })
4215
+ );
4216
+ }
4217
+ var CALLOUT_TONE = { note: "neutral", warning: "brand", danger: "danger" };
4218
+ function Callout({
4219
+ tone = "note",
4098
4220
  title,
4099
- lead,
4100
- actions,
4101
- art,
4102
4221
  children,
4103
4222
  className
4104
4223
  }) {
4105
- const p = protocolSite(protocol2);
4106
4224
  return /* @__PURE__ */ jsxRuntime.jsx(
4107
- PageHero,
4225
+ Notice,
4108
4226
  {
4109
- className,
4110
- eyebrow: `Protocol \xB7 ${p.verb}`,
4227
+ tone: CALLOUT_TONE[tone],
4111
4228
  title,
4112
- lead,
4113
- actions,
4114
- art,
4115
- children: p.status !== "live" || children ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-start gap-4", children: [
4116
- p.status !== "live" ? /* @__PURE__ */ jsxRuntime.jsx(StatusBadge, { status: p.status }) : null,
4117
- children
4118
- ] }) : null
4229
+ role: "note",
4230
+ className: cn("my-6 [&_p]:my-0 [&_p]:text-[0.9375rem] [&_p]:leading-relaxed [&_p+p]:mt-3", className),
4231
+ children
4119
4232
  }
4120
4233
  );
4121
4234
  }
4122
- function ProtocolNav({
4123
- current: current2,
4124
- link = "page",
4125
- className
4126
- }) {
4127
- 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) => {
4128
- const on = p.slug === current2;
4129
- return /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx(
4130
- "a",
4131
- {
4132
- href: link === "tool" ? p.toolHref : p.pageHref,
4133
- "aria-current": on ? "page" : void 0,
4134
- className: cn(
4135
- "-mb-px inline-flex h-11 items-center border-b-2 text-[0.9375rem] transition-colors",
4136
- on ? "border-foreground text-foreground" : "border-transparent text-muted-foreground hover:text-foreground"
4137
- ),
4138
- children: p.label
4139
- }
4140
- ) }, p.slug);
4141
- }) }) }) });
4142
- }
4143
- function SpecCard({
4144
- protocol: protocol2,
4145
- version,
4146
- license,
4147
- vectors,
4148
- size = "md",
4149
- className
4150
- }) {
4151
- const p = protocolSite(protocol2);
4152
- const repo = `oc-${p.slug}-protocol`;
4153
- const facts = [
4154
- ["Version", version],
4155
- ...license ? [["Licence", license]] : [],
4156
- ["Nostr kind", p.kinds],
4157
- ...vectors !== void 0 ? [["Test vectors", String(vectors)]] : []
4158
- ];
4159
- if (size === "sm") {
4160
- return /* @__PURE__ */ jsxRuntime.jsxs(
4161
- "a",
4235
+ function Step({ title, id, children }) {
4236
+ return /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "relative pb-8 pl-11 last:pb-0 [counter-increment:oca-step]", children: [
4237
+ /* @__PURE__ */ jsxRuntime.jsx(
4238
+ "span",
4162
4239
  {
4163
- href: p.specHref,
4164
- className: cn(
4165
- "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",
4166
- className
4167
- ),
4168
- children: [
4169
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono text-[0.8125rem] text-foreground", children: repo }),
4170
- /* @__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 ") }),
4171
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "ml-auto flex items-center gap-1 text-muted-foreground group-hover:text-foreground", children: [
4172
- "Read the spec ",
4173
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUpRight, { "aria-hidden": true, className: "size-4" })
4174
- ] })
4175
- ]
4240
+ "aria-hidden": true,
4241
+ className: "absolute left-0 top-0 flex size-7 items-center justify-center rounded-full border border-oca-hairline-strong bg-card text-[0.8125rem] oca-tabular text-foreground before:content-[counter(oca-step)]"
4176
4242
  }
4177
- );
4178
- }
4179
- 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: [
4180
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-4", children: [
4181
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-col gap-1.5", children: [
4182
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[0.875rem] text-muted-foreground", children: "The spec" }),
4183
- /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "oca-title break-all font-mono text-[1.0625rem] tracking-normal", children: repo })
4184
- ] }),
4185
- p.status !== "live" ? /* @__PURE__ */ jsxRuntime.jsx(StatusBadge, { status: p.status }) : null
4186
- ] }),
4187
- /* @__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: [
4188
- /* @__PURE__ */ jsxRuntime.jsx("dt", { className: "text-[0.8125rem] text-muted-foreground", children: k }),
4189
- /* @__PURE__ */ jsxRuntime.jsx("dd", { className: "oca-tabular text-[1.0625rem]", children: v })
4190
- ] }, k)) }),
4191
- /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(Button, { asChild: true, variant: "secondary", size: "sm", children: /* @__PURE__ */ jsxRuntime.jsxs("a", { href: p.specHref, children: [
4192
- "Read the spec ",
4193
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUpRight, { "aria-hidden": true })
4194
- ] }) }) })
4243
+ ),
4244
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: "absolute bottom-1 left-[0.8125rem] top-9 w-px bg-border" }),
4245
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { id, className: "scroll-mt-28 pt-0.5 text-[1.0625rem] font-medium leading-snug tracking-[-0.008em] text-foreground", children: title }),
4246
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2 text-muted-foreground [&>*:first-child]:mt-0 [&>*:last-child]:mb-0", children })
4195
4247
  ] });
4196
4248
  }
4197
- function VerifyBox({
4198
- action,
4199
- param = "q",
4249
+ function Steps({ children, className }) {
4250
+ return /* @__PURE__ */ jsxRuntime.jsx("ol", { className: cn("not-prose my-8 flex flex-col [counter-reset:oca-step] [&>li:last-child>span:nth-child(2)]:hidden", className), children });
4251
+ }
4252
+ function LinkCard({
4253
+ href,
4200
4254
  title,
4201
4255
  description,
4202
- label = "Id, envelope or link",
4203
- placeholder,
4204
- hint,
4205
- submitLabel = "Verify",
4206
- multiline = false,
4207
- onVerify,
4256
+ icon,
4257
+ meta,
4208
4258
  className
4209
4259
  }) {
4210
- const [value, setValue] = react.useState("");
4211
- const submit = (e) => {
4212
- if (!onVerify) return;
4213
- e.preventDefault();
4214
- if (value.trim()) onVerify(value.trim());
4215
- };
4216
- const button = /* @__PURE__ */ jsxRuntime.jsx(Button, { type: "submit", className: multiline ? void 0 : "w-full sm:w-auto", children: submitLabel });
4260
+ const Arrow = isInternal(href) ? lucideReact.ArrowRight : lucideReact.ArrowUpRight;
4217
4261
  return /* @__PURE__ */ jsxRuntime.jsxs(
4218
- "form",
4262
+ DocLink,
4219
4263
  {
4220
- action,
4221
- method: "get",
4222
- onSubmit: submit,
4223
- className: cn("flex flex-col gap-5 rounded-[1.25rem] border border-border bg-card p-6 md:p-8", className),
4264
+ href,
4265
+ className: cn(
4266
+ "group flex h-full flex-col gap-3 rounded-[1.25rem] border border-border bg-card p-5 transition-colors hover:border-oca-hairline-strong",
4267
+ className
4268
+ ),
4224
4269
  children: [
4225
- title || description ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
4226
- title ? /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "oca-title", children: title }) : null,
4227
- description ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "oca-body text-[0.9375rem]", children: description }) : null
4228
- ] }) : null,
4229
- multiline ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4230
- /* @__PURE__ */ jsxRuntime.jsx(Field, { label, hint, children: /* @__PURE__ */ jsxRuntime.jsx(
4231
- Textarea,
4232
- {
4233
- name: param,
4234
- required: true,
4235
- value,
4236
- onChange: (e) => setValue(e.target.value),
4237
- placeholder,
4238
- spellCheck: false,
4239
- className: "min-h-32 font-mono text-base md:text-[0.8125rem]"
4240
- }
4241
- ) }),
4242
- /* @__PURE__ */ jsxRuntime.jsx("div", { children: button })
4243
- ] }) : /* @__PURE__ */ jsxRuntime.jsx(Field, { label, hint, action: button, children: /* @__PURE__ */ jsxRuntime.jsx(
4244
- Input,
4245
- {
4246
- name: param,
4247
- required: true,
4248
- value,
4249
- onChange: (e) => setValue(e.target.value),
4250
- placeholder,
4251
- spellCheck: false,
4252
- autoComplete: "off",
4253
- className: "font-mono text-base md:text-[0.875rem]"
4254
- }
4255
- ) })
4270
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-start justify-between gap-3", children: [
4271
+ icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex size-9 shrink-0 items-center justify-center rounded-xl bg-muted text-foreground [&_svg]:size-[1.125rem]", children: icon }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[1rem] font-medium leading-snug text-foreground", children: title }),
4272
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex shrink-0 items-center gap-2", children: [
4273
+ meta,
4274
+ /* @__PURE__ */ jsxRuntime.jsx(Arrow, { "aria-hidden": true, className: "size-4 text-muted-foreground transition-transform group-hover:translate-x-0.5 group-hover:text-foreground" })
4275
+ ] })
4276
+ ] }),
4277
+ icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[1rem] font-medium leading-snug text-foreground", children: title }) : null,
4278
+ description ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[0.9375rem] leading-relaxed text-muted-foreground", children: description }) : null
4256
4279
  ]
4257
4280
  }
4258
4281
  );
4259
4282
  }
4260
- var TINT = "bg-[color-mix(in_oklab,var(--oca-orange)_9%,var(--card))]";
4261
- function ComparisonTable({
4262
- columns,
4283
+ function CardGrid({ columns = 2, children, className }) {
4284
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("not-prose my-6 grid grid-cols-1 gap-3 sm:grid-cols-2", columns === 3 && "lg:grid-cols-3", className), children });
4285
+ }
4286
+ function MdxTable({ className, ...props }) {
4287
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "not-prose my-6 overflow-hidden rounded-2xl border border-border bg-card", children: /* @__PURE__ */ jsxRuntime.jsx(ScrollFade, { fade: "var(--card)", children: /* @__PURE__ */ jsxRuntime.jsx(
4288
+ "table",
4289
+ {
4290
+ className: cn(
4291
+ "w-full border-collapse text-left text-[0.875rem] leading-relaxed",
4292
+ "[&_th]:whitespace-nowrap [&_th]:border-b [&_th]:border-oca-hairline-strong [&_th]:bg-oca-table-head [&_th]:px-4 [&_th]:py-2.5 [&_th]:text-[0.8125rem] [&_th]:font-medium [&_th]:text-foreground",
4293
+ "[&_td]:border-t [&_td]:border-border [&_td]:px-4 [&_td]:py-2.5 [&_td]:align-top [&_td]:text-muted-foreground [&_tbody_tr:first-child_td]:border-t-0",
4294
+ "[&_td_code]:bg-transparent [&_td_code]:p-0 [&_td_code]:text-foreground [&_td:first-child]:text-foreground",
4295
+ "[&_[align=center]]:text-center [&_[align=right]]:text-right",
4296
+ // On a phone a cell keeps a readable width; the table scrolls instead of crushing it.
4297
+ "max-sm:[&_td]:min-w-[9rem]",
4298
+ className
4299
+ ),
4300
+ ...props
4301
+ }
4302
+ ) }) });
4303
+ }
4304
+ var said = (n) => n !== void 0 && n !== null && n !== false && n !== "";
4305
+ function ApiTable({
4263
4306
  rows,
4264
- label,
4265
- propertyHeading = "Property",
4307
+ caption,
4308
+ nameHeader = "Name",
4266
4309
  className
4267
4310
  }) {
4268
- const wide = columns.length > 3;
4269
- const grid = wide ? "lg:grid lg:grid-cols-[var(--oca-compare)]" : "md:grid md:grid-cols-[var(--oca-compare)]";
4270
- const desk = wide ? "lg" : "md";
4271
- const style = {
4272
- // The argued-for column gets a little more room: its answers carry the page.
4273
- "--oca-compare": ["minmax(0, 1.4fr)", ...columns.map((c) => c.highlight ? "minmax(0, 1.3fr)" : "minmax(0, 1fr)")].join(" ")
4311
+ const hasDefault = rows.some((r) => r.default !== void 0);
4312
+ const hasDescription = rows.some((r) => said(r.description));
4313
+ const hasSource = rows.some((r) => said(r.source));
4314
+ const cell = "px-4 py-3 max-sm:p-0";
4315
+ 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: [
4316
+ caption ? /* @__PURE__ */ jsxRuntime.jsx("caption", { className: "sr-only", children: caption }) : null,
4317
+ /* @__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: [
4318
+ /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", className: "px-4 py-2.5 font-medium", children: nameHeader }),
4319
+ /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", className: "px-4 py-2.5 font-medium", children: "Type" }),
4320
+ hasDefault ? /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", className: "px-4 py-2.5 font-medium", children: "Default" }) : null,
4321
+ hasDescription ? /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", className: "px-4 py-2.5 font-medium", children: "Description" }) : null,
4322
+ hasSource ? /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", className: "px-4 py-2.5 font-medium", children: "Defined in" }) : null
4323
+ ] }) }),
4324
+ /* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "divide-y divide-border max-sm:block", children: rows.map((r) => /* @__PURE__ */ jsxRuntime.jsxs(
4325
+ "tr",
4326
+ {
4327
+ id: r.id,
4328
+ 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",
4329
+ children: [
4330
+ /* @__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: [
4331
+ /* @__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 }),
4332
+ r.required ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[0.75rem] text-oca-accent-ink", children: "Required" }) : null,
4333
+ r.deprecated ? /* @__PURE__ */ jsxRuntime.jsx(Badge, { tone: "muted", children: "Deprecated" }) : null,
4334
+ r.status ? /* @__PURE__ */ jsxRuntime.jsx(StatusBadge, { status: r.status }) : null
4335
+ ] }) }),
4336
+ /* @__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" }),
4337
+ 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: [
4338
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-sans sm:hidden", children: "Default " }),
4339
+ r.default ?? "\u2014"
4340
+ ] }) : null,
4341
+ hasDescription ? /* @__PURE__ */ jsxRuntime.jsx("td", { className: cn(cell, "leading-relaxed text-muted-foreground", !said(r.description) && "max-sm:hidden"), children: r.description }) : null,
4342
+ 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
4343
+ ]
4344
+ },
4345
+ r.id ?? r.name
4346
+ )) })
4347
+ ] }) }) });
4348
+ }
4349
+ function useDarkMode() {
4350
+ const [dark, setDark] = react.useState(false);
4351
+ react.useEffect(() => {
4352
+ const root = document.documentElement;
4353
+ const read = () => setDark(root.classList.contains("dark"));
4354
+ read();
4355
+ const mo = new MutationObserver(read);
4356
+ mo.observe(root, { attributes: true, attributeFilter: ["class"] });
4357
+ return () => mo.disconnect();
4358
+ }, []);
4359
+ return dark;
4360
+ }
4361
+ function mermaidTheme(el) {
4362
+ const css = getComputedStyle(el);
4363
+ const v = (name) => css.getPropertyValue(name).trim();
4364
+ const card = v("--card");
4365
+ const muted = v("--muted");
4366
+ const text = v("--foreground");
4367
+ const subtle = v("--muted-foreground");
4368
+ const line = v("--input");
4369
+ const hair = v("--oca-hairline-strong");
4370
+ return {
4371
+ background: "transparent",
4372
+ fontFamily: css.fontFamily,
4373
+ fontSize: "14px",
4374
+ textColor: text,
4375
+ mainBkg: card,
4376
+ primaryColor: card,
4377
+ primaryTextColor: text,
4378
+ primaryBorderColor: hair,
4379
+ secondaryColor: muted,
4380
+ secondaryTextColor: text,
4381
+ secondaryBorderColor: hair,
4382
+ tertiaryColor: muted,
4383
+ tertiaryTextColor: text,
4384
+ tertiaryBorderColor: hair,
4385
+ nodeBorder: hair,
4386
+ lineColor: line,
4387
+ edgeLabelBackground: card,
4388
+ clusterBkg: muted,
4389
+ clusterBorder: hair,
4390
+ titleColor: text,
4391
+ noteBkgColor: muted,
4392
+ noteTextColor: text,
4393
+ noteBorderColor: hair,
4394
+ actorBkg: card,
4395
+ actorBorder: hair,
4396
+ actorTextColor: text,
4397
+ actorLineColor: line,
4398
+ signalColor: text,
4399
+ signalTextColor: text,
4400
+ labelBoxBkgColor: card,
4401
+ labelBoxBorderColor: hair,
4402
+ labelTextColor: text,
4403
+ loopTextColor: subtle,
4404
+ activationBkgColor: muted,
4405
+ activationBorderColor: hair,
4406
+ sequenceNumberColor: card
4274
4407
  };
4275
- const ordered = [...columns].sort((a, b) => Number(Boolean(b.highlight)) - Number(Boolean(a.highlight)));
4276
- 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: [
4277
- /* @__PURE__ */ jsxRuntime.jsxs(
4278
- "li",
4408
+ }
4409
+ var FIT = 4 / 3;
4410
+ function naturalSize(svg) {
4411
+ const w = svg.match(/viewBox="[\d.-]+ [\d.-]+ ([\d.]+) [\d.]+"/)?.[1];
4412
+ if (!w) return { svg, width: null };
4413
+ const width = Math.ceil(Number(w));
4414
+ return {
4415
+ svg: svg.replace(/<svg([^>]*?)\swidth="100%"/, `<svg$1 width="${width}"`).replace(/max-width:\s*[\d.]+px;?/, ""),
4416
+ width
4417
+ };
4418
+ }
4419
+ function useInnerWidth(ref, padding) {
4420
+ const [width, setWidth] = react.useState(null);
4421
+ react.useEffect(() => {
4422
+ const el = ref.current;
4423
+ if (!el) return;
4424
+ const ro = new ResizeObserver(() => setWidth(el.clientWidth - padding));
4425
+ ro.observe(el);
4426
+ return () => ro.disconnect();
4427
+ }, [ref, padding]);
4428
+ return width;
4429
+ }
4430
+ function Diagram({ chart, caption, load, className }) {
4431
+ const ref = react.useRef(null);
4432
+ const dark = useDarkMode();
4433
+ const raw = react.useId();
4434
+ const [drawn, setDrawn] = react.useState(null);
4435
+ const [failed, setFailed] = react.useState(false);
4436
+ const room = useInnerWidth(ref, 48);
4437
+ const fits = drawn?.width != null && room != null && drawn.width <= room * FIT;
4438
+ react.useEffect(() => {
4439
+ let live = true;
4440
+ const el = ref.current;
4441
+ if (!el) return;
4442
+ (async () => {
4443
+ try {
4444
+ const mod = await load();
4445
+ const mermaid = "default" in mod ? mod.default : mod;
4446
+ mermaid.initialize({ startOnLoad: false, securityLevel: "strict", theme: "base", themeVariables: mermaidTheme(el) });
4447
+ const { svg } = await mermaid.render(`oca-diagram-${raw.replace(/[^a-zA-Z0-9]/g, "")}-${dark ? "d" : "l"}`, chart);
4448
+ if (live) {
4449
+ setDrawn(naturalSize(svg));
4450
+ setFailed(false);
4451
+ }
4452
+ } catch {
4453
+ if (live) setFailed(true);
4454
+ }
4455
+ })();
4456
+ return () => {
4457
+ live = false;
4458
+ };
4459
+ }, [chart, dark, load, raw]);
4460
+ if (failed) return /* @__PURE__ */ jsxRuntime.jsx(CodeBlock, { code: chart, caption: "Diagram (shown as its source)", className: cn("my-6", className) });
4461
+ return /* @__PURE__ */ jsxRuntime.jsxs("figure", { ref, className: cn("not-prose my-6 overflow-hidden rounded-[1.25rem] border border-border bg-card", className), children: [
4462
+ drawn ? /* @__PURE__ */ jsxRuntime.jsx(ScrollFade, { fade: "var(--card)", children: /* @__PURE__ */ jsxRuntime.jsx(
4463
+ "div",
4279
4464
  {
4280
- "aria-hidden": true,
4465
+ "data-fit": fits ? "" : void 0,
4281
4466
  className: cn(
4282
- "hidden gap-5 px-5 py-4 text-[0.875rem] font-medium text-muted-foreground",
4283
- wide ? "lg:grid lg:px-8" : "md:grid md:px-8",
4284
- grid
4467
+ "flex justify-center p-6 [&_svg]:h-auto",
4468
+ fits ? "w-full [&_svg]:max-w-full" : "w-max min-w-full [&_svg]:max-w-none"
4285
4469
  ),
4286
- children: [
4287
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: propertyHeading }),
4288
- 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))
4289
- ]
4470
+ role: "img",
4471
+ "aria-label": typeof caption === "string" ? caption : "Diagram",
4472
+ dangerouslySetInnerHTML: { __html: drawn.svg }
4290
4473
  }
4291
- ),
4292
- 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: [
4293
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-col gap-1", children: [
4294
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "oca-title-sm", children: r.label }),
4295
- r.note ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[0.875rem] leading-snug text-muted-foreground", children: r.note }) : null
4296
- ] }),
4297
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("grid grid-cols-2 gap-1", desk === "lg" ? "lg:contents" : "md:contents"), children: columns.map((c) => {
4298
- return /* @__PURE__ */ jsxRuntime.jsxs(
4299
- "div",
4300
- {
4301
- style: { "--oca-order": ordered.indexOf(c) },
4302
- className: cn(
4303
- // Two rows of the pair's grid (name, answer), so answers line up
4304
- // across a pair even when one name wraps.
4305
- "order-[var(--oca-order)] row-span-2 grid min-w-0 grid-rows-subgrid gap-1 rounded-xl px-3 py-2.5",
4306
- 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",
4307
- c.highlight ? cn(
4308
- TINT,
4309
- "col-span-2",
4310
- 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"
4311
- ) : desk === "lg" ? "lg:p-0" : "md:p-0"
4312
- ),
4313
- children: [
4314
- /* @__PURE__ */ jsxRuntime.jsx(
4315
- "span",
4316
- {
4317
- className: cn(
4318
- "text-[0.8125rem]",
4319
- c.highlight ? "text-oca-accent-ink" : "text-muted-foreground",
4320
- desk === "lg" ? "lg:sr-only" : "md:sr-only"
4321
- ),
4322
- children: c.label
4323
- }
4324
- ),
4325
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("text-[0.9375rem]", c.highlight && "font-medium"), children: r.values[c.key] ?? "\u2014" })
4326
- ]
4327
- },
4328
- c.key
4329
- );
4330
- }) })
4331
- ] }, ri))
4474
+ ) }) : /* @__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" }) }),
4475
+ caption ? /* @__PURE__ */ jsxRuntime.jsx("figcaption", { className: "border-t border-border px-5 py-3 text-[0.8125rem] text-muted-foreground", children: caption }) : null
4332
4476
  ] });
4333
4477
  }
4334
- var CHECK = {
4335
- ok: { word: "Passed", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CircleCheck, {}), tone: "text-success" },
4336
- fail: { word: "Failed", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CircleX, {}), tone: "text-destructive" },
4337
- pending: { word: "Pending", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Clock, {}), tone: "text-oca-accent-ink" },
4338
- skipped: { word: "Skipped", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CircleMinus, {}), tone: "text-muted-foreground" },
4339
- unchecked: { word: "Not checked", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CircleDashed, {}), tone: "text-oca-subtle" }
4478
+ var HEADING = {
4479
+ h1: "oca-display-3 mb-4 text-foreground",
4480
+ h2: "mb-3 mt-12 text-[1.375rem] font-medium leading-tight tracking-[-0.015em] text-foreground md:text-[1.5rem]",
4481
+ h3: "mb-2 mt-9 text-[1.125rem] font-medium leading-snug tracking-[-0.01em] text-foreground",
4482
+ h4: "mb-2 mt-7 text-[1rem] font-medium leading-snug text-foreground"
4340
4483
  };
4341
- function VerifyReport({
4342
- verdict,
4343
- title,
4344
- summary,
4345
- checks,
4346
- facts,
4347
- notChecked,
4348
- actions,
4349
- as: Heading = "h2",
4350
- className
4484
+ function DocsHeading({
4485
+ as: Tag,
4486
+ id,
4487
+ children,
4488
+ className,
4489
+ ...props
4351
4490
  }) {
4352
- return /* @__PURE__ */ jsxRuntime.jsxs(
4353
- "section",
4354
- {
4355
- "aria-label": "Verification result",
4356
- className: cn("overflow-hidden rounded-[1.25rem] border border-border bg-card", className),
4357
- children: [
4358
- /* @__PURE__ */ jsxRuntime.jsxs("header", { className: "flex flex-col items-start gap-3 p-6 md:p-8", children: [
4359
- /* @__PURE__ */ jsxRuntime.jsx(StatusBadge, { status: verdict }),
4360
- /* @__PURE__ */ jsxRuntime.jsx(Heading, { className: "oca-display-3", children: title }),
4361
- summary ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "oca-body max-w-[40rem]", children: summary }) : null
4362
- ] }),
4363
- /* @__PURE__ */ jsxRuntime.jsx("ul", { "aria-label": "Checks", className: "divide-y divide-border border-t border-border", children: checks.map((c, i) => {
4364
- const k = CHECK[c.state];
4365
- return /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex items-start gap-3 px-6 py-3.5 md:px-8", children: [
4366
- /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: cn("mt-0.5 shrink-0 [&_svg]:size-[1.125rem]", k.tone), children: k.icon }),
4367
- /* @__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: [
4368
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-col gap-0.5", children: [
4369
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[0.9375rem]", children: c.label }),
4370
- c.note ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "break-words text-[0.8125rem] leading-snug text-muted-foreground", children: c.note }) : null
4371
- ] }),
4372
- /* @__PURE__ */ jsxRuntime.jsx(
4373
- "span",
4374
- {
4375
- className: cn(
4376
- "shrink-0 text-[0.8125rem]",
4377
- c.state === "fail" ? "text-destructive" : "text-muted-foreground"
4378
- ),
4379
- children: k.word
4380
- }
4381
- )
4382
- ] })
4383
- ] }, i);
4384
- }) }),
4385
- 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,
4386
- 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: [
4387
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[0.875rem] font-medium", children: "What this did not check" }),
4388
- /* @__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)) })
4389
- ] }) : null,
4390
- 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
4391
- ]
4392
- }
4393
- );
4394
- }
4395
- function SignMessage({
4396
- lead,
4397
- address,
4398
- message,
4399
- wallets,
4400
- busy = false,
4401
- error,
4402
- submitLabel = "Confirm",
4403
- secondary,
4404
- onSignature,
4405
- className
4406
- }) {
4407
- const [pasted, setPasted] = react.useState("");
4408
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-col gap-5", className), children: [
4409
- lead ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[0.9375rem] leading-relaxed", children: lead }) : null,
4410
- wallets ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4411
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-2", children: wallets }),
4412
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 text-[0.8125rem] text-muted-foreground", children: [
4413
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "h-px flex-1 bg-border" }),
4414
- "or sign it in any wallet",
4415
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "h-px flex-1 bg-border" })
4416
- ] })
4417
- ] }) : null,
4418
- /* @__PURE__ */ jsxRuntime.jsx(CodeBlock, { code: message, caption: "Message to sign" }),
4419
- /* @__PURE__ */ jsxRuntime.jsxs(
4420
- "form",
4491
+ return /* @__PURE__ */ jsxRuntime.jsxs(Tag, { id, className: cn("group scroll-mt-28", HEADING[Tag], className), ...props, children: [
4492
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "data-heading-text": "", children }),
4493
+ id && Tag !== "h1" ? /* @__PURE__ */ jsxRuntime.jsxs(
4494
+ "a",
4421
4495
  {
4422
- className: "flex flex-col gap-4",
4423
- onSubmit: (e) => {
4424
- e.preventDefault();
4425
- if (pasted.trim()) onSignature(pasted.trim());
4426
- },
4496
+ href: `#${id}`,
4497
+ 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",
4427
4498
  children: [
4428
- /* @__PURE__ */ jsxRuntime.jsx(
4429
- Field,
4430
- {
4431
- label: "Signature",
4432
- error,
4433
- hint: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4434
- "From your wallet\u2019s \u201Csign message\u201D (BIP-322), signed by",
4435
- " ",
4436
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "break-all font-mono", children: address }),
4437
- "."
4438
- ] }),
4439
- children: /* @__PURE__ */ jsxRuntime.jsx(
4440
- Textarea,
4441
- {
4442
- value: pasted,
4443
- onChange: (e) => setPasted(e.target.value),
4444
- rows: 3,
4445
- spellCheck: false,
4446
- className: "min-h-24 font-mono text-base md:text-[0.8125rem]"
4447
- }
4448
- )
4449
- }
4450
- ),
4451
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-2", children: [
4452
- /* @__PURE__ */ jsxRuntime.jsx(Button, { type: "submit", loading: busy, disabled: !pasted.trim(), children: submitLabel }),
4453
- secondary
4454
- ] })
4499
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, children: "#" }),
4500
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Link to this section" })
4455
4501
  ]
4456
4502
  }
4457
- )
4458
- ] });
4459
- }
4460
- var isInternal = (href) => href.startsWith("/") || href.startsWith("#");
4461
- function DocLink({ href, className, children, ...rest }) {
4462
- return isInternal(href) ? /* @__PURE__ */ jsxRuntime.jsx(Link8__default.default, { href, className, ...rest, children }) : /* @__PURE__ */ jsxRuntime.jsx("a", { href, className, ...rest, children });
4463
- }
4464
- function Breadcrumbs({ items, action, className }) {
4465
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex min-h-11 items-center justify-between gap-4 sm:min-h-0", className), children: [
4466
- /* @__PURE__ */ jsxRuntime.jsx("nav", { "aria-label": "Breadcrumb", className: "min-w-0", children: /* @__PURE__ */ jsxRuntime.jsx("ol", { className: "flex min-w-0 items-center gap-1.5 text-[0.875rem] text-muted-foreground", children: items.map((c, i) => {
4467
- const last = i === items.length - 1;
4468
- return /* @__PURE__ */ jsxRuntime.jsxs("li", { className: cn("flex items-center gap-1.5", last ? "min-w-0" : "shrink-0"), children: [
4469
- c.href && !last ? /* @__PURE__ */ jsxRuntime.jsx(DocLink, { href: c.href, className: "inline-flex min-h-11 items-center transition-colors hover:text-foreground sm:min-h-0", children: c.label }) : /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-current": last ? "page" : void 0, className: cn("truncate", last && "text-foreground"), children: c.label }),
4470
- !last ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { "aria-hidden": true, className: "size-3.5 shrink-0 text-oca-subtle" }) : null
4471
- ] }, i);
4472
- }) }) }),
4473
- action ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0 text-[0.875rem]", children: action }) : null
4474
- ] });
4475
- }
4476
- function DocsPager({ prev, next, className }) {
4477
- if (!prev && !next) return null;
4478
- const card = (l, dir) => /* @__PURE__ */ jsxRuntime.jsxs(
4479
- DocLink,
4480
- {
4481
- href: l.href,
4482
- className: cn(
4483
- "group flex min-h-20 flex-col justify-center gap-1 rounded-2xl border border-border bg-card px-5 py-4 transition-colors hover:border-oca-hairline-strong",
4484
- dir === "next" && "items-end text-right sm:col-start-2"
4485
- ),
4486
- children: [
4487
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-1.5 text-[0.8125rem] text-muted-foreground", children: [
4488
- dir === "prev" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowLeft, { "aria-hidden": true, className: "size-3.5" }) : null,
4489
- dir === "prev" ? "Previous" : "Next",
4490
- l.section ? /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, children: "\xB7" }) : null,
4491
- l.section ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: l.section }) : null,
4492
- dir === "next" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowRight, { "aria-hidden": true, className: "size-3.5" }) : null
4493
- ] }),
4494
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[1rem] font-medium leading-snug text-foreground", children: l.label })
4495
- ]
4496
- }
4497
- );
4498
- return /* @__PURE__ */ jsxRuntime.jsxs("nav", { "aria-label": "Previous and next page", className: cn("grid grid-cols-1 gap-3 border-t border-border pt-8 sm:grid-cols-2", className), children: [
4499
- prev ? card(prev, "prev") : null,
4500
- next ? card(next, "next") : null
4503
+ ) : null
4501
4504
  ] });
4502
4505
  }
4503
- function useHeadings(selector = "#docs-content", key) {
4504
- const [items, setItems] = react.useState([]);
4505
- react.useEffect(() => {
4506
- const read = () => {
4507
- const root = document.querySelector(selector);
4508
- if (!root) return setItems([]);
4509
- setItems(
4510
- Array.from(root.querySelectorAll("h2[id], h3[id]")).map((h) => ({
4511
- id: h.id,
4512
- // The anchor link's "#" is not part of the name.
4513
- label: (h.querySelector("[data-heading-text]") ?? h).textContent?.trim() ?? "",
4514
- level: h.tagName === "H3" ? 3 : 2
4515
- }))
4516
- );
4517
- };
4518
- const raf = requestAnimationFrame(read);
4519
- const t = setTimeout(read, 80);
4520
- return () => {
4521
- cancelAnimationFrame(raf);
4522
- clearTimeout(t);
4523
- };
4524
- }, [selector, key]);
4525
- const activeId = useActiveHeading(items.map((i) => i.id));
4526
- return { items, activeId };
4506
+ function codeText(node) {
4507
+ if (typeof node === "string") return node;
4508
+ if (typeof node === "number") return String(node);
4509
+ if (Array.isArray(node)) return node.map(codeText).join("");
4510
+ if (react.isValidElement(node)) return codeText(node.props.children);
4511
+ return "";
4527
4512
  }
4528
- function OnThisPage({
4529
- items,
4530
- activeId,
4531
- title = "On this page",
4532
- onNavigate,
4533
- className
4534
- }) {
4535
- const id = react.useId();
4536
- if (items.length === 0) return null;
4537
- return (
4538
- // With no visible title (a folded list under its own summary) the name is still "On this page".
4539
- /* @__PURE__ */ jsxRuntime.jsxs("nav", { "aria-labelledby": title ? id : void 0, "aria-label": title ? void 0 : "On this page", className, children: [
4540
- title ? /* @__PURE__ */ jsxRuntime.jsx("p", { id, className: "mb-3 text-[0.875rem] font-medium", children: title }) : null,
4541
- /* @__PURE__ */ jsxRuntime.jsx("ul", { children: items.map((t) => {
4542
- const on = t.id === activeId;
4543
- return /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx(
4544
- "a",
4545
- {
4546
- href: `#${t.id}`,
4547
- onClick: onNavigate,
4548
- "aria-current": on ? "location" : void 0,
4549
- className: cn(
4550
- "block border-l py-1.5 text-[0.875rem] leading-snug transition-colors",
4551
- t.level === 3 ? "pl-7" : "pl-4",
4552
- on ? "border-foreground text-foreground" : "border-border text-muted-foreground hover:text-foreground"
4553
- ),
4554
- children: t.label
4555
- }
4556
- ) }, t.id);
4557
- }) })
4558
- ] })
4559
- );
4513
+ function codeLang(node) {
4514
+ const child = react.Children.toArray(node)[0];
4515
+ if (!react.isValidElement(child)) return void 0;
4516
+ const cls = child.props.className ?? "";
4517
+ return cls.match(/language-([\w+-]+)/)?.[1];
4560
4518
  }
4561
- var CALLOUT_TONE = { note: "neutral", warning: "brand", danger: "danger" };
4562
- function Callout({
4563
- tone = "note",
4519
+ function ProtocolHero({
4520
+ protocol: protocol2,
4564
4521
  title,
4522
+ lead,
4523
+ actions,
4524
+ art,
4565
4525
  children,
4566
4526
  className
4567
4527
  }) {
4528
+ const p = protocolSite(protocol2);
4568
4529
  return /* @__PURE__ */ jsxRuntime.jsx(
4569
- Notice,
4530
+ PageHero,
4570
4531
  {
4571
- tone: CALLOUT_TONE[tone],
4532
+ className,
4533
+ eyebrow: `Protocol \xB7 ${p.verb}`,
4572
4534
  title,
4573
- role: "note",
4574
- className: cn("my-6 [&_p]:my-0 [&_p]:text-[0.9375rem] [&_p]:leading-relaxed [&_p+p]:mt-3", className),
4575
- children
4535
+ lead,
4536
+ actions,
4537
+ art,
4538
+ children: p.status !== "live" || children ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-start gap-4", children: [
4539
+ p.status !== "live" ? /* @__PURE__ */ jsxRuntime.jsx(StatusBadge, { status: p.status }) : null,
4540
+ children
4541
+ ] }) : null
4576
4542
  }
4577
4543
  );
4578
4544
  }
4579
- function Step({ title, id, children }) {
4580
- return /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "relative pb-8 pl-11 last:pb-0 [counter-increment:oca-step]", children: [
4581
- /* @__PURE__ */ jsxRuntime.jsx(
4582
- "span",
4545
+ function ProtocolNav({
4546
+ current: current2,
4547
+ link = "page",
4548
+ className
4549
+ }) {
4550
+ 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) => {
4551
+ const on = p.slug === current2;
4552
+ return /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx(
4553
+ "a",
4583
4554
  {
4584
- "aria-hidden": true,
4585
- className: "absolute left-0 top-0 flex size-7 items-center justify-center rounded-full border border-oca-hairline-strong bg-card text-[0.8125rem] oca-tabular text-foreground before:content-[counter(oca-step)]"
4586
- }
4587
- ),
4588
- /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: "absolute bottom-1 left-[0.8125rem] top-9 w-px bg-border" }),
4589
- /* @__PURE__ */ jsxRuntime.jsx("h3", { id, className: "scroll-mt-28 pt-0.5 text-[1.0625rem] font-medium leading-snug tracking-[-0.008em] text-foreground", children: title }),
4590
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2 text-muted-foreground [&>*:first-child]:mt-0 [&>*:last-child]:mb-0", children })
4555
+ href: link === "tool" ? p.toolHref : p.pageHref,
4556
+ "aria-current": on ? "page" : void 0,
4557
+ className: cn(
4558
+ "-mb-px inline-flex h-11 items-center border-b-2 text-[0.9375rem] transition-colors",
4559
+ on ? "border-foreground text-foreground" : "border-transparent text-muted-foreground hover:text-foreground"
4560
+ ),
4561
+ children: p.label
4562
+ }
4563
+ ) }, p.slug);
4564
+ }) }) }) });
4565
+ }
4566
+ var SPEC_FILE = {
4567
+ spec: {
4568
+ file: "SPEC.md",
4569
+ title: "Normative source",
4570
+ note: "This page is a human-readable summary. The authoritative copy lives in the spec repo. If the two ever drift, the repo wins."
4571
+ },
4572
+ security: {
4573
+ file: "SECURITY.md",
4574
+ title: "Normative threat model",
4575
+ note: "This page is the short form. The authoritative, numbered threat model lives in the spec repo."
4576
+ },
4577
+ rationale: {
4578
+ file: "WHY.md",
4579
+ title: "Design rationale",
4580
+ note: "This page is the short version. The full rationale and the rejected-design log live in the spec repo."
4581
+ }
4582
+ };
4583
+ function SpecCard(props) {
4584
+ return props.repo !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(SpecFileNote, { ...props }) : /* @__PURE__ */ jsxRuntime.jsx(ProtocolSpecCard, { ...props });
4585
+ }
4586
+ function SpecFileNote({ repo, file, kind = "spec", version, note, className }) {
4587
+ const d = SPEC_FILE[kind];
4588
+ const f = file ?? d.file;
4589
+ return /* @__PURE__ */ jsxRuntime.jsxs(Callout, { title: version ? `${d.title} \xB7 ${version}` : d.title, className, children: [
4590
+ /* @__PURE__ */ jsxRuntime.jsx("p", { children: note ?? d.note }),
4591
+ /* @__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}` }) })
4591
4592
  ] });
4592
4593
  }
4593
- function Steps({ children, className }) {
4594
- return /* @__PURE__ */ jsxRuntime.jsx("ol", { className: cn("not-prose my-8 flex flex-col [counter-reset:oca-step] [&>li:last-child>span:nth-child(2)]:hidden", className), children });
4594
+ function ProtocolSpecCard({ protocol: protocol2, version, license, vectors, size = "md", className }) {
4595
+ const p = protocolSite(protocol2);
4596
+ const repo = `oc-${p.slug}-protocol`;
4597
+ const facts = [
4598
+ ["Version", version],
4599
+ ...license ? [["Licence", license]] : [],
4600
+ ["Nostr kind", p.kinds],
4601
+ ...vectors !== void 0 ? [["Test vectors", String(vectors)]] : []
4602
+ ];
4603
+ if (size === "sm") {
4604
+ return /* @__PURE__ */ jsxRuntime.jsxs(
4605
+ "a",
4606
+ {
4607
+ href: p.specHref,
4608
+ className: cn(
4609
+ "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",
4610
+ className
4611
+ ),
4612
+ children: [
4613
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono text-[0.8125rem] text-foreground", children: repo }),
4614
+ /* @__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 ") }),
4615
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "ml-auto flex items-center gap-1 text-muted-foreground group-hover:text-foreground", children: [
4616
+ "Read the spec ",
4617
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUpRight, { "aria-hidden": true, className: "size-4" })
4618
+ ] })
4619
+ ]
4620
+ }
4621
+ );
4622
+ }
4623
+ 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: [
4624
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-4", children: [
4625
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-col gap-1.5", children: [
4626
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[0.875rem] text-muted-foreground", children: "The spec" }),
4627
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "oca-title break-all font-mono text-[1.0625rem] tracking-normal", children: repo })
4628
+ ] }),
4629
+ p.status !== "live" ? /* @__PURE__ */ jsxRuntime.jsx(StatusBadge, { status: p.status }) : null
4630
+ ] }),
4631
+ /* @__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: [
4632
+ /* @__PURE__ */ jsxRuntime.jsx("dt", { className: "text-[0.8125rem] text-muted-foreground", children: k }),
4633
+ /* @__PURE__ */ jsxRuntime.jsx("dd", { className: "oca-tabular text-[1.0625rem]", children: v })
4634
+ ] }, k)) }),
4635
+ /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(Button, { asChild: true, variant: "secondary", size: "sm", children: /* @__PURE__ */ jsxRuntime.jsxs("a", { href: p.specHref, children: [
4636
+ "Read the spec ",
4637
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUpRight, { "aria-hidden": true })
4638
+ ] }) }) })
4639
+ ] });
4595
4640
  }
4596
- function LinkCard({
4597
- href,
4641
+ function VerifyBox({
4642
+ action,
4643
+ param = "q",
4598
4644
  title,
4599
4645
  description,
4600
- icon,
4601
- meta,
4646
+ label = "Id, envelope or link",
4647
+ placeholder,
4648
+ hint,
4649
+ submitLabel = "Verify",
4650
+ multiline = false,
4651
+ onVerify,
4602
4652
  className
4603
4653
  }) {
4604
- const Arrow = isInternal(href) ? lucideReact.ArrowRight : lucideReact.ArrowUpRight;
4654
+ const [value, setValue] = react.useState("");
4655
+ const submit = (e) => {
4656
+ if (!onVerify) return;
4657
+ e.preventDefault();
4658
+ if (value.trim()) onVerify(value.trim());
4659
+ };
4660
+ const button = /* @__PURE__ */ jsxRuntime.jsx(Button, { type: "submit", className: multiline ? void 0 : "w-full sm:w-auto", children: submitLabel });
4605
4661
  return /* @__PURE__ */ jsxRuntime.jsxs(
4606
- DocLink,
4662
+ "form",
4607
4663
  {
4608
- href,
4609
- className: cn(
4610
- "group flex h-full flex-col gap-3 rounded-[1.25rem] border border-border bg-card p-5 transition-colors hover:border-oca-hairline-strong",
4611
- className
4612
- ),
4664
+ action,
4665
+ method: "get",
4666
+ onSubmit: submit,
4667
+ className: cn("flex flex-col gap-5 rounded-[1.25rem] border border-border bg-card p-6 md:p-8", className),
4613
4668
  children: [
4614
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-start justify-between gap-3", children: [
4615
- icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex size-9 shrink-0 items-center justify-center rounded-xl bg-muted text-foreground [&_svg]:size-[1.125rem]", children: icon }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[1rem] font-medium leading-snug text-foreground", children: title }),
4616
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex shrink-0 items-center gap-2", children: [
4617
- meta,
4618
- /* @__PURE__ */ jsxRuntime.jsx(Arrow, { "aria-hidden": true, className: "size-4 text-muted-foreground transition-transform group-hover:translate-x-0.5 group-hover:text-foreground" })
4619
- ] })
4620
- ] }),
4621
- icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[1rem] font-medium leading-snug text-foreground", children: title }) : null,
4622
- description ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[0.9375rem] leading-relaxed text-muted-foreground", children: description }) : null
4669
+ title || description ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
4670
+ title ? /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "oca-title", children: title }) : null,
4671
+ description ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "oca-body text-[0.9375rem]", children: description }) : null
4672
+ ] }) : null,
4673
+ multiline ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4674
+ /* @__PURE__ */ jsxRuntime.jsx(Field, { label, hint, children: /* @__PURE__ */ jsxRuntime.jsx(
4675
+ Textarea,
4676
+ {
4677
+ name: param,
4678
+ required: true,
4679
+ value,
4680
+ onChange: (e) => setValue(e.target.value),
4681
+ placeholder,
4682
+ spellCheck: false,
4683
+ className: "min-h-32 font-mono text-base md:text-[0.8125rem]"
4684
+ }
4685
+ ) }),
4686
+ /* @__PURE__ */ jsxRuntime.jsx("div", { children: button })
4687
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx(Field, { label, hint, action: button, children: /* @__PURE__ */ jsxRuntime.jsx(
4688
+ Input,
4689
+ {
4690
+ name: param,
4691
+ required: true,
4692
+ value,
4693
+ onChange: (e) => setValue(e.target.value),
4694
+ placeholder,
4695
+ spellCheck: false,
4696
+ autoComplete: "off",
4697
+ className: "font-mono text-base md:text-[0.875rem]"
4698
+ }
4699
+ ) })
4623
4700
  ]
4624
4701
  }
4625
4702
  );
4626
4703
  }
4627
- function CardGrid({ columns = 2, children, className }) {
4628
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("not-prose my-6 grid grid-cols-1 gap-3 sm:grid-cols-2", columns === 3 && "lg:grid-cols-3", className), children });
4629
- }
4630
- function MdxTable({ className, ...props }) {
4631
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "not-prose my-6 overflow-hidden rounded-2xl border border-border bg-card", children: /* @__PURE__ */ jsxRuntime.jsx(ScrollFade, { fade: "var(--card)", children: /* @__PURE__ */ jsxRuntime.jsx(
4632
- "table",
4633
- {
4634
- className: cn(
4635
- "w-full border-collapse text-left text-[0.875rem] leading-relaxed",
4636
- "[&_th]:whitespace-nowrap [&_th]:border-b [&_th]:border-oca-hairline-strong [&_th]:bg-oca-table-head [&_th]:px-4 [&_th]:py-2.5 [&_th]:text-[0.8125rem] [&_th]:font-medium [&_th]:text-foreground",
4637
- "[&_td]:border-t [&_td]:border-border [&_td]:px-4 [&_td]:py-2.5 [&_td]:align-top [&_td]:text-muted-foreground [&_tbody_tr:first-child_td]:border-t-0",
4638
- "[&_td_code]:bg-transparent [&_td_code]:p-0 [&_td_code]:text-foreground [&_td:first-child]:text-foreground",
4639
- "[&_[align=center]]:text-center [&_[align=right]]:text-right",
4640
- // On a phone a cell keeps a readable width; the table scrolls instead of crushing it.
4641
- "max-sm:[&_td]:min-w-[9rem]",
4642
- className
4643
- ),
4644
- ...props
4645
- }
4646
- ) }) });
4647
- }
4648
- function ApiTable({
4704
+ var TINT = "bg-[color-mix(in_oklab,var(--oca-orange)_9%,var(--card))]";
4705
+ function ComparisonTable({
4706
+ columns,
4649
4707
  rows,
4650
- caption,
4651
- nameHeader = "Name",
4708
+ label,
4709
+ propertyHeading = "Property",
4652
4710
  className
4653
4711
  }) {
4654
- const hasDefault = rows.some((r) => r.default !== void 0);
4655
- const marks = (r) => /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4656
- r.required ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[0.75rem] text-oca-accent-ink", children: "Required" }) : null,
4657
- r.deprecated ? /* @__PURE__ */ jsxRuntime.jsx(Badge, { tone: "muted", children: "Deprecated" }) : null,
4658
- r.status ? /* @__PURE__ */ jsxRuntime.jsx(StatusBadge, { status: r.status }) : null
4659
- ] });
4660
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("not-prose my-6", className), children: [
4661
- /* @__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: [
4662
- caption ? /* @__PURE__ */ jsxRuntime.jsx("caption", { className: "sr-only", children: caption }) : null,
4663
- /* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "border-b border-oca-hairline-strong bg-oca-table-head text-[0.8125rem]", children: [
4664
- /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", className: "px-4 py-2.5 font-medium", children: nameHeader }),
4665
- /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", className: "px-4 py-2.5 font-medium", children: "Type" }),
4666
- hasDefault ? /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", className: "px-4 py-2.5 font-medium", children: "Default" }) : null,
4667
- /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", className: "px-4 py-2.5 font-medium", children: "Description" })
4668
- ] }) }),
4669
- /* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "divide-y divide-border", children: rows.map((r) => /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "align-top", children: [
4670
- /* @__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: [
4671
- /* @__PURE__ */ jsxRuntime.jsx("code", { className: cn("font-mono text-[0.8125rem] text-foreground", r.deprecated && "line-through decoration-oca-subtle"), children: r.name }),
4672
- marks(r)
4673
- ] }) }),
4674
- /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3 font-mono text-[0.8125rem] text-muted-foreground", children: r.type ?? "\u2014" }),
4675
- hasDefault ? /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3 font-mono text-[0.8125rem] text-muted-foreground", children: r.default ?? "\u2014" }) : null,
4676
- /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-4 py-3 leading-relaxed text-muted-foreground", children: r.description })
4677
- ] }, r.name)) })
4678
- ] }) }) }),
4679
- /* @__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: [
4680
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex flex-wrap items-baseline gap-x-2 gap-y-1", children: [
4681
- /* @__PURE__ */ jsxRuntime.jsx("code", { className: cn("font-mono text-[0.875rem] text-foreground", r.deprecated && "line-through decoration-oca-subtle"), children: r.name }),
4682
- r.type ? /* @__PURE__ */ jsxRuntime.jsx("code", { className: "break-all font-mono text-[0.8125rem] text-muted-foreground", children: r.type }) : null
4712
+ const wide = columns.length > 3;
4713
+ const grid = wide ? "lg:grid lg:grid-cols-[var(--oca-compare)]" : "md:grid md:grid-cols-[var(--oca-compare)]";
4714
+ const desk = wide ? "lg" : "md";
4715
+ const style = {
4716
+ // The argued-for column gets a little more room: its answers carry the page.
4717
+ "--oca-compare": ["minmax(0, 1.4fr)", ...columns.map((c) => c.highlight ? "minmax(0, 1.3fr)" : "minmax(0, 1fr)")].join(" ")
4718
+ };
4719
+ const ordered = [...columns].sort((a, b) => Number(Boolean(b.highlight)) - Number(Boolean(a.highlight)));
4720
+ 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: [
4721
+ /* @__PURE__ */ jsxRuntime.jsxs(
4722
+ "li",
4723
+ {
4724
+ "aria-hidden": true,
4725
+ className: cn(
4726
+ "hidden gap-5 px-5 py-4 text-[0.875rem] font-medium text-muted-foreground",
4727
+ wide ? "lg:grid lg:px-8" : "md:grid md:px-8",
4728
+ grid
4729
+ ),
4730
+ children: [
4731
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: propertyHeading }),
4732
+ 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))
4733
+ ]
4734
+ }
4735
+ ),
4736
+ 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: [
4737
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-col gap-1", children: [
4738
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "oca-title-sm", children: r.label }),
4739
+ r.note ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[0.875rem] leading-snug text-muted-foreground", children: r.note }) : null
4683
4740
  ] }),
4684
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex flex-wrap items-center gap-2 empty:hidden", children: marks(r) }),
4685
- r.description ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[0.875rem] leading-relaxed text-muted-foreground", children: r.description }) : null,
4686
- r.default !== void 0 ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-[0.8125rem] text-muted-foreground", children: [
4687
- "Default ",
4688
- /* @__PURE__ */ jsxRuntime.jsx("code", { className: "font-mono text-foreground", children: r.default })
4689
- ] }) : null
4690
- ] }, r.name)) })
4741
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("grid grid-cols-2 gap-1", desk === "lg" ? "lg:contents" : "md:contents"), children: columns.map((c) => {
4742
+ return /* @__PURE__ */ jsxRuntime.jsxs(
4743
+ "div",
4744
+ {
4745
+ style: { "--oca-order": ordered.indexOf(c) },
4746
+ className: cn(
4747
+ // Two rows of the pair's grid (name, answer), so answers line up
4748
+ // across a pair even when one name wraps.
4749
+ "order-[var(--oca-order)] row-span-2 grid min-w-0 grid-rows-subgrid gap-1 rounded-xl px-3 py-2.5",
4750
+ 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",
4751
+ c.highlight ? cn(
4752
+ TINT,
4753
+ "col-span-2",
4754
+ 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"
4755
+ ) : desk === "lg" ? "lg:p-0" : "md:p-0"
4756
+ ),
4757
+ children: [
4758
+ /* @__PURE__ */ jsxRuntime.jsx(
4759
+ "span",
4760
+ {
4761
+ className: cn(
4762
+ "text-[0.8125rem]",
4763
+ c.highlight ? "text-oca-accent-ink" : "text-muted-foreground",
4764
+ desk === "lg" ? "lg:sr-only" : "md:sr-only"
4765
+ ),
4766
+ children: c.label
4767
+ }
4768
+ ),
4769
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("text-[0.9375rem]", c.highlight && "font-medium"), children: r.values[c.key] ?? "\u2014" })
4770
+ ]
4771
+ },
4772
+ c.key
4773
+ );
4774
+ }) })
4775
+ ] }, ri))
4691
4776
  ] });
4692
4777
  }
4693
- function useDarkMode() {
4694
- const [dark, setDark] = react.useState(false);
4695
- react.useEffect(() => {
4696
- const root = document.documentElement;
4697
- const read = () => setDark(root.classList.contains("dark"));
4698
- read();
4699
- const mo = new MutationObserver(read);
4700
- mo.observe(root, { attributes: true, attributeFilter: ["class"] });
4701
- return () => mo.disconnect();
4702
- }, []);
4703
- return dark;
4704
- }
4705
- function mermaidTheme(el) {
4706
- const css = getComputedStyle(el);
4707
- const v = (name) => css.getPropertyValue(name).trim();
4708
- const card = v("--card");
4709
- const muted = v("--muted");
4710
- const text = v("--foreground");
4711
- const subtle = v("--muted-foreground");
4712
- const line = v("--input");
4713
- const hair = v("--oca-hairline-strong");
4714
- return {
4715
- background: "transparent",
4716
- fontFamily: css.fontFamily,
4717
- fontSize: "14px",
4718
- textColor: text,
4719
- mainBkg: card,
4720
- primaryColor: card,
4721
- primaryTextColor: text,
4722
- primaryBorderColor: hair,
4723
- secondaryColor: muted,
4724
- secondaryTextColor: text,
4725
- secondaryBorderColor: hair,
4726
- tertiaryColor: muted,
4727
- tertiaryTextColor: text,
4728
- tertiaryBorderColor: hair,
4729
- nodeBorder: hair,
4730
- lineColor: line,
4731
- edgeLabelBackground: card,
4732
- clusterBkg: muted,
4733
- clusterBorder: hair,
4734
- titleColor: text,
4735
- noteBkgColor: muted,
4736
- noteTextColor: text,
4737
- noteBorderColor: hair,
4738
- actorBkg: card,
4739
- actorBorder: hair,
4740
- actorTextColor: text,
4741
- actorLineColor: line,
4742
- signalColor: text,
4743
- signalTextColor: text,
4744
- labelBoxBkgColor: card,
4745
- labelBoxBorderColor: hair,
4746
- labelTextColor: text,
4747
- loopTextColor: subtle,
4748
- activationBkgColor: muted,
4749
- activationBorderColor: hair,
4750
- sequenceNumberColor: card
4751
- };
4752
- }
4753
- function naturalSize(svg) {
4754
- const w = svg.match(/viewBox="[\d.-]+ [\d.-]+ ([\d.]+) [\d.]+"/)?.[1];
4755
- if (!w) return svg;
4756
- return svg.replace(/<svg([^>]*?)\swidth="100%"/, `<svg$1 width="${Math.ceil(Number(w))}"`).replace(/max-width:\s*[\d.]+px;?/, "");
4757
- }
4758
- function Diagram({ chart, caption, load, className }) {
4759
- const ref = react.useRef(null);
4760
- const dark = useDarkMode();
4761
- const raw = react.useId();
4762
- const [svg, setSvg] = react.useState(null);
4763
- const [failed, setFailed] = react.useState(false);
4764
- react.useEffect(() => {
4765
- let live = true;
4766
- const el = ref.current;
4767
- if (!el) return;
4768
- (async () => {
4769
- try {
4770
- const mod = await load();
4771
- const mermaid = "default" in mod ? mod.default : mod;
4772
- mermaid.initialize({ startOnLoad: false, securityLevel: "strict", theme: "base", themeVariables: mermaidTheme(el) });
4773
- const { svg: drawn } = await mermaid.render(`oca-diagram-${raw.replace(/[^a-zA-Z0-9]/g, "")}-${dark ? "d" : "l"}`, chart);
4774
- if (live) {
4775
- setSvg(naturalSize(drawn));
4776
- setFailed(false);
4777
- }
4778
- } catch {
4779
- if (live) setFailed(true);
4780
- }
4781
- })();
4782
- return () => {
4783
- live = false;
4784
- };
4785
- }, [chart, dark, load, raw]);
4786
- if (failed) return /* @__PURE__ */ jsxRuntime.jsx(CodeBlock, { code: chart, caption: "Diagram (shown as its source)", className: cn("my-6", className) });
4787
- return /* @__PURE__ */ jsxRuntime.jsxs("figure", { ref, className: cn("not-prose my-6 overflow-hidden rounded-[1.25rem] border border-border bg-card", className), children: [
4788
- svg ? /* @__PURE__ */ jsxRuntime.jsx(ScrollFade, { fade: "var(--card)", children: /* @__PURE__ */ jsxRuntime.jsx(
4789
- "div",
4790
- {
4791
- className: "flex w-max min-w-full justify-center p-6 [&_svg]:h-auto [&_svg]:max-w-none",
4792
- role: "img",
4793
- "aria-label": typeof caption === "string" ? caption : "Diagram",
4794
- dangerouslySetInnerHTML: { __html: svg }
4795
- }
4796
- ) }) : /* @__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" }) }),
4797
- caption ? /* @__PURE__ */ jsxRuntime.jsx("figcaption", { className: "border-t border-border px-5 py-3 text-[0.8125rem] text-muted-foreground", children: caption }) : null
4798
- ] });
4799
- }
4800
- var HEADING = {
4801
- h1: "oca-display-3 mb-4 text-foreground",
4802
- h2: "mb-3 mt-12 text-[1.375rem] font-medium leading-tight tracking-[-0.015em] text-foreground md:text-[1.5rem]",
4803
- h3: "mb-2 mt-9 text-[1.125rem] font-medium leading-snug tracking-[-0.01em] text-foreground",
4804
- h4: "mb-2 mt-7 text-[1rem] font-medium leading-snug text-foreground"
4778
+ var CHECK = {
4779
+ ok: { word: "Passed", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CircleCheck, {}), tone: "text-success" },
4780
+ fail: { word: "Failed", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CircleX, {}), tone: "text-destructive" },
4781
+ pending: { word: "Pending", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Clock, {}), tone: "text-oca-accent-ink" },
4782
+ none: { word: "None", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CircleSlash, {}), tone: "text-muted-foreground" },
4783
+ skipped: { word: "Skipped", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CircleMinus, {}), tone: "text-muted-foreground" },
4784
+ unchecked: { word: "Not checked", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CircleDashed, {}), tone: "text-oca-subtle" }
4805
4785
  };
4806
- function DocsHeading({
4807
- as: Tag,
4808
- id,
4809
- children,
4810
- className,
4811
- ...props
4786
+ function VerifyReport({
4787
+ verdict,
4788
+ title,
4789
+ summary,
4790
+ checks,
4791
+ facts,
4792
+ notChecked,
4793
+ actions,
4794
+ as: Heading = "h2",
4795
+ className
4812
4796
  }) {
4813
- return /* @__PURE__ */ jsxRuntime.jsxs(Tag, { id, className: cn("group scroll-mt-28", HEADING[Tag], className), ...props, children: [
4814
- /* @__PURE__ */ jsxRuntime.jsx("span", { "data-heading-text": "", children }),
4815
- id && Tag !== "h1" ? /* @__PURE__ */ jsxRuntime.jsxs(
4816
- "a",
4797
+ return /* @__PURE__ */ jsxRuntime.jsxs(
4798
+ "section",
4799
+ {
4800
+ "aria-label": "Verification result",
4801
+ className: cn("overflow-hidden rounded-[1.25rem] border border-border bg-card", className),
4802
+ children: [
4803
+ /* @__PURE__ */ jsxRuntime.jsxs("header", { className: "flex flex-col items-start gap-3 p-6 md:p-8", children: [
4804
+ /* @__PURE__ */ jsxRuntime.jsx(StatusBadge, { status: verdict }),
4805
+ /* @__PURE__ */ jsxRuntime.jsx(Heading, { className: "oca-display-3 [overflow-wrap:anywhere]", children: title }),
4806
+ summary ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "oca-body max-w-[40rem] [overflow-wrap:anywhere]", children: summary }) : null
4807
+ ] }),
4808
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { "aria-label": "Checks", className: "divide-y divide-border border-t border-border", children: checks.map((c, i) => {
4809
+ const k = CHECK[c.state];
4810
+ return /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex items-start gap-3 px-6 py-3.5 md:px-8", children: [
4811
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: cn("mt-0.5 shrink-0 [&_svg]:size-[1.125rem]", k.tone), children: k.icon }),
4812
+ /* @__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: [
4813
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-col gap-0.5", children: [
4814
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[0.9375rem]", children: c.label }),
4815
+ c.note ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "break-words text-[0.8125rem] leading-snug text-muted-foreground", children: c.note }) : null
4816
+ ] }),
4817
+ /* @__PURE__ */ jsxRuntime.jsx(
4818
+ "span",
4819
+ {
4820
+ className: cn(
4821
+ "shrink-0 text-[0.8125rem]",
4822
+ c.state === "fail" ? "text-destructive" : "text-muted-foreground"
4823
+ ),
4824
+ children: k.word
4825
+ }
4826
+ )
4827
+ ] })
4828
+ ] }, i);
4829
+ }) }),
4830
+ 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,
4831
+ 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: [
4832
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[0.875rem] font-medium", children: "What this did not check" }),
4833
+ /* @__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)) })
4834
+ ] }) : null,
4835
+ 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
4836
+ ]
4837
+ }
4838
+ );
4839
+ }
4840
+ function SignMessage({
4841
+ lead,
4842
+ address,
4843
+ message,
4844
+ wallets,
4845
+ busy = false,
4846
+ error,
4847
+ submitLabel = "Confirm",
4848
+ secondary,
4849
+ onSignature,
4850
+ className
4851
+ }) {
4852
+ const [pasted, setPasted] = react.useState("");
4853
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-col gap-5", className), children: [
4854
+ lead ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[0.9375rem] leading-relaxed", children: lead }) : null,
4855
+ wallets ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4856
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-2", children: wallets }),
4857
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 text-[0.8125rem] text-muted-foreground", children: [
4858
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "h-px flex-1 bg-border" }),
4859
+ "or sign it in any wallet",
4860
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "h-px flex-1 bg-border" })
4861
+ ] })
4862
+ ] }) : null,
4863
+ /* @__PURE__ */ jsxRuntime.jsx(CodeBlock, { code: message, caption: "Message to sign" }),
4864
+ /* @__PURE__ */ jsxRuntime.jsxs(
4865
+ "form",
4817
4866
  {
4818
- href: `#${id}`,
4819
- 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",
4867
+ className: "flex flex-col gap-4",
4868
+ onSubmit: (e) => {
4869
+ e.preventDefault();
4870
+ if (pasted.trim()) onSignature(pasted.trim());
4871
+ },
4820
4872
  children: [
4821
- /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, children: "#" }),
4822
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Link to this section" })
4873
+ /* @__PURE__ */ jsxRuntime.jsx(
4874
+ Field,
4875
+ {
4876
+ label: "Signature",
4877
+ error,
4878
+ hint: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4879
+ "From your wallet\u2019s \u201Csign message\u201D (BIP-322), signed by",
4880
+ " ",
4881
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "break-all font-mono", children: address }),
4882
+ "."
4883
+ ] }),
4884
+ children: /* @__PURE__ */ jsxRuntime.jsx(
4885
+ Textarea,
4886
+ {
4887
+ value: pasted,
4888
+ onChange: (e) => setPasted(e.target.value),
4889
+ rows: 3,
4890
+ spellCheck: false,
4891
+ className: "min-h-24 font-mono text-base md:text-[0.8125rem]"
4892
+ }
4893
+ )
4894
+ }
4895
+ ),
4896
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-2", children: [
4897
+ /* @__PURE__ */ jsxRuntime.jsx(Button, { type: "submit", loading: busy, disabled: !pasted.trim(), children: submitLabel }),
4898
+ secondary
4899
+ ] })
4823
4900
  ]
4824
4901
  }
4825
- ) : null
4902
+ )
4826
4903
  ] });
4827
4904
  }
4828
- function codeText(node) {
4829
- if (typeof node === "string") return node;
4830
- if (typeof node === "number") return String(node);
4831
- if (Array.isArray(node)) return node.map(codeText).join("");
4832
- if (react.isValidElement(node)) return codeText(node.props.children);
4833
- return "";
4834
- }
4835
- function codeLang(node) {
4836
- const child = react.Children.toArray(node)[0];
4837
- if (!react.isValidElement(child)) return void 0;
4838
- const cls = child.props.className ?? "";
4839
- return cls.match(/language-([\w+-]+)/)?.[1];
4840
- }
4841
4905
  function useMacKeys() {
4842
4906
  const [mac, setMac] = react.useState(true);
4843
4907
  react.useEffect(() => {
@@ -5640,7 +5704,7 @@ function ToolGrid({
5640
5704
  ] }),
5641
5705
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1.5", children: [
5642
5706
  /* @__PURE__ */ jsxRuntime.jsx(Heading, { className: "oca-title-sm", children: /* @__PURE__ */ jsxRuntime.jsx(
5643
- Link8__default.default,
5707
+ Link6__default.default,
5644
5708
  {
5645
5709
  href: t.href,
5646
5710
  className: "outline-none after:absolute after:inset-0 after:rounded-[1.25rem] after:content-['']",
@@ -5733,813 +5797,861 @@ function FamilyMenu({ current: current2, className }) {
5733
5797
  )
5734
5798
  ] });
5735
5799
  }
5736
- function NavLink({
5737
- item,
5738
- className,
5739
- onNavigate,
5740
- line = false
5800
+ function SideNav({ groups, onNavigate }) {
5801
+ return /* @__PURE__ */ jsxRuntime.jsx("nav", { "aria-label": "Pages", className: "flex flex-col gap-5", children: groups.map((g, gi) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-0.5", children: [
5802
+ g.label ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "px-3 pb-1 text-[0.8125rem] text-muted-foreground", children: g.label }) : null,
5803
+ g.items.map((it) => /* @__PURE__ */ jsxRuntime.jsxs(
5804
+ Link6__default.default,
5805
+ {
5806
+ href: it.href,
5807
+ onClick: onNavigate,
5808
+ "aria-current": it.active ? "page" : void 0,
5809
+ className: cn(
5810
+ "flex h-9 items-center gap-3 rounded-xl px-3 text-[0.9375rem] transition-colors",
5811
+ "[&_svg]:size-[1.0625rem] [&_svg]:shrink-0",
5812
+ it.active ? "bg-card text-foreground shadow-sm ring-1 ring-border [&_svg]:text-foreground" : "text-muted-foreground hover:bg-accent hover:text-foreground"
5813
+ ),
5814
+ children: [
5815
+ it.icon,
5816
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate", children: it.label }),
5817
+ it.badge ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0", children: it.badge }) : null
5818
+ ]
5819
+ },
5820
+ it.href
5821
+ ))
5822
+ ] }, g.label ?? gi)) });
5823
+ }
5824
+ function SectionSwitch({
5825
+ sections,
5826
+ current: current2,
5827
+ onNavigate
5741
5828
  }) {
5742
- const cls = cn(
5743
- "rounded-full px-3 py-2 text-[0.9375rem] transition-colors",
5744
- item.active ? "text-foreground" : "text-muted-foreground hover:text-foreground",
5745
- line && "relative after:absolute after:inset-x-3 after:-bottom-[0.625rem] after:h-0.5 after:rounded-full",
5746
- line && item.active && "after:bg-foreground",
5747
- className
5748
- );
5749
- if (item.external) {
5750
- return /* @__PURE__ */ jsxRuntime.jsx("a", { href: item.href, className: cls, rel: "noreferrer", onClick: onNavigate, children: item.label });
5751
- }
5752
- return /* @__PURE__ */ jsxRuntime.jsx(Link8__default.default, { href: item.href, className: cls, "aria-current": item.active ? "page" : void 0, onClick: onNavigate, children: item.label });
5753
- }
5754
- function NavRow({ item, onNavigate }) {
5755
- const body = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
5756
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[0.9375rem] font-medium leading-6 text-foreground", children: item.label }),
5757
- item.description ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[0.8125rem] leading-snug text-muted-foreground", children: item.description }) : null
5758
- ] });
5759
- const cls = cn(
5760
- "flex flex-col gap-0.5 rounded-xl px-3 py-2 transition-colors hover:bg-accent",
5761
- item.active && "bg-muted hover:bg-muted dark:bg-white/[0.06]"
5829
+ const cols = sections.length <= 3 ? sections.length : 2;
5830
+ return /* @__PURE__ */ jsxRuntime.jsx(
5831
+ "nav",
5832
+ {
5833
+ "aria-label": "Sections",
5834
+ className: cn("grid gap-1 bg-muted p-1", cols === sections.length ? "rounded-full" : "rounded-[1.25rem]"),
5835
+ style: { gridTemplateColumns: `repeat(${cols}, minmax(0, 1fr))` },
5836
+ children: sections.map((sec) => {
5837
+ const on = sec.id === current2.id;
5838
+ return /* @__PURE__ */ jsxRuntime.jsx(
5839
+ Link6__default.default,
5840
+ {
5841
+ href: sec.href,
5842
+ onClick: onNavigate,
5843
+ "aria-current": on ? "true" : void 0,
5844
+ className: cn(
5845
+ "flex h-8 min-w-0 items-center justify-center rounded-full px-1.5 text-[0.8125rem] font-medium transition-colors",
5846
+ on ? "bg-card text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"
5847
+ ),
5848
+ children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: sec.label })
5849
+ },
5850
+ sec.id
5851
+ );
5852
+ })
5853
+ }
5762
5854
  );
5763
- return item.external ? /* @__PURE__ */ jsxRuntime.jsx("a", { href: item.href, className: cls, rel: "noreferrer", onClick: onNavigate, children: body }) : /* @__PURE__ */ jsxRuntime.jsx(Link8__default.default, { href: item.href, className: cls, "aria-current": item.active ? "page" : void 0, onClick: onNavigate, children: body });
5764
- }
5765
- var seeAll = (item) => typeof item.label === "string" ? `All ${item.label.toLowerCase()}` : "See all";
5766
- function NavDropdown({ item }) {
5767
- const [open, setOpen] = react.useState(false);
5768
- const active = item.active || item.children?.some((c) => c.active);
5769
- return /* @__PURE__ */ jsxRuntime.jsxs(Popover, { open, onOpenChange: setOpen, children: [
5770
- /* @__PURE__ */ jsxRuntime.jsxs(
5771
- PopoverTrigger,
5772
- {
5773
- className: cn(
5774
- "group inline-flex items-center gap-1 rounded-full py-2 pl-3 pr-2.5 text-[0.9375rem] transition-colors md:max-lg:pl-2.5 md:max-lg:pr-2",
5775
- active ? "text-foreground" : "text-muted-foreground hover:text-foreground data-[state=open]:text-foreground"
5776
- ),
5777
- children: [
5778
- item.label,
5779
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { "aria-hidden": true, className: "size-3.5 transition-transform duration-200 group-data-[state=open]:rotate-180" })
5780
- ]
5781
- }
5782
- ),
5783
- /* @__PURE__ */ jsxRuntime.jsxs(PopoverContent, { align: "center", sideOffset: 10, className: "w-[min(calc(100vw-2rem),26rem)] p-2", children: [
5784
- /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "flex flex-col", children: item.children?.map((c) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx(NavRow, { item: c, onNavigate: () => setOpen(false) }) }, c.href)) }),
5785
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1.5 border-t border-border px-1 pt-1.5", children: /* @__PURE__ */ jsxRuntime.jsx(
5786
- NavLink,
5787
- {
5788
- item: { ...item, label: seeAll(item), children: void 0 },
5789
- className: "block rounded-xl px-2 py-2 text-[0.875rem]",
5790
- onNavigate: () => setOpen(false)
5791
- }
5792
- ) })
5793
- ] })
5794
- ] });
5795
5855
  }
5796
- function SiteHeader({
5797
- home = "/",
5798
- brand,
5799
- product,
5800
- family,
5801
- nav = [],
5802
- search,
5803
- actions,
5804
- variant = "site",
5805
- navOnPhone = true,
5806
- menu: menuExtra,
5807
- className
5808
- }) {
5809
- const [open, setOpen] = react.useState(false);
5810
- const tool = variant === "tool";
5811
- const size = tool ? 24 : 28;
5812
- const current2 = typeof family === "string" ? family : void 0;
5813
- const phoneNav = navOnPhone ? nav : [];
5814
- const menu = phoneNav.length > 0 || Boolean(family) || Boolean(menuExtra);
5815
- const brandNode = brand ?? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center", children: [
5816
- /* @__PURE__ */ jsxRuntime.jsx(Lockup, { size }),
5817
- product ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
5818
- /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: "mx-3 h-5 w-px bg-oca-hairline-strong" }),
5819
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium tracking-[-0.01em]", style: { fontSize: size * 0.56 }, children: product })
5820
- ] }) : null
5821
- ] });
5822
- const navigation = nav.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("nav", { "aria-label": "Main", className: "hidden items-center gap-1 md:flex", children: nav.map(
5823
- (n) => n.children?.length ? /* @__PURE__ */ jsxRuntime.jsx(NavDropdown, { item: n }, n.href) : (
5824
- // Between md and lg the family menu and the actions share the row: tighter.
5825
- /* @__PURE__ */ jsxRuntime.jsx(NavLink, { item: n, line: tool, className: tool ? void 0 : "md:max-lg:px-2.5" }, n.href)
5826
- )
5827
- ) }) : null;
5856
+ function TabBar({ items }) {
5828
5857
  return /* @__PURE__ */ jsxRuntime.jsx(
5829
- "header",
5858
+ "nav",
5830
5859
  {
5831
- className: cn(
5832
- "sticky top-0 z-40 w-full border-b bg-background/95 backdrop-blur-md supports-[backdrop-filter]:bg-background/90",
5833
- tool ? "border-border" : "border-transparent",
5834
- className
5835
- ),
5836
- children: /* @__PURE__ */ jsxRuntime.jsxs(
5860
+ "aria-label": "Pages",
5861
+ "data-oca-tabbar": "",
5862
+ className: "fixed inset-x-0 bottom-0 z-40 border-t border-border bg-background/90 pb-[env(safe-area-inset-bottom)] backdrop-blur-md md:hidden",
5863
+ children: /* @__PURE__ */ jsxRuntime.jsx(
5837
5864
  "div",
5838
5865
  {
5839
- className: cn(
5840
- "flex items-center justify-between gap-4",
5841
- tool ? "h-14 px-4 md:px-6" : "oca-container h-16 md:h-[4.5rem] md:max-lg:gap-2",
5842
- // Three columns, the outer two each at least their content: the
5843
- // navigation stays centred whatever the actions hold, so it does
5844
- // not shift when they change (signed out to signed in).
5845
- !tool && nav.length > 0 && "md:grid md:grid-cols-[minmax(max-content,1fr)_auto_minmax(max-content,1fr)]"
5846
- ),
5847
- children: [
5848
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex min-w-0 items-center gap-1", tool ? "md:gap-1" : "justify-self-start"), children: [
5849
- /* @__PURE__ */ jsxRuntime.jsxs(Link8__default.default, { href: home, className: "-ml-1 min-w-0 rounded-lg p-1", children: [
5850
- brandNode,
5851
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: " home" })
5852
- ] }),
5853
- family ? /* @__PURE__ */ jsxRuntime.jsx(FamilyMenu, { current: current2, className: "max-md:hidden" }) : null,
5854
- tool && navigation ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ml-5", children: navigation }) : null
5855
- ] }),
5856
- !tool ? navigation : null,
5857
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 justify-self-end", children: [
5858
- search,
5859
- actions,
5860
- menu ? /* @__PURE__ */ jsxRuntime.jsxs(Sheet, { open, onOpenChange: setOpen, children: [
5861
- /* @__PURE__ */ jsxRuntime.jsx(
5862
- SheetTrigger,
5866
+ className: "mx-auto grid h-14 max-w-[32rem] px-1.5",
5867
+ style: { gridTemplateColumns: `repeat(${items.length}, minmax(0, 1fr))` },
5868
+ children: items.map((it) => /* @__PURE__ */ jsxRuntime.jsxs(
5869
+ Link6__default.default,
5870
+ {
5871
+ href: it.href,
5872
+ "aria-current": it.active ? "page" : void 0,
5873
+ className: cn(
5874
+ "flex min-w-0 flex-col items-center justify-center gap-1 rounded-2xl text-[0.6875rem] leading-none outline-none transition-colors [-webkit-tap-highlight-color:transparent] focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring",
5875
+ it.active ? "text-foreground" : "text-muted-foreground hover:text-foreground"
5876
+ ),
5877
+ children: [
5878
+ /* @__PURE__ */ jsxRuntime.jsxs(
5879
+ "span",
5863
5880
  {
5864
- className: "inline-flex size-10 items-center justify-center rounded-full text-foreground hover:bg-accent md:hidden",
5865
- "aria-label": "Open menu",
5866
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Menu, { className: "size-5" })
5881
+ className: cn(
5882
+ "relative flex h-7 w-12 items-center justify-center rounded-full transition-[background-color,box-shadow] duration-200",
5883
+ "[&_svg]:size-[1.125rem] [&_svg]:shrink-0",
5884
+ it.active ? "bg-card shadow-sm ring-1 ring-border [&_svg]:stroke-2" : "[&_svg]:stroke-[1.75]"
5885
+ ),
5886
+ children: [
5887
+ it.icon,
5888
+ it.badge ? /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: "absolute right-2.5 top-0.5 size-2 rounded-full bg-oca-orange ring-2 ring-background" }) : null
5889
+ ]
5867
5890
  }
5868
5891
  ),
5869
- /* @__PURE__ */ jsxRuntime.jsxs(SheetContent, { side: "right", className: "pt-16", children: [
5870
- /* @__PURE__ */ jsxRuntime.jsx(SheetTitle, { className: "sr-only", children: "Menu" }),
5871
- menuExtra ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex flex-col", (phoneNav.length > 0 || family) && "border-b border-border pb-3"), children: menuExtra }) : null,
5872
- phoneNav.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("nav", { "aria-label": "Main", className: "flex flex-col", children: phoneNav.map(
5873
- (n) => n.children?.length ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col py-2", children: [
5874
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "px-3 pb-1 text-[0.8125rem] text-muted-foreground", children: n.label }),
5875
- n.children.map((c) => /* @__PURE__ */ jsxRuntime.jsx(
5876
- NavLink,
5877
- {
5878
- item: c,
5879
- className: "rounded-xl px-3 py-2.5 text-[1.0625rem]",
5880
- onNavigate: () => setOpen(false)
5881
- },
5882
- c.href
5883
- ))
5884
- ] }, n.href) : /* @__PURE__ */ jsxRuntime.jsx(
5885
- NavLink,
5886
- {
5887
- item: n,
5888
- className: "rounded-xl px-3 py-3 text-[1.0625rem]",
5889
- onNavigate: () => setOpen(false)
5890
- },
5891
- n.href
5892
- )
5893
- ) }) : null,
5894
- family ? /* @__PURE__ */ jsxRuntime.jsxs("details", { className: cn("group", phoneNav.length > 0 && "mt-2 border-t border-border pt-4"), children: [
5895
- /* @__PURE__ */ jsxRuntime.jsxs("summary", { className: "flex cursor-pointer list-none items-center justify-between rounded-xl px-3 py-2.5 text-[1.0625rem] [&::-webkit-details-marker]:hidden", children: [
5896
- "All orangecheck sites",
5897
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { "aria-hidden": true, className: "size-4 text-muted-foreground transition-transform group-open:rotate-180" })
5898
- ] }),
5899
- /* @__PURE__ */ jsxRuntime.jsx(FamilyList, { current: current2, onNavigate: () => setOpen(false), stack: true, className: "mt-2" })
5900
- ] }) : null
5901
- ] })
5902
- ] }) : null
5903
- ] })
5904
- ]
5892
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "max-w-full truncate px-0.5", children: it.label }),
5893
+ it.badge ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: it.badge }) : null
5894
+ ]
5895
+ },
5896
+ it.href
5897
+ ))
5905
5898
  }
5906
5899
  )
5907
5900
  }
5908
5901
  );
5909
5902
  }
5910
- function SkipLink({ href = "#main-content", children = "Skip to content" }) {
5911
- return /* @__PURE__ */ jsxRuntime.jsx(
5912
- "a",
5913
- {
5914
- href,
5915
- className: "sr-only focus:not-sr-only focus:fixed focus:left-4 focus:top-3 focus:z-50 focus:rounded-full focus:border focus:border-border focus:bg-card focus:px-4 focus:py-2 focus:text-[0.9375rem] focus:font-medium focus:text-foreground focus:shadow-md",
5916
- children
5903
+ function tabsFor(groups) {
5904
+ const items = groups.flatMap((g) => g.items);
5905
+ return items.length >= 2 && items.length <= 5 && items.every((it) => it.icon) ? items : null;
5906
+ }
5907
+ var activeItem = (groups) => groups.flatMap((g) => g.items).find((it) => it.active);
5908
+ var warned = /* @__PURE__ */ new Set();
5909
+ function warnDuplicateLabels(groups) {
5910
+ if (typeof process === "undefined" || process.env.NODE_ENV === "production") return;
5911
+ const seen = /* @__PURE__ */ new Set();
5912
+ for (const it of groups.flatMap((g) => g.items)) {
5913
+ if (seen.has(it.label) && !warned.has(it.label)) {
5914
+ warned.add(it.label);
5915
+ console.warn(`AppShell: two pages are labelled "${it.label}"; give each its own name.`);
5917
5916
  }
5918
- );
5917
+ seen.add(it.label);
5918
+ }
5919
5919
  }
5920
- var BANNER_TONE = {
5921
- neutral: "border-border bg-muted",
5922
- brand: "border-[color-mix(in_oklab,var(--oca-orange)_30%,var(--border))] bg-[color-mix(in_oklab,var(--oca-orange)_9%,var(--background))]",
5923
- danger: "border-[color-mix(in_oklab,var(--destructive)_35%,var(--border))] bg-[color-mix(in_oklab,var(--destructive)_8%,var(--background))]"
5924
- };
5925
- function SiteBanner({
5926
- tone = "neutral",
5920
+ function AppShell({
5921
+ nav,
5922
+ sections,
5923
+ activeSection,
5924
+ page: pageOverride,
5925
+ persistent = [],
5926
+ home = "/",
5927
+ family,
5928
+ account,
5929
+ banner,
5930
+ footer,
5927
5931
  children,
5928
- action,
5929
5932
  className
5930
5933
  }) {
5931
- return /* @__PURE__ */ jsxRuntime.jsx("div", { role: "status", "aria-live": "polite", "data-tone": tone, className: cn("border-b text-[0.875rem]", BANNER_TONE[tone], className), children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "oca-container flex flex-wrap items-center justify-between gap-x-4 gap-y-1 py-2.5", children: [
5932
- /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "flex min-w-0 items-baseline gap-2.5 leading-snug", children: [
5933
- tone !== "neutral" ? /* @__PURE__ */ jsxRuntime.jsx(
5934
- "span",
5935
- {
5936
- "aria-hidden": true,
5937
- className: cn(
5938
- "size-2 shrink-0 translate-y-[-0.05em] rounded-full",
5939
- tone === "brand" ? "bg-oca-orange" : "bg-destructive"
5940
- )
5941
- }
5942
- ) : null,
5943
- /* @__PURE__ */ jsxRuntime.jsx("span", { children })
5944
- ] }),
5945
- action ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("shrink-0 font-medium", tone !== "neutral" && "max-sm:pl-[1.125rem]"), children: action }) : null
5946
- ] }) });
5947
- }
5948
- var FOOT_LINK = "inline-flex min-h-11 items-center transition-colors hover:text-foreground md:min-h-0";
5949
- function LegalRow({ links }) {
5950
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-x-6 gap-y-2 sm:flex-row sm:items-center sm:justify-between", children: [
5951
- /* @__PURE__ */ jsxRuntime.jsx("nav", { "aria-label": "Legal", children: /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "flex flex-wrap gap-x-5", children: links.map((l) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: l.href.startsWith("/") ? /* @__PURE__ */ jsxRuntime.jsx(Link8__default.default, { href: l.href, className: FOOT_LINK, children: l.label }) : /* @__PURE__ */ jsxRuntime.jsx("a", { href: l.href, className: FOOT_LINK, children: l.label }) }, l.href)) }) }),
5952
- /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
5953
- "\xA9 ",
5954
- (/* @__PURE__ */ new Date()).getFullYear(),
5955
- " OrangeCheck"
5956
- ] })
5957
- ] });
5958
- }
5959
- function SiteFooter({
5960
- columns = [],
5961
- family = false,
5962
- legal = false,
5963
- compact = false,
5964
- fineprint,
5965
- meta,
5966
- signature = true,
5967
- className
5968
- }) {
5969
- const legalLinks = legal === true ? LEGAL_LINKS : legal || null;
5970
- if (compact) {
5971
- return /* @__PURE__ */ jsxRuntime.jsx("footer", { className: cn("border-t border-border bg-background text-[0.875rem] text-muted-foreground", className), children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "oca-container flex flex-col gap-x-8 gap-y-3 py-5 lg:flex-row lg:items-center lg:justify-between", children: [
5972
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-x-6 gap-y-1", children: [
5973
- /* @__PURE__ */ jsxRuntime.jsx("a", { href: OCHK_IO, className: "rounded-lg text-foreground", children: /* @__PURE__ */ jsxRuntime.jsx(Lockup, { size: 22 }) }),
5974
- family ? /* @__PURE__ */ jsxRuntime.jsx("nav", { "aria-label": "Protocols", children: /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "flex flex-wrap gap-x-4", children: PROTOCOLS.map((p) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx("a", { href: p.pageHref, className: FOOT_LINK, children: p.label }) }, p.slug)) }) }) : null
5975
- ] }),
5976
- legalLinks || meta ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-x-6 gap-y-2 sm:flex-row sm:flex-wrap sm:items-center", children: [
5977
- legalLinks ? /* @__PURE__ */ jsxRuntime.jsx(LegalRow, { links: legalLinks }) : null,
5978
- meta
5979
- ] }) : null
5980
- ] }) });
5981
- }
5982
- const cols = [
5983
- ...columns,
5984
- ...family ? familyByGroup().map((g) => ({
5985
- // The lockup above already says orangecheck.
5986
- heading: g.id === "orangecheck" ? "Start here" : g.label,
5987
- links: g.sites.map((s) => ({ href: s.href, label: s.label, external: true }))
5988
- })) : []
5989
- ];
5990
- const n = cols.length;
5991
- const inline = n <= 5;
5992
- const grid = {
5993
- "--oca-footer-md": `repeat(${Math.max(1, Math.min(n, 4))}, minmax(0, 1fr))`,
5994
- "--oca-footer-lg": inline ? `minmax(0, 1.3fr) repeat(${Math.max(1, n)}, minmax(0, 1fr))` : `repeat(${Math.min(n, 6)}, minmax(0, 1fr))`
5995
- };
5996
- return /* @__PURE__ */ jsxRuntime.jsxs("footer", { className: cn("border-t border-border bg-background", className), children: [
5997
- /* @__PURE__ */ jsxRuntime.jsxs(
5998
- "div",
5999
- {
6000
- style: grid,
6001
- className: "oca-container grid grid-cols-2 gap-x-6 gap-y-10 py-14 md:grid-cols-[var(--oca-footer-md)] md:py-16 lg:grid-cols-[var(--oca-footer-lg)]",
6002
- children: [
6003
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("col-span-full flex flex-col gap-4", inline && "lg:col-span-1"), children: [
6004
- /* @__PURE__ */ jsxRuntime.jsx(Lockup, { size: 26 }),
6005
- fineprint ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "max-w-xs text-[0.9375rem] leading-relaxed text-muted-foreground", children: fineprint }) : null
6006
- ] }),
6007
- cols.map((col, i) => {
6008
- const spans = n % 2 === 1 && i === n - 1;
6009
- return /* @__PURE__ */ jsxRuntime.jsxs(
6010
- "div",
6011
- {
6012
- className: cn("flex min-w-0 flex-col gap-1", spans && "col-span-2 md:col-span-1"),
6013
- children: [
6014
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mb-2 text-[0.875rem] font-medium", children: col.heading }),
6015
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex flex-col gap-1", spans && "grid grid-cols-2 gap-x-6 md:flex md:flex-col"), children: col.links.map((l) => /* @__PURE__ */ jsxRuntime.jsx(
6016
- NavLink,
6017
- {
6018
- item: l,
6019
- className: "-mx-3 py-2.5 text-[0.9375rem] md:py-1.5"
6020
- },
6021
- l.href
6022
- )) })
6023
- ]
6024
- },
6025
- col.heading
6026
- );
6027
- })
6028
- ]
6029
- }
6030
- ),
6031
- signature ? /* @__PURE__ */ jsxRuntime.jsx("div", { "aria-hidden": true, className: "oca-container select-none overflow-hidden pb-8 md:pb-12", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-end gap-[0.18em] text-[clamp(3rem,11.5vw,10rem)] leading-[0.78] tracking-[-0.065em] [font-family:var(--oc-font-display)]", children: [
6032
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mb-[0.06em] inline-block w-[1.1em] shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(Mark, { className: "block h-auto w-full" }) }),
6033
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: "orangecheck" })
6034
- ] }) }) : null,
6035
- legalLinks || meta ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "oca-container", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3 border-t border-border py-6 text-[0.875rem] text-muted-foreground", children: [
6036
- legalLinks ? /* @__PURE__ */ jsxRuntime.jsx(LegalRow, { links: legalLinks }) : null,
6037
- meta
6038
- ] }) }) : null
6039
- ] });
6040
- }
6041
- function SignInFrame({
6042
- title = "Sign in",
6043
- lead,
6044
- children,
6045
- error,
6046
- fineprint,
6047
- brand,
6048
- home = "/",
6049
- back,
6050
- art,
6051
- caption,
6052
- className
6053
- }) {
6054
- return /* @__PURE__ */ jsxRuntime.jsxs(
6055
- "main",
5934
+ const [open, setOpen] = react.useState(false);
5935
+ const current2 = sections && sections.length > 0 ? sections.find((sec) => sec.id === activeSection) ?? sections.find((sec) => activeItem(sec.groups)) ?? sections[0] : void 0;
5936
+ const groups = current2 ? [...current2.groups, ...persistent] : [...nav ?? [], ...persistent];
5937
+ warnDuplicateLabels(groups);
5938
+ const tabs = current2 ? null : tabsFor(groups);
5939
+ const page = activeItem(groups);
5940
+ const place = react.useMemo(
5941
+ () => ({
5942
+ section: current2 ? current2.title ?? current2.label : void 0,
5943
+ page: pageOverride ?? page?.label
5944
+ }),
5945
+ [current2, page?.label, pageOverride]
5946
+ );
5947
+ const familyMenu = family ? /* @__PURE__ */ jsxRuntime.jsx(FamilyMenu, { current: typeof family === "string" ? family : void 0 }) : null;
5948
+ const switcher = sections && current2 && sections.length > 1 ? /* @__PURE__ */ jsxRuntime.jsx(SectionSwitch, { sections, current: current2, onNavigate: () => setOpen(false) }) : null;
5949
+ return /* @__PURE__ */ jsxRuntime.jsx(ShellContext.Provider, { value: place, children: /* @__PURE__ */ jsxRuntime.jsxs(
5950
+ "div",
6056
5951
  {
6057
- id: "main-content",
6058
- className: cn("grid min-h-dvh grid-cols-1 bg-background text-foreground lg:grid-cols-2", className),
5952
+ className: cn(
5953
+ "min-h-dvh bg-background",
5954
+ tabs && "max-md:pb-[calc(3.5rem_+_env(safe-area-inset-bottom))]",
5955
+ className
5956
+ ),
6059
5957
  children: [
6060
- /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "flex flex-col px-4 pb-8 pt-5 sm:px-8 lg:px-14 lg:pt-8", children: [
6061
- /* @__PURE__ */ jsxRuntime.jsxs("header", { className: "flex items-center justify-between gap-4", children: [
6062
- /* @__PURE__ */ jsxRuntime.jsxs(Link8__default.default, { href: home, className: "w-fit rounded-lg", children: [
6063
- brand ?? /* @__PURE__ */ jsxRuntime.jsx(Lockup, { size: 28 }),
6064
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: " home" })
5958
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sticky top-0 z-40 border-b border-border bg-background/90 backdrop-blur-md lg:hidden", children: [
5959
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-14 items-center gap-2 px-3", children: [
5960
+ /* @__PURE__ */ jsxRuntime.jsxs(Sheet, { open, onOpenChange: setOpen, children: [
5961
+ /* @__PURE__ */ jsxRuntime.jsx(
5962
+ SheetTrigger,
5963
+ {
5964
+ className: cn(
5965
+ "inline-flex size-10 items-center justify-center rounded-full hover:bg-accent",
5966
+ // The tab bar holds every page; the sheet is left for a footer.
5967
+ tabs && !footer && "max-md:hidden"
5968
+ ),
5969
+ "aria-label": "Open navigation",
5970
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Menu, { className: "size-5" })
5971
+ }
5972
+ ),
5973
+ /* @__PURE__ */ jsxRuntime.jsxs(SheetContent, { side: "left", className: "flex flex-col gap-6 overflow-y-auto p-4 pt-16", children: [
5974
+ /* @__PURE__ */ jsxRuntime.jsx(SheetTitle, { className: "sr-only", children: "Navigation" }),
5975
+ switcher,
5976
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: tabs ? "max-md:hidden" : void 0, children: /* @__PURE__ */ jsxRuntime.jsx(SideNav, { groups, onNavigate: () => setOpen(false) }) }),
5977
+ footer ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-auto flex flex-col gap-3", children: footer }) : null
5978
+ ] })
6065
5979
  ] }),
6066
- back === void 0 ? /* @__PURE__ */ jsxRuntime.jsx(
6067
- Link8__default.default,
6068
- {
6069
- href: home,
6070
- className: "text-[0.9375rem] text-muted-foreground underline-offset-4 hover:text-foreground hover:underline",
6071
- children: "Back to home"
6072
- }
6073
- ) : back
5980
+ /* @__PURE__ */ jsxRuntime.jsx(Link6__default.default, { href: home, "aria-label": "Home", className: "rounded-lg p-1", children: /* @__PURE__ */ jsxRuntime.jsx(Lockup, { size: 22 }) }),
5981
+ familyMenu,
5982
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ml-auto flex items-center", children: account })
6074
5983
  ] }),
6075
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mx-auto flex w-full max-w-[25rem] flex-1 flex-col justify-center gap-9 py-12", children: [
6076
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3", children: [
6077
- /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "oca-display-2", children: title }),
6078
- lead ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "oca-lead", children: lead }) : null
5984
+ place.page ? /* @__PURE__ */ jsxRuntime.jsxs(
5985
+ "div",
5986
+ {
5987
+ className: cn(
5988
+ "flex h-9 items-center gap-1.5 border-t border-border px-4 text-[0.875rem]",
5989
+ // The active tab already names the page.
5990
+ tabs && !pageOverride && "max-md:hidden"
5991
+ ),
5992
+ children: [
5993
+ place.section ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
5994
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 text-muted-foreground", children: place.section }),
5995
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { "aria-hidden": true, className: "size-3.5 shrink-0 text-muted-foreground" })
5996
+ ] }) : null,
5997
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate font-medium", children: place.page })
5998
+ ]
5999
+ }
6000
+ ) : null
6001
+ ] }),
6002
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mx-auto flex w-full max-w-[90rem]", children: [
6003
+ /* @__PURE__ */ jsxRuntime.jsxs("aside", { className: "sticky top-0 hidden h-dvh w-[17rem] shrink-0 flex-col gap-6 overflow-y-auto px-4 py-6 lg:flex", children: [
6004
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
6005
+ /* @__PURE__ */ jsxRuntime.jsx(Link6__default.default, { href: home, className: "px-2", "aria-label": "Home", children: /* @__PURE__ */ jsxRuntime.jsx(Lockup, { size: 26 }) }),
6006
+ familyMenu
6079
6007
  ] }),
6080
- /* @__PURE__ */ jsxRuntime.jsx("div", { children }),
6081
- error ? /* @__PURE__ */ jsxRuntime.jsx("p", { role: "alert", className: "text-[0.9375rem] text-destructive", children: error }) : null,
6082
- fineprint ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[0.8125rem] leading-relaxed text-muted-foreground", children: fineprint }) : null
6008
+ switcher,
6009
+ /* @__PURE__ */ jsxRuntime.jsx(SideNav, { groups }),
6010
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-auto flex flex-col gap-3", children: footer })
6011
+ ] }),
6012
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-1 flex-col", children: [
6013
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden h-[4.5rem] items-center justify-end gap-3 px-8 lg:flex", children: account }),
6014
+ banner ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 pb-2 pt-4 md:px-8 lg:pt-0", children: banner }) : null,
6015
+ /* @__PURE__ */ jsxRuntime.jsx("main", { id: "main-content", className: "flex-1 px-4 pb-16 pt-6 md:px-8 lg:pt-2", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-auto w-full max-w-[72rem]", children }) })
6083
6016
  ] })
6084
6017
  ] }),
6085
- /* @__PURE__ */ jsxRuntime.jsxs(
6086
- "aside",
6087
- {
6088
- "aria-hidden": true,
6089
- className: "relative hidden flex-col justify-between gap-10 overflow-hidden border-l border-[var(--oca-band-line)] bg-oca-ink p-14 text-oca-ink-foreground lg:flex",
6090
- children: [
6091
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-1 items-center justify-center", children: art ?? /* @__PURE__ */ jsxRuntime.jsx(IsoCheck, { size: 340, settle: true, tilt: true, className: "max-w-full" }) }),
6092
- caption ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex max-w-[24rem] flex-col gap-3", children: caption }) : null
6093
- ]
6094
- }
6095
- )
6018
+ tabs ? /* @__PURE__ */ jsxRuntime.jsx(TabBar, { items: tabs }) : null
6096
6019
  ]
6097
6020
  }
6098
- );
6021
+ ) });
6099
6022
  }
6100
- var STATUS_WORDS = /* @__PURE__ */ new Set(["live", "testing", "not-yet", "paused", "good", "caution", "refused"]);
6101
- var pathOf = (href) => href.split(/[?#]/)[0].replace(/(.)\/$/, "$1");
6102
- function DocsNav({
6103
- sections,
6104
- current: current2,
6105
- onNavigate,
6106
- className
6023
+ function AccountMenu({
6024
+ name,
6025
+ detail,
6026
+ items,
6027
+ nameFrom = "sm"
6107
6028
  }) {
6108
- const here = pathOf(current2);
6109
- const activeSection = react.useMemo(
6110
- () => sections.findIndex((s) => s.items.some((i) => pathOf(i.href) === here)),
6111
- [sections, here]
6112
- );
6113
- const [peeked, setPeeked] = react.useState(() => /* @__PURE__ */ new Set());
6114
- react.useEffect(() => setPeeked(/* @__PURE__ */ new Set()), [activeSection]);
6115
- const activeRef = react.useRef(null);
6116
- react.useEffect(() => {
6117
- const id = requestAnimationFrame(() => activeRef.current?.scrollIntoView({ block: "nearest" }));
6118
- return () => cancelAnimationFrame(id);
6119
- }, [here]);
6120
- const base = react.useId();
6121
- return /* @__PURE__ */ jsxRuntime.jsx("nav", { "aria-label": "Docs", className: cn("flex flex-col gap-0.5", className), children: sections.map((section, si) => {
6122
- const isActive = si === activeSection;
6123
- const open = isActive || peeked.has(si);
6124
- const panel = `${base}-s${si}`;
6125
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
6126
- /* @__PURE__ */ jsxRuntime.jsxs(
6127
- "button",
6128
- {
6129
- type: "button",
6130
- "aria-expanded": open,
6131
- "aria-controls": panel,
6132
- onClick: () => {
6133
- if (isActive) return;
6134
- setPeeked((p) => {
6135
- const n = new Set(p);
6136
- if (n.has(si)) n.delete(si);
6137
- else n.add(si);
6138
- return n;
6139
- });
6140
- },
6141
- className: cn(
6142
- "flex min-h-9 w-full items-center justify-between gap-2 rounded-lg px-2.5 py-1.5 text-left text-[0.875rem] transition-colors",
6143
- isActive ? "font-medium text-foreground" : "text-muted-foreground hover:bg-accent hover:text-foreground",
6144
- isActive && "cursor-default"
6029
+ const initial = name.trim().charAt(0).toUpperCase() || "\xB7";
6030
+ return /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenu, { children: [
6031
+ /* @__PURE__ */ jsxRuntime.jsxs(
6032
+ DropdownMenuTrigger,
6033
+ {
6034
+ className: cn(
6035
+ "inline-flex h-10 items-center gap-2.5 rounded-full border border-border bg-card pl-1 pr-1 text-[0.9375rem] outline-none transition-colors hover:border-oca-hairline-strong focus-visible:ring-2 focus-visible:ring-ring",
6036
+ nameFrom === "lg" ? "lg:pr-3.5" : "sm:pr-3.5"
6037
+ ),
6038
+ "aria-label": `${name}, account menu`,
6039
+ children: [
6040
+ /* @__PURE__ */ jsxRuntime.jsx(
6041
+ "span",
6042
+ {
6043
+ "aria-hidden": true,
6044
+ "data-initial": initial,
6045
+ className: "flex size-8 items-center justify-center rounded-full bg-foreground text-[0.8125rem] font-medium text-background before:content-[attr(data-initial)]"
6046
+ }
6145
6047
  ),
6146
- children: [
6147
- section.label,
6148
- /* @__PURE__ */ jsxRuntime.jsx(
6149
- lucideReact.ChevronRight,
6150
- {
6151
- "aria-hidden": true,
6152
- className: cn("size-3.5 shrink-0 text-oca-subtle transition-transform duration-200", open && "rotate-90")
6153
- }
6154
- )
6155
- ]
6156
- }
6157
- ),
6158
- /* @__PURE__ */ jsxRuntime.jsx("ul", { id: panel, hidden: !open, className: "mb-2 ml-2.5 mt-0.5 border-l border-border", children: section.items.map((item) => {
6159
- const on = pathOf(item.href) === here;
6160
- const badge = typeof item.badge === "string" && STATUS_WORDS.has(item.badge) ? /* @__PURE__ */ jsxRuntime.jsx(StatusBadge, { status: item.badge }) : item.badge ? /* @__PURE__ */ jsxRuntime.jsx(Badge, { tone: "muted", children: item.badge }) : null;
6161
- return /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsxs(
6162
- Link8__default.default,
6163
- {
6164
- href: item.href,
6165
- ref: on ? activeRef : void 0,
6166
- onClick: onNavigate,
6167
- "aria-current": on ? "page" : void 0,
6168
- className: cn(
6169
- "-ml-px flex min-h-9 items-center gap-2 border-l-2 py-1.5 pl-3.5 pr-2 text-[0.875rem] leading-snug transition-colors",
6170
- on ? "border-foreground font-medium text-foreground" : "border-transparent text-muted-foreground hover:border-oca-hairline-strong hover:text-foreground"
6171
- ),
6172
- children: [
6173
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1", children: item.label }),
6174
- badge
6175
- ]
6176
- }
6177
- ) }, item.href);
6178
- }) })
6179
- ] }, section.label);
6180
- }) });
6181
- }
6182
- var DOCS_HEADER_NAV = OCHK_IO_NAV.map((n) => n.href === DOCS_HREF ? { ...n, active: true } : n);
6183
- function DocsShell({
6184
- nav,
6185
- current: current2,
6186
- header,
6187
- search,
6188
- actions,
6189
- breadcrumbs,
6190
- toc,
6191
- pager,
6192
- footer,
6193
- children
6194
- }) {
6195
- const [menu, setMenu] = react.useState(false);
6196
- react.useEffect(() => setMenu(false), [current2]);
6197
- const read = useHeadings("#docs-content", current2);
6198
- const items = toc ?? read.items;
6199
- const activeId = toc ? void 0 : read.activeId;
6200
- const here = pathOf(current2);
6201
- const place = react.useMemo(() => {
6202
- for (const s of nav) {
6203
- const it = s.items.find((i) => pathOf(i.href) === here);
6204
- if (it) return { section: s.label, page: it.label };
6205
- }
6206
- return null;
6207
- }, [nav, here]);
6208
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-h-dvh flex-col bg-background", children: [
6209
- /* @__PURE__ */ jsxRuntime.jsx(SkipLink, {}),
6210
- header ?? /* @__PURE__ */ jsxRuntime.jsx(SiteHeader, { home: OCHK_IO, family: "docs", nav: DOCS_HEADER_NAV, search, actions }),
6211
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "sticky top-16 z-30 border-b border-border bg-background/95 backdrop-blur-md supports-[backdrop-filter]:bg-background/90 md:top-[4.5rem] lg:hidden", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "oca-container flex h-12 items-center gap-2", children: /* @__PURE__ */ jsxRuntime.jsxs(Sheet, { open: menu, onOpenChange: setMenu, children: [
6212
- /* @__PURE__ */ jsxRuntime.jsxs(SheetTrigger, { className: "-ml-2 inline-flex h-10 min-w-0 items-center gap-2 rounded-full px-2.5 text-[0.875rem] hover:bg-accent", children: [
6213
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PanelLeft, { "aria-hidden": true, className: "size-[1.125rem] shrink-0" }),
6214
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Docs menu. " }),
6215
- place ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 items-center gap-1.5", children: [
6216
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 text-muted-foreground", children: place.section }),
6217
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { "aria-hidden": true, className: "size-3.5 shrink-0 text-oca-subtle" }),
6218
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate font-medium", children: place.page })
6219
- ] }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: "Docs" })
6220
- ] }),
6221
- /* @__PURE__ */ jsxRuntime.jsxs(SheetContent, { side: "left", className: "w-[min(88vw,22rem)] gap-0 p-0", children: [
6222
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-b border-border px-5 py-4 pr-14", children: /* @__PURE__ */ jsxRuntime.jsx(SheetTitle, { className: "text-[1.0625rem] font-medium", children: "Docs" }) }),
6223
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-y-auto p-3", children: /* @__PURE__ */ jsxRuntime.jsx(DocsNav, { sections: nav, current: current2, onNavigate: () => setMenu(false) }) })
6224
- ] })
6225
- ] }) }) }),
6226
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "oca-container flex-1", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "lg:grid lg:grid-cols-[13.5rem_minmax(0,1fr)] lg:gap-x-10 xl:grid-cols-[13.5rem_minmax(0,1fr)_11rem]", children: [
6227
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "sticky top-[4.5rem] hidden max-h-[calc(100dvh-4.5rem)] self-start overflow-y-auto overscroll-contain py-8 pr-1 lg:block", children: /* @__PURE__ */ jsxRuntime.jsx(DocsNav, { sections: nav, current: current2 }) }),
6228
- /* @__PURE__ */ jsxRuntime.jsxs("main", { id: "main-content", className: "min-w-0 pb-16 pt-6 md:pt-8", children: [
6229
- breadcrumbs ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-6 max-lg:hidden", children: breadcrumbs }) : null,
6230
- items.length > 1 ? /* @__PURE__ */ jsxRuntime.jsxs("details", { className: "group mb-8 rounded-2xl border border-border bg-card xl:hidden", children: [
6231
- /* @__PURE__ */ jsxRuntime.jsxs("summary", { className: "flex min-h-12 cursor-pointer list-none items-center justify-between px-4 text-[0.9375rem] font-medium [&::-webkit-details-marker]:hidden", children: [
6232
- "On this page",
6233
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { "aria-hidden": true, className: "size-4 text-muted-foreground transition-transform group-open:rotate-180" })
6234
- ] }),
6235
- /* @__PURE__ */ jsxRuntime.jsx(OnThisPage, { items, activeId, title: null, className: "px-4 pb-4" })
6236
- ] }) : null,
6237
- /* @__PURE__ */ jsxRuntime.jsx("article", { id: "docs-content", className: "max-w-[46rem]", children }),
6238
- pager ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-16 max-w-[46rem]", children: pager }) : null
6048
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("max-w-[10rem] truncate", nameFrom === "lg" ? "max-lg:hidden" : "max-sm:hidden"), children: name })
6049
+ ]
6050
+ }
6051
+ ),
6052
+ /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenuContent, { align: "end", className: "w-64", children: [
6053
+ /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenuLabel, { className: "flex flex-col gap-0.5", children: [
6054
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-[0.9375rem] font-medium text-foreground", children: name }),
6055
+ detail ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate font-mono text-[0.75rem]", children: detail }) : null
6239
6056
  ] }),
6240
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "sticky top-[4.5rem] hidden max-h-[calc(100dvh-4.5rem)] self-start overflow-y-auto py-10 xl:block", children: items.length > 1 ? /* @__PURE__ */ jsxRuntime.jsx(OnThisPage, { items, activeId }) : null })
6241
- ] }) }),
6242
- footer ?? /* @__PURE__ */ jsxRuntime.jsx(SiteFooter, { columns: OCHK_IO_FOOTER, family: true, legal: true, signature: false })
6057
+ /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuSeparator, {}),
6058
+ items.map(
6059
+ (it, i) => it === "separator" ? /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuSeparator, {}, `sep-${i}`) : it.href ? /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuItem, { asChild: true, destructive: it.destructive, children: /* @__PURE__ */ jsxRuntime.jsxs(Link6__default.default, { href: it.href, children: [
6060
+ it.icon,
6061
+ it.label
6062
+ ] }) }, it.label) : /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenuItem, { onSelect: it.onSelect, destructive: it.destructive, children: [
6063
+ it.icon,
6064
+ it.label
6065
+ ] }, it.label)
6066
+ )
6067
+ ] })
6243
6068
  ] });
6244
6069
  }
6245
- function SideNav({ groups, onNavigate }) {
6246
- return /* @__PURE__ */ jsxRuntime.jsx("nav", { "aria-label": "Pages", className: "flex flex-col gap-5", children: groups.map((g, gi) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-0.5", children: [
6247
- g.label ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "px-3 pb-1 text-[0.8125rem] text-muted-foreground", children: g.label }) : null,
6248
- g.items.map((it) => /* @__PURE__ */ jsxRuntime.jsxs(
6249
- Link8__default.default,
6070
+ function ThemeToggle({ className }) {
6071
+ const { theme, setTheme } = nextThemes.useTheme();
6072
+ const [mounted, setMounted] = react.useState(false);
6073
+ react.useEffect(() => setMounted(true), []);
6074
+ const current2 = mounted ? theme ?? "system" : "system";
6075
+ const next = current2 === "light" ? "dark" : current2 === "dark" ? "system" : "light";
6076
+ const Icon2 = current2 === "light" ? lucideReact.Sun : current2 === "dark" ? lucideReact.Moon : lucideReact.SunMoon;
6077
+ return /* @__PURE__ */ jsxRuntime.jsx(
6078
+ "button",
6079
+ {
6080
+ type: "button",
6081
+ onClick: () => setTheme(next),
6082
+ "aria-label": `Theme: ${current2}. Switch to ${next}`,
6083
+ title: `Theme: ${current2}`,
6084
+ className: cn(
6085
+ "inline-flex size-10 items-center justify-center rounded-full text-muted-foreground transition-colors hover:bg-accent hover:text-foreground",
6086
+ className
6087
+ ),
6088
+ children: /* @__PURE__ */ jsxRuntime.jsx(Icon2, { className: "size-[1.125rem]" })
6089
+ }
6090
+ );
6091
+ }
6092
+ function NavLink({
6093
+ item,
6094
+ className,
6095
+ onNavigate,
6096
+ line = false
6097
+ }) {
6098
+ const cls = cn(
6099
+ "rounded-full px-3 py-2 text-[0.9375rem] transition-colors",
6100
+ item.active ? "text-foreground" : "text-muted-foreground hover:text-foreground",
6101
+ line && "relative after:absolute after:inset-x-3 after:-bottom-[0.625rem] after:h-0.5 after:rounded-full",
6102
+ line && item.active && "after:bg-foreground",
6103
+ className
6104
+ );
6105
+ if (item.external) {
6106
+ return /* @__PURE__ */ jsxRuntime.jsx("a", { href: item.href, className: cls, rel: "noreferrer", onClick: onNavigate, children: item.label });
6107
+ }
6108
+ return /* @__PURE__ */ jsxRuntime.jsx(Link6__default.default, { href: item.href, className: cls, "aria-current": item.active ? "page" : void 0, onClick: onNavigate, children: item.label });
6109
+ }
6110
+ function NavRow({ item, onNavigate }) {
6111
+ const body = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
6112
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[0.9375rem] font-medium leading-6 text-foreground", children: item.label }),
6113
+ item.description ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[0.8125rem] leading-snug text-muted-foreground", children: item.description }) : null
6114
+ ] });
6115
+ const cls = cn(
6116
+ "flex flex-col gap-0.5 rounded-xl px-3 py-2 transition-colors hover:bg-accent",
6117
+ item.active && "bg-muted hover:bg-muted dark:bg-white/[0.06]"
6118
+ );
6119
+ return item.external ? /* @__PURE__ */ jsxRuntime.jsx("a", { href: item.href, className: cls, rel: "noreferrer", onClick: onNavigate, children: body }) : /* @__PURE__ */ jsxRuntime.jsx(Link6__default.default, { href: item.href, className: cls, "aria-current": item.active ? "page" : void 0, onClick: onNavigate, children: body });
6120
+ }
6121
+ var seeAll = (item) => typeof item.label === "string" ? `All ${item.label.toLowerCase()}` : "See all";
6122
+ function NavDropdown({ item }) {
6123
+ const [open, setOpen] = react.useState(false);
6124
+ const active = item.active || item.children?.some((c) => c.active);
6125
+ return /* @__PURE__ */ jsxRuntime.jsxs(Popover, { open, onOpenChange: setOpen, children: [
6126
+ /* @__PURE__ */ jsxRuntime.jsxs(
6127
+ PopoverTrigger,
6250
6128
  {
6251
- href: it.href,
6252
- onClick: onNavigate,
6253
- "aria-current": it.active ? "page" : void 0,
6254
6129
  className: cn(
6255
- "flex h-9 items-center gap-3 rounded-xl px-3 text-[0.9375rem] transition-colors",
6256
- "[&_svg]:size-[1.0625rem] [&_svg]:shrink-0",
6257
- it.active ? "bg-card text-foreground shadow-sm ring-1 ring-border [&_svg]:text-foreground" : "text-muted-foreground hover:bg-accent hover:text-foreground"
6130
+ "group inline-flex items-center gap-1 rounded-full py-2 pl-3 pr-2.5 text-[0.9375rem] transition-colors md:max-lg:pl-2.5 md:max-lg:pr-2",
6131
+ active ? "text-foreground" : "text-muted-foreground hover:text-foreground data-[state=open]:text-foreground"
6258
6132
  ),
6259
6133
  children: [
6260
- it.icon,
6261
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate", children: it.label }),
6262
- it.badge ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0", children: it.badge }) : null
6134
+ item.label,
6135
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { "aria-hidden": true, className: "size-3.5 transition-transform duration-200 group-data-[state=open]:rotate-180" })
6263
6136
  ]
6264
- },
6265
- it.href
6266
- ))
6267
- ] }, g.label ?? gi)) });
6137
+ }
6138
+ ),
6139
+ /* @__PURE__ */ jsxRuntime.jsxs(PopoverContent, { align: "center", sideOffset: 10, className: "w-[min(calc(100vw-2rem),26rem)] p-2", children: [
6140
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "flex flex-col", children: item.children?.map((c) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx(NavRow, { item: c, onNavigate: () => setOpen(false) }) }, c.href)) }),
6141
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1.5 border-t border-border px-1 pt-1.5", children: /* @__PURE__ */ jsxRuntime.jsx(
6142
+ NavLink,
6143
+ {
6144
+ item: { ...item, label: seeAll(item), children: void 0 },
6145
+ className: "block rounded-xl px-2 py-2 text-[0.875rem]",
6146
+ onNavigate: () => setOpen(false)
6147
+ }
6148
+ ) })
6149
+ ] })
6150
+ ] });
6268
6151
  }
6269
- function SectionSwitch({
6270
- sections,
6271
- current: current2,
6272
- onNavigate
6152
+ function SiteHeader({
6153
+ home = "/",
6154
+ brand,
6155
+ product,
6156
+ family,
6157
+ nav = [],
6158
+ search,
6159
+ actions,
6160
+ variant = "site",
6161
+ navOnPhone = true,
6162
+ menu: menuExtra,
6163
+ className
6273
6164
  }) {
6274
- const cols = sections.length <= 3 ? sections.length : 2;
6275
- return /* @__PURE__ */ jsxRuntime.jsx(
6276
- "nav",
6277
- {
6278
- "aria-label": "Sections",
6279
- className: cn("grid gap-1 bg-muted p-1", cols === sections.length ? "rounded-full" : "rounded-[1.25rem]"),
6280
- style: { gridTemplateColumns: `repeat(${cols}, minmax(0, 1fr))` },
6281
- children: sections.map((sec) => {
6282
- const on = sec.id === current2.id;
6283
- return /* @__PURE__ */ jsxRuntime.jsx(
6284
- Link8__default.default,
6285
- {
6286
- href: sec.href,
6287
- onClick: onNavigate,
6288
- "aria-current": on ? "true" : void 0,
6289
- className: cn(
6290
- "flex h-8 min-w-0 items-center justify-center rounded-full px-1.5 text-[0.8125rem] font-medium transition-colors",
6291
- on ? "bg-card text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"
6292
- ),
6293
- children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: sec.label })
6294
- },
6295
- sec.id
6296
- );
6297
- })
6298
- }
6299
- );
6300
- }
6301
- function TabBar({ items }) {
6165
+ const [open, setOpen] = react.useState(false);
6166
+ const tool = variant === "tool";
6167
+ const size = tool ? 24 : 28;
6168
+ const current2 = typeof family === "string" ? family : void 0;
6169
+ const phoneNav = navOnPhone ? nav : [];
6170
+ const menu = phoneNav.length > 0 || Boolean(family) || Boolean(menuExtra);
6171
+ const brandNode = brand ?? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center", children: [
6172
+ /* @__PURE__ */ jsxRuntime.jsx(Lockup, { size }),
6173
+ product ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
6174
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: "mx-3 h-5 w-px bg-oca-hairline-strong" }),
6175
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium tracking-[-0.01em]", style: { fontSize: size * 0.56 }, children: product })
6176
+ ] }) : null
6177
+ ] });
6178
+ const navigation = nav.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("nav", { "aria-label": "Main", className: "hidden items-center gap-1 md:flex", children: nav.map(
6179
+ (n) => n.children?.length ? /* @__PURE__ */ jsxRuntime.jsx(NavDropdown, { item: n }, n.href) : (
6180
+ // Between md and lg the family menu and the actions share the row: tighter.
6181
+ /* @__PURE__ */ jsxRuntime.jsx(NavLink, { item: n, line: tool, className: tool ? void 0 : "md:max-lg:px-2.5" }, n.href)
6182
+ )
6183
+ ) }) : null;
6302
6184
  return /* @__PURE__ */ jsxRuntime.jsx(
6303
- "nav",
6185
+ "header",
6304
6186
  {
6305
- "aria-label": "Pages",
6306
- "data-oca-tabbar": "",
6307
- className: "fixed inset-x-0 bottom-0 z-40 border-t border-border bg-background/90 pb-[env(safe-area-inset-bottom)] backdrop-blur-md md:hidden",
6308
- children: /* @__PURE__ */ jsxRuntime.jsx(
6187
+ className: cn(
6188
+ "sticky top-0 z-40 w-full border-b bg-background/95 backdrop-blur-md supports-[backdrop-filter]:bg-background/90",
6189
+ tool ? "border-border" : "border-transparent",
6190
+ className
6191
+ ),
6192
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
6309
6193
  "div",
6310
6194
  {
6311
- className: "mx-auto grid h-14 max-w-[32rem] px-1.5",
6312
- style: { gridTemplateColumns: `repeat(${items.length}, minmax(0, 1fr))` },
6313
- children: items.map((it) => /* @__PURE__ */ jsxRuntime.jsxs(
6314
- Link8__default.default,
6315
- {
6316
- href: it.href,
6317
- "aria-current": it.active ? "page" : void 0,
6318
- className: cn(
6319
- "flex min-w-0 flex-col items-center justify-center gap-1 rounded-2xl text-[0.6875rem] leading-none outline-none transition-colors [-webkit-tap-highlight-color:transparent] focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring",
6320
- it.active ? "text-foreground" : "text-muted-foreground hover:text-foreground"
6321
- ),
6322
- children: [
6323
- /* @__PURE__ */ jsxRuntime.jsxs(
6324
- "span",
6195
+ className: cn(
6196
+ "flex items-center justify-between gap-4",
6197
+ tool ? "h-14 px-4 md:px-6" : "oca-container h-16 md:h-[4.5rem] md:max-lg:gap-2",
6198
+ // Three columns, the outer two each at least their content: the
6199
+ // navigation stays centred whatever the actions hold, so it does
6200
+ // not shift when they change (signed out to signed in).
6201
+ !tool && nav.length > 0 && "md:grid md:grid-cols-[minmax(max-content,1fr)_auto_minmax(max-content,1fr)]"
6202
+ ),
6203
+ children: [
6204
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex min-w-0 items-center gap-1", tool ? "md:gap-1" : "justify-self-start"), children: [
6205
+ /* @__PURE__ */ jsxRuntime.jsxs(Link6__default.default, { href: home, className: "-ml-1 min-w-0 rounded-lg p-1", children: [
6206
+ brandNode,
6207
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: " home" })
6208
+ ] }),
6209
+ family ? /* @__PURE__ */ jsxRuntime.jsx(FamilyMenu, { current: current2, className: "max-md:hidden" }) : null,
6210
+ tool && navigation ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ml-5", children: navigation }) : null
6211
+ ] }),
6212
+ !tool ? navigation : null,
6213
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 justify-self-end", children: [
6214
+ search,
6215
+ actions,
6216
+ menu ? /* @__PURE__ */ jsxRuntime.jsxs(Sheet, { open, onOpenChange: setOpen, children: [
6217
+ /* @__PURE__ */ jsxRuntime.jsx(
6218
+ SheetTrigger,
6325
6219
  {
6326
- className: cn(
6327
- "relative flex h-7 w-12 items-center justify-center rounded-full transition-[background-color,box-shadow] duration-200",
6328
- "[&_svg]:size-[1.125rem] [&_svg]:shrink-0",
6329
- it.active ? "bg-card shadow-sm ring-1 ring-border [&_svg]:stroke-2" : "[&_svg]:stroke-[1.75]"
6330
- ),
6331
- children: [
6332
- it.icon,
6333
- it.badge ? /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: "absolute right-2.5 top-0.5 size-2 rounded-full bg-oca-orange ring-2 ring-background" }) : null
6334
- ]
6220
+ className: "inline-flex size-10 items-center justify-center rounded-full text-foreground hover:bg-accent md:hidden",
6221
+ "aria-label": "Open menu",
6222
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Menu, { className: "size-5" })
6335
6223
  }
6336
6224
  ),
6337
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "max-w-full truncate px-0.5", children: it.label }),
6338
- it.badge ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: it.badge }) : null
6339
- ]
6340
- },
6341
- it.href
6342
- ))
6225
+ /* @__PURE__ */ jsxRuntime.jsxs(SheetContent, { side: "right", className: "pt-16", children: [
6226
+ /* @__PURE__ */ jsxRuntime.jsx(SheetTitle, { className: "sr-only", children: "Menu" }),
6227
+ menuExtra ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex flex-col", (phoneNav.length > 0 || family) && "border-b border-border pb-3"), children: menuExtra }) : null,
6228
+ phoneNav.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("nav", { "aria-label": "Main", className: "flex flex-col", children: phoneNav.map(
6229
+ (n) => n.children?.length ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col py-2", children: [
6230
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "px-3 pb-1 text-[0.8125rem] text-muted-foreground", children: n.label }),
6231
+ n.children.map((c) => /* @__PURE__ */ jsxRuntime.jsx(
6232
+ NavLink,
6233
+ {
6234
+ item: c,
6235
+ className: "rounded-xl px-3 py-2.5 text-[1.0625rem]",
6236
+ onNavigate: () => setOpen(false)
6237
+ },
6238
+ c.href
6239
+ ))
6240
+ ] }, n.href) : /* @__PURE__ */ jsxRuntime.jsx(
6241
+ NavLink,
6242
+ {
6243
+ item: n,
6244
+ className: "rounded-xl px-3 py-3 text-[1.0625rem]",
6245
+ onNavigate: () => setOpen(false)
6246
+ },
6247
+ n.href
6248
+ )
6249
+ ) }) : null,
6250
+ family ? /* @__PURE__ */ jsxRuntime.jsxs("details", { className: cn("group", phoneNav.length > 0 && "mt-2 border-t border-border pt-4"), children: [
6251
+ /* @__PURE__ */ jsxRuntime.jsxs("summary", { className: "flex cursor-pointer list-none items-center justify-between rounded-xl px-3 py-2.5 text-[1.0625rem] [&::-webkit-details-marker]:hidden", children: [
6252
+ "All orangecheck sites",
6253
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { "aria-hidden": true, className: "size-4 text-muted-foreground transition-transform group-open:rotate-180" })
6254
+ ] }),
6255
+ /* @__PURE__ */ jsxRuntime.jsx(FamilyList, { current: current2, onNavigate: () => setOpen(false), stack: true, className: "mt-2" })
6256
+ ] }) : null
6257
+ ] })
6258
+ ] }) : null
6259
+ ] })
6260
+ ]
6343
6261
  }
6344
6262
  )
6345
6263
  }
6346
6264
  );
6347
6265
  }
6348
- function tabsFor(groups) {
6349
- const items = groups.flatMap((g) => g.items);
6350
- return items.length >= 2 && items.length <= 5 && items.every((it) => it.icon) ? items : null;
6351
- }
6352
- var activeItem = (groups) => groups.flatMap((g) => g.items).find((it) => it.active);
6353
- var warned = /* @__PURE__ */ new Set();
6354
- function warnDuplicateLabels(groups) {
6355
- if (typeof process === "undefined" || process.env.NODE_ENV === "production") return;
6356
- const seen = /* @__PURE__ */ new Set();
6357
- for (const it of groups.flatMap((g) => g.items)) {
6358
- if (seen.has(it.label) && !warned.has(it.label)) {
6359
- warned.add(it.label);
6360
- console.warn(`AppShell: two pages are labelled "${it.label}"; give each its own name.`);
6266
+ function SkipLink({ href = "#main-content", children = "Skip to content" }) {
6267
+ return /* @__PURE__ */ jsxRuntime.jsx(
6268
+ "a",
6269
+ {
6270
+ href,
6271
+ className: "sr-only focus:not-sr-only focus:fixed focus:left-4 focus:top-3 focus:z-50 focus:rounded-full focus:border focus:border-border focus:bg-card focus:px-4 focus:py-2 focus:text-[0.9375rem] focus:font-medium focus:text-foreground focus:shadow-md",
6272
+ children
6361
6273
  }
6362
- seen.add(it.label);
6363
- }
6274
+ );
6364
6275
  }
6365
- function AppShell({
6366
- nav,
6367
- sections,
6368
- activeSection,
6369
- page: pageOverride,
6370
- persistent = [],
6371
- home = "/",
6372
- account,
6373
- banner,
6374
- footer,
6276
+ var BANNER_TONE = {
6277
+ neutral: "border-border bg-muted",
6278
+ brand: "border-[color-mix(in_oklab,var(--oca-orange)_30%,var(--border))] bg-[color-mix(in_oklab,var(--oca-orange)_9%,var(--background))]",
6279
+ danger: "border-[color-mix(in_oklab,var(--destructive)_35%,var(--border))] bg-[color-mix(in_oklab,var(--destructive)_8%,var(--background))]"
6280
+ };
6281
+ function SiteBanner({
6282
+ tone = "neutral",
6375
6283
  children,
6284
+ action,
6376
6285
  className
6377
6286
  }) {
6378
- const [open, setOpen] = react.useState(false);
6379
- const current2 = sections && sections.length > 0 ? sections.find((sec) => sec.id === activeSection) ?? sections.find((sec) => activeItem(sec.groups)) ?? sections[0] : void 0;
6380
- const groups = current2 ? [...current2.groups, ...persistent] : [...nav ?? [], ...persistent];
6381
- warnDuplicateLabels(groups);
6382
- const tabs = current2 ? null : tabsFor(groups);
6383
- const page = activeItem(groups);
6384
- const place = react.useMemo(
6385
- () => ({
6386
- section: current2 ? current2.title ?? current2.label : void 0,
6387
- page: pageOverride ?? page?.label
6388
- }),
6389
- [current2, page?.label, pageOverride]
6390
- );
6391
- const switcher = sections && current2 && sections.length > 1 ? /* @__PURE__ */ jsxRuntime.jsx(SectionSwitch, { sections, current: current2, onNavigate: () => setOpen(false) }) : null;
6392
- return /* @__PURE__ */ jsxRuntime.jsx(ShellContext.Provider, { value: place, children: /* @__PURE__ */ jsxRuntime.jsxs(
6393
- "div",
6394
- {
6395
- className: cn(
6396
- "min-h-dvh bg-background",
6397
- tabs && "max-md:pb-[calc(3.5rem_+_env(safe-area-inset-bottom))]",
6398
- className
6399
- ),
6400
- children: [
6401
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sticky top-0 z-40 border-b border-border bg-background/90 backdrop-blur-md lg:hidden", children: [
6402
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-14 items-center gap-2 px-3", children: [
6403
- /* @__PURE__ */ jsxRuntime.jsxs(Sheet, { open, onOpenChange: setOpen, children: [
6404
- /* @__PURE__ */ jsxRuntime.jsx(
6405
- SheetTrigger,
6406
- {
6407
- className: cn(
6408
- "inline-flex size-10 items-center justify-center rounded-full hover:bg-accent",
6409
- // The tab bar holds every page; the sheet is left for a footer.
6410
- tabs && !footer && "max-md:hidden"
6411
- ),
6412
- "aria-label": "Open navigation",
6413
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Menu, { className: "size-5" })
6414
- }
6415
- ),
6416
- /* @__PURE__ */ jsxRuntime.jsxs(SheetContent, { side: "left", className: "flex flex-col gap-6 overflow-y-auto p-4 pt-16", children: [
6417
- /* @__PURE__ */ jsxRuntime.jsx(SheetTitle, { className: "sr-only", children: "Navigation" }),
6418
- switcher,
6419
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: tabs ? "max-md:hidden" : void 0, children: /* @__PURE__ */ jsxRuntime.jsx(SideNav, { groups, onNavigate: () => setOpen(false) }) }),
6420
- footer ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-auto flex flex-col gap-3", children: footer }) : null
6421
- ] })
6422
- ] }),
6423
- /* @__PURE__ */ jsxRuntime.jsx(Link8__default.default, { href: home, "aria-label": "Home", className: "rounded-lg p-1", children: /* @__PURE__ */ jsxRuntime.jsx(Lockup, { size: 22 }) }),
6424
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ml-auto flex items-center", children: account })
6287
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { role: "status", "aria-live": "polite", "data-tone": tone, className: cn("border-b text-[0.875rem]", BANNER_TONE[tone], className), children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "oca-container flex flex-wrap items-center justify-between gap-x-4 gap-y-1 py-2.5", children: [
6288
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "flex min-w-0 items-baseline gap-2.5 leading-snug", children: [
6289
+ tone !== "neutral" ? /* @__PURE__ */ jsxRuntime.jsx(
6290
+ "span",
6291
+ {
6292
+ "aria-hidden": true,
6293
+ className: cn(
6294
+ "size-2 shrink-0 translate-y-[-0.05em] rounded-full",
6295
+ tone === "brand" ? "bg-oca-orange" : "bg-destructive"
6296
+ )
6297
+ }
6298
+ ) : null,
6299
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children })
6300
+ ] }),
6301
+ action ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("shrink-0 font-medium", tone !== "neutral" && "max-sm:pl-[1.125rem]"), children: action }) : null
6302
+ ] }) });
6303
+ }
6304
+ var FOOT_LINK = "inline-flex min-h-11 items-center transition-colors hover:text-foreground md:min-h-0";
6305
+ function LegalRow({ links }) {
6306
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-x-6 gap-y-2 sm:flex-row sm:items-center sm:justify-between", children: [
6307
+ /* @__PURE__ */ jsxRuntime.jsx("nav", { "aria-label": "Legal", children: /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "flex flex-wrap gap-x-5", children: links.map((l) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: l.href.startsWith("/") ? /* @__PURE__ */ jsxRuntime.jsx(Link6__default.default, { href: l.href, className: FOOT_LINK, children: l.label }) : /* @__PURE__ */ jsxRuntime.jsx("a", { href: l.href, className: FOOT_LINK, children: l.label }) }, l.href)) }) }),
6308
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
6309
+ "\xA9 ",
6310
+ (/* @__PURE__ */ new Date()).getFullYear(),
6311
+ " OrangeCheck"
6312
+ ] })
6313
+ ] });
6314
+ }
6315
+ function SiteFooter({
6316
+ columns = [],
6317
+ family = false,
6318
+ legal = false,
6319
+ compact = false,
6320
+ fineprint,
6321
+ meta,
6322
+ signature = true,
6323
+ className
6324
+ }) {
6325
+ const legalLinks = legal === true ? LEGAL_LINKS : legal || null;
6326
+ if (compact) {
6327
+ return /* @__PURE__ */ jsxRuntime.jsx("footer", { className: cn("border-t border-border bg-background text-[0.875rem] text-muted-foreground", className), children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "oca-container flex flex-col gap-x-8 gap-y-3 py-5 lg:flex-row lg:items-center lg:justify-between", children: [
6328
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-x-6 gap-y-1", children: [
6329
+ /* @__PURE__ */ jsxRuntime.jsx("a", { href: OCHK_IO, className: "rounded-lg text-foreground", children: /* @__PURE__ */ jsxRuntime.jsx(Lockup, { size: 22 }) }),
6330
+ family ? /* @__PURE__ */ jsxRuntime.jsx("nav", { "aria-label": "Protocols", children: /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "flex flex-wrap gap-x-4", children: PROTOCOLS.map((p) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx("a", { href: p.pageHref, className: FOOT_LINK, children: p.label }) }, p.slug)) }) }) : null
6331
+ ] }),
6332
+ legalLinks || meta ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-x-6 gap-y-2 sm:flex-row sm:flex-wrap sm:items-center", children: [
6333
+ legalLinks ? /* @__PURE__ */ jsxRuntime.jsx(LegalRow, { links: legalLinks }) : null,
6334
+ meta
6335
+ ] }) : null
6336
+ ] }) });
6337
+ }
6338
+ const cols = [
6339
+ ...columns,
6340
+ ...family ? familyByGroup().map((g) => ({
6341
+ // The lockup above already says orangecheck.
6342
+ heading: g.id === "orangecheck" ? "Start here" : g.label,
6343
+ links: g.sites.map((s) => ({ href: s.href, label: s.label, external: true }))
6344
+ })) : []
6345
+ ];
6346
+ const n = cols.length;
6347
+ const inline = n <= 5;
6348
+ const grid = {
6349
+ "--oca-footer-md": `repeat(${Math.max(1, Math.min(n, 4))}, minmax(0, 1fr))`,
6350
+ "--oca-footer-lg": inline ? `minmax(0, 1.3fr) repeat(${Math.max(1, n)}, minmax(0, 1fr))` : `repeat(${Math.min(n, 6)}, minmax(0, 1fr))`
6351
+ };
6352
+ return /* @__PURE__ */ jsxRuntime.jsxs("footer", { className: cn("border-t border-border bg-background", className), children: [
6353
+ /* @__PURE__ */ jsxRuntime.jsxs(
6354
+ "div",
6355
+ {
6356
+ style: grid,
6357
+ className: "oca-container grid grid-cols-2 gap-x-6 gap-y-10 py-14 md:grid-cols-[var(--oca-footer-md)] md:py-16 lg:grid-cols-[var(--oca-footer-lg)]",
6358
+ children: [
6359
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("col-span-full flex flex-col gap-4", inline && "lg:col-span-1"), children: [
6360
+ /* @__PURE__ */ jsxRuntime.jsx(Lockup, { size: 26 }),
6361
+ fineprint ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "max-w-xs text-[0.9375rem] leading-relaxed text-muted-foreground", children: fineprint }) : null
6425
6362
  ] }),
6426
- place.page ? /* @__PURE__ */ jsxRuntime.jsxs(
6427
- "div",
6428
- {
6429
- className: cn(
6430
- "flex h-9 items-center gap-1.5 border-t border-border px-4 text-[0.875rem]",
6431
- // The active tab already names the page.
6432
- tabs && !pageOverride && "max-md:hidden"
6433
- ),
6434
- children: [
6435
- place.section ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
6436
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 text-muted-foreground", children: place.section }),
6437
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { "aria-hidden": true, className: "size-3.5 shrink-0 text-muted-foreground" })
6438
- ] }) : null,
6439
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate font-medium", children: place.page })
6440
- ]
6441
- }
6442
- ) : null
6363
+ cols.map((col, i) => {
6364
+ const spans = n % 2 === 1 && i === n - 1;
6365
+ return /* @__PURE__ */ jsxRuntime.jsxs(
6366
+ "div",
6367
+ {
6368
+ className: cn("flex min-w-0 flex-col gap-1", spans && "col-span-2 md:col-span-1"),
6369
+ children: [
6370
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mb-2 text-[0.875rem] font-medium", children: col.heading }),
6371
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex flex-col gap-1", spans && "grid grid-cols-2 gap-x-6 md:flex md:flex-col"), children: col.links.map((l) => /* @__PURE__ */ jsxRuntime.jsx(
6372
+ NavLink,
6373
+ {
6374
+ item: l,
6375
+ className: "-mx-3 py-2.5 text-[0.9375rem] md:py-1.5"
6376
+ },
6377
+ l.href
6378
+ )) })
6379
+ ]
6380
+ },
6381
+ col.heading
6382
+ );
6383
+ })
6384
+ ]
6385
+ }
6386
+ ),
6387
+ signature ? /* @__PURE__ */ jsxRuntime.jsx("div", { "aria-hidden": true, className: "oca-container select-none overflow-hidden pb-8 md:pb-12", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-end gap-[0.18em] text-[clamp(3rem,11.5vw,10rem)] leading-[0.78] tracking-[-0.065em] [font-family:var(--oc-font-display)]", children: [
6388
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mb-[0.06em] inline-block w-[1.1em] shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(Mark, { className: "block h-auto w-full" }) }),
6389
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "orangecheck" })
6390
+ ] }) }) : null,
6391
+ legalLinks || meta ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "oca-container", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3 border-t border-border py-6 text-[0.875rem] text-muted-foreground", children: [
6392
+ legalLinks ? /* @__PURE__ */ jsxRuntime.jsx(LegalRow, { links: legalLinks }) : null,
6393
+ meta
6394
+ ] }) }) : null
6395
+ ] });
6396
+ }
6397
+ function OchkIoFooter({ columns = OCHK_IO_FOOTER, className }) {
6398
+ return /* @__PURE__ */ jsxRuntime.jsx(
6399
+ SiteFooter,
6400
+ {
6401
+ columns,
6402
+ family: true,
6403
+ legal: true,
6404
+ fineprint: "Open protocols on Bitcoin. Anyone can check the result.",
6405
+ meta: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center justify-between gap-4", children: [
6406
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
6407
+ "Open-source work on orangecheck is ",
6408
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "whitespace-nowrap", children: "supported by OpenSats." })
6443
6409
  ] }),
6444
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mx-auto flex w-full max-w-[90rem]", children: [
6445
- /* @__PURE__ */ jsxRuntime.jsxs("aside", { className: "sticky top-0 hidden h-dvh w-[17rem] shrink-0 flex-col gap-6 overflow-y-auto px-4 py-6 lg:flex", children: [
6446
- /* @__PURE__ */ jsxRuntime.jsx(Link8__default.default, { href: home, className: "px-2", "aria-label": "Home", children: /* @__PURE__ */ jsxRuntime.jsx(Lockup, { size: 26 }) }),
6447
- switcher,
6448
- /* @__PURE__ */ jsxRuntime.jsx(SideNav, { groups }),
6449
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-auto flex flex-col gap-3", children: footer })
6410
+ /* @__PURE__ */ jsxRuntime.jsx(ThemeToggle, { className: "-mx-3" })
6411
+ ] }),
6412
+ className
6413
+ }
6414
+ );
6415
+ }
6416
+ function SignInFrame({
6417
+ title = "Sign in",
6418
+ lead,
6419
+ children,
6420
+ error,
6421
+ fineprint,
6422
+ brand,
6423
+ home = "/",
6424
+ back,
6425
+ art,
6426
+ caption,
6427
+ className
6428
+ }) {
6429
+ return /* @__PURE__ */ jsxRuntime.jsxs(
6430
+ "main",
6431
+ {
6432
+ id: "main-content",
6433
+ className: cn("grid min-h-dvh grid-cols-1 bg-background text-foreground lg:grid-cols-2", className),
6434
+ children: [
6435
+ /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "flex flex-col px-4 pb-8 pt-5 sm:px-8 lg:px-14 lg:pt-8", children: [
6436
+ /* @__PURE__ */ jsxRuntime.jsxs("header", { className: "flex items-center justify-between gap-4", children: [
6437
+ /* @__PURE__ */ jsxRuntime.jsxs(Link6__default.default, { href: home, className: "w-fit rounded-lg", children: [
6438
+ brand ?? /* @__PURE__ */ jsxRuntime.jsx(Lockup, { size: 28 }),
6439
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: " home" })
6440
+ ] }),
6441
+ back === void 0 ? /* @__PURE__ */ jsxRuntime.jsx(
6442
+ Link6__default.default,
6443
+ {
6444
+ href: home,
6445
+ className: "text-[0.9375rem] text-muted-foreground underline-offset-4 hover:text-foreground hover:underline",
6446
+ children: "Back to home"
6447
+ }
6448
+ ) : back
6450
6449
  ] }),
6451
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-1 flex-col", children: [
6452
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden h-[4.5rem] items-center justify-end gap-3 px-8 lg:flex", children: account }),
6453
- banner ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 pb-2 pt-4 md:px-8 lg:pt-0", children: banner }) : null,
6454
- /* @__PURE__ */ jsxRuntime.jsx("main", { id: "main-content", className: "flex-1 px-4 pb-16 pt-6 md:px-8 lg:pt-2", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-auto w-full max-w-[72rem]", children }) })
6450
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mx-auto flex w-full max-w-[25rem] flex-1 flex-col justify-center gap-9 py-12", children: [
6451
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3", children: [
6452
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "oca-display-2", children: title }),
6453
+ lead ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "oca-lead", children: lead }) : null
6454
+ ] }),
6455
+ /* @__PURE__ */ jsxRuntime.jsx("div", { children }),
6456
+ error ? /* @__PURE__ */ jsxRuntime.jsx("p", { role: "alert", className: "text-[0.9375rem] text-destructive", children: error }) : null,
6457
+ fineprint ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[0.8125rem] leading-relaxed text-muted-foreground", children: fineprint }) : null
6455
6458
  ] })
6456
6459
  ] }),
6457
- tabs ? /* @__PURE__ */ jsxRuntime.jsx(TabBar, { items: tabs }) : null
6460
+ /* @__PURE__ */ jsxRuntime.jsxs(
6461
+ "aside",
6462
+ {
6463
+ "aria-hidden": true,
6464
+ className: "relative hidden flex-col justify-between gap-10 overflow-hidden border-l border-[var(--oca-band-line)] bg-oca-ink p-14 text-oca-ink-foreground lg:flex",
6465
+ children: [
6466
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-1 items-center justify-center", children: art ?? /* @__PURE__ */ jsxRuntime.jsx(IsoCheck, { size: 340, settle: true, tilt: true, className: "max-w-full" }) }),
6467
+ caption ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex max-w-[24rem] flex-col gap-3", children: caption }) : null
6468
+ ]
6469
+ }
6470
+ )
6458
6471
  ]
6459
6472
  }
6460
- ) });
6473
+ );
6461
6474
  }
6462
- function AccountMenu({
6463
- name,
6464
- detail,
6465
- items,
6466
- nameFrom = "sm"
6475
+ var STATUS_WORDS = /* @__PURE__ */ new Set(["live", "testing", "not-yet", "paused", "good", "caution", "refused"]);
6476
+ var pathOf = (href) => href.split(/[?#]/)[0].replace(/(.)\/$/, "$1");
6477
+ function DocsNav({
6478
+ sections,
6479
+ current: current2,
6480
+ onNavigate,
6481
+ className
6467
6482
  }) {
6468
- const initial = name.trim().charAt(0).toUpperCase() || "\xB7";
6469
- return /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenu, { children: [
6470
- /* @__PURE__ */ jsxRuntime.jsxs(
6471
- DropdownMenuTrigger,
6472
- {
6473
- className: cn(
6474
- "inline-flex h-10 items-center gap-2.5 rounded-full border border-border bg-card pl-1 pr-1 text-[0.9375rem] outline-none transition-colors hover:border-oca-hairline-strong focus-visible:ring-2 focus-visible:ring-ring",
6475
- nameFrom === "lg" ? "lg:pr-3.5" : "sm:pr-3.5"
6476
- ),
6477
- "aria-label": `${name}, account menu`,
6478
- children: [
6479
- /* @__PURE__ */ jsxRuntime.jsx(
6480
- "span",
6481
- {
6482
- "aria-hidden": true,
6483
- "data-initial": initial,
6484
- className: "flex size-8 items-center justify-center rounded-full bg-foreground text-[0.8125rem] font-medium text-background before:content-[attr(data-initial)]"
6485
- }
6483
+ const here = pathOf(current2);
6484
+ const activeSection = react.useMemo(
6485
+ () => sections.findIndex((s) => s.items.some((i) => pathOf(i.href) === here)),
6486
+ [sections, here]
6487
+ );
6488
+ const [peeked, setPeeked] = react.useState(() => /* @__PURE__ */ new Set());
6489
+ react.useEffect(() => setPeeked(/* @__PURE__ */ new Set()), [activeSection]);
6490
+ const activeRef = react.useRef(null);
6491
+ react.useEffect(() => {
6492
+ const id = requestAnimationFrame(() => activeRef.current?.scrollIntoView({ block: "nearest" }));
6493
+ return () => cancelAnimationFrame(id);
6494
+ }, [here]);
6495
+ const base = react.useId();
6496
+ return /* @__PURE__ */ jsxRuntime.jsx("nav", { "aria-label": "Docs", className: cn("flex flex-col gap-0.5", className), children: sections.map((section, si) => {
6497
+ const isActive = si === activeSection;
6498
+ const open = isActive || peeked.has(si);
6499
+ const panel = `${base}-s${si}`;
6500
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
6501
+ /* @__PURE__ */ jsxRuntime.jsxs(
6502
+ "button",
6503
+ {
6504
+ type: "button",
6505
+ "aria-expanded": open,
6506
+ "aria-controls": panel,
6507
+ onClick: () => {
6508
+ if (isActive) return;
6509
+ setPeeked((p) => {
6510
+ const n = new Set(p);
6511
+ if (n.has(si)) n.delete(si);
6512
+ else n.add(si);
6513
+ return n;
6514
+ });
6515
+ },
6516
+ className: cn(
6517
+ "flex min-h-9 w-full items-center justify-between gap-2 rounded-lg px-2.5 py-1.5 text-left text-[0.875rem] transition-colors",
6518
+ isActive ? "font-medium text-foreground" : "text-muted-foreground hover:bg-accent hover:text-foreground",
6519
+ isActive && "cursor-default"
6486
6520
  ),
6487
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("max-w-[10rem] truncate", nameFrom === "lg" ? "max-lg:hidden" : "max-sm:hidden"), children: name })
6488
- ]
6489
- }
6490
- ),
6491
- /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenuContent, { align: "end", className: "w-64", children: [
6492
- /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenuLabel, { className: "flex flex-col gap-0.5", children: [
6493
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-[0.9375rem] font-medium text-foreground", children: name }),
6494
- detail ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate font-mono text-[0.75rem]", children: detail }) : null
6495
- ] }),
6496
- /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuSeparator, {}),
6497
- items.map(
6498
- (it, i) => it === "separator" ? /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuSeparator, {}, `sep-${i}`) : it.href ? /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuItem, { asChild: true, destructive: it.destructive, children: /* @__PURE__ */ jsxRuntime.jsxs(Link8__default.default, { href: it.href, children: [
6499
- it.icon,
6500
- it.label
6501
- ] }) }, it.label) : /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenuItem, { onSelect: it.onSelect, destructive: it.destructive, children: [
6502
- it.icon,
6503
- it.label
6504
- ] }, it.label)
6505
- )
6506
- ] })
6507
- ] });
6508
- }
6509
- function ThemeToggle({ className }) {
6510
- const { theme, setTheme } = nextThemes.useTheme();
6511
- const [mounted, setMounted] = react.useState(false);
6512
- react.useEffect(() => setMounted(true), []);
6513
- const current2 = mounted ? theme ?? "system" : "system";
6514
- const next = current2 === "light" ? "dark" : current2 === "dark" ? "system" : "light";
6515
- const Icon2 = current2 === "light" ? lucideReact.Sun : current2 === "dark" ? lucideReact.Moon : lucideReact.SunMoon;
6516
- return /* @__PURE__ */ jsxRuntime.jsx(
6517
- "button",
6518
- {
6519
- type: "button",
6520
- onClick: () => setTheme(next),
6521
- "aria-label": `Theme: ${current2}. Switch to ${next}`,
6522
- title: `Theme: ${current2}`,
6523
- className: cn(
6524
- "inline-flex size-10 items-center justify-center rounded-full text-muted-foreground transition-colors hover:bg-accent hover:text-foreground",
6525
- className
6521
+ children: [
6522
+ section.label,
6523
+ /* @__PURE__ */ jsxRuntime.jsx(
6524
+ lucideReact.ChevronRight,
6525
+ {
6526
+ "aria-hidden": true,
6527
+ className: cn("size-3.5 shrink-0 text-oca-subtle transition-transform duration-200", open && "rotate-90")
6528
+ }
6529
+ )
6530
+ ]
6531
+ }
6526
6532
  ),
6527
- children: /* @__PURE__ */ jsxRuntime.jsx(Icon2, { className: "size-[1.125rem]" })
6533
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { id: panel, hidden: !open, className: "mb-2 ml-2.5 mt-0.5 border-l border-border", children: section.items.map((item) => {
6534
+ const on = pathOf(item.href) === here;
6535
+ const badge = typeof item.badge === "string" && STATUS_WORDS.has(item.badge) ? /* @__PURE__ */ jsxRuntime.jsx(StatusBadge, { status: item.badge }) : item.badge ? /* @__PURE__ */ jsxRuntime.jsx(Badge, { tone: "muted", children: item.badge }) : null;
6536
+ return /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsxs(
6537
+ Link6__default.default,
6538
+ {
6539
+ href: item.href,
6540
+ ref: on ? activeRef : void 0,
6541
+ onClick: onNavigate,
6542
+ "aria-current": on ? "page" : void 0,
6543
+ className: cn(
6544
+ "-ml-px flex min-h-9 items-center gap-2 border-l-2 py-1.5 pl-3.5 pr-2 text-[0.875rem] leading-snug transition-colors",
6545
+ on ? "border-foreground font-medium text-foreground" : "border-transparent text-muted-foreground hover:border-oca-hairline-strong hover:text-foreground"
6546
+ ),
6547
+ children: [
6548
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1", children: item.label }),
6549
+ badge
6550
+ ]
6551
+ }
6552
+ ) }, item.href);
6553
+ }) })
6554
+ ] }, section.label);
6555
+ }) });
6556
+ }
6557
+ var DOCS_HEADER_NAV = OCHK_IO_NAV.map((n) => n.href === DOCS_HREF ? { ...n, active: true } : n);
6558
+ function DocsShell({
6559
+ nav,
6560
+ current: current2,
6561
+ navCurrent,
6562
+ header,
6563
+ search,
6564
+ actions,
6565
+ breadcrumbs,
6566
+ toc,
6567
+ pager,
6568
+ footer,
6569
+ children
6570
+ }) {
6571
+ const [menu, setMenu] = react.useState(false);
6572
+ react.useEffect(() => setMenu(false), [current2]);
6573
+ const read = useHeadings("#docs-content", current2);
6574
+ const items = toc ?? read.items;
6575
+ const activeId = toc ? void 0 : read.activeId;
6576
+ const marked = navCurrent ?? current2;
6577
+ const here = pathOf(marked);
6578
+ const place = react.useMemo(() => {
6579
+ for (const s of nav) {
6580
+ const it = s.items.find((i) => pathOf(i.href) === here);
6581
+ if (it) return { section: s.label, page: it.label };
6528
6582
  }
6529
- );
6583
+ return null;
6584
+ }, [nav, here]);
6585
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-h-dvh flex-col bg-background", children: [
6586
+ /* @__PURE__ */ jsxRuntime.jsx(SkipLink, {}),
6587
+ header ?? /* @__PURE__ */ jsxRuntime.jsx(SiteHeader, { home: OCHK_IO, family: "docs", nav: DOCS_HEADER_NAV, search, actions }),
6588
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "sticky top-16 z-30 border-b border-border bg-background/95 backdrop-blur-md supports-[backdrop-filter]:bg-background/90 md:top-[4.5rem] lg:hidden", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "oca-container flex h-12 items-center gap-2", children: /* @__PURE__ */ jsxRuntime.jsxs(Sheet, { open: menu, onOpenChange: setMenu, children: [
6589
+ /* @__PURE__ */ jsxRuntime.jsxs(SheetTrigger, { className: "-ml-2 inline-flex h-10 min-w-0 items-center gap-2 rounded-full px-2.5 text-[0.875rem] hover:bg-accent", children: [
6590
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PanelLeft, { "aria-hidden": true, className: "size-[1.125rem] shrink-0" }),
6591
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Docs menu. " }),
6592
+ place ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 items-center gap-1.5", children: [
6593
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 text-muted-foreground", children: place.section }),
6594
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { "aria-hidden": true, className: "size-3.5 shrink-0 text-oca-subtle" }),
6595
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate font-medium", children: place.page })
6596
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: "Docs" })
6597
+ ] }),
6598
+ /* @__PURE__ */ jsxRuntime.jsxs(SheetContent, { side: "left", className: "w-[min(88vw,22rem)] gap-0 p-0", children: [
6599
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-b border-border px-5 py-4 pr-14", children: /* @__PURE__ */ jsxRuntime.jsx(SheetTitle, { className: "text-[1.0625rem] font-medium", children: "Docs" }) }),
6600
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-y-auto p-3", children: /* @__PURE__ */ jsxRuntime.jsx(DocsNav, { sections: nav, current: marked, onNavigate: () => setMenu(false) }) })
6601
+ ] })
6602
+ ] }) }) }),
6603
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "oca-container flex-1", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "lg:grid lg:grid-cols-[13.5rem_minmax(0,1fr)] lg:gap-x-10 xl:grid-cols-[13.5rem_minmax(0,1fr)_11rem]", children: [
6604
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "sticky top-[4.5rem] hidden max-h-[calc(100dvh-4.5rem)] self-start overflow-y-auto overscroll-contain py-8 pr-1 lg:block", children: /* @__PURE__ */ jsxRuntime.jsx(DocsNav, { sections: nav, current: marked }) }),
6605
+ /* @__PURE__ */ jsxRuntime.jsxs("main", { id: "main-content", className: "min-w-0 pb-16 pt-6 md:pt-8", children: [
6606
+ breadcrumbs ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-6 max-lg:hidden", children: breadcrumbs }) : null,
6607
+ items.length > 1 ? /* @__PURE__ */ jsxRuntime.jsxs("details", { className: "group mb-8 rounded-2xl border border-border bg-card xl:hidden", children: [
6608
+ /* @__PURE__ */ jsxRuntime.jsxs("summary", { className: "flex min-h-12 cursor-pointer list-none items-center justify-between px-4 text-[0.9375rem] font-medium [&::-webkit-details-marker]:hidden", children: [
6609
+ "On this page",
6610
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { "aria-hidden": true, className: "size-4 text-muted-foreground transition-transform group-open:rotate-180" })
6611
+ ] }),
6612
+ /* @__PURE__ */ jsxRuntime.jsx(OnThisPage, { items, activeId, title: null, className: "px-4 pb-4" })
6613
+ ] }) : null,
6614
+ /* @__PURE__ */ jsxRuntime.jsx("article", { id: "docs-content", className: "max-w-[46rem]", children: /* @__PURE__ */ jsxRuntime.jsx(InDocsContext.Provider, { value: true, children }) }),
6615
+ pager ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-16 max-w-[46rem]", children: pager }) : null
6616
+ ] }),
6617
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "sticky top-[4.5rem] hidden max-h-[calc(100dvh-4.5rem)] self-start overflow-y-auto py-10 xl:block", children: items.length > 1 ? /* @__PURE__ */ jsxRuntime.jsx(OnThisPage, { items, activeId }) : null })
6618
+ ] }) }),
6619
+ footer ?? /* @__PURE__ */ jsxRuntime.jsx(OchkIoFooter, {})
6620
+ ] });
6530
6621
  }
6531
6622
  var OCHK_APP_ACCOUNT = "https://ochk.app/me/account";
6623
+ function onHistory(change) {
6624
+ window.addEventListener("popstate", change);
6625
+ return () => window.removeEventListener("popstate", change);
6626
+ }
6627
+ function herePath() {
6628
+ const { href, origin, pathname, search } = window.location;
6629
+ const path = pathname + search;
6630
+ return new URL(path, href).origin === origin ? path : "/";
6631
+ }
6632
+ function routePath(router) {
6633
+ if (!router || router.pathname.includes("[")) return null;
6634
+ return router.basePath && router.pathname === "/" ? router.basePath : router.basePath + router.pathname;
6635
+ }
6636
+ function useSignInHref(path) {
6637
+ const router$1 = router.useRouter();
6638
+ const here = react.useSyncExternalStore(onHistory, herePath, () => routePath(router$1));
6639
+ if (!path) return void 0;
6640
+ return here ? `${path}?return_to=${encodeURIComponent(here)}` : path;
6641
+ }
6532
6642
  function SessionAccountView({
6533
6643
  state,
6534
6644
  name,
6535
6645
  detail,
6536
6646
  items = [],
6537
6647
  signInHref,
6648
+ signInPath,
6538
6649
  signInLabel = "Sign in",
6539
6650
  accountHref = OCHK_APP_ACCOUNT,
6540
6651
  onSignOut,
6541
6652
  nameFrom = "lg"
6542
6653
  }) {
6654
+ const inPlace = useSignInHref(signInPath);
6543
6655
  if (state === "in") {
6544
6656
  return /* @__PURE__ */ jsxRuntime.jsx(
6545
6657
  AccountMenu,
@@ -6562,13 +6674,13 @@ function SessionAccountView({
6562
6674
  }
6563
6675
  return (
6564
6676
  // No box of its own: it sits exactly where the signed-in chip will. While checking it is only unseen.
6565
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: state === "checking" ? "contents invisible" : "contents", "aria-hidden": state === "checking" || void 0, children: /* @__PURE__ */ jsxRuntime.jsx(Button, { asChild: true, size: "sm", variant: "secondary", tabIndex: state === "checking" ? -1 : void 0, children: /* @__PURE__ */ jsxRuntime.jsx("a", { href: signInHref, children: signInLabel }) }) })
6677
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: state === "checking" ? "contents invisible" : "contents", "aria-hidden": state === "checking" || void 0, children: /* @__PURE__ */ jsxRuntime.jsx(Button, { asChild: true, size: "sm", variant: "secondary", tabIndex: state === "checking" ? -1 : void 0, children: /* @__PURE__ */ jsxRuntime.jsx("a", { href: signInHref ?? inPlace ?? "https://ochk.io/signin", children: signInLabel }) }) })
6566
6678
  );
6567
6679
  }
6568
6680
  function ToolShell({
6569
6681
  protocol: protocol2,
6570
6682
  tools,
6571
- home = "/",
6683
+ home,
6572
6684
  account,
6573
6685
  rail = false,
6574
6686
  railFooter,
@@ -6607,7 +6719,7 @@ function ToolShell({
6607
6719
  SiteHeader,
6608
6720
  {
6609
6721
  variant: "tool",
6610
- home,
6722
+ home: home ?? p.pageHref,
6611
6723
  product: p.label,
6612
6724
  family: protocol2,
6613
6725
  nav: tools.map((t) => ({ href: t.href, label: t.label, active: t.active })),
@@ -6667,6 +6779,7 @@ function rehypeCode(options = {}) {
6667
6779
  if (lang && skip.has(lang)) continue;
6668
6780
  const meta = parseCodeMeta(code.data?.meta);
6669
6781
  let source = textOf(code);
6782
+ const newline = /\n$/.test(source);
6670
6783
  const diff = meta.diff || lang === "diff" ? readDiff(source) : null;
6671
6784
  if (diff) source = diff.code;
6672
6785
  const lines = options.tokenize?.(source, lang) ?? highlight(source, lang === "diff" ? void 0 : lang);
@@ -6677,7 +6790,8 @@ function rehypeCode(options = {}) {
6677
6790
  ...lang ? { dataLang: lang } : {},
6678
6791
  ...meta.title ? { dataTitle: meta.title } : {},
6679
6792
  ...diff ? { dataDiff: "" } : {},
6680
- ...meta.lineNumbers ? { dataLineNumbers: "" } : {}
6793
+ ...meta.lineNumbers ? { dataLineNumbers: "" } : {},
6794
+ ...newline ? { dataEol: "" } : {}
6681
6795
  };
6682
6796
  child.children = [];
6683
6797
  continue;
@@ -6698,6 +6812,7 @@ function createMdxComponents({ mermaid } = {}) {
6698
6812
  caption: props["data-title"],
6699
6813
  diff: props["data-diff"] !== void 0,
6700
6814
  lineNumbers: props["data-line-numbers"] !== void 0,
6815
+ trailingNewline: props["data-eol"] !== void 0,
6701
6816
  className: "my-6"
6702
6817
  }
6703
6818
  );
@@ -6724,6 +6839,9 @@ function createMdxComponents({ mermaid } = {}) {
6724
6839
  const heading = (as) => function Heading(props) {
6725
6840
  return /* @__PURE__ */ jsxRuntime.jsx(DocsHeading, { as, ...props });
6726
6841
  };
6842
+ const minor = (Tag) => function Minor({ className, ...props }) {
6843
+ return /* @__PURE__ */ jsxRuntime.jsx(Tag, { className: cn("mb-2 mt-6 scroll-mt-28 text-[0.9375rem] font-medium leading-snug text-foreground", className), ...props });
6844
+ };
6727
6845
  return {
6728
6846
  h1: heading("h1"),
6729
6847
  h2: heading("h2"),
@@ -6732,11 +6850,15 @@ function createMdxComponents({ mermaid } = {}) {
6732
6850
  p: ({ className, ...props }) => /* @__PURE__ */ jsxRuntime.jsx("p", { className: cn("my-4 text-[1rem] leading-[1.75] text-muted-foreground md:text-[1.0625rem]", className), ...props }),
6733
6851
  a: A,
6734
6852
  strong: (props) => /* @__PURE__ */ jsxRuntime.jsx("strong", { className: "font-medium text-foreground", ...props }),
6853
+ h5: minor("h5"),
6854
+ h6: minor("h6"),
6735
6855
  ul: ({ className, ...props }) => /* @__PURE__ */ jsxRuntime.jsx(
6736
6856
  "ul",
6737
6857
  {
6738
6858
  className: cn(
6739
6859
  "my-4 list-disc space-y-1.5 pl-5 text-[1rem] leading-[1.7] text-muted-foreground marker:text-oca-subtle md:text-[1.0625rem]",
6860
+ // A GitHub task list: the box replaces the bullet.
6861
+ className?.includes("contains-task-list") && "list-none pl-0",
6740
6862
  className
6741
6863
  ),
6742
6864
  ...props
@@ -6752,7 +6874,26 @@ function createMdxComponents({ mermaid } = {}) {
6752
6874
  ...props
6753
6875
  }
6754
6876
  ),
6755
- li: ({ className, ...props }) => /* @__PURE__ */ jsxRuntime.jsx("li", { className: cn("pl-1 [&>p]:my-1 [&>ul]:my-1.5 [&>ol]:my-1.5", className), ...props }),
6877
+ li: ({ className, ...props }) => /* @__PURE__ */ jsxRuntime.jsx(
6878
+ "li",
6879
+ {
6880
+ className: cn(
6881
+ "pl-1 [&>p]:my-1 [&>ul]:my-1.5 [&>ol]:my-1.5",
6882
+ // A wrapped task starts under its text, not under the box.
6883
+ className?.includes("task-list-item") && "pl-6 -indent-6",
6884
+ className
6885
+ ),
6886
+ ...props
6887
+ }
6888
+ ),
6889
+ input: (props) => props.type === "checkbox" ? /* @__PURE__ */ jsxRuntime.jsx(
6890
+ "input",
6891
+ {
6892
+ ...props,
6893
+ className: cn("mr-2 size-4 translate-y-[2px] align-baseline accent-foreground", props.className),
6894
+ "aria-label": props.checked ? "Done" : "To do"
6895
+ }
6896
+ ) : /* @__PURE__ */ jsxRuntime.jsx("input", { ...props }),
6756
6897
  blockquote: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx(Callout, { children }),
6757
6898
  hr: () => /* @__PURE__ */ jsxRuntime.jsx("hr", { className: "my-10 border-border" }),
6758
6899
  table: MdxTable,
@@ -6895,6 +7036,7 @@ exports.OCHK_APP_ACCOUNT = OCHK_APP_ACCOUNT;
6895
7036
  exports.OCHK_IO = OCHK_IO;
6896
7037
  exports.OCHK_IO_FOOTER = OCHK_IO_FOOTER;
6897
7038
  exports.OCHK_IO_NAV = OCHK_IO_NAV;
7039
+ exports.OchkIoFooter = OchkIoFooter;
6898
7040
  exports.OnThisPage = OnThisPage;
6899
7041
  exports.PROTOCOLS = PROTOCOLS;
6900
7042
  exports.PROTOCOL_ORDER = PROTOCOL_ORDER;
@@ -7025,6 +7167,7 @@ exports.useDensity = useDensity;
7025
7167
  exports.useHeadings = useHeadings;
7026
7168
  exports.useInView = useInView;
7027
7169
  exports.useShellPlace = useShellPlace;
7170
+ exports.useSignInHref = useSignInHref;
7028
7171
  exports.useTimedOut = useTimedOut;
7029
7172
  //# sourceMappingURL=index.js.map
7030
7173
  //# sourceMappingURL=index.js.map