Real Estate — Suburban Family Homes Landing
A warm, family-friendly suburban real-estate landing for the fictional Maple & Meadow brokerage, pairing a golden-hour hero rendered in pure CSS gradients with a neighborhood-and-beds search bar, a ranch/colonial/craftsman home-style chooser, and a featured-homes grid where every listing carries price, status, bed-bath-sqft specs, save-to-shortlist hearts, and a color-coded school-rating badge. Vanilla JS filters listings by style and a school-rating slider, with a community-life section, friendly tour CTA, and toast feedback throughout a fully responsive layout.
MCP
代码
:root{
/* Palette override — Suburban Family Homes */
--sage:#7d9b80; --sage-d:#647e67; --sage-700:#56705a; --sage-50:#e9efe9;
--cream:#f4efe3; --paper:#fbf8f1; --white:#ffffff;
--wood:#b5804f; --wood-d:#97683b; --wood-50:#f1e4d3;
--ink:#27302a; --ink-2:#46524b; --muted:#7b857d;
--line:rgba(39,48,42,0.12); --line-2:rgba(39,48,42,0.20);
--ok:#5a9e6f; --warn:#c98a2b; --danger:#c4503e;
--r-sm:8px; --r-md:14px; --r-lg:22px;
--sh-1:0 1px 2px rgba(39,48,42,.05), 0 2px 8px rgba(39,48,42,.05);
--sh-2:0 6px 18px rgba(39,48,42,.08), 0 2px 6px rgba(39,48,42,.05);
--sh-3:0 22px 48px rgba(56,70,52,.16), 0 8px 18px rgba(39,48,42,.08);
}
*,*::before,*::after{box-sizing:border-box;}
html{scroll-behavior:smooth;}
body{
margin:0; background:var(--cream); color:var(--ink);
font-family:"Inter",system-ui,-apple-system,sans-serif;
line-height:1.55; -webkit-font-smoothing:antialiased; text-rendering:optimizeLegibility;
}
h1,h2,h3{font-family:"Cormorant Garamond",Georgia,serif; margin:0; line-height:1.05;}
.display{font-family:"Cormorant Garamond",Georgia,serif; font-weight:600;}
.display em{font-style:italic; color:var(--wood-d);}
img{max-width:100%;display:block;}
a{color:inherit;}
.wrap{width:min(1140px,92vw); margin-inline:auto;}
.vh{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;}
/* ---------- Buttons ---------- */
.btn{
display:inline-flex; align-items:center; gap:.5rem; cursor:pointer;
font-family:"Inter",sans-serif; font-weight:600; font-size:.95rem;
border-radius:999px; padding:.72rem 1.3rem; border:1px solid transparent;
transition:transform .15s ease, box-shadow .15s ease, background .15s ease, color .15s ease;
text-decoration:none; white-space:nowrap;
}
.btn:active{transform:translateY(1px);}
.btn-solid{background:var(--sage-700); color:#fff; box-shadow:var(--sh-1);}
.btn-solid:hover{background:var(--sage-d); box-shadow:var(--sh-2); transform:translateY(-1px);}
.btn-ghost{background:transparent; color:var(--sage-700); border-color:var(--line-2);}
.btn-ghost:hover{background:var(--sage-50); border-color:var(--sage);}
:focus-visible{outline:2.5px solid var(--wood); outline-offset:2px;}
/* ---------- Header ---------- */
.site-head{
position:sticky; top:0; z-index:40;
background:rgba(251,248,241,.82); backdrop-filter:saturate(1.2) blur(10px);
border-bottom:1px solid var(--line);
}
.head-inner{display:flex; align-items:center; gap:1.4rem; padding:.85rem 0;}
.brand{display:inline-flex; align-items:center; gap:.55rem; text-decoration:none; font-weight:700;}
.brand-mark{
display:grid; place-items:center; width:36px; height:36px; border-radius:11px;
background:linear-gradient(150deg,var(--sage),var(--sage-700)); color:#fff; box-shadow:var(--sh-1);
}
.brand-text{font-family:"Cormorant Garamond",serif; font-weight:700; font-size:1.32rem; letter-spacing:.01em; color:var(--ink);}
.head-nav{display:flex; gap:1.5rem; margin-left:auto;}
.head-nav a{text-decoration:none; color:var(--ink-2); font-weight:500; font-size:.95rem; position:relative;}
.head-nav a:hover{color:var(--sage-700);}
.head-nav a::after{content:""; position:absolute; left:0; bottom:-4px; height:2px; width:0; background:var(--wood); transition:width .2s ease;}
.head-nav a:hover::after{width:100%;}
.head-cta{padding:.55rem 1.1rem; font-size:.9rem;}
/* ---------- Hero ---------- */
.hero{padding:clamp(2.2rem,6vw,4.4rem) 0 clamp(2rem,5vw,3.6rem); position:relative; overflow:hidden;}
.hero::before{content:""; position:absolute; inset:0; background:
radial-gradient(1100px 520px at 78% -8%, var(--wood-50) 0%, transparent 55%),
radial-gradient(900px 480px at 0% 10%, var(--sage-50) 0%, transparent 50%);
opacity:.7; pointer-events:none;}
.hero-grid{display:grid; grid-template-columns:1.05fr 1fr; gap:clamp(1.5rem,4vw,3.4rem); align-items:center; position:relative;}
.eyebrow{display:inline-flex; align-items:center; gap:.5rem; font-size:.82rem; font-weight:600; letter-spacing:.06em; text-transform:uppercase; color:var(--sage-700); background:var(--sage-50); padding:.42rem .8rem; border-radius:999px; border:1px solid rgba(125,155,128,.25);}
.eyebrow .dot{width:7px;height:7px;border-radius:50%;background:var(--wood);box-shadow:0 0 0 3px rgba(181,128,79,.2);}
.hero-copy h1{font-size:clamp(2.5rem,5.6vw,4rem); margin:1rem 0 .4rem; letter-spacing:-.01em; color:var(--ink);}
.lede{font-size:1.1rem; color:var(--ink-2); max-width:34ch; margin:.4rem 0 1.5rem;}
.search{
display:flex; gap:.55rem; align-items:flex-end; flex-wrap:wrap;
background:var(--white); padding:.7rem; border-radius:var(--r-lg);
border:1px solid var(--line); box-shadow:var(--sh-2); max-width:540px;
}
.search-field{display:flex; flex-direction:column; gap:.22rem; flex:1 1 auto;}
.search-beds{flex:0 0 92px;}
.search-label{font-size:.7rem; font-weight:600; text-transform:uppercase; letter-spacing:.05em; color:var(--muted); padding-left:.55rem;}
.search input, .search select{
font-family:inherit; font-size:.96rem; color:var(--ink); width:100%;
border:1px solid var(--line); border-radius:var(--r-md); padding:.62rem .7rem; background:var(--paper);
}
.search input:focus, .search select:focus{border-color:var(--sage); outline:none; background:#fff;}
.search .btn{align-self:stretch;}
.trust{list-style:none; display:flex; flex-wrap:wrap; gap:1.4rem 2rem; margin:1.6rem 0 0; padding:0;}
.trust li{font-size:.9rem; color:var(--muted);}
.trust strong{display:block; font-family:"Cormorant Garamond",serif; font-size:1.5rem; color:var(--ink); font-weight:700; line-height:1;}
/* ---------- Hero photo ---------- */
.hero-photo{
position:relative; aspect-ratio:5/4.4; border-radius:var(--r-lg); overflow:hidden;
box-shadow:var(--sh-3); border:1px solid rgba(255,255,255,.5);
}
.ph-sky{position:absolute; inset:0; background:linear-gradient(180deg,#f6dcb0 0%,#f3c98f 26%,#eecf9d 52%,#e7e0c4 100%);}
.ph-yard{position:absolute; left:0; right:0; bottom:0; height:34%; background:linear-gradient(180deg,#9bb487 0%,#7f9d70 60%,#6d8a60 100%);}
.ph-yard::after{content:""; position:absolute; inset:0; background:radial-gradient(120% 60% at 50% 120%, rgba(0,0,0,.12), transparent 60%);}
.ph-house{
position:absolute; left:18%; right:16%; bottom:20%; height:46%;
background:linear-gradient(180deg,#f3e7d4 0%,#e9d6bb 100%);
border-radius:6px 6px 3px 3px; box-shadow:0 16px 30px rgba(60,45,25,.28);
}
.ph-house::before{ /* roof */
content:""; position:absolute; left:-9%; right:-9%; top:-30%; height:36%;
background:linear-gradient(180deg,#a9683c,#8a5530);
clip-path:polygon(50% 0,100% 100%,0 100%);
filter:drop-shadow(0 6px 8px rgba(60,40,20,.3));
}
.ph-house::after{ /* door + windows */
content:""; position:absolute; inset:0;
background:
linear-gradient(#7d9b80,#647e67) 50% 100%/26% 44% no-repeat,
linear-gradient(#cfe2ef,#a9c6da) 16% 30%/22% 24% no-repeat,
linear-gradient(#cfe2ef,#a9c6da) 84% 30%/22% 24% no-repeat;
border-radius:inherit;
}
.ph-tree{position:absolute; left:5%; bottom:14%; width:90px; height:150px;}
.ph-tree::before{content:""; position:absolute; bottom:0; left:42%; width:14px; height:54px; background:linear-gradient(#8a5e36,#6f4a29); border-radius:3px;}
.ph-tree::after{content:""; position:absolute; top:0; left:0; width:90px; height:90px; border-radius:50% 50% 46% 54%; background:radial-gradient(circle at 35% 30%, #92b07e, #5e7d56); box-shadow:0 8px 18px rgba(40,60,40,.3);}
.ph-tag{position:absolute; left:14px; top:14px; font-size:.74rem; font-weight:600; color:#fff; background:rgba(39,48,42,.5); backdrop-filter:blur(4px); padding:.3rem .65rem; border-radius:999px; letter-spacing:.02em;}
.float-card{
position:absolute; right:14px; bottom:14px; background:rgba(255,253,247,.95);
backdrop-filter:blur(6px); border:1px solid rgba(255,255,255,.7);
padding:.7rem .85rem; border-radius:var(--r-md); box-shadow:var(--sh-2);
display:grid; gap:.15rem;
}
.fc-price{font-family:"Cormorant Garamond",serif; font-weight:700; font-size:1.3rem; color:var(--ink); line-height:1;}
.fc-meta{font-size:.78rem; color:var(--muted);}
/* ---------- Sections ---------- */
.section{padding:clamp(2.6rem,6vw,4.6rem) 0;}
.section-tint{background:var(--paper); border-block:1px solid var(--line);}
.sec-head{max-width:640px; margin-bottom:2rem;}
.sec-head-row{display:flex; justify-content:space-between; align-items:flex-end; gap:1.5rem; max-width:none; flex-wrap:wrap;}
.kicker{font-size:.8rem; font-weight:700; letter-spacing:.12em; text-transform:uppercase; color:var(--wood-d); margin:0 0 .4rem;}
.sec-title{font-size:clamp(1.9rem,4vw,2.8rem); color:var(--ink); letter-spacing:-.01em;}
.sec-sub{color:var(--ink-2); font-size:1.04rem; margin:.55rem 0 0;}
/* ---------- Badges ---------- */
.badge{display:inline-flex; align-items:center; gap:.3rem; font-size:.72rem; font-weight:700; letter-spacing:.03em; padding:.26rem .6rem; border-radius:999px; text-transform:uppercase;}
.badge-new{background:var(--wood); color:#fff;}
.badge-sale{background:var(--sage-50); color:var(--sage-700); border:1px solid rgba(125,155,128,.3);}
.badge-pending{background:#f6e7cf; color:var(--wood-d);}
.badge-open{background:#e8f0e9; color:var(--ok);}
/* ---------- Style chooser ---------- */
.style-row{display:grid; grid-template-columns:repeat(4,1fr); gap:1rem;}
.style-card{
text-align:left; cursor:pointer; font-family:inherit; color:var(--ink);
background:var(--white); border:1px solid var(--line); border-radius:var(--r-lg);
padding:.85rem; box-shadow:var(--sh-1); display:grid; gap:.15rem;
transition:transform .18s ease, box-shadow .18s ease, border-color .18s ease;
}
.style-card:hover{transform:translateY(-3px); box-shadow:var(--sh-2); border-color:var(--sage);}
.style-card.is-active{border-color:var(--sage-700); box-shadow:0 0 0 2px rgba(86,112,90,.35), var(--sh-2);}
.sc-art{display:block; height:78px; border-radius:var(--r-md); margin-bottom:.6rem; position:relative; overflow:hidden;}
.sc-all{background:linear-gradient(135deg,#e9efe9,#f1e4d3); }
.sc-all::after{content:"⌂"; position:absolute; inset:0; display:grid; place-items:center; font-size:2rem; color:var(--sage-700);}
.sc-ranch{background:linear-gradient(180deg,#f3e3c9,#e3cba6);}
.sc-ranch::after{content:""; position:absolute; left:14%; right:14%; bottom:20%; height:34%; background:#fff8ec; border-radius:3px; box-shadow:0 -16px 0 -4px #b5804f inset; clip-path:inset(0 round 3px);}
.sc-colonial{background:linear-gradient(180deg,#e7eef0,#cdd9d3);}
.sc-colonial::after{content:""; position:absolute; left:28%; right:28%; bottom:16%; height:52%; background:#fdfaf3; border-radius:3px 3px 0 0; box-shadow:0 -10px 0 -2px #97683b;}
.sc-craftsman{background:linear-gradient(180deg,#efe0cb,#d9bf9c);}
.sc-craftsman::after{content:""; position:absolute; left:20%; right:20%; bottom:18%; height:40%; background:#7d9b80; border-radius:2px; box-shadow:0 -8px 0 0 #8a5530;}
.sc-name{font-weight:700; font-size:1rem;}
.sc-sub{font-size:.82rem; color:var(--muted);}
/* ---------- Home grid ---------- */
.filter-school{display:grid; gap:.4rem; min-width:240px; flex:1 1 240px; max-width:320px;}
.rating-label{font-size:.9rem; color:var(--ink-2); font-weight:500;}
.rating-label strong{font-family:"Cormorant Garamond",serif; color:var(--sage-700); font-size:1.05rem; margin-left:.2rem;}
.rating-help{font-size:.78rem; color:var(--muted);}
input[type=range]{-webkit-appearance:none; appearance:none; width:100%; height:6px; border-radius:999px; background:linear-gradient(90deg,var(--sage) var(--fill,0%), var(--line-2) var(--fill,0%)); outline-offset:4px;}
input[type=range]::-webkit-slider-thumb{-webkit-appearance:none; width:20px; height:20px; border-radius:50%; background:var(--white); border:3px solid var(--sage-700); box-shadow:var(--sh-1); cursor:pointer; margin-top:0;}
input[type=range]::-moz-range-thumb{width:18px; height:18px; border-radius:50%; background:var(--white); border:3px solid var(--sage-700); cursor:pointer;}
.home-grid{display:grid; grid-template-columns:repeat(3,1fr); gap:1.4rem;}
.home{
background:var(--white); border:1px solid var(--line); border-radius:var(--r-lg);
overflow:hidden; box-shadow:var(--sh-1); display:flex; flex-direction:column;
transition:transform .2s ease, box-shadow .2s ease;
}
.home:hover{transform:translateY(-4px); box-shadow:var(--sh-3);}
.home-photo{position:relative; aspect-ratio:16/11; overflow:hidden;}
.home-photo::after{content:""; position:absolute; left:12%; right:12%; bottom:14%; height:40%; background:linear-gradient(180deg,rgba(255,253,247,.92),rgba(255,253,247,.78)); border-radius:5px; box-shadow:0 10px 22px rgba(60,45,25,.22);}
.home-photo::before{content:""; position:absolute; left:6%; right:6%; bottom:50%; top:18%; clip-path:polygon(50% 0,100% 100%,0 100%); filter:drop-shadow(0 5px 6px rgba(50,35,18,.28));}
.home-photo .roof{position:absolute; inset:0;}
.home-badges{position:absolute; left:12px; top:12px; display:flex; gap:.4rem; z-index:2; flex-wrap:wrap;}
.home-fav{
position:absolute; right:12px; top:12px; z-index:2; width:36px; height:36px; border-radius:50%;
display:grid; place-items:center; cursor:pointer; border:1px solid rgba(255,255,255,.6);
background:rgba(255,253,247,.9); backdrop-filter:blur(4px); color:var(--ink-2); box-shadow:var(--sh-1);
transition:transform .15s ease, color .15s ease, background .15s ease;
}
.home-fav:hover{transform:scale(1.08);}
.home-fav.is-fav{color:var(--danger); background:#fff;}
.home-fav.is-fav svg{fill:var(--danger);}
.home-style-tag{position:absolute; left:12px; bottom:12px; z-index:2; font-size:.7rem; font-weight:600; color:#fff; background:rgba(39,48,42,.55); backdrop-filter:blur(3px); padding:.26rem .6rem; border-radius:999px; text-transform:capitalize;}
.home-body{padding:1rem 1.05rem 1.1rem; display:flex; flex-direction:column; gap:.5rem; flex:1;}
.home-price{font-family:"Cormorant Garamond",serif; font-weight:700; font-size:1.55rem; color:var(--ink); line-height:1;}
.home-addr{font-size:.92rem; color:var(--ink-2);}
.home-addr .hood{display:block; color:var(--muted); font-size:.82rem;}
.home-specs{display:flex; gap:1rem; font-size:.85rem; color:var(--ink-2); border-top:1px solid var(--line); padding-top:.7rem; margin-top:auto;}
.home-specs span{display:inline-flex; align-items:center; gap:.3rem;}
.school{
display:flex; align-items:center; gap:.55rem; background:var(--sage-50);
border:1px solid rgba(125,155,128,.28); border-radius:var(--r-md); padding:.5rem .65rem;
}
.school-score{font-family:"Cormorant Garamond",serif; font-weight:700; font-size:1.2rem; width:34px; height:34px; display:grid; place-items:center; border-radius:9px; color:#fff;}
.school-score.s-hi{background:var(--ok);}
.school-score.s-mid{background:var(--warn);}
.school-score.s-lo{background:var(--danger);}
.school-meta{font-size:.78rem; color:var(--ink-2); line-height:1.3;}
.school-meta strong{display:block; color:var(--ink); font-weight:600; font-size:.83rem;}
.empty{text-align:center; color:var(--muted); padding:2.5rem 0; font-size:1rem;}
/* ---------- Community ---------- */
.community{display:grid; grid-template-columns:1fr 1fr; gap:clamp(1.5rem,4vw,3.2rem); align-items:center;}
.perk-list{list-style:none; margin:1.6rem 0 0; padding:0; display:grid; gap:1.05rem;}
.perk-list li{display:flex; gap:.85rem; align-items:flex-start;}
.perk-ico{flex:0 0 auto; width:44px; height:44px; border-radius:12px; display:grid; place-items:center; font-size:1.25rem; background:var(--wood-50); border:1px solid rgba(181,128,79,.25);}
.perk-list strong{display:block; font-size:1rem; color:var(--ink);}
.perk-list span{font-size:.9rem; color:var(--ink-2);}
.community-art{position:relative; aspect-ratio:1/1; border-radius:var(--r-lg); overflow:hidden; box-shadow:var(--sh-3); border:1px solid rgba(255,255,255,.5);}
.ca-sky{position:absolute; inset:0; background:linear-gradient(180deg,#bfe0ec 0%,#d8ecdc 55%,#e9efd9 100%);}
.ca-hills{position:absolute; left:0; right:0; bottom:30%; height:30%; background:radial-gradient(120% 100% at 50% 100%, #8fb083, #7c9f76); border-radius:50% 50% 0 0/100% 100% 0 0;}
.ca-path{position:absolute; left:42%; right:42%; bottom:0; height:36%; background:linear-gradient(180deg,#dcc7a3,#c9ad84); clip-path:polygon(38% 0,62% 0,100% 100%,0 100%);}
.ca-tree{position:absolute; bottom:30%;}
.ca-tree::before{content:""; position:absolute; bottom:0; left:42%; width:10px; height:34px; background:#7a5331; border-radius:2px;}
.ca-tree::after{content:""; position:absolute; bottom:24px; left:0; width:62px; height:62px; border-radius:50%; background:radial-gradient(circle at 35% 30%, #8fb07c, #5d7d54); box-shadow:0 6px 14px rgba(40,60,40,.25);}
.ca-t1{left:10%; transform:scale(.9);}
.ca-t2{right:8%; bottom:34%; transform:scale(1.15);}
.ca-t3{left:36%; bottom:46%; transform:scale(.7);}
.ca-tag{position:absolute; left:14px; bottom:14px; font-size:.74rem; font-weight:600; color:#fff; background:rgba(39,48,42,.5); backdrop-filter:blur(4px); padding:.3rem .65rem; border-radius:999px;}
/* ---------- CTA ---------- */
.cta{
background:linear-gradient(135deg,var(--sage-700),var(--sage-d) 70%); color:#fff;
border-radius:var(--r-lg); padding:clamp(1.8rem,4vw,3rem); position:relative; overflow:hidden;
display:grid; grid-template-columns:1.1fr 1fr; gap:2rem; align-items:center; box-shadow:var(--sh-3);
}
.cta::before{content:""; position:absolute; right:-60px; top:-60px; width:260px; height:260px; border-radius:50%; background:radial-gradient(circle,rgba(181,128,79,.45),transparent 70%);}
.cta-copy{position:relative;}
.cta-title{font-size:clamp(1.7rem,3.6vw,2.6rem); color:#fff;}
.cta-copy p{color:rgba(255,255,255,.85); margin:.6rem 0 0; max-width:40ch;}
.cta-form{position:relative; display:grid; gap:.7rem;}
.cta-form input{font-family:inherit; font-size:.96rem; padding:.78rem .9rem; border-radius:var(--r-md); border:1px solid rgba(255,255,255,.3); background:rgba(255,255,255,.14); color:#fff;}
.cta-form input::placeholder{color:rgba(255,255,255,.7);}
.cta-form input:focus{outline:none; background:rgba(255,255,255,.22); border-color:#fff;}
.cta-form .btn-solid{background:var(--wood); justify-content:center;}
.cta-form .btn-solid:hover{background:var(--wood-d);}
/* ---------- Footer ---------- */
.site-foot{border-top:1px solid var(--line); background:var(--paper); padding:1.6rem 0;}
.foot-inner{display:flex; justify-content:space-between; align-items:center; gap:1rem; flex-wrap:wrap;}
.foot-note{font-size:.85rem; color:var(--muted); margin:0;}
/* ---------- Toast ---------- */
.toast{
position:fixed; left:50%; bottom:26px; transform:translate(-50%,140%);
background:var(--ink); color:#fff; padding:.8rem 1.15rem; border-radius:999px;
font-size:.92rem; font-weight:500; box-shadow:var(--sh-3); z-index:90;
transition:transform .35s cubic-bezier(.2,.8,.3,1), opacity .35s ease; opacity:0; max-width:90vw;
}
.toast.show{transform:translate(-50%,0); opacity:1;}
.toast::before{content:"🏡"; margin-right:.4rem;}
/* ---------- Responsive ---------- */
@media (max-width:900px){
.hero-grid{grid-template-columns:1fr;}
.hero-photo{order:-1; aspect-ratio:16/10; max-height:340px;}
.community{grid-template-columns:1fr;}
.cta{grid-template-columns:1fr;}
.home-grid{grid-template-columns:repeat(2,1fr);}
.style-row{grid-template-columns:repeat(2,1fr);}
}
@media (max-width:520px){
.head-nav{display:none;}
.head-cta{margin-left:auto;}
.hero-copy h1{font-size:2.3rem;}
.search{flex-direction:column; align-items:stretch;}
.search-beds{flex:1 1 auto;}
.home-grid{grid-template-columns:1fr;}
.style-row{grid-template-columns:1fr 1fr;}
.sec-head-row{flex-direction:column; align-items:stretch;}
.filter-school{max-width:none;}
.trust{gap:1rem 1.4rem;}
.lede{max-width:none;}
}
@media (prefers-reduced-motion:reduce){
*{scroll-behavior:auto !important; transition-duration:.01ms !important; animation:none !important;}
}(function () {
"use strict";
/* ---------------- Toast helper ---------------- */
var toastEl = document.getElementById("toast");
var toastTimer = null;
function toast(msg) {
if (!toastEl) return;
toastEl.textContent = msg;
toastEl.classList.add("show");
clearTimeout(toastTimer);
toastTimer = setTimeout(function () {
toastEl.classList.remove("show");
}, 2600);
}
/* ---------------- Listing data ---------------- */
var HOMES = [
{
id: "mg1", price: 612000, style: "colonial", status: "new",
address: "84 Birchwood Lane", hood: "Cedar Hollow",
beds: 4, baths: 3, sqft: 2640, rating: 9,
school: "Cedar Hollow Elementary", roof: "#8a5530", body: "#f3e7d4", sky: "#f3c98f"
},
{
id: "mg2", price: 489000, style: "ranch", status: "sale",
address: "12 Sunny Meadow Ct", hood: "Maple Grove",
beds: 3, baths: 2, sqft: 1890, rating: 8,
school: "Maple Grove Primary", roof: "#a9683c", body: "#efe2cc", sky: "#f6dcb0"
},
{
id: "mg3", price: 735000, style: "craftsman", status: "open",
address: "27 Willow Bend Rd", hood: "Willowbrook",
beds: 5, baths: 4, sqft: 3120, rating: 10,
school: "Willowbrook Academy", roof: "#7a5331", body: "#e7d6bb", sky: "#eecf9d"
},
{
id: "mg4", price: 525000, style: "colonial", status: "sale",
address: "5 Garden Gate Way", hood: "Sunnyside Park",
beds: 4, baths: 3, sqft: 2410, rating: 7,
school: "Sunnyside Elementary", roof: "#8a5530", body: "#f1e3cd", sky: "#e7e0c4"
},
{
id: "mg5", price: 398000, style: "ranch", status: "pending",
address: "60 Clover Field Dr", hood: "Maple Grove",
beds: 3, baths: 2, sqft: 1640, rating: 6,
school: "Clover Field School", roof: "#a9683c", body: "#eedfca", sky: "#f3c98f"
},
{
id: "mg6", price: 668000, style: "craftsman", status: "new",
address: "19 Maplewood Terrace", hood: "Cedar Hollow",
beds: 4, baths: 3, sqft: 2780, rating: 9,
school: "Maplewood Charter", roof: "#7a5331", body: "#e9d8bd", sky: "#f6dcb0"
},
{
id: "mg7", price: 559000, style: "colonial", status: "sale",
address: "31 Hawthorne Circle", hood: "Willowbrook",
beds: 4, baths: 3, sqft: 2520, rating: 8,
school: "Hawthorne Day School", roof: "#8a5530", body: "#f3e7d4", sky: "#eecf9d"
},
{
id: "mg8", price: 432000, style: "ranch", status: "open",
address: "8 Prairie View Ln", hood: "Sunnyside Park",
beds: 3, baths: 2, sqft: 1720, rating: 5,
school: "Prairie View Elementary", roof: "#a9683c", body: "#efe2cc", sky: "#e7e0c4"
},
{
id: "mg9", price: 812000, style: "craftsman", status: "new",
address: "44 Orchard Hill Rd", hood: "Cedar Hollow",
beds: 5, baths: 4, sqft: 3340, rating: 10,
school: "Orchard Hill Magnet", roof: "#7a5331", body: "#e7d6bb", sky: "#f3c98f"
}
];
var STATUS = {
new: { cls: "badge-new", label: "Just listed" },
sale: { cls: "badge-sale", label: "For sale" },
pending: { cls: "badge-pending", label: "Pending" },
open: { cls: "badge-open", label: "Open house" }
};
var fmtPrice = new Intl.NumberFormat("en-US", {
style: "currency", currency: "USD", maximumFractionDigits: 0
});
var fmtNum = new Intl.NumberFormat("en-US");
var state = { style: "all", minRating: 1 };
var favs = {};
/* ---------------- Render ---------------- */
var grid = document.getElementById("home-grid");
var emptyEl = document.getElementById("empty");
function scoreClass(r) {
if (r >= 8) return "s-hi";
if (r >= 6) return "s-mid";
return "s-lo";
}
function cardHTML(h) {
var st = STATUS[h.status];
var sc = scoreClass(h.rating);
return (
'<article class="home" data-id="' + h.id + '">' +
'<div class="home-photo" style="background:linear-gradient(180deg,' + h.sky + ' 0%,#e7e0c4 100%)">' +
'<span class="roof" style="background:linear-gradient(180deg,' + h.roof + ',' + h.roof + ')"></span>' +
'<div class="home-badges"><span class="badge ' + st.cls + '">' + st.label + '</span></div>' +
'<button class="home-fav" type="button" aria-pressed="false" aria-label="Save ' + h.address + '">' +
'<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M12 21s-7.5-4.6-10-9.2C.2 8.4 1.9 5 5.3 5c2 0 3.4 1.1 4.7 2.8C11.3 6.1 12.7 5 14.7 5 18.1 5 19.8 8.4 22 11.8 19.5 16.4 12 21 12 21z"/></svg>' +
"</button>" +
'<span class="home-style-tag">' + h.style + "</span>" +
"</div>" +
'<div class="home-body">' +
'<div class="home-price">' + fmtPrice.format(h.price) + "</div>" +
'<div class="home-addr">' + h.address + '<span class="hood">' + h.hood + "</span></div>" +
'<div class="school">' +
'<span class="school-score ' + sc + '">' + h.rating + "</span>" +
'<span class="school-meta"><strong>' + h.school + "</strong>School rating " + h.rating + "/10</span>" +
"</div>" +
'<div class="home-specs">' +
"<span>🛏 " + h.beds + " bd</span>" +
"<span>🛁 " + h.baths + " ba</span>" +
"<span>📐 " + fmtNum.format(h.sqft) + " sqft</span>" +
"</div>" +
"</div>" +
"</article>"
);
}
function render() {
var list = HOMES.filter(function (h) {
var styleOk = state.style === "all" || h.style === state.style;
var ratingOk = h.rating >= state.minRating;
return styleOk && ratingOk;
});
grid.innerHTML = list.map(cardHTML).join("");
emptyEl.hidden = list.length !== 0;
// restore fav state
Array.prototype.forEach.call(grid.querySelectorAll(".home"), function (card) {
var id = card.getAttribute("data-id");
if (favs[id]) {
var btn = card.querySelector(".home-fav");
btn.classList.add("is-fav");
btn.setAttribute("aria-pressed", "true");
}
});
}
/* ---------------- Favorites (event delegation) ---------------- */
grid.addEventListener("click", function (e) {
var btn = e.target.closest(".home-fav");
if (!btn) return;
var card = btn.closest(".home");
var id = card.getAttribute("data-id");
favs[id] = !favs[id];
btn.classList.toggle("is-fav", favs[id]);
btn.setAttribute("aria-pressed", favs[id] ? "true" : "false");
var addr = card.querySelector(".home-addr").childNodes[0].textContent;
toast(favs[id] ? "Saved " + addr + " to your shortlist" : "Removed " + addr);
});
/* ---------------- Style chooser ---------------- */
var styleRow = document.getElementById("style-row");
styleRow.addEventListener("click", function (e) {
var card = e.target.closest(".style-card");
if (!card) return;
state.style = card.getAttribute("data-style");
Array.prototype.forEach.call(styleRow.children, function (c) {
var active = c === card;
c.classList.toggle("is-active", active);
c.setAttribute("aria-pressed", active ? "true" : "false");
});
render();
var name = card.querySelector(".sc-name").textContent;
toast(state.style === "all" ? "Showing every home style" : "Filtered to " + name + " homes");
});
/* ---------------- School-rating slider ---------------- */
var rating = document.getElementById("rating");
var ratingVal = document.getElementById("rating-val");
function syncSlider() {
var v = parseInt(rating.value, 10);
state.minRating = v;
ratingVal.textContent = v + "+";
var pct = ((v - rating.min) / (rating.max - rating.min)) * 100;
rating.style.setProperty("--fill", pct + "%");
render();
}
rating.addEventListener("input", syncSlider);
rating.addEventListener("change", function () {
toast("Showing homes rated " + rating.value + "/10 and up");
});
/* ---------------- Search form ---------------- */
var search = document.getElementById("search");
search.addEventListener("submit", function (e) {
e.preventDefault();
var hood = document.getElementById("neighborhood").value.trim();
var beds = document.getElementById("beds").value;
var parts = [];
if (hood) parts.push("in " + hood);
if (beds !== "0") parts.push(beds + "+ beds");
toast(parts.length ? "Searching homes " + parts.join(", ") + "…" : "Browsing all neighborhoods…");
document.getElementById("homes").scrollIntoView({ behavior: "smooth" });
});
/* ---------------- CTA form ---------------- */
var ctaForm = document.getElementById("cta-form");
ctaForm.addEventListener("submit", function (e) {
e.preventDefault();
var name = document.getElementById("cta-name").value.trim() || "there";
toast("Thanks " + name + " — a neighborhood guide will reach out to book your tour!");
ctaForm.reset();
});
/* ---------------- Init ---------------- */
syncSlider(); // sets fill + initial render
})();<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Maple & Meadow — Suburban Family Homes</title>
<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=Cormorant+Garamond:wght@500;600;700&family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="style.css" />
</head>
<body>
<!-- ============ HEADER ============ -->
<header class="site-head">
<div class="wrap head-inner">
<a class="brand" href="#top" aria-label="Maple and Meadow home">
<span class="brand-mark" aria-hidden="true">
<svg viewBox="0 0 24 24" width="22" height="22" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 11.5 12 4l9 7.5"/><path d="M5 10v9h14v-9"/><path d="M10 19v-5h4v5"/></svg>
</span>
<span class="brand-text">Maple & Meadow</span>
</a>
<nav class="head-nav" aria-label="Primary">
<a href="#styles">Home styles</a>
<a href="#homes">Listings</a>
<a href="#community">Community</a>
</nav>
<a href="#cta" class="btn btn-ghost head-cta">Tour a home</a>
</div>
</header>
<main id="top">
<!-- ============ HERO ============ -->
<section class="hero">
<div class="wrap hero-grid">
<div class="hero-copy">
<span class="eyebrow"><span class="dot" aria-hidden="true"></span> Welcome to the neighborhood</span>
<h1 class="display">A front porch,<br />a backyard, and<br /><em>room to grow.</em></h1>
<p class="lede">Friendly suburban homes in walkable, tree-lined neighborhoods — close to great schools, parks, and the people who make a street feel like home.</p>
<form class="search" id="search" aria-label="Search homes by neighborhood">
<label class="search-field">
<span class="search-label">Neighborhood</span>
<input id="neighborhood" name="neighborhood" type="text" list="hoods" placeholder="Maple Grove, Cedar Hollow…" autocomplete="off" />
</label>
<datalist id="hoods">
<option value="Maple Grove"></option>
<option value="Cedar Hollow"></option>
<option value="Willowbrook"></option>
<option value="Sunnyside Park"></option>
</datalist>
<label class="search-field search-beds">
<span class="search-label">Beds</span>
<select id="beds" name="beds">
<option value="0">Any</option>
<option value="3">3+</option>
<option value="4">4+</option>
<option value="5">5+</option>
</select>
</label>
<button class="btn btn-solid" type="submit">
<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><circle cx="11" cy="11" r="7"/><path d="m21 21-4.3-4.3"/></svg>
Search
</button>
</form>
<ul class="trust">
<li><strong>1,200+</strong> families moved home</li>
<li><strong>4.9★</strong> avg. neighborhood rating</li>
<li><strong>18</strong> communities</li>
</ul>
</div>
<div class="hero-photo" role="img" aria-label="Illustration of a warm two-story family home with a front porch at golden hour">
<div class="ph-sky"></div>
<div class="ph-yard"></div>
<div class="ph-house"></div>
<div class="ph-tree" aria-hidden="true"></div>
<span class="ph-tag">Cedar Hollow · golden hour</span>
<div class="float-card" aria-hidden="true">
<span class="fc-price">$612,000</span>
<span class="fc-meta">4 bd · 3 ba · 2,640 sqft</span>
<span class="badge badge-new">Just listed</span>
</div>
</div>
</div>
</section>
<!-- ============ HOME STYLE CHOOSER ============ -->
<section id="styles" class="section">
<div class="wrap">
<header class="sec-head">
<p class="kicker">Find your fit</p>
<h2 class="display sec-title">Which home style feels like you?</h2>
<p class="sec-sub">Pick a style to filter the listings below — or choose “All styles” to see everything.</p>
</header>
<div class="style-row" id="style-row" role="group" aria-label="Filter homes by style">
<button class="style-card is-active" data-style="all" aria-pressed="true">
<span class="sc-art sc-all" aria-hidden="true"></span>
<span class="sc-name">All styles</span>
<span class="sc-sub">Show everything</span>
</button>
<button class="style-card" data-style="ranch" aria-pressed="false">
<span class="sc-art sc-ranch" aria-hidden="true"></span>
<span class="sc-name">Ranch</span>
<span class="sc-sub">Single-level, easy living</span>
</button>
<button class="style-card" data-style="colonial" aria-pressed="false">
<span class="sc-art sc-colonial" aria-hidden="true"></span>
<span class="sc-name">Colonial</span>
<span class="sc-sub">Classic, symmetrical, roomy</span>
</button>
<button class="style-card" data-style="craftsman" aria-pressed="false">
<span class="sc-art sc-craftsman" aria-hidden="true"></span>
<span class="sc-name">Craftsman</span>
<span class="sc-sub">Cozy porches & warm wood</span>
</button>
</div>
</div>
</section>
<!-- ============ FEATURED HOMES ============ -->
<section id="homes" class="section section-tint">
<div class="wrap">
<header class="sec-head sec-head-row">
<div>
<p class="kicker">Featured family homes</p>
<h2 class="display sec-title">Homes ready for the next chapter</h2>
</div>
<div class="filter-school">
<label for="rating" class="rating-label">
Min. school rating <strong id="rating-val">1+</strong>
</label>
<input id="rating" type="range" min="1" max="10" step="1" value="1" aria-describedby="rating-help" />
<span id="rating-help" class="rating-help">Slide to set the lowest school rating you’ll consider.</span>
</div>
</header>
<div class="home-grid" id="home-grid" aria-live="polite"></div>
<p class="empty" id="empty" hidden>No homes match these filters yet — try a lower school rating or another style.</p>
</div>
</section>
<!-- ============ COMMUNITY LIFE ============ -->
<section id="community" class="section">
<div class="wrap community">
<div class="community-copy">
<p class="kicker">Community life</p>
<h2 class="display sec-title">More than a house — a place to belong.</h2>
<p class="sec-sub">Our neighborhoods are built around the small things that make daily life easier and weekends more fun.</p>
<ul class="perk-list">
<li>
<span class="perk-ico" aria-hidden="true">🏫</span>
<div><strong>Top-rated schools</strong><span>Walk-to-school routes and award-winning districts.</span></div>
</li>
<li>
<span class="perk-ico" aria-hidden="true">🌳</span>
<div><strong>Parks & trails</strong><span>Greenways, playgrounds, and community gardens nearby.</span></div>
</li>
<li>
<span class="perk-ico" aria-hidden="true">🛒</span>
<div><strong>Everyday errands</strong><span>Farmers markets, cafés, and grocers minutes away.</span></div>
</li>
<li>
<span class="perk-ico" aria-hidden="true">🤝</span>
<div><strong>Friendly neighbors</strong><span>Block parties, swap groups, and a watchful porch culture.</span></div>
</li>
</ul>
</div>
<div class="community-art" role="img" aria-label="Illustration of a sunny neighborhood park with trees and a path">
<div class="ca-sky"></div>
<div class="ca-hills"></div>
<div class="ca-path"></div>
<span class="ca-tree ca-t1" aria-hidden="true"></span>
<span class="ca-tree ca-t2" aria-hidden="true"></span>
<span class="ca-tree ca-t3" aria-hidden="true"></span>
<span class="ca-tag">Meadow Commons Park</span>
</div>
</div>
</section>
<!-- ============ CTA ============ -->
<section id="cta" class="section">
<div class="wrap">
<div class="cta">
<div class="cta-copy">
<h2 class="display cta-title">Let’s find your family’s next home.</h2>
<p>Book a relaxed weekend tour with a neighborhood guide — no pressure, just open doors and honest answers.</p>
</div>
<form class="cta-form" id="cta-form" aria-label="Request a tour">
<label class="vh" for="cta-name">Your name</label>
<input id="cta-name" name="name" type="text" placeholder="Your name" required />
<label class="vh" for="cta-email">Email</label>
<input id="cta-email" name="email" type="email" placeholder="[email protected]" required />
<button class="btn btn-solid" type="submit">Book a tour</button>
</form>
</div>
</div>
</section>
</main>
<footer class="site-foot">
<div class="wrap foot-inner">
<span class="brand-text">Maple & Meadow</span>
<p class="foot-note">Illustrative UI only — sample listings and data are fictional.</p>
</div>
</footer>
<div id="toast" class="toast" role="status" aria-live="polite"></div>
<script src="script.js"></script>
</body>
</html>Suburban Family Homes Landing
A welcoming marketing landing for Maple & Meadow, a fictional suburban brokerage. A serif display hero anchors a friendly headline and a two-field search bar (neighborhood with autocomplete, plus a beds selector), beside a golden-hour “photo” of a porch-front family home built entirely from layered CSS gradients — roof, windows, door, a shade tree, and a floating just-listed price card. A trust strip counts off families moved, average rating, and communities served.
Below the hero, a “find your fit” chooser lets you pick a home style — ranch, colonial, or craftsman, each with its own illustrated thumbnail — to filter the listings. The featured-homes grid renders nine fictional family homes, each with a gradient property image, a status badge (Just listed / For sale / Pending / Open house), a save-to-shortlist heart, price, address and neighborhood, bed/bath/sqft specs, and a color-coded school-rating badge (green for top schools, amber and red for lower). A community-life section and a relaxed “book a tour” CTA round out the page.
Interactions are vanilla JS only: the style chooser and a school-rating range slider filter the grid live (with an empty-state message when nothing matches), the heart buttons toggle a shortlist via event delegation, and a reusable toast() helper surfaces feedback for searches, filters, saves, and tour requests. The slider track fills as you drag, and the layout stays usable down to ~360px while respecting prefers-reduced-motion.
Illustrative UI only — sample listings and data are fictional; not a real real-estate service.