/* ============================================================
   currymango — Home
   Tokens repris des variables Figma (fichier "currymango")
   ============================================================ */

/* Epilogue, hébergée sur le site (pas d'appel à Google Fonts : aucune adresse IP transmise).
   Police variable, graisses 100 à 900 en continu : la vague de graisse de la section services
   l'anime. Fichiers Google Fonts v20, découpés comme chez Google : latin (préchargé dans chaque
   page) et latin étendu (chargé seulement si un caractère de cette plage s'affiche).
   Licence SIL OFL 1.1 : assets/fonts/OFL.txt. */
@font-face {
  font-family: 'Epilogue';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url(../assets/fonts/epilogue-latin-ext.woff2) 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-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Epilogue';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url(../assets/fonts/epilogue-latin.woff2) 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;
}

:root {
  --beige:  #ffe6d8;
  --marron: #443025;
  --bleu:   #8e9ffe;
  --rose:   #ff92e4;
  --rouge:  #ff4733;
  --blanc:  #f5f5f5;
  --dark:   #1b1515;
  --muted:  #866c5e;

  --arrondis: 6px;
  --petit-espace: 16px;
  --grand-espace: 24px;

  --page: 1440px;
  --gutter: 20px;
  --header-h: calc(74 * var(--hs)); /* 20 + logo 44 + 10 */

  /* Largeur utile hors barre de défilement, posée par le JS (100vw l'inclut
     et ferait déborder la mise à l'échelle). */
  --vw: 100vw;

  /* Échelle (sans unité) du frame de la section services, posée par le JS. */
  --k: 1;

  /* Un pixel de la maquette Figma (1440 × 795) ramené à l'échelle du viewport :
     borné par la hauteur pour que le cadre ne déborde jamais verticalement. */
  --s: min(var(--vw) / 1440, 100svh / 795);

  /* Échelle du header. Il est aux cotes de la maquette (logo de 44) sur téléphone, tablette et
     écran normal, mais il grandit avec le reste sur les grands écrans : sinon il paraît
     minuscule à côté des images mises à l'échelle (écrans 21:9). */
  --hs: max(1px, var(--s));
}

*, *::before, *::after { box-sizing: border-box; }

/* Pas de barre de défilement visible (la page défile toujours à la molette, au clavier
   et au doigt). Sur téléphone et tablette elle est déjà en surimpression. */
html { scrollbar-width: none; }
html::-webkit-scrollbar { display: none; }

/* Pas de scroll-behavior: smooth — incompatible avec le pin de ScrollTrigger
   (le défilement vers le haut devient impossible). Le lissage des ancres est en JS. */

body {
  margin: 0;
  background: var(--beige);
  color: var(--marron);
  font-family: 'Epilogue', system-ui, -apple-system, 'Segoe UI', sans-serif;
  letter-spacing: -0.03em;
  /* clip et non hidden : hidden ferait de <body> un conteneur de défilement,
     ce qui casserait position:sticky sur la colonne texte des Projets. */
  overflow-x: clip;
  -webkit-font-smoothing: antialiased;
}

img { display: block; max-width: 100%; }
ul  { list-style: none; margin: 0; padding: 0; }
a   { color: inherit; text-decoration: none; }

/* ---------- Échelle typographique (Figma) ---------- */
.h1 {
  font-size: clamp(48px, 6.67vw, 96px);
  line-height: 1.042;
  font-weight: 600;
}
.h2 {
  font-size: clamp(28px, 2.78vw, 40px);
  line-height: 1.125;
  font-weight: 600;
  margin: 0;
}
.body-lead { font-size: 20px; line-height: 26px; font-weight: 500; margin: 0; }
.body-md   { font-size: 16px; line-height: 22px; font-weight: 400; margin: 0; }
.body-sm   { font-size: 14px; line-height: 20px; font-weight: 400; margin: 0; }
.legal     { font-size: 12px; line-height: 1;    font-weight: 400; }

/* ---------- Boutons ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 15px 20px 14px;
  border: 0;
  border-radius: var(--arrondis);
  font: 500 20px/26px 'Epilogue', sans-serif;
  letter-spacing: -0.03em;
  cursor: pointer;
}
.btn--brown { background: var(--marron); color: var(--beige); }
.btn--pink  { background: var(--rose);   color: var(--dark); padding: 16px 25px 15px; }

/* Flèche des CTA (maquette 1345:128, état 1 et survol) : une flèche à gauche du texte, de la
   couleur du texte. Au survol elle s'allonge jusqu'au bout du bouton et pousse le texte, qui
   sort par la droite ; au départ de la souris, l'inverse (vidéo de réf. « CTA hover alexis »).
   Cotes en em (maquette en 20 px) : flèche de 32.3 × 20.3, trait de 2.67, 10 avant le texte ;
   elles suivent donc la taille de chaque bouton. Toute la flèche est dessinée dans
   .btn__arrow, qui couvre la zone de contenu : le trait s'allonge (width) et la pointe glisse
   (left) du même mouvement que le texte (translate de sa largeur + l'écart). */
.btn__inner {
  --arrow: 1.615em;   /* longueur de la flèche au repos */
  --head: .635em;     /* largeur de la pointe */
  --gap: .5em;        /* flèche → texte */
  --in: .6s cubic-bezier(.65, 0, .35, 1);   /* aller : départ et fin en douceur */
  --out: .6s cubic-bezier(.22, 1, .36, 1);  /* retour : vif puis longue fin */
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--gap);
}
.btn__icon { flex: none; width: var(--arrow); }
/* Découpe du texte qui sort par la droite. Élargie d'un rien dans la marge du bouton : avec
   l'interlettrage négatif, la dernière lettre déborde de sa boîte et serait rognée. */
/* Centrage optique (2026-10-05, « le texte est un poil trop haut ») : la boîte de ligne est
   centrée, mais les capitales en haut de la boîte laissaient 18 px au-dessus et 22 px sous la
   ligne de base (bouton de 20 px). Le texte descend de .1em : capitales centrées dans le bouton.
   La flèche ne bouge pas (elle reste au milieu du bouton). */
.btn__label { position: relative; top: .1em; overflow: hidden; padding-right: .2em; margin-right: -.2em; }
.btn__text { display: block; transition: translate var(--out); }
.btn__arrow {
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  height: 1.015em;
  translate: 0 -50%;
  pointer-events: none;
}
.btn__line {
  position: absolute;
  left: 0;
  top: 50%;
  width: var(--arrow);
  height: .1335em;
  translate: 0 -50%;
  border-radius: 1em;
  background: currentColor;
  transition: width var(--out);
}
.btn__head {
  position: absolute;
  top: 0;
  left: calc(var(--arrow) - var(--head));
  width: var(--head);
  height: 100%;
  overflow: visible;
  fill: none;
  stroke: currentColor;
  stroke-width: 2.67;
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: left var(--out);
}
@media (hover: hover) {
  .btn:hover .btn__text { translate: calc(100% + var(--gap)) 0; transition: translate var(--in); }
  .btn:hover .btn__line { width: 100%; transition: width var(--in); }
  .btn:hover .btn__head { left: calc(100% - var(--head)); transition: left var(--in); }
}
.btn:focus-visible .btn__text { translate: calc(100% + var(--gap)) 0; transition: translate var(--in); }
.btn:focus-visible .btn__line { width: 100%; transition: width var(--in); }
.btn:focus-visible .btn__head { left: calc(100% - var(--head)); transition: left var(--in); }

/* ============================================================
   HERO
   ============================================================ */
.hero {
  position: relative;
  height: 100svh;
  background: var(--marron);
  color: var(--beige);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-between;
  overflow: hidden;
}
/* Place du header (désormais fixe, hors du hero) : garde le contenu du hero
   exactement où il était quand le header en faisait partie. */
.hero::before { content: ''; flex: none; height: var(--header-h); }

/* Préloader (accueil, première page de la visite) : fond marron plein écran au-dessus de tout
   (sous le curseur) ; la vidéo est placée par main.js pour que sa dernière image tombe sur le
   logo du hero. Pendant ce temps, header, slogan et lien du hero attendent, invisibles. */
.preloader { display: none; }
.is-preloading .preloader {
  display: block;
  position: fixed;
  inset: 0;
  z-index: 150;
  overflow: hidden;
  background: var(--marron);
}
/* La vidéo n'est pas montrée telle quelle : son fond, décodé et affiché à part (surtout en HDR),
   ne tombe jamais exactement sur le marron de la page. main.js la recopie image par image dans
   le canevas en rendant ce fond transparent : l'animation se pose sur le vrai marron. */
.preloader__video { position: absolute; left: 0; top: 0; display: block; max-width: none; height: auto; opacity: 0; }
.preloader__canvas { position: absolute; left: 0; top: 0; display: block; }
/* À la fin, le logo de la vidéo se fond dans cette copie du logo du hero (filtre d'encre posé
   sur .preloader__ink par main.js), à la même place : quand le calque disparaît, rien ne bouge. */
.preloader__ink { position: absolute; inset: 0; }
.preloader__logo { position: absolute; left: 0; top: 0; max-width: none; height: auto; opacity: 0; }
.is-preloading .menu,
.is-preloading .hero__tagline,
.is-preloading .hero__scroll { opacity: 0; }

/* ============================================================
   HEADER — fixe sur toute la page
   Fond foncé dessous : logo et bouton en beige.
   Fond clair dessous (.menu--on-light) : en marron.
   ============================================================ */
.menu {
  --menu-ink: var(--beige);
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 50;
  height: var(--header-h);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: calc(20 * var(--hs)) calc(var(--gutter) * var(--hs) / 1px) calc(10 * var(--hs));
  /* Le bandeau est transparent : il ne doit pas bloquer les clics sur la page. */
  pointer-events: none;
  transition: opacity .4s ease, transform .4s ease, visibility 0s;
}
.menu > * { pointer-events: auto; }
/* Sur le footer : le header s'efface (main.js, initHeaderTheme). visibility le rend
   aussi inatteignable au clic et au clavier, une fois le fondu fini. */
.menu--hidden {
  opacity: 0;
  transform: translateY(-16px);
  visibility: hidden;
  transition: opacity .4s ease, transform .4s ease, visibility 0s .4s;
}
.menu--on-light {
  --menu-ink: var(--marron);
}
/* Logo en SVG intégré : son tracé prend la couleur du texte (currentColor). */
.menu__logo-mark {
  display: block;
  width: calc(44 * var(--hs));
  height: calc(44 * var(--hs));
  overflow: visible;
  color: var(--menu-ink);
  transition: color .35s ease;
}
/* Bouton « Menu » / « Fermer » : texte seul, sans pastille (header de la home et
   « Menu Neutre » dans Figma). Le mot finit à la même distance du bord droit que le
   logo du bord gauche (la marge du header) ; son rembourrage reste une zone cliquable,
   que la marge négative fait déborder dans la marge du header. */
.menu__btn {
  background: none;
  color: var(--menu-ink);
  border: 0;
  padding: calc(10 * var(--hs)) calc(20 * var(--hs));
  margin-right: calc(-1 * var(--gutter) * var(--hs) / 1px);
  font: 400 calc(20 * var(--hs)) / calc(21 * var(--hs)) 'Epilogue', sans-serif;
  letter-spacing: -0.02em;
  cursor: pointer;
  /* Epilogue est chargée en police variable : la graisse s'anime en continu. */
  transition: font-weight .3s ease, translate .3s ease, color .35s ease;
}
/* Survol (« Menu » comme « Fermer ») : le mot s'épaissit depuis son centre, puis revient à la
   sortie. Le bouton est calé à droite, il s'élargirait donc vers la gauche : on le décale
   vers la droite de la moitié du gain de largeur (--grow, mesuré dans main.js).
   Souris seulement : au doigt, le survol resterait collé après le toucher. */
@media (hover: hover) {
  .menu__btn:hover { font-weight: 700; translate: calc(var(--grow, 0px) / 2) 0; }
}
.menu__btn:focus-visible { font-weight: 700; translate: calc(var(--grow, 0px) / 2) 0; }

/* ============================================================
   MENU — panneau plein écran
   ============================================================ */
.menu-panel {
  position: fixed;
  inset: 0;
  z-index: 40; /* sous le header (50) : le bouton « Fermer » reste au-dessus */
  overflow: hidden;
  color: var(--beige);
  /* Fermé : masque d'aire nulle. L'ouverture anime ce polygone (main.js). */
  clip-path: polygon(0 100%, 0 100%, 0 100%);
  visibility: hidden;
}
.menu-panel.is-open,
.menu-panel.is-animating { visibility: visible; }
/* Arrivée depuis un lien du menu : le panneau couvre déjà l'écran à la première image (classe
   posée par le petit script en tête de page), le temps que la nouvelle page se charge
   dessous. main.js rejoue ensuite la fermeture pour la découvrir. */
.menu-arrive .menu-panel {
  visibility: visible;
  clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%);
}
/* Header clair sur le panneau, comme menu ouvert (sans ça, il prendrait un instant la couleur
   de la page qui est dessous). */
.menu-arrive .menu { --menu-ink: var(--beige); }
/* Changement de page hors menu (cartes, boutons, footer…) : la page suivante s'ouvre dans la
   forme du menu, par-dessus celle qu'on quitte (transition de vue entre documents : Chrome,
   Edge, Safari 18.2+ ; ailleurs, changement de page simple). L'ancienne page reste figée
   dessous, la nouvelle (vivante) est découpée par le masque du menu : mêmes angles, même
   courbe, même durée (0,57 s). Images clés générées d'après applyMask (main.js) ; les sommets
   glissent le long des bords, l'interpolation entre deux images est donc exacte.
   Le script de tête retient l'ouverture (vt-wait) jusqu'au chargement de la page, 1 s au
   plus, pour découvrir une page finie. Les liens du menu gardent leur propre passage (main.js
   annule la transition de vue). */
@view-transition { navigation: auto; }
@media (prefers-reduced-motion: reduce) {
  @view-transition { navigation: none; }
}
::view-transition-old(root),
::view-transition-new(root) { mix-blend-mode: normal; }
::view-transition-old(root) { animation: none; }
::view-transition-new(root) { animation: cm-page-reveal .57s linear both; }
:root.vt-wait::view-transition-new(root) { animation-play-state: paused; }
@keyframes cm-page-reveal {
  0% { clip-path: polygon(100% 0, 0 100%, 0 100%, 0 100%); }
  2.5% { clip-path: polygon(100% 0, 0 98.55%, 0 100%, 1.45% 100%); }
  5% { clip-path: polygon(100% 0, 0 96.53%, 0 100%, 3.47% 100%); }
  7.5% { clip-path: polygon(100% 0, 0 93.81%, 0 100%, 6.19% 100%); }
  10% { clip-path: polygon(100% 0, 0 90.27%, 0 100%, 9.73% 100%); }
  12.5% { clip-path: polygon(100% 0, 0 85.77%, 0 100%, 14.23% 100%); }
  15% { clip-path: polygon(100% 0, 0 80.18%, 0 100%, 19.82% 100%); }
  17.5% { clip-path: polygon(100% 0, 0 73.52%, 0 100%, 26.48% 100%); }
  20% { clip-path: polygon(100% 0, 0 66.09%, 0 100%, 33.91% 100%); }
  22.5% { clip-path: polygon(100% 0, 0 58.52%, 0 100%, 41.48% 100%); }
  25% { clip-path: polygon(100% 0, 0 51.46%, 0 100%, 48.54% 100%); }
  27.5% { clip-path: polygon(100% 0, 0 45.29%, 0 100%, 54.71% 100%); }
  30% { clip-path: polygon(100% 0, 0 40.01%, 0 100%, 59.99% 100%); }
  32.5% { clip-path: polygon(100% 0, 0 35.53%, 0 100%, 64.47% 100%); }
  35% { clip-path: polygon(100% 0, 0 31.68%, 0 100%, 68.32% 100%); }
  37.5% { clip-path: polygon(100% 0, 0 28.35%, 0 100%, 71.65% 100%); }
  40% { clip-path: polygon(100% 0, 0 25.43%, 0 100%, 74.57% 100%); }
  42.5% { clip-path: polygon(100% 0, 0 22.86%, 0 100%, 77.14% 100%); }
  45% { clip-path: polygon(100% 0, 0 20.57%, 0 100%, 79.43% 100%); }
  47.5% { clip-path: polygon(100% 0, 0 18.51%, 0 100%, 81.49% 100%); }
  50% { clip-path: polygon(100% 0, 0 16.66%, 0 100%, 83.34% 100%); }
  52.5% { clip-path: polygon(100% 0, 0 14.98%, 0 100%, 85.02% 100%); }
  55% { clip-path: polygon(100% 0, 0 13.46%, 0 100%, 86.54% 100%); }
  57.5% { clip-path: polygon(100% 0, 0 12.06%, 0 100%, 87.94% 100%); }
  60% { clip-path: polygon(100% 0, 0 10.79%, 0 100%, 89.21% 100%); }
  62.5% { clip-path: polygon(100% 0, 0 9.61%, 0 100%, 90.39% 100%); }
  65% { clip-path: polygon(100% 0, 0 8.54%, 0 100%, 91.46% 100%); }
  67.5% { clip-path: polygon(100% 0, 0 7.55%, 0 100%, 92.45% 100%); }
  70% { clip-path: polygon(100% 0, 0 6.64%, 0 100%, 93.36% 100%); }
  72.5% { clip-path: polygon(100% 0, 0 5.79%, 0 100%, 94.21% 100%); }
  75% { clip-path: polygon(100% 0, 0 5.02%, 0 100%, 94.98% 100%); }
  77.5% { clip-path: polygon(100% 0, 0 4.3%, 0 100%, 95.7% 100%); }
  80% { clip-path: polygon(100% 0, 0 3.65%, 0 100%, 96.35% 100%); }
  82.5% { clip-path: polygon(100% 0, 0 3.04%, 0 100%, 96.96% 100%); }
  85% { clip-path: polygon(100% 0, 0 2.48%, 0 100%, 97.52% 100%); }
  87.5% { clip-path: polygon(100% 0, 0 1.97%, 0 100%, 98.03% 100%); }
  90% { clip-path: polygon(100% 0, 0 1.5%, 0 100%, 98.5% 100%); }
  92.5% { clip-path: polygon(100% 0, 0 1.07%, 0 100%, 98.93% 100%); }
  95% { clip-path: polygon(100% 0, 0 0.68%, 0 100%, 99.32% 100%); }
  97.5% { clip-path: polygon(100% 0, 0 0.32%, 0 100%, 99.68% 100%); }
  100% { clip-path: polygon(100% 0, 0 0, 0 100%, 100% 100%); }
}

.menu-panel__frame {
  /* Écran plus large que la maquette (21:9…) : le frame est mis à l'échelle par la
     hauteur et déborde à droite ; --center recentre la composition visible, du début
     des liens (x = 102) au bord droit de la mascotte (x ≈ 1527, qui dépasse la maquette),
     soit un centre à 814.5. Écran 16:9 ou plus étroit : 0, calage de la maquette. */
  --center: max(0px, calc(var(--vw) / var(--k) / 2 - 814.5px));
  position: absolute;
  left: 0;
  top: 50%;
  width: calc(var(--vw) / var(--k));
  height: 795px;
  transform-origin: 0 50%;
  transform: translateY(-50%) scale(var(--k));
}

/* Fond : trame de la photo (image 1716 × 795 = la photo calée en hauteur, bord gauche
   à x = -276 dans le frame). Le fond vit DANS le frame pour que l'ombre de la mascotte
   (mode différence) se mélange avec lui ; il déborde du frame pour couvrir l'écran. */
.menu-panel__bg {
  position: absolute;
  z-index: 0;
  left: 0;
  width: calc(var(--vw) / var(--k));
  top: calc(397.5px - 50vh / var(--k));
  height: calc(100vh / var(--k));
  background: #382820 url('../assets/img/menu-halftone.png') right center / cover no-repeat;
}

.menu-panel__nav ul { list-style: none; margin: 0; padding: 0; }
/* Cotes Figma : coin haut-gauche de la boîte de texte (non tournée), qui pivote
   autour de ce coin. Vérifié : le bord droit de « Projets » tombe alors pile sur
   le bord du groupe Figma, et les départs de ligne sur ceux de la vidéo. */
/* Décalages en left plutôt qu'en translate : GSAP anime ces calques (glissement des
   liens, montée de la mascotte) et intègre un translate CSS à sa propre transformation,
   qui ne suivrait alors plus --center au redimensionnement. */
.menu-panel__nav li {
  position: absolute;
  left: calc(var(--x) + var(--center));
  top: var(--y);
  transform-origin: 0 0;
  translate: var(--slide, 0px) 0; /* glissement d'entrée (main.js) */
  rotate: var(--tilt);
}
/* Corps, approche et ligne de base calés sur les glyphes du rendu Figma (profil haut/bas
   de chaque mot, écart moyen ≈ 1 px) : ligne de base à 99 px du coin, départ à +3 px. */
.menu-link {
  position: relative;
  display: block;
  font-size: 125px;
  line-height: 128px;
  font-weight: 500;
  letter-spacing: -0.04em;
  white-space: nowrap;
  color: var(--beige);
}
.menu-link__text { display: block; padding-left: 3px; }

/* Surligné au survol : forme de couleur + bande (--hl / --hl-paper, tracés relevés
   dans les frames Figma « Hover ») et une copie marron du mot, dans un même conteneur
   découpé. La boîte (--bx/--by/--bw/--bh, posée sur le lien) englobe les tracés, pointe
   comprise ; le balayage s'ouvre depuis la droite et se referme vers la droite.

   --wipe = bord du balayage, en px dans le repère du lien : à sa droite, surlignage et
   mot marron ; à sa gauche, mot beige. Les deux découpages lisent la même valeur, donc
   le mot beige disparaît exactement là où la copie marron apparaît (sinon son liseré
   d'anticrénelage dépasse autour des jambages du j et du p). */
@property --wipe {
  syntax: '<length>';
  inherits: true;
  initial-value: 0px;
}
.menu-link {
  --wipe: calc(var(--bx) + var(--bw));
  transition: --wipe .45s cubic-bezier(.65, 0, .35, 1);
}
.menu-link:hover,
.menu-link:focus-visible {
  --wipe: var(--bx);
  transition: --wipe .6s cubic-bezier(.22, 1, .36, 1);
}
.menu-link > .menu-link__text { clip-path: inset(-60px calc(100% - var(--wipe)) -60px -60px); }
.menu-link__on {
  position: absolute;
  left: var(--bx);
  top: var(--by);
  width: var(--bw);
  height: var(--bh);
  pointer-events: none;
  clip-path: inset(-2px 0 -2px calc(var(--wipe) - var(--bx)));
}
.menu-link__on svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.menu-link__shape { fill: var(--hl); }
.menu-link__paper { fill: var(--hl-paper); }
.menu-link__on .menu-link__text {
  position: absolute;
  left: calc(-1 * var(--bx));
  top: calc(-1 * var(--by));
  color: var(--marron);
}
.menu-link:focus-visible { outline: none; }

/* Mascotte : les deux « Union » du Figma, ombre décalée de -10 / +13, pivotées de -15°
   autour de leur coin haut-gauche. 972.45 px est la boîte du tracé tourné : côté réel
   794 px (972.45 / (cos 15° + sin 15°)) — contour vérifié sur le rendu Figma à ~1.5 px
   près. Deux calques frères plutôt qu'un groupe :
   un groupe transformé isolerait l'ombre, qui doit se mélanger avec la trame.
   L'ombre #7b4d34 en « différence » : relevé sur le rendu Figma, elle donne pile
   |fond − #7b4d34| sur la photo, le rose et le beige. */
.menu-panel__mascot {
  position: absolute;
  inset: 0;
  left: var(--center);
  right: calc(-1 * var(--center));
  pointer-events: none;
}
.menu-panel__mascot svg {
  position: absolute;
  width: 794px;
  height: 794px;
  overflow: visible;
  transform-origin: 0 0;
  rotate: -15deg;
}
.menu-panel__mascot--shadow { mix-blend-mode: difference; color: #7b4d34; }
.menu-panel__mascot--shadow svg { left: 595px; top: 130.5px; }
.menu-panel__mascot--face { color: var(--beige); }
.menu-panel__mascot--face svg { left: 605px; top: 117.5px; }

.hero__center {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--petit-espace);
  width: 100%;
  padding: 0 var(--gutter);
}
.hero__title { margin: 0; } /* h1 autour du logo : aucun effet sur la mise en page */
.hero__wordmark {
  display: block;
  width: min(658px, 80vw);
  height: auto;
}
.hero__tagline {
  font-size: 20px;
  line-height: 26px;
  font-weight: 500;
  text-align: center;
  margin: 0;
}

.hero__scroll {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  padding-bottom: 40px;
  font-size: 16px;
  line-height: 22px;
}
.hero__scroll img { width: 14px; height: 13px; }
.hero__scroll:hover img { animation: bob .8s ease-in-out infinite; }
@keyframes bob { 50% { transform: translateY(4px); } }

/* ============================================================
   TRANSITION 1 — la pyramide beige monte depuis le bas du hero
   ============================================================ */
.wipe {
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  transform: translateY(100%);
  will-change: transform;
  pointer-events: none;
  z-index: 2;
}
.wipe__step {
  width: var(--w);
  height: clamp(48px, 6.944vw, 100px);
  background: var(--beige);
  flex: none;
}
.wipe__fill {
  width: 100%;
  height: 100svh;
  background: var(--beige);
  flex: none;
}

/* ============================================================
   PROJETS
   ============================================================ */
/* Cotes de la maquette Figma (1440 × 795) multipliées par --s.
   Pas d'overflow ici : la colonne de visuels est simplement plus haute que
   l'écran et la page défile à travers. Un overflow créerait un conteneur de
   défilement et casserait le sticky de la colonne texte. */
.projects {
  background: var(--beige);
  display: flex;
  justify-content: center;
}
.projects__inner {
  width: calc(1440 * var(--s));
  padding: calc(250 * var(--s)) calc(20 * var(--s)) calc(160 * var(--s));
  display: flex;
  align-items: flex-start;
  gap: calc(42 * var(--s));
}
.projects__text {
  flex: 0 0 calc(490 * var(--s));
  width: calc(490 * var(--s));
  height: calc(497 * var(--s));
  position: sticky;
  /* Exactement la position du bloc dans la maquette : le texte est déjà à son
     point d'ancrage quand la section arrive, donc aucun recalage au 1er scroll. */
  top: calc(250 * var(--s));
  /* Le collant s'arrête au bas de la colonne des cartes, bouton compris : cette marge
     (marge du bouton 40 + sa hauteur 15 + 26 + 14) le fait s'arrêter au bas de la
     dernière image, bas de la description aligné dessus. */
  margin-bottom: calc(95 * var(--s));
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}
.projects__desc {
  display: flex;
  flex-direction: column;
  gap: calc(16 * var(--s));
}
/* Fenêtre du titre : le sortant glisse hors champ, l'entrant arrive de l'autre bord. */
.proj-title { overflow: hidden; }
.proj-title span { display: block; }

.projects .h2        { font-size: calc(40 * var(--s)); line-height: calc(45 * var(--s)); }
.projects .body-lead { font-size: calc(20 * var(--s)); line-height: calc(26 * var(--s)); }
.projects .body-md   { font-size: calc(16 * var(--s)); line-height: calc(22 * var(--s)); }

.projects__viewport {
  flex: 0 0 calc(868 * var(--s));
  width: calc(868 * var(--s));
}
.projects__track {
  display: flex;
  flex-direction: column;
  gap: calc(10 * var(--s));
}
.project-card {
  position: relative;
  height: calc(498 * var(--s));
  flex: 0 0 calc(498 * var(--s));
  border-radius: calc(6 * var(--s));
  overflow: hidden;
  background: var(--marron);
}
.project-card img { width: 100%; height: 100%; object-fit: cover; }
/* Vidéo facultative (data-video, initVideos) sur n'importe quel emplacement d'image (carte
   de l'accueil, image d'une page projet) : par-dessus l'image, sous un éventuel lien,
   invisible tant qu'elle ne joue pas ; fondu à l'apparition comme à la sortie. L'élément
   qui porte data-video doit être en position relative. */
.video-layer {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity .6s ease;
  pointer-events: none;
}
.is-playing > .video-layer { opacity: 1; }
/* Lecteur Vimeo : une iframe n'a pas d'object-fit. main.js la dimensionne en pixels pour
   que la vidéo couvre l'emplacement (même recadrage que l'image), avec des bandes en plus
   en haut et en bas où tombe l'interface Vimeo ; ici on la centre. */
.video-layer--vimeo {
  inset: auto;
  top: 50%;
  left: 50%;
  width: 100%;
  height: 100%;
  translate: -50% -50%;
  border: 0;
}
/* Page projet : la vidéo remplace l'image d'emblée (figée sur sa première image), sans fondu. */
.pj .video-layer { transition: none; }
/* Toute la carte mène à la page du projet (lien posé par-dessus, l'image reste dessous). */
.project-card__link { position: absolute; inset: 0; z-index: 1; }
/* Après la dernière carte. Bouton à l'échelle de la section, comme ceux des autres sections. */
.projects__cta {
  margin-top: calc(40 * var(--s));
  font-size: calc(20 * var(--s));
  line-height: calc(26 * var(--s));
  padding: calc(15 * var(--s)) calc(20 * var(--s)) calc(14 * var(--s));
  border-radius: calc(6 * var(--s));
}

/* ============================================================
   TRANSITIONS COULEUR (2 & 3)
   ============================================================ */
/* Bande d'un écran de haut. Le virage de couleur se joue pendant que la
   section suivante monte par-dessous : la bande et cette section prennent la
   même couleur en même temps (main.js), donc pas de couture, et la couleur
   atteint son pic pile quand la section arrive en haut de l'écran. */
.transition { height: 100svh; }
.transition-2 { background-color: var(--beige); }
.transition-3 { background-color: var(--bleu); }

/* ============================================================
   SERVICES — bande horizontale (4620 px dans Figma)
   ============================================================ */
.services {
  position: relative;
  /* Épinglée au scroll : doit remplir le viewport pour éviter une bande vide. */
  height: 100svh;
  background: var(--bleu);
  overflow: hidden;
}
/* Le frame Figma (795px de haut) rendu à l'échelle --k et centré verticalement.
   Toutes les cotes à l'intérieur sont celles de la maquette, en px maquette.
   Sa largeur couvre tout l'écran une fois mis à l'échelle. */
.services__frame {
  /* Écran plus large que la maquette (21:9…) : la maquette de 1440 est centrée dans la
     largeur (la bande et le bouton décalés de --center) ; main.js compte les seuils
     d'apparition dans cette maquette centrée. */
  --center: max(0px, calc((var(--vw) / var(--k) - 1440px) / 2));
  position: absolute;
  left: 0;
  top: 50%;
  width: calc(var(--vw) / var(--k));
  height: 795px;
  transform-origin: 0 50%;
  transform: translateY(-50%) scale(var(--k));
}
.services__track {
  position: relative;
  left: var(--center);
  height: 100%;
  width: 4620px;
  will-change: transform;
}

/* Lettres découpées par le JS pour les entrées lettre à lettre. */
.ch { display: inline-block; white-space: pre; }

.services__title {
  position: absolute;
  left: 48px;
  top: 358px;
  margin: 0;
  color: var(--beige);
  font-size: 40px;
  line-height: 45px;
  font-weight: 600;
  white-space: nowrap;
}
.services__cta {
  position: absolute;
  left: calc(48px + var(--center));
  top: 521px;
  /* Sur petit écran le frame est très réduit : le bouton garde une taille lisible. */
  transform-origin: 0 0;
  transform: scale(max(1, calc(.75 / var(--k))));
}
/* Bouton : un clic emmène à la fin de la bande services (initServicesChevron dans main.js). */
.services__chevron {
  position: absolute;
  left: 466px;
  top: 349px;
  width: 124px;
  height: 96.5px;
  overflow: visible;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  transition: scale .25s ease;
}
.services__chevron-art { display: block; width: 100%; height: 100%; overflow: visible; }
@media (hover: hover) {
  .services__chevron:hover { scale: 1.06; }
}
.services__chevron:focus-visible { outline: 2px solid var(--beige); outline-offset: 6px; }

.services__rows {
  /* Écart unique entre tous les mots et stickers, rangées comprises. */
  --services-gap: 72px;
  /* Ligne commune de tous les mots (celle de Branding dans le Figma). */
  --word-top: 65.29px;
  position: absolute;
  left: 657px;
  top: 50%;
  transform: translateY(-50%);
  display: flex;
  align-items: center;
  gap: var(--services-gap);
}

/* Rangées en flux : l'écart suit la largeur réelle des mots. Toutes les
   rangées ont la même hauteur, donc le même haut : les mots partagent une
   seule ligne (--word-top) et chaque sticker garde sa hauteur Figma. */
.srow {
  position: relative;
  flex: none;
  display: flex;
  align-items: flex-start;
  gap: var(--services-gap);
  height: 207.55px;
}
.srow > * { position: relative; flex: none; }
.srow__word { color: var(--beige); white-space: nowrap; margin-top: var(--word-top); }
.srow .h1 { font-size: 96px; line-height: 100px; }

/* Mots dont les lettres arrivent masquées : le padding laisse passer
   ascendantes et descendantes, compensé par les marges pour rester sur la ligne. */
.srow__word--motion,
.srow__word--illu {
  overflow: hidden;
  padding-block: .14em;
  margin-top: calc(var(--word-top) - .14em);
  margin-bottom: -.14em;
}

/* --- rangée haut --- */
/* Marges négatives = zones transparentes des images, mesurées au pixel : l'écart
   se compte depuis le bord réellement dessiné, pas depuis le cadre de l'image. */
.sticker--tiger { width: 211.98px; height: 188.346px; object-fit: contain; margin: 9.6px -13px 0 -11.5px; }

/* --- rangée milieu --- */
/* Bloc sticker rose → ligne → losange → flèche rouge, cotes Figma relatives au sticker rose. */
.srow__chain { width: 539.45px; height: 157.039px; margin: 25.26px 0 0 -16px; /* -16 : bord transparent du sticker rose */ }
.srow__chain > * { position: absolute; }
.sticker--curve    { left: 79.26px;  top: 55.72px; width: 412.296px; height: 52.178px; }
.sticker--pink     { left: 0;        top: 0;       width: 118.157px; height: 157.039px; }
.sticker--redarrow { left: 448.48px; top: 26.75px; width: 90.971px;  height: 106.237px; }
.sticker--square {
  left: 208.72px;
  top: 21.43px;
  width: 116.883px;
  height: 116.883px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.sticker--square span {
  width: 82.649px;
  height: 82.649px;
  background: var(--marron);
  border-radius: 11.502px;
  transform: rotate(45deg);
}

/* --- rangée bas --- */
/* Le bonhomme est pivoté : son encombrement visuel déborde de 12px sur la droite. */
.sticker--runner { margin-top: 50.6px; margin-right: 12px; width: 154.128px; height: 144.089px; transform: rotate(-10.47deg); }
/* Bouteille (nouveau sticker du 2026-10-05, export ×2 de 571 × 429) : dessin de 213,5 × 197 dans
   une image de 285,5 × 214,5, avec 65,5 px transparents à droite et 17,5 en haut. Le bas du
   dessin reste sur celui de l'ancien sticker (199 px sous le haut de la rangée). */
.sticker--bottle { width: 285.5px; height: 214.5px; object-fit: contain; margin: -15.5px -65.5px 0 -6.5px; }

/* ============================================================
   À PROPOS
   ============================================================ */
/* Comme la section projets : le frame Figma "section à propos" (1098:2350, 1440 × 757)
   est rendu à l'échelle --s et centré. Toutes les cotes = maquette × --s,
   typographie comprise, pour suivre les grands écrans (21:9 compris).
   Cotes relevées sur le rendu Figma : portraits 344 × 427, arrondi 8, centrés à
   y = 384.8 et x = 353.3 / 718 / 1082.5, inclinés de +1.1° / -0.62° / -2.03° ;
   texte (780 de large) et bouton alignés en haut à y = 629, de x = 178 à 1262.
   Les images sources (4096 × 2275, trame déjà appliquée) sont recadrées comme le
   remplissage Figma : cover centré, exportées à ×3.
   Contrairement à la maquette (165 au-dessus, 50 en dessous), le bloc portraits + texte
   est centré verticalement dans l'écran : seule la marge due à l'inclinaison des
   portraits (6.35, débord du 3e au-dessus de sa boîte) est gardée en haut. */
.about {
  background: var(--dark);
  min-height: 100svh;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
.about__inner {
  width: calc(1440 * var(--s));
  padding: calc(6.35 * var(--s)) calc(178 * var(--s)) 0;
  display: flex;
  flex-direction: column;
  gap: calc(30.7 * var(--s));
}
.about__portraits {
  display: flex;
  gap: calc(20.6 * var(--s));
  padding-left: calc(3.3 * var(--s));
}
/* Cartes (initAboutCards dans main.js) : recto = portrait (<picture> : portrait sur desktop,
   bandeau recadré sur mobile, voir plus bas), verso = présentation. Le retournement se fait
   autour de l'axe vertical, le bord droit venant vers soi, en perspective (≈ 3 largeurs de
   carte, relevé sur la vidéo de réf. « carte flip ») : bascule rapide, longue pose, sans
   rebond. */
.about__card {
  width: calc(344 * var(--s));
  height: calc(427 * var(--s));
  flex: none;
  perspective: calc(1100 * var(--s));
}
/* Inclinaison au survol (initAboutCards) : calque à part, pour se combiner au retournement. */
.about__card-tilt {
  width: 100%;
  height: 100%;
  transform-style: preserve-3d;
}
.about__card-inner {
  position: relative;
  width: 100%;
  height: 100%;
  transform-style: preserve-3d;
  /* Courbe calée sur la vidéo : bord à bord (90°) à 0.2 s, 3/4 du chemin à 0.33 s, puis
     une longue pose jusqu'à 1 s. */
  transition: transform 1s cubic-bezier(.2, 0, 0, 1);
}
.about__card.is-flipped .about__card-inner { transform: rotateY(-180deg); }
.about__face {
  position: absolute;
  inset: 0;
  display: block;
  overflow: hidden;
  border-radius: calc(8 * var(--s));
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
}
.about__face img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.about__face--back { transform: rotateY(180deg); }
/* Reflet holographique du verso, seulement sur les dessins (masques carte-<associé>-holo.png :
   le personnage et son ombre ; ni le texte ni le fond beige). Bandes arc-en-ciel qui glissent
   avec la souris (--holo-x / --holo-y, 0 à 100, posés par initAboutCards), posées en « lumière
   douce » renforcée : irisé, couleurs d'origine préservées. (Essayé en « éclaircir » avec un
   halo blanc : tout blanchissait. Essayé aussi l'effet « Holographic Name Card » de simeydotme
   sur une carte : écarté.) Discret au repos, plus marqué quand la souris est sur la carte. */
.about__holo {
  position: absolute;
  inset: 0;
  pointer-events: none;
  /* L'image du masque est posée dans le HTML (style en ligne) : une url() passée par une
     variable CSS se résoudrait depuis css/ et ne serait pas trouvée. */
  -webkit-mask-size: 100% 100%;
          mask-size: 100% 100%;
  -webkit-mask-repeat: no-repeat;
          mask-repeat: no-repeat;
  background-image: repeating-linear-gradient(115deg,
    #ff6fb5 0%, #ffcf6b 6%, #8dff9d 12%, #6fe4ff 18%, #9a86ff 24%, #ff6fb5 30%);
  background-size: 300% 300%;
  background-position: calc(var(--holo-x, 50) * 1%) calc(var(--holo-y, 50) * 1%);
  filter: contrast(1.7) saturate(1.3);
  mix-blend-mode: soft-light;
  opacity: .15;
  transition: opacity .4s ease;
}
.about__card.is-hover .about__holo { opacity: .35; }
.about__card[role="button"] { cursor: pointer; }
.about__card:focus-visible { outline: 2px solid var(--rose); outline-offset: 6px; border-radius: calc(8 * var(--s)); }
.about__card:nth-child(1) { rotate: 1.1deg; }
.about__card:nth-child(2) { rotate: -0.62deg; }
.about__card:nth-child(3) { rotate: -2.03deg; }
.about__bottom {
  /* Au-dessus des cartes : elles montent de plus bas à leur entrée (initAboutCards). */
  position: relative;
  z-index: 1;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: calc(40 * var(--s));
}
.about__text {
  color: #fff;
  width: calc(780 * var(--s));
  font-weight: 400; /* largeurs des lignes Figma : Regular, pas Medium */
  letter-spacing: -0.024em; /* -0.48px à 20 px, à l'échelle pour garder les coupures Figma */
  font-size: calc(20 * var(--s));
  line-height: calc(26 * var(--s));
}
.about .btn {
  font-size: calc(20 * var(--s));
  line-height: calc(26 * var(--s));
  padding: calc(16 * var(--s)) calc(25 * var(--s)) calc(15 * var(--s));
  border-radius: calc(6 * var(--s));
}

/* ============================================================
   FOOTER
   Au-dessus de 1100px, toutes les cotes Figma sont multipliées par --f
   (= --s, comme les autres sections) : le footer grandit avec l'écran au lieu
   de rester plafonné à 1440px. Entre 761 et 1100px --f vaut 1px (cotes
   Figma telles quelles, largeur fluide) ; sous 760px, empilement.
   ============================================================ */
.footer {
  --f: var(--s);
  /* Couleurs (maquette « Footer » 1662:1441) : seul l'accord change d'une variante à l'autre.
     Fond, encre (textes, logo, bouton), lueur du dégradé du bas ; le texte atténué et le
     milieu du dégradé en découlent. Par défaut : Footer Beige (accueil). */
  --footer-bg: var(--beige);
  --footer-ink: var(--marron);
  --footer-glow: var(--bleu);
  --footer-glow-mid: color-mix(in srgb, var(--footer-glow), var(--footer-bg));
  --footer-muted: color-mix(in srgb, var(--footer-ink) 67%, var(--footer-bg)); /* #866c5e en beige */
  position: relative;
  overflow: hidden;
  background: var(--footer-bg);
  color: var(--footer-ink);
}
/* Variantes, relevées sur la maquette. Le logo « currymango » est une image : chaque page
   prend le fichier de sa couleur (wordmark-footer[-beige|-rose|-dark].svg). */
.footer--marron { --footer-bg: var(--marron); --footer-ink: var(--beige); --footer-glow: var(--rose); }
.footer--black  { --footer-bg: var(--dark);   --footer-ink: var(--rose);  --footer-glow: var(--marron); }
.footer--bleu   { --footer-bg: var(--bleu);   --footer-ink: var(--beige); --footer-glow: var(--rose); }
/* Rose : lueur beige plus marquée (milieu du dégradé à 70 % de beige au lieu de 50). */
.footer--rose {
  --footer-bg: var(--rose);
  --footer-ink: var(--dark);
  --footer-glow: var(--beige);
  --footer-glow-mid: color-mix(in srgb, var(--beige) 70%, var(--rose));
}
.footer .btn--brown { background: var(--footer-ink); color: var(--footer-bg); }
/* Dégradé bleu du bas, sur son propre calque qui couvre tout le footer (aucun bord visible) :
   - à l'arrivée (initFooterInk), --glow va de 0 à 1 : l'ellipse grandit depuis le bas
     (--glow-size) pendant que le calque apparaît ;
   - à la souris (initFooterGlow), son centre glisse très légèrement vers le pointeur
     (--gx, --gy, en % du footer).
   Sans JS, --glow reste à 1 et le dégradé est immobile. */
.footer::before {
  --glow-size: calc(.35 + .65 * var(--glow, 1));
  --glow-at: calc(50% + var(--gx, 0%)) calc(100% + var(--gy, 0%));
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(ellipse calc(72.56% * var(--glow-size)) calc(46.35% * var(--glow-size)) at var(--glow-at),
              var(--footer-glow) 0%, var(--footer-glow-mid) 50%, var(--footer-bg) 100%);
  opacity: var(--glow, 1);
}
.footer__inner {
  position: relative; /* au-dessus du calque du dégradé */
  padding: calc(60 * var(--f)) calc(50 * var(--f)) 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(100 * var(--f));
}
.footer__grid {
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: calc(60 * var(--f));
}
.footer__top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: calc(40 * var(--f));
}
.footer__cta { display: flex; flex-direction: column; gap: calc(24 * var(--f)); align-items: flex-start; }
.footer__cta-text { display: flex; flex-direction: column; gap: calc(16 * var(--f)); }
.footer__cta-text p { max-width: calc(404 * var(--f)); }
.footer__muted { color: var(--footer-muted); }
.footer .h2 { font-size: calc(40 * var(--f)); }
/* Petits textes : planchers de lisibilité quand l'écran est bas (--s < 1). */
.footer .body-sm { font-size: max(13px, calc(14 * var(--f))); line-height: 1.43; }
.footer .body-lead { font-size: calc(20 * var(--f)); line-height: calc(26 * var(--f)); }
.footer .legal { font-size: max(11px, calc(12 * var(--f))); }
.footer .btn {
  gap: calc(8 * var(--f));
  padding: calc(15 * var(--f)) calc(20 * var(--f)) calc(14 * var(--f));
  border-radius: calc(6 * var(--f));
  font-size: calc(20 * var(--f));
  line-height: calc(26 * var(--f));
}

.footer__nav { display: flex; justify-content: space-between; gap: calc(50 * var(--f)); width: calc(454 * var(--f)); }
.footer__col { width: calc(202 * var(--f)); display: flex; flex-direction: column; gap: calc(24 * var(--f)); }
.footer__col ul {
  display: flex;
  flex-direction: column;
  gap: calc(16 * var(--f));
  font-size: max(14px, calc(16 * var(--f)));
  line-height: 1.375;
}
/* Survol d'un lien : ce sont tous les autres (des deux colonnes) qui s'estompent, lui reste
   plein. Souris seulement (au doigt, le survol resterait collé après un toucher). Behance,
   sans lien pour l'instant, ne déclenche rien mais s'estompe avec les autres. */
.footer__col a { transition: opacity .2s ease; }
@media (hover: hover) {
  .footer__nav:has(a[href]:hover) .footer__col a:not(:hover) { opacity: .6; }
}

.footer__legal {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: calc(40 * var(--f));
  color: var(--footer-muted);
}
.footer__legal p { margin: 0; }
.footer__rights { display: none; } /* « Tous droits réservés » : mobile seulement */
.footer__legal-links { display: flex; gap: calc(50 * var(--f)); width: calc(454 * var(--f)); }
.footer__legal-links a { width: calc(202 * var(--f)); }

/* Le logo occupe toute la largeur utile (1339 sur 1340 dans le Figma). */
.footer__wordmark { position: relative; width: 100%; }
.footer__wordmark img { width: 100%; height: auto; }
.footer__wordmark-sub {
  position: absolute;
  left: 42.7%;
  top: 83.2%;
  color: var(--footer-ink);
  font-weight: 500;
  font-size: 5.26cqw;
  line-height: .83;
  letter-spacing: -0.09em;
  white-space: nowrap;
}
.footer__wordmark { container-type: inline-size; }

/* Définitions SVG (filtres) : présentes dans le document, jamais affichées. */
.sr-defs { position: absolute; width: 0; height: 0; overflow: hidden; }

/* Bande des stickers : 320px de haut à 1440 de large, proportionnelle ensuite (le motif
   couvre toute la largeur, comme le logo). Le motif (1530.86 × 408.96) déborde en bas et
   sur les côtés comme dans le Figma ; c'est le footer (overflow: hidden) qui le rogne,
   pas la bande : un sticker attrapé peut ainsi être déplacé partout dans le footer. */
.footer__pattern {
  position: relative;
  aspect-ratio: 1440 / 320;
}
.footer__stickers {
  position: absolute;
  top: 0;
  left: -3.79%;
  width: 106.31%;
  aspect-ratio: 1530.86 / 408.963;
}
/* Motifs mobile et tablette (index.html) : affichés seulement dans leur format. */
.footer__band,
.footer__band-tablet {
  display: none;
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  aspect-ratio: 375 / 81.9;
}
.footer__band-tablet { aspect-ratio: 1024 / 139.3; }
.footer__sticker {
  position: absolute;
  height: auto;
  overflow: visible;
  /* Seule la forme est attrapable, pas le rectangle autour. */
  pointer-events: none;
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
  transition: filter .25s ease;
}
.footer__sticker use { pointer-events: visiblePainted; cursor: grab; }
.footer__sticker.is-dragging { filter: drop-shadow(0 18px 22px rgba(27, 21, 21, .28)); cursor: grabbing; }
.footer__sticker.is-dragging use { cursor: grabbing; }

/* ============================================================
   PAGE SERVICES (services.html) — maquette « Services - Desktop » (1015:314)
   Hero puis trois sections plein écran (design, digital, audit et conseil), chacune avec
   ses pilules de prestations soumises à un moteur physique (services.js). Cotes = maquette
   (sections de 1440 × 795) × --s, le cadre de 795 étant centré verticalement dans l'écran.
   Relevés sur le rendu Figma : titres 96 px semi-gras (style .h1), ligne de base à 435
   dans la section (hero : 390 et 491) ; pilules de 56 px de haut, texte 32 px à 18 de marge.
   ============================================================ */
.svc-hero,
.svc {
  position: relative;
  height: 100svh;
  overflow: hidden;
}
.svc-hero { background: var(--beige); color: var(--marron); }
.svc--design { background: var(--rose); --pill-ink: var(--rose); }
.svc--digital { background: var(--bleu); --pill-ink: var(--bleu); }
.svc--audit { background: var(--marron); --pill-ink: var(--marron); }

.svc-hero__title,
.svc__title {
  position: absolute;
  left: 0;
  right: 0;
  margin: 0;
  text-align: center;
  font-size: calc(96 * var(--s));
  line-height: calc(100 * var(--s));
  letter-spacing: -0.03em;
}
/* Haut de la première ligne : 313.6 dans le cadre de 795 (centre à 397.5). */
.svc-hero__title { top: calc(50% - 83.9 * var(--s)); }
.svc-hero__scroll {
  position: absolute;
  left: 50%;
  bottom: 14px;
  translate: -50% 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  font-size: 16px;
  line-height: 22px;
  white-space: nowrap;
}
.svc-hero__scroll svg { display: block; }
.svc-hero__scroll:hover svg { animation: bob .8s ease-in-out infinite; }

/* Haut du titre : 358.6 dans le cadre. Boîte limitée au mot (centrée) : le survol ne se
   déclenche que sur le mot, pas sur toute la largeur de la section. */
.svc__title {
  top: calc(50% - 38.9 * var(--s));
  width: fit-content;
  margin-inline: auto;
  color: var(--beige);
}
/* Lettres du titre (survol en symboles, services.js) : largeur figée, symbole centré. */
.svc__ch { display: inline-block; white-space: pre; text-align: center; }

/* Sans le moteur physique (pas de JS, animations réduites) : pilules rangées en bas. */
.svc__pills {
  position: absolute;
  inset: 0;
  margin: 0;
  padding: 0 calc(120 * var(--s)) calc(24 * var(--s));
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-content: flex-end;
  gap: calc(8 * var(--s));
}
/* Pilule : 51.4 de haut (maquette « Hover pillule », 1295:1865), ligne de base du texte à 37
   du haut (d'où le rembourrage haut de 5 et la hauteur de ligne de 46.4). */
.svc__pill {
  height: calc(51.4 * var(--s));
  padding: calc(5 * var(--s)) calc(18 * var(--s)) 0;
  border-radius: calc(25.7 * var(--s));
  background: var(--beige);
  color: var(--pill-ink);
  font-size: calc(32 * var(--s));
  line-height: calc(46.4 * var(--s));
  letter-spacing: -0.04em;
  white-space: nowrap;
  user-select: none;
  -webkit-user-select: none;
  transition: background-color .2s ease, color .2s ease, box-shadow .2s ease;
}
/* Survol (et pilule tenue) : couleurs inversées — fond de la couleur de la section, texte et
   contour de 2 px en beige (contour intérieur : la taille ne change pas). Souris seulement. */
@media (hover: hover) {
  .svc__pill:hover,
  .svc__pill.is-dragging {
    background: var(--pill-ink);
    color: var(--beige);
    box-shadow: inset 0 0 0 calc(2 * var(--s)) var(--beige);
  }
}
/* Avec le moteur (classe posée par services.js) : calque sur toute la section, chaque pilule
   placée par sa transformation, cachée tant qu'elle n'est pas tombée. */
.svc__pills.has-physics { display: block; padding: 0; pointer-events: none; }
.has-physics .svc__pill {
  position: absolute;
  left: 0;
  top: 0;
  visibility: hidden;
  pointer-events: auto;
  cursor: grab;
  touch-action: none;
  will-change: transform;
}
.has-physics .svc__pill.is-dropped { visibility: visible; }
.has-physics .svc__pill.is-dragging { cursor: grabbing; }

/* ============================================================
   PAGE CONTACT (contact.html, maquette 933:85)
   Un seul écran : le cadre de 1440 × 795 à l'échelle --s, centré verticalement. Texte centré,
   haut du titre à 217.7 dans le cadre. Relevés sur le rendu Figma : titre 40 px sur 45 (lignes
   de base à 251.4 et 296.4), intitulés 20 px medium, coordonnées 16 px ; réseaux soulignés.
   ============================================================ */
.contact {
  position: relative;
  height: 100svh;
  overflow: hidden;
  background: var(--beige);
}
.contact__inner {
  position: absolute;
  left: 0;
  right: 0;
  top: calc(50% - 179.8 * var(--s));
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}
.contact__title {
  margin: 0 0 calc(80 * var(--s));
  font-size: calc(40 * var(--s));
  line-height: calc(45 * var(--s));
}
.contact__label { font-size: calc(20 * var(--s)); line-height: calc(26 * var(--s)); }
.contact__block + .contact__block { margin-top: calc(24 * var(--s)); }
.contact__list {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(16 * var(--s));
  margin-top: calc(16 * var(--s));
  font-size: calc(16 * var(--s));
  line-height: calc(22 * var(--s));
}
.contact__list--social { gap: calc(5 * var(--s)); margin-top: calc(13 * var(--s)); }
.contact__list--social a {
  text-decoration: underline;
  text-decoration-thickness: max(1px, calc(1 * var(--s)));
  text-underline-offset: calc(2 * var(--s));
}

/* Traînée de stickers (contact.js) : sous le texte, sans capter la souris. Un sticker fait
   400 unités du tracé (centrées sur son centre de gravité) × 0.587, sa taille pleine sur la
   maquette (≈ 146 px de haut pour le bleu) ; contour beige de 5 unités comme au footer. */
.contact__trail {
  position: absolute;
  inset: 0;
  pointer-events: none;
}
.contact__sticker {
  position: absolute;
  left: 0;
  top: 0;
  width: calc(234.8 * var(--s));
  height: calc(234.8 * var(--s));
  overflow: visible;
  stroke-width: 5;
  will-change: transform, opacity;
}
.contact__sticker--bleu   { fill: var(--bleu); }
.contact__sticker--marron { fill: var(--marron); }
.contact__sticker--rose   { fill: var(--rose); }

/* ============================================================
   PAGE 404 (404.html, maquette 1702:520) : un écran rose de 1440 × 795 à l'échelle --s.
   Bloc centré dans l'écran (son haut à 207 sur la maquette, soit pile au milieu) : titre 96 sur
   100, phrase 40 sur 45, puis deux boutons, écarts de 20 et 16. Boutons : ceux de l'accueil
   (marron, texte beige, flèche — demande de l'utilisateur), à la taille du « Voir tous nos
   projets » (.projects__cta), au lieu des pilules roses de la maquette.
   ============================================================ */
.e404 {
  position: relative;
  height: 100svh;
  overflow: hidden;
  background: var(--rose);
}
.e404__inner {
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  translate: 0 -50%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(20 * var(--s));
  padding: 0 var(--gutter);
  text-align: center;
}
.e404__title,
.e404__text {
  margin: 0;
  font-weight: 600;
  letter-spacing: -0.03em;
}
.e404__title { font-size: calc(96 * var(--s)); line-height: calc(100 * var(--s)); }
.e404__text  { font-size: calc(40 * var(--s)); line-height: calc(45 * var(--s)); }
.e404__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: calc(16 * var(--s));
}
.e404__btn {
  font-size: calc(20 * var(--s));
  line-height: calc(26 * var(--s));
  padding: calc(15 * var(--s)) calc(20 * var(--s)) calc(14 * var(--s));
  border-radius: calc(6 * var(--s));
}

/* ============================================================
   PAGES LÉGALES (mentions-legales.html, confidentialite.html), sans maquette : une colonne
   de lecture centrée sur fond beige (≈ 75 signes par ligne), titres semi-gras du site, liens
   soulignés, puis le footer. Le tableau des finalités s'empile en fiches sur mobile.
   ============================================================ */
.legal-page {
  width: min(780px, calc(100% - 2 * var(--gutter)));
  margin: 0 auto;
  padding: calc(var(--header-h) + 96px) 0 140px;
  font-size: 17px;
  line-height: 1.6;
}
.legal-page__title {
  margin: 0 0 40px;
  font-size: clamp(40px, 5vw, 72px);
  line-height: 1.05;
  font-weight: 600;
  letter-spacing: -0.03em;
}
.legal-page h2 {
  margin: 48px 0 12px;
  font-size: 24px;
  line-height: 1.25;
  font-weight: 600;
  letter-spacing: -0.03em;
}
.legal-page p,
.legal-page ul { margin: 0 0 14px; }
.legal-page ul { padding-left: 1.2em; list-style: disc; }
.legal-page li + li { margin-top: 6px; }
.legal-page a {
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
}
.legal-page h2[id] { scroll-margin-top: calc(var(--header-h) + 24px); } /* ancre #cookies */
.legal-page__update { margin-top: 56px; color: var(--muted); font-size: 15px; }
.legal-page__table { margin: 8px 0 14px; }
.legal-page table {
  width: 100%;
  border-collapse: collapse;
  font-size: 15px;
  line-height: 1.45;
}
.legal-page th,
.legal-page td {
  padding: 12px 16px 12px 0;
  text-align: left;
  vertical-align: top;
  border-bottom: 1px solid color-mix(in srgb, var(--marron) 20%, transparent);
}
.legal-page th { font-weight: 600; border-bottom-color: var(--marron); }
@media (max-width: 760px) {
  .legal-page { padding: calc(var(--header-h) + 48px) 0 80px; font-size: 16px; }
  .legal-page__title { margin-bottom: 28px; }
  .legal-page h2 { margin-top: 40px; font-size: 21px; }
  /* Tableau en fiches : une par finalité, chaque valeur précédée de son intitulé. */
  .legal-page thead { display: none; }
  .legal-page table,
  .legal-page tbody,
  .legal-page tr,
  .legal-page td { display: block; }
  .legal-page tr { padding: 14px 0; border-bottom: 1px solid color-mix(in srgb, var(--marron) 20%, transparent); }
  .legal-page td { padding: 2px 0; border: 0; }
  .legal-page td::before { content: attr(data-label) "\00a0: "; font-weight: 600; }
}

/* ============================================================
   PAGE PROJETS (projets.html, maquette 1672:2081)
   Grille à l'échelle --s. Cotes Figma : première rangée à 114 du haut (40 sous le header),
   56 sous la dernière ; vignettes de 512 de haut, 38 entre elles ; « type 1 » = vignette de
   910 puis de 443, « type 2 » = l'inverse ; arrondi de 6. Rangées centrées (la maquette les
   pose 1,5 px à droite du centre). Vignette grise tant que son image n'est pas chargée.
   La liste est ouverte : chaque projet ajouté (CMS) prend la largeur suivante de l'alternance
   et les rangées se reforment toutes seules. Vidéo au survol : initVideos (main.js).
   ============================================================ */
.pgrid {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: calc(114 * var(--s)) 0 calc(56 * var(--s));
}
/* Titre pour les lecteurs d'écran seulement (pas de titre visible sur la maquette). */
.pgrid__title {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
/* Largeur de la rangée : deux vignettes et leur écart tiennent tout juste, la troisième passe
   à la ligne (910 + 38 + 443 = 1391). */
.pgrid__list {
  display: flex;
  flex-wrap: wrap;
  width: calc(1391 * var(--s));
  gap: calc(38 * var(--s));
}
/* Alternance des largeurs : grande, petite / petite, grande, et ainsi de suite. */
.pgrid__item {
  position: relative; /* support de la vidéo au survol (data-video) */
  width: calc(443 * var(--s));
  height: calc(512 * var(--s));
  overflow: hidden;
  border-radius: calc(6 * var(--s));
  background: #626262; /* gris tant que l'image n'est pas chargée */
}
.pgrid__item:nth-child(4n + 1),
.pgrid__item:nth-child(4n) { width: calc(910 * var(--s)); }

/* ============================================================
   PAGE PROJET GRIPH (griph.html, maquette « projet_griph_test » 1448:115)
   Blocs empilés à l'échelle --s (cotes de la maquette, 1440 de large) : marges de 40,
   contenu de 1360, 50 entre deux blocs et 60 autour des textes seuls (leur cadre Figma a
   10 de marge). Titre à 240 du haut de page (header 74 + 156 + 10), 150 sous le dernier
   bloc. Textes relevés sur le rendu Figma à 200 % : titre 96 sur 100 semi-gras ; accroche
   et titres 40 sur 45 semi-gras ; paragraphes 24 sur 30 medium (-2,4 %) ; étiquettes 24
   regular (-4 %), 51.4 de haut, marges de 18, écart de 9.
   ============================================================ */
.pj {
  /* Haut de la première image (400 dans la maquette), bas du header (logo et bouton : 20 + 44)
     et écart entre blocs : le titre se centre entre les deux premiers (voir .pj__title). */
  --pj-media-top: calc(400 * var(--s));
  --pj-head: calc(64 * var(--hs));
  --pj-gap: calc(50 * var(--s));
  display: flex;
  flex-direction: column;
  gap: var(--pj-gap);
  width: calc(1440 * var(--s));
  margin: 0 auto;
  padding: var(--pj-head) calc(40 * var(--s)) calc(150 * var(--s));
}
.pj figure { margin: 0; }
.pj__media {
  position: relative; /* support d'une vidéo éventuelle (data-video) */
  overflow: hidden;
  border-radius: calc(6 * var(--s));
}
.pj__media img {
  display: block;
  width: 100%;
  height: auto;
}
.pj__title,
.pj__lead {
  margin: calc(10 * var(--s)) 0;
  text-align: center;
}
/* Titre centré entre le header et la première image, même distance au-dessus et au-dessous
   des capitales. Il occupe l'espace du header à l'image (moins l'écart qui le suit, reporté
   en retrait haut pour que son centre tombe au milieu). Capitales d'Epilogue 600 : 0,75 em de haut,
   leur milieu 0,1 em au-dessus de celui de la ligne (ascendante 0,79, descendante 0,235,
   et le G qui déborde un peu sous la ligne), d'où le décalage de .1em vers le bas. */
.pj__title {
  height: calc(var(--pj-media-top) - var(--pj-head) - var(--pj-gap));
  margin: 0;
  padding-top: var(--pj-gap);
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
  top: .1em;
  font-size: calc(96 * var(--s));
  line-height: calc(100 * var(--s));
  font-weight: 600;
}
.pj__lead,
.pj__heading {
  font-size: calc(40 * var(--s));
  line-height: calc(45 * var(--s));
  font-weight: 600;
}
.pj__heading { margin: 0; }
.pj__text {
  margin: 0;
  font-size: calc(24 * var(--s));
  line-height: calc(30 * var(--s));
  font-weight: 500;
  letter-spacing: -0.024em;
}
/* Colonne de droite (de 733 à 1397) ou large à gauche (899, la largeur de l'image au-dessus). */
.pj__text--right {
  width: calc(663.8 * var(--s));
  margin-left: calc(693.1 * var(--s));
}
.pj__text--wide { width: calc(898.9 * var(--s)); }
/* Mot à trait d'union gardé entier, comme dans la maquette (« e-commerce »). */
.pj .nowrap { white-space: nowrap; }

/* Étiquettes en haut et paragraphe en bas à gauche, image à droite. */
.pj__intro {
  display: grid;
  grid-template-columns: 1fr 1fr;
  column-gap: calc(30 * var(--s));
}
.pj__intro-text {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}
/* Deux rangées de trois comme la maquette (641 puis 609 de large) : la 4e passe à la ligne. */
.pj__tags {
  display: flex;
  flex-wrap: wrap;
  gap: calc(9 * var(--s));
  max-width: calc(660 * var(--s));
  margin: 0;
  padding: 0;
  list-style: none;
}
.pj__tags li {
  padding: calc(16.7 * var(--s)) calc(18 * var(--s));
  border-radius: calc(6 * var(--s));
  background: var(--marron);
  color: var(--beige);
  font-size: calc(24 * var(--s));
  line-height: calc(18 * var(--s));
  letter-spacing: -0.04em;
  white-space: nowrap;
}

/* Grande image (899) à gauche, titre en haut à droite. */
.pj__wide {
  display: grid;
  grid-template-columns: calc(898.9 * var(--s)) 1fr;
  column-gap: calc(32.9 * var(--s));
  align-items: start;
}
/* Petite image (434) calée en bas à gauche, image (664) à droite. */
.pj__list {
  display: grid;
  grid-template-columns: calc(434 * var(--s)) 1fr calc(663.9 * var(--s));
  align-items: end;
}
.pj__list > :last-child { grid-column: 3; }
/* Deux images empilées à gauche et une haute à droite ; deux images côte à côte. */
.pj__cards,
.pj__duo {
  display: grid;
  grid-template-columns: 1fr 1fr;
  column-gap: calc(32.2 * var(--s));
}
.pj__cards-stack {
  display: flex;
  flex-direction: column;
  gap: calc(40 * var(--s));
}

/* Deux rangées d'affiches (273 × 387, écart de 20) sur fond sombre, coupées aux bords du
   bloc : la 1re part de -189, la 2de de -42, à 21 et 428 du haut. En unités du bloc (cqw)
   pour garder la composition à toutes les largeurs. */
.pj__marquee {
  position: relative;
  container-type: inline-size;
  aspect-ratio: 1360 / 835.3;
  overflow: hidden;
  border-radius: calc(6 * var(--s));
  background: #332927;
}
.pj__marquee-row {
  position: absolute;
  top: calc(21 / 1360 * 100cqw);
  left: calc(-189 / 1360 * 100cqw);
  display: flex;
  gap: calc(20 / 1360 * 100cqw);
  margin: 0;
  padding: 0;
  list-style: none;
}
.pj__marquee-row + .pj__marquee-row {
  top: calc(428 / 1360 * 100cqw);
  left: calc(-42 / 1360 * 100cqw);
}
.pj__marquee-row li {
  flex: none;
  width: calc(273 / 1360 * 100cqw);
}
.pj__marquee-row img {
  display: block;
  width: 100%;
  height: auto;
}

/* Variantes de la page Mojo (maquette « projet_mojo » 1448:287), mêmes cotes et même rythme
   que GRIPH (50 entre blocs, 60 autour de l'accroche) :
   · première image à 245 du haut de page (400 pour GRIPH), le titre centré au-dessus ;
   · paragraphe décalé : 640 de large, à 272 du bord de la maquette ;
   · image de 897 à gauche, étiquettes ou paragraphe calés en bas dans la colonne de droite
     (à 967, comme le 2e cadre de pj__intro) ;
   · titre seul sur une demi-largeur (665), pour sa coupure en deux lignes. */
.pj--mojo { --pj-media-top: calc(245 * var(--s)); }
.pj__text--indent {
  width: calc(640 * var(--s));
  margin-left: calc(232 * var(--s));
}
.pj__aside {
  display: grid;
  grid-template-columns: calc(897 * var(--s)) 1fr;
  column-gap: calc(30 * var(--s));
  align-items: end;
}
/* Cadre de texte un peu plus étroit que la colonne (433) : 431, d'où ses coupures de ligne
   (« …gravé pour » / « la prise en main… »). */
.pj__aside > .pj__text { width: calc(431.4 * var(--s)); }
.pj__heading--half { width: calc(665 * var(--s)); }

/* Page Meraki (maquette « projet_meraki » 1561:1359) : rythme plus serré, 30 entre deux blocs
   (40 autour de l'accroche avec sa marge de 10), première image à 274 du haut. Blocs propres :
   paragraphe sur une demi-largeur (665) à gauche, paragraphe large (895) calé à droite,
   étiquettes en haut à droite de l'image (au lieu d'en bas), deux et trois images côte à
   côte (écarts de 30 et 29). */
.pj--meraki {
  --pj-media-top: calc(274 * var(--s));
  --pj-gap: calc(30 * var(--s));
}
.pj__text--half { width: calc(665 * var(--s)); }
.pj__text--wide-right {
  width: calc(895 * var(--s));
  margin-left: auto;
}
.pj__aside--top { align-items: start; }
.pj__pair,
.pj__trio {
  display: grid;
  grid-template-columns: 1fr 1fr;
  column-gap: calc(30 * var(--s));
}
.pj__trio {
  grid-template-columns: repeat(3, 1fr);
  column-gap: calc(29 * var(--s));
}

/* Page Ahno111 (maquette « projet_Ahno » 1645:218) : blocs et rythme de GRIPH, première image à
   245 du haut comme Mojo. pj__intro y a l'image à gauche (ordre du HTML) ; pj__wide passe dans
   l'autre sens : titre à gauche (428), image de 899 à droite. */
.pj--ahno { --pj-media-top: calc(245 * var(--s)); }
.pj__wide--reverse { grid-template-columns: 1fr calc(898.9 * var(--s)); }

/* ============================================================
   PAGE À PROPOS (apropos.html, maquette « à propos » 1582:373)
   Cotes de la maquette (1440 de large) à l'échelle --s. Animations au défilement dans
   js/apropos.js : intro figée avec texte dévoilé mot à mot, bandeaux des associés au survol,
   carrousel horizontal figé à l'écran.
   ============================================================ */
.ap-intro,
.ap-team { background: var(--marron); color: var(--beige); }

/* 1. Intro : titre 96 sur 90 semi-gras (haut à 177), texte 40 sur 45 semi-gras sur 1037 de
   large (haut à 436), deux paragraphes séparés d'une ligne vide. */
.ap-intro {
  min-height: 100svh;
  display: flex;
  justify-content: center;
}
.ap-intro__inner {
  width: calc(1440 * var(--s));
  padding: calc(177 * var(--s)) 0 calc(80 * var(--s));
  text-align: center;
}
.ap-intro__title {
  margin: 0;
  font-size: calc(96 * var(--s));
  line-height: calc(90 * var(--s));
  font-weight: 600;
  letter-spacing: -0.03em; /* -3 % de sa taille (celui du body, calculé à 16 px, ne suit pas) */
}
/* Lignes du titre : fenêtre pour l'apparition (le texte monte de sous la ligne). */
.ap-line {
  display: block;
  overflow: hidden;
  padding-bottom: .12em;
  margin-bottom: -.12em;
}
.ap-line > span { display: inline-block; }
.ap-intro__text {
  width: calc(1037 * var(--s));
  margin: calc(79 * var(--s)) auto 0;
  font-size: calc(40 * var(--s));
  line-height: calc(45 * var(--s));
  font-weight: 600;
  letter-spacing: -0.03em;
}
.ap-intro__text p { margin: 0; }
.ap-intro__text p + p { margin-top: calc(45 * var(--s)); }
/* Mots à dévoiler (enveloppés par apropos.js) : en transparence, puis pleins. */
.ap-word { opacity: .5; }
/* Vignettes photo dans la ligne (100 × 40) : fermées, elles s'ouvrent quand la lecture les
   atteint (apropos.js anime --open de 0 à 1). */
.ap-chip,
.ap-mascots {
  --open: 1;
  display: inline-block;
  position: relative;
  vertical-align: top;
  height: calc(45 * var(--s));
  opacity: var(--open);
}
.ap-chip { width: calc(100 * var(--s) * var(--open)); }
/* Fin de la 2e ligne : la maquette y garde des espaces, qui décalent la ligne centrée de 41
   vers la gauche (la vidéo aussi) ; cette cale les reproduit. */
.ap-trail { display: inline-block; width: calc(82 * var(--s)); }
.ap-chip img {
  position: absolute;
  left: 50%;
  top: calc(3 * var(--s));
  width: calc(100 * var(--s));
  height: calc(40 * var(--s));
  max-width: none;
  object-fit: cover;
  border-radius: calc(6 * var(--s));
  translate: -50% 0;
  scale: calc(.4 + .6 * var(--open));
}
.ap-chip--toulouse img { border-radius: calc(5 * var(--s)); }
/* Les trois mascottes, entre « Trois associés, » et « trois expertises » (167 de large),
   placées et tournées comme dans la maquette, en débordant de la ligne. */
.ap-mascots { width: calc(167 * var(--s) * var(--open)); }
.ap-mascot {
  position: absolute;
  max-width: none;
  height: auto;
  translate: -50% -50%;
  scale: var(--open);
}
.ap-mascot--bleue   { left: calc(32.8 * var(--s));  top: calc(19.4 * var(--s)); width: calc(65.1 * var(--s)); rotate: 9.14deg; }
.ap-mascot--rose    { left: calc(85.9 * var(--s));  top: calc(20.2 * var(--s)); width: calc(71.1 * var(--s)); rotate: -54.87deg; }
.ap-mascot--contour { left: calc(135.7 * var(--s)); top: calc(19.9 * var(--s)); width: calc(70.2 * var(--s)); rotate: 2.72deg; }

/* 2. Associés : trois bandeaux de 1400 × 129 ; celui qu'on survole passe à 332, voilé de
   marron foncé (70 %), avec nom (24 sur 30) et bio (16 sur 22) à gauche. Le bloc est centré
   dans l'écran : il grandit vers le haut et vers le bas, comme sur la vidéo. */
.ap-team {
  min-height: 100svh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: calc(60 * var(--s)) 0;
}
.ap-bands {
  width: calc(1400 * var(--s));
  border-radius: calc(6 * var(--s));
  overflow: hidden;
}
.ap-band {
  position: relative;
  height: calc(129 * var(--s));
  overflow: hidden;
  outline: none;
  transition: height .6s cubic-bezier(.65, 0, .35, 1);
}
.ap-band.is-open { height: calc(332 * var(--s)); }
.ap-band__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover; /* tranche centrale du portrait, comme la maquette */
}
.ap-band::after {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(27, 21, 21, .7);
  opacity: 0;
  transition: opacity .5s ease;
}
.ap-band.is-open::after { opacity: 1; }
.ap-band__info {
  position: absolute;
  z-index: 1;
  left: calc(67 * var(--s));
  bottom: calc(44 * var(--s));
  width: calc(381 * var(--s));
  display: flex;
  flex-direction: column;
  gap: calc(16 * var(--s));
  opacity: 0;
  translate: 0 calc(12 * var(--s));
  transition: opacity .35s ease, translate .35s ease;
}
.ap-band.is-open .ap-band__info {
  opacity: 1;
  translate: 0 0;
  transition: opacity .5s ease .2s, translate .5s cubic-bezier(.22, 1, .36, 1) .2s;
}
.ap-band__name,
.ap-band__bio,
.ap-story__text { letter-spacing: -0.03em; }
.ap-band__name {
  margin: 0;
  font-size: calc(24 * var(--s));
  line-height: calc(30 * var(--s));
  font-weight: 600;
}
.ap-band__bio {
  margin: 0;
  font-size: calc(16 * var(--s));
  line-height: calc(22 * var(--s));
}
.ap-band:focus-visible { box-shadow: inset 0 0 0 2px var(--rose); }

/* 3. Virage du marron au bleu, comme les transitions de l'accueil (.transition) : une bande
   d'un écran qui vire au bleu avec l'histoire pendant que celle-ci monte (apropos.js). Sans
   animation, un dégradé fixe fait le lien. */
.ap-fade {
  height: 100svh;
  background: var(--marron);
}
@media (prefers-reduced-motion: reduce) {
  .ap-fade { background: linear-gradient(var(--marron), var(--bleu)); }
}

/* 4. Histoire : fond bleu, sept images de 451 × 520 (écart 24) qui partent du milieu de la
   largeur (700 dans le cadre de 1400) et débordent à droite ; texte 24 sur 30 à droite. */
.ap-story {
  min-height: 100svh;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden; /* les images coupées aux bords de l'écran */
  background: var(--bleu);
  color: var(--beige);
}
.ap-story__inner {
  width: calc(1400 * var(--s));
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: calc(24 * var(--s));
}
.ap-story__viewport { width: 100%; }
.ap-story__track {
  display: flex;
  gap: calc(24 * var(--s));
  margin: 0;
  padding: 0 0 0 calc(700 * var(--s));
  list-style: none;
  will-change: transform;
}
.ap-story__track li {
  flex: none;
  width: calc(451 * var(--s));
  height: calc(520 * var(--s));
  border-radius: calc(6 * var(--s));
  overflow: hidden;
}
.ap-story__track img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.ap-story__text {
  width: calc(927 * var(--s));
  margin: 0;
  font-size: calc(24 * var(--s));
  line-height: calc(30 * var(--s));
  font-weight: 600;
}

.pgrid__link,
.pgrid__media {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* ============================================================
   APPARITION DES TITRES (initTitleReveal dans main.js)
   Un masque par mot, de la hauteur d'une ligne : le mot monte de dessous. Aligné en haut de
   la ligne (avec overflow: hidden, un inline-block se poserait sinon sur son bord bas et
   décalerait le texte) ; prolongé de .15em sous la ligne pour ne pas rogner les jambages.
   ============================================================ */
.reveal-mask {
  display: inline-block;
  overflow: hidden;
  vertical-align: top;
  padding-bottom: .15em;
  margin-bottom: -.15em;
}
.reveal-word { display: inline-block; will-change: transform; }

/* ============================================================
   CURSEUR MAISON (js/cursor.js)
   Les trois dessins d'assets/svg remplacent le curseur du système : flèche, main qui pointe,
   main ouverte. Le calque suit la souris avec un léger retard ; chaque dessin est décalé de
   son point actif, si bien que le calque est posé exactement sous la souris.
   ============================================================ */
/* `none` sur tout : sinon les règles plus précises (pilules, boutons) rendraient le curseur
   du système par-dessus le dessin. La classe n'est posée que si le curseur maison démarre. */
.has-cursor, .has-cursor * { cursor: none !important; }
.cursor {
  position: fixed;
  left: 0;
  top: 0;
  z-index: 200;
  width: 0;
  height: 0;
  opacity: 0;
  pointer-events: none;
  transition: opacity .2s ease;
}
.cursor.is-visible { opacity: 1; }
.cursor__shape {
  position: absolute;
  left: 0;
  top: 0;
  max-width: none; /* le calque fait 0 de large : sans ça, le `max-width: 100%` des images
                      du site écraserait le dessin */
  opacity: 0;
  transition: opacity .12s ease, scale .12s ease;
}
.cursor__shape.is-on { opacity: 1; }
.cursor.is-down .cursor__shape { scale: .9; }

/* ============================================================
   RESPONSIVE
   ============================================================ */
@media (max-width: 1100px) {
  /* Sous 1100px on abandonne la mise à l'échelle du frame : empilement classique. */
  .projects__inner {
    width: 100%;
    max-width: var(--page);
    padding: 60px var(--gutter);
    flex-direction: column;
    gap: 32px;
  }
  .projects__text { position: static; width: 100%; flex: none; height: auto; gap: 24px; margin-bottom: 0; }
  .projects__desc { gap: var(--petit-espace); }
  .projects .h2        { font-size: clamp(28px, 2.78vw, 40px); line-height: 1.125; }
  .projects .body-lead { font-size: 20px; line-height: 26px; }
  .projects .body-md   { font-size: 16px; line-height: 22px; }
  .projects__viewport { width: 100%; flex: none; }
  .projects__track { gap: 16px; }
  .project-card { height: auto; aspect-ratio: 868 / 498; flex: none; border-radius: var(--arrondis); }
  .projects__cta { margin-top: 24px; font-size: 20px; line-height: 26px; padding: 15px 20px 14px; border-radius: var(--arrondis); }

  /* Sous 1100px, pas de mise à l'échelle du frame : empilement classique. */
  .about { padding: 60px 0; }
  .about__inner { width: 100%; max-width: var(--page); height: auto; padding: 0 var(--gutter); gap: var(--grand-espace); }
  .about__portraits { flex-wrap: wrap; gap: 20px; justify-content: center; }
  .about__portraits { padding-left: 0; }
  .about__card { width: 344px; height: auto; flex: 0 1 344px; aspect-ratio: 344 / 427; perspective: 1100px; }
  .about__face { border-radius: 8px; }
  .about__bottom { flex-direction: column; align-items: flex-start; gap: 40px; }
  .about__text { width: auto; max-width: 660px; font-size: 20px; line-height: 26px; }
  .about .btn { font-size: 20px; line-height: 26px; padding: 16px 25px 15px; border-radius: var(--arrondis); }

  /* Footer : cotes Figma telles quelles (le bloc tablette plus bas remet l'échelle). */
  .footer { --f: 1px; }
}

/* Footer tablette (maquette 1098:2360, 1024 × 709) : la mise en page desktop à l'échelle de
   la largeur (--f = 1 à 1024 px). Cotes relevées sur le rendu Figma : marges 13, titre
   (ligne de base à 114) et colonnes alignés en haut à 80.5, bouton 179 × 60 avec la flèche
   avant le texte, mentions à 60 sous le bloc, logo de 959 centré à 403, puis la bande de
   stickers tablette jusqu'en bas. Dégradé : ellipse 800 × 152 centrée en bas. */
@media (min-width: 761px) and (max-width: 1100px) {
  .footer { --f: calc(var(--vw) / 1024); }
  .footer::before {
    background: radial-gradient(ellipse calc(800 * var(--f) * var(--glow-size)) calc(152 * var(--f) * var(--glow-size)) at var(--glow-at),
                var(--footer-glow) 0%, var(--footer-glow-mid) 50%, var(--footer-bg) 100%);
  }
  .footer__inner {
    padding: calc(80.5 * var(--f)) calc(13 * var(--f)) calc(164.7 * var(--f));
    gap: calc(65.3 * var(--f));
  }
  .footer__cta-text { gap: calc(15.6 * var(--f)); }
  .footer__cta .btn {
    flex-direction: row-reverse;
    padding: calc(17.5 * var(--f)) calc(20.75 * var(--f)) calc(16.5 * var(--f));
  }
  .footer__col { gap: calc(23 * var(--f)); }
  .footer__wordmark { width: calc(959 * var(--f)); }
  .footer__pattern { display: none; }
  .footer__band-tablet { display: block; }
}

/* Projets tablette (maquette 1098:1920, 1024 × 852) : titre « Nos réalisations », les
   4 images en grille 2 × 2, sans texte ni dégradé, puis le bouton centré dessous. Le tout
   tient dans un écran (section de 100svh). Les cartes gardent le format desktop (868 × 498)
   et son arrondi (6 px) : leur taille est la plus grande qui tienne à la fois dans la
   largeur et dans la hauteur restante (unités cq de .projects__inner, conteneur de taille) ;
   le bloc titre + grille + bouton est centré. Cotes relevées sur le rendu Figma : marges
   81 / 44 / 39, titre 24/30, cartes écartées de 10, bouton 20 px (61 px de haut).
   Couleur du projet 3 : le bleu clair de la maquette tablette. */
@media (min-width: 761px) and (max-width: 1100px) {
  .projects__inner {
    height: 100svh;
    padding: 81px 44px 39px;
    gap: 24px;
    container-type: size;
    align-items: center;
    justify-content: center;
  }
  .projects__inner > * {
    /* Hauteur d'une carte : limitée par la largeur (2 colonnes) ou par la hauteur libre
       une fois retirés titre 30 + écart 24 + écart 24 + bouton 61 + écart entre rangées 10. */
    --card-h: min(calc((100cqw - 10px) / 2 * 498 / 868), calc((100cqh - 149px) / 2));
    --grid-w: calc(var(--card-h) * 868 / 498 * 2 + 10px);
  }
  .projects__text { flex: none; gap: 0; width: var(--grid-w); }
  .projects__desc { display: none; }
  .projects .h2 { font-size: 24px; line-height: 30px; letter-spacing: -0.04em; }
  .projects__viewport {
    flex: none;
    width: var(--grid-w);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 24px;
  }
  .projects__track {
    width: 100%;
    display: grid;
    grid-template-columns: 1fr 1fr;
    grid-template-rows: repeat(2, var(--card-h));
    gap: 10px;
  }
  .project-card { aspect-ratio: auto; height: auto; min-height: 0; border-radius: 6px; }
  .projects__cta {
    flex: none;
    margin: 0;
    font-size: 20px;
    line-height: 26px;
    padding: 18px 20px 17px;
  }
}

/* À propos tablette (maquette 1098:2360, 1024 × 757) : la mise en page desktop à l'échelle
   de la largeur (--t = 1 à 1024 px). Cotes relevées sur le rendu Figma : portraits
   311.8 × 387.3 (mêmes inclinaisons que desktop), centrés à x = 178.8 / 508.6 / 841.4 ;
   texte 20/26 à x = 20 et bouton calé à 20 du bord droit, 30.45 sous les portraits.
   Comme sur desktop, le bloc est centré verticalement dans l'écran (5.4 = débord du
   3e portrait incliné au-dessus de sa boîte). */
@media (min-width: 761px) and (max-width: 1100px) {
  .about { --t: calc(var(--vw) / 1024); padding: 20px 0; }
  .about__inner {
    max-width: none;
    padding: calc(5.4 * var(--t)) calc(20 * var(--t)) 0;
    gap: calc(30.45 * var(--t));
  }
  .about__portraits { flex-wrap: nowrap; justify-content: flex-start; gap: 0; }
  .about__card {
    width: calc(311.8 * var(--t));
    height: calc(387.3 * var(--t));
    flex: none;
    aspect-ratio: auto;
    perspective: calc(1000 * var(--t));
  }
  .about__face { border-radius: calc(8 * var(--t)); }
  .about__card:nth-child(1) { margin-left: calc(2.9 * var(--t)); }
  .about__card:nth-child(2) { margin-left: calc(18 * var(--t)); }
  .about__card:nth-child(3) { margin-left: calc(21 * var(--t)); }
  .about__bottom { flex-direction: row; justify-content: space-between; gap: calc(40 * var(--t)); }
  .about__text {
    width: calc(648 * var(--t)); /* coupures Figma : ligne 1 = 646, ligne 2 + « du » = 650.5 */
    max-width: none;
    letter-spacing: -0.024em; /* -0.48px à 20 px, à l'échelle pour garder les coupures */
    font-size: calc(20 * var(--t));
    line-height: calc(26 * var(--t));
  }
  .about .btn {
    font-size: calc(20 * var(--t));
    line-height: calc(26 * var(--t));
    letter-spacing: -0.024em;
    padding: calc(16 * var(--t)) calc(25 * var(--t)) calc(15 * var(--t));
    border-radius: calc(6 * var(--t));
  }
}

/* Menu mobile et tablette : frames Figma « Menu » 375 × 795 (1092:131) et 1024 × 795
   (1096:1081), même principe. Frame centré et mis à l'échelle (main.js), pas de mascotte
   ni de surlignage (écran tactile), mots centrés et légèrement inclinés. Cotes relevées
   sur le rendu Figma (écart ≈ 1–2 px), réglées par format :
   --fw largeur du frame · --fscale échelle · --fcover agrandissement du fond ·
   --photo-left bord gauche de la photo par rapport au centre du frame ·
   --word-size / --word-lh / --word-base corps, interligne et ligne de base du mot ;
   et par lien : --ny ligne de base, --nx décalage du centre, --ntilt inclinaison
   (autour du point centre / ligne de base).
   Téléphone à l'horizontale : composition desktop. */
@media (max-width: 760px) and (orientation: portrait) {
  .menu-panel {
    --fw: 375px; --fscale: var(--mk); --fcover: var(--mc); --photo-left: 697.5px; /* photo à x = -510 */
    --word-size: 81px; --word-lh: 83px; --word-base: 64px;
  }
  .menu-panel__nav li { --ny: var(--my); --nx: var(--mx); --ntilt: var(--mtilt); }
}
@media (min-width: 761px) and (max-width: 1100px) {
  .menu-panel {
    --fw: 1024px; --fscale: var(--tk); --fcover: var(--tc); --photo-left: 812px; /* photo à x = -300 */
    --word-size: 106px; --word-lh: 109px; --word-base: 84px;
  }
  .menu-panel__nav li { --ny: var(--ty); --nx: var(--tx); --ntilt: var(--ttilt); }
}
@media (max-width: 760px) and (orientation: portrait), (min-width: 761px) and (max-width: 1100px) {
  .menu-panel__frame {
    left: 50%;
    top: 50%;
    width: var(--fw);
    height: 795px;
    transform-origin: 50% 50%;
    transform: translate(-50%, -50%) scale(var(--fscale));
  }
  /* Photo calée comme dans la maquette, agrandie autour du centre par --fcover si
     l'écran est plus haut ou plus large que le frame. */
  .menu-panel__bg {
    left: calc(var(--fw) / 2 - var(--photo-left) * var(--fcover));
    top: calc(397.5px - 397.5px * var(--fcover));
    width: calc(1716px * var(--fcover));
    height: calc(795px * var(--fcover));
    background-size: 100% 100%;
    background-position: 0 0;
  }
  .menu-panel__mascot,
  .menu-link__on { display: none; }
  .menu-panel__nav li {
    left: var(--nx);
    width: var(--fw);
    top: calc(var(--ny) - var(--word-base));
    transform-origin: 50% var(--word-base);
    rotate: var(--ntilt);
  }
  .menu-link { font-size: var(--word-size); line-height: var(--word-lh); text-align: center; }
  .menu-link > .menu-link__text { padding-left: 0; clip-path: none; }
}

/* Services sur téléphone à la verticale et sur tablette : maquette mobile (1098:1618),
   375 × 836, mise à l'échelle de la largeur (--svs, main.js, plafonnée sur tablette ; sur
   téléphone, aussi limitée par la hauteur de l'écran pour que toute la section soit visible).
   Tout est empilé et centré ; les entrées se jouent au scroll vertical (main.js). Cotes
   relevées sur le rendu Figma : hauts de boîte calculés depuis les lignes de base mesurées
   (mots en 48/48 px : ligne de base à 37.4 px du haut) et les contours dessinés des
   stickers. Le bouton, absent de la maquette, suit « Packaging » : 36 px sous ses
   jambages, puis la même marge basse que la maquette (64 px). */
@media (max-width: 760px) and (orientation: portrait), (min-width: 761px) and (max-width: 1100px) {
  .services { height: calc(836px * var(--svs)); }
  .services__frame {
    left: 50%;
    top: 0;
    width: 375px;
    height: 836px;
    margin-left: -187.5px;
    transform-origin: 50% 0;
    transform: scale(var(--svs));
  }
  .services__track { left: 0; width: 375px; }
  .services__cta {
    left: 0;
    right: 0;
    top: 727px;
    width: fit-content;
    margin: 0 auto;
    transform: none;
    /* Bouton réduit (16 px au lieu de 20) : 45 px de haut. */
    gap: 6px;
    padding: 12px 16px 11px;
    font-size: 16px;
    line-height: 22px;
  }

  .services__title {
    left: 0;
    right: 0;
    top: 59.3px;
    text-align: center;
    white-space: normal;
    font-size: 24px;
    line-height: 30px;
    letter-spacing: -0.04em;
  }
  /* Flèche pixel tournée vers le bas, à mi-taille. */
  .services__chevron { left: 156.5px; top: 146.4px; width: 62px; height: 48.25px; rotate: 90deg; }

  .services__rows { inset: 0; left: 0; top: 0; transform: none; display: block; }
  .srow { display: contents; }
  .srow > * { position: absolute; margin: 0; }
  .srow__word {
    left: 0;
    right: 0;
    width: fit-content;
    margin: 0 auto;
    letter-spacing: -0.02em;
  }
  .srow .h1 { font-size: 48px; line-height: 48px; }
  .srow__word--motion,
  .srow__word--illu { margin: 0 auto; }

  .srow__word--branding { top: 223.6px; }
  .sticker--tiger       { left: 147.6px; top: 265.5px; width: 78.4px; height: 69.7px; margin: 0; }
  .srow__word--web      { top: 341.6px; }
  .srow__chain          { left: 117.8px; top: 382px; margin: 0; transform: scale(.26); transform-origin: 0 0; }
  .srow__word--motion   { top: 422.9px; } /* 429.6 moins le rembourrage du masque (.14em) */
  .sticker--runner      { left: 158.7px; top: 476.4px; width: 57px; height: 53.3px; margin: 0; }
  .srow__word--illu     { top: 533.9px; }
  /* Même échelle et même place du dessin qu'avec l'ancien sticker (marges transparentes comprises). */
  .sticker--bottle      { left: 155.24px; top: 576.36px; width: 73.65px; height: 55.34px; margin: 0; }
  .srow__word--pack     { top: 643.1px; }
}

@media (max-width: 760px) {
  .hero__tagline { font-size: 16px; }

  /* Projets mobile (maquette 1226:599, 375 × 731) : titre « Nos réalisations » puis les
     images seules. Cotes relevées sur le rendu Figma : titre 24/30 (ligne de base à 102),
     cartes 335 px de large à partir de 134, écart 10, arrondi desktop (6 px). La liste est
     une fenêtre de trois cartes qui défile en interne jusqu'à la 4e ; le fondu vers le beige
     (37 % → 104 % de la hauteur d'une carte, relevé sur la 3e) et le bouton, centré à
     20 px du bas, restent fixés au bas de la fenêtre. Sur un écran bas (iPhone SE), la
     fenêtre raccourcit pour s'arrêter au bas de l'écran : le bouton reste visible. */
  .projects__inner { padding: 80px 20px 0; gap: 24px; }
  .projects__text { gap: 0; }
  .projects__desc { display: none; }
  .projects .h2 { font-size: 24px; line-height: 30px; letter-spacing: -0.04em; }
  /* Les cartes défilent avec la page (plus de fenêtre qui défile à l'intérieur : arrivé à la
     dernière carte, l'iPhone faisait rebondir la fenêtre au lieu de descendre la page). Le
     fondu et le bouton restent collés au bas de l'écran pendant qu'on passe les cartes
     (position: sticky), comme la fenêtre de la maquette ; au bout de la liste, le bouton se
     pose 20 px sous la dernière carte et le fondu s'est effacé. */
  .projects__viewport {
    --card-h: calc((var(--vw) - 40px) * 498 / 868);
    --fade-h: calc(var(--card-h) * .6306); /* de 37 % de la carte au bas de la fenêtre */
    /* La fenêtre de la maquette : trois cartes, ou jusqu'au bas de l'écran s'il est plus bas
       (iPhone SE), au moins une carte au-dessus du bouton (téléphone à l'horizontale).
       134 px = marge haute 80 + titre 30 + écart 24. Sous la fenêtre, du beige (--below). */
    --window-h: min(calc(var(--card-h) * 3 + 20px), max(calc(100svh - 134px), calc(var(--card-h) + 93px)));
    --below: max(0px, calc(100svh - 134px - var(--window-h)));
    position: relative;
    display: flex;
    flex-direction: column;
  }
  .projects__track { gap: 10px; }
  .projects__viewport::after {
    content: '';
    position: sticky;
    z-index: 1;
    bottom: 0;
    height: calc(var(--fade-h) + var(--below));
    margin-top: calc(-1 * (var(--fade-h) + var(--below))); /* sur le bas de la liste, sans place en plus */
    background: linear-gradient(rgba(255, 230, 216, 0), var(--beige) calc(var(--fade-h) * 1.076), var(--beige));
    pointer-events: none;
    /* S'efface en arrivant au bout de la liste (--fade, main.js). */
    opacity: var(--fade, 1);
  }
  .project-card { border-radius: 6px; }
  .projects__cta {
    position: sticky;
    z-index: 2;
    bottom: calc(20px + var(--below));
    order: 1; /* après le fondu : par-dessus, et en dernier dans la colonne */
    align-self: center;
    margin: 20px 0;
    font-size: 16px;
    line-height: 22px;
    padding: 16px 24px 15px;
  }
  /* Écart Work → Services : la bande du virage de couleur fait un écran sur desktop ; sur
     téléphone, elle laissait près d'un écran vide sous le bouton (demandé : réduit). */
  .transition-2 { height: 40svh; }

  /* À propos mobile (maquette 1262:268, 375 × 612). Cotes relevées sur le rendu Figma :
     trois bandeaux 336 × 67 (arrondi 6, écart 13) — chaque portrait source pris sur toute
     sa largeur, bande centrée (3e : 35 px sous le haut de l'image, soit 29.3 % de la marge
     de recadrage) —, texte à 24 px dessous, bouton centré 16 px plus bas.
     Texte 13/20, -0.03em (hauteur d'x de 7 px et largeurs des 4 lignes) ; bouton 14/20,
     120 × 51.
     Le bloc occupe tout l'écran avec les marges de la maquette (107 px en haut et en bas) :
     sur les téléphones plus hauts que la maquette, les bandeaux s'allongent pour prendre la
     place libre (jamais moins que 336 × 67). Les images bandeau-<associé>.webp sont les portraits
     entiers, recadrés par object-fit / object-position. */
  .about { padding: 0; }
  .about__inner { min-height: 100svh; padding: 107px 19.5px; gap: 24px; }
  .about__portraits { flex: 1 1 auto; flex-direction: column; flex-wrap: nowrap; gap: 13px; }
  .about__card {
    width: 100%;
    flex: 1 1 0;
    min-height: calc((var(--vw) - 39px) * 67 / 336);
    aspect-ratio: auto;
    perspective: none;
  }
  .about__face { border-radius: 6px; }
  .about__face--back { display: none; } /* pas de retournement sur les bandeaux mobiles */
  .about__card:nth-child(n) { rotate: none; }
  .about__card:nth-child(3) .about__face img { object-position: 50% 29.3%; }
  .about__bottom { align-items: center; gap: 16px; }
  .about__text { width: 100%; max-width: none; font-size: 13px; line-height: 20px; letter-spacing: -0.03em; }
  .about .btn { font-size: 14px; line-height: 20px; padding: 16px 25.5px 15px; border-radius: 6px; }

  /* Footer mobile (maquette 1098:1855, 375 × 621.9). Cotes relevées sur le rendu Figma
     (lignes de base et largeurs d'encre des textes) : marges 26, titre 20/22.5 semi-gras,
     texte 14/20 medium -0.04em, bouton 116.5 × 35 (14/20, arrondi 3), colonnes calées aux
     deux bords, liens 14 px espacés de 26.67, mentions 12/19.5 medium sur deux lignes,
     logo de 13.5 à 361.5 (ligne de base du haut à 481.3), puis la bande de stickers
     mobile (.footer__band) jusqu'en bas. Dégradé : ellipse 299 × 130 centrée en bas. */
  .footer::before {
    background: radial-gradient(ellipse calc(79.7% * var(--glow-size)) calc(130px * var(--glow-size)) at var(--glow-at),
                var(--footer-glow) 0%, var(--footer-glow-mid) 50%, var(--footer-bg) 100%);
  }
  .footer__inner {
    padding: 42.5px 26px calc(var(--vw) * 89.3 / 375);
    gap: 41.1px;
  }
  .footer__grid { gap: 42.34px; }
  .footer__top { flex-direction: column; gap: 40.35px; }
  .footer__cta { gap: 16px; }
  .footer__cta-text { gap: 9.4px; }
  .footer__cta-text p { max-width: none; }
  .footer .h2 { font-size: 20px; line-height: 22.5px; letter-spacing: 0; }
  .footer .body-sm { font-size: 14px; line-height: 20px; font-weight: 500; letter-spacing: -0.04em; }
  .footer .btn { gap: 5.6px; padding: 7.5px 10px; font-size: 14px; line-height: 20px; border-radius: 3px; }
  .footer__nav { width: 100%; justify-content: space-between; gap: 0; }
  .footer__col { flex: none; width: auto; gap: 12.3px; }
  .footer__col ul { gap: 12px; font-size: 14px; line-height: 14.7px; letter-spacing: -0.04em; }
  .footer__legal { display: block; line-height: 19.5px; font-weight: 500; letter-spacing: -0.04em; }
  .footer .legal { font-size: 12px; }
  .footer__rights { display: inline; }
  .footer__legal-links { display: block; width: auto; }
  .footer__legal-links a { width: auto; }
  .footer__legal-links a + a::before { content: '| '; }
  .footer__wordmark { width: calc(100% + 25px); }
  .footer__pattern { display: none; }
  .footer__band { display: block; }

  /* Page Services mobile (maquette 1095:293 : hero et sections de 375 × 795, footer mobile).
     Cotes × --m (largeur d'écran / 375), sections toujours plein écran, contenu placé par
     rapport au centre comme sur desktop. Relevés sur le rendu Figma : titre du hero 32 px
     sur 27 (lignes de base à 390 et 417) ; titres 40 px, ligne de base à 391 ; pilules en
     20 px, 32.1 de haut, ligne de base à 23.1 du haut (le desktop × 0.625). */
  .svc-hero,
  .svc { --m: calc(var(--vw) / 375); }
  .svc-hero__title {
    top: calc(50% - 29.8 * var(--m));
    font-size: calc(32 * var(--m));
    line-height: calc(27 * var(--m));
  }
  .svc__title {
    top: calc(50% - 38.3 * var(--m));
    font-size: calc(40 * var(--m));
    line-height: calc(42 * var(--m));
  }
  .svc__pill {
    height: calc(32.1 * var(--m));
    padding: calc(3.1 * var(--m)) calc(11.25 * var(--m)) 0;
    border-radius: calc(16 * var(--m));
    font-size: calc(20 * var(--m));
    line-height: calc(29 * var(--m));
  }

  /* Page Contact mobile (maquette 1095:597, 375 × 795), avec le titre et les liens soulignés
     du desktop. Cotes × --m (largeur / 375), bloc centré dans l'écran (2.3 sous le milieu).
     Relevés sur le rendu Figma : titre 24 px sur 22 (semi-gras du desktop, normal sur la
     maquette), en trois lignes (lignes de base à
     292, 314, 336) ; intitulés 16 px medium ; coordonnées 12 px sur 17 ; lignes de base à 396,
     421, 438, 477, 502 et 519. Pas de traînée de stickers au doigt (contact.js). */
  .contact { --m: calc(var(--vw) / 375); }
  .contact__inner {
    top: calc(50% + 2.3 * var(--m));
    translate: 0 -50%;
    padding: 0 calc(12 * var(--m));
  }
  .contact__title {
    max-width: calc(351 * var(--m));
    margin-bottom: calc(37.7 * var(--m)); /* 40.2 de la maquette − demi-interligne ajouté */
    font-size: calc(24 * var(--m));
    line-height: calc(27 * var(--m)); /* 22 sur la maquette : aéré au rapport du desktop (40/45) */
    text-wrap: balance;
  }
  .contact__title br { display: none; }
  .contact__label { font-size: calc(16 * var(--m)); line-height: calc(22 * var(--m)); }
  .contact__block + .contact__block { margin-top: calc(18.4 * var(--m)); }
  .contact__list,
  .contact__list--social {
    gap: 0;
    margin-top: calc(6.9 * var(--m));
    font-size: calc(12 * var(--m));
    line-height: calc(17 * var(--m));
  }
  .contact__list--social a { text-decoration-thickness: 1px; text-underline-offset: calc(1.5 * var(--m)); }
  /* 404 mobile (pas de maquette) : mêmes éléments à l'échelle de la largeur (--m), titre et
     phrase repliés en lignes équilibrées, boutons l'un sous l'autre. */
  .e404 { --m: calc(var(--vw) / 375); }
  .e404__inner { gap: calc(16 * var(--m)); padding: 0 calc(20 * var(--m)); }
  .e404__title { font-size: calc(40 * var(--m)); line-height: calc(42 * var(--m)); text-wrap: balance; }
  .e404__text  { font-size: calc(20 * var(--m)); line-height: calc(24 * var(--m)); text-wrap: balance; }
  .e404__text br { display: none; }
  .e404__actions { flex-direction: column; align-items: center; gap: calc(10 * var(--m)); margin-top: calc(8 * var(--m)); }
  /* Boutons comme le « Voir tous nos projets » de l'accueil mobile. */
  .e404__btn {
    font-size: 16px;
    line-height: 22px;
    padding: 16px 24px 15px;
    border-radius: var(--arrondis);
  }

  /* Page Projets mobile (maquette 1094:274, 375 × 795) : une grande vignette pleine largeur
     puis deux petites côte à côte, en boucle — la liste reste ouverte (CMS). Cotes × --m
     (largeur / 375) : contenu de 336 centré, première vignette à 104 du haut, écart de 14 ;
     grande de 189 de haut (16/9 comme sur desktop), petites de 161 × 185.7. */
  .pgrid { --m: calc(var(--vw) / 375); padding: calc(104 * var(--m)) 0; }
  .pgrid__list { width: calc(336 * var(--m)); gap: calc(14 * var(--m)); }
  .pgrid__item,
  .pgrid__item:nth-child(4n + 1),
  .pgrid__item:nth-child(4n) {
    width: calc(161 * var(--m));
    height: calc(185.7 * var(--m));
  }
  .pgrid__item:nth-child(3n + 1) {
    width: calc(336 * var(--m));
    height: calc(189 * var(--m));
  }
  .pgrid__item { border-radius: var(--arrondis); }

  /* Page projet mobile (en attendant la maquette) : une colonne, images pleine largeur,
     textes à taille fixe lisible. */
  .pj {
    --pj-media-top: calc(var(--header-h) + 116px);
    --pj-gap: 24px;
    width: 100%;
    padding: var(--pj-head) var(--gutter) 60px;
  }
  .pj__title { margin: 0; font-size: 48px; line-height: 52px; }
  .pj__lead { margin: 0; }
  .pj__lead br { display: none; } /* la coupure du desktop tomberait mal sur 335 de large */
  .pj__lead,
  .pj__heading { font-size: 24px; line-height: 30px; }
  .pj__text { font-size: 16px; line-height: 22px; }
  /* Pas de mot seul en dernière ligne (ex. « assume. » sous l'accroche de Mojo). */
  .pj__lead,
  .pj__heading,
  .pj__text { text-wrap: pretty; }
  .pj__text--right,
  .pj__text--wide,
  .pj__text--indent,
  .pj__text--half,
  .pj__text--wide-right,
  .pj__heading--half,
  .pj__aside > .pj__text { width: auto; margin-left: 0; }
  .pj__intro,
  .pj__wide,
  .pj__aside,
  .pj__pair,
  .pj__trio,
  .pj__list,
  .pj__cards,
  .pj__duo { display: flex; flex-direction: column; gap: 16px; }
  /* Mobile : l'image d'abord, puis étiquettes ou texte en dessous. */
  .pj__aside { align-items: stretch; }
  .pj__wide--reverse .pj__heading { order: 1; }
  .pj__intro-text { gap: 24px; }
  .pj__tags { gap: 6px; max-width: none; }
  .pj__tags li { padding: 10px 12px; border-radius: var(--arrondis); font-size: 14px; line-height: 18px; }
  .pj__cards-stack { gap: 16px; }
  .pj__media,
  .pj__marquee { border-radius: var(--arrondis); }

  /* Page À propos mobile (en attendant la maquette) : l'intro garde ses proportions à une
     échelle plus grande (--s local), bandeaux et carrousel à tailles fixes lisibles. */
  /* Intro centrée dans l'écran (le texte garde d'emblée sa hauteur finale, cf. apropos.js :
     le bloc ne remonte pas quand les vignettes s'ouvrent). */
  .ap-intro { --s: calc(var(--vw) / 760); align-items: center; }
  .ap-intro__inner { width: 100%; padding: var(--header-h) var(--gutter); }
  /* Pas de mot seul en dernière ligne (navigateurs récents ; ailleurs les espaces insécables
     du HTML gardent au moins « bien fait. » ensemble). */
  .ap-intro__text { width: 100%; text-wrap: pretty; }
  .ap-trail { display: none; }
  .ap-team { padding: 40px 0; }
  .ap-bands { width: calc(100% - 2 * var(--gutter)); border-radius: var(--arrondis); }
  /* Bandeaux hauts, suivant la hauteur de l'écran (iPhone SE : 120 / 267, 812 de haut :
     146 / 325). Un toucher ouvre le bandeau et affiche le nom et la bio. */
  .ap-band { height: clamp(96px, 18svh, 150px); }
  .ap-band.is-open { height: clamp(240px, 40svh, 340px); }
  .ap-band__info { left: 16px; right: 16px; bottom: 16px; width: auto; gap: 8px; }
  .ap-band__name { font-size: 18px; line-height: 24px; }
  .ap-band__bio { font-size: 13px; line-height: 18px; }
  .ap-story__inner { width: 100%; gap: 40px; }
  .ap-story__track { --end: var(--gutter); gap: 12px; padding-left: var(--gutter); }
  .ap-story__track li { width: min(84vw, 380px); height: auto; aspect-ratio: 451 / 520; border-radius: var(--arrondis); }
  .ap-story__text { width: auto; padding: 0 var(--gutter); font-size: 16px; line-height: 22px; }
}

/* Page Services tablette (maquette 1096:822 : hero et sections de 1024 × 795, footer tablette).
   Titres et pilules aux cotes desktop, mais dans un cadre de 1024 de large : échelle --t
   (largeur / 1024, bornée par la hauteur comme --s). Relevés sur le rendu Figma : titre du
   hero 40 px sur 45 (lignes de base à 386 et 431) ; titres 96 px, ligne de base à 434.5 ;
   pilules de 51.4 de haut en 32 px ; « Voir nos service » plus haut et plus écarté du
   chevron qu'en desktop (ligne de base à 755, chevron de 772 à 776). */
@media (min-width: 761px) and (max-width: 1100px) {
  .svc-hero,
  .svc { --t: min(var(--vw) / 1024, 100svh / 795); }
  .svc-hero__title {
    top: calc(50% - 45.5 * var(--t));
    font-size: calc(40 * var(--t));
    line-height: calc(45 * var(--t));
  }
  .svc-hero__scroll { bottom: 17px; gap: 10px; }
  .svc__title {
    top: calc(50% - 39 * var(--t));
    font-size: calc(96 * var(--t));
    line-height: calc(100 * var(--t));
  }
  .svc__pill {
    height: calc(51.4 * var(--t));
    padding: calc(5 * var(--t)) calc(18 * var(--t)) 0;
    border-radius: calc(25.7 * var(--t));
    font-size: calc(32 * var(--t));
    line-height: calc(46.4 * var(--t));
  }
  @media (hover: hover) {
    .svc__pill:hover,
    .svc__pill.is-dragging { box-shadow: inset 0 0 0 calc(2 * var(--t)) var(--beige); }
  }
}

/* Page À propos tablette (en attendant la maquette) : l'intro centrée dans l'écran, comme en
   mobile — la mise en page desktop la calait en haut (à 177), avec un grand vide dessous. Le
   texte garde d'emblée sa hauteur finale (apropos.js) : le bloc ne bouge pas pendant la lecture. */
@media (min-width: 761px) and (max-width: 1100px) {
  .ap-intro { align-items: center; }
  .ap-intro__inner { padding: var(--header-h) 0; }
}

@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; transition: none !important; }
}
