From 1fa7532b6cc39f314b6cb2905275db88d2b1cee0 Mon Sep 17 00:00:00 2001 From: Pheonix <150040105+ArshiBansal@users.noreply.github.com> Date: Tue, 16 Jun 2026 18:31:17 +0530 Subject: [PATCH] fixed contact section --- public/css/home.css | 287 +++- public/home.html | 3226 +++++++++++++++++++++++++++++-------------- public/js/home.js | 503 ++++--- 3 files changed, 2688 insertions(+), 1328 deletions(-) diff --git a/public/css/home.css b/public/css/home.css index e3411bb..5342088 100644 --- a/public/css/home.css +++ b/public/css/home.css @@ -15,7 +15,10 @@ filter: blur(28px); z-index: 9999; mix-blend-mode: screen; - transition: transform 0.1s ease-out, width 0.3s ease, height 0.3s ease; + transition: + transform 0.1s ease-out, + width 0.3s ease, + height 0.3s ease; transform: translate(-50%, -50%); display: none; /* JS will reveal it to avoid popping instantly */ @@ -35,7 +38,6 @@ } @keyframes blink { - 0%, 100% { opacity: 1; @@ -142,8 +144,6 @@ gap: 6px; } - - @media (max-width: 768px) { .navbar-actions { gap: 6px; @@ -157,14 +157,6 @@ } } - - - - - - - - .btn-nav-ghost { color: var(--text-secondary); border: 1px solid var(--border); @@ -382,7 +374,7 @@ color: var(--accent-light); } [data-theme="light"] .mega-item:hover .mega-item-title { - color: #111111 !important; + color: #111111 !important; } /* Dropdown CTA Banner */ @@ -394,7 +386,11 @@ } .mega-cta-content { - background: linear-gradient(135deg, rgba(168, 85, 247, 0.08), rgba(236, 72, 153, 0.08)); + background: linear-gradient( + 135deg, + rgba(168, 85, 247, 0.08), + rgba(236, 72, 153, 0.08) + ); border: 1px solid rgba(168, 85, 247, 0.15); border-radius: 14px; padding: 16px 24px; @@ -571,7 +567,12 @@ } .gradient-text { - background: linear-gradient(135deg, var(--accent-light), var(--accent2-light), var(--accent)); + background: linear-gradient( + 135deg, + var(--accent-light), + var(--accent2-light), + var(--accent) + ); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; @@ -668,7 +669,6 @@ } @keyframes heroFloat { - 0%, 100% { transform: translateY(0); @@ -719,7 +719,12 @@ position: absolute; inset: -3px; border-radius: 50%; - background: conic-gradient(from 0deg, var(--accent), var(--accent2), var(--accent)); + background: conic-gradient( + from 0deg, + var(--accent), + var(--accent2), + var(--accent) + ); animation: rotateGlow 4s linear infinite; filter: blur(3px); opacity: 0.7; @@ -796,12 +801,15 @@ } .mock-featured { - background: linear-gradient(135deg, rgba(168, 85, 247, 0.1), rgba(236, 72, 153, 0.1)); + background: linear-gradient( + 135deg, + rgba(168, 85, 247, 0.1), + rgba(236, 72, 153, 0.1) + ); border-color: rgba(168, 85, 247, 0.25); } @keyframes mockLinkFloat { - 0%, 100% { transform: translateX(0); @@ -912,7 +920,11 @@ /* ─── Theme Gallery ─── */ .theme-gallery-section { - background: radial-gradient(ellipse 60% 40% at 50% 50%, rgba(168, 85, 247, 0.04), transparent); + background: radial-gradient( + ellipse 60% 40% at 50% 50%, + rgba(168, 85, 247, 0.04), + transparent + ); } .theme-showcase { @@ -998,7 +1010,11 @@ font-family: var(--font-heading); font-size: 3.5rem; font-weight: 800; - background: linear-gradient(135deg, var(--accent-light), var(--accent2-light)); + background: linear-gradient( + 135deg, + var(--accent-light), + var(--accent2-light) + ); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; @@ -1013,7 +1029,11 @@ /* ─── Pricing Section ─── */ .pricing-section { - background: radial-gradient(ellipse 70% 50% at 50% 50%, rgba(168, 85, 247, 0.04), transparent); + background: radial-gradient( + ellipse 70% 50% at 50% 50%, + rgba(168, 85, 247, 0.04), + transparent + ); } .billing-toggle { @@ -1111,7 +1131,11 @@ /* Popular card – gradient border glow */ .pricing-card-popular { - background: linear-gradient(135deg, rgba(168, 85, 247, 0.06), rgba(236, 72, 153, 0.06)); + background: linear-gradient( + 135deg, + rgba(168, 85, 247, 0.06), + rgba(236, 72, 153, 0.06) + ); border-color: rgba(168, 85, 247, 0.3); box-shadow: 0 0 40px rgba(168, 85, 247, 0.08); transform: scale(1.03); @@ -1203,14 +1227,22 @@ font-size: 3.2rem; font-weight: 800; line-height: 1; - background: linear-gradient(135deg, var(--text-primary), var(--text-secondary)); + background: linear-gradient( + 135deg, + var(--text-primary), + var(--text-secondary) + ); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; } .pricing-card-popular .price-amount { - background: linear-gradient(135deg, var(--accent-light), var(--accent2-light)); + background: linear-gradient( + 135deg, + var(--accent-light), + var(--accent2-light) + ); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; @@ -1314,7 +1346,11 @@ } .cta-card { - background: linear-gradient(135deg, rgba(168, 85, 247, 0.08), rgba(236, 72, 153, 0.08)); + background: linear-gradient( + 135deg, + rgba(168, 85, 247, 0.08), + rgba(236, 72, 153, 0.08) + ); border: 1px solid rgba(168, 85, 247, 0.2); border-radius: var(--radius-xl); padding: 60px 40px; @@ -1340,80 +1376,192 @@ justify-content: center; } -/* ─── Contact Section ─── */ +/* ─── Enhanced Contact Section ─── */ .contact-section { - padding-bottom: 40px; + padding-bottom: 80px; } -.contact-card { - max-width: 640px; +.contact-grid { + display: grid; + grid-template-columns: 380px 1fr; /* Sidebar (Left) | Form (Right) */ + gap: 48px; + max-width: 1240px; margin: 0 auto; + align-items: start; +} + +.contact-form-card { background: var(--bg-glass); border: 1px solid var(--border); border-radius: var(--radius-xl); - padding: 36px; + padding: 42px 40px; + height: fit-content; } -.contact-form { +.contact-info-sidebar { display: flex; flex-direction: column; + gap: 28px; +} + +.info-card { + background: var(--bg-glass); + border: 1px solid var(--border); + border-radius: var(--radius-xl); + padding: 32px; +} + +.info-card h4 { + font-family: var(--font-heading); + font-size: 1.15rem; + margin-bottom: 22px; + color: var(--text-primary); +} + +.response-time { + display: flex; gap: 18px; + align-items: flex-start; } -.contact-form-row { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 16px; +.time-badge { + font-size: 1.8rem; + flex-shrink: 0; + line-height: 1; } -.contact-form .form-group { - margin-bottom: 0; +.response-time strong { + display: block; + margin-bottom: 6px; + color: var(--text-primary); } -.contact-form .form-label { +.contact-methods { + display: flex; + flex-direction: column; + gap: 18px; +} + +.contact-method { + display: flex; + align-items: center; + gap: 18px; + padding: 14px 18px; + border-radius: var(--radius-lg); + text-decoration: none; + color: inherit; + transition: all var(--duration-fast) var(--ease-out); +} + +.contact-method:hover { + background: var(--bg-card); + transform: translateX(6px); +} + +.method-icon { + font-size: 1.5rem; + width: 44px; + flex-shrink: 0; +} + +.contact-method strong { display: block; - font-size: 0.8rem; - font-weight: 500; + font-size: 0.97rem; +} + +.contact-method span { + font-size: 0.82rem; color: var(--text-secondary); - margin-bottom: 6px; - text-transform: uppercase; - letter-spacing: 0.04em; } -.contact-form .form-input { - width: 100%; - padding: 10px 14px; +.social-links { + display: flex; + gap: 14px; +} + +.social-btn { + width: 52px; + height: 52px; + border-radius: var(--radius-lg); background: var(--bg-card); border: 1px solid var(--border); - border-radius: var(--radius-sm); - font-size: 0.9rem; - color: var(--text-primary); - font-family: var(--font-body); + display: flex; + align-items: center; + justify-content: center; + color: var(--text-secondary); + font-size: 1.1rem; + font-weight: 600; transition: all var(--duration-fast) var(--ease-out); } -.contact-form .form-input:focus { +.social-btn:hover { + background: var(--accent); + color: white; border-color: var(--accent); - box-shadow: 0 0 0 3px var(--accent-glow); - outline: none; + transform: translateY(-3px); } -.contact-form .form-input::placeholder { - color: var(--text-muted); +.faq-cta { + text-align: center; + font-size: 0.9rem; + color: var(--text-secondary); + padding: 24px; + background: var(--bg-glass); + border: 1px solid var(--border); + border-radius: var(--radius-xl); + line-height: 1.5; } -.contact-success { +.faq-cta a { + color: var(--accent-light); + text-decoration: underline; +} + +/* Form Enhancements */ +.contact-form .required { + color: #f87171; +} + +.btn-spinner { + display: inline-block; + animation: spin 1s linear infinite; +} + +@keyframes spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} + +/* Success & Error States */ +.contact-success, +.contact-error { + padding: 48px 20px; text-align: center; - padding: 32px 20px; } -@media (max-width: 768px) { - .contact-form-row { +/* Responsive */ +@media (max-width: 1024px) { + .contact-grid { grid-template-columns: 1fr; + gap: 36px; } - .contact-card { - padding: 24px; + .contact-form-card { + padding: 36px; + } +} + +@media (max-width: 640px) { + .contact-form-card { + padding: 28px 24px; + } + + .info-card { + padding: 28px; } } @@ -1484,7 +1632,9 @@ .animate-on-scroll { opacity: 0; transform: translateY(40px); - transition: opacity 1.2s cubic-bezier(0.16, 1, 0.3, 1), transform 1.2s cubic-bezier(0.16, 1, 0.3, 1); + transition: + opacity 1.2s cubic-bezier(0.16, 1, 0.3, 1), + transform 1.2s cubic-bezier(0.16, 1, 0.3, 1); transition-delay: var(--delay, 0s); will-change: opacity, transform; } @@ -1533,7 +1683,11 @@ align-items: center; position: relative; min-height: 300px; - background: radial-gradient(circle at center, rgba(168, 85, 247, 0.1), transparent 70%); + background: radial-gradient( + circle at center, + rgba(168, 85, 247, 0.1), + transparent 70% + ); } .mock-card { @@ -1854,7 +2008,6 @@ } @media (max-width: 768px) { - .use-case-card, .use-case-card.reverse { flex-direction: column; @@ -1949,7 +2102,6 @@ } @media (max-width: 768px) { - .navbar-links, .navbar-actions { display: none !important; @@ -2039,6 +2191,3 @@ display: flex; } } - - - diff --git a/public/home.html b/public/home.html index 7d96474..9ca75ae 100644 --- a/public/home.html +++ b/public/home.html @@ -1,1191 +1,2335 @@ - + + + + + + Conn — All Links at One Place | Best Link in Bio Tool + + + + - - - - - Conn — All Links at One Place | Best Link in Bio Tool - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - -
-
-
-
-
- - - - - - -
-
-
- - ✨ Your links, your style -
-

- One Link.
- Infinite Possibilities. -

-

- |
- Choose from 26+ stunning themes, track analytics, and make your online presence unforgettable. -

- - - -
-
-
-
-
-
-
C
-
-
Creator Name
-
Digital creator & developer
- + + + +
+
+
+ + ✨ Your links, your style +
+

+ One Link.
+ Infinite Possibilities. +

+

+ |
+ Choose from 26+ stunning themes, track analytics, and make your + online presence unforgettable. +

+
-
-
-
- - -
-
-
-
-
- -

Share every type of content in limitless ways. -

-

Connect all your content across social media, websites, stores, and more in one link in bio. Customize - every detail to match your brand and drive more clicks.

-
-
-
- - - - Latest Video + + +
+
+
+
+
+
+
C
-
- - - - New Podcast +
Creator Name
+
Digital creator & developer
+
+
+
+
-
-
- -

Sell products, collect payments and make monetization - simple.

-

Turn your Conn page into a storefront that pays. Add affiliate products, share what you love, and start - earning by directing your audience to your curated offers.

-
-
-
-
Total Earnings
-
₹42,500
-
-
-
-
-
-
-
+ +
+
+
+
+
+ +

+ Share every type of content in + limitless ways. +

+

+ Connect all your content across social media, websites, stores, + and more in one link in bio. Customize every detail to match + your brand and drive more clicks. +

+
+
+
+ + + + Latest Video +
+
+ + + + New Podcast
-
-
-
- -

Grow, own and engage your audience across all - channels.

-

Track your engagement over time, monitor click-throughs, and learn what’s converting your audience. Make - informed updates on the fly to keep them coming back.

-
-
-
-
- Clicks - 12.4K +
+
+ +

+ Sell products, collect payments and make + monetization simple. +

+

+ Turn your Conn page into a storefront that pays. Add affiliate + products, share what you love, and start earning by directing + your audience to your curated offers. +

+
+
+
+
Total Earnings
+
₹42,500
+
+
+
+
+
+
+
+
-
- CTR - 4.8% +
+
+ +
+
+ +

+ Grow, own and engage your audience + across all channels. +

+

+ Track your engagement over time, monitor click-throughs, and + learn what’s converting your audience. Make informed updates on + the fly to keep them coming back. +

+
+
+
+
+ Clicks + 12.4K +
+
+ CTR + 4.8% +
-
-
- - -
-
-
- -

Everything you need.
Nothing you don't.

-

Powerful tools to build and manage your online presence, wrapped in a beautiful - interface.

-
+
-
-
-
- - - - - -
-

26+ Stunning Themes

-

From Midnight Noir to Neon Cyber — find the perfect aesthetic that matches your vibe. One click to switch. + +

+
+
+ +

+ Everything you need.
Nothing you don't. +

+

+ Powerful tools to build and manage your online presence, wrapped in + a beautiful interface.

-
-
- - - - - +
+
+
+ + + + + +
+

26+ Stunning Themes

+

+ From Midnight Noir to Neon Cyber — find the perfect aesthetic that + matches your vibe. One click to switch. +

-

Real-Time Analytics

-

Track every click, see what's working, optimize your links. Powerful insights with a clean dashboard.

-
-
-
- - - - +
+
+ + + + + +
+

Real-Time Analytics

+

+ Track every click, see what's working, optimize your links. + Powerful insights with a clean dashboard. +

-

Full Customization

-

Edit your name, bio, avatar, and social links. Drag to reorder. Toggle links on and off instantly.

-
-
-
- - - - +
+
+ + + + +
+

Full Customization

+

+ Edit your name, bio, avatar, and social links. Drag to reorder. + Toggle links on and off instantly. +

-

Unlimited Links

-

No limits on how many links you can add. Portfolios, music, stores, socials — all in one beautiful page. -

-
-
-
- - - - - +
+
+ + + + +
+

Unlimited Links

+

+ No limits on how many links you can add. Portfolios, music, + stores, socials — all in one beautiful page. +

-

Mobile-First Design

-

Pixel-perfect on every device. Your page looks incredible whether viewed on a phone, tablet, or desktop. -

-
-
-
- - - +
+
+ + + + + +
+

Mobile-First Design

+

+ Pixel-perfect on every device. Your page looks incredible whether + viewed on a phone, tablet, or desktop. +

-

Fast & Secure

-

Lightning-fast load times. No tracking scripts. Your data stays yours. Built with performance in mind.

-
-
-
-
- - - -
-
-
- - - -
-
-
-

Neon Cyber

Electric -
+ + - - -
-
-
- -

Built for creators.

-
-
-
-
0
-
Themes
-
-
-
0
-
% Free
-
-
-
0
-
Ads
-
-
-
0
-
ms Load Time
+
+ + +
+
+
+ +

+ Built for creators. +

-
-
- - - -
-
-
- -

The only link in bio trusted by creators.

-
-
-
-
DC
-

"Once I got Conn set up, I was like, oh my god – why did I spend ₹5000 on a - website? I don’t need all of that! Now, I can see the monetization of my following becoming a full-time - thing."

-
-

David Coleman

- Digital Creator +
+
+
0
+
Themes
-
-
-
CT
-

"It’s so much easier to set up and have all of your links in one place in a - well-designed format. I hardly touch my Wordpress site anymore. I just send people to my Conn page!"

-
-

Catie T.

- Musician +
+
0
+
% Free
-
-
-
TF
-

"We love how Conn has helped us manage our business by having all social media - and ways to pay in one location. The verified badge and custom domain make it look extremely professional." -

-
-

Tiffany

- Business Owner +
+
0
+
Ads
+
+
+
0
+
ms Load Time
-
-
- - -
-
+ + +
+
- - -
-
-
- -

Questions? Answered.

+
+ + +
+ -
-
- -
-

Every time you have something new to share, changing the link in each of your social bios is - time-consuming. Conn means you never have to compromise. You can keep everything you want to share online - in one link! If you don't have a website, that's fine. If you have a Conn page, you don't need one.

-
+
+ + +
+
+
+ +

+ Questions? Answered. +

-
- -
-

Yes! Conn is a trusted, identifiable, and familiar link that your audience will feel perfectly safe - clicking on. It is fully compliant with the guidelines of major platforms like Instagram, TikTok, and - YouTube.

+
+
+ +
+

+ Every time you have something new to share, changing the link in + each of your social bios is time-consuming. Conn means you never + have to compromise. You can keep everything you want to share + online in one link! If you don't have a website, that's fine. If + you have a Conn page, you don't need one. +

+
-
-
- -
-

Absolutely! You can share affiliate links, direct audiences to your online stores, or collect leads for - your services. Removing the friction between discovery and purchase significantly boosts your conversion - rates.

+
+ +
+

+ Yes! Conn is a trusted, identifiable, and familiar link that + your audience will feel perfectly safe clicking on. It is fully + compliant with the guidelines of major platforms like Instagram, + TikTok, and YouTube. +

+
-
-
- -
-

No coding skills are required! You can change themes, update links, and edit your profile directly from - our beautifully simple dashboard. For advanced users on the Plus/Pro plans, we do offer custom CSS if you - really want to get technical.

+
+ +
+

+ Absolutely! You can share affiliate links, direct audiences to + your online stores, or collect leads for your services. Removing + the friction between discovery and purchase significantly boosts + your conversion rates. +

+
+
+
+ +
+

+ No coding skills are required! You can change themes, update + links, and edit your profile directly from our beautifully + simple dashboard. For advanced users on the Plus/Pro plans, we + do offer custom CSS if you really want to get technical. +

+
-
-
- - -
-
-
-

Ready to stand out?

-

Create your page in under a minute. No sign-up needed.

-
+ + +
+
+
+

Ready to stand out?

+

Create your page in under a minute. No sign-up needed.

+
-
- - - -
-
-
- -

Get in touch.

-

Have a question, feedback, or want to collaborate? Drop us a message and we'll get back - to you.

-
+
+ + +
+
+
+ +

+ Get in touch. +

+

+ Have a question, feedback, bug report, or partnership idea? Our team + is ready to help you. +

+
-
-
-
-
- - +
+ +
+
+

Response Time

+
+ ⏱️ +
+ We reply within 24–48 hours +

Business hours: Mon–Fri, 9 AM – 6 PM IST

+
+
-
- - + + + +
+

Connect With Us

+ +
+ +
+

+ Quick tip: Many questions are already answered in our + FAQ section. +

-
- - + + +
+ +
+ + +
+ +
+
+ + +
+
+ + +
+
+ +
+ + +
+ + + + + + + + +
- - -
-
-
+ - - + + + + + + + + diff --git a/public/js/home.js b/public/js/home.js index 71802c8..cf5f598 100644 --- a/public/js/home.js +++ b/public/js/home.js @@ -3,13 +3,13 @@ ═══════════════════════════════════════════════════════════ */ (function () { - 'use strict'; + "use strict"; // ─── Particle Canvas (reused from app.js) ─── function initParticles() { - const canvas = document.getElementById('particleCanvas'); + const canvas = document.getElementById("particleCanvas"); if (!canvas) return; - const ctx = canvas.getContext('2d'); + const ctx = canvas.getContext("2d"); let particles = []; let w, h; @@ -26,7 +26,7 @@ vy: (Math.random() - 0.5) * 0.3, size: Math.random() * 1.5 + 0.5, alpha: Math.random() * 0.3 + 0.05, - pulse: Math.random() * Math.PI * 2 + pulse: Math.random() * Math.PI * 2, }; } @@ -39,7 +39,7 @@ function draw() { ctx.clearRect(0, 0, w, h); - particles.forEach(p => { + particles.forEach((p) => { p.x += p.vx; p.y += p.vy; p.pulse += 0.01; @@ -71,62 +71,65 @@ requestAnimationFrame(draw); } - window.addEventListener('resize', resize); + window.addEventListener("resize", resize); init(); draw(); } // ─── Scroll Reveal ─── function initScrollReveal() { - const elements = document.querySelectorAll('.animate-on-scroll'); - const observer = new IntersectionObserver((entries) => { - entries.forEach(entry => { - if (entry.isIntersecting) { - entry.target.classList.add('visible'); - observer.unobserve(entry.target); - } - }); - }, { threshold: 0.1, rootMargin: '0px 0px -40px 0px' }); + const elements = document.querySelectorAll(".animate-on-scroll"); + const observer = new IntersectionObserver( + (entries) => { + entries.forEach((entry) => { + if (entry.isIntersecting) { + entry.target.classList.add("visible"); + observer.unobserve(entry.target); + } + }); + }, + { threshold: 0.1, rootMargin: "0px 0px -40px 0px" }, + ); - elements.forEach(el => observer.observe(el)); + elements.forEach((el) => observer.observe(el)); } // ─── Navbar Scroll Effect ─── function initNavbar() { - const navbar = document.getElementById('navbar'); + const navbar = document.getElementById("navbar"); let lastY = 0; - window.addEventListener('scroll', () => { + window.addEventListener("scroll", () => { const y = window.scrollY; - navbar.classList.toggle('scrolled', y > 50); + navbar.classList.toggle("scrolled", y > 50); lastY = y; // Close mega dropdown on scroll closeMegaDropdown(); }); // Mobile menu - const btn = document.getElementById('mobileMenuBtn'); - const menu = document.getElementById('mobileMenu'); - btn.addEventListener('click', () => menu.classList.toggle('open')); + const btn = document.getElementById("mobileMenuBtn"); + const menu = document.getElementById("mobileMenu"); + btn.addEventListener("click", () => menu.classList.toggle("open")); // Close menu on link click - menu.querySelectorAll('a').forEach(a => { - a.addEventListener('click', () => menu.classList.remove('open')); + menu.querySelectorAll("a").forEach((a) => { + a.addEventListener("click", () => menu.classList.remove("open")); }); // Mobile product accordion - const mobileProductToggle = document.getElementById('mobileProductToggle'); - const mobileProductPanel = document.getElementById('mobileProductPanel'); + const mobileProductToggle = document.getElementById("mobileProductToggle"); + const mobileProductPanel = document.getElementById("mobileProductPanel"); if (mobileProductToggle && mobileProductPanel) { - mobileProductToggle.addEventListener('click', () => { - mobileProductToggle.classList.toggle('open'); - mobileProductPanel.classList.toggle('open'); + mobileProductToggle.addEventListener("click", () => { + mobileProductToggle.classList.toggle("open"); + mobileProductPanel.classList.toggle("open"); }); // Close accordion when a link inside is clicked - mobileProductPanel.querySelectorAll('a').forEach(a => { - a.addEventListener('click', () => { - menu.classList.remove('open'); - mobileProductToggle.classList.remove('open'); - mobileProductPanel.classList.remove('open'); + mobileProductPanel.querySelectorAll("a").forEach((a) => { + a.addEventListener("click", () => { + menu.classList.remove("open"); + mobileProductToggle.classList.remove("open"); + mobileProductPanel.classList.remove("open"); }); }); } @@ -134,9 +137,9 @@ // ─── Mega Dropdown Logic ─── function initMegaDropdown() { - const dropdown = document.getElementById('navDropdown'); - const trigger = document.getElementById('navDropdownTrigger'); - const megaPanel = document.getElementById('megaDropdown'); + const dropdown = document.getElementById("navDropdown"); + const trigger = document.getElementById("navDropdownTrigger"); + const megaPanel = document.getElementById("megaDropdown"); if (!dropdown || !trigger || !megaPanel) return; let hoverTimeout = null; @@ -144,43 +147,43 @@ function openMegaDropdown() { clearTimeout(hoverTimeout); - dropdown.classList.add('open'); + dropdown.classList.add("open"); isOpen = true; } function closeMegaDropdownDelayed(delay) { clearTimeout(hoverTimeout); hoverTimeout = setTimeout(() => { - dropdown.classList.remove('open'); + dropdown.classList.remove("open"); isOpen = false; }, delay || 200); } // Desktop: hover with delay - dropdown.addEventListener('mouseenter', () => { + dropdown.addEventListener("mouseenter", () => { if (window.innerWidth > 768) openMegaDropdown(); }); - dropdown.addEventListener('mouseleave', () => { + dropdown.addEventListener("mouseleave", () => { if (window.innerWidth > 768) closeMegaDropdownDelayed(250); }); - megaPanel.addEventListener('mouseenter', () => { + megaPanel.addEventListener("mouseenter", () => { if (window.innerWidth > 768) { clearTimeout(hoverTimeout); } }); - megaPanel.addEventListener('mouseleave', () => { + megaPanel.addEventListener("mouseleave", () => { if (window.innerWidth > 768) closeMegaDropdownDelayed(250); }); // Click toggle (works on both desktop and as fallback) - trigger.addEventListener('click', (e) => { + trigger.addEventListener("click", (e) => { e.preventDefault(); e.stopPropagation(); if (isOpen) { - dropdown.classList.remove('open'); + dropdown.classList.remove("open"); isOpen = false; } else { openMegaDropdown(); @@ -188,25 +191,29 @@ }); // Close on outside click - document.addEventListener('click', (e) => { - if (isOpen && !dropdown.contains(e.target) && !megaPanel.contains(e.target)) { - dropdown.classList.remove('open'); + document.addEventListener("click", (e) => { + if ( + isOpen && + !dropdown.contains(e.target) && + !megaPanel.contains(e.target) + ) { + dropdown.classList.remove("open"); isOpen = false; } }); // Close on Escape - document.addEventListener('keydown', (e) => { - if (e.key === 'Escape' && isOpen) { - dropdown.classList.remove('open'); + document.addEventListener("keydown", (e) => { + if (e.key === "Escape" && isOpen) { + dropdown.classList.remove("open"); isOpen = false; } }); // Close on link click inside mega dropdown - megaPanel.querySelectorAll('a').forEach(a => { - a.addEventListener('click', () => { - dropdown.classList.remove('open'); + megaPanel.querySelectorAll("a").forEach((a) => { + a.addEventListener("click", () => { + dropdown.classList.remove("open"); isOpen = false; }); }); @@ -214,25 +221,28 @@ // Global close function (used by scroll handler) function closeMegaDropdown() { - const dropdown = document.getElementById('navDropdown'); - if (dropdown) dropdown.classList.remove('open'); + const dropdown = document.getElementById("navDropdown"); + if (dropdown) dropdown.classList.remove("open"); } // ─── Counter Animation ─── function initCounters() { - const counters = document.querySelectorAll('.stat-number'); - const observer = new IntersectionObserver((entries) => { - entries.forEach(entry => { - if (entry.isIntersecting) { - const el = entry.target; - const target = parseInt(el.dataset.target); - animateCounter(el, 0, target, 1500); - observer.unobserve(el); - } - }); - }, { threshold: 0.5 }); + const counters = document.querySelectorAll(".stat-number"); + const observer = new IntersectionObserver( + (entries) => { + entries.forEach((entry) => { + if (entry.isIntersecting) { + const el = entry.target; + const target = parseInt(el.dataset.target); + animateCounter(el, 0, target, 1500); + observer.unobserve(el); + } + }); + }, + { threshold: 0.5 }, + ); - counters.forEach(c => observer.observe(c)); + counters.forEach((c) => observer.observe(c)); } function animateCounter(el, start, end, duration) { @@ -254,175 +264,224 @@ // ─── Smooth Scroll ─── function initSmoothScroll() { - document.querySelectorAll('a[href^="#"]').forEach(anchor => { - anchor.addEventListener('click', (e) => { + document.querySelectorAll('a[href^="#"]').forEach((anchor) => { + anchor.addEventListener("click", (e) => { e.preventDefault(); - const target = document.querySelector(anchor.getAttribute('href')); + const target = document.querySelector(anchor.getAttribute("href")); if (target) { - target.scrollIntoView({ behavior: 'smooth', block: 'start' }); + target.scrollIntoView({ behavior: "smooth", block: "start" }); } }); }); } - // ─── Contact Form ─── + // ─── Enhanced Contact Form ─── function initContactForm() { - const form = document.getElementById('contactForm'); + const form = document.getElementById("contactForm"); if (!form) return; - form.addEventListener('submit', async (e) => { + + const submitBtn = document.getElementById("submitBtn"); + const btnText = submitBtn.querySelector(".btn-text"); + const btnSpinner = submitBtn.querySelector(".btn-spinner"); + const successDiv = document.getElementById("contactSuccess"); + const errorDiv = document.getElementById("contactError"); + const errorMessage = document.getElementById("errorMessage"); + + function showLoading() { + submitBtn.disabled = true; + if (btnText) btnText.style.display = "none"; + if (btnSpinner) btnSpinner.style.display = "inline-block"; + } + + function hideLoading() { + submitBtn.disabled = false; + if (btnText) btnText.style.display = "inline-flex"; + if (btnSpinner) btnSpinner.style.display = "none"; + } + + function showSuccess() { + form.style.display = "none"; + successDiv.style.display = "block"; + errorDiv.style.display = "none"; + } + + function showError(msg) { + errorMessage.textContent = + msg || "Something went wrong. Please try again."; + errorDiv.style.display = "block"; + successDiv.style.display = "none"; + hideLoading(); + } + + function resetContactForm() { + form.reset(); + form.style.display = "block"; + successDiv.style.display = "none"; + errorDiv.style.display = "none"; + hideLoading(); + } + + function hideError() { + errorDiv.style.display = "none"; + } + + // Make functions available globally for onclick handlers in HTML + window.resetContactForm = resetContactForm; + window.hideError = hideError; + + form.addEventListener("submit", async (e) => { e.preventDefault(); - const btn = form.querySelector('button[type="submit"]'); - const originalHTML = btn.innerHTML; - const name = document.getElementById('contactName').value.trim(); - const email = document.getElementById('contactEmail').value.trim(); - const message = document.getElementById('contactMessage').value.trim(); + const inquiryType = document.getElementById("contactInquiryType").value; + const name = document.getElementById("contactName").value.trim(); + const email = document.getElementById("contactEmail").value.trim(); + const message = document.getElementById("contactMessage").value.trim(); - if (!name || !email || !message) return; + // Client-side validation + if (!inquiryType) return showError("Please select an inquiry type."); + if (!name || name.length < 2) + return showError("Please enter a valid name (min 2 characters)."); + if (!email || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) + return showError("Please enter a valid email address."); + if (!message || message.length < 20) + return showError("Message must be at least 20 characters long."); - btn.disabled = true; - btn.innerHTML = 'Sending…'; + showLoading(); try { - const res = await fetch('/api/contact', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ name, email, message }) + const res = await fetch("/api/contact", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ inquiryType, name, email, message }), }); const data = await res.json(); if (res.ok && data.success) { - form.style.display = 'none'; - document.getElementById('contactSuccess').style.display = 'block'; - // Reset after 5s so they can send another - setTimeout(() => { - form.reset(); - form.style.display = 'flex'; - document.getElementById('contactSuccess').style.display = 'none'; - btn.disabled = false; - btn.innerHTML = originalHTML; - }, 5000); + showSuccess(); + // Auto reset after 8 seconds + setTimeout(resetContactForm, 8000); } else { - alert(data.error || 'Failed to send message. Please try again.'); - btn.disabled = false; - btn.innerHTML = originalHTML; + showError( + data.error || "Failed to send your message. Please try again.", + ); } } catch (err) { - alert('Network error. Please try again.'); - btn.disabled = false; - btn.innerHTML = originalHTML; + console.error(err); + showError("Network error. Please check your connection and try again."); } }); } // ─── Auth State (toggle navbar buttons) ─── function initAuthState() { - fetch('/api/auth/check') - .then(res => res.json()) - .then(data => { - const navGuest = document.getElementById('navGuest'); - const navAuth = document.getElementById('navAuth'); - const mobileGuest = document.getElementById('mobileGuest'); - const mobileAuth = document.getElementById('mobileAuth'); + fetch("/api/auth/check") + .then((res) => res.json()) + .then((data) => { + const navGuest = document.getElementById("navGuest"); + const navAuth = document.getElementById("navAuth"); + const mobileGuest = document.getElementById("mobileGuest"); + const mobileAuth = document.getElementById("mobileAuth"); if (data.authenticated) { - if (navAuth) navAuth.style.display = 'flex'; - if (navGuest) navGuest.style.display = 'none'; - if (mobileAuth) mobileAuth.style.display = 'block'; - if (mobileGuest) mobileGuest.style.display = 'none'; + if (navAuth) navAuth.style.display = "flex"; + if (navGuest) navGuest.style.display = "none"; + if (mobileAuth) mobileAuth.style.display = "block"; + if (mobileGuest) mobileGuest.style.display = "none"; } else { - if (navGuest) navGuest.style.display = 'flex'; - if (navAuth) navAuth.style.display = 'none'; - if (mobileGuest) mobileGuest.style.display = 'block'; - if (mobileAuth) mobileAuth.style.display = 'none'; + if (navGuest) navGuest.style.display = "flex"; + if (navAuth) navAuth.style.display = "none"; + if (mobileGuest) mobileGuest.style.display = "block"; + if (mobileAuth) mobileAuth.style.display = "none"; } }) .catch(() => { // Fallback: show guest buttons on error - const navGuest = document.getElementById('navGuest'); - const mobileGuest = document.getElementById('mobileGuest'); - if (navGuest) navGuest.style.display = 'flex'; - if (mobileGuest) mobileGuest.style.display = 'block'; + const navGuest = document.getElementById("navGuest"); + const mobileGuest = document.getElementById("mobileGuest"); + if (navGuest) navGuest.style.display = "flex"; + if (mobileGuest) mobileGuest.style.display = "block"; }); } // ─── Billing Toggle (Monthly / Yearly) ─── function initBillingToggle() { - const toggle = document.getElementById('billingToggle'); - const monthlyLabel = document.getElementById('billingMonthlyLabel'); - const yearlyLabel = document.getElementById('billingYearlyLabel'); - const plusPrice = document.getElementById('plusPrice'); - const plusInterval = document.getElementById('plusInterval'); - const yearlyNote = document.getElementById('yearlyNote'); + const toggle = document.getElementById("billingToggle"); + const monthlyLabel = document.getElementById("billingMonthlyLabel"); + const yearlyLabel = document.getElementById("billingYearlyLabel"); + const plusPrice = document.getElementById("plusPrice"); + const plusInterval = document.getElementById("plusInterval"); + const yearlyNote = document.getElementById("yearlyNote"); - const proPrice = document.getElementById('proPrice'); - const proInterval = document.getElementById('proInterval'); - const proYearlyNote = document.getElementById('proYearlyNote'); + const proPrice = document.getElementById("proPrice"); + const proInterval = document.getElementById("proInterval"); + const proYearlyNote = document.getElementById("proYearlyNote"); if (!toggle) return; let isYearly = false; // Default state: monthly active - if (monthlyLabel) monthlyLabel.classList.add('active'); + if (monthlyLabel) monthlyLabel.classList.add("active"); - toggle.addEventListener('click', () => { + toggle.addEventListener("click", () => { isYearly = !isYearly; - toggle.classList.toggle('active', isYearly); + toggle.classList.toggle("active", isYearly); - if (monthlyLabel) monthlyLabel.classList.toggle('active', !isYearly); - if (yearlyLabel) yearlyLabel.classList.toggle('active', isYearly); + if (monthlyLabel) monthlyLabel.classList.toggle("active", !isYearly); + if (yearlyLabel) yearlyLabel.classList.toggle("active", isYearly); if (isYearly) { - if (plusPrice) plusPrice.textContent = '500'; - if (plusInterval) plusInterval.textContent = '/year'; - if (yearlyNote) yearlyNote.style.display = 'flex'; - - if (proPrice) proPrice.textContent = '4000'; - if (proInterval) proInterval.textContent = '/year'; - if (proYearlyNote) proYearlyNote.style.display = 'flex'; + if (plusPrice) plusPrice.textContent = "500"; + if (plusInterval) plusInterval.textContent = "/year"; + if (yearlyNote) yearlyNote.style.display = "flex"; + + if (proPrice) proPrice.textContent = "4000"; + if (proInterval) proInterval.textContent = "/year"; + if (proYearlyNote) proYearlyNote.style.display = "flex"; } else { - if (plusPrice) plusPrice.textContent = '50'; - if (plusInterval) plusInterval.textContent = '/month'; - if (yearlyNote) yearlyNote.style.display = 'none'; - - if (proPrice) proPrice.textContent = '399'; - if (proInterval) proInterval.textContent = '/month'; - if (proYearlyNote) proYearlyNote.style.display = 'none'; + if (plusPrice) plusPrice.textContent = "50"; + if (plusInterval) plusInterval.textContent = "/month"; + if (yearlyNote) yearlyNote.style.display = "none"; + + if (proPrice) proPrice.textContent = "399"; + if (proInterval) proInterval.textContent = "/month"; + if (proYearlyNote) proYearlyNote.style.display = "none"; } }); } // ─── Razorpay Checkout (Landing) ─── function initRazorpayLanding() { - const btnPlus = document.getElementById('btnLandingPlus'); - const btnPro = document.getElementById('btnLandingPro'); + const btnPlus = document.getElementById("btnLandingPlus"); + const btnPro = document.getElementById("btnLandingPro"); if (!btnPlus || !btnPro) return; async function handleUpgradeClick(e, planId) { e.preventDefault(); - + // Check auth First try { - const authRes = await fetch('/api/auth/check'); + const authRes = await fetch("/api/auth/check"); const authData = await authRes.json(); - + if (!authData.authenticated) { - window.location.href = '/signup'; + window.location.href = "/signup"; return; } // Get billing cycle - const isYearly = document.getElementById('billingToggle').classList.contains('active'); - const billing = isYearly ? 'yearly' : 'monthly'; + const isYearly = document + .getElementById("billingToggle") + .classList.contains("active"); + const billing = isYearly ? "yearly" : "monthly"; // Create Order - const orderRes = await fetch('/api/payment/create-order', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ planId, billing }) + const orderRes = await fetch("/api/payment/create-order", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ planId, billing }), }); - + const orderData = await orderRes.json(); if (orderData.error) { alert(orderData.error); @@ -434,58 +493,59 @@ key: orderData.key, amount: orderData.amount, currency: orderData.currency, - name: 'Conn', + name: "Conn", description: `Upgrade to ${planId.charAt(0).toUpperCase() + planId.slice(1)} Plan`, order_id: orderData.orderId, handler: async function (response) { // Verify payment - const verifyRes = await fetch('/api/payment/verify', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, + const verifyRes = await fetch("/api/payment/verify", { + method: "POST", + headers: { "Content-Type": "application/json" }, body: JSON.stringify({ razorpay_order_id: response.razorpay_order_id, razorpay_payment_id: response.razorpay_payment_id, - razorpay_signature: response.razorpay_signature - }) + razorpay_signature: response.razorpay_signature, + }), }); const verifyData = await verifyRes.json(); if (verifyData.success) { - window.location.href = '/admin'; // Redirect to dashboard + window.location.href = "/admin"; // Redirect to dashboard } else { - alert('Payment verification failed.'); + alert("Payment verification failed."); } }, - theme: { color: '#a855f7' } + theme: { color: "#a855f7" }, }; const rzp = new window.Razorpay(options); - rzp.on('payment.failed', function (response) { - alert('Payment failed: ' + response.error.description); + rzp.on("payment.failed", function (response) { + alert("Payment failed: " + response.error.description); }); rzp.open(); - } catch (err) { - console.error('Error starting checkout:', err); - alert('An error occurred. Please try again.'); + console.error("Error starting checkout:", err); + alert("An error occurred. Please try again."); } } - btnPlus.addEventListener('click', (e) => handleUpgradeClick(e, 'plus')); - btnPro.addEventListener('click', (e) => handleUpgradeClick(e, 'professional')); + btnPlus.addEventListener("click", (e) => handleUpgradeClick(e, "plus")); + btnPro.addEventListener("click", (e) => + handleUpgradeClick(e, "professional"), + ); } // ─── FAQ Accordion ─── function initFAQ() { - const faqItems = document.querySelectorAll('.faq-item'); - faqItems.forEach(item => { - const btn = item.querySelector('.faq-question'); + const faqItems = document.querySelectorAll(".faq-item"); + faqItems.forEach((item) => { + const btn = item.querySelector(".faq-question"); if (!btn) return; - btn.addEventListener('click', () => { + btn.addEventListener("click", () => { // Toggle current, close others - const isOpen = item.classList.contains('open'); - faqItems.forEach(other => other.classList.remove('open')); + const isOpen = item.classList.contains("open"); + faqItems.forEach((other) => other.classList.remove("open")); if (!isOpen) { - item.classList.add('open'); + item.classList.add("open"); } }); }); @@ -493,34 +553,36 @@ // ─── Visual Upgrades (Cursor, Typewriter, Magnetic, Tilt) ─── function initCustomCursor() { - const cursor = document.getElementById('cursor-glow'); + const cursor = document.getElementById("cursor-glow"); if (!cursor) return; - document.addEventListener('mousemove', (e) => { + document.addEventListener("mousemove", (e) => { cursor.style.transform = `translate(calc(${e.clientX}px - 50%), calc(${e.clientY}px - 50%))`; }); - const interactables = document.querySelectorAll('a, button, .feature-card, .pricing-card, .use-case-card, .theme-preview-card'); - interactables.forEach(el => { - el.addEventListener('mouseenter', () => { - cursor.style.width = '60px'; - cursor.style.height = '60px'; - cursor.style.background = 'var(--accent-light)'; + const interactables = document.querySelectorAll( + "a, button, .feature-card, .pricing-card, .use-case-card, .theme-preview-card", + ); + interactables.forEach((el) => { + el.addEventListener("mouseenter", () => { + cursor.style.width = "60px"; + cursor.style.height = "60px"; + cursor.style.background = "var(--accent-light)"; }); - el.addEventListener('mouseleave', () => { - cursor.style.width = '40px'; - cursor.style.height = '40px'; - cursor.style.background = 'var(--accent)'; + el.addEventListener("mouseleave", () => { + cursor.style.width = "40px"; + cursor.style.height = "40px"; + cursor.style.background = "var(--accent)"; }); }); } function initTypewriter() { - const tw = document.getElementById('typewriter'); + const tw = document.getElementById("typewriter"); if (!tw) return; const phrases = [ "Your entire digital universe in one place.", "Monetize your passion effortlessly.", "Grow your audience exponentially.", - "Create your digital home in seconds." + "Create your digital home in seconds.", ]; let i = 0; let charIndex = 0; @@ -551,9 +613,9 @@ } function initMagneticButtons() { - const buttons = document.querySelectorAll('.btn-hero'); - buttons.forEach(btn => { - btn.addEventListener('mousemove', (e) => { + const buttons = document.querySelectorAll(".btn-hero"); + buttons.forEach((btn) => { + btn.addEventListener("mousemove", (e) => { const rect = btn.getBoundingClientRect(); const x = e.clientX - rect.left - rect.width / 2; const y = e.clientY - rect.top - rect.height / 2; @@ -561,26 +623,31 @@ const mappedY = (y / (rect.height / 2)) * 12; btn.style.transform = `translate(${mappedX}px, ${mappedY}px)`; }); - btn.addEventListener('mouseleave', () => { + btn.addEventListener("mouseleave", () => { btn.style.transform = `translate(0, 0)`; }); }); } function initVanillaTilt() { - if (typeof VanillaTilt !== 'undefined') { - VanillaTilt.init(document.querySelectorAll(".feature-card, .use-case-card, .pricing-card, .testimonial-card, .learn-card"), { - max: 8, - speed: 400, - glare: true, - "max-glare": 0.15, - scale: 1.02 - }); + if (typeof VanillaTilt !== "undefined") { + VanillaTilt.init( + document.querySelectorAll( + ".feature-card, .use-case-card, .pricing-card, .testimonial-card, .learn-card", + ), + { + max: 8, + speed: 400, + glare: true, + "max-glare": 0.15, + scale: 1.02, + }, + ); } } // ─── Init ─── - document.addEventListener('DOMContentLoaded', () => { + document.addEventListener("DOMContentLoaded", () => { initParticles(); initScrollReveal(); initNavbar(); @@ -600,10 +667,10 @@ })(); // Scroll to Top -const scrollTopBtn = document.getElementById('scrollTopBtn'); -window.addEventListener('scroll', () => { - scrollTopBtn.classList.toggle('visible', window.scrollY > 300); +const scrollTopBtn = document.getElementById("scrollTopBtn"); +window.addEventListener("scroll", () => { + scrollTopBtn.classList.toggle("visible", window.scrollY > 300); }); -scrollTopBtn.addEventListener('click', () => { - window.scrollTo({ top: 0, behavior: 'smooth' }); +scrollTopBtn.addEventListener("click", () => { + window.scrollTo({ top: 0, behavior: "smooth" }); });