957 lines
51 KiB
TypeScript
957 lines
51 KiB
TypeScript
"use client";
|
||
|
||
import { useState, useEffect } from "react";
|
||
import Link from "next/link";
|
||
import axios from "axios";
|
||
import "./ornamental-fence.css";
|
||
|
||
export default function OrnamentalFenceClient() {
|
||
// FAQ state
|
||
const [openFaq, setOpenFaq] = useState<number | null>(null);
|
||
|
||
// Active section for jump navigation
|
||
const [activeSection, setActiveSection] = useState<string>("tokio");
|
||
|
||
// Form state
|
||
const [formData, setFormData] = useState({
|
||
companyName: "",
|
||
name: "",
|
||
phone: "",
|
||
email: "",
|
||
modelSize: "",
|
||
city: "",
|
||
footage: "",
|
||
});
|
||
const [formStatus, setFormStatus] = useState<"idle" | "submitting" | "success" | "error">("idle");
|
||
|
||
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement>) => {
|
||
setFormData({ ...formData, [e.target.name]: e.target.value });
|
||
};
|
||
|
||
const handleFormSubmit = async (e: React.FormEvent) => {
|
||
e.preventDefault();
|
||
setFormStatus("submitting");
|
||
|
||
const emailData = {
|
||
name: formData.name,
|
||
email: formData.email,
|
||
phone: formData.phone,
|
||
service: "Ornamental Fence & Gates Quote",
|
||
message: `
|
||
<b>Company Name:</b> ${formData.companyName || "N/A"}<br/>
|
||
<b>Model & Panel Size:</b> ${formData.modelSize || "Not Specified"}<br/>
|
||
<b>Job Site City:</b> ${formData.city || "Not Specified"}<br/>
|
||
<b>Linear Footage:</b> ${formData.footage || "Not Specified"}
|
||
`,
|
||
to: "info@vgfenceproducts.com",
|
||
senderName: "VG Ornamental Fence Page",
|
||
};
|
||
|
||
try {
|
||
await axios.post("https://mailserver.metatronnest.com/send", emailData, {
|
||
headers: { "Content-Type": "application/json" },
|
||
});
|
||
setFormStatus("success");
|
||
setFormData({
|
||
companyName: "",
|
||
name: "",
|
||
phone: "",
|
||
email: "",
|
||
modelSize: "",
|
||
city: "",
|
||
footage: "",
|
||
});
|
||
} catch (err) {
|
||
console.error("❌ Ornamental Fence Quote Submission Error:", err);
|
||
setFormStatus("error");
|
||
}
|
||
};
|
||
|
||
useEffect(() => {
|
||
// Scrollspy setup
|
||
const sections = ["tokio", "rio", "denver", "oslo", "posts-hardware", "compare"];
|
||
const sysObs = new IntersectionObserver(
|
||
(entries) => {
|
||
entries.forEach((entry) => {
|
||
if (entry.isIntersecting) {
|
||
setActiveSection(entry.target.id);
|
||
}
|
||
});
|
||
},
|
||
{ threshold: 0.3 }
|
||
);
|
||
|
||
sections.forEach((id) => {
|
||
const el = document.getElementById(id);
|
||
if (el) sysObs.observe(el);
|
||
});
|
||
|
||
// Reveal animations setup
|
||
const revealObs = new IntersectionObserver(
|
||
(entries) => {
|
||
entries.forEach((entry) => {
|
||
if (entry.isIntersecting) {
|
||
entry.target.classList.add("visible");
|
||
}
|
||
});
|
||
},
|
||
{ threshold: 0.08 }
|
||
);
|
||
|
||
const revealElements = document.querySelectorAll(".reveal");
|
||
revealElements.forEach((el) => revealObs.observe(el));
|
||
|
||
return () => {
|
||
sections.forEach((id) => {
|
||
const el = document.getElementById(id);
|
||
if (el) sysObs.unobserve(el);
|
||
});
|
||
revealElements.forEach((el) => revealObs.unobserve(el));
|
||
};
|
||
}, []);
|
||
|
||
const toggleFaq = (index: number) => {
|
||
setOpenFaq(openFaq === index ? null : index);
|
||
};
|
||
|
||
const scrollToSection = (id: string) => {
|
||
const el = document.getElementById(id);
|
||
if (el) {
|
||
el.scrollIntoView({ behavior: "smooth" });
|
||
}
|
||
};
|
||
|
||
return (
|
||
<div className="ornamental-fence-page">
|
||
{/* BREADCRUMB */}
|
||
{/* <nav className="breadcrumb" aria-label="Breadcrumb">
|
||
<Link href="/">Home</Link>
|
||
<span>›</span>
|
||
<Link href="/products">Products</Link>
|
||
<span>›</span>
|
||
<span>Ornamental Fence & Gates</span>
|
||
</nav> */}
|
||
|
||
{/* HERO */}
|
||
<section className="hero">
|
||
<div className="hero-grid-bg"></div>
|
||
<div className="hero-spears">
|
||
<div className="hero-spear"></div><div className="hero-spear"></div><div className="hero-spear"></div>
|
||
<div className="hero-spear"></div><div className="hero-spear"></div><div className="hero-spear"></div>
|
||
<div className="hero-spear"></div><div className="hero-spear"></div><div className="hero-spear"></div>
|
||
<div className="hero-spear"></div><div className="hero-spear"></div><div className="hero-spear"></div>
|
||
</div>
|
||
<div className="hero-accent"></div>
|
||
<div className="hero-inner">
|
||
<div className="hero-eyebrow">Ornamental fence & gates · KWC Ontario</div>
|
||
<h1>
|
||
Elegant. Durable.<br />
|
||
<em>Built to last.</em>
|
||
</h1>
|
||
<p className="hero-desc">
|
||
We carry <strong>4 ornamental fence models</strong> — Tokio, Rio, Denver, and Oslo — each available in rackable panels, matching gates, and all required posts and hardware. Residential quality with clean, timeless design.
|
||
Serving contractors and builders across <strong>250km from Kitchener–Waterloo.</strong>
|
||
</p>
|
||
<div className="hero-badges">
|
||
<span className="badge badge-fill">4 Residential Models</span>
|
||
<span className="badge">Rackable Panels</span>
|
||
<span className="badge">Matching Gates</span>
|
||
<span className="badge">Contractor Pricing</span>
|
||
<span className="badge">Commercial on Request</span>
|
||
</div>
|
||
<div className="hero-stats">
|
||
<div>
|
||
<div className="stat-val">4</div>
|
||
<div className="stat-label">Fence models</div>
|
||
</div>
|
||
<div>
|
||
<div className="stat-val">2</div>
|
||
<div className="stat-label">Panel heights</div>
|
||
</div>
|
||
<div>
|
||
<div className="stat-val">250km</div>
|
||
<div className="stat-label">Ontario delivery</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
{/* MODEL JUMP NAV */}
|
||
<div className="model-nav">
|
||
<a
|
||
className={`model-nav-item ${activeSection === "tokio" ? "active" : ""}`}
|
||
href="#tokio"
|
||
onClick={(e) => { e.preventDefault(); scrollToSection("tokio"); }}
|
||
>
|
||
Tokio
|
||
</a>
|
||
<a
|
||
className={`model-nav-item ${activeSection === "rio" ? "active" : ""}`}
|
||
href="#rio"
|
||
onClick={(e) => { e.preventDefault(); scrollToSection("rio"); }}
|
||
>
|
||
Rio
|
||
</a>
|
||
<a
|
||
className={`model-nav-item ${activeSection === "denver" ? "active" : ""}`}
|
||
href="#denver"
|
||
onClick={(e) => { e.preventDefault(); scrollToSection("denver"); }}
|
||
>
|
||
Denver
|
||
</a>
|
||
<a
|
||
className={`model-nav-item ${activeSection === "oslo" ? "active" : ""}`}
|
||
href="#oslo"
|
||
onClick={(e) => { e.preventDefault(); scrollToSection("oslo"); }}
|
||
>
|
||
Oslo
|
||
</a>
|
||
<a
|
||
className={`model-nav-item ${activeSection === "posts-hardware" ? "active" : ""}`}
|
||
href="#posts-hardware"
|
||
onClick={(e) => { e.preventDefault(); scrollToSection("posts-hardware"); }}
|
||
>
|
||
Posts & Hardware
|
||
</a>
|
||
<a
|
||
className={`model-nav-item ${activeSection === "compare" ? "active" : ""}`}
|
||
href="#compare"
|
||
onClick={(e) => { e.preventDefault(); scrollToSection("compare"); }}
|
||
>
|
||
Compare All
|
||
</a>
|
||
</div>
|
||
|
||
{/* INTRO */}
|
||
<section className="intro">
|
||
<div className="reveal">
|
||
<div className="section-eyebrow">About this product line</div>
|
||
<h2 className="sh">Ornamental fence supply<br /><span>for contractors.</span></h2>
|
||
</div>
|
||
<div className="intro-grid">
|
||
<div className="intro-text reveal">
|
||
<p>
|
||
<strong>VG Fence Products stocks a complete range of ornamental fence panels, gates, posts, and hardware</strong> for residential fence contractors across Waterloo Region and Ontario. Our four models — Tokio, Rio, Denver, and Oslo — cover a broad range of design preferences, from classic to contemporary.
|
||
</p>
|
||
<p>
|
||
All panels are rackable, available in 48" and 60" heights with a standard 92" width. Each model has a matching gate in two opening sizes, and all hardware, posts, brackets, and caps are in stock to complete the installation.
|
||
</p>
|
||
<p>
|
||
Commercial ornamental fence orders are also available on request — contact us for specifications and pricing on larger or custom commercial projects.
|
||
</p>
|
||
<ul className="check-list">
|
||
<li>4 models in stock — Tokio, Rio, Denver, Oslo</li>
|
||
<li>Rackable panels — 48" × 92" and 60" × 92"</li>
|
||
<li>Matching walk gates in two opening sizes</li>
|
||
<li>Complete post, cap, bracket, and hardware supply</li>
|
||
<li>Self-closing gate hardware available for pool compliance</li>
|
||
<li>Contractor pricing — bulk orders welcome</li>
|
||
<li>Commercial ornamental fence available on request</li>
|
||
</ul>
|
||
</div>
|
||
<div className="highlight-cards reveal">
|
||
<div className="hcard">
|
||
<div className="hcard-title">Rackable panels</div>
|
||
<div className="hcard-desc">All four models feature rackable panel design, allowing the fence to follow the natural slope of any property without stair-stepping. Available in 48" and 60" heights × 92" width.</div>
|
||
</div>
|
||
<div className="hcard">
|
||
<div className="hcard-title">Matching gates included</div>
|
||
<div className="hcard-desc">Every model has a matching single walk gate in 46" and 60" opening widths. Gate frames, hinges, latches, and self-closing hardware for pool installations all in stock.</div>
|
||
</div>
|
||
<div className="hcard">
|
||
<div className="hcard-title">Commercial orders available</div>
|
||
<div className="hcard-desc">While our standard line is residential, commercial ornamental fence orders are available on request. Contact us with your project specs and we'll provide pricing and lead time.</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
{/* MODEL 1 — TOKIO */}
|
||
<section className="model-section" id="tokio" style={{ background: "var(--white)" }}>
|
||
<div className="model-layout reveal">
|
||
<div>
|
||
<div className="model-accent-strip"></div>
|
||
<div className="model-label">Model 01</div>
|
||
<div className="model-name">Tokio</div>
|
||
<div className="model-tagline">Classic spear-top residential fence</div>
|
||
<p className="model-desc">The Tokio is a timeless ornamental fence design featuring a clean spear-top picket profile. A popular choice for front yards, property boundaries, and residential landscaping projects where classic curb appeal is the priority.</p>
|
||
|
||
<div className="specs-block">
|
||
<div className="specs-title">Panel sizes</div>
|
||
<div className="spec-row"><span className="spec-key">48" × 92" Rackable Panel</span><span className="spec-val orange">In stock</span></div>
|
||
<div className="spec-row"><span className="spec-key">60" × 92" Rackable Panel</span><span className="spec-val orange">In stock</span></div>
|
||
</div>
|
||
|
||
<div className="specs-block">
|
||
<div className="specs-title">Matching gates</div>
|
||
<div className="gate-cards">
|
||
<div className="gate-card">
|
||
<div className="gate-label">Walk gate</div>
|
||
<div className="gate-size">48"H × 46" OP</div>
|
||
<div className="gate-note">Standard walk gate</div>
|
||
</div>
|
||
<div className="gate-card">
|
||
<div className="gate-label">Walk gate</div>
|
||
<div className="gate-size">48"H × 60" OP</div>
|
||
<div className="gate-note">Wider opening</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div>
|
||
<div className="photo-area" style={{ minHeight: "340px" }}>
|
||
<svg className="photo-icon" width="48" height="48" viewBox="0 0 48 48" fill="none"><rect x="4" y="10" width="40" height="30" rx="4" stroke="#B0ADA6" strokeWidth="2" /><circle cx="17" cy="22" r="5" stroke="#B0ADA6" strokeWidth="2" /><path d="M4 34 L14 24 L22 32 L30 22 L44 34" stroke="#B0ADA6" strokeWidth="2" fill="none" /></svg>
|
||
<div className="photo-label">Tokio fence photo</div>
|
||
<div className="photo-sub">Upload product image here</div>
|
||
</div>
|
||
<div className="photo-row" style={{ marginTop: "12px" }}>
|
||
<div className="photo-area" style={{ minHeight: "160px" }}>
|
||
<svg className="photo-icon" width="32" height="32" viewBox="0 0 48 48" fill="none"><rect x="4" y="10" width="40" height="30" rx="4" stroke="#B0ADA6" strokeWidth="2" /><circle cx="17" cy="22" r="5" stroke="#B0ADA6" strokeWidth="2" /><path d="M4 34 L14 24 L22 32 L30 22 L44 34" stroke="#B0ADA6" strokeWidth="2" fill="none" /></svg>
|
||
<div className="photo-sub" style={{ fontSize: "11px" }}>Detail / close-up</div>
|
||
</div>
|
||
<div className="photo-area" style={{ minHeight: "160px" }}>
|
||
<svg className="photo-icon" width="32" height="32" viewBox="0 0 48 48" fill="none"><rect x="4" y="10" width="40" height="30" rx="4" stroke="#B0ADA6" strokeWidth="2" /><circle cx="17" cy="22" r="5" stroke="#B0ADA6" strokeWidth="2" /><path d="M4 34 L14 24 L22 32 L30 22 L44 34" stroke="#B0ADA6" strokeWidth="2" fill="none" /></svg>
|
||
<div className="photo-sub" style={{ fontSize: "11px" }}>Installed project</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
{/* MODEL 2 — RIO */}
|
||
<section className="model-section" id="rio" style={{ background: "var(--gray-100)" }}>
|
||
<div className="model-layout reverse reveal">
|
||
<div>
|
||
<div className="photo-area" style={{ minHeight: "340px" }}>
|
||
<svg className="photo-icon" width="48" height="48" viewBox="0 0 48 48" fill="none"><rect x="4" y="10" width="40" height="30" rx="4" stroke="#B0ADA6" strokeWidth="2" /><circle cx="17" cy="22" r="5" stroke="#B0ADA6" strokeWidth="2" /><path d="M4 34 L14 24 L22 32 L30 22 L44 34" stroke="#B0ADA6" strokeWidth="2" fill="none" /></svg>
|
||
<div className="photo-label">Rio fence photo</div>
|
||
<div className="photo-sub">Upload product image here</div>
|
||
</div>
|
||
<div className="photo-row" style={{ marginTop: "12px" }}>
|
||
<div className="photo-area" style={{ minHeight: "160px" }}>
|
||
<svg className="photo-icon" width="32" height="32" viewBox="0 0 48 48" fill="none"><rect x="4" y="10" width="40" height="30" rx="4" stroke="#B0ADA6" strokeWidth="2" /><circle cx="17" cy="22" r="5" stroke="#B0ADA6" strokeWidth="2" /><path d="M4 34 L14 24 L22 32 L30 22 L44 34" stroke="#B0ADA6" strokeWidth="2" fill="none" /></svg>
|
||
<div className="photo-sub" style={{ fontSize: "11px" }}>Detail / close-up</div>
|
||
</div>
|
||
<div className="photo-area" style={{ minHeight: "160px" }}>
|
||
<svg className="photo-icon" width="32" height="32" viewBox="0 0 48 48" fill="none"><rect x="4" y="10" width="40" height="30" rx="4" stroke="#B0ADA6" strokeWidth="2" /><circle cx="17" cy="22" r="5" stroke="#B0ADA6" strokeWidth="2" /><path d="M4 34 L14 24 L22 32 L30 22 L44 34" stroke="#B0ADA6" strokeWidth="2" fill="none" /></svg>
|
||
<div className="photo-sub" style={{ fontSize: "11px" }}>Installed project</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div>
|
||
<div className="model-accent-strip"></div>
|
||
<div className="model-label">Model 02</div>
|
||
<div className="model-name">Rio</div>
|
||
<div className="model-tagline">Contemporary flat-bar ornamental panel</div>
|
||
<p className="model-desc">The Rio offers a refined contemporary profile with a clean finish. Ideal for modern homes, landscaped properties, and residential projects where a sleek, low-maintenance fence complements current architectural styles.</p>
|
||
|
||
<div className="specs-block">
|
||
<div className="specs-title">Panel sizes</div>
|
||
<div className="spec-row"><span className="spec-key">48" × 92" Rackable Panel</span><span className="spec-val orange">In stock</span></div>
|
||
<div className="spec-row"><span className="spec-key">60" × 92" Rackable Panel</span><span className="spec-val orange">In stock</span></div>
|
||
</div>
|
||
|
||
<div className="specs-block">
|
||
<div className="specs-title">Matching gates</div>
|
||
<div className="gate-cards">
|
||
<div className="gate-card">
|
||
<div className="gate-label">Walk gate</div>
|
||
<div className="gate-size">48"H × 46" OP</div>
|
||
<div className="gate-note">Standard walk gate</div>
|
||
</div>
|
||
<div className="gate-card">
|
||
<div className="gate-label">Walk gate</div>
|
||
<div className="gate-size">48"H × 60" OP</div>
|
||
<div className="gate-note">Wider opening</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
{/* MODEL 3 — DENVER */}
|
||
<section className="model-section" id="denver" style={{ background: "var(--navy)" }}>
|
||
<div className="model-layout reveal">
|
||
<div>
|
||
<div className="model-accent-strip"></div>
|
||
<div className="model-label" style={{ color: "rgba(255,255,255,.5)" }}>Model 03 · Railing</div>
|
||
<div className="model-name white">Denver</div>
|
||
<div className="model-tagline">Railing-style ornamental panel</div>
|
||
<p className="model-desc white">The Denver is a railing-profile ornamental fence, offering a more open, elegant look suited for front yards, pool surrounds, and properties where visibility and design are equally important. Also serves beautifully as a deck or step railing system.</p>
|
||
|
||
<div className="specs-block">
|
||
<div className="specs-title white">Panel sizes</div>
|
||
<div className="spec-row white-row"><span className="spec-key white">48" × 92" Rackable Panel</span><span className="spec-val orange">In stock</span></div>
|
||
<div className="spec-row white-row"><span className="spec-key white">60" × 92" Rackable Panel</span><span className="spec-val orange">In stock</span></div>
|
||
</div>
|
||
|
||
<div className="specs-block">
|
||
<div className="specs-title white">Matching gates</div>
|
||
<div className="gate-cards">
|
||
<div className="gate-card dark">
|
||
<div className="gate-label">Walk gate</div>
|
||
<div className="gate-size white">48"H × 46" OP</div>
|
||
<div className="gate-note white">Standard walk gate</div>
|
||
</div>
|
||
<div className="gate-card dark">
|
||
<div className="gate-label">Walk gate</div>
|
||
<div className="gate-size white">48"H × 60" OP</div>
|
||
<div className="gate-note white">Wider opening</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div style={{ marginTop: "18px", background: "rgba(232,87,42,.12)", border: "1px solid rgba(232,87,42,.25)", borderRadius: "8px", padding: "14px 18px" }}>
|
||
<div style={{ fontFamily: "var(--fd)", fontSize: "12px", fontWeight: 700, letterSpacing: ".08em", textTransform: "uppercase", color: "var(--orange)", marginBottom: "4px" }}>Railing application</div>
|
||
<div style={{ fontSize: "13px", color: "rgba(255,255,255,.65)", lineHeight: 1.6 }}>The Denver railing profile is also suitable for deck railings, step railings, and balcony perimeters where an ornamental metal railing is required.</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div>
|
||
<div className="photo-area dark-placeholder" style={{ minHeight: "340px" }}>
|
||
<svg className="photo-icon" width="48" height="48" viewBox="0 0 48 48" fill="none"><rect x="4" y="10" width="40" height="30" rx="4" stroke="rgba(255,255,255,.35)" strokeWidth="2" /><circle cx="17" cy="22" r="5" stroke="rgba(255,255,255,.35)" strokeWidth="2" /><path d="M4 34 L14 24 L22 32 L30 22 L44 34" stroke="rgba(255,255,255,.35)" strokeWidth="2" fill="none" /></svg>
|
||
<div className="photo-label">Denver fence photo</div>
|
||
<div className="photo-sub">Upload product image here</div>
|
||
</div>
|
||
<div className="photo-row" style={{ marginTop: "12px" }}>
|
||
<div className="photo-area dark-placeholder" style={{ minHeight: "160px" }}>
|
||
<svg className="photo-icon" width="32" height="32" viewBox="0 0 48 48" fill="none"><rect x="4" y="10" width="40" height="30" rx="4" stroke="rgba(255,255,255,.35)" strokeWidth="2" /><circle cx="17" cy="22" r="5" stroke="rgba(255,255,255,.35)" strokeWidth="2" /><path d="M4 34 L14 24 L22 32 L30 22 L44 34" stroke="rgba(255,255,255,.35)" strokeWidth="2" fill="none" /></svg>
|
||
<div className="photo-sub" style={{ fontSize: "11px" }}>Detail / close-up</div>
|
||
</div>
|
||
<div className="photo-area dark-placeholder" style={{ minHeight: "160px" }}>
|
||
<svg className="photo-icon" width="32" height="32" viewBox="0 0 48 48" fill="none"><rect x="4" y="10" width="40" height="30" rx="4" stroke="rgba(255,255,255,.35)" strokeWidth="2" /><circle cx="17" cy="22" r="5" stroke="rgba(255,255,255,.35)" strokeWidth="2" /><path d="M4 34 L14 24 L22 32 L30 22 L44 34" stroke="rgba(255,255,255,.35)" strokeWidth="2" fill="none" /></svg>
|
||
<div className="photo-sub" style={{ fontSize: "11px" }}>Railing install</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
{/* MODEL 4 — OSLO */}
|
||
<section className="model-section" id="oslo" style={{ background: "var(--cream)" }}>
|
||
<div className="model-layout reverse reveal">
|
||
<div>
|
||
<div className="photo-area" style={{ minHeight: "340px", background: "var(--gray-200)" }}>
|
||
<svg className="photo-icon" width="48" height="48" viewBox="0 0 48 48" fill="none"><rect x="4" y="10" width="40" height="30" rx="4" stroke="#B0ADA6" strokeWidth="2" /><circle cx="17" cy="22" r="5" stroke="#B0ADA6" strokeWidth="2" /><path d="M4 34 L14 24 L22 32 L30 22 L44 34" stroke="#B0ADA6" strokeWidth="2" fill="none" /></svg>
|
||
<div className="photo-label">Oslo fence photo</div>
|
||
<div className="photo-sub">Upload product image here</div>
|
||
</div>
|
||
<div className="photo-row" style={{ marginTop: "12px" }}>
|
||
<div className="photo-area" style={{ minHeight: "160px", background: "var(--gray-200)" }}>
|
||
<svg className="photo-icon" width="32" height="32" viewBox="0 0 48 48" fill="none"><rect x="4" y="10" width="40" height="30" rx="4" stroke="#B0ADA6" strokeWidth="2" /><circle cx="17" cy="22" r="5" stroke="#B0ADA6" strokeWidth="2" /><path d="M4 34 L14 24 L22 32 L30 22 L44 34" stroke="#B0ADA6" strokeWidth="2" fill="none" /></svg>
|
||
<div className="photo-sub" style={{ fontSize: "11px" }}>Detail / close-up</div>
|
||
</div>
|
||
<div className="photo-area" style={{ minHeight: "160px", background: "var(--gray-200)" }}>
|
||
<svg className="photo-icon" width="32" height="32" viewBox="0 0 48 48" fill="none"><rect x="4" y="10" width="40" height="30" rx="4" stroke="#B0ADA6" strokeWidth="2" /><circle cx="17" cy="22" r="5" stroke="#B0ADA6" strokeWidth="2" /><path d="M4 34 L14 24 L22 32 L30 22 L44 34" stroke="#B0ADA6" strokeWidth="2" fill="none" /></svg>
|
||
<div className="photo-sub" style={{ fontSize: "11px" }}>Railing install</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div>
|
||
<div className="model-accent-strip"></div>
|
||
<div className="model-label">Model 04 · Railing</div>
|
||
<div className="model-name">Oslo</div>
|
||
<div className="model-tagline">Modern flat-bar railing panel</div>
|
||
<p className="model-desc">The Oslo features a modern flat-bar horizontal or vertical railing design with a Scandinavian-inspired clean profile. Perfect for contemporary properties, pool enclosures, and projects where a minimalist aesthetic is desired alongside strong functionality.</p>
|
||
|
||
<div className="specs-block">
|
||
<div className="specs-title">Panel sizes</div>
|
||
<div className="spec-row"><span className="spec-key">48" × 92" Rackable Panel</span><span className="spec-val orange">In stock</span></div>
|
||
<div className="spec-row"><span className="spec-key">60" × 92" Rackable Panel</span><span className="spec-val orange">In stock</span></div>
|
||
</div>
|
||
|
||
<div className="specs-block">
|
||
<div className="specs-title">Matching gates</div>
|
||
<div className="gate-cards">
|
||
<div className="gate-card">
|
||
<div className="gate-label">Walk gate</div>
|
||
<div className="gate-size">48"H × 46" OP</div>
|
||
<div className="gate-note">Standard walk gate</div>
|
||
</div>
|
||
<div className="gate-card">
|
||
<div className="gate-label">Walk gate</div>
|
||
<div className="gate-size">48"H × 60" OP</div>
|
||
<div className="gate-note">Wider opening</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
{/* POSTS & HARDWARE */}
|
||
<section className="hw-section" id="posts-hardware">
|
||
<div className="reveal">
|
||
<div className="section-eyebrow" style={{ color: "rgba(255,255,255,.5)" }}>Posts, brackets & hardware</div>
|
||
<h2 className="sh sh-white">Everything to complete<br /><span>the installation.</span></h2>
|
||
</div>
|
||
<div className="hw-grid reveal">
|
||
<div className="hw-card">
|
||
<div className="hw-icon">
|
||
<svg viewBox="0 0 20 20" fill="none"><rect x="8" y="1" width="4" height="18" rx="1.5" fill="white" /><rect x="5" y="1" width="3" height="4" rx="1" fill="white" opacity=".4" /><rect x="12" y="1" width="3" height="4" rx="1" fill="white" opacity=".4" /></svg>
|
||
</div>
|
||
<div className="hw-name">Posts — <span>2" Square</span></div>
|
||
<div className="hw-desc">Powder-coated 2" square posts to suit all four models. Available in heights from 6'6" to 10' to accommodate both standard and taller fence installations.</div>
|
||
<div className="hw-specs">
|
||
<div className="hw-spec">2" square section</div>
|
||
<div className="hw-spec">Heights: 6'6" to 10'</div>
|
||
<div className="hw-spec">Powder coated finish</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="hw-card">
|
||
<div className="hw-icon">
|
||
<svg viewBox="0 0 20 20" fill="none"><rect x="8" y="6" width="4" height="13" rx="1" fill="white" opacity=".8" /><polygon points="10,1 13,6 7,6" fill="white" /></svg>
|
||
</div>
|
||
<div className="hw-name">Post Caps — <span>3 Styles</span></div>
|
||
<div className="hw-desc">Finish every post top cleanly with your choice of three cap styles. Each seals the post top to prevent water ingress and adds a refined finishing detail.</div>
|
||
<div className="hw-specs">
|
||
<div className="hw-spec">Pyramid cap — classic pointed top</div>
|
||
<div className="hw-spec">Ball cap — decorative round top</div>
|
||
<div className="hw-spec">Finial cap — ornate spear top</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="hw-card">
|
||
<div className="hw-icon">
|
||
<svg viewBox="0 0 20 20" fill="none"><rect x="2" y="8" width="16" height="4" rx="1.5" fill="white" opacity=".8" /><rect x="6" y="4" width="3" height="12" rx="1" fill="white" opacity=".5" /><rect x="11" y="4" width="3" height="12" rx="1" fill="white" opacity=".5" /></svg>
|
||
</div>
|
||
<div className="hw-name">Rackable <span>Multi-Bracket</span></div>
|
||
<div className="hw-desc">The 2" × 1-1/4" rackable multi-functional bracket connects panels to posts and accommodates the rackable angle on sloped terrain. Works with all four models.</div>
|
||
<div className="hw-specs">
|
||
<div className="hw-spec">2" × 1-1/4" size</div>
|
||
<div className="hw-spec">Rackable — adapts to slope</div>
|
||
<div className="hw-spec">Compatible with all 4 models</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="hw-card">
|
||
<div className="hw-icon">
|
||
<svg viewBox="0 0 20 20" fill="none"><circle cx="6" cy="10" r="4" fill="none" stroke="white" strokeWidth="2" /><rect x="10" y="9" width="9" height="2" rx="1" fill="white" /><circle cx="6" cy="10" r="1.5" fill="white" /></svg>
|
||
</div>
|
||
<div className="hw-name">Regular <span>Gate Hardware</span></div>
|
||
<div className="hw-desc">Standard 2" × 1-1/4" gate hardware set including heavy-duty hinges, fork latch, and all required fasteners. Suitable for all standard residential gate installations.</div>
|
||
<div className="hw-specs">
|
||
<div className="hw-spec">2" × 1-1/4" fitting size</div>
|
||
<div className="hw-spec">Hinges + fork latch</div>
|
||
<div className="hw-spec">All 4 gate models</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="hw-card" style={{ borderColor: "rgba(232,87,42,.35)" }}>
|
||
<div className="hw-icon" style={{ background: "rgba(232,87,42,.8)" }}>
|
||
<svg viewBox="0 0 20 20" fill="none"><circle cx="10" cy="10" r="7" fill="none" stroke="white" strokeWidth="2" /><path d="M10 6 L10 10 L13 13" stroke="white" strokeWidth="1.8" strokeLinecap="round" /></svg>
|
||
</div>
|
||
<div className="hw-name">Self-Close <span>Gate Hardware</span></div>
|
||
<div className="hw-desc">Self-closing gate hardware required for all swimming pool fence installations per Ontario pool enclosure regulations. Automatically closes and latches after each use.</div>
|
||
<div className="hw-specs">
|
||
<div className="hw-spec">2" × 1-1/4" fitting size</div>
|
||
<div className="hw-spec">Auto-close spring mechanism</div>
|
||
<div className="hw-spec" style={{ color: "var(--orange)" }}>Required for pool enclosures</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="hw-card">
|
||
<div className="hw-icon">
|
||
<svg viewBox="0 0 20 20" fill="none"><rect x="3" y="3" width="14" height="14" rx="2" fill="none" stroke="white" strokeWidth="2" /><line x1="3" y1="10" x2="17" y2="10" stroke="white" strokeWidth="1" opacity=".5" /><line x1="10" y1="3" x2="10" y2="17" stroke="white" strokeWidth="1" opacity=".5" /></svg>
|
||
</div>
|
||
<div className="hw-name">Complete <span>Hardware Packs</span></div>
|
||
<div className="hw-desc">Order all posts, caps, brackets, and gate hardware together as a complete package for your project. We'll help you calculate quantities based on your fence linear footage and gate count.</div>
|
||
<div className="hw-specs">
|
||
<div className="hw-spec">Posts + caps + brackets</div>
|
||
<div className="hw-spec">Gate hardware included</div>
|
||
<div className="hw-spec">Quantity calc on request</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
{/* COMMERCIAL BANNER */}
|
||
<div className="commercial-banner">
|
||
<div className="commercial-banner-icon">
|
||
<svg viewBox="0 0 28 28" fill="none"><rect x="2" y="8" width="24" height="18" rx="3" stroke="white" strokeWidth="2" /><path d="M9 8 V5 a5 5 0 0 1 10 0 V8" stroke="white" strokeWidth="2" /><line x1="14" y1="14" x2="14" y2="20" stroke="white" strokeWidth="2" strokeLinecap="round" /><line x1="11" y1="17" x2="17" y2="17" stroke="white" strokeWidth="2" strokeLinecap="round" /></svg>
|
||
</div>
|
||
<div className="commercial-banner-text">
|
||
<h3>Commercial ornamental fence — available on request</h3>
|
||
<p>Our standard product line is residential, but we can source and supply commercial-grade ornamental fence orders for larger projects, institutional applications, and commercial properties. Contact us with your project specifications and we'll provide pricing and lead time.</p>
|
||
</div>
|
||
<button className="commercial-banner-cta" onClick={() => scrollToSection("quote-section")}>Get commercial pricing →</button>
|
||
</div>
|
||
|
||
{/* COMPARE ALL MODELS */}
|
||
<section className="compare-section" id="compare">
|
||
<div className="reveal">
|
||
<div className="section-eyebrow">Model comparison</div>
|
||
<h2 className="sh">Compare all<br /><span>4 models.</span></h2>
|
||
</div>
|
||
<div className="compare-table-wrap reveal">
|
||
<table className="compare-table">
|
||
<thead>
|
||
<tr>
|
||
<th>Specification</th>
|
||
<th><span className="model-pill pill-tokio">Tokio</span></th>
|
||
<th><span className="model-pill pill-rio">Rio</span></th>
|
||
<th><span className="model-pill pill-denver">Denver</span></th>
|
||
<th><span className="model-pill pill-oslo">Oslo</span></th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>Application type</td>
|
||
<td>Fence</td>
|
||
<td>Fence</td>
|
||
<td>Fence / Railing</td>
|
||
<td>Fence / Railing</td>
|
||
</tr>
|
||
<tr>
|
||
<td>48" × 92" panel</td>
|
||
<td><span className="check">✓</span></td>
|
||
<td><span className="check">✓</span></td>
|
||
<td><span className="check">✓</span></td>
|
||
<td><span className="check">✓</span></td>
|
||
</tr>
|
||
<tr>
|
||
<td>60" × 92" panel</td>
|
||
<td><span className="check">✓</span></td>
|
||
<td><span className="check">✓</span></td>
|
||
<td><span className="check">✓</span></td>
|
||
<td><span className="check">✓</span></td>
|
||
</tr>
|
||
<tr>
|
||
<td>Rackable</td>
|
||
<td><span className="check">✓</span></td>
|
||
<td><span className="check">✓</span></td>
|
||
<td><span className="check">✓</span></td>
|
||
<td><span className="check">✓</span></td>
|
||
</tr>
|
||
<tr>
|
||
<td>Gate 48"H × 46" OP</td>
|
||
<td><span className="check">✓</span></td>
|
||
<td><span className="check">✓</span></td>
|
||
<td><span className="check">✓</span></td>
|
||
<td><span className="check">✓</span></td>
|
||
</tr>
|
||
<tr>
|
||
<td>Gate 48"H × 60" OP</td>
|
||
<td><span className="check">✓</span></td>
|
||
<td><span className="check">✓</span></td>
|
||
<td><span className="check">✓</span></td>
|
||
<td><span className="check">✓</span></td>
|
||
</tr>
|
||
<tr>
|
||
<td>Post size</td>
|
||
<td>2" sq</td>
|
||
<td>2" sq</td>
|
||
<td>2" sq</td>
|
||
<td>2" sq</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Post heights</td>
|
||
<td>6'6" – 10'</td>
|
||
<td>6'6" – 10'</td>
|
||
<td>6'6" – 10'</td>
|
||
<td>6'6" – 10'</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Railing application</td>
|
||
<td>—</td>
|
||
<td>—</td>
|
||
<td><span className="check">✓</span></td>
|
||
<td><span className="check">✓</span></td>
|
||
</tr>
|
||
<tr>
|
||
<td>Pool-safe gate hardware</td>
|
||
<td><span className="check">✓</span></td>
|
||
<td><span className="check">✓</span></td>
|
||
<td><span className="check">✓</span></td>
|
||
<td><span className="check">✓</span></td>
|
||
</tr>
|
||
<tr>
|
||
<td>In stock</td>
|
||
<td><span className="check">✓</span></td>
|
||
<td><span className="check">✓</span></td>
|
||
<td><span className="check">✓</span></td>
|
||
<td><span className="check">✓</span></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</section>
|
||
|
||
{/* FAQ + SEO CONTENT */}
|
||
<section className="faq-section">
|
||
<div className="reveal">
|
||
<div className="section-eyebrow">Helpful information</div>
|
||
<h2 className="sh">Ornamental fence<br /><span>knowledge base.</span></h2>
|
||
</div>
|
||
<div className="faq-seo-grid">
|
||
<div className="faq reveal">
|
||
{[
|
||
{
|
||
q: "What models of ornamental fence do you carry?",
|
||
a: "We carry four residential ornamental fence models: Tokio, Rio, Denver, and Oslo. Tokio and Rio are traditional fence panels; Denver and Oslo are railing-profile panels that also work as deck or step railings. All four are rackable, available in 48\" and 60\" heights, with matching gates and hardware.",
|
||
},
|
||
{
|
||
q: "What panel sizes are available?",
|
||
a: "All four models are available in two heights: 48\" × 92\" rackable panels and 60\" × 92\" rackable panels. The 92\" width is standard across all models. Rackable design means panels can follow sloped terrain without stair-stepping.",
|
||
},
|
||
{
|
||
q: "What gate sizes do you stock?",
|
||
a: "Each model has matching walk gates in two opening widths: 48\"H × 46\" OP (standard walk gate) and 48\"H × 60\" OP (wider opening). Both are available with standard gate hardware or self-closing hardware required for pool enclosures.",
|
||
},
|
||
{
|
||
q: "Do you have pool-compliant gate hardware?",
|
||
a: "Yes. We stock the 2\" × 1-1/4\" self-closing gate hardware required for swimming pool fence installations. This hardware automatically closes and latches the gate after each use, meeting Ontario pool enclosure safety regulations. Specify self-close hardware when ordering.",
|
||
},
|
||
{
|
||
q: "Is commercial ornamental fence available?",
|
||
a: "Yes, commercial ornamental fence orders are available on request. Our standard stocked line is residential, but we can source commercial-grade ornamental fence for larger projects and institutional or commercial applications. Contact us with your project specs for pricing and lead time.",
|
||
},
|
||
{
|
||
q: "Do you deliver ornamental fence to job sites across Ontario?",
|
||
a: "Yes. We offer scheduled delivery to job sites across a 250km radius from our Kitchener–Waterloo base, covering Guelph, Hamilton, Brantford, Toronto/GTA, London, Windsor, Niagara, Barrie, and all communities in between. Contact us to schedule a delivery for your project.",
|
||
},
|
||
].map((item, idx) => (
|
||
<div key={idx} className={`faq-item ${openFaq === idx ? "open" : ""}`}>
|
||
<div className="faq-q" onClick={() => toggleFaq(idx)}>
|
||
{item.q}
|
||
<span className="faq-icon">{openFaq === idx ? "×" : "+"}</span>
|
||
</div>
|
||
<div className="faq-a" style={{ maxHeight: openFaq === idx ? "240px" : "0px", paddingBottom: openFaq === idx ? "18px" : "0px" }}>
|
||
{item.a}
|
||
</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
|
||
<div className="content-block reveal">
|
||
<h3>Ornamental fence supply — Kitchener, Waterloo & Ontario</h3>
|
||
<p>VG Fence Products is a dedicated ornamental fence supplier serving fence contractors and builders across the Kitchener–Waterloo–Cambridge region. We stock four residential ornamental fence models with matching gates, posts, and hardware — everything a contractor needs to complete an ornamental fence installation from a single source.</p>
|
||
|
||
<h3>Rackable ornamental fence panels</h3>
|
||
<p>All four of our ornamental fence models feature rackable panel construction. Rackable panels allow the fence line to follow the natural slope of a property without creating a stepped, uneven appearance. This makes installation faster and the finished fence look more professional on any terrain.</p>
|
||
|
||
<h3>Ornamental fence for pool enclosures</h3>
|
||
<p>Ornamental fence is a popular choice for pool enclosures because of its open, elegant appearance and compliance with pool safety requirements. We stock the self-closing gate hardware required by Ontario pool enclosure regulations — ensuring your pool fence installation meets all code requirements.</p>
|
||
|
||
<h3>Contractor pricing & bulk orders</h3>
|
||
<p>We supply fence contractors, landscaping companies, and builders with ornamental fence panels, gates, and hardware at contractor pricing. Set up a contractor account for streamlined ordering and preferential rates on bulk orders. Delivery is available directly to your job site across our 250km service radius.</p>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
{/* SERVICE TERRITORY */}
|
||
<section className="territory" id="territory">
|
||
<div className="reveal">
|
||
<div className="section-eyebrow" style={{ color: "rgba(255,255,255,.5)" }}>Where we deliver</div>
|
||
<h2 className="sh sh-white">Ornamental fence supply<br /><span>across Ontario.</span></h2>
|
||
<p className="territory-intro">Scheduled delivery to job sites across a 250km radius from Kitchener–Waterloo. Below are the communities we serve.</p>
|
||
</div>
|
||
<div className="region-grid reveal">
|
||
<div className="region-block">
|
||
<div className="region-name">Waterloo Region</div>
|
||
<ul className="region-cities">
|
||
<li className="primary">Kitchener</li><li className="primary">Waterloo</li><li className="primary">Cambridge</li>
|
||
<li>Ayr</li><li>Breslau</li><li>Elmira</li><li>St. Jacobs</li><li>New Hamburg</li><li>Baden</li><li>Wellesley</li>
|
||
</ul>
|
||
</div>
|
||
<div className="region-block">
|
||
<div className="region-name">Guelph & Wellington</div>
|
||
<ul className="region-cities">
|
||
<li className="primary">Guelph</li><li>Fergus</li><li>Elora</li><li>Rockwood</li><li>Acton</li><li>Georgetown</li>
|
||
</ul>
|
||
</div>
|
||
<div className="region-block">
|
||
<div className="region-name">Halton & Hamilton</div>
|
||
<ul className="region-cities">
|
||
<li className="primary">Hamilton</li><li className="primary">Burlington</li><li>Milton</li><li>Oakville</li>
|
||
<li>Stoney Creek</li><li>Grimsby</li><li>Brantford</li><li>Paris</li>
|
||
</ul>
|
||
</div>
|
||
<div className="region-block">
|
||
<div className="region-name">GTA & Peel</div>
|
||
<ul className="region-cities">
|
||
<li className="primary">Mississauga</li><li className="primary">Brampton</li><li>Vaughan</li><li>Markham</li><li>Richmond Hill</li>
|
||
</ul>
|
||
</div>
|
||
<div className="region-block">
|
||
<div className="region-name">Oxford & Perth</div>
|
||
<ul className="region-cities">
|
||
<li className="primary">Woodstock</li><li className="primary">Stratford</li><li>Ingersoll</li><li>Tillsonburg</li><li>St. Marys</li>
|
||
</ul>
|
||
</div>
|
||
<div className="region-block">
|
||
<div className="region-name">London & Elgin</div>
|
||
<ul className="region-cities">
|
||
<li className="primary">London</li><li>St. Thomas</li><li>Strathroy</li><li>Komoka</li>
|
||
</ul>
|
||
</div>
|
||
<div className="region-block">
|
||
<div className="region-name">Southwest Ontario</div>
|
||
<ul className="region-cities">
|
||
<li className="primary">Windsor</li><li className="primary">Chatham</li><li>Leamington</li><li>Sarnia</li><li>Petrolia</li>
|
||
</ul>
|
||
</div>
|
||
<div className="region-block">
|
||
<div className="region-name">Extended Service</div>
|
||
<ul className="region-cities">
|
||
<li className="primary">Niagara Falls</li><li>St. Catharines</li><li>Welland</li>
|
||
<li className="primary">Barrie</li><li>Owen Sound</li><li>Collingwood</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
{/* QUOTE CTA */}
|
||
<section className="quote-cta" id="quote-section">
|
||
<div className="quote-inner">
|
||
<div className="quote-left">
|
||
<h2>Get ornamental fence pricing.</h2>
|
||
<p>Tell us the model, panel height, linear footage, and number of gates — we'll come back with contractor pricing within 2 business hours. Commercial orders also available on request.</p>
|
||
</div>
|
||
<div className="quote-form-card">
|
||
{formStatus === "success" ? (
|
||
<div style={{ padding: "30px", background: "rgba(255,255,255,0.1)", borderRadius: "8px", border: "1px solid white", color: "white", textAlign: "center" }}>
|
||
<div style={{ fontSize: "40px", marginBottom: "15px" }}>✅</div>
|
||
<h3 style={{ margin: "0 0 10px 0", fontFamily: "var(--fd)" }}>Request Sent!</h3>
|
||
<p style={{ margin: 0, opacity: 0.9 }}>Thank you. We'll be in touch within 2 business hours.</p>
|
||
<button
|
||
type="button"
|
||
className="qbtn"
|
||
style={{ marginTop: "20px" }}
|
||
onClick={() => setFormStatus("idle")}
|
||
>
|
||
Send another request
|
||
</button>
|
||
</div>
|
||
) : (
|
||
<form onSubmit={handleFormSubmit}>
|
||
<div style={{ fontFamily: "var(--fd)", fontSize: "17px", fontWeight: 700, textTransform: "uppercase", color: "var(--white)", letterSpacing: ".04em", marginBottom: "4px" }}>Request a quote</div>
|
||
<div style={{ fontSize: "12px", color: "rgba(255,255,255,.6)", marginBottom: "20px" }}>Response within 2 business hours · Contractor pricing</div>
|
||
|
||
<div className="qrow">
|
||
<div>
|
||
<label className="ql">Company name</label>
|
||
<input
|
||
className="qi"
|
||
type="text"
|
||
name="companyName"
|
||
placeholder="ABC Fence Co."
|
||
value={formData.companyName}
|
||
onChange={handleInputChange}
|
||
/>
|
||
</div>
|
||
<div>
|
||
<label className="ql">Your name</label>
|
||
<input
|
||
className="qi"
|
||
type="text"
|
||
name="name"
|
||
placeholder="John Smith"
|
||
value={formData.name}
|
||
onChange={handleInputChange}
|
||
required
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="qrow">
|
||
<div>
|
||
<label className="ql">Phone</label>
|
||
<input
|
||
className="qi"
|
||
type="tel"
|
||
name="phone"
|
||
placeholder="519-xxx-xxxx"
|
||
value={formData.phone}
|
||
onChange={handleInputChange}
|
||
required
|
||
/>
|
||
</div>
|
||
<div>
|
||
<label className="ql">Email</label>
|
||
<input
|
||
className="qi"
|
||
type="email"
|
||
name="email"
|
||
placeholder="you@company.com"
|
||
value={formData.email}
|
||
onChange={handleInputChange}
|
||
required
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
<label className="ql">Model & panel size</label>
|
||
<select
|
||
className="qi"
|
||
name="modelSize"
|
||
value={formData.modelSize}
|
||
onChange={handleInputChange}
|
||
required
|
||
>
|
||
<option value="">Select model...</option>
|
||
<option value='Tokio — 48" × 92"'>Tokio — 48" × 92"</option>
|
||
<option value='Tokio — 60" × 92"'>Tokio — 60" × 92"</option>
|
||
<option value='Rio — 48" × 92"'>Rio — 48" × 92"</option>
|
||
<option value='Rio — 60" × 92"'>Rio — 60" × 92"</option>
|
||
<option value='Denver — 48" × 92"'>Denver — 48" × 92"</option>
|
||
<option value='Denver — 60" × 92"'>Denver — 60" × 92"</option>
|
||
<option value='Oslo — 48" × 92"'>Oslo — 48" × 92"</option>
|
||
<option value='Oslo — 60" × 92"'>Oslo — 60" × 92"</option>
|
||
<option value="Multiple models / Commercial inquiry">Multiple models / Commercial inquiry</option>
|
||
</select>
|
||
|
||
<div className="qrow">
|
||
<div>
|
||
<label className="ql">Job site city</label>
|
||
<input
|
||
className="qi"
|
||
type="text"
|
||
name="city"
|
||
placeholder="Kitchener, Guelph..."
|
||
value={formData.city}
|
||
onChange={handleInputChange}
|
||
required
|
||
/>
|
||
</div>
|
||
<div>
|
||
<label className="ql">Linear footage</label>
|
||
<input
|
||
className="qi"
|
||
type="text"
|
||
name="footage"
|
||
placeholder="e.g. 150 linear ft"
|
||
value={formData.footage}
|
||
onChange={handleInputChange}
|
||
required
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
{formStatus === "error" && (
|
||
<p style={{ color: "#fee2e2", fontSize: "14px", marginBottom: "15px" }}>
|
||
⚠️ Failed to send request. Please try again or email us directly.
|
||
</p>
|
||
)}
|
||
|
||
<button
|
||
className="qbtn"
|
||
type="submit"
|
||
disabled={formStatus === "submitting"}
|
||
>
|
||
{formStatus === "submitting" ? "Sending..." : "Send quote request →"}
|
||
</button>
|
||
</form>
|
||
)}
|
||
</div>
|
||
</div>
|
||
</section>
|
||
</div>
|
||
);
|
||
}
|