@orangecheck/app-design 1.3.0 → 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.
package/dist/index.mjs CHANGED
@@ -12,14 +12,14 @@ import * as LabelPrimitive from '@radix-ui/react-label';
12
12
  import * as RadioGroupPrimitive from '@radix-ui/react-radio-group';
13
13
  import * as SelectPrimitive from '@radix-ui/react-select';
14
14
  import * as SwitchPrimitive from '@radix-ui/react-switch';
15
- import { ChevronDown, Check, X, Search, ArrowUpRight, ArrowRight, Copy, ChevronLeft, ChevronRight, CornerDownLeft, Download, FileText, Upload, Menu, PanelLeft, Sun, Moon, SunMoon, CircleUser, LogOut, ArrowLeft, Lock, CircleDashed, CircleMinus, CircleSlash, Clock, CircleX, CircleCheck } from 'lucide-react';
15
+ import { ChevronDown, Check, X, Search, ArrowUpRight, ArrowRight, Copy, ChevronLeft, ChevronRight, CornerDownLeft, Download, FileText, Upload, Menu, Sun, Moon, SunMoon, PanelLeft, CircleUser, LogOut, ArrowLeft, Lock, CircleDashed, CircleMinus, CircleSlash, Clock, CircleX, CircleCheck } from 'lucide-react';
16
16
  import * as DialogPrimitive from '@radix-ui/react-dialog';
17
17
  import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
18
18
  import * as PopoverPrimitive from '@radix-ui/react-popover';
19
19
  import * as TooltipPrimitive from '@radix-ui/react-tooltip';
20
20
  import * as TabsPrimitive from '@radix-ui/react-tabs';
21
21
  import QRCode from 'qrcode';
22
- import Link8 from 'next/link';
22
+ import Link6 from 'next/link';
23
23
  import { useRouter } from 'next/compat/router';
24
24
  import { useTheme } from 'next-themes';
25
25
 
@@ -2971,11 +2971,13 @@ function forClipboard(text, lang) {
2971
2971
  if (!lines.some((l) => l.startsWith("$ "))) return text;
2972
2972
  return lines.filter((l) => l.startsWith("$ ")).map((l) => l.slice(2)).join("\n");
2973
2973
  }
2974
- function linesFromDom(pre) {
2974
+ function linesFromDom(pre, newline) {
2975
2975
  if (!pre) return null;
2976
2976
  const lines = pre.querySelectorAll("[data-line]");
2977
2977
  if (lines.length === 0) return pre.textContent ?? "";
2978
- return Array.from(lines).filter((l) => l.getAttribute("data-diff") !== "remove").map((l) => l.textContent ?? "").join("\n");
2978
+ const text = Array.from(lines).filter((l) => l.getAttribute("data-diff") !== "remove").map((l) => l.textContent ?? "").join("\n");
2979
+ return newline ? `${text}
2980
+ ` : text;
2979
2981
  }
2980
2982
  function prepare(code, lang, marks, diff) {
2981
2983
  const d = diff ? readDiff(code) : null;
@@ -2984,7 +2986,8 @@ function prepare(code, lang, marks, diff) {
2984
2986
  const kept = d ? src.split("\n").filter((_, i) => d.diff.get(i + 1) !== "remove") : null;
2985
2987
  return {
2986
2988
  html: linesToHtml(lines, { highlight: parseLineRanges(marks), diff: d?.diff }),
2987
- copy: kept ? kept.join("\n") : src,
2989
+ // Byte for byte, the final newline too: a hash printed beside the code must match a copy of it.
2990
+ copy: kept ? kept.join("\n") + (/\n$/.test(code) ? "\n" : "") : code,
2988
2991
  lines: lines.length,
2989
2992
  diff: !!d
2990
2993
  };
@@ -3049,6 +3052,7 @@ function CodeBlock({
3049
3052
  code,
3050
3053
  html,
3051
3054
  children,
3055
+ trailingNewline = false,
3052
3056
  lang,
3053
3057
  caption,
3054
3058
  copy = true,
@@ -3069,7 +3073,7 @@ function CodeBlock({
3069
3073
  );
3070
3074
  const markup = prepared?.html ?? html;
3071
3075
  const lines = prepared?.lines ?? (html !== void 0 ? html.split("\n").length : code?.split("\n").length ?? 0);
3072
- const read = () => forClipboard(prepared?.copy ?? linesFromDom(preRef.current) ?? code ?? "", lang);
3076
+ const read = () => forClipboard(prepared?.copy ?? linesFromDom(preRef.current, trailingNewline) ?? code ?? "", lang);
3073
3077
  return /* @__PURE__ */ jsxs("figure", { className: cn(FRAME, className), children: [
3074
3078
  /* @__PURE__ */ jsxs("figcaption", { className: "flex h-11 items-center justify-between gap-3 border-b border-[var(--oca-code-line)] pl-5 pr-2", children: [
3075
3079
  /* @__PURE__ */ jsx("span", { className: "truncate text-[0.8125rem] text-oca-ink-subtle", children: caption ?? languageName(lang) ?? "Code" }),
@@ -3586,7 +3590,7 @@ function ErrorPage({
3586
3590
  /* @__PURE__ */ jsx("p", { className: "oca-lead oca-enter [--enter-delay:150ms]", children: detail ?? words.detail }),
3587
3591
  /* @__PURE__ */ jsx("div", { className: "oca-enter flex flex-wrap gap-3 [--enter-delay:230ms]", children: actions ?? /* @__PURE__ */ jsxs(Fragment, { children: [
3588
3592
  server ? /* @__PURE__ */ jsx(Button, { onClick: () => window.location.reload(), children: "Try again" }) : null,
3589
- /* @__PURE__ */ jsx(Button, { asChild: true, variant: server ? "secondary" : "primary", children: /* @__PURE__ */ jsx(Link8, { href: home, children: "Go home" }) })
3593
+ /* @__PURE__ */ jsx(Button, { asChild: true, variant: server ? "secondary" : "primary", children: /* @__PURE__ */ jsx(Link6, { href: home, children: "Go home" }) })
3590
3594
  ] }) })
3591
3595
  ] }),
3592
3596
  art !== null ? /* @__PURE__ */ jsx("div", { "aria-hidden": true, className: "oca-enter hidden justify-center md:col-span-5 md:flex [--enter-delay:120ms]", children: art ?? /* @__PURE__ */ jsx(MarkOutline, { className: "w-full max-w-[20rem] text-oca-hairline-strong" }) }) : null
@@ -3705,16 +3709,25 @@ function Faq({
3705
3709
  return /* @__PURE__ */ jsx(Accordion, { single: true, className, children: items.map((it, i) => /* @__PURE__ */ jsx(AccordionItem, { id: it.id, title: it.q, children: it.a }, it.id ?? i)) });
3706
3710
  }
3707
3711
  var LINK = "text-foreground underline decoration-foreground/35 underline-offset-4 transition-colors hover:decoration-foreground";
3712
+ var SCHEME = /^[a-z][a-z\d+.-]*:/i;
3713
+ function useResolved(href) {
3714
+ const router = useRouter();
3715
+ if (!router || !href || href.startsWith("/") || href.startsWith("#") || href.startsWith("?") || SCHEME.test(href)) return href;
3716
+ const here = router.asPath.split(/[?#]/)[0] || "/";
3717
+ const url = new URL(href, `https://page.invalid${here}`);
3718
+ return url.pathname + url.search + url.hash;
3719
+ }
3708
3720
  function TextLink({
3709
- href,
3721
+ href: written,
3710
3722
  children,
3711
3723
  external,
3712
3724
  className
3713
3725
  }) {
3726
+ const href = useResolved(written);
3714
3727
  const internal = href.startsWith("/") && !href.startsWith("/api/") && !href.startsWith("/.well-known/");
3715
3728
  const offsite = external ?? /^https?:\/\//.test(href);
3716
3729
  if (internal && !offsite) {
3717
- return /* @__PURE__ */ jsx(Link8, { href, className: cn(LINK, className), children });
3730
+ return /* @__PURE__ */ jsx(Link6, { href, className: cn(LINK, className), children });
3718
3731
  }
3719
3732
  return /* @__PURE__ */ jsxs("a", { href, className: cn(LINK, className), ...offsite ? { target: "_blank", rel: "noreferrer" } : {}, children: [
3720
3733
  children,
@@ -3982,6 +3995,10 @@ var OCHK_IO_FOOTER = [
3982
3995
  ]
3983
3996
  }
3984
3997
  ];
3998
+ var InDocsContext = sharedContext("in-docs", false);
3999
+ function useInDocs() {
4000
+ return useContext(InDocsContext);
4001
+ }
3985
4002
  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";
3986
4003
  var STRETCH = 'outline-none after:absolute after:inset-0 after:rounded-[1.25rem] after:content-[""]';
3987
4004
  var pad2 = (n) => String(n + 1).padStart(2, "0");
@@ -3990,6 +4007,7 @@ function ProtocolGrid({
3990
4007
  link = "page",
3991
4008
  className
3992
4009
  }) {
4010
+ const inDocs = useInDocs();
3993
4011
  return /* @__PURE__ */ jsx("ul", { className: cn("grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 md:gap-5", className), children: protocols.map((slug) => {
3994
4012
  const p = protocolSite(slug);
3995
4013
  const i = PROTOCOL_ORDER.indexOf(slug);
@@ -4002,7 +4020,7 @@ function ProtocolGrid({
4002
4020
  ] }),
4003
4021
  p.status !== "live" ? /* @__PURE__ */ jsx(StatusBadge, { status: p.status }) : null
4004
4022
  ] }),
4005
- /* @__PURE__ */ jsx("h3", { className: "oca-display-3", children: /* @__PURE__ */ jsx(
4023
+ /* @__PURE__ */ jsx("h3", { className: "oca-display-3", children: link === "docs" && inDocs ? /* @__PURE__ */ jsx(Link6, { href: `/${p.slug}`, className: STRETCH, children: p.label }) : /* @__PURE__ */ jsx(
4006
4024
  "a",
4007
4025
  {
4008
4026
  href: link === "tool" ? p.toolHref : link === "docs" ? `${DOCS_HREF}/${p.slug}` : p.pageHref,
@@ -4060,752 +4078,795 @@ function AppGrid({
4060
4078
  const list = sites ? sites.map((slug) => FAMILY.find((s) => s.slug === slug)).filter((s) => s !== void 0) : FAMILY.filter((s) => s.group === group);
4061
4079
  return /* @__PURE__ */ jsx("ul", { className: cn("grid grid-cols-1 gap-4 sm:grid-cols-2 md:gap-5", className), children: list.map((s) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(AppCard, { name: s.label, line: s.line, href: s.href, protocols: s.protocols, status: s.status }) }, s.slug)) });
4062
4080
  }
4063
- function ProtocolHero({
4064
- protocol: protocol2,
4081
+ var isInternal = (href) => href.startsWith("/") || href.startsWith("#");
4082
+ function DocLink({ href, className, children, ...rest }) {
4083
+ return isInternal(href) ? /* @__PURE__ */ jsx(Link6, { href, className, ...rest, children }) : /* @__PURE__ */ jsx("a", { href, className, ...rest, children });
4084
+ }
4085
+ function Breadcrumbs({ items, action, className }) {
4086
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex min-h-11 items-center justify-between gap-4 sm:min-h-0", className), children: [
4087
+ /* @__PURE__ */ jsx("nav", { "aria-label": "Breadcrumb", className: "min-w-0", children: /* @__PURE__ */ jsx("ol", { className: "flex min-w-0 items-center gap-1.5 text-[0.875rem] text-muted-foreground", children: items.map((c, i) => {
4088
+ const last = i === items.length - 1;
4089
+ return /* @__PURE__ */ jsxs("li", { className: cn("flex items-center gap-1.5", last ? "min-w-0" : "shrink-0"), children: [
4090
+ c.href && !last ? /* @__PURE__ */ 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__ */ jsx("span", { "aria-current": last ? "page" : void 0, className: cn("truncate", last && "text-foreground"), children: c.label }),
4091
+ !last ? /* @__PURE__ */ jsx(ChevronRight, { "aria-hidden": true, className: "size-3.5 shrink-0 text-oca-subtle" }) : null
4092
+ ] }, i);
4093
+ }) }) }),
4094
+ action ? /* @__PURE__ */ jsx("div", { className: "shrink-0 text-[0.875rem]", children: action }) : null
4095
+ ] });
4096
+ }
4097
+ function DocsPager({ prev, next, className }) {
4098
+ if (!prev && !next) return null;
4099
+ const card = (l, dir) => /* @__PURE__ */ jsxs(
4100
+ DocLink,
4101
+ {
4102
+ href: l.href,
4103
+ className: cn(
4104
+ "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",
4105
+ dir === "next" && "items-end text-right sm:col-start-2"
4106
+ ),
4107
+ children: [
4108
+ /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1.5 text-[0.8125rem] text-muted-foreground", children: [
4109
+ dir === "prev" ? /* @__PURE__ */ jsx(ArrowLeft, { "aria-hidden": true, className: "size-3.5" }) : null,
4110
+ dir === "prev" ? "Previous" : "Next",
4111
+ l.section ? /* @__PURE__ */ jsx("span", { "aria-hidden": true, children: "\xB7" }) : null,
4112
+ l.section ? /* @__PURE__ */ jsx("span", { className: "truncate", children: l.section }) : null,
4113
+ dir === "next" ? /* @__PURE__ */ jsx(ArrowRight, { "aria-hidden": true, className: "size-3.5" }) : null
4114
+ ] }),
4115
+ /* @__PURE__ */ jsx("span", { className: "text-[1rem] font-medium leading-snug text-foreground", children: l.label })
4116
+ ]
4117
+ }
4118
+ );
4119
+ return /* @__PURE__ */ 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: [
4120
+ prev ? card(prev, "prev") : null,
4121
+ next ? card(next, "next") : null
4122
+ ] });
4123
+ }
4124
+ function useHeadings(selector = "#docs-content", key) {
4125
+ const [items, setItems] = useState([]);
4126
+ useEffect(() => {
4127
+ const read = () => {
4128
+ const root = document.querySelector(selector);
4129
+ if (!root) return setItems([]);
4130
+ setItems(
4131
+ Array.from(root.querySelectorAll("h2[id], h3[id]")).map((h) => ({
4132
+ id: h.id,
4133
+ // The anchor link's "#" is not part of the name.
4134
+ label: (h.querySelector("[data-heading-text]") ?? h).textContent?.trim() ?? "",
4135
+ level: h.tagName === "H3" ? 3 : 2
4136
+ }))
4137
+ );
4138
+ };
4139
+ const raf = requestAnimationFrame(read);
4140
+ const t = setTimeout(read, 80);
4141
+ return () => {
4142
+ cancelAnimationFrame(raf);
4143
+ clearTimeout(t);
4144
+ };
4145
+ }, [selector, key]);
4146
+ const activeId = useActiveHeading(items.map((i) => i.id));
4147
+ return { items, activeId };
4148
+ }
4149
+ function OnThisPage({
4150
+ items,
4151
+ activeId,
4152
+ title = "On this page",
4153
+ onNavigate,
4154
+ className
4155
+ }) {
4156
+ const id = useId();
4157
+ if (items.length === 0) return null;
4158
+ return (
4159
+ // With no visible title (a folded list under its own summary) the name is still "On this page".
4160
+ /* @__PURE__ */ jsxs("nav", { "aria-labelledby": title ? id : void 0, "aria-label": title ? void 0 : "On this page", className, children: [
4161
+ title ? /* @__PURE__ */ jsx("p", { id, className: "mb-3 text-[0.875rem] font-medium", children: title }) : null,
4162
+ /* @__PURE__ */ jsx("ul", { children: items.map((t) => {
4163
+ const on = t.id === activeId;
4164
+ return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
4165
+ "a",
4166
+ {
4167
+ href: `#${t.id}`,
4168
+ onClick: onNavigate,
4169
+ "aria-current": on ? "location" : void 0,
4170
+ className: cn(
4171
+ "block border-l py-1.5 text-[0.875rem] leading-snug transition-colors",
4172
+ t.level === 3 ? "pl-7" : "pl-4",
4173
+ on ? "border-foreground text-foreground" : "border-border text-muted-foreground hover:text-foreground"
4174
+ ),
4175
+ children: t.label
4176
+ }
4177
+ ) }, t.id);
4178
+ }) })
4179
+ ] })
4180
+ );
4181
+ }
4182
+ var CALLOUT_TONE = { note: "neutral", warning: "brand", danger: "danger" };
4183
+ function Callout({
4184
+ tone = "note",
4065
4185
  title,
4066
- lead,
4067
- actions,
4068
- art,
4069
4186
  children,
4070
4187
  className
4071
4188
  }) {
4072
- const p = protocolSite(protocol2);
4073
4189
  return /* @__PURE__ */ jsx(
4074
- PageHero,
4190
+ Notice,
4075
4191
  {
4076
- className,
4077
- eyebrow: `Protocol \xB7 ${p.verb}`,
4192
+ tone: CALLOUT_TONE[tone],
4078
4193
  title,
4079
- lead,
4080
- actions,
4081
- art,
4082
- children: p.status !== "live" || children ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-start gap-4", children: [
4083
- p.status !== "live" ? /* @__PURE__ */ jsx(StatusBadge, { status: p.status }) : null,
4084
- children
4085
- ] }) : null
4194
+ role: "note",
4195
+ className: cn("my-6 [&_p]:my-0 [&_p]:text-[0.9375rem] [&_p]:leading-relaxed [&_p+p]:mt-3", className),
4196
+ children
4086
4197
  }
4087
4198
  );
4088
4199
  }
4089
- function ProtocolNav({
4090
- current: current2,
4091
- link = "page",
4092
- className
4093
- }) {
4094
- return /* @__PURE__ */ jsx("nav", { "aria-label": "Protocols", className, children: /* @__PURE__ */ jsx(ScrollFade, { fade: "var(--background)", children: /* @__PURE__ */ jsx("ul", { className: "flex w-max min-w-full items-center gap-6 border-b border-border", children: PROTOCOLS.map((p) => {
4095
- const on = p.slug === current2;
4096
- return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
4097
- "a",
4098
- {
4099
- href: link === "tool" ? p.toolHref : p.pageHref,
4100
- "aria-current": on ? "page" : void 0,
4101
- className: cn(
4102
- "-mb-px inline-flex h-11 items-center border-b-2 text-[0.9375rem] transition-colors",
4103
- on ? "border-foreground text-foreground" : "border-transparent text-muted-foreground hover:text-foreground"
4104
- ),
4105
- children: p.label
4106
- }
4107
- ) }, p.slug);
4108
- }) }) }) });
4109
- }
4110
- function SpecCard({
4111
- protocol: protocol2,
4112
- version,
4113
- license,
4114
- vectors,
4115
- size = "md",
4116
- className
4117
- }) {
4118
- const p = protocolSite(protocol2);
4119
- const repo = `oc-${p.slug}-protocol`;
4120
- const facts = [
4121
- ["Version", version],
4122
- ...license ? [["Licence", license]] : [],
4123
- ["Nostr kind", p.kinds],
4124
- ...vectors !== void 0 ? [["Test vectors", String(vectors)]] : []
4125
- ];
4126
- if (size === "sm") {
4127
- return /* @__PURE__ */ jsxs(
4128
- "a",
4200
+ function Step({ title, id, children }) {
4201
+ return /* @__PURE__ */ jsxs("li", { className: "relative pb-8 pl-11 last:pb-0 [counter-increment:oca-step]", children: [
4202
+ /* @__PURE__ */ jsx(
4203
+ "span",
4129
4204
  {
4130
- href: p.specHref,
4131
- className: cn(
4132
- "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",
4133
- className
4134
- ),
4135
- children: [
4136
- /* @__PURE__ */ jsx("span", { className: "font-mono text-[0.8125rem] text-foreground", children: repo }),
4137
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: facts.map(([k, v]) => k === "Version" ? `v${v}` : k === "Nostr kind" ? `kind ${v}` : v).join(" \xB7 ") }),
4138
- /* @__PURE__ */ jsxs("span", { className: "ml-auto flex items-center gap-1 text-muted-foreground group-hover:text-foreground", children: [
4139
- "Read the spec ",
4140
- /* @__PURE__ */ jsx(ArrowUpRight, { "aria-hidden": true, className: "size-4" })
4141
- ] })
4142
- ]
4205
+ "aria-hidden": true,
4206
+ 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)]"
4143
4207
  }
4144
- );
4145
- }
4146
- return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-6 rounded-[1.25rem] border border-border bg-card p-6 md:p-8", className), children: [
4147
- /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-4", children: [
4148
- /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col gap-1.5", children: [
4149
- /* @__PURE__ */ jsx("p", { className: "text-[0.875rem] text-muted-foreground", children: "The spec" }),
4150
- /* @__PURE__ */ jsx("h3", { className: "oca-title break-all font-mono text-[1.0625rem] tracking-normal", children: repo })
4151
- ] }),
4152
- p.status !== "live" ? /* @__PURE__ */ jsx(StatusBadge, { status: p.status }) : null
4153
- ] }),
4154
- /* @__PURE__ */ jsx("dl", { className: "grid grid-cols-2 gap-x-6 gap-y-4 sm:grid-cols-4", children: facts.map(([k, v]) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
4155
- /* @__PURE__ */ jsx("dt", { className: "text-[0.8125rem] text-muted-foreground", children: k }),
4156
- /* @__PURE__ */ jsx("dd", { className: "oca-tabular text-[1.0625rem]", children: v })
4157
- ] }, k)) }),
4158
- /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Button, { asChild: true, variant: "secondary", size: "sm", children: /* @__PURE__ */ jsxs("a", { href: p.specHref, children: [
4159
- "Read the spec ",
4160
- /* @__PURE__ */ jsx(ArrowUpRight, { "aria-hidden": true })
4161
- ] }) }) })
4208
+ ),
4209
+ /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "absolute bottom-1 left-[0.8125rem] top-9 w-px bg-border" }),
4210
+ /* @__PURE__ */ jsx("h3", { id, className: "scroll-mt-28 pt-0.5 text-[1.0625rem] font-medium leading-snug tracking-[-0.008em] text-foreground", children: title }),
4211
+ /* @__PURE__ */ jsx("div", { className: "mt-2 text-muted-foreground [&>*:first-child]:mt-0 [&>*:last-child]:mb-0", children })
4162
4212
  ] });
4163
4213
  }
4164
- function VerifyBox({
4165
- action,
4166
- param = "q",
4214
+ function Steps({ children, className }) {
4215
+ return /* @__PURE__ */ 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 });
4216
+ }
4217
+ function LinkCard({
4218
+ href,
4167
4219
  title,
4168
4220
  description,
4169
- label = "Id, envelope or link",
4170
- placeholder,
4171
- hint,
4172
- submitLabel = "Verify",
4173
- multiline = false,
4174
- onVerify,
4221
+ icon,
4222
+ meta,
4175
4223
  className
4176
4224
  }) {
4177
- const [value, setValue] = useState("");
4178
- const submit = (e) => {
4179
- if (!onVerify) return;
4180
- e.preventDefault();
4181
- if (value.trim()) onVerify(value.trim());
4182
- };
4183
- const button = /* @__PURE__ */ jsx(Button, { type: "submit", className: multiline ? void 0 : "w-full sm:w-auto", children: submitLabel });
4225
+ const Arrow = isInternal(href) ? ArrowRight : ArrowUpRight;
4184
4226
  return /* @__PURE__ */ jsxs(
4185
- "form",
4227
+ DocLink,
4186
4228
  {
4187
- action,
4188
- method: "get",
4189
- onSubmit: submit,
4190
- className: cn("flex flex-col gap-5 rounded-[1.25rem] border border-border bg-card p-6 md:p-8", className),
4229
+ href,
4230
+ className: cn(
4231
+ "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",
4232
+ className
4233
+ ),
4191
4234
  children: [
4192
- title || description ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
4193
- title ? /* @__PURE__ */ jsx("h3", { className: "oca-title", children: title }) : null,
4194
- description ? /* @__PURE__ */ jsx("p", { className: "oca-body text-[0.9375rem]", children: description }) : null
4195
- ] }) : null,
4196
- multiline ? /* @__PURE__ */ jsxs(Fragment, { children: [
4197
- /* @__PURE__ */ jsx(Field, { label, hint, children: /* @__PURE__ */ jsx(
4198
- Textarea,
4199
- {
4200
- name: param,
4201
- required: true,
4202
- value,
4203
- onChange: (e) => setValue(e.target.value),
4204
- placeholder,
4205
- spellCheck: false,
4206
- className: "min-h-32 font-mono text-base md:text-[0.8125rem]"
4207
- }
4208
- ) }),
4209
- /* @__PURE__ */ jsx("div", { children: button })
4210
- ] }) : /* @__PURE__ */ jsx(Field, { label, hint, action: button, children: /* @__PURE__ */ jsx(
4211
- Input,
4212
- {
4213
- name: param,
4214
- required: true,
4215
- value,
4216
- onChange: (e) => setValue(e.target.value),
4217
- placeholder,
4218
- spellCheck: false,
4219
- autoComplete: "off",
4220
- className: "font-mono text-base md:text-[0.875rem]"
4221
- }
4222
- ) })
4235
+ /* @__PURE__ */ jsxs("span", { className: "flex items-start justify-between gap-3", children: [
4236
+ icon ? /* @__PURE__ */ 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__ */ jsx("span", { className: "text-[1rem] font-medium leading-snug text-foreground", children: title }),
4237
+ /* @__PURE__ */ jsxs("span", { className: "flex shrink-0 items-center gap-2", children: [
4238
+ meta,
4239
+ /* @__PURE__ */ jsx(Arrow, { "aria-hidden": true, className: "size-4 text-muted-foreground transition-transform group-hover:translate-x-0.5 group-hover:text-foreground" })
4240
+ ] })
4241
+ ] }),
4242
+ icon ? /* @__PURE__ */ jsx("span", { className: "text-[1rem] font-medium leading-snug text-foreground", children: title }) : null,
4243
+ description ? /* @__PURE__ */ jsx("span", { className: "text-[0.9375rem] leading-relaxed text-muted-foreground", children: description }) : null
4223
4244
  ]
4224
4245
  }
4225
4246
  );
4226
4247
  }
4227
- var TINT = "bg-[color-mix(in_oklab,var(--oca-orange)_9%,var(--card))]";
4228
- function ComparisonTable({
4229
- columns,
4248
+ function CardGrid({ columns = 2, children, className }) {
4249
+ return /* @__PURE__ */ 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 });
4250
+ }
4251
+ function MdxTable({ className, ...props }) {
4252
+ return /* @__PURE__ */ jsx("div", { className: "not-prose my-6 overflow-hidden rounded-2xl border border-border bg-card", children: /* @__PURE__ */ jsx(ScrollFade, { fade: "var(--card)", children: /* @__PURE__ */ jsx(
4253
+ "table",
4254
+ {
4255
+ className: cn(
4256
+ "w-full border-collapse text-left text-[0.875rem] leading-relaxed",
4257
+ "[&_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",
4258
+ "[&_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",
4259
+ "[&_td_code]:bg-transparent [&_td_code]:p-0 [&_td_code]:text-foreground [&_td:first-child]:text-foreground",
4260
+ "[&_[align=center]]:text-center [&_[align=right]]:text-right",
4261
+ // On a phone a cell keeps a readable width; the table scrolls instead of crushing it.
4262
+ "max-sm:[&_td]:min-w-[9rem]",
4263
+ className
4264
+ ),
4265
+ ...props
4266
+ }
4267
+ ) }) });
4268
+ }
4269
+ var said = (n) => n !== void 0 && n !== null && n !== false && n !== "";
4270
+ function ApiTable({
4230
4271
  rows,
4231
- label,
4232
- propertyHeading = "Property",
4272
+ caption,
4273
+ nameHeader = "Name",
4233
4274
  className
4234
4275
  }) {
4235
- const wide = columns.length > 3;
4236
- const grid = wide ? "lg:grid lg:grid-cols-[var(--oca-compare)]" : "md:grid md:grid-cols-[var(--oca-compare)]";
4237
- const desk = wide ? "lg" : "md";
4238
- const style = {
4239
- // The argued-for column gets a little more room: its answers carry the page.
4240
- "--oca-compare": ["minmax(0, 1.4fr)", ...columns.map((c) => c.highlight ? "minmax(0, 1.3fr)" : "minmax(0, 1fr)")].join(" ")
4276
+ const hasDefault = rows.some((r) => r.default !== void 0);
4277
+ const hasDescription = rows.some((r) => said(r.description));
4278
+ const hasSource = rows.some((r) => said(r.source));
4279
+ const cell = "px-4 py-3 max-sm:p-0";
4280
+ return /* @__PURE__ */ jsx("div", { className: cn("not-prose my-6 overflow-hidden rounded-2xl border border-border bg-card", className), children: /* @__PURE__ */ jsx(ScrollFade, { fade: "var(--card)", children: /* @__PURE__ */ jsxs("table", { className: "w-full border-collapse text-left text-[0.875rem] max-sm:block", children: [
4281
+ caption ? /* @__PURE__ */ jsx("caption", { className: "sr-only", children: caption }) : null,
4282
+ /* @__PURE__ */ jsx("thead", { className: "max-sm:sr-only", children: /* @__PURE__ */ jsxs("tr", { className: "border-b border-oca-hairline-strong bg-oca-table-head text-[0.8125rem]", children: [
4283
+ /* @__PURE__ */ jsx("th", { scope: "col", className: "px-4 py-2.5 font-medium", children: nameHeader }),
4284
+ /* @__PURE__ */ jsx("th", { scope: "col", className: "px-4 py-2.5 font-medium", children: "Type" }),
4285
+ hasDefault ? /* @__PURE__ */ jsx("th", { scope: "col", className: "px-4 py-2.5 font-medium", children: "Default" }) : null,
4286
+ hasDescription ? /* @__PURE__ */ jsx("th", { scope: "col", className: "px-4 py-2.5 font-medium", children: "Description" }) : null,
4287
+ hasSource ? /* @__PURE__ */ jsx("th", { scope: "col", className: "px-4 py-2.5 font-medium", children: "Defined in" }) : null
4288
+ ] }) }),
4289
+ /* @__PURE__ */ jsx("tbody", { className: "divide-y divide-border max-sm:block", children: rows.map((r) => /* @__PURE__ */ jsxs(
4290
+ "tr",
4291
+ {
4292
+ id: r.id,
4293
+ 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",
4294
+ children: [
4295
+ /* @__PURE__ */ jsx("th", { scope: "row", className: cn(cell, "text-left font-normal"), children: /* @__PURE__ */ jsxs("span", { className: "flex flex-col items-start gap-1 max-sm:flex-row max-sm:flex-wrap max-sm:items-baseline max-sm:gap-x-2", children: [
4296
+ /* @__PURE__ */ jsx("code", { className: cn("font-mono text-[0.8125rem] text-foreground max-sm:text-[0.875rem]", r.deprecated && "line-through decoration-oca-subtle"), children: r.name }),
4297
+ r.required ? /* @__PURE__ */ jsx("span", { className: "text-[0.75rem] text-oca-accent-ink", children: "Required" }) : null,
4298
+ r.deprecated ? /* @__PURE__ */ jsx(Badge, { tone: "muted", children: "Deprecated" }) : null,
4299
+ r.status ? /* @__PURE__ */ jsx(StatusBadge, { status: r.status }) : null
4300
+ ] }) }),
4301
+ /* @__PURE__ */ jsx("td", { className: cn(cell, "font-mono text-[0.8125rem] text-muted-foreground max-sm:break-all", !said(r.type) && "max-sm:hidden"), children: r.type ?? "\u2014" }),
4302
+ hasDefault ? /* @__PURE__ */ jsxs("td", { className: cn(cell, "font-mono text-[0.8125rem] text-muted-foreground max-sm:order-last", r.default === void 0 && "max-sm:hidden"), children: [
4303
+ /* @__PURE__ */ jsx("span", { className: "font-sans sm:hidden", children: "Default " }),
4304
+ r.default ?? "\u2014"
4305
+ ] }) : null,
4306
+ hasDescription ? /* @__PURE__ */ jsx("td", { className: cn(cell, "leading-relaxed text-muted-foreground", !said(r.description) && "max-sm:hidden"), children: r.description }) : null,
4307
+ hasSource ? /* @__PURE__ */ jsx("td", { className: cn(cell, "text-[0.8125rem] text-muted-foreground max-sm:order-last max-sm:break-all", !said(r.source) && "max-sm:hidden"), children: r.source }) : null
4308
+ ]
4309
+ },
4310
+ r.id ?? r.name
4311
+ )) })
4312
+ ] }) }) });
4313
+ }
4314
+ function useDarkMode() {
4315
+ const [dark, setDark] = useState(false);
4316
+ useEffect(() => {
4317
+ const root = document.documentElement;
4318
+ const read = () => setDark(root.classList.contains("dark"));
4319
+ read();
4320
+ const mo = new MutationObserver(read);
4321
+ mo.observe(root, { attributes: true, attributeFilter: ["class"] });
4322
+ return () => mo.disconnect();
4323
+ }, []);
4324
+ return dark;
4325
+ }
4326
+ function mermaidTheme(el) {
4327
+ const css = getComputedStyle(el);
4328
+ const v = (name) => css.getPropertyValue(name).trim();
4329
+ const card = v("--card");
4330
+ const muted = v("--muted");
4331
+ const text = v("--foreground");
4332
+ const subtle = v("--muted-foreground");
4333
+ const line = v("--input");
4334
+ const hair = v("--oca-hairline-strong");
4335
+ return {
4336
+ background: "transparent",
4337
+ fontFamily: css.fontFamily,
4338
+ fontSize: "14px",
4339
+ textColor: text,
4340
+ mainBkg: card,
4341
+ primaryColor: card,
4342
+ primaryTextColor: text,
4343
+ primaryBorderColor: hair,
4344
+ secondaryColor: muted,
4345
+ secondaryTextColor: text,
4346
+ secondaryBorderColor: hair,
4347
+ tertiaryColor: muted,
4348
+ tertiaryTextColor: text,
4349
+ tertiaryBorderColor: hair,
4350
+ nodeBorder: hair,
4351
+ lineColor: line,
4352
+ edgeLabelBackground: card,
4353
+ clusterBkg: muted,
4354
+ clusterBorder: hair,
4355
+ titleColor: text,
4356
+ noteBkgColor: muted,
4357
+ noteTextColor: text,
4358
+ noteBorderColor: hair,
4359
+ actorBkg: card,
4360
+ actorBorder: hair,
4361
+ actorTextColor: text,
4362
+ actorLineColor: line,
4363
+ signalColor: text,
4364
+ signalTextColor: text,
4365
+ labelBoxBkgColor: card,
4366
+ labelBoxBorderColor: hair,
4367
+ labelTextColor: text,
4368
+ loopTextColor: subtle,
4369
+ activationBkgColor: muted,
4370
+ activationBorderColor: hair,
4371
+ sequenceNumberColor: card
4241
4372
  };
4242
- const ordered = [...columns].sort((a, b) => Number(Boolean(b.highlight)) - Number(Boolean(a.highlight)));
4243
- return /* @__PURE__ */ jsxs("ul", { "aria-label": label, style, className: cn("divide-y divide-border rounded-[1.25rem] border border-border bg-card", className), children: [
4244
- /* @__PURE__ */ jsxs(
4245
- "li",
4373
+ }
4374
+ var FIT = 4 / 3;
4375
+ function naturalSize(svg) {
4376
+ const w = svg.match(/viewBox="[\d.-]+ [\d.-]+ ([\d.]+) [\d.]+"/)?.[1];
4377
+ if (!w) return { svg, width: null };
4378
+ const width = Math.ceil(Number(w));
4379
+ return {
4380
+ svg: svg.replace(/<svg([^>]*?)\swidth="100%"/, `<svg$1 width="${width}"`).replace(/max-width:\s*[\d.]+px;?/, ""),
4381
+ width
4382
+ };
4383
+ }
4384
+ function useInnerWidth(ref, padding) {
4385
+ const [width, setWidth] = useState(null);
4386
+ useEffect(() => {
4387
+ const el = ref.current;
4388
+ if (!el) return;
4389
+ const ro = new ResizeObserver(() => setWidth(el.clientWidth - padding));
4390
+ ro.observe(el);
4391
+ return () => ro.disconnect();
4392
+ }, [ref, padding]);
4393
+ return width;
4394
+ }
4395
+ function Diagram({ chart, caption, load, className }) {
4396
+ const ref = useRef(null);
4397
+ const dark = useDarkMode();
4398
+ const raw = useId();
4399
+ const [drawn, setDrawn] = useState(null);
4400
+ const [failed, setFailed] = useState(false);
4401
+ const room = useInnerWidth(ref, 48);
4402
+ const fits = drawn?.width != null && room != null && drawn.width <= room * FIT;
4403
+ useEffect(() => {
4404
+ let live = true;
4405
+ const el = ref.current;
4406
+ if (!el) return;
4407
+ (async () => {
4408
+ try {
4409
+ const mod = await load();
4410
+ const mermaid = "default" in mod ? mod.default : mod;
4411
+ mermaid.initialize({ startOnLoad: false, securityLevel: "strict", theme: "base", themeVariables: mermaidTheme(el) });
4412
+ const { svg } = await mermaid.render(`oca-diagram-${raw.replace(/[^a-zA-Z0-9]/g, "")}-${dark ? "d" : "l"}`, chart);
4413
+ if (live) {
4414
+ setDrawn(naturalSize(svg));
4415
+ setFailed(false);
4416
+ }
4417
+ } catch {
4418
+ if (live) setFailed(true);
4419
+ }
4420
+ })();
4421
+ return () => {
4422
+ live = false;
4423
+ };
4424
+ }, [chart, dark, load, raw]);
4425
+ if (failed) return /* @__PURE__ */ jsx(CodeBlock, { code: chart, caption: "Diagram (shown as its source)", className: cn("my-6", className) });
4426
+ return /* @__PURE__ */ jsxs("figure", { ref, className: cn("not-prose my-6 overflow-hidden rounded-[1.25rem] border border-border bg-card", className), children: [
4427
+ drawn ? /* @__PURE__ */ jsx(ScrollFade, { fade: "var(--card)", children: /* @__PURE__ */ jsx(
4428
+ "div",
4246
4429
  {
4247
- "aria-hidden": true,
4430
+ "data-fit": fits ? "" : void 0,
4248
4431
  className: cn(
4249
- "hidden gap-5 px-5 py-4 text-[0.875rem] font-medium text-muted-foreground",
4250
- wide ? "lg:grid lg:px-8" : "md:grid md:px-8",
4251
- grid
4432
+ "flex justify-center p-6 [&_svg]:h-auto",
4433
+ fits ? "w-full [&_svg]:max-w-full" : "w-max min-w-full [&_svg]:max-w-none"
4252
4434
  ),
4253
- children: [
4254
- /* @__PURE__ */ jsx("span", { children: propertyHeading }),
4255
- columns.map((c) => /* @__PURE__ */ jsx("span", { className: cn(c.highlight && cn(TINT, "-my-4 px-4 py-4 text-oca-accent-ink")), children: c.label }, c.key))
4256
- ]
4435
+ role: "img",
4436
+ "aria-label": typeof caption === "string" ? caption : "Diagram",
4437
+ dangerouslySetInnerHTML: { __html: drawn.svg }
4257
4438
  }
4258
- ),
4259
- rows.map((r, ri) => /* @__PURE__ */ jsxs("li", { className: cn("grid grid-cols-1 gap-3 px-5 py-5", wide ? "lg:items-start lg:gap-5 lg:px-8" : "md:items-start md:gap-5 md:px-8", grid), children: [
4260
- /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col gap-1", children: [
4261
- /* @__PURE__ */ jsx("span", { className: "oca-title-sm", children: r.label }),
4262
- r.note ? /* @__PURE__ */ jsx("span", { className: "text-[0.875rem] leading-snug text-muted-foreground", children: r.note }) : null
4263
- ] }),
4264
- /* @__PURE__ */ jsx("div", { className: cn("grid grid-cols-2 gap-1", desk === "lg" ? "lg:contents" : "md:contents"), children: columns.map((c) => {
4265
- return /* @__PURE__ */ jsxs(
4266
- "div",
4267
- {
4268
- style: { "--oca-order": ordered.indexOf(c) },
4269
- className: cn(
4270
- // Two rows of the pair's grid (name, answer), so answers line up
4271
- // across a pair even when one name wraps.
4272
- "order-[var(--oca-order)] row-span-2 grid min-w-0 grid-rows-subgrid gap-1 rounded-xl px-3 py-2.5",
4273
- 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",
4274
- c.highlight ? cn(
4275
- TINT,
4276
- "col-span-2",
4277
- 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"
4278
- ) : desk === "lg" ? "lg:p-0" : "md:p-0"
4279
- ),
4280
- children: [
4281
- /* @__PURE__ */ jsx(
4282
- "span",
4283
- {
4284
- className: cn(
4285
- "text-[0.8125rem]",
4286
- c.highlight ? "text-oca-accent-ink" : "text-muted-foreground",
4287
- desk === "lg" ? "lg:sr-only" : "md:sr-only"
4288
- ),
4289
- children: c.label
4290
- }
4291
- ),
4292
- /* @__PURE__ */ jsx("span", { className: cn("text-[0.9375rem]", c.highlight && "font-medium"), children: r.values[c.key] ?? "\u2014" })
4293
- ]
4294
- },
4295
- c.key
4296
- );
4297
- }) })
4298
- ] }, ri))
4439
+ ) }) : /* @__PURE__ */ jsx("div", { role: "status", "aria-label": "Drawing the diagram", className: "p-6", children: /* @__PURE__ */ jsx(Skeleton, { className: "h-40 w-full rounded-xl" }) }),
4440
+ caption ? /* @__PURE__ */ jsx("figcaption", { className: "border-t border-border px-5 py-3 text-[0.8125rem] text-muted-foreground", children: caption }) : null
4299
4441
  ] });
4300
4442
  }
4301
- var CHECK = {
4302
- ok: { word: "Passed", icon: /* @__PURE__ */ jsx(CircleCheck, {}), tone: "text-success" },
4303
- fail: { word: "Failed", icon: /* @__PURE__ */ jsx(CircleX, {}), tone: "text-destructive" },
4304
- pending: { word: "Pending", icon: /* @__PURE__ */ jsx(Clock, {}), tone: "text-oca-accent-ink" },
4305
- none: { word: "None", icon: /* @__PURE__ */ jsx(CircleSlash, {}), tone: "text-muted-foreground" },
4306
- skipped: { word: "Skipped", icon: /* @__PURE__ */ jsx(CircleMinus, {}), tone: "text-muted-foreground" },
4307
- unchecked: { word: "Not checked", icon: /* @__PURE__ */ jsx(CircleDashed, {}), tone: "text-oca-subtle" }
4443
+ var HEADING = {
4444
+ h1: "oca-display-3 mb-4 text-foreground",
4445
+ h2: "mb-3 mt-12 text-[1.375rem] font-medium leading-tight tracking-[-0.015em] text-foreground md:text-[1.5rem]",
4446
+ h3: "mb-2 mt-9 text-[1.125rem] font-medium leading-snug tracking-[-0.01em] text-foreground",
4447
+ h4: "mb-2 mt-7 text-[1rem] font-medium leading-snug text-foreground"
4308
4448
  };
4309
- function VerifyReport({
4310
- verdict,
4311
- title,
4312
- summary,
4313
- checks,
4314
- facts,
4315
- notChecked,
4316
- actions,
4317
- as: Heading = "h2",
4318
- className
4449
+ function DocsHeading({
4450
+ as: Tag,
4451
+ id,
4452
+ children,
4453
+ className,
4454
+ ...props
4319
4455
  }) {
4320
- return /* @__PURE__ */ jsxs(
4321
- "section",
4322
- {
4323
- "aria-label": "Verification result",
4324
- className: cn("overflow-hidden rounded-[1.25rem] border border-border bg-card", className),
4325
- children: [
4326
- /* @__PURE__ */ jsxs("header", { className: "flex flex-col items-start gap-3 p-6 md:p-8", children: [
4327
- /* @__PURE__ */ jsx(StatusBadge, { status: verdict }),
4328
- /* @__PURE__ */ jsx(Heading, { className: "oca-display-3 [overflow-wrap:anywhere]", children: title }),
4329
- summary ? /* @__PURE__ */ jsx("p", { className: "oca-body max-w-[40rem] [overflow-wrap:anywhere]", children: summary }) : null
4330
- ] }),
4331
- /* @__PURE__ */ jsx("ul", { "aria-label": "Checks", className: "divide-y divide-border border-t border-border", children: checks.map((c, i) => {
4332
- const k = CHECK[c.state];
4333
- return /* @__PURE__ */ jsxs("li", { className: "flex items-start gap-3 px-6 py-3.5 md:px-8", children: [
4334
- /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: cn("mt-0.5 shrink-0 [&_svg]:size-[1.125rem]", k.tone), children: k.icon }),
4335
- /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-0.5 sm:flex-row sm:items-baseline sm:justify-between sm:gap-6", children: [
4336
- /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col gap-0.5", children: [
4337
- /* @__PURE__ */ jsx("span", { className: "text-[0.9375rem]", children: c.label }),
4338
- c.note ? /* @__PURE__ */ jsx("span", { className: "break-words text-[0.8125rem] leading-snug text-muted-foreground", children: c.note }) : null
4339
- ] }),
4340
- /* @__PURE__ */ jsx(
4341
- "span",
4342
- {
4343
- className: cn(
4344
- "shrink-0 text-[0.8125rem]",
4345
- c.state === "fail" ? "text-destructive" : "text-muted-foreground"
4346
- ),
4347
- children: k.word
4348
- }
4349
- )
4350
- ] })
4351
- ] }, i);
4352
- }) }),
4353
- facts && facts.length > 0 ? /* @__PURE__ */ jsx(KeyValueList, { items: facts, className: "rounded-none border-x-0 border-b-0 bg-transparent [&>div]:px-6 md:[&>div]:px-8" }) : null,
4354
- notChecked && notChecked.length > 0 ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 border-t border-border bg-muted/50 px-6 py-5 md:px-8", children: [
4355
- /* @__PURE__ */ jsx("p", { className: "text-[0.875rem] font-medium", children: "What this did not check" }),
4356
- /* @__PURE__ */ jsx("ul", { className: "flex list-disc flex-col gap-1 pl-5 text-[0.875rem] leading-relaxed text-muted-foreground", children: notChecked.map((n, i) => /* @__PURE__ */ jsx("li", { children: n }, i)) })
4357
- ] }) : null,
4358
- actions ? /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-3 border-t border-border px-6 py-5 md:px-8", children: actions }) : null
4359
- ]
4360
- }
4361
- );
4362
- }
4363
- function SignMessage({
4364
- lead,
4365
- address,
4366
- message,
4367
- wallets,
4368
- busy = false,
4369
- error,
4370
- submitLabel = "Confirm",
4371
- secondary,
4372
- onSignature,
4373
- className
4374
- }) {
4375
- const [pasted, setPasted] = useState("");
4376
- return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-5", className), children: [
4377
- lead ? /* @__PURE__ */ jsx("p", { className: "text-[0.9375rem] leading-relaxed", children: lead }) : null,
4378
- wallets ? /* @__PURE__ */ jsxs(Fragment, { children: [
4379
- /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2", children: wallets }),
4380
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 text-[0.8125rem] text-muted-foreground", children: [
4381
- /* @__PURE__ */ jsx("span", { className: "h-px flex-1 bg-border" }),
4382
- "or sign it in any wallet",
4383
- /* @__PURE__ */ jsx("span", { className: "h-px flex-1 bg-border" })
4384
- ] })
4385
- ] }) : null,
4386
- /* @__PURE__ */ jsx(CodeBlock, { code: message, caption: "Message to sign" }),
4387
- /* @__PURE__ */ jsxs(
4388
- "form",
4456
+ return /* @__PURE__ */ jsxs(Tag, { id, className: cn("group scroll-mt-28", HEADING[Tag], className), ...props, children: [
4457
+ /* @__PURE__ */ jsx("span", { "data-heading-text": "", children }),
4458
+ id && Tag !== "h1" ? /* @__PURE__ */ jsxs(
4459
+ "a",
4389
4460
  {
4390
- className: "flex flex-col gap-4",
4391
- onSubmit: (e) => {
4392
- e.preventDefault();
4393
- if (pasted.trim()) onSignature(pasted.trim());
4394
- },
4461
+ href: `#${id}`,
4462
+ 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",
4395
4463
  children: [
4396
- /* @__PURE__ */ jsx(
4397
- Field,
4398
- {
4399
- label: "Signature",
4400
- error,
4401
- hint: /* @__PURE__ */ jsxs(Fragment, { children: [
4402
- "From your wallet\u2019s \u201Csign message\u201D (BIP-322), signed by",
4403
- " ",
4404
- /* @__PURE__ */ jsx("span", { className: "break-all font-mono", children: address }),
4405
- "."
4406
- ] }),
4407
- children: /* @__PURE__ */ jsx(
4408
- Textarea,
4409
- {
4410
- value: pasted,
4411
- onChange: (e) => setPasted(e.target.value),
4412
- rows: 3,
4413
- spellCheck: false,
4414
- className: "min-h-24 font-mono text-base md:text-[0.8125rem]"
4415
- }
4416
- )
4417
- }
4418
- ),
4419
- /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-2", children: [
4420
- /* @__PURE__ */ jsx(Button, { type: "submit", loading: busy, disabled: !pasted.trim(), children: submitLabel }),
4421
- secondary
4422
- ] })
4464
+ /* @__PURE__ */ jsx("span", { "aria-hidden": true, children: "#" }),
4465
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Link to this section" })
4423
4466
  ]
4424
4467
  }
4425
- )
4426
- ] });
4427
- }
4428
- var isInternal = (href) => href.startsWith("/") || href.startsWith("#");
4429
- function DocLink({ href, className, children, ...rest }) {
4430
- return isInternal(href) ? /* @__PURE__ */ jsx(Link8, { href, className, ...rest, children }) : /* @__PURE__ */ jsx("a", { href, className, ...rest, children });
4431
- }
4432
- function Breadcrumbs({ items, action, className }) {
4433
- return /* @__PURE__ */ jsxs("div", { className: cn("flex min-h-11 items-center justify-between gap-4 sm:min-h-0", className), children: [
4434
- /* @__PURE__ */ jsx("nav", { "aria-label": "Breadcrumb", className: "min-w-0", children: /* @__PURE__ */ jsx("ol", { className: "flex min-w-0 items-center gap-1.5 text-[0.875rem] text-muted-foreground", children: items.map((c, i) => {
4435
- const last = i === items.length - 1;
4436
- return /* @__PURE__ */ jsxs("li", { className: cn("flex items-center gap-1.5", last ? "min-w-0" : "shrink-0"), children: [
4437
- c.href && !last ? /* @__PURE__ */ 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__ */ jsx("span", { "aria-current": last ? "page" : void 0, className: cn("truncate", last && "text-foreground"), children: c.label }),
4438
- !last ? /* @__PURE__ */ jsx(ChevronRight, { "aria-hidden": true, className: "size-3.5 shrink-0 text-oca-subtle" }) : null
4439
- ] }, i);
4440
- }) }) }),
4441
- action ? /* @__PURE__ */ jsx("div", { className: "shrink-0 text-[0.875rem]", children: action }) : null
4442
- ] });
4443
- }
4444
- function DocsPager({ prev, next, className }) {
4445
- if (!prev && !next) return null;
4446
- const card = (l, dir) => /* @__PURE__ */ jsxs(
4447
- DocLink,
4448
- {
4449
- href: l.href,
4450
- className: cn(
4451
- "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",
4452
- dir === "next" && "items-end text-right sm:col-start-2"
4453
- ),
4454
- children: [
4455
- /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1.5 text-[0.8125rem] text-muted-foreground", children: [
4456
- dir === "prev" ? /* @__PURE__ */ jsx(ArrowLeft, { "aria-hidden": true, className: "size-3.5" }) : null,
4457
- dir === "prev" ? "Previous" : "Next",
4458
- l.section ? /* @__PURE__ */ jsx("span", { "aria-hidden": true, children: "\xB7" }) : null,
4459
- l.section ? /* @__PURE__ */ jsx("span", { className: "truncate", children: l.section }) : null,
4460
- dir === "next" ? /* @__PURE__ */ jsx(ArrowRight, { "aria-hidden": true, className: "size-3.5" }) : null
4461
- ] }),
4462
- /* @__PURE__ */ jsx("span", { className: "text-[1rem] font-medium leading-snug text-foreground", children: l.label })
4463
- ]
4464
- }
4465
- );
4466
- return /* @__PURE__ */ 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: [
4467
- prev ? card(prev, "prev") : null,
4468
- next ? card(next, "next") : null
4468
+ ) : null
4469
4469
  ] });
4470
4470
  }
4471
- function useHeadings(selector = "#docs-content", key) {
4472
- const [items, setItems] = useState([]);
4473
- useEffect(() => {
4474
- const read = () => {
4475
- const root = document.querySelector(selector);
4476
- if (!root) return setItems([]);
4477
- setItems(
4478
- Array.from(root.querySelectorAll("h2[id], h3[id]")).map((h) => ({
4479
- id: h.id,
4480
- // The anchor link's "#" is not part of the name.
4481
- label: (h.querySelector("[data-heading-text]") ?? h).textContent?.trim() ?? "",
4482
- level: h.tagName === "H3" ? 3 : 2
4483
- }))
4484
- );
4485
- };
4486
- const raf = requestAnimationFrame(read);
4487
- const t = setTimeout(read, 80);
4488
- return () => {
4489
- cancelAnimationFrame(raf);
4490
- clearTimeout(t);
4491
- };
4492
- }, [selector, key]);
4493
- const activeId = useActiveHeading(items.map((i) => i.id));
4494
- return { items, activeId };
4471
+ function codeText(node) {
4472
+ if (typeof node === "string") return node;
4473
+ if (typeof node === "number") return String(node);
4474
+ if (Array.isArray(node)) return node.map(codeText).join("");
4475
+ if (isValidElement(node)) return codeText(node.props.children);
4476
+ return "";
4495
4477
  }
4496
- function OnThisPage({
4497
- items,
4498
- activeId,
4499
- title = "On this page",
4500
- onNavigate,
4501
- className
4502
- }) {
4503
- const id = useId();
4504
- if (items.length === 0) return null;
4505
- return (
4506
- // With no visible title (a folded list under its own summary) the name is still "On this page".
4507
- /* @__PURE__ */ jsxs("nav", { "aria-labelledby": title ? id : void 0, "aria-label": title ? void 0 : "On this page", className, children: [
4508
- title ? /* @__PURE__ */ jsx("p", { id, className: "mb-3 text-[0.875rem] font-medium", children: title }) : null,
4509
- /* @__PURE__ */ jsx("ul", { children: items.map((t) => {
4510
- const on = t.id === activeId;
4511
- return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
4512
- "a",
4513
- {
4514
- href: `#${t.id}`,
4515
- onClick: onNavigate,
4516
- "aria-current": on ? "location" : void 0,
4517
- className: cn(
4518
- "block border-l py-1.5 text-[0.875rem] leading-snug transition-colors",
4519
- t.level === 3 ? "pl-7" : "pl-4",
4520
- on ? "border-foreground text-foreground" : "border-border text-muted-foreground hover:text-foreground"
4521
- ),
4522
- children: t.label
4523
- }
4524
- ) }, t.id);
4525
- }) })
4526
- ] })
4527
- );
4478
+ function codeLang(node) {
4479
+ const child = Children.toArray(node)[0];
4480
+ if (!isValidElement(child)) return void 0;
4481
+ const cls = child.props.className ?? "";
4482
+ return cls.match(/language-([\w+-]+)/)?.[1];
4528
4483
  }
4529
- var CALLOUT_TONE = { note: "neutral", warning: "brand", danger: "danger" };
4530
- function Callout({
4531
- tone = "note",
4484
+ function ProtocolHero({
4485
+ protocol: protocol2,
4532
4486
  title,
4487
+ lead,
4488
+ actions,
4489
+ art,
4533
4490
  children,
4534
4491
  className
4535
4492
  }) {
4493
+ const p = protocolSite(protocol2);
4536
4494
  return /* @__PURE__ */ jsx(
4537
- Notice,
4495
+ PageHero,
4538
4496
  {
4539
- tone: CALLOUT_TONE[tone],
4497
+ className,
4498
+ eyebrow: `Protocol \xB7 ${p.verb}`,
4540
4499
  title,
4541
- role: "note",
4542
- className: cn("my-6 [&_p]:my-0 [&_p]:text-[0.9375rem] [&_p]:leading-relaxed [&_p+p]:mt-3", className),
4543
- children
4500
+ lead,
4501
+ actions,
4502
+ art,
4503
+ children: p.status !== "live" || children ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-start gap-4", children: [
4504
+ p.status !== "live" ? /* @__PURE__ */ jsx(StatusBadge, { status: p.status }) : null,
4505
+ children
4506
+ ] }) : null
4544
4507
  }
4545
4508
  );
4546
4509
  }
4547
- function Step({ title, id, children }) {
4548
- return /* @__PURE__ */ jsxs("li", { className: "relative pb-8 pl-11 last:pb-0 [counter-increment:oca-step]", children: [
4549
- /* @__PURE__ */ jsx(
4550
- "span",
4510
+ function ProtocolNav({
4511
+ current: current2,
4512
+ link = "page",
4513
+ className
4514
+ }) {
4515
+ return /* @__PURE__ */ jsx("nav", { "aria-label": "Protocols", className, children: /* @__PURE__ */ jsx(ScrollFade, { fade: "var(--background)", children: /* @__PURE__ */ jsx("ul", { className: "flex w-max min-w-full items-center gap-6 border-b border-border", children: PROTOCOLS.map((p) => {
4516
+ const on = p.slug === current2;
4517
+ return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
4518
+ "a",
4551
4519
  {
4552
- "aria-hidden": true,
4553
- 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)]"
4554
- }
4555
- ),
4556
- /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "absolute bottom-1 left-[0.8125rem] top-9 w-px bg-border" }),
4557
- /* @__PURE__ */ jsx("h3", { id, className: "scroll-mt-28 pt-0.5 text-[1.0625rem] font-medium leading-snug tracking-[-0.008em] text-foreground", children: title }),
4558
- /* @__PURE__ */ jsx("div", { className: "mt-2 text-muted-foreground [&>*:first-child]:mt-0 [&>*:last-child]:mb-0", children })
4520
+ href: link === "tool" ? p.toolHref : p.pageHref,
4521
+ "aria-current": on ? "page" : void 0,
4522
+ className: cn(
4523
+ "-mb-px inline-flex h-11 items-center border-b-2 text-[0.9375rem] transition-colors",
4524
+ on ? "border-foreground text-foreground" : "border-transparent text-muted-foreground hover:text-foreground"
4525
+ ),
4526
+ children: p.label
4527
+ }
4528
+ ) }, p.slug);
4529
+ }) }) }) });
4530
+ }
4531
+ var SPEC_FILE = {
4532
+ spec: {
4533
+ file: "SPEC.md",
4534
+ title: "Normative source",
4535
+ note: "This page is a human-readable summary. The authoritative copy lives in the spec repo. If the two ever drift, the repo wins."
4536
+ },
4537
+ security: {
4538
+ file: "SECURITY.md",
4539
+ title: "Normative threat model",
4540
+ note: "This page is the short form. The authoritative, numbered threat model lives in the spec repo."
4541
+ },
4542
+ rationale: {
4543
+ file: "WHY.md",
4544
+ title: "Design rationale",
4545
+ note: "This page is the short version. The full rationale and the rejected-design log live in the spec repo."
4546
+ }
4547
+ };
4548
+ function SpecCard(props) {
4549
+ return props.repo !== void 0 ? /* @__PURE__ */ jsx(SpecFileNote, { ...props }) : /* @__PURE__ */ jsx(ProtocolSpecCard, { ...props });
4550
+ }
4551
+ function SpecFileNote({ repo, file, kind = "spec", version, note, className }) {
4552
+ const d = SPEC_FILE[kind];
4553
+ const f = file ?? d.file;
4554
+ return /* @__PURE__ */ jsxs(Callout, { title: version ? `${d.title} \xB7 ${version}` : d.title, className, children: [
4555
+ /* @__PURE__ */ jsx("p", { children: note ?? d.note }),
4556
+ /* @__PURE__ */ jsx("p", { children: /* @__PURE__ */ jsx(TextLink, { href: `https://github.com/orangecheck/${repo}/blob/main/${f}`, className: "break-all font-mono text-[0.875rem]", children: `${repo}/${f}` }) })
4559
4557
  ] });
4560
4558
  }
4561
- function Steps({ children, className }) {
4562
- return /* @__PURE__ */ 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 });
4559
+ function ProtocolSpecCard({ protocol: protocol2, version, license, vectors, size = "md", className }) {
4560
+ const p = protocolSite(protocol2);
4561
+ const repo = `oc-${p.slug}-protocol`;
4562
+ const facts = [
4563
+ ["Version", version],
4564
+ ...license ? [["Licence", license]] : [],
4565
+ ["Nostr kind", p.kinds],
4566
+ ...vectors !== void 0 ? [["Test vectors", String(vectors)]] : []
4567
+ ];
4568
+ if (size === "sm") {
4569
+ return /* @__PURE__ */ jsxs(
4570
+ "a",
4571
+ {
4572
+ href: p.specHref,
4573
+ className: cn(
4574
+ "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",
4575
+ className
4576
+ ),
4577
+ children: [
4578
+ /* @__PURE__ */ jsx("span", { className: "font-mono text-[0.8125rem] text-foreground", children: repo }),
4579
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: facts.map(([k, v]) => k === "Version" ? `v${v}` : k === "Nostr kind" ? `kind ${v}` : v).join(" \xB7 ") }),
4580
+ /* @__PURE__ */ jsxs("span", { className: "ml-auto flex items-center gap-1 text-muted-foreground group-hover:text-foreground", children: [
4581
+ "Read the spec ",
4582
+ /* @__PURE__ */ jsx(ArrowUpRight, { "aria-hidden": true, className: "size-4" })
4583
+ ] })
4584
+ ]
4585
+ }
4586
+ );
4587
+ }
4588
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-6 rounded-[1.25rem] border border-border bg-card p-6 md:p-8", className), children: [
4589
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-4", children: [
4590
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col gap-1.5", children: [
4591
+ /* @__PURE__ */ jsx("p", { className: "text-[0.875rem] text-muted-foreground", children: "The spec" }),
4592
+ /* @__PURE__ */ jsx("h3", { className: "oca-title break-all font-mono text-[1.0625rem] tracking-normal", children: repo })
4593
+ ] }),
4594
+ p.status !== "live" ? /* @__PURE__ */ jsx(StatusBadge, { status: p.status }) : null
4595
+ ] }),
4596
+ /* @__PURE__ */ jsx("dl", { className: "grid grid-cols-2 gap-x-6 gap-y-4 sm:grid-cols-4", children: facts.map(([k, v]) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
4597
+ /* @__PURE__ */ jsx("dt", { className: "text-[0.8125rem] text-muted-foreground", children: k }),
4598
+ /* @__PURE__ */ jsx("dd", { className: "oca-tabular text-[1.0625rem]", children: v })
4599
+ ] }, k)) }),
4600
+ /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Button, { asChild: true, variant: "secondary", size: "sm", children: /* @__PURE__ */ jsxs("a", { href: p.specHref, children: [
4601
+ "Read the spec ",
4602
+ /* @__PURE__ */ jsx(ArrowUpRight, { "aria-hidden": true })
4603
+ ] }) }) })
4604
+ ] });
4563
4605
  }
4564
- function LinkCard({
4565
- href,
4606
+ function VerifyBox({
4607
+ action,
4608
+ param = "q",
4566
4609
  title,
4567
4610
  description,
4568
- icon,
4569
- meta,
4611
+ label = "Id, envelope or link",
4612
+ placeholder,
4613
+ hint,
4614
+ submitLabel = "Verify",
4615
+ multiline = false,
4616
+ onVerify,
4570
4617
  className
4571
4618
  }) {
4572
- const Arrow = isInternal(href) ? ArrowRight : ArrowUpRight;
4619
+ const [value, setValue] = useState("");
4620
+ const submit = (e) => {
4621
+ if (!onVerify) return;
4622
+ e.preventDefault();
4623
+ if (value.trim()) onVerify(value.trim());
4624
+ };
4625
+ const button = /* @__PURE__ */ jsx(Button, { type: "submit", className: multiline ? void 0 : "w-full sm:w-auto", children: submitLabel });
4573
4626
  return /* @__PURE__ */ jsxs(
4574
- DocLink,
4627
+ "form",
4575
4628
  {
4576
- href,
4577
- className: cn(
4578
- "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",
4579
- className
4580
- ),
4629
+ action,
4630
+ method: "get",
4631
+ onSubmit: submit,
4632
+ className: cn("flex flex-col gap-5 rounded-[1.25rem] border border-border bg-card p-6 md:p-8", className),
4581
4633
  children: [
4582
- /* @__PURE__ */ jsxs("span", { className: "flex items-start justify-between gap-3", children: [
4583
- icon ? /* @__PURE__ */ 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__ */ jsx("span", { className: "text-[1rem] font-medium leading-snug text-foreground", children: title }),
4584
- /* @__PURE__ */ jsxs("span", { className: "flex shrink-0 items-center gap-2", children: [
4585
- meta,
4586
- /* @__PURE__ */ jsx(Arrow, { "aria-hidden": true, className: "size-4 text-muted-foreground transition-transform group-hover:translate-x-0.5 group-hover:text-foreground" })
4587
- ] })
4588
- ] }),
4589
- icon ? /* @__PURE__ */ jsx("span", { className: "text-[1rem] font-medium leading-snug text-foreground", children: title }) : null,
4590
- description ? /* @__PURE__ */ jsx("span", { className: "text-[0.9375rem] leading-relaxed text-muted-foreground", children: description }) : null
4634
+ title || description ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
4635
+ title ? /* @__PURE__ */ jsx("h3", { className: "oca-title", children: title }) : null,
4636
+ description ? /* @__PURE__ */ jsx("p", { className: "oca-body text-[0.9375rem]", children: description }) : null
4637
+ ] }) : null,
4638
+ multiline ? /* @__PURE__ */ jsxs(Fragment, { children: [
4639
+ /* @__PURE__ */ jsx(Field, { label, hint, children: /* @__PURE__ */ jsx(
4640
+ Textarea,
4641
+ {
4642
+ name: param,
4643
+ required: true,
4644
+ value,
4645
+ onChange: (e) => setValue(e.target.value),
4646
+ placeholder,
4647
+ spellCheck: false,
4648
+ className: "min-h-32 font-mono text-base md:text-[0.8125rem]"
4649
+ }
4650
+ ) }),
4651
+ /* @__PURE__ */ jsx("div", { children: button })
4652
+ ] }) : /* @__PURE__ */ jsx(Field, { label, hint, action: button, children: /* @__PURE__ */ jsx(
4653
+ Input,
4654
+ {
4655
+ name: param,
4656
+ required: true,
4657
+ value,
4658
+ onChange: (e) => setValue(e.target.value),
4659
+ placeholder,
4660
+ spellCheck: false,
4661
+ autoComplete: "off",
4662
+ className: "font-mono text-base md:text-[0.875rem]"
4663
+ }
4664
+ ) })
4591
4665
  ]
4592
4666
  }
4593
4667
  );
4594
4668
  }
4595
- function CardGrid({ columns = 2, children, className }) {
4596
- return /* @__PURE__ */ 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 });
4597
- }
4598
- function MdxTable({ className, ...props }) {
4599
- return /* @__PURE__ */ jsx("div", { className: "not-prose my-6 overflow-hidden rounded-2xl border border-border bg-card", children: /* @__PURE__ */ jsx(ScrollFade, { fade: "var(--card)", children: /* @__PURE__ */ jsx(
4600
- "table",
4601
- {
4602
- className: cn(
4603
- "w-full border-collapse text-left text-[0.875rem] leading-relaxed",
4604
- "[&_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",
4605
- "[&_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",
4606
- "[&_td_code]:bg-transparent [&_td_code]:p-0 [&_td_code]:text-foreground [&_td:first-child]:text-foreground",
4607
- "[&_[align=center]]:text-center [&_[align=right]]:text-right",
4608
- // On a phone a cell keeps a readable width; the table scrolls instead of crushing it.
4609
- "max-sm:[&_td]:min-w-[9rem]",
4610
- className
4611
- ),
4612
- ...props
4613
- }
4614
- ) }) });
4615
- }
4616
- function ApiTable({
4669
+ var TINT = "bg-[color-mix(in_oklab,var(--oca-orange)_9%,var(--card))]";
4670
+ function ComparisonTable({
4671
+ columns,
4617
4672
  rows,
4618
- caption,
4619
- nameHeader = "Name",
4673
+ label,
4674
+ propertyHeading = "Property",
4620
4675
  className
4621
4676
  }) {
4622
- const hasDefault = rows.some((r) => r.default !== void 0);
4623
- const marks = (r) => /* @__PURE__ */ jsxs(Fragment, { children: [
4624
- r.required ? /* @__PURE__ */ jsx("span", { className: "text-[0.75rem] text-oca-accent-ink", children: "Required" }) : null,
4625
- r.deprecated ? /* @__PURE__ */ jsx(Badge, { tone: "muted", children: "Deprecated" }) : null,
4626
- r.status ? /* @__PURE__ */ jsx(StatusBadge, { status: r.status }) : null
4627
- ] });
4628
- return /* @__PURE__ */ jsxs("div", { className: cn("not-prose my-6", className), children: [
4629
- /* @__PURE__ */ jsx("div", { className: "overflow-hidden rounded-2xl border border-border bg-card max-sm:hidden", children: /* @__PURE__ */ jsx(ScrollFade, { fade: "var(--card)", children: /* @__PURE__ */ jsxs("table", { className: "w-full border-collapse text-left text-[0.875rem]", children: [
4630
- caption ? /* @__PURE__ */ jsx("caption", { className: "sr-only", children: caption }) : null,
4631
- /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { className: "border-b border-oca-hairline-strong bg-oca-table-head text-[0.8125rem]", children: [
4632
- /* @__PURE__ */ jsx("th", { scope: "col", className: "px-4 py-2.5 font-medium", children: nameHeader }),
4633
- /* @__PURE__ */ jsx("th", { scope: "col", className: "px-4 py-2.5 font-medium", children: "Type" }),
4634
- hasDefault ? /* @__PURE__ */ jsx("th", { scope: "col", className: "px-4 py-2.5 font-medium", children: "Default" }) : null,
4635
- /* @__PURE__ */ jsx("th", { scope: "col", className: "px-4 py-2.5 font-medium", children: "Description" })
4636
- ] }) }),
4637
- /* @__PURE__ */ jsx("tbody", { className: "divide-y divide-border", children: rows.map((r) => /* @__PURE__ */ jsxs("tr", { className: "align-top", children: [
4638
- /* @__PURE__ */ jsx("th", { scope: "row", className: "px-4 py-3 text-left font-normal", children: /* @__PURE__ */ jsxs("span", { className: "flex flex-col items-start gap-1", children: [
4639
- /* @__PURE__ */ jsx("code", { className: cn("font-mono text-[0.8125rem] text-foreground", r.deprecated && "line-through decoration-oca-subtle"), children: r.name }),
4640
- marks(r)
4641
- ] }) }),
4642
- /* @__PURE__ */ jsx("td", { className: "px-4 py-3 font-mono text-[0.8125rem] text-muted-foreground", children: r.type ?? "\u2014" }),
4643
- hasDefault ? /* @__PURE__ */ jsx("td", { className: "px-4 py-3 font-mono text-[0.8125rem] text-muted-foreground", children: r.default ?? "\u2014" }) : null,
4644
- /* @__PURE__ */ jsx("td", { className: "px-4 py-3 leading-relaxed text-muted-foreground", children: r.description })
4645
- ] }, r.name)) })
4646
- ] }) }) }),
4647
- /* @__PURE__ */ jsx("ul", { "aria-label": caption, className: "divide-y divide-border rounded-2xl border border-border bg-card sm:hidden", children: rows.map((r) => /* @__PURE__ */ jsxs("li", { className: "flex flex-col gap-1.5 px-4 py-3.5", children: [
4648
- /* @__PURE__ */ jsxs("span", { className: "flex flex-wrap items-baseline gap-x-2 gap-y-1", children: [
4649
- /* @__PURE__ */ jsx("code", { className: cn("font-mono text-[0.875rem] text-foreground", r.deprecated && "line-through decoration-oca-subtle"), children: r.name }),
4650
- r.type ? /* @__PURE__ */ jsx("code", { className: "break-all font-mono text-[0.8125rem] text-muted-foreground", children: r.type }) : null
4677
+ const wide = columns.length > 3;
4678
+ const grid = wide ? "lg:grid lg:grid-cols-[var(--oca-compare)]" : "md:grid md:grid-cols-[var(--oca-compare)]";
4679
+ const desk = wide ? "lg" : "md";
4680
+ const style = {
4681
+ // The argued-for column gets a little more room: its answers carry the page.
4682
+ "--oca-compare": ["minmax(0, 1.4fr)", ...columns.map((c) => c.highlight ? "minmax(0, 1.3fr)" : "minmax(0, 1fr)")].join(" ")
4683
+ };
4684
+ const ordered = [...columns].sort((a, b) => Number(Boolean(b.highlight)) - Number(Boolean(a.highlight)));
4685
+ return /* @__PURE__ */ jsxs("ul", { "aria-label": label, style, className: cn("divide-y divide-border rounded-[1.25rem] border border-border bg-card", className), children: [
4686
+ /* @__PURE__ */ jsxs(
4687
+ "li",
4688
+ {
4689
+ "aria-hidden": true,
4690
+ className: cn(
4691
+ "hidden gap-5 px-5 py-4 text-[0.875rem] font-medium text-muted-foreground",
4692
+ wide ? "lg:grid lg:px-8" : "md:grid md:px-8",
4693
+ grid
4694
+ ),
4695
+ children: [
4696
+ /* @__PURE__ */ jsx("span", { children: propertyHeading }),
4697
+ columns.map((c) => /* @__PURE__ */ jsx("span", { className: cn(c.highlight && cn(TINT, "-my-4 px-4 py-4 text-oca-accent-ink")), children: c.label }, c.key))
4698
+ ]
4699
+ }
4700
+ ),
4701
+ rows.map((r, ri) => /* @__PURE__ */ jsxs("li", { className: cn("grid grid-cols-1 gap-3 px-5 py-5", wide ? "lg:items-start lg:gap-5 lg:px-8" : "md:items-start md:gap-5 md:px-8", grid), children: [
4702
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col gap-1", children: [
4703
+ /* @__PURE__ */ jsx("span", { className: "oca-title-sm", children: r.label }),
4704
+ r.note ? /* @__PURE__ */ jsx("span", { className: "text-[0.875rem] leading-snug text-muted-foreground", children: r.note }) : null
4651
4705
  ] }),
4652
- /* @__PURE__ */ jsx("span", { className: "flex flex-wrap items-center gap-2 empty:hidden", children: marks(r) }),
4653
- r.description ? /* @__PURE__ */ jsx("span", { className: "text-[0.875rem] leading-relaxed text-muted-foreground", children: r.description }) : null,
4654
- r.default !== void 0 ? /* @__PURE__ */ jsxs("span", { className: "text-[0.8125rem] text-muted-foreground", children: [
4655
- "Default ",
4656
- /* @__PURE__ */ jsx("code", { className: "font-mono text-foreground", children: r.default })
4657
- ] }) : null
4658
- ] }, r.name)) })
4706
+ /* @__PURE__ */ jsx("div", { className: cn("grid grid-cols-2 gap-1", desk === "lg" ? "lg:contents" : "md:contents"), children: columns.map((c) => {
4707
+ return /* @__PURE__ */ jsxs(
4708
+ "div",
4709
+ {
4710
+ style: { "--oca-order": ordered.indexOf(c) },
4711
+ className: cn(
4712
+ // Two rows of the pair's grid (name, answer), so answers line up
4713
+ // across a pair even when one name wraps.
4714
+ "order-[var(--oca-order)] row-span-2 grid min-w-0 grid-rows-subgrid gap-1 rounded-xl px-3 py-2.5",
4715
+ 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",
4716
+ c.highlight ? cn(
4717
+ TINT,
4718
+ "col-span-2",
4719
+ 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"
4720
+ ) : desk === "lg" ? "lg:p-0" : "md:p-0"
4721
+ ),
4722
+ children: [
4723
+ /* @__PURE__ */ jsx(
4724
+ "span",
4725
+ {
4726
+ className: cn(
4727
+ "text-[0.8125rem]",
4728
+ c.highlight ? "text-oca-accent-ink" : "text-muted-foreground",
4729
+ desk === "lg" ? "lg:sr-only" : "md:sr-only"
4730
+ ),
4731
+ children: c.label
4732
+ }
4733
+ ),
4734
+ /* @__PURE__ */ jsx("span", { className: cn("text-[0.9375rem]", c.highlight && "font-medium"), children: r.values[c.key] ?? "\u2014" })
4735
+ ]
4736
+ },
4737
+ c.key
4738
+ );
4739
+ }) })
4740
+ ] }, ri))
4659
4741
  ] });
4660
4742
  }
4661
- function useDarkMode() {
4662
- const [dark, setDark] = useState(false);
4663
- useEffect(() => {
4664
- const root = document.documentElement;
4665
- const read = () => setDark(root.classList.contains("dark"));
4666
- read();
4667
- const mo = new MutationObserver(read);
4668
- mo.observe(root, { attributes: true, attributeFilter: ["class"] });
4669
- return () => mo.disconnect();
4670
- }, []);
4671
- return dark;
4672
- }
4673
- function mermaidTheme(el) {
4674
- const css = getComputedStyle(el);
4675
- const v = (name) => css.getPropertyValue(name).trim();
4676
- const card = v("--card");
4677
- const muted = v("--muted");
4678
- const text = v("--foreground");
4679
- const subtle = v("--muted-foreground");
4680
- const line = v("--input");
4681
- const hair = v("--oca-hairline-strong");
4682
- return {
4683
- background: "transparent",
4684
- fontFamily: css.fontFamily,
4685
- fontSize: "14px",
4686
- textColor: text,
4687
- mainBkg: card,
4688
- primaryColor: card,
4689
- primaryTextColor: text,
4690
- primaryBorderColor: hair,
4691
- secondaryColor: muted,
4692
- secondaryTextColor: text,
4693
- secondaryBorderColor: hair,
4694
- tertiaryColor: muted,
4695
- tertiaryTextColor: text,
4696
- tertiaryBorderColor: hair,
4697
- nodeBorder: hair,
4698
- lineColor: line,
4699
- edgeLabelBackground: card,
4700
- clusterBkg: muted,
4701
- clusterBorder: hair,
4702
- titleColor: text,
4703
- noteBkgColor: muted,
4704
- noteTextColor: text,
4705
- noteBorderColor: hair,
4706
- actorBkg: card,
4707
- actorBorder: hair,
4708
- actorTextColor: text,
4709
- actorLineColor: line,
4710
- signalColor: text,
4711
- signalTextColor: text,
4712
- labelBoxBkgColor: card,
4713
- labelBoxBorderColor: hair,
4714
- labelTextColor: text,
4715
- loopTextColor: subtle,
4716
- activationBkgColor: muted,
4717
- activationBorderColor: hair,
4718
- sequenceNumberColor: card
4719
- };
4720
- }
4721
- function naturalSize(svg) {
4722
- const w = svg.match(/viewBox="[\d.-]+ [\d.-]+ ([\d.]+) [\d.]+"/)?.[1];
4723
- if (!w) return svg;
4724
- return svg.replace(/<svg([^>]*?)\swidth="100%"/, `<svg$1 width="${Math.ceil(Number(w))}"`).replace(/max-width:\s*[\d.]+px;?/, "");
4725
- }
4726
- function Diagram({ chart, caption, load, className }) {
4727
- const ref = useRef(null);
4728
- const dark = useDarkMode();
4729
- const raw = useId();
4730
- const [svg, setSvg] = useState(null);
4731
- const [failed, setFailed] = useState(false);
4732
- useEffect(() => {
4733
- let live = true;
4734
- const el = ref.current;
4735
- if (!el) return;
4736
- (async () => {
4737
- try {
4738
- const mod = await load();
4739
- const mermaid = "default" in mod ? mod.default : mod;
4740
- mermaid.initialize({ startOnLoad: false, securityLevel: "strict", theme: "base", themeVariables: mermaidTheme(el) });
4741
- const { svg: drawn } = await mermaid.render(`oca-diagram-${raw.replace(/[^a-zA-Z0-9]/g, "")}-${dark ? "d" : "l"}`, chart);
4742
- if (live) {
4743
- setSvg(naturalSize(drawn));
4744
- setFailed(false);
4745
- }
4746
- } catch {
4747
- if (live) setFailed(true);
4748
- }
4749
- })();
4750
- return () => {
4751
- live = false;
4752
- };
4753
- }, [chart, dark, load, raw]);
4754
- if (failed) return /* @__PURE__ */ jsx(CodeBlock, { code: chart, caption: "Diagram (shown as its source)", className: cn("my-6", className) });
4755
- return /* @__PURE__ */ jsxs("figure", { ref, className: cn("not-prose my-6 overflow-hidden rounded-[1.25rem] border border-border bg-card", className), children: [
4756
- svg ? /* @__PURE__ */ jsx(ScrollFade, { fade: "var(--card)", children: /* @__PURE__ */ jsx(
4757
- "div",
4758
- {
4759
- className: "flex w-max min-w-full justify-center p-6 [&_svg]:h-auto [&_svg]:max-w-none",
4760
- role: "img",
4761
- "aria-label": typeof caption === "string" ? caption : "Diagram",
4762
- dangerouslySetInnerHTML: { __html: svg }
4763
- }
4764
- ) }) : /* @__PURE__ */ jsx("div", { role: "status", "aria-label": "Drawing the diagram", className: "p-6", children: /* @__PURE__ */ jsx(Skeleton, { className: "h-40 w-full rounded-xl" }) }),
4765
- caption ? /* @__PURE__ */ jsx("figcaption", { className: "border-t border-border px-5 py-3 text-[0.8125rem] text-muted-foreground", children: caption }) : null
4766
- ] });
4767
- }
4768
- var HEADING = {
4769
- h1: "oca-display-3 mb-4 text-foreground",
4770
- h2: "mb-3 mt-12 text-[1.375rem] font-medium leading-tight tracking-[-0.015em] text-foreground md:text-[1.5rem]",
4771
- h3: "mb-2 mt-9 text-[1.125rem] font-medium leading-snug tracking-[-0.01em] text-foreground",
4772
- h4: "mb-2 mt-7 text-[1rem] font-medium leading-snug text-foreground"
4743
+ var CHECK = {
4744
+ ok: { word: "Passed", icon: /* @__PURE__ */ jsx(CircleCheck, {}), tone: "text-success" },
4745
+ fail: { word: "Failed", icon: /* @__PURE__ */ jsx(CircleX, {}), tone: "text-destructive" },
4746
+ pending: { word: "Pending", icon: /* @__PURE__ */ jsx(Clock, {}), tone: "text-oca-accent-ink" },
4747
+ none: { word: "None", icon: /* @__PURE__ */ jsx(CircleSlash, {}), tone: "text-muted-foreground" },
4748
+ skipped: { word: "Skipped", icon: /* @__PURE__ */ jsx(CircleMinus, {}), tone: "text-muted-foreground" },
4749
+ unchecked: { word: "Not checked", icon: /* @__PURE__ */ jsx(CircleDashed, {}), tone: "text-oca-subtle" }
4773
4750
  };
4774
- function DocsHeading({
4775
- as: Tag,
4776
- id,
4777
- children,
4778
- className,
4779
- ...props
4751
+ function VerifyReport({
4752
+ verdict,
4753
+ title,
4754
+ summary,
4755
+ checks,
4756
+ facts,
4757
+ notChecked,
4758
+ actions,
4759
+ as: Heading = "h2",
4760
+ className
4780
4761
  }) {
4781
- return /* @__PURE__ */ jsxs(Tag, { id, className: cn("group scroll-mt-28", HEADING[Tag], className), ...props, children: [
4782
- /* @__PURE__ */ jsx("span", { "data-heading-text": "", children }),
4783
- id && Tag !== "h1" ? /* @__PURE__ */ jsxs(
4784
- "a",
4762
+ return /* @__PURE__ */ jsxs(
4763
+ "section",
4764
+ {
4765
+ "aria-label": "Verification result",
4766
+ className: cn("overflow-hidden rounded-[1.25rem] border border-border bg-card", className),
4767
+ children: [
4768
+ /* @__PURE__ */ jsxs("header", { className: "flex flex-col items-start gap-3 p-6 md:p-8", children: [
4769
+ /* @__PURE__ */ jsx(StatusBadge, { status: verdict }),
4770
+ /* @__PURE__ */ jsx(Heading, { className: "oca-display-3 [overflow-wrap:anywhere]", children: title }),
4771
+ summary ? /* @__PURE__ */ jsx("p", { className: "oca-body max-w-[40rem] [overflow-wrap:anywhere]", children: summary }) : null
4772
+ ] }),
4773
+ /* @__PURE__ */ jsx("ul", { "aria-label": "Checks", className: "divide-y divide-border border-t border-border", children: checks.map((c, i) => {
4774
+ const k = CHECK[c.state];
4775
+ return /* @__PURE__ */ jsxs("li", { className: "flex items-start gap-3 px-6 py-3.5 md:px-8", children: [
4776
+ /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: cn("mt-0.5 shrink-0 [&_svg]:size-[1.125rem]", k.tone), children: k.icon }),
4777
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-0.5 sm:flex-row sm:items-baseline sm:justify-between sm:gap-6", children: [
4778
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col gap-0.5", children: [
4779
+ /* @__PURE__ */ jsx("span", { className: "text-[0.9375rem]", children: c.label }),
4780
+ c.note ? /* @__PURE__ */ jsx("span", { className: "break-words text-[0.8125rem] leading-snug text-muted-foreground", children: c.note }) : null
4781
+ ] }),
4782
+ /* @__PURE__ */ jsx(
4783
+ "span",
4784
+ {
4785
+ className: cn(
4786
+ "shrink-0 text-[0.8125rem]",
4787
+ c.state === "fail" ? "text-destructive" : "text-muted-foreground"
4788
+ ),
4789
+ children: k.word
4790
+ }
4791
+ )
4792
+ ] })
4793
+ ] }, i);
4794
+ }) }),
4795
+ facts && facts.length > 0 ? /* @__PURE__ */ jsx(KeyValueList, { items: facts, className: "rounded-none border-x-0 border-b-0 bg-transparent [&>div]:px-6 md:[&>div]:px-8" }) : null,
4796
+ notChecked && notChecked.length > 0 ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 border-t border-border bg-muted/50 px-6 py-5 md:px-8", children: [
4797
+ /* @__PURE__ */ jsx("p", { className: "text-[0.875rem] font-medium", children: "What this did not check" }),
4798
+ /* @__PURE__ */ jsx("ul", { className: "flex list-disc flex-col gap-1 pl-5 text-[0.875rem] leading-relaxed text-muted-foreground", children: notChecked.map((n, i) => /* @__PURE__ */ jsx("li", { children: n }, i)) })
4799
+ ] }) : null,
4800
+ actions ? /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-3 border-t border-border px-6 py-5 md:px-8", children: actions }) : null
4801
+ ]
4802
+ }
4803
+ );
4804
+ }
4805
+ function SignMessage({
4806
+ lead,
4807
+ address,
4808
+ message,
4809
+ wallets,
4810
+ busy = false,
4811
+ error,
4812
+ submitLabel = "Confirm",
4813
+ secondary,
4814
+ onSignature,
4815
+ className
4816
+ }) {
4817
+ const [pasted, setPasted] = useState("");
4818
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-5", className), children: [
4819
+ lead ? /* @__PURE__ */ jsx("p", { className: "text-[0.9375rem] leading-relaxed", children: lead }) : null,
4820
+ wallets ? /* @__PURE__ */ jsxs(Fragment, { children: [
4821
+ /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2", children: wallets }),
4822
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 text-[0.8125rem] text-muted-foreground", children: [
4823
+ /* @__PURE__ */ jsx("span", { className: "h-px flex-1 bg-border" }),
4824
+ "or sign it in any wallet",
4825
+ /* @__PURE__ */ jsx("span", { className: "h-px flex-1 bg-border" })
4826
+ ] })
4827
+ ] }) : null,
4828
+ /* @__PURE__ */ jsx(CodeBlock, { code: message, caption: "Message to sign" }),
4829
+ /* @__PURE__ */ jsxs(
4830
+ "form",
4785
4831
  {
4786
- href: `#${id}`,
4787
- 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",
4832
+ className: "flex flex-col gap-4",
4833
+ onSubmit: (e) => {
4834
+ e.preventDefault();
4835
+ if (pasted.trim()) onSignature(pasted.trim());
4836
+ },
4788
4837
  children: [
4789
- /* @__PURE__ */ jsx("span", { "aria-hidden": true, children: "#" }),
4790
- /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Link to this section" })
4838
+ /* @__PURE__ */ jsx(
4839
+ Field,
4840
+ {
4841
+ label: "Signature",
4842
+ error,
4843
+ hint: /* @__PURE__ */ jsxs(Fragment, { children: [
4844
+ "From your wallet\u2019s \u201Csign message\u201D (BIP-322), signed by",
4845
+ " ",
4846
+ /* @__PURE__ */ jsx("span", { className: "break-all font-mono", children: address }),
4847
+ "."
4848
+ ] }),
4849
+ children: /* @__PURE__ */ jsx(
4850
+ Textarea,
4851
+ {
4852
+ value: pasted,
4853
+ onChange: (e) => setPasted(e.target.value),
4854
+ rows: 3,
4855
+ spellCheck: false,
4856
+ className: "min-h-24 font-mono text-base md:text-[0.8125rem]"
4857
+ }
4858
+ )
4859
+ }
4860
+ ),
4861
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-2", children: [
4862
+ /* @__PURE__ */ jsx(Button, { type: "submit", loading: busy, disabled: !pasted.trim(), children: submitLabel }),
4863
+ secondary
4864
+ ] })
4791
4865
  ]
4792
4866
  }
4793
- ) : null
4867
+ )
4794
4868
  ] });
4795
4869
  }
4796
- function codeText(node) {
4797
- if (typeof node === "string") return node;
4798
- if (typeof node === "number") return String(node);
4799
- if (Array.isArray(node)) return node.map(codeText).join("");
4800
- if (isValidElement(node)) return codeText(node.props.children);
4801
- return "";
4802
- }
4803
- function codeLang(node) {
4804
- const child = Children.toArray(node)[0];
4805
- if (!isValidElement(child)) return void 0;
4806
- const cls = child.props.className ?? "";
4807
- return cls.match(/language-([\w+-]+)/)?.[1];
4808
- }
4809
4870
  function useMacKeys() {
4810
4871
  const [mac, setMac] = useState(true);
4811
4872
  useEffect(() => {
@@ -5608,7 +5669,7 @@ function ToolGrid({
5608
5669
  ] }),
5609
5670
  /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
5610
5671
  /* @__PURE__ */ jsx(Heading, { className: "oca-title-sm", children: /* @__PURE__ */ jsx(
5611
- Link8,
5672
+ Link6,
5612
5673
  {
5613
5674
  href: t.href,
5614
5675
  className: "outline-none after:absolute after:inset-0 after:rounded-[1.25rem] after:content-['']",
@@ -5701,800 +5762,827 @@ function FamilyMenu({ current: current2, className }) {
5701
5762
  )
5702
5763
  ] });
5703
5764
  }
5704
- function NavLink({
5705
- item,
5706
- className,
5707
- onNavigate,
5708
- line = false
5709
- }) {
5710
- const cls = cn(
5711
- "rounded-full px-3 py-2 text-[0.9375rem] transition-colors",
5712
- item.active ? "text-foreground" : "text-muted-foreground hover:text-foreground",
5713
- line && "relative after:absolute after:inset-x-3 after:-bottom-[0.625rem] after:h-0.5 after:rounded-full",
5714
- line && item.active && "after:bg-foreground",
5715
- className
5716
- );
5717
- if (item.external) {
5718
- return /* @__PURE__ */ jsx("a", { href: item.href, className: cls, rel: "noreferrer", onClick: onNavigate, children: item.label });
5719
- }
5720
- return /* @__PURE__ */ jsx(Link8, { href: item.href, className: cls, "aria-current": item.active ? "page" : void 0, onClick: onNavigate, children: item.label });
5721
- }
5722
- function NavRow({ item, onNavigate }) {
5723
- const body = /* @__PURE__ */ jsxs(Fragment, { children: [
5724
- /* @__PURE__ */ jsx("span", { className: "text-[0.9375rem] font-medium leading-6 text-foreground", children: item.label }),
5725
- item.description ? /* @__PURE__ */ jsx("span", { className: "text-[0.8125rem] leading-snug text-muted-foreground", children: item.description }) : null
5726
- ] });
5727
- const cls = cn(
5728
- "flex flex-col gap-0.5 rounded-xl px-3 py-2 transition-colors hover:bg-accent",
5729
- item.active && "bg-muted hover:bg-muted dark:bg-white/[0.06]"
5730
- );
5731
- return item.external ? /* @__PURE__ */ jsx("a", { href: item.href, className: cls, rel: "noreferrer", onClick: onNavigate, children: body }) : /* @__PURE__ */ jsx(Link8, { href: item.href, className: cls, "aria-current": item.active ? "page" : void 0, onClick: onNavigate, children: body });
5732
- }
5733
- var seeAll = (item) => typeof item.label === "string" ? `All ${item.label.toLowerCase()}` : "See all";
5734
- function NavDropdown({ item }) {
5735
- const [open, setOpen] = useState(false);
5736
- const active = item.active || item.children?.some((c) => c.active);
5737
- return /* @__PURE__ */ jsxs(Popover, { open, onOpenChange: setOpen, children: [
5738
- /* @__PURE__ */ jsxs(
5739
- PopoverTrigger,
5765
+ function SideNav({ groups, onNavigate }) {
5766
+ return /* @__PURE__ */ jsx("nav", { "aria-label": "Pages", className: "flex flex-col gap-5", children: groups.map((g, gi) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5", children: [
5767
+ g.label ? /* @__PURE__ */ jsx("p", { className: "px-3 pb-1 text-[0.8125rem] text-muted-foreground", children: g.label }) : null,
5768
+ g.items.map((it) => /* @__PURE__ */ jsxs(
5769
+ Link6,
5740
5770
  {
5771
+ href: it.href,
5772
+ onClick: onNavigate,
5773
+ "aria-current": it.active ? "page" : void 0,
5741
5774
  className: cn(
5742
- "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",
5743
- active ? "text-foreground" : "text-muted-foreground hover:text-foreground data-[state=open]:text-foreground"
5775
+ "flex h-9 items-center gap-3 rounded-xl px-3 text-[0.9375rem] transition-colors",
5776
+ "[&_svg]:size-[1.0625rem] [&_svg]:shrink-0",
5777
+ it.active ? "bg-card text-foreground shadow-sm ring-1 ring-border [&_svg]:text-foreground" : "text-muted-foreground hover:bg-accent hover:text-foreground"
5744
5778
  ),
5745
5779
  children: [
5746
- item.label,
5747
- /* @__PURE__ */ jsx(ChevronDown, { "aria-hidden": true, className: "size-3.5 transition-transform duration-200 group-data-[state=open]:rotate-180" })
5780
+ it.icon,
5781
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate", children: it.label }),
5782
+ it.badge ? /* @__PURE__ */ jsx("span", { className: "shrink-0", children: it.badge }) : null
5748
5783
  ]
5749
- }
5750
- ),
5751
- /* @__PURE__ */ jsxs(PopoverContent, { align: "center", sideOffset: 10, className: "w-[min(calc(100vw-2rem),26rem)] p-2", children: [
5752
- /* @__PURE__ */ jsx("ul", { className: "flex flex-col", children: item.children?.map((c) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(NavRow, { item: c, onNavigate: () => setOpen(false) }) }, c.href)) }),
5753
- /* @__PURE__ */ jsx("div", { className: "mt-1.5 border-t border-border px-1 pt-1.5", children: /* @__PURE__ */ jsx(
5754
- NavLink,
5755
- {
5756
- item: { ...item, label: seeAll(item), children: void 0 },
5757
- className: "block rounded-xl px-2 py-2 text-[0.875rem]",
5758
- onNavigate: () => setOpen(false)
5759
- }
5760
- ) })
5761
- ] })
5762
- ] });
5784
+ },
5785
+ it.href
5786
+ ))
5787
+ ] }, g.label ?? gi)) });
5763
5788
  }
5764
- function SiteHeader({
5765
- home = "/",
5766
- brand,
5767
- product,
5768
- family,
5769
- nav = [],
5770
- search,
5771
- actions,
5772
- variant = "site",
5773
- navOnPhone = true,
5774
- menu: menuExtra,
5775
- className
5789
+ function SectionSwitch({
5790
+ sections,
5791
+ current: current2,
5792
+ onNavigate
5776
5793
  }) {
5777
- const [open, setOpen] = useState(false);
5778
- const tool = variant === "tool";
5779
- const size = tool ? 24 : 28;
5780
- const current2 = typeof family === "string" ? family : void 0;
5781
- const phoneNav = navOnPhone ? nav : [];
5782
- const menu = phoneNav.length > 0 || Boolean(family) || Boolean(menuExtra);
5783
- const brandNode = brand ?? /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center", children: [
5784
- /* @__PURE__ */ jsx(Lockup, { size }),
5785
- product ? /* @__PURE__ */ jsxs(Fragment, { children: [
5786
- /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "mx-3 h-5 w-px bg-oca-hairline-strong" }),
5787
- /* @__PURE__ */ jsx("span", { className: "font-medium tracking-[-0.01em]", style: { fontSize: size * 0.56 }, children: product })
5788
- ] }) : null
5789
- ] });
5790
- const navigation = nav.length > 0 ? /* @__PURE__ */ jsx("nav", { "aria-label": "Main", className: "hidden items-center gap-1 md:flex", children: nav.map(
5791
- (n) => n.children?.length ? /* @__PURE__ */ jsx(NavDropdown, { item: n }, n.href) : (
5792
- // Between md and lg the family menu and the actions share the row: tighter.
5793
- /* @__PURE__ */ jsx(NavLink, { item: n, line: tool, className: tool ? void 0 : "md:max-lg:px-2.5" }, n.href)
5794
- )
5795
- ) }) : null;
5794
+ const cols = sections.length <= 3 ? sections.length : 2;
5796
5795
  return /* @__PURE__ */ jsx(
5797
- "header",
5796
+ "nav",
5798
5797
  {
5799
- className: cn(
5800
- "sticky top-0 z-40 w-full border-b bg-background/95 backdrop-blur-md supports-[backdrop-filter]:bg-background/90",
5801
- tool ? "border-border" : "border-transparent",
5802
- className
5803
- ),
5804
- children: /* @__PURE__ */ jsxs(
5798
+ "aria-label": "Sections",
5799
+ className: cn("grid gap-1 bg-muted p-1", cols === sections.length ? "rounded-full" : "rounded-[1.25rem]"),
5800
+ style: { gridTemplateColumns: `repeat(${cols}, minmax(0, 1fr))` },
5801
+ children: sections.map((sec) => {
5802
+ const on = sec.id === current2.id;
5803
+ return /* @__PURE__ */ jsx(
5804
+ Link6,
5805
+ {
5806
+ href: sec.href,
5807
+ onClick: onNavigate,
5808
+ "aria-current": on ? "true" : void 0,
5809
+ className: cn(
5810
+ "flex h-8 min-w-0 items-center justify-center rounded-full px-1.5 text-[0.8125rem] font-medium transition-colors",
5811
+ on ? "bg-card text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"
5812
+ ),
5813
+ children: /* @__PURE__ */ jsx("span", { className: "truncate", children: sec.label })
5814
+ },
5815
+ sec.id
5816
+ );
5817
+ })
5818
+ }
5819
+ );
5820
+ }
5821
+ function TabBar({ items }) {
5822
+ return /* @__PURE__ */ jsx(
5823
+ "nav",
5824
+ {
5825
+ "aria-label": "Pages",
5826
+ "data-oca-tabbar": "",
5827
+ 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",
5828
+ children: /* @__PURE__ */ jsx(
5805
5829
  "div",
5806
5830
  {
5807
- className: cn(
5808
- "flex items-center justify-between gap-4",
5809
- tool ? "h-14 px-4 md:px-6" : "oca-container h-16 md:h-[4.5rem] md:max-lg:gap-2",
5810
- // Three columns, the outer two each at least their content: the
5811
- // navigation stays centred whatever the actions hold, so it does
5812
- // not shift when they change (signed out to signed in).
5813
- !tool && nav.length > 0 && "md:grid md:grid-cols-[minmax(max-content,1fr)_auto_minmax(max-content,1fr)]"
5814
- ),
5815
- children: [
5816
- /* @__PURE__ */ jsxs("div", { className: cn("flex min-w-0 items-center gap-1", tool ? "md:gap-1" : "justify-self-start"), children: [
5817
- /* @__PURE__ */ jsxs(Link8, { href: home, className: "-ml-1 min-w-0 rounded-lg p-1", children: [
5818
- brandNode,
5819
- /* @__PURE__ */ jsx("span", { className: "sr-only", children: " home" })
5820
- ] }),
5821
- family ? /* @__PURE__ */ jsx(FamilyMenu, { current: current2, className: "max-md:hidden" }) : null,
5822
- tool && navigation ? /* @__PURE__ */ jsx("div", { className: "ml-5", children: navigation }) : null
5823
- ] }),
5824
- !tool ? navigation : null,
5825
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 justify-self-end", children: [
5826
- search,
5827
- actions,
5828
- menu ? /* @__PURE__ */ jsxs(Sheet, { open, onOpenChange: setOpen, children: [
5829
- /* @__PURE__ */ jsx(
5830
- SheetTrigger,
5831
+ className: "mx-auto grid h-14 max-w-[32rem] px-1.5",
5832
+ style: { gridTemplateColumns: `repeat(${items.length}, minmax(0, 1fr))` },
5833
+ children: items.map((it) => /* @__PURE__ */ jsxs(
5834
+ Link6,
5835
+ {
5836
+ href: it.href,
5837
+ "aria-current": it.active ? "page" : void 0,
5838
+ className: cn(
5839
+ "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",
5840
+ it.active ? "text-foreground" : "text-muted-foreground hover:text-foreground"
5841
+ ),
5842
+ children: [
5843
+ /* @__PURE__ */ jsxs(
5844
+ "span",
5831
5845
  {
5832
- className: "inline-flex size-10 items-center justify-center rounded-full text-foreground hover:bg-accent md:hidden",
5833
- "aria-label": "Open menu",
5834
- children: /* @__PURE__ */ jsx(Menu, { className: "size-5" })
5846
+ className: cn(
5847
+ "relative flex h-7 w-12 items-center justify-center rounded-full transition-[background-color,box-shadow] duration-200",
5848
+ "[&_svg]:size-[1.125rem] [&_svg]:shrink-0",
5849
+ it.active ? "bg-card shadow-sm ring-1 ring-border [&_svg]:stroke-2" : "[&_svg]:stroke-[1.75]"
5850
+ ),
5851
+ children: [
5852
+ it.icon,
5853
+ it.badge ? /* @__PURE__ */ 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
5854
+ ]
5835
5855
  }
5836
5856
  ),
5837
- /* @__PURE__ */ jsxs(SheetContent, { side: "right", className: "pt-16", children: [
5838
- /* @__PURE__ */ jsx(SheetTitle, { className: "sr-only", children: "Menu" }),
5839
- menuExtra ? /* @__PURE__ */ jsx("div", { className: cn("flex flex-col", (phoneNav.length > 0 || family) && "border-b border-border pb-3"), children: menuExtra }) : null,
5840
- phoneNav.length > 0 ? /* @__PURE__ */ jsx("nav", { "aria-label": "Main", className: "flex flex-col", children: phoneNav.map(
5841
- (n) => n.children?.length ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col py-2", children: [
5842
- /* @__PURE__ */ jsx("p", { className: "px-3 pb-1 text-[0.8125rem] text-muted-foreground", children: n.label }),
5843
- n.children.map((c) => /* @__PURE__ */ jsx(
5844
- NavLink,
5845
- {
5846
- item: c,
5847
- className: "rounded-xl px-3 py-2.5 text-[1.0625rem]",
5848
- onNavigate: () => setOpen(false)
5849
- },
5850
- c.href
5851
- ))
5852
- ] }, n.href) : /* @__PURE__ */ jsx(
5853
- NavLink,
5854
- {
5855
- item: n,
5856
- className: "rounded-xl px-3 py-3 text-[1.0625rem]",
5857
- onNavigate: () => setOpen(false)
5858
- },
5859
- n.href
5860
- )
5861
- ) }) : null,
5862
- family ? /* @__PURE__ */ jsxs("details", { className: cn("group", phoneNav.length > 0 && "mt-2 border-t border-border pt-4"), children: [
5863
- /* @__PURE__ */ 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: [
5864
- "All orangecheck sites",
5865
- /* @__PURE__ */ jsx(ChevronDown, { "aria-hidden": true, className: "size-4 text-muted-foreground transition-transform group-open:rotate-180" })
5866
- ] }),
5867
- /* @__PURE__ */ jsx(FamilyList, { current: current2, onNavigate: () => setOpen(false), stack: true, className: "mt-2" })
5868
- ] }) : null
5869
- ] })
5870
- ] }) : null
5871
- ] })
5872
- ]
5857
+ /* @__PURE__ */ jsx("span", { className: "max-w-full truncate px-0.5", children: it.label }),
5858
+ it.badge ? /* @__PURE__ */ jsx("span", { className: "sr-only", children: it.badge }) : null
5859
+ ]
5860
+ },
5861
+ it.href
5862
+ ))
5873
5863
  }
5874
5864
  )
5875
5865
  }
5876
5866
  );
5877
5867
  }
5878
- function SkipLink({ href = "#main-content", children = "Skip to content" }) {
5879
- return /* @__PURE__ */ jsx(
5880
- "a",
5881
- {
5882
- href,
5883
- 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",
5884
- children
5868
+ function tabsFor(groups) {
5869
+ const items = groups.flatMap((g) => g.items);
5870
+ return items.length >= 2 && items.length <= 5 && items.every((it) => it.icon) ? items : null;
5871
+ }
5872
+ var activeItem = (groups) => groups.flatMap((g) => g.items).find((it) => it.active);
5873
+ var warned = /* @__PURE__ */ new Set();
5874
+ function warnDuplicateLabels(groups) {
5875
+ if (typeof process === "undefined" || process.env.NODE_ENV === "production") return;
5876
+ const seen = /* @__PURE__ */ new Set();
5877
+ for (const it of groups.flatMap((g) => g.items)) {
5878
+ if (seen.has(it.label) && !warned.has(it.label)) {
5879
+ warned.add(it.label);
5880
+ console.warn(`AppShell: two pages are labelled "${it.label}"; give each its own name.`);
5885
5881
  }
5886
- );
5882
+ seen.add(it.label);
5883
+ }
5887
5884
  }
5888
- var BANNER_TONE = {
5889
- neutral: "border-border bg-muted",
5890
- brand: "border-[color-mix(in_oklab,var(--oca-orange)_30%,var(--border))] bg-[color-mix(in_oklab,var(--oca-orange)_9%,var(--background))]",
5891
- danger: "border-[color-mix(in_oklab,var(--destructive)_35%,var(--border))] bg-[color-mix(in_oklab,var(--destructive)_8%,var(--background))]"
5892
- };
5893
- function SiteBanner({
5894
- tone = "neutral",
5885
+ function AppShell({
5886
+ nav,
5887
+ sections,
5888
+ activeSection,
5889
+ page: pageOverride,
5890
+ persistent = [],
5891
+ home = "/",
5892
+ family,
5893
+ account,
5894
+ banner,
5895
+ footer,
5895
5896
  children,
5896
- action,
5897
5897
  className
5898
5898
  }) {
5899
- return /* @__PURE__ */ jsx("div", { role: "status", "aria-live": "polite", "data-tone": tone, className: cn("border-b text-[0.875rem]", BANNER_TONE[tone], className), children: /* @__PURE__ */ jsxs("div", { className: "oca-container flex flex-wrap items-center justify-between gap-x-4 gap-y-1 py-2.5", children: [
5900
- /* @__PURE__ */ jsxs("p", { className: "flex min-w-0 items-baseline gap-2.5 leading-snug", children: [
5901
- tone !== "neutral" ? /* @__PURE__ */ jsx(
5902
- "span",
5903
- {
5904
- "aria-hidden": true,
5905
- className: cn(
5906
- "size-2 shrink-0 translate-y-[-0.05em] rounded-full",
5907
- tone === "brand" ? "bg-oca-orange" : "bg-destructive"
5908
- )
5909
- }
5910
- ) : null,
5911
- /* @__PURE__ */ jsx("span", { children })
5912
- ] }),
5913
- action ? /* @__PURE__ */ jsx("div", { className: cn("shrink-0 font-medium", tone !== "neutral" && "max-sm:pl-[1.125rem]"), children: action }) : null
5914
- ] }) });
5915
- }
5916
- var FOOT_LINK = "inline-flex min-h-11 items-center transition-colors hover:text-foreground md:min-h-0";
5917
- function LegalRow({ links }) {
5918
- return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-x-6 gap-y-2 sm:flex-row sm:items-center sm:justify-between", children: [
5919
- /* @__PURE__ */ jsx("nav", { "aria-label": "Legal", children: /* @__PURE__ */ jsx("ul", { className: "flex flex-wrap gap-x-5", children: links.map((l) => /* @__PURE__ */ jsx("li", { children: l.href.startsWith("/") ? /* @__PURE__ */ jsx(Link8, { href: l.href, className: FOOT_LINK, children: l.label }) : /* @__PURE__ */ jsx("a", { href: l.href, className: FOOT_LINK, children: l.label }) }, l.href)) }) }),
5920
- /* @__PURE__ */ jsxs("p", { children: [
5921
- "\xA9 ",
5922
- (/* @__PURE__ */ new Date()).getFullYear(),
5923
- " OrangeCheck"
5924
- ] })
5925
- ] });
5926
- }
5927
- function SiteFooter({
5928
- columns = [],
5929
- family = false,
5930
- legal = false,
5931
- compact = false,
5932
- fineprint,
5933
- meta,
5934
- signature = true,
5935
- className
5936
- }) {
5937
- const legalLinks = legal === true ? LEGAL_LINKS : legal || null;
5938
- if (compact) {
5939
- return /* @__PURE__ */ jsx("footer", { className: cn("border-t border-border bg-background text-[0.875rem] text-muted-foreground", className), children: /* @__PURE__ */ 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: [
5940
- /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-x-6 gap-y-1", children: [
5941
- /* @__PURE__ */ jsx("a", { href: OCHK_IO, className: "rounded-lg text-foreground", children: /* @__PURE__ */ jsx(Lockup, { size: 22 }) }),
5942
- family ? /* @__PURE__ */ jsx("nav", { "aria-label": "Protocols", children: /* @__PURE__ */ jsx("ul", { className: "flex flex-wrap gap-x-4", children: PROTOCOLS.map((p) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx("a", { href: p.pageHref, className: FOOT_LINK, children: p.label }) }, p.slug)) }) }) : null
5943
- ] }),
5944
- legalLinks || meta ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-x-6 gap-y-2 sm:flex-row sm:flex-wrap sm:items-center", children: [
5945
- legalLinks ? /* @__PURE__ */ jsx(LegalRow, { links: legalLinks }) : null,
5946
- meta
5947
- ] }) : null
5948
- ] }) });
5949
- }
5950
- const cols = [
5951
- ...columns,
5952
- ...family ? familyByGroup().map((g) => ({
5953
- // The lockup above already says orangecheck.
5954
- heading: g.id === "orangecheck" ? "Start here" : g.label,
5955
- links: g.sites.map((s) => ({ href: s.href, label: s.label, external: true }))
5956
- })) : []
5957
- ];
5958
- const n = cols.length;
5959
- const inline = n <= 5;
5960
- const grid = {
5961
- "--oca-footer-md": `repeat(${Math.max(1, Math.min(n, 4))}, minmax(0, 1fr))`,
5962
- "--oca-footer-lg": inline ? `minmax(0, 1.3fr) repeat(${Math.max(1, n)}, minmax(0, 1fr))` : `repeat(${Math.min(n, 6)}, minmax(0, 1fr))`
5963
- };
5964
- return /* @__PURE__ */ jsxs("footer", { className: cn("border-t border-border bg-background", className), children: [
5965
- /* @__PURE__ */ jsxs(
5966
- "div",
5967
- {
5968
- style: grid,
5969
- 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)]",
5970
- children: [
5971
- /* @__PURE__ */ jsxs("div", { className: cn("col-span-full flex flex-col gap-4", inline && "lg:col-span-1"), children: [
5972
- /* @__PURE__ */ jsx(Lockup, { size: 26 }),
5973
- fineprint ? /* @__PURE__ */ jsx("p", { className: "max-w-xs text-[0.9375rem] leading-relaxed text-muted-foreground", children: fineprint }) : null
5974
- ] }),
5975
- cols.map((col, i) => {
5976
- const spans = n % 2 === 1 && i === n - 1;
5977
- return /* @__PURE__ */ jsxs(
5978
- "div",
5979
- {
5980
- className: cn("flex min-w-0 flex-col gap-1", spans && "col-span-2 md:col-span-1"),
5981
- children: [
5982
- /* @__PURE__ */ jsx("p", { className: "mb-2 text-[0.875rem] font-medium", children: col.heading }),
5983
- /* @__PURE__ */ 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__ */ jsx(
5984
- NavLink,
5985
- {
5986
- item: l,
5987
- className: "-mx-3 py-2.5 text-[0.9375rem] md:py-1.5"
5988
- },
5989
- l.href
5990
- )) })
5991
- ]
5992
- },
5993
- col.heading
5994
- );
5995
- })
5996
- ]
5997
- }
5998
- ),
5999
- signature ? /* @__PURE__ */ jsx("div", { "aria-hidden": true, className: "oca-container select-none overflow-hidden pb-8 md:pb-12", children: /* @__PURE__ */ 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: [
6000
- /* @__PURE__ */ jsx("span", { className: "mb-[0.06em] inline-block w-[1.1em] shrink-0", children: /* @__PURE__ */ jsx(Mark, { className: "block h-auto w-full" }) }),
6001
- /* @__PURE__ */ jsx("span", { children: "orangecheck" })
6002
- ] }) }) : null,
6003
- legalLinks || meta ? /* @__PURE__ */ jsx("div", { className: "oca-container", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3 border-t border-border py-6 text-[0.875rem] text-muted-foreground", children: [
6004
- legalLinks ? /* @__PURE__ */ jsx(LegalRow, { links: legalLinks }) : null,
6005
- meta
6006
- ] }) }) : null
6007
- ] });
6008
- }
6009
- function SignInFrame({
6010
- title = "Sign in",
6011
- lead,
6012
- children,
6013
- error,
6014
- fineprint,
6015
- brand,
6016
- home = "/",
6017
- back,
6018
- art,
6019
- caption,
6020
- className
6021
- }) {
6022
- return /* @__PURE__ */ jsxs(
6023
- "main",
5899
+ const [open, setOpen] = useState(false);
5900
+ const current2 = sections && sections.length > 0 ? sections.find((sec) => sec.id === activeSection) ?? sections.find((sec) => activeItem(sec.groups)) ?? sections[0] : void 0;
5901
+ const groups = current2 ? [...current2.groups, ...persistent] : [...nav ?? [], ...persistent];
5902
+ warnDuplicateLabels(groups);
5903
+ const tabs = current2 ? null : tabsFor(groups);
5904
+ const page = activeItem(groups);
5905
+ const place = useMemo(
5906
+ () => ({
5907
+ section: current2 ? current2.title ?? current2.label : void 0,
5908
+ page: pageOverride ?? page?.label
5909
+ }),
5910
+ [current2, page?.label, pageOverride]
5911
+ );
5912
+ const familyMenu = family ? /* @__PURE__ */ jsx(FamilyMenu, { current: typeof family === "string" ? family : void 0 }) : null;
5913
+ const switcher = sections && current2 && sections.length > 1 ? /* @__PURE__ */ jsx(SectionSwitch, { sections, current: current2, onNavigate: () => setOpen(false) }) : null;
5914
+ return /* @__PURE__ */ jsx(ShellContext.Provider, { value: place, children: /* @__PURE__ */ jsxs(
5915
+ "div",
6024
5916
  {
6025
- id: "main-content",
6026
- className: cn("grid min-h-dvh grid-cols-1 bg-background text-foreground lg:grid-cols-2", className),
5917
+ className: cn(
5918
+ "min-h-dvh bg-background",
5919
+ tabs && "max-md:pb-[calc(3.5rem_+_env(safe-area-inset-bottom))]",
5920
+ className
5921
+ ),
6027
5922
  children: [
6028
- /* @__PURE__ */ jsxs("section", { className: "flex flex-col px-4 pb-8 pt-5 sm:px-8 lg:px-14 lg:pt-8", children: [
6029
- /* @__PURE__ */ jsxs("header", { className: "flex items-center justify-between gap-4", children: [
6030
- /* @__PURE__ */ jsxs(Link8, { href: home, className: "w-fit rounded-lg", children: [
6031
- brand ?? /* @__PURE__ */ jsx(Lockup, { size: 28 }),
6032
- /* @__PURE__ */ jsx("span", { className: "sr-only", children: " home" })
5923
+ /* @__PURE__ */ jsxs("div", { className: "sticky top-0 z-40 border-b border-border bg-background/90 backdrop-blur-md lg:hidden", children: [
5924
+ /* @__PURE__ */ jsxs("div", { className: "flex h-14 items-center gap-2 px-3", children: [
5925
+ /* @__PURE__ */ jsxs(Sheet, { open, onOpenChange: setOpen, children: [
5926
+ /* @__PURE__ */ jsx(
5927
+ SheetTrigger,
5928
+ {
5929
+ className: cn(
5930
+ "inline-flex size-10 items-center justify-center rounded-full hover:bg-accent",
5931
+ // The tab bar holds every page; the sheet is left for a footer.
5932
+ tabs && !footer && "max-md:hidden"
5933
+ ),
5934
+ "aria-label": "Open navigation",
5935
+ children: /* @__PURE__ */ jsx(Menu, { className: "size-5" })
5936
+ }
5937
+ ),
5938
+ /* @__PURE__ */ jsxs(SheetContent, { side: "left", className: "flex flex-col gap-6 overflow-y-auto p-4 pt-16", children: [
5939
+ /* @__PURE__ */ jsx(SheetTitle, { className: "sr-only", children: "Navigation" }),
5940
+ switcher,
5941
+ /* @__PURE__ */ jsx("div", { className: tabs ? "max-md:hidden" : void 0, children: /* @__PURE__ */ jsx(SideNav, { groups, onNavigate: () => setOpen(false) }) }),
5942
+ footer ? /* @__PURE__ */ jsx("div", { className: "mt-auto flex flex-col gap-3", children: footer }) : null
5943
+ ] })
6033
5944
  ] }),
6034
- back === void 0 ? /* @__PURE__ */ jsx(
6035
- Link8,
6036
- {
6037
- href: home,
6038
- className: "text-[0.9375rem] text-muted-foreground underline-offset-4 hover:text-foreground hover:underline",
6039
- children: "Back to home"
6040
- }
6041
- ) : back
5945
+ /* @__PURE__ */ jsx(Link6, { href: home, "aria-label": "Home", className: "rounded-lg p-1", children: /* @__PURE__ */ jsx(Lockup, { size: 22 }) }),
5946
+ familyMenu,
5947
+ /* @__PURE__ */ jsx("div", { className: "ml-auto flex items-center", children: account })
6042
5948
  ] }),
6043
- /* @__PURE__ */ jsxs("div", { className: "mx-auto flex w-full max-w-[25rem] flex-1 flex-col justify-center gap-9 py-12", children: [
6044
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
6045
- /* @__PURE__ */ jsx("h1", { className: "oca-display-2", children: title }),
6046
- lead ? /* @__PURE__ */ jsx("p", { className: "oca-lead", children: lead }) : null
5949
+ place.page ? /* @__PURE__ */ jsxs(
5950
+ "div",
5951
+ {
5952
+ className: cn(
5953
+ "flex h-9 items-center gap-1.5 border-t border-border px-4 text-[0.875rem]",
5954
+ // The active tab already names the page.
5955
+ tabs && !pageOverride && "max-md:hidden"
5956
+ ),
5957
+ children: [
5958
+ place.section ? /* @__PURE__ */ jsxs(Fragment, { children: [
5959
+ /* @__PURE__ */ jsx("span", { className: "shrink-0 text-muted-foreground", children: place.section }),
5960
+ /* @__PURE__ */ jsx(ChevronRight, { "aria-hidden": true, className: "size-3.5 shrink-0 text-muted-foreground" })
5961
+ ] }) : null,
5962
+ /* @__PURE__ */ jsx("span", { className: "truncate font-medium", children: place.page })
5963
+ ]
5964
+ }
5965
+ ) : null
5966
+ ] }),
5967
+ /* @__PURE__ */ jsxs("div", { className: "mx-auto flex w-full max-w-[90rem]", children: [
5968
+ /* @__PURE__ */ 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: [
5969
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
5970
+ /* @__PURE__ */ jsx(Link6, { href: home, className: "px-2", "aria-label": "Home", children: /* @__PURE__ */ jsx(Lockup, { size: 26 }) }),
5971
+ familyMenu
6047
5972
  ] }),
6048
- /* @__PURE__ */ jsx("div", { children }),
6049
- error ? /* @__PURE__ */ jsx("p", { role: "alert", className: "text-[0.9375rem] text-destructive", children: error }) : null,
6050
- fineprint ? /* @__PURE__ */ jsx("p", { className: "text-[0.8125rem] leading-relaxed text-muted-foreground", children: fineprint }) : null
5973
+ switcher,
5974
+ /* @__PURE__ */ jsx(SideNav, { groups }),
5975
+ /* @__PURE__ */ jsx("div", { className: "mt-auto flex flex-col gap-3", children: footer })
5976
+ ] }),
5977
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 flex-col", children: [
5978
+ /* @__PURE__ */ jsx("div", { className: "hidden h-[4.5rem] items-center justify-end gap-3 px-8 lg:flex", children: account }),
5979
+ banner ? /* @__PURE__ */ jsx("div", { className: "px-4 pb-2 pt-4 md:px-8 lg:pt-0", children: banner }) : null,
5980
+ /* @__PURE__ */ jsx("main", { id: "main-content", className: "flex-1 px-4 pb-16 pt-6 md:px-8 lg:pt-2", children: /* @__PURE__ */ jsx("div", { className: "mx-auto w-full max-w-[72rem]", children }) })
6051
5981
  ] })
6052
5982
  ] }),
6053
- /* @__PURE__ */ jsxs(
6054
- "aside",
6055
- {
6056
- "aria-hidden": true,
6057
- 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",
6058
- children: [
6059
- /* @__PURE__ */ jsx("div", { className: "flex flex-1 items-center justify-center", children: art ?? /* @__PURE__ */ jsx(IsoCheck, { size: 340, settle: true, tilt: true, className: "max-w-full" }) }),
6060
- caption ? /* @__PURE__ */ jsx("div", { className: "flex max-w-[24rem] flex-col gap-3", children: caption }) : null
6061
- ]
6062
- }
6063
- )
5983
+ tabs ? /* @__PURE__ */ jsx(TabBar, { items: tabs }) : null
6064
5984
  ]
6065
5985
  }
6066
- );
6067
- }
6068
- var STATUS_WORDS = /* @__PURE__ */ new Set(["live", "testing", "not-yet", "paused", "good", "caution", "refused"]);
6069
- var pathOf = (href) => href.split(/[?#]/)[0].replace(/(.)\/$/, "$1");
6070
- function DocsNav({
6071
- sections,
6072
- current: current2,
6073
- onNavigate,
6074
- className
6075
- }) {
6076
- const here = pathOf(current2);
6077
- const activeSection = useMemo(
6078
- () => sections.findIndex((s) => s.items.some((i) => pathOf(i.href) === here)),
6079
- [sections, here]
6080
- );
6081
- const [peeked, setPeeked] = useState(() => /* @__PURE__ */ new Set());
6082
- useEffect(() => setPeeked(/* @__PURE__ */ new Set()), [activeSection]);
6083
- const activeRef = useRef(null);
6084
- useEffect(() => {
6085
- const id = requestAnimationFrame(() => activeRef.current?.scrollIntoView({ block: "nearest" }));
6086
- return () => cancelAnimationFrame(id);
6087
- }, [here]);
6088
- const base = useId();
6089
- return /* @__PURE__ */ jsx("nav", { "aria-label": "Docs", className: cn("flex flex-col gap-0.5", className), children: sections.map((section, si) => {
6090
- const isActive = si === activeSection;
6091
- const open = isActive || peeked.has(si);
6092
- const panel = `${base}-s${si}`;
6093
- return /* @__PURE__ */ jsxs("div", { children: [
6094
- /* @__PURE__ */ jsxs(
6095
- "button",
6096
- {
6097
- type: "button",
6098
- "aria-expanded": open,
6099
- "aria-controls": panel,
6100
- onClick: () => {
6101
- if (isActive) return;
6102
- setPeeked((p) => {
6103
- const n = new Set(p);
6104
- if (n.has(si)) n.delete(si);
6105
- else n.add(si);
6106
- return n;
6107
- });
6108
- },
6109
- className: cn(
6110
- "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",
6111
- isActive ? "font-medium text-foreground" : "text-muted-foreground hover:bg-accent hover:text-foreground",
6112
- isActive && "cursor-default"
6113
- ),
6114
- children: [
6115
- section.label,
6116
- /* @__PURE__ */ jsx(
6117
- ChevronRight,
6118
- {
6119
- "aria-hidden": true,
6120
- className: cn("size-3.5 shrink-0 text-oca-subtle transition-transform duration-200", open && "rotate-90")
6121
- }
6122
- )
6123
- ]
6124
- }
6125
- ),
6126
- /* @__PURE__ */ jsx("ul", { id: panel, hidden: !open, className: "mb-2 ml-2.5 mt-0.5 border-l border-border", children: section.items.map((item) => {
6127
- const on = pathOf(item.href) === here;
6128
- const badge = typeof item.badge === "string" && STATUS_WORDS.has(item.badge) ? /* @__PURE__ */ jsx(StatusBadge, { status: item.badge }) : item.badge ? /* @__PURE__ */ jsx(Badge, { tone: "muted", children: item.badge }) : null;
6129
- return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(
6130
- Link8,
6131
- {
6132
- href: item.href,
6133
- ref: on ? activeRef : void 0,
6134
- onClick: onNavigate,
6135
- "aria-current": on ? "page" : void 0,
6136
- className: cn(
6137
- "-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",
6138
- on ? "border-foreground font-medium text-foreground" : "border-transparent text-muted-foreground hover:border-oca-hairline-strong hover:text-foreground"
6139
- ),
6140
- children: [
6141
- /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1", children: item.label }),
6142
- badge
6143
- ]
6144
- }
6145
- ) }, item.href);
6146
- }) })
6147
- ] }, section.label);
6148
- }) });
5986
+ ) });
6149
5987
  }
6150
- var DOCS_HEADER_NAV = OCHK_IO_NAV.map((n) => n.href === DOCS_HREF ? { ...n, active: true } : n);
6151
- function DocsShell({
6152
- nav,
6153
- current: current2,
6154
- header,
6155
- search,
6156
- actions,
6157
- breadcrumbs,
6158
- toc,
6159
- pager,
6160
- footer,
6161
- children
5988
+ function AccountMenu({
5989
+ name,
5990
+ detail,
5991
+ items,
5992
+ nameFrom = "sm"
6162
5993
  }) {
6163
- const [menu, setMenu] = useState(false);
6164
- useEffect(() => setMenu(false), [current2]);
6165
- const read = useHeadings("#docs-content", current2);
6166
- const items = toc ?? read.items;
6167
- const activeId = toc ? void 0 : read.activeId;
6168
- const here = pathOf(current2);
6169
- const place = useMemo(() => {
6170
- for (const s of nav) {
6171
- const it = s.items.find((i) => pathOf(i.href) === here);
6172
- if (it) return { section: s.label, page: it.label };
6173
- }
6174
- return null;
6175
- }, [nav, here]);
6176
- return /* @__PURE__ */ jsxs("div", { className: "flex min-h-dvh flex-col bg-background", children: [
6177
- /* @__PURE__ */ jsx(SkipLink, {}),
6178
- header ?? /* @__PURE__ */ jsx(SiteHeader, { home: OCHK_IO, family: "docs", nav: DOCS_HEADER_NAV, search, actions }),
6179
- /* @__PURE__ */ 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__ */ jsx("div", { className: "oca-container flex h-12 items-center gap-2", children: /* @__PURE__ */ jsxs(Sheet, { open: menu, onOpenChange: setMenu, children: [
6180
- /* @__PURE__ */ 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: [
6181
- /* @__PURE__ */ jsx(PanelLeft, { "aria-hidden": true, className: "size-[1.125rem] shrink-0" }),
6182
- /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Docs menu. " }),
6183
- place ? /* @__PURE__ */ jsxs("span", { className: "flex min-w-0 items-center gap-1.5", children: [
6184
- /* @__PURE__ */ jsx("span", { className: "shrink-0 text-muted-foreground", children: place.section }),
6185
- /* @__PURE__ */ jsx(ChevronRight, { "aria-hidden": true, className: "size-3.5 shrink-0 text-oca-subtle" }),
6186
- /* @__PURE__ */ jsx("span", { className: "truncate font-medium", children: place.page })
6187
- ] }) : /* @__PURE__ */ jsx("span", { className: "font-medium", children: "Docs" })
6188
- ] }),
6189
- /* @__PURE__ */ jsxs(SheetContent, { side: "left", className: "w-[min(88vw,22rem)] gap-0 p-0", children: [
6190
- /* @__PURE__ */ jsx("div", { className: "border-b border-border px-5 py-4 pr-14", children: /* @__PURE__ */ jsx(SheetTitle, { className: "text-[1.0625rem] font-medium", children: "Docs" }) }),
6191
- /* @__PURE__ */ jsx("div", { className: "overflow-y-auto p-3", children: /* @__PURE__ */ jsx(DocsNav, { sections: nav, current: current2, onNavigate: () => setMenu(false) }) })
6192
- ] })
6193
- ] }) }) }),
6194
- /* @__PURE__ */ jsx("div", { className: "oca-container flex-1", children: /* @__PURE__ */ 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: [
6195
- /* @__PURE__ */ 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__ */ jsx(DocsNav, { sections: nav, current: current2 }) }),
6196
- /* @__PURE__ */ jsxs("main", { id: "main-content", className: "min-w-0 pb-16 pt-6 md:pt-8", children: [
6197
- breadcrumbs ? /* @__PURE__ */ jsx("div", { className: "mb-6 max-lg:hidden", children: breadcrumbs }) : null,
6198
- items.length > 1 ? /* @__PURE__ */ jsxs("details", { className: "group mb-8 rounded-2xl border border-border bg-card xl:hidden", children: [
6199
- /* @__PURE__ */ 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: [
6200
- "On this page",
6201
- /* @__PURE__ */ jsx(ChevronDown, { "aria-hidden": true, className: "size-4 text-muted-foreground transition-transform group-open:rotate-180" })
6202
- ] }),
6203
- /* @__PURE__ */ jsx(OnThisPage, { items, activeId, title: null, className: "px-4 pb-4" })
6204
- ] }) : null,
6205
- /* @__PURE__ */ jsx("article", { id: "docs-content", className: "max-w-[46rem]", children }),
6206
- pager ? /* @__PURE__ */ jsx("div", { className: "mt-16 max-w-[46rem]", children: pager }) : null
6207
- ] }),
6208
- /* @__PURE__ */ 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__ */ jsx(OnThisPage, { items, activeId }) : null })
6209
- ] }) }),
6210
- footer ?? /* @__PURE__ */ jsx(SiteFooter, { columns: OCHK_IO_FOOTER, family: true, legal: true, signature: false })
6211
- ] });
6212
- }
6213
- function SideNav({ groups, onNavigate }) {
6214
- return /* @__PURE__ */ jsx("nav", { "aria-label": "Pages", className: "flex flex-col gap-5", children: groups.map((g, gi) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5", children: [
6215
- g.label ? /* @__PURE__ */ jsx("p", { className: "px-3 pb-1 text-[0.8125rem] text-muted-foreground", children: g.label }) : null,
6216
- g.items.map((it) => /* @__PURE__ */ jsxs(
6217
- Link8,
5994
+ const initial = name.trim().charAt(0).toUpperCase() || "\xB7";
5995
+ return /* @__PURE__ */ jsxs(DropdownMenu, { children: [
5996
+ /* @__PURE__ */ jsxs(
5997
+ DropdownMenuTrigger,
6218
5998
  {
6219
- href: it.href,
6220
- onClick: onNavigate,
6221
- "aria-current": it.active ? "page" : void 0,
6222
5999
  className: cn(
6223
- "flex h-9 items-center gap-3 rounded-xl px-3 text-[0.9375rem] transition-colors",
6224
- "[&_svg]:size-[1.0625rem] [&_svg]:shrink-0",
6225
- it.active ? "bg-card text-foreground shadow-sm ring-1 ring-border [&_svg]:text-foreground" : "text-muted-foreground hover:bg-accent hover:text-foreground"
6000
+ "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",
6001
+ nameFrom === "lg" ? "lg:pr-3.5" : "sm:pr-3.5"
6226
6002
  ),
6003
+ "aria-label": `${name}, account menu`,
6227
6004
  children: [
6228
- it.icon,
6229
- /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate", children: it.label }),
6230
- it.badge ? /* @__PURE__ */ jsx("span", { className: "shrink-0", children: it.badge }) : null
6005
+ /* @__PURE__ */ jsx(
6006
+ "span",
6007
+ {
6008
+ "aria-hidden": true,
6009
+ "data-initial": initial,
6010
+ className: "flex size-8 items-center justify-center rounded-full bg-foreground text-[0.8125rem] font-medium text-background before:content-[attr(data-initial)]"
6011
+ }
6012
+ ),
6013
+ /* @__PURE__ */ jsx("span", { className: cn("max-w-[10rem] truncate", nameFrom === "lg" ? "max-lg:hidden" : "max-sm:hidden"), children: name })
6231
6014
  ]
6232
- },
6233
- it.href
6234
- ))
6235
- ] }, g.label ?? gi)) });
6015
+ }
6016
+ ),
6017
+ /* @__PURE__ */ jsxs(DropdownMenuContent, { align: "end", className: "w-64", children: [
6018
+ /* @__PURE__ */ jsxs(DropdownMenuLabel, { className: "flex flex-col gap-0.5", children: [
6019
+ /* @__PURE__ */ jsx("span", { className: "truncate text-[0.9375rem] font-medium text-foreground", children: name }),
6020
+ detail ? /* @__PURE__ */ jsx("span", { className: "truncate font-mono text-[0.75rem]", children: detail }) : null
6021
+ ] }),
6022
+ /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
6023
+ items.map(
6024
+ (it, i) => it === "separator" ? /* @__PURE__ */ jsx(DropdownMenuSeparator, {}, `sep-${i}`) : it.href ? /* @__PURE__ */ jsx(DropdownMenuItem, { asChild: true, destructive: it.destructive, children: /* @__PURE__ */ jsxs(Link6, { href: it.href, children: [
6025
+ it.icon,
6026
+ it.label
6027
+ ] }) }, it.label) : /* @__PURE__ */ jsxs(DropdownMenuItem, { onSelect: it.onSelect, destructive: it.destructive, children: [
6028
+ it.icon,
6029
+ it.label
6030
+ ] }, it.label)
6031
+ )
6032
+ ] })
6033
+ ] });
6236
6034
  }
6237
- function SectionSwitch({
6238
- sections,
6239
- current: current2,
6240
- onNavigate
6241
- }) {
6242
- const cols = sections.length <= 3 ? sections.length : 2;
6035
+ function ThemeToggle({ className }) {
6036
+ const { theme, setTheme } = useTheme();
6037
+ const [mounted, setMounted] = useState(false);
6038
+ useEffect(() => setMounted(true), []);
6039
+ const current2 = mounted ? theme ?? "system" : "system";
6040
+ const next = current2 === "light" ? "dark" : current2 === "dark" ? "system" : "light";
6041
+ const Icon2 = current2 === "light" ? Sun : current2 === "dark" ? Moon : SunMoon;
6243
6042
  return /* @__PURE__ */ jsx(
6244
- "nav",
6043
+ "button",
6245
6044
  {
6246
- "aria-label": "Sections",
6247
- className: cn("grid gap-1 bg-muted p-1", cols === sections.length ? "rounded-full" : "rounded-[1.25rem]"),
6248
- style: { gridTemplateColumns: `repeat(${cols}, minmax(0, 1fr))` },
6249
- children: sections.map((sec) => {
6250
- const on = sec.id === current2.id;
6251
- return /* @__PURE__ */ jsx(
6252
- Link8,
6253
- {
6254
- href: sec.href,
6255
- onClick: onNavigate,
6256
- "aria-current": on ? "true" : void 0,
6257
- className: cn(
6258
- "flex h-8 min-w-0 items-center justify-center rounded-full px-1.5 text-[0.8125rem] font-medium transition-colors",
6259
- on ? "bg-card text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"
6260
- ),
6261
- children: /* @__PURE__ */ jsx("span", { className: "truncate", children: sec.label })
6262
- },
6263
- sec.id
6264
- );
6265
- })
6045
+ type: "button",
6046
+ onClick: () => setTheme(next),
6047
+ "aria-label": `Theme: ${current2}. Switch to ${next}`,
6048
+ title: `Theme: ${current2}`,
6049
+ className: cn(
6050
+ "inline-flex size-10 items-center justify-center rounded-full text-muted-foreground transition-colors hover:bg-accent hover:text-foreground",
6051
+ className
6052
+ ),
6053
+ children: /* @__PURE__ */ jsx(Icon2, { className: "size-[1.125rem]" })
6266
6054
  }
6267
6055
  );
6268
6056
  }
6269
- function TabBar({ items }) {
6057
+ function NavLink({
6058
+ item,
6059
+ className,
6060
+ onNavigate,
6061
+ line = false
6062
+ }) {
6063
+ const cls = cn(
6064
+ "rounded-full px-3 py-2 text-[0.9375rem] transition-colors",
6065
+ item.active ? "text-foreground" : "text-muted-foreground hover:text-foreground",
6066
+ line && "relative after:absolute after:inset-x-3 after:-bottom-[0.625rem] after:h-0.5 after:rounded-full",
6067
+ line && item.active && "after:bg-foreground",
6068
+ className
6069
+ );
6070
+ if (item.external) {
6071
+ return /* @__PURE__ */ jsx("a", { href: item.href, className: cls, rel: "noreferrer", onClick: onNavigate, children: item.label });
6072
+ }
6073
+ return /* @__PURE__ */ jsx(Link6, { href: item.href, className: cls, "aria-current": item.active ? "page" : void 0, onClick: onNavigate, children: item.label });
6074
+ }
6075
+ function NavRow({ item, onNavigate }) {
6076
+ const body = /* @__PURE__ */ jsxs(Fragment, { children: [
6077
+ /* @__PURE__ */ jsx("span", { className: "text-[0.9375rem] font-medium leading-6 text-foreground", children: item.label }),
6078
+ item.description ? /* @__PURE__ */ jsx("span", { className: "text-[0.8125rem] leading-snug text-muted-foreground", children: item.description }) : null
6079
+ ] });
6080
+ const cls = cn(
6081
+ "flex flex-col gap-0.5 rounded-xl px-3 py-2 transition-colors hover:bg-accent",
6082
+ item.active && "bg-muted hover:bg-muted dark:bg-white/[0.06]"
6083
+ );
6084
+ return item.external ? /* @__PURE__ */ jsx("a", { href: item.href, className: cls, rel: "noreferrer", onClick: onNavigate, children: body }) : /* @__PURE__ */ jsx(Link6, { href: item.href, className: cls, "aria-current": item.active ? "page" : void 0, onClick: onNavigate, children: body });
6085
+ }
6086
+ var seeAll = (item) => typeof item.label === "string" ? `All ${item.label.toLowerCase()}` : "See all";
6087
+ function NavDropdown({ item }) {
6088
+ const [open, setOpen] = useState(false);
6089
+ const active = item.active || item.children?.some((c) => c.active);
6090
+ return /* @__PURE__ */ jsxs(Popover, { open, onOpenChange: setOpen, children: [
6091
+ /* @__PURE__ */ jsxs(
6092
+ PopoverTrigger,
6093
+ {
6094
+ className: cn(
6095
+ "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",
6096
+ active ? "text-foreground" : "text-muted-foreground hover:text-foreground data-[state=open]:text-foreground"
6097
+ ),
6098
+ children: [
6099
+ item.label,
6100
+ /* @__PURE__ */ jsx(ChevronDown, { "aria-hidden": true, className: "size-3.5 transition-transform duration-200 group-data-[state=open]:rotate-180" })
6101
+ ]
6102
+ }
6103
+ ),
6104
+ /* @__PURE__ */ jsxs(PopoverContent, { align: "center", sideOffset: 10, className: "w-[min(calc(100vw-2rem),26rem)] p-2", children: [
6105
+ /* @__PURE__ */ jsx("ul", { className: "flex flex-col", children: item.children?.map((c) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(NavRow, { item: c, onNavigate: () => setOpen(false) }) }, c.href)) }),
6106
+ /* @__PURE__ */ jsx("div", { className: "mt-1.5 border-t border-border px-1 pt-1.5", children: /* @__PURE__ */ jsx(
6107
+ NavLink,
6108
+ {
6109
+ item: { ...item, label: seeAll(item), children: void 0 },
6110
+ className: "block rounded-xl px-2 py-2 text-[0.875rem]",
6111
+ onNavigate: () => setOpen(false)
6112
+ }
6113
+ ) })
6114
+ ] })
6115
+ ] });
6116
+ }
6117
+ function SiteHeader({
6118
+ home = "/",
6119
+ brand,
6120
+ product,
6121
+ family,
6122
+ nav = [],
6123
+ search,
6124
+ actions,
6125
+ variant = "site",
6126
+ navOnPhone = true,
6127
+ menu: menuExtra,
6128
+ className
6129
+ }) {
6130
+ const [open, setOpen] = useState(false);
6131
+ const tool = variant === "tool";
6132
+ const size = tool ? 24 : 28;
6133
+ const current2 = typeof family === "string" ? family : void 0;
6134
+ const phoneNav = navOnPhone ? nav : [];
6135
+ const menu = phoneNav.length > 0 || Boolean(family) || Boolean(menuExtra);
6136
+ const brandNode = brand ?? /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center", children: [
6137
+ /* @__PURE__ */ jsx(Lockup, { size }),
6138
+ product ? /* @__PURE__ */ jsxs(Fragment, { children: [
6139
+ /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "mx-3 h-5 w-px bg-oca-hairline-strong" }),
6140
+ /* @__PURE__ */ jsx("span", { className: "font-medium tracking-[-0.01em]", style: { fontSize: size * 0.56 }, children: product })
6141
+ ] }) : null
6142
+ ] });
6143
+ const navigation = nav.length > 0 ? /* @__PURE__ */ jsx("nav", { "aria-label": "Main", className: "hidden items-center gap-1 md:flex", children: nav.map(
6144
+ (n) => n.children?.length ? /* @__PURE__ */ jsx(NavDropdown, { item: n }, n.href) : (
6145
+ // Between md and lg the family menu and the actions share the row: tighter.
6146
+ /* @__PURE__ */ jsx(NavLink, { item: n, line: tool, className: tool ? void 0 : "md:max-lg:px-2.5" }, n.href)
6147
+ )
6148
+ ) }) : null;
6270
6149
  return /* @__PURE__ */ jsx(
6271
- "nav",
6150
+ "header",
6272
6151
  {
6273
- "aria-label": "Pages",
6274
- "data-oca-tabbar": "",
6275
- 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",
6276
- children: /* @__PURE__ */ jsx(
6152
+ className: cn(
6153
+ "sticky top-0 z-40 w-full border-b bg-background/95 backdrop-blur-md supports-[backdrop-filter]:bg-background/90",
6154
+ tool ? "border-border" : "border-transparent",
6155
+ className
6156
+ ),
6157
+ children: /* @__PURE__ */ jsxs(
6277
6158
  "div",
6278
6159
  {
6279
- className: "mx-auto grid h-14 max-w-[32rem] px-1.5",
6280
- style: { gridTemplateColumns: `repeat(${items.length}, minmax(0, 1fr))` },
6281
- children: items.map((it) => /* @__PURE__ */ jsxs(
6282
- Link8,
6283
- {
6284
- href: it.href,
6285
- "aria-current": it.active ? "page" : void 0,
6286
- className: cn(
6287
- "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",
6288
- it.active ? "text-foreground" : "text-muted-foreground hover:text-foreground"
6289
- ),
6290
- children: [
6291
- /* @__PURE__ */ jsxs(
6292
- "span",
6160
+ className: cn(
6161
+ "flex items-center justify-between gap-4",
6162
+ tool ? "h-14 px-4 md:px-6" : "oca-container h-16 md:h-[4.5rem] md:max-lg:gap-2",
6163
+ // Three columns, the outer two each at least their content: the
6164
+ // navigation stays centred whatever the actions hold, so it does
6165
+ // not shift when they change (signed out to signed in).
6166
+ !tool && nav.length > 0 && "md:grid md:grid-cols-[minmax(max-content,1fr)_auto_minmax(max-content,1fr)]"
6167
+ ),
6168
+ children: [
6169
+ /* @__PURE__ */ jsxs("div", { className: cn("flex min-w-0 items-center gap-1", tool ? "md:gap-1" : "justify-self-start"), children: [
6170
+ /* @__PURE__ */ jsxs(Link6, { href: home, className: "-ml-1 min-w-0 rounded-lg p-1", children: [
6171
+ brandNode,
6172
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: " home" })
6173
+ ] }),
6174
+ family ? /* @__PURE__ */ jsx(FamilyMenu, { current: current2, className: "max-md:hidden" }) : null,
6175
+ tool && navigation ? /* @__PURE__ */ jsx("div", { className: "ml-5", children: navigation }) : null
6176
+ ] }),
6177
+ !tool ? navigation : null,
6178
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 justify-self-end", children: [
6179
+ search,
6180
+ actions,
6181
+ menu ? /* @__PURE__ */ jsxs(Sheet, { open, onOpenChange: setOpen, children: [
6182
+ /* @__PURE__ */ jsx(
6183
+ SheetTrigger,
6293
6184
  {
6294
- className: cn(
6295
- "relative flex h-7 w-12 items-center justify-center rounded-full transition-[background-color,box-shadow] duration-200",
6296
- "[&_svg]:size-[1.125rem] [&_svg]:shrink-0",
6297
- it.active ? "bg-card shadow-sm ring-1 ring-border [&_svg]:stroke-2" : "[&_svg]:stroke-[1.75]"
6298
- ),
6299
- children: [
6300
- it.icon,
6301
- it.badge ? /* @__PURE__ */ 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
6302
- ]
6185
+ className: "inline-flex size-10 items-center justify-center rounded-full text-foreground hover:bg-accent md:hidden",
6186
+ "aria-label": "Open menu",
6187
+ children: /* @__PURE__ */ jsx(Menu, { className: "size-5" })
6303
6188
  }
6304
6189
  ),
6305
- /* @__PURE__ */ jsx("span", { className: "max-w-full truncate px-0.5", children: it.label }),
6306
- it.badge ? /* @__PURE__ */ jsx("span", { className: "sr-only", children: it.badge }) : null
6307
- ]
6308
- },
6309
- it.href
6310
- ))
6190
+ /* @__PURE__ */ jsxs(SheetContent, { side: "right", className: "pt-16", children: [
6191
+ /* @__PURE__ */ jsx(SheetTitle, { className: "sr-only", children: "Menu" }),
6192
+ menuExtra ? /* @__PURE__ */ jsx("div", { className: cn("flex flex-col", (phoneNav.length > 0 || family) && "border-b border-border pb-3"), children: menuExtra }) : null,
6193
+ phoneNav.length > 0 ? /* @__PURE__ */ jsx("nav", { "aria-label": "Main", className: "flex flex-col", children: phoneNav.map(
6194
+ (n) => n.children?.length ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col py-2", children: [
6195
+ /* @__PURE__ */ jsx("p", { className: "px-3 pb-1 text-[0.8125rem] text-muted-foreground", children: n.label }),
6196
+ n.children.map((c) => /* @__PURE__ */ jsx(
6197
+ NavLink,
6198
+ {
6199
+ item: c,
6200
+ className: "rounded-xl px-3 py-2.5 text-[1.0625rem]",
6201
+ onNavigate: () => setOpen(false)
6202
+ },
6203
+ c.href
6204
+ ))
6205
+ ] }, n.href) : /* @__PURE__ */ jsx(
6206
+ NavLink,
6207
+ {
6208
+ item: n,
6209
+ className: "rounded-xl px-3 py-3 text-[1.0625rem]",
6210
+ onNavigate: () => setOpen(false)
6211
+ },
6212
+ n.href
6213
+ )
6214
+ ) }) : null,
6215
+ family ? /* @__PURE__ */ jsxs("details", { className: cn("group", phoneNav.length > 0 && "mt-2 border-t border-border pt-4"), children: [
6216
+ /* @__PURE__ */ 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: [
6217
+ "All orangecheck sites",
6218
+ /* @__PURE__ */ jsx(ChevronDown, { "aria-hidden": true, className: "size-4 text-muted-foreground transition-transform group-open:rotate-180" })
6219
+ ] }),
6220
+ /* @__PURE__ */ jsx(FamilyList, { current: current2, onNavigate: () => setOpen(false), stack: true, className: "mt-2" })
6221
+ ] }) : null
6222
+ ] })
6223
+ ] }) : null
6224
+ ] })
6225
+ ]
6311
6226
  }
6312
6227
  )
6313
6228
  }
6314
6229
  );
6315
6230
  }
6316
- function tabsFor(groups) {
6317
- const items = groups.flatMap((g) => g.items);
6318
- return items.length >= 2 && items.length <= 5 && items.every((it) => it.icon) ? items : null;
6319
- }
6320
- var activeItem = (groups) => groups.flatMap((g) => g.items).find((it) => it.active);
6321
- var warned = /* @__PURE__ */ new Set();
6322
- function warnDuplicateLabels(groups) {
6323
- if (typeof process === "undefined" || process.env.NODE_ENV === "production") return;
6324
- const seen = /* @__PURE__ */ new Set();
6325
- for (const it of groups.flatMap((g) => g.items)) {
6326
- if (seen.has(it.label) && !warned.has(it.label)) {
6327
- warned.add(it.label);
6328
- console.warn(`AppShell: two pages are labelled "${it.label}"; give each its own name.`);
6231
+ function SkipLink({ href = "#main-content", children = "Skip to content" }) {
6232
+ return /* @__PURE__ */ jsx(
6233
+ "a",
6234
+ {
6235
+ href,
6236
+ 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",
6237
+ children
6329
6238
  }
6330
- seen.add(it.label);
6331
- }
6239
+ );
6332
6240
  }
6333
- function AppShell({
6334
- nav,
6335
- sections,
6336
- activeSection,
6337
- page: pageOverride,
6338
- persistent = [],
6339
- home = "/",
6340
- account,
6341
- banner,
6342
- footer,
6241
+ var BANNER_TONE = {
6242
+ neutral: "border-border bg-muted",
6243
+ brand: "border-[color-mix(in_oklab,var(--oca-orange)_30%,var(--border))] bg-[color-mix(in_oklab,var(--oca-orange)_9%,var(--background))]",
6244
+ danger: "border-[color-mix(in_oklab,var(--destructive)_35%,var(--border))] bg-[color-mix(in_oklab,var(--destructive)_8%,var(--background))]"
6245
+ };
6246
+ function SiteBanner({
6247
+ tone = "neutral",
6343
6248
  children,
6249
+ action,
6344
6250
  className
6345
6251
  }) {
6346
- const [open, setOpen] = useState(false);
6347
- const current2 = sections && sections.length > 0 ? sections.find((sec) => sec.id === activeSection) ?? sections.find((sec) => activeItem(sec.groups)) ?? sections[0] : void 0;
6348
- const groups = current2 ? [...current2.groups, ...persistent] : [...nav ?? [], ...persistent];
6349
- warnDuplicateLabels(groups);
6350
- const tabs = current2 ? null : tabsFor(groups);
6351
- const page = activeItem(groups);
6352
- const place = useMemo(
6353
- () => ({
6354
- section: current2 ? current2.title ?? current2.label : void 0,
6355
- page: pageOverride ?? page?.label
6356
- }),
6357
- [current2, page?.label, pageOverride]
6358
- );
6359
- const switcher = sections && current2 && sections.length > 1 ? /* @__PURE__ */ jsx(SectionSwitch, { sections, current: current2, onNavigate: () => setOpen(false) }) : null;
6360
- return /* @__PURE__ */ jsx(ShellContext.Provider, { value: place, children: /* @__PURE__ */ jsxs(
6361
- "div",
6362
- {
6363
- className: cn(
6364
- "min-h-dvh bg-background",
6365
- tabs && "max-md:pb-[calc(3.5rem_+_env(safe-area-inset-bottom))]",
6366
- className
6367
- ),
6368
- children: [
6369
- /* @__PURE__ */ jsxs("div", { className: "sticky top-0 z-40 border-b border-border bg-background/90 backdrop-blur-md lg:hidden", children: [
6370
- /* @__PURE__ */ jsxs("div", { className: "flex h-14 items-center gap-2 px-3", children: [
6371
- /* @__PURE__ */ jsxs(Sheet, { open, onOpenChange: setOpen, children: [
6372
- /* @__PURE__ */ jsx(
6373
- SheetTrigger,
6374
- {
6375
- className: cn(
6376
- "inline-flex size-10 items-center justify-center rounded-full hover:bg-accent",
6377
- // The tab bar holds every page; the sheet is left for a footer.
6378
- tabs && !footer && "max-md:hidden"
6379
- ),
6380
- "aria-label": "Open navigation",
6381
- children: /* @__PURE__ */ jsx(Menu, { className: "size-5" })
6382
- }
6383
- ),
6384
- /* @__PURE__ */ jsxs(SheetContent, { side: "left", className: "flex flex-col gap-6 overflow-y-auto p-4 pt-16", children: [
6385
- /* @__PURE__ */ jsx(SheetTitle, { className: "sr-only", children: "Navigation" }),
6386
- switcher,
6387
- /* @__PURE__ */ jsx("div", { className: tabs ? "max-md:hidden" : void 0, children: /* @__PURE__ */ jsx(SideNav, { groups, onNavigate: () => setOpen(false) }) }),
6388
- footer ? /* @__PURE__ */ jsx("div", { className: "mt-auto flex flex-col gap-3", children: footer }) : null
6389
- ] })
6390
- ] }),
6391
- /* @__PURE__ */ jsx(Link8, { href: home, "aria-label": "Home", className: "rounded-lg p-1", children: /* @__PURE__ */ jsx(Lockup, { size: 22 }) }),
6392
- /* @__PURE__ */ jsx("div", { className: "ml-auto flex items-center", children: account })
6252
+ return /* @__PURE__ */ jsx("div", { role: "status", "aria-live": "polite", "data-tone": tone, className: cn("border-b text-[0.875rem]", BANNER_TONE[tone], className), children: /* @__PURE__ */ jsxs("div", { className: "oca-container flex flex-wrap items-center justify-between gap-x-4 gap-y-1 py-2.5", children: [
6253
+ /* @__PURE__ */ jsxs("p", { className: "flex min-w-0 items-baseline gap-2.5 leading-snug", children: [
6254
+ tone !== "neutral" ? /* @__PURE__ */ jsx(
6255
+ "span",
6256
+ {
6257
+ "aria-hidden": true,
6258
+ className: cn(
6259
+ "size-2 shrink-0 translate-y-[-0.05em] rounded-full",
6260
+ tone === "brand" ? "bg-oca-orange" : "bg-destructive"
6261
+ )
6262
+ }
6263
+ ) : null,
6264
+ /* @__PURE__ */ jsx("span", { children })
6265
+ ] }),
6266
+ action ? /* @__PURE__ */ jsx("div", { className: cn("shrink-0 font-medium", tone !== "neutral" && "max-sm:pl-[1.125rem]"), children: action }) : null
6267
+ ] }) });
6268
+ }
6269
+ var FOOT_LINK = "inline-flex min-h-11 items-center transition-colors hover:text-foreground md:min-h-0";
6270
+ function LegalRow({ links }) {
6271
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-x-6 gap-y-2 sm:flex-row sm:items-center sm:justify-between", children: [
6272
+ /* @__PURE__ */ jsx("nav", { "aria-label": "Legal", children: /* @__PURE__ */ jsx("ul", { className: "flex flex-wrap gap-x-5", children: links.map((l) => /* @__PURE__ */ jsx("li", { children: l.href.startsWith("/") ? /* @__PURE__ */ jsx(Link6, { href: l.href, className: FOOT_LINK, children: l.label }) : /* @__PURE__ */ jsx("a", { href: l.href, className: FOOT_LINK, children: l.label }) }, l.href)) }) }),
6273
+ /* @__PURE__ */ jsxs("p", { children: [
6274
+ "\xA9 ",
6275
+ (/* @__PURE__ */ new Date()).getFullYear(),
6276
+ " OrangeCheck"
6277
+ ] })
6278
+ ] });
6279
+ }
6280
+ function SiteFooter({
6281
+ columns = [],
6282
+ family = false,
6283
+ legal = false,
6284
+ compact = false,
6285
+ fineprint,
6286
+ meta,
6287
+ signature = true,
6288
+ className
6289
+ }) {
6290
+ const legalLinks = legal === true ? LEGAL_LINKS : legal || null;
6291
+ if (compact) {
6292
+ return /* @__PURE__ */ jsx("footer", { className: cn("border-t border-border bg-background text-[0.875rem] text-muted-foreground", className), children: /* @__PURE__ */ 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: [
6293
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-x-6 gap-y-1", children: [
6294
+ /* @__PURE__ */ jsx("a", { href: OCHK_IO, className: "rounded-lg text-foreground", children: /* @__PURE__ */ jsx(Lockup, { size: 22 }) }),
6295
+ family ? /* @__PURE__ */ jsx("nav", { "aria-label": "Protocols", children: /* @__PURE__ */ jsx("ul", { className: "flex flex-wrap gap-x-4", children: PROTOCOLS.map((p) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx("a", { href: p.pageHref, className: FOOT_LINK, children: p.label }) }, p.slug)) }) }) : null
6296
+ ] }),
6297
+ legalLinks || meta ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-x-6 gap-y-2 sm:flex-row sm:flex-wrap sm:items-center", children: [
6298
+ legalLinks ? /* @__PURE__ */ jsx(LegalRow, { links: legalLinks }) : null,
6299
+ meta
6300
+ ] }) : null
6301
+ ] }) });
6302
+ }
6303
+ const cols = [
6304
+ ...columns,
6305
+ ...family ? familyByGroup().map((g) => ({
6306
+ // The lockup above already says orangecheck.
6307
+ heading: g.id === "orangecheck" ? "Start here" : g.label,
6308
+ links: g.sites.map((s) => ({ href: s.href, label: s.label, external: true }))
6309
+ })) : []
6310
+ ];
6311
+ const n = cols.length;
6312
+ const inline = n <= 5;
6313
+ const grid = {
6314
+ "--oca-footer-md": `repeat(${Math.max(1, Math.min(n, 4))}, minmax(0, 1fr))`,
6315
+ "--oca-footer-lg": inline ? `minmax(0, 1.3fr) repeat(${Math.max(1, n)}, minmax(0, 1fr))` : `repeat(${Math.min(n, 6)}, minmax(0, 1fr))`
6316
+ };
6317
+ return /* @__PURE__ */ jsxs("footer", { className: cn("border-t border-border bg-background", className), children: [
6318
+ /* @__PURE__ */ jsxs(
6319
+ "div",
6320
+ {
6321
+ style: grid,
6322
+ 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)]",
6323
+ children: [
6324
+ /* @__PURE__ */ jsxs("div", { className: cn("col-span-full flex flex-col gap-4", inline && "lg:col-span-1"), children: [
6325
+ /* @__PURE__ */ jsx(Lockup, { size: 26 }),
6326
+ fineprint ? /* @__PURE__ */ jsx("p", { className: "max-w-xs text-[0.9375rem] leading-relaxed text-muted-foreground", children: fineprint }) : null
6393
6327
  ] }),
6394
- place.page ? /* @__PURE__ */ jsxs(
6395
- "div",
6396
- {
6397
- className: cn(
6398
- "flex h-9 items-center gap-1.5 border-t border-border px-4 text-[0.875rem]",
6399
- // The active tab already names the page.
6400
- tabs && !pageOverride && "max-md:hidden"
6401
- ),
6402
- children: [
6403
- place.section ? /* @__PURE__ */ jsxs(Fragment, { children: [
6404
- /* @__PURE__ */ jsx("span", { className: "shrink-0 text-muted-foreground", children: place.section }),
6405
- /* @__PURE__ */ jsx(ChevronRight, { "aria-hidden": true, className: "size-3.5 shrink-0 text-muted-foreground" })
6406
- ] }) : null,
6407
- /* @__PURE__ */ jsx("span", { className: "truncate font-medium", children: place.page })
6408
- ]
6409
- }
6410
- ) : null
6328
+ cols.map((col, i) => {
6329
+ const spans = n % 2 === 1 && i === n - 1;
6330
+ return /* @__PURE__ */ jsxs(
6331
+ "div",
6332
+ {
6333
+ className: cn("flex min-w-0 flex-col gap-1", spans && "col-span-2 md:col-span-1"),
6334
+ children: [
6335
+ /* @__PURE__ */ jsx("p", { className: "mb-2 text-[0.875rem] font-medium", children: col.heading }),
6336
+ /* @__PURE__ */ 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__ */ jsx(
6337
+ NavLink,
6338
+ {
6339
+ item: l,
6340
+ className: "-mx-3 py-2.5 text-[0.9375rem] md:py-1.5"
6341
+ },
6342
+ l.href
6343
+ )) })
6344
+ ]
6345
+ },
6346
+ col.heading
6347
+ );
6348
+ })
6349
+ ]
6350
+ }
6351
+ ),
6352
+ signature ? /* @__PURE__ */ jsx("div", { "aria-hidden": true, className: "oca-container select-none overflow-hidden pb-8 md:pb-12", children: /* @__PURE__ */ 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: [
6353
+ /* @__PURE__ */ jsx("span", { className: "mb-[0.06em] inline-block w-[1.1em] shrink-0", children: /* @__PURE__ */ jsx(Mark, { className: "block h-auto w-full" }) }),
6354
+ /* @__PURE__ */ jsx("span", { children: "orangecheck" })
6355
+ ] }) }) : null,
6356
+ legalLinks || meta ? /* @__PURE__ */ jsx("div", { className: "oca-container", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3 border-t border-border py-6 text-[0.875rem] text-muted-foreground", children: [
6357
+ legalLinks ? /* @__PURE__ */ jsx(LegalRow, { links: legalLinks }) : null,
6358
+ meta
6359
+ ] }) }) : null
6360
+ ] });
6361
+ }
6362
+ function OchkIoFooter({ columns = OCHK_IO_FOOTER, className }) {
6363
+ return /* @__PURE__ */ jsx(
6364
+ SiteFooter,
6365
+ {
6366
+ columns,
6367
+ family: true,
6368
+ legal: true,
6369
+ fineprint: "Open protocols on Bitcoin. Anyone can check the result.",
6370
+ meta: /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-4", children: [
6371
+ /* @__PURE__ */ jsxs("p", { children: [
6372
+ "Open-source work on orangecheck is ",
6373
+ /* @__PURE__ */ jsx("span", { className: "whitespace-nowrap", children: "supported by OpenSats." })
6411
6374
  ] }),
6412
- /* @__PURE__ */ jsxs("div", { className: "mx-auto flex w-full max-w-[90rem]", children: [
6413
- /* @__PURE__ */ 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: [
6414
- /* @__PURE__ */ jsx(Link8, { href: home, className: "px-2", "aria-label": "Home", children: /* @__PURE__ */ jsx(Lockup, { size: 26 }) }),
6415
- switcher,
6416
- /* @__PURE__ */ jsx(SideNav, { groups }),
6417
- /* @__PURE__ */ jsx("div", { className: "mt-auto flex flex-col gap-3", children: footer })
6375
+ /* @__PURE__ */ jsx(ThemeToggle, { className: "-mx-3" })
6376
+ ] }),
6377
+ className
6378
+ }
6379
+ );
6380
+ }
6381
+ function SignInFrame({
6382
+ title = "Sign in",
6383
+ lead,
6384
+ children,
6385
+ error,
6386
+ fineprint,
6387
+ brand,
6388
+ home = "/",
6389
+ back,
6390
+ art,
6391
+ caption,
6392
+ className
6393
+ }) {
6394
+ return /* @__PURE__ */ jsxs(
6395
+ "main",
6396
+ {
6397
+ id: "main-content",
6398
+ className: cn("grid min-h-dvh grid-cols-1 bg-background text-foreground lg:grid-cols-2", className),
6399
+ children: [
6400
+ /* @__PURE__ */ jsxs("section", { className: "flex flex-col px-4 pb-8 pt-5 sm:px-8 lg:px-14 lg:pt-8", children: [
6401
+ /* @__PURE__ */ jsxs("header", { className: "flex items-center justify-between gap-4", children: [
6402
+ /* @__PURE__ */ jsxs(Link6, { href: home, className: "w-fit rounded-lg", children: [
6403
+ brand ?? /* @__PURE__ */ jsx(Lockup, { size: 28 }),
6404
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: " home" })
6405
+ ] }),
6406
+ back === void 0 ? /* @__PURE__ */ jsx(
6407
+ Link6,
6408
+ {
6409
+ href: home,
6410
+ className: "text-[0.9375rem] text-muted-foreground underline-offset-4 hover:text-foreground hover:underline",
6411
+ children: "Back to home"
6412
+ }
6413
+ ) : back
6418
6414
  ] }),
6419
- /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 flex-col", children: [
6420
- /* @__PURE__ */ jsx("div", { className: "hidden h-[4.5rem] items-center justify-end gap-3 px-8 lg:flex", children: account }),
6421
- banner ? /* @__PURE__ */ jsx("div", { className: "px-4 pb-2 pt-4 md:px-8 lg:pt-0", children: banner }) : null,
6422
- /* @__PURE__ */ jsx("main", { id: "main-content", className: "flex-1 px-4 pb-16 pt-6 md:px-8 lg:pt-2", children: /* @__PURE__ */ jsx("div", { className: "mx-auto w-full max-w-[72rem]", children }) })
6415
+ /* @__PURE__ */ jsxs("div", { className: "mx-auto flex w-full max-w-[25rem] flex-1 flex-col justify-center gap-9 py-12", children: [
6416
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
6417
+ /* @__PURE__ */ jsx("h1", { className: "oca-display-2", children: title }),
6418
+ lead ? /* @__PURE__ */ jsx("p", { className: "oca-lead", children: lead }) : null
6419
+ ] }),
6420
+ /* @__PURE__ */ jsx("div", { children }),
6421
+ error ? /* @__PURE__ */ jsx("p", { role: "alert", className: "text-[0.9375rem] text-destructive", children: error }) : null,
6422
+ fineprint ? /* @__PURE__ */ jsx("p", { className: "text-[0.8125rem] leading-relaxed text-muted-foreground", children: fineprint }) : null
6423
6423
  ] })
6424
6424
  ] }),
6425
- tabs ? /* @__PURE__ */ jsx(TabBar, { items: tabs }) : null
6425
+ /* @__PURE__ */ jsxs(
6426
+ "aside",
6427
+ {
6428
+ "aria-hidden": true,
6429
+ 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",
6430
+ children: [
6431
+ /* @__PURE__ */ jsx("div", { className: "flex flex-1 items-center justify-center", children: art ?? /* @__PURE__ */ jsx(IsoCheck, { size: 340, settle: true, tilt: true, className: "max-w-full" }) }),
6432
+ caption ? /* @__PURE__ */ jsx("div", { className: "flex max-w-[24rem] flex-col gap-3", children: caption }) : null
6433
+ ]
6434
+ }
6435
+ )
6426
6436
  ]
6427
6437
  }
6428
- ) });
6438
+ );
6429
6439
  }
6430
- function AccountMenu({
6431
- name,
6432
- detail,
6433
- items,
6434
- nameFrom = "sm"
6440
+ var STATUS_WORDS = /* @__PURE__ */ new Set(["live", "testing", "not-yet", "paused", "good", "caution", "refused"]);
6441
+ var pathOf = (href) => href.split(/[?#]/)[0].replace(/(.)\/$/, "$1");
6442
+ function DocsNav({
6443
+ sections,
6444
+ current: current2,
6445
+ onNavigate,
6446
+ className
6435
6447
  }) {
6436
- const initial = name.trim().charAt(0).toUpperCase() || "\xB7";
6437
- return /* @__PURE__ */ jsxs(DropdownMenu, { children: [
6438
- /* @__PURE__ */ jsxs(
6439
- DropdownMenuTrigger,
6440
- {
6441
- className: cn(
6442
- "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",
6443
- nameFrom === "lg" ? "lg:pr-3.5" : "sm:pr-3.5"
6444
- ),
6445
- "aria-label": `${name}, account menu`,
6446
- children: [
6447
- /* @__PURE__ */ jsx(
6448
- "span",
6449
- {
6450
- "aria-hidden": true,
6451
- "data-initial": initial,
6452
- className: "flex size-8 items-center justify-center rounded-full bg-foreground text-[0.8125rem] font-medium text-background before:content-[attr(data-initial)]"
6453
- }
6448
+ const here = pathOf(current2);
6449
+ const activeSection = useMemo(
6450
+ () => sections.findIndex((s) => s.items.some((i) => pathOf(i.href) === here)),
6451
+ [sections, here]
6452
+ );
6453
+ const [peeked, setPeeked] = useState(() => /* @__PURE__ */ new Set());
6454
+ useEffect(() => setPeeked(/* @__PURE__ */ new Set()), [activeSection]);
6455
+ const activeRef = useRef(null);
6456
+ useEffect(() => {
6457
+ const id = requestAnimationFrame(() => activeRef.current?.scrollIntoView({ block: "nearest" }));
6458
+ return () => cancelAnimationFrame(id);
6459
+ }, [here]);
6460
+ const base = useId();
6461
+ return /* @__PURE__ */ jsx("nav", { "aria-label": "Docs", className: cn("flex flex-col gap-0.5", className), children: sections.map((section, si) => {
6462
+ const isActive = si === activeSection;
6463
+ const open = isActive || peeked.has(si);
6464
+ const panel = `${base}-s${si}`;
6465
+ return /* @__PURE__ */ jsxs("div", { children: [
6466
+ /* @__PURE__ */ jsxs(
6467
+ "button",
6468
+ {
6469
+ type: "button",
6470
+ "aria-expanded": open,
6471
+ "aria-controls": panel,
6472
+ onClick: () => {
6473
+ if (isActive) return;
6474
+ setPeeked((p) => {
6475
+ const n = new Set(p);
6476
+ if (n.has(si)) n.delete(si);
6477
+ else n.add(si);
6478
+ return n;
6479
+ });
6480
+ },
6481
+ className: cn(
6482
+ "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",
6483
+ isActive ? "font-medium text-foreground" : "text-muted-foreground hover:bg-accent hover:text-foreground",
6484
+ isActive && "cursor-default"
6454
6485
  ),
6455
- /* @__PURE__ */ jsx("span", { className: cn("max-w-[10rem] truncate", nameFrom === "lg" ? "max-lg:hidden" : "max-sm:hidden"), children: name })
6456
- ]
6457
- }
6458
- ),
6459
- /* @__PURE__ */ jsxs(DropdownMenuContent, { align: "end", className: "w-64", children: [
6460
- /* @__PURE__ */ jsxs(DropdownMenuLabel, { className: "flex flex-col gap-0.5", children: [
6461
- /* @__PURE__ */ jsx("span", { className: "truncate text-[0.9375rem] font-medium text-foreground", children: name }),
6462
- detail ? /* @__PURE__ */ jsx("span", { className: "truncate font-mono text-[0.75rem]", children: detail }) : null
6463
- ] }),
6464
- /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
6465
- items.map(
6466
- (it, i) => it === "separator" ? /* @__PURE__ */ jsx(DropdownMenuSeparator, {}, `sep-${i}`) : it.href ? /* @__PURE__ */ jsx(DropdownMenuItem, { asChild: true, destructive: it.destructive, children: /* @__PURE__ */ jsxs(Link8, { href: it.href, children: [
6467
- it.icon,
6468
- it.label
6469
- ] }) }, it.label) : /* @__PURE__ */ jsxs(DropdownMenuItem, { onSelect: it.onSelect, destructive: it.destructive, children: [
6470
- it.icon,
6471
- it.label
6472
- ] }, it.label)
6473
- )
6474
- ] })
6475
- ] });
6476
- }
6477
- function ThemeToggle({ className }) {
6478
- const { theme, setTheme } = useTheme();
6479
- const [mounted, setMounted] = useState(false);
6480
- useEffect(() => setMounted(true), []);
6481
- const current2 = mounted ? theme ?? "system" : "system";
6482
- const next = current2 === "light" ? "dark" : current2 === "dark" ? "system" : "light";
6483
- const Icon2 = current2 === "light" ? Sun : current2 === "dark" ? Moon : SunMoon;
6484
- return /* @__PURE__ */ jsx(
6485
- "button",
6486
- {
6487
- type: "button",
6488
- onClick: () => setTheme(next),
6489
- "aria-label": `Theme: ${current2}. Switch to ${next}`,
6490
- title: `Theme: ${current2}`,
6491
- className: cn(
6492
- "inline-flex size-10 items-center justify-center rounded-full text-muted-foreground transition-colors hover:bg-accent hover:text-foreground",
6493
- className
6486
+ children: [
6487
+ section.label,
6488
+ /* @__PURE__ */ jsx(
6489
+ ChevronRight,
6490
+ {
6491
+ "aria-hidden": true,
6492
+ className: cn("size-3.5 shrink-0 text-oca-subtle transition-transform duration-200", open && "rotate-90")
6493
+ }
6494
+ )
6495
+ ]
6496
+ }
6494
6497
  ),
6495
- children: /* @__PURE__ */ jsx(Icon2, { className: "size-[1.125rem]" })
6498
+ /* @__PURE__ */ jsx("ul", { id: panel, hidden: !open, className: "mb-2 ml-2.5 mt-0.5 border-l border-border", children: section.items.map((item) => {
6499
+ const on = pathOf(item.href) === here;
6500
+ const badge = typeof item.badge === "string" && STATUS_WORDS.has(item.badge) ? /* @__PURE__ */ jsx(StatusBadge, { status: item.badge }) : item.badge ? /* @__PURE__ */ jsx(Badge, { tone: "muted", children: item.badge }) : null;
6501
+ return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(
6502
+ Link6,
6503
+ {
6504
+ href: item.href,
6505
+ ref: on ? activeRef : void 0,
6506
+ onClick: onNavigate,
6507
+ "aria-current": on ? "page" : void 0,
6508
+ className: cn(
6509
+ "-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",
6510
+ on ? "border-foreground font-medium text-foreground" : "border-transparent text-muted-foreground hover:border-oca-hairline-strong hover:text-foreground"
6511
+ ),
6512
+ children: [
6513
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1", children: item.label }),
6514
+ badge
6515
+ ]
6516
+ }
6517
+ ) }, item.href);
6518
+ }) })
6519
+ ] }, section.label);
6520
+ }) });
6521
+ }
6522
+ var DOCS_HEADER_NAV = OCHK_IO_NAV.map((n) => n.href === DOCS_HREF ? { ...n, active: true } : n);
6523
+ function DocsShell({
6524
+ nav,
6525
+ current: current2,
6526
+ navCurrent,
6527
+ header,
6528
+ search,
6529
+ actions,
6530
+ breadcrumbs,
6531
+ toc,
6532
+ pager,
6533
+ footer,
6534
+ children
6535
+ }) {
6536
+ const [menu, setMenu] = useState(false);
6537
+ useEffect(() => setMenu(false), [current2]);
6538
+ const read = useHeadings("#docs-content", current2);
6539
+ const items = toc ?? read.items;
6540
+ const activeId = toc ? void 0 : read.activeId;
6541
+ const marked = navCurrent ?? current2;
6542
+ const here = pathOf(marked);
6543
+ const place = useMemo(() => {
6544
+ for (const s of nav) {
6545
+ const it = s.items.find((i) => pathOf(i.href) === here);
6546
+ if (it) return { section: s.label, page: it.label };
6496
6547
  }
6497
- );
6548
+ return null;
6549
+ }, [nav, here]);
6550
+ return /* @__PURE__ */ jsxs("div", { className: "flex min-h-dvh flex-col bg-background", children: [
6551
+ /* @__PURE__ */ jsx(SkipLink, {}),
6552
+ header ?? /* @__PURE__ */ jsx(SiteHeader, { home: OCHK_IO, family: "docs", nav: DOCS_HEADER_NAV, search, actions }),
6553
+ /* @__PURE__ */ 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__ */ jsx("div", { className: "oca-container flex h-12 items-center gap-2", children: /* @__PURE__ */ jsxs(Sheet, { open: menu, onOpenChange: setMenu, children: [
6554
+ /* @__PURE__ */ 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: [
6555
+ /* @__PURE__ */ jsx(PanelLeft, { "aria-hidden": true, className: "size-[1.125rem] shrink-0" }),
6556
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Docs menu. " }),
6557
+ place ? /* @__PURE__ */ jsxs("span", { className: "flex min-w-0 items-center gap-1.5", children: [
6558
+ /* @__PURE__ */ jsx("span", { className: "shrink-0 text-muted-foreground", children: place.section }),
6559
+ /* @__PURE__ */ jsx(ChevronRight, { "aria-hidden": true, className: "size-3.5 shrink-0 text-oca-subtle" }),
6560
+ /* @__PURE__ */ jsx("span", { className: "truncate font-medium", children: place.page })
6561
+ ] }) : /* @__PURE__ */ jsx("span", { className: "font-medium", children: "Docs" })
6562
+ ] }),
6563
+ /* @__PURE__ */ jsxs(SheetContent, { side: "left", className: "w-[min(88vw,22rem)] gap-0 p-0", children: [
6564
+ /* @__PURE__ */ jsx("div", { className: "border-b border-border px-5 py-4 pr-14", children: /* @__PURE__ */ jsx(SheetTitle, { className: "text-[1.0625rem] font-medium", children: "Docs" }) }),
6565
+ /* @__PURE__ */ jsx("div", { className: "overflow-y-auto p-3", children: /* @__PURE__ */ jsx(DocsNav, { sections: nav, current: marked, onNavigate: () => setMenu(false) }) })
6566
+ ] })
6567
+ ] }) }) }),
6568
+ /* @__PURE__ */ jsx("div", { className: "oca-container flex-1", children: /* @__PURE__ */ 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: [
6569
+ /* @__PURE__ */ 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__ */ jsx(DocsNav, { sections: nav, current: marked }) }),
6570
+ /* @__PURE__ */ jsxs("main", { id: "main-content", className: "min-w-0 pb-16 pt-6 md:pt-8", children: [
6571
+ breadcrumbs ? /* @__PURE__ */ jsx("div", { className: "mb-6 max-lg:hidden", children: breadcrumbs }) : null,
6572
+ items.length > 1 ? /* @__PURE__ */ jsxs("details", { className: "group mb-8 rounded-2xl border border-border bg-card xl:hidden", children: [
6573
+ /* @__PURE__ */ 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: [
6574
+ "On this page",
6575
+ /* @__PURE__ */ jsx(ChevronDown, { "aria-hidden": true, className: "size-4 text-muted-foreground transition-transform group-open:rotate-180" })
6576
+ ] }),
6577
+ /* @__PURE__ */ jsx(OnThisPage, { items, activeId, title: null, className: "px-4 pb-4" })
6578
+ ] }) : null,
6579
+ /* @__PURE__ */ jsx("article", { id: "docs-content", className: "max-w-[46rem]", children: /* @__PURE__ */ jsx(InDocsContext.Provider, { value: true, children }) }),
6580
+ pager ? /* @__PURE__ */ jsx("div", { className: "mt-16 max-w-[46rem]", children: pager }) : null
6581
+ ] }),
6582
+ /* @__PURE__ */ 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__ */ jsx(OnThisPage, { items, activeId }) : null })
6583
+ ] }) }),
6584
+ footer ?? /* @__PURE__ */ jsx(OchkIoFooter, {})
6585
+ ] });
6498
6586
  }
6499
6587
  var OCHK_APP_ACCOUNT = "https://ochk.app/me/account";
6500
6588
  function onHistory(change) {
@@ -6656,6 +6744,7 @@ function rehypeCode(options = {}) {
6656
6744
  if (lang && skip.has(lang)) continue;
6657
6745
  const meta = parseCodeMeta(code.data?.meta);
6658
6746
  let source = textOf(code);
6747
+ const newline = /\n$/.test(source);
6659
6748
  const diff = meta.diff || lang === "diff" ? readDiff(source) : null;
6660
6749
  if (diff) source = diff.code;
6661
6750
  const lines = options.tokenize?.(source, lang) ?? highlight(source, lang === "diff" ? void 0 : lang);
@@ -6666,7 +6755,8 @@ function rehypeCode(options = {}) {
6666
6755
  ...lang ? { dataLang: lang } : {},
6667
6756
  ...meta.title ? { dataTitle: meta.title } : {},
6668
6757
  ...diff ? { dataDiff: "" } : {},
6669
- ...meta.lineNumbers ? { dataLineNumbers: "" } : {}
6758
+ ...meta.lineNumbers ? { dataLineNumbers: "" } : {},
6759
+ ...newline ? { dataEol: "" } : {}
6670
6760
  };
6671
6761
  child.children = [];
6672
6762
  continue;
@@ -6687,6 +6777,7 @@ function createMdxComponents({ mermaid } = {}) {
6687
6777
  caption: props["data-title"],
6688
6778
  diff: props["data-diff"] !== void 0,
6689
6779
  lineNumbers: props["data-line-numbers"] !== void 0,
6780
+ trailingNewline: props["data-eol"] !== void 0,
6690
6781
  className: "my-6"
6691
6782
  }
6692
6783
  );
@@ -6713,6 +6804,9 @@ function createMdxComponents({ mermaid } = {}) {
6713
6804
  const heading = (as) => function Heading(props) {
6714
6805
  return /* @__PURE__ */ jsx(DocsHeading, { as, ...props });
6715
6806
  };
6807
+ const minor = (Tag) => function Minor({ className, ...props }) {
6808
+ return /* @__PURE__ */ jsx(Tag, { className: cn("mb-2 mt-6 scroll-mt-28 text-[0.9375rem] font-medium leading-snug text-foreground", className), ...props });
6809
+ };
6716
6810
  return {
6717
6811
  h1: heading("h1"),
6718
6812
  h2: heading("h2"),
@@ -6721,11 +6815,15 @@ function createMdxComponents({ mermaid } = {}) {
6721
6815
  p: ({ className, ...props }) => /* @__PURE__ */ jsx("p", { className: cn("my-4 text-[1rem] leading-[1.75] text-muted-foreground md:text-[1.0625rem]", className), ...props }),
6722
6816
  a: A,
6723
6817
  strong: (props) => /* @__PURE__ */ jsx("strong", { className: "font-medium text-foreground", ...props }),
6818
+ h5: minor("h5"),
6819
+ h6: minor("h6"),
6724
6820
  ul: ({ className, ...props }) => /* @__PURE__ */ jsx(
6725
6821
  "ul",
6726
6822
  {
6727
6823
  className: cn(
6728
6824
  "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]",
6825
+ // A GitHub task list: the box replaces the bullet.
6826
+ className?.includes("contains-task-list") && "list-none pl-0",
6729
6827
  className
6730
6828
  ),
6731
6829
  ...props
@@ -6741,7 +6839,26 @@ function createMdxComponents({ mermaid } = {}) {
6741
6839
  ...props
6742
6840
  }
6743
6841
  ),
6744
- li: ({ className, ...props }) => /* @__PURE__ */ jsx("li", { className: cn("pl-1 [&>p]:my-1 [&>ul]:my-1.5 [&>ol]:my-1.5", className), ...props }),
6842
+ li: ({ className, ...props }) => /* @__PURE__ */ jsx(
6843
+ "li",
6844
+ {
6845
+ className: cn(
6846
+ "pl-1 [&>p]:my-1 [&>ul]:my-1.5 [&>ol]:my-1.5",
6847
+ // A wrapped task starts under its text, not under the box.
6848
+ className?.includes("task-list-item") && "pl-6 -indent-6",
6849
+ className
6850
+ ),
6851
+ ...props
6852
+ }
6853
+ ),
6854
+ input: (props) => props.type === "checkbox" ? /* @__PURE__ */ jsx(
6855
+ "input",
6856
+ {
6857
+ ...props,
6858
+ className: cn("mr-2 size-4 translate-y-[2px] align-baseline accent-foreground", props.className),
6859
+ "aria-label": props.checked ? "Done" : "To do"
6860
+ }
6861
+ ) : /* @__PURE__ */ jsx("input", { ...props }),
6745
6862
  blockquote: ({ children }) => /* @__PURE__ */ jsx(Callout, { children }),
6746
6863
  hr: () => /* @__PURE__ */ jsx("hr", { className: "my-10 border-border" }),
6747
6864
  table: MdxTable,
@@ -6771,6 +6888,6 @@ function createMdxComponents({ mermaid } = {}) {
6771
6888
  }
6772
6889
  var mdxComponents = createMdxComponents();
6773
6890
 
6774
- export { APP_ATTRIBUTE, APP_ID, Accent, Accordion, AccordionItem, AccountMenu, ActivityList, AnchorStatus, ApiTable, AppCard, AppGrid, AppIcon, AppShell, ArtifactView, Badge, BlockCountdown, BlockHeight, Breadcrumbs, BrowserFrame, Button, CODE_LANGS, Callout, Card, CardContent, CardDescription, CardFooter, CardGrid, CardHeader, CardNumeral, CardTitle, Checkbox, Closing, CodeBlock, CodeTabs, ComparisonTable, Container, CopyButton, Crowd, DOCS_HEADER_NAV, DOCS_HREF, DataTable, DensityProvider, Diagram, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogHost, DialogTitle, DialogTrigger, Display, DocHeader, DocLayout, DocsHeading, DocsNav, DocsPager, DocsShell, DropZone, DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, EmptyLine, EmptyState, EndpointList, ErrorBoundary, ErrorPage, Eyebrow, FAMILY, FAMILY_GROUPS, FactBlock, FactRows, FamilyMenu, Faq, Field, FilterChips, FloatChip, Footnote, FormSection, HalftoneCanvas, HalftoneSphere, HashChip, Input, InstallTabs, IsoCheck, Kbd, KeyValueList, LEGAL_LINKS, Label, Lead, LegalDocument, LinkCard, LoadingBlock, Lockup, MARK_FACES, Mark, MdxTable, Meter, Monogram, Notice, OCHK_APP_ACCOUNT, OCHK_IO, OCHK_IO_FOOTER, OCHK_IO_NAV, OnThisPage, PROTOCOLS, PROTOCOL_ORDER, PackageCard, PageHeader, PageHero, Pagination, PhoneFrame, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, ProgressSteps, ProofStrip, Prose, ProtocolGrid, ProtocolHero, ProtocolNav, QrCode, RadioGroup, RadioGroupItem, Reveal, SELF_HOSTED_LEGAL_LINKS, SPHERE_GRADIENT, Sats, SatsFigure, ScrollFade, ScrollStory, SearchButton, SearchDialog, Section, SectionHeading, SectionIntro, Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue, Separator, SessionAccountView, Sheet, SheetClose, SheetContent, SheetDescription, SheetTitle, SheetTrigger, ShellContext, SignInFrame, SignMessage, SiteBanner, SiteFooter, SiteHeader, Skeleton, SkipLink, SpecCard, Spinner, SplitBar, StatCard, StatGrid, StateBadge, StatusBadge, StatusDot, StatusPill, Step, StepGrid, Steps, Switch, TOKEN_CLASS, Tabs, TabsContent, TabsList, TabsTrigger, TextLink, Textarea, ThemeToggle, Ticker, Toaster, ToolGrid, ToolShell, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, TruthTable, UsdApprox, VerifyBox, VerifyReport, appColors, appFonts, badgeVariants, blocksToDuration, buttonVariants, cardVariants, cn, confirm, createMdxComponents, createStateBadge, escapeHtml, explorerUrl, familyByGroup, familySite, formatBlockHeight, formatBytes, formatUtc, grammarOf, highlight, highlightToHtml, languageName, linesToHtml, mdxComponents, monogramGround, monogramLetter, parseCodeMeta, parseLineRanges, portraitTone, prompt, protocolSite, readDiff, rehypeCode, satsText, sectionVariants, shortenMiddle, statusWord, useActiveHeading, useCopy, useDensity, useHeadings, useInView, useShellPlace, useSignInHref, useTimedOut };
6891
+ export { APP_ATTRIBUTE, APP_ID, Accent, Accordion, AccordionItem, AccountMenu, ActivityList, AnchorStatus, ApiTable, AppCard, AppGrid, AppIcon, AppShell, ArtifactView, Badge, BlockCountdown, BlockHeight, Breadcrumbs, BrowserFrame, Button, CODE_LANGS, Callout, Card, CardContent, CardDescription, CardFooter, CardGrid, CardHeader, CardNumeral, CardTitle, Checkbox, Closing, CodeBlock, CodeTabs, ComparisonTable, Container, CopyButton, Crowd, DOCS_HEADER_NAV, DOCS_HREF, DataTable, DensityProvider, Diagram, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogHost, DialogTitle, DialogTrigger, Display, DocHeader, DocLayout, DocsHeading, DocsNav, DocsPager, DocsShell, DropZone, DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, EmptyLine, EmptyState, EndpointList, ErrorBoundary, ErrorPage, Eyebrow, FAMILY, FAMILY_GROUPS, FactBlock, FactRows, FamilyMenu, Faq, Field, FilterChips, FloatChip, Footnote, FormSection, HalftoneCanvas, HalftoneSphere, HashChip, Input, InstallTabs, IsoCheck, Kbd, KeyValueList, LEGAL_LINKS, Label, Lead, LegalDocument, LinkCard, LoadingBlock, Lockup, MARK_FACES, Mark, MdxTable, Meter, Monogram, Notice, OCHK_APP_ACCOUNT, OCHK_IO, OCHK_IO_FOOTER, OCHK_IO_NAV, OchkIoFooter, OnThisPage, PROTOCOLS, PROTOCOL_ORDER, PackageCard, PageHeader, PageHero, Pagination, PhoneFrame, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, ProgressSteps, ProofStrip, Prose, ProtocolGrid, ProtocolHero, ProtocolNav, QrCode, RadioGroup, RadioGroupItem, Reveal, SELF_HOSTED_LEGAL_LINKS, SPHERE_GRADIENT, Sats, SatsFigure, ScrollFade, ScrollStory, SearchButton, SearchDialog, Section, SectionHeading, SectionIntro, Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue, Separator, SessionAccountView, Sheet, SheetClose, SheetContent, SheetDescription, SheetTitle, SheetTrigger, ShellContext, SignInFrame, SignMessage, SiteBanner, SiteFooter, SiteHeader, Skeleton, SkipLink, SpecCard, Spinner, SplitBar, StatCard, StatGrid, StateBadge, StatusBadge, StatusDot, StatusPill, Step, StepGrid, Steps, Switch, TOKEN_CLASS, Tabs, TabsContent, TabsList, TabsTrigger, TextLink, Textarea, ThemeToggle, Ticker, Toaster, ToolGrid, ToolShell, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, TruthTable, UsdApprox, VerifyBox, VerifyReport, appColors, appFonts, badgeVariants, blocksToDuration, buttonVariants, cardVariants, cn, confirm, createMdxComponents, createStateBadge, escapeHtml, explorerUrl, familyByGroup, familySite, formatBlockHeight, formatBytes, formatUtc, grammarOf, highlight, highlightToHtml, languageName, linesToHtml, mdxComponents, monogramGround, monogramLetter, parseCodeMeta, parseLineRanges, portraitTone, prompt, protocolSite, readDiff, rehypeCode, satsText, sectionVariants, shortenMiddle, statusWord, useActiveHeading, useCopy, useDensity, useHeadings, useInView, useShellPlace, useSignInHref, useTimedOut };
6775
6892
  //# sourceMappingURL=index.mjs.map
6776
6893
  //# sourceMappingURL=index.mjs.map