diff --git a/assets/css/style.css b/assets/css/style.css
index ed51f1e..9395a37 100644
--- a/assets/css/style.css
+++ b/assets/css/style.css
@@ -133,6 +133,22 @@ body {
-moz-osx-font-smoothing: grayscale;
}
+/* Prevent scrolling when mobile menu is open */
+body.menu-open {
+ overflow: hidden;
+}
+
+/* Mobile specific styles */
+body.is-mobile .hero-particles {
+ animation-duration: 30s;
+}
+
+/* Touch active state for mobile */
+.touch-active {
+ opacity: 0.8 !important;
+ transition: opacity 0.15s ease;
+}
+
/* Typography */
h1, h2, h3, h4, h5, h6 {
font-family: var(--font-heading);
@@ -2915,12 +2931,299 @@ section {
}
}
+/* Enhanced Mobile Responsiveness for 320px and up */
+@media (max-width: 480px) {
+ .container {
+ padding: 0 var(--space-3);
+ }
+
+ /* Enhanced Hero Section for mobile */
+ .hero {
+ min-height: 80vh;
+ padding-top: 60px;
+ }
+
+ .hero-title {
+ font-size: var(--text-3xl);
+ line-height: 1.2;
+ }
+
+ .hero-description {
+ font-size: var(--text-base);
+ margin-bottom: var(--space-6);
+ }
+
+ .hero-buttons {
+ gap: var(--space-3);
+ }
+
+ .hero-buttons .btn {
+ width: 100%;
+ max-width: 280px;
+ padding: var(--space-3) var(--space-4);
+ }
+
+ .hero-stats {
+ flex-direction: column;
+ gap: var(--space-4);
+ margin-top: var(--space-8);
+ }
+
+ .stat {
+ padding: var(--space-4);
+ background: var(--card-bg);
+ border-radius: var(--radius-lg);
+ border: 1px solid var(--border-color);
+ }
+
+ /* Services grid mobile optimization */
+ .services-grid {
+ grid-template-columns: 1fr;
+ gap: var(--space-6);
+ }
+
+ .service-card {
+ padding: var(--space-6);
+ }
+
+ /* Portfolio grid mobile optimization */
+ .portfolio-grid {
+ grid-template-columns: 1fr;
+ gap: var(--space-6);
+ }
+
+ .portfolio-actions {
+ flex-direction: column;
+ gap: var(--space-2);
+ }
+
+ .portfolio-actions .btn {
+ width: 100%;
+ }
+
+ /* Testimonials mobile optimization */
+ .testimonial-author {
+ flex-direction: column;
+ gap: var(--space-3);
+ }
+
+ .author-info {
+ text-align: center;
+ }
+
+ .testimonial-text p {
+ font-size: var(--text-lg);
+ }
+
+ /* Page titles and sections */
+ .page-title {
+ font-size: var(--text-3xl);
+ }
+
+ .page-description {
+ font-size: var(--text-base);
+ }
+
+ .section-title {
+ font-size: var(--text-3xl);
+ }
+
+ .section-description {
+ font-size: var(--text-base);
+ }
+
+ /* Form improvements for mobile */
+ .form-row {
+ grid-template-columns: 1fr;
+ gap: var(--space-3);
+ }
+
+ .form-input,
+ .form-select,
+ .form-textarea {
+ padding: var(--space-4);
+ font-size: 16px; /* Prevents zoom on iOS */
+ }
+
+ /* Button improvements for mobile */
+ .btn {
+ padding: var(--space-4) var(--space-6);
+ font-size: var(--text-base);
+ min-height: 44px; /* Improve touch targets */
+ }
+
+ .btn-sm {
+ padding: var(--space-3) var(--space-5);
+ min-height: 40px;
+ }
+
+ .btn-lg {
+ padding: var(--space-5) var(--space-8);
+ min-height: 48px;
+ }
+}
+
+/* Disabled button styles */
+.btn-disabled,
+.btn:disabled {
+ opacity: 0.6;
+ cursor: not-allowed;
+ transform: none !important;
+ box-shadow: none !important;
+}
+
+.btn-disabled:hover,
+.btn:disabled:hover {
+ transform: none !important;
+ box-shadow: none !important;
+}
+
+/* Social link disabled state */
+.social-link.btn-disabled {
+ opacity: 0.5;
+ cursor: not-allowed;
+ pointer-events: none;
+}
+
+/* Enhanced touch targets for mobile */
+@media (max-width: 768px) {
+ .nav-link {
+ padding: var(--space-4) 0;
+ font-size: var(--text-lg);
+ }
+
+ .theme-toggle {
+ width: 48px;
+ height: 48px;
+ }
+
+ .mobile-menu-btn {
+ width: 48px;
+ height: 48px;
+ padding: var(--space-3);
+ }
+
+ .testimonial-nav-btn {
+ width: 16px;
+ height: 16px;
+ }
+
+ /* Improve spacing for mobile */
+ section {
+ padding: var(--space-16) 0;
+ }
+
+ .section-header {
+ margin-bottom: var(--space-12);
+ }
+
+ /* Portfolio filter mobile scrolling */
+ .filter-tabs {
+ -webkit-overflow-scrolling: touch;
+ scrollbar-width: none;
+ -ms-overflow-style: none;
+ }
+
+ .filter-tabs::-webkit-scrollbar {
+ display: none;
+ }
+
+ /* Enhanced focus states for accessibility */
+ .nav-link:focus,
+ .btn:focus,
+ .theme-toggle:focus,
+ .mobile-menu-btn:focus {
+ outline: 2px solid var(--primary-color);
+ outline-offset: 2px;
+ }
+
+ /* Loading spinner mobile */
+ .loading-spinner {
+ backdrop-filter: blur(5px);
+ }
+
+ .spinner {
+ width: 32px;
+ height: 32px;
+ }
+}
+
+/* Typography scaling for very small screens */
+@media (max-width: 360px) {
+ html {
+ font-size: 14px;
+ }
+
+ .hero-title {
+ font-size: calc(var(--text-2xl) + 0.5rem);
+ }
+
+ .cta-title {
+ font-size: var(--text-3xl);
+ }
+}
+
+/* Landscape mobile optimization */
+@media (max-width: 768px) and (orientation: landscape) {
+ .hero {
+ min-height: 70vh;
+ padding-top: 80px;
+ }
+
+ .hero-content {
+ gap: var(--space-6);
+ }
+
+ .hero-stats {
+ flex-direction: row;
+ justify-content: center;
+ gap: var(--space-6);
+ }
+}
+
+/* Performance optimizations for mobile */
+@media (max-width: 768px) {
+ /* Reduce animation complexity on mobile */
+ .hero-particles {
+ animation-duration: 30s;
+ }
+
+ /* Simplify transforms for better performance */
+ .service-card:hover,
+ .portfolio-item:hover,
+ .team-member:hover {
+ transform: translateY(-2px);
+ }
+
+ /* Reduce blur effects on mobile for performance */
+ .header {
+ backdrop-filter: blur(5px);
+ }
+
+ .modal-overlay {
+ backdrop-filter: blur(3px);
+ }
+}
+
+/* Scroll progress indicator */
+.scroll-progress {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 0%;
+ height: 3px;
+ background: linear-gradient(90deg, var(--primary-color) 0%, var(--secondary-color) 100%);
+ z-index: var(--z-tooltip);
+ transition: width 0.1s ease-out;
+}
+
/* Print Styles */
@media print {
.header,
.footer,
.back-to-top,
- .loading-spinner {
+ .loading-spinner,
+ .scroll-progress {
display: none !important;
}
diff --git a/assets/js/main.js b/assets/js/main.js
index 6db0016..d6a29d7 100644
--- a/assets/js/main.js
+++ b/assets/js/main.js
@@ -11,23 +11,26 @@ document.addEventListener('DOMContentLoaded', function() {
initializeAccessibility();
initializePortfolioFilter();
initializeContactForm();
+ initializeMobileEnhancements();
+ initializeScrollProgress();
});
-// Navigation functionality
+// Enhanced navigation functionality with mobile improvements
function initializeNavigation() {
const mobileMenuBtn = document.querySelector('.mobile-menu-btn');
const navbarMenu = document.querySelector('.navbar-menu');
const navLinks = document.querySelectorAll('.nav-link');
const header = document.querySelector('.header');
- // Mobile menu toggle
+ // Mobile menu toggle with improved animation
if (mobileMenuBtn && navbarMenu) {
mobileMenuBtn.addEventListener('click', function() {
const isExpanded = this.getAttribute('aria-expanded') === 'true';
this.setAttribute('aria-expanded', !isExpanded);
navbarMenu.classList.toggle('active');
+ document.body.classList.toggle('menu-open');
- // Animate hamburger lines
+ // Animate hamburger lines with improved timing
const lines = this.querySelectorAll('.hamburger-line');
lines.forEach((line, index) => {
if (navbarMenu.classList.contains('active')) {
@@ -40,34 +43,73 @@ function initializeNavigation() {
}
});
});
+
+ // Close menu when clicking outside
+ document.addEventListener('click', function(e) {
+ if (!mobileMenuBtn.contains(e.target) && !navbarMenu.contains(e.target)) {
+ if (navbarMenu.classList.contains('active')) {
+ closeMobileMenu();
+ }
+ }
+ });
+
+ // Close menu on escape key
+ document.addEventListener('keydown', function(e) {
+ if (e.key === 'Escape' && navbarMenu.classList.contains('active')) {
+ closeMobileMenu();
+ }
+ });
+ }
+
+ function closeMobileMenu() {
+ if (navbarMenu && mobileMenuBtn) {
+ navbarMenu.classList.remove('active');
+ document.body.classList.remove('menu-open');
+ mobileMenuBtn.setAttribute('aria-expanded', 'false');
+ const lines = mobileMenuBtn.querySelectorAll('.hamburger-line');
+ lines.forEach(line => {
+ line.style.transform = '';
+ line.style.opacity = '';
+ });
+ }
}
- // Close mobile menu when clicking nav links
+ // Enhanced mobile menu close on nav link click
navLinks.forEach(link => {
- link.addEventListener('click', () => {
- if (navbarMenu && navbarMenu.classList.contains('active')) {
- navbarMenu.classList.remove('active');
- if (mobileMenuBtn) {
- mobileMenuBtn.setAttribute('aria-expanded', 'false');
- const lines = mobileMenuBtn.querySelectorAll('.hamburger-line');
- lines.forEach(line => {
- line.style.transform = '';
- line.style.opacity = '';
+ link.addEventListener('click', (e) => {
+ closeMobileMenu();
+
+ // Smooth scroll for anchor links
+ if (link.getAttribute('href').startsWith('#')) {
+ e.preventDefault();
+ const target = document.querySelector(link.getAttribute('href'));
+ if (target) {
+ const headerHeight = header ? header.offsetHeight : 80;
+ const targetPosition = target.offsetTop - headerHeight;
+
+ window.scrollTo({
+ top: targetPosition,
+ behavior: 'smooth'
});
}
}
});
});
- // Header scroll effect
+ // Enhanced header scroll effect with better performance
if (header) {
let lastScrollY = window.scrollY;
+ let ticking = false;
- window.addEventListener('scroll', () => {
+ function updateHeader() {
const currentScrollY = window.scrollY;
if (currentScrollY > 100) {
- header.style.transform = currentScrollY > lastScrollY ? 'translateY(-100%)' : 'translateY(0)';
+ if (currentScrollY > lastScrollY) {
+ header.style.transform = 'translateY(-100%)';
+ } else {
+ header.style.transform = 'translateY(0)';
+ }
header.style.boxShadow = 'var(--shadow-lg)';
} else {
header.style.transform = 'translateY(0)';
@@ -75,10 +117,18 @@ function initializeNavigation() {
}
lastScrollY = currentScrollY;
+ ticking = false;
+ }
+
+ window.addEventListener('scroll', () => {
+ if (!ticking) {
+ requestAnimationFrame(updateHeader);
+ ticking = true;
+ }
});
}
- // Smooth scrolling for anchor links
+ // Enhanced smooth scrolling for anchor links
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', function(e) {
e.preventDefault();
@@ -1129,4 +1179,215 @@ window.CodeStormUtils = utils;
initializePerformanceMonitoring();
// Optional: Initialize service worker for PWA features
+
+// Mobile-specific enhancements
+function initializeMobileEnhancements() {
+ // Detect mobile device
+ const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
+ const isTouch = 'ontouchstart' in window || navigator.maxTouchPoints > 0;
+
+ if (isMobile || isTouch) {
+ document.body.classList.add('is-mobile');
+
+ // Enhanced touch interactions for portfolio items
+ const portfolioItems = document.querySelectorAll('.portfolio-item, .portfolio-project');
+ portfolioItems.forEach(item => {
+ let touchStartY = 0;
+ let touchEndY = 0;
+
+ item.addEventListener('touchstart', (e) => {
+ touchStartY = e.touches[0].clientY;
+ item.classList.add('touch-active');
+ });
+
+ item.addEventListener('touchend', (e) => {
+ touchEndY = e.changedTouches[0].clientY;
+ item.classList.remove('touch-active');
+
+ // Handle tap to show overlay on mobile
+ const overlay = item.querySelector('.portfolio-overlay, .project-overlay');
+ if (overlay && Math.abs(touchStartY - touchEndY) < 10) {
+ overlay.style.opacity = overlay.style.opacity === '1' ? '0' : '1';
+ setTimeout(() => {
+ overlay.style.opacity = '';
+ }, 3000);
+ }
+ });
+ });
+
+ // Improve touch scrolling for testimonials
+ const testimonialSlider = document.querySelector('.testimonials-slider');
+ if (testimonialSlider) {
+ testimonialSlider.style.webkitOverflowScrolling = 'touch';
+ }
+
+ // Prevent zoom on form inputs (iOS Safari)
+ const formInputs = document.querySelectorAll('input, select, textarea');
+ formInputs.forEach(input => {
+ if (input.style.fontSize === '' || parseFloat(input.style.fontSize) < 16) {
+ input.style.fontSize = '16px';
+ }
+ });
+
+ // Add visual feedback for touch interactions
+ const touchableElements = document.querySelectorAll('.btn, .nav-link, .service-card, .team-member');
+ touchableElements.forEach(element => {
+ element.addEventListener('touchstart', () => {
+ element.style.opacity = '0.8';
+ });
+
+ element.addEventListener('touchend', () => {
+ setTimeout(() => {
+ element.style.opacity = '';
+ }, 150);
+ });
+ });
+
+ // Optimize animations for mobile performance
+ const animatedElements = document.querySelectorAll('[data-aos]');
+ animatedElements.forEach(element => {
+ element.style.willChange = 'transform, opacity';
+ });
+
+ // Reduce motion for users who prefer it
+ if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
+ const style = document.createElement('style');
+ style.textContent = `
+ *, *::before, *::after {
+ animation-duration: 0.01ms !important;
+ animation-iteration-count: 1 !important;
+ transition-duration: 0.01ms !important;
+ }
+ `;
+ document.head.appendChild(style);
+ }
+ }
+
+ // Enhanced keyboard navigation for desktop
+ if (!isMobile) {
+ // Add keyboard shortcuts
+ document.addEventListener('keydown', (e) => {
+ // Alt + M to toggle mobile menu (useful for testing)
+ if (e.altKey && e.key === 'm') {
+ const mobileMenuBtn = document.querySelector('.mobile-menu-btn');
+ if (mobileMenuBtn) {
+ mobileMenuBtn.click();
+ }
+ }
+
+ // Alt + T to toggle theme
+ if (e.altKey && e.key === 't') {
+ const themeToggle = document.querySelector('.theme-toggle');
+ if (themeToggle) {
+ themeToggle.click();
+ }
+ }
+ });
+ }
+
+ // Handle orientation changes on mobile
+ window.addEventListener('orientationchange', () => {
+ setTimeout(() => {
+ // Recalculate hero height
+ const hero = document.querySelector('.hero');
+ if (hero) {
+ hero.style.minHeight = `${window.innerHeight}px`;
+ }
+
+ // Close mobile menu on orientation change
+ const navbarMenu = document.querySelector('.navbar-menu');
+ const mobileMenuBtn = document.querySelector('.mobile-menu-btn');
+ if (navbarMenu && navbarMenu.classList.contains('active')) {
+ navbarMenu.classList.remove('active');
+ mobileMenuBtn.setAttribute('aria-expanded', 'false');
+ }
+ }, 100);
+ });
+
+ // Prevent iOS bounce scrolling
+ if (/iPad|iPhone|iPod/.test(navigator.userAgent)) {
+ document.addEventListener('touchmove', (e) => {
+ if (e.scale && e.scale !== 1) {
+ e.preventDefault();
+ }
+ }, { passive: false });
+ }
+}
+
+// Scroll progress indicator
+function initializeScrollProgress() {
+ const progressBar = document.createElement('div');
+ progressBar.className = 'scroll-progress';
+ document.body.appendChild(progressBar);
+
+ let ticking = false;
+
+ function updateScrollProgress() {
+ const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
+ const scrollHeight = document.documentElement.scrollHeight - window.innerHeight;
+ const scrollPercent = (scrollTop / scrollHeight) * 100;
+
+ progressBar.style.width = `${Math.min(scrollPercent, 100)}%`;
+ ticking = false;
+ }
+
+ window.addEventListener('scroll', () => {
+ if (!ticking) {
+ requestAnimationFrame(updateScrollProgress);
+ ticking = true;
+ }
+ });
+
+ // Show/hide progress bar based on scroll position
+ window.addEventListener('scroll', utils.throttle(() => {
+ const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
+ if (scrollTop > 300) {
+ progressBar.style.opacity = '1';
+ } else {
+ progressBar.style.opacity = '0';
+ }
+ }, 100));
+}
+
+// Add breadcrumb navigation for better UX
+function initializeBreadcrumbs() {
+ const breadcrumbContainer = document.querySelector('.breadcrumb');
+ if (!breadcrumbContainer) return;
+
+ const currentPath = window.location.pathname;
+ const pathSegments = currentPath.split('/').filter(segment => segment);
+
+ let breadcrumbHTML = '
Home';
+ let currentPath_build = '';
+
+ pathSegments.forEach((segment, index) => {
+ currentPath_build += '/' + segment;
+ const isLast = index === pathSegments.length - 1;
+ const segmentName = segment.charAt(0).toUpperCase() + segment.slice(1);
+
+ if (isLast) {
+ breadcrumbHTML += `
/ ${segmentName}`;
+ } else {
+ breadcrumbHTML += `
/ ${segmentName}`;
+ }
+ });
+
+ breadcrumbContainer.innerHTML = breadcrumbHTML;
+}
+
+// Enhanced error handling
+window.addEventListener('error', (e) => {
+ console.error('JavaScript error:', e.error);
+
+ // In production, you might want to send errors to a logging service
+ if (window.location.hostname !== 'localhost') {
+ // Example: Send to error tracking service
+ // sendErrorToTracking(e.error);
+ }
+});
+
+// Initialize breadcrumbs if container exists
+document.addEventListener('DOMContentLoaded', () => {
+ initializeBreadcrumbs();
+});
// initializeServiceWorker();
\ No newline at end of file
diff --git a/index.html b/index.html
index 6093273..58a1553 100644
--- a/index.html
+++ b/index.html
@@ -144,8 +144,8 @@
Featured Projects
E-commerce Platform
Web Development