@import url('https://fonts.googleapis.com/css2?family=Lexend:wght@300;400;500&display=swap');

/* ═══════════════════════════════════════════════════════════════
   #9 — Standardized easing curves (3 named, used site-wide)
   ═══════════════════════════════════════════════════════════════ */
:root {
    --ease-out-soft: cubic-bezier(0.22, 1, 0.36, 1);  /* entrances, hover, reveals (90% of cases) */
    --ease-in-out:   cubic-bezier(0.4, 0, 0.2, 1);    /* state changes (overlay, color shifts) */
    --ease-spring:   cubic-bezier(0.34, 1.56, 0.64, 1); /* playful micro-interactions only */
}

html { scroll-behavior: smooth; }

#heroSection {
    background-size: cover;
    background-position: center;
}

/* #1 — Replace `transition: all` with named properties for performance */
.property-card {
    transition: transform 0.45s var(--ease-out-soft),
                box-shadow 0.45s var(--ease-out-soft),
                border-color 0.3s var(--ease-in-out);
    will-change: transform;
}
.property-card:hover {
    transform: translateY(-4px);
    box-shadow: 0 18px 40px -20px rgba(0, 0, 0, 0.18);
    border-color: #A30005;
}

/* #12 — Micro-press on every interactive element */
button,
a[role="button"],
.contact-btn,
.contact-form-btn,
.hamburger-btn {
    transition: transform 0.12s var(--ease-out-soft),
                background-color 0.3s var(--ease-in-out),
                color 0.3s var(--ease-in-out),
                border-color 0.3s var(--ease-in-out),
                opacity 0.2s var(--ease-in-out) !important;
}
button:active,
a[role="button"]:active,
.contact-btn:active,
.contact-form-btn:active,
.hamburger-btn:active {
    transform: scale(0.97);
}

.active-zone {
    fill: rgba(163, 0, 5, 0.4) !important;
    stroke: #A30005 !important;
    stroke-width: 2px;
}

input:focus { border-color: #A30005; outline: none; }

/* Cloudflare Turnstile widgets render a fixed 300px-wide iframe. Inside
   the listing contact card the available column drops below that on
   phones (≈190px at a 320px viewport), so the iframe poked out of its
   box and dragged the whole page into horizontal scroll. Containing it
   keeps the layout stable — the checkbox sits on the left of the widget
   and stays fully visible and clickable. (Alternative, needs markup
   change: data-size="flexible" on the widget.) */
.cf-turnstile {
    max-width: 100%;
    overflow: hidden;
}

html,
body {
    background: #f7f6f0 !important;
    min-height: 100vh;
    display: flex;
    flex-direction: column;
}

.site-nav {
    width: 100%;
    height: 90px;
    border-bottom: 1px solid #eeeeee;
    background: #f7f6f0;
    backdrop-filter: blur(12px);
    position: fixed;
    top: 0;
    left: 0;
    z-index: 1050;
    padding: 0 60px;
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
}

.nav-left {
    display: flex;
    align-items: center;
    gap: 55px;
}

.nav-left a,
.contact-btn {
    font-family: 'Quicksand', sans-serif;
    font-size: 12px;
    font-weight: 400;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    text-decoration: none;
}

.nav-left a {
    color: #000000 !important;
}

.brand {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-decoration: none;
    text-align: center;
    color: #0f172a;
    white-space: nowrap;
    position: relative;
}

.brand-logo-img {
    display: block;
    height: 58px;
    width: auto;
}

.brand-title {
    display: none;
}

.brand-subtitle {
    display: none;
}

.nav-right {
    display: flex;
    justify-content: flex-end;
}

.contact-btn {
    background: #000000;
    color: #f7f6f0;
    padding: 12px 34px;
    border-radius: 2px;
    display: inline-block;
}

#portfolio {
    background: #f7f6f0 !important;
    padding-top: 4.5rem !important;
    padding-left: 3rem !important;
    padding-right: 3rem !important;
}

@media (min-width: 768px) {
    #portfolio {
        padding-left: 6rem !important;
        padding-right: 6rem !important;
    }
}

.page-panel {
    background: #f7f6f0;
}

body.view-properties #heroSection,
body.view-about #heroSection,
body.view-contact #heroSection,
body.view-services #heroSection {
    display: none !important;
}

body.view-about #portfolio,
body.view-about #contactPage,
body.view-about #servicesPage,
body.view-contact #portfolio,
body.view-contact #aboutPage,
body.view-contact #servicesPage,
body.view-services #portfolio,
body.view-services #aboutPage,
body.view-services #contactPage {
    display: none !important;
}

body.view-properties #aboutPage,
body.view-properties #contactPage,
body.view-properties #servicesPage {
    display: none !important;
}

body.view-properties #portfolio,
body.view-about #aboutPage,
body.view-contact #contactPage,
body.view-services #servicesPage {
    display: block !important;
    padding-top: 8rem !important;
}

body.view-home #heroSection,
body.view-home #portfolio,
body.view-home #servicesPage,
body.view-home #aboutPage,
body.view-home #contactPage {
    display: block !important;
}

@media (max-width: 768px) {
    .site-nav {
        height: 82px;
        padding: 0 20px;
        grid-template-columns: auto auto;
        gap: 12px;
    }

    .nav-left {
        display: none;
    }

    .brand {
        justify-self: start;
        align-items: flex-start;
    }

    .brand-logo-img {
        height: 32px;
    }

    .contact-btn {
        padding: 10px 20px;
        font-size: 11px;
    }

    .hero-fill {
        margin-top: 82px;
        height: 72vh;
        min-height: 420px;
    }

    body.view-properties #portfolio,
    body.view-about #aboutPage,
    body.view-contact #contactPage {
        padding-top: 7rem !important;
    }
}

.hero-fill {
    display: none !important;
}

.hero-video-container {
    margin-top: 90px;
    width: 100%;
    height: 76vh;
    min-height: 470px;
    overflow: hidden;
    position: relative;
    background: #f7f6f0;
}

.hero-video {
    position: absolute;
    top: 50%;
    left: 50%;
    width: 100%;
    height: 100%;
    object-fit: cover;
    transform: translate(-50%, -50%);
    display: block;
}

/* ── Hero intro (Task 55; rebuilt for mobile in Task 57): black screen →
   red "in" mark → the n-arch opens into a growing window that reveals the
   hero video. The whole reveal is drawn per frame into ONE <canvas>
   (#heroIntroCanvas): a black even-odd plane with the arch window carved
   out, the red n bitmap re-sampled from source at the current zoom, and the
   plug that seals the window until the arch opens. That is a VIEWPORT-SIZED
   repaint each frame — the old 300vmax box-shadow scaled ×40 forced
   compositors to build giant layers that stalled and flickered on phones —
   and, unlike an inline SVG <image>, the bitmap's decode state is exactly
   knowable so the curtain never swaps to a half-drawn mark. Geometry
   (position, size, arch radius, final scale) is computed in script.js from
   the source mark bitmap; this block only sets paint/stacking/safety
   behaviour. ── */
#heroIntro {
    position: absolute;
    inset: 0;
    z-index: 5;
    overflow: hidden;
    cursor: pointer;
    user-select: none;
    -webkit-user-select: none;
    /* Safety net: if the JS orchestrator never runs, the intro still fades
       away so the hero is never permanently covered. 8s (Task 57, was 5s):
       the orchestrator disarms this as soon as it takes over at
       DOMContentLoaded; a very slow phone can still be parsing past 5s, and
       a fade that fires mid-intro then snaps back reads as a glitch. 8s is
       past any realistic DCL while still guaranteeing the hero can never
       stay covered if JS is broken. */
    animation: heroIntroFallback 0.6s ease 8s forwards;
}
#heroIntroCanvas {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    display: block;
}
#heroIntroI {
    opacity: 0; /* brought to 1 by the paint-time entrance fade below */
    animation: heroIntroLogoIn 0.7s ease-out 0.15s forwards;
    pointer-events: none;
}
#heroIntroI {
    position: absolute;
    -webkit-user-drag: none;
    max-width: none; /* Tailwind preflight's img{max-width:100%} would clamp it */
}
/* Curtain (Task 57): paints the black screen + the full red mark from
   stylesheet-apply time — BEFORE any script runs — so slow (mobile) loads
   never flash the bare video and the mark is visible while scripts parse.
   DOM-stacked above the SVG for exactly that reason; script.js hides it at
   DOMContentLoaded in the same frame the SVG geometry goes live, with both
   marks on the same fade phase, so the swap is seamless. */
#heroIntroCurtain {
    position: absolute;
    inset: 0;
    background: #000000;
}
#heroIntroMark {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    /* Home hero is 100vh; script.js clamps the real mark to 17% of the
       hero height between 96 and 150px — same clamp here keeps the
       curtain→SVG mark swap within a few pixels. */
    height: clamp(96px, 17vh, 150px);
    width: auto;
    max-width: none;
    opacity: 0; /* same paint-time entrance fade as the SVG marks */
    animation: heroIntroLogoIn 0.7s ease-out 0.15s forwards;
    pointer-events: none;
    -webkit-user-drag: none;
}
/* Wordmark line (Task 59): "Investments ⚷ Estate" — white words with the
   red key between them, extracted from the master lockup — completes the
   logo under the "in" mark. Both copies (live layer + curtain) are placed
   from the SAME clamp the curtain mark uses, so the JS orchestrator never
   has to move them and the curtain→canvas handover cannot seam:
   · centre-x sits 0.16×mark-height LEFT of the hero centre — the line is
     optically centred under the whole lockup, not under the mark glyph;
   · top edge sits 0.8136×mark-height below centre (key teeth clear the
     mark, bow hangs below the words — proportions measured from the
     master artwork);
   · height is 0.4748×mark-height, with a max() floor: on phones the
     proportional line (≈54px against a 113px mark) would set
     "Investments" at ~10px — the floor keeps the words legible while
     desktops stay strictly proportional. */
#heroIntroWord,
#heroIntroWordCurtain {
    position: absolute;
    left: calc(50% - clamp(96px, 17vh, 150px) * 0.16);
    top: calc(50% + clamp(96px, 17vh, 150px) * 0.8136);
    transform: translate(-50%, 0);
    height: max(calc(clamp(96px, 17vh, 150px) * 0.4748), calc(min(58vw, 240px) / 3.4734));
    width: auto;
    max-width: none; /* Tailwind preflight's img{max-width:100%} would clamp it */
    opacity: 0; /* brought in by the entrance below */
    animation: heroIntroWordIn 0.55s ease-out 0.25s forwards;
    pointer-events: none;
    -webkit-user-drag: none;
}
/* Paint-time mark entrance (Task 56): the red "in" fades in as soon as the
   stylesheet applies — NOT at DOMContentLoaded — so on a slow mobile
   connection the mark is already visible while scripts are still parsing.
   Opacity-only, so it is also safe for prefers-reduced-motion users. */
@keyframes heroIntroLogoIn {
    to { opacity: 1; }
}
/* Wordmark entrance (Task 59): staggered 0.25s behind the mark so the line
   reads as the mark finishing the sentence — a small 10px rise keeps it
   settling rather than popping. The translate(-50%,…) must stay in BOTH
   states: the element is centre-anchored by it. */
@keyframes heroIntroWordIn {
    from { opacity: 0; transform: translate(-50%, 10px); }
    to { opacity: 1; transform: translate(-50%, 0); }
}
@keyframes heroIntroFallback {
    to {
        opacity: 0;
        visibility: hidden;
        pointer-events: none;
    }
}
/* Reduced motion (Task 58): the overlay is NO LONGER display:none here —
   that hid the intro completely on phones with "Reduce Motion" enabled (a
   very common mobile setting), which read as "the intro is missing on
   mobile". Task 56 then made the JS orchestrator play a quiet hold-and-fade
   under prefers-reduced-motion — but iOS Safari reports reduce whenever
   Low Power Mode is on (and for the Reduce Motion accessibility toggle),
   so a large share of real iPhones never saw the arch at all: mark on
   black → fade → video. Since Task 58 the JS-drawn arch intro plays for
   everyone (a one-shot ~2.9s brand moment, tap-to-skip); under this media
   query the CSS entrance fades above simply complete instantly (global
   rule #19) and the canvas reveal is unaffected. If JS never runs,
   heroIntroFallback still fades the overlay away, so the hero can never
   stay covered. */

@media (max-width: 768px) {
    .hero-video-container {
        margin-top: 82px;
        height: 72vh;
        min-height: 420px;
    }
}

.kaly-footer {
    display: block !important;
    visibility: visible !important;
    opacity: 1 !important;
    background: #000000 !important;
    color: #f7f6f0 !important;
    padding: 70px 80px !important;
    margin-top: auto !important;
    position: relative !important;
    z-index: 1 !important;
}

.footer-inner {
    display: grid !important;
    grid-template-columns: 2fr 1fr 1fr 1fr !important;
    gap: 50px !important;
    max-width: 1400px !important;
    margin: auto !important;
}

/* Footer logo image */
.footer-logo-img {
    width: 110px;
    max-width: 100%;
    height: auto;
    margin-bottom: 15px;
    display: block;
}

@media (max-width: 768px) {
    .footer-logo-img {
        width: 80px;
    }
}

.kaly-footer h4 {
    font-family: 'Lexend', sans-serif !important;
    font-size: 32px;
    font-weight: 300 !important;
    letter-spacing: .25em;
    margin-bottom: 15px;
}

.kaly-footer span {
    font-size: 11px;
    letter-spacing: .2em;
    text-transform: uppercase;
    opacity: .7;
}

.kaly-footer p {
    margin-top: 10px;
    font-size: 14px;
    line-height: 1.7;
}

body.view-about #heroSection,
body.view-about #portfolio,
body.view-contact #heroSection,
body.view-contact #portfolio {
    display: none !important;
}

body.view-about #aboutPage,
body.view-contact #contactPage {
    display: block !important;
    padding-top: 130px !important;
    padding-bottom: 40px !important;
    min-height: auto !important;
}

body.view-about #contactPage,
body.view-contact #aboutPage,
body.view-properties #aboutPage,
body.view-properties #contactPage,
body.view-home #aboutPage,
body.view-home #contactPage {
    display: none !important;
}

body.view-about .kaly-footer,
body.view-contact .kaly-footer,
body.view-properties .kaly-footer,
body.view-home .kaly-footer {
    display: block !important;
}

@media (max-width: 768px) {
    .kaly-footer {
        padding: 55px 24px !important;
    }

    .footer-inner {
        grid-template-columns: 1fr !important;
        gap: 28px !important;
    }

    body.view-about #aboutPage,
    body.view-contact #contactPage {
        padding-top: 120px !important;
    }
}

#listingPage, #listingPage2 {
    background: #f7f6f0;
    padding-top: 130px !important;
    padding-bottom: 90px !important;
}

.listing-hero-detail {
    display: grid;
    /* minmax(0,1fr) lets the title column shrink below its longest word on
       narrow screens — a plain 1fr floor made the panel's min-content wider
       than a phone viewport (462px on a 390px screen), forcing horizontal
       scroll on every listing page. Desktop rendering is unchanged. */
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 40px;
    align-items: end;
    margin-bottom: 45px;
}

.listing-title {
    font-family: 'Playfair Display', serif;
    font-size: 56px;
    line-height: 1.05;
    letter-spacing: .04em;
    color: #0f172a;
}

.listing-subtitle {
    margin-top: 18px;
    max-width: 760px;
    color: #6b7280;
    font-weight: 300;
    line-height: 1.8;
}

.listing-price {
    font-size: 28px;
    font-weight: 300;
    color: #0f172a;
    white-space: nowrap;
}

.listing-gallery {
    display: grid;
    grid-template-columns: 2fr 1fr;
    gap: 18px;
    margin-bottom: 40px;
}

.gallery-main,
.gallery-side > div {
    background: #efece6;
    overflow: hidden;
    position: relative;
    cursor: zoom-in;
}

.gallery-main {
    aspect-ratio: 16/9;
}

.gallery-main img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
    transition: transform 1.2s var(--ease-out-soft);
    will-change: transform;
}

/* #3 — Gallery hover zoom + vignette */
.gallery-main:hover img,
.gallery-side > div:hover img {
    transform: scale(1.05);
}
.gallery-main::after,
.gallery-side > div::after {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg, transparent 55%, rgba(0, 0, 0, 0.22));
    opacity: 0;
    transition: opacity 0.4s var(--ease-in-out);
    pointer-events: none;
}
.gallery-main:hover::after,
.gallery-side > div:hover::after {
    opacity: 1;
}

/* Desktop: the side column must end on EXACTLY the main photo's bottom
   line. height:100% looks tempting but is CYCLIC — "100% of a row whose
   height depends on this column" — and when it can't resolve (wide tiles
   from properties with few photos contribute big intrinsic image heights)
   the column overflows the main photo by hundreds of pixels. Instead the
   column carries its own aspect ratio: in the 2fr/1fr + 18px split the
   main is exactly 2× the side width, so a 16/9 main stands at
   (2 × 9/16) = 8/9 of the side width — aspect-ratio: 8/9 reproduces the
   main photo's height to the pixel for ANY photo count, and the 1fr rows
   below split that definite height evenly. */
.gallery-side {
    display: grid;
    grid-template-columns: 1fr 1fr;
    grid-auto-rows: minmax(0, 1fr);
    gap: 18px;
    aspect-ratio: 8 / 9;
    min-height: 0;
}

.gallery-side > div {
    height: 100%;
    min-height: 0;
    min-width: 0;
}

/* With 1–3 side tiles the last one spans the full width so the column
   never shows an empty cell beside it (2 tiles → two stacked strips). */
.gallery-side > div.gallery-tile--wide {
    grid-column: 1 / -1;
}

.gallery-side img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
    transition: transform 1.2s var(--ease-out-soft);
    will-change: transform;
}

/* Specifications — compact label/value cards + EU-style energy badge */
.spec-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
    gap: 12px;
}

.spec-card {
    background: #f7f6f0;
    border: 1px solid #e7e2d6;
    padding: 15px 18px 13px;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.spec-card__label {
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: .16em;
    color: #8a8578;
}

.spec-card__value {
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 15px;
    font-weight: 600;
    color: #121212;
    line-height: 1.35;
}

.energy-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    width: 36px;
    height: 36px;
    border-radius: 4px 4px 14px 4px;
    color: #fff;
    font-weight: 700;
    font-size: 17px;
    letter-spacing: .02em;
}

.energy-extra {
    font-size: 12.5px;
    font-weight: 400;
    color: #6b7280;
    letter-spacing: 0;
}

.photo-upload-slot {
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    min-height: 150px;
    border: 1px dashed #cfc8b8;
    color: #6b7280;
    font-size: 13px;
    letter-spacing: .08em;
    text-transform: uppercase;
}

.photo-upload-slot span {
    display: block;
    font-size: 10px;
    margin-top: 6px;
    opacity: .7;
}

/* Facts strip — flexbox so the boxes ALWAYS fill the row edge-to-edge no
   matter how many facts a listing has (a fixed 6-column grid left beige
   background showing through whenever a listing had fewer than 6 facts).
   flex-basis 0 + grow 1 = equal widths; min-width forces sensible wrapping
   and the last (short) row stretches full width instead of leaving a gap. */
.listing-facts {
    display: flex;
    flex-wrap: wrap;
    gap: 1px;
    background: #ded8ca;
    margin-bottom: 55px;
}

.listing-facts div {
    flex: 1 1 0;
    min-width: 150px;
    background: #f7f6f0;
    padding: 24px;
    text-align: center;
    /* Insurance against future CMS values that form one long unbreakable
       token (URLs, compounds): text breaks inside the box instead of
       poking through its edge. All current values wrap at spaces. */
    overflow-wrap: break-word;
}

.listing-facts span {
    display: block;
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: .18em;
    color: #888;
    margin-bottom: 8px;
}

.listing-facts strong {
    font-weight: 400;
    color: #0f172a;
}

.listing-layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 280px;
    gap: 40px;
}

/* Listing with no sidebar cards (listing has no original brochure):
   main content spans the full width. The two-class selector
   outspecifies the responsive .listing-layout column rules at every
   breakpoint, so no media-query variants are needed. */
.listing-layout.listing-layout--full {
    grid-template-columns: minmax(0, 1fr);
}

.listing-section {
    margin-bottom: 55px;
}

.listing-section h2 {
    font-family: 'Cormorant Garamond', serif;
    font-size: 34px;
    margin-bottom: 18px;
    color: #0f172a;
}

.listing-section p {
    color: #6b7280;
    font-weight: 300;
    line-height: 1.9;
}

/* ── Homogeneous reading text — 19px site-wide ─────────────────────
   Every reading paragraph on the site shares ONE size (19px), so the
   contrast between serif headings and body copy is identical on the
   homepage, services, about, contact, legal pages and every listing:

   • p.text-gray-500.font-light.leading-7.text-sm covers the content
     paragraphs on all static pages (about/services/contact, GDPR and
     Terms), the property-card excerpts and the per-section intro
     captions inside listing pages (they all share those 4 utilities).
   • div.text-gray-500.font-light.leading-7.text-sm > p covers the
     services/about blocks where the utilities sit on a wrapping div.
   • The listing-specific selectors (Task 27) stay for the elements
     without those utilities: overview paragraphs, info-grid bodies,
     feature lists, sidebar cards, listing subtitle.

   Deliberately unchanged: form fields, buttons, nav, fact-strip
   values, spec chips, badges, the 360 hint (text-xs), photo-counter
   micro-labels — they are UI chrome, not reading text. */
.listing-subtitle,
.listing-section p:not(.text-xs):not(.yt360-hint),
.listing-section span.text-sm,
.feature-list li,
.sidebar-card p,
p.text-gray-500.font-light.leading-7.text-sm,
div.text-gray-500.font-light.leading-7.text-sm > p {
    font-size: 19px;
}

/* Responsive 16:9 video embeds (360 Video Tour / Property video) */
.video-embed {
    position: relative;
    width: 100%;
    padding: 0 0 56.25%;
    overflow: hidden;
}

.video-embed iframe {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    border: 0;
    display: block;
}

/* 360° drag-to-look overlay — covers the player for smooth pan/look-around,
   while keeping the bottom bar and bottom-right settings popup (Quality,
   Subtitles, Speed) completely accessible for direct clicks. */
.yt360-drag {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 56px;
    z-index: 2;
    cursor: grab;
    touch-action: none;          /* Pointer Events own touch drags */
    -webkit-user-select: none;
    user-select: none;
    /* Exclude bottom-right corner (~300px wide, ~240px tall above bottom bar)
       so YouTube's Settings gear menu (Quality, Subtitles, Speed) receives direct clicks */
    clip-path: polygon(
        0% 0%,
        100% 0%,
        100% calc(100% - 240px),
        calc(100% - 300px) calc(100% - 240px),
        calc(100% - 300px) 100%,
        0% 100%
    );
}

@media (max-width: 640px) {
    .yt360-drag {
        clip-path: polygon(
            0% 0%,
            100% 0%,
            100% calc(100% - 200px),
            calc(100% - 220px) calc(100% - 200px),
            calc(100% - 220px) 100%,
            0% 100%
        );
    }
}

.yt360-drag.yt360-grabbing {
    cursor: grabbing;
}

.yt360-drag:focus-visible {
    outline: 2px solid #A30005;
    outline-offset: -2px;
}

.info-grid {
    display: grid;
    /* minmax(0,1fr) — plain 1fr tracks floor at the widest unwrappable cell
       content (multi-column feature lists), which pushed the panel's
       min-content past a phone viewport and forced horizontal scroll on
       listing pages. Cells can now shrink and let text reflow. */
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 22px;
}

.info-grid div,
.sidebar-card {
    border: 1px solid #e5e1d7;
    padding: 28px;
    background: #f7f6f0;
}

/* Cell text must wrap INSIDE the box: long words (compound terms, URLs,
   Greek compounds) could previously run past the border on narrow
   screens. break-word keeps every glyph inside the box. */
.info-grid div {
    overflow-wrap: break-word;
}

/* Feature list living inside a What-You-Need-To-Know cell: always a
   single column — two list columns inside a half-width box cramp the
   items and push them over the box border. Two classes so it outranks
   the base .feature-list { columns: 2 } rule that follows. */
.feature-list.feature-list--in-cell {
    columns: 1;
    padding-left: 18px;
    margin-top: 6px;
}

.info-grid h3,
.sidebar-card h3 {
    font-family: 'Cormorant Garamond', serif;
    font-size: 24px;
    margin-bottom: 10px;
}

.feature-list {
    columns: 2;
    color: #6b7280;
    font-weight: 300;
    line-height: 2;
    padding-left: 18px;
}

.document-row {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: 12px 20px;
    margin-top: 22px;
}

.document-row button,
.sidebar-card a {
    background: #000;
    color: #f7f6f0;
    padding: 10px 18px;
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: .14em;
    text-decoration: none;
    border: 0;
    display: inline-block;
}

.map-placeholder {
    height: 360px;
    border: 1px solid #d8d2c4;
    background: linear-gradient(135deg, #e8e1d3, #f7f6f0);
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    color: #6b7280;
}

.sidebar-card {
    margin-bottom: 22px;
}

body.view-listing #heroSection,
body.view-listing #portfolio,
body.view-listing #servicesPage,
body.view-listing #aboutPage,
body.view-listing #contactPage {
    display: none !important;
}

body.view-listing2 #heroSection,
body.view-listing2 #portfolio,
body.view-listing2 #servicesPage,
body.view-listing2 #aboutPage,
body.view-listing2 #contactPage {
    display: none !important;
}

body.view-listing #listingPage,
body.view-listing2 #listingPage2 {
    display: block !important;
}

body.view-home #listingPage,
body.view-properties #listingPage,
body.view-services #listingPage,
body.view-about #listingPage,
body.view-contact #listingPage,
body.view-home #listingPage2,
body.view-properties #listingPage2,
body.view-services #listingPage2,
body.view-about #listingPage2,
body.view-contact #listingPage2,
body.view-listing #listingPage2,
body.view-listing2 #listingPage {
    display: none !important;
}

@media (max-width: 900px) {
    .listing-hero-detail,
    .listing-gallery,
    .listing-layout {
        grid-template-columns: 1fr;
    }

    /* Stacked gallery: the side column now sits BELOW the main photo, so
       it no longer stretches to the main photo's height — restore natural
       aspect-ratio tiles (the desktop rules tie the column height to the
       main photo, which is meaningless once the column stacks). */
    .listing-gallery .gallery-side {
        height: auto;
        aspect-ratio: auto;
        grid-auto-rows: auto;
    }

    .listing-gallery .gallery-side > div {
        height: auto;
        aspect-ratio: 4/3;
    }

    .listing-gallery .gallery-side > div.gallery-tile--wide {
        aspect-ratio: 16/7;
    }

    /* 2 boxes per row on small screens (flex-basis 40% → exactly 2 fit,
       grow normalises to 50/50; a lone last box stretches full width) */
    .listing-facts div {
        flex: 1 1 40%;
        min-width: 0;
    }

    .feature-list {
        columns: 1;
    }

    .listing-title {
        font-size: 42px;
    }
}

@media (max-width: 640px) {
    /* The info squares stack one per row on phones. Two columns left
       each box ~160px wide; with 28px padding the body text had ~100px
       to live in and spilled over the box borders. */
    .info-grid {
        grid-template-columns: 1fr;
        gap: 16px;
    }

    .info-grid div {
        padding: 20px;
    }

    .info-grid h3 {
        font-size: 20px;
    }
}

@media (min-width: 1280px) {
    .listing-layout {
        grid-template-columns: minmax(0, 1fr) 240px;
        gap: 32px;
    }
    #listingPage, #listingPage2 {
        max-width: 1600px !important;
        padding-left: 48px !important;
        padding-right: 48px !important;
    }
}

@media (min-width: 1600px) {
    .listing-layout {
        grid-template-columns: minmax(0, 1fr) 220px;
        gap: 28px;
    }
    #listingPage, #listingPage2 {
        max-width: 1720px !important;
        padding-left: 64px !important;
        padding-right: 64px !important;
    }
}

/* Transparent nav over video only on the home page at the top */
body.view-home:not(.scrolled) .site-nav {
    background: rgba(247, 246, 240, 0.66) !important;
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
}

/* Solid nav once scrolling, and always solid on every other page/view */
body.view-home.scrolled .site-nav,
body.view-properties .site-nav,
body.view-services .site-nav,
body.view-about .site-nav,
body.view-contact .site-nav,
body.view-listing .site-nav,
body.view-listing2 .site-nav {
    background: #f7f6f0 !important;
}

/* Let the home video bleed underneath the fixed navigation */
body.view-home #heroSection.hero-video-container {
    margin-top: 0 !important;
    padding-top: 0 !important;
}

/* Keep non-home pages clear below the fixed navigation */
body.view-properties #portfolio,
body.view-about #aboutPage,
body.view-contact #contactPage,
body.view-listing #listingPage,
body.view-listing2 #listingPage2 {
    padding-top: 130px !important;
}

/* Because the video now bleeds under the transparent nav, extend the hero so its bottom still sits lower on the page. */
body.view-home #heroSection.hero-video-container {
    height: calc(76vh + 90px) !important;
    min-height: 560px !important;
}

@media (max-width: 768px) {
    body.view-home #heroSection.hero-video-container {
        height: calc(72vh + 82px) !important;
        min-height: 500px !important;
    }
}

.site-nav {
    border-bottom: none !important;
    box-shadow: none !important;
}

/* Slightly larger home hero video */
body.view-home #heroSection.hero-video-container {
    height: calc(80vh + 90px) !important;
    min-height: 600px !important;
}

@media (max-width: 768px) {
    body.view-home #heroSection.hero-video-container {
        height: calc(76vh + 82px) !important;
        min-height: 540px !important;
    }
}

/* Full front-screen hero video on home */
body.view-home #heroSection.hero-video-container {
    height: 100vh !important;
    min-height: 100vh !important;
    margin-top: 0 !important;
}

@media (max-width: 768px) {
    body.view-home #heroSection.hero-video-container {
        height: 100vh !important;
        min-height: 100vh !important;
        margin-top: 0 !important;
    }
}

.hamburger-btn {
    display: none;
    background: transparent;
    border: 0;
    padding: 10px;
    cursor: pointer;
    z-index: 1001;
}

.hamburger-btn span {
    display: block;
    width: 24px;
    height: 1px;
    background: #000000;
    margin: 6px 0;
}

.mobile-menu {
    display: none;
}

@media (max-width: 768px) {
    .site-nav {
        grid-template-columns: 1fr auto !important;
    }

    .nav-right .contact-btn {
        display: none !important;
    }

    .hamburger-btn {
        display: block !important;
    }

    .mobile-menu {
        display: none;
        position: fixed;
        top: 82px;
        left: 0;
        right: 0;
        z-index: 1040;
        background: #f7f6f0;
        border-bottom: none;
        padding: 32px 24px 36px;
        text-align: center;
    }

    .mobile-menu.open {
        display: block !important;
    }

    .mobile-menu a {
        display: block;
        font-family: 'Quicksand', sans-serif;
        font-size: 12px;
        font-weight: 400;
        letter-spacing: 0.18em;
        text-transform: uppercase;
        text-decoration: none;
        color: #000000;
        padding: 16px 0;
    }
}

/* ── Leaflet Satellite Map ──────────────────────────────────── */
.leaflet-map-container {
    width: 100%;
    height: 420px;
    border: 1px solid #d8d2c4;
    background: #efece6;
    position: relative;
}

/* Gold dot marker */
.leaflet-gold-marker {
    width: 16px;
    height: 16px;
    background: #A30005;
    border: 2.5px solid #f7f6f0;
    border-radius: 50%;
    box-shadow: 0 0 0 2px rgba(163,0,5,0.35), 0 2px 8px rgba(0,0,0,0.35);
}

/* Popup – override Leaflet defaults to match site palette */
.leaflet-popup-content-wrapper {
    background: #f7f6f0 !important;
    border: 1px solid #d8d2c4 !important;
    border-radius: 2px !important;
    box-shadow: 0 4px 20px rgba(0,0,0,0.12) !important;
    padding: 0 !important;
}

.leaflet-popup-content {
    margin: 20px 24px !important;
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.leaflet-popup-tip-container {
    display: none !important;
}

.leaflet-popup-title {
    display: block;
    font-family: 'Cormorant Garamond', serif;
    font-size: 17px;
    font-weight: 600;
    color: #0f172a;
    letter-spacing: 0.02em;
    white-space: nowrap;
}

/* Privacy note in approximate-area popups (listing map) */
.leaflet-popup-note {
    display: block;
    font-family: 'Inter', sans-serif;
    font-size: 10.5px;
    line-height: 1.55;
    letter-spacing: 0.02em;
    color: #6b7280;
    margin-top: 6px;
}

/* Leaflet close button */
.leaflet-popup-close-button {
    color: #6b7280 !important;
    font-size: 18px !important;
    top: 8px !important;
    right: 10px !important;
}

.leaflet-popup-close-button:hover {
    color: #A30005 !important;
}

/* Compass control */
.map-compass {
    position: absolute;
    bottom: 12px;
    left: 12px;
    z-index: 1000;
    background: rgba(247, 246, 240, 0.95);
    backdrop-filter: blur(8px);
    border: 1.5px solid #A30005;
    border-radius: 50%;
    width: 52px;
    height: 52px;
    box-shadow: 0 2px 12px rgba(0,0,0,0.25);
    cursor: pointer;
    transition: box-shadow 0.2s, transform 0.2s;
}
.map-compass:hover {
    box-shadow: 0 2px 18px rgba(163,0,5,0.5) !important;
    transform: scale(1.08);
}
.map-compass svg {
    width: 100%;
    height: 100%;
    display: block;
}
.compass-n {
    fill: #b08d40;
    pointer-events: none;
}
.compass-s {
    fill: #9ca3af;
    pointer-events: none;
}
.compass-ring {
    fill: none;
    stroke: #d8d2c4;
    stroke-width: 1.2;
    pointer-events: none;
}
.compass-label {
    font-family: 'Inter', sans-serif;
    font-size: 9px;
    font-weight: 600;
    letter-spacing: 0.04em;
    pointer-events: none;
}
.compass-label-n {
    fill: #a07c30;
    font-size: 10px;
    font-weight: 700;
}
.compass-label-other {
    fill: #9ca3af;
}
.compass-tick {
    stroke: #d8d2c4;
    stroke-width: 0.8;
    pointer-events: none;
}
.compass-center {
    fill: #0f172a;
    pointer-events: none;
}

.footer-copyright {
    font-size: 9px;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    opacity: 0.4;
    margin-top: 16px;
    text-align: left;
}

@media (min-width: 769px) {
    .footer-copyright {
        text-align: center;
        margin-top: 24px;
    }
}

.footer-socials {
    display: flex;
    gap: 14px;
    margin-top: 18px;
}

.footer-socials a {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    border: 1px solid #555;
    border-radius: 50%;
    color: #f7f6f0;
    transition: all 0.25s ease;
    text-decoration: none;
}

.footer-socials a:hover {
    border-color: #A30005;
    color: #A30005;
    transform: translateY(-2px);
}

.footer-socials svg {
    width: 16px;
    height: 16px;
}

.footer-links {
    display: flex;
    gap: 14px;
    margin-top: 10px;
    flex-wrap: wrap;
}

.footer-links a {
    font-size: 10px;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: #f7f6f0;
    opacity: 0.45;
    text-decoration: none;
    transition: opacity 0.2s ease;
}

.footer-links a:hover {
    opacity: 1;
    color: #A30005;
}

/* ── Cookie Consent Banner ──────────────────────────────────── */
/* #14 — Slide-up via transform instead of display:none (which can't transition) */
.cookie-banner {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: 10000;
    background: #121212;
    color: #f7f6f0;
    padding: 18px 24px;
    font-size: 13px;
    line-height: 1.6;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 20px;
    flex-wrap: wrap;
    border-top: 1px solid #333;
    transform: translateY(100%);
    transition: transform 0.5s var(--ease-out-soft);
    pointer-events: none;
}

.cookie-banner.visible {
    transform: translateY(0);
    pointer-events: auto;
}

.cookie-banner a {
    color: #A30005;
    text-decoration: underline;
}

.cookie-banner button {
    background: #A30005;
    color: #121212;
    border: none;
    padding: 10px 22px;
    font-size: 11px;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    cursor: pointer;
    border-radius: 2px;
    transition: background 0.2s ease;
}

.cookie-banner button:hover {
    background: #f7f6f0;
}

/* ── GDPR Form Checkbox ─────────────────────────────────────── */
.gdpr-consent {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    font-size: 12px;
    color: #6b7280;
    line-height: 1.5;
}

.gdpr-consent input[type="checkbox"] {
    margin-top: 2px;
    accent-color: #A30005;
}

.gdpr-consent a {
    color: #A30005;
    text-decoration: underline;
}

/* View hiding for legal pages */
body.view-gdpr #heroSection,
body.view-gdpr #portfolio,
body.view-gdpr #servicesPage,
body.view-gdpr #aboutPage,
body.view-gdpr #contactPage,
body.view-gdpr #listingPage,
body.view-gdpr #listingPage2,
body.view-privacy #heroSection,
body.view-privacy #portfolio,
body.view-privacy #servicesPage,
body.view-privacy #aboutPage,
body.view-privacy #contactPage,
body.view-privacy #listingPage,
body.view-privacy #listingPage2,
body.view-terms #heroSection,
body.view-terms #portfolio,
body.view-terms #servicesPage,
body.view-terms #aboutPage,
body.view-terms #contactPage,
body.view-terms #listingPage,
body.view-terms #listingPage2,
body.view-goldenvisa #heroSection,
body.view-goldenvisa #portfolio,
body.view-goldenvisa #servicesPage,
body.view-goldenvisa #aboutPage,
body.view-goldenvisa #contactPage,
body.view-goldenvisa #listingPage,
body.view-goldenvisa #listingPage2 {
    display: none !important;
}

body.view-gdpr #gdprPage,
body.view-privacy #privacyPage,
body.view-terms #termsPage,
body.view-goldenvisa #goldenVisaPage {
    display: block !important;
    padding-top: 130px !important;
    padding-bottom: 40px !important;
}

body.view-gdpr .site-nav,
body.view-privacy .site-nav,
body.view-terms .site-nav,
body.view-goldenvisa .site-nav {
    background: #f7f6f0 !important;
}

body.view-gdpr .kaly-footer,
body.view-privacy .kaly-footer,
body.view-terms .kaly-footer,
body.view-goldenvisa .kaly-footer {
    display: block !important;
}

body.view-gdpr #privacyPage,
body.view-gdpr #termsPage,
body.view-privacy #gdprPage,
body.view-privacy #termsPage,
body.view-terms #gdprPage,
body.view-terms #privacyPage,
body.view-goldenvisa #gdprPage,
body.view-goldenvisa #privacyPage,
body.view-goldenvisa #termsPage,
body.view-gdpr #goldenVisaPage,
body.view-privacy #goldenVisaPage,
body.view-terms #goldenVisaPage {
    display: none !important;
}

@media (max-width: 768px) {
    body.view-gdpr #gdprPage,
    body.view-privacy #privacyPage,
    body.view-terms #termsPage,
    body.view-goldenvisa #goldenVisaPage {
        padding-top: 120px !important;
    }
}

.leaflet-control-attribution {
    background: rgba(247,246,240,0.85) !important;
    font-size: 9px !important;
    letter-spacing: 0.06em !important;
    color: #6b7280 !important;
    border-top: 1px solid #e5e1d7 !important;
}

/* Zoom controls */
.leaflet-control-zoom a {
    background: #f7f6f0 !important;
    color: #0f172a !important;
    border: 1px solid #d8d2c4 !important;
    font-weight: 300 !important;
}

.leaflet-control-zoom a:hover {
    background: #A30005 !important;
    color: #f7f6f0 !important;
    border-color: #A30005 !important;
}

/* Explicit hiding of legal pages on other views */
body.view-home #gdprPage,
body.view-home #privacyPage,
body.view-home #termsPage,
body.view-properties #gdprPage,
body.view-properties #privacyPage,
body.view-properties #termsPage,
body.view-services #gdprPage,
body.view-services #privacyPage,
body.view-services #termsPage,
body.view-about #gdprPage,
body.view-about #privacyPage,
body.view-about #termsPage,
body.view-contact #gdprPage,
body.view-contact #privacyPage,
body.view-contact #termsPage,
body.view-listing #gdprPage,
body.view-listing #privacyPage,
body.view-listing #termsPage,
body.view-listing2 #gdprPage,
body.view-listing2 #privacyPage,
body.view-listing2 #termsPage {
    display: none !important;
}


/* Form submission status messages */
.form-status {
    font-size: 12px;
    line-height: 1.5;
    padding: 10px 14px;
    border-radius: 2px;
    transition: all 0.2s ease;
}

.form-status.hidden {
    display: none;
}

.form-status.success {
    background: rgba(163, 0, 5, 0.1);
    color: #8a6d3b;
    border: 1px solid rgba(163, 0, 5, 0.3);
}

.form-status.error {
    background: rgba(220, 38, 38, 0.05);
    color: #dc2626;
    border: 1px solid rgba(220, 38, 38, 0.2);
}

.form-status.loading {
    background: rgba(0, 0, 0, 0.03);
    color: #6b7280;
    border: 1px solid rgba(0, 0, 0, 0.08);
}

.contact-form-btn:disabled {
    opacity: 0.6;
    cursor: not-allowed;
}

/* ═══════════════════════════════════════════════════════════════
   #2a — Refined page transition (crossfade instead of flash + spring)
   Replaces the original 200ms opaque overlay + spring scale.
   ═══════════════════════════════════════════════════════════════ */
#pageTransition {
    /* Override the inline style injected by script.js — gentler fade */
    background: #f7f6f0 !important;
    transition: opacity 0.28s var(--ease-in-out) !important;
}

/* Remove the spring-bounce pageEnter; replace with a calm fade-up */
@keyframes pageEnter {
    from { opacity: 0; transform: translateY(12px); }
    to   { opacity: 1; transform: translateY(0); }
}
body.transitioning #portfolio,
body.transitioning #listingPage,
body.transitioning #listingPage2,
body.transitioning #aboutPage,
body.transitioning #contactPage,
body.transitioning #gdprPage,
body.transitioning #privacyPage,
body.transitioning #termsPage {
    animation: pageEnter 0.4s var(--ease-out-soft) forwards;
}

/* ═══════════════════════════════════════════════════════════════
   #4 — Lightbox entrance/exit + image crossfade
   Original used Tailwind `hidden`/`flex` toggle (snap). Now we animate.
   ═══════════════════════════════════════════════════════════════ */
#lightboxModal {
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.4s var(--ease-in-out),
                visibility 0.4s var(--ease-in-out);
}
#lightboxModal.lightbox-open {
    opacity: 1;
    visibility: visible;
}
#lightboxImg {
    transform: scale(0.96);
    opacity: 0;
    transition: transform 0.5s var(--ease-out-soft),
                opacity 0.35s var(--ease-in-out);
}
#lightboxModal.lightbox-open #lightboxImg {
    transform: scale(1);
    opacity: 1;
}
/* Crossfade class applied during image swaps */
#lightboxImg.fading {
    opacity: 0;
    transition: opacity 0.18s var(--ease-in-out);
}

/* ═══════════════════════════════════════════════════════════════
   #6 — Scroll reveal classes (toggled by IntersectionObserver in script.js)
   ═══════════════════════════════════════════════════════════════ */
[data-reveal] {
    opacity: 0;
    transform: translateY(28px);
    transition: opacity 0.9s var(--ease-out-soft),
                transform 0.9s var(--ease-out-soft);
    transition-delay: var(--reveal-delay, 0ms);
}
[data-reveal].is-visible {
    opacity: 1;
    transform: none;
}

/* ═══════════════════════════════════════════════════════════════
   #7 — Card CTA animated underline grow + arrow slide
   Targets the "View full property profile" link in property cards.
   ═══════════════════════════════════════════════════════════════ */
.view-profile-link {
    position: relative;
    display: inline-block;
}
.view-profile-link::after {
    content: '';
    position: absolute;
    left: 0;
    bottom: -3px;
    width: 0;
    height: 1px;
    background: #A30005;
    transition: width 0.5s var(--ease-out-soft);
}
.property-card:hover .view-profile-link::after,
.view-profile-link:hover::after {
    width: 100%;
}
.view-profile-link .arrow {
    display: inline-block;
    transition: transform 0.45s var(--ease-out-soft);
}
.property-card:hover .view-profile-link .arrow,
.view-profile-link:hover .arrow {
    transform: translateX(6px);
}

/* ═══════════════════════════════════════════════════════════════
   #15 — Map loading placeholder
   Wraps .leaflet map containers with a "Loading map…" mask until tiles render.
   ═══════════════════════════════════════════════════════════════ */
.listing-map-wrapper,
#listingMap1,
#listingMap2 {
    position: relative;
    background: #efece6;
}
.listing-map-wrapper::before,
#listingMap1:not(.leaflet-container)::before,
#listingMap2:not(.leaflet-container)::before {
    content: 'Loading map…';
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: 0.18em;
    color: #888;
    z-index: 0;
    pointer-events: none;
}

/* ═══════════════════════════════════════════════════════════════
   #8 — FLIP animation helper for filter changes
   ═══════════════════════════════════════════════════════════════ */
.property-card.flipping {
    transition: transform 0.55s var(--ease-out-soft),
                opacity 0.4s var(--ease-in-out);
}

/* ═══════════════════════════════════════════════════════════════
   #19 — Respect prefers-reduced-motion
   ═══════════════════════════════════════════════════════════════ */
@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
    [data-reveal] {
        opacity: 1 !important;
        transform: none !important;
    }
}

/* ═══════════════════════════════════════════════════════════════
   Cookie Reject Button
   ═══════════════════════════════════════════════════════════════ */
.cookie-reject-btn {
    background: transparent;
    border: 1px solid rgba(255, 255, 255, 0.4);
    color: rgba(255, 255, 255, 0.8);
    padding: 8px 16px;
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    cursor: pointer;
    transition: all 0.2s ease;
    font-family: 'Inter', sans-serif;
}
.cookie-reject-btn:hover {
    border-color: rgba(255, 255, 255, 0.7);
    color: #fff;
}



/* ═══════════════════════════════════════════════════════════════
   Services — Stacking Deck (#servicesPage) — white section
   Cards are position: sticky with fanned tops (140/154/…/196 desktop,
   108/118/…/148 mobile) — MUST match script.js stickyTopFor().
   As you scroll, each card pins and the next slides over it; buried
   cards scale back (transform-origin top) and dim via the --dim
   overlay (handled by script.js), like cards stacking in a deck.
   ═══════════════════════════════════════════════════════════════ */
#servicesPage {
    background: #ffffff;
    scroll-margin-top: 90px;
    padding-bottom: 20px;
}

.services-header {
    text-align: center;
    padding: 96px 24px 56px;
    max-width: 760px;
    margin: 0 auto;
}

.services-lede {
    margin-top: 18px;
    color: rgba(18, 18, 18, 0.55);
    font-weight: 300;
    font-size: 19px;
    letter-spacing: 0.01em;
    line-height: 1.8;
}

.services-deck {
    max-width: 1060px;
    margin: 0 auto;
    /* No padding-bottom: it sits OUTSIDE the sticky constraint box, so it
       never helped the animation — it was pure blank below the run-out. */
    padding: 0 24px;
}

.service-card {
    position: sticky;
    top: 140px; /* base top — script.js derives stickyTopFor() from 140 + index*14 */
    min-height: 460px;
    margin-bottom: 52vh;
}

/* Visual layer: receives the JS-driven scale + --dim so the sticky box
   itself is never mutated (mutating sticky elements desyncs their
   positions in Chromium after large scroll jumps). */
.service-card-inner {
    position: relative;
    display: grid;
    grid-template-columns: 42% 1fr;
    background: #1c1c1c;
    color: #f7f6f0;
    border: 1px solid rgba(163, 0, 5, 0.28);
    border-radius: 2px;
    overflow: hidden;
    min-height: 460px;
    box-shadow: 0 25px 50px rgba(0, 0, 0, 0.14);
    will-change: transform;
    transform-origin: 50% 0%; /* recede towards the top edge so deck edges keep fanning */
}

/* Fanned deck: each successive card sticks 14px lower, so buried
   cards peek out as progressively darker strips above the top card. */
.service-card:nth-child(1) { top: 140px; }
.service-card:nth-child(2) { top: 154px; }
.service-card:nth-child(3) { top: 168px; }
.service-card:nth-child(4) { top: 182px; }
.service-card:nth-child(5) { top: 196px; }

/* Run-out & hand-off. Sticky mechanics force a minimum run-out below
   the last card: card4 must stay pinned until card 5 locks, i.e.
   card5-margin + tail ≥ card4-margin − 14px (≈52vh with the uniform
   52vh rhythm). That blank used to be followed by a 40vh tail + 26vh
   deck padding — ≈118vh of dead white after the stack completed.
   Now the tail is just a 10vh pose and the footer — which follows the
   deck in BOTH deck views (home hides About/Contact; /services shows
   only the deck) — is pulled up over most of the remaining run-out, so
   the deck hands off straight to it with only a ≈25vh lead-in band.
   The overlap can never cover the cards: it is smaller than the
   run-out itself, so the footer always starts below the stack — and
   it sits above the cards' inline z-index (1-5) while doing so.
   Short views (about/contact/gdpr/listing…) keep margin-top:auto. */
body.view-services .kaly-footer,
body.view-home .kaly-footer {
    /* max() caps the pull at the footer's own min height (342px on
       desktop): if 37vh exceeded it, the deck's box would poke out
       below the document end and scrollHeight — governed by the deck —
       would leave a blank strip UNDER the footer at full scroll.
       At 900px-tall viewports max(-333px, -338px) = -333px, so the
       approved hand-off geometry is untouched there. */
    margin-top: max(-37vh, -338px) !important; /* beats .kaly-footer's margin-top:auto */
    z-index: 30 !important;
}

/* Dim veil driven by script.js via --dim (replaces filter: brightness,
   which forced full repaints every frame and shimmered during scroll) */
.service-card-inner::after {
    content: '';
    position: absolute;
    inset: 0;
    background: #0c0c0c;
    opacity: var(--dim, 0);
    pointer-events: none;
    z-index: 20;
}

/* Final pose: after card 5 locks, the completed deck holds this short
   beat while the next section rises in behind it, then the stack lifts
   away (face card first, 14px cascade). The spacer also completes the
   sticky run-out budget — without it card 4 could release too early. */
.deck-tail {
    height: 10vh;
}

.service-card-media {
    position: relative;
    overflow: hidden;
    background: #efece6;
    min-height: 300px;
}

.service-card-media img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* Black & white treatment for selected service cards */
.service-card-media--bw img {
    filter: grayscale(100%);
}

.service-card-media::after {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(90deg, transparent 55%, #1c1c1c 100%);
    pointer-events: none;
}

.service-card-body {
    padding: 44px 48px;
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 14px;
}

.service-card-kicker {
    font-family: 'Inter', sans-serif;
    font-size: 10px;
    letter-spacing: 0.3em;
    text-transform: uppercase;
    color: #A30005;
    margin-bottom: 2px;
}

.service-card-body h4 {
    font-family: 'Playfair Display', serif;
    font-size: 34px;
    line-height: 1.15;
    font-weight: 400;
    color: #f7f6f0;
}

.service-card-sub {
    font-family: 'Cormorant Garamond', serif;
    font-style: italic;
    font-size: 18px;
    color: #A30005;
    line-height: 1.5;
}

.service-card-text {
    font-family: 'Inter', sans-serif;
    font-weight: 300;
    font-size: 19px;
    line-height: 1.75;
    color: rgba(247, 246, 240, 0.68);
}

.service-card-tags {
    list-style: none;
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    margin-top: 10px;
    padding: 0;
}

/* Golden Visa chip in the Consulting card — first tag, styled as the
   interactive entry point to the /golden-visa page. */
.service-card-tags li.service-card-tags--link {
    border-color: rgba(163, 0, 5, 0.55);
    background: rgba(163, 0, 5, 0.14);
    color: #f7f6f0;
}

.service-card-tags li.service-card-tags--link a {
    color: inherit;
    text-decoration: none;
}

.service-card-tags li.service-card-tags--link:hover {
    background: #A30005;
    border-color: #A30005;
    color: #fff;
}

.service-card-tags li {
    font-family: 'Inter', sans-serif;
    font-size: 10px;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: rgba(247, 246, 240, 0.7);
    border: 1px solid rgba(247, 246, 240, 0.18);
    background: rgba(247, 246, 240, 0.04);
    padding: 7px 14px;
    border-radius: 2px;
}

@media (max-width: 900px) {
    .service-card {
        min-height: 0;
        /* Tighter flow spacing than desktop: tall single-column cards +
           large margins shrink the window where the whole fan stays
           pinned while the final card holds (window ≈ tail − margin). */
        margin-bottom: 20vh;
    }

    .service-card-inner {
        grid-template-columns: 1fr;
        min-height: 0;
        max-height: calc(100vh - 175px);
        overflow-y: auto;
    }

    .service-card:nth-child(1) { top: 108px; }
    .service-card:nth-child(2) { top: 118px; }
    .service-card:nth-child(3) { top: 128px; }
    .service-card:nth-child(4) { top: 138px; }
    .service-card:nth-child(5) { top: 148px; }

    .service-card:nth-last-child(2) {
        /* 24vh covers the mobile run-out floor (20vh − 10px), so card 4
           stays pinned until card 5 locks; the 6vh tail adds the pose. */
        margin-bottom: 24vh;
    }

    .deck-tail {
        height: 6vh;
    }

    body.view-services .kaly-footer,
    body.view-home .kaly-footer {
        /* Mobile run-out is 24vh + 6vh → a smaller ≈12vh hand-off band.
           !important is required to out-rank the desktop !important rule. */
        margin-top: -18vh !important;
    }

    .service-card-media {
        min-height: 0;
        height: 168px;
    }

    .service-card-media::after {
        background: linear-gradient(180deg, transparent 55%, #1c1c1c 100%);
    }

    .service-card-body {
        padding: 24px 22px 28px;
        gap: 10px;
    }

    .service-card-body h4 {
        font-size: 26px;
    }

    .service-card-sub {
        font-size: 16px;
    }

    .service-card-text {
        font-size: 17px;
        line-height: 1.7;
    }

    .services-header {
        padding: 72px 20px 40px;
    }

    .services-deck {
        padding: 0 16px;
    }
}

/* ═══════════════════════════════════════════════════════════════
   #21 — About page: editorial splits, framed parallax images,
   statement band, Vision/Mission cards  (v2.4)
   ═══════════════════════════════════════════════════════════════ */
.about-split {
    display: grid;
    grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
    gap: clamp(2.5rem, 5vw, 4.5rem);
    align-items: center;
}
.about-split-reverse {
    grid-template-columns: minmax(0, 6fr) minmax(0, 5fr);
}

/* Framed image with inner parallax bleed — .about-parallax gets a
   JS scroll translate (see script.js #6b) inside the clipped frame */
.about-frame {
    position: relative;
    overflow: hidden;
    background: #e9e5db;
    box-shadow: 0 30px 60px -35px rgba(18, 18, 18, 0.35);
}
.about-frame .about-parallax {
    position: absolute;
    inset: -9% 0;
    will-change: transform;
}
.about-frame .about-parallax img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

/* Frame entrance: the frame unclips while the inner image settles
   from a slight zoom (composed with the shared [data-reveal] fade) */
.about-frame[data-reveal] {
    clip-path: inset(12% 8% 12% 8%);
    transition: opacity 0.9s var(--ease-out-soft),
                transform 1s var(--ease-out-soft),
                clip-path 1.25s var(--ease-out-soft);
    transition-delay: var(--reveal-delay, 0ms);
}
.about-frame[data-reveal].is-visible {
    clip-path: inset(0 0 0 0);
}
.about-frame .about-parallax img {
    transform: scale(1.12);
    transition: transform 1.7s var(--ease-out-soft);
    transition-delay: var(--reveal-delay, 0ms);
}
.about-frame.is-visible .about-parallax img {
    transform: scale(1);
}

/* 02 · Our Vision — serif statement band with growing gold rule */
.about-statement-text {
    font-family: 'Playfair Display', serif;
    font-size: clamp(1.25rem, 2.2vw, 1.6rem);
    line-height: 1.75;
    font-weight: 400;
    color: #3d3d3a;
    margin-bottom: 1.5rem;
}
.about-statement-text:last-child {
    margin-bottom: 0;
}
.about-rule[data-reveal] {
    opacity: 1;
    transform: scaleX(0);
    transform-origin: center;
    width: 3rem;
    height: 2px;
    background: #A30005;
    margin: 0 auto 2.75rem;
    transition: transform 1.1s var(--ease-out-soft) 0.15s;
}
.about-rule[data-reveal].is-visible {
    transform: scaleX(1);
}

/* Mobile: stack the splits, trim the parallax bleed to stay safe */
@media (max-width: 767px) {
    .about-split,
    .about-split-reverse {
        grid-template-columns: 1fr;
        gap: 2.25rem;
    }
    .about-frame .about-parallax {
        inset: -8% 0;
    }
}

/* ═══ #24 Language & currency pickers (top navigation, left of Contact) ═══ */
.nav-pickers {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-right: 14px;
}

.picker {
    position: relative;
}

.picker-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    height: 36px;
    padding: 0 12px;
    background: transparent;
    border: 1px solid #e3e0d8;
    border-radius: 2px;
    color: #121212;
    font-family: 'Quicksand', sans-serif;
    font-size: 11px;
    letter-spacing: .12em;
    cursor: pointer;
    transition: border-color .25s ease, color .25s ease;
}

.picker-btn svg {
    width: 15px;
    height: 15px;
}

.picker-btn:hover,
.picker-btn[aria-expanded="true"] {
    border-color: #A30005;
    color: #A30005;
}

.picker-menu {
    position: absolute;
    top: calc(100% + 10px);
    right: 0;
    min-width: 150px;
    background: #ffffff;
    border: 1px solid #ececec;
    box-shadow: 0 14px 34px rgba(18, 18, 18, .10);
    padding: 6px;
    opacity: 0;
    visibility: hidden;
    transform: translateY(-6px);
    transition: opacity .2s ease, transform .2s ease, visibility .2s;
    z-index: 1100;
}

.picker-menu.open {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
}

.picker-menu button {
    display: block;
    width: 100%;
    text-align: left;
    padding: 10px 12px;
    background: transparent;
    border: 0;
    font-family: 'Quicksand', sans-serif;
    font-size: 12px;
    letter-spacing: .06em;
    color: #121212;
    cursor: pointer;
    transition: background .15s ease, color .15s ease;
}

.picker-menu button:hover {
    background: #f7f6f0;
    color: #A30005;
}

.picker-menu button.active {
    color: #A30005;
    font-weight: 600;
}

.picker-menu button.active::after {
    content: '•';
    float: right;
    color: #A30005;
}

/* Mobile menu preference rows */
.mobile-prefs {
    display: flex;
    flex-direction: column;
    gap: 16px;
    margin-top: 26px;
    padding-top: 22px;
    border-top: 1px solid rgba(247, 246, 240, .18);
}

.mobile-prefs-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 14px;
}

.mobile-prefs-label {
    font-size: 10px;
    letter-spacing: .25em;
    text-transform: uppercase;
    opacity: .65;
}

.mobile-seg {
    display: inline-flex;
    border: 1px solid rgba(18, 18, 18, .3);
    border-radius: 2px;
    overflow: hidden;
}

.mobile-seg button {
    min-width: 46px;
    padding: 9px 12px;
    background: transparent;
    border: 0;
    border-right: 1px solid rgba(18, 18, 18, .18);
    color: #121212;
    font-family: 'Quicksand', sans-serif;
    font-size: 11px;
    letter-spacing: .1em;
    cursor: pointer;
    transition: background .2s ease, color .2s ease;
}

.mobile-seg button:last-child {
    border-right: 0;
}

.mobile-seg button.active {
    background: #121212;
    color: #f7f6f0;
    font-weight: 600;
}

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

/* ── Golden Visa badge (property cards) + mention strip (listing page) ── */
/* Badge: golden field (#C5A059) + white caps, per the approved treatment —
   distinct from the red Exclusive chip so both can stack on one card. */
.gv-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    background: #C5A059;
    color: #fff;
    font-family: 'Inter', sans-serif;
    font-size: 10px;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    font-weight: 500;
    padding: 7px 14px;
    line-height: 1.2;
}

.gv-chip svg {
    width: 12px;
    height: 12px;
    flex-shrink: 0;
}

.gv-strip {
    border: 1px solid rgba(163, 0, 5, 0.25);
    background: #f7f6f0;
    padding: 20px 24px;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 14px;
    justify-content: space-between;
}

.gv-strip-text {
    font-family: 'Inter', sans-serif;
    font-size: 13px;
    line-height: 1.6;
    color: #374151;
    display: flex;
    align-items: center;
    gap: 12px;
    min-width: 0;
}

.gv-strip-text svg {
    width: 20px;
    height: 20px;
    color: #A30005;
    flex-shrink: 0;
}

.gv-strip-text strong {
    color: #121212;
    font-weight: 600;
}

.gv-strip a.gv-strip-link {
    font-family: 'Inter', sans-serif;
    font-size: 11px;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    font-weight: 500;
    color: #A30005;
    text-decoration: none;
    border: 1px solid rgba(163, 0, 5, 0.4);
    padding: 10px 18px;
    white-space: nowrap;
    transition: background 0.3s, color 0.3s;
}

.gv-strip a.gv-strip-link:hover {
    background: #A30005;
    color: #fff;
}

/* ── "+ N More Photos" gallery tile ──
   Brand-red field with white caps by default; hovering swaps to a white
   field with black text. Declared as .gallery-side > div.gallery-more-tile
   so it outranks the clay placeholder on .gallery-side > div (0,1,1) — a
   bare utility class (0,1,0) would lose that tie, which is exactly why
   this is plain CSS rather than bg-[…] utilities in script.js. */
.gallery-side > div.gallery-more-tile {
    background: #A30005;
    color: #fff;
}

.gallery-side > div.gallery-more-tile:hover {
    background: #fff;
    color: #121212;
}

/* No photo → no hover vignette: keep the swap between the two solid
   colors pure (the shared .gallery-side > div::after gradient is for
   photos only). */
.gallery-side > div.gallery-more-tile::after {
    content: none;
}

/* ═══════════════════════════════════════════════════════════════════
   Task 60 — Advanced-search flag checkboxes + hero brand motto
   ═══════════════════════════════════════════════════════════════════ */

/* ── Minimal flag checkboxes (Golden Visa / Exclusive / Non-exclusive).
   Plain CSS on purpose: the flags row spans the Advanced Search grid and
   the tick boxes carry their own accent per facet — gold for Golden Visa
   (the .gv-chip tone), brand red for Exclusive (#A30005), charcoal for
   Non-exclusive. No Tailwind recompile involved. ── */
.adv-flags-row {
    grid-column: 1 / -1;
    display: flex;
    flex-wrap: wrap;
    gap: 0.875rem 2.5rem;
    padding-top: 0.25rem;
}

.flag-check {
    display: inline-flex;
    align-items: center;
    gap: 0.6rem;
    cursor: pointer;
    -webkit-user-select: none;
    user-select: none;
    min-height: 24px;
}

/* Keep the native input for a11y/state but visually replace it */
.flag-check input {
    position: absolute;
    opacity: 0;
    width: 1px;
    height: 1px;
    margin: 0;
    pointer-events: none;
}

.flag-check-box {
    width: 16px;
    height: 16px;
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 1px solid #c9c3b7;
    border-radius: 2px;
    background: #fff;
    color: #fff;
    transition: background-color 0.18s ease, border-color 0.18s ease;
}

.flag-check-box svg {
    width: 11px;
    height: 11px;
    opacity: 0;
    transform: scale(0.4);
    transition: opacity 0.18s ease, transform 0.18s ease;
}

.flag-check:hover .flag-check-box {
    border-color: #9a948a;
}

.flag-check input:checked ~ .flag-check-box svg {
    opacity: 1;
    transform: scale(1);
}

.flag-check--gold input:checked ~ .flag-check-box {
    background: #C5A059;
    border-color: #C5A059;
}

.flag-check--red input:checked ~ .flag-check-box {
    background: #A30005;
    border-color: #A30005;
}

.flag-check--dark input:checked ~ .flag-check-box {
    background: #121212;
    border-color: #121212;
}

.flag-check input:focus-visible ~ .flag-check-box {
    outline: 2px solid #C5A059;
    outline-offset: 2px;
}

.flag-check-label {
    font-size: 11px;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    font-weight: 500;
    color: #6b7280;
    transition: color 0.18s ease;
}

.flag-check:hover .flag-check-label {
    color: #121212;
}

.flag-check input:checked ~ .flag-check-label {
    color: #121212;
}

/* ── Hero brand motto: "Your Key For A Better Living". Lives inside the hero
   (above the video, below the intro overlay), fades in when the orchestrator
   releases the intro, holds, and is gone by 5s — then script.js removes the
   node. Sits at the hero's LOWER BOTTOM (Task 66) and uses the site-wide
   Inter face instead of the old Playfair italic. pointer-events:none keeps
   the video/skip handlers untouched. ── */
#heroMotto {
    position: absolute;
    inset: 0;
    z-index: 4;
    display: flex;
    align-items: flex-end;
    justify-content: center;
    padding: 0 6vw 8vh;
    text-align: center;
    pointer-events: none;
}

/* Author-level display rule so the `hidden` attribute always wins over the
   flex layout above (otherwise the motto would flash before the intro ends). */
#heroMotto[hidden] {
    display: none;
}

.hero-motto-text {
    font-family: 'Inter', sans-serif;
    font-weight: 500;
    color: #ffffff;
    font-size: clamp(1.35rem, 2.6vw, 2.25rem);
    line-height: 1.35;
    letter-spacing: 0.14em;
    text-shadow: 0 1px 3px rgba(0, 0, 0, 0.55), 0 2px 26px rgba(0, 0, 0, 0.45);
    opacity: 0;
}

#heroMotto.hero-motto-play .hero-motto-text {
    animation: heroMottoIn 5s cubic-bezier(0.22, 0.61, 0.36, 1) forwards;
}

@keyframes heroMottoIn {
    0% {
        opacity: 0;
        transform: translateY(14px);
        letter-spacing: 0.1em;
    }
    16% {
        opacity: 1;
        transform: translateY(0);
    }
    78% {
        opacity: 1;
        letter-spacing: 0.26em;
    }
    100% {
        opacity: 0;
        transform: translateY(-6px);
        letter-spacing: 0.3em;
    }
}

/* Reduced motion: same lifecycle, no travel/spacing motion — a plain fade.
   (The intro itself already plays for everyone; this only calms the motto.) */
@media (prefers-reduced-motion: reduce) {
    #heroMotto.hero-motto-play .hero-motto-text {
        animation-name: heroMottoFade;
    }
}

@keyframes heroMottoFade {
    0% { opacity: 0; }
    18% { opacity: 1; }
    78% { opacity: 1; }
    100% { opacity: 0; }
}

/* ═══════════════════════════════════════════════════════════════════
   Task 61 — Restoration badge + services banner, filter facets,
   brochure button, WYNTK cell edges, mobile card corner
   ═══════════════════════════════════════════════════════════════════ */

/* ── Restoration chip (property cards): black field + white caps, stacked
   with the Golden Visa (gold) and Exclusive (red) chips. A plain class —
   not utilities — so the badge-normaliser pass in script.js and the mobile
   rules below can target it precisely. ── */
.restoration-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    background: #121212;
    color: #fff;
    font-family: 'Inter', sans-serif;
    font-size: 10px;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    font-weight: 500;
    padding: 7px 14px;
    line-height: 1.2;
}

.restoration-chip svg {
    width: 12px;
    height: 12px;
    flex-shrink: 0;
}

/* ── Restoration services banner (listing page) — same visual family as
   the Golden Visa strip: paper card, brand-red border tone, red icons. ── */
.restoration-strip {
    border: 1px solid rgba(163, 0, 5, 0.25);
    border-left: 4px solid #A30005;
    background: #f7f6f0;
    padding: 24px;
}

.restoration-strip-head {
    display: flex;
    align-items: center;
}

.restoration-strip-text {
    font-family: 'Inter', sans-serif;
    font-size: 13px;
    line-height: 1.6;
    color: #374151;
    display: flex;
    align-items: center;
    gap: 12px;
    min-width: 0;
}

.restoration-strip-text svg {
    width: 20px;
    height: 20px;
    color: #A30005;
    flex-shrink: 0;
}

.restoration-strip-text strong {
    color: #121212;
    font-weight: 600;
}

/* The service mini-sections: how we restore — or rebuild from scratch. */
.restoration-services {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 20px;
    margin-top: 18px;
    padding-top: 18px;
    border-top: 1px solid rgba(163, 0, 5, 0.15);
}

.restoration-service {
    min-width: 0;
}

.restoration-service svg {
    width: 20px;
    height: 20px;
    color: #A30005;
    margin-bottom: 8px;
}

.restoration-service h4 {
    font-family: 'Inter', sans-serif;
    font-size: 11px;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    font-weight: 600;
    color: #121212;
    margin: 0 0 6px;
}

.restoration-service p {
    font-size: 13px;
    line-height: 1.65;
    color: #374151;
    margin: 0;
}

.restoration-strip-cta {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
    margin-top: 20px;
}

.restoration-link {
    font-family: 'Inter', sans-serif;
    font-size: 11px;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    font-weight: 500;
    text-decoration: none;
    padding: 10px 18px;
    white-space: nowrap;
    background: #A30005;
    color: #fff;
    border: 1px solid #A30005;
    transition: background 0.3s, color 0.3s, border-color 0.3s;
}

.restoration-link:hover {
    background: #7c0002;
    border-color: #7c0002;
    color: #fff;
}

.restoration-link--ghost {
    background: transparent;
    color: #A30005;
    border: 1px solid rgba(163, 0, 5, 0.4);
}

.restoration-link--ghost:hover {
    background: #A30005;
    border-color: #A30005;
    color: #fff;
}

@media (max-width: 760px) {
    .restoration-strip {
        padding: 18px;
    }

    .restoration-services {
        grid-template-columns: 1fr;
        gap: 16px;
    }
}

/* ── Advanced-search facet: Restoration checkbox (black tick, matching
   its black card badge) ── */
.flag-check--black input:checked ~ .flag-check-box {
    background: #000;
    border-color: #000;
}

/* ── Property brochure card: the download button adopts the Golden Visa
   strip button scheme (red outline on paper, red fill on hover) instead
   of the old solid black. Scoped override AFTER the shared
   .document-row button / .sidebar-card a rule so only the brochure card
   changes. ── */
.sidebar-card a {
    background: transparent;
    color: #A30005;
    border: 1px solid rgba(163, 0, 5, 0.4);
    letter-spacing: .16em;
    font-family: 'Inter', sans-serif;
    font-weight: 500;
    transition: background 0.3s, color 0.3s;
}

.sidebar-card a:hover {
    background: #A30005;
    color: #fff;
}

/* ── "What You Need to Know" cells: the edge colour matches the Golden
   Visa strip's red border instead of the neutral sand line. Scoped to the
   WYNTK grid only (Useful Information keeps its neutral edges). ── */
.info-grid.wyntk-grid div {
    border-color: rgba(163, 0, 5, 0.25);
}

/* ── Mobile property cards (≤640px): the badges spread across the top edge
   of the photo — Restoration top-left, Exclusive top-centre (the approved
   Task 61 centring), Golden Visa top-right. Spec chips stay in the black
   row under the card text. Desktop keeps the right-aligned corner stack.
   Chips are compacted so three badges coexist on a phone; below 401px every
   chip shrinks a step further so all badges stay on the ONE row (nothing
   ever drops to a second line). ── */
@media (max-width: 640px) {
    .property-card .card-corner > .card-specs-chip {
        display: none;
    }

    /* The corner becomes a full-width, zero-height positioning strip pinned
       under the photo's top edge; each badge anchors itself inside it. */
    .property-card .card-corner {
        left: 8px;
        right: 8px;
        max-width: none;
        display: block;
    }

    .property-card .card-corner > .restoration-chip {
        position: absolute;
        top: 0;
        left: 0;
        white-space: nowrap;
        font-size: 8px;
        letter-spacing: 0.08em;
        padding: 5px 8px;
        gap: 4px;
    }

    .property-card .card-corner > .gv-chip {
        position: absolute;
        top: 0;
        right: 0;
        white-space: nowrap;
        font-size: 8px;
        letter-spacing: 0.08em;
        padding: 5px 8px;
        gap: 4px;
    }

    /* The Exclusive badge has no stable class (utilities + inline tone), so
       it is reached by exclusion — same logic as the badge-normaliser pass
       in script.js. Its inner span ("• {title} • {tagline}") is desktop-only
       garnish: hidden on phones the badge reads simply "EXCLUSIVE", which is
       what frees the middle slot for the left/right badges. */
    .property-card .card-corner > div:not(.gv-chip):not(.restoration-chip):not(.card-specs-chip) {
        position: absolute;
        top: 0;
        left: 50%;
        transform: translateX(-50%);
        white-space: nowrap;
        font-size: 8px;
        letter-spacing: 0.08em;
        padding: 5px 8px;
    }

    .property-card .card-corner > div:not(.gv-chip):not(.restoration-chip):not(.card-specs-chip) > span {
        display: none;
    }
}

@media (max-width: 400px) {
    /* Shrink-to-fit: badges never drop to a second row — on small phones the
       Golden Visa used to hang lower (top:24px), which read as a collision
       with the Exclusive badge. Instead every badge STAYS on the one top row
       (Restoration left, Exclusive centre, Golden Visa right) and simply gets
       smaller so all three fit even on an iPhone SE (320px photo ≈ 264px). */
    .property-card .card-corner > .restoration-chip,
    .property-card .card-corner > .gv-chip {
        font-size: 7px;
        letter-spacing: 0.06em;
        padding: 4px 6px;
        gap: 3px;
    }

    .property-card .card-corner > .restoration-chip svg,
    .property-card .card-corner > .gv-chip svg {
        width: 8px;
        height: 8px;
    }

    .property-card .card-corner > div:not(.gv-chip):not(.restoration-chip):not(.card-specs-chip) {
        font-size: 7px;
        letter-spacing: 0.06em;
        padding: 4px 6px;
    }
}

@media (max-width: 330px) {
    /* Ultra-narrow (320px iPhone SE: photo ≈ 224px): one more size step down
       so the three badges keep a visible gap between each other instead of
       touching. Same one-row layout — nothing wraps, nothing drops. */
    .property-card .card-corner {
        left: 6px;
        right: 6px;
    }

    .property-card .card-corner > .restoration-chip,
    .property-card .card-corner > .gv-chip {
        font-size: 7px;
        letter-spacing: 0.04em;
        padding: 3px 5px;
        gap: 2px;
    }

    .property-card .card-corner > .restoration-chip svg,
    .property-card .card-corner > .gv-chip svg {
        width: 7px;
        height: 7px;
    }

    .property-card .card-corner > div:not(.gv-chip):not(.restoration-chip):not(.card-specs-chip) {
        font-size: 7px;
        letter-spacing: 0.04em;
        padding: 3px 5px;
    }
}

/* ════════════════════════════════════════════════════════════════════
   BRAND KEY (red) — the key from the footer logo ("E" of Estate)
   ════════════════════════════════════════════════════════════════════ */

/* Centred between the Advanced Search toggle and the Map View button
   (listings grid toolbar). Absolutely centred so it stays exactly in the
   middle regardless of the two buttons' widths. */
.search-toolbar {
    position: relative;
}

.toolbar-key {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    pointer-events: none;
    line-height: 0;
}

.toolbar-key img {
    display: block;
    height: 30px;
    width: auto;
}

/* Brochure sidebar card — key on the right edge, level with the heading. */
.sidebar-card--brochure {
    position: relative;
}

/* Keep the heading clear of the key (long translated headings wrap instead
   of colliding — e.g. Greek "Ενημερωτικό δελτίο ακινήτου"). */
.sidebar-card--brochure h3 {
    padding-right: 52px;
}

.sidebar-card--brochure .brochure-key {
    position: absolute;
    top: 26px;
    right: 26px;
    height: 52px;
    width: auto;
}

@media (max-width: 640px) {
    /* Mobile: the two buttons need the full row — the key drops to its own
       centred line underneath instead of squeezing between them. */
    .search-toolbar {
        flex-wrap: wrap;
        row-gap: 12px;
    }

    .toolbar-key {
        position: static;
        transform: none;
        order: 3;
        flex-basis: 100%;
        display: flex;
        justify-content: center;
    }

    .toolbar-key img {
        height: 26px;
    }

    .sidebar-card--brochure .brochure-key {
        top: 22px;
        right: 22px;
        height: 44px;
    }
}
