/* =========================================================
   badis.builds — feuille de style
   Version claire, révisée après revue du rendu réel (27/07/2026).

   Ce qui a été corrigé par rapport à la première version claire :
   - le bord gauche ne bouge plus : toutes les sections partagent le même
     conteneur, la largeur de lecture est bridée sur le texte lui-même
   - les vides entre sections étaient dus au hasard des hauteurs de bloc,
     ils sont maintenant fixés
   - le blanc était quasi pur donc il ne se lisait pas comme un choix
   - la palette est désormais extraite des frames de la vidéo (voir plus bas)

   Aucune couleur en dur hors de :root. Aucun style inline dans le HTML.
   ========================================================= */

/* ---------- Palette, extraite de la vidéo ----------
   Les 97 frames ont été échantillonnées (bords, mur, dalle, halo de la
   ligne) : tout se situe entre 195° et 216° de teinte, saturation 6 à 31 %.
   La vidéo est donc entièrement en bleu-gris froid. Toute la palette est
   construite sur cette teinte unique, 207°, en ne faisant varier que la
   clarté et la saturation. Le fond de la page est le halo de la ligne
   éclairci ; l'encre est le noir du mur ; l'accent est le bleu acier de la
   lumière assombri jusqu'à être lisible sur fond clair.
   Changer --hue suffirait à tout déplacer si la vidéo changeait un jour. */

:root {
  --color-bg: #f3f5f7;          /* le halo de la ligne, éclairci */
  --color-raised: #fafbfc;
  --color-ink: #191e22;         /* le noir du mur, pas du noir pur */
  --color-text: #191e22;
  --color-text-dim: #545e66;    /* le gris du béton — 6.1:1 sur le fond */
  /* Ces deux valeurs ont été assombries le 29/07 après calcul des contrastes :
     #7b868e ne donnait que 3,41:1 (sous le seuil AA de 4,5:1) alors qu'il servait
     à du texte de 12-14px, et #bac3ca tombait à 1,64:1 sur la bordure des
     boutons flèches du carrousel — ils étaient quasi invisibles. Même teinte
     (207°), seule la clarté a bougé. */
  --color-text-faint: #646e76;  /* 4,76:1 — surtitres et méta */
  --color-line: #e0e5e9;
  --color-line-strong: #818b94; /* 3,17:1 — contours de contrôles interactifs */
  --color-accent: #284862;      /* le bleu acier de la lumière, assombri */

  /* Anneau de focus : variable héritée, pour pouvoir l'éclaircir dans la zone
     sombre où l'accent ne fait que 1,92:1 (focus clavier invisible). */
  --color-focus: #284862;

  /* Zone sombre de la séquence : reprise des vraies valeurs des frames,
     pour que la jonction page / vidéo ne se voie pas. */
  --color-dark-bg: #121516;
  --color-dark-text: #eef3f6;
  --color-dark-dim: #a1a9af;
  --color-dark-line: #2e3438;

  /* Deux familles auto-hébergées (aucun appel à Google Fonts — RGPD).
     Instrument Serif pour les titres : un serif à fort contraste, en 400
     uniquement, qui se lit comme un choix. Geist pour le texte courant et
     l'interface. Les deux en SIL Open Font License 1.1, usage commercial
     compris (vérifié sur l'API Fontsource le 29/07/2026). */
  --font-display: "Instrument Serif", Georgia, "Times New Roman", serif;
  --font-sans: "Geist", -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;

  /* Deux rayons distincts au lieu d'un seul partout : les contrôles sont
     arrondis, les images restent presque nettes. La variation est ce qui
     distingue une hiérarchie voulue d'un réglage global. */
  --radius: 6px;                /* boutons et contrôles */
  --radius-media: 2px;          /* captures et portrait */
  --pad-page: 32px;
  --max-width: 1120px;
  --read: 62ch;                 /* largeur de lecture : bride le texte, pas le conteneur */
  --nav-h: 66px;
}

/* ---------- Polices auto-hébergées ----------
   font-display: swap → le texte s'affiche tout de suite avec la police de
   secours, puis bascule. Jamais de texte invisible pendant le chargement.
   Les fichiers latin-ext ne sont téléchargés que si un caractère de cette
   plage apparaît réellement dans la page. */

@font-face {
  font-family: "Instrument Serif";
  src: url("fonts/instrument-serif-latin-400.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  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+2074, U+20AC,
                 U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Instrument Serif";
  src: url("fonts/instrument-serif-latin-ext-400.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0100-02AF, U+0304-0311, U+0326-0327, U+1E00-1EFF, U+2020,
                 U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: "Geist";
  src: url("fonts/geist-latin-400.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Geist";
  src: url("fonts/geist-latin-500.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

/* Le 600 sert aux titres d'étape, aux questions de la FAQ et aux libellés de
   contact — les seuls endroits où il faut du gras sans passer au serif. Sans
   ce fichier, le navigateur fabriquerait un faux gras à partir du 400. */
@font-face {
  font-family: "Geist";
  src: url("fonts/geist-latin-600.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}

* { box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--nav-h) + 24px);
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-sans);
  font-size: 17px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  /* Chiffres à largeur fixe : les « 8 semaines », prix et stats ne dansent
     plus quand un chiffre change. */
  font-variant-numeric: tabular-nums;
}

/* Famille display sur les seuls titres qui portent la voix du site.
   Les titres d'étape, de FAQ et de contact restent en Geist : si tout passait
   en serif, la variation d'anatomie entre sections disparaîtrait. */
.hero-title,
.sequence-title,
.section-title,
.project-title,
.row-title {
  font-family: var(--font-display);
  font-weight: 400;               /* Instrument Serif n'existe qu'en 400 :
                                     demander 600 forcerait un faux gras */
  letter-spacing: -.012em;        /* un serif à fort contraste ne supporte pas
                                     le -.033em réglé pour du sans */
  text-wrap: balance;             /* évite le mot seul sur la dernière ligne */
}

p { text-wrap: pretty; }

img, video { max-width: 100%; }

a { color: inherit; }

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  background: var(--color-ink);
  color: var(--color-raised);
  padding: 12px 20px;
  text-decoration: none;
}
.skip-link:focus { left: 0; }

:focus-visible {
  outline: 2px solid var(--color-focus);
  outline-offset: 3px;
}

/* Les variables CSS s'héritent : redéfinir --color-focus sur la section sombre
   suffit à éclaircir l'anneau pour tous ses descendants. */
.sequence,
.nav.is-over-dark { --color-focus: #eef3f6; }

/* Un seul conteneur pour toute la page : le bord gauche ne bouge jamais. */
.wrap {
  max-width: var(--max-width);
  margin: 0 auto;
  padding-left: var(--pad-page);
  padding-right: var(--pad-page);
}

/* ---------- Bouton ---------- */

.btn {
  display: inline-block;
  background: var(--color-accent);
  color: var(--color-raised);
  text-decoration: none;
  padding: 16px 34px;
  border-radius: var(--radius);
  font-size: 16px;
  font-weight: 500;
  letter-spacing: -.005em;
  transition: opacity .2s ease;
}

/* ---------- Navigation ---------- */

/* Fond opaque, pas de verre dépoli (29/07). Deux raisons : le glassmorphism
   est un marqueur de site généré (technique.md 6bis), et un fond translucide
   laissait deviner le texte qui défile dessous — un fond franc est plus net et
   ne coûte rien en performance. */
.nav {
  position: sticky;
  top: 0;
  z-index: 50;
  background: var(--color-bg);
  border-bottom: 1px solid transparent;
  transition: border-color .3s ease;
}

.nav.is-stuck { border-bottom-color: var(--color-line); }

/* Quand la séquence occupe l'écran, la barre claire posait un bandeau blanc
   en travers de l'image. Elle passe en transparent et en texte clair. */
.nav.is-over-dark {
  background: transparent;
  border-bottom-color: transparent;
  color: var(--color-dark-text);
}

.nav.is-over-dark .nav-links a { color: var(--color-dark-dim); }
.nav.is-over-dark .nav-burger-bar { background: var(--color-dark-text); }

.nav-inner {
  max-width: var(--max-width);
  margin: 0 auto;
  height: var(--nav-h);
  padding: 0 var(--pad-page);
  display: flex;
  align-items: center;
  gap: 34px;
}

/* Le nom en serif fait office de signature : c'est le seul endroit de
   l'interface où la police des titres apparaît en petit, et ça suffit à
   installer la marque sans logo. */
.nav-name {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 19px;
  letter-spacing: -.005em;
  text-decoration: none;
  white-space: nowrap;
}

.nav-links {
  list-style: none;
  display: flex;
  gap: 30px;
  margin: 0 auto 0 0;
  padding: 0;
}

.nav-links a {
  text-decoration: none;
  font-size: 15px;
  color: var(--color-text-dim);
  transition: color .2s ease;
}

/* Petit bouton plein plutôt qu'un lien souligné : dans la revue, le lien
   souligné en haut à droite se lisait comme une note de bas de page. */
.nav-cta {
  text-decoration: none;
  font-size: 14px;
  font-weight: 500;
  white-space: nowrap;
  color: var(--color-raised);
  background: var(--color-accent);
  padding: 9px 18px;
  border-radius: var(--radius);
  transition: opacity .2s ease;
}

.nav-burger {
  display: none;
  margin-left: auto;
  width: 40px;
  height: 40px;
  padding: 0;
  background: none;
  border: 0;
  cursor: pointer;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
}

.nav-burger-bar {
  display: block;
  width: 20px;
  height: 1.5px;
  background: var(--color-ink);
  transition: transform .22s ease;
}

.nav-burger[aria-expanded="true"] .nav-burger-bar:first-child { transform: translateY(3.75px) rotate(45deg); }
.nav-burger[aria-expanded="true"] .nav-burger-bar:last-child  { transform: translateY(-3.75px) rotate(-45deg); }

.nav-panel {
  border-top: 1px solid var(--color-line);
  padding: 6px var(--pad-page) 20px;
}

.nav-panel a {
  display: block;
  padding: 15px 0;
  font-size: 18px;
  text-decoration: none;
  border-bottom: 1px solid var(--color-line);
}

.nav-panel a:last-child { border-bottom: 0; font-weight: 600; color: var(--color-accent); }

/* ---------- Hero ---------- */

.hero {
  max-width: var(--max-width);
  margin: 0 auto;
  padding: clamp(64px, 9vh, 112px) var(--pad-page) 0;
}

/* Ramené de 76 à 64 px : à 76 px la police système montrait ses limites,
   et le titre écrasait tout le reste du premier écran. */
/* Tailles relevées le 29/07 : un serif en 400 pèse optiquement moins qu'un
   sans en 600 à la même taille en pixels. Sans ce rattrapage, le titre
   paraissait avoir rétréci. */
.hero-title {
  margin: 0 0 26px;
  font-size: clamp(40px, 6.2vw, 76px);
  line-height: 1.02;
  max-width: 22ch;
}

/* Remontée à 21 px : l'écart avec le titre était tel que la phrase la plus
   utile de la page se lisait comme une mention légale. */
.hero-lede {
  margin: 0 0 40px;
  max-width: 46ch;
  font-size: clamp(17px, 1.55vw, 21px);
  line-height: 1.5;
  color: var(--color-text-dim);
}

.hero-action {
  margin: 0;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 18px 32px;
}

/* align-self : sans lui le lien s'étirait sur toute la largeur en mobile et
   son soulignement traversait l'écran. */
.hero-alt {
  align-self: flex-start;
  font-size: 15px;
  color: var(--color-text-dim);
  text-decoration: none;
  border-bottom: 1px solid var(--color-line-strong);
  padding-bottom: 2px;
  transition: color .2s ease, border-color .2s ease;
}

/* L'image fixe du hero a été retirée (27/07) : c'est la séquence au scroll
   qui prend sa place, en plein écran. */

.hero { padding-bottom: clamp(48px, 7vh, 84px); }

/* ---------- Séquence au scroll ----------
   Pleine largeur, pleine hauteur. Le maintien à l'écran est fait par
   `position: sticky` en CSS — ScrollTrigger ne fait QUE le défilement des
   frames. Cumuler `pin:` et `position: sticky` faisait se battre deux
   mécanismes : c'était la cause du scrub qui ne marchait pas. */

.sequence {
  position: relative;
  height: 320vh;                 /* durée du scrub : plus haut = plus lent */
  background: var(--color-dark-bg);
  color: var(--color-dark-text);
}

.sequence-sticky {
  position: sticky;
  top: 0;
  height: 100vh;
  height: 100svh;                /* iOS : évite le saut quand la barre d'URL se rétracte */
  overflow: hidden;
}

.sequence-canvas,
.sequence-video {
  display: block;
  width: 100%;
  height: 100%;
}

.sequence-video { display: none; object-fit: cover; }

.sequence-sticky::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 44%;
  background: linear-gradient(to bottom, rgba(18, 21, 22, 0) 0%, rgba(18, 21, 22, .55) 45%, rgba(18, 21, 22, .9) 100%);
  pointer-events: none;
}

.sequence-loader {
  position: absolute;
  left: 50%;
  bottom: 52px;
  transform: translateX(-50%);
  width: min(200px, 55vw);
  opacity: 1;
  transition: opacity .5s ease;
}

.sequence-loader.is-done { opacity: 0; pointer-events: none; }

.sequence-loader-bar {
  display: block;
  height: 2px;
  background: var(--color-dark-line);
  overflow: hidden;
}

.sequence-loader-bar i {
  display: block;
  height: 100%;
  width: 0;
  background: var(--color-dark-text);
  transition: width .2s ease;
}

.sequence-overlay {
  position: absolute;
  z-index: 2;
  left: 0;
  right: 0;
  bottom: 16vh;
  padding: 0 var(--pad-page);
  text-align: center;
  pointer-events: none;
}

.sequence-title {
  position: relative;
  margin: 0;
  min-height: 1.3em;
  font-size: clamp(30px, 5vw, 62px);
  line-height: 1.15;
}

.sequence-line {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  opacity: 0;
  transform: translateY(14px);
  transition: opacity .45s ease, transform .45s ease;
}

.sequence-line.is-active { opacity: 1; transform: translateY(0); }

.sequence-signature {
  margin: 1.5em 0 0;
  font-size: 13px;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--color-dark-dim);
  opacity: 0;
  transform: translateY(10px);
  transition: opacity .6s ease, transform .6s ease;
}

.sequence-signature.is-active { opacity: 1; transform: translateY(0); }

/* ---------- Sections ----------
   Rythme resserré : les 160 px de la version précédente créaient des vides
   qui ne ressemblaient pas à une intention. */

.section { padding: clamp(72px, 10vh, 116px) 0; }

.section-title {
  margin: 0 0 18px;
  font-size: clamp(30px, 3.8vw, 48px);
  line-height: 1.08;
  max-width: 24ch;
}

.section-lede {
  margin: 0 0 clamp(36px, 5vh, 56px);
  max-width: 48ch;
  font-size: 18px;
  color: var(--color-text-dim);
}

/* ---------- Réalisations ---------- */

.filters {
  display: flex;
  flex-wrap: wrap;
  gap: 28px;
  margin-bottom: clamp(36px, 5vh, 56px);
  padding-bottom: 14px;
  border-bottom: 1px solid var(--color-line);
}

.filter {
  font: inherit;
  font-size: 15px;
  color: var(--color-text-dim);
  background: none;
  border: 0;
  border-bottom: 1.5px solid transparent;
  padding: 0 0 6px;
  margin-bottom: -15.5px;
  cursor: pointer;
  transition: color .2s ease, border-color .2s ease;
}

.filter.is-active {
  color: var(--color-ink);
  border-bottom-color: var(--color-ink);
}

.realisations-top {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 24px;
  flex-wrap: wrap;
}

.projects-nav { display: flex; gap: 10px; padding-bottom: 6px; }

/* C'est le contrôle principal de la section : il doit se voir sans hésitation.
   Le contour à 1,64:1 de la version précédente le rendait quasi invisible sur
   le fond clair — corrigé par --color-line-strong (3,17:1) et un contour de
   1,5px. Le bouton actif est plein, le bouton en butée est vidé : la forme
   elle-même indique où on se trouve dans la série. */
.projects-arrow {
  width: 46px;
  height: 46px;
  border-radius: 999px;
  border: 1.5px solid var(--color-ink);
  background: var(--color-ink);
  color: var(--color-bg);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: background-color .2s ease, color .2s ease, border-color .2s ease;
}

.projects-arrow:disabled {
  background: transparent;
  border-color: var(--color-line-strong);
  color: var(--color-line-strong);
  cursor: default;
}

/* Carrousel : un masque fixe (.projects-viewport) + une piste qui coulisse
   (.projects). Le JS ne touche qu'au translateX de la piste — aucune dépendance
   au scroll natif, donc rien qui puisse retomber en pile verticale. */

.projects-viewport {
  --slide-gap: 24px;
  --slide-peek: 44px;   /* sliver de la démo suivante, laissé visible exprès */
  overflow: hidden;
  padding: 4px 0 28px;
}

.projects-viewport:focus-visible { outline-offset: -3px; }

.projects {
  display: flex;
  gap: var(--slide-gap);
  padding-left: var(--pad-page);
  /* Padding droit = gap + aperçu, et pas la gouttière de page : c'est ce qui
     permet à la DERNIÈRE démo de venir se poser exactement sur la gouttière
     gauche comme les autres, au lieu de rester coincée 36px trop à droite. */
  padding-right: calc(var(--slide-gap) + var(--slide-peek));
  cursor: grab;
  touch-action: pan-y;          /* le navigateur garde le scroll vertical */
  will-change: transform;
  transition: transform .58s cubic-bezier(.22, .61, .36, 1);
}

/* Pendant le glisser, la piste doit suivre le doigt sans retard. */
.projects.is-dragging {
  transition: none;
  cursor: grabbing;
}

.project {
  flex: 0 0 calc(100% - var(--pad-page) - var(--slide-gap) - var(--slide-peek));
}

/* Une seule démo affichée à la fois : assez de largeur pour remettre
   l'image et le texte côte à côte, comme une planche de cas client. */
/* Seuil relevé de 760 à 1000px le 29/07, après calcul. La carte est désormais
   plus étroite que la fenêtre (gouttière + gap + aperçu retirés), et la grille
   1.3fr/1fr laisse 2,3 parts au texte : à 820px la colonne de texte tombait à
   300px, soit 35 caractères par ligne — trop court pour lire confortablement.
   Il faut 1000px de fenêtre pour que cette colonne atteigne 45 caractères.
   En dessous, l'image passe au-dessus du texte, ce qui se lit très bien. */
@media (min-width: 1000px) {
  .project {
    display: grid;
    grid-template-columns: 1.3fr 1fr;
    gap: clamp(32px, 4vw, 64px);
    align-items: center;
  }
}

/* Sur un petit écran, l'aperçu doit rester discret : la carte est déjà étroite. */
@media (max-width: 620px) {
  .projects-viewport { --slide-gap: 16px; --slide-peek: 24px; }
}

.project.is-hidden { display: none; }

.project-media { display: block; text-decoration: none; }

.chrome {
  display: block;
  padding: 0 0 9px;
  border-bottom: 1px solid var(--color-line);
  margin-bottom: 13px;
}

/* Monospace : c'est une barre d'adresse, elle doit se lire comme telle. Pile
   système, donc aucun fichier de police en plus. */
.chrome-url {
  font-family: var(--font-mono);
  font-size: 12.5px;
  color: var(--color-text-faint);
  letter-spacing: .01em;
}

/* aspect-ratio : les captures n'auront pas toutes le même format, sans ça
   les deux colonnes du bas se décalent l'une par rapport à l'autre. */
.project-media img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 11;
  object-fit: cover;
  object-position: top center;
  /* Presque net et cerné d'un filet, comme une planche imprimée. Un rayon de
     6px sur une capture de site produisait deux arrondis concentriques — celui
     de la capture et celui de la fenêtre dedans. */
  border-radius: var(--radius-media);
  border: 1px solid var(--color-line);
  background: var(--color-raised);
  transition: opacity .25s ease;
}

.project-body { min-width: 0; }

.project-kicker {
  margin: 20px 0 11px;
  font-size: 12px;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--color-text-faint);
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 12px;
}

.project-badge {
  text-transform: none;
  letter-spacing: .02em;
  font-size: 12px;
  color: var(--color-text-faint);
  border-left: 1px solid var(--color-line-strong);
  padding-left: 12px;
}

.project-title {
  margin: 0 0 11px;
  font-size: clamp(23px, 2.4vw, 31px);
  line-height: 1.15;
}

.project-desc {
  margin: 0 0 16px;
  font-size: 16px;
  color: var(--color-text-dim);
  max-width: 44ch;
}

.project-meta {
  margin: 0 0 18px;
  font-size: 14px;
  color: var(--color-text-faint);
}

.project-link {
  display: inline-block;
  font-size: 15px;
  font-weight: 500;
  text-decoration: none;
  border-bottom: 1px solid var(--color-ink);
  padding-bottom: 2px;
  transition: color .2s ease, border-color .2s ease;
}

/* Barre de progression du carrousel : reflète la position de la piste (index
   courant / nombre de démos) et permet de sauter à une démo au clic. */
.projects-scrollbar {
  position: relative;
  height: 3px;
  background: var(--color-line);
  border-radius: 3px;
  margin-top: clamp(4px, 1vh, 12px);
  cursor: pointer;
}

.projects-scrollbar-thumb {
  position: absolute;
  top: -4px;
  left: 0;
  height: 11px;
  min-width: 40px;
  border-radius: 999px;
  background: var(--color-ink);
  cursor: grab;
  transition: transform .58s cubic-bezier(.22, .61, .36, 1), width .3s ease;
}

.projects-scrollbar-thumb:active { cursor: grabbing; }
.projects-scrollbar.is-hidden { opacity: 0; pointer-events: none; }

/* ---------- Ce que je fais ----------
   Colonne de titre resserrée : à 1fr/2fr le titre flottait seul très loin
   de son paragraphe. */

.rows { border-top: 1px solid var(--color-line); }

.row {
  display: grid;
  grid-template-columns: minmax(180px, 0.55fr) 1.45fr;
  gap: clamp(24px, 3.5vw, 48px);
  padding: clamp(34px, 4.5vh, 52px) 0;
  border-bottom: 1px solid var(--color-line);
  align-items: start;
}

.row-title {
  margin: 0;
  font-size: clamp(22px, 2.4vw, 30px);
  line-height: 1.15;
}

.row-text p {
  margin: 0;
  font-size: 18px;
  color: var(--color-text-dim);
  max-width: 52ch;
}

/* ---------- Comment ça se passe ---------- */

.steps {
  list-style: none;
  margin: 0;
  padding: 0 0 0 30px;
  max-width: 640px;
  border-left: 1px solid var(--color-line);
}

.step { position: relative; padding: 0 0 clamp(30px, 4vh, 42px); }

.step:last-child { padding-bottom: 0; }

.step::before {
  content: "";
  position: absolute;
  left: -34px;
  top: 9px;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--color-accent);
}

.step-title {
  margin: 0 0 8px;
  font-size: 20px;
  font-weight: 600;
  letter-spacing: -.02em;
}

.step-desc {
  margin: 0;
  font-size: 17px;
  color: var(--color-text-dim);
  max-width: 52ch;
}

/* ---------- Qui je suis ----------
   Portrait en 4/5 aligné en haut : en centrage vertical il flottait au
   milieu d'un bloc vide. */

.about-grid {
  display: grid;
  grid-template-columns: 1.38fr minmax(240px, 0.62fr);
  gap: clamp(36px, 5vw, 68px);
  align-items: start;
}

.about-media { order: 2; }
.about-text { order: 1; }

.about-media img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  border-radius: var(--radius-media);
  background: var(--color-raised);
}

.about-text .section-title { margin-top: -8px; }

.about-text p {
  margin: 0 0 17px;
  font-size: 18px;
  color: var(--color-text-dim);
  max-width: 50ch;
}

.about-text p:last-child { margin-bottom: 0; }

/* Les styles de la FAQ (.faq, .qa, .qa-body) ont été supprimés le 29/07 avec la
   section. Ils sont récupérables dans
   _versions/site-2026-07-29-avant-retrait-faq/style.css si elle revient. */

/* ---------- Contact ---------- */

.contact-lede {
  margin: 0 0 clamp(34px, 4.5vh, 48px);
  max-width: 48ch;
  font-size: 18px;
  color: var(--color-text-dim);
}

.contact-list {
  list-style: none;
  margin: 0;
  padding: 0;
  max-width: 720px;
  border-top: 1px solid var(--color-line);
}

.contact-item {
  display: flex;
  align-items: baseline;
  gap: 24px;
  padding: 23px 0;
  border-bottom: 1px solid var(--color-line);
  text-decoration: none;
  transition: padding-left .25s ease;
}

/* La première ligne est le canal principal : elle doit se voir comme tel. */
.contact-list li:first-child .contact-label { color: var(--color-accent); }
.contact-list li:first-child .contact-item { padding-top: 26px; padding-bottom: 26px; }

.contact-label {
  flex: 0 0 130px;
  font-size: 19px;
  font-weight: 600;
  letter-spacing: -.02em;
}

.contact-value { font-size: 16px; color: var(--color-text-dim); }

/* ---------- Pied de page ---------- */

.site-footer {
  border-top: 1px solid var(--color-line);
  padding: 40px 0;
}

.footer-inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 18px 36px;
}

.footer-note { margin: 0; font-size: 14px; color: var(--color-text-dim); }

.footer-links {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 22px;
  margin: 0;
  padding: 0;
}

.footer-links a { font-size: 14px; color: var(--color-text-dim); text-decoration: none; }

/* ---------- Barre d'action mobile ---------- */

.dock {
  position: fixed;
  z-index: 40;
  left: 0;
  right: 0;
  bottom: 0;
  padding: 12px var(--pad-page) calc(12px + env(safe-area-inset-bottom, 0px));
  background: var(--color-bg);
  border-top: 1px solid var(--color-line);
  transform: translateY(102%);
  transition: transform .3s ease;
}

.dock.is-visible { transform: translateY(0); }

/* Sur la séquence, la barre claire posait un bandeau en travers de l'image :
   même traitement que la barre de navigation. */
.dock.is-over-dark {
  background: transparent;
  border-top-color: transparent;
}

.dock-link {
  display: block;
  text-align: center;
  background: var(--color-accent);
  color: var(--color-raised);
  text-decoration: none;
  font-size: 16px;
  font-weight: 500;
  padding: 15px 20px;
  border-radius: var(--radius);
}

/* =========================================================
   Survol — desktop uniquement
   ========================================================= */

@media (hover: hover) and (pointer: fine) {
  .btn:hover, .nav-cta:hover, .dock-link:hover { opacity: .86; }
  .nav-links a:hover { color: var(--color-ink); }
  .hero-alt:hover { color: var(--color-ink); border-color: var(--color-ink); }
  .filter:hover { color: var(--color-ink); }
  .project-media:hover img { opacity: .88; }
  .projects-arrow:hover:not(:disabled) { background: var(--color-accent); border-color: var(--color-accent); }
  .project-link:hover { color: var(--color-accent); border-color: var(--color-accent); }
  .contact-item:hover { padding-left: 12px; }
  .footer-links a:hover { color: var(--color-ink); }
}

/* =========================================================
   Tablette
   ========================================================= */

@media (max-width: 1000px) {
  :root { --pad-page: 28px; }

  .nav-links { display: none; }
  .nav-cta { display: none; }
  .nav-burger { display: flex; }

  .about-grid { grid-template-columns: 1.6fr minmax(200px, .8fr); gap: 40px; }
  .row { grid-template-columns: 1fr; gap: 14px; }
}

/* =========================================================
   Mobile
   ========================================================= */

@media (max-width: 768px) {
  :root { --pad-page: 22px; }

  body { font-size: 16px; }

  /* -.028em était réglé pour l'ancien sans en 600 ; un serif à fort contraste
     se colle à lui-même à cette valeur. */
  .hero-title { max-width: none; letter-spacing: -.008em; }
  .hero-action { gap: 20px; }
  .btn { display: block; text-align: center; width: 100%; }

  .sequence-overlay { bottom: 13vh; }

  .filters { gap: 22px; }

  .about-grid { grid-template-columns: 1fr; gap: 26px; }
  .about-media { max-width: 260px; order: 2; }
  .about-text { order: 1; }
  .about-text .section-title { margin-top: 0; }

  .steps { padding-left: 24px; }
  .step::before { left: -28px; }

  .contact-item { flex-direction: column; gap: 5px; }
  .contact-label { flex: none; }

  .footer-inner { flex-direction: column; align-items: flex-start; }

  body.has-dock .site-footer { padding-bottom: calc(92px + env(safe-area-inset-bottom, 0px)); }
}

/* =========================================================
   Mode « clip » — appareils tactiles
   Cette requête doit rester STRICTEMENT identique à MEDIA_CLIP dans hero.js.
   Sans ça, le CSS et le JS se désynchronisent au redimensionnement ou à la
   rotation : le canvas s'affiche alors qu'aucune frame n'a été chargée, ou
   l'inverse. C'était le bug de l'écran noir en paysage.
   ========================================================= */

@media (max-width: 768px), (pointer: coarse) and (max-width: 1024px) {
  /* Les 97 frames (3,8 Mo) ne sont pas téléchargées : un clip de ~250 Ko
     prend le relais, dans l'orientation qui correspond à l'écran. */
  .sequence { height: 260vh; }
  .sequence-canvas { display: none; }
  .sequence-video { display: block; }
  .sequence-loader { display: none; }
}

/* =========================================================
   Accessibilité — mouvement réduit
   ========================================================= */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  .sequence { height: auto; min-height: 0; padding: clamp(72px, 10vh, 116px) 0; }
  .sequence-sticky { position: static; height: auto; overflow: visible; }
  .sequence-sticky::after { display: none; }
  .sequence-canvas, .sequence-video, .sequence-loader { display: none; }

  .sequence-overlay { position: static; padding: 0 var(--pad-page); }
  .sequence-title { position: static; min-height: 0; }

  .sequence-line {
    position: static;
    opacity: 1;
    transform: none;
    transition: none;
    display: block;
    margin-bottom: 12px;
  }

  .sequence-signature { opacity: 1; transform: none; transition: none; }

  .btn, .nav-cta, .hero-alt, .filter, .contact-item, .dock, .dock-link,
  .nav-burger-bar, .project-media img, .project-link,
  .projects, .projects-arrow, .projects-scrollbar-thumb { transition: none; }
}
