@orangecheck/app-design 0.6.1 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/README.md +23 -6
  2. package/dist/brand.js.map +1 -1
  3. package/dist/brand.mjs.map +1 -1
  4. package/dist/chrome.d.mts +78 -55
  5. package/dist/chrome.d.ts +78 -55
  6. package/dist/chrome.js +1100 -59
  7. package/dist/chrome.js.map +1 -1
  8. package/dist/chrome.mjs +1091 -61
  9. package/dist/chrome.mjs.map +1 -1
  10. package/dist/code.d.mts +52 -0
  11. package/dist/code.d.ts +52 -0
  12. package/dist/code.js +534 -0
  13. package/dist/code.js.map +1 -0
  14. package/dist/code.mjs +522 -0
  15. package/dist/code.mjs.map +1 -0
  16. package/dist/components.d.mts +216 -42
  17. package/dist/components.d.ts +216 -42
  18. package/dist/components.js +3350 -100
  19. package/dist/components.js.map +1 -1
  20. package/dist/components.mjs +3293 -103
  21. package/dist/components.mjs.map +1 -1
  22. package/dist/docs-DhnstueM.d.ts +219 -0
  23. package/dist/docs-DiR6s43s.d.mts +219 -0
  24. package/dist/family.d.mts +2 -0
  25. package/dist/family.d.ts +2 -0
  26. package/dist/family.js +167 -0
  27. package/dist/family.js.map +1 -0
  28. package/dist/family.mjs +154 -0
  29. package/dist/family.mjs.map +1 -0
  30. package/dist/format.d.mts +12 -0
  31. package/dist/format.d.ts +12 -0
  32. package/dist/format.js +65 -0
  33. package/dist/format.js.map +1 -0
  34. package/dist/format.mjs +58 -0
  35. package/dist/format.mjs.map +1 -0
  36. package/dist/hero-Dn37il-9.d.mts +31 -0
  37. package/dist/hero-Dn37il-9.d.ts +31 -0
  38. package/dist/index-C6hDqOOS.d.mts +58 -0
  39. package/dist/index-C6hDqOOS.d.ts +58 -0
  40. package/dist/index.d.mts +12 -3
  41. package/dist/index.d.ts +12 -3
  42. package/dist/index.js +4319 -295
  43. package/dist/index.js.map +1 -1
  44. package/dist/index.mjs +4219 -298
  45. package/dist/index.mjs.map +1 -1
  46. package/dist/mdx.d.mts +58 -0
  47. package/dist/mdx.d.ts +58 -0
  48. package/dist/mdx.js +1712 -0
  49. package/dist/mdx.js.map +1 -0
  50. package/dist/mdx.mjs +1685 -0
  51. package/dist/mdx.mjs.map +1 -0
  52. package/dist/primitives.d.mts +73 -5
  53. package/dist/primitives.d.ts +73 -5
  54. package/dist/primitives.js +331 -8
  55. package/dist/primitives.js.map +1 -1
  56. package/dist/primitives.mjs +320 -11
  57. package/dist/primitives.mjs.map +1 -1
  58. package/dist/session.d.mts +18 -0
  59. package/dist/session.d.ts +18 -0
  60. package/dist/session.js +432 -0
  61. package/dist/session.js.map +1 -0
  62. package/dist/session.mjs +401 -0
  63. package/dist/session.mjs.map +1 -0
  64. package/dist/status-badge-BEOxeY9j.d.ts +13 -0
  65. package/dist/status-badge-DRwGhB0h.d.mts +13 -0
  66. package/dist/styles/code.css +97 -0
  67. package/dist/styles/fonts.css +1 -1
  68. package/dist/styles/theme.css +2 -0
  69. package/dist/styles/tokens.css +44 -2
  70. package/dist/styles.css +1 -0
  71. package/dist/tokens.d.mts +3 -1
  72. package/dist/tokens.d.ts +3 -1
  73. package/dist/tokens.js +5 -3
  74. package/dist/tokens.js.map +1 -1
  75. package/dist/tokens.mjs +5 -3
  76. package/dist/tokens.mjs.map +1 -1
  77. package/dist/tool-shell-B1C7ahKE.d.ts +81 -0
  78. package/dist/tool-shell-BDx_N5ai.d.mts +81 -0
  79. package/dist/tools-BggNN5DV.d.ts +131 -0
  80. package/dist/tools-DFIxIj5p.d.mts +131 -0
  81. package/package.json +38 -2
package/dist/chrome.js CHANGED
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var lucideReact = require('lucide-react');
4
- var Link2 = require('next/link');
4
+ var Link5 = require('next/link');
5
5
  var react = require('react');
6
6
  var clsx = require('clsx');
7
7
  var tailwindMerge = require('tailwind-merge');
@@ -10,6 +10,10 @@ var DialogPrimitive = require('@radix-ui/react-dialog');
10
10
  var DropdownMenuPrimitive = require('@radix-ui/react-dropdown-menu');
11
11
  var PopoverPrimitive = require('@radix-ui/react-popover');
12
12
  var TooltipPrimitive = require('@radix-ui/react-tooltip');
13
+ var classVarianceAuthority = require('class-variance-authority');
14
+ var SeparatorPrimitive = require('@radix-ui/react-separator');
15
+ require('sonner');
16
+ var reactSlot = require('@radix-ui/react-slot');
13
17
  var nextThemes = require('next-themes');
14
18
 
15
19
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
@@ -32,11 +36,12 @@ function _interopNamespace(e) {
32
36
  return Object.freeze(n);
33
37
  }
34
38
 
35
- var Link2__default = /*#__PURE__*/_interopDefault(Link2);
39
+ var Link5__default = /*#__PURE__*/_interopDefault(Link5);
36
40
  var DialogPrimitive__namespace = /*#__PURE__*/_interopNamespace(DialogPrimitive);
37
41
  var DropdownMenuPrimitive__namespace = /*#__PURE__*/_interopNamespace(DropdownMenuPrimitive);
38
42
  var PopoverPrimitive__namespace = /*#__PURE__*/_interopNamespace(PopoverPrimitive);
39
43
  var TooltipPrimitive__namespace = /*#__PURE__*/_interopNamespace(TooltipPrimitive);
44
+ var SeparatorPrimitive__namespace = /*#__PURE__*/_interopNamespace(SeparatorPrimitive);
40
45
 
41
46
  var merge = tailwindMerge.extendTailwindMerge({
42
47
  extend: {
@@ -127,6 +132,154 @@ function Lockup({ name = "orangecheck", size = 28, className }) {
127
132
  }
128
133
  );
129
134
  }
135
+
136
+ // src/family/index.ts
137
+ var OCHK_IO = "https://ochk.io";
138
+ var DOCS_HREF = `${OCHK_IO}/docs`;
139
+ function protocol(slug, verb, line, kinds) {
140
+ return {
141
+ slug,
142
+ label: slug,
143
+ href: `${OCHK_IO}/${slug}`,
144
+ group: "protocol",
145
+ line,
146
+ status: "live",
147
+ verb,
148
+ pageHref: `${OCHK_IO}/${slug}`,
149
+ toolHref: `https://${slug}.ochk.io`,
150
+ specHref: `https://github.com/orangecheck/oc-${slug}-protocol`,
151
+ kinds
152
+ };
153
+ }
154
+ var PROTOCOLS = [
155
+ protocol("attest", "identity", "Show that an address holds bitcoin, and for how long.", "30078"),
156
+ protocol("lock", "confidentiality", "Encrypt to a Bitcoin address, so only its holder can open it.", "30078"),
157
+ protocol("vote", "legitimacy", "Polls weighed in sats, that anyone can tally.", "30080\u201330082"),
158
+ protocol("stamp", "provenance", "Prove who signed something, and when.", "30083"),
159
+ protocol("agent", "authority", "Give software scoped, revocable permission to act for you.", "30083\u201330086"),
160
+ protocol("pledge", "commitment", "Make a promise with bitcoin behind it, on a public record.", "30078")
161
+ ];
162
+ PROTOCOLS.map((p) => p.slug);
163
+ var FAMILY = [
164
+ {
165
+ slug: "home",
166
+ label: "ochk.io",
167
+ href: OCHK_IO,
168
+ group: "orangecheck",
169
+ line: "The open protocols, and the company behind them.",
170
+ status: "live"
171
+ },
172
+ {
173
+ slug: "me",
174
+ label: "ochk.app",
175
+ href: "https://ochk.app",
176
+ group: "orangecheck",
177
+ line: "One account, with Bitcoin behind it.",
178
+ status: "testing"
179
+ },
180
+ {
181
+ slug: "docs",
182
+ label: "docs",
183
+ href: DOCS_HREF,
184
+ group: "orangecheck",
185
+ line: "Specs, SDKs and guides for every protocol.",
186
+ status: "live"
187
+ },
188
+ ...PROTOCOLS,
189
+ {
190
+ slug: "vault",
191
+ label: "vault",
192
+ href: "https://vault.ochk.io",
193
+ group: "app",
194
+ line: "A password manager, encrypted in your browser.",
195
+ status: "live",
196
+ protocols: ["lock"]
197
+ },
198
+ {
199
+ slug: "chat",
200
+ label: "chat",
201
+ href: "https://chat.ochk.io",
202
+ group: "app",
203
+ line: "Messages only the holder of a Bitcoin address can read.",
204
+ status: "testing",
205
+ protocols: ["lock"]
206
+ },
207
+ {
208
+ slug: "cosign",
209
+ label: "cosign",
210
+ href: "https://cosign.ochk.io",
211
+ group: "app",
212
+ line: "Builders find co-founders and backers.",
213
+ status: "testing",
214
+ protocols: ["attest"]
215
+ },
216
+ {
217
+ slug: "me-demo",
218
+ // "demo", not the made-up app's own name, so nobody takes it for ours.
219
+ label: "demo",
220
+ href: "https://me-demo.ochk.io",
221
+ group: "app",
222
+ line: "Lumen Notes, a made-up app that signs in with orangecheck.",
223
+ status: "live"
224
+ },
225
+ {
226
+ slug: "globe",
227
+ label: "globe",
228
+ href: "https://globe.ochk.io",
229
+ group: "public-good",
230
+ line: "The Bitcoin network, live, on a globe.",
231
+ status: "live"
232
+ },
233
+ {
234
+ slug: "btc",
235
+ label: "btc",
236
+ href: "https://btc.ochk.io",
237
+ group: "public-good",
238
+ line: "A free desk for reading the Bitcoin market.",
239
+ status: "live"
240
+ }
241
+ ];
242
+ var FAMILY_GROUPS = [
243
+ { id: "orangecheck", label: "orangecheck" },
244
+ { id: "protocol", label: "Protocols" },
245
+ { id: "app", label: "Apps" },
246
+ { id: "public-good", label: "Public goods" }
247
+ ];
248
+ var BY_SLUG = new Map(FAMILY.map((s) => [s.slug, s]));
249
+ function protocolSite(slug) {
250
+ return BY_SLUG.get(slug);
251
+ }
252
+ function familyByGroup() {
253
+ return FAMILY_GROUPS.map((g) => ({ ...g, sites: FAMILY.filter((s) => s.group === g.id) }));
254
+ }
255
+ var LEGAL_LINKS = [
256
+ { href: `${OCHK_IO}/privacy`, label: "Privacy" },
257
+ { href: `${OCHK_IO}/terms`, label: "Terms" },
258
+ { href: `${OCHK_IO}/security`, label: "Security" },
259
+ { href: `${OCHK_IO}/trademark`, label: "Trademarks" },
260
+ { href: `${OCHK_IO}/contact`, label: "Contact" }
261
+ ];
262
+ var OCHK_IO_NAV = [
263
+ {
264
+ href: `${OCHK_IO}/protocols`,
265
+ label: "Protocols",
266
+ children: PROTOCOLS.map((p) => ({ href: p.pageHref, label: p.label, description: p.line }))
267
+ },
268
+ { href: `${OCHK_IO}/apps`, label: "Apps" },
269
+ { href: DOCS_HREF, label: "Docs" },
270
+ { href: `${OCHK_IO}/trust`, label: "Trust" },
271
+ { href: `${OCHK_IO}/about`, label: "About" }
272
+ ];
273
+ var OCHK_IO_FOOTER = [
274
+ {
275
+ heading: "Company",
276
+ links: [
277
+ { href: `${OCHK_IO}/about`, label: "About" },
278
+ { href: `${OCHK_IO}/trust`, label: "Trust" },
279
+ { href: "https://github.com/orangecheck", label: "GitHub", external: true }
280
+ ]
281
+ }
282
+ ];
130
283
  var overlayClass = "oca-animate-fade fixed inset-0 z-50 bg-[rgb(10_10_10/0.38)] backdrop-blur-[2px] data-[state=closed]:opacity-0";
131
284
  react.forwardRef(function DialogContent2({ className, children, hideClose, ...props }, ref) {
132
285
  return /* @__PURE__ */ jsxRuntime.jsxs(DialogPrimitive__namespace.Portal, { children: [
@@ -206,7 +359,9 @@ var SheetContent = react.forwardRef(function SheetContent2({ className, children
206
359
  )
207
360
  ] });
208
361
  });
209
- react.forwardRef(function PopoverContent2({ className, align = "center", sideOffset = 8, ...props }, ref) {
362
+ var Popover = PopoverPrimitive__namespace.Root;
363
+ var PopoverTrigger = PopoverPrimitive__namespace.Trigger;
364
+ var PopoverContent = react.forwardRef(function PopoverContent2({ className, align = "center", sideOffset = 8, ...props }, ref) {
210
365
  return /* @__PURE__ */ jsxRuntime.jsx(PopoverPrimitive__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
211
366
  PopoverPrimitive__namespace.Content,
212
367
  {
@@ -279,51 +434,254 @@ var DropdownMenuLabel = react.forwardRef(function DropdownMenuLabel2({ className
279
434
  var DropdownMenuSeparator = react.forwardRef(function DropdownMenuSeparator2({ className, ...props }, ref) {
280
435
  return /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuPrimitive__namespace.Separator, { ref, className: cn("my-1.5 h-px bg-border", className), ...props });
281
436
  });
282
- function NavLink({ item, className, onNavigate }) {
437
+ var GOOD_DOT = "border-border bg-card text-foreground before:size-1.5 before:shrink-0 before:rounded-full before:bg-success before:content-['']";
438
+ var badgeVariants = classVarianceAuthority.cva(
439
+ "inline-flex h-6 shrink-0 items-center gap-1.5 whitespace-nowrap rounded-full border px-2.5 text-[0.8125rem] font-medium leading-none",
440
+ {
441
+ variants: {
442
+ tone: {
443
+ neutral: "border-border bg-card text-foreground",
444
+ muted: "border-transparent bg-muted text-muted-foreground",
445
+ brand: "border-transparent bg-[color-mix(in_oklab,var(--oca-orange)_9%,var(--card))] text-oca-accent-ink",
446
+ danger: "border-transparent bg-[color-mix(in_oklab,var(--destructive)_12%,var(--card))] text-destructive",
447
+ // A good state is a neutral pill with a green dot, not a green pill.
448
+ success: GOOD_DOT,
449
+ // Aliases kept so older call sites keep compiling: attention is
450
+ // the brand accent, information is neutral.
451
+ warning: "border-transparent bg-[color-mix(in_oklab,var(--oca-orange)_9%,var(--card))] text-oca-accent-ink",
452
+ info: "border-border bg-card text-foreground",
453
+ // Inverted in dark mode, where ink would sit on a card of nearly its own colour.
454
+ ink: "border-transparent bg-oca-ink text-oca-ink-foreground dark:bg-foreground dark:text-background",
455
+ onInk: "border-white/15 bg-white/5 text-white/90"
456
+ }
457
+ },
458
+ defaultVariants: { tone: "neutral" }
459
+ }
460
+ );
461
+ function Badge({ className, tone, ...props }) {
462
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { "data-ui": "badge", className: cn(badgeVariants({ tone }), className), ...props });
463
+ }
464
+ var WORD = {
465
+ live: "Live",
466
+ testing: "In testing",
467
+ "not-yet": "Not yet",
468
+ paused: "Paused",
469
+ good: "Good",
470
+ caution: "Caution",
471
+ refused: "Refused"
472
+ };
473
+ var TONE = {
474
+ live: "success",
475
+ testing: "brand",
476
+ "not-yet": "muted",
477
+ paused: "muted",
478
+ good: "success",
479
+ caution: "brand",
480
+ refused: "danger"
481
+ };
482
+ function StatusBadge({ status, className, ...props }) {
483
+ return /* @__PURE__ */ jsxRuntime.jsx(Badge, { tone: TONE[status], "data-status": status, className: cn(className), ...props, children: WORD[status] });
484
+ }
485
+ function SiteRow({ site, here, onNavigate }) {
486
+ return /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsxs(
487
+ "a",
488
+ {
489
+ href: site.href,
490
+ onClick: onNavigate,
491
+ "aria-current": here ? "page" : void 0,
492
+ className: cn(
493
+ "flex flex-col gap-0.5 rounded-xl px-3 py-2 transition-colors hover:bg-accent",
494
+ here && "bg-muted hover:bg-muted dark:bg-white/[0.06]"
495
+ ),
496
+ children: [
497
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-2 text-[0.9375rem] font-medium leading-6", children: [
498
+ site.label,
499
+ site.status !== "live" ? /* @__PURE__ */ jsxRuntime.jsx(StatusBadge, { status: site.status }) : null,
500
+ here ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "(this site)" }) : null
501
+ ] }),
502
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[0.8125rem] leading-snug text-muted-foreground", children: site.line })
503
+ ]
504
+ }
505
+ ) });
506
+ }
507
+ var PLACE = {
508
+ orangecheck: "sm:col-start-1 sm:row-start-1 lg:row-span-2",
509
+ protocol: "sm:col-start-1 sm:row-start-2 lg:col-start-2 lg:row-start-1 lg:row-span-2",
510
+ app: "sm:col-start-2 sm:row-start-1 lg:col-start-3",
511
+ "public-good": "sm:col-start-2 sm:row-start-2 lg:col-start-3"
512
+ };
513
+ function FamilyList({
514
+ current,
515
+ onNavigate,
516
+ stack = false,
517
+ className
518
+ }) {
519
+ const id = react.useId();
520
+ return /* @__PURE__ */ jsxRuntime.jsx(
521
+ "div",
522
+ {
523
+ className: cn(
524
+ "grid grid-cols-1 gap-x-2 gap-y-4",
525
+ // The second desk row takes the slack, so the public goods sit right under the apps.
526
+ !stack && "sm:grid-cols-2 lg:grid-cols-3 lg:grid-rows-[auto_1fr]",
527
+ className
528
+ ),
529
+ children: familyByGroup().map((g) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-col gap-1", !stack && PLACE[g.id]), children: [
530
+ /* @__PURE__ */ jsxRuntime.jsx("p", { id: `${id}-${g.id}`, className: "px-3 pt-1 text-[0.8125rem] text-muted-foreground", children: g.label }),
531
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { "aria-labelledby": `${id}-${g.id}`, className: "flex flex-col", children: g.sites.map((s) => /* @__PURE__ */ jsxRuntime.jsx(SiteRow, { site: s, here: s.slug === current, onNavigate }, s.slug)) })
532
+ ] }, g.id))
533
+ }
534
+ );
535
+ }
536
+ function FamilyMenu({ current, className }) {
537
+ const [open, setOpen] = react.useState(false);
538
+ return /* @__PURE__ */ jsxRuntime.jsxs(Popover, { open, onOpenChange: setOpen, children: [
539
+ /* @__PURE__ */ jsxRuntime.jsx(
540
+ PopoverTrigger,
541
+ {
542
+ "aria-label": "All orangecheck sites",
543
+ className: cn(
544
+ "group inline-flex size-8 shrink-0 items-center justify-center rounded-full text-muted-foreground transition-colors",
545
+ "hover:bg-accent hover:text-foreground data-[state=open]:bg-accent data-[state=open]:text-foreground",
546
+ className
547
+ ),
548
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { "aria-hidden": true, className: "size-4 transition-transform duration-200 group-data-[state=open]:rotate-180" })
549
+ }
550
+ ),
551
+ /* @__PURE__ */ jsxRuntime.jsx(
552
+ PopoverContent,
553
+ {
554
+ align: "start",
555
+ sideOffset: 14,
556
+ collisionPadding: 16,
557
+ className: "max-h-[min(40rem,var(--radix-popover-content-available-height))] w-[min(calc(100vw-2rem),42rem)] overflow-y-auto p-3 lg:w-[min(calc(100vw-2rem),56rem)]",
558
+ children: /* @__PURE__ */ jsxRuntime.jsx(FamilyList, { current, onNavigate: () => setOpen(false) })
559
+ }
560
+ )
561
+ ] });
562
+ }
563
+ function NavLink({
564
+ item,
565
+ className,
566
+ onNavigate,
567
+ line = false
568
+ }) {
283
569
  const cls = cn(
284
570
  "rounded-full px-3 py-2 text-[0.9375rem] transition-colors",
285
571
  item.active ? "text-foreground" : "text-muted-foreground hover:text-foreground",
572
+ line && "relative after:absolute after:inset-x-3 after:-bottom-[0.625rem] after:h-0.5 after:rounded-full",
573
+ line && item.active && "after:bg-foreground",
286
574
  className
287
575
  );
288
576
  if (item.external) {
289
577
  return /* @__PURE__ */ jsxRuntime.jsx("a", { href: item.href, className: cls, rel: "noreferrer", onClick: onNavigate, children: item.label });
290
578
  }
291
- return /* @__PURE__ */ jsxRuntime.jsx(Link2__default.default, { href: item.href, className: cls, "aria-current": item.active ? "page" : void 0, onClick: onNavigate, children: item.label });
579
+ return /* @__PURE__ */ jsxRuntime.jsx(Link5__default.default, { href: item.href, className: cls, "aria-current": item.active ? "page" : void 0, onClick: onNavigate, children: item.label });
580
+ }
581
+ function NavRow({ item, onNavigate }) {
582
+ const body = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
583
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[0.9375rem] font-medium leading-6 text-foreground", children: item.label }),
584
+ item.description ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[0.8125rem] leading-snug text-muted-foreground", children: item.description }) : null
585
+ ] });
586
+ const cls = cn(
587
+ "flex flex-col gap-0.5 rounded-xl px-3 py-2 transition-colors hover:bg-accent",
588
+ item.active && "bg-muted hover:bg-muted dark:bg-white/[0.06]"
589
+ );
590
+ return item.external ? /* @__PURE__ */ jsxRuntime.jsx("a", { href: item.href, className: cls, rel: "noreferrer", onClick: onNavigate, children: body }) : /* @__PURE__ */ jsxRuntime.jsx(Link5__default.default, { href: item.href, className: cls, "aria-current": item.active ? "page" : void 0, onClick: onNavigate, children: body });
591
+ }
592
+ var seeAll = (item) => typeof item.label === "string" ? `All ${item.label.toLowerCase()}` : "See all";
593
+ function NavDropdown({ item }) {
594
+ const [open, setOpen] = react.useState(false);
595
+ const active = item.active || item.children?.some((c) => c.active);
596
+ return /* @__PURE__ */ jsxRuntime.jsxs(Popover, { open, onOpenChange: setOpen, children: [
597
+ /* @__PURE__ */ jsxRuntime.jsxs(
598
+ PopoverTrigger,
599
+ {
600
+ className: cn(
601
+ "group inline-flex items-center gap-1 rounded-full py-2 pl-3 pr-2.5 text-[0.9375rem] transition-colors",
602
+ active ? "text-foreground" : "text-muted-foreground hover:text-foreground data-[state=open]:text-foreground"
603
+ ),
604
+ children: [
605
+ item.label,
606
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { "aria-hidden": true, className: "size-3.5 transition-transform duration-200 group-data-[state=open]:rotate-180" })
607
+ ]
608
+ }
609
+ ),
610
+ /* @__PURE__ */ jsxRuntime.jsxs(PopoverContent, { align: "center", sideOffset: 10, className: "w-[min(calc(100vw-2rem),26rem)] p-2", children: [
611
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "flex flex-col", children: item.children?.map((c) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx(NavRow, { item: c, onNavigate: () => setOpen(false) }) }, c.href)) }),
612
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1.5 border-t border-border px-1 pt-1.5", children: /* @__PURE__ */ jsxRuntime.jsx(
613
+ NavLink,
614
+ {
615
+ item: { ...item, label: seeAll(item), children: void 0 },
616
+ className: "block rounded-xl px-2 py-2 text-[0.875rem]",
617
+ onNavigate: () => setOpen(false)
618
+ }
619
+ ) })
620
+ ] })
621
+ ] });
292
622
  }
293
623
  function SiteHeader({
294
624
  home = "/",
295
625
  brand,
626
+ product,
627
+ family,
296
628
  nav = [],
629
+ search,
297
630
  actions,
631
+ variant = "site",
632
+ navOnPhone = true,
633
+ menu: menuExtra,
298
634
  className
299
635
  }) {
300
636
  const [open, setOpen] = react.useState(false);
637
+ const tool = variant === "tool";
638
+ const size = tool ? 24 : 28;
639
+ const current = typeof family === "string" ? family : void 0;
640
+ const phoneNav = navOnPhone ? nav : [];
641
+ const menu = phoneNav.length > 0 || Boolean(family) || Boolean(menuExtra);
642
+ const brandNode = brand ?? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center", children: [
643
+ /* @__PURE__ */ jsxRuntime.jsx(Lockup, { size }),
644
+ product ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
645
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: "mx-3 h-5 w-px bg-oca-hairline-strong" }),
646
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium tracking-[-0.01em]", style: { fontSize: size * 0.56 }, children: product })
647
+ ] }) : null
648
+ ] });
649
+ const navigation = nav.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("nav", { "aria-label": "Main", className: "hidden items-center gap-1 md:flex", children: nav.map(
650
+ (n) => n.children?.length ? /* @__PURE__ */ jsxRuntime.jsx(NavDropdown, { item: n }, n.href) : /* @__PURE__ */ jsxRuntime.jsx(NavLink, { item: n, line: tool }, n.href)
651
+ ) }) : null;
301
652
  return /* @__PURE__ */ jsxRuntime.jsx(
302
653
  "header",
303
654
  {
304
655
  className: cn(
305
- "sticky top-0 z-40 w-full border-b border-transparent bg-background/95 backdrop-blur-md supports-[backdrop-filter]:bg-background/90",
656
+ "sticky top-0 z-40 w-full border-b bg-background/95 backdrop-blur-md supports-[backdrop-filter]:bg-background/90",
657
+ tool ? "border-border" : "border-transparent",
306
658
  className
307
659
  ),
308
660
  children: /* @__PURE__ */ jsxRuntime.jsxs(
309
661
  "div",
310
662
  {
311
663
  className: cn(
312
- "oca-container flex h-16 items-center justify-between gap-4 md:h-[4.5rem]",
664
+ "flex items-center justify-between gap-4",
665
+ tool ? "h-14 px-4 md:px-6" : "oca-container h-16 md:h-[4.5rem]",
313
666
  // Three columns, the outer two each at least their content: the
314
667
  // navigation stays centred whatever the actions hold, so it does
315
668
  // not shift when they change (signed out to signed in).
316
- nav.length > 0 && "md:grid md:grid-cols-[minmax(max-content,1fr)_auto_minmax(max-content,1fr)]"
669
+ !tool && nav.length > 0 && "md:grid md:grid-cols-[minmax(max-content,1fr)_auto_minmax(max-content,1fr)]"
317
670
  ),
318
671
  children: [
319
- /* @__PURE__ */ jsxRuntime.jsxs(Link2__default.default, { href: home, className: "-ml-1 justify-self-start rounded-lg p-1", children: [
320
- brand ?? /* @__PURE__ */ jsxRuntime.jsx(Lockup, { size: 28 }),
321
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: " home" })
672
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex min-w-0 items-center gap-1", tool ? "md:gap-1" : "justify-self-start"), children: [
673
+ /* @__PURE__ */ jsxRuntime.jsxs(Link5__default.default, { href: home, className: "-ml-1 min-w-0 rounded-lg p-1", children: [
674
+ brandNode,
675
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: " home" })
676
+ ] }),
677
+ family ? /* @__PURE__ */ jsxRuntime.jsx(FamilyMenu, { current, className: "max-md:hidden" }) : null,
678
+ tool && navigation ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ml-5", children: navigation }) : null
322
679
  ] }),
323
- nav.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("nav", { "aria-label": "Main", className: "hidden items-center gap-1 md:flex", children: nav.map((n) => /* @__PURE__ */ jsxRuntime.jsx(NavLink, { item: n }, n.href)) }) : null,
680
+ !tool ? navigation : null,
324
681
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 justify-self-end", children: [
682
+ search,
325
683
  actions,
326
- nav.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs(Sheet, { open, onOpenChange: setOpen, children: [
684
+ menu ? /* @__PURE__ */ jsxRuntime.jsxs(Sheet, { open, onOpenChange: setOpen, children: [
327
685
  /* @__PURE__ */ jsxRuntime.jsx(
328
686
  SheetTrigger,
329
687
  {
@@ -334,15 +692,36 @@ function SiteHeader({
334
692
  ),
335
693
  /* @__PURE__ */ jsxRuntime.jsxs(SheetContent, { side: "right", className: "pt-16", children: [
336
694
  /* @__PURE__ */ jsxRuntime.jsx(SheetTitle, { className: "sr-only", children: "Menu" }),
337
- /* @__PURE__ */ jsxRuntime.jsx("nav", { "aria-label": "Main", className: "flex flex-col", children: nav.map((n) => /* @__PURE__ */ jsxRuntime.jsx(
338
- NavLink,
339
- {
340
- item: n,
341
- className: "rounded-xl px-3 py-3 text-[1.0625rem]",
342
- onNavigate: () => setOpen(false)
343
- },
344
- n.href
345
- )) })
695
+ menuExtra ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex flex-col", (phoneNav.length > 0 || family) && "border-b border-border pb-3"), children: menuExtra }) : null,
696
+ phoneNav.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("nav", { "aria-label": "Main", className: "flex flex-col", children: phoneNav.map(
697
+ (n) => n.children?.length ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col py-2", children: [
698
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "px-3 pb-1 text-[0.8125rem] text-muted-foreground", children: n.label }),
699
+ n.children.map((c) => /* @__PURE__ */ jsxRuntime.jsx(
700
+ NavLink,
701
+ {
702
+ item: c,
703
+ className: "rounded-xl px-3 py-2.5 text-[1.0625rem]",
704
+ onNavigate: () => setOpen(false)
705
+ },
706
+ c.href
707
+ ))
708
+ ] }, n.href) : /* @__PURE__ */ jsxRuntime.jsx(
709
+ NavLink,
710
+ {
711
+ item: n,
712
+ className: "rounded-xl px-3 py-3 text-[1.0625rem]",
713
+ onNavigate: () => setOpen(false)
714
+ },
715
+ n.href
716
+ )
717
+ ) }) : null,
718
+ family ? /* @__PURE__ */ jsxRuntime.jsxs("details", { className: cn("group", phoneNav.length > 0 && "mt-2 border-t border-border pt-4"), children: [
719
+ /* @__PURE__ */ jsxRuntime.jsxs("summary", { className: "flex cursor-pointer list-none items-center justify-between rounded-xl px-3 py-2.5 text-[1.0625rem] [&::-webkit-details-marker]:hidden", children: [
720
+ "All orangecheck sites",
721
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { "aria-hidden": true, className: "size-4 text-muted-foreground transition-transform group-open:rotate-180" })
722
+ ] }),
723
+ /* @__PURE__ */ jsxRuntime.jsx(FamilyList, { current, onNavigate: () => setOpen(false), stack: true, className: "mt-2" })
724
+ ] }) : null
346
725
  ] })
347
726
  ] }) : null
348
727
  ] })
@@ -352,57 +731,588 @@ function SiteHeader({
352
731
  }
353
732
  );
354
733
  }
734
+ function SkipLink({ href = "#main-content", children = "Skip to content" }) {
735
+ return /* @__PURE__ */ jsxRuntime.jsx(
736
+ "a",
737
+ {
738
+ href,
739
+ 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",
740
+ children
741
+ }
742
+ );
743
+ }
744
+ var BANNER_TONE = {
745
+ neutral: "border-border bg-muted",
746
+ brand: "border-[color-mix(in_oklab,var(--oca-orange)_30%,var(--border))] bg-[color-mix(in_oklab,var(--oca-orange)_9%,var(--background))]",
747
+ danger: "border-[color-mix(in_oklab,var(--destructive)_35%,var(--border))] bg-[color-mix(in_oklab,var(--destructive)_8%,var(--background))]"
748
+ };
749
+ function SiteBanner({
750
+ tone = "neutral",
751
+ children,
752
+ action,
753
+ className
754
+ }) {
755
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { role: "status", "aria-live": "polite", "data-tone": tone, className: cn("border-b text-[0.875rem]", BANNER_TONE[tone], className), children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "oca-container flex flex-wrap items-center justify-between gap-x-4 gap-y-1 py-2.5", children: [
756
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "flex min-w-0 items-baseline gap-2.5 leading-snug", children: [
757
+ tone !== "neutral" ? /* @__PURE__ */ jsxRuntime.jsx(
758
+ "span",
759
+ {
760
+ "aria-hidden": true,
761
+ className: cn(
762
+ "size-2 shrink-0 translate-y-[-0.05em] rounded-full",
763
+ tone === "brand" ? "bg-oca-orange" : "bg-destructive"
764
+ )
765
+ }
766
+ ) : null,
767
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children })
768
+ ] }),
769
+ action ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("shrink-0 font-medium", tone !== "neutral" && "max-sm:pl-[1.125rem]"), children: action }) : null
770
+ ] }) });
771
+ }
772
+ var FOOT_LINK = "inline-flex min-h-11 items-center transition-colors hover:text-foreground md:min-h-0";
773
+ function LegalRow() {
774
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-x-6 gap-y-2 sm:flex-row sm:items-center sm:justify-between", children: [
775
+ /* @__PURE__ */ jsxRuntime.jsx("nav", { "aria-label": "Legal", children: /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "flex flex-wrap gap-x-5", children: LEGAL_LINKS.map((l) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx("a", { href: l.href, className: FOOT_LINK, children: l.label }) }, l.href)) }) }),
776
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
777
+ "\xA9 ",
778
+ (/* @__PURE__ */ new Date()).getFullYear(),
779
+ " OrangeCheck"
780
+ ] })
781
+ ] });
782
+ }
355
783
  function SiteFooter({
356
784
  columns = [],
785
+ family = false,
786
+ legal = false,
787
+ compact = false,
357
788
  fineprint,
358
789
  meta,
359
790
  signature = true,
360
791
  className
361
792
  }) {
362
- return /* @__PURE__ */ jsxRuntime.jsxs("footer", { className: cn("border-t border-border bg-background", className), children: [
363
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "oca-container grid grid-cols-2 gap-x-6 gap-y-10 py-14 md:grid-cols-[1.3fr_repeat(3,1fr)] md:py-16", children: [
364
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "col-span-2 flex flex-col gap-4 md:col-span-1", children: [
365
- /* @__PURE__ */ jsxRuntime.jsx(Lockup, { size: 26 }),
366
- fineprint ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "max-w-xs text-[0.9375rem] leading-relaxed text-muted-foreground", children: fineprint }) : null
793
+ if (compact) {
794
+ return /* @__PURE__ */ jsxRuntime.jsx("footer", { className: cn("border-t border-border bg-background text-[0.875rem] text-muted-foreground", className), children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "oca-container flex flex-col gap-x-8 gap-y-3 py-5 lg:flex-row lg:items-center lg:justify-between", children: [
795
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-x-6 gap-y-1", children: [
796
+ /* @__PURE__ */ jsxRuntime.jsx("a", { href: OCHK_IO, className: "rounded-lg text-foreground", children: /* @__PURE__ */ jsxRuntime.jsx(Lockup, { size: 22 }) }),
797
+ family ? /* @__PURE__ */ jsxRuntime.jsx("nav", { "aria-label": "Protocols", children: /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "flex flex-wrap gap-x-4", children: PROTOCOLS.map((p) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx("a", { href: p.pageHref, className: FOOT_LINK, children: p.label }) }, p.slug)) }) }) : null
367
798
  ] }),
368
- columns.map((col, i) => {
369
- const spans = columns.length % 2 === 1 && i === columns.length - 1;
370
- return /* @__PURE__ */ jsxRuntime.jsxs(
371
- "div",
372
- {
373
- className: cn("flex min-w-0 flex-col gap-1", spans && "col-span-2 md:col-span-1"),
374
- children: [
375
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mb-2 text-[0.875rem] font-medium", children: col.heading }),
376
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex flex-col gap-1", spans && "grid grid-cols-2 gap-x-6 md:flex md:flex-col"), children: col.links.map((l) => /* @__PURE__ */ jsxRuntime.jsx(
377
- NavLink,
378
- {
379
- item: l,
380
- className: "-mx-3 py-2.5 text-[0.9375rem] md:py-1.5"
381
- },
382
- l.href
383
- )) })
384
- ]
385
- },
386
- col.heading
387
- );
388
- })
389
- ] }),
799
+ legal || meta ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-x-6 gap-y-2 sm:flex-row sm:flex-wrap sm:items-center", children: [
800
+ legal ? /* @__PURE__ */ jsxRuntime.jsx(LegalRow, {}) : null,
801
+ meta
802
+ ] }) : null
803
+ ] }) });
804
+ }
805
+ const cols = [
806
+ ...columns,
807
+ ...family ? familyByGroup().map((g) => ({
808
+ // The lockup above already says orangecheck.
809
+ heading: g.id === "orangecheck" ? "Start here" : g.label,
810
+ links: g.sites.map((s) => ({ href: s.href, label: s.label, external: true }))
811
+ })) : []
812
+ ];
813
+ const n = cols.length;
814
+ const inline = n <= 5;
815
+ const grid = {
816
+ "--oca-footer-md": `repeat(${Math.max(1, Math.min(n, 4))}, minmax(0, 1fr))`,
817
+ "--oca-footer-lg": inline ? `minmax(0, 1.3fr) repeat(${Math.max(1, n)}, minmax(0, 1fr))` : `repeat(${Math.min(n, 6)}, minmax(0, 1fr))`
818
+ };
819
+ return /* @__PURE__ */ jsxRuntime.jsxs("footer", { className: cn("border-t border-border bg-background", className), children: [
820
+ /* @__PURE__ */ jsxRuntime.jsxs(
821
+ "div",
822
+ {
823
+ style: grid,
824
+ 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)]",
825
+ children: [
826
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("col-span-full flex flex-col gap-4", inline && "lg:col-span-1"), children: [
827
+ /* @__PURE__ */ jsxRuntime.jsx(Lockup, { size: 26 }),
828
+ fineprint ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "max-w-xs text-[0.9375rem] leading-relaxed text-muted-foreground", children: fineprint }) : null
829
+ ] }),
830
+ cols.map((col, i) => {
831
+ const spans = n % 2 === 1 && i === n - 1;
832
+ return /* @__PURE__ */ jsxRuntime.jsxs(
833
+ "div",
834
+ {
835
+ className: cn("flex min-w-0 flex-col gap-1", spans && "col-span-2 md:col-span-1"),
836
+ children: [
837
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mb-2 text-[0.875rem] font-medium", children: col.heading }),
838
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex flex-col gap-1", spans && "grid grid-cols-2 gap-x-6 md:flex md:flex-col"), children: col.links.map((l) => /* @__PURE__ */ jsxRuntime.jsx(
839
+ NavLink,
840
+ {
841
+ item: l,
842
+ className: "-mx-3 py-2.5 text-[0.9375rem] md:py-1.5"
843
+ },
844
+ l.href
845
+ )) })
846
+ ]
847
+ },
848
+ col.heading
849
+ );
850
+ })
851
+ ]
852
+ }
853
+ ),
390
854
  signature ? /* @__PURE__ */ jsxRuntime.jsx("div", { "aria-hidden": true, className: "oca-container select-none overflow-hidden pb-8 md:pb-12", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-end gap-[0.18em] text-[clamp(3rem,11.5vw,10rem)] leading-[0.78] tracking-[-0.065em] [font-family:var(--oc-font-display)]", children: [
391
855
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mb-[0.06em] inline-block w-[1.1em] shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(Mark, { className: "block h-auto w-full" }) }),
392
856
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: "orangecheck" })
393
857
  ] }) }) : null,
394
- meta ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "oca-container", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t border-border py-6 text-[0.875rem] text-muted-foreground", children: meta }) }) : null
858
+ legal || meta ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "oca-container", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3 border-t border-border py-6 text-[0.875rem] text-muted-foreground", children: [
859
+ legal ? /* @__PURE__ */ jsxRuntime.jsx(LegalRow, {}) : null,
860
+ meta
861
+ ] }) }) : null
395
862
  ] });
396
863
  }
397
- var ShellContext = react.createContext({});
864
+ function IsoCheck({ size = 360, settle = false, shadow = true, tilt = false, title, className }) {
865
+ const ref = react.useRef(null);
866
+ react.useEffect(() => {
867
+ const el = ref.current;
868
+ if (!el || !tilt || window.matchMedia("(prefers-reduced-motion: reduce)").matches) return;
869
+ let raf = 0;
870
+ let tx = 0;
871
+ let ty = 0;
872
+ let x = 0;
873
+ let y = 0;
874
+ const step = () => {
875
+ x += (tx - x) * 0.08;
876
+ y += (ty - y) * 0.08;
877
+ el.style.setProperty("--rx", `${(-y * 10).toFixed(2)}deg`);
878
+ el.style.setProperty("--ry", `${(x * 14).toFixed(2)}deg`);
879
+ raf = Math.abs(tx - x) + Math.abs(ty - y) > 1e-3 ? requestAnimationFrame(step) : 0;
880
+ };
881
+ const move = (e) => {
882
+ const b = el.getBoundingClientRect();
883
+ tx = Math.max(-1, Math.min(1, (e.clientX - (b.left + b.width / 2)) / (window.innerWidth / 2)));
884
+ ty = Math.max(-1, Math.min(1, (e.clientY - (b.top + b.height / 2)) / (window.innerHeight / 2)));
885
+ if (!raf) raf = requestAnimationFrame(step);
886
+ };
887
+ window.addEventListener("pointermove", move, { passive: true });
888
+ return () => {
889
+ cancelAnimationFrame(raf);
890
+ window.removeEventListener("pointermove", move);
891
+ };
892
+ }, [tilt]);
893
+ return /* @__PURE__ */ jsxRuntime.jsxs(
894
+ "div",
895
+ {
896
+ ref,
897
+ className: cn("relative inline-block", settle && "oca-animate-settle", className),
898
+ style: { width: size, perspective: tilt ? 900 : void 0 },
899
+ children: [
900
+ tilt ? /* @__PURE__ */ jsxRuntime.jsx(
901
+ "div",
902
+ {
903
+ "aria-hidden": true,
904
+ className: "absolute left-1/2 top-1/2 -z-0 aspect-square w-[120%] -translate-x-1/2 -translate-y-1/2 rounded-full opacity-70 blur-3xl",
905
+ style: { background: "radial-gradient(closest-side, rgb(255 140 70 / 0.35), transparent)" }
906
+ }
907
+ ) : null,
908
+ /* @__PURE__ */ jsxRuntime.jsx(
909
+ "div",
910
+ {
911
+ className: "relative z-10 transition-transform duration-300 ease-out",
912
+ style: tilt ? { transform: "rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg))", transformStyle: "preserve-3d" } : void 0,
913
+ children: /* @__PURE__ */ jsxRuntime.jsx(Mark, { size, title, className: "block" })
914
+ }
915
+ ),
916
+ shadow ? /* @__PURE__ */ jsxRuntime.jsx(
917
+ "div",
918
+ {
919
+ "aria-hidden": true,
920
+ className: "absolute left-[8%] right-[8%] rounded-[50%] opacity-60 blur-xl",
921
+ style: { height: size * 0.08, bottom: -size * 0.04, background: "rgb(234 88 11 / 0.18)" }
922
+ }
923
+ ) : null
924
+ ]
925
+ }
926
+ );
927
+ }
928
+ function SignInFrame({
929
+ title = "Sign in",
930
+ lead,
931
+ children,
932
+ error,
933
+ fineprint,
934
+ brand,
935
+ home = "/",
936
+ back,
937
+ art,
938
+ caption,
939
+ className
940
+ }) {
941
+ return /* @__PURE__ */ jsxRuntime.jsxs(
942
+ "main",
943
+ {
944
+ id: "main-content",
945
+ className: cn("grid min-h-dvh grid-cols-1 bg-background text-foreground lg:grid-cols-2", className),
946
+ children: [
947
+ /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "flex flex-col px-4 pb-8 pt-5 sm:px-8 lg:px-14 lg:pt-8", children: [
948
+ /* @__PURE__ */ jsxRuntime.jsxs("header", { className: "flex items-center justify-between gap-4", children: [
949
+ /* @__PURE__ */ jsxRuntime.jsxs(Link5__default.default, { href: home, className: "w-fit rounded-lg", children: [
950
+ brand ?? /* @__PURE__ */ jsxRuntime.jsx(Lockup, { size: 28 }),
951
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: " home" })
952
+ ] }),
953
+ back === void 0 ? /* @__PURE__ */ jsxRuntime.jsx(
954
+ Link5__default.default,
955
+ {
956
+ href: home,
957
+ className: "text-[0.9375rem] text-muted-foreground underline-offset-4 hover:text-foreground hover:underline",
958
+ children: "Back to home"
959
+ }
960
+ ) : back
961
+ ] }),
962
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mx-auto flex w-full max-w-[25rem] flex-1 flex-col justify-center gap-9 py-12", children: [
963
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3", children: [
964
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "oca-display-2", children: title }),
965
+ lead ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "oca-lead", children: lead }) : null
966
+ ] }),
967
+ /* @__PURE__ */ jsxRuntime.jsx("div", { children }),
968
+ error ? /* @__PURE__ */ jsxRuntime.jsx("p", { role: "alert", className: "text-[0.9375rem] text-destructive", children: error }) : null,
969
+ fineprint ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[0.8125rem] leading-relaxed text-muted-foreground", children: fineprint }) : null
970
+ ] })
971
+ ] }),
972
+ /* @__PURE__ */ jsxRuntime.jsxs(
973
+ "aside",
974
+ {
975
+ "aria-hidden": true,
976
+ 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",
977
+ children: [
978
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-1 items-center justify-center", children: art ?? /* @__PURE__ */ jsxRuntime.jsx(IsoCheck, { size: 340, settle: true, tilt: true, className: "max-w-full" }) }),
979
+ caption ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex max-w-[24rem] flex-col gap-3", children: caption }) : null
980
+ ]
981
+ }
982
+ )
983
+ ]
984
+ }
985
+ );
986
+ }
987
+ function Spinner({ className, label }) {
988
+ return /* @__PURE__ */ jsxRuntime.jsxs(
989
+ "svg",
990
+ {
991
+ viewBox: "0 0 24 24",
992
+ fill: "none",
993
+ role: label ? "status" : void 0,
994
+ "aria-label": label,
995
+ "aria-hidden": label ? void 0 : true,
996
+ className: cn("size-4 animate-spin", className),
997
+ children: [
998
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "9", stroke: "currentColor", strokeOpacity: "0.2", strokeWidth: "2.5" }),
999
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M21 12a9 9 0 0 0-9-9", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round" })
1000
+ ]
1001
+ }
1002
+ );
1003
+ }
1004
+ react.forwardRef(function Separator3({ className, orientation = "horizontal", decorative = true, ...props }, ref) {
1005
+ return /* @__PURE__ */ jsxRuntime.jsx(
1006
+ SeparatorPrimitive__namespace.Root,
1007
+ {
1008
+ ref,
1009
+ decorative,
1010
+ orientation,
1011
+ className: cn(
1012
+ "shrink-0 bg-border",
1013
+ orientation === "horizontal" ? "h-px w-full" : "h-full w-px",
1014
+ className
1015
+ ),
1016
+ ...props
1017
+ }
1018
+ );
1019
+ });
1020
+ function sharedContext(name, initial) {
1021
+ const key = /* @__PURE__ */ Symbol.for(`@orangecheck/app-design/${name}`);
1022
+ const store = globalThis;
1023
+ return store[key] ?? (store[key] = react.createContext(initial));
1024
+ }
1025
+
1026
+ // src/lib/density.ts
1027
+ var DensityContext = sharedContext("density", "comfortable");
1028
+ function DensityProvider({ density, children }) {
1029
+ return react.createElement(DensityContext.Provider, { value: density }, children);
1030
+ }
1031
+ var ShellContext = sharedContext("shell-place", {});
398
1032
  function useShellPlace() {
399
1033
  return react.useContext(ShellContext);
400
1034
  }
1035
+ var buttonVariants = classVarianceAuthority.cva(
1036
+ [
1037
+ "inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-full font-medium",
1038
+ "transition-[background-color,border-color,color,box-shadow,transform] duration-150",
1039
+ "outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
1040
+ "active:translate-y-px disabled:pointer-events-none",
1041
+ // Disabled is one look for every variant: a quiet grey pill, never a
1042
+ // faded black or orange slab that reads as broken.
1043
+ "disabled:border disabled:border-border disabled:bg-muted disabled:text-oca-subtle disabled:shadow-none",
1044
+ "[&_svg]:pointer-events-none [&_svg]:size-[1.1em] [&_svg]:shrink-0"
1045
+ ],
1046
+ {
1047
+ variants: {
1048
+ variant: {
1049
+ primary: "bg-primary text-primary-foreground hover:bg-primary/85",
1050
+ secondary: "border border-border bg-secondary text-secondary-foreground hover:border-oca-hairline-strong hover:bg-accent",
1051
+ brand: "bg-brand text-brand-foreground hover:bg-oca-orange-deep",
1052
+ ghost: "text-foreground hover:bg-accent",
1053
+ danger: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
1054
+ link: "h-auto rounded-none px-0 text-foreground underline decoration-foreground/35 underline-offset-4 hover:decoration-foreground",
1055
+ onInk: "bg-white text-oca-ink hover:bg-white/90",
1056
+ onInkOutline: "border border-white/20 text-white hover:bg-white/10"
1057
+ },
1058
+ size: {
1059
+ sm: "h-9 px-4 text-sm",
1060
+ md: "h-11 px-5 text-[0.9375rem]",
1061
+ lg: "h-14 px-7 text-[1.0625rem]",
1062
+ icon: "size-10",
1063
+ "icon-sm": "size-8"
1064
+ }
1065
+ },
1066
+ compoundVariants: [{ variant: "link", className: "h-auto px-0" }],
1067
+ defaultVariants: { variant: "primary", size: "md" }
1068
+ }
1069
+ );
1070
+ var Button = react.forwardRef(function Button2({ className, variant, size, asChild = false, loading = false, disabled, children, type, ...props }, ref) {
1071
+ const Comp = asChild ? reactSlot.Slot : "button";
1072
+ return /* @__PURE__ */ jsxRuntime.jsx(
1073
+ Comp,
1074
+ {
1075
+ ref,
1076
+ "data-ui": "button",
1077
+ className: cn(buttonVariants({ variant, size }), className),
1078
+ disabled: asChild ? void 0 : disabled || loading,
1079
+ "aria-busy": loading || void 0,
1080
+ type: asChild ? void 0 : type ?? "button",
1081
+ ...props,
1082
+ children: asChild ? children : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1083
+ loading ? /* @__PURE__ */ jsxRuntime.jsx(Spinner, { className: "size-[1.1em]" }) : null,
1084
+ children
1085
+ ] })
1086
+ }
1087
+ );
1088
+ });
1089
+ function useActiveHeading(ids) {
1090
+ const [active, setActive] = react.useState(ids[0]);
1091
+ const key = ids.join("|");
1092
+ react.useEffect(() => {
1093
+ setActive(key.split("|")[0] || void 0);
1094
+ const els = key.split("|").map((id) => document.getElementById(id)).filter((el) => el !== null);
1095
+ if (els.length === 0 || typeof IntersectionObserver === "undefined") return;
1096
+ const io = new IntersectionObserver(
1097
+ (entries) => {
1098
+ const hit = entries.filter((e) => e.isIntersecting).sort((a, b) => a.boundingClientRect.top - b.boundingClientRect.top)[0];
1099
+ if (hit) setActive(hit.target.id);
1100
+ },
1101
+ { rootMargin: "-80px 0px -65% 0px" }
1102
+ );
1103
+ els.forEach((el) => io.observe(el));
1104
+ return () => io.disconnect();
1105
+ }, [key]);
1106
+ return active;
1107
+ }
1108
+ function useHeadings(selector = "#docs-content", key) {
1109
+ const [items, setItems] = react.useState([]);
1110
+ react.useEffect(() => {
1111
+ const read = () => {
1112
+ const root = document.querySelector(selector);
1113
+ if (!root) return setItems([]);
1114
+ setItems(
1115
+ Array.from(root.querySelectorAll("h2[id], h3[id]")).map((h) => ({
1116
+ id: h.id,
1117
+ // The anchor link's "#" is not part of the name.
1118
+ label: (h.querySelector("[data-heading-text]") ?? h).textContent?.trim() ?? "",
1119
+ level: h.tagName === "H3" ? 3 : 2
1120
+ }))
1121
+ );
1122
+ };
1123
+ const raf = requestAnimationFrame(read);
1124
+ const t = setTimeout(read, 80);
1125
+ return () => {
1126
+ cancelAnimationFrame(raf);
1127
+ clearTimeout(t);
1128
+ };
1129
+ }, [selector, key]);
1130
+ const activeId = useActiveHeading(items.map((i) => i.id));
1131
+ return { items, activeId };
1132
+ }
1133
+ function OnThisPage({
1134
+ items,
1135
+ activeId,
1136
+ title = "On this page",
1137
+ onNavigate,
1138
+ className
1139
+ }) {
1140
+ const id = react.useId();
1141
+ if (items.length === 0) return null;
1142
+ return (
1143
+ // With no visible title (a folded list under its own summary) the name is still "On this page".
1144
+ /* @__PURE__ */ jsxRuntime.jsxs("nav", { "aria-labelledby": title ? id : void 0, "aria-label": title ? void 0 : "On this page", className, children: [
1145
+ title ? /* @__PURE__ */ jsxRuntime.jsx("p", { id, className: "mb-3 text-[0.875rem] font-medium", children: title }) : null,
1146
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { children: items.map((t) => {
1147
+ const on = t.id === activeId;
1148
+ return /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx(
1149
+ "a",
1150
+ {
1151
+ href: `#${t.id}`,
1152
+ onClick: onNavigate,
1153
+ "aria-current": on ? "location" : void 0,
1154
+ className: cn(
1155
+ "block border-l py-1.5 text-[0.875rem] leading-snug transition-colors",
1156
+ t.level === 3 ? "pl-7" : "pl-4",
1157
+ on ? "border-foreground text-foreground" : "border-border text-muted-foreground hover:text-foreground"
1158
+ ),
1159
+ children: t.label
1160
+ }
1161
+ ) }, t.id);
1162
+ }) })
1163
+ ] })
1164
+ );
1165
+ }
1166
+ var STATUS_WORDS = /* @__PURE__ */ new Set(["live", "testing", "not-yet", "paused", "good", "caution", "refused"]);
1167
+ var pathOf = (href) => href.split(/[?#]/)[0].replace(/(.)\/$/, "$1");
1168
+ function DocsNav({
1169
+ sections,
1170
+ current,
1171
+ onNavigate,
1172
+ className
1173
+ }) {
1174
+ const here = pathOf(current);
1175
+ const activeSection = react.useMemo(
1176
+ () => sections.findIndex((s) => s.items.some((i) => pathOf(i.href) === here)),
1177
+ [sections, here]
1178
+ );
1179
+ const [peeked, setPeeked] = react.useState(() => /* @__PURE__ */ new Set());
1180
+ react.useEffect(() => setPeeked(/* @__PURE__ */ new Set()), [activeSection]);
1181
+ const activeRef = react.useRef(null);
1182
+ react.useEffect(() => {
1183
+ const id = requestAnimationFrame(() => activeRef.current?.scrollIntoView({ block: "nearest" }));
1184
+ return () => cancelAnimationFrame(id);
1185
+ }, [here]);
1186
+ const base = react.useId();
1187
+ return /* @__PURE__ */ jsxRuntime.jsx("nav", { "aria-label": "Docs", className: cn("flex flex-col gap-0.5", className), children: sections.map((section, si) => {
1188
+ const isActive = si === activeSection;
1189
+ const open = isActive || peeked.has(si);
1190
+ const panel = `${base}-s${si}`;
1191
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1192
+ /* @__PURE__ */ jsxRuntime.jsxs(
1193
+ "button",
1194
+ {
1195
+ type: "button",
1196
+ "aria-expanded": open,
1197
+ "aria-controls": panel,
1198
+ onClick: () => {
1199
+ if (isActive) return;
1200
+ setPeeked((p) => {
1201
+ const n = new Set(p);
1202
+ if (n.has(si)) n.delete(si);
1203
+ else n.add(si);
1204
+ return n;
1205
+ });
1206
+ },
1207
+ className: cn(
1208
+ "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",
1209
+ isActive ? "font-medium text-foreground" : "text-muted-foreground hover:bg-accent hover:text-foreground",
1210
+ isActive && "cursor-default"
1211
+ ),
1212
+ children: [
1213
+ section.label,
1214
+ /* @__PURE__ */ jsxRuntime.jsx(
1215
+ lucideReact.ChevronRight,
1216
+ {
1217
+ "aria-hidden": true,
1218
+ className: cn("size-3.5 shrink-0 text-oca-subtle transition-transform duration-200", open && "rotate-90")
1219
+ }
1220
+ )
1221
+ ]
1222
+ }
1223
+ ),
1224
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { id: panel, hidden: !open, className: "mb-2 ml-2.5 mt-0.5 border-l border-border", children: section.items.map((item) => {
1225
+ const on = pathOf(item.href) === here;
1226
+ const badge = typeof item.badge === "string" && STATUS_WORDS.has(item.badge) ? /* @__PURE__ */ jsxRuntime.jsx(StatusBadge, { status: item.badge }) : item.badge ? /* @__PURE__ */ jsxRuntime.jsx(Badge, { tone: "muted", children: item.badge }) : null;
1227
+ return /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsxs(
1228
+ Link5__default.default,
1229
+ {
1230
+ href: item.href,
1231
+ ref: on ? activeRef : void 0,
1232
+ onClick: onNavigate,
1233
+ "aria-current": on ? "page" : void 0,
1234
+ className: cn(
1235
+ "-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",
1236
+ on ? "border-foreground font-medium text-foreground" : "border-transparent text-muted-foreground hover:border-oca-hairline-strong hover:text-foreground"
1237
+ ),
1238
+ children: [
1239
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1", children: item.label }),
1240
+ badge
1241
+ ]
1242
+ }
1243
+ ) }, item.href);
1244
+ }) })
1245
+ ] }, section.label);
1246
+ }) });
1247
+ }
1248
+ var DOCS_HEADER_NAV = OCHK_IO_NAV.map((n) => n.href === DOCS_HREF ? { ...n, active: true } : n);
1249
+ function DocsShell({
1250
+ nav,
1251
+ current,
1252
+ header,
1253
+ search,
1254
+ actions,
1255
+ breadcrumbs,
1256
+ toc,
1257
+ pager,
1258
+ footer,
1259
+ children
1260
+ }) {
1261
+ const [menu, setMenu] = react.useState(false);
1262
+ react.useEffect(() => setMenu(false), [current]);
1263
+ const read = useHeadings("#docs-content", current);
1264
+ const items = toc ?? read.items;
1265
+ const activeId = toc ? void 0 : read.activeId;
1266
+ const here = pathOf(current);
1267
+ const place = react.useMemo(() => {
1268
+ for (const s of nav) {
1269
+ const it = s.items.find((i) => pathOf(i.href) === here);
1270
+ if (it) return { section: s.label, page: it.label };
1271
+ }
1272
+ return null;
1273
+ }, [nav, here]);
1274
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-h-dvh flex-col bg-background", children: [
1275
+ /* @__PURE__ */ jsxRuntime.jsx(SkipLink, {}),
1276
+ header ?? /* @__PURE__ */ jsxRuntime.jsx(SiteHeader, { home: OCHK_IO, family: "docs", nav: DOCS_HEADER_NAV, search, actions }),
1277
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "sticky top-16 z-30 border-b border-border bg-background/95 backdrop-blur-md supports-[backdrop-filter]:bg-background/90 md:top-[4.5rem] lg:hidden", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "oca-container flex h-12 items-center gap-2", children: /* @__PURE__ */ jsxRuntime.jsxs(Sheet, { open: menu, onOpenChange: setMenu, children: [
1278
+ /* @__PURE__ */ jsxRuntime.jsxs(SheetTrigger, { className: "-ml-2 inline-flex h-10 min-w-0 items-center gap-2 rounded-full px-2.5 text-[0.875rem] hover:bg-accent", children: [
1279
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PanelLeft, { "aria-hidden": true, className: "size-[1.125rem] shrink-0" }),
1280
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Docs menu. " }),
1281
+ place ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 items-center gap-1.5", children: [
1282
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 text-muted-foreground", children: place.section }),
1283
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { "aria-hidden": true, className: "size-3.5 shrink-0 text-oca-subtle" }),
1284
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate font-medium", children: place.page })
1285
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: "Docs" })
1286
+ ] }),
1287
+ /* @__PURE__ */ jsxRuntime.jsxs(SheetContent, { side: "left", className: "w-[min(88vw,22rem)] gap-0 p-0", children: [
1288
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-b border-border px-5 py-4 pr-14", children: /* @__PURE__ */ jsxRuntime.jsx(SheetTitle, { className: "text-[1.0625rem] font-medium", children: "Docs" }) }),
1289
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-y-auto p-3", children: /* @__PURE__ */ jsxRuntime.jsx(DocsNav, { sections: nav, current, onNavigate: () => setMenu(false) }) })
1290
+ ] })
1291
+ ] }) }) }),
1292
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "oca-container flex-1", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "lg:grid lg:grid-cols-[13.5rem_minmax(0,1fr)] lg:gap-x-10 xl:grid-cols-[13.5rem_minmax(0,1fr)_11rem]", children: [
1293
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "sticky top-[4.5rem] hidden max-h-[calc(100dvh-4.5rem)] self-start overflow-y-auto overscroll-contain py-8 pr-1 lg:block", children: /* @__PURE__ */ jsxRuntime.jsx(DocsNav, { sections: nav, current }) }),
1294
+ /* @__PURE__ */ jsxRuntime.jsxs("main", { id: "main-content", className: "min-w-0 pb-16 pt-6 md:pt-8", children: [
1295
+ breadcrumbs ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-6 max-lg:hidden", children: breadcrumbs }) : null,
1296
+ items.length > 1 ? /* @__PURE__ */ jsxRuntime.jsxs("details", { className: "group mb-8 rounded-2xl border border-border bg-card xl:hidden", children: [
1297
+ /* @__PURE__ */ jsxRuntime.jsxs("summary", { className: "flex min-h-12 cursor-pointer list-none items-center justify-between px-4 text-[0.9375rem] font-medium [&::-webkit-details-marker]:hidden", children: [
1298
+ "On this page",
1299
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { "aria-hidden": true, className: "size-4 text-muted-foreground transition-transform group-open:rotate-180" })
1300
+ ] }),
1301
+ /* @__PURE__ */ jsxRuntime.jsx(OnThisPage, { items, activeId, title: null, className: "px-4 pb-4" })
1302
+ ] }) : null,
1303
+ /* @__PURE__ */ jsxRuntime.jsx("article", { id: "docs-content", className: "max-w-[46rem]", children }),
1304
+ pager ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-16 max-w-[46rem]", children: pager }) : null
1305
+ ] }),
1306
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "sticky top-[4.5rem] hidden max-h-[calc(100dvh-4.5rem)] self-start overflow-y-auto py-10 xl:block", children: items.length > 1 ? /* @__PURE__ */ jsxRuntime.jsx(OnThisPage, { items, activeId }) : null })
1307
+ ] }) }),
1308
+ footer ?? /* @__PURE__ */ jsxRuntime.jsx(SiteFooter, { columns: OCHK_IO_FOOTER, family: true, legal: true, signature: false })
1309
+ ] });
1310
+ }
401
1311
  function SideNav({ groups, onNavigate }) {
402
1312
  return /* @__PURE__ */ jsxRuntime.jsx("nav", { "aria-label": "Pages", className: "flex flex-col gap-5", children: groups.map((g, gi) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-0.5", children: [
403
1313
  g.label ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "px-3 pb-1 text-[0.8125rem] text-muted-foreground", children: g.label }) : null,
404
1314
  g.items.map((it) => /* @__PURE__ */ jsxRuntime.jsxs(
405
- Link2__default.default,
1315
+ Link5__default.default,
406
1316
  {
407
1317
  href: it.href,
408
1318
  onClick: onNavigate,
@@ -437,7 +1347,7 @@ function SectionSwitch({
437
1347
  children: sections.map((sec) => {
438
1348
  const on = sec.id === current.id;
439
1349
  return /* @__PURE__ */ jsxRuntime.jsx(
440
- Link2__default.default,
1350
+ Link5__default.default,
441
1351
  {
442
1352
  href: sec.href,
443
1353
  onClick: onNavigate,
@@ -467,7 +1377,7 @@ function TabBar({ items }) {
467
1377
  className: "mx-auto grid h-14 max-w-[32rem] px-1.5",
468
1378
  style: { gridTemplateColumns: `repeat(${items.length}, minmax(0, 1fr))` },
469
1379
  children: items.map((it) => /* @__PURE__ */ jsxRuntime.jsxs(
470
- Link2__default.default,
1380
+ Link5__default.default,
471
1381
  {
472
1382
  href: it.href,
473
1383
  "aria-current": it.active ? "page" : void 0,
@@ -576,7 +1486,7 @@ function AppShell({
576
1486
  footer ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-auto flex flex-col gap-3", children: footer }) : null
577
1487
  ] })
578
1488
  ] }),
579
- /* @__PURE__ */ jsxRuntime.jsx(Link2__default.default, { href: home, "aria-label": "Home", className: "rounded-lg p-1", children: /* @__PURE__ */ jsxRuntime.jsx(Lockup, { size: 22 }) }),
1489
+ /* @__PURE__ */ jsxRuntime.jsx(Link5__default.default, { href: home, "aria-label": "Home", className: "rounded-lg p-1", children: /* @__PURE__ */ jsxRuntime.jsx(Lockup, { size: 22 }) }),
580
1490
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ml-auto flex items-center", children: account })
581
1491
  ] }),
582
1492
  place.page ? /* @__PURE__ */ jsxRuntime.jsxs(
@@ -599,7 +1509,7 @@ function AppShell({
599
1509
  ] }),
600
1510
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mx-auto flex w-full max-w-[90rem]", children: [
601
1511
  /* @__PURE__ */ jsxRuntime.jsxs("aside", { className: "sticky top-0 hidden h-dvh w-[17rem] shrink-0 flex-col gap-6 overflow-y-auto px-4 py-6 lg:flex", children: [
602
- /* @__PURE__ */ jsxRuntime.jsx(Link2__default.default, { href: home, className: "px-2", "aria-label": "Home", children: /* @__PURE__ */ jsxRuntime.jsx(Lockup, { size: 26 }) }),
1512
+ /* @__PURE__ */ jsxRuntime.jsx(Link5__default.default, { href: home, className: "px-2", "aria-label": "Home", children: /* @__PURE__ */ jsxRuntime.jsx(Lockup, { size: 26 }) }),
603
1513
  switcher,
604
1514
  /* @__PURE__ */ jsxRuntime.jsx(SideNav, { groups }),
605
1515
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-auto flex flex-col gap-3", children: footer })
@@ -630,9 +1540,16 @@ function AccountMenu({
630
1540
  "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",
631
1541
  nameFrom === "lg" ? "lg:pr-3.5" : "sm:pr-3.5"
632
1542
  ),
633
- "aria-label": `Account: ${name}`,
1543
+ "aria-label": `${name}, account menu`,
634
1544
  children: [
635
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex size-8 items-center justify-center rounded-full bg-foreground text-[0.8125rem] font-medium text-background", children: initial }),
1545
+ /* @__PURE__ */ jsxRuntime.jsx(
1546
+ "span",
1547
+ {
1548
+ "aria-hidden": true,
1549
+ "data-initial": initial,
1550
+ className: "flex size-8 items-center justify-center rounded-full bg-foreground text-[0.8125rem] font-medium text-background before:content-[attr(data-initial)]"
1551
+ }
1552
+ ),
636
1553
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("max-w-[10rem] truncate", nameFrom === "lg" ? "max-lg:hidden" : "max-sm:hidden"), children: name })
637
1554
  ]
638
1555
  }
@@ -644,7 +1561,7 @@ function AccountMenu({
644
1561
  ] }),
645
1562
  /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuSeparator, {}),
646
1563
  items.map(
647
- (it, i) => it === "separator" ? /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuSeparator, {}, `sep-${i}`) : it.href ? /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuItem, { asChild: true, destructive: it.destructive, children: /* @__PURE__ */ jsxRuntime.jsxs(Link2__default.default, { href: it.href, children: [
1564
+ (it, i) => it === "separator" ? /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuSeparator, {}, `sep-${i}`) : it.href ? /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuItem, { asChild: true, destructive: it.destructive, children: /* @__PURE__ */ jsxRuntime.jsxs(Link5__default.default, { href: it.href, children: [
648
1565
  it.icon,
649
1566
  it.label
650
1567
  ] }) }, it.label) : /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenuItem, { onSelect: it.onSelect, destructive: it.destructive, children: [
@@ -677,13 +1594,137 @@ function ThemeToggle({ className }) {
677
1594
  }
678
1595
  );
679
1596
  }
1597
+ var OCHK_APP_ACCOUNT = "https://ochk.app/me/account";
1598
+ function SessionAccountView({
1599
+ state,
1600
+ name,
1601
+ detail,
1602
+ items = [],
1603
+ signInHref,
1604
+ signInLabel = "Sign in",
1605
+ accountHref = OCHK_APP_ACCOUNT,
1606
+ onSignOut,
1607
+ nameFrom = "lg"
1608
+ }) {
1609
+ if (state === "in") {
1610
+ return /* @__PURE__ */ jsxRuntime.jsx(
1611
+ AccountMenu,
1612
+ {
1613
+ name: name || "Your account",
1614
+ detail,
1615
+ nameFrom,
1616
+ items: [
1617
+ ...items,
1618
+ ...items.length > 0 ? ["separator"] : [],
1619
+ { label: "Your account", href: accountHref, icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CircleUser, {}) },
1620
+ "separator",
1621
+ { label: "Sign out", onSelect: onSignOut, icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.LogOut, {}) }
1622
+ ]
1623
+ }
1624
+ );
1625
+ }
1626
+ if (state === "unknown") {
1627
+ return /* @__PURE__ */ jsxRuntime.jsx(Button, { asChild: true, size: "sm", variant: "secondary", children: /* @__PURE__ */ jsxRuntime.jsx("a", { href: accountHref, children: "Your account" }) });
1628
+ }
1629
+ return (
1630
+ // No box of its own: it sits exactly where the signed-in chip will. While checking it is only unseen.
1631
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: state === "checking" ? "contents invisible" : "contents", "aria-hidden": state === "checking" || void 0, children: /* @__PURE__ */ jsxRuntime.jsx(Button, { asChild: true, size: "sm", variant: "secondary", tabIndex: state === "checking" ? -1 : void 0, children: /* @__PURE__ */ jsxRuntime.jsx("a", { href: signInHref, children: signInLabel }) }) })
1632
+ );
1633
+ }
1634
+ function ToolShell({
1635
+ protocol: protocol2,
1636
+ tools,
1637
+ home = "/",
1638
+ account,
1639
+ rail = false,
1640
+ railFooter,
1641
+ variant = "tool",
1642
+ banner,
1643
+ footer,
1644
+ children
1645
+ }) {
1646
+ const p = protocolSite(protocol2);
1647
+ const app = variant === "app";
1648
+ const tabs = app ? null : tabsFor([{ items: [...tools] }]);
1649
+ const about = /* @__PURE__ */ jsxRuntime.jsxs(
1650
+ "a",
1651
+ {
1652
+ href: p.pageHref,
1653
+ className: "inline-flex items-center gap-1 rounded-full px-3 py-2 text-[0.9375rem] text-muted-foreground transition-colors hover:text-foreground",
1654
+ children: [
1655
+ "About ",
1656
+ p.label,
1657
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUpRight, { "aria-hidden": true, className: "size-3.5" })
1658
+ ]
1659
+ }
1660
+ );
1661
+ return /* @__PURE__ */ jsxRuntime.jsx(DensityProvider, { density: "compact", children: /* @__PURE__ */ jsxRuntime.jsxs(
1662
+ "div",
1663
+ {
1664
+ className: cn(
1665
+ "flex flex-col bg-background",
1666
+ app ? "h-dvh overflow-hidden" : "min-h-dvh",
1667
+ tabs && "max-md:pb-[calc(3.5rem_+_env(safe-area-inset-bottom))]"
1668
+ ),
1669
+ children: [
1670
+ /* @__PURE__ */ jsxRuntime.jsx(SkipLink, {}),
1671
+ banner,
1672
+ /* @__PURE__ */ jsxRuntime.jsx(
1673
+ SiteHeader,
1674
+ {
1675
+ variant: "tool",
1676
+ home,
1677
+ product: p.label,
1678
+ family: protocol2,
1679
+ nav: tools.map((t) => ({ href: t.href, label: t.label, active: t.active })),
1680
+ navOnPhone: !tabs,
1681
+ menu: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "[&>a]:px-3 [&>a]:py-3 [&>a]:text-[1.0625rem]", children: about }),
1682
+ className: cn(rail && "lg:[&_nav[aria-label=Main]]:hidden"),
1683
+ actions: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1684
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "hidden lg:contents", children: about }),
1685
+ p.status !== "live" ? /* @__PURE__ */ jsxRuntime.jsx(StatusBadge, { status: p.status, className: "max-sm:hidden" }) : null,
1686
+ /* @__PURE__ */ jsxRuntime.jsx(ThemeToggle, { className: "max-sm:hidden" }),
1687
+ account
1688
+ ] })
1689
+ }
1690
+ ),
1691
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("mx-auto flex w-full", app ? "min-h-0 flex-1" : "max-w-[90rem] flex-1"), children: [
1692
+ rail ? /* @__PURE__ */ jsxRuntime.jsxs("aside", { className: "sticky top-14 hidden h-[calc(100dvh-3.5rem)] w-60 shrink-0 flex-col gap-6 overflow-y-auto px-4 py-6 lg:flex", children: [
1693
+ /* @__PURE__ */ jsxRuntime.jsx(SideNav, { groups: [{ label: "Tools", items: tools.map(({ href, label, icon, active }) => ({ href, label, icon, active })) }] }),
1694
+ railFooter ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-auto flex flex-col gap-0.5 px-3 text-[0.875rem] text-muted-foreground [&_a:hover]:text-foreground [&_a]:py-1.5 [&_a]:transition-colors", children: railFooter }) : null
1695
+ ] }) : null,
1696
+ /* @__PURE__ */ jsxRuntime.jsx(
1697
+ "main",
1698
+ {
1699
+ id: "main-content",
1700
+ className: cn("min-w-0 flex-1", app ? "flex min-h-0 flex-col" : "px-4 pb-16 pt-8 md:px-8 md:pt-10"),
1701
+ children: app ? children : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-auto w-full max-w-[72rem]", children })
1702
+ }
1703
+ )
1704
+ ] }),
1705
+ app || footer === false ? null : footer ?? /* @__PURE__ */ jsxRuntime.jsx(SiteFooter, { compact: true, family: true, legal: true }),
1706
+ tabs ? /* @__PURE__ */ jsxRuntime.jsx(TabBar, { items: tabs }) : null
1707
+ ]
1708
+ }
1709
+ ) });
1710
+ }
680
1711
 
681
1712
  exports.AccountMenu = AccountMenu;
682
1713
  exports.AppShell = AppShell;
1714
+ exports.DOCS_HEADER_NAV = DOCS_HEADER_NAV;
1715
+ exports.DocsNav = DocsNav;
1716
+ exports.DocsShell = DocsShell;
1717
+ exports.FamilyMenu = FamilyMenu;
1718
+ exports.OCHK_APP_ACCOUNT = OCHK_APP_ACCOUNT;
1719
+ exports.SessionAccountView = SessionAccountView;
683
1720
  exports.ShellContext = ShellContext;
1721
+ exports.SignInFrame = SignInFrame;
1722
+ exports.SiteBanner = SiteBanner;
684
1723
  exports.SiteFooter = SiteFooter;
685
1724
  exports.SiteHeader = SiteHeader;
1725
+ exports.SkipLink = SkipLink;
686
1726
  exports.ThemeToggle = ThemeToggle;
1727
+ exports.ToolShell = ToolShell;
687
1728
  exports.useShellPlace = useShellPlace;
688
1729
  //# sourceMappingURL=chrome.js.map
689
1730
  //# sourceMappingURL=chrome.js.map