1// =================================== 2// NAVIGATION 3// =================================== 4 5const navbar = document.querySelector('.navbar'); 6const mobileMenuToggle = document.querySelector('.mobile-menu-toggle'); 7const navLinks = document.querySelector('.nav-links'); 8 9// Sticky navbar on scroll 10window.addEventListener('scroll', () => { 11 if (window.scrollY > 50) { 12 navbar.classList.add('scrolled'); 13 } else { 14 navbar.classList.remove('scrolled'); 15 } 16}); 17 18// Mobile menu toggle 19if (mobileMenuToggle) { 20 mobileMenuToggle.addEventListener('click', () => { 21 navLinks.classList.toggle('active'); 22 23 // Animate hamburger menu 24 const spans = mobileMenuToggle.querySelectorAll('span'); 25 if (navLinks.classList.contains('active')) { 26 spans[0].style.transform = 'rotate(45deg) translateY(7px)'; 27 spans[1].style.opacity = '0'; 28 spans[2].style.transform = 'rotate(-45deg) translateY(-7px)'; 29 } else { 30 spans[0].style.transform = 'none'; 31 spans[1].style.opacity = '1'; 32 spans[2].style.transform = 'none'; 33 } 34 }); 35} 36 37// Close mobile menu when clicking on a link 38document.querySelectorAll('.nav-links a').forEach(link => { 39 link.addEventListener('click', () => { 40 navLinks.classList.remove('active'); 41 const spans = mobileMenuToggle.querySelectorAll('span'); 42 spans[0].style.transform = 'none'; 43 spans[1].style.opacity = '1'; 44 spans[2].style.transform = 'none'; 45 }); 46}); 47 48// =================================== 49// SMOOTH SCROLLING 50// =================================== 51 52document.querySelectorAll('a[href^="#"]').forEach(anchor => { 53 anchor.addEventListener('click', function (e) { 54 const href = this.getAttribute('href'); 55 56 // Ignore empty hash or just # links 57 if (href === '#' || href === '#!') { 58 e.preventDefault(); 59 return; 60 } 61 62 const target = document.querySelector(href); 63 if (target) { 64 e.preventDefault(); 65 const offsetTop = target.offsetTop - 80; 66 window.scrollTo({ 67 top: offsetTop, 68 behavior: 'smooth' 69 }); 70 } 71 }); 72}); 73 74// =================================== 75// FAQ ACCORDION 76// =================================== 77 78const faqItems = document.querySelectorAll('.faq-item'); 79 80faqItems.forEach(item => { 81 const question = item.querySelector('.faq-question'); 82 83 question.addEventListener('click', () => { 84 const isActive = item.classList.contains('active'); 85 86 // Close all FAQ items 87 faqItems.forEach(faq => { 88 faq.classList.remove('active'); 89 }); 90 91 // Open clicked item if it wasn't active 92 if (!isActive) { 93 item.classList.add('active'); 94 } 95 }); 96}); 97 98// =================================== 99// SCROLL ANIMATIONS 100// =================================== 101 102const observerOptions = { 103 threshold: 0.1, 104 rootMargin: '0px 0px -100px 0px' 105}; 106 107const observer = new IntersectionObserver((entries) => { 108 entries.forEach(entry => { 109 if (entry.isIntersecting) { 110 entry.target.style.opacity = '1'; 111 entry.target.style.transform = 'translateY(0)'; 112 } 113 }); 114}, observerOptions); 115 116// Animate elements on scroll 117const animateOnScroll = document.querySelectorAll(` 118 .benefit-item, 119 .stat-box, 120 .reason-item, 121 .video-type-card, 122 .option-card, 123 .step-card, 124 .showcase-item, 125 .feature-card, 126 .use-case-card, 127 .testimonial-card, 128 .sample-item 129`); 130 131animateOnScroll.forEach(el => { 132 el.style.opacity = '0'; 133 el.style.transform = 'translateY(30px)'; 134 el.style.transition = 'opacity 0.6s ease, transform 0.6s ease'; 135 observer.observe(el); 136}); 137 138// =================================== 139// COUNTER ANIMATION 140// =================================== 141 142function animateCounter(element, target, duration = 2000) { 143 const start = 0; 144 const increment = target / (duration / 16);
145 let current = start; 146 147 const timer = setInterval(() => { 148 current += increment; 149 if (current >= target) { 150 element.textContent = target + '%'; 151 clearInterval(timer); 152 } else { 153 element.textContent = Math.floor(current) + '%'; 154 } 155 }, 16); 156} 157 158// Animate stat number when visible 159const statNumber = document.querySelector('.stat-number'); 160if (statNumber) { 161 const statObserver = new IntersectionObserver((entries) => { 162 entries.forEach(entry => { 163 if (entry.isIntersecting && !entry.target.classList.contains('animated')) { 164 animateCounter(entry.target, 63); 165 entry.target.classList.add('animated'); 166 } 167 }); 168 }, { threshold: 0.5 }); 169 170 statObserver.observe(statNumber); 171} 172 173// =================================== 174// VIDEO PLAY BUTTONS 175// =================================== 176 177const playButtons = document.querySelectorAll('.play-button, .watch-demo'); 178 179function openVideoModal(url) { 180 const modal = document.createElement('div'); 181 modal.className = 'video-modal'; 182 modal.innerHTML = ` 183 <div class="modal-overlay"></div> 184 <div class="modal-content" style="position:relative;max-width:960px;width:92%;aspect-ratio:16/9;background:#000;border-radius:12px;overflow:hidden;"> 185 <button class="modal-close" aria-label="Close video" style="position:absolute;top:8px;right:8px;background:rgba(0,0,0,0.6);border:none;color:#fff;font-size:28px;line-height:1;padding:6px 10px;border-radius:8px;cursor:pointer;z-index:2">Ã</button> 186 <iframe src="${url}" title="Demo video" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen style="width:100%;height:100%"></iframe> 187 </div> 188 `; 189 190 Object.assign(modal.style, { 191 position: 'fixed', 192 inset: '0', 193 zIndex: '10000', 194 display: 'flex', 195 alignItems: 'center', 196 justifyContent: 'center', 197 background: 'rgba(0,0,0,0.8)' 198 }); 199 200 document.body.appendChild(modal); 201 202 const close = () => { 203 modal.style.opacity = '0'; 204 setTimeout(() => modal.remove(), 200); 205 }; 206 207 modal.querySelector('.modal-overlay')?.addEventListener('click', close); 208 modal.querySelector('.modal-close')?.addEventListener('click', close); 209 document.addEventListener('keydown', function esc(e){ 210 if (e.key === 'Escape') { close(); document.removeEventListener('keydown', esc); } 211 }); 212} 213 214playButtons.forEach(button => { 215 button.addEventListener('click', (e) => { 216 e.preventDefault(); 217 const url = button.getAttribute('data-video'); 218 if (url) openVideoModal(url); 219 }); 220}); 221 222// =================================== 223// FORM VALIDATION (if you add forms later) 224// =================================== 225 226function validateEmail(email) { 227 const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; 228 return re.test(email); 229} 230 231// =================================== 232// PRICING BUTTON ACTIONS 233// =================================== 234 235const buyButtons = document.querySelectorAll('.btn-primary'); 236 237buyButtons.forEach(button => { 238 if (button.textContent.includes('BUY NOW') || button.textContent.includes('Get ClipBee')) { 239 button.addEventListener('click', (e) => { 240 // Here you would integrate with your payment processor 241 // For now, we'll just prevent the default action if it's not a link 242 if (button.tagName !== 'A') { 243 e.preventDefault(); 244 console.log('Payment integration would go here'); 245 } 246 }); 247 } 248}); 249 250// =================================== 251// LAZY LOADING IMAGES 252// =================================== 253 254if ('loading' in HTMLImageElement.prototype) { 255 const images = document.querySelectorAll('img[loading="lazy"]'); 256 images.forEach(img => { 257 img.src = img.dataset.src || img.src; 258 }); 259} else { 260 // Fallback for browsers that don't support lazy loading 261 const script = document.createElement('script'); 262 script.src = 'https://cdnjs.cloudflare.com/ajax/libs/lazysizes/5.3.2/lazysizes.min.js'; 263 document.body.appendChild(script); 264} 265 266// =================================== 267// PARALLAX EFFECT 268// =================================== 269 270window.addEventListener('scroll', () => { 271 const scrolled = window.pageYOffset; 272 const heroVideo = document.querySelector('.hero-video'); 273 274 if (heroVideo) { 275 heroVideo.style.transform = `translateY(${scrolled * 0.5}px)`; 276 } 277}); 278 279// =================================== 280// COUNTDOWN TIMER (Optional - for urgency) 281// =================================== 282 283function startCountdown(duration, displayElement) { 284 let timer = duration; 285 const interval = setInterval(() => { 286 const hours = Math.floor(timer / 3600); 287 const minutes = Math.floor((timer % 3600) / 60); 288 const seconds = timer % 60; 289 290 if (displayElement) { 291 displayElement.textContent = 292 `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`; 293 } 294 295 if (--timer < 0) { 296 clearInterval(interval); 297 if (displayElement) { 298 displayElement.textContent = 'Offer Expired!'; 299 } 300 } 301 }, 1000); 302} 303 304// Example: Start a 24-hour countdown 305// const countdownElement = document.querySelector('.countdown-timer'); 306// if (countdownElement) { 307// startCountdown(24 * 60 * 60, countdownElement); 308// } 309 310// =================================== 311// SAMPLE GALLERY MODAL (Optional) 312// =================================== 313 314const sampleItems = document.querySelectorAll('.sample-item'); 315
316sampleItems.forEach(item => { 317 item.addEventListener('click', () => { 318 const imgSrc = item.querySelector('img').src; 319 const label = item.querySelector('.sample-label').textContent; 320 321 // Create modal 322 const modal = document.createElement('div'); 323 modal.className = 'image-modal'; 324 modal.innerHTML = ` 325 <div class="modal-overlay"></div> 326 <div class="modal-content"> 327 <button class="modal-close">×</button> 328 <img src="${imgSrc}" alt="${label}"> 329 <p>${label}</p> 330 </div> 331 `; 332 333 // Add styles 334 modal.style.cssText = ` 335 position: fixed; 336 top: 0; 337 left: 0; 338 width: 100%; 339 height: 100%; 340 z-index: 10000; 341 display: flex; 342 align-items: center; 343 justify-content: center; 344 `; 345 346 const overlay = modal.querySelector('.modal-overlay'); 347 overlay.style.cssText = ` 348 position: absolute; 349 top: 0; 350 left: 0; 351 width: 100%; 352 height: 100%; 353 background: rgba(0, 0, 0, 0.9); 354 `; 355 356 const content = modal.querySelector('.modal-content'); 357 content.style.cssText = ` 358 position: relative; 359 max-width: 90%; 360 max-height: 90%; 361 z-index: 1; 362 `; 363 364 const closeBtn = modal.querySelector('.modal-close'); 365 closeBtn.style.cssText = ` 366 position: absolute; 367 top: -40px; 368 right: 0; 369 background: none; 370 border: none; 371 color: white; 372 font-size: 40px; 373 cursor: pointer; 374 line-height: 1; 375 `; 376 377 const img = modal.querySelector('img'); 378 img.style.cssText = ` 379 max-width: 100%; 380 max-height: 80vh; 381 border-radius: 12px; 382 display: block; 383 `; 384 385 const p = modal.querySelector('p'); 386 p.style.cssText = ` 387 color: white; 388 text-align: center; 389 margin-top: 16px; 390 font-size: 1.125rem; 391 `; 392 393 document.body.appendChild(modal); 394 395 // Close modal 396 const closeModal = () => { 397 modal.style.opacity = '0'; 398 setTimeout(() => modal.remove(), 300); 399 }; 400 401 modal.style.opacity = '0'; 402 setTimeout(() => modal.style.opacity = '1', 10); 403 modal.style.transition = 'opacity 0.3s ease'; 404 405 closeBtn.addEventListener('click', closeModal); 406 overlay.addEventListener('click', closeModal); 407 408 // Close on escape key 409 document.addEventListener('keydown', function escapeHandler(e) { 410 if (e.key === 'Escape') { 411 closeModal(); 412 document.removeEventListener('keydown', escapeHandler); 413 } 414 }); 415 }); 416}); 417 418// =================================== 419// FEATURE CARD HOVER EFFECT 420// =================================== 421 422const featureCards = document.querySelectorAll('.feature-card'); 423 424featureCards.forEach(card => { 425 card.addEventListener('mouseenter', function() { 426 this.style.transform = 'translateY(-8px) scale(1.02)'; 427 }); 428 429 card.addEventListener('mouseleave', function() { 430 this.style.transform = 'translateY(0) scale(1)'; 431 }); 432}); 433 434// =================================== 435// SCROLL TO TOP BUTTON (Optional) 436// =================================== 437 438function createScrollToTop() { 439 const button = document.createElement('button'); 440 button.innerHTML = 'â'; 441 button.className = 'scroll-to-top'; 442 button.style.cssText = ` 443 position: fixed; 444 bottom: 40px; 445 right: 40px; 446 width: 50px; 447 height: 50px; 448 border-radius: 50%; 449 background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%); 450 color: white; 451 border: none; 452 font-size: 24px; 453 cursor: pointer; 454 opacity: 0; 455 pointer-events: none; 456 transition: all 0.3s ease; 457 z-index: 999; 458 box-shadow: 0 4px 20px rgba(99, 102, 241, 0.4); 459 `; 460 461 document.body.appendChild(button); 462 463 window.addEventListener('scroll', () => { 464 if (window.pageYOffset > 500) { 465 button.style.opacity = '1'; 466 button.style.pointerEvents = 'all'; 467 } else { 468 button.style.opacity = '0'; 469 button.style.pointerEvents = 'none'; 470 } 471 });
472 473 button.addEventListener('click', () => { 474 window.scrollTo({ 475 top: 0, 476 behavior: 'smooth' 477 }); 478 }); 479 480 button.addEventListener('mouseenter', function() { 481 this.style.transform = 'scale(1.1) translateY(-4px)'; 482 this.style.boxShadow = '0 8px 30px rgba(99, 102, 241, 0.5)'; 483 }); 484 485 button.addEventListener('mouseleave', function() { 486 this.style.transform = 'scale(1) translateY(0)'; 487 this.style.boxShadow = '0 4px 20px rgba(99, 102, 241, 0.4)'; 488 }); 489} 490 491// Initialize scroll to top button 492createScrollToTop(); 493 494// =================================== 495// TESTIMONIAL ROTATION (Optional) 496// =================================== 497 498function rotateTestimonials() { 499 const testimonials = document.querySelectorAll('.testimonial-card'); 500 if (testimonials.length === 0) return; 501 502 let currentIndex = 0; 503 504 setInterval(() => { 505 testimonials[currentIndex].style.transform = 'scale(1)'; 506 currentIndex = (currentIndex + 1) % testimonials.length; 507 testimonials[currentIndex].style.transform = 'scale(1.05)'; 508 }, 3000); 509} 510 511// Uncomment to enable testimonial rotation 512// rotateTestimonials(); 513 514// =================================== 515// ANALYTICS TRACKING (Placeholder) 516// =================================== 517 518function trackEvent(category, action, label) { 519 // Google Analytics or other tracking 520 if (typeof gtag !== 'undefined') { 521 gtag('event', action, { 522 'event_category': category, 523 'event_label': label 524 }); 525 } 526 527 console.log(`Event tracked: ${category} - ${action} - ${label}`); 528} 529 530// Track CTA clicks 531document.querySelectorAll('.btn-primary').forEach(btn => { 532 btn.addEventListener('click', () => { 533 const text = btn.textContent.trim(); 534 trackEvent('CTA', 'click', text); 535 }); 536}); 537 538// Track section views 539const sections = document.querySelectorAll('section[id]'); 540const sectionObserver = new IntersectionObserver((entries) => { 541 entries.forEach(entry => { 542 if (entry.isIntersecting) { 543 trackEvent('Section View', 'view', entry.target.id); 544 } 545 }); 546}, { threshold: 0.5 }); 547 548sections.forEach(section => { 549 sectionObserver.observe(section); 550}); 551 552// =================================== 553// INITIALIZATION 554// =================================== 555 556document.addEventListener('DOMContentLoaded', () => { 557 console.log('ClipBee Sales Page Loaded Successfully! ð'); 558 559 // Add any initialization code here 560 561 // Smooth reveal on page load 562 document.body.style.opacity = '0'; 563 setTimeout(() => { 564 document.body.style.transition = 'opacity 0.5s ease'; 565 document.body.style.opacity = '1'; 566 }, 100); 567 568 // Progressive enhancement: add loading="lazy" to all images if not present 569 document.querySelectorAll('img').forEach(img => { 570 if (!img.hasAttribute('loading')) { 571 img.setAttribute('loading', 'lazy'); 572 } 573 }); 574}); 575 576// =================================== 577// PERFORMANCE OPTIMIZATION 578// =================================== 579 580// Debounce function for scroll events 581function debounce(func, wait) { 582 let timeout; 583 return function executedFunction(...args) { 584 const later = () => { 585 clearTimeout(timeout); 586 func(...args); 587 }; 588 clearTimeout(timeout); 589 timeout = setTimeout(later, wait); 590 }; 591} 592 593// Throttle function for scroll events 594function throttle(func, limit) { 595 let inThrottle; 596 return function() { 597 const args = arguments; 598 const context = this; 599 if (!inThrottle) { 600 func.apply(context, args); 601 inThrottle = true; 602 setTimeout(() => inThrottle = false, limit); 603 } 604 }; 605} 606 607// Use throttled scroll handler for better performance 608window.addEventListener('scroll', throttle(() => { 609 // Sticky CTA visibility 610 const sticky = document.querySelector('.sticky-cta'); 611 const pricing = document.querySelector('#pricing'); 612 const hero = document.querySelector('.hero'); 613 if (!sticky || !pricing || !hero) return; 614 615 const heroBottom = hero.getBoundingClientRect().bottom; 616 const pricingTop = pricing.getBoundingClientRect().top;
617 const viewportHeight = window.innerHeight; 618 619 // Show sticky CTA after hero leaves, hide when pricing is in view 620 if (heroBottom < 0 && pricingTop > viewportHeight * 0.5) { 621 sticky.classList.add('visible'); 622 } else { 623 sticky.classList.remove('visible'); 624 } 625}, 100)); 626 627console.log('ClipBee - The Future of AI Stock Footage Generation ð¬'); 628
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.