@orangecheck/app-design 0.6.0 → 1.0.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 (46) hide show
  1. package/README.md +4 -3
  2. package/dist/brand.js.map +1 -1
  3. package/dist/brand.mjs.map +1 -1
  4. package/dist/chrome.d.mts +49 -15
  5. package/dist/chrome.d.ts +49 -15
  6. package/dist/chrome.js +619 -55
  7. package/dist/chrome.js.map +1 -1
  8. package/dist/chrome.mjs +617 -57
  9. package/dist/chrome.mjs.map +1 -1
  10. package/dist/components.d.mts +231 -1
  11. package/dist/components.d.ts +231 -1
  12. package/dist/components.js +1187 -2
  13. package/dist/components.js.map +1 -1
  14. package/dist/components.mjs +1162 -5
  15. package/dist/components.mjs.map +1 -1
  16. package/dist/family.d.mts +2 -0
  17. package/dist/family.d.ts +2 -0
  18. package/dist/family.js +167 -0
  19. package/dist/family.js.map +1 -0
  20. package/dist/family.mjs +154 -0
  21. package/dist/family.mjs.map +1 -0
  22. package/dist/index-C6hDqOOS.d.mts +58 -0
  23. package/dist/index-C6hDqOOS.d.ts +58 -0
  24. package/dist/index.d.mts +5 -3
  25. package/dist/index.d.ts +5 -3
  26. package/dist/index.js +1619 -132
  27. package/dist/index.js.map +1 -1
  28. package/dist/index.mjs +1575 -134
  29. package/dist/index.mjs.map +1 -1
  30. package/dist/primitives.d.mts +52 -1
  31. package/dist/primitives.d.ts +52 -1
  32. package/dist/primitives.js +280 -3
  33. package/dist/primitives.js.map +1 -1
  34. package/dist/primitives.mjs +271 -6
  35. package/dist/primitives.mjs.map +1 -1
  36. package/dist/status-badge-BEOxeY9j.d.ts +13 -0
  37. package/dist/status-badge-DRwGhB0h.d.mts +13 -0
  38. package/dist/styles/fonts.css +1 -1
  39. package/dist/styles/tokens.css +4 -2
  40. package/dist/tokens.d.mts +3 -1
  41. package/dist/tokens.d.ts +3 -1
  42. package/dist/tokens.js +5 -3
  43. package/dist/tokens.js.map +1 -1
  44. package/dist/tokens.mjs +5 -3
  45. package/dist/tokens.mjs.map +1 -1
  46. package/package.json +9 -2
@@ -1,12 +1,18 @@
1
- import { forwardRef, createContext, createElement, useRef, useState, useEffect, useContext, Children, isValidElement, cloneElement, useCallback, Component } from 'react';
1
+ import { forwardRef, createContext, createElement, useRef, useState, useEffect, useContext, Children, isValidElement, cloneElement, useCallback, Component, useId, Fragment as Fragment$1 } from 'react';
2
2
  import { clsx } from 'clsx';
3
3
  import { extendTailwindMerge } from 'tailwind-merge';
4
4
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
5
5
  import { cva } from 'class-variance-authority';
6
- import { Check, Copy } from 'lucide-react';
6
+ import { ChevronDown, Check, Copy, ArrowUpRight, CircleDashed, CircleMinus, Clock, CircleX, CircleCheck } from 'lucide-react';
7
7
  import { Slot } from '@radix-ui/react-slot';
8
8
  import * as SeparatorPrimitive from '@radix-ui/react-separator';
9
9
  import 'sonner';
10
+ import Link from 'next/link';
11
+ import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
12
+ import * as LabelPrimitive from '@radix-ui/react-label';
13
+ import * as RadioGroupPrimitive from '@radix-ui/react-radio-group';
14
+ import * as SelectPrimitive from '@radix-ui/react-select';
15
+ import * as SwitchPrimitive from '@radix-ui/react-switch';
10
16
 
11
17
  var merge = extendTailwindMerge({
12
18
  extend: {
@@ -343,13 +349,13 @@ var badgeVariants = cva(
343
349
  tone: {
344
350
  neutral: "border-border bg-card text-foreground",
345
351
  muted: "border-transparent bg-muted text-muted-foreground",
346
- brand: "border-transparent bg-[color-mix(in_oklab,var(--oca-orange)_12%,var(--card))] text-oca-accent-ink",
352
+ brand: "border-transparent bg-[color-mix(in_oklab,var(--oca-orange)_9%,var(--card))] text-oca-accent-ink",
347
353
  danger: "border-transparent bg-[color-mix(in_oklab,var(--destructive)_12%,var(--card))] text-destructive",
348
354
  // A good state is a neutral pill with a green dot, not a green pill.
349
355
  success: GOOD_DOT,
350
356
  // Aliases kept so older call sites keep compiling: attention is
351
357
  // the brand accent, information is neutral.
352
- warning: "border-transparent bg-[color-mix(in_oklab,var(--oca-orange)_12%,var(--card))] text-oca-accent-ink",
358
+ warning: "border-transparent bg-[color-mix(in_oklab,var(--oca-orange)_9%,var(--card))] text-oca-accent-ink",
353
359
  info: "border-border bg-card text-foreground",
354
360
  // Inverted in dark mode, where ink would sit on a card of nearly its own colour.
355
361
  ink: "border-transparent bg-oca-ink text-oca-ink-foreground dark:bg-foreground dark:text-background",
@@ -1433,7 +1439,1158 @@ var ErrorBoundary = class extends Component {
1433
1439
  ) });
1434
1440
  }
1435
1441
  };
1442
+ var TOP = "0,3 2,2 6,4 14,0 16,1 6,6";
1443
+ var LEFT = "0,3 6,6 6,8 0,5";
1444
+ var RIGHT = "6,6 16,1 16,3 6,8";
1445
+ var MARK_FACES = { top: "#FED8AB", left: "#FB933C", right: "#EA580B" };
1446
+ function Mark({ title, size, className, ...rest }) {
1447
+ return /* @__PURE__ */ jsxs(
1448
+ "svg",
1449
+ {
1450
+ viewBox: "0 0 16 8",
1451
+ width: size,
1452
+ height: size ? size / 2 : void 0,
1453
+ role: title ? "img" : void 0,
1454
+ "aria-hidden": title ? void 0 : true,
1455
+ className: cn("shrink-0", className),
1456
+ ...rest,
1457
+ children: [
1458
+ title ? /* @__PURE__ */ jsx("title", { children: title }) : null,
1459
+ /* @__PURE__ */ jsx("polygon", { points: LEFT, fill: MARK_FACES.left }),
1460
+ /* @__PURE__ */ jsx("polygon", { points: RIGHT, fill: MARK_FACES.right }),
1461
+ /* @__PURE__ */ jsx("polygon", { points: TOP, fill: MARK_FACES.top })
1462
+ ]
1463
+ }
1464
+ );
1465
+ }
1466
+ function MarkOutline({ className }) {
1467
+ return /* @__PURE__ */ jsx("svg", { viewBox: "-0.2 -0.2 16.4 8.4", "aria-hidden": true, className: cn("shrink-0 overflow-visible", className), children: [TOP, LEFT, RIGHT].map((points) => /* @__PURE__ */ jsx(
1468
+ "polygon",
1469
+ {
1470
+ points,
1471
+ fill: "none",
1472
+ stroke: "currentColor",
1473
+ strokeWidth: "1",
1474
+ strokeLinejoin: "round",
1475
+ vectorEffect: "non-scaling-stroke"
1476
+ },
1477
+ points
1478
+ )) });
1479
+ }
1480
+ var WORDS = {
1481
+ 404: {
1482
+ name: "Not found",
1483
+ title: "This page isn\u2019t here.",
1484
+ detail: "The link may be old, or the address mistyped."
1485
+ },
1486
+ 500: {
1487
+ name: "Server error",
1488
+ title: "Something broke on our side.",
1489
+ detail: "Try again in a moment."
1490
+ }
1491
+ };
1492
+ function ErrorPage({
1493
+ code = 404,
1494
+ title,
1495
+ detail,
1496
+ actions,
1497
+ home = "/",
1498
+ art,
1499
+ className
1500
+ }) {
1501
+ const words = WORDS[code] ?? (code >= 500 ? WORDS[500] : WORDS[404]);
1502
+ const server = code >= 500;
1503
+ return /* @__PURE__ */ jsx(Section, { space: "none", className: cn("flex min-h-[min(40rem,72dvh)] items-center py-16 md:py-24", className), children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 items-center gap-12 md:grid-cols-12", children: [
1504
+ /* @__PURE__ */ jsxs("div", { className: "flex max-w-[40rem] flex-col items-start gap-6 md:col-span-7", children: [
1505
+ /* @__PURE__ */ jsxs("p", { className: "oca-eyebrow oca-enter", children: [
1506
+ /* @__PURE__ */ jsx("span", { className: "oca-tabular", children: code }),
1507
+ " \xB7 ",
1508
+ WORDS[code]?.name ?? (server ? "Error" : "Not available")
1509
+ ] }),
1510
+ /* @__PURE__ */ jsx("h1", { className: "oca-display-2 oca-enter [--enter-delay:70ms]", children: title ?? words.title }),
1511
+ /* @__PURE__ */ jsx("p", { className: "oca-lead oca-enter [--enter-delay:150ms]", children: detail ?? words.detail }),
1512
+ /* @__PURE__ */ jsx("div", { className: "oca-enter flex flex-wrap gap-3 [--enter-delay:230ms]", children: actions ?? /* @__PURE__ */ jsxs(Fragment, { children: [
1513
+ server ? /* @__PURE__ */ jsx(Button, { onClick: () => window.location.reload(), children: "Try again" }) : null,
1514
+ /* @__PURE__ */ jsx(Button, { asChild: true, variant: server ? "secondary" : "primary", children: /* @__PURE__ */ jsx(Link, { href: home, children: "Go home" }) })
1515
+ ] }) })
1516
+ ] }),
1517
+ 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
1518
+ ] }) });
1519
+ }
1520
+ function IsoCheck({ size = 360, settle = false, shadow = true, tilt = false, title, className }) {
1521
+ const ref = useRef(null);
1522
+ useEffect(() => {
1523
+ const el = ref.current;
1524
+ if (!el || !tilt || window.matchMedia("(prefers-reduced-motion: reduce)").matches) return;
1525
+ let raf = 0;
1526
+ let tx = 0;
1527
+ let ty = 0;
1528
+ let x = 0;
1529
+ let y = 0;
1530
+ const step = () => {
1531
+ x += (tx - x) * 0.08;
1532
+ y += (ty - y) * 0.08;
1533
+ el.style.setProperty("--rx", `${(-y * 10).toFixed(2)}deg`);
1534
+ el.style.setProperty("--ry", `${(x * 14).toFixed(2)}deg`);
1535
+ raf = Math.abs(tx - x) + Math.abs(ty - y) > 1e-3 ? requestAnimationFrame(step) : 0;
1536
+ };
1537
+ const move = (e) => {
1538
+ const b = el.getBoundingClientRect();
1539
+ tx = Math.max(-1, Math.min(1, (e.clientX - (b.left + b.width / 2)) / (window.innerWidth / 2)));
1540
+ ty = Math.max(-1, Math.min(1, (e.clientY - (b.top + b.height / 2)) / (window.innerHeight / 2)));
1541
+ if (!raf) raf = requestAnimationFrame(step);
1542
+ };
1543
+ window.addEventListener("pointermove", move, { passive: true });
1544
+ return () => {
1545
+ cancelAnimationFrame(raf);
1546
+ window.removeEventListener("pointermove", move);
1547
+ };
1548
+ }, [tilt]);
1549
+ return /* @__PURE__ */ jsxs(
1550
+ "div",
1551
+ {
1552
+ ref,
1553
+ className: cn("relative inline-block", settle && "oca-animate-settle", className),
1554
+ style: { width: size, perspective: tilt ? 900 : void 0 },
1555
+ children: [
1556
+ tilt ? /* @__PURE__ */ jsx(
1557
+ "div",
1558
+ {
1559
+ "aria-hidden": true,
1560
+ 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",
1561
+ style: { background: "radial-gradient(closest-side, rgb(255 140 70 / 0.35), transparent)" }
1562
+ }
1563
+ ) : null,
1564
+ /* @__PURE__ */ jsx(
1565
+ "div",
1566
+ {
1567
+ className: "relative z-10 transition-transform duration-300 ease-out",
1568
+ style: tilt ? { transform: "rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg))", transformStyle: "preserve-3d" } : void 0,
1569
+ children: /* @__PURE__ */ jsx(Mark, { size, title, className: "block" })
1570
+ }
1571
+ ),
1572
+ shadow ? /* @__PURE__ */ jsx(
1573
+ "div",
1574
+ {
1575
+ "aria-hidden": true,
1576
+ className: "absolute left-[8%] right-[8%] rounded-[50%] opacity-60 blur-xl",
1577
+ style: { height: size * 0.08, bottom: -size * 0.04, background: "rgb(234 88 11 / 0.18)" }
1578
+ }
1579
+ ) : null
1580
+ ]
1581
+ }
1582
+ );
1583
+ }
1584
+ var GroupName = createContext(void 0);
1585
+ function Accordion({
1586
+ single = false,
1587
+ children,
1588
+ className
1589
+ }) {
1590
+ const name = useId();
1591
+ return /* @__PURE__ */ jsx(GroupName.Provider, { value: single ? name : void 0, children: /* @__PURE__ */ jsx("div", { className: cn("divide-y divide-border overflow-hidden rounded-[1.25rem] border border-border bg-card", className), children }) });
1592
+ }
1593
+ function AccordionItem({
1594
+ title,
1595
+ children,
1596
+ defaultOpen = false,
1597
+ id,
1598
+ className
1599
+ }) {
1600
+ const name = useContext(GroupName);
1601
+ return /* @__PURE__ */ jsxs("details", { id, name, open: defaultOpen || void 0, className: cn("group scroll-mt-24", className), children: [
1602
+ /* @__PURE__ */ jsxs(
1603
+ "summary",
1604
+ {
1605
+ className: cn(
1606
+ "flex min-h-14 cursor-pointer list-none items-center justify-between gap-4 px-5 py-4 text-[1rem] font-medium leading-snug md:px-6",
1607
+ // Inside the card's clip, so the ring is drawn within the row.
1608
+ "transition-colors hover:bg-accent/60 focus-visible:outline-offset-[-2px] [&::-webkit-details-marker]:hidden"
1609
+ ),
1610
+ children: [
1611
+ title,
1612
+ /* @__PURE__ */ jsx(
1613
+ ChevronDown,
1614
+ {
1615
+ "aria-hidden": true,
1616
+ className: "size-4 shrink-0 text-muted-foreground transition-transform duration-200 group-open:rotate-180"
1617
+ }
1618
+ )
1619
+ ]
1620
+ }
1621
+ ),
1622
+ /* @__PURE__ */ jsx("div", { className: "oca-body px-5 pb-5 text-[0.9375rem] md:px-6 md:pb-6", children })
1623
+ ] });
1624
+ }
1625
+ function SectionHeading({
1626
+ eyebrow,
1627
+ title,
1628
+ lead,
1629
+ id,
1630
+ onInk = false,
1631
+ level = 2,
1632
+ as = "h2",
1633
+ align = "start",
1634
+ reveal = true,
1635
+ className
1636
+ }) {
1637
+ return /* @__PURE__ */ jsxs(SectionIntro, { align, reveal, className: cn("max-w-3xl gap-4 md:gap-4", className), children: [
1638
+ eyebrow ? /* @__PURE__ */ jsx(Eyebrow, { onInk, children: eyebrow }) : null,
1639
+ /* @__PURE__ */ jsx(Display, { level, as, id, className: "scroll-mt-24", children: title }),
1640
+ lead ? /* @__PURE__ */ jsx("p", { className: cn("oca-lead", onInk && "text-oca-ink-muted"), children: lead }) : null
1641
+ ] });
1642
+ }
1643
+ function FactBlock({
1644
+ id,
1645
+ title,
1646
+ description,
1647
+ aside,
1648
+ children,
1649
+ className
1650
+ }) {
1651
+ return /* @__PURE__ */ jsxs("section", { id, className: cn("flex scroll-mt-24 flex-col gap-6", className), children: [
1652
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3 md:flex-row md:items-end md:justify-between md:gap-8", children: [
1653
+ /* @__PURE__ */ jsxs("div", { className: "flex max-w-[44rem] flex-col gap-3", children: [
1654
+ /* @__PURE__ */ jsx("h2", { className: "oca-display-3", children: title }),
1655
+ description ? /* @__PURE__ */ jsx("div", { className: "oca-body text-[1.0625rem]", children: description }) : null
1656
+ ] }),
1657
+ aside ? /* @__PURE__ */ jsx("div", { className: "flex shrink-0 flex-wrap gap-x-5 gap-y-2 text-[0.9375rem]", children: aside }) : null
1658
+ ] }),
1659
+ children
1660
+ ] });
1661
+ }
1662
+ function FactRows({
1663
+ rows,
1664
+ columns = 1,
1665
+ label,
1666
+ className
1667
+ }) {
1668
+ return /* @__PURE__ */ jsx("ul", { "aria-label": label, className: cn("divide-y divide-border rounded-[1.25rem] border border-border bg-card", className), children: rows.map((r) => /* @__PURE__ */ jsxs("li", { className: "flex flex-col gap-5 px-5 py-6 md:px-8 md:py-7", children: [
1669
+ /* @__PURE__ */ jsxs("div", { className: "flex items-baseline justify-between gap-x-6", children: [
1670
+ /* @__PURE__ */ jsx("h3", { className: "oca-title min-w-0 text-pretty", children: r.title }),
1671
+ r.figure ? /* @__PURE__ */ jsx("span", { className: "oca-tabular shrink-0 whitespace-nowrap text-[1.75rem] leading-none tracking-[-0.02em]", children: r.figure }) : null
1672
+ ] }),
1673
+ /* @__PURE__ */ jsx("dl", { className: columns === 2 ? "grid grid-cols-1 gap-x-10 gap-y-4 md:grid-cols-2" : "flex flex-col gap-4", children: r.fields.map((f, i) => /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col gap-1", children: [
1674
+ /* @__PURE__ */ jsx("dt", { className: "text-[0.875rem] font-medium text-muted-foreground", children: f.label }),
1675
+ /* @__PURE__ */ jsx("dd", { className: "break-words text-[1rem] leading-relaxed", children: f.value })
1676
+ ] }, i)) })
1677
+ ] }, r.key)) });
1678
+ }
1679
+ function EndpointList({ items, label, className }) {
1680
+ return /* @__PURE__ */ jsx("ul", { "aria-label": label, className: cn("divide-y divide-border rounded-[1.25rem] border border-border bg-card", className), children: items.map((a) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(
1681
+ "a",
1682
+ {
1683
+ href: a.href,
1684
+ target: "_blank",
1685
+ rel: "noreferrer",
1686
+ className: "flex flex-col gap-1 px-5 py-3.5 transition-colors hover:bg-accent/60 sm:flex-row sm:items-baseline sm:justify-between sm:gap-6",
1687
+ children: [
1688
+ /* @__PURE__ */ jsx("code", { className: "break-all text-[0.875rem] text-foreground", children: a.label ?? a.href }),
1689
+ /* @__PURE__ */ jsxs("span", { className: "text-[0.875rem] text-muted-foreground sm:text-right", children: [
1690
+ a.description,
1691
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: " (opens in a new tab)" })
1692
+ ] })
1693
+ ]
1694
+ }
1695
+ ) }, a.href)) });
1696
+ }
1697
+ function ProofStrip({ items, className }) {
1698
+ return /* @__PURE__ */ jsx("div", { className: cn("border-y border-border", className), children: /* @__PURE__ */ jsx("ul", { className: "oca-container grid grid-cols-2 gap-x-6 gap-y-4 py-6 md:grid-cols-4", children: items.map((it, i) => /* @__PURE__ */ jsxs(
1699
+ "li",
1700
+ {
1701
+ className: "flex items-center gap-3 text-[0.9375rem] [&_svg]:size-[1.1rem] [&_svg]:shrink-0 [&_svg]:text-oca-accent-ink",
1702
+ children: [
1703
+ it.icon ? /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "flex", children: it.icon }) : null,
1704
+ it.label
1705
+ ]
1706
+ },
1707
+ i
1708
+ )) }) });
1709
+ }
1710
+ function Closing({
1711
+ title,
1712
+ lead,
1713
+ actions,
1714
+ art,
1715
+ className
1716
+ }) {
1717
+ return /* @__PURE__ */ jsx(Section, { className: cn("overflow-hidden", className), children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 items-center gap-12 md:grid-cols-12", children: [
1718
+ /* @__PURE__ */ jsxs(Reveal, { className: "flex flex-col items-start gap-8 md:col-span-7", children: [
1719
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-5", children: [
1720
+ /* @__PURE__ */ jsx("h2", { className: "oca-display-1 text-[clamp(2.5rem,1.5rem+4vw,5rem)] leading-[1]", children: title }),
1721
+ lead ? /* @__PURE__ */ jsx("p", { className: "oca-lead max-w-[34rem]", children: lead }) : null
1722
+ ] }),
1723
+ actions ? /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-3", children: actions }) : null
1724
+ ] }),
1725
+ art !== null ? (
1726
+ // Room under the check on a phone, so its glow fades before the band ends.
1727
+ /* @__PURE__ */ jsx("div", { "aria-hidden": true, className: "flex justify-center max-md:pb-16 md:col-span-5", children: art ?? /* @__PURE__ */ jsx(IsoCheck, { size: 340, settle: true, tilt: true, className: "max-w-full" }) })
1728
+ ) : null
1729
+ ] }) });
1730
+ }
1731
+ function Faq({
1732
+ items,
1733
+ className
1734
+ }) {
1735
+ 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)) });
1736
+ }
1737
+ var LINK = "text-foreground underline decoration-foreground/35 underline-offset-4 transition-colors hover:decoration-foreground";
1738
+ function TextLink({
1739
+ href,
1740
+ children,
1741
+ external,
1742
+ className
1743
+ }) {
1744
+ const internal = href.startsWith("/") && !href.startsWith("/api/") && !href.startsWith("/.well-known/");
1745
+ const offsite = external ?? /^https?:\/\//.test(href);
1746
+ if (internal && !offsite) {
1747
+ return /* @__PURE__ */ jsx(Link, { href, className: cn(LINK, className), children });
1748
+ }
1749
+ return /* @__PURE__ */ jsxs("a", { href, className: cn(LINK, className), ...offsite ? { target: "_blank", rel: "noreferrer" } : {}, children: [
1750
+ children,
1751
+ offsite ? /* @__PURE__ */ jsx("span", { className: "sr-only", children: " (opens in a new tab)" }) : null
1752
+ ] });
1753
+ }
1754
+ var PROPER = {
1755
+ kyc: "KYC",
1756
+ pii: "PII",
1757
+ ccpa: "CCPA",
1758
+ cpra: "CPRA",
1759
+ gdpr: "GDPR",
1760
+ uk: "UK",
1761
+ eu: "EU",
1762
+ california: "California",
1763
+ europe: "Europe",
1764
+ united: "United",
1765
+ kingdom: "Kingdom"
1766
+ };
1767
+ function headingCase(text) {
1768
+ const words = text.replace(/\b[a-z]+\b/g, (w) => PROPER[w] ?? w);
1769
+ if (/^orangecheck\b/.test(words)) return `OrangeCheck${words.slice("orangecheck".length)}`;
1770
+ return words.length === 0 ? words : words[0].toUpperCase() + words.slice(1);
1771
+ }
1772
+ function sentencesCase(text) {
1773
+ return text.split(/(?<=[.!?])\s+/).map((s) => headingCase(s)).join(" ");
1774
+ }
1775
+ function openSentence(text) {
1776
+ const first = /^\S+/.exec(text)?.[0] ?? "";
1777
+ if (!/^[a-z][a-z'’-]*,?$/.test(first)) return text;
1778
+ return text[0].toUpperCase() + text.slice(1);
1779
+ }
1780
+ var INLINE = /(\*\*[^*]+\*\*|`[^`]+`|\[[^\]]+\]\([^)]+\))/g;
1781
+ var LINK2 = /^\[([^\]]+)\]\(([^)]+)\)$/;
1782
+ function Inline({ text }) {
1783
+ return /* @__PURE__ */ jsx(Fragment, { children: text.split(INLINE).map((part, i) => {
1784
+ if (!part) return null;
1785
+ if (part.startsWith("**") && part.endsWith("**") && part.length > 4) {
1786
+ return /* @__PURE__ */ jsx("strong", { children: /* @__PURE__ */ jsx(Inline, { text: part.slice(2, -2) }) }, i);
1787
+ }
1788
+ if (part.startsWith("`") && part.endsWith("`") && part.length > 2) return /* @__PURE__ */ jsx("code", { children: part.slice(1, -1) }, i);
1789
+ const link = LINK2.exec(part);
1790
+ if (link) {
1791
+ return /* @__PURE__ */ jsx(TextLink, { href: link[2] ?? "", children: link[1] }, i);
1792
+ }
1793
+ return /* @__PURE__ */ jsx(Fragment$1, { children: part }, i);
1794
+ }) });
1795
+ }
1796
+ function BlockView({ block }) {
1797
+ switch (block.kind) {
1798
+ case "para":
1799
+ return /* @__PURE__ */ jsx(Fragment, { children: block.text.split(/\n{2,}/).map((para, i) => /* @__PURE__ */ jsx("p", { children: /* @__PURE__ */ jsx(Inline, { text: para }) }, i)) });
1800
+ case "subhead":
1801
+ return /* @__PURE__ */ jsx("h3", { children: /* @__PURE__ */ jsx(Inline, { text: headingCase(block.text) }) });
1802
+ case "bullets":
1803
+ return /* @__PURE__ */ jsx("ul", { children: block.items.map(
1804
+ (item, i) => typeof item === "string" ? /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(Inline, { text: item }) }, i) : /* @__PURE__ */ jsxs("li", { children: [
1805
+ /* @__PURE__ */ jsxs("strong", { children: [
1806
+ headingCase(item.k),
1807
+ "."
1808
+ ] }),
1809
+ " ",
1810
+ /* @__PURE__ */ jsx(Inline, { text: openSentence(item.v) })
1811
+ ] }, i)
1812
+ ) });
1813
+ case "callout":
1814
+ return /* @__PURE__ */ jsx("div", { className: "not-prose my-6", children: /* @__PURE__ */ jsx(Notice, { tone: block.emphatic ? "brand" : "neutral", children: /* @__PURE__ */ jsx(Inline, { text: block.text }) }) });
1815
+ case "stub":
1816
+ return /* @__PURE__ */ jsx("div", { className: "not-prose my-6", children: /* @__PURE__ */ jsx(Notice, { tone: "brand", title: "Pending counsel review", children: /* @__PURE__ */ jsx(Inline, { text: block.text }) }) });
1817
+ }
1818
+ }
1819
+ function LegalDocument({ doc, className }) {
1820
+ return /* @__PURE__ */ jsx(
1821
+ DocLayout,
1822
+ {
1823
+ className,
1824
+ header: /* @__PURE__ */ jsx(
1825
+ DocHeader,
1826
+ {
1827
+ eyebrow: headingCase(doc.eyebrow),
1828
+ title: doc.title,
1829
+ lead: doc.description,
1830
+ meta: `Effective ${doc.effective} \xB7 last updated ${doc.updated}`
1831
+ }
1832
+ ),
1833
+ toc: doc.sections.map((s) => ({ id: s.id, label: headingCase(s.heading) })),
1834
+ children: /* @__PURE__ */ jsx("article", { className: "min-w-0", children: /* @__PURE__ */ jsxs(Prose, { children: [
1835
+ doc.preamble?.map((b, i) => /* @__PURE__ */ jsx(BlockView, { block: b }, i)),
1836
+ doc.sections.map((s) => /* @__PURE__ */ jsxs("section", { children: [
1837
+ /* @__PURE__ */ jsxs("h2", { id: s.id, className: "scroll-mt-24", children: [
1838
+ s.num ? /* @__PURE__ */ jsxs("span", { className: "oca-tabular text-muted-foreground", children: [
1839
+ s.num,
1840
+ " "
1841
+ ] }) : null,
1842
+ headingCase(s.heading)
1843
+ ] }),
1844
+ s.hint ? /* @__PURE__ */ jsx("p", { className: "text-[0.9375rem]", children: headingCase(s.hint) }) : null,
1845
+ s.blocks.map((b, i) => /* @__PURE__ */ jsx(BlockView, { block: b }, i))
1846
+ ] }, s.id)),
1847
+ doc.summary ? /* @__PURE__ */ jsxs("p", { className: "mt-14 border-t border-border pt-6 text-[0.9375rem]", children: [
1848
+ /* @__PURE__ */ jsx("strong", { children: "In short." }),
1849
+ " ",
1850
+ sentencesCase(doc.summary.replace(/^summary:\s*/i, ""))
1851
+ ] }) : null
1852
+ ] }) })
1853
+ }
1854
+ );
1855
+ }
1856
+
1857
+ // src/family/index.ts
1858
+ var OCHK_IO = "https://ochk.io";
1859
+ var DOCS_HREF = `${OCHK_IO}/docs`;
1860
+ function protocol(slug, verb, line, kinds) {
1861
+ return {
1862
+ slug,
1863
+ label: slug,
1864
+ href: `${OCHK_IO}/${slug}`,
1865
+ group: "protocol",
1866
+ line,
1867
+ status: "live",
1868
+ verb,
1869
+ pageHref: `${OCHK_IO}/${slug}`,
1870
+ toolHref: `https://${slug}.ochk.io`,
1871
+ specHref: `https://github.com/orangecheck/oc-${slug}-protocol`,
1872
+ kinds
1873
+ };
1874
+ }
1875
+ var PROTOCOLS = [
1876
+ protocol("attest", "identity", "Show that an address holds bitcoin, and for how long.", "30078"),
1877
+ protocol("lock", "confidentiality", "Encrypt to a Bitcoin address, so only its holder can open it.", "30078"),
1878
+ protocol("vote", "legitimacy", "Polls weighed in sats, that anyone can tally.", "30080\u201330082"),
1879
+ protocol("stamp", "provenance", "Prove who signed something, and when.", "30083"),
1880
+ protocol("agent", "authority", "Give software scoped, revocable permission to act for you.", "30083\u201330086"),
1881
+ protocol("pledge", "commitment", "Make a promise with bitcoin behind it, on a public record.", "30078")
1882
+ ];
1883
+ var PROTOCOL_ORDER = PROTOCOLS.map((p) => p.slug);
1884
+ var FAMILY = [
1885
+ {
1886
+ slug: "home",
1887
+ label: "ochk.io",
1888
+ href: OCHK_IO,
1889
+ group: "orangecheck",
1890
+ line: "The open protocols, and the company behind them.",
1891
+ status: "live"
1892
+ },
1893
+ {
1894
+ slug: "me",
1895
+ label: "ochk.app",
1896
+ href: "https://ochk.app",
1897
+ group: "orangecheck",
1898
+ line: "One account, with Bitcoin behind it.",
1899
+ status: "testing"
1900
+ },
1901
+ {
1902
+ slug: "docs",
1903
+ label: "docs",
1904
+ href: DOCS_HREF,
1905
+ group: "orangecheck",
1906
+ line: "Specs, SDKs and guides for every protocol.",
1907
+ status: "live"
1908
+ },
1909
+ ...PROTOCOLS,
1910
+ {
1911
+ slug: "vault",
1912
+ label: "vault",
1913
+ href: "https://vault.ochk.io",
1914
+ group: "app",
1915
+ line: "A password manager, encrypted in your browser.",
1916
+ status: "live",
1917
+ protocols: ["lock"]
1918
+ },
1919
+ {
1920
+ slug: "chat",
1921
+ label: "chat",
1922
+ href: "https://chat.ochk.io",
1923
+ group: "app",
1924
+ line: "Messages only the holder of a Bitcoin address can read.",
1925
+ status: "testing",
1926
+ protocols: ["lock"]
1927
+ },
1928
+ {
1929
+ slug: "cosign",
1930
+ label: "cosign",
1931
+ href: "https://cosign.ochk.io",
1932
+ group: "app",
1933
+ line: "Builders find co-founders and backers.",
1934
+ status: "testing",
1935
+ protocols: ["attest"]
1936
+ },
1937
+ {
1938
+ slug: "me-demo",
1939
+ // "demo", not the made-up app's own name, so nobody takes it for ours.
1940
+ label: "demo",
1941
+ href: "https://me-demo.ochk.io",
1942
+ group: "app",
1943
+ line: "Lumen Notes, a made-up app that signs in with orangecheck.",
1944
+ status: "live"
1945
+ },
1946
+ {
1947
+ slug: "globe",
1948
+ label: "globe",
1949
+ href: "https://globe.ochk.io",
1950
+ group: "public-good",
1951
+ line: "The Bitcoin network, live, on a globe.",
1952
+ status: "live"
1953
+ },
1954
+ {
1955
+ slug: "btc",
1956
+ label: "btc",
1957
+ href: "https://btc.ochk.io",
1958
+ group: "public-good",
1959
+ line: "A free desk for reading the Bitcoin market.",
1960
+ status: "live"
1961
+ }
1962
+ ];
1963
+ var BY_SLUG = new Map(FAMILY.map((s) => [s.slug, s]));
1964
+ function protocolSite(slug) {
1965
+ return BY_SLUG.get(slug);
1966
+ }
1967
+ [
1968
+ {
1969
+ href: `${OCHK_IO}/protocols`,
1970
+ label: "Protocols",
1971
+ children: PROTOCOLS.map((p) => ({ href: p.pageHref, label: p.label, description: p.line }))
1972
+ },
1973
+ { href: `${OCHK_IO}/apps`, label: "Apps" },
1974
+ { href: DOCS_HREF, label: "Docs" },
1975
+ { href: `${OCHK_IO}/trust`, label: "Trust" },
1976
+ { href: `${OCHK_IO}/about`, label: "About" }
1977
+ ];
1978
+ var WORD = {
1979
+ live: "Live",
1980
+ testing: "In testing",
1981
+ "not-yet": "Not yet",
1982
+ paused: "Paused",
1983
+ good: "Good",
1984
+ caution: "Caution",
1985
+ refused: "Refused"
1986
+ };
1987
+ var TONE2 = {
1988
+ live: "success",
1989
+ testing: "brand",
1990
+ "not-yet": "muted",
1991
+ paused: "muted",
1992
+ good: "success",
1993
+ caution: "brand",
1994
+ refused: "danger"
1995
+ };
1996
+ function StatusBadge({ status, className, ...props }) {
1997
+ return /* @__PURE__ */ jsx(Badge, { tone: TONE2[status], "data-status": status, className: cn(className), ...props, children: WORD[status] });
1998
+ }
1999
+ 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";
2000
+ var STRETCH = 'outline-none after:absolute after:inset-0 after:rounded-[1.25rem] after:content-[""]';
2001
+ var pad2 = (n) => String(n + 1).padStart(2, "0");
2002
+ function ProtocolGrid({
2003
+ protocols = PROTOCOL_ORDER,
2004
+ link = "page",
2005
+ className
2006
+ }) {
2007
+ 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) => {
2008
+ const p = protocolSite(slug);
2009
+ const i = PROTOCOL_ORDER.indexOf(slug);
2010
+ return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs("div", { className: cn(CARD, "gap-4"), children: [
2011
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3", children: [
2012
+ /* @__PURE__ */ jsxs("span", { className: "oca-numeral", children: [
2013
+ pad2(i),
2014
+ " ",
2015
+ /* @__PURE__ */ jsx("span", { className: "ml-1.5 capitalize", children: p.verb })
2016
+ ] }),
2017
+ p.status !== "live" ? /* @__PURE__ */ jsx(StatusBadge, { status: p.status }) : null
2018
+ ] }),
2019
+ /* @__PURE__ */ jsx("h3", { className: "oca-display-3", children: /* @__PURE__ */ jsx("a", { href: link === "tool" ? p.toolHref : p.pageHref, className: STRETCH, children: p.label }) }),
2020
+ /* @__PURE__ */ jsx("p", { className: "oca-body", children: p.line }),
2021
+ /* @__PURE__ */ jsxs("div", { className: "mt-auto flex items-center justify-between gap-3 pt-2 text-[0.875rem] text-muted-foreground", children: [
2022
+ /* @__PURE__ */ jsxs("span", { className: "oca-tabular", children: [
2023
+ "Nostr kind ",
2024
+ p.kinds
2025
+ ] }),
2026
+ /* @__PURE__ */ jsx(
2027
+ ArrowUpRight,
2028
+ {
2029
+ "aria-hidden": true,
2030
+ className: "size-4 transition-transform duration-200 group-hover:-translate-y-0.5 group-hover:translate-x-0.5 group-hover:text-foreground"
2031
+ }
2032
+ )
2033
+ ] })
2034
+ ] }) }, slug);
2035
+ }) });
2036
+ }
2037
+ function AppCard({ name, line, href, protocols = [], status = "live", className }) {
2038
+ return /* @__PURE__ */ jsxs("div", { className: cn(CARD, "gap-3", className), children: [
2039
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-3", children: [
2040
+ /* @__PURE__ */ jsx("h3", { className: "oca-title", children: /* @__PURE__ */ jsx("a", { href, className: STRETCH, children: name }) }),
2041
+ status !== "live" ? /* @__PURE__ */ jsx(StatusBadge, { status }) : null
2042
+ ] }),
2043
+ /* @__PURE__ */ jsx("p", { className: "oca-body text-[0.9375rem]", children: line }),
2044
+ /* @__PURE__ */ jsxs("div", { className: "mt-auto flex items-end justify-between gap-3 pt-3", children: [
2045
+ protocols.length > 0 ? /* @__PURE__ */ jsxs("p", { className: "flex flex-wrap items-center gap-1.5 text-[0.8125rem] text-muted-foreground", children: [
2046
+ "Shows",
2047
+ protocols.map((p) => /* @__PURE__ */ jsx(Badge, { tone: "muted", children: p }, p))
2048
+ ] }) : /* @__PURE__ */ jsx("span", {}),
2049
+ /* @__PURE__ */ jsxs("span", { className: "flex shrink-0 items-center gap-1 text-[0.875rem] text-muted-foreground transition-colors group-hover:text-foreground", children: [
2050
+ href.replace(/^https?:\/\//, ""),
2051
+ /* @__PURE__ */ jsx(ArrowUpRight, { "aria-hidden": true, className: "size-4" })
2052
+ ] })
2053
+ ] })
2054
+ ] });
2055
+ }
2056
+ function AppGrid({
2057
+ group = "app",
2058
+ sites,
2059
+ className
2060
+ }) {
2061
+ const list = sites ? sites.map((slug) => FAMILY.find((s) => s.slug === slug)).filter((s) => s !== void 0) : FAMILY.filter((s) => s.group === group);
2062
+ 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)) });
2063
+ }
2064
+ var fieldBase = [
2065
+ "w-full rounded-xl border border-input bg-card text-foreground placeholder:text-oca-subtle",
2066
+ "text-base md:text-[0.9375rem] outline-none transition-[border-color,box-shadow]",
2067
+ "focus:border-foreground/35 focus:ring-4 focus:ring-[color-mix(in_oklab,var(--oca-orange)_16%,transparent)]",
2068
+ "disabled:cursor-not-allowed disabled:opacity-55",
2069
+ "aria-[invalid=true]:border-destructive aria-[invalid=true]:focus:ring-[color-mix(in_oklab,var(--destructive)_14%,transparent)]"
2070
+ ];
2071
+ var Input = forwardRef(function Input2({ className, type = "text", ...props }, ref) {
2072
+ return /* @__PURE__ */ jsx("input", { ref, type, "data-ui": "input", className: cn(fieldBase, "h-11 px-3.5", className), ...props });
2073
+ });
2074
+ var Textarea = forwardRef(
2075
+ function Textarea2({ className, ...props }, ref) {
2076
+ return /* @__PURE__ */ jsx(
2077
+ "textarea",
2078
+ {
2079
+ ref,
2080
+ "data-ui": "textarea",
2081
+ className: cn(fieldBase, "min-h-28 px-3.5 py-3 leading-relaxed", className),
2082
+ ...props
2083
+ }
2084
+ );
2085
+ }
2086
+ );
2087
+ var Label = forwardRef(function Label2({ className, ...props }, ref) {
2088
+ return /* @__PURE__ */ jsx(
2089
+ LabelPrimitive.Root,
2090
+ {
2091
+ ref,
2092
+ className: cn("text-sm font-medium leading-none text-foreground", className),
2093
+ ...props
2094
+ }
2095
+ );
2096
+ });
2097
+ function Field({ label, hint, optional, error, children, className, hideLabel, action }) {
2098
+ const id = useId();
2099
+ const hintId = hint ? `${id}-hint` : void 0;
2100
+ const errorId = error ? `${id}-error` : void 0;
2101
+ const describedBy = [hintId, errorId].filter(Boolean).join(" ") || void 0;
2102
+ const control = isValidElement(children) ? cloneElement(children, {
2103
+ id,
2104
+ "aria-describedby": describedBy,
2105
+ "aria-invalid": error ? true : void 0
2106
+ }) : children;
2107
+ const hintNode = hint ? /* @__PURE__ */ jsx("p", { id: hintId, className: "text-[0.8125rem] leading-snug text-muted-foreground", children: hint }) : null;
2108
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-2", className), children: [
2109
+ /* @__PURE__ */ jsxs(Label, { htmlFor: id, className: hideLabel ? "sr-only" : "flex items-baseline gap-2", children: [
2110
+ label,
2111
+ optional ? /* @__PURE__ */ jsx("span", { className: "text-[0.8125rem] font-normal text-muted-foreground", children: "Optional" }) : null
2112
+ ] }),
2113
+ action ? (
2114
+ // The hint belongs to the input, so it sits under the input, not under the button.
2115
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3 sm:flex-row sm:items-start", children: [
2116
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-2 [&>input]:w-full", children: [
2117
+ control,
2118
+ hintNode
2119
+ ] }),
2120
+ /* @__PURE__ */ jsx("div", { className: "shrink-0", children: action })
2121
+ ] })
2122
+ ) : /* @__PURE__ */ jsxs(Fragment, { children: [
2123
+ control,
2124
+ hintNode
2125
+ ] }),
2126
+ error ? /* @__PURE__ */ jsx("p", { id: errorId, role: "alert", className: "text-[0.8125rem] leading-snug text-destructive", children: error }) : null
2127
+ ] });
2128
+ }
2129
+ forwardRef(function SelectTrigger2({ className, children, ...props }, ref) {
2130
+ return /* @__PURE__ */ jsxs(
2131
+ SelectPrimitive.Trigger,
2132
+ {
2133
+ ref,
2134
+ className: cn(fieldBase, "flex h-11 items-center justify-between gap-2 px-3.5 text-left", className),
2135
+ ...props,
2136
+ children: [
2137
+ /* @__PURE__ */ jsx("span", { className: "truncate", children }),
2138
+ /* @__PURE__ */ jsx(SelectPrimitive.Icon, { asChild: true, children: /* @__PURE__ */ jsx(ChevronDown, { className: "size-4 shrink-0 text-muted-foreground" }) })
2139
+ ]
2140
+ }
2141
+ );
2142
+ });
2143
+ forwardRef(function SelectContent2({ className, children, position = "popper", ...props }, ref) {
2144
+ return /* @__PURE__ */ jsx(SelectPrimitive.Portal, { children: /* @__PURE__ */ jsx(
2145
+ SelectPrimitive.Content,
2146
+ {
2147
+ ref,
2148
+ position,
2149
+ sideOffset: 6,
2150
+ className: cn(
2151
+ "oca-animate-fade z-50 max-h-[min(24rem,var(--radix-select-content-available-height))] min-w-[var(--radix-select-trigger-width)] overflow-hidden rounded-xl border border-border bg-popover p-1 text-popover-foreground shadow-lg",
2152
+ className
2153
+ ),
2154
+ ...props,
2155
+ children: /* @__PURE__ */ jsx(SelectPrimitive.Viewport, { children })
2156
+ }
2157
+ ) });
2158
+ });
2159
+ forwardRef(function SelectItem2({ className, children, ...props }, ref) {
2160
+ return /* @__PURE__ */ jsxs(
2161
+ SelectPrimitive.Item,
2162
+ {
2163
+ ref,
2164
+ className: cn(
2165
+ "relative flex h-10 cursor-default select-none items-center rounded-lg pl-3 pr-9 text-[0.9375rem] outline-none",
2166
+ "data-[highlighted]:bg-accent data-[disabled]:opacity-50",
2167
+ className
2168
+ ),
2169
+ ...props,
2170
+ children: [
2171
+ /* @__PURE__ */ jsx(SelectPrimitive.ItemText, { children }),
2172
+ /* @__PURE__ */ jsx(SelectPrimitive.ItemIndicator, { className: "absolute right-3", children: /* @__PURE__ */ jsx(Check, { className: "size-4" }) })
2173
+ ]
2174
+ }
2175
+ );
2176
+ });
2177
+ forwardRef(function Checkbox2({ className, ...props }, ref) {
2178
+ return /* @__PURE__ */ jsx(
2179
+ CheckboxPrimitive.Root,
2180
+ {
2181
+ ref,
2182
+ className: cn(
2183
+ "peer inline-flex size-5 shrink-0 items-center justify-center rounded-[6px] border border-input bg-card",
2184
+ "outline-none transition-colors focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
2185
+ "data-[state=checked]:border-primary data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
2186
+ "disabled:cursor-not-allowed disabled:opacity-50",
2187
+ className
2188
+ ),
2189
+ ...props,
2190
+ children: /* @__PURE__ */ jsx(CheckboxPrimitive.Indicator, { children: /* @__PURE__ */ jsx(Check, { className: "size-3.5", strokeWidth: 3 }) })
2191
+ }
2192
+ );
2193
+ });
2194
+ forwardRef(function Switch2({ className, ...props }, ref) {
2195
+ return /* @__PURE__ */ jsx(
2196
+ SwitchPrimitive.Root,
2197
+ {
2198
+ ref,
2199
+ className: cn(
2200
+ "peer inline-flex h-6 w-11 shrink-0 items-center rounded-full border border-transparent bg-input p-0.5",
2201
+ "outline-none transition-colors focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
2202
+ // The deep orange: the track is the state, so it must clear 3:1 on a card.
2203
+ "data-[state=checked]:bg-oca-orange-deep disabled:cursor-not-allowed disabled:opacity-50",
2204
+ className
2205
+ ),
2206
+ ...props,
2207
+ children: /* @__PURE__ */ jsx(SwitchPrimitive.Thumb, { className: "pointer-events-none block size-5 rounded-full bg-white shadow-sm transition-transform data-[state=checked]:translate-x-5" })
2208
+ }
2209
+ );
2210
+ });
2211
+ forwardRef(function RadioGroup2({ className, ...props }, ref) {
2212
+ return /* @__PURE__ */ jsx(RadioGroupPrimitive.Root, { ref, className: cn("grid gap-3", className), ...props });
2213
+ });
2214
+ forwardRef(function RadioGroupItem2({ className, ...props }, ref) {
2215
+ return /* @__PURE__ */ jsx(
2216
+ RadioGroupPrimitive.Item,
2217
+ {
2218
+ ref,
2219
+ className: cn(
2220
+ "inline-flex size-5 shrink-0 items-center justify-center rounded-full border border-input bg-card",
2221
+ "outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
2222
+ "data-[state=checked]:border-primary disabled:cursor-not-allowed disabled:opacity-50",
2223
+ className
2224
+ ),
2225
+ ...props,
2226
+ children: /* @__PURE__ */ jsx(RadioGroupPrimitive.Indicator, { className: "block size-2.5 rounded-full bg-primary" })
2227
+ }
2228
+ );
2229
+ });
2230
+ function ProtocolHero({
2231
+ protocol: protocol2,
2232
+ title,
2233
+ lead,
2234
+ actions,
2235
+ art,
2236
+ children,
2237
+ className
2238
+ }) {
2239
+ const p = protocolSite(protocol2);
2240
+ return /* @__PURE__ */ jsx(
2241
+ PageHero,
2242
+ {
2243
+ className,
2244
+ eyebrow: `Protocol \xB7 ${p.verb}`,
2245
+ title,
2246
+ lead,
2247
+ actions,
2248
+ art,
2249
+ children: p.status !== "live" || children ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-start gap-4", children: [
2250
+ p.status !== "live" ? /* @__PURE__ */ jsx(StatusBadge, { status: p.status }) : null,
2251
+ children
2252
+ ] }) : null
2253
+ }
2254
+ );
2255
+ }
2256
+ function ProtocolNav({
2257
+ current,
2258
+ link = "page",
2259
+ className
2260
+ }) {
2261
+ 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) => {
2262
+ const on = p.slug === current;
2263
+ return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
2264
+ "a",
2265
+ {
2266
+ href: link === "tool" ? p.toolHref : p.pageHref,
2267
+ "aria-current": on ? "page" : void 0,
2268
+ className: cn(
2269
+ "-mb-px inline-flex h-11 items-center border-b-2 text-[0.9375rem] transition-colors",
2270
+ on ? "border-foreground text-foreground" : "border-transparent text-muted-foreground hover:text-foreground"
2271
+ ),
2272
+ children: p.label
2273
+ }
2274
+ ) }, p.slug);
2275
+ }) }) }) });
2276
+ }
2277
+ function SpecCard({
2278
+ protocol: protocol2,
2279
+ version,
2280
+ license,
2281
+ vectors,
2282
+ size = "md",
2283
+ className
2284
+ }) {
2285
+ const p = protocolSite(protocol2);
2286
+ const repo = `oc-${p.slug}-protocol`;
2287
+ const facts = [
2288
+ ["Version", version],
2289
+ ...license ? [["Licence", license]] : [],
2290
+ ["Nostr kind", p.kinds],
2291
+ ...vectors !== void 0 ? [["Test vectors", String(vectors)]] : []
2292
+ ];
2293
+ if (size === "sm") {
2294
+ return /* @__PURE__ */ jsxs(
2295
+ "a",
2296
+ {
2297
+ href: p.specHref,
2298
+ className: cn(
2299
+ "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",
2300
+ className
2301
+ ),
2302
+ children: [
2303
+ /* @__PURE__ */ jsx("span", { className: "font-mono text-[0.8125rem] text-foreground", children: repo }),
2304
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: facts.map(([k, v]) => k === "Version" ? `v${v}` : k === "Nostr kind" ? `kind ${v}` : v).join(" \xB7 ") }),
2305
+ /* @__PURE__ */ jsxs("span", { className: "ml-auto flex items-center gap-1 text-muted-foreground group-hover:text-foreground", children: [
2306
+ "Read the spec ",
2307
+ /* @__PURE__ */ jsx(ArrowUpRight, { "aria-hidden": true, className: "size-4" })
2308
+ ] })
2309
+ ]
2310
+ }
2311
+ );
2312
+ }
2313
+ 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: [
2314
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-4", children: [
2315
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col gap-1.5", children: [
2316
+ /* @__PURE__ */ jsx("p", { className: "text-[0.875rem] text-muted-foreground", children: "The spec" }),
2317
+ /* @__PURE__ */ jsx("h3", { className: "oca-title break-all font-mono text-[1.0625rem] tracking-normal", children: repo })
2318
+ ] }),
2319
+ p.status !== "live" ? /* @__PURE__ */ jsx(StatusBadge, { status: p.status }) : null
2320
+ ] }),
2321
+ /* @__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: [
2322
+ /* @__PURE__ */ jsx("dt", { className: "text-[0.8125rem] text-muted-foreground", children: k }),
2323
+ /* @__PURE__ */ jsx("dd", { className: "oca-tabular text-[1.0625rem]", children: v })
2324
+ ] }, k)) }),
2325
+ /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Button, { asChild: true, variant: "secondary", size: "sm", children: /* @__PURE__ */ jsxs("a", { href: p.specHref, children: [
2326
+ "Read the spec ",
2327
+ /* @__PURE__ */ jsx(ArrowUpRight, { "aria-hidden": true })
2328
+ ] }) }) })
2329
+ ] });
2330
+ }
2331
+ function VerifyBox({
2332
+ action,
2333
+ param = "q",
2334
+ title,
2335
+ description,
2336
+ label = "Id, envelope or link",
2337
+ placeholder,
2338
+ hint,
2339
+ submitLabel = "Verify",
2340
+ multiline = false,
2341
+ onVerify,
2342
+ className
2343
+ }) {
2344
+ const [value, setValue] = useState("");
2345
+ const submit = (e) => {
2346
+ if (!onVerify) return;
2347
+ e.preventDefault();
2348
+ if (value.trim()) onVerify(value.trim());
2349
+ };
2350
+ const button = /* @__PURE__ */ jsx(Button, { type: "submit", className: multiline ? void 0 : "w-full sm:w-auto", children: submitLabel });
2351
+ return /* @__PURE__ */ jsxs(
2352
+ "form",
2353
+ {
2354
+ action,
2355
+ method: "get",
2356
+ onSubmit: submit,
2357
+ className: cn("flex flex-col gap-5 rounded-[1.25rem] border border-border bg-card p-6 md:p-8", className),
2358
+ children: [
2359
+ title || description ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
2360
+ title ? /* @__PURE__ */ jsx("h3", { className: "oca-title", children: title }) : null,
2361
+ description ? /* @__PURE__ */ jsx("p", { className: "oca-body text-[0.9375rem]", children: description }) : null
2362
+ ] }) : null,
2363
+ multiline ? /* @__PURE__ */ jsxs(Fragment, { children: [
2364
+ /* @__PURE__ */ jsx(Field, { label, hint, children: /* @__PURE__ */ jsx(
2365
+ Textarea,
2366
+ {
2367
+ name: param,
2368
+ required: true,
2369
+ value,
2370
+ onChange: (e) => setValue(e.target.value),
2371
+ placeholder,
2372
+ spellCheck: false,
2373
+ className: "min-h-32 font-mono text-base md:text-[0.8125rem]"
2374
+ }
2375
+ ) }),
2376
+ /* @__PURE__ */ jsx("div", { children: button })
2377
+ ] }) : /* @__PURE__ */ jsx(Field, { label, hint, action: button, children: /* @__PURE__ */ jsx(
2378
+ Input,
2379
+ {
2380
+ name: param,
2381
+ required: true,
2382
+ value,
2383
+ onChange: (e) => setValue(e.target.value),
2384
+ placeholder,
2385
+ spellCheck: false,
2386
+ autoComplete: "off",
2387
+ className: "font-mono text-base md:text-[0.875rem]"
2388
+ }
2389
+ ) })
2390
+ ]
2391
+ }
2392
+ );
2393
+ }
2394
+ var TINT = "bg-[color-mix(in_oklab,var(--oca-orange)_9%,var(--card))]";
2395
+ function ComparisonTable({
2396
+ columns,
2397
+ rows,
2398
+ label,
2399
+ propertyHeading = "Property",
2400
+ className
2401
+ }) {
2402
+ const wide = columns.length > 3;
2403
+ const grid = wide ? "lg:grid lg:grid-cols-[var(--oca-compare)]" : "md:grid md:grid-cols-[var(--oca-compare)]";
2404
+ const desk = wide ? "lg" : "md";
2405
+ const style = {
2406
+ // The argued-for column gets a little more room: its answers carry the page.
2407
+ "--oca-compare": ["minmax(0, 1.4fr)", ...columns.map((c) => c.highlight ? "minmax(0, 1.3fr)" : "minmax(0, 1fr)")].join(" ")
2408
+ };
2409
+ const ordered = [...columns].sort((a, b) => Number(Boolean(b.highlight)) - Number(Boolean(a.highlight)));
2410
+ return /* @__PURE__ */ jsxs("ul", { "aria-label": label, style, className: cn("divide-y divide-border rounded-[1.25rem] border border-border bg-card", className), children: [
2411
+ /* @__PURE__ */ jsxs(
2412
+ "li",
2413
+ {
2414
+ "aria-hidden": true,
2415
+ className: cn(
2416
+ "hidden gap-5 px-5 py-4 text-[0.875rem] font-medium text-muted-foreground",
2417
+ wide ? "lg:grid lg:px-8" : "md:grid md:px-8",
2418
+ grid
2419
+ ),
2420
+ children: [
2421
+ /* @__PURE__ */ jsx("span", { children: propertyHeading }),
2422
+ 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))
2423
+ ]
2424
+ }
2425
+ ),
2426
+ 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: [
2427
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col gap-1", children: [
2428
+ /* @__PURE__ */ jsx("span", { className: "oca-title-sm", children: r.label }),
2429
+ r.note ? /* @__PURE__ */ jsx("span", { className: "text-[0.875rem] leading-snug text-muted-foreground", children: r.note }) : null
2430
+ ] }),
2431
+ /* @__PURE__ */ jsx("div", { className: cn("grid grid-cols-2 gap-1", desk === "lg" ? "lg:contents" : "md:contents"), children: columns.map((c) => {
2432
+ return /* @__PURE__ */ jsxs(
2433
+ "div",
2434
+ {
2435
+ style: { "--oca-order": ordered.indexOf(c) },
2436
+ className: cn(
2437
+ // Two rows of the pair's grid (name, answer), so answers line up
2438
+ // across a pair even when one name wraps.
2439
+ "order-[var(--oca-order)] row-span-2 grid min-w-0 grid-rows-subgrid gap-1 rounded-xl px-3 py-2.5",
2440
+ 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",
2441
+ c.highlight ? cn(
2442
+ TINT,
2443
+ "col-span-2",
2444
+ 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"
2445
+ ) : desk === "lg" ? "lg:p-0" : "md:p-0"
2446
+ ),
2447
+ children: [
2448
+ /* @__PURE__ */ jsx(
2449
+ "span",
2450
+ {
2451
+ className: cn(
2452
+ "text-[0.8125rem]",
2453
+ c.highlight ? "text-oca-accent-ink" : "text-muted-foreground",
2454
+ desk === "lg" ? "lg:sr-only" : "md:sr-only"
2455
+ ),
2456
+ children: c.label
2457
+ }
2458
+ ),
2459
+ /* @__PURE__ */ jsx("span", { className: cn("text-[0.9375rem]", c.highlight && "font-medium"), children: r.values[c.key] ?? "\u2014" })
2460
+ ]
2461
+ },
2462
+ c.key
2463
+ );
2464
+ }) })
2465
+ ] }, ri))
2466
+ ] });
2467
+ }
2468
+ var CHECK = {
2469
+ ok: { word: "Passed", icon: /* @__PURE__ */ jsx(CircleCheck, {}), tone: "text-success" },
2470
+ fail: { word: "Failed", icon: /* @__PURE__ */ jsx(CircleX, {}), tone: "text-destructive" },
2471
+ pending: { word: "Pending", icon: /* @__PURE__ */ jsx(Clock, {}), tone: "text-oca-accent-ink" },
2472
+ skipped: { word: "Skipped", icon: /* @__PURE__ */ jsx(CircleMinus, {}), tone: "text-muted-foreground" },
2473
+ unchecked: { word: "Not checked", icon: /* @__PURE__ */ jsx(CircleDashed, {}), tone: "text-oca-subtle" }
2474
+ };
2475
+ function VerifyReport({
2476
+ verdict,
2477
+ title,
2478
+ summary,
2479
+ checks,
2480
+ facts,
2481
+ notChecked,
2482
+ actions,
2483
+ className
2484
+ }) {
2485
+ return /* @__PURE__ */ jsxs(
2486
+ "section",
2487
+ {
2488
+ "aria-label": "Verification result",
2489
+ className: cn("overflow-hidden rounded-[1.25rem] border border-border bg-card", className),
2490
+ children: [
2491
+ /* @__PURE__ */ jsxs("header", { className: "flex flex-col items-start gap-3 p-6 md:p-8", children: [
2492
+ /* @__PURE__ */ jsx(StatusBadge, { status: verdict }),
2493
+ /* @__PURE__ */ jsx("h3", { className: "oca-display-3", children: title }),
2494
+ summary ? /* @__PURE__ */ jsx("p", { className: "oca-body max-w-[40rem]", children: summary }) : null
2495
+ ] }),
2496
+ /* @__PURE__ */ jsx("ul", { "aria-label": "Checks", className: "divide-y divide-border border-t border-border", children: checks.map((c, i) => {
2497
+ const k = CHECK[c.state];
2498
+ return /* @__PURE__ */ jsxs("li", { className: "flex items-start gap-3 px-6 py-3.5 md:px-8", children: [
2499
+ /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: cn("mt-0.5 shrink-0 [&_svg]:size-[1.125rem]", k.tone), children: k.icon }),
2500
+ /* @__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: [
2501
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col gap-0.5", children: [
2502
+ /* @__PURE__ */ jsx("span", { className: "text-[0.9375rem]", children: c.label }),
2503
+ c.note ? /* @__PURE__ */ jsx("span", { className: "break-words text-[0.8125rem] leading-snug text-muted-foreground", children: c.note }) : null
2504
+ ] }),
2505
+ /* @__PURE__ */ jsx(
2506
+ "span",
2507
+ {
2508
+ className: cn(
2509
+ "shrink-0 text-[0.8125rem]",
2510
+ c.state === "fail" ? "text-destructive" : "text-muted-foreground"
2511
+ ),
2512
+ children: k.word
2513
+ }
2514
+ )
2515
+ ] })
2516
+ ] }, i);
2517
+ }) }),
2518
+ 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,
2519
+ 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: [
2520
+ /* @__PURE__ */ jsx("p", { className: "text-[0.875rem] font-medium", children: "What this did not check" }),
2521
+ /* @__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)) })
2522
+ ] }) : null,
2523
+ actions ? /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-3 border-t border-border px-6 py-5 md:px-8", children: actions }) : null
2524
+ ]
2525
+ }
2526
+ );
2527
+ }
2528
+ function SignMessage({
2529
+ lead,
2530
+ address,
2531
+ message,
2532
+ wallets,
2533
+ busy = false,
2534
+ error,
2535
+ submitLabel = "Confirm",
2536
+ secondary,
2537
+ onSignature,
2538
+ className
2539
+ }) {
2540
+ const [pasted, setPasted] = useState("");
2541
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-5", className), children: [
2542
+ lead ? /* @__PURE__ */ jsx("p", { className: "text-[0.9375rem] leading-relaxed", children: lead }) : null,
2543
+ wallets ? /* @__PURE__ */ jsxs(Fragment, { children: [
2544
+ /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2", children: wallets }),
2545
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 text-[0.8125rem] text-muted-foreground", children: [
2546
+ /* @__PURE__ */ jsx("span", { className: "h-px flex-1 bg-border" }),
2547
+ "or sign it in any wallet",
2548
+ /* @__PURE__ */ jsx("span", { className: "h-px flex-1 bg-border" })
2549
+ ] })
2550
+ ] }) : null,
2551
+ /* @__PURE__ */ jsx(CodeBlock, { code: message, caption: "Message to sign" }),
2552
+ /* @__PURE__ */ jsxs(
2553
+ "form",
2554
+ {
2555
+ className: "flex flex-col gap-4",
2556
+ onSubmit: (e) => {
2557
+ e.preventDefault();
2558
+ if (pasted.trim()) onSignature(pasted.trim());
2559
+ },
2560
+ children: [
2561
+ /* @__PURE__ */ jsx(
2562
+ Field,
2563
+ {
2564
+ label: "Signature",
2565
+ error,
2566
+ hint: /* @__PURE__ */ jsxs(Fragment, { children: [
2567
+ "From your wallet\u2019s \u201Csign message\u201D (BIP-322), signed by",
2568
+ " ",
2569
+ /* @__PURE__ */ jsx("span", { className: "break-all font-mono", children: address }),
2570
+ "."
2571
+ ] }),
2572
+ children: /* @__PURE__ */ jsx(
2573
+ Textarea,
2574
+ {
2575
+ value: pasted,
2576
+ onChange: (e) => setPasted(e.target.value),
2577
+ rows: 3,
2578
+ spellCheck: false,
2579
+ className: "min-h-24 font-mono text-base md:text-[0.8125rem]"
2580
+ }
2581
+ )
2582
+ }
2583
+ ),
2584
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-2", children: [
2585
+ /* @__PURE__ */ jsx(Button, { type: "submit", loading: busy, disabled: !pasted.trim(), children: submitLabel }),
2586
+ secondary
2587
+ ] })
2588
+ ]
2589
+ }
2590
+ )
2591
+ ] });
2592
+ }
1436
2593
 
1437
- export { Accent, ActivityList, BrowserFrame, CodeBlock, Container, CopyButton, DataTable, Display, DocHeader, DocLayout, EmptyLine, EmptyState, ErrorBoundary, Eyebrow, FloatChip, Footnote, HashChip, KeyValueList, Lead, LoadingBlock, Monogram, Notice, PackageCard, PageHeader, PageHero, PhoneFrame, ProgressSteps, Prose, Reveal, Sats, SatsFigure, ScrollStory, Section, SectionIntro, SplitBar, StatCard, StatGrid, StepGrid, Ticker, TruthTable, UsdApprox, monogramGround, monogramLetter, satsText, sectionVariants, useCopy, useInView };
2594
+ export { Accent, ActivityList, AppCard, AppGrid, BrowserFrame, Closing, CodeBlock, ComparisonTable, Container, CopyButton, DataTable, Display, DocHeader, DocLayout, EmptyLine, EmptyState, EndpointList, ErrorBoundary, ErrorPage, Eyebrow, FactBlock, FactRows, Faq, FloatChip, Footnote, HashChip, KeyValueList, Lead, LegalDocument, LoadingBlock, Monogram, Notice, PackageCard, PageHeader, PageHero, PhoneFrame, ProgressSteps, ProofStrip, Prose, ProtocolGrid, ProtocolHero, ProtocolNav, Reveal, Sats, SatsFigure, ScrollStory, Section, SectionHeading, SectionIntro, SignMessage, SpecCard, SplitBar, StatCard, StatGrid, StepGrid, TextLink, Ticker, TruthTable, UsdApprox, VerifyBox, VerifyReport, monogramGround, monogramLetter, satsText, sectionVariants, useCopy, useInView };
1438
2595
  //# sourceMappingURL=components.mjs.map
1439
2596
  //# sourceMappingURL=components.mjs.map