@carrierllc/mcp 0.2.18 → 0.2.20

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 (45) hide show
  1. package/README.md +22 -1
  2. package/dist/chunk-NHQDO2E7.js +461 -0
  3. package/dist/chunk-NHQDO2E7.js.map +1 -0
  4. package/dist/cli.js +877 -148
  5. package/dist/cli.js.map +1 -1
  6. package/dist/index.js +148 -297
  7. package/dist/index.js.map +1 -1
  8. package/package.json +6 -6
  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/package-lock.json +12722 -0
  13. package/templates/storefront/package.json +3 -3
  14. package/templates/storefront/public/brand/logo.svg +13 -0
  15. package/templates/storefront/src/app/activate/[orderId]/ActivateClient.tsx +12 -12
  16. package/templates/storefront/src/app/checkout/[templateId]/CheckoutClient.tsx +5 -5
  17. package/templates/storefront/src/app/checkout/success/CheckoutSuccessClient.tsx +29 -29
  18. package/templates/storefront/src/app/checkout/success/page.tsx +1 -1
  19. package/templates/storefront/src/app/contact/page.tsx +33 -25
  20. package/templates/storefront/src/app/dashboard/page.tsx +7 -4
  21. package/templates/storefront/src/app/globals.css +72 -82
  22. package/templates/storefront/src/app/help/page.tsx +22 -17
  23. package/templates/storefront/src/app/layout.tsx +15 -4
  24. package/templates/storefront/src/app/page.tsx +16 -7
  25. package/templates/storefront/src/app/shop/ShopClient.tsx +7 -3
  26. package/templates/storefront/src/app/sign-in/[[...sign-in]]/page.tsx +1 -1
  27. package/templates/storefront/src/app/sign-up/[[...sign-up]]/StorefrontSignUpClient.tsx +16 -16
  28. package/templates/storefront/src/app/sign-up/[[...sign-up]]/page.tsx +1 -1
  29. package/templates/storefront/src/brand.config.ts +3 -3
  30. package/templates/storefront/src/components/faq/FaqSection.tsx +23 -26
  31. package/templates/storefront/src/components/footer/StorefrontFooter.tsx +37 -22
  32. package/templates/storefront/src/components/landing/FinalCTA.tsx +28 -0
  33. package/templates/storefront/src/components/landing/HeroSection.tsx +57 -24
  34. package/templates/storefront/src/components/landing/HowItWorks.tsx +44 -0
  35. package/templates/storefront/src/components/landing/PlanCard.tsx +58 -28
  36. package/templates/storefront/src/components/nav/StorefrontNav.tsx +59 -24
  37. package/templates/storefront/src/components/theme/BrandStyles.tsx +8 -0
  38. package/templates/storefront/src/components/theme/ThemeToggle.tsx +27 -0
  39. package/templates/storefront/src/components/theme/clerk-appearance.ts +33 -35
  40. package/templates/storefront/src/components/theme/theme-provider.tsx +25 -32
  41. package/templates/storefront/src/components/theme/theme-script.tsx +4 -7
  42. package/templates/storefront/src/lib/checkout-order-claim.ts +16 -2
  43. package/templates/storefront/src/lib/complete-email-sign-up.ts +3 -3
  44. package/templates/storefront/src/lib/verify-checkout-session.ts +19 -2
  45. package/templates/storefront/src/vendor/ui/brand.ts +6 -6
@@ -17,7 +17,7 @@
17
17
  "clsx": "^2.1.1",
18
18
  "framer-motion": "^11.15.0",
19
19
  "geist": "^1.3.1",
20
- "next": "^15.3.0",
20
+ "next": "^16.3.0",
21
21
  "react": "^19.0.0",
22
22
  "react-dom": "^19.0.0",
23
23
  "tailwind-merge": "^2.6.0"
@@ -29,8 +29,8 @@
29
29
  "@types/node": "^22.0.0",
30
30
  "@types/react": "^19.0.0",
31
31
  "@types/react-dom": "^19.0.0",
32
- "eslint": "^9.0.0",
33
- "eslint-config-next": "^15.3.0",
32
+ "eslint": "^10.8.1",
33
+ "eslint-config-next": "^16.3.0",
34
34
  "tailwindcss": "^4.1.4",
35
35
  "typescript": "^5.8.0",
36
36
  "wrangler": "^4.94.0"
@@ -0,0 +1,13 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512" role="img" aria-label="Carrier logo">
3
+ <defs>
4
+ <linearGradient id="lgcf797g" x1="0" y1="0" x2="1" y2="1">
5
+ <stop offset="0%" stop-color="#ff9c75"/>
6
+ <stop offset="55%" stop-color="#FF6B35"/>
7
+ <stop offset="100%" stop-color="#984625"/>
8
+ </linearGradient>
9
+ </defs>
10
+ <rect width="512" height="512" rx="96" fill="#FAFAF7"/>
11
+ <path d="M256 64 C320 64 400 96 424 176 C448 256 424 352 344 416 C280 464 232 464 168 416 C88 352 64 256 88 176 C112 96 192 64 256 64 Z" fill="url(#lgcf797g)"/>
12
+ <text x="256" y="300" text-anchor="middle" font-family="Georgia, 'Times New Roman', serif" font-size="220" font-weight="700" fill="#FFF8EB">C</text>
13
+ </svg>
@@ -51,34 +51,34 @@ export function ActivateClient({ orderId }: Props) {
51
51
  <div className="inline-flex items-center justify-center size-14 rounded-full bg-emerald-500/10 border border-emerald-500/30 mb-4">
52
52
  <span className="text-2xl">✓</span>
53
53
  </div>
54
- <h1 className="text-2xl font-bold text-white">Your eSIM is ready</h1>
55
- <p className="mt-2 text-sm text-white/50">Order: {orderId}</p>
54
+ <h1 className="text-2xl font-bold text-sand-900 dark:text-sand-50">Your eSIM is ready</h1>
55
+ <p className="mt-2 text-sm text-sand-500">Order: {orderId}</p>
56
56
  </div>
57
57
 
58
58
  {/* QR Code placeholder */}
59
- <div className="rounded-2xl border border-white/10 bg-white/5 p-8 text-center mb-8">
60
- <p className="text-white/60 text-sm mb-2">
59
+ <div className="rounded-2xl border border-sand-200 dark:border-sand-800 bg-white dark:bg-sand-900 p-8 text-center mb-8">
60
+ <p className="text-sand-600 dark:text-sand-400 text-sm mb-2">
61
61
  Your QR code will appear here once your order is confirmed.
62
62
  </p>
63
- <p className="text-white/30 text-xs">
63
+ <p className="text-sand-400 text-xs">
64
64
  This usually takes less than a minute. Refresh if needed.
65
65
  </p>
66
66
  </div>
67
67
 
68
68
  {/* Optional phone / WhatsApp collection */}
69
- <div className="rounded-2xl border border-white/10 bg-white/5 p-6">
69
+ <div className="rounded-2xl border border-sand-200 dark:border-sand-800 bg-white dark:bg-sand-900 p-6">
70
70
  <div className="flex items-start gap-3 mb-4">
71
71
  <div className="shrink-0 mt-0.5">
72
- <span className="inline-flex items-center justify-center size-5 rounded-full bg-white/10 text-[10px] text-white/50">
72
+ <span className="inline-flex items-center justify-center size-5 rounded-full bg-white/10 text-[10px] text-sand-500">
73
73
  ?
74
74
  </span>
75
75
  </div>
76
76
  <div>
77
- <p className="text-sm font-medium text-white">
77
+ <p className="text-sm font-medium text-sand-900 dark:text-sand-50">
78
78
  Get eSIM updates via WhatsApp{" "}
79
- <span className="text-white/30 font-normal">(optional)</span>
79
+ <span className="text-sand-400 font-normal">(optional)</span>
80
80
  </p>
81
- <p className="text-xs text-white/40 mt-0.5">
81
+ <p className="text-xs text-sand-500 mt-0.5">
82
82
  We&apos;ll send your QR code and activation status. You can skip this.
83
83
  </p>
84
84
  </div>
@@ -97,7 +97,7 @@ export function ActivateClient({ orderId }: Props) {
97
97
  value={phone}
98
98
  onChange={(e) => setPhone(e.target.value)}
99
99
  placeholder="+1 555 000 0000"
100
- className="flex-1 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"
100
+ className="flex-1 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"
101
101
  />
102
102
  <button
103
103
  type="submit"
@@ -113,7 +113,7 @@ export function ActivateClient({ orderId }: Props) {
113
113
  <button
114
114
  type="button"
115
115
  onClick={() => setSubmitted(true)}
116
- className="w-full text-center text-xs text-white/30 hover:text-white/50 py-1"
116
+ className="w-full text-center text-xs text-sand-400 hover:text-sand-500 py-1"
117
117
  >
118
118
  Skip for now
119
119
  </button>
@@ -86,11 +86,11 @@ export function CheckoutClient({ plan, session }: Props) {
86
86
  if (checkoutError) {
87
87
  return (
88
88
  <div className="mx-auto max-w-lg px-4 py-32 text-center">
89
- <p className="text-white/80">{checkoutError}</p>
90
- <p className="text-sm text-white/30 mt-2">{plan.name}</p>
89
+ <p className="text-sand-700 dark:text-sand-200">{checkoutError}</p>
90
+ <p className="text-sm text-sand-400 mt-2">{plan.name}</p>
91
91
  <a
92
92
  href="/shop"
93
- className="mt-6 inline-block rounded-full border border-white/20 px-6 py-2 text-sm text-white hover:bg-white/10 transition-colors"
93
+ className="mt-6 inline-block rounded-full border border-sand-300 dark:border-sand-700 px-6 py-2 text-sm text-sand-900 dark:text-sand-50 hover:bg-white/10 transition-colors"
94
94
  >
95
95
  ← Back to shop
96
96
  </a>
@@ -101,10 +101,10 @@ export function CheckoutClient({ plan, session }: Props) {
101
101
  return (
102
102
  <div className="mx-auto max-w-lg px-4 py-32 text-center">
103
103
  <div className="h-8 w-8 rounded-full border-2 border-[var(--brand-accent)] border-t-transparent animate-spin mx-auto mb-4" />
104
- <p className="text-white/60">
104
+ <p className="text-sand-600 dark:text-sand-400">
105
105
  {loading ? "Preparing your checkout…" : "Redirecting to payment…"}
106
106
  </p>
107
- <p className="text-sm text-white/30 mt-2">{plan.name}</p>
107
+ <p className="text-sm text-sand-400 mt-2">{plan.name}</p>
108
108
  </div>
109
109
  );
110
110
  }
@@ -11,7 +11,7 @@
11
11
  * The orderId is verified server-side before this component renders.
12
12
  */
13
13
  import { useState, FormEvent, useEffect, useCallback } from "react";
14
- import { useSignUp, useSignIn } from "@clerk/nextjs/legacy";
14
+ import { useSignUp, useSignIn } from "@clerk/nextjs";
15
15
  import { useClerk, useAuth } from "@clerk/nextjs";
16
16
  import { useRouter } from "next/navigation";
17
17
  import { completeEmailSignUpAfterVerify } from "@/lib/complete-email-sign-up";
@@ -166,7 +166,7 @@ export function CheckoutSuccessClient({
166
166
  <div className="flex min-h-[calc(100vh-4rem)] items-center justify-center px-4">
167
167
  <div className="text-center space-y-3">
168
168
  <div className="mx-auto size-8 animate-spin rounded-full border-2 border-[var(--brand-accent)] border-t-transparent" />
169
- <p className="text-sm text-white/60">
169
+ <p className="text-sm text-sand-600 dark:text-sand-400">
170
170
  {step === "redirecting" ? "Activating your eSIM…" : "Loading…"}
171
171
  </p>
172
172
  </div>
@@ -181,8 +181,8 @@ export function CheckoutSuccessClient({
181
181
  <div className="rounded-2xl border border-emerald-500/30 bg-emerald-500/10 px-6 py-4">
182
182
  <p className="text-lg font-semibold text-emerald-300">✓ Payment successful!</p>
183
183
  </div>
184
- <div className="rounded-2xl border border-white/10 bg-white/5 p-8 backdrop-blur space-y-4">
185
- <p className="text-sm text-white/80">We could not link this purchase to your account.</p>
184
+ <div className="rounded-2xl border border-sand-200 dark:border-sand-800 bg-white dark:bg-sand-900 p-8 backdrop-blur space-y-4">
185
+ <p className="text-sm text-sand-700 dark:text-sand-200">We could not link this purchase to your account.</p>
186
186
  {error && (
187
187
  <p className="rounded-lg border border-red-500/30 bg-red-500/10 px-3 py-2 text-xs text-red-300">
188
188
  {error}
@@ -213,17 +213,17 @@ export function CheckoutSuccessClient({
213
213
  </div>
214
214
 
215
215
  {/* Auth card */}
216
- <div className="rounded-2xl border border-white/10 bg-white/5 p-8 backdrop-blur">
216
+ <div className="rounded-2xl border border-sand-200 dark:border-sand-800 bg-white dark:bg-sand-900 p-8 backdrop-blur">
217
217
  {/* Mode toggle */}
218
218
  {step === "credentials" && (
219
- <div className="flex rounded-lg border border-white/10 p-1 mb-6">
219
+ <div className="flex rounded-lg border border-sand-200 dark:border-sand-800 p-1 mb-6">
220
220
  <button
221
221
  type="button"
222
222
  onClick={() => { setMode("signup"); setError(null); }}
223
223
  className={`flex-1 rounded-md py-1.5 text-sm font-medium transition-colors ${
224
224
  mode === "signup"
225
- ? "bg-[var(--brand-accent)] text-white"
226
- : "text-white/40 hover:text-white/70"
225
+ ? "bg-[var(--brand-accent)] text-sand-900 dark:text-sand-50"
226
+ : "text-sand-500 hover:text-sand-600 dark:text-sand-300"
227
227
  }`}
228
228
  >
229
229
  Create account
@@ -233,8 +233,8 @@ export function CheckoutSuccessClient({
233
233
  onClick={() => { setMode("signin"); setError(null); }}
234
234
  className={`flex-1 rounded-md py-1.5 text-sm font-medium transition-colors ${
235
235
  mode === "signin"
236
- ? "bg-[var(--brand-accent)] text-white"
237
- : "text-white/40 hover:text-white/70"
236
+ ? "bg-[var(--brand-accent)] text-sand-900 dark:text-sand-50"
237
+ : "text-sand-500 hover:text-sand-600 dark:text-sand-300"
238
238
  }`}
239
239
  >
240
240
  Sign in
@@ -245,15 +245,15 @@ export function CheckoutSuccessClient({
245
245
  {/* Sign-up: credentials step */}
246
246
  {step === "credentials" && mode === "signup" && (
247
247
  <>
248
- <h2 className="text-base font-semibold text-white mb-1">Create your account</h2>
249
- <p className="text-xs text-white/40 mb-5">
248
+ <h2 className="text-base font-semibold text-sand-900 dark:text-sand-50 mb-1">Create your account</h2>
249
+ <p className="text-xs text-sand-500 mb-5">
250
250
  {emailLocked
251
251
  ? "Use the email from your checkout to create your account."
252
252
  : "Email and password — no phone required."}
253
253
  </p>
254
254
  <form onSubmit={handleSignUp} className="space-y-4">
255
255
  <div>
256
- <label className="block text-xs font-medium text-white/60 mb-1" htmlFor="su-email">
256
+ <label className="block text-xs font-medium text-sand-600 dark:text-sand-400 mb-1" htmlFor="su-email">
257
257
  Email address
258
258
  </label>
259
259
  <input
@@ -264,12 +264,12 @@ export function CheckoutSuccessClient({
264
264
  readOnly={emailLocked}
265
265
  value={email}
266
266
  onChange={(e) => setEmail(e.target.value)}
267
- 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"
267
+ 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"
268
268
  placeholder="you@example.com"
269
269
  />
270
270
  </div>
271
271
  <div>
272
- <label className="block text-xs font-medium text-white/60 mb-1" htmlFor="su-password">
272
+ <label className="block text-xs font-medium text-sand-600 dark:text-sand-400 mb-1" htmlFor="su-password">
273
273
  Password
274
274
  </label>
275
275
  <input
@@ -280,7 +280,7 @@ export function CheckoutSuccessClient({
280
280
  minLength={8}
281
281
  value={password}
282
282
  onChange={(e) => setPassword(e.target.value)}
283
- 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"
283
+ 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"
284
284
  placeholder="Min. 8 characters"
285
285
  />
286
286
  </div>
@@ -303,15 +303,15 @@ export function CheckoutSuccessClient({
303
303
  {/* Sign-in: credentials step */}
304
304
  {step === "credentials" && mode === "signin" && (
305
305
  <>
306
- <h2 className="text-base font-semibold text-white mb-1">Sign in</h2>
307
- <p className="text-xs text-white/40 mb-5">
306
+ <h2 className="text-base font-semibold text-sand-900 dark:text-sand-50 mb-1">Sign in</h2>
307
+ <p className="text-xs text-sand-500 mb-5">
308
308
  {emailLocked
309
309
  ? "Sign in with the email from your checkout to activate your eSIM."
310
310
  : "Sign in to activate your eSIM."}
311
311
  </p>
312
312
  <form onSubmit={handleSignIn} className="space-y-4">
313
313
  <div>
314
- <label className="block text-xs font-medium text-white/60 mb-1" htmlFor="si-email">
314
+ <label className="block text-xs font-medium text-sand-600 dark:text-sand-400 mb-1" htmlFor="si-email">
315
315
  Email address
316
316
  </label>
317
317
  <input
@@ -322,12 +322,12 @@ export function CheckoutSuccessClient({
322
322
  readOnly={emailLocked}
323
323
  value={email}
324
324
  onChange={(e) => setEmail(e.target.value)}
325
- 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"
325
+ 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"
326
326
  placeholder="you@example.com"
327
327
  />
328
328
  </div>
329
329
  <div>
330
- <label className="block text-xs font-medium text-white/60 mb-1" htmlFor="si-password">
330
+ <label className="block text-xs font-medium text-sand-600 dark:text-sand-400 mb-1" htmlFor="si-password">
331
331
  Password
332
332
  </label>
333
333
  <input
@@ -337,7 +337,7 @@ export function CheckoutSuccessClient({
337
337
  required
338
338
  value={password}
339
339
  onChange={(e) => setPassword(e.target.value)}
340
- 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"
340
+ 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"
341
341
  placeholder="Your password"
342
342
  />
343
343
  </div>
@@ -360,13 +360,13 @@ export function CheckoutSuccessClient({
360
360
  {/* Email verification step */}
361
361
  {step === "verify" && (
362
362
  <>
363
- <h2 className="text-base font-semibold text-white mb-1">Check your email</h2>
364
- <p className="text-xs text-white/40 mb-5">
365
- We sent a 6-digit code to <span className="text-white/70">{email}</span>.
363
+ <h2 className="text-base font-semibold text-sand-900 dark:text-sand-50 mb-1">Check your email</h2>
364
+ <p className="text-xs text-sand-500 mb-5">
365
+ We sent a 6-digit code to <span className="text-sand-600 dark:text-sand-300">{email}</span>.
366
366
  </p>
367
367
  <form onSubmit={handleVerify} className="space-y-4">
368
368
  <div>
369
- <label className="block text-xs font-medium text-white/60 mb-1" htmlFor="verify-code">
369
+ <label className="block text-xs font-medium text-sand-600 dark:text-sand-400 mb-1" htmlFor="verify-code">
370
370
  Verification code
371
371
  </label>
372
372
  <input
@@ -378,7 +378,7 @@ export function CheckoutSuccessClient({
378
378
  maxLength={6}
379
379
  value={code}
380
380
  onChange={(e) => setCode(e.target.value.replace(/\D/g, ""))}
381
- 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"
381
+ 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"
382
382
  placeholder="000000"
383
383
  />
384
384
  </div>
@@ -398,7 +398,7 @@ export function CheckoutSuccessClient({
398
398
  <button
399
399
  type="button"
400
400
  onClick={() => { setStep("credentials"); setError(null); setCode(""); }}
401
- className="mt-4 w-full text-center text-xs text-white/30 hover:text-white/50"
401
+ className="mt-4 w-full text-center text-xs text-sand-400 hover:text-sand-500"
402
402
  >
403
403
  ← Back
404
404
  </button>
@@ -406,7 +406,7 @@ export function CheckoutSuccessClient({
406
406
  )}
407
407
  </div>
408
408
 
409
- <p className="text-center text-xs text-white/30">
409
+ <p className="text-center text-xs text-sand-400">
410
410
  Your payment is confirmed. Account setup is required to receive your eSIM QR code.
411
411
  </p>
412
412
  </div>
@@ -43,7 +43,7 @@ export default async function CheckoutSuccessPage({ searchParams }: Props) {
43
43
  <div className="flex min-h-[calc(100vh-4rem)] items-center justify-center px-4">
44
44
  <div className="text-center space-y-3">
45
45
  <div className="mx-auto size-8 animate-spin rounded-full border-2 border-[var(--brand-accent)] border-t-transparent" />
46
- <p className="text-sm text-white/60">Loading…</p>
46
+ <p className="text-sm text-sand-600 dark:text-sand-400">Loading…</p>
47
47
  </div>
48
48
  </div>
49
49
  }
@@ -1,34 +1,42 @@
1
+ import Link from "next/link";
1
2
  import brand from "@/brand.config";
3
+ import { buildSupportLink } from "@/vendor/ui/brand";
2
4
 
3
5
  export const metadata = { title: "Contact" };
4
6
 
5
7
  export default function ContactPage() {
6
8
  return (
7
- <div className="mx-auto max-w-2xl px-4 py-24">
8
- <h1 className="text-3xl font-bold text-white mb-8">Get in touch</h1>
9
- <div className="space-y-4 text-white/70">
10
- <p>
11
- Email:{" "}
12
- <a
13
- href={`mailto:${brand.supportEmail}`}
14
- className="text-[var(--brand-accent)] hover:underline"
15
- >
16
- {brand.supportEmail}
17
- </a>
18
- </p>
19
- {brand.supportWhatsapp && (
20
- <p>
21
- WhatsApp:{" "}
22
- <a
23
- href={`https://wa.me/${brand.supportWhatsapp.replace(/[^0-9]/g, "")}`}
24
- target="_blank"
25
- rel="noopener noreferrer"
26
- className="text-[var(--brand-accent)] hover:underline"
27
- >
28
- {brand.supportWhatsapp}
29
- </a>
30
- </p>
31
- )}
9
+ <div className="mx-auto max-w-2xl px-4 py-16">
10
+ <h1 className="text-3xl font-semibold tracking-tight text-sand-900 dark:text-sand-50">
11
+ Get in touch
12
+ </h1>
13
+ <p className="mt-2 mb-10 text-sand-600 dark:text-sand-400">
14
+ Real humans. 24/7. Pick the channel you already have open.
15
+ </p>
16
+ <div className="space-y-3">
17
+ <Link
18
+ href={buildSupportLink("whatsapp", { message: `Hi ${brand.name}!` })}
19
+ target="_blank"
20
+ rel="noopener noreferrer"
21
+ className="flex items-center justify-between rounded-2xl border border-sand-200 bg-white px-5 py-4 text-sand-900 dark:border-sand-800 dark:bg-sand-900 dark:text-sand-50"
22
+ >
23
+ <span className="font-medium">WhatsApp</span>
24
+ <span className="text-sm text-sand-500">24/7</span>
25
+ </Link>
26
+ <Link
27
+ href={buildSupportLink("sms")}
28
+ className="flex items-center justify-between rounded-2xl border border-sand-200 bg-white px-5 py-4 text-sand-900 dark:border-sand-800 dark:bg-sand-900 dark:text-sand-50"
29
+ >
30
+ <span className="font-medium">SMS</span>
31
+ <span className="text-sm text-sand-500">{brand.supportWhatsapp}</span>
32
+ </Link>
33
+ <a
34
+ href={`mailto:${brand.supportEmail}`}
35
+ className="flex items-center justify-between rounded-2xl border border-sand-200 bg-white px-5 py-4 text-sand-900 dark:border-sand-800 dark:bg-sand-900 dark:text-sand-50"
36
+ >
37
+ <span className="font-medium">Email</span>
38
+ <span className="text-sm text-sand-500">{brand.supportEmail}</span>
39
+ </a>
32
40
  </div>
33
41
  </div>
34
42
  );
@@ -11,12 +11,15 @@ export default async function DashboardPage() {
11
11
 
12
12
  return (
13
13
  <div className="mx-auto max-w-4xl px-4 py-16">
14
- <h1 className="text-3xl font-bold text-white mb-8">Your eSIMs</h1>
15
- <div className="rounded-2xl border border-white/10 bg-white/5 p-12 text-center">
16
- <p className="text-white/50">No active eSIMs yet.</p>
14
+ <h1 className="mb-8 text-3xl font-semibold tracking-tight text-sand-900 dark:text-sand-50">
15
+ Your eSIMs
16
+ </h1>
17
+ <div className="rounded-2xl border border-sand-200 bg-white p-12 text-center dark:border-sand-800 dark:bg-sand-900">
18
+ <p className="text-sand-500">No active eSIMs yet.</p>
17
19
  <a
18
20
  href="/shop"
19
- className="mt-4 inline-block rounded-full bg-[var(--brand-accent)] px-6 py-2 text-sm font-semibold text-white hover:bg-[var(--brand-accent-dark)] transition-colors"
21
+ className="mt-4 inline-block rounded-full px-6 py-2 text-sm font-semibold text-white transition-opacity hover:opacity-90"
22
+ style={{ background: "var(--brand-accent)" }}
20
23
  >
21
24
  Browse plans
22
25
  </a>
@@ -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
  }