@orangecheck/app-design 1.4.0 → 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -4,6 +4,7 @@ import { forwardRef, useContext, createContext, useRef, useState, useCallback, u
4
4
  import { clsx } from 'clsx';
5
5
  import { extendTailwindMerge } from 'tailwind-merge';
6
6
  import * as SeparatorPrimitive from '@radix-ui/react-separator';
7
+ import { useTheme } from 'next-themes';
7
8
  import { Toaster as Toaster$1 } from 'sonner';
8
9
  export { toast } from 'sonner';
9
10
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
@@ -21,7 +22,6 @@ import * as TabsPrimitive from '@radix-ui/react-tabs';
21
22
  import QRCode from 'qrcode';
22
23
  import Link6 from 'next/link';
23
24
  import { useRouter } from 'next/compat/router';
24
- import { useTheme } from 'next-themes';
25
25
 
26
26
  // src/tokens/index.ts
27
27
  var APP_ATTRIBUTE = "data-oc-app";
@@ -173,10 +173,18 @@ function StatusDot({
173
173
  }
174
174
  );
175
175
  }
176
- function Toaster(props) {
176
+ var TOAST_COLOURS = {
177
+ "--normal-bg": "var(--popover)",
178
+ "--normal-text": "var(--popover-foreground)",
179
+ "--normal-border": "var(--border)"
180
+ };
181
+ function Toaster({ style, ...props }) {
182
+ const { resolvedTheme } = useTheme();
177
183
  return /* @__PURE__ */ jsx(
178
184
  Toaster$1,
179
185
  {
186
+ theme: resolvedTheme === "dark" ? "dark" : resolvedTheme === "light" ? "light" : "system",
187
+ style: { ...TOAST_COLOURS, ...style },
180
188
  position: "bottom-right",
181
189
  toastOptions: {
182
190
  classNames: {
@@ -3000,7 +3008,8 @@ function Well({
3000
3008
  lines,
3001
3009
  maxLines,
3002
3010
  diff,
3003
- lineNumbers
3011
+ lineNumbers,
3012
+ wrap
3004
3013
  }) {
3005
3014
  const foldable = maxLines !== void 0 && lines > maxLines + 2;
3006
3015
  const [open, setOpen] = useState(false);
@@ -3019,7 +3028,8 @@ function Well({
3019
3028
  "data-diff": diff ? "" : void 0,
3020
3029
  "data-line-numbers": lineNumbers ? "" : void 0,
3021
3030
  className: cn(
3022
- "oca-code w-max min-w-full py-4 font-mono text-[0.875rem] leading-[1.625] text-oca-ink-muted [font-variant-ligatures:none]",
3031
+ "oca-code py-4 font-mono text-[0.875rem] leading-[1.625] text-oca-ink-muted [font-variant-ligatures:none]",
3032
+ wrap ? "whitespace-pre-wrap break-all" : "w-max min-w-full",
3023
3033
  !lined && "px-5"
3024
3034
  ),
3025
3035
  children: lined ? /* @__PURE__ */ jsx("code", { className: "block", "data-lang": lang, dangerouslySetInnerHTML: { __html: html } }) : /* @__PURE__ */ jsx("code", { className: "block", "data-lang": lang, children })
@@ -3061,6 +3071,7 @@ function CodeBlock({
3061
3071
  highlight: marks,
3062
3072
  diff,
3063
3073
  lineNumbers,
3074
+ wrap,
3064
3075
  actions,
3065
3076
  className
3066
3077
  }) {
@@ -3092,6 +3103,7 @@ function CodeBlock({
3092
3103
  maxLines,
3093
3104
  diff: prepared ? prepared.diff : isDiff,
3094
3105
  lineNumbers,
3106
+ wrap,
3095
3107
  children
3096
3108
  }
3097
3109
  )
@@ -3556,6 +3568,169 @@ var ErrorBoundary = class extends Component {
3556
3568
  ) });
3557
3569
  }
3558
3570
  };
3571
+
3572
+ // src/family/index.ts
3573
+ var OCHK_IO = "https://ochk.io";
3574
+ var DOCS_HREF = `${OCHK_IO}/docs`;
3575
+ function protocol(slug, verb, line, kinds) {
3576
+ return {
3577
+ slug,
3578
+ label: slug,
3579
+ href: `${OCHK_IO}/${slug}`,
3580
+ group: "protocol",
3581
+ line,
3582
+ status: "live",
3583
+ verb,
3584
+ pageHref: `${OCHK_IO}/${slug}`,
3585
+ toolHref: `https://${slug}.ochk.io`,
3586
+ specHref: `https://github.com/orangecheck/oc-${slug}-protocol`,
3587
+ kinds
3588
+ };
3589
+ }
3590
+ var PROTOCOLS = [
3591
+ protocol("attest", "identity", "Show that an address holds bitcoin, and for how long.", "30078"),
3592
+ protocol("lock", "confidentiality", "Encrypt to a Bitcoin address, so only its holder can open it.", "30078"),
3593
+ protocol("vote", "legitimacy", "Polls weighed in sats, that anyone can tally.", "30080\u201330082"),
3594
+ protocol("stamp", "provenance", "Prove who signed something, and when.", "30083"),
3595
+ protocol("agent", "authority", "Give software scoped, revocable permission to act for you.", "30083\u201330086"),
3596
+ protocol("pledge", "commitment", "Make a promise with bitcoin behind it, on a public record.", "30078")
3597
+ ];
3598
+ var PROTOCOL_ORDER = PROTOCOLS.map((p) => p.slug);
3599
+ var FAMILY = [
3600
+ {
3601
+ slug: "home",
3602
+ label: "ochk.io",
3603
+ href: OCHK_IO,
3604
+ group: "orangecheck",
3605
+ line: "The open protocols, and the company behind them.",
3606
+ status: "live"
3607
+ },
3608
+ {
3609
+ slug: "me",
3610
+ label: "ochk.app",
3611
+ href: "https://ochk.app",
3612
+ group: "orangecheck",
3613
+ line: "One account, with Bitcoin behind it.",
3614
+ status: "testing"
3615
+ },
3616
+ {
3617
+ slug: "docs",
3618
+ label: "docs",
3619
+ href: DOCS_HREF,
3620
+ group: "orangecheck",
3621
+ line: "Specs, SDKs and guides for every protocol.",
3622
+ status: "live"
3623
+ },
3624
+ ...PROTOCOLS,
3625
+ {
3626
+ slug: "vault",
3627
+ label: "vault",
3628
+ href: "https://vault.ochk.io",
3629
+ group: "app",
3630
+ line: "A password manager, encrypted in your browser.",
3631
+ status: "live",
3632
+ protocols: ["lock"]
3633
+ },
3634
+ {
3635
+ slug: "chat",
3636
+ label: "chat",
3637
+ href: "https://chat.ochk.io",
3638
+ group: "app",
3639
+ line: "Messages only the holder of a Bitcoin address can read.",
3640
+ status: "testing",
3641
+ protocols: ["lock"]
3642
+ },
3643
+ {
3644
+ slug: "cosign",
3645
+ label: "cosign",
3646
+ href: "https://cosign.ochk.io",
3647
+ group: "app",
3648
+ line: "Builders find co-founders and backers.",
3649
+ status: "testing",
3650
+ // Signs in with an orangecheck account and a wallet; uses none of the six directly.
3651
+ protocols: []
3652
+ },
3653
+ {
3654
+ slug: "me-demo",
3655
+ // "demo", not the made-up app's own name, so nobody takes it for ours.
3656
+ label: "demo",
3657
+ href: "https://me-demo.ochk.io",
3658
+ group: "app",
3659
+ line: "Lumen Notes, a made-up app that signs in with orangecheck.",
3660
+ status: "live"
3661
+ },
3662
+ {
3663
+ slug: "globe",
3664
+ label: "globe",
3665
+ href: "https://globe.ochk.io",
3666
+ group: "public-good",
3667
+ line: "The Bitcoin network, live, on a globe.",
3668
+ status: "live"
3669
+ },
3670
+ {
3671
+ slug: "btc",
3672
+ label: "btc",
3673
+ href: "https://btc.ochk.io",
3674
+ group: "public-good",
3675
+ line: "A free desk for reading the Bitcoin market.",
3676
+ status: "live"
3677
+ }
3678
+ ];
3679
+ var FAMILY_GROUPS = [
3680
+ { id: "orangecheck", label: "orangecheck" },
3681
+ { id: "protocol", label: "Protocols" },
3682
+ { id: "app", label: "Apps" },
3683
+ { id: "public-good", label: "Public goods" }
3684
+ ];
3685
+ var BY_SLUG = new Map(FAMILY.map((s) => [s.slug, s]));
3686
+ function familySite(slug) {
3687
+ return BY_SLUG.get(slug);
3688
+ }
3689
+ function protocolSite(slug) {
3690
+ return BY_SLUG.get(slug);
3691
+ }
3692
+ function familyByGroup() {
3693
+ return FAMILY_GROUPS.map((g) => ({ ...g, sites: FAMILY.filter((s) => s.group === g.id) }));
3694
+ }
3695
+ var LEGAL_LINKS = [
3696
+ { href: `${OCHK_IO}/privacy`, label: "Privacy" },
3697
+ { href: `${OCHK_IO}/terms`, label: "Terms" },
3698
+ { href: `${OCHK_IO}/security`, label: "Security" },
3699
+ { href: `${OCHK_IO}/trademark`, label: "Trademarks" },
3700
+ { href: `${OCHK_IO}/contact`, label: "Contact" }
3701
+ ];
3702
+ var SELF_HOSTED_LEGAL_LINKS = [
3703
+ { href: "/privacy", label: "Privacy" },
3704
+ { href: "/terms", label: "Terms" },
3705
+ { href: "/security", label: "Security" },
3706
+ { href: `${OCHK_IO}/trademark`, label: "Trademarks" },
3707
+ { href: "/contact", label: "Contact" }
3708
+ ];
3709
+ var OCHK_IO_NAV = [
3710
+ {
3711
+ href: `${OCHK_IO}/protocols`,
3712
+ label: "Protocols",
3713
+ children: PROTOCOLS.map((p) => ({ href: p.pageHref, label: p.label, description: p.line }))
3714
+ },
3715
+ { href: `${OCHK_IO}/apps`, label: "Apps" },
3716
+ { href: DOCS_HREF, label: "Docs" },
3717
+ { href: `${OCHK_IO}/trust`, label: "Trust" },
3718
+ { href: `${OCHK_IO}/about`, label: "About" }
3719
+ ];
3720
+ var OCHK_IO_FOOTER = [
3721
+ {
3722
+ heading: "Company",
3723
+ links: [
3724
+ { href: `${OCHK_IO}/about`, label: "About" },
3725
+ { href: `${OCHK_IO}/trust`, label: "Trust" },
3726
+ { href: "https://github.com/orangecheck", label: "GitHub", external: true }
3727
+ ]
3728
+ }
3729
+ ];
3730
+ var SiteHomeContext = sharedContext("site-home", void 0);
3731
+ function useSiteHome() {
3732
+ return useContext(SiteHomeContext);
3733
+ }
3559
3734
  var WORDS = {
3560
3735
  404: {
3561
3736
  name: "Not found",
@@ -3573,10 +3748,13 @@ function ErrorPage({
3573
3748
  title,
3574
3749
  detail,
3575
3750
  actions,
3576
- home = "/",
3751
+ home,
3752
+ protocol: protocol2,
3577
3753
  art,
3578
3754
  className
3579
3755
  }) {
3756
+ const shellHome = useSiteHome();
3757
+ const homeHref = home ?? (protocol2 ? protocolSite(protocol2).pageHref : shellHome ?? OCHK_IO);
3580
3758
  const words = WORDS[code] ?? (code >= 500 ? WORDS[500] : WORDS[404]);
3581
3759
  const server = code >= 500;
3582
3760
  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: [
@@ -3590,7 +3768,7 @@ function ErrorPage({
3590
3768
  /* @__PURE__ */ jsx("p", { className: "oca-lead oca-enter [--enter-delay:150ms]", children: detail ?? words.detail }),
3591
3769
  /* @__PURE__ */ jsx("div", { className: "oca-enter flex flex-wrap gap-3 [--enter-delay:230ms]", children: actions ?? /* @__PURE__ */ jsxs(Fragment, { children: [
3592
3770
  server ? /* @__PURE__ */ jsx(Button, { onClick: () => window.location.reload(), children: "Try again" }) : null,
3593
- /* @__PURE__ */ jsx(Button, { asChild: true, variant: server ? "secondary" : "primary", children: /* @__PURE__ */ jsx(Link6, { href: home, children: "Go home" }) })
3771
+ /* @__PURE__ */ jsx(Button, { asChild: true, variant: server ? "secondary" : "primary", children: /* @__PURE__ */ jsx(Link6, { href: homeHref, children: "Go home" }) })
3594
3772
  ] }) })
3595
3773
  ] }),
3596
3774
  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
@@ -3836,165 +4014,6 @@ function LegalDocument({ doc, className }) {
3836
4014
  }
3837
4015
  );
3838
4016
  }
3839
-
3840
- // src/family/index.ts
3841
- var OCHK_IO = "https://ochk.io";
3842
- var DOCS_HREF = `${OCHK_IO}/docs`;
3843
- function protocol(slug, verb, line, kinds) {
3844
- return {
3845
- slug,
3846
- label: slug,
3847
- href: `${OCHK_IO}/${slug}`,
3848
- group: "protocol",
3849
- line,
3850
- status: "live",
3851
- verb,
3852
- pageHref: `${OCHK_IO}/${slug}`,
3853
- toolHref: `https://${slug}.ochk.io`,
3854
- specHref: `https://github.com/orangecheck/oc-${slug}-protocol`,
3855
- kinds
3856
- };
3857
- }
3858
- var PROTOCOLS = [
3859
- protocol("attest", "identity", "Show that an address holds bitcoin, and for how long.", "30078"),
3860
- protocol("lock", "confidentiality", "Encrypt to a Bitcoin address, so only its holder can open it.", "30078"),
3861
- protocol("vote", "legitimacy", "Polls weighed in sats, that anyone can tally.", "30080\u201330082"),
3862
- protocol("stamp", "provenance", "Prove who signed something, and when.", "30083"),
3863
- protocol("agent", "authority", "Give software scoped, revocable permission to act for you.", "30083\u201330086"),
3864
- protocol("pledge", "commitment", "Make a promise with bitcoin behind it, on a public record.", "30078")
3865
- ];
3866
- var PROTOCOL_ORDER = PROTOCOLS.map((p) => p.slug);
3867
- var FAMILY = [
3868
- {
3869
- slug: "home",
3870
- label: "ochk.io",
3871
- href: OCHK_IO,
3872
- group: "orangecheck",
3873
- line: "The open protocols, and the company behind them.",
3874
- status: "live"
3875
- },
3876
- {
3877
- slug: "me",
3878
- label: "ochk.app",
3879
- href: "https://ochk.app",
3880
- group: "orangecheck",
3881
- line: "One account, with Bitcoin behind it.",
3882
- status: "testing"
3883
- },
3884
- {
3885
- slug: "docs",
3886
- label: "docs",
3887
- href: DOCS_HREF,
3888
- group: "orangecheck",
3889
- line: "Specs, SDKs and guides for every protocol.",
3890
- status: "live"
3891
- },
3892
- ...PROTOCOLS,
3893
- {
3894
- slug: "vault",
3895
- label: "vault",
3896
- href: "https://vault.ochk.io",
3897
- group: "app",
3898
- line: "A password manager, encrypted in your browser.",
3899
- status: "live",
3900
- protocols: ["lock"]
3901
- },
3902
- {
3903
- slug: "chat",
3904
- label: "chat",
3905
- href: "https://chat.ochk.io",
3906
- group: "app",
3907
- line: "Messages only the holder of a Bitcoin address can read.",
3908
- status: "testing",
3909
- protocols: ["lock"]
3910
- },
3911
- {
3912
- slug: "cosign",
3913
- label: "cosign",
3914
- href: "https://cosign.ochk.io",
3915
- group: "app",
3916
- line: "Builders find co-founders and backers.",
3917
- status: "testing",
3918
- // Signs in with an orangecheck account and a wallet; uses none of the six directly.
3919
- protocols: []
3920
- },
3921
- {
3922
- slug: "me-demo",
3923
- // "demo", not the made-up app's own name, so nobody takes it for ours.
3924
- label: "demo",
3925
- href: "https://me-demo.ochk.io",
3926
- group: "app",
3927
- line: "Lumen Notes, a made-up app that signs in with orangecheck.",
3928
- status: "live"
3929
- },
3930
- {
3931
- slug: "globe",
3932
- label: "globe",
3933
- href: "https://globe.ochk.io",
3934
- group: "public-good",
3935
- line: "The Bitcoin network, live, on a globe.",
3936
- status: "live"
3937
- },
3938
- {
3939
- slug: "btc",
3940
- label: "btc",
3941
- href: "https://btc.ochk.io",
3942
- group: "public-good",
3943
- line: "A free desk for reading the Bitcoin market.",
3944
- status: "live"
3945
- }
3946
- ];
3947
- var FAMILY_GROUPS = [
3948
- { id: "orangecheck", label: "orangecheck" },
3949
- { id: "protocol", label: "Protocols" },
3950
- { id: "app", label: "Apps" },
3951
- { id: "public-good", label: "Public goods" }
3952
- ];
3953
- var BY_SLUG = new Map(FAMILY.map((s) => [s.slug, s]));
3954
- function familySite(slug) {
3955
- return BY_SLUG.get(slug);
3956
- }
3957
- function protocolSite(slug) {
3958
- return BY_SLUG.get(slug);
3959
- }
3960
- function familyByGroup() {
3961
- return FAMILY_GROUPS.map((g) => ({ ...g, sites: FAMILY.filter((s) => s.group === g.id) }));
3962
- }
3963
- var LEGAL_LINKS = [
3964
- { href: `${OCHK_IO}/privacy`, label: "Privacy" },
3965
- { href: `${OCHK_IO}/terms`, label: "Terms" },
3966
- { href: `${OCHK_IO}/security`, label: "Security" },
3967
- { href: `${OCHK_IO}/trademark`, label: "Trademarks" },
3968
- { href: `${OCHK_IO}/contact`, label: "Contact" }
3969
- ];
3970
- var SELF_HOSTED_LEGAL_LINKS = [
3971
- { href: "/privacy", label: "Privacy" },
3972
- { href: "/terms", label: "Terms" },
3973
- { href: "/security", label: "Security" },
3974
- { href: `${OCHK_IO}/trademark`, label: "Trademarks" },
3975
- { href: "/contact", label: "Contact" }
3976
- ];
3977
- var OCHK_IO_NAV = [
3978
- {
3979
- href: `${OCHK_IO}/protocols`,
3980
- label: "Protocols",
3981
- children: PROTOCOLS.map((p) => ({ href: p.pageHref, label: p.label, description: p.line }))
3982
- },
3983
- { href: `${OCHK_IO}/apps`, label: "Apps" },
3984
- { href: DOCS_HREF, label: "Docs" },
3985
- { href: `${OCHK_IO}/trust`, label: "Trust" },
3986
- { href: `${OCHK_IO}/about`, label: "About" }
3987
- ];
3988
- var OCHK_IO_FOOTER = [
3989
- {
3990
- heading: "Company",
3991
- links: [
3992
- { href: `${OCHK_IO}/about`, label: "About" },
3993
- { href: `${OCHK_IO}/trust`, label: "Trust" },
3994
- { href: "https://github.com/orangecheck", label: "GitHub", external: true }
3995
- ]
3996
- }
3997
- ];
3998
4017
  var InDocsContext = sharedContext("in-docs", false);
3999
4018
  function useInDocs() {
4000
4019
  return useContext(InDocsContext);
@@ -4811,6 +4830,7 @@ function SignMessage({
4811
4830
  error,
4812
4831
  submitLabel = "Confirm",
4813
4832
  secondary,
4833
+ scheme = "bip322",
4814
4834
  onSignature,
4815
4835
  className
4816
4836
  }) {
@@ -4825,7 +4845,7 @@ function SignMessage({
4825
4845
  /* @__PURE__ */ jsx("span", { className: "h-px flex-1 bg-border" })
4826
4846
  ] })
4827
4847
  ] }) : null,
4828
- /* @__PURE__ */ jsx(CodeBlock, { code: message, caption: "Message to sign" }),
4848
+ /* @__PURE__ */ jsx(CodeBlock, { code: message, caption: "Message to sign", wrap: true }),
4829
4849
  /* @__PURE__ */ jsxs(
4830
4850
  "form",
4831
4851
  {
@@ -4841,7 +4861,9 @@ function SignMessage({
4841
4861
  label: "Signature",
4842
4862
  error,
4843
4863
  hint: /* @__PURE__ */ jsxs(Fragment, { children: [
4844
- "From your wallet\u2019s \u201Csign message\u201D (BIP-322), signed by",
4864
+ "From your wallet\u2019s \u201Csign message\u201D (",
4865
+ scheme === "legacy" ? "legacy, BIP-137" : "BIP-322",
4866
+ "), signed by",
4845
4867
  " ",
4846
4868
  /* @__PURE__ */ jsx("span", { className: "break-all font-mono", children: address }),
4847
4869
  "."
@@ -5353,7 +5375,7 @@ function FormSection({
5353
5375
  "aria-current": status === "current" ? "step" : void 0,
5354
5376
  className: cn("scroll-mt-24 rounded-[1.25rem] border border-border bg-card", className),
5355
5377
  children: [
5356
- /* @__PURE__ */ jsxs("header", { className: cn("flex items-start gap-3.5", tight ? "px-5 pt-5" : "px-6 pt-6"), children: [
5378
+ /* @__PURE__ */ jsxs("header", { className: cn("flex flex-wrap items-start gap-x-3.5 gap-y-3", tight ? "px-5 pt-5" : "px-6 pt-6"), children: [
5357
5379
  n !== void 0 ? /* @__PURE__ */ jsx(
5358
5380
  "span",
5359
5381
  {
@@ -5380,7 +5402,7 @@ function FormSection({
5380
5402
  ] }),
5381
5403
  hint ? /* @__PURE__ */ jsx("p", { className: "text-[0.875rem] leading-snug text-muted-foreground", children: hint }) : null
5382
5404
  ] }),
5383
- action ? /* @__PURE__ */ jsx("div", { className: "shrink-0", children: action }) : null
5405
+ action ? /* @__PURE__ */ jsx("div", { className: cn("shrink-0 max-sm:basis-full", n !== void 0 && "max-sm:pl-[2.625rem]"), children: action }) : null
5384
5406
  ] }),
5385
5407
  /* @__PURE__ */ jsx("div", { className: cn("flex flex-col", tight ? "gap-4 p-5" : "gap-5 p-6", n !== void 0 && (tight ? "sm:pl-[3.875rem]" : "sm:pl-[4.125rem]")), children })
5386
5408
  ]
@@ -5610,27 +5632,30 @@ function FilterChips({
5610
5632
  onChange(cur.includes(v) ? cur.filter((x) => x !== v) : [...cur, v]);
5611
5633
  } else onChange(v);
5612
5634
  };
5613
- return /* @__PURE__ */ jsx(ScrollFade, { fade: "var(--background)", className: cn("w-full", className), children: /* @__PURE__ */ jsx("div", { role: "group", "aria-label": label, className: "flex w-max items-center gap-2 py-0.5", children: options.map((o) => {
5614
- const on = isOn(o.value);
5615
- return /* @__PURE__ */ jsxs(
5616
- "button",
5617
- {
5618
- type: "button",
5619
- "aria-pressed": on,
5620
- onClick: () => press(o.value),
5621
- className: cn(
5622
- "inline-flex shrink-0 items-center gap-1.5 rounded-full border px-3.5 text-[0.875rem] transition-colors",
5623
- tight ? "h-8" : "h-9",
5624
- on ? "border-foreground bg-foreground text-background" : "border-border bg-card text-muted-foreground hover:border-oca-hairline-strong hover:text-foreground"
5625
- ),
5626
- children: [
5627
- o.label,
5628
- o.count !== void 0 ? /* @__PURE__ */ jsx("span", { className: "oca-tabular", children: o.count.toLocaleString("en-US") }) : null
5629
- ]
5630
- },
5631
- o.value
5632
- );
5633
- }) }) });
5635
+ return (
5636
+ // Wraps rather than scrolls: every filter stays in view on a phone.
5637
+ /* @__PURE__ */ jsx("div", { role: "group", "aria-label": label, className: cn("flex flex-wrap items-center gap-2 py-0.5", className), children: options.map((o) => {
5638
+ const on = isOn(o.value);
5639
+ return /* @__PURE__ */ jsxs(
5640
+ "button",
5641
+ {
5642
+ type: "button",
5643
+ "aria-pressed": on,
5644
+ onClick: () => press(o.value),
5645
+ className: cn(
5646
+ "inline-flex shrink-0 items-center gap-1.5 rounded-full border px-3.5 text-[0.875rem] transition-colors",
5647
+ tight ? "h-8" : "h-9",
5648
+ on ? "border-foreground bg-foreground text-background" : "border-border bg-card text-muted-foreground hover:border-oca-hairline-strong hover:text-foreground"
5649
+ ),
5650
+ children: [
5651
+ o.label,
5652
+ o.count !== void 0 ? /* @__PURE__ */ jsx("span", { className: "oca-tabular", children: o.count.toLocaleString("en-US") }) : null
5653
+ ]
5654
+ },
5655
+ o.value
5656
+ );
5657
+ }) })
5658
+ );
5634
5659
  }
5635
5660
  function ToolGrid({
5636
5661
  tools,
@@ -6385,12 +6410,14 @@ function SignInFrame({
6385
6410
  error,
6386
6411
  fineprint,
6387
6412
  brand,
6388
- home = "/",
6413
+ home,
6414
+ protocol: protocol2,
6389
6415
  back,
6390
6416
  art,
6391
6417
  caption,
6392
6418
  className
6393
6419
  }) {
6420
+ const homeHref = home ?? (protocol2 ? protocolSite(protocol2).pageHref : OCHK_IO);
6394
6421
  return /* @__PURE__ */ jsxs(
6395
6422
  "main",
6396
6423
  {
@@ -6399,14 +6426,14 @@ function SignInFrame({
6399
6426
  children: [
6400
6427
  /* @__PURE__ */ jsxs("section", { className: "flex flex-col px-4 pb-8 pt-5 sm:px-8 lg:px-14 lg:pt-8", children: [
6401
6428
  /* @__PURE__ */ jsxs("header", { className: "flex items-center justify-between gap-4", children: [
6402
- /* @__PURE__ */ jsxs(Link6, { href: home, className: "w-fit rounded-lg", children: [
6429
+ /* @__PURE__ */ jsxs(Link6, { href: homeHref, className: "w-fit rounded-lg", children: [
6403
6430
  brand ?? /* @__PURE__ */ jsx(Lockup, { size: 28 }),
6404
6431
  /* @__PURE__ */ jsx("span", { className: "sr-only", children: " home" })
6405
6432
  ] }),
6406
6433
  back === void 0 ? /* @__PURE__ */ jsx(
6407
6434
  Link6,
6408
6435
  {
6409
- href: home,
6436
+ href: homeHref,
6410
6437
  className: "text-[0.9375rem] text-muted-foreground underline-offset-4 hover:text-foreground hover:underline",
6411
6438
  children: "Back to home"
6412
6439
  }
@@ -6655,6 +6682,7 @@ function ToolShell({
6655
6682
  children
6656
6683
  }) {
6657
6684
  const p = protocolSite(protocol2);
6685
+ const homeHref = home ?? p.pageHref;
6658
6686
  const app = variant === "app";
6659
6687
  const tabs = app ? null : tabsFor([{ items: [...tools] }]);
6660
6688
  const about = /* @__PURE__ */ jsxs(
@@ -6684,7 +6712,7 @@ function ToolShell({
6684
6712
  SiteHeader,
6685
6713
  {
6686
6714
  variant: "tool",
6687
- home: home ?? p.pageHref,
6715
+ home: homeHref,
6688
6716
  product: p.label,
6689
6717
  family: protocol2,
6690
6718
  nav: tools.map((t) => ({ href: t.href, label: t.label, active: t.active })),
@@ -6709,7 +6737,7 @@ function ToolShell({
6709
6737
  {
6710
6738
  id: "main-content",
6711
6739
  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"),
6712
- children: app ? children : /* @__PURE__ */ jsx("div", { className: "mx-auto w-full max-w-[72rem]", children })
6740
+ children: /* @__PURE__ */ jsx(SiteHomeContext.Provider, { value: homeHref, children: app ? children : /* @__PURE__ */ jsx("div", { className: "mx-auto w-full max-w-[72rem]", children }) })
6713
6741
  }
6714
6742
  )
6715
6743
  ] }),