<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Pressure Washing Broward County | Paver Sealing & Roof Cleaning | Vold Services</title>
<meta name="description" content="Pressure washing, paver sealing and repair, and soft wash roof cleaning across Broward, Miami-Dade, and Palm Beach counties. Call or text (954) 401-3301." />
<meta name="robots" content="index, follow, max-image-preview:large" />
<link rel="canonical" href="https://voldservices.com/" />
<meta name="geo.region" content="US-FL" />
<meta name="geo.placename" content="Fort Lauderdale, Florida" />
<meta name="geo.position" content="26.1224;-80.1373" />
<meta name="ICBM" content="26.1224, -80.1373" />
<meta property="og:type" content="website" />
<meta property="og:site_name" content="Vold Services" />
<meta property="og:title" content="Pressure Washing, Paver Sealing & Roof Cleaning | Vold Services" />
<meta property="og:description" content="Pressure washing, paver sealing and repair, and roof cleaning for homes and commercial properties across South Florida. Call or text (954) 401-3301." />
<meta property="og:url" content="https://voldservices.com/" />
<meta property="og:image" content="https://voldservices.com/og-card-v2.jpg" />
<meta property="og:image:secure_url" content="https://voldservices.com/og-card-v2.jpg" />
<meta property="og:image:type" content="image/jpeg" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="og:image:alt" content="Vold Services — pressure washing, paver sealing, and roof cleaning in South Florida" />
<meta property="og:locale" content="en_US" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="Pressure Washing, Paver Sealing & Roof Cleaning | Vold Services" />
<meta name="twitter:description" content="Pressure washing, paver sealing and repair, and roof cleaning across South Florida. Call or text (954) 401-3301." />
<meta name="twitter:image" content="https://voldservices.com/og-card-v2.jpg" />
<meta name="twitter:image:alt" content="Vold Services — pressure washing, paver sealing, and roof cleaning in South Florida" />
<meta name="theme-color" content="#080808" />
<link rel="icon" href="https://voldservices.com/favicon.png" type="image/png" />
<link rel="apple-touch-icon" href="https://voldservices.com/favicon.png" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600&family=Roboto+Mono:wght@400;500&family=Teko:wght@500;600&display=swap" rel="stylesheet" />
<link rel="preload" as="image" href="https://voldservices.com/img/hero-poster-v2.jpg" />
<style>
/* True charcoal and concrete neutrals, with the logo blue reserved
for actions and small highlights rather than page backgrounds. */
:root {
--ink: #080808;
--ink-2: #10100f;
--ink-3: #181816;
--brand: #078ed1;
--brand-deep: #056ca1;
--lift: #58bdec;
--spray: #c9efff;
--bone: #f2f0e9;
--muted: #aaa89f;
--muted-dim: #77766f;
--line: rgba(242, 240, 233, 0.17);
--line-soft: rgba(242, 240, 233, 0.08);
--panel: rgba(255, 255, 255, 0.035);
--display: "Teko", Impact, sans-serif;
--body: "Manrope", system-ui, sans-serif;
--mono: "Roboto Mono", ui-monospace, monospace;
--gutter: clamp(20px, 4vw, 44px);
--wrap: 1240px;
--nav-h: 76px;
}
/* ── base ───────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }
body {
margin: 0;
background: var(--ink);
color: var(--bone);
font-family: var(--body);
font-size: 16px;
line-height: 1.65;
overflow-x: hidden;
-webkit-font-smoothing: antialiased;
}
img, video { max-width: 100%; display: block; }
a { color: inherit; }
:focus-visible {
outline: 2px solid var(--lift);
outline-offset: 3px;
border-radius: 2px;
}
.skip-link {
position: absolute;
left: 12px;
top: -60px;
z-index: 200;
background: var(--brand);
color: #fff;
padding: 12px 18px;
font-family: var(--mono);
font-size: .8rem;
text-decoration: none;
transition: top .18s ease;
}
.skip-link:focus { top: 12px; }
.wrap {
width: min(var(--wrap), 100% - (var(--gutter) * 2));
margin-inline: auto;
}
/* Section rhythm. The hairline at the top of each band is the
"wand pass" — the same gesture as the before/after handle. */
.band {
position: relative;
padding: clamp(76px, 9.5vw, 132px) 0;
/* Anchor jumps clear the fixed nav instead of landing behind it. The
logo can push the bar past --nav-h on wide screens, so leave slack. */
scroll-margin-top: calc(var(--nav-h) + 24px);
}
.band::before {
content: "";
position: absolute;
inset: 0 0 auto 0;
height: 1px;
background: var(--line);
}
.band--tinted { background: linear-gradient(180deg, var(--ink-2), var(--ink)); }
.band--flush::before { display: none; }
/* ── type ───────────────────────────────────────────────────── */
.eyebrow {
font-family: var(--mono);
font-size: .74rem;
letter-spacing: .2em;
text-transform: uppercase;
color: var(--lift);
margin: 0 0 18px;
display: flex;
align-items: center;
gap: 12px;
}
.eyebrow::before {
content: "";
width: 26px;
height: 1px;
background: var(--brand);
flex: 0 0 auto;
}
h1, h2, h3, h4 {
font-family: var(--display);
font-weight: 600;
letter-spacing: -.015em;
line-height: .88;
text-transform: uppercase;
margin: 0;
text-wrap: balance;
}
h1 { font-size: clamp(4.2rem, 9.3vw, 8.4rem); }
.h2 { font-size: clamp(3.1rem, 6vw, 5.4rem); }
.h3 { font-size: clamp(1.85rem, 2.8vw, 2.35rem); letter-spacing: -.01em; }
.accent { color: var(--lift); }
.lead {
max-width: 60ch;
margin: 22px 0 0;
color: var(--muted);
font-size: clamp(1rem, 1.25vw, 1.14rem);
line-height: 1.72;
}
.lead strong { color: var(--bone); font-weight: 600; }
.section-head { max-width: 780px; }
.section-head .lead { margin-top: 20px; }
/* ── buttons ────────────────────────────────────────────────── */
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 10px;
min-height: 52px;
padding: 0 26px;
border: 1px solid transparent;
border-radius: 0;
font-family: var(--display);
font-weight: 700;
font-size: .88rem;
letter-spacing: .06em;
text-transform: uppercase;
text-decoration: none;
cursor: pointer;
white-space: nowrap;
transition: background .18s ease, border-color .18s ease, color .18s ease, transform .18s ease;
}
.btn:hover { transform: translateY(-1px); }
.btn:active { transform: translateY(0); }
.btn--primary { background: var(--brand); color: #fff; }
.btn--primary:hover { background: var(--lift); color: var(--ink); }
.btn--ghost {
border-color: rgba(242, 240, 233, .32);
color: var(--bone);
background: rgba(8, 8, 8, .4);
}
.btn--ghost:hover { border-color: var(--lift); background: rgba(7, 142, 209, .12); }
.btn--block { width: 100%; }
.btn-row {
display: flex;
flex-wrap: wrap;
gap: 14px;
margin-top: 34px;
}
/* ── nav ────────────────────────────────────────────────────── */
.nav {
position: fixed;
inset: 0 0 auto 0;
z-index: 90;
background: rgba(8, 8, 8, .2);
backdrop-filter: blur(14px);
-webkit-backdrop-filter: blur(14px);
border-bottom: 1px solid transparent;
transition: background .28s ease, border-color .28s ease;
}
.nav.is-stuck {
background: var(--ink);
border-bottom-color: var(--line);
}
/* Opaque, not near-opaque: the open menu sits over page content and any
alpha at all lets the hero read through it. */
.nav.is-open { background: var(--ink); }
.nav-inner {
display: flex;
align-items: center;
justify-content: space-between;
gap: 20px;
min-height: var(--nav-live-height, clamp(112px, 12vh, 138px));
}
.brand { display: inline-flex; align-items: center; flex: 0 0 auto; }
.brand img { width: var(--nav-live-logo, clamp(230px, 24vw, 310px)); height: auto; }
.nav-links {
position: absolute;
top: 100%;
right: var(--gutter);
display: none;
width: min(360px, calc(100vw - 40px));
flex-direction: column;
align-items: stretch;
gap: 0;
padding: 9px 20px 20px;
font-family: var(--mono);
font-size: .86rem;
letter-spacing: .06em;
background: var(--ink);
border: 1px solid var(--line);
border-top: 0;
box-shadow: 0 22px 48px rgba(0, 0, 0, .38);
}
.nav.is-open .nav-links { display: flex; }
.nav-links a {
position: relative;
color: var(--muted);
text-decoration: none;
padding: 15px 4px;
border-bottom: 1px solid var(--line-soft);
transition: color .18s ease;
}
.nav-links a:last-child { border-bottom: 0; }
.nav-links a::after {
content: "";
position: absolute;
left: 0;
bottom: 0;
width: 100%;
height: 1px;
background: var(--lift);
transform: scaleX(0);
transform-origin: left;
transition: transform .22s ease;
}
.nav-links a:hover, .nav-links a.is-current { color: var(--bone); }
.nav-links a::after { display: none; }
.nav-actions {
display: flex;
align-items: center;
justify-content: flex-end;
gap: 10px;
flex: 0 0 auto;
}
.nav-call {
display: inline-flex;
align-items: center;
gap: 9px;
background: var(--brand);
color: #fff;
font-family: var(--display);
font-weight: 700;
font-size: var(--nav-live-call-font, 1rem);
letter-spacing: .02em;
text-decoration: none;
padding: var(--nav-live-call-y, 14px) var(--nav-live-call-x, 22px);
border-radius: 0;
flex: 0 0 auto;
white-space: nowrap;
transition: background .18s ease;
}
.nav-call:hover { background: var(--lift); color: var(--ink); }
.nav-call svg {
width: var(--nav-live-icon, 18px);
height: var(--nav-live-icon, 18px);
flex: 0 0 auto;
}
.nav-toggle {
display: inline-flex;
width: 46px;
height: 46px;
padding: 0;
border: 1px solid var(--line);
background: rgba(255, 255, 255, .04);
color: var(--bone);
cursor: pointer;
border-radius: 3px;
align-items: center;
justify-content: center;
flex-direction: column;
gap: 5px;
}
.nav-toggle span {
display: block;
width: 19px;
height: 1.5px;
background: currentColor;
transition: transform .22s ease, opacity .22s ease;
}
.nav-toggle[aria-expanded="true"] span:nth-child(1) { transform: translateY(6.5px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] span:nth-child(3) { transform: translateY(-6.5px) rotate(-45deg); }
.nav-progress {
position: absolute;
left: 0;
bottom: -1px;
height: 2px;
width: 100%;
transform: scaleX(0);
transform-origin: left;
background: linear-gradient(90deg, var(--brand), var(--spray));
opacity: 0;
transition: opacity .3s ease;
}
.nav.is-stuck .nav-progress { opacity: 1; }
/* ── hero ─────────────────────────────────────────────────────
The footage and service headline are present from the first frame.
Scrolling advances the footage and stages in the supporting message.
───────────────────────────────────────────────────────────── */
.hero {
position: relative;
isolation: isolate;
height: 300vh;
height: 300svh;
scroll-margin-top: var(--nav-h);
}
.hero-sticky {
--hero-media-scale: 1.03;
--hero-scrim-opacity: .3;
--hero-cue-opacity: 1;
position: sticky;
top: 0;
display: grid;
align-items: center;
width: 100%;
height: 100vh;
height: 100svh;
min-height: 100vh;
min-height: 100svh;
padding-top: calc(var(--nav-h) + clamp(40px, 7vh, 88px));
padding-bottom: clamp(64px, 10vh, 120px);
overflow: hidden;
background: var(--ink);
}
.hero-media {
position: absolute;
inset: 0;
z-index: 0;
overflow: hidden;
background: var(--ink);
}
.hero-media video,
.hero-media img.hero-fallback {
position: absolute;
inset: 0;
display: block;
width: 100%;
height: 100%;
object-fit: cover;
object-position: center 52%;
filter: saturate(1.04) contrast(1.03) brightness(.94);
transform: scale(var(--hero-media-scale));
transform-origin: center 52%;
will-change: transform;
}
.hero-media img.hero-fallback { z-index: 0; }
.hero-media video {
z-index: 1;
opacity: 0;
pointer-events: none;
transition: opacity .18s ease-out;
}
.hero-media.is-video-ready video { opacity: 1; }
.hero-media video::-webkit-media-controls,
.hero-media video::-webkit-media-controls-panel,
.hero-media video::-webkit-media-controls-play-button,
.hero-media video::-webkit-media-controls-start-playback-button {
display: none !important;
-webkit-appearance: none;
opacity: 0;
pointer-events: none;
}
.hero-media::after {
content: "";
position: absolute;
inset: 0;
z-index: 2;
pointer-events: none;
background:
linear-gradient(90deg, rgba(8, 8, 8, .94) 0%, rgba(8, 8, 8, .62) 43%, rgba(8, 8, 8, .06) 74%),
linear-gradient(180deg, rgba(8, 8, 8, .55), transparent 28%, rgba(8, 8, 8, .38) 76%, rgba(8, 8, 8, .82));
opacity: var(--hero-scrim-opacity);
}
.hero-grain {
position: absolute;
inset: 0;
z-index: 2;
pointer-events: none;
opacity: .2;
mix-blend-mode: overlay;
background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='.5'/%3E%3C/svg%3E");
}
.hero-inner {
position: relative;
z-index: 3;
width: min(66%, 820px);
}
.hero h1 {
max-width: none;
font-size: clamp(4.2rem, 7.45vw, 7.1rem);
}
.hero-title-line {
display: block;
overflow: hidden;
white-space: nowrap;
}
.hero-title-inner {
display: block;
opacity: 1;
transform: translate3d(0, 0, 0);
will-change: transform, opacity;
}
.hero .lead { max-width: 48ch; margin-top: 26px; }
.hero-inner .eyebrow,
.hero h1,
.hero .lead { text-shadow: 0 2px 26px rgba(0, 0, 0, .7); }
.hero-eyebrow,
.hero-lead,
.hero-primary-actions {
opacity: 1;
transform: translate3d(0, 0, 0);
will-change: transform, opacity;
}
.hero-cue {
position: absolute;
z-index: 3;
left: 50%;
bottom: 26px;
transform: translateX(-50%);
display: flex;
align-items: center;
gap: 10px;
font-family: var(--mono);
font-size: .68rem;
letter-spacing: .18em;
text-transform: uppercase;
color: var(--muted-dim);
text-decoration: none;
opacity: var(--hero-cue-opacity);
transition: color .2s ease;
}
.hero-cue:hover { color: var(--spray); }
.hero-cue::after {
content: "";
width: 8px;
height: 8px;
border-right: 1px solid currentColor;
border-bottom: 1px solid currentColor;
transform: rotate(45deg) translate(-2px, -2px);
}
/* ── credential strip ───────────────────────────────────────── */
.strip {
border-block: 1px solid var(--line-soft);
background: #0d0d0c;
}
.strip-viewport { overflow: hidden; }
.strip-inner {
display: flex;
align-items: center;
padding: 17px 0;
font-family: var(--mono);
font-size: .74rem;
letter-spacing: .09em;
text-transform: uppercase;
color: var(--muted-dim);
}
.strip-group {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
gap: 14px 30px;
width: 100%;
}
.strip-group--clone { display: none; }
.strip-inner span { display: inline-flex; align-items: center; gap: 9px; }
.strip-inner span::before {
content: "";
width: 5px;
height: 5px;
border-radius: 50%;
background: var(--brand);
flex: 0 0 auto;
}
.strip-inner a { color: var(--bone); text-decoration: none; }
.strip-inner a:hover { color: var(--lift); }
@keyframes credential-ticker {
to { transform: translate3d(-50%, 0, 0); }
}
/* ── services ───────────────────────────────────────────────── */
.service-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 18px;
margin-top: 52px;
}
.service {
position: relative;
display: flex;
flex-direction: column;
padding: 32px 30px 30px;
border: 1px solid var(--line);
border-radius: 0;
background: var(--panel);
overflow: hidden;
transition: border-color .24s ease, transform .24s ease;
}
.service:hover { border-color: rgba(88, 189, 236, .44); transform: translateY(-3px); }
.service::before {
content: "";
position: absolute;
inset: 0 0 auto 0;
height: 2px;
background: var(--tint, var(--brand));
opacity: .85;
}
.service--wash { --tint: var(--brand); }
.service--seal { --tint: var(--brand); }
.service--repair { --tint: var(--brand); }
.service--roof { --tint: var(--brand); }
.service-icon {
width: 42px;
height: 42px;
margin-bottom: 22px;
color: var(--lift);
}
.service--seal .service-icon,
.service--repair .service-icon,
.service--roof .service-icon { color: var(--lift); }
.service-icon svg { width: 100%; height: 100%; }
.service h3 { margin-bottom: 12px; }
.service p {
margin: 0;
color: var(--muted);
font-size: .96rem;
line-height: 1.7;
}
.service-list {
margin: 22px 0 0;
padding: 20px 0 0;
border-top: 1px solid var(--line-soft);
list-style: none;
display: grid;
gap: 9px;
font-family: var(--mono);
font-size: .78rem;
color: var(--muted-dim);
}
.service-list li { display: flex; gap: 10px; align-items: flex-start; }
.service-list li::before { content: "—"; color: var(--brand); flex: 0 0 auto; }
/* ─────────────────────────────────────────────────────────────
Signature: the wand line. A drag reveals the cleaned surface
behind a lit seam — the same edge you see on a real job.
A range input drives it so keyboard and screen readers work.
───────────────────────────────────────────────────────────── */
.results-head { max-width: 780px; }
.results-head .lead { max-width: 56ch; }
.wand-comparisons {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 20px;
margin-top: 50px;
}
.wand-project {
margin: 0;
border: 1px solid var(--line);
background: var(--panel);
overflow: hidden;
}
.wand {
--pos: 50%;
position: relative;
/* Matches the source photos (746×829) so nothing important is cropped.
width must be definite, or the max-height resolves through the ratio
and shrinks the box horizontally instead of cropping it. */
width: 100%;
aspect-ratio: 746 / 829;
max-height: min(76vh, 700px);
border: 1px solid var(--line);
border-radius: 4px;
overflow: hidden;
background: var(--ink-2);
touch-action: pan-y;
}
.wand-layer { position: absolute; inset: 0; }
.wand-layer img { width: 100%; height: 100%; object-fit: cover; }
/* Before stays on the left; the cleaned surface occupies the right. */
.wand-layer--after { clip-path: inset(0 0 0 var(--pos)); }
.wand-seam {
position: absolute;
top: 0;
bottom: 0;
left: var(--pos);
width: 2px;
margin-left: -1px;
background: linear-gradient(180deg, rgba(184, 236, 255, .35), var(--spray) 42%, rgba(184, 236, 255, .35));
box-shadow: 0 0 18px 3px rgba(184, 236, 255, .5);
pointer-events: none;
}
/* Fan of spray thrown just ahead of the seam. */
.wand-seam::before {
content: "";
position: absolute;
top: 0;
bottom: 0;
left: 1px;
width: 66px;
background: linear-gradient(90deg, rgba(184, 236, 255, .3), transparent 78%);
pointer-events: none;
}
.wand-handle {
position: absolute;
top: 50%;
left: var(--pos);
transform: translate(-50%, -50%);
width: 52px;
height: 52px;
border-radius: 50%;
background: var(--spray);
color: var(--ink);
display: grid;
place-items: center;
box-shadow: 0 6px 26px rgba(0, 0, 0, .48), 0 0 0 1px rgba(255, 255, 255, .5) inset;
pointer-events: none;
}
.wand-handle svg { width: 24px; height: 24px; }
.wand-range {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
margin: 0;
opacity: 0;
cursor: ew-resize;
-webkit-appearance: none;
appearance: none;
background: transparent;
}
.wand-range::-webkit-slider-thumb {
-webkit-appearance: none;
width: 58px;
height: 100%;
cursor: ew-resize;
}
.wand-range::-moz-range-thumb {
width: 58px;
height: 100%;
border: 0;
border-radius: 0;
cursor: ew-resize;
}
.wand-range:focus-visible ~ .wand-handle {
outline: 2px solid var(--lift);
outline-offset: 4px;
}
.wand-tag {
position: absolute;
top: 14px;
z-index: 2;
font-family: var(--mono);
font-size: .7rem;
letter-spacing: .16em;
text-transform: uppercase;
padding: 6px 12px;
border-radius: 999px;
background: rgba(8, 8, 8, .82);
backdrop-filter: blur(6px);
pointer-events: none;
}
.wand-tag--before { left: 14px; color: var(--muted); border: 1px solid var(--line); }
.wand-tag--after { right: 14px; color: var(--spray); border: 1px solid rgba(184, 236, 255, .34); }
.wand-project .wand {
max-height: none;
border: 0;
border-radius: 0;
}
/* ── work gallery ───────────────────────────────────────────── */
.work-heading {
display: flex;
align-items: flex-end;
justify-content: space-between;
gap: 32px;
}
.work-instagram {
display: inline-flex;
align-items: center;
gap: 9px;
flex: 0 0 auto;
margin-bottom: 7px;
padding-bottom: 5px;
border-bottom: 1px solid rgba(88, 189, 236, .42);
color: var(--lift);
font-family: var(--mono);
font-size: .75rem;
letter-spacing: .08em;
text-decoration: none;
text-transform: uppercase;
}
.work-instagram svg { width: 15px; height: 15px; }
.work-instagram:hover { color: var(--bone); border-bottom-color: var(--bone); }
.work-grid {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 14px;
margin-top: 50px;
}
.work-tile {
position: relative;
aspect-ratio: 746 / 829;
padding: 0;
border: 1px solid var(--line-soft);
border-radius: 4px;
overflow: hidden;
background: var(--ink-2);
cursor: zoom-in;
color: inherit;
text-align: left;
display: block;
}
.work-tile img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform .5s ease;
}
.work-tile:hover img { transform: scale(1.05); }
.work-tile::after {
content: "";
position: absolute;
inset: 0;
background: linear-gradient(180deg, transparent 42%, rgba(8, 8, 8, .9));
}
.work-cap {
position: absolute;
left: 18px;
bottom: 15px;
z-index: 2;
}
.work-cap b {
display: block;
font-family: var(--display);
font-weight: 700;
font-size: 1rem;
letter-spacing: -.01em;
}
.work-cap span {
display: block;
font-family: var(--mono);
font-size: .7rem;
letter-spacing: .08em;
color: var(--lift);
text-transform: uppercase;
margin-top: 2px;
}
/* ── service areas ──────────────────────────────────────────── */
.areas-grid {
display: grid;
grid-template-columns: 1.35fr 1fr 1fr;
gap: 20px;
margin-top: 50px;
align-items: start;
}
.area {
padding: 30px 28px;
border: 1px solid var(--line);
border-radius: 4px;
background: linear-gradient(180deg, var(--panel), transparent);
}
.area--primary { border-color: rgba(7, 142, 209, .42); }
.area h3 { font-size: 1.24rem; margin-bottom: 6px; }
.area-note {
font-family: var(--mono);
font-size: .72rem;
letter-spacing: .08em;
text-transform: uppercase;
color: var(--lift);
margin: 0 0 18px;
}
.area ul {
margin: 0;
padding: 0;
list-style: none;
display: flex;
flex-wrap: wrap;
gap: 6px 8px;
font-size: .87rem;
color: var(--muted);
}
.area li::after { content: " ·"; color: var(--muted-dim); }
.area li:last-child::after { content: ""; }
/* ── reviews ────────────────────────────────────────────────── */
.reviews {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 18px;
margin-top: 50px;
}
.review {
margin: 0;
padding: 30px 28px;
border: 1px solid var(--line);
border-radius: 4px;
background: var(--panel);
display: flex;
flex-direction: column;
}
.review blockquote {
margin: 0 0 22px;
font-size: 1rem;
line-height: 1.72;
color: var(--bone);
}
.review figcaption {
margin-top: auto;
padding-top: 18px;
border-top: 1px solid var(--line-soft);
font-family: var(--mono);
font-size: .76rem;
color: var(--muted-dim);
letter-spacing: .04em;
}
.stars { color: var(--lift); letter-spacing: .18em; margin-bottom: 14px; font-size: .84rem; }
.placeholder-note {
margin-top: 22px;
font-family: var(--mono);
font-size: .74rem;
color: var(--muted-dim);
border-left: 2px solid var(--brand);
padding-left: 14px;
}
/* ── quote ──────────────────────────────────────────────────── */
.quote-grid {
display: grid;
grid-template-columns: .82fr 1.18fr;
gap: 26px;
margin-top: 50px;
align-items: start;
}
.quote-side, .quote-form, .form-success {
border: 1px solid var(--line);
border-radius: 4px;
padding: 32px 30px;
background: var(--panel);
}
.quote-side { background: linear-gradient(180deg, rgba(7, 142, 209, .11), var(--panel) 46%); }
.quote-row { padding: 20px 0; border-top: 1px solid var(--line-soft); }
.quote-row:first-of-type { border-top: 0; padding-top: 0; }
.quote-label {
font-family: var(--mono);
font-size: .72rem;
letter-spacing: .14em;
text-transform: uppercase;
color: var(--lift);
margin-bottom: 7px;
}
.quote-value { color: var(--bone); text-decoration: none; font-size: .97rem; }
a.quote-value:hover { color: var(--lift); }
.quote-phone {
font-family: var(--display);
font-weight: 800;
font-size: clamp(1.6rem, 3vw, 2rem);
letter-spacing: -.02em;
text-decoration: none;
display: inline-block;
}
.quote-phone:hover { color: var(--lift); }
.social-links {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
.social-link {
display: inline-flex;
align-items: center;
justify-content: center;
width: 44px;
height: 44px;
border: 1px solid var(--line);
border-radius: 3px;
color: var(--muted);
background: rgba(8, 8, 8, .28);
text-decoration: none;
transition: color .18s ease, border-color .18s ease, background .18s ease, transform .18s ease;
}
.social-link svg { width: 19px; height: 19px; }
.social-link:hover {
color: #fff;
border-color: var(--brand);
background: var(--brand);
transform: translateY(-2px);
}
.quote-form-wrap { min-width: 0; }
.quote-form { display: grid; gap: 18px; }
.quote-form[hidden], .form-success[hidden], .form-error[hidden] { display: none; }
.field-row {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 18px;
}
.field label {
display: block;
margin-bottom: 7px;
font-family: var(--mono);
font-size: .72rem;
letter-spacing: .1em;
text-transform: uppercase;
color: var(--muted-dim);
}
.field input, .field select, .field textarea {
width: 100%;
padding: 13px 14px;
border: 1px solid var(--line);
border-radius: 3px;
background: rgba(8, 8, 8, .64);
color: var(--bone);
font: inherit;
font-size: .95rem;
transition: border-color .18s ease, background .18s ease;
}
.field input::placeholder, .field textarea::placeholder { color: var(--muted-dim); }
.field input:focus, .field select:focus, .field textarea:focus {
outline: none;
border-color: var(--lift);
background: rgba(7, 142, 209, .08);
}
.field select option { background: var(--ink-2); color: var(--bone); }
.field textarea { min-height: 122px; resize: vertical; }
.field input.photo-input {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
.field .photo-picker {
display: flex;
align-items: center;
justify-content: space-between;
gap: 14px;
min-height: 54px;
margin: 0;
padding: 8px 10px 8px 8px;
border: 1px solid var(--line);
border-radius: 3px;
background: rgba(8, 8, 8, .64);
color: var(--muted);
font-family: inherit;
font-size: .78rem;
letter-spacing: 0;
text-transform: none;
cursor: pointer;
transition: border-color .18s ease, background .18s ease;
}
.photo-picker__action {
display: inline-grid;
place-items: center;
min-height: 38px;
padding: 0 15px;
border: 1px solid var(--line);
border-radius: 2px;
background: rgba(7, 142, 209, .14);
color: var(--bone);
font-family: var(--mono);
font-size: .72rem;
letter-spacing: .08em;
text-transform: uppercase;
transition: border-color .18s ease, background .18s ease, color .18s ease;
}
.photo-picker__note { text-align: right; }
.field .photo-picker:hover,
.field .photo-input:focus-visible + .photo-picker {
border-color: var(--lift);
background: rgba(7, 142, 209, .08);
}
.field .photo-picker:hover .photo-picker__action,
.field .photo-input:focus-visible + .photo-picker .photo-picker__action {
border-color: var(--lift);
background: var(--brand);
color: #fff;
}
.field .photo-input:focus-visible + .photo-picker {
outline: 2px solid var(--lift);
outline-offset: 2px;
}
.field-help, .photo-status {
margin: 7px 0 0;
font-family: var(--mono);
font-size: .7rem;
line-height: 1.55;
color: var(--muted-dim);
}
.photo-status:not(:empty) { color: var(--muted); }
.photo-list {
display: grid;
gap: 6px;
margin: 9px 0 0;
padding: 0;
list-style: none;
}
.photo-list[hidden] { display: none; }
.photo-item {
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
align-items: center;
gap: 12px;
padding: 9px 10px 9px 12px;
border-left: 2px solid var(--brand);
border-radius: 2px;
background: rgba(255, 255, 255, .035);
}
.photo-file { min-width: 0; }
.photo-name {
display: block;
overflow: hidden;
color: var(--bone);
font-size: .82rem;
text-overflow: ellipsis;
white-space: nowrap;
}
.photo-size {
display: block;
margin-top: 2px;
color: var(--muted-dim);
font-family: var(--mono);
font-size: .65rem;
letter-spacing: .06em;
text-transform: uppercase;
}
.photo-remove {
padding: 6px 8px;
border: 1px solid transparent;
border-radius: 2px;
background: transparent;
color: var(--muted);
font-family: var(--mono);
font-size: .66rem;
letter-spacing: .07em;
text-transform: uppercase;
cursor: pointer;
}
.photo-remove:hover, .photo-remove:focus-visible {
border-color: rgba(255, 132, 111, .55);
color: #ffd8d1;
outline: none;
}
.form-note {
font-family: var(--mono);
font-size: .72rem;
color: var(--muted-dim);
margin: 0;
}
.form-error {
padding: 12px 14px;
border: 1px solid rgba(255, 132, 111, .55);
border-radius: 3px;
background: rgba(141, 42, 26, .18);
color: #ffd8d1;
font-size: .84rem;
line-height: 1.55;
}
.quote-form[aria-busy="true"] .btn { cursor: wait; }
.quote-form .btn:disabled {
opacity: .68;
transform: none;
}
.form-success {
min-height: 410px;
align-items: flex-start;
justify-content: center;
background:
linear-gradient(135deg, rgba(7, 142, 209, .18), transparent 58%),
var(--panel);
}
.form-success:not([hidden]) { display: flex; }
.success-mark {
display: grid;
place-items: center;
width: 54px;
height: 54px;
margin-bottom: 26px;
border: 1px solid rgba(88, 189, 236, .6);
border-radius: 50%;
color: var(--lift);
background: rgba(7, 142, 209, .14);
}
.success-mark svg { width: 25px; height: 25px; }
.form-success .eyebrow { margin-bottom: 17px; }
.form-success h3 { font-size: clamp(2.3rem, 5vw, 4rem); }
.form-success p {
max-width: 46ch;
margin: 20px 0 0;
color: var(--muted);
}
.form-success .quote-value {
display: inline-block;
margin-top: 22px;
color: var(--lift);
font-family: var(--mono);
font-size: .76rem;
}
/* ── footer ─────────────────────────────────────────────────── */
.footer {
border-top: 1px solid var(--line);
padding: 52px 0 40px;
background: var(--ink-2);
}
.footer-inner {
display: grid;
grid-template-columns: 1.4fr 1fr 1fr;
gap: 34px;
}
.footer img { width: 168px; margin-bottom: 18px; }
.footer p { margin: 0; color: var(--muted-dim); font-size: .9rem; max-width: 42ch; }
.footer .social-links { margin-top: 22px; }
.footer .social-link { width: 38px; height: 38px; }
.footer .social-link svg { width: 17px; height: 17px; }
.footer h4 {
font-size: .8rem;
font-family: var(--mono);
font-weight: 500;
letter-spacing: .14em;
text-transform: uppercase;
color: var(--lift);
margin-bottom: 14px;
}
.footer ul { margin: 0; padding: 0; list-style: none; display: grid; gap: 9px; }
.footer ul a { color: var(--muted); text-decoration: none; font-size: .9rem; }
.footer ul a:hover { color: var(--bone); }
.footer-base {
margin-top: 42px;
padding-top: 22px;
border-top: 1px solid var(--line-soft);
display: flex;
flex-wrap: wrap;
gap: 12px 26px;
justify-content: space-between;
font-family: var(--mono);
font-size: .74rem;
color: var(--muted-dim);
}
/* ── mobile sticky CTA ──────────────────────────────────────── */
.sticky-cta { display: none; }
/* ── reveal ─────────────────────────────────────────────────── */
.reveal {
opacity: 0;
transform: translateY(22px);
transition: opacity .6s ease, transform .7s cubic-bezier(.2,.7,.3,1);
}
.reveal.is-in { opacity: 1; transform: none; }
/* ── lightbox ───────────────────────────────────────────────── */
.lightbox {
position: fixed;
inset: 0;
z-index: 200;
display: grid;
place-items: center;
padding: 26px;
background: rgba(8, 8, 8, .94);
backdrop-filter: blur(12px);
opacity: 0;
visibility: hidden;
transition: opacity .22s ease, visibility .22s ease;
}
.lightbox.is-open { opacity: 1; visibility: visible; }
.lightbox img { max-width: 100%; max-height: 88vh; border-radius: 4px; }
.lightbox-close {
position: absolute;
top: 18px;
right: 18px;
width: 46px;
height: 46px;
border: 1px solid var(--line);
border-radius: 3px;
background: rgba(20, 20, 20, .8);
color: var(--bone);
font-size: 1.7rem;
line-height: 1;
cursor: pointer;
}
body.is-locked { overflow: hidden; }
/* ── responsive ─────────────────────────────────────────────── */
@media (max-width: 1060px) {
.service-grid, .reviews { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.areas-grid { grid-template-columns: 1fr 1fr; }
.areas-grid > :first-child { grid-column: span 2; }
.quote-grid { grid-template-columns: 1fr; }
.footer-inner { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 900px) {
.hero-inner { width: min(62%, 610px); }
.work-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.wand-comparisons { grid-template-columns: 1fr; max-width: 680px; }
/* Bottom bar takes over from the nav's call button on phones. */
.sticky-cta {
position: fixed;
left: 0;
right: 0;
bottom: 0;
z-index: 95;
display: flex;
align-items: stretch;
gap: 10px;
padding: 11px var(--gutter) calc(11px + env(safe-area-inset-bottom));
background: rgba(8, 8, 8, .97);
backdrop-filter: blur(16px);
border-top: 1px solid var(--line);
box-shadow: 0 -14px 40px rgba(0, 0, 0, .46);
transform: translateY(110%);
transition: transform .32s cubic-bezier(.4,0,.2,1);
}
.sticky-cta.is-up { transform: none; }
.sticky-cta .btn { flex: 1 1 0; min-height: 50px; padding: 0 14px; font-size: .84rem; }
.sticky-cta .btn--primary { flex: 1.35 1 0; }
body { padding-bottom: 78px; }
}
@media (max-width: 720px) {
.nav-actions .nav-call { display: none; }
.nav-links { left: 0; right: 0; width: auto; border-inline: 0; }
.service-grid, .reviews, .work-grid,
.areas-grid, .field-row, .footer-inner {
grid-template-columns: 1fr;
}
.areas-grid > :first-child { grid-column: auto; }
.work-heading { align-items: flex-start; flex-direction: column; gap: 17px; }
.work-instagram { margin-bottom: 0; }
.work-grid { margin-top: 34px; }
.strip-inner {
width: max-content;
max-width: none;
margin-inline: 0;
flex-wrap: nowrap;
align-items: center;
justify-content: flex-start;
gap: 0;
padding-block: 15px;
animation: credential-ticker 24s linear infinite;
will-change: transform;
}
.strip-group {
width: max-content;
flex: 0 0 auto;
flex-wrap: nowrap;
justify-content: flex-start;
gap: 32px;
padding: 0 32px 0 var(--gutter);
}
.strip-group--clone { display: flex; }
.strip-inner span { width: auto; white-space: nowrap; }
.strip-viewport:hover .strip-inner { animation-play-state: paused; }
.btn-row .btn { width: 100%; }
.hero { height: 300vh; height: 300svh; }
.hero-sticky {
align-items: start;
padding-top: calc(var(--nav-h) + 54px);
padding-bottom: 24px;
}
.hero-inner { width: 100%; }
.hero h1 { font-size: clamp(2.7rem, 12.25vw, 3.45rem); }
.hero .lead { margin-top: 19px; font-size: .94rem; line-height: 1.62; }
.hero .eyebrow { margin-bottom: 14px; font-size: .65rem; }
.hero .hero-primary-actions { margin-top: 22px; }
.hero .hero-primary-actions .btn { width: auto; min-height: 48px; padding-inline: 18px; }
.hero .hero-primary-actions .btn--ghost { display: none; }
.hero-media video,
.hero-media img.hero-fallback {
object-position: center 50%;
filter: saturate(1.02) contrast(1.03) brightness(.9);
}
.hero-cue { left: 20px; bottom: 26px; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
html { scroll-behavior: auto; }
.hero { height: auto; }
.hero-sticky {
position: relative;
--hero-cue-opacity: 1;
--hero-media-scale: 1;
--hero-scrim-opacity: .9;
min-height: 100vh;
min-height: 100svh;
}
.hero-media video,
.hero-media img.hero-fallback { transform: none; will-change: auto; }
.hero-title-inner,
.hero-eyebrow,
.hero-lead,
.hero-primary-actions { opacity: 1 !important; transform: none !important; will-change: auto; }
.reveal { opacity: 1; transform: none; transition: none; }
.nav, .sticky-cta, .work-tile img, .btn, .service { transition: none; }
.work-tile:hover img, .btn:hover, .service:hover { transform: none; }
}
@media (max-width: 720px) and (prefers-reduced-motion: reduce) {
.strip-viewport { overflow-x: auto; scrollbar-width: none; }
.strip-viewport::-webkit-scrollbar { display: none; }
.strip-inner { animation: none; will-change: auto; }
.strip-group--clone { display: none; }
}
</style>
</head>
<body>
<a class="skip-link" href="#main">Skip to content</a>
<header class="nav" id="nav">
<div class="wrap nav-inner">
<a class="brand" href="#top" aria-label="Vold Services home">
<img src="https://voldservices.com/logo.png" alt="Vold Services" width="188" height="97" />
</a>
<div class="nav-actions">
<a class="nav-call" href="tel:+19544013301">
<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M6.6 10.8c1.4 2.7 3.6 4.9 6.3 6.3l2.1-2.1c.3-.3.8-.4 1.1-.2 1.1.4 2.3.6 3.5.6.5 0 .9.4.9.9V20c0 .5-.4.9-.9.9C10.7 20.9 3.1 13.3 3.1 4c0-.5.4-.9.9-.9h3.7c.5 0 .9.4.9.9 0 1.2.2 2.4.6 3.5.1.4.1.8-.2 1.1L6.6 10.8z"/></svg>
(954) 401-3301
</a>
<button class="nav-toggle" type="button" aria-label="Open menu" aria-controls="nav-links" aria-expanded="false">
<span></span><span></span><span></span>
</button>
</div>
<nav class="nav-links" id="nav-links" aria-label="Primary">
<a href="#services">Services</a>
<a href="#results">Results</a>
<a href="#work">Recent Work</a>
<a href="#areas">Service Areas</a>
<a href="#reviews">Reviews</a>
<a href="#quote">Contact</a>
</nav>
</div>
<div class="nav-progress" id="nav-progress" aria-hidden="true"></div>
</header>
<main id="main">
<!-- ── hero ────────────────────────────────────────────────── -->
<section class="hero" id="top">
<div class="hero-sticky" id="hero-sticky">
<div class="hero-media">
<img class="hero-fallback" src="https://voldservices.com/img/hero-scrub-poster.jpg" alt="" aria-hidden="true" />
<video
id="hero-video"
data-desktop-src="/hero-scrub.mp4"
data-mobile-src="/hero-scrub-mobile.mp4"
poster="https://voldservices.com/img/hero-scrub-poster.jpg"
muted playsinline webkit-playsinline preload="auto"
controlslist="nodownload nofullscreen noremoteplayback"
disablepictureinpicture disableremoteplayback
aria-hidden="true" tabindex="-1"></video>
</div>
<div class="hero-grain" aria-hidden="true"></div>
<div class="wrap">
<div class="hero-inner">
<p class="eyebrow hero-eyebrow">Broward · Miami-Dade · Palm Beach</p>
<h1>
<span class="hero-title-line"><span class="hero-title-inner">Pressure washing.</span></span>
<span class="hero-title-line"><span class="hero-title-inner">Paver sealing.</span></span>
<span class="hero-title-line accent"><span class="hero-title-inner">Roof cleaning.</span></span>
</h1>
<p class="lead hero-lead">
<strong>Exterior cleaning and sealing</strong> for South Florida homes and commercial properties. Boost your property value, restore curb appeal and protect your investment with VOLD Services.
</p>
<div class="btn-row hero-primary-actions" id="hero-actions" aria-hidden="true" inert>
<a class="btn btn--primary" href="#quote">Request an estimate</a>
<a class="btn btn--ghost" href="tel:+19544013301">Call (954) 401-3301</a>
</div>
</div>
</div>
<a class="hero-cue" href="#services">Scroll</a>
</div>
</section>
<!-- ── credential strip ────────────────────────────────────── -->
<div class="strip">
<div class="strip-viewport">
<div class="wrap strip-inner">
<div class="strip-group">
<span>South Florida homes & businesses</span>
<span>Licensed & insured</span>
<span>Free estimates</span>
</div>
<div class="strip-group strip-group--clone" aria-hidden="true">
<span>South Florida homes & businesses</span>
<span>Licensed & insured</span>
<span>Free estimates</span>
</div>
</div>
</div>
</div>
<!-- ── services ────────────────────────────────────────────── -->
<section class="band" id="services">
<div class="wrap">
<div class="section-head reveal">
<h2 class="h2">Residential & commercial services offered</h2>
<p class="lead">
Concrete, pavers, paint, tile, and shingles do not get cleaned the same way.
We choose the pressure and treatment for the material, then protect the areas around it.
</p>
</div>
<div class="service-grid">
<article class="service service--wash reveal">
<div class="service-icon" aria-hidden="true">
<svg viewBox="0 0 48 48" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M30 12h10l4 6-4 6H30z"/><path d="M30 18h-8v-4a3 3 0 0 0-3-3h-3"/>
<path d="M22 18v18a4 4 0 0 1-4 4h-2a4 4 0 0 1-4-4V18z"/>
<path d="M8 26h-3M8 32h-5M8 20h-4"/>
</svg>
</div>
<h3 class="h3">Pressure washing</h3>
<p>
We use surface cleaners on concrete and lower pressure on painted or porous areas.
That clears algae, dirt, and tire marks without treating every surface like a driveway.
</p>
<ul class="service-list">
<li>Driveways, walkways, sidewalks</li>
<li>Pool decks, patios, lanais</li>
<li>House and building washes</li>
<li>Fences, screen enclosures, gutters</li>
<li>Dumpster pads & storefronts</li>
</ul>
</article>
<article class="service service--seal reveal">
<div class="service-icon" aria-hidden="true">
<svg viewBox="0 0 48 48" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M24 6s10 11 10 17a10 10 0 0 1-20 0c0-6 10-17 10-17z"/>
<path d="M6 40h36M6 44h36"/>
</svg>
</div>
<h3 class="h3">Paver sealing</h3>
<p>
Good sealing starts with clean, dry pavers and full joints. We wash the surface,
replace missing joint sand, and apply the finish you choose once the pavers are ready.
</p>
<ul class="service-list">
<li>Deep clean & efflorescence removal</li>
<li>Joint sand replacement</li>
<li>Wet-look, semi-gloss, or natural finishes</li>
<li>Driveways, pool decks, walkways</li>
<li>Resealing for worn pavers</li>
</ul>
</article>
<article class="service service--repair reveal">
<div class="service-icon" aria-hidden="true">
<svg viewBox="0 0 48 48" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect x="5" y="7" width="17" height="12" rx="1"/>
<rect x="26" y="7" width="17" height="12" rx="1"/>
<rect x="5" y="24" width="17" height="12" rx="1"/>
<path d="M27 34h16M35 24v18M30 29l5-5 5 5"/>
</svg>
</div>
<h3 class="h3">Paver repair</h3>
<p>
Loose, sunken, or separated pavers need more than fresh sand. We lift the affected
area, correct the base, replace damaged pieces when a match is available, and reset it.
</p>
<ul class="service-list">
<li>Sunken and uneven pavers</li>
<li>Loose edge and border pavers</li>
<li>Small-area lift and relay</li>
<li>Damaged paver replacement</li>
<li>Joint sand and final rinse</li>
</ul>
</article>
<article class="service service--roof reveal">
<div class="service-icon" aria-hidden="true">
<svg viewBox="0 0 48 48" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M4 24 24 8l20 16"/><path d="M8 22v18h32V22"/>
<path d="M16 40V28h8v12"/><path d="M30 28h6v6h-6z"/>
</svg>
</div>
<h3 class="h3">Roof cleaning</h3>
<p>
Black roof streaks are algae. We clean tile, shingle, and metal roofs with a
low-pressure soft wash, so a pressure-washer wand never touches the roof surface.
</p>
<ul class="service-list">
<li>Barrel and flat tile</li>
<li>Asphalt shingle and metal</li>
<li>Low-pressure application</li>
<li>Landscaping watered before and rinsed after</li>
<li>Photos available for HOA notices</li>
</ul>
</article>
</div>
</div>
</section>
<!-- ── signature: the wand line ────────────────────────────── -->
<section class="band band--tinted" id="results">
<div class="wrap">
<div class="section-head results-head reveal">
<h2 class="h2">Real results: See the before and after</h2>
</div>
<div class="wand-comparisons">
<article class="wand-project reveal" data-comparison-id="result-1">
<div class="wand">
<div class="wand-layer">
<img data-comparison-side="before" src="https://voldservices.com/img/before-driveway.jpg"
alt="Travertine paver driveway dulled by dirt and organic growth before cleaning"
loading="lazy" decoding="async" width="746" height="829" />
</div>
<div class="wand-layer wand-layer--after">
<img data-comparison-side="after" src="https://voldservices.com/img/after-driveway.jpg"
alt="The same driveway after pressure washing, re-sanding, and sealing"
loading="lazy" decoding="async" width="746" height="829" />
</div>
<span class="wand-tag wand-tag--before">Before</span>
<span class="wand-tag wand-tag--after">After</span>
<input class="wand-range" type="range" min="0" max="100" value="50" step="0.1"
aria-label="Compare the paver driveway before on the left and after on the right. Use the arrow keys to move the divider." />
<div class="wand-seam" aria-hidden="true"></div>
<div class="wand-handle" aria-hidden="true">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
<path d="M9 6 4 12l5 6M15 6l5 6-5 6"/>
</svg>
</div>
</div>
</article>
<article class="wand-project reveal" data-comparison-id="result-2">
<div class="wand">
<div class="wand-layer">
<img data-comparison-side="before" src="https://voldservices.com/img/before-pool-deck.jpg"
alt="Gold travertine pool deck greyed by weathering and organic staining before cleaning"
loading="lazy" decoding="async" width="746" height="829" />
</div>
<div class="wand-layer wand-layer--after">
<img data-comparison-side="after" src="https://voldservices.com/img/after-pool-deck.jpg"
alt="The same pool deck after cleaning and sealing, with the stone color brought back"
loading="lazy" decoding="async" width="746" height="829" />
</div>
<span class="wand-tag wand-tag--before">Before</span>
<span class="wand-tag wand-tag--after">After</span>
<input class="wand-range" type="range" min="0" max="100" value="50" step="0.1"
aria-label="Compare the travertine pool deck before on the left and after on the right. Use the arrow keys to move the divider." />
<div class="wand-seam" aria-hidden="true"></div>
<div class="wand-handle" aria-hidden="true">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
<path d="M9 6 4 12l5 6M15 6l5 6-5 6"/>
</svg>
</div>
</div>
</article>
</div>
</div>
</section>
<!-- ── work ────────────────────────────────────────────────── -->
<section class="band" id="work">
<div class="wrap">
<div class="work-heading reveal">
<div class="section-head">
<h2 class="h2">View some of our recent work</h2>
</div>
<a class="work-instagram" href="https://www.instagram.com/voldservices/" target="_blank" rel="noopener noreferrer">
More jobs on Instagram
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" aria-hidden="true">
<rect x="3" y="3" width="18" height="18" rx="5" />
<circle cx="12" cy="12" r="4" />
<circle cx="17.4" cy="6.6" r="1" fill="currentColor" stroke="none" />
</svg>
</a>
</div>
<div class="work-grid reveal" id="work-grid" data-gallery-manifest="gallery/gallery.json">
<button class="work-tile" type="button">
<img src="https://voldservices.com/img/after-driveway.jpg" alt="Travertine paver driveway cleaned and sealed at a two-storey South Florida home" loading="lazy" decoding="async" width="746" height="829" />
<span class="work-cap"><b>Driveway wash & seal</b><span>Paver sealing</span></span>
</button>
<button class="work-tile" type="button">
<img src="https://voldservices.com/img/after-pool-deck.jpg" alt="Gold travertine pool deck sealed to a wet look beside a screened pool" loading="lazy" decoding="async" width="746" height="829" />
<span class="work-cap"><b>Pool deck seal</b><span>Paver sealing</span></span>
</button>
<button class="work-tile" type="button">
<img src="https://voldservices.com/img/after-lanai.jpg" alt="Screened lanai with travertine pavers cleaned back to a warm tone" loading="lazy" decoding="async" width="746" height="829" />
<span class="work-cap"><b>Screened lanai</b><span>Pressure washing</span></span>
</button>
<button class="work-tile" type="button">
<img src="https://voldservices.com/img/after-patio.jpg" alt="Front paver patio and walkway cleaned, weeded, and re-sanded" loading="lazy" decoding="async" width="746" height="829" />
<span class="work-cap"><b>Patio & walkway</b><span>Pressure washing</span></span>
</button>
<button class="work-tile" type="button">
<img src="https://voldservices.com/img/work-driveway-travertine.jpg" alt="Finished travertine paver driveway taped off after sealing" loading="lazy" decoding="async" width="746" height="829" />
<span class="work-cap"><b>Travertine driveway</b><span>Sealed & taped off</span></span>
</button>
<button class="work-tile" type="button">
<img src="https://voldservices.com/img/work-driveway-install.jpg" alt="Paver driveway restoration in progress, with new pavers being laid over the old concrete" loading="lazy" decoding="async" width="746" height="829" />
<span class="work-cap"><b>Driveway restoration</b><span>In progress</span></span>
</button>
</div>
</div>
</section>
<!-- ── service areas ───────────────────────────────────────── -->
<section class="band band--tinted" id="areas">
<div class="wrap">
<div class="section-head reveal">
<h2 class="h2">Areas Serviced</h2>
<p class="lead">
We service all of Broward, Palm Beach, and Miami-Dade. No matter where you are located in South Florida, we can make your space shine!
</p>
</div>
<div class="areas-grid reveal">
<div class="area area--primary">
<h3>Broward County</h3>
<ul>
<li>Fort Lauderdale</li><li>Pembroke Pines</li><li>Hollywood</li><li>Miramar</li>
<li>Coral Springs</li><li>Plantation</li><li>Weston</li><li>Pompano Beach</li><li>Deerfield Beach</li><li>Coconut Creek</li>
<li>Parkland</li><li>Margate</li><li>Lauderhill</li><li>Oakland Park</li><li>Wilton Manors</li>
<li>Dania Beach</li><li>Hallandale Beach</li><li>Lighthouse Point</li><li>Lauderdale-by-the-Sea</li>
</ul>
</div>
<div class="area">
<h3>Miami-Dade County</h3>
<ul>
<li>Miami</li><li>Aventura</li><li>Miami Beach</li><li>Doral</li>
<li>Hialeah</li><li>Kendall</li><li>Coral Gables</li><li>Miami Lakes</li>
<li>North Miami</li><li>Pinecrest</li><li>Palmetto Bay</li><li>Homestead</li>
</ul>
</div>
<div class="area">
<h3>Palm Beach County</h3>
<ul>
<li>Boca Raton</li><li>Delray Beach</li><li>Boynton Beach</li><li>West Palm Beach</li>
<li>Wellington</li><li>Jupiter</li><li>Royal Palm Beach</li><li>Lake Worth</li>
<li>Palm Beach Gardens</li><li>Greenacres</li>
</ul>
</div>
</div>
</div>
</section>
<!-- ── reviews ─────────────────────────────────────────────── -->
<section class="band" id="reviews">
<div class="wrap">
<div class="section-head reveal">
<h2 class="h2">100 five star reviews and counting</h2>
</div>
<div class="reviews reveal">
<figure class="review">
<div class="stars" aria-label="5 out of 5 stars">★★★★★</div>
<blockquote>Don't hesitate. These guys are pros. From unbelievably quick response to immaculate prep work to superior sealant, you will not be disappointed. You get what you pay for and Nano Seal is worth every penny.</blockquote>
<figcaption>Julie Walsh</figcaption>
</figure>
<figure class="review">
<div class="stars" aria-label="5 out of 5 stars">★★★★★</div>
<blockquote>A good friend recommended Vold to me and I had a great experience. Jack showed up on time to give an estimate and came several days later to pressure clean my pavers front and back. A great job at a reasonable price, I highly recommend this company!</blockquote>
<figcaption>Christopher Cooper</figcaption>
</figure>
<figure class="review">
<div class="stars" aria-label="5 out of 5 stars">★★★★★</div>
<blockquote>Absolutely exceptional. The level of professionalism, precision, and attention to detail truly sets this company apart. From start to finish, everything reflects a commitment to excellence and high standards. It’s rare to find a business that delivers with this level of care and consistency. If you’re looking for a premium, top-tier experience, this is the company to trust </blockquote>
<figcaption>Skye Proferes</figcaption>
</figure>
</div>
<p class="placeholder-note reveal">
See all of our reviews on <a href="https://share.google/Gy96TtpQu6SzJoTp2">Google</a>.
</p>
</div>
</section>
<!-- ── quote ───────────────────────────────────────────────── -->
<section class="band band--tinted" id="quote">
<div class="wrap">
<div class="section-head reveal">
<h2 class="h2">Contact us today!</h2>
<p class="lead">
Send the address, the surface, and any details you know. We'll call or text to confirm
the job and arrange a walkthrough if one is needed.
</p>
</div>
<div class="quote-grid reveal">
<div class="quote-side">
<div class="quote-row">
<div class="quote-label">Call or text</div>
<a class="quote-phone" href="tel:+19544013301">(954) 401-3301</a>
</div>
<div class="quote-row">
<div class="quote-label">Find us online</div>
<div class="social-links" aria-label="Vold Services social links">
<a class="social-link" href="https://www.instagram.com/voldservices/" target="_blank" rel="noopener noreferrer" aria-label="Vold Services on Instagram" title="Instagram">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" aria-hidden="true">
<rect x="3" y="3" width="18" height="18" rx="5" />
<circle cx="12" cy="12" r="4" />
<circle cx="17.4" cy="6.6" r="1" fill="currentColor" stroke="none" />
</svg>
</a>
<a class="social-link" href="https://www.facebook.com/p/VOLD-Services-61553817020348/" target="_blank" rel="noopener noreferrer" aria-label="Vold Services on Facebook" title="Facebook">
<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
<path d="M14.2 8H17V4h-3.2C10.6 4 9 5.9 9 9v2H6v4h3v7h4v-7h3.2l.8-4h-4V9.4c0-1 .3-1.4 1.2-1.4Z" />
</svg>
</a>
<a class="social-link" href="https://share.google/Gy96TtpQu6SzJoTp2" target="_blank" rel="noopener noreferrer" aria-label="Vold Services on Google" title="Google">
<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
<path d="M12.48 10.92v3.28h4.58c-.18 1.1-1.37 3.23-4.58 3.23-2.75 0-5-2.28-5-5.07s2.25-5.07 5-5.07c1.57 0 2.62.67 3.22 1.25l2.2-2.13C16.48 5.1 14.66 4.3 12.48 4.3 8.02 4.3 4.4 7.9 4.4 12.36s3.62 8.06 8.08 8.06c4.66 0 7.75-3.27 7.75-7.89 0-.53-.06-.93-.13-1.61h-7.62Z" />
</svg>
</a>
</div>
</div>
<div class="quote-row">
<div class="quote-label">Services</div>
<div class="quote-value">Pressure washing · Paver sealing · Paver repair · Roof cleaning</div>
</div>
<div class="quote-row">
<div class="quote-label">Service area</div>
<div class="quote-value">Broward, Miami-Dade, and Palm Beach counties</div>
</div>
<div class="quote-row">
<div class="quote-label">Property types</div>
<div class="quote-value">Residential, commercial, HOA and multi-family</div>
</div>
<div class="quote-row">
<div class="quote-label">Hours</div>
<div class="quote-value">Monday–Saturday, 7:00 AM – 6:00 PM</div>
</div>
</div>
<div class="quote-form-wrap">
<form class="quote-form" id="quote-form"
action="https://formspree.io/f/xaewpyaq"
method="POST"
enctype="multipart/form-data">
<div class="field-row">
<div class="field">
<label for="q-name">Name</label>
<input id="q-name" name="name" type="text" autocomplete="name" placeholder="Your name" required />
</div>
<div class="field">
<label for="q-phone">Phone</label>
<input id="q-phone" name="phone" type="tel" autocomplete="tel" placeholder="(954) 000-0000" required />
</div>
</div>
<div class="field-row">
<div class="field">
<label for="q-email">Email</label>
<input id="q-email" name="email" type="email" autocomplete="email" placeholder="[email protected]" />
</div>
<div class="field">
<label for="q-city">City</label>
<input id="q-city" name="city" type="text" autocomplete="address-level2" placeholder="Fort Lauderdale" />
</div>
</div>
<div class="field-row">
<div class="field">
<label for="q-service">Service needed</label>
<select id="q-service" name="service">
<option>Pressure washing</option>
<option>Paver sealing</option>
<option>Paver repair</option>
<option>Roof cleaning</option>
<option>House wash</option>
<option>Pool deck or patio</option>
<option>Commercial / recurring</option>
<option>Not sure yet</option>
</select>
</div>
<div class="field">
<label for="q-property">Property type</label>
<select id="q-property" name="property">
<option>Residential</option>
<option>Commercial</option>
<option>HOA / multi-family</option>
</select>
</div>
</div>
<div class="field">
<label for="q-message">What needs cleaning?</label>
<textarea id="q-message" name="message" placeholder="Approximate size, roof material, when it was last cleaned, or anything else that will help us quote the job."></textarea>
</div>
<div class="field">
<label for="q-photos">Show us the surface <span aria-hidden="true">·</span> Optional</label>
<input class="photo-input" id="q-photos" name="photos" type="file" accept="image/*" multiple
aria-describedby="q-photos-help q-photos-status" />
<label class="photo-picker" for="q-photos">
<span class="photo-picker__action">Add photos</span>
<span class="photo-picker__note">One at a time or several together</span>
</label>
<p class="field-help" id="q-photos-help">Add up to 5 photos. You can open the picker again to add more. Maximum 25 MB each and 90 MB total.</p>
<ul class="photo-list" id="q-photo-list" aria-label="Selected photos" hidden></ul>
<p class="photo-status" id="q-photos-status" aria-live="polite"></p>
</div>
<div class="form-error" id="form-error" role="alert" hidden></div>
<button class="btn btn--primary btn--block" id="quote-submit" type="submit">Request an estimate</button>
<p class="form-note">Prefer to talk? Call or text (954) 401-3301 during business hours.</p>
</form>
<div class="form-success" id="form-success" role="status" aria-live="polite" tabindex="-1" hidden>
<div>
<div class="success-mark" aria-hidden="true">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="m5 12 4 4L19 6" />
</svg>
</div>
<p class="eyebrow">Request received</p>
<h3>Thanks, <span id="success-name">we’ve got it</span>.</h3>
<p>We’ll call or text to confirm the details and arrange a walkthrough if one is needed.</p>
<a class="quote-value" href="tel:+19544013301">Need us sooner? Call (954) 401-3301</a>
</div>
</div>
</div>
</div>
</div>
</section>
</main>
<footer class="footer">
<div class="wrap">
<div class="footer-inner">
<div>
<img src="https://voldservices.com/logo.png" alt="Vold Services" width="168" height="87" />
<p>
Exterior cleaning for homes, HOAs, and commercial properties across Broward,
Miami-Dade, and Palm Beach counties.
</p>
<div class="social-links" aria-label="Vold Services social links">
<a class="social-link" href="https://www.instagram.com/voldservices/" target="_blank" rel="noopener noreferrer" aria-label="Vold Services on Instagram" title="Instagram">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" aria-hidden="true">
<rect x="3" y="3" width="18" height="18" rx="5" />
<circle cx="12" cy="12" r="4" />
<circle cx="17.4" cy="6.6" r="1" fill="currentColor" stroke="none" />
</svg>
</a>
<a class="social-link" href="https://www.facebook.com/p/VOLD-Services-61553817020348/" target="_blank" rel="noopener noreferrer" aria-label="Vold Services on Facebook" title="Facebook">
<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
<path d="M14.2 8H17V4h-3.2C10.6 4 9 5.9 9 9v2H6v4h3v7h4v-7h3.2l.8-4h-4V9.4c0-1 .3-1.4 1.2-1.4Z" />
</svg>
</a>
<a class="social-link" href="https://share.google/Gy96TtpQu6SzJoTp2" target="_blank" rel="noopener noreferrer" aria-label="Vold Services on Google" title="Google">
<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
<path d="M12.48 10.92v3.28h4.58c-.18 1.1-1.37 3.23-4.58 3.23-2.75 0-5-2.28-5-5.07s2.25-5.07 5-5.07c1.57 0 2.62.67 3.22 1.25l2.2-2.13C16.48 5.1 14.66 4.3 12.48 4.3 8.02 4.3 4.4 7.9 4.4 12.36s3.62 8.06 8.08 8.06c4.66 0 7.75-3.27 7.75-7.89 0-.53-.06-.93-.13-1.61h-7.62Z" />
</svg>
</a>
</div>
</div>
<div>
<h4>Services</h4>
<ul>
<li><a href="#services">Pressure washing</a></li>
<li><a href="#services">Paver sealing</a></li>
<li><a href="#services">Paver repair</a></li>
<li><a href="#services">Roof cleaning</a></li>
<li><a href="#services">House & building wash</a></li>
<li><a href="#services">Commercial cleaning</a></li>
</ul>
</div>
<div>
<h4>Company</h4>
<ul>
<li><a href="#results">Before & after</a></li>
<li><a href="#work">Recent work</a></li>
<li><a href="#areas">Service areas</a></li>
<li><a href="#quote">Contact</a></li>
<li><a href="tel:+19544013301">(954) 401-3301</a></li>
</ul>
</div>
</div>
<div class="footer-base">
<span>© <span id="year">2026</span> Vold Services. All rights reserved.</span>
<span>Broward · Miami-Dade · Palm Beach · Licensed & insured</span>
</div>
</div>
</footer>
<!-- Mobile-only bottom bar; slides up once the hero is out of view. -->
<div class="sticky-cta" id="sticky-cta">
<a class="btn btn--primary" href="tel:+19544013301">
<svg viewBox="0 0 24 24" width="15" height="15" fill="currentColor" aria-hidden="true"><path d="M6.6 10.8c1.4 2.7 3.6 4.9 6.3 6.3l2.1-2.1c.3-.3.8-.4 1.1-.2 1.1.4 2.3.6 3.5.6.5 0 .9.4.9.9V20c0 .5-.4.9-.9.9C10.7 20.9 3.1 13.3 3.1 4c0-.5.4-.9.9-.9h3.7c.5 0 .9.4.9.9 0 1.2.2 2.4.6 3.5.1.4.1.8-.2 1.1L6.6 10.8z"/></svg>
(954) 401-3301
</a>
<a class="btn btn--ghost" href="#quote">Get estimate</a>
</div>
<div class="lightbox" id="lightbox" role="dialog" aria-modal="true" aria-label="Project photo">
<button class="lightbox-close" type="button" aria-label="Close photo">×</button>
<img id="lightbox-img" alt="" />
</div>
<!-- ── structured data ───────────────────────────────────────── -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@graph": [
{
"@type": ["LocalBusiness", "HomeAndConstructionBusiness"],
"@id": "https://voldservices.com/#business",
"name": "Vold Services",
"description": "Pressure washing, paver sealing and repair, and roof cleaning for residential and commercial properties in Broward, Miami-Dade, and Palm Beach counties, Florida.",
"url": "https://voldservices.com/",
"telephone": "+1-954-401-3301",
"image": "https://voldservices.com/og-card-v2.jpg",
"logo": "https://voldservices.com/logo.png",
"sameAs": [
"https://www.instagram.com/voldservices/",
"https://www.facebook.com/p/VOLD-Services-61553817020348/",
"https://share.google/Gy96TtpQu6SzJoTp2"
],
"priceRange": "$$",
"currenciesAccepted": "USD",
"address": {
"@type": "PostalAddress",
"addressLocality": "Fort Lauderdale",
"addressRegion": "FL",
"addressCountry": "US"
},
"geo": { "@type": "GeoCoordinates", "latitude": 26.1224, "longitude": -80.1373 },
"areaServed": [
{ "@type": "AdministrativeArea", "name": "Broward County, Florida" },
{ "@type": "AdministrativeArea", "name": "Miami-Dade County, Florida" },
{ "@type": "AdministrativeArea", "name": "Palm Beach County, Florida" },
{ "@type": "City", "name": "Fort Lauderdale" },
{ "@type": "City", "name": "Pembroke Pines" },
{ "@type": "City", "name": "Hollywood" },
{ "@type": "City", "name": "Miramar" },
{ "@type": "City", "name": "Coral Springs" },
{ "@type": "City", "name": "Davie" },
{ "@type": "City", "name": "Plantation" },
{ "@type": "City", "name": "Sunrise" },
{ "@type": "City", "name": "Weston" },
{ "@type": "City", "name": "Pompano Beach" },
{ "@type": "City", "name": "Deerfield Beach" },
{ "@type": "City", "name": "Parkland" },
{ "@type": "City", "name": "Boca Raton" },
{ "@type": "City", "name": "Miami" }
],
"openingHoursSpecification": [
{
"@type": "OpeningHoursSpecification",
"dayOfWeek": ["Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],
"opens": "07:00",
"closes": "18:00"
}
],
"hasOfferCatalog": {
"@type": "OfferCatalog",
"name": "Exterior cleaning services",
"itemListElement": [
{
"@type": "Offer",
"itemOffered": {
"@type": "Service",
"name": "Pressure Washing",
"serviceType": "Pressure washing",
"description": "Driveways, walkways, pool decks, patios, house washes, fences, and commercial flatwork cleaned at surface-appropriate pressure.",
"areaServed": "Broward County, Florida"
}
},
{
"@type": "Offer",
"itemOffered": {
"@type": "Service",
"name": "Paver Sealing",
"serviceType": "Paver sealing",
"description": "Paver cleaning, efflorescence removal, polymeric joint sand replacement, and wet-look or matte sealing for driveways and pool decks.",
"areaServed": "Broward County, Florida"
}
},
{
"@type": "Offer",
"itemOffered": {
"@type": "Service",
"name": "Paver Repair",
"serviceType": "Paver repair",
"description": "Repair for sunken, uneven, loose, separated, or damaged pavers, including small-area lift and relay, base correction, replacement, and joint sand.",
"areaServed": "Broward County, Florida"
}
},
{
"@type": "Offer",
"itemOffered": {
"@type": "Service",
"name": "Roof Cleaning",
"serviceType": "Roof cleaning",
"description": "Low-pressure soft wash roof cleaning for barrel tile, flat tile, asphalt shingle, and metal roofs to remove algae streaking.",
"areaServed": "Broward County, Florida"
}
}
]
}
},
{
"@type": "WebSite",
"@id": "https://voldservices.com/#website",
"url": "https://voldservices.com/",
"name": "Vold Services",
"publisher": { "@id": "https://voldservices.com/#business" },
"inLanguage": "en-US"
}
]
}
</script>
<script>
(function () {
'use strict';
var reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
/* ── cinematic hero scroll ────────────────────────────────
The section supplies the scroll distance; its sticky child remains
pinned while these values interpolate from the user's real scroll.
No scroll is captured or eased, so trackpads and touch keep their
native feel. */
var heroCinematic = document.getElementById('top');
var heroSticky = document.getElementById('hero-sticky');
var heroCue = heroSticky.querySelector('.hero-cue');
var heroEyebrow = heroSticky.querySelector('.hero-eyebrow');
var heroLead = heroSticky.querySelector('.hero-lead');
var heroActions = document.getElementById('hero-actions');
var heroMedia = heroSticky.querySelector('.hero-media');
var heroVideo = document.getElementById('hero-video');
var heroVideoReady = false;
var heroVideoPrimed = false;
var heroVideoPrimePending = false;
var heroTouchStarted = false;
var heroUsesTouch = ('ontouchstart' in window) || navigator.maxTouchPoints > 0;
var heroVideoVisible = false;
var heroVideoRevealPending = false;
var heroVideoProgress = 0;
var heroVideoObjectUrl = '';
function clamp01(value) {
return Math.max(0, Math.min(1, value));
}
function smoothstep(value) {
value = clamp01(value);
return value * value * (3 - (2 * value));
}
function paintReveal(element, progress, travel) {
element.style.opacity = progress.toFixed(4);
element.style.transform = 'translate3d(0,' + ((1 - progress) * travel).toFixed(2) + 'px,0)';
}
/* The optimized file has a seek point every three frames. Keep the
video paused and seek its playhead to the user's actual scroll
position; there is no autonomous playback or scroll hijacking. */
function syncHeroVideo(progress, force) {
heroVideoProgress = progress;
if (reduceMotion || !heroVideoReady || !Number.isFinite(heroVideo.duration)) return;
var usableDuration = Math.max(heroVideo.duration - (1 / 24), 0);
// Safari can clear the poster before it has decoded a seek at exactly
// zero. Start a fraction into the first frame and keep a real image
// beneath the video until a decoded frame has actually been painted.
var targetTime = Math.max(1 / 48, usableDuration * heroVideoProgress);
if (!force && (heroVideo.seeking || Math.abs(heroVideo.currentTime - targetTime) < (1 / 48))) return;
heroVideo.currentTime = targetTime;
}
function revealHeroVideo() {
if (reduceMotion || heroVideoVisible || heroVideoRevealPending || heroVideo.readyState < 2) return;
heroVideoRevealPending = true;
var reveal = function () {
heroVideoRevealPending = false;
if (reduceMotion || heroVideoVisible || heroVideo.readyState < 2) return;
heroVideoVisible = true;
heroMedia.classList.add('is-video-ready');
};
if (typeof heroVideo.requestVideoFrameCallback === 'function') {
heroVideo.requestVideoFrameCallback(reveal);
// A paused iOS video can finish seeking before a queued frame
// callback is delivered. By this point seeked + HAVE_CURRENT_DATA
// make a delayed reveal safe, while the poster covers the handoff.
window.setTimeout(reveal, 160);
} else {
window.requestAnimationFrame(function () {
window.requestAnimationFrame(reveal);
});
}
}
function finishHeroVideoPrime() {
heroVideo.pause();
heroVideoPrimePending = false;
heroVideoPrimed = true;
heroVideoReady = true;
window.removeEventListener('touchstart', primeHeroVideoFromTouch);
syncHeroVideo(heroVideoProgress, true);
}
function usePausedSeekFallback() {
heroVideo.pause();
heroVideoPrimePending = false;
heroVideoReady = true;
syncHeroVideo(heroVideoProgress, true);
}
// iOS may load metadata for a muted video without activating its decoder.
// On touch devices, a brief hidden play/pause on the first scroll touch
// primes frame presentation without autoplay or visible player chrome.
function primeHeroVideo() {
if (reduceMotion || heroVideoPrimed || heroVideoPrimePending || heroVideo.readyState < 1) return;
heroVideoPrimePending = true;
heroVideo.muted = true;
heroVideo.defaultMuted = true;
var playAttempt = heroVideo.play();
if (playAttempt && typeof playAttempt.then === 'function') {
playAttempt.then(finishHeroVideoPrime).catch(usePausedSeekFallback);
} else {
finishHeroVideoPrime();
}
}
function primeHeroVideoFromTouch() {
heroTouchStarted = true;
primeHeroVideo();
}
function prepareHeroVideo() {
if (!heroUsesTouch || heroTouchStarted) primeHeroVideo();
}
function attachHeroVideoSource(source) {
heroVideo.src = source;
heroVideo.load();
}
/* The origin currently serves MP4 files without byte-range responses.
Mobile's smaller encode can finish downloading before that becomes
noticeable, but desktop seeks otherwise snap back to frame zero.
Buffer the desktop file into a blob so its full timeline is locally
seekable, keeping the poster visible until the first frame is ready. */
function loadHeroVideo() {
var mobileSource = window.innerWidth <= 720;
var source = mobileSource
? heroVideo.getAttribute('data-mobile-src')
: heroVideo.getAttribute('data-desktop-src');
if (mobileSource || typeof window.fetch !== 'function' || typeof window.URL.createObjectURL !== 'function') {
attachHeroVideoSource(source);
return;
}
window.fetch(source, { cache: 'force-cache' })
.then(function (response) {
if (!response.ok) throw new Error('Hero video request failed');
return response.blob();
})
.then(function (blob) {
heroVideoObjectUrl = window.URL.createObjectURL(blob);
attachHeroVideoSource(heroVideoObjectUrl);
})
.catch(function () {
attachHeroVideoSource(source);
});
}
if (reduceMotion) {
heroVideo.pause();
} else {
heroVideo.addEventListener('loadedmetadata', prepareHeroVideo);
if (heroUsesTouch) {
window.addEventListener('touchstart', primeHeroVideoFromTouch, { passive: true });
}
// Cached media can reach metadata before this bottom-of-page script runs.
if (heroVideo.readyState >= 1) prepareHeroVideo();
loadHeroVideo();
}
window.addEventListener('beforeunload', function () {
if (heroVideoObjectUrl) window.URL.revokeObjectURL(heroVideoObjectUrl);
});
// If the user scrolls again while a seek is being decoded, catch the
// playhead up to the most recent position as soon as that frame lands.
heroVideo.addEventListener('seeked', function () {
revealHeroVideo();
syncHeroVideo(heroVideoProgress, false);
});
heroVideo.addEventListener('error', function () {
heroVideoReady = false;
heroVideoPrimed = false;
heroVideoPrimePending = false;
heroVideoVisible = false;
heroVideoRevealPending = false;
heroMedia.classList.remove('is-video-ready');
});
function paintHeroScroll() {
if (reduceMotion) {
heroActions.inert = false;
heroActions.setAttribute('aria-hidden', 'false');
return;
}
var runway = Math.max(heroCinematic.offsetHeight - window.innerHeight, 1);
var progress = clamp01(-heroCinematic.getBoundingClientRect().top / runway);
syncHeroVideo(progress, false);
var eyebrowIn = smoothstep((progress - 0.1) / 0.15);
var leadIn = smoothstep((progress - 0.28) / 0.18);
var actionsIn = smoothstep((progress - 0.42) / 0.18);
var cueOut = smoothstep(progress / 0.12);
var scrimIn = smoothstep((progress - 0.08) / 0.42);
heroSticky.style.setProperty('--hero-media-scale', (1.03 + (0.08 * smoothstep(progress))).toFixed(4));
heroSticky.style.setProperty('--hero-scrim-opacity', (0.3 + (0.7 * scrimIn)).toFixed(4));
heroSticky.style.setProperty('--hero-cue-opacity', (1 - cueOut).toFixed(4));
paintReveal(heroEyebrow, eyebrowIn, 20);
paintReveal(heroLead, leadIn, 30);
paintReveal(heroActions, actionsIn, 24);
var cueActive = cueOut < 0.92;
var actionsActive = actionsIn > 0.8;
heroCue.style.pointerEvents = cueActive ? '' : 'none';
heroCue.inert = !cueActive;
heroCue.setAttribute('aria-hidden', String(!cueActive));
heroActions.style.pointerEvents = actionsActive ? '' : 'none';
heroActions.inert = !actionsActive;
heroActions.setAttribute('aria-hidden', String(!actionsActive));
}
/* ── scroll-aware nav ─────────────────────────────────────
Keeps the nav visible while the oversized opening state compacts. */
var nav = document.getElementById('nav');
var navProgress = document.getElementById('nav-progress');
var navToggle = document.querySelector('.nav-toggle');
var navLinksWrap = document.getElementById('nav-links');
var navAnchors = navLinksWrap.querySelectorAll('a[href^="#"]');
var stickyCta = document.getElementById('sticky-cta');
var ticking = false;
function mix(from, to, progress) {
return from + ((to - from) * progress);
}
/* The opening masthead collapses over the first 220px of real scroll.
Values finish at the original compact nav measurements. */
function paintNavScale(y) {
var mobileNav = window.innerWidth <= 900;
var progress = reduceMotion ? (y > 12 ? 1 : 0) : smoothstep(clamp01(y / 220));
var compactLogo = Math.min(188, Math.max(146, window.innerWidth * 0.17));
var introLogo = mobileNav
? Math.min(240, Math.max(190, window.innerWidth * 0.45))
: Math.min(310, Math.max(230, window.innerWidth * 0.24));
var introHeight = mobileNav
? 104
: Math.min(138, Math.max(112, window.innerHeight * 0.12));
nav.style.setProperty('--nav-live-height', mix(introHeight, 76, progress).toFixed(2) + 'px');
nav.style.setProperty('--nav-live-logo', mix(introLogo, compactLogo, progress).toFixed(2) + 'px');
nav.style.setProperty('--nav-live-call-font', mix(16, 13.76, progress).toFixed(2) + 'px');
nav.style.setProperty('--nav-live-call-y', mix(14, 11, progress).toFixed(2) + 'px');
nav.style.setProperty('--nav-live-call-x', mix(22, 18, progress).toFixed(2) + 'px');
nav.style.setProperty('--nav-live-icon', mix(18, 15, progress).toFixed(2) + 'px');
}
function onScroll() {
var y = window.scrollY;
var max = document.documentElement.scrollHeight - window.innerHeight;
paintHeroScroll();
paintNavScale(y);
nav.classList.toggle('is-stuck', y > 12);
navProgress.style.transform = 'scaleX(' + (max > 0 ? Math.min(y / max, 1) : 0) + ')';
stickyCta.classList.toggle('is-up', y > heroCinematic.offsetTop + heroCinematic.offsetHeight);
ticking = false;
}
window.addEventListener('scroll', function () {
if (ticking) return;
ticking = true;
window.requestAnimationFrame(onScroll);
}, { passive: true });
window.addEventListener('resize', function () {
if (ticking) return;
ticking = true;
window.requestAnimationFrame(onScroll);
});
onScroll();
/* ── mobile menu ──────────────────────────────────────── */
navToggle.addEventListener('click', function () {
var open = navToggle.getAttribute('aria-expanded') === 'true';
navToggle.setAttribute('aria-expanded', String(!open));
navToggle.setAttribute('aria-label', open ? 'Open menu' : 'Close menu');
nav.classList.toggle('is-open', !open);
});
function closeMenu() {
navToggle.setAttribute('aria-expanded', 'false');
navToggle.setAttribute('aria-label', 'Open menu');
nav.classList.remove('is-open');
}
navLinksWrap.addEventListener('click', function (e) {
if (e.target.closest('a')) closeMenu();
});
document.addEventListener('keydown', function (e) {
if (e.key === 'Escape' && nav.classList.contains('is-open')) {
closeMenu();
navToggle.focus();
}
});
document.addEventListener('click', function (e) {
if (!nav.classList.contains('is-open') || nav.contains(e.target)) return;
closeMenu();
});
/* ── active section in the nav ────────────────────────── */
var sections = [];
navAnchors.forEach(function (a) {
var el = document.querySelector(a.getAttribute('href'));
if (el) sections.push({ el: el, link: a });
});
if (sections.length && 'IntersectionObserver' in window) {
var spy = new IntersectionObserver(function (entries) {
entries.forEach(function (entry) {
if (!entry.isIntersecting) return;
navAnchors.forEach(function (a) { a.classList.remove('is-current'); });
var match = sections.find(function (s) { return s.el === entry.target; });
if (match) match.link.classList.add('is-current');
});
}, { rootMargin: '-45% 0px -50% 0px' });
sections.forEach(function (s) { spy.observe(s.el); });
}
/* ── reveal on scroll ─────────────────────────────────── */
var reveals = document.querySelectorAll('.reveal');
if (reduceMotion || !('IntersectionObserver' in window)) {
reveals.forEach(function (el) { el.classList.add('is-in'); });
} else {
var revealObserver = new IntersectionObserver(function (entries) {
entries.forEach(function (entry) {
if (!entry.isIntersecting) return;
entry.target.classList.add('is-in');
revealObserver.unobserve(entry.target);
});
}, { threshold: 0.12, rootMargin: '0px 0px -6% 0px' });
reveals.forEach(function (el) { revealObserver.observe(el); });
}
/* ── the wand line ────────────────────────────────────── */
document.querySelectorAll('.wand').forEach(function (wand) {
var wandRange = wand.querySelector('.wand-range');
function paintWand() {
wand.style.setProperty('--pos', wandRange.value + '%');
var beforePercent = Math.round(Number(wandRange.value));
wandRange.setAttribute('aria-valuetext', beforePercent + '% before, ' + (100 - beforePercent) + '% after');
}
wandRange.addEventListener('input', paintWand);
paintWand();
});
/* ── gallery lightbox ─────────────────────────────────── */
var lightbox = document.getElementById('lightbox');
var lightboxImg = document.getElementById('lightbox-img');
var lightboxClose = lightbox.querySelector('.lightbox-close');
var lastFocused = null;
var workGrid = document.getElementById('work-grid');
workGrid.addEventListener('click', function (event) {
var tile = event.target.closest('.work-tile');
if (!tile || !workGrid.contains(tile)) return;
var img = tile.querySelector('img');
if (!img) return;
lastFocused = tile;
lightboxImg.src = img.dataset.full || img.currentSrc || img.src;
lightboxImg.alt = img.alt;
lightbox.classList.add('is-open');
document.body.classList.add('is-locked');
lightboxClose.focus();
});
function renderManagedPhotos(manifest) {
if (!manifest || manifest.version !== 1 || !Array.isArray(manifest.images)) return;
if (Array.isArray(manifest.comparisons)) {
manifest.comparisons.forEach(function (comparison) {
var project = Array.prototype.find.call(
document.querySelectorAll('[data-comparison-id]'),
function (item) { return item.dataset.comparisonId === comparison.id; }
);
if (!project) return;
['before', 'after'].forEach(function (side) {
var media = comparison[side];
var image = project.querySelector('[data-comparison-side="' + side + '"]');
if (!image || !media || !media.src || !media.alt) return;
image.src = media.src;
image.alt = media.alt;
});
});
}
var fragment = document.createDocumentFragment();
manifest.images.forEach(function (item) {
if (!item || !item.src || !item.caption || !item.alt) return;
var tile = document.createElement('button');
tile.className = 'work-tile';
tile.type = 'button';
var image = document.createElement('img');
image.src = item.thumb || item.src;
image.alt = item.alt;
image.loading = 'lazy';
image.decoding = 'async';
image.dataset.full = item.src;
var cap = document.createElement('span');
cap.className = 'work-cap';
var title = document.createElement('b');
title.textContent = item.caption;
cap.appendChild(title);
tile.appendChild(image);
tile.appendChild(cap);
fragment.appendChild(tile);
});
workGrid.replaceChildren(fragment);
}
fetch(workGrid.dataset.galleryManifest, { credentials: 'same-origin' })
.then(function (response) {
if (!response.ok) throw new Error('Gallery request failed');
return response.json();
})
.then(renderManagedPhotos)
.catch(function () {
// Keep the server-rendered photos in place as the resilient fallback.
});
function closeLightbox() {
lightbox.classList.remove('is-open');
document.body.classList.remove('is-locked');
lightboxImg.removeAttribute('src');
lightboxImg.alt = '';
if (lastFocused) lastFocused.focus();
}
lightboxClose.addEventListener('click', closeLightbox);
lightbox.addEventListener('click', function (e) {
if (e.target === lightbox) closeLightbox();
});
document.addEventListener('keydown', function (e) {
if (e.key === 'Escape' && lightbox.classList.contains('is-open')) closeLightbox();
});
/* ── quote form ─────────────────────────────────────────── */
var form = document.getElementById('quote-form');
var success = document.getElementById('form-success');
var successName = document.getElementById('success-name');
var formError = document.getElementById('form-error');
var submitButton = document.getElementById('quote-submit');
var photoInput = document.getElementById('q-photos');
var photoList = document.getElementById('q-photo-list');
var photoStatus = document.getElementById('q-photos-status');
var maxPhotos = 5;
var maxPhotoBytes = 25 * 1024 * 1024;
var maxTotalPhotoBytes = 90 * 1024 * 1024;
var selectedPhotos = [];
function clearFormError() {
formError.hidden = true;
formError.textContent = '';
}
function showFormError(message) {
formError.textContent = message;
formError.hidden = false;
}
function formatPhotoStatus(files) {
if (!files.length) return '';
return files.length + ' of ' + maxPhotos + (files.length === 1 ? ' photo is' : ' photos are') + ' ready to send.';
}
function photoValidationMessage(files) {
var totalBytes = files.reduce(function (total, file) { return total + file.size; }, 0);
var oversizedPhoto = files.find(function (file) { return file.size > maxPhotoBytes; });
var nonPhoto = files.find(function (file) {
return file.type && file.type.indexOf('image/') !== 0;
});
if (files.length > maxPhotos) {
return 'Choose no more than 5 photos. Remove one before adding another.';
}
if (oversizedPhoto) {
return oversizedPhoto.name + ' is larger than 25 MB and was not added.';
}
if (totalBytes > maxTotalPhotoBytes) {
return 'Keep the combined photo size under 90 MB. Those photos were not added.';
}
if (nonPhoto) return 'Choose image files only.';
return '';
}
function formatPhotoSize(bytes) {
if (bytes < 1024 * 1024) return Math.max(1, Math.round(bytes / 1024)) + ' KB';
return (bytes / (1024 * 1024)).toFixed(1).replace('.0', '') + ' MB';
}
function photoKey(file) {
return [file.name, file.size, file.lastModified, file.type].join('|');
}
function renderPhotos(message) {
photoList.textContent = '';
selectedPhotos.forEach(function (file, index) {
var item = document.createElement('li');
var fileDetails = document.createElement('span');
var fileName = document.createElement('span');
var fileSize = document.createElement('span');
var removeButton = document.createElement('button');
item.className = 'photo-item';
fileDetails.className = 'photo-file';
fileName.className = 'photo-name';
fileName.textContent = file.name;
fileSize.className = 'photo-size';
fileSize.textContent = 'Photo ' + (index + 1) + ' · ' + formatPhotoSize(file.size);
removeButton.className = 'photo-remove';
removeButton.type = 'button';
removeButton.dataset.photoIndex = index;
removeButton.setAttribute('aria-label', 'Remove ' + file.name);
removeButton.textContent = 'Remove';
fileDetails.appendChild(fileName);
fileDetails.appendChild(fileSize);
item.appendChild(fileDetails);
item.appendChild(removeButton);
photoList.appendChild(item);
});
photoList.hidden = selectedPhotos.length === 0;
photoStatus.textContent = message || formatPhotoStatus(selectedPhotos);
}
function validatePhotos() {
var message = photoValidationMessage(selectedPhotos);
photoInput.setCustomValidity(message);
if (message) {
photoStatus.textContent = message;
return false;
}
photoStatus.textContent = formatPhotoStatus(selectedPhotos);
return true;
}
function formspreeErrorMessage(data, status) {
var errors = data && Array.isArray(data.errors) ? data.errors : [];
var codes = errors.map(function (error) { return error.code; });
if (status === 429) {
return 'Too many requests were sent at once. Wait a minute, then try again.';
}
if (codes.indexOf('NO_FILE_UPLOADS') !== -1) {
return 'Photo uploads are not enabled for this form yet. Remove the photos and try again, or call or text (954) 401-3301.';
}
if (codes.indexOf('TOO_MANY_FILES') !== -1) {
return 'Too many photos were attached. Choose up to 5 and try again.';
}
if (codes.indexOf('FILES_TOO_BIG') !== -1) {
return 'One or more photos are too large. Choose smaller files and try again.';
}
var messages = errors.map(function (error) { return error.message; }).filter(Boolean);
if (messages.length) return messages.join(' ');
return 'Your request could not be sent. Check your connection and try again, or call or text (954) 401-3301.';
}
photoInput.addEventListener('change', function () {
clearFormError();
var incomingPhotos = Array.prototype.slice.call(photoInput.files || []);
var selectedKeys = selectedPhotos.map(photoKey);
var duplicateCount = 0;
photoInput.value = '';
incomingPhotos = incomingPhotos.filter(function (file) {
var key = photoKey(file);
if (selectedKeys.indexOf(key) !== -1) {
duplicateCount += 1;
return false;
}
selectedKeys.push(key);
return true;
});
var candidatePhotos = selectedPhotos.concat(incomingPhotos);
var message = photoValidationMessage(candidatePhotos);
photoInput.setCustomValidity('');
if (message) {
renderPhotos(message);
return;
}
selectedPhotos = candidatePhotos;
renderPhotos(duplicateCount
? (duplicateCount === 1 ? 'That photo is already selected. ' : 'Those photos are already selected. ') + formatPhotoStatus(selectedPhotos)
: '');
});
photoList.addEventListener('click', function (e) {
var removeButton = e.target.closest('.photo-remove');
if (!removeButton) return;
var index = Number(removeButton.dataset.photoIndex);
if (!Number.isInteger(index) || !selectedPhotos[index]) return;
selectedPhotos.splice(index, 1);
photoInput.setCustomValidity('');
clearFormError();
renderPhotos();
});
form.addEventListener('submit', async function (e) {
e.preventDefault();
clearFormError();
if (!validatePhotos() || !form.checkValidity()) {
form.reportValidity();
return;
}
var submittedName = form.querySelector('#q-name').value.trim();
var originalButtonText = submitButton.textContent;
form.setAttribute('aria-busy', 'true');
submitButton.disabled = true;
submitButton.textContent = 'Sending request…';
try {
var formData = new FormData(form);
formData.delete(photoInput.name);
selectedPhotos.forEach(function (file) {
formData.append(photoInput.name, file, file.name);
});
var response = await fetch(form.action, {
method: form.method,
body: formData,
headers: { 'Accept': 'application/json' }
});
var data = await response.json().catch(function () { return null; });
if (!response.ok) {
throw { formspree: true, data: data, status: response.status };
}
successName.textContent = submittedName || 'we’ve got it';
form.reset();
selectedPhotos = [];
renderPhotos();
form.hidden = true;
success.hidden = false;
success.focus();
} catch (error) {
var message = error && error.formspree
? formspreeErrorMessage(error.data, error.status)
: 'Your request could not be sent. Check your connection and try again, or call or text (954) 401-3301.';
showFormError(message);
} finally {
form.removeAttribute('aria-busy');
submitButton.disabled = false;
submitButton.textContent = originalButtonText;
}
});
document.getElementById('year').textContent = new Date().getFullYear();
})();
</script>
</body>
</html>