/* ==========================================================================
   Grapheva — Page d'accueil (redesign Figma "Accueil — Desktop 1440")
   Feuille autonome : elle ne dépend d’aucune autre feuille (chaque page charge
   autres pages). Écrite mobile-first, les media queries montent vers 1440.
   ========================================================================== */

:root {
  --ink: #111111;            /* fond principal */
  --ink-panel: #1b1b1e;      /* panneaux / cartes */
  --ink-deep: #000000;       /* pied de page */
  --fg: #ffffff;
  --fg-soft: rgba(255, 255, 255, 0.82);
  --muted: #7b8087;
  --hairline: rgba(255, 255, 255, 0.08);

  --r-sm: 8px;
  --r-md: 12px;
  --r-lg: 16px;

  /* Gouttière : 24px en mobile → 124px à partir de 1440 (maquette) */
  --gutter: clamp(20px, 8.6vw, 124px);
  --content: 1192px;

  --ease-out-soft: cubic-bezier(0.32, 0.72, 0, 1);
}

* { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* Réserve la gouttière de la barre de défilement en permanence : sans
     elle, une page qui passe sous la hauteur d’écran fait disparaître la
     barre, la largeur utile saute de ~15 px et tout le contenu se décale
     latéralement. C’est l’autre source classique de « tremblement ». */
  scrollbar-gutter: stable;
}

body {
  margin: 0;
  background: var(--ink);
  color: var(--fg);
  font-family: Inter, system-ui, -apple-system, "Segoe UI", sans-serif;
  font-size: 16px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

/* height:auto neutralise les attributs width/height du HTML, pour que les
   ratios déclarés en CSS (aspect-ratio) fassent foi. */
img, svg { display: block; max-width: 100%; height: auto; }
a { color: inherit; text-decoration: none; }
p { margin: 0; }
h1, h2, h3 { margin: 0; font-weight: 600; }
ul { margin: 0; padding: 0; list-style: none; }
button { font: inherit; color: inherit; background: none; border: 0; }

:focus-visible {
  outline: 2px solid #fff;
  outline-offset: 3px;
  border-radius: 4px;
}

.skip-link {
  position: fixed;
  top: 8px;
  left: 8px;
  z-index: 200;
  padding: 10px 16px;
  background: #fff;
  color: var(--ink);
  border-radius: var(--r-sm);
  font-weight: 600;
  transform: translateY(-160%);
  transition: transform 160ms ease-out;
}
.skip-link:focus-visible { transform: none; }

.wrap {
  width: 100%;
  max-width: calc(var(--content) + var(--gutter) * 2);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.eyebrow {
  margin: 0;
  color: var(--muted);
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 1.61px;
  text-transform: uppercase;
}

.lede { color: var(--muted); font-size: 16px; line-height: 1.65; }

.rule { height: 1px; background: var(--hairline); border: 0; margin: 0; }

/* ---------- Visuels en parallaxe ----------------------------------------
   L’image déborde de 24 % en hauteur, son cadre la rogne, et js/home.js la
   déplace dans ce débord au fil du défilement. Le décalage de −12 % la centre
   au repos : elle a autant de marge en haut qu'en bas. */
[data-parallax] {
  position: absolute;
  top: -12%;
  left: 0;
  width: 100%;
  height: 124%;
  object-fit: cover;
  will-change: transform;
}
[data-parallax-frame] { position: relative; overflow: hidden; }

/* ---------- Boutons ----------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 15px 26px;
  border-radius: var(--r-sm);
  font-size: 15px;
  font-weight: 600;
  white-space: nowrap;
  transition: transform 150ms ease-out, background-color 150ms ease-out;
}
.btn-primary { background: #fff; color: var(--ink); }
/* Filet indispensable : posé sur le motif de tuiles, un aplat #111 sans bord
   disparaît et il ne reste que le libellé flottant. */
.btn-dark { background: var(--ink); color: #fff; border: 1px solid rgba(255, 255, 255, 0.16); border-radius: 6px; }
.btn:active { transform: scale(0.97); }

@media (hover: hover) and (pointer: fine) {
  .btn-primary:hover { background: #ececec; }
  .btn-dark:hover { background: #1f1f1f; }
}

/* Lien fléché des sections pôle */
.arrow-link {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-size: 14.5px;
  font-weight: 600;
  color: #fff;
}
.arrow-link::after { content: "→"; transition: transform 200ms var(--ease-out-soft); }
@media (hover: hover) and (pointer: fine) {
  .arrow-link:hover::after { transform: translateX(4px); }
}

/* Puce ronde (flèches carrousel, bouton +) */
.pill-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: 999px;
  background: var(--ink-panel);
  color: #fff;
  font-size: 16px;
  font-weight: 600;
  cursor: pointer;
  transition: transform 150ms ease-out, background-color 150ms ease-out;
}
.pill-btn:active { transform: scale(0.97); }
.pill-btn[disabled] { opacity: 0.35; cursor: default; }
@media (hover: hover) and (pointer: fine) {
  .pill-btn:not([disabled]):hover { background: #26262b; }
}

.plus-btn {
  flex: none;
  width: 40px;
  height: 40px;
  border-radius: 20px;
  background: var(--ink);
  border: 1px solid var(--hairline);
  color: #fff;
  font-size: 16px;
  font-weight: 600;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: transform 150ms ease-out, background-color 150ms ease-out;
}
.plus-btn:active { transform: scale(0.97); }
@media (hover: hover) and (pointer: fine) {
  .plus-btn:hover { background: #1b1b1e; }
}

/* ---------- Apparition au scroll ---------------------------------------- */

/* Pas de filter: blur() ici, bien que la maquette le demande. Un filtre sur
   un bloc de texte lui fait perdre l'anticrénelage sous-pixel : le texte
   paraît flou et plus maigre, durablement, sur tous les blocs pas encore
   apparus. C'est la cause principale du « texte flou » signalé — et elle
   est invisible sur une capture d'écran, qui réapplique son propre rendu.
   L'entrée reste lisible avec l'opacité et le déplacement seuls. */
.reveal {
  opacity: 0;
  transform: translateY(24px);
  transition:
    opacity 700ms var(--ease-out-soft),
    transform 700ms var(--ease-out-soft);
  transition-delay: var(--reveal-delay, 0ms);
}
/* transform: none plutôt qu'une valeur nulle : laisser un transform, même
   identité, maintient le calque composité et son rendu de texte dégradé. */
.reveal.is-in { opacity: 1; transform: none; }

/* ==========================================================================
   En-tête flottant
   ========================================================================== */

.site-header {
  position: fixed;
  inset: 0 0 auto;
  z-index: 100;
  padding: 16px var(--gutter) 0;
  pointer-events: none;
  transition: transform 320ms var(--ease-out-soft);
}
/* Escamotée pendant la descente — voir js/common.js. Le décalage dépasse la
   hauteur de la barre pour emporter aussi le rembourrage au-dessus d'elle. */
.site-header.is-hidden { transform: translateY(-130%); }
@media (prefers-reduced-motion: reduce) { .site-header { transition: none; } }

.header-bar {
  pointer-events: auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  max-width: var(--content);
  margin-inline: auto;
  min-height: 64px;
  padding: 10px 14px 10px 18px;
  border: 1px solid var(--hairline);
  border-radius: var(--r-lg);
  /* Pas de backdrop-filter : il recalcule un flou sur tout ce qui passe
     dessous à chaque frame de défilement, et le texte posé par-dessus perd
     son anticrénelage sous-pixel. C'est coûteux en continu et ça se voit
     comme un scintillement — que les captures d'écran ne montrent pas.
     Un fond semi-opaque suffit à détacher la barre. */
  background: rgba(14, 14, 16, 0.72);
  transition: background-color 250ms ease-out;
}
/* Opaque dès que la page a défilé. Tant qu’un backdrop-filter floutait le
   fond, 0.82 d’opacité suffisait : on devinait une forme derrière la barre.
   Sans lui, le contenu passe net au travers et les titres de section se
   lisent par transparence sous le menu. Au repos en haut de page la barre
   reste translucide, la photo du hero devant rester visible. */
.site-header.is-stuck .header-bar {
  background: #0e0e10;
  border-color: rgba(255, 255, 255, 0.1);
}

.brand { display: flex; align-items: center; gap: 8px; }
.brand-mark { width: 26px; height: 28px; }
.brand-name { font-size: 18px; font-weight: 700; letter-spacing: -0.3px; }

.header-nav { display: none; gap: 26px; align-items: center; }
.header-nav a {
  font-size: 14px;
  font-weight: 500;
  color: rgba(255, 255, 255, 0.85);
  transition: color 150ms ease-out;
}
@media (hover: hover) and (pointer: fine) {
  .header-nav a:hover { color: #fff; }
}
.header-nav a[aria-current="page"] { color: #fff; }

/* ---------- Menu déroulant « Services » ---------- */

.nav-dropdown { position: relative; }

.nav-trigger {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 14px;
  font-weight: 500;
  color: rgba(255, 255, 255, 0.85);
  cursor: pointer;
  transition: color 150ms ease-out;
}
.nav-trigger[data-current] { color: #fff; }
@media (hover: hover) and (pointer: fine) { .nav-trigger:hover { color: #fff; } }

.nav-chevron { width: 13px; height: 13px; transition: transform 200ms var(--ease-out-soft); }
.nav-dropdown.is-open .nav-chevron { transform: rotate(180deg); }

.nav-panel {
  position: absolute;
  top: calc(100% + 18px);
  left: 50%;
  translate: -50% 0;
  z-index: 10;
  display: grid;
  gap: 2px;
  width: max-content;
  min-width: 280px;
  padding: 8px;
  border: 1px solid var(--hairline);
  border-radius: 14px;
  /* Opaque : posé sur une photo de hero très contrastée, le moindre reste
     de transparence laissait affleurer les lignes du décor derrière les
     libellés. Un menu doit se lire, pas se fondre. */
  background: #15151a;
  box-shadow: 0 18px 40px rgba(0, 0, 0, 0.45);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-6px);
  transition: opacity 180ms ease-out, transform 180ms var(--ease-out-soft), visibility 180ms;
}
.nav-dropdown.is-open .nav-panel { opacity: 1; visibility: visible; transform: none; }

/* Pont invisible entre le bouton et le panneau : sans lui, le survol se
   coupe dans l'espace qui les sépare et le menu se referme en route. */
.nav-panel::before {
  content: "";
  position: absolute;
  inset: -18px 0 100% 0;
}

.nav-panel a {
  display: grid;
  gap: 2px;
  padding: 10px 14px;
  border-radius: 9px;
  font-size: 14px;
  color: rgba(255, 255, 255, 0.82);
  transition: background-color 150ms ease-out, color 150ms ease-out;
}
.nav-panel b {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: var(--muted);
}
@media (hover: hover) and (pointer: fine) {
  .nav-panel a:hover { background: rgba(255, 255, 255, 0.07); color: #fff; }
}

/* Intitulé de groupe dans le menu mobile */
.mobile-nav-label {
  margin: 10px 0 2px;
  padding: 0 12px;
  color: var(--muted);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 1.2px;
  text-transform: uppercase;
}

.header-cta { display: none; }

.nav-toggle {
  display: inline-flex;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: 44px;
  height: 44px;
  align-items: center;
  cursor: pointer;
}
.nav-toggle span {
  display: block;
  width: 20px;
  height: 2px;
  background: #fff;
  border-radius: 2px;
  transition: transform 200ms var(--ease-out-soft), opacity 160ms ease-out;
}
.nav-toggle[aria-expanded="true"] span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

.mobile-nav {
  pointer-events: auto;
  display: grid;
  gap: 4px;
  max-width: var(--content);
  margin: 8px auto 0;
  padding: 12px;
  border: 1px solid var(--hairline);
  border-radius: var(--r-lg);
  background: #15151a;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-8px);
  transition: opacity 200ms ease-out, transform 200ms var(--ease-out-soft), visibility 200ms;
}
.mobile-nav.is-open { opacity: 1; visibility: visible; transform: none; }
.mobile-nav a {
  padding: 13px 12px;
  border-radius: var(--r-sm);
  font-size: 15px;
  font-weight: 500;
}
.mobile-nav .btn { margin-top: 4px; }

@media (min-width: 1040px) {
  .header-nav { display: flex; }
  .header-cta { display: inline-flex; }
  .nav-toggle, .mobile-nav { display: none; }
  .header-bar { min-height: 84px; padding: 0 20px 0 24px; }
}

/* ==========================================================================
   Hero
   ========================================================================== */

/* L'en-tête est fixe et recouvre les ~100 premiers pixels : centrer le
   contenu dans toute la hauteur le ferait paraître trop haut. On décale donc
   le centre de flex vers le bas en creusant 100 px de plus en haut qu'en bas
   (148 − 48), ce qui le place au milieu de la zone réellement visible. */
.hero {
  position: relative;
  display: flex;
  align-items: center;
  min-height: 100svh;
  padding: 148px 0 48px;
  overflow: hidden;
}

.hero-bg {
  position: absolute;
  inset: -12% 0;
  z-index: 0;
  will-change: transform;
}
.hero-bg img { width: 100%; height: 100%; object-fit: cover; }
.hero-bg::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(
    180deg,
    rgba(0, 0, 0, 0.72) 0%,
    rgba(0, 0, 0, 0.25) 32%,
    rgba(0, 0, 0, 0.55) 68%,
    rgba(0, 0, 0, 0.9) 100%
  );
}

.hero-content { position: relative; z-index: 1; max-width: 760px; }
.hero h1 {
  margin: 0 0 24px;
  font-size: clamp(34px, 7.2vw, 64px);
  font-weight: 700;
  line-height: 1;
  letter-spacing: -0.034em;
}
.hero-lede {
  max-width: 620px;
  margin-bottom: 28px;
  color: var(--fg-soft);
  font-size: clamp(15px, 1.6vw, 18px);
  line-height: 1.5;
}

@media (min-width: 1040px) {
  /* Pas de position: absolute avec un top figé. La maquette place le bloc à
     300 px du haut d'un cadre de 900 px ; transposé tel quel, il laissait un
     grand vide sous l'en-tête dès que l'écran n'a pas cette hauteur exacte.
     Le centrage flex vaut pour toutes les hauteurs. */
  .hero { padding: 172px 0 72px; }
}

/* ==========================================================================
   Notre métier
   ========================================================================== */

.metier { padding: 88px 0 72px; }
@media (min-width: 1040px) { .metier { padding: 130px 0 85px; } }

.metier-intro { display: grid; gap: 22px; }
.metier-intro h2 {
  font-size: clamp(24px, 3.4vw, 34px);
  line-height: 1.25;
  letter-spacing: -0.02em;
}
.metier-intro .lede { max-width: 620px; }

.metier-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 18px;
  margin-top: 56px;
}
@media (min-width: 1040px) {
  .metier-intro { grid-template-columns: 150px 1fr; column-gap: 40px; }
  .metier-intro .eyebrow { grid-row: span 2; }
  .metier-grid { grid-template-columns: repeat(4, 1fr); margin-top: 96px; }
}

.metier-card { display: grid; gap: 14px; }
/* Le cadre porte le ratio et le rognage ; l'image parallaxée flotte dedans. */
.metier-media {
  width: 100%;
  aspect-ratio: 284 / 379;
  border-radius: var(--r-md);
}
.metier-card p { font-size: 15px; font-weight: 500; line-height: 1.3; }

/* ==========================================================================
   Pôle 01 — bande défilante
   ========================================================================== */

.pole01 { padding: 72px 0; }
@media (min-width: 1040px) { .pole01 { padding: 110px 0; } }

.rail-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 24px;
}
.rail-head h2 {
  margin-top: 20px;
  font-size: clamp(28px, 4vw, 44px);
  line-height: 1.15;
  letter-spacing: -0.02em;
}
.rail-nav { display: none; gap: 10px; flex: none; }
@media (min-width: 900px) { .rail-nav { display: flex; } }

.rail {
  display: flex;
  gap: 24px;
  margin-top: 40px;
  padding-inline: var(--gutter);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  /* Sans cela le navigateur cale la 1re carte sur le bord et mange la gouttière */
  scroll-padding-inline: var(--gutter);
  scrollbar-width: none;
  overscroll-behavior-x: contain;
}
.rail::-webkit-scrollbar { display: none; }
/* Affordance : sans curseur « grab », rien n’indique que la bande se tire. */
.rail { cursor: grab; }
.rail.is-dragging { scroll-snap-type: none; cursor: grabbing; user-select: none; }
/* Double sécurité avec le preventDefault de dragstart : certains navigateurs
   démarrent le glisser-déposer natif avant même l’événement. */
.rail img, .rail a, .rail svg { -webkit-user-drag: none; }
@media (min-width: 1040px) { .rail { margin-top: 52px; } }

.rail-item {
  flex: none;
  width: min(85vw, 460px);
  scroll-snap-align: start;
}
.rail-item.is-wide { width: min(90vw, 557px); }

.rail-visual {
  position: relative;
  aspect-ratio: 460 / 428;
  border-radius: var(--r-md);
  overflow: hidden;
  background: linear-gradient(169deg, #36383d 0%, #212429 85%);
}
.rail-visual img { width: 100%; height: 100%; object-fit: cover; }

.rail-item.is-wide .rail-visual { aspect-ratio: 557 / 446; }

.badge-num {
  position: absolute;
  top: 20px;
  left: 20px;
  padding: 6px 12px;
  border-radius: 999px;
  background: rgba(17, 17, 17, 0.78);
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.92px;
}

.play-badge {
  position: absolute;
  top: 50%;
  left: 50%;
  translate: -50% -50%;
  width: 68px;
  height: 68px;
  transition: transform 160ms ease-out;
}

.rail-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-top: 18px;
}
.rail-foot h3 { font-size: 18px; letter-spacing: -0.18px; }
.rail-foot p { margin-top: 4px; color: var(--muted); font-size: 13px; line-height: 1.5; }

/* ==========================================================================
   Sections domaine (démos + pôles 02/03/04)
   ========================================================================== */

.domain { padding-bottom: 72px; }
@media (min-width: 1040px) { .domain { padding-bottom: 110px; } }

.domain-inner { padding-top: 72px; }
@media (min-width: 1040px) { .domain-inner { padding-top: 110px; } }

.domain-title {
  margin: 20px 0 20px;
  font-size: clamp(30px, 4.6vw, 48px);
  line-height: 1.08;
  letter-spacing: -0.025em;
}
.domain .lede { max-width: 620px; }
.domain .arrow-link,
.demo-orbit .arrow-link { margin-top: 28px; }

.media-panel {
  position: relative;
  width: 100%;
  margin-top: 56px;
  border-radius: var(--r-lg);
  overflow: hidden;
}
@media (min-width: 1040px) { .media-panel { margin-top: 96px; } }
.media-panel > img { width: 100%; height: 100%; object-fit: cover; }

.panel-hint {
  position: absolute;
  left: 22px;
  bottom: 22px;
  padding: 8px 16px;
  border-radius: 999px;
  background: rgba(17, 17, 17, 0.82);
  font-size: 11.5px;
  font-weight: 500;
  letter-spacing: 0.69px;
}

.panel-tag {
  position: absolute;
  top: 10px;
  left: 10px;
  padding: 6px 12px;
  border-radius: var(--r-sm);
  background: #fff;
  color: var(--ink);
  font-size: 13px;
  font-weight: 700;
  /* L'étiquette flotte au-dessus d'une visionneuse manipulable : sans ça elle
     intercepterait les clics destinés à ses propres commandes. */
  pointer-events: none;
}

/* Panneau contenant une visionneuse tierce (Bativy) */
.media-panel--embed { background: var(--ink-panel); }
.media-panel--embed iframe {
  display: block;
  width: 100%;
  height: 100%;
  border: 0;
}

/* Garde tactile — invisible au pointeur fin, indispensable au doigt */
.embed-guard { display: none; }
@media (hover: none) {
  .media-panel--embed:not(.is-active) .embed-guard {
    position: absolute;
    inset: 0;
    z-index: 2;
    display: grid;
    place-items: center;
    background: rgba(17, 17, 17, 0.45);
    cursor: pointer;
  }
  .embed-guard span {
    padding: 11px 20px;
    border-radius: 999px;
    background: rgba(17, 17, 17, 0.88);
    color: #fff;
    font-size: 13px;
    font-weight: 600;
  }
}

/* Démo orbitale — turntable de 65 vues pré-rendues */
.demo-orbit {
  background: var(--ink-panel);
  padding: 72px 0;
}
@media (min-width: 1040px) { .demo-orbit { padding: 110px 0; } }

.orbit {
  /* Ratio des vues recadrées sur l'emprise du projet (assets/orbit) */
  aspect-ratio: 1280 / 607;
  max-height: 560px;
  border: 1px solid var(--hairline);
  background: #e9eaee;          /* fond des rendus, évite un flash sombre */
  cursor: grab;
  /* pan-y : le glissé horizontal pilote la rotation, le vertical reste au scroll */
  touch-action: pan-y;
  user-select: none;
  -webkit-user-select: none;
}
.orbit.is-dragging { cursor: grabbing; }
.orbit-frame {
  width: 100%;
  height: 100%;
  object-fit: contain;
  -webkit-user-drag: none;
  pointer-events: none;
}
.orbit .panel-hint {
  left: 50%;
  translate: -50% 0;
  white-space: nowrap;
  transition: opacity 300ms ease-out;
}
.orbit.is-touched .panel-hint { opacity: 0; }

/* Barre de préchargement des vues */
.orbit-loader {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 2px;
  background: rgba(17, 17, 17, 0.12);
  opacity: 1;
  transition: opacity 400ms ease-out;
}
.orbit-loader span {
  display: block;
  height: 100%;
  width: 0;
  background: var(--ink);
  transition: width 200ms linear;
}
.orbit-loader.is-done { opacity: 0; }

/* Démo 360 */
.demo-360 .media-panel { aspect-ratio: 1192 / 670; }

/* ---------- Pôle 02 ---------- */
.pole02-grid { display: grid; gap: 48px; }
@media (min-width: 1040px) {
  .pole02-grid { grid-template-columns: 420px 1fr; gap: 96px; align-items: start; }
  .pole02-grid .domain-title { max-width: 420px; }
  .pole02-grid .lede { max-width: 420px; }
}

.capability-list li {
  padding: 18px 0;
  border-top: 1px solid var(--hairline);
  font-size: clamp(18px, 2.4vw, 24px);
  font-weight: 500;
  letter-spacing: -0.01em;
}
.capability-list li:first-child { border-top: 0; padding-top: 0; }
@media (min-width: 1040px) { .capability-list li { padding: 22px 0; } }

.video-card {
  position: relative;
  display: block;
  width: 100%;
  margin-top: 56px;
  aspect-ratio: 1192 / 658;
  border-radius: var(--r-lg);
  overflow: hidden;
}
@media (min-width: 1040px) { .video-card { margin-top: 64px; } }
.video-media { position: absolute; inset: 0; display: block; overflow: hidden; }
.video-card .veil {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(0,0,0,0.1) 0%, rgba(0,0,0,0.25) 55%, rgba(0,0,0,0.8) 100%);
  transition: opacity 160ms ease-out;
}
.video-card .play-badge { width: 72px; height: 72px; }
@media (min-width: 900px) { .video-card .play-badge { width: 89px; height: 89px; } }
.video-caption {
  position: absolute;
  left: clamp(20px, 4vw, 48px);
  right: clamp(20px, 4vw, 48px);
  bottom: clamp(20px, 3.2vw, 38px);
}
.video-caption h3 {
  font-size: clamp(18px, 2.6vw, 29px);
  line-height: 1.3;
  letter-spacing: -0.01em;
}
.video-caption p {
  margin-top: 6px;
  color: rgba(255, 255, 255, 0.72);
  font-size: 12.5px;
  font-weight: 500;
  letter-spacing: 1.25px;
  text-transform: uppercase;
}
@media (hover: hover) and (pointer: fine) {
  .video-card:hover .play-badge { transform: scale(1.06); }
  .video-card:hover .veil { opacity: 0.88; }
}

/* Lecture sur place : l'affiche cède la place au lecteur, sans modale.
   Le cadre garde exactement la même boîte, donc rien ne saute à l'écran. */
.video-card.is-playing { cursor: default; background: #000; }
.video-card.is-playing .video-still,
.video-card.is-playing .veil,
.video-card.is-playing .play-badge,
.video-card.is-playing .video-caption { opacity: 0; pointer-events: none; }
.video-card .video-still,
.video-card .veil,
.video-card .play-badge,
.video-card .video-caption { transition: opacity 260ms var(--ease-out-soft); }
.video-card iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
  opacity: 0;
  animation: video-in 320ms var(--ease-out-soft) forwards;
}
@keyframes video-in { to { opacity: 1; } }

/* ---------- Pôle 03 — lecteur de plans ---------- */
.plan-reader {
  margin-top: 56px;
  border: 1px solid var(--hairline);
  border-radius: var(--r-lg);
  background: var(--ink-panel);
  overflow: hidden;
}
@media (min-width: 1040px) { .plan-reader { margin-top: 96px; } }

.plan-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 12px 16px;
  min-height: 60px;
  padding: 12px 18px 12px 22px;
}
.plan-toolbar h3 { font-size: 15px; }
.plan-toolbar p {
  margin-top: 2px;
  color: var(--muted);
  font-size: 11.5px;
  font-weight: 500;
  letter-spacing: 0.92px;
}
.plan-ident { min-width: 0; }

.plan-tabs {
  display: flex;
  gap: 4px;
  flex: none;
  padding: 4px;
  border: 1px solid var(--hairline);
  border-radius: 999px;
}
.plan-tab {
  padding: 8px 16px;
  border-radius: 999px;
  color: var(--muted);
  font-size: 13px;
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color 150ms ease-out, color 150ms ease-out, transform 150ms ease-out;
}
.plan-tab.is-active { background: #fff; color: var(--ink); }
.plan-tab:active { transform: scale(0.97); }
@media (hover: hover) and (pointer: fine) {
  .plan-tab:not(.is-active):hover { color: #fff; background: rgba(255, 255, 255, 0.06); }
}

.plan-doc {
  position: relative;
  width: 100%;
  aspect-ratio: 1192 / 579;
  min-height: 260px;
  background: linear-gradient(174deg, #232325 0%, #141416 85%);
  display: grid;
  place-items: center;
  padding: 28px;
}
.plan-panel[hidden] { display: none; }

/* Aperçu cliquable : ouvre packages/pdf-viewer en plein écran */
.plan-canvas {
  position: relative;
  display: grid;
  place-items: center;
  max-width: 100%;
  max-height: 100%;
  cursor: zoom-in;
  transition: transform 200ms var(--ease-out-soft);
}
.plan-canvas img {
  max-height: 100%;
  width: auto;
  border-radius: var(--r-sm);
  object-fit: contain;
}
.plan-open-hint {
  position: absolute;
  padding: 10px 18px;
  border-radius: 999px;
  background: rgba(17, 17, 17, 0.88);
  color: #fff;
  font-size: 13px;
  font-weight: 600;
  opacity: 0;
  transition: opacity 180ms ease-out;
}
.plan-canvas:active { transform: scale(0.99); }
@media (hover: hover) and (pointer: fine) {
  .plan-canvas:hover .plan-open-hint { opacity: 1; }
}
.plan-canvas:focus-visible .plan-open-hint { opacity: 1; }

.plan-page {
  position: absolute;
  left: 22px;
  bottom: 26px;
  padding: 8px 14px;
  border-radius: 999px;
  background: rgba(17, 17, 17, 0.82);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.48px;
}

/* Sélecteur de planches — bandeau propre, au-dessus du document */
.plan-sheets {
  display: flex;
  gap: 5px;
  padding: 12px 22px;
  border-top: 1px solid var(--hairline);
  overflow-x: auto;
  scrollbar-width: none;
}
.plan-sheets::-webkit-scrollbar { display: none; }
.plan-sheets button {
  flex: none;
  padding: 7px 14px;
  border: 1px solid var(--hairline);
  border-radius: 999px;
  background: rgba(17, 17, 17, 0.82);
  color: var(--muted);
  font-size: 12px;
  font-weight: 500;
  cursor: pointer;
  transition: background-color 150ms ease-out, color 150ms ease-out, transform 150ms ease-out;
}
.plan-sheets button.is-active { background: #fff; border-color: #fff; color: var(--ink); }
.plan-sheets button:active { transform: scale(0.97); }
@media (hover: hover) and (pointer: fine) {
  .plan-sheets button:not(.is-active):hover { color: #fff; }
}
/* Panneau BIMx */
.plan-panel--bimx { display: block; }
.bimx-frame {
  position: relative;
  width: 100%;
  height: 100%;
  min-height: 320px;
  display: grid;
  place-items: center;
}
.bimx-frame iframe { width: 100%; height: 100%; border: 0; display: block; }
.bimx-placeholder {
  max-width: 460px;
  padding: 32px;
  text-align: center;
  color: var(--muted);
  font-size: 14px;
  line-height: 1.6;
}
.bimx-placeholder .eyebrow { margin-bottom: 10px; }
.bimx-placeholder code {
  padding: 2px 6px;
  border-radius: 4px;
  background: rgba(255, 255, 255, 0.07);
  color: #fff;
  font-size: 12.5px;
}

/* ---------- Pôle 04 — liste ---------- */
.service-rows { margin-top: 40px; border-top: 1px solid var(--hairline); }
@media (min-width: 1040px) { .service-rows { margin-top: 56px; } }
.service-rows li {
  display: grid;
  gap: 8px;
  padding: 22px 0;
  border-bottom: 1px solid var(--hairline);
}
.service-rows h3 {
  font-size: clamp(18px, 2.2vw, 22px);
  font-weight: 500;
  line-height: 1.3;
  letter-spacing: -0.4px;
}
.service-rows p { color: var(--muted); line-height: 1.5; }
@media (min-width: 900px) {
  .service-rows li {
    grid-template-columns: 400px 1fr;
    align-items: center;
    gap: 24px;
    padding: 28px 0;
  }
}
.pole04 .arrow-link { margin-top: 44px; }

/* ==========================================================================
   Bandeau galerie
   ========================================================================== */

/* Pleine largeur : la carte court d'un bord à l'autre de la fenêtre */
.gallery-band { padding: 20px 0; }
.gallery-band > .wrap { max-width: none; padding-inline: 0; }

.gallery-card {
  position: relative;
  display: grid;
  place-items: center;
  min-height: 420px;
  padding: 72px clamp(20px, 5vw, 48px);
  overflow: hidden;
  background: #0b0b0d;
}
@media (min-width: 1040px) { .gallery-card { min-height: 460px; } }

/* Mosaïque de vignettes — reprise du motif de tuile de galerie.html
   (.tile-media de l’ancienne feuille) : trame fine, dégradé directionnel alterné
   et filigrane logomark. Les valeurs sont les jetons sombres d’origine
   recopiés en dur, cette feuille étant autonome. */
.gallery-mosaic {
  --grid-line: rgba(255, 255, 255, 0.045);
  /* Gris neutres, sans la pointe de violet des jetons d'origine : sous le
     voile elle virait au brun au contact du fond de carte. */
  --surface: #1e1e20;
  --surface-hi: #262628;

  /* Grille dense, comme .works-mosaic sur galerie.html : la mosaïque occupe
     tout le cadre, gouttière serrée, et `dense` rebouche les trous laissés
     par les tuiles à cheval sur deux colonnes ou deux rangées. */
  position: absolute;
  inset: 0;                 /* à fleur du cadre : pas de marge en haut */
  display: grid;
  grid-template-columns: repeat(10, 1fr);
  grid-template-rows: repeat(3, 1fr);
  grid-auto-flow: dense;
  gap: 5px;
}
.gtile--w2 { grid-column: span 2; }
.gtile--h2 { grid-row: span 2; }

.gtile {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  border-radius: 5px;
  box-shadow: inset 0 0 0 1px var(--hairline);
  background-image:
    repeating-linear-gradient(90deg, var(--grid-line) 0 1px, transparent 1px 38px),
    repeating-linear-gradient(0deg, var(--grid-line) 0 1px, transparent 1px 38px),
    linear-gradient(150deg, var(--surface), var(--surface-hi));
  background-size: auto, auto, cover;
}
/* Mêmes variantes de dégradé que .tile:nth-child(3n+2) / (3n+3) */
.gtile:nth-of-type(3n+2) {
  background-image:
    repeating-linear-gradient(90deg, var(--grid-line) 0 1px, transparent 1px 38px),
    repeating-linear-gradient(0deg, var(--grid-line) 0 1px, transparent 1px 38px),
    linear-gradient(28deg, var(--surface-hi), var(--surface));
}
.gtile:nth-of-type(3n+3) {
  background-image:
    repeating-linear-gradient(90deg, var(--grid-line) 0 1px, transparent 1px 38px),
    repeating-linear-gradient(0deg, var(--grid-line) 0 1px, transparent 1px 38px),
    linear-gradient(205deg, var(--surface), var(--surface-hi));
}
/* Filigrane : logomark centré dans sa tuile. Les décalages de la maquette
   (left/top variables) donnaient un éparpillement voulu, mais à l'écran la
   marque paraissait simplement mal posée, d'autant qu'elle débordait des
   petites tuiles. Le centrage vient du flex de .gtile — pas de
   positionnement absolu — et la variété tient désormais à la taille et à
   l'inclinaison seules, ce qui suffit à éviter l'effet « motif imprimé ». */
.gtile-mark {
  width: 34%;
  max-width: 130px;
  height: auto;
  flex: none;
  color: #fff;
  opacity: 0.12;
  transform: rotate(-22deg);
}
.gtile:nth-child(4n+2) .gtile-mark { width: 40%; transform: rotate(12deg); }
.gtile:nth-child(4n+3) .gtile-mark { width: 30%; transform: rotate(-8deg); }
.gtile:nth-child(4n)   .gtile-mark { width: 38%; transform: rotate(24deg); }

@media (max-width: 899px) { .gallery-mosaic { display: none; } }

.gallery-inner {
  position: relative;
  max-width: 620px;
  text-align: center;
  display: grid;
  justify-items: center;
}
.gallery-inner .eyebrow { color: rgba(255, 255, 255, 0.7); }
.gallery-inner h2 {
  margin: 18px 0 20px;
  font-size: clamp(28px, 4vw, 44px);
  line-height: 1.15;
  letter-spacing: -0.01em;
}
.gallery-inner p {
  max-width: 500px;
  margin-bottom: 34px;
  color: var(--fg-soft);
  line-height: 1.6;
}

/* ==========================================================================
   Bande partenaires (marquee)
   ========================================================================== */

.partners {
  position: relative;
  padding: 64px 0 72px;
  overflow: hidden;
}
@media (min-width: 1040px) { .partners { padding: 76px 0 88px; } }

.partners h2 {
  margin-bottom: 44px;
  font-size: 22px;
  line-height: 1.4;
  text-align: center;
}

.marquee { overflow: hidden; }
.marquee + .marquee { margin-top: 12px; }
.marquee-track {
  display: flex;
  gap: 56px;
  width: max-content;
  padding-right: 56px;
  color: rgba(123, 128, 135, 0.8);
  font-size: 18px;
  font-weight: 700;
  letter-spacing: -0.18px;
  white-space: nowrap;
  animation: marquee-left 46s linear infinite;
}
.marquee--reverse .marquee-track { animation-name: marquee-right; animation-duration: 64s; }

/* Le déplacement est posé en pixels entiers par js/common.js (--marquee-shift)
   et non en pourcentage : -50 % d'une piste de largeur impaire tombe sur un
   demi-pixel, et le texte s'y rastérise flou en permanence puisque
   l'animation ne s'arrête jamais. */
@keyframes marquee-left  { from { transform: translate3d(0, 0, 0); }
                           to   { transform: translate3d(var(--marquee-shift, -50%), 0, 0); } }
@keyframes marquee-right { from { transform: translate3d(var(--marquee-shift, -50%), 0, 0); }
                           to   { transform: translate3d(0, 0, 0); } }

@media (hover: hover) and (pointer: fine) {
  .marquee:hover .marquee-track { animation-play-state: paused; }
}

.partners::before,
.partners::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  width: clamp(60px, 14vw, 200px);
  z-index: 1;
  pointer-events: none;
}
.partners::before { left: 0; background: linear-gradient(90deg, var(--ink), rgba(17, 17, 17, 0)); }
.partners::after { right: 0; background: linear-gradient(90deg, rgba(17, 17, 17, 0), var(--ink)); }

/* ==========================================================================
   Appel à l'action
   ========================================================================== */

.cta { padding: 96px 0; }
@media (min-width: 1040px) { .cta { padding: 150px 0; } }

.cta-inner { display: grid; justify-items: center; text-align: center; }
.cta-inner h2 {
  max-width: 680px;
  margin: 18px 0 22px;
  font-size: clamp(28px, 4vw, 44px);
  line-height: 1.15;
  letter-spacing: -0.01em;
}
.cta-inner p { max-width: 520px; margin-bottom: 40px; color: var(--muted); line-height: 1.6; }

/* ==========================================================================
   Pied de page
   ========================================================================== */

.site-footer { background: var(--ink-deep); padding: 64px 0 40px; }

.footer-cols { display: grid; gap: 40px; }
@media (min-width: 900px) {
  .footer-cols { grid-template-columns: 320px auto auto; justify-content: space-between; gap: 48px; }
}

.footer-brand { display: flex; align-items: center; gap: 10px; margin-bottom: 16px; }
.footer-brand svg { width: 24px; height: 26px; }
.footer-brand span { font-size: 16px; font-weight: 600; }
.footer-blurb { max-width: 320px; color: var(--muted); font-size: 14px; line-height: 1.6; }

.footer-col h2 {
  margin-bottom: 12px;
  color: var(--muted);
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 1.38px;
  text-transform: uppercase;
}
.footer-col li + li { margin-top: 12px; }
.footer-col a, .footer-col li { color: rgba(255, 255, 255, 0.8); font-size: 14px; }
@media (hover: hover) and (pointer: fine) { .footer-col a:hover { color: #fff; } }

.footer-legal { margin-top: 24px; color: var(--muted); font-size: 12.5px; }
.site-footer .rule { margin-top: 40px; }

/* ==========================================================================
   Accessibilité — mouvement réduit
   ========================================================================== */

/* Le scroll inertiel (js/home.js) pilote lui-même l'amorti : laisser en plus
   scroll-behavior: smooth ferait lutter les deux animations l'une contre
   l'autre sur les ancres. */
html.has-smooth-scroll { scroll-behavior: auto; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .reveal { opacity: 1; transform: none; filter: none; transition: none; }
  .marquee-track { animation: none; }
  .hero-bg, .hero-content { transform: none !important; opacity: 1 !important; }
  *, *::before, *::after { transition-duration: 1ms !important; }
}

/* Titre de section nécessaire à la structure mais redondant à l'écran */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ==========================================================================
   Bouton WhatsApp flottant
   ==========================================================================
   z-index 90 : au-dessus du contenu, mais sous l'en-tête (100) et sous les
   surcouches — lecteur de plans, visionneuse de la galerie — qu'il ne doit
   jamais recouvrir. */

.wa-float {
  position: fixed;
  right: max(20px, env(safe-area-inset-right));
  bottom: max(20px, env(safe-area-inset-bottom));
  z-index: 90;
  display: grid;
  place-items: center;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: #25d366;
  color: #fff;
  box-shadow: 0 10px 28px rgba(0, 0, 0, 0.45);
  transition: transform 160ms ease-out, box-shadow 160ms ease-out;
}
.wa-float svg { width: 30px; height: 30px; }
.wa-float:active { transform: scale(0.94); }
@media (hover: hover) and (pointer: fine) {
  .wa-float:hover { transform: scale(1.06); box-shadow: 0 14px 34px rgba(0, 0, 0, 0.55); }
}

/* L'infobulle n'apparaît qu'au pointeur fin : au doigt elle resterait
   collée après le tap, sans moyen de la faire disparaître. */
.wa-float::after {
  content: attr(data-label);
  position: absolute;
  right: calc(100% + 12px);
  padding: 9px 14px;
  border-radius: 999px;
  background: rgba(17, 17, 17, 0.94);
  color: #fff;
  font-size: 13px;
  font-weight: 600;
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transform: translateX(6px);
  transition: opacity 180ms ease-out, transform 180ms var(--ease-out-soft);
}
@media (hover: hover) and (pointer: fine) {
  .wa-float:hover::after,
  .wa-float:focus-visible::after { opacity: 1; transform: none; }
}
@media (max-width: 480px) {
  .wa-float { width: 52px; height: 52px; }
  .wa-float svg { width: 27px; height: 27px; }
}

/* ==========================================================================
   Time-lapse pleine largeur
   ==========================================================================
   Lecture automatique, en boucle, muette et sans aucune interface : la vidéo
   est un décor, pas un lecteur. pointer-events: none la rend inerte, ce qui
   évite au passage que YouTube affiche son propre habillage au survol. */

.video-band {
  position: relative;
  /* width: 100% est indispensable : avec aspect-ratio et une min-height qui
     prend le dessus, une largeur auto se recalcule depuis le ratio et
     dépasse l’écran en étroit. */
  width: 100%;
  margin: 56px 0 0;
  aspect-ratio: 1440 / 620;
  min-height: 280px;
  overflow: hidden;
  background: #000;
}
@media (min-width: 1040px) { .video-band { margin-top: 72px; } }

.video-band .video-media { position: absolute; inset: 0; display: block; overflow: hidden; }
.video-band .video-still { width: 100%; height: 100%; object-fit: cover; }

.video-band iframe {
  position: absolute;
  /* La vidéo est en 16/9, le bandeau est plus large que haut : on agrandit
     l'iframe au-delà du cadre et on la recentre, pour couvrir sans bande
     noire ni déformation — l'équivalent d'un object-fit: cover. */
  top: 50%;
  left: 50%;
  width: 100vw;
  height: 56.25vw;
  min-height: 100%;
  min-width: 177.78vh;
  transform: translate(-50%, -50%);
  border: 0;
  pointer-events: none;
  z-index: 1;
}

.video-band figcaption {
  position: absolute;
  left: clamp(20px, 8.6vw, 124px);
  bottom: clamp(16px, 2.4vw, 28px);
  z-index: 2;
  color: rgba(255, 255, 255, 0.72);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 1.1px;
  text-transform: uppercase;
  text-shadow: 0 1px 12px rgba(0, 0, 0, 0.8);
}

/* L'affiche reste tant que l'iframe n'est pas montée, puis s'efface sous elle */
.video-band.is-playing .video-media { opacity: 0; transition: opacity 500ms ease-out; }

/* Interrupteur de diagnostic : ?sansanim coupe tout mouvement.
   Voir js/common.js — sert à isoler une anomalie d'affichage. */
.sans-anim *,
.sans-anim *::before,
.sans-anim *::after {
  animation: none !important;
  transition: none !important;
  transform: none !important;
  filter: none !important;
  backdrop-filter: none !important;
  scroll-behavior: auto !important;
}
