/* ============================================================
   06 — PAGE ACCUEIL
   Uniquement ce qui est propre à index.html : le hero plein
   écran, et les teasers condensés qui renvoient vers chaque
   page dédiée (Studio, Services, Réalisations, Contact).
   ============================================================ */

/* ---------- SCROLL SNAP ----------
   Chaque section de l'accueil occupe déjà un écran plein
   (min-height:100vh) : un scroll fait glisser jusqu'à la section
   suivante plutôt que de s'arrêter à mi-hauteur entre deux. Scopé à
   index.html — seule page à charger ce fichier — les autres pages
   ont un contenu de longueur variable (texte, grilles) pas adapté à
   ce comportement. scroll-snap-stop:always empêche un swipe rapide
   de sauter une section entière. */
html{ scroll-snap-type: y mandatory; }
.hero, .pillars, .teaser-studio, .teaser-work, footer{
  scroll-snap-align: start;
  scroll-snap-stop: always;
}

/* ---------- HERO ---------- */
.hero{
  position:relative;
  background:var(--ink);
  color:var(--text-light);
  min-height:100vh;
  min-height:100svh;
  min-height:100dvh; /* repli avant le premier calcul JS ci-dessous */
  min-height:var(--vh100, 100dvh); /* hauteur visible réelle, mesurée en JS (voir js/main.js) — dvh seul restait parfois faux une fois la barre d'adresse repliée pendant le scroll */
  display:flex;
  flex-direction:column;
  justify-content:center;
  padding:132px 0 96px;
  overflow:hidden;
  isolation:isolate;
}
.hero::before{
  content:"";
  position:absolute; inset:0;
  background:
    radial-gradient(ellipse 700px 500px at 82% 20%, rgba(78,85,160,0.35), transparent 60%),
    radial-gradient(ellipse 500px 400px at 10% 90%, rgba(185,135,60,0.10), transparent 60%);
  z-index:-1;
}
/* Sélecteur à deux classes (.hero .hero-content) plutôt que
   .hero-content seul : garantit que ça l'emporte sur .container
   (même s'il était rechargé/mis en cache après ce fichier) au lieu
   de compter sur l'ordre de chargement des <link> pour départager
   une spécificité CSS identique. */
.hero .hero-content{
  position:relative;
  z-index:1; /* passe au-dessus du filigrane empreinte */
  width:100%;
  max-width:none; /* le hero ignore le plafond de 1180px du .container
    partagé : sur grand écran, le texte démarre près du vrai bord
    gauche au lieu de flotter dans un îlot centré avec une grande
    marge vide (l'empreinte en filigrane, elle, comble déjà le
    même vide côté droit). */
  margin-left:0;
  margin-right:0;
  padding-left:var(--edge);
  padding-right:var(--edge);
  box-sizing:border-box;
}
.hero-eyebrow{ color:var(--indigo-lt); margin-bottom:34px; }
.hero h1{
  /* Poppins Bold plutôt que Super Nugget (var(--display)) : la charte
     réserve la police arrondie aux "gros titres", mais sur un H1 pleine
     largeur elle lit plus enfantin que premium. Poppins reste dans la
     charte (stand-in Gilroy) — on change quel rôle porte le H1, pas la
     liste des polices de la marque. Décision explicite, pas un oubli :
     voir 00-tokens.css pour le détail de la charte. */
  font-family:var(--heading);
  /* Clamp réduit vs l'ancien 6.2vw/84px : Poppins Bold est nettement
     plus large par caractère que Super Nugget au même corps — avec
     l'ancienne formule, "pensée jusqu'au moindre détail." débordait
     sur une 3e ligne (testé 1024→1920px), poussant .hero-meta-row
     hors de l'écran alors que le hero est calé sur 100vh pour le
     scroll-snap. Cette formule garde 2 lignes sur toute la plage. */
  font-size:clamp(40px, 5.2vw, 72px);
  line-height:1.1;
  font-weight:700;
  letter-spacing:-0.01em;
  /* Pas de max-width en ch : le retour à la ligne est géré par le
     <br> manuel dans le HTML (2 lignes voulues), pas un plafond
     de largeur qui casserait les lignes ailleurs. */
}
.hero h1 em{
  font-style:italic;
  font-weight:600;
  color:var(--indigo-lt);
}
/* Retours à la ligne réservés au mobile — masqués par défaut, activés
   sous 560px (voir RESPONSIVE) pour découper le H1 en 4 lignes
   courtes plutôt que de laisser le navigateur casser au hasard. */
.hero h1 br.mobile-break{ display:none; }
.hero p.lead{
  margin-top:34px;
  font-size:18px;
  line-height:1.7;
  color:var(--text-light-dim);
  max-width:56ch;
}
.hero-actions{
  margin-top:52px;
  display:flex; align-items:center; gap:22px; flex-wrap:wrap;
}
.hero-actions .scroll-cue{
  position:relative;
  font-family:var(--body); font-size:11.5px; letter-spacing:0.1em;
  color:var(--text-light-dim);
  display:inline-flex; align-items:center; gap:8px;
  padding-bottom:4px;
  transition:color .25s ease;
}
.hero-actions .scroll-cue:hover{ color:var(--text-light); }
.hero-actions .scroll-cue::after{
  content:"";
  position:absolute; left:0; right:0; bottom:0;
  height:1px; background:currentColor;
  transform:scaleX(0); transform-origin:left;
  transition:transform .35s ease;
}
.hero-actions .scroll-cue:hover::after{ transform:scaleX(1); }

/* Indicateur de scroll — signale que le hero occupe tout l'écran
   et qu'il y a du contenu en dessous. Purement décoratif. */
.hero-scroll{
  position:absolute; left:50%; bottom:40px; transform:translateX(-50%);
  width:22px; height:36px;
  border:1px solid rgba(255,255,255,0.35);
  border-radius:12px;
  display:flex; justify-content:center;
  padding-top:6px;
}
.hero-scroll::before{
  content:"";
  width:3px; height:6px;
  border-radius:2px;
  background:var(--text-light);
  animation:hero-scroll-dot 1.8s ease-in-out infinite;
}
@keyframes hero-scroll-dot{
  0%{ opacity:1; transform:translateY(0); }
  70%{ opacity:0; transform:translateY(12px); }
  100%{ opacity:0; transform:translateY(0); }
}

/* Empreinte animée — filigrane en arrière-plan du hero, calée dans
   l'angle bas-droit (desktop) plutôt que centrée verticalement.
   .fingerprint-wrap porte le parallax souris (JS, translate3d) ;
   .fingerprint-wrap svg porte la respiration (scale) — deux éléments
   séparés car une animation CSS et un style.transform inline sur le
   MÊME élément se marchent dessus (l'animation regagne la main à
   chaque frame et écrase la translation posée par le JS). */
.fingerprint-wrap{
  position:absolute;
  bottom:-14%; right:-10%;
  width:min(70vw, 940px);
  height:min(70vw, 940px);
  opacity:0.36;
  pointer-events:none;
  z-index:0;
  will-change:transform;
}
.fingerprint-wrap svg{
  width:100%; height:100%; overflow:visible;
  animation:hero-fingerprint-breathe 8.5s cubic-bezier(.45,0,.55,1) 2.3s infinite;
}
.fingerprint-wrap path{
  fill:#FFFFFF;
  fill-opacity:0;
  stroke:#FFFFFF;
  stroke-width:1.4;
  stroke-opacity:0;
  transition:
    stroke-dashoffset 1.15s cubic-bezier(.5,0,.3,1),
    stroke-opacity .35s ease;
}
/* Étape 1 (JS ajoute .in puis force stroke-dashoffset à 0) : le
   sillon se trace à l'encre, du centre de l'empreinte vers l'extérieur
   (ordre calculé en JS via getBBox — pas l'ordre du <path> dans le
   SVG). Étape 2 (.filled, ajoutée ~1.2s plus tard) : le tracé cède la
   place au remplissage plein, comme une encre qui se pose. */
.fingerprint-wrap path.in{ stroke-opacity:0.85; }
.fingerprint-wrap path.filled{
  fill-opacity:1;
  stroke-opacity:0;
  transition:fill-opacity .6s ease, stroke-opacity .5s ease;
}

/* Respiration lente une fois l'empreinte révélée — signale un
   filigrane vivant sans distraire du texte au premier plan. Amplitude
   volontairement discrète (1 → 1.01) : un souffle, pas un battement. */
@keyframes hero-fingerprint-breathe{
  0%, 100%{ transform:scale(1); }
  50%{ transform:scale(1.01); }
}

.hero-meta-row{
  margin-top:100px;
  max-width:760px; /* évite que les 3 blocs ne s'étirent à l'excès sur très grand écran */
  display:grid;
  grid-template-columns:repeat(3,1fr);
  gap:32px;
  border-top:1px solid var(--ink-line);
  padding-top:28px;
}
.hero-meta-row .m-label{
  font-family:var(--body); font-size:10.5px; letter-spacing:0.14em;
  color:var(--text-light-dim); text-transform:uppercase;
  margin-bottom:8px;
}
.hero-meta-row .m-value{
  font-family:var(--display); font-size:19px; color:var(--text-light);
}

/* ---------- SECTION 2 — PILIERS ----------
   Les deux grandes familles du métier, en un coup d'œil :
   construire l'identité, puis l'imprimer fidèlement. */
/* Plein écran, comme le hero et le teaser Studio — chaque section
   "moment" de l'accueil occupe tout l'écran plutôt qu'un padding fixe. */
.pillars{
  background:var(--paper-gray);
  min-height:100vh;
  min-height:100svh;
  min-height:100dvh;
  min-height:var(--vh100, 100dvh); /* voir .hero — hauteur visible réelle mesurée en JS */
  display:flex;
  flex-direction:column;
  justify-content:flex-start; /* pas de centrage vertical parfait : sur
    un grand écran, un centrage strict laisse un vide énorme au-dessus
    du texte. On ancre en haut avec un padding fixe à la place. */
  padding:140px 0 60px; /* -20px en haut ; bas resserré pour que les
    4 cartes tiennent dans les 100svh avec le texte d'intro. */
}

/* En-tête de section propre aux Piliers (pas le .section-head
   générique partagé par tout le site) : texte plus compact pour
   laisser de la place aux 4 cartes sur un seul écran. */
.pillars .section-head{
  max-width:none; /* le H1 doit tenir sur une seule ligne */
  margin-bottom:40px;
}
.pillars .section-head .eyebrow{ margin-bottom:0; } /* -20px : le H1 remonte d'autant */
.pillars .section-head h2{ white-space:nowrap; } /* débordait sur mobile — réinitialisé + <br> dédié, voir RESPONSIVE */
.pillars .section-head h2 br.mobile-break{ display:none; }
.pillars .section-head p{
  margin-top:0; /* -20px : encore un cran plus haut */
  max-width:880px; /* recalé pour retomber sur 2 lignes au lieu de 3 */
}
/* Même correctif que le hero (.hero .hero-content) : ignore
   complètement le plafond de 1180px du .container partagé au lieu de
   se contenter d'un plafond plus large. Sur grand écran, un simple
   plafond (même à 1540px) laisse encore un vide symétrique de chaque
   côté ; ici les cartes s'étendent jusqu'à --edge du vrai bord. */
.pillars > .container{
  max-width:none;
  width:100%;
  margin-left:0;
  margin-right:0;
  padding-left:var(--edge);
  padding-right:var(--edge);
  box-sizing:border-box;
}
/* Grille 2x2 — chaque carte a une position explicite (:nth-of-type
   compte les <a> entre eux, indépendamment des <div> diviseurs
   intercalés dans le HTML). Le placement automatique se déroberait
   ici : le diviseur vertical occupe toute la colonne centrale sur les
   3 pistes de hauteur, ce qui laissait l'algorithme de repli pousser
   les cartes suivantes dans de mauvaises cases (chevauchement observé
   à l'écran). Explicite = sans ambiguïté. */
.pillars-grid{
  display:grid;
  grid-template-columns:1fr 32px 1fr;
  grid-template-rows:auto 32px auto;
  border:1px solid var(--paper-line);
}
.pillar-card:nth-of-type(1){ grid-column:1; grid-row:1; }
.pillar-card:nth-of-type(2){ grid-column:3; grid-row:1; }
.pillar-card:nth-of-type(3){ grid-column:1; grid-row:3; }
.pillar-card:nth-of-type(4){ grid-column:3; grid-row:3; }
/* .pillars-grid .pillar-card (2 classes) plutôt que .pillar-card seul :
   même renfort de spécificité que .hero .hero-content, pour que ce
   padding l'emporte à coup sûr sur toute autre règle à spécificité
   égale, peu importe l'ordre de chargement des fichiers CSS. */
.pillars-grid .pillar-card{
  position:relative;
  overflow:hidden;
  background:var(--paper);
  padding:40px 44px; /* resserré (était 81px) : 4 cartes en 2x2 tiennent
    moins large en hauteur qu'une seule rangée de 2. */
  transition:background .3s ease, transform .3s ease, box-shadow .3s ease;
}
.pillar-card:hover{
  background:var(--paper-dim);
  transform:translateY(-4px);
  box-shadow:0 20px 40px -20px rgba(0,15,159,0.25);
}
/* La flèche "Découvrir" réagit au survol de toute la carte (elle est
   cliquable en entier), pas seulement quand le curseur est pile sur
   le petit lien en bas. */
.pillar-card:hover .link-arrow .arrow{ transform:translateX(5px); }

/* Repères de calage au survol — même motif que les boutons .btn-brass,
   pour une signature d'interaction cohérente sur tout le site. */
.pillar-card::before,
.pillar-card::after{
  content:"";
  position:absolute;
  width:14px; height:14px;
  opacity:0;
  border-color:var(--indigo);
  transition:opacity .3s ease, transform .3s ease;
  pointer-events:none;
}
.pillar-card::before{
  top:16px; left:16px;
  border-top:1.5px solid; border-left:1.5px solid;
  transform:translate(6px, 6px);
}
.pillar-card::after{
  bottom:16px; right:16px;
  border-bottom:1.5px solid; border-right:1.5px solid;
  transform:translate(-6px, -6px);
}
.pillar-card:hover::before,
.pillar-card:hover::after{ opacity:0.6; transform:translate(0,0); }

/* Grand numéro en filigrane — élément dédié (pas un pseudo-élément :
   ::before/::after sont déjà pris par les repères de calage), très
   pâle, en fond de carte. aria-hidden dans le HTML, purement décoratif. */
.pillar-bg-num{
  position:absolute;
  top:-0.12em; right:24px;
  font-family:var(--display);
  font-size:220px;
  line-height:1;
  color:rgba(0,15,159,0.055);
  z-index:0;
  transition:color .3s ease;
  user-select:none;
  /* Léger va-et-vient horizontal — même famille de courbe que la
     respiration de l'empreinte du hero, pour une signature de
     mouvement cohérente sur tout le site plutôt qu'un filigrane figé. */
  animation:pillar-num-drift 9s cubic-bezier(.45,0,.55,1) infinite;
}
.pillar-card:hover .pillar-bg-num{ color:rgba(0,15,159,0.09); }

@keyframes pillar-num-drift{
  0%, 100%{ transform:translateX(0); }
  50%{ transform:translateX(-36px); }
}

/* Tout le contenu utile repasse au-dessus du filigrane */
.pillar-icon,
.pillar-card .num,
.pillar-card h3,
.pillar-card p,
.pillar-card .tag-row,
.pillar-card .link-arrow{ position:relative; z-index:1; }

.pillar-icon{
  width:34px; height:34px;
  color:var(--indigo);
}
.pillar-icon svg{ width:100%; height:100%; stroke:currentColor; fill:none; stroke-width:1.3; }

.pillar-card .num{
  margin-top:14px;
  font-family:var(--body); font-weight:600; font-size:12px; color:var(--indigo);
  letter-spacing:0.14em; text-transform:uppercase;
}
.pillar-card h3{
  margin-top:8px;
  font-size:24px;
  font-weight:500;
  color:var(--text-dark);
  white-space:nowrap; /* "Impression & Supports" doit tenir sur une ligne */
}
.pillar-card p{
  margin-top:10px;
  color:var(--text-dim);
  font-size:14.5px;
  line-height:1.55;
  max-width:38ch;
}
.pillar-card .tag-row{ margin-top:14px; margin-bottom:16px; }
.pillar-card .tag{
  border:1px solid var(--paper-line);
  color:var(--text-dim);
}

/* Diviseurs façon repère de coupe (trait pointillé + amorces) — un
   vertical, un horizontal, qui se croisent au centre de la grille 2x2. */
.pillars-divider{
  grid-column:2;
  grid-row:1/4; /* span les 2 rangées de cartes + la piste centrale */
  position:relative;
  border-left:1px dashed var(--paper-line);
  margin:0 auto;
}
.pillars-divider::before,
.pillars-divider::after{
  content:"";
  position:absolute; left:-6px;
  width:13px; height:1.5px;
  background:var(--indigo);
}
.pillars-divider::before{ top:0; }
.pillars-divider::after{ bottom:0; }

.pillars-divider-h{
  /* Les deux axes doivent être explicites (pas seulement la colonne) :
     le diviseur vertical occupe déjà toute la colonne 2 sur les 3
     rangées, donc un placement auto sur la rangée pousserait celui-ci
     dans une rangée fantôme au lieu de croiser le vertical au centre. */
  grid-column:1/4;
  grid-row:2;
  position:relative;
  border-top:1px dashed var(--paper-line);
  margin:auto 0;
}
.pillars-divider-h::before,
.pillars-divider-h::after{
  content:"";
  position:absolute; top:-6px;
  width:1.5px; height:13px;
  background:var(--indigo);
}
.pillars-divider-h::before{ left:0; }
.pillars-divider-h::after{ right:0; }

/* ---------- SECTION 3 — STUDIO (teaser) ----------
   Plein écran comme le hero : c'est le moment "manifeste" de la
   page, il mérite le même traitement que l'entrée. */
.teaser-studio{
  background:var(--ink);
  color:var(--text-light);
  min-height:100vh;
  min-height:100svh;
  min-height:100dvh;
  min-height:var(--vh100, 100dvh); /* voir .hero — hauteur visible réelle mesurée en JS */
  display:flex;
  flex-direction:column;
  justify-content:center;
  position:relative;
  /* Pas d'overflow:hidden ici : la galerie (voir .teaser-studio-gallery)
     doit pouvoir dépasser le haut/bas de la section. Le filigrane
     empreinte, lui, reste cadré via son propre wrapper ci-dessous —
     seule la galerie est censée déborder. */
}
/* Wrapper de cadrage dédié au filigrane : mêmes dimensions que la
   section (inset:0), mais avec son overflow:hidden propre — la galerie
   n'est pas un enfant de ce wrapper, donc pas concernée. */
.teaser-studio-clip{
  position:absolute; inset:0;
  overflow:hidden;
  z-index:0;
  pointer-events:none;
}
/* .teaser-studio .teaser-studio-grid (2 classes) plutôt que
   .teaser-studio-grid seul : même motif défensif que .hero
   .hero-content — l'emporte sur le plafond de 1180px de .container
   quel que soit l'ordre de chargement des feuilles de style. La
   galerie doit atteindre le vrai bord droit de l'écran, pas s'arrêter
   au conteneur centré comme le reste du site. */
.teaser-studio .teaser-studio-grid{
  position:relative; /* ancre les repères de calage (::before/::after) */
  z-index:2;
  display:grid;
  grid-template-columns:1.05fr 32px 0.95fr;
  align-items:stretch;
  min-height:min(94vh, 880px); /* la cellule remplit quasi toute la section — le débordement vient en plus, voir .teaser-studio-gallery */
  max-width:none;
  margin-left:0;
  margin-right:0;
  padding-left:var(--edge);
  padding-right:var(--edge);
  box-sizing:border-box;
}
.teaser-studio-text{
  position:relative;
  display:flex;
  flex-direction:column;
  justify-content:center; /* le bloc texte reste centré même si la cellule s'étire à la hauteur de la galerie */
}

/* Diviseur vertical façon repère de coupe — même motif que celui des
   Piliers, pour que les deux sections se répondent visuellement. */
.teaser-studio-divider{
  align-self:stretch;
  position:relative;
  border-left:1px dashed var(--ink-line);
  margin:0 auto;
}
.teaser-studio-divider::before,
.teaser-studio-divider::after{
  content:"";
  position:absolute; left:-6px;
  width:13px; height:1.5px;
  background:var(--indigo-lt);
}
.teaser-studio-divider::before{ top:0; }
.teaser-studio-divider::after{ bottom:0; }

/* position:relative + z-index:1 — repassent au-dessus du guillemet en
   filigrane (position:absolute, z-index:0, même colonne texte). */
.teaser-studio .eyebrow{
  position:relative; z-index:1;
  color:var(--text-light); margin-bottom:32px;
}
.teaser-studio .pull{
  position:relative; z-index:1;
  font-family:var(--display);
  font-size:clamp(30px, 3.6vw, 46px);
  line-height:1.3;
  font-weight:400;
  color:var(--text-light);
}
.teaser-studio .pull em{ font-style:italic; color:var(--indigo-lt); font-weight:500; }
.teaser-studio .link-arrow{ position:relative; z-index:1; margin-top:36px; }
/* Deux versions de la citation dans le HTML : la longue (desktop, par
   défaut) et une version raccourcie réservée au mobile (voir
   RESPONSIVE) — pas juste une taille de police réduite, un texte plus
   court, pour que l'aplat de texte reste compact sur le fond photo. */
.teaser-studio .pull-short{ display:none; }

/* ---------- Colonne "galerie" ----------
   Collage de photos des réalisations (mockups déjà utilisés sur
   services.html), en colonnes décalées façon mur d'inspiration.
   Révélation déclenchée par la même classe .in que les repères de
   calage du bloc texte (posée par l'observer générique de .reveal
   sur .teaser-studio-grid) : pas de JS supplémentaire. */
.teaser-studio-gallery{
  position:relative;
  display:flex;
  gap:14px;
  align-items:stretch;
  top:-70px;
  height:calc(100% + 140px); /* dépasse la section de 70px en haut et en bas */
  /* Horloge de scroll nommée et partagée par les 6 photos (voir plus
     bas, animation-timeline:--tsg-scroll sur .tsg-item) : en s'appuyant
     sur CE conteneur (haut d'environ un écran) plutôt que sur chaque
     petite photo individuellement, la progression dispose d'une vraie
     course longue — le glissement se voit nettement au lieu de se
     terminer dans les 30 premiers pixels de scroll. */
  view-timeline-name:--tsg-scroll;
}
.tsg-col{
  flex:1;
  min-width:0;
  height:100%;
  display:flex;
  flex-direction:column;
  gap:14px;
}
.tsg-col-offset{ margin-top:56px; }
/* flex:1 (plutôt qu'un aspect-ratio fixe) : chaque photo se partage la
   hauteur totale de sa colonne, ratio ajusté par object-fit:cover —
   c'est ce qui fait "monter" la galerie jusqu'en haut et en bas de la
   section au lieu de rester une bande centrée. tsg-tall grandit un peu
   plus que sa voisine pour garder l'asymétrie du mur de références. */
.tsg-item{
  flex:1;
  min-height:0;
  overflow:hidden;
  background:var(--ink-soft);
  /* Révélation "rideau qui se lève" — écho direct au "On la révèle" du
     texte : la photo apparaît comme tirée hors d'un cache, pas juste
     un fondu. clip-path anime la hauteur visible, opacity+translateY
     ajoutent la même retombée douce que le reste du site. */
  clip-path:inset(100% 0 0 0);
  opacity:0;
  transform:translateY(28px) scale(0.97);
  transition:clip-path .85s cubic-bezier(.16,.7,.2,1), opacity .6s ease, transform .85s cubic-bezier(.16,.7,.2,1);
}
.tsg-item.tsg-tall{ flex:1.35; }
.teaser-studio-grid.in .tsg-item{
  clip-path:inset(0 0 0 0);
  opacity:1;
  transform:translateY(0) scale(1);
}
.tsg-col:nth-child(1) .tsg-item:nth-child(1){ transition-delay:.05s; }
.tsg-col:nth-child(1) .tsg-item:nth-child(2){ transition-delay:.32s; }
.tsg-col:nth-child(2) .tsg-item:nth-child(1){ transition-delay:.16s; }
.tsg-col:nth-child(2) .tsg-item:nth-child(2){ transition-delay:.43s; }
.tsg-col:nth-child(3) .tsg-item:nth-child(1){ transition-delay:.10s; }
.tsg-col:nth-child(3) .tsg-item:nth-child(2){ transition-delay:.37s; }
.tsg-item img{
  width:100%; height:100%;
  object-fit:cover;
  display:block;
  transition:transform .7s cubic-bezier(.2,.8,.2,1);
}
.tsg-item:hover img{ transform:scale(1.06); }

/* ---------- Galerie : glissement asservi au scroll ----------
   Amélioration progressive au-dessus du rideau clip-path ci-dessus
   (qui reste le filet de sécurité pour les navigateurs sans support).
   En descendant, la photo glisse depuis le côté jusqu'à sa place ; en
   remontant, exactement le même mouvement se joue à l'envers, sans
   JS, calculé au frame près par le compositeur.

   animation-timeline:--tsg-scroll (plutôt que view() directement sur
   chaque .tsg-item) : les 6 photos partagent l'horloge de scroll du
   conteneur .teaser-studio-gallery (haut d'environ un écran) au lieu
   d'avoir chacune la sienne, calée sur sa propre (petite) hauteur —
   sans ça, la course ne durait que la hauteur de la photo elle-même,
   beaucoup trop courte pour se voir/se savourer au scroll. */
@supports (animation-timeline: view()) {
  .tsg-col:nth-child(1){ --tsg-x: 70px; }
  .tsg-col:nth-child(2){ --tsg-x: 110px; }
  .tsg-col:nth-child(3){ --tsg-x: 150px; }

  .tsg-item{
    clip-path:none;
    transition:none; /* le scrubbing pilote transform/opacity image par image ; une transition CSS en plus créerait un décalage/à-coup */
    animation-name:tsg-slide-in;
    animation-timing-function:linear; /* linéaire : la photo doit suivre le doigt/la molette au pixel, pas une courbe qui continuerait de bouger une fois le scroll arrêté */
    animation-fill-mode:both;
    animation-timeline:--tsg-scroll;
    animation-range:entry; /* la course dure tout le temps que met la galerie à entrer dans l'écran — nettement plus lent et observable */
  }

}
/* Le parallax vertical par colonne (vitesses différentes selon la
   colonne, sur toute la traversée de la section) est piloté par GSAP
   ScrollTrigger — voir js/main.js. Pas en animation-timeline:view()
   comme tsg-slide-in ci-dessus : testé en conditions réelles (scroll
   molette ET programmatique), animation-range:cover ne s'actualise
   jamais après le premier calcul sur cette page précise — le
   applyprogress reste figé quel que soit le scroll, alors qu'un cas
   isolé minimal avec la même structure fonctionne. Cause exacte non
   identifiée (piste explorée et écartée : scroll-snap, display:flex,
   multi-consommateurs du même timeline nommé, JS de la page — le gel
   persiste même tout JS coupé). tsg-slide-in au-dessus fonctionne
   probablement pour la même raison douteuse ; à revalider avant de
   compter dessus. */
@keyframes tsg-slide-in{
  from{ opacity:.35; transform:translateX(var(--tsg-x, 110px)) scale(.94); }
  to{ opacity:1; transform:translateX(0) scale(1); }
}

/* Révélation mot par mot au scroll (voir js/main.js, [data-reveal-words]) */
.teaser-studio .pull .word{
  display:inline-block;
  opacity:0;
  transform:translateY(10px);
  transition:opacity .5s cubic-bezier(.16,.7,.2,1), transform .5s cubic-bezier(.16,.7,.2,1);
}
.teaser-studio .pull .word.in{ opacity:1; transform:translateY(0); }

/* Repères de calage qui encadrent la citation à l'entrée dans le champ
   de vision — même motif que boutons/cartes, déclenché par la classe
   .in déjà posée par l'observer générique de .reveal (pas de JS en
   plus). Un temps de retard (.3s) pour arriver juste après le texte. */
.teaser-studio .container::before,
.teaser-studio .container::after{
  content:"";
  position:absolute;
  width:16px; height:16px;
  opacity:0;
  border-color:var(--indigo-lt);
  transition:opacity .6s ease .3s, transform .6s ease .3s;
}
.teaser-studio .container::before{
  top:-28px; left:-28px;
  border-top:1.5px solid; border-left:1.5px solid;
  transform:translate(8px, 8px);
}
.teaser-studio .container::after{
  bottom:-28px; right:-28px;
  border-bottom:1.5px solid; border-right:1.5px solid;
  transform:translate(-8px, -8px);
}
.teaser-studio .container.in::before,
.teaser-studio .container.in::after{ opacity:0.7; transform:translate(0,0); }

/* Guillemet géant en filigrane — décalé en haut à gauche du bloc de
   texte plutôt que centré derrière (il se noyait dans l'empreinte,
   toutes deux au même endroit). Position relative au conteneur, donc
   solidaire du texte quelle que soit la largeur d'écran. */
.teaser-quote-mark{
  position:absolute;
  top:-0.48em; left:-0.1em;
  font-family:var(--display);
  font-size:clamp(140px, 13vw, 220px);
  line-height:1;
  color:rgba(255,255,255,0.09);
  z-index:0;
  pointer-events:none;
  user-select:none;
}

/* Empreinte reléguée en coin bas-droit (même logique que le hero) —
   laisse le centre libre pour le guillemet et le texte, plutôt que de
   se superposer dessus. */
.teaser-studio .fp-watermark{
  width:min(48vw, 640px); height:min(48vw, 640px);
  top:auto; left:auto;
  bottom:-16%; right:-8%;
  transform:none;
  z-index:0;
  animation:teaser-fingerprint-breathe 8.5s cubic-bezier(.45,0,.55,1) infinite;
}
@keyframes teaser-fingerprint-breathe{
  0%, 100%{ transform:scale(1); }
  50%{ transform:scale(1.04); }
}

/* ---------- SECTION 4 — RÉALISATIONS (teaser) ----------
   Grille asymétrique propre au teaser accueil (pas realisations.html,
   qui garde une grille régulière pour parcourir tout le catalogue) :
   une pièce mise en avant à gauche, deux en pile à droite, séparées
   par des diviseurs façon repère de coupe — écho des Piliers et de
   Notre Approche plutôt qu'une simple grille à cases identiques. */
/* Plein écran comme les 3 sections précédentes — mais ancré en haut
   (flex-start + padding fixe) plutôt que centré : même choix que les
   Piliers, pour la même raison (un centrage strict aurait laissé un
   vide disproportionné selon la hauteur réelle du contenu). */
.teaser-work{
  background:var(--paper);
  min-height:100vh;
  min-height:100svh;
  min-height:100dvh;
  min-height:var(--vh100, 100dvh); /* voir .hero — hauteur visible réelle mesurée en JS */
  display:flex;
  flex-direction:column;
  justify-content:flex-start;
  padding:120px 0 40px;
}
/* Espace resserré au-dessus de la grille (le .section-head générique
   partagé prévoit 64px, trop pour que tout tienne ici). */
.teaser-work .section-head{ margin-bottom:36px; }
/* La hauteur de la grille est pilotée directement (min(...vh, ...px))
   plutôt que dérivée d'un aspect-ratio sur les cartes : un ratio fixe
   (ex. 1:1) donne une hauteur qui dépend de la largeur de colonne —
   imprévisible et, sur un écran large, largement plus haute que
   100svh (constaté à l'écran : la 3e carte débordait hors champ).
   Ici les 2 rangées se partagent une hauteur totale plafonnée, la
   carte vedette s'étire dessus (grid-row:1/3), quelle que soit la
   largeur de l'écran. */
.teaser-work .work-grid{
  max-width:1400px;
  margin:0 auto;
  height:min(30vh, 320px);
  margin-bottom:50px; /* espace demandé entre le bas de la grille et ce qui suit */
}
/* Même correctif que .hero .hero-content et .pillars > .container :
   ignore le plafond de 1180px du .container partagé, marge pilotée
   uniquement par --edge jusqu'au vrai bord de l'écran. */
.teaser-work > .container{
  max-width:none;
  width:100%;
  margin-left:0;
  margin-right:0;
  padding-left:var(--edge);
  padding-right:var(--edge);
  box-sizing:border-box;
}
.teaser-work .work-grid{
  position:relative;
  grid-template-columns:1.6fr 1fr;
  grid-template-rows:1fr 1fr;
  gap:0;
  background:var(--paper);
}
.teaser-work .work-grid::before{ /* diviseur vertical, pleine hauteur */
  content:"";
  position:absolute;
  top:0; bottom:0; left:61.5%;
  border-left:1px dashed var(--paper-line);
  z-index:1;
}
.teaser-work .work-grid::after{ /* diviseur horizontal, colonne de droite seulement */
  content:"";
  position:absolute;
  left:61.5%; right:0; top:50%;
  border-top:1px dashed var(--paper-line);
  z-index:1;
}
/* Aucune des deux cartes n'a de ratio fixe : leur hauteur vient des
   rangées de la grille (1fr chacune, elles-mêmes bornées par la
   hauteur totale fixée sur .work-grid ci-dessus), pas l'inverse — un
   ratio comme 1:1 donnerait une hauteur qui dépend de la largeur de
   colonne, imprévisible sur grand écran (constaté à l'écran : la
   grille débordait largement de la section). La vedette s'étire sur
   les 2 rangées réunies (grid-row:1/3, align-self:stretch par défaut). */
.teaser-work .work-card.work-featured{ grid-column:1; grid-row:1/3; }
.teaser-work .work-card:not(.work-featured):nth-of-type(2){ grid-column:2; grid-row:1; }
.teaser-work .work-card:not(.work-featured):nth-of-type(3){ grid-column:2; grid-row:2; }
/* Le monogramme partagé (04-sections.css) est dimensionné en vw, pensé
   pour des cartes en aspect-ratio 4/5 (realisations.html). Ici la
   grille a une hauteur fixée en vh/px (voir plus haut), complètement
   indépendante de la largeur d'écran — un monogramme en vw ne
   rétrécissait donc pas avec la grille. Repris en vh pour les deux
   tailles de carte de ce teaser. */
.teaser-work .work-card:not(.work-featured) .work-monogram{ font-size:clamp(22px, 6vh, 40px); }
.teaser-work .work-featured .work-monogram{ font-size:clamp(36px, 11vh, 88px); }

.teaser-work .section-foot{
  margin-top:36px;
  display:flex; justify-content:center;
}

/* ---------- RESPONSIVE ---------- */
@media (max-width: 980px){
  /* +50px demandés par-dessus la hauteur d'écran réelle — chaque
     section déborde légèrement plutôt que de s'arrêter pile au bord.
     100svh (fixe) plutôt que var(--vh100) : la valeur mesurée en JS
     suit la barre d'adresse de Safari en direct (repliée au chargement
     puis redéployée aussitôt après), ce qui faisait visiblement
     "rétrécir" la section juste après l'arrivée sur la page. svh
     correspond déjà à l'état barre déployée — jamais de saut ensuite. */
  .hero, .pillars, .teaser-studio, .teaser-work{
    min-height: calc(100svh + 50px);
  }

  .hero{ padding:120px 0 64px; }
  .fingerprint-wrap{ width:80vw; height:80vw; opacity:0.2; right:-20%; }
  .hero-meta-row{ grid-template-columns:1fr; gap:22px; margin-top:56px; }
  .hero-scroll{ display:none; }

  /* Titre Piliers : le nowrap desktop (une seule ligne) déborderait
     sur mobile — repasse en 2 lignes maîtrisées via le <br> dédié
     plutôt qu'un retour à la ligne au hasard du navigateur. */
  .pillars .section-head h2{ white-space:normal; }
  .pillars .section-head h2 br.mobile-break{ display:inline; }

  /* Cartes piliers : carrousel horizontal avec "peek" (le bord de la
     carte suivante dépasse) dès qu'on quitte le desktop — pas de palier
     intermédiaire empilé, la grille 2x2 est un format desktop, en
     dessous de 980px c'est un slide. Swipe au doigt, calage franc
     grâce au scroll-snap. */
  .pillars-grid{
    display:flex; /* grid-column/grid-row des cartes deviennent inertes hors contexte grid */
    border:none;
    gap:14px;
    overflow-x:auto;
    scroll-snap-type:x mandatory;
    /* Marge gauche/droite = (100% - largeur carte)/2 : permet à la
       toute première et à la toute dernière carte de se centrer aussi,
       pas seulement celles du milieu qui ont des voisines des 2 côtés. */
    padding-left:calc((100% - 82%) / 2);
    padding-right:calc((100% - 82%) / 2);
    padding-bottom:20px; /* dégagement visuel, la scrollbar est masquée */
    -webkit-overflow-scrolling:touch;
    scrollbar-width:none;
  }
  .pillars-grid::-webkit-scrollbar{ display:none; }
  .pillars-divider, .pillars-divider-h{ display:none; }
  .pillar-card{
    flex:0 0 82%;
    scroll-snap-align:center; /* la carte active est centrée à l'écran, pas calée à gauche */
    border:1px solid var(--paper-line);
    border-radius:var(--radius);
  }
  /* Spécificité .pillars-grid .pillar-card (2 classes) requise pour
     l'emporter sur la règle desktop de même sélecteur (padding:81px
     48px) — un simple .pillar-card ne suffit pas, quel que soit
     l'ordre des règles dans la cascade. */
  .pillars-grid .pillar-card{ padding:36px 28px; }
  .pillar-card h3{ white-space:normal; }
  .pillar-bg-num{ font-size:150px; animation:pillar-num-drift 6.5s cubic-bezier(.45,0,.55,1) infinite; }

  /* Carte hors-champ discrète (réduite, estompée), pleine taille/opacité
     en devenant la carte active. .in-view vient d'un IntersectionObserver
     dédié au carrousel (voir js/main.js), rejoué à chaque swipe —
     contrairement à .reveal qui ne joue qu'une fois au chargement. */
  .pillar-card{
    opacity:0.45;
    transform:scale(0.93);
    transition:opacity .45s cubic-bezier(.16,.7,.2,1), transform .45s cubic-bezier(.16,.7,.2,1), background .3s ease, box-shadow .3s ease;
  }
  .pillar-card.in-view{
    opacity:1;
    transform:scale(1);
  }

  /* Réalisations (teaser accueil uniquement — .teaser-work scope,
     realisations.html garde sa grille classique) : même carrousel
     horizontal centré que les Piliers, pour une cohérence de pattern
     de navigation sur tout le mobile plutôt qu'un empilement vertical. */
  .teaser-work .work-grid{
    display:flex;
    border:none;
    gap:14px;
    overflow-x:auto;
    scroll-snap-type:x mandatory;
    padding-left:calc((100% - 78%) / 2);
    padding-right:calc((100% - 78%) / 2);
    padding-bottom:20px;
    -webkit-overflow-scrolling:touch;
    scrollbar-width:none;
  }
  .teaser-work .work-grid::-webkit-scrollbar{ display:none; }
  /* Neutralise explicitement la révélation en cascade (opacity/transform
     via .work-reveal.in) : sur ce carrousel, c'est .in-view qui pilote
     seul l'opacité/l'échelle (peek). Sans ça, les deux systèmes se
     disputeraient les mêmes propriétés à spécificité égale, avec un
     résultat dépendant de l'ordre de chargement des fichiers CSS —
     même piège que .hero .hero-content vs .container plus haut. */
  .teaser-work .work-card{
    flex:0 0 78%;
    scroll-snap-align:center;
    border:1px solid var(--paper-line);
  }
  /* .work-card.work-reveal (3 classes) pour être au moins aussi
     spécifique que .work-card.work-reveal.in de 04-sections.css (elle
     aussi 3 classes) : sans ça, une fois une carte révélée (.in), sa
     règle l'emporterait sur le simple .teaser-work .work-card (2
     classes) ci-dessus et empêcherait l'effet d'atténuation "peek".
     aspect-ratio est logé ici plutôt que sur .teaser-work .work-card
     ci-dessus pour la même raison : la règle desktop de la carte
     vedette (.work-card:not(.work-featured), 3 classes) serait sinon
     plus spécifique et gagnerait même sous 980px. */
  .teaser-work .work-card.work-reveal{
    opacity:0.5;
    transform:scale(0.94);
    aspect-ratio:3/4;
    transition:opacity .4s cubic-bezier(.16,.7,.2,1), transform .4s cubic-bezier(.16,.7,.2,1);
  }
  .teaser-work .work-card.work-reveal.in-view{ opacity:1; transform:scale(1); }

  /* Notre approche, mobile : les deux parties se superposent au lieu
     de s'empiler — la galerie devient un fond plein écran (position
     absolute), et le texte flotte par-dessus, centré, avec un voile
     indigo translucide pour rester lisible sur des photos chargées.
     Le texte est volontairement compact (citation raccourcie côté
     HTML, tailles réduites ci-dessous) pour laisser les photos
     respirer derrière plutôt que remplir tout l'écran de texte. */
  /* .teaser-studio .teaser-studio-grid (2 classes) — obligatoire ici :
     la règle desktop de base utilise déjà ce même sélecteur à 2
     classes (pour ignorer le plafond de .container), donc un simple
     .teaser-studio-grid ici perdrait face à elle malgré la cascade
     (spécificité égale requise, sans quoi ce bloc entier est ignoré :
     display:grid et les 3 colonnes desktop restent actifs même sous
     980px). */
  .teaser-studio .teaser-studio-grid{
    grid-template-columns:1fr;
    display:flex;
    align-items:center;
    justify-content:center;
    min-height:100vh;
    min-height:100svh;
    min-height:100dvh;
    min-height:var(--vh100, 100dvh); /* voir .hero — sans ça la galerie (position:absolute sur cette cellule) ne remplit que le viewport théorique et laisse la section suivante apparaître dessous */
    /* height (pas seulement min-height) : la galerie ci-dessous est en
       position:absolute + inset:0 sur cette cellule — sans une hauteur
       explicite et non ambiguë ici, son étirement à 100% était
       inconstant (elle s'arrêtait avant le bas de l'écran, laissant un
       bandeau indigo uni sous les photos). */
    height:100vh;
    height:100svh;
    height:100dvh;
    height:var(--vh100, 100dvh);
  }
  .teaser-studio-divider{ display:none; }
  .teaser-studio-clip{ display:none; } /* filigrane inutile : entièrement recouvert par la galerie + le voile */

  .teaser-studio-text{
    position:relative;
    z-index:2;
    align-items:center;
    text-align:center;
    padding:0 12px;
  }
  .teaser-studio .eyebrow{ justify-content:center; margin-bottom:16px; }
  .teaser-studio .pull-full{ display:none; }
  .teaser-studio .pull-short{ display:block; }
  .teaser-studio .pull{
    font-size:clamp(19px, 5.2vw, 24px);
    line-height:1.4;
  }
  .teaser-studio .link-arrow{ justify-content:center; margin-top:22px; }
  .teaser-quote-mark{ display:none; } /* le guillemet géant se perdrait sur un fond photo plutôt qu'un aplat indigo */

  .teaser-studio-gallery{
    position:absolute;
    inset:0;
    height:auto; /* annule le height:calc(100% + 140px) du débordement desktop — ici top:0 + bottom:0 + height:auto suffit à étirer exactement jusqu'aux bords de la cellule (voir .teaser-studio .teaser-studio-grid juste au-dessus pour sa hauteur explicite) */
    z-index:0;
    gap:8px;
  }
  /* Voile indigo translucide entre les photos et le texte — mêmes
     photos qu'en desktop, mais elles deviennent un décor plutôt que
     le sujet : le texte doit rester le premier plan lisible. */
  .teaser-studio-gallery::after{
    content:"";
    position:absolute; inset:0;
    background:rgba(0, 15, 159, 0.74);
    z-index:1;
  }
  .tsg-col{ height:100%; }
  .tsg-col-offset{ margin-top:28px; }
  .tsg-item{ flex:1; }
  .tsg-item.tsg-tall{ flex:1.35; }
}

/* ---------- HERO — mobile ----------
   En dessous de 560px, on resserre tout le hero pour qu'il tienne
   sans scroll excessif : l'eyebrow remonte tout en haut et passe sur
   une seule ligne, le H1 est réduit pour garder les deux lignes
   voulues par le <br> du HTML, les deux CTA passent sur une même
   ligne, et les 3 métadonnées redeviennent une rangée (au lieu d'une
   colonne) façon fiche technique compacte. */
@media (max-width: 560px){
  .hero{ padding:76px 0 40px; justify-content:flex-start; }

  /* Le contenu occupe toute la hauteur du hero (au lieu de se tasser
     en haut) pour que les métadonnées puissent être ancrées tout en
     bas via margin-top:auto, juste au-dessus de l'empreinte qui
     reste en arrière-plan (z-index:0 vs 1 pour .hero-content). */
  .hero .hero-content{ display:flex; flex-direction:column; flex:1 1 auto; }

  .hero-eyebrow{
    font-size:9px;
    letter-spacing:0.07em;
    gap:7px;
    margin-bottom:22px;
    white-space:nowrap;
  }
  .hero-eyebrow::before{ width:14px; }

  .hero h1{ font-size:clamp(30px, 11.4vw, 42px); margin-top:auto; }
  .hero h1 br.mobile-break{ display:inline; }

  .hero p.lead{ margin-top:36px; font-size:14px; line-height:1.6; }

  .hero-actions{
    margin-top:44px;
    gap:10px;
    flex-wrap:nowrap;
  }
  .hero-actions .btn{
    padding:10px 14px;
    font-size:11px;
    gap:6px;
    white-space:nowrap;
  }
  .hero-actions .scroll-cue{
    font-size:9.5px;
    letter-spacing:0.06em;
    gap:5px;
    white-space:nowrap;
  }

  .hero-meta-row{
    grid-template-columns:repeat(3, 1fr);
    gap:10px;
    margin-top:32px;
    padding-top:20px;
  }
  .hero-meta-row .m-label{ font-size:8px; letter-spacing:0.08em; margin-bottom:5px; }
  .hero-meta-row .m-value{ font-size:8.5px; line-height:1.25; }

  /* L'empreinte : encore plus grande, ancrée en bas à droite — même
     logique `bottom`/`right` que sur desktop (voir plus haut), juste
     poussée plus loin pour un rendu filigrane de pied de page. */
  .fingerprint-wrap{
    width:145vw; height:145vw;
    bottom:-38%;
    right:-70%;
    opacity:0.16;
  }

  /* Carrousel piliers : resserré encore un peu plus sur très petit
     écran (le comportement lui-même — flex, scroll-snap, .in-view —
     vient déjà du palier 980px ci-dessus). */
  .pillar-card{ flex-basis:88%; }
  .pillars-grid .pillar-card{ padding:28px 24px; }
  .pillar-card .num{ margin-top:14px; }
  .pillar-card h3{ margin-top:8px; font-size:22px; }
  .pillar-card p{ margin-top:10px; font-size:14px; }
  .pillar-card .tag-row{ margin-top:14px; margin-bottom:16px; }
}
