/* ============================================================
   site.css — public web template design system
   Springs-choreography language, parameterized by brand.config.
   Token values (--c-*, --font-*) are injected by SSR on :root;
   fallbacks below match the default preset.
   ============================================================ */

/* ---- Reset ---- */
*,
*::before,
*::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

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

/* ---- Tokens ---- */
:root {
  /* Color + font tokens: SSR overrides these from brand.config.web */
  --c-dark: #162d24;
  --c-dark-alt: #1b4732;
  --c-light: #e0d1b6;
  --c-card: #f5e8d1;
  --font-display: "Fraunces", serif;
  --font-text: "Hanken Grotesk", sans-serif;

  /* Fluid scale: 0.5px at 720px viewport, 1px at 1440px, clamped */
  --scale-px: clamp(0.5px, calc(0.5px + 0.5 * ((100vw - 720px) / 720)), 1px);

  /* Motion tokens */
  --ease: cubic-bezier(0.25, 0.74, 0.22, 0.99);
  --dur-micro: 0.4s;
  --dur-std: 0.8s;
  --dur-reveal: 1.6s;

  /* Gradient washes. The three accent tones fall back to green-leaning mixes
     (the demo look), but each accepts a --c-tone-* override injected from
     brand.config web.toneSea/toneMoss/toneGlow so an agency on a clashing
     palette (e.g. navy + gold) can retint the hero. See BRANDING.md. */
  --tone-deep: color-mix(in oklab, var(--c-dark) 78%, black);
  --tone-sea: var(--c-tone-sea, color-mix(in oklab, var(--c-dark) 45%, #145a66)); /* teal / turquoise */
  --tone-moss: var(--c-tone-moss, color-mix(in oklab, var(--c-dark-alt) 70%, #2a5a40));
  --tone-glow: var(--c-tone-glow, color-mix(in oklab, #8fd15a 74%, var(--c-light, #e0d1b6))); /* bright point of light */
  --wash-a: linear-gradient(180deg, var(--tone-deep) 0%, var(--c-dark) 55%, var(--c-dark-alt) 100%);
  --wash-b: linear-gradient(180deg, var(--tone-sea) 0%, color-mix(in oklab, var(--tone-sea) 60%, var(--c-dark-alt)) 60%, var(--c-dark-alt) 100%);
  --wash-menu: linear-gradient(180deg, var(--tone-deep) 0%, var(--c-dark-alt) 55%, var(--tone-moss) 100%);
  --wash-text: linear-gradient(to top, rgba(8, 16, 13, 0.82) 0%, rgba(8, 16, 13, 0) 50%);
}

/* ---- Base ---- */
html {
  overflow-x: clip; /* belt against any stray horizontal overflow */
}

body {
  background: var(--c-dark, #162d24);
  background-image: var(--wash-a);
  background-attachment: fixed;
  color: var(--c-light, #e0d1b6);
  font-family: var(--font-text, sans-serif);
  overscroll-behavior: none;
  -webkit-font-smoothing: antialiased;
}

/* ---- Typography ---- */
.display {
  font-family: var(--font-display, serif);
  font-size: calc(var(--scale-px) * 140);
  font-weight: 350;
  line-height: 0.95;
  color: var(--c-light, #e0d1b6);
}

.display--md {
  font-size: calc(var(--scale-px) * 80);
}

.display--sm {
  font-size: calc(var(--scale-px) * 48);
}

.kicker {
  font-family: var(--font-text, sans-serif);
  font-size: calc(var(--scale-px) * 13);
  text-transform: uppercase;
  letter-spacing: 0.12em;
  opacity: 0.8;
}

/* ---- Components ---- */
.pill {
  display: inline-block;
  border: 1px solid currentColor;
  border-radius: 999px;
  padding: 0.5em 1.2em;
  font-family: var(--font-text, sans-serif);
  font-size: calc(var(--scale-px) * 13);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  background: transparent;
  color: inherit;
  cursor: pointer;
  transition: background-color var(--dur-micro) var(--ease),
    color var(--dur-micro) var(--ease);
}

.pill.is-active {
  background: var(--c-light, #e0d1b6);
  color: var(--c-dark, #162d24);
  border-color: var(--c-light, #e0d1b6);
}

.card-light {
  background: var(--c-card, #f5e8d1);
  color: var(--c-dark, #162d24);
  border-radius: 2px;
}

/* Contract: place .full-bleed as a direct child of a full-width section
   (not inside .px-layout). 100% avoids the 100vw scrollbar-gutter overflow. */
.full-bleed {
  width: 100%;
  height: 100vh; /* fallback */
  height: 100lvh;
  object-fit: cover;
}

/* ---- Reveal states (toggled by motion.js via .is-inview) ----
   Hidden state is gated on html.js so content stays visible without
   JavaScript (SSR pages, crawlers, blocked scripts). The shell swaps
   the no-js class for js in an inline script before paint (Task 6). */
html.js [data-reveal] {
  opacity: 0;
  transform: translateY(40px);
}

html.js [data-reveal].is-inview {
  opacity: 1;
  transform: none;
  transition: opacity var(--dur-reveal) var(--ease),
    transform var(--dur-reveal) var(--ease);
}

html.js [data-reveal="mask"] {
  clip-path: inset(100% 0 0 0);
  opacity: 1;
  transform: none;
}

html.js [data-reveal="mask"].is-inview {
  clip-path: inset(0 0 0 0);
  transition: clip-path var(--dur-reveal) var(--ease);
}

/* Top-down reveal (springs scene 10, property gallery): mirrors
   [data-reveal="mask"] but the hidden band sits at the BOTTOM of the box
   (inset 0 0 100% 0), so opening it uncovers the image from the top edge
   downward instead of bottom-up. Class-based like every other reveal
   (motion.js just adds .is-inview generically), so no JS change needed. */
html.js [data-reveal="mask-down"] {
  clip-path: inset(0 0 100% 0);
  opacity: 1;
  transform: none;
}

html.js [data-reveal="mask-down"].is-inview {
  clip-path: inset(0 0 0 0);
  transition: clip-path var(--dur-reveal) var(--ease);
}


/* ---- Scrub progress (driven by motion.js as --p on [data-scrub]) ----
   Default 1 = finished state, so touch, reduced-motion and no-js modes
   render every scrubbed timeline at rest instead of frozen mid-flight. */
[data-scrub] {
  --p: 1;
}

/* ---- Curtain chain ----
   Static-clip overlap: the section that follows a pinned range physically
   overlaps it (negative margin-top) and hides its own overlapping first
   viewport with a STATIC clip-path (relative to its own box). As the box
   rises with scroll, the clip stays put in document space relative to the
   box, so the content enters like a curtain rising — no per-frame clip
   animation needed. See docs/HANDOFF and the motion v3 spec §3/§5.2.

   .curtain--under: a pinned range whose pin is meant to be COVERED by the
   next section (stacks below it). .curtain--over: the incoming section
   that does the covering (stacks above, overlaps up by one viewport, and
   is opaque so the previous pin never bleeds through at the edges). A
   section chained on both sides carries both classes. position: relative
   is required on both — clip-path alone does not reliably establish a
   stacking context across engines. */
.curtain--under {
  position: relative;
  z-index: 1;
}

.curtain--over {
  position: relative;
  z-index: 2;
  /* Overlap = clip (100svh) + one viewport (100svh): the crossing must END
     exactly when the previous pin unfreezes (range height - 100svh), so the
     whole curtain rises over a FIXED pin. With only -100svh the visible edge
     would enter at the freeze point and the previous section would slide
     away natively: no curtain at all, just normal flow. The under-range must
     budget 200svh of runway after its solo time (hero: 300svh = 100 solo +
     100 crossing + 100 covered). */
  margin-top: -200svh;
  clip-path: inset(100svh 0 0);
  background: var(--c-dark, #162d24);
  /* Fragment jumps target the border-box top, which sits one viewport under
     the clip: land at the end of the crossing instead. */
  scroll-margin-top: -100svh;
}

/* Spacer: the box's first (clipped) viewport must be EMPTY, or the section's
   own headline content lives in the permanently hidden band. Also guarantees
   the visible box is tall enough to keep the frozen pin covered. Chain note:
   consecutive curtain--over sections tie at z-index 2 and document order
   breaks the tie — do not "fix" that with per-section z-indexes. */
.curtain--over::before {
  content: "";
  display: block;
  height: 100svh;
}

/* ---- Layout utilities ---- */
.px-layout {
  padding-left: calc(var(--scale-px) * 60);
  padding-right: calc(var(--scale-px) * 60);
}

.section-dark {
  background: var(--c-dark, #162d24);
}

.section-dark-alt {
  background: var(--c-dark-alt, #1b4732);
}

.grid-12 {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: calc(var(--scale-px) * 24);
}

.col-span-6 {
  grid-column: span 6;
}

.col-span-4 {
  grid-column: span 4;
}

.col-span-3 {
  grid-column: span 3;
}

@media (max-width: 768px) {
  .px-layout {
    padding-left: 20px;
    padding-right: 20px;
  }

  .grid-12 {
    grid-template-columns: 1fr;
  }

  .col-span-6,
  .col-span-4,
  .col-span-3 {
    grid-column: auto;
  }
}

/* ---- Reduced motion ---- */
@media (prefers-reduced-motion: reduce) {
  [data-reveal],
  [data-reveal="mask"],
  [data-reveal="mask-down"] {
    opacity: 1 !important;
    transform: none !important;
    clip-path: none !important;
    transition: none !important;
  }

  .hero__reel {
    transform: rotate(-28deg) !important;
  }

  .home-band__media img,
  .home-contact__bg img {
    transform: none !important;
  }

  .home-vitrine--cream,
  .home-band {
    clip-path: none !important;
  }

  /* motion.js never runs in this mode (see the engine's reduced-motion
     guard), so [data-speed] wrappers (intro head, split text/images) never
     receive an inline transform — nothing to neutralize here beyond the
     media transforms above. */
}

/* ---- Shell: nav, menu overlay, footer ---- */
.site-nav {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  /* Above .menu-overlay (55) so the burger stays clickable to close it. */
  z-index: 56;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  padding: calc(var(--scale-px) * 20) calc(var(--scale-px) * 60);
  color: var(--c-light, #e0d1b6);
  /* Clean over the hero: a subtle top gradient for legibility, no bar. */
  background: linear-gradient(
    to bottom,
    rgba(6, 14, 11, 0.5) 0%,
    rgba(6, 14, 11, 0.22) 55%,
    rgba(6, 14, 11, 0) 100%
  );
}

/* The glass bar itself is a SEPARATE layer (like springs' .header__background):
   pure backdrop blur over a TRANSPARENT background — no colour fill, that is
   what actually reads as glass — with a bright white crystal hairline via
   box-shadow. It slides down into place when .is-glass is set, and retracts
   (merging back to the clean hero) when removed. Sits above the nav's own
   gradient (negative z-index) but below the menu/logo/contact content. */
.site-nav::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: transparent;
  -webkit-backdrop-filter: blur(16px) saturate(1.3);
  backdrop-filter: blur(16px) saturate(1.3);
  box-shadow:
    0 0 0 1px rgba(255, 255, 255, 0.32),
    inset 0 1px 0 0 rgba(255, 255, 255, 0.45),
    0 10px 30px rgba(6, 14, 11, 0.16);
  transform: translateY(-101%);
  opacity: 0;
  transition: transform var(--dur-std) var(--ease),
    opacity var(--dur-std) var(--ease);
  pointer-events: none;
}

.site-nav.is-glass::before {
  transform: translateY(0);
  opacity: 1;
}

.site-nav__menu {
  display: flex;
  align-items: center;
  gap: calc(var(--scale-px) * 12);
}

.menu-btn {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: 40px;
  height: 40px;
  padding: 8px;
  background: none;
  border: 0;
  cursor: pointer;
  /* Buttons do not inherit color from the UA stylesheet: force it so the
     bars (background: currentColor) are cream, not the default black. */
  color: inherit;
}

.menu-btn span {
  display: block;
  width: 24px;
  height: 1px;
  background: currentColor;
  transition: transform var(--dur-micro) var(--ease),
    opacity var(--dur-micro) var(--ease);
}

.menu-btn__label {
  font-size: calc(var(--scale-px) * 13);
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.site-nav__logo {
  justify-self: center;
  display: block;
}

.site-nav__logo img {
  display: block;
  height: calc(var(--scale-px) * 36);
  width: auto;
}

.site-nav__actions {
  justify-self: end;
  display: flex;
  align-items: center;
  gap: calc(var(--scale-px) * 20);
}

/* ---- Text roll (springs-style hover): the label rolls up and an identical
   copy rolls into its place. Two stacked lines clipped to one line-height;
   trigger via `js-roll` on the interactive ancestor (hover or keyboard focus
   within). Line-height 1.12 keeps accents (é, à) from being clipped. ---- */
.roll {
  display: inline-block;
  position: relative;
  overflow: hidden;
  vertical-align: bottom;
  line-height: 1.12;
}

.roll__t {
  display: block;
  transition: transform var(--dur-std) var(--ease);
}

.roll__t--clone {
  position: absolute;
  top: 100%;
  left: 0;
}

.js-roll:hover .roll__t,
.js-roll:focus-within .roll__t {
  transform: translateY(-100%);
}

@media (prefers-reduced-motion: reduce) {
  .roll__t {
    transition: none;
  }
  .js-roll:hover .roll__t,
  .js-roll:focus-within .roll__t {
    transform: none;
  }
}

.site-nav__contact {
  font-size: calc(var(--scale-px) * 13);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  text-decoration: none;
  color: inherit;
}

/* Language toggle: same kicker language as the nav, set apart by a leading
   hairline so it reads as a switch, not another nav link. */
.site-nav__lang {
  font-size: calc(var(--scale-px) * 13);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  text-decoration: none;
  color: inherit;
  opacity: 0.75;
  padding-right: calc(var(--scale-px) * 20);
  border-right: 1px solid color-mix(in srgb, currentColor 35%, transparent);
  transition: opacity var(--dur-micro) var(--ease);
}

.site-nav__lang:hover {
  opacity: 1;
}

.menu-overlay__lang {
  color: inherit;
  text-decoration: none;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  opacity: 0.75;
}

.menu-overlay {
  position: fixed;
  inset: 0;
  z-index: 55;
  display: grid;
  grid-template-columns: minmax(420px, 45%) 1fr;
  opacity: 0;
  pointer-events: none;
  /* visibility removes the hidden links from the tab order (a11y);
     delayed on close so the opacity fade still plays. */
  visibility: hidden;
  transition: opacity var(--dur-micro) var(--ease),
    visibility 0s var(--dur-micro);
}

.menu-overlay.is-open {
  opacity: 1;
  pointer-events: auto;
  visibility: visible;
  transition: opacity var(--dur-micro) var(--ease);
}

/* Burger morphs into an X while the menu is open. */
.menu-btn[aria-expanded="true"] span:nth-child(1) {
  transform: translateY(6px) rotate(45deg);
}

.menu-btn[aria-expanded="true"] span:nth-child(2) {
  opacity: 0;
}

.menu-btn[aria-expanded="true"] span:nth-child(3) {
  transform: translateY(-6px) rotate(-45deg);
}

/* Left half: gradient wash panel, serif links aligned left. */
.menu-overlay__panel {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: calc(var(--scale-px) * 140) calc(var(--scale-px) * 60) calc(var(--scale-px) * 48);
  /* Solid fallback first: --wash-menu needs color-mix (Safari 16.2+). */
  background: var(--c-dark-alt, #1b4732);
  background: var(--wash-menu);
  /* All menu text is the cream letter colour on the dark panel. */
  color: var(--c-light, #e0d1b6);
}

.menu-overlay__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: calc(var(--scale-px) * 8);
}

/* Links fade in with the menu — no lateral slide (Josué). */
.menu-overlay__link {
  display: inline-block;
  color: var(--c-light, #e0d1b6);
  text-decoration: none;
  opacity: 0;
  transition: opacity var(--dur-std) var(--ease);
}

.menu-overlay.is-open .menu-overlay__link {
  opacity: 1;
}

.menu-overlay__meta {
  display: flex;
  flex-direction: column;
  gap: calc(var(--scale-px) * 6);
  font-size: calc(var(--scale-px) * 14);
  opacity: 0.75;
}

.menu-overlay__meta a {
  color: inherit;
  text-decoration: none;
}

/* Right half: stacked photographs, cross-faded on hover of the nav items.
   Each .menu-preview maps to a nav item's data-preview key; the overlay's
   data-preview attribute (set by MENU_SCRIPT) decides which is visible. */
.menu-overlay__photo {
  position: relative;
  overflow: hidden;
}

.menu-preview {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transform: scale(1.06);
  transition: opacity var(--dur-std) var(--ease),
    transform var(--dur-reveal) var(--ease);
}

/* Default (menu just opened, nothing hovered) shows the home image. */
.menu-preview--home {
  opacity: 1;
}

.menu-overlay[data-preview] .menu-preview {
  opacity: 0;
}

.menu-overlay[data-preview="home"] .menu-preview--home,
.menu-overlay[data-preview="biens"] .menu-preview--biens,
.menu-overlay[data-preview="equipe"] .menu-preview--equipe,
.menu-overlay[data-preview="contact"] .menu-preview--contact {
  opacity: 1;
}

.menu-overlay.is-open .menu-preview {
  transform: scale(1);
}

.site-footer {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: start;
  gap: calc(var(--scale-px) * 48);
  padding-top: calc(var(--scale-px) * 96);
  padding-bottom: calc(var(--scale-px) * 64);
  color: var(--c-light, #e0d1b6);
}

.site-footer a {
  color: inherit;
  text-decoration: none;
}

.site-footer__logo img {
  display: block;
  height: calc(var(--scale-px) * 40);
  width: auto;
}

.site-footer__nav {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: calc(var(--scale-px) * 10);
  font-size: calc(var(--scale-px) * 14);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.site-footer__legal {
  text-align: right;
  font-size: calc(var(--scale-px) * 14);
  opacity: 0.8;
}

.site-footer__legal p {
  margin: 0 0 calc(var(--scale-px) * 8);
}

/* ---- Footer trust row: configurable review badges + social links ----
   Spans all footer columns, set off by the same hairline as the builder credit.
   Everything is monochrome (currentColor) except the review stars, which take
   the brand accent; agencies without any of this configured see nothing. */
.site-footer__trust {
  grid-column: 1 / -1;
  margin-top: calc(var(--scale-px) * 40);
  padding-top: calc(var(--scale-px) * 28);
  border-top: 1px solid color-mix(in srgb, var(--c-light, #e0d1b6) 14%, transparent);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: calc(var(--scale-px) * 24);
}

.site-reviews {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: calc(var(--scale-px) * 28);
}

.site-review {
  display: inline-flex;
  align-items: center;
  gap: calc(var(--scale-px) * 8);
  font-size: calc(var(--scale-px) * 14);
  opacity: 0.85;
  transition: opacity var(--dur-micro) var(--ease);
}
.site-review:hover { opacity: 1; }
.site-review__name { font-weight: 500; letter-spacing: 0.02em; }
.site-review__stars {
  display: inline-flex;
  align-items: center;
  gap: calc(var(--scale-px) * 1);
  color: var(--c-accent, #c9a45c);
}
.site-review__score { font-variant-numeric: tabular-nums; }
.site-review__count { opacity: 0.7; }

.site-socials {
  display: inline-flex;
  align-items: center;
  gap: calc(var(--scale-px) * 18);
}
.site-socials a {
  display: inline-flex;
  opacity: 0.8;
  transition: opacity var(--dur-micro) var(--ease), transform var(--dur-micro) var(--ease);
}
.site-socials a:hover { opacity: 1; transform: translateY(-2px); }

/* ---- Builder credit (Powered by MonkeyWeaver) ----
   The wordmark is a CSS mask filled with currentColor, so the logo takes the
   host site's footer text colour. Reusable across every MonkeyWeaver project:
   the same SVG + these rules re-theme to whatever palette they land in. */
.site-credit {
  padding: calc(var(--scale-px) * 28) calc(var(--scale-px) * 60);
  border-top: 1px solid color-mix(in srgb, var(--c-light, #e0d1b6) 14%, transparent);
  text-align: center;
}

.site-credit__link {
  display: inline-flex;
  align-items: center;
  gap: calc(var(--scale-px) * 12);
  color: var(--c-light, #e0d1b6);
  text-decoration: none;
  opacity: 0.7;
  transition: opacity var(--dur-micro) var(--ease);
}

.site-credit__link:hover {
  opacity: 1;
}

.site-credit__by,
.site-credit__tag {
  font-family: var(--font-text, sans-serif);
  font-size: calc(var(--scale-px) * 12);
  text-transform: uppercase;
  letter-spacing: 0.12em;
}

.site-credit__tag {
  opacity: 0.7;
}

/* currentColor fill via mask → adapts to whatever palette the footer uses. */
.site-credit__logo {
  display: inline-block;
  height: calc(var(--scale-px) * 30);
  aspect-ratio: 418 / 191;
  background-color: currentColor;
  -webkit-mask: url(/monkeyweaver-wordmark.svg) center / contain no-repeat;
  mask: url(/monkeyweaver-wordmark.svg) center / contain no-repeat;
}

@media (max-width: 768px) {
  .site-nav {
    padding: 14px 20px;
  }

  /* Stack the credit so the logo stays legible on a narrow bar. */
  .site-credit__link {
    flex-direction: column;
    gap: 8px;
  }

  .site-credit__logo {
    height: 26px;
  }

  /* Keep the top bar uncrowded on phones: the language toggle stays, the
     Contact link folds into the menu (and the property dock covers contact). */
  .site-nav__contact {
    display: none;
  }

  .site-nav__lang {
    padding-right: 0;
    border-right: none;
    /* Fixed 44px tap target + legible size: --scale-px floors to 0.5px at
       375px, which would render the label at ~6.5px and an ~8px tap box. */
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    font-size: 13px;
  }

  .site-footer {
    grid-template-columns: 1fr;
    gap: 32px;
  }

  .site-footer__legal {
    text-align: left;
  }

  .menu-overlay {
    grid-template-columns: 1fr;
  }

  .menu-overlay__photo {
    display: none;
  }

  .menu-overlay__panel {
    padding: calc(var(--scale-px) * 120) 20px 32px;
  }
}

/* ---- Home ---- */

/* Preloader: full-screen brand veil; motion.js drives --progress and the
   FLIP hand-off, then removes the node. Hidden without JS so the page is
   never covered when motion.js cannot run. */
html.no-js #preloader {
  display: none;
}

#preloader {
  position: fixed;
  inset: 0;
  z-index: 70;
  display: grid;
  place-items: center;
  background: var(--c-dark, #162d24);
}

/* Offset wrapper: keeps the 45vh placement out of .preloader-logo, whose
   transform is owned by the motion.js FLIP animation. */
.preloader-logo-wrap {
  transform: translateY(45vh) scale(1.5);
}

.preloader-logo {
  position: relative;
}

.preloader-logo img {
  display: block;
  height: calc(var(--scale-px) * 48);
  width: auto;
}

.preloader-logo__base {
  opacity: 0.3;
}

/* Fill layer: clipped from the bottom up as --progress goes 0 → 1. */
.preloader-logo__fill {
  position: absolute;
  inset: 0;
  clip-path: inset(calc(100% - var(--progress, 0) * 100%) 0 0 0);
}

/* Hero: autonomous reel, pinned for 250svh so the following section can
   curtain over it. The reel itself is time-driven (motion.js module 10),
   never touched by scroll or scrub — no --p dependency here. */
.hero {
  position: relative;
}

/* Coverable: z-index and position come from the generic .curtain--under. */

.hero__pin {
  position: relative;
  height: 100svh;
  overflow: hidden;
}

/* Rotated oversized reel, centered by negative margins so the -28°
   rotation never exposes the container edges. Three stacked rows, each an
   endless belt of absolutely-positioned tiles (module 10 writes translateX
   inline; no translateY needed since rows are separate containers). */
.hero__reel {
  position: absolute;
  left: 50%;
  top: 50%;
  /* Wide enough for the belt's largest wrap window (175vw middle row) plus
     one tile, so the wrap seam always sits outside the viewport. Tall enough
     (200vh) that the three equal bands overflow the viewport: the top band
     bleeds off the top and the bottom band off the bottom, cropped by the
     pin's overflow, so the reel has no hard edges and the centre dominates. */
  width: 200vw;
  height: 200vh;
  margin-left: -100vw;
  margin-top: -100vh;
  transform: rotate(-28deg);
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 2.5vw;
}

/* Three bands of large ~4:5 portrait tiles (matching the reference: big
   photos, thin dark-green frame between them, NOT skinny strips in a sea of
   green). The MIDDLE band is taller so it dominates the centre; the -28°
   rotation throws the outer bands into the top-left and bottom-right corners
   where the gradient dissolves them. Tile width (23vw) sits just under the
   25vw belt pitch, so the gutter is a ~2vw frame. */
/* All three bands share ONE height (Josué), but TALL: the tiles read strongly
   portrait (Y ≫ X) and the outer bands run off the top and bottom of the
   viewport. The centre dominates by position, not by being taller. */
.hero__reel-row {
  position: relative;
  height: 58vh;
}

.hero__reel-row:nth-child(2) {
  margin-left: -12vw; /* static-grid offset (no-js); the engine zeroes it */
}

.hero__reel-row:nth-child(3) {
  margin-left: -6vw;
}

.hero__tile {
  position: absolute;
  top: 0;
  /* Large and gently portrait (≈4:5 on a laptop): near the belt pitch so the
     gutter is a thin frame, tall band height makes Y > X. */
  width: 23vw;
  height: 100%;
  overflow: hidden;
  border-radius: 2px;
}

.hero__tile img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Josué (2026-07-08): the zoom-from-a-point entrance was removed. Tiles are
   full-size from frame 0 so the reel is already circulating on first load, no
   grow-in. will-change stays as a perf hint for the reel's transform. */
@media (pointer: fine) and (prefers-reduced-motion: no-preference) {
  html.js .hero__tile {
    will-change: transform;
  }
}

/* Green gradient pooled at the BOTTOM-RIGHT corner (Josué): it seats the
   serif title (bottom-right) and dissolves the lower-right reel band into
   green. Deep and opaque at the very corner, fading out by ~62% radius so the
   centre reel stays clear. */
.hero__gradient {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  /* Four tonal points, mapped from Josué's annotated reference (the colour
     bubbles + red circles): teal top-left, a bright green point of light in
     the lower-left-centre, dark green top-right, and a forest-green pool
     bottom-right that seats the title. This IS the layer between the photos
     and the text. NOT a flat wash. */
  background:
    /* bright green point of light, lower-left of centre — pronounced */
    radial-gradient(
      40% 45% at 19% 72%,
      color-mix(in oklab, var(--tone-glow, #a6dd7a) 71%, transparent) 0%,
      color-mix(in oklab, var(--tone-glow, #a6dd7a) 29%, transparent) 42%,
      transparent 66%
    ),
    /* teal / turquoise, top-left — opaque at the corner, fading in */
    radial-gradient(
      78% 72% at 12% 10%,
      var(--tone-sea, #17414a) 0%,
      color-mix(in oklab, var(--tone-sea, #17414a) 52%, transparent) 40%,
      transparent 66%
    ),
    /* dark green, top-right — pronounced, opaque at the corner */
    radial-gradient(
      56% 56% at 80% 2%,
      var(--c-dark, #162d24) 0%,
      color-mix(in oklab, var(--c-dark, #162d24) 55%, transparent) 34%,
      transparent 60%
    ),
    /* forest-green pool, bottom-right — deeply filled at the corner so the
       title sits on near-solid colour (Josué: filled, but 15% more see-through). */
    radial-gradient(
      96% 90% at 100% 92%,
      color-mix(in oklab, var(--c-dark-alt, #1b4732) 85%, transparent) 0%,
      color-mix(in oklab, var(--c-dark-alt, #1b4732) 85%, transparent) 38%,
      color-mix(in oklab, var(--c-dark-alt, #1b4732) 47%, transparent) 60%,
      transparent 80%
    );
}

/* The cohesive green atmosphere: a flat wash over the whole reel unifies the
   varied photography into one branded scene (our tiles are warm interiors,
   not all-green nature like the reference, so this tint does more work here),
   plus corner vignettes that recede the top-left band and the left edge under
   the subtitle. The bottom-right is handled by .hero__gradient above. */
.hero__veil {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background:
    /* Top edge dissolves the upper band into the background (the artistic
       bleed: no hard reel edge). Covers the nav strip too, helping its copy. */
    linear-gradient(
      to bottom,
      color-mix(in oklab, var(--c-dark, #162d24) 70%, transparent) 0%,
      color-mix(in oklab, var(--c-dark, #162d24) 24%, transparent) 14%,
      transparent 30%
    ),
    /* Subtitle legibility, centre-left low. */
    radial-gradient(60% 54% at 6% 60%, color-mix(in oklab, var(--c-dark, #162d24) 38%, transparent) 0%, transparent 55%),
    /* Thin cohesive atmosphere: unify without flattening the tonal points. */
    color-mix(in oklab, var(--c-dark, #162d24) 16%, transparent);
}

/* Screen-reader-only: keeps a descriptive hero <h1> for SEO/a11y after the big
   display title was replaced by the search card. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ---- Hero search: frosted glass card on the right of the hero ----
   Readable fixed sizing (the springs --scale-px halves below 720px, which would
   render form text far too small); glass = real backdrop-blur over a translucent
   crème-white panel, dark-green ink to match the brand. */
/* Right-hand hero panel: stacks the glass search card and, beneath it, the
   tagline. Positioned once here; the card itself is a static flex child. */
.hero__panel {
  position: absolute;
  z-index: 3;
  right: clamp(16px, 14vw, 260px);
  top: 50%;
  transform: translateY(-50%);
  width: min(92vw, 460px);
  display: flex;
  flex-direction: column;
  gap: 22px;
}

.hero-search {
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 22px;
  padding: 30px 30px 26px;
  border-radius: 22px;
  color: var(--c-dark, #162d24);
  background: color-mix(in srgb, #ffffff 46%, transparent);
  border: 1px solid color-mix(in srgb, #ffffff 55%, transparent);
  box-shadow: 0 34px 80px -28px rgba(10, 20, 15, 0.55);
  backdrop-filter: blur(20px) saturate(1.15);
  -webkit-backdrop-filter: blur(20px) saturate(1.15);
}

.hero-search__tabs {
  display: flex;
  gap: 36px;
  padding-bottom: 4px;
}
.hero-search__tab {
  position: relative;
  cursor: pointer;
  font-family: var(--font-text, sans-serif);
  font-size: 17px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: color-mix(in srgb, var(--c-dark, #162d24) 45%, transparent);
  transition: color var(--dur-micro) var(--ease);
}
.hero-search__tab input {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
  pointer-events: none;
}
.hero-search__tab:has(input:checked) { color: var(--c-dark, #162d24); }
.hero-search__tab:has(input:focus-visible) {
  outline: 2px solid var(--c-accent, #c9a45c);
  outline-offset: 4px;
  border-radius: 3px;
}

.hero-search__field {
  display: flex;
  align-items: center;
  gap: 10px;
  border-bottom: 1px solid color-mix(in srgb, var(--c-dark, #162d24) 26%, transparent);
  padding-bottom: 8px;
  transition: border-color var(--dur-micro) var(--ease);
}
.hero-search__field:focus-within { border-bottom-color: var(--c-dark, #162d24); }
.hero-search__icon { flex: none; color: color-mix(in srgb, var(--c-dark, #162d24) 55%, transparent); }
.hero-search__field input {
  flex: 1;
  min-width: 0;
  border: 0;
  padding: 0;
  background: transparent;
  font-family: var(--font-text, sans-serif);
  font-size: 17px;
  color: var(--c-dark, #162d24);
}
.hero-search__field input:focus { outline: none; }
.hero-search__field input::placeholder { color: color-mix(in srgb, var(--c-dark, #162d24) 45%, transparent); }
.hero-search__suffix {
  flex: none;
  font-size: 17px;
  color: color-mix(in srgb, var(--c-dark, #162d24) 55%, transparent);
}
.hero-search__field input[type="number"] { appearance: textfield; -moz-appearance: textfield; }
.hero-search__field input[type="number"]::-webkit-inner-spin-button,
.hero-search__field input[type="number"]::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }

.hero-search__row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 24px;
}

.hero-search__actions {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
  margin-top: 4px;
}
.hero-search__more,
.hero-search__submit {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  height: 60px;
  border-radius: 12px;
  font-family: var(--font-text, sans-serif);
  font-size: 14px;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background-color var(--dur-micro) var(--ease),
    color var(--dur-micro) var(--ease), border-color var(--dur-micro) var(--ease),
    transform var(--dur-micro) var(--ease);
}
.hero-search__more {
  color: var(--c-dark, #162d24);
  background: transparent;
  border: 1px solid color-mix(in srgb, var(--c-dark, #162d24) 35%, transparent);
  text-decoration: none;
}
.hero-search__more:hover { border-color: var(--c-dark, #162d24); }
.hero-search__submit {
  color: var(--c-light, #e0d1b6);
  background: var(--c-dark, #162d24);
  border: 1px solid var(--c-dark, #162d24);
}
.hero-search__submit:hover { transform: translateY(-2px); }
.hero-search__submit svg { transition: transform var(--dur-micro) var(--ease); }
.hero-search__submit:hover svg { transform: translateX(4px); }

@media (max-width: 860px) {
  .hero__panel {
    right: 50%;
    transform: translate(50%, -50%);
    width: min(92vw, 420px);
  }
  .hero-search {
    gap: 18px;
    padding: 22px 22px 20px;
    border-radius: 18px;
  }
  .hero-search__tab { font-size: 14px; letter-spacing: 0.12em; }
  .hero-search__field input,
  .hero-search__suffix { font-size: 15px; }
  .hero-search__more,
  .hero-search__submit { height: 50px; font-size: 12px; }
  .hero__subtitle { font-size: clamp(22px, 6vw, 30px); }
}

/* Tagline sitting under the search card, centred to the panel. */
.hero__subtitle {
  margin: 0;
  text-align: left;
  color: var(--c-light, #e0d1b6);
  font-family: var(--font-display, serif);
  font-size: clamp(30px, 3.4vw, 52px);
  line-height: 1.05;
  letter-spacing: 0;
  text-shadow: 0 1px 14px rgba(10, 20, 15, 0.5);
}

.hero__arrow {
  position: absolute;
  left: calc(var(--scale-px) * 60);
  bottom: calc(var(--scale-px) * 60);
  z-index: 2;
  display: grid;
  place-items: center;
  width: calc(var(--scale-px) * 56);
  height: calc(var(--scale-px) * 56);
  border: 1px solid currentColor;
  border-radius: 50%;
  color: var(--c-light, #e0d1b6);
  transition: background-color var(--dur-micro) var(--ease),
    color var(--dur-micro) var(--ease);
}

.hero__arrow:hover {
  background: var(--c-light, #e0d1b6);
  color: var(--c-dark, #162d24);
}

/* Intro "glass bar" (springs opening scene): a translucent green panel (left)
   holding the editorial line, with a building photo (right). curtain--over
   rises it over the hero; the glass is translucent so the hero reel shows
   through and the panel merges with the hero as you scroll in and out; then an
   inner pin holds it still while the vitrine wipes across (Josué v3.2). */
.home-intro {
  position: relative;
  overflow: hidden;
}

/* Transparent section: the glass panel's own translucency (not an opaque
   curtain fill) is what lets the hero read through it. Overrides the default
   opaque .curtain--over background. */
.home-intro.curtain--over {
  background: transparent;
}

.home-intro__range {
  position: relative;
}

.home-intro__pin {
  position: relative;
  height: 100svh;
  overflow: hidden;
  display: grid;
  grid-template-columns: 46% 54%;
}

/* Left: the glass. Translucent green + a soft blur so the reel behind reads as
   frosted glass, not a clear window. */
.home-intro__glass {
  position: relative;
  display: flex;
  align-items: flex-end;
  padding: calc(var(--scale-px) * 96) calc(var(--scale-px) * 60);
  background: color-mix(in oklab, var(--c-dark, #162d24) 68%, transparent);
  -webkit-backdrop-filter: blur(7px);
  backdrop-filter: blur(7px);
}

.home-intro__copy {
  position: relative;
  max-width: 14em;
}

.home-intro__title {
  /* 14em keeps "Immobilier de caractère" to two lines; at 12em "de caractère"
     wrapped to a third line that the bottom-anchored copy pushed below the
     viewport, so the phrase read as cut off. */
  max-width: 14em;
  margin-top: calc(var(--scale-px) * 20);
}

/* Right: the building photo, full height. */
.home-intro__photo {
  position: relative;
  overflow: hidden;
}

.home-intro__photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Number card section (between the glass bar and the vitrine). Same curtain +
   pin pattern as the intro; the rock/foam texture is its scene, the framed
   stat card centred over it. */
.home-stat {
  position: relative;
  overflow: hidden;
}

.home-stat__range {
  position: relative;
}

.home-stat__pin {
  position: relative;
  height: 100svh;
  overflow: hidden;
  display: grid;
  place-items: center;
}

.home-stat__bg {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
}

.home-stat__bg img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.home-stat__bg::after {
  content: "";
  position: absolute;
  inset: 0;
  background: color-mix(in oklab, var(--c-dark, #162d24) 55%, transparent);
}

/* The framed stat card: dark panel, inset photo, giant serif figure. */
.stat-card {
  position: relative;
  z-index: 1;
  /* Solid first: --tone-deep needs color-mix (Safari 16.2+). */
  background: #10241d;
  background: var(--tone-deep, #10241d);
  padding: calc(var(--scale-px) * 24) calc(var(--scale-px) * 24) calc(var(--scale-px) * 28);
  display: flex;
  flex-direction: column;
  gap: calc(var(--scale-px) * 36);
  width: min(90vw, calc(var(--scale-px) * 440));
}

.stat-card__media {
  width: 100%;
  aspect-ratio: 1 / 1;
  object-fit: cover;
}

.stat-card__figure {
  font-size: calc(var(--scale-px) * 130);
  line-height: 0.8;
}

.stat-card__caption {
  text-align: right;
  opacity: 0.9;
}

/* Vitrine: draggable featured slider. As curtain--wipe it overlaps the pinned
   intro and its own pin holds the cream screen while a scroll-driven clip
   wipes it in left to right (the horizontal cut over a static screen). */
.curtain--wipe {
  position: relative;
  z-index: 2;
  /* Overlap the intro's held viewport so the wipe covers a still screen. */
  margin-top: -200svh;
}

.home-vitrine__range {
  position: relative;
}

.home-vitrine__pin {
  position: relative;
  height: 100svh;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  justify-content: center;
  /* Opaque cream so the revealed (left) side covers the intro beneath; the
     clipped (right) side lets the still intro show through as the wipe moves.
     --p (scrub range) drives the horizontal reveal, left to right. */
  background: var(--c-card, #f5e8d1);
  clip-path: inset(0 calc((1 - min(1, var(--p, 1))) * 100%) 0 0);
}

.home-vitrine__title {
  margin-top: calc(var(--scale-px) * 16);
  margin-bottom: calc(var(--scale-px) * 40);
}

.home-vitrine__slider {
  overflow: hidden;
}

.vitrine-track {
  display: flex;
  gap: calc(var(--scale-px) * 24);
  padding-left: calc(var(--scale-px) * 60);
  padding-right: calc(var(--scale-px) * 60);
  width: max-content;
  will-change: transform;
}

.vitrine-card {
  display: block;
  /* 15% wider and, via the media aspect below, ~20% shorter so the whole card
     (down past the price and the metres line) fits inside the pinned viewport
     (Josué: the title and the bottom of the card were being cut off). */
  width: calc(var(--scale-px) * 437);
  text-decoration: none;
  overflow: hidden;
}

.vitrine-card__media {
  width: 100%;
  aspect-ratio: 5 / 4;
  object-fit: cover;
}

.vitrine-card__media--empty {
  background: var(--c-dark-alt, #1b4732);
  opacity: 0.25;
}

.vitrine-card__body {
  padding: calc(var(--scale-px) * 20) calc(var(--scale-px) * 24) calc(var(--scale-px) * 28);
}

.vitrine-card__type {
  opacity: 0.6;
}

.vitrine-card__name {
  color: inherit;
  margin-top: calc(var(--scale-px) * 10);
  line-height: 1.05;
}

.vitrine-card__price {
  margin-top: calc(var(--scale-px) * 14);
  font-size: calc(var(--scale-px) * 17);
}

.vitrine-card__meta {
  margin-top: calc(var(--scale-px) * 4);
  font-size: calc(var(--scale-px) * 14);
  opacity: 0.7;
}

.vitrine-progress {
  margin-top: calc(var(--scale-px) * 48);
}

.vitrine-progress span {
  display: block;
  height: 1px;
  background: var(--c-light, #e0d1b6);
  transform: scaleX(0);
  transform-origin: left;
}

/* Cream world change (springs scene 9): dark text on the cream tone. The
   cream fill lives on the PIN (.home-vitrine__pin), not the section: the
   section must stay transparent so the not-yet-wiped (right) side shows the
   still intro beneath, not a cream block. .display and .vitrine-progress
   hardcode the light color for the dark sections elsewhere, so both need an
   inherit override here. */
.home-vitrine--cream {
  color: var(--c-dark, #162d24);
}

.home-vitrine--cream .display {
  color: inherit;
}

.home-vitrine--cream .vitrine-progress span {
  background: var(--c-dark, #162d24);
}

/* Cards were card-light (cream) on a dark section; on the cream world give
   them a white lift so they still read as distinct objects. */
.home-vitrine--cream .vitrine-card {
  background: #fff;
}

.home-vitrine--cream .vitrine-card__media--empty {
  background: color-mix(in srgb, var(--c-dark, #162d24) 12%, transparent);
  opacity: 1;
}

/* Ambiance band: full-bleed photograph that breathes in on entry (springs
   scene 7) — a gentle inset from all four sides reading as a soft zoom-in
   rather than a screen-cut duplicate of the curtain chain. Rounded corners
   only show mid-breath (var(--p) < 1); resting state (--p: 1) is a flat
   full-bleed rectangle. */
/* Full-bleed always (no green frame): the sea photo pushes IN cinematically as
   the section scrolls (Josué), the water coming forward until it fills the
   screen. --p (view scrub) drives a monotonic zoom. */
.home-band {
  position: relative;
  height: 110svh;
  overflow: hidden;
  /* Deliberate green surround for the small-scale entrance frame. */
  background: var(--c-dark, #162d24);
}

.home-band__media,
.home-band__media img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.home-band__media img {
  object-fit: cover;
  /* Cinematic entrance: it starts SMALL and deep (scale 0.5, green showing
     around it, as if we are entering the scene from far), and the sea comes
     forward and floods the screen (grows to 1.35) as the section scrolls
     (Josué). --p is the view scrub. */
  transform: scale(calc(0.5 + var(--p, 1) * 0.85));
  transform-origin: 50% 50%;
}

/* Stronger scrim so the serif line never competes with the photo (Josué:
   photo, then gradient, then text). */
.home-band__wash {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(
    to top,
    rgba(8, 16, 13, 0.9) 0%,
    rgba(8, 16, 13, 0.5) 32%,
    rgba(8, 16, 13, 0.12) 62%,
    transparent 100%
  );
}

.home-band__copy {
  position: absolute;
  left: 0;
  right: 0;
  bottom: calc(var(--scale-px) * 80);
}

.home-band__copy h2 {
  max-width: 14em;
  margin-top: calc(var(--scale-px) * 20);
}

/* Asymmetric vertical cut (springs scenes 3/5): a framed dark text panel
   that does NOT span the full Y axis, beside a photo column that bleeds
   full height. Left and right move at slightly different parallax rates
   (data-speed 1.04 / 0.94 on the JSX wrappers) so the cut reads as two
   independent planes rather than one flat pin. */
.home-split {
  position: relative;
}

.home-split__pin {
  height: 100svh;
  overflow: hidden;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: calc(var(--scale-px) * 24);
}

/* The framed left panel: dark, centered in the pin, shorter than the full
   viewport so the cut reads as asymmetric rather than two equal halves. */
.home-split__text {
  height: 70svh;
  align-self: center;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding-left: calc(var(--scale-px) * 60);
  padding-right: calc(var(--scale-px) * 40);
  background: var(--c-dark-alt, #1b4732);
  border-radius: 2px;
}

.home-split__text .display--md {
  margin-top: calc(var(--scale-px) * 24);
  margin-bottom: calc(var(--scale-px) * 40);
}

/* The right column: full-height photo, bleeding to the section edge. */
.home-split__images {
  height: 100%;
}

/* Overscan absorbs the parallax travel: at speed 0.94 over the 300svh pin
   the column drifts up to ~18svh; without this the photo would detach from
   the pin edges and expose the body wash (the pin's overflow clips it). */
.home-split__cover {
  width: 100%;
  height: calc(100% + 26svh);
  margin-top: -18svh;
  object-fit: cover;
}

/* Team teaser */
.home-team {
  padding-top: calc(var(--scale-px) * 120);
  padding-bottom: calc(var(--scale-px) * 120);
}

.home-team__grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: calc(var(--scale-px) * 24);
  margin-top: calc(var(--scale-px) * 64);
  margin-bottom: calc(var(--scale-px) * 64);
}

.home-team__photo {
  width: 100%;
  aspect-ratio: 3 / 4;
  object-fit: cover;
  border-radius: 2px;
}

.home-team__photo--empty {
  display: grid;
  place-items: center;
  background: var(--c-dark-alt, #1b4732);
  font-family: var(--font-display, serif);
  font-size: calc(var(--scale-px) * 96);
  color: var(--c-light, #e0d1b6);
}

.home-team__name {
  margin-top: calc(var(--scale-px) * 20);
}

.home-team__role {
  margin-top: calc(var(--scale-px) * 6);
  opacity: 0.6;
}

/* Contact CTA */
.home-contact {
  padding-top: calc(var(--scale-px) * 140);
  padding-bottom: calc(var(--scale-px) * 140);
  position: relative;
  overflow: hidden;
}

.home-contact .display--md {
  margin-top: calc(var(--scale-px) * 24);
}

.home-contact__bg {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
}

.home-contact__bg img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0.38;
  transform: scale(calc(1.1 - var(--p, 1) * 0.1));
}

.home-contact__bg::after {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--wash-text);
}

.home-contact > .kicker,
.home-contact > .display,
.home-contact > a {
  position: relative;
  z-index: 1;
}

.home-contact__phone,
.home-contact__email {
  display: block;
  color: inherit;
  text-decoration: none;
  width: fit-content;
}

.home-contact__phone {
  margin-top: calc(var(--scale-px) * 48);
  font-family: var(--font-display, serif);
  font-size: calc(var(--scale-px) * 56);
  line-height: 1.1;
}

.home-contact__email {
  margin-top: calc(var(--scale-px) * 12);
  font-size: calc(var(--scale-px) * 18);
  opacity: 0.85;
}

/* Contact: two columns — the invitation on the left, the form in a glass pill
   on the right (same frosted language as the hero search card). */
.home-contact__grid {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: 1fr 1fr;
  align-items: center;
  gap: calc(var(--scale-px) * 64);
  margin-top: calc(var(--scale-px) * 40);
}
.home-contact__subtitle {
  max-width: 28em;
  margin-top: calc(var(--scale-px) * 20);
  font-size: calc(var(--scale-px) * 18);
  line-height: 1.5;
  opacity: 0.9;
}
.home-contact__direct {
  margin-top: calc(var(--scale-px) * 40);
  display: flex;
  flex-wrap: wrap;
  gap: calc(var(--scale-px) * 8) calc(var(--scale-px) * 28);
}
/* Compact, inline direct-contact links (override the old oversized display). */
.home-contact__direct .home-contact__phone,
.home-contact__direct .home-contact__email {
  margin-top: 0;
  font-family: var(--font-text, sans-serif);
  font-size: calc(var(--scale-px) * 16);
  line-height: 1.4;
  opacity: 0.85;
}

/* Glass pill holding the form. */
.home-contact__card {
  padding: calc(var(--scale-px) * 40);
  border-radius: 22px;
  color: var(--c-dark, #162d24);
  background: color-mix(in srgb, #ffffff 5%, transparent);
  border: 1px solid color-mix(in srgb, #ffffff 20%, transparent);
  box-shadow: 0 34px 80px -28px rgba(10, 20, 15, 0.55);
  backdrop-filter: blur(20px) saturate(1.15);
  -webkit-backdrop-filter: blur(20px) saturate(1.15);
}
.home-contact__form {
  display: grid;
  grid-template-columns: 1fr;
  gap: calc(var(--scale-px) * 18);
}
.home-contact__form label {
  display: flex;
  flex-direction: column;
  gap: calc(var(--scale-px) * 7);
  font-family: var(--font-text, sans-serif);
  font-size: calc(var(--scale-px) * 12);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: color-mix(in srgb, var(--c-dark, #162d24) 55%, transparent);
}
.home-contact__form input,
.home-contact__form textarea {
  width: 100%;
  padding: 0.6em 0.8em;
  background: color-mix(in srgb, #ffffff 30%, transparent);
  border: 1px solid color-mix(in srgb, var(--c-dark, #162d24) 22%, transparent);
  border-radius: 8px;
  color: var(--c-dark, #162d24);
  font-family: var(--font-text, sans-serif);
  font-size: calc(var(--scale-px) * 16);
  text-transform: none;
  letter-spacing: normal;
}
.home-contact__form input:focus,
.home-contact__form textarea:focus {
  outline: none;
  border-color: var(--c-dark, #162d24);
}
.home-contact__form textarea { resize: vertical; }
.home-contact__form .pill {
  justify-self: start;
  margin-top: calc(var(--scale-px) * 4);
  background: var(--c-dark, #162d24);
  color: var(--c-light, #e0d1b6);
  border-color: var(--c-dark, #162d24);
}
.home-contact__success {
  color: var(--c-dark, #162d24);
  font-family: var(--font-display, serif);
  font-size: calc(var(--scale-px) * 26);
  line-height: 1.25;
}
@media (max-width: 860px) {
  .home-contact__grid { grid-template-columns: 1fr; gap: calc(var(--scale-px) * 40); }
  .home-contact__card { padding: 24px; border-radius: 18px; }
}

/* Link from the quick contact to the detailed search form. */
.home-contact__more {
  position: relative;
  z-index: 1;
  margin-top: calc(var(--scale-px) * 24);
  font-size: calc(var(--scale-px) * 16);
  opacity: 0.9;
}
.home-contact__more a {
  color: var(--c-accent, #c9a45c);
  text-decoration: none;
  border-bottom: 1px solid color-mix(in srgb, var(--c-accent, #c9a45c) 50%, transparent);
  white-space: nowrap;
  transition: border-color var(--dur-micro) var(--ease);
}
.home-contact__more a:hover { border-color: var(--c-accent, #c9a45c); }

/* ---- Detailed search form page (/recherche): high-end reference styling ----
   Big serif display heading + editorial photo on the left, a light crème card of
   minimal underline fields on the right. */
.search-page {
  background: var(--c-dark, #162d24);
  color: var(--c-light, #e0d1b6);
  padding-top: calc(var(--scale-px) * 170);
  /* Content-driven height; padding-bottom is the section's breathing room (no
     100vh min, which could leave a purposeless void on tall screens). */
  padding-bottom: calc(var(--scale-px) * 96);
}
.search-page__grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: calc(var(--scale-px) * 72);
  align-items: stretch;
}
/* Left column is a flex stack so the photo grows to the card's bottom edge. */
.search-page__intro {
  display: flex;
  flex-direction: column;
}
.search-page__title {
  margin: calc(var(--scale-px) * 18) 0 0;
  max-width: 11em;
  font-family: var(--font-display, serif);
  font-weight: 300;
  text-transform: uppercase;
  letter-spacing: 0.015em;
  line-height: 1.03;
  font-size: clamp(34px, calc(var(--scale-px) * 74), 78px);
}
.search-page__subtitle {
  max-width: 30em;
  margin-top: calc(var(--scale-px) * 24);
  font-size: calc(var(--scale-px) * 18);
  line-height: 1.55;
  opacity: 0.9;
}
.search-page__photo {
  position: relative;
  margin-top: calc(var(--scale-px) * 48);
  border-radius: 90px 6px 6px 6px;
  overflow: hidden;
  /* Grow to the card's bottom edge. The image is taken out of flow (absolute)
     so its intrinsic height never inflates the left column — the card (its
     natural content height) always drives the row height, and the photo simply
     fills down to the same Y at every viewport width. */
  flex: 1;
  min-height: 0;
}
.search-page__photo img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Right card: light crème, big rounded top-left corner echoing the photo. */
.search-panel {
  color: var(--c-dark, #162d24);
  background: color-mix(in srgb, var(--c-card, #f5e8d1) 94%, transparent);
  border-radius: 80px 22px 22px 22px;
  padding: calc(var(--scale-px) * 56);
  box-shadow: 0 40px 90px -40px rgba(0, 0, 0, 0.55);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
}
.search-panel__success {
  margin: 0;
  font-family: var(--font-display, serif);
  font-size: calc(var(--scale-px) * 30);
  line-height: 1.25;
}
.search-form { display: grid; gap: calc(var(--scale-px) * 40); }
.search-group { display: grid; gap: calc(var(--scale-px) * 22); }
.search-group__label {
  margin: 0;
  font-family: var(--font-text, sans-serif);
  font-size: calc(var(--scale-px) * 12);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: color-mix(in srgb, var(--c-dark, #162d24) 55%, transparent);
}
.search-row { display: grid; grid-template-columns: 1fr 1fr; gap: calc(var(--scale-px) * 28); }

/* Minimal underline fields. */
.search-field {
  display: flex;
  align-items: center;
  gap: calc(var(--scale-px) * 10);
  border-bottom: 1px solid color-mix(in srgb, var(--c-dark, #162d24) 24%, transparent);
  padding-bottom: calc(var(--scale-px) * 10);
  transition: border-color var(--dur-micro) var(--ease);
}
.search-field:focus-within { border-bottom-color: var(--c-dark, #162d24); }
.search-field input,
.search-field select,
.search-field textarea {
  flex: 1;
  min-width: 0;
  border: 0;
  padding: 0;
  background: transparent;
  color: var(--c-dark, #162d24);
  font-family: var(--font-text, sans-serif);
  font-size: calc(var(--scale-px) * 17);
}
.search-field input:focus,
.search-field select:focus,
.search-field textarea:focus { outline: none; }
.search-field input::placeholder,
.search-field textarea::placeholder { color: color-mix(in srgb, var(--c-dark, #162d24) 42%, transparent); }
.search-field textarea { resize: vertical; }
.search-field__icon { flex: none; color: color-mix(in srgb, var(--c-dark, #162d24) 55%, transparent); }
.search-field__suffix {
  flex: none;
  font-size: calc(var(--scale-px) * 17);
  color: color-mix(in srgb, var(--c-dark, #162d24) 55%, transparent);
}
.search-field input[type="number"] { appearance: textfield; -moz-appearance: textfield; }
.search-field input[type="number"]::-webkit-inner-spin-button,
.search-field input[type="number"]::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }

/* Select with a drawn chevron. */
.search-field--select { position: relative; }
.search-field--select select { appearance: none; -webkit-appearance: none; cursor: pointer; }
.search-field--select::after {
  content: "";
  position: absolute;
  right: 2px;
  top: 42%;
  width: 8px;
  height: 8px;
  border-right: 1.5px solid color-mix(in srgb, var(--c-dark, #162d24) 55%, transparent);
  border-bottom: 1.5px solid color-mix(in srgb, var(--c-dark, #162d24) 55%, transparent);
  transform: translateY(-50%) rotate(45deg);
  pointer-events: none;
}

/* Rooms −/+ round steppers. */
.search-field--step { justify-content: space-between; }
.search-steppers { display: flex; gap: calc(var(--scale-px) * 8); flex: none; }
.search-step {
  width: 34px;
  height: 34px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  border: 1px solid color-mix(in srgb, var(--c-dark, #162d24) 30%, transparent);
  background: transparent;
  color: var(--c-dark, #162d24);
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  transition: background-color var(--dur-micro) var(--ease), color var(--dur-micro) var(--ease), border-color var(--dur-micro) var(--ease);
}
.search-step:hover { background: var(--c-dark, #162d24); color: var(--c-light, #e0d1b6); border-color: var(--c-dark, #162d24); }

.search-consent {
  display: flex;
  align-items: flex-start;
  gap: calc(var(--scale-px) * 12);
  font-size: calc(var(--scale-px) * 13);
  line-height: 1.5;
  color: color-mix(in srgb, var(--c-dark, #162d24) 70%, transparent);
}
.search-consent input { flex: none; margin-top: 0.2em; }

.search-submit {
  justify-self: start;
  display: inline-flex;
  align-items: center;
  gap: calc(var(--scale-px) * 8);
  height: calc(var(--scale-px) * 38);
  padding: 0 calc(var(--scale-px) * 24);
  border: 0;
  border-radius: 40px;
  background: var(--c-dark, #162d24);
  color: var(--c-light, #e0d1b6);
  font-family: var(--font-text, sans-serif);
  font-size: calc(var(--scale-px) * 12);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  cursor: pointer;
  transition: transform var(--dur-micro) var(--ease);
}
.search-submit svg { width: calc(var(--scale-px) * 15); height: calc(var(--scale-px) * 15); }
.search-submit:hover { transform: translateY(-2px); }
.search-submit svg { transition: transform var(--dur-micro) var(--ease); }
.search-submit:hover svg { transform: translateX(4px); }

@media (max-width: 900px) {
  .search-page__grid { grid-template-columns: 1fr; gap: calc(var(--scale-px) * 44); }
  .search-panel { padding: 30px 24px; border-radius: 44px 18px 18px 18px; }
  .search-row { grid-template-columns: 1fr; }
  .search-page__photo { flex: none; min-height: 0; aspect-ratio: 3 / 2; }
}

/* When motion.js does not run (touch, coarse pointer, reduced motion, no-js)
   the pins are static: collapse the multi-screen scroll ranges so the page
   reads with native scroll. !important beats the inline range heights. */
/* (not (pointer: fine)) mirrors the engine's own bail-out exactly (covers
   pointer: none devices); coarse stays for browsers without MQ4 `not`. */
@media (max-width: 768px), (pointer: coarse), (not (pointer: fine)), (prefers-reduced-motion: reduce) {
  /* Pure-CSS belt: motion.js also removes it, but the page must never stay
     covered if the script fails to run. */
  #preloader {
    display: none;
  }

  .hero {
    height: 100svh !important;
  }

  .home-split {
    height: auto !important;
  }

  /* No virtual slider in these modes: the track (width: max-content, no JS
     transform) flows with native horizontal scroll. */
  .home-vitrine__slider {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }

  /* Curtain chain degrades to plain stacked sections: no overlap, no clip. */
  .curtain--over {
    margin-top: 0 !important;
    clip-path: none !important;
    background: none !important;
    scroll-margin-top: 0 !important;
  }

  .curtain--over::before {
    display: none !important;
  }

  .curtain--under {
    z-index: auto !important;
  }

  /* Pinned wipe structure degrades to plain stacked sections: no pin runway,
     no held viewport, no horizontal clip. */
  .curtain--wipe {
    margin-top: 0 !important;
  }

  .home-intro__range,
  .home-stat__range,
  .home-vitrine__range {
    height: auto !important;
  }

  .home-intro__pin,
  .home-stat__pin,
  .home-vitrine__pin {
    height: auto !important;
    overflow: visible !important;
    clip-path: none !important;
    padding-top: calc(var(--scale-px) * 100);
    padding-bottom: calc(var(--scale-px) * 100);
  }

  /* Glass bar stacks: green panel over the photo, no blur (no reel behind). */
  .home-intro__pin {
    grid-template-columns: 1fr !important;
    padding: 0 !important;
  }

  .home-intro__glass {
    backdrop-filter: none !important;
    -webkit-backdrop-filter: none !important;
    padding: calc(var(--scale-px) * 100) 20px !important;
  }

  .home-intro__photo {
    height: 60svh;
  }
}

html.no-js .hero {
  height: 100svh !important;
}

html.no-js .curtain--wipe {
  margin-top: 0 !important;
}

html.no-js .home-intro__range,
html.no-js .home-stat__range,
html.no-js .home-vitrine__range {
  height: auto !important;
}

html.no-js .home-intro__pin,
html.no-js .home-stat__pin,
html.no-js .home-vitrine__pin {
  height: auto !important;
  overflow: visible !important;
  clip-path: none !important;
  padding-top: calc(var(--scale-px) * 100);
  padding-bottom: calc(var(--scale-px) * 100);
}

html.no-js .home-intro__pin {
  grid-template-columns: 1fr !important;
  padding: 0 !important;
}

html.no-js .home-intro__glass {
  backdrop-filter: none !important;
  -webkit-backdrop-filter: none !important;
  padding: calc(var(--scale-px) * 100) 20px !important;
}

html.no-js .home-intro__photo {
  height: 60svh;
}

html.no-js .home-split {
  height: auto !important;
}

html.no-js .curtain--over {
  margin-top: 0 !important;
  clip-path: none !important;
  background: none !important;
  scroll-margin-top: 0 !important;
}

html.no-js .curtain--over::before {
  display: none !important;
}

html.no-js .curtain--under {
  z-index: auto !important;
}

html.no-js .home-vitrine__slider {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

@media (max-width: 768px) {
  /* Static fallback (no JS ticker at this width): fewer, wider tiles so the
     rotated composition still reads instead of a dense unreadable grid. */
  .hero__reel-row {
    height: 30vh;
  }

  .hero__tile {
    width: 55vw;
  }

  /* Keep the first 3 tiles of each row visible; the rest would overflow
     off-screen anyway at this tile width and just add DOM weight to paint. */
  .hero__tile:nth-child(n + 4) {
    display: none;
  }

  /* Static pitch matching the 55vw tiles: the inline left offsets assume
     24vw tiles and would overlap here. !important beats the inline style. */
  .hero__tile:nth-child(1) {
    left: 0 !important;
  }

  .hero__tile:nth-child(2) {
    left: 58vw !important;
  }

  .hero__tile:nth-child(3) {
    left: 116vw !important;
  }

  .hero__title {
    font-size: calc(var(--scale-px) * 120);
    right: 20px;
    bottom: 88px;
  }

  .hero__subtitle {
    left: 20px;
    right: 20px;
  }

  .hero__arrow {
    left: 20px;
    bottom: 20px;
  }

  .home-intro__title {
    font-size: calc(var(--scale-px) * 64);
  }

  .home-vitrine__slider {
    overflow-x: auto;
  }

  .vitrine-track {
    padding-left: 20px;
    padding-right: 20px;
  }

  .vitrine-card {
    width: 78vw;
  }

  .home-split__pin {
    height: auto;
    grid-template-columns: 1fr;
    gap: 48px;
  }

  /* The desktop asymmetric framing (fixed 70svh, dark panel) does not
     translate to a stacked mobile layout: collapse to a plain flow block. */
  .home-split__text {
    height: auto;
    padding: 48px 20px;
  }

  .home-split__images {
    height: 60vh;
  }

  .home-team__grid {
    grid-template-columns: 1fr;
  }
}

/* ---- Catalog ---- */
.catalog {
  /* Clear the fixed nav; no hero on this page. */
  padding-top: calc(var(--scale-px) * 160);
  padding-bottom: calc(var(--scale-px) * 120);
}

.catalog-header {
  margin-bottom: calc(var(--scale-px) * 64);
}

.catalog-header__title {
  font-size: calc(var(--scale-px) * 96);
  margin-top: calc(var(--scale-px) * 12);
}

.catalog-layout {
  display: grid;
  grid-template-columns: calc(var(--scale-px) * 300) 1fr;
  gap: calc(var(--scale-px) * 64);
  align-items: start;
}

/* Sidebar is a plain column in v1 — native sticky is unreliable under the
   virtual-scroll transform, so no position: sticky here. */
.catalog-sidebar {
  display: flex;
  flex-direction: column;
  gap: calc(var(--scale-px) * 40);
}

.filter-group__title {
  margin-bottom: calc(var(--scale-px) * 14);
  opacity: 0.55;
}

.filter-pills {
  display: flex;
  flex-wrap: wrap;
  gap: calc(var(--scale-px) * 8);
}

.filter-pills .pill,
.catalog-sidebar .pill {
  text-decoration: none;
}

.filter-price {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: calc(var(--scale-px) * 12);
}

.filter-price__field {
  display: flex;
  flex-direction: column;
  gap: calc(var(--scale-px) * 6);
  width: 100%;
  font-family: var(--font-text, sans-serif);
  font-size: calc(var(--scale-px) * 13);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  opacity: 0.85;
}

.filter-price input[type="number"],
.filter-sort select {
  width: 100%;
  padding: 0.55em 0.9em;
  background: transparent;
  border: 1px solid color-mix(in srgb, var(--c-light, #e0d1b6) 30%, transparent);
  border-radius: 2px;
  color: var(--c-light, #e0d1b6);
  font-family: var(--font-text, sans-serif);
  font-size: calc(var(--scale-px) * 15);
}

.filter-price input[type="number"]:focus,
.filter-sort select:focus {
  outline: none;
  border-color: var(--c-light, #e0d1b6);
}

.filter-sort select option {
  color: var(--c-dark, #162d24);
}

.catalog-clear {
  color: inherit;
  font-family: var(--font-text, sans-serif);
  font-size: calc(var(--scale-px) * 14);
  text-decoration: underline;
  text-underline-offset: 0.25em;
  opacity: 0.7;
}

.catalog-count {
  margin-bottom: calc(var(--scale-px) * 24);
  opacity: 0.55;
}

.catalog-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: calc(var(--scale-px) * 32);
}

.catalog-card {
  display: block;
  text-decoration: none;
  overflow: hidden;
}

.catalog-empty {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: calc(var(--scale-px) * 24);
  padding: calc(var(--scale-px) * 48) 0;
  font-size: calc(var(--scale-px) * 18);
}

.catalog-empty .pill {
  text-decoration: none;
}

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

@media (max-width: 768px) {
  .catalog {
    padding-top: 120px;
    padding-bottom: 72px;
  }

  .catalog-header {
    margin-bottom: 40px;
  }

  .catalog-header__title {
    font-size: calc(var(--scale-px) * 88);
  }

  .catalog-layout {
    grid-template-columns: 1fr;
    gap: 40px;
  }

  /* Sidebar collapses above the grid; pill rows scroll horizontally. */
  .catalog-sidebar {
    gap: 24px;
  }

  .filter-pills {
    flex-wrap: nowrap;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    padding-bottom: 4px;
  }

  .filter-pills .pill {
    flex: 0 0 auto;
    white-space: nowrap;
  }

  .catalog-grid {
    grid-template-columns: 1fr;
    gap: 24px;
  }
}

/* ---- Property detail ---- */
.property-cover {
  position: relative;
  min-height: 100svh;
  display: flex;
  align-items: flex-end;
  overflow: hidden;
}

/* In the /pro preview windows (?embed=1 sets html.is-embed) the iframe is a
   STILL crop, never scrolled. A full-height cover would show only its sky at the
   top; shrink it so the title block ("À VENDRE" + title + price) sits above the
   window fold. Only affects the embedded preview, never the real fiche. */
html.is-embed .property-cover {
  min-height: 60svh;
}

.property-cover__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Gradient veil so kicker/title/price stay readable over any photo.
   pointer-events: none so a click on the hero reaches the [data-lb] image
   underneath and opens the lightbox. */
.property-cover__veil {
  position: absolute;
  inset: 0;
  pointer-events: none;
  /* +15% solidity vs. the previous veil so the title/price separate cleanly
     from a busy photo (Josué): 82->97 at the bottom, 35->50 at mid. */
  background: linear-gradient(
    to top,
    color-mix(in srgb, var(--c-dark, #162d24) 97%, transparent) 0%,
    color-mix(in srgb, var(--c-dark, #162d24) 50%, transparent) 45%,
    transparent 100%
  );
}

.property-cover__text {
  position: relative;
  width: 100%;
  padding-bottom: calc(var(--scale-px) * 80);
}

.property-cover__title {
  max-width: 16ch;
  margin-top: calc(var(--scale-px) * 16);
}

/* Editorial cover accroche: sober italic serif line between title and price. */
.property-cover__hook {
  max-width: 34ch;
  margin-top: calc(var(--scale-px) * 18);
  font-family: var(--font-display, serif);
  font-style: italic;
  font-size: calc(var(--scale-px) * 24);
  font-weight: 350;
  line-height: 1.35;
  opacity: 0.92;
}

.property-cover__price {
  font-family: var(--font-display, serif);
  font-size: calc(var(--scale-px) * 40);
  font-weight: 350;
  margin-top: calc(var(--scale-px) * 24);
}

/* ---- Editorial body (AD-style magazine layout, Josué): a light canvas so
   the photography is the protagonist. Full-bleed single plates alternate with
   50/50 pairs, each captioned by an atout, with a serif lead column and a pull
   quote. ---- */
.property-meta {
  background: var(--c-card, #f5e8d1);
  color: var(--c-dark, #162d24);
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: baseline;
  gap: calc(var(--scale-px) * 16);
  padding: calc(var(--scale-px) * 64) calc(var(--scale-px) * 60);
  border-bottom: 1px solid color-mix(in srgb, var(--c-dark, #162d24) 12%, transparent);
}

.property-meta__dot {
  opacity: 0.4;
}

.property-editorial {
  background: var(--c-card, #f5e8d1);
  color: var(--c-dark, #162d24);
  padding-bottom: calc(var(--scale-px) * 40);
}

/* Serif lead column, narrow and centred, larger opening line. */
.property-lead-copy {
  max-width: calc(var(--scale-px) * 680);
  margin: 0 auto;
  padding: calc(var(--scale-px) * 120) calc(var(--scale-px) * 24) calc(var(--scale-px) * 20);
}

.property-lead-copy .lead {
  font-family: var(--font-display, serif);
  font-size: calc(var(--scale-px) * 30);
  line-height: 1.4;
}

.property-lead-copy p {
  font-size: calc(var(--scale-px) * 19);
  line-height: 1.7;
}

.property-lead-copy p + p {
  margin-top: calc(var(--scale-px) * 22);
}

/* Plates: generous vertical rhythm; singles are full-bleed, pairs split 50/50. */
.plate-full,
.plate-pair {
  margin: calc(var(--scale-px) * 72) 0;
}

.plate-pair {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: calc(var(--scale-px) * 8);
}

.plate {
  margin: 0;
}

.plate img {
  width: 100%;
  display: block;
  object-fit: cover;
}

.plate-full .plate img {
  aspect-ratio: 3 / 2;
}

.plate-pair .plate img {
  aspect-ratio: 4 / 5;
}

.plate__caption {
  margin-top: calc(var(--scale-px) * 12);
  padding: 0 calc(var(--scale-px) * 60);
  font-size: calc(var(--scale-px) * 13);
  line-height: 1.5;
  opacity: 0.66;
}

.plate-pair .plate__caption {
  padding: 0 calc(var(--scale-px) * 8);
}

/* Pull quote drawn from an atout. */
.property-quote {
  max-width: calc(var(--scale-px) * 880);
  margin: calc(var(--scale-px) * 120) auto;
  padding: 0 calc(var(--scale-px) * 40);
  font-family: var(--font-display, serif);
  font-size: calc(var(--scale-px) * 42);
  font-weight: 350;
  line-height: 1.2;
  text-align: center;
}

.property-legal {
  /* Stays on the light editorial canvas, small print before the dark CTA. */
  background: var(--c-card, #f5e8d1);
  color: var(--c-dark, #162d24);
  padding-top: calc(var(--scale-px) * 40);
  padding-bottom: calc(var(--scale-px) * 100);
}

.property-legal__energy {
  font-family: var(--font-text, sans-serif);
  font-size: calc(var(--scale-px) * 16);
  letter-spacing: 0.04em;
}

.property-legal__risks {
  max-width: 70ch;
  margin-top: calc(var(--scale-px) * 20);
  font-size: calc(var(--scale-px) * 14);
  line-height: 1.6;
  opacity: 0.65;
}

.property-legal__risks a {
  color: inherit;
  text-underline-offset: 0.25em;
}

.property-lead {
  padding-top: calc(var(--scale-px) * 120);
  padding-bottom: calc(var(--scale-px) * 120);
}

.property-lead__title {
  margin-top: calc(var(--scale-px) * 12);
  max-width: 14ch;
}

.property-lead__success {
  margin-top: calc(var(--scale-px) * 40);
  font-size: calc(var(--scale-px) * 22);
}

.property-lead__form {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: calc(var(--scale-px) * 28) calc(var(--scale-px) * 32);
  max-width: calc(var(--scale-px) * 760);
  margin-top: calc(var(--scale-px) * 56);
}

.property-lead__form label {
  display: flex;
  flex-direction: column;
  gap: calc(var(--scale-px) * 8);
  font-family: var(--font-text, sans-serif);
  font-size: calc(var(--scale-px) * 13);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  opacity: 0.9;
}

.property-lead__form input,
.property-lead__form select,
.property-lead__form textarea {
  width: 100%;
  padding: 0.6em 0.9em;
  background: transparent;
  border: 1px solid color-mix(in srgb, var(--c-light, #e0d1b6) 30%, transparent);
  border-radius: 2px;
  color: var(--c-light, #e0d1b6);
  font-family: var(--font-text, sans-serif);
  font-size: calc(var(--scale-px) * 16);
  text-transform: none;
  letter-spacing: normal;
}

.property-lead__form input:focus,
.property-lead__form select:focus,
.property-lead__form textarea:focus {
  outline: none;
  border-color: var(--c-light, #e0d1b6);
}

.property-lead__form select option {
  color: var(--c-dark, #162d24);
}

.property-lead__form textarea {
  resize: vertical;
}

.property-lead__message {
  grid-column: 1 / -1;
}

.property-lead__form .pill {
  justify-self: start;
  grid-column: 1 / -1;
}

@media (max-width: 768px) {
  .property-cover__text {
    padding-bottom: 48px;
  }

  .property-cover__title {
    max-width: none;
  }

  .property-meta {
    padding-top: 32px;
    padding-bottom: 32px;
    gap: 10px;
  }

  .property-lead-copy {
    padding-top: 72px;
  }

  /* Pairs stack to single column on mobile so the photos stay large. */
  .plate-pair {
    grid-template-columns: 1fr;
    gap: 32px;
  }

  .plate-full,
  .plate-pair {
    margin: 40px 0;
  }

  .plate__caption,
  .plate-pair .plate__caption {
    padding: 0 20px;
  }

  .property-quote {
    font-size: calc(var(--scale-px) * 30);
    margin: 72px auto;
  }

  .property-legal {
    padding-bottom: 72px;
  }

  .property-lead {
    padding-top: 72px;
    padding-bottom: 72px;
  }

  .property-lead__form {
    grid-template-columns: 1fr;
    gap: 20px;
  }

  .more-card {
    width: 78vw !important;
  }
}

/* ---- Closing carousel: other properties (AD "Read more") ---- */
.property-more {
  background: var(--c-card, #f5e8d1);
  color: var(--c-dark, #162d24);
  padding: calc(var(--scale-px) * 120) 0;
  border-top: 1px solid color-mix(in srgb, var(--c-dark, #162d24) 12%, transparent);
}

.property-more__head {
  margin-bottom: calc(var(--scale-px) * 48);
}

.property-more .display {
  color: inherit;
  margin-top: calc(var(--scale-px) * 12);
}

.property-more__row {
  overflow: hidden;
}

.property-more__track {
  display: flex;
  gap: calc(var(--scale-px) * 24);
  padding: 0 calc(var(--scale-px) * 60);
  width: max-content;
  will-change: transform;
}

.more-card {
  display: block;
  width: calc(var(--scale-px) * 400);
  text-decoration: none;
  color: inherit;
}

.more-card__media {
  width: 100%;
  aspect-ratio: 3 / 2;
  object-fit: cover;
}

.more-card__media--empty {
  background: color-mix(in srgb, var(--c-dark, #162d24) 12%, transparent);
}

.more-card__type {
  display: block;
  margin-top: calc(var(--scale-px) * 16);
  opacity: 0.6;
}

.more-card__name {
  margin-top: calc(var(--scale-px) * 8);
  color: inherit;
  line-height: 1.05;
}

.more-card__price {
  margin-top: calc(var(--scale-px) * 10);
  font-size: calc(var(--scale-px) * 17);
}

/* No virtual drag off the engine: the track flows with native scroll. */
@media (max-width: 768px), (pointer: coarse), (not (pointer: fine)), (prefers-reduced-motion: reduce) {
  .property-more__row {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }
}

html.no-js .property-more__row {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

/* ============================================================
   Tier 1 detail additions — all in the editorial idiom: cream
   canvas / dark CTA, Fraunces + Hanken, hairline separators,
   no boxes or shadows. See docs and the Tier 1 spec.
   ============================================================ */

/* A · reference chip in the meta band */
.property-meta__ref {
  opacity: 0.5;
}

/* D + E · ficha technique: typographic columns of terme : valeur on cream */
.property-spec {
  background: var(--c-card, #f5e8d1);
  color: var(--c-dark, #162d24);
  padding-top: calc(var(--scale-px) * 100);
  padding-bottom: calc(var(--scale-px) * 40);
  border-top: 1px solid color-mix(in srgb, var(--c-dark, #162d24) 12%, transparent);
}

.property-spec__grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: calc(var(--scale-px) * 56);
  margin-top: calc(var(--scale-px) * 40);
}

.property-spec__group-title {
  padding-bottom: calc(var(--scale-px) * 14);
  margin-bottom: calc(var(--scale-px) * 6);
  border-bottom: 1px solid color-mix(in srgb, var(--c-dark, #162d24) 22%, transparent);
  opacity: 1;
}

.property-spec__row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: calc(var(--scale-px) * 20);
  padding: calc(var(--scale-px) * 14) 0;
  border-bottom: 1px solid color-mix(in srgb, var(--c-dark, #162d24) 12%, transparent);
}

.property-spec__row dt {
  font-family: var(--font-text, sans-serif);
  font-size: calc(var(--scale-px) * 14);
  letter-spacing: 0.02em;
  opacity: 0.6;
  flex: 0 0 auto;
}

.property-spec__row dd {
  font-family: var(--font-text, sans-serif);
  font-size: calc(var(--scale-px) * 16);
  text-align: right;
  line-height: 1.4;
}

/* F · consultant card in the dark CTA — photo + text, no box */
.property-consultant {
  display: flex;
  align-items: center;
  gap: calc(var(--scale-px) * 24);
  margin-top: calc(var(--scale-px) * 48);
}

.property-consultant__photo {
  width: calc(var(--scale-px) * 88);
  height: calc(var(--scale-px) * 110);
  object-fit: cover;
  border-radius: 2px;
  flex: 0 0 auto;
}

.property-consultant__name {
  color: var(--c-light, #e0d1b6);
  margin-top: calc(var(--scale-px) * 6);
}

.property-consultant__phone {
  display: inline-block;
  margin-top: calc(var(--scale-px) * 8);
  color: var(--c-light, #e0d1b6);
  font-family: var(--font-text, sans-serif);
  font-size: calc(var(--scale-px) * 17);
  letter-spacing: 0.02em;
  text-underline-offset: 0.25em;
}

/* B · contact intents — pills wrapping a hidden radio; :has drives the active
   state with no JS, site.js additionally swaps the message + button label */
.property-lead__intents {
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  gap: calc(var(--scale-px) * 12);
  margin-bottom: calc(var(--scale-px) * 8);
}

.property-lead__intent {
  position: relative;
  display: inline-flex;
  align-items: center;
  color: var(--c-light, #e0d1b6);
}

.property-lead__intent input {
  position: absolute;
  opacity: 0;
  width: 1px;
  height: 1px;
  pointer-events: none;
}

.property-lead__intent.is-active,
.property-lead__intent:has(input:checked) {
  background: var(--c-light, #e0d1b6);
  color: var(--c-dark, #162d24);
  border-color: var(--c-light, #e0d1b6);
}

.property-lead__intent:has(input:focus-visible) {
  outline: 2px solid var(--c-light, #e0d1b6);
  outline-offset: 2px;
}

/* C · fixed mobile contact dock (mobile only; shown in the media query below) */
.property-dock {
  display: none;
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 40;
  gap: calc(var(--scale-px) * 10);
  padding: calc(var(--scale-px) * 12) calc(var(--scale-px) * 16);
  padding-bottom: calc(var(--scale-px) * 12 + env(safe-area-inset-bottom, 0px));
  background: color-mix(in srgb, var(--c-dark, #162d24) 82%, transparent);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  border-top: 1px solid color-mix(in srgb, var(--c-light, #e0d1b6) 22%, transparent);
}

.property-dock__btn {
  flex: 1;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid color-mix(in srgb, var(--c-light, #e0d1b6) 45%, transparent);
  border-radius: 999px;
  color: var(--c-light, #e0d1b6);
  font-family: var(--font-text, sans-serif);
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  text-decoration: none;
}

.property-dock__btn--accent {
  background: var(--c-light, #e0d1b6);
  color: var(--c-dark, #162d24);
  border-color: var(--c-light, #e0d1b6);
}

/* G · lightbox — built by site.js, near-black full-screen, image contained */
[data-lb] {
  cursor: zoom-in;
}

.lb {
  position: fixed;
  inset: 0;
  z-index: 65;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(10, 16, 13, 0.95);
  opacity: 0;
  transition: opacity var(--dur-micro, 0.4s) var(--ease);
}

.lb.is-open {
  opacity: 1;
}

.lb__img {
  max-width: 92vw;
  max-height: 86vh;
  object-fit: contain;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.4);
}

.lb__counter {
  position: absolute;
  top: calc(var(--scale-px) * 28);
  left: 50%;
  transform: translateX(-50%);
  color: var(--c-light, #e0d1b6);
  font-family: var(--font-text, sans-serif);
  font-size: 13px;
  letter-spacing: 0.12em;
  opacity: 0.8;
}

.lb__btn {
  position: absolute;
  min-width: 44px;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: none;
  color: var(--c-light, #e0d1b6);
  font-size: 28px;
  line-height: 1;
  cursor: pointer;
  opacity: 0.85;
  transition: opacity var(--dur-micro, 0.4s) var(--ease);
}

.lb__btn:hover {
  opacity: 1;
}

.lb__close {
  top: calc(var(--scale-px) * 20);
  right: calc(var(--scale-px) * 24);
}

.lb__prev {
  left: calc(var(--scale-px) * 16);
  top: 50%;
  transform: translateY(-50%);
  font-size: 40px;
}

.lb__next {
  right: calc(var(--scale-px) * 16);
  top: 50%;
  transform: translateY(-50%);
  font-size: 40px;
}

@media (max-width: 768px) {
  .property-spec__grid {
    grid-template-columns: 1fr;
    gap: 40px;
  }

  .property-consultant {
    margin-top: 32px;
    gap: 16px;
  }

  .property-consultant__photo {
    width: 72px;
    height: 90px;
  }

  /* Show the dock and keep the closing carousel clear of it. */
  .property-dock {
    display: flex;
  }

  .property-more {
    padding-bottom: calc(var(--scale-px) * 120 + 76px);
  }

  .lb__prev {
    left: 4px;
  }

  .lb__next {
    right: 4px;
  }
}

/* ---- Team ---- */
.team {
  /* Clear the fixed nav; no hero on this page. */
  padding-top: calc(var(--scale-px) * 160);
  padding-bottom: calc(var(--scale-px) * 120);
}

.team-header {
  margin-bottom: calc(var(--scale-px) * 72);
}

.team-header__title {
  font-size: calc(var(--scale-px) * 96);
  margin-top: calc(var(--scale-px) * 12);
}

.team-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: calc(var(--scale-px) * 48) calc(var(--scale-px) * 32);
}

.team-card__photo {
  width: 100%;
  aspect-ratio: 3 / 4;
  object-fit: cover;
  border-radius: 2px;
}

.team-card__photo--empty {
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--c-dark-alt, #1b4732);
  font-family: var(--font-display, serif);
  font-size: calc(var(--scale-px) * 96);
  font-weight: 350;
  color: color-mix(in srgb, var(--c-light, #e0d1b6) 55%, transparent);
}

.team-card__name {
  margin-top: calc(var(--scale-px) * 24);
}

.team-card__role {
  margin-top: calc(var(--scale-px) * 8);
  opacity: 0.6;
}

.team-card__contact {
  display: block;
  margin-top: calc(var(--scale-px) * 10);
  color: inherit;
  font-size: calc(var(--scale-px) * 15);
  text-decoration: none;
  opacity: 0.85;
}

.team-card__contact:hover {
  text-decoration: underline;
  text-underline-offset: 0.25em;
}

.team-empty {
  font-size: calc(var(--scale-px) * 20);
  opacity: 0.8;
}

@media (max-width: 768px) {
  .team {
    padding-top: 120px;
    padding-bottom: 72px;
  }

  .team-header {
    margin-bottom: 40px;
  }

  .team-header__title {
    font-size: calc(var(--scale-px) * 88);
  }

  .team-grid {
    grid-template-columns: 1fr;
    gap: 40px;
  }
}

/* Sales-only return-to-/pro pill (see site.tsx ProPill). Bottom-right, glass
   treatment matching .site-nav::before. Collapsed to the monogram; the label
   expands on hover/focus. Hidden on mobile (the property page already has a
   fixed bottom dock there) and inside /pro's embedded iframe previews. */
.pro-pill {
  position: fixed;
  right: 20px;
  bottom: 20px;
  z-index: 45;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 10px 14px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--c-dark, #162d24) 60%, transparent);
  -webkit-backdrop-filter: blur(16px) saturate(1.3);
  backdrop-filter: blur(16px) saturate(1.3);
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--c-light, #e0d1b6) 22%, transparent);
  color: var(--c-light, #e0d1b6);
  text-decoration: none;
  overflow: hidden;
}

.pro-pill__mark {
  display: inline-block;
  flex: none;
  width: 18px;
  height: 18px;
  background-color: currentColor;
  -webkit-mask: url(/monkeyweaver-wordmark.svg) center / contain no-repeat;
  mask: url(/monkeyweaver-wordmark.svg) center / contain no-repeat;
}

.pro-pill__text {
  font-family: var(--font-text, sans-serif);
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  white-space: nowrap;
  max-width: 0;
  opacity: 0;
  transition: max-width var(--dur-micro) var(--ease), opacity var(--dur-micro) var(--ease);
}

.pro-pill:hover .pro-pill__text,
.pro-pill:focus-visible .pro-pill__text {
  max-width: 220px;
  opacity: 1;
}

@media (max-width: 768px) {
  .pro-pill {
    display: none;
  }
}

.is-embed .pro-pill {
  display: none;
}

/* Sales-only reinforcement line at the close of a property page (see
   property.tsx OtherProperties). Reads as one more editorial caption, not a
   banner — same restrained tone as the rest of the fiche's chrome. */
.property-more__demo-note {
  margin-top: calc(var(--scale-px) * 24);
  text-align: center;
}

.property-more__demo-note a {
  font-family: var(--font-text, sans-serif);
  font-size: calc(var(--scale-px) * 13);
  letter-spacing: 0.04em;
  color: var(--c-dark, #162d24);
  opacity: 0.6;
  text-decoration: none;
  transition: opacity var(--dur-micro) var(--ease);
}

.property-more__demo-note a:hover,
.property-more__demo-note a:focus-visible {
  opacity: 1;
}
