// Services "bento" — Apple-store-ish feature tiles. // Two rows: (1) hero feature tile (Water damage, dark) + Carpet tile. // (2) 3-up row of remaining tiles. Each tile is a card with big title, sub, CTA. function FeatureTile({ tile }) { const [ref, inView] = useInView(); const { bg, ink, inkMuted, eyebrow, title, sub, cta, ctaColor, visual, span, minH, align } = tile; return (
{eyebrow}

{title}

{sub && (

{sub}

)} {cta && ( {cta.label} )}
{visual}
); } // --- Visual renderers for each tile (SVG/CSS-only, no AI-looking illustrations) function VisCarpet() { return (
{/* Perspective carpet */} {Array.from({length: 10}).map((_,i) => ( ))} {/* Clean pass overlay */}
); } function VisWater() { return (
{[0,1,2,3,4].map((i) => ( ))} {/* Droplet */}
); } function VisTile() { return (
{Array.from({length: 24}).map((_,i) => (
))}
); } function VisAir() { return (
{/* Duct grille */} {Array.from({length: 7}).map((_,i)=>( ))} {/* Airflow curves — animated drift */} {[0,1,2,3,4].map(i => ( ))}
); } function VisProperty() { return (
{/* Building silhouettes */} {/* Windows */} {[[170,100],[200,100],[230,100],[170,130],[200,130],[230,130],[170,160],[200,160],[230,160],[170,190],[200,190],[230,190],[170,220],[200,220],[230,220]].map(([x,y],i)=>( ))} {[[385,80],[420,80],[455,80],[385,115],[420,115],[455,115],[385,150],[420,150],[455,150],[385,185],[420,185],[455,185],[385,220],[420,220],[455,220],[385,255],[420,255],[455,255]].map(([x,y],i)=>( ))}
); } function Services() { const tiles = [ { key: 'water', span: '1 / span 6', minH: 560, bg: 'linear-gradient(180deg, #0b1f2e 0%, #143447 100%)', ink: '#ffffff', inkMuted: 'rgba(255,255,255,0.72)', ctaColor: '#5fb6ea', eyebrow: '24/7 response', title: 'Emergency water damage.\nOn-site, fast.', sub: 'Extraction, pad removal, mildewcide, deodorizing and sanitizing. Blowers, dehumidifiers, ozone and air scrubbers billed per day on-site.', cta: { label: 'See response details', href: 'Services.html#water' }, visual: , align: 'center', }, { key: 'carpet', span: '7 / span 6', minH: 560, bg: 'var(--bg-soft)', ink: 'var(--ink)', inkMuted: 'var(--muted)', ctaColor: 'var(--link)', eyebrow: 'Carpet', title: 'Cleaned, stretched,\nstain-treated.', sub: 'Pre-condition, hot-water extraction, deodorizer. Deep-stain, re-seam and pet / urine treatments priced as add-ons.', cta: { label: 'See carpet services', href: 'Services.html#carpet' }, visual: , align: 'center', }, { key: 'tile', span: '1 / span 4', minH: 460, bg: '#eef1f5', ink: 'var(--ink)', inkMuted: 'var(--muted)', ctaColor: 'var(--link)', eyebrow: 'Tile & vinyl', title: 'Hard floors,\nrestored.', sub: 'Grout degrease and extraction. Vinyl strip and re-coat.', cta: { label: 'Learn more', href: 'Services.html#tile' }, visual: , }, { key: 'air', span: '5 / span 4', minH: 460, bg: '#f5f5f7', ink: 'var(--ink)', inkMuted: 'var(--muted)', ctaColor: 'var(--link)', eyebrow: 'A/C & dryer vents', title: 'Clear airflow,\ndeodorized.', sub: 'Supply and return ducts, grille paint, dryer-vent lines — per unit or full property.', cta: { label: 'Learn more', href: 'Services.html#duct' }, visual: , }, { key: 'property', span: '9 / span 4', minH: 460, bg: '#111113', ink: '#fff', inkMuted: 'rgba(255,255,255,0.7)', ctaColor: '#5fb6ea', eyebrow: 'Full-property', title: 'Property-wide\nservice.', sub: 'A/C line flushes, dryer-vent campaigns and pool / deck furniture.', cta: { label: 'Request estimate', href: '#quote' }, visual: , }, ]; return (
Services

Everything a turn needs. Priced per property.

{tiles.map(t => (
))}
); } Object.assign(window, { Services });