/* ==========================================================================
   ENDEVELOPMENT · lauvas.css — the Villas Lauvas page
   --------------------------------------------------------------------------
   Loaded by villas-lauvas.html only, after styles.css. The page is built from
   the site's own blocks (mhero, mvilla, shead, mpair, specs, mgrid, mshot,
   mnote); its own are the galleries' shapes, the 3D models, the plans and the
   two ways on. The diary and the viewer of the pictures are chantier.css.
   ========================================================================== */

/* the villa at dusk: an upright phone shows a third of the picture's width, so the crop is held there on the
   lit living room and the pool, not on the blind wall; the title keeps a darker side of its own */
@media (max-width: 720px) {
  .lhero .mhero__media img { object-position: 64% 50%; }
}
.lhero .mhero__veil::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to right, rgba(44, 46, 53, .5) 0%, rgba(44, 46, 53, .22) 40%, rgba(44, 46, 53, 0) 66%);
}

/* ---------- the perspectives: the architect's and the designer's pictures ----------
   The site's grid of pictures; here every picture keeps its own shape (5:3, the wide dusk view 16:9) and is
   a link: it opens in the viewer of the diary (chantier.js, the <dialog> of its section). */
.lgal .mshot { aspect-ratio: 5 / 3; }
.lgal .mshot--wide { aspect-ratio: 16 / 9; }
.lgal .mshot a { display: block; width: 100%; height: 100%; }
.lgal .mshot a:focus-visible { outline: 2px solid var(--bleu); outline-offset: -2px; }
@media (hover: none) {
  .lgal .mshot__cap { opacity: 1; }           /* a finger cannot hover: the caption stays */
}
@media (max-width: 899px) {
  .lgal .mshot--third { grid-column: span 6; }   /* the small pictures go two by two, the page stays short */
  .lgal .mshot--third .mshot__cap { padding: 28px 10px 10px; font-size: 9px; letter-spacing: .14em; }
}

/* ---------- the plans of a villa: two drawings side by side ---------- */
.lplans__title { margin-top: clamp(40px, 8vh, 96px); }
.lplans { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: clamp(14px, 1.6vw, 26px); margin-top: clamp(14px, 2.4vh, 26px); }
.lplans__fig { margin: 0; }
.lplans__fig a { display: block; overflow: clip; border: 1px solid var(--gris-clair); background: var(--blanc); }
.lplans__fig a:focus-visible { outline: 2px solid var(--bleu); outline-offset: 2px; }
.lplans__fig img { display: block; width: 100%; height: auto; transition: scale 900ms var(--ease-out); }
@media (hover: hover) and (pointer: fine) {
  .lplans__fig a:hover img { scale: 1.03; }
}
@media (max-width: 720px) {
  .lplans { grid-template-columns: minmax(0, 1fr); }
}
@media (prefers-reduced-motion: reduce) {
  .lplans__fig img { transition: none; }
}

.lplan {
  position: relative;
  width: min(100%, 980px);
  margin: clamp(40px, 8vh, 96px) auto 0;
  overflow: clip;
  background: var(--gris-clair-40);
}
.lplan img { display: block; width: 100%; height: auto; }
.lplan__cap {
  padding: 14px 0 0;
  background: var(--blanc);
  font: 600 10px/1.4 var(--font-ui);
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--gris-cendre);
}

/* ---------- the villa as a 3D model (markup in lauvas.html, logic in lauvas3d.js) ---------- *
   Without JavaScript or WebGL only the picture and the names of the two villas show. With them the
   canvas fades in over the picture once the model stands (.is-ready). Everything that moves here is
   opacity or transform.                                                                           */
.l3d { margin-top: clamp(40px, 8vh, 96px); }
.l3d__head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 8px 32px; }
.l3d__head .plannote__title { margin-top: 0; }
.l3d__tabs { display: flex; gap: clamp(18px, 3vw, 40px); }
.l3d__tabs button {
  position: relative;
  min-height: 44px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--gris-cendre);
  font: 600 11px/1 var(--font-ui);
  letter-spacing: .18em;
  text-transform: uppercase;
  cursor: pointer;
  transition: color 240ms var(--ease-out);
}
.l3d__tabs button::after {
  content: "";
  position: absolute;
  inset: auto 0 9px 0;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 420ms var(--ease-out);
}
.l3d__tabs button[aria-selected="true"] { color: var(--anthracite); }
.l3d__tabs button[aria-selected="true"]::after { transform: scaleX(1); }
.l3d__tabs button:focus-visible { outline: 1px solid var(--bleu); outline-offset: 6px; }
.l3d:not(.is-live) .l3d__tabs button { cursor: default; }
@media (hover: hover) and (pointer: fine) {
  .l3d.is-live .l3d__tabs button:hover { color: var(--anthracite); }
}

.l3d__stage {
  position: relative;
  aspect-ratio: 16 / 10;
  width: 100%;                                    /* with a max-height the ratio would otherwise narrow the box */
  max-height: max(420px, calc(100svh - 150px));   /* model, hint and reset button fit one screen of a laptop */
  margin-top: clamp(10px, 2vh, 22px);
  overflow: clip;
  background: radial-gradient(120% 90% at 50% 38%, #edebe6 0%, #dbd8d1 100%);
}
.l3d__poster, .l3d__canvas { position: absolute; inset: 0; width: 100%; height: 100%; }
.l3d__poster { object-fit: cover; transition: opacity 700ms var(--ease-out); }
.l3d__canvas { display: block; opacity: 0; cursor: grab; outline: none; transition: opacity 700ms var(--ease-out); }
.l3d__canvas:active { cursor: grabbing; }
.l3d__canvas:focus-visible { outline: 2px solid var(--bleu); outline-offset: -2px; }
.l3d:not(.is-live) .l3d__canvas { display: none; }
.l3d.is-ready .l3d__canvas { opacity: 1; }
.l3d.is-ready .l3d__poster { opacity: 0; }

.l3d__labels { position: absolute; inset: 0; overflow: clip; pointer-events: none; opacity: 0; transition: opacity 500ms var(--ease-out); }
.l3d.is-ready .l3d__labels { opacity: 1; }
.l3d__label {
  position: absolute;
  left: 0;
  top: 0;
  padding: 5px 9px;
  background: rgba(255, 255, 255, .88);
  color: var(--anthracite);
  font: 600 9px/1 var(--font-ui);
  letter-spacing: .16em;
  text-transform: uppercase;
  white-space: nowrap;
  will-change: transform;
  transition: opacity 200ms var(--ease-out);
}

.l3d__start, .l3d__quit {
  position: absolute;
  min-height: 44px;
  padding: 0 22px;
  border: 1px solid var(--glass-on-light-line);
  background: rgba(255, 255, 255, .9);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  color: var(--anthracite);
  font: 600 11px/1 var(--font-ui);
  letter-spacing: .18em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background-color 200ms var(--ease-out), scale 200ms var(--ease-out);
}
.l3d__start { left: 50%; bottom: clamp(16px, 4vh, 36px); translate: -50% 0; }
.l3d__quit { left: 14px; top: 14px; }
.l3d__start:active, .l3d__quit:active { scale: .97; }
.l3d__start:focus-visible, .l3d__quit:focus-visible, .l3d__reset:focus-visible { outline: 2px solid var(--bleu); outline-offset: 3px; }
.l3d__reset {
  position: absolute;
  right: 14px;
  bottom: 14px;
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 1px solid var(--glass-on-light-line);
  border-radius: 50%;
  background: rgba(255, 255, 255, .9);
  color: var(--anthracite);
  cursor: pointer;
  opacity: 0;
  pointer-events: none;
  transition: opacity 400ms var(--ease-out), rotate 500ms var(--ease-out), scale 200ms var(--ease-out);
}
.l3d__reset svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
.l3d.is-ready .l3d__reset { opacity: 1; pointer-events: auto; }
.l3d__reset:active { scale: .94; }
/* + and −, above the reset button: one pane of frosted glass with a hairline between the two, light enough
   to let the model show through (lauvas3d.js; held, they go on zooming) */
.l3d__zoom {
  position: absolute;
  right: 14px;
  bottom: 68px;
  display: grid;
  width: 44px;
  border: 1px solid var(--glass-on-light-line);
  border-radius: 22px;
  overflow: clip;
  background: rgba(255, 255, 255, .5);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  opacity: 0;
  pointer-events: none;
  transition: opacity 400ms var(--ease-out), background-color 200ms var(--ease-out);
}
.l3d.is-ready .l3d__zoom { opacity: 1; pointer-events: auto; }
.l3d__zoom button {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--anthracite);
  cursor: pointer;
  touch-action: manipulation;
  -webkit-touch-callout: none;
  user-select: none;
  transition: background-color 200ms var(--ease-out);
}
.l3d__zoom button + button { border-top: 1px solid var(--glass-on-light-line); }
.l3d__zoom svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linecap: round; transition: scale 160ms var(--ease-out); }
.l3d__zoom button:active svg { scale: .86; }
.l3d__zoom button:focus-visible { outline: 2px solid var(--bleu); outline-offset: -3px; }
@media (hover: hover) and (pointer: fine) {
  .l3d__start:hover, .l3d__quit:hover { background: var(--blanc); }
  .l3d__reset:hover { rotate: -45deg; }
  .l3d__zoom:hover { background: rgba(255, 255, 255, .72); }
  .l3d__zoom button:hover { background: rgba(255, 255, 255, .6); }
}
.l3d__hint {
  position: absolute;
  left: 50%;
  bottom: 18px;
  translate: -50% 6px;
  max-width: calc(100% - 140px);
  padding: 9px 14px;
  background: rgba(44, 46, 53, .78);
  color: var(--blanc);
  font: 300 .8125rem/1.35 var(--font-body);
  text-align: center;
  pointer-events: none;
  opacity: 0;
  transition: opacity 500ms var(--ease-out), translate 500ms var(--ease-out);
}
.l3d__hint.is-shown { opacity: 1; translate: -50% 0; }
.l3d__bar { position: absolute; inset: 0 0 auto 0; height: 2px; overflow: clip; pointer-events: none; opacity: 0; transition: opacity 300ms var(--ease-out); }
.l3d.is-loading .l3d__bar { opacity: 1; }
.l3d__bar span { position: absolute; inset: 0; background: var(--anthracite); transform: scaleX(var(--k, 0)); transform-origin: left center; transition: transform 300ms var(--ease-out); }
.l3d__bar.is-unknown span { width: 40%; transform: none; animation: l3d-bar 1.4s var(--ease-in-out) infinite; }
@keyframes l3d-bar { from { translate: -100% 0; } to { translate: 250% 0; } }
.l3d__error { display: none; position: absolute; inset: auto 14px 14px 14px; padding: 12px 16px; background: rgba(255, 255, 255, .92); font: 300 .875rem/1.5 var(--font-body); color: var(--anthracite); }
.l3d.is-failed .l3d__error { display: block; }
.l3d__cap {
  padding: 14px 0 0;
  font: 600 10px/1.4 var(--font-ui);
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--gris-cendre);
}
@media (max-width: 720px) {
  .l3d__stage { aspect-ratio: 4 / 5; }
  .l3d__label { font-size: 8px; padding: 4px 7px; }
  .l3d__hint { max-width: calc(100% - 28px); bottom: 70px; }
}
@media (prefers-reduced-motion: reduce) {
  .l3d__poster, .l3d__canvas, .l3d__labels { transition-duration: 200ms; }
  .l3d__bar.is-unknown span { animation: none; width: 100%; opacity: .5; }
  .l3d__reset, .l3d__zoom { transition: opacity 200ms; }
}

.lnext {
  display: flex;
  flex-wrap: wrap;
  gap: 8px clamp(28px, 5vw, 64px);
  margin-top: clamp(12px, 3vh, 32px);
}

/* ---------- the diary of the site and the way on ----------
   The diary (chantier.css) stands on the pale grey of "Ambiances", so the page reads in bands;
   the two links that close the page keep a band of their own, shorter than a section. */
#etat { background: var(--gris-clair-20); }
.lclose { padding-block: clamp(36px, 7vh, 80px); }
.lclose .lnext { margin-top: 0; }

/* ---------- the level of a villa: three small buttons over the model ----------
   Ground floor / upper floor / closed villa (lauvas3d.js). They show for the two villas only, and only
   when the model can be drawn. */
.l3d__levels { position: absolute; top: 14px; right: 14px; display: flex; border: 1px solid var(--glass-on-light-line); background: rgba(255, 255, 255, .9); -webkit-backdrop-filter: var(--glass-blur); backdrop-filter: var(--glass-blur); }
.l3d__levels[hidden], .l3d:not(.is-live) .l3d__levels { display: none; }
.l3d__levels button {
  min-height: 40px;
  padding: 0 14px;
  border: 0;
  background: none;
  color: var(--gris-cendre);
  font: 600 10px/1 var(--font-ui);
  letter-spacing: .16em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background-color 240ms var(--ease-out), color 240ms var(--ease-out);
}
.l3d__levels button + button { border-left: 1px solid var(--glass-on-light-line); }
.l3d__levels button[aria-pressed="true"] { background: var(--anthracite); color: var(--blanc); }
.l3d__levels button:focus-visible { outline: 2px solid var(--bleu); outline-offset: 2px; }
@media (hover: hover) and (pointer: fine) {
  .l3d__levels button[aria-pressed="false"]:hover { color: var(--anthracite); }
}
@media (max-width: 720px) {
  .l3d__levels { top: 10px; right: 10px; }
  .l3d__levels button { min-height: 44px; padding: 0 10px; font-size: 9px; letter-spacing: .12em; }
  .l3d__quit { top: 64px; }                    /* under the level buttons, which take the top of a narrow stage */
}
