:root {
    --ink: #14181d;
    --paper: #faf8f4;
    --muted: #5b6169;
    --gold: #a9865a;
    --gold-light: #c6a677;
    /* Same gold family, darkened until it clears 4.5:1 against --paper (verified: ~4.7:1) —
       --gold itself only measures ~3.2:1 on paper, which fails WCAG AA for normal-size text.
       Use this for gold TEXT sitting on paper/white; --gold stays fine for gold-on-dark-ink
       text (contact section, dark cards) and for large/decorative uses (buttons, borders). */
    --gold-ink: #8a6a3f;
    --line: rgba(20, 24, 29, 0.1);
    --grid-line: rgba(20, 24, 29, 0.055);
    --sky-top: #1b2027;
    --sky-mid: #3c3220;
    --header-h: 84px;
    /* AUREA editorial-luxury additions — same palette, new hairlines/serif accents */
    --gold-hairline: rgba(169, 134, 90, 0.28);
    --gold-hairline-dark: rgba(169, 134, 90, 0.22);
    --paper-dim: rgba(250, 248, 244, 0.62);
    --font-serif: 'Frank Ruhl Libre', Georgia, serif;
    --ease-lux: cubic-bezier(0.22, 1, 0.36, 1);
}

* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

html {
    scroll-behavior: smooth;
}

body {
    font-family: 'Assistant', sans-serif;
    color: var(--ink);
    background: var(--paper);
    overflow-x: hidden;
}

/* Scroll stays locked until the loader's fade-out finishes and script.js
   removes this class. overflow:hidden only (no height constraint) — clamping
   the root's height would clip the document and break the hero pin's
   ScrollTrigger measurement of the tall pinned page. */
html.is-loading body {
    overflow: hidden;
}

/* ════════════════════════════════════════════════════════════
   Luxury preloader
   ════════════════════════════════════════════════════════════ */

.loader {
    position: fixed;
    inset: 0;
    z-index: 999;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
}

/* A moody radial vignette, not the hero's linear sky — that gradient ends
   in bright --paper at the bottom, which reads fine cross-fading into the
   hero but looks like a washed-out band on this screen's own dark backdrop
   now that the loader slides away instead of fading. Stays entirely within
   the ink/gold palette: warm bronze glow near the wordmark, deepening to
   near-black at the corners. */
.loader__sky {
    position: absolute;
    inset: 0;
    background: radial-gradient(130% 95% at 50% 22%, var(--sky-mid) 0%, var(--sky-top) 52%, #0d0b08 100%);
}

/* Same noise technique/values as .contact-noise — barely perceptible grain,
   not a new texture invented for this screen. */
.loader__noise {
    position: absolute;
    inset: 0;
    opacity: 0.05;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
    background-size: 200px 200px;
    mix-blend-mode: overlay;
}

/* Volumetric light — a soft, entirely static vertical beam of studio light
   behind the wordmark. No motion, no pulsing; just ambient presence. */
.loader__glow {
    position: absolute;
    top: -12%;
    left: 50%;
    width: min(60vw, 640px);
    height: 85vh;
    transform: translateX(-50%);
    background: radial-gradient(closest-side, rgba(169, 134, 90, 0.16), rgba(169, 134, 90, 0) 72%);
    filter: blur(6px);
    pointer-events: none;
}

.loader__inner {
    position: relative;
    z-index: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 26px;
}

.loader__logoWrap {
    position: relative;
    overflow: hidden;
    line-height: 1;
}

/* Same logo asset as the hero, sized up as this preloader's centerpiece. */
.loader__logo {
    display: block;
    width: clamp(210px, 28vw, 340px);
    height: auto;
}

.loader__percent {
    font-family: 'Heebo', sans-serif;
    font-weight: 300;
    font-size: 26px;
    letter-spacing: 0.08em;
    color: var(--gold-light);
    font-variant-numeric: tabular-nums;
}

.loader__bar {
    position: relative;
    width: 180px;
    height: 2px;
    background: var(--gold-hairline-dark);
    overflow: hidden;
}

.loader__barFill {
    display: block;
    height: 100%;
    width: 0%;
    background: var(--gold);
}

/* A quiet reflection along the bar's top edge — not a glow. */
.loader__barSheen {
    position: absolute;
    inset: 0 0 auto 0;
    height: 1px;
    background: linear-gradient(90deg, transparent, rgba(250, 248, 244, 0.3), transparent);
    pointer-events: none;
}

@media (max-width: 640px) {
    .loader__logo {
        width: clamp(160px, 52vw, 230px);
    }

    .loader__percent {
        font-size: 19px;
    }

    .loader__bar {
        width: 130px;
    }

    .loader__inner {
        gap: 20px;
    }
}

@media (prefers-reduced-motion: reduce) {
    .loader {
        display: none !important;
    }

    html.is-loading body {
        overflow: visible !important;
    }
}

img {
    display: block;
    max-width: 100%;
}

a {
    text-decoration: none;
    color: inherit;
}

section[id] {
    scroll-margin-top: var(--header-h);
}

::selection {
    background: var(--gold);
    color: var(--ink);
}

:focus-visible {
    outline: 2px solid var(--gold);
    outline-offset: 3px;
    border-radius: 2px;
}

/* Custom scrollbar — Firefox + WebKit, degrades gracefully everywhere else */
html {
    scrollbar-color: var(--gold) var(--paper);
    scrollbar-width: thin;
}

::-webkit-scrollbar {
    width: 10px;
}

::-webkit-scrollbar-track {
    background: var(--paper);
}

::-webkit-scrollbar-thumb {
    background: var(--gold);
    border-radius: 999px;
    border: 2px solid var(--paper);
}

/* ---------- Scroll progress indicator ---------- */

.scroll-progress {
    position: fixed;
    top: 0;
    right: 0;
    height: 3px;
    width: 100%;
    background: linear-gradient(90deg, var(--gold-light), var(--gold));
    transform: scaleX(0);
    transform-origin: right center;
    z-index: 200;
    pointer-events: none;
}

/* ---------- Header ---------- */

.site-header {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: var(--header-h);
    z-index: 100;
    /*
       Low-opacity black panel with white text/logo — since the header is only ever
       shown past the hero now (never during it), this one scheme has to stay legible
       over whatever content sits underneath as the page scrolls (white sections, the
       dark contact section, etc). A dark backdrop behind light text holds contrast
       consistently regardless of what's behind it, rather than needing a light/dark
       swap per section.
    */
    background: rgba(20, 24, 29, 0.55);
    backdrop-filter: blur(14px) saturate(140%);
    -webkit-backdrop-filter: blur(14px) saturate(140%);
    border-bottom: 1px solid rgba(250, 248, 244, 0.08);
    /*
       Not shown at all on the hero — see .header-visible, toggled from script.js
       once the user has scrolled past the hero's full (pinned) scroll range.
       visibility (not just opacity/pointer-events) keeps the hidden nav links out
       of the keyboard tab order entirely — the visibility switch is delayed until
       the fade-out finishes so it doesn't cut the transition short, but happens
       immediately when revealing.
    */
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition: opacity 0.4s ease, visibility 0s linear 0.4s, background-color 0.35s ease, box-shadow 0.35s ease, border-color 0.35s ease, transform 0.4s ease;
}

.site-header.header-visible {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    transition: opacity 0.4s ease, visibility 0s linear 0s, background-color 0.35s ease, box-shadow 0.35s ease, border-color 0.35s ease, transform 0.4s ease;
}

/*
   In practice this is the state that's actually seen: heroScrollEnd (the point the
   header can even become visible) is always several viewport-heights of scroll, far
   past this rule's 40px threshold — so .scrolled is active from the header's very
   first appearance onward. 0.65 alpha was picked by checking contrast against the
   lightest section backgrounds (pure white): it's the lowest opacity that still
   clears 4.5:1 for the white nav text against a white page section behind it.
*/
.site-header.scrolled {
    background: rgba(20, 24, 29, 0.65);
    box-shadow: 0 12px 30px -22px rgba(0, 0, 0, 0.4);
    border-bottom-color: rgba(250, 248, 244, 0.12);
}

/* Tucks away while scrolling down through content, reappears the moment the user
   scrolls back up — keeps the frosted bar from competing with the page for attention
   during a long read, without ever losing access to it. */
.site-header.header-hidden {
    transform: translateY(-100%);
}

.header-inner {
    max-width: 1320px;
    height: 100%;
    margin: 0 auto;
    padding: 0 40px;
    display: flex;
    align-items: center;
    justify-content: space-between;
}

.logo {
    font-family: 'Heebo', sans-serif;
    font-size: 22px;
    font-weight: 600;
    letter-spacing: 0.14em;
    color: var(--paper);
}

.header-inner img.logo {
    display: block;
    height: 64px;
    width: auto;
}

.main-nav {
    display: flex;
    gap: 40px;
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
}

/* Desktop only: group the logo with the nav links instead of leaving the
   centered nav to float independently of it — .nav-toggle is display:none
   here already, so .header-inner's only real flex children left are the
   logo and (once un-absolutized) the nav, letting `gap` sit them close
   together as one centered unit. Mobile keeps the base rules untouched:
   .main-nav is display:none there anyway, and .header-inner still needs
   its space-between to hold logo/toggle at opposite edges. */
@media (min-width: 861px) {
    .header-inner {
        justify-content: center;
        gap: 32px;
    }

    .main-nav {
        position: static;
        transform: none;
    }
}

.main-nav a {
    position: relative;
    padding-bottom: 4px;
    font-size: 14.5px;
    font-weight: 500;
    color: var(--paper);
    opacity: 0.85;
    transition: opacity 0.25s ease;
}

.main-nav a::after {
    content: '';
    position: absolute;
    right: 0;
    left: 0;
    bottom: 0;
    height: 1px;
    background: var(--gold);
    transform: scaleX(0);
    transition: transform 0.3s ease;
}

.main-nav a:hover {
    opacity: 1;
}

.main-nav a:hover::after {
    transform: scaleX(1);
}

.nav-toggle {
    display: none;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 5px;
    /* 44px meets the mobile touch-target guideline — the bars themselves
       stay their original ~32px width (set on the span below) so the icon
       doesn't visually balloon to match, just gains tappable padding. */
    width: 44px;
    height: 44px;
    background: none;
    border: none;
    cursor: pointer;
    z-index: 110;
}

.nav-toggle span {
    display: block;
    width: 32px;
    height: 2px;
    background: var(--paper);
    transition: transform 0.3s ease, opacity 0.3s ease;
}

.nav-toggle.open span:nth-child(1) {
    transform: translateY(7px) rotate(45deg);
}

.nav-toggle.open span:nth-child(2) {
    opacity: 0;
}

.nav-toggle.open span:nth-child(3) {
    transform: translateY(-7px) rotate(-45deg);
}

.mobile-nav {
    display: none;
    position: fixed;
    top: 0;
    left: -100%;
    width: min(78vw, 360px);
    height: 100vh;
    /* Safe to keep dvh here specifically: position:fixed removes this
       drawer from document flow entirely, so its height changing as mobile
       chrome shows/hides can't shift any other element's document position
       or feed into ScrollTrigger's pin math — unlike the sections noted
       elsewhere in this file that had this reverted back to plain vh. */
    height: 100dvh;
    background: var(--paper);
    flex-direction: column;
    align-items: flex-start;
    justify-content: center;
    gap: 28px;
    padding: 40px;
    transition: left 0.45s cubic-bezier(0.22, 1, 0.36, 1);
    z-index: 105;
    box-shadow: 12px 0 40px rgba(0, 0, 0, 0.08);
}

.mobile-nav.open {
    left: 0;
}

.mobile-nav a {
    font-family: 'Heebo', sans-serif;
    font-size: 26px;
    font-weight: 300;
    letter-spacing: 0.04em;
    transition: color 0.25s ease;
}

.mobile-nav a:hover {
    color: var(--gold);
}

/* ---------- Hero ---------- */

.hero {
    position: relative;
    width: 100%;
    /*
       Deliberately plain 100vh, not 100dvh — this section is a GSAP
       ScrollTrigger pin target. dvh recalculates live as the mobile
       browser's chrome (address bar) shows/hides DURING scroll, which
       fires a native resize event; the site's resize handler responds by
       calling ScrollTrigger.refresh(), which recomputes every pin's
       position against the now-different element heights. For a pinned
       section that's a live layout shift happening mid-scroll — it desyncs
       this pin's own math and shifts the document position of everything
       below it (testimonials, the statement banner, contact), which is
       exactly what caused those sections to visibly snap/bounce on mobile.
       vh is fixed at layout time and never changes mid-scroll, which is
       what pin math actually needs, even though it means this section is
       sized slightly taller than the visible area while mobile chrome is
       showing — a real but far smaller cosmetic issue than a broken pin.
    */
    height: 100vh;
    min-height: 640px;
    overflow: hidden;
    background: var(--paper);
}

.hero-sky {
    position: absolute;
    inset: 0;
    /* Radial vignette layered over the linear dusk gradient adds cinematic depth
       (darker corners) without needing any photographic asset. */
    background:
        radial-gradient(120% 70% at 50% 0%, rgba(0, 0, 0, 0.18), transparent 65%),
        linear-gradient(180deg, var(--sky-top) 0%, var(--sky-mid) 58%, var(--paper) 100%);
    will-change: transform;
    opacity: 0;
}

.hero-content {
    position: relative;
    z-index: 2;
    height: 100%;
    width: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    /* Vertically centered in the viewport, and nudged right-of-center horizontally:
       align-items: center centers the block within the padded content box, and
       giving it more padding on the left than the right shrinks/shifts that box
       toward the right side of the screen — not a hard edge, just leaning right. */
    justify-content: center;
    padding-right: 1vw;
    padding-left: 45vw;
    text-align: center;
}

.hero-logo {
    width: min(480px, 75vw);
    height: auto;
    margin-bottom: 6px;
    opacity: 0;
    will-change: opacity;
}

.hero-title {
    /* Heebo Black — matches the reference composition's bold display headline.
       No negative letter-spacing needed: Heebo at weight 900 is a UI-grade
       Hebrew/Latin sans drawn tight by default. */
    font-family: 'Heebo', 'Assistant', sans-serif;
    font-weight: 900;
    font-size: clamp(2.6rem, 6.5vw, 6rem);
    line-height: 1.1;
    color: var(--paper);
    text-shadow: 0 2px 30px rgba(0, 0, 0, 0.25);
    /* 3D context for the per-character rotateX stagger set up in script.js */
    perspective: 600px;
    opacity: 0;
    will-change: opacity;
}

.hero-title .char {
    will-change: transform, opacity;
}

.hero-subtitle {
    margin-top: 22px;
    font-size: clamp(1rem, 1.4vw, 1.2rem);
    color: rgba(250, 248, 244, 0.75);
    max-width: 40ch;
    opacity: 0;
    transform: translateY(20px);
    will-change: transform, opacity;
}

.hero-cta {
    margin-top: 38px;
    display: inline-flex;
    align-items: center;
    gap: 10px;
    padding: 16px 34px;
    background: var(--gold);
    color: var(--ink);
    font-size: 14.5px;
    font-weight: 700;
    border-radius: 999px;
    opacity: 0;
    transform: translateY(15px) scale(0.97);
    will-change: transform, opacity;
    transition: transform 0.35s ease, background-color 0.35s ease, box-shadow 0.35s ease;
}

.hero-cta:hover {
    background: var(--gold-light);
    transform: translateY(-3px);
    box-shadow: 0 16px 32px -12px rgba(169, 134, 90, 0.55);
}

.cta-arrow {
    display: inline-block;
    transition: transform 0.3s ease;
}

.hero-cta:hover .cta-arrow {
    transform: translateX(-5px);
}

/* Scroll-scrubbed hero video layer — sits above the sky gradient (which stays as the
   fallback backdrop while the video loads or if it fails) and below the text content. */
.hero-video-wrap {
    position: absolute;
    inset: 0;
    z-index: 1;
    opacity: 0;
    pointer-events: none;
    will-change: opacity;
}

/* Canvas is replaced content like <img>/<video>, so object-fit: cover crops its
   2556x1440 bitmap to fill the hero exactly like the old video did. */
.hero-canvas {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* Contrast scrim over the video: dark at the top (behind the light title/nav area)
   and at the bottom (seam into the next section), lighter through the middle so
   the footage still reads clearly. Keeps the paper-colored title at readable
   contrast no matter what frame the scrub lands on. */
.hero-video-wrap::after {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg,
        rgba(20, 24, 29, 0.55) 0%,
        rgba(20, 24, 29, 0.2) 45%,
        rgba(20, 24, 29, 0.6) 100%);
}

/* ════════════════════════════════════════════════════════════
   FROM HERE DOWN — AUREA editorial-luxury redesign.
   Same palette (ink / paper / gold), new language: hairline gold
   rules, thin display weights, square corners, serif accents,
   generous air. Selectors are unchanged — script.js depends on them.
   ════════════════════════════════════════════════════════════ */

/* ---------- Shared section layout ---------- */

.section-inner {
    position: relative;
    z-index: 2;
    max-width: 1320px;
    margin: 0 auto;
    padding: 160px 40px;
}

.eyebrow {
    display: flex;
    align-items: center;
    gap: 16px;
    font-size: 12.5px;
    font-weight: 600;
    letter-spacing: 0.22em;
    color: var(--gold-ink);
    margin-bottom: 26px;
}

/* Hairline gold rule opening every eyebrow — sits on the reading-start (right)
   side in RTL automatically, since it's simply the first flex item. */
.eyebrow::before {
    content: '';
    width: 44px;
    height: 1px;
    background: var(--gold);
    flex-shrink: 0;
}

.section-heading {
    font-family: 'Heebo', sans-serif;
    font-weight: 200;
    font-size: clamp(2.4rem, 5vw, 4.6rem);
    letter-spacing: -0.01em;
    line-height: 1.08;
    max-width: 20ch;
}

.section-lede {
    margin-top: 26px;
    color: var(--muted);
    max-width: 58ch;
    font-size: 1.05rem;
    font-weight: 400;
    line-height: 1.9;
}

.section-head {
    margin-bottom: 90px;
}

.reveal {
    opacity: 0;
    transform: translateY(30px);
    will-change: transform, opacity;
}

/* ---------- Properties (shared shell for showcase + catalog) ---------- */
/* Unified onto the same dark "gallery room" language as why-aurea /
   featured-project / testimonials — every section between About and
   Testimonials used to be a stray white page floating between black ones;
   ink background + gold-tinted grid + paper text everywhere below. */

/* Scrolls normally with the page (default background-attachment) — same
   112px size used on .why-aurea/.lifestyle-expand-bg/.testimonials below. */
.properties,
.process {
    position: relative;
    background-image:
        linear-gradient(rgba(169, 134, 90, 0.05) 1px, transparent 1px),
        linear-gradient(90deg, rgba(169, 134, 90, 0.05) 1px, transparent 1px);
    background-size: 112px 112px;
}

.properties {
    background-color: var(--ink);
}

.properties .eyebrow,
.lifestyle .eyebrow,
.process .eyebrow {
    color: var(--gold);
}

.properties .section-heading,
.lifestyle .section-heading,
.process .section-heading {
    color: var(--paper);
}

.properties .section-lede,
.lifestyle .section-lede,
.process .section-lede {
    color: var(--paper-dim);
}

.property-title {
    font-family: 'Heebo', sans-serif;
    font-weight: 300;
    letter-spacing: 0.01em;
}

.property-location {
    margin-top: 12px;
    font-size: 0.82rem;
    font-weight: 600;
    letter-spacing: 0.18em;
}

.property-specs {
    margin-top: 18px;
    font-size: 0.95rem;
    line-height: 1.7;
}

.property-price {
    margin-top: 26px;
    padding-top: 18px;
    border-top: 1px solid var(--gold-hairline);
    font-family: 'Heebo', sans-serif;
    font-weight: 400;
    letter-spacing: 0.03em;
}

.property-link {
    margin-top: 28px;
    display: inline-flex;
    align-items: center;
    gap: 10px;
    font-size: 0.8rem;
    font-weight: 700;
    letter-spacing: 0.16em;
    /* Light-context default (used on white property cards) — gold-ink clears 4.5:1. */
    color: var(--gold-ink);
    border-bottom: 1px solid var(--gold-hairline);
    padding-bottom: 6px;
    transition: color 0.25s ease, border-color 0.25s ease;
    width: fit-content;
}

.property-link:hover {
    color: var(--gold-light);
    border-color: var(--gold-light);
}

.property-link .link-arrow {
    transition: transform 0.3s ease;
}

.property-link:hover .link-arrow {
    transform: translateX(-5px);
}

.property-panel-content .property-title {
    font-size: 2.1rem;
    color: var(--paper);
}

.property-panel-content .property-location {
    color: var(--gold);
}

.property-panel-content .property-specs {
    color: var(--paper-dim);
}

.property-panel-content .property-price {
    font-size: 1.6rem;
    font-weight: 300;
    color: var(--paper);
    border-top-color: var(--gold-hairline-dark);
}

/* Dark-context override — the plain --gold already clears 4.5:1 against the ink
   background here, and reads brighter/richer than gold-ink would on dark.
   Shared with .catalog-card, now also on an ink background. */
.property-panel-content .property-link,
.catalog-card .property-link {
    color: var(--gold);
    border-color: var(--gold-hairline-dark);
}

.property-panel-content .property-link:hover,
.catalog-card .property-link:hover {
    color: var(--gold-light);
    border-color: var(--gold-light);
}

/* ---------- Property showcase (animated tabs) ---------- */
/* The sliding "bubble": a dark pill that glides behind the active tab.
   script.js drives it with translateX + width via getBoundingClientRect
   (moveIndicator in script.js) — CSS only needs to give it a shape and the
   fixed vertical inset (top/height) that math assumes. Square-cornered pill
   edges swapped for the AUREA language elsewhere would break that assumption
   nowhere here, so this stays close to the original pill treatment, just
   re-toned to the gold/ink palette (gold ring on the bar, gold-lit shadow
   under the moving pill). */

.property-tabs {
    display: flex;
    flex-direction: column;
    gap: 44px;
}

.property-tabs-bar {
    position: relative;
    display: flex;
    /* No wrapping — script.js positions the indicator with a single left-based
       offset (getBoundingClientRect delta), which only stays correct as long as
       every tab sits on one row. Overflow scrolls horizontally instead on narrow
       screens rather than wrapping to a second row. */
    flex-wrap: nowrap;
    gap: 2px;
    width: fit-content;
    max-width: 100%;
    overflow-x: auto;
    background: rgba(169, 134, 90, 0.05);
    border: 1px solid var(--gold-hairline);
    padding: 6px;
    border-radius: 999px;
}

.property-tabs-indicator {
    position: absolute;
    top: 6px;
    /* Anchored from the left to match script.js's translateX math, which computes
       btnRect.left - barRect.left — a physical (left-edge-relative) offset that's
       the same regardless of RTL. Anchoring this element from the right instead
       would silently put every translateX() value in the wrong coordinate space. */
    left: 0;
    bottom: auto;
    height: calc(100% - 12px);
    width: 0;
    border-radius: 999px;
    /* Elevated dark surface, one notch lighter than the section's own ink
       background — the bubble needs to read as a distinct pill, not vanish
       into the now-dark .properties background it used to contrast against
       as a white section. */
    background: #181d23;
    box-shadow: 0 10px 24px -12px rgba(169, 134, 90, 0.45);
    z-index: 0;
    pointer-events: none;
}

.property-tab {
    position: relative;
    z-index: 1;
    padding: 12px 24px;
    border: none;
    background: transparent;
    font-family: 'Assistant', sans-serif;
    font-size: 0.92rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    color: var(--paper);
    white-space: nowrap;
    cursor: pointer;
    border-radius: 999px;
    transition: color 0.3s ease;
}

.property-tab:hover {
    color: var(--gold-light);
}

.property-tab.active {
    color: var(--paper);
}

.property-tab.active:hover {
    color: var(--paper);
}

.property-panel {
    position: relative;
    display: grid;
    grid-template-columns: 1fr;
    background: var(--ink);
    border: 1px solid var(--gold-hairline-dark);
    border-radius: 24px;
    overflow: hidden;
    transition: box-shadow 0.4s ease, border-color 0.4s ease;
}

/* Same cursor-following spotlight ring as .catalog-card::before, and the
   same --mx/--my custom properties (set on mousemove in script.js) — copied
   here so this single showcase panel gets the identical framing/glow
   treatment as the catalog grid's cards below. */
.property-panel::before {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 2;
    border-radius: inherit;
    padding: 1px;
    background: radial-gradient(220px circle at var(--mx, 50%) var(--my, 0%), rgba(169, 134, 90, 0.65), transparent 65%);
    -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
    -webkit-mask-composite: xor;
    mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
    mask-composite: exclude;
    opacity: 0;
    transition: opacity 0.4s ease;
    pointer-events: none;
}

.property-panel:hover::before {
    opacity: 1;
}

.property-panel:hover {
    border-color: rgba(169, 134, 90, 0.45);
    box-shadow: 0 30px 60px -38px rgba(0, 0, 0, 0.7);
}

.property-panel-media {
    position: relative;
    min-height: 280px;
}

.property-panel-media img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.property-panel-media .property-badge {
    position: absolute;
    top: 20px;
    right: 20px;
    background: var(--gold);
    color: var(--ink);
    font-size: 11.5px;
    font-weight: 700;
    letter-spacing: 0.16em;
    padding: 9px 18px;
    border-radius: 999px;
}

.property-panel-content {
    position: relative;
    padding: 56px 48px;
    display: flex;
    flex-direction: column;
    justify-content: center;
}

/* ---------- Property catalog (full listing, below the tabs showcase) ---------- */

.catalog-head {
    margin-top: 110px;
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 12px;
    padding-top: 44px;
    border-top: 1px solid var(--gold-hairline-dark);
}

.catalog-title {
    font-family: 'Heebo', sans-serif;
    font-weight: 200;
    font-size: clamp(1.7rem, 2.6vw, 2.4rem);
    color: var(--paper);
}

.catalog-count {
    color: var(--paper-dim);
    font-size: 0.85rem;
    letter-spacing: 0.08em;
}

.catalog-toolbar {
    margin-top: 36px;
    display: flex;
    align-items: flex-end;
    flex-wrap: wrap;
    gap: 28px;
}

.catalog-filter {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.catalog-filter label {
    font-size: 11.5px;
    font-weight: 700;
    letter-spacing: 0.2em;
    color: var(--gold);
}

/* Editorial underline fields — no boxes, just a hairline that warms to gold. */
.catalog-filter select {
    appearance: none;
    font-family: 'Assistant', sans-serif;
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--paper);
    background: transparent;
    border: none;
    border-bottom: 1px solid var(--gold-hairline-dark);
    border-radius: 0;
    padding: 10px 4px 12px 32px;
    min-width: 170px;
    cursor: pointer;
    /* Simple inline chevron so the native select still reads as a dropdown
       without pulling in an icon font — positioned for RTL (opens/reads
       right-to-left, so the indicator sits on the left, the "end" of the field).
       Stroke is gold-light (not the dark gold-ink used on paper) so it's
       visible against this section's ink background. */
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath d='M5 8l5 5 5-5' fill='none' stroke='%23c6a677' stroke-width='1.4' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: left 4px center;
    background-size: 15px;
    transition: border-color 0.25s ease;
}

/* The select shell's transparent background is fine sitting over this
   section's own dark background, but that transparency doesn't carry into
   the native dropdown popup — browsers paint that with their own default
   (usually white), leaving the options' inherited white text unreadable.
   Giving the options an explicit dark background fixes the popup itself,
   independent of the shell's own transparent look. */
.catalog-filter select option {
    color: var(--paper);
    background-color: var(--ink);
}

.catalog-filter select:hover {
    border-bottom-color: var(--gold);
}

.catalog-filter select:focus-visible {
    border-bottom-color: var(--gold);
    outline: none;
}

.catalog-reset {
    align-self: flex-end;
    padding: 10px 2px 12px;
    background: transparent;
    border: none;
    border-bottom: 1px solid var(--gold-hairline-dark);
    border-radius: 0;
    font-family: 'Assistant', sans-serif;
    font-size: 0.82rem;
    font-weight: 700;
    letter-spacing: 0.14em;
    color: var(--paper-dim);
    cursor: pointer;
    transition: border-color 0.25s ease, color 0.25s ease;
}

.catalog-reset:hover {
    border-bottom-color: var(--gold);
    color: var(--gold-light);
}

.catalog-grid {
    margin-top: 48px;
    display: grid;
    grid-template-columns: 1fr;
    gap: 32px;
}

.catalog-card {
    position: relative;
    /* Elevated dark surface — one notch lighter than the section's own ink
       background, same tone as the property-tab bubble, so the card reads as
       a distinct panel rather than vanishing into the background. */
    background: #181d23;
    border: 1px solid var(--gold-hairline-dark);
    border-radius: 18px;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    box-shadow: none;
    /* Dynamically inserted/removed by script.js on every filter change — plain
       CSS transition (not GSAP) since cards are created and destroyed on every
       re-render, which is simpler to keep correct with toggled classes than
       coordinating GSAP tweens against a constantly-changing node set. */
    opacity: 0;
    transform: translateY(14px);
    transition: opacity 0.4s ease, transform 0.4s ease, box-shadow 0.4s ease, border-color 0.4s ease;
}

.catalog-card.is-visible {
    opacity: 1;
    transform: translateY(0);
}

/* Cursor-following spotlight ring — a soft gold glow traces the card border
   toward wherever the pointer is, via the --mx/--my custom properties script.js
   updates on mousemove (delegated on #catalog-grid, since cards are destroyed
   and recreated on every filter change — see comment above). Classic gradient-
   border trick: a padded pseudo-element masked down to just its own ring. */
.catalog-card::before {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 2;
    border-radius: inherit;
    padding: 1px;
    background: radial-gradient(220px circle at var(--mx, 50%) var(--my, 0%), rgba(169, 134, 90, 0.65), transparent 65%);
    -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
    -webkit-mask-composite: xor;
    mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
    mask-composite: exclude;
    opacity: 0;
    transition: opacity 0.4s ease;
    pointer-events: none;
}

.catalog-card:hover::before {
    opacity: 1;
}

.catalog-card:hover {
    border-color: rgba(169, 134, 90, 0.45);
    /* True black (not --ink) for the shadow — an ink-tinted shadow would be
       invisible cast onto an ink-toned card over an ink background. */
    box-shadow: 0 30px 60px -38px rgba(0, 0, 0, 0.7);
}

.catalog-card-media {
    aspect-ratio: 4 / 3;
    overflow: hidden;
}

.catalog-card-media img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
    transition: transform 1.2s var(--ease-lux);
}

.catalog-card:hover .catalog-card-media img {
    transform: scale(1.05);
}

.catalog-card-body {
    padding: 26px 26px 28px;
    display: flex;
    flex-direction: column;
}

.catalog-card-title {
    font-family: 'Heebo', sans-serif;
    font-weight: 300;
    font-size: 1.25rem;
    letter-spacing: 0.01em;
    color: var(--paper);
}

.catalog-card-location {
    margin-top: 8px;
    color: var(--gold);
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.18em;
}

.catalog-card-specs {
    margin-top: 14px;
    color: var(--paper-dim);
    font-size: 0.88rem;
}

.catalog-card-price {
    margin-top: 18px;
    padding-top: 14px;
    border-top: 1px solid var(--gold-hairline-dark);
    font-family: 'Heebo', sans-serif;
    font-weight: 400;
    font-size: 1.05rem;
    letter-spacing: 0.03em;
    color: var(--paper);
}

.catalog-card .property-link {
    margin-top: 18px;
    font-size: 0.75rem;
}

.catalog-empty {
    margin-top: 48px;
    padding: 48px;
    text-align: center;
    color: var(--paper-dim);
    background: #181d23;
    border: 1px dashed var(--gold-hairline-dark);
    border-radius: 16px;
}

/* ---------- Why AUREA ---------- */
/* Flipped to a full ink section — the page's first dark "gallery room" moment
   after the hero, per the AUREA black/paper rhythm. Gold hairline grid texture
   + a soft gold glow give the 3D ring depth to rotate against. */

.why-aurea {
    position: relative;
    /* First section after the hero now — carries the "curtain" treatment that
       used to live on .about: sits above the hero in the stacking order and its
       rounded top edge visibly rises up and over the still-settling hero (the
       -100vh offset is set from script.js on THIS section). */
    z-index: 5;
    overflow: hidden;
    background-color: var(--ink);
    background-image:
        linear-gradient(rgba(169, 134, 90, 0.05) 1px, transparent 1px),
        linear-gradient(90deg, rgba(169, 134, 90, 0.05) 1px, transparent 1px),
        radial-gradient(60% 50% at 50% 20%, rgba(169, 134, 90, 0.12), transparent 70%);
    background-size: 112px 112px, 112px 112px, 100% 100%;
    border-radius: 32px 32px 0 0;
    box-shadow: 0 -60px 90px -55px rgba(20, 24, 29, 0.45);
    border-top: 1px solid var(--gold-hairline-dark);
    will-change: transform;
}

.why-aurea .eyebrow {
    color: var(--gold);
}

.why-aurea .section-heading {
    color: var(--paper);
}

.why-aurea .section-lede {
    color: var(--paper-dim);
}

.why-carousel {
    margin-top: 64px;
}

/* Flat responsive grid — this is the ONLY layout the fallback path ever sees
   (no GSAP, reduced motion, or a viewport script.js decided is too narrow for
   the ring). Same rules the original .why-grid had. */
.why-carousel-track {
    display: grid;
    grid-template-columns: 1fr;
    gap: 1px;
}

/*
   Enhanced state — script.js adds .is-3d only after confirming GSAP is present,
   motion isn't reduced, and the viewport is wide enough. Perspective lives on the
   OUTER element; the rotation goes on .why-carousel-track (a separate element)
   specifically so the vanishing point doesn't spin along with the content.
*/
.why-carousel.is-3d {
    position: relative;
    height: 460px;
    perspective: 1800px;
    overflow: hidden;
}

.why-carousel.is-3d .why-carousel-track {
    display: block;
    position: relative;
    width: 100%;
    height: 100%;
    transform-style: preserve-3d;
}

.why-carousel.is-3d .why-card {
    position: absolute;
    top: 50%;
    left: 50%;
    width: 240px;
    margin-top: -150px;
    margin-left: -120px;
    cursor: default;
}

/* Dark museum-plinth cards: near-black glass over the gold-lit grid, softly
   rounded corners, a gold hairline border. The subtle backdrop blur still has
   the section's glow/grid texture behind it to read against. */
.why-card {
    position: relative;
    text-align: center;
    padding: 44px 26px 40px;
    background: rgba(250, 248, 244, 0.03);
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    border: 1px solid var(--gold-hairline-dark);
    border-radius: 20px;
    box-shadow: 0 30px 60px -40px rgba(0, 0, 0, 0.7);
    transition: box-shadow 0.4s ease, background-color 0.4s ease, border-color 0.4s ease;
}

.why-card:hover {
    background: rgba(250, 248, 244, 0.055);
    border-color: rgba(169, 134, 90, 0.45);
    box-shadow: 0 40px 70px -40px rgba(0, 0, 0, 0.8);
}

/* The lift-on-hover only applies to the flat grid — in 3D mode script.js owns
   .why-card's transform (rotateY + translateZ for ring position, updated every
   animation frame during rotation) and re-declares the transition here too:
   transform is deliberately left OUT of .why-card's own base transition above,
   since a CSS transition on a property JS is animating every frame would fight
   it and make the rotation visibly lag instead of updating crisply. */
.why-carousel:not(.is-3d) .why-card {
    transition: transform 0.4s ease, box-shadow 0.4s ease, background-color 0.4s ease, border-color 0.4s ease;
}

.why-carousel:not(.is-3d) .why-card:hover {
    transform: translateY(-6px);
}

.why-num {
    display: block;
    margin-bottom: 18px;
    font-family: 'Heebo', sans-serif;
    font-weight: 200;
    font-size: 0.95rem;
    letter-spacing: 0.3em;
    color: var(--gold);
}

.why-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 56px;
    height: 56px;
    margin-bottom: 20px;
    border-radius: 50%;
    border: 1px solid var(--gold-hairline-dark);
    background: transparent;
    transition: transform 0.4s ease, border-color 0.4s ease, background-color 0.4s ease;
}

.why-card:hover .why-icon {
    transform: scale(1.06);
    border-color: var(--gold);
    background: rgba(169, 134, 90, 0.08);
}

.why-icon svg {
    width: 24px;
    height: 24px;
    fill: none;
    stroke: var(--gold-light);
    stroke-width: 1.3;
    stroke-linecap: round;
    stroke-linejoin: round;
}

.why-card h3 {
    font-family: 'Heebo', sans-serif;
    font-weight: 300;
    font-size: 1.15rem;
    letter-spacing: 0.04em;
    color: var(--paper);
}

.why-card p {
    margin-top: 12px;
    color: var(--paper-dim);
    font-size: 0.9rem;
    line-height: 1.75;
}

/* ---------- Featured project ---------- */

.featured-project {
    position: relative;
    display: grid;
    grid-template-columns: 1fr;
    /* Plain vh, not dvh — see .hero's comment. Not itself pinned, but its
       height changing mid-scroll would still shift the document position
       of every section after it (properties-catalog, lifestyle-expand,
       process, testimonials...), which is the same underlying problem. */
    min-height: 100vh;
    background: var(--ink);
    overflow: hidden;
}

.featured-project-media {
    position: relative;
    min-height: 340px;
    overflow: hidden;
}

.featured-project-media img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
    /* Resting scale is 1.08, scrubbed down toward 1 on scroll (see script.js) —
       starting zoomed-in and easing out reads calmer than the more common
       "zoom in as you scroll" and avoids the image ever revealing its edge. */
    transform: scale(1.08);
    will-change: transform;
}

.featured-project-panel {
    position: relative;
    padding: 100px 56px;
    display: flex;
    flex-direction: column;
    justify-content: center;
    color: var(--paper);
}

.featured-project-panel .eyebrow {
    color: var(--gold);
}

.featured-project-panel .section-heading {
    color: var(--paper);
}

.featured-project-panel .section-lede {
    color: var(--paper-dim);
    max-width: 48ch;
}

/* Spec sheet rows — hairline-divided, like a printed dossier. */
.featured-project-specs {
    list-style: none;
    margin-top: 44px;
    display: grid;
    grid-template-columns: 1fr;
    gap: 0;
    border-top: 1px solid var(--gold-hairline-dark);
}

.featured-project-specs li {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 15px 2px;
    border-bottom: 1px solid rgba(169, 134, 90, 0.14);
    font-size: 0.95rem;
    letter-spacing: 0.04em;
    color: rgba(250, 248, 244, 0.85);
}

.featured-project-specs svg {
    flex-shrink: 0;
    width: 17px;
    height: 17px;
    fill: none;
    stroke: var(--gold);
    stroke-width: 1.3;
    stroke-linecap: round;
    stroke-linejoin: round;
}

/* Outlined, letter-spaced pill — keeps the same rounded language as the hero's
   own .hero-cta base this element shares, just outlined instead of filled. */
.featured-project-cta {
    margin-top: 48px;
    width: fit-content;
    background: transparent;
    color: var(--gold-light);
    border: 1px solid var(--gold);
    border-radius: 999px;
    padding: 17px 38px;
    font-size: 13px;
    font-weight: 600;
    letter-spacing: 0.2em;
}

.featured-project-cta:hover {
    background: var(--gold);
    color: var(--ink);
    box-shadow: none;
    transform: translateY(-2px);
}

/* ---------- Lifestyle: scroll-expansion media hero ---------- */
/* Adapted from a React/framer-motion "ScrollExpandMedia" component: a small
   centered video grows to near full-bleed as the section is scroll-pinned
   (mechanics live in script.js, driven by the same GSAP ScrollTrigger
   pin+scrub idiom as the hero/about sections — not the original's manual
   wheel-event scroll-jacking), while the title's two halves slide apart to
   reveal the footage where they used to overlap. */

.lifestyle {
    background: var(--ink);
}

.lifestyle-expand {
    position: relative;
    /* Plain vh, not dvh — this is a pin target, see .hero's comment. */
    height: 100vh;
    min-height: 560px;
    overflow: hidden;
    background-color: var(--ink);
}

/* Same gold-hairline grid + soft glow used on .why-aurea/.properties/.process
   — no photo behind this section, just the sitewide dark "gallery room"
   texture. */
.lifestyle-expand-bg {
    position: absolute;
    inset: 0;
    z-index: 0;
    background-image:
        linear-gradient(rgba(169, 134, 90, 0.05) 1px, transparent 1px),
        linear-gradient(90deg, rgba(169, 134, 90, 0.05) 1px, transparent 1px),
        radial-gradient(60% 50% at 50% 40%, rgba(169, 134, 90, 0.12), transparent 70%);
    background-size: 112px 112px, 112px 112px, 100% 100%;
}

.lifestyle-expand-bg-tint {
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg, rgba(20, 24, 29, 0.15), rgba(20, 24, 29, 0.45));
}

.lifestyle-expand-stage {
    position: relative;
    z-index: 1;
    height: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
}

/* Absolutely centered independent of the title below — script.js grows
   .lifestyle-expand-media's width/height in lockstep with scroll, and this
   wrapper (not overflow-hidden, unsized) just keeps the caption trailing
   immediately under whatever size the media box currently is. */
.lifestyle-expand-wrap {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    z-index: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 20px;
}

/* Resting size below matches script.js's own progress=0 formula
   (300 + 0*1250, 400 + 0*400) — script.js overwrites width/height inline as
   the section scrolls; these are just the pre-JS/JS-not-yet-run default. */
.lifestyle-expand-media {
    position: relative;
    width: 300px;
    height: 400px;
    max-width: 95vw;
    max-height: 85vh;
    border-radius: 20px;
    overflow: hidden;
    box-shadow: 0 40px 90px -30px rgba(0, 0, 0, 0.65);
}

/* Two clips stacked exactly on top of each other rather than one <video>
   whose src gets swapped — reassigning src forces a fetch/decode-from-
   scratch, which is the actual cause of the blank-frame gap between clips.
   Both layers sit absolutely positioned at the same spot the whole time;
   the second one is already playing, invisible, underneath the first
   before the handoff (see script.js) — the "cut" is just an opacity swap
   between two already-live videos, with a short crossfade so any leftover
   few-frame mistiming blends away instead of reading as a hard cut. */
.lifestyle-expand-video-layer {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
    opacity: 0;
    transition: opacity 0.25s ease;
}

.lifestyle-expand-video-layer.is-active {
    opacity: 1;
}

.lifestyle-expand-media-tint {
    position: absolute;
    inset: 0;
    background: rgba(20, 24, 29, 0.35);
}

.lifestyle-expand-caption {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    text-align: center;
    will-change: transform;
}

.lifestyle-expand-date {
    font-size: 0.72rem;
    font-weight: 600;
    letter-spacing: 0.24em;
    text-transform: uppercase;
    color: var(--gold-light);
}

.lifestyle-expand-cue {
    font-size: 0.7rem;
    letter-spacing: 0.16em;
    color: var(--paper-dim);
}

/* Sits in normal flex flow (centered in the 100vh stage) while the media
   wrap floats absolutely — the two halves start overlapping the video's
   center and slide outward as the video expands underneath them. */
.lifestyle-expand-title {
    position: relative;
    z-index: 10;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    text-align: center;
    pointer-events: none;
}

.lifestyle-expand-title span {
    display: block;
    font-family: 'Heebo', sans-serif;
    font-weight: 200;
    font-size: clamp(2.4rem, 7vw, 6rem);
    line-height: 1.08;
    color: var(--paper);
    text-shadow: 0 4px 40px rgba(0, 0, 0, 0.55);
    will-change: transform;
}

/* Second line in the serif voice — the AUREA statement pattern (sans line /
   serif line) used across the site. */
.lifestyle-expand-title span:last-child {
    font-family: var(--font-serif);
    font-weight: 500;
    color: var(--gold-light);
}

/* Sits above everything (including the media, once it's grown to near
   full-bleed), starts invisible — script.js fades it in only once the video
   has nearly finished expanding (see renderLifestyleExpand). */
.lifestyle-luxury-text {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 110px;
    z-index: 5;
    margin: 0;
    text-align: center;
    opacity: 0;
    pointer-events: none;
}

/* inline-flex shrinks to the text's own natural width — the underline below
   is sized as a % of THIS, so it's always a little shorter than the actual
   sentence, at any font-size/viewport, with no JS measurement needed. */
.lifestyle-luxury-text-inner {
    display: inline-flex;
    flex-direction: column;
    align-items: center;
    gap: 18px;
}

.lifestyle-luxury-text-word {
    font-family: 'Heebo', sans-serif;
    font-weight: 800;
    font-size: clamp(2.8rem, 7vw, 5.5rem);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--paper);
    text-shadow: 0 4px 30px rgba(0, 0, 0, 0.55);
    white-space: nowrap;
}

/* Draws in via scaleX, set from script.js in step with the same scroll
   progress that fades the text in — same "line drawing itself in" idiom as
   .process-line-fill, just under this text instead of above the process
   steps. */
.lifestyle-luxury-underline {
    display: block;
    width: 82%;
    height: 3px;
    background: var(--gold);
    transform: scaleX(0);
    transform-origin: center;
}

/* ---------- Process ---------- */

.process {
    background-color: var(--ink);
}

.process-track {
    display: grid;
    grid-template-columns: 1fr;
    gap: 48px;
    position: relative;
    padding-top: 0;
}

/* The gold progress line now sits flush along the top of the whole track,
   acting as the steps' shared "border-top" that draws itself in. */
.process-line {
    position: absolute;
    top: 0;
    right: 0;
    left: 0;
    height: 1px;
    background: var(--gold-hairline-dark);
    z-index: 0;
    overflow: hidden;
    display: none;
}

/* Draws in as the section scrolls into view (see script.js), tracing
   the same "step by step" progression the four stages describe. transform-origin
   sits on the right — the reading-start edge in RTL — so it fills the way the eye
   already reads: 01 → 02 → 03 → 04. */
.process-line-fill {
    position: absolute;
    inset: 0;
    background: var(--gold);
    transform: scaleX(0);
    transform-origin: right center;
}

.process-step {
    position: relative;
    z-index: 1;
    padding-top: 36px;
    transition: transform 0.35s ease;
}

.process-step:hover {
    transform: translateY(-4px);
}

/* Oversized thin numeral in gold — no circle, no badge; pure editorial. */
.process-num {
    display: block;
    font-family: 'Heebo', sans-serif;
    font-weight: 200;
    font-size: clamp(2.6rem, 3.5vw, 3.6rem);
    line-height: 1;
    color: var(--gold);
    margin-bottom: 24px;
    transition: color 0.3s ease;
}

.process-step:hover .process-num {
    /* Dimmed gold for the hover state — gold-ink (the light-context dark gold)
       would nearly vanish against this section's ink background. */
    color: rgba(169, 134, 90, 0.6);
}

.process-step h3 {
    font-family: 'Heebo', sans-serif;
    font-size: 1.25rem;
    font-weight: 400;
    letter-spacing: 0.02em;
    margin-bottom: 12px;
    color: var(--paper);
}

.process-step p {
    color: var(--paper-dim);
    font-size: 0.95rem;
    line-height: 1.8;
    max-width: 30ch;
}

/* ---------- About ---------- */

.about {
    position: relative;
    /* Full-viewport scroll-scrubbed image sequence — same technique as the
       hero: script.js pins this section for a few viewport-heights of scroll
       and draws the frame matching the scroll progress onto the canvas below.
       Scrolling back up plays the sequence in reverse.
       Plain vh, not dvh — this is a pin target, see .hero's comment. */
    height: 100vh;
    min-height: 560px;
    overflow: hidden;
    background-color: var(--ink);
}

.about-scrub-wrap {
    position: absolute;
    inset: 0;
}

/* Canvas is replaced content like <img>/<video>, so object-fit: cover crops
   the 3524x2352 bitmap to fill the section — same approach as .hero-canvas.
   background: var(--ink) covers the gap before the first frame paints. */
.about-canvas {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
    background: var(--ink);
}

/* ---------- About overlay — fades in near the end of the sequence ---------- */
/* Hidden at rest (opacity + visibility, i.e. GSAP's autoAlpha pair); the
   scrubbed timeline in script.js fades it in over the last stretch of the
   pinned phase, scrim included, so the footage darkens exactly as the words
   arrive. pointer-events: none — it's purely presentational, so the overlay
   never blocks scrolling gestures over the section. */
.about-overlay {
    position: absolute;
    inset: 0;
    z-index: 2;
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    padding: 24px;
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    will-change: opacity, transform;
}

/* Cinematic darkening behind the words — strongest in the middle band where
   the text sits, breathing room at the edges so the footage stays present. */
.about-overlay-scrim {
    position: absolute;
    inset: 0;
    background:
        radial-gradient(90% 70% at 50% 52%, rgba(20, 24, 29, 0.62), rgba(20, 24, 29, 0.18) 78%, transparent 100%),
        linear-gradient(180deg, rgba(20, 24, 29, 0.35), transparent 30%, transparent 70%, rgba(20, 24, 29, 0.45));
}

/* Two-column composition (adapted from the React/Motion stats-section
   template): text column on the reading side, logo-masked video on the other.
   Stacks vertically on narrow screens. */
.about-overlay-inner {
    position: relative;
    width: 100%;
    max-width: 1320px;
    margin-inline: auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 36px;
}

.about-overlay-text {
    text-align: right;
    max-width: 640px;
}

.about-overlay .eyebrow {
    color: var(--gold);
    margin-bottom: 26px;
}

.about-tw-heading {
    font-family: 'Heebo', sans-serif;
    font-weight: 200;
    font-size: clamp(1.7rem, 3.6vw, 3.4rem);
    letter-spacing: -0.01em;
    line-height: 1.15;
    color: var(--paper);
    text-shadow: 0 2px 30px rgba(20, 24, 29, 0.55);
}

.about-tw-heading .tw-line {
    display: block;
}

/* Accent line in the serif voice — the template's Instrument-Serif role,
   played here by Frank Ruhl Libre in gold. */
.about-overlay-accent {
    margin-top: 0.12em;
    font-family: var(--font-serif);
    font-weight: 500;
    color: var(--gold-light);
}

.about-overlay-lede {
    margin-top: 24px;
    max-width: 48ch;
    color: rgba(250, 248, 244, 0.78);
    font-size: 1.02rem;
    font-weight: 300;
    line-height: 1.85;
    text-shadow: 0 1px 18px rgba(20, 24, 29, 0.6);
}

/* Typewriter internals — words stay unbreakable so char-spans never split a
   word across lines mid-reveal. */
.tw-word {
    display: inline-block;
}

.tw-char {
    display: inline-block;
}

.about-overlay-stats {
    margin-top: 42px;
    padding-top: 28px;
    border-top: 1px solid var(--gold-hairline-dark);
    display: grid;
    grid-template-columns: repeat(2, max-content);
    gap: 26px clamp(32px, 4vw, 64px);
}

.about-overlay-stat {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

/* Serif numerals — the template sets its stat numbers in the accent serif. */
.about-stat-num {
    font-family: var(--font-serif);
    font-weight: 500;
    font-size: clamp(1.9rem, 2.8vw, 2.9rem);
    line-height: 1;
    color: var(--gold-light);
}

.about-overlay-stat small {
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.14em;
    color: rgba(250, 248, 244, 0.62);
}

/* Logo-masked video: the clip is visible only through the AUREA "A"
   monogram, via mask-image (template's logo-masked right column). */
.about-overlay-media-wrap {
    display: flex;
    justify-content: center;
    align-items: center;
}

.about-overlay-media {
    width: min(44vh, 82vw, 520px);
    aspect-ratio: 1;
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Cpath d='M32 8 L52 56 H43.5 L32 26 L20.5 56 H12 Z'/%3E%3C/svg%3E");
    -webkit-mask-size: contain;
    -webkit-mask-repeat: no-repeat;
    -webkit-mask-position: center;
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Cpath d='M32 8 L52 56 H43.5 L32 26 L20.5 56 H12 Z'/%3E%3C/svg%3E");
    mask-size: contain;
    mask-repeat: no-repeat;
    mask-position: center;
    will-change: transform, opacity;
}

.about-overlay-media video {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

@media (min-width: 992px) {
    .about-overlay-inner {
        flex-direction: row;
        gap: clamp(48px, 7vw, 130px);
    }

    .about-overlay-text {
        flex: 1.15;
    }

    .about-overlay-media-wrap {
        flex: 1;
        justify-content: flex-start;
    }
}

@media (max-width: 991px) {
    .about-overlay-media {
        width: min(30vh, 70vw);
    }
}

/* Grid texture lives on its own oversized absolute layer (rather than directly
   on .about's background) so the light scroll parallax in script.js can move it
   a few px via `transform` — a plain CSS background-position tween isn't GPU
   composited, transform is. Inset -20px on every side gives the 5px of travel
   room to move without ever revealing an edge. */
.about-bg-grid {
    position: absolute;
    inset: -20px;
    z-index: 0;
    pointer-events: none;
    background-image:
        linear-gradient(rgba(20, 24, 29, 0.017) 1px, transparent 1px),
        linear-gradient(90deg, rgba(20, 24, 29, 0.017) 1px, transparent 1px),
        radial-gradient(55% 45% at 100% 0%, rgba(169, 134, 90, 0.05), transparent 70%);
    background-size: 56px 56px, 56px 56px, 100% 100%;
}

/* Same wrapper everywhere else, widened ~25% (1320px → 1650px) for THIS section
   only — makes better use of screen width on the wide 3-column layout below
   without touching the shared .section-inner max-width used site-wide. */
.about .section-inner {
    max-width: 1650px;
    padding-top: 190px;
    padding-bottom: 190px;
}

/* Ghost numeral watermark — soft background texture, never competing. */
.about-ghost-num {
    position: absolute;
    top: -0.1em;
    left: 40px;
    font-family: 'Heebo', sans-serif;
    font-weight: 900;
    font-size: clamp(7rem, 14vw, 12rem);
    line-height: 1;
    color: var(--ink);
    opacity: 0.015;
    filter: blur(2px);
    pointer-events: none;
    user-select: none;
    z-index: 0;
}

.about-inner {
    position: relative;
    z-index: 1;
    display: grid;
    grid-template-columns: 1fr;
    gap: 68px;
    align-items: start;
}

.about-heading-rule {
    display: none;
}

/* Scoped larger heading for this section specifically — thin display weight,
   and the second line breaks into the serif voice in gold: the AUREA
   statement pattern ("sans line / serif line"). */
.about-text .section-heading {
    font-weight: 200;
    font-size: clamp(2.6rem, 4.4vw, 4.4rem);
    line-height: 1.12;
}

.about-heading-line {
    display: block;
}

.about-heading-line + .about-heading-line {
    margin-top: 0.12em;
    font-family: var(--font-serif);
    font-weight: 500;
    color: var(--gold-ink);
}

/* Text column widened ~20% in proportion (see .about-inner grid-template-columns
   media rule below) plus its own type scale — larger heading, shorter line
   measure for easier reading, more air between paragraphs. Scoped to
   .about-text so the shared .section-lede class is untouched everywhere else. */
.about-text .section-lede {
    font-size: 1.15rem;
    max-width: 44ch;
}

.about-text .section-lede + .section-lede {
    margin-top: 26px;
}

.about-text .eyebrow {
    margin-bottom: 22px;
}

/* 3D-tilt stage for the portrait — perspective lives on the frame, the tilt
   itself is applied to the img via GSAP (transform only) in script.js. */
.about-portrait-frame {
    position: relative;
    perspective: 1400px;
}

/* Offset gold hairline frame behind the portrait — the classic gallery
   double-frame. Sits outside the tilt transform (it's on the frame, not the
   img), so it stays put while the photo leans. */
.about-portrait-frame::after {
    content: '';
    position: absolute;
    top: 20px;
    right: -20px;
    bottom: -20px;
    left: 20px;
    max-width: 410px;
    border: 1px solid var(--gold-hairline);
    z-index: 0;
    pointer-events: none;
}

/* Soft gold studio-light glow sitting behind the frame — a blurred radial
   gradient, not a hard-edged effect, so it reads as ambient light rather than
   a decorative ring. Intensifies slightly on hover alongside the tilt. */
.about-portrait-glow {
    position: absolute;
    inset: -14%;
    z-index: 0;
    background: radial-gradient(closest-side, rgba(169, 134, 90, 0.3), rgba(169, 134, 90, 0) 72%);
    filter: blur(38px);
    opacity: 0.5;
    pointer-events: none;
    transition: opacity 0.5s ease;
}

.about-portrait-frame:hover .about-portrait-glow {
    opacity: 0.8;
}

/* transform-style: preserve-3d + will-change keep the hover tilt (set
   via GSAP in script.js) GPU-composited; the shadow itself stays a plain CSS
   transition so it can soften/strengthen independently of the tilt tween. */
.about-portrait img {
    position: relative;
    z-index: 1;
    width: 100%;
    max-width: 410px;
    aspect-ratio: 3 / 4;
    object-fit: cover;
    border-radius: 16px;
    box-shadow: 0 40px 80px -35px rgba(20, 24, 29, 0.3), 0 18px 40px -22px rgba(20, 24, 29, 0.16);
    transform-style: preserve-3d;
    will-change: transform;
    transition: box-shadow 0.5s ease;
}

.about-portrait-frame:hover img {
    box-shadow: 0 55px 100px -30px rgba(20, 24, 29, 0.38), 0 25px 55px -20px rgba(169, 134, 90, 0.22);
}

.about-portrait-caption {
    margin-top: 34px;
    display: flex;
    flex-direction: column;
    gap: 5px;
}

.about-portrait-name {
    font-family: 'Heebo', sans-serif;
    font-weight: 400;
    font-size: 1.05rem;
    letter-spacing: 0.03em;
    color: var(--ink);
}

/* Role + firm set in a small-caps-style Latin treatment — letter-spaced,
   uppercase, restrained — the typographic register luxury mastheads use for a
   title line under a name. */
.about-portrait-role {
    font-family: 'Heebo', sans-serif;
    font-size: 0.74rem;
    font-weight: 600;
    letter-spacing: 0.22em;
    text-transform: uppercase;
    color: var(--gold-ink);
}

.about-portrait-company {
    font-family: 'Heebo', sans-serif;
    font-size: 0.7rem;
    font-weight: 500;
    letter-spacing: 0.26em;
    text-transform: uppercase;
    color: var(--muted);
}

/* Editorial drop cap on the opening paragraph — now in the serif voice, gold. */
.about-dropcap::first-letter {
    float: right;
    margin-left: 12px;
    font-family: var(--font-serif);
    font-weight: 500;
    font-size: 3.4em;
    line-height: 0.82;
    color: var(--gold-ink);
}

/* Pull quote: serif voice, thin gold rule on the reading side. */
.about-pullquote {
    margin: 44px 0;
    padding-right: 28px;
    border-right: 1px solid var(--gold);
    font-family: var(--font-serif);
    font-weight: 500;
    font-size: clamp(1.5rem, 2.3vw, 2rem);
    line-height: 1.55;
    color: var(--ink);
}

.about-stats {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 44px 32px;
}

/* Editorial stat blocks: hairline gold rule above a big thin numeral and a
   small letter-spaced label. No icons, no boxes — pure type. */
.stat {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding-top: 24px;
    border-top: 1px solid var(--gold-hairline);
    transition: transform 0.35s ease, border-color 0.35s ease;
}

.stat:hover {
    transform: translateY(-4px);
    border-top-color: var(--gold);
}

.stat-icon {
    display: none;
}

.stat-icon svg {
    display: none;
}

.stat-num {
    font-family: 'Heebo', sans-serif;
    font-size: clamp(2.6rem, 3.4vw, 3.4rem);
    font-weight: 200;
    letter-spacing: -0.01em;
    color: var(--ink);
}

.stat-label {
    font-size: 0.74rem;
    font-weight: 600;
    letter-spacing: 0.18em;
    color: var(--muted);
}

/* ---------- Testimonials ---------- */
/* Second dark "gallery room": ink section, serif quotes, gold monograms.
   Social proof placed right before Contact, per the conversion pattern. */

/* Same grid as why-aurea/properties/process/lifestyle. */
.testimonials {
    position: relative;
    background-color: var(--ink);
    background-image:
        linear-gradient(rgba(169, 134, 90, 0.05) 1px, transparent 1px),
        linear-gradient(90deg, rgba(169, 134, 90, 0.05) 1px, transparent 1px);
    background-size: 112px 112px;
}

.testimonials .eyebrow {
    color: var(--gold);
}

.testimonials .section-heading {
    color: var(--paper);
}

.testimonials .section-lede {
    color: var(--paper-dim);
}

.testimonial-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 1px;
    background: var(--gold-hairline-dark);
    border: 1px solid var(--gold-hairline-dark);
    border-radius: 20px;
    overflow: hidden;
}

.testimonial-card {
    position: relative;
    display: flex;
    flex-direction: column;
    background: var(--ink);
    border: none;
    border-radius: 0;
    padding: 48px 36px 40px;
    overflow: hidden;
    transition: background-color 0.5s ease;
}

.testimonial-card:hover {
    background: #181d23;
    transform: none;
    box-shadow: none;
}

.testimonial-quote-mark {
    font-family: var(--font-serif);
    font-size: 64px;
    line-height: 1;
    color: var(--gold);
    opacity: 0.45;
    margin-bottom: 10px;
}

.testimonial-quote {
    flex: 1;
    font-family: var(--font-serif);
    font-weight: 400;
    color: rgba(250, 248, 244, 0.9);
    font-size: 1.15rem;
    line-height: 1.85;
    margin-bottom: 32px;
}

.testimonial-author {
    display: flex;
    align-items: center;
    gap: 16px;
    padding-top: 22px;
    border-top: 1px solid rgba(169, 134, 90, 0.14);
}

.testimonial-avatar {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 46px;
    height: 46px;
    border-radius: 50%;
    background: transparent;
    border: 1px solid var(--gold-hairline-dark);
    color: var(--gold);
    font-family: 'Heebo', sans-serif;
    font-weight: 400;
    font-size: 0.82rem;
    letter-spacing: 0.08em;
}

.testimonial-meta {
    display: flex;
    flex-direction: column;
    gap: 3px;
}

.testimonial-name {
    color: var(--paper);
    font-weight: 500;
    font-size: 0.95rem;
    letter-spacing: 0.03em;
}

.testimonial-role {
    color: var(--paper-dim);
    font-size: 0.78rem;
    letter-spacing: 0.1em;
}

/* ---------- CTA banner ---------- */

.cta-banner {
    position: relative;
    min-height: 90vh;
    display: flex;
    align-items: center;
    background: var(--ink);
    overflow: hidden;
}

/* Soft radial gold glow behind the text — the same "light behind the headline"
   technique as the hero's vignette (see .hero-sky), reused here so the two
   full-bleed dark moments in the page feel like they belong to one family. */
.cta-banner-glow {
    position: absolute;
    inset: 0;
    background: radial-gradient(45% 55% at 50% 45%, rgba(169, 134, 90, 0.22), transparent 70%);
    pointer-events: none;
}

.cta-banner-inner {
    position: relative;
    z-index: 1;
    text-align: center;
    display: flex;
    flex-direction: column;
    align-items: center;
}

.cta-banner-heading {
    color: var(--paper);
    max-width: 16ch;
}

.cta-banner-lede {
    margin-top: 22px;
    color: var(--paper-dim);
    max-width: 52ch;
}

.cta-banner-actions {
    margin-top: 44px;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 18px;
}

.cta-banner-secondary {
    display: inline-flex;
    align-items: center;
    padding: 17px 38px;
    border: 1px solid rgba(250, 248, 244, 0.35);
    border-radius: 999px;
    color: var(--paper);
    font-size: 13px;
    font-weight: 600;
    letter-spacing: 0.18em;
    transition: border-color 0.3s ease, background-color 0.3s ease, color 0.3s ease;
}

.cta-banner-secondary:hover {
    border-color: var(--gold);
    color: var(--gold-light);
    background: rgba(250, 248, 244, 0.04);
}

/* ---------- Statement banner (Testimonials → Contact) ---------- */
/* Same 112px hairline grid as the rest of the site, plain and static — no
   animated reveal here anymore, just the heading sitting over it. Centering
   lives HERE, on the section, rather than on the heading itself via
   position:absolute; inset:0 — that used to make the heading's own
   bounding box match the full 100vh section instead of just its visible
   text, which threw off the shared .reveal ScrollTrigger (start: 'top 85%'
   fired against that oversized box, completing while the section had only
   just peeked into view — long before the actual centered text was
   visible). A normal, content-sized flex child gives ScrollTrigger a box
   that matches what's actually on screen. */
.pixelReveal {
    position: relative;
    /* Plain vh, not dvh — see .hero's comment. Not pinned itself, but it
       sits directly before .contact, so its height changing mid-scroll
       would shift contact's document position right when this section is
       reached — the same underlying problem, in exactly the area it was
       reported in. */
    height: 100vh;
    min-height: 480px;
    overflow: hidden;
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: var(--ink);
    background-image:
        linear-gradient(rgba(169, 134, 90, 0.05) 1px, transparent 1px),
        linear-gradient(90deg, rgba(169, 134, 90, 0.05) 1px, transparent 1px);
    background-size: 112px 112px;
}

.pixelReveal__heading {
    margin: 0;
    padding: 0 32px;
    text-align: center;
    font-family: 'Heebo', sans-serif;
    font-weight: 800;
    font-size: clamp(2rem, 5.5vw, 4.2rem);
    line-height: 1.2;
    color: var(--paper);
}

/* ---------- Contact ---------- */

/* Background picks up exactly where the pixel-grid reveal above leaves off:
   that canvas's own gradient ends on var(--ink) at its bottom row, so this
   section starts there too, then keeps deepening further into near-black
   (half of --ink's own RGB values, same hue family — not a new color pulled
   from outside the palette) before settling — the gradient's downward motion
   continues instead of cutting straight to a flat block right at the seam.
   Never brightens back up at any point, so there's no visible seam or pulse.
   The gold accent still comes through via .contact-shadow's soft blob layer
   below. No border-top here on purpose: a hairline exactly at that boundary
   would draw a visible seam back in. */
.contact {
    position: relative;
    overflow: hidden;
    background: linear-gradient(180deg,
        var(--ink) 0%,
        #0a0c0f 55%,
        #0a0c0f 100%);
    color: var(--paper);
}

/* Soft gold blob, distorted into an organic, slowly-shifting cloud by the
   feTurbulence/feDisplacementMap filter defined inline in the HTML — a
   mask-image (multiple overlapping radial-gradients, same technique as the
   about-portrait glow) shapes it instead of a flat rectangle, so the
   displacement has an irregular edge to distort rather than a hard-edged box. */
.contact-shadow {
    position: absolute;
    inset: -15%;
    z-index: 0;
    pointer-events: none;
}

.contact-shadow-blob {
    width: 100%;
    height: 100%;
    filter: url(#contact-shadow-filter) blur(30px);
    background: radial-gradient(closest-side, rgba(169, 134, 90, 0.65), rgba(169, 134, 90, 0) 70%);
    -webkit-mask-image:
        radial-gradient(circle at 32% 38%, #fff 0%, #fff 26%, transparent 55%),
        radial-gradient(circle at 68% 55%, #fff 0%, #fff 30%, transparent 60%),
        radial-gradient(circle at 45% 72%, #fff 0%, #fff 24%, transparent 52%);
    mask-image:
        radial-gradient(circle at 32% 38%, #fff 0%, #fff 26%, transparent 55%),
        radial-gradient(circle at 68% 55%, #fff 0%, #fff 30%, transparent 60%),
        radial-gradient(circle at 45% 72%, #fff 0%, #fff 24%, transparent 52%);
}

/* Static, self-generated grain (inline SVG feTurbulence data URI — no
   external image) laid over the blob for texture, same spirit as the
   noise prop on the source component. */
.contact-noise {
    position: absolute;
    inset: 0;
    z-index: 1;
    pointer-events: none;
    opacity: 0.05;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
    background-size: 200px 200px;
    mix-blend-mode: overlay;
}

.contact .eyebrow {
    color: var(--gold);
}

.contact .section-lede {
    color: var(--paper-dim);
}

.contact .section-heading {
    color: var(--paper);
}

.contact-inner {
    position: relative;
    z-index: 2;
    display: grid;
    grid-template-columns: 1fr;
    gap: 60px;
}

.contact-details {
    list-style: none;
    margin-top: 44px;
    display: flex;
    flex-direction: column;
    gap: 0;
}

.contact-details li {
    display: flex;
    align-items: flex-start;
    gap: 16px;
    font-size: 1rem;
    padding: 16px 2px;
    border-bottom: 1px solid rgba(169, 134, 90, 0.14);
}

.contact-details li:first-child {
    border-top: 1px solid rgba(169, 134, 90, 0.14);
}

.contact-icon {
    flex-shrink: 0;
    width: 19px;
    height: 19px;
    margin-top: 3px;
    fill: none;
    stroke: var(--gold);
    stroke-width: 1.3;
    stroke-linecap: round;
    stroke-linejoin: round;
}

.contact-details li > span {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.contact-label {
    font-size: 11.5px;
    letter-spacing: 0.2em;
    color: var(--gold);
    font-weight: 600;
}

.contact-form {
    display: flex;
    flex-direction: column;
    gap: 26px;
}

.contact-form label {
    display: flex;
    flex-direction: column;
    gap: 8px;
    font-size: 0.8rem;
    font-weight: 600;
    letter-spacing: 0.16em;
    color: var(--paper-dim);
    transition: color 0.25s ease;
}

.contact-form label:focus-within {
    color: var(--gold-light);
}

.contact-form input,
.contact-form textarea {
    background: transparent;
    border: none;
    border-bottom: 1px solid rgba(250, 248, 244, 0.28);
    padding: 10px 0;
    color: var(--paper);
    font-family: 'Assistant', sans-serif;
    font-size: 1rem;
    letter-spacing: normal;
    resize: vertical;
    transition: border-color 0.25s ease;
}

.contact-form input:focus,
.contact-form textarea:focus {
    outline: none;
    border-color: var(--gold);
}

/* Outlined, pill-shaped, letter-spaced — fills with gold on hover. */
.form-submit {
    margin-top: 10px;
    align-self: flex-start;
    padding: 16px 44px;
    background: transparent;
    color: var(--gold-light);
    font-family: 'Assistant', sans-serif;
    font-weight: 600;
    font-size: 0.85rem;
    letter-spacing: 0.22em;
    border: 1px solid var(--gold);
    border-radius: 999px;
    cursor: pointer;
    transition: transform 0.3s ease, background-color 0.3s ease, color 0.3s ease, box-shadow 0.3s ease;
}

.form-submit:hover {
    background: var(--gold);
    color: var(--ink);
    transform: translateY(-2px);
    box-shadow: 0 14px 28px -12px rgba(169, 134, 90, 0.5);
}

.form-note {
    font-size: 0.9rem;
    color: var(--gold);
    min-height: 1.2em;
}

/* ---------- Footer ---------- */

.site-footer {
    background: #0e1114;
    color: var(--paper-dim);
    border-top: 1px solid var(--gold-hairline-dark);
}

.footer-inner {
    padding: 72px 40px 56px;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 28px;
}

.footer-brand .logo {
    color: var(--paper);
    font-weight: 300;
    letter-spacing: 0.3em;
}

.footer-brand p {
    margin-top: 10px;
    font-size: 0.85rem;
    letter-spacing: 0.06em;
}

.footer-nav {
    display: flex;
    gap: 32px;
}

.footer-nav a {
    font-size: 0.85rem;
    letter-spacing: 0.1em;
    transition: color 0.25s ease;
}

.footer-nav a:hover {
    color: var(--gold);
}

.footer-note {
    width: 100%;
    font-size: 0.78rem;
    opacity: 0.55;
    letter-spacing: 0.04em;
    border-top: 1px solid rgba(250, 248, 244, 0.1);
    padding-top: 26px;
}

/* ---------- Floating "leave details" CTA ---------- */
/* Same outlined-pill language as .featured-project-cta/.cta-banner-secondary
   (border + gold-light text, fills solid gold on hover), plus a layered,
   gently pulsing gold box-shadow for the "neon" glow. Cheap to animate —
   the element itself is tiny, nothing like the size/cost of the contact
   section's own filter-based glow. Visibility (not display) is toggled from
   script.js via .is-hidden so the fade transition has something to animate. */
.floating-contact-btn {
    position: fixed;
    left: 24px;
    bottom: 24px;
    z-index: 90;
    display: inline-flex;
    align-items: center;
    padding: 15px 30px;
    background: rgba(20, 24, 29, 0.85);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    border: 1px solid var(--gold);
    border-radius: 999px;
    color: var(--gold-light);
    font-size: 13px;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-decoration: none;
    white-space: nowrap;
    animation: floatingCtaGlow 2.6s ease-in-out infinite;
    transition: opacity 0.4s ease, transform 0.4s ease, background-color 0.3s ease, color 0.3s ease;
}

.floating-contact-btn:hover {
    background: var(--gold);
    color: var(--ink);
    transform: translateY(-3px);
}

.floating-contact-btn.is-hidden {
    opacity: 0;
    visibility: hidden;
    transform: translateY(12px);
    pointer-events: none;
}

@keyframes floatingCtaGlow {
    0%, 100% {
        box-shadow: 0 0 8px rgba(169, 134, 90, 0.5),
                    0 0 18px rgba(169, 134, 90, 0.32),
                    0 0 34px rgba(169, 134, 90, 0.18);
    }
    50% {
        box-shadow: 0 0 12px rgba(169, 134, 90, 0.75),
                    0 0 28px rgba(169, 134, 90, 0.5),
                    0 0 50px rgba(169, 134, 90, 0.28);
    }
}

@media (prefers-reduced-motion: reduce) {
    .floating-contact-btn {
        animation: none;
        box-shadow: 0 0 10px rgba(169, 134, 90, 0.5),
                    0 0 22px rgba(169, 134, 90, 0.35);
    }
}

/* ---------- Responsive ---------- */

@media (min-width: 560px) {
    .catalog-grid {
        grid-template-columns: repeat(2, 1fr);
    }

    .why-carousel-track {
        grid-template-columns: repeat(2, 1fr);
    }
}

@media (min-width: 1080px) {
    .catalog-grid {
        grid-template-columns: repeat(3, 1fr);
    }

    .why-carousel-track {
        grid-template-columns: repeat(4, 1fr);
    }

    /* Asymmetric "magazine" mosaic: the large tile spans 2×2, the two plain
       tiles fill the row beside it, and the wide tile closes the second row —
       same zero-gap math already used for the bento property grid earlier. */
    .lifestyle-grid {
        grid-template-columns: repeat(4, 1fr);
        grid-auto-rows: 260px;
    }

    .lifestyle-tile--lg {
        grid-column: span 2;
        grid-row: span 2;
    }

    .lifestyle-tile--wide {
        grid-column: span 2;
    }
}

@media (min-width: 861px) {
    .about-inner {
        grid-template-columns: 1.05fr 1.8fr 0.9fr;
    }

    .contact-inner {
        grid-template-columns: 1fr 1fr;
    }

    .process-track {
        grid-template-columns: repeat(4, 1fr);
        gap: 32px;
    }

    .process-line {
        display: block;
    }

    .testimonial-grid {
        grid-template-columns: repeat(3, 1fr);
    }

    .property-panel {
        grid-template-columns: 1.1fr 1fr;
    }

    .property-panel-media {
        min-height: 420px;
    }

    .featured-project {
        grid-template-columns: 1fr 1fr;
    }

    .featured-project-panel {
        padding: 100px 72px;
    }
}

@media (max-width: 860px) {
    .main-nav {
        display: none;
    }

    .nav-toggle {
        display: flex;
    }

    .mobile-nav {
        display: flex;
    }

    .header-inner {
        padding: 0 22px;
    }

    .hero-content {
        /* Asymmetric left/right padding only reads as "right of center" on wide
           screens — on mobile it would just look off-balance, so go back to a
           plain centered block here. */
        justify-content: flex-start;
        padding-top: calc(var(--header-h) + 4vh);
        padding-right: 22px;
        padding-left: 22px;
    }

    .section-inner {
        padding: 100px 22px;
    }

    .property-panel-content {
        padding: 34px 26px;
    }

    .about-ghost-num {
        left: 12px;
    }

    /* Scoped .about padding beats the generic .section-inner mobile rule above
       on specificity, so it needs its own mobile value here — still more
       generous than the site-wide 100px, just not the full desktop 190px. */
    .about .section-inner {
        padding-top: 120px;
        padding-bottom: 120px;
    }

    .about-inner {
        gap: 56px;
    }

    .about-portrait-frame::after {
        display: none;
    }

    .featured-project-panel {
        padding: 64px 24px;
    }

    .cta-banner {
        min-height: auto;
        padding: 20px 0;
    }

    .footer-inner {
        flex-direction: column;
        align-items: flex-start;
    }

    .floating-contact-btn {
        left: 16px;
        bottom: 16px;
        padding: 13px 24px;
        font-size: 12px;
    }

    /* The contact section's background glow normally runs through an SVG
       filter (feTurbulence + feDisplacementMap, animated via SMIL <animate>,
       see index.html) that continuously recomputes procedural noise and
       displaces the blob with it, forever, on top of a 30px blur — one of
       the most expensive things a browser can be asked to paint every
       frame, and a real drag on mobile GPUs. Dropping the filter reference
       down to just the plain blur removes the animation entirely (an
       unreferenced SVG filter costs nothing) while keeping the same soft
       gold glow shape, just static instead of slowly churning. */
    .contact-shadow-blob {
        filter: blur(30px);
    }
}

@media (prefers-reduced-motion: reduce) {
    .hero-sky,
    .hero-logo,
    .hero-title,
    .hero-subtitle,
    .hero-cta,
    .hero-video-wrap,
    .reveal,
    .about-overlay {
        opacity: 1 !important;
        visibility: visible !important;
        transform: none !important;
    }

    .hero-title {
        filter: none !important;
    }

    /* Skip the expand/split animation entirely — instead of pushing the
       title off to the sides (which would leave it unreadable without the
       scroll-driven reveal that normally justifies it), re-stack it as a
       plain readable heading above a moderately-sized static video.
       script.js's no-GSAP branch mirrors these same values for when the
       media query can't fire, e.g. the GSAP CDN failing to load. */
    .lifestyle-expand-stage {
        justify-content: flex-start;
        gap: 32px;
        padding-top: 90px;
    }

    .lifestyle-expand-title {
        order: -1;
    }

    .lifestyle-expand-title span,
    .lifestyle-expand-date,
    .lifestyle-expand-cue {
        transform: none !important;
    }

    .lifestyle-expand-wrap {
        position: static !important;
        transform: none !important;
    }

    .lifestyle-expand-media {
        width: min(90vw, 900px) !important;
        height: min(60vh, 560px) !important;
    }

    .lifestyle-expand-bg-tint {
        background: rgba(20, 24, 29, 0.75) !important;
    }

    /* No scrub left to fade it in, so it sits statically visible, in normal
       flow below the re-stacked title/video instead of pinned to the bottom
       of a 100vh section that no longer exists in this layout. */
    .lifestyle-luxury-text {
        opacity: 1 !important;
        position: static !important;
        margin-top: 12px;
    }

    .lifestyle-luxury-underline {
        transform: scaleX(1) !important;
    }
}
