:root {
  --bg: #0b0b0c;
  --panel: #111113;
  --ink: #e9e5dd;
  --ink-2: #a9a49b;
  --ink-3: #7a766f;
  --line: rgba(233, 229, 221, 0.14);
  --bronze: #a8865a;
  --serif: "Cormorant Garamond", Georgia, "Times New Roman", serif;
  --mono: "DM Mono", "SFMono-Regular", Menlo, Consolas, monospace;
  --gutter: clamp(1.25rem, 5vw, 5rem);
  --section: clamp(6rem, 14vw, 11rem);
  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--mono);
  font-weight: 300;
  font-size: 0.8125rem;
  line-height: 1.9;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1,
h2,
h3,
p,
ul,
ol,
figure {
  margin: 0;
  padding: 0;
}

ul,
ol {
  list-style: none;
}

img {
  display: block;
  max-width: 100%;
  height: auto;
}

a {
  color: inherit;
  text-decoration: none;
}

::selection {
  background: var(--bronze);
  color: var(--bg);
}

:focus-visible {
  outline: 1px solid var(--bronze);
  outline-offset: 4px;
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

.skip {
  position: absolute;
  top: -100%;
  left: var(--gutter);
  z-index: 20;
  padding: 0.75rem 1rem;
  background: var(--ink);
  color: var(--bg);
  font-size: 0.6875rem;
  letter-spacing: 0.24em;
  text-transform: uppercase;
}

.skip:focus {
  top: 1rem;
}

/* Vocabulaire commun */

.kicker {
  font-size: 0.6875rem;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-bottom: clamp(1.5rem, 3vw, 2.5rem);
}

.title {
  font-family: var(--serif);
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  font-size: clamp(2rem, 3.8vw, 3.5rem);
  line-height: 1.08;
  max-width: 30ch;
}

.rule {
  display: block;
  width: 2rem;
  height: 1px;
  background: var(--bronze);
}

/* En-tête */

/* Plus de bandeau. Le logo et la navigation se posent directement sur la page,
   sans fond, sans arête, sans plaque : il ne reste que ce qui est écrit.
   La seule concession est une ombre portée très basse sur le texte, invisible à
   l'œil mais qui garantit la lisibilité si un jour une section claire passe
   dessous. */
.site-header {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 1.6rem var(--gutter);
  transition: padding 0.5s var(--ease);
  text-shadow: 0 1px 14px rgba(0, 0, 0, 0.55);
}

.site-header.is-scrolled {
  padding: 1.1rem var(--gutter);
}

.brand img {
  height: 2rem;
  width: auto;
  opacity: 0.95;
  transition: opacity 0.4s var(--ease);
}

.brand:hover img {
  opacity: 1;
}

.site-nav {
  display: flex;
  gap: 2.5rem;
}

.site-nav a {
  position: relative;
  padding: 0.4rem 0;
  font-size: 0.6875rem;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--ink-2);
  transition: color 0.4s var(--ease);
}

.site-nav a::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 1px;
  background: var(--bronze);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.5s var(--ease);
}

.site-nav a:hover,
.site-nav a:focus-visible {
  color: var(--ink);
}

.site-nav a:hover::after,
.site-nav a:focus-visible::after {
  transform: scaleX(1);
}

/* Hero */

.hero {
  position: relative;
  display: grid;
  grid-template-columns: 1fr;
  min-height: 100vh;
  min-height: 100svh;
}

.hero-media {
  position: relative;
  overflow: hidden;
  background: var(--panel);
}

.hero-film,
.hero-arret {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 50%;
  background: var(--bg);
}

.hero-media::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='180' height='180'><filter id='g'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.6 0'/></filter><rect width='100%' height='100%' filter='url(%23g)'/></svg>");
  opacity: 0.1;
  mix-blend-mode: overlay;
  pointer-events: none;
}

.hero-media::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg,
    rgba(11, 11, 12, 0.5) 0%,
    rgba(11, 11, 12, 0) 18%,
    rgba(11, 11, 12, 0) 45%,
    rgba(11, 11, 12, 0.92) 100%);
  pointer-events: none;
}

.hero-text {
  position: absolute;
  inset: auto 0 0 0;
  padding: 0 var(--gutter) clamp(3rem, 7vh, 5rem);
}

/* Le nom n'est plus écrit sur l'image : l'image de repos est la dernière du
   film, et le logo Ben Kouider Group y figure déjà, en grand et au centre.
   L'écrire une seconde fois faisait doublon. Le titre de niveau un reste dans
   le document, pour la structure et pour les lecteurs d'écran. */
.hero-name {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.hero-name-visuel {
  font-family: var(--serif);
  font-weight: 300;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-size: clamp(2.75rem, 6vw, 5.75rem);
  line-height: 1.02;
}

.hero-name span {
  display: block;
}

.hero-role {
  margin-top: 1.75rem;
  font-size: 0.75rem;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--ink-2);
}

.hero .rule {
  margin-top: 1.5rem;
}

.hero-places {
  margin-top: 2.75rem;
  font-size: 0.6875rem;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--ink-3);
}

/* Le hero se repose sur l'image de fin du film, figée : le logo. Le nom est donc
   là dès l'arrivée. Il garde son fondu d'entrée, monté par script.js. */
.js .hero .hero-text,
.js .hero .hero-cue {
  opacity: 0;
}

.js .hero.is-ended .hero-text,
.js .hero.is-ended .hero-cue {
  opacity: 1;
}

.hero-cue {
  position: absolute;
  right: var(--gutter);
  bottom: 2.5rem;
  width: 1px;
  height: 3rem;
  background: var(--ink);
  opacity: 0.35;
  transform-origin: top;
}

/* Vision */

.vision {
  display: grid;
  grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
  column-gap: clamp(2rem, 6vw, 6rem);
  padding: var(--section) var(--gutter);
  background: var(--panel);
}

.vision .kicker,
.vision .title {
  grid-column: 1 / -1;
}

.vision .title {
  margin-bottom: clamp(2.5rem, 6vw, 4.5rem);
}

.manifesto {
  max-width: 68ch;
  font-size: 0.75rem;
  line-height: 2.25;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-2);
}

.pull {
  align-self: start;
  max-width: 24ch;
  padding-top: 1.25rem;
  border-top: 1px solid var(--line);
  font-family: var(--serif);
  font-style: italic;
  font-weight: 300;
  font-size: clamp(1.5rem, 2.3vw, 2.1rem);
  line-height: 1.3;
  color: var(--ink);
}

/* Activités */

.triptych {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
}

.panel {
  position: relative;
  overflow: hidden;
  height: clamp(28rem, 78vh, 52rem);
  background: var(--panel);
}

.panel img,
.panel-film {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0.8;
  transform: scale(1.001);
  transition: opacity 1s var(--ease), transform 1.8s var(--ease);
}

.panel:hover img,
.panel:hover .panel-film {
  opacity: 0.95;
  transform: scale(1.035);
}

.panel-title {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding-top: 12%;
  font-family: var(--serif);
  font-weight: 300;
  font-size: clamp(1.05rem, 1.5vw, 1.4rem);
  letter-spacing: 0.42em;
  text-indent: 0.42em;
  text-transform: uppercase;
  color: var(--ink);
  text-shadow: 0 1px 28px rgba(0, 0, 0, 0.7);
  transition: letter-spacing 1.2s var(--ease), text-indent 1.2s var(--ease);
}

.panel:hover .panel-title {
  letter-spacing: 0.5em;
  text-indent: 0.5em;
}

/* Parcours */

.path {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  column-gap: clamp(3rem, 8vw, 8rem);
  padding: var(--section) var(--gutter);
}

.lede {
  max-width: 44ch;
  margin-top: 2.5rem;
  font-size: 0.8125rem;
  line-height: 2;
  color: var(--ink-2);
}

.timeline {
  padding-top: clamp(0rem, 6vw, 4.5rem);
}

.timeline li {
  display: grid;
  grid-template-columns: 7rem 1fr;
  align-items: baseline;
  gap: 2rem;
  padding: 1.75rem 0;
  border-top: 1px solid var(--line);
}

.timeline li:last-child {
  border-bottom: 1px solid var(--line);
}

.year {
  font-family: var(--serif);
  font-weight: 300;
  font-size: clamp(1.75rem, 2.6vw, 2.4rem);
  line-height: 1;
  color: var(--ink);
  transition: color 0.5s var(--ease);
}

.timeline li:hover .year {
  color: rgba(214, 226, 240, 0.9);
}

.timeline p {
  max-width: 48ch;
  color: var(--ink-2);
}

/* Rencontres : mur de photos */

.wall {
  padding-top: var(--section);
  overflow: hidden;
}

.wall-intro {
  display: grid;
  grid-template-columns: minmax(0, 6fr) minmax(0, 6fr);
  column-gap: clamp(2rem, 6vw, 6rem);
  align-items: end;
  padding: 0 var(--gutter);
}

.wall-intro .kicker {
  grid-column: 1 / -1;
}

.wall-intro .lede {
  max-width: 36ch;
  margin-top: 0;
  padding-bottom: 0.4rem;
}

.wall-stage {
  position: relative;
  aspect-ratio: 16 / 11;
  margin-top: clamp(3rem, 8vw, 6rem);
  perspective: 1400px;
}

.wall-items {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
  will-change: transform;
}

.wall-item {
  position: absolute;
  left: var(--x);
  top: var(--y);
  width: var(--w);
  transform: translate3d(0, var(--shift, 0px), calc(var(--d) * 90px)) rotate(var(--r));
  transition: opacity 0.6s var(--ease);
}

.wall-item figure {
  position: relative;
  aspect-ratio: var(--a, 3 / 2);
  overflow: hidden;
  background: var(--panel);
  box-shadow: 0 40px 80px -30px rgba(0, 0, 0, 0.85), 0 0 0 1px rgba(233, 229, 221, 0.08);
  transition: transform 0.8s var(--ease), box-shadow 0.8s var(--ease);
}

.wall-item img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* les légendes restent vides tant que lieux, dates et noms ne sont pas validés */
.wall-item figcaption:empty {
  display: none;
}

.wall-item figcaption {
  position: absolute;
  inset: auto 0 0 0;
  padding: 2.5rem 1rem 0.9rem;
  font-size: 0.625rem;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--ink);
  background: linear-gradient(180deg, rgba(11, 11, 12, 0), rgba(11, 11, 12, 0.85));
  opacity: 0;
  transition: opacity 0.6s var(--ease);
}

.wall-item figcaption:empty {
  display: none;
}

.wall-item:hover {
  z-index: 5;
}

.wall-item:hover figure {
  transform: scale(1.035);
  box-shadow: 0 60px 100px -30px rgba(0, 0, 0, 0.9), 0 0 0 1px rgba(233, 229, 221, 0.18);
}

.wall-item:hover figcaption {
  opacity: 1;
}

.wall-stage:has(.wall-item:hover) .wall-item:not(:hover) {
  opacity: 0.5;
}

@media (hover: none) {
  .wall-item figcaption {
    opacity: 1;
  }
}

/* Conciergerie */

.concierge {
  padding-top: var(--section);
}

.concierge-intro {
  display: grid;
  grid-template-columns: minmax(0, 6fr) minmax(0, 6fr);
  column-gap: clamp(2rem, 6vw, 6rem);
  align-items: end;
  padding: 0 var(--gutter);
}

.concierge-intro .kicker {
  grid-column: 1 / -1;
}

.concierge-intro .lede {
  margin-top: 0;
  padding-bottom: 0.4rem;
}

.wide-media {
  position: relative;
  height: clamp(20rem, 64vh, 46rem);
  /* sur écran étroit la hauteur en vh donnait un cadre presque carré,
     donc une bande de tarmac vide : on garde toujours un format large */
  max-height: 62vw;
  margin-top: clamp(3rem, 8vw, 6rem);
  overflow: hidden;
  background: var(--panel);
  border-top: 1px solid var(--line);
}

.wide-media img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 34%;
}

/* the photograph is the only lit surface on the page, so its edges are
   dissolved back into the page ground instead of ending on a hard rectangle */
.wide-media::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    linear-gradient(to bottom,
      rgba(11, 11, 12, 0.96) 0%,
      rgba(11, 11, 12, 0) 20%,
      rgba(11, 11, 12, 0) 74%,
      rgba(11, 11, 12, 0.55) 100%),
    linear-gradient(to right,
      rgba(11, 11, 12, 0.5) 0%,
      rgba(11, 11, 12, 0) 20%,
      rgba(11, 11, 12, 0) 80%,
      rgba(11, 11, 12, 0.5) 100%);
}

/* Les cinq services : de petits objets réels détourés, dans une bande
   soudée au bas de la photographie plutôt qu'une grille de cartes détachée */

.poles {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  border-bottom: 1px solid var(--line);
}

.pole {
  position: relative;
  padding: clamp(1.5rem, 2.2vw, 2.25rem) clamp(1rem, 1.6vw, 1.75rem) clamp(1.5rem, 2.2vw, 2rem);
}

.pole + .pole {
  border-left: 1px solid var(--line);
}

.pole-stage {
  --h: clamp(3rem, 4.4vw, 4rem);
  /* largeur réelle de l'objet, déduite de son rapport posé dans index.html :
     elle sert à caler le point de fuite exactement sur lui */
  --w: min(100%, calc(var(--obj, 2) * var(--h)));
  position: relative;
  height: var(--h);
  margin: 0 0 clamp(1rem, 1.6vw, 1.5rem);
  display: flex;
  align-items: flex-end;
  justify-content: flex-start;
  perspective: 620px;
  /* sans ça le point de fuite tombe au milieu de la case alors que les objets
     sont calés à gauche et n'ont pas la même largeur : chacun pencherait
     différemment, et la bande perdrait son unité */
  perspective-origin: calc(var(--w) / 2) 45%;
}

/* l'image seule : sans script, en mouvement réduit, et sur petit écran */
.pole-stage img {
  position: relative;
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  object-fit: contain;
}

/* Le volume feuilleté, monté par script.js. Un détourage est une surface plate :
   de tranche il disparaît complètement. On empile donc la même image sur
   quelques degrés d'écart, si bien qu'au moment où un feuillet passe de profil
   ses voisins sont encore assez de face pour que l'objet garde une largeur. */
.pole-solid {
  position: absolute;
  left: 0;
  bottom: 0;
  width: var(--w);
  height: 100%;
  transform-style: preserve-3d;
}

.pole-stage .pole-solid img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: none;
  max-height: none;
  object-fit: contain;
  transform: rotateY(var(--a));
}

/* seules les deux faces extérieures gardent la pleine lumière ; les feuillets
   intérieurs, assombris, se lisent comme l'épaisseur de l'objet */
.pole-stage .pole-solid img:not(:first-child):not(:last-child) {
  filter: brightness(0.4);
}

.pole-index {
  margin: 0;
  font-family: var(--mono);
  font-size: 0.5625rem;
  font-weight: 400;
  letter-spacing: 0.3em;
  color: rgba(214, 226, 240, 0.9);
}

.pole-title {
  margin: 0.5rem 0 0;
  font-family: var(--serif);
  font-size: clamp(1.0625rem, 1.5vw, 1.3125rem);
  font-weight: 300;
  line-height: 1.15;
  color: var(--ink);
}

.pole-note {
  margin: 0.55rem 0 0;
  font-family: var(--mono);
  font-size: 0.6875rem;
  font-weight: 300;
  line-height: 1.75;
  color: var(--ink-2);
}

.world {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  column-gap: clamp(2rem, 6vw, 6rem);
  align-items: center;
  padding: clamp(4rem, 10vw, 8rem) var(--gutter) var(--section);
}

.clocks {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(1.25rem, 2.5vw, 2rem) clamp(1.5rem, 3vw, 2.5rem);
}

.clock {
  display: grid;
  justify-items: start;
  gap: 0.35rem;
  width: 100%;
  margin: 0;
  padding: 1.5rem 0 0;
  appearance: none;
  background: none;
  border: 0;
  border-top: 1px solid var(--line);
  border-radius: 0;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
  transition: border-color 0.5s var(--ease);
}

.clock:hover,
.clock.is-active {
  border-top-color: var(--bronze);
}

.clock-face {
  width: clamp(5.5rem, 9vw, 7.5rem);
  height: auto;
  margin-bottom: 0.9rem;
}

.dial {
  fill: none;
  stroke: var(--line);
  stroke-width: 1;
  transition: stroke 0.5s var(--ease);
}

.clock:hover .dial,
.clock.is-active .dial {
  stroke: rgba(233, 229, 221, 0.5);
}

.ticks {
  fill: none;
  stroke: rgba(233, 229, 221, 0.4);
  stroke-width: 5;
  stroke-dasharray: 0.06 0.94;
  stroke-dashoffset: 0.03;
}

.hand {
  stroke: var(--ink);
  stroke-width: 1.4;
  stroke-linecap: round;
}

.hand-s {
  stroke: var(--bronze);
  stroke-width: 1;
}

.pin {
  fill: var(--bronze);
}

.clock-city {
  font-size: 0.6875rem;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--ink-2);
  transition: color 0.5s var(--ease);
}

.clock:hover .clock-city,
.clock.is-active .clock-city {
  color: var(--ink);
}

.clock-time {
  font-family: var(--serif);
  font-weight: 300;
  font-size: clamp(1.75rem, 2.4vw, 2.25rem);
  line-height: 1;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}

.clock-offset {
  font-size: 0.625rem;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.world-hint {
  margin-top: 2.5rem;
  font-size: 0.625rem;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.globe-wrap {
  position: relative;
  width: 100%;
  max-width: 38rem;
  aspect-ratio: 1 / 1;
  margin: 0 auto;
}

.globe {
  display: block;
  width: 100%;
  height: 100%;
}

/* Contact */

.contact {
  display: grid;
  grid-template-columns: 1fr 1fr;
  min-height: 90vh;
  background: var(--panel);
}

.contact-media {
  position: relative;
  overflow: hidden;
}

.contact-media img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 35% 50%;
  opacity: 0.85;
}

.contact-text {
  align-self: center;
  padding: clamp(5rem, 12vh, 8rem) var(--gutter) clamp(5rem, 12vh, 8rem) clamp(2rem, 6vw, 5.5rem);
}

.mail {
  display: inline-block;
  margin-top: 2.5rem;
  padding-bottom: 0.4rem;
  font-size: 0.8125rem;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--ink);
  border-bottom: 1px solid transparent;
  transition: border-color 0.5s var(--ease);
}

.mail:hover,
.mail:focus-visible {
  border-color: var(--bronze);
}

.contact .rule {
  margin-top: 2.5rem;
}

.places {
  margin-top: 1.25rem;
  font-size: 0.6875rem;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--ink-3);
}

/* Pied de page */

/* Le pied de page ne se pose pas sous le site, il s'y enfonce. Le filet qui le
   séparait courait d'un bord à l'autre et le détachait comme une étiquette
   collée dessous ; il est remplacé par un trait qui s'éteint à ses deux
   extrémités, donc qui n'atteint jamais les bords. C'est ce qui fait la
   différence entre une pièce rapportée et une pièce incrustée.

   Le fond descend en même temps vers un noir plus profond que celui de la page,
   si bien que le regard sort par le bas au lieu de buter sur une barre. */
.site-footer {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem 2rem;
  padding: clamp(3.5rem, 7vw, 5.5rem) var(--gutter) clamp(2.5rem, 5vw, 3.5rem);
  border-top: 0;
  background: linear-gradient(180deg, transparent 0%, rgba(0, 0, 0, 0.55) 62%, rgba(0, 0, 0, 0.85) 100%);
  font-size: 0.625rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.site-footer::before {
  content: "";
  position: absolute;
  left: var(--gutter);
  right: var(--gutter);
  top: 0;
  height: 1px;
  background: linear-gradient(90deg,
    transparent 0%,
    rgba(233, 229, 221, 0.16) 22%,
    rgba(233, 229, 221, 0.16) 78%,
    transparent 100%);
}

.site-footer img {
  height: 1.5rem;
  width: auto;
  opacity: 0.5;
  transition: opacity 0.5s var(--ease);
}

.site-footer:hover img {
  opacity: 0.75;
}

.site-footer p {
  margin: 0;
}

/* Mouvement : une entrée de hero, une apparition par titre, rien d'autre */

@media (prefers-reduced-motion: no-preference) {
  .hero-media {
    animation: unveil 1.3s var(--ease) both;
  }

  .hero.is-ended .hero-name span,
  .hero.is-ended .hero-role,
  .hero.is-ended .rule,
  .hero.is-ended .hero-places {
    opacity: 0;
    transform: translateY(1rem);
    animation: rise 0.9s var(--ease) forwards;
  }

  .hero.is-ended .hero-name span:nth-child(1) { animation-delay: 0.1s; }
  .hero.is-ended .hero-name span:nth-child(2) { animation-delay: 0.22s; }
  .hero.is-ended .hero-name span:nth-child(3) { animation-delay: 0.34s; }
  .hero.is-ended .hero-role { animation-delay: 0.5s; }
  .hero.is-ended .rule { animation-delay: 0.62s; }
  .hero.is-ended .hero-places { animation-delay: 0.72s; }

  .hero.is-ended .hero-cue {
    transform: scaleY(0);
    animation: grow 1s var(--ease) 0.85s forwards;
  }

  /* Apparition au défilement.

     L'état caché n'est plus décrit ici mais posé en style direct par script.js.
     Une version précédente le portait par une classe : sur neuf éléments, la
     règle « visible » ne l'emportait pas et le texte restait invisible. Un style
     direct prime sur toute la cascade, donc le problème ne peut pas revenir.

     Il ne reste ici que la transition, le décalage et l'amplitude, c'est à dire
     ce qui relève vraiment de la feuille de style. */
  .js .reveal {
    transition: opacity 1.15s var(--ease), transform 1.15s var(--ease);
    transition-delay: calc(var(--rang, 0) * 85ms);
  }

  /* les titres montent de plus loin et plus lentement que leur texte : c'est ce
     décalage de vitesse entre les deux qui fait le mouvement */
  .js .reveal-titre {
    transition-duration: 1.45s;
  }

  .js .panel.reveal:nth-child(2) { transition-delay: 0.12s; }
  .js .panel.reveal:nth-child(3) { transition-delay: 0.24s; }

  .js .wide-media img {
    opacity: 0;
    transform: scale(1.045);
    transition: opacity 1.4s var(--ease), transform 2s var(--ease);
  }

  .js .wide-media.has-image img {
    opacity: 1;
    transform: none;
  }

  /* Les cinq objets partagent une seule horloge : même durée, aucun décalage,
     vitesse angulaire constante d'un bout à l'autre, vingt degrés par seconde.
     Hors écran l'animation est suspendue et non retirée, sinon les objets
     sauteraient à zéro en revenant dans le champ. */
  .js .poles .pole-solid {
    animation: pole-turn 11s cubic-bezier(0.37, 0, 0.63, 1) infinite;
    animation-play-state: paused;
  }

  .js .poles.is-turning .pole-solid {
    animation-play-state: running;
  }
}

/* Un objet détouré est une surface plate : à 90 degrés il disparaît. Le tour
   marque donc un temps de pose de face et de dos, et traverse la tranche vite. */
@keyframes pole-turn {
  0% { transform: rotateY(-32deg); }
  50% { transform: rotateY(32deg); }
  100% { transform: rotateY(-32deg); }
}


@keyframes unveil {
  from { clip-path: inset(0 0 100% 0); }
  to { clip-path: inset(0); }
}

@keyframes rise {
  to { opacity: 1; transform: none; }
}

@keyframes grow {
  to { transform: scaleY(1); }
}

/* Tablette */

@media (max-width: 1023px) {
  .vision,
  .path {
    grid-template-columns: 1fr;
    row-gap: 3rem;
  }

  .pull {
    max-width: 28ch;
  }

  .timeline {
    padding-top: 0;
  }

  .contact {
    grid-template-columns: 1fr;
    min-height: 0;
  }

  .contact-media {
    height: 55vh;
  }

  .wall-intro,
  .concierge-intro {
    grid-template-columns: 1fr;
    row-gap: 2rem;
  }

  .wall-intro .lede {
    margin-top: 0.5rem;
    padding-bottom: 0;
  }

  .wall-stage {
    aspect-ratio: 16 / 14;
  }

  .concierge-intro .lede {
    margin-top: 0.5rem;
    padding-bottom: 0;
  }

  .poles {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .pole:nth-child(n + 4) {
    border-top: 1px solid var(--line);
  }

  .pole:nth-child(4) {
    border-left: 0;
  }

  .world {
    grid-template-columns: 1fr;
    row-gap: 3rem;
  }

  .globe-wrap {
    order: -1;
    max-width: 32rem;
  }
}

/* Mobile : le hero devient une couverture */

@media (max-width: 767px) {
  .site-nav {
    gap: 0;
  }

  .site-nav a:not(.nav-contact) {
    display: none;
  }

  .hero-text {
    padding-bottom: 3.5rem;
  }

  .hero-cue {
    display: none;
  }

  .manifesto br {
    display: none;
  }

  .triptych {
    grid-template-columns: 1fr;
  }

  .panel {
    height: 62vh;
  }

  .timeline li {
    grid-template-columns: 4.5rem 1fr;
    gap: 1.25rem;
  }

  .contact-media {
    height: 45vh;
  }

  .site-footer {
    flex-direction: column;
    align-items: flex-start;
    gap: 0.75rem;
  }

  .wide-media {
    height: 48vh;
  }

  .wall-stage {
    aspect-ratio: auto;
    padding: 0 var(--gutter);
    perspective: none;
  }

  .wall-items {
    position: static;
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 2rem 1.25rem;
    transform: none !important;
    /* le mur ne bouge plus ici : inutile de garder une couche promise */
    will-change: auto;
  }

  .wall-item {
    position: static;
    width: auto;
    transform: rotate(calc(var(--r) * 0.6));
  }

  .wall-item:nth-child(even) {
    translate: 0 1.75rem;
  }

  .wall-item:nth-child(3n) {
    grid-column: span 2;
    translate: 0 0;
  }

  .wall-item:last-child {
    margin-bottom: 2rem;
  }

  .poles {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .pole:nth-child(n + 3) {
    border-top: 1px solid var(--line);
  }

  .pole:nth-child(odd) {
    border-left: 0;
  }

  .pole:last-child {
    grid-column: 1 / -1;
  }

  .clocks {
    column-gap: 1.25rem;
  }

  .clock-face {
    width: 5rem;
  }

  .globe-wrap {
    max-width: 100%;
  }
}

/* Le volume réel, monté par poles3d.js. Le maillage vient de la photographie
   de l'objet lui-même, donc il tourne vraiment sur trois cent soixante degrés,
   ce qu'un détourage plat ne peut pas faire. La toile occupe toute la case :
   l'objet est cadré sur sa sphère englobante, sa taille apparente ne bouge donc
   pas pendant le tour, même quand le jet passe de face. */
.pole-toile {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
}

/* une fois le volume prêt, l'image plate s'efface ; elle reste dans le document
   comme repli si le maillage ne charge pas */
.pole-stage.a-volume > img {
  opacity: 0;
  transition: opacity 0.6s var(--ease, ease);
}

/* L'invitation à voir le film. Discrète par construction : un filet, un mot en
   petites capitales, rien qui ressemble à un bouton de lecteur vidéo. Elle
   devient « Revoir le film » une fois le film vu. */
.hero-voir {
  margin-top: 2.25rem;
  display: inline-flex;
  align-items: center;
  gap: 0.85rem;
  padding: 0;
  border: 0;
  background: none;
  color: var(--ink-2);
  font-family: var(--mono);
  font-size: 0.625rem;
  font-weight: 300;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  cursor: pointer;
  transition: color 0.5s var(--ease);
}

.hero-voir-marque {
  position: relative;
  width: 2.25rem;
  height: 1px;
  background: var(--ink-3);
  transition: width 0.5s var(--ease), background-color 0.5s var(--ease);
}

/* le triangle de lecture, minuscule, au bout du filet */
.hero-voir-marque::after {
  content: "";
  position: absolute;
  right: -1px;
  top: 50%;
  width: 0;
  height: 0;
  border-left: 5px solid var(--ink-3);
  border-top: 3.5px solid transparent;
  border-bottom: 3.5px solid transparent;
  transform: translateY(-50%);
  transition: border-left-color 0.5s var(--ease);
}

.hero-voir:hover,
.hero-voir:focus-visible {
  color: var(--ink);
}

.hero-voir:hover .hero-voir-marque,
.hero-voir:focus-visible .hero-voir-marque {
  width: 3.25rem;
  background: var(--bronze);
}

.hero-voir:hover .hero-voir-marque::after,
.hero-voir:focus-visible .hero-voir-marque::after {
  border-left-color: var(--bronze);
}

/* La salle : le film complet, en plein écran, sur fond noir et rien d'autre.
   Elle s'ouvre sur son affiche, le plan large de la tour, et la lecture ne part
   qu'une fois l'ouverture finie, sinon le premier plan passe pendant la
   transition. C'est exactement ce qui se perdait en lecture automatique. */
.salle {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #000;
  opacity: 0;
  transition: opacity 0.9s var(--ease);
}

.salle.est-ouverte {
  opacity: 1;
}

.salle-film {
  width: 100%;
  height: 100%;
  object-fit: contain;
  background: #000;
}

.salle-ouverte,
.salle-ouverte body {
  overflow: hidden;
}

.salle-sortie {
  position: absolute;
  top: clamp(1rem, 3vh, 2rem);
  right: var(--gutter);
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.6rem 0.2rem;
  border: 0;
  background: none;
  color: var(--ink-3);
  font-family: var(--mono);
  font-size: 0.625rem;
  font-weight: 300;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  cursor: pointer;
  opacity: 0;
  transition: color 0.4s var(--ease), opacity 0.6s var(--ease);
}

.salle-sortie span[aria-hidden] {
  font-size: 1.05rem;
  line-height: 1;
}

/* la sortie ne s'affiche pas d'emblée : elle attend le premier geste, pour ne
   pas poser un bouton par-dessus le plan d'ouverture */
.salle.est-ouverte:hover .salle-sortie,
.salle-sortie:focus-visible {
  opacity: 1;
}

.salle-sortie:hover {
  color: var(--ink);
}

@media (hover: none) {
  .salle.est-ouverte .salle-sortie { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .salle { transition: none; }
  .hero-voir,
  .hero-voir-marque,
  .hero-voir-marque::after,
  .salle-sortie { transition: none; }
}

/* Sur écran vertical, un cadrage en `cover` rogne les côtés d'une image 16:9 et
   coupe le logo, qui est précisément ce qu'on veut montrer. On l'inscrit donc en
   entier. Le fond qui reste au-dessus et au-dessous n'est pas une bande noire
   visible : les bords de cette image sont déjà presque noirs, ils se fondent
   dans le fond du site. */
@media (max-width: 767px) {
  .hero-media {
    background: var(--bg);
  }

  .hero-arret {
    object-fit: contain;
    /* remontée sous l'en-tête : centrée, l'image laissait un grand vide en haut
       et se retrouvait collée au bloc de texte du bas */
    object-position: 50% 34%;
  }
}

/* Le plan du jet est large, la colonne qui l'accueille est haute : le cadrer en
   `cover` lui coupait les ailes. On l'inscrit donc en entier. Il ne tourne pas
   en boucle non plus : il se joue une fois à l'approche puis se fige sur sa
   dernière image, sans relance. */
.contact-film {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  opacity: 0.9;
}

/* Le retour à l'image de repos passe par un fondu. Sans lui, le plan sautait
   d'un coup à son point de départ et la coupe se voyait beaucoup : c'est le
   même défaut que celui reproché aux boucles. Le panneau étant sombre, le plan
   traverse simplement le noir avant de revenir. */
.panel-film.revient {
  opacity: 0;
  transition: opacity 0.85s var(--ease);
}


@media (prefers-reduced-motion: reduce) {
}

@media (max-width: 600px) {
}

/* ============================================================
   L'ouverture : le plan-séquence scrubé au défilement
   ============================================================ */

/* La toile est fixe et occupe l'écran entier. Elle reste derrière tout le
   reste : les sections du site glissent par-dessus quand le film est fini. */
#ouverture {
  position: fixed;
  inset: 0;
  z-index: 0;
  background: #06070a;
  overflow: hidden;
}

#ouverture canvas {
  display: block;
  width: 100%;
  height: 100%;
}

/* Repli : si trop d'images manquent, on montre l'affiche fixe plutôt qu'un
   film troué. Elle sert aussi quand le script ne tourne pas du tout. */
.ouverture-repli-image {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.js.ouverture-active .ouverture-repli-image { display: none; }
.js.ouverture-active #ouverture canvas { display: block; }
.js #ouverture canvas { display: none; }
.js.ouverture-active #ouverture canvas { display: block; }

/* La piste ne contient rien : elle ne sert qu'à donner au défilement la
   longueur nécessaire pour dérouler les cent quatre-vingt-treize images.
   Cinq écrans donnent une avance douce sans obliger à scroller longtemps. */
#ouverture-piste {
  position: relative;
  z-index: 1;
  height: 500vh;
  pointer-events: none;
}

/* Le titre n'arrive qu'à la fin, quand le yacht est au large. Blanc, grand,
   et seul : rien d'autre ne doit occuper cet instant. */
#ouverture-titre {
  position: fixed;
  z-index: 2;
  left: 0;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  margin: 0;
  padding: 0 var(--gutter);
  text-align: center;
  font-family: var(--serif);
  font-weight: 300;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  line-height: 1.05;
  font-size: clamp(2rem, 7vw, 6rem);
  color: #fff;
  opacity: 0;
  pointer-events: none;
  /* deux ombres : une courte et dense qui décolle les lettres du fond clair,
     une longue et diffuse qui assombrit la zone entière. Sans elles, le blanc
     sur la mer au soleil devient illisible. */
  text-shadow: 0 1px 12px rgba(4, 10, 18, 0.55), 0 0 90px rgba(4, 10, 18, 0.5);
}

/* Sans script, le titre reste lisible sur l'affiche */
html:not(.js) #ouverture-titre { opacity: 1; }

/* Tout ce qui suit le film passe au-dessus de la toile, sur un fond opaque :
   sinon le film resterait visible en transparence sous le texte. */
main > section,
.site-footer {
  position: relative;
  z-index: 3;
  background-color: var(--bg);
}

.contact { background-color: var(--panel); }
.panel { background-color: var(--panel); }

/* L'écran de chargement. Un logo, une barre, un pourcentage en chiffres et une
   phrase simple : les métaphores ne sont pas comprises. */
#ouverture-chargement {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1.5rem;
  background: #06070a;
  transition: opacity 0.8s var(--ease), visibility 0.8s var(--ease);
}

#ouverture-chargement img {
  height: 2.6rem;
  width: auto;
  opacity: 0.85;
}

.chargement-barre {
  width: min(15rem, 52vw);
  height: 1px;
  background: rgba(233, 229, 221, 0.16);
  overflow: hidden;
}

.chargement-part {
  display: block;
  height: 100%;
  width: 0;
  background: var(--ink);
  transition: width 0.25s linear;
}

.chargement-pc,
.chargement-mot {
  margin: 0;
  font-family: var(--mono);
  font-size: 0.6875rem;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--ink-3);
}

#ouverture-chargement.est-fini {
  opacity: 0;
  visibility: hidden;
}

html:not(.js) #ouverture-chargement { display: none; }

@media (prefers-reduced-motion: reduce) {
  #ouverture-piste { height: 100vh; }
  #ouverture-titre { opacity: 1; }
}
