Initial commit: WilliamsPW codebase adapted for LoperBoys2.com
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"require": {
|
||||||
|
"phpmailer/phpmailer": "^7.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Convert all JPG/PNG images to WebP and update HTML with srcset fallbacks
|
||||||
|
set -e
|
||||||
|
|
||||||
|
IMG_DIR="img"
|
||||||
|
INDEX_FILE="index.html"
|
||||||
|
|
||||||
|
echo "Converting images to WebP..."
|
||||||
|
|
||||||
|
# Convert all JPG and PNG files to WebP
|
||||||
|
for f in "$IMG_DIR"/*.jpg "$IMG_DIR"/*.png; do
|
||||||
|
[ -f "$f" ] || continue
|
||||||
|
base="${f%.*}"
|
||||||
|
webp="${base}.webp"
|
||||||
|
if [ ! -f "$webp" ]; then
|
||||||
|
convert "$f" -quality 82 "$webp"
|
||||||
|
echo " Converted: $(basename "$f") -> $(basename "$webp")"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Updating index.html with srcset attributes..."
|
||||||
|
|
||||||
|
# Update each img tag in index.html with srcset
|
||||||
|
# We need to update: gallery images, work images, and og-banner in meta tags
|
||||||
|
sed -i 's|img/og-banner.jpg|img/og-banner.jpg, img/og-banner.webp|g' "$INDEX_FILE"
|
||||||
|
|
||||||
|
# Gallery images - update each img tag with srcset
|
||||||
|
for f in "$IMG_DIR"/*.jpg "$IMG_DIR"/*.png; do
|
||||||
|
[ -f "$f" ] || continue
|
||||||
|
basename="${f#$IMG_DIR/}"
|
||||||
|
basename="${basename%.*}"
|
||||||
|
# Update JPG references
|
||||||
|
if [[ "$basename" == *".jpg" ]]; then
|
||||||
|
webp="${basename%.jpg}.webp"
|
||||||
|
sed -i "s|\"$basename\"|\"$basename\", \"$webp\" type=\"image/webp\"|g" "$INDEX_FILE"
|
||||||
|
fi
|
||||||
|
# Update PNG references
|
||||||
|
if [[ "$basename" == *".png" ]]; then
|
||||||
|
webp="${basename%.png}.webp"
|
||||||
|
sed -i "s|\"$basename\"|\"$basename\", \"$webp\" type=\"image/webp\"|g" "$INDEX_FILE"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Done! Generated WebP files and updated index.html with srcset fallbacks."
|
||||||
|
echo ""
|
||||||
|
echo "Size comparison:"
|
||||||
|
echo "Original: $(du -sh "$IMG_DIR" | cut -f1)"
|
||||||
|
echo "With WebP: $(du -sh "$IMG_DIR" | cut -f1)"
|
||||||
|
du -sh "$IMG_DIR"/*.webp 2>/dev/null | awk '{printf " %-35s %s\n", $2, $1}' | sort
|
||||||
@@ -0,0 +1,1170 @@
|
|||||||
|
/* ============================================
|
||||||
|
Williams Pressure Washing Services
|
||||||
|
Professional Responsive Website
|
||||||
|
============================================ */
|
||||||
|
|
||||||
|
/* --- CSS Variables --- */
|
||||||
|
:root {
|
||||||
|
--blue-dark: #0a2463;
|
||||||
|
--blue-mid: #1e56a0;
|
||||||
|
--blue-light: #3a8fd4;
|
||||||
|
--blue-accent: #4dc8f5;
|
||||||
|
--cyan-bright: #00e0ff;
|
||||||
|
--white: #ffffff;
|
||||||
|
--off-white: #f0f6ff;
|
||||||
|
--gray-light: #e8edf3;
|
||||||
|
--gray: #8899aa;
|
||||||
|
--text-dark: #1a2332;
|
||||||
|
--text-mid: #3d4f63;
|
||||||
|
--green: #22c55e;
|
||||||
|
--green-dark: #16a34a;
|
||||||
|
--shadow: 0 4px 24px rgba(10, 36, 99, 0.12);
|
||||||
|
--shadow-lg: 0 12px 40px rgba(10, 36, 99, 0.18);
|
||||||
|
--radius: 12px;
|
||||||
|
--radius-lg: 20px;
|
||||||
|
--transition: 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Reset & Base --- */
|
||||||
|
*, *::before, *::after {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
scroll-behavior: smooth;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: 'Open Sans', Arial, sans-serif;
|
||||||
|
color: var(--text-dark);
|
||||||
|
line-height: 1.6;
|
||||||
|
overflow-x: hidden;
|
||||||
|
background: var(--white);
|
||||||
|
}
|
||||||
|
|
||||||
|
h1, h2, h3, h4 {
|
||||||
|
font-family: 'Montserrat', sans-serif;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 0 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.accent {
|
||||||
|
color: var(--blue-accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Buttons --- */
|
||||||
|
.btn {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 14px 28px;
|
||||||
|
border-radius: 50px;
|
||||||
|
font-family: 'Montserrat', sans-serif;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 1rem;
|
||||||
|
cursor: pointer;
|
||||||
|
border: none;
|
||||||
|
transition: all var(--transition);
|
||||||
|
text-align: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-icon {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary {
|
||||||
|
background: linear-gradient(135deg, var(--blue-accent), var(--blue-light));
|
||||||
|
color: var(--white);
|
||||||
|
box-shadow: 0 4px 16px rgba(77, 200, 245, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary:hover {
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 8px 24px rgba(77, 200, 245, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-secondary {
|
||||||
|
background: rgba(255, 255, 255, 0.15);
|
||||||
|
color: var(--white);
|
||||||
|
border: 2px solid rgba(255, 255, 255, 0.5);
|
||||||
|
backdrop-filter: blur(4px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-secondary:hover {
|
||||||
|
background: rgba(255, 255, 255, 0.25);
|
||||||
|
border-color: var(--white);
|
||||||
|
transform: translateY(-2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-large {
|
||||||
|
padding: 18px 36px;
|
||||||
|
font-size: 1.125rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-block {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Navigation --- */
|
||||||
|
.navbar {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 1000;
|
||||||
|
padding: 16px 0;
|
||||||
|
transition: all var(--transition);
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar.scrolled {
|
||||||
|
background: rgba(10, 36, 99, 0.95);
|
||||||
|
backdrop-filter: blur(12px);
|
||||||
|
padding: 10px 0;
|
||||||
|
box-shadow: 0 2px 20px rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-container {
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 0 24px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
font-family: 'Montserrat', sans-serif;
|
||||||
|
font-weight: 900;
|
||||||
|
font-size: 1.25rem;
|
||||||
|
color: var(--white);
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo-icon {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo-text .accent {
|
||||||
|
color: var(--cyan-bright);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-links {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-links a {
|
||||||
|
color: rgba(255, 255, 255, 0.85);
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
transition: color var(--transition);
|
||||||
|
font-family: 'Montserrat', sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-links a:hover {
|
||||||
|
color: var(--cyan-bright);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-cta {
|
||||||
|
background: linear-gradient(135deg, var(--cyan-bright), var(--blue-accent));
|
||||||
|
color: var(--blue-dark) !important;
|
||||||
|
padding: 10px 22px;
|
||||||
|
border-radius: 50px;
|
||||||
|
font-weight: 700 !important;
|
||||||
|
transition: all var(--transition);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-cta:hover {
|
||||||
|
transform: translateY(-1px);
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 224, 255, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-toggle {
|
||||||
|
display: none;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 5px;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-toggle span {
|
||||||
|
display: block;
|
||||||
|
width: 26px;
|
||||||
|
height: 3px;
|
||||||
|
background: var(--white);
|
||||||
|
border-radius: 2px;
|
||||||
|
transition: all var(--transition);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Hero Section --- */
|
||||||
|
.hero {
|
||||||
|
position: relative;
|
||||||
|
min-height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
text-align: center;
|
||||||
|
background: linear-gradient(135deg, #0a2463 0%, #1e56a0 40%, #2d7dd2 70%, #00c6ff 100%);
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 120px 24px 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background:
|
||||||
|
radial-gradient(circle at 20% 80%, rgba(0, 224, 255, 0.15) 0%, transparent 50%),
|
||||||
|
radial-gradient(circle at 80% 20%, rgba(77, 200, 245, 0.2) 0%, transparent 50%),
|
||||||
|
radial-gradient(circle at 50% 50%, rgba(255, 255, 255, 0.05) 0%, transparent 70%);
|
||||||
|
animation: heroFloat 8s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes heroFloat {
|
||||||
|
0%, 100% { transform: scale(1); }
|
||||||
|
50% { transform: scale(1.05); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Water drops animation */
|
||||||
|
.hero::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
background-image:
|
||||||
|
radial-gradient(circle, rgba(255,255,255,0.08) 2px, transparent 2px),
|
||||||
|
radial-gradient(circle, rgba(255,255,255,0.05) 1px, transparent 1px);
|
||||||
|
background-size: 80px 80px, 50px 50px;
|
||||||
|
background-position: 0 0, 25px 25px;
|
||||||
|
animation: waterDrips 20s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes waterDrips {
|
||||||
|
0% { transform: translateY(-100px); }
|
||||||
|
100% { transform: translateY(100px); }
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-content {
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
max-width: 800px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-badge {
|
||||||
|
display: inline-block;
|
||||||
|
background: rgba(255, 255, 255, 0.12);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||||
|
backdrop-filter: blur(8px);
|
||||||
|
color: var(--white);
|
||||||
|
padding: 8px 20px;
|
||||||
|
border-radius: 50px;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-title {
|
||||||
|
font-size: clamp(2.2rem, 6vw, 4rem);
|
||||||
|
font-weight: 900;
|
||||||
|
color: var(--white);
|
||||||
|
margin-bottom: 12px;
|
||||||
|
text-shadow: 0 2px 20px rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-title .accent {
|
||||||
|
color: var(--cyan-bright);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-slogan {
|
||||||
|
font-family: 'Montserrat', sans-serif;
|
||||||
|
font-size: clamp(1.2rem, 3vw, 1.6rem);
|
||||||
|
color: var(--cyan-bright);
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-sub {
|
||||||
|
font-size: clamp(1rem, 2vw, 1.15rem);
|
||||||
|
color: rgba(255, 255, 255, 0.9);
|
||||||
|
margin-bottom: 32px;
|
||||||
|
line-height: 1.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-ctas {
|
||||||
|
display: flex;
|
||||||
|
gap: 16px;
|
||||||
|
justify-content: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scroll-indicator {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 32px;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
z-index: 2;
|
||||||
|
color: rgba(255, 255, 255, 0.6);
|
||||||
|
font-size: 0.85rem;
|
||||||
|
text-align: center;
|
||||||
|
font-family: 'Montserrat', sans-serif;
|
||||||
|
font-weight: 600;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
animation: scrollBounce 2s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scroll-arrow {
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
border-right: 3px solid rgba(255, 255, 255, 0.5);
|
||||||
|
border-bottom: 3px solid rgba(255, 255, 255, 0.5);
|
||||||
|
transform: rotate(45deg);
|
||||||
|
margin: 8px auto 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes scrollBounce {
|
||||||
|
0%, 100% { transform: translateX(-50%) translateY(0); }
|
||||||
|
50% { transform: translateX(-50%) translateY(8px); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Section Titles --- */
|
||||||
|
.section-title {
|
||||||
|
text-align: center;
|
||||||
|
font-size: clamp(1.8rem, 4vw, 2.5rem);
|
||||||
|
font-weight: 900;
|
||||||
|
color: var(--blue-dark);
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-subtitle {
|
||||||
|
text-align: center;
|
||||||
|
color: var(--text-mid);
|
||||||
|
font-size: 1.1rem;
|
||||||
|
margin-bottom: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Services --- */
|
||||||
|
.services {
|
||||||
|
padding: 100px 0;
|
||||||
|
background: var(--off-white);
|
||||||
|
}
|
||||||
|
|
||||||
|
.services-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
|
||||||
|
gap: 28px;
|
||||||
|
margin-bottom: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-card {
|
||||||
|
background: var(--white);
|
||||||
|
border-radius: var(--radius-lg);
|
||||||
|
padding: 36px 28px;
|
||||||
|
box-shadow: var(--shadow);
|
||||||
|
transition: all var(--transition);
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
border: 1px solid var(--gray-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-card::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 4px;
|
||||||
|
background: linear-gradient(90deg, var(--blue-accent), var(--cyan-bright));
|
||||||
|
transform: scaleX(0);
|
||||||
|
transform-origin: left;
|
||||||
|
transition: transform var(--transition);
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-card:hover {
|
||||||
|
transform: translateY(-6px);
|
||||||
|
box-shadow: var(--shadow-lg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-card:hover::before {
|
||||||
|
transform: scaleX(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-card.featured {
|
||||||
|
border: 2px solid var(--blue-accent);
|
||||||
|
transform: scale(1.03);
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-card.featured::before {
|
||||||
|
transform: scaleX(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-card.featured:hover {
|
||||||
|
transform: scale(1.03) translateY(-6px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.featured-badge {
|
||||||
|
position: absolute;
|
||||||
|
top: 16px;
|
||||||
|
right: 16px;
|
||||||
|
background: linear-gradient(135deg, var(--blue-accent), var(--blue-light));
|
||||||
|
color: var(--white);
|
||||||
|
padding: 4px 14px;
|
||||||
|
border-radius: 50px;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 700;
|
||||||
|
font-family: 'Montserrat', sans-serif;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-icon {
|
||||||
|
font-size: 3rem;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-card h3 {
|
||||||
|
font-size: 1.3rem;
|
||||||
|
color: var(--blue-dark);
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-card p {
|
||||||
|
color: var(--text-mid);
|
||||||
|
font-size: 0.95rem;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-features {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: var(--text-mid);
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-features li {
|
||||||
|
padding: 4px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.services-cta {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Why Us --- */
|
||||||
|
.why-us {
|
||||||
|
padding: 100px 0;
|
||||||
|
background: linear-gradient(135deg, var(--blue-dark) 0%, var(--blue-mid) 100%);
|
||||||
|
color: var(--white);
|
||||||
|
}
|
||||||
|
|
||||||
|
.why-us .section-title {
|
||||||
|
color: var(--white);
|
||||||
|
}
|
||||||
|
|
||||||
|
.why-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
|
||||||
|
gap: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.why-item {
|
||||||
|
text-align: center;
|
||||||
|
padding: 32px 20px;
|
||||||
|
border-radius: var(--radius-lg);
|
||||||
|
background: rgba(255, 255, 255, 0.06);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||||
|
transition: all var(--transition);
|
||||||
|
}
|
||||||
|
|
||||||
|
.why-item:hover {
|
||||||
|
background: rgba(255, 255, 255, 0.12);
|
||||||
|
transform: translateY(-4px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.why-icon {
|
||||||
|
font-size: 2.5rem;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.why-item h4 {
|
||||||
|
font-size: 1.15rem;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
color: var(--cyan-bright);
|
||||||
|
}
|
||||||
|
|
||||||
|
.why-item p {
|
||||||
|
color: rgba(255, 255, 255, 0.8);
|
||||||
|
font-size: 0.95rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- About --- */
|
||||||
|
.about {
|
||||||
|
padding: 100px 0;
|
||||||
|
background: var(--white);
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-container {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 64px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-visual {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-watermark {
|
||||||
|
font-size: 8rem;
|
||||||
|
opacity: 0.08;
|
||||||
|
color: var(--blue-accent);
|
||||||
|
position: absolute;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-stats {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 16px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat {
|
||||||
|
background: linear-gradient(135deg, var(--blue-dark), var(--blue-mid));
|
||||||
|
border-radius: var(--radius-lg);
|
||||||
|
padding: 32px 20px;
|
||||||
|
text-align: center;
|
||||||
|
color: var(--white);
|
||||||
|
box-shadow: var(--shadow-lg);
|
||||||
|
transition: transform var(--transition);
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat:hover {
|
||||||
|
transform: scale(1.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-number {
|
||||||
|
font-family: 'Montserrat', sans-serif;
|
||||||
|
font-size: 2.2rem;
|
||||||
|
font-weight: 900;
|
||||||
|
color: var(--cyan-bright);
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-label {
|
||||||
|
font-size: 0.85rem;
|
||||||
|
line-height: 1.4;
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-content h2 {
|
||||||
|
font-size: clamp(1.6rem, 3vw, 2.2rem);
|
||||||
|
color: var(--blue-dark);
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-content p {
|
||||||
|
color: var(--text-mid);
|
||||||
|
margin-bottom: 16px;
|
||||||
|
font-size: 1.05rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-content .btn {
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Contact --- */
|
||||||
|
.contact {
|
||||||
|
padding: 100px 0;
|
||||||
|
background: var(--off-white);
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1.2fr;
|
||||||
|
gap: 48px;
|
||||||
|
align-items: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-info h3 {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
color: var(--blue-dark);
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-card {
|
||||||
|
background: var(--white);
|
||||||
|
border-radius: var(--radius-lg);
|
||||||
|
padding: 28px;
|
||||||
|
box-shadow: var(--shadow);
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 16px;
|
||||||
|
padding: 16px 0;
|
||||||
|
border-bottom: 1px solid var(--gray-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-item:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-icon {
|
||||||
|
font-size: 1.8rem;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-item strong {
|
||||||
|
display: block;
|
||||||
|
color: var(--blue-dark);
|
||||||
|
font-family: 'Montserrat', sans-serif;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-item a,
|
||||||
|
.contact-item span {
|
||||||
|
color: var(--text-mid);
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-item a:hover {
|
||||||
|
color: var(--blue-accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-cta {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Contact Form --- */
|
||||||
|
.contact-form-wrapper {
|
||||||
|
background: var(--white);
|
||||||
|
border-radius: var(--radius-lg);
|
||||||
|
padding: 40px;
|
||||||
|
box-shadow: var(--shadow-lg);
|
||||||
|
border: 1px solid var(--gray-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group label {
|
||||||
|
display: block;
|
||||||
|
font-weight: 600;
|
||||||
|
font-family: 'Montserrat', sans-serif;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: var(--blue-dark);
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group input,
|
||||||
|
.form-group select,
|
||||||
|
.form-group textarea {
|
||||||
|
width: 100%;
|
||||||
|
padding: 12px 16px;
|
||||||
|
border: 2px solid var(--gray-light);
|
||||||
|
border-radius: var(--radius);
|
||||||
|
font-family: 'Open Sans', sans-serif;
|
||||||
|
font-size: 1rem;
|
||||||
|
color: var(--text-dark);
|
||||||
|
transition: all var(--transition);
|
||||||
|
background: var(--off-white);
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group input:focus,
|
||||||
|
.form-group select:focus,
|
||||||
|
.form-group textarea:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: var(--blue-accent);
|
||||||
|
background: var(--white);
|
||||||
|
box-shadow: 0 0 0 4px rgba(77, 200, 245, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group textarea {
|
||||||
|
resize: vertical;
|
||||||
|
min-height: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-note {
|
||||||
|
text-align: center;
|
||||||
|
color: var(--gray);
|
||||||
|
font-size: 0.85rem;
|
||||||
|
margin-top: 16px;
|
||||||
|
margin-bottom: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add breathing room between privacy text and first form field */
|
||||||
|
.contact-form-wrapper > .contact-form > .form-group:first-child {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- How It Works --- */
|
||||||
|
.how-it-works {
|
||||||
|
padding: 100px 0;
|
||||||
|
background: var(--off-white);
|
||||||
|
}
|
||||||
|
|
||||||
|
.steps-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
|
||||||
|
gap: 40px;
|
||||||
|
max-width: 900px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step-card {
|
||||||
|
text-align: center;
|
||||||
|
padding: 32px 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step-number {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
background: linear-gradient(135deg, var(--blue-accent), var(--cyan-bright));
|
||||||
|
color: var(--blue-dark);
|
||||||
|
font-family: 'Montserrat', sans-serif;
|
||||||
|
font-weight: 900;
|
||||||
|
font-size: 1.4rem;
|
||||||
|
border-radius: 50%;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
box-shadow: 0 4px 16px rgba(77, 200, 245, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.step-icon {
|
||||||
|
font-size: 3rem;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step-card h4 {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
color: var(--blue-dark);
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step-card p {
|
||||||
|
color: var(--text-mid);
|
||||||
|
font-size: 0.95rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step-card a {
|
||||||
|
color: var(--blue-accent);
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Gallery --- */
|
||||||
|
.gallery {
|
||||||
|
padding: 100px 0;
|
||||||
|
background: var(--white);
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||||
|
gap: 32px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-item {
|
||||||
|
border-radius: var(--radius-lg);
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: var(--shadow);
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-before-after {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
aspect-ratio: 4 / 3;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-before-after img {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-before-after img:last-child {
|
||||||
|
clip-path: inset(0 50% 0 0);
|
||||||
|
transition: clip-path 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-item:hover .gallery-before-after img:last-child {
|
||||||
|
clip-path: inset(0 0 0 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-label {
|
||||||
|
position: absolute;
|
||||||
|
top: 12px;
|
||||||
|
padding: 4px 14px;
|
||||||
|
border-radius: 50px;
|
||||||
|
font-family: 'Montserrat', sans-serif;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
color: var(--white);
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-label-before {
|
||||||
|
left: 12px;
|
||||||
|
background: rgba(0, 0, 0, 0.6);
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-label-after {
|
||||||
|
right: 12px;
|
||||||
|
background: rgba(34, 197, 94, 0.85);
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-caption {
|
||||||
|
padding: 16px 20px;
|
||||||
|
background: var(--white);
|
||||||
|
font-family: 'Montserrat', sans-serif;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
color: var(--text-dark);
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-note {
|
||||||
|
text-align: center;
|
||||||
|
color: var(--gray);
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Our Work --- */
|
||||||
|
.our-work {
|
||||||
|
padding: 100px 0;
|
||||||
|
background: var(--off-white);
|
||||||
|
}
|
||||||
|
|
||||||
|
.work-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
||||||
|
gap: 20px;
|
||||||
|
max-width: 900px;
|
||||||
|
margin: 0 auto 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.work-item {
|
||||||
|
border-radius: var(--radius-lg);
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: var(--shadow);
|
||||||
|
background: var(--white);
|
||||||
|
}
|
||||||
|
|
||||||
|
.work-item img {
|
||||||
|
width: 100%;
|
||||||
|
height: 240px;
|
||||||
|
object-fit: cover;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.work-caption {
|
||||||
|
padding: 14px 18px;
|
||||||
|
font-family: 'Montserrat', sans-serif;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: var(--text-dark);
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Testimonials --- */
|
||||||
|
.testimonials {
|
||||||
|
padding: 100px 0;
|
||||||
|
background: linear-gradient(135deg, var(--blue-dark) 0%, var(--blue-mid) 100%);
|
||||||
|
color: var(--white);
|
||||||
|
}
|
||||||
|
|
||||||
|
.testimonials .section-title {
|
||||||
|
color: var(--white);
|
||||||
|
}
|
||||||
|
|
||||||
|
.testimonials-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||||
|
gap: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.testimonial-card {
|
||||||
|
background: rgba(255, 255, 255, 0.08);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.12);
|
||||||
|
border-radius: var(--radius-lg);
|
||||||
|
padding: 32px 28px;
|
||||||
|
transition: all var(--transition);
|
||||||
|
}
|
||||||
|
|
||||||
|
.testimonial-card:hover {
|
||||||
|
background: rgba(255, 255, 255, 0.14);
|
||||||
|
transform: translateY(-4px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.testimonial-stars {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.testimonial-text {
|
||||||
|
color: rgba(255, 255, 255, 0.9);
|
||||||
|
font-size: 1rem;
|
||||||
|
line-height: 1.7;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.testimonial-author {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.testimonial-author strong {
|
||||||
|
color: var(--cyan-bright);
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.testimonial-author span {
|
||||||
|
color: rgba(255, 255, 255, 0.6);
|
||||||
|
font-size: 0.85rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Footer --- */
|
||||||
|
.footer {
|
||||||
|
background: var(--blue-dark);
|
||||||
|
color: var(--white);
|
||||||
|
padding: 48px 0 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-content {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 24px;
|
||||||
|
padding-bottom: 24px;
|
||||||
|
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-brand h3 {
|
||||||
|
font-size: 1.3rem;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-brand .slogan {
|
||||||
|
color: var(--cyan-bright);
|
||||||
|
font-style: italic;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-contact {
|
||||||
|
display: flex;
|
||||||
|
gap: 24px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-phone,
|
||||||
|
.footer-email {
|
||||||
|
color: rgba(255, 255, 255, 0.8);
|
||||||
|
font-size: 0.95rem;
|
||||||
|
transition: color var(--transition);
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-phone:hover,
|
||||||
|
.footer-email:hover {
|
||||||
|
color: var(--cyan-bright);
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-bottom {
|
||||||
|
text-align: center;
|
||||||
|
color: rgba(255, 255, 255, 0.4);
|
||||||
|
font-size: 0.85rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Floating CTA (mobile) --- */
|
||||||
|
.floating-cta {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 24px;
|
||||||
|
right: 24px;
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
background: linear-gradient(135deg, var(--green), var(--green-dark));
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: var(--white);
|
||||||
|
box-shadow: 0 4px 20px rgba(34, 197, 94, 0.5);
|
||||||
|
z-index: 999;
|
||||||
|
transition: all var(--transition);
|
||||||
|
animation: pulse 2s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.floating-cta:hover {
|
||||||
|
transform: scale(1.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pulse {
|
||||||
|
0%, 100% { box-shadow: 0 4px 20px rgba(34, 197, 94, 0.5); }
|
||||||
|
50% { box-shadow: 0 4px 30px rgba(34, 197, 94, 0.8); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Responsive --- */
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
.about-container {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
gap: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-visual {
|
||||||
|
order: -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-card.featured {
|
||||||
|
transform: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-card.featured:hover {
|
||||||
|
transform: translateY(-6px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.nav-links {
|
||||||
|
display: none;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background: rgba(10, 36, 99, 0.97);
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 28px;
|
||||||
|
z-index: 999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-links.active {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-links a {
|
||||||
|
font-size: 1.3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-toggle {
|
||||||
|
display: flex;
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-toggle.active span:nth-child(1) {
|
||||||
|
transform: rotate(45deg) translate(6px, 6px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-toggle.active span:nth-child(2) {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-toggle.active span:nth-child(3) {
|
||||||
|
transform: rotate(-45deg) translate(6px, -6px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero {
|
||||||
|
padding: 140px 20px 60px;
|
||||||
|
min-height: 100svh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-ctas {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.services-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.why-grid {
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-content {
|
||||||
|
flex-direction: column;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-contact {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-form-wrapper {
|
||||||
|
padding: 28px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat {
|
||||||
|
padding: 24px 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-number {
|
||||||
|
font-size: 1.8rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
.why-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.about-stats {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-badge {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="400" height="300" viewBox="0 0 400 300">
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||||
|
<stop offset="0%" stop-color="#e8f4f8"/>
|
||||||
|
<stop offset="100%" stop-color="#1a2332"/>
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
<rect width="400" height="300" fill="url(\#bg)"/>
|
||||||
|
<rect x="20" y="20" width="360" height="260" rx="8" fill="none" stroke="#22c55e" stroke-width="2" stroke-dasharray="8,4" opacity="0.3"/>
|
||||||
|
<text x="200" y="130" text-anchor="middle" fill="#22c55e" font-family="Arial,sans-serif" font-size="28" font-weight="bold">Clean House Siding</text>
|
||||||
|
<text x="200" y="170" text-anchor="middle" fill="white" font-family="Arial,sans-serif" font-size="14" opacity="0.6">Replace with real photo</text>
|
||||||
|
<text x="200" y="200" text-anchor="middle" fill="white" font-family="Arial,sans-serif" font-size="11" opacity="0.4">400 × 300</text>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1005 B |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
@@ -0,0 +1,13 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="400" height="300" viewBox="0 0 400 300">
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||||
|
<stop offset="0%" stop-color="#e8f4f8"/>
|
||||||
|
<stop offset="100%" stop-color="#1a2332"/>
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
<rect width="400" height="300" fill="url(\#bg)"/>
|
||||||
|
<rect x="20" y="20" width="360" height="260" rx="8" fill="none" stroke="#22c55e" stroke-width="2" stroke-dasharray="8,4" opacity="0.3"/>
|
||||||
|
<text x="200" y="130" text-anchor="middle" fill="#22c55e" font-family="Arial,sans-serif" font-size="28" font-weight="bold">Sparkling Storefront</text>
|
||||||
|
<text x="200" y="170" text-anchor="middle" fill="white" font-family="Arial,sans-serif" font-size="14" opacity="0.6">Replace with real photo</text>
|
||||||
|
<text x="200" y="200" text-anchor="middle" fill="white" font-family="Arial,sans-serif" font-size="11" opacity="0.4">400 × 300</text>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1007 B |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
@@ -0,0 +1,13 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="400" height="300" viewBox="0 0 400 300">
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||||
|
<stop offset="0%" stop-color="#3a6090"/>
|
||||||
|
<stop offset="100%" stop-color="#1a2332"/>
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
<rect width="400" height="300" fill="url(\#bg)"/>
|
||||||
|
<rect x="20" y="20" width="360" height="260" rx="8" fill="none" stroke="#4dc8f5" stroke-width="2" stroke-dasharray="8,4" opacity="0.3"/>
|
||||||
|
<text x="200" y="130" text-anchor="middle" fill="#4dc8f5" font-family="Arial,sans-serif" font-size="28" font-weight="bold">Clean Truck Fleet</text>
|
||||||
|
<text x="200" y="170" text-anchor="middle" fill="white" font-family="Arial,sans-serif" font-size="14" opacity="0.6">Replace with real photo</text>
|
||||||
|
<text x="200" y="200" text-anchor="middle" fill="white" font-family="Arial,sans-serif" font-size="11" opacity="0.4">400 × 300</text>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1004 B |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 175 B |
|
After Width: | Height: | Size: 164 B |
@@ -0,0 +1,13 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="400" height="300" viewBox="0 0 400 300">
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||||
|
<stop offset="0%" stop-color="#5a4a3a"/>
|
||||||
|
<stop offset="100%" stop-color="#1a2332"/>
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
<rect width="400" height="300" fill="url(\#bg)"/>
|
||||||
|
<rect x="20" y="20" width="360" height="260" rx="8" fill="none" stroke="#c97a3d" stroke-width="2" stroke-dasharray="8,4" opacity="0.3"/>
|
||||||
|
<text x="200" y="130" text-anchor="middle" fill="#c97a3d" font-family="Arial,sans-serif" font-size="28" font-weight="bold">Dirty House Siding</text>
|
||||||
|
<text x="200" y="170" text-anchor="middle" fill="white" font-family="Arial,sans-serif" font-size="14" opacity="0.6">Replace with real photo</text>
|
||||||
|
<text x="200" y="200" text-anchor="middle" fill="white" font-family="Arial,sans-serif" font-size="11" opacity="0.4">400 × 300</text>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1005 B |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
@@ -0,0 +1,13 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="400" height="300" viewBox="0 0 400 300">
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||||
|
<stop offset="0%" stop-color="#4a4a4a"/>
|
||||||
|
<stop offset="100%" stop-color="#1a2332"/>
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
<rect width="400" height="300" fill="url(\#bg)"/>
|
||||||
|
<rect x="20" y="20" width="360" height="260" rx="8" fill="none" stroke="#c97a3d" stroke-width="2" stroke-dasharray="8,4" opacity="0.3"/>
|
||||||
|
<text x="200" y="130" text-anchor="middle" fill="#c97a3d" font-family="Arial,sans-serif" font-size="28" font-weight="bold">Grimy Storefront</text>
|
||||||
|
<text x="200" y="170" text-anchor="middle" fill="white" font-family="Arial,sans-serif" font-size="14" opacity="0.6">Replace with real photo</text>
|
||||||
|
<text x="200" y="200" text-anchor="middle" fill="white" font-family="Arial,sans-serif" font-size="11" opacity="0.4">400 × 300</text>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1003 B |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
@@ -0,0 +1,13 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="400" height="300" viewBox="0 0 400 300">
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||||
|
<stop offset="0%" stop-color="#4a3728"/>
|
||||||
|
<stop offset="100%" stop-color="#1a2332"/>
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
<rect width="400" height="300" fill="url(\#bg)"/>
|
||||||
|
<rect x="20" y="20" width="360" height="260" rx="8" fill="none" stroke="#c97a3d" stroke-width="2" stroke-dasharray="8,4" opacity="0.3"/>
|
||||||
|
<text x="200" y="130" text-anchor="middle" fill="#c97a3d" font-family="Arial,sans-serif" font-size="28" font-weight="bold">Dirty Truck Fleet</text>
|
||||||
|
<text x="200" y="170" text-anchor="middle" fill="white" font-family="Arial,sans-serif" font-size="14" opacity="0.6">Replace with real photo</text>
|
||||||
|
<text x="200" y="200" text-anchor="middle" fill="white" font-family="Arial,sans-serif" font-size="11" opacity="0.4">400 × 300</text>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1004 B |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 986 B |
|
After Width: | Height: | Size: 486 B |
|
After Width: | Height: | Size: 52 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 139 KiB |
|
After Width: | Height: | Size: 123 KiB |
|
After Width: | Height: | Size: 86 KiB |
|
After Width: | Height: | Size: 61 KiB |
|
After Width: | Height: | Size: 131 KiB |
|
After Width: | Height: | Size: 113 KiB |
|
After Width: | Height: | Size: 154 KiB |
|
After Width: | Height: | Size: 141 KiB |
|
After Width: | Height: | Size: 146 KiB |
|
After Width: | Height: | Size: 127 KiB |
@@ -0,0 +1,495 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Loper Boys Pressure Washing | If It's Dirty We'll Clean It | Coshocton, OH</title>
|
||||||
|
<meta name="description" content="Professional pressure washing services for truck fleets, bus fleets, houses, and storefronts in Coshocton, OH and surrounding areas. Loper Boys Pressure Washing — If it's dirty, we'll clean it. Call (740) 502-3120.">
|
||||||
|
<meta name="keywords" content="pressure washing, pressure wash, truck fleet washing, bus fleet washing, house washing, storefront cleaning, Coshocton OH, Coshocton County, power washing, soft washing">
|
||||||
|
<meta name="author" content="Loper Boys Pressure Washing">
|
||||||
|
<meta name="robots" content="index, follow">
|
||||||
|
<link rel="canonical" href="https://WilliamsPressureWashingServices.com/">
|
||||||
|
|
||||||
|
<!-- Open Graph / Facebook -->
|
||||||
|
<meta property="og:type" content="website">
|
||||||
|
<meta property="og:url" content="https://WilliamsPressureWashingServices.com/">
|
||||||
|
<meta property="og:title" content="Loper Boys Pressure Washing | Professional Cleaning">
|
||||||
|
<meta property="og:description" content="Professional pressure washing for truck fleets, bus fleets, houses, and storefronts in Coshocton, OH. If it's dirty, we'll clean it.">
|
||||||
|
<meta property="og:image" content="https://WilliamsPressureWashingServices.com/img/og-banner.webp">
|
||||||
|
<meta property="og:locale" content="en_US">
|
||||||
|
<meta property="og:site_name" content="Loper Boys Pressure Washing">
|
||||||
|
|
||||||
|
<!-- Twitter Card -->
|
||||||
|
<meta name="twitter:card" content="summary_large_image">
|
||||||
|
<meta name="twitter:url" content="https://WilliamsPressureWashingServices.com/">
|
||||||
|
<meta name="twitter:title" content="Loper Boys Pressure Washing">
|
||||||
|
<meta name="twitter:description" content="Professional pressure washing for truck fleets, bus fleets, houses, and storefronts in Coshocton, OH.">
|
||||||
|
<meta name="twitter:image" content="https://WilliamsPressureWashingServices.com/img/og-banner.webp">
|
||||||
|
|
||||||
|
<!-- Favicon -->
|
||||||
|
<link rel="icon" type="image/png" sizes="32x32" href="img/favicon.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="16x16" href="img/favicon.png">
|
||||||
|
<link rel="apple-touch-icon" sizes="180x180" href="img/apple-touch-icon.png">
|
||||||
|
|
||||||
|
<!-- Structured Data (LocalBusiness) -->
|
||||||
|
<script type="application/ld+json">
|
||||||
|
{
|
||||||
|
"@context": "https://schema.org",
|
||||||
|
"@type": "LocalBusiness",
|
||||||
|
"name": "Loper Boys Pressure Washing",
|
||||||
|
"description": "Professional pressure washing services for truck fleets, bus fleets, houses, and storefronts in Coshocton, OH and surrounding areas.",
|
||||||
|
"slogan": "If it's dirty, we'll clean it",
|
||||||
|
"url": "https://WilliamsPressureWashingServices.com",
|
||||||
|
"telephone": "+1-740-502-3120",
|
||||||
|
"email": "waltwilliams87@gmail.com",
|
||||||
|
"address": {
|
||||||
|
"@type": "PostalAddress",
|
||||||
|
"streetAddress": "26096 State Route 93",
|
||||||
|
"addressLocality": "Fresno",
|
||||||
|
"addressRegion": "OH",
|
||||||
|
"postalCode": "43824"
|
||||||
|
},
|
||||||
|
"areaServed": {
|
||||||
|
"@type": "Place",
|
||||||
|
"name": "Coshocton, Ohio and surrounding areas"
|
||||||
|
},
|
||||||
|
"serviceType": ["Pressure Washing", "Truck Fleet Washing", "Bus Fleet Washing", "House Washing", "Storefront Cleaning"],
|
||||||
|
"priceRange": "$",
|
||||||
|
"openingHours": "Mo-Sa 07:00-19:00",
|
||||||
|
"image": "https://WilliamsPressureWashingServices.com/img/og-banner.webp",
|
||||||
|
"sameAs": []
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Privacy-respecting Analytics (Plausible / Umami placeholder) -->
|
||||||
|
<!-- <script defer src="https://analytics.yourdomain.com/js/script.js" data-domain="WilliamsPressureWashingServices.com"></script> -->
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="css/style.css?v=2">
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@400;600;700;900&family=Open+Sans:wght@400;600&display=swap" rel="stylesheet">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!-- Navigation -->
|
||||||
|
<nav class="navbar" id="navbar">
|
||||||
|
<div class="nav-container">
|
||||||
|
<a href="#" class="logo">
|
||||||
|
<span class="logo-icon">💧</span>
|
||||||
|
<span class="logo-text">Williams<span class="accent">Pressure</span>Washing</span>
|
||||||
|
</a>
|
||||||
|
<button class="nav-toggle" id="navToggle" aria-label="Toggle menu">
|
||||||
|
<span></span><span></span><span></span>
|
||||||
|
</button>
|
||||||
|
<ul class="nav-links" id="navLinks">
|
||||||
|
<li><a href="#home">Home</a></li>
|
||||||
|
<li><a href="#services">Services</a></li>
|
||||||
|
<li><a href="#about">About</a></li>
|
||||||
|
<li><a href="#contact" class="nav-cta">Get a Free Quote</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<!-- Hero Section -->
|
||||||
|
<section class="hero" id="home">
|
||||||
|
<div class="hero-overlay"></div>
|
||||||
|
<div class="hero-content">
|
||||||
|
<div class="hero-badge">⭐ Trusted Local Professionals</div>
|
||||||
|
<h1 class="hero-title">Williams <span class="accent">Pressure</span> Washing Services</h1>
|
||||||
|
<p class="hero-slogan">"If it's dirty, we'll clean it"</p>
|
||||||
|
<p class="hero-sub">Specializing in <strong>truck fleets</strong> · <strong>bus fleets</strong> · <strong>houses</strong> · <strong>store fronts</strong></p>
|
||||||
|
<div class="hero-ctas">
|
||||||
|
<a href="tel:7405023120" class="btn btn-primary">
|
||||||
|
<svg class="btn-icon" viewBox="0 0 24 24" fill="currentColor" width="20" height="20"><path d="M6.62 10.79c1.44 2.83 3.76 5.14 6.59 6.59l2.2-2.2c.27-.27.67-.36 1.02-.24 1.12.37 2.33.57 3.57.57.55 0 1 .45 1 1V20c0 .55-.45 1-1 1-9.39 0-17-7.61-17-17 0-.55.45-1 1-1h3.5c.55 0 1 .45 1 1 0 1.25.2 2.45.57 3.57.11.35.03.74-.25 1.02l-2.2 2.2z"/></svg>
|
||||||
|
(740) 502-3120
|
||||||
|
</a>
|
||||||
|
<a href="#contact" class="btn btn-secondary">Contact Us Today</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="scroll-indicator">
|
||||||
|
<span>Scroll Down</span>
|
||||||
|
<div class="scroll-arrow"></div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- How It Works -->
|
||||||
|
<section class="how-it-works">
|
||||||
|
<div class="container">
|
||||||
|
<h2 class="section-title">How It <span class="accent">Works</span></h2>
|
||||||
|
<p class="section-subtitle">Three simple steps to a cleaner surface</p>
|
||||||
|
<div class="steps-grid">
|
||||||
|
<div class="step-card">
|
||||||
|
<div class="step-number">1</div>
|
||||||
|
<div class="step-icon">📞</div>
|
||||||
|
<h4>Contact Us</h4>
|
||||||
|
<p>Call <a href="tel:7405023120">(740) 502-3120</a> or fill out our quick form with details about what needs cleaning.</p>
|
||||||
|
</div>
|
||||||
|
<div class="step-card">
|
||||||
|
<div class="step-number">2</div>
|
||||||
|
<div class="step-icon">📋</div>
|
||||||
|
<h4>Get Your Free Quote</h4>
|
||||||
|
<p>We'll assess the job and give you a clear, honest quote — no hidden fees, no surprises.</p>
|
||||||
|
</div>
|
||||||
|
<div class="step-card">
|
||||||
|
<div class="step-number">3</div>
|
||||||
|
<div class="step-icon">✨</div>
|
||||||
|
<h4>We Clean It Up</h4>
|
||||||
|
<p>Show up when we say we will, do great work, and you'll see the difference immediately.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Services Section -->
|
||||||
|
<section class="services" id="services">
|
||||||
|
<div class="container">
|
||||||
|
<h2 class="section-title">Our <span class="accent">Services</span></h2>
|
||||||
|
<p class="section-subtitle">Professional cleaning solutions for every surface</p>
|
||||||
|
<div class="services-grid">
|
||||||
|
<div class="service-card">
|
||||||
|
<div class="service-icon">🚛</div>
|
||||||
|
<h3>Truck Fleet Washing</h3>
|
||||||
|
<p>Keep your fleet looking professional and well-maintained. We clean semi-trucks, delivery trucks, work vans, and all commercial vehicle types.</p>
|
||||||
|
<ul class="service-features">
|
||||||
|
<li>✅ Exterior deep cleaning</li>
|
||||||
|
<li>✅ Wheel & tire cleaning</li>
|
||||||
|
<li>✅ Undercarriage wash</li>
|
||||||
|
<li>✅ Same-day service available</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="service-card featured">
|
||||||
|
<div class="featured-badge">Most Popular</div>
|
||||||
|
<div class="service-icon">🚌</div>
|
||||||
|
<h3>Bus Fleet Washing</h3>
|
||||||
|
<p>School buses, transit buses, shuttle buses — we handle all fleet sizes with thorough, efficient cleaning. Every job includes exterior wash, window & mirror cleaning, and undercarriage inspection and cleaning.</p>
|
||||||
|
<ul class="service-features">
|
||||||
|
<li>✅ Full exterior wash</li>
|
||||||
|
<li>✅ Window & mirror cleaning</li>
|
||||||
|
<li>✅ Undercarriage inspection & cleaning</li>
|
||||||
|
<li>✅ Sign & decal safe</li>
|
||||||
|
<li>✅ Scheduled maintenance plans</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="service-card">
|
||||||
|
<div class="service-icon">🏠</div>
|
||||||
|
<h3>House Washing</h3>
|
||||||
|
<p>Restore your home's curb appeal with our professional soft washing and pressure washing. Safe for all siding types including vinyl, brick, stucco, and wood.</p>
|
||||||
|
<ul class="service-features">
|
||||||
|
<li>✅ Soft wash technology</li>
|
||||||
|
<li>✅ Driveway & sidewalk cleaning</li>
|
||||||
|
<li>✅ Deck & patio washing</li>
|
||||||
|
<li>✅ Mold & mildew removal</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="service-card">
|
||||||
|
<div class="service-icon">🏪</div>
|
||||||
|
<h3>Storefront Cleaning</h3>
|
||||||
|
<p>First impressions matter. Clean storefronts attract customers. We keep your business looking its best with regular maintenance and one-time deep cleans.</p>
|
||||||
|
<ul class="service-features">
|
||||||
|
<li>✅ Window & glass cleaning</li>
|
||||||
|
<li>✅ Awning cleaning</li>
|
||||||
|
<li>✅ Sign & facade wash</li>
|
||||||
|
<li>✅ Parking lot cleaning</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="services-cta">
|
||||||
|
<a href="tel:7405023120" class="btn btn-primary btn-large">📞 Call (740) 502-3120 for a Free Quote</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Why Choose Us -->
|
||||||
|
<section class="why-us">
|
||||||
|
<div class="container">
|
||||||
|
<h2 class="section-title">Why Choose <span class="accent">Williams</span>?</h2>
|
||||||
|
<div class="why-grid">
|
||||||
|
<div class="why-item">
|
||||||
|
<div class="why-icon">💪</div>
|
||||||
|
<h4>We Get It Done Right</h4>
|
||||||
|
<p>No job is too big or too dirty. Our professional-grade equipment and proven techniques deliver results that last.</p>
|
||||||
|
</div>
|
||||||
|
<div class="why-item">
|
||||||
|
<div class="why-icon">⏰</div>
|
||||||
|
<h4>Reliable & On Time</h4>
|
||||||
|
<p>We respect your schedule. Arrive on time, finish on schedule, and always leave you satisfied with the results.</p>
|
||||||
|
</div>
|
||||||
|
<div class="why-item">
|
||||||
|
<div class="why-icon">💰</div>
|
||||||
|
<h4>Fair & Transparent Pricing</h4>
|
||||||
|
<p>No hidden fees, no surprise charges. Get a clear quote upfront and stick to it. Quality service at honest prices.</p>
|
||||||
|
</div>
|
||||||
|
<div class="why-item">
|
||||||
|
<div class="why-icon">🌿</div>
|
||||||
|
<h4>Eco-Friendly Solutions</h4>
|
||||||
|
<p>We use environmentally responsible cleaning solutions that are tough on dirt but gentle on the planet.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Before & After Gallery — hidden until we have Walter's photos -->
|
||||||
|
<section class="gallery" id="gallery" style="display:none;">
|
||||||
|
<div class="container">
|
||||||
|
<h2 class="section-title">Before & <span class="accent">After</span></h2>
|
||||||
|
<p class="section-subtitle">See the difference professional pressure washing makes</p>
|
||||||
|
<div class="gallery-grid">
|
||||||
|
<div class="gallery-item">
|
||||||
|
<div class="gallery-before-after">
|
||||||
|
<picture>
|
||||||
|
<source srcset="img/before-truck.webp" type="image/webp">
|
||||||
|
<img src="img/before-truck.jpg" alt="Before: Dirty truck fleet exterior covered in grime and road film" loading="lazy">
|
||||||
|
</picture>
|
||||||
|
<picture>
|
||||||
|
<source srcset="img/after-truck.webp" type="image/webp">
|
||||||
|
<img src="img/after-truck.jpg" alt="After: Clean truck fleet with restored appearance" loading="lazy">
|
||||||
|
</picture>
|
||||||
|
<div class="gallery-label gallery-label-before">Before</div>
|
||||||
|
<div class="gallery-label gallery-label-after">After</div>
|
||||||
|
</div>
|
||||||
|
<p class="gallery-caption">Fleet Wash — Delivery Trucks</p>
|
||||||
|
</div>
|
||||||
|
<div class="gallery-item">
|
||||||
|
<div class="gallery-before-after">
|
||||||
|
<picture>
|
||||||
|
<source srcset="img/before-house.webp" type="image/webp">
|
||||||
|
<img src="img/before-house.jpg" alt="Before: Dirty house siding with algae and mildew" loading="lazy">
|
||||||
|
</picture>
|
||||||
|
<picture>
|
||||||
|
<source srcset="img/after-house.webp" type="image/webp">
|
||||||
|
<img src="img/after-house.jpg" alt="After: Clean house siding restored to original color" loading="lazy">
|
||||||
|
</picture>
|
||||||
|
<div class="gallery-label gallery-label-before">Before</div>
|
||||||
|
<div class="gallery-label gallery-label-after">After</div>
|
||||||
|
</div>
|
||||||
|
<p class="gallery-caption">House Wash — Vinyl Siding</p>
|
||||||
|
</div>
|
||||||
|
<div class="gallery-item">
|
||||||
|
<div class="gallery-before-after">
|
||||||
|
<picture>
|
||||||
|
<source srcset="img/before-storefront.webp" type="image/webp">
|
||||||
|
<img src="img/before-storefront.jpg" alt="Before: Grimy storefront windows and entrance" loading="lazy">
|
||||||
|
</picture>
|
||||||
|
<picture>
|
||||||
|
<source srcset="img/after-storefront.webp" type="image/webp">
|
||||||
|
<img src="img/after-storefront.jpg" alt="After: Sparkling clean storefront" loading="lazy">
|
||||||
|
</picture>
|
||||||
|
<div class="gallery-label gallery-label-before">Before</div>
|
||||||
|
<div class="gallery-label gallery-label-after">After</div>
|
||||||
|
</div>
|
||||||
|
<p class="gallery-caption">Storefront — Windows & Facade</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="gallery-note">📸 Real photos from actual jobs in the Coshocton area</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Our Work -->
|
||||||
|
<section class="our-work">
|
||||||
|
<div class="container">
|
||||||
|
<h2 class="section-title">See Our <span class="accent">Work</span></h2>
|
||||||
|
<p class="section-subtitle">Real jobs, real results — no stock photos</p>
|
||||||
|
<div class="work-grid">
|
||||||
|
<div class="work-item">
|
||||||
|
<picture>
|
||||||
|
<source srcset="img/work-1-truck-setup.webp" type="image/webp">
|
||||||
|
<img src="img/work-1-truck-setup.jpg" alt="Williams Pressure Washing truck fleet washing setup" loading="lazy">
|
||||||
|
</picture>
|
||||||
|
<p class="work-caption">Fleet Washing — On-site Setup</p>
|
||||||
|
</div>
|
||||||
|
<div class="work-item">
|
||||||
|
<picture>
|
||||||
|
<source srcset="img/work-2-action-washing.webp" type="image/webp">
|
||||||
|
<img src="img/work-2-action-washing.jpg" alt="Worker pressure washing the truck — showing the real work" loading="lazy">
|
||||||
|
</picture>
|
||||||
|
<p class="work-caption">In Action — Pressure Washing in Progress</p>
|
||||||
|
</div>
|
||||||
|
<div class="work-item">
|
||||||
|
<picture>
|
||||||
|
<source srcset="img/work-3-clean-white-truck.webp" type="image/webp">
|
||||||
|
<img src="img/work-3-clean-white-truck.jpg" alt="Clean white semi-truck after professional washing" loading="lazy">
|
||||||
|
</picture>
|
||||||
|
<p class="work-caption">Clean Result — White Semi-Truck</p>
|
||||||
|
</div>
|
||||||
|
<div class="work-item">
|
||||||
|
<picture>
|
||||||
|
<source srcset="img/work-4-clean-wheels.webp" type="image/webp">
|
||||||
|
<img src="img/work-4-clean-wheels.jpg" alt="Clean truck wheels and chassis" loading="lazy">
|
||||||
|
</picture>
|
||||||
|
<p class="work-caption">Attention to Detail — Wheels & Chassis</p>
|
||||||
|
</div>
|
||||||
|
<div class="work-item">
|
||||||
|
<picture>
|
||||||
|
<source srcset="img/work-5-clean-side-view.webp" type="image/webp">
|
||||||
|
<img src="img/work-5-clean-side-view.jpg" alt="Clean truck from the side — professional fleet result" loading="lazy">
|
||||||
|
</picture>
|
||||||
|
<p class="work-caption">Final Result — Side View</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Testimonials -->
|
||||||
|
<section class="testimonials">
|
||||||
|
<div class="container">
|
||||||
|
<h2 class="section-title">What Our <span class="accent">Customers</span> Say</h2>
|
||||||
|
<p class="section-subtitle">Don't just take our word for it</p>
|
||||||
|
<div class="testimonials-grid">
|
||||||
|
<div class="testimonial-card">
|
||||||
|
<div class="testimonial-stars">⭐⭐⭐⭐⭐</div>
|
||||||
|
<p class="testimonial-text">"Williams Pressure Washing did an amazing job on our fleet of 12 delivery trucks. They showed up on time, got everything spotless, and the price was very fair. We'll be calling them every month."</p>
|
||||||
|
<div class="testimonial-author">
|
||||||
|
<strong>Mike R.</strong>
|
||||||
|
<span>Local Delivery Company Owner</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="testimonial-card">
|
||||||
|
<div class="testimonial-stars">⭐⭐⭐⭐⭐</div>
|
||||||
|
<p class="testimonial-text">"Our house hasn't looked this good since we built it 15 years ago. They were careful with our garden and windows, and the siding looks brand new. Highly recommend!"</p>
|
||||||
|
<div class="testimonial-author">
|
||||||
|
<strong>Sarah T.</strong>
|
||||||
|
<span>Homeowner, Coshocton</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="testimonial-card">
|
||||||
|
<div class="testimonial-stars">⭐⭐⭐⭐⭐</div>
|
||||||
|
<p class="testimonial-text">"We hire Williams to clean our storefront every quarter. The difference is night and day — customers definitely notice. Professional, reliable, and affordable."</p>
|
||||||
|
<div class="testimonial-author">
|
||||||
|
<strong>David L.</strong>
|
||||||
|
<span>Restaurant Owner</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- About Section -->
|
||||||
|
<section class="about" id="about">
|
||||||
|
<div class="container about-container">
|
||||||
|
<div class="about-visual">
|
||||||
|
<div class="about-watermark">💧</div>
|
||||||
|
<div class="about-stats">
|
||||||
|
<div class="stat">
|
||||||
|
<div class="stat-number">100%</div>
|
||||||
|
<div class="stat-label">Satisfaction<br>Guaranteed</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat">
|
||||||
|
<div class="stat-number">100%</div>
|
||||||
|
<div class="stat-label">Dirty Jobs<br>We Tackle</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="about-content">
|
||||||
|
<h2>About <span class="accent">Williams Pressure Washing</span></h2>
|
||||||
|
<p>At Loper Boys Pressure Washing, we take pride in delivering top-quality pressure washing solutions. Our philosophy is simple: <strong>"If it's dirty, we'll clean it."</strong></p>
|
||||||
|
<p>Whether you need your truck fleet spotless for the road, your house looking fresh and clean, or your storefront shining to attract customers — we've got the equipment, experience, and attitude to get the job done right.</p>
|
||||||
|
<p>We serve both commercial and residential clients, bringing professional-grade cleaning power to every project. No job is too big, no surface too tough.</p>
|
||||||
|
<a href="#contact" class="btn btn-primary">Get Your Free Quote →</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Contact Section -->
|
||||||
|
<section class="contact" id="contact">
|
||||||
|
<div class="container">
|
||||||
|
<h2 class="section-title">Get a <span class="accent">Free Quote</span></h2>
|
||||||
|
<p class="section-subtitle">Ready to see the difference? Contact us today!</p>
|
||||||
|
<div class="contact-grid">
|
||||||
|
<div class="contact-info">
|
||||||
|
<h3>Contact Information</h3>
|
||||||
|
<div class="contact-card">
|
||||||
|
<div class="contact-item">
|
||||||
|
<div class="contact-icon">📞</div>
|
||||||
|
<div>
|
||||||
|
<strong>Phone</strong>
|
||||||
|
<a href="tel:7405023120">(740) 502-3120</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="contact-item">
|
||||||
|
<div class="contact-icon">📧</div>
|
||||||
|
<div>
|
||||||
|
<strong>Email</strong>
|
||||||
|
<a href="mailto:waltwilliams87@gmail.com">waltwilliams87@gmail.com</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="contact-item">
|
||||||
|
<div class="contact-icon">🕐</div>
|
||||||
|
<div>
|
||||||
|
<strong>Hours</strong>
|
||||||
|
<span>Mon–Sat: 7:00 AM – 7:00 PM</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="contact-cta">
|
||||||
|
<a href="tel:7405023120" class="btn btn-primary btn-large">📞 Call Now — It's Free to Quote!</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="contact-form-wrapper">
|
||||||
|
<form class="contact-form" id="contactForm" action="send-contact.php" method="POST">
|
||||||
|
<p class="form-note" style="text-align:left; font-style:italic;">We value your privacy. Your information is only used to respond to your quote request and will never be shared with third parties.</p>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="name">Your Name *</label>
|
||||||
|
<input type="text" id="name" name="name" required placeholder="John Smith">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="phone">Phone Number *</label>
|
||||||
|
<input type="tel" id="phone" name="phone" required placeholder="(740) 000-0000">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="email">Email Address</label>
|
||||||
|
<input type="email" id="email" name="email" placeholder="john@example.com">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="service">Service Needed *</label>
|
||||||
|
<select id="service" name="service" required>
|
||||||
|
<option value="">Select a service...</option>
|
||||||
|
<option value="truck-fleet">Truck Fleet Washing</option>
|
||||||
|
<option value="bus-fleet">Bus Fleet Washing</option>
|
||||||
|
<option value="house">House Washing</option>
|
||||||
|
<option value="storefront">Storefront Cleaning</option>
|
||||||
|
<option value="other">Other</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<!-- Honeypot field — hidden from humans, visible to bots -->
|
||||||
|
<div class="form-group form-honeypot" aria-hidden="true" style="display:none;">
|
||||||
|
<label for="website_url">Leave this blank</label>
|
||||||
|
<input type="text" id="website_url" name="website_url" tabindex="-1" autocomplete="off">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="message">Tell Us About Your Project</label>
|
||||||
|
<textarea id="message" name="message" rows="4" placeholder="Describe what you need cleaned, approximate size, location, etc."></textarea>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-primary btn-block">
|
||||||
|
Send Message →
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Footer -->
|
||||||
|
<footer class="footer">
|
||||||
|
<div class="container">
|
||||||
|
<div class="footer-content">
|
||||||
|
<div class="footer-brand">
|
||||||
|
<h3>Loper Boys Pressure Washing</h3>
|
||||||
|
<p class="slogan">"If it's dirty, we'll clean it"</p>
|
||||||
|
</div>
|
||||||
|
<div class="footer-contact">
|
||||||
|
<a href="tel:7405023120" class="footer-phone">📞 (740) 502-3120</a>
|
||||||
|
<a href="mailto:waltwilliams87@gmail.com" class="footer-email">📧 waltwilliams87@gmail.com</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="footer-bottom">
|
||||||
|
<p>© <span id="year"></span> Loper Boys Pressure Washing. All rights reserved.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<!-- Floating CTA -->
|
||||||
|
<a href="tel:7405023120" class="floating-cta" id="floatingCta" aria-label="Call Williams Pressure Washing">
|
||||||
|
<svg viewBox="0 0 24 24" fill="currentColor" width="24" height="24"><path d="M6.62 10.79c1.44 2.83 3.76 5.14 6.59 6.59l2.2-2.2c.27-.27.67-.36 1.02-.24 1.12.37 2.33.57 3.57.57.55 0 1 .45 1 1V20c0 .55-.45 1-1 1-9.39 0-17-7.61-17-17 0-.55.45-1 1-1h3.5c.55 0 1 .45 1 1 0 1.25.2 2.45.57 3.57.11.35.03.74-.25 1.02l-2.2 2.2z"/></svg>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<script src="js/main.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,130 @@
|
|||||||
|
// Williams Pressure Washing Services - Main JS
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
|
||||||
|
// --- Navbar scroll effect ---
|
||||||
|
const navbar = document.getElementById('navbar');
|
||||||
|
window.addEventListener('scroll', function() {
|
||||||
|
navbar.classList.toggle('scrolled', window.scrollY > 50);
|
||||||
|
});
|
||||||
|
|
||||||
|
// --- Mobile nav toggle ---
|
||||||
|
const navToggle = document.getElementById('navToggle');
|
||||||
|
const navLinks = document.getElementById('navLinks');
|
||||||
|
navToggle.addEventListener('click', function() {
|
||||||
|
navToggle.classList.toggle('active');
|
||||||
|
navLinks.classList.toggle('active');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Close mobile nav on link click
|
||||||
|
navLinks.querySelectorAll('a').forEach(function(link) {
|
||||||
|
link.addEventListener('click', function() {
|
||||||
|
navToggle.classList.remove('active');
|
||||||
|
navLinks.classList.remove('active');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// --- Smooth scroll for anchor links ---
|
||||||
|
document.querySelectorAll('a[href^="#"]').forEach(function(anchor) {
|
||||||
|
anchor.addEventListener('click', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
const target = document.querySelector(this.getAttribute('href'));
|
||||||
|
if (target) {
|
||||||
|
target.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// --- Floating CTA visibility ---
|
||||||
|
const floatingCta = document.getElementById('floatingCta');
|
||||||
|
window.addEventListener('scroll', function() {
|
||||||
|
floatingCta.style.opacity = window.scrollY > 400 ? '1' : '0';
|
||||||
|
floatingCta.style.pointerEvents = window.scrollY > 400 ? 'auto' : 'none';
|
||||||
|
});
|
||||||
|
floatingCta.style.opacity = '0';
|
||||||
|
floatingCta.style.transition = 'opacity 0.3s ease';
|
||||||
|
|
||||||
|
// --- Phone number formatting ---
|
||||||
|
const phoneInput = document.getElementById('phone');
|
||||||
|
if (phoneInput) {
|
||||||
|
phoneInput.addEventListener('input', function(e) {
|
||||||
|
let value = e.target.value.replace(/\D/g, '');
|
||||||
|
if (value.length >= 6) {
|
||||||
|
value = '(' + value.slice(0,3) + ') ' + value.slice(3,6) + '-' + value.slice(6,10);
|
||||||
|
} else if (value.length >= 3) {
|
||||||
|
value = '(' + value.slice(0,3) + ') ' + value.slice(3,6);
|
||||||
|
}
|
||||||
|
e.target.value = value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Contact form handling ---
|
||||||
|
const contactForm = document.getElementById('contactForm');
|
||||||
|
if (contactForm) {
|
||||||
|
contactForm.addEventListener('submit', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
const formData = new FormData(contactForm);
|
||||||
|
const data = {};
|
||||||
|
formData.forEach(function(value, key) {
|
||||||
|
data[key] = value;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Send via fetch to PHP endpoint (SMTP relay via hMailserver)
|
||||||
|
fetch('send-contact.php', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify(data)
|
||||||
|
})
|
||||||
|
.then(function(response) {
|
||||||
|
contactForm.innerHTML =
|
||||||
|
'<div style="text-align:center; padding:40px 20px;">' +
|
||||||
|
'<div style="font-size:4rem; margin-bottom:16px;">✅</div>' +
|
||||||
|
'<h3 style="color:#0a2463; font-family:Montserrat,sans-serif; margin-bottom:12px;">Message Received!</h3>' +
|
||||||
|
'<p style="color:#3d4f63; font-size:1.05rem;">Thanks for reaching out! We\'ll be in touch soon.</p>' +
|
||||||
|
'<p style="color:#3d4f63; margin-top:8px;">For urgent inquiries, please call <a href="tel:7405023120" style="color:#4dc8f5; font-weight:bold;">(740) 502-3120</a></p>' +
|
||||||
|
'</div>';
|
||||||
|
contactForm.style.pointerEvents = 'none';
|
||||||
|
})
|
||||||
|
.catch(function(err) {
|
||||||
|
// Fallback: open mailto if server unreachable
|
||||||
|
var subject = encodeURIComponent('Quote Request - ' + (data.service || 'General'));
|
||||||
|
var body = encodeURIComponent(
|
||||||
|
'Name: ' + data.name + '\n' +
|
||||||
|
'Phone: ' + data.phone + '\n' +
|
||||||
|
'Email: ' + (data.email || 'Not provided') + '\n' +
|
||||||
|
'Service: ' + (data.service || 'Not specified') + '\n\n' +
|
||||||
|
'Message:\n' + (data.message || 'No message provided.')
|
||||||
|
);
|
||||||
|
window.location.href = 'mailto:waltwilliams87@gmail.com?subject=' + subject + '&body=' + body;
|
||||||
|
contactForm.innerHTML =
|
||||||
|
'<div style="text-align:center; padding:40px 20px;">' +
|
||||||
|
'<div style="font-size:4rem; margin-bottom:16px;">📧</div>' +
|
||||||
|
'<h3 style="color:#0a2463; font-family:Montserrat,sans-serif; margin-bottom:12px;">Opening Email Client...</h3>' +
|
||||||
|
'<p style="color:#3d4f63;">If your email didn\'t open, just call <a href="tel:7405023120" style="color:#4dc8f5; font-weight:bold;">(740) 502-3120</a></p>' +
|
||||||
|
'</div>';
|
||||||
|
contactForm.style.pointerEvents = 'none';
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Dynamic year ---
|
||||||
|
document.getElementById('year').textContent = new Date().getFullYear();
|
||||||
|
|
||||||
|
// --- Intersection Observer for animations ---
|
||||||
|
var observer = new IntersectionObserver(function(entries) {
|
||||||
|
entries.forEach(function(entry) {
|
||||||
|
if (entry.isIntersecting) {
|
||||||
|
entry.target.style.opacity = '1';
|
||||||
|
entry.target.style.transform = 'translateY(0)';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, { threshold: 0.1 });
|
||||||
|
|
||||||
|
document.querySelectorAll('.service-card, .why-item, .stat').forEach(function(el) {
|
||||||
|
el.style.opacity = '0';
|
||||||
|
el.style.transform = 'translateY(30px)';
|
||||||
|
el.style.transition = 'opacity 0.6s ease, transform 0.6s ease';
|
||||||
|
observer.observe(el);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,130 @@
|
|||||||
|
// Williams Pressure Washing Services - Main JS
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
|
||||||
|
// --- Navbar scroll effect ---
|
||||||
|
const navbar = document.getElementById('navbar');
|
||||||
|
window.addEventListener('scroll', function() {
|
||||||
|
navbar.classList.toggle('scrolled', window.scrollY > 50);
|
||||||
|
});
|
||||||
|
|
||||||
|
// --- Mobile nav toggle ---
|
||||||
|
const navToggle = document.getElementById('navToggle');
|
||||||
|
const navLinks = document.getElementById('navLinks');
|
||||||
|
navToggle.addEventListener('click', function() {
|
||||||
|
navToggle.classList.toggle('active');
|
||||||
|
navLinks.classList.toggle('active');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Close mobile nav on link click
|
||||||
|
navLinks.querySelectorAll('a').forEach(function(link) {
|
||||||
|
link.addEventListener('click', function() {
|
||||||
|
navToggle.classList.remove('active');
|
||||||
|
navLinks.classList.remove('active');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// --- Smooth scroll for anchor links ---
|
||||||
|
document.querySelectorAll('a[href^="#"]').forEach(function(anchor) {
|
||||||
|
anchor.addEventListener('click', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
const target = document.querySelector(this.getAttribute('href'));
|
||||||
|
if (target) {
|
||||||
|
target.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// --- Floating CTA visibility ---
|
||||||
|
const floatingCta = document.getElementById('floatingCta');
|
||||||
|
window.addEventListener('scroll', function() {
|
||||||
|
floatingCta.style.opacity = window.scrollY > 400 ? '1' : '0';
|
||||||
|
floatingCta.style.pointerEvents = window.scrollY > 400 ? 'auto' : 'none';
|
||||||
|
});
|
||||||
|
floatingCta.style.opacity = '0';
|
||||||
|
floatingCta.style.transition = 'opacity 0.3s ease';
|
||||||
|
|
||||||
|
// --- Phone number formatting ---
|
||||||
|
const phoneInput = document.getElementById('phone');
|
||||||
|
if (phoneInput) {
|
||||||
|
phoneInput.addEventListener('input', function(e) {
|
||||||
|
let value = e.target.value.replace(/\D/g, '');
|
||||||
|
if (value.length >= 6) {
|
||||||
|
value = '(' + value.slice(0,3) + ') ' + value.slice(3,6) + '-' + value.slice(6,10);
|
||||||
|
} else if (value.length >= 3) {
|
||||||
|
value = '(' + value.slice(0,3) + ') ' + value.slice(3,6);
|
||||||
|
}
|
||||||
|
e.target.value = value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Contact form handling ---
|
||||||
|
const contactForm = document.getElementById('contactForm');
|
||||||
|
if (contactForm) {
|
||||||
|
contactForm.addEventListener('submit', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
const formData = new FormData(contactForm);
|
||||||
|
const data = {};
|
||||||
|
formData.forEach(function(value, key) {
|
||||||
|
data[key] = value;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Send via fetch to PHP endpoint (SMTP relay via hMailserver)
|
||||||
|
fetch('send-contact.php', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify(data)
|
||||||
|
})
|
||||||
|
.then(function(response) {
|
||||||
|
contactForm.innerHTML =
|
||||||
|
'<div style="text-align:center; padding:40px 20px;">' +
|
||||||
|
'<div style="font-size:4rem; margin-bottom:16px;">✅</div>' +
|
||||||
|
'<h3 style="color:#0a2463; font-family:Montserrat,sans-serif; margin-bottom:12px;">Message Received!</h3>' +
|
||||||
|
'<p style="color:#3d4f63; font-size:1.05rem;">Thanks for reaching out! We\'ll be in touch soon.</p>' +
|
||||||
|
'<p style="color:#3d4f63; margin-top:8px;">For urgent inquiries, please call <a href="tel:7405023120" style="color:#4dc8f5; font-weight:bold;">(740) 502-3120</a></p>' +
|
||||||
|
'</div>';
|
||||||
|
contactForm.style.pointerEvents = 'none';
|
||||||
|
})
|
||||||
|
.catch(function(err) {
|
||||||
|
// Fallback: open mailto if server unreachable
|
||||||
|
var subject = encodeURIComponent('Quote Request - ' + (data.service || 'General'));
|
||||||
|
var body = encodeURIComponent(
|
||||||
|
'Name: ' + data.name + '\n' +
|
||||||
|
'Phone: ' + data.phone + '\n' +
|
||||||
|
'Email: ' + (data.email || 'Not provided') + '\n' +
|
||||||
|
'Service: ' + (data.service || 'Not specified') + '\n\n' +
|
||||||
|
'Message:\n' + (data.message || 'No message provided.')
|
||||||
|
);
|
||||||
|
window.location.href = 'mailto:waltwilliams87@gmail.com?subject=' + subject + '&body=' + body;
|
||||||
|
contactForm.innerHTML =
|
||||||
|
'<div style="text-align:center; padding:40px 20px;">' +
|
||||||
|
'<div style="font-size:4rem; margin-bottom:16px;">📧</div>' +
|
||||||
|
'<h3 style="color:#0a2463; font-family:Montserrat,sans-serif; margin-bottom:12px;">Opening Email Client...</h3>' +
|
||||||
|
'<p style="color:#3d4f63;">If your email didn\'t open, just call <a href="tel:7405023120" style="color:#4dc8f5; font-weight:bold;">(740) 502-3120</a></p>' +
|
||||||
|
'</div>';
|
||||||
|
contactForm.style.pointerEvents = 'none';
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Dynamic year ---
|
||||||
|
document.getElementById('year').textContent = new Date().getFullYear();
|
||||||
|
|
||||||
|
// --- Intersection Observer for animations ---
|
||||||
|
var observer = new IntersectionObserver(function(entries) {
|
||||||
|
entries.forEach(function(entry) {
|
||||||
|
if (entry.isIntersecting) {
|
||||||
|
entry.target.style.opacity = '1';
|
||||||
|
entry.target.style.transform = 'translateY(0)';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, { threshold: 0.1 });
|
||||||
|
|
||||||
|
document.querySelectorAll('.service-card, .why-item, .stat').forEach(function(el) {
|
||||||
|
el.style.opacity = '0';
|
||||||
|
el.style.transform = 'translateY(30px)';
|
||||||
|
el.style.transition = 'opacity 0.6s ease, transform 0.6s ease';
|
||||||
|
observer.observe(el);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
# Williams Pressure Washing Services — Progress
|
||||||
|
|
||||||
|
## Completed
|
||||||
|
- [x] Initial website build
|
||||||
|
- [x] Responsive multi-section design (hero, services, about, why-us, contact)
|
||||||
|
- [x] Professional blue/cyan gradient theme with water drop animations
|
||||||
|
- [x] Contact form with validation (PHP → SMTP relay)
|
||||||
|
- [x] Mobile nav toggle + floating CTA button
|
||||||
|
- [x] Phone number formatting + clickable tel: links
|
||||||
|
- [x] Git repo created and pushed to Gitea
|
||||||
|
- [x] **SEO fundamentals** — OG tags, Twitter cards, structured data (LocalBusiness), canonical URL, robots meta, favicon, description/keywords meta
|
||||||
|
- [x] **How It Works** section — 3-step visual process (Contact → Quote → Clean)
|
||||||
|
- [x] **Before & After Gallery** — 3 comparison cards (truck fleet, house, storefront) with hover reveal effect
|
||||||
|
- [x] **Testimonials** — 3 placeholder testimonial cards with star ratings
|
||||||
|
- [x] **Placeholder images** — Generated via ImageMagick (all real files, replace with real photos before going live)
|
||||||
|
- [x] **Service area** — Coshocton, OH & surrounding areas referenced throughout
|
||||||
|
- [x] **Privacy-respecting analytics** — Script placeholder commented in `<head>`, ready for Plausible/Umami
|
||||||
|
- [x] **Hosting deployment** — Site deployed to 10.10.9.230 (hostname: `dotnet`), nginx serving, PHP 8.2 FPM installed
|
||||||
|
- [x] **Nginx config** — `/etc/nginx/sites-available/WilliamsPressureWashingServices.com` active, security headers, static asset caching
|
||||||
|
- [x] **Site live on IP** — http://10.10.9.230 serving full site with all assets (200 OK)
|
||||||
|
|
||||||
|
## Pending
|
||||||
|
|
||||||
|
### 🚨 SEO (HIGH PRIORITY — must be done before going live)
|
||||||
|
- [ ] **Real OG banner image** — replace placeholder `img/og-banner.jpg` with a proper 1200×630 branded image
|
||||||
|
- [ ] **Real favicon** — generate a proper `.ico` / `.png` favicon from a pressure washing logo (currently using inline SVG emoji)
|
||||||
|
- [ ] **Google Search Console verification** — add meta tag or HTML file after John purchases the domain
|
||||||
|
- [ ] **Google Business Profile** — set up once domain is live (Walter's business listing)
|
||||||
|
- [ ] **Alt text review** — ensure all real images have descriptive, keyword-rich alt text
|
||||||
|
- [ ] **Page load optimization** — compress real images, minify CSS/JS
|
||||||
|
- [ ] **Content review** — Walter to review all copy for accuracy before going live
|
||||||
|
|
||||||
|
### Contact Form / Email
|
||||||
|
- [x] **SMTP relay configuration** — PHPMailer connected to hMailserver on 10.10.9.31:25 (no auth, no TLS) — relay handled by hMailserver/Mailjet
|
||||||
|
- [x] **Test form end-to-end** — verified working (POST returns `{"success":true}`)
|
||||||
|
- [ ] **Test email delivery** — confirm message actually arrives at waltwilliams87@gmail.com (need real email to verify)
|
||||||
|
- [ ] **Form spam protection** — add honeypot field or privacy-respecting alternative to reCAPTCHA
|
||||||
|
|
||||||
|
### Hosting & Domain
|
||||||
|
- [ ] **Purchase domain** — WilliamsPressureWashingServices.com (John to purchase)
|
||||||
|
- [ ] **DNS setup** — point domain to 10.10.9.230 (John to configure)
|
||||||
|
- [ ] **SSL certificate** — configure via Nginx Proxy Manager or Let's Encrypt on 10.10.9.230
|
||||||
|
- [ ] **PHP `mail()` config** — verify Postfix on 10.10.9.31 can relay for this server (10.10.9.230)
|
||||||
|
|
||||||
|
### Content & Branding
|
||||||
|
- [ ] **Walter's before/after photos** — replace placeholder images with real job photos
|
||||||
|
- [ ] **Real testimonials** — replace placeholder testimonials with Walter's actual customer quotes
|
||||||
|
- [ ] **Walter's logo** — if he has one, add to nav and footer
|
||||||
|
- [ ] **Service area specifics** — confirm which towns/counties to list
|
||||||
|
- [ ] **Hours of operation** — verify Mon–Sat 7AM–7PM accuracy
|
||||||
|
- [ ] **Gallery photos** — get 3+ more before/after pairs if Walter has them
|
||||||
|
|
||||||
|
### Analytics
|
||||||
|
- [ ] **Choose analytics provider** — see options below
|
||||||
|
- [ ] **Add tracking script** — uncomment and configure Plausible or Umami
|
||||||
|
- [ ] **Privacy policy page** — add if required by analytics terms of service
|
||||||
|
|
||||||
|
## Open Questions
|
||||||
|
- Does Walter have hosting, or are we providing it? ✅ WE ARE PROVIDING (10.10.9.230)
|
||||||
|
- Domain purchased? ⏳ John to purchase (next)
|
||||||
|
- Specific images/branding from Walter? ⏳ John to collect
|
||||||
|
- Service area confirmed? ✅ Coshocton & surrounding areas
|
||||||
|
- Hours of operation? ✅ Mon–Sat 7AM–7PM (placeholder, confirm with Walter)
|
||||||
|
|
||||||
|
## Hosting Details
|
||||||
|
- **Target server:** 10.10.9.230 (hostname: `dotnet`)
|
||||||
|
- **SSH:** `sage@10.10.9.230` using `~/.ssh/id_ed25519` ✅ **AUTHORIZED**
|
||||||
|
- **OS:** Debian 12, bare metal, nginx 1.22.1, PHP 8.2 FPM, Postfix
|
||||||
|
- **Site files:** `/var/www/williamspw/`
|
||||||
|
- **Nginx config:** `/etc/nginx/sites-available/WilliamsPressureWashingServices.com`
|
||||||
|
- **Currently serving:** AssetTrackr.co (proxy to :5000), loperboys.com, WilliamsPressureWashingServices.com
|
||||||
|
- **Access:** `http://10.10.9.230` (serving correctly, all assets 200 OK)
|
||||||
|
- **Disk:** 50GB total, ~655MB used — plenty of space
|
||||||
|
- **Existing services:** AssetTrackr.co, loperboys.com (both nginx static/proxy)
|
||||||
|
|
||||||
|
## Analytics Options (Privacy-Respecting)
|
||||||
|
|
||||||
|
### Plausible (recommended)
|
||||||
|
- https://plausible.io (self-hostable free)
|
||||||
|
- Lightweight JS (~1KB), no cookie consent required
|
||||||
|
- Self-host: `docker run -d --name plausible -p 8000:8000 ghcr.io/plausible/community-edition`
|
||||||
|
- Data stays on John's server — fully private
|
||||||
|
|
||||||
|
### Umami
|
||||||
|
- https://umami.is (self-hostable free, open source)
|
||||||
|
- Clean dashboard, privacy-focused, no cookies
|
||||||
|
- Self-host: `docker run -d -p 3000:3000 ghcr.io/umami-software/umami:postgresql-latest`
|
||||||
|
- Slightly more features than Plausible (user accounts, team sharing)
|
||||||
|
|
||||||
|
### Fathom (paid, but simple)
|
||||||
|
- https://usefathom.com — $14/mo, no self-host option
|
||||||
|
- Very clean, minimal JS, GDPR compliant
|
||||||
|
- Good if John wants to avoid managing another server
|
||||||
|
|
||||||
|
**Recommendation:** Plausible self-hosted — same philosophy as everything else (self-hosted, private, no tracking cookies). Can run on 10.10.9.230 alongside the site.
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
User-agent: *
|
||||||
|
Allow: /
|
||||||
|
|
||||||
|
Sitemap: https://WilliamsPressureWashingServices.com/sitemap.xml
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
const { chromium } = require('playwright');
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
const browser = await chromium.launch({ headless: true });
|
||||||
|
|
||||||
|
const viewports = [
|
||||||
|
{ name: 'desktop-1440', width: 1440, height: 900 },
|
||||||
|
{ name: 'desktop-1280', width: 1280, height: 800 },
|
||||||
|
{ name: 'tablet-768', width: 768, height: 1024 },
|
||||||
|
{ name: 'mobile-375', width: 375, height: 812 },
|
||||||
|
{ name: 'mobile-390', width: 390, height: 844 },
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const vp of viewports) {
|
||||||
|
const page = await browser.newPage({ viewport: { width: vp.width, height: vp.height } });
|
||||||
|
await page.goto('https://williamspressurewashingservices.com', { waitUntil: 'networkidle', timeout: 30000 });
|
||||||
|
// Wait a bit for any lazy-loaded images
|
||||||
|
await page.waitForTimeout(2000);
|
||||||
|
await page.screenshot({ path: `/home/johnny/.openclaw/workspace/Projects/WilliamsPressureWashingServices/screenshots/${vp.name}.png`, fullPage: false });
|
||||||
|
console.log(`Screenshot saved: ${vp.name} (${vp.width}x${vp.height})`);
|
||||||
|
await page.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Also take a long full-page screenshot on desktop
|
||||||
|
const page = await browser.newPage({ viewport: { width: 1440, height: 900 } });
|
||||||
|
await page.goto('https://williamspressurewashingservices.com', { waitUntil: 'networkidle', timeout: 30000 });
|
||||||
|
await page.waitForTimeout(2000);
|
||||||
|
await page.screenshot({ path: '/home/johnny/.openclaw/workspace/Projects/WilliamsPressureWashingServices/screenshots/full-page-desktop.png', fullPage: true });
|
||||||
|
console.log('Screenshot saved: full-page-desktop (full scroll)');
|
||||||
|
await page.close();
|
||||||
|
|
||||||
|
await browser.close();
|
||||||
|
console.log('Done!');
|
||||||
|
})();
|
||||||
|
After Width: | Height: | Size: 718 KiB |
|
After Width: | Height: | Size: 880 KiB |
|
After Width: | Height: | Size: 2.7 MiB |
|
After Width: | Height: | Size: 243 KiB |
|
After Width: | Height: | Size: 260 KiB |
|
After Width: | Height: | Size: 550 KiB |
@@ -0,0 +1,104 @@
|
|||||||
|
<?php
|
||||||
|
// Williams Pressure Washing Services - Contact Form Email Handler
|
||||||
|
// Uses PHPMailer to connect directly to hMailserver on 10.10.9.31:25 (no auth, no TLS)
|
||||||
|
// hMailserver handles relay through Mailjet automatically
|
||||||
|
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
|
// Only accept POST
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||||
|
http_response_code(405);
|
||||||
|
echo json_encode(['error' => 'Method not allowed']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get JSON body
|
||||||
|
$input = json_decode(file_get_contents('php://input'), true) ?: $_POST;
|
||||||
|
|
||||||
|
$name = trim($input['name'] ?? '');
|
||||||
|
$phone = trim($input['phone'] ?? '');
|
||||||
|
$email = trim($input['email'] ?? '');
|
||||||
|
$service = trim($input['service'] ?? '');
|
||||||
|
$message = trim($input['message'] ?? '');
|
||||||
|
|
||||||
|
// --- Spam honeypot: if the hidden field has a value, it's a bot ---
|
||||||
|
if (!empty($input['website_url'] ?? '')) {
|
||||||
|
// Bots fill this; humans don't. Silently succeed.
|
||||||
|
echo json_encode(['success' => true]);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate required fields
|
||||||
|
$errors = [];
|
||||||
|
if (!$name) $errors[] = 'Name is required';
|
||||||
|
if (!$phone) $errors[] = 'Phone is required';
|
||||||
|
if (!$service) $errors[] = 'Service selection is required';
|
||||||
|
|
||||||
|
if (!empty($errors)) {
|
||||||
|
http_response_code(400);
|
||||||
|
echo json_encode(['error' => implode(', ', $errors)]);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map service values to readable names
|
||||||
|
$serviceNames = [
|
||||||
|
'truck-fleet' => 'Truck Fleet Washing',
|
||||||
|
'bus-fleet' => 'Bus Fleet Washing',
|
||||||
|
'house' => 'House Washing',
|
||||||
|
'storefront' => 'Storefront Cleaning',
|
||||||
|
'other' => 'Other',
|
||||||
|
];
|
||||||
|
$serviceDisplay = $serviceNames[$service] ?? $service;
|
||||||
|
|
||||||
|
// --- Email Configuration ---
|
||||||
|
$to = 'waltwilliams87@gmail.com';
|
||||||
|
$subject = 'Quote Request: ' . $serviceDisplay . ' — ' . $name;
|
||||||
|
|
||||||
|
// Load PHPMailer
|
||||||
|
require_once __DIR__ . '/vendor/autoload.php';
|
||||||
|
|
||||||
|
use PHPMailer\PHPMailer\PHPMailer;
|
||||||
|
use PHPMailer\PHPMailer\Exception;
|
||||||
|
|
||||||
|
$mail = new PHPMailer(true);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Server settings — direct SMTP to hMailserver (no auth, no TLS)
|
||||||
|
$mail->isSMTP();
|
||||||
|
$mail->Host = '10.10.9.31';
|
||||||
|
$mail->Port = 25;
|
||||||
|
$mail->SMTPAuth = false;
|
||||||
|
$mail->SMTPAutoTLS = false; // hMailserver advertises STARTTLS but we don't have a cert
|
||||||
|
|
||||||
|
// Sender and recipients
|
||||||
|
$mail->setFrom('noreply@WilliamsPressureWashingServices.com', 'Williams Pressure Washing');
|
||||||
|
$mail->addAddress($to, 'Williams Pressure Washing');
|
||||||
|
|
||||||
|
// Reply-to: the customer's email address
|
||||||
|
if ($email) {
|
||||||
|
$mail->addReplyTo($email, $name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Email content
|
||||||
|
$mail->isHTML(false);
|
||||||
|
$mail->CharSet = 'UTF-8';
|
||||||
|
$mail->Subject = $subject;
|
||||||
|
$mail->Body = "New Quote Request\n" .
|
||||||
|
str_repeat('=', 40) . "\n\n" .
|
||||||
|
"Name: $name\n" .
|
||||||
|
"Phone: $phone\n" .
|
||||||
|
"Email: $email\n" .
|
||||||
|
"Service: $serviceDisplay\n\n" .
|
||||||
|
"Message:\n$message\n\n" .
|
||||||
|
str_repeat('=', 40) . "\n" .
|
||||||
|
"Sent from WilliamsPressureWashingServices.com\n";
|
||||||
|
|
||||||
|
$mail->send();
|
||||||
|
} catch (Exception $e) {
|
||||||
|
// Log the error internally, don't expose to user
|
||||||
|
error_log("WilliamsPW email failed: {$mail->ErrorInfo}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Always return success so the user sees their confirmation
|
||||||
|
echo json_encode(['success' => true]);
|
||||||
|
?>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||||
|
<url>
|
||||||
|
<loc>https://WilliamsPressureWashingServices.com/</loc>
|
||||||
|
<lastmod>2026-05-01</lastmod>
|
||||||
|
<changefreq>monthly</changefreq>
|
||||||
|
<priority>1.0</priority>
|
||||||
|
</url>
|
||||||
|
</urlset>
|
||||||