diff --git a/src/app/(dashboard)/leads/[id]/page.tsx b/src/app/(dashboard)/leads/[id]/page.tsx
index 7530b5e..9136b4c 100644
--- a/src/app/(dashboard)/leads/[id]/page.tsx
+++ b/src/app/(dashboard)/leads/[id]/page.tsx
@@ -2,6 +2,7 @@
import Link from "next/link"
import { motion } from "framer-motion"
+import { use } from "react"
import { PageHeader } from "@/components/shared/page-header"
import { LeadDetailsCard } from "@/components/leads/lead-details-card"
import { LeadStatusBadge } from "@/components/leads/lead-status-badge"
@@ -19,8 +20,9 @@ import { getLeadById } from "@/data/leads"
import { getNotesByLeadId } from "@/data/notes"
import { ArrowLeft, Edit, ExternalLink } from "lucide-react"
-export default function LeadDetailsPage({ params }: { params: { id: string } }) {
- const lead = getLeadById(params.id)
+export default function LeadDetailsPage({ params }: { params: Promise<{ id: string }> }) {
+ const { id } = use(params)
+ const lead = getLeadById(id)
const leadNotes = lead ? getNotesByLeadId(lead.id) : []
if (!lead) {
diff --git a/src/app/globals.css b/src/app/globals.css
index b0b378f..b66e82b 100644
--- a/src/app/globals.css
+++ b/src/app/globals.css
@@ -2,74 +2,72 @@
@tailwind components;
@tailwind utilities;
-@layer base {
- :root {
- --background: 210 40% 98%;
- --foreground: 222.2 84% 4.9%;
- --card: 0 0% 100%;
- --card-foreground: 222.2 84% 4.9%;
- --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%;
- --sidebar: 222.2 84% 4.9%;
- --sidebar-foreground: 210 40% 98%;
- --sidebar-primary: 217.2 91.2% 59.8%;
- --sidebar-primary-foreground: 0 0% 100%;
- --sidebar-accent: 217.2 32.6% 17.5%;
- --sidebar-accent-foreground: 210 40% 98%;
- --sidebar-border: 217.2 32.6% 17.5%;
- --sidebar-ring: 224.3 76.3% 48%;
- --radius: 0.5rem;
- }
-
- .dark {
- --background: 222.2 84% 4.9%;
- --foreground: 210 40% 98%;
- --card: 222.2 84% 4.9%;
- --card-foreground: 210 40% 98%;
- --popover: 222.2 84% 4.9%;
- --popover-foreground: 210 40% 98%;
- --primary: 217.2 91.2% 59.8%;
- --primary-foreground: 222.2 47.4% 11.2%;
- --secondary: 217.2 32.6% 17.5%;
- --secondary-foreground: 210 40% 98%;
- --muted: 217.2 32.6% 17.5%;
- --muted-foreground: 215 20.2% 65.1%;
- --accent: 217.2 32.6% 17.5%;
- --accent-foreground: 210 40% 98%;
- --destructive: 0 62.8% 30.6%;
- --destructive-foreground: 210 40% 98%;
- --border: 217.2 32.6% 17.5%;
- --input: 217.2 32.6% 17.5%;
- --ring: 224.3 76.3% 48%;
- --sidebar: 222.2 84% 4.9%;
- --sidebar-foreground: 210 40% 98%;
- --sidebar-primary: 217.2 91.2% 59.8%;
- --sidebar-primary-foreground: 0 0% 100%;
- --sidebar-accent: 217.2 32.6% 17.5%;
- --sidebar-accent-foreground: 210 40% 98%;
- --sidebar-border: 217.2 32.6% 17.5%;
- --sidebar-ring: 224.3 76.3% 48%;
- }
-
- * {
- @apply border-border;
- }
-
- body {
- @apply bg-background text-foreground;
- font-family: var(--font-inter), ui-sans-serif, system-ui, sans-serif;
- }
+:root {
+ --background: 210 40% 98%;
+ --foreground: 222.2 84% 4.9%;
+ --card: 0 0% 100%;
+ --card-foreground: 222.2 84% 4.9%;
+ --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%;
+ --sidebar: 222.2 84% 4.9%;
+ --sidebar-foreground: 210 40% 98%;
+ --sidebar-primary: 217.2 91.2% 59.8%;
+ --sidebar-primary-foreground: 0 0% 100%;
+ --sidebar-accent: 217.2 32.6% 17.5%;
+ --sidebar-accent-foreground: 210 40% 98%;
+ --sidebar-border: 217.2 32.6% 17.5%;
+ --sidebar-ring: 224.3 76.3% 48%;
+ --radius: 0.5rem;
+}
+
+.dark {
+ --background: 222.2 84% 4.9%;
+ --foreground: 210 40% 98%;
+ --card: 222.2 84% 4.9%;
+ --card-foreground: 210 40% 98%;
+ --popover: 222.2 84% 4.9%;
+ --popover-foreground: 210 40% 98%;
+ --primary: 217.2 91.2% 59.8%;
+ --primary-foreground: 222.2 47.4% 11.2%;
+ --secondary: 217.2 32.6% 17.5%;
+ --secondary-foreground: 210 40% 98%;
+ --muted: 217.2 32.6% 17.5%;
+ --muted-foreground: 215 20.2% 65.1%;
+ --accent: 217.2 32.6% 17.5%;
+ --accent-foreground: 210 40% 98%;
+ --destructive: 0 62.8% 30.6%;
+ --destructive-foreground: 210 40% 98%;
+ --border: 217.2 32.6% 17.5%;
+ --input: 217.2 32.6% 17.5%;
+ --ring: 224.3 76.3% 48%;
+ --sidebar: 222.2 84% 4.9%;
+ --sidebar-foreground: 210 40% 98%;
+ --sidebar-primary: 217.2 91.2% 59.8%;
+ --sidebar-primary-foreground: 0 0% 100%;
+ --sidebar-accent: 217.2 32.6% 17.5%;
+ --sidebar-accent-foreground: 210 40% 98%;
+ --sidebar-border: 217.2 32.6% 17.5%;
+ --sidebar-ring: 224.3 76.3% 48%;
+}
+
+* {
+ @apply border-border;
+}
+
+body {
+ @apply bg-background text-foreground;
+ font-family: var(--font-inter), ui-sans-serif, system-ui, sans-serif;
}
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index 64a14ed..b333a78 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -25,7 +25,7 @@ export default function RootLayout({
return (
-
+
{children}
diff --git a/src/app/login/page.tsx b/src/app/login/page.tsx
index ae34cc4..f9d1265 100644
--- a/src/app/login/page.tsx
+++ b/src/app/login/page.tsx
@@ -1,15 +1,18 @@
"use client"
-import { useState } from "react"
+import { useState, useEffect, useRef } from "react"
import { useRouter } from "next/navigation"
-import { motion } from "framer-motion"
-import { Button } from "@/components/ui/button"
-import { Input } from "@/components/ui/input"
-import { Label } from "@/components/ui/label"
-import { Checkbox } from "@/components/ui/checkbox"
import { COMPANY_NAME } from "@/lib/constants"
import { Eye, EyeOff, Loader2 } from "lucide-react"
+const waves = [
+ { a: 16, f: 0.011, s: 0.018, y: 0.38, fill: "rgba(27,176,206,0.18)" },
+ { a: 20, f: 0.008, s: 0.013, y: 0.52, fill: "rgba(27,176,206,0.25)" },
+ { a: 12, f: 0.015, s: 0.025, y: 0.28, fill: "rgba(180,192,210,0.06)" },
+ { a: 26, f: 0.006, s: 0.010, y: 0.65, fill: "rgba(180,192,210,0.15)" },
+ { a: 10, f: 0.019, s: 0.030, y: 0.20, fill: "rgba(27,176,206,0.10)" },
+]
+
export default function LoginPage() {
const router = useRouter()
const [email, setEmail] = useState("admin@coastalit.com")
@@ -17,175 +20,575 @@ export default function LoginPage() {
const [showPassword, setShowPassword] = useState(false)
const [loading, setLoading] = useState(false)
const [remember, setRemember] = useState(false)
+ const [counts, setCounts] = useState({ leads: 0, conversion: 0, users: 0 })
+ const counterStarted = useRef(false)
+ const canvasRef = useRef(null)
+ const starsCanvasRightRef = useRef(null)
+
+ useEffect(() => {
+ const canvas = canvasRef.current
+ if (!canvas) return
+ const ctx = canvas.getContext("2d")
+ if (!ctx) return
+
+ let animId: number
+ let time = 0
+
+ const resize = () => {
+ const parent = canvas.parentElement!
+ const rect = parent.getBoundingClientRect()
+ const dpr = window.devicePixelRatio || 1
+ canvas.width = rect.width * dpr
+ canvas.height = 200 * dpr
+ canvas.style.width = rect.width + "px"
+ canvas.style.height = "200px"
+ ctx!.setTransform(dpr, 0, 0, dpr, 0, 0)
+ }
+
+ resize()
+ window.addEventListener("resize", resize)
+
+ const draw = () => {
+ const w = canvas.width / (window.devicePixelRatio || 1)
+ const h = 200
+ ctx!.clearRect(0, 0, w, h)
+
+ for (const wave of waves) {
+ ctx!.beginPath()
+ ctx!.moveTo(0, h)
+ for (let x = 0; x <= w; x++) {
+ const y = wave.y * h + Math.sin(x * wave.f + time * wave.s) * wave.a
+ ctx!.lineTo(x, y)
+ }
+ ctx!.lineTo(w, h)
+ ctx!.closePath()
+ ctx!.fillStyle = wave.fill
+ ctx!.fill()
+ }
+
+ time += 1
+ animId = requestAnimationFrame(draw)
+ }
+
+ animId = requestAnimationFrame(draw)
+
+ return () => {
+ cancelAnimationFrame(animId)
+ window.removeEventListener("resize", resize)
+ }
+ }, [])
+
+ useEffect(() => {
+ const canvases = [starsCanvasRightRef.current].filter(Boolean) as HTMLCanvasElement[]
+ if (canvases.length === 0) return
+
+ const stars = Array.from({ length: 312 }, () => ({
+ x: Math.random(),
+ y: Math.random(),
+ r: 0.2 + Math.random() * 0.6,
+ baseOpacity: 0.12 + Math.random() * 0.43,
+ speed: 0.003 + Math.random() * 0.015,
+ phase: Math.random() * Math.PI * 2,
+ driftX: (Math.random() - 0.5) * 0.00003,
+ driftY: (Math.random() - 0.5) * 0.00003,
+ }))
+
+ let animId: number
+ let time = 0
+
+ const resize = () => {
+ for (const c of canvases) {
+ const dpr = window.devicePixelRatio || 1
+ const rect = c.getBoundingClientRect()
+ c.width = rect.width * dpr
+ c.height = rect.height * dpr
+ const ctx = c.getContext("2d")
+ if (ctx) ctx.setTransform(dpr, 0, 0, dpr, 0, 0)
+ }
+ }
+
+ resize()
+ const ros = canvases.map((c) => {
+ const ro = new ResizeObserver(() => resize())
+ ro.observe(c.parentElement!)
+ return ro
+ })
+ window.addEventListener("resize", resize)
+
+ const draw = () => {
+ time += 1
+ for (const c of canvases) {
+ const dpr = window.devicePixelRatio || 1
+ const w = c.width / dpr
+ const h = c.height / dpr
+ const ctx = c.getContext("2d")
+ if (!ctx) continue
+ ctx.clearRect(0, 0, w, h)
+
+ for (const star of stars) {
+ const x = ((star.x + time * star.driftX) % 1) * w
+ const y = ((star.y + time * star.driftY) % 1) * h
+ const opacity = star.baseOpacity * (0.5 + 0.5 * Math.sin(time * star.speed + star.phase))
+
+ ctx.beginPath()
+ ctx.arc(x, y, star.r, 0, Math.PI * 2)
+ ctx.fillStyle = `rgba(255,255,255,${opacity})`
+ ctx.fill()
+
+ if (star.r > 0.5) {
+ ctx.beginPath()
+ ctx.arc(x, y, star.r * 1.8, 0, Math.PI * 2)
+ ctx.fillStyle = `rgba(255,255,255,${opacity * 0.06})`
+ ctx.fill()
+ }
+ }
+ }
+
+ animId = requestAnimationFrame(draw)
+ }
+
+ animId = requestAnimationFrame(draw)
+
+ return () => {
+ cancelAnimationFrame(animId)
+ ros.forEach((ro) => ro.disconnect())
+ window.removeEventListener("resize", resize)
+ }
+ }, [])
+
+ useEffect(() => {
+ if (counterStarted.current) return
+ counterStarted.current = true
+ const targets = { leads: 1247, conversion: 40, users: 83 }
+ const steps = 150
+
+ const delayTimer = setTimeout(() => {
+ let step = 0
+ const interval = setInterval(() => {
+ step++
+ if (step >= steps) {
+ clearInterval(interval)
+ setCounts(targets)
+ return
+ }
+ setCounts({
+ leads: Math.min(Math.floor((targets.leads / steps) * step), targets.leads),
+ conversion: Math.min(Math.floor((targets.conversion / steps) * step), targets.conversion),
+ users: Math.min(Math.floor((targets.users / steps) * step), targets.users),
+ })
+ }, 15)
+ }, 400)
+
+ return () => clearTimeout(delayTimer)
+ }, [])
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()
setLoading(true)
-
await new Promise((resolve) => setTimeout(resolve, 1200))
-
router.push("/dashboard")
}
return (
-
- {/* Left - Brand panel */}
-
-
+ <>
+
-
-
+
+
+

-
{COMPANY_NAME}
-
-
-
- Your Agency's Growth Starts Here
-
-
- Manage leads, track conversions, and grow your web development business with our CRM.
-
+
+
+
+ Your Agency's{" "}
+ Growth{" "}
+ Starts Here
+
+
+ Manage leads, track conversions, and grow your web development business with our CRM.
+
+
+
+
{counts.leads.toLocaleString()}
+
leads tracked
+
+
+
{counts.conversion}%
+
conversion lift
+
+
+
{counts.users}
+
active users
+
+
+
+
-
-
+
+
“This CRM transformed how we manage our sales pipeline. We've seen a 40% increase in lead conversion.”
-
-
-
-
Marcus Johnson
-
Sales Lead, Coast IT
-
-
-
-
-
-
- © 2026 {COMPANY_NAME}. All rights reserved.
-
-
-
- {/* Right - Login form */}
-
-
- {/* Mobile logo */}
-
-

-
{COMPANY_NAME}
-
-
-
-
Welcome back
-
- Sign in to your account to continue
+
+ Marcus Johnson, Sales Lead at Coast IT
-
-
-
-
-
+
+
+
+
+
+
+
+
+ Welcome back
+
+
+ Sign in to your account to continue
+
+
+
-
-
- setRemember(checked as boolean)}
- />
-
-
-
-
+
+
-
- By signing in, you agree to our{" "}
- {" "}
- and{" "}
-
-
-
+
+ By signing in, you agree to our{" "}
+ {" "}
+ and{" "}
+
+
+
+
-
+ >
)
}