/* Transition entre les pages du site (accueil ↔ CV ↔ 404).
   Sans elle, la navigation provoque un flash blanc. Les navigateurs qui ne
   connaissent pas la règle l'ignorent simplement. */
@view-transition { navigation: auto; }

/* ==========================================================================
   PORTFOLIO — Jérémy Sauterel
   Feuille de style principale
   --------------------------------------------------------------------------
   SOMMAIRE
   01. Design system (variables, tokens)
   02. Reset & bases
   03. Utilitaires (container, boutons, liens)
   04. Curseur personnalisé & barre de progression
   05. Navigation fixe
   06. Hero
   07. Marquee (bandeau défilant)
   08. Titres de section
   09. Bento grid (À propos)
   10. Cartes & galeries (Photos / Vidéos / Graphisme)
   11. Filtres
   12. Contact & footer
   13. Lightbox
   14. Animations (keyframes + scroll reveal)
   15. Responsive
   16. Accessibilité (mouvement réduit, focus)
   ========================================================================== */


/* ==========================================================================
   01. DESIGN SYSTEM
   ========================================================================== */
:root {
  /* — Couleurs : thème sombre élégant, contraste fort — */
  --bg:            #08080A;   /* fond général, presque noir */
  --bg-alt:        #0C0C10;   /* fond des sections alternées */
  --surface:       #121216;   /* cartes */
  --surface-2:     #17171D;   /* cartes au survol */
  --line:          rgba(255, 255, 255, .08);
  --line-strong:   rgba(255, 255, 255, .16);

  --text:          #F5F5F7;   /* texte principal */
  --text-soft:     #A6A6B0;   /* texte secondaire */
  --text-mute:     #8B8B97;   /* légendes, méta */

  /* — Touches de couleur subtiles (utilisées avec parcimonie) — */
  --accent:        #7C6BFF;   /* violet électrique */
  --accent-2:      #4AD9FF;   /* cyan */
  --accent-soft:   rgba(124, 107, 255, .14);
  --gradient:      linear-gradient(120deg, var(--accent), var(--accent-2));

  /* — Typographie — */
  --font: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
          "Helvetica Neue", Arial, sans-serif;

  /* Tailles fluides : s'adaptent seules entre mobile et desktop */
  --fs-hero:   clamp(3rem, 11vw, 9rem);
  --fs-h2:     clamp(2rem, 5.2vw, 4rem);
  --fs-h3:     clamp(1.125rem, 2vw, 1.5rem);
  --fs-lead:   clamp(1rem, 1.6vw, 1.25rem);
  --fs-body:   clamp(.95rem, 1.2vw, 1.05rem);
  --fs-small:  .8125rem;

  /* — Espacements & rayons — */
  --space-section: clamp(3.25rem, 7.5vw, 6.5rem);
  --radius-sm: 12px;
  --radius:    20px;
  --radius-lg: 28px;

  /* — Transitions : une seule courbe, partout, pour la cohérence — */
  --ease:      cubic-bezier(.22, 1, .36, 1);   /* easeOutQuint : très fluide */
  --ease-soft: cubic-bezier(.4, 0, .2, 1);
  --t-fast:    .25s var(--ease-soft);
  --t:         .45s var(--ease);
  --t-slow:    .8s var(--ease);

  /* — Ombres — */
  --shadow:    0 24px 60px -20px rgba(0, 0, 0, .8);
  --shadow-lg: 0 40px 90px -25px rgba(0, 0, 0, .9);

  --nav-h: 72px;
}


/* ==========================================================================
   02. RESET & BASES
   ========================================================================== */
*, *::before, *::after { box-sizing: border-box; }

* { margin: 0; padding: 0; }

html {
  scroll-behavior: smooth;
  /* On décale l'ancrage pour ne pas passer sous la nav fixe */
  scroll-padding-top: calc(var(--nav-h) + 24px);
  -webkit-text-size-adjust: 100%;
}

body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  font-size: var(--fs-body);
  line-height: 1.65;
  font-weight: 400;
  letter-spacing: -.01em;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

/* Verrouillage du scroll quand un overlay est ouvert (menu mobile, lightbox) */
body.is-locked { overflow: hidden; }

/* ==========================================================================
   1 bis. ÉCRAN DE CHARGEMENT
   Le logo apparaît, un trait de lumière le traverse, une barre se remplit,
   puis l'écran se soulève. Tout est en CSS : si le JavaScript ne s'exécute
   pas, l'animation de repli le fait disparaître quand même.
   ========================================================================== */
.chargement {
  position: fixed; inset: 0; z-index: 2000;
  overflow: hidden;
  display: grid; place-content: center; justify-items: center;
  gap: 1.6rem;
  background: var(--bg);
  /* Filet de sécurité : l'écran s'efface seul au bout de 3 s, quoi qu'il
     arrive du côté du JavaScript. */
  animation: chargementSecours .8s var(--ease) 3s forwards;
}
/* Retrait piloté par le JavaScript, dès que la page est prête */
.chargement.est-parti {
  opacity: 0; visibility: hidden;
  transform: translateY(-1.5rem);
  transition: opacity .55s var(--ease), transform .7s var(--ease),
              visibility 0s linear .7s;
  animation: none;
}

/* — Animation du logo —
   Le monogramme se dessine : son contour se trace d'un trait, puis le
   remplissage apparaît et le contour s'efface. Pendant ce temps la « caméra »
   recule depuis un gros plan, avec une petite poussée à la fin.
   Les longueurs 394 et 696 sont celles des tracés, mesurées sur le fichier :
   c'est ce qui permet au trait de se dérouler exactement. */
.chargement__logo {
  position: relative;
  width: clamp(58px, 12vw, 82px);
  color: var(--text);
  animation: logoCamera 1.2s cubic-bezier(.22, 1, .36, 1) both;
}
.chargement__logo svg { width: 100%; height: auto; display: block; overflow: visible; }

/* Le contour qui se trace */
.logo-trace {
  fill: none;
  stroke: currentColor; stroke-width: 1.7;
  stroke-linecap: round; stroke-linejoin: round;
  stroke-dasharray: var(--L); stroke-dashoffset: var(--L);
  animation: logoTrace .72s cubic-bezier(.65, 0, .35, 1) both,
             logoEfface .26s var(--ease) .82s both;
}
.logo-trace--1 { --L: 394; }
.logo-trace--2 { --L: 696; animation-delay: .12s, .82s; }

/* Le remplissage prend le relais du contour */
.logo-plein { opacity: 0; animation: logoRemplit .34s var(--ease) .78s both; }

/* Un reflet unique, une fois le logo plein */
.chargement__logo::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(105deg,
    transparent 40%, rgba(255, 255, 255, .95) 50%, transparent 60%);
  background-size: 240% 100%;
  -webkit-mask: url("assets/logo.svg") center / contain no-repeat;
  mask: url("assets/logo.svg") center / contain no-repeat;
  animation: logoBalayage .9s var(--ease-soft) 1.05s both;
  pointer-events: none;
}

.chargement__barre {
  display: block; width: clamp(90px, 22vw, 132px); height: 2px;
  border-radius: 2px;
  background: rgba(255, 255, 255, .12);
  overflow: hidden;
}
.chargement__barre i {
  display: block; height: 100%; width: 100%;
  background: var(--gradient);
  transform-origin: left;
  animation: chargementBarre 1.2s var(--ease) .05s both;
}

/* Rien ne clignote pour qui a demandé moins d'animation */
@media (prefers-reduced-motion: reduce) {
  .chargement__logo, .chargement__logo::after,
  .logo-trace, .logo-plein, .chargement__barre i { animation: none; }
  .logo-trace { display: none; }
  .logo-plein { opacity: 1; }
  .chargement { animation: chargementSecours .01s linear .4s forwards; }
}


img, video, svg { display: block; max-width: 100%; }
img, video { height: auto; }

a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
ul, ol { list-style: none; }

h1, h2, h3, h4 {
  line-height: 1.05;
  font-weight: 700;
  letter-spacing: -.035em;
}

/* Mots en dégradé. Deux couches de fond découpées sur le texte : la bande
   claire est posée au-dessus du dégradé et se déplace au survol. */
em,
.hero__subtitle strong {
  font-style: normal;
  background:
    linear-gradient(105deg, transparent 42%, rgba(255, 255, 255, .92) 50%, transparent 58%) no-repeat,
    var(--gradient);
  background-size: 220% 100%, 100% 100%;
  /* Une image de fond plus large que le conteneur inverse le sens des
     pourcentages : 120% place la bande juste à gauche du mot, -20% juste à
     droite. Course serrée pour que le reflet traverse sur toute la durée. */
  background-position: 120% 0, 0 0;
  -webkit-background-clip: text; background-clip: text;
  color: transparent;
}
/* Titres : le reflet traverse le titre entier au survol.
   Sur un texte déjà blanc une bande blanche serait invisible : elle prend
   donc la couleur d'accent. Sur les mots en dégradé, c'est l'inverse. */
/* Le titre d'accueil est exclu : ses mots sont enveloppés dans des spans
   animés, et le découpage sur le texte ne suit pas des glyphes transformés
   — le titre disparaîtrait. */
.section__title,
.contact__title,
.bento__title {
  background:
    linear-gradient(105deg, transparent 42%, var(--accent-2) 50%, transparent 58%) no-repeat,
    linear-gradient(var(--text), var(--text));
  background-size: 220% 100%, 100% 100%;
  background-position: 120% 0, 0 0;
  -webkit-background-clip: text; background-clip: text;
  color: transparent;
}

.section__title:hover,
.contact__title:hover,
.bento__title:hover,
.section__title:hover em,
.contact__title:hover em,
.bento__title:hover em,
.section__title.is-sweeping,
.contact__title.is-sweeping,
.bento__title.is-sweeping,
.section__title.is-sweeping em,
.contact__title.is-sweeping em,
.bento__title.is-sweeping em { animation: textSweep 1.6s var(--ease-soft); }

@keyframes stepFill    { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@keyframes bufferSweep { from { background-position: 130% 0; } to { background-position: -30% 0; } }
@keyframes tourne     { to { transform: rotate(360deg); } }
@keyframes traceCoche { to { stroke-dashoffset: 0; } }
@keyframes traceCroix { to { stroke-dashoffset: 0; } }
@keyframes textSweep {
  from { background-position: 120% 0, 0 0; }   /* bande hors cadre, à gauche */
  to   { background-position: -20% 0, 0 0; }   /* bande hors cadre, à droite */
}
strong { font-weight: 600; color: var(--text); }

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

/* Barre de défilement discrète (WebKit) */
::-webkit-scrollbar { width: 10px; }
::-webkit-scrollbar-track { background: var(--bg); }
::-webkit-scrollbar-thumb { background: #26262e; border-radius: 99px; border: 3px solid var(--bg); }
::-webkit-scrollbar-thumb:hover { background: #3a3a46; }

/* Lien d'évitement clavier */
.skip-link {
  position: fixed; top: 8px; left: 8px; z-index: 999;
  padding: .6rem 1rem; background: var(--text); color: var(--bg);
  border-radius: 8px; font-weight: 600; font-size: var(--fs-small);
  transform: translateY(-200%); transition: transform var(--t-fast);
}
.skip-link:focus-visible { transform: translateY(0); }


/* ==========================================================================
   03. UTILITAIRES
   ========================================================================== */
.container {
  width: min(1240px, 100% - 3rem);
  margin-inline: auto;
}

.section { padding-block: var(--space-section); position: relative; }
.section--alt { background: var(--bg-alt); }

/* — Boutons — */
.btn {
  --btn-bg: transparent;
  display: inline-flex; align-items: center; gap: .6rem;
  padding: .95rem 1.6rem;
  border-radius: 99px;
  font-size: .95rem; font-weight: 600; letter-spacing: -.01em;
  background: var(--btn-bg);
  border: 1px solid var(--line-strong);
  position: relative; overflow: hidden;
  transition: transform var(--t), border-color var(--t-fast), color var(--t-fast), background var(--t-fast);
  will-change: transform;
}
.btn svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; transition: transform var(--t); }
.btn:hover svg { transform: translateX(4px); }

.btn--primary { --btn-bg: var(--text); color: var(--bg); border-color: var(--text); }
.btn--primary:hover { transform: translateY(-3px); box-shadow: 0 16px 40px -12px rgba(245, 245, 247, .35); }

.btn--ghost { color: var(--text); }
.btn--ghost:hover { transform: translateY(-3px); border-color: var(--text); background: rgba(255, 255, 255, .05); }

.btn--small { padding: .55rem 1.05rem; font-size: .85rem; }

/* — Balayage lumineux sur les boutons transparents —
   Même principe que sur les cartes, en plus court : ces éléments sont petits,
   un reflet lent y paraîtrait traînant. Réservé aux boutons ajourés : sur le
   bouton blanc plein, une bande claire ne se verrait pas. */
.btn--ghost,
.bio-toggle,
.carousel-nav__btn {
  position: relative;
  overflow: hidden;
}
.btn--ghost::after,
.bio-toggle::after,
.carousel-nav__btn::after {
  content: "";
  position: absolute; inset: 0; z-index: 0;
  pointer-events: none;
  opacity: 0;
  background: linear-gradient(105deg,
    transparent 35%,
    rgba(255, 255, 255, .07) 45%,
    rgba(255, 255, 255, .20) 50%,
    rgba(255, 255, 255, .07) 55%,
    transparent 65%);
}
.btn--ghost:hover::after,
.bio-toggle:hover::after,
.carousel-nav__btn:hover:not(:disabled)::after,
.btn--ghost.is-sweeping::after,
.bio-toggle.is-sweeping::after,
.carousel-nav__btn.is-sweeping::after { animation: sweepLR .9s var(--ease-soft); }

/* Le contenu doit rester au-dessus du reflet */
.btn--ghost > *,
.bio-toggle > * { position: relative; z-index: 1; }

/* — Lien dans le corps du texte —
   Souligné discret qui se colore au survol, sans casser le rythme de lecture. */
.link-inline {
  color: inherit;
  text-decoration: underline;
  text-decoration-color: var(--line-strong);
  text-underline-offset: .22em;
  text-decoration-thickness: 1px;
  transition: color var(--t-fast), text-decoration-color var(--t-fast);
}
.link-inline:hover {
  color: var(--accent-2);
  text-decoration-color: var(--accent-2);
}

/* — Lien fléché — */
.link-arrow {
  display: inline-flex; align-items: center; gap: .45rem;
  font-weight: 600; font-size: .95rem; color: var(--text);
  margin-top: auto; padding-top: 1.2rem;
}
.link-arrow svg { width: 17px; height: 17px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; transition: transform var(--t); }
.link-arrow:hover svg { transform: translateX(5px); }


/* ==========================================================================
   04. CURSEUR PERSONNALISÉ & PROGRESSION
   ========================================================================== */
.cursor { position: fixed; inset: 0; pointer-events: none; z-index: 900; display: none; }
/* Activé uniquement sur les appareils à souris (classe posée par le JS) */
body.has-cursor .cursor { display: block; }

.cursor__dot,
.cursor__ring {
  position: absolute; top: 0; left: 0;
  border-radius: 50%;
  transform: translate(-50%, -50%);
  will-change: transform;
}
.cursor__dot { width: 6px; height: 6px; background: var(--text); }
.cursor__ring {
  width: 34px; height: 34px;
  border: 1px solid var(--line-strong);
  transition: width var(--t-fast), height var(--t-fast), background var(--t-fast), border-color var(--t-fast);
}
/* État "survol d'un élément interactif" */
.cursor.is-hover .cursor__ring {
  width: 58px; height: 58px;
  background: rgba(255, 255, 255, .07);
  border-color: transparent;
}


.scroll-progress {
  position: fixed; top: 0; left: 0; right: 0; height: 2px; z-index: 700;
  background: transparent; pointer-events: none;
}
.scroll-progress span {
  display: block; height: 100%; width: 0%;
  background: var(--gradient);
  transition: width .1s linear;
}


/* ==========================================================================
   05. NAVIGATION FIXE
   ========================================================================== */
.nav {
  position: fixed; top: 0; left: 0; right: 0; z-index: 800;
  height: var(--nav-h);
  display: flex; align-items: center;
  transition: background var(--t), border-color var(--t), backdrop-filter var(--t);
  border-bottom: 1px solid transparent;
}
/* État après défilement : fond translucide + flou (effet "Apple") */
.nav.is-scrolled {
  background: rgba(8, 8, 10, .72);
  backdrop-filter: saturate(180%) blur(20px);
  -webkit-backdrop-filter: saturate(180%) blur(20px);
  border-bottom-color: var(--line);
}
/* La nav se masque au scroll vers le bas, réapparaît vers le haut */
.nav.is-hidden { transform: translateY(-100%); }
.nav { transition: transform var(--t), background var(--t), border-color var(--t); }

.nav__inner { display: flex; align-items: center; justify-content: space-between; gap: 1.5rem; }

.nav__logo { display: flex; align-items: center; gap: .6rem; font-weight: 600; letter-spacing: -.02em; }
/* Le logo est vertical (ratio 0,87) : on cale la hauteur, la largeur suit. */
.nav__logo-mark {
  height: 34px; width: auto;
  transition: transform var(--t), opacity var(--t-fast);
}
.nav__logo:hover .nav__logo-mark { transform: scale(1.08); }
.nav__logo-text { font-size: .95rem; }

.nav__menu { display: flex; align-items: center; gap: 2rem; }
.nav__list { display: flex; align-items: center; gap: .35rem; position: relative; }

/* — Repère de section courante —
   Une pastille qui glisse d'un lien à l'autre au fil du défilement. Elle est
   posée par le JavaScript, qui lui donne la position et la largeur du lien
   actif ; sans JavaScript elle reste invisible et la couleur suffit. */
.nav__pill {
  position: absolute; left: 0; top: 50%; z-index: 0;
  height: 2px; width: var(--pill-w, 0);
  transform: translate(var(--pill-x, 0), 14px);
  background: var(--gradient);
  border-radius: 2px;
  opacity: 0; pointer-events: none;
  transition: transform .45s var(--ease), width .45s var(--ease), opacity var(--t);
}
.nav__pill.is-on { opacity: 1; }

.nav__link {
  position: relative;
  display: block; padding: .5rem .9rem;
  font-size: .9rem; font-weight: 500; color: var(--text-soft);
  border-radius: 99px;
  transition: color var(--t-fast);
}
/* Pastille de fond qui apparaît au survol */
.nav__link::before {
  content: ""; position: absolute; inset: 0;
  background: rgba(255, 255, 255, .07); border-radius: 99px;
  transform: scale(.85); opacity: 0;
  transition: transform var(--t), opacity var(--t);
}
.nav__link span { position: relative; z-index: 1; }
.nav__link:hover { color: var(--text); }
.nav__link:hover::before { transform: scale(1); opacity: 1; }

/* Section active (scrollspy géré en JS).
   Sur grand écran, c'est la barre .nav__pill qui marque la position : le
   point d'origine ferait doublon. Il ne subsiste que dans le menu au doigt,
   où la barre est masquée (voir la partie responsive). */
.nav__link.is-active { color: var(--text); }

/* Burger */
.nav__burger {
  display: none;
  width: 44px; height: 44px; border-radius: 12px;
  border: 1px solid var(--line);
  position: relative;
}
.nav__burger span {
  position: absolute; left: 50%; width: 18px; height: 1.5px;
  background: var(--text); border-radius: 2px;
  transition: transform var(--t), opacity var(--t-fast);
}
.nav__burger span:nth-child(1) { transform: translate(-50%, -4px); }
.nav__burger span:nth-child(2) { transform: translate(-50%, 4px); }
.nav__burger.is-open span:nth-child(1) { transform: translate(-50%, 0) rotate(45deg); }
.nav__burger.is-open span:nth-child(2) { transform: translate(-50%, 0) rotate(-45deg); }


/* ==========================================================================
   06. HERO
   ========================================================================== */
.hero {
  position: relative;
  min-height: 100svh;
  display: flex; flex-direction: column; justify-content: center;
  padding-block: calc(var(--nav-h) + 4rem) 6rem;
  overflow: hidden;
}

/* Grille de fond très discrète */
.hero__grid-bg {
  position: absolute; inset: 0;
  background-image:
    linear-gradient(var(--line) 1px, transparent 1px),
    linear-gradient(90deg, var(--line) 1px, transparent 1px);
  background-size: 90px 90px;
  mask-image: radial-gradient(circle at 50% 40%, #000 0%, transparent 70%);
  -webkit-mask-image: radial-gradient(circle at 50% 40%, #000 0%, transparent 70%);
  opacity: .5;
}

/* Halos colorés animés (les touches de couleur du thème sombre) */
.hero__glow {
  position: absolute; border-radius: 50%;
  filter: blur(120px); opacity: .35; pointer-events: none;
  animation: float 14s ease-in-out infinite;
}
.hero__glow--1 { width: 46vw; height: 46vw; background: var(--accent);   top: -12%; left: -8%; }
.hero__glow--2 { width: 38vw; height: 38vw; background: var(--accent-2); bottom: -18%; right: -6%; opacity: .22; animation-delay: -7s; }

.hero__inner { position: relative; z-index: 1; }

.hero__badge {
  display: inline-flex; align-items: center; gap: .55rem;
  padding: .45rem 1rem; border-radius: 99px;
  border: 1px solid var(--line-strong);
  background: rgba(255, 255, 255, .03);
  font-size: var(--fs-small); color: var(--text-soft); font-weight: 500;
  margin-bottom: 2rem;
}
/* Léger grossissement au survol.
   On anime « scale » et non « transform » : la révélation au défilement
   (.reveal) se sert déjà de transform pour faire monter le badge, et les
   deux s'écraseraient. Le sélecteur vise aussi .reveal pour passer devant
   sa propre transition, tout en lui rendant opacity et transform — sans
   quoi l'apparition deviendrait instantanée.
   L'origine à gauche évite que le badge déborde du bord de l'écran. */
.hero__badge, .hero__badge.reveal {
  transform-origin: left center;
  transition: opacity .9s var(--ease), transform .9s var(--ease),
              scale .25s var(--ease), border-color var(--t-fast), background var(--t-fast);
  transition-delay: var(--reveal-delay, 0ms), var(--reveal-delay, 0ms), 0ms, 0ms, 0ms;
}
.hero__badge:hover {
  scale: 1.04;
  border-color: var(--text-mute);
  background: rgba(255, 255, 255, .07);
}
.pulse {
  width: 7px; height: 7px; border-radius: 50%; background: #46E39B;
  box-shadow: 0 0 0 0 rgba(70, 227, 155, .6);
  animation: pulse 2.2s infinite;
}

.hero__title {
  font-size: var(--fs-hero);
  font-weight: 800;
  letter-spacing: -.055em;
  line-height: .92;
  margin-bottom: 1.75rem;
}
/* Chaque mot est enveloppé par le JS pour l'animation d'apparition */
.hero__title .word { display: inline-block; overflow: hidden; vertical-align: bottom; }
.hero__title .word > span {
  display: inline-block;
  transform: translateY(105%);
  animation: wordUp 1.1s var(--ease) forwards;
  animation-delay: var(--d, 0s);
}

.hero__subtitle {
  font-size: clamp(1.1rem, 2.4vw, 1.75rem);
  font-weight: 500; color: var(--text);
  letter-spacing: -.02em; margin-bottom: 1rem;
}

.hero__text {
  max-width: 46ch; color: var(--text-soft);
  font-size: var(--fs-lead); margin-bottom: 2.5rem;
}

.hero__actions { display: flex; flex-wrap: wrap; gap: .75rem; margin-bottom: 4rem; }

.hero__stats {
  display: flex; flex-wrap: wrap; gap: clamp(1.5rem, 5vw, 4rem);
  padding-top: 2rem; border-top: 1px solid var(--line);
}
.hero__stats li { display: flex; flex-direction: column; gap: .15rem; }
.hero__stats strong { font-size: clamp(1.75rem, 3.5vw, 2.75rem); font-weight: 700; letter-spacing: -.04em; line-height: 1; }
.hero__stats span { font-size: var(--fs-small); color: var(--text-mute); }

/* Sans cet enregistrement, --tilt serait une simple chaîne : l'inclinaison
   sauterait d'un coup quand une carte change de rang au lieu de pivoter. */
@property --tilt { syntax: '<angle>'; inherits: false; initial-value: 0deg; }

/* — Pile de photos du hero —
   Trois travaux empilés en éventail dans l'espace libre à droite du titre.
   Chaque carte flotte à son rythme ; au survol, l'éventail s'ouvre. */
.hero__stack {
  position: absolute;
  right: 0; top: 59.5%;        /* centrée dans la bande libre entre le titre et les stats */
  transform: translateY(-50%);
  /* La taille suit aussi la hauteur d'écran : sur un portable, la bande
     disponible se réduit et la pile doit se réduire avec elle. */
  width: min(26vw, 320px, 38vh);
  aspect-ratio: 1;
  z-index: 1;
}
.hero__stack-img {
  position: absolute;
  width: 55%; aspect-ratio: 2 / 3;
  object-fit: cover;
  border-radius: 16px;
  border: 1px solid rgba(255, 255, 255, .12);
  box-shadow: 0 30px 70px -20px rgba(0, 0, 0, .85);
  transition: transform .8s var(--ease), box-shadow var(--t),
              left .8s var(--ease), top .8s var(--ease), --tilt .8s var(--ease),
              scale .4s var(--ease), opacity .4s var(--ease);
  animation: floatCard 9s ease-in-out infinite;
}
/* Position de repos de chaque carte, de l'arrière vers l'avant */
.hero__stack-img--3 { left: 0;   top: 0;   --tilt: -9deg; z-index: 1; animation-delay: -6s; }
.hero__stack-img--2 { left: 21%; top: 9%;  --tilt:  3deg; z-index: 2; animation-delay: -3s; }
.hero__stack-img--1 { left: 42%; top: 18%; --tilt: -2deg; z-index: 3; }

/* — Rotation de la pile (javascript.js, initPileHero) —
   Toutes les quatre secondes, les trois cartes changent de place d'un seul
   mouvement : celle de devant file vers le fond de l'éventail, les deux
   autres avancent d'un rang. Aucune ne sort de la pile. La place de chaque
   carte suit data-pos, qui l'emporte sur sa classe de départ ; sans
   JavaScript, les classes gardent la pile en place. */
.hero__stack-img[data-pos="3"] { left: 0;   top: 0;   --tilt: -9deg; z-index: 1; }
.hero__stack-img[data-pos="2"] { left: 21%; top: 9%;  --tilt:  3deg; z-index: 2; }
.hero__stack-img[data-pos="1"] { left: 42%; top: 18%; --tilt: -2deg; z-index: 3; }
/* La carte qui recule traverse les deux autres : en deux dimensions, elle
   ne peut passer derrière elles qu'en changeant de plan d'un coup. Elle
   s'estompe et rapetisse le temps de la bascule, qui se fait à mi-course,
   au moment où elle est la plus effacée — on lit un recul en profondeur,
   pas une carte qui disparaît. scale et non transform : il se compose avec
   le flottement au lieu de l'écraser. */
.hero__stack-img.is-recul { opacity: .3; scale: .9; }

/* L'éventail s'ouvre au survol */
.hero__stack:hover .hero__stack-img { animation-play-state: paused; }
.hero__stack:hover :is(.hero__stack-img--3:not([data-pos]), .hero__stack-img[data-pos="3"]) { transform: translate(-14%, -6%) rotate(-14deg); }
.hero__stack:hover :is(.hero__stack-img--2:not([data-pos]), .hero__stack-img[data-pos="2"]) { transform: translateY(-4%) rotate(2deg); }
.hero__stack:hover :is(.hero__stack-img--1:not([data-pos]), .hero__stack-img[data-pos="1"]) { transform: translate(14%, 6%) rotate(4deg); }
.hero__stack:hover .hero__stack-img { box-shadow: 0 40px 90px -20px rgba(0, 0, 0, .95); }

@keyframes floatCard {
  0%, 100% { transform: translateY(0)     rotate(var(--tilt)); }
  50%      { transform: translateY(-14px) rotate(var(--tilt)); }
}

.hero__scroll {
  position: absolute; bottom: 2rem; left: 50%; transform: translateX(-50%);
  display: flex; flex-direction: column; align-items: center; gap: .6rem;
  font-size: .7rem; text-transform: uppercase; letter-spacing: .18em;
  color: var(--text-mute); z-index: 1;
  transition: color var(--t-fast);
}
.hero__scroll:hover { color: var(--text); }
.hero__scroll-line {
  width: 1px; height: 46px; background: linear-gradient(var(--line-strong), transparent);
  position: relative; overflow: hidden;
}
.hero__scroll-line::after {
  content: ""; position: absolute; top: 0; left: 0; width: 100%; height: 40%;
  background: var(--text); animation: scrollLine 2.2s var(--ease-soft) infinite;
}


/* ==========================================================================
   07. MARQUEE
   ========================================================================== */
.marquee {
  border-block: 1px solid var(--line);
  padding-block: 1.35rem;
  overflow: hidden;
  background: var(--bg-alt);
  /* Fondu sur les bords */
  mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}
/* Le déplacement est piloté en JavaScript (voir initMarquee) pour pouvoir
   suivre la vitesse de défilement et s'inverser au scroll vers le haut. */
.marquee__track { display: flex; width: max-content; will-change: transform; }
.marquee__group {
  display: inline-flex; align-items: center; gap: 1.2rem;
  padding-right: 1.2rem; white-space: nowrap;
  font-size: clamp(1rem, 2vw, 1.4rem); font-weight: 600;
  letter-spacing: -.02em; color: var(--text-soft);
}
.marquee__group i { color: var(--accent); font-style: normal; }


/* ==========================================================================
   08. TITRES DE SECTION
   ========================================================================== */
.section__head { max-width: 62ch; margin-bottom: clamp(2.5rem, 6vw, 4.5rem); }

.section__eyebrow {
  display: inline-block;
  font-size: var(--fs-small); font-weight: 600; letter-spacing: .12em;
  text-transform: uppercase; color: var(--text-mute);
  margin-bottom: 1rem;
}
.section__title {
  font-size: var(--fs-h2); font-weight: 700;
  letter-spacing: -.045em; margin-bottom: 1rem;
}
.section__lead { color: var(--text-soft); font-size: var(--fs-lead); max-width: 52ch; }


/* ==========================================================================
   09. BENTO GRID (À propos)
   ========================================================================== */
.bento {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1rem;
}

.bento__card {
  display: flex; flex-direction: column;
  padding: clamp(1.5rem, 3vw, 2.25rem);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  position: relative; overflow: hidden;
  transition: transform var(--t), border-color var(--t), background var(--t);
}
/* Lueur qui suit le curseur (variables --mx/--my mises à jour en JS) */
.bento__card::before {
  content: ""; position: absolute; inset: 0;
  background: radial-gradient(420px circle at var(--mx, 50%) var(--my, 0%), var(--accent-soft), transparent 65%);
  opacity: 0; transition: opacity var(--t);
  pointer-events: none;
}
.bento__card:hover { transform: translateY(-4px); border-color: var(--line-strong); background: var(--surface-2); }
.bento__card:hover::before { opacity: 1; }

.bento__card--wide { grid-column: span 2; }
.bento__card > * { position: relative; z-index: 1; }

/* — Balayage lumineux au survol (façon « CC Light Sweep ») —
   Une bande claire inclinée traverse la carte. Elle passe au-dessus du
   contenu, comme un reflet, et l'overflow de la carte la découpe. */
.bento__card::after {
  content: "";
  position: absolute; inset: 0; z-index: 2;
  pointer-events: none;
  opacity: 0;
  background: linear-gradient(var(--sweep-angle, 105deg),
    transparent 38%,
    rgba(255, 255, 255, .05) 45%,
    rgba(255, 255, 255, .16) 50%,
    rgba(255, 255, 255, .05) 55%,
    transparent 62%);
}
.bento__card:hover::after,
.bento__card.is-sweeping::after {
  animation: var(--sweep, sweepLR) 1.6s var(--ease-soft);
}

/* Chaque carte reçoit sa propre direction : le reflet ne vient jamais
   deux fois du même côté quand on parcourt la section. */
.bento__card:nth-of-type(1) { --sweep: sweepLR;   --sweep-angle: 105deg; }
.bento__card:nth-of-type(2) { --sweep: sweepRL;   --sweep-angle:  75deg; }
.bento__card:nth-of-type(3) { --sweep: sweepTB;   --sweep-angle: 190deg; }
.bento__card:nth-of-type(4) { --sweep: sweepBT;   --sweep-angle: 170deg; }
.bento__card:nth-of-type(5) { --sweep: sweepDiag; --sweep-angle: 135deg; }

@keyframes sweepLR {
  0% { opacity: 0; transform: translateX(-100%); } 12% { opacity: 1; }
  88% { opacity: 1; } 100% { opacity: 0; transform: translateX(100%); }
}
@keyframes sweepRL {
  0% { opacity: 0; transform: translateX(100%); } 12% { opacity: 1; }
  88% { opacity: 1; } 100% { opacity: 0; transform: translateX(-100%); }
}
@keyframes sweepTB {
  0% { opacity: 0; transform: translateY(-100%); } 12% { opacity: 1; }
  88% { opacity: 1; } 100% { opacity: 0; transform: translateY(100%); }
}
@keyframes sweepBT {
  0% { opacity: 0; transform: translateY(100%); } 12% { opacity: 1; }
  88% { opacity: 1; } 100% { opacity: 0; transform: translateY(-100%); }
}
@keyframes sweepDiag {
  0% { opacity: 0; transform: translate(-90%, -90%); } 12% { opacity: 1; }
  88% { opacity: 1; } 100% { opacity: 0; transform: translate(90%, 90%); }
}
.bento__title { font-size: var(--fs-h3); margin-bottom: 1.1rem; letter-spacing: -.03em; }
.bento__card p { color: var(--text-soft); margin-bottom: .9rem; }
.bento__card p:last-of-type { margin-bottom: 0; }

/* — Intro de la bio, présentée comme un message de chat —
   Le portrait tient dans la colonne de gauche, le texte s'écoule à droite.
   Pour un portrait plus grand, augmenter les valeurs du clamp ci-dessous. */
.bio-intro { display: flex; align-items: center; gap: 1rem; margin-bottom: .9rem; }
.bio-intro__avatar {
  flex: 0 0 auto;
  width: clamp(52px, 5vw, 64px);
  aspect-ratio: 1;
  border-radius: 50%;
  object-fit: cover;
  border: 1px solid var(--line-strong);
  transition: transform var(--t);
}
.bio-intro__avatar:hover { transform: scale(1.06); }
.bio-intro p { margin-bottom: 0; }

@media (max-width: 640px) {
  .bio-intro { gap: .8rem; }
}

/* Repli générique : la rangée de grille passe de 0fr à 1fr, l'animation suit
   donc exactement la hauteur du contenu, sans max-height à deviner. */
.bio-panel { display: grid; grid-template-rows: 1fr; }
.bio-panel > * { min-height: 0; }
/* Boutons de repli, réservés au téléphone */
.bio-toggle {
  display: none;
  /* Enfant direct d'un conteneur flex : sans cela il s'étirerait sur toute
     la largeur, car `inline-flex` est « blockifié » en `flex`. */
  align-self: flex-start;
  align-items: center; gap: .5rem;
  padding: .6rem 1.1rem; margin-bottom: 1rem;
  border-radius: 99px; border: 1px solid var(--line-strong);
  font-size: .85rem; font-weight: 600; color: var(--text);
  transition: background var(--t-fast), border-color var(--t-fast);
}
.bio-toggle svg {
  width: 15px; height: 15px; fill: none; stroke: currentColor;
  stroke-width: 2; stroke-linecap: round; stroke-linejoin: round;
  transition: transform var(--t);
}
.bio-toggle:hover { background: rgba(255, 255, 255, .06); border-color: var(--text); }
.bio-toggle.is-open svg { transform: rotate(180deg); }
/* — Liste d'outils — */
.tools { display: flex; flex-direction: column; gap: .1rem; }
.tools li {
  display: flex; align-items: center; gap: .7rem;
  padding: .6rem 0; border-bottom: 1px solid var(--line);
  transition: padding-left var(--t-fast);
}
.tools li:last-child { border-bottom: 0; }
.tools li:hover { padding-left: .5rem; }
.tools__name { flex: 1; font-weight: 500; font-size: .95rem; }
.tools__tag { font-size: .75rem; color: var(--text-mute); letter-spacing: .02em; }

/* Logos des applications.
   Les logos Adobe et Figma sont des fichiers SVG (assets/outils/), redessinés
   d'après les icônes officielles fournies par Jérémy et partagés avec le CV ;
   DaVinci Resolve et CapCut restent dessinés en ligne en attendant les leurs. */
.tools__logo {
  flex: 0 0 auto;
  width: 24px; height: 24px;
  border-radius: 6px;
  display: grid; place-items: center;
  font-size: .6rem; font-weight: 700; letter-spacing: 0;
  background: var(--logo-bg); color: var(--logo-fg);
  border: 1px solid color-mix(in srgb, var(--logo-fg) 40%, transparent);
  transition: transform var(--t);
}
.tools li:hover .tools__logo { transform: scale(1.1); }
.tools__logo--img { border: 0; background: none; object-fit: contain; }

/* CapCut et DaVinci Resolve : pastilles provisoires, en attente des logos officiels */
.tools__logo--cc { --logo-bg: #0B0B0B; --logo-fg: #FFFFFF; }
.tools__logo--dr { --logo-bg: #16161A; --logo-fg: #E6E6EB; }

/* — Les trois métiers —
   Remplacent les anciennes barres de pourcentage : un niveau qu'on
   s'attribue soi-même se lit comme une estimation, pas comme une preuve.
   Une phrase par métier dit ce qu'il recouvre réellement. */
.metiers { list-style: none; margin: 0; padding: 0; display: grid; gap: 1.05rem; }
.metiers li { display: grid; gap: .3rem; }
.metiers b { font-size: .92rem; font-weight: 600; color: var(--text); }
.metiers span { font-size: .85rem; line-height: 1.55; color: var(--text-soft); }

/* — Informations complémentaires (langues, mobilité) —
   `margin-top: auto` colle le bloc en bas : il absorbe la hauteur libre
   quand la colonne voisine est plus longue. */
.facts {
  margin-top: auto; padding-top: 1.8rem;
  display: grid; gap: 1.3rem;
}
.facts__row { display: grid; gap: .5rem; }
.facts dt {
  font-size: .7rem; font-weight: 600; letter-spacing: .12em;
  text-transform: uppercase; color: var(--text-mute);
}
.facts dd {
  margin: 0; display: flex; align-items: baseline; gap: .5rem;
  font-size: .92rem; font-weight: 500; color: var(--text);
  padding-bottom: .5rem; border-bottom: 1px solid var(--line);
}
.facts__row dd:last-child { padding-bottom: 0; border-bottom: 0; }
.facts dd span {
  margin-left: auto; text-align: right;
  font-size: .78rem; font-weight: 400; color: var(--text-mute);
}

/* — Ce que je livre, en clôture du parcours —
   `margin-top: auto` absorbe la hauteur libre : la frise ne laisse plus
   de blanc quand la colonne voisine est plus longue. Sur deux colonnes
   pour ne pas faire une liste étirée sur toute la largeur de la carte. */
.livrables {
  margin: auto 0 0; padding-top: 1.7rem;
  border-top: 1px solid var(--line);
}
.livrables__label {
  margin: 0 0 1.1rem;
  font-size: .72rem; font-weight: 600; letter-spacing: .12em;
  text-transform: uppercase; color: var(--text-mute);
}
.livrables .checklist {
  grid-template-columns: repeat(2, 1fr);
  gap: .65rem 1.4rem;
}
@media (max-width: 560px) {
  .livrables .checklist { grid-template-columns: 1fr; }
}

/* — Témoignage client, en clôture du parcours —
   `margin-top: auto` le colle au bas de la carte : il absorbe la hauteur
   libre quand la colonne voisine est plus longue, au lieu de laisser un
   blanc sous la frise. */
.temoignage {
  margin: auto 0 0; padding-top: 1.7rem;
  border-top: 1px solid var(--line);
}
.temoignage blockquote {
  margin: 0; position: relative; padding-left: 1.1rem;
  font-size: .98rem; line-height: 1.65; color: var(--text);
}
/* Guillemet ouvrant en filigrane, posé dans la marge */
.temoignage blockquote::before {
  content: "«"; position: absolute; left: 0; top: -.1em;
  font-size: 1.4em; line-height: 1; color: var(--accent);
}
.temoignage figcaption {
  margin-top: .9rem; padding-left: 1.1rem;
  font-size: .82rem; font-weight: 500; color: var(--text-soft);
}
.temoignage figcaption span { font-weight: 400; color: var(--text-mute); }

/* — Timeline — */
.timeline { display: grid; gap: 1.75rem; }
/* Quand un bloc suit la frise (« Ce que je livre »), il garde toujours un
   écart avant son filet : son `margin-top: auto` tombe à zéro dès que la
   carte n'a plus de hauteur libre, et le texte venait alors toucher le trait. */
.timeline:not(:last-child) { margin-bottom: 1.8rem; }
.timeline__item { position: relative; padding-left: 1.6rem; }
.timeline__item::before {
  content: ""; position: absolute; left: 0; top: .45rem;
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--accent); box-shadow: 0 0 0 4px var(--accent-soft);
}
.timeline__item::after {
  content: ""; position: absolute; left: 3.5px; top: 1.4rem; bottom: -1.75rem;
  width: 1px; background: var(--line);
}
.timeline__item:last-child::after { display: none; }
.timeline__date { font-size: .75rem; text-transform: uppercase; letter-spacing: .1em; color: var(--text-mute); }
.timeline__item h4 { font-size: 1.05rem; margin: .3rem 0 .35rem; letter-spacing: -.02em; }
.timeline__item p { font-size: .92rem; color: var(--text-soft); margin: 0; }

/* — Checklist — */
.checklist { display: grid; gap: .65rem; }
.checklist li {
  display: flex; align-items: flex-start; gap: .6rem;
  font-size: .95rem; color: var(--text-soft);
}
.checklist li::before {
  content: "✓"; color: var(--accent-2);
  font-weight: 700; font-size: .85rem; line-height: 1.7;
}


/* ==========================================================================
   10. CARTES & GALERIES
   ========================================================================== */

/* — Note d'information sous une accroche de section —
   Discrète : c'est une précision, pas un avertissement. Le picto la
   distingue du texte courant sans l'alourdir. */
.section__note {
  display: flex; align-items: flex-start; gap: .55rem;
  margin-top: .9rem; max-width: 62ch;
  font-size: .85rem; line-height: 1.55; color: var(--text-mute);
}
.section__note svg {
  flex: 0 0 auto; width: 15px; height: 15px; margin-top: .18rem;
  fill: none; stroke: currentColor; stroke-width: 1.8;
  stroke-linecap: round; stroke-linejoin: round;
  opacity: .8;
}

/* — Grilles — */
.gallery { display: grid; gap: 1rem; margin-top: 2rem; }
/* Sauf sous la barre de flèches, qui porte déjà sa marge */
.section__controls + .gallery,
.section__controls + .videos { margin-top: 0; }

/* — Carrousels horizontaux (Photos, Vidéos et Graphisme) —
   Une seule rangée que l'on fait défiler latéralement. Le rembourrage
   vertical laisse la place au soulèvement des cartes au survol, sinon le
   conteneur de défilement les rognerait. */
.gallery--photos,
.gallery--grid,
.videos {
  display: flex;
  gap: 1rem;
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x proximity;
  padding: .75rem 0 1.35rem;
  scrollbar-width: none;
  overscroll-behavior-x: contain;
  /* Chaque cellule garde sa hauteur propre : sans cela, celle qui porte un
     bouton de charte étirerait les autres cartes et décollerait leur légende
     du bas de l'image. */
  align-items: flex-start;
}
.gallery--photos > .card,
.videos > .card,
.gallery--grid > .card,
.gallery--grid > .projet-charte {
  flex: 0 0 clamp(210px, 23vw, 290px);
  scroll-snap-align: start;
}
/* Le format paysage occupe environ deux cartes verticales */
.videos > .card--paysage { flex-basis: clamp(280px, 50vw, 620px); }

/* — Barre de défilement des carrousels —
   La barre native dépend du système : sur macOS elle se cache, ailleurs elle
   s'impose, et son apparence nous échappe. On la retire au profit d'une barre
   à nous, toujours visible, saisissable et accordée au thème. */
.gallery--photos::-webkit-scrollbar,
.gallery--grid::-webkit-scrollbar,
.videos::-webkit-scrollbar { display: none; }

.carousel-bar {
  position: relative;
  height: 4px; border-radius: 99px;
  background: rgba(255, 255, 255, .08);
  margin-top: .35rem;
  cursor: pointer;
  touch-action: none;
  transition: height var(--t-fast), opacity var(--t), background var(--t-fast);
}
.carousel-bar:hover,
.carousel-bar.is-grabbing { height: 6px; background: rgba(255, 255, 255, .12); }
/* Rien à faire défiler : la barre s'efface plutôt que de mentir */
.carousel-bar.is-inutile { opacity: 0; pointer-events: none; }

.carousel-bar__thumb {
  position: absolute; top: 0; left: 0; height: 100%;
  width: var(--bar-w, 25%);
  border-radius: 99px;
  background: var(--gradient);
  transform: translateX(var(--bar-x, 0px));
  transition: transform .1s linear;
}
/* Pendant la saisie, la moindre transition donnerait l'impression que la
   barre traîne derrière le doigt. */
.carousel-bar.is-grabbing .carousel-bar__thumb { transition: none; }

/* Au doigt, 4 px de haut sont impossibles à saisir : on épaissit la zone
   sensible sans changer l'apparence, grâce au fond limité au contenu.
   Ce bloc vient après la définition du curseur : la cascade exige que la
   surcharge soit déclarée en dernier. */
@media (hover: none) {
  .carousel-bar {
    height: 22px; padding: 9px 0;
    background-clip: content-box;
    background-color: rgba(255, 255, 255, .08);
    margin-top: .1rem;
  }
  .carousel-bar:hover, .carousel-bar.is-grabbing { height: 22px; }
  .carousel-bar__thumb { top: 9px; height: 4px; }
}

/* — Projet accompagné d'un document —
   Charte graphique ou dossier de présentation selon le projet. La carte et
   son bouton occupent une même cellule de la grille : le bouton se place
   sous la vignette sans se glisser dans la carte, dont la légende est calée
   en bas et qu'il déplacerait. */
.projet-charte { display: flex; flex-direction: column; gap: .7rem; }
.doc-lien {
  justify-content: center;
  width: 100%;
  font-size: .82rem;
  padding: .7rem 1rem;
}
.doc-lien svg {
  width: 15px; height: 15px; flex: 0 0 auto;
  fill: none; stroke: currentColor; stroke-width: 2;
  stroke-linecap: round; stroke-linejoin: round;
}

/* Ratios natifs des médias : 2:3 pour la photo, 9:16 pour la vidéo verticale */
.card--photo .card__media,
.card--graphic .card__media { height: auto; aspect-ratio: 2 / 3; }
.card--video .card__media { height: auto; aspect-ratio: 9 / 16; }
/* — Carte au format paysage —
   Un film paysage glissé dans une carte verticale perdrait les deux tiers de
   chaque plan : elle est donc plus large et moins haute que les autres.
   Le rapport suit exactement celui du fichier (1920x1012, le film est étalonné
   en 1.90:1), pour qu'aucune bande noire n'apparaisse au-dessus ni en dessous. */
.card--paysage .card__media { aspect-ratio: 480 / 253; }

/* Le conteneur <picture> ne sert qu'à proposer le WebP : on le rend
   transparent pour la mise en page, l'image reste l'enfant direct. */
picture { display: contents; }

/* — Carte générique — */
.card {
  position: relative;
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--surface);
  border: 1px solid var(--line);
  isolation: isolate;
  transition: transform var(--t), border-color var(--t), box-shadow var(--t), opacity var(--t);
  will-change: transform;
}
.card:hover { transform: translateY(-6px); border-color: var(--line-strong); box-shadow: var(--shadow-lg); }

.card__media {
  position: relative;
  width: 100%; height: 100%;
  overflow: hidden;
  /* Dégradé de secours visible tant qu'aucune image n'est fournie */
  background:
    radial-gradient(120% 120% at 20% 10%, rgba(124, 107, 255, .35), transparent 55%),
    radial-gradient(120% 120% at 85% 90%, rgba(74, 217, 255, .28), transparent 55%),
    #14141A;
}
.card__media img,
.card__media video {
  width: 100%; height: 100%;
  object-fit: cover;
  transition: transform .9s var(--ease), filter var(--t), opacity var(--t);
  filter: saturate(.92) brightness(.92);
}
/* — Calques du diaporama de carte —
   Ils se superposent à la couverture, qui reste en place dessous : la liste
   lue par la visionneuse n'est jamais modifiée. Le zoom au survol et le
   recadrage viennent de la règle .card__media img juste au-dessus. */
.card__slide {
  position: absolute; inset: 0;
  opacity: 0;
  transition: opacity .7s var(--ease), transform .9s var(--ease),
              filter var(--t);
}
.card__slide.is-shown { opacity: 1; }

/* Zoom fluide au survol */
.card:hover .card__media img,
.card:hover .card__media video { transform: scale(1.07); filter: saturate(1.05) brightness(1); }

/* Voile dégradé pour la lisibilité de la légende */
.card__media::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(to top, rgba(6, 6, 8, .92) 0%, rgba(6, 6, 8, .35) 42%, transparent 70%);
  opacity: .85; transition: opacity var(--t);
}
.card:hover .card__media::after { opacity: 1; }

/* Message affiché si l'image n'est pas encore déposée (ajouté par le JS) */
.media-fallback {
  position: absolute; inset: 0; z-index: 1;
  display: grid; place-content: center; place-items: center; gap: .4rem;
  text-align: center; padding: 1rem;
  font-size: .72rem; letter-spacing: .12em; text-transform: uppercase;
  color: rgba(255, 255, 255, .55);
}
.media-fallback b { font-size: 1.4rem; letter-spacing: -.02em; text-transform: none; color: rgba(255, 255, 255, .85); }

/* — Légende — */
.card__caption {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 2;
  padding: 1.35rem;
  transform: translateY(8px);
  transition: transform var(--t);
}
.card:hover .card__caption { transform: translateY(0); }

.card__tag {
  display: inline-block; margin-bottom: .5rem;
  padding: .25rem .6rem; border-radius: 99px;
  background: rgba(255, 255, 255, .12);
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
  font-size: .68rem; font-weight: 600; letter-spacing: .06em; text-transform: uppercase;
}
/* Les intitulés sont en capitales : on desserre légèrement le crénage */
.card__title { font-size: 1.12rem; letter-spacing: .005em; margin-bottom: .2rem; }
.card__meta {
  font-size: .8rem; color: var(--text-soft);
  opacity: 0; transform: translateY(6px);
  transition: opacity var(--t), transform var(--t);
}
.card:hover .card__meta { opacity: 1; transform: translateY(0); }

/* — Bouton loupe (photos / graphisme) — */
.card__zoom {
  position: absolute; top: 1rem; right: 1rem; z-index: 3;
  width: 40px; height: 40px; border-radius: 50%;
  display: grid; place-items: center;
  background: rgba(255, 255, 255, .12);
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
  border: 1px solid rgba(255, 255, 255, .18);
  opacity: 0; transform: scale(.7);
  transition: opacity var(--t), transform var(--t), background var(--t-fast);
}
.card__zoom svg { width: 16px; height: 16px; fill: none; stroke: #fff; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.card:hover .card__zoom { opacity: 1; transform: scale(1); }
.card__zoom:hover { background: rgba(255, 255, 255, .25); }

/* — Calque poster des vidéos —
   Le navigateur n'affiche l'attribut poster que tant que la lecture n'a jamais
   démarré : après un survol, la carte montrerait sinon la première image du
   fichier (souvent un carton-titre). Ce calque garantit une vignette stable. */
.card__poster {
  position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover;
  transition: opacity .4s var(--ease), transform .9s var(--ease), filter var(--t);
}
.card--video.is-playing .card__poster { opacity: 0; }

/* — Pastille d'audience (cartes vidéo) — */
/* — Pastilles d'en-tête (durée, portée) —
   Regroupées dans un même conteneur : posées chacune en absolu, elles se
   superposeraient sur les cartes qui portent les deux. */
.card__badges {
  position: absolute; top: 1rem; left: 1rem; z-index: 3;
  margin: 0; display: flex; flex-wrap: wrap; gap: .4rem;
}
.card__duree {
  padding: .3rem .7rem; border-radius: 99px;
  background: rgba(6, 6, 8, .55);
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
  border: 1px solid rgba(255, 255, 255, .16);
  font-size: .72rem; font-weight: 600; letter-spacing: .02em;
  font-variant-numeric: tabular-nums; color: var(--text-soft);
}
.card__reach {
  padding: .3rem .7rem; border-radius: 99px;
  background: rgba(255, 255, 255, .14);
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
  border: 1px solid rgba(255, 255, 255, .2);
  font-size: .72rem; font-weight: 700; letter-spacing: .02em;
  font-variant-numeric: tabular-nums;
}

/* — Contrôles des cartes vidéo : son et grand écran — */
.card__controls {
  position: absolute; top: 1rem; right: 1rem; z-index: 4;
  display: flex; gap: .4rem;
  opacity: 0; transform: translateY(-6px);
  transition: opacity var(--t), transform var(--t);
}
.card--video:hover .card__controls,
.card--video:focus-within .card__controls { opacity: 1; transform: translateY(0); }

.card__ctrl {
  width: 36px; height: 36px; border-radius: 50%;
  display: grid; place-items: center;
  background: rgba(0, 0, 0, .5);
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
  border: 1px solid rgba(255, 255, 255, .18);
  transition: background var(--t-fast), transform var(--t-fast);
}
.card__ctrl:hover { background: rgba(255, 255, 255, .24); transform: scale(1.08); }
/* Au doigt : 36 px sont sous le seuil de confort tactile (44 px). */
@media (hover: none) {
  .card__ctrl { width: 44px; height: 44px; }
}
.card__ctrl svg {
  width: 16px; height: 16px; fill: none; stroke: #fff;
  stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round;
}
/* Bascule d'icône selon l'état du son */
.card__sound .icon-sound-on  { display: none; }
.card__sound .icon-sound-off { display: block; }
.card__sound.is-on .icon-sound-on  { display: block; }
.card__sound.is-on .icon-sound-off { display: none; }

/* — Repères du diaporama —
   Une barre segmentée en bas de carte : un segment par photo, celui en cours
   se remplit sur les 2 secondes du cycle. Elle dit d'un coup d'œil qu'il y a
   une série derrière la vignette, et où l'on en est. */
.card__steps {
  position: absolute; left: 1rem; right: 1rem; bottom: .65rem; z-index: 4;
  display: flex; gap: 3px; pointer-events: none;
}
.card__step {
  flex: 1; height: 2px; border-radius: 2px;
  background: rgba(255, 255, 255, .25);
  overflow: hidden;
  transition: background var(--t-fast);
}
/* Les vues déjà passées restent marquées */
.card__step.is-done { background: rgba(255, 255, 255, .6); }
/* La vue en cours se remplit au rythme du diaporama */
.card__step.is-on::after {
  content: ""; display: block; height: 100%; width: 100%;
  background: #fff; transform-origin: left;
  animation: stepFill 2s linear both;
}

/* — Attente de la vidéo —
   Les aperçus démarrent au défilement et pèsent parfois plusieurs dizaines
   de Mo : sans ce voile, le poster reste figé sans rien annoncer. */
.card--video .card__media::before {
  content: ""; position: absolute; inset: 0; z-index: 1;
  opacity: 0; pointer-events: none;
  background: linear-gradient(105deg,
    transparent 40%, rgba(255, 255, 255, .13) 50%, transparent 60%);
  background-size: 260% 100%;
  transition: opacity var(--t);
}
.card--video.is-buffering .card__media::before {
  opacity: 1;
  animation: bufferSweep 1.4s var(--ease-soft) infinite;
}

/* — Pastille « n photos » (cartes projet) — */
.card__count {
  position: absolute; top: 1rem; left: 1rem; z-index: 3;
  padding: .3rem .7rem; border-radius: 99px;
  background: rgba(0, 0, 0, .5);
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
  border: 1px solid rgba(255, 255, 255, .14);
  font-size: .72rem; font-weight: 600; letter-spacing: .02em;
  opacity: 0; transform: translateY(-6px);
  transition: opacity var(--t), transform var(--t);
}
.card:hover .card__count { opacity: 1; transform: translateY(0); }

/* Les vues supplémentaires d'un projet ne sont jamais rendues dans la page */
.card__set { display: none; }

/* — Bouton play (vidéos) — */
.card__play {
  position: absolute; top: 50%; left: 50%; z-index: 3;
  width: 72px; height: 72px; border-radius: 50%;
  display: grid; place-items: center;
  background: rgba(255, 255, 255, .14);
  backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
  border: 1px solid rgba(255, 255, 255, .22);
  transform: translate(-50%, -50%) scale(.82);
  opacity: .75;
  transition: transform var(--t), opacity var(--t), background var(--t-fast);
}
.card__play svg { width: 26px; height: 26px; fill: #fff; margin-left: 3px; }
.card--video:hover .card__play { transform: translate(-50%, -50%) scale(1); opacity: 1; background: rgba(255, 255, 255, .22); }
/* Anneau pulsé autour du play */
.card__play::after {
  content: ""; position: absolute; inset: -1px; border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, .35);
  animation: ring 2.6s var(--ease-soft) infinite;
}
/* Quand la vidéo est réellement en lecture, le play s'efface */
.card--video.is-playing .card__play { opacity: 0; transform: translate(-50%, -50%) scale(1.4); }

/* — Barre de lecture des aperçus —
   Remplace le badge de secondes : la progression se lit d'un coup d'œil,
   au même endroit et dans le même langage que les repères des cartes photo. */
.card__progress {
  position: absolute; left: 1rem; right: 1rem; bottom: .65rem; z-index: 4;
  height: 2px; border-radius: 2px;
  background: rgba(255, 255, 255, .25);
  overflow: hidden;
  opacity: 0; transition: opacity var(--t);
}
/* Elle n'apparaît que lorsque l'aperçu tourne */
.card--video.is-playing .card__progress { opacity: 1; }
.card__progress span {
  display: block; height: 100%; width: 100%;
  background: #fff; transform-origin: left;
  transform: scaleX(0);
}

/* Le bouton play se décale vers le haut pour ne pas heurter la légende */
.card--video .card__play { top: 42%; }


/* ==========================================================================
   11. FLÈCHES DE CARROUSEL
   ========================================================================== */
/* Flèches de défilement, alignées à droite au-dessus du carrousel */
.section__controls {
  display: flex; align-items: center; justify-content: flex-end;
  gap: 1rem 1.5rem; flex-wrap: wrap;
  margin-bottom: clamp(.75rem, 2vw, 1rem);
}
/* Photos et Vidéos glissent cette rangée entre le chapeau et la galerie.
   Sans compensation l'écart y doublait (144 px contre 72 ailleurs) : la
   rangée prend sa place dans la marge du chapeau au lieu de s'y ajouter. */
.section__head:has(+ .section__controls) {
  margin-bottom: clamp(1.25rem, 3vw, 1.75rem);
}
/* — Flèches des carrousels —
   Indispensables : sur macOS la barre de défilement est en surimpression et
   ne s'affiche que pendant le geste, rien n'indiquerait qu'on peut défiler. */
.carousel-nav { display: flex; gap: .5rem; flex: 0 0 auto; }
.carousel-nav__btn {
  width: 40px; height: 40px; border-radius: 50%;
  display: grid; place-items: center;
  border: 1px solid var(--line-strong);
  color: var(--text);
  transition: background var(--t-fast), border-color var(--t-fast),
              transform var(--t-fast), opacity var(--t-fast);
}
.carousel-nav__btn svg {
  width: 18px; height: 18px; fill: none; stroke: currentColor;
  stroke-width: 2; stroke-linecap: round; stroke-linejoin: round;
}
.carousel-nav__btn:hover:not(:disabled) {
  background: rgba(255, 255, 255, .08);
  border-color: var(--text);
  transform: scale(1.06);
}
.carousel-nav__btn:disabled { opacity: .3; cursor: default; }

/* Au doigt, le glissement suffit : la barre n'ayant plus que les flèches,
   on retire le conteneur entier pour ne pas laisser une marge orpheline. */
@media (hover: none) {
  .carousel-nav,
  .section__controls { display: none; }
  /* La rangée masquée ne compense plus rien : marge d'origine */
  .section__head:has(+ .section__controls) { margin-bottom: clamp(2.5rem, 6vw, 4.5rem); }
}

/* ==========================================================================
   12. CONTACT & FOOTER
   ========================================================================== */
.contact { text-align: center; position: relative; overflow: hidden; }
.contact::before {
  content: ""; position: absolute; top: 20%; left: 50%; transform: translateX(-50%);
  width: 60vw; height: 60vw; max-width: 900px; max-height: 900px;
  background: var(--accent); filter: blur(160px); opacity: .16; border-radius: 50%;
  pointer-events: none;
}
.contact__inner { position: relative; z-index: 1; display: flex; flex-direction: column; align-items: center; }
.contact__title {
  font-size: clamp(2.25rem, 7vw, 5.5rem);
  letter-spacing: -.05em; margin-bottom: 1.25rem;
}
.contact__text { color: var(--text-soft); font-size: var(--fs-lead); max-width: 46ch; margin-bottom: 2.5rem; }

/* Texte réservé aux lecteurs d'écran */
.visuellement-cache {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  clip-path: inset(50%); overflow: hidden; white-space: nowrap;
}


/* ==========================================================================
   12 bis. FORMULAIRE DE CONTACT
   Les envois passent par Netlify Forms : aucun serveur à tenir. Les libellés
   flottent au-dessus du champ dès qu'il est rempli ou actif, et un trait se
   déploie sous le champ en cours de saisie.
   ========================================================================== */
.formulaire {
  width: 100%; max-width: 620px;
  margin: 2.5rem auto 0;
  display: grid; gap: 1.15rem;
  grid-template-columns: 1fr 1fr;
  text-align: left;
  position: relative;
}
/* Le leurre à robots ne doit être vu de personne, ni atteint au clavier */
.formulaire__leurre { position: absolute; left: -9999px; opacity: 0; pointer-events: none; }

.champ { position: relative; grid-column: span 1; }
.champ--large, .formulaire__envoi { grid-column: 1 / -1; }

.champ input,
.champ select,
.champ textarea {
  width: 100%;
  padding: 1.5rem 1rem .7rem;
  border-radius: var(--radius-sm, 12px);
  border: 1px solid var(--line);
  background: rgba(255, 255, 255, .03);
  color: var(--text);
  font: inherit; font-size: .95rem;
  transition: border-color var(--t-fast), background var(--t-fast);
}
.champ textarea { resize: vertical; min-height: 130px; line-height: 1.6; }
.champ select { appearance: none; cursor: pointer; }
/* Chevron du menu déroulant, dessiné en CSS pour rester dans les 3 fichiers */
.champ--choix::after {
  content: ""; position: absolute; right: 1.1rem; top: 58%;
  width: 8px; height: 8px; pointer-events: none;
  border-right: 2px solid var(--text-soft);
  border-bottom: 2px solid var(--text-soft);
  transform: translateY(-50%) rotate(45deg);
}
.champ input:hover, .champ select:hover, .champ textarea:hover { border-color: var(--line-strong); }
.champ input:focus, .champ select:focus, .champ textarea:focus {
  outline: none;
  border-color: var(--line-strong);
  background: rgba(255, 255, 255, .05);
}

/* Libellé flottant : il monte quand le champ est actif ou déjà rempli */
.champ label {
  position: absolute; left: 1rem; top: 1.05rem;
  font-size: .95rem; color: var(--text-mute);
  pointer-events: none;
  transform-origin: left top;
  transition: transform var(--t-fast), color var(--t-fast);
}
.champ input:focus + label,
.champ input:not(:placeholder-shown) + label,
.champ textarea:focus + label,
.champ textarea:not(:placeholder-shown) + label,
.champ select:focus + label,
.champ--choix label {
  transform: translateY(-.72rem) scale(.78);
  color: var(--text-soft);
}

/* Trait qui se déploie sous le champ actif */
.champ__trait {
  position: absolute; left: 1rem; right: 1rem; bottom: 0; height: 2px;
  background: var(--gradient); border-radius: 2px;
  transform: scaleX(0); transform-origin: left;
  transition: transform .45s var(--ease);
}
.champ input:focus ~ .champ__trait,
.champ select:focus ~ .champ__trait,
.champ textarea:focus ~ .champ__trait { transform: scaleX(1); }

/* Signalement d'erreur, posé par le JavaScript après une tentative d'envoi */
.champ.est-invalide input,
.champ.est-invalide textarea { border-color: #E2545C; }
.champ.est-invalide label { color: #E2545C; }

/* — Bouton d'envoi —
   Pendant l'envoi il se vide de son texte et laisse tourner un anneau. */
.formulaire__envoi {
  justify-content: center; gap: .6rem;
  margin-top: .35rem;
  position: relative; overflow: hidden;
}
.formulaire__fleche {
  width: 17px; height: 17px; fill: none; stroke: currentColor;
  stroke-width: 2; stroke-linecap: round; stroke-linejoin: round;
  transition: transform var(--t-fast);
}
.formulaire__envoi:hover .formulaire__fleche { transform: translateX(4px); }
.formulaire__libelle, .formulaire__fleche { transition: opacity var(--t-fast), transform var(--t-fast); }
.formulaire__rond {
  position: absolute; top: 50%; left: 50%;
  width: 18px; height: 18px; margin: -9px 0 0 -9px;
  border: 2px solid currentColor; border-top-color: transparent;
  border-radius: 50%;
  opacity: 0;
}
.formulaire.est-envoi .formulaire__libelle,
.formulaire.est-envoi .formulaire__fleche { opacity: 0; transform: translateY(6px); }
.formulaire.est-envoi .formulaire__rond { opacity: 1; animation: tourne .7s linear infinite; }
.formulaire.est-envoi .formulaire__envoi { pointer-events: none; }

/* — Confirmation —
   Le formulaire s'efface et la coche se trace à sa place. */
.formulaire__reussi {
  grid-column: 1 / -1;
  display: grid; justify-items: center; gap: .5rem;
  padding: 2.5rem 1rem;
  text-align: center;
}
.formulaire__reussi[hidden] { display: none; }
.formulaire__coche {
  width: 58px; height: 58px; border-radius: 50%;
  display: grid; place-items: center;
  border: 2px solid var(--accent-2);
  animation: popCentre .45s var(--ease) both;
}
.formulaire__coche svg {
  width: 28px; height: 28px; fill: none; stroke: var(--accent-2);
  stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round;
  stroke-dasharray: 30; stroke-dashoffset: 30;
  animation: traceCoche .5s var(--ease) .18s forwards;
}
.formulaire__merci { font-size: 1.15rem; font-weight: 700; letter-spacing: -.02em; }
.formulaire__suite { color: var(--text-soft); font-size: .92rem; }

/* Les champs disparaissent une fois l'envoi confirmé */
.formulaire.est-reussi .champ,
.formulaire.est-reussi .formulaire__envoi { display: none; }

.formulaire__etat {
  grid-column: 1 / -1;
  margin: 0; font-size: .88rem; color: #E2545C; text-align: center;
}
.formulaire__etat:empty { display: none; }

/* — Alerte d'envoi —
   Même mécanique que la visionneuse : l'attribut hidden coupe l'affichage,
   la classe is-open déclenche l'entrée. La croix se trace trait par trait,
   en écho à la coche de confirmation. */
.alerte {
  position: fixed; inset: 0; z-index: 980;
  display: grid; place-items: center;
  padding: clamp(1rem, 5vw, 2rem);
  background: rgba(6, 6, 8, .82);
  backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px);
  opacity: 0;
  transition: opacity .32s var(--ease);
}
.alerte[hidden] { display: none; }
.alerte.is-open { opacity: 1; }

.alerte__boite {
  position: relative;
  width: min(420px, 100%);
  padding: 2.75rem 1.9rem 2rem;
  border-radius: var(--radius);
  background: var(--surface);
  border: 1px solid var(--line-strong);
  box-shadow: var(--shadow-lg);
  text-align: center;
  display: grid; justify-items: center; gap: .7rem;
  transform: scale(.9) translateY(14px);
  opacity: 0;
  transition: transform .42s var(--ease), opacity .32s var(--ease);
}
.alerte.is-open .alerte__boite { transform: none; opacity: 1; }

.alerte__fermer {
  position: absolute; top: .8rem; right: .8rem;
  width: 32px; height: 32px; border-radius: 50%;
  display: grid; place-items: center;
  color: var(--text-mute);
  transition: color var(--t-fast), background var(--t-fast);
}
.alerte__fermer svg {
  width: 15px; height: 15px; fill: none; stroke: currentColor;
  stroke-width: 2; stroke-linecap: round;
}
.alerte__fermer:hover { color: var(--text); background: rgba(255, 255, 255, .07); }

/* — La croix —
   Le cercle apparaît d'abord, puis les deux traits se dessinent l'un après
   l'autre : le geste dit « erreur » avant même qu'on lise le titre. */
.alerte__croix {
  width: 62px; height: 62px; border-radius: 50%;
  display: grid; place-items: center;
  border: 2px solid #E2545C;
  margin-bottom: .35rem;
}
.alerte__croix svg {
  width: 30px; height: 30px; fill: none; stroke: #E2545C;
  stroke-width: 2.4; stroke-linecap: round;
}
.alerte__croix path { stroke-dasharray: 20; stroke-dashoffset: 20; }

.alerte.is-open .alerte__croix { animation: popCentre .45s var(--ease) .1s both; }
.alerte.is-open .croix__trait-1 { animation: traceCroix .28s var(--ease) .34s forwards; }
.alerte.is-open .croix__trait-2 { animation: traceCroix .28s var(--ease) .56s forwards; }

.alerte__titre { font-size: 1.2rem; font-weight: 700; letter-spacing: -.02em; }
.alerte__texte { color: var(--text-soft); font-size: .92rem; line-height: 1.55; }
/* L'adresse et son bouton de copie sur une même ligne : on peut écrire
   d'un clic, ou emporter l'adresse ailleurs. */
.alerte__contact {
  display: flex; align-items: center; justify-content: center;
  gap: .5rem; width: 100%;
  margin-top: .6rem;
}
.alerte__mail { word-break: break-word; font-size: .92rem; flex: 0 1 auto; }
.alerte__astuce {
  margin-top: -.25rem;
  font-size: .78rem; color: var(--text-mute);
}

.alerte__copier {
  flex: 0 0 auto;
  width: 42px; height: 42px; border-radius: 50%;
  display: grid; place-items: center;
  border: 1px solid var(--line);
  color: var(--text-soft);
  transition: color var(--t-fast), border-color var(--t-fast), background var(--t-fast);
}
.alerte__copier:hover {
  color: var(--text); border-color: var(--line-strong);
  background: rgba(255, 255, 255, .06);
}
/* Les deux icônes se superposent, une seule est visible à la fois */
.alerte__copier-icones { position: relative; width: 17px; height: 17px; }
.alerte__copier-icones svg {
  position: absolute; inset: 0; width: 17px; height: 17px;
  fill: none; stroke: currentColor; stroke-width: 2;
  stroke-linecap: round; stroke-linejoin: round;
  transition: opacity var(--t-fast), transform var(--t-fast);
}
.alerte__copier .icone-fait { opacity: 0; transform: scale(.6); }
.alerte__copier.is-done { color: var(--accent-2); border-color: var(--accent-2); }
.alerte__copier.is-done .icone-copier { opacity: 0; transform: scale(.6); }
.alerte__copier.is-done .icone-fait   { opacity: 1; transform: scale(1); }
.alerte__reessayer {
  font-size: .85rem; color: var(--text-mute);
  text-decoration: underline; text-underline-offset: 3px;
  transition: color var(--t-fast);
}
.alerte__reessayer:hover { color: var(--text); }

/* Sur écran étroit, l'adresse se coupait en plein milieu d'un mot : on
   resserre la boîte et le bouton pour qu'elle tienne sur une ligne. */
@media (max-width: 420px) {
  .alerte__boite { padding: 2.5rem 1.15rem 1.75rem; }
  /* Zones tactiles portées au seuil de confort */
  .alerte__fermer { width: 44px; height: 44px; top: .4rem; right: .4rem; }
  .alerte__mail {
    padding: .85rem .9rem;
    font-size: .8rem;
    word-break: normal;
  }
  .alerte__copier { width: 44px; height: 44px; }
  .alerte__contact { gap: .4rem; }
}

/* Repli : l'adresse reste accessible si le formulaire échoue */
.contact__repli {
  margin-top: 1.4rem;
  font-size: .88rem; color: var(--text-mute);
}
.contact__repli a { color: var(--text-soft); text-decoration: underline; text-underline-offset: 3px; }
.contact__repli a:hover { color: var(--text); }

@media (max-width: 620px) {
  .formulaire { grid-template-columns: 1fr; }
  /* 16 px exactement : en dessous, Safari iOS agrandit la page dès qu'on
     touche un champ, et la mise en page saute sous les doigts. */
  .champ input, .champ select, .champ textarea { font-size: 16px; }
}

.contact__cv { margin-top: 1.75rem; }
.contact__links { display: flex; flex-wrap: wrap; justify-content: center; gap: 1.75rem; margin-top: 2.5rem; }
.contact__links a {
  position: relative; font-size: .9rem; font-weight: 500; color: var(--text-soft);
  transition: color var(--t-fast);
}
.contact__links a::after {
  content: ""; position: absolute; left: 0; bottom: -4px;
  width: 100%; height: 1px; background: currentColor;
  transform: scaleX(0); transform-origin: right;
  transition: transform var(--t);
}
.contact__links a:hover { color: var(--text); }
.contact__links a:hover::after { transform: scaleX(1); transform-origin: left; }

/* Logo du réseau devant le nom : même couleur que le texte, qui s'éclaire
   avec lui au survol. Le soulignement démarre après l'icône, sous le mot. */
.contact__links a:has(svg) { display: inline-flex; align-items: center; gap: .55rem; }
.contact__links a:has(svg)::after { left: calc(1.15em + .55rem); width: auto; right: 0; }
.contact__links svg {
  width: 1.15em; height: 1.15em; flex: 0 0 auto;
  fill: none; stroke: currentColor; stroke-width: 2;
}
.contact__links svg .plein { fill: currentColor; stroke: none; }

.footer { border-top: 1px solid var(--line); padding-block: 2.5rem; }
.footer__inner {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: 1rem;
}
/* — Signature du pied de page : logo + nom + accroche — */
.footer__brand { display: flex; align-items: center; gap: 1rem; }
.footer__logo { height: 44px; width: auto; flex: 0 0 auto; color: var(--text); }
.footer__brand-text {
  display: flex; flex-direction: column; gap: .25rem;
  padding-left: 1rem; border-left: 1px solid var(--line-strong);
}
.footer__brand-name { font-size: 1rem; font-weight: 700; letter-spacing: -.03em; }
.footer__brand-baseline {
  font-size: .66rem; letter-spacing: .24em; text-transform: uppercase; color: var(--text-mute);
}
.footer__legal { text-align: right; }
.footer__copy, .footer__note { font-size: var(--fs-small); color: var(--text-mute); }
/* Liens légaux : présents sans tirer l'œil, soulignés au survol seulement */
.footer__liens { font-size: var(--fs-small); color: var(--text-mute); margin-top: .35rem; }
.footer__liens a { color: var(--text-mute); transition: color var(--t-fast); }
.footer__liens a:hover { color: var(--text); text-decoration: underline; text-underline-offset: 3px; }
.footer__liens span { margin-inline: .35rem; opacity: .5; }

@media (max-width: 640px) {
  .footer__legal { text-align: center; }
}
.footer__top {
  width: 42px; height: 42px; border-radius: 50%;
  border: 1px solid var(--line);
  display: grid; place-items: center;
  transition: transform var(--t), border-color var(--t-fast), background var(--t-fast);
}
.footer__top svg { width: 17px; height: 17px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.footer__top:hover { transform: translateY(-4px); border-color: var(--text); background: rgba(255, 255, 255, .05); }


/* ==========================================================================
   13. LIGHTBOX
   ========================================================================== */
.lightbox {
  position: fixed; inset: 0; z-index: 950;
  display: grid; grid-template-columns: auto 1fr auto; align-items: center;
  gap: clamp(.5rem, 3vw, 2rem);
  padding: clamp(1rem, 5vw, 3rem);
  background: rgba(6, 6, 8, .88);
  backdrop-filter: blur(18px); -webkit-backdrop-filter: blur(18px);
  opacity: 0; transition: opacity var(--t);
}
/* L'attribut [hidden] doit l'emporter sur le display:grid ci-dessus */
.lightbox[hidden] { display: none; }
.lightbox.is-open { opacity: 1; }

.lightbox__figure {
  grid-column: 2; display: flex; flex-direction: column;
  align-items: center; gap: 1rem;
  max-height: 100%;
}
.lightbox__media {
  border-radius: var(--radius); overflow: hidden;
  display: grid; place-items: center;
  position: relative;
  transform: scale(.94); opacity: 0;
  transition: transform .5s var(--ease), opacity .35s var(--ease);
}
.lightbox.is-open .lightbox__media { transform: scale(1); opacity: 1; }
/* Pendant le morphing, la mise à l'échelle du cadre ferait doublon avec le
   trajet calculé par le navigateur : on la neutralise le temps du passage. */
.lightbox.is-morphing .lightbox__media {
  transition: none; transform: none; opacity: 1;
}
/* Fondu-glissé au changement de photo : l'ancienne sort dans le sens de la
   navigation, la nouvelle entre par le côté opposé. */
.lightbox__media img {
  transition: opacity .19s var(--ease-soft), transform .19s var(--ease-soft);
}
/* — Loupe —
   Au repos l'image invite au zoom ; agrandie, elle se déplace au glissement.
   Pendant le glissement on coupe la transition, sinon l'image traîne. */
.lightbox__media { cursor: zoom-in; touch-action: pan-y; }
.lightbox__media.is-zoomed { cursor: grab; touch-action: none; }
.lightbox__media.is-zoomed img { transform-origin: 0 0; will-change: transform; }
.lightbox__media.is-dragging { cursor: grabbing; }
.lightbox__media.is-dragging img { transition: none; }
.lightbox__media.is-sortie img {
  opacity: 0;
  transform: translateX(calc(var(--dir, 1) * -26px));
}
.lightbox__media.is-entree img {
  opacity: 0;
  transform: translateX(calc(var(--dir, 1) * 26px));
  transition: none;
}

/* Le cadre épouse exactement la photo, quel que soit son format */
.lightbox__media img {
  max-height: 76vh; max-width: min(100%, 92vw);
  width: auto; height: auto; object-fit: contain;
}
/* Cadre de secours, uniquement si la photo n'est pas encore fournie */
.lightbox.is-empty .lightbox__media {
  min-width: min(420px, 80vw); min-height: min(560px, 60vh);
  background:
    radial-gradient(120% 120% at 20% 10%, rgba(124, 107, 255, .35), transparent 55%),
    radial-gradient(120% 120% at 85% 90%, rgba(74, 217, 255, .28), transparent 55%),
    #14141A;
}
.lightbox__caption { font-size: .9rem; color: var(--text-soft); text-align: center; }
.lightbox__counter {
  font-size: .78rem; color: var(--text-mute);
  font-variant-numeric: tabular-nums; letter-spacing: .08em;
}
.lightbox__nav[hidden] { display: none; }

.lightbox__close {
  position: absolute; top: clamp(1rem, 3vw, 2rem); right: clamp(1rem, 3vw, 2rem);
  width: 46px; height: 46px; border-radius: 50%;
  display: grid; place-items: center;
  border: 1px solid var(--line-strong);
  transition: transform var(--t), background var(--t-fast);
}
.lightbox__nav {
  width: 52px; height: 52px; border-radius: 50%;
  display: grid; place-items: center;
  border: 1px solid var(--line-strong);
  transition: transform var(--t), background var(--t-fast);
}
.lightbox__nav--prev { grid-column: 1; }
.lightbox__nav--next { grid-column: 3; }
.lightbox__close svg, .lightbox__nav svg {
  width: 20px; height: 20px; fill: none; stroke: currentColor;
  stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round;
}
.lightbox__close:hover, .lightbox__nav:hover { background: rgba(255, 255, 255, .1); transform: scale(1.08); }


/* ==========================================================================
   13 bis. LECTEUR VIDÉO
   ========================================================================== */
.videobox {
  position: fixed; inset: 0; z-index: 960;
  display: grid; place-items: center;
  padding: clamp(1rem, 4vw, 3rem);
  background: rgba(6, 6, 8, .92);
  backdrop-filter: blur(18px); -webkit-backdrop-filter: blur(18px);
  opacity: 0; transition: opacity var(--t);
}
.videobox[hidden] { display: none; }
.videobox.is-open { opacity: 1; }

.videobox__figure {
  display: flex; flex-direction: column; align-items: center; gap: 1rem;
  max-width: 100%;
  transform: scale(.94); opacity: 0;
  transition: transform .5s var(--ease), opacity .35s var(--ease);
}
.videobox.is-open .videobox__figure { transform: scale(1); opacity: 1; }

/* Le lecteur épouse le format vertical sans jamais déborder de l'écran */
.videobox__player {
  max-height: 78vh; max-width: min(100%, 92vw);
  width: auto; height: auto;
  border-radius: var(--radius);
  background: #000;
}
.videobox__caption { font-size: .9rem; color: var(--text-soft); text-align: center; }

.videobox__close {
  position: absolute; top: clamp(1rem, 3vw, 2rem); right: clamp(1rem, 3vw, 2rem);
  width: 46px; height: 46px; border-radius: 50%;
  display: grid; place-items: center;
  border: 1px solid var(--line-strong);
  transition: transform var(--t), background var(--t-fast);
}
.videobox__close svg {
  width: 20px; height: 20px; fill: none; stroke: currentColor;
  stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round;
}
.videobox__close:hover { background: rgba(255, 255, 255, .1); transform: scale(1.08); }


/* ==========================================================================
   14. ANIMATIONS
   ========================================================================== */

/* — Scroll reveal : état initial posé par le JS (classe .reveal) — */
.reveal {
  opacity: 0;
  transform: translateY(38px);
  transition: opacity .9s var(--ease), transform .9s var(--ease);
  transition-delay: var(--reveal-delay, 0ms);
  will-change: opacity, transform;
}
.reveal.is-visible { opacity: 1; transform: translateY(0); }

@keyframes wordUp   { to { transform: translateY(0); } }
/* « pop » embarque un translateX(-50%) : il sert au point de la nav, centré
   en absolu. Pour un élément dans le flux normal ce décalage est parasite,
   d'où cette variante. */
@keyframes pop      { from { transform: translateX(-50%) scale(0); } to { transform: translateX(-50%) scale(1); } }
@keyframes logoTrace    { to { stroke-dashoffset: 0; } }
@keyframes logoEfface   { to { opacity: 0; } }
@keyframes logoRemplit  { from { opacity: 0; } to { opacity: 1; } }
@keyframes logoCamera   { 0%   { opacity: 0; transform: scale(1.8); }
                          16%  { opacity: 1; }
                          68%  { transform: scale(1); }
                          82%  { transform: scale(1.08); }
                          100% { transform: scale(1); } }
@keyframes logoBalayage    { from { background-position: 130% 0; } to { background-position: -30% 0; } }
@keyframes chargementBarre { from { transform: scaleX(0); } 65% { transform: scaleX(.75); } to { transform: scaleX(1); } }
@keyframes chargementSecours { to { opacity: 0; visibility: hidden; transform: translateY(-1.5rem); } }
@keyframes popCentre { from { transform: scale(0); } to { transform: scale(1); } }
@keyframes float {
  0%, 100% { transform: translate(0, 0) scale(1); }
  50%      { transform: translate(4%, 6%) scale(1.12); }
}
@keyframes pulse {
  0%   { box-shadow: 0 0 0 0 rgba(70, 227, 155, .55); }
  70%  { box-shadow: 0 0 0 10px rgba(70, 227, 155, 0); }
  100% { box-shadow: 0 0 0 0 rgba(70, 227, 155, 0); }
}
@keyframes ring {
  0%   { transform: scale(1);   opacity: .6; }
  70%  { transform: scale(1.4); opacity: 0; }
  100% { transform: scale(1.4); opacity: 0; }
}
@keyframes scrollLine {
  0%   { transform: translateY(-100%); }
  100% { transform: translateY(250%); }
}


/* ==========================================================================
   15. RESPONSIVE
   ========================================================================== */

/* — Tablette — */
@media (max-width: 1024px) {
  .bento { grid-template-columns: repeat(2, 1fr); }
  .bento__card--wide { grid-column: span 2; }

}

/* — Sous 1100 px, le hero n'a plus la place d'accueillir la pile — */
@media (max-width: 1100px) {
  .hero__stack { display: none; }
}

/* — Mobile : menu plein écran — */
@media (max-width: 860px) {
  :root { --nav-h: 64px; }

  .nav__logo-text { display: none; }
  .nav__burger { display: block; }

  .nav__menu {
    position: fixed; inset: 0;
    flex-direction: column; justify-content: center; gap: 1.5rem;
    padding: 2rem;
    background: rgba(8, 8, 10, .96);
    backdrop-filter: blur(24px); -webkit-backdrop-filter: blur(24px);
    /* Ouverture par révélation circulaire depuis le burger */
    clip-path: circle(0% at calc(100% - 46px) 34px);
    transition: clip-path .7s var(--ease);
    pointer-events: none;
  }
  .nav__menu.is-open { clip-path: circle(150% at calc(100% - 46px) 34px); pointer-events: auto; }
  /* Le menu au doigt empile les liens : la barre, pensée pour une rangée
     horizontale, n'a plus de sens. Le point d'origine reprend son rôle. */
  .nav__pill { display: none; }
  .nav__link.is-active::after {
    content: ""; position: absolute; left: 50%; bottom: 2px;
    width: 4px; height: 4px; border-radius: 50%;
    background: var(--accent);
    transform: translateX(-50%);
    animation: pop .4s var(--ease) both;
  }

  .nav__list { flex-direction: column; gap: .5rem; text-align: center; }
  .nav__link { font-size: 1.75rem; font-weight: 600; letter-spacing: -.04em; padding: .4rem 1.2rem; }
  /* Apparition décalée de chaque entrée */
  .nav__menu li, .nav__cta { opacity: 0; transform: translateY(20px); transition: opacity .5s var(--ease), transform .5s var(--ease); }
  .nav__menu.is-open li, .nav__menu.is-open .nav__cta { opacity: 1; transform: translateY(0); }
  .nav__menu.is-open li:nth-child(1) { transition-delay: .16s; }
  .nav__menu.is-open li:nth-child(2) { transition-delay: .22s; }
  .nav__menu.is-open li:nth-child(3) { transition-delay: .28s; }
  .nav__menu.is-open li:nth-child(4) { transition-delay: .34s; }
  .nav__menu.is-open .nav__cta { transition-delay: .4s; }
  .nav__cta { padding: .8rem 1.6rem; font-size: .95rem; }

  .hero__scroll { display: none; }
}

/* — Petit mobile — */
@media (max-width: 640px) {
  .container { width: min(1240px, 100% - 2.25rem); }

  .bento { grid-template-columns: 1fr; }
  .bento__card--wide { grid-column: span 1; }

  /* Suite de la bio repliée derrière un bouton */
  .bio-toggle { display: inline-flex; }
  .bio-panel {
    grid-template-rows: 0fr;
    transition: grid-template-rows .55s var(--ease);
  }
  .bio-panel > * { overflow: hidden; }
  .bio-panel.is-open { grid-template-rows: 1fr; }

  /* Trois colonnes égales : les chiffres s'alignent au lieu de se répartir
     au fil du retour à la ligne. */
  .hero__stats {
    display: grid; grid-template-columns: repeat(3, 1fr);
    gap: 1.25rem 1rem;
  }
  .hero__stats strong { font-size: 1.6rem; }
  .hero__stats span { font-size: .72rem; line-height: 1.3; }
  .hero__actions .btn { flex: 1 1 100%; justify-content: center; }

  .lightbox { grid-template-columns: 1fr; }
  .lightbox__figure { grid-column: 1; }
  .lightbox__nav { position: absolute; bottom: 1.5rem; }
  .lightbox__nav--prev { left: 25%; }
  .lightbox__nav--next { right: 25%; }
  .lightbox__media { min-width: 0; }

  .footer__inner { flex-direction: column; text-align: center; }
}

/* — Petit écran : une carte occupe presque toute la largeur — */
@media (max-width: 640px) {
  .gallery--photos > .card,
  .videos > .card,
  .gallery--grid > .card,
  .gallery--grid > .projet-charte { flex-basis: 76%; }
  /* En paysage la carte est basse : autant lui donner toute la largeur */
  .videos > .card--paysage { flex-basis: 100%; }
}

/* Les effets de survol n'ont pas de sens au doigt : on les neutralise */
@media (hover: none) {
  /* Dernières zones tactiles portées au seuil de confort de 44 px */
  .card__zoom { width: 44px; height: 44px; }
  .footer__top { width: 44px; height: 44px; }
  .card__meta { opacity: 1; transform: none; }
  .card__zoom { opacity: 1; transform: scale(1); }
  .card__controls,
  .card__count { opacity: 1; transform: none; }
  .card:hover { transform: none; }
}


/* ==========================================================================
   16. ACCESSIBILITÉ
   ========================================================================== */
:focus-visible {
  outline: 2px solid var(--accent-2);
  outline-offset: 3px;
  border-radius: 6px;
}

/* Respect du réglage système « réduire les animations » */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
  .reveal { opacity: 1; transform: none; }
  .hero__title .word > span { transform: none; }
  .cursor { display: none !important; }
}

/* Impression : version simple et lisible */
@media print {
  .nav, .cursor, .scroll-progress, .hero__glow, .marquee, .lightbox, .footer__top { display: none !important; }
  body { background: #fff; color: #000; }
  .reveal { opacity: 1; transform: none; }
}


/* ==========================================================================
   17. ANIMATIONS PILOTÉES PAR LE DÉFILEMENT
   Là où le navigateur sait le faire, deux effets passent du JavaScript au
   CSS : ils suivent alors la position réelle dans la page plutôt que d'être
   recalculés à chaque événement, et tournent sur le compositeur graphique.
   Le JavaScript se retire de lui-même (voir initScrollProgress et
   initHeroParallax) ; ailleurs, rien ne change.
   ========================================================================== */
@supports (animation-timeline: scroll()) {
  @media (prefers-reduced-motion: no-preference) {

    /* La barre de progression suit le défilement du document */
    html.a-timeline .scroll-progress span {
      width: 100%;
      transform-origin: left;
      transform: scaleX(0);
      transition: none;
      animation: barreProgression linear both;
      animation-timeline: scroll(root block);
    }

    /* La pile de photos du hero dérive doucement */
    html.a-timeline .hero__stack {
      /* « both » est indispensable : hors de la plage, une animation sans
         fill-mode cesse de s'appliquer et l'élément revient à sa position
         de départ dès qu'on a dépassé le premier écran. */
      animation: deriveHero linear both;
      animation-timeline: scroll(root block);
      animation-range: 0 100vh;
    }
  }
}

@keyframes barreProgression { to { transform: scaleX(1); } }
@keyframes deriveHero {
  from { transform: translateY(-50%); }
  to   { transform: translateY(calc(-50% + 90px)); }
}


/* Trajet de la vignette vers la visionneuse (voir « ouvrir » dans le JS) */
::view-transition-old(photo-ouverte),
::view-transition-new(photo-ouverte) {
  animation-duration: .42s;
  animation-timing-function: var(--ease);
  mix-blend-mode: normal;
}

/* ==========================================================================
   PAGES DE DOCUMENT (confidentialité, CGU)
   Colonne de lecture étroite : au-delà de ~70 signes par ligne, l'œil perd
   le début de la ligne suivante. Même palette et même typographie que le site.
   ========================================================================== */
.doc {
  width: min(70ch, 100% - 2.5rem);
  margin-inline: auto;
  padding-block: clamp(2.5rem, 7vh, 4.5rem) clamp(2rem, 5vh, 3rem);
}
.doc__retour {
  display: inline-flex; align-items: center; gap: .4rem;
  font-size: .85rem; color: var(--text-mute);
  transition: color var(--t-fast);
}
.doc__retour:hover { color: var(--text); }
.doc h1 {
  font-size: clamp(1.7rem, 4.5vw, 2.6rem); font-weight: 700;
  letter-spacing: -.03em; line-height: 1.1; margin: 1.6rem 0 .6rem;
}
.doc__maj { color: var(--text-mute); font-size: .85rem; margin-bottom: 2.5rem; }
.doc h2 {
  font-size: 1.05rem; font-weight: 700; letter-spacing: -.01em;
  margin: 2.4rem 0 .7rem; padding-top: 1.4rem; border-top: 1px solid var(--line);
}
.doc h3 { font-size: .95rem; font-weight: 600; margin: 1.4rem 0 .4rem; }
.doc p, .doc li { color: var(--text-soft); line-height: 1.7; font-size: .95rem; }
.doc p + p { margin-top: .8rem; }
.doc ul { margin: .7rem 0 0; padding-left: 1.1rem; display: grid; gap: .45rem; }
/* Un paragraphe qui suit une liste a besoin du même souffle qu'entre deux
   paragraphes, sinon il se colle au dernier point. */
.doc ul + p, .doc ul + h2, .doc__table + h2 { margin-top: 1.1rem; }
.doc ul + h2, .doc__table + h2 { margin-top: 2.4rem; }
.doc li::marker { color: var(--text-mute); }
.doc strong { color: var(--text); font-weight: 600; }
.doc a:not(.doc__retour):not(.btn) { color: var(--text); text-decoration: underline; text-underline-offset: 3px; }
.doc a:not(.doc__retour):not(.btn):hover { color: var(--accent-2); }
/* Tableau de durées : lisible sans bordures, aligné sur la grille du texte */
.doc__table { width: 100%; border-collapse: collapse; margin-top: .9rem; }
.doc__table th, .doc__table td {
  text-align: left; padding: .6rem .8rem .6rem 0;
  border-bottom: 1px solid var(--line); font-size: .92rem; color: var(--text-soft);
}
.doc__table th { color: var(--text); font-weight: 600; }
.doc__pied {
  border-top: 1px solid var(--line);
  padding-block: 2rem;
  text-align: center; font-size: .85rem; color: var(--text-mute);
}
.doc__pied a { color: var(--text-soft); }
.doc__pied a:hover { color: var(--text); }

/* ==========================================================================
   BANDEAU D'INFORMATION (cookies)
   Posé en bas, il ne bloque ni la lecture ni la navigation : le site
   n'attend aucun consentement, le bandeau ne fait que renseigner.
   ========================================================================== */
.bandeau {
  position: fixed; z-index: 90;
  left: 1rem; right: 1rem; bottom: 1rem;
  margin-inline: auto; max-width: 640px;
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: .9rem 1.4rem;
  padding: .9rem 1.1rem;
  background: rgba(18, 18, 22, .92);
  backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
  border: 1px solid var(--line-strong); border-radius: 14px;
  box-shadow: 0 20px 50px -20px rgba(0, 0, 0, .8);
  opacity: 0; transform: translateY(14px);
  transition: opacity .35s var(--ease), transform .35s var(--ease);
}
.bandeau.is-open { opacity: 1; transform: translateY(0); }
.bandeau__texte { font-size: .85rem; color: var(--text-soft); line-height: 1.5; margin: 0; flex: 1 1 260px; }
.bandeau__texte strong { color: var(--text); font-weight: 600; }
.bandeau__texte a { color: var(--text); text-decoration: underline; text-underline-offset: 3px; }
.bandeau__texte a:hover { color: var(--accent-2); }
.bandeau__ok {
  flex: 0 0 auto;
  padding: .55rem 1.1rem; border-radius: 99px;
  border: 1px solid var(--line-strong); background: rgba(255, 255, 255, .06);
  font-size: .85rem; font-weight: 600; color: var(--text);
  transition: background var(--t-fast), border-color var(--t-fast);
}
.bandeau__ok:hover { background: rgba(255, 255, 255, .12); border-color: var(--text); }
@media (max-width: 480px) {
  .bandeau { flex-direction: column; align-items: stretch; text-align: center; }
  .bandeau__ok { width: 100%; }
}
