/* ============================================================
   LA POLICE
   Outfit, servie d'ici : un fichier variable (graisses 100 à 900) pour le
   latin, un second pour le latin étendu, plus de passage par Google. Le
   repli ajuste Arial aux proportions d'Outfit (mesuré dans Chrome) pour que
   le texte ne bouge presque pas quand la police arrive.
   ============================================================ */
@font-face{
  font-family:'Outfit'; font-style:normal; font-weight:100 900; font-display:swap;
  src:url("../fonts/outfit.woff2?v=98ccc2b7") format("woff2");
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face{
  font-family:'Outfit'; font-style:normal; font-weight:100 900; font-display:swap;
  src:url("../fonts/outfit-latin-ext.woff2?v=e2b64ddc") format("woff2");
  unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C4,U+2113,U+2C60-2C7F,U+A720-A7FF;
}
@font-face{
  font-family:'Outfit Repli'; src:local('Arial');
  size-adjust:98.51%; ascent-override:101.5%; descent-override:26.4%; line-gap-override:0%;
}

/* ============================================================
   BASE
   ============================================================ */
*,*::before,*::after{ box-sizing:border-box; margin:0; padding:0; }
html{ -webkit-font-smoothing:antialiased; -moz-osx-font-smoothing:grayscale; }
body{
  font-family:var(--font); font-weight:400; font-size:1.15rem; line-height:1.5;
  color:var(--noir); background:var(--blanc); overflow-x:hidden;
}
a{ color:inherit; text-decoration:none; }
button{ font:inherit; color:inherit; background:none; border:0; cursor:pointer; }
svg{ display:block; }
ul{ list-style:none; }

/* Un seul focus pour tout le site : l'anneau orange déjà choisi pour les
   cartes. Les exceptions (cartes, vitrine, champs) gardent leur dessin. */
:focus-visible{ outline:2px solid var(--orange); outline-offset:3px; }

/* Le lien d'évitement : invisible jusqu'au premier Tab, puis une pilule
   orange sous le haut de l'écran. */
.evite{
  position:fixed; top:var(--barre-y); left:50%; z-index:100;
  padding:.7rem 1.3rem; border-radius:6rem;
  background:var(--orange-fond); color:var(--blanc); font-weight:500;
  transform:translate(-50%,-200%); transition:transform .3s var(--ease);
}
.evite:focus-visible{ transform:translate(-50%,0); }

/* Les ancres glissent au lieu de sauter, sauf si le visiteur a demandé moins
   de mouvement. Un peu d'air au-dessus de la cible. */
@media (prefers-reduced-motion:no-preference){
  html{ scroll-behavior:smooth; scroll-padding-top:.75rem; }
}

/* Au-delà de 1512 px, la page est celle d'un portable de 14 pouces, agrandie
   d'un bloc : tout ce qui se mesure en rem grandit avec l'écran, comme ce
   qui se mesure déjà en vw. Les proportions restent celles du portable au
   lieu de s'étaler. */
@media (min-width:1512px){ html{ font-size:calc(100vw / 94.5); } }

/* ============================================================
   BARRE DE NAVIGATION
   ============================================================ */
.header{
  position:fixed; inset:var(--barre-y) 0 auto; z-index:60;
  display:flex; justify-content:center; pointer-events:none;
}
.nav{
  pointer-events:auto; width:var(--largeur);
  display:flex; align-items:center;
  padding:var(--retrait) var(--retrait) var(--retrait) clamp(2rem,2vw,2.8rem);
  border-radius:6rem;
  /* Un verre liquide : assez de blanc pour que les liens restent nets sur
     n'importe quelle image, le reste flouté et un peu saturé. Un reflet clair
     sur l'arête du haut et un liseré lumineux tout autour lui donnent son
     épaisseur. */
  background:linear-gradient(160deg, rgba(255,255,255,.78), rgba(255,255,255,.6));
  -webkit-backdrop-filter:blur(16px) saturate(1.9) brightness(1.04);
  backdrop-filter:blur(16px) saturate(1.9) brightness(1.04);
  box-shadow:
    var(--ombre-barre),
    inset 0 1px 0 rgba(255,255,255,.95),
    inset 0 -1px 1px rgba(255,255,255,.4),
    inset 0 0 0 1px rgba(255,255,255,.5),
    inset 0 -10px 20px -14px rgba(34,31,32,.12);
  transition:border-radius .45s var(--ease), padding .45s var(--ease);
}
.nav-haut{ display:flex; align-items:center; flex:0 0 auto; }
.logo-lien{ display:flex; align-items:center; }
/* Le logo grossit sans faire grossir la barre : sa boîte reste haute de
   `--haut-btn`, c'est le dessin qui est agrandi par-dessus. Le débord — 7 % de
   sa hauteur de chaque côté — tient largement dans le retrait de la barre, il
   n'est donc ni rogné ni compensé. */
.logo{ height:var(--haut-btn); width:auto; transform:scale(1.14); transform-origin:left center; }

.nav-panneau{ flex:1 1 auto; min-width:0; }
.nav-panneau-in{ display:flex; align-items:center; justify-content:flex-end; gap:clamp(1.5rem,2.2vw,2.6rem); }

/* Sur ordinateur, la barre se ramasse au centre, le logo au milieu : deux
   liens à sa gauche, deux à sa droite, « Parlons-en » compris. Les deux
   colonnes de liens valent `1fr` dans une barre à la largeur de son
   contenu : elles prennent donc la largeur de la plus large des deux, et le
   logo tombe au centre exact. Les conteneurs intermédiaires s'effacent pour
   que les listes entrent directement dans la grille. */
@media (min-width:901px){
  .nav{
    width:max-content; max-width:var(--largeur);
    display:grid; grid-template-columns:1fr auto 1fr;
    column-gap:clamp(2.2rem,3.6vw,4.5rem);
    padding-inline:clamp(2rem,2.6vw,3.2rem);
  }
  .nav-panneau, .nav-panneau-in{ display:contents; }
  .nav-haut{ grid-column:2; grid-row:1; }
  /* La liste la plus courte se centre dans sa colonne : la différence se
     partage entre le bord de la barre et le logo. */
  .nav-liens--g{ grid-column:1; grid-row:1; justify-self:center; }
  .nav-liens--d{ grid-column:3; grid-row:1; justify-self:center; }
  /* Le logo grossit depuis son centre : il reste au milieu de la barre. */
  .logo{ transform-origin:center; }
}
.nav-liens{ display:flex; align-items:center; gap:clamp(1.5rem,2.2vw,2.6rem); }
.nav-liens a{
  font-size:var(--corps); font-weight:500; color:var(--noir);
  transition:opacity .35s var(--ease);
}
.nav-liens a:hover{ opacity:.5; }

.nav-mobile{ display:none; align-items:center; gap:.55rem; margin-left:auto; }
.btn-contact{
  display:grid; place-items:center; width:2.85rem; height:2.85rem;
  border-radius:50%; background:var(--noir); flex:0 0 auto;
  transition:transform .35s var(--ease);
}
.btn-contact:active{ transform:scale(.92); }
/* La bulle est en tracé, comme les pictos des pastilles, et à la même
   épaisseur de trait. Plus grosse aussi : elle est seule dans son rond. */
.btn-contact svg{
  width:1.55rem; height:1.55rem;
  fill:none; stroke:var(--blanc); stroke-width:1.7;
  stroke-linecap:round; stroke-linejoin:round;
  /* La pointe est large — sept unités de base pour cinq de descente — donc
     l'encre tient de 2,6 à 21,6 dans une boîte de 24 : presque centrée. Il ne
     reste qu'un demi-pixel à rendre à l'œil, qui se cale sur le corps de la
     bulle plus que sur la pointe. */
  transform:translateY(.04rem);
}
.burger{
  position:relative; width:2.85rem; height:2.85rem; border-radius:50%;
  display:grid; place-items:center; flex:0 0 auto;
  box-shadow:inset 0 0 0 1.5px rgba(34,31,32,.16);
}
.burger i{
  position:absolute; left:50%; width:1.05rem; height:1.6px; border-radius:2px;
  background:var(--noir); transform:translateX(-50%);
  transition:transform .4s var(--ease), opacity .25s var(--ease);
}
.burger i:nth-child(1){ transform:translate(-50%,-.32rem); }
.burger i:nth-child(3){ transform:translate(-50%,.32rem); }
.nav.ouvert .burger i:nth-child(1){ transform:translate(-50%,0) rotate(45deg); }
.nav.ouvert .burger i:nth-child(2){ opacity:0; }
.nav.ouvert .burger i:nth-child(3){ transform:translate(-50%,0) rotate(-45deg); }

/* ============================================================
   BOUTONS
   ============================================================ */
.btn{
  position:relative; z-index:1; display:inline-flex; align-items:center; justify-content:center;
  padding:var(--btn-py) var(--btn-px); border-radius:6rem; color:var(--blanc);
  font-size:var(--corps); font-weight:500; letter-spacing:-.01em; white-space:nowrap;
}
.btn::before{
  content:''; position:absolute; inset:0; z-index:-1; border-radius:6rem;
  background:var(--noir); transition:transform .45s var(--ease);
}
.btn:hover::before{ transform:scale(.94); }
.btn:active{ transform:scale(.97); transition:transform .12s var(--ease); }
.btn--ghost{ color:var(--noir); }
.btn--ghost::before{ background:var(--blanc); box-shadow:inset 0 0 0 1.5px var(--noir); }
.btn-label{ position:relative; display:block; overflow:hidden; line-height:var(--interligne); }
/* Les deux lignes du libellé sont ses enfants directs : un mot mis en forme
   à l'intérieur (le nombre d'un filtre) reste dans sa ligne. */
.btn-label > span{ display:block; transition:transform .45s cubic-bezier(.165,.84,.44,1); }
.btn-label > span:nth-child(2){ position:absolute; inset:0; transform:translate3d(0,calc(100% + .2em),0); }
.btn:hover .btn-label > span:nth-child(1){ transform:translate3d(0,calc(-100% - .2em),0); }
.btn:hover .btn-label > span:nth-child(2){ transform:translate3d(0,0,0); }

/* ============================================================
   PREMIER ÉCRAN
   Le titre à gauche, la vitrine à droite : une carte de projet qui
   change au rythme du mot.
   ============================================================ */
.premier{ position:relative; overflow:hidden; }
.ecran{ position:relative; min-height:100svh; display:flex; flex-direction:column; }

.hero{
  position:relative; z-index:2; flex:1 1 auto;
  display:flex; flex-direction:column; justify-content:center;
  padding:clamp(8rem,14vh,11rem) 0 clamp(3rem,7vh,5.5rem);
}
.hero-inner{
  position:relative; width:var(--largeur); margin-inline:auto;
  display:grid; grid-template-columns:minmax(0,1.3fr) minmax(0,.7fr);
  gap:clamp(2rem,4vw,6rem); align-items:center;
}

h1{
  font-size:clamp(2.6rem,6.3vw,11rem);
  font-weight:500; line-height:.96; letter-spacing:-.038em;
  max-width:18ch; text-wrap:balance;
  opacity:0; transform:translateY(2.2rem);
  transition:opacity 1s var(--ease), transform 1s var(--ease);
}
.ready h1, html:not(.js) h1{ opacity:1; transform:none; }
.h1-tete{ white-space:nowrap; }

/* --- Le mot qui tourne ---
   Il a sa propre ligne : un mot plus long ne fait rien bouger d'autre.
   L'ancien et le nouveau partagent la même case (une grille d'une seule
   cellule) : ils se croisent au lieu de se succéder, il n'y a donc jamais
   de vide ni de coupure. La case prend la largeur du nouveau mot en
   glissant — le script la lui donne —, et le trait orange, posé DERRIÈRE
   les lettres, s'allonge ou se raccourcit avec elle. */
.tourne{
  position:relative; isolation:isolate;
  display:grid; width:max-content;
  transition:width .8s cubic-bezier(.65,0,.25,1);
}
.tourne-mot{ grid-area:1 / 1; justify-self:start; width:max-content; white-space:nowrap; }
.tourne-mot .l{
  display:inline-block;
  transition:transform .8s cubic-bezier(.2,.75,.2,1), opacity .7s var(--ease), filter .7s var(--ease);
  transition-delay:calc(var(--n) * 30ms + 120ms);
}
.tourne-mot .l--espace{ width:.26em; }
/* Le nouveau mot attend sous la ligne, flou et transparent… */
.tourne-mot.attend .l{ transform:translateY(.42em); opacity:0; filter:blur(.06em); transition:none; }
/* …l'ancien s'en va vers le haut de la même façon, un peu plus vite. */
.tourne-mot.part .l{
  transform:translateY(-.34em); opacity:0; filter:blur(.06em);
  transition-duration:.55s; transition-delay:calc(var(--n) * 18ms);
}
/* Le trait : l'épaisseur du fût de la lettre, SOUS les lettres — juste sous
   la ligne de base — et derrière elles : seuls les jambages (g, q, p) le
   traversent, en passant devant. */
.tourne::after{
  content:''; position:absolute; z-index:-1; left:-.02em; right:-.02em; bottom:-.03em;
  height:var(--rature-e); background:var(--orange); border-radius:2px;
  transform:scaleX(0); transform-origin:left center;
  transition:transform .8s var(--ease);
}
.tourne.pose::after, html:not(.js) .tourne::after{ transform:scaleX(1); }

.sub{
  margin-top:clamp(1.5rem,2.4vw,2.6rem); max-width:52ch;
  font-size:clamp(var(--corps), 1.25vw, 1.75rem); line-height:1.55; font-weight:300;
  opacity:0; transform:translateY(1.4rem);
  transition:opacity .9s var(--ease), transform .9s var(--ease);
}
.sub strong{ font-weight:500; }
.ready .sub, html:not(.js) .sub{ opacity:1; transform:none; transition-delay:.34s; }

.actions{
  display:flex; flex-wrap:wrap; gap:.75rem; margin-top:clamp(1.6rem,2.6vw,2.4rem);
  opacity:0; transform:translateY(1.4rem);
  transition:opacity .9s var(--ease), transform .9s var(--ease);
}
.ready .actions, html:not(.js) .actions{ opacity:1; transform:none; transition-delay:.48s; }

/* --- La vitrine ---
   Une pile de cartes, légèrement inclinées. Chaque carte lit son rang
   (`--rang`, 0 au-dessus) et s'en déduit tout : décalage, inclinaison,
   réduction, ordre — trois cartes se voient, les autres attendent dessous.
   Quand le mot change, la carte du dessus s'écarte vers la gauche en
   tournant, puis repasse au fond sans qu'on la voie.
   Pas de pastilles : l'image suffit, et le mot du titre la nomme. Les
   cartes sont carrées, comme les couvertures. */
.vitrine{
  position:relative; justify-self:end;
  width:min(100%, 40rem, 58svh); aspect-ratio:1/1;
  margin-right:clamp(1rem,2vw,2.5rem);
  opacity:0; transform:translateY(2rem);
  transition:opacity 1.1s var(--ease) .3s, transform 1.1s var(--ease) .3s;
}
.ready .vitrine, html:not(.js) .vitrine{ opacity:1; transform:none; }
.vitrine-carte{
  --r:var(--rang,0);
  position:absolute; inset:0;
  transform:
    translate(calc(var(--r) * 5%), calc(var(--r) * -3.5%))
    rotate(calc(-3deg + var(--r) * 5deg))
    scale(calc(1 - var(--r) * .06));
  z-index:calc(20 - var(--r));
  opacity:clamp(0, 3 - var(--r), 1);
  transition:transform .95s cubic-bezier(.6,0,.2,1), opacity .6s var(--ease);
}
.vitrine-image{
  width:100%; height:100%; object-fit:cover; display:block;
  border-radius:var(--rayon); background:var(--blanc);
  box-shadow:0 30px 60px -28px rgba(34,31,32,.45), var(--ombre-barre);
}
.vitrine-carte.ecartee{
  z-index:30;
  transform:translate(-30%, 7%) rotate(-15deg) scale(.94);
  opacity:0;
  transition:transform .9s cubic-bezier(.5,0,.3,1), opacity .7s var(--ease) .15s;
}
/* --- Les éclats ---
   Des pièces du projet qui s'échappent de la carte quand elle passe devant :
   un téléphone, une page, un croquis, une mascotte. Ils partent du centre de
   l'image (`--dx`, `--dy`, calculés par le générateur), petits et
   transparents, et jaillissent à leur place l'un après l'autre, avec un
   léger rebond. Quand la carte s'écarte, ils s'éteignent aussitôt. */
.eclat{
  position:absolute; z-index:3;
  left:var(--x); top:var(--y); width:var(--l);
  opacity:0; pointer-events:none;
  transform:translate(var(--dx,0), var(--dy,0)) rotate(0deg) scale(.4);
  transition:opacity .25s var(--ease), transform .3s var(--ease);
}
.vitrine-carte[data-devant] .eclat{
  opacity:1; transform:rotate(var(--r));
  transition:
    opacity .45s var(--ease) calc(.5s + var(--n) * .16s),
    transform 1s cubic-bezier(.2,1.3,.35,1) calc(.5s + var(--n) * .16s);
}
.vitrine-carte.ecartee .eclat{ opacity:0; transition-delay:0s; }
/* L'écart qui fuit le pointeur (`translate`) est animé par le script, image
   par image : pas de transition CSS sur lui, elle freinerait le ressort. */
.eclat img{ display:block; width:100%; height:auto; }
.eclat--carte img{
  border-radius:var(--rayon-petit); background:var(--blanc);
  box-shadow:0 24px 44px -18px rgba(34,31,32,.5), var(--ombre-barre), 0 0 0 1px rgba(255,255,255,.16);
}
/* Une pièce qui a déjà sa forme (l'icône de Tennis Match Up, arrondie à
   20 %) : pas de fond, et l'arrondi de l'image épouse le sien, pour que ni
   le blanc ni l'ombre ne dépassent dans les coins. */
.eclat--nu img{ background:none; border-radius:20%; box-shadow:0 24px 44px -18px rgba(34,31,32,.5); }
.eclat--detour img{ filter:drop-shadow(0 18px 22px rgba(34,31,32,.3)); }
.eclat--rond img{
  aspect-ratio:1; object-fit:cover; border-radius:50%; background:var(--blanc);
  border:clamp(3px,.4vw,6px) solid var(--blanc);
  box-shadow:0 24px 44px -18px rgba(34,31,32,.5);
}
/* Le téléphone : les proportions d'un iPhone. Bord de 2,4 % de la largeur,
   écran arrondi à 15 % ; les pourcentages verticaux se rapportent à la
   hauteur, d'où le second jeu de valeurs. */
.eclat--tel{
  aspect-ratio:390/844; background:#121212;
  border-radius:15% / 6.93%;
  /* Un liseré clair : sur une carte sombre, le téléphone s'en détache. */
  box-shadow:0 28px 50px -18px rgba(0,0,0,.55), 0 0 0 1px rgba(255,255,255,.16);
}
.eclat--tel img{
  position:absolute; left:2.4%; top:1.11%; width:95.2%; height:97.78%;
  object-fit:cover; object-position:top;
  border-radius:13.2% / 5.95%;
}
@media (hover:hover){
  .vitrine-carte[data-devant]:hover{ transform:translateY(-.5rem) rotate(-2deg); }
}
.vitrine-carte:focus-visible{ outline:none; }
.vitrine-carte:focus-visible img{ outline:2px solid var(--orange); outline-offset:4px; }

/* ============================================================
   FRISE
   ============================================================ */
.frises{
  position:relative; z-index:3;
  display:flex; flex-direction:column;
  padding:clamp(5rem,12vh,8rem) 0 clamp(.3rem,.7vh,.55rem);
}
/* `clip` permet de rogner un seul axe sans créer de conteneur de
   défilement : le défilé est coupé à droite et à gauche, l'ombre des
   pastilles déborde librement en hauteur. */
/* Le masque du défilé ne peint que la boîte : tout ce qui dépasse est
   effacé, ombre comprise, d'où le bas des pastilles tranché net. La bande
   se réserve donc la place de cette ombre à l'intérieur — 19 px mesurés
   sous une pastille, arrondis à 1,35 rem. */
.frise{
  position:relative; flex:0 0 auto;
  padding:.5rem 0 1.35rem;
  display:flex; overflow-x:clip; overflow-y:visible; user-select:none;
  -webkit-mask-image:linear-gradient(90deg,transparent 0,#000 4%,#000 96%,transparent 100%);
  mask-image:linear-gradient(90deg,transparent 0,#000 4%,#000 96%,transparent 100%);
}
/* La bande ne défile plus seule : c'est le défilement de la page qui la
   pousse (voir « La bande de pastilles » dans le script). Elle avance quand
   on descend, recule quand on remonte, et s'arrête avec la page. Les deux
   lignes sont identiques : décalées d'une largeur de ligne au plus, elles
   bouclent sans raccord. */
.frise-ligne{
  flex-shrink:0; display:flex; align-items:center; min-width:100%;
  will-change:transform;
}
/* Un intervalle constant, indépendant de la largeur d'écran. */
.frise-groupe{ display:flex; align-items:center; gap:6rem; padding-right:6rem; }
.pilule{
  display:flex; align-items:center; gap:.55em; flex:0 0 auto;
  padding:var(--pil-py) var(--btn-px) var(--pil-py) var(--pil-py); border-radius:6rem;
  background:var(--blanc);
  box-shadow:var(--ombre-barre);
  white-space:nowrap; font-size:var(--corps); font-weight:500; line-height:var(--interligne);
  letter-spacing:-.01em; color:var(--noir);
}
.pastille{
  display:grid; place-items:center; flex:0 0 auto;
  width:var(--badge); height:var(--badge);
  border-radius:50%; background:var(--orange);
}
.pastille svg{
  width:54%; height:54%;
  fill:none; stroke:var(--blanc); stroke-width:1.9;
  stroke-linecap:round; stroke-linejoin:round;
}

/* ============================================================
   SECTIONS — ossature commune
   ============================================================ */
.section{ position:relative; padding:var(--pad) 0; }
/* Le passage au sable se fait en fondu, de part et d'autre : la bande de
   transition tient dans le retrait de la section, elle ne lui ajoute donc
   aucune hauteur. */
.section--sable{
  --fondu:clamp(2rem,4.5vh,4rem);
  /* Le fondu du bas est plus court que celui du haut : le sable descend
     nettement plus bas que la légende avant de céder au blanc. */
  --fondu-bas:clamp(1rem,2vh,1.75rem);
  background:linear-gradient(
    to bottom,
    var(--blanc) 0,
    var(--sable) var(--fondu),
    var(--sable) calc(100% - var(--fondu-bas)),
    var(--blanc) 100%);
}
.contenu{ width:var(--largeur); margin-inline:auto; }

h2{
  font-size:clamp(2.15rem,4.9vw,5.4rem);
  font-weight:500; line-height:1; letter-spacing:-.035em;
}

/* Le titre casse aux points, pas au hasard : une phrase par ligne. */
.nb{ white-space:nowrap; }

/* Le trait orange du titre : même géométrie que la rature du hero,
   posé sous le mot au lieu de le barrer. */
.souligne{ position:relative; z-index:0; white-space:nowrap; }
.souligne::after{
  content:''; position:absolute; z-index:-1; left:-.03em; right:-.03em; top:1.02em;
  height:var(--rature-e); background:var(--orange); border-radius:2px;
  transform-origin:left center;
  transition:transform .75s var(--ease) .35s;
}
.js .souligne::after{ transform:scaleX(0); }
@media (max-width:900px){ .souligne::after{ top:1.14em; } }
.js .vu .souligne::after{ transform:scaleX(1); }

/* Étiquette de section : le rond orange porte le signe, le texte reste noir. */
.etiquette{
  display:flex; align-items:center; gap:.7rem;
  margin-bottom:var(--etiquette-ecart);
  font-size:var(--etiquette); line-height:var(--etiquette-interligne);
  font-weight:500; letter-spacing:.09em; text-transform:uppercase;
}
.etiquette::before{
  content:''; width:.62rem; height:.62rem; border-radius:50%;
  background:var(--orange); flex:0 0 auto;
}

/* Apparition au défilement, une seule courbe, une seule distance.
   L'état masqué est conditionné à `.js` : sans script, tout reste lisible. */
.apparait{
  transition:opacity .9s var(--ease), transform .9s var(--ease);
  transition-delay:calc(var(--i,0) * .1s);
}
.js .apparait{ opacity:0; transform:translateY(1.6rem); }
.js .apparait.vu{ opacity:1; transform:none; }

/* ============================================================
   LES CHAPITRES
   Chaque étiquette : le point orange, puis le nom de la partie.
   ============================================================ */
.projet{ transition:opacity .9s var(--ease), transform .9s var(--ease); }

/* (Plus aucun mot en contour : l’Outfit est une police variable, et son
   contour laisse voir les tracés qui se chevauchent dans les lettres.) */

/* ============================================================
   L'INTERMÈDE
   Trois lignes, en très grand. C'est la typographie qui fait l'image :
   une ligne noire, une ligne qui passe du gris à l'orange au défilement,
   une ligne noire. Elles glissent en sens contraire (`--x`, posé par le
   script).
   ============================================================ */
.monument{
  position:relative; overflow:hidden;
  padding:clamp(5rem,12vh,9rem) 0;
  display:flex; flex-direction:column; gap:clamp(.2rem,1vw,1rem);
}
.monument-ligne{
  white-space:nowrap; text-align:center;
  font-size:clamp(3.4rem,12.5vw,15rem); font-weight:500;
  line-height:.92; letter-spacing:-.055em;
  transform:translateX(var(--x,0));
  will-change:transform;
}
.monument-ligne span{ display:inline-block; }
.monument-ligne i{ font-style:normal; }
/* La ligne du milieu : grise quand elle entre, elle se colore d'orange de
   gauche à droite à mesure qu'on descend (`--rempli`, posé par le script). */
.monument-ligne--contour span{
  color:transparent;
  background:linear-gradient(90deg, var(--orange) var(--rempli,0%), var(--gris) var(--rempli,0%));
  -webkit-background-clip:text; background-clip:text;
  /* Le dégradé ne peint que dans la boîte du mot ; avec un interligne de
     0,92, le jambage du j en sortait et restait transparent. La boîte
     descend donc de 0,25 em (et remonte de 0,1 em pour l'accent), sans rien
     décaler : les marges négatives rendent la place. */
  padding:.1em 0 .25em; margin:-.1em 0 -.25em;
}
.monument-ligne--contour i{ color:transparent; }
html:not(.js) .monument-ligne--contour span{ background:none; color:var(--orange); }

/* ============================================================
   02 — NOTRE OFFRE
   Trois cartes debout, de même hauteur. Le numéro en haut, le nom, ce
   qu'on obtient, et le prix en très grand, en bas, en noir — en blanc
   quand l'aplat orange, qui passe d'une carte à l'autre, arrive sur lui.
   ============================================================ */
.section--offre{ padding-top:clamp(5rem,10vw,9rem); }
.offre-chapo{ margin-top:clamp(1rem,1.8vw,1.5rem); max-width:52ch; font-size:var(--corps); font-weight:300; line-height:1.6; color:var(--noir); }
.offres{
  display:grid; grid-template-columns:repeat(3,minmax(0,1fr));
  gap:clamp(.7rem,1.2vw,1.2rem);
  margin-top:clamp(2.4rem,4.5vw,4.2rem);
}
.offre{
  position:relative; overflow:hidden;
  display:flex; flex-direction:column;
  min-height:clamp(24rem,36vw,32rem);
  padding:clamp(1.3rem,2vw,2rem);
  border-radius:var(--rayon);
  background:var(--sable); color:var(--noir);
}
.js .offre{
  transition:
    opacity .9s var(--ease) calc(var(--i,0) * .1s),
    transform .9s var(--ease) calc(var(--i,0) * .1s),
    background-color 1.25s var(--ease),
    color 1.25s var(--ease);
}
/* L'aplat orange porte du texte blanc : il prend l'orange de fond, 4,50:1. */
.offre.offre--phare{ background:var(--orange-fond); color:var(--blanc); }
.offre-nom{
  font-size:clamp(1.6rem,2.5vw,2.6rem); font-weight:500;
  line-height:1.05; letter-spacing:-.035em;
}
.offre-option{ font-size:var(--corps); font-weight:300; letter-spacing:0; opacity:.85; }
.offre-liste{
  margin-top:clamp(1rem,1.8vw,1.5rem);
  display:flex; flex-direction:column; gap:.45rem;
  font-size:var(--corps); line-height:1.35;
}
.offre-liste li{ position:relative; padding-left:.95rem; }
.offre-liste li::before{
  content:''; position:absolute; left:0; top:.5em;
  width:.36rem; height:.36rem; border-radius:50%;
  background:currentColor; opacity:.5;
}
.offre-liste strong{ font-weight:500; }
/* Le prix, en bas de carte. */
.offre-prix{
  margin-top:auto; padding-top:clamp(1.4rem,3vw,2.6rem);
  display:flex; align-items:baseline; flex-wrap:wrap; gap:0 .3em;
  font-size:clamp(3.2rem,6.4vw,7rem); font-weight:500;
  line-height:.9; letter-spacing:-.05em; white-space:nowrap;
}
/* Le prix en noir ; en blanc quand l'aplat orange passe sur sa carte. */
.offre-prix .montant{ color:var(--noir); transition:color 1.25s var(--ease); }
.offre--phare .offre-prix .montant{ color:var(--blanc); }
.offre-prix small{ font-size:max(.85rem, .18em); font-weight:500; letter-spacing:.02em; }
.offre-prix .des{ width:100%; margin-bottom:.35rem; text-transform:uppercase; letter-spacing:.09em; opacity:.85; }

/* Au changement de couleur, les chiffres se soulèvent l'un après l'autre. */
.montant .ch{ display:inline-block; }
.montant.onde .ch{ animation:onde .6s var(--ease); animation-delay:calc(var(--c) * 45ms); }
@keyframes onde{ 0%{ transform:translateY(0); } 38%{ transform:translateY(-.15em); } 100%{ transform:translateY(0); } }

.lu-seul{
  position:absolute; width:1px; height:1px; overflow:hidden;
  clip-path:inset(50%); white-space:nowrap;
}

/* ============================================================
   SECTION 3 — MÉTHODE
   Une table de montage : une règle graduée en jours, une tête de lecture
   orange poussée par le défilement, et des bulles qui s'allument au passage.
   Le panneau est collé pendant que la tête parcourt les quatre semaines,
   puis la page reprend son cours.
   ============================================================ */
/* La section suivante est une scène plein écran qui se centre elle-même :
   son retrait de section ferait double emploi, et celui de la section qui la
   précède peut se resserrer. */
.js .section--montage{ padding-block:0; }
.methode-piste{ position:relative; --course:280vh; }
.js .methode-piste{ height:calc(100svh + var(--course)); }
/* Le panneau se colle **sous la barre**, pas en haut de l'écran : sinon le
   titre passe derrière elle au moment où la scène se fige. Sa hauteur se
   déduit de la même valeur, pour que le bas tombe juste sur le bas de
   l'écran — ni débord, ni vide. Et il se cale en haut plutôt qu'au centre :
   le centrage rejetait la scène vers le bas et laissait l'écart au-dessus. */
.js .methode-collant{
  position:sticky; top:var(--haut-barre);
  min-height:calc(100svh - var(--haut-barre));
  display:flex; align-items:stretch;
}
/* La scène occupe toute la hauteur du panneau, et c'est la frise qui absorbe
   ce qui reste : l'intro garde le haut — donc le titre reste sous la barre —
   et le vide se partage de part et d'autre de la frise au lieu de s'entasser
   en bas. Sur un grand écran, 215 px de vide deviennent deux fois 107. */
.js .methode-scene{ grid-template-rows:auto auto minmax(0,1fr); }
.js .frise-temps{ align-self:center; }
/* La scène est calée en haut : l'écart avec la frise est celui qu'on écrit,
   et le titre reste sous la barre. Sur grand écran aussi : la page y est
   celle d'un portable, agrandie. */
.js .section--montage{ padding-top:clamp(1.75rem,4vh,3rem); }
/* Les textes légaux, sur un très grand écran, en deux colonnes : la hauteur
   tombe de moitié et le défilement disparaît. */
@media (min-width:1920px){
  .js .boite.boite--legal .boite-panneau{ width:min(92vw,72rem); max-height:min(88svh,60rem); }
  .js .legal-volet.texte-long{ max-width:none; column-count:2; column-gap:clamp(2rem,3vw,3.5rem); }
  .js .legal-volet h3{ break-after:avoid; break-inside:avoid; margin-top:0; }
  .js .legal-volet h3 + p{ break-before:avoid; }
  .js .legal-volet p, .js .legal-volet li{ break-inside:avoid; }
  /* La boîte d'écriture n'a pas besoin de colonnes, juste d'un peu d'aise. */
  #ecrire .boite-panneau{ width:min(92vw,42rem); max-height:min(88svh,52rem); }
}
@media (max-width:900px){
  .js .section--montage{ padding-top:1.75rem; }
  /* La course est deux fois plus courte au pouce qu'à la molette : 280vh de
     défilement pour quatre semaines, c'était plus de deux écrans et demi à
     pousser sur un téléphone. À 140vh la règle va deux fois plus vite. Rien
     d'autre à changer : le script relit la course sur la hauteur réelle de la
     piste, il ne la connaît pas. */
  .methode-piste{ --course:140vh; }
  /* Sur mobile, c'est le TITRE qui doit venir sous la barre, pas l'étiquette.
     Le panneau se colle donc plus haut, de la place exacte qu'occupe
     l'étiquette au-dessus du titre — `--haut-etiquette`, qui comprend déjà
     son écart. L'étiquette passe alors derrière la barre, et toute la règle
     remonte d'autant : elle reste visible quand Safari fait réapparaître sa
     barre d'outils en remontant. La course du défilement suit toute seule :
     elle lit `top` sur le style calculé du panneau. */
  .js .methode-collant{
    top:calc(var(--haut-barre) - var(--haut-etiquette));
    min-height:calc(100svh - var(--haut-barre) + var(--haut-etiquette));
  }
}

/* Trois zones nommées : sur ordinateur l'intro et les actions se partagent
   une ligne, la frise court dessous ; sur mobile la frise se glisse entre
   les deux, pour que la tête de lecture reste au-dessus des actions qu'elle
   commande. */
.methode-scene{
  display:grid; align-items:start;
  grid-template-columns:minmax(0,1fr) minmax(0,.82fr);
  grid-template-areas:
    "titre actions"
    "intro actions"
    "frise frise";
  /* Deux écarts, pas un. En largeur il faut de l'air entre le texte et le
     bloc de semaine ; en hauteur, non : la règle appartient à ce qui la
     précède, et un écart de 5vw la faisait lire comme une pièce à part.
     Mesuré à 1470 px : la règle passe de 212 à 163 px sous le texte. */
  column-gap:clamp(2rem,5vw,6rem);
  row-gap:clamp(1.4rem,2.6vh,2.6rem);
}
.methode-titre{ grid-area:titre; }
.methode-intro{ grid-area:intro; }
.methode-actions{
  grid-area:actions;
  /* Le cadre part du haut du titre, à côté de lui : il descend de la place
     que l'étiquette occupe au-dessus du titre, écart compris. */
  margin-top:var(--haut-etiquette);
  /* …et du haut des lettres, pas de celui de leur boîte : l'interligne de 1
     laisse 0,16 em de vide au-dessus des capitales. */
  margin-top:calc(var(--haut-etiquette) + .16 * clamp(2.15rem,4.9vw,5.4rem));
  /* Le contenu de la semaine tient dans un cadre : posé au milieu de rien,
     on ne voyait pas qu'il changeait. */
  padding:clamp(1.35rem,2.1vw,1.9rem) clamp(1.35rem,2.1vw,1.9rem) clamp(1.5rem,2.3vw,2.1rem);
  border-radius:var(--rayon); background:var(--sable);
}
/* Les quatre semaines occupent la même case : le cadre prend la hauteur de la
   plus haute et ne saute donc pas d'une semaine à l'autre. Sans script elles
   se suivent, et la règle ne s'applique pas. */
.js .methode-actions{ display:grid; grid-template-areas:"semaine"; align-items:start; }
.js .methode-semaine{ grid-area:semaine; }
.frise-temps{ grid-area:frise; }
.methode-texte{
  margin-top:0;
  font-size:var(--corps); line-height:1.6; max-width:70ch;
}
@media (max-width:900px){ .methode-texte br{ display:none; } }
/* Sur grand écran, la frise se détache davantage du texte qui la précède. */
@media (min-width:1460px){
  .frise-temps{ margin-top:clamp(1rem,3.5vh,3rem); }
}

/* --- La colonne des actions --- */
.methode-semaine-nom{
  font-size:clamp(1.3rem,1.7vw,1.75rem); font-weight:500;
  line-height:1.15; letter-spacing:-.025em; margin-bottom:1.3rem;
}
.methode-semaine ul{ display:flex; flex-direction:column; gap:.95rem; }
/* Une puce ronde, orange, à la hauteur de la première ligne : le centre du
   point se cale sur celui du texte, .75em pour un interligne de 1,5. */
.methode-semaine li{
  position:relative; padding-left:1.15rem;
  font-size:var(--corps); line-height:1.5; max-width:38ch;
}
.methode-semaine li::before{
  content:''; position:absolute; left:0; top:calc(.75em - .21rem);
  width:.42rem; height:.42rem; border-radius:50%; background:var(--orange);
}
/* Sans script les quatre semaines s'affichent à la suite : la section reste
   lisible même si rien ne bouge. */
.methode-semaine + .methode-semaine{ margin-top:2.2rem; }
.js .methode-semaine{
  opacity:0; visibility:hidden; transform:translateY(1.2rem);
  transition:opacity .42s var(--ease), transform .42s var(--ease), visibility 0s .42s;
}
.js .methode-semaine.active{
  opacity:1; visibility:visible; transform:none;
  transition:opacity .42s var(--ease), transform .42s var(--ease), visibility 0s;
}
.js .methode-semaine + .methode-semaine{ margin-top:0; }
.js .methode-semaine li{
  opacity:0; transform:translateY(.6rem);
  transition:opacity .5s var(--ease), transform .5s var(--ease);
}
.js .methode-semaine li.vu{ opacity:1; transform:none; }

/* --- La frise --- */
.frise-temps{
  position:relative;
  --legende:4.4rem; --h-regle:3.4rem; --ecart-voie:.55rem;
  --jeu:2px;          /* le léger écart entre deux blocs voisins */
  /* La voie fait la hauteur d'une ligne de texte courant plus son retrait :
     les blocs s'épaississent donc d'eux-mêmes quand le corps grandit. */
  --h-voie:calc(1.25 * var(--corps) + 1.15rem);
  --cols:3.8rem minmax(0,1fr) minmax(0,1fr);
  padding-left:calc(var(--legende) + 1.1rem);
}
/* Les noms de voie se posent avant le premier trait : la règle et les blocs
   partent donc du même bord, et « Entretien » tombe sous « Semaine 1:00 ». */
.voie-nom{
  position:absolute; left:0; width:var(--legende); height:var(--h-voie);
  display:flex; align-items:center;
  font-size:.78rem; font-weight:500; letter-spacing:.09em; text-transform:uppercase;
  color:var(--gris-texte);
}
.voie-nom--vous{ top:calc(var(--h-regle) + var(--ecart-voie)); }
.voie-nom--nous{ top:calc(var(--h-regle) + 2 * var(--ecart-voie) + var(--h-voie)); }

.frise-scene{ position:relative; }

.frise-regle{ position:relative; height:var(--h-regle); border-top:1.5px solid var(--gris); }
.jour{
  position:absolute; top:0; left:calc(var(--p) * 1%);
  width:1px; height:.45rem; background:var(--gris);
}
.jour--semaine{ height:1.15rem; width:1.5px; background:var(--noir); }
.frise-libelle{
  position:absolute; z-index:2; top:1.7rem; left:calc(var(--p) * 1%);
  margin-left:.7rem; white-space:nowrap;
  font-size:.8rem; font-weight:500; letter-spacing:.09em; text-transform:uppercase;
  color:var(--gris-texte);
  transition:color .5s var(--ease);
}
.frise-libelle.active{ color:var(--noir); }
.frise-libelle .court{ display:none; }

/* Les voies : ce que vous faites, ce qu'on fait. Un bloc s'allume tant que
   la tête de lecture le traverse. */
.voie{ position:relative; height:var(--h-voie); margin-top:var(--ecart-voie); }
.clip{
  position:absolute; top:0; bottom:0;
  left:calc(var(--a) * 1% + var(--jeu));
  width:calc((var(--b) - var(--a)) * 1% - 2 * var(--jeu));
  display:flex; align-items:center; padding-inline:.75rem;
  border-radius:var(--rayon-petit); overflow:hidden; white-space:nowrap;
  background:var(--sable); box-shadow:inset 0 0 0 1.5px var(--gris);
  font-size:var(--corps); font-weight:500; letter-spacing:-.01em;
  transition:background-color .45s var(--ease), color .45s var(--ease),
             box-shadow .45s var(--ease);
}
.clip.active{ background:var(--orange-fond); color:var(--blanc); box-shadow:none; }
/* Les blocs passent devant la tête de lecture, et chacun en redessine le
   morceau qui le traverse : orange sur un bloc éteint, blanc sur un bloc
   allumé. La position vient de la scène (`--t`, en unités de conteneur), le
   bloc s'en retranche son propre départ. */
.frise-scene{ container-type:inline-size; --trait-tete:3px; }
.clip{ z-index:2; }
.clip::after{
  content:''; position:absolute; top:0; bottom:0;
  left:calc((var(--t) - var(--a)) * 1cqw - var(--jeu));
  width:var(--trait-tete); margin-left:calc(var(--trait-tete) / -2);
  background:var(--orange); pointer-events:none;
}
.clip.active::after{ background:var(--blanc); }

/* La tête de lecture : un trait, et sa poignée en haut, comme sur une
   table de montage. */
.frise-tete{
  position:absolute; z-index:1; top:0; bottom:0; left:calc(var(--t) * 1%);
  width:var(--trait-tete); margin-left:calc(var(--trait-tete) / -2); background:var(--orange);
  pointer-events:none;
}
.frise-tete::before{
  content:''; position:absolute; top:-.6rem; left:50%;
  width:1.05rem; height:1.05rem; border-radius:50%;
  background:var(--orange); transform:translateX(-50%);
}

/* ============================================================
   RÉALISATIONS
   Une galerie en deux colonnes, la seconde décalée vers le bas : les
   cartes se lisent en quinconce. Chaque carte mène à la page du projet.
   Le nom du projet est posé dans une encoche taillée dans le coin haut
   gauche de l'image, à la couleur du fond de la section : la carte et la
   section ne font qu'une. Les pastilles disent le métier, en bas à gauche.
   ============================================================ */
.section--avant-montage{
  /* Autant d'air avant qu'après : les fondus sont symétriques, il leur faut
     la même place de part et d'autre. */
  padding-top:clamp(7rem,15vh,11.5rem);
  padding-bottom:clamp(7rem,15vh,11.5rem);
  /* Le fondu du haut est la référence : le bas le recopie. */
  --fondu-bas:var(--fondu);
}

/* Le titre à gauche ; à droite, le lien vers tous les projets, calé sur le
   bas du titre. Sur téléphone, ce lien passe sous la dernière carte. */
.realisations-tete{ display:flex; align-items:flex-end; justify-content:space-between; gap:1.5rem 2rem; }
.realisations-tous{ flex:0 0 auto; }
.realisations-pied{ display:none; }
.realisations-texte{
  font-size:var(--corps); line-height:1.6; color:var(--noir);
  /* Le paragraphe se cale sur la dernière ligne du titre. */
  padding-bottom:.35em;
}

.galerie{
  display:grid; grid-template-columns:repeat(3,minmax(0,1fr));
  column-gap:clamp(1.2rem,2.4vw,3rem); align-items:start;
  margin-top:clamp(3.2rem,5vw,5.6rem);
}
.galerie-col{ display:flex; flex-direction:column; gap:clamp(3.2rem,5.5vw,6rem); }
/* La colonne du milieu descend : les titres ne tombent jamais à la même
   hauteur que ceux de ses voisines, et le bas des trois colonnes se rejoint
   (3,5 hauteurs de carte à gauche et à droite, 3,25 au milieu). */
.galerie-col{ gap:clamp(2.6rem,4.4vw,4.6rem); }
.galerie-col--decalee{ padding-top:clamp(4rem,8vw,8.5rem); }

/* --- La carte --- */
.projet{ --encoche:var(--sable); --marge-carte:clamp(.8rem,1.4vw,1.3rem); }
.projet-lien{ position:relative; display:block; color:inherit; }
.projet-visuel{
  position:relative; overflow:hidden; isolation:isolate;
  aspect-ratio:var(--format,4/5);
  border-radius:var(--rayon); background:var(--blanc);
}
.projet-visuel > img,
.projet-visuel > video{
  position:absolute; inset:0; width:100%; height:100%;
  object-fit:cover; display:block;
  transition:transform 1.2s var(--ease);
}
/* L'identité ne se recadre jamais : le signe garde sa marge blanche. */
.projet-visuel > video.signe{ object-fit:contain; padding:12% 8% 16%; }

/* L'encoche. Le titre porte la couleur du fond et un arrondi en bas à
   droite ; ses deux voisins, à sa droite et sous lui, sont deux quarts de
   cercle creusés. L'image semble ainsi contourner le titre, sans masque ni
   découpe.
   Le coin à droite du titre et l'arrondi du titre se suivent sur sa hauteur :
   ils doivent donc tenir chacun dans une moitié. Au rayon des cartes, le titre
   (36 px de haut sur téléphone pour 2 × 27 de rayon) était trop court, et un
   coin de l'image passait entre les deux courbes. Leur rayon vaut donc la
   moitié de la hauteur du titre, sans dépasser celui de la carte ; le coin
   sous le titre, lui, garde le rayon de la carte. Les deux quarts de cercle
   mordent d'un pixel sous le titre : aux tailles fractionnaires, un liseré de
   l'image passait sinon entre eux. */
.projet-titre{
  --pied-titre:clamp(.55rem,1vw,.95rem);
  --r-encoche:min(var(--rayon), calc((1.1em + var(--pied-titre)) / 2));
  position:absolute; z-index:2; top:0; left:0;
  padding:0 clamp(.9rem,1.5vw,1.5rem) var(--pied-titre) 0;
  background:var(--encoche); border-bottom-right-radius:var(--r-encoche);
  /* Pendant l'apparition, la carte glisse : le bord de l'image tombait sur
     des fractions de pixel et un liseré sombre passait au-dessus du nom. Le
     titre déborde donc de 2 px vers le haut et la gauche, à la couleur du
     fond, et le recouvre. */
  box-shadow:0 -2px 0 var(--encoche), -2px 0 0 var(--encoche), -2px -2px 0 var(--encoche);
  font-size:var(--titre-carte,clamp(1.3rem,1.8vw,2.1rem)); font-weight:500;
  line-height:1.1; letter-spacing:-.035em;
}
.projet-titre::before,
.projet-titre::after{
  content:''; position:absolute;
  --r:var(--rayon);
  background:radial-gradient(circle at 100% 100%,
    transparent calc(var(--r) - .5px), var(--encoche) var(--r));
}
/* Chaque quart de cercle ne déborde d'un pixel que du côté du titre : à
   droite, il s'élargit vers la gauche, sous le titre il s'allonge vers le
   haut. Le cercle garde ainsi son centre exact, et sa courbe rejoint le bord
   de l'image sans marche — un pixel de trop dans l'autre sens la décalait. */
.projet-titre::before{
  --r:var(--r-encoche);
  top:0; left:calc(100% - 1px);
  width:calc(var(--r) + 1px); height:var(--r);
}
.projet-titre::after{
  top:calc(100% - 1px); left:0;
  width:var(--r); height:calc(var(--r) + 1px);
}

.projet-pastilles{
  position:absolute; z-index:2;
  left:var(--marge-carte); bottom:var(--marge-carte);
  right:calc(var(--marge-carte) + 3.6rem);
  /* Les pastilles se rangent depuis le bas : la ligne du bas se remplit
     d'abord, et ce qui n'y tient pas monte au-dessus. Jamais une pastille
     seule en bas avec les autres perchées au-dessus d'elle. */
  display:flex; flex-wrap:wrap-reverse; gap:.4rem;
}
.projet-pastilles li{
  padding:.36rem .85rem; border-radius:6rem;
  background:var(--blanc); color:var(--noir); box-shadow:var(--ombre-barre);
  font-size:.78rem; font-weight:500; letter-spacing:.07em;
  line-height:1.4; text-transform:uppercase; white-space:nowrap;
}

/* Le bas de la carte : les pastilles, puis la phrase du projet, repliée.
   Au survol elle se déplie — les pastilles remontent d'autant — sur un
   léger dégradé noir qui monte du bas de l'image. */
.projet-bas{
  position:absolute; z-index:2;
  left:var(--marge-carte); bottom:var(--marge-carte);
  right:calc(var(--marge-carte) + 3.6rem);
}
.projet-bas .projet-pastilles{ position:static; }
.projet-ligne{
  max-height:0; overflow:hidden; opacity:0;
  max-width:46ch; color:var(--blanc);
  font-size:calc(var(--corps) * .9); line-height:1.45;
  transition:max-height .55s var(--ease), opacity .4s var(--ease), margin-top .55s var(--ease);
}
.projet-ligne strong{ font-weight:500; }
.projet-visuel::after{
  content:''; position:absolute; inset:auto 0 0 0; height:65%; z-index:1;
  background:linear-gradient(to top, rgba(22,20,21,.72) 0%, rgba(22,20,21,.35) 45%, rgba(22,20,21,0) 100%);
  opacity:0; pointer-events:none;
  transition:opacity .5s var(--ease);
}
@media (hover:hover){
  .projet-lien:hover .projet-ligne{ max-height:8em; opacity:1; margin-top:.7rem; transition-delay:0s, .1s, 0s; }
  .projet-lien:hover .projet-visuel::after{ opacity:1; }
}
.projet-lien:focus-visible .projet-ligne{ max-height:8em; opacity:1; margin-top:.7rem; }
.projet-lien:focus-visible .projet-visuel::after{ opacity:1; }
/* Sans survol (tactile), la phrase reste dépliée : c'est le seul moyen de la
   lire, et c'est là que le site est le plus consulté. */
@media (hover:none){
  .projet-ligne{ max-height:8em; opacity:1; margin-top:.7rem; }
  .projet-visuel::after{ opacity:1; }
}

/* La flèche : le rond du bouton, seul, en bas à droite. */
.projet-fleche{
  position:absolute; z-index:2; right:var(--marge-carte); bottom:var(--marge-carte);
  display:grid; place-items:center; width:2.9rem; height:2.9rem;
  border-radius:50%; background:var(--blanc); box-shadow:var(--ombre-barre);
  transition:background-color .38s var(--ease), transform .5s var(--ease);
}
.projet-fleche svg{
  width:1.05rem; height:1.05rem; fill:none; stroke:var(--noir);
  transition:stroke .38s var(--ease);
  stroke-width:2.4; stroke-linecap:round; stroke-linejoin:round;
}
@media (hover:hover){
  .projet-lien:hover .projet-visuel > img{ transform:scale(1.035); }
  .projet-lien:hover .projet-fleche{ background:var(--orange); transform:translateX(.2rem); }
  .projet-lien:hover .projet-fleche svg{ stroke:var(--blanc); }
}
.projet-lien:focus-visible{ outline:none; }
.projet-lien:focus-visible .projet-visuel{ outline:2px solid var(--orange); outline-offset:4px; }


/* Sans script, rien ne pose l'adresse de l'animation Lybe : l'affiche
   prend sa place en fond. */
html:not(.js) .projet--lybe .projet-visuel{
  background:var(--blanc) url("../Assets/realisations/lybe/signe-poster.jpg?v=d8876dfb") center/84% auto no-repeat;
}

/* --- Le bouton, le même partout ---
   Sa hauteur vaut deux retraits plus le diamètre du rond : le rond, posé à
   `--jeton-py` de chaque bord, y est donc centré par construction. Au survol,
   le rond et le texte échangent leur place — la course de chacun se déduit
   des mêmes retraits, elle s'adapte donc au libellé. */
.jeton{
  /* Redéclarée ici, et pas seulement à la racine : une propriété
     personnalisée est résolue là où elle est écrite, donc une variante qui
     change le retrait ou le diamètre ne remonterait pas jusqu'à la hauteur. */
  --jeton-h:calc(2 * var(--jeton-py) + var(--jeton-rond));
  position:relative; display:inline-flex; align-items:center;
  height:var(--jeton-h);
  padding-left:calc(var(--jeton-py) + var(--jeton-rond) + var(--jeton-ecart));
  padding-right:var(--jeton-pr);
  border-radius:6rem; background:var(--noir); color:var(--blanc);
  font-size:calc(var(--corps) * .94); font-weight:500; letter-spacing:-.01em;
  white-space:nowrap;
  transition:transform .35s var(--ease), background-color .38s var(--ease);
}
.jeton-texte{ position:relative; transition:transform .44s var(--ease); }
.jeton-rond{
  position:absolute; top:var(--jeton-py); left:var(--jeton-py);
  display:grid; place-items:center;
  width:var(--jeton-rond); height:var(--jeton-rond);
  border-radius:50%; background:var(--orange);
  transition:left .44s var(--ease), background-color .38s var(--ease);
}
.jeton-rond svg{
  width:.62em; height:.62em; fill:none; stroke:var(--blanc);
  stroke-width:3; stroke-linecap:round; stroke-linejoin:round;
  transition:stroke .38s var(--ease);
}
/* Deux mouvements, un seul battement : la flèche s'élance, le halo part
   d'elle. Ils ne dérivent donc jamais l'un par rapport à l'autre. Réservé au
   jeton d'appel de chaque page (`.jeton--appel`) : quand tout pulse, rien ne
   pulse. */
.js .jeton--appel .jeton-rond{ animation:appelle 3.6s var(--ease) infinite; }
.js .jeton--appel .jeton-rond::after{
  content:''; position:absolute; inset:0; border-radius:50%;
  animation:halo 3.6s var(--ease) infinite;
}
@keyframes appelle{ 0%,66%,100%{ transform:none; } 78%{ transform:translateX(.3rem); } }
@keyframes halo{
  0%,58%  { box-shadow:0 0 0 0 rgba(221,94,0,.45); }
  84%,100%{ box-shadow:0 0 0 .75rem rgba(221,94,0,0); }
}
.jeton:active{ transform:scale(.97); transition:transform .12s var(--ease); }
@media (hover:hover){
  .jeton:hover{ background:var(--orange-fond); color:var(--blanc); transform:translateY(-.18rem); }
  .jeton:hover .jeton-rond{
    left:calc(100% - var(--jeton-rond) - var(--jeton-py));
    background:var(--sable); animation:none; transform:none;
  }
  .jeton:hover .jeton-rond svg{ stroke:var(--noir); }
  .jeton:hover .jeton-rond::after{ animation:none; }
  .jeton:hover .jeton-texte{
    transform:translateX(calc(-1 * (var(--jeton-py) + var(--jeton-rond)
                                    + var(--jeton-ecart) - var(--jeton-pr))));
  }
}

/* Dans le premier écran, il prend la hauteur des boutons de la barre : le
   diamètre de son rond s'en déduit au lieu d'être choisi. */
.jeton--plein, .jeton--contour{
  --jeton-py:.55rem;
  --jeton-rond:calc(var(--haut-btn) - 2 * var(--jeton-py));
  --jeton-ecart:.9rem;
  --jeton-pr:1.7rem;
  font-size:var(--corps);
}
/* Le second bouton du premier écran : même hauteur, même rond orange, mais
   blanc cerclé de noir. Les deux appels se lisent au même poids. */
.jeton--contour{
  background:var(--blanc); color:var(--noir);
  box-shadow:inset 0 0 0 1.5px var(--noir);
}
@media (hover:hover){
  .jeton--contour:hover{ background:var(--noir); color:var(--blanc); box-shadow:none; }
}

/* ============================================================
   SECTION 5 — LA RÉSERVATION
   Le mot à gauche, le calendrier à droite. Le calendrier est un cadre
   étranger : on lui donne une carte à lui, avec un fond blanc et le même
   rayon que partout, pour qu'il ne dépareille pas.
   ============================================================ */
.rdv{
  margin-top:clamp(1.6rem,3vw,2.6rem);
  display:grid; gap:clamp(1.6rem,3vw,3.2rem);
  grid-template-columns:minmax(0,.85fr) minmax(0,1fr);
  /* Le calendrier prend la hauteur de la colonne de gauche : les deux côtés
     se referment à la même ligne, sans qu'aucune hauteur soit écrite. */
  align-items:stretch;
}
/* Le rectangle est un enfant de la grille, pas de la colonne : c'est ce qui
   permet de le poser à gauche ici, et sous le calendrier sur mobile, sans
   dupliquer le balisage. */
.rdv-mot   { grid-column:1; grid-row:1; }
.rdv-cadre {
  grid-column:2; grid-row:1;
  /* La carte descend jusqu'au bas de la colonne de gauche : les deux
     colonnes se referment à la même ligne. Elle avait été mise en
     `start` pour qu'elle épouse le calendrier — mais quand Cal est en
     paysage (538 px) et la colonne de gauche plus haute, cela laissait un
     vide sous la carte et à droite du rectangle. */
  align-self:stretch;
}
/* Le conteneur prend toute la place de la carte. */
.rdv-creneaux{ flex:1 1 auto; }
/* Le paragraphe se cale sur le bord haut du calendrier : la grille aligne
   déjà les deux colonnes, il suffit de ne rien ajouter au-dessus. */
.rdv-mot{ padding-top:0; }
/* La colonne prend la largeur du titre, et le paragraphe s'y plie : sa
   largeur propre ne compte pas (0), il s'étire ensuite à celle de la colonne.
   Il revient donc à la ligne là où le titre s'arrête. */
.rdv-mot{ justify-self:start; width:fit-content; max-width:100%; }
.rdv-texte{ width:0; min-width:100%; }
.rdv-ecrire{ margin-top:clamp(1.6rem,2.6vw,2.4rem); }
/* Le titre partage désormais la colonne de gauche avec le reste : il se règle
   sur la largeur de cette colonne, pas sur celle de la page. */
#reservation h2{ max-width:16ch; }
#reservation .etiquette{ margin-bottom:var(--etiquette-ecart); }
.rdv-texte{ margin-top:clamp(1.1rem,2vw,1.6rem); }
.rdv-texte{ font-size:var(--corps); line-height:1.6; max-width:none; }
.rdv-repli{
  margin-top:clamp(1.2rem,2.2vw,1.8rem);
  font-size:calc(.93 * var(--corps)); color:var(--gris-texte);
}
.rdv-repli a{ color:var(--noir); text-decoration:underline; text-underline-offset:.18em; }

.rdv-cadre{
  border-radius:var(--rayon); background:var(--blanc);
  box-shadow:var(--ombre-barre); overflow:hidden;
  /* Colonne flexible : c'est ce qui donne au conteneur du calendrier une
     hauteur *définie*. Un `height:100%` contre une hauteur d'étirement de
     grille ne se résout pas — le conteneur retombait alors sur sa réserve de
     382 px, et le calendrier flottait au milieu de la carte. */
  display:flex; flex-direction:column;
}
/* La hauteur ne se choisit pas au hasard : un calendrier montre un mois et
   une colonne d'horaires. En dessous il se met à défiler dans son cadre. */
/* Réserve d'attente pendant le chargement, volontairement plus basse que
   ce que Cal rend (538 px en paysage) : au-delà elle ajouterait du blanc. */
.rdv-creneaux{ min-height:clamp(20rem,40vh,26rem); display:grid; overflow:auto; }
/* Cal écrit la hauteur de son iframe EN LIGNE, dès qu'il connaît celle de son
   contenu : c'est elle qu'on garde. */
.rdv-creneaux iframe{ width:100%; height:auto; min-height:0; border:0; display:block; }
/* Sur ordinateur, le calendrier se CENTRE dans la carte, à sa hauteur
   naturelle. Il avait été forcé à la remplir (`height:100% !important`
   contre la hauteur en ligne que Cal écrit) : Cal dessine alors son contenu
   en haut de l'iframe, et l'on voyait une boîte collée au bord haut, la
   marque Cal.com dessous, et du vide en bas. Centré et sans bordure (voir
   `cssVarsPerTheme` dans le script), le même vide devient une marge. */
@media (min-width:901px){
  /* Le conteneur ne rétrécit jamais sous le calendrier (`flex-shrink:0`) :
     s'il le pouvait, Cal défilerait dans son propre cadre. La carte grandit
     plutôt, et la grille avec elle. */
  .rdv-creneaux{ flex:1 0 auto; align-content:center; overflow:visible; }
  /* La carte démarre à la hauteur du titre, pas à celle de l'étiquette :
     elle descend de la place que l'étiquette occupe au-dessus de lui, écart
     compris — c'est ce que vaut `--haut-etiquette`, déjà utilisé par le bloc
     de semaine de la méthode. Le bas ne bouge pas : la carte reste étirée sur
     les deux rangées, elle perd seulement sa marge en haut. */
  .rdv-cadre{ margin-top:var(--haut-etiquette); }
}

/* Sur un écran large, le calendrier tient dans une carte CARRÉE, à sa juste
   largeur : Cal dessine son contenu en pixels (720 px en paysage : le mois,
   puis les horaires) et le centre dans son cadre, en laissant du blanc de
   part et d'autre. Il ne passe en paysage qu'à partir de 820 px de cadre :
   l'iframe garde donc 860 px, centrée dans une carte de 752 px qui en rogne
   les bords vides — il reste 16 px d'air de chaque côté du contenu. Le texte
   prend toute la place restante, à gauche. */
@media (min-width:1200px){
  .rdv{ grid-template-columns:minmax(0,1fr) 752px; }
  .rdv-cadre{ width:752px; aspect-ratio:1; align-self:start; }
  .rdv-creneaux iframe{
    width:860px !important; min-width:860px !important; max-width:none !important;
    margin-left:calc((100% - 860px) / 2);
  }
  #reservation h2{ max-width:none; }
}

/* Sur un portable, la réservation doit se lire sans partir à sa recherche.
   Le retrait de section vaut 180 px de chaque côté à cette hauteur, soit
   360 px sur 1083 : ramené à 7 rem il place le bas du calendrier à 692 px
   pour 721 utiles sous la barre. Le rectangle, lui, reste à découvrir en
   descendant — c'est son rôle. */
@media (min-width:901px) and (max-height:900px), (min-width:1512px) and (min-aspect-ratio:168/100){
  #reservation{ padding-top:7rem; padding-bottom:7rem; }
}
.rdv-vide{
  place-self:center; padding:clamp(1.5rem,3vw,2.5rem);
  text-align:center; font-size:var(--corps); line-height:1.6;
  color:var(--gris-texte); max-width:32ch;
}
.rdv-vide a{ color:var(--noir); text-decoration:underline; text-underline-offset:.18em; }

/* --- Les deux pages légales ---
   Elles n'ont ni barre ni pied : une colonne de texte, et le retour. Elles
   partagent la feuille du site pour ne pas avoir de couleurs à elles. */
.texte-long{ max-width:70ch; }
.texte-long h3{
  margin-top:clamp(1.8rem,3.4vw,2.6rem); margin-bottom:.6rem;
  font-size:clamp(1.15rem,1.5vw,1.4rem); font-weight:500; letter-spacing:-.02em;
}
.texte-long p, .texte-long li{ font-size:var(--corps); line-height:1.65; }
.texte-long p + p{ margin-top:.8rem; }
.texte-long .chapo{ margin-top:clamp(1.2rem,2.2vw,1.8rem); }
.texte-long strong{ font-weight:500; }
.texte-long a{ text-decoration:underline; text-underline-offset:.18em; text-decoration-thickness:1px; }
@media (hover:hover){ .texte-long a:hover{ color:var(--orange); } }
.liste-long{ margin-top:.8rem; display:flex; flex-direction:column; gap:.8rem; padding-left:1.15rem; }
.liste-long li{ position:relative; }
.liste-long li::before{
  content:''; position:absolute; left:-1.15rem; top:calc(.825em - .21rem);
  width:.42rem; height:.42rem; border-radius:50%; background:var(--orange);
}

/* --- La boîte des textes légaux ---
   Sans script, ce n'est pas une boîte : c'est une section en fin de page, les
   deux textes l'un sous l'autre. Le fond, la croix et les onglets n'ont alors
   aucun sens et disparaissent. Avec script, tout bascule en dialogue. */
/* `.boite` est déclarée plus bas dans la feuille : à égalité de spécificité
   elle l'emporterait, et le bloc resterait un calque fixe en plein écran sans
   script. On double donc la classe pour passer devant. */
.boite.boite--legal{
  position:static; inset:auto; z-index:auto; display:block;
  padding:0 0 clamp(2.5rem,5vw,4rem);
}
.boite--legal .boite-fond,
.boite--legal .visionneuse-fermer,
.boite--legal .legal-onglets{ display:none; }
.boite--legal .boite-panneau{
  position:static; width:var(--largeur); margin:0 auto;
  max-height:none; overflow:visible;
  padding:0; background:none; box-shadow:none;
}
.boite--legal .legal-volet + .legal-volet{ margin-top:clamp(2.5rem,5vw,4rem); }

.js .boite.boite--legal{ position:fixed; inset:0; z-index:90; display:none; place-items:center; padding:0; }
.js .boite.boite--legal.ouverte{ display:grid; }
.js .boite--legal .boite-fond{ display:block; }
.js .boite--legal .visionneuse-fermer{ display:grid; }
.js .boite--legal .legal-onglets{ display:flex; }
.js .boite--legal .boite-panneau{
  position:relative; width:min(92vw,46rem); margin:0;
  max-height:min(88svh,52rem); overflow:auto;
  padding:clamp(1.3rem,2.6vw,2rem);
  background:var(--blanc); box-shadow:var(--ombre-barre);
}
.js .legal-volet{ display:none; }
.js .legal-volet.active{ display:block; }
.js .legal-nom{ position:absolute; left:-9999px; }   /* l'onglet le dit déjà */

.legal-nom{
  font-size:clamp(1.5rem,2.4vw,2rem); font-weight:500;
  line-height:1.1; letter-spacing:-.03em; margin-bottom:.4rem;
}
/* Les onglets reprennent la géométrie des pastilles : même rayon, même
   retrait vertical, l'orange marquant celui qu'on lit. */
.legal-onglets{ gap:.5rem; margin-bottom:clamp(1rem,2vw,1.4rem); flex-wrap:wrap; }
.legal-onglet{
  font:inherit; font-size:calc(.9 * var(--corps)); font-weight:500;
  padding:.42rem 1rem; border-radius:6rem; border:0; cursor:pointer;
  background:var(--sable); color:var(--noir);
  transition:background-color .3s var(--ease), color .3s var(--ease);
}
.legal-onglet[aria-pressed="true"]{ background:var(--orange-fond); color:var(--blanc); }
@media (hover:hover){
  .legal-onglet:not([aria-pressed="true"]):hover{ background:var(--gris); }
}

/* Dans le pied, les deux appels sont des boutons : ils ouvrent, ils ne mènent
   pas ailleurs. Ils gardent l'allure d'un lien. */
.pied-legal button{
  font:inherit; font-size:inherit; color:inherit;
  background:none; border:0; padding:0; cursor:pointer;
  transition:color .3s var(--ease);
}
@media (hover:hover){ .pied-legal button:hover{ color:var(--orange); } }

/* ============================================================
   SECTION 6 — LE PIED DE PAGE
   Fond blanc : la page se referme sur la couleur qui l'a ouverte.
   ============================================================ */
.pied{
  position:relative; background:var(--blanc);
  padding:0 0 clamp(1.6rem,3vw,2.4rem);
}
.pied-texte{
  margin-top:clamp(1.2rem,2.2vw,1.8rem);
  font-size:var(--corps); line-height:1.6; max-width:40ch;
}
.pied .actions{ margin-top:clamp(1.5rem,2.6vw,2.2rem); opacity:1; transform:none; }

/* L'anti-cible se lit comme une note, pas comme une offre. Elle vit dans la
   réservation, dont le fond est sable : elle prend donc le blanc, comme la
   carte du calendrier en face — deux surfaces claires sur le même fond. */

/* Le haut du pied : le logo et le métier, les sections du site, l'agence
   (adresse, e-mail). Un filet fin l'ouvre, à l'épaisseur des autres filets. */
.pied-haut{
  display:grid; grid-template-columns:minmax(0,1.3fr) minmax(0,1fr) minmax(0,1fr);
  gap:2rem clamp(2rem,4vw,5rem);
  padding-top:clamp(2.2rem,4.5vw,3.6rem);
}
.pied-logo{ height:4rem; width:auto; }
.pied-colonne p, .pied-colonne li{ font-size:calc(.95 * var(--corps)); line-height:1.6; }
.pied-logo + p{ margin-top:1rem; max-width:30ch; }
.pied-titre{
  margin-bottom:.7rem;
  font-size:.78rem; font-weight:500; letter-spacing:.09em; text-transform:uppercase;
  color:var(--gris-texte);
}
.pied-colonne ul{ display:flex; flex-direction:column; gap:.35rem; }
.pied-colonne a{ transition:color .3s var(--ease); }
@media (hover:hover){ .pied-colonne a:hover{ color:var(--orange); } }
.pied-adresse{ font-style:normal; }

/* La ligne du bas : l'année, les deux pages légales. */
.pied-bas{
  margin-top:clamp(1.6rem,3vw,2.6rem);
  padding-top:clamp(1.1rem,2vw,1.6rem);
  display:flex; align-items:baseline; justify-content:space-between;
  gap:1rem 2rem; flex-wrap:wrap;
  font-size:calc(.9 * var(--corps)); color:var(--gris-texte);
}
.pied-signature strong{ font-weight:500; color:var(--noir); }
.pied-legal{ display:flex; gap:1.4rem; flex-wrap:wrap; }
.pied-legal a{ color:inherit; transition:color .3s var(--ease); }
@media (hover:hover){ .pied-legal a:hover{ color:var(--orange); } }

@media (max-width:900px){
  .pied-haut{ grid-template-columns:1fr; gap:1.6rem; }
  .pied-bas{ flex-direction:column; align-items:flex-start; gap:.9rem; }
}

/* --- La boîte d'écriture ---
   Même mécanique que la visionneuse : un fond qui ferme, un panneau au même
   rayon, une tête avec la croix. Elle n'en reprend pas les règles pour autant,
   les deux n'ayant ni la même largeur ni le même contenu. */
.boite{ position:fixed; inset:0; z-index:90; display:grid; place-items:center; }
.boite[hidden]{ display:none; }
.boite-fond{ position:absolute; inset:0; background:rgba(34,31,32,.55); }
.boite-panneau{
  position:relative; width:min(92vw,34rem); max-height:min(90svh,44rem);
  overflow:auto; border-radius:var(--rayon);
  background:var(--blanc); box-shadow:var(--ombre-barre);
  padding:clamp(1.3rem,2.6vw,2rem);
}
.js .boite-panneau{ transform:translateY(1.2rem); transition:transform .32s var(--ease); }
.js .boite.ouverte .boite-panneau{ transform:none; }
.boite-tete{
  display:flex; align-items:flex-start; justify-content:space-between;
  gap:1rem; margin-bottom:clamp(1.1rem,2vw,1.5rem);
}
.boite-tete p{ font-size:var(--corps); line-height:1.4; }
/* La croix des boîtes. Elle a gardé le nom de la visionneuse, d'où elle vient. */
.visionneuse-fermer{
  display:grid; place-items:center; width:2.4rem; height:2.4rem; flex:0 0 auto;
  border-radius:50%; box-shadow:inset 0 0 0 1.5px var(--gris);
  transition:box-shadow .3s var(--ease);
}
.visionneuse-fermer:hover{ box-shadow:inset 0 0 0 1.5px var(--noir); }
.visionneuse-fermer svg{ width:1.05rem; height:1.05rem; fill:none; stroke:var(--noir); stroke-width:2; stroke-linecap:round; }
.boite-tete strong{ font-weight:500; }

[hidden]{ display:none !important; }
.formulaire{ display:flex; flex-direction:column; gap:clamp(.75rem,1.4vw,1.05rem); }
.champ{ display:flex; flex-direction:column; gap:.35rem; }
.champ label{
  font-size:calc(.9 * var(--corps)); font-weight:500;
  letter-spacing:.01em; color:var(--gris-texte);
}
.champ input, .champ textarea{
  font:inherit; font-size:var(--corps); color:var(--noir);
  padding:.7rem .9rem; border-radius:var(--rayon-petit); resize:vertical;
  background:var(--sable); border:1px solid rgba(34,31,32,.22);
  transition:border-color .25s var(--ease), background-color .25s var(--ease);
}
.champ input::placeholder, .champ textarea::placeholder{ color:rgba(34,31,32,.5); }
/* Un champ en erreur : bord orange, et la raison juste dessous. */
.champ--erreur input, .champ--erreur textarea{ border-color:var(--orange); background:var(--blanc); }
.champ-erreur{ font-size:calc(.85 * var(--corps)); line-height:1.4; color:var(--orange-fond); }
.champ input:focus-visible, .champ textarea:focus-visible{
  outline:0; background:var(--blanc); border-color:var(--orange);
}
/* Le piège doit être invisible à l'œil sans l'être aux robots : ni `hidden`
   ni `display:none`, qu'ils savent lire. */
.piege{ position:absolute; left:-9999px; width:1px; height:1px; overflow:hidden; }
.champ--verif input{ max-width:7rem; }

.formulaire-merci{ display:flex; flex-direction:column; align-items:flex-start; gap:.9rem; }
.merci-titre{
  font-size:clamp(1.5rem,2.4vw,2rem); font-weight:500;
  line-height:1.1; letter-spacing:-.03em;
}
.merci-texte{ font-size:var(--corps); line-height:1.55; max-width:34ch; }
.merci-texte strong{ font-weight:500; }

.formulaire-pied{
  display:flex; align-items:center; gap:1rem; flex-wrap:wrap;
  margin-top:.35rem;
}
.formulaire-etat{
  flex:1 1 12rem; min-width:0;
  font-size:calc(.9 * var(--corps)); line-height:1.4; color:var(--gris-texte);
}
.jeton[disabled]{ opacity:.6; pointer-events:none; }
/* Le lien du message de repli est un bouton : il ouvre la même boîte. */
.lien-ecrire{
  font:inherit; color:var(--noir); background:none; border:0; padding:0;
  text-decoration:underline; text-underline-offset:.18em; cursor:pointer;
}

@media (max-width:900px){
  .boite-panneau{ width:min(94vw,34rem); max-height:88svh; }
}

@media (max-width:900px){
  /* Empilés, les trois blocs reprennent leur rang : le mot, le calendrier,
     puis le rectangle. Les places de grille de l'ordinateur sont défaites,
     sinon elles continueraient de commander. */
  .rdv{ grid-template-columns:minmax(0,1fr); }
  .rdv-mot, .rdv-cadre{ grid-column:1; grid-row:auto; }
  .rdv-mot   { order:0; }
  .rdv-cadre { order:1; }
  /* La méthode n'a pas de retrait bas — son panneau est collant — et le pied
     n'en a pas non plus en haut. C'est donc la réservation qui porte l'air de
     ses deux côtés, et sur mobile il en faut plus que le retrait ordinaire. */
  #reservation{
    padding-top:clamp(4.5rem,10vh,7rem);
    padding-bottom:clamp(4.5rem,10vh,7rem);
  }
  /* Sur mobile Cal rend 398 px : une réserve de 544 (34 rem) laissait
     146 px de blanc dans la carte. Elle repasse sous le rendu réel — elle
     ne sert qu'à tenir la place pendant le chargement. */
  .rdv-creneaux{ min-height:clamp(16rem,40vh,22rem); }
  /* Rien ne s'étire : la carte épouse le calendrier, en haut comme en bas. */
  .rdv-creneaux{ align-content:start; }
  .rdv-creneaux iframe{ height:auto; min-height:0; }
}

@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{ animation:none !important; transition-duration:.01ms !important; }
  /* Sans mouvement, la vitrine montre sa première carte et l'intermède ses
     trois lignes, posées et pleines. */
  .monument-ligne{ transform:none; }
  .monument-ligne--contour span{ background:none; color:var(--orange); }
  .js .methode-piste{ height:auto; }
  .js .methode-collant{ position:static; min-height:0; display:block; }
  .js .methode-actions{ display:block; }
  .js .methode-semaine{ opacity:1; visibility:visible; transform:none; }
  .js .methode-semaine + .methode-semaine{ margin-top:2.2rem; }
  .js .methode-semaine li{ opacity:1; transform:none; }
  .bulle{ transform:translateX(-50%) scale(1); }
  /* Le signe portait une information : sans mouvement, on montre l'affiche,
     qui est le mot entier, plutôt que de laisser tourner la vidéo. */
  .projet-visuel > video.signe{ display:none; }
  .projet--lybe .projet-visuel{
    background:var(--blanc) url("../Assets/realisations/lybe/signe-poster.jpg?v=d8876dfb") center/84% auto no-repeat;
  }
}

/* ============================================================
   RESPONSIVE
   ============================================================ */
/* ============================================================
   ÉCRANS PEU HAUTS — PORTABLES
   Les portables : la hauteur contraint plus que la largeur. C'est la
   hauteur qui contraint, pas la largeur : le réglage se fait donc sur elle,
   ce qui laisse les grands écrans intacts.
   ============================================================ */
@media (min-width:901px) and (max-height:900px), (min-width:1512px) and (min-aspect-ratio:168/100){
  .offre{ min-height:clamp(20rem,62vh,28rem); }
  .vitrine{ width:min(100%, 26rem); }
  /* Septembre 2026 : la section tenait en 675 px sur 900 — serrée pour rien.
     L'air est rendu, et elle tient toujours d'un seul écran. */
  .section--avant-montage{ padding-top:6.2rem; padding-bottom:6.2rem; }
  /* L'écart sous le titre doit valoir celui qui le sépare de son étiquette :
     ils se lisent comme une paire. Sur écran court on réduit les deux à la
     même valeur — la marge des cartes se DÉDUIT de `--etiquette-ecart`, elles
     ne peuvent donc plus se désaccorder. C'est ici que ça se jouait : la
     marge des cartes tombait à 1,2 rem quand celle de l'étiquette restait à
     2,6, et le titre paraissait collé aux projets. */
  #pages{ --etiquette-ecart:2.4rem; }
}
/* Un cran de plus sous 700 px de haut, où les quelques dizaines de pixels
   qui restent font la différence entre « tout voir » et « devoir défiler ». */
@media (min-width:901px) and (max-height:700px){
  /* Sous 700 px de haut, l'écart entre les deux parties reste le même mais se
     répartit autrement : il descend dans la partie 2, qui a de la marge, pour
     que la partie 3 continue de tenir d'un seul écran. */
  /* Sous 700 px de haut l'écart reste doublé, mais il descend presque
     entièrement dans la partie 2 : c'est elle qui a de la marge. */
  .section--avant-montage{ padding-top:3.4rem; padding-bottom:3.4rem; }
  .etiquette{ margin-bottom:1.1rem; }
}

@media (max-width:1100px){
  .offres{ grid-template-columns:minmax(0,1fr) minmax(0,1fr); }
  .offre--suivi{ grid-column:1 / -1; min-height:0; }
}

@media (max-width:900px){
  .nav{
    flex-direction:column; align-items:stretch;
    padding:.5rem .5rem .5rem 1rem; border-radius:1.7rem;
  }
  .nav.ouvert{ padding-bottom:1.1rem; }
  .nav-haut{ justify-content:space-between; }
  .nav-mobile{ display:flex; }

  .nav-panneau{ display:grid; grid-template-rows:0fr; transition:grid-template-rows .5s var(--ease); }
  .nav.ouvert .nav-panneau{ grid-template-rows:1fr; }
  .nav-panneau-in{
    overflow:hidden; flex-direction:column; align-items:stretch;
    justify-content:flex-start; gap:0; padding:0 .5rem;
    /* Replié, le panneau est aussi invisible pour le clavier et les lecteurs
       d'écran ; le délai laisse finir l'animation de fermeture. */
    visibility:hidden; transition:visibility 0s .5s;
  }
  .nav.ouvert .nav-panneau-in{ visibility:visible; transition-delay:0s; }
  .nav-liens{ flex-direction:column; align-items:stretch; gap:0; padding-top:.9rem; }
  .nav-liens--d{ padding-top:0; }
  .nav-liens a{ padding:.95rem .25rem; font-size:1.45rem; letter-spacing:-.02em; }

  /* L'écart entre le bas de la barre et le titre était de 55 px ; il est
     doublé. Le retrait vaut donc l'ancien plus ces 55 px. */
  .hero{ justify-content:flex-start; padding-top:9.85rem; }
  h1{ max-width:none; }
  /* Les deux boutons côte à côte, à la largeur de l'écran. */
  .hero .actions{ flex-wrap:nowrap; gap:.5rem; }
  .hero .actions > *{ flex:0 1 auto; min-width:0; white-space:nowrap; }

  /* Le titre remonte : l'écart entre la barre et lui passe de 110 à 77 px,
     soit 30 % de moins. La mascotte ne bouge pas — elle est calée sur le bas
     du premier écran, dont la hauteur ne dépend pas de ce retrait. */
  .hero{ padding-top:7.8rem; }
  /* La règle finissait sur le dégradé vers le sable : la méthode se réserve
     du blanc après elle, pour que la fin du trait tombe sur du blanc franc. */
  .js .section--montage{ padding-bottom:clamp(2.5rem,6vh,4rem); }

  /* Le titre, puis la vitrine dessous, un peu moins large que l'écran. */
  .hero-inner{ grid-template-columns:minmax(0,1fr); }
  /* La pile au milieu de l'écran. Les cartes du dessous dépassent à droite
     et en haut : la boîte recule d'autant vers la gauche pour que ce soit
     l'ensemble, et non la seule carte du dessus, qui tombe au centre. */
  .vitrine{ justify-self:center; width:min(76%, 22rem); margin:1.6rem 0 0; left:-2%; }

  /* Les titres un cran plus grands sur téléphone, et l'intermède plus encore :
     sa ligne la plus longue occupe presque toute la largeur. */
  /* « Agence de création » tient sur une ligne, le mot qui tourne dessous :
     la taille suit la largeur (le texte fait 7,9 fois sa taille de long). */
  h1{ font-size:min(2.95rem, calc(90vw / 8.1)); }
  h2{ font-size:2.6rem; }
  .monument-ligne{ font-size:16.5vw; }
  .projet{ --titre-carte:1.55rem; }
  /* Le premier écran est plus haut sur mobile (la vitrine est dessous) : les
     réalisations n'ont pas besoin d'autant d'air pour s'en détacher. */
  .section--avant-montage{ padding-top:clamp(4rem,9vh,5.5rem); }
  .monument{ padding:clamp(3.5rem,9vh,5rem) 0; }

  .frise-groupe{ gap:2.5rem; padding-right:2.5rem; }

  h2{ max-width:none; }

  /* Les projets s'empilent : une colonne, plus de quinconce. */
  .realisations-tete .realisations-tous{ display:none; }
  .realisations-pied{ display:flex; justify-content:center; margin-top:clamp(3.2rem,10vw,4.4rem); }
  .galerie{ grid-template-columns:1fr; }
  .galerie-col + .galerie-col{ margin-top:clamp(3.2rem,10vw,4.4rem); }
  .galerie-col--decalee{ padding-top:0; }
  /* Le descriptif ayant disparu, la frise prend toute la largeur : c'est
     sa propre grille qui répartit la règle et les deux voies. */
  .methode-scene{
    grid-template-columns:minmax(0,1fr);
    grid-template-areas: "titre" "intro" "frise" "actions";
    gap:clamp(1.2rem,3vw,1.8rem) 0;
    align-items:start;
  }
  .methode-actions{ margin-top:0; }
  .frise-libelle .long{ display:none; }
  .frise-libelle .court{ display:inline; }

  /* La frise bascule : même valeur de position, autre axe. Plus courte
     qu'avant : le bloc de la semaine prend place dessous. */
  .frise-scene{ height:clamp(11rem,28svh,18rem); align-items:stretch; }
  .frise-regle{
    position:relative; grid-column:1; grid-row:1;
    width:1.2rem; height:auto;
    border-top:0; border-left:1.5px solid var(--gris);
  }
  .jour{
    left:0; top:calc(var(--p) * 1%);
    width:.45rem; height:1px;
  }
  .jour--semaine{ width:1.15rem; height:1.5px; }
  .frise-libelle{
    top:calc(var(--p) * 1%); left:1.5rem;
    margin-left:0; margin-top:-.5em;
    font-size:.78rem; letter-spacing:.06em;
  }
  /* Sous la frise, le bloc de la semaine active : sans lui, le téléphone ne
     voyait de la méthode que la règle. Plus serré qu'à l'ordinateur. */
  .methode-actions{ padding:1rem 1.1rem 1.1rem; }
  .methode-semaine-nom{ font-size:1.1rem; margin-bottom:.6rem; }
  .methode-semaine ul{ gap:.4rem; }
  .methode-semaine li{ font-size:calc(.92 * var(--corps)); line-height:1.4; max-width:none; }

  .frise-temps{
    padding-left:0;
    display:grid; grid-template-columns:var(--cols);
    column-gap:.8rem; row-gap:.55rem;
  }
  .voie-nom{
    position:static; width:auto; height:auto; grid-row:1;
    font-size:.78rem; letter-spacing:.06em;
  }
  .voie-nom--vous{ grid-column:2; }
  .voie-nom--nous{ grid-column:3; }

  .frise-scene{
    grid-column:1 / -1; grid-row:2;
    display:grid; grid-template-columns:var(--cols); column-gap:.8rem;
  }
  .voie{ grid-row:1; height:auto; margin-top:0; }
  .voie--vous{ grid-column:2; }
  .voie--nous{ grid-column:3; }
  .clip{
    left:0; width:auto; right:0;
    top:calc(var(--a) * 1% + 3px); bottom:auto;
    height:calc((var(--b) - var(--a)) * 1% - 6px);
    padding-inline:.55rem; font-size:.8rem; border-radius:var(--rayon-petit);
  }
  .frise-tete{
    top:calc(var(--t) * 1%); left:0; right:0; bottom:auto;
    width:auto; height:2px; margin-left:0; margin-top:-1px;
  }
  .frise-tete::before{ top:50%; left:-.1rem; transform:translate(0,-50%); }
  .frise-tete{ height:var(--trait-tete); margin-top:calc(var(--trait-tete) / -2); }
  /* La frise est verticale : la scène, qui a une hauteur écrite, devient un
     conteneur dans les deux sens, et le morceau de tête se pose en hauteur. */
  .frise-scene{ container-type:size; }
  .clip::after{
    left:0; right:0; bottom:auto; width:auto; margin-left:0;
    top:calc((var(--t) - var(--a)) * 1cqh - 3px);
    height:var(--trait-tete); margin-top:calc(var(--trait-tete) / -2);
  }
}

/* Sous 700 px de haut, les cinq blocs empilés ne tiennent pas dans un
   panneau collé : la section redevient un défilement ordinaire.
   `min-width:901px` est indispensable : sans lui ce repli d'ordinateur
   s'appliquait aussi aux téléphones, dont la hauteur utile passe sous
   700 px une fois la barre d'adresse déduite. Il y ramenait les blocs de
   semaine, que le mobile masque, et remettait le panneau en `display:block`,
   ce qui cassait la grille mobile — le texte tombait à un mot par ligne.
   Son jumeau de la partie 2 porte la même garde. */
@media (min-width:901px) and (max-height:700px){
  .js .methode-piste{ height:auto; }
  .js .methode-collant{ position:static; min-height:0; display:block; }
  .js .methode-actions{ display:block; }
  .js .methode-semaine{ opacity:1; visibility:visible; transform:none; }
  .js .methode-semaine + .methode-semaine{ margin-top:2.2rem; }
  .js .methode-semaine li{ opacity:1; transform:none; }
}

@media (max-width:640px){
  .offres{ grid-template-columns:1fr; }
  .offre, .offre--suivi{ min-height:0; grid-column:auto; }
  .offre-prix{ font-size:clamp(3rem,16vw,4.4rem); }
}

@media (max-width:490px){
  .btn, .pilule{ font-size:.94rem; }
  /* Le débordement est porté par la translation, pour rester égal en bas
     et à droite ; la taille vient du jeton. */
}
