===ENDFILE=== ===FILE: styles.css=== /* ========================================================================== CSS Custom Properties & Design Tokens Aesthetic: Dark Glassmorphism | Card Style: Border Accent Spacing Scale: 4px, 8px, 16px, 24px, 40px, 64px ========================================================================== */ :root { --bg-main: #0b0f17; --bg-surface: rgba(19, 26, 38, 0.7); --bg-surface-elevated: rgba(26, 36, 52, 0.75); --bg-panel: rgba(15, 21, 32, 0.85); --border-subtle: rgba(255, 255, 255, 0.08); --border-neon-cyan: #00f0ff; --border-neon-magenta: #ff007a; --border-neon-violet: #9d4edd; --border-neon-amber: #ffaa00; --text-main: #e2e8f0; --text-muted: #94a3b8; --text-inverse: #0b0f17; --text-accent: #00f0ff; --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif; --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; --radius-sm: 4px; --radius-md: 8px; --radius-lg: 12px; --shadow-glass: 0 8px 32px 0 rgba(0, 0, 0, 0.45); --shadow-neon: 0 0 15px rgba(0, 240, 255, 0.25); --header-height: 64px; --header-height-mobile: 52px; } /* Base Reset & Box Sizing */ *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } html { font-size: 16px; background-color: var(--bg-main); color: var(--text-main); font-family: var(--font-sans); line-height: 1.6; scroll-behavior: smooth; -webkit-text-size-adjust: 100%; } body { background-color: var(--bg-main); color: var(--text-main); min-height: 100vh; display: flex; flex-direction: column; background-image: radial-gradient(at 10% 10%, rgba(0, 240, 255, 0.06) 0px, transparent 50%), radial-gradient(at 90% 90%, rgba(255, 0, 122, 0.05) 0px, transparent 50%); background-attachment: fixed; } /* Ensure flex/grid children can shrink below min content */ main, section, article, div, header, footer, nav, aside { min-width: 0; } h1, h2, h3, h4, h5, h6, .brand-name, .nav-link { overflow-wrap: anywhere; color: #ffffff; font-weight: 700; line-height: 1.25; } p, li, address { overflow-wrap: anywhere; } a { color: var(--text-accent); text-decoration: underline; text-underline-offset: 3px; transition: color 0.15s ease, opacity 0.15s ease; } a:hover { color: #67e8f9; } img { max-width: 100%; height: auto; display: block; } /* Accessibility Focus States */ :focus-visible { outline: 2px solid var(--border-neon-cyan); outline-offset: 3px; } /* Container */ .site-container { width: 100%; max-width: 1160px; margin-left: auto; margin-right: auto; padding-left: 16px; padding-right: 16px; } /* ========================================================================== Global Header (Non-sticky, 56-64px desktop, 48-52px mobile) ========================================================================== */ .site-header { height: var(--header-height); background-color: rgba(11, 15, 23, 0.85); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); border-bottom: 1px solid var(--border-subtle); position: relative; z-index: 1000; display: flex; align-items: center; } .header-inner { width: 100%; max-width: 1160px; margin-left: auto; margin-right: auto; padding-left: 16px; padding-right: 16px; display: flex; align-items: center; justify-content: space-between; gap: 16px; } .brand-logo { display: flex; align-items: center; gap: 8px; text-decoration: none; flex-shrink: 0; } .brand-icon { flex-shrink: 0; } .brand-name { font-size: 1.125rem; font-weight: 800; letter-spacing: -0.02em; color: #ffffff; } /* Navigation Desktop */ .nav-menu { display: flex; align-items: center; } .nav-list { display: flex; align-items: center; gap: 24px; list-style: none; } .nav-link { color: var(--text-muted); text-decoration: none; font-size: 0.9375rem; font-weight: 500; padding: 6px 0; transition: color 0.2s ease; } .nav-link:hover, .nav-link.is-active { color: var(--border-neon-cyan); } .header-cta-slot { flex-shrink: 0; } /* Hamburger Toggle Button */ .nav-toggle { display: none; flex-direction: column; justify-content: center; gap: 5px; width: 40px; height: 40px; background: transparent; border: 1px solid var(--border-subtle); border-radius: var(--radius-sm); cursor: pointer; padding: 8px; color: #ffffff; } .hamburger-bar { display: block; width: 100%; height: 2px; background-color: #ffffff; transition: transform 0.2s ease, opacity 0.2s ease; } /* ========================================================================== Buttons & Tags ========================================================================== */ .btn { display: inline-flex; align-items: center; justify-content: center; font-weight: 600; border-radius: var(--radius-sm); text-decoration: none; cursor: pointer; transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease; padding: 10px 20px; font-size: 0.9375rem; border: 1px solid transparent; } .btn-sm { padding: 6px 14px; font-size: 0.8125rem; } .btn-block { width: 100%; } .btn-accent { background-color: var(--border-neon-cyan); color: var(--text-inverse); border-color: var(--border-neon-cyan); } .btn-accent:hover { background-color: #38f4ff; color: #000000; box-shadow: var(--shadow-neon); } .btn-secondary { background-color: rgba(255, 255, 255, 0.08); color: #ffffff; border-color: rgba(255, 255, 255, 0.15); } .btn-secondary:hover { background-color: rgba(255, 255, 255, 0.15); color: #ffffff; } .btn-outline { background-color: transparent; color: var(--text-muted); border-color: var(--border-subtle); } .btn-outline:hover { color: #ffffff; border-color: rgba(255, 255, 255, 0.3); } .badge-tag { display: inline-block; font-size: 0.75rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em; color: var(--border-neon-cyan); background-color: rgba(0, 240, 255, 0.1); padding: 4px 10px; border-radius: var(--radius-sm); border: 1px solid rgba(0, 240, 255, 0.25); margin-bottom: 16px; } /* ========================================================================== Layout Sections & Glass Panels ========================================================================== */ .section-padding { padding-top: 64px; padding-bottom: 64px; } .section-header { margin-bottom: 40px; } .section-title { font-size: 2rem; margin-bottom: 8px; } .section-subtitle { color: var(--text-muted); font-size: 1.0625rem; max-width: 680px; } .glass-panel { background-color: var(--bg-surface); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); border: 1px solid var(--border-subtle); border-radius: var(--radius-md); padding: 24px; box-shadow: var(--shadow-glass); } /* ========================================================================== Hero Section ========================================================================== */ .hero-section { padding-top: 64px; padding-bottom: 40px; } .hero-card { background-color: var(--bg-surface); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); border: 1px solid var(--border-subtle); border-radius: var(--radius-lg); padding: 40px 32px; box-shadow: var(--shadow-glass); } .hero-title { font-size: clamp(1.875rem, 4vw, 2.75rem); font-weight: 800; letter-spacing: -0.03em; margin-bottom: 16px; } .hero-lead { font-size: 1.125rem; color: var(--text-muted); max-width: 780px; margin-bottom: 40px; line-height: 1.65; } .hero-meta-row { display: flex; flex-wrap: wrap; gap: 32px; padding-top: 24px; border-top: 1px solid var(--border-subtle); } .stat-unit { display: flex; flex-direction: column; } .stat-value { font-size: 1.75rem; font-weight: 800; color: var(--border-neon-cyan); line-height: 1; margin-bottom: 12px; /* Enforces 12px between stat and label rule */ } .stat-label { font-size: 0.8125rem; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.05em; } /* ========================================================================== Card Style: Border Accent (Consistent Across Catalogue) No border except a top accent bar. Frosted dark glass body. Minimum 24px between distinct elements inside a card. ========================================================================== */ .card-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 24px; } .accent-card { background-color: var(--bg-surface); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); border: none; border-radius: 0 0 var(--radius-md) var(--radius-md); position: relative; display: flex; flex-direction: column; box-shadow: var(--shadow-glass); transition: transform 0.2s ease, box-shadow 0.2s ease; } .accent-card::before { content: ""; position: absolute; top: 0; left: 0; right: 0; height: 4px; border-radius: var(--radius-sm) var(--radius-sm) 0 0; } .accent-card.accent-cyan::before { background-color: var(--border-neon-cyan); } .accent-card.accent-magenta::before { background-color: var(--border-neon-magenta); } .accent-card.accent-violet::before { background-color: var(--border-neon-violet); } .accent-card.accent-amber::before { background-color: var(--border-neon-amber); } .card-content { padding: 24px; display: flex; flex-direction: column; flex-grow: 1; } .card-tag { font-size: 0.75rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em; color: var(--text-muted); margin-bottom: 24px; /* Min 24px between distinct card elements */ } .card-title { font-size: 1.25rem; margin-bottom: 24px; line-height: 1.35; } .card-summary { color: var(--text-muted); font-size: 0.9375rem; line-height: 1.6; margin-bottom: 24px; flex-grow: 1; } .card-meta { display: flex; flex-wrap: wrap; gap: 12px; font-size: 0.8125rem; color: #cbd5e1; background-color: rgba(0, 0, 0, 0.2); padding: 12px 16px; border-radius: var(--radius-sm); margin-bottom: 24px; } .meta-item { font-family: var(--font-mono); } .card-action { font-weight: 600; font-size: 0.9375rem; color: var(--border-neon-cyan); text-decoration: none; display: inline-flex; align-items: center; gap: 4px; } .card-action:hover { text-decoration: underline; color: #ffffff; } /* Supporting Section */ .supporting-section { padding-bottom: 64px; } .support-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 40px; align-items: start; } .support-title { font-size: 1.75rem; margin-bottom: 16px; } .support-desc { color: var(--text-muted); margin-bottom: 16px; } .support-action { margin-top: 24px; } .support-feature-list { display: flex; flex-direction: column; gap: 24px; } .feature-item { border-left: 2px solid var(--border-neon-cyan); padding-left: 16px; } .feature-heading { font-size: 1.0625rem; color: #ffffff; margin-bottom: 4px; } .feature-body { color: var(--text-muted); font-size: 0.875rem; line-height: 1.5; } /* ========================================================================== Article & Guide Layout (Sub-pages) ========================================================================== */ .article-wrapper { padding-bottom: 64px; } .article-hero { padding-top: 48px; padding-bottom: 32px; border-bottom: 1px solid var(--border-subtle); margin-bottom: 40px; } .article-title { font-size: clamp(1.875rem, 3.5vw, 2.5rem); margin-bottom: 16px; } .article-subtitle { font-size: 1.125rem; color: var(--text-muted); max-width: 820px; } .article-body-layout { display: grid; grid-template-columns: 1fr 300px; gap: 40px; } .article-content { font-size: 1rem; line-height: 1.75; color: #cbd5e1; } .article-content h2 { font-size: 1.5rem; margin-top: 40px; margin-bottom: 16px; padding-bottom: 8px; border-bottom: 1px solid var(--border-subtle); } .article-content h3 { font-size: 1.25rem; margin-top: 24px; margin-bottom: 12px; } .article-content p { margin-bottom: 20px; } .article-content ul { margin-bottom: 24px; padding-left: 24px; } .article-content li { margin-bottom: 8px; } .article-media { margin-bottom: 32px; } .media-frame { border-radius: var(--radius-md); border: 1px solid var(--border-subtle); background-color: var(--bg-surface); } figcaption { font-size: 0.8125rem; color: var(--text-muted); margin-top: 8px; font-style: italic; } .data-callout { background-color: var(--bg-surface); border: 1px solid var(--border-subtle); border-left: 4px solid var(--border-neon-cyan); border-radius: 0 var(--radius-md) var(--radius-md) 0; padding: 24px; margin: 32px 0; } .data-callout h3 { margin-top: 0; margin-bottom: 16px; } /* Responsive Table Wrapper */ .table-responsive { width: 100%; overflow-x: auto; margin: 16px 0; } .specs-table { width: 100%; border-collapse: collapse; text-align: left; font-size: 0.875rem; } .specs-table th, .specs-table td { padding: 12px 16px; border-bottom: 1px solid var(--border-subtle); } .specs-table th { background-color: rgba(0, 0, 0, 0.3); color: #ffffff; font-weight: 600; } .specs-table td { color: #cbd5e1; } .specs-table tr:hover td { background-color: rgba(255, 255, 255, 0.02); } /* Sidebar */ .article-sidebar { display: flex; flex-direction: column; gap: 24px; } .sidebar-box { background-color: var(--bg-surface); border: 1px solid var(--border-subtle); border-radius: var(--radius-md); padding: 20px; } .sidebar-title { font-size: 1rem; margin-bottom: 16px; padding-bottom: 8px; border-bottom: 1px solid var(--border-subtle); } .spec-list { list-style: none; } .spec-list li { display: flex; flex-direction: column; margin-bottom: 12px; font-size: 0.8125rem; } .spec-prop { color: var(--text-muted); margin-bottom: 2px; } .spec-val { color: #ffffff; font-weight: 600; font-family: var(--font-mono); } .related-nav { list-style: none; } .related-nav li { margin-bottom: 8px; } .related-nav a { font-size: 0.875rem; text-decoration: none; } .related-nav a:hover { text-decoration: underline; } /* ========================================================================== Legal Pages Layout ========================================================================== */ .legal-page-wrapper { padding-top: 48px; padding-bottom: 64px; } .legal-header { margin-bottom: 32px; } .legal-title { font-size: 2.25rem; margin-bottom: 8px; } .legal-meta { color: var(--text-muted); font-size: 0.875rem; } .legal-body { font-size: 0.9375rem; line-height: 1.7; color: #cbd5e1; } .legal-section { margin-bottom: 32px; } .legal-section:last-child { margin-bottom: 0; } .legal-section h2 { font-size: 1.25rem; margin-bottom: 12px; color: #ffffff; border-bottom: 1px solid var(--border-subtle); padding-bottom: 6px; } .legal-section p { margin-bottom: 16px; } .legal-section ul { padding-left: 20px; margin-bottom: 16px; } .legal-section li { margin-bottom: 6px; } .legal-address { font-style: normal; background-color: rgba(0, 0, 0, 0.25); padding: 16px; border-radius: var(--radius-sm); border-left: 3px solid var(--border-neon-cyan); line-height: 1.6; } /* ========================================================================== Contact Page & Form ========================================================================== */ .contact-grid { display: grid; grid-template-columns: 1.2fr 0.8fr; gap: 32px; align-items: start; } .contact-form-pane, .address-card, .map-block { padding: 24px; } .contact-info-pane { display: flex; flex-direction: column; gap: 24px; } .form-title { font-size: 1.5rem; margin-bottom: 8px; } .form-desc { color: var(--text-muted); font-size: 0.875rem; margin-bottom: 24px; } .styled-form { display: flex; flex-direction: column; gap: 20px; } .form-group { display: flex; flex-direction: column; gap: 6px; } .form-label { font-size: 0.875rem; font-weight: 600; color: #e2e8f0; } .form-control { width: 100%; background-color: rgba(11, 15, 23, 0.8); border: 1px solid var(--border-subtle); border-radius: var(--radius-sm); padding: 10px 14px; font-size: 0.9375rem; color: #ffffff; font-family: inherit; transition: border-color 0.2s ease, box-shadow 0.2s ease; } .form-control:focus { border-color: var(--border-neon-cyan); outline: none; box-shadow: 0 0 8px rgba(0, 240, 255, 0.3); } .form-control.is-invalid { border-color: #f43f5e; background-color: rgba(244, 63, 94, 0.05); } .field-error { font-size: 0.75rem; color: #f43f5e; display: none; } .field-error.is-visible { display: block; } .form-status-banner { padding: 12px 16px; border-radius: var(--radius-sm); font-size: 0.875rem; line-height: 1.5; } .form-status-banner.is-success { background-color: rgba(16, 185, 129, 0.15); border: 1px solid #10b981; color: #34d399; } .form-status-banner.is-error { background-color: rgba(244, 63, 94, 0.15); border: 1px solid #f43f5e; color: #fda4af; } .info-card-title { font-size: 1.125rem; margin-bottom: 16px; border-bottom: 1px solid var(--border-subtle); padding-bottom: 8px; } .info-item { display: flex; flex-direction: column; margin-bottom: 12px; font-size: 0.875rem; } .info-label { color: var(--text-muted); font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.05em; } .info-data { color: #ffffff; font-weight: 500; } .map-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; } .map-title { font-size: 1rem; } .map-coords { font-family: var(--font-mono); font-size: 0.75rem; color: var(--border-neon-cyan); } .static-map-canvas { width: 100%; border-radius: var(--radius-sm); overflow: hidden; border: 1px solid var(--border-subtle); margin-bottom: 12px; } .map-graphic { width: 100%; height: auto; display: block; } .map-caption { font-size: 0.8125rem; color: var(--text-muted); line-height: 1.4; } /* ========================================================================== Global Footer ========================================================================== */ .site-footer { background-color: #070a10; border-top: 1px solid var(--border-subtle); padding-top: 48px; padding-bottom: 32px; margin-top: auto; } .footer-grid { display: grid; grid-template-columns: 2fr 1fr 1fr; gap: 40px; margin-bottom: 40px; } .footer-col { display: flex; flex-direction: column; } .brand-col .brand-logo { margin-bottom: 16px; } .footer-summary { color: var(--text-muted); font-size: 0.875rem; line-height: 1.5; max-width: 420px; margin-bottom: 16px; } .legal-identity { font-size: 0.75rem; color: #64748b; line-height: 1.6; } .legal-identity p { margin-bottom: 2px; } .footer-heading { font-size: 0.875rem; text-transform: uppercase; letter-spacing: 0.08em; color: #ffffff; margin-bottom: 16px; } .footer-links { list-style: none; display: flex; flex-direction: column; gap: 8px; } .footer-links a { color: var(--text-muted); text-decoration: none; font-size: 0.875rem; } .footer-links a:hover { color: var(--border-neon-cyan); } .footer-bottom { padding-top: 24px; border-top: 1px solid rgba(255, 255, 255, 0.05); font-size: 0.75rem; color: #64748b; text-align: center; } /* ========================================================================== Cookie Banner (Fixed Bottom) ========================================================================== */ .cookie-banner { position: fixed; bottom: 0; left: 0; right: 0; background-color: rgba(11, 15, 23, 0.95); backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px); border-top: 1px solid var(--border-neon-cyan); box-shadow: 0 -4px 20px rgba(0, 0, 0, 0.6); padding: 16px 0; z-index: 9999; } .cookie-banner[hidden] { display: none !important; } .cookie-container { width: 100%; max-width: 1160px; margin-left: auto; margin-right: auto; padding-left: 16px; padding-right: 16px; display: flex; align-items: center; justify-content: space-between; gap: 24px; flex-wrap: wrap; } .cookie-text { flex: 1 1 500px; font-size: 0.8125rem; color: #cbd5e1; line-height: 1.5; } .cookie-actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; } /* ========================================================================== Responsive Breakpoints Rule: Down to 320px. Breakpoint below 400px. Reflow, don't hide. ========================================================================== */ /* Tablet and below: Under 768px */ @media (max-width: 767.98px) { .site-header { height: var(--header-height-mobile); } .header-cta-slot { display: none; } .nav-toggle { display: flex; } .nav-menu { position: fixed; top: var(--header-height-mobile); left: 0; right: 0; bottom: 0; background-color: rgba(11, 15, 23, 0.98); backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px); display: none; flex-direction: column; align-items: flex-start; padding: 32px 24px; overflow-y: auto; border-top: 1px solid var(--border-subtle); } .nav-menu.is-visible { display: flex; } .nav-list { flex-direction: column; align-items: flex-start; gap: 20px; width: 100%; } .nav-link { font-size: 1.125rem; display: block; width: 100%; padding: 8px 0; border-bottom: 1px solid var(--border-subtle); } .hero-meta-row { flex-direction: column; gap: 20px; } .support-grid { grid-template-columns: 1fr; gap: 32px; } .article-body-layout { grid-template-columns: 1fr; } .contact-grid { grid-template-columns: 1fr; } .footer-grid { grid-template-columns: 1fr; gap: 32px; } .cookie-container { flex-direction: column; align-items: stretch; } .cookie-actions { justify-content: flex-start; } } /* Mobile Below 400px (Extra Compact Screens) */ @media (max-width: 399.98px) { html { font-size: 15px; } .site-container { padding-left: 12px; padding-right: 12px; } .hero-card { padding: 24px 16px; } .card-content { padding: 20px 16px; } .glass-panel { padding: 20px 16px; } .btn { padding: 8px 14px; } .cookie-actions { flex-direction: column; align-items: stretch; } .cookie-actions .btn { width: 100%; } } /* ========================================================================== Accessibility: Reduced Motion Query ========================================================================== */ @media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; scroll-behavior: auto !important; } } ===ENDFILE=== ===FILE: script.js=== /** * Sprygoclipsarchv - Core Hardware Archive Scripts * Handles accessible mobile navigation, cookie consent persistence, and contact form validation. */ document.addEventListener('DOMContentLoaded', () => { initMobileNavigation(); initCookieConsent(); initContactForm(); }); /** * 1. Mobile Navigation Toggle (No Layout Shift, Accessible ARIA) */ function initMobileNavigation() { const toggleBtn = document.querySelector('[data-nav-toggle]'); const navMenu = document.querySelector('[data-nav-menu]'); if (!toggleBtn || !navMenu) return; toggleBtn.addEventListener('click', () => { const isExpanded = toggleBtn.getAttribute('aria-expanded') === 'true'; const nextState = !isExpanded; toggleBtn.setAttribute('aria-expanded', String(nextState)); if (nextState) { navMenu.classList.add('is-visible'); document.body.style.overflow = 'hidden'; } else { navMenu.classList.remove('is-visible'); document.body.style.overflow = ''; } }); // Close menu on link click const navLinks = navMenu.querySelectorAll('.nav-link'); navLinks.forEach(link => { link.addEventListener('click', () => { toggleBtn.setAttribute('aria-expanded', 'false'); navMenu.classList.remove('is-visible'); document.body.style.overflow = ''; }); }); // Close menu on Escape key document.addEventListener('keydown', (e) => { if (e.key === 'Escape' && navMenu.classList.contains('is-visible')) { toggleBtn.setAttribute('aria-expanded', 'false'); navMenu.classList.remove('is-visible'); document.body.style.overflow = ''; toggleBtn.focus(); } }); } /** * 2. Cookie Consent Banner * Binds to [data-cookie-choice="accept"|"reject"|"preferences"] and persists via localStorage. */ function initCookieConsent() { const banner = document.querySelector('[data-cookie-banner]'); if (!banner) return; const STORAGE_KEY = 'sprygo_consent'; const savedChoice = localStorage.getItem(STORAGE_KEY); // If choice previously made, hide banner if (savedChoice) { banner.setAttribute('hidden', ''); return; } // Ensure banner is displayed banner.removeAttribute('hidden'); const actionButtons = banner.querySelectorAll('[data-cookie-choice]'); actionButtons.forEach(button => { button.addEventListener('click', (e) => { const choice = button.getAttribute('data-cookie-choice'); if (choice === 'accept' || choice === 'reject') { localStorage.setItem(STORAGE_KEY, choice); banner.setAttribute('hidden', ''); } else if (choice === 'preferences') { // Let the link navigate to cookie-policy.html } }); }); } /** * 3. Client-Side Contact Form Validation */ function initContactForm() { const form = document.querySelector('[data-contact-form]'); if (!form) return; const statusBanner = form.querySelector('[data-form-status]'); form.addEventListener('submit', (e) => { e.preventDefault(); let isValid = true; // Name field validation const nameInput = form.querySelector('#contact-name'); const nameError = form.querySelector('[data-error-for="contact-name"]'); if (!nameInput.value.trim()) { nameInput.classList.add('is-invalid'); nameError.classList.add('is-visible'); isValid = false; } else { nameInput.classList.remove('is-invalid'); nameError.classList.remove('is-visible'); } // Email field validation const emailInput = form.querySelector('#contact-email'); const emailError = form.querySelector('[data-error-for="contact-email"]'); const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; if (!emailInput.value.trim() || !emailPattern.test(emailInput.value.trim())) { emailInput.classList.add('is-invalid'); emailError.classList.add('is-visible'); isValid = false; } else { emailInput.classList.remove('is-invalid'); emailError.classList.remove('is-visible'); } // Subject dropdown validation const subjectSelect = form.querySelector('#contact-subject'); const subjectError = form.querySelector('[data-error-for="contact-subject"]'); if (!subjectSelect.value) { subjectSelect.classList.add('is-invalid'); subjectError.classList.add('is-visible'); isValid = false; } else { subjectSelect.classList.remove('is-invalid'); subjectError.classList.remove('is-visible'); } // Message field validation (min 15 chars) const messageInput = form.querySelector('#contact-message'); const messageError = form.querySelector('[data-error-for="contact-message"]'); if (!messageInput.value.trim() || messageInput.value.trim().length < 15) { messageInput.classList.add('is-invalid'); messageError.classList.add('is-visible'); isValid = false; } else { messageInput.classList.remove('is-invalid'); messageError.classList.remove('is-visible'); } if (isValid) { // Simulate successful dispatch form.reset(); if (statusBanner) { statusBanner.className = 'form-status-banner is-success'; statusBanner.textContent = 'Transmission acknowledged. Your technical inquiry has been routed to our hardware engineering desk.'; statusBanner.removeAttribute('hidden'); } } else { if (statusBanner) { statusBanner.className = 'form-status-banner is-error'; statusBanner.textContent = 'Please review and correct the highlighted fields before resubmitting.'; statusBanner.removeAttribute('hidden'); } } }); // Clear validation styles on input change form.querySelectorAll('.form-control').forEach(input => { input.addEventListener('input', () => { if (input.classList.contains('is-invalid')) { input.classList.remove('is-invalid'); const err = form.querySelector(`[data-error-for="${input.id}"]`); if (err) err.classList.remove('is-visible'); } }); }); } ===ENDFILE===