/* ==========================================================================
   ENDEVELOPMENT · one-page site
   --------------------------------------------------------------------------
   Colours: sampled from the swatches of the charte graphique (p. 36). The HEX
   printed under all five swatches (#2E5895, a blue) matches none of them and is
   a layout error in the PDF, so the visible swatch colour is the reference.
   Type: Old Standard TT (logo-style display, p. 40), Inter (web titles, p. 41),
   Montserrat (texts, p. 42–44).

   Progressive enhancement: every rule outside `.is-*` states describes the
   static page (no JavaScript, or prefers-reduced-motion). main.js adds the
   `.is-*` classes that turn sections into pinned, scroll-driven scenes, so any
   element hidden for an animation is hidden by script, never by CSS alone.
   ========================================================================== */

/* ---------- 1. Tokens ---------- */
:root {
  --blanc: #FFFFFF;
  --gris-clair: #D4D4D4;
  --gris-cendre: #4F4F4F;
  --anthracite: #323331;
  --graphite: #2C2E35;

  /* Tints from the "Dégradés de couleurs" page (100/80/60/40/20 %) */
  --gris-clair-40: #EEEEEE;
  --gris-clair-20: #F6F6F6;

  /* The only colour the charte actually names (p. 36). It is kept for one job:
     the accent that answers a focus or a hover on an interactive element. */
  --bleu: #2E5895;
  /* A warm off-white, the single non-neutral tint in the type: it marks the
     card a cursor is on in "Savoir-faire", nothing else. */
  --creme: #E8E0D2;

  /* Glass, one recipe. The navigation capsule, the nuit/jour switch, the plan
     buttons and the social buttons of the contact page all read these, so they
     cannot drift apart; the "on-light" set is the same glass, inverted. */
  --glass-blur: blur(20px) saturate(1.25);
  --glass-on-dark: rgba(255, 255, 255, .12);
  --glass-on-dark-line: rgba(255, 255, 255, .17);
  --glass-on-dark-hi: rgba(255, 255, 255, .22);
  --glass-on-light: rgba(44, 46, 53, .05);
  --glass-on-light-line: rgba(44, 46, 53, .13);
  --glass-on-light-hi: rgba(44, 46, 53, .1);
  /* Pop-overs float over photographs with no scrim of their own, so they take
     a denser version of the same glass. */
  --glass-panel-on-dark: rgba(26, 27, 32, .66);
  --glass-panel-on-light: rgba(255, 255, 255, .8);

  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-strong: cubic-bezier(0.23, 1, 0.32, 1);
  --ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);

  --font-display: "Old Standard TT", "Times New Roman", Times, serif;
  --font-ui: "Inter", "Helvetica Neue", Arial, sans-serif;
  --font-body: "Montserrat", "Helvetica Neue", Arial, sans-serif;

  --gutter: clamp(16px, 4.2vw, 72px);
  --maxw: 1440px;
  --header-h: 88px;

  /* z-index scale */
  --z-scene: 1;
  --z-header: 40;
  --z-grain: 60;
  --z-cursor: 70;
}

/* ---------- 2. Base ---------- */
*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  background: var(--graphite);
}
html.lenis, html.lenis body { height: auto; }
.lenis:not(.lenis-autoToggle).lenis-stopped { overflow: clip; }
/* Touch screens run without Lenis (main.js), so an open dialog holds the page still by itself. */
html:has(dialog[open]) { overflow: clip; }
.lenis [data-lenis-prevent], .lenis [data-lenis-prevent-horizontal] { overscroll-behavior: contain; }

body {
  margin: 0;
  background: var(--graphite);
  color: var(--blanc);
  font-family: var(--font-body);
  font-weight: 400;
  font-size: 1rem;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-kerning: normal;
}

main { display: block; overflow: clip; }
img, video, canvas, svg { display: block; max-width: 100%; }
img { height: auto; }
h1, h2, h3, p, figure, blockquote, dl, dd { margin: 0; }
ul, ol { margin: 0; padding: 0; list-style: none; }
a { color: inherit; }
button { font: inherit; color: inherit; }
address { font-style: normal; }
h1, h2, h3 { text-wrap: balance; }
p { text-wrap: pretty; }

::selection { background: var(--anthracite); color: var(--blanc); }

:focus-visible {
  outline: 1px solid currentColor;
  outline-offset: 4px;
}

.skip {
  position: absolute;
  left: var(--gutter);
  top: 12px;
  z-index: calc(var(--z-cursor) + 1);
  padding: 12px 18px;
  background: var(--blanc);
  color: var(--anthracite);
  font: 600 12px/1 var(--font-ui);
  letter-spacing: .16em;
  text-transform: uppercase;
  text-decoration: none;
}
/* visible only while focused from the keyboard */
.skip:not(:focus) {
  width: 1px;
  height: 1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.skip:focus-visible { outline-color: var(--anthracite); }
.skip--film { position: absolute; top: calc(var(--header-h) + 12px); }

.vh {
  position: absolute !important;
  width: 1px; height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ---------- 3. Section heading (the charte's "LOGOTYPE ——— Variations" bar) ---------- */
.shead {
  display: flex;
  align-items: center;
  gap: clamp(14px, 2vw, 32px);
  max-width: var(--maxw);
  margin-inline: auto;
}
.shead__title {
  font: 800 clamp(1.125rem, 1.9vw, 1.75rem)/1 var(--font-ui);
  letter-spacing: .16em;
  text-transform: uppercase;
}
.shead__rule {
  flex: 1 1 24px;
  height: 1px;
  background: currentColor;
  opacity: .42;
  transform-origin: left center;
}
.shead__label {
  font: 300 clamp(.95rem, 1.25vw, 1.25rem)/1.2 var(--font-body);
  white-space: nowrap;
}
.shead__link { text-decoration: none; border-bottom: 1px solid currentColor; padding-bottom: 2px; transition: opacity 300ms var(--ease-out); }
@media (hover: hover) and (pointer: fine) {
  .shead__link:hover { opacity: .64; }
}

/* ---------- 4. Header ---------- */
.site-header {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: var(--z-header);
  height: var(--header-h);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 0 var(--gutter);
  color: var(--blanc);
  pointer-events: none;
  /* One set of glass values for the whole page: the capsule, the nuit/jour
     switch and the social buttons of the contact page all read from here, so
     they cannot drift apart. They flip with the section the header sits over. */
  --glass-bg: var(--glass-on-dark);
  --glass-line: var(--glass-on-dark-line);
  --glass-hi: var(--glass-on-dark-hi);
  --glass-panel: var(--glass-panel-on-dark);
  transition: transform 600ms var(--ease-out), color 400ms var(--ease-out);
}
.site-header > * { pointer-events: auto; }
.site-header[data-theme="light"] {
  color: var(--anthracite);
  --header-scrim: rgba(255, 255, 255, .92);
  --glass-bg: var(--glass-on-light);
  --glass-line: var(--glass-on-light-line);
  --glass-hi: var(--glass-on-light-hi);
  --glass-panel: var(--glass-panel-on-light);
}
.site-header.is-hidden { transform: translate3d(0, -110%, 0); }
/* Once the header floats over content instead of the first screen, a soft scrim
   keeps the monogram and the links readable above photographs and text. */
.site-header::before {
  content: "";
  position: absolute;
  inset: 0 0 -28px;
  z-index: -1;
  background: linear-gradient(to bottom, var(--header-scrim, rgba(44, 46, 53, .82)), transparent);
  opacity: 0;
  transition: opacity 400ms var(--ease-out);
  pointer-events: none;
}
.site-header.is-floating::before { opacity: 1; }

.brand {
  position: relative;
  display: grid;
  place-items: center;
  width: 72px;
  height: 72px;
  color: inherit;
  flex: none;
}
/* Logo symbole at its charte minimum (56 px), untouched; the progress ring
   sits outside it with its own clear space and is a separate UI element. */
.brand__symbol { width: 56px; height: 56px; fill: currentColor; }
.brand__ring {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  transform: rotate(-90deg);
  overflow: visible;
}
.brand__ring circle { fill: none; stroke: currentColor; stroke-width: 1; }
.brand__track { opacity: .16; }
.brand__progress { stroke-dasharray: 1 1; stroke-dashoffset: 1; }

/* The glass capsule ------------------------------------------------------- */
.capsule {
  display: flex;
  align-items: center;
  gap: clamp(4px, .8vw, 10px);
  min-width: 0;
  padding: 5px;
  border: 1px solid var(--glass-line);
  border-radius: 999px;
  background: var(--glass-bg);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  transition: background 400ms var(--ease-out), border-color 400ms var(--ease-out);
}
.capsule__rule {
  flex: none;
  width: 1px;
  height: 22px;
  background: currentColor;
  opacity: .22;
}

.nav { position: relative; min-width: 0; }
.nav > ul { display: flex; align-items: center; }
.nav__item { position: relative; display: flex; align-items: center; }
.nav a {
  position: relative;
  display: block;
  padding: 11px clamp(10px, 1.4vw, 20px);
  border-radius: 999px;
  font: 600 12px/1 var(--font-ui);
  letter-spacing: .18em;
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
  opacity: .72;
  transition: opacity 320ms var(--ease-out);
}
.nav a[aria-current] { opacity: 1; }
@media (hover: hover) and (pointer: fine) {
  .nav a:hover { opacity: 1; }
}
.nav a:focus-visible { opacity: 1; outline-offset: -3px; }
/* The pill behind the current item. Its width has to follow the label, so this
   is the one place on the page where a size is animated — a single element,
   out of flow, so it costs no layout anywhere else. */
.nav__pill {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: var(--pill-w, 0px);
  border-radius: 999px;
  background: var(--glass-hi);
  opacity: var(--pill-o, 0);
  transform: translate3d(var(--pill-x, 0px), 0, 0);
  transition: transform 560ms var(--ease-strong), width 560ms var(--ease-strong), opacity 320ms var(--ease-out);
  pointer-events: none;
}

/* The chevron that opens the home page's own sections. It is a second,
   smaller control inside the Accueil pill: the label still goes to the top of
   the home page, the chevron opens the list. */
.nav__more {
  display: grid;
  place-items: center;
  /* 24 px at least, for a finger (WCAG target size); the margin keeps the arrow where it was (25.10.2026) */
  width: 24px;
  height: 30px;
  margin-left: -9px;
  padding: 0;
  border: 0;
  border-radius: 999px;
  background: none;
  color: inherit;
  opacity: .58;
  cursor: pointer;
  transition: opacity 300ms var(--ease-out), rotate 360ms var(--ease-strong);
}
.nav__more svg { width: 12px; height: 12px; fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
.nav__more[aria-expanded="true"] { opacity: 1; rotate: 180deg; }
@media (hover: hover) and (pointer: fine) {
  .nav__more:hover { opacity: 1; }
}

.submenu {
  position: absolute;
  top: calc(100% + 14px);
  left: -6px;
  z-index: 2;
  min-width: 210px;
  padding: 8px;
  border: 1px solid var(--glass-line);
  border-radius: 20px;
  background: var(--glass-panel);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  box-shadow: 0 24px 50px -30px rgba(12, 13, 16, .6);
  opacity: 0;
  visibility: hidden;
  translate: 0 -8px;
  transition: opacity 260ms var(--ease-out), translate 300ms var(--ease-out), visibility 0s linear 300ms;
}
.nav__item--menu.is-open .submenu {
  opacity: 1;
  visibility: visible;
  translate: 0 0;
  transition-delay: 0s;
}
/* The header slides away on the way down; a list left open under a resting
   pointer hangs below the bar, so it would stay in view on its own. */
.site-header.is-hidden .nav__item--menu.is-open .submenu {
  opacity: 0;
  visibility: hidden;
}
.submenu li { display: block; }
.submenu a {
  display: block;
  padding: 10px 14px;
  border-radius: 999px;
  font: 600 11px/1 var(--font-ui);
  letter-spacing: .14em;
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
  opacity: .74;
  transition: opacity 260ms var(--ease-out), background-color 260ms var(--ease-out);
}
.submenu a[aria-current] { opacity: 1; background: var(--glass-hi); }
@media (hover: hover) and (pointer: fine) {
  .submenu a:hover { opacity: 1; background: var(--glass-hi); }
}
.submenu a:focus-visible { opacity: 1; outline-offset: -3px; }
/* The page you are on is listed, but it goes nowhere (Lestòbi on the home page). */
.submenu a:not([href]) { cursor: default; }

/* "Projets" is a button, not a link: its list is the whole point. It wears
   the same type as the links beside it, with the chevron inside the label. */
.nav__label {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 11px clamp(10px, 1.4vw, 20px);
  border: 0;
  border-radius: 999px;
  background: none;
  color: inherit;
  cursor: pointer;
  font: 600 12px/1 var(--font-ui);
  letter-spacing: .18em;
  text-transform: uppercase;
  white-space: nowrap;
  opacity: .72;
  transition: opacity 320ms var(--ease-out);
}
.nav__label svg { flex: none; width: 11px; height: 11px; fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; transition: rotate 360ms var(--ease-strong); }
.nav__label[aria-expanded="true"], .nav__label.is-current { opacity: 1; }
.nav__label[aria-expanded="true"] svg { rotate: 180deg; }
@media (hover: hover) and (pointer: fine) {
  .nav__label:hover { opacity: 1; }
}
.nav__label:focus-visible { opacity: 1; outline-offset: -3px; }
/* Without the script the lists still open: on hover, or when a tap or the
   keyboard puts focus inside. main.js sets .js-nav and takes over. */
html:not(.js-nav) .nav__item--menu:hover .submenu,
html:not(.js-nav) .nav__item--menu:focus-within .submenu {
  opacity: 1;
  visibility: visible;
  translate: 0 0;
  transition-delay: 0s;
}

/* The nuit / jour switch --------------------------------------------------
   A track and a knob. The palm rides the knob from the night end to the day
   end: --dn-p is 0 at night and 1 by day, and while the clip runs main.js
   writes every value in between, so the knob crosses at the pace of the sun.
   Only the knob's transform moves; the track never changes size. */
.daynight {
  --dn-w: 68px;
  --dn-h: 40px;
  --dn-knob: 32px;
  --dn-goal: 12px;
  --dn-travel: calc(var(--dn-w) - var(--dn-h));
  --dn-p: 0;
  position: relative;
  flex: none;
  display: block;
  width: var(--dn-w);
  height: var(--dn-h);
  padding: 0;
  border: 1px solid var(--glass-line);
  border-radius: 999px;
  background: var(--glass-bg);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  color: inherit;
  cursor: pointer;
  transition: background 320ms var(--ease-out), border-color 320ms var(--ease-out);
}
.daynight[data-state="jour"] { --dn-p: 1; }
.daynight.is-busy { cursor: progress; }
.daynight__knob {
  position: absolute;
  left: 3px;
  top: 3px;
  display: grid;
  place-items: center;
  width: var(--dn-knob);
  height: var(--dn-knob);
  border-radius: 50%;
  background: var(--glass-hi);
  box-shadow: inset 0 0 0 1px var(--glass-line);
  transform: translate3d(calc(var(--dn-p) * var(--dn-travel)), 0, 0);
  /* a spring with a little overshoot (bounce ≈ 0.2): it is a thing you push */
  transition: transform 620ms cubic-bezier(0.34, 1.42, 0.64, 1), scale 240ms var(--ease-out), translate 320ms var(--ease-out), background-color 320ms var(--ease-out);
  will-change: transform;
}
/* While the clip runs the knob is placed every frame: no easing on top. */
.daynight.is-tracking .daynight__knob { transition: scale 240ms var(--ease-out); }
.daynight:active .daynight__knob { scale: .92; }
@media (hover: hover) and (pointer: fine) {
  .daynight:hover { background: var(--glass-hi); }
  /* the knob leans towards the end it will go to */
  .daynight:not(.is-busy):hover .daynight__knob { translate: 3px 0; }
  .daynight[data-state="jour"]:not(.is-busy):hover .daynight__knob { translate: -3px 0; }
}
/* Where the knob is going: a sun at the day end, a moon at the night end. */
.daynight__goal {
  position: absolute;
  top: 50%;
  width: var(--dn-goal);
  height: var(--dn-goal);
  margin-top: calc(var(--dn-goal) / -2);
  fill: none;
  stroke: currentColor;
  stroke-width: 1.1;
  stroke-linecap: round;
  stroke-linejoin: round;
  pointer-events: none;
  transition: opacity 420ms var(--ease-out);
}
.daynight__goal--jour { right: calc(var(--dn-travel) / 2 - var(--dn-goal) / 2 + 3px); opacity: calc((1 - var(--dn-p)) * .55); }
.daynight__goal--nuit { left: calc(var(--dn-travel) / 2 - var(--dn-goal) / 2 + 3px); opacity: calc(var(--dn-p) * .55); }
.daynight__goal--nuit path { fill: currentColor; stroke: none; }
.daynight__label {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.daynight__faces { position: relative; display: block; width: 20px; height: 20px; }
.daynight__face {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.25;
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: opacity 400ms var(--ease-out), rotate 420ms var(--ease-strong), scale 420ms var(--ease-strong);
}
.daynight__sky circle { fill: currentColor; stroke: none; }
.daynight__face--nuit .daynight__sky path { fill: currentColor; stroke: none; }
.daynight__sky { opacity: .9; }
.daynight[data-state="nuit"] .daynight__face--jour,
.daynight[data-state="jour"] .daynight__face--nuit {
  opacity: 0;
  rotate: -32deg;
  scale: .72;
}
.daynight[data-state="jour"] .daynight__face--nuit { rotate: 32deg; }
/* While the clip runs, the ring traces how far the sun has come up. */
.daynight__progress {
  position: absolute;
  inset: -1px;
  width: calc(100% + 2px);
  height: calc(100% + 2px);
  transform: rotate(-90deg);
  opacity: 0;
  transition: opacity 240ms var(--ease-out);
}
.daynight__progress circle {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.4;
  stroke-dasharray: 1 1;
  stroke-dashoffset: 1;
}
.daynight.is-busy .daynight__progress { opacity: .85; }

/* The palm lives: now and then a breeze bends it, and until the switch has
   been used once the whole button gives a small nudge with it, so it reads
   as something to press. Transform only; nothing moves under reduced motion
   (.motion-ok is set by the page head only when motion is welcome). */
.daynight__palm { transform-box: view-box; transform-origin: 9px 21.6px; }
.motion-ok .daynight:not(.is-busy) .daynight__palm { animation: palmSway 4.2s var(--ease-in-out) 1s infinite; }
/* Until the first press the knob keeps starting towards the day end and
   coming back: the gesture it is waiting for. */
.motion-ok .daynight:not(.was-used):not(.is-busy) .daynight__knob { animation: daynightNudge 4.2s var(--ease-out) 1s infinite; }
/* Until the first press: an outline keeps leaving the switch, like a tap
   target asking to be tapped, and a short caption says what it does.
   Transform and opacity only. */
.daynight::before {
  content: "";
  position: absolute;
  inset: -1px;
  border-radius: 999px;
  border: 1px solid currentColor;
  opacity: 0;
  pointer-events: none;
}
.motion-ok .daynight:not(.was-used):not(.is-busy)::before { animation: daynightRing 2.8s var(--ease-out) .8s infinite; }
@keyframes daynightRing {
  0% { transform: scale(1); opacity: .6; }
  70%, 100% { transform: scale(1.26, 1.5); opacity: 0; }
}
.daynight__label {
  position: absolute;
  inset: auto 0 auto auto;
  top: calc(100% + 10px);
  right: 0;
  width: max-content;
  max-width: 220px;
  height: auto;
  padding: 8px 12px;
  border-radius: 999px;
  border: 1px solid var(--glass-line);
  background: color-mix(in srgb, var(--anthracite) 82%, transparent);
  color: var(--blanc);
  clip-path: none;
  overflow: visible;
  font: 500 11px/1.25 var(--font-ui);
  letter-spacing: .06em;
  text-align: right;
  white-space: normal;
  opacity: 0;
  translate: 0 -4px;
  pointer-events: none;
  transition: opacity 320ms var(--ease-out), translate 320ms var(--ease-out);
}
.motion-ok .daynight:not(.was-used) .daynight__label { animation: daynightHint 9s var(--ease-out) 1.4s 1 both; }
@keyframes daynightHint {
  0% { opacity: 0; translate: 0 -4px; }
  8%, 78% { opacity: 1; translate: 0 0; }
  100% { opacity: 0; translate: 0 -4px; }
}
.daynight:focus-visible .daynight__label { opacity: 1; translate: 0 0; animation: none; }
@media (hover: hover) and (pointer: fine) {
  .daynight:hover .daynight__label { opacity: 1; translate: 0 0; animation: none; }
}
@keyframes palmSway {
  0%, 58%, 100% { rotate: 0deg; }
  66% { rotate: -9deg; }
  74% { rotate: 6deg; }
  82% { rotate: -3.5deg; }
  90% { rotate: 1.2deg; }
}
@keyframes daynightNudge {
  0%, 58%, 100% { translate: 0 0; }
  64% { translate: 7px 0; }
  71% { translate: -1.5px 0; }
  78% { translate: 2.5px 0; }
  85% { translate: 0 0; }
}
@media (hover: hover) and (pointer: fine) {
  .motion-ok .daynight:hover .daynight__knob { animation: none; }
  .motion-ok .daynight:not(.is-busy):hover .daynight__palm { animation: palmHover 1.1s var(--ease-in-out) infinite alternate; }
}
@keyframes palmHover { from { rotate: -7deg; } to { rotate: 5deg; } }

/* ---------- 5. Hero ---------- */
.hero {
  position: relative;
  height: 100svh;
  min-height: 560px;
  overflow: clip;
  background: var(--graphite);
  color: var(--blanc);
  perspective: 1400px;
}
.hero__media {
  position: absolute;
  inset: -3%;
  transform-origin: 50% 45%;
  will-change: transform;
}
/* Three layers, one framing: the night still (it carries the first paint, and
   the whole hero when there is no JavaScript), the day still, and the clip the
   nuit/jour switch drives. Under prefers-reduced-motion the clip never loads
   and the switch cross-fades the two stills instead. */
.hero__img, .hero__video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* the villa fills the upper two thirds, the dark lawn below carries the logo */
  object-position: 50% var(--hero-y);
  transform: scale(1.06);
  will-change: transform;
}
/* The frame is 4:3, so the wider the screen, the less of its height shows: 75 % at 16:9, 56 % at 21:9. At 60 %
   the crop takes 15 % off the top at 16:9, 20 % at 2:1, but 26 % at 21:9, and the night's roof went (22.10.2026, a
   3440 x 1440 screen). Ultra-wide screens hold the frame
   higher, so no more than about 20 % comes off the top: the whole roof and its chimney with a little sky (45 %
   chosen from 50, 45 and 40 on 3440 x 1440; 34 % brought the house down under the title). */
.hero { --hero-y: 60%; }
@media (min-aspect-ratio: 22/10) { .hero { --hero-y: 45%; } }
@media (min-aspect-ratio: 28/10) { .hero { --hero-y: 32%; } }
.hero__img--jour, .hero__video { opacity: 0; transition: opacity 760ms var(--ease-out); }
.hero.is-video .hero__video { opacity: 1; }
.hero.is-stills.is-jour .hero__img--jour { opacity: 1; }
/* The day frame stands closer to the house than the night one (the clip moves
   in), and on a wide screen the night's framing cut its roof off. So the
   picture rises with the sun: --hero-rise goes from 0 (night) to 1 (day) with
   the clip (main.js, initDayNight) and the day still stands where the clip
   ends. A screen held upright shows the frame's whole height: nothing moves. */
.hero__video { object-position: 50% calc(var(--hero-y) - var(--hero-rise, 0) * (var(--hero-y) - 22%)); }
.hero__img--jour { object-position: 50% 22%; }
/* The clip's frames are soft (it is a generated clip). Once it rests on its
   last frame, the same picture cut from a 4K master fades in over it; it steps
   aside quickly before the clip rewinds. */
.hero.is-video .hero__img--jour { z-index: 1; transition-duration: 260ms; }
.hero.is-video.is-sharp .hero__img--jour { opacity: 1; transition-duration: 760ms; }
.hero__veil {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(to bottom, rgba(44, 46, 53, .55) 0%, rgba(44, 46, 53, 0) 20%, rgba(44, 46, 53, 0) 42%, rgba(44, 46, 53, .62) 60%, rgba(44, 46, 53, .9) 100%);
  pointer-events: none;
}
.hero__content {
  position: absolute;
  inset: auto 0 0 0;
  display: grid;
  justify-items: center;
  gap: clamp(22px, 3.6vh, 40px);
  padding: 0 var(--gutter) clamp(88px, 12vh, 132px);
  text-align: center;
}
.hero__logo img {
  width: clamp(240px, 32vw, 480px);
  height: auto;
  aspect-ratio: 390.9 / 114.1;
  /* clear space around the mark (charte p. 29) */
  margin: 8px;
}
.hero__line { display: block; }
.hero__line--lead {
  font: 400 clamp(1.25rem, 2vw, 1.75rem)/1.3 var(--font-display);
  letter-spacing: .01em;
}
.hero__line--sub {
  margin-top: 14px;
  font: 600 clamp(.625rem, .78vw, .75rem)/1.9 var(--font-ui);
  letter-spacing: .26em;
  text-transform: uppercase;
  color: var(--gris-clair);
  max-width: 62ch;
}
.hero__scroll {
  position: absolute;
  left: 50%;
  bottom: 24px;
  width: 1px;
  height: 56px;
  margin-left: -.5px;
  overflow: hidden;
  background: rgba(255, 255, 255, .22);
}
.hero__scroll::before { content: ""; position: absolute; inset: -12px -20px; }
.hero__scroll span {
  position: absolute;
  inset: 0;
  background: var(--blanc);
  transform: translate3d(0, -100%, 0);
  animation: cue 2.4s var(--ease-in-out) infinite;
}
@keyframes cue {
  0% { transform: translate3d(0, -100%, 0); }
  55% { transform: translate3d(0, 0, 0); }
  100% { transform: translate3d(0, 100%, 0); }
}

/* ---------- 6. Film (PROLIT) ---------- */
.film {
  position: relative;
  z-index: var(--z-scene);
  background: var(--graphite);
  color: var(--blanc);
}

/* Static storyboard (no JS / reduced motion) */
.film__stage { padding: calc(var(--header-h) + 40px) var(--gutter) clamp(72px, 12vh, 140px); }
.film__media {
  position: relative;
  max-width: 1200px;
  margin: 0 auto;
  aspect-ratio: 16 / 9;
  background: #000;
}
.film__poster { display: none; }
.film__video { width: 100%; height: 100%; object-fit: cover; }
.film__scrim, .film__hud, .film__rail, .film__loader { display: none; }
.film__title {
  max-width: 1200px;
  margin: 40px auto 0;
  font: 400 clamp(2rem, 4vw, 3.5rem)/1.1 var(--font-display);
}
.film__title span {
  display: block;
  margin-top: 10px;
  font: 600 12px/1.4 var(--font-ui);
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--gris-clair);
}
.film__chapters {
  max-width: 1200px;
  margin: 40px auto 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 320px), 1fr));
  gap: 48px 32px;
}
.chapter__still { width: 100%; aspect-ratio: 16 / 9; object-fit: cover; }
.chapter__name {
  margin-top: 18px;
  display: flex;
  justify-content: space-between;
  font: 700 12px/1.4 var(--font-ui);
  letter-spacing: .2em;
  text-transform: uppercase;
}
.chapter__name span { font-weight: 600; color: var(--gris-clair); letter-spacing: .08em; }
.chapter__body { margin-top: 12px; display: grid; gap: 8px; }

.beat { display: block; }
.beat--display { font: 400 1.5rem/1.2 var(--font-display); }
.beat--title { font: 400 1.75rem/1.1 var(--font-display); }
.beat--room { font: 400 1.5rem/1.15 var(--font-display); }
.beat--quote { font: 400 1.125rem/1.45 var(--font-display); display: inline; }
.beat--label {
  font: 600 11px/1.5 var(--font-ui);
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--gris-clair);
}
.beat--sub { font: 300 .9375rem/1.5 var(--font-body); color: var(--gris-clair); }
.beat--sign {
  font: 700 11px/1.5 var(--font-ui);
  letter-spacing: .22em;
  text-transform: uppercase;
}
.beat--sign span {
  display: block;
  font-weight: 600;
  letter-spacing: .16em;
  color: var(--gris-clair);
}
.beat--logo { width: min(260px, 70%); height: auto; aspect-ratio: 390.9 / 114.1; fill: var(--blanc); margin: 8px 0; }
.beat--cta {
  position: relative;
  justify-self: start;
  display: inline-block;
  padding: 12px 0;
  font: 600 12px/1 var(--font-ui);
  letter-spacing: .22em;
  text-transform: uppercase;
  text-decoration: none;
}
.beat--cta::after {
  content: "";
  position: absolute;
  left: 0; right: .22em; bottom: 4px;
  height: 1px;
  background: currentColor;
  transform-origin: left center;
}

/* Scroll-scrubbed mode */
.film.is-scrub .film__track { height: calc(var(--film-screens, 16) * 100svh); }
.film.is-scrub .film__stage {
  position: sticky;
  top: 0;
  height: 100svh;
  padding: 0;
  overflow: clip;
}
.film.is-scrub .film__media {
  position: absolute;
  inset: 0;
  max-width: none;
  aspect-ratio: auto;
  overflow: hidden;
  background: var(--graphite);
}
.film.is-scrub .film__poster,
.film.is-scrub .film__video {
  display: block;
  position: absolute;
  left: 50%;
  top: 50%;
  /* exactly 16:9 and never smaller than the screen: cover, but panned by transform */
  width: max(100vw, 177.78svh);
  height: max(100svh, 56.25vw);
  max-width: none;
  object-fit: cover;
  transform: translate(-50%, -50%);
  will-change: transform;
}
/* An upright screen has the upright film (main.js, is-tall): 9:16, cover, centred (it is already cut along the subject) */
.film.is-scrub.is-tall .film__poster,
.film.is-scrub.is-tall .film__video { width: max(100vw, 56.25svh); height: max(100svh, 177.78vw); }
.film.is-scrub .film__video { opacity: 0; transition: opacity 600ms var(--ease-out); }
.film.is-scrub .film__video.is-ready { opacity: 1; }
/* The light copy of the film, under the sharp one (main.js, scrubFilm): there only where the sharp film has not
   arrived yet. The sharp film steps aside at once and comes back with the fade above; the light copy itself never
   fades, as a moving picture fading over a still one shows both. */
.film.is-scrub .film__video--lo { transition: none; }
.film.is-scrub .film__video--lo.is-shown { opacity: 1; }
.film.is-scrub .film__video.is-under { opacity: 0; transition: none; }
.film.is-scrub .film__scrim {
  display: block;
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    linear-gradient(to bottom, rgba(44, 46, 53, .42) 0%, rgba(44, 46, 53, 0) 18%),
    linear-gradient(to top, rgba(44, 46, 53, .8) 0%, rgba(44, 46, 53, .38) 28%, rgba(44, 46, 53, 0) 52%);
}
.film__veil { display: none; }
.film.is-scrub .film__veil {
  display: block;
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(ellipse 75% 65% at 50% 50%, rgba(44, 46, 53, .66), rgba(44, 46, 53, .42));
}
.film.is-scrub .film__veil--soft {
  background: radial-gradient(ellipse 60% 50% at 50% 50%, rgba(44, 46, 53, .36), rgba(44, 46, 53, 0));
}
.film.is-scrub .film__title { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); margin: 0; }
.film.is-scrub .film__chapters {
  position: absolute;
  inset: 0;
  max-width: none;
  margin: 0;
  display: block;
  pointer-events: none;
}
.film.is-scrub .chapter { position: absolute; inset: 0; }
.film.is-scrub .chapter__still,
.film.is-scrub .chapter__name { display: none; }
.film.is-scrub .chapter__body {
  position: absolute;
  left: var(--gutter);
  right: var(--gutter);
  bottom: clamp(104px, 15vh, 160px);
  margin: 0;
  gap: 14px;
  max-width: 820px;
}
.film.is-scrub .chapter__body--center {
  left: 50%;
  right: auto;
  bottom: 50%;
  width: min(92vw, 900px);
  transform: translate(-50%, 50%);
  justify-items: center;
  text-align: center;
}
.film.is-scrub .chapter__body--quote { max-width: min(880px, 78vw); gap: 22px; }
/* The president's opening words, once said, park in the top-left corner and
   stay (main.js scales the whole block, so its line breaks never change). No
   plate behind them: a soft shadow keeps white type legible over bright sea. */
.film { --pin-size: 17px; }
.film.is-scrub [data-pin],
.film.is-scrub [data-pin] .beat--sign { transform-origin: 0 0; }
/* No layer of their own: a promoted layer keeps its first raster and the
   shrunk type would come out jagged; this way it is redrawn at its real size. */
.film.is-scrub [data-pin] .beat {
  will-change: auto;
  /* sized for the block at full scale: once it is shrunk to the corner the
     shadow shrinks with it, so it starts wider than it looks necessary */
  text-shadow: 0 2px 5px rgba(20, 21, 25, .62), 0 0 30px rgba(20, 21, 25, .5);
}
.film.is-scrub .chapter__body--finale {
  left: 50%;
  right: auto;
  bottom: 50%;
  width: min(92vw, 640px);
  transform: translate(-50%, 50%);
  justify-items: center;
  gap: clamp(28px, 5vh, 48px);
}
.film.is-scrub .beat { will-change: opacity, transform; }
.film.is-scrub .beat--display { font-size: clamp(2rem, 5vw, 4.75rem); line-height: 1.05; letter-spacing: -.005em; }
.film.is-scrub .beat--title { font-size: clamp(2.5rem, 6vw, 5.5rem); line-height: 1; }
.film.is-scrub .beat--room { font-size: clamp(2rem, 4.2vw, 3.75rem); line-height: 1.05; }
.film.is-scrub .beat--quote { display: block; font-size: clamp(1.375rem, 2.7vw, 2.5rem); line-height: 1.28; }
.film.is-scrub .beat--quote + .beat--quote { margin-top: .35em; }
.film.is-scrub .beat--sub { font-size: clamp(.9375rem, 1.2vw, 1.125rem); color: var(--blanc); opacity: .9; }
.film.is-scrub .beat--label { color: var(--blanc); }
.film.is-scrub .beat--logo { width: clamp(240px, 30vw, 440px); }
.film.is-scrub .beat--cta { justify-self: center; pointer-events: auto; }

/* HUD: chapter name, timecode, tick rail */
.film.is-scrub .film__hud {
  display: flex;
  position: absolute;
  right: calc(var(--gutter) + 36px);
  bottom: clamp(30px, 5vh, 48px);
  gap: 22px;
  align-items: baseline;
  font: 600 11px/1 var(--font-ui);
  letter-spacing: .2em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, .9);
}
.hud__time { font-variant-numeric: tabular-nums; letter-spacing: .08em; color: rgba(255, 255, 255, .62); }
.hud__now { color: var(--blanc); }

.film.is-scrub .film__rail {
  display: flex;
  flex-direction: column;
  position: absolute;
  right: var(--gutter);
  top: 50%;
  width: 20px;
  height: min(58vh, 540px);
  transform: translateY(-50%);
}
.rail__seg {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  align-items: flex-end;
  padding: 4px 0;
  margin: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  cursor: pointer;
}
/* A chapter is a button (main.js): the ticks stay as they were, the hand finds a wider target to their left. */
.rail__seg::before { content: ""; position: absolute; inset: 0 -6px 0 -26px; }
.rail__seg:focus-visible { outline: 1px solid var(--blanc); outline-offset: 4px; }
.rail__name {
  position: absolute;
  right: calc(100% + 14px);
  top: -1px;
  white-space: nowrap;
  font: 600 10px/1 var(--font-ui);
  letter-spacing: .24em;
  text-transform: uppercase;
  color: var(--blanc);
  text-shadow: 0 1px 14px rgba(20, 21, 24, .7);
  opacity: 0;
  translate: 8px 0;
  pointer-events: none;
  transition: opacity 220ms var(--ease-out), translate 280ms var(--ease-strong);
}
.rail__seg:focus-visible .rail__name { opacity: 1; translate: 0 0; }
@media (hover: hover) and (pointer: fine) {
  .rail__seg:hover .rail__name { opacity: 1; translate: 0 0; }
  .rail__seg:hover .rail__tick { background: var(--blanc); }
}
.rail__seg:active .rail__tick:first-child { transform: scaleX(.8); transform-origin: 100% 50%; }
.rail__tick {
  display: block;
  width: 6px;
  height: 1px;
  background: rgba(255, 255, 255, .45);
  transition: background-color 300ms var(--ease-out);
}
.rail__tick:first-child { width: 14px; background: rgba(255, 255, 255, .6); }
.rail__seg.is-active .rail__tick { background: var(--blanc); }
.rail__head {
  position: absolute;
  right: 0;
  top: 0;
  width: 20px;
  height: 1px;
  background: var(--blanc);
  will-change: transform;
}

.film.is-scrub .film__loader {
  display: flex;
  position: absolute;
  left: var(--gutter);
  bottom: clamp(30px, 5vh, 48px);
  align-items: center;
  gap: 14px;
  font: 600 10px/1 var(--font-ui);
  letter-spacing: .2em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, .7);
  opacity: 0;
  transition: opacity 400ms var(--ease-out);
}
.film.is-waiting .film__loader { opacity: 1; }
.film__loader-bar {
  position: relative;
  width: 96px;
  height: 1px;
  overflow: hidden;
  background: rgba(255, 255, 255, .22);
}
.film__loader-bar::after {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--blanc);
  transform: scaleX(var(--loaded, 0));
  transform-origin: left center;
}

/* ---------- 7. Réalisations: presenter scene ---------- */
.realisations { position: relative; z-index: 2; background: var(--blanc); color: var(--anthracite); }
.presenter { position: relative; background: var(--blanc); }

/* Static layout: presenter beside the mosaic */
.presenter__stage {
  position: relative;
  display: grid;
  grid-template-columns: minmax(200px, 28%) 1fr;
  grid-template-areas:
    "head head"
    "figure mosaic"
    "caption caption";
  gap: 32px clamp(24px, 4vw, 64px);
  padding: calc(var(--header-h) + 48px) var(--gutter) clamp(48px, 8vh, 96px);
  max-width: var(--maxw);
  margin: 0 auto;
}
.presenter__bg {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  /* fades to pure white at the bottom, where the stage meets the page */
  -webkit-mask-image: linear-gradient(to bottom, #000 62%, transparent 96%);
  mask-image: linear-gradient(to bottom, #000 62%, transparent 96%);
}
.blob {
  position: absolute;
  border-radius: 50%;
  background: radial-gradient(closest-side, rgba(212, 212, 212, .55), rgba(212, 212, 212, 0));
  will-change: transform;
}
.blob--1 { width: 70vmax; height: 70vmax; left: -22vmax; top: -30vmax; animation: drift1 26s var(--ease-in-out) infinite alternate; }
.blob--2 { width: 60vmax; height: 60vmax; right: -24vmax; bottom: -30vmax; animation: drift2 32s var(--ease-in-out) infinite alternate; }
.blob--3 { width: 38vmax; height: 38vmax; left: 38%; top: 30%; opacity: .7; animation: drift3 22s var(--ease-in-out) infinite alternate; }
@keyframes drift1 { to { transform: translate3d(14vmax, 10vmax, 0) scale(1.08); } }
@keyframes drift2 { to { transform: translate3d(-12vmax, -8vmax, 0) scale(.94); } }
@keyframes drift3 { to { transform: translate3d(-10vmax, 8vmax, 0) scale(1.12); } }
.motes { position: absolute; inset: 0; }
.motes i {
  position: absolute;
  width: 3px;
  height: 3px;
  border-radius: 50%;
  background: var(--gris-clair);
  opacity: 0;
  animation: mote 14s linear infinite;
}
.motes i:nth-child(1)  { left: 8%;  top: 82%; animation-delay: -1s; }
.motes i:nth-child(2)  { left: 16%; top: 64%; animation-delay: -7s; width: 2px; height: 2px; }
.motes i:nth-child(3)  { left: 24%; top: 90%; animation-delay: -3s; }
.motes i:nth-child(4)  { left: 33%; top: 72%; animation-delay: -11s; width: 4px; height: 4px; }
.motes i:nth-child(5)  { left: 41%; top: 86%; animation-delay: -5s; width: 2px; height: 2px; }
.motes i:nth-child(6)  { left: 52%; top: 78%; animation-delay: -9s; }
.motes i:nth-child(7)  { left: 60%; top: 94%; animation-delay: -2s; width: 4px; height: 4px; }
.motes i:nth-child(8)  { left: 67%; top: 70%; animation-delay: -12s; width: 2px; height: 2px; }
.motes i:nth-child(9)  { left: 74%; top: 88%; animation-delay: -6s; }
.motes i:nth-child(10) { left: 81%; top: 66%; animation-delay: -10s; width: 2px; height: 2px; }
.motes i:nth-child(11) { left: 88%; top: 84%; animation-delay: -4s; width: 4px; height: 4px; }
.motes i:nth-child(12) { left: 94%; top: 74%; animation-delay: -8s; }
.motes i:nth-child(13) { left: 12%; top: 96%; animation-delay: -13s; width: 2px; height: 2px; }
.motes i:nth-child(14) { left: 46%; top: 60%; animation-delay: -0.5s; }
@keyframes mote {
  0% { transform: translate3d(0, 0, 0); opacity: 0; }
  15% { opacity: .9; }
  85% { opacity: .6; }
  100% { transform: translate3d(3vw, -55vh, 0); opacity: 0; }
}

.presenter__head { grid-area: head; position: relative; z-index: 4; margin-inline: 0; max-width: none; }
.presenter__film { display: none; }
.presenter__figure {
  grid-area: figure;
  position: relative;
  z-index: 2;
  align-self: end;
  justify-self: center;
  width: 100%;
  max-width: 360px;
}
.presenter__figure img { width: auto; height: auto; aspect-ratio: 328 / 950; max-height: min(72vh, 680px); margin: 0 auto; }

.mosaic {
  grid-area: mosaic;
  position: relative;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-template-rows: repeat(2, 1fr);
  gap: clamp(8px, .9vw, 14px);
  height: clamp(420px, 66vh, 720px);
}
.tile--b { grid-column: 1 / 3; grid-row: 1; }
.tile--c { grid-column: 3; grid-row: 1 / 3; }
.tile--d { grid-column: 4; grid-row: 1; }
.tile--e { grid-column: 1; grid-row: 2; }
.tile--f { grid-column: 2; grid-row: 2; }
.tile--g { grid-column: 4; grid-row: 2; }

.tile {
  position: relative;
  overflow: hidden;
  background: var(--gris-clair-40);
  outline-offset: 3px;
}
.tile__img, .tile__alt {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 1000ms var(--ease-out);
}
.tile__alt { opacity: 0; }
.tile__cap, .shot__cap span, .estate__slide {
  transition: transform 460ms var(--ease-out), opacity 460ms var(--ease-out);
}
.tile__cap {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  padding: 36px 16px 14px;
  font: 600 11px/1.3 var(--font-ui);
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--blanc);
  background: linear-gradient(to top, rgba(44, 46, 53, .78), rgba(44, 46, 53, 0));
  transform: translate3d(0, 100%, 0);
}
@media (hover: hover) and (pointer: fine) {
  .tile:hover .tile__img, .tile:hover .tile__alt { transform: scale(1.07); }
  .tile:hover .tile__cap { transform: none; }
}
.tile.is-active .tile__img, .tile.is-active .tile__alt { transform: scale(1.07); }
.tile:focus-visible .tile__cap, .tile.is-active .tile__cap { transform: none; }

.presenter__caption {
  grid-area: caption;
  position: relative;
  z-index: 4;
  font: 600 12px/1.4 var(--font-ui);
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--gris-cendre);
}
.presenter__caption span {
  display: block;
  margin-bottom: 6px;
  font: 400 clamp(1.5rem, 2.4vw, 2.25rem)/1.1 var(--font-display);
  letter-spacing: 0;
  text-transform: none;
  color: var(--anthracite);
}

/* Live (pinned, scroll-driven) presenter scene */
.presenter.is-live { margin-top: -100svh; }
.presenter.is-live .presenter__track { height: 340svh; }
.presenter.is-live .presenter__stage {
  position: sticky;
  top: 0;
  display: block;
  height: 100svh;
  max-width: none;
  padding: 0;
  overflow: clip;
  /* Transparent while it slides over the film's last pinned screen; switched on
     (.is-on) in the very frame where both stages meet at the top, so the film's
     last frame is replaced by an identical card without a visible seam. */
  background: transparent;
  pointer-events: none;
}
.presenter.is-live { background: transparent; }
/* the section starts one screen early (it overlaps the film), so that screen stays see-through */
.realisations.has-live-presenter {
  background: linear-gradient(to bottom, transparent 0, transparent 100svh, var(--blanc) 100svh);
}
.presenter.is-live .presenter__bg,
.presenter.is-live .presenter__film { visibility: hidden; }
.presenter.is-live.is-on .presenter__stage { background: var(--blanc); pointer-events: auto; }
.presenter.is-live.is-on .presenter__bg,
.presenter.is-live.is-on .presenter__film { visibility: visible; }
.presenter.is-live .presenter__head {
  position: absolute;
  left: var(--gutter);
  right: var(--gutter);
  top: calc(var(--header-h) + 10px);
}
.presenter.is-live .presenter__film {
  display: block;
  position: absolute;
  inset: 0;
  z-index: 1;
  overflow: hidden;
  will-change: transform;
}
.presenter.is-live .presenter__film img {
  position: absolute;
  left: 50%;
  top: 50%;
  width: max(100vw, 177.78svh);
  height: max(100svh, 56.25vw);
  max-width: none;
  object-fit: cover;
  transform: translate(-50%, -50%) translateX(var(--end-pan, 0px));
}
.presenter.is-live .presenter__figure {
  position: absolute;
  left: 50%;
  bottom: 0;
  width: auto;
  max-width: none;
  height: 80svh;
  margin-left: calc(80svh * -0.1726); /* half the cut-out's width (328 / 950) */
}
.presenter.is-live .presenter__figure img { height: 100%; width: auto; aspect-ratio: 328 / 950; }
.presenter.is-live .mosaic {
  position: absolute;
  left: clamp(300px, 35vw, 620px);
  right: var(--gutter);
  top: calc(var(--header-h) + 124px);
  bottom: 7svh;
  height: auto;
}
.presenter.is-live .tile { z-index: 1; will-change: transform, opacity; }
.presenter.is-live .tile--c,
.presenter.is-live .tile--e { z-index: 3; }
.presenter.is-live .presenter__caption {
  position: absolute;
  left: clamp(300px, 35vw, 620px);
  right: var(--gutter);
  top: calc(var(--header-h) + 64px);
}
.presenter.is-live .presenter__caption span { display: inline; margin: 0 14px 0 0; }

/* ---------- 8. Villa Lestòbi ---------- */
.villa {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(32px, 6vw, 120px);
  align-items: end;
  max-width: var(--maxw);
  margin: 0 auto;
  padding: clamp(96px, 16vh, 180px) var(--gutter) clamp(48px, 8vh, 88px);
  color: var(--anthracite);
}
.villa__name {
  font: 400 clamp(2.75rem, 6vw, 5.75rem)/1 var(--font-display);
  letter-spacing: -.01em;
}
.villa__place {
  margin-top: 22px;
  font: 600 12px/1.5 var(--font-ui);
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--gris-cendre);
}
.villa__lead {
  font: 300 clamp(1.125rem, 1.55vw, 1.4rem)/1.6 var(--font-body);
  max-width: 38ch;
}

.specs {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 28px clamp(20px, 3vw, 44px);
  margin-top: 44px;
}
.specs > div { padding-top: 14px; border-top: 1px solid var(--gris-clair); }
.specs dt {
  font: 600 11px/1.4 var(--font-ui);
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--gris-cendre);
}
.specs dd {
  margin-top: 10px;
  font: 400 clamp(1.25rem, 1.7vw, 1.625rem)/1.2 var(--font-display);
}
.specs--compact { grid-template-columns: repeat(2, minmax(0, 1fr)); margin-top: 28px; gap: 22px 28px; }
.specs--compact dd { font-size: 1.1875rem; }

/* ---------- 9. Gallery (horizontal) ---------- */
.gallery { position: relative; background: var(--blanc); padding-bottom: clamp(72px, 12vh, 140px); }
.gallery__viewport {
  overflow-x: auto;
  overflow-y: hidden;
  overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
  touch-action: pan-x pan-y pinch-zoom;
}
.gallery__viewport.is-dragging { scroll-snap-type: none; }
/* how far along the strip the visitor is; also shows that it can be dragged */
.gallery__bar {
  position: relative;
  height: 1px;
  margin: clamp(18px, 3vh, 32px) var(--gutter) 0;
  background: var(--gris-clair);
  overflow: hidden;
}
.gallery__bar span {
  position: absolute;
  inset: 0;
  background: var(--anthracite);
  transform: scaleX(var(--p, 0));
  transform-origin: left center;
}
.gallery__viewport::-webkit-scrollbar { display: none; }
.gallery__track {
  display: flex;
  align-items: flex-end;
  user-select: none;
  -webkit-user-drag: none;
  gap: clamp(16px, 2vw, 32px);
  width: max-content;
  padding: 0 var(--gutter);
}
.shot {
  flex: none;
  width: clamp(260px, 40vw, 640px);
  scroll-snap-align: center;
  outline-offset: 4px;
}
.shot--tall { width: clamp(220px, 27vw, 440px); }
.shot__frame {
  position: relative;
  overflow: hidden;
  aspect-ratio: 3 / 2;
  background: var(--gris-clair-40);
}
.shot--tall .shot__frame { aspect-ratio: 4 / 5; }
.shot__frame img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transform: scale(1.01);
  transition: transform 1000ms var(--ease-out);
}
.shot__cap {
  overflow: hidden;
  margin-top: 14px;
  font: 600 11px/1.4 var(--font-ui);
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--gris-cendre);
}
.shot__cap span { display: inline-block; transform: translate3d(0, 110%, 0); }
@media (hover: hover) and (pointer: fine) {
  .shot:hover .shot__frame img { transform: scale(1.07); }
  .shot:hover .shot__cap span { transform: none; }
}
.shot.is-active .shot__frame img { transform: scale(1.07); }
.shot:focus-visible .shot__cap span, .shot.is-active .shot__cap span { transform: none; }

.gallery__label {
  max-width: var(--maxw);
  margin: 0 auto 28px;
  padding: 0 var(--gutter);
  font: 600 11px/1.4 var(--font-ui);
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--gris-cendre);
}
.gallery__label span { color: var(--anthracite); margin-right: 14px; }

.gallery.is-pinned .gallery__viewport { overflow: visible; scroll-snap-type: none; }
.gallery.is-pinned .gallery__pin {
  position: sticky;
  top: 0;
  height: 100svh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  overflow: clip;
}
.gallery.is-pinned .gallery__label { margin: 0 0 3vh; max-width: none; }
.gallery.is-pinned .gallery__bar { margin-top: 4vh; }
.gallery.is-pinned .gallery__track { will-change: transform; }
.gallery.is-pinned .shot { width: auto; }
.gallery.is-pinned .shot__frame { height: min(62svh, 640px); width: auto; }
.gallery.is-pinned .shot--tall .shot__frame { height: min(70svh, 720px); }

/* ---------- 10. Du tracé à la réalité (0916) ---------- */
.trace { background: var(--blanc); color: var(--anthracite); }
.trace__stage {
  display: grid;
  gap: 24px;
  padding: clamp(72px, 12vh, 140px) var(--gutter);
  max-width: var(--maxw);
  margin: 0 auto;
}
.trace__title { font: 400 clamp(2.25rem, 5vw, 4.5rem)/1.04 var(--font-display); letter-spacing: -.005em; }
.trace__title span { display: inline-block; }
.trace__frame { position: relative; }
.trace__static { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.trace__static img { width: 100%; aspect-ratio: 16 / 9; object-fit: cover; }
.trace__canvas, .trace__edge { display: none; }
.trace__caption {
  font: 600 11px/1.5 var(--font-ui);
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--gris-cendre);
}

.trace.is-scrub .trace__track { height: 330svh; }
.trace.is-scrub .trace__stage {
  position: sticky;
  top: 0;
  height: 100svh;
  max-width: none;
  grid-template-rows: auto minmax(0, 1fr) auto;
  gap: clamp(10px, 1.6vh, 18px);
  padding: calc(var(--header-h) + 4px) var(--gutter) clamp(14px, 2.4vh, 26px);
  overflow: clip;
}
.trace.is-scrub .trace__title { font-size: clamp(2rem, 4.2vw, 3.75rem); }
.trace.is-scrub .trace__static { display: none; }
.trace.is-scrub .trace__canvas {
  display: block;
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}
.trace.is-scrub .trace__edge {
  display: block;
  position: absolute;
  inset: -1px;
  pointer-events: none;
  box-shadow: inset 0 0 48px 36px var(--blanc);
  will-change: opacity;
}
.trace.is-scrub .trace__a, .trace.is-scrub .trace__b { will-change: opacity, transform; }

/* ---------- 11. Mougins estates ---------- */
.domaines {
  background: linear-gradient(to bottom, var(--blanc), var(--gris-clair-20) 40%);
  padding: clamp(96px, 16vh, 180px) var(--gutter) clamp(72px, 12vh, 140px);
  color: var(--anthracite);
}
.estates {
  display: grid;
  gap: clamp(64px, 11vh, 120px);
  max-width: var(--maxw);
  margin: clamp(48px, 8vh, 88px) auto 0;
}
.estate { display: grid; gap: 26px; align-content: start; }
.estate--wide { grid-template-columns: 1.4fr 1fr; gap: clamp(28px, 5vw, 88px); align-items: end; }
.estates__pair {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 28px clamp(24px, 4vw, 64px);
}
.estates__pair .estate:last-child { margin-top: clamp(0px, 10vh, 120px); }
.estates__pair-note {
  grid-column: 1 / -1;
  max-width: 34ch;
  font: 400 clamp(1.375rem, 2.2vw, 2rem)/1.25 var(--font-display);
}
.estate__visual {
  position: relative;
  overflow: hidden;
  display: grid;
  place-items: center;
  aspect-ratio: 4 / 3;
  background: linear-gradient(140deg, var(--graphite) 0%, var(--anthracite) 55%, var(--gris-cendre) 130%);
  color: var(--blanc);
  outline-offset: 4px;
}
.estate--wide .estate__visual { aspect-ratio: 16 / 10; }
.estate__figure {
  font: 400 clamp(3rem, 7vw, 6rem)/1 var(--font-display);
  letter-spacing: -.01em;
  transition: transform 1000ms var(--ease-out);
}
.estate__figure small { font-size: .38em; letter-spacing: .02em; }
.estate__todo {
  position: absolute;
  top: 18px;
  left: 20px;
  font: 600 10px/1 var(--font-ui);
  letter-spacing: .24em;
  text-transform: uppercase;
  color: var(--gris-clair);
}
.estate__slide {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  display: grid;
  gap: 4px;
  padding: 40px 20px 18px;
  font: 400 .9375rem/1.5 var(--font-body);
  background: linear-gradient(to top, rgba(44, 46, 53, .9), rgba(44, 46, 53, 0));
  transform: translate3d(0, 100%, 0);
}
@media (hover: hover) and (pointer: fine) {
  .estate__visual:hover .estate__figure { transform: scale(1.06); }
  .estate__visual:hover .estate__slide { transform: none; }
}
.estate__visual:focus-visible .estate__slide,
.estate__visual.is-active .estate__slide { transform: none; }
.estate__visual.is-active .estate__figure { transform: scale(1.06); }
.estate__name { font: 400 clamp(2rem, 3.6vw, 3.25rem)/1.05 var(--font-display); }
.estate__place {
  margin-top: 12px;
  font: 600 11px/1.5 var(--font-ui);
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--gris-cendre);
}
.estate__text { margin-top: 18px; font: 300 1.0625rem/1.65 var(--font-body); max-width: 44ch; }

/* ---------- 12. Grey-scale transitions between light and dark ---------- */
.fade { height: clamp(180px, 38vh, 440px); }
.fade--to-dark {
  background: linear-gradient(to bottom, var(--gris-clair-20) 0%, var(--gris-clair) 32%, var(--gris-cendre) 70%, var(--graphite) 100%);
}
.fade--to-light {
  margin-top: clamp(96px, 16vh, 180px);
  margin-inline: calc(var(--gutter) * -1);
  background: linear-gradient(to bottom, var(--graphite) 0%, var(--gris-cendre) 34%, var(--gris-clair) 70%, var(--blanc) 100%);
}

/* ---------- 13. Keywords marquee ---------- */
.keywords {
  position: relative;
  margin-top: -1px; /* covers the sub-pixel seam under the grey-scale fade */
  background: var(--graphite);
  color: var(--blanc);
  padding: clamp(40px, 9vh, 110px) var(--gutter);
  overflow: clip;
}
.marquee__track { display: flex; flex-wrap: wrap; justify-content: center; }
.marquee__list {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  row-gap: 6px;
}
.marquee__list[aria-hidden="true"] { display: none; }
.marquee__list li {
  display: flex;
  align-items: center;
  white-space: nowrap;
  font: 400 clamp(1.5rem, 3.4vw, 2.75rem)/1.2 var(--font-display);
}
/* the charte's square separator */
.marquee__list li::after {
  content: "";
  flex: none;
  width: .14em;
  height: .14em;
  margin: 0 .6em;
  background: var(--gris-cendre);
}
.marquee.is-running { margin-inline: calc(var(--gutter) * -1); }
.marquee.is-running .marquee__track { flex-wrap: nowrap; justify-content: flex-start; width: max-content; will-change: transform; }
.marquee.is-running .marquee__list { flex-wrap: nowrap; }
.marquee.is-running .marquee__list[aria-hidden="true"] { display: flex; }
.marquee.is-running .marquee__list li { font-size: clamp(2.5rem, 6.4vw, 6rem); line-height: 1.1; }

/* ---------- 14. Savoir-faire ---------- */
.pillars {
  position: relative;
  background: var(--graphite);
  color: var(--blanc);
  padding: clamp(80px, 13vh, 150px) var(--gutter) clamp(90px, 15vh, 170px);
}
.pillars__list {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(20px, 3vw, 56px);
  max-width: var(--maxw);
  margin: clamp(48px, 9vh, 100px) auto 0;
  align-items: start;
  perspective: 1200px;
}
.pillar {
  position: relative;
  padding: clamp(28px, 3vw, 48px);
  border: 1px solid rgba(212, 212, 212, .16);
  transform-style: preserve-3d;
  will-change: transform;
}
.pillar:nth-child(2) { margin-top: clamp(32px, 9vh, 110px); }
.pillar:nth-child(3) { margin-top: clamp(64px, 18vh, 220px); }
.pillar__rule {
  display: block;
  width: 40px;
  height: 1px;
  background: var(--gris-clair);
  transform-origin: left center;
}
.pillar__title {
  margin-top: 28px;
  font: 400 clamp(1.75rem, 2.7vw, 2.625rem)/1.08 var(--font-display);
  transform: translateZ(28px);
}
.pillar__text {
  margin-top: 18px;
  font: 300 1.0625rem/1.65 var(--font-body);
  color: var(--gris-clair);
  max-width: 32ch;
  transform: translateZ(14px);
}

/* ---------- 15. Contact ---------- */
.contact {
  position: relative;
  margin-top: -1px; /* covers the sub-pixel seam under the grey-scale fade */
  background: var(--blanc);
  color: var(--anthracite);
  padding: clamp(40px, 8vh, 96px) var(--gutter) clamp(96px, 16vh, 180px);
}
.contact__grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(48px, 8vw, 140px);
  max-width: var(--maxw);
  margin: clamp(48px, 9vh, 100px) auto 0;
}
.contact__lead { font: 400 clamp(2.25rem, 4.6vw, 4.25rem)/1.05 var(--font-display); max-width: 12ch; }
.contact__details { margin-top: clamp(32px, 6vh, 56px); }
.contact__details > div {
  display: grid;
  grid-template-columns: minmax(96px, 30%) 1fr;
  gap: 16px;
  align-items: baseline;
  padding: 16px 0;
  border-top: 1px solid var(--gris-clair);
}
.contact__details dt {
  font: 600 11px/1.4 var(--font-ui);
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--gris-cendre);
}
.contact__details dd { font: 400 1.0625rem/1.5 var(--font-body); }
.contact__details a { text-decoration: none; background: linear-gradient(currentColor, currentColor) left bottom / 100% 1px no-repeat; }

.form { display: grid; align-content: start; }
.field { margin-bottom: 26px; }
.field__label {
  display: block;
  margin-bottom: 8px;
  font: 600 11px/1.4 var(--font-ui);
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--gris-cendre);
  transition: color 240ms var(--ease-out);
}
.field__control { position: relative; display: block; }
.field__control::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 2px;
  background: var(--anthracite);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 520ms var(--ease-out);
}
.field__input {
  display: block;
  width: 100%;
  padding: 10px 0 12px;
  border: 0;
  border-bottom: 1px solid #8A8A8A;
  border-radius: 0;
  background: transparent;
  color: var(--anthracite);
  font: 400 1.0625rem/1.5 var(--font-body);
  outline: none;
  -webkit-appearance: none;
  appearance: none;
}
.field__input--area { resize: vertical; min-height: 112px; }
.field:focus-within .field__control::after,
.field.is-invalid .field__control::after { transform: scaleX(1); }
.field:focus-within .field__label { color: var(--anthracite); }
.field__error {
  min-height: 1.4em;
  margin-top: 8px;
  font: 400 .8125rem/1.4 var(--font-body);
  font-style: italic;
  color: var(--anthracite);
}
.form__actions { display: flex; flex-wrap: wrap; align-items: center; gap: 18px 28px; margin-top: 8px; }
.form__helper { font: 300 .9375rem/1.5 var(--font-body); color: var(--gris-cendre); }
.form__status { min-height: 1.5em; margin-top: 18px; font: 400 .9375rem/1.5 var(--font-body); }
.form__legal { margin-top: 10px; font: 300 .8125rem/1.6 var(--font-body); color: var(--gris-cendre); }

.btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 56px;
  padding: 0 34px;
  overflow: hidden;
  border: 1px solid var(--anthracite);
  border-radius: 0;
  background: var(--anthracite);
  color: var(--blanc);
  font: 600 12px/1 var(--font-ui);
  letter-spacing: .2em;
  text-transform: uppercase;
  white-space: nowrap;
  cursor: pointer;
  transition: transform 160ms var(--ease-out);
}
.btn::before {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--blanc);
  transform: translate3d(0, 101%, 0);
  transition: transform 460ms var(--ease-out);
}
.btn__label { position: relative; transition: color 300ms var(--ease-out); }
@media (hover: hover) and (pointer: fine) {
  .btn:hover::before { transform: none; }
  .btn:hover .btn__label { color: var(--anthracite); }
}
.btn:active { transform: scale(.97); }
.btn:focus-visible { outline-color: var(--anthracite); }
.btn[aria-busy="true"] { opacity: .7; pointer-events: none; }

.linkish {
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
  cursor: pointer;
}

/* ---------- 16. Footer ---------- */
.footer {
  position: relative;
  background: var(--graphite);
  color: var(--blanc);
  padding: clamp(88px, 14vh, 160px) var(--gutter) 28px;
}
.footer__brand { display: flex; justify-content: center; }
.footer__logo {
  width: clamp(220px, 24vw, 340px);
  height: auto;
  aspect-ratio: 390.9 / 114.1;
  fill: var(--blanc);
  margin: 24px;
}
.footer__grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 40px 32px;
  max-width: var(--maxw);
  margin: clamp(64px, 11vh, 120px) auto 0;
  padding-top: 40px;
  border-top: 1px solid rgba(212, 212, 212, .22);
}
.fcol--wide { grid-column: span 2; }
.fcol__label {
  margin-bottom: 12px;
  font: 600 11px/1.4 var(--font-ui);
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--gris-clair);
}
.fcol p:not(.fcol__label), .fcol address, .fcol li { font: 300 1rem/1.7 var(--font-body); }
.footer a {
  text-decoration: none;
  background: linear-gradient(currentColor, currentColor) left bottom / 0 1px no-repeat;
  transition: background-size 420ms var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .footer a:hover { background-size: 100% 1px; }
}
.footer__bar {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: 16px 32px;
  max-width: var(--maxw);
  margin: clamp(56px, 9vh, 96px) auto 0;
  padding-top: 22px;
  border-top: 1px solid rgba(212, 212, 212, .22);
  font: 400 .8125rem/1.5 var(--font-body);
  color: var(--gris-clair);
}
.footer__legal { display: flex; flex-wrap: wrap; gap: 8px 28px; }
.footer__legal .linkish { text-decoration: none; min-height: 44px; }
/* The footer's links are lines of small text (16-20 px high): an invisible margin around each makes it at
   least 24 px for a finger, without moving anything (25.10.2026). */
.fcol a, .footer__legal a { position: relative; }
.fcol a::before, .footer__legal a::before { content: ""; position: absolute; inset: -3px -2px; }
.footer__legal a::before { inset: -5px -2px; }
@media (hover: hover) and (pointer: fine) {
  .footer__legal .linkish:hover { text-decoration: underline; }
}

/* ---------- 17. Legal dialogs ---------- */
.dialog {
  width: min(720px, calc(100vw - 32px));
  max-height: min(84vh, 760px);
  padding: 0;
  border: 0;
  background: var(--blanc);
  color: var(--anthracite);
}
.dialog::backdrop { background: rgba(44, 46, 53, .76); }
.dialog[open] { animation: dialog-in 420ms var(--ease-out); }
@keyframes dialog-in { from { opacity: 0; transform: translate3d(0, 16px, 0) scale(.98); } }
.dialog__inner { display: flex; flex-direction: column; max-height: inherit; }
.dialog__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 22px 28px;
  border-bottom: 1px solid var(--gris-clair);
}
.dialog__title {
  font: 800 1rem/1.2 var(--font-ui);
  letter-spacing: .16em;
  text-transform: uppercase;
}
.dialog__close {
  min-height: 44px;
  padding: 0 4px;
  border: 0;
  background: none;
  font: 600 11px/1 var(--font-ui);
  letter-spacing: .2em;
  text-transform: uppercase;
  cursor: pointer;
}
.dialog__body { overflow: auto; padding: 8px 28px 32px; font: 300 1rem/1.7 var(--font-body); }
.dialog__body h3 {
  margin: 26px 0 8px;
  font: 700 11px/1.4 var(--font-ui);
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--gris-cendre);
}
.dialog__body p + p { margin-top: 12px; }
/* Legal notice: label and value side by side; on a narrow screen the value
   wraps under its label (flex-wrap, so no media query is needed). */
.legal-list { margin: 0; }
.legal-list > div { display: flex; flex-wrap: wrap; column-gap: 20px; padding: 3px 0; }
.legal-list dt { flex: 0 0 13em; font-weight: 500; }
.legal-list dd { flex: 1 1 16em; min-width: 0; margin: 0; overflow-wrap: anywhere; }

/* The page mentions-legales.html: the same texts and lists in a calm column
   under the site's section heads (sizes are fluid, so no media query). */
.legalpage {
  padding: clamp(120px, 18vh, 200px) var(--gutter) clamp(80px, 12vh, 140px);
  background: var(--blanc);
  color: var(--anthracite);
}
.legalpage .shead { scroll-margin-top: clamp(96px, 14vh, 140px); }
.legalpage .shead + .legalpage__body { margin-top: clamp(28px, 4vh, 44px); }
.legalpage__body + .shead { margin-top: clamp(72px, 11vh, 120px); }
.legalpage__body {
  max-width: 760px;
  margin-inline: auto;
  font: 300 1rem/1.7 var(--font-body);
}
.legalpage__body h3 {
  margin: 34px 0 10px;
  font: 700 11px/1.4 var(--font-ui);
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--gris-cendre);
}
.legalpage__body h3:first-child { margin-top: 0; }
.legalpage__body p + p { margin-top: 12px; }
.legalpage__body a { color: inherit; text-underline-offset: 3px; text-decoration-thickness: 1px; }

/* ---------- 18. Cursor + grain ---------- */
.cursor, .cursor-ring { display: none; }
@media (hover: hover) and (pointer: fine) {
  html.has-cursor .cursor,
  html.has-cursor .cursor-ring {
    display: block;
    position: fixed;
    left: 0;
    top: 0;
    z-index: var(--z-cursor);
    pointer-events: none;
    color: var(--blanc);
    will-change: transform;
    transition: color 300ms var(--ease-out), opacity 200ms var(--ease-out);
  }
  html.has-cursor[data-ui="light"] .cursor,
  html.has-cursor[data-ui="light"] .cursor-ring { color: var(--anthracite); }
  html.has-cursor .cursor { width: 6px; height: 6px; margin: -3px 0 0 -3px; border-radius: 50%; background: currentColor; }
  html.has-cursor .cursor-ring { width: 40px; height: 40px; margin: -20px 0 0 -20px; }
  .cursor-ring svg {
    width: 100%;
    height: 100%;
    overflow: visible;
    transition: transform 420ms var(--ease-out);
  }
  .cursor-ring circle { fill: currentColor; fill-opacity: 0; stroke: currentColor; stroke-width: 1; transition: fill-opacity 300ms var(--ease-out), stroke-opacity 300ms var(--ease-out); }
  .cursor-ring__label {
    position: absolute;
    inset: 0;
    display: grid;
    place-items: center;
    padding-left: .2em; /* the tracking after the last letter, so the word sits centred */
    font: 600 8px/1 var(--font-ui);
    letter-spacing: .2em;
    text-transform: uppercase;
    opacity: 0;
    transition: opacity 240ms var(--ease-out);
  }
  html.has-cursor[data-cursor="link"] .cursor-ring svg { transform: scale(1.5); }
  html.has-cursor[data-cursor="link"] .cursor { opacity: 0; }
  /* Over a photograph: a small smoked disc with the word in white. It only
     ever sits on pictures, so it does not follow the page's light or dark
     theme, and it stays small enough to leave the picture visible (56 px). */
  html.has-cursor[data-cursor="view"] .cursor-ring { color: var(--blanc); }
  html.has-cursor[data-cursor="view"] .cursor-ring svg { transform: scale(1.4); }
  html.has-cursor[data-cursor="view"] .cursor-ring circle { fill: #17181c; fill-opacity: .34; stroke-opacity: .62; }
  html.has-cursor[data-cursor="view"] .cursor-ring__label { opacity: .92; }
  html.has-cursor[data-cursor="view"] .cursor { opacity: 0; }
  html.has-cursor[data-cursor="text"] .cursor,
  html.has-cursor[data-cursor="text"] .cursor-ring,
  html.has-cursor.cursor-out .cursor,
  html.has-cursor.cursor-out .cursor-ring { opacity: 0; }

  /* The system pointer is replaced over imagery and controls only. Over running
     text and form fields the native cursor stays (caret, I-beam). */
  html.has-cursor body,
  html.has-cursor a,
  html.has-cursor button,
  html.has-cursor [data-cursor] { cursor: none; }
  html.has-cursor input,
  html.has-cursor textarea,
  html.has-cursor p,
  html.has-cursor dd,
  html.has-cursor address,
  html.has-cursor blockquote,
  html.has-cursor dialog { cursor: auto; }
  html.has-cursor dialog a,
  html.has-cursor dialog button { cursor: pointer; }
  html.has-cursor .film__chapters p,
  html.has-cursor .tile p,
  html.has-cursor .estate__visual p { cursor: none; }
}

.grain {
  position: fixed;
  inset: -12%;
  z-index: var(--z-grain);
  pointer-events: none;
  background: url("assets/img/grain.webp") repeat;
  background-size: 160px 160px;
  opacity: .032;
}
@media (hover: hover) and (pointer: fine) {
  .grain { animation: grain 900ms steps(5) infinite; }
}
@keyframes grain {
  0% { transform: translate3d(0, 0, 0); }
  20% { transform: translate3d(-4%, 3%, 0); }
  40% { transform: translate3d(3%, -5%, 0); }
  60% { transform: translate3d(-6%, -2%, 0); }
  80% { transform: translate3d(5%, 4%, 0); }
  100% { transform: translate3d(-2%, 6%, 0); }
}

/* ---------- 19. Motion states set by script ---------- */
/* The tagline is the LCP element: it starts dimmed, never invisible, so it
   counts as painted on the first frame and the entrance only lifts it. */
html.js-pending .hero__scroll { opacity: 0; }
html.js-pending .hero__logo,
html.js-pending [data-hero-line] { opacity: .22; translate: 0 14px; }
/* Scroll scenes are coming. Reserve the film's scroll length from the first
   paint (no layout jump when main.js arrives, and the lazy images further down
   stay far away) and skip the storyboard stills. */
html.motion-ok .chapter__still { display: none; }
html.motion-ok .film__track { min-height: calc(var(--film-screens, 16) * 100svh); }
@media (max-width: 899px) {
  html.motion-ok .film__track { min-height: calc(var(--film-screens, 13.5) * 100svh); }
}
.gallery.is-pinned { padding-bottom: 0; }
html.js-motion [data-reveal],
html.js-motion [data-reveal-group] > * { will-change: transform, opacity; }

/* ---------- 20. Responsive ---------- */
@media (max-width: 899px) {
  :root { --header-h: 80px; }

  .presenter__stage {
    grid-template-columns: 1fr;
    grid-template-areas: "head" "figure" "mosaic" "caption";
  }
  .presenter__figure { max-width: 240px; }
  .mosaic {
    grid-template-columns: 1fr 1fr;
    grid-template-rows: repeat(4, 1fr);
    height: clamp(560px, 120vw, 900px);
  }
  .tile--b { grid-column: 1 / 3; grid-row: 1; }
  .tile--c { grid-column: 1; grid-row: 2 / 4; }
  .tile--d { grid-column: 2; grid-row: 2; }
  .tile--e { grid-column: 2; grid-row: 3; }
  .tile--f { grid-column: 1; grid-row: 4; }
  .tile--g { grid-column: 2; grid-row: 4; }

  .presenter.is-live .presenter__figure { height: 66svh; margin-left: calc(66svh * -0.1726); }
  .presenter.is-live .mosaic {
    left: var(--gutter);
    right: var(--gutter);
    top: calc(var(--header-h) + 64px);
    bottom: calc(5svh + 56px);
  }
  .presenter.is-live .presenter__caption { top: auto; left: var(--gutter); right: var(--gutter); bottom: 3svh; max-width: none; }
  .presenter.is-live .presenter__caption span { display: inline; margin-right: 10px; font-size: 1.375rem; }

  .film.is-scrub .chapter__body { bottom: 112px; }
  .film.is-scrub .chapter__body--quote { max-width: none; }
  /* the logo and the button stay in the middle: the rule above, as specific and later, had pulled them down
     onto the chapter name and timecode at the foot of the screen (found 14.10.2026) */
  .film.is-scrub .chapter__body--finale { bottom: 50%; }
  .film { --pin-size: 12.5px; }
  .film.is-scrub .film__rail {
    flex-direction: row;
    top: auto;
    right: var(--gutter);
    left: var(--gutter);
    bottom: 22px;
    width: auto;
    height: 16px;
    transform: none;
  }
  .rail__seg { flex-direction: row; align-items: flex-end; padding: 0 3px; }
  /* along the foot of a phone the rail is 16 px tall: the finger gets 44 px (above it, not over the edge) */
  .rail__seg::before { inset: -24px 0 -4px 0; }
  .rail__name { display: none; }
  .rail__tick { width: 1px; height: 6px; }
  .rail__tick:first-child { width: 1px; height: 14px; }
  .rail__head { top: auto; bottom: 0; right: auto; left: 0; width: 1px; height: 20px; }
  .film.is-scrub .film__hud { right: auto; left: var(--gutter); bottom: 54px; }
  .film.is-scrub .film__loader { left: auto; right: var(--gutter); bottom: 54px; }

  .villa { grid-template-columns: 1fr; align-items: start; gap: 28px; }
  .specs { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .estate--wide, .estates__pair { grid-template-columns: 1fr; }
  .estates__pair .estate:last-child { margin-top: 0; }
  .pillars__list { grid-template-columns: 1fr; }
  .pillar:nth-child(2), .pillar:nth-child(3) { margin-top: 0; }

  .capsule { padding: 4px; }
  .nav a, .nav__label { padding: 10px 12px; letter-spacing: .12em; }
  .daynight { --dn-w: 60px; --dn-h: 36px; --dn-knob: 28px; --dn-goal: 11px; }
  .daynight__faces { width: 18px; height: 18px; }

  .contact__grid { grid-template-columns: 1fr; }
  .footer__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* A switch needs a track to travel along, and a phone's bar has no room for
   one (at 430 px the three links, the language and a 60 px track are 20 px too
   many). So on a phone it steps out of the capsule and sits just under its
   right end, over the first screen — the only place where it has anything to
   do. It leaves with the first scroll and comes back at the top.
   (Placed from the capsule: a backdrop-filter makes an element the containing
   block of whatever is positioned inside it.) */
@media (max-width: 640px) {
  .daynight {
    position: absolute;
    right: -1px;
    top: calc(100% + 9px);
    transition: background 320ms var(--ease-out), border-color 320ms var(--ease-out), opacity 320ms var(--ease-out), visibility 0s linear 0s;
  }
  /* It also steps aside while a list of the capsule is open: the lists drop
     into the very place where it sits. */
  .site-header.is-floating .daynight,
  .capsule:has(.is-open) .daynight {
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition: opacity 240ms var(--ease-out), visibility 0s linear 240ms;
  }
}

@media (max-width: 560px) {
  .shead { flex-wrap: wrap; row-gap: 10px; }
  .shead__rule { flex-basis: 40px; }
  .shead__label { flex-basis: 100%; text-align: right; }
  /* Three links instead of five leaves room for the monogram on every phone:
     the capsule takes what is left of the row and shares it between them. */
  .site-header { gap: 8px; }
  .capsule { flex: 1 1 auto; min-width: 0; }
  .nav { flex: 1 1 auto; }
  .nav > ul { justify-content: space-between; }
  .nav a, .nav__label { font-size: 10px; padding: 11px 8px; letter-spacing: .06em; }
  .nav__label { gap: 4px; }
  .nav__label svg { width: 9px; height: 9px; }
  .nav__more { width: 24px; height: 26px; margin-left: -9px; }
  .capsule__rule { height: 18px; }
  .submenu { min-width: 176px; }
  .footer__grid { grid-template-columns: 1fr; }
  .fcol--wide { grid-column: auto; }
  .contact__details > div { grid-template-columns: 1fr; gap: 4px; }
  .btn { width: 100%; }
}

/* ---------- 21. Reduced motion ---------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    scroll-behavior: auto !important;
  }
  .hero__scroll span { transform: none; }
  .blob, .motes { display: none; }
  .tile__img, .tile__alt, .shot__frame img, .estate__figure { transition: none; }
  .tile__cap, .shot__cap span, .estate__slide { transition: opacity 300ms ease; }
  .tile:hover .tile__img, .shot:hover .shot__frame img, .estate__visual:hover .estate__figure { transform: none; }
  .grain { animation: none; }
  /* the switch changes ends at once: its position is a state, not a movement */
  .daynight__knob { transition: none; }
  .daynight:not(.is-busy):hover .daynight__knob,
  .daynight[data-state="jour"]:not(.is-busy):hover .daynight__knob { translate: none; }
}

/* ---------- 22. Du tracé: the two drawings, annotated ---------- */
/* Static layout (no JavaScript, or prefers-reduced-motion): the two pictures
   with their notes underneath, the buttons opening the same sheets. */
.trace__notes {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: clamp(20px, 3vw, 44px);
  margin-top: clamp(24px, 4vh, 44px);
}
.plannote { max-width: 34ch; }
.plannote__level {
  font: 600 11px/1 var(--font-ui);
  letter-spacing: .24em;
  text-transform: uppercase;
  color: var(--gris-cendre);
}
.plannote__title {
  margin-top: 12px;
  font: 400 clamp(1.5rem, 2.4vw, 2.125rem)/1.1 var(--font-display);
}
.plannote__text {
  margin-top: 12px;
  font: 300 1rem/1.6 var(--font-body);
  color: var(--gris-cendre);
}
.plannote__btn {
  margin-top: 18px;
  padding: 13px 22px;
  border: 1px solid rgba(50, 51, 49, .28);
  border-radius: 999px;
  background: rgba(255, 255, 255, .72);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  color: var(--anthracite);
  font: 600 11px/1 var(--font-ui);
  letter-spacing: .14em;
  text-transform: uppercase;
  white-space: nowrap;
  cursor: pointer;
  transition: border-color 300ms var(--ease-out), background-color 300ms var(--ease-out), color 300ms var(--ease-out), scale 260ms var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .plannote__btn:hover { border-color: var(--bleu); background: var(--blanc); color: var(--bleu); scale: 1.03; }
}
.plannote__btn:active { scale: .98; }

/* Scrubbed layout: the notes float in the white margin beside the drawing.
   Their coordinates come from the positionsByTime table in main.js and are
   written on the element, so moving a note is one number in that table. */
.trace.is-scrub .trace__notes {
  position: absolute;
  inset: 0;
  display: block;
  margin: 0;
  z-index: 2;
  pointer-events: none;
}
/* --plan-left / --plan-right are written by main.js: they are the real edges
   of the drawing inside the frame, whatever the window's shape. The note takes
   the margin beside it, and never lands on the plan. */
.trace.is-scrub .plannote {
  position: absolute;
  --note-gap: clamp(20px, 2.4vw, 40px);
  top: var(--note-y, 20%);
  max-width: none;
  opacity: 0;
  translate: 0 16px;
  /* Hidden for the keyboard as well as the eye: the note only becomes
     visible (and its button reachable) while its drawing is on screen. */
  visibility: hidden;
  transition:
    opacity 420ms var(--ease-out),
    translate 460ms var(--ease-out),
    left 520ms var(--ease-strong),
    top 520ms var(--ease-strong),
    visibility 0s linear 460ms;
}
.trace.is-scrub .plannote.is-on {
  opacity: 1;
  translate: 0 0;
  visibility: visible;
  transition-delay: 0s;
}
.trace.is-scrub .plannote[data-side="left"] {
  right: calc(100% - var(--plan-left, 32%) + var(--note-gap));
  left: auto;
  width: min(320px, calc(var(--plan-left, 32%) - var(--note-gap) - 4px));
}
.trace.is-scrub .plannote[data-side="right"] {
  left: calc(var(--plan-right, 68%) + var(--note-gap));
  right: auto;
  width: min(320px, calc(100% - var(--plan-right, 68%) - var(--note-gap) - 4px));
}
/* Too little white beside the drawing (a short, wide window): both notes drop
   under it, exactly as they do on a phone. */
.trace.is-scrub .trace__notes.is-tight .plannote,
.trace.is-scrub .trace__notes.is-tight .plannote[data-side="left"],
.trace.is-scrub .trace__notes.is-tight .plannote[data-side="right"] {
  left: 0;
  right: 0;
  top: auto;
  bottom: 0;
  width: auto;
  max-width: 46ch;
}
.trace.is-scrub .trace__notes.is-tight .plannote__text { display: none; }
/* The note itself never eats the pointer — the frame below keeps reacting to
   the mouse — but its button does, with its own hover. */
.trace.is-scrub .plannote__btn { pointer-events: auto; }
.trace.is-scrub .plannote__title { font-size: clamp(1.375rem, 2vw, 1.875rem); }
.trace.is-scrub .plannote__text { font-size: .9375rem; }

/* The drawing is line art: a touch more contrast makes the strokes bite on a
   screen without turning the photograph at the other end of the clip harsh. */
.trace.is-scrub .trace__canvas {
  filter: contrast(1.05) brightness(1.02);
  transform: translate3d(var(--trace-x, 0px), var(--trace-y, 0px), 0);
  will-change: transform;
}

/* ---------- 23. The plan sheet, full size ---------- */
.planmodal {
  width: min(1240px, 94vw);
  max-width: none;
  height: min(88svh, 900px);
  max-height: none;
  padding: 0;
  border: 0;
  border-radius: 20px;
  background: var(--blanc);
  color: var(--anthracite);
  box-shadow: 0 60px 140px -60px rgba(0, 0, 0, .6);
}
.planmodal::backdrop { background: rgba(20, 21, 24, .68); }
.planmodal__inner {
  display: grid;
  grid-template-rows: auto minmax(0, 1fr) auto;
  height: 100%;
}
.planmodal__head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 24px;
  padding: clamp(18px, 3vw, 28px) clamp(18px, 3vw, 32px) 14px;
  border-bottom: 1px solid var(--gris-clair);
}
.planmodal__level {
  font: 600 11px/1 var(--font-ui);
  letter-spacing: .24em;
  text-transform: uppercase;
  color: var(--gris-cendre);
}
.planmodal__title { margin-top: 8px; font: 400 clamp(1.5rem, 2.6vw, 2.25rem)/1.05 var(--font-display); }
.planmodal__tools { display: flex; align-items: center; gap: 8px; }
.planmodal__zoom, .planmodal__close {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  padding: 0;
  border: 1px solid rgba(50, 51, 49, .2);
  border-radius: 50%;
  background: transparent;
  font: 400 20px/1 var(--font-ui);
  cursor: pointer;
  transition: border-color 260ms var(--ease-out), background-color 260ms var(--ease-out), color 260ms var(--ease-out), scale 220ms var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .planmodal__zoom:hover, .planmodal__close:hover { border-color: var(--bleu); color: var(--bleu); scale: 1.06; }
}
.planmodal__close { font-size: 24px; }
.planmodal__ratio {
  min-width: 5ch;
  text-align: center;
  font: 600 11px/1 var(--font-ui);
  letter-spacing: .12em;
  color: var(--gris-cendre);
}
.planmodal__viewport {
  position: relative;
  overflow: hidden;
  touch-action: none;
  cursor: grab;
  background: var(--gris-clair-20);
}
.planmodal__viewport.is-dragging { cursor: grabbing; }
.planmodal__img {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 100%;
  max-width: none;
  height: auto;
  transform-origin: 0 0;
  translate: -50% -50%;
  user-select: none;
  -webkit-user-drag: none;
}
.planmodal__hint {
  padding: 12px clamp(18px, 3vw, 32px) clamp(16px, 2.6vw, 24px);
  font: 300 .8125rem/1.5 var(--font-body);
  color: var(--gris-cendre);
}

/* ---------- 24. Savoir-faire, the cascade ---------- */
.pillars { overflow: clip; isolation: isolate; }
/* A very faint grain that breathes, so the dark field is never quite flat. */
.pillars__grain {
  position: absolute;
  inset: 0;
  z-index: 0;
  background-image: url("assets/img/grain.webp");
  background-size: 180px 180px;
  opacity: .04;
  mix-blend-mode: overlay;
  pointer-events: none;
  animation: pillarsBreathe 11s ease-in-out infinite;
}
@keyframes pillarsBreathe {
  0%, 100% { opacity: .03; }
  50% { opacity: .075; }
}
/* Phones go without it: a blended layer that never stops breathing is blended again by Safari at every frame,
   over the whole section and under the cards moving with the scroll (iPhone, 25.10.2026). At 4 % it is
   hardly seen on a phone. */
@media (hover: none), (pointer: coarse) {
  .pillars__grain { display: none; }
}
/* A soft patch of light that trails the cursor with inertia (main.js). */
.pillars__glow {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 0;
  width: 52vmax;
  height: 52vmax;
  margin: -26vmax 0 0 -26vmax;
  border-radius: 50%;
  background: radial-gradient(circle closest-side, rgba(232, 224, 210, .16), rgba(232, 224, 210, 0) 70%);
  opacity: 0;
  pointer-events: none;
  transform: translate3d(var(--glow-x, 50vw), var(--glow-y, 40vh), 0);
  transition: opacity 700ms var(--ease-out);
  will-change: transform;
}
.pillars.is-lit .pillars__glow { opacity: 1; }
.pillars > .shead, .pillars__list, .pillars > .fade { position: relative; z-index: 1; }
/* Letters of the title, split by the script. */
.shead__title .ltr { display: inline-block; white-space: pre; will-change: transform, opacity, filter; }

.pillar {
  background: rgba(255, 255, 255, .012);
  transition:
    border-color 420ms var(--ease-out),
    box-shadow 520ms var(--ease-out),
    translate 420ms var(--ease-out);
}
.pillar__rule { transition: width 460ms var(--ease-strong), background-color 420ms var(--ease-out); }
.pillar__title { transition: color 420ms var(--ease-out); }
/* What each card speaks of, shown above its words: the materials, the
   drawing, the place. The picture fills the top of the card to its border.
   It is a little taller than its frame, so it can drift inside it as the
   section passes (main.js), and it waits behind a curtain that the scroll
   lifts — --veil, 0 without the script, so the picture is simply there. */
.pillar { --pad: clamp(28px, 3vw, 48px); padding: var(--pad); }
.pillar__media {
  position: relative;
  margin: calc(var(--pad) * -1) calc(var(--pad) * -1) clamp(26px, 2.6vw, 38px);
  aspect-ratio: 4 / 5;
  overflow: clip;
  background: #22242a; /* the plate of the drawing; also what shows while a photograph loads */
}
.pillar__img {
  position: absolute;
  left: 0;
  top: -6%;
  width: 100%;
  max-width: none;
  height: 112%;
  object-fit: cover;
  transition: scale 1200ms var(--ease-out);
  will-change: transform;
}
.pillar__media::after {
  content: "";
  position: absolute;
  inset: -1px;
  background: var(--graphite);
  transform-origin: 50% 0;
  transform: scaleY(var(--veil, 0));
  pointer-events: none;
}
.pillar__rule { margin-top: 0; }
@media (hover: hover) and (pointer: fine) {
  .pillar:hover {
    border-color: rgba(232, 224, 210, .48);
    translate: 0 -4px;
    box-shadow: 0 30px 70px -34px rgba(0, 0, 0, .9);
  }
  .pillar:hover .pillar__rule { width: 48px; background: var(--creme); }
  .pillar:hover .pillar__title { color: var(--creme); }
  .pillar:hover .pillar__img { scale: 1.045; }
}
@media (max-width: 899px) {
  .pillar__media { aspect-ratio: 1 / 1; }
}
@media (prefers-reduced-motion: reduce) {
  .pillar__img { transition: none; }
  .pillar:hover .pillar__img { scale: none; }
}

/* ---------- 25. Inner pages: shell ---------- */
.page {
  padding: calc(var(--header-h) + clamp(28px, 6vh, 64px)) 0 0;
  background: var(--gris-clair-20);
  color: var(--anthracite);
}
.page__head {
  max-width: var(--maxw);
  margin-inline: auto;
  padding: clamp(24px, 6vh, 72px) var(--gutter) clamp(28px, 5vh, 56px);
}
.page__eyebrow {
  font: 600 11px/1 var(--font-ui);
  letter-spacing: .26em;
  text-transform: uppercase;
  color: var(--gris-cendre);
}
.page__title {
  margin-top: clamp(14px, 2vh, 24px);
  font: 400 clamp(2.5rem, 6.4vw, 5rem)/1.02 var(--font-display);
  letter-spacing: -.01em;
}
.page__lead {
  margin-top: clamp(16px, 2.4vh, 28px);
  max-width: 58ch;
  font: 300 clamp(1.0625rem, 1.5vw, 1.25rem)/1.65 var(--font-body);
  color: var(--gris-cendre);
}
.page__back {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin-top: clamp(20px, 3vh, 32px);
  font: 600 11px/1 var(--font-ui);
  letter-spacing: .18em;
  text-transform: uppercase;
  text-decoration: none;
}
.page__back::before { content: ""; width: 26px; height: 1px; background: currentColor; transition: width 360ms var(--ease-out); }
@media (hover: hover) and (pointer: fine) {
  .page__back:hover::before { width: 42px; }
}

/* ---------- 26. Contact page ---------- */
.contactpage {
  position: relative;
  min-height: 100svh;
  padding: calc(var(--header-h) + clamp(28px, 6vh, 72px)) var(--gutter) clamp(72px, 12vh, 140px);
  background: var(--gris-clair-20);
  color: var(--anthracite);
  overflow: clip;
}
/* The decorative blur behind the card: the one colour the charte names
   (#2E5895) at low opacity, warmed by a second, paler tone. */
.contactpage__blur {
  position: absolute;
  right: -14vmax;
  bottom: -18vmax;
  width: 62vmax;
  height: 62vmax;
  border-radius: 50%;
  background:
    radial-gradient(circle at 38% 34%, rgba(46, 88, 149, .26), rgba(46, 88, 149, 0) 62%),
    radial-gradient(circle at 70% 68%, rgba(150, 197, 186, .3), rgba(150, 197, 186, 0) 60%);
  filter: blur(46px);
  pointer-events: none;
}
.contactpage__grid {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: clamp(28px, 4vw, 0px);
  max-width: var(--maxw);
  margin-inline: auto;
}
.card {
  position: relative;
  z-index: 1;
  padding: clamp(28px, 4vw, 56px);
  border-radius: 24px;
  background: var(--blanc);
  box-shadow: 0 40px 90px -46px rgba(24, 26, 32, .46), 0 2px 10px -4px rgba(24, 26, 32, .1);
}
.card__title { font: 400 clamp(2rem, 4vw, 3rem)/1.05 var(--font-display); }
/* split by main.js for its arrival, letter by letter, inside whole words */
.card__sub {
  margin-top: 12px;
  max-width: 46ch;
  font: 300 1rem/1.65 var(--font-body);
  color: var(--gris-cendre);
}

/* Rounded fields, the site's type, the charte's blue on focus. */
.cform { margin-top: clamp(22px, 3vw, 34px); display: grid; gap: 18px; }
/* The field only robots fill in (api/contact.php): out of sight and out of the grid. */
.cform__trap { position: absolute; left: -10000px; width: 1px; height: 1px; overflow: hidden; }
.cfield__label {
  display: block;
  margin-bottom: 8px;
  font: 600 11px/1.4 var(--font-ui);
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--gris-cendre);
  transition: color 240ms var(--ease-out);
}
.cfield__input {
  display: block;
  width: 100%;
  padding: 15px 18px;
  border: 1px solid #DCDCDC;
  border-radius: 14px;
  background: var(--blanc);
  color: var(--anthracite);
  font: 400 1rem/1.5 var(--font-body);
  outline: none;
  -webkit-appearance: none;
  appearance: none;
  transition: border-color 260ms var(--ease-out), box-shadow 260ms var(--ease-out);
}
.cfield__input--area { min-height: 132px; resize: vertical; }
.cfield__input:focus { border-color: var(--bleu); box-shadow: 0 0 0 4px rgba(46, 88, 149, .16); }
.cfield:focus-within .cfield__label { color: var(--bleu); }
.cfield.is-invalid .cfield__input { border-color: #B3432F; box-shadow: 0 0 0 4px rgba(179, 67, 47, .12); }
.cfield__error {
  min-height: 1.3em;
  margin-top: 7px;
  font: 400 .8125rem/1.4 var(--font-body);
  font-style: italic;
  color: #8E3423;
}
.cform__actions { display: grid; justify-items: center; gap: 14px; margin-top: 6px; }
.cbtn {
  min-height: 56px;
  padding: 0 40px;
  border: 0;
  border-radius: 999px;
  background: var(--anthracite);
  color: var(--blanc);
  font: 600 12px/1 var(--font-ui);
  letter-spacing: .2em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background-color 300ms var(--ease-out), scale 220ms var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .cbtn:hover { background: var(--bleu); scale: 1.03; }
}
.cbtn:active { scale: .98; }
.cbtn[disabled] { opacity: .55; cursor: default; scale: 1; }
.cform__legal { font: 300 .8125rem/1.6 var(--font-body); color: var(--gris-cendre); text-align: center; }
.cform__status {
  margin-top: clamp(18px, 3vh, 28px);
  text-align: center;
  font: 400 1.0625rem/1.6 var(--font-body);
  opacity: 0;
  translate: 0 10px;
  scale: .96;
  transition: opacity 520ms var(--ease-out), translate 520ms var(--ease-out), scale 520ms var(--ease-out);
}
.cform__status.is-on { opacity: 1; translate: 0 0; scale: 1; }

/* The round window ------------------------------------------------------- */
.portal {
  position: relative;
  z-index: 2;
  width: clamp(260px, 30vw, 420px);
  aspect-ratio: 1;
  margin-left: clamp(-120px, -6vw, -40px);
  perspective: 1200px;
}
.portal__flip {
  position: relative;
  width: 100%;
  height: 100%;
  transform-style: preserve-3d;
  transition: transform 720ms var(--ease-in-out), scale 720ms var(--ease-in-out);
}
.portal.is-flipped .portal__flip { transform: rotateY(180deg); }
.portal.is-turning .portal__flip { scale: 1.05; }
.portal__face {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  overflow: hidden;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  clip-path: circle(50%);
}
.portal__face--back { transform: rotateY(180deg); }
.portal__video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.portal__button {
  position: absolute;
  inset: 0;
  z-index: 3;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: none;
  color: inherit;
  cursor: pointer;
}
.portal__button:focus-visible { outline-color: var(--bleu); outline-offset: 6px; }
/* The ring of ticks. It turns once every 25 s; three neighbouring ticks glow
   and drift around it like a sweep. */
.portal__ring {
  position: absolute;
  /* -12 % of the circle on every side, and the viewBox is 248 units for the
     200 the circle occupies: the ticks stand just outside the video's edge at
     any size. The size is spelled out instead of being solved from the insets,
     because the base rule gives every <svg> max-width: 100 % — which clamped
     the ring back to the size of the circle and left it 29 px off centre, so
     the ring and the video did not line up. */
  left: -12%;
  top: -12%;
  width: 124%;
  height: 124%;
  max-width: none;
  z-index: 1;
  transform-box: border-box;
  transform-origin: 50% 50%;
  pointer-events: none;
  animation: portalSpin 25s linear infinite;
}
.portal__ring line { stroke: rgba(50, 51, 49, .28); stroke-width: 1; stroke-linecap: round; }
.portal__ring .is-lit { stroke: var(--bleu); opacity: .9; }
@keyframes portalSpin { to { transform: rotate(360deg); } }
/* The glow that answers a finished submission. */
.portal__halo {
  position: absolute;
  inset: -6px;
  z-index: 0;
  border-radius: 50%;
  opacity: 0;
  box-shadow: 0 0 0 0 rgba(46, 88, 149, .45);
}
.portal.is-accepting .portal__halo { animation: portalPulse 900ms var(--ease-out); }
@keyframes portalPulse {
  0% { opacity: 1; box-shadow: 0 0 0 0 rgba(46, 88, 149, .5), 0 0 30px 6px rgba(46, 88, 149, .35); }
  100% { opacity: 0; box-shadow: 0 0 0 42px rgba(46, 88, 149, 0), 0 0 60px 20px rgba(46, 88, 149, 0); }
}
/* The back of the coin: the message that was just sent. */
.portal__card {
  display: grid;
  align-content: center;
  gap: 10px;
  width: 100%;
  height: 100%;
  padding: clamp(24px, 4vw, 44px);
  background: var(--anthracite);
  color: var(--blanc);
  text-align: center;
}
.portal__eyebrow {
  font: 600 10px/1 var(--font-ui);
  letter-spacing: .26em;
  text-transform: uppercase;
  color: var(--gris-clair);
}
.portal__name { font: 400 clamp(1.25rem, 2vw, 1.75rem)/1.15 var(--font-display); }
.portal__mail { font: 300 .875rem/1.5 var(--font-body); color: var(--gris-clair); word-break: break-word; }
.portal__msg {
  font: 300 .875rem/1.6 var(--font-body);
  color: var(--gris-clair);
  display: -webkit-box;
  -webkit-line-clamp: 4;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.portal__again {
  justify-self: center;
  margin-top: 8px;
  padding: 8px 16px;
  border: 1px solid var(--glass-on-dark-line);
  border-radius: 999px;
  background: var(--glass-on-dark);
  color: inherit;
  font: 600 10px/1 var(--font-ui);
  letter-spacing: .16em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background-color 260ms var(--ease-out), scale 220ms var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .portal__again:hover { background: var(--glass-on-dark-hi); scale: 1.05; }
}
/* A field being pulled into the portal. The script sets the vector; the
   keyframes do the spiral. */
.cfield.is-spiralling {
  pointer-events: none;
  animation: spiralIn var(--spiral-ms, 850ms) cubic-bezier(.62, .02, .28, 1) var(--spiral-delay, 0ms) forwards;
  will-change: transform, opacity;
}
@keyframes spiralIn {
  0% { transform: translate3d(0, 0, 0) rotate(0deg) scale(1); opacity: 1; }
  55% { transform: translate3d(calc(var(--spiral-x) * .58), calc(var(--spiral-y) * .46), 0) rotate(240deg) scale(.58); opacity: .9; }
  100% { transform: translate3d(var(--spiral-x), var(--spiral-y), 0) rotate(560deg) scale(.04); opacity: 0; }
}

/* The social buttons: the capsule's glass, on the light card. */
.socials { display: flex; align-items: center; gap: 10px; margin-top: clamp(22px, 3vw, 32px); }
.socials__label {
  margin-right: 4px;
  font: 600 11px/1 var(--font-ui);
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--gris-cendre);
}
.social {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  border: 1px solid var(--glass-on-light-line);
  border-radius: 999px;
  background: var(--glass-on-light);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  color: var(--anthracite);
  transition: background-color 300ms var(--ease-out), border-color 300ms var(--ease-out), color 300ms var(--ease-out), scale 260ms var(--ease-out);
}
.social svg { width: 18px; height: 18px; fill: currentColor; }
@media (hover: hover) and (pointer: fine) {
  .social:hover { border-color: var(--bleu); color: var(--bleu); background: var(--glass-on-light-hi); scale: 1.05; }
}
.social:active { scale: .97; }

.contactpage__details {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: clamp(18px, 3vw, 40px);
  max-width: var(--maxw);
  margin: clamp(48px, 8vh, 96px) auto 0;
}
.contactpage__details dt {
  font: 600 11px/1 var(--font-ui);
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--gris-cendre);
}
.contactpage__details dd { margin-top: 10px; font: 300 1.0625rem/1.6 var(--font-body); }
.contactpage__details a { text-decoration: none; border-bottom: 1px solid currentColor; }

/* ---------- 27. Mougins page ---------- */
.mhero {
  position: relative;
  height: min(86svh, 820px);
  min-height: 480px;
  overflow: clip;
  background: var(--graphite);
  color: var(--blanc);
}
.mhero__media, .mhero__media img, .mhero__media video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.mhero__media video { opacity: 0; transition: opacity 800ms var(--ease-out); }
.mhero.is-video .mhero__media video { opacity: 1; }
.mhero__veil {
  position: absolute;
  inset: 0;
  background: linear-gradient(to bottom, rgba(44, 46, 53, .62) 0%, rgba(44, 46, 53, .08) 30%, rgba(44, 46, 53, .34) 56%, rgba(44, 46, 53, .74) 78%, rgba(44, 46, 53, .94) 100%);
}
/* On the photograph the eyebrow has to read light, not grey. */
.mhero__content .page__eyebrow { color: var(--gris-clair); }
.mhero__content {
  position: absolute;
  inset: auto 0 0 0;
  max-width: var(--maxw);
  margin-inline: auto;
  padding: 0 var(--gutter) clamp(36px, 7vh, 80px);
}
.mhero__title { margin-top: 14px; font: 400 clamp(2.75rem, 7vw, 5.5rem)/1 var(--font-display); }
.mhero__place {
  margin-top: 16px;
  font: 600 11px/1.8 var(--font-ui);
  letter-spacing: .26em;
  text-transform: uppercase;
  color: var(--gris-clair);
}
/* A villa that is not built yet says so where it is first seen: one line of small print in the corner of the
   first screen (the full note stands further down the page). */
.mhero__notice {
  position: absolute;
  right: var(--gutter);
  /* a cover taller than the screen (min-height 480 px on a phone held sideways) keeps the line on the screen */
  bottom: max(12px, calc(100% - 100svh + 12px));
  max-width: calc(100% - 2 * var(--gutter));
  font: 600 10px/1.4 var(--font-ui);
  letter-spacing: .16em;
  text-transform: uppercase;
  text-align: right;
  color: var(--gris-clair);
  text-shadow: 0 1px 12px rgba(20, 21, 24, .7);
  pointer-events: none;
}

.mvilla {
  background: var(--blanc);
  color: var(--anthracite);
  padding: clamp(64px, 12vh, 140px) var(--gutter);
}
.mvilla__inner { max-width: var(--maxw); margin-inline: auto; }
.mgrid {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: clamp(14px, 1.6vw, 26px);
  margin-top: clamp(32px, 6vh, 72px);
}
.mshot { position: relative; overflow: clip; }
.mshot img { width: 100%; height: 100%; object-fit: cover; transition: scale 900ms var(--ease-out); }
@media (hover: hover) and (pointer: fine) {
  .mshot:hover img { scale: 1.04; }
}
.mshot--wide { grid-column: span 12; aspect-ratio: 16 / 9; }
.mshot--half { grid-column: span 6; aspect-ratio: 3 / 2; }
.mshot--third { grid-column: span 4; aspect-ratio: 4 / 5; }
.mshot--twothirds { grid-column: span 8; aspect-ratio: 3 / 2; }
.mshot__cap {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: 44px 18px 16px;
  background: linear-gradient(to top, rgba(28, 29, 33, .74), transparent);
  color: var(--blanc);
  font: 600 10px/1.4 var(--font-ui);
  letter-spacing: .2em;
  text-transform: uppercase;
  opacity: 0;
  transition: opacity 360ms var(--ease-out);
}
.mshot:hover .mshot__cap, .mshot:focus-within .mshot__cap { opacity: 1; }
/* Fine print under the pictures, in this order: who drew the project (the names as they stand on the drawings)
   and the sentence the law asks for in an advertisement of a property for sale (Géorisques), then, smallest, the
   note "3D renderings, non-contractual…". A hairline above the group, a reading measure of about 75 characters
   (the note ran the full width of a wide screen inside a box before), and 400 rather than 300 at these sizes so
   the letters stay solid. The grey is the charte's ash lightened by 15 %: about 5:1 on the light sections, still
   above the 4.5:1 that small text needs. */
.mcredit, .mlegal, .mnote {
  max-width: 40rem;
  margin-top: 4px;
  font: 400 .75rem/1.6 var(--font-body);
  color: var(--gris-cendre);
  color: color-mix(in srgb, var(--gris-cendre) 85%, var(--blanc));
  text-wrap: balance;
}
.mnote { font-size: .6875rem; text-wrap: pretty; }
:is(.mcredit, .mlegal) + .mnote { margin-top: 10px; }
/* The first line of the group, whatever it is (:where keeps this rule weaker than the one under the specs). */
:where(:not(.mcredit, .mlegal, .mnote)) + :is(.mcredit, .mlegal, .mnote) {
  margin-top: clamp(28px, 5vh, 48px);
  padding-top: 12px;
  border-top: 1px solid var(--gris-clair);
}
.specs + .mlegal { margin-top: 22px; padding-top: 0; border-top: 0; }
.mlegal a { color: inherit; text-underline-offset: 3px; text-decoration-thickness: 1px; }
.mlegal a:focus-visible { outline: 1px solid var(--bleu); outline-offset: 3px; }
.mambiance { background: var(--gris-clair-20); }
.mpair { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: clamp(20px, 3vw, 48px); align-items: start; margin-top: clamp(32px, 6vh, 64px); }

/* ---------- 28. The narrowest phones ---------- */
@media (max-width: 400px) {
  .site-header { padding: 0 10px; gap: 6px; }
  .brand { width: 62px; height: 62px; }
  .brand__symbol { width: 56px; height: 56px; }
  .nav a, .nav__label { font-size: 9.5px; padding: 11px 6px; letter-spacing: .03em; }
  .nav__label { gap: 3px; }
}
/* 320 px, the oldest phones still in use: the three links and the language
   were 26 px too many for the bar and "Contact" ran under the language. */
@media (max-width: 340px) {
  .site-header { gap: 4px; }
  .brand { width: 58px; height: 58px; }
  .nav a, .nav__label { font-size: 9px; padding: 11px 4px; letter-spacing: 0; }
  .nav__more { width: 24px; margin-left: -8px; }
  .capsule { padding: 3px; gap: 2px; }
}

/* ---------- 29. Responsive and reduced motion, sections 22-28 ----------
   These come last on purpose: they override the base rules a few sections
   above, and a media query carries no extra weight in the cascade. */
@media (max-width: 899px) {
  /* The drawing fills a narrow frame, so the note sits under it, full width. */
  .trace.is-scrub .plannote,
  .trace.is-scrub .plannote[data-side="left"],
  .trace.is-scrub .plannote[data-side="right"] {
    left: 0;
    right: 0;
    top: auto;
    bottom: clamp(8px, 2vh, 20px);
    width: auto;
  }
  .trace.is-scrub .plannote__text { display: none; }
  .trace.is-scrub .plannote__title { font-size: 1.25rem; }
  .trace.is-scrub .plannote__btn { margin-top: 12px; }

  /* The round window moves above the card and tucks under its top edge. */
  .contactpage__grid { grid-template-columns: 1fr; justify-items: center; gap: 0; }
  .portal { order: -1; margin: 0 0 clamp(-44px, -7vw, -20px); }
  .card { width: 100%; }
  .contactpage__blur { right: -30vmax; bottom: -30vmax; }

  .mshot--half, .mshot--third, .mshot--twothirds { grid-column: span 12; }
  .mshot--third { aspect-ratio: 3 / 2; }
  .mhero { height: min(78svh, 720px); }
}

@media (max-width: 560px) {
  .socials { flex-wrap: wrap; row-gap: 12px; }
  .portal { width: clamp(220px, 62vw, 300px); }
}

@media (prefers-reduced-motion: reduce) {
  .portal__ring, .pillars__grain { animation: none; }
  .pillars__glow { display: none; }
  .cfield.is-spiralling { animation: none; opacity: 0; }
  /* No coin flip: the two faces simply cross-fade in place. */
  .portal__flip { transition: none; }
  .portal__face { backface-visibility: visible; transition: opacity 320ms ease; }
  .portal__face--back { transform: none; opacity: 0; }
  .portal.is-flipped .portal__face--front { opacity: 0; }
  .portal.is-flipped .portal__face--back { opacity: 1; }
  .trace.is-scrub .trace__canvas { transform: none; }
  .mshot img { transition: none; }
}

/* ---------- 30. Contact: the villa seen through turning windows ----------
   Wide screens only. One <video> decodes; the canvas paints it once per
   window, each time behind its own clip, so there is a single video stream no
   matter how many windows turn. The ring orbits the card, not the section. */
.portholes { display: none; }
.portholes__canvas { display: block; width: 100%; height: 100%; }
.portholes__src {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  pointer-events: none;
}

/* ---------- 31. The message is on its way ---------- */
.done { display: none; }
.card.is-sent .cform,
.card.is-sent .socials,
.card.is-sent .card__sub { display: none; }
.card.is-sent .done {
  display: grid;
  justify-items: center;
  gap: 14px;
  padding: clamp(22px, 4vw, 44px) 0 clamp(6px, 1vw, 14px);
  text-align: center;
}
.done__mark {
  width: clamp(78px, 9vw, 108px);
  height: auto;
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.done__ring {
  stroke: var(--bleu);
  stroke-width: 2;
  opacity: .45;
  stroke-dasharray: 195;
  stroke-dashoffset: 195;
}
.done__check {
  stroke: var(--bleu);
  stroke-width: 4.5;
  stroke-dasharray: 44;
  stroke-dashoffset: 44;
}
.card.is-sent .done__ring { animation: doneRing 760ms var(--ease-out) forwards; }
.card.is-sent .done__check { animation: doneCheck 460ms var(--ease-out) 500ms forwards; }
.card.is-sent .done__mark { animation: donePop 720ms var(--ease-strong) 620ms; }
@keyframes doneRing { to { stroke-dashoffset: 0; } }
@keyframes doneCheck { to { stroke-dashoffset: 0; } }
@keyframes donePop {
  0%, 100% { scale: 1; }
  42% { scale: 1.07; }
}
.done__title { font: 400 clamp(1.625rem, 2.8vw, 2.25rem)/1.1 var(--font-display); }
.done__text {
  max-width: 42ch;
  font: 300 1rem/1.65 var(--font-body);
  color: var(--gris-cendre);
}
.done__mail { color: var(--anthracite); }
/* Only the mail client was opened: the ring, not a check mark that would
   say the message has already arrived. */
.card.is-mail .done__check { display: none; }
.done__again {
  margin-top: 8px;
  padding: 12px 24px;
  border: 1px solid rgba(50, 51, 49, .22);
  border-radius: 999px;
  background: none;
  color: inherit;
  font: 600 11px/1 var(--font-ui);
  letter-spacing: .16em;
  text-transform: uppercase;
  cursor: pointer;
  transition: border-color 280ms var(--ease-out), color 280ms var(--ease-out), scale 240ms var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .done__again:hover { border-color: var(--bleu); color: var(--bleu); scale: 1.03; }
}

/* ---------- 32. Contact, wide screens ---------- */
@media (min-width: 900px) {
  .contactpage {
    display: grid;
    align-content: center;
    min-height: 100svh;
    background: var(--gris-clair-20);
  }
  .portholes {
    display: block;
    position: absolute;
    inset: 0;
    z-index: 0;
    pointer-events: none;
  }
  /* The windows are bright; the card needs its own weight to sit on top. */
  .contactpage__grid {
    z-index: 1;
    grid-template-columns: minmax(0, 640px);
    justify-content: center;
    gap: 0;
  }
  /* A shade deeper than the page usually is, so the white card reads as a
     sheet laid over the windows rather than a panel of the same paper. */
  .contactpage { background: #EAEAEC; }
  .card {
    background: var(--blanc);
    -webkit-backdrop-filter: blur(10px);
    backdrop-filter: blur(10px);
    box-shadow: 0 70px 130px -60px rgba(20, 22, 28, .6), 0 6px 22px -10px rgba(20, 22, 28, .18);
  }
  /* The round window belongs to the phone layout. */
  .portal { display: none; }
  .contactpage__details { position: relative; z-index: 1; }
  .contactpage__blur { opacity: .7; }
}

@media (prefers-reduced-motion: reduce) {
  /* The check mark is already drawn; nothing sweeps or pops. */
  .card.is-sent .done__ring,
  .card.is-sent .done__check,
  .card.is-sent .done__mark { animation: none; }
  .done__ring, .done__check { stroke-dashoffset: 0; }
}

/* ---------- 23. Languages: the switcher in the capsule, the footer list ---------- */
/* Same glass as the nuit/jour switch, so the capsule keeps one material. The
   list is generated per page by tools/build-i18n.mjs: every link points at the
   same page in the other language, never at the other language's home. */
.lang { position: relative; flex: none; }
.lang__btn {
  display: flex;
  align-items: center;
  gap: 7px;
  height: 40px;
  padding: 0 12px 0 14px;
  border: 1px solid var(--glass-line);
  border-radius: 999px;
  background: var(--glass-bg);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  color: inherit;
  font: 600 11px/1 var(--font-ui);
  letter-spacing: .16em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background 320ms var(--ease-out), border-color 320ms var(--ease-out), scale 320ms var(--ease-out);
}
.lang__btn svg {
  width: 10px;
  height: 10px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: .7;
  transition: rotate 360ms var(--ease-strong);
}
.lang.is-open .lang__btn svg { rotate: 180deg; }
@media (hover: hover) and (pointer: fine) {
  .lang__btn:hover { background: var(--glass-hi); scale: 1.04; }
}
.lang__btn:active { scale: .97; }
.lang__list {
  position: absolute;
  top: calc(100% + 14px);
  right: -6px;
  z-index: 2;
  min-width: 200px;
  padding: 8px;
  border: 1px solid var(--glass-line);
  border-radius: 20px;
  background: var(--glass-panel);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  box-shadow: 0 24px 50px -30px rgba(12, 13, 16, .6);
  opacity: 0;
  visibility: hidden;
  translate: 0 -8px;
  transition: opacity 260ms var(--ease-out), translate 300ms var(--ease-out), visibility 0s linear 300ms;
}
.lang.is-open .lang__list {
  opacity: 1;
  visibility: visible;
  translate: 0 0;
  transition-delay: 0s;
}
.lang.is-open .lang__list li { animation: langIn 420ms var(--ease-strong) both; animation-delay: calc(var(--i, 0) * 32ms); }
@keyframes langIn {
  from { opacity: 0; transform: translate3d(0, -6px, 0); }
}
.lang__list a {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 20px;
  padding: 11px 14px;
  border-radius: 999px;
  font: 500 13px/1 var(--font-body);
  text-decoration: none;
  opacity: .78;
  transition: opacity 260ms var(--ease-out), background-color 260ms var(--ease-out);
}
.lang__list a span {
  font: 600 10px/1 var(--font-ui);
  letter-spacing: .16em;
  opacity: .6;
}
.lang__list a[aria-current] { opacity: 1; background: var(--glass-hi); }
@media (hover: hover) and (pointer: fine) {
  .lang__list a:hover { opacity: 1; background: var(--glass-hi); }
}
.lang__list a:focus-visible { opacity: 1; outline-offset: -3px; }

.footer__langs { display: flex; flex-wrap: wrap; gap: 8px 22px; }
.footer__langs a { display: inline-flex; align-items: center; min-height: 44px; opacity: .72; transition: opacity 300ms var(--ease-out), background-size 420ms var(--ease-out); }
.footer__langs a[aria-current] { opacity: 1; }
@media (hover: hover) and (pointer: fine) {
  .footer__langs a:hover { opacity: 1; }
}

@media (max-width: 899px) {
  .lang__btn { height: 36px; padding: 0 10px 0 12px; }
}
@media (max-width: 560px) {
  /* The capsule already shares a phone's width between three links: the
     switcher keeps only its two letters. */
  .lang__btn { height: 34px; padding: 0 9px; font-size: 10px; letter-spacing: .08em; }
  .lang__btn svg { display: none; }
  .lang__list { right: -4px; min-width: 180px; }
}

/* ---------- 24. Acquérir: the two addresses and the buyer's questions ---------- */
.pillars:has(> .fade) { padding-bottom: 0; }
.buy {
  position: relative;
  background: var(--blanc);
  color: var(--anthracite);
  padding: clamp(24px, 6vh, 72px) var(--gutter) 0;
}
.buy__lead {
  max-width: var(--maxw);
  margin: clamp(28px, 5vh, 56px) auto 0;
  padding-right: clamp(0px, 28vw, 520px);
  font: 400 clamp(1.375rem, 2.4vw, 2.25rem)/1.3 var(--font-display);
  text-wrap: pretty;
}
.places {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(20px, 3vw, 48px);
  max-width: var(--maxw);
  margin: clamp(44px, 8vh, 88px) auto 0;
  perspective: 1400px;
}
.place {
  display: flex;
  flex-direction: column;
  padding: clamp(26px, 3.2vw, 48px);
  border: 1px solid var(--gris-clair);
  background: var(--blanc);
  transition: border-color 420ms var(--ease-out), translate 420ms var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .place:hover { border-color: rgba(50, 51, 49, .42); translate: 0 -4px; }
}
.place__area {
  font: 600 11px/1.4 var(--font-ui);
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--gris-cendre);
}
.place__name { margin-top: 14px; font: 400 clamp(2.25rem, 3.6vw, 3.5rem)/1 var(--font-display); }
.place__text {
  margin-top: 18px;
  max-width: 54ch;
  font: 300 1.0625rem/1.7 var(--font-body);
  color: var(--gris-cendre);
}
.place__facts { margin-top: auto; padding-top: 30px; }
.place__facts > div {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  padding: 12px 0;
  border-top: 1px solid var(--gris-clair);
}
.place__facts dt { font: 400 .9375rem/1.4 var(--font-body); }
.place__facts dd { font: 400 1.0625rem/1.3 var(--font-display); white-space: nowrap; }
.place__link {
  position: relative;
  align-self: flex-start;
  margin-top: 22px;
  padding: 12px 0;
  font: 600 11px/1 var(--font-ui);
  letter-spacing: .2em;
  text-transform: uppercase;
  text-decoration: none;
}
.place__link::after {
  content: "";
  position: absolute;
  left: 0;
  right: .2em;
  bottom: 4px;
  height: 1px;
  background: currentColor;
  transform-origin: right center;
}
@media (hover: hover) and (pointer: fine) {
  .place__link:hover::after { animation: lineSweep 620ms var(--ease-strong); }
}
@keyframes lineSweep {
  0% { transform: scaleX(1); transform-origin: right center; }
  45% { transform: scaleX(0); transform-origin: right center; }
  46% { transform: scaleX(0); transform-origin: left center; }
  100% { transform: scaleX(1); transform-origin: left center; }
}

.buy__faqhead { margin-top: clamp(80px, 14vh, 150px); }
/* The questions read as a numbered index. Each row is ruled by two hairlines
   laid one on the other: a grey one that draws itself when the list arrives
   (--rule, main.js) and an anthracite one that runs across under the pointer
   and stays under the open question. The answer opens by its own height
   (main.js, Web Animations) while its text rises into place; without the
   script <details name="faq"> still opens and closes, at once. */
.faq {
  --qa-num: clamp(34px, 4.6vw, 72px);
  position: relative;
  max-width: var(--maxw);
  margin: clamp(28px, 5vh, 52px) auto 0;
  counter-reset: qa;
}
.faq::before,
.qa::before,
.qa::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  height: 1px;
  background: var(--gris-clair);
  transform-origin: 0 50%;
  pointer-events: none;
}
.faq::before { top: 0; transform: scaleX(var(--rule-top, 1)); }
.qa { position: relative; counter-increment: qa; overflow: clip; }
.qa::before { bottom: 0; transform: scaleX(var(--rule, 1)); }
/* The dark line is parked off the left edge. Lit (pointer on the row, or the
   row open) it slides in; leaving, it carries on out to the right and is put
   back on the left unseen — so it always travels one way, even when the
   pointer only crosses the row. main.js sets the two classes. */
.qa::after { bottom: 0; background: var(--anthracite); transform: translate3d(-101%, 0, 0); }
.qa.is-lit::after { transform: none; transition: transform 760ms var(--ease-strong); }
.qa.is-leaving::after { transform: translate3d(101%, 0, 0); transition: transform 620ms var(--ease-strong); }
.faq:not(.is-enhanced) .qa[open]::after { transform: none; transition: transform 760ms var(--ease-strong); }
.qa__q {
  display: grid;
  grid-template-columns: var(--qa-num) minmax(0, 1fr) auto;
  align-items: center;
  column-gap: clamp(8px, 1.4vw, 20px);
  padding: clamp(20px, 3vh, 28px) 0;
  font: 400 clamp(1.1875rem, 1.9vw, 1.625rem)/1.3 var(--font-display);
  list-style: none;
  cursor: pointer;
}
.qa__q::-webkit-details-marker { display: none; }
.qa__q::before {
  content: counter(qa, decimal-leading-zero);
  font: 600 11px/1 var(--font-ui);
  letter-spacing: .2em;
  color: var(--gris-cendre);
  opacity: .62;
  transition: opacity 360ms var(--ease-out);
}
.qa__q span { transition: translate 520ms var(--ease-strong); }
.qa__q i {
  position: relative;
  flex: none;
  width: 36px;
  height: 36px;
  border: 1px solid var(--gris-clair);
  border-radius: 50%;
  margin-right: 2px; /* room to grow under the pointer inside the row's clip */
  transition: rotate 620ms var(--ease-strong), border-color 320ms var(--ease-out), background-color 420ms var(--ease-out), color 320ms var(--ease-out), scale 320ms var(--ease-out);
}
.qa__q i::before,
.qa__q i::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 12px;
  height: 1px;
  margin: -.5px 0 0 -6px;
  background: currentColor;
}
.qa__q i::after { transform: rotate(90deg); transition: transform 620ms var(--ease-strong); }
/* open: the disc turns half a circle and fills, the plus closes into a minus */
.qa.is-open .qa__q i,
.faq:not(.is-enhanced) .qa[open] .qa__q i { rotate: 180deg; border-color: var(--anthracite); background-color: var(--anthracite); color: var(--blanc); }
.qa.is-open .qa__q i::after,
.faq:not(.is-enhanced) .qa[open] .qa__q i::after { transform: rotate(0deg); }
.qa.is-open .qa__q::before,
.faq:not(.is-enhanced) .qa[open] .qa__q::before { opacity: 1; }
@media (hover: hover) and (pointer: fine) {
  .faq:not(.is-enhanced) .qa:hover::after { transform: none; transition: transform 760ms var(--ease-strong); }
  .qa__q:hover::before { opacity: 1; }
  .qa__q:hover span { translate: 8px 0; }
  .qa__q:hover i { border-color: var(--anthracite); scale: 1.08; }
}
.qa__q:focus-visible { outline-offset: -1px; }
.qa__a p {
  max-width: 72ch;
  margin-left: calc(var(--qa-num) + clamp(8px, 1.4vw, 20px));
  padding: 0 clamp(0px, 6vw, 60px) clamp(24px, 3.6vh, 34px) 0;
  font: 300 1.0625rem/1.75 var(--font-body);
  color: var(--gris-cendre);
}
.qa__a a { color: var(--anthracite); text-underline-offset: 3px; text-decoration-thickness: 1px; }
.faq:not(.is-enhanced) .qa[open] .qa__a { animation: qaIn 560ms var(--ease-strong) both; }
@keyframes qaIn {
  from { opacity: 0; transform: translate3d(0, -10px, 0); }
}
/* With the script: the box opens by height, the text rises a little later
   and leaves a little sooner than the box closes. */
.faq.is-enhanced .qa__a { overflow: clip; }
.faq.is-enhanced .qa__a p {
  opacity: 0;
  transform: translate3d(0, 16px, 0);
  transition: opacity 220ms var(--ease-out), transform 320ms var(--ease-out);
}
.faq.is-enhanced .qa.is-open .qa__a p {
  opacity: 1;
  transform: none;
  transition: opacity 620ms var(--ease-out) 140ms, transform 820ms var(--ease-strong) 100ms;
}
.buy__cta { max-width: var(--maxw); margin: clamp(40px, 7vh, 72px) auto 0; }
.fade--from-white {
  margin-top: clamp(96px, 16vh, 180px);
  margin-inline: calc(var(--gutter) * -1);
  background: linear-gradient(to bottom, var(--blanc) 0%, var(--gris-clair) 32%, var(--gris-cendre) 70%, var(--graphite) 100%);
}

@media (max-width: 899px) {
  .places { grid-template-columns: 1fr; }
  .buy__lead { padding-right: 0; }
}
@media (max-width: 560px) {
  .qa__q i { width: 32px; height: 32px; }
  .buy__cta .btn { width: 100%; }
}
@media (prefers-reduced-motion: reduce) {
  /* nothing travels: the dark line and the answer simply fade */
  .qa::after { transform: none; opacity: 0; transition: opacity 300ms ease; }
  .qa.is-lit::after, .faq:not(.is-enhanced) .qa[open]::after { transform: none; opacity: 1; transition: opacity 300ms ease; }
  .qa.is-leaving::after { transform: none; opacity: 0; transition: opacity 300ms ease; }
  .faq.is-enhanced .qa__a p, .faq.is-enhanced .qa.is-open .qa__a p { transform: none; }
  .qa__q:hover span { translate: none; }
}

/* ---------- 33. When the message could not be sent ----------
   The tick is a promise; it is only drawn when the message really left. If
   nothing could be sent the same circle turns amber and shows a cross, and the
   card says so in words — see sendMessage() in main.js. */
.done__cross { display: none; }
.card.is-failed .done__ring { stroke: #B3432F; opacity: .55; }
.card.is-failed .done__check { display: none; }
.card.is-failed .done__cross {
  display: block;
  stroke: #B3432F;
  stroke-width: 4.5;
  stroke-dasharray: 52;
  stroke-dashoffset: 52;
  animation: doneCheck 460ms var(--ease-out) 260ms forwards;
}
