Real Estate — Luxury Estates Landing
A cinematic luxury-estate landing page with a full-bleed gradient hero, a refined inquiry bar, and an auto-rotating featured-estate switcher. A curated collection of premium listings reveals price on hover, filters by residence type, and animates in on scroll. A private-services desk, a bespoke advisor block with lifetime statistics, and an understated viewing-request form round out an editorial, invitation-only experience built in vanilla HTML, CSS and JavaScript.
MCP
Код
:root {
--ivory: #f7f4ec;
--paper: #fffdf8;
--white: #ffffff;
--green: #1f3d34;
--green-d: #16302a;
--green-700: #26493e;
--green-50: #e8efea;
--brass: #b08d57;
--brass-d: #94733f;
--brass-50: #f3ead9;
--ink: #1c2a25;
--ink-2: #33433d;
--muted: #6b7a72;
--line: rgba(31, 61, 52, 0.12);
--line-2: rgba(31, 61, 52, 0.22);
--ok: #2f9e6f;
--warn: #c98a2b;
--danger: #c4503e;
--r-sm: 8px;
--r-md: 14px;
--r-lg: 22px;
--sh-1: 0 1px 2px rgba(28, 42, 37, 0.05), 0 6px 18px rgba(28, 42, 37, 0.06);
--sh-2: 0 10px 30px rgba(28, 42, 37, 0.12), 0 30px 70px rgba(28, 42, 37, 0.1);
--ease: cubic-bezier(0.22, 0.61, 0.36, 1);
}
* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
margin: 0;
background: var(--ivory);
color: var(--ink);
font-family: "Inter", system-ui, sans-serif;
font-size: 16px;
line-height: 1.55;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
h1, h2, h3 {
font-family: "Cormorant Garamond", Georgia, serif;
font-weight: 600;
line-height: 1.08;
margin: 0;
letter-spacing: 0.005em;
}
p { margin: 0; }
img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
.wrap { width: min(1180px, 92vw); margin-inline: auto; }
.skip {
position: absolute;
left: -9999px;
top: 0;
background: var(--green);
color: var(--paper);
padding: 10px 16px;
z-index: 200;
border-radius: 0 0 var(--r-sm) 0;
}
.skip:focus { left: 0; }
/* ===== Eyebrow ===== */
.eyebrow {
font-size: 0.72rem;
letter-spacing: 0.28em;
text-transform: uppercase;
font-weight: 600;
color: var(--brass-d);
margin-bottom: 14px;
}
.eyebrow--light { color: var(--brass-50); }
.eyebrow--brass { color: var(--brass); }
/* ===== Buttons ===== */
.btn {
font-family: "Inter", sans-serif;
font-size: 0.82rem;
font-weight: 600;
letter-spacing: 0.04em;
padding: 13px 24px;
border-radius: 999px;
border: 1px solid transparent;
cursor: pointer;
transition: transform 0.5s var(--ease), background 0.4s var(--ease),
color 0.4s var(--ease), box-shadow 0.4s var(--ease), border-color 0.4s var(--ease);
}
.btn:active { transform: translateY(1px); }
.btn:focus-visible { outline: 2px solid var(--brass); outline-offset: 3px; }
.btn--brass { background: var(--brass); color: var(--green-d); border-color: var(--brass); }
.btn--brass:hover { background: var(--brass-d); color: var(--paper); box-shadow: 0 8px 22px rgba(148, 115, 63, 0.35); }
.btn--green { background: var(--green); color: var(--paper); }
.btn--green:hover { background: var(--green-700); box-shadow: 0 8px 22px rgba(31, 61, 52, 0.28); }
.btn--ghost {
background: transparent;
color: var(--green);
border-color: var(--line-2);
}
.btn--ghost:hover { border-color: var(--green); background: var(--green); color: var(--paper); }
.link {
font-size: 0.85rem;
font-weight: 600;
color: var(--green);
border-bottom: 1px solid var(--line-2);
padding-bottom: 2px;
transition: border-color 0.3s var(--ease), color 0.3s var(--ease);
}
.link:hover { color: var(--brass-d); border-color: var(--brass); }
/* ===== Topbar ===== */
.topbar {
position: sticky;
top: 0;
z-index: 100;
background: rgba(247, 244, 236, 0.82);
backdrop-filter: blur(14px) saturate(1.4);
border-bottom: 1px solid var(--line);
transition: background 0.4s var(--ease), box-shadow 0.4s var(--ease);
}
.topbar.is-scrolled { box-shadow: var(--sh-1); background: rgba(247, 244, 236, 0.94); }
.topbar__inner {
display: flex;
align-items: center;
gap: 28px;
height: 74px;
}
.brand { display: flex; align-items: center; gap: 12px; }
.brand__mark {
display: grid;
place-items: center;
width: 40px; height: 40px;
border: 1px solid var(--brass);
border-radius: 50%;
color: var(--brass-d);
font-family: "Cormorant Garamond", serif;
font-weight: 700;
font-size: 0.92rem;
letter-spacing: 0.02em;
}
.brand__name {
font-family: "Cormorant Garamond", serif;
font-size: 1.4rem;
font-weight: 600;
color: var(--green);
}
.brand__name .amp { color: var(--brass); }
.nav { display: flex; gap: 30px; margin-left: auto; }
.nav a {
font-size: 0.84rem;
font-weight: 500;
letter-spacing: 0.03em;
color: var(--ink-2);
position: relative;
padding: 4px 0;
transition: color 0.3s var(--ease);
}
.nav a::after {
content: "";
position: absolute;
left: 0; bottom: 0;
width: 0; height: 1px;
background: var(--brass);
transition: width 0.4s var(--ease);
}
.nav a:hover { color: var(--green); }
.nav a:hover::after { width: 100%; }
.nav__cta { margin-left: 4px; }
/* ===== Hero ===== */
.hero {
position: relative;
min-height: 88vh;
display: flex;
align-items: flex-end;
padding: 0 0 64px;
overflow: hidden;
color: var(--paper);
}
.hero__media { position: absolute; inset: 0; z-index: 0; }
.hero__photo {
position: absolute;
inset: 0;
transition: opacity 1.1s var(--ease), transform 8s linear;
background:
radial-gradient(120% 80% at 78% 18%, rgba(176, 141, 87, 0.55), transparent 55%),
radial-gradient(90% 70% at 10% 90%, rgba(22, 48, 42, 0.85), transparent 60%),
linear-gradient(160deg, #2c4a40 0%, #1f3d34 38%, #16302a 100%);
}
.hero__photo[data-variant="0"] {
background:
radial-gradient(120% 80% at 78% 18%, rgba(176, 141, 87, 0.55), transparent 55%),
radial-gradient(90% 70% at 10% 90%, rgba(22, 48, 42, 0.85), transparent 60%),
linear-gradient(160deg, #355a4d 0%, #1f3d34 40%, #16302a 100%);
}
.hero__photo[data-variant="1"] {
background:
radial-gradient(120% 90% at 70% 12%, rgba(214, 196, 168, 0.6), transparent 52%),
radial-gradient(80% 80% at 12% 95%, rgba(40, 60, 70, 0.9), transparent 58%),
linear-gradient(165deg, #4a5d68 0%, #2c3e46 45%, #1a262c 100%);
}
.hero__photo[data-variant="2"] {
background:
radial-gradient(130% 80% at 82% 20%, rgba(190, 150, 96, 0.55), transparent 55%),
radial-gradient(90% 80% at 8% 92%, rgba(28, 54, 66, 0.85), transparent 60%),
linear-gradient(160deg, #3c5b62 0%, #244149 42%, #14282e 100%);
}
.hero__scrim {
position: absolute;
inset: 0;
background:
linear-gradient(180deg, rgba(16, 30, 26, 0.32) 0%, rgba(16, 30, 26, 0) 30%),
linear-gradient(0deg, rgba(16, 30, 26, 0.78) 0%, rgba(16, 30, 26, 0.1) 55%);
}
.hero__inner { position: relative; z-index: 2; max-width: 760px; }
.hero__title {
font-size: clamp(2.8rem, 7vw, 5.4rem);
font-weight: 600;
margin-bottom: 22px;
text-shadow: 0 2px 30px rgba(0, 0, 0, 0.25);
}
.hero__title em { font-style: italic; color: var(--brass-50); }
.hero__lede {
font-size: clamp(1rem, 1.6vw, 1.18rem);
max-width: 540px;
color: rgba(247, 244, 236, 0.88);
margin-bottom: 30px;
}
/* inquiry bar */
.inquiry {
display: flex;
flex-wrap: wrap;
gap: 4px;
align-items: flex-end;
background: rgba(255, 253, 248, 0.94);
border: 1px solid rgba(176, 141, 87, 0.4);
border-radius: var(--r-lg);
padding: 14px;
box-shadow: var(--sh-2);
max-width: 760px;
margin-bottom: 34px;
}
.inquiry__field {
flex: 1 1 150px;
display: flex;
flex-direction: column;
padding: 6px 16px;
border-right: 1px solid var(--line);
min-width: 120px;
}
.inquiry__field:nth-child(3) { border-right: none; }
.inquiry__field label {
font-size: 0.64rem;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--muted);
margin-bottom: 4px;
font-weight: 600;
}
.inquiry__field select {
appearance: none;
border: none;
background: transparent;
font-family: "Cormorant Garamond", serif;
font-size: 1.2rem;
font-weight: 600;
color: var(--green);
cursor: pointer;
padding-right: 14px;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='7' viewBox='0 0 10 7'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%23b08d57' stroke-width='1.5' fill='none' stroke-linecap='round'/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: right center;
}
.inquiry__field select:focus-visible { outline: 2px solid var(--brass); outline-offset: 4px; border-radius: 4px; }
.inquiry__submit { flex: 1 1 160px; margin: 6px; }
/* hero switcher */
.hero__switch { display: flex; gap: 12px; flex-wrap: wrap; }
.hswitch {
display: flex;
flex-direction: column;
gap: 2px;
text-align: left;
padding: 12px 20px;
background: rgba(255, 253, 248, 0.08);
border: 1px solid rgba(247, 244, 236, 0.18);
border-radius: var(--r-md);
color: var(--paper);
cursor: pointer;
backdrop-filter: blur(6px);
transition: background 0.5s var(--ease), border-color 0.5s var(--ease), transform 0.5s var(--ease);
}
.hswitch:hover { transform: translateY(-2px); background: rgba(255, 253, 248, 0.14); }
.hswitch.is-active { background: var(--brass); border-color: var(--brass); color: var(--green-d); }
.hswitch__name { font-family: "Cormorant Garamond", serif; font-size: 1.12rem; font-weight: 600; }
.hswitch__loc { font-size: 0.7rem; letter-spacing: 0.12em; text-transform: uppercase; opacity: 0.78; }
.hswitch:focus-visible { outline: 2px solid var(--brass-50); outline-offset: 2px; }
/* ===== Strip ===== */
.strip {
background: var(--green-d);
color: var(--brass-50);
overflow: hidden;
border-bottom: 1px solid rgba(176, 141, 87, 0.25);
}
.strip__track {
display: flex;
align-items: center;
gap: 28px;
white-space: nowrap;
padding: 16px 0;
font-family: "Cormorant Garamond", serif;
font-size: 1.1rem;
letter-spacing: 0.08em;
width: max-content;
animation: marquee 28s linear infinite;
}
.strip__track .dot { color: var(--brass); }
@keyframes marquee {
from { transform: translateX(0); }
to { transform: translateX(-50%); }
}
/* ===== Sections ===== */
.section { padding: clamp(64px, 9vw, 120px) 0; }
.section--green { background: var(--green); color: var(--paper); }
.section__head {
display: flex;
align-items: flex-end;
justify-content: space-between;
gap: 24px;
margin-bottom: 48px;
flex-wrap: wrap;
}
.section__head--center { flex-direction: column; align-items: center; text-align: center; }
.section__title { font-size: clamp(2.1rem, 4vw, 3.2rem); color: var(--green); }
.section__title--light { color: var(--paper); }
.section__sub { color: rgba(247, 244, 236, 0.8); max-width: 540px; margin-top: 14px; }
/* filters */
.filters { display: flex; gap: 8px; flex-wrap: wrap; }
.chip {
font-size: 0.78rem;
font-weight: 500;
letter-spacing: 0.03em;
padding: 9px 18px;
border-radius: 999px;
border: 1px solid var(--line-2);
background: transparent;
color: var(--ink-2);
cursor: pointer;
transition: all 0.35s var(--ease);
}
.chip:hover { border-color: var(--green); color: var(--green); }
.chip.is-active { background: var(--green); color: var(--paper); border-color: var(--green); }
.chip:focus-visible { outline: 2px solid var(--brass); outline-offset: 2px; }
/* ===== Grid / Cards ===== */
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 30px 26px;
}
.card {
background: var(--paper);
border: 1px solid var(--line);
border-radius: var(--r-lg);
overflow: hidden;
box-shadow: var(--sh-1);
transition: transform 0.6s var(--ease), box-shadow 0.6s var(--ease), border-color 0.6s var(--ease);
}
.card:hover, .card:focus-within {
transform: translateY(-6px);
box-shadow: var(--sh-2);
border-color: rgba(176, 141, 87, 0.45);
}
.card:focus-visible { outline: 2px solid var(--brass); outline-offset: 3px; }
.card.is-hidden { display: none; }
.card__photo {
position: relative;
aspect-ratio: 4 / 3;
overflow: hidden;
}
.card__photo::after {
content: "";
position: absolute;
inset: 0;
background: linear-gradient(180deg, rgba(16, 30, 26, 0) 45%, rgba(16, 30, 26, 0.42) 100%);
}
.card__photo::before {
content: "";
position: absolute;
inset: 0;
transform: scale(1.02);
transition: transform 1.4s var(--ease);
}
.card:hover .card__photo::before { transform: scale(1.09); }
/* simulated photos */
.ph-1::before { background:
radial-gradient(110% 90% at 80% 14%, rgba(214, 196, 168, 0.7), transparent 52%),
linear-gradient(155deg, #6b8378 0%, #3b5a4e 50%, #24433a 100%); }
.ph-2::before { background:
radial-gradient(120% 80% at 70% 18%, rgba(176, 141, 87, 0.5), transparent 55%),
linear-gradient(160deg, #45525c 0%, #2b3a43 55%, #1b262d 100%); }
.ph-3::before { background:
radial-gradient(120% 90% at 25% 10%, rgba(226, 206, 172, 0.78), transparent 55%),
linear-gradient(150deg, #b79a6c 0%, #8c7048 45%, #5c4a2f 100%); }
.ph-4::before { background:
radial-gradient(120% 80% at 82% 20%, rgba(190, 210, 214, 0.6), transparent 52%),
linear-gradient(160deg, #5b7d83 0%, #38565c 50%, #20383d 100%); }
.ph-5::before { background:
radial-gradient(110% 80% at 75% 15%, rgba(214, 196, 168, 0.55), transparent 55%),
linear-gradient(155deg, #7c7a82 0%, #4d4b56 50%, #2c2b33 100%); }
.ph-6::before { background:
radial-gradient(120% 90% at 20% 12%, rgba(231, 225, 210, 0.8), transparent 50%),
linear-gradient(150deg, #8aa0a4 0%, #51676c 45%, #2c3e42 100%); }
.status {
position: absolute;
top: 14px; left: 14px;
z-index: 2;
font-size: 0.64rem;
font-weight: 600;
letter-spacing: 0.12em;
text-transform: uppercase;
padding: 6px 12px;
border-radius: 999px;
background: var(--paper);
color: var(--green);
}
.status--new { background: var(--green); color: var(--brass-50); }
.status--exclusive { background: var(--brass); color: var(--green-d); }
.status--pending { background: rgba(255, 253, 248, 0.92); color: var(--warn); }
.card__price {
position: absolute;
bottom: 14px; right: 14px;
z-index: 2;
font-family: "Cormorant Garamond", serif;
font-size: 1.5rem;
font-weight: 700;
color: var(--paper);
background: rgba(22, 48, 42, 0.55);
backdrop-filter: blur(4px);
border: 1px solid rgba(176, 141, 87, 0.5);
padding: 4px 16px;
border-radius: 999px;
opacity: 0;
transform: translateY(8px);
transition: opacity 0.55s var(--ease), transform 0.55s var(--ease);
}
.card:hover .card__price,
.card:focus-within .card__price { opacity: 1; transform: translateY(0); }
.card__body { padding: 22px 24px 26px; }
.card__title { font-size: 1.6rem; color: var(--green); margin-bottom: 4px; }
.card__loc { font-size: 0.8rem; letter-spacing: 0.06em; color: var(--muted); text-transform: uppercase; }
.meta {
display: flex;
gap: 16px;
list-style: none;
margin: 16px 0 0;
padding: 14px 0 0;
border-top: 1px solid var(--line);
}
.meta li { font-size: 0.82rem; color: var(--ink-2); font-weight: 500; position: relative; }
.meta li + li::before {
content: "";
position: absolute;
left: -9px; top: 50%;
width: 3px; height: 3px;
background: var(--brass);
border-radius: 50%;
transform: translateY(-50%);
}
/* ===== Services ===== */
.services {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 1px;
background: rgba(247, 244, 236, 0.16);
border: 1px solid rgba(247, 244, 236, 0.16);
border-radius: var(--r-lg);
overflow: hidden;
}
.svc {
background: var(--green);
padding: 36px 28px 40px;
transition: background 0.5s var(--ease);
}
.svc:hover { background: var(--green-700); }
.svc__no {
font-family: "Cormorant Garamond", serif;
font-size: 1.5rem;
color: var(--brass);
display: block;
margin-bottom: 18px;
}
.svc__title { font-size: 1.5rem; color: var(--paper); margin-bottom: 12px; }
.svc p { font-size: 0.9rem; color: rgba(247, 244, 236, 0.72); }
/* ===== Advisor ===== */
.advisor { background: var(--paper); }
.advisor__inner {
display: grid;
grid-template-columns: 0.85fr 1.15fr;
gap: clamp(32px, 6vw, 80px);
align-items: center;
}
.advisor__portrait { position: relative; }
.advisor__photo {
aspect-ratio: 4 / 5;
border-radius: var(--r-lg);
border: 1px solid var(--line);
box-shadow: var(--sh-2);
background:
radial-gradient(80% 60% at 50% 28%, rgba(231, 225, 210, 0.9), transparent 60%),
radial-gradient(100% 90% at 50% 120%, rgba(22, 48, 42, 0.75), transparent 60%),
linear-gradient(165deg, #c9b896 0%, #8a7a5c 45%, #3e4a40 100%);
}
.advisor__sig {
position: absolute;
bottom: -22px; right: -10px;
font-family: "Cormorant Garamond", serif;
font-size: 3.4rem;
font-weight: 700;
color: var(--brass);
opacity: 0.5;
}
.advisor__name { font-size: clamp(2.2rem, 4vw, 3rem); color: var(--green); margin-bottom: 4px; }
.advisor__role { font-size: 0.78rem; letter-spacing: 0.16em; text-transform: uppercase; color: var(--brass-d); font-weight: 600; margin-bottom: 22px; }
.advisor__bio { color: var(--ink-2); max-width: 520px; margin-bottom: 30px; }
.stats {
display: flex;
gap: 40px;
margin: 0 0 32px;
flex-wrap: wrap;
}
.stats dt { font-family: "Cormorant Garamond", serif; font-size: 2.2rem; font-weight: 700; color: var(--green); }
.stats dd { margin: 2px 0 0; font-size: 0.74rem; letter-spacing: 0.1em; text-transform: uppercase; color: var(--muted); }
.advisor__actions { display: flex; align-items: center; gap: 24px; flex-wrap: wrap; }
/* ===== CTA ===== */
.cta {
background: var(--green-d);
color: var(--paper);
padding: clamp(72px, 10vw, 130px) 0;
position: relative;
overflow: hidden;
}
.cta::before {
content: "";
position: absolute;
inset: 0;
background: radial-gradient(70% 60% at 80% 0%, rgba(176, 141, 87, 0.22), transparent 60%);
pointer-events: none;
}
.cta__inner { position: relative; max-width: 720px; text-align: center; margin-inline: auto; }
.cta__title { font-size: clamp(2.4rem, 5vw, 3.6rem); margin-bottom: 14px; }
.cta__title { color: var(--paper); }
.cta__sub { color: rgba(247, 244, 236, 0.78); margin-bottom: 34px; }
.cta__form { display: flex; flex-direction: column; gap: 14px; max-width: 620px; margin-inline: auto; }
.cta__row { display: flex; gap: 14px; }
.cta__row input {
flex: 1;
font-family: "Inter", sans-serif;
font-size: 0.92rem;
padding: 15px 20px;
border-radius: 999px;
border: 1px solid rgba(247, 244, 236, 0.24);
background: rgba(247, 244, 236, 0.06);
color: var(--paper);
transition: border-color 0.4s var(--ease), background 0.4s var(--ease);
}
.cta__row input::placeholder { color: rgba(247, 244, 236, 0.5); }
.cta__row input:focus-visible {
outline: none;
border-color: var(--brass);
background: rgba(247, 244, 236, 0.1);
}
.cta__row .btn { white-space: nowrap; }
/* ===== Footer ===== */
.footer { background: var(--ivory); border-top: 1px solid var(--line); padding: 48px 0; }
.footer__inner { display: flex; flex-direction: column; align-items: center; gap: 12px; text-align: center; }
.brand--footer .brand__name { font-size: 1.5rem; }
.footer__note { font-size: 0.84rem; color: var(--muted); letter-spacing: 0.04em; }
.footer__legal { font-size: 0.74rem; color: var(--muted); }
/* ===== Toast ===== */
.toast {
position: fixed;
bottom: 28px;
left: 50%;
transform: translate(-50%, 140%);
z-index: 300;
background: var(--green-d);
color: var(--paper);
border: 1px solid rgba(176, 141, 87, 0.5);
padding: 14px 26px;
border-radius: 999px;
font-size: 0.86rem;
box-shadow: var(--sh-2);
transition: transform 0.55s var(--ease);
max-width: 88vw;
}
.toast.is-visible { transform: translate(-50%, 0); }
/* ===== Reveal ===== */
.reveal {
opacity: 0;
transform: translateY(26px);
transition: opacity 0.9s var(--ease), transform 0.9s var(--ease);
}
.reveal.is-in { opacity: 1; transform: none; }
/* ===== Responsive ===== */
@media (max-width: 920px) {
.grid { grid-template-columns: repeat(2, 1fr); }
.services { grid-template-columns: repeat(2, 1fr); }
.advisor__inner { grid-template-columns: 1fr; }
.advisor__portrait { max-width: 420px; }
}
@media (max-width: 760px) {
.nav { display: none; }
}
@media (max-width: 520px) {
body { font-size: 15px; }
.topbar__inner { height: 64px; gap: 12px; }
.nav__cta { display: none; }
.hero { min-height: 80vh; padding-bottom: 44px; }
.hero__title { font-size: clamp(2.4rem, 11vw, 3.2rem); }
.inquiry { flex-direction: column; align-items: stretch; gap: 2px; padding: 12px; }
.inquiry__field { border-right: none; border-bottom: 1px solid var(--line); }
.inquiry__field:last-of-type { border-bottom: none; }
.inquiry__submit { margin: 8px 0 0; }
.hero__switch { gap: 8px; }
.hswitch { flex: 1 1 100%; }
.grid { grid-template-columns: 1fr; }
.services { grid-template-columns: 1fr; }
.section__head { flex-direction: column; align-items: flex-start; }
.card__price { opacity: 1; transform: none; }
.stats { gap: 26px; }
.cta__row { flex-direction: column; }
.cta__row .btn { width: 100%; }
}
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
.reveal { opacity: 1; transform: none; }
.strip__track { animation: none; }
}(function () {
"use strict";
/* ---------- Toast helper ---------- */
const toastEl = document.querySelector("[data-toast]");
let toastTimer;
function toast(msg) {
if (!toastEl) return;
toastEl.textContent = msg;
toastEl.classList.add("is-visible");
clearTimeout(toastTimer);
toastTimer = setTimeout(() => toastEl.classList.remove("is-visible"), 3200);
}
/* ---------- Sticky topbar shadow ---------- */
const topbar = document.querySelector(".topbar");
const onScroll = () => {
if (!topbar) return;
topbar.classList.toggle("is-scrolled", window.scrollY > 24);
};
window.addEventListener("scroll", onScroll, { passive: true });
onScroll();
/* ---------- Smooth scroll for data-scroll buttons ---------- */
document.querySelectorAll("[data-scroll]").forEach((btn) => {
btn.addEventListener("click", () => {
const target = document.querySelector(btn.getAttribute("data-scroll"));
if (target) target.scrollIntoView({ behavior: "smooth", block: "start" });
});
});
/* ---------- Reveal on scroll ---------- */
const reveals = document.querySelectorAll(".reveal");
if ("IntersectionObserver" in window) {
const io = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
entry.target.classList.add("is-in");
io.unobserve(entry.target);
}
});
},
{ threshold: 0.14, rootMargin: "0px 0px -40px 0px" }
);
reveals.forEach((el) => io.observe(el));
} else {
reveals.forEach((el) => el.classList.add("is-in"));
}
/* ---------- Featured estate switcher ---------- */
const heroData = [
{
title: "Estates composed<br /><em>for a quieter life.</em>",
lede: "A discreet portfolio of architecturally significant residences across coast, canyon and old-world capitals — represented by invitation.",
},
{
title: "A mountain house,<br /><em>carved into light.</em>",
lede: "Eight bedrooms above the Highlands, glass to the tree line, and thirty-five private acres an hour from the slopes.",
},
{
title: "Lake water,<br /><em>framed in stone.</em>",
lede: "A restored lakeside villa on Como — terraced gardens, a private dock, and frescoes returned to their original hand.",
},
];
const heroPhoto = document.querySelector("[data-hero-photo]");
const heroTitle = document.querySelector(".hero__title");
const heroLede = document.querySelector(".hero__lede");
const switches = Array.from(document.querySelectorAll(".hswitch"));
function setHero(idx) {
const data = heroData[idx];
if (!data) return;
switches.forEach((s, i) => {
const active = i === idx;
s.classList.toggle("is-active", active);
s.setAttribute("aria-selected", active ? "true" : "false");
});
if (heroPhoto) {
heroPhoto.style.opacity = "0";
setTimeout(() => {
heroPhoto.setAttribute("data-variant", String(idx));
heroPhoto.style.opacity = "1";
}, 260);
}
if (heroTitle) heroTitle.innerHTML = data.title;
if (heroLede) heroLede.textContent = data.lede;
}
if (heroPhoto) heroPhoto.setAttribute("data-variant", "0");
switches.forEach((s, i) => {
s.addEventListener("click", () => setHero(i));
});
// auto-rotate hero, pause on interaction
let autoIdx = 0;
let autoTimer = setInterval(rotate, 6500);
function rotate() {
autoIdx = (autoIdx + 1) % heroData.length;
setHero(autoIdx);
}
switches.forEach((s, i) => {
s.addEventListener("click", () => {
autoIdx = i;
clearInterval(autoTimer);
autoTimer = setInterval(rotate, 9000);
});
});
/* ---------- Listing filters ---------- */
const chips = Array.from(document.querySelectorAll(".chip"));
const cards = Array.from(document.querySelectorAll(".card"));
chips.forEach((chip) => {
chip.addEventListener("click", () => {
chips.forEach((c) => c.classList.remove("is-active"));
chip.classList.add("is-active");
const filter = chip.getAttribute("data-filter");
let shown = 0;
cards.forEach((card) => {
const match = filter === "all" || card.getAttribute("data-kind") === filter;
card.classList.toggle("is-hidden", !match);
if (match) shown++;
});
toast(
shown +
(shown === 1 ? " residence" : " residences") +
(filter === "all" ? " in the collection" : " · " + chip.textContent.trim())
);
});
});
/* ---------- Card activation (keyboard + click) ---------- */
cards.forEach((card) => {
const open = () => {
const title = card.querySelector(".card__title");
toast("Requesting details — " + (title ? title.textContent : "residence"));
};
card.addEventListener("click", open);
card.addEventListener("keydown", (e) => {
if (e.key === "Enter" || e.key === " ") {
e.preventDefault();
open();
}
});
});
/* ---------- Inquiry bar ---------- */
const inquiry = document.querySelector("[data-inquiry]");
if (inquiry) {
inquiry.addEventListener("submit", (e) => {
e.preventDefault();
const loc = inquiry.querySelector("#loc").value;
const kind = inquiry.querySelector("#kind").value;
toast("Portfolio en route — " + kind + " · " + loc);
});
}
/* ---------- CTA form ---------- */
const ctaForm = document.querySelector("[data-cta]");
if (ctaForm) {
ctaForm.addEventListener("submit", (e) => {
e.preventDefault();
const name = (ctaForm.querySelector('[name="name"]').value || "").trim();
const first = name.split(" ")[0] || "there";
toast("Thank you, " + first + " — an advisor will be in touch within one business day.");
ctaForm.reset();
});
}
})();<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Maison & Vale — Luxury Estates</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>
<a class="skip" href="#listings">Skip to listings</a>
<!-- ===== Top bar ===== -->
<header class="topbar" id="top">
<div class="wrap topbar__inner">
<a class="brand" href="#top" aria-label="Maison and Vale home">
<span class="brand__mark" aria-hidden="true">M&V</span>
<span class="brand__name">Maison <span class="amp">&</span> Vale</span>
</a>
<nav class="nav" aria-label="Primary">
<a href="#listings">Collection</a>
<a href="#services">Private Services</a>
<a href="#advisor">Advisors</a>
<a href="#cta">Contact</a>
</nav>
<button class="btn btn--ghost nav__cta" data-scroll="#cta">Private Viewing</button>
</div>
</header>
<!-- ===== Hero ===== -->
<section class="hero" aria-label="Featured estate">
<div class="hero__media" data-hero-media>
<div class="hero__photo" data-hero-photo></div>
<div class="hero__scrim"></div>
</div>
<div class="wrap hero__inner">
<p class="eyebrow eyebrow--light reveal">Private Collection · 2026</p>
<h1 class="hero__title reveal">
Estates composed<br /><em>for a quieter life.</em>
</h1>
<p class="hero__lede reveal">
A discreet portfolio of architecturally significant residences across coast,
canyon and old-world capitals — represented by invitation.
</p>
<form class="inquiry reveal" data-inquiry aria-label="Estate inquiry">
<div class="inquiry__field">
<label for="loc">Location</label>
<select id="loc" name="loc">
<option>Côte d'Azur, FR</option>
<option>Aspen Highlands, CO</option>
<option>Montecito, CA</option>
<option>Lake Como, IT</option>
<option>Hampstead, UK</option>
</select>
</div>
<div class="inquiry__field">
<label for="kind">Residence</label>
<select id="kind" name="kind">
<option>Villa</option>
<option>Penthouse</option>
<option>Estate & Grounds</option>
<option>Townhouse</option>
</select>
</div>
<div class="inquiry__field">
<label for="budget">Budget from</label>
<select id="budget" name="budget">
<option>$5M</option>
<option>$12M</option>
<option>$25M</option>
<option>$50M+</option>
</select>
</div>
<button class="btn btn--brass inquiry__submit" type="submit">Request Portfolio</button>
</form>
<!-- featured switcher -->
<div class="hero__switch reveal" role="tablist" aria-label="Featured estates">
<button class="hswitch is-active" role="tab" aria-selected="true" data-hero="0">
<span class="hswitch__name">Villa Soléanne</span>
<span class="hswitch__loc">Côte d'Azur</span>
</button>
<button class="hswitch" role="tab" aria-selected="false" data-hero="1">
<span class="hswitch__name">The Aspen House</span>
<span class="hswitch__loc">Highlands, CO</span>
</button>
<button class="hswitch" role="tab" aria-selected="false" data-hero="2">
<span class="hswitch__name">Casa del Lago</span>
<span class="hswitch__loc">Lake Como</span>
</button>
</div>
</div>
</section>
<!-- ===== Marquee strip ===== -->
<div class="strip" aria-hidden="true">
<div class="strip__track">
<span>Sotheby's Selects</span><span class="dot">·</span>
<span>Architectural Digest</span><span class="dot">·</span>
<span>Robb Report</span><span class="dot">·</span>
<span>Forbes Global</span><span class="dot">·</span>
<span>Sotheby's Selects</span><span class="dot">·</span>
<span>Architectural Digest</span><span class="dot">·</span>
<span>Robb Report</span><span class="dot">·</span>
<span>Forbes Global</span><span class="dot">·</span>
</div>
</div>
<!-- ===== Listings ===== -->
<section class="section" id="listings">
<div class="wrap">
<div class="section__head reveal">
<div>
<p class="eyebrow">The Collection</p>
<h2 class="section__title">Currently represented</h2>
</div>
<div class="filters" role="group" aria-label="Filter listings">
<button class="chip is-active" data-filter="all">All</button>
<button class="chip" data-filter="villa">Villas</button>
<button class="chip" data-filter="penthouse">Penthouses</button>
<button class="chip" data-filter="estate">Estates</button>
</div>
</div>
<div class="grid" data-grid>
<!-- card 1 -->
<article class="card reveal" data-kind="villa" tabindex="0">
<div class="card__photo ph-1">
<span class="status status--new">New</span>
<span class="card__price">$24.5M</span>
</div>
<div class="card__body">
<h3 class="card__title">Villa Soléanne</h3>
<p class="card__loc">Cap Ferrat · Côte d'Azur</p>
<ul class="meta">
<li>6 Beds</li><li>8 Baths</li><li>11,200 ft²</li>
</ul>
</div>
</article>
<!-- card 2 -->
<article class="card reveal" data-kind="penthouse" tabindex="0">
<div class="card__photo ph-2">
<span class="status status--exclusive">Exclusive</span>
<span class="card__price">$18.9M</span>
</div>
<div class="card__body">
<h3 class="card__title">The Vale Penthouse</h3>
<p class="card__loc">Tribeca · New York</p>
<ul class="meta">
<li>4 Beds</li><li>5 Baths</li><li>6,400 ft²</li>
</ul>
</div>
</article>
<!-- card 3 -->
<article class="card reveal" data-kind="estate" tabindex="0">
<div class="card__photo ph-3">
<span class="card__price">$41.0M</span>
</div>
<div class="card__body">
<h3 class="card__title">Hawthorne Estate</h3>
<p class="card__loc">Montecito · California</p>
<ul class="meta">
<li>9 Beds</li><li>12 Baths</li><li>22 Acres</li>
</ul>
</div>
</article>
<!-- card 4 -->
<article class="card reveal" data-kind="villa" tabindex="0">
<div class="card__photo ph-4">
<span class="status status--pending">Reserved</span>
<span class="card__price">$13.2M</span>
</div>
<div class="card__body">
<h3 class="card__title">Casa del Lago</h3>
<p class="card__loc">Tremezzina · Lake Como</p>
<ul class="meta">
<li>5 Beds</li><li>6 Baths</li><li>8,900 ft²</li>
</ul>
</div>
</article>
<!-- card 5 -->
<article class="card reveal" data-kind="penthouse" tabindex="0">
<div class="card__photo ph-5">
<span class="status status--new">New</span>
<span class="card__price">$9.8M</span>
</div>
<div class="card__body">
<h3 class="card__title">Belgravia Sky House</h3>
<p class="card__loc">Belgravia · London</p>
<ul class="meta">
<li>3 Beds</li><li>4 Baths</li><li>4,750 ft²</li>
</ul>
</div>
</article>
<!-- card 6 -->
<article class="card reveal" data-kind="estate" tabindex="0">
<div class="card__photo ph-6">
<span class="status status--exclusive">Exclusive</span>
<span class="card__price">$56.0M</span>
</div>
<div class="card__body">
<h3 class="card__title">The Aspen House</h3>
<p class="card__loc">Highlands · Aspen, CO</p>
<ul class="meta">
<li>8 Beds</li><li>10 Baths</li><li>35 Acres</li>
</ul>
</div>
</article>
</div>
</div>
</section>
<!-- ===== Private services ===== -->
<section class="section section--green" id="services">
<div class="wrap">
<div class="section__head section__head--center reveal">
<p class="eyebrow eyebrow--brass">By Arrangement</p>
<h2 class="section__title section__title--light">A private services desk</h2>
<p class="section__sub">Every Maison & Vale acquisition is accompanied by a concierge mandate — discreet, end to end.</p>
</div>
<div class="services">
<article class="svc reveal">
<span class="svc__no">01</span>
<h3 class="svc__title">Off-market access</h3>
<p>Quietly held residences never listed publicly, surfaced through a thirty-year relationship network.</p>
</article>
<article class="svc reveal">
<span class="svc__no">02</span>
<h3 class="svc__title">Acquisition counsel</h3>
<p>Valuation, structuring and cross-border closing handled by a dedicated principal advisor.</p>
</article>
<article class="svc reveal">
<span class="svc__no">03</span>
<h3 class="svc__title">Estate stewardship</h3>
<p>Renovation, staffing and seasonal management coordinated long after the keys change hands.</p>
</article>
<article class="svc reveal">
<span class="svc__no">04</span>
<h3 class="svc__title">Private viewings</h3>
<p>Charter, itinerary and on-site hosting arranged for a single afternoon or a full weekend.</p>
</article>
</div>
</div>
</section>
<!-- ===== Advisor ===== -->
<section class="section advisor" id="advisor">
<div class="wrap advisor__inner">
<div class="advisor__portrait reveal" aria-hidden="true">
<div class="advisor__photo"></div>
<span class="advisor__sig">M&V</span>
</div>
<div class="advisor__copy reveal">
<p class="eyebrow">Your Advisor</p>
<h2 class="advisor__name">Eleanor Whitmore</h2>
<p class="advisor__role">Principal · International Estates</p>
<p class="advisor__bio">
Eleanor has guided more than $2.4 billion in private residential transactions across
eleven countries. She represents a small number of clients each year, by introduction only,
and personally accompanies every viewing.
</p>
<dl class="stats">
<div><dt>$2.4B</dt><dd>Lifetime volume</dd></div>
<div><dt>11</dt><dd>Countries</dd></div>
<div><dt>32</dt><dd>Years</dd></div>
</dl>
<div class="advisor__actions">
<button class="btn btn--green" data-scroll="#cta">Request an introduction</button>
<a class="link" href="#listings">View the collection →</a>
</div>
</div>
</div>
</section>
<!-- ===== CTA ===== -->
<section class="cta" id="cta">
<div class="wrap cta__inner reveal">
<p class="eyebrow eyebrow--brass">Private Viewing</p>
<h2 class="cta__title">Arrange a discreet introduction.</h2>
<p class="cta__sub">Share a few details and a principal advisor will respond within one business day.</p>
<form class="cta__form" data-cta aria-label="Contact form">
<div class="cta__row">
<input type="text" name="name" placeholder="Full name" aria-label="Full name" required />
<input type="email" name="email" placeholder="Email address" aria-label="Email address" required />
</div>
<div class="cta__row">
<input type="text" name="interest" placeholder="Residence or location of interest" aria-label="Interest" />
<button class="btn btn--brass" type="submit">Request Viewing</button>
</div>
</form>
</div>
</section>
<!-- ===== Footer ===== -->
<footer class="footer">
<div class="wrap footer__inner">
<div class="brand brand--footer">
<span class="brand__mark" aria-hidden="true">M&V</span>
<span class="brand__name">Maison <span class="amp">&</span> Vale</span>
</div>
<p class="footer__note">Private residential representation · By invitation</p>
<p class="footer__legal">© 2026 Maison & Vale. Fictional brand for demonstration.</p>
</div>
</footer>
<div class="toast" data-toast aria-live="polite"></div>
<script src="script.js"></script>
</body>
</html>Luxury Estates Landing
An editorial landing page for a fictional invitation-only estate brokerage, Maison & Vale. The full-bleed hero simulates cinematic property photography with layered CSS gradients, pairs a Cormorant Garamond display headline with a glassy inquiry bar, and rotates between three featured estates — each swap fades the backdrop and rewrites the headline and lede. A small tablist lets visitors switch manually, which pauses the auto-rotation.
Below the hero, an animated marquee of press marks gives way to the curated collection: six premium listings rendered as refined cards with warm gradient “photos”, status badges, and a price chip that reveals on hover or focus. Filter chips narrow the grid by residence type and surface a toast with the result count. Cards are keyboard-operable, and every section animates in gently on scroll via IntersectionObserver.
The page closes with a four-part private-services desk on a deep-green field, a bespoke advisor block carrying lifetime statistics, and an understated viewing-request CTA. Both the inquiry bar and the contact form are wired to a shared toast() helper for friendly, non-blocking confirmation. Everything is self-contained vanilla HTML, CSS and JavaScript, responsive down to roughly 360px, and respects prefers-reduced-motion.
Illustrative UI only — sample listings and data are fictional; not a real real-estate service.