brand identity overhaul: match BRAND-IDENTITY.md across all pages

Design system changes (per brand guide):
- ZERO rounded-2xl/3xl remaining (was 131 instances)
- ZERO bg-gradient remaining (was 25) — all solid colors
- ZERO colored shadows (shadow-trust-blue, etc) — flat, no glow
- ZERO backdrop-blur/glass effects — solid backgrounds
- ZERO emoji in logo marks — square P logomark everywhere
- ZERO decorative scale animations (group-hover:scale-105, etc)

Tailwind config:
- Added brand color names: midnight, promise-blue, generosity-gold, fulfilled-green, alert-red, paper
- Kept legacy aliases (trust-blue, etc) for backwards compat
- --radius: 0.75rem → 0.5rem (tighter corners)

CSS:
- Removed glass, glass-dark, card-hover, pulse-ring, bounce-gentle, confetti-fall, scale-in animations
- Kept only purposeful animations: fadeUp, fadeIn, slideDown, shimmer, counter-roll
- --primary tuned to match Promise Blue exactly

Components:
- Button: removed all colored shadows, added 'blue' variant, removed rounded from sizes
- All UI components: rounded-xl/2xl → rounded-lg

Pages updated (41 files):
- Dashboard layout: solid header (no blur), border-l-2 active indicator, midnight logo mark
- Login/Signup: paper bg (no gradient), midnight logo mark, no emoji
- Pledge flow: solid color icons, no gradient progress bars
- All dashboard pages: flat, sharp, editorial
This commit is contained in:
2026-03-03 20:13:22 +08:00
parent f4ad6df45a
commit fc80399092
41 changed files with 282 additions and 475 deletions

View File

@@ -33,58 +33,56 @@ function LoginForm() {
}
}
// Auto-login as demo if ?demo=1
// eslint-disable-next-line react-hooks/exhaustive-deps
useEffect(() => { if (isDemo) doLogin(undefined, "demo@pnpl.app", "demo1234") }, [])
return (
<div className="min-h-screen flex items-center justify-center bg-gradient-to-br from-trust-blue/5 via-white to-warm-amber/5 p-4">
<div className="w-full max-w-sm space-y-5">
<div className="min-h-screen flex items-center justify-center bg-paper p-4">
<div className="w-full max-w-sm space-y-6">
{isDemo && (
<div className="text-center py-8">
<div className="inline-flex h-12 w-12 rounded-2xl bg-gradient-to-br from-trust-blue to-blue-600 items-center justify-center shadow-lg shadow-trust-blue/20 animate-pulse mb-3">
<span className="text-white text-xl">🤲</span>
<div className="text-center py-12">
<div className="h-10 w-10 bg-midnight flex items-center justify-center mx-auto mb-4">
<span className="text-white text-sm font-black">P</span>
</div>
<p className="text-sm font-medium text-trust-blue animate-pulse">Loading demo...</p>
<p className="text-sm font-medium text-gray-500">Loading demo...</p>
</div>
)}
{!isDemo && (
<>
<div className="text-center">
<div className="inline-flex h-12 w-12 rounded-2xl bg-gradient-to-br from-trust-blue to-blue-600 items-center justify-center shadow-lg shadow-trust-blue/20 mb-3">
<span className="text-white text-xl">🤲</span>
<div className="text-center space-y-3">
<div className="h-10 w-10 bg-midnight flex items-center justify-center mx-auto">
<span className="text-white text-sm font-black">P</span>
</div>
<div>
<h1 className="text-2xl font-black text-midnight">Welcome back</h1>
<p className="text-sm text-gray-500 mt-1">Sign in to your charity dashboard</p>
</div>
<h1 className="text-2xl font-black text-gray-900">Welcome back</h1>
<p className="text-sm text-muted-foreground mt-1">Sign in to your charity dashboard</p>
</div>
{/* Social login */}
<div className="space-y-2">
<button
onClick={() => signIn("auth0", { callbackUrl: "/dashboard" })}
className="w-full flex items-center justify-center gap-2 rounded-xl border border-gray-200 bg-white px-4 py-3 text-sm font-medium text-gray-700 hover:bg-gray-50 transition-all"
>
<svg className="h-4 w-4" viewBox="0 0 24 24"><path d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92a5.06 5.06 0 01-2.2 3.32v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.1z" fill="#4285F4"/><path d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z" fill="#34A853"/><path d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z" fill="#FBBC05"/><path d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z" fill="#EA4335"/></svg>
Continue with Google
</button>
</div>
{/* Google */}
<button
onClick={() => signIn("auth0", { callbackUrl: "/dashboard" })}
className="w-full flex items-center justify-center gap-2 border border-gray-200 bg-white px-4 py-3 text-sm font-medium text-gray-700 hover:bg-gray-50 transition-colors"
>
<svg className="h-4 w-4" viewBox="0 0 24 24"><path d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92a5.06 5.06 0 01-2.2 3.32v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.1z" fill="#4285F4"/><path d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z" fill="#34A853"/><path d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z" fill="#FBBC05"/><path d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z" fill="#EA4335"/></svg>
Continue with Google
</button>
<div className="relative">
<div className="absolute inset-0 flex items-center"><div className="w-full border-t" /></div>
<div className="relative flex justify-center text-xs"><span className="bg-gradient-to-br from-trust-blue/5 via-white to-warm-amber/5 px-3 text-muted-foreground">or sign in with email</span></div>
<div className="absolute inset-0 flex items-center"><div className="w-full border-t border-gray-200" /></div>
<div className="relative flex justify-center text-xs"><span className="bg-paper px-3 text-gray-400">or sign in with email</span></div>
</div>
{/* Email/password form */}
<form onSubmit={(e) => doLogin(e)} className="space-y-3">
{error && (
<div className="rounded-xl bg-danger-red/10 border border-danger-red/20 p-2.5 text-sm text-danger-red text-center">{error}</div>
<div className="border border-alert-red/20 bg-alert-red/5 p-2.5 text-sm text-alert-red text-center">{error}</div>
)}
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
className="w-full rounded-xl border border-gray-200 px-4 py-3 text-sm focus:border-trust-blue focus:ring-2 focus:ring-trust-blue/20 outline-none transition-all"
className="w-full border border-gray-200 px-4 py-3 text-sm focus:border-promise-blue focus:ring-1 focus:ring-promise-blue/20 outline-none transition-colors"
placeholder="Email"
required
/>
@@ -92,36 +90,36 @@ function LoginForm() {
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
className="w-full rounded-xl border border-gray-200 px-4 py-3 text-sm focus:border-trust-blue focus:ring-2 focus:ring-trust-blue/20 outline-none transition-all"
className="w-full border border-gray-200 px-4 py-3 text-sm focus:border-promise-blue focus:ring-1 focus:ring-promise-blue/20 outline-none transition-colors"
placeholder="Password"
required
/>
<button
type="submit"
disabled={loading}
className="w-full rounded-xl bg-trust-blue px-4 py-3 text-sm font-semibold text-white hover:bg-trust-blue/90 disabled:opacity-50 transition-all"
className="w-full bg-midnight px-4 py-3 text-sm font-semibold text-white hover:bg-gray-800 disabled:opacity-50 transition-colors"
>
{loading ? "Signing in..." : "Sign In"}
</button>
</form>
<div className="relative">
<div className="absolute inset-0 flex items-center"><div className="w-full border-t" /></div>
<div className="relative flex justify-center text-xs"><span className="bg-gradient-to-br from-trust-blue/5 via-white to-warm-amber/5 px-2 text-muted-foreground">or</span></div>
<div className="absolute inset-0 flex items-center"><div className="w-full border-t border-gray-200" /></div>
<div className="relative flex justify-center text-xs"><span className="bg-paper px-2 text-gray-400">or</span></div>
</div>
<button
type="button"
onClick={() => doLogin(undefined, "demo@pnpl.app", "demo1234")}
disabled={loading}
className="w-full rounded-xl border-2 border-dashed border-gray-200 px-4 py-3 text-sm font-medium text-muted-foreground hover:border-trust-blue hover:text-trust-blue disabled:opacity-50 transition-all"
className="w-full border border-dashed border-gray-300 px-4 py-3 text-sm font-medium text-gray-500 hover:border-promise-blue hover:text-promise-blue disabled:opacity-50 transition-colors"
>
🎮 Try the Demo no signup needed
Try the Demo no signup needed
</button>
<p className="text-center text-sm text-muted-foreground">
<p className="text-center text-sm text-gray-500">
Don&apos;t have an account?{" "}
<Link href="/signup" className="text-trust-blue font-semibold hover:underline">Get Started Free</Link>
<Link href="/signup" className="text-promise-blue font-semibold hover:underline">Get Started Free</Link>
</p>
</>
)}
@@ -132,7 +130,7 @@ function LoginForm() {
export default function LoginPage() {
return (
<Suspense fallback={<div className="min-h-screen flex items-center justify-center"><div className="animate-spin h-8 w-8 border-2 border-trust-blue border-t-transparent rounded-full" /></div>}>
<Suspense fallback={<div className="min-h-screen flex items-center justify-center bg-paper"><div className="animate-spin h-6 w-6 border-2 border-promise-blue border-t-transparent rounded-full" /></div>}>
<LoginForm />
</Suspense>
)

View File

@@ -38,7 +38,6 @@ export default function SignupPage() {
return
}
// Auto sign in and go straight to dashboard
const result = await signIn("credentials", { email, password, redirect: false })
if (result?.error) {
setError("Account created — please sign in")
@@ -54,86 +53,83 @@ export default function SignupPage() {
if (step === "loading") {
return (
<div className="min-h-screen flex items-center justify-center bg-gradient-to-br from-trust-blue/5 via-white to-warm-amber/5">
<div className="min-h-screen flex items-center justify-center bg-paper">
<div className="text-center space-y-4">
<div className="inline-flex h-14 w-14 rounded-2xl bg-gradient-to-br from-trust-blue to-blue-600 items-center justify-center shadow-lg shadow-trust-blue/20 animate-pulse">
<span className="text-white text-2xl">🤲</span>
<div className="h-10 w-10 bg-midnight flex items-center justify-center mx-auto">
<span className="text-white text-sm font-black">P</span>
</div>
<p className="text-sm font-medium text-trust-blue animate-pulse">Setting up your charity...</p>
<p className="text-sm font-medium text-gray-500">Setting up your charity...</p>
</div>
</div>
)
}
return (
<div className="min-h-screen flex items-center justify-center bg-gradient-to-br from-trust-blue/5 via-white to-warm-amber/5 p-4">
<div className="w-full max-w-sm space-y-5">
<div className="text-center">
<div className="inline-flex h-12 w-12 rounded-2xl bg-gradient-to-br from-trust-blue to-blue-600 items-center justify-center shadow-lg shadow-trust-blue/20 mb-3">
<span className="text-white text-xl">🤲</span>
<div className="min-h-screen flex items-center justify-center bg-paper p-4">
<div className="w-full max-w-sm space-y-6">
<div className="text-center space-y-3">
<div className="h-10 w-10 bg-midnight flex items-center justify-center mx-auto">
<span className="text-white text-sm font-black">P</span>
</div>
<div>
<h1 className="text-2xl font-black text-midnight">Start collecting pledges</h1>
<p className="text-sm text-gray-500 mt-1">Free. 30 seconds. No card.</p>
</div>
<h1 className="text-2xl font-black text-gray-900">Start collecting pledges</h1>
<p className="text-sm text-muted-foreground mt-1">Free. 30 seconds. No card.</p>
</div>
{/* Google signup */}
<button
onClick={signUpWithGoogle}
className="w-full flex items-center justify-center gap-2 rounded-xl border border-gray-200 bg-white px-4 py-3 text-sm font-medium text-gray-700 hover:bg-gray-50 transition-all"
className="w-full flex items-center justify-center gap-2 border border-gray-200 bg-white px-4 py-3 text-sm font-medium text-gray-700 hover:bg-gray-50 transition-colors"
>
<svg className="h-4 w-4" viewBox="0 0 24 24"><path d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92a5.06 5.06 0 01-2.2 3.32v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.1z" fill="#4285F4"/><path d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z" fill="#34A853"/><path d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z" fill="#FBBC05"/><path d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z" fill="#EA4335"/></svg>
Sign up with Google
</button>
<div className="relative">
<div className="absolute inset-0 flex items-center"><div className="w-full border-t" /></div>
<div className="relative flex justify-center text-xs"><span className="bg-gradient-to-br from-trust-blue/5 via-white to-warm-amber/5 px-3 text-muted-foreground">or use email</span></div>
<div className="absolute inset-0 flex items-center"><div className="w-full border-t border-gray-200" /></div>
<div className="relative flex justify-center text-xs"><span className="bg-paper px-3 text-gray-400">or use email</span></div>
</div>
<form onSubmit={handleSubmit} className="space-y-3">
{error && (
<div className="rounded-xl bg-danger-red/10 border border-danger-red/20 p-2.5 text-sm text-danger-red text-center">{error}</div>
<div className="border border-alert-red/20 bg-alert-red/5 p-2.5 text-sm text-alert-red text-center">{error}</div>
)}
<input
type="text"
value={charityName}
onChange={(e) => setCharityName(e.target.value)}
className="w-full rounded-xl border border-gray-200 px-4 py-3 text-sm focus:border-trust-blue focus:ring-2 focus:ring-trust-blue/20 outline-none transition-all"
className="w-full border border-gray-200 px-4 py-3 text-sm focus:border-promise-blue focus:ring-1 focus:ring-promise-blue/20 outline-none transition-colors"
placeholder="Your charity or mosque name"
required
autoFocus
/>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
className="w-full rounded-xl border border-gray-200 px-4 py-3 text-sm focus:border-trust-blue focus:ring-2 focus:ring-trust-blue/20 outline-none transition-all"
className="w-full border border-gray-200 px-4 py-3 text-sm focus:border-promise-blue focus:ring-1 focus:ring-promise-blue/20 outline-none transition-colors"
placeholder="Your email"
required
/>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
className="w-full rounded-xl border border-gray-200 px-4 py-3 text-sm focus:border-trust-blue focus:ring-2 focus:ring-trust-blue/20 outline-none transition-all"
className="w-full border border-gray-200 px-4 py-3 text-sm focus:border-promise-blue focus:ring-1 focus:ring-promise-blue/20 outline-none transition-colors"
placeholder="Pick a password (8+ chars)"
required
minLength={8}
/>
<button
type="submit"
className="w-full rounded-xl bg-trust-blue px-4 py-3.5 text-sm font-bold text-white hover:bg-trust-blue/90 transition-all shadow-lg shadow-trust-blue/20"
className="w-full bg-midnight px-4 py-3.5 text-sm font-bold text-white hover:bg-gray-800 transition-colors"
>
Create Account
</button>
</form>
<p className="text-center text-xs text-muted-foreground">
Already have an account? <Link href="/login" className="text-trust-blue font-semibold hover:underline">Sign in</Link>
<p className="text-center text-xs text-gray-500">
Already have an account? <Link href="/login" className="text-promise-blue font-semibold hover:underline">Sign in</Link>
</p>
</div>
</div>

View File

@@ -93,7 +93,7 @@ export default function AdminPage() {
<CardContent>
<div className="flex gap-3 overflow-x-auto">
{Object.entries(data.byStatus).map(([status, { count, amount }]) => (
<div key={status} className="flex-shrink-0 rounded-xl bg-muted/50 px-4 py-2 text-center min-w-[100px]">
<div key={status} className="flex-shrink-0 rounded-lg bg-muted/50 px-4 py-2 text-center min-w-[100px]">
<Badge variant={status === "paid" ? "success" : status === "overdue" ? "destructive" : "secondary"} className="text-[10px]">{status}</Badge>
<p className="text-lg font-bold mt-1">{count}</p>
<p className="text-[10px] text-muted-foreground">{fmt(amount)}</p>

View File

@@ -141,7 +141,7 @@ export default function CampaignLinksPage() {
<Card key={src.id} className="hover:shadow-md transition-shadow">
<CardContent className="pt-6 space-y-4">
{/* QR Code — compact */}
<div className="max-w-[140px] mx-auto bg-white rounded-xl flex items-center justify-center p-1.5">
<div className="max-w-[140px] mx-auto bg-white rounded-lg flex items-center justify-center p-1.5">
<QRCodeCanvas url={`${baseUrl}/p/${src.code}`} size={128} />
</div>

View File

@@ -250,7 +250,7 @@ export default function EventsPage() {
<button
type="button"
onClick={() => setForm(f => ({ ...f, paymentMode: "self" }))}
className={`rounded-xl border p-3 text-left text-xs transition-all ${form.paymentMode === "self" ? "border-trust-blue bg-trust-blue/5" : "border-gray-200"}`}
className={`rounded-lg border p-3 text-left text-xs transition-all ${form.paymentMode === "self" ? "border-trust-blue bg-trust-blue/5" : "border-gray-200"}`}
>
<span className="font-bold block">🏦 Bank transfer</span>
<span className="text-muted-foreground">We show our bank details</span>
@@ -258,7 +258,7 @@ export default function EventsPage() {
<button
type="button"
onClick={() => setForm(f => ({ ...f, paymentMode: "external" }))}
className={`rounded-xl border p-3 text-left text-xs transition-all ${form.paymentMode === "external" ? "border-warm-amber bg-warm-amber/5" : "border-gray-200"}`}
className={`rounded-lg border p-3 text-left text-xs transition-all ${form.paymentMode === "external" ? "border-warm-amber bg-warm-amber/5" : "border-gray-200"}`}
>
<span className="font-bold block">🔗 External page</span>
<span className="text-muted-foreground">LaunchGood, Enthuse, etc.</span>
@@ -267,7 +267,7 @@ export default function EventsPage() {
</div>
{form.paymentMode === "external" && (
<div className="space-y-3 rounded-xl border border-warm-amber/20 bg-warm-amber/5 p-3">
<div className="space-y-3 rounded-lg border border-warm-amber/20 bg-warm-amber/5 p-3">
<div className="space-y-2">
<Label>Fundraising page URL *</Label>
<div className="relative">
@@ -285,7 +285,7 @@ export default function EventsPage() {
<select
value={form.externalPlatform}
onChange={(e) => setForm(f => ({ ...f, externalPlatform: e.target.value }))}
className="w-full rounded-xl border border-gray-200 px-3 py-2 text-sm"
className="w-full rounded-lg border border-gray-200 px-3 py-2 text-sm"
>
<option value="">Select platform...</option>
<option value="launchgood">🌙 LaunchGood</option>
@@ -302,7 +302,7 @@ export default function EventsPage() {
<button
type="button"
onClick={() => setForm(f => ({ ...f, zakatEligible: !f.zakatEligible }))}
className={`w-full flex items-center justify-between rounded-xl border-2 p-3 text-left transition-all ${
className={`w-full flex items-center justify-between rounded-lg border-2 p-3 text-left transition-all ${
form.zakatEligible ? "border-trust-blue bg-trust-blue/5" : "border-gray-200"
}`}
>

View File

@@ -73,7 +73,7 @@ export default function ExportsPage() {
<li>Event and reference for audit trail</li>
</ul>
</div>
<div className="rounded-xl bg-success-green/5 border border-success-green/20 p-3">
<div className="rounded-lg bg-success-green/5 border border-success-green/20 p-3">
<p className="text-xs text-success-green font-medium">
💷 Claim 25p for every £1 donated by a UK taxpayer
</p>
@@ -101,7 +101,7 @@ export default function ExportsPage() {
</code>
<p className="text-xs">Returns pending reminders with donor contact info for external email/SMS.</p>
</div>
<div className="rounded-xl bg-trust-blue/5 border border-trust-blue/20 p-3">
<div className="rounded-lg bg-trust-blue/5 border border-trust-blue/20 p-3">
<p className="text-xs text-trust-blue font-medium">
💡 Connect to Zapier or n8n to send automatic reminder emails and SMS
</p>

View File

@@ -24,31 +24,31 @@ export default function DashboardLayout({ children }: { children: React.ReactNod
const user = session?.user as any
return (
<div className="min-h-screen bg-gray-50/50">
{/* Top bar */}
<header className="sticky top-0 z-40 border-b bg-white/80 backdrop-blur-xl">
<div className="min-h-screen bg-paper">
{/* Top bar — sharp, no blur */}
<header className="sticky top-0 z-40 border-b border-gray-200 bg-white">
<div className="flex h-14 items-center gap-4 px-4 md:px-6">
<Link href="/dashboard" className="flex items-center gap-2.5">
<div className="h-8 w-8 rounded-xl bg-gradient-to-br from-trust-blue to-blue-600 flex items-center justify-center shadow-lg shadow-trust-blue/20">
<span className="text-white font-bold text-sm">P</span>
<div className="h-7 w-7 bg-midnight flex items-center justify-center">
<span className="text-white text-xs font-black">P</span>
</div>
<div className="hidden sm:block">
<span className="font-black text-sm text-gray-900">{user?.orgName || "Pledge Now, Pay Later"}</span>
<span className="font-black text-sm text-midnight">{user?.orgName || "Pledge Now, Pay Later"}</span>
</div>
</Link>
<div className="flex-1" />
<Link href="/dashboard/events" className="hidden md:block">
<button className="inline-flex items-center gap-1.5 rounded-lg bg-trust-blue px-3 py-1.5 text-xs font-semibold text-white hover:bg-trust-blue/90 transition-colors">
<button className="inline-flex items-center gap-1.5 bg-midnight px-3 py-1.5 text-xs font-semibold text-white hover:bg-gray-800 transition-colors">
<Plus className="h-3 w-3" /> New Campaign
</button>
</Link>
<Link href="/" className="text-xs text-muted-foreground hover:text-foreground transition-colors flex items-center gap-1">
<Link href="/" className="text-xs text-gray-400 hover:text-midnight transition-colors flex items-center gap-1">
<ExternalLink className="h-3 w-3" />
</Link>
{session && (
<button
onClick={() => signOut({ callbackUrl: "/login" })}
className="text-xs text-muted-foreground hover:text-foreground transition-colors flex items-center gap-1"
className="text-xs text-gray-400 hover:text-midnight transition-colors flex items-center gap-1"
>
<LogOut className="h-3 w-3" />
</button>
@@ -57,8 +57,8 @@ export default function DashboardLayout({ children }: { children: React.ReactNod
</header>
<div className="flex">
{/* Desktop sidebar */}
<aside className="hidden md:flex w-56 flex-col border-r bg-white min-h-[calc(100vh-3.5rem)] py-3 px-2">
{/* Desktop sidebar — clean, no decorative elements */}
<aside className="hidden md:flex w-52 flex-col border-r border-gray-200 bg-white min-h-[calc(100vh-3.5rem)] py-3 px-2">
<nav className="space-y-0.5">
{navItems.map((item) => {
const isActive = pathname === item.href || (item.href !== "/dashboard" && pathname.startsWith(item.href))
@@ -67,10 +67,10 @@ export default function DashboardLayout({ children }: { children: React.ReactNod
key={item.href}
href={item.href}
className={cn(
"flex items-center gap-2.5 rounded-lg px-3 py-2 text-sm font-medium transition-colors",
"flex items-center gap-2.5 px-3 py-2 text-sm font-medium transition-colors",
isActive
? "bg-trust-blue/5 text-trust-blue"
: "text-muted-foreground hover:bg-gray-100 hover:text-foreground"
? "bg-promise-blue/5 text-promise-blue border-l-2 border-promise-blue -ml-0.5"
: "text-gray-500 hover:bg-gray-50 hover:text-midnight"
)}
>
<item.icon className="h-4 w-4" />
@@ -80,14 +80,14 @@ export default function DashboardLayout({ children }: { children: React.ReactNod
})}
{user?.role === "super_admin" && (
<>
<div className="my-2 border-t" />
<div className="my-2 border-t border-gray-100" />
<Link
href={adminNav.href}
className={cn(
"flex items-center gap-2.5 rounded-lg px-3 py-2 text-sm font-medium transition-colors",
"flex items-center gap-2.5 px-3 py-2 text-sm font-medium transition-colors",
pathname === adminNav.href
? "bg-trust-blue/5 text-trust-blue"
: "text-muted-foreground hover:bg-gray-100 hover:text-foreground"
? "bg-promise-blue/5 text-promise-blue border-l-2 border-promise-blue -ml-0.5"
: "text-gray-500 hover:bg-gray-50 hover:text-midnight"
)}
>
<adminNav.icon className="h-4 w-4" />
@@ -98,12 +98,12 @@ export default function DashboardLayout({ children }: { children: React.ReactNod
</nav>
<div className="mt-auto px-2 pt-4">
<div className="rounded-xl bg-gradient-to-br from-trust-blue/5 to-warm-amber/5 border p-3 space-y-1.5">
<p className="text-xs font-semibold">Need help?</p>
<p className="text-[10px] text-muted-foreground leading-relaxed">
<div className="border border-gray-200 p-3 space-y-1.5">
<p className="text-xs font-bold text-midnight">Need help?</p>
<p className="text-[10px] text-gray-500 leading-relaxed">
Get a fractional Head of Technology to optimise your charity&apos;s digital stack.
</p>
<Link href="/dashboard/apply" className="inline-block text-[10px] font-semibold text-trust-blue hover:underline">
<Link href="/dashboard/apply" className="inline-block text-[10px] font-semibold text-promise-blue hover:underline">
Learn more
</Link>
</div>
@@ -111,7 +111,7 @@ export default function DashboardLayout({ children }: { children: React.ReactNod
</aside>
{/* Mobile bottom nav */}
<nav className="md:hidden fixed bottom-0 left-0 right-0 z-40 border-t bg-white/95 backdrop-blur-xl flex justify-around py-1.5 px-1">
<nav className="md:hidden fixed bottom-0 left-0 right-0 z-40 border-t border-gray-200 bg-white flex justify-around py-1.5 px-1">
{navItems.slice(0, 5).map((item) => {
const isActive = pathname === item.href || (item.href !== "/dashboard" && pathname.startsWith(item.href))
return (
@@ -119,8 +119,8 @@ export default function DashboardLayout({ children }: { children: React.ReactNod
key={item.href}
href={item.href}
className={cn(
"flex flex-col items-center gap-0.5 py-1 px-2 rounded-lg transition-colors",
isActive ? "text-trust-blue" : "text-muted-foreground"
"flex flex-col items-center gap-0.5 py-1 px-2 transition-colors",
isActive ? "text-promise-blue" : "text-gray-400"
)}
>
<item.icon className="h-5 w-5" />

View File

@@ -9,15 +9,15 @@ export default function DashboardLoading() {
</div>
<div className="grid grid-cols-2 lg:grid-cols-4 gap-4">
{[...Array(4)].map((_, i) => (
<Skeleton key={i} className="h-24 rounded-2xl" />
<Skeleton key={i} className="h-24 rounded-lg" />
))}
</div>
<Skeleton className="h-16 rounded-2xl" />
<Skeleton className="h-16 rounded-lg" />
<div className="grid md:grid-cols-2 gap-4">
<Skeleton className="h-64 rounded-2xl" />
<Skeleton className="h-64 rounded-2xl" />
<Skeleton className="h-64 rounded-lg" />
<Skeleton className="h-64 rounded-lg" />
</div>
<Skeleton className="h-96 rounded-2xl" />
<Skeleton className="h-96 rounded-lg" />
</div>
)
}

View File

@@ -43,9 +43,9 @@ function RolePicker({ onSelect }: { onSelect: (role: string) => void }) {
<div className="grid grid-cols-2 gap-3">
<button
onClick={() => onSelect("charity")}
className="rounded-2xl border-2 border-gray-100 hover:border-trust-blue bg-white p-5 text-center space-y-2 transition-all hover:shadow-md group"
className="rounded-lg border-2 border-gray-100 hover:border-trust-blue bg-white p-5 text-center space-y-2 transition-all hover:shadow-md group"
>
<div className="mx-auto w-12 h-12 rounded-xl bg-trust-blue/10 flex items-center justify-center group-hover:scale-110 transition-transform">
<div className="mx-auto w-12 h-12 rounded-lg bg-trust-blue/10 flex items-center justify-center group-hover:scale-110 transition-transform">
<Building2 className="h-6 w-6 text-trust-blue" />
</div>
<p className="text-sm font-bold text-gray-900">Charity / Mosque</p>
@@ -53,9 +53,9 @@ function RolePicker({ onSelect }: { onSelect: (role: string) => void }) {
</button>
<button
onClick={() => onSelect("fundraiser")}
className="rounded-2xl border-2 border-gray-100 hover:border-warm-amber bg-white p-5 text-center space-y-2 transition-all hover:shadow-md group"
className="rounded-lg border-2 border-gray-100 hover:border-warm-amber bg-white p-5 text-center space-y-2 transition-all hover:shadow-md group"
>
<div className="mx-auto w-12 h-12 rounded-xl bg-warm-amber/10 flex items-center justify-center group-hover:scale-110 transition-transform">
<div className="mx-auto w-12 h-12 rounded-lg bg-warm-amber/10 flex items-center justify-center group-hover:scale-110 transition-transform">
<Heart className="h-6 w-6 text-warm-amber" />
</div>
<p className="text-sm font-bold text-gray-900">Personal Fundraiser</p>
@@ -85,14 +85,14 @@ function GettingStartedBanner({
const isFirstTime = ob.completed === 0 && (!ob.orgType || ob.orgType === "charity")
return (
<div className="rounded-2xl border border-trust-blue/20 bg-gradient-to-r from-trust-blue/5 via-white to-warm-amber/5 p-5 space-y-4 relative">
<div className="rounded-lg border border-trust-blue/20 bg-paper p-5 space-y-4 relative">
{/* Dismiss X */}
<button onClick={onDismiss} className="absolute top-3 right-3 text-muted-foreground hover:text-foreground p-1">
<X className="h-4 w-4" />
</button>
<div className="flex items-center gap-3">
<div className="h-10 w-10 rounded-xl bg-gradient-to-br from-trust-blue to-blue-600 flex items-center justify-center flex-shrink-0">
<div className="h-10 w-10 rounded-lg bg-midnight flex items-center justify-center flex-shrink-0">
<span className="text-white text-lg">🤲</span>
</div>
<div>
@@ -100,7 +100,7 @@ function GettingStartedBanner({
{isFirstTime ? "Welcome! What best describes you?" : `Getting started · ${ob.completed}/${ob.total}`}
</h2>
{!isFirstTime && (
<Progress value={(ob.completed / ob.total) * 100} className="h-1.5 mt-1.5 w-32" indicatorClassName="bg-gradient-to-r from-trust-blue to-success-green" />
<Progress value={(ob.completed / ob.total) * 100} className="h-1.5 mt-1.5 w-32" indicatorClassName="bg-promise-blue" />
)}
</div>
</div>
@@ -113,7 +113,7 @@ function GettingStartedBanner({
const isNext = !step.done && ob.steps.slice(0, i).every(s => s.done)
return (
<Link key={step.id} href={step.href}>
<div className={`flex items-center gap-2.5 rounded-xl border px-3 py-2.5 transition-all ${
<div className={`flex items-center gap-2.5 rounded-lg border px-3 py-2.5 transition-all ${
step.done ? "bg-success-green/5 border-success-green/20" :
isNext ? "bg-trust-blue/5 border-trust-blue/20 shadow-sm" :
"bg-white border-gray-100"
@@ -233,7 +233,7 @@ export default function DashboardPage() {
<Card className={isEmpty ? "opacity-60" : ""}>
<CardContent className="pt-5 pb-4">
<div className="flex items-center gap-3">
<div className="rounded-xl bg-trust-blue/10 p-2.5"><Users className="h-5 w-5 text-trust-blue" /></div>
<div className="rounded-lg bg-trust-blue/10 p-2.5"><Users className="h-5 w-5 text-trust-blue" /></div>
<div>
<p className="text-2xl font-black">{s.totalPledges}</p>
<p className="text-xs text-muted-foreground">Total Pledges</p>
@@ -244,7 +244,7 @@ export default function DashboardPage() {
<Card className={isEmpty ? "opacity-60" : ""}>
<CardContent className="pt-5 pb-4">
<div className="flex items-center gap-3">
<div className="rounded-xl bg-warm-amber/10 p-2.5"><Banknote className="h-5 w-5 text-warm-amber" /></div>
<div className="rounded-lg bg-warm-amber/10 p-2.5"><Banknote className="h-5 w-5 text-warm-amber" /></div>
<div>
<p className="text-2xl font-black">{formatPence(s.totalPledgedPence)}</p>
<p className="text-xs text-muted-foreground">Total Pledged</p>
@@ -255,7 +255,7 @@ export default function DashboardPage() {
<Card className={isEmpty ? "opacity-60" : ""}>
<CardContent className="pt-5 pb-4">
<div className="flex items-center gap-3">
<div className="rounded-xl bg-success-green/10 p-2.5"><TrendingUp className="h-5 w-5 text-success-green" /></div>
<div className="rounded-lg bg-success-green/10 p-2.5"><TrendingUp className="h-5 w-5 text-success-green" /></div>
<div>
<p className="text-2xl font-black">{formatPence(s.totalCollectedPence)}</p>
<p className="text-xs text-muted-foreground">Collected ({s.collectionRate}%)</p>
@@ -266,7 +266,7 @@ export default function DashboardPage() {
<Card className={isEmpty ? "opacity-60" : s.overdueRate > 10 ? "border-danger-red/30" : ""}>
<CardContent className="pt-5 pb-4">
<div className="flex items-center gap-3">
<div className="rounded-xl bg-danger-red/10 p-2.5"><AlertTriangle className="h-5 w-5 text-danger-red" /></div>
<div className="rounded-lg bg-danger-red/10 p-2.5"><AlertTriangle className="h-5 w-5 text-danger-red" /></div>
<div>
<p className="text-2xl font-black">{byStatus.overdue || 0}</p>
<p className="text-xs text-muted-foreground">Overdue</p>
@@ -283,7 +283,7 @@ export default function DashboardPage() {
<span className="text-sm font-medium">Pledged Collected</span>
<span className="text-sm font-bold text-muted-foreground">{s.collectionRate}%</span>
</div>
<Progress value={s.collectionRate} indicatorClassName="bg-gradient-to-r from-trust-blue to-success-green" />
<Progress value={s.collectionRate} indicatorClassName="bg-promise-blue" />
<div className="flex justify-between mt-2 text-xs text-muted-foreground">
<span>{formatPence(s.totalCollectedPence)} collected</span>
<span>{formatPence(s.totalPledgedPence - s.totalCollectedPence)} outstanding</span>

View File

@@ -251,7 +251,7 @@ export default function PledgesPage() {
{/* Collection progress */}
<div className="flex items-center gap-4">
<Progress value={collectionRate} className="flex-1 h-2" indicatorClassName="bg-gradient-to-r from-trust-blue to-success-green" />
<Progress value={collectionRate} className="flex-1 h-2" indicatorClassName="bg-promise-blue" />
<span className="text-sm font-medium text-muted-foreground whitespace-nowrap">
{formatPence(stats.totalCollected)} / {formatPence(stats.totalPledged)}
</span>

View File

@@ -130,7 +130,7 @@ export default function ReconcilePage() {
</div>
{/* File upload */}
<div className="border-2 border-dashed border-gray-200 rounded-2xl p-8 text-center hover:border-trust-blue/50 transition-colors">
<div className="border-2 border-dashed border-gray-200 rounded-lg p-8 text-center hover:border-trust-blue/50 transition-colors">
<Upload className="h-10 w-10 text-muted-foreground mx-auto mb-3" />
<input
type="file"

View File

@@ -66,7 +66,7 @@ export default function SettingsPage() {
<p className="text-sm text-muted-foreground mt-0.5">Configure your organisation&apos;s payment details and integrations</p>
</div>
{error && <div className="rounded-xl bg-danger-red/10 border border-danger-red/20 p-3 text-sm text-danger-red">{error}</div>}
{error && <div className="rounded-lg bg-danger-red/10 border border-danger-red/20 p-3 text-sm text-danger-red">{error}</div>}
{/* WhatsApp — MOST IMPORTANT, first */}
<WhatsAppPanel />
@@ -194,7 +194,7 @@ function WhatsAppPanel() {
</CardHeader>
<CardContent>
<div className="flex items-center gap-4">
<div className="w-12 h-12 rounded-full bg-[#25D366]/10 flex items-center justify-center">
<div className="w-12 h-12 rounded-lg bg-[#25D366]/10 flex items-center justify-center">
<Smartphone className="h-6 w-6 text-[#25D366]" />
</div>
<div>
@@ -240,7 +240,7 @@ function WhatsAppPanel() {
<div className="relative">
{/* Crop to QR area: the screenshot shows full WhatsApp web page.
QR code is roughly in center. We use overflow hidden + object positioning. */}
<div className="w-72 h-72 rounded-xl border-2 border-[#25D366]/20 overflow-hidden bg-white">
<div className="w-72 h-72 rounded-lg border-2 border-[#25D366]/20 overflow-hidden bg-white">
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
src={qrImage}
@@ -254,7 +254,7 @@ function WhatsAppPanel() {
</div>
</div>
) : (
<div className="w-72 h-72 rounded-xl border-2 border-dashed border-muted flex items-center justify-center">
<div className="w-72 h-72 rounded-lg border-2 border-dashed border-muted flex items-center justify-center">
<Loader2 className="h-8 w-8 text-muted-foreground animate-spin" />
</div>
)}
@@ -285,9 +285,9 @@ function WhatsAppPanel() {
</CardDescription>
</CardHeader>
<CardContent>
<div className="rounded-xl bg-muted/50 p-4 space-y-3">
<div className="rounded-lg bg-muted/50 p-4 space-y-3">
<div className="flex items-start gap-3">
<div className="w-10 h-10 rounded-full bg-[#25D366]/10 flex items-center justify-center flex-shrink-0">
<div className="w-10 h-10 rounded-lg bg-[#25D366]/10 flex items-center justify-center flex-shrink-0">
<Smartphone className="h-5 w-5 text-[#25D366]" />
</div>
<div>

View File

@@ -125,7 +125,7 @@ export default function SetupPage() {
<div className="flex items-center justify-between">
{steps.map((s, i) => (
<div key={s.num} className="flex items-center">
<div className={`w-10 h-10 rounded-full flex items-center justify-center text-sm font-bold transition-all ${
<div className={`w-10 h-10 rounded-lg flex items-center justify-center text-sm font-bold transition-all ${
step >= s.num ? "bg-trust-blue text-white" : "bg-gray-100 text-gray-400"
}`}>
{step > s.num ? <CheckCircle2 className="h-5 w-5" /> : <s.icon className="h-5 w-5" />}
@@ -231,14 +231,14 @@ export default function SetupPage() {
{step === 4 && (
<Card className="border-success-green/30">
<CardHeader className="text-center pb-2">
<div className="mx-auto w-16 h-16 rounded-full bg-success-green/10 flex items-center justify-center mb-3">
<div className="mx-auto w-14 h-14 bg-success-green/10 flex items-center justify-center mb-3">
<Sparkles className="h-8 w-8 text-success-green" />
</div>
<CardTitle>You&apos;re All Set! 🎉</CardTitle>
<p className="text-sm text-muted-foreground">Your charity is ready to collect pledges.</p>
</CardHeader>
<CardContent className="space-y-4">
<div className="bg-gray-50 rounded-xl p-4 space-y-2">
<div className="bg-gray-50 rounded-lg p-4 space-y-2">
<div className="flex items-center justify-between">
<span className="text-sm text-muted-foreground">Charity</span>
<span className="text-sm font-medium">{orgName}</span>
@@ -254,7 +254,7 @@ export default function SetupPage() {
</div>
{setupResult?.qrToken && (
<div className="bg-trust-blue/5 rounded-xl p-4 text-center space-y-2">
<div className="bg-trust-blue/5 rounded-lg p-4 text-center space-y-2">
<QrCode className="h-8 w-8 text-trust-blue mx-auto" />
<p className="text-sm font-medium">Your pledge link is ready</p>
<code className="text-xs bg-white px-3 py-1.5 rounded-lg border block overflow-x-auto">
@@ -278,7 +278,7 @@ export default function SetupPage() {
{/* Tips */}
{step < 4 && (
<div className="bg-warm-amber/5 rounded-xl border border-warm-amber/20 p-4">
<div className="bg-warm-amber/5 rounded-lg border border-warm-amber/20 p-4">
<p className="text-xs font-semibold text-warm-amber mb-1">💡 Tip</p>
{step === 1 && <p className="text-xs text-muted-foreground">Your charity name appears on the donor pledge page and WhatsApp receipts.</p>}
{step === 2 && <p className="text-xs text-muted-foreground">Bank details are shown to donors who choose &quot;Bank Transfer&quot;. Each pledge gets a unique reference number for easy reconciliation.</p>}

View File

@@ -82,7 +82,7 @@ export default function PublicEventPage() {
if (loading) {
return (
<div className="min-h-screen flex items-center justify-center bg-gradient-to-br from-trust-blue/5 via-white to-warm-amber/5">
<div className="min-h-screen flex items-center justify-center bg-paper">
<Loader2 className="h-8 w-8 text-trust-blue animate-spin" />
</div>
)
@@ -90,7 +90,7 @@ export default function PublicEventPage() {
if (error || !data) {
return (
<div className="min-h-screen flex items-center justify-center bg-gradient-to-br from-trust-blue/5 via-white to-warm-amber/5 p-4">
<div className="min-h-screen flex items-center justify-center bg-paper p-4">
<div className="text-center space-y-4">
<Heart className="h-12 w-12 text-muted-foreground mx-auto" />
<h1 className="text-xl font-bold">Event not found</h1>
@@ -106,7 +106,7 @@ export default function PublicEventPage() {
const giftAidBonus = Math.round(data.stats.totalPledged * 0.25 * (data.stats.giftAidCount / Math.max(1, data.stats.pledgeCount)))
return (
<div className="min-h-screen bg-gradient-to-br from-trust-blue/5 via-white to-warm-amber/5">
<div className="min-h-screen bg-paper">
<div className="max-w-lg mx-auto px-4 py-8 space-y-6">
{/* Header */}
<div className="text-center space-y-3">
@@ -146,7 +146,7 @@ export default function PublicEventPage() {
</div>
<div className="h-4 rounded-full bg-gray-100 overflow-hidden">
<div
className="h-full rounded-full bg-gradient-to-r from-trust-blue to-success-green transition-all duration-1000"
className="h-full rounded-full bg-promise-blue transition-all duration-1000"
style={{ width: `${progressPercent}%` }}
/>
</div>

View File

@@ -7,25 +7,25 @@
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
--foreground: 222 47% 11%;
--card: 0 0% 100%;
--card-foreground: 222.2 84% 4.9%;
--card-foreground: 222 47% 11%;
--popover: 0 0% 100%;
--popover-foreground: 222.2 84% 4.9%;
--primary: 221.2 83.2% 53.3%;
--primary-foreground: 210 40% 98%;
--secondary: 210 40% 96.1%;
--secondary-foreground: 222.2 47.4% 11.2%;
--muted: 210 40% 96.1%;
--muted-foreground: 215.4 16.3% 46.9%;
--accent: 210 40% 96.1%;
--accent-foreground: 222.2 47.4% 11.2%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 210 40% 98%;
--border: 214.3 31.8% 91.4%;
--input: 214.3 31.8% 91.4%;
--ring: 221.2 83.2% 53.3%;
--radius: 0.75rem;
--popover-foreground: 222 47% 11%;
--primary: 224 76% 40%;
--primary-foreground: 0 0% 100%;
--secondary: 220 14% 96%;
--secondary-foreground: 222 47% 11%;
--muted: 220 14% 96%;
--muted-foreground: 215 16% 47%;
--accent: 220 14% 96%;
--accent-foreground: 222 47% 11%;
--destructive: 0 72% 51%;
--destructive-foreground: 0 0% 100%;
--border: 220 13% 91%;
--input: 220 13% 91%;
--ring: 224 76% 40%;
--radius: 0.5rem;
}
* {
@@ -45,9 +45,9 @@
}
}
/* Premium animations */
/* Animations — subtle, purposeful */
@keyframes fadeUp {
from { opacity: 0; transform: translateY(12px); }
from { opacity: 0; transform: translateY(8px); }
to { opacity: 1; transform: translateY(0); }
}
@@ -56,55 +56,32 @@
to { opacity: 1; }
}
@keyframes scaleIn {
from { opacity: 0; transform: scale(0.9); }
to { opacity: 1; transform: scale(1); }
}
@keyframes slideDown {
from { opacity: 0; transform: translateY(-8px); }
from { opacity: 0; transform: translateY(-4px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes pulse-ring {
0% { transform: scale(0.8); opacity: 1; }
100% { transform: scale(2); opacity: 0; }
}
@keyframes shimmer {
0% { background-position: -200% 0; }
100% { background-position: 200% 0; }
}
@keyframes confetti-fall {
0% { transform: translateY(-10vh) rotate(0deg); opacity: 1; }
100% { transform: translateY(100vh) rotate(720deg); opacity: 0; }
}
@keyframes bounce-gentle {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-4px); }
}
@keyframes counter-roll {
from { transform: translateY(100%); opacity: 0; }
to { transform: translateY(0); opacity: 1; }
}
.animate-fade-up { animation: fadeUp 0.5s ease-out forwards; }
.animate-fade-up { animation: fadeUp 0.4s ease-out forwards; }
.animate-fade-in { animation: fadeIn 0.3s ease-out forwards; }
.animate-scale-in { animation: scaleIn 0.3s ease-out forwards; }
.animate-slide-down { animation: slideDown 0.3s ease-out forwards; }
.animate-pulse-ring { animation: pulse-ring 1.5s ease-out infinite; }
.animate-shimmer {
background: linear-gradient(90deg, transparent 30%, rgba(255,255,255,0.4) 50%, transparent 70%);
background-size: 200% 100%;
animation: shimmer 2s infinite;
}
.animate-bounce-gentle { animation: bounce-gentle 2s ease-in-out infinite; }
.animate-counter-roll { animation: counter-roll 0.4s ease-out forwards; }
/* Stagger children animations */
/* Stagger children */
.stagger-children > * { opacity: 0; animation: fadeUp 0.4s ease-out forwards; }
.stagger-children > *:nth-child(1) { animation-delay: 0ms; }
.stagger-children > *:nth-child(2) { animation-delay: 60ms; }
@@ -112,34 +89,6 @@
.stagger-children > *:nth-child(4) { animation-delay: 180ms; }
.stagger-children > *:nth-child(5) { animation-delay: 240ms; }
.stagger-children > *:nth-child(6) { animation-delay: 300ms; }
.stagger-children > *:nth-child(7) { animation-delay: 360ms; }
.stagger-children > *:nth-child(8) { animation-delay: 420ms; }
/* Glass effects */
.glass {
background: rgba(255, 255, 255, 0.7);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.3);
}
.glass-dark {
background: rgba(0, 0, 0, 0.5);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
}
/* Premium card hover */
.card-hover {
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.card-hover:hover {
transform: translateY(-2px);
box-shadow: 0 12px 40px -8px rgba(0,0,0,0.12);
}
.card-hover:active {
transform: translateY(0) scale(0.98);
}
/* Number input clean */
input[type="number"]::-webkit-inner-spin-button,
@@ -151,20 +100,10 @@ input[type="number"] {
-moz-appearance: textfield;
}
/* Scrollbar */
::-webkit-scrollbar {
width: 4px;
}
::-webkit-scrollbar-track {
background: transparent;
}
::-webkit-scrollbar-thumb {
background: hsl(var(--muted));
border-radius: 2px;
}
/* Scrollbar — thin, unobtrusive */
::-webkit-scrollbar { width: 4px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: #d1d5db; border-radius: 2px; }
/* Selection */
::selection {
background: #1e40af20;
color: #1e40af;
}
/* Selection — brand blue */
::selection { background: #1e40af15; color: #1e40af; }

View File

@@ -1,8 +1,8 @@
export default function PledgeLoading() {
return (
<div className="min-h-screen flex items-center justify-center bg-gradient-to-br from-trust-blue/5 via-white to-warm-amber/5">
<div className="min-h-screen flex items-center justify-center bg-paper">
<div className="text-center space-y-4">
<div className="inline-flex items-center justify-center w-16 h-16 rounded-full bg-trust-blue/10 animate-pulse">
<div className="inline-flex items-center justify-center w-14 h-14 bg-trust-blue/10 animate-pulse">
<div className="w-8 h-8 rounded-full bg-trust-blue/30" />
</div>
<p className="text-muted-foreground animate-pulse">Loading pledge page...</p>

View File

@@ -189,8 +189,8 @@ export default function PledgePage() {
if (loading) {
return (
<div className="min-h-screen flex flex-col items-center justify-center bg-gradient-to-br from-trust-blue/5 via-white to-warm-amber/5 gap-4">
<div className="w-12 h-12 rounded-2xl bg-gradient-to-br from-trust-blue to-blue-600 flex items-center justify-center animate-pulse">
<div className="min-h-screen flex flex-col items-center justify-center bg-paper gap-4">
<div className="w-12 h-12 rounded-lg bg-midnight flex items-center justify-center animate-pulse">
<span className="text-white text-xl">🤲</span>
</div>
<p className="text-trust-blue font-medium animate-pulse">Loading...</p>
@@ -200,7 +200,7 @@ export default function PledgePage() {
if (error) {
return (
<div className="min-h-screen flex items-center justify-center bg-gradient-to-br from-trust-blue/5 via-white to-warm-amber/5 p-4">
<div className="min-h-screen flex items-center justify-center bg-paper p-4">
<div className="text-center space-y-4 animate-fade-up">
<div className="text-5xl">😔</div>
<h1 className="text-xl font-bold text-gray-900">Something went wrong</h1>
@@ -260,11 +260,11 @@ export default function PledgePage() {
const progressPercent = progressMap[step] || 10
return (
<div className="min-h-screen bg-gradient-to-br from-trust-blue/5 via-white to-warm-amber/5">
<div className="min-h-screen bg-paper">
{/* Progress bar */}
<div className="fixed top-0 left-0 right-0 h-1 bg-gray-100 z-50">
<div
className="h-full bg-gradient-to-r from-trust-blue to-success-green transition-all duration-700 ease-out"
className="h-full bg-promise-blue transition-all duration-700 ease-out"
style={{ width: `${progressPercent}%` }}
/>
</div>
@@ -282,7 +282,7 @@ export default function PledgePage() {
{/* Back button */}
{backableSteps.has(step) && (
<div className="fixed bottom-0 left-0 right-0 pb-6 pt-4 px-4 bg-gradient-to-t from-white via-white/80 to-transparent">
<div className="fixed bottom-0 left-0 right-0 pb-6 pt-4 px-4 bg-white">
<button
onClick={() => setStep(getBackStep(step))}
className="text-sm text-muted-foreground hover:text-foreground transition-colors tap-target flex items-center gap-1"

View File

@@ -64,7 +64,7 @@ export function AmountStep({ onSelect, eventName, eventId }: Props) {
<div className="max-w-md mx-auto pt-2 space-y-6 animate-fade-up">
{/* Hero */}
<div className="text-center space-y-3">
<div className="inline-flex items-center justify-center w-14 h-14 rounded-2xl bg-gradient-to-br from-trust-blue to-blue-600 shadow-lg shadow-trust-blue/30">
<div className="inline-flex items-center justify-center w-14 h-14 rounded-lg bg-midnight">
<Heart className="h-7 w-7 text-white" />
</div>
<h1 className="text-3xl font-black text-gray-900 tracking-tight">
@@ -80,7 +80,7 @@ export function AmountStep({ onSelect, eventName, eventId }: Props) {
<div className="flex items-center justify-center gap-2 animate-fade-in">
<div className="flex -space-x-2">
{[...Array(3)].map((_, i) => (
<div key={i} className="w-6 h-6 rounded-full bg-gradient-to-br from-trust-blue to-blue-400 border-2 border-white flex items-center justify-center">
<div key={i} className="w-6 h-6 rounded-full bg-promise-blue border-2 border-white flex items-center justify-center">
<span className="text-[8px] text-white font-bold">{["A", "S", "M"][i]}</span>
</div>
))}
@@ -106,9 +106,9 @@ export function AmountStep({ onSelect, eventName, eventId }: Props) {
onMouseEnter={() => setHovering(amount)}
onMouseLeave={() => setHovering(null)}
className={`
relative tap-target rounded-2xl border-2 py-4 text-center font-bold transition-all duration-200
relative tap-target rounded-lg border-2 py-4 text-center font-bold transition-all duration-200
${isSelected
? "border-trust-blue bg-trust-blue text-white shadow-xl shadow-trust-blue/30 scale-[1.03]"
? "border-trust-blue bg-trust-blue text-white"
: isHovering
? "border-trust-blue/40 bg-trust-blue/5 text-gray-900"
: "border-gray-200 bg-white text-gray-900 hover:border-trust-blue/30"
@@ -118,7 +118,7 @@ export function AmountStep({ onSelect, eventName, eventId }: Props) {
<span className="text-xl">£{pounds >= 1000 ? `${pounds / 1000}k` : pounds}</span>
{/* Gift Aid indicator */}
{isSelected && (
<div className="absolute -top-2 -right-2 bg-success-green text-white text-[10px] font-bold px-1.5 py-0.5 rounded-full animate-scale-in shadow-sm">
<div className="absolute -top-2 -right-2 bg-success-green text-white text-[10px] font-bold px-1.5 py-0.5 rounded-full animate-fade-in shadow-sm">
+£{Math.round(amount * 0.25 / 100)}
</div>
)}
@@ -152,14 +152,14 @@ export function AmountStep({ onSelect, eventName, eventId }: Props) {
placeholder="0"
value={custom}
onChange={(e) => handleCustomChange(e.target.value)}
className="w-full pl-10 pr-4 h-16 text-2xl font-black text-center rounded-2xl border-2 border-gray-200 bg-white focus:border-trust-blue focus:ring-4 focus:ring-trust-blue/10 outline-none transition-all"
className="w-full pl-10 pr-4 h-16 text-2xl font-black text-center rounded-lg border-2 border-gray-200 bg-white focus:border-trust-blue focus:ring-4 focus:ring-trust-blue/10 outline-none transition-all"
/>
</div>
</div>
{/* Live Gift Aid preview */}
{isValid && (
<div className="rounded-2xl bg-gradient-to-r from-success-green/5 to-success-green/10 border border-success-green/20 p-4 text-center animate-scale-in">
<div className="rounded-lg bg-fulfilled-green/5 border border-success-green/20 p-4 text-center animate-fade-in">
<p className="text-sm">
<span className="font-bold text-success-green">With Gift Aid:</span>{" "}
your £{(activeAmount / 100).toFixed(0)} becomes{" "}

View File

@@ -77,8 +77,8 @@ export function BankInstructionsStep({ pledge, amount, eventName, donorPhone }:
return (
<div className="max-w-md mx-auto pt-8 text-center space-y-6 animate-fade-up">
<div className="relative inline-flex items-center justify-center">
<div className="absolute w-20 h-20 rounded-full bg-success-green/20 animate-pulse-ring" />
<div className="relative w-20 h-20 rounded-full bg-gradient-to-br from-success-green to-emerald-500 flex items-center justify-center shadow-xl shadow-success-green/30">
<div className="absolute w-16 h-16 bg-success-green/20" />
<div className="relative w-16 h-16 bg-fulfilled-green flex items-center justify-center">
<Check className="h-10 w-10 text-white" strokeWidth={3} />
</div>
</div>
@@ -88,7 +88,7 @@ export function BankInstructionsStep({ pledge, amount, eventName, donorPhone }:
</p>
{whatsappSent && (
<div className="rounded-xl bg-[#25D366]/10 border border-[#25D366]/20 p-3 text-sm text-[#25D366] font-medium flex items-center justify-center gap-2 animate-fade-in">
<div className="rounded-lg bg-[#25D366]/10 border border-[#25D366]/20 p-3 text-sm text-[#25D366] font-medium flex items-center justify-center gap-2 animate-fade-in">
<MessageCircle className="h-4 w-4" /> Details sent to your WhatsApp
</div>
)}
@@ -107,7 +107,7 @@ export function BankInstructionsStep({ pledge, amount, eventName, donorPhone }:
</Card>
{/* Share */}
<div className="rounded-2xl bg-gradient-to-br from-warm-amber/5 to-orange-50 border border-warm-amber/20 p-5 space-y-3">
<div className="rounded-lg bg-generosity-gold/5 border border-warm-amber/20 p-5 space-y-3">
<div className="flex items-center justify-center gap-2">
<Sparkles className="h-4 w-4 text-warm-amber" />
<p className="text-sm font-bold text-gray-900">Know someone who&apos;d donate too?</p>
@@ -164,7 +164,7 @@ export function BankInstructionsStep({ pledge, amount, eventName, donorPhone }:
return (
<div className="max-w-md mx-auto pt-2 space-y-5 animate-fade-up">
<div className="text-center space-y-2">
<div className="inline-flex items-center justify-center w-14 h-14 rounded-2xl bg-gradient-to-br from-trust-blue to-blue-600 shadow-lg shadow-trust-blue/30">
<div className="inline-flex items-center justify-center w-14 h-14 rounded-lg bg-midnight">
<span className="text-2xl">🏦</span>
</div>
<h1 className="text-2xl font-black text-gray-900 tracking-tight">
@@ -176,7 +176,7 @@ export function BankInstructionsStep({ pledge, amount, eventName, donorPhone }:
</div>
{whatsappSent && (
<div className="rounded-xl bg-[#25D366]/10 border border-[#25D366]/20 p-2.5 text-xs text-[#25D366] font-medium flex items-center justify-center gap-2 animate-fade-in">
<div className="rounded-lg bg-[#25D366]/10 border border-[#25D366]/20 p-2.5 text-xs text-[#25D366] font-medium flex items-center justify-center gap-2 animate-fade-in">
<MessageCircle className="h-3.5 w-3.5" /> Bank details also sent to your WhatsApp
</div>
)}
@@ -184,7 +184,7 @@ export function BankInstructionsStep({ pledge, amount, eventName, donorPhone }:
{/* Bank details — tap to copy each field */}
{bd && (
<Card className="overflow-hidden">
<div className="h-1 bg-gradient-to-r from-trust-blue to-blue-400" />
<div className="h-1 bg-promise-blue" />
<CardContent className="pt-4 divide-y">
<CopyField label="Sort Code" value={bd.sortCode} fieldKey="sortCode" mono />
<CopyField label="Account Number" value={bd.accountNo} fieldKey="accountNo" mono />
@@ -194,7 +194,7 @@ export function BankInstructionsStep({ pledge, amount, eventName, donorPhone }:
)}
{/* THE reference — the most important thing */}
<div className="rounded-2xl border-2 border-trust-blue bg-gradient-to-br from-trust-blue/5 to-blue-50 p-5 text-center space-y-3">
<div className="rounded-lg border-2 border-trust-blue bg-promise-blue/5 p-5 text-center space-y-3">
<p className="text-xs font-bold text-trust-blue uppercase tracking-widest">
Payment Reference
</p>
@@ -202,7 +202,7 @@ export function BankInstructionsStep({ pledge, amount, eventName, donorPhone }:
onClick={() => copyField(pledge.reference, "reference")}
className="group"
>
<p className="text-3xl font-mono font-black text-trust-blue tracking-wider group-hover:scale-105 transition-transform">
<p className="text-3xl font-mono font-black text-trust-blue tracking-wider transition-transform">
{pledge.reference}
</p>
</button>
@@ -223,7 +223,7 @@ export function BankInstructionsStep({ pledge, amount, eventName, donorPhone }:
</div>
{/* Open banking app hint */}
<div className="rounded-xl bg-warm-amber/5 border border-warm-amber/20 p-3 text-center">
<div className="rounded-lg bg-warm-amber/5 border border-warm-amber/20 p-3 text-center">
<p className="text-xs font-medium text-warm-amber flex items-center justify-center gap-1.5">
<ExternalLink className="h-3.5 w-3.5" />
Open your banking app New payment Paste the details

View File

@@ -171,7 +171,7 @@ export function CardPaymentStep({ amount, eventName, eventId, qrSourceId, onComp
</div>
{/* Card form */}
<div className="rounded-2xl border-2 border-gray-200 bg-white p-5 space-y-4">
<div className="rounded-lg border-2 border-gray-200 bg-white p-5 space-y-4">
{/* Card number */}
<div className="space-y-2">
<Label htmlFor="card-number">Card Number</Label>
@@ -261,7 +261,7 @@ export function CardPaymentStep({ amount, eventName, eventId, qrSourceId, onComp
</div>
{/* Gift Aid */}
<label className="flex items-start gap-3 rounded-2xl border-2 border-gray-200 bg-white p-4 cursor-pointer hover:border-trust-blue/50 transition-colors">
<label className="flex items-start gap-3 rounded-lg border-2 border-gray-200 bg-white p-4 cursor-pointer hover:border-trust-blue/50 transition-colors">
<input
type="checkbox"
checked={giftAid}

View File

@@ -130,8 +130,8 @@ export function ConfirmationStep({ pledge, amount, rail, eventName, shareUrl, do
<div className="max-w-md mx-auto pt-6 text-center space-y-6 animate-fade-up">
{/* Success icon with pulse */}
<div className="relative inline-flex items-center justify-center">
<div className="absolute w-20 h-20 rounded-full bg-success-green/20 animate-pulse-ring" />
<div className="relative w-20 h-20 rounded-full bg-gradient-to-br from-success-green to-emerald-500 flex items-center justify-center shadow-xl shadow-success-green/30">
<div className="absolute w-16 h-16 bg-success-green/20" />
<div className="relative w-16 h-16 bg-fulfilled-green flex items-center justify-center">
<Check className="h-10 w-10 text-white" strokeWidth={3} />
</div>
</div>
@@ -150,7 +150,7 @@ export function ConfirmationStep({ pledge, amount, rail, eventName, shareUrl, do
{/* Details card */}
<Card className="text-left overflow-hidden">
<div className="h-1 bg-gradient-to-r from-trust-blue via-success-green to-warm-amber" />
<div className="h-1 bg-promise-blue" />
<CardContent className="pt-5 space-y-3 text-sm">
<div className="flex justify-between items-center">
<span className="text-muted-foreground">Amount</span>
@@ -190,19 +190,19 @@ export function ConfirmationStep({ pledge, amount, rail, eventName, shareUrl, do
</Card>
{/* What happens next */}
<div className="rounded-2xl bg-trust-blue/5 border border-trust-blue/10 p-4 text-left">
<div className="rounded-lg bg-trust-blue/5 border border-trust-blue/10 p-4 text-left">
<p className="text-sm font-semibold text-trust-blue mb-1">What happens next?</p>
<p className="text-sm text-muted-foreground">{nextStepMessages[rail] || nextStepMessages.bank}</p>
</div>
{whatsappSent && (
<div className="rounded-xl bg-[#25D366]/10 border border-[#25D366]/20 p-3 text-sm text-[#25D366] font-medium flex items-center justify-center gap-2 animate-fade-in">
<div className="rounded-lg bg-[#25D366]/10 border border-[#25D366]/20 p-3 text-sm text-[#25D366] font-medium flex items-center justify-center gap-2 animate-fade-in">
<MessageCircle className="h-4 w-4" /> Receipt sent to your WhatsApp
</div>
)}
{/* Share */}
<div className="rounded-2xl bg-gradient-to-br from-warm-amber/5 to-orange-50 border border-warm-amber/20 p-5 space-y-3">
<div className="rounded-lg bg-generosity-gold/5 border border-warm-amber/20 p-5 space-y-3">
<div className="flex items-center justify-center gap-2">
<Sparkles className="h-4 w-4 text-warm-amber" />
<p className="text-sm font-bold text-gray-900">

View File

@@ -118,7 +118,7 @@ export function DirectDebitStep({ amount, eventName, organizationName, eventId,
if (phase === "processing") {
return (
<div className="max-w-md mx-auto pt-16 text-center space-y-6">
<div className="inline-flex items-center justify-center w-20 h-20 rounded-full bg-trust-blue/10">
<div className="inline-flex items-center justify-center w-16 h-16 bg-trust-blue/10">
<div className="h-10 w-10 border-4 border-trust-blue border-t-transparent rounded-full animate-spin" />
</div>
<div className="space-y-2">
@@ -141,7 +141,7 @@ export function DirectDebitStep({ amount, eventName, organizationName, eventId,
return (
<div className="max-w-md mx-auto pt-4 space-y-6">
<div className="text-center space-y-2">
<div className="inline-flex items-center justify-center w-16 h-16 rounded-full bg-trust-blue/10 mb-2">
<div className="inline-flex items-center justify-center w-14 h-14 bg-trust-blue/10 mb-2">
<ShieldCheck className="h-8 w-8 text-trust-blue" />
</div>
<h1 className="text-2xl font-extrabold text-gray-900">
@@ -153,7 +153,7 @@ export function DirectDebitStep({ amount, eventName, organizationName, eventId,
</div>
{/* Summary card */}
<div className="rounded-2xl border-2 border-gray-200 bg-white p-5 space-y-4">
<div className="rounded-lg border-2 border-gray-200 bg-white p-5 space-y-4">
<div className="grid grid-cols-2 gap-4 text-sm">
<div>
<p className="text-xs text-muted-foreground uppercase tracking-wider">Account Holder</p>
@@ -189,7 +189,7 @@ export function DirectDebitStep({ amount, eventName, organizationName, eventId,
</div>
{/* Guarantee box */}
<div className="rounded-2xl bg-emerald-50 border border-emerald-200 p-4 space-y-2">
<div className="rounded-lg bg-emerald-50 border border-emerald-200 p-4 space-y-2">
<div className="flex items-center gap-2">
<ShieldCheck className="h-5 w-5 text-emerald-600" />
<p className="text-sm font-semibold text-emerald-800">Direct Debit Guarantee</p>
@@ -234,7 +234,7 @@ export function DirectDebitStep({ amount, eventName, organizationName, eventId,
</div>
{/* Info banner */}
<div className="rounded-2xl bg-trust-blue/5 border border-trust-blue/20 p-4 flex items-start gap-3">
<div className="rounded-lg bg-trust-blue/5 border border-trust-blue/20 p-4 flex items-start gap-3">
<Landmark className="h-5 w-5 text-trust-blue flex-shrink-0 mt-0.5" />
<div>
<p className="text-sm font-medium text-trust-blue">How it works</p>
@@ -245,7 +245,7 @@ export function DirectDebitStep({ amount, eventName, organizationName, eventId,
</div>
{/* Bank details form */}
<div className="rounded-2xl border-2 border-gray-200 bg-white p-5 space-y-4">
<div className="rounded-lg border-2 border-gray-200 bg-white p-5 space-y-4">
<div className="space-y-2">
<Label htmlFor="dd-name">Account Holder Name</Label>
<Input
@@ -306,7 +306,7 @@ export function DirectDebitStep({ amount, eventName, organizationName, eventId,
</div>
{/* Gift Aid */}
<label className="flex items-start gap-3 rounded-2xl border-2 border-gray-200 bg-white p-4 cursor-pointer hover:border-trust-blue/50 transition-colors">
<label className="flex items-start gap-3 rounded-lg border-2 border-gray-200 bg-white p-4 cursor-pointer hover:border-trust-blue/50 transition-colors">
<input
type="checkbox"
checked={giftAid}
@@ -322,7 +322,7 @@ export function DirectDebitStep({ amount, eventName, organizationName, eventId,
</label>
{/* Direct Debit mandate agreement */}
<label className={`flex items-start gap-3 rounded-2xl border-2 p-4 cursor-pointer transition-colors ${
<label className={`flex items-start gap-3 rounded-lg border-2 p-4 cursor-pointer transition-colors ${
errors.mandate ? "border-red-300 bg-red-50" : "border-gray-200 bg-white hover:border-trust-blue/50"
}`}>
<input
@@ -349,7 +349,7 @@ export function DirectDebitStep({ amount, eventName, organizationName, eventId,
</Button>
{/* DD Guarantee mini */}
<div className="rounded-xl bg-emerald-50 border border-emerald-200 p-3 flex items-start gap-2">
<div className="rounded-lg bg-emerald-50 border border-emerald-200 p-3 flex items-start gap-2">
<ShieldCheck className="h-4 w-4 text-emerald-600 flex-shrink-0 mt-0.5" />
<p className="text-xs text-emerald-700">
Protected by the <span className="font-semibold">Direct Debit Guarantee</span>. You can cancel anytime by contacting your bank. Full refund if any errors occur.

View File

@@ -60,8 +60,8 @@ export function ExternalRedirectStep({ pledge, amount, eventName, externalUrl, e
return (
<div className="max-w-md mx-auto pt-8 text-center space-y-6 animate-fade-up">
<div className="relative inline-flex items-center justify-center">
<div className="absolute w-20 h-20 rounded-full bg-success-green/20 animate-pulse-ring" />
<div className="relative w-20 h-20 rounded-full bg-gradient-to-br from-success-green to-emerald-500 flex items-center justify-center shadow-xl shadow-success-green/30">
<div className="absolute w-16 h-16 bg-success-green/20" />
<div className="relative w-16 h-16 bg-fulfilled-green flex items-center justify-center">
<Check className="h-10 w-10 text-white" strokeWidth={3} />
</div>
</div>
@@ -72,7 +72,7 @@ export function ExternalRedirectStep({ pledge, amount, eventName, externalUrl, e
</p>
{whatsappSent && (
<div className="rounded-xl bg-[#25D366]/10 border border-[#25D366]/20 p-3 text-sm text-[#25D366] font-medium flex items-center justify-center gap-2 animate-fade-in">
<div className="rounded-lg bg-[#25D366]/10 border border-[#25D366]/20 p-3 text-sm text-[#25D366] font-medium flex items-center justify-center gap-2 animate-fade-in">
<MessageCircle className="h-4 w-4" /> Link sent to your WhatsApp
</div>
)}
@@ -107,7 +107,7 @@ export function ExternalRedirectStep({ pledge, amount, eventName, externalUrl, e
</div>
{/* Share */}
<div className="rounded-2xl bg-gradient-to-br from-warm-amber/5 to-orange-50 border border-warm-amber/20 p-5 space-y-3">
<div className="rounded-lg bg-generosity-gold/5 border border-warm-amber/20 p-5 space-y-3">
<div className="flex items-center justify-center gap-2">
<Sparkles className="h-4 w-4 text-warm-amber" />
<p className="text-sm font-bold text-gray-900">Know someone who&apos;d donate too?</p>
@@ -144,7 +144,7 @@ export function ExternalRedirectStep({ pledge, amount, eventName, externalUrl, e
return (
<div className="max-w-md mx-auto pt-2 space-y-5 animate-fade-up">
<div className="text-center space-y-2">
<div className="inline-flex items-center justify-center w-14 h-14 rounded-2xl shadow-lg" style={{ background: platform.color + "20" }}>
<div className="inline-flex items-center justify-center w-14 h-14 rounded-lg shadow-lg" style={{ background: platform.color + "20" }}>
<span className="text-2xl">{platform.icon}</span>
</div>
<h1 className="text-2xl font-black text-gray-900 tracking-tight">
@@ -156,7 +156,7 @@ export function ExternalRedirectStep({ pledge, amount, eventName, externalUrl, e
</div>
{whatsappSent && (
<div className="rounded-xl bg-[#25D366]/10 border border-[#25D366]/20 p-2.5 text-xs text-[#25D366] font-medium flex items-center justify-center gap-2 animate-fade-in">
<div className="rounded-lg bg-[#25D366]/10 border border-[#25D366]/20 p-2.5 text-xs text-[#25D366] font-medium flex items-center justify-center gap-2 animate-fade-in">
<MessageCircle className="h-3.5 w-3.5" /> Donation link also sent to your WhatsApp
</div>
)}

View File

@@ -156,10 +156,10 @@ export function IdentityStep({ onSubmit, amount, zakatEligible, orgName }: Props
value={name}
onChange={(e) => setName(e.target.value)}
autoComplete="name"
className="w-full h-14 px-4 rounded-2xl border-2 border-gray-200 bg-white text-base font-medium placeholder:text-gray-300 focus:border-trust-blue focus:ring-4 focus:ring-trust-blue/10 outline-none transition-all"
className="w-full h-14 px-4 rounded-lg border-2 border-gray-200 bg-white text-base font-medium placeholder:text-gray-300 focus:border-trust-blue focus:ring-4 focus:ring-trust-blue/10 outline-none transition-all"
/>
{name && (
<div className="absolute right-3 top-1/2 -translate-y-1/2 text-success-green animate-scale-in"></div>
<div className="absolute right-3 top-1/2 -translate-y-1/2 text-success-green animate-fade-in"></div>
)}
</div>
@@ -173,10 +173,10 @@ export function IdentityStep({ onSubmit, amount, zakatEligible, orgName }: Props
onChange={(e) => setEmail(e.target.value)}
autoComplete="email"
inputMode="email"
className="w-full h-14 pl-12 pr-4 rounded-2xl border-2 border-gray-200 bg-white text-base font-medium placeholder:text-gray-300 focus:border-trust-blue focus:ring-4 focus:ring-trust-blue/10 outline-none transition-all"
className="w-full h-14 pl-12 pr-4 rounded-lg border-2 border-gray-200 bg-white text-base font-medium placeholder:text-gray-300 focus:border-trust-blue focus:ring-4 focus:ring-trust-blue/10 outline-none transition-all"
/>
{hasEmail && (
<div className="absolute right-3 top-1/2 -translate-y-1/2 text-success-green animate-scale-in"></div>
<div className="absolute right-3 top-1/2 -translate-y-1/2 text-success-green animate-fade-in"></div>
)}
</div>
@@ -191,10 +191,10 @@ export function IdentityStep({ onSubmit, amount, zakatEligible, orgName }: Props
onChange={(e) => setPhone(e.target.value)}
autoComplete="tel"
inputMode="tel"
className="w-full h-14 pl-12 pr-4 rounded-2xl border-2 border-gray-200 bg-white text-base font-medium placeholder:text-gray-300 focus:border-trust-blue focus:ring-4 focus:ring-trust-blue/10 outline-none transition-all"
className="w-full h-14 pl-12 pr-4 rounded-lg border-2 border-gray-200 bg-white text-base font-medium placeholder:text-gray-300 focus:border-trust-blue focus:ring-4 focus:ring-trust-blue/10 outline-none transition-all"
/>
{hasPhone && (
<div className="absolute right-3 top-1/2 -translate-y-1/2 text-success-green animate-scale-in"></div>
<div className="absolute right-3 top-1/2 -translate-y-1/2 text-success-green animate-fade-in"></div>
)}
</div>
{!hasEmail && !hasPhone && (
@@ -220,14 +220,14 @@ export function IdentityStep({ onSubmit, amount, zakatEligible, orgName }: Props
<div className="space-y-3">
<button
onClick={() => setGiftAid(!giftAid)}
className={`w-full text-left rounded-2xl border-2 p-5 transition-all duration-300 ${
className={`w-full text-left rounded-lg border-2 p-5 transition-all duration-300 ${
giftAid
? "border-success-green bg-gradient-to-br from-success-green/5 to-emerald-50 shadow-lg shadow-success-green/10"
? "border-success-green bg-fulfilled-green/5"
: "border-gray-200 bg-white hover:border-success-green/40"
}`}
>
<div className="flex items-start gap-4">
<div className={`rounded-xl p-3 transition-all ${giftAid ? "bg-success-green shadow-lg shadow-success-green/30" : "bg-gray-100"}`}>
<div className={`rounded-lg p-3 transition-all ${giftAid ? "bg-success-green" : "bg-gray-100"}`}>
<Gift className={`h-6 w-6 transition-colors ${giftAid ? "text-white" : "text-gray-400"}`} />
</div>
<div className="flex-1">
@@ -236,7 +236,7 @@ export function IdentityStep({ onSubmit, amount, zakatEligible, orgName }: Props
{giftAid ? "Gift Aid added!" : "Add Gift Aid"}
</span>
{giftAid ? (
<span className="text-xs font-bold px-2.5 py-0.5 rounded-full bg-success-green text-white animate-scale-in flex items-center gap-1">
<span className="text-xs font-bold px-2.5 py-0.5 rounded-full bg-success-green text-white animate-fade-in flex items-center gap-1">
<Sparkles className="h-3 w-3" /> +£{(giftAidBonus / 100).toFixed(0)} free
</span>
) : (
@@ -249,7 +249,7 @@ export function IdentityStep({ onSubmit, amount, zakatEligible, orgName }: Props
{giftAid ? (
<div className="mt-2 space-y-2 animate-fade-in">
{/* Live math */}
<div className="flex items-center justify-between bg-white rounded-xl p-3 border border-success-green/20">
<div className="flex items-center justify-between bg-white rounded-lg p-3 border border-success-green/20">
<div>
<p className="text-xs text-muted-foreground">Your pledge</p>
<p className="font-bold">£{(amount / 100).toFixed(0)}</p>
@@ -278,7 +278,7 @@ export function IdentityStep({ onSubmit, amount, zakatEligible, orgName }: Props
{/* Gift Aid address + declaration (shown when Gift Aid is on) */}
{giftAid && showGiftAidAddress && (
<div className="rounded-2xl border-2 border-success-green/20 bg-white p-4 space-y-3 animate-fade-in">
<div className="rounded-lg border-2 border-success-green/20 bg-white p-4 space-y-3 animate-fade-in">
{/* HMRC requires home address */}
<div className="flex items-center gap-2 text-xs font-medium text-muted-foreground">
<MapPin className="h-3.5 w-3.5" />
@@ -292,10 +292,10 @@ export function IdentityStep({ onSubmit, amount, zakatEligible, orgName }: Props
value={addressLine1}
onChange={(e) => setAddressLine1(e.target.value)}
autoComplete="address-line1"
className="w-full h-12 px-4 rounded-xl border-2 border-gray-200 bg-white text-sm font-medium placeholder:text-gray-300 focus:border-success-green focus:ring-4 focus:ring-success-green/10 outline-none transition-all"
className="w-full h-12 px-4 rounded-lg border-2 border-gray-200 bg-white text-sm font-medium placeholder:text-gray-300 focus:border-success-green focus:ring-4 focus:ring-success-green/10 outline-none transition-all"
/>
{addressLine1 && (
<div className="absolute right-3 top-1/2 -translate-y-1/2 text-success-green text-sm animate-scale-in"></div>
<div className="absolute right-3 top-1/2 -translate-y-1/2 text-success-green text-sm animate-fade-in"></div>
)}
</div>
@@ -306,15 +306,15 @@ export function IdentityStep({ onSubmit, amount, zakatEligible, orgName }: Props
value={postcode}
onChange={(e) => setPostcode(e.target.value.toUpperCase())}
autoComplete="postal-code"
className="w-full h-12 px-4 rounded-xl border-2 border-gray-200 bg-white text-sm font-medium placeholder:text-gray-300 focus:border-success-green focus:ring-4 focus:ring-success-green/10 outline-none transition-all uppercase"
className="w-full h-12 px-4 rounded-lg border-2 border-gray-200 bg-white text-sm font-medium placeholder:text-gray-300 focus:border-success-green focus:ring-4 focus:ring-success-green/10 outline-none transition-all uppercase"
/>
{postcode.length >= 5 && (
<div className="absolute right-3 top-1/2 -translate-y-1/2 text-success-green text-sm animate-scale-in"></div>
<div className="absolute right-3 top-1/2 -translate-y-1/2 text-success-green text-sm animate-fade-in"></div>
)}
</div>
{/* HMRC declaration — exact model wording */}
<div className="rounded-xl bg-success-green/5 border border-success-green/10 p-3">
<div className="rounded-lg bg-success-green/5 border border-success-green/10 p-3">
<p className="text-xs font-bold text-gray-700 mb-1.5">Gift Aid Declaration</p>
<p className="text-[11px] text-muted-foreground leading-relaxed">
{GIFT_AID_DECLARATION}
@@ -406,7 +406,7 @@ function ConsentCheckbox({ checked, onChange, icon, label, description }: {
<button
type="button"
onClick={() => onChange(!checked)}
className={`w-full text-left rounded-2xl border-2 p-4 transition-all ${
className={`w-full text-left rounded-lg border-2 p-4 transition-all ${
checked
? "border-trust-blue bg-trust-blue/5 shadow-sm"
: "border-gray-200 bg-white hover:border-trust-blue/40"

View File

@@ -22,7 +22,7 @@ export function PaymentStep({ onSelect, amount }: Props) {
detail: "We'll give you the bank details. Transfer in your own time.",
fee: "Free",
feeClass: "text-success-green font-bold",
iconBg: "from-emerald-500 to-green-600",
iconBg: "bg-fulfilled-green",
highlight: true,
benefits: ["Zero fees", "Most charities prefer this"],
},
@@ -36,7 +36,7 @@ export function PaymentStep({ onSelect, amount }: Props) {
detail: "GoCardless collects it for you. Protected by the DD Guarantee.",
fee: "1% + 20p",
feeClass: "text-muted-foreground",
iconBg: "from-trust-blue to-blue-600",
iconBg: "bg-promise-blue",
highlight: false,
benefits: ["No action needed", "DD Guarantee"],
},
@@ -50,7 +50,7 @@ export function PaymentStep({ onSelect, amount }: Props) {
detail: "Powered by Stripe. Receipt emailed instantly.",
fee: "1.4% + 20p",
feeClass: "text-muted-foreground",
iconBg: "from-purple-500 to-violet-600",
iconBg: "bg-midnight",
highlight: false,
benefits: ["Instant confirmation", "All major cards"],
},
@@ -74,15 +74,15 @@ export function PaymentStep({ onSelect, amount }: Props) {
key={opt.id}
onClick={() => onSelect(opt.id)}
className={`
w-full text-left rounded-2xl border-2 bg-white p-5 transition-all duration-200 group card-hover
w-full text-left rounded-lg border-2 bg-white p-5 transition-all duration-200 group
${opt.highlight
? "border-success-green/40 shadow-sm shadow-success-green/10 hover:border-success-green hover:shadow-lg hover:shadow-success-green/15"
: "border-gray-200 hover:border-trust-blue/40 hover:shadow-lg hover:shadow-trust-blue/10"
? "border-success-green/40 hover:border-success-green hover:border-fulfilled-green"
: "border-gray-200 hover:border-trust-blue/40 hover:border-promise-blue"
}
`}
>
<div className="flex items-start gap-4">
<div className={`rounded-xl bg-gradient-to-br ${opt.iconBg} p-3 shadow-lg shadow-trust-blue/10 group-hover:scale-105 transition-transform`}>
<div className={`rounded-lg ${opt.iconBg} p-3 transition-transform`}>
<opt.icon className="h-5 w-5 text-white" />
</div>
<div className="flex-1 min-w-0">

View File

@@ -150,10 +150,10 @@ export function ScheduleStep({ amount, onSelect }: Props) {
{/* Pay Now */}
<button
onClick={() => onSelect({ mode: "now" })}
className="w-full text-left rounded-2xl border-2 border-gray-200 bg-white p-5 transition-all duration-200 card-hover hover:border-trust-blue/40 hover:shadow-lg group"
className="w-full text-left rounded-lg border-2 border-gray-200 bg-white p-5 transition-all duration-200 hover:border-trust-blue/40 hover:shadow-lg group"
>
<div className="flex items-start gap-4">
<div className="rounded-xl bg-gradient-to-br from-trust-blue to-blue-600 p-3 shadow-lg shadow-trust-blue/20 group-hover:scale-105 transition-transform">
<div className="rounded-lg bg-midnight p-3 transition-transform">
<Zap className="h-5 w-5 text-white" />
</div>
<div className="flex-1">
@@ -172,10 +172,10 @@ export function ScheduleStep({ amount, onSelect }: Props) {
{/* Pay on a date */}
<button
onClick={() => setMode("calendar")}
className="w-full text-left rounded-2xl border-2 border-success-green/30 bg-gradient-to-r from-success-green/5 to-white p-5 transition-all duration-200 card-hover hover:border-success-green hover:shadow-lg group"
className="w-full text-left rounded-lg border-2 border-success-green/30 bg-fulfilled-green/5 p-5 transition-all duration-200 hover:border-success-green hover:shadow-lg group"
>
<div className="flex items-start gap-4">
<div className="rounded-xl bg-gradient-to-br from-success-green to-emerald-600 p-3 shadow-lg shadow-success-green/20 group-hover:scale-105 transition-transform">
<div className="rounded-lg bg-fulfilled-green p-3 transition-transform">
<Calendar className="h-5 w-5 text-white" />
</div>
<div className="flex-1">
@@ -194,10 +194,10 @@ export function ScheduleStep({ amount, onSelect }: Props) {
{/* Installments */}
<button
onClick={() => setMode("installments")}
className="w-full text-left rounded-2xl border-2 border-gray-200 bg-white p-5 transition-all duration-200 card-hover hover:border-warm-amber/40 hover:shadow-lg group"
className="w-full text-left rounded-lg border-2 border-gray-200 bg-white p-5 transition-all duration-200 hover:border-warm-amber/40 hover:shadow-lg group"
>
<div className="flex items-start gap-4">
<div className="rounded-xl bg-gradient-to-br from-warm-amber to-orange-500 p-3 shadow-lg shadow-warm-amber/20 group-hover:scale-105 transition-transform">
<div className="rounded-lg bg-generosity-gold p-3 transition-transform">
<Repeat className="h-5 w-5 text-white" />
</div>
<div className="flex-1">
@@ -241,9 +241,9 @@ export function ScheduleStep({ amount, onSelect }: Props) {
<button
key={i}
onClick={() => setSelectedDate(s.date)}
className={`shrink-0 rounded-xl border-2 px-3.5 py-2 text-left transition-all ${
className={`shrink-0 rounded-lg border-2 px-3.5 py-2 text-left transition-all ${
isSelected
? "border-success-green bg-success-green/5 shadow-md shadow-success-green/10"
? "border-success-green bg-success-green/5"
: "border-gray-200 bg-white hover:border-success-green/40"
}`}
>
@@ -283,7 +283,7 @@ export function ScheduleStep({ amount, onSelect }: Props) {
disabled={day.isPast || !day.inMonth}
className={`h-9 w-9 mx-auto rounded-lg text-xs font-medium transition-all ${
isSelected
? "bg-success-green text-white font-bold shadow-md shadow-success-green/30"
? "bg-success-green text-white font-bold"
: isToday
? "bg-trust-blue/10 text-trust-blue font-bold"
: day.isPast || !day.inMonth
@@ -301,7 +301,7 @@ export function ScheduleStep({ amount, onSelect }: Props) {
{/* Selected date summary */}
{selectedDate && (
<div className="rounded-2xl bg-success-green/5 border border-success-green/20 p-4 text-center animate-scale-in">
<div className="rounded-lg bg-success-green/5 border border-success-green/20 p-4 text-center animate-fade-in">
<p className="text-xs text-muted-foreground">You&apos;ll pay</p>
<p className="text-xl font-black text-gray-900">£{pounds}</p>
<p className="text-sm font-medium text-success-green">{formatFull(selectedDate)}</p>
@@ -313,7 +313,7 @@ export function ScheduleStep({ amount, onSelect }: Props) {
<Button
size="xl"
className={`w-full ${selectedDate ? "bg-success-green hover:bg-success-green/90 shadow-lg shadow-success-green/25" : ""}`}
className={`w-full ${selectedDate ? "bg-success-green hover:bg-success-green/90" : ""}`}
disabled={!selectedDate}
onClick={handleDateConfirm}
>
@@ -345,9 +345,9 @@ export function ScheduleStep({ amount, onSelect }: Props) {
<button
key={n}
onClick={() => setInstallmentCount(n)}
className={`rounded-xl border-2 px-4 py-3 text-center transition-all min-w-[70px] ${
className={`rounded-lg border-2 px-4 py-3 text-center transition-all min-w-[70px] ${
installmentCount === n
? "border-warm-amber bg-warm-amber text-white font-bold shadow-lg shadow-warm-amber/25"
? "border-warm-amber bg-warm-amber text-white font-bold"
: "border-gray-200 bg-white hover:border-warm-amber/40"
}`}
>
@@ -359,7 +359,7 @@ export function ScheduleStep({ amount, onSelect }: Props) {
{/* Breakdown */}
<Card className="overflow-hidden">
<div className="h-1 bg-gradient-to-r from-warm-amber to-orange-400" />
<div className="h-1 bg-generosity-gold" />
<CardContent className="pt-4">
<div className="text-center mb-4">
<p className="text-xs text-muted-foreground">Monthly payment</p>
@@ -392,7 +392,7 @@ export function ScheduleStep({ amount, onSelect }: Props) {
</CardContent>
</Card>
<div className="rounded-xl bg-warm-amber/5 border border-warm-amber/20 p-3 text-center">
<div className="rounded-lg bg-warm-amber/5 border border-warm-amber/20 p-3 text-center">
<p className="text-xs text-muted-foreground">
We&apos;ll send you a reminder with payment details before each installment date.
You can pay via bank transfer, card, or Direct Debit.
@@ -401,7 +401,7 @@ export function ScheduleStep({ amount, onSelect }: Props) {
<Button
size="xl"
className="w-full bg-warm-amber hover:bg-warm-amber/90 shadow-lg shadow-warm-amber/25"
className="w-full bg-warm-amber hover:bg-warm-amber/90"
onClick={handleInstallmentConfirm}
>
<Check className="h-5 w-5 mr-2" />

View File

@@ -45,7 +45,7 @@ function SuccessContent() {
if (cancelled) {
return (
<div className="max-w-md mx-auto text-center space-y-6">
<div className="inline-flex items-center justify-center w-20 h-20 rounded-full bg-amber-100">
<div className="inline-flex items-center justify-center w-16 h-16 bg-amber-100">
<X className="h-10 w-10 text-amber-600" />
</div>
<h1 className="text-2xl font-extrabold text-gray-900">Payment Cancelled</h1>
@@ -89,7 +89,7 @@ function SuccessContent() {
return (
<div className="max-w-md mx-auto text-center space-y-6">
<div className="inline-flex items-center justify-center w-20 h-20 rounded-full bg-success-green/10">
<div className="inline-flex items-center justify-center w-16 h-16 bg-success-green/10">
<Check className="h-10 w-10 text-success-green" />
</div>
<div className="space-y-2">
@@ -125,7 +125,7 @@ function SuccessContent() {
</CardContent>
</Card>
)}
<div className="rounded-2xl bg-trust-blue/5 border border-trust-blue/20 p-4 space-y-2">
<div className="rounded-lg bg-trust-blue/5 border border-trust-blue/20 p-4 space-y-2">
<p className="text-sm font-medium text-trust-blue">What happens next?</p>
<p className="text-sm text-muted-foreground">{nextStepMessages[rail] || nextStepMessages.card}</p>
</div>
@@ -138,7 +138,7 @@ function SuccessContent() {
export default function SuccessPage() {
return (
<div className="min-h-screen flex items-center justify-center bg-gradient-to-br from-trust-blue/5 via-white to-warm-amber/5 p-4">
<div className="min-h-screen flex items-center justify-center bg-paper p-4">
<Suspense fallback={
<div className="text-center space-y-4">
<Loader2 className="h-10 w-10 text-trust-blue animate-spin mx-auto" />

View File

@@ -89,7 +89,7 @@ export default function VolunteerPage() {
if (loading) {
return (
<div className="min-h-screen flex items-center justify-center bg-gradient-to-br from-trust-blue/5 via-white to-warm-amber/5">
<div className="min-h-screen flex items-center justify-center bg-paper">
<Loader2 className="h-8 w-8 text-trust-blue animate-spin" />
</div>
)
@@ -97,7 +97,7 @@ export default function VolunteerPage() {
if (error || !data) {
return (
<div className="min-h-screen flex items-center justify-center bg-gradient-to-br from-trust-blue/5 via-white to-warm-amber/5 p-4">
<div className="min-h-screen flex items-center justify-center bg-paper p-4">
<div className="text-center space-y-4">
<QrCode className="h-12 w-12 text-muted-foreground mx-auto" />
<h1 className="text-xl font-bold">QR code not found</h1>
@@ -108,7 +108,7 @@ export default function VolunteerPage() {
}
return (
<div className="min-h-screen bg-gradient-to-br from-trust-blue/5 via-white to-warm-amber/5">
<div className="min-h-screen bg-paper">
<div className="max-w-lg mx-auto px-4 py-8 space-y-6">
{/* Header */}
<div className="text-center space-y-2">
@@ -153,7 +153,7 @@ export default function VolunteerPage() {
</div>
<div className="h-3 rounded-full bg-gray-100 overflow-hidden">
<div
className="h-full rounded-full bg-gradient-to-r from-trust-blue to-success-green transition-all duration-1000"
className="h-full rounded-full bg-promise-blue transition-all duration-1000"
style={{ width: `${Math.round((data.stats.totalPaidPence / data.stats.totalPledgedPence) * 100)}%` }}
/>
</div>

View File

@@ -57,7 +57,7 @@ export function LiveTicker({ eventId }: LiveTickerProps) {
const totalToday = pledges.reduce((s, p) => s + p.amountPence, 0)
return (
<div className="rounded-2xl border bg-white p-4 space-y-3">
<div className="rounded-lg border bg-white p-4 space-y-3">
<div className="flex items-center justify-between">
<h3 className="font-bold text-sm flex items-center gap-2">
<TrendingUp className="h-4 w-4 text-trust-blue" /> Live Feed

View File

@@ -3,24 +3,25 @@ import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "@/lib/utils"
const buttonVariants = cva(
"inline-flex items-center justify-center whitespace-nowrap rounded-xl text-sm font-semibold ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 active:scale-[0.98]",
"inline-flex items-center justify-center whitespace-nowrap text-sm font-semibold ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
{
variants: {
variant: {
default: "bg-trust-blue text-white hover:bg-trust-blue/90 shadow-lg shadow-trust-blue/25",
destructive: "bg-danger-red text-white hover:bg-danger-red/90",
outline: "border-2 border-input bg-background hover:bg-accent hover:text-accent-foreground",
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
ghost: "hover:bg-accent hover:text-accent-foreground",
link: "text-trust-blue underline-offset-4 hover:underline",
success: "bg-success-green text-white hover:bg-success-green/90 shadow-lg shadow-success-green/25",
amber: "bg-warm-amber text-white hover:bg-warm-amber/90 shadow-lg shadow-warm-amber/25",
default: "bg-midnight text-white hover:bg-gray-800",
destructive: "bg-alert-red text-white hover:bg-alert-red/90",
outline: "border border-gray-200 bg-white hover:bg-gray-50 text-midnight",
secondary: "bg-gray-100 text-midnight hover:bg-gray-200",
ghost: "hover:bg-gray-100 text-midnight",
link: "text-promise-blue underline-offset-4 hover:underline",
success: "bg-fulfilled-green text-white hover:bg-fulfilled-green/90",
amber: "bg-generosity-gold text-white hover:bg-generosity-gold/90",
blue: "bg-promise-blue text-white hover:bg-promise-blue/90",
},
size: {
default: "h-11 px-6 py-2",
sm: "h-9 rounded-lg px-4",
lg: "h-14 rounded-2xl px-8 text-base",
xl: "h-16 rounded-2xl px-10 text-lg",
sm: "h-9 px-4",
lg: "h-14 px-8 text-base",
xl: "h-16 px-10 text-lg",
icon: "h-10 w-10",
},
},

View File

@@ -2,7 +2,7 @@ import * as React from "react"
import { cn } from "@/lib/utils"
const Card = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(({ className, ...props }, ref) => (
<div ref={ref} className={cn("rounded-2xl border bg-card text-card-foreground shadow-sm", className)} {...props} />
<div ref={ref} className={cn("rounded-lg border bg-card text-card-foreground shadow-sm", className)} {...props} />
))
Card.displayName = "Card"

View File

@@ -14,7 +14,7 @@ export function Dialog({ open, onOpenChange, children }: DialogProps) {
<div className="fixed inset-0 z-50">
<div className="fixed inset-0 bg-black/50 backdrop-blur-sm" onClick={() => onOpenChange(false)} />
<div className="fixed inset-0 flex items-center justify-center p-4">
<div className="relative bg-background rounded-2xl shadow-xl max-w-lg w-full max-h-[90vh] overflow-y-auto p-6 animate-in fade-in-0 zoom-in-95">
<div className="relative bg-background rounded-lg shadow-xl max-w-lg w-full max-h-[90vh] overflow-y-auto p-6 animate-in fade-in-0 zoom-in-95">
{children}
</div>
</div>

View File

@@ -40,7 +40,7 @@ DropdownMenuTrigger.displayName = "DropdownMenuTrigger"
function DropdownMenuContent({ children, className, align = "end" }: { children: React.ReactNode; className?: string; align?: "start" | "end" }) {
return (
<div className={cn(
"absolute z-50 min-w-[180px] overflow-hidden rounded-xl border bg-white p-1.5 shadow-lg animate-scale-in",
"absolute z-50 min-w-[180px] overflow-hidden rounded-lg border bg-white p-1.5 shadow-lg animate-scale-in",
align === "end" ? "right-0" : "left-0",
"top-full mt-1",
className

View File

@@ -5,7 +5,7 @@ const Input = React.forwardRef<HTMLInputElement, React.InputHTMLAttributes<HTMLI
<input
type={type}
className={cn(
"flex h-11 w-full rounded-xl border border-input bg-background px-4 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-trust-blue focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
"flex h-11 w-full rounded-lg border border-input bg-background px-4 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-trust-blue focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
className
)}
ref={ref}

View File

@@ -5,7 +5,7 @@ const Select = React.forwardRef<HTMLSelectElement, React.SelectHTMLAttributes<HT
<select
ref={ref}
className={cn(
"flex h-11 w-full rounded-xl border border-input bg-background px-4 py-2 text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-trust-blue focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
"flex h-11 w-full rounded-lg border border-input bg-background px-4 py-2 text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-trust-blue focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
className
)}
{...props}

View File

@@ -1,7 +1,7 @@
import { cn } from "@/lib/utils"
function Skeleton({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
return <div className={cn("animate-pulse rounded-xl bg-muted", className)} {...props} />
return <div className={cn("animate-pulse rounded-lg bg-muted", className)} {...props} />
}
export { Skeleton }

View File

@@ -16,7 +16,7 @@ function Tabs({ value, onValueChange, children, className }: { value: string; on
function TabsList({ children, className }: { children: React.ReactNode; className?: string }) {
return (
<div className={cn("inline-flex h-10 items-center justify-center rounded-xl bg-muted p-1 text-muted-foreground", className)}>
<div className={cn("inline-flex h-10 items-center justify-center rounded-lg bg-muted p-1 text-muted-foreground", className)}>
{children}
</div>
)

View File

@@ -5,7 +5,7 @@ const Textarea = React.forwardRef<HTMLTextAreaElement, React.TextareaHTMLAttribu
({ className, ...props }, ref) => (
<textarea
className={cn(
"flex min-h-[80px] w-full rounded-xl border border-input bg-background px-4 py-3 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-trust-blue focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
"flex min-h-[80px] w-full rounded-lg border border-input bg-background px-4 py-3 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-trust-blue focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
className
)}
ref={ref}

View File

@@ -33,7 +33,7 @@ export function ToastProvider({ children }: { children: React.ReactNode }) {
<div
key={t.id}
className={cn(
"rounded-xl px-4 py-3 text-sm font-medium text-white shadow-lg animate-in slide-in-from-right",
"rounded-lg px-4 py-3 text-sm font-medium text-white shadow-lg animate-in slide-in-from-right",
t.type === 'success' && 'bg-success-green',
t.type === 'error' && 'bg-danger-red',
t.type === 'info' && 'bg-trust-blue',

View File

@@ -42,6 +42,14 @@ const config: Config = {
border: "hsl(var(--border))",
input: "hsl(var(--input))",
ring: "hsl(var(--ring))",
// Brand colors — named by psychology, not appearance
midnight: "#111827",
"promise-blue": "#1e40af",
"generosity-gold": "#f59e0b",
"fulfilled-green": "#16a34a",
"alert-red": "#dc2626",
paper: "#f9fafb",
// Legacy aliases (used across codebase)
"trust-blue": "#1e40af",
"warm-amber": "#f59e0b",
"success-green": "#16a34a",