Skip to content

Commit 3e127b7

Browse files
committed
DT cards: ghost number watermark + hover reveal
1 parent 951c066 commit 3e127b7

19 files changed

Lines changed: 305 additions & 107 deletions

app/globals.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
@import url("https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&family=JetBrains+Mono:wght@400;500&display=swap");
1+
@import url("https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&family=JetBrains+Mono:wght@400;500&display=swap&family=Caveat:wght@500;600;700&display=swap");
22

33
@tailwind base;
44
@tailwind components;

components/DigitalTransformation.jsx

Lines changed: 41 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,28 @@
11
"use client";
22
import { motion } from "framer-motion";
3-
import {
4-
FiArrowRight, FiCompass,
5-
} from "react-icons/fi";
3+
import { FiArrowRight, FiCompass } from "react-icons/fi";
64
import {
75
FaMagnifyingGlass, FaBullseye, FaShieldHalved, FaRocket, FaCloudArrowUp,
86
FaGraduationCap, FaUsers, FaBolt, FaChartColumn, FaArrowsRotate,
97
} from "react-icons/fa6";
108

11-
// 10 steps + matching Style-D icons
9+
// 10 steps + Style-D icons
1210
const STEPS = [
13-
{ n: "01", t: "Discover", d: "Assess current tools, gaps & goals", Icon: FaMagnifyingGlass },
14-
{ n: "02", t: "Strategise", d: "Design a tailored roadmap", Icon: FaBullseye },
15-
{ n: "03", t: "Secure", d: "Secure, governed foundation", Icon: FaShieldHalved },
16-
{ n: "04", t: "Pilot", d: "Prove value, low-risk rollout", Icon: FaRocket },
17-
{ n: "05", t: "Migrate", d: "Email, files & apps moved", Icon: FaCloudArrowUp },
18-
{ n: "06", t: "Enable", d: "Role-based training that sticks", Icon: FaGraduationCap },
19-
{ n: "07", t: "Adopt", d: "Drive usage via change mgmt", Icon: FaUsers },
20-
{ n: "08", t: "Automate", d: "Streamline with Power Platform", Icon: FaBolt },
21-
{ n: "09", t: "Measure", d: "Track adoption & prove ROI", Icon: FaChartColumn },
22-
{ n: "10", t: "Sustain", d: "Train-the-trainer + support", Icon: FaArrowsRotate },
11+
{ n: "01", t: "Discover", d: "Assess current tools, gaps & goals", Icon: FaMagnifyingGlass },
12+
{ n: "02", t: "Strategise", d: "Design a tailored roadmap", Icon: FaBullseye },
13+
{ n: "03", t: "Secure", d: "Secure, governed foundation", Icon: FaShieldHalved },
14+
{ n: "04", t: "Pilot", d: "Prove value, low-risk rollout", Icon: FaRocket },
15+
{ n: "05", t: "Migrate", d: "Email, files & apps moved", Icon: FaCloudArrowUp },
16+
{ n: "06", t: "Enable", d: "Role-based training that sticks", Icon: FaGraduationCap },
17+
{ n: "07", t: "Adopt", d: "Drive usage via change mgmt", Icon: FaUsers },
18+
{ n: "08", t: "Automate", d: "Streamline with Power Platform", Icon: FaBolt },
19+
{ n: "09", t: "Measure", d: "Track adoption & prove ROI", Icon: FaChartColumn },
20+
{ n: "10", t: "Sustain", d: "Train-the-trainer + support", Icon: FaArrowsRotate },
2321
];
2422

2523
export default function DigitalTransformation() {
2624
return (
27-
<section id="transformation" className="py-10 border-t border-line relative overflow-hidden">
25+
<section id="transformation" className="py-16 border-t border-line relative overflow-hidden">
2826
<div className="pointer-events-none absolute inset-0 -z-10">
2927
<div className="absolute top-10 left-1/4 w-80 h-80 rounded-full bg-accent2/15 blur-3xl" />
3028
</div>
@@ -41,8 +39,8 @@ export default function DigitalTransformation() {
4139
</p>
4240
</div>
4341

44-
{/* smaller cards · icon LEFT · number TOP-RIGHT · hover animation */}
45-
<div className="mt-10 grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-5 gap-3">
42+
{/* cards with GIANT ghost number watermark */}
43+
<div className="mt-10 grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-5 gap-4">
4644
{STEPS.map((s, i) => {
4745
const { Icon } = s;
4846
return (
@@ -53,24 +51,40 @@ export default function DigitalTransformation() {
5351
whileInView={{ opacity: 1, y: 0 }}
5452
viewport={{ once: true, margin: "-40px" }}
5553
transition={{ duration: 0.4, delay: (i % 5) * 0.05 }}
56-
whileHover={{ y: -4 }}
57-
className="group relative glass rounded-xl p-3.5 hover:border-accent/60 transition-colors"
54+
whileHover={{ y: -6 }}
55+
className="group relative overflow-hidden rounded-2xl p-4 bg-surface/60 border border-line
56+
hover:border-accent/60 hover:shadow-xl hover:shadow-accent/10 transition-all"
5857
>
59-
{/* number — top-right corner */}
60-
<span className="absolute top-2.5 right-3 text-[11px] font-mono text-muted/50 group-hover:text-accent transition-colors">
58+
{/* GIANT ghost number watermark */}
59+
<span
60+
aria-hidden="true"
61+
className="pointer-events-none select-none absolute -top-5 -right-3 leading-none font-black
62+
text-[90px] text-accent/[0.15] group-hover:text-accent/[0.14]
63+
group-hover:scale-110 group-hover:-translate-y-1
64+
transition-all duration-500 ease-out"
65+
>
6166
{s.n}
6267
</span>
6368

64-
{/* icon — left */}
65-
<span className="inline-flex w-9 h-9 rounded-lg bg-gradient-to-br from-accent to-accent2 text-bg items-center justify-center shadow-sm group-hover:scale-110 transition-transform">
66-
<Icon size={16} />
69+
{/* icon — top-left */}
70+
<span className="relative z-10 inline-flex w-11 h-11 rounded-xl bg-gradient-to-br from-accent to-accent2
71+
text-white items-center justify-center shadow-md shadow-accent/25
72+
group-hover:scale-110 group-hover:rotate-3 transition-transform duration-300">
73+
<Icon size={17} />
6774
</span>
6875

6976
{/* text */}
70-
<div className="mt-2.5">
71-
<div className="font-bold text-sm group-hover:text-accent transition-colors">{s.t}</div>
72-
<div className="text-[11px] text-muted mt-0.5 leading-snug">{s.d}</div>
77+
<div className="relative z-10 mt-3">
78+
<div className="font-bold text-[15px] group-hover:text-accent transition-colors">{s.t}</div>
79+
<div className="text-[11.5px] text-muted mt-1 leading-snug">{s.d}</div>
7380
</div>
81+
82+
{/* subtle arrow reveal on hover */}
83+
<span className="relative z-10 mt-2 flex items-center gap-1 text-[11px] font-semibold text-accent
84+
opacity-0 -translate-x-1 group-hover:opacity-100 group-hover:translate-x-0
85+
transition-all duration-300">
86+
Details <FiArrowRight size={11} />
87+
</span>
7488
</motion.div>
7589
);
7690
})}

components/Hero.jsx

Lines changed: 150 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,102 +1,177 @@
11
"use client";
22
import { motion } from "framer-motion";
33
import { FiDownload } from "react-icons/fi";
4+
import {
5+
FaRocket, FaCloud, FaUsers, FaShieldHalved, FaChartColumn, FaStar,
6+
} from "react-icons/fa6";
47
import { profile, stats } from "@/data/portfolio";
58

9+
/* icon map for the stats strip */
10+
function statIcon(key) {
11+
const map = {
12+
rocket: FaRocket,
13+
cloud: FaCloud,
14+
users: FaUsers,
15+
shield: FaShieldHalved,
16+
chart: FaChartColumn,
17+
star: FaStar,
18+
};
19+
return map[key] || FaStar;
20+
}
21+
622
export default function Hero() {
723
return (
8-
<section className="relative overflow-hidden pt-32 pb-20">
24+
<section className="relative overflow-hidden pt-32 pb-16">
925
<div className="pointer-events-none absolute inset-0 -z-10">
1026
<div className="absolute top-10 left-1/4 w-72 h-72 rounded-full bg-accent/20 blur-3xl animate-blob" />
1127
<div className="absolute top-40 right-1/4 w-80 h-80 rounded-full bg-accent2/20 blur-3xl animate-blob [animation-delay:4s]" />
1228
</div>
1329

14-
<div className="container grid md:grid-cols-[1.15fr_0.85fr] gap-10 items-center">
15-
<div>
16-
<motion.h1
17-
initial={{ opacity: 0, y: 16 }}
18-
animate={{ opacity: 1, y: 0 }}
19-
transition={{ duration: 0.6 }}
20-
className="text-4xl sm:text-6xl font-extrabold leading-[1.05]"
21-
>
22-
Hi, I&apos;m {profile.firstName}{" "}
23-
<span className="inline-block animate-wave origin-[70%_70%]">👋</span>
24-
<br />
25-
<span className="text-gradient">{profile.role}</span>
26-
</motion.h1>
27-
28-
<motion.p
29-
initial={{ opacity: 0, y: 16 }}
30-
animate={{ opacity: 1, y: 0 }}
31-
transition={{ duration: 0.6, delay: 0.12 }}
32-
className="mt-5 text-base sm:text-lg text-muted max-w-xl"
33-
>
34-
{profile.tagline}
35-
</motion.p>
30+
<div className="container">
31+
{/* ---------- TOP: text + photo ---------- */}
32+
<div className="grid md:grid-cols-[1.1fr_0.9fr] gap-10 md:gap-16 lg:gap-24 items-center">
33+
<div>
34+
<motion.h1
35+
initial={{ opacity: 0, y: 16 }}
36+
animate={{ opacity: 1, y: 0 }}
37+
transition={{ duration: 0.6 }}
38+
className="text-4xl sm:text-6xl font-extrabold leading-[1.05]"
39+
>
40+
Hi, I&apos;m {profile.firstName}{" "}
41+
<span className="inline-block animate-wave origin-[70%_70%]">👋</span>
42+
</motion.h1>
3643

37-
<motion.p
38-
initial={{ opacity: 0, y: 12 }}
39-
animate={{ opacity: 1, y: 0 }}
40-
transition={{ duration: 0.6, delay: 0.2 }}
41-
className="mt-4 text-sm font-mono text-accent"
42-
>
43-
{profile.locationNote}
44-
</motion.p>
44+
<motion.p
45+
initial={{ opacity: 0, y: 16 }}
46+
animate={{ opacity: 1, y: 0 }}
47+
transition={{ duration: 0.6, delay: 0.08 }}
48+
className="text-2xl sm:text-3xl font-bold mt-3 text-gradient leading-snug"
49+
>
50+
{profile.role}
51+
</motion.p>
4552

46-
<motion.div
47-
initial={{ opacity: 0, y: 16 }}
48-
animate={{ opacity: 1, y: 0 }}
49-
transition={{ duration: 0.6, delay: 0.28 }}
50-
className="mt-7 flex flex-wrap gap-4"
51-
>
52-
<a href="#projects" className="px-6 py-3 rounded-full bg-accent text-bg font-semibold hover:opacity-90 transition">
53-
See my work →
54-
</a>
55-
<a href="#training" className="px-6 py-3 rounded-full border border-line hover:border-accent transition">
56-
Book training
57-
</a>
58-
{profile.resumeUrl && (
59-
<a
60-
href={profile.resumeUrl}
61-
target="_blank"
62-
rel="noopener noreferrer"
63-
download="Krishna_Andhe_CV.pdf"
64-
className="px-6 py-3 rounded-full border border-accent text-accent font-semibold flex items-center gap-2 hover:bg-accent hover:text-bg transition"
53+
{/* handwritten tagline (Style C) */}
54+
{profile.handwritten && (
55+
<motion.div
56+
initial={{ opacity: 0, y: 10 }}
57+
animate={{ opacity: 1, y: 0 }}
58+
transition={{ duration: 0.6, delay: 0.2 }}
59+
className="relative inline-block mt-4"
6560
>
66-
<FiDownload size={18} /> Download Resume
67-
</a>
61+
<span className="font-hand text-accent text-3xl sm:text-4xl leading-none select-none">
62+
{profile.handwritten}
63+
</span>
64+
<motion.svg
65+
viewBox="0 0 300 18" fill="none" preserveAspectRatio="none"
66+
className="absolute -bottom-2 left-0 w-full h-3 text-accent" aria-hidden="true"
67+
>
68+
<motion.path
69+
d="M3 12 C 60 4, 120 4, 180 9 S 260 14, 297 6"
70+
stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" fill="none"
71+
initial={{ pathLength: 0, opacity: 0 }}
72+
animate={{ pathLength: 1, opacity: 1 }}
73+
transition={{ duration: 0.9, delay: 0.5, ease: "easeInOut" }}
74+
/>
75+
</motion.svg>
76+
</motion.div>
6877
)}
69-
</motion.div>
7078

79+
<motion.p
80+
initial={{ opacity: 0, y: 16 }}
81+
animate={{ opacity: 1, y: 0 }}
82+
transition={{ duration: 0.6, delay: 0.3 }}
83+
className="mt-6 text-base sm:text-lg text-muted max-w-xl"
84+
>
85+
{profile.tagline}
86+
</motion.p>
87+
88+
<motion.p
89+
initial={{ opacity: 0, y: 12 }}
90+
animate={{ opacity: 1, y: 0 }}
91+
transition={{ duration: 0.6, delay: 0.36 }}
92+
className="mt-4 text-sm font-mono text-accent"
93+
>
94+
{profile.locationNote}
95+
</motion.p>
96+
97+
<motion.div
98+
initial={{ opacity: 0, y: 16 }}
99+
animate={{ opacity: 1, y: 0 }}
100+
transition={{ duration: 0.6, delay: 0.44 }}
101+
className="mt-7 flex flex-wrap gap-4"
102+
>
103+
<a href="#projects" data-hover
104+
className="px-6 py-3 rounded-full bg-accent text-bg font-semibold hover:opacity-90 transition">
105+
See my work →
106+
</a>
107+
<a href="#training" data-hover
108+
className="px-6 py-3 rounded-full border border-line hover:border-accent transition">
109+
Book training
110+
</a>
111+
{profile.resumeUrl && (
112+
<a href={profile.resumeUrl} target="_blank" rel="noopener noreferrer" download="Krishna_Andhe_CV.pdf" data-hover
113+
className="px-6 py-3 rounded-full border border-accent text-accent font-semibold flex items-center gap-2 hover:bg-accent hover:text-bg transition">
114+
<FiDownload size={18} /> Résumé
115+
</a>
116+
)}
117+
</motion.div>
118+
</div>
119+
120+
{/* photo — squircle */}
71121
<motion.div
72-
initial={{ opacity: 0 }}
73-
animate={{ opacity: 1 }}
74-
transition={{ duration: 0.8, delay: 0.42 }}
75-
className="mt-12 grid grid-cols-3 gap-6 max-w-md"
122+
initial={{ opacity: 0, scale: 0.92 }}
123+
animate={{ opacity: 1, scale: 1 }}
124+
transition={{ duration: 0.7, delay: 0.2 }}
125+
className="relative w-72 sm:w-80 lg:w-96 aspect-[4/5] mx-auto md:justify-self-end md:mr-2 lg:mr-6"
76126
>
77-
{stats.map((s) => (
78-
<div key={s.label}>
79-
<div className="text-2xl sm:text-3xl font-bold text-gradient">{s.value}</div>
80-
<div className="text-sm text-muted">{s.label}</div>
81-
</div>
82-
))}
127+
<div className="absolute -inset-3 rounded-[30%] bg-gradient-to-tr from-accent via-transparent to-accent2 blur-md opacity-70 animate-spinSlow" />
128+
<div className="relative w-full h-full rounded-[30%]">
129+
{/* eslint-disable-next-line @next/next/no-img-element */}
130+
<img src={profile.photo} alt={profile.name}
131+
className="w-full h-full rounded-[28%] object-cover object-top bg-surface" />
132+
</div>
83133
</motion.div>
84134
</div>
85135

136+
{/* ---------- STATS STRIP (full width, bordered, dividers) ---------- */}
86137
<motion.div
87-
initial={{ opacity: 0, scale: 0.92 }}
88-
animate={{ opacity: 1, scale: 1 }}
89-
transition={{ duration: 0.7, delay: 0.2 }}
90-
className="relative w-72 sm:w-80 lg:w-96 aspect-[4/5] mx-auto md:justify-self-end md:mr-2 lg:mr-6"
138+
initial={{ opacity: 0, y: 24 }}
139+
animate={{ opacity: 1, y: 0 }}
140+
transition={{ duration: 0.6, delay: 0.6 }}
141+
className="mt-14 glass rounded-2xl px-2 sm:px-4 py-5 sm:py-6"
91142
>
92-
<div className="absolute -inset-3 rounded-[30%] bg-gradient-to-tr from-accent via-transparent to-accent2 blur-md opacity-60 animate-spinSlow" />
93-
{/* eslint-disable-next-line @next/next/no-img-element */}
94-
<img
95-
src={profile.photo}
96-
alt={profile.name}
97-
className="relative w-full h-full rounded-[30%] object-cover object-top ring-1 ring-line/50 shadow-2xl shadow-accent/10"
98-
/>
99-
<div/>
143+
<div className="overflow-x-auto no-scrollbar">
144+
<ul className="flex items-center min-w-max sm:min-w-0">
145+
{stats.map((s, i) => {
146+
const Icon = statIcon(s.icon);
147+
return (
148+
<li
149+
key={s.label}
150+
className={`flex-1 flex items-center gap-3 sm:gap-4 px-4 sm:px-6 ${
151+
i < stats.length - 1 ? "border-r border-line/70" : ""
152+
}`}
153+
>
154+
<motion.span
155+
initial={{ scale: 0.6, opacity: 0 }}
156+
animate={{ scale: 1, opacity: 1 }}
157+
transition={{ delay: 0.7 + i * 0.08, type: "spring", stiffness: 220, damping: 14 }}
158+
className="shrink-0 text-accent"
159+
>
160+
<Icon size={26} />
161+
</motion.span>
162+
<span className="min-w-0">
163+
<span className="block text-2xl sm:text-3xl font-extrabold leading-none">
164+
{s.value}
165+
</span>
166+
<span className="block text-[11px] sm:text-xs text-muted mt-1 whitespace-nowrap">
167+
{s.label}
168+
</span>
169+
</span>
170+
</li>
171+
);
172+
})}
173+
</ul>
174+
</div>
100175
</motion.div>
101176
</div>
102177
</section>

0 commit comments

Comments
 (0)