Compare commits

..

No commits in common. "lighthouse" and "main" have entirely different histories.

55 changed files with 645 additions and 3104 deletions

View File

@ -1,12 +0,0 @@
{
"permissions": {
"allow": [
"Bash(npm run build:*)",
"Bash(npm install:*)",
"Bash(ls:*)",
"Bash(node scripts/optimize-images.js:*)",
"Bash(node scripts/optimize-images.cjs:*)",
"Skill(frontend-design)"
]
}
}

View File

@ -3,9 +3,9 @@
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>IT Support Corpus Christi ⚡ 24/7 Managed Services | Bay Area Affiliates</title> <title>Managed IT Services Corpus Christi | Bay Area Affiliates</title>
<meta name="description" content="Stop IT headaches! 25+ years experience, 2-hour response time, 24/7 monitoring. Managed IT services in Corpus Christi & Coastal Bend. Free assessment. Call (361) 765-8400" /> <meta name="description" content="Secure, tailored IT support—Corpus Christi's trusted experts for 25+ years. Call today for a free assessment." />
<meta name="keywords" content="managed IT services corpus christi, IT support coastal bend, 24/7 IT monitoring, business computer solutions, Windows 11 migration, VPN setup, network security corpus christi, same-day IT support" /> <meta name="keywords" content="managed IT services corpus christi, IT support coastal bend, business computer solutions, Portland IT services, computer repair corpus christi" />
<meta name="author" content="Bay Area Affiliates, Inc." /> <meta name="author" content="Bay Area Affiliates, Inc." />
<meta property="og:title" content="Corpus Christi Managed IT Experts. Reliable, Secure, Local." /> <meta property="og:title" content="Corpus Christi Managed IT Experts. Reliable, Secure, Local." />
@ -211,33 +211,10 @@
} }
</script> </script>
<!-- Performance Optimization -->
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link rel="dns-prefetch" href="https://fonts.gstatic.com" />
<!-- Non-blocking font loading with font-display: swap -->
<link rel="preload" as="style" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Poppins:wght@600;700;800&display=swap" />
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Poppins:wght@600;700;800&display=swap" media="print" onload="this.media='all'" />
<noscript><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Poppins:wght@600;700;800&display=swap" /></noscript>
<!-- Critical asset preloads -->
<link rel="preload" href="/logo_bayarea.svg" as="image" />
<link rel="preload" href="/serverroom.webp" as="image" type="image/webp" />
<!-- Canonical URL -->
<link rel="canonical" href="https://bayarea-cc.com/" />
<!-- Favicon --> <!-- Favicon -->
<link rel="icon" type="image/svg+xml" href="/logo_bayarea.svg" /> <link rel="icon" type="image/svg+xml" href="/logo_bayarea.svg" />
<link rel="apple-touch-icon" sizes="180x180" href="/logo_bayarea.svg" /> <link rel="icon" type="image/png" href="/logo_bayarea.svg" />
<!-- Note: For production, consider converting logo_bayarea.svg to favicon.ico for better browser support -->
<!-- PWA / Mobile -->
<meta name="theme-color" content="#3366ff" />
<meta name="mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<link rel="manifest" href="/manifest.json" />
</head> </head>
<body> <body>

682
package-lock.json generated
View File

@ -42,7 +42,6 @@
"cmdk": "^1.1.1", "cmdk": "^1.1.1",
"date-fns": "^3.6.0", "date-fns": "^3.6.0",
"embla-carousel-react": "^8.6.0", "embla-carousel-react": "^8.6.0",
"framer-motion": "^12.24.12",
"gsap": "^3.13.0", "gsap": "^3.13.0",
"input-otp": "^1.4.2", "input-otp": "^1.4.2",
"lucide-react": "^0.462.0", "lucide-react": "^0.462.0",
@ -74,13 +73,10 @@
"globals": "^15.15.0", "globals": "^15.15.0",
"lovable-tagger": "^1.1.9", "lovable-tagger": "^1.1.9",
"postcss": "^8.5.6", "postcss": "^8.5.6",
"sharp": "^0.34.5",
"tailwindcss": "^3.4.17", "tailwindcss": "^3.4.17",
"terser": "^5.44.1",
"typescript": "^5.8.3", "typescript": "^5.8.3",
"typescript-eslint": "^8.38.0", "typescript-eslint": "^8.38.0",
"vite": "^5.4.19", "vite": "^5.4.19"
"web-vitals": "^5.1.0"
} }
}, },
"node_modules/@alloc/quick-lru": { "node_modules/@alloc/quick-lru": {
@ -154,17 +150,6 @@
"node": ">=6.9.0" "node": ">=6.9.0"
} }
}, },
"node_modules/@emnapi/runtime": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz",
"integrity": "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
"tslib": "^2.4.0"
}
},
"node_modules/@esbuild/aix-ppc64": { "node_modules/@esbuild/aix-ppc64": {
"version": "0.25.9", "version": "0.25.9",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.9.tgz", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.9.tgz",
@ -874,496 +859,6 @@
"url": "https://github.com/sponsors/nzakas" "url": "https://github.com/sponsors/nzakas"
} }
}, },
"node_modules/@img/colour": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.0.0.tgz",
"integrity": "sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=18"
}
},
"node_modules/@img/sharp-darwin-arm64": {
"version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz",
"integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==",
"cpu": [
"arm64"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-darwin-arm64": "1.2.4"
}
},
"node_modules/@img/sharp-darwin-x64": {
"version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz",
"integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==",
"cpu": [
"x64"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-darwin-x64": "1.2.4"
}
},
"node_modules/@img/sharp-libvips-darwin-arm64": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz",
"integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==",
"cpu": [
"arm64"
],
"dev": true,
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
"darwin"
],
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-libvips-darwin-x64": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz",
"integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==",
"cpu": [
"x64"
],
"dev": true,
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
"darwin"
],
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-libvips-linux-arm": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz",
"integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==",
"cpu": [
"arm"
],
"dev": true,
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
"linux"
],
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-libvips-linux-arm64": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz",
"integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
"linux"
],
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-libvips-linux-ppc64": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz",
"integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==",
"cpu": [
"ppc64"
],
"dev": true,
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
"linux"
],
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-libvips-linux-riscv64": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz",
"integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==",
"cpu": [
"riscv64"
],
"dev": true,
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
"linux"
],
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-libvips-linux-s390x": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz",
"integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==",
"cpu": [
"s390x"
],
"dev": true,
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
"linux"
],
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-libvips-linux-x64": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz",
"integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==",
"cpu": [
"x64"
],
"dev": true,
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
"linux"
],
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-libvips-linuxmusl-arm64": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz",
"integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
"linux"
],
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-libvips-linuxmusl-x64": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz",
"integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==",
"cpu": [
"x64"
],
"dev": true,
"license": "LGPL-3.0-or-later",
"optional": true,
"os": [
"linux"
],
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-linux-arm": {
"version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz",
"integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==",
"cpu": [
"arm"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-linux-arm": "1.2.4"
}
},
"node_modules/@img/sharp-linux-arm64": {
"version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz",
"integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==",
"cpu": [
"arm64"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-linux-arm64": "1.2.4"
}
},
"node_modules/@img/sharp-linux-ppc64": {
"version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz",
"integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==",
"cpu": [
"ppc64"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-linux-ppc64": "1.2.4"
}
},
"node_modules/@img/sharp-linux-riscv64": {
"version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz",
"integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==",
"cpu": [
"riscv64"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-linux-riscv64": "1.2.4"
}
},
"node_modules/@img/sharp-linux-s390x": {
"version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz",
"integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==",
"cpu": [
"s390x"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-linux-s390x": "1.2.4"
}
},
"node_modules/@img/sharp-linux-x64": {
"version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz",
"integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-linux-x64": "1.2.4"
}
},
"node_modules/@img/sharp-linuxmusl-arm64": {
"version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz",
"integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==",
"cpu": [
"arm64"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-linuxmusl-arm64": "1.2.4"
}
},
"node_modules/@img/sharp-linuxmusl-x64": {
"version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz",
"integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==",
"cpu": [
"x64"
],
"dev": true,
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-libvips-linuxmusl-x64": "1.2.4"
}
},
"node_modules/@img/sharp-wasm32": {
"version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz",
"integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==",
"cpu": [
"wasm32"
],
"dev": true,
"license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT",
"optional": true,
"dependencies": {
"@emnapi/runtime": "^1.7.0"
},
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-win32-arm64": {
"version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz",
"integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==",
"cpu": [
"arm64"
],
"dev": true,
"license": "Apache-2.0 AND LGPL-3.0-or-later",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-win32-ia32": {
"version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz",
"integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==",
"cpu": [
"ia32"
],
"dev": true,
"license": "Apache-2.0 AND LGPL-3.0-or-later",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-win32-x64": {
"version": "0.34.5",
"resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz",
"integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==",
"cpu": [
"x64"
],
"dev": true,
"license": "Apache-2.0 AND LGPL-3.0-or-later",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@isaacs/cliui": { "node_modules/@isaacs/cliui": {
"version": "8.0.2", "version": "8.0.2",
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
@ -1413,17 +908,6 @@
"node": ">=6.0.0" "node": ">=6.0.0"
} }
}, },
"node_modules/@jridgewell/source-map": {
"version": "0.3.11",
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz",
"integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.25"
}
},
"node_modules/@jridgewell/sourcemap-codec": { "node_modules/@jridgewell/sourcemap-codec": {
"version": "1.5.5", "version": "1.5.5",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
@ -4027,13 +3511,6 @@
"node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
} }
}, },
"node_modules/buffer-from": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
"dev": true,
"license": "MIT"
},
"node_modules/callsites": { "node_modules/callsites": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
@ -4391,16 +3868,6 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/detect-libc": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
"integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
"dev": true,
"license": "Apache-2.0",
"engines": {
"node": ">=8"
}
},
"node_modules/detect-node-es": { "node_modules/detect-node-es": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz",
@ -4895,33 +4362,6 @@
"url": "https://github.com/sponsors/rawify" "url": "https://github.com/sponsors/rawify"
} }
}, },
"node_modules/framer-motion": {
"version": "12.24.12",
"resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.24.12.tgz",
"integrity": "sha512-W+tBOI1SDGNMH4D4mADY95qYd16Drke2Tj9zlGlwTGSCi6yy8wbMmPY1mvirfcTK8HBeuuCd2PflHdN/zbL4ew==",
"license": "MIT",
"dependencies": {
"motion-dom": "^12.24.11",
"motion-utils": "^12.24.10",
"tslib": "^2.4.0"
},
"peerDependencies": {
"@emotion/is-prop-valid": "*",
"react": "^18.0.0 || ^19.0.0",
"react-dom": "^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@emotion/is-prop-valid": {
"optional": true
},
"react": {
"optional": true
},
"react-dom": {
"optional": true
}
}
},
"node_modules/fsevents": { "node_modules/fsevents": {
"version": "2.3.3", "version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
@ -5434,21 +4874,6 @@
"node": ">=16 || 14 >=14.17" "node": ">=16 || 14 >=14.17"
} }
}, },
"node_modules/motion-dom": {
"version": "12.24.11",
"resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.24.11.tgz",
"integrity": "sha512-DlWOmsXMJrV8lzZyd+LKjG2CXULUs++bkq8GZ2Sr0R0RRhs30K2wtY+LKiTjhmJU3W61HK+rB0GLz6XmPvTA1A==",
"license": "MIT",
"dependencies": {
"motion-utils": "^12.24.10"
}
},
"node_modules/motion-utils": {
"version": "12.24.10",
"resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.24.10.tgz",
"integrity": "sha512-x5TFgkCIP4pPsRLpKoI86jv/q8t8FQOiM/0E8QKBzfMozWHfkKap2gA1hOki+B5g3IsBNpxbUnfOum1+dgvYww==",
"license": "MIT"
},
"node_modules/ms": { "node_modules/ms": {
"version": "2.1.3", "version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
@ -6258,9 +5683,9 @@
} }
}, },
"node_modules/semver": { "node_modules/semver": {
"version": "7.7.3", "version": "7.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
"integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
"dev": true, "dev": true,
"license": "ISC", "license": "ISC",
"bin": { "bin": {
@ -6270,51 +5695,6 @@
"node": ">=10" "node": ">=10"
} }
}, },
"node_modules/sharp": {
"version": "0.34.5",
"resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz",
"integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==",
"dev": true,
"hasInstallScript": true,
"license": "Apache-2.0",
"dependencies": {
"@img/colour": "^1.0.0",
"detect-libc": "^2.1.2",
"semver": "^7.7.3"
},
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-darwin-arm64": "0.34.5",
"@img/sharp-darwin-x64": "0.34.5",
"@img/sharp-libvips-darwin-arm64": "1.2.4",
"@img/sharp-libvips-darwin-x64": "1.2.4",
"@img/sharp-libvips-linux-arm": "1.2.4",
"@img/sharp-libvips-linux-arm64": "1.2.4",
"@img/sharp-libvips-linux-ppc64": "1.2.4",
"@img/sharp-libvips-linux-riscv64": "1.2.4",
"@img/sharp-libvips-linux-s390x": "1.2.4",
"@img/sharp-libvips-linux-x64": "1.2.4",
"@img/sharp-libvips-linuxmusl-arm64": "1.2.4",
"@img/sharp-libvips-linuxmusl-x64": "1.2.4",
"@img/sharp-linux-arm": "0.34.5",
"@img/sharp-linux-arm64": "0.34.5",
"@img/sharp-linux-ppc64": "0.34.5",
"@img/sharp-linux-riscv64": "0.34.5",
"@img/sharp-linux-s390x": "0.34.5",
"@img/sharp-linux-x64": "0.34.5",
"@img/sharp-linuxmusl-arm64": "0.34.5",
"@img/sharp-linuxmusl-x64": "0.34.5",
"@img/sharp-wasm32": "0.34.5",
"@img/sharp-win32-arm64": "0.34.5",
"@img/sharp-win32-ia32": "0.34.5",
"@img/sharp-win32-x64": "0.34.5"
}
},
"node_modules/shebang-command": { "node_modules/shebang-command": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
@ -6358,16 +5738,6 @@
"react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc" "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc"
} }
}, },
"node_modules/source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true,
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/source-map-js": { "node_modules/source-map-js": {
"version": "1.2.1", "version": "1.2.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
@ -6377,17 +5747,6 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/source-map-support": {
"version": "0.5.21",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
"integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
"dev": true,
"license": "MIT",
"dependencies": {
"buffer-from": "^1.0.0",
"source-map": "^0.6.0"
}
},
"node_modules/string-width": { "node_modules/string-width": {
"version": "5.1.2", "version": "5.1.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
@ -6600,32 +5959,6 @@
"tailwindcss": ">=3.0.0 || insiders" "tailwindcss": ">=3.0.0 || insiders"
} }
}, },
"node_modules/terser": {
"version": "5.44.1",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.44.1.tgz",
"integrity": "sha512-t/R3R/n0MSwnnazuPpPNVO60LX0SKL45pyl9YlvxIdkH0Of7D5qM2EVe+yASRIlY5pZ73nclYJfNANGWPwFDZw==",
"dev": true,
"license": "BSD-2-Clause",
"dependencies": {
"@jridgewell/source-map": "^0.3.3",
"acorn": "^8.15.0",
"commander": "^2.20.0",
"source-map-support": "~0.5.20"
},
"bin": {
"terser": "bin/terser"
},
"engines": {
"node": ">=10"
}
},
"node_modules/terser/node_modules/commander": {
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
"dev": true,
"license": "MIT"
},
"node_modules/thenify": { "node_modules/thenify": {
"version": "3.3.1", "version": "3.3.1",
"resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
@ -7372,13 +6705,6 @@
"@esbuild/win32-x64": "0.21.5" "@esbuild/win32-x64": "0.21.5"
} }
}, },
"node_modules/web-vitals": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-5.1.0.tgz",
"integrity": "sha512-ArI3kx5jI0atlTtmV0fWU3fjpLmq/nD3Zr1iFFlJLaqa5wLBkUSzINwBPySCX/8jRyjlmy1Volw1kz1g9XE4Jg==",
"dev": true,
"license": "Apache-2.0"
},
"node_modules/which": { "node_modules/which": {
"version": "2.0.2", "version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",

View File

@ -45,7 +45,6 @@
"cmdk": "^1.1.1", "cmdk": "^1.1.1",
"date-fns": "^3.6.0", "date-fns": "^3.6.0",
"embla-carousel-react": "^8.6.0", "embla-carousel-react": "^8.6.0",
"framer-motion": "^12.24.12",
"gsap": "^3.13.0", "gsap": "^3.13.0",
"input-otp": "^1.4.2", "input-otp": "^1.4.2",
"lucide-react": "^0.462.0", "lucide-react": "^0.462.0",
@ -77,12 +76,9 @@
"globals": "^15.15.0", "globals": "^15.15.0",
"lovable-tagger": "^1.1.9", "lovable-tagger": "^1.1.9",
"postcss": "^8.5.6", "postcss": "^8.5.6",
"sharp": "^0.34.5",
"tailwindcss": "^3.4.17", "tailwindcss": "^3.4.17",
"terser": "^5.44.1",
"typescript": "^5.8.3", "typescript": "^5.8.3",
"typescript-eslint": "^8.38.0", "typescript-eslint": "^8.38.0",
"vite": "^5.4.19", "vite": "^5.4.19"
"web-vitals": "^5.1.0"
} }
} }

View File

@ -1,33 +0,0 @@
# Security Headers for all routes
/*
# XSS Protection
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
# Referrer Policy
Referrer-Policy: strict-origin-when-cross-origin
# Permissions Policy
Permissions-Policy: geolocation=(self), microphone=(), camera=(), payment=()
# Strict Transport Security (HSTS)
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
# Content Security Policy
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://fonts.googleapis.com https://www.googletagmanager.com https://www.google-analytics.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data: https: blob:; connect-src 'self' https://www.google-analytics.com https://*.googletagmanager.com; frame-ancestors 'none';
# Cache Control for static assets
Cache-Control: public, max-age=31536000, immutable
# Cache Control for HTML
/*.html
Cache-Control: public, max-age=0, must-revalidate
# Cache Control for service worker
/sw.js
Cache-Control: public, max-age=0, must-revalidate
# Cache Control for manifest
/manifest.json
Cache-Control: public, max-age=86400, must-revalidate

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 324 KiB

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 272 KiB

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 144 KiB

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 469 KiB

After

Width:  |  Height:  |  Size: 4.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 75 KiB

View File

@ -1,22 +0,0 @@
{
"name": "Bay Area Affiliates - Managed IT Services",
"short_name": "Bay Area IT",
"description": "Professional managed IT services in Corpus Christi & Coastal Bend",
"start_url": "/",
"display": "standalone",
"background_color": "#030303",
"theme_color": "#3366ff",
"orientation": "portrait-primary",
"icons": [
{
"src": "/logo_bayarea.svg",
"sizes": "any",
"type": "image/svg+xml",
"purpose": "any maskable"
}
],
"categories": ["business", "productivity", "utilities"],
"scope": "/",
"lang": "en-US",
"dir": "ltr"
}

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 217 KiB

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 232 KiB

After

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

View File

@ -1,113 +0,0 @@
const sharp = require('sharp');
const fs = require('fs');
const path = require('path');
const PUBLIC_DIR = path.join(__dirname, '../public');
const WEBP_QUALITY = 80;
const AVIF_QUALITY = 80;
const PNG_QUALITY = 80;
async function optimizeImages() {
console.log('Starting image optimization...\n');
// Get all PNG files in public directory
const files = fs.readdirSync(PUBLIC_DIR)
.filter(file => file.endsWith('.png'))
.map(file => path.join(PUBLIC_DIR, file));
if (files.length === 0) {
console.log('No PNG files found in public directory');
return;
}
console.log(`Found ${files.length} PNG files to optimize\n`);
let totalOriginalSize = 0;
let totalWebpSize = 0;
let totalAvifSize = 0;
let totalCompressedPngSize = 0;
for (const filePath of files) {
const filename = path.basename(filePath);
const filenameWithoutExt = path.basename(filePath, '.png');
const originalSize = fs.statSync(filePath).size;
totalOriginalSize += originalSize;
console.log(`Processing: ${filename} (${(originalSize / 1024 / 1024).toFixed(2)} MB)`);
try {
// Generate WebP version
const webpPath = path.join(PUBLIC_DIR, `${filenameWithoutExt}.webp`);
await sharp(filePath)
.resize(1920, null, { withoutEnlargement: true, fit: 'inside' })
.webp({ quality: WEBP_QUALITY })
.toFile(webpPath);
const webpSize = fs.statSync(webpPath).size;
totalWebpSize += webpSize;
console.log(` ✓ WebP: ${(webpSize / 1024).toFixed(2)} KB (${((1 - webpSize / originalSize) * 100).toFixed(1)}% reduction)`);
// Generate AVIF version
const avifPath = path.join(PUBLIC_DIR, `${filenameWithoutExt}.avif`);
await sharp(filePath)
.resize(1920, null, { withoutEnlargement: true, fit: 'inside' })
.avif({ quality: AVIF_QUALITY })
.toFile(avifPath);
const avifSize = fs.statSync(avifPath).size;
totalAvifSize += avifSize;
console.log(` ✓ AVIF: ${(avifSize / 1024).toFixed(2)} KB (${((1 - avifSize / originalSize) * 100).toFixed(1)}% reduction)`);
// Compress original PNG
const compressedPngPath = path.join(PUBLIC_DIR, `${filenameWithoutExt}_compressed.png`);
await sharp(filePath)
.resize(1920, null, { withoutEnlargement: true, fit: 'inside' })
.png({
quality: PNG_QUALITY,
compressionLevel: 9,
palette: true
})
.toFile(compressedPngPath);
const compressedPngSize = fs.statSync(compressedPngPath).size;
totalCompressedPngSize += compressedPngSize;
console.log(` ✓ Compressed PNG: ${(compressedPngSize / 1024).toFixed(2)} KB (${((1 - compressedPngSize / originalSize) * 100).toFixed(1)}% reduction)`);
// Replace original with compressed version
fs.unlinkSync(filePath);
fs.renameSync(compressedPngPath, filePath);
console.log(` ✓ Original PNG replaced with compressed version\n`);
} catch (error) {
console.error(` ✗ Error processing ${filename}:`, error.message);
}
}
// Summary
console.log('\n' + '='.repeat(60));
console.log('OPTIMIZATION SUMMARY');
console.log('='.repeat(60));
console.log(`Total original PNG size: ${(totalOriginalSize / 1024 / 1024).toFixed(2)} MB`);
console.log(`Total WebP size: ${(totalWebpSize / 1024 / 1024).toFixed(2)} MB (${((1 - totalWebpSize / totalOriginalSize) * 100).toFixed(1)}% reduction)`);
console.log(`Total AVIF size: ${(totalAvifSize / 1024 / 1024).toFixed(2)} MB (${((1 - totalAvifSize / totalOriginalSize) * 100).toFixed(1)}% reduction)`);
console.log(`Total compressed PNG size: ${(totalCompressedPngSize / 1024 / 1024).toFixed(2)} MB (${((1 - totalCompressedPngSize / totalOriginalSize) * 100).toFixed(1)}% reduction)`);
console.log('\nAverage file sizes:');
console.log(` WebP: ${(totalWebpSize / files.length / 1024).toFixed(2)} KB`);
console.log(` AVIF: ${(totalAvifSize / files.length / 1024).toFixed(2)} KB`);
console.log(` Compressed PNG: ${(totalCompressedPngSize / files.length / 1024).toFixed(2)} KB`);
console.log('='.repeat(60));
// Check if targets are met
const avgWebpSize = totalWebpSize / files.length / 1024;
const avgAvifSize = totalAvifSize / files.length / 1024;
const totalSizeAfter = (totalWebpSize + totalAvifSize + totalCompressedPngSize) / 1024 / 1024;
console.log('\nTarget Achievement:');
console.log(` WebP avg < 200KB: ${avgWebpSize < 200 ? '✓ PASS' : '✗ FAIL'} (${avgWebpSize.toFixed(2)} KB)`);
console.log(` AVIF avg < 150KB: ${avgAvifSize < 150 ? '✓ PASS' : '✗ FAIL'} (${avgAvifSize.toFixed(2)} KB)`);
console.log(` Total size < 2MB: ${totalSizeAfter < 2 ? '✓ PASS' : '✗ FAIL'} (${totalSizeAfter.toFixed(2)} MB)`);
}
optimizeImages()
.then(() => console.log('\nOptimization complete!'))
.catch(error => console.error('Optimization failed:', error));

View File

@ -2,12 +2,8 @@ import { Toaster } from "@/components/ui/toaster";
import { Toaster as Sonner } from "@/components/ui/sonner"; import { Toaster as Sonner } from "@/components/ui/sonner";
import { TooltipProvider } from "@/components/ui/tooltip"; import { TooltipProvider } from "@/components/ui/tooltip";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { BrowserRouter, Routes, Route, useLocation } from "react-router-dom"; import { BrowserRouter, Routes, Route } from "react-router-dom";
import { lazy, Suspense, useEffect } from "react"; import { lazy, Suspense } from "react";
import { AnimatePresence, motion } from "framer-motion";
import { reportWebVitals, observePerformance } from "@/utils/reportWebVitals";
import { pageTransition } from "@/utils/animations";
import ExitIntentPopup from "@/components/ExitIntentPopup";
// Eager load critical pages for better initial performance // Eager load critical pages for better initial performance
import Index from "./pages/Index"; import Index from "./pages/Index";
@ -30,101 +26,42 @@ const NetworkAttachedStorage = lazy(() => import("./pages/NetworkAttachedStorage
const queryClient = new QueryClient(); const queryClient = new QueryClient();
// Loading fallback component with animation // Loading fallback component
const PageLoader = () => ( const PageLoader = () => (
<motion.div <div className="min-h-screen flex items-center justify-center bg-background-deep">
className="min-h-screen flex items-center justify-center bg-background-deep"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
>
<div className="text-center"> <div className="text-center">
<motion.div <div className="w-16 h-16 border-4 border-neon/30 border-t-neon rounded-full animate-spin mx-auto mb-4"></div>
className="w-16 h-16 border-4 border-neon/30 border-t-neon rounded-full mx-auto mb-4" <p className="text-foreground-muted">Loading...</p>
animate={{ rotate: 360 }}
transition={{ duration: 1, repeat: Infinity, ease: "linear" }}
/>
<motion.p
className="text-foreground-muted"
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.2 }}
>
Loading...
</motion.p>
</div> </div>
</motion.div> </div>
); );
// Animated page wrapper
const AnimatedPage = ({ children }: { children: React.ReactNode }) => {
return (
<motion.div
initial="initial"
animate="animate"
exit="exit"
variants={{
initial: pageTransition.initial,
animate: pageTransition.animate,
exit: pageTransition.exit
}}
transition={pageTransition.transition}
>
{children}
</motion.div>
);
};
const AppContent = () => {
const location = useLocation();
useEffect(() => {
// Initialize Web Vitals monitoring
reportWebVitals();
observePerformance();
}, []);
// Scroll to top on route change
useEffect(() => {
window.scrollTo(0, 0);
}, [location.pathname]);
return (
<>
<ExitIntentPopup />
<AnimatePresence mode="wait">
<Suspense fallback={<PageLoader />}>
<Routes location={location} key={location.pathname}>
<Route path="/" element={<AnimatedPage><Index /></AnimatedPage>} />
<Route path="/services" element={<AnimatedPage><Services /></AnimatedPage>} />
<Route path="/about" element={<AnimatedPage><About /></AnimatedPage>} />
<Route path="/blog" element={<AnimatedPage><Blog /></AnimatedPage>} />
<Route path="/blog/:slug" element={<AnimatedPage><BlogPost /></AnimatedPage>} />
<Route path="/contact" element={<AnimatedPage><Contact /></AnimatedPage>} />
<Route path="/windows-11-transition" element={<AnimatedPage><Windows11Transition /></AnimatedPage>} />
<Route path="/vpn-setup" element={<AnimatedPage><VpnSetup /></AnimatedPage>} />
<Route path="/web-services" element={<AnimatedPage><WebServices /></AnimatedPage>} />
<Route path="/performance-upgrades" element={<AnimatedPage><PerformanceUpgrades /></AnimatedPage>} />
<Route path="/printer-scanner-installation" element={<AnimatedPage><PrinterScannerInstallation /></AnimatedPage>} />
<Route path="/desktop-hardware" element={<AnimatedPage><DesktopHardware /></AnimatedPage>} />
<Route path="/network-infrastructure" element={<AnimatedPage><NetworkInfrastructure /></AnimatedPage>} />
<Route path="/network-attached-storage" element={<AnimatedPage><NetworkAttachedStorage /></AnimatedPage>} />
{/* ADD ALL CUSTOM ROUTES ABOVE THE CATCH-ALL "*" ROUTE */}
<Route path="*" element={<AnimatedPage><NotFound /></AnimatedPage>} />
</Routes>
</Suspense>
</AnimatePresence>
</>
);
};
const App = () => ( const App = () => (
<QueryClientProvider client={queryClient}> <QueryClientProvider client={queryClient}>
<TooltipProvider> <TooltipProvider>
<Toaster /> <Toaster />
<Sonner /> <Sonner />
<BrowserRouter> <BrowserRouter>
<AppContent /> <Suspense fallback={<PageLoader />}>
<Routes>
<Route path="/" element={<Index />} />
<Route path="/services" element={<Services />} />
<Route path="/about" element={<About />} />
<Route path="/blog" element={<Blog />} />
<Route path="/blog/:slug" element={<BlogPost />} />
<Route path="/contact" element={<Contact />} />
<Route path="/windows-11-transition" element={<Windows11Transition />} />
<Route path="/vpn-setup" element={<VpnSetup />} />
<Route path="/web-services" element={<WebServices />} />
<Route path="/performance-upgrades" element={<PerformanceUpgrades />} />
<Route path="/printer-scanner-installation" element={<PrinterScannerInstallation />} />
<Route path="/desktop-hardware" element={<DesktopHardware />} />
<Route path="/network-infrastructure" element={<NetworkInfrastructure />} />
<Route path="/network-attached-storage" element={<NetworkAttachedStorage />} />
{/* ADD ALL CUSTOM ROUTES ABOVE THE CATCH-ALL "*" ROUTE */}
<Route path="*" element={<NotFound />} />
</Routes>
</Suspense>
</BrowserRouter> </BrowserRouter>
</TooltipProvider> </TooltipProvider>
</QueryClientProvider> </QueryClientProvider>

View File

@ -1,134 +0,0 @@
import { useEffect, useState } from 'react';
import { X, Download } from 'lucide-react';
import { Link } from 'react-router-dom';
const ExitIntentPopup = () => {
const [isVisible, setIsVisible] = useState(false);
const [hasShown, setHasShown] = useState(false);
useEffect(() => {
// Check if popup was already shown in this session
const shown = sessionStorage.getItem('exitIntentShown');
if (shown) {
setHasShown(true);
return;
}
const handleMouseLeave = (e: MouseEvent) => {
// Only trigger if mouse is leaving from top of viewport
if (e.clientY <= 0 && !hasShown) {
setIsVisible(true);
setHasShown(true);
sessionStorage.setItem('exitIntentShown', 'true');
}
};
// Add delay before activating to avoid false triggers
const timer = setTimeout(() => {
document.addEventListener('mouseleave', handleMouseLeave);
}, 3000);
return () => {
clearTimeout(timer);
document.removeEventListener('mouseleave', handleMouseLeave);
};
}, [hasShown]);
const handleClose = () => {
setIsVisible(false);
};
if (!isVisible) return null;
return (
<>
{/* Backdrop */}
<div
className="fixed inset-0 bg-black/80 backdrop-blur-sm z-50 animate-in fade-in duration-300"
onClick={handleClose}
/>
{/* Popup */}
<div className="fixed top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 z-50 animate-in zoom-in duration-300">
<div className="card-dark p-8 max-w-lg w-[90vw] relative">
{/* Close button */}
<button
onClick={handleClose}
className="absolute top-4 right-4 text-foreground-muted hover:text-foreground transition-colors"
aria-label="Close popup"
>
<X className="w-6 h-6" />
</button>
{/* Content */}
<div className="text-center">
<div className="w-16 h-16 bg-neon/20 rounded-full flex items-center justify-center mx-auto mb-4">
<Download className="w-8 h-8 text-neon" />
</div>
<h2 className="font-heading font-bold text-2xl sm:text-3xl text-foreground mb-4">
Wait! Don't leave empty-handed
</h2>
<p className="text-foreground-muted mb-6 text-lg">
Download our <span className="text-neon font-semibold">free Windows 11 Migration Checklist</span>
a $299 value guide to help you prepare for the upgrade.
</p>
{/* Key benefits */}
<ul className="text-left space-y-2 mb-6 text-sm">
<li className="flex items-start gap-2">
<svg className="w-5 h-5 text-green-400 flex-shrink-0 mt-0.5" fill="currentColor" viewBox="0 0 20 20">
<path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clipRule="evenodd" />
</svg>
<span>Hardware compatibility check (avoid costly mistakes)</span>
</li>
<li className="flex items-start gap-2">
<svg className="w-5 h-5 text-green-400 flex-shrink-0 mt-0.5" fill="currentColor" viewBox="0 0 20 20">
<path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clipRule="evenodd" />
</svg>
<span>Step-by-step migration timeline</span>
</li>
<li className="flex items-start gap-2">
<svg className="w-5 h-5 text-green-400 flex-shrink-0 mt-0.5" fill="currentColor" viewBox="0 0 20 20">
<path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clipRule="evenodd" />
</svg>
<span>Security & compliance considerations</span>
</li>
<li className="flex items-start gap-2">
<svg className="w-5 h-5 text-green-400 flex-shrink-0 mt-0.5" fill="currentColor" viewBox="0 0 20 20">
<path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clipRule="evenodd" />
</svg>
<span>Rollback plan (just in case)</span>
</li>
</ul>
{/* CTA */}
<Link
to="/contact?lead=windows11-checklist"
onClick={handleClose}
className="btn-neon w-full flex items-center justify-center space-x-2 mb-3"
>
<Download className="w-5 h-5" />
<span>Download Free Checklist</span>
</Link>
<p className="text-xs text-foreground-muted">
No spam. No credit card required. Instant access.
</p>
{/* Close link */}
<button
onClick={handleClose}
className="text-sm text-foreground-muted hover:text-foreground mt-4 underline"
>
No thanks, I'll figure it out myself
</button>
</div>
</div>
</div>
</>
);
};
export default ExitIntentPopup;

View File

@ -20,7 +20,7 @@ const Footer = () => {
]; ];
return ( return (
<footer role="contentinfo" className="bg-background-deep border-t border-border"> <footer className="bg-background-deep border-t border-border">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-16"> <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-16">
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8 mb-12"> <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8 mb-12">
{/* Company info */} {/* Company info */}

View File

@ -1,8 +1,6 @@
import { useState, useEffect } from 'react'; import { useState, useEffect } from 'react';
import { Link, useLocation } from 'react-router-dom'; import { Link, useLocation } from 'react-router-dom';
import { Menu, X } from 'lucide-react'; import { Menu, X } from 'lucide-react';
import { motion, AnimatePresence } from 'framer-motion';
import { navVariants, staggerContainer, staggerItem, buttonHover, buttonTap } from '@/utils/animations';
const Navigation = () => { const Navigation = () => {
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
@ -29,173 +27,87 @@ const Navigation = () => {
const isActive = (path: string) => location.pathname === path; const isActive = (path: string) => location.pathname === path;
return ( return (
<> <nav className={`fixed top-0 left-0 right-0 z-50 transition-all duration-300 ${isScrolled
{/* Skip link for accessibility */} ? 'bg-white/5 backdrop-blur-2xl border-b border-white/20 shadow-2xl shadow-black/20'
<a href="#main-content" className="skip-link"> : 'bg-transparent'
Skip to main content }`}>
</a> <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex items-center justify-between h-16">
<motion.nav {/* Logo */}
className={`fixed top-0 left-0 right-0 z-50 transition-all duration-300 ${isScrolled <Link to="/" className="flex items-center space-x-3">
? 'bg-background-deep/80 backdrop-blur-md border-b border-neon/30 shadow-[0_0_20px_rgba(0,0,0,0.5)]' <div className="w-12 h-12 flex items-center justify-center overflow-visible">
: 'bg-transparent border-b border-transparent' <img
}`} src="/logo_bayarea.svg"
initial="hidden" alt="Bay Area Affiliates Logo"
animate="visible" className="w-10 h-10 opacity-90 hover:opacity-100 transition-opacity duration-300"
variants={navVariants} />
role="navigation"
aria-label="Main navigation"
>
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex items-center justify-between h-14 md:h-16">
{/* Logo with animation */}
<Link to="/" className="flex items-center space-x-3">
<motion.div
className="w-12 h-12 flex items-center justify-center overflow-visible"
whileHover={{ rotate: 360 }}
transition={{ duration: 0.6, ease: "easeInOut" }}
>
<img
src="/logo_bayarea.svg"
alt="Bay Area Affiliates Logo"
className="w-10 h-10 opacity-90"
/>
</motion.div>
<span className="font-heading font-bold text-lg text-white">
Bay Area Affiliates
</span>
</Link>
{/* Desktop Navigation with animations */}
<div className="hidden md:flex items-center space-x-8">
{navItems.map((item, index) => (
<motion.div
key={item.name}
initial={{ opacity: 0, y: -20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: index * 0.1, duration: 0.5 }}
>
<Link
to={item.path}
className={`font-medium transition-all duration-200 relative group px-2 py-1 ${isActive(item.path)
? 'text-neon'
: 'text-white hover:text-neon'
}`}
>
{item.name}
{/* Animated underline */}
<motion.span
className="absolute -bottom-1 left-0 h-0.5 bg-neon rounded-full"
initial={{ width: isActive(item.path) ? '100%' : 0 }}
whileHover={{ width: '100%', boxShadow: '0 0 8px rgba(51, 102, 255, 0.6)' }}
transition={{ duration: 0.3, ease: "easeOut" }}
/>
{/* Glow effect on hover */}
<motion.span
className="absolute inset-0 bg-neon/5 rounded-lg -z-10"
initial={{ opacity: 0, scale: 0.8 }}
whileHover={{ opacity: 1, scale: 1 }}
transition={{ duration: 0.2 }}
/>
</Link>
</motion.div>
))}
<motion.div
initial={{ opacity: 0, scale: 0.8 }}
animate={{ opacity: 1, scale: 1 }}
transition={{ delay: 0.5, duration: 0.5 }}
whileHover={buttonHover}
whileTap={buttonTap}
>
<Link
to="/contact"
className="btn-neon ml-4"
>
Get Started
</Link>
</motion.div>
</div> </div>
<span className="font-heading font-bold text-lg text-white">
Bay Area Affiliates
</span>
</Link>
{/* Mobile menu button with animation */} {/* Desktop Navigation */}
<motion.button <div className="hidden md:flex items-center space-x-8">
onClick={() => setIsOpen(!isOpen)} {navItems.map((item) => (
className="md:hidden text-white hover:text-neon transition-colors" <Link
aria-label="Toggle navigation menu" key={item.name}
whileHover={{ scale: 1.1 }} to={item.path}
whileTap={{ scale: 0.9 }} className={`font-medium transition-colors duration-200 ${isActive(item.path)
? 'text-neon'
: 'text-white hover:text-neon'
}`}
>
{item.name}
</Link>
))}
<Link
to="/contact"
className="btn-neon ml-4"
> >
<AnimatePresence mode="wait"> Get Started
{isOpen ? ( </Link>
<motion.div
key="close"
initial={{ rotate: -90, opacity: 0 }}
animate={{ rotate: 0, opacity: 1 }}
exit={{ rotate: 90, opacity: 0 }}
transition={{ duration: 0.2 }}
>
<X size={24} />
</motion.div>
) : (
<motion.div
key="menu"
initial={{ rotate: 90, opacity: 0 }}
animate={{ rotate: 0, opacity: 1 }}
exit={{ rotate: -90, opacity: 0 }}
transition={{ duration: 0.2 }}
>
<Menu size={24} />
</motion.div>
)}
</AnimatePresence>
</motion.button>
</div> </div>
{/* Mobile Navigation with smooth animations */} {/* Mobile menu button */}
<AnimatePresence> <button
{isOpen && ( onClick={() => setIsOpen(!isOpen)}
<motion.div className="md:hidden text-white hover:text-neon transition-colors"
initial={{ height: 0, opacity: 0 }} aria-label="Toggle navigation menu"
animate={{ height: 'auto', opacity: 1 }} >
exit={{ height: 0, opacity: 0 }} {isOpen ? <X size={24} /> : <Menu size={24} />}
transition={{ duration: 0.3, ease: "easeInOut" }} </button>
className="md:hidden bg-white/5 backdrop-blur-2xl border-t border-white/20 overflow-hidden"
>
<motion.div
className="px-2 pt-2 pb-3 space-y-1"
variants={staggerContainer}
initial="hidden"
animate="visible"
>
{navItems.map((item) => (
<motion.div key={item.name} variants={staggerItem}>
<Link
to={item.path}
onClick={() => setIsOpen(false)}
className={`block px-3 py-2 rounded-md text-base font-medium transition-colors ${isActive(item.path)
? 'text-neon bg-neon/10'
: 'text-white hover:text-neon hover:bg-neon/5'
}`}
>
{item.name}
</Link>
</motion.div>
))}
<motion.div variants={staggerItem}>
<Link
to="/contact"
onClick={() => setIsOpen(false)}
className="block w-full text-center btn-neon mt-4"
>
Get Started
</Link>
</motion.div>
</motion.div>
</motion.div>
)}
</AnimatePresence>
</div> </div>
</motion.nav>
</> {/* Mobile Navigation */}
{isOpen && (
<div className="md:hidden bg-white/5 backdrop-blur-2xl border-t border-white/20">
<div className="px-2 pt-2 pb-3 space-y-1">
{navItems.map((item) => (
<Link
key={item.name}
to={item.path}
onClick={() => setIsOpen(false)}
className={`block px-3 py-2 rounded-md text-base font-medium transition-colors ${isActive(item.path)
? 'text-neon bg-neon/10'
: 'text-white hover:text-neon hover:bg-neon/5'
}`}
>
{item.name}
</Link>
))}
<Link
to="/contact"
onClick={() => setIsOpen(false)}
className="block w-full text-center btn-neon mt-4"
>
Get Started
</Link>
</div>
</div>
)}
</div>
</nav>
); );
}; };

View File

@ -1,50 +1,47 @@
import { ReactNode } from 'react'; import { ReactNode, useLayoutEffect, useRef } from 'react';
import { motion, useInView } from 'framer-motion'; import gsap from 'gsap';
import React, { useRef } from 'react'; import { ScrollTrigger } from 'gsap/ScrollTrigger';
interface ScrollRevealProps { gsap.registerPlugin(ScrollTrigger);
children: React.ReactNode;
width?: 'fit-content' | '100%'; type ScrollRevealProps = {
children: ReactNode;
delay?: number; delay?: number;
duration?: number;
direction?: 'up' | 'down' | 'left' | 'right';
className?: string; className?: string;
} };
const ScrollReveal: React.FC<ScrollRevealProps> = ({ const ScrollReveal = ({ children, delay = 0, className = '' }: ScrollRevealProps) => {
children, const elementRef = useRef<HTMLDivElement>(null);
width = 'fit-content',
delay = 0,
duration = 0.5,
direction = 'up',
className = ""
}) => {
const ref = useRef(null);
const isInView = useInView(ref, { once: true, margin: "-50px 0px" }); // Trigger slightly before element is fully in view
const getDirectionOffset = () => { useLayoutEffect(() => {
switch (direction) { const element = elementRef.current;
case 'up': return { y: 75 }; if (!element) return;
case 'down': return { y: -75 };
case 'left': return { x: 75 }; const ctx = gsap.context(() => {
case 'right': return { x: -75 }; gsap.fromTo(
default: return { y: 75 }; element,
} { autoAlpha: 0, y: 32 },
}; {
autoAlpha: 1,
y: 0,
duration: 0.8,
ease: 'power3.out',
delay: delay / 1000,
scrollTrigger: {
trigger: element,
start: 'top 85%',
once: true,
},
}
);
}, element);
return () => ctx.revert();
}, [delay]);
return ( return (
<div ref={ref} style={{ position: 'relative', width, overflow: 'hidden' }} className={className}> <div ref={elementRef} className={className}>
<motion.div {children}
variants={{
hidden: { opacity: 0, ...getDirectionOffset() },
visible: { opacity: 1, x: 0, y: 0 },
}}
initial="hidden"
animate={isInView ? "visible" : "hidden"}
transition={{ duration, delay, ease: "easeOut" }}
>
{children}
</motion.div>
</div> </div>
); );
}; };

View File

@ -1,244 +0,0 @@
import { motion } from 'framer-motion';
import { useMemo } from 'react';
const BackgroundAnimations = () => {
// Particles with better visibility (increased opacity and size)
const particles = useMemo(() => {
return Array.from({ length: 18 }, (_, i) => ({
id: i,
x: Math.random() * 100,
y: Math.random() * 100,
size: Math.random() * 4 + 2, // Larger particles (2-6px instead of 1-3px)
duration: Math.random() * 10 + 6,
delay: Math.random() * 4,
opacity: Math.random() * 0.4 + 0.5, // Much higher opacity (0.5-0.9)
}));
}, []);
// Circuit nodes for tech effect
const circuitNodes = useMemo(() => {
return Array.from({ length: 8 }, (_, i) => ({
id: i,
x: Math.random() * 80 + 10,
y: Math.random() * 80 + 10,
pulseDelay: Math.random() * 2,
}));
}, []);
// Connection lines between nodes
const connectionLines = useMemo(() => {
const lines = [];
for (let i = 0; i < circuitNodes.length - 1; i++) {
if (i + 1 < circuitNodes.length) {
lines.push({
id: i,
x1: circuitNodes[i].x,
y1: circuitNodes[i].y,
x2: circuitNodes[i + 1].x,
y2: circuitNodes[i + 1].y,
});
}
}
return lines;
}, [circuitNodes]);
return (
<div className="absolute inset-0 overflow-hidden pointer-events-none" style={{ willChange: 'transform' }}>
{/* Animated Grid Background */}
<motion.div
className="absolute inset-0"
style={{
backgroundImage: `
linear-gradient(to right, rgba(51, 102, 255, 0.08) 1px, transparent 1px),
linear-gradient(to bottom, rgba(51, 102, 255, 0.08) 1px, transparent 1px)
`,
backgroundSize: '60px 60px',
willChange: 'transform',
}}
animate={{
opacity: [0.3, 0.5, 0.3],
}}
transition={{
duration: 4,
repeat: Infinity,
ease: "easeInOut",
}}
/>
{/* SVG Container for Lines and Nodes */}
<svg className="absolute inset-0 w-full h-full" style={{ willChange: 'transform' }}>
{/* Animated Connection Lines */}
{connectionLines.map((line) => (
<motion.line
key={line.id}
x1={`${line.x1}%`}
y1={`${line.y1}%`}
x2={`${line.x2}%`}
y2={`${line.y2}%`}
stroke="rgba(51, 102, 255, 0.4)"
strokeWidth="1.5"
initial={{ pathLength: 0, opacity: 0 }}
animate={{ pathLength: 1, opacity: [0.3, 0.7, 0.3] }}
transition={{
pathLength: { duration: 2, delay: line.id * 0.3 },
opacity: { duration: 3, repeat: Infinity, ease: "easeInOut" },
}}
/>
))}
{/* Vertical Data Streams */}
{[...Array(6)].map((_, i) => (
<motion.line
key={`vertical-${i}`}
x1={`${10 + i * 18}%`}
y1="0%"
x2={`${10 + i * 18}%`}
y2="100%"
stroke="rgba(51, 102, 255, 0.3)"
strokeWidth="1.5"
strokeDasharray="8 16"
initial={{ strokeDashoffset: 0 }}
animate={{ strokeDashoffset: 100 }}
transition={{
duration: 3,
repeat: Infinity,
ease: "linear",
delay: i * 0.4,
}}
/>
))}
{/* Circuit Nodes with pulse ring */}
{circuitNodes.map((node) => (
<g key={node.id}>
{/* Pulse ring */}
<motion.circle
cx={`${node.x}%`}
cy={`${node.y}%`}
r="6"
fill="none"
stroke="#3366ff"
strokeWidth="1"
animate={{
r: [6, 12, 6],
opacity: [0.8, 0, 0.8],
}}
transition={{
duration: 2.5,
repeat: Infinity,
delay: node.pulseDelay,
ease: "easeOut",
}}
/>
{/* Core node */}
<motion.circle
cx={`${node.x}%`}
cy={`${node.y}%`}
r="4"
fill="#3366ff"
animate={{
opacity: [0.7, 1, 0.7],
r: [3, 4.5, 3],
}}
transition={{
duration: 2,
repeat: Infinity,
delay: node.pulseDelay,
ease: "easeInOut",
}}
/>
</g>
))}
</svg>
{/* Floating Data Particles - highly visible */}
{particles.map((particle) => (
<motion.div
key={particle.id}
className="absolute rounded-full bg-neon"
style={{
width: `${particle.size}px`,
height: `${particle.size}px`,
left: `${particle.x}%`,
top: `${particle.y}%`,
boxShadow: '0 0 12px rgba(51, 102, 255, 0.9), 0 0 24px rgba(51, 102, 255, 0.5)',
willChange: 'transform, opacity',
}}
animate={{
y: [0, -500],
opacity: [0, particle.opacity, particle.opacity, 0],
}}
transition={{
duration: particle.duration,
repeat: Infinity,
delay: particle.delay,
ease: "linear",
}}
/>
))}
{/* Scanline Effect */}
<motion.div
className="absolute inset-0 pointer-events-none"
style={{
background: `repeating-linear-gradient(
0deg,
transparent,
transparent 2px,
rgba(51, 102, 255, 0.04) 2px,
rgba(51, 102, 255, 0.04) 4px
)`,
}}
animate={{
opacity: [0.3, 0.5, 0.3],
}}
transition={{
duration: 2,
repeat: Infinity,
ease: "easeInOut",
}}
/>
{/* Radial Glows */}
{[
{ x: 20, y: 30, size: 300 },
{ x: 80, y: 70, size: 350 },
{ x: 50, y: 50, size: 400 },
].map((pos, i) => (
<motion.div
key={`glow-${i}`}
className="absolute rounded-full pointer-events-none"
style={{
left: `${pos.x}%`,
top: `${pos.y}%`,
width: `${pos.size}px`,
height: `${pos.size}px`,
background: 'radial-gradient(circle, rgba(51, 102, 255, 0.25) 0%, transparent 70%)',
transform: 'translate(-50%, -50%)',
willChange: 'transform',
}}
animate={{
scale: [1, 1.3, 1],
opacity: [0.5, 0.8, 0.5],
}}
transition={{
duration: 5,
repeat: Infinity,
delay: i * 1.5,
ease: "easeInOut",
}}
/>
))}
{/* Corner Accent Glows */}
<div className="absolute top-0 left-0 w-96 h-96 bg-gradient-to-br from-neon/20 to-transparent rounded-full opacity-60 pointer-events-none" />
<div className="absolute bottom-0 right-0 w-[500px] h-[500px] bg-gradient-to-tl from-neon/20 to-transparent rounded-full opacity-60 pointer-events-none" />
</div>
);
};
export default BackgroundAnimations;

View File

@ -1,8 +1,6 @@
import { ArrowRight, Clock, DollarSign, Phone } from 'lucide-react'; import { ArrowRight, Clock, DollarSign, Phone } from 'lucide-react';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { motion, useInView } from 'framer-motion'; import ScrollReveal from '../ScrollReveal';
import { useRef } from 'react';
import { fadeInUp, staggerContainer, staggerItem, buttonHover, buttonTap } from '@/utils/animations';
const CTASection = () => { const CTASection = () => {
const faqs = [ const faqs = [
@ -23,13 +21,6 @@ const CTASection = () => {
} }
]; ];
const headerRef = useRef(null);
const ctaRef = useRef(null);
const faqRef = useRef(null);
const isHeaderInView = useInView(headerRef, { once: true, margin: "-100px" });
const isCtaInView = useInView(ctaRef, { once: true, margin: "-100px" });
const isFaqInView = useInView(faqRef, { once: true, margin: "-100px" });
return ( return (
<section className="py-24 bg-background-deep relative overflow-hidden"> <section className="py-24 bg-background-deep relative overflow-hidden">
{/* Background decoration */} {/* Background decoration */}
@ -38,141 +29,88 @@ const CTASection = () => {
<div className="relative max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> <div className="relative max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="max-w-4xl mx-auto text-center"> <div className="max-w-4xl mx-auto text-center">
<motion.div <ScrollReveal>
ref={headerRef}
initial="hidden"
animate={isHeaderInView ? "visible" : "hidden"}
variants={fadeInUp}
>
<h2 className="font-heading font-bold text-4xl sm:text-5xl lg:text-6xl text-foreground mb-6"> <h2 className="font-heading font-bold text-4xl sm:text-5xl lg:text-6xl text-foreground mb-6">
Ready for <motion.span Ready for <span className="text-neon text-glow">reliable IT?</span>
className="text-neon text-glow"
animate={{
textShadow: [
"0 0 20px rgba(51, 102, 255, 0.5)",
"0 0 40px rgba(51, 102, 255, 0.8)",
"0 0 20px rgba(51, 102, 255, 0.5)"
]
}}
transition={{ duration: 3, repeat: Infinity, ease: "easeInOut" }}
>
reliable IT?
</motion.span>
</h2> </h2>
<p className="text-xl text-foreground-muted mb-12 leading-relaxed"> <p className="text-xl text-foreground-muted mb-12 leading-relaxed">
Join 150+ Coastal Bend businesses that trust us with their technology. Join 150+ Coastal Bend businesses that trust us with their technology.
Get started with a free 20-minute assessment. Get started with a free 20-minute assessment.
</p> </p>
</motion.div> </ScrollReveal>
{/* Primary CTAs */} {/* Primary CTAs */}
<motion.div <ScrollReveal delay={200}>
ref={ctaRef} <div className="flex flex-col sm:flex-row gap-4 justify-center items-center mb-16">
initial={{ opacity: 0, y: 30 }}
animate={isCtaInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 30 }}
transition={{ delay: 0.2, duration: 0.6 }}
className="flex flex-col sm:flex-row gap-4 justify-center items-center mb-16"
>
<motion.div whileHover={buttonHover} whileTap={buttonTap}>
<Link <Link
to="/contact" to="/contact"
className="btn-neon group flex items-center space-x-2 text-lg px-8 py-4" className="btn-neon group flex items-center space-x-2 text-lg px-8 py-4"
> >
<span>Book a 20-minute assessment</span> <span>Book a 20-minute assessment</span>
<motion.div <ArrowRight className="w-5 h-5 transition-transform group-hover:translate-x-1" />
animate={{ x: [0, 3, 0] }}
transition={{ duration: 1.5, repeat: Infinity, ease: "easeInOut" }}
>
<ArrowRight className="w-5 h-5" />
</motion.div>
</Link> </Link>
</motion.div>
<motion.div whileHover={buttonHover} whileTap={buttonTap}>
<Link <Link
to="/contact" to="/contact"
className="btn-ghost group flex items-center space-x-2 text-lg px-8 py-4" className="btn-ghost group flex items-center space-x-2 text-lg px-8 py-4"
> >
<span>Send a message</span> <span>Send a message</span>
</Link> </Link>
</motion.div> </div>
</motion.div> </ScrollReveal>
{/* Micro FAQ */} {/* Micro FAQ */}
<motion.div <ScrollReveal delay={400}>
ref={faqRef} <div className="grid grid-cols-1 md:grid-cols-3 gap-8">
initial="hidden" {faqs.map((faq, index) => {
animate={isFaqInView ? "visible" : "hidden"} const Icon = faq.icon;
variants={staggerContainer}
className="grid grid-cols-1 md:grid-cols-3 gap-8" return (
> <div key={faq.question} className="text-left">
{faqs.map((faq, index) => { <div className="flex items-start space-x-3">
const Icon = faq.icon; <div className="w-8 h-8 bg-neon/20 rounded-lg flex items-center justify-center flex-shrink-0 mt-1">
<Icon className="w-4 h-4 text-neon" />
return ( </div>
<motion.div <div>
key={faq.question} <h3 className="font-semibold text-foreground mb-2">
variants={staggerItem} {faq.question}
className="text-left" </h3>
> <p className="text-sm text-foreground-muted">
<motion.div {faq.answer}
className="flex items-start space-x-3" </p>
whileHover={{ x: 5 }} </div>
transition={{ duration: 0.2 }}
>
<motion.div
className="w-8 h-8 bg-neon/20 rounded-lg flex items-center justify-center flex-shrink-0 mt-1"
whileHover={{ rotate: 360, scale: 1.1 }}
transition={{ duration: 0.5 }}
>
<Icon className="w-4 h-4 text-neon" />
</motion.div>
<div>
<h3 className="font-semibold text-foreground mb-2">
{faq.question}
</h3>
<p className="text-sm text-foreground-muted">
{faq.answer}
</p>
</div> </div>
</motion.div> </div>
</motion.div> );
); })}
})} </div>
</motion.div> </ScrollReveal>
{/* Contact info */} {/* Contact info */}
<motion.div <ScrollReveal delay={600}>
initial={{ opacity: 0, y: 20 }} <div className="mt-16 pt-8 border-t border-border/30">
animate={isFaqInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 20 }} <p className="text-sm text-foreground-muted mb-4">
transition={{ delay: 0.6, duration: 0.6 }} Ready to talk? We're here to help.
className="mt-16 pt-8 border-t border-border/30" </p>
> <div className="flex flex-col sm:flex-row gap-4 justify-center items-center text-sm">
<p className="text-sm text-foreground-muted mb-4"> <a
Ready to talk? We're here to help. href="tel:+1-361-555-0123"
</p> className="text-neon hover:text-neon/80 transition-colors flex items-center"
<div className="flex flex-col sm:flex-row gap-4 justify-center items-center text-sm"> >
<motion.a <Phone className="w-4 h-4 mr-2" />
href="tel:+1-361-555-0123" (361) 555-0123
className="text-neon hover:text-neon/80 transition-colors flex items-center" </a>
whileHover={{ scale: 1.05 }} <span className="hidden sm:block text-border">|</span>
whileTap={{ scale: 0.95 }} <a
> href="mailto:info@bayareaaffiliates.com"
<Phone className="w-4 h-4 mr-2" /> className="text-neon hover:text-neon/80 transition-colors"
(361) 555-0123 >
</motion.a> info@bayareaaffiliates.com
<span className="hidden sm:block text-border">|</span> </a>
<motion.a </div>
href="mailto:info@bayareaaffiliates.com"
className="text-neon hover:text-neon/80 transition-colors"
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
>
info@bayareaaffiliates.com
</motion.a>
</div> </div>
</motion.div> </ScrollReveal>
</div> </div>
</div> </div>
</section> </section>

View File

@ -1,165 +1,87 @@
import { ArrowRight, Play } from 'lucide-react'; import { ArrowRight, Play } from 'lucide-react';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { motion, useScroll, useTransform } from 'framer-motion'; import { useEffect, useRef } from 'react';
import { heroVariants, heroItemVariants, buttonHover, buttonTap, easing } from '@/utils/animations'; import heroNetwork from '@/assets/hero-network.jpg';
import BackgroundAnimations from './BackgroundAnimations';
const HeroSection = () => { const HeroSection = () => {
const { scrollY } = useScroll(); const imageRef = useRef<HTMLImageElement>(null);
// Smooth parallax effect with Framer Motion useEffect(() => {
const y = useTransform(scrollY, [0, 500], [0, 150]); const handleScroll = () => {
const opacity = useTransform(scrollY, [0, 300], [1, 0]); if (imageRef.current) {
const scrolled = window.pageYOffset;
const parallax = scrolled * 0.5;
imageRef.current.style.transform = `translateY(${parallax}px) scale(1.1)`;
}
};
window.addEventListener('scroll', handleScroll, { passive: true });
return () => window.removeEventListener('scroll', handleScroll);
}, []);
return ( return (
<section className="section-pin"> <section className="section-pin">
<div className="relative h-full flex items-center justify-center overflow-hidden"> <div className="relative h-full flex items-center justify-center overflow-hidden">
{/* Background image with smooth parallax */} {/* Background image with parallax */}
<motion.div <div className="absolute inset-0 overflow-hidden">
className="absolute inset-0 overflow-hidden" <img
style={{ y }} ref={imageRef}
> src="/serverroom.png"
<picture> alt="Modern IT infrastructure with network connections"
<source type="image/avif" srcSet="/serverroom.avif" /> className="w-full h-[110%] object-cover will-change-transform"
<source type="image/webp" srcSet="/serverroom.webp" /> style={{ transform: 'translateY(0px) scale(1.1)' }}
<motion.img />
src="/serverroom.png" {/* Dark overlay */}
alt="Modern IT infrastructure with network connections and server equipment" <div className="absolute inset-0 bg-black/35"></div>
className="w-full h-[110%] object-cover" </div>
initial={{ scale: 1.1, opacity: 0 }}
animate={{ scale: 1.1, opacity: 1 }}
transition={{ duration: 1.2, ease: easing.elegant }}
loading="eager"
fetchPriority="high"
/>
</picture>
{/* Animated background effects */} {/* Main content */}
<BackgroundAnimations /> <div className="relative z-10 max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
{/* Darker overlay for better text contrast */}
<div className="absolute inset-0 bg-gradient-to-b from-black/60 via-black/50 to-black/60"></div>
</motion.div>
{/* Main content with staggered animations */}
<motion.div
className="relative z-10 max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 text-center"
variants={heroVariants}
initial="hidden"
animate="visible"
style={{ opacity }}
>
<div className="max-w-4xl mx-auto"> <div className="max-w-4xl mx-auto">
{/* Badge */} {/* Badge */}
<motion.div <div className="inline-flex items-center px-4 py-2 rounded-full bg-neon/20 border border-neon/40 text-neon text-sm font-medium mb-8 drop-shadow-[0_0_10px_rgba(51,102,255,0.5)]">
variants={heroItemVariants} <span className="w-2 h-2 bg-neon rounded-full mr-2 animate-glow-pulse"></span>
className="inline-flex items-center px-4 py-2 rounded-full bg-neon/20 border border-neon/40 text-neon text-sm font-medium mb-8 drop-shadow-[0_0_10px_rgba(51,102,255,0.5)]"
>
<motion.span
className="w-2 h-2 bg-neon rounded-full mr-2"
animate={{
scale: [1, 1.2, 1],
opacity: [1, 0.7, 1],
}}
transition={{
duration: 2,
repeat: Infinity,
ease: "easeInOut",
}}
/>
Serving the Coastal Bend since 2010 Serving the Coastal Bend since 2010
</motion.div> </div>
{/* Main headline */} {/* Main headline */}
<motion.h1 <h1 className="font-heading font-bold text-5xl sm:text-6xl lg:text-7xl text-white mb-6 text-balance drop-shadow-[0_0_20px_rgba(255,255,255,0.3)]">
variants={heroItemVariants}
className="font-heading font-bold text-5xl sm:text-6xl lg:text-7xl text-white mb-6 text-balance drop-shadow-[0_0_20px_rgba(255,255,255,0.3)]"
>
Modern IT that keeps your{' '} Modern IT that keeps your{' '}
<motion.span <span className="text-neon text-glow drop-shadow-[0_0_30px_rgba(51,102,255,0.8)]">business moving</span>
className="text-neon text-glow drop-shadow-[0_0_30px_rgba(51,102,255,0.8)]" </h1>
animate={{
textShadow: [
'0 0 20px rgba(51,102,255,0.5)',
'0 0 30px rgba(51,102,255,0.8)',
'0 0 20px rgba(51,102,255,0.5)',
],
}}
transition={{
duration: 3,
repeat: Infinity,
ease: "easeInOut",
}}
>
business moving
</motion.span>
</motion.h1>
{/* Subheadline */} {/* Subheadline */}
<motion.p <p className="text-xl sm:text-2xl text-white/95 mb-12 max-w-3xl mx-auto leading-relaxed drop-shadow-[0_0_15px_rgba(255,255,255,0.2)]">
variants={heroItemVariants}
className="text-xl sm:text-2xl text-white/95 mb-12 max-w-3xl mx-auto leading-relaxed drop-shadow-[0_0_15px_rgba(255,255,255,0.2)]"
>
From fast devices to secure remote access and resilient networks we design, From fast devices to secure remote access and resilient networks we design,
run and protect your tech so you can focus on growth. run and protect your tech so you can focus on growth.
</motion.p> </p>
{/* CTA buttons with hover animations */} {/* CTA buttons */}
<motion.div <div className="flex flex-col sm:flex-row gap-4 justify-center items-center">
variants={heroItemVariants} <Link
className="flex flex-col sm:flex-row gap-4 justify-center items-center" to="/contact"
> className="btn-neon group flex items-center space-x-2"
<motion.div
whileHover={buttonHover}
whileTap={buttonTap}
> >
<Link <span>Get in touch</span>
to="/contact" <ArrowRight className="w-5 h-5 transition-transform group-hover:translate-x-1" />
className="btn-neon group flex items-center space-x-2" </Link>
>
<span>Get in touch</span>
<motion.div
animate={{ x: [0, 3, 0] }}
transition={{ duration: 1.5, repeat: Infinity, ease: "easeInOut" }}
>
<ArrowRight className="w-5 h-5" />
</motion.div>
</Link>
</motion.div>
<motion.div <button className="btn-ghost group flex items-center space-x-2">
whileHover={buttonHover} <Play className="w-5 h-5 transition-transform group-hover:scale-110" />
whileTap={buttonTap} <span>See our system</span>
> </button>
<Link </div>
to="/services"
className="btn-ghost group flex items-center space-x-2"
>
<Play className="w-5 h-5" />
<span>See our services</span>
</Link>
</motion.div>
</motion.div>
</div> </div>
</motion.div> </div>
{/* Animated scroll indicator */} {/* Scroll indicator */}
<motion.div <div className="absolute bottom-8 left-1/2 transform -translate-x-1/2">
className="absolute bottom-8 left-1/2 transform -translate-x-1/2"
initial={{ opacity: 0, y: -20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 1.5, duration: 0.8 }}
>
<div className="w-6 h-10 border-2 border-neon/60 rounded-full flex justify-center drop-shadow-[0_0_10px_rgba(51,102,255,0.3)]"> <div className="w-6 h-10 border-2 border-neon/60 rounded-full flex justify-center drop-shadow-[0_0_10px_rgba(51,102,255,0.3)]">
<motion.div <div className="w-1 h-3 bg-neon rounded-full mt-2 animate-bounce"></div>
className="w-1 h-3 bg-neon rounded-full mt-2"
animate={{ y: [0, 12, 0] }}
transition={{ duration: 1.5, repeat: Infinity, ease: "easeInOut" }}
/>
</div> </div>
</motion.div> </div>
</div> </div>
</section> </section>
); );

View File

@ -1,20 +1,10 @@
import { useEffect, useRef, useState } from 'react'; import { useEffect, useRef, useState } from 'react';
import { Search, Shield, Cog, Zap } from 'lucide-react'; import { Search, Shield, Cog, Zap } from 'lucide-react';
import { motion, useInView, useScroll, useTransform } from 'framer-motion'; import ScrollReveal from '../ScrollReveal';
import { fadeInUp, scaleIn } from '@/utils/animations';
const ProcessTimeline = () => { const ProcessTimeline = () => {
const [activeStep, setActiveStep] = useState(0); const [activeStep, setActiveStep] = useState(0);
const sectionRef = useRef<HTMLDivElement>(null); const sectionRef = useRef<HTMLDivElement>(null);
const headerRef = useRef(null);
const isHeaderInView = useInView(headerRef, { once: true, margin: "-100px" });
// Smooth scroll-based timeline progress
const { scrollYProgress } = useScroll({
target: sectionRef,
offset: ["start end", "end start"]
});
const timelineProgress = useTransform(scrollYProgress, [0.2, 0.8], [0, 100]);
const steps = [ const steps = [
{ {
@ -73,12 +63,7 @@ const ProcessTimeline = () => {
</div> </div>
<div className="relative max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> <div className="relative max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<motion.div <ScrollReveal>
ref={headerRef}
initial="hidden"
animate={isHeaderInView ? "visible" : "hidden"}
variants={fadeInUp}
>
<div className="text-center mb-20"> <div className="text-center mb-20">
<h2 className="font-heading font-bold text-4xl sm:text-5xl text-foreground mb-6"> <h2 className="font-heading font-bold text-4xl sm:text-5xl text-foreground mb-6">
How we <span className="text-neon">transform</span> your IT How we <span className="text-neon">transform</span> your IT
@ -87,14 +72,14 @@ const ProcessTimeline = () => {
Our proven four-phase methodology ensures systematic improvement and lasting results. Our proven four-phase methodology ensures systematic improvement and lasting results.
</p> </p>
</div> </div>
</motion.div> </ScrollReveal>
<div className="relative"> <div className="relative">
{/* Timeline line */} {/* Timeline line */}
<div className="absolute left-8 lg:left-1/2 lg:transform lg:-translate-x-1/2 top-0 bottom-0 w-px bg-border"> <div className="absolute left-8 lg:left-1/2 lg:transform lg:-translate-x-1/2 top-0 bottom-0 w-px bg-border">
<motion.div <div
className="absolute top-0 left-0 w-full bg-neon" className="absolute top-0 left-0 w-full bg-neon transition-all duration-500 ease-out"
style={{ height: useTransform(timelineProgress, (value) => `${value}%`) }} style={{ height: `${(activeStep + 1) * 25}%` }}
/> />
</div> </div>
@ -104,35 +89,17 @@ const ProcessTimeline = () => {
const Icon = step.icon; const Icon = step.icon;
const isActive = index <= activeStep; const isActive = index <= activeStep;
const isEven = index % 2 === 0; const isEven = index % 2 === 0;
const stepRef = useRef(null);
const isInView = useInView(stepRef, { once: true, margin: "-150px" });
return ( return (
<motion.div <ScrollReveal key={step.title} delay={index * 100}>
key={step.title}
ref={stepRef}
initial="hidden"
animate={isInView ? "visible" : "hidden"}
variants={fadeInUp}
transition={{ delay: index * 0.1 }}
>
<div className={`relative flex flex-col lg:flex-row items-center ${ <div className={`relative flex flex-col lg:flex-row items-center ${
isEven ? '' : 'lg:flex-row-reverse' isEven ? '' : 'lg:flex-row-reverse'
}`}> }`}>
{/* Step content */} {/* Step content */}
<motion.div <div className={`flex-1 ${isEven ? 'lg:pr-16' : 'lg:pl-16'} ${
className={`flex-1 ${isEven ? 'lg:pr-16' : 'lg:pl-16'} ${ isEven ? 'lg:text-right' : 'lg:text-left'
isEven ? 'lg:text-right' : 'lg:text-left' } text-center lg:text-left`}>
} text-center lg:text-left`} <div className="card-dark p-8 max-w-lg mx-auto lg:mx-0">
initial={{ opacity: 0, x: isEven ? -40 : 40 }}
animate={isInView ? { opacity: 1, x: 0 } : { opacity: 0, x: isEven ? -40 : 40 }}
transition={{ delay: index * 0.1 + 0.2, duration: 0.6 }}
>
<motion.div
className="card-dark p-8 max-w-lg mx-auto lg:mx-0"
whileHover={{ y: -5, boxShadow: "0 0 30px rgba(51, 102, 255, 0.3)" }}
transition={{ duration: 0.3 }}
>
<div className="mb-4"> <div className="mb-4">
<span className="text-sm font-medium text-neon uppercase tracking-wider"> <span className="text-sm font-medium text-neon uppercase tracking-wider">
Step {index + 1} Step {index + 1}
@ -147,34 +114,24 @@ const ProcessTimeline = () => {
<p className="text-sm text-foreground-muted"> <p className="text-sm text-foreground-muted">
{step.details} {step.details}
</p> </p>
</motion.div> </div>
</motion.div> </div>
{/* Timeline dot */} {/* Timeline dot */}
<div className="relative z-10 my-8 lg:my-0"> <div className="relative z-10 my-8 lg:my-0">
<motion.div <div className={`w-16 h-16 rounded-full border-4 flex items-center justify-center transition-all duration-500 ${
className={`w-16 h-16 rounded-full border-4 flex items-center justify-center ${ isActive
isActive ? 'border-neon bg-neon text-neon-foreground shadow-neon'
? 'border-neon bg-neon text-neon-foreground shadow-neon' : 'border-border bg-background text-foreground-muted'
: 'border-border bg-background text-foreground-muted' }`}>
}`}
initial={{ scale: 0, rotate: -180 }}
animate={isInView ? { scale: 1, rotate: 0 } : { scale: 0, rotate: -180 }}
transition={{
delay: index * 0.1 + 0.3,
duration: 0.6,
type: "spring",
stiffness: 200
}}
>
<Icon className="w-6 h-6" /> <Icon className="w-6 h-6" />
</motion.div> </div>
</div> </div>
{/* Spacer for layout */} {/* Spacer for layout */}
<div className="flex-1 hidden lg:block"></div> <div className="flex-1 hidden lg:block"></div>
</div> </div>
</motion.div> </ScrollReveal>
); );
})} })}
</div> </div>

View File

@ -1,8 +1,6 @@
import { MapPin, Star, Users } from 'lucide-react'; import { MapPin, Star, Users } from 'lucide-react';
import { motion, useInView } from 'framer-motion'; import ScrollReveal from '../ScrollReveal';
import { useRef } from 'react';
import CountUpNumber from '../CountUpNumber'; import CountUpNumber from '../CountUpNumber';
import { fadeInUp, scaleIn, staggerContainer, staggerItem } from '@/utils/animations';
const ProofSection = () => { const ProofSection = () => {
const stats = [ const stats = [
@ -19,13 +17,6 @@ const ProofSection = () => {
company: "Coastal Medical Group" company: "Coastal Medical Group"
}; };
const headerRef = useRef(null);
const statsRef = useRef(null);
const testimonialRef = useRef(null);
const isHeaderInView = useInView(headerRef, { once: true, margin: "-100px" });
const isStatsInView = useInView(statsRef, { once: true, margin: "-100px" });
const isTestimonialInView = useInView(testimonialRef, { once: true, margin: "-100px" });
return ( return (
<section className="py-24 bg-background relative overflow-hidden"> <section className="py-24 bg-background relative overflow-hidden">
{/* Background decoration */} {/* Background decoration */}
@ -33,27 +24,12 @@ const ProofSection = () => {
<div className="absolute top-0 left-1/2 transform -translate-x-1/2 w-96 h-96 bg-neon/5 rounded-full blur-3xl"></div> <div className="absolute top-0 left-1/2 transform -translate-x-1/2 w-96 h-96 bg-neon/5 rounded-full blur-3xl"></div>
<div className="relative max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> <div className="relative max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<motion.div <ScrollReveal>
ref={headerRef}
initial="hidden"
animate={isHeaderInView ? "visible" : "hidden"}
variants={fadeInUp}
>
<div className="text-center mb-16"> <div className="text-center mb-16">
<motion.div <div className="inline-flex items-center px-4 py-2 rounded-full bg-neon/10 border border-neon/30 text-neon text-sm font-medium mb-8">
className="inline-flex items-center px-4 py-2 rounded-full bg-neon/10 border border-neon/30 text-neon text-sm font-medium mb-8"
animate={{
boxShadow: [
"0 0 20px rgba(51, 102, 255, 0.2)",
"0 0 30px rgba(51, 102, 255, 0.4)",
"0 0 20px rgba(51, 102, 255, 0.2)"
]
}}
transition={{ duration: 2, repeat: Infinity, ease: "easeInOut" }}
>
<MapPin className="w-4 h-4 mr-2" /> <MapPin className="w-4 h-4 mr-2" />
Proudly serving the Coastal Bend Proudly serving the Coastal Bend
</motion.div> </div>
<h2 className="font-heading font-bold text-4xl sm:text-5xl text-foreground mb-6"> <h2 className="font-heading font-bold text-4xl sm:text-5xl text-foreground mb-6">
Local expertise for{' '} Local expertise for{' '}
@ -66,92 +42,48 @@ const ProofSection = () => {
tailored solutions that work in the real world. tailored solutions that work in the real world.
</p> </p>
</div> </div>
</motion.div> </ScrollReveal>
{/* Stats */} {/* Stats */}
<motion.div <ScrollReveal delay={200}>
ref={statsRef} <div className="grid grid-cols-2 lg:grid-cols-4 gap-8 mb-20">
initial="hidden" {stats.map((stat, index) => (
animate={isStatsInView ? "visible" : "hidden"} <div key={stat.label} className="text-center">
variants={staggerContainer} <div className="font-heading font-bold text-4xl lg:text-5xl text-neon mb-2">
className="grid grid-cols-2 lg:grid-cols-4 gap-8 mb-20" <CountUpNumber
> value={stat.value}
{stats.map((stat, index) => ( duration={2000 + index * 200}
<motion.div className="inline-block"
key={stat.label} />
variants={staggerItem} </div>
className="text-center" <div className="text-foreground-muted text-sm lg:text-base">
> {stat.label}
<div className="font-heading font-bold text-4xl lg:text-5xl text-neon mb-2"> </div>
<CountUpNumber
value={stat.value}
duration={2000 + index * 200}
className="inline-block"
/>
</div> </div>
<motion.div ))}
className="text-foreground-muted text-sm lg:text-base" </div>
initial={{ opacity: 0, y: 10 }} </ScrollReveal>
animate={isStatsInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 10 }}
transition={{ delay: index * 0.1 + 0.3, duration: 0.5 }}
>
{stat.label}
</motion.div>
</motion.div>
))}
</motion.div>
{/* Testimonial */} {/* Testimonial */}
<motion.div <ScrollReveal delay={400}>
ref={testimonialRef} <div className="card-dark p-8 lg:p-12 max-w-4xl mx-auto">
initial="hidden"
animate={isTestimonialInView ? "visible" : "hidden"}
variants={scaleIn}
>
<motion.div
className="card-dark p-8 lg:p-12 max-w-4xl mx-auto"
whileHover={{ y: -5, boxShadow: "0 0 40px rgba(51, 102, 255, 0.3)" }}
transition={{ duration: 0.3 }}
>
<div className="flex flex-col lg:flex-row items-start gap-8"> <div className="flex flex-col lg:flex-row items-start gap-8">
{/* Quote */} {/* Quote */}
<div className="flex-1"> <div className="flex-1">
<motion.div <div className="flex items-center mb-6">
className="flex items-center mb-6"
initial="hidden"
animate={isTestimonialInView ? "visible" : "hidden"}
variants={staggerContainer}
>
{[...Array(5)].map((_, i) => ( {[...Array(5)].map((_, i) => (
<motion.div <Star key={i} className="w-5 h-5 text-neon fill-current" />
key={i}
variants={staggerItem}
whileHover={{ scale: 1.2, rotate: 360 }}
transition={{ duration: 0.4 }}
>
<Star className="w-5 h-5 text-neon fill-current" />
</motion.div>
))} ))}
</motion.div> </div>
<blockquote className="text-lg lg:text-xl text-foreground leading-relaxed mb-6"> <blockquote className="text-lg lg:text-xl text-foreground leading-relaxed mb-6">
"{testimonial.quote}" "{testimonial.quote}"
</blockquote> </blockquote>
<div className="flex items-center"> <div className="flex items-center">
<motion.div <div className="w-12 h-12 bg-neon/20 rounded-full flex items-center justify-center mr-4">
className="w-12 h-12 bg-neon/20 rounded-full flex items-center justify-center mr-4"
animate={{
boxShadow: [
"0 0 10px rgba(51, 102, 255, 0.3)",
"0 0 20px rgba(51, 102, 255, 0.5)",
"0 0 10px rgba(51, 102, 255, 0.3)"
]
}}
transition={{ duration: 2, repeat: Infinity }}
>
<Users className="w-6 h-6 text-neon" /> <Users className="w-6 h-6 text-neon" />
</motion.div> </div>
<div> <div>
<div className="font-semibold text-foreground">{testimonial.author}</div> <div className="font-semibold text-foreground">{testimonial.author}</div>
<div className="text-foreground-muted text-sm"> <div className="text-foreground-muted text-sm">
@ -161,43 +93,29 @@ const ProofSection = () => {
</div> </div>
</div> </div>
</div> </div>
</motion.div> </div>
</motion.div> </ScrollReveal>
{/* Service area */} {/* Service area */}
<motion.div <ScrollReveal delay={600}>
initial={{ opacity: 0, y: 30 }} <div className="mt-16 text-center">
animate={isTestimonialInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 30 }} <h3 className="font-heading font-semibold text-xl text-foreground mb-6">
transition={{ delay: 0.4, duration: 0.6 }} Serving businesses throughout the Coastal Bend
className="mt-16 text-center" </h3>
>
<h3 className="font-heading font-semibold text-xl text-foreground mb-6">
Serving businesses throughout the Coastal Bend
</h3>
<motion.div <div className="flex flex-wrap justify-center items-center gap-6 text-foreground-muted">
className="flex flex-wrap justify-center items-center gap-6 text-foreground-muted" {[
initial="hidden" 'Corpus Christi', 'Portland', 'Ingleside', 'Aransas Pass',
animate={isTestimonialInView ? "visible" : "hidden"} 'Rockport', 'Fulton', 'Sinton', 'Mathis'
variants={staggerContainer} ].map((city) => (
> <span key={city} className="flex items-center text-sm">
{[ <MapPin className="w-3 h-3 mr-1 text-neon" />
'Corpus Christi', 'Portland', 'Ingleside', 'Aransas Pass', {city}
'Rockport', 'Fulton', 'Sinton', 'Mathis' </span>
].map((city) => ( ))}
<motion.span </div>
key={city} </div>
className="flex items-center text-sm" </ScrollReveal>
variants={staggerItem}
whileHover={{ scale: 1.1, color: "rgba(51, 102, 255, 1)" }}
transition={{ duration: 0.2 }}
>
<MapPin className="w-3 h-3 mr-1 text-neon" />
{city}
</motion.span>
))}
</motion.div>
</motion.div>
</div> </div>
</section> </section>
); );

View File

@ -1,8 +1,6 @@
import { Monitor, Wifi, Cloud, Shield, Database, Settings } from 'lucide-react'; import { Monitor, Wifi, Cloud, Shield, Database, Settings } from 'lucide-react';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { motion, useInView } from 'framer-motion'; import ScrollReveal from '../ScrollReveal';
import { useRef } from 'react';
import { fadeInUp, staggerContainer, staggerItem, cardHover, glowHover } from '@/utils/animations';
const ServicesOverview = () => { const ServicesOverview = () => {
const services = [ const services = [
@ -44,11 +42,6 @@ const ServicesOverview = () => {
} }
]; ];
const headerRef = useRef(null);
const gridRef = useRef(null);
const isHeaderInView = useInView(headerRef, { once: true, margin: "-100px" });
const isGridInView = useInView(gridRef, { once: true, margin: "-100px" });
return ( return (
<section className="py-24 bg-background-deep relative overflow-hidden"> <section className="py-24 bg-background-deep relative overflow-hidden">
{/* Background decoration */} {/* Background decoration */}
@ -57,12 +50,7 @@ const ServicesOverview = () => {
<div className="absolute bottom-1/4 left-0 w-96 h-96 bg-neon/5 rounded-full blur-3xl"></div> <div className="absolute bottom-1/4 left-0 w-96 h-96 bg-neon/5 rounded-full blur-3xl"></div>
<div className="relative max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> <div className="relative max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<motion.div <ScrollReveal>
ref={headerRef}
initial="hidden"
animate={isHeaderInView ? "visible" : "hidden"}
variants={fadeInUp}
>
<div className="text-center mb-16"> <div className="text-center mb-16">
<h2 className="font-heading font-bold text-4xl sm:text-5xl text-foreground mb-6"> <h2 className="font-heading font-bold text-4xl sm:text-5xl text-foreground mb-6">
Complete IT solutions for{' '} Complete IT solutions for{' '}
@ -72,110 +60,66 @@ const ServicesOverview = () => {
From desktop support to enterprise infrastructure we've got your technology covered. From desktop support to enterprise infrastructure we've got your technology covered.
</p> </p>
</div> </div>
</motion.div> </ScrollReveal>
<motion.div <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
ref={gridRef}
initial="hidden"
animate={isGridInView ? "visible" : "hidden"}
variants={staggerContainer}
className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8"
>
{services.map((service, index) => { {services.map((service, index) => {
const Icon = service.icon; const Icon = service.icon;
return ( return (
<motion.div key={service.title} variants={staggerItem} className="h-full"> <ScrollReveal key={service.title} delay={index * 100}>
<motion.div <div className="card-dark p-8 group hover:shadow-neon transition-all duration-500 hover:-translate-y-1">
className="card-dark p-8 h-full relative overflow-hidden group border border-white/5 hover:border-neon/50 transition-colors duration-500"
whileHover={{
y: -10,
scale: 1.02,
boxShadow: "0 20px 40px -10px rgba(51, 102, 255, 0.3)"
}}
transition={{ duration: 0.4, ease: "easeOut" }}
>
{/* Subtle gradient background nice touch */}
<div className="absolute inset-0 bg-gradient-to-br from-neon/5 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-500" />
{/* Icon */} {/* Icon */}
<motion.div <div className="w-12 h-12 bg-neon/20 rounded-xl flex items-center justify-center mb-6 group-hover:bg-neon/30 transition-colors">
className="w-12 h-12 bg-neon/10 rounded-xl flex items-center justify-center mb-6 relative z-10 group-hover:bg-neon/20 transition-colors duration-300" <Icon className="w-6 h-6 text-neon" />
whileHover={{ rotate: 360, scale: 1.1 }} </div>
transition={{ duration: 0.6 }}
>
<Icon className="w-6 h-6 text-neon drop-shadow-[0_0_8px_rgba(51,102,255,0.6)]" />
</motion.div>
{/* Content */} {/* Content */}
<div className="relative z-10"> <h3 className="font-heading font-bold text-xl text-foreground mb-4">
<h3 className="font-heading font-bold text-xl text-foreground mb-4 group-hover:text-neon transition-colors duration-300"> {service.title}
{service.title} </h3>
</h3>
<p className="text-foreground-muted mb-6 leading-relaxed">
{service.description}
</p>
<p className="text-foreground-muted mb-6 leading-relaxed"> {/* Features */}
{service.description} <ul className="space-y-2 mb-6">
</p> {service.features.map((feature) => (
<li key={feature} className="flex items-center text-sm text-foreground-muted">
<div className="w-1.5 h-1.5 bg-neon rounded-full mr-3"></div>
{feature}
</li>
))}
</ul>
{/* Features */} {/* CTA */}
<ul className="space-y-2 mb-6"> <Link
{service.features.map((feature) => ( to="/services"
<li key={feature} className="flex items-center text-sm text-foreground-muted"> className="inline-flex items-center text-neon font-medium hover:text-neon/80 transition-colors group-hover:underline"
<motion.div >
className="w-1.5 h-1.5 bg-neon rounded-full mr-3 shadow-[0_0_5px_rgba(51,102,255,0.8)]" Learn more
animate={{ <svg className="w-4 h-4 ml-1 transition-transform group-hover:translate-x-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
scale: [1, 1.5, 1], <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M9 5l7 7-7 7" />
opacity: [0.7, 1, 0.7] </svg>
}} </Link>
transition={{ </div>
duration: 2, </ScrollReveal>
repeat: Infinity,
delay: index * 0.2
}}
/>
{feature}
</li>
))}
</ul>
{/* CTA */}
<Link
to="/services"
className="inline-flex items-center text-neon font-medium group-hover:translate-x-2 transition-transform duration-300"
>
Learn more
<motion.svg
className="w-4 h-4 ml-1"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
animate={{ x: [0, 3, 0] }}
transition={{ duration: 1.5, repeat: Infinity, ease: "easeInOut" }}
>
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M9 5l7 7-7 7" />
</motion.svg>
</Link>
</div>
</motion.div>
</motion.div>
); );
})} })}
</motion.div> </div>
{/* Bottom CTA */} {/* Bottom CTA */}
<motion.div <ScrollReveal delay={600}>
initial={{ opacity: 0, y: 30 }} <div className="text-center mt-16">
animate={isGridInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 30 }} <Link
transition={{ delay: 0.8, duration: 0.6 }} to="/services"
className="text-center mt-16" className="btn-ghost text-lg px-12 py-4"
> >
<Link View all services
to="/services" </Link>
className="btn-ghost text-lg px-12 py-4" </div>
> </ScrollReveal>
View all services
</Link>
</motion.div>
</div> </div>
</section> </section>
); );

View File

@ -1,54 +0,0 @@
import { motion } from 'framer-motion';
const TrustedBy = () => {
// Placeholder logos - in a real app these would be SVGs
const companies = [
{ name: "TechCorp", color: "bg-blue-400" },
{ name: "SecureNet", color: "bg-indigo-400" },
{ name: "CloudSystems", color: "bg-cyan-400" },
{ name: "FutureData", color: "bg-sky-400" },
{ name: "CyberGuard", color: "bg-teal-400" },
{ name: "NetWorks", color: "bg-emerald-400" },
];
// duplicate for seamless loop
const logos = [...companies, ...companies, ...companies];
return (
<section className="py-10 border-b border-white/5 bg-background-deep relative overflow-hidden">
<p className="text-center text-sm font-medium text-foreground-muted mb-8 tracking-wider uppercase relative z-10 px-4">
Trusted by innovative businesses in Corpus Christi
</p>
<div className="relative flex overflow-hidden mask-linear-fade">
{/* Gradient Masks for smooth fade out at edges */}
<div className="absolute left-0 top-0 bottom-0 w-24 bg-gradient-to-r from-background-deep to-transparent z-10"></div>
<div className="absolute right-0 top-0 bottom-0 w-24 bg-gradient-to-l from-background-deep to-transparent z-10"></div>
<motion.div
className="flex space-x-16 items-center"
animate={{ x: ["0%", "-50%"] }}
transition={{
duration: 30,
repeat: Infinity,
ease: "linear",
repeatType: "loop"
}}
>
{logos.map((company, index) => (
<div key={index} className="flex items-center space-x-2 opacity-50 grayscale hover:grayscale-0 hover:opacity-100 transition-all duration-300">
{/* Fake Logo Icon */}
<div className={`w-8 h-8 rounded-lg ${company.color}/20 flex items-center justify-center`}>
<div className={`w-4 h-4 rounded-full ${company.color}`}></div>
</div>
{/* Fake Logo Text */}
<span className="text-xl font-bold text-white tracking-tight">{company.name}</span>
</div>
))}
</motion.div>
</div>
</section>
);
};
export default TrustedBy;

View File

@ -1,58 +1,6 @@
import { Shield, Zap, Users, ArrowRight } from 'lucide-react'; import { Shield, Zap, Users, ArrowRight } from 'lucide-react';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { motion, useInView, useMotionValue, useSpring, useTransform } from 'framer-motion'; import ScrollReveal from '../ScrollReveal';
import { useRef, MouseEvent } from 'react';
import { fadeInUp, slideInLeft, slideInRight, buttonHover, buttonTap, cardHover } from '@/utils/animations';
// Optimized 3D Tilt Card Component with reduced effect
const TiltCard = ({ children, className = '' }: { children: React.ReactNode; className?: string }) => {
const cardRef = useRef<HTMLDivElement>(null);
const mouseX = useMotionValue(0);
const mouseY = useMotionValue(0);
// Reduced rotation range for subtler effect (10 -> 5 degrees)
const rotateX = useSpring(useTransform(mouseY, [-0.5, 0.5], [5, -5]), {
stiffness: 200,
damping: 25,
});
const rotateY = useSpring(useTransform(mouseX, [-0.5, 0.5], [-5, 5]), {
stiffness: 200,
damping: 25,
});
const handleMouseMove = (e: MouseEvent<HTMLDivElement>) => {
if (!cardRef.current) return;
const rect = cardRef.current.getBoundingClientRect();
const centerX = rect.left + rect.width / 2;
const centerY = rect.top + rect.height / 2;
mouseX.set((e.clientX - centerX) / (rect.width / 2));
mouseY.set((e.clientY - centerY) / (rect.height / 2));
};
const handleMouseLeave = () => {
mouseX.set(0);
mouseY.set(0);
};
return (
<motion.div
ref={cardRef}
onMouseMove={handleMouseMove}
onMouseLeave={handleMouseLeave}
style={{
rotateX,
rotateY,
transformStyle: 'preserve-3d',
willChange: 'transform',
}}
className={className}
whileHover={{ scale: 1.01 }}
transition={{ duration: 0.3 }}
>
{children}
</motion.div>
);
};
const ValuePillars = () => { const ValuePillars = () => {
const pillars = [ const pillars = [
@ -79,21 +27,13 @@ const ValuePillars = () => {
}, },
]; ];
const headerRef = useRef(null);
const isHeaderInView = useInView(headerRef, { once: true, margin: "-100px" });
return ( return (
<section className="py-24 bg-background-deep relative overflow-hidden"> <section className="py-24 bg-background-deep relative overflow-hidden">
{/* Background decoration */} {/* Background decoration */}
<div className="absolute inset-0 grid-overlay opacity-20"></div> <div className="absolute inset-0 grid-overlay opacity-20"></div>
<div className="relative max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> <div className="relative max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<motion.div <ScrollReveal>
ref={headerRef}
initial="hidden"
animate={isHeaderInView ? "visible" : "hidden"}
variants={fadeInUp}
>
<div className="text-center mb-16"> <div className="text-center mb-16">
<h2 className="font-heading font-bold text-4xl sm:text-5xl text-foreground mb-6"> <h2 className="font-heading font-bold text-4xl sm:text-5xl text-foreground mb-6">
Why teams choose us for{' '} Why teams choose us for{' '}
@ -103,96 +43,58 @@ const ValuePillars = () => {
We handle the complexity so you can focus on what you do best. We handle the complexity so you can focus on what you do best.
</p> </p>
</div> </div>
</motion.div> </ScrollReveal>
<div className="space-y-24"> <div className="space-y-24">
{pillars.map((pillar, index) => { {pillars.map((pillar, index) => {
const Icon = pillar.icon; const Icon = pillar.icon;
const isReverse = index % 2 === 1; const isReverse = index % 2 === 1;
const itemRef = useRef(null);
const isInView = useInView(itemRef, { once: true, margin: "-100px" });
return ( return (
<motion.div <ScrollReveal key={pillar.number} delay={index * 200}>
key={pillar.number}
ref={itemRef}
initial="hidden"
animate={isInView ? "visible" : "hidden"}
variants={isReverse ? slideInRight : slideInLeft}
transition={{ delay: 0.2 }}
>
<div className={`flex flex-col ${isReverse ? 'lg:flex-row-reverse' : 'lg:flex-row'} items-center gap-12 lg:gap-16`}> <div className={`flex flex-col ${isReverse ? 'lg:flex-row-reverse' : 'lg:flex-row'} items-center gap-12 lg:gap-16`}>
{/* Content */} {/* Content */}
<div className="flex-1 space-y-6"> <div className="flex-1 space-y-6">
<div className="flex items-center space-x-4"> <div className="flex items-center space-x-4">
<motion.span <span className="text-6xl font-heading font-bold text-neon/30">
className="text-6xl font-heading font-bold text-neon/30"
initial={{ opacity: 0, scale: 0.5 }}
animate={isInView ? { opacity: 1, scale: 1 } : { opacity: 0, scale: 0.5 }}
transition={{ delay: 0.4, duration: 0.6, type: "spring" }}
>
{pillar.number} {pillar.number}
</motion.span> </span>
<motion.div <div className="w-12 h-12 bg-neon/20 rounded-xl flex items-center justify-center">
className="w-12 h-12 bg-neon/20 rounded-xl flex items-center justify-center"
initial={{ opacity: 0, rotate: -180 }}
animate={isInView ? { opacity: 1, rotate: 0 } : { opacity: 0, rotate: -180 }}
transition={{ delay: 0.5, duration: 0.6 }}
>
<Icon className="w-6 h-6 text-neon" /> <Icon className="w-6 h-6 text-neon" />
</motion.div> </div>
</div> </div>
<h3 className="font-heading font-bold text-3xl text-foreground"> <h3 className="font-heading font-bold text-3xl text-foreground">
{pillar.title} {pillar.title}
</h3> </h3>
<p className="text-lg text-foreground-muted leading-relaxed"> <p className="text-lg text-foreground-muted leading-relaxed">
{pillar.description} {pillar.description}
</p> </p>
<motion.div whileHover={buttonHover} whileTap={buttonTap}> <Link
<Link to="/services"
to="/services" className="btn-ghost group flex items-center space-x-2 w-fit"
className="btn-ghost group flex items-center space-x-2 w-fit" onClick={() => window.scrollTo(0, 0)}
onClick={() => window.scrollTo(0, 0)} >
> <span>Learn more</span>
<span>Learn more</span> <ArrowRight className="w-4 h-4 transition-transform group-hover:translate-x-1" />
<motion.div </Link>
animate={{ x: [0, 3, 0] }}
transition={{ duration: 1.5, repeat: Infinity, ease: "easeInOut" }}
>
<ArrowRight className="w-4 h-4" />
</motion.div>
</Link>
</motion.div>
</div> </div>
{/* Image with 3D Tilt Effect */} {/* Image */}
<TiltCard className="flex-1"> <div className="flex-1 parallax">
<div className="card-dark p-2 group hover:shadow-neon transition-all duration-500"> <div className="card-dark p-2 group hover:shadow-neon transition-all duration-500">
<div className="relative overflow-hidden rounded-xl"> <img
<motion.img src={pillar.image}
src={pillar.image} alt={pillar.title}
alt={pillar.title} className="w-full h-64 lg:h-80 object-cover rounded-xl transition-transform duration-500 group-hover:scale-105"
className="w-full h-64 lg:h-80 object-cover" loading="lazy"
whileHover={{ scale: 1.05 }} />
transition={{ duration: 0.4, ease: "easeOut" }}
loading="lazy"
style={{ willChange: 'transform' }}
/>
{/* Simplified shine effect on hover */}
<motion.div
className="absolute inset-0 bg-gradient-to-tr from-transparent via-white/8 to-transparent pointer-events-none"
initial={{ x: '-100%', y: '-100%' }}
whileHover={{ x: '100%', y: '100%' }}
transition={{ duration: 0.5, ease: "easeOut" }}
/>
</div>
</div> </div>
</TiltCard> </div>
</div> </div>
</motion.div> </ScrollReveal>
); );
})} })}
</div> </div>

View File

@ -1,3 +1,5 @@
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Poppins:wght@600;700;800&display=swap');
@tailwind base; @tailwind base;
@tailwind components; @tailwind components;
@tailwind utilities; @tailwind utilities;
@ -86,36 +88,11 @@
scroll-behavior: smooth; scroll-behavior: smooth;
} }
/* Accessibility: Focus visible styles */
*:focus-visible {
outline: 2px solid hsl(var(--neon));
outline-offset: 3px;
border-radius: 4px;
}
/* Skip link for keyboard navigation */
.skip-link {
position: absolute;
top: -40px;
left: 0;
background: hsl(var(--neon));
color: hsl(var(--background));
padding: 8px 16px;
text-decoration: none;
z-index: 100;
font-weight: 600;
border-radius: 0 0 8px 0;
}
.skip-link:focus {
top: 0;
}
@media (prefers-reduced-motion: reduce) { @media (prefers-reduced-motion: reduce) {
html { html {
scroll-behavior: auto; scroll-behavior: auto;
} }
*, *,
*::before, *::before,
*::after { *::after {
@ -124,29 +101,6 @@
transition-duration: 0.01ms !important; transition-duration: 0.01ms !important;
} }
} }
/* Screen reader only class */
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border-width: 0;
}
.sr-only:focus,
.sr-only:active {
position: static;
width: auto;
height: auto;
overflow: visible;
clip: auto;
white-space: normal;
}
} }
@layer components { @layer components {
@ -194,26 +148,6 @@
@apply rounded-[var(--radius)] px-8 py-4 font-semibold; @apply rounded-[var(--radius)] px-8 py-4 font-semibold;
@apply transition-all duration-300 ease-out; @apply transition-all duration-300 ease-out;
@apply shadow-[0_0_0_1px_hsl(var(--neon))] hover:shadow-[0_0_20px_hsl(var(--neon)/0.5)]; @apply shadow-[0_0_0_1px_hsl(var(--neon))] hover:shadow-[0_0_20px_hsl(var(--neon)/0.5)];
position: relative;
overflow: hidden;
}
.btn-neon::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 0;
height: 0;
border-radius: 50%;
background: rgba(255, 255, 255, 0.2);
transform: translate(-50%, -50%);
transition: width 0.6s, height 0.6s;
}
.btn-neon:hover::before {
width: 300px;
height: 300px;
} }
.btn-ghost { .btn-ghost {
@ -221,116 +155,16 @@
@apply rounded-[var(--radius)] px-8 py-4 font-semibold; @apply rounded-[var(--radius)] px-8 py-4 font-semibold;
@apply transition-all duration-300 ease-out; @apply transition-all duration-300 ease-out;
@apply hover:shadow-[0_0_15px_hsl(var(--neon)/0.3)]; @apply hover:shadow-[0_0_15px_hsl(var(--neon)/0.3)];
position: relative;
overflow: hidden;
}
.btn-ghost::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 2px;
background: linear-gradient(to right, transparent, hsl(var(--neon)), transparent);
transform: translateX(-100%);
transition: transform 0.5s ease-out;
}
.btn-ghost:hover::after {
transform: translateX(100%);
} }
/* Card styles */ /* Card styles */
.card-dark { .card-dark {
@apply bg-card border border-card-border rounded-[var(--radius-lg)]; @apply bg-card border border-card-border rounded-[var(--radius-lg)];
@apply backdrop-blur-sm shadow-[var(--shadow-card)]; @apply backdrop-blur-sm shadow-[var(--shadow-card)];
position: relative;
overflow: hidden;
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
}
.card-dark::before {
content: '';
position: absolute;
top: -2px;
left: -2px;
right: -2px;
bottom: -2px;
background: linear-gradient(45deg,
transparent 30%,
hsl(var(--neon) / 0.1) 50%,
transparent 70%);
border-radius: inherit;
opacity: 0;
transition: opacity 0.4s ease;
z-index: -1;
}
.card-dark:hover::before {
opacity: 1;
}
.card-dark:hover {
transform: translateY(-4px);
border-color: hsl(var(--neon) / 0.3);
} }
/* Typography helpers */ /* Typography helpers */
.text-balance { .text-balance {
text-wrap: balance; text-wrap: balance;
} }
/* Smooth focus ring for better UX */
.focus-ring {
@apply focus:outline-none focus:ring-2 focus:ring-neon focus:ring-offset-2 focus:ring-offset-background;
transition: all 0.2s ease;
}
/* Magnetic hover effect for interactive elements */
.magnetic-hover {
transition: transform 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}
.magnetic-hover:hover {
transform: translateY(-2px);
}
/* Glassmorphism effect */
.glass {
background: rgba(255, 255, 255, 0.03);
backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.1);
}
/* Shimmer effect for loading states */
@keyframes shimmer {
0% {
transform: translateX(-100%);
}
100% {
transform: translateX(100%);
}
}
.shimmer {
position: relative;
overflow: hidden;
}
.shimmer::after {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(
90deg,
transparent,
rgba(51, 102, 255, 0.1),
transparent
);
animation: shimmer 2s infinite;
}
} }

View File

@ -4,19 +4,10 @@ import { Shield, Users, Zap, MapPin } from 'lucide-react';
import ScrollReveal from '@/components/ScrollReveal'; import ScrollReveal from '@/components/ScrollReveal';
import CountUpNumber from '@/components/CountUpNumber'; import CountUpNumber from '@/components/CountUpNumber';
import { useEffect, useRef } from 'react'; import { useEffect, useRef } from 'react';
import { useSEO } from '@/hooks/useSEO';
const About = () => { const About = () => {
const imageRef = useRef<HTMLImageElement>(null); const imageRef = useRef<HTMLImageElement>(null);
useSEO({
title: 'About Bay Area Affiliates | IT Experts Corpus Christi Since 2010',
description: 'Local IT expertise for the Coastal Bend since 2010. 150+ businesses served, 99.9% uptime. Security-first approach with clear communication. Meet the team.',
keywords: 'about Bay Area Affiliates, IT company Corpus Christi, managed services provider Texas, local IT support Coastal Bend',
canonical: 'https://bayarea-cc.com/about',
ogImage: 'https://bayarea-cc.com/og-image.png',
});
useEffect(() => { useEffect(() => {
const handleScroll = () => { const handleScroll = () => {
if (imageRef.current) { if (imageRef.current) {
@ -75,7 +66,7 @@ const About = () => {
<div className="min-h-screen"> <div className="min-h-screen">
<Navigation /> <Navigation />
<main role="main"> <main>
{/* Hero section with image background */} {/* Hero section with image background */}
<section className="relative h-screen flex items-center justify-center overflow-hidden"> <section className="relative h-screen flex items-center justify-center overflow-hidden">
{/* Background image with parallax */} {/* Background image with parallax */}
@ -87,7 +78,7 @@ const About = () => {
className="w-full h-[110%] object-cover will-change-transform" className="w-full h-[110%] object-cover will-change-transform"
style={{ transform: 'translateY(0px) scale(1.1)' }} style={{ transform: 'translateY(0px) scale(1.1)' }}
loading="eager" loading="eager"
fetchPriority="high" fetchpriority="high"
/> />
</div> </div>

View File

@ -81,7 +81,7 @@ const Blog = () => {
<div className="min-h-screen"> <div className="min-h-screen">
<Navigation /> <Navigation />
<main role="main"> <main>
{/* Hero section with image background */} {/* Hero section with image background */}
<section className="relative h-screen flex items-center justify-center overflow-hidden"> <section className="relative h-screen flex items-center justify-center overflow-hidden">
{/* Background image with parallax */} {/* Background image with parallax */}
@ -93,7 +93,7 @@ const Blog = () => {
className="w-full h-[110%] object-cover will-change-transform" className="w-full h-[110%] object-cover will-change-transform"
style={{ transform: 'translateY(0px) scale(1.1)' }} style={{ transform: 'translateY(0px) scale(1.1)' }}
loading="eager" loading="eager"
fetchPriority="high" fetchpriority="high"
/> />
</div> </div>
@ -211,8 +211,9 @@ const Blog = () => {
{/* Scroll to Top Button */} {/* Scroll to Top Button */}
<button <button
onClick={scrollToTop} onClick={scrollToTop}
className={`fixed bottom-8 right-8 z-50 p-4 bg-neon text-neon-foreground rounded-full shadow-lg shadow-neon/50 transition-all duration-300 hover:scale-110 hover:shadow-neon ${showScrollTop ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-16 pointer-events-none' className={`fixed bottom-8 right-8 z-50 p-4 bg-neon text-neon-foreground rounded-full shadow-lg shadow-neon/50 transition-all duration-300 hover:scale-110 hover:shadow-neon ${
}`} showScrollTop ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-16 pointer-events-none'
}`}
aria-label="Scroll to top" aria-label="Scroll to top"
> >
<ArrowUp className="w-6 h-6" /> <ArrowUp className="w-6 h-6" />

View File

@ -112,7 +112,7 @@ const BlogPost = () => {
<div className="min-h-screen bg-background-deep"> <div className="min-h-screen bg-background-deep">
<Navigation /> <Navigation />
<main role="main"> <main>
{/* Hero section with featured image */} {/* Hero section with featured image */}
<section className="relative h-[60vh] min-h-[400px] flex items-center justify-center overflow-hidden"> <section className="relative h-[60vh] min-h-[400px] flex items-center justify-center overflow-hidden">
{/* Background image */} {/* Background image */}
@ -122,7 +122,7 @@ const BlogPost = () => {
alt={post.title} alt={post.title}
className="w-full h-full object-cover" className="w-full h-full object-cover"
loading="eager" loading="eager"
fetchPriority="high" fetchpriority="high"
/> />
<div className="absolute inset-0 bg-gradient-to-t from-background-deep via-background-deep/60 to-transparent"></div> <div className="absolute inset-0 bg-gradient-to-t from-background-deep via-background-deep/60 to-transparent"></div>
</div> </div>

View File

@ -5,17 +5,8 @@ import { Mail, Phone, MapPin, Clock, DollarSign, Headphones } from 'lucide-react
import ScrollReveal from '@/components/ScrollReveal'; import ScrollReveal from '@/components/ScrollReveal';
import { useToast } from '@/hooks/use-toast'; import { useToast } from '@/hooks/use-toast';
import { useEffect, useRef } from 'react'; import { useEffect, useRef } from 'react';
import { useSEO } from '@/hooks/useSEO';
const Contact = () => { const Contact = () => {
useSEO({
title: 'Contact Bay Area Affiliates | Free IT Consultation Corpus Christi',
description: 'Get in touch for a free IT consultation. 24-hour response, free assessment, no obligation. Serving Corpus Christi, Portland, Rockport & the Coastal Bend.',
keywords: 'contact IT support Corpus Christi, free IT consultation, Bay Area Affiliates phone, IT services quote Texas',
canonical: 'https://bayarea-cc.com/contact',
ogImage: 'https://bayarea-cc.com/og-image.png',
});
const { toast } = useToast(); const { toast } = useToast();
const imageRef = useRef<HTMLImageElement>(null); const imageRef = useRef<HTMLImageElement>(null);
const [formData, setFormData] = useState({ const [formData, setFormData] = useState({
@ -90,7 +81,7 @@ const Contact = () => {
<div className="min-h-screen"> <div className="min-h-screen">
<Navigation /> <Navigation />
<main role="main"> <main>
{/* Hero section with image background */} {/* Hero section with image background */}
<section className="relative h-screen flex items-center justify-center overflow-hidden"> <section className="relative h-screen flex items-center justify-center overflow-hidden">
{/* Background image with parallax */} {/* Background image with parallax */}
@ -167,7 +158,7 @@ const Contact = () => {
required required
value={formData.name} value={formData.name}
onChange={handleChange} onChange={handleChange}
className="w-full px-4 py-3 bg-white/5 backdrop-blur-sm border border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-neon focus:border-neon focus:bg-white/10 focus:shadow-[0_0_15px_rgba(51,102,255,0.3)] transition-all duration-300 text-foreground placeholder-foreground-muted/50" className="w-full px-4 py-3 bg-input border border-input-border rounded-lg focus:outline-none focus:ring-2 focus:ring-neon focus:border-transparent text-foreground"
placeholder="Your full name" placeholder="Your full name"
/> />
</div> </div>
@ -183,7 +174,7 @@ const Contact = () => {
required required
value={formData.email} value={formData.email}
onChange={handleChange} onChange={handleChange}
className="w-full px-4 py-3 bg-white/5 backdrop-blur-sm border border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-neon focus:border-neon focus:bg-white/10 focus:shadow-[0_0_15px_rgba(51,102,255,0.3)] transition-all duration-300 text-foreground placeholder-foreground-muted/50" className="w-full px-4 py-3 bg-input border border-input-border rounded-lg focus:outline-none focus:ring-2 focus:ring-neon focus:border-transparent text-foreground"
placeholder="your@email.com" placeholder="your@email.com"
/> />
</div> </div>
@ -200,7 +191,7 @@ const Contact = () => {
name="company" name="company"
value={formData.company} value={formData.company}
onChange={handleChange} onChange={handleChange}
className="w-full px-4 py-3 bg-white/5 backdrop-blur-sm border border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-neon focus:border-neon focus:bg-white/10 focus:shadow-[0_0_15px_rgba(51,102,255,0.3)] transition-all duration-300 text-foreground placeholder-foreground-muted/50" className="w-full px-4 py-3 bg-input border border-input-border rounded-lg focus:outline-none focus:ring-2 focus:ring-neon focus:border-transparent text-foreground"
placeholder="Your company name" placeholder="Your company name"
/> />
</div> </div>
@ -215,7 +206,7 @@ const Contact = () => {
name="phone" name="phone"
value={formData.phone} value={formData.phone}
onChange={handleChange} onChange={handleChange}
className="w-full px-4 py-3 bg-white/5 backdrop-blur-sm border border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-neon focus:border-neon focus:bg-white/10 focus:shadow-[0_0_15px_rgba(51,102,255,0.3)] transition-all duration-300 text-foreground placeholder-foreground-muted/50" className="w-full px-4 py-3 bg-input border border-input-border rounded-lg focus:outline-none focus:ring-2 focus:ring-neon focus:border-transparent text-foreground"
placeholder="(361) 555-0123" placeholder="(361) 555-0123"
/> />
</div> </div>
@ -232,7 +223,7 @@ const Contact = () => {
rows={5} rows={5}
value={formData.message} value={formData.message}
onChange={handleChange} onChange={handleChange}
className="w-full px-4 py-3 bg-white/5 backdrop-blur-sm border border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-neon focus:border-neon focus:bg-white/10 focus:shadow-[0_0_15px_rgba(51,102,255,0.3)] transition-all duration-300 text-foreground placeholder-foreground-muted/50 resize-none" className="w-full px-4 py-3 bg-input border border-input-border rounded-lg focus:outline-none focus:ring-2 focus:ring-neon focus:border-transparent text-foreground resize-none"
placeholder="Tell us about your IT needs or challenges..." placeholder="Tell us about your IT needs or challenges..."
/> />
</div> </div>
@ -381,47 +372,6 @@ const Contact = () => {
</ScrollReveal> </ScrollReveal>
</div> </div>
</section> </section>
{/* Service Area Map */}
<section className="py-16 bg-background-deep">
<div className="w-full max-w-[95%] mx-auto px-4 sm:px-6 lg:px-8">
<ScrollReveal width="100%">
<div className="text-center mb-8">
<h2 className="font-heading font-bold text-3xl text-foreground mb-4">
Our Service Area
</h2>
<p className="text-foreground-muted max-w-2xl mx-auto">
Proudly serving Corpus Christi, Portland, Rockport, Aransas Pass, Kingsville, Port Aransas, and the entire Coastal Bend region.
</p>
</div>
<div className="card-dark p-2 overflow-hidden">
<iframe
src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d113726.84791849895!2d-97.48659164550781!3d27.800587899999997!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x8668fa3c40818e93%3A0x4e3c0a1c2bef9c65!2sCorpus%20Christi%2C%20TX!5e0!3m2!1sen!2sus!4v1736364000000!5m2!1sen!2sus"
width="100%"
height="450"
style={{ border: 0, borderRadius: '1rem' }}
allowFullScreen
loading="lazy"
referrerPolicy="no-referrer-when-downgrade"
title="Bay Area Affiliates Service Area - Corpus Christi and Coastal Bend"
aria-label="Google Maps showing our service area in Corpus Christi and the Coastal Bend region"
/>
</div>
<div className="mt-8 grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-4">
{['Corpus Christi', 'Portland', 'Rockport', 'Aransas Pass', 'Kingsville', 'Port Aransas'].map((city) => (
<div key={city} className="text-center">
<div className="card-dark p-3">
<MapPin className="w-5 h-5 text-neon mx-auto mb-1" />
<p className="text-xs text-foreground font-medium">{city}</p>
</div>
</div>
))}
</div>
</ScrollReveal>
</div>
</section>
</main> </main>
<Footer /> <Footer />

View File

@ -9,27 +9,27 @@ import { Monitor, HardDrive, Cpu, CheckCircle, DollarSign, Truck, Shield, Award
const DesktopHardware = () => { const DesktopHardware = () => {
useEffect(() => { useEffect(() => {
document.title = 'Desktop Hardware Corpus Christi | Bay Area Affiliates'; document.title = 'Desktop Hardware Corpus Christi | Bay Area Affiliates';
const metaDescription = document.querySelector('meta[name="description"]'); const metaDescription = document.querySelector('meta[name="description"]');
if (metaDescription) { if (metaDescription) {
metaDescription.setAttribute('content', 'Quality new/refurbished desktops, fast local installation.'); metaDescription.setAttribute('content', 'Quality new/refurbished desktops, fast local installation.');
} }
const ogTitle = document.querySelector('meta[property="og:title"]'); const ogTitle = document.querySelector('meta[property="og:title"]');
if (ogTitle) { if (ogTitle) {
ogTitle.setAttribute('content', 'Refurbished Desktops Corpus Christi—Quality Business Hardware'); ogTitle.setAttribute('content', 'Refurbished Desktops Corpus Christi—Quality Business Hardware');
} }
const ogDescription = document.querySelector('meta[property="og:description"]'); const ogDescription = document.querySelector('meta[property="og:description"]');
if (ogDescription) { if (ogDescription) {
ogDescription.setAttribute('content', 'Quality new/refurbished desktops, fast local installation.'); ogDescription.setAttribute('content', 'Quality new/refurbished desktops, fast local installation.');
} }
const twitterTitle = document.querySelector('meta[name="twitter:title"]'); const twitterTitle = document.querySelector('meta[name="twitter:title"]');
if (twitterTitle) { if (twitterTitle) {
twitterTitle.setAttribute('content', 'Affordable PC Business Hardware Corpus Christi'); twitterTitle.setAttribute('content', 'Affordable PC Business Hardware Corpus Christi');
} }
const twitterDescription = document.querySelector('meta[name="twitter:description"]'); const twitterDescription = document.querySelector('meta[name="twitter:description"]');
if (twitterDescription) { if (twitterDescription) {
twitterDescription.setAttribute('content', 'Quality new/refurbished desktops, fast local installation.'); twitterDescription.setAttribute('content', 'Quality new/refurbished desktops, fast local installation.');
@ -39,7 +39,7 @@ const DesktopHardware = () => {
return ( return (
<div className="min-h-screen"> <div className="min-h-screen">
<Navigation /> <Navigation />
<main role="main"> <main>
{/* Hero Section */} {/* Hero Section */}
<section className="bg-gradient-to-br from-gray-900 via-gray-800 to-gray-600 text-white py-20"> <section className="bg-gradient-to-br from-gray-900 via-gray-800 to-gray-600 text-white py-20">
<div className="container mx-auto px-4"> <div className="container mx-auto px-4">
@ -72,7 +72,7 @@ const DesktopHardware = () => {
<div className="container mx-auto px-4"> <div className="container mx-auto px-4">
<div className="max-w-4xl mx-auto"> <div className="max-w-4xl mx-auto">
<h2 className="text-3xl font-bold text-center mb-12">Professional Desktop Solutions</h2> <h2 className="text-3xl font-bold text-center mb-12">Professional Desktop Solutions</h2>
<div className="grid md:grid-cols-2 gap-8 mb-12"> <div className="grid md:grid-cols-2 gap-8 mb-12">
<Card> <Card>
<CardHeader> <CardHeader>
@ -93,7 +93,7 @@ const DesktopHardware = () => {
</ul> </ul>
</CardContent> </CardContent>
</Card> </Card>
<Card> <Card>
<CardHeader> <CardHeader>
<div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mb-4"> <div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mb-4">
@ -113,7 +113,7 @@ const DesktopHardware = () => {
</ul> </ul>
</CardContent> </CardContent>
</Card> </Card>
<Card> <Card>
<CardHeader> <CardHeader>
<div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mb-4"> <div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mb-4">
@ -133,7 +133,7 @@ const DesktopHardware = () => {
</div> </div>
</CardContent> </CardContent>
</Card> </Card>
<Card> <Card>
<CardHeader> <CardHeader>
<div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mb-4"> <div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mb-4">
@ -163,7 +163,7 @@ const DesktopHardware = () => {
<div className="container mx-auto px-4"> <div className="container mx-auto px-4">
<div className="max-w-4xl mx-auto"> <div className="max-w-4xl mx-auto">
<h2 className="text-3xl font-bold text-center mb-12">Desktop Categories for Every Business Need</h2> <h2 className="text-3xl font-bold text-center mb-12">Desktop Categories for Every Business Need</h2>
<div className="grid md:grid-cols-3 gap-8 mb-12"> <div className="grid md:grid-cols-3 gap-8 mb-12">
<div className="bg-white p-6 rounded-lg shadow border-l-4 border-blue-500"> <div className="bg-white p-6 rounded-lg shadow border-l-4 border-blue-500">
<h3 className="font-bold text-lg mb-4">Essential Business</h3> <h3 className="font-bold text-lg mb-4">Essential Business</h3>
@ -180,7 +180,7 @@ const DesktopHardware = () => {
<div className="text-sm text-gray-500">Starting price</div> <div className="text-sm text-gray-500">Starting price</div>
</div> </div>
</div> </div>
<div className="bg-white p-6 rounded-lg shadow border-l-4 border-orange-500"> <div className="bg-white p-6 rounded-lg shadow border-l-4 border-orange-500">
<h3 className="font-bold text-lg mb-4">Professional Plus</h3> <h3 className="font-bold text-lg mb-4">Professional Plus</h3>
<p className="text-gray-600 mb-4">Enhanced performance for demanding business applications and multitasking.</p> <p className="text-gray-600 mb-4">Enhanced performance for demanding business applications and multitasking.</p>
@ -196,7 +196,7 @@ const DesktopHardware = () => {
<div className="text-sm text-gray-500">Starting price</div> <div className="text-sm text-gray-500">Starting price</div>
</div> </div>
</div> </div>
<div className="bg-white p-6 rounded-lg shadow border-l-4 border-purple-500"> <div className="bg-white p-6 rounded-lg shadow border-l-4 border-purple-500">
<h3 className="font-bold text-lg mb-4">Workstation Class</h3> <h3 className="font-bold text-lg mb-4">Workstation Class</h3>
<p className="text-gray-600 mb-4">High-performance systems for CAD, design, development, and intensive applications.</p> <p className="text-gray-600 mb-4">High-performance systems for CAD, design, development, and intensive applications.</p>
@ -213,7 +213,7 @@ const DesktopHardware = () => {
</div> </div>
</div> </div>
</div> </div>
<div className="bg-white p-8 rounded-lg shadow-lg"> <div className="bg-white p-8 rounded-lg shadow-lg">
<h3 className="text-2xl font-bold mb-6 text-center">Why Choose Refurbished Business Hardware?</h3> <h3 className="text-2xl font-bold mb-6 text-center">Why Choose Refurbished Business Hardware?</h3>
<div className="grid md:grid-cols-2 gap-8"> <div className="grid md:grid-cols-2 gap-8">
@ -270,7 +270,7 @@ const DesktopHardware = () => {
<div className="container mx-auto px-4"> <div className="container mx-auto px-4">
<div className="max-w-4xl mx-auto"> <div className="max-w-4xl mx-auto">
<h2 className="text-3xl font-bold text-center mb-12">Complete Installation & Setup Service</h2> <h2 className="text-3xl font-bold text-center mb-12">Complete Installation & Setup Service</h2>
<div className="grid md:grid-cols-4 gap-8"> <div className="grid md:grid-cols-4 gap-8">
<Card className="text-center"> <Card className="text-center">
<CardHeader> <CardHeader>
@ -283,7 +283,7 @@ const DesktopHardware = () => {
<p className="text-sm">Assess your needs and recommend the optimal hardware configuration for your business.</p> <p className="text-sm">Assess your needs and recommend the optimal hardware configuration for your business.</p>
</CardContent> </CardContent>
</Card> </Card>
<Card className="text-center"> <Card className="text-center">
<CardHeader> <CardHeader>
<div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4"> <div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4">
@ -295,7 +295,7 @@ const DesktopHardware = () => {
<p className="text-sm">Install and configure software, security settings, and business applications.</p> <p className="text-sm">Install and configure software, security settings, and business applications.</p>
</CardContent> </CardContent>
</Card> </Card>
<Card className="text-center"> <Card className="text-center">
<CardHeader> <CardHeader>
<div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4"> <div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4">
@ -307,7 +307,7 @@ const DesktopHardware = () => {
<p className="text-sm">On-site installation, network integration, and user account setup.</p> <p className="text-sm">On-site installation, network integration, and user account setup.</p>
</CardContent> </CardContent>
</Card> </Card>
<Card className="text-center"> <Card className="text-center">
<CardHeader> <CardHeader>
<div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4"> <div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4">
@ -330,10 +330,10 @@ const DesktopHardware = () => {
<div className="max-w-4xl mx-auto text-center"> <div className="max-w-4xl mx-auto text-center">
<h2 className="text-3xl font-bold mb-8">Trusted Hardware Supplier for Coastal Bend SMBs</h2> <h2 className="text-3xl font-bold mb-8">Trusted Hardware Supplier for Coastal Bend SMBs</h2>
<p className="text-xl text-gray-600 mb-8"> <p className="text-xl text-gray-600 mb-8">
Bay Area Affiliates has supplied and serviced business computers throughout the Corpus Christi area since 1999. Bay Area Affiliates has supplied and serviced business computers throughout the Corpus Christi area since 1999.
We understand local business needs and provide personalized hardware solutions. We understand local business needs and provide personalized hardware solutions.
</p> </p>
<div className="grid md:grid-cols-3 gap-8 mb-12"> <div className="grid md:grid-cols-3 gap-8 mb-12">
<div className="text-center"> <div className="text-center">
<div className="text-4xl font-bold text-blue-600 mb-2">5,000+</div> <div className="text-4xl font-bold text-blue-600 mb-2">5,000+</div>
@ -348,11 +348,11 @@ const DesktopHardware = () => {
<div className="text-gray-600">Years Experience</div> <div className="text-gray-600">Years Experience</div>
</div> </div>
</div> </div>
<div className="bg-white p-8 rounded-lg shadow-lg"> <div className="bg-white p-8 rounded-lg shadow-lg">
<h3 className="text-2xl font-bold mb-4">Local Hardware Support Throughout the Coastal Bend</h3> <h3 className="text-2xl font-bold mb-4">Local Hardware Support Throughout the Coastal Bend</h3>
<p className="text-gray-700 mb-6"> <p className="text-gray-700 mb-6">
From single desktop replacements to complete office refreshes, we provide comprehensive From single desktop replacements to complete office refreshes, we provide comprehensive
hardware solutions with local pickup, delivery, and installation services. hardware solutions with local pickup, delivery, and installation services.
</p> </p>
<div className="flex flex-wrap justify-center gap-4"> <div className="flex flex-wrap justify-center gap-4">
@ -374,10 +374,10 @@ const DesktopHardware = () => {
<div className="max-w-4xl mx-auto text-center"> <div className="max-w-4xl mx-auto text-center">
<h2 className="text-3xl font-bold mb-6">Upgrade Your Business Hardware Today</h2> <h2 className="text-3xl font-bold mb-6">Upgrade Your Business Hardware Today</h2>
<p className="text-xl mb-8 text-gray-100"> <p className="text-xl mb-8 text-gray-100">
Get quality business desktops with professional installation and local support. Get quality business desktops with professional installation and local support.
Free consultation and custom quotes for Corpus Christi area businesses. Free consultation and custom quotes for Corpus Christi area businesses.
</p> </p>
<div className="flex flex-col sm:flex-row gap-4 justify-center mb-8"> <div className="flex flex-col sm:flex-row gap-4 justify-center mb-8">
<Button size="lg" className="bg-orange-600 hover:bg-orange-700"> <Button size="lg" className="bg-orange-600 hover:bg-orange-700">
<Award className="w-5 h-5 mr-2" /> <Award className="w-5 h-5 mr-2" />
@ -387,7 +387,7 @@ const DesktopHardware = () => {
Call (361) 765-8400 Call (361) 765-8400
</Button> </Button>
</div> </div>
<p className="text-gray-200"> <p className="text-gray-200">
Free consultation Local delivery Professional installation 12-month warranty Free consultation Local delivery Professional installation 12-month warranty
</p> </p>

View File

@ -6,48 +6,18 @@ import ProcessTimeline from '@/components/home/ProcessTimeline';
import ServicesOverview from '@/components/home/ServicesOverview'; import ServicesOverview from '@/components/home/ServicesOverview';
import ProofSection from '@/components/home/ProofSection'; import ProofSection from '@/components/home/ProofSection';
import CTASection from '@/components/home/CTASection'; import CTASection from '@/components/home/CTASection';
import TrustedBy from '@/components/home/TrustedBy';
import ScrollReveal from '@/components/ScrollReveal';
import { useSEO } from '@/hooks/useSEO';
const Index = () => { const Index = () => {
useSEO({
title: 'IT Support Corpus Christi ⚡ 24/7 Managed Services | Bay Area Affiliates',
description: 'Stop IT headaches! 25+ years experience, 2-hour response time, 24/7 monitoring. Managed IT services in Corpus Christi & Coastal Bend. Free assessment. Call (361) 765-8400',
keywords: 'managed IT services corpus christi, IT support coastal bend, 24/7 IT monitoring, business computer solutions, Windows 11 migration, VPN setup, network security corpus christi',
canonical: 'https://bayarea-cc.com/',
ogImage: 'https://bayarea-cc.com/og-image.png',
});
return ( return (
<div className="min-h-screen"> <div className="min-h-screen">
<Navigation /> <Navigation />
<main id="main-content" role="main"> <main>
<HeroSection /> <HeroSection />
<ValuePillars />
<ScrollReveal delay={0.2} width="100%"> <ProcessTimeline />
<TrustedBy /> <ServicesOverview />
</ScrollReveal> <ProofSection />
<CTASection />
<ScrollReveal width="100%">
<ValuePillars />
</ScrollReveal>
<ScrollReveal width="100%">
<ProcessTimeline />
</ScrollReveal>
<ScrollReveal width="100%">
<ServicesOverview />
</ScrollReveal>
<ScrollReveal width="100%">
<ProofSection />
</ScrollReveal>
<ScrollReveal width="100%">
<CTASection />
</ScrollReveal>
</main> </main>
<Footer /> <Footer />
</div> </div>

View File

@ -9,27 +9,27 @@ import { HardDrive, Cloud, Shield, CheckCircle, Database, Server, Lock, Archive
const NetworkAttachedStorage = () => { const NetworkAttachedStorage = () => {
useEffect(() => { useEffect(() => {
document.title = 'NAS Setup Corpus Christi | Bay Area Affiliates'; document.title = 'NAS Setup Corpus Christi | Bay Area Affiliates';
const metaDescription = document.querySelector('meta[name="description"]'); const metaDescription = document.querySelector('meta[name="description"]');
if (metaDescription) { if (metaDescription) {
metaDescription.setAttribute('content', 'Secure, scalable backups for business data. Book install.'); metaDescription.setAttribute('content', 'Secure, scalable backups for business data. Book install.');
} }
const ogTitle = document.querySelector('meta[property="og:title"]'); const ogTitle = document.querySelector('meta[property="og:title"]');
if (ogTitle) { if (ogTitle) {
ogTitle.setAttribute('content', 'Network Attached Storage Setup Corpus Christi—Business Data Solutions'); ogTitle.setAttribute('content', 'Network Attached Storage Setup Corpus Christi—Business Data Solutions');
} }
const ogDescription = document.querySelector('meta[property="og:description"]'); const ogDescription = document.querySelector('meta[property="og:description"]');
if (ogDescription) { if (ogDescription) {
ogDescription.setAttribute('content', 'Secure, scalable backups for business data. Book install.'); ogDescription.setAttribute('content', 'Secure, scalable backups for business data. Book install.');
} }
const twitterTitle = document.querySelector('meta[name="twitter:title"]'); const twitterTitle = document.querySelector('meta[name="twitter:title"]');
if (twitterTitle) { if (twitterTitle) {
twitterTitle.setAttribute('content', 'NAS Backup Storage SMB Corpus Christi'); twitterTitle.setAttribute('content', 'NAS Backup Storage SMB Corpus Christi');
} }
const twitterDescription = document.querySelector('meta[name="twitter:description"]'); const twitterDescription = document.querySelector('meta[name="twitter:description"]');
if (twitterDescription) { if (twitterDescription) {
twitterDescription.setAttribute('content', 'Secure, scalable backups for business data. Book install.'); twitterDescription.setAttribute('content', 'Secure, scalable backups for business data. Book install.');
@ -39,7 +39,7 @@ const NetworkAttachedStorage = () => {
return ( return (
<div className="min-h-screen"> <div className="min-h-screen">
<Navigation /> <Navigation />
<main role="main"> <main>
{/* Hero Section */} {/* Hero Section */}
<section className="bg-gradient-to-br from-blue-900 via-blue-800 to-blue-600 text-white py-20"> <section className="bg-gradient-to-br from-blue-900 via-blue-800 to-blue-600 text-white py-20">
<div className="container mx-auto px-4"> <div className="container mx-auto px-4">
@ -72,7 +72,7 @@ const NetworkAttachedStorage = () => {
<div className="container mx-auto px-4"> <div className="container mx-auto px-4">
<div className="max-w-4xl mx-auto"> <div className="max-w-4xl mx-auto">
<h2 className="text-3xl font-bold text-center mb-12">Protect Your Business Data with Professional NAS</h2> <h2 className="text-3xl font-bold text-center mb-12">Protect Your Business Data with Professional NAS</h2>
<div className="grid md:grid-cols-2 gap-8 mb-12"> <div className="grid md:grid-cols-2 gap-8 mb-12">
<Card> <Card>
<CardHeader> <CardHeader>
@ -93,7 +93,7 @@ const NetworkAttachedStorage = () => {
</ul> </ul>
</CardContent> </CardContent>
</Card> </Card>
<Card> <Card>
<CardHeader> <CardHeader>
<div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mb-4"> <div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mb-4">
@ -113,7 +113,7 @@ const NetworkAttachedStorage = () => {
</ul> </ul>
</CardContent> </CardContent>
</Card> </Card>
<Card> <Card>
<CardHeader> <CardHeader>
<div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mb-4"> <div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mb-4">
@ -133,7 +133,7 @@ const NetworkAttachedStorage = () => {
</ul> </ul>
</CardContent> </CardContent>
</Card> </Card>
<Card> <Card>
<CardHeader> <CardHeader>
<div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mb-4"> <div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mb-4">
@ -163,7 +163,7 @@ const NetworkAttachedStorage = () => {
<div className="container mx-auto px-4"> <div className="container mx-auto px-4">
<div className="max-w-4xl mx-auto"> <div className="max-w-4xl mx-auto">
<h2 className="text-3xl font-bold text-center mb-12">NAS Solutions for Every Business Size</h2> <h2 className="text-3xl font-bold text-center mb-12">NAS Solutions for Every Business Size</h2>
<div className="grid md:grid-cols-3 gap-8 mb-12"> <div className="grid md:grid-cols-3 gap-8 mb-12">
<div className="bg-white p-6 rounded-lg shadow border-l-4 border-blue-500"> <div className="bg-white p-6 rounded-lg shadow border-l-4 border-blue-500">
<h3 className="font-bold text-lg mb-4">Essential NAS</h3> <h3 className="font-bold text-lg mb-4">Essential NAS</h3>
@ -181,7 +181,7 @@ const NetworkAttachedStorage = () => {
<div className="text-sm text-gray-500">Complete setup</div> <div className="text-sm text-gray-500">Complete setup</div>
</div> </div>
</div> </div>
<div className="bg-white p-6 rounded-lg shadow border-l-4 border-orange-500"> <div className="bg-white p-6 rounded-lg shadow border-l-4 border-orange-500">
<h3 className="font-bold text-lg mb-4">Professional NAS</h3> <h3 className="font-bold text-lg mb-4">Professional NAS</h3>
<p className="text-gray-600 mb-4">Advanced features for growing businesses with critical data protection needs.</p> <p className="text-gray-600 mb-4">Advanced features for growing businesses with critical data protection needs.</p>
@ -198,7 +198,7 @@ const NetworkAttachedStorage = () => {
<div className="text-sm text-gray-500">Complete setup</div> <div className="text-sm text-gray-500">Complete setup</div>
</div> </div>
</div> </div>
<div className="bg-white p-6 rounded-lg shadow border-l-4 border-purple-500"> <div className="bg-white p-6 rounded-lg shadow border-l-4 border-purple-500">
<h3 className="font-bold text-lg mb-4">Enterprise NAS</h3> <h3 className="font-bold text-lg mb-4">Enterprise NAS</h3>
<p className="text-gray-600 mb-4">High-performance storage for businesses with demanding data requirements.</p> <p className="text-gray-600 mb-4">High-performance storage for businesses with demanding data requirements.</p>
@ -216,7 +216,7 @@ const NetworkAttachedStorage = () => {
</div> </div>
</div> </div>
</div> </div>
<div className="bg-white p-8 rounded-lg shadow-lg"> <div className="bg-white p-8 rounded-lg shadow-lg">
<h3 className="text-2xl font-bold mb-6 text-center">Why Businesses Choose NAS Over Cloud Storage</h3> <h3 className="text-2xl font-bold mb-6 text-center">Why Businesses Choose NAS Over Cloud Storage</h3>
<div className="grid md:grid-cols-2 gap-8"> <div className="grid md:grid-cols-2 gap-8">
@ -263,7 +263,7 @@ const NetworkAttachedStorage = () => {
</ul> </ul>
</div> </div>
</div> </div>
<div className="mt-6 bg-blue-50 p-6 rounded-lg"> <div className="mt-6 bg-blue-50 p-6 rounded-lg">
<h4 className="font-semibold text-blue-700 mb-3">ROI Calculation Example</h4> <h4 className="font-semibold text-blue-700 mb-3">ROI Calculation Example</h4>
<div className="grid md:grid-cols-2 gap-6 text-sm"> <div className="grid md:grid-cols-2 gap-6 text-sm">
@ -288,7 +288,7 @@ const NetworkAttachedStorage = () => {
<div className="container mx-auto px-4"> <div className="container mx-auto px-4">
<div className="max-w-4xl mx-auto"> <div className="max-w-4xl mx-auto">
<h2 className="text-3xl font-bold text-center mb-12">Professional NAS Installation Process</h2> <h2 className="text-3xl font-bold text-center mb-12">Professional NAS Installation Process</h2>
<div className="grid md:grid-cols-4 gap-8"> <div className="grid md:grid-cols-4 gap-8">
<Card className="text-center"> <Card className="text-center">
<CardHeader> <CardHeader>
@ -301,7 +301,7 @@ const NetworkAttachedStorage = () => {
<p className="text-sm">Analyze your data storage needs, backup requirements, and growth projections.</p> <p className="text-sm">Analyze your data storage needs, backup requirements, and growth projections.</p>
</CardContent> </CardContent>
</Card> </Card>
<Card className="text-center"> <Card className="text-center">
<CardHeader> <CardHeader>
<div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4"> <div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4">
@ -313,7 +313,7 @@ const NetworkAttachedStorage = () => {
<p className="text-sm">Set up NAS hardware, configure RAID, and install necessary software applications.</p> <p className="text-sm">Set up NAS hardware, configure RAID, and install necessary software applications.</p>
</CardContent> </CardContent>
</Card> </Card>
<Card className="text-center"> <Card className="text-center">
<CardHeader> <CardHeader>
<div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4"> <div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4">
@ -325,7 +325,7 @@ const NetworkAttachedStorage = () => {
<p className="text-sm">Transfer existing data safely and set up automated backup schedules for all devices.</p> <p className="text-sm">Transfer existing data safely and set up automated backup schedules for all devices.</p>
</CardContent> </CardContent>
</Card> </Card>
<Card className="text-center"> <Card className="text-center">
<CardHeader> <CardHeader>
<div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4"> <div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4">
@ -349,11 +349,11 @@ const NetworkAttachedStorage = () => {
<h2 className="text-3xl font-bold text-center mb-8">Emergency Data Recovery Services</h2> <h2 className="text-3xl font-bold text-center mb-8">Emergency Data Recovery Services</h2>
<div className="text-center mb-8"> <div className="text-center mb-8">
<p className="text-xl text-gray-600"> <p className="text-xl text-gray-600">
Already experienced data loss? We provide emergency recovery services while setting up Already experienced data loss? We provide emergency recovery services while setting up
your new NAS to prevent future disasters. your new NAS to prevent future disasters.
</p> </p>
</div> </div>
<div className="grid md:grid-cols-2 gap-8"> <div className="grid md:grid-cols-2 gap-8">
<div className="bg-white p-6 rounded-lg shadow"> <div className="bg-white p-6 rounded-lg shadow">
<h3 className="text-xl font-bold mb-4 text-red-600">What We Recover</h3> <h3 className="text-xl font-bold mb-4 text-red-600">What We Recover</h3>
@ -366,7 +366,7 @@ const NetworkAttachedStorage = () => {
<li> Photos and multimedia files</li> <li> Photos and multimedia files</li>
</ul> </ul>
</div> </div>
<div className="bg-white p-6 rounded-lg shadow"> <div className="bg-white p-6 rounded-lg shadow">
<h3 className="text-xl font-bold mb-4 text-red-600">Recovery Process</h3> <h3 className="text-xl font-bold mb-4 text-red-600">Recovery Process</h3>
<ul className="space-y-2 text-gray-700"> <ul className="space-y-2 text-gray-700">
@ -379,7 +379,7 @@ const NetworkAttachedStorage = () => {
</ul> </ul>
</div> </div>
</div> </div>
<div className="mt-8 text-center"> <div className="mt-8 text-center">
<Button size="lg" className="bg-red-600 hover:bg-red-700 text-white"> <Button size="lg" className="bg-red-600 hover:bg-red-700 text-white">
<Lock className="w-5 h-5 mr-2" /> <Lock className="w-5 h-5 mr-2" />
@ -396,10 +396,10 @@ const NetworkAttachedStorage = () => {
<div className="max-w-4xl mx-auto text-center"> <div className="max-w-4xl mx-auto text-center">
<h2 className="text-3xl font-bold mb-8">Data Storage Specialists Serving the Coastal Bend</h2> <h2 className="text-3xl font-bold mb-8">Data Storage Specialists Serving the Coastal Bend</h2>
<p className="text-xl text-gray-600 mb-8"> <p className="text-xl text-gray-600 mb-8">
Bay Area Affiliates has protected business data for Corpus Christi companies since 1999. Bay Area Affiliates has protected business data for Corpus Christi companies since 1999.
We understand the critical importance of data security and business continuity. We understand the critical importance of data security and business continuity.
</p> </p>
<div className="grid md:grid-cols-3 gap-8 mb-12"> <div className="grid md:grid-cols-3 gap-8 mb-12">
<div className="text-center"> <div className="text-center">
<div className="text-4xl font-bold text-blue-600 mb-2">250+</div> <div className="text-4xl font-bold text-blue-600 mb-2">250+</div>
@ -414,11 +414,11 @@ const NetworkAttachedStorage = () => {
<div className="text-gray-600">Data Loss with Our NAS</div> <div className="text-gray-600">Data Loss with Our NAS</div>
</div> </div>
</div> </div>
<div className="bg-blue-50 p-8 rounded-lg shadow-lg"> <div className="bg-blue-50 p-8 rounded-lg shadow-lg">
<h3 className="text-2xl font-bold mb-4">Protecting Business Data Throughout the Coastal Bend</h3> <h3 className="text-2xl font-bold mb-4">Protecting Business Data Throughout the Coastal Bend</h3>
<p className="text-gray-700 mb-6"> <p className="text-gray-700 mb-6">
From small professional practices to growing enterprises, we provide comprehensive From small professional practices to growing enterprises, we provide comprehensive
data storage and backup solutions with local support and maintenance. data storage and backup solutions with local support and maintenance.
</p> </p>
<div className="flex flex-wrap justify-center gap-4"> <div className="flex flex-wrap justify-center gap-4">
@ -440,10 +440,10 @@ const NetworkAttachedStorage = () => {
<div className="max-w-4xl mx-auto text-center"> <div className="max-w-4xl mx-auto text-center">
<h2 className="text-3xl font-bold mb-6">Don't Risk Your Business Data</h2> <h2 className="text-3xl font-bold mb-6">Don't Risk Your Business Data</h2>
<p className="text-xl mb-8 text-blue-100"> <p className="text-xl mb-8 text-blue-100">
Get professional NAS installation and data protection from Corpus Christi's trusted IT experts. Get professional NAS installation and data protection from Corpus Christi's trusted IT experts.
Protect your business before disaster strikes. Protect your business before disaster strikes.
</p> </p>
<div className="flex flex-col sm:flex-row gap-4 justify-center mb-8"> <div className="flex flex-col sm:flex-row gap-4 justify-center mb-8">
<Button size="lg" className="bg-orange-600 hover:bg-orange-700"> <Button size="lg" className="bg-orange-600 hover:bg-orange-700">
<Database className="w-5 h-5 mr-2" /> <Database className="w-5 h-5 mr-2" />
@ -453,7 +453,7 @@ const NetworkAttachedStorage = () => {
Call (361) 765-8400 Call (361) 765-8400
</Button> </Button>
</div> </div>
<p className="text-blue-200"> <p className="text-blue-200">
Free consultation Professional installation 24/7 monitoring Local support Free consultation Professional installation 24/7 monitoring Local support
</p> </p>

View File

@ -9,27 +9,27 @@ import { Network, Router, Shield, CheckCircle, Users, Monitor, Lock, Search } fr
const NetworkInfrastructure = () => { const NetworkInfrastructure = () => {
useEffect(() => { useEffect(() => {
document.title = 'Network Support Corpus Christi | Bay Area Affiliates'; document.title = 'Network Support Corpus Christi | Bay Area Affiliates';
const metaDescription = document.querySelector('meta[name="description"]'); const metaDescription = document.querySelector('meta[name="description"]');
if (metaDescription) { if (metaDescription) {
metaDescription.setAttribute('content', 'Reliable SMB network solutions—secure, scalable, supported.'); metaDescription.setAttribute('content', 'Reliable SMB network solutions—secure, scalable, supported.');
} }
const ogTitle = document.querySelector('meta[property="og:title"]'); const ogTitle = document.querySelector('meta[property="og:title"]');
if (ogTitle) { if (ogTitle) {
ogTitle.setAttribute('content', 'Network Infrastructure Support Corpus Christi—SMB IT Solutions'); ogTitle.setAttribute('content', 'Network Infrastructure Support Corpus Christi—SMB IT Solutions');
} }
const ogDescription = document.querySelector('meta[property="og:description"]'); const ogDescription = document.querySelector('meta[property="og:description"]');
if (ogDescription) { if (ogDescription) {
ogDescription.setAttribute('content', 'Reliable SMB network solutions—secure, scalable, supported.'); ogDescription.setAttribute('content', 'Reliable SMB network solutions—secure, scalable, supported.');
} }
const twitterTitle = document.querySelector('meta[name="twitter:title"]'); const twitterTitle = document.querySelector('meta[name="twitter:title"]');
if (twitterTitle) { if (twitterTitle) {
twitterTitle.setAttribute('content', 'Router Setup IT Audit Corpus Christi'); twitterTitle.setAttribute('content', 'Router Setup IT Audit Corpus Christi');
} }
const twitterDescription = document.querySelector('meta[name="twitter:description"]'); const twitterDescription = document.querySelector('meta[name="twitter:description"]');
if (twitterDescription) { if (twitterDescription) {
twitterDescription.setAttribute('content', 'Reliable SMB network solutions—secure, scalable, supported.'); twitterDescription.setAttribute('content', 'Reliable SMB network solutions—secure, scalable, supported.');
@ -39,7 +39,7 @@ const NetworkInfrastructure = () => {
return ( return (
<div className="min-h-screen"> <div className="min-h-screen">
<Navigation /> <Navigation />
<main role="main"> <main>
{/* Hero Section */} {/* Hero Section */}
<section className="bg-gradient-to-br from-teal-900 via-teal-800 to-teal-600 text-white py-20"> <section className="bg-gradient-to-br from-teal-900 via-teal-800 to-teal-600 text-white py-20">
<div className="container mx-auto px-4"> <div className="container mx-auto px-4">
@ -72,7 +72,7 @@ const NetworkInfrastructure = () => {
<div className="container mx-auto px-4"> <div className="container mx-auto px-4">
<div className="max-w-4xl mx-auto"> <div className="max-w-4xl mx-auto">
<h2 className="text-3xl font-bold text-center mb-12">Comprehensive Network Solutions</h2> <h2 className="text-3xl font-bold text-center mb-12">Comprehensive Network Solutions</h2>
<div className="grid md:grid-cols-2 gap-8 mb-12"> <div className="grid md:grid-cols-2 gap-8 mb-12">
<Card> <Card>
<CardHeader> <CardHeader>
@ -93,7 +93,7 @@ const NetworkInfrastructure = () => {
</ul> </ul>
</CardContent> </CardContent>
</Card> </Card>
<Card> <Card>
<CardHeader> <CardHeader>
<div className="w-16 h-16 bg-teal-100 rounded-full flex items-center justify-center mb-4"> <div className="w-16 h-16 bg-teal-100 rounded-full flex items-center justify-center mb-4">
@ -113,7 +113,7 @@ const NetworkInfrastructure = () => {
</ul> </ul>
</CardContent> </CardContent>
</Card> </Card>
<Card> <Card>
<CardHeader> <CardHeader>
<div className="w-16 h-16 bg-teal-100 rounded-full flex items-center justify-center mb-4"> <div className="w-16 h-16 bg-teal-100 rounded-full flex items-center justify-center mb-4">
@ -133,7 +133,7 @@ const NetworkInfrastructure = () => {
</ul> </ul>
</CardContent> </CardContent>
</Card> </Card>
<Card> <Card>
<CardHeader> <CardHeader>
<div className="w-16 h-16 bg-teal-100 rounded-full flex items-center justify-center mb-4"> <div className="w-16 h-16 bg-teal-100 rounded-full flex items-center justify-center mb-4">
@ -163,7 +163,7 @@ const NetworkInfrastructure = () => {
<div className="container mx-auto px-4"> <div className="container mx-auto px-4">
<div className="max-w-4xl mx-auto"> <div className="max-w-4xl mx-auto">
<h2 className="text-3xl font-bold text-center mb-12">Scalable Network Solutions for Growing SMBs</h2> <h2 className="text-3xl font-bold text-center mb-12">Scalable Network Solutions for Growing SMBs</h2>
<div className="grid md:grid-cols-3 gap-8 mb-12"> <div className="grid md:grid-cols-3 gap-8 mb-12">
<div className="bg-white p-6 rounded-lg shadow border-l-4 border-teal-500"> <div className="bg-white p-6 rounded-lg shadow border-l-4 border-teal-500">
<h3 className="font-bold text-lg mb-4">Starter Network</h3> <h3 className="font-bold text-lg mb-4">Starter Network</h3>
@ -181,7 +181,7 @@ const NetworkInfrastructure = () => {
<div className="text-sm text-gray-500">Complete setup</div> <div className="text-sm text-gray-500">Complete setup</div>
</div> </div>
</div> </div>
<div className="bg-white p-6 rounded-lg shadow border-l-4 border-orange-500"> <div className="bg-white p-6 rounded-lg shadow border-l-4 border-orange-500">
<h3 className="font-bold text-lg mb-4">Professional Network</h3> <h3 className="font-bold text-lg mb-4">Professional Network</h3>
<p className="text-gray-600 mb-4">Advanced infrastructure for growing businesses with 15-50 employees.</p> <p className="text-gray-600 mb-4">Advanced infrastructure for growing businesses with 15-50 employees.</p>
@ -198,7 +198,7 @@ const NetworkInfrastructure = () => {
<div className="text-sm text-gray-500">Complete setup</div> <div className="text-sm text-gray-500">Complete setup</div>
</div> </div>
</div> </div>
<div className="bg-white p-6 rounded-lg shadow border-l-4 border-purple-500"> <div className="bg-white p-6 rounded-lg shadow border-l-4 border-purple-500">
<h3 className="font-bold text-lg mb-4">Enterprise Network</h3> <h3 className="font-bold text-lg mb-4">Enterprise Network</h3>
<p className="text-gray-600 mb-4">Comprehensive infrastructure for larger organizations with 50+ employees.</p> <p className="text-gray-600 mb-4">Comprehensive infrastructure for larger organizations with 50+ employees.</p>
@ -216,7 +216,7 @@ const NetworkInfrastructure = () => {
</div> </div>
</div> </div>
</div> </div>
<div className="bg-white p-8 rounded-lg shadow-lg"> <div className="bg-white p-8 rounded-lg shadow-lg">
<h3 className="text-2xl font-bold mb-6 text-center">Network Performance Benefits</h3> <h3 className="text-2xl font-bold mb-6 text-center">Network Performance Benefits</h3>
<div className="grid md:grid-cols-2 gap-8"> <div className="grid md:grid-cols-2 gap-8">
@ -273,7 +273,7 @@ const NetworkInfrastructure = () => {
<div className="container mx-auto px-4"> <div className="container mx-auto px-4">
<div className="max-w-4xl mx-auto"> <div className="max-w-4xl mx-auto">
<h2 className="text-3xl font-bold text-center mb-12">Professional Network Implementation</h2> <h2 className="text-3xl font-bold text-center mb-12">Professional Network Implementation</h2>
<div className="grid md:grid-cols-4 gap-8"> <div className="grid md:grid-cols-4 gap-8">
<Card className="text-center"> <Card className="text-center">
<CardHeader> <CardHeader>
@ -286,7 +286,7 @@ const NetworkInfrastructure = () => {
<p className="text-sm">Comprehensive evaluation of current infrastructure, requirements, and growth plans.</p> <p className="text-sm">Comprehensive evaluation of current infrastructure, requirements, and growth plans.</p>
</CardContent> </CardContent>
</Card> </Card>
<Card className="text-center"> <Card className="text-center">
<CardHeader> <CardHeader>
<div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4"> <div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4">
@ -298,7 +298,7 @@ const NetworkInfrastructure = () => {
<p className="text-sm">Custom network design with equipment selection and detailed implementation plan.</p> <p className="text-sm">Custom network design with equipment selection and detailed implementation plan.</p>
</CardContent> </CardContent>
</Card> </Card>
<Card className="text-center"> <Card className="text-center">
<CardHeader> <CardHeader>
<div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4"> <div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4">
@ -310,7 +310,7 @@ const NetworkInfrastructure = () => {
<p className="text-sm">Professional installation, configuration, and testing with minimal business disruption.</p> <p className="text-sm">Professional installation, configuration, and testing with minimal business disruption.</p>
</CardContent> </CardContent>
</Card> </Card>
<Card className="text-center"> <Card className="text-center">
<CardHeader> <CardHeader>
<div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4"> <div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4">
@ -332,7 +332,7 @@ const NetworkInfrastructure = () => {
<div className="container mx-auto px-4"> <div className="container mx-auto px-4">
<div className="max-w-4xl mx-auto"> <div className="max-w-4xl mx-auto">
<h2 className="text-3xl font-bold text-center mb-12">Network Problems We Solve</h2> <h2 className="text-3xl font-bold text-center mb-12">Network Problems We Solve</h2>
<div className="grid md:grid-cols-2 gap-8"> <div className="grid md:grid-cols-2 gap-8">
<div className="bg-white p-6 rounded-lg shadow"> <div className="bg-white p-6 rounded-lg shadow">
<h3 className="text-xl font-bold mb-4 text-red-600">Performance Issues</h3> <h3 className="text-xl font-bold mb-4 text-red-600">Performance Issues</h3>
@ -345,7 +345,7 @@ const NetworkInfrastructure = () => {
<li> Printers frequently going offline</li> <li> Printers frequently going offline</li>
</ul> </ul>
</div> </div>
<div className="bg-white p-6 rounded-lg shadow"> <div className="bg-white p-6 rounded-lg shadow">
<h3 className="text-xl font-bold mb-4 text-red-600">Security Concerns</h3> <h3 className="text-xl font-bold mb-4 text-red-600">Security Concerns</h3>
<ul className="space-y-3 text-gray-700"> <ul className="space-y-3 text-gray-700">
@ -358,11 +358,11 @@ const NetworkInfrastructure = () => {
</ul> </ul>
</div> </div>
</div> </div>
<div className="mt-8 bg-white p-6 rounded-lg shadow text-center"> <div className="mt-8 bg-white p-6 rounded-lg shadow text-center">
<h3 className="text-xl font-bold mb-4 text-teal-600">Emergency Network Support</h3> <h3 className="text-xl font-bold mb-4 text-teal-600">Emergency Network Support</h3>
<p className="text-gray-700 mb-4"> <p className="text-gray-700 mb-4">
When your network goes down, every minute counts. Our emergency support team provides When your network goes down, every minute counts. Our emergency support team provides
same-day response for critical network issues affecting your business operations. same-day response for critical network issues affecting your business operations.
</p> </p>
<Button className="bg-red-600 hover:bg-red-700 text-white"> <Button className="bg-red-600 hover:bg-red-700 text-white">
@ -380,10 +380,10 @@ const NetworkInfrastructure = () => {
<div className="max-w-4xl mx-auto text-center"> <div className="max-w-4xl mx-auto text-center">
<h2 className="text-3xl font-bold mb-8">Trusted Network Experts in the Coastal Bend</h2> <h2 className="text-3xl font-bold mb-8">Trusted Network Experts in the Coastal Bend</h2>
<p className="text-xl text-gray-600 mb-8"> <p className="text-xl text-gray-600 mb-8">
Bay Area Affiliates has designed and maintained business networks throughout the Corpus Christi area since 1999. Bay Area Affiliates has designed and maintained business networks throughout the Corpus Christi area since 1999.
We understand the unique connectivity challenges of coastal businesses. We understand the unique connectivity challenges of coastal businesses.
</p> </p>
<div className="grid md:grid-cols-3 gap-8 mb-12"> <div className="grid md:grid-cols-3 gap-8 mb-12">
<div className="text-center"> <div className="text-center">
<div className="text-4xl font-bold text-teal-600 mb-2">300+</div> <div className="text-4xl font-bold text-teal-600 mb-2">300+</div>
@ -398,11 +398,11 @@ const NetworkInfrastructure = () => {
<div className="text-gray-600">Average Response Time</div> <div className="text-gray-600">Average Response Time</div>
</div> </div>
</div> </div>
<div className="bg-teal-50 p-8 rounded-lg shadow-lg"> <div className="bg-teal-50 p-8 rounded-lg shadow-lg">
<h3 className="text-2xl font-bold mb-4">Network Support Across the Coastal Bend</h3> <h3 className="text-2xl font-bold mb-4">Network Support Across the Coastal Bend</h3>
<p className="text-gray-700 mb-6"> <p className="text-gray-700 mb-6">
From small office networks to multi-location enterprises, we provide comprehensive From small office networks to multi-location enterprises, we provide comprehensive
network infrastructure solutions with 24/7 monitoring and local technical support. network infrastructure solutions with 24/7 monitoring and local technical support.
</p> </p>
<div className="flex flex-wrap justify-center gap-4"> <div className="flex flex-wrap justify-center gap-4">
@ -424,10 +424,10 @@ const NetworkInfrastructure = () => {
<div className="max-w-4xl mx-auto text-center"> <div className="max-w-4xl mx-auto text-center">
<h2 className="text-3xl font-bold mb-6">Secure Your Business Network Infrastructure</h2> <h2 className="text-3xl font-bold mb-6">Secure Your Business Network Infrastructure</h2>
<p className="text-xl mb-8 text-teal-100"> <p className="text-xl mb-8 text-teal-100">
Get a comprehensive network assessment and custom infrastructure solution from Corpus Christi's Get a comprehensive network assessment and custom infrastructure solution from Corpus Christi's
trusted IT experts. Free consultation for SMBs. trusted IT experts. Free consultation for SMBs.
</p> </p>
<div className="flex flex-col sm:flex-row gap-4 justify-center mb-8"> <div className="flex flex-col sm:flex-row gap-4 justify-center mb-8">
<Button size="lg" className="bg-orange-600 hover:bg-orange-700"> <Button size="lg" className="bg-orange-600 hover:bg-orange-700">
<Router className="w-5 h-5 mr-2" /> <Router className="w-5 h-5 mr-2" />
@ -437,7 +437,7 @@ const NetworkInfrastructure = () => {
Call (361) 765-8400 Call (361) 765-8400
</Button> </Button>
</div> </div>
<p className="text-teal-200"> <p className="text-teal-200">
Free network assessment Same-day emergency support Local experts 24/7 monitoring Free network assessment Same-day emergency support Local experts 24/7 monitoring
</p> </p>

View File

@ -9,27 +9,27 @@ import { Zap, HardDrive, TrendingUp, CheckCircle, DollarSign, Clock, Gauge, BarC
const PerformanceUpgrades = () => { const PerformanceUpgrades = () => {
useEffect(() => { useEffect(() => {
document.title = 'SSD Upgrade Corpus Christi | Bay Area Affiliates'; document.title = 'SSD Upgrade Corpus Christi | Bay Area Affiliates';
const metaDescription = document.querySelector('meta[name="description"]'); const metaDescription = document.querySelector('meta[name="description"]');
if (metaDescription) { if (metaDescription) {
metaDescription.setAttribute('content', 'Boost device speed and reliability. Contact for upgrade today.'); metaDescription.setAttribute('content', 'Boost device speed and reliability. Contact for upgrade today.');
} }
const ogTitle = document.querySelector('meta[property="og:title"]'); const ogTitle = document.querySelector('meta[property="og:title"]');
if (ogTitle) { if (ogTitle) {
ogTitle.setAttribute('content', 'SSD Upgrade Corpus Christi—Boost SMB Performance'); ogTitle.setAttribute('content', 'SSD Upgrade Corpus Christi—Boost SMB Performance');
} }
const ogDescription = document.querySelector('meta[property="og:description"]'); const ogDescription = document.querySelector('meta[property="og:description"]');
if (ogDescription) { if (ogDescription) {
ogDescription.setAttribute('content', 'Boost device speed and reliability. Contact for upgrade today.'); ogDescription.setAttribute('content', 'Boost device speed and reliability. Contact for upgrade today.');
} }
const twitterTitle = document.querySelector('meta[name="twitter:title"]'); const twitterTitle = document.querySelector('meta[name="twitter:title"]');
if (twitterTitle) { if (twitterTitle) {
twitterTitle.setAttribute('content', 'Desktop Speed & Laptop Optimization Corpus Christi'); twitterTitle.setAttribute('content', 'Desktop Speed & Laptop Optimization Corpus Christi');
} }
const twitterDescription = document.querySelector('meta[name="twitter:description"]'); const twitterDescription = document.querySelector('meta[name="twitter:description"]');
if (twitterDescription) { if (twitterDescription) {
twitterDescription.setAttribute('content', 'Boost device speed and reliability. Contact for upgrade today.'); twitterDescription.setAttribute('content', 'Boost device speed and reliability. Contact for upgrade today.');
@ -39,7 +39,7 @@ const PerformanceUpgrades = () => {
return ( return (
<div className="min-h-screen"> <div className="min-h-screen">
<Navigation /> <Navigation />
<main role="main"> <main>
{/* Hero Section */} {/* Hero Section */}
<section className="bg-gradient-to-br from-purple-900 via-purple-800 to-purple-600 text-white py-20"> <section className="bg-gradient-to-br from-purple-900 via-purple-800 to-purple-600 text-white py-20">
<div className="container mx-auto px-4"> <div className="container mx-auto px-4">
@ -72,7 +72,7 @@ const PerformanceUpgrades = () => {
<div className="container mx-auto px-4"> <div className="container mx-auto px-4">
<div className="max-w-4xl mx-auto"> <div className="max-w-4xl mx-auto">
<h2 className="text-3xl font-bold text-center mb-12">Transform Your Business Performance</h2> <h2 className="text-3xl font-bold text-center mb-12">Transform Your Business Performance</h2>
<div className="grid md:grid-cols-2 gap-8 mb-12"> <div className="grid md:grid-cols-2 gap-8 mb-12">
<Card> <Card>
<CardHeader> <CardHeader>
@ -95,7 +95,7 @@ const PerformanceUpgrades = () => {
</div> </div>
</CardContent> </CardContent>
</Card> </Card>
<Card> <Card>
<CardHeader> <CardHeader>
<div className="w-16 h-16 bg-purple-100 rounded-full flex items-center justify-center mb-4"> <div className="w-16 h-16 bg-purple-100 rounded-full flex items-center justify-center mb-4">
@ -113,7 +113,7 @@ const PerformanceUpgrades = () => {
</ul> </ul>
</CardContent> </CardContent>
</Card> </Card>
<Card> <Card>
<CardHeader> <CardHeader>
<div className="w-16 h-16 bg-purple-100 rounded-full flex items-center justify-center mb-4"> <div className="w-16 h-16 bg-purple-100 rounded-full flex items-center justify-center mb-4">
@ -132,7 +132,7 @@ const PerformanceUpgrades = () => {
</div> </div>
</CardContent> </CardContent>
</Card> </Card>
<Card> <Card>
<CardHeader> <CardHeader>
<div className="w-16 h-16 bg-purple-100 rounded-full flex items-center justify-center mb-4"> <div className="w-16 h-16 bg-purple-100 rounded-full flex items-center justify-center mb-4">
@ -160,7 +160,7 @@ const PerformanceUpgrades = () => {
<div className="container mx-auto px-4"> <div className="container mx-auto px-4">
<div className="max-w-4xl mx-auto"> <div className="max-w-4xl mx-auto">
<h2 className="text-3xl font-bold text-center mb-12">Professional Upgrade Process</h2> <h2 className="text-3xl font-bold text-center mb-12">Professional Upgrade Process</h2>
<div className="grid md:grid-cols-4 gap-8 mb-12"> <div className="grid md:grid-cols-4 gap-8 mb-12">
<Card className="text-center"> <Card className="text-center">
<CardHeader> <CardHeader>
@ -173,7 +173,7 @@ const PerformanceUpgrades = () => {
<p className="text-sm">Comprehensive performance testing to identify bottlenecks and optimal upgrade path.</p> <p className="text-sm">Comprehensive performance testing to identify bottlenecks and optimal upgrade path.</p>
</CardContent> </CardContent>
</Card> </Card>
<Card className="text-center"> <Card className="text-center">
<CardHeader> <CardHeader>
<div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4"> <div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4">
@ -185,7 +185,7 @@ const PerformanceUpgrades = () => {
<p className="text-sm">Right-sized SSD recommendation based on your usage patterns and budget.</p> <p className="text-sm">Right-sized SSD recommendation based on your usage patterns and budget.</p>
</CardContent> </CardContent>
</Card> </Card>
<Card className="text-center"> <Card className="text-center">
<CardHeader> <CardHeader>
<div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4"> <div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4">
@ -197,7 +197,7 @@ const PerformanceUpgrades = () => {
<p className="text-sm">Seamless transfer of all files, programs, and settings to the new SSD.</p> <p className="text-sm">Seamless transfer of all files, programs, and settings to the new SSD.</p>
</CardContent> </CardContent>
</Card> </Card>
<Card className="text-center"> <Card className="text-center">
<CardHeader> <CardHeader>
<div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4"> <div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4">
@ -210,7 +210,7 @@ const PerformanceUpgrades = () => {
</CardContent> </CardContent>
</Card> </Card>
</div> </div>
<div className="bg-white p-8 rounded-lg shadow-lg"> <div className="bg-white p-8 rounded-lg shadow-lg">
<h3 className="text-2xl font-bold mb-6 text-center">Performance Upgrade Options</h3> <h3 className="text-2xl font-bold mb-6 text-center">Performance Upgrade Options</h3>
<div className="grid md:grid-cols-3 gap-6"> <div className="grid md:grid-cols-3 gap-6">
@ -227,7 +227,7 @@ const PerformanceUpgrades = () => {
<div className="text-sm text-gray-600">per device</div> <div className="text-sm text-gray-600">per device</div>
</div> </div>
</div> </div>
<div className="border-2 border-purple-500 p-6 rounded-lg bg-purple-50"> <div className="border-2 border-purple-500 p-6 rounded-lg bg-purple-50">
<h4 className="font-bold text-lg mb-4 text-purple-600">Professional</h4> <h4 className="font-bold text-lg mb-4 text-purple-600">Professional</h4>
<ul className="space-y-2 text-sm mb-4"> <ul className="space-y-2 text-sm mb-4">
@ -242,7 +242,7 @@ const PerformanceUpgrades = () => {
<div className="text-sm text-gray-600">per device</div> <div className="text-sm text-gray-600">per device</div>
</div> </div>
</div> </div>
<div className="border-2 border-gray-200 p-6 rounded-lg"> <div className="border-2 border-gray-200 p-6 rounded-lg">
<h4 className="font-bold text-lg mb-4 text-purple-600">Enterprise</h4> <h4 className="font-bold text-lg mb-4 text-purple-600">Enterprise</h4>
<ul className="space-y-2 text-sm mb-4"> <ul className="space-y-2 text-sm mb-4">
@ -270,10 +270,10 @@ const PerformanceUpgrades = () => {
<div className="max-w-4xl mx-auto text-center"> <div className="max-w-4xl mx-auto text-center">
<h2 className="text-3xl font-bold mb-8">Trusted Performance Experts in the Coastal Bend</h2> <h2 className="text-3xl font-bold mb-8">Trusted Performance Experts in the Coastal Bend</h2>
<p className="text-xl text-gray-600 mb-8"> <p className="text-xl text-gray-600 mb-8">
Bay Area Affiliates has optimized thousands of computers for Corpus Christi businesses since 1999. Bay Area Affiliates has optimized thousands of computers for Corpus Christi businesses since 1999.
We know which upgrades deliver the best ROI for your specific needs. We know which upgrades deliver the best ROI for your specific needs.
</p> </p>
<div className="grid md:grid-cols-3 gap-8 mb-12"> <div className="grid md:grid-cols-3 gap-8 mb-12">
<div className="text-center"> <div className="text-center">
<div className="text-4xl font-bold text-purple-600 mb-2">2,500+</div> <div className="text-4xl font-bold text-purple-600 mb-2">2,500+</div>
@ -288,11 +288,11 @@ const PerformanceUpgrades = () => {
<div className="text-gray-600">Average Turnaround</div> <div className="text-gray-600">Average Turnaround</div>
</div> </div>
</div> </div>
<div className="bg-purple-50 p-8 rounded-lg shadow-lg"> <div className="bg-purple-50 p-8 rounded-lg shadow-lg">
<h3 className="text-2xl font-bold mb-4">Serving All Coastal Bend SMBs</h3> <h3 className="text-2xl font-bold mb-4">Serving All Coastal Bend SMBs</h3>
<p className="text-gray-700 mb-6"> <p className="text-gray-700 mb-6">
From single-device upgrades to fleet optimization, we provide on-site and in-shop services From single-device upgrades to fleet optimization, we provide on-site and in-shop services
throughout the Corpus Christi area. throughout the Corpus Christi area.
</p> </p>
<div className="flex flex-wrap justify-center gap-4"> <div className="flex flex-wrap justify-center gap-4">
@ -314,10 +314,10 @@ const PerformanceUpgrades = () => {
<div className="max-w-4xl mx-auto text-center"> <div className="max-w-4xl mx-auto text-center">
<h2 className="text-3xl font-bold mb-6">Stop Waiting for Slow Computers</h2> <h2 className="text-3xl font-bold mb-6">Stop Waiting for Slow Computers</h2>
<p className="text-xl mb-8 text-purple-100"> <p className="text-xl mb-8 text-purple-100">
Transform your business productivity with professional SSD upgrades. Same-day service available Transform your business productivity with professional SSD upgrades. Same-day service available
for Corpus Christi area businesses. for Corpus Christi area businesses.
</p> </p>
<div className="flex flex-col sm:flex-row gap-4 justify-center mb-8"> <div className="flex flex-col sm:flex-row gap-4 justify-center mb-8">
<Button size="lg" className="bg-orange-600 hover:bg-orange-700"> <Button size="lg" className="bg-orange-600 hover:bg-orange-700">
<Clock className="w-5 h-5 mr-2" /> <Clock className="w-5 h-5 mr-2" />
@ -327,7 +327,7 @@ const PerformanceUpgrades = () => {
Call (361) 765-8400 Call (361) 765-8400
</Button> </Button>
</div> </div>
<p className="text-purple-200"> <p className="text-purple-200">
Free speed analysis Same-day service Local pickup & delivery Free speed analysis Same-day service Local pickup & delivery
</p> </p>

View File

@ -9,27 +9,27 @@ import { Printer, Scan, Network, CheckCircle, Wrench, Clock, Settings, Users } f
const PrinterScannerInstallation = () => { const PrinterScannerInstallation = () => {
useEffect(() => { useEffect(() => {
document.title = 'Printer Install Corpus Christi | Bay Area Affiliates'; document.title = 'Printer Install Corpus Christi | Bay Area Affiliates';
const metaDescription = document.querySelector('meta[name="description"]'); const metaDescription = document.querySelector('meta[name="description"]');
if (metaDescription) { if (metaDescription) {
metaDescription.setAttribute('content', 'Hassle-free device setup—local experts, same-day support.'); metaDescription.setAttribute('content', 'Hassle-free device setup—local experts, same-day support.');
} }
const ogTitle = document.querySelector('meta[property="og:title"]'); const ogTitle = document.querySelector('meta[property="og:title"]');
if (ogTitle) { if (ogTitle) {
ogTitle.setAttribute('content', 'Printer Installation Corpus Christi—Same-Day Setup'); ogTitle.setAttribute('content', 'Printer Installation Corpus Christi—Same-Day Setup');
} }
const ogDescription = document.querySelector('meta[property="og:description"]'); const ogDescription = document.querySelector('meta[property="og:description"]');
if (ogDescription) { if (ogDescription) {
ogDescription.setAttribute('content', 'Hassle-free device setup—local experts, same-day support.'); ogDescription.setAttribute('content', 'Hassle-free device setup—local experts, same-day support.');
} }
const twitterTitle = document.querySelector('meta[name="twitter:title"]'); const twitterTitle = document.querySelector('meta[name="twitter:title"]');
if (twitterTitle) { if (twitterTitle) {
twitterTitle.setAttribute('content', 'Scanner Setup & Office Device Support Corpus Christi'); twitterTitle.setAttribute('content', 'Scanner Setup & Office Device Support Corpus Christi');
} }
const twitterDescription = document.querySelector('meta[name="twitter:description"]'); const twitterDescription = document.querySelector('meta[name="twitter:description"]');
if (twitterDescription) { if (twitterDescription) {
twitterDescription.setAttribute('content', 'Hassle-free device setup—local experts, same-day support.'); twitterDescription.setAttribute('content', 'Hassle-free device setup—local experts, same-day support.');
@ -39,7 +39,7 @@ const PrinterScannerInstallation = () => {
return ( return (
<div className="min-h-screen"> <div className="min-h-screen">
<Navigation /> <Navigation />
<main role="main"> <main>
{/* Hero Section */} {/* Hero Section */}
<section className="bg-gradient-to-br from-indigo-900 via-indigo-800 to-indigo-600 text-white py-20"> <section className="bg-gradient-to-br from-indigo-900 via-indigo-800 to-indigo-600 text-white py-20">
<div className="container mx-auto px-4"> <div className="container mx-auto px-4">
@ -72,7 +72,7 @@ const PrinterScannerInstallation = () => {
<div className="container mx-auto px-4"> <div className="container mx-auto px-4">
<div className="max-w-4xl mx-auto"> <div className="max-w-4xl mx-auto">
<h2 className="text-3xl font-bold text-center mb-12">End Office Device Frustrations</h2> <h2 className="text-3xl font-bold text-center mb-12">End Office Device Frustrations</h2>
<div className="grid md:grid-cols-2 gap-8 mb-12"> <div className="grid md:grid-cols-2 gap-8 mb-12">
<Card> <Card>
<CardHeader> <CardHeader>
@ -92,7 +92,7 @@ const PrinterScannerInstallation = () => {
</ul> </ul>
</CardContent> </CardContent>
</Card> </Card>
<Card> <Card>
<CardHeader> <CardHeader>
<div className="w-16 h-16 bg-indigo-100 rounded-full flex items-center justify-center mb-4"> <div className="w-16 h-16 bg-indigo-100 rounded-full flex items-center justify-center mb-4">
@ -111,7 +111,7 @@ const PrinterScannerInstallation = () => {
</ul> </ul>
</CardContent> </CardContent>
</Card> </Card>
<Card> <Card>
<CardHeader> <CardHeader>
<div className="w-16 h-16 bg-indigo-100 rounded-full flex items-center justify-center mb-4"> <div className="w-16 h-16 bg-indigo-100 rounded-full flex items-center justify-center mb-4">
@ -130,7 +130,7 @@ const PrinterScannerInstallation = () => {
</ul> </ul>
</CardContent> </CardContent>
</Card> </Card>
<Card> <Card>
<CardHeader> <CardHeader>
<div className="w-16 h-16 bg-indigo-100 rounded-full flex items-center justify-center mb-4"> <div className="w-16 h-16 bg-indigo-100 rounded-full flex items-center justify-center mb-4">
@ -159,7 +159,7 @@ const PrinterScannerInstallation = () => {
<div className="container mx-auto px-4"> <div className="container mx-auto px-4">
<div className="max-w-4xl mx-auto"> <div className="max-w-4xl mx-auto">
<h2 className="text-3xl font-bold text-center mb-12">Professional Installation Process</h2> <h2 className="text-3xl font-bold text-center mb-12">Professional Installation Process</h2>
<div className="grid md:grid-cols-4 gap-8 mb-12"> <div className="grid md:grid-cols-4 gap-8 mb-12">
<Card className="text-center"> <Card className="text-center">
<CardHeader> <CardHeader>
@ -172,7 +172,7 @@ const PrinterScannerInstallation = () => {
<p className="text-sm">Evaluate your office layout, network setup, and device requirements.</p> <p className="text-sm">Evaluate your office layout, network setup, and device requirements.</p>
</CardContent> </CardContent>
</Card> </Card>
<Card className="text-center"> <Card className="text-center">
<CardHeader> <CardHeader>
<div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4"> <div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4">
@ -184,7 +184,7 @@ const PrinterScannerInstallation = () => {
<p className="text-sm">Install drivers, configure network settings, and optimize device performance.</p> <p className="text-sm">Install drivers, configure network settings, and optimize device performance.</p>
</CardContent> </CardContent>
</Card> </Card>
<Card className="text-center"> <Card className="text-center">
<CardHeader> <CardHeader>
<div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4"> <div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4">
@ -196,7 +196,7 @@ const PrinterScannerInstallation = () => {
<p className="text-sm">Configure access for all users and train staff on device operation.</p> <p className="text-sm">Configure access for all users and train staff on device operation.</p>
</CardContent> </CardContent>
</Card> </Card>
<Card className="text-center"> <Card className="text-center">
<CardHeader> <CardHeader>
<div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4"> <div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4">
@ -209,7 +209,7 @@ const PrinterScannerInstallation = () => {
</CardContent> </CardContent>
</Card> </Card>
</div> </div>
<div className="bg-white p-8 rounded-lg shadow-lg"> <div className="bg-white p-8 rounded-lg shadow-lg">
<h3 className="text-2xl font-bold mb-6 text-center">Common Device Issues We Solve</h3> <h3 className="text-2xl font-bold mb-6 text-center">Common Device Issues We Solve</h3>
<div className="grid md:grid-cols-2 gap-8"> <div className="grid md:grid-cols-2 gap-8">
@ -274,7 +274,7 @@ const PrinterScannerInstallation = () => {
<div className="container mx-auto px-4"> <div className="container mx-auto px-4">
<div className="max-w-4xl mx-auto"> <div className="max-w-4xl mx-auto">
<h2 className="text-3xl font-bold text-center mb-12">We Support All Major Brands</h2> <h2 className="text-3xl font-bold text-center mb-12">We Support All Major Brands</h2>
<div className="grid md:grid-cols-3 gap-8 mb-12"> <div className="grid md:grid-cols-3 gap-8 mb-12">
<div className="bg-gray-50 p-6 rounded-lg text-center"> <div className="bg-gray-50 p-6 rounded-lg text-center">
<h3 className="font-bold text-lg mb-4">Printer Brands</h3> <h3 className="font-bold text-lg mb-4">Printer Brands</h3>
@ -285,7 +285,7 @@ const PrinterScannerInstallation = () => {
<div>Kyocera Sharp Konica</div> <div>Kyocera Sharp Konica</div>
</div> </div>
</div> </div>
<div className="bg-gray-50 p-6 rounded-lg text-center"> <div className="bg-gray-50 p-6 rounded-lg text-center">
<h3 className="font-bold text-lg mb-4">Scanner Types</h3> <h3 className="font-bold text-lg mb-4">Scanner Types</h3>
<div className="space-y-2 text-gray-700"> <div className="space-y-2 text-gray-700">
@ -296,7 +296,7 @@ const PrinterScannerInstallation = () => {
<div>Photo Scanners</div> <div>Photo Scanners</div>
</div> </div>
</div> </div>
<div className="bg-gray-50 p-6 rounded-lg text-center"> <div className="bg-gray-50 p-6 rounded-lg text-center">
<h3 className="font-bold text-lg mb-4">Connection Types</h3> <h3 className="font-bold text-lg mb-4">Connection Types</h3>
<div className="space-y-2 text-gray-700"> <div className="space-y-2 text-gray-700">
@ -318,10 +318,10 @@ const PrinterScannerInstallation = () => {
<div className="max-w-4xl mx-auto text-center"> <div className="max-w-4xl mx-auto text-center">
<h2 className="text-3xl font-bold mb-8">Corpus Christi's Office Device Specialists</h2> <h2 className="text-3xl font-bold mb-8">Corpus Christi's Office Device Specialists</h2>
<p className="text-xl text-gray-600 mb-8"> <p className="text-xl text-gray-600 mb-8">
Bay Area Affiliates has been solving office equipment challenges for Coastal Bend businesses since 1999. Bay Area Affiliates has been solving office equipment challenges for Coastal Bend businesses since 1999.
We know the unique needs of local SMBs and provide same-day service. We know the unique needs of local SMBs and provide same-day service.
</p> </p>
<div className="grid md:grid-cols-3 gap-8 mb-12"> <div className="grid md:grid-cols-3 gap-8 mb-12">
<div className="text-center"> <div className="text-center">
<div className="text-4xl font-bold text-indigo-600 mb-2">1,200+</div> <div className="text-4xl font-bold text-indigo-600 mb-2">1,200+</div>
@ -336,11 +336,11 @@ const PrinterScannerInstallation = () => {
<div className="text-gray-600">Technical Support</div> <div className="text-gray-600">Technical Support</div>
</div> </div>
</div> </div>
<div className="bg-white p-8 rounded-lg shadow-lg"> <div className="bg-white p-8 rounded-lg shadow-lg">
<h3 className="text-2xl font-bold mb-4">Serving the Entire Coastal Bend</h3> <h3 className="text-2xl font-bold mb-4">Serving the Entire Coastal Bend</h3>
<p className="text-gray-700 mb-6"> <p className="text-gray-700 mb-6">
On-site installation and support for businesses throughout the Corpus Christi area. On-site installation and support for businesses throughout the Corpus Christi area.
We bring the expertise to your location. We bring the expertise to your location.
</p> </p>
<div className="flex flex-wrap justify-center gap-4"> <div className="flex flex-wrap justify-center gap-4">
@ -362,10 +362,10 @@ const PrinterScannerInstallation = () => {
<div className="max-w-4xl mx-auto text-center"> <div className="max-w-4xl mx-auto text-center">
<h2 className="text-3xl font-bold mb-6">Stop Wrestling with Office Devices</h2> <h2 className="text-3xl font-bold mb-6">Stop Wrestling with Office Devices</h2>
<p className="text-xl mb-8 text-indigo-100"> <p className="text-xl mb-8 text-indigo-100">
Get professional printer and scanner installation from Corpus Christi's trusted IT experts. Get professional printer and scanner installation from Corpus Christi's trusted IT experts.
Same-day service available for urgent business needs. Same-day service available for urgent business needs.
</p> </p>
<div className="flex flex-col sm:flex-row gap-4 justify-center mb-8"> <div className="flex flex-col sm:flex-row gap-4 justify-center mb-8">
<Button size="lg" className="bg-orange-600 hover:bg-orange-700"> <Button size="lg" className="bg-orange-600 hover:bg-orange-700">
<Clock className="w-5 h-5 mr-2" /> <Clock className="w-5 h-5 mr-2" />
@ -375,7 +375,7 @@ const PrinterScannerInstallation = () => {
Call (361) 765-8400 Call (361) 765-8400
</Button> </Button>
</div> </div>
<p className="text-indigo-200"> <p className="text-indigo-200">
Free consultation Same-day service Local on-site support Free consultation Same-day service Local on-site support
</p> </p>

View File

@ -3,20 +3,11 @@ import Footer from '@/components/Footer';
import { Monitor, Wifi, Cloud, Shield, Database, Settings, CheckCircle } from 'lucide-react'; import { Monitor, Wifi, Cloud, Shield, Database, Settings, CheckCircle } from 'lucide-react';
import ScrollReveal from '@/components/ScrollReveal'; import ScrollReveal from '@/components/ScrollReveal';
import { useLayoutEffect, useRef } from 'react'; import { useLayoutEffect, useRef } from 'react';
import { useSEO } from '@/hooks/useSEO';
const Services = () => { const Services = () => {
const pageRef = useRef<HTMLDivElement>(null); const pageRef = useRef<HTMLDivElement>(null);
const heroImageRef = useRef<HTMLImageElement>(null); const heroImageRef = useRef<HTMLImageElement>(null);
useSEO({
title: 'IT Services Corpus Christi | Managed IT, Network, Cloud | Bay Area Affiliates',
description: 'Complete IT solutions for Corpus Christi businesses. Hardware support, network infrastructure, cloud services, secure remote access, backup & Microsoft 365. Free consultation.',
keywords: 'IT services Corpus Christi, managed IT Coastal Bend, network infrastructure Texas, cloud services, VPN setup, Microsoft 365',
canonical: 'https://bayarea-cc.com/services',
ogImage: 'https://bayarea-cc.com/og-image.png',
});
useLayoutEffect(() => { useLayoutEffect(() => {
// Dynamically import GSAP only when needed to reduce initial bundle size // Dynamically import GSAP only when needed to reduce initial bundle size
let ctx: any; let ctx: any;
@ -172,7 +163,7 @@ const Services = () => {
<div ref={pageRef} className="min-h-screen"> <div ref={pageRef} className="min-h-screen">
<Navigation /> <Navigation />
<main role="main"> <main>
{/* Hero section with image background */} {/* Hero section with image background */}
<section className="relative h-screen flex items-center justify-center overflow-hidden"> <section className="relative h-screen flex items-center justify-center overflow-hidden">
{/* Background image with parallax */} {/* Background image with parallax */}
@ -183,7 +174,7 @@ const Services = () => {
alt="Corpus Christi IT services data center with enterprise networking equipment and server infrastructure" alt="Corpus Christi IT services data center with enterprise networking equipment and server infrastructure"
className="w-full h-[110%] object-cover will-change-transform" className="w-full h-[110%] object-cover will-change-transform"
loading="eager" loading="eager"
fetchPriority="high" fetchpriority="high"
/> />
</div> </div>

View File

@ -9,27 +9,27 @@ import { Shield, Lock, Zap, CheckCircle, Users, Globe, Server, Smartphone } from
const VpnSetup = () => { const VpnSetup = () => {
useEffect(() => { useEffect(() => {
document.title = 'VPN Setup Corpus Christi | Business WireGuard Experts'; document.title = 'VPN Setup Corpus Christi | Business WireGuard Experts';
const metaDescription = document.querySelector('meta[name="description"]'); const metaDescription = document.querySelector('meta[name="description"]');
if (metaDescription) { if (metaDescription) {
metaDescription.setAttribute('content', 'Secure remote access for SMBs—Corpus Christi\'s WireGuard VPN experts. Get fast, reliable VPN setup today.'); metaDescription.setAttribute('content', 'Secure remote access for SMBs—Corpus Christi\'s WireGuard VPN experts. Get fast, reliable VPN setup today.');
} }
const ogTitle = document.querySelector('meta[property="og:title"]'); const ogTitle = document.querySelector('meta[property="og:title"]');
if (ogTitle) { if (ogTitle) {
ogTitle.setAttribute('content', 'Corpus Christi WireGuard VPN Setup—Fast, Secure for SMBs'); ogTitle.setAttribute('content', 'Corpus Christi WireGuard VPN Setup—Fast, Secure for SMBs');
} }
const ogDescription = document.querySelector('meta[property="og:description"]'); const ogDescription = document.querySelector('meta[property="og:description"]');
if (ogDescription) { if (ogDescription) {
ogDescription.setAttribute('content', 'Secure remote access for SMBs—Corpus Christi\'s WireGuard VPN experts. Get fast, reliable VPN setup today.'); ogDescription.setAttribute('content', 'Secure remote access for SMBs—Corpus Christi\'s WireGuard VPN experts. Get fast, reliable VPN setup today.');
} }
const twitterTitle = document.querySelector('meta[name="twitter:title"]'); const twitterTitle = document.querySelector('meta[name="twitter:title"]');
if (twitterTitle) { if (twitterTitle) {
twitterTitle.setAttribute('content', 'WireGuard VPN—Remote Work Corpus Christi'); twitterTitle.setAttribute('content', 'WireGuard VPN—Remote Work Corpus Christi');
} }
const twitterDescription = document.querySelector('meta[name="twitter:description"]'); const twitterDescription = document.querySelector('meta[name="twitter:description"]');
if (twitterDescription) { if (twitterDescription) {
twitterDescription.setAttribute('content', 'Secure remote access for SMBs—Corpus Christi\'s WireGuard VPN experts. Get fast, reliable VPN setup today.'); twitterDescription.setAttribute('content', 'Secure remote access for SMBs—Corpus Christi\'s WireGuard VPN experts. Get fast, reliable VPN setup today.');
@ -39,7 +39,7 @@ const VpnSetup = () => {
return ( return (
<div className="min-h-screen"> <div className="min-h-screen">
<Navigation /> <Navigation />
<main role="main"> <main>
{/* Hero Section */} {/* Hero Section */}
<section className="bg-gradient-to-br from-green-900 via-green-800 to-green-600 text-white py-20"> <section className="bg-gradient-to-br from-green-900 via-green-800 to-green-600 text-white py-20">
<div className="container mx-auto px-4"> <div className="container mx-auto px-4">
@ -72,7 +72,7 @@ const VpnSetup = () => {
<div className="container mx-auto px-4"> <div className="container mx-auto px-4">
<div className="max-w-4xl mx-auto"> <div className="max-w-4xl mx-auto">
<h2 className="text-3xl font-bold text-center mb-12">Why WireGuard for Corpus SMBs</h2> <h2 className="text-3xl font-bold text-center mb-12">Why WireGuard for Corpus SMBs</h2>
<div className="grid md:grid-cols-2 gap-8 mb-12"> <div className="grid md:grid-cols-2 gap-8 mb-12">
<Card> <Card>
<CardHeader> <CardHeader>
@ -85,7 +85,7 @@ const VpnSetup = () => {
<p className="text-gray-600">WireGuard outperforms traditional VPN protocols with minimal latency and maximum throughput for your remote teams.</p> <p className="text-gray-600">WireGuard outperforms traditional VPN protocols with minimal latency and maximum throughput for your remote teams.</p>
</CardContent> </CardContent>
</Card> </Card>
<Card> <Card>
<CardHeader> <CardHeader>
<div className="w-16 h-16 bg-green-100 rounded-full flex items-center justify-center mb-4"> <div className="w-16 h-16 bg-green-100 rounded-full flex items-center justify-center mb-4">
@ -97,7 +97,7 @@ const VpnSetup = () => {
<p className="text-gray-600">Advanced cryptography and smaller codebase mean fewer vulnerabilities and stronger protection for your business data.</p> <p className="text-gray-600">Advanced cryptography and smaller codebase mean fewer vulnerabilities and stronger protection for your business data.</p>
</CardContent> </CardContent>
</Card> </Card>
<Card> <Card>
<CardHeader> <CardHeader>
<div className="w-16 h-16 bg-green-100 rounded-full flex items-center justify-center mb-4"> <div className="w-16 h-16 bg-green-100 rounded-full flex items-center justify-center mb-4">
@ -109,7 +109,7 @@ const VpnSetup = () => {
<p className="text-gray-600">Easy configuration and maintenance with automatic key exchange and seamless roaming between networks.</p> <p className="text-gray-600">Easy configuration and maintenance with automatic key exchange and seamless roaming between networks.</p>
</CardContent> </CardContent>
</Card> </Card>
<Card> <Card>
<CardHeader> <CardHeader>
<div className="w-16 h-16 bg-green-100 rounded-full flex items-center justify-center mb-4"> <div className="w-16 h-16 bg-green-100 rounded-full flex items-center justify-center mb-4">
@ -131,7 +131,7 @@ const VpnSetup = () => {
<div className="container mx-auto px-4"> <div className="container mx-auto px-4">
<div className="max-w-4xl mx-auto"> <div className="max-w-4xl mx-auto">
<h2 className="text-3xl font-bold text-center mb-12">Benefits of Secure Remote Work</h2> <h2 className="text-3xl font-bold text-center mb-12">Benefits of Secure Remote Work</h2>
<div className="grid md:grid-cols-3 gap-8 mb-12"> <div className="grid md:grid-cols-3 gap-8 mb-12">
<div className="text-center"> <div className="text-center">
<div className="w-20 h-20 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4"> <div className="w-20 h-20 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4">
@ -140,7 +140,7 @@ const VpnSetup = () => {
<h3 className="text-xl font-bold mb-2">Work From Anywhere</h3> <h3 className="text-xl font-bold mb-2">Work From Anywhere</h3>
<p className="text-gray-600">Access your office network securely from home, client sites, or anywhere in the world.</p> <p className="text-gray-600">Access your office network securely from home, client sites, or anywhere in the world.</p>
</div> </div>
<div className="text-center"> <div className="text-center">
<div className="w-20 h-20 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4"> <div className="w-20 h-20 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4">
<Server className="w-10 h-10 text-blue-600" /> <Server className="w-10 h-10 text-blue-600" />
@ -148,7 +148,7 @@ const VpnSetup = () => {
<h3 className="text-xl font-bold mb-2">Secure File Access</h3> <h3 className="text-xl font-bold mb-2">Secure File Access</h3>
<p className="text-gray-600">Connect to your business servers, printers, and shared drives as if you're in the office.</p> <p className="text-gray-600">Connect to your business servers, printers, and shared drives as if you're in the office.</p>
</div> </div>
<div className="text-center"> <div className="text-center">
<div className="w-20 h-20 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4"> <div className="w-20 h-20 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4">
<Smartphone className="w-10 h-10 text-blue-600" /> <Smartphone className="w-10 h-10 text-blue-600" />
@ -157,7 +157,7 @@ const VpnSetup = () => {
<p className="text-gray-600">One VPN solution for all your deviceslaptops, phones, tablets, and desktops.</p> <p className="text-gray-600">One VPN solution for all your deviceslaptops, phones, tablets, and desktops.</p>
</div> </div>
</div> </div>
<div className="bg-white p-8 rounded-lg shadow-lg"> <div className="bg-white p-8 rounded-lg shadow-lg">
<h3 className="text-2xl font-bold mb-6 text-center">WireGuard vs Traditional VPN</h3> <h3 className="text-2xl font-bold mb-6 text-center">WireGuard vs Traditional VPN</h3>
<div className="overflow-x-auto"> <div className="overflow-x-auto">
@ -208,7 +208,7 @@ const VpnSetup = () => {
<div className="container mx-auto px-4"> <div className="container mx-auto px-4">
<div className="max-w-4xl mx-auto"> <div className="max-w-4xl mx-auto">
<h2 className="text-3xl font-bold text-center mb-12">Fast, Reliable VPN Deployment</h2> <h2 className="text-3xl font-bold text-center mb-12">Fast, Reliable VPN Deployment</h2>
<div className="grid md:grid-cols-4 gap-8"> <div className="grid md:grid-cols-4 gap-8">
<Card className="text-center"> <Card className="text-center">
<CardHeader> <CardHeader>
@ -221,7 +221,7 @@ const VpnSetup = () => {
<p className="text-sm">Evaluate your network infrastructure and remote access needs.</p> <p className="text-sm">Evaluate your network infrastructure and remote access needs.</p>
</CardContent> </CardContent>
</Card> </Card>
<Card className="text-center"> <Card className="text-center">
<CardHeader> <CardHeader>
<div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4"> <div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4">
@ -233,7 +233,7 @@ const VpnSetup = () => {
<p className="text-sm">Install and configure WireGuard server on your network.</p> <p className="text-sm">Install and configure WireGuard server on your network.</p>
</CardContent> </CardContent>
</Card> </Card>
<Card className="text-center"> <Card className="text-center">
<CardHeader> <CardHeader>
<div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4"> <div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4">
@ -245,7 +245,7 @@ const VpnSetup = () => {
<p className="text-sm">Set up VPN clients on all employee devices with secure keys.</p> <p className="text-sm">Set up VPN clients on all employee devices with secure keys.</p>
</CardContent> </CardContent>
</Card> </Card>
<Card className="text-center"> <Card className="text-center">
<CardHeader> <CardHeader>
<div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4"> <div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4">
@ -268,10 +268,10 @@ const VpnSetup = () => {
<div className="max-w-4xl mx-auto text-center"> <div className="max-w-4xl mx-auto text-center">
<h2 className="text-3xl font-bold mb-8">Trusted VPN Experts Serving the Coastal Bend</h2> <h2 className="text-3xl font-bold mb-8">Trusted VPN Experts Serving the Coastal Bend</h2>
<p className="text-xl text-gray-600 mb-8"> <p className="text-xl text-gray-600 mb-8">
Bay Area Affiliates specializes in secure network solutions for local businesses. Bay Area Affiliates specializes in secure network solutions for local businesses.
We've helped hundreds of Corpus Christi SMBs implement reliable remote access. We've helped hundreds of Corpus Christi SMBs implement reliable remote access.
</p> </p>
<div className="grid md:grid-cols-2 gap-8 mb-12"> <div className="grid md:grid-cols-2 gap-8 mb-12">
<div className="bg-white p-6 rounded-lg shadow"> <div className="bg-white p-6 rounded-lg shadow">
<h3 className="text-xl font-bold mb-4 text-green-600">Local Business Focus</h3> <h3 className="text-xl font-bold mb-4 text-green-600">Local Business Focus</h3>
@ -282,7 +282,7 @@ const VpnSetup = () => {
<li> Bilingual technical support</li> <li> Bilingual technical support</li>
</ul> </ul>
</div> </div>
<div className="bg-white p-6 rounded-lg shadow"> <div className="bg-white p-6 rounded-lg shadow">
<h3 className="text-xl font-bold mb-4 text-green-600">WireGuard Specialization</h3> <h3 className="text-xl font-bold mb-4 text-green-600">WireGuard Specialization</h3>
<ul className="text-left space-y-2 text-gray-700"> <ul className="text-left space-y-2 text-gray-700">
@ -293,7 +293,7 @@ const VpnSetup = () => {
</ul> </ul>
</div> </div>
</div> </div>
<div className="bg-white p-8 rounded-lg shadow-lg"> <div className="bg-white p-8 rounded-lg shadow-lg">
<h3 className="text-2xl font-bold mb-4">Areas We Serve</h3> <h3 className="text-2xl font-bold mb-4">Areas We Serve</h3>
<div className="flex flex-wrap justify-center gap-4"> <div className="flex flex-wrap justify-center gap-4">
@ -315,10 +315,10 @@ const VpnSetup = () => {
<div className="max-w-4xl mx-auto text-center"> <div className="max-w-4xl mx-auto text-center">
<h2 className="text-3xl font-bold mb-6">Secure Your Remote Work Today</h2> <h2 className="text-3xl font-bold mb-6">Secure Your Remote Work Today</h2>
<p className="text-xl mb-8 text-green-100"> <p className="text-xl mb-8 text-green-100">
Get a fast, secure WireGuard VPN setup from Corpus Christi's trusted IT experts. Get a fast, secure WireGuard VPN setup from Corpus Christi's trusted IT experts.
Protect your business data and enable productive remote work. Protect your business data and enable productive remote work.
</p> </p>
<div className="flex flex-col sm:flex-row gap-4 justify-center mb-8"> <div className="flex flex-col sm:flex-row gap-4 justify-center mb-8">
<Button size="lg" className="bg-orange-600 hover:bg-orange-700"> <Button size="lg" className="bg-orange-600 hover:bg-orange-700">
<Lock className="w-5 h-5 mr-2" /> <Lock className="w-5 h-5 mr-2" />
@ -328,7 +328,7 @@ const VpnSetup = () => {
Call (361) 765-8400 Call (361) 765-8400
</Button> </Button>
</div> </div>
<p className="text-green-200"> <p className="text-green-200">
Free consultation Same-day setup available Local support team Free consultation Same-day setup available Local support team
</p> </p>

View File

@ -9,27 +9,27 @@ import { Globe, Mail, Palette, CheckCircle, Smartphone, Search, TrendingUp, User
const WebServices = () => { const WebServices = () => {
useEffect(() => { useEffect(() => {
document.title = 'Web Services Corpus Christi | Bay Area Affiliates'; document.title = 'Web Services Corpus Christi | Bay Area Affiliates';
const metaDescription = document.querySelector('meta[name="description"]'); const metaDescription = document.querySelector('meta[name="description"]');
if (metaDescription) { if (metaDescription) {
metaDescription.setAttribute('content', 'Elevate your local business presence—sites, domains, email.'); metaDescription.setAttribute('content', 'Elevate your local business presence—sites, domains, email.');
} }
const ogTitle = document.querySelector('meta[property="og:title"]'); const ogTitle = document.querySelector('meta[property="og:title"]');
if (ogTitle) { if (ogTitle) {
ogTitle.setAttribute('content', 'Web Services Corpus Christi—Professional Business Websites'); ogTitle.setAttribute('content', 'Web Services Corpus Christi—Professional Business Websites');
} }
const ogDescription = document.querySelector('meta[property="og:description"]'); const ogDescription = document.querySelector('meta[property="og:description"]');
if (ogDescription) { if (ogDescription) {
ogDescription.setAttribute('content', 'Elevate your local business presence—sites, domains, email.'); ogDescription.setAttribute('content', 'Elevate your local business presence—sites, domains, email.');
} }
const twitterTitle = document.querySelector('meta[name="twitter:title"]'); const twitterTitle = document.querySelector('meta[name="twitter:title"]');
if (twitterTitle) { if (twitterTitle) {
twitterTitle.setAttribute('content', 'Web Design Domain Email Portland Coastal Bend SMB'); twitterTitle.setAttribute('content', 'Web Design Domain Email Portland Coastal Bend SMB');
} }
const twitterDescription = document.querySelector('meta[name="twitter:description"]'); const twitterDescription = document.querySelector('meta[name="twitter:description"]');
if (twitterDescription) { if (twitterDescription) {
twitterDescription.setAttribute('content', 'Elevate your local business presence—sites, domains, email.'); twitterDescription.setAttribute('content', 'Elevate your local business presence—sites, domains, email.');
@ -39,7 +39,7 @@ const WebServices = () => {
return ( return (
<div className="min-h-screen"> <div className="min-h-screen">
<Navigation /> <Navigation />
<main role="main"> <main>
{/* Hero Section */} {/* Hero Section */}
<section className="bg-gradient-to-br from-emerald-900 via-emerald-800 to-emerald-600 text-white py-20"> <section className="bg-gradient-to-br from-emerald-900 via-emerald-800 to-emerald-600 text-white py-20">
<div className="container mx-auto px-4"> <div className="container mx-auto px-4">
@ -72,7 +72,7 @@ const WebServices = () => {
<div className="container mx-auto px-4"> <div className="container mx-auto px-4">
<div className="max-w-4xl mx-auto"> <div className="max-w-4xl mx-auto">
<h2 className="text-3xl font-bold text-center mb-12">Complete Digital Presence Solutions</h2> <h2 className="text-3xl font-bold text-center mb-12">Complete Digital Presence Solutions</h2>
<div className="grid md:grid-cols-2 gap-8 mb-12"> <div className="grid md:grid-cols-2 gap-8 mb-12">
<Card> <Card>
<CardHeader> <CardHeader>
@ -93,7 +93,7 @@ const WebServices = () => {
</ul> </ul>
</CardContent> </CardContent>
</Card> </Card>
<Card> <Card>
<CardHeader> <CardHeader>
<div className="w-16 h-16 bg-emerald-100 rounded-full flex items-center justify-center mb-4"> <div className="w-16 h-16 bg-emerald-100 rounded-full flex items-center justify-center mb-4">
@ -113,7 +113,7 @@ const WebServices = () => {
</ul> </ul>
</CardContent> </CardContent>
</Card> </Card>
<Card> <Card>
<CardHeader> <CardHeader>
<div className="w-16 h-16 bg-emerald-100 rounded-full flex items-center justify-center mb-4"> <div className="w-16 h-16 bg-emerald-100 rounded-full flex items-center justify-center mb-4">
@ -133,7 +133,7 @@ const WebServices = () => {
</ul> </ul>
</CardContent> </CardContent>
</Card> </Card>
<Card> <Card>
<CardHeader> <CardHeader>
<div className="w-16 h-16 bg-emerald-100 rounded-full flex items-center justify-center mb-4"> <div className="w-16 h-16 bg-emerald-100 rounded-full flex items-center justify-center mb-4">
@ -163,7 +163,7 @@ const WebServices = () => {
<div className="container mx-auto px-4"> <div className="container mx-auto px-4">
<div className="max-w-4xl mx-auto"> <div className="max-w-4xl mx-auto">
<h2 className="text-3xl font-bold text-center mb-12">Website Packages for Local SMBs</h2> <h2 className="text-3xl font-bold text-center mb-12">Website Packages for Local SMBs</h2>
<div className="grid md:grid-cols-3 gap-8 mb-12"> <div className="grid md:grid-cols-3 gap-8 mb-12">
<div className="bg-white p-6 rounded-lg shadow border-l-4 border-emerald-500"> <div className="bg-white p-6 rounded-lg shadow border-l-4 border-emerald-500">
<h3 className="font-bold text-lg mb-4">Business Starter</h3> <h3 className="font-bold text-lg mb-4">Business Starter</h3>
@ -181,7 +181,7 @@ const WebServices = () => {
<div className="text-sm text-gray-500">One-time setup</div> <div className="text-sm text-gray-500">One-time setup</div>
</div> </div>
</div> </div>
<div className="bg-white p-6 rounded-lg shadow border-l-4 border-orange-500"> <div className="bg-white p-6 rounded-lg shadow border-l-4 border-orange-500">
<h3 className="font-bold text-lg mb-4">Professional Plus</h3> <h3 className="font-bold text-lg mb-4">Professional Plus</h3>
<p className="text-gray-600 mb-4">Advanced features for growing businesses with online sales needs.</p> <p className="text-gray-600 mb-4">Advanced features for growing businesses with online sales needs.</p>
@ -198,7 +198,7 @@ const WebServices = () => {
<div className="text-sm text-gray-500">One-time setup</div> <div className="text-sm text-gray-500">One-time setup</div>
</div> </div>
</div> </div>
<div className="bg-white p-6 rounded-lg shadow border-l-4 border-purple-500"> <div className="bg-white p-6 rounded-lg shadow border-l-4 border-purple-500">
<h3 className="font-bold text-lg mb-4">Enterprise Solution</h3> <h3 className="font-bold text-lg mb-4">Enterprise Solution</h3>
<p className="text-gray-600 mb-4">Comprehensive digital presence for established businesses and organizations.</p> <p className="text-gray-600 mb-4">Comprehensive digital presence for established businesses and organizations.</p>
@ -216,7 +216,7 @@ const WebServices = () => {
</div> </div>
</div> </div>
</div> </div>
<div className="bg-white p-8 rounded-lg shadow-lg"> <div className="bg-white p-8 rounded-lg shadow-lg">
<h3 className="text-2xl font-bold mb-6 text-center">Why Local Businesses Choose Our Web Services</h3> <h3 className="text-2xl font-bold mb-6 text-center">Why Local Businesses Choose Our Web Services</h3>
<div className="grid md:grid-cols-2 gap-8"> <div className="grid md:grid-cols-2 gap-8">
@ -273,7 +273,7 @@ const WebServices = () => {
<div className="container mx-auto px-4"> <div className="container mx-auto px-4">
<div className="max-w-4xl mx-auto"> <div className="max-w-4xl mx-auto">
<h2 className="text-3xl font-bold text-center mb-12">Boost Your Local Business Visibility</h2> <h2 className="text-3xl font-bold text-center mb-12">Boost Your Local Business Visibility</h2>
<div className="grid md:grid-cols-3 gap-8 mb-12"> <div className="grid md:grid-cols-3 gap-8 mb-12">
<div className="text-center"> <div className="text-center">
<div className="w-20 h-20 bg-emerald-100 rounded-full flex items-center justify-center mx-auto mb-4"> <div className="w-20 h-20 bg-emerald-100 rounded-full flex items-center justify-center mx-auto mb-4">
@ -282,7 +282,7 @@ const WebServices = () => {
<h3 className="text-xl font-bold mb-2">Get Found Online</h3> <h3 className="text-xl font-bold mb-2">Get Found Online</h3>
<p className="text-gray-600">Appear at the top of Google searches when Corpus Christi customers look for your services.</p> <p className="text-gray-600">Appear at the top of Google searches when Corpus Christi customers look for your services.</p>
</div> </div>
<div className="text-center"> <div className="text-center">
<div className="w-20 h-20 bg-emerald-100 rounded-full flex items-center justify-center mx-auto mb-4"> <div className="w-20 h-20 bg-emerald-100 rounded-full flex items-center justify-center mx-auto mb-4">
<Smartphone className="w-10 h-10 text-emerald-600" /> <Smartphone className="w-10 h-10 text-emerald-600" />
@ -290,7 +290,7 @@ const WebServices = () => {
<h3 className="text-xl font-bold mb-2">Mobile-First Design</h3> <h3 className="text-xl font-bold mb-2">Mobile-First Design</h3>
<p className="text-gray-600">Your website looks perfect on phones, tablets, and desktopscritical for local searches.</p> <p className="text-gray-600">Your website looks perfect on phones, tablets, and desktopscritical for local searches.</p>
</div> </div>
<div className="text-center"> <div className="text-center">
<div className="w-20 h-20 bg-emerald-100 rounded-full flex items-center justify-center mx-auto mb-4"> <div className="w-20 h-20 bg-emerald-100 rounded-full flex items-center justify-center mx-auto mb-4">
<TrendingUp className="w-10 h-10 text-emerald-600" /> <TrendingUp className="w-10 h-10 text-emerald-600" />
@ -299,7 +299,7 @@ const WebServices = () => {
<p className="text-gray-600">Track website visitors, leads, and customer inquiries with detailed analytics reporting.</p> <p className="text-gray-600">Track website visitors, leads, and customer inquiries with detailed analytics reporting.</p>
</div> </div>
</div> </div>
<div className="bg-emerald-50 p-8 rounded-lg shadow-lg"> <div className="bg-emerald-50 p-8 rounded-lg shadow-lg">
<h3 className="text-2xl font-bold mb-6 text-center">Local SEO Success Stories</h3> <h3 className="text-2xl font-bold mb-6 text-center">Local SEO Success Stories</h3>
<div className="grid md:grid-cols-2 gap-8"> <div className="grid md:grid-cols-2 gap-8">
@ -314,7 +314,7 @@ const WebServices = () => {
</div> </div>
<div className="mt-6 text-center"> <div className="mt-6 text-center">
<p className="text-gray-700"> <p className="text-gray-700">
"Bay Area Affiliates redesigned our website and now we get 3x more customer inquiries from online searches. "Bay Area Affiliates redesigned our website and now we get 3x more customer inquiries from online searches.
They understand the Corpus Christi market better than anyone." They understand the Corpus Christi market better than anyone."
</p> </p>
<p className="text-emerald-600 font-semibold mt-2"> Local Business Owner</p> <p className="text-emerald-600 font-semibold mt-2"> Local Business Owner</p>
@ -329,7 +329,7 @@ const WebServices = () => {
<div className="container mx-auto px-4"> <div className="container mx-auto px-4">
<div className="max-w-4xl mx-auto"> <div className="max-w-4xl mx-auto">
<h2 className="text-3xl font-bold text-center mb-12">Professional Web Development Process</h2> <h2 className="text-3xl font-bold text-center mb-12">Professional Web Development Process</h2>
<div className="grid md:grid-cols-4 gap-8"> <div className="grid md:grid-cols-4 gap-8">
<Card className="text-center"> <Card className="text-center">
<CardHeader> <CardHeader>
@ -342,7 +342,7 @@ const WebServices = () => {
<p className="text-sm">In-person consultation to understand your business goals and target customers.</p> <p className="text-sm">In-person consultation to understand your business goals and target customers.</p>
</CardContent> </CardContent>
</Card> </Card>
<Card className="text-center"> <Card className="text-center">
<CardHeader> <CardHeader>
<div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4"> <div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4">
@ -354,7 +354,7 @@ const WebServices = () => {
<p className="text-sm">Custom website design that reflects your brand and appeals to local customers.</p> <p className="text-sm">Custom website design that reflects your brand and appeals to local customers.</p>
</CardContent> </CardContent>
</Card> </Card>
<Card className="text-center"> <Card className="text-center">
<CardHeader> <CardHeader>
<div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4"> <div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4">
@ -366,7 +366,7 @@ const WebServices = () => {
<p className="text-sm">Professional coding and testing to ensure optimal performance and security.</p> <p className="text-sm">Professional coding and testing to ensure optimal performance and security.</p>
</CardContent> </CardContent>
</Card> </Card>
<Card className="text-center"> <Card className="text-center">
<CardHeader> <CardHeader>
<div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4"> <div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4">
@ -389,10 +389,10 @@ const WebServices = () => {
<div className="max-w-4xl mx-auto text-center"> <div className="max-w-4xl mx-auto text-center">
<h2 className="text-3xl font-bold mb-8">Serving Coastal Bend Businesses Since 1999</h2> <h2 className="text-3xl font-bold mb-8">Serving Coastal Bend Businesses Since 1999</h2>
<p className="text-xl text-gray-600 mb-8"> <p className="text-xl text-gray-600 mb-8">
Bay Area Affiliates has created professional websites for hundreds of local businesses throughout Bay Area Affiliates has created professional websites for hundreds of local businesses throughout
the Corpus Christi area. We understand what works in our local market. the Corpus Christi area. We understand what works in our local market.
</p> </p>
<div className="grid md:grid-cols-4 gap-8 mb-12"> <div className="grid md:grid-cols-4 gap-8 mb-12">
<div className="text-center"> <div className="text-center">
<div className="text-4xl font-bold text-emerald-600 mb-2">200+</div> <div className="text-4xl font-bold text-emerald-600 mb-2">200+</div>
@ -411,11 +411,11 @@ const WebServices = () => {
<div className="text-gray-600">Support Team</div> <div className="text-gray-600">Support Team</div>
</div> </div>
</div> </div>
<div className="bg-white p-8 rounded-lg shadow-lg"> <div className="bg-white p-8 rounded-lg shadow-lg">
<h3 className="text-2xl font-bold mb-4">Web Services Throughout the Coastal Bend</h3> <h3 className="text-2xl font-bold mb-4">Web Services Throughout the Coastal Bend</h3>
<p className="text-gray-700 mb-6"> <p className="text-gray-700 mb-6">
From Portland's waterfront businesses to Kingsville's agricultural services, we create websites From Portland's waterfront businesses to Kingsville's agricultural services, we create websites
that connect local businesses with their communities and drive real results. that connect local businesses with their communities and drive real results.
</p> </p>
<div className="flex flex-wrap justify-center gap-4"> <div className="flex flex-wrap justify-center gap-4">
@ -437,10 +437,10 @@ const WebServices = () => {
<div className="max-w-4xl mx-auto text-center"> <div className="max-w-4xl mx-auto text-center">
<h2 className="text-3xl font-bold mb-6">Ready to Grow Your Local Business Online?</h2> <h2 className="text-3xl font-bold mb-6">Ready to Grow Your Local Business Online?</h2>
<p className="text-xl mb-8 text-emerald-100"> <p className="text-xl mb-8 text-emerald-100">
Get a professional website that attracts local customers and grows your business. Get a professional website that attracts local customers and grows your business.
Free consultation and custom quote for Coastal Bend SMBs. Free consultation and custom quote for Coastal Bend SMBs.
</p> </p>
<div className="flex flex-col sm:flex-row gap-4 justify-center mb-8"> <div className="flex flex-col sm:flex-row gap-4 justify-center mb-8">
<Button size="lg" className="bg-orange-600 hover:bg-orange-700"> <Button size="lg" className="bg-orange-600 hover:bg-orange-700">
<Globe className="w-5 h-5 mr-2" /> <Globe className="w-5 h-5 mr-2" />
@ -450,7 +450,7 @@ const WebServices = () => {
Call (361) 765-8400 Call (361) 765-8400
</Button> </Button>
</div> </div>
<p className="text-emerald-200"> <p className="text-emerald-200">
Free consultation Local market expertise Ongoing support Mobile-first design Free consultation Local market expertise Ongoing support Mobile-first design
</p> </p>

View File

@ -9,27 +9,27 @@ import { Clock, Shield, Zap, CheckCircle, AlertTriangle } from 'lucide-react';
const Windows11Transition = () => { const Windows11Transition = () => {
useEffect(() => { useEffect(() => {
document.title = 'Windows 11 Upgrade Corpus Christi | Bay Area Affiliates'; document.title = 'Windows 11 Upgrade Corpus Christi | Bay Area Affiliates';
const metaDescription = document.querySelector('meta[name="description"]'); const metaDescription = document.querySelector('meta[name="description"]');
if (metaDescription) { if (metaDescription) {
metaDescription.setAttribute('content', 'Windows 10 support ends Oct 14, 2025—upgrade now for security. Trusted service for Corpus Christi businesses.'); metaDescription.setAttribute('content', 'Windows 10 support ends Oct 14, 2025—upgrade now for security. Trusted service for Corpus Christi businesses.');
} }
const ogTitle = document.querySelector('meta[property="og:title"]'); const ogTitle = document.querySelector('meta[property="og:title"]');
if (ogTitle) { if (ogTitle) {
ogTitle.setAttribute('content', 'Windows 11 Upgrade: Secure Your Business Before Deadline'); ogTitle.setAttribute('content', 'Windows 11 Upgrade: Secure Your Business Before Deadline');
} }
const ogDescription = document.querySelector('meta[property="og:description"]'); const ogDescription = document.querySelector('meta[property="og:description"]');
if (ogDescription) { if (ogDescription) {
ogDescription.setAttribute('content', 'Windows 10 support ends Oct 14, 2025—upgrade now for security. Trusted service for Corpus Christi businesses.'); ogDescription.setAttribute('content', 'Windows 10 support ends Oct 14, 2025—upgrade now for security. Trusted service for Corpus Christi businesses.');
} }
const twitterTitle = document.querySelector('meta[name="twitter:title"]'); const twitterTitle = document.querySelector('meta[name="twitter:title"]');
if (twitterTitle) { if (twitterTitle) {
twitterTitle.setAttribute('content', 'Corpus Christi Windows 11 Upgrade—Urgent for Business Security'); twitterTitle.setAttribute('content', 'Corpus Christi Windows 11 Upgrade—Urgent for Business Security');
} }
const twitterDescription = document.querySelector('meta[name="twitter:description"]'); const twitterDescription = document.querySelector('meta[name="twitter:description"]');
if (twitterDescription) { if (twitterDescription) {
twitterDescription.setAttribute('content', 'Windows 10 support ends Oct 14, 2025—upgrade now for security. Trusted service for Corpus Christi businesses.'); twitterDescription.setAttribute('content', 'Windows 10 support ends Oct 14, 2025—upgrade now for security. Trusted service for Corpus Christi businesses.');
@ -39,7 +39,7 @@ const Windows11Transition = () => {
return ( return (
<div className="min-h-screen"> <div className="min-h-screen">
<Navigation /> <Navigation />
<main role="main"> <main>
{/* Hero Section */} {/* Hero Section */}
<section className="bg-gradient-to-br from-blue-900 via-blue-800 to-blue-600 text-white py-20"> <section className="bg-gradient-to-br from-blue-900 via-blue-800 to-blue-600 text-white py-20">
<div className="container mx-auto px-4"> <div className="container mx-auto px-4">
@ -77,11 +77,11 @@ const Windows11Transition = () => {
<h2 className="text-2xl font-bold text-red-800">Windows 10 Support Ends Oct 14, 2025</h2> <h2 className="text-2xl font-bold text-red-800">Windows 10 Support Ends Oct 14, 2025</h2>
</div> </div>
<p className="text-red-700 text-lg"> <p className="text-red-700 text-lg">
After this date, Microsoft will no longer provide security updates, bug fixes, or technical support for Windows 10. After this date, Microsoft will no longer provide security updates, bug fixes, or technical support for Windows 10.
Your business will be vulnerable to security threats and compliance issues. Your business will be vulnerable to security threats and compliance issues.
</p> </p>
</div> </div>
<div className="grid md:grid-cols-2 gap-8"> <div className="grid md:grid-cols-2 gap-8">
<Card> <Card>
<CardHeader> <CardHeader>
@ -106,7 +106,7 @@ const Windows11Transition = () => {
</div> </div>
</CardContent> </CardContent>
</Card> </Card>
<Card> <Card>
<CardHeader> <CardHeader>
<CardTitle className="text-green-600">Benefits of Windows 11</CardTitle> <CardTitle className="text-green-600">Benefits of Windows 11</CardTitle>
@ -140,7 +140,7 @@ const Windows11Transition = () => {
<div className="container mx-auto px-4"> <div className="container mx-auto px-4">
<div className="max-w-4xl mx-auto"> <div className="max-w-4xl mx-auto">
<h2 className="text-3xl font-bold text-center mb-12">Seamless Migration for Local SMBs</h2> <h2 className="text-3xl font-bold text-center mb-12">Seamless Migration for Local SMBs</h2>
<div className="grid md:grid-cols-3 gap-8 mb-12"> <div className="grid md:grid-cols-3 gap-8 mb-12">
<Card className="text-center"> <Card className="text-center">
<CardHeader> <CardHeader>
@ -153,7 +153,7 @@ const Windows11Transition = () => {
<p>We evaluate your current hardware and software for Windows 11 compatibility.</p> <p>We evaluate your current hardware and software for Windows 11 compatibility.</p>
</CardContent> </CardContent>
</Card> </Card>
<Card className="text-center"> <Card className="text-center">
<CardHeader> <CardHeader>
<div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4"> <div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4">
@ -165,7 +165,7 @@ const Windows11Transition = () => {
<p>Custom migration plan tailored to minimize business disruption.</p> <p>Custom migration plan tailored to minimize business disruption.</p>
</CardContent> </CardContent>
</Card> </Card>
<Card className="text-center"> <Card className="text-center">
<CardHeader> <CardHeader>
<div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4"> <div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-4">
@ -178,7 +178,7 @@ const Windows11Transition = () => {
</CardContent> </CardContent>
</Card> </Card>
</div> </div>
<div className="bg-blue-50 p-8 rounded-lg"> <div className="bg-blue-50 p-8 rounded-lg">
<h3 className="text-2xl font-bold mb-4">Enhanced Security & Features</h3> <h3 className="text-2xl font-bold mb-4">Enhanced Security & Features</h3>
<div className="grid md:grid-cols-2 gap-6"> <div className="grid md:grid-cols-2 gap-6">
@ -212,10 +212,10 @@ const Windows11Transition = () => {
<div className="max-w-4xl mx-auto text-center"> <div className="max-w-4xl mx-auto text-center">
<h2 className="text-3xl font-bold mb-8">Trusted by Corpus Christi Businesses for 25+ Years</h2> <h2 className="text-3xl font-bold mb-8">Trusted by Corpus Christi Businesses for 25+ Years</h2>
<p className="text-xl text-gray-600 mb-8"> <p className="text-xl text-gray-600 mb-8">
Bay Area Affiliates has been helping local businesses navigate technology transitions since 1999. Bay Area Affiliates has been helping local businesses navigate technology transitions since 1999.
We understand the unique needs of Coastal Bend SMBs. We understand the unique needs of Coastal Bend SMBs.
</p> </p>
<div className="grid md:grid-cols-3 gap-8 mb-12"> <div className="grid md:grid-cols-3 gap-8 mb-12">
<div className="text-center"> <div className="text-center">
<div className="text-4xl font-bold text-blue-600 mb-2">25+</div> <div className="text-4xl font-bold text-blue-600 mb-2">25+</div>
@ -230,7 +230,7 @@ const Windows11Transition = () => {
<div className="text-gray-600">Local Support</div> <div className="text-gray-600">Local Support</div>
</div> </div>
</div> </div>
<div className="bg-white p-8 rounded-lg shadow-lg"> <div className="bg-white p-8 rounded-lg shadow-lg">
<h3 className="text-2xl font-bold mb-4">Serving the Entire Coastal Bend</h3> <h3 className="text-2xl font-bold mb-4">Serving the Entire Coastal Bend</h3>
<div className="flex flex-wrap justify-center gap-4"> <div className="flex flex-wrap justify-center gap-4">
@ -254,7 +254,7 @@ const Windows11Transition = () => {
<p className="text-xl mb-8 text-blue-100"> <p className="text-xl mb-8 text-blue-100">
Schedule your Windows 11 upgrade assessment today. Protect your business before the October 14, 2025 deadline. Schedule your Windows 11 upgrade assessment today. Protect your business before the October 14, 2025 deadline.
</p> </p>
<div className="flex flex-col sm:flex-row gap-4 justify-center mb-8"> <div className="flex flex-col sm:flex-row gap-4 justify-center mb-8">
<Button size="lg" className="bg-orange-600 hover:bg-orange-700"> <Button size="lg" className="bg-orange-600 hover:bg-orange-700">
<Clock className="w-5 h-5 mr-2" /> <Clock className="w-5 h-5 mr-2" />
@ -264,7 +264,7 @@ const Windows11Transition = () => {
Call (361) 765-8400 Call (361) 765-8400
</Button> </Button>
</div> </div>
<p className="text-blue-200"> <p className="text-blue-200">
Free consultation Same-day response Local experts Free consultation Same-day response Local experts
</p> </p>

View File

@ -1,210 +0,0 @@
import { Variants } from 'framer-motion';
// Smooth easing curves
export const easing = {
smooth: [0.6, 0.01, 0.05, 0.95],
snappy: [0.25, 0.46, 0.45, 0.94],
bouncy: [0.68, -0.55, 0.265, 1.55],
elegant: [0.43, 0.13, 0.23, 0.96],
};
// Hero section animations
export const heroVariants: Variants = {
hidden: { opacity: 0 },
visible: {
opacity: 1,
transition: {
staggerChildren: 0.15,
delayChildren: 0.3,
},
},
};
export const heroItemVariants: Variants = {
hidden: { opacity: 0, y: 30 },
visible: {
opacity: 1,
y: 0,
transition: {
duration: 0.8,
ease: easing.elegant,
},
},
};
// Fade in up animation
export const fadeInUp: Variants = {
hidden: {
opacity: 0,
y: 60,
},
visible: {
opacity: 1,
y: 0,
transition: {
duration: 0.7,
ease: easing.elegant,
},
},
};
// Scale in animation
export const scaleIn: Variants = {
hidden: {
opacity: 0,
scale: 0.8,
},
visible: {
opacity: 1,
scale: 1,
transition: {
duration: 0.6,
ease: easing.smooth,
},
},
};
// Slide in from left
export const slideInLeft: Variants = {
hidden: {
opacity: 0,
x: -60,
},
visible: {
opacity: 1,
x: 0,
transition: {
duration: 0.7,
ease: easing.elegant,
},
},
};
// Slide in from right
export const slideInRight: Variants = {
hidden: {
opacity: 0,
x: 60,
},
visible: {
opacity: 1,
x: 0,
transition: {
duration: 0.7,
ease: easing.elegant,
},
},
};
// Stagger container
export const staggerContainer: Variants = {
hidden: { opacity: 0 },
visible: {
opacity: 1,
transition: {
staggerChildren: 0.12,
delayChildren: 0.1,
},
},
};
// Stagger item
export const staggerItem: Variants = {
hidden: { opacity: 0, y: 20 },
visible: {
opacity: 1,
y: 0,
transition: {
duration: 0.5,
ease: easing.elegant,
},
},
};
// Button hover animation
export const buttonHover = {
scale: 1.02,
transition: {
duration: 0.2,
ease: easing.snappy,
},
};
export const buttonTap = {
scale: 0.98,
};
// Card hover animation
export const cardHover = {
y: -8,
transition: {
duration: 0.3,
ease: easing.smooth,
},
};
// Glow effect
export const glowHover = {
boxShadow: '0 0 30px rgba(51, 102, 255, 0.6)',
transition: {
duration: 0.3,
},
};
// Navigation animation
export const navVariants: Variants = {
hidden: {
y: -100,
opacity: 0,
},
visible: {
y: 0,
opacity: 1,
transition: {
duration: 0.6,
ease: easing.elegant,
},
},
};
// Page transition
export const pageTransition = {
initial: { opacity: 0, y: 20 },
animate: { opacity: 1, y: 0 },
exit: { opacity: 0, y: -20 },
transition: { duration: 0.4, ease: easing.elegant },
};
// Parallax scroll effect
export const parallaxScroll = (scrollY: number, factor: number = 0.5) => ({
y: scrollY * factor,
transition: { type: 'tween', ease: 'linear', duration: 0 },
});
// Scroll reveal with intersection observer
export const scrollRevealVariants: Variants = {
hidden: {
opacity: 0,
y: 50,
},
visible: {
opacity: 1,
y: 0,
transition: {
duration: 0.7,
ease: easing.elegant,
},
},
};
// Magnetic button effect (advanced)
export const magneticEffect = (x: number, y: number, strength: number = 0.3) => ({
x: x * strength,
y: y * strength,
transition: {
type: 'spring',
stiffness: 150,
damping: 15,
mass: 0.1,
},
});

View File

@ -1,100 +0,0 @@
import { onCLS, onFCP, onLCP, onTTFB, onINP, type Metric } from 'web-vitals';
function sendToAnalytics(metric: Metric) {
// Log to console in development
if (import.meta.env.DEV) {
console.log('Web Vitals:', {
name: metric.name,
value: metric.value,
rating: metric.rating,
delta: metric.delta,
id: metric.id,
});
}
// Send to Google Analytics if available
if (typeof window !== 'undefined' && (window as any).gtag) {
(window as any).gtag('event', metric.name, {
value: Math.round(metric.name === 'CLS' ? metric.value * 1000 : metric.value),
event_category: 'Web Vitals',
event_label: metric.id,
non_interaction: true,
});
}
// Send to custom analytics endpoint if needed
if (import.meta.env.PROD && import.meta.env.VITE_ANALYTICS_ENDPOINT) {
fetch(import.meta.env.VITE_ANALYTICS_ENDPOINT, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
metric: metric.name,
value: metric.value,
rating: metric.rating,
id: metric.id,
timestamp: Date.now(),
url: window.location.href,
userAgent: navigator.userAgent,
}),
keepalive: true,
}).catch((error) => {
console.error('Failed to send web vitals:', error);
});
}
}
export function reportWebVitals() {
// Core Web Vitals
onCLS(sendToAnalytics);
onLCP(sendToAnalytics);
onINP(sendToAnalytics); // Replaces deprecated FID
// Other important metrics
onFCP(sendToAnalytics);
onTTFB(sendToAnalytics);
}
// Performance observer for additional metrics
export function observePerformance() {
if (typeof window === 'undefined' || !('PerformanceObserver' in window)) {
return;
}
// Observe long tasks (blocking the main thread)
try {
const longTaskObserver = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (entry.duration > 50) {
console.warn('Long Task detected:', {
duration: entry.duration,
startTime: entry.startTime,
name: entry.name,
});
}
}
});
longTaskObserver.observe({ entryTypes: ['longtask'] });
} catch (e) {
// Long task API not supported
}
// Observe layout shifts
try {
const layoutShiftObserver = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if ((entry as any).hadRecentInput) continue;
const value = (entry as any).value;
if (value > 0.1) {
console.warn('Large Layout Shift:', {
value,
startTime: entry.startTime,
sources: (entry as any).sources,
});
}
}
});
layoutShiftObserver.observe({ entryTypes: ['layout-shift'] });
} catch (e) {
// Layout shift API not supported
}
}