diff --git a/client/src/components/home/AboutSection.jsx b/client/src/components/home/AboutSection.jsx
deleted file mode 100644
index 77fe50b..0000000
--- a/client/src/components/home/AboutSection.jsx
+++ /dev/null
@@ -1,126 +0,0 @@
-import { useRef, useEffect } from 'react';
-import anime from 'animejs';
-import FeatureCard from './FeatureCard';
-import styles from './AboutSection.module.css';
-
-export default function AboutSection() {
- const sectionRef = useRef(null);
- const titleRef = useRef(null);
- const introRef = useRef(null);
- const cardsRef = useRef(null);
- const hasAnimated = useRef(false);
-
- useEffect(() => {
- const observer = new IntersectionObserver(
- (entries) => {
- entries.forEach((entry) => {
- if (entry.isIntersecting && !hasAnimated.current) {
- hasAnimated.current = true;
-
- // Animate title
- anime({
- targets: titleRef.current,
- translateY: [40, 0],
- opacity: [0, 1],
- duration: 800,
- easing: 'easeOutExpo',
- });
-
- // Animate intro text
- anime({
- targets: introRef.current,
- translateY: [30, 0],
- opacity: [0, 1],
- duration: 800,
- delay: 200,
- easing: 'easeOutExpo',
- });
-
- // Cards will animate via CSS with stagger
- anime({
- targets: cardsRef.current,
- opacity: [0, 1],
- duration: 600,
- delay: 400,
- easing: 'easeOutExpo',
- });
-
- observer.unobserve(entry.target);
- }
- });
- },
- { threshold: 0.2 }
- );
-
- if (sectionRef.current) {
- observer.observe(sectionRef.current);
- }
-
- return () => observer.disconnect();
- }, []);
-
- const features = [
- {
- icon: '🔐',
- title: 'Password Security',
- description: 'Learn to create strong passwords and understand common vulnerabilities through interactive challenges.',
- },
- {
- icon: '🛡️',
- title: 'Privacy Protection',
- description: 'Master data protection techniques and learn how to keep your personal information safe online.',
- },
- {
- icon: '🎮',
- title: 'Gesture Controls',
- description: 'Navigate through challenges using hand gestures powered by MediaPipe technology.',
- },
- {
- icon: '🤖',
- title: 'AI Companions',
- description: 'Collect unique AI-generated robot companions to help you on your cybersecurity journey.',
- },
- {
- icon: '🏆',
- title: 'Earn Rewards',
- description: 'Gain points, coins, badges, and unlock new areas as you master security concepts.',
- },
- {
- icon: '🌐',
- title: 'Immersive 3D World',
- description: 'Explore cyberpunk environments built with Three.js in a visually stunning game world.',
- },
- ];
-
- return (
-
- {/* Forest Silhouette Background */}
-
-
-
-
-
- What is SafeForest ?
-
-
-
- SafeForest is a digital forest sanctuary where cybersecurity education
- meets immersive gameplay. Transform complex security concepts into engaging challenges
- while exploring a world where technology and nature harmoniously blend.
-
-
-
- {features.map((feature, index) => (
-
- ))}
-
-
-
- );
-}
diff --git a/client/src/components/home/AboutSection.module.css b/client/src/components/home/AboutSection.module.css
deleted file mode 100644
index 7003885..0000000
--- a/client/src/components/home/AboutSection.module.css
+++ /dev/null
@@ -1,211 +0,0 @@
-/* ===== ABOUT SECTION - DIGITAL FOREST SANCTUARY ===== */
-/* Cyber-Forest Sanctuary Theme */
-
-.aboutSection {
- position: relative;
- min-height: 100vh;
- display: flex;
- align-items: center;
- justify-content: center;
- padding: 120px 24px;
- background: var(--neo-bg);
- overflow: hidden;
-}
-
-/* Forest Silhouette Background */
-.forestBackground {
- position: absolute;
- bottom: 0;
- left: 0;
- right: 0;
- height: 300px;
- background: linear-gradient(
- to top,
- rgba(0, 255, 159, 0.05) 0%,
- transparent 100%
- );
- opacity: 0.3;
- z-index: 0;
-}
-
-.forestBackground::before {
- content: '';
- position: absolute;
- bottom: 0;
- left: 0;
- right: 0;
- height: 150px;
- background: repeating-linear-gradient(
- 90deg,
- transparent,
- transparent 40px,
- rgba(0, 255, 159, 0.1) 40px,
- rgba(0, 255, 159, 0.1) 42px
- );
- clip-path: polygon(
- 0% 100%,
- 5% 60%,
- 8% 100%,
- 12% 50%,
- 15% 100%,
- 20% 40%,
- 23% 100%,
- 28% 55%,
- 32% 100%,
- 36% 45%,
- 40% 100%,
- 44% 60%,
- 48% 100%,
- 52% 50%,
- 56% 100%,
- 60% 40%,
- 64% 100%,
- 68% 55%,
- 72% 100%,
- 76% 45%,
- 80% 100%,
- 84% 60%,
- 88% 100%,
- 92% 50%,
- 95% 100%,
- 100% 100%
- );
-}
-
-/* Circuit Pattern Overlay */
-.circuitPattern {
- position: absolute;
- inset: 0;
- background-image:
- linear-gradient(var(--neo-border) 1px, transparent 1px),
- linear-gradient(90deg, var(--neo-border) 1px, transparent 1px);
- background-size: 50px 50px;
- opacity: 0.03;
- z-index: 0;
- animation: circuitMove 20s linear infinite;
-}
-
-@keyframes circuitMove {
- from {
- background-position: 0 0, 0 0;
- }
- to {
- background-position: 50px 50px, 50px 50px;
- }
-}
-
-/* Container */
-.container {
- position: relative;
- max-width: 1300px;
- width: 100%;
- margin: 0 auto;
- z-index: 1;
-}
-
-/* Section Title */
-.sectionTitle {
- font-family: 'Orbitron', sans-serif;
- font-size: clamp(42px, 6vw, 72px);
- font-weight: 900;
- color: var(--neo-text);
- text-align: center;
- margin: 0 0 32px;
- letter-spacing: -1px;
- text-transform: uppercase;
- text-shadow: 0 4px 30px rgba(0, 0, 0, 0.3);
-}
-
-.titleHighlight {
- background: linear-gradient(
- 135deg,
- var(--forest-emerald),
- var(--portal-cyan),
- var(--portal-purple)
- );
- -webkit-background-clip: text;
- -webkit-text-fill-color: transparent;
- background-clip: text;
- filter: drop-shadow(0 0 30px rgba(0, 255, 159, 0.5));
- font-weight: 900;
-}
-
-/* Intro Text */
-.intro {
- font-family: 'Fredoka', sans-serif;
- font-size: clamp(16px, 2.2vw, 20px);
- font-weight: 400;
- color: var(--neo-text-dim);
- text-align: center;
- max-width: 900px;
- margin: 0 auto 80px;
- line-height: 1.9;
- letter-spacing: 0.2px;
-}
-
-.intro strong {
- color: var(--neo-text);
- font-weight: 600;
- background: linear-gradient(135deg, var(--forest-emerald), var(--portal-cyan));
- -webkit-background-clip: text;
- -webkit-text-fill-color: transparent;
- background-clip: text;
-}
-
-/* Features Grid */
-.featuresGrid {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
- gap: 32px;
- margin-top: 80px;
- opacity: 0;
-}
-
-/* Accessibility: Reduced Motion */
-@media (prefers-reduced-motion: reduce) {
- .circuitPattern {
- animation: none;
- }
-}
-
-/* Responsive Design */
-@media (max-width: 1024px) {
- .featuresGrid {
- grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
- gap: 24px;
- }
-}
-
-@media (max-width: 768px) {
- .aboutSection {
- padding: 100px 20px;
- }
-
- .intro {
- margin-bottom: 60px;
- }
-
- .featuresGrid {
- grid-template-columns: 1fr;
- gap: 20px;
- margin-top: 60px;
- }
-
- .forestBackground {
- height: 200px;
- }
-
- .forestBackground::before {
- height: 100px;
- }
-}
-
-@media (max-width: 480px) {
- .aboutSection {
- padding: 80px 16px;
- }
-
- .circuitPattern {
- display: none;
- }
-}
diff --git a/client/src/components/home/DemoSection.jsx b/client/src/components/home/DemoSection.jsx
deleted file mode 100644
index 53ffe1a..0000000
--- a/client/src/components/home/DemoSection.jsx
+++ /dev/null
@@ -1,75 +0,0 @@
-import { useRef, useEffect } from 'react';
-import anime from 'animejs';
-import styles from './DemoSection.module.css';
-
-export default function DemoSection() {
- const sectionRef = useRef(null);
- const videoRef = useRef(null);
- const titleRef = useRef(null);
- const hasAnimated = useRef(false);
-
- useEffect(() => {
- // Intersection Observer for scroll animation
- const observer = new IntersectionObserver(
- (entries) => {
- entries.forEach((entry) => {
- if (entry.isIntersecting && !hasAnimated.current) {
- hasAnimated.current = true;
-
- anime({
- targets: titleRef.current,
- translateY: [40, 0],
- opacity: [0, 1],
- duration: 800,
- easing: 'easeOutExpo',
- });
-
- anime({
- targets: videoRef.current,
- translateY: [60, 0],
- opacity: [0, 1],
- duration: 1000,
- delay: 200,
- easing: 'easeOutExpo',
- });
-
- observer.unobserve(entry.target);
- }
- });
- },
- { threshold: 0.2 }
- );
-
- if (sectionRef.current) {
- observer.observe(sectionRef.current);
- }
-
- return () => observer.disconnect();
- }, []);
-
- return (
-
-
-
- See It In Action
-
-
-
- {/* Video placeholder - replace with actual video later */}
-
-
- ▶
-
-
Demo Video Coming Soon
-
-
-
-
- Watch how players navigate through cyberpunk environments, solve security
- challenges using hand gestures, and earn rewards for mastering digital
- safety skills.
-
-
-
- );
-}
diff --git a/client/src/components/home/DemoSection.module.css b/client/src/components/home/DemoSection.module.css
deleted file mode 100644
index 093384f..0000000
--- a/client/src/components/home/DemoSection.module.css
+++ /dev/null
@@ -1,287 +0,0 @@
-/* ===== DEMO SECTION - TERMINAL/MONITOR FRAME ===== */
-/* Cyber-Forest Sanctuary Theme */
-
-.demoSection {
- position: relative;
- min-height: 100vh;
- display: flex;
- align-items: center;
- justify-content: center;
- padding: 100px 24px;
- background: var(--neo-bg);
- overflow: hidden;
-}
-
-/* Data Stream Background */
-.demoSection::before {
- content: '';
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- height: 100%;
- background: repeating-linear-gradient(
- 0deg,
- transparent,
- transparent 2px,
- var(--neo-border) 2px,
- var(--neo-border) 3px
- );
- opacity: 0.02;
- animation: dataStream 20s linear infinite;
- z-index: 0;
-}
-
-@keyframes dataStreamMove {
- from {
- background-position: 0 0;
- }
- to {
- background-position: 0 100px;
- }
-}
-
-.container {
- position: relative;
- max-width: 1200px;
- width: 100%;
- margin: 0 auto;
- z-index: 1;
-}
-
-.sectionTitle {
- font-family: 'Orbitron', sans-serif;
- font-size: clamp(42px, 6vw, 68px);
- font-weight: 900;
- color: var(--neo-text);
- text-align: center;
- margin: 0 0 60px;
- background: linear-gradient(135deg, var(--portal-cyan), var(--portal-purple));
- -webkit-background-clip: text;
- -webkit-text-fill-color: transparent;
- background-clip: text;
- letter-spacing: -0.8px;
- text-transform: uppercase;
- filter: drop-shadow(0 0 30px rgba(0, 242, 255, 0.3));
-}
-
-/* Terminal/Monitor Frame */
-.videoWrapper {
- position: relative;
- width: 100%;
- max-width: 950px;
- margin: 0 auto 48px;
- border-radius: 24px;
- overflow: visible;
-}
-
-.videoWrapper::before {
- content: '';
- position: absolute;
- inset: -4px;
- border-radius: 24px;
- background: linear-gradient(
- 135deg,
- var(--portal-cyan),
- var(--portal-purple),
- var(--forest-emerald)
- );
- background-size: 300% 300%;
- animation: borderFlow 6s ease infinite;
- z-index: -1;
- filter: blur(8px);
-}
-
-/* Terminal Header Bar */
-.videoWrapper::after {
- content: '● ● ●';
- position: absolute;
- top: -40px;
- left: 20px;
- font-size: 16px;
- color: var(--neo-text-dim);
- letter-spacing: 8px;
- font-family: 'Orbitron', sans-serif;
-}
-
-.videoPlaceholder {
- position: relative;
- width: 100%;
- aspect-ratio: 16 / 9;
- background: var(--glass-bg);
- backdrop-filter: blur(var(--glass-blur));
- -webkit-backdrop-filter: blur(var(--glass-blur));
- border: 2px solid var(--neo-border);
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- gap: 24px;
- border-radius: 20px;
- overflow: hidden;
- box-shadow:
- 0 0 40px rgba(0, 242, 255, 0.2),
- 0 20px 60px rgba(0, 0, 0, 0.3),
- inset 0 0 40px rgba(0, 242, 255, 0.05);
-}
-
-/* Scanline Effect */
-.videoPlaceholder::before {
- content: '';
- position: absolute;
- inset: 0;
- background: repeating-linear-gradient(
- 0deg,
- rgba(0, 0, 0, 0.05),
- rgba(0, 0, 0, 0.05) 2px,
- transparent 2px,
- transparent 4px
- );
- pointer-events: none;
- z-index: 2;
-}
-
-/* Terminal Grid Background */
-.videoPlaceholder::after {
- content: '';
- position: absolute;
- inset: 0;
- background-image:
- linear-gradient(var(--neo-border) 1px, transparent 1px),
- linear-gradient(90deg, var(--neo-border) 1px, transparent 1px);
- background-size: 40px 40px;
- opacity: 0.05;
- pointer-events: none;
-}
-
-.playButton {
- position: relative;
- width: 90px;
- height: 90px;
- border-radius: 50%;
- background: linear-gradient(135deg, var(--portal-cyan), var(--portal-purple));
- display: grid;
- place-items: center;
- cursor: pointer;
- transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
- z-index: 3;
- box-shadow:
- 0 0 40px rgba(0, 242, 255, 0.5),
- 0 0 60px rgba(112, 0, 255, 0.4);
-}
-
-.playButton::before {
- content: '';
- position: absolute;
- inset: -6px;
- border-radius: 50%;
- background: linear-gradient(135deg, var(--portal-cyan), var(--portal-purple));
- z-index: -1;
- animation: portalPulse 3s ease-in-out infinite;
- opacity: 0.6;
-}
-
-.playButton:hover {
- transform: scale(1.15);
- box-shadow:
- 0 0 60px rgba(0, 242, 255, 0.7),
- 0 0 100px rgba(112, 0, 255, 0.6);
-}
-
-.playIcon {
- font-size: 36px;
- color: white;
- margin-left: 6px;
- filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.3));
-}
-
-.placeholderText {
- font-family: 'Orbitron', sans-serif;
- font-size: 24px;
- font-weight: 700;
- color: var(--neo-text);
- margin: 0;
- letter-spacing: 0.5px;
- text-transform: uppercase;
- position: relative;
- z-index: 3;
- text-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
-}
-
-.description {
- font-family: 'Fredoka', sans-serif;
- font-size: clamp(15px, 2vw, 19px);
- font-weight: 400;
- color: var(--neo-text-dim);
- text-align: center;
- max-width: 800px;
- margin: 0 auto;
- line-height: 1.9;
- letter-spacing: 0.2px;
-}
-
-/* Accessibility: Reduced Motion */
-@media (prefers-reduced-motion: reduce) {
- .demoSection::before,
- .videoWrapper::before,
- .playButton::before {
- animation: none !important;
- }
-
- .playButton:hover {
- transform: scale(1.08);
- }
-}
-
-/* Responsive Design */
-@media (max-width: 768px) {
- .demoSection {
- padding: 80px 20px;
- }
-
- .sectionTitle {
- margin-bottom: 48px;
- }
-
- .videoWrapper::after {
- top: -35px;
- left: 16px;
- font-size: 14px;
- }
-
- .playButton {
- width: 70px;
- height: 70px;
- }
-
- .playIcon {
- font-size: 28px;
- }
-
- .placeholderText {
- font-size: 20px;
- }
-}
-
-@media (max-width: 480px) {
- .demoSection {
- padding: 60px 16px;
- }
-
- .playButton {
- width: 60px;
- height: 60px;
- }
-
- .playIcon {
- font-size: 24px;
- }
-
- .placeholderText {
- font-size: 18px;
- }
-
- .videoWrapper::after {
- display: none;
- }
-}
diff --git a/client/src/components/home/FeatureCard.jsx b/client/src/components/home/FeatureCard.jsx
deleted file mode 100644
index fdfa51b..0000000
--- a/client/src/components/home/FeatureCard.jsx
+++ /dev/null
@@ -1,100 +0,0 @@
-import { useRef, useEffect } from 'react';
-import styles from './FeatureCard.module.css';
-
-export default function FeatureCard({ icon, title, description, index }) {
- const cardRef = useRef(null);
-
- useEffect(() => {
- const card = cardRef.current;
- if (!card) return;
-
- const handleMouseMove = (e) => {
- const rect = card.getBoundingClientRect();
- const x = e.clientX - rect.left;
- const y = e.clientY - rect.top;
-
- card.style.setProperty('--mouse-x', `${x}px`);
- card.style.setProperty('--mouse-y', `${y}px`);
- };
-
- card.addEventListener('mousemove', handleMouseMove);
- return () => card.removeEventListener('mousemove', handleMouseMove);
- }, []);
-
- // SVG Icon mapping
- const getSvgIcon = () => {
- switch (title) {
- case 'Password Security':
- return (
-
-
-
-
- );
- case 'Privacy Protection':
- return (
-
-
-
- );
- case 'Gesture Controls':
- return (
-
-
-
-
-
-
- );
- case 'AI Companions':
- return (
-
-
-
-
-
-
-
- );
- case 'Earn Rewards':
- return (
-
-
-
-
- );
- case 'Immersive 3D World':
- return (
-
-
-
-
-
- );
- default:
- return {icon} ;
- }
- };
-
- return (
-
-
-
-
-
-
- {getSvgIcon()}
-
-
-
{title}
-
{description}
-
-
-
- );
-}
diff --git a/client/src/components/home/FeatureCard.module.css b/client/src/components/home/FeatureCard.module.css
deleted file mode 100644
index 7edbd6d..0000000
--- a/client/src/components/home/FeatureCard.module.css
+++ /dev/null
@@ -1,280 +0,0 @@
-/* ===== HOLOGRAPHIC TERMINAL FEATURE CARD ===== */
-/* Cyber-Forest Sanctuary Theme */
-
-.card {
- position: relative;
- padding: 36px 28px;
- border-radius: 20px;
- background: var(--glass-bg);
- backdrop-filter: blur(var(--glass-blur));
- -webkit-backdrop-filter: blur(var(--glass-blur));
- border: 1px solid;
- border-image: linear-gradient(
- 135deg,
- var(--portal-cyan),
- var(--portal-purple),
- transparent
- ) 1;
- transition: all 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
- overflow: hidden;
- cursor: pointer;
- --mouse-x: 50%;
- --mouse-y: 50%;
-}
-
-/* Animated Border Gradient */
-.card::before {
- content: '';
- position: absolute;
- inset: 0;
- border-radius: 20px;
- padding: 2px;
- background: linear-gradient(
- 135deg,
- var(--portal-cyan),
- var(--portal-purple),
- var(--forest-emerald),
- var(--portal-cyan)
- );
- background-size: 300% 300%;
- animation: borderFlow 4s ease infinite;
- -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
- -webkit-mask-composite: xor;
- mask-composite: exclude;
- opacity: 0;
- transition: opacity 0.4s;
-}
-
-.card:hover::before {
- opacity: 1;
-}
-
-/* Scanning Line Animation */
-.scanLine {
- position: absolute;
- top: 0;
- left: 0;
- width: 100%;
- height: 2px;
- background: linear-gradient(
- 90deg,
- transparent,
- var(--portal-cyan),
- transparent
- );
- box-shadow: 0 0 10px var(--portal-cyan);
- transform: translateY(-100%);
- opacity: 0;
- transition: opacity 0.3s;
-}
-
-.card:hover .scanLine {
- animation: scan 2s linear infinite;
- opacity: 1;
-}
-
-/* Corner Brackets */
-.cornerBrackets div {
- position: absolute;
- width: 20px;
- height: 20px;
- border: 2px solid var(--security-shield);
- opacity: 0;
- transition: opacity 0.4s, transform 0.4s;
-}
-
-.cornerTL {
- top: 8px;
- left: 8px;
- border-right: none;
- border-bottom: none;
- transform: translate(-4px, -4px);
-}
-
-.cornerTR {
- top: 8px;
- right: 8px;
- border-left: none;
- border-bottom: none;
- transform: translate(4px, -4px);
-}
-
-.cornerBL {
- bottom: 8px;
- left: 8px;
- border-right: none;
- border-top: none;
- transform: translate(-4px, 4px);
-}
-
-.cornerBR {
- bottom: 8px;
- right: 8px;
- border-left: none;
- border-top: none;
- transform: translate(4px, 4px);
-}
-
-.card:hover .cornerBrackets div {
- opacity: 0.6;
- transform: translate(0, 0);
-}
-
-/* Icon Wrapper */
-.iconWrapper {
- width: 64px;
- height: 64px;
- margin: 0 auto 20px;
- display: flex;
- align-items: center;
- justify-content: center;
- border-radius: 16px;
- background: linear-gradient(135deg, var(--portal-cyan), var(--portal-purple));
- padding: 16px;
- transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
- position: relative;
- z-index: 1;
-}
-
-.iconWrapper svg {
- width: 100%;
- height: 100%;
- color: white;
- filter: drop-shadow(0 4px 8px rgba(0, 0, 0, 0.3));
- transition: transform 0.4s;
-}
-
-.card:hover .iconWrapper {
- transform: translateY(-8px) scale(1.1);
- box-shadow:
- 0 0 30px rgba(0, 242, 255, 0.5),
- 0 20px 40px rgba(0, 0, 0, 0.3);
-}
-
-.card:hover .iconWrapper svg {
- transform: rotate(5deg);
-}
-
-/* Title */
-.title {
- font-family: 'Orbitron', sans-serif;
- font-size: 22px;
- font-weight: 700;
- color: var(--neo-text);
- margin: 0 0 16px;
- letter-spacing: 0.5px;
- text-align: center;
- text-transform: uppercase;
- position: relative;
- z-index: 1;
- transition: color 0.3s;
-}
-
-.card:hover .title {
- background: linear-gradient(135deg, var(--portal-cyan), var(--forest-emerald));
- -webkit-background-clip: text;
- -webkit-text-fill-color: transparent;
- background-clip: text;
-}
-
-/* Description */
-.description {
- font-family: 'Fredoka', sans-serif;
- font-size: 15px;
- font-weight: 400;
- color: var(--neo-text-dim);
- line-height: 1.7;
- margin: 0;
- text-align: center;
- position: relative;
- z-index: 1;
-}
-
-/* Interactive Spotlight Effect */
-.spotlight {
- position: absolute;
- inset: 0;
- background: radial-gradient(
- 600px circle at var(--mouse-x) var(--mouse-y),
- rgba(0, 242, 255, 0.1),
- transparent 40%
- );
- opacity: 0;
- transition: opacity 0.3s;
- pointer-events: none;
-}
-
-.card:hover .spotlight {
- opacity: 1;
-}
-
-/* Hover Animation */
-.card:hover {
- transform: translateY(-12px) scale(1.02);
- box-shadow:
- 0 0 40px rgba(0, 242, 255, 0.3),
- 0 0 80px rgba(112, 0, 255, 0.2),
- 0 30px 60px rgba(0, 0, 0, 0.3);
-}
-
-/* Staggered Entrance Animation */
-@keyframes cardEntrance {
- from {
- opacity: 0;
- transform: translateY(60px) scale(0.95);
- }
- to {
- opacity: 1;
- transform: translateY(0) scale(1);
- }
-}
-
-.card {
- animation: cardEntrance 0.8s cubic-bezier(0.34, 1.56, 0.64, 1) backwards;
- animation-delay: calc(var(--index) * 0.1s);
-}
-
-/* Accessibility: Reduced Motion */
-@media (prefers-reduced-motion: reduce) {
- .card,
- .scanLine,
- .card::before,
- .iconWrapper,
- .iconWrapper svg {
- animation: none !important;
- transition-duration: 0.1s;
- }
-
- .card:hover {
- transform: translateY(-6px);
- }
-
- .card:hover .iconWrapper {
- transform: translateY(-4px) scale(1.05);
- }
-
- .card:hover .iconWrapper svg {
- transform: none;
- }
-}
-
-/* Responsive Design */
-@media (max-width: 768px) {
- .card {
- padding: 28px 24px;
- }
-
- .iconWrapper {
- width: 56px;
- height: 56px;
- margin-bottom: 16px;
- }
-
- .title {
- font-size: 20px;
- }
-
- .description {
- font-size: 14px;
- }
-}
diff --git a/client/src/components/home/FeaturesShowcase.jsx b/client/src/components/home/FeaturesShowcase.jsx
new file mode 100644
index 0000000..d5b4baf
--- /dev/null
+++ b/client/src/components/home/FeaturesShowcase.jsx
@@ -0,0 +1,91 @@
+import { useRef, useEffect, useState } from 'react';
+import styles from './FeaturesShowcase.module.css';
+
+export default function FeaturesShowcase() {
+ const sectionRef = useRef(null);
+ const [isVisible, setIsVisible] = useState(false);
+
+ useEffect(() => {
+ const observer = new IntersectionObserver(
+ ([entry]) => {
+ if (entry.isIntersecting) {
+ setIsVisible(true);
+ }
+ },
+ { threshold: 0.1 }
+ );
+
+ if (sectionRef.current) {
+ observer.observe(sectionRef.current);
+ }
+
+ return () => observer.disconnect();
+ }, []);
+
+ const features = [
+ {
+ title: 'Password Security',
+ description: 'Learn to create unbreakable passwords through interactive challenges. Test password strength in real-time and discover common vulnerabilities.',
+ icon: '🔐',
+ color: 'var(--portal-cyan)',
+ },
+ {
+ title: 'Privacy Protection',
+ description: 'Master data privacy concepts with hands-on scenarios. Understand tracking, cookies, and how to protect your digital footprint.',
+ icon: '🛡️',
+ color: 'var(--forest-emerald)',
+ },
+ {
+ title: 'Gesture Controls',
+ description: 'Navigate through the cyber-forest using intuitive hand gestures powered by MediaPipe AI. Experience cutting-edge interaction technology.',
+ icon: '👋',
+ color: 'var(--portal-purple)',
+ },
+ {
+ title: 'AI Companions',
+ description: 'Generate unique AI-powered companion dolls that guide you through challenges. Each companion is personalized to your learning journey.',
+ icon: '🤖',
+ color: 'var(--portal-pink)',
+ },
+ ];
+
+ return (
+
+
+
+
Why SafeForest?
+
+ Immersive learning meets cutting-edge technology in a gamified cybersecurity adventure
+
+
+
+
+ {features.map((feature, index) => (
+
+
+
+
+
{feature.title}
+
{feature.description}
+
+
+ ))}
+
+
+
+ );
+}
diff --git a/client/src/components/home/FeaturesShowcase.module.css b/client/src/components/home/FeaturesShowcase.module.css
new file mode 100644
index 0000000..8ca273a
--- /dev/null
+++ b/client/src/components/home/FeaturesShowcase.module.css
@@ -0,0 +1,220 @@
+.featuresShowcase {
+ position: relative;
+ padding: var(--space-3xl) var(--space-md);
+ background: var(--section-bg-alt);
+ overflow: hidden;
+}
+
+.container {
+ max-width: var(--container-xl);
+ margin: 0 auto;
+}
+
+.header {
+ text-align: center;
+ margin-bottom: var(--space-3xl);
+ opacity: 0;
+ transform: translateY(30px);
+ transition: all 0.8s ease;
+}
+
+.featuresShowcase.visible .header {
+ opacity: 1;
+ transform: translateY(0);
+}
+
+.heading {
+ font-family: 'Orbitron', sans-serif;
+ font-size: clamp(36px, 5vw, 56px);
+ font-weight: 900;
+ color: var(--neo-text);
+ margin: 0 0 var(--space-md);
+ letter-spacing: -1px;
+ text-transform: uppercase;
+ background: linear-gradient(135deg, var(--neo-cyan), var(--neo-purple));
+ background-clip: text;
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+}
+
+.subheading {
+ font-family: 'Fredoka', sans-serif;
+ font-size: clamp(16px, 2vw, 20px);
+ font-weight: 500;
+ color: var(--neo-text-dim);
+ max-width: 700px;
+ margin: 0 auto;
+ line-height: 1.6;
+}
+
+.featuresGrid {
+ display: flex;
+ flex-direction: column;
+ gap: var(--space-3xl);
+}
+
+.feature {
+ display: flex;
+ gap: var(--space-2xl);
+ align-items: center;
+ opacity: 0;
+ transform: translateX(-50px);
+ transition: all 0.8s cubic-bezier(0.34, 1.56, 0.64, 1);
+}
+
+.featuresShowcase.visible .feature {
+ opacity: 1;
+ transform: translateX(0);
+}
+
+.feature.reverse {
+ flex-direction: row-reverse;
+ transform: translateX(50px);
+}
+
+.featuresShowcase.visible .feature.reverse {
+ transform: translateX(0);
+}
+
+.featureVisual {
+ flex: 1 1 400px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ min-height: 300px;
+}
+
+.iconWrapper {
+ position: relative;
+ width: 200px;
+ height: 200px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background: var(--glass-bg);
+ border: 2px solid var(--glass-border);
+ border-radius: 24px;
+ backdrop-filter: blur(var(--glass-blur));
+ -webkit-backdrop-filter: blur(var(--glass-blur));
+ transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
+ box-shadow: var(--glass-shadow);
+}
+
+.iconWrapper::before {
+ content: '';
+ position: absolute;
+ inset: -2px;
+ border-radius: 24px;
+ padding: 2px;
+ background: linear-gradient(135deg, var(--feature-color), transparent);
+ -webkit-mask:
+ linear-gradient(#fff 0 0) content-box,
+ linear-gradient(#fff 0 0);
+ -webkit-mask-composite: xor;
+ mask-composite: exclude;
+ opacity: 0;
+ transition: opacity 0.4s ease;
+}
+
+.feature:hover .iconWrapper::before {
+ opacity: 1;
+}
+
+.featureIcon {
+ font-size: 80px;
+ filter: drop-shadow(0 0 20px var(--feature-color));
+ transition: transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
+}
+
+.feature:hover .iconWrapper {
+ transform: translateY(-8px) scale(1.05);
+ box-shadow:
+ 0 20px 60px rgba(0, 242, 255, 0.3),
+ 0 20px 60px rgba(112, 0, 255, 0.2);
+}
+
+.feature:hover .featureIcon {
+ transform: scale(1.1) rotate(5deg);
+}
+
+.featureContent {
+ flex: 1 1 400px;
+}
+
+.featureTitle {
+ font-family: 'Orbitron', sans-serif;
+ font-size: clamp(24px, 3vw, 32px);
+ font-weight: 800;
+ color: var(--neo-text);
+ margin: 0 0 var(--space-md);
+ letter-spacing: -0.5px;
+}
+
+.featureDescription {
+ font-family: 'Fredoka', sans-serif;
+ font-size: clamp(15px, 1.5vw, 18px);
+ font-weight: 400;
+ color: var(--neo-text-dim);
+ line-height: 1.8;
+ margin: 0;
+}
+
+/* Responsive Design */
+@media (max-width: 1024px) {
+ .feature,
+ .feature.reverse {
+ flex-direction: column;
+ text-align: center;
+ gap: var(--space-xl);
+ }
+
+ .featureVisual {
+ min-height: auto;
+ }
+
+ .iconWrapper {
+ width: 160px;
+ height: 160px;
+ }
+
+ .featureIcon {
+ font-size: 64px;
+ }
+}
+
+@media (max-width: 768px) {
+ .featuresShowcase {
+ padding: var(--space-2xl) var(--space-md);
+ }
+
+ .header {
+ margin-bottom: var(--space-2xl);
+ }
+
+ .featuresGrid {
+ gap: var(--space-2xl);
+ }
+
+ .iconWrapper {
+ width: 140px;
+ height: 140px;
+ }
+
+ .featureIcon {
+ font-size: 56px;
+ }
+}
+
+@media (prefers-reduced-motion: reduce) {
+ .feature {
+ transition: opacity 0.3s ease;
+ }
+
+ .feature:hover .iconWrapper {
+ transform: scale(1.02);
+ }
+
+ .feature:hover .featureIcon {
+ transform: scale(1.05);
+ }
+}
diff --git a/client/src/components/home/FinalCTA.jsx b/client/src/components/home/FinalCTA.jsx
new file mode 100644
index 0000000..cd0b5be
--- /dev/null
+++ b/client/src/components/home/FinalCTA.jsx
@@ -0,0 +1,84 @@
+import { useNavigate } from 'react-router-dom';
+import anime from 'animejs';
+import { useRef } from 'react';
+import styles from './FinalCTA.module.css';
+
+export default function FinalCTA() {
+ const navigate = useNavigate();
+ const primaryBtnRef = useRef(null);
+ const secondaryBtnRef = useRef(null);
+
+ const handlePrimaryClick = () => {
+ anime({
+ targets: primaryBtnRef.current,
+ scale: [1, 0.95, 1.05, 1],
+ duration: 400,
+ easing: 'easeInOutQuad',
+ complete: () => navigate('/login'),
+ });
+ };
+
+ const handleSecondaryClick = () => {
+ anime({
+ targets: secondaryBtnRef.current,
+ scale: [1, 0.95, 1.05, 1],
+ duration: 400,
+ easing: 'easeInOutQuad',
+ complete: () => {
+ // Scroll to demo section or show demo modal
+ const demoSection = document.getElementById('demo');
+ if (demoSection) {
+ demoSection.scrollIntoView({ behavior: 'smooth' });
+ }
+ },
+ });
+ };
+
+ return (
+
+
+
+
+
EXPLORE A NEW DIMENSION
+
+
+ Ready to unlock your{' '}
+ cybersecurity potential
+ {' '}and protect what matters most?
+
+
+
+ Join thousands of learners mastering digital security through immersive gameplay.
+ Your journey to becoming a cyber-guardian starts here.
+
+
+
+
+ Join for Free
+ →
+
+
+
+ Watch Demo
+ ▶
+
+
+
+
+ {/* Floating particles */}
+
+ {[...Array(8)].map((_, i) => (
+
+ ))}
+
+
+ );
+}
diff --git a/client/src/components/home/FinalCTA.module.css b/client/src/components/home/FinalCTA.module.css
new file mode 100644
index 0000000..0f4f43b
--- /dev/null
+++ b/client/src/components/home/FinalCTA.module.css
@@ -0,0 +1,335 @@
+.finalCTA {
+ position: relative;
+ padding: var(--space-3xl) var(--space-md);
+ min-height: 600px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ overflow: hidden;
+ background: var(--neo-bg);
+}
+
+.gradientBg {
+ position: absolute;
+ inset: 0;
+ background: linear-gradient(
+ 135deg,
+ rgba(0, 242, 255, 0.15) 0%,
+ rgba(112, 0, 255, 0.15) 50%,
+ rgba(0, 255, 159, 0.15) 100%
+ );
+ opacity: 0.8;
+}
+
+.gradientBg::before {
+ content: '';
+ position: absolute;
+ inset: 0;
+ background: radial-gradient(
+ ellipse at center,
+ transparent 0%,
+ var(--neo-bg) 70%
+ );
+}
+
+.content {
+ position: relative;
+ z-index: 10;
+ text-align: center;
+ max-width: 900px;
+ padding: 0 var(--space-md);
+}
+
+.eyebrow {
+ font-family: 'Orbitron', sans-serif;
+ font-size: 14px;
+ font-weight: 700;
+ letter-spacing: 3px;
+ text-transform: uppercase;
+ color: var(--portal-cyan);
+ margin-bottom: var(--space-md);
+ opacity: 0.9;
+ text-shadow: 0 0 20px rgba(0, 242, 255, 0.5);
+ animation: fadeInDown 0.8s ease;
+}
+
+.headline {
+ font-family: 'Orbitron', sans-serif;
+ font-size: clamp(32px, 5vw, 56px);
+ font-weight: 900;
+ color: var(--neo-text);
+ margin: 0 0 var(--space-lg);
+ letter-spacing: -1px;
+ line-height: 1.2;
+ animation: fadeInUp 0.8s ease 0.2s backwards;
+}
+
+.highlight {
+ background: linear-gradient(135deg, var(--neo-cyan), var(--neo-purple));
+ background-clip: text;
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+}
+
+.description {
+ font-family: 'Fredoka', sans-serif;
+ font-size: clamp(16px, 2vw, 20px);
+ font-weight: 500;
+ color: var(--neo-text-dim);
+ line-height: 1.7;
+ margin: 0 auto var(--space-2xl);
+ max-width: 700px;
+ animation: fadeInUp 0.8s ease 0.4s backwards;
+}
+
+.ctaButtons {
+ display: flex;
+ justify-content: center;
+ gap: var(--space-md);
+ flex-wrap: wrap;
+ animation: fadeInUp 0.8s ease 0.6s backwards;
+}
+
+.primaryButton {
+ position: relative;
+ display: inline-flex;
+ align-items: center;
+ gap: 12px;
+ padding: 0 48px;
+ height: 70px;
+ border-radius: 999px;
+ border: none;
+ background: linear-gradient(135deg, var(--portal-cyan), var(--portal-purple));
+ color: white;
+ font-family: 'Orbitron', sans-serif;
+ font-size: 18px;
+ font-weight: 800;
+ cursor: pointer;
+ overflow: hidden;
+ letter-spacing: 0.5px;
+ text-transform: uppercase;
+ transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
+ box-shadow:
+ 0 0 50px rgba(0, 242, 255, 0.5),
+ 0 0 70px rgba(112, 0, 255, 0.4),
+ 0 20px 40px rgba(0, 0, 0, 0.3);
+}
+
+.primaryButton::before {
+ content: '';
+ position: absolute;
+ inset: -4px;
+ border-radius: 999px;
+ background: linear-gradient(135deg, var(--portal-cyan), var(--portal-purple), var(--portal-pink));
+ z-index: -1;
+ animation: glow 2s ease-in-out infinite;
+ opacity: 0.8;
+}
+
+.primaryButton::after {
+ content: '';
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ width: 0;
+ height: 0;
+ border-radius: 50%;
+ background: rgba(255, 255, 255, 0.3);
+ transform: translate(-50%, -50%);
+ transition: width 0.6s, height 0.6s;
+}
+
+.primaryButton:hover::after {
+ width: 400px;
+ height: 400px;
+}
+
+.primaryButton:hover {
+ transform: translateY(-6px) scale(1.05);
+ box-shadow:
+ 0 0 70px rgba(0, 242, 255, 0.7),
+ 0 0 100px rgba(112, 0, 255, 0.6),
+ 0 30px 60px rgba(0, 0, 0, 0.4);
+}
+
+.arrow {
+ font-size: 24px;
+ transition: transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
+ position: relative;
+ z-index: 1;
+}
+
+.primaryButton:hover .arrow {
+ transform: translateX(8px);
+}
+
+.secondaryButton {
+ position: relative;
+ display: inline-flex;
+ align-items: center;
+ gap: 10px;
+ padding: 0 40px;
+ height: 70px;
+ border-radius: 999px;
+ border: 2px solid var(--neo-cyan);
+ background: transparent;
+ color: var(--neo-text);
+ font-family: 'Orbitron', sans-serif;
+ font-size: 18px;
+ font-weight: 700;
+ cursor: pointer;
+ letter-spacing: 0.5px;
+ text-transform: uppercase;
+ transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
+ backdrop-filter: blur(8px);
+ -webkit-backdrop-filter: blur(8px);
+}
+
+.secondaryButton:hover {
+ transform: translateY(-6px);
+ background: rgba(0, 242, 255, 0.1);
+ border-color: var(--neo-purple);
+ box-shadow:
+ 0 0 40px rgba(0, 242, 255, 0.4),
+ 0 20px 40px rgba(0, 0, 0, 0.2);
+}
+
+.playIcon {
+ font-size: 14px;
+ transition: transform 0.3s ease;
+}
+
+.secondaryButton:hover .playIcon {
+ transform: translateX(4px);
+}
+
+.particles {
+ position: absolute;
+ inset: 0;
+ z-index: 1;
+ pointer-events: none;
+ overflow: hidden;
+}
+
+.particle {
+ position: absolute;
+ width: 4px;
+ height: 4px;
+ background: var(--portal-cyan);
+ border-radius: 50%;
+ box-shadow: 0 0 10px currentColor;
+ animation: particleFloat 15s linear infinite;
+ opacity: 0;
+}
+
+.particle:nth-child(1) { left: 10%; animation-delay: 0s; }
+.particle:nth-child(2) { left: 20%; animation-delay: 2s; background: var(--forest-emerald); }
+.particle:nth-child(3) { left: 35%; animation-delay: 4s; }
+.particle:nth-child(4) { left: 50%; animation-delay: 1s; background: var(--portal-purple); }
+.particle:nth-child(5) { left: 65%; animation-delay: 5s; }
+.particle:nth-child(6) { left: 75%; animation-delay: 3s; background: var(--forest-emerald); }
+.particle:nth-child(7) { left: 85%; animation-delay: 6s; }
+.particle:nth-child(8) { left: 95%; animation-delay: 1.5s; background: var(--portal-purple); }
+
+@keyframes fadeInDown {
+ from {
+ opacity: 0;
+ transform: translateY(-30px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+@keyframes fadeInUp {
+ from {
+ opacity: 0;
+ transform: translateY(30px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+@keyframes glow {
+ 0%, 100% {
+ opacity: 0.6;
+ }
+ 50% {
+ opacity: 1;
+ }
+}
+
+@keyframes particleFloat {
+ 0% {
+ transform: translateY(100vh) translateX(0) rotate(0deg);
+ opacity: 0;
+ }
+ 10% {
+ opacity: 0.8;
+ }
+ 90% {
+ opacity: 0.8;
+ }
+ 100% {
+ transform: translateY(-100vh) translateX(50px) rotate(360deg);
+ opacity: 0;
+ }
+}
+
+/* Responsive Design */
+@media (max-width: 768px) {
+ .finalCTA {
+ padding: var(--space-2xl) var(--space-md);
+ min-height: 500px;
+ }
+
+ .ctaButtons {
+ flex-direction: column;
+ align-items: center;
+ }
+
+ .primaryButton,
+ .secondaryButton {
+ width: 100%;
+ max-width: 320px;
+ }
+}
+
+@media (max-width: 480px) {
+ .primaryButton,
+ .secondaryButton {
+ height: 60px;
+ font-size: 16px;
+ padding: 0 36px;
+ }
+}
+
+@media (prefers-reduced-motion: reduce) {
+ .eyebrow,
+ .headline,
+ .description,
+ .ctaButtons {
+ animation: none;
+ }
+
+ .primaryButton::before,
+ .particle {
+ animation: none !important;
+ }
+
+ .primaryButton:hover {
+ transform: translateY(-3px) scale(1.02);
+ }
+
+ .secondaryButton:hover {
+ transform: translateY(-3px);
+ }
+
+ .primaryButton:hover .arrow,
+ .secondaryButton:hover .playIcon {
+ transform: translateX(4px);
+ }
+}
diff --git a/client/src/components/home/HeroSection.jsx b/client/src/components/home/HeroSection.jsx
index 2771c9b..2dfa993 100644
--- a/client/src/components/home/HeroSection.jsx
+++ b/client/src/components/home/HeroSection.jsx
@@ -128,11 +128,13 @@ export default function HeroSection() {
{/* Content Overlay */}
+
CYBERSECURITY EDUCATION
+
- Learn{' '}
- Cybersecurity
+ Master{' '}
+ Digital Security
- Through Play
+ Through Immersive Play
@@ -145,6 +147,14 @@ export default function HeroSection() {
→
+
+ {/* Scroll Down Indicator */}
+
);
}
diff --git a/client/src/components/home/HeroSection.module.css b/client/src/components/home/HeroSection.module.css
index 7316721..607c2cb 100644
--- a/client/src/components/home/HeroSection.module.css
+++ b/client/src/components/home/HeroSection.module.css
@@ -34,7 +34,7 @@
z-index: 0;
transition: opacity 0.5s ease;
mix-blend-mode: screen;
- opacity: 0.6;
+ opacity: 0.3;
}
.gradientWrapper canvas {
@@ -111,6 +111,19 @@
width: 100%;
}
+/* Eyebrow Text */
+.eyebrow {
+ font-family: 'Orbitron', sans-serif;
+ font-size: 14px;
+ font-weight: 700;
+ letter-spacing: 3px;
+ text-transform: uppercase;
+ color: var(--portal-cyan);
+ margin-bottom: 24px;
+ opacity: 0.9;
+ text-shadow: 0 0 20px rgba(0, 242, 255, 0.5);
+}
+
/* Main Title */
.title {
font-family: 'Orbitron', sans-serif;
@@ -162,7 +175,8 @@
display: inline-flex;
align-items: center;
gap: 14px;
- padding: 20px 48px;
+ padding: 0 48px;
+ height: 60px;
border-radius: 999px;
border: none;
background: linear-gradient(135deg, var(--portal-cyan), var(--portal-purple));
@@ -180,6 +194,7 @@
0 0 40px rgba(0, 242, 255, 0.5),
0 0 60px rgba(112, 0, 255, 0.4),
0 20px 40px rgba(0, 0, 0, 0.3);
+ animation: ctaGlow 2s ease-in-out infinite;
}
/* Ripple Effect on Button */
@@ -263,12 +278,97 @@
.particle:nth-child(9) { left: 85%; animation-delay: 4.5s; }
.particle:nth-child(10) { left: 95%; animation-delay: 1.5s; background: var(--forest-emerald); }
+/* Scroll Down Indicator */
+.scrollIndicator {
+ position: absolute;
+ bottom: 40px;
+ left: 50%;
+ transform: translateX(-50%);
+ z-index: 10;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 12px;
+ animation: scrollBounce 2s ease-in-out infinite;
+}
+
+.scrollMouse {
+ width: 28px;
+ height: 44px;
+ border: 2px solid var(--portal-cyan);
+ border-radius: 14px;
+ position: relative;
+ box-shadow: 0 0 20px rgba(0, 242, 255, 0.4);
+}
+
+.scrollWheel {
+ width: 4px;
+ height: 8px;
+ background: var(--portal-cyan);
+ border-radius: 2px;
+ position: absolute;
+ top: 8px;
+ left: 50%;
+ transform: translateX(-50%);
+ animation: scrollWheel 1.5s ease-in-out infinite;
+ box-shadow: 0 0 10px var(--portal-cyan);
+}
+
+.scrollText {
+ font-family: 'Orbitron', sans-serif;
+ font-size: 12px;
+ font-weight: 600;
+ letter-spacing: 1.5px;
+ text-transform: uppercase;
+ color: var(--neo-text-dim);
+ opacity: 0.8;
+ text-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
+}
+
+@keyframes scrollBounce {
+ 0%, 100% {
+ transform: translateX(-50%) translateY(0);
+ }
+ 50% {
+ transform: translateX(-50%) translateY(-10px);
+ }
+}
+
+@keyframes scrollWheel {
+ 0% {
+ opacity: 1;
+ top: 8px;
+ }
+ 100% {
+ opacity: 0;
+ top: 24px;
+ }
+}
+
+@keyframes ctaGlow {
+ 0%, 100% {
+ box-shadow:
+ 0 0 40px rgba(0, 242, 255, 0.5),
+ 0 0 60px rgba(112, 0, 255, 0.4),
+ 0 20px 40px rgba(0, 0, 0, 0.3);
+ }
+ 50% {
+ box-shadow:
+ 0 0 60px rgba(0, 242, 255, 0.7),
+ 0 0 80px rgba(112, 0, 255, 0.6),
+ 0 20px 40px rgba(0, 0, 0, 0.3);
+ }
+}
+
/* Accessibility: Reduced Motion */
@media (prefers-reduced-motion: reduce) {
.floatingIcon,
.glitch,
+ .ctaButton,
.ctaButton::after,
- .particle {
+ .particle,
+ .scrollIndicator,
+ .scrollWheel {
animation: none !important;
}
@@ -317,11 +417,16 @@
.ctaButton {
font-size: 16px;
- padding: 16px 32px;
+ height: 52px;
+ padding: 0 32px;
gap: 10px;
}
.particle {
display: none;
}
+
+ .scrollIndicator {
+ display: none;
+ }
}
diff --git a/client/src/components/home/LearningModulesGrid.jsx b/client/src/components/home/LearningModulesGrid.jsx
new file mode 100644
index 0000000..614705f
--- /dev/null
+++ b/client/src/components/home/LearningModulesGrid.jsx
@@ -0,0 +1,93 @@
+import { useRef, useEffect, useState } from 'react';
+import ModuleCard from './ModuleCard';
+import styles from './LearningModulesGrid.module.css';
+
+export default function LearningModulesGrid() {
+ const sectionRef = useRef(null);
+ const [isVisible, setIsVisible] = useState(false);
+
+ useEffect(() => {
+ const observer = new IntersectionObserver(
+ ([entry]) => {
+ if (entry.isIntersecting) {
+ setIsVisible(true);
+ }
+ },
+ { threshold: 0.1 }
+ );
+
+ if (sectionRef.current) {
+ observer.observe(sectionRef.current);
+ }
+
+ return () => observer.disconnect();
+ }, []);
+
+ const modules = [
+ {
+ id: 1,
+ title: 'Password Room',
+ level: 'beginner',
+ icon: '🔐',
+ gradient: 'linear-gradient(135deg, #00f2ff, #0099cc)',
+ rating: 5,
+ players: 1200,
+ },
+ {
+ id: 2,
+ title: 'Privacy Lab',
+ level: 'intermediate',
+ icon: '🛡️',
+ gradient: 'linear-gradient(135deg, #00ff9f, #00cc7f)',
+ rating: 5,
+ players: 850,
+ },
+ {
+ id: 3,
+ title: 'Threat Arena',
+ level: 'advanced',
+ icon: '⚔️',
+ gradient: 'linear-gradient(135deg, #ff006e, #cc0056)',
+ rating: 4,
+ players: 620,
+ },
+ {
+ id: 4,
+ title: 'Encryption Workshop',
+ level: 'intermediate',
+ icon: '🔑',
+ gradient: 'linear-gradient(135deg, #7000ff, #5500cc)',
+ rating: 5,
+ players: 940,
+ },
+ ];
+
+ return (
+
+
+
+
Learning Paths
+
+ Choose your adventure through cybersecurity fundamentals
+
+
+
+
+ {modules.map((module, index) => (
+
+
+
+ ))}
+
+
+
+ );
+}
diff --git a/client/src/components/home/LearningModulesGrid.module.css b/client/src/components/home/LearningModulesGrid.module.css
new file mode 100644
index 0000000..c1ab4c1
--- /dev/null
+++ b/client/src/components/home/LearningModulesGrid.module.css
@@ -0,0 +1,93 @@
+.learningModules {
+ position: relative;
+ padding: var(--space-3xl) var(--space-md);
+ background: var(--neo-bg);
+ overflow: hidden;
+}
+
+.container {
+ max-width: var(--container-xl);
+ margin: 0 auto;
+}
+
+.header {
+ text-align: center;
+ margin-bottom: var(--space-2xl);
+ opacity: 0;
+ transform: translateY(30px);
+ transition: all 0.8s ease;
+}
+
+.learningModules.visible .header {
+ opacity: 1;
+ transform: translateY(0);
+}
+
+.heading {
+ font-family: 'Orbitron', sans-serif;
+ font-size: clamp(36px, 5vw, 56px);
+ font-weight: 900;
+ color: var(--neo-text);
+ margin: 0 0 var(--space-md);
+ letter-spacing: -1px;
+ text-transform: uppercase;
+ background: linear-gradient(135deg, var(--portal-cyan), var(--portal-purple), var(--forest-emerald));
+ background-clip: text;
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+}
+
+.subheading {
+ font-family: 'Fredoka', sans-serif;
+ font-size: clamp(16px, 2vw, 20px);
+ font-weight: 500;
+ color: var(--neo-text-dim);
+ max-width: 700px;
+ margin: 0 auto;
+ line-height: 1.6;
+}
+
+.grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
+ gap: var(--space-lg);
+}
+
+.gridItem {
+ opacity: 0;
+ transform: translateY(30px);
+ transition: all 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
+}
+
+.learningModules.visible .gridItem {
+ opacity: 1;
+ transform: translateY(0);
+}
+
+/* Responsive Design */
+@media (max-width: 768px) {
+ .learningModules {
+ padding: var(--space-2xl) var(--space-md);
+ }
+
+ .header {
+ margin-bottom: var(--space-xl);
+ }
+
+ .grid {
+ grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
+ gap: var(--space-md);
+ }
+}
+
+@media (max-width: 480px) {
+ .grid {
+ grid-template-columns: 1fr;
+ }
+}
+
+@media (prefers-reduced-motion: reduce) {
+ .gridItem {
+ transition: opacity 0.3s ease;
+ }
+}
diff --git a/client/src/components/home/ModuleCard.jsx b/client/src/components/home/ModuleCard.jsx
new file mode 100644
index 0000000..f28d34e
--- /dev/null
+++ b/client/src/components/home/ModuleCard.jsx
@@ -0,0 +1,65 @@
+import { useNavigate } from 'react-router-dom';
+import styles from './ModuleCard.module.css';
+
+export default function ModuleCard({ module }) {
+ const navigate = useNavigate();
+
+ const getBadgeColor = (level) => {
+ switch (level) {
+ case 'beginner':
+ return 'var(--badge-beginner)';
+ case 'intermediate':
+ return 'var(--badge-intermediate)';
+ case 'advanced':
+ return 'var(--badge-advanced)';
+ default:
+ return 'var(--badge-beginner)';
+ }
+ };
+
+ const handleStartModule = () => {
+ navigate('/login');
+ };
+
+ return (
+
+
+ {module.level}
+
+
+
+
+
+
{module.title}
+
+
+
+ {[...Array(5)].map((_, i) => (
+
+ ★
+
+ ))}
+
+
+
+ 👥
+ {module.players}+
+
+
+
+
+ Start Module
+ →
+
+
+
+ );
+}
diff --git a/client/src/components/home/ModuleCard.module.css b/client/src/components/home/ModuleCard.module.css
new file mode 100644
index 0000000..d8935ff
--- /dev/null
+++ b/client/src/components/home/ModuleCard.module.css
@@ -0,0 +1,202 @@
+.moduleCard {
+ position: relative;
+ background: var(--glass-bg);
+ border: 1px solid var(--glass-border);
+ border-radius: 16px;
+ overflow: hidden;
+ backdrop-filter: blur(var(--glass-blur));
+ -webkit-backdrop-filter: blur(var(--glass-blur));
+ box-shadow: var(--glass-shadow);
+ transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
+ cursor: pointer;
+}
+
+.moduleCard:hover {
+ transform: translateY(-8px);
+ box-shadow:
+ 0 20px 60px rgba(0, 242, 255, 0.3),
+ 0 20px 60px rgba(112, 0, 255, 0.2);
+ border-color: var(--neo-cyan);
+}
+
+.badge {
+ position: absolute;
+ top: 16px;
+ right: 16px;
+ padding: 6px 12px;
+ border-radius: 20px;
+ background: var(--badge-color);
+ color: white;
+ font-family: 'Orbitron', sans-serif;
+ font-size: 11px;
+ font-weight: 700;
+ letter-spacing: 1px;
+ text-transform: uppercase;
+ z-index: 10;
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
+}
+
+.imageWrapper {
+ position: relative;
+ width: 100%;
+ aspect-ratio: 16 / 9;
+ overflow: hidden;
+}
+
+.imageGradient {
+ width: 100%;
+ height: 100%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ transition: transform 0.4s ease;
+}
+
+.moduleCard:hover .imageGradient {
+ transform: scale(1.1);
+}
+
+.moduleIcon {
+ font-size: 64px;
+ filter: drop-shadow(0 0 20px rgba(0, 0, 0, 0.5));
+}
+
+.content {
+ padding: var(--space-md);
+}
+
+.title {
+ font-family: 'Orbitron', sans-serif;
+ font-size: 20px;
+ font-weight: 800;
+ color: var(--neo-text);
+ margin: 0 0 var(--space-md);
+ letter-spacing: -0.5px;
+}
+
+.meta {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: var(--space-md);
+}
+
+.rating {
+ display: flex;
+ gap: 2px;
+}
+
+.star {
+ color: var(--star-gold);
+ font-size: 16px;
+ transition: opacity 0.3s ease;
+}
+
+.players {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ font-family: 'Fredoka', sans-serif;
+ font-size: 14px;
+ font-weight: 600;
+ color: var(--neo-text-dim);
+}
+
+.playersIcon {
+ font-size: 16px;
+}
+
+.playersCount {
+ opacity: 0.9;
+}
+
+.ctaButton {
+ width: 100%;
+ padding: 12px 24px;
+ border-radius: 8px;
+ border: 2px solid transparent;
+ background: linear-gradient(135deg, var(--neo-cyan), var(--neo-purple));
+ color: white;
+ font-family: 'Orbitron', sans-serif;
+ font-size: 14px;
+ font-weight: 700;
+ letter-spacing: 0.5px;
+ text-transform: uppercase;
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 8px;
+ transition: all 0.3s ease;
+ position: relative;
+ overflow: hidden;
+}
+
+.ctaButton::before {
+ content: '';
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ width: 0;
+ height: 0;
+ border-radius: 50%;
+ background: rgba(255, 255, 255, 0.3);
+ transform: translate(-50%, -50%);
+ transition: width 0.5s, height 0.5s;
+}
+
+.ctaButton:hover::before {
+ width: 300px;
+ height: 300px;
+}
+
+.ctaButton:hover {
+ transform: translateY(-2px);
+ box-shadow:
+ 0 8px 24px rgba(0, 242, 255, 0.4),
+ 0 8px 24px rgba(112, 0, 255, 0.3);
+}
+
+.arrow {
+ font-size: 18px;
+ transition: transform 0.3s ease;
+ position: relative;
+ z-index: 1;
+}
+
+.ctaButton:hover .arrow {
+ transform: translateX(4px);
+}
+
+@media (max-width: 480px) {
+ .content {
+ padding: var(--space-sm);
+ }
+
+ .title {
+ font-size: 18px;
+ }
+
+ .ctaButton {
+ font-size: 13px;
+ padding: 10px 20px;
+ }
+}
+
+@media (prefers-reduced-motion: reduce) {
+ .moduleCard:hover {
+ transform: translateY(-4px);
+ }
+
+ .moduleCard:hover .imageGradient {
+ transform: scale(1.05);
+ }
+
+ .ctaButton:hover {
+ transform: none;
+ }
+
+ .ctaButton:hover .arrow {
+ transform: translateX(2px);
+ }
+}
diff --git a/client/src/components/home/StatsCounter.jsx b/client/src/components/home/StatsCounter.jsx
new file mode 100644
index 0000000..355ce32
--- /dev/null
+++ b/client/src/components/home/StatsCounter.jsx
@@ -0,0 +1,79 @@
+import { useRef, useEffect, useState } from 'react';
+import anime from 'animejs';
+import styles from './StatsCounter.module.css';
+
+export default function StatsCounter() {
+ const sectionRef = useRef(null);
+ const [hasAnimated, setHasAnimated] = useState(false);
+ const statsRefs = useRef([]);
+
+ const stats = [
+ { label: 'Active Players', value: 5000, suffix: '+', icon: '👥' },
+ { label: 'Challenges Completed', value: 2500, suffix: '+', icon: '🎯' },
+ { label: 'Learning Modules', value: 15, suffix: '', icon: '📚' },
+ { label: 'Badges Earned', value: 10000, suffix: '+', icon: '🏆' },
+ ];
+
+ useEffect(() => {
+ const observer = new IntersectionObserver(
+ ([entry]) => {
+ if (entry.isIntersecting && !hasAnimated) {
+ setHasAnimated(true);
+
+ // Animate each stat counter
+ statsRefs.current.forEach((ref, index) => {
+ if (ref) {
+ const stat = stats[index];
+ const obj = { value: 0 };
+
+ anime({
+ targets: obj,
+ value: stat.value,
+ duration: 2000,
+ delay: index * 100,
+ easing: 'easeOutExpo',
+ round: 1,
+ update: function() {
+ ref.textContent = obj.value.toLocaleString();
+ }
+ });
+ }
+ });
+
+ observer.disconnect();
+ }
+ },
+ { threshold: 0.3 }
+ );
+
+ if (sectionRef.current) {
+ observer.observe(sectionRef.current);
+ }
+
+ return () => observer.disconnect();
+ }, [hasAnimated]);
+
+ return (
+
+
+
+ {stats.map((stat, index) => (
+
+
{stat.icon}
+
+ (statsRefs.current[index] = el)}
+ className={styles.number}
+ >
+ 0
+
+ {stat.suffix}
+
+
{stat.label}
+
+ ))}
+
+
+
+ );
+}
diff --git a/client/src/components/home/StatsCounter.module.css b/client/src/components/home/StatsCounter.module.css
new file mode 100644
index 0000000..2fe4132
--- /dev/null
+++ b/client/src/components/home/StatsCounter.module.css
@@ -0,0 +1,159 @@
+.statsCounter {
+ position: relative;
+ padding: var(--space-3xl) var(--space-md);
+ background: var(--section-bg-alt);
+ overflow: hidden;
+}
+
+.statsCounter::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: 50%;
+ transform: translateX(-50%);
+ width: 80%;
+ height: 1px;
+ background: linear-gradient(
+ 90deg,
+ transparent,
+ var(--neo-cyan),
+ var(--neo-purple),
+ transparent
+ );
+ opacity: 0.5;
+}
+
+.container {
+ max-width: var(--container-xl);
+ margin: 0 auto;
+}
+
+.statsGrid {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: center;
+ gap: var(--space-xl);
+}
+
+.statCard {
+ flex: 1 1 200px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: var(--space-sm);
+ padding: var(--space-lg);
+ text-align: center;
+ position: relative;
+}
+
+.statIcon {
+ font-size: 48px;
+ filter: drop-shadow(0 0 20px currentColor);
+ opacity: 0.9;
+ animation: float 3s ease-in-out infinite;
+}
+
+.statCard:nth-child(1) .statIcon {
+ animation-delay: 0s;
+ color: var(--portal-cyan);
+}
+
+.statCard:nth-child(2) .statIcon {
+ animation-delay: 0.5s;
+ color: var(--forest-emerald);
+}
+
+.statCard:nth-child(3) .statIcon {
+ animation-delay: 1s;
+ color: var(--portal-purple);
+}
+
+.statCard:nth-child(4) .statIcon {
+ animation-delay: 1.5s;
+ color: var(--star-gold);
+}
+
+.statValue {
+ display: flex;
+ align-items: baseline;
+ gap: 4px;
+}
+
+.number {
+ font-family: 'Orbitron', sans-serif;
+ font-size: clamp(40px, 6vw, 64px);
+ font-weight: 900;
+ background: linear-gradient(135deg, var(--neo-cyan), var(--neo-purple));
+ background-clip: text;
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ letter-spacing: -2px;
+ line-height: 1;
+}
+
+.suffix {
+ font-family: 'Orbitron', sans-serif;
+ font-size: clamp(24px, 3vw, 32px);
+ font-weight: 700;
+ color: var(--neo-cyan);
+ opacity: 0.8;
+}
+
+.statLabel {
+ font-family: 'Fredoka', sans-serif;
+ font-size: clamp(14px, 1.5vw, 18px);
+ font-weight: 600;
+ color: var(--neo-text-dim);
+ letter-spacing: 0.5px;
+ text-transform: uppercase;
+}
+
+@keyframes float {
+ 0%, 100% {
+ transform: translateY(0);
+ }
+ 50% {
+ transform: translateY(-10px);
+ }
+}
+
+/* Responsive Design */
+@media (max-width: 768px) {
+ .statsCounter {
+ padding: var(--space-2xl) var(--space-md);
+ }
+
+ .statsGrid {
+ gap: var(--space-lg);
+ }
+
+ .statCard {
+ flex: 1 1 150px;
+ padding: var(--space-md);
+ }
+
+ .statIcon {
+ font-size: 40px;
+ }
+}
+
+@media (max-width: 480px) {
+ .statsGrid {
+ gap: var(--space-md);
+ }
+
+ .statCard {
+ flex: 1 1 120px;
+ padding: var(--space-sm);
+ }
+
+ .statIcon {
+ font-size: 32px;
+ }
+}
+
+@media (prefers-reduced-motion: reduce) {
+ .statIcon {
+ animation: none !important;
+ }
+}
diff --git a/client/src/components/home/TestimonialCard.jsx b/client/src/components/home/TestimonialCard.jsx
new file mode 100644
index 0000000..f4a6968
--- /dev/null
+++ b/client/src/components/home/TestimonialCard.jsx
@@ -0,0 +1,27 @@
+import styles from './TestimonialCard.module.css';
+
+export default function TestimonialCard({ testimonial }) {
+ return (
+
+
+ {[...Array(5)].map((_, i) => (
+ ★
+ ))}
+
+
+
+ "{testimonial.quote}"
+
+
+
+
+
+
{testimonial.name}
+
{testimonial.title}
+
+
+
+ );
+}
diff --git a/client/src/components/home/TestimonialCard.module.css b/client/src/components/home/TestimonialCard.module.css
new file mode 100644
index 0000000..f3dcaa3
--- /dev/null
+++ b/client/src/components/home/TestimonialCard.module.css
@@ -0,0 +1,116 @@
+.testimonialCard {
+ position: relative;
+ padding: var(--space-lg);
+ background: var(--glass-bg);
+ border: 1px solid var(--glass-border);
+ border-radius: 16px;
+ backdrop-filter: blur(var(--glass-blur));
+ -webkit-backdrop-filter: blur(var(--glass-blur));
+ box-shadow: var(--glass-shadow);
+ transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
+ display: flex;
+ flex-direction: column;
+ gap: var(--space-md);
+ min-height: 280px;
+}
+
+.testimonialCard:hover {
+ transform: translateY(-6px);
+ box-shadow:
+ 0 20px 60px rgba(0, 242, 255, 0.25),
+ 0 20px 60px rgba(112, 0, 255, 0.15);
+ border-color: var(--neo-cyan);
+}
+
+.rating {
+ display: flex;
+ gap: 4px;
+}
+
+.star {
+ color: var(--star-gold);
+ font-size: 18px;
+ filter: drop-shadow(0 0 8px var(--star-gold));
+}
+
+.quote {
+ font-family: 'Fredoka', sans-serif;
+ font-size: clamp(15px, 1.5vw, 17px);
+ font-weight: 500;
+ color: var(--neo-text);
+ line-height: 1.7;
+ margin: 0;
+ flex: 1;
+ font-style: italic;
+}
+
+.author {
+ display: flex;
+ align-items: center;
+ gap: var(--space-md);
+ padding-top: var(--space-sm);
+ border-top: 1px solid var(--neo-border);
+}
+
+.avatarWrapper {
+ position: relative;
+ padding: 3px;
+ border-radius: 50%;
+ background: linear-gradient(135deg, var(--neo-cyan), var(--neo-purple));
+}
+
+.avatar {
+ width: 48px;
+ height: 48px;
+ border-radius: 50%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 24px;
+ background: var(--neo-bg);
+ border: 2px solid var(--neo-bg);
+}
+
+.authorInfo {
+ flex: 1;
+}
+
+.authorName {
+ font-family: 'Orbitron', sans-serif;
+ font-size: 15px;
+ font-weight: 700;
+ color: var(--neo-text);
+ margin-bottom: 2px;
+}
+
+.authorTitle {
+ font-family: 'Fredoka', sans-serif;
+ font-size: 13px;
+ font-weight: 500;
+ color: var(--neo-text-dim);
+}
+
+@media (max-width: 480px) {
+ .testimonialCard {
+ padding: var(--space-md);
+ min-height: 260px;
+ }
+
+ .quote {
+ font-size: 15px;
+ }
+
+ .authorName {
+ font-size: 14px;
+ }
+
+ .authorTitle {
+ font-size: 12px;
+ }
+}
+
+@media (prefers-reduced-motion: reduce) {
+ .testimonialCard:hover {
+ transform: translateY(-3px);
+ }
+}
diff --git a/client/src/components/home/TestimonialsSection.jsx b/client/src/components/home/TestimonialsSection.jsx
new file mode 100644
index 0000000..f7870a2
--- /dev/null
+++ b/client/src/components/home/TestimonialsSection.jsx
@@ -0,0 +1,74 @@
+import { useRef, useEffect, useState } from 'react';
+import TestimonialCard from './TestimonialCard';
+import styles from './TestimonialsSection.module.css';
+
+export default function TestimonialsSection() {
+ const sectionRef = useRef(null);
+ const [isVisible, setIsVisible] = useState(false);
+
+ useEffect(() => {
+ const observer = new IntersectionObserver(
+ ([entry]) => {
+ if (entry.isIntersecting) {
+ setIsVisible(true);
+ }
+ },
+ { threshold: 0.1 }
+ );
+
+ if (sectionRef.current) {
+ observer.observe(sectionRef.current);
+ }
+
+ return () => observer.disconnect();
+ }, []);
+
+ const testimonials = [
+ {
+ quote: "SafeForest made learning cybersecurity actually fun! The gesture controls are incredible and the 3D environment keeps me engaged. I've learned more here in a week than months of traditional courses.",
+ avatar: '👨💻',
+ name: 'Alex Chen',
+ title: 'Computer Science Student',
+ },
+ {
+ quote: "As a teacher, I'm always looking for innovative ways to engage students. SafeForest's gamified approach to security education is brilliant. My students are actually excited about learning password safety!",
+ avatar: '👩🏫',
+ name: 'Sarah Martinez',
+ title: 'High School Teacher',
+ },
+ {
+ quote: "The AI companion feature is genius! Having a personalized guide through the challenges makes the learning experience feel unique. Plus, the forest-cyberpunk aesthetic is stunning.",
+ avatar: '👨🎓',
+ name: 'David Kim',
+ title: 'Cybersecurity Enthusiast',
+ },
+ ];
+
+ return (
+
+
+
+
What Learners Say
+
+ Join thousands discovering cybersecurity through immersive gameplay
+
+
+
+
+ {testimonials.map((testimonial, index) => (
+
+
+
+ ))}
+
+
+
+ );
+}
diff --git a/client/src/components/home/TestimonialsSection.module.css b/client/src/components/home/TestimonialsSection.module.css
new file mode 100644
index 0000000..c934179
--- /dev/null
+++ b/client/src/components/home/TestimonialsSection.module.css
@@ -0,0 +1,109 @@
+.testimonialsSection {
+ position: relative;
+ padding: var(--space-3xl) var(--space-md);
+ background: var(--neo-bg);
+ overflow: hidden;
+}
+
+.container {
+ max-width: var(--container-xl);
+ margin: 0 auto;
+}
+
+.header {
+ text-align: center;
+ margin-bottom: var(--space-2xl);
+ opacity: 0;
+ transform: translateY(30px);
+ transition: all 0.8s ease;
+}
+
+.testimonialsSection.visible .header {
+ opacity: 1;
+ transform: translateY(0);
+}
+
+.heading {
+ font-family: 'Orbitron', sans-serif;
+ font-size: clamp(36px, 5vw, 56px);
+ font-weight: 900;
+ color: var(--neo-text);
+ margin: 0 0 var(--space-md);
+ letter-spacing: -1px;
+ text-transform: uppercase;
+ background: linear-gradient(135deg, var(--neo-cyan), var(--neo-purple));
+ background-clip: text;
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+}
+
+.subheading {
+ font-family: 'Fredoka', sans-serif;
+ font-size: clamp(16px, 2vw, 20px);
+ font-weight: 500;
+ color: var(--neo-text-dim);
+ max-width: 700px;
+ margin: 0 auto;
+ line-height: 1.6;
+}
+
+.testimonialsGrid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
+ gap: var(--space-lg);
+}
+
+.gridItem {
+ opacity: 0;
+ transform: translateY(30px);
+ transition: all 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
+}
+
+.testimonialsSection.visible .gridItem {
+ opacity: 1;
+ transform: translateY(0);
+}
+
+/* Mobile: Horizontal Scroll */
+@media (max-width: 768px) {
+ .testimonialsSection {
+ padding: var(--space-2xl) var(--space-md);
+ }
+
+ .header {
+ margin-bottom: var(--space-xl);
+ }
+
+ .testimonialsGrid {
+ display: flex;
+ overflow-x: auto;
+ scroll-snap-type: x mandatory;
+ -webkit-overflow-scrolling: touch;
+ scrollbar-width: none;
+ gap: var(--space-md);
+ padding: var(--space-sm) 0;
+ }
+
+ .testimonialsGrid::-webkit-scrollbar {
+ display: none;
+ }
+
+ .gridItem {
+ flex-shrink: 0;
+ scroll-snap-align: center;
+ width: 85vw;
+ max-width: 400px;
+ }
+}
+
+@media (max-width: 480px) {
+ .gridItem {
+ width: 90vw;
+ }
+}
+
+@media (prefers-reduced-motion: reduce) {
+ .gridItem {
+ transition: opacity 0.3s ease;
+ }
+}
diff --git a/client/src/components/home/TrustBadges.jsx b/client/src/components/home/TrustBadges.jsx
new file mode 100644
index 0000000..f3d98bf
--- /dev/null
+++ b/client/src/components/home/TrustBadges.jsx
@@ -0,0 +1,57 @@
+import { useRef, useEffect, useState } from 'react';
+import styles from './TrustBadges.module.css';
+
+export default function TrustBadges() {
+ const containerRef = useRef(null);
+ const [isVisible, setIsVisible] = useState(false);
+
+ useEffect(() => {
+ const observer = new IntersectionObserver(
+ ([entry]) => {
+ if (entry.isIntersecting) {
+ setIsVisible(true);
+ observer.disconnect();
+ }
+ },
+ { threshold: 0.2 }
+ );
+
+ if (containerRef.current) {
+ observer.observe(containerRef.current);
+ }
+
+ return () => observer.disconnect();
+ }, []);
+
+ const technologies = [
+ { name: 'Three.js', icon: '🎮' },
+ { name: 'MediaPipe', icon: '👋' },
+ { name: 'React', icon: '⚛️' },
+ { name: 'Google OAuth', icon: '🔐' },
+ { name: 'MySQL', icon: '🗄️' },
+ { name: 'OpenAI', icon: '🤖' },
+ ];
+
+ return (
+
+
+
Built with industry-leading technologies
+
+ {technologies.map((tech, index) => (
+
+ {tech.icon}
+ {tech.name}
+
+ ))}
+
+
+
+ );
+}
diff --git a/client/src/components/home/TrustBadges.module.css b/client/src/components/home/TrustBadges.module.css
new file mode 100644
index 0000000..82cfefb
--- /dev/null
+++ b/client/src/components/home/TrustBadges.module.css
@@ -0,0 +1,152 @@
+.trustBadges {
+ position: relative;
+ padding: var(--space-xl) var(--space-md);
+ background: var(--neo-bg);
+ overflow: hidden;
+}
+
+.container {
+ max-width: var(--container-xl);
+ margin: 0 auto;
+ text-align: center;
+}
+
+.label {
+ font-family: 'Orbitron', sans-serif;
+ font-size: 13px;
+ font-weight: 600;
+ letter-spacing: 2px;
+ text-transform: uppercase;
+ color: var(--neo-text-dim);
+ margin: 0 0 var(--space-lg);
+ opacity: 0;
+ transform: translateY(20px);
+ transition: all 0.6s ease;
+}
+
+.trustBadges.visible .label {
+ opacity: 1;
+ transform: translateY(0);
+}
+
+.logoGrid {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ gap: var(--space-lg);
+ flex-wrap: wrap;
+}
+
+.logoCard {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: var(--space-xs);
+ padding: var(--space-md);
+ border-radius: 12px;
+ background: var(--glass-bg);
+ border: 1px solid var(--glass-border);
+ backdrop-filter: blur(var(--glass-blur));
+ -webkit-backdrop-filter: blur(var(--glass-blur));
+ transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
+ cursor: pointer;
+ min-width: 120px;
+ opacity: 0;
+ transform: translateY(30px);
+}
+
+.trustBadges.visible .logoCard {
+ opacity: 1;
+ transform: translateY(0);
+ animation: fadeInUp 0.6s ease forwards;
+}
+
+.logoIcon {
+ font-size: 40px;
+ filter: grayscale(100%);
+ opacity: 0.6;
+ transition: all 0.4s ease;
+}
+
+.logoName {
+ font-family: 'Orbitron', sans-serif;
+ font-size: 12px;
+ font-weight: 600;
+ letter-spacing: 0.5px;
+ color: var(--neo-text-dim);
+ transition: color 0.4s ease;
+}
+
+.logoCard:hover {
+ transform: translateY(-8px);
+ box-shadow:
+ 0 12px 40px rgba(0, 242, 255, 0.2),
+ 0 12px 40px rgba(112, 0, 255, 0.15);
+ border-color: var(--neo-cyan);
+}
+
+.logoCard:hover .logoIcon {
+ filter: grayscale(0%);
+ opacity: 1;
+ transform: scale(1.1);
+}
+
+.logoCard:hover .logoName {
+ color: var(--neo-cyan);
+}
+
+@keyframes fadeInUp {
+ from {
+ opacity: 0;
+ transform: translateY(30px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+/* Mobile: Horizontal Scroll */
+@media (max-width: 768px) {
+ .logoGrid {
+ flex-wrap: nowrap;
+ overflow-x: auto;
+ scroll-snap-type: x mandatory;
+ -webkit-overflow-scrolling: touch;
+ scrollbar-width: none;
+ padding: var(--space-sm) 0;
+ justify-content: flex-start;
+ }
+
+ .logoGrid::-webkit-scrollbar {
+ display: none;
+ }
+
+ .logoCard {
+ flex-shrink: 0;
+ scroll-snap-align: center;
+ min-width: 100px;
+ }
+
+ .logoIcon {
+ font-size: 32px;
+ }
+
+ .logoName {
+ font-size: 11px;
+ }
+}
+
+@media (prefers-reduced-motion: reduce) {
+ .logoCard {
+ animation: none !important;
+ }
+
+ .logoCard:hover {
+ transform: translateY(-4px);
+ }
+
+ .logoCard:hover .logoIcon {
+ transform: scale(1.05);
+ }
+}
diff --git a/client/src/components/layout/Footer.jsx b/client/src/components/layout/Footer.jsx
index 12645cc..696ef1a 100644
--- a/client/src/components/layout/Footer.jsx
+++ b/client/src/components/layout/Footer.jsx
@@ -1,9 +1,18 @@
import { useNavigate } from 'react-router-dom';
+import { useState } from 'react';
import styles from './Footer.module.css';
export default function Footer() {
const navigate = useNavigate();
const currentYear = new Date().getFullYear();
+ const [email, setEmail] = useState('');
+
+ const handleNewsletterSubmit = (e) => {
+ e.preventDefault();
+ // TODO: Implement newsletter signup
+ console.log('Newsletter signup:', email);
+ setEmail('');
+ };
return (