Construction — Roofing Landing
A rugged roofing-company landing page with a free-inspection hero CTA, four core service cards, an insurance-claim help section, materials and warranty grid, a before-and-after teaser, customer reviews and a working inspection request form with inline validation and a live submitted-state confirmation.
MCP
Code
:root {
--hv: #f5c518; /* hi-vis yellow */
--hv-d: #d9ad0d;
--steel: #2b3440;
--steel-d: #1b222b;
--bg: #eceae6; /* concrete */
--surface: #ffffff;
--ink: #1a1d22;
--muted: #666c75;
--orange: #e8642a;
--line: #d6d3cd;
--line-steel: #3c4757;
--radius: 10px;
--shadow: 0 2px 0 rgba(0, 0, 0, .06), 0 10px 24px rgba(27, 34, 43, .08);
--font: 'Inter', system-ui, -apple-system, sans-serif;
--maxw: 1140px;
}
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }
html { scroll-behavior: smooth; }
body {
font-family: var(--font);
color: var(--ink);
background: var(--bg);
line-height: 1.55;
-webkit-font-smoothing: antialiased;
}
img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
h1, h2, h3, h4 {
line-height: 1.05;
letter-spacing: -.01em;
font-weight: 800;
text-transform: uppercase;
}
h1 { font-size: clamp(2.4rem, 6vw, 4rem); letter-spacing: -.02em; }
h2 { font-size: clamp(1.5rem, 3.2vw, 2.2rem); }
.wrap { width: 100%; max-width: var(--maxw); margin: 0 auto; padding: 0 22px; }
/* ---------- buttons ---------- */
.btn {
--bc: var(--ink);
display: inline-flex;
align-items: center;
justify-content: center;
gap: .45rem;
font-family: var(--font);
font-weight: 800;
text-transform: uppercase;
letter-spacing: .03em;
font-size: .82rem;
padding: .72rem 1.25rem;
border: 2px solid var(--bc);
border-radius: 8px;
cursor: pointer;
transition: transform .08s ease, box-shadow .12s ease, background .15s ease;
background: var(--surface);
color: var(--ink);
}
.btn:hover { transform: translateY(-2px); }
.btn:active { transform: translateY(0); }
.btn:focus-visible { outline: 3px solid var(--hv); outline-offset: 2px; }
.btn--lg { padding: .9rem 1.5rem; font-size: .9rem; }
.btn--block { width: 100%; }
.btn--hv { --bc: var(--hv-d); background: var(--hv); color: var(--steel-d); box-shadow: 0 4px 0 var(--hv-d); }
.btn--hv:hover { box-shadow: 0 6px 0 var(--hv-d); }
.btn--steel { --bc: var(--steel-d); background: var(--steel); color: #fff; box-shadow: 0 4px 0 var(--steel-d); }
.btn--steel:hover { box-shadow: 0 6px 0 var(--steel-d); }
.btn--ghost { background: transparent; border-color: currentColor; }
/* ---------- nav ---------- */
.nav {
position: sticky;
top: 0;
z-index: 40;
background: var(--steel-d);
color: #fff;
border-bottom: 3px solid var(--hv);
}
.nav__inner { display: flex; align-items: center; gap: 1.5rem; min-height: 64px; }
.brand { display: flex; align-items: center; gap: .55rem; font-weight: 800; }
.brand__mark {
width: 30px; height: 30px;
display: grid; place-items: center;
background: var(--hv); color: var(--steel-d);
border-radius: 6px; font-size: 1rem;
}
.brand__name {
display: flex; flex-direction: column; line-height: .95;
font-size: 1.05rem; letter-spacing: .02em;
}
.brand__name small {
font-size: .55rem; letter-spacing: .22em;
color: var(--hv); font-weight: 700;
}
.nav__links { display: flex; gap: 1.4rem; margin-left: auto; font-size: .82rem; font-weight: 600; text-transform: uppercase; letter-spacing: .04em; }
.nav__links a { color: #cdd3da; padding: .4rem 0; border-bottom: 2px solid transparent; transition: color .15s, border-color .15s; }
.nav__links a:hover { color: #fff; border-color: var(--hv); }
.nav__cta { display: flex; align-items: center; gap: 1rem; }
.phone {
font-weight: 800; letter-spacing: .02em; color: var(--hv);
font-size: .92rem; white-space: nowrap;
}
.phone:hover { color: #fff; }
/* ---------- hero ---------- */
.hero {
position: relative;
background: var(--steel);
color: #fff;
overflow: hidden;
}
.hero__hazard {
position: absolute; inset: 0;
background: repeating-linear-gradient(135deg,
transparent 0 38px, rgba(245, 197, 24, .05) 38px 76px);
pointer-events: none;
}
.hero::after {
content: "";
position: absolute; left: 0; right: 0; bottom: -1px; height: 26px;
background: repeating-linear-gradient(135deg,
var(--hv) 0 22px, var(--steel-d) 22px 44px);
opacity: .9;
}
.hero__inner {
position: relative;
display: grid;
grid-template-columns: 1.3fr .9fr;
gap: 2.5rem;
align-items: center;
padding: 4.5rem 22px 5.5rem;
}
.kicker {
display: inline-block;
font-size: .72rem; font-weight: 700; letter-spacing: .14em;
text-transform: uppercase; color: var(--hv);
border: 1px solid var(--line-steel);
padding: .35rem .7rem; border-radius: 999px;
margin-bottom: 1.1rem;
}
.hero h1 { color: #fff; }
.hero h1 .hl { color: var(--hv); }
.hero__lede { color: #c3c9d1; font-size: 1.08rem; max-width: 46ch; margin: 1.1rem 0 1.8rem; }
.hero__actions { display: flex; flex-wrap: wrap; gap: .8rem; margin-bottom: 2rem; }
.hero__trust {
list-style: none; padding: 0;
display: flex; gap: 1.8rem; flex-wrap: wrap;
border-top: 1px solid var(--line-steel); padding-top: 1.2rem;
}
.hero__trust li { font-size: .82rem; color: #aab1ba; text-transform: uppercase; letter-spacing: .03em; }
.hero__trust strong { display: block; font-size: 1.5rem; color: #fff; }
.hero__card {
background: var(--surface); color: var(--ink);
border-radius: var(--radius);
border: 1px solid var(--line);
padding: 1.6rem 1.5rem;
box-shadow: 0 18px 40px rgba(0, 0, 0, .3);
border-top: 5px solid var(--orange);
}
.hero__card h2 { font-size: 1.4rem; margin: .7rem 0 .5rem; }
.hero__card p { color: var(--muted); font-size: .92rem; }
.badge {
display: inline-block; font-size: .7rem; font-weight: 800;
text-transform: uppercase; letter-spacing: .06em;
padding: .3rem .6rem; border-radius: 6px;
}
.badge--orange { background: #fde8de; color: var(--orange); }
.checks { list-style: none; padding: 0; margin: 1rem 0 1.3rem; }
.checks li {
position: relative; padding-left: 1.6rem;
font-size: .9rem; margin-bottom: .55rem; color: var(--ink);
}
.checks li::before {
content: "✓"; position: absolute; left: 0; top: 0;
color: var(--orange); font-weight: 900;
}
/* ---------- sections ---------- */
.section { padding: 4.5rem 0; }
.section--steel { background: var(--steel-d); color: #fff; }
.section--concrete { background: #e2dfd9; }
.section__head { max-width: 640px; margin: 0 auto 2.5rem; text-align: center; }
.section__head--left { margin: 0 0 1.8rem; text-align: left; }
.eyebrow {
display: inline-block; font-size: .74rem; font-weight: 800;
text-transform: uppercase; letter-spacing: .14em; color: var(--orange);
margin-bottom: .6rem;
}
.eyebrow--hv { color: var(--hv); }
/* ---------- grids / cards ---------- */
.grid { display: grid; gap: 1.2rem; }
.grid--4 { grid-template-columns: repeat(4, 1fr); }
.grid--3 { grid-template-columns: repeat(3, 1fr); }
.card {
background: var(--surface);
border: 1px solid var(--line);
border-radius: var(--radius);
padding: 1.5rem;
box-shadow: var(--shadow);
}
.svc { border-top: 4px solid var(--steel); transition: transform .12s ease, border-color .15s; }
.svc:hover { transform: translateY(-4px); border-top-color: var(--orange); }
.svc__ico { font-size: 1.9rem; display: block; margin-bottom: .6rem; }
.svc h3 { font-size: 1.1rem; margin-bottom: .45rem; }
.svc p { color: var(--muted); font-size: .9rem; margin-bottom: 1rem; }
.tag {
display: inline-block; font-size: .72rem; font-weight: 800;
text-transform: uppercase; letter-spacing: .04em;
background: var(--bg); color: var(--steel);
padding: .3rem .6rem; border-radius: 6px;
}
.tag--orange { background: #fde8de; color: var(--orange); }
/* ---------- claims ---------- */
.claims { display: grid; grid-template-columns: 1.4fr 1fr; gap: 2.5rem; align-items: start; }
.claims__copy p { color: #c3c9d1; margin: 1rem 0 1.5rem; max-width: 52ch; }
.steps { list-style: none; padding: 0; margin: 0 0 1.8rem; display: grid; gap: .8rem; }
.steps li {
display: flex; align-items: center; gap: .9rem;
font-size: .95rem; color: #e6e9ed;
}
.steps li span {
flex: 0 0 auto; width: 30px; height: 30px; border-radius: 7px;
display: grid; place-items: center; font-weight: 900;
background: var(--hv); color: var(--steel-d);
}
.claims__panel {
background: #232c37; border: 1px solid var(--line-steel);
border-radius: var(--radius); padding: 1.6rem;
}
.claims__panel h3 { font-size: 1rem; color: var(--hv); margin-bottom: 1rem; }
.carriers { list-style: none; padding: 0; display: grid; grid-template-columns: 1fr 1fr; gap: .6rem; }
.carriers li {
font-size: .85rem; font-weight: 600; color: #e6e9ed;
background: #1b222b; border: 1px solid var(--line-steel);
border-radius: 6px; padding: .55rem .7rem; text-align: center;
}
.claims__note {
margin-top: 1.2rem; font-size: .82rem; color: #ffd86b;
border-left: 3px solid var(--orange); padding-left: .8rem;
}
/* ---------- materials ---------- */
.mat { position: relative; }
.mat h3 { font-size: 1.15rem; margin-bottom: .35rem; }
.mat__price { color: var(--orange); font-weight: 800; font-size: .82rem; text-transform: uppercase; letter-spacing: .05em; margin-bottom: 1rem; }
.mat ul { list-style: none; padding: 0; display: grid; gap: .6rem; }
.mat li { font-size: .9rem; color: var(--muted); padding-left: 1.4rem; position: relative; }
.mat li::before { content: "▸"; position: absolute; left: 0; color: var(--steel); }
.mat .warr { color: var(--ink); font-weight: 700; }
.mat .warr::before { content: "🛡"; }
.mat--feature { border: 2px solid var(--hv); box-shadow: 0 12px 30px rgba(245, 197, 24, .25); }
.ribbon {
position: absolute; top: -12px; right: 16px;
background: var(--hv); color: var(--steel-d);
font-size: .68rem; font-weight: 900; text-transform: uppercase; letter-spacing: .06em;
padding: .3rem .65rem; border-radius: 6px;
}
/* ---------- before / after ---------- */
.ba__sub { color: var(--muted); margin-top: .5rem; }
.ba__viewer {
position: relative; margin-top: 1.6rem;
height: 340px; border-radius: var(--radius); overflow: hidden;
border: 3px solid var(--steel-d); user-select: none;
box-shadow: var(--shadow);
}
.ba__panel { position: absolute; inset: 0; }
.ba__panel--after { clip-path: inset(0 0 0 50%); }
.ba__art { position: absolute; inset: 0; }
.ba__art--before {
background:
repeating-linear-gradient(100deg, #6b6256 0 14px, #5b5348 14px 28px),
#5b5348;
filter: brightness(.85);
}
.ba__art--before::after {
content: ""; position: absolute; inset: 0;
background:
radial-gradient(circle at 30% 40%, rgba(0,0,0,.4) 0 8px, transparent 9px),
radial-gradient(circle at 60% 65%, rgba(0,0,0,.4) 0 10px, transparent 11px),
radial-gradient(circle at 80% 30%, rgba(0,0,0,.35) 0 6px, transparent 7px);
}
.ba__art--after {
background:
repeating-linear-gradient(100deg, #3a4654 0 16px, #2f3a47 16px 32px),
#2f3a47;
}
.ba__label {
position: absolute; top: 12px; left: 12px; z-index: 3;
background: var(--steel-d); color: #fff;
font-size: .72rem; font-weight: 800; text-transform: uppercase; letter-spacing: .08em;
padding: .35rem .7rem; border-radius: 6px;
}
.ba__label--after { left: auto; right: 12px; background: var(--orange); }
.ba__divider {
position: absolute; top: 0; bottom: 0; left: 50%;
width: 3px; background: var(--hv); z-index: 4; transform: translateX(-50%);
}
.ba__handle {
position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
width: 44px; height: 44px; border-radius: 50%;
background: var(--hv); color: var(--steel-d);
border: 3px solid var(--steel-d); cursor: ew-resize;
font-weight: 900; font-size: 1rem; display: grid; place-items: center;
box-shadow: 0 4px 12px rgba(0, 0, 0, .35);
}
.ba__handle:focus-visible { outline: 3px solid var(--steel-d); outline-offset: 2px; }
/* ---------- reviews ---------- */
.review { display: flex; flex-direction: column; gap: .8rem; }
.stars { color: var(--hv); font-size: 1.05rem; letter-spacing: .08em; }
.review blockquote { font-size: .95rem; color: var(--ink); }
.review figcaption { font-size: .85rem; color: var(--muted); margin-top: auto; }
.review figcaption strong { color: var(--ink); display: block; }
/* ---------- inspection form ---------- */
.inspect { display: grid; grid-template-columns: 1fr 1fr; gap: 2.5rem; align-items: start; }
.inspect__copy { grid-row: 1; }
.inspect__copy p { color: #c3c9d1; margin: 1rem 0 1.4rem; max-width: 46ch; }
.inspect__perks { list-style: none; padding: 0; display: grid; gap: .55rem; }
.inspect__perks li { color: #e6e9ed; font-size: .92rem; font-weight: 600; }
.form { color: var(--ink); display: grid; gap: 1rem; border-top: 5px solid var(--hv); }
.field { display: grid; gap: .35rem; }
.field label { font-size: .78rem; font-weight: 800; text-transform: uppercase; letter-spacing: .05em; color: var(--steel); }
.field input, .field select {
font-family: var(--font); font-size: .95rem;
padding: .7rem .8rem; border: 2px solid var(--line);
border-radius: 8px; background: #fafafa; color: var(--ink);
transition: border-color .15s, box-shadow .15s;
}
.field input:focus, .field select:focus {
outline: none; border-color: var(--steel);
box-shadow: 0 0 0 3px rgba(43, 52, 64, .12); background: #fff;
}
.field.invalid input { border-color: var(--orange); background: #fff6f2; }
.err { color: var(--orange); font-size: .78rem; font-weight: 600; min-height: 0; }
.field.invalid .err { min-height: 1em; }
.check { display: flex; align-items: center; gap: .6rem; font-size: .9rem; color: var(--ink); cursor: pointer; }
.check input { width: 18px; height: 18px; accent-color: var(--orange); }
.form__fine { font-size: .74rem; color: var(--muted); text-align: center; }
.success { text-align: center; border-top: 5px solid var(--orange); color: var(--ink); }
.success__ico {
display: grid; place-items: center; width: 56px; height: 56px;
margin: 0 auto 1rem; border-radius: 50%;
background: var(--hv); color: var(--steel-d);
font-size: 1.8rem; font-weight: 900;
}
.success h3 { font-size: 1.3rem; margin-bottom: .5rem; }
.success p { color: var(--muted); margin-bottom: 1.4rem; }
.success p strong { color: var(--orange); }
/* ---------- footer ---------- */
.footer { background: var(--steel-d); color: #c3c9d1; border-top: 3px solid var(--hv); }
.footer__inner {
display: grid; grid-template-columns: 1.6fr 1fr 1fr 1fr; gap: 1.8rem;
padding: 3rem 22px 2rem;
}
.footer__brand p { font-size: .85rem; margin-top: .6rem; max-width: 34ch; }
.footer__brand .brand__name { color: #fff; }
.footer__col h4 { font-size: .8rem; color: var(--hv); margin-bottom: .6rem; }
.footer__col p { font-size: .88rem; }
.footer__legal {
border-top: 1px solid var(--line-steel); padding-top: 1.2rem; padding-bottom: 1.6rem;
font-size: .8rem; color: #8a929c;
}
/* ---------- responsive ---------- */
@media (max-width: 900px) {
.grid--4 { grid-template-columns: repeat(2, 1fr); }
.grid--3 { grid-template-columns: 1fr; }
.hero__inner, .claims, .inspect { grid-template-columns: 1fr; }
.footer__inner { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 520px) {
.nav__links { display: none; }
.nav__cta .phone { display: none; }
.nav__inner { gap: .8rem; }
.section { padding: 3rem 0; }
.hero__inner { padding: 3rem 22px 4rem; }
.grid--4 { grid-template-columns: 1fr; }
.carriers { grid-template-columns: 1fr; }
.footer__inner { grid-template-columns: 1fr; }
.hero__trust { gap: 1.1rem; }
.ba__viewer { height: 240px; }
.btn--lg { width: 100%; }
.hero__actions { flex-direction: column; }
.hero__actions .btn { width: 100%; }
}
@media (prefers-reduced-motion: reduce) {
* { scroll-behavior: auto; transition: none !important; }
}(function () {
"use strict";
/* ---------- Inspection form ---------- */
var form = document.getElementById("inspectForm");
var successPanel = document.getElementById("successPanel");
var ticketNo = document.getElementById("ticketNo");
var resetBtn = document.getElementById("resetForm");
function setError(name, msg) {
var input = form.elements[name];
if (!input) return;
var field = input.closest(".field");
var err = field ? field.querySelector('.err[data-for="' + name + '"]') : null;
if (field) field.classList.toggle("invalid", !!msg);
if (err) err.textContent = msg || "";
if (msg) input.setAttribute("aria-invalid", "true");
else input.removeAttribute("aria-invalid");
}
function validate() {
var ok = true;
var name = form.elements.name.value.trim();
var phone = form.elements.phone.value.trim();
var address = form.elements.address.value.trim();
if (name.length < 2) { setError("name", "Please enter your name."); ok = false; }
else setError("name", "");
// require at least 7 digits in the phone
var digits = phone.replace(/\D/g, "");
if (digits.length < 7) { setError("phone", "Enter a valid phone number."); ok = false; }
else setError("phone", "");
if (address.length < 5) { setError("address", "Enter the property address."); ok = false; }
else setError("address", "");
return ok;
}
function makeTicket() {
var n = Math.floor(10000 + Math.random() * 89999);
return "#IR-" + n;
}
if (form) {
// clear errors as the user fixes them
["name", "phone", "address"].forEach(function (n) {
var el = form.elements[n];
if (el) el.addEventListener("input", function () {
if (el.closest(".field").classList.contains("invalid")) setError(n, "");
});
});
form.addEventListener("submit", function (e) {
e.preventDefault();
if (!validate()) {
var firstBad = form.querySelector(".field.invalid input");
if (firstBad) firstBad.focus();
return;
}
ticketNo.textContent = makeTicket();
form.hidden = true;
successPanel.hidden = false;
successPanel.focus && successPanel.focus();
successPanel.scrollIntoView({ behavior: "smooth", block: "center" });
});
}
if (resetBtn) {
resetBtn.addEventListener("click", function () {
form.reset();
["name", "phone", "address"].forEach(function (n) { setError(n, ""); });
successPanel.hidden = true;
form.hidden = false;
form.elements.name.focus();
});
}
/* ---------- Before / After slider ---------- */
var viewer = document.getElementById("baViewer");
var divider = document.getElementById("baDivider");
var handle = document.getElementById("baHandle");
var afterPanel = viewer ? viewer.querySelector(".ba__panel--after") : null;
var dragging = false;
function setSplit(pct) {
pct = Math.max(4, Math.min(96, pct));
if (afterPanel) afterPanel.style.clipPath = "inset(0 0 0 " + pct + "%)";
if (divider) divider.style.left = pct + "%";
}
function pointerToPct(clientX) {
var rect = viewer.getBoundingClientRect();
return ((clientX - rect.left) / rect.width) * 100;
}
if (viewer && divider && afterPanel) {
var start = function (e) { dragging = true; e.preventDefault(); };
var move = function (e) {
if (!dragging) return;
var x = (e.touches ? e.touches[0].clientX : e.clientX);
setSplit(pointerToPct(x));
};
var end = function () { dragging = false; };
handle.addEventListener("mousedown", start);
handle.addEventListener("touchstart", start, { passive: false });
window.addEventListener("mousemove", move);
window.addEventListener("touchmove", move, { passive: false });
window.addEventListener("mouseup", end);
window.addEventListener("touchend", end);
// click anywhere on the viewer to jump
viewer.addEventListener("click", function (e) {
if (e.target === handle) return;
setSplit(pointerToPct(e.clientX));
});
// keyboard support
handle.addEventListener("keydown", function (e) {
var cur = parseFloat(divider.style.left) || 50;
if (e.key === "ArrowLeft") { setSplit(cur - 4); e.preventDefault(); }
if (e.key === "ArrowRight") { setSplit(cur + 4); e.preventDefault(); }
});
setSplit(50);
}
/* ---------- Smooth-scroll active nav highlight (tiny enhancement) ---------- */
var navLinks = document.querySelectorAll(".nav__links a");
if (navLinks.length && "IntersectionObserver" in window) {
var map = {};
navLinks.forEach(function (a) {
var id = a.getAttribute("href").slice(1);
var sec = document.getElementById(id);
if (sec) map[id] = a;
});
var obs = new IntersectionObserver(function (entries) {
entries.forEach(function (en) {
if (en.isIntersecting && map[en.target.id]) {
navLinks.forEach(function (a) { a.style.borderColor = "transparent"; a.style.color = ""; });
map[en.target.id].style.borderColor = "var(--hv)";
map[en.target.id].style.color = "#fff";
}
});
}, { rootMargin: "-45% 0px -50% 0px" });
Object.keys(map).forEach(function (id) { obs.observe(document.getElementById(id)); });
}
})();<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Ironclad Roofing — Free Inspection</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<header class="nav">
<div class="wrap nav__inner">
<a class="brand" href="#top">
<span class="brand__mark" aria-hidden="true">▲</span>
<span class="brand__name">IRONCLAD<small>ROOFING CO.</small></span>
</a>
<nav class="nav__links" aria-label="Primary">
<a href="#services">Services</a>
<a href="#claims">Insurance Claims</a>
<a href="#materials">Materials</a>
<a href="#reviews">Reviews</a>
</nav>
<div class="nav__cta">
<a class="phone" href="tel:+15558007663">
<span aria-hidden="true">☎</span> (555) 800-ROOF
</a>
<a class="btn btn--hv" href="#inspect">Free Inspection</a>
</div>
</div>
</header>
<main id="top">
<!-- HERO -->
<section class="hero">
<div class="hero__hazard" aria-hidden="true"></div>
<div class="wrap hero__inner">
<div class="hero__copy">
<span class="kicker">Licensed · Bonded · Insured — Lic #RC-44128</span>
<h1>Built to take the<br /><span class="hl">worst weather.</span></h1>
<p class="hero__lede">
Storm-damage repair and full roof replacement across the tri-county area.
Same-week inspections, honest estimates, and a warranty in writing.
</p>
<div class="hero__actions">
<a class="btn btn--hv btn--lg" href="#inspect">Book Free Inspection</a>
<a class="btn btn--ghost btn--lg" href="#claims">We handle the claim →</a>
</div>
<ul class="hero__trust">
<li><strong>1,800+</strong> roofs done</li>
<li><strong>24/7</strong> storm response</li>
<li><strong>4.9★</strong> on 612 reviews</li>
</ul>
</div>
<aside class="hero__card" aria-label="Quick estimate badge">
<span class="badge badge--orange">⚡ Storm season is here</span>
<h2>Free roof inspection</h2>
<p>No-obligation 21-point check. Drone photos of every slope sent to your phone.</p>
<ul class="checks">
<li>Shingle & flashing assessment</li>
<li>Leak & moisture detection</li>
<li>Hail / wind damage report</li>
</ul>
<a class="btn btn--steel btn--block" href="#inspect">Get my report</a>
</aside>
</div>
</section>
<!-- SERVICES -->
<section id="services" class="section">
<div class="wrap">
<header class="section__head">
<span class="eyebrow">What we do</span>
<h2>Roofing services, done right the first time</h2>
</header>
<div class="grid grid--4">
<article class="card svc">
<span class="svc__ico" aria-hidden="true">🔧</span>
<h3>Roof Repair</h3>
<p>Leaks, missing shingles, popped nails and flashing fixes — most jobs done in a day.</p>
<span class="tag">From $385</span>
</article>
<article class="card svc">
<span class="svc__ico" aria-hidden="true">🏠</span>
<h3>Full Replacement</h3>
<p>Tear-off, deck repair and a brand-new system with a manufacturer-backed warranty.</p>
<span class="tag">Financing avail.</span>
</article>
<article class="card svc">
<span class="svc__ico" aria-hidden="true">⛈️</span>
<h3>Storm Damage</h3>
<p>Emergency tarp-up, hail and wind inspection, and full insurance documentation.</p>
<span class="tag tag--orange">24/7 response</span>
</article>
<article class="card svc">
<span class="svc__ico" aria-hidden="true">🌧️</span>
<h3>Gutters</h3>
<p>Seamless aluminum gutters, leaf guards and downspout re-routing to protect the foundation.</p>
<span class="tag">Seamless</span>
</article>
</div>
</div>
</section>
<!-- INSURANCE CLAIMS -->
<section id="claims" class="section section--steel">
<div class="wrap claims">
<div class="claims__copy">
<span class="eyebrow eyebrow--hv">Storm hit? We've got you.</span>
<h2>We handle the insurance claim, start to finish</h2>
<p>
Filing for storm damage is a headache. Our claims team meets your adjuster on the roof,
documents every shingle, and fights for full coverage — you usually just pay your
deductible.
</p>
<ol class="steps">
<li><span>1</span> Free damage inspection + drone photo report</li>
<li><span>2</span> We file & document the claim with your carrier</li>
<li><span>3</span> Meet the adjuster on-site for the assessment</li>
<li><span>4</span> Approved & installed — most jobs in under 3 weeks</li>
</ol>
<a class="btn btn--hv" href="#inspect">Start my claim</a>
</div>
<aside class="claims__panel">
<h3>Carriers we work with daily</h3>
<ul class="carriers">
<li>State Farm</li>
<li>Allstate</li>
<li>Farmers</li>
<li>USAA</li>
<li>Liberty Mutual</li>
<li>Nationwide</li>
</ul>
<p class="claims__note">
⚠ You choose your contractor — not the insurance company. Get a second opinion before
you sign anything.
</p>
</aside>
</div>
</section>
<!-- MATERIALS / WARRANTY -->
<section id="materials" class="section">
<div class="wrap">
<header class="section__head">
<span class="eyebrow">Materials & warranty</span>
<h2>Pick the system that fits your home</h2>
</header>
<div class="grid grid--3">
<article class="card mat">
<h3>Architectural Shingle</h3>
<p class="mat__price">$$ · Most popular</p>
<ul>
<li>30-year shingles, 130 mph wind rating</li>
<li>Algae-resistant granules</li>
<li class="warr">25-yr workmanship warranty</li>
</ul>
</article>
<article class="card mat mat--feature">
<span class="ribbon">Best value</span>
<h3>Impact-Resistant</h3>
<p class="mat__price">$$$ · Class 4 rated</p>
<ul>
<li>Class 4 hail-impact shingles</li>
<li>Often lowers your insurance premium</li>
<li class="warr">Lifetime ltd. + 50-yr non-prorated</li>
</ul>
</article>
<article class="card mat">
<h3>Standing-Seam Metal</h3>
<p class="mat__price">$$$$ · Premium</p>
<ul>
<li>24-gauge steel panels, 40+ yr lifespan</li>
<li>Energy-reflective finish</li>
<li class="warr">40-yr paint & finish warranty</li>
</ul>
</article>
</div>
</div>
</section>
<!-- BEFORE / AFTER -->
<section class="section section--concrete">
<div class="wrap ba">
<header class="section__head section__head--left">
<span class="eyebrow">Recent work</span>
<h2>Before & after on Maple Ridge Dr.</h2>
<p class="ba__sub">Hail-damaged 3-tab roof replaced with Class 4 impact shingles in 2 days.</p>
</header>
<div class="ba__viewer" id="baViewer">
<div class="ba__panel ba__panel--before">
<span class="ba__label">Before</span>
<div class="ba__art ba__art--before" aria-hidden="true"></div>
</div>
<div class="ba__panel ba__panel--after">
<span class="ba__label ba__label--after">After</span>
<div class="ba__art ba__art--after" aria-hidden="true"></div>
</div>
<div class="ba__divider" id="baDivider" role="separator" aria-label="Drag to compare before and after">
<button class="ba__handle" id="baHandle" type="button" aria-label="Drag to reveal after photo">⇄</button>
</div>
</div>
</div>
</section>
<!-- REVIEWS -->
<section id="reviews" class="section">
<div class="wrap">
<header class="section__head">
<span class="eyebrow">What homeowners say</span>
<h2>4.9 out of 5 across 612 verified reviews</h2>
</header>
<div class="grid grid--3">
<figure class="card review">
<div class="stars" aria-label="5 out of 5 stars">★★★★★</div>
<blockquote>Storm took half our shingles. Ironclad tarped it the same night and had a new roof on in two weeks. Insurance covered everything but the deductible.</blockquote>
<figcaption><strong>Dana Whitfield</strong> · Cedar Park, TX</figcaption>
</figure>
<figure class="card review">
<div class="stars" aria-label="5 out of 5 stars">★★★★★</div>
<blockquote>The drone report showed me exactly what was wrong. No upsell, no pressure. Crew cleaned up so well I couldn't find a single nail in the yard.</blockquote>
<figcaption><strong>Marcus Lindqvist</strong> · Round Rock, TX</figcaption>
</figure>
<figure class="card review">
<div class="stars" aria-label="5 out of 5 stars">★★★★★</div>
<blockquote>Got three quotes — Ironclad was the only one that met the adjuster on the roof. Made the whole claim painless. Highly recommend.</blockquote>
<figcaption><strong>Priya Raman</strong> · Pflugerville, TX</figcaption>
</figure>
</div>
</div>
</section>
<!-- INSPECTION FORM -->
<section id="inspect" class="section section--steel">
<div class="wrap inspect">
<div class="inspect__copy">
<span class="eyebrow eyebrow--hv">No cost, no obligation</span>
<h2>Book your free roof inspection</h2>
<p>Tell us where the roof is and a coordinator will call within one business day to lock in a time. Storm-damage requests get same-day priority.</p>
<ul class="inspect__perks">
<li>✓ 21-point inspection & drone photos</li>
<li>✓ Written estimate, no surprises</li>
<li>✓ Insurance claim guidance included</li>
</ul>
</div>
<form class="card form" id="inspectForm" novalidate>
<div class="field">
<label for="name">Full name</label>
<input id="name" name="name" type="text" autocomplete="name" placeholder="Jamie Carter" required />
<small class="err" data-for="name"></small>
</div>
<div class="field">
<label for="phone">Phone</label>
<input id="phone" name="phone" type="tel" autocomplete="tel" inputmode="tel" placeholder="(555) 123-4567" required />
<small class="err" data-for="phone"></small>
</div>
<div class="field">
<label for="address">Property address</label>
<input id="address" name="address" type="text" autocomplete="street-address" placeholder="412 Maple Ridge Dr, Cedar Park" required />
<small class="err" data-for="address"></small>
</div>
<div class="field">
<label for="service">What do you need?</label>
<select id="service" name="service">
<option value="inspection">General inspection</option>
<option value="storm">Storm / hail damage</option>
<option value="repair">Roof repair</option>
<option value="replace">Full replacement</option>
<option value="gutters">Gutters</option>
</select>
</div>
<label class="check">
<input type="checkbox" id="urgent" name="urgent" />
<span>This is an active leak — please prioritize</span>
</label>
<button class="btn btn--hv btn--block btn--lg" type="submit">Request my inspection</button>
<p class="form__fine">By submitting you agree to be contacted about your request.</p>
</form>
<div class="card success" id="successPanel" hidden>
<span class="success__ico" aria-hidden="true">✓</span>
<h3>Inspection requested!</h3>
<p>Your request <strong id="ticketNo">#IR-00000</strong> is in the queue. A coordinator will call you shortly.</p>
<button class="btn btn--ghost" type="button" id="resetForm">Submit another request</button>
</div>
</div>
</section>
</main>
<footer class="footer">
<div class="wrap footer__inner">
<div class="footer__brand">
<span class="brand__name">IRONCLAD<small>ROOFING CO.</small></span>
<p>Residential & commercial roofing · Lic #RC-44128 · Fully insured.</p>
</div>
<div class="footer__col">
<h4>Service area</h4>
<p>Cedar Park · Round Rock · Pflugerville · Leander · Georgetown</p>
</div>
<div class="footer__col">
<h4>Hours</h4>
<p>Mon–Fri 7a–6p · Sat 8a–2p<br />Storm line open 24/7</p>
</div>
<div class="footer__col">
<h4>Call us</h4>
<a class="phone" href="tel:+15558007663">(555) 800-ROOF</a>
</div>
</div>
<div class="wrap footer__legal">
<span>© 2026 Ironclad Roofing Co. — Illustrative demo, not a real company.</span>
</div>
</footer>
<script src="script.js"></script>
</body>
</html>Roofing Landing
A weatherproof, trades-style landing page for a residential and commercial roofing contractor. The hero leads with a hi-vis free-inspection call to action over a steel backdrop with a diagonal hazard accent, while a sticky nav keeps the phone number and quote button in reach. Sections cover the four core services — repair, full replacement, storm-damage response and gutters — plus an insurance-claim help block that walks homeowners through filing.
A materials and warranty grid lists shingle tiers with their warranty terms, followed by a before-and-after teaser and a wall of customer reviews with star ratings. The inspection request form validates name, phone and address inline, then swaps to a confirmation panel with a fake ticket number once submitted — all in vanilla JS, no libraries.
Illustrative UI only — not a real roofing service.