@carrierllc/mcp 0.2.19 → 0.3.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 (41) hide show
  1. package/README.md +22 -1
  2. package/dist/chunk-ZII4CD4U.js +461 -0
  3. package/dist/chunk-ZII4CD4U.js.map +1 -0
  4. package/dist/cli.js +1294 -105
  5. package/dist/cli.js.map +1 -1
  6. package/dist/index.js +144 -315
  7. package/dist/index.js.map +1 -1
  8. package/package.json +1 -1
  9. package/plugin/carrier/commands/storefront.md +24 -12
  10. package/plugin/carrier/skills/carrier-operations/SKILL.md +4 -1
  11. package/templates/storefront/{next.config.ts → next.config.mjs} +2 -6
  12. package/templates/storefront/public/brand/logo.svg +13 -0
  13. package/templates/storefront/src/app/activate/[orderId]/ActivateClient.tsx +12 -12
  14. package/templates/storefront/src/app/checkout/[templateId]/CheckoutClient.tsx +5 -5
  15. package/templates/storefront/src/app/checkout/success/CheckoutSuccessClient.tsx +29 -29
  16. package/templates/storefront/src/app/checkout/success/page.tsx +1 -1
  17. package/templates/storefront/src/app/contact/page.tsx +33 -25
  18. package/templates/storefront/src/app/dashboard/page.tsx +7 -4
  19. package/templates/storefront/src/app/globals.css +72 -82
  20. package/templates/storefront/src/app/help/page.tsx +22 -17
  21. package/templates/storefront/src/app/layout.tsx +15 -4
  22. package/templates/storefront/src/app/page.tsx +16 -7
  23. package/templates/storefront/src/app/shop/ShopClient.tsx +7 -3
  24. package/templates/storefront/src/app/sign-in/[[...sign-in]]/page.tsx +1 -1
  25. package/templates/storefront/src/app/sign-up/[[...sign-up]]/StorefrontSignUpClient.tsx +16 -16
  26. package/templates/storefront/src/app/sign-up/[[...sign-up]]/page.tsx +1 -1
  27. package/templates/storefront/src/brand.config.ts +3 -3
  28. package/templates/storefront/src/components/faq/FaqSection.tsx +23 -26
  29. package/templates/storefront/src/components/footer/StorefrontFooter.tsx +37 -22
  30. package/templates/storefront/src/components/landing/FinalCTA.tsx +28 -0
  31. package/templates/storefront/src/components/landing/HeroSection.tsx +57 -24
  32. package/templates/storefront/src/components/landing/HowItWorks.tsx +44 -0
  33. package/templates/storefront/src/components/landing/PlanCard.tsx +58 -28
  34. package/templates/storefront/src/components/nav/StorefrontNav.tsx +59 -24
  35. package/templates/storefront/src/components/theme/BrandStyles.tsx +8 -0
  36. package/templates/storefront/src/components/theme/ThemeToggle.tsx +27 -0
  37. package/templates/storefront/src/components/theme/clerk-appearance.ts +33 -35
  38. package/templates/storefront/src/components/theme/theme-provider.tsx +25 -32
  39. package/templates/storefront/src/components/theme/theme-script.tsx +4 -7
  40. package/templates/storefront/src/lib/complete-email-sign-up.ts +3 -3
  41. package/templates/storefront/src/vendor/ui/brand.ts +6 -6
@@ -1,99 +1,89 @@
1
1
  @import "tailwindcss";
2
2
 
3
- @custom-variant dark (&:where([data-theme=dark], [data-theme=dark] *));
3
+ @custom-variant dark (&:where([data-theme="dark"], [data-theme="dark"] *));
4
4
 
5
5
  @theme {
6
- /* Brand palette — overridden per white-label via CSS vars */
7
- --color-brand-bg: var(--brand-bg);
8
- --color-brand-accent: var(--brand-accent);
9
- --color-brand-accent-dark: var(--brand-accent-dark);
10
- --color-brand-accent-light: var(--brand-accent-light);
11
- --color-brand-text: var(--brand-text);
12
- --color-brand-text-secondary: var(--brand-text-secondary);
6
+ --color-leaf-50: #F0FDF4;
7
+ --color-leaf-500: #22C55E;
8
+ --color-leaf-600: #16A34A;
9
+ --color-leaf-700: #15803D;
13
10
 
14
- /* Map mango-* → brand flame so ported component classNames keep working */
15
- --color-mango-50: #fff4ef;
16
- --color-mango-100: #ffe0d0;
17
- --color-mango-200: #ffbfa0;
18
- --color-mango-300: #ff9970;
19
- --color-mango-400: #ff7d4d;
20
- --color-mango-500: var(--brand-accent);
21
- --color-mango-600: var(--brand-accent-dark);
22
- --color-mango-700: #b33a17;
23
- --color-mango-800: #8a2d12;
24
- --color-mango-900: #5e1e0c;
25
- --color-mango-950: #3a1107;
11
+ --color-sand-50: #FAFAF7;
12
+ --color-sand-100: #F4F2EC;
13
+ --color-sand-200: #E8E4D8;
14
+ --color-sand-400: #A8A28E;
15
+ --color-sand-500: #78725F;
16
+ --color-sand-600: #5C5644;
17
+ --color-sand-700: #3F3B30;
18
+ --color-sand-800: #2C291F;
19
+ --color-sand-900: #1A1812;
20
+ --color-sand-950: #0F0E0A;
26
21
 
27
- /* Neutral slate */
28
- --color-slate-950: #080C16;
22
+ --font-sans: var(--font-geist-sans, "Geist", "Inter", system-ui, sans-serif);
23
+ --font-display: var(--font-geist-sans, "Geist", system-ui, sans-serif);
24
+ --font-mono: var(--font-geist-mono, ui-monospace, monospace);
29
25
 
30
- /* Fonts */
31
- --font-sans: var(--font-geist-sans, system-ui, sans-serif);
32
- --font-mono: var(--font-geist-mono, monospace);
33
-
34
- /* Radii */
35
- --radius-sm: 0.25rem;
36
- --radius-md: 0.5rem;
37
- --radius-lg: 0.75rem;
38
- --radius-xl: 1rem;
39
- --radius-2xl: 1.5rem;
26
+ --radius-sm: 6px;
27
+ --radius-md: 10px;
28
+ --radius-lg: 14px;
29
+ --radius-xl: 20px;
30
+ --radius-2xl: 28px;
40
31
  --radius-full: 9999px;
41
32
  }
42
33
 
43
- /* ── Brand CSS variables (dark-first default) ─────────────────────────────── */
44
- :root {
45
- --brand-bg: #080C16;
46
- --brand-accent: #FF6B35;
47
- --brand-accent-dark: #D9461C;
48
- --brand-accent-light: #FFB088;
49
- --brand-text: #F5F1EA;
50
- --brand-text-secondary: #C9CCD6;
51
- }
34
+ @layer base {
35
+ :root {
36
+ color-scheme: light;
37
+ --brand-accent: #FF6B35;
38
+ --brand-accent-dark: #D9461C;
39
+ --brand-accent-light: #FFB088;
40
+ }
52
41
 
53
- [data-theme="light"] {
54
- --brand-bg: #FAFAF8;
55
- --brand-text: #0F1117;
56
- --brand-text-secondary: #6B7280;
57
- }
42
+ html[data-theme="dark"] {
43
+ color-scheme: dark;
44
+ }
58
45
 
59
- /* ── Base reset ───────────────────────────────────────────────────────────── */
60
- *,
61
- *::before,
62
- *::after {
63
- box-sizing: border-box;
64
- margin: 0;
65
- padding: 0;
66
- }
46
+ * { box-sizing: border-box; }
67
47
 
68
- html {
69
- scroll-behavior: smooth;
70
- -webkit-text-size-adjust: 100%;
71
- }
48
+ html {
49
+ scroll-behavior: smooth;
50
+ -webkit-font-smoothing: antialiased;
51
+ -moz-osx-font-smoothing: grayscale;
52
+ background-color: var(--color-sand-50);
53
+ scrollbar-gutter: stable;
54
+ }
72
55
 
73
- body {
74
- background-color: var(--brand-bg);
75
- color: var(--brand-text);
76
- font-family: var(--font-sans);
77
- line-height: 1.6;
78
- -webkit-font-smoothing: antialiased;
79
- -moz-osx-font-smoothing: grayscale;
80
- }
56
+ body {
57
+ background-color: var(--color-sand-50);
58
+ color: var(--color-sand-900);
59
+ font-family: var(--font-sans);
60
+ text-rendering: optimizeLegibility;
61
+ transition: background-color 0.3s ease, color 0.3s ease;
62
+ }
81
63
 
82
- /* ── Selection ───────────────────────────────────────────────────────────── */
83
- ::selection {
84
- background-color: color-mix(in srgb, var(--brand-accent) 30%, transparent);
85
- color: var(--brand-text);
86
- }
64
+ html[data-theme="dark"] {
65
+ background-color: var(--color-sand-950);
66
+ }
87
67
 
88
- /* ── Scrollbar ───────────────────────────────────────────────────────────── */
89
- ::-webkit-scrollbar {
90
- width: 6px;
91
- height: 6px;
92
- }
93
- ::-webkit-scrollbar-track {
94
- background: transparent;
95
- }
96
- ::-webkit-scrollbar-thumb {
97
- background: color-mix(in srgb, var(--brand-accent) 40%, transparent);
98
- border-radius: 3px;
68
+ html[data-theme="dark"] body {
69
+ background-color: var(--color-sand-950);
70
+ color: var(--color-sand-50);
71
+ }
72
+
73
+ ::selection {
74
+ background-color: color-mix(in srgb, var(--brand-accent) 28%, transparent);
75
+ }
76
+
77
+ :focus-visible {
78
+ outline: 2px solid var(--brand-accent);
79
+ outline-offset: 2px;
80
+ }
81
+
82
+ @media (prefers-reduced-motion: reduce) {
83
+ *, *::before, *::after {
84
+ animation-duration: 0.01ms !important;
85
+ animation-iteration-count: 1 !important;
86
+ transition-duration: 0.01ms !important;
87
+ }
88
+ }
99
89
  }
@@ -1,24 +1,29 @@
1
- export const metadata = { title: "Help" };
1
+ import { HowItWorks } from "@/components/landing/HowItWorks";
2
+ import brand from "@/brand.config";
2
3
 
3
- const STEPS = [
4
- { title: "1. Choose your plan", body: "Browse plans by region or data size and select one that suits your trip." },
5
- { title: "2. Create an account", body: "Sign up for free to manage your eSIMs in one place." },
6
- { title: "3. Complete checkout", body: "Pay securely. You will receive a QR code by email within seconds." },
7
- { title: "4. Scan & connect", body: "Open Settings on your device, scan the QR code, and you are online." },
8
- ];
4
+ export const metadata = { title: "Help" };
9
5
 
10
6
  export default function HelpPage() {
11
7
  return (
12
- <div className="mx-auto max-w-3xl px-4 py-24">
13
- <h1 className="text-3xl font-bold text-white mb-4">How it works</h1>
14
- <p className="text-white/50 mb-12">Get connected in under 5 minutes.</p>
15
- <div className="grid gap-6">
16
- {STEPS.map((step) => (
17
- <div key={step.title} className="rounded-2xl border border-white/10 bg-white/5 p-6">
18
- <h2 className="font-semibold text-white mb-2">{step.title}</h2>
19
- <p className="text-sm text-white/60">{step.body}</p>
20
- </div>
21
- ))}
8
+ <div className="pb-16">
9
+ <div className="mx-auto max-w-3xl px-4 py-16">
10
+ <h1 className="text-3xl font-semibold tracking-tight text-sand-900 dark:text-sand-50">
11
+ Help
12
+ </h1>
13
+ <p className="mt-2 text-sand-600 dark:text-sand-400">
14
+ Get connected in under five minutes. Humans on WhatsApp, 24/7.
15
+ </p>
16
+ </div>
17
+ <HowItWorks />
18
+ <div className="mx-auto max-w-3xl px-4 pt-10 text-sm text-sand-600 dark:text-sand-400">
19
+ Need a human?{" "}
20
+ <a href={`mailto:${brand.supportEmail}`} className="font-medium" style={{ color: "var(--brand-accent)" }}>
21
+ {brand.supportEmail}
22
+ </a>
23
+ {" · "}
24
+ <a href="/contact" className="font-medium" style={{ color: "var(--brand-accent)" }}>
25
+ All channels
26
+ </a>
22
27
  </div>
23
28
  </div>
24
29
  );
@@ -5,6 +5,7 @@ import { GeistSans } from "geist/font/sans";
5
5
  import { GeistMono } from "geist/font/mono";
6
6
  import { Providers } from "@/components/Providers";
7
7
  import { ThemeScript } from "@/components/theme/theme-script";
8
+ import { BrandStyles } from "@/components/theme/BrandStyles";
8
9
  import { StorefrontNav } from "@/components/nav/StorefrontNav";
9
10
  import { StorefrontFooter } from "@/components/footer/StorefrontFooter";
10
11
  import brand from "@/brand.config";
@@ -12,7 +13,7 @@ import "./globals.css";
12
13
 
13
14
  export const metadata: Metadata = {
14
15
  title: {
15
- default: brand.name,
16
+ default: `${brand.name} — ${brand.tagline}`,
16
17
  template: `%s — ${brand.name}`,
17
18
  },
18
19
  description: brand.tagline,
@@ -30,24 +31,34 @@ export const metadata: Metadata = {
30
31
 
31
32
  export const viewport: Viewport = {
32
33
  themeColor: brand.colors.accent,
33
- colorScheme: "dark light",
34
+ colorScheme: "light dark",
34
35
  };
35
36
 
36
37
  export default function RootLayout({ children }: { children: React.ReactNode }) {
37
38
  return (
38
39
  <html
39
40
  lang="en"
40
- data-theme="dark"
41
+ data-theme="light"
41
42
  className={`${GeistSans.variable} ${GeistMono.variable}`}
42
43
  suppressHydrationWarning
43
44
  >
44
45
  <head>
45
46
  <ThemeScript />
47
+ <BrandStyles />
46
48
  </head>
47
49
  <body>
48
50
  <Providers>
51
+ <a
52
+ href="#main-content"
53
+ className="sr-only focus:not-sr-only focus:absolute focus:left-4 focus:top-20 focus:z-[100] focus:rounded-lg focus:px-4 focus:py-2 focus:text-sm focus:font-semibold focus:text-white"
54
+ style={{ background: "var(--brand-accent)" }}
55
+ >
56
+ Skip to main content
57
+ </a>
49
58
  <StorefrontNav />
50
- <main className="pt-16 min-h-screen">{children}</main>
59
+ <main id="main-content" className="pt-16">
60
+ {children}
61
+ </main>
51
62
  <StorefrontFooter />
52
63
  </Providers>
53
64
  </body>
@@ -1,4 +1,6 @@
1
1
  import { HeroSection } from "@/components/landing/HeroSection";
2
+ import { HowItWorks } from "@/components/landing/HowItWorks";
3
+ import { FinalCTA } from "@/components/landing/FinalCTA";
2
4
  import { FaqSection } from "@/components/faq/FaqSection";
3
5
  import { fetchTemplates } from "@/vendor/carrier/client";
4
6
  import { PlanCard } from "@/components/landing/PlanCard";
@@ -11,21 +13,28 @@ export default async function HomePage() {
11
13
  <>
12
14
  <HeroSection />
13
15
 
14
- <section className="py-24 bg-[var(--brand-bg)]">
15
- <div className="mx-auto max-w-6xl px-4">
16
- <h2 className="text-3xl font-bold text-white text-center mb-4">Popular plans</h2>
17
- <p className="text-center text-white/50 mb-12">
18
- Instant activation. No contracts. Cancel anytime.
16
+ <section className="px-4 py-20">
17
+ <div className="mx-auto max-w-6xl">
18
+ <p className="text-center text-xs font-semibold uppercase tracking-[0.18em] text-sand-500">
19
+ Plans
19
20
  </p>
20
- <div className="grid grid-cols-1 md:grid-cols-3 gap-6">
21
+ <h2 className="mt-2 text-center text-3xl font-semibold tracking-tight text-sand-900 dark:text-sand-50">
22
+ Popular plans
23
+ </h2>
24
+ <p className="mx-auto mt-3 max-w-lg text-center text-sand-600 dark:text-sand-400">
25
+ Instant activation. No contracts. Price next to the limit.
26
+ </p>
27
+ <div className="mt-12 grid grid-cols-1 gap-8 md:grid-cols-3">
21
28
  {featured.map((plan, i) => (
22
- <PlanCard key={plan.id} plan={plan} featured={i === 1} />
29
+ <PlanCard key={plan.id} plan={plan} featured={i === 1} href={`/checkout/${plan.id}`} />
23
30
  ))}
24
31
  </div>
25
32
  </div>
26
33
  </section>
27
34
 
35
+ <HowItWorks />
28
36
  <FaqSection />
37
+ <FinalCTA />
29
38
  </>
30
39
  );
31
40
  }
@@ -15,9 +15,13 @@ export function ShopClient({ plans }: { plans: SkuTemplate[] }) {
15
15
 
16
16
  return (
17
17
  <div className="mx-auto max-w-6xl px-4 py-16">
18
- <h1 className="text-4xl font-bold text-white mb-2">Choose your plan</h1>
19
- <p className="text-white/50 mb-12">Instant activation. No contracts.</p>
20
- <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
18
+ <h1 className="text-4xl font-semibold tracking-tight text-sand-900 dark:text-sand-50">
19
+ Choose your plan
20
+ </h1>
21
+ <p className="mt-2 mb-12 text-sand-600 dark:text-sand-400">
22
+ Instant activation. No contracts. Price next to the limit.
23
+ </p>
24
+ <div className="grid grid-cols-1 gap-8 sm:grid-cols-2 lg:grid-cols-3">
21
25
  {plans.map((plan, i) => (
22
26
  <PlanCard key={plan.id} plan={plan} featured={i === 1} onSelect={handleSelect} />
23
27
  ))}
@@ -16,7 +16,7 @@ export default async function SignInPage({ searchParams }: Props) {
16
16
  return (
17
17
  <div className="flex min-h-[calc(100vh-4rem)] items-center justify-center px-4">
18
18
  <SignIn
19
- redirectUrl={redirectUrl}
19
+ fallbackRedirectUrl={redirectUrl}
20
20
  signUpUrl="/sign-up"
21
21
  />
22
22
  </div>
@@ -10,7 +10,7 @@
10
10
  * useClerk() → { setActive }
11
11
  */
12
12
  import { useState, FormEvent } from "react";
13
- import { useSignUp } from "@clerk/nextjs/legacy";
13
+ import { useSignUp } from "@clerk/nextjs";
14
14
  import { useClerk } from "@clerk/nextjs";
15
15
  import { useSearchParams, useRouter } from "next/navigation";
16
16
  import { completeEmailSignUpAfterVerify } from "@/lib/complete-email-sign-up";
@@ -82,14 +82,14 @@ export function StorefrontSignUpClient() {
82
82
  }
83
83
 
84
84
  return (
85
- <div className="w-full max-w-sm rounded-2xl border border-white/10 bg-white/5 p-8 backdrop-blur">
85
+ <div className="w-full max-w-sm rounded-2xl border border-sand-200 dark:border-sand-800 bg-white dark:bg-sand-900 p-8 backdrop-blur">
86
86
  {step === "credentials" && (
87
87
  <>
88
- <h1 className="text-xl font-bold text-white mb-1">Create account</h1>
89
- <p className="text-xs text-white/40 mb-6">Email and password — no phone required.</p>
88
+ <h1 className="text-xl font-bold text-sand-900 dark:text-sand-50 mb-1">Create account</h1>
89
+ <p className="text-xs text-sand-500 mb-6">Email and password — no phone required.</p>
90
90
  <form onSubmit={handleCredentials} className="space-y-4">
91
91
  <div>
92
- <label className="block text-xs font-medium text-white/60 mb-1" htmlFor="sf-email">
92
+ <label className="block text-xs font-medium text-sand-600 dark:text-sand-400 mb-1" htmlFor="sf-email">
93
93
  Email address
94
94
  </label>
95
95
  <input
@@ -99,12 +99,12 @@ export function StorefrontSignUpClient() {
99
99
  required
100
100
  value={email}
101
101
  onChange={(e) => setEmail(e.target.value)}
102
- className="w-full rounded-lg border border-white/10 bg-black/30 px-3 py-2 text-sm text-white placeholder-white/20 focus:border-[var(--brand-accent)] focus:outline-none"
102
+ className="w-full rounded-lg border border-sand-200 dark:border-sand-800 bg-sand-50 dark:bg-sand-950 px-3 py-2 text-sm text-sand-900 dark:text-sand-50 placeholder:text-sand-400 focus:border-[var(--brand-accent)] focus:outline-none"
103
103
  placeholder="you@example.com"
104
104
  />
105
105
  </div>
106
106
  <div>
107
- <label className="block text-xs font-medium text-white/60 mb-1" htmlFor="sf-password">
107
+ <label className="block text-xs font-medium text-sand-600 dark:text-sand-400 mb-1" htmlFor="sf-password">
108
108
  Password
109
109
  </label>
110
110
  <input
@@ -115,7 +115,7 @@ export function StorefrontSignUpClient() {
115
115
  minLength={8}
116
116
  value={password}
117
117
  onChange={(e) => setPassword(e.target.value)}
118
- className="w-full rounded-lg border border-white/10 bg-black/30 px-3 py-2 text-sm text-white placeholder-white/20 focus:border-[var(--brand-accent)] focus:outline-none"
118
+ className="w-full rounded-lg border border-sand-200 dark:border-sand-800 bg-sand-50 dark:bg-sand-950 px-3 py-2 text-sm text-sand-900 dark:text-sand-50 placeholder:text-sand-400 focus:border-[var(--brand-accent)] focus:outline-none"
119
119
  placeholder="Min. 8 characters"
120
120
  />
121
121
  </div>
@@ -132,7 +132,7 @@ export function StorefrontSignUpClient() {
132
132
  {loading ? "Creating account…" : "Continue"}
133
133
  </button>
134
134
  </form>
135
- <p className="mt-4 text-center text-xs text-white/30">
135
+ <p className="mt-4 text-center text-xs text-sand-400">
136
136
  Already have an account?{" "}
137
137
  <a href="/sign-in" className="text-[var(--brand-accent)] hover:underline">
138
138
  Sign in
@@ -143,13 +143,13 @@ export function StorefrontSignUpClient() {
143
143
 
144
144
  {step === "verify" && (
145
145
  <>
146
- <h1 className="text-xl font-bold text-white mb-1">Check your email</h1>
147
- <p className="text-xs text-white/40 mb-6">
148
- We sent a 6-digit code to <span className="text-white/70">{email}</span>.
146
+ <h1 className="text-xl font-bold text-sand-900 dark:text-sand-50 mb-1">Check your email</h1>
147
+ <p className="text-xs text-sand-500 mb-6">
148
+ We sent a 6-digit code to <span className="text-sand-600 dark:text-sand-300">{email}</span>.
149
149
  </p>
150
150
  <form onSubmit={handleVerify} className="space-y-4">
151
151
  <div>
152
- <label className="block text-xs font-medium text-white/60 mb-1" htmlFor="sf-code">
152
+ <label className="block text-xs font-medium text-sand-600 dark:text-sand-400 mb-1" htmlFor="sf-code">
153
153
  Verification code
154
154
  </label>
155
155
  <input
@@ -161,7 +161,7 @@ export function StorefrontSignUpClient() {
161
161
  maxLength={6}
162
162
  value={code}
163
163
  onChange={(e) => setCode(e.target.value.replace(/\D/g, ""))}
164
- className="w-full rounded-lg border border-white/10 bg-black/30 px-3 py-2 text-center text-lg tracking-[0.4em] text-white placeholder-white/20 focus:border-[var(--brand-accent)] focus:outline-none"
164
+ className="w-full rounded-lg border border-sand-200 dark:border-sand-800 bg-sand-50 dark:bg-sand-950 px-3 py-2 text-center text-lg tracking-[0.4em] text-sand-900 dark:text-sand-50 placeholder:text-sand-400 focus:border-[var(--brand-accent)] focus:outline-none"
165
165
  placeholder="000000"
166
166
  />
167
167
  </div>
@@ -181,7 +181,7 @@ export function StorefrontSignUpClient() {
181
181
  <button
182
182
  type="button"
183
183
  onClick={() => { setStep("credentials"); setError(null); setCode(""); }}
184
- className="mt-4 w-full text-center text-xs text-white/30 hover:text-white/50"
184
+ className="mt-4 w-full text-center text-xs text-sand-400 hover:text-sand-500"
185
185
  >
186
186
  ← Back
187
187
  </button>
@@ -191,7 +191,7 @@ export function StorefrontSignUpClient() {
191
191
  {step === "complete" && (
192
192
  <div className="text-center space-y-3 py-4">
193
193
  <div className="mx-auto size-8 animate-spin rounded-full border-2 border-[var(--brand-accent)] border-t-transparent" />
194
- <p className="text-sm text-white/60">Setting up your account…</p>
194
+ <p className="text-sm text-sand-600 dark:text-sand-400">Setting up your account…</p>
195
195
  </div>
196
196
  )}
197
197
  </div>
@@ -17,7 +17,7 @@ export default function SignUpPage() {
17
17
  fallback={
18
18
  <div className="text-center space-y-3">
19
19
  <div className="mx-auto size-8 animate-spin rounded-full border-2 border-[var(--brand-accent)] border-t-transparent" />
20
- <p className="text-sm text-white/60">Loading…</p>
20
+ <p className="text-sm text-sand-600 dark:text-sand-400">Loading…</p>
21
21
  </div>
22
22
  }
23
23
  >
@@ -11,12 +11,12 @@ const brand = {
11
11
  supportEmail: "support@carrier.llc",
12
12
  supportWhatsapp: "+17864604829",
13
13
  colors: {
14
- bg: "#080C16",
14
+ bg: "#FAFAF7",
15
15
  accent: "#FF6B35",
16
16
  accentDark: "#D9461C",
17
17
  accentLight: "#FFB088",
18
- text: "#F5F1EA",
19
- textSecondary: "#C9CCD6",
18
+ text: "#1A1812",
19
+ textSecondary: "#5C5644",
20
20
  },
21
21
  social: {
22
22
  x: "@carrier_llc",
@@ -3,45 +3,41 @@
3
3
  import { useState } from "react";
4
4
  import { motion, AnimatePresence } from "framer-motion";
5
5
  import { cn } from "@/vendor/ui/cn";
6
+ import brand from "@/brand.config";
6
7
 
7
8
  const FAQS = [
8
9
  {
9
10
  q: "What is an eSIM?",
10
- a: "An eSIM (embedded SIM) is a digital SIM that lets you activate a mobile plan without a physical SIM card. You scan a QR code and your device is connected instantly.",
11
+ a: "An eSIM is a digital SIM. You scan a QR code no plastic card, no store visit. Your phone is online in about 30 seconds.",
11
12
  },
12
13
  {
13
14
  q: "Which devices are compatible?",
14
- a: "Most modern smartphones, tablets, and smartwatches support eSIM including iPhone XS and later, Samsung Galaxy S21+, Google Pixel 3a+, and many more.",
15
+ a: "iPhone XS and later, recent Google Pixels, Samsung Galaxy S21 and newer, and most modern iPads. If your phone can add a cellular plan in Settings, you are set.",
15
16
  },
16
17
  {
17
- q: "How quickly does the eSIM activate?",
18
- a: "Activation is immediate after purchase. You will receive a QR code by email within seconds. Scan it in your device settings and you are connected.",
18
+ q: "How fast is activation?",
19
+ a: "The QR code arrives by email as soon as payment clears. Scan it before you fly or after you land.",
19
20
  },
20
21
  {
21
- q: "What happens when my data runs out?",
22
- a: "You will receive a notification when you are running low. You can purchase a top-up or a new plan from the dashboard at any time.",
22
+ q: "What happens when data runs low?",
23
+ a: "You get a warning, then you can top up or buy another plan from the dashboard. We do not cut you off without telling you.",
23
24
  },
24
25
  {
25
- q: "Can I use my eSIM in multiple countries?",
26
- a: "Yes regional plans cover multiple countries. Check the plan details for the exact coverage area before purchasing.",
26
+ q: "Can I use one plan in several countries?",
27
+ a: "Regional and nomad plans cover more than one country. The card lists coverage before you pay.",
27
28
  },
28
29
  ];
29
30
 
30
31
  function FaqItem({ q, a }: { q: string; a: string }) {
31
32
  const [open, setOpen] = useState(false);
32
33
  return (
33
- <div className="border-b border-white/10">
34
+ <div className="border-b border-sand-200 dark:border-sand-800">
34
35
  <button
35
- className="flex w-full items-center justify-between py-4 text-left text-white hover:text-[var(--brand-accent)] transition-colors"
36
+ className="flex w-full items-center justify-between py-4 text-left text-sand-900 transition-colors hover:text-[var(--brand-accent)] dark:text-sand-50"
36
37
  onClick={() => setOpen((o) => !o)}
37
38
  >
38
39
  <span className="font-medium">{q}</span>
39
- <span
40
- className={cn(
41
- "ml-4 shrink-0 text-[var(--brand-accent)] transition-transform",
42
- open && "rotate-45",
43
- )}
44
- >
40
+ <span className={cn("ml-4 shrink-0 text-[var(--brand-accent)] transition-transform", open && "rotate-45")}>
45
41
  +
46
42
  </span>
47
43
  </button>
@@ -54,7 +50,7 @@ function FaqItem({ q, a }: { q: string; a: string }) {
54
50
  transition={{ duration: 0.2 }}
55
51
  className="overflow-hidden"
56
52
  >
57
- <p className="pb-4 text-sm text-white/60">{a}</p>
53
+ <p className="pb-4 text-sm leading-relaxed text-sand-600 dark:text-sand-400">{a}</p>
58
54
  </motion.div>
59
55
  )}
60
56
  </AnimatePresence>
@@ -64,16 +60,17 @@ function FaqItem({ q, a }: { q: string; a: string }) {
64
60
 
65
61
  export function FaqSection() {
66
62
  return (
67
- <section className="py-24 bg-[var(--brand-bg)]">
68
- <div className="mx-auto max-w-2xl px-4">
69
- <h2 className="text-3xl font-bold text-white text-center mb-12">
70
- Frequently asked questions
63
+ <section className="px-4 py-20">
64
+ <div className="mx-auto max-w-2xl">
65
+ <h2 className="mb-10 text-center text-3xl font-semibold tracking-tight text-sand-900 dark:text-sand-50">
66
+ Questions, answered
71
67
  </h2>
72
- <div>
73
- {FAQS.map((faq) => (
74
- <FaqItem key={faq.q} q={faq.q} a={faq.a} />
75
- ))}
76
- </div>
68
+ {FAQS.map((faq) => (
69
+ <FaqItem key={faq.q} q={faq.q} a={faq.a} />
70
+ ))}
71
+ <p className="mt-8 text-center text-sm text-sand-500">
72
+ Still stuck? WhatsApp {brand.name} — real humans, 24/7.
73
+ </p>
77
74
  </div>
78
75
  </section>
79
76
  );