/* ==========================================================
   STYLE.CSS — Alexis Rey Portfolio
   ========================================================== */

/* ── Enregistrement des variables de couleur (clair/sombre) ──
   Sans ça, une custom property qui change de valeur bascule
   instantanément (pas d'interpolation), même si les propriétés
   qui l'utilisent (color, border-color...) ont une transition :
   d'où le "mélange" visible pendant la transition dark/light. */
@property --c-text {
  syntax: '<color>';
  inherits: true;
  initial-value: #111118;
}
@property --c-muted {
  syntax: '<color>';
  inherits: true;
  initial-value: #6b7a86;
}
@property --c-border {
  syntax: '<color>';
  inherits: true;
  initial-value: #e0eae6;
}

/* ── Variables ─────────────────────────────────────────── */
:root {
  --c-bg:     #e8f5f0;
  --c-nav:    #121220;
  --c-accent: #2CC4A8;
  --c-text:   #111118;
  --c-muted:  #6b7a86;
  --c-card:   #ffffff;
  --c-border: #e0eae6;

  --f-ui:   'Anton', sans-serif;
  --f-body: 'Poppins', sans-serif;

  --max-w:  1300px;
  --nav-h:  58px;
  --px:     clamp(24px, 4.3vw, 80px);
  --r-card: 30px;

  --shadow: 0 2px 24px rgba(0,0,0,.07);
  --ease:   cubic-bezier(.4,0,.2,1);
  --dur:    220ms;

  /* Hauteur des lettres ALEXIS + REY : une seule variable partagée par les
     deux sélecteurs, pour qu'ils aient toujours exactement la même
     hauteur. script.js la recalcule au chargement/resize pour que le
     groupe remplisse exactement la largeur de .hero__rey-row. */
  --hero-name-h: clamp(1.3rem, 2.1vw, 1.9rem);
}

/* ── Reset ─────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
/* La scrollbar est masquée (::-webkit-scrollbar / scrollbar-width plus bas) :
   scrollbar-gutter:stable réservait un espace pour compenser son
   apparition/disparition, mais comme elle est maintenant toujours
   invisible, cet espace réservé restait vide et non couvert — une fine
   bande sur le bord droit, plus visible après une rotation d'écran mobile. */
html  { scroll-behavior: smooth; scrollbar-width: none; -ms-overflow-style: none; }
html::-webkit-scrollbar { display: none; }
body  {
  font-family: var(--f-body);
  color: var(--c-text);
  background: #f8fffe;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
  position: relative;
  transition: background 1.1s cubic-bezier(.4,0,.2,1), color 1.1s cubic-bezier(.4,0,.2,1);
}

/* ── Blobs de fond (défilent avec la page) ── */
.page-bg {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  overflow: hidden;
}
.page-bg + * { position: relative; z-index: 1; }
header, main, footer { position: relative; z-index: 1; }

.blob {
  position: absolute;
  border-radius: 50%;
  /* Un rayon de flou plus grand coûte cher à peindre (le coût croît avec le
     carré du rayon) sans gain visuel perceptible passé un certain point sur
     un dégradé qui va déjà à transparent à 70% : 90px reste très doux. */
  filter: blur(90px);
}
/* 1 — bleu haut-gauche */
.blob--1 {
  width: 900px; height: 900px;
  background: radial-gradient(circle, rgba(34,196,168,.40) 0%, transparent 70%);
  left: -450px; top: -450px;
}
/* 2 — rose haut-droite */
.blob--2 {
  width: 800px; height: 800px;
  background: radial-gradient(circle, rgba(180,140,255,.36) 0%, transparent 70%);
  right: -200px; top: 200px;
}
/* 5 — miroir blob--1 : bleu bas-gauche (autres projets+) */
.blob--5 {
  width: 900px; height: 900px;
  background: radial-gradient(circle, rgba(34,196,168,.55) 0%, transparent 70%);
  left: -450px; bottom: 200px;
  opacity: 0; transition: opacity 1.2s ease;
}
/* 6 — miroir blob--2 : violet bas-droite (autres projets+) */
.blob--6 {
  width: 800px; height: 800px;
  background: radial-gradient(circle, rgba(180,140,255,.50) 0%, transparent 70%);
  right: -200px; bottom: -300px;
  opacity: 0; transition: opacity 1.2s ease;
}
body.show-end-gradient .blob--5,
body.show-end-gradient .blob--6 { opacity: 1; }
/* ── Mood blobs (changent selon la card active) ── */
.mood {
  position: fixed;
  border-radius: 50%;
  filter: blur(80px);
  opacity: 0;
  transition: opacity 1.5s cubic-bezier(.4,0,.2,1);
  pointer-events: none;
  z-index: 0;
}
/* Positions dans le viewport */
.mood--a { width: 700px; height: 700px; left: -250px; top: -100px; }
.mood--b { width: 600px; height: 600px; right: -200px; bottom: -100px; }

/* Couleurs par card */
/* EKE-DEKA : orange #E07B39 + brun #5C3A1E */
.mood--eke-deka.mood--a { background: radial-gradient(circle, rgba(224,123,57,.28) 0%, transparent 65%); }
.mood--eke-deka.mood--b { background: radial-gradient(circle, rgba(92,58,30,.45) 0%, transparent 65%); }
/* ELMY : vert #1B8C70 + vert foncé #0E634E */
.mood--elmy.mood--a         { background: radial-gradient(circle, rgba(27,140,112,.55) 0%, transparent 65%); }
.mood--elmy.mood--b         { background: radial-gradient(circle, rgba(14,99,78,.75) 0%, transparent 65%); }
/* GAME'N CHILL : lavande #BF90DA + violet nuit #12001B */
.mood--game-n-chill.mood--a { background: radial-gradient(circle, rgba(191,144,218,.55) 0%, transparent 65%); }
.mood--game-n-chill.mood--b { background: radial-gradient(circle, rgba(18,0,27,.75) 0%, transparent 65%); }
/* AMELIORAMA 3 : sable #DCC28E + brun #544A36 */
.mood--ameliorama-3.mood--a { background: radial-gradient(circle, rgba(220,194,142,.55) 0%, transparent 65%); }
.mood--ameliorama-3.mood--b { background: radial-gradient(circle, rgba(84,74,54,.75) 0%, transparent 65%); }

/* Activation via classe sur <body> */
body.mood-eke-deka     .mood--eke-deka,
body.mood-elmy         .mood--elmy,
body.mood-game-n-chill .mood--game-n-chill,
body.mood-ameliorama-3 .mood--ameliorama-3 { opacity: 1; }

/* Couleur de la scrollbar selon le mood */
body.mood-eke-deka     .scroll-nav__dot           { background: #D89860; }
body.mood-eke-deka     .scroll-nav__dot.is-active { background: #E07B39; }
body.mood-eke-deka     .scroll-nav__track::before { background: rgba(224,123,57,.5); }
body.mood-elmy         .scroll-nav__dot           { background: #5DA391; }
body.mood-elmy         .scroll-nav__dot.is-active { background: #1B8C70; }
body.mood-elmy         .scroll-nav__track::before { background: rgba(27,140,112,.5); }
body.mood-game-n-chill .scroll-nav__dot           { background: #D8BBE8; }
body.mood-game-n-chill .scroll-nav__dot.is-active { background: #BF90DA; }
body.mood-game-n-chill .scroll-nav__track::before { background: rgba(191,144,218,.5); }
body.mood-ameliorama-3 .scroll-nav__dot           { background: #EADABA; }
body.mood-ameliorama-3 .scroll-nav__dot.is-active { background: #DCC28E; }
body.mood-ameliorama-3 .scroll-nav__track::before { background: rgba(220,194,142,.5); }

/* ── Dark mode : Game'N Chill + Ameliorama 3 ── */
body.mood-game-n-chill,
body.mood-ameliorama-3 {
  background: #0e0c14;
  --c-text:   #f2f0f5;
  --c-muted:  #a89fb3;
  --c-border: rgba(255,255,255,.12);
}
body.mood-game-n-chill .card,
body.mood-ameliorama-3 .card {
  background: rgba(255,255,255,.06);
  box-shadow: 0 4px 28px rgba(0,0,0,.4);
}

img    { display: block; max-width: 100%; }
ul     { list-style: none; }
a      { text-decoration: none; color: inherit; }
button { font-family: var(--f-body); cursor: pointer; }

/* ── Boutons ───────────────────────────────────────────── */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--f-body);
  font-size: 14px;
  font-weight: 500;
  padding: .7rem 1.5rem;
  border-radius: 8px;
  border: none;
  white-space: nowrap;
  cursor: pointer;
  transition: opacity var(--dur) var(--ease);
}
.btn:hover { opacity: .88; }

.btn--filled {
  background: #22888D;
  color: #fff;
}
.btn--outline {
  background: transparent;
  color: #8C56D3;
  border: 1.5px solid #8C56D3;
}

/* ═══════════════════════════════════════════════════════
   NAVIGATION
════════════════════════════════════════════════════════ */
.nav {
  background: transparent;
  height: var(--nav-h);
}
.nav__inner {
  max-width: var(--max-w);
  margin: 0 auto;
  padding: 0 var(--px);
  height: 100%;
  display: flex;
  align-items: center;
}

.nav__logo {
  font-family: 'neutronic', sans-serif;
  font-weight: 700;
  font-size: 1rem;
  color: #464646;
  text-transform: uppercase;
  letter-spacing: .02em;
  flex: 1;
  /* min-width:0 : sans ça, un flex item ne rétrécit jamais sous la largeur
     de son contenu (ici "ALEXIS REY" sur une ligne) — sur mobile, si ce
     texte ne tient pas dans sa moitié de .nav__inner, il forçait tout le
     nav (et donc la page entière) à déborder horizontalement au lieu de
     simplement rétrécir/passer à la ligne. */
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.nav__links {
  display: flex;
  justify-content: center;
  gap: 2.5rem;
}
.nav__link {
  font-size: .875rem;
  font-weight: 400;
  color: #2f2f2f;
  transition: color var(--dur);
}
.nav__link:hover,
.nav__link.is-active { color: #000; }

.nav__actions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 1rem;
  flex: 1;
}

/* Toggle Animations */
.anim-toggle {
  display: flex;
  align-items: center;
  gap: .45rem;
  cursor: pointer;
  user-select: none;
}
.anim-toggle input { position: absolute; opacity: 0; width: 0; height: 0; }

.anim-toggle__track {
  width: 36px; height: 20px;
  background: rgba(17,17,24,.15);
  border-radius: 10px;
  position: relative;
  transition: background var(--dur);
  flex-shrink: 0;
}
.anim-toggle input:checked ~ .anim-toggle__track {
  background: #22888D;
}
.anim-toggle__thumb {
  position: absolute;
  top: 2px; left: 2px;
  width: 16px; height: 16px;
  background: #fff;
  border-radius: 50%;
  box-shadow: 0 1px 3px rgba(0,0,0,.25);
  transition: transform var(--dur) var(--ease);
}
.anim-toggle input:checked ~ .anim-toggle__track .anim-toggle__thumb {
  transform: translateX(16px);
}
.anim-toggle__label {
  font-size: .875rem;
  color: #2f2f2f;
}

.lang-btn {
  font-size: .875rem;
  color: #2f2f2f;
  background: none;
  border: none;
  display: inline-flex;
  align-items: center;
  gap: .2rem;
  transition: color var(--dur);
  /* Vrai padding (pas de marge négative pour compenser) : la marge
     négative ne rendait pas la zone tactile réellement cliquable, seul le
     texte répondait au clic. */
  padding: .6rem .3rem;
}
.lang-btn:hover { color: #000; }
.lang-btn__icon {
  width: 1.1em; height: 1.1em; flex-shrink: 0;
  transition: transform var(--dur) var(--ease);
}

.lang-dropdown {
  position: relative;
}
.lang-dropdown__menu {
  position: absolute;
  top: calc(100% + 16px);
  left: 0;
  opacity: 0;
  pointer-events: none;
  transform: translateY(-4px);
  transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.lang-dropdown.is-open .lang-dropdown__menu {
  opacity: 1;
  pointer-events: auto;
  transform: translateY(0);
}
.lang-dropdown.is-open .lang-btn__icon {
  transform: rotate(180deg);
}
.lang-btn--option {
  /* inline-flex (pas block+width:100%) : .lang-dropdown__menu (le parent)
     n'a pas de largeur propre, il se dimensionne sur son contenu — un
     enfant en width:100% y est ambigu (100% de quoi ?) et ne garantit pas
     que le fond épouse le texte. En inline-flex, la boîte se dimensionne
     sur SON PROPRE contenu (texte + padding), donc épouse le texte
     naturellement, tout en restant garantie d'être une seule zone
     cliquable (fond visible = zone de clic = même boîte). */
  display: inline-flex;
  align-items: center;
  /* 44×44px : taille minimale recommandée pour une zone tactile, garantie
     même si le texte seul est plus petit — le texte reste centré dedans
     grâce à align-items ci-dessus plutôt que collé en haut ou en bas. */
  min-width: 44px;
  min-height: 44px;
  /* Padding horizontal identique à .lang-btn : le texte "Anglais" démarre
     au même x que "Français". Pas de padding vertical : min-height suffit
     à garantir la zone tactile sans étirer artificiellement la boîte. */
  padding: 0 .3rem;
  text-align: left;
}
.lang-btn--option:hover {
  color: #22888D;
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* ═══════════════════════════════════════════════════════
   HERO
════════════════════════════════════════════════════════ */
.hero {
  position: relative;
  min-height: calc(100vh - var(--nav-h));
  padding: 0 var(--px) 4rem;
  display: flex;
  flex-direction: column;
  justify-content: center;
}
/* 2 colonnes flex : gauche (photo+texte) | mockups */
.hero__inner {
  max-width: var(--max-w);
  margin: 0 auto;
  width: 100%;
  display: flex;
  gap: 4rem;
  align-items: center;
  justify-content: space-between;
}

/* Colonne gauche : photo + texte + boutons */
.hero__left {
  flex: 1;
  min-width: 0;
  display: grid;
  grid-template-columns: auto 1fr;
  grid-template-rows: auto auto auto;
  gap: 2rem;
  align-items: start;
}

.hero__hero-row {
  display: flex;
  align-items: flex-end;
  gap: 2rem;
  width: 100%;
  grid-column: 1 / -1;
  grid-row: 1;
}

.hero__photo-wrap { grid-column: 1; grid-row: 1 / span 2; justify-self: start; align-self: start; }

.hero__hero-title {
  /* flex:1 : prend exactement le reste de la largeur de .hero__hero-row
     après la photo (qui est flex-shrink:0), la même largeur que .hero__text
     et .hero__actions en dessous — le groupe ALEXIS/REY et le rôle,
     alignés à droite dans cette boîte, s'arrêtent donc pile au bord droit
     des boutons, jamais au-delà. */
  display: flex;
  flex: 1;
  flex-direction: column;
  justify-content: flex-end;
  align-items: flex-end;
  align-self: flex-end;
  min-width: 0;
}

.hero__text {
  grid-column: 1 / -1;
  grid-row: 2;
  display: flex;
  flex-direction: column;
  gap: 2rem;
}

.hero__actions {
  grid-column: 1 / -1;
  grid-row: 3;
  justify-self: stretch;
}

/* ── Photo + blob + badge ── */
.hero__photo-wrap {
  display: flex;
  flex-direction: column;
  align-items: center;
  flex-shrink: 0;
}

/* Frame : contient blob + photo, sert de référence au positionnement absolu */
.hero__photo-frame {
  position: relative;
  width: 233.51px;
}

.hero__photo-blob {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 126.68px;
  border-radius: 42.67px;
  background: #22888D;
  z-index: 0;
}

.hero__photo {
  position: relative;
  z-index: 1;
  width: calc(100% + 3px);
  left: 0px;
  height: 219.33px;
  object-fit: cover;
  object-position: center top;
  border-radius: 16px 16px 42.67px 42.67px;
  display: block;
  top: 1px;
}

.hero__badge {
  position: absolute;
  left: -13px;
  bottom: -16px;
  z-index: 3;
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 8px;
  font-family: var(--f-body);
  font-size: 11.06px;
  font-weight: 500;
  color: #2f2f2f;
  white-space: nowrap;
  background: #fff;
  border-radius: 12px;
  box-shadow: 0 0 5.82px rgba(0,0,0,.15);
}
.hero__badge-dot {
  display: inline-block;
  width: 8px; height: 8px;
  border-radius: 50%;
  background: #22c55e;
  flex-shrink: 0;
}

/* Texte réel pour les moteurs de recherche/lecteurs d'écran, invisible à
   l'oeil : pas de display:none (Google l'ignore alors complètement), ni
   left:-9999px (déplace le point de scroll au focus) — clip+position:
   absolute+1px reste la technique la plus fiable. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

/* Le contenu visuel (lettres ALEXIS/REY en images, rôle en texte) est
   dupliqué par le <span class="sr-only"> ci-dessus pour le SEO/a11y — donc
   masqué de l'arbre d'accessibilité via aria-hidden sur son wrapper.
   display:contents : ce wrapper ne doit introduire AUCUNE boîte propre,
   sinon il casserait la mise en page flex de .hero__title-block (qui
   traite aujourd'hui .hero__rey-row et .hero__role comme ses enfants
   flex directs) — avec display:contents, ce sont toujours eux qui sont
   traités comme tels, le wrapper devient invisible pour le rendu tout en
   restant présent dans le DOM pour aria-hidden. */
.hero__title-visual {
  display: contents;
}

/* ── Bloc titre : REY / ALEXIS / ROLE ── */
.hero__title-block {
  /* width:100% (au lieu de fit-content) : le bloc occupe toute la largeur
     de .hero__hero-title, ALEXIS/REY et le rôle restant alignés à droite
     à l'intérieur (voir justify-content/text-align ci-dessous). */
  display: flex;
  flex-direction: column;
  gap: 0;
  line-height: 1;
  width: 100%;
}

/* Ligne ALEXIS + REY + pointillés (ordre visuel : ALEXIS plein, REY en contour).
   Un seul groupe (name-group) aligné à droite dans la ligne : pointillés et
   curseur restent voisins directs de REY pour garder leur calibrage au
   pixel près (marges négatives) relatif à son bas. */
.hero__rey-row {
  /* justify-content:flex-start (et non flex-end) : le groupe ALEXIS/REY
     démarre au bord gauche de .hero__title-block, aligné avec le début de
     "UI / UX DESIGNER" en dessous (text-align-last:justify démarre aussi
     à gauche) — tout en restant width:100% du même parent. */
  display: flex;
  align-items: flex-end;
  justify-content: flex-start;
  width: 100%;
  /* Hauteur de la ligne doublée par rapport à --hero-name-h (la hauteur
     réelle d'ALEXIS/REY) : align-items:flex-end garde le nom collé en bas,
     l'espace supplémentaire apparaît au-dessus — la taille du nom/texte
     lui-même n'est pas affectée, seule la boîte de la ligne s'agrandit. */
  height: calc(var(--hero-name-h) * 2);
  /* Garde-fou : si --hero-name-h est calculé trop grand (JS pas encore
     rejoué après un changement de mise en page, ex. photo redimensionnée),
     le groupe ALEXIS/REY ne doit jamais déborder HORIZONTALEMENT de son
     conteneur — on le coupe plutôt que de laisser le texte dépasser
     visuellement. clip et non hidden : hidden forcerait overflow-y en
     auto (par spec CSS, dès qu'un axe n'est pas visible, l'autre axe
     visible est recalculé en auto) et ferait apparaître une barre de
     défilement à cause du dépassement voulu du curseur (margin-bottom
     négatif, voir .hero__cursor) — clip ne crée pas de conteneur de
     défilement, donc ne force pas l'autre axe. */
  max-width: 100%;
  overflow-x: clip;
  overflow-y: visible;
  /* Relatif à --hero-name-h (plutôt qu'un px fixe) : l'écart avec la ligne
     UI/UX DESIGNER reste proportionnel à la taille du nom, que ce dernier
     soit petit (mobile) ou grand (desktop) — au lieu d'un écart fixe qui
     paraissait relativement plus grand quand le nom est petit. */
  margin-bottom: calc(var(--hero-name-h) * 0.43);
}
/* Caché jusqu'à ce que script.js ait calculé la taille finale (images du
   nom chargées + polices prêtes) : évite de voir chaque état intermédiaire
   (police de secours, taille pas encore ajustée) comme un saut visible. */
.hero__name-group,
.hero__role {
  opacity: 0;
  transition: opacity .2s ease;
}
#hero.hero--name-ready .hero__name-group,
#hero.hero--name-ready .hero__role {
  opacity: 1;
}
.hero__name-group {
  display: flex;
  align-items: flex-end;
  gap: 0;
}
.hero__rey-img {
  /* Même hauteur exacte que .hero__letter (via --hero-name-h) — et 20px
     d'écart avec la dernière lettre ALEXIS. */
  height: var(--hero-name-h);
  width: auto;
  display: block;
  transition: height .15s ease;
  flex-shrink: 0;
  margin-left: 10px;
}
.hero__dots-wrap {
  display: block;
  flex-shrink: 0;
  overflow: hidden;
  margin-left: calc(clamp(-1.207rem, -1.336vw, -0.832rem) + 4px);
  margin-bottom: -0.81px;
  max-width: 300px;
}
/* Gaté sur #hero.hero--name-ready (comme .hero__letter/.hero__role plus
   bas) et pas seulement .anim-on : sans ça, son décompte démarrerait au
   chargement de la page — un repère différent de celui de role-enter (le
   décompte de la rotation démarre à la révélation) — et "juste après la
   rotation" ne voudrait plus dire la même chose selon la vitesse de charge. */
.anim-on #hero.hero--name-ready .hero__dots-wrap {
  max-width: 0;
  animation: dots-grow 1.8s cubic-bezier(.4,0,.2,1) 0.4s forwards;
}
.hero__dots {
  display: block;
  flex-shrink: 0;
  height: clamp(0.147rem, 0.235vw, 0.213rem);
  width: auto;
}

/* Chaque lettre ALEXIS : hauteur proportionnelle à la grille Figma */
.hero__letter {
  /* Hauteur pilotée par --hero-name-h, recalculée par script.js pour
     remplir exactement la largeur disponible (voir fitHeroName()).
     transition : les changements de taille au resize s'animent au lieu
     de sauter brutalement d'une valeur à l'autre. */
  height: var(--hero-name-h);
  width: auto;
  display: block;
  transition: height .15s ease;
}
/* Rebond d'entrée : déclenché par #hero.hero--name-ready (ajouté par
   script.js une fois la taille finale figée et révélée), pas par .anim-on
   seul — sinon le décompte démarrait dès le chargement de la page, avant
   même que le nom soit visible, et pouvait être déjà terminé au moment de
   la révélation. */
.anim-on #hero.hero--name-ready .hero__letter {
  animation: letter-bounce 0.55s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
}
.anim-on #hero.hero--name-ready .hero__name-group .hero__letter:nth-child(1) { animation-delay: 0.30s; }
.anim-on #hero.hero--name-ready .hero__name-group .hero__letter:nth-child(2) { animation-delay: 0.42s; }
.anim-on #hero.hero--name-ready .hero__name-group .hero__letter:nth-child(3) { animation-delay: 0.54s; }
.anim-on #hero.hero--name-ready .hero__name-group .hero__letter:nth-child(4) { animation-delay: 0.66s; }
.anim-on #hero.hero--name-ready .hero__name-group .hero__letter:nth-child(5) { animation-delay: 0.78s; }
.anim-on #hero.hero--name-ready .hero__name-group .hero__letter:nth-child(6) { animation-delay: 0.90s; }
@keyframes letter-bounce {
  0%   { transform: translateY(0); }
  40%  { transform: translateY(-10px); }
  100% { transform: translateY(0); }
}
.hero__cursor {
  height: clamp(1rem, 1.8vw, 1.5rem);
  width: auto;
  display: block;
  /* pointe SVG à 10.3% W / 7.6% H → aligner tip sur l'extrémité droite des dots */
  margin-left: -0.14rem;
  margin-bottom: -1.28rem;
}

/* Rôle — Figma : Anton 40px */
.hero__role {
  display: block;
  font-family: var(--f-ui);
  font-weight: 400;
  /* Valeur de repli avant que script.js (fitHeroRole) ne recalcule la
     taille exacte pour que le texte fasse la même largeur que le groupe
     ALEXIS/REY — sans toucher aux espaces entre les mots/le "/". */
  font-size: clamp(1.45rem, 2.91vw, 2.38rem);
  text-transform: uppercase;
  letter-spacing: .03rem;
  color: #464646;
  /* em (relatif à la taille de police du rôle lui-même) plutôt qu'un rem
     fixe : reste proportionnel que le texte soit petit ou grand. */
  margin-top: 0.21em;
  transform-origin: center center;
  /* fit-content (pas 100%) : la boîte colle à la largeur réelle du texte
     (première à dernière lettre), pas à celle du parent — nécessaire
     aussi pour que script.js mesure la vraie largeur du texte (offsetWidth)
     plutôt que celle, artificielle, du parent. */
  width: fit-content;
  /* Garde-fou, comme sur .hero__rey-row : si le font-size calculé est trop
     grand (JS pas encore rejoué après un changement de mise en page), le
     texte ne doit jamais déborder de son conteneur — max-width le limite,
     overflow:hidden coupe le texte (nowrap) plutôt que de le laisser
     déborder visuellement. */
  max-width: 100%;
  overflow: hidden;
  white-space: nowrap;
  transition: font-size .15s ease;
}
/* Rotation d'entrée : gatée sur #hero.hero--name-ready pour la même raison
   que le rebond des lettres ci-dessus. */
.anim-on #hero.hero--name-ready .hero__role {
  animation: role-enter 0.4s cubic-bezier(0.34, 1.56, 0.64, 1) both;
}
@keyframes role-enter {
  from { transform: rotate(-9deg); }
  to   { transform: rotate(0deg); }
}

@keyframes dots-grow {
  to { max-width: 300px; }
}

/* Description + CTA */
.hero__tagline {
  font-size: .875rem;
  font-weight: 500;
  line-height: 1.65;
  color: #2f2f2f;
  max-width: 100%;
}
.hero__actions {
  display: flex;
  gap: .875rem;
  flex-wrap: wrap;
}
.hero__actions .btn {
  flex: 1;
}

/* ── Colonne droite : mockups ── */
.hero__right {
  flex: 0 0 50%;
  min-width: 0;
  align-self: center;
}
.hero__mockups {
  position: relative;
  width: 100%;
  aspect-ratio: 661 / 360;
}
.hero__rect {
  position: absolute;
  border-radius: 0;
  overflow: hidden;
  box-shadow: 0 0 6.27px 0 rgba(0,0,0,.15);
  /* Blanc neutre plutôt qu'une couleur marquée : en object-fit:contain,
     l'espace qui peut apparaître autour de l'image (ratio different de
     la case) se voit moins qu'avec une teinte saturée. */
  background: #fff;
  display: flex;
}
/* Le <picture> ajouté pour le chargement conditionnel par media ne doit pas
   devenir lui-même l'élément flex (sinon .hero__rect img { flex:1 } ne
   s'applique plus au bon élément) : display:contents le retire de l'arbre
   de boîtes, l'<img> reste l'enfant flex direct comme avant. */
.hero__rect picture { display: contents; }
.hero__rect img {
  flex: 1;
  min-width: 0;
  min-height: 0;
  /* contain (pas cover) : 100% de l'image doit être visible, sans
     rognage — l'espace éventuel autour (si le ratio de l'image ne
     correspond pas exactement à la case) est comblé par le fond blanc
     de .hero__rect ci-dessus, plutôt qu'une couleur marquée. */
  object-fit: contain;
  object-position: top;
  display: block;
}
/* Positions en % du conteneur 661×360px (pixel-perfect Figma) */
.hero__rect--1 { width: 39.94%; height: 46.39%; left: 0%;     top: 30.28%; }
.hero__rect--2 { width: 39.79%; height: 46.39%; left: 60.21%; top: 30.28%; }
.hero__rect--3 { width: 29.80%; height: 34.72%; left: 24.21%; top: 65.00%; }
/* Capture eke-deka en background-image (pas <img>+object-fit comme les
   autres mockups) : object-fit:cover se dérègle sur cette case à certains
   niveaux de zoom navigateur (l'image ne remplit plus la case, laissant voir
   le fond derrière) — un bug connu de rendu, pas de notre calcul. Un
   background-size:cover n'est jamais affecté par ce bug, quel que soit le
   zoom. */
.hero__rect--4 {
  width: 58.09%; height: 69.44%; left: 18.61%; top: 18.89%; z-index: 2;
  background-image: url('images/banner/eke-deka-apercu.png');
  background-size: cover;
  background-position: top center;
  background-repeat: no-repeat;
}
.hero__rect--5 { width: 28.29%; height: 32.78%; left: 38.13%; top:  0%;    z-index: 1; }
/* Ces animations tournent en boucle infinie : sans les mettre en pause une
   fois le hero sorti de l'écran, elles continuent à coûter du temps de
   rendu (compositing) pendant tout le reste de la visite. #hero.hero--in-view
   (bascule via IntersectionObserver dans script.js) ne les laisse tourner
   que quand le hero est effectivement visible. */
.anim-on .hero__rect--1 { animation: float-a  7s ease-in-out infinite -1.0s; animation-play-state: paused; }
.anim-on .hero__rect--2 { animation: float-b  9s ease-in-out infinite -3.5s; animation-play-state: paused; }
.anim-on .hero__rect--3 { animation: float-a  6s ease-in-out infinite -2.2s; animation-play-state: paused; }
.anim-on .hero__rect--4 { animation: float-b  8s ease-in-out infinite  0.0s; animation-play-state: paused; }
.anim-on .hero__rect--5 { animation: float-a 10s ease-in-out infinite -4.0s; animation-play-state: paused; }
#hero.hero--in-view .hero__rect--1,
#hero.hero--in-view .hero__rect--2,
#hero.hero--in-view .hero__rect--3,
#hero.hero--in-view .hero__rect--4,
#hero.hero--in-view .hero__rect--5 { animation-play-state: running; }

@keyframes float-a {
  0%, 100% { transform: translateY(0px)   translateX(0px); }
  50%       { transform: translateY(-9px)  translateX(3px); }
}
@keyframes float-b {
  0%, 100% { transform: translateY(0px)   translateX(0px); }
  33%       { transform: translateY(-7px)  translateX(-3px); }
  66%       { transform: translateY(-4px)  translateX(4px); }
}

/* ── Chevron de défilement ── */
.hero__scroll {
  position: absolute;
  bottom: 2rem;
  left: 50%;
  transform: translateX(-50%);
  opacity: .50;
  cursor: pointer;
  transition: opacity .2s;
}
.hero__scroll:hover { opacity: .85; }

/* ═══════════════════════════════════════════════════════
   SCROLL NAV
════════════════════════════════════════════════════════ */
.scroll-nav {
  position: sticky;
  top: 0;
  height: 100vh;
  width: 48px;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  z-index: 10;
}
.scroll-nav__track {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-between;
  height: 100%;
  width: 100%;
  padding: 40px 0;
}
.scroll-nav__track::before {
  content: '';
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  top: 40px;
  bottom: 40px;
  width: 1.5px;
  background: #e0e0e0;
  transition: background 1.2s ease;
}
.scroll-nav__dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #d0d0d0;
  position: relative;
  z-index: 1;
  flex-shrink: 0;
  pointer-events: auto;
  cursor: pointer;
  transition: background 0.3s, transform 0.3s;
}
.scroll-nav__dot:hover {
  background: #aaa;
  transform: scale(1.2);
}
.scroll-nav__dot.is-active {
  background: #22888D;
  transform: scale(1.35);
}
.scroll-nav__cursor {
  position: absolute;
  right: 26px;
  height: 28px;
  width: auto;
  transform-origin: center center;
  top: 0;
  transition: top 0.45s cubic-bezier(0.34, 1.56, 0.64, 1);
  /* Pose figée = même position/inclinaison que le repos de l'animation */
  transform: scaleX(-1) translateY(15px) translate(-1px, -1px);
}
.anim-on .scroll-nav__cursor {
  animation: cursor-float 1.8s linear infinite alternate;
}
@keyframes cursor-float {
  0%, 100% { transform: scaleX(-1) translateY(15px) translate(-1px, -1px); }
  50%      { transform: scaleX(-1) translateY(15px) translate(1px,   4px); }
}

/* ═══════════════════════════════════════════════════════
   PROJETS
════════════════════════════════════════════════════════ */
.projects {
  max-width: var(--max-w);
  margin: 0 auto;
  padding: 3rem var(--px) 2rem;
}
.projects__inner {
  display: flex;
  align-items: flex-start;
  gap: 32px;
}
.projects__cards {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2.5rem;
}

/* ── Carte ──────────────────────────────────────────── */
.card {
  background: rgba(255, 255, 255, 0.50);
  backdrop-filter: blur(28px) saturate(130%);
  -webkit-backdrop-filter: blur(28px) saturate(130%);
  border-radius: var(--r-card);
  box-shadow: 0 4px 28px rgba(0, 0, 0, 0.09);
  overflow: hidden;
  transition: background 1.1s cubic-bezier(.4,0,.2,1), box-shadow 1.1s cubic-bezier(.4,0,.2,1);
}

/* En-tête : intro + meta + timeline */
.card__top {
  display: grid;
  grid-template-columns: 1fr 160px 24px;
  gap: 1.5rem 3.5rem;
  padding: 54px 54px 40px;
  align-items: start;
}

.card__title {
  font-family: var(--f-ui);
  font-weight: 400;
  font-size: 50px;
  line-height: 1;
  text-transform: uppercase;
  letter-spacing: .02em;
  display: flex;
  align-items: center;
  gap: 0;
  margin-bottom: .9rem;
}
.card__dot {
  display: inline-block;
  height: 37.5px;
  width: 18.75px;
  border-radius: 37.5px 0 0 37.5px;
  background: var(--card-accent, #2EBD8A);
  flex-shrink: 0;
  margin-left: -24.75px;
  margin-right: 6px;
}
.card__desc {
  font-size: .82rem;
  font-weight: 400;
  line-height: 1.8;
  color: var(--c-text);
  transition: color 1.1s cubic-bezier(.4,0,.2,1);
}

/* Méta */
.card__meta {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  padding-top: .15rem;
}
.card__meta-group { display: flex; flex-direction: column; }
.card__meta-group dt {
  font-size: .67rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .1em;
  color: var(--c-muted);
  margin-bottom: .2rem;
  transition: color 1.1s cubic-bezier(.4,0,.2,1);
}
.card__meta-group dd {
  font-size: .82rem;
  font-weight: 400;
  color: var(--c-text);
  margin: 0;
  line-height: 1.5;
  transition: color 1.1s cubic-bezier(.4,0,.2,1);
}


/* ── Galerie photos ── */
.card__gallery {
  display: flex;
  gap: 3px;
  align-items: stretch;
  box-shadow: 0 0 12px rgba(0, 0, 0, 0.14);
}
.gallery__main {
  flex: 2;
  min-width: 0;
  overflow: hidden;
  aspect-ratio: 16 / 9;
}
.gallery__grid {
  flex: 1;
  min-width: 0;
  display: grid;
  grid-template-columns: 1fr;
  grid-template-rows: 1fr 1fr;
  gap: 3px;
}
.gallery__ph {
  width: 100%;
  height: 100%;
  background: #e8e8e8;
  background-image: linear-gradient(135deg, #e0e0e0 25%, #ebebeb 25%, #ebebeb 50%, #e0e0e0 50%, #e0e0e0 75%, #ebebeb 75%);
  background-size: 20px 20px;
}
.gallery__thumb,
.gallery__main {
  cursor: pointer;
}
.gallery__thumb {
  position: relative;
  overflow: hidden;
}
.gallery__thumb .gallery__ph,
.gallery__main .gallery__ph {
  height: 100%;
}
.gallery__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
/* +4 overlay */
.gallery__thumb--more {
  cursor: pointer;
}
.gallery__more-overlay {
  position: absolute;
  inset: 0;
  background: rgba(0,0,0,.45);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background .2s;
}
.gallery__thumb--more:hover .gallery__more-overlay {
  background: rgba(0,0,0,.6);
}
.gallery__more-overlay span {
  color: #fff;
  font-family: var(--f-body);
  font-size: 1.5rem;
  font-weight: 600;
  letter-spacing: .02em;
}

/* ── Modal galerie ── */
.gallery-modal {
  position: fixed;
  inset: 0;
  z-index: 500;
  display: flex;
  align-items: center;
  justify-content: center;
}
.gallery-modal[hidden] { display: none; }
.gallery-modal__backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0,0,0,.85);
  backdrop-filter: blur(6px);
}
.gallery-modal__inner {
  position: relative;
  width: min(90vw, 1100px);
  max-height: 90vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
}
.gallery-modal__track {
  width: 100%;
  aspect-ratio: 16/9;
  overflow: hidden;
  border-radius: 12px;
  position: relative;
  background: #111;
}
.gallery-modal__slide {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  transition: opacity .35s ease;
  pointer-events: none;
}
.gallery-modal__slide.is-active {
  opacity: 1;
  pointer-events: auto;
}
.gallery-modal__slide .gallery__ph {
  width: 100%;
  height: 100%;
  background: #1a1a1a;
  background-image: linear-gradient(135deg, #1a1a1a 25%, #222 25%, #222 50%, #1a1a1a 50%, #1a1a1a 75%, #222 75%);
  background-size: 24px 24px;
}
.gallery-modal__img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
}
.gallery-modal__close,
.gallery-modal__prev,
.gallery-modal__next {
  position: absolute;
  background: rgba(255,255,255,.12);
  border: none;
  color: #fff;
  cursor: pointer;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background .2s;
  z-index: 10;
}
.gallery-modal__close:hover,
.gallery-modal__prev:hover,
.gallery-modal__next:hover {
  background: rgba(255,255,255,.25);
}
.gallery-modal__close {
  top: -44px;
  right: 0;
  width: 36px;
  height: 36px;
  font-size: 1rem;
}
.gallery-modal__prev,
.gallery-modal__next {
  top: 50%;
  transform: translateY(-50%);
  width: 44px;
  height: 44px;
  font-size: 1.8rem;
  line-height: 1;
}
.gallery-modal__prev { left: -56px; }
.gallery-modal__next { right: -56px; }
.gallery-modal__dots {
  display: flex;
  gap: 8px;
}
.gallery-modal__dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: rgba(255,255,255,.35);
  cursor: pointer;
  transition: background .2s, transform .2s;
  border: none;
}
.gallery-modal__dot.is-active {
  background: #fff;
  transform: scale(1.3);
}

/* Pied de carte : typo + couleurs */
.card__footer {
  display: flex;
  gap: 4rem;
  align-items: flex-start;
  padding: 54px;
  border-top: 1px solid var(--c-border);
  transition: border-color 1.1s cubic-bezier(.4,0,.2,1);
}
.card__note {
  flex: 1 1 300px;
  max-width: 380px;
  margin-left: auto;
  font-size: .92rem;
  font-style: italic;
  line-height: 1.7;
  color: var(--c-muted);
  transition: color 1.1s cubic-bezier(.4,0,.2,1);
}
.card__section-label {
  display: block;
  font-size: .68rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .12em;
  color: var(--c-muted);
  margin-bottom: .875rem;
  transition: color 1.1s cubic-bezier(.4,0,.2,1);
}

/* Échantillons de typographie */
.card__typo { min-width: 200px; }
.card__font { line-height: 1.2; }
.card__font--primary {
  font-size: clamp(1.8rem, 2.5vw, 2.5rem);
  font-weight: 700;
  color: var(--c-text);
  transition: color 1.1s cubic-bezier(.4,0,.2,1);
}
.card__font--secondary {
  font-size: clamp(1.1rem, 1.6vw, 1.5rem);
  font-weight: 400;
  color: var(--c-text);
  margin-top: .5rem;
  transition: color 1.1s cubic-bezier(.4,0,.2,1);
}

/* Swatches couleurs — grille 2×2 */
.card__palette { flex: 1; }
.card__swatches {
  display: grid;
  grid-template-columns: repeat(2, 76px);
  grid-template-rows: repeat(2, 76px);
  gap: 0;
}
.swatch {
  width: 76px;
  height: 76px;
  border-radius: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
  overflow: hidden;
  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.22);
  transition: border-radius .2s ease;
}
.swatch:hover {
  border-radius: 20px;
}
.swatch::after {
  content: attr(data-hex);
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'Poppins', sans-serif;
  font-size: 14px;
  font-weight: 400;
  color: var(--swatch-text, #111118);
  padding: 8px;
  box-sizing: border-box;
  opacity: 0;
  transition: opacity .2s ease;
  pointer-events: none;
  text-align: center;
  line-height: 1.2;
}
.swatch:hover::after {
  opacity: 1;
}

/* ═══════════════════════════════════════════════════════
   AUTRES PROJETS
════════════════════════════════════════════════════════ */
.other {
  max-width: var(--max-w);
  margin: 124px auto 0;
  padding: 0 var(--px);
}
.other__inner {
  padding: 0 0 2.5rem;
}
.other__header {
  display: flex;
  align-items: center;
  gap: .75rem;
  margin-bottom: 1rem;
}
.other__title {
  font-family: var(--f-ui);
  font-weight: 400;
  font-size: 20px;
}
.other__text {
  font-size: .82rem;
  font-weight: 400;
  color: var(--c-text);
  max-width: 640px;
}

/* ═══════════════════════════════════════════════════════
   CONTACT
════════════════════════════════════════════════════════ */
.contact {
  padding: 124px var(--px) 4.5rem;
  text-align: center;
}
.contact__inner {
  max-width: 580px;
  margin: 0 auto;
}
.contact__title {
  font-family: var(--f-ui);
  font-weight: 400;
  font-size: clamp(2rem, 4vw, 3.25rem);
  text-transform: uppercase;
  letter-spacing: .02em;
  margin-bottom: .35rem;
}
.contact__sub {
  font-size: .9rem;
  color: var(--c-muted);
  margin-bottom: 2.5rem;
}
.contact__form {
  text-align: left;
  display: flex;
  flex-direction: column;
  gap: 1rem;
}
/* Honeypot Netlify Forms : display:none (pas l'attribut hidden) pour rester
   un champ "normal" que les bots naïfs remplissent quand même. */
.form__honeypot { display: none; }
.field { display: flex; flex-direction: column; gap: .35rem; }
.field--consent { flex-direction: row; }
.field__consent {
  display: flex;
  align-items: flex-start;
  gap: .6rem;
  font-size: .8rem;
  line-height: 1.5;
  color: var(--c-muted);
  text-align: left;
  cursor: pointer;
}
.field__consent input {
  margin-top: .2rem;
  flex-shrink: 0;
  accent-color: var(--c-accent);
}
.field__consent a {
  color: var(--c-text);
  text-decoration: underline;
}
.field__error {
  font-size: .82rem;
  color: #ef4444;
}
.field__label {
  font-size: .82rem;
  font-weight: 400;
  color: var(--c-text);
}
.field__input {
  width: 100%;
  padding: .65rem .9rem;
  font-family: var(--f-body);
  font-size: .9rem;
  color: var(--c-text);
  background: #fff;
  border: 1.5px solid #cdd5da;
  border-radius: 6px;
  outline: none;
  resize: vertical;
  transition: border-color var(--dur);
}
.field__input:focus { border-color: var(--c-accent); }
.field__textarea { min-height: 100px; }
.btn--send { align-self: center; padding: .75rem 2.75rem; margin-top: .75rem; }

/* ═══════════════════════════════════════════════════════
   FOOTER
════════════════════════════════════════════════════════ */
.footer {
  /* padding (pas de margin sur les enfants) pour cet espace du bas : une
     margin sur le dernier enfant peut laisser un espace en bas de body non
     couvert par le fond dégradé de la page (.page-bg suit la hauteur de
     body, pas celle d'un enfant + sa margin qui dépasse). */
  padding: 56px var(--px) 40px;
  border-top: 1px solid #c2d0cb;
}
.footer__nav {
  max-width: var(--max-w);
  margin: 0 auto;
  display: flex;
  gap: 4rem;
  flex-wrap: wrap;
}
.footer__col {
  display: flex;
  flex-direction: column;
  gap: .6rem;
}
.footer__col-title {
  font-size: .78rem;
  color: #5c6b76;
}
.footer__link {
  display: inline-block;
  width: fit-content;
  font-size: .82rem;
  font-weight: 400;
  color: #2F2F2F;
  transition: color var(--dur);
}
.footer__link:hover { color: var(--c-accent); }

/* Barre du bas : copyright à gauche, identité légale (raison sociale,
   SIRET) + liens légaux empilés et alignés à droite. Pas de séparateur :
   les colonnes Contact/Réseaux sociaux au-dessus s'enchaînent directement. */
.footer__bottom {
  max-width: var(--max-w);
  margin: 1.75rem auto 0;
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  gap: 1.5rem;
  flex-wrap: wrap;
}
.footer__legal-nav {
  display: flex;
  align-items: center;
  gap: .5rem;
}
.footer__legal-link {
  font-size: .8rem;
  color: #5c6b76;
  transition: color var(--dur);
}
.footer__legal-link:hover { color: var(--c-accent); }
.footer__legal-sep {
  font-size: .8rem;
  color: #5c6b76;
}
.footer__copyright {
  font-size: .74rem;
  color: #5c6b76;
}

/* ═══════════════════════════════════════════════════════
   ANIMATIONS — pilotées par .anim-on sur <body>
════════════════════════════════════════════════════════ */
.anim-on .hero__scroll {
  animation: bounce 2s ease-in-out infinite;
  animation-play-state: paused;
}
#hero.hero--in-view .hero__scroll {
  animation-play-state: running;
}
@keyframes bounce {
  0%, 100% { transform: translateX(-50%) translateY(0); }
  50%       { transform: translateX(-50%) translateY(6px); }
}

/* ═══════════════════════════════════════════════════════
   RESPONSIVE
════════════════════════════════════════════════════════ */

/* ── Grand écran (≥ 1440px) ─────────────────────────── */
@media (min-width: 1440px) {
  /* --max-w était à 100% (pas de limite) : sur très grand écran, le
     conteneur grandissait sans plafond et le nom (mis à l'échelle par
     script.js) débordait de sa boîte. 1600px reste plus généreux que le
     1300px de base, sans grandir indéfiniment. (zoom avait été tenté
     comme correctif global, mais entrait en conflit avec les mesures
     getBoundingClientRect() de script.js — retiré.) */
  :root { --px: 124px; --max-w: 1600px; }
  .hero__right { flex: 0 0 52%; }

  /* Blobs mood plus grands + plus intenses pour couvrir les cards élargies */
  .mood--a { width: 1100px; height: 1100px; }
  .mood--b { width: 950px;  height: 950px;  }
  .mood--eke-deka.mood--a     { background: radial-gradient(circle, rgba(224,123,57,.42) 0%, transparent 65%); }
  .mood--elmy.mood--a         { background: radial-gradient(circle, rgba(27,140,112,.65) 0%, transparent 65%); }
  .mood--game-n-chill.mood--a { background: radial-gradient(circle, rgba(191,144,218,.65) 0%, transparent 65%); }
  .mood--ameliorama-3.mood--a { background: radial-gradient(circle, rgba(220,194,142,.65) 0%, transparent 65%); }
}

/* ── Desktop (> 1024px) : petits titres + paragraphes +2px ── */
@media (min-width: 1025px) {
  .hero__tagline          { font-size: calc(.875rem + 2px); }
  .card__desc,
  .card__meta-group dd,
  .other__text            { font-size: calc(.82rem + 2px); }
  .contact__sub           { font-size: calc(.9rem + 2px); }
  .card__meta-group dt    { font-size: calc(.67rem + 2px); }
  .other__title           { font-size: 22px; }
}

/* ── PC portable (≤ 1280px) ─────────────────────────── */
@media (max-width: 1280px) {
  .hero__right { flex: 0 0 46%; }
  .card__top   { gap: 1.5rem 2rem; }
}

/* ── Tablette (≤ 1024px) ─────────────────────────────── */
@media (max-width: 1024px) {
  /* Nav */
  .nav__links         { display: none; }
  .anim-toggle__label { display: none; }

  /* Codes hexa : pas de hover au tactile, on affiche au scroll */
  .swatch--visible::after { opacity: 1; }

  /* Hero */
  .hero         { min-height: auto; padding: 3rem var(--px); }
  .hero__inner  { flex-direction: column; gap: 2rem; }
  .hero__left   { width: 100%; gap: 2rem; }
  .hero__right  { flex: none; width: 100%; margin-top: 2.5rem; }

  /* hero__left occupe désormais toute la largeur : le bloc photo+titre
     est agrandi en bloc (transform: scale) pour garder strictement les
     mêmes proportions internes, avec une marge pour compenser le débord
     visuel (le scale ne modifie pas la taille de la grille sous-jacente).
     width:80% AVANT le scale(1.25) : 80% × 1.25 = 100% — la boîte, une
     fois agrandie visuellement, occupe exactement la largeur disponible
     au lieu de déborder de 25% sur la droite (transform ne change pas la
     largeur réservée dans la mise en page, seulement le rendu visuel —
     sans ce recalage, la partie droite du bloc, ALEXIS REY et UI/UX
     DESIGNER, sortait de l'écran et était invisible, coupée par
     l'overflow-x:hidden du body). */
  .hero__hero-row {
    width: 80%;
    transform: scale(1.25);
    transform-origin: top left;
    margin-bottom: 3.5rem;
  }

  /* Rééquilibrage interne : photo un peu plus petite, bloc REY ALEXIS/UI UX
     un peu plus grand (proportions internes de chaque élément conservées). */
  .hero__photo-frame { width: 190px; }
  .hero__photo-blob  { height: 103px; }
  .hero__photo       { height: 178px; }
  :root { --hero-name-h: 2rem; }
  .hero__role        { font-size: 2.5rem; }

  /* Flèche scroll — en flux normal sous le contenu, centrée via
     align-self (et non plus left:50%+translateX comme en absolute) :
     l'animation de rebond ne doit garder que le décalage vertical,
     sinon le translateX(-50%) hérité la décentre. */
  .hero__scroll {
    position: static;
    transform: none;
    align-self: center;
    margin-top: 3rem;
  }
  .anim-on .hero__scroll {
    animation: bounce-static 2s ease-in-out infinite;
    animation-play-state: paused;
  }
  @keyframes bounce-static {
    0%, 100% { transform: translateY(0); }
    50%       { transform: translateY(6px); }
  }

  /* Scroll nav */
  .scroll-nav   { display: none; }

  /* Cards */
  .card__top {
    grid-template-columns: 1fr 140px;
    padding: 40px 40px 30px;
    gap: 1.25rem 2rem;
  }
  .card__title  { font-size: 38px; }
  .card__dot {
    height: 28.5px;
    width: 14.25px;
    border-radius: 28.5px 0 0 28.5px;
    margin-left: -20.25px;
  }
  .card__footer { padding: 40px; gap: 2.5rem; }

  /* Spacing */
  .other   { margin-top: 80px; }
  .contact { padding: 80px var(--px) 3rem; }
  .footer  { padding: 40px var(--px) 32px; }
}

/* ── Footer : empilé et centré (≤ 768px) ─────────────── */
@media (max-width: 768px) {
  .footer__nav {
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 2rem;
  }
  .footer__col { align-items: center; }
  .footer__bottom {
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 1rem;
  }
}

/* ── Mobile (≤ 600px) ────────────────────────────────── */
@media (max-width: 600px) {
  /* Nav */
  .nav__logo { font-size: .74rem; }
  .anim-toggle__label { display: inline; }

  /* 30px de plus que les 3rem (48px) déjà posés au palier tablette. */
  .hero__scroll { margin-top: calc(3rem + 30px); }

  /* Curseur remonté pour toucher les pointillés. */
  .hero__cursor { margin-bottom: -1.55rem; }

  /* Fond léger sur "Anglais" (le padding haut/bas identique est déjà posé
     dans la règle de base, pas besoin de le resurcharger ici). */
  .lang-btn--option {
    background: rgba(0, 0, 0, .04);
    border-radius: 6px;
  }

  /* will-change : prévient le GPU mobile de préparer la couche du flou
     backdrop-filter à l'avance, pour éviter que le texte de la card
     s'affiche visiblement avant que le fond flouté n'ait fini de se
     composer (flash contenu-avant-fond au premier rendu). */
  .card { will-change: backdrop-filter, background; }

  /* Fond décoratif : un filter: blur() large coûte cher à peindre, encore
     plus sur un GPU mobile que sur desktop. Rayon réduit ici uniquement
     (aucun changement sur desktop) ; les blobs restent aussi doux à l'œil,
     juste moins coûteux à recalculer. */
  .blob { filter: blur(45px); }
  .mood { filter: blur(40px); }

  /* Hero — photo + texte 50/50 en ligne */
  .hero         { padding: 2rem var(--px) 2.5rem; }
  .hero__inner  { gap: 2rem; }
  .hero__left {
    grid-template-columns: 1fr;
    grid-template-rows: auto auto auto;
    align-items: flex-start;
    gap: 1rem;
  }
  .hero__photo-wrap { grid-column: 1; grid-row: 1; }
  .hero__text       { grid-column: 1; grid-row: 2; width: 100%; }
  .hero__actions    { grid-column: 1; grid-row: 3; width: 100%; display: flex; justify-content: space-between; }
  .hero__right      { display: none; }

  /* 50 % gauche : photo */
  .hero__photo-wrap  { flex: 1; min-width: 0; }
  .hero__hero-row { display: flex; flex-direction: row; align-items: flex-end; gap: 1rem; }
  .hero__photo-wrap { flex: 0 0 auto; width: auto; }
  .hero__hero-title { flex: 1; min-width: 0; }
  /* Sous 600px, on abandonne le transform:scale(1.25) hérité du breakpoint
     1024px : il agrandissait tout le bloc APRÈS coup, mais l'espace
     réellement disponible pour le nom (mesuré par script.js AVANT le scale,
     voir offsetWidth dans fitHeroName) restait celui, plus étroit, de la
     boîte non agrandie — sur les écrans les plus étroits, ça ne laissait
     pas assez de place et forçait le nom/rôle à dépasser malgré le plafond
     de sécurité (HERO_NAME_MIN_H/HERO_ROLE_MIN_FS). En direct (sans scale),
     script.js mesure la largeur RÉELLEMENT disponible et ajuste le nom/rôle
     pour la remplir exactement, sans jamais la dépasser. Les tailles ci-
     dessous (photo, badge) sont les anciennes valeurs × 1.25, pour un rendu
     visuel identique à avant, juste sans le transform. */
  .hero__hero-row { width: 100%; transform: none; margin-bottom: 2rem; }
  /* Répartition 1/3 (photo) — 2/3 (nom/rôle) demandée explicitement pour
     mobile : .hero__photo-wrap se dimensionne sur .hero__photo-frame (flex:
     0 0 auto), donc sa largeur en px cible ~1/3 d'une largeur de contenu
     mobile typique (~360px) ; .hero__hero-title (flex:1) récupère les deux
     tiers restants automatiquement. */
  .hero__photo-frame { width: 115px; }
  .hero__photo {
    height: 115px;
    border-radius: 11px 11px 23px 23px;
  }
  .hero__photo-blob  { height: 66px; border-radius: 23px; }

  /* Badge proportionnel à la photo */
  .hero__badge {
    font-size: 7px;
    padding: 5px;
    left: -8px;
    bottom: -11px;
    border-radius: 8px;
    gap: 3px;
  }
  .hero__badge-dot { width: 5px; height: 5px; }

  /* 50 % droite : texte */
  .hero__text        { gap: 1rem; }
  .hero__title-block { width: 100%; min-width: 0; flex-shrink: 1; }
  .hero__rey-row     { min-width: 0; }
  /* Hauteur fluide (vw) plutôt que fixe : sur les très petits écrans,
     REY/ALEXIS rétrécit avec la largeur au lieu de dépasser le padding. */
  :root { --hero-name-h: clamp(1rem, 6vw, 1.4rem); }
  .hero__role        { font-size: 1rem; }
  .hero__tagline     { max-width: 100%; width: 100%; }

  /* Boutons pleine largeur sous le 50/50 */
  .hero__actions  { gap: .5rem; flex-wrap: wrap; }
  .hero__actions .btn {
    flex: 1 1 0;
    min-width: 0;
    width: calc(50% - .25rem);
    font-size: 11px;
    padding: .5rem .75rem;
    white-space: normal;
    text-align: center;
    line-height: 1.3;
  }

  /* Projects */
  .projects       { padding: 2rem var(--px) 1rem; }
  .projects__cards { gap: 1.5rem; }

  /* Cards */
  .card { border-radius: 20px; }
  .card__top {
    grid-template-columns: 1fr;
    padding: 1.75rem 1.5rem 1.25rem;
    gap: 1.25rem;
  }
  .card__title  { font-size: 32px; }
  .card__dot {
    height: 20px;
    width: 10px;
    border-radius: 20px 0 0 20px;
    margin-left: -18px;
    margin-right: 3px;
  }
  .card__meta   { flex-direction: row; flex-wrap: wrap; gap: 1rem 2rem; }
  .card__footer {
    flex-direction: column;
    padding: 1.5rem 1.5rem 2rem;
    gap: 1.5rem;
  }
  /* La card doit "hug" son contenu jusqu'au dernier paragraphe : le
     flex-basis de 300px (pensé pour une colonne côte à côte) devient
     une hauteur minimale en flex-direction:column et laisse du vide. */
  .card__note {
    flex: 0 0 auto;
    width: 100%;
    max-width: 100%;
    margin-left: 0;
  }
  .card__swatches {
    grid-template-columns: repeat(2, 60px);
    grid-template-rows: repeat(2, 60px);
  }
  .swatch { width: 60px; height: 60px; }
  .swatch::after { font-size: 10px; }

  /* Galerie */
  .card__gallery    { flex-direction: column; }
  .gallery__main    { aspect-ratio: 16/9; height: auto; }
  .gallery__grid    { display: flex; height: 100px; }
  .gallery__thumb   { flex: 1; min-width: 0; }

  /* Modal */
  .gallery-modal__inner { width: 96vw; }
  .gallery-modal__prev  { left: 4px; }
  .gallery-modal__next  { right: 4px; }

  /* Bas de page */
  .other   { margin-top: 60px; }
  .contact { padding: 60px var(--px) 2.5rem; }
  .footer  { padding: 32px var(--px) 24px; }
}

/* ═══════════════════════════════════════════════════════
   PAGES LÉGALES (mentions légales, confidentialité)
════════════════════════════════════════════════════════ */
.legal__back {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  font-size: .82rem;
  color: var(--c-muted);
  transition: color var(--dur);
}
.legal__back:hover { color: var(--c-accent); }

.legal {
  max-width: 760px;
  margin: 0 auto;
  padding: 40px var(--px) 96px;
}
.legal__title {
  font-family: var(--f-ui);
  font-weight: 400;
  font-size: clamp(1.8rem, 3.5vw, 2.6rem);
  text-transform: uppercase;
  letter-spacing: .02em;
  margin-bottom: .5rem;
}
.legal__updated {
  font-size: .78rem;
  color: var(--c-muted);
  margin-bottom: 3rem;
}
.legal__section { margin-bottom: 2.5rem; }
.legal__section h2 {
  font-family: var(--f-ui);
  font-weight: 400;
  font-size: 1.15rem;
  text-transform: uppercase;
  letter-spacing: .02em;
  margin-bottom: .75rem;
  color: #464646;
}
.legal__section p { margin-bottom: 1rem; }
.legal__section p,
.legal__section li {
  font-size: .9rem;
  line-height: 1.8;
  color: var(--c-text);
}
.legal__section ul { padding-left: 1.25rem; list-style: disc; }
.legal__section a { color: var(--c-accent); text-decoration: underline; }

@media (max-width: 600px) {
  .legal { padding-left: 24px; padding-right: 24px; }
}
