/* ==========================================================================
   ZidaneStudio â€” Refonte 2026
   Direction artistique : Â« clair Ã©ditorial Â»
   Papier crÃ¨me Â· encre bleu nuit Â· accent terracotta
   Angles nets Â· filets 1px Â· typographie serif de labeur
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Tokens
   -------------------------------------------------------------------------- */
:root {
  /* Surfaces */
  --paper:        #f7f3ee;
  --paper-raised: #fffdfb;
  --paper-sunk:   #efe8e0;
  --ink:          #0b2530;
  --ink-deep:     #06161d;

  /* Texte â€” chaque teinte est calibrÃ©e pour son usage :
     --ink-body    10.4:1  corps de texte
     --ink-muted    5.6:1  labels, liens secondaires (WCAG AA)
     --ink-faint    4.5:1  mÃ©tadonnÃ©es, numÃ©ros (ne descend plus en dessous) */
  --ink-body:     #12303c;
  --ink-muted:    #3d5158;
  --ink-faint:    #566b73;

  /* Accent â€” trois intensitÃ©s selon la taille du texte :
     --accent      3.1:1  purely dÃ©coratif (pastilles, filets, bordures)
     --accent-ink  5.0:1  texte de grand titre (seuil AA grand texte)
     --accent-text 5.0:1  petit texte (seuil AA normal) */
  --accent:       #e1652f;
  --accent-ink:   #c2501a;
  --accent-text:  #a94214;
  --accent-deep:  #b8481a;   /* 5.3:1 sur blanc â€” boutons, liens */
  --accent-wash:  #fbe4d6;
  --accent-tint:  #ffb47e;   /* teinte de marque historique */

  /* Filets & surfaces */
  --line:         rgba(11, 37, 48, 0.14);
  --line-soft:    rgba(11, 37, 48, 0.08);
  --line-strong:  rgba(11, 37, 48, 0.28);
  --on-ink:       #f3efe9;
  --on-ink-muted: rgba(243, 239, 233, 0.66);
  --line-on-ink:  rgba(243, 239, 233, 0.18);

  /* Typographie */
  --font-display: "Instrument Serif", "Times New Roman", Georgia, serif;
  --font-sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
    Helvetica, Arial, sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, "SFMono-Regular", Menlo,
    Consolas, monospace;

  /* Rythme */
  --container: 1240px;
  --gutter: clamp(1.25rem, 4vw, 3.5rem);
  --section-y: clamp(3rem, 5vw, 4.75rem);
   /* 9.5rem de plafond donnait 152px de marge haute et 152px basse, donc 280px
      de vide entre deux sections consecutivees sur un ecran large. C'est le
      regime des pages-beacons : le regard ne trouve plus le rythme, il saute
      d'un bloc a l'autre. 6rem ramene l'intervalle a 96px par cote, soit 192px
      entre deux sections : assez pour separer deux sujets, pas assez pour
      donner l'impression d'une page manquante. */

  --radius: 2px;

  /* Ancrage â€” hauteur du menu fixe (mesurÃ©e : 79px, identique desktop/mobile)
     et respiration entre le bas du menu et le titre d'une section. */
  --header-h: 79px;
  --anchor-gap: 24px;

  /* Transitions */
  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --dur: 0.45s;

  /* Ombres â€” trÃ¨s discrÃ¨tes, cohÃ©rentes avec lxisage papier */
  --shadow-sm: 0 1px 2px rgba(11, 37, 48, 0.04);
  --shadow-md: 0 12px 30px -12px rgba(11, 37, 48, 0.16);
  --shadow-lg: 0 30px 60px -24px rgba(11, 37, 48, 0.24);
}

/* --------------------------------------------------------------------------
   1b. Polices auto-hÃ©bergÃ©es
   Sous-ensemble latin, 4 fichiers, 120 Ko. DÃ©clarÃ©es ici plutÃ´t que dans une
   feuille sÃ©parÃ©e : un second <link rel=stylesheet> est render-blocking et
   serialise avec le reste du CSS sur un serveur mono-thread.

   Ces rÃ¨gles vivaient avant sur fonts.googleapis.com, puis les .woff2 Ã©taient
   servis par fonts.gstatic.com : 2 origines tierces, donc 2 suites de
   handshakes DNS+TCP+TLS (150 ms de RTT simulÃ© par Lighthouse mobile) avant le
   moindre glyphe. Gain mesurÃ© en throttling : ~900 ms de LCP.
   Effet secondaire : plus aucune IP de visiteur transmise Ã  Google (RGPD).

   Inter et JetBrains Mono sont variables : un seul fichier couvre toute la
   plage de poids, sinon 5 fichiers redondants pour 172 Ko de plus.
   -------------------------------------------------------------------------- */
@font-face {
  font-family: "Instrument Serif";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("../fonts/instrument-serif-400.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;
}
@font-face {
  font-family: "Instrument Serif";
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url("../fonts/instrument-serif-400-italic.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;
}
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 300 600;
  font-display: swap;
  src: url("../fonts/inter-300-600.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;
}
@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 400 500;
  font-display: swap;
  src: url("../fonts/jetbrains-mono-400-500.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;
}

/* --------------------------------------------------------------------------
   2. Reset
   -------------------------------------------------------------------------- */
*,
*::before,
*::after { box-sizing: border-box; }

* { margin: 0; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* DÃ©gage uniquement le menu fixe. Le souffle de --anchor-gap est ensuite
     apportÃ© par `.section:target` (padding-top). Ne pas cumuler les deux, sinon
     le gap est doublÃ©. */
  scroll-padding-top: var(--header-h);
  /* ATTENTION : ne jamais mettre `overflow-x` sur <body>. Cela transforme le
     body en conteneur de dÃ©filement (overflow-y passe Ã  `auto`, le body prend
     toute la hauteur du document) et casse window.scrollTo, les scripts
     de defilement et le positionnement fixe. On porte le clipping sur <html>. */
  overflow-x: hidden;
  /* RÃ©serve la gouttiÃ¨re de dÃ©filement en permanence, pour que poser le verrou
     de scroll du menu ne provoque pas un saut horizontal du layout. */
  scrollbar-gutter: stable;
}
@supports (overflow-x: clip) {
  html { overflow-x: clip; } /* ne cree aucun conteneur de defilement */
}

body {
  background-color: var(--paper);
  color: var(--ink-body);
  font-family: var(--font-sans);
  font-size: 1.0625rem;
  font-weight: 400;
  line-height: 1.7;
  font-feature-settings: "kern" 1, "liga" 1, "cv11" 1;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  min-height: 100vh;
}

/* Grain papier â€” trÃ¨s lÃ©ger, donne la texture dâ€™un tirage imprimÃ© */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 9999;
  pointer-events: none;
  opacity: 0.032;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23n)'/%3E%3C/svg%3E");
}

img,
picture,
svg,
video,
canvas {
  display: block;
  max-width: 100%;
}

img,
video { height: auto; }

input,
button,
textarea,
select {
  font: inherit;
  color: inherit;
}

button { background: none; border: 0; cursor: pointer; }

ul[class],
ol[class] { list-style: none; padding: 0; }

a { color: inherit; text-decoration: none; }

/* Plus de `scroll-margin-top` ici : il s'ajoutait au `scroll-padding-top` du
   document et repoussait le titre ~230px sous le menu. Le dÃ©gagement est
   dÃ©sormais gÃ©rÃ© en un seul endroit (scroll-padding-top). */

::selection {
  background: var(--accent);
  color: #fff;
}

/* --------------------------------------------------------------------------
   3. Typographie
   -------------------------------------------------------------------------- */
h1, h2, h3, h4, h5, h6 {
  font-family: var(--font-display);
  color: var(--ink);
  font-weight: 400;
  line-height: 1.04;
  letter-spacing: -0.015em;
  text-wrap: balance;
}

/* 136px sur grand Ã©cran : beaucoup trop grand en PC. PlafonnÃ© Ã  4.5rem (72px),
   ce qui est aussi la taille maximale pour que Â« une forme qui marque. Â» tienne
   sur une seule ligne dans la colonne de texte (632px dispo / 784px Ã  100px).
   Sans ce plafond, le titre casse sur 3 lignes dÃ¨s 1280px.
   Les pages lÃ©gales gardent leur propre taille (`.page-head h1`). */
h1 { font-size: clamp(2.75rem, 5.2vw, 4.5rem); line-height: 0.95; }
h2 { font-size: clamp(2.15rem, 5.4vw, 4.5rem); }
h3 { font-size: clamp(1.5rem, 2.6vw, 2.15rem); line-height: 1.12; }
h4 { font-size: clamp(1.2rem, 1.7vw, 1.5rem); line-height: 1.2; }

p { text-wrap: pretty; }

/* Emphase serif italique dans les titres â€” signature Ã©ditoriale */
.em {
  font-style: italic;
  color: var(--accent-ink);
  font-family: var(--font-display);
}

.lead {
  font-size: clamp(1.1rem, 1.6vw, 1.3rem);
  line-height: 1.6;
  color: var(--ink-muted);
  font-weight: 300;
  max-width: 56ch;
}


/* --------------------------------------------------------------------------
   4. AccessibilitÃ©
   -------------------------------------------------------------------------- */
:where(a, button, input, textarea, select, summary, [tabindex]):focus-visible {
  outline: 2px solid var(--accent-deep);
  outline-offset: 3px;
  border-radius: 1px;
}

.skip-link {
  position: absolute;
  top: -100px;
  left: 1rem;
  z-index: 10000;
  padding: 0.85rem 1.4rem;
  background: var(--ink);
  color: var(--on-ink);
  font-family: var(--font-mono);
  font-size: 0.75rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  transition: top 0.25s var(--ease);
}
.skip-link:focus { top: 1rem; }

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* --------------------------------------------------------------------------
   5. Mise en page
   -------------------------------------------------------------------------- */
.container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.container--narrow { max-width: 800px; }

.section {
  position: relative;
  padding-block: var(--section-y);
}

/* Option B : quand une section est ciblÃ©e, son padding haut est rÃ©duit Ã 
   --anchor-gap. Le titre se retrouve juste sous le menu, et le fond --sunk /
   --ink reste cohÃ©rent au-dessus. `scroll-margin-top` est volontairement absent
   : le dÃ©gagement du menu est dÃ©jÃ  fait par scroll-padding-top sur <html>. */
.section:target {
  padding-top: var(--anchor-gap);
}

/* a-propos : son libellÃ© est un <p class="eyebrow"> en inline-flex dans une
   cellule de grille. Le leading de ligne le dÃ©cale d'environ 9px sous les
   autres sections. On le repasse en flex (block) pour l'aligner au meme gap. */
.section:target .about__body .eyebrow {
  display: flex;
}

.section--sunk { background: var(--paper-sunk); }
.section--ink {
  background: var(--ink);
  color: var(--on-ink);
}
.section--ink h2,
.section--ink h3,
.section--ink h4 { color: var(--on-ink); }
.section--ink .lead { color: var(--on-ink-muted); }


/* 7/5 et 5/7 â€” grille asymÃ©trique Ã©ditoriale */
.split {
  display: grid;
  grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
  gap: clamp(2rem, 6vw, 6rem);
  align-items: center;
}
.split--flip { grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); }
.split--top { align-items: start; }

/* --------------------------------------------------------------------------
   6. Composants : labels & en-tÃªtes de section
   -------------------------------------------------------------------------- */
.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.7rem;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-muted);
}

.eyebrow::before {
  content: "";
  width: 6px;
  height: 6px;
  background: var(--accent);
  flex: none;
  border-radius: 50%;
}


.section-head {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 1.5rem;
  margin-bottom: clamp(2rem, 4.5vw, 3.5rem);
}

.section-head--row {
  grid-template-columns: minmax(0, 1fr) minmax(0, 22rem);
  gap: clamp(1.5rem, 4vw, 4rem);
  align-items: end;
}

/* Sections services : le chapÃ´ passe sous le titre au lieu d'Ãªtre
   placÃ© dans une colonne Ã  cÃ´tÃ©. */
.section-head--stack {
  grid-template-columns: minmax(0, 1fr);
  align-items: start;
}

.section-head__index {
  display: block;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.18em;
  color: var(--accent-text);
  margin-bottom: 1.25rem;
}

.section-head h2 { max-width: 20ch; }

/* Le chapÃ´ Ã  droite du titre de section Ã©tait trop imposant en PC (20,8px,
   presque la taille du corps de texte). On le ramÃ¨ne Ã  17px maximum, comme le
   texte courant, pour que le h2 garde la hiÃ©rarchie.

   Largeur : 52ch ne donnaient que 546 px dans un conteneur de 1240 px, soit
   44 % de la ligne et 694 px vides Ã  droite â€” le texte restait collÃ© au bord
   gauche. On monte Ã  72ch (~756 px, 61 %), qui reste dans la fourchette
   confortable de lecture (45-75 caractÃ¨res). Au-delÃ , la ligne deviendrait
   difficile Ã  suivre : le conteneur ferait 145 caractÃ¨res par ligne. */
.section-head .lead {
  max-width: 72ch;
  font-size: clamp(1.05rem, 1.15vw, 1.0625rem);
  line-height: 1.65;
}

/* --------------------------------------------------------------------------
   7. Boutons
   -------------------------------------------------------------------------- */
.btn {
  --btn-bg: var(--ink);
  --btn-fg: var(--on-ink);
  --btn-bd: var(--ink);
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 0.85rem;
  padding: 1.05rem 1.85rem;
  background: var(--btn-bg);
  color: var(--btn-fg);
  border: 1px solid var(--btn-bd);
  border-radius: var(--radius);
  font-family: var(--font-mono);
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  white-space: nowrap;
  overflow: hidden;
  isolation: isolate;
  transition: color 0.35s var(--ease), border-color 0.35s var(--ease),
    transform 0.35s var(--ease);
}

/* Voile d'accent qui monte au survol */
.btn::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--accent-deep);
  transform: scaleY(0);
  transform-origin: bottom;
  transition: transform 0.4s var(--ease-out);
}

.btn:hover::before,
.btn:focus-visible::before { transform: scaleY(1); }

.btn:hover,
.btn:focus-visible { color: #fff; border-color: var(--accent-deep); }
.btn:active { transform: translateY(1px); }

.btn__arrow {
  width: 1em; height: 1em;
  flex: none;
  transition: transform 0.4s var(--ease-out);
}
.btn:hover .btn__arrow { transform: translateX(4px); }

.btn--ghost {
  --btn-bg: transparent;
  --btn-fg: var(--ink);
  --btn-bd: var(--line-strong);
}
.btn--ghost:hover,
.btn--ghost:focus-visible { color: #fff; }

.btn--accent {
  --btn-bg: var(--accent-deep);
  --btn-fg: #fff;
  --btn-bd: var(--accent-deep);
}
.btn--accent::before { background: var(--ink); }
.btn--accent:hover,
.btn--accent:focus-visible { border-color: var(--ink); }

.btn--on-ink {
  --btn-bg: var(--on-ink);
  --btn-fg: var(--ink);
  --btn-bd: var(--on-ink);
}
.btn--on-ink:hover,
.btn--on-ink:focus-visible { color: #fff; }

.btn--sm { padding: 0.75rem 1.25rem; font-size: 0.68rem; }
.btn--block { width: 100%; justify-content: center; }

/* Lien texte avec soulignement animÃ© */
.link {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  color: var(--accent-deep);
  font-weight: 500;
  border-bottom: 1px solid currentColor;
  padding-bottom: 2px;
  transition: color 0.3s var(--ease), gap 0.3s var(--ease);
}
.link:hover { color: var(--accent); gap: 0.85rem; }
.section--ink .link { color: var(--accent-tint); }
.section--ink .link:hover { color: #fff; }

/* --------------------------------------------------------------------------
   8. En-tÃªte
   -------------------------------------------------------------------------- */
.header {
  position: fixed;
  inset: 0 0 auto;
  z-index: 900;
  transition: background-color 0.4s var(--ease),
    border-color 0.4s var(--ease), box-shadow 0.4s var(--ease);
  border-bottom: 1px solid transparent;
}

.header.is-stuck {
  background: rgba(247, 243, 238, 0.86);
  -webkit-backdrop-filter: saturate(180%) blur(14px);
  backdrop-filter: saturate(180%) blur(14px);
  border-bottom-color: var(--line);
}

.header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 2rem;
  min-height: 78px;
}

/* Signature */
.brand {
  display: inline-flex;
  align-items: center;
  gap: 0.75rem;
  color: var(--ink);
  flex: none;
}
.brand__logo {
  width: auto;
  height: 38px;
  object-fit: contain;
  flex: none;
  transition: transform 0.3s var(--ease);
}
.brand:hover .brand__logo {
  transform: scale(1.05);
}
.brand__text {
  display: inline-flex;
  align-items: baseline;
  gap: 0.35rem;
}
.brand__name {
  font-family: var(--font-display);
  font-size: 1.65rem;
  letter-spacing: -0.02em;
  line-height: 1;
}
.brand__name i { font-style: italic; color: var(--accent); }
.brand__sub {
  font-family: var(--font-mono);
  font-size: 0.6rem;
  font-weight: 500;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--ink-muted);
}

.nav { display: flex; align-items: center; gap: clamp(1.25rem, 2.5vw, 2.4rem); }

.nav__link {
  position: relative;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--ink-muted);
  padding-block: 0.55rem;
  transition: color 0.3s var(--ease);
}
.nav__link::after {
  content: "";
  position: absolute;
  left: 0; bottom: 0;
  width: 100%; height: 1px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: right;
  transition: transform 0.4s var(--ease-out);
}
.nav__link:hover,
.nav__link.is-active { color: var(--ink); }
.nav__link:hover::after,
.nav__link.is-active::after { transform: scaleX(1); transform-origin: left; }

.header__actions { display: flex; align-items: center; gap: 1rem; }

/* Bouton menu mobile */
.nav-toggle {
  display: none;
  width: 44px; height: 44px;
  margin-right: -8px;
  place-items: center;
  color: var(--ink);
}
.nav-toggle__bars {
  display: block;
  position: relative;
  width: 22px; height: 12px;
}
.nav-toggle__bars span {
  position: absolute;
  left: 0;
  width: 100%; height: 1.5px;
  background: currentColor;
  transition: transform 0.4s var(--ease-out), opacity 0.2s linear;
}
.nav-toggle__bars span:nth-child(1) { top: 0; }
.nav-toggle__bars span:nth-child(2) { bottom: 0; }
.nav-toggle[aria-expanded="true"] .nav-toggle__bars span:nth-child(1) {
  transform: translateY(5.25px) rotate(45deg);
}
.nav-toggle[aria-expanded="true"] .nav-toggle__bars span:nth-child(2) {
  transform: translateY(-5.25px) rotate(-45deg);
}

/* Menu mobile plein Ã©cran */
.mobile-menu {
  position: fixed;
  inset: 0;
  z-index: 890;
  background: var(--paper);
  padding: 7rem var(--gutter) 2.5rem;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-12px);
  transition: opacity 0.4s var(--ease), transform 0.5s var(--ease-out),
    visibility 0.4s;
}
.mobile-menu.is-open {
  opacity: 1;
  visibility: visible;
  transform: none;
}
.mobile-menu__list { display: flex; flex-direction: column; }
.mobile-menu__list li {
  border-bottom: 1px solid var(--line);
  opacity: 0;
  transform: translateY(10px);
}
.mobile-menu.is-open .mobile-menu__list li {
  animation: menu-in 0.5s var(--ease-out) forwards;
  animation-delay: calc(0.06s * var(--i));
}
.mobile-menu__list a {
  display: flex;
  align-items: baseline;
  gap: 1rem;
  padding-block: 1.1rem;
  font-family: var(--font-display);
  font-size: clamp(2rem, 8vw, 2.8rem);
  color: var(--ink);
}
.mobile-menu__list a span {
  font-family: var(--font-mono);
  font-size: 0.65rem;
  color: var(--accent);
  letter-spacing: 0.14em;
}
.mobile-menu__foot {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
  opacity: 0;
}
.mobile-menu.is-open .mobile-menu__foot {
  animation: menu-in 0.5s var(--ease-out) 0.36s forwards;
}

@keyframes menu-in {
  to { opacity: 1; transform: none; }
}

/* Verrou de scroll du menu mobile.
   Le verrou doit porter sur <html> : c'est document.scrollingElement qui dÃ©file,
   donc `body { overflow: hidden }` seul ne l'empÃªche pas (vÃ©rifiÃ© au navigateur :
   la page scrollait de 0 Ã  552px avec le menu ouvert). `body` est conservÃ© pour
   les navigateurs anciens qui ne respecteraient que lui. */
html.is-locked,
body.is-locked { overflow: hidden; }

/* --------------------------------------------------------------------------
   9. HÃ©ros
   -------------------------------------------------------------------------- */
.hero {
  position: relative;
  /* Le menu est `position: fixed` : son occupant la place en haut du flux. On
     ne garde donc qu'un souffle minimal au-dessus du libellÃ©, sans le recompter.
     Avant : clamp(9rem, 18vw, 13rem) â†’ 109 Ã  137px de vide sous le menu. */
  padding-top: calc(var(--header-h) + clamp(1.5rem, 2.5vw, 2.25rem));
  padding-bottom: clamp(2.5rem, 5vw, 4rem);
  overflow: hidden;
}

/* Lueur d'accent en arriÃ¨re-plan */
.hero::before {
  content: "";
  position: absolute;
  top: -18%;
  right: -12%;
  width: min(760px, 82vw);
  aspect-ratio: 1;
  background: radial-gradient(
    circle at 50% 50%,
    var(--accent-wash) 0%,
    rgba(251, 228, 214, 0) 68%
  );
  pointer-events: none;
  z-index: 2;
}

/* --- VidÃ©o de fond -------------------------------------------------------
   Ordre d'empilement du hÃ©ros, du fond vers l'avant :
     0  .hero__bg        la vidÃ©o
     1  .hero__veil      le voile de lisibilitÃ©
     2  .hero::before    la lueur d'accent
     3  .hero__grid      le texte et le collage
   Les z-index sont explicites et distincts : Ã  valeur Ã©gale, l'ordre de
   peinture suit l'ordre du DOM, ce qui rendrait ce rÃ©sultat implicite. */
.hero__bg {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
}
.hero__bg-video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* LÃ©ger dÃ©bord pour Ã©viter la couture d'un demi-pixel sur les Ã©crans larges. */
  transform: scale(1.02);
}

/* Voile de lisibilitÃ©. Il est dense Ã  gauche, sous la colonne de texte, et
   s'Ã©claircit vers la droite oÃ¹ le collage couvre dÃ©jÃ  la vidÃ©o. C'est ce qui
   permet de garder les contrastes documentÃ©s (titres 15,8:1, texte 11,2:1) :
   fond composÃ© = --paper Ã  ~93 % sous le texte, donc l'Ã©cart rÃ©el avec --ink
   reste proche de celui mesurÃ© sur fond papier. Un voile sombre donnerait un
   hero sombre et invaliderait toute la table de contrastes du design system. */
.hero__veil {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background:
    linear-gradient(
      100deg,
      var(--paper) 0%,
      rgba(247, 243, 238, 0.93) 34%,
      rgba(247, 243, 238, 0.74) 64%,
      rgba(247, 243, 238, 0.56) 100%
    ),
    linear-gradient(to bottom, var(--paper) 0%, rgba(247, 243, 238, 0) 26%);
}

.hero__grid {
  position: relative;
  z-index: 3;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 26rem);
  gap: clamp(2.5rem, 6vw, 5rem);
  align-items: end;
}

/* Colonne de texte du hero. Porteuse du h1, donc de tous les points de
   coupure de ligne ; min-width:0 evite qu'un mot long refuse de
   descendre dans la colonne voisine. */
.hero__text {
  min-width: 0;
}

.hero__eyebrow { margin-bottom: clamp(1.5rem, 3vw, 2.25rem); }

.hero h1 { margin-bottom: clamp(1.5rem, 3vw, 2.25rem); }
.hero h1 .line { display: block; }

.hero__sub {
  font-size: clamp(1.05rem, 1.5vw, 1.2rem);
  font-weight: 300;
  color: var(--ink-muted);
  max-width: 46ch;
  line-height: 1.65;
  margin-bottom: clamp(2rem, 4vw, 3rem);
}

.hero__cta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.85rem;
  margin-bottom: 2.5rem;
}

/* Carreau du studio : une plaque, un carrousel de 5 visuels.
   Ce bloc remplace les trois .hero__card, qui empilaient une photo portrait et
   deux vignettes en grille 2 colonnes. */
.hero__visual {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
}

/* Pas de backdrop-filter, volontairement. Le hÃ©ros fait jouer hero.mp4 en fond,
   et un backdrop-filter au-dessus d'une vidÃ©o en lecture fait chuter les
   images â€” le mÃªmeraisonnement qui coupe le verre du formulaire sous 900px.
   Un fond semi-opaque posÃ© sur le voile est ici indiscernable, et gratuit. */
.hero__glass {
  position: relative;
  padding: 0.85rem;
  background: rgba(255, 253, 251, 0.72);
  border: 1px solid var(--line);
  box-shadow: var(--shadow-lg);
}

/* Toutes les slides partagent la cellule 1/1 : pas de flux, donc passer de l'une
   Ã  l'autre ne dÃ©place rien et ne provoque pas de saut de mise en page. */
.hero__slides {
  display: grid;
  aspect-ratio: 780 / 672;
  overflow: hidden;
  background: var(--paper-sunk);
}
.hero__slide {
  grid-area: 1 / 1;
  margin: 0;
  opacity: 0;
  transition: opacity 0.6s var(--ease);
}
.hero__slide.is-active { opacity: 1; }
.hero__slide img { width: 100%; height: 100%; object-fit: cover; }

/* Un fondu en opacity, rien d'autre. Pas de Ken Burns : un transform: scale en
   boucle au-dessus d'une vidÃ©o qui joue force un re-raster Ã  chaque image.
   L'opacitÃ©, elle, est composÃ©e par le GPU. */
.hero__dots {
  display: flex;
  gap: 0.4rem;
  justify-content: flex-end;
  margin-top: 0.75rem;
}
.hero__dots button {
  width: 26px;
  height: 3px;
  padding: 0;
  border: 0;
  background: var(--line-strong);
  cursor: pointer;
  transition: background 0.3s var(--ease);
}
.hero__dots button:hover { background: var(--ink-faint); }
.hero__dots button[aria-current="true"] { background: var(--ink); }
/* Cible de focus Ã©largie, visible au clavier uniquement, sur le mÃªme bleu que
   les liens du site. */
.hero__dots button:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
}

.hero__badge {
  grid-column: 1 / -1;
  align-self: end;
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.9rem 1.1rem;
  background: var(--ink);
  color: var(--on-ink);
}
/* Halo pulsant. L'animation porte sur un pseudo-Ã©lÃ©ment et n'utilise que
   transform + opacity : animer `box-shadow` sur la pastille elle-mÃªme
   repeignait la zone Ã  chaque frame, en boucle infinie, pour toute la session. */
.hero__badge .pulse {
  position: relative;
  width: 7px; height: 7px;
  border-radius: 50%;
  background: #5bd98a;
  flex: none;
}
.hero__badge .pulse::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: #5bd98a;
  animation: pulse 2.4s var(--ease) infinite;
}
@keyframes pulse {
  70%  { transform: scale(2.6); opacity: 0; }
  100% { transform: scale(2.6); opacity: 0; }
}
.hero__badge span { font-family: var(--font-mono); font-size: 0.66rem;
  letter-spacing: 0.13em; text-transform: uppercase; }

/* Les marqueurs d'angle (.hero__card::after) disparaissent avec les trois
   cartes : ils n'ont plus de surface Ã  orner. */

/* --------------------------------------------------------------------------
   10. Bandeau dÃ©filant
   -------------------------------------------------------------------------- */
.marquee {
  background: var(--ink);
  color: var(--on-ink);
  padding-block: 1.15rem;
  overflow: hidden;
  border-block: 1px solid var(--ink-deep);
  --marquee-duration: 42s;
}
.marquee__track {
  display: flex;
  width: max-content;
  animation: marquee var(--marquee-duration) linear infinite;
}
.marquee:hover .marquee__track { animation-play-state: paused; }
.marquee__group {
  display: flex;
  align-items: center;
  flex: none;
}
.marquee__item {
  display: inline-flex;
  align-items: center;
  gap: 2.5rem;
  padding-right: 2.5rem;
  font-family: var(--font-display);
  font-size: clamp(1.15rem, 2.2vw, 1.75rem);
  white-space: nowrap;
  color: var(--on-ink);
}
.marquee__item::after {
  content: "";
  width: 5px; height: 5px;
  background: var(--accent-tint);
  border-radius: 50%;
  flex: none;
}
@keyframes marquee {
  to { transform: translateX(-50%); }
}

/* --------------------------------------------------------------------------
   11. Chiffres clÃ©s
   -------------------------------------------------------------------------- */
.stats {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
}
.stat {
  background: var(--paper);
  padding: clamp(1.5rem, 3vw, 2.25rem);
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}
.stat__num {
  font-family: var(--font-display);
  font-size: clamp(2.4rem, 4.5vw, 3.75rem);
  line-height: 1;
  color: var(--ink);
  letter-spacing: -0.02em;
}
.stat__num sup {
  font-size: 0.45em;
  color: var(--accent);
  top: -0.6em;
}
.stat__label {
  font-family: var(--font-mono);
  font-size: 0.66rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-muted);
}
/* Ã‰cart propre Ã  l'emplacement dans Â« Ã€ propos Â» : la grille .stats n'a pas de
   marge propre, parce qu'elle occupait jusqu'ici une section Ã  elle seule et
   tirait son espace du padding de .section. PosÃ©e sous la bio, elle a besoin
   d'un intervalle qui la sÃ©pare du bloc de texte. */
/* À propos : .section-head est dans la colonne de droite (7fr de 1240 px),
   pas au-dessus d'une grille pleine largeur. Sa marge basse est reglee pour
   ce second cas, jusqu'a 5rem : on la reduce, sinon elle ecarterait le premier
   paragraphe de la bio de toute la hauteur de l'ecran. */
.about__body .section-head { margin-bottom: 1.25rem; }

/* Le h2 global est a clamp(2.15rem, 5.4vw, 4.5rem), donc 72px sur grand ecran :
   c'est la taille des en-tetes pleine largeur. Dans la colonne de droite, large
   de 609px, « Plutot la clarte que la decoration » prenait 3 lignes a 72px et
   prenait toute la place visuelle. On le ramene a l'echelle d'une colonne, comme
   on a ramene le chapo de 52ch a 72ch plutot que l'inverse. */
.about__body .section-head h2 {
  font-size: clamp(1.6rem, 3vw, 2.3rem);
  max-width: 20ch;
}
/* Meme raison pour la citation : 2.5rem de marge haute et basse, plus 37.6px de
   corps, donnaient 211px pour une phrase qui en occupe 103. */
.about__body .about__quote {
  font-size: clamp(1.35rem, 2.4vw, 1.85rem);
  margin: 1.75rem 0;
}

/* Chiffres cles sous la photo, en 2 colonnes.
   La grille .stats n'a pas de marge propre parce qu'elle occupait jusqu'ici une
   section a elle seule et tirait son espace du padding de .section. Des qu'elle
   est posee sous la photo dans la colonne de gauche, il faut au contraire un
   intervalle discret : c'est une legende de la photo, pas un nouveau bloc.

   2 colonnes et non 4 : la colonne fait 481 px sur 1240 px de conteneur. En 4
   colonnes il ne resterait que 120 px de contenu par cellule et
   « Delai de réponse moyen » tiendrait sur 4 lignes.

   Tout est serre : nombres a 1.6rem au plus, labels a 0.52rem, marges internes
   reduites. Les cases suivent leur contenu (align-items stretch + gap 0.15rem) au
   lieu d'etre des blocs surdimensionnes, et align-content: start empeche la
   grille de s'etirer si une ligne est plus haute que l'autre. La photo est le
   sujet ; les chiffres sont une signature, pas un deuxieme hero. */
/* Enveloppe photo + chiffres. Sans regle propre elle n'existe que comme
   enfant de grille : c'est .split--flip qui donne ses proportions.
   min-width:0 autorise la reduction sous la largeur de la photo. */
.about__col {
  min-width: 0;
}

.about__stats {
  grid-template-columns: repeat(2, minmax(0, 1fr));
  align-content: start;
  margin-top: clamp(0.6rem, 1.2vw, 1rem);
}
.about__stats .stat {
  padding: clamp(0.55rem, 1.1vw, 0.8rem);
  gap: 0.15rem;
}
.about__stats .stat__num {
  font-size: clamp(1.25rem, 2.2vw, 1.6rem);
}
.about__stats .stat__label {
  font-size: 0.52rem;
  letter-spacing: 0.08em;
  line-height: 1.25;
}
/* --------------------------------------------------------------------------
   12. Services
   -------------------------------------------------------------------------- */
.services { border-top: 1px solid var(--line); }

.service {
  position: relative;
  display: grid;
  grid-template-columns: 4.5rem minmax(0, 1fr) auto;
  gap: clamp(1rem, 2.5vw, 2.5rem);
  align-items: start;
  padding-block: clamp(1.75rem, 3.5vw, 2.5rem);
  border-bottom: 1px solid var(--line);
  transition: background-color 0.4s var(--ease);
}
.service::before {
  content: "";
  position: absolute;
  left: calc(var(--gutter) * -1);
  right: calc(var(--gutter) * -1);
  top: 0; bottom: 0;
  background: var(--paper-raised);
  opacity: 0;
  transition: opacity 0.4s var(--ease);
  pointer-events: none;
}
.service:hover::before { opacity: 1; }
.service > * { position: relative; }

.service__num {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  color: var(--ink-faint);
  padding-top: 0.55rem;
  transition: color 0.3s var(--ease);
}
.service:hover .service__num { color: var(--accent-text); }

.service__title {
  font-family: var(--font-display);
  font-size: clamp(1.5rem, 3vw, 2.35rem);
  line-height: 1.08;
  color: var(--ink);
  margin-bottom: 0.6rem;
  letter-spacing: -0.015em;
}
.service__desc {
  color: var(--ink-muted);
  max-width: 58ch;
  font-weight: 300;
  font-size: 1rem;
}

.service__tags {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin-top: 1.1rem;
}
.tag {
  font-family: var(--font-mono);
  font-size: 0.62rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-muted);
  padding: 0.35rem 0.65rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  transition: border-color 0.3s var(--ease), color 0.3s var(--ease);
}
.service:hover .tag { border-color: var(--line-strong); color: var(--ink-body); }

.service__cta {
  align-self: center;
  width: 46px; height: 46px;
  flex: none;
  display: grid;
  place-items: center;
  border: 1px solid var(--line);
  border-radius: 50%;
  color: var(--ink);
  transition: background-color 0.35s var(--ease), color 0.35s var(--ease),
    border-color 0.35s var(--ease), transform 0.35s var(--ease-out);
}
.service:hover .service__cta {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--on-ink);
  transform: rotate(-45deg);
}

/* --------------------------------------------------------------------------
   13. Realisations

   File horizontale de vignettes, pas une grille de grands blocs : le client
   qui arrive sur cette page doit voir qu'il y a du travail derriere, pas
   decouvrir qu'il existe trois projets caches.

   choix de scroll-snap : proximity, pas mandatory. Les guides d'accessibilite
   sont explicites — mandatory devient un piege des qu'un contenu se glisse
   entre deux points d'ancrage, ce qui le rend inatteignable au clavier. On
   reserve mandatory aux parcours etape par etape. Ici on consulte librement.

   scroll-snap-align: start et non center : les cartes ont une legende
   alignee a gauche, et start est le seul point de snapping qui ne depend pas
   du arrondi du conteneur.

   La barre de defilement reste visible. La plupart des tutos la masquent avec
   scrollbar-width: none ; un audit d'accessibilite montre que c'est elle la
   qui previent qu'il y a du contenu a droite. Elle est donc coloree au lieu
   d'etre masquee. */
/* --------------------------------------------------------------------------
   Avis « contenu en cours de mise à jour »
   --------------------------------------------------------------------------
   Les vignettes de #realisations restent des placeholders tant que les études
   de cas n'existent pas. L'avis est un statut, pas une excuse : il disparait
   avec le dernier vrai projet, pas avant. */
.notice-update {
  display: flex;
  gap: clamp(.75rem, 1.4vw, 1.1rem);
  align-items: flex-start;
  margin-top: clamp(2rem, 4vw, 3rem);
  padding: clamp(1rem, 1.8vw, 1.4rem) clamp(1.1rem, 2vw, 1.6rem);
  border: 1px solid var(--line);
  border-left: 2px solid var(--accent-deep);
  background: var(--accent-wash);
}
.notice-update__icon {
  flex: none;
  width: 1.5rem;
  height: 1.5rem;
  color: var(--accent-deep);
}
.notice-update__body { display: grid; gap: .3rem; }
.notice-update__label {
  font-size: .68rem;
  font-weight: 600;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--accent-text);
}
.notice-update__text {
  font-size: .95rem;
  line-height: 1.55;
  color: var(--ink-body);
}
.notice-update__text strong { font-weight: 600; color: var(--ink); }

.work-rail {
  position: relative;
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: clamp(250px, 22vw, 330px);
  gap: clamp(1rem, 1.6vw, 1.5rem);
  margin: 0;
  padding: 0;
  list-style: none;

  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  scroll-padding-inline: 1px;
}

/* Pas de survol qui soulève ni qui zoome, et pas de fleche : les cartes ne
   mènent nulle part, donc rien ne doit laisser croire le contraire. */
.work {
  scroll-snap-align: start;
  background: var(--paper-raised);
  border: 1px solid var(--line);
  overflow: hidden;
}

.work__media {
  position: relative;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  background: var(--paper-sunk);
}
.work__media img {
  width: 100%; height: 100%;
  object-fit: cover;
}

.work-rail::-webkit-scrollbar { height: 9px; }
.work-rail::-webkit-scrollbar-track { background: var(--paper-sunk); }
.work-rail::-webkit-scrollbar-thumb {
  background: var(--line-strong);
  border-radius: 99px;
}

.work__body {
  padding: 0.95rem 1.1rem 1.15rem;
}
.work__title {
  font-family: var(--font-display);
  font-size: clamp(1.08rem, 1.3vw, 1.28rem);
  color: var(--ink);
  line-height: 1.15;
  margin-bottom: 0.35rem;
}
.work__meta {
  font-family: var(--font-mono);
  font-size: 0.62rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-muted);
}
@supports (height: 1lh) {
  .work__title { font-size: min(clamp(1.08rem, 1.3vw, 1.28rem), 1lh); }
}
   14. Vitrine motion design
   -------------------------------------------------------------------------- */
.motion {
  position: relative;
  overflow: hidden;
}
.motion__media {
  position: relative;
  aspect-ratio: 16 / 8;
  background: var(--ink-deep);
  overflow: hidden;
}
.motion__media video {
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
}
/* Voile : ne subsiste que pour lisser le bord gauche de la vidÃ©o. Le texte
   n'est plus posÃ© dessus â€” il vit dans la carte de verre â€” donc on a pu
   l'allÃ©ger de 0,82 Ã  0,42, sans quoi l'imageizonait sur son tiers gauche. */
.motion__scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(
    100deg,
    rgba(6, 22, 29, 0.42) 0%,
    rgba(6, 22, 29, 0.16) 45%,
    rgba(6, 22, 29, 0) 100%
  );
  pointer-events: none;
}
/* --------------------------------------------------------------------------
   Carte de texte : verre dÃ©poli, entrÃ©e par la gauche, refermable.
   --------------------------------------------------------------------------
   La carte n'est plus un calque qui recouvre toute la vidÃ©o (inset: 0) mais un
   panneau dÃ©tachÃ©, ancrÃ© Ã  gauche, pour que l'image reste lisible autour.

   Le fond sous le flou n'est pas dÃ©coratif : sans lui, le texte perd le
   contraste dÃ¨s que la vidÃ©o passe sur une zone claire.

   backdrop-filter reste sur desktop seulement (media query 900px) : posÃ© au-
   dessus d'une vidÃ©o en lecture, il force le navigateur Ã  recomposer Ã  chaque
   image, ce qui fait chuter le nombre d'images par seconde. C'est prÃ©cisÃ©ment
   la section qui doit mettre la vidÃ©o en valeur.
   -------------------------------------------------------------------------- */
.motion__panel {
  /* Distance de glissement, partagÃ©e par l'entrÃ©e et la sortie pour que les
     deux trajets soient rigoureusement identiques. */
  position: absolute;
  top: clamp(1.25rem, 4vw, 3rem);
  bottom: clamp(1.25rem, 4vw, 3rem);
  left: clamp(1.25rem, 4vw, 3.5rem);
  width: min(34rem, 72%);
  overflow-y: auto;
  overscroll-behavior: contain;

  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 1.15rem;
  /* Le padding du haut cÃ¨de la place au bouton de fermeture (32px + 0,75rem
     de dÃ©calage, plus 1px de bordure). */
  padding: clamp(2.75rem, 3.75vw, 3.25rem) clamp(1.75rem, 3vw, 2.5rem) clamp(1.75rem, 3vw, 2.5rem);

  color: var(--on-ink);
  background: rgba(6, 22, 29, 0.58);
  border: 1px solid var(--line-on-ink);
  border-radius: var(--radius);
  -webkit-backdrop-filter: blur(14px) saturate(125%);
  backdrop-filter: blur(14px) saturate(125%);
}
.motion__panel h3 { color: var(--on-ink); max-width: 16ch; }
.motion__panel p { color: var(--on-ink-muted); max-width: 46ch; font-weight: 300; }

/* Carte refermÃ©e. Deux points appris Ã  la dure ici :
   1. on passe par .motion__media pour atteindre 3 classes et battre
      [data-reveal].is-visible (2 classes) ;
   2. la valeur est Ã©crite en dur, PAS via var(--motion-slide) : dÃ©clarÃ©e plus
      haut dans la feuille, la variable Ã©tait ignorÃ©e par le navigateur et la
      fermeture ne produisait aucun effet (transform calculÃ© : none).
   calc(-100% - 3rem) sur une carte de 544px vaut -592px. */
.motion__media .motion__panel.is-closed {
  transform: translateX(calc(-100% - 3rem));
  /* Refermer plus vite que l'entrÃ©e : c'est une action de l'utilisateur, on
     veut la voir aboutir tout de suite. */
  transition: transform 0.35s var(--ease-out);
}

/* Bouton de fermeture : 32x32 Ã  l'affichage, pour rester discret sur la carte
   de verre. La zone cliquable reste Ã  44x44 grÃ¢ce au pseudo-Ã©lÃ©ment ci-dessous :
   rÃ©duire la cible rÃ©elle sous 44px rendrait le bouton difficile Ã  toucher sur
   mobile (cible tactile minimale WCAG 2.5.8), alors que seule la boÃ®te visible
   posait problÃ¨me. */
.motion__close {
  position: absolute;
  top: 0.75rem;
  right: 0.75rem;
  width: 32px;
  height: 32px;
  display: grid;
  place-items: center;
  border: 1px solid var(--line-on-ink);
  border-radius: var(--radius);
  background: rgba(6, 22, 29, 0.42);
  color: var(--on-ink);
  cursor: pointer;
  transition: background-color 0.3s var(--ease), color 0.3s var(--ease);
}
/* Zone de toucher de 44x44, centrÃ©e sur les 32px visibles. Invisible, mais
   cliquable. inset: -7px et non -6px : la bordure de 1px compte dans le
   border-box du bouton, -6px ne donnait que 42px de cible rÃ©elle. */
.motion__close::after {
  content: "";
  position: absolute;
  inset: -7px;
}
.motion__close:hover { background: rgba(6, 22, 29, 0.82); color: var(--accent-tint); }
.motion__close:focus-visible { outline: 2px solid var(--accent-tint); outline-offset: 2px; }
.motion__close svg { width: 13px; height: 13px; }

/* PoignÃ©e de rappel, collÃ©e au bord gauche. Elle n'existe que lorsque la carte
   est refermÃ©e : maintenue visible en permanence, elle resterait dans l'ordre
   de tabulation et serait annoncÃ©e par un lecteur d'Ã©cran alors qu'elle n'a
   rien Ã  afficher. D'oÃ¹ visibility plutÃ´t qu'une simple opacitÃ©. */
.motion__toggle {
  position: absolute;
  left: 0;
  top: 50%;
  z-index: 3;
  transform: translateY(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
  padding: 0.85rem 0.5rem;
  border: 1px solid var(--line-on-ink);
  border-left: 0;
  border-radius: 0 var(--radius) var(--radius) 0;
  background: rgba(6, 22, 29, 0.72);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  color: var(--on-ink);
  cursor: pointer;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 0.3s var(--ease), background-color 0.3s var(--ease),
              color 0.3s var(--ease);
}
.motion__media .motion__panel.is-closed ~ .motion__toggle {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
}
.motion__toggle:hover { background: rgba(6, 22, 29, 0.9); color: var(--accent-tint); }
.motion__toggle:focus-visible { outline: 2px solid var(--accent-tint); outline-offset: -2px; }
.motion__toggle svg { width: 14px; height: 14px; flex: none; }
.motion__toggle-label {
  writing-mode: vertical-rl;
  font-family: var(--font-mono);
  font-size: 0.6rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  white-space: nowrap;
}

.motion__facts {
  display: flex;
  flex-wrap: wrap;
  gap: 1.5rem 2.5rem;
  padding-top: 0.5rem;
}
.motion__fact { display: flex; flex-direction: column; gap: 0.2rem; }
.motion__fact b {
  font-family: var(--font-display);
  font-size: 1.6rem;
  font-weight: 400;
  color: var(--accent-tint);
  line-height: 1;
}
.motion__fact span {
  font-family: var(--font-mono);
  font-size: 0.62rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--on-ink-muted);
}

/* Bouton lecture */
.play-btn {
  position: absolute;
  right: clamp(1.25rem, 4vw, 3rem);
  bottom: clamp(1.25rem, 4vw, 3rem);
  width: 74px; height: 74px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  border: 1px solid var(--line-on-ink);
  color: var(--on-ink);
  background: rgba(247, 243, 238, 0.08);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  transition: background-color 0.4s var(--ease), color 0.4s var(--ease),
    transform 0.4s var(--ease-out);
}
.play-btn:hover {
  background: var(--accent-deep);
  border-color: var(--accent-deep);
  color: #fff;
  transform: scale(1.06);
}
.play-btn svg { width: 1.5rem; height: 1.5rem; margin-left: 3px; }
.play-btn .icon-pause { display: none; }
.play-btn.is-playing .icon-play { display: none; }
.play-btn.is-playing .icon-pause { display: block; margin-left: 0; }

/* --------------------------------------------------------------------------
   15. Processus
   -------------------------------------------------------------------------- */
.process { counter-reset: step; }
.step {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: clamp(1rem, 2.5vw, 2rem);
  padding-block: clamp(1.5rem, 3vw, 2.25rem);
  border-top: 1px solid var(--line);
  position: relative;
}
.step:last-child { border-bottom: 1px solid var(--line); }
.step__num {
  counter-increment: step;
  font-family: var(--font-display);
  font-size: clamp(2rem, 3.5vw, 2.75rem);
  line-height: 1;
  color: var(--accent-ink);
  min-width: 2.5ch;
}
.step__num::before { content: "0" counter(step); }
.step__title {
  font-family: var(--font-display);
  font-size: clamp(1.35rem, 2.4vw, 1.9rem);
  color: var(--ink);
  margin-bottom: 0.45rem;
  line-height: 1.1;
}
.step__desc { color: var(--ink-muted); font-weight: 300; max-width: 54ch; }
.step__meta {
  margin-top: 0.85rem;
  font-family: var(--font-mono);
  font-size: 0.64rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

/* --------------------------------------------------------------------------
   16. Ã€ propos
   -------------------------------------------------------------------------- */
.about__media { position: relative; }
.about__media img {
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  filter: grayscale(1) contrast(1.05);
  transition: filter 0.7s var(--ease);
}
.about__media:hover img { filter: none; }
.about__media::before {
  content: "";
  position: absolute;
  inset: 18px -18px -18px 18px;
  border: 1px solid var(--accent);
  z-index: -1;
}
.about__quote {
  font-family: var(--font-display);
  font-size: clamp(1.5rem, 3vw, 2.35rem);
  line-height: 1.16;
  color: var(--ink);
  font-style: italic;
  margin: 2.5rem 0;
  padding-left: 1.5rem;
  border-left: 2px solid var(--accent);
}
.about__body p + p { margin-top: 1.1rem; }
.about__body p { color: var(--ink-muted); font-weight: 300; }

.signature {
  margin-top: 2.5rem;
  padding-top: 1.75rem;
  border-top: 1px solid var(--line);
  display: flex;
  align-items: center;
  gap: 1rem;
}
.signature__name {
  font-family: var(--font-display);
  font-size: 1.5rem;
  font-style: italic;
  color: var(--ink);
  line-height: 1.1;
}
.signature__role {
  font-family: var(--font-mono);
  font-size: 0.64rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-muted);
}

/* --------------------------------------------------------------------------
   17. Marketing / SEO
   -------------------------------------------------------------------------- */
.checklist { display: grid; gap: 0; }
.checklist li {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 1rem;
  align-items: start;
  padding-block: 1.15rem;
  border-bottom: 1px solid var(--line-soft);
}
.checklist li:first-child { border-top: 1px solid var(--line-soft); }
.checklist li::before {
  content: "";
  width: 7px; height: 7px;
  margin-top: 0.7rem;
  background: var(--accent);
  flex: none;
  border-radius: 50%;
}
.checklist b {
  display: block;
  font-weight: 600;
  color: var(--ink);
  margin-bottom: 0.15rem;
}
.checklist span { color: var(--ink-muted); font-weight: 300; font-size: 0.95rem; }

/* --------------------------------------------------------------------------
   19. Contact
   -------------------------------------------------------------------------- */
.contact-grid {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  gap: clamp(2rem, 5vw, 4.5rem);
  align-items: start;
  /* Passe au-dessus de .contact__bg et .contact__veil. */
  position: relative;
  z-index: 2;
}

/* Colonne de gauche de #contact. .contact-grid est en align-items:start,
   donc les deux colonnes s'alignent deja en haut ; align-self l'ecrit pour
   qu'un futur align-items:center ne la fasse pas flotter. */
.contact__aside {
  align-self: start;
  min-width: 0;
}

.contact-list { display: grid; gap: 0; margin-top: 2rem; }
.contact-list__row {
  display: grid;
  grid-template-columns: 7.5rem minmax(0, 1fr);
  gap: 1rem;
  padding-block: 1.1rem;
  border-top: 1px solid var(--line);
  align-items: baseline;
}
.contact-list__row:last-child { border-bottom: 1px solid var(--line); }
.contact-list dt {
  font-family: var(--font-mono);
  font-size: 0.65rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  /* --ink-muted et non --ink-faint : mesurÃ© sur le pire fond rÃ©el, --ink-faint
     tombait Ã  4,00:1 pour un seuil de 4,5. --ink-muted donne 5,69:1. Ce sont
     des micro-labels en capitales : les foncer ne change rien Ã  la lecture. */
  color: var(--ink-muted);
}
.contact-list dd { margin: 0; }
.contact-list a,
.contact-list span { color: var(--ink); font-weight: 400; }
.contact-list a {
  border-bottom: 1px solid var(--line-strong);
  transition: color 0.3s var(--ease), border-color 0.3s var(--ease);
}
.contact-list a:hover { color: var(--accent-deep); border-color: var(--accent); }

.copy-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  margin-left: 0.5rem;
  color: var(--ink-muted);
  vertical-align: middle;
  transition: color 0.3s var(--ease);
}
.copy-btn:hover { color: var(--accent-deep); }
.copy-btn svg { width: 0.85rem; height: 0.85rem; }

/* Formulaire */
.form {
  background: var(--paper-raised);
  border: 1px solid var(--line);
  padding: clamp(1.5rem, 3vw, 2rem);
  box-shadow: var(--shadow-md);
}
/* DÃ©cor vidÃ©o de la colonne Â« Faisons Ã©quipe Â».

   Trois budgets de contraste coexistent dans cette colonne, et c'est eux qui
   dictent la forme du dÃ©cor â€” pas le goÃ»t :

   1. .contact-list dt, 10,4 px, --ink-faint : 4,61:1 sur le fond nu. Il ne
      reste aucune marge, donc la vidÃ©o ne passe JAMAIS derriÃ¨re. Le masque
      s'Ã©teint Ã  36,2 % de la colonne, la liste commence Ã  40,8 %.
   2. Le paragraphe d'intro, 17 px, --ink-muted : 6,87:1 sur le fond nu. Il
      peut descendre Ã  4,5:1, soit un fond Ã  L >= 0,516 â€” mais sur un plan
      sombre cela interdit de descendre plus bas que ~210 sur un papier Ã  239.
      C'est la contrainte qui rendait la vidÃ©o invisible : Ã  0,2 d'opacitÃ© sous
      un voile de papier, il ne restait que 13 % du clip, donc un aplat de 10 %.
   3. Le h3, 34,4 px, --ink : 12,96:1, et le seuil du grand texte est 3:1.
      Budget quasi illimitÃ©.

   D'oÃ¹ le dÃ©gradÃ© ci-dessous : la vidÃ©o est rÃ©elle lÃ  oÃ¹ il n'y a que le h3,
   et le paragraphe reste sur un fond Ã  peine teintÃ©. */
/* La colonne n'a plus besoin d'Ãªtre positionnÃ©e : le dÃ©cor est remontÃ© au
   niveau de la section, sur toute la largeur. */

/* VidÃ©o de fond de la section Contact, sur toute la largeur.

   Ordre d'empilement, du fond vers l'avant â€” strictement le mÃªme que le
   hÃ©ros, et pour la mÃªme raison :

     0  .contact__bg      la vidÃ©o, inset:0, toute la section
     1  .contact__veil    le voile de lisibilitÃ©
     2  .contact-grid     le texte et le formulaire

   Les z-index sont explicites et distincts : Ã  valeur Ã©gale l'ordre de
   peinture suit l'ordre du DOM, ce qui rendrait le rÃ©sultat implicite.

   Pourquoi un voile aussi dense : la colonne de gauche n'est pas du grand
   texte. Elle contient .contact-list dt, 10,4 px, --ink-faint, qui est Ã 
   4,61:1 sur le papier nu â€” la vidÃ©o ne peut donc pas passer derriÃ¨re. Le
   voile s'Ã©claircit vers la droite, oÃ¹ la plaque de verre du formulaire
   apporte sa propre clarification : c'est lÃ  que le plan se voit. */
.contact__bg {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
}

.contact__bg-video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* LÃ©ger dÃ©bord, comme .hero__bg-video : Ã©vite la couture d'un demi-pixel
     sur les Ã©crans larges. */
  transform: scale(1.02);
  /* Le clip est sombre (luminance moyenne 25 %). Sans cette remontÃ©e, il
     tomberait sous les seuils du texte qui le surplombe. */
  filter: brightness(1.35) saturate(0.85);
}

/* Sous 900px le dÃ©cor est retirÃ© du rendu, pas seulement de la lecture : le
   Â« rien ne change sous 900px Â» est alors vrai au pixel prÃ¨s, et le dÃ©bord
   horizontal disparaÃ®t avec lui. */
@media (max-width: 900px) {
  .contact__bg,
  .contact__veil { display: none; }
}

/* Marges verticales de la section. Deux raisons de les rÃ©duire ici plutÃ´t que
   via --section-y, qui reste intact pour les sept autres sections :

   1. Contact est la seule section dont dÃ©cor est en fond perdu sur toute la
      largeur. Ses marges ne sont pas du vide : ce sont les bandes oÃ¹ la vidÃ©o
      respire avant le premier texte et aprÃ¨s le formulaire.
   2. Contact est suivie de .cta-band, qui applique lui aussi --section-y. Les
      deux s'additionnaient : 144px ici plus 144px lÃ  faisaient 288px de vide
      entre le formulaire et le bandeau.

   Haut 72px -> 36px, bas 63px -> 30px. Les marges de contact sont desormais du
   MesurÃ© Ã  1440px : section 1140px -> 1046px. */
#contact {
  padding-top: clamp(1.25rem, 2vw, 1.5rem);
  padding-bottom: clamp(1.2rem, 2.15vw, 1.9rem);
}

/* 56px sous l'en-tete de contact s'ajoutaient au padding de la section et
   a celui de la section precedente : 169px separaient le dernier contenu de
   #visibilite du titre « Soyons libres de parler ». La section paraissait
   commencer ailleurs. 32px laisse l'en-tete respirer sans ouvrir de vide. */
#contact .section-head {
  margin-bottom: clamp(1.5rem, 2.5vw, 2rem);
}

/* Voile de lisibilitÃ©, couche sÃ©parÃ©e comme .hero__veil.

   Dense Ã  gauche sous la colonne de texte, il s'Ã©claircit vers la droite oÃ¹
   la plaque de verre apporte sa propre clarification : c'est lÃ  que le plan
   se voit. Le second dÃ©gradÃ© referme le haut de la section pour que la
   bordure avec la section prÃ©cÃ©dente reste nette.

   Un voile sombre donnerait une section sombre et invaliderait toute la table
   de contrastes du design system â€” mÃªme raison que pour .hero__veil.

   La colonne de gauche ne bouge pas de couleur : 17 px en graisse 300 est du
   petit texte (seuil 4,5:1) et .contact-list dt, 10,4 px, est Ã  4,61:1 sur le
   papier nu. Aucune valeur de voile ne peut faire passer la vidÃ©o derriÃ¨re
   ces deux Ã©lÃ©ments sans les effacer, donc c'est la luminance qui est
   rÃ©servÃ©e au texte, pas le texte qui s'assombrit. */
.contact__veil {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background:
    linear-gradient(
      100deg,
      var(--paper-sunk) 0%,
      rgba(239, 232, 224, 0.96) 24%,
      rgba(239, 232, 224, 0.9) 44%,
      rgba(239, 232, 224, 0.62) 66%,
      rgba(239, 232, 224, 0.45) 100%
    ),
    linear-gradient(
      to bottom,
      var(--paper-sunk) 0%,
      rgba(239, 232, 224, 0.72) 20%,
      rgba(239, 232, 224, 0.28) 33%,
      rgba(239, 232, 224, 0) 44%
    );
}

/* Formulaire : plaque de verre.

   Desktop seulement pour l'instant. Le verre au-dessus d'une vidÃ©o en lecture
   oblige le navigateur Ã  recomposer Ã  chaque image, ce qui fait chuter le
   nombre d'images par seconde â€” c'est dÃ©jÃ  la rÃ¨gle appliquÃ©e au panneau
   Motion, et la raison pour laquelle il perd son backdrop-filter sous
   900px. Le comportement sous 900px reste donc celui d'aujourd'hui
   (fond plein) : rien Ã  dÃ©faire le jour oÃ¹ la dÃ©cision sera prise. */
@media (min-width: 901px) {
  .form {
    background: rgba(255, 253, 251, 0.58);
    -webkit-backdrop-filter: blur(18px) saturate(140%);
    backdrop-filter: blur(18px) saturate(140%);
    /* Le bord du verre est plus clair que son fond : c'est l'arÃªte qui
       attrape la lumiÃ¨re, pas un contour sombre. */
    border: 1px solid rgba(255, 255, 255, 0.6);
    box-shadow: var(--shadow-lg), inset 0 1px 0 rgba(255, 255, 255, 0.9);
  }
}

.form__row {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1.25rem;
}
.field { position: relative; margin-bottom: 1rem; }
.field__label {
  display: block;
  font-family: var(--font-mono);
  font-size: 0.64rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink);
  margin-bottom: 0.35rem;
}
/* --ink et non --ink-muted : le libellÃ© est Ã  10,2 px, donc petit texte. Sur le
   pire fond rÃ©el mesurÃ© (rgb 131,141,140, la plaque de verre au-dessus de la
   vidÃ©o), --ink-muted tombait Ã  2,45:1 pour un seuil de 4,5. --ink remonte Ã 
   4,82:1 sans avoir Ã  Ã©paissir la plaque de verre, donc sans effacer la vidÃ©o
   que la plaque est censÃ©e laisser voir. */
.field__label .req { color: var(--accent); margin-left: 0.15rem; }

.field input,
.field textarea,
.field select {
  width: 100%;
  padding: 0.85rem 0;
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--line-strong);
  color: var(--ink);
  font-size: 1rem;
  transition: border-color 0.3s var(--ease);
  border-radius: 0;
}
.field textarea { resize: vertical; min-height: 5rem; line-height: 1.6; }
.field select {
  appearance: none;
  -webkit-appearance: none;
  cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%234e636c' stroke-width='1.5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 2px center;
  background-size: 11px;
  padding-right: 1.75rem;
}
.field input::placeholder,
.field textarea::placeholder { color: var(--ink-faint); }

.field input:focus,
.field textarea:focus,
.field select:focus {
  outline: none;
  border-bottom-color: var(--accent-deep);
  box-shadow: none;
}
.field input:focus-visible,
.field textarea:focus-visible,
.field select:focus-visible { outline: none; }

.field--error input,
.field--error textarea,
.field--error select { border-bottom-color: #c0392b; }

.field__error {
  display: block;
  font-size: 0.78rem;
  color: #b02a1c;
  margin-top: 0.25rem;
  min-height: 1em;
}

/* Case Ã  cocher */
.check { display: flex; gap: 0.75rem; align-items: flex-start; margin-bottom: 1.25rem; }
.check input { width: 1.05rem; height: 1.05rem; margin-top: 0.2rem; accent-color: var(--accent-deep); flex: none; }
.check label { font-size: 0.85rem; color: var(--ink-muted); font-weight: 300; }
.check label a { text-decoration: underline; text-underline-offset: 2px; }

.honeypot {
  position: absolute !important;
  left: -9999px !important;
  width: 1px; height: 1px;
  overflow: hidden;
}

.form__status {
  margin-top: 1.25rem;
  padding: 0.9rem 1.1rem;
  font-size: 0.9rem;
  border: 1px solid;
  display: none;
}
.form__status.is-visible { display: block; }
.form__status.is-ok {
  background: rgba(91, 217, 138, 0.1);
  border-color: rgba(45, 138, 78, 0.35);
  color: #24693f;
}
.form__status.is-err {
  background: rgba(192, 57, 43, 0.08);
  border-color: rgba(192, 57, 43, 0.3);
  color: #9c2b1c;
}
.form__status a { text-decoration: underline; font-weight: 500; }

.btn.is-loading { pointer-events: none; opacity: 0.7; }

/* --------------------------------------------------------------------------
   20. Pied de page
   -------------------------------------------------------------------------- */
.footer {
  background: var(--ink-deep);
  color: var(--on-ink-muted);
  padding-block: clamp(3rem, 6vw, 5rem) 2rem;
  font-size: 0.925rem;
}
.footer__grid {
  display: grid;
  grid-template-columns: minmax(0, 1.6fr) repeat(3, minmax(0, 1fr));
  gap: clamp(2rem, 4vw, 3.5rem);
  padding-bottom: clamp(2.5rem, 5vw, 4rem);
}
.footer .brand { color: var(--on-ink); margin-bottom: 1.25rem; }
.footer .brand__sub { color: var(--on-ink-muted); }
.footer__blurb { max-width: 34ch; font-weight: 300; }

.footer__coltitle {
  font-family: var(--font-mono);
  font-size: 0.65rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--on-ink);
  margin-bottom: 1.15rem;
}
.footer ul { display: grid; gap: 0.6rem; }
.footer a { transition: color 0.3s var(--ease); }
.footer a:hover { color: var(--accent-tint); }

.socials { display: flex; flex-wrap: wrap; gap: 0.55rem; margin-top: 1.75rem; }
.social {
  width: 40px; height: 40px;
  display: grid;
  place-items: center;
  border: 1px solid var(--line-on-ink);
  color: var(--on-ink);
  transition: background-color 0.3s var(--ease), color 0.3s var(--ease),
    border-color 0.3s var(--ease), transform 0.3s var(--ease-out);
}
.social:hover {
  background: var(--accent-deep);
  border-color: var(--accent-deep);
  color: #fff;
  transform: translateY(-3px);
}
.social svg { width: 16px; height: 16px; }

.footer__bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1.25rem;
  padding-top: 1.75rem;
  border-top: 1px solid var(--line-on-ink);
  font-family: var(--font-mono);
  font-size: 0.66rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}
.footer__legal { display: flex; flex-wrap: wrap; gap: 1.5rem; }

.to-top {
  width: 44px; height: 44px;
  display: grid;
  place-items: center;
  border: 1px solid var(--line-on-ink);
  color: var(--on-ink);
  transition: background-color 0.3s var(--ease), color 0.3s var(--ease);
}
.to-top:hover { background: var(--on-ink); color: var(--ink); }
.to-top svg { width: 14px; height: 14px; }

/* --------------------------------------------------------------------------
   21. Animations d'apparition
   -------------------------------------------------------------------------- */
[data-reveal] {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity 0.8s var(--ease-out), transform 0.8s var(--ease-out);
  transition-delay: var(--reveal-delay, 0s);
}
[data-reveal].is-visible { opacity: 1; transform: none; }

[data-reveal="fade"] { transform: none; }
[data-reveal="left"] { transform: translateX(-26px); }
/* La carte Motion Design entre depuis le bord gauche, pas de 26 px : ici le
   glissement doit parcourir toute la largeur de la carte pour que la vidÃ©o
   se dÃ©voile d'un bloc. La distance est calc(-100% - 3rem), identique Ã  celle
   de .is-closed, pour que l'entrÃ©e et la sortie coÃ¯ncident.
   On ne gate pas l'opacitÃ© : le texte doit rester lisible mÃªme si le JS
   Ã©choue, et translateX(-100%) le sort dÃ©jÃ  de l'Ã©cran. */
[data-reveal="panel"] { transform: translateX(calc(-100% - 3rem)); opacity: 1; }
[data-reveal="right"] { transform: translateX(26px); }
[data-reveal="scale"] {
  /* L'Ã©lÃ©ment qui porte ce reveal est l'image LCP de la page d'accueil.
     On garde l'animation de scale (composÃ©e sur le GPU) mais on ne gate plus
     l'opacitÃ© : un LCP dÃ©pendant d'une opacitÃ© 0 -> 1 pilotÃ©e par JS fait
     exploser le Render Delay, et casse l'affichage si le JS Ã©choue. */
  opacity: 1;
  transform: scale(0.96);
}

/* --------------------------------------------------------------------------
   22. Pages lÃ©gales
   -------------------------------------------------------------------------- */
.page-head {
  padding-top: clamp(8.5rem, 15vw, 11rem);
  padding-bottom: clamp(2rem, 4vw, 3rem);
  border-bottom: 1px solid var(--line);
}
.page-head h1 { font-size: clamp(2.5rem, 7vw, 5rem); margin-block: 1.25rem; }
.page-head .lead { max-width: 60ch; }

.prose { padding-block: clamp(3rem, 6vw, 5rem); }
.prose h2 {
  font-size: clamp(1.5rem, 2.6vw, 2rem);
  margin-top: 3rem;
  margin-bottom: 1rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--line);
}
.prose h2:first-child { margin-top: 0; border-top: 0; padding-top: 0; }
.prose h3 {
  font-size: clamp(1.2rem, 1.8vw, 1.4rem);
  margin-top: 2rem;
  margin-bottom: 0.6rem;
}
.prose p,
.prose ul,
.prose ol { color: var(--ink-muted); font-weight: 300; }
.prose p + p { margin-top: 1rem; }
.prose ul,
.prose ol { padding-left: 1.25rem; margin-block: 1rem; }
.prose li { margin-bottom: 0.5rem; }
.prose li::marker { color: var(--accent); }
.prose a { color: var(--accent-deep); text-decoration: underline; text-underline-offset: 3px; }
.prose a:hover { color: var(--accent); }
.prose strong { color: var(--ink); font-weight: 600; }
.prose dl { margin-block: 1rem; }
.prose dt {
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin-top: 1.25rem;
}
.prose dd { margin: 0.25rem 0 0; color: var(--ink-muted); font-weight: 300; }
.prose__meta {
  font-family: var(--font-mono);
  font-size: 0.66rem;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin-bottom: 2.5rem;
}

/* Bandeau CTA de fin de page */
.cta-band {
  position: relative;
  overflow: hidden;
}
.cta-band::after {
  content: "";
  position: absolute;
  bottom: -40%;
  right: -8%;
  width: min(560px, 80vw);
  aspect-ratio: 1;
  background: radial-gradient(circle, rgba(255, 180, 126, 0.18), transparent 66%);
  pointer-events: none;
}
.cta-band__inner {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: clamp(2rem, 5vw, 4rem);
  align-items: center;
}
.cta-band h2 { max-width: 18ch; }

/* --------------------------------------------------------------------------
   23. Barre de progression
   -------------------------------------------------------------------------- */
.progress {
  position: fixed;
  top: 0; left: 0;
  z-index: 950;
  height: 2px;
  width: 100%;
  transform: scaleX(0);
  transform-origin: left;
  background: var(--accent);
  pointer-events: none;
}

/* --------------------------------------------------------------------------
   24. Responsive
   -------------------------------------------------------------------------- */
@media (max-width: 1100px) {
  .hero__grid { grid-template-columns: minmax(0, 1fr); }
  .hero__visual { max-width: 30rem; }
  .contact-grid { grid-template-columns: minmax(0, 1fr); }
  .footer__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .footer__brand { grid-column: 1 / -1; }
  .section-head--row { grid-template-columns: minmax(0, 1fr); align-items: start; }
}

@media (max-width: 900px) {
  .nav,
  .header__actions .btn { display: none; }
  .nav-toggle { display: grid; }
  .split,
  .split--flip { grid-template-columns: minmax(0, 1fr); gap: 3rem; }
  .split--flip .split__media { order: -1; }
  .stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .service { grid-template-columns: 3rem minmax(0, 1fr) auto; }
  .cta-band__inner { grid-template-columns: minmax(0, 1fr); }
  .motion__media { aspect-ratio: 4 / 3; }
  /* Sous 900px la carte repasse dans le flux, au-dessus de la vidÃ©o. Le verre
     tombe (backdrop-filter au-dessus d'une vidÃ©o en lecture fait chuter les
     images par seconde) mais la fermeture reste possible : elle sert Ã  dÃ©gager
     la carte pour regarder la vidÃ©o en entier. */
  .motion__panel {
    position: relative;
    top: auto; bottom: auto; left: auto;
    width: auto; max-width: none;
    overflow: visible;
    /* Le padding haut laisse la place au bouton de fermeture, toujours en
       position absolue : sans cela il chevauche le sur-titre Â« 03 Â». */
    padding: 2.75rem 0 0;
    background: var(--ink-deep);
    border: 0;
    border-radius: 0;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }
  /* RefermÃ©e en flux, la carte doit LIBÃ‰RER sa hauteur, pas se dÃ©calager : un
     transform laisse la place rÃ©servÃ©e, la vidÃ©o ne remonte pas. On replie donc
     la boÃ®te (max-height) et on masque le dÃ©bordement. */
  .motion__media .motion__panel.is-closed {
    transform: none;
    max-height: 0;
    padding-top: 0;
    opacity: 0;
    pointer-events: none;
    overflow: hidden;
    transition: max-height 0.35s var(--ease-out), opacity 0.25s var(--ease-out),
                padding-top 0.35s var(--ease-out);
  }
  /* La poignÃ©e reste donc affichÃ©e sur mobile â€” c'est le seul moyen de rouvrir.
     Elle redevient un bouton en flux sous la carte, pas un onglet latÃ©ral. */
  .motion__toggle {
    position: static;
    transform: none;
    display: none;
    align-self: flex-start;
    flex-direction: row;
    border-left: 1px solid var(--line-on-ink);
    border-radius: var(--radius);
    padding: 0.6rem 1rem;
  }
  .motion__media .motion__panel.is-closed ~ .motion__toggle { display: flex; }
  .motion__toggle-label { writing-mode: horizontal-tb; }
  /* Le bouton ne doit pas disparaÃ®tre : sans lui, la vidÃ©o en autoplay boucle
     n'a aucun moyen d'Ãªtre mise en pause (WCAG 2.2.2). En dessous de 900px le
     panneau n'est plus un calque superposÃ©, donc on repasse le bouton dans le
     flux, centrÃ© sous la vidÃ©o. Le sÃ©lecteur adjacent doit englober la poignÃ©e
     interposÃ©e, sans quoi le bouton resterait en position absolue. */
  .motion__panel ~ .play-btn {
    position: static;
    display: grid;
    margin: 1.25rem auto 0;
  }
  .motion { display: flex; flex-direction: column; }
  /* Plus aucune regle .work ici : la grille est une file horizontale, et un
     grid-column: span 12 la casserait (elle ne s'applique plus qu'a un flux en
     colonnes). Le seul ajustement mobile est la largeur des cartes, traitee par
     clamp() dans .work-rail. */

  /* VidÃ©o de fond du hÃ©ros : jamais sur mobile. Choix assumÃ© â€” 1,5 Ã  2 Mo pour
     une image de fond dÃ©corative ne vaut pas la data d'un visiteur en 4G. Le
     hÃ©ros retombe sur --paper, l'accent et le grain, donc il garde exactement
     son rendu texte. Le poster (85 Ko) ne part pas non plus : il est en
     data-poster et main.js ne le pose qu'au-dessus de 900px, parce que Chrome
     rÃ©cupÃ¨re un attribut poster mÃªme sur une balise en display:none. */
  .hero__bg,
  .hero__veil { display: none; }
}

@media (max-width: 620px) {
  body { font-size: 1rem; }
  .stats { grid-template-columns: minmax(0, 1fr); }
  .form__row { grid-template-columns: minmax(0, 1fr); gap: 0; }
  .service {
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 0.75rem 1rem;
  }
  .service__num { grid-column: 1 / -1; padding-top: 0; }
  .service__cta { align-self: end; }
  .footer__grid { grid-template-columns: minmax(0, 1fr); }
  .contact-list__row { grid-template-columns: minmax(0, 1fr); gap: 0.25rem; }
  .footer__bar { flex-direction: column; align-items: flex-start; }
  .play-btn { width: 58px; height: 58px; }
  .about__media::before { inset: 12px -12px -12px 12px; }
}

/* --------------------------------------------------------------------------
   25. PrÃ©fÃ©rences systÃ¨me
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
    [data-reveal] { opacity: 1 !important; transform: none !important; }
    /* ConsÃ©quence Ã  traiter : le !important ci-dessus Ã©crase le glissement de
       .motion__panel.is-closed (spÃ©cificitÃ© 3 classes, mais un !important
       l'emporte toujours). Sans cette rÃ¨gle, le bouton de fermeture ne ferait
       rien du tout pour ces visiteurs â€” le texte resterait collÃ© sur la vidÃ©o.
       On referme donc sans dÃ©placer, par l'opacitÃ© et la visibilitÃ©. */
    .motion__panel.is-closed {
      transform: none !important;
      opacity: 0 !important;
      visibility: hidden;
    }
    .marquee__track { animation: none; }
  /* La vidÃ©o de fond s'arrÃªte d'elle-mÃªme : main.js ne l'appelle jamais en
     reduced-motion, et preload="none" garantit qu'aucun octet n'a Ã©tÃ©
     tÃ©lÃ©chargÃ©. Le poster reste affichÃ©, ce qui est autorisÃ© â€” ce qui est
     interdit en reduced-motion, c'est le mouvement, pas l'image fixe. */
  .hero__bg-video { display: none; }
  .hero__bg { background: var(--paper) url("../img/hero-poster.jpg") center / cover no-repeat; }
}

@media print {
  .header, .mobile-menu, .marquee, .progress, .footer, .skip-link { display: none !important; }
  body { background: #fff; color: #000; font-size: 11pt; }
  .section { padding-block: 1.5rem; }
  a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 9pt; color: #555; }
}