diff --git a/404.html b/404.html index de5481d..73c1cbc 100644 --- a/404.html +++ b/404.html @@ -46,5 +46,6 @@

+ diff --git a/about.html b/about.html index cdb7529..be1e065 100644 --- a/about.html +++ b/about.html @@ -195,5 +195,6 @@

Contact Us

+ diff --git a/css/style.css b/css/style.css index 832a43c..d875bbc 100644 --- a/css/style.css +++ b/css/style.css @@ -3508,7 +3508,334 @@ body.dark .hero-content p { } } +/* ===== COMPREHENSIVE ACCESSIBILITY & MOBILE RESPONSIVE NAV ===== */ + +/* Skip link styling */ +.skip-link { + position: absolute; + top: -60px; + left: 10px; + background: #bf360c; + color: white; + padding: 10px 20px; + z-index: 10000; + transition: top 0.2s ease; + font-weight: 700; + text-decoration: none; + border-radius: 0 0 8px 8px; + box-shadow: 0 4px 10px rgba(0, 0, 0, 0.25); +} + +.skip-link:focus { + top: 0; + outline: 3px solid white; + outline-offset: -3px; +} + +/* Scroll lock when mobile drawer is open */ +body.nav-menu-open { + overflow: hidden; +} + +/* Hamburger toggle button */ +.mobile-nav-toggle { + display: none; + background: transparent; + border: none; + cursor: pointer; + padding: 0.5rem; + z-index: 1200; + flex-direction: column; + justify-content: space-between; + width: 32px; + height: 24px; +} + +.mobile-nav-toggle .hamburger-bar { + display: block; + width: 100%; + height: 3px; + background-color: white; + border-radius: 2px; + transition: transform 0.3s ease, opacity 0.3s ease; +} + +/* High-Contrast & Premium Glowing Focus Outlines */ +button:focus-visible, +a:focus-visible, +input:focus-visible, +textarea:focus-visible, +select:focus-visible { + outline: 3px solid #ff5722 !important; + outline-offset: 2px !important; + box-shadow: 0 0 12px rgba(255, 87, 34, 0.6) !important; + border-radius: 4px; +} + +header button:focus-visible, +header a:focus-visible, +header input:focus-visible { + outline: 3px solid #ffffff !important; + outline-offset: 2px !important; + box-shadow: 0 0 12px rgba(255, 255, 255, 0.6) !important; +} + +body.keyboard-nav button:focus, +body.keyboard-nav a:focus, +body.keyboard-nav input:focus, +body.keyboard-nav textarea:focus, +body.keyboard-nav select:focus { + outline: 3px solid #ff5722 !important; + outline-offset: 2px !important; + box-shadow: 0 0 12px rgba(255, 87, 34, 0.6) !important; +} + +body.keyboard-nav header button:focus, +body.keyboard-nav header a:focus, +body.keyboard-nav header input:focus { + outline: 3px solid #ffffff !important; + outline-offset: 2px !important; + box-shadow: 0 0 12px rgba(255, 255, 255, 0.6) !important; +} + +/* Card & Interactive Element Keyboard Focus Indicator Refinements */ +.card:focus-visible, +.team-member:focus-visible, +.testimonial:focus-visible { + outline: 3px solid #ff5722 !important; + outline-offset: 4px !important; + box-shadow: 0 0 15px rgba(255, 87, 34, 0.5) !important; +} + +/* Visual validation error states */ +input.input-error, +textarea.input-error { + border-color: #c0392b !important; + box-shadow: 0 0 10px rgba(192, 57, 43, 0.25) !important; +} + +input.input-error:focus, +textarea.input-error:focus { + border-color: #c0392b !important; + box-shadow: 0 0 12px rgba(192, 57, 43, 0.4) !important; + outline: none !important; +} + +/* Mobile responsive navigation styles */ +@media (max-width: 1024px) { + .mobile-nav-toggle { + display: flex; + } + + .header-inner { + padding: 0.8rem 1.5rem !important; + display: flex !important; + flex-direction: row !important; + justify-content: space-between !important; + align-items: center !important; + width: 100% !important; + gap: 0 !important; + } + + .logo { + margin-right: 0 !important; + font-size: 1.6rem !important; + } + + nav { + position: fixed; + top: 0; + right: -100%; + width: 290px; + height: 100vh; + background: #ff5722; + box-shadow: -8px 0 25px rgba(0, 0, 0, 0.15); + flex-direction: column; + align-items: flex-start !important; + justify-content: flex-start !important; + padding: 5.5rem 1.8rem 2rem !important; + gap: 1.2rem !important; + transition: right 0.4s cubic-bezier(0.16, 1, 0.3, 1); + z-index: 1100; + overflow-y: auto; + } + + nav.nav-open { + right: 0; + } + + nav a { + width: 100%; + padding: 0.75rem 1rem !important; + font-size: 1.05rem; + border-radius: 8px; + display: block; + text-align: left; + background: rgba(255, 255, 255, 0.05); + transition: background 0.2s ease; + box-shadow: none !important; + } + + nav a:hover, + nav a.active { + background: #e64a19 !important; + } + + /* Cart button inline layout inside drawer */ + .cart-btn-modern { + width: 100% !important; + justify-content: flex-start !important; + padding: 0.75rem 1rem !important; + background: rgba(255, 255, 255, 0.1) !important; + border-radius: 8px !important; + } + + /* Mobile search bar alignment */ + .search-bar { + margin-left: 0 !important; + width: 100% !important; + display: flex !important; + justify-content: flex-start !important; + margin-top: 0.5rem !important; + } + + .search-bar input { + width: 100% !important; + max-width: none !important; + } + + .theme-toggle { + margin-left: 0 !important; + margin-top: 0.5rem; + align-self: flex-start; + } + + .auth-nav-item { + width: 100%; + margin-left: 0 !important; + margin-top: 0.5rem; + } + + .login-btn-nav { + display: block !important; + text-align: center !important; + width: 100%; + } + + /* Dropdown accordions */ + .dropdown { + width: 100%; + } + + .dropdown-menu { + position: static !important; + opacity: 1 !important; + visibility: visible !important; + transform: none !important; + box-shadow: none !important; + padding-left: 1rem !important; + padding-top: 0.5rem !important; + display: none; + background: transparent !important; + border-radius: 0 !important; + border-left: 2px solid rgba(255, 255, 255, 0.2); + } + + .dropdown.open .dropdown-menu { + display: block !important; + } + + .dropdown-toggle::after { + margin-left: auto; + transition: transform 0.3s ease; + } + + .dropdown.open .dropdown-toggle::after { + transform: rotate(180deg); + } + + /* Hamburger transition to cross button */ + .mobile-nav-toggle[aria-expanded="true"] .hamburger-bar:nth-child(1) { + transform: translateY(10.5px) rotate(45deg); + } + + .mobile-nav-toggle[aria-expanded="true"] .hamburger-bar:nth-child(2) { + opacity: 0; + } + + .mobile-nav-toggle[aria-expanded="true"] .hamburger-bar:nth-child(3) { + transform: translateY(-10.5px) rotate(-45deg); + } +} + +/* Spacing and Responsive Layout Polish */ +@media (max-width: 768px) { + /* About Page Section Polish */ + .about-page { + padding-top: 3.5rem !important; + padding-bottom: 4rem !important; + } + + .about-desc-large { + font-size: 1.05rem !important; + margin-bottom: 2.5rem !important; + line-height: 1.7 !important; + } + + /* Testimonials layout adjustments */ + section.testimonials { + padding: 3.5rem 1rem 5rem !important; + } + + .testimonial { + max-width: 100% !important; + margin-bottom: 1rem; + } + + .testimonial-cards { + gap: 1.5rem !important; + } + + /* Team members layout */ + .team { + gap: 1.5rem !important; + } + + .team-member { + max-width: 100% !important; + height: 320px !important; + } + + /* Increase tap target sizes for filter and social icons on mobile */ + .filter-btn { + padding: 0.8rem 2rem !important; + } + + .footer-social-icons a { + width: 44px !important; + height: 44px !important; + font-size: 1.25rem !important; + } + + footer .social-icons a { + display: inline-flex !important; + min-width: 44px !important; + min-height: 44px !important; + align-items: center !important; + justify-content: center !important; + } +} + +/* Reduced Motion preferences */ @media (prefers-reduced-motion: reduce) { + * { + animation-delay: 0s !important; + animation-duration: 0s !important; + animation-iteration-count: 1 !important; + transition-duration: 0s !important; + scroll-behavior: auto !important; + } + .hero-bg-video, .hero-badge, .hero-content h1, @@ -3519,5 +3846,35 @@ body.dark .hero-content p { animation: none !important; transition: none !important; } + + .card:hover { + animation: none !important; + transform: translateY(-4px) !important; + } + + .card img { + transition: none !important; + transform: none !important; + } + + .filter-btn.active { + animation: none !important; + } + + .skeleton { + animation: none !important; + background: #f0e0d0 !important; + } + + .cart-item { + animation: none !important; + } + + .floating-food { + animation: none !important; + display: none !important; + } } + + diff --git a/dashboard.html b/dashboard.html index dbb5b04..db6db5f 100644 --- a/dashboard.html +++ b/dashboard.html @@ -70,5 +70,6 @@

Dashboard - Coming Soon

+ diff --git a/faq.html b/faq.html index 6477932..499fabd 100644 --- a/faq.html +++ b/faq.html @@ -475,6 +475,7 @@

Contact Us

+ + \ No newline at end of file diff --git a/index.html b/index.html index 08cc12c..a85b46d 100644 --- a/index.html +++ b/index.html @@ -952,6 +952,7 @@

+ diff --git a/js/accessibility.js b/js/accessibility.js index c523d6a..687f287 100644 --- a/js/accessibility.js +++ b/js/accessibility.js @@ -1,8 +1,20 @@ -// ===== Accessibility Enhancements ===== -// Screen reader support, keyboard navigation, and ARIA improvements +// ===== Accessibility & Responsive Navigation Enhancements ===== +// Screen reader support, keyboard navigation, dynamic mobile navigation, validation feedback, and ARIA improvements // Setup skip links for keyboard navigation function setupSkipLinks() { + let mainContent = document.getElementById('main-content') || document.querySelector('main') || document.querySelector('section'); + if (mainContent) { + if (!mainContent.id) { + mainContent.id = 'main-content'; + } + mainContent.setAttribute('tabindex', '-1'); + mainContent.style.outline = 'none'; + } + + // Check if skip link already exists + if (document.querySelector('.skip-link')) return; + const skipLink = document.createElement('a'); skipLink.href = '#main-content'; skipLink.className = 'skip-link'; @@ -10,7 +22,120 @@ function setupSkipLinks() { document.body.insertBefore(skipLink, document.body.firstChild); } -// Enhance dropdown keyboard navigation +// Setup mobile hamburger navigation and accessibility controls +function setupMobileNavigation() { + const headerInner = document.querySelector('.header-inner'); + const nav = document.querySelector('nav'); + if (!headerInner || !nav) return; + + if (document.getElementById('mobile-nav-toggle')) return; + + const toggleBtn = document.createElement('button'); + toggleBtn.id = 'mobile-nav-toggle'; + toggleBtn.className = 'mobile-nav-toggle'; + toggleBtn.setAttribute('aria-label', 'Open navigation menu'); + toggleBtn.setAttribute('aria-expanded', 'false'); + toggleBtn.setAttribute('aria-controls', 'primary-navigation'); + + toggleBtn.innerHTML = ` + + + + `; + + if (!nav.id) { + nav.id = 'primary-navigation'; + } + + headerInner.insertBefore(toggleBtn, nav); + + toggleBtn.addEventListener('click', () => { + const isExpanded = toggleBtn.getAttribute('aria-expanded') === 'true'; + const nextState = !isExpanded; + toggleBtn.setAttribute('aria-expanded', String(nextState)); + toggleBtn.setAttribute('aria-label', nextState ? 'Close navigation menu' : 'Open navigation menu'); + nav.classList.toggle('nav-open', nextState); + document.body.classList.toggle('nav-menu-open', nextState); + + if (nextState) { + const firstLink = nav.querySelector('a'); + if (firstLink) setTimeout(() => firstLink.focus(), 100); + } else { + toggleBtn.focus(); + } + }); + + const navLinks = nav.querySelectorAll('a:not(.dropdown-toggle)'); + navLinks.forEach(link => { + link.addEventListener('click', () => { + toggleBtn.setAttribute('aria-expanded', 'false'); + toggleBtn.setAttribute('aria-label', 'Open navigation menu'); + nav.classList.remove('nav-open'); + document.body.classList.remove('nav-menu-open'); + }); + }); + + // Dropdown accordions for mobile menu + const dropdowns = nav.querySelectorAll('.dropdown'); + dropdowns.forEach(dropdown => { + const toggle = dropdown.querySelector('.dropdown-toggle'); + if (!toggle) return; + + toggle.addEventListener('click', (e) => { + if (window.innerWidth <= 1024) { + e.preventDefault(); + e.stopPropagation(); + const isOpen = dropdown.classList.contains('open'); + + dropdowns.forEach(d => { + if (d !== dropdown) { + d.classList.remove('open'); + const dToggle = d.querySelector('.dropdown-toggle'); + if (dToggle) dToggle.setAttribute('aria-expanded', 'false'); + } + }); + + dropdown.classList.toggle('open', !isOpen); + toggle.setAttribute('aria-expanded', String(!isOpen)); + } + }); + }); + + // Trap focus and close drawer on Escape + nav.addEventListener('keydown', (e) => { + if (!nav.classList.contains('nav-open')) return; + + if (e.key === 'Escape') { + e.preventDefault(); + toggleBtn.setAttribute('aria-expanded', 'false'); + toggleBtn.setAttribute('aria-label', 'Open navigation menu'); + nav.classList.remove('nav-open'); + document.body.classList.remove('nav-menu-open'); + toggleBtn.focus(); + } + + if (e.key === 'Tab') { + const focusable = nav.querySelectorAll('a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), [tabindex="0"]'); + if (focusable.length === 0) return; + const first = focusable[0]; + const last = focusable[focusable.length - 1]; + + if (e.shiftKey) { + if (document.activeElement === first) { + last.focus(); + e.preventDefault(); + } + } else { + if (document.activeElement === last) { + first.focus(); + e.preventDefault(); + } + } + } + }); +} + +// Enhance dropdown keyboard navigation for desktop function setupDropdownKeyboardNav() { const dropdowns = document.querySelectorAll('.dropdown'); @@ -86,6 +211,7 @@ function setupSearchKeyboardNav() { e.preventDefault(); selectedIndex = Math.min(selectedIndex + 1, items.length - 1); if (selectedIndex >= 0) { + items.forEach(el => el.classList.remove('focused')); items[selectedIndex].classList.add('focused'); items[selectedIndex].scrollIntoView({ block: 'nearest' }); } @@ -102,8 +228,8 @@ function setupSearchKeyboardNav() { searchInput.focus(); } } else if (e.key === 'Enter') { - e.preventDefault(); if (selectedIndex >= 0) { + e.preventDefault(); items[selectedIndex].click(); } } else if (e.key === 'Escape') { @@ -113,7 +239,6 @@ function setupSearchKeyboardNav() { } }); - const originalShowSuggestions = searchInput._showSuggestions; searchInput.addEventListener('input', () => { selectedIndex = -1; }); @@ -136,20 +261,163 @@ function setupCardKeyboardNav() { }); } +// Field validation helper for ARIA updates +function validateField(input, errorMsg) { + let isValid = true; + let message = ''; + const value = input.value.trim(); + + if (input.required && !value) { + isValid = false; + message = `${input.previousElementSibling ? input.previousElementSibling.textContent.trim() : 'Field'} is required.`; + } else if (input.type === 'email' && value) { + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + if (!emailRegex.test(value)) { + isValid = false; + message = 'Please enter a valid email address.'; + } + } else if (input.tagName === 'TEXTAREA' && value && value.length < 10) { + isValid = false; + message = 'Message must be at least 10 characters.'; + } + + if (!isValid) { + input.setAttribute('aria-invalid', 'true'); + input.classList.add('input-error'); + if (errorMsg) { + errorMsg.textContent = message; + errorMsg.style.display = 'block'; + } + } else { + input.setAttribute('aria-invalid', 'false'); + input.classList.remove('input-error'); + if (errorMsg) { + errorMsg.textContent = ''; + } + } + + return isValid; +} + +// Auth fields validation validation +function validateAuthField(input, errorMsg) { + let isValid = true; + let message = ''; + const value = input.value.trim(); + + if (input.required && !value) { + isValid = false; + message = 'This field is required.'; + } else if (input.type === 'email' && value) { + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + if (!emailRegex.test(value)) { + isValid = false; + message = 'Please enter a valid email address.'; + } + } else if (input.type === 'password' && value && value.length < 6) { + isValid = false; + message = 'Password must be at least 6 characters.'; + } else if (input.type === 'tel' && value && !/^\d{10}$/.test(value)) { + isValid = false; + message = 'Please enter a valid 10-digit phone number.'; + } + + if (!isValid) { + input.setAttribute('aria-invalid', 'true'); + input.classList.add('input-error'); + if (errorMsg) { + errorMsg.textContent = message; + } + } else { + input.setAttribute('aria-invalid', 'false'); + input.classList.remove('input-error'); + if (errorMsg) { + errorMsg.textContent = ''; + } + } + return isValid; +} + // Enhance form accessibility with proper labels and error associations function setupFormAccessibility() { const contactForm = document.getElementById('contact-form'); const newsLetterForm = document.getElementById('newsletter-form'); + const loginForm = document.getElementById('login-form'); + const signupForm = document.getElementById('signup-form'); if (contactForm) { const inputs = contactForm.querySelectorAll('input, textarea'); inputs.forEach(input => { - const label = contactForm.querySelector(`label[for="${input.id}"]`); const errorMsg = contactForm.querySelector(`#error-${input.id}`); - if (errorMsg) { input.setAttribute('aria-describedby', `error-${input.id}`); } + + input.addEventListener('blur', () => { + validateField(input, errorMsg); + }); + + input.addEventListener('input', () => { + input.removeAttribute('aria-invalid'); + input.classList.remove('input-error'); + if (errorMsg) errorMsg.textContent = ''; + }); + }); + + contactForm.addEventListener('submit', (e) => { + let isFormValid = true; + inputs.forEach(input => { + const errorMsg = contactForm.querySelector(`#error-${input.id}`); + const isValid = validateField(input, errorMsg); + if (!isValid) isFormValid = false; + }); + + if (!isFormValid) { + e.preventDefault(); + e.stopPropagation(); + const firstInvalid = contactForm.querySelector('[aria-invalid="true"]'); + if (firstInvalid) firstInvalid.focus(); + } + }); + } + + if (loginForm) { + const inputs = loginForm.querySelectorAll('input'); + inputs.forEach(input => { + const errorMsg = loginForm.querySelector(`#${input.id}-error`); + if (errorMsg) { + input.setAttribute('aria-describedby', `${input.id}-error`); + } + + input.addEventListener('input', () => { + input.removeAttribute('aria-invalid'); + input.classList.remove('input-error'); + if (errorMsg) errorMsg.textContent = ''; + }); + + input.addEventListener('blur', () => { + validateAuthField(input, errorMsg); + }); + }); + } + + if (signupForm) { + const inputs = signupForm.querySelectorAll('input'); + inputs.forEach(input => { + const errorMsg = signupForm.querySelector(`#${input.id}-error`); + if (errorMsg) { + input.setAttribute('aria-describedby', `${input.id}-error`); + } + + input.addEventListener('input', () => { + input.removeAttribute('aria-invalid'); + input.classList.remove('input-error'); + if (errorMsg) errorMsg.textContent = ''; + }); + + input.addEventListener('blur', () => { + validateAuthField(input, errorMsg); + }); }); } @@ -175,21 +443,53 @@ function setupFilterButtonAccessibility() { }); } -// Setup cart sidebar keyboard accessibility +// Setup cart sidebar keyboard accessibility and focus trapping function setupCartSidebarKeyboardNav() { const cartSidebar = document.getElementById('cart-sidebar'); const cartCloseBtn = document.getElementById('cart-close'); if (!cartSidebar) return; - // Trap focus within sidebar when open cartSidebar.addEventListener('keydown', (e) => { if (e.key === 'Escape') { e.preventDefault(); cartSidebar.setAttribute('aria-hidden', 'true'); cartSidebar.classList.remove('open'); + const cartOpenBtn = document.getElementById('cart-open-btn'); + if (cartOpenBtn) cartOpenBtn.focus(); } + + if (e.key === 'Tab') { + const focusable = cartSidebar.querySelectorAll('a[href], button:not([disabled]), input:not([disabled]), textarea:not([disabled]), select:not([disabled]), [tabindex="0"]'); + if (focusable.length === 0) return; + const first = focusable[0]; + const last = focusable[focusable.length - 1]; + + if (e.shiftKey) { + if (document.activeElement === first) { + last.focus(); + e.preventDefault(); + } + } else { + if (document.activeElement === last) { + first.focus(); + e.preventDefault(); + } + } + } + }); + + const observer = new MutationObserver((mutations) => { + mutations.forEach((mutation) => { + if (mutation.attributeName === 'class') { + const isOpen = cartSidebar.classList.contains('open'); + if (isOpen && cartCloseBtn) { + setTimeout(() => cartCloseBtn.focus(), 50); + } + } + }); }); + observer.observe(cartSidebar, { attributes: true }); } // Enhance checkbox and radio accessibility @@ -244,6 +544,7 @@ function setupFocusVisibility() { // Initialize all accessibility enhancements function initializeAccessibility() { setupSkipLinks(); + setupMobileNavigation(); setupDropdownKeyboardNav(); setupSearchKeyboardNav(); setupCardKeyboardNav(); diff --git a/login.html b/login.html index 5b71d66..a8614e7 100644 --- a/login.html +++ b/login.html @@ -83,5 +83,6 @@

Welcome Back

+ diff --git a/menu.html b/menu.html index 94d9f3d..fb1c5dd 100644 --- a/menu.html +++ b/menu.html @@ -216,5 +216,6 @@

Contact Us

+ diff --git a/orders.html b/orders.html index 932d146..dd35b25 100644 --- a/orders.html +++ b/orders.html @@ -407,18 +407,11 @@

Have a promo cod - - - - - - - - + + diff --git a/recommendations.html b/recommendations.html index 2a0b0dd..c2206e2 100644 --- a/recommendations.html +++ b/recommendations.html @@ -336,6 +336,7 @@

+ +