/* Styles KJC — d'après le Figma KJC-V2 base 1440 (Home 68:2, About 74:436).
   Mobile-first fluide : tout grandit en vw jusqu'à 1440 px puis se fige, les
   gouttières absorbant le surplus (voir --gutter dans tokens.css). */
@import url("/static/tokens.css");

*, *::before, *::after { box-sizing: border-box; }
/* --gutter se mesure en 100vw : sans barre de défilement réservée, l'apparition
   d'un ascenseur (Windows) décalerait la colonne de contenu de ~8 px. */
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; scrollbar-gutter: stable; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--c-bg);
  color: var(--c-text);
  font-family: var(--font-sans);
  font-size: var(--fs-md);
  font-weight: var(--fw-body);
  /* IDENTITY §5 : 1,6 à 1,85 pour le corps de texte. */
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}
img, video, svg { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
button { font: inherit; cursor: pointer; }
h1, h2, h3, h4 { margin: 0; font-weight: var(--fw-display); line-height: 1; }
main { display: block; }

/* Déjà borné à 1440 px et centré : c'est la gouttière FLUIDE qui s'applique
   (la figée cumulerait deux centrages et étranglerait le contenu au-delà). */
.container { max-width: var(--container); margin-inline: auto; padding-inline: var(--gutter-fluid); }
.visually-hidden { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

/* Une section = un écran (`--section-h`, cf. tokens.css) : la Home avance d'un
   écran par mouvement, quelle que soit la quantité de contenu. Les sections
   plus courtes que l'écran centrent leur contenu dans la hauteur (`.latest`,
   `.social`, `.about` ci-dessous) ; `.services` garde son flux normal, son
   épinglage gère déjà sa propre course. */
.section { position: relative; min-height: var(--section-h); }

/* Label de section centré (LATEST WORK / SERVICES / SOCIAL) */
.section__label {
  /* pas `eyebrow` d'IDENTITY §5 : capitales, 700, tracking 0,14em */
  margin: 0; text-align: center; text-transform: uppercase;
  font-weight: var(--fw-label); font-size: var(--fs-md); letter-spacing: var(--eyebrow-tracking);
  /* Le Figma pose 46 px au-dessus du label et 18 px en dessous — mais il n'est
     pas cohérent d'une section à l'autre (0 px avant « Our Services », 80 px
     avant « Social ») et ses 18 px collent le label au bloc qui suit : à 1440
     le label touche presque un rail de 453 px de haut. On retient donc une
     valeur unique pour les trois sections, 60/40 (cf. GUIDE §8).
     L'interligne dessiné (45 px pour un texte de 16 px) ajouterait ~13 px de
     part et d'autre : la boîte de ligne reste serrée, tout l'espacement passe
     par le padding. */
  line-height: 1;
  color: var(--c-text); padding-block: clamp(2.25rem, 4.167vw, 60px) clamp(1.5rem, 2.778vw, 40px);
}

/* ── Bande « clap » multicolore ───────────────────────────────────────────────
   Reconstruite en CSS depuis l'ancien /img/clap.svg — les couleurs descendent
   des tokens au lieu d'être figées dans un fichier. Géométrie du SVG conservée
   sur sa base 1957 : période de 162 (lame 81 + espace 81), hauteur 99,5,
   inclinaison atan(93,5 / 99,5) ≈ 43,2°. Le motif glisse en continu de gauche
   à droite (une période de 12 cellules en 150 s, soit ~9,5 px/s à 1440) ; la
   translation retombe exactement sur le motif — boucle invisible. */
.clap {
  --clap-cell:  8.278vw;   /* 162 / 1957 */
  --clap-blade: 4.139vw;   /*  81 / 1957 */
  --clap-gap: calc(var(--clap-cell) - var(--clap-blade));
  position: relative; width: 100%; height: 5.084vw;   /* 99,5 / 1957 */
  overflow: hidden;
}
/* la copie du footer est en miroir (comme l'ancien SVG retourné) ; la
   direction d'animation est inversée pour garder le même sens visuel */
.clap--flip { transform: scaleX(-1); }
.clap--flip .clap__strip { animation-direction: reverse; }
.clap__strip {
  position: absolute; inset: 0 auto 0 0;
  display: flex; gap: var(--clap-gap); width: max-content; height: 100%;
  will-change: transform;
  animation: clap-slide 150s linear infinite;
}
.clap__blade { flex: none; width: var(--clap-blade); height: 100%; transform: skewX(-43.2deg); }
.clap__blade--blue   { background: var(--c-blue); }
.clap__blade--paper  { background: var(--c-paper); }
.clap__blade--yellow { background: var(--c-yellow); }
.clap__blade--red    { background: var(--c-red); }
.clap__blade--green  { background: var(--c-green); }
@keyframes clap-slide {
  from { transform: translateX(calc(-12 * var(--clap-cell))); }
  to   { transform: translateX(0); }
}
@media (prefers-reduced-motion: reduce) { .clap__strip { animation: none; } }

/* ── Header / nav ───────────────────────────────────────────────────────────── */
.site-header {
  position: absolute; inset: 0 0 auto 0; z-index: 50;
  display: grid; grid-template-columns: auto 1fr auto; align-items: center;
  gap: clamp(1rem, 4vw, 4rem);
  /* Figma 1440 : logo 40×55 posé à y=57, nav sur la même ligne médiane
     (y=84,5) — bandeau d'environ 145 px de haut (voir --header-h). */
  padding: clamp(1.25rem, 3.958vw, 57px) var(--gutter) 0;
}
.site-header__logo img { height: clamp(32px, 3.82vw, 55px); width: auto; }
/* Inter capitales, graisse 700. L'emphase (survol, page active) passe par la
   COULEUR seule — aucun soulignement. Le repos descend à 55 % de papier : à
   80 % l'écart avec le blanc plein était invisible sur photo, le survol ne se
   voyait pas. */
.site-nav {
  justify-self: center; display: flex; gap: clamp(1rem, 2.778vw, 40px);
  align-items: center; font-family: var(--font-sans); font-weight: var(--fw-label);
  font-size: var(--fs-nav); letter-spacing: 0.02em; text-transform: uppercase;
}
.site-nav a { color: rgb(var(--c-paper-rgb) / 0.55); }
.site-nav a[aria-current="page"] { color: var(--c-text); }
.site-nav a:hover { color: var(--c-text); }
/* même famille, même graisse et même casse que « Work / About / … » */
.lang-switch {
  justify-self: end; font-family: var(--font-sans); font-weight: var(--fw-label);
  font-size: var(--fs-nav); text-transform: uppercase;
  color: rgb(var(--c-paper-rgb) / 0.55); letter-spacing: 0.02em;
}
.lang-switch:hover { color: var(--c-text); }
@media (max-width: 900px) {
  .site-header { grid-template-columns: auto auto; }
  .site-nav { display: none; }
}

/* ── HERO ───────────────────────────────────────────────────────────────────── */
.hero { position: relative; min-height: var(--section-h); overflow: hidden; display: flex; }
.hero__media { position: absolute; inset: 0; }
/* Coupe FRANCHE entre les affiches (refonte teasers) : chaque projet joue son
   teaser de ~8 s, la fin de la vidéo fait la coupe — aucune transition, comme
   un cut de montage. */
.hero__slide { position: absolute; inset: 0; opacity: 0; }
.hero__slide.is-active { opacity: 1; }
.hero__slide img, .hero__slide video { width: 100%; height: 100%; object-fit: cover; }
.hero__scrim { position: absolute; inset: 0; background: linear-gradient(180deg, rgb(var(--c-ink-rgb) / .35) 0%, rgb(var(--c-ink-rgb) / .15) 40%, rgb(var(--c-ink-rgb) / .65) 100%); }

/* Composition bas-gauche (référence Photoshop validée, après la V4 centrée) :
   le bloc titre + kicker s'ancre dans le coin bas-gauche, calé sur la
   gouttière — même axe vertical que le logo du header — et sa ligne de base
   rejoint celle de la légende projet en bas à droite (même retrait bas que
   .hero__caption). Tailles inchangées. */
.hero__inner {
  position: relative; z-index: 2; align-self: end;
  width: 100%; padding-inline: var(--gutter);
  padding-bottom: clamp(1.5rem, 4.167vw, 60px);
  display: grid; justify-items: start; text-align: left;
}
/* « WE ARE KJC » en Replique Sans (la voix de la marque) : une seule graisse,
   le contraste 900/200 italique de l'ancienne version disparaît. */
.hero__title {
  display: flex; flex-direction: column; align-items: flex-start; color: var(--c-text-80);
  font-size: var(--fs-hero); line-height: 0.829; letter-spacing: -0.01em; text-transform: uppercase;
  font-family: var(--font-brand); font-weight: 400;
}
/* Kicker : Inter 700/16 en capitales, tracking eyebrow, blanc plein — assez
   présent pour tenir sous le titre sans jamais rivaliser avec lui. */
.hero__subtitle {
  margin: clamp(1rem, 1.806vw, 26px) 0 0;
  font-weight: var(--fw-label); font-size: var(--fs-md); line-height: 1.4;
  letter-spacing: var(--eyebrow-tracking); text-transform: uppercase; color: var(--c-text);
}
.hero__caption {
  position: absolute; z-index: 2; right: var(--gutter); bottom: clamp(1.5rem, 4.167vw, 60px);
  display: flex; flex-direction: column; align-items: flex-end; text-align: right;
  gap: 10px; color: var(--c-text-80); max-width: 300px;
}
.hero__caption-title { font-weight: 700; font-size: var(--fs-lead); letter-spacing: -0.015em; }
.hero__caption-more { font-weight: var(--fw-label); font-size: var(--fs-md); letter-spacing: -0.015em; display: inline-flex; align-items: center; gap: 8px; }
.hero__caption-more svg { width: 18px; height: 18px; transition: transform var(--dur) var(--ease-out); }
.hero__caption:hover { color: var(--c-text); }
.hero__caption:hover .hero__caption-more svg { transform: translateX(5px); }
/* la légende se relaie à mi-glissement au lieu de sauter */
.hero__caption { transition: opacity 0.3s var(--ease-out), transform 0.3s var(--ease-out); }
.hero__caption.is-swapping { opacity: 0; transform: translateX(14px); }
@media (prefers-reduced-motion: reduce) {
  .hero__caption { transition-duration: 1ms; }
  .hero__caption-more svg { transition: none; }
}

/* ── Bouton pilule (gabarit aurore : .btn d'about.html) ───────────────────────
   IDENTITY §9 : le bouton primaire est l'inversion encre/papier, graisse 700.
   Sur cette surface sombre, l'inversion c'est donc un aplat PAPIER à texte
   ENCRE — c'est la variante par défaut. Gabarit repris d'aurore : Inter 700
   15 px, tracking -0.01em, padding 15/32, rayon --r-pill, survol scale(1.05)
   sur la courbe signature. Plus de carré-flèche ni d'animation de flèche.
   Les variantes rouge/jaune restent des aplats de marque (IDENTITY §3). */
.btn {
  --btn-bg: var(--c-paper); --btn-fg: var(--c-ink);
  display: inline-flex; align-items: center; justify-content: center;
  padding: 15px 32px;
  background: var(--btn-bg); color: var(--btn-fg); border-radius: var(--r-pill);
  font-weight: var(--fw-label); font-size: 15px; letter-spacing: -0.01em;
  line-height: 1; white-space: nowrap;
  transition: transform 0.3s var(--ease-out);
}
.btn:hover { transform: scale(1.05); }
.btn:active { transform: scale(0.98); transition-duration: 80ms; }
.btn--light  { --btn-bg: var(--c-paper); --btn-fg: var(--c-ink); }
.btn--dark   { --btn-bg: var(--c-ink); --btn-fg: var(--c-paper); }
.btn--red    { --btn-bg: var(--c-red); --btn-fg: var(--c-paper); }
.btn--yellow { --btn-bg: var(--c-yellow); --btn-fg: var(--c-ink); }
/* Secondaire (IDENTITY §9, gabarit .signin d'aurore) : fond transparent,
   filet de 1 px qui se renforce au survol. */
.btn--outline {
  --btn-bg: transparent; --btn-fg: var(--c-text);
  border: 1px solid var(--c-line-glass);
  transition: transform 0.3s var(--ease-out), border-color 0.25s ease;
}
.btn--outline:hover { border-color: var(--c-paper); }
/* Lien externe : flèche ↗ masquée (même dessin que le footer kjc/aurore),
   révélée au survol. L'espace est réservé en permanence (opacity, pas
   display) : révéler la flèche ne décale jamais le libellé sous le curseur.
   Masquée plutôt que dessinée en couleur : elle hérite de la couleur du lien. */
.btn--ext::after,
.footer-links a[target="_blank"]::after {
  content: '';
  display: inline-block;
  width: 0.72em;
  height: 0.72em;
  margin-left: 0.32em;
  vertical-align: -0.01em;
  background-color: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10' fill='none' stroke='white' stroke-width='1.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M1.4 8.6 8.6 1.4'/%3E%3Cpath d='M4.3 1.4H8.6V5.7'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10' fill='none' stroke='white' stroke-width='1.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M1.4 8.6 8.6 1.4'/%3E%3Cpath d='M4.3 1.4H8.6V5.7'/%3E%3C/svg%3E") center / contain no-repeat;
  opacity: 0;
  transform: translate(-0.15em, 0.15em);
  transition: opacity 0.2s ease, transform 0.3s cubic-bezier(0.16, 1, 0.3, 1);
}
.btn--ext:hover::after,
.btn--ext:focus-visible::after,
.footer-links a[target="_blank"]:hover::after,
.footer-links a[target="_blank"]:focus-visible::after {
  opacity: 1;
  transform: translate(0, 0);
}
@media (prefers-reduced-motion: reduce) {
  .btn, .btn--ext::after, .footer-links a[target="_blank"]::after { transition: none; }
  .btn:hover, .btn:active { transform: none; }
}

/* ── LATEST WORK ────────────────────────────────────────────────────────────── */
/* Le rail est piloté par transform (variables posées par motion.js) dès que le JS
   tourne ; sans JS il reste un simple scroll horizontal natif. */
.latest {
  --rail-gap: clamp(10px, 1.389vw, 20px);
  --rail-shift: 0px;   /* translation du rail, posée par motion.js */
  --rail-drag: 0px;    /* offset temporaire pendant un swipe */
  --rail-end: 0;       /* 0 → 1 : progression vers /work */
  --rail-dur: 560ms;
  /* le bloc détail se termine 63 px avant le bas de la section */
  background: var(--c-bg); padding-bottom: clamp(2rem, 4.375vw, 63px);
  /* hauteur d'affiche : la référence Figma, bornée à un demi-écran (cf.
     `.work-card`) */
  --card-h: min(clamp(255px, 31.458vw, 453px), 50svh);
  /* le rail + sa légende se centrent dans l'écran de la section. `safe` :
     si le contenu dépasse malgré tout, il repart du HAUT au lieu de déborder
     des deux côtés et de mordre sur la section précédente.
     `minmax(0, 1fr)` et non `1fr` : par défaut un élément de grille refuse de
     descendre sous sa largeur min-content, et le bandeau de contrôle (une
     barre de progression par affiche) est plus large que l'écran — la section
     partait alors en défilement horizontal. */
  display: grid; grid-template-columns: minmax(0, 1fr);
  align-content: center; align-content: safe center;
  -webkit-tap-highlight-color: transparent;
}
.latest:focus { outline: none; }
.latest:focus-visible { outline: 2px solid var(--c-text); outline-offset: -4px; }
.latest__rail-wrap { padding-inline: var(--gutter); }
.latest__viewport { overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch; padding-bottom: 4px; }
.latest__viewport::-webkit-scrollbar { display: none; }
.latest__rail { display: flex; gap: var(--rail-gap); }

/* mode piloté : plus de scroll natif, translation + masque de bord droit */
.latest.is-live { touch-action: pan-y; }
.latest.is-live .latest__viewport {
  overflow: hidden; cursor: grab;
  -webkit-mask-image: linear-gradient(to right, #000 0, #000 calc(100% - 90px), transparent 100%);
          mask-image: linear-gradient(to right, #000 0, #000 calc(100% - 90px), transparent 100%);
}
/* bout de course : le rail est collé à droite, plus rien à annoncer */
.latest.is-live.is-at-end .latest__viewport {
  -webkit-mask-image: none; mask-image: none;
}
.latest.is-live .latest__rail {
  will-change: transform;
  transform: translate3d(calc(var(--rail-shift) + var(--rail-drag)), 0, 0);
  transition: transform var(--rail-dur) var(--ease-out);
}
.latest.is-live .latest__rail.is-dragging { transition: none; user-select: none; cursor: grabbing; }
.latest.is-live .latest__rail.is-dragging * { cursor: grabbing; }

.work-card {
  position: relative; flex: 0 0 auto;
  /* Figma 1440 : carte de devant 320×453, carte réduite 250 (même hauteur).
     La hauteur (`--card-h`, posée sur `.latest`) est bornée à la MOITIÉ de
     l'écran — exactement la proportion du Figma (453 sur 900) — pour que le
     rail, son bandeau de contrôle et sa légende tiennent dans l'écran de la
     section sur un écran bas (13" 1280×720). Quand cette borne mord, la
     LARGEUR suit la hauteur : une affiche reste une affiche, elle ne
     s'aplatit pas en carré. À la taille de référence rien ne bouge (450 ≈ 453,
     318 ≈ 320). */
  width: min(clamp(170px, 22.222vw, 320px), calc(var(--card-h) * 320 / 453));
  height: var(--card-h);
  border-radius: var(--r-display); overflow: hidden; background: var(--c-surface);
  transition:
    width var(--rail-dur) var(--ease-out),
    filter var(--dur) var(--ease-out),
    opacity var(--dur) var(--ease-out);
}
.work-card[data-size="small"] { width: min(clamp(135px, 17.361vw, 250px), calc(var(--card-h) * 250 / 453)); opacity: 0.65; }
.latest.is-live .work-card[data-size="small"] { filter: brightness(0.5) saturate(0.75); opacity: 0.85; }
.latest.is-live .work-card[data-size="small"]:hover { filter: brightness(0.72) saturate(0.9); }
.work-card:focus-visible { outline: 2px solid var(--c-text); outline-offset: 3px; }
.work-card img {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  transform: scale(1.05); transition: transform 1.1s var(--ease-out);
  -webkit-user-drag: none; user-select: none;
}
.work-card[data-size="large"] img { transform: scale(1); }
.work-card__label {
  position: absolute; left: clamp(16px, 2.778vw, 40px); bottom: clamp(16px, 2.778vw, 40px); z-index: 2;
  font-weight: var(--fw-label); font-size: var(--fs-md); color: var(--c-text); max-width: 60%; line-height: 1;
  text-shadow: 0 1px 12px rgb(var(--c-ink-rgb) / 0.5);
}

/* carte de fin : anneau de progression + flèche qui défile */
.work-card--end {
  background: linear-gradient(165deg, var(--c-surface) 0%, var(--c-bg) 100%);
  border: 1px dashed var(--c-line);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: clamp(14px, 1.806vw, 26px); padding-inline: clamp(14px, 1.806vw, 26px); text-align: center;
}
.latest__ring {
  position: relative; display: grid; place-items: center; border-radius: 50%;
  width: clamp(56px, 5vw, 72px); height: clamp(56px, 5vw, 72px);
  background: conic-gradient(var(--c-text) calc(var(--rail-end) * 360deg), var(--c-text-dim) 0);
  transition: background 140ms linear;
}
.latest__ring::before { content: ""; position: absolute; inset: 2px; border-radius: 50%; background: var(--c-surface); }
.latest__ring-window { position: relative; z-index: 1; width: 46px; height: 26px; overflow: hidden; display: grid; place-items: center; }
.latest__arrow { width: 26px; height: 26px; color: var(--c-text); }
.work-card--end[data-size="large"] .latest__arrow { animation: latest-nudge 1.9s var(--ease-out) infinite; }
@keyframes latest-nudge {
  0%   { transform: translateX(-170%); opacity: 0; }
  22%  { opacity: 1; }
  55%  { transform: translateX(0); opacity: 1; }
  78%  { opacity: 1; }
  100% { transform: translateX(170%); opacity: 0; }
}
.work-card__end-text { font-size: var(--fs-sm); line-height: 1.4; color: var(--c-text-mid); max-width: 22ch; }
.work-card__end-text b { display: block; margin-bottom: 6px; font-size: var(--fs-md); font-weight: var(--fw-label); color: var(--c-text); }

/* Figma 1440 : barres de 5 px, 20 px sous les cartes, 20 px entre elles.
   Les barres et la paire ‹ › partagent une même rangée de contrôle. */
.latest__controls {
  display: flex; align-items: center; gap: clamp(16px, 2.222vw, 32px);
  margin-top: clamp(1.25rem, 1.944vw, 28px);
}
.latest__progress { display: flex; gap: 20px; flex: 1 1 auto; min-width: 0; }
.latest__bar {
  /* le trait fait 5 px, la CIBLE en fait 24 : à la souris comme au doigt une
     barre de 5 px est intouchable. Le trait est peint par ::before. */
  position: relative; height: 24px; border: 0; padding: 0; background: none;
  cursor: pointer; flex: 1 1 0;
  transition: flex-grow var(--dur) var(--ease-out);
}
.latest__bar::before {
  content: ""; position: absolute; left: 0; right: 0; top: 50%; translate: 0 -50%;
  height: 5px; border-radius: var(--r-pill); background: var(--c-paper); opacity: 0.35;
  transition: opacity var(--dur) var(--ease-out);
}
/* la barre de fin fait la largeur de sa carte (100 px au Figma 1440) */
.latest__bar--end { flex-grow: 0; flex-basis: clamp(34px, 6.944vw, 100px); }
.latest__bar[data-active="true"] { flex-grow: 1.3; }
.latest__bar[data-active="true"]::before { opacity: 1; }
.latest__bar--end[data-active="true"] { flex-grow: 0.35; }
.latest__bar[data-seen="true"]::before { opacity: 0.6; }
.latest__bar:focus-visible { outline: 2px solid var(--c-text); outline-offset: 4px; border-radius: var(--r-control); }

/* Paire ‹ › — l'unique commande visible pour une souris à molette verticale.
   Sans JS le rail est un scroll natif : les boutons n'auraient rien à piloter. */
.latest__nav { display: none; gap: 10px; flex: 0 0 auto; }
.latest.is-live .latest__nav { display: flex; }
.latest__nav-btn {
  width: clamp(40px, 3.056vw, 44px); height: clamp(40px, 3.056vw, 44px);
  display: grid; place-items: center; cursor: pointer;
  border: 1px solid var(--c-line); border-radius: var(--r-pill);
  background: var(--c-surface); color: var(--c-text);
  transition: background var(--dur-fast) var(--ease-soft),
              border-color var(--dur-fast) var(--ease-soft),
              opacity var(--dur-fast) var(--ease-soft);
}
.latest__nav-btn svg { width: 20px; height: 20px; }
.latest__nav-btn[data-featured-prev] svg { transform: rotate(180deg); }
.latest__nav-btn:hover { background: var(--c-surface-soft); border-color: var(--c-border-mid); }
.latest__nav-btn:focus-visible { outline: 2px solid var(--c-text); outline-offset: 3px; }
.latest__nav-btn:disabled { opacity: 0.3; cursor: default; }
.latest__nav-btn:disabled:hover { background: var(--c-surface); border-color: var(--c-line); }

/* bascule du bloc détail au changement de projet */
.latest__fade { transition: opacity 0.42s var(--ease-out), transform 0.56s var(--ease-out); }
.latest__detail.is-out .latest__fade { opacity: 0; }
.latest__detail.is-out[data-dir="fwd"] .latest__fade { transform: translateY(16px); }
.latest__detail.is-out[data-dir="back"] .latest__fade { transform: translateY(-16px); }

/* Figma 1440 (74:672) : titre sur 465 px jusqu'au filet, texte sur 587 px,
   bouton isolé à droite et centré verticalement. Le bloc part de la gouttière
   (le retrait supplémentaire de 60 px de la base 1920 disparaît). */
.latest__detail {
  display: grid;
  grid-template-columns: minmax(0, 465px) 1px minmax(0, 587px) 1fr;
  /* 65 px entre les COLONNES (Figma) ; en rangée, sous 1280, le bouton repasse
     sous le texte et 65 px le détacheraient de la légende. */
  column-gap: clamp(1.5rem, 4.514vw, 65px);
  row-gap: clamp(1.5rem, 2.5vw, 32px);
  align-items: start;
  /* respiration franche entre le rail et sa légende : le bandeau de contrôle
     appartient encore au rail, la légende est le mouvement suivant. */
  padding: clamp(2.5rem, 4.028vw, 58px) var(--gutter) 0;
}
.latest__detail-title { max-width: 400px; font-size: var(--fs-h2); font-weight: 900; text-transform: uppercase; line-height: 0.87; }
/* le filet épouse la hauteur de la rangée : un plancher trop haut (100 px) le
   faisait pendre sous le texte qu'il sépare. */
.latest__detail-rule { align-self: stretch; width: 1px; background: var(--c-text); min-height: 72px; }
/* Le hook et la méta forment UN bloc : les 54 px du Figma ouvraient un vide de
   la hauteur du texte lui-même (un hook d'une ligne = 32 px). */
.latest__detail-body { display: flex; flex-direction: column; gap: clamp(0.875rem, 1.528vw, 22px); }
.latest__detail-desc { margin: 0; font-weight: var(--fw-body); font-size: var(--fs-lead); line-height: 1.33; }
.latest__detail-meta { margin: 0; font-size: var(--fs-md); letter-spacing: 0.069em; text-transform: uppercase; color: var(--c-text-80); }
.latest__detail-cta { grid-column: 4; grid-row: 1; justify-self: end; align-self: center; }
/* Sous la largeur du design, la 4ᵉ colonne étrangle le texte : le bouton
   repasse sous le bloc de droite, comme sur mobile. */
@media (max-width: 1280px) {
  .latest__detail { grid-template-columns: minmax(0, 1fr) 1px minmax(0, 1.45fr); padding-left: var(--gutter); }
  .latest__detail-cta { grid-column: 3; grid-row: 2; justify-self: start; align-self: start; }
}
@media (max-width: 768px) {
  .latest { --rail-gap: 10px; }
  .latest__detail { grid-template-columns: 1fr; gap: 1.5rem; padding-left: var(--gutter); }
  .latest__detail-rule { display: none; }
  .latest__detail-cta { grid-column: 1; grid-row: auto; justify-self: start; }
  .latest__progress { gap: 12px; }
  .work-card__end-text { font-size: var(--fs-xs); }
}
/* Écrans BAS (13 pouces 1280×720 et compagnie) : les dégagements de « Latest
   work » sont dessinés pour un écran de 900 px de haut et poussent le bloc
   légende hors de l'écran de la section. On les resserre — la section reste
   d'un écran, comme les autres. Rien ne bouge au-dessus de 800 px de haut. */
@media (max-height: 800px) {
  .latest .section__label { padding-block: var(--space-6) var(--space-5); }
  .latest__detail { padding-top: var(--space-6); }
  .latest { padding-bottom: var(--space-5); }
}
@media (prefers-reduced-motion: reduce) {
  .latest { --rail-dur: 1ms; }
  .latest__rail, .work-card, .work-card img, .latest__fade { transition-duration: 1ms !important; }
  .work-card--end[data-size="large"] .latest__arrow { animation: none; }
}

/* ── SERVICES — deck épinglé (Figma 1440 : 74:673) ───────────────────────────
   Base = liste verticale (sans JS, petit écran, mouvement réduit).
   motion.js pose `is-live` sur le conteneur épinglé et bascule en mode deck :
   au repos c'est exactement la composition du Figma — carte de devant
   900×500, les suivantes décalées vers le bas et mises à l'échelle
   (origine haut-centre). */
/* Toutes les métriques (tailles de texte, paddings, colonnes) sont relevées sur
   la carte de devant du Figma 1440 : carte 900×500, padding 60, titre Inter
   Black 38, tagline Tinos 28/40, texte Inter 16 sur 550 px dans une colonne de
   593. Le deck vaut 900 px de large au maximum, les `cqw` ci-dessous sont donc
   les pourcentages exacts de cette référence — la carte reste homothétique
   quelle que soit la taille réelle du deck. */
.services {
  background: var(--c-bg); padding-bottom: clamp(1.5rem, 4.167vw, 60px);
  /* Le Figma dessine la carte à 900 px dans une section de 1440×800 : elle
     occupe 62,5 % de la largeur ET 112,5 % de la hauteur utile. Sur une
     fenêtre plus haute que ce ratio, se caler sur les 62,5 % laisserait un
     grand vide autour de la carte pendant l'épinglage — on prend donc la plus
     grande des deux contraintes, toujours bornée aux 900 px du design. */
  --deck-w: clamp(300px, max(62.5vw, 112.5vh), 900px);
  /* course de scroll par carte : plus la valeur est haute, moins le deck est
     nerveux (la référence hildenkaira défile lentement). */
  --card-travel: 115vh;
}
.services__pin { position: relative; }
.services__viewport { padding-inline: var(--gutter); }
/* Le deck sert d'unité de mesure : toutes les métriques de carte sont
   exprimées en `cqw`, soit exactement les pourcentages relevés sur la carte
   de 900 px du Figma 1440 — quelle que soit la taille réelle du deck. */
.services__deck {
  max-width: 900px; margin-inline: auto; display: grid; gap: clamp(1.5rem, 2.083vw, 30px);
  container-type: inline-size;
}

.service-card {
  position: relative; min-height: 300px;
  display: flex; flex-direction: column; justify-content: space-between;
  border-radius: var(--r-display); box-shadow: var(--shadow-card);
  /* Le padding du Figma (60 px sur 900) se mesure depuis le bord EXTÉRIEUR de
     la carte : sur la carte bordée il faut donc défalquer l'épaisseur du trait. */
  --card-bd: 0px;
  --card-pad: max(1.25rem, 6.667cqw);
  padding: calc(var(--card-pad) - var(--card-bd)) calc(var(--card-pad) - var(--card-bd))
           calc(var(--card-pad) * 0.89 - var(--card-bd));
  transform-origin: top center;
  transition: transform 620ms var(--ease-out), opacity 620ms var(--ease-out);
}
.service-card--dark { --card-bd: clamp(3px, 0.347vw, 5px); background: var(--c-ink); border: var(--card-bd) solid var(--c-paper); color: var(--c-text); }
.service-card--yellow { background: var(--c-yellow); color: var(--c-ink); }
.service-card--red { background: var(--c-red); color: var(--c-text); }

.service-card__top, .service-card__bottom {
  /* colonne de texte : 593 px sur la carte de 900 px du Figma 1440, mesurée sur
     la carte entière — donc en cqw, pas en % de la boîte de contenu */
  position: relative; z-index: 2; max-width: 65.9cqw;
  display: flex; flex-direction: column; gap: max(0.5rem, 1.333cqw);
  transition: opacity 380ms var(--ease-out);
}
/* Tailles exprimées en cqw (et non en vw) pour rester homothétiques du deck
   quand celui-ci est contraint par la hauteur : les ratios ci-dessous valent
   exactement les tailles du Figma (38 / 28 / 16) sur une carte de 900 px. */
.service-card__title { font-size: clamp(1.4rem, 4.222cqw, 38px); font-weight: 900; text-transform: uppercase; line-height: 0.867; }
.service-card__tagline { margin: 0; font-family: var(--font-serif); font-weight: 400; font-size: clamp(1.05rem, 3.111cqw, 28px); line-height: 1.429; }
.service-card__desc { margin: 0; max-width: 61.1cqw; font-weight: var(--fw-body); font-size: clamp(0.9rem, 1.778cqw, 16px); line-height: 1.334; }
.service-card__bottom .btn { align-self: flex-start; }
.service-card__photo { position: relative; width: 70%; margin: clamp(1.5rem, 4vw, 2.5rem) auto 0; transform: rotate(3deg); transition: opacity 380ms var(--ease-out); }
.service-card__photo img { width: 100%; aspect-ratio: 3/4; object-fit: cover; border-radius: var(--r-display); box-shadow: var(--shadow-pop); }

/* ── mode deck ────────────────────────────────────────────────────────────── */
/* Une course par bascule, plus un palier : c'est lui qui laisse la DERNIÈRE
   carte posée avant que l'épinglage ne se relâche. `--card-hold` vient de
   motion.js (CARD_HOLD), qui s'en sert pour la même découpe — une seule valeur
   fait foi. Le repli à 0 vaut pour l'instant qui précède le JS. */
.services__pin.is-live {
  height: calc(100vh + (var(--n) - 1 + var(--card-hold, 0)) * var(--card-travel));
}
.services__pin.is-live .services__viewport {
  position: sticky; top: 0; height: 100vh; display: grid; place-items: center;
  overflow: hidden;   /* les cartes qui s'échappent ne débordent pas sur la section du dessus */
}
/* ratio de la carte de référence : 900×500 */
.services__pin.is-live .services__deck {
  position: relative; display: block; width: var(--deck-w);
  height: calc(var(--deck-w) * 0.5556); min-height: 240px; margin: 0;
}
/* En mode deck les cartes sont réellement empilées les unes SUR les autres :
   c'est le seul cas où une carte a droit à --shadow-pop (IDENTITY §6). Au
   repos (liste, mobile, sans JS) elle garde --shadow-card, soit rien en
   sombre — le filet suffit. */
/* `--d` : profondeur de la carte, posée par motion.js — 0 pour celle de devant,
   et FRACTIONNAIRE : la pile suit donc le scroll en continu au lieu de basculer
   d'un cran. D'où l'absence de transition ici : elle traînerait derrière la main.
   Deux régimes tiennent dans la même expression, min()/max() faisant
   l'aiguillage : au-dessus de 0 la carte est encore dans la pile (+13 % et ×0,91
   par carte, relevés au Figma 1440) ; en dessous, elle s'échappe vers le haut
   hors du deck. */
.services__pin.is-live .service-card {
  position: absolute; inset: 0; min-height: 0; overflow: visible;
  box-shadow: var(--shadow-pop);
  transform:
    translateY(calc(max(var(--d, 0), 0) * 13% + min(var(--d, 0), 0) * 118%))
    scale(calc(1 - max(var(--d, 0), 0) * 0.09));
  /* Elle reste franche sur le premier cinquième de sa sortie — sinon on verrait
     la carte du dessous par transparence, à travers un aplat de couleur — puis
     s'efface avant d'atteindre le haut du cadre : jamais de carte coupée net
     sur le bord. */
  opacity: clamp(0, calc(1.3 + var(--d, 0) * 1.6), 1);
  z-index: calc(100 - var(--d, 0));
  transition: none;
  will-change: transform, opacity;
}
/* Derrière, seul le bandeau coloré dépasse (Figma) : le contenu ne se montre
   qu'à l'approche du devant. Le fondu est dissymétrique, et c'est voulu — le
   contenu qui arrive paraît tôt (dès --d ≈ 0,6), celui qui part s'efface vite
   (à --d ≈ -0,3). Symétrique, la bascule laisserait en son milieu une carte
   colorée vide, le temps que l'un s'en aille avant que l'autre ne vienne. */
.services__pin.is-live .service-card__top,
.services__pin.is-live .service-card__bottom,
.services__pin.is-live .service-card__photo {
  opacity: clamp(0, calc(1 - max(var(--d, 0), 0) * 1.6 - max(-1 * var(--d, 0), 0) * 3.2), 1);
  transition: none;
}
.services__pin.is-live .service-card:not([data-front]) .service-card__top,
.services__pin.is-live .service-card:not([data-front]) .service-card__bottom,
.services__pin.is-live .service-card:not([data-front]) .service-card__photo { pointer-events: none; }
.services__pin.is-live .service-card[data-past] { pointer-events: none; }
/* la photo déborde du cadre à droite, comme dans le Figma 1440 :
   320×420 posé à 625 / 36 sur une carte de 900×500. */
.services__pin.is-live .service-card__photo {
  position: absolute; left: 69.4%; top: 7.2%; z-index: 1;
  width: 35.6%; height: 84%; margin: 0; transform: rotate(5.62deg);
}
.services__pin.is-live .service-card__photo img { height: 100%; aspect-ratio: auto; }
/* Hors mode deck (mobile, sans JS) la carte redevient une liste : le texte
   reprend toute la largeur, sinon il resterait coincé sur 56 %. */
@media (max-width: 820px) {
  .service-card__top, .service-card__bottom { max-width: 100%; }
}

/* ── ABOUT ────────────────────────────────────────────────────────────────────
   Scène calée au pixel sur le Figma (1440×900) : titre au tiers haut, texte +
   boutons descendus au niveau des polaroïds, polaroïds sur les bords.
   Toutes les valeurs ci-dessous sont les coordonnées du design en % — le cadre
   1440×900 a exactement le même ratio 1,6 que l'ancienne base 1920×1200, les
   pourcentages restent donc valides tels quels. */
/* La scène occupe TOUT l'écran de la section, à fond perdu : plus de dégagement
   haut/bas (l'ancienne marge de 80 px laissait deux bandes de fond de page et
   la photo ne remplissait pas son écran). Le ratio 1440 × 900 du Figma n'est
   donc plus imposé au cadre — c'est l'écran qui le dessine, et toute la
   composition étant en %, elle suit. */
.about { position: relative; display: grid; grid-template-columns: minmax(0, 1fr); }
.about__stage {
  position: relative; z-index: 2; overflow: hidden;
  width: 100%; height: var(--section-h); min-height: 560px;
}
/* le fond déborde en haut/en bas pour laisser de la course à la parallaxe */
.about__bg { position: absolute; inset: -16% 0; z-index: 0; will-change: transform; }
.about__bg img { width: 100%; height: 100%; object-fit: cover; }
.about__stage::after {
  content: ""; position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(180deg, rgb(var(--c-ink-rgb) / .34) 0%, rgb(var(--c-ink-rgb) / .2) 45%, rgb(var(--c-ink-rgb) / .38) 100%);
}
/* Le cadre est APLATI dans le Figma 1440 (image unique, aucun calque) : pas de
   nouveau relevé possible. Les % ci-dessous viennent de la base 1920×1200 et
   restent exacts au pixel puisque le ratio est identique.
   titre : x 467/1920, y 444/1200, colonne 930/1920 */
/* le voile est désormais posé DANS le cadre (`.about__stage::after`, z-index 1) :
   titre, bloc de texte et polaroïds repassent explicitement au-dessus */
.about__title {
  position: absolute; z-index: 2; left: 24.32%; top: 37%; width: 48.44%;
  text-align: center; font-family: var(--font-serif); font-weight: 400;
  font-size: var(--fs-display); line-height: 0.834; letter-spacing: -0.0186em;
  color: var(--c-text);
}
/* texte + boutons : x 566/1920, colonne 777/1920, bas du bloc à 1137/1200.
   Ancré par le bas : un texte plus long que celui du Figma pousse vers le
   haut au lieu de déborder sous la scène. */
.about__block {
  position: absolute; z-index: 2; left: 29.48%; bottom: 5.25%; width: 40.47%;
  display: grid; gap: clamp(1rem, 3.125vw, 45px); justify-items: center;
}
/* même paragraphe d'intro que `.story-hero__text` — même pas typographique */
.about__desc { margin: 0; width: 100%; font-weight: var(--fw-body); font-size: var(--fs-body-lg); line-height: 1.6; }
.about__cta { display: flex; gap: 15px; flex-wrap: wrap; justify-content: center; }

/* pas d'ombre : dans la section « And this, is only the beginning » les photos
   flottantes se détachent par le cadre, la rotation et le flottement (décision
   de refonte, GUIDE §6) */
.polaroid {
  position: absolute; z-index: 2; border: 5px solid var(--c-paper);
  overflow: hidden; aspect-ratio: 3 / 4; pointer-events: none;
}
.polaroid img { width: 100%; height: 100%; object-fit: cover; }
/* polaroïds : centres relevés sur 12:2298 (gauche) et 12:2297 (droite) — même
   remarque que ci-dessus, les % valent aussi bien pour le cadre 1440×900.
   Deux ajustements depuis que le cadre est borné à l'écran :
   — ancrage par le BAS (les tops 55,25 % et 52,75 % du Figma deviennent 9,23 %
     et 13,9 %, exacts au pixel sur le cadre de référence), sinon un cadre plus
     court que le ratio les faisait sortir par le bas ;
   — taille prise sur la HAUTEUR du cadre (320 et 300 px sur les 900 du Figma)
     et non plus sur sa largeur : c'est la hauteur que le cadrage à l'écran
     comprime, c'est donc elle qui doit commander la taille des photos
     flottantes. La largeur suit toute seule (`aspect-ratio: 3 / 4`). */
.polaroid--left  { left: 6.61%;  bottom: 9.23%; height: 35.56%; transform: rotate(-10.74deg); }
.polaroid--right { left: 77.42%; bottom: 13.9%; height: 33.33%; transform: rotate(11.03deg); }

/* En dessous de la largeur du design, la scène absolue devient illisible :
   on repasse en flux vertical centré et on retire les polaroïds. */
@media (max-width: 900px) {
  .about__stage {
    height: auto; min-height: 0;
    display: grid; justify-items: center; gap: clamp(1.5rem, 5vw, 2.5rem);
    padding: clamp(3rem, 12vw, 6rem) var(--gutter);
  }
  .about__title, .about__block { position: static; left: auto; top: auto; width: 100%; max-width: 620px; }
  .about__desc { text-align: center; }
  .polaroid { display: none; }
}

/* ── SOCIAL ─────────────────────────────────────────────────────────────────── */
.social {
  background: var(--c-bg); padding-bottom: clamp(3rem, 6vw, 6rem);
  /* carte + stickers centrés dans l'écran de la section (`minmax(0, 1fr)` et
     `safe` : cf. `.latest`) */
  display: grid; grid-template-columns: minmax(0, 1fr);
  align-content: center; align-content: safe center;
}
.social__card {
  position: relative; margin: 0 var(--gutter); border-radius: var(--r-display); overflow: hidden;
  height: clamp(160px, 23.194vw, 334px); display: grid; place-content: center; background: var(--c-surface);
  isolation: isolate;
}
.social__card-bg {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  transform: scale(1.02); filter: brightness(0.78) saturate(0.9);
  transition: transform 1.4s var(--ease-out), filter 0.7s var(--ease-out);
}
/* roll-over : la photo respire et s'éclaire, le handle avance légèrement */
.social__card:hover .social__card-bg { transform: scale(1.09); filter: brightness(1) saturate(1.05); }
.social__card::after {
  content: ""; position: absolute; inset: 0; z-index: 1;
  background: radial-gradient(120% 80% at 50% 50%, rgb(var(--c-ink-rgb) / 0) 30%, rgb(var(--c-ink-rgb) / .55) 100%);
  opacity: 0.9; transition: opacity 0.7s var(--ease-out);
}
.social__card:hover::after { opacity: 0.55; }
.social__handle {
  /* Figma 1440 : Inter Black 175 sur un interligne de 180 */
  position: relative; z-index: 2; font-weight: 900; font-size: var(--fs-social); line-height: 1.0286;
  text-align: center; white-space: nowrap; color: var(--c-text);
  transition: transform 0.9s var(--ease-out), letter-spacing 0.9s var(--ease-out);
}
.social__card:hover .social__handle { transform: scale(1.035); letter-spacing: 0.01em; }
.social__card:focus-visible { outline: 2px solid var(--c-text); outline-offset: 4px; }
@media (prefers-reduced-motion: reduce) {
  .social__card-bg, .social__handle, .social__card::after { transition-duration: 1ms; }
  .social__card:hover .social__card-bg, .social__card:hover .social__handle { transform: none; }
}
/* ── Stickers réseaux (maquette « V4 » validée) ──────────────────────────────
   Chips aux aplats de marque (IDENTITY §3 : aplats, pas du texte d'interface),
   inclinées comme des autocollants. Au repos elles se BALANCENT doucement —
   le balancement passe par la propriété `rotate`, qui se compose avec le
   `transform` (inclinaison de base, redressement au survol) sans le
   combattre. Durées/délais désynchronisés pour éviter l'effet métronome. */
.social__links {
  display: flex; gap: clamp(1rem, 1.806vw, 26px); justify-content: center; flex-wrap: wrap;
  margin: clamp(2rem, 3.611vw, 52px) var(--gutter) 0;
}
.sticker {
  --tilt: 0deg;
  display: inline-block; padding: 16px 34px; border-radius: var(--r-pill);
  font-weight: var(--fw-label); font-size: 17px; line-height: 1; white-space: nowrap;
  transform: rotate(var(--tilt));
  transition: transform 0.35s var(--ease-out);
  animation: sticker-sway 4.6s ease-in-out infinite;
}
/* couleurs et inclinaisons en cycle de 3 : la rangée vient de D1, le motif
   tient quel que soit le nombre de réseaux */
.sticker:nth-child(3n + 1) { --tilt: -6deg;   background: var(--c-yellow); color: var(--c-ink); }
.sticker:nth-child(3n + 2) { --tilt: 3deg;    background: var(--c-red);    color: var(--c-paper); animation-duration: 5.4s; animation-delay: -1.7s; }
.sticker:nth-child(3n)     { --tilt: -2.5deg; background: var(--c-blue);   color: var(--c-paper); animation-duration: 6.1s; animation-delay: -3.2s; }
.sticker:hover { transform: rotate(0deg) scale(1.06); }
.sticker:focus-visible { outline: 2px solid var(--c-text); outline-offset: 3px; }
@keyframes sticker-sway {
  0%, 100% { rotate: -1.4deg; }
  50%      { rotate: 1.4deg; }
}
@media (prefers-reduced-motion: reduce) {
  .sticker { animation: none; transition: none; }
  .sticker:hover { transform: rotate(var(--tilt)); }
}

/* ── FOOTER — copie du footer global du site kjc actuel ─────────────────────
   Source : wearekjc-worker.js (SITE_FOOTER_HTML / SITE_FOOTER_CSS), porté tel
   quel avec deux adaptations : les couleurs en dur remappées sur les tokens
   (--ink → --c-ink, --paper → --c-paper) et le sélecteur `footer` nu scopé en
   `.footer-grid`. Bande clap sombre, puis bloc PAPIER : colonnes de liens et
   wordmark géant « WE ARE KJC » rogné volontairement par l'overflow du wrap. */
.site-footer { background: var(--c-footer); }
.footer-wrap a { color: inherit; text-decoration: none; }
.footer-wrap {
  background-color: var(--c-paper);
  border-top: 1px solid rgb(var(--c-ink-rgb) / 0.16);
  color: var(--c-ink);
  overflow: hidden;
}
/* Colonnes réparties sur TOUTE la largeur (gouttière du site) : la première
   s'aligne à gauche, la dernière finit contre la gouttière droite —
   space-between absorbe un nombre de colonnes variable (elles viennent de
   D1). Le max-width 1200 centré du footer kjc d'origine tassait tout à
   gauche de la page. */
.footer-grid {
  padding: 3.5rem var(--gutter) 2rem;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 2.5rem 1.5rem;
  align-items: start;
}
@media (min-width: 860px) {
  .footer-grid {
    display: flex;
    justify-content: space-between;
    padding: 4rem var(--gutter) 2.5rem;
  }
}
.footer-col-t {
  display: block;
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-label);
  letter-spacing: var(--eyebrow-tracking);
  text-transform: uppercase;
  color: var(--c-ink);
  margin-bottom: 1.1rem;
}
.footer-links {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}
.footer-links a {
  font-size: var(--fs-sm);
  color: rgb(var(--c-ink-rgb) / 0.45);
  transition: color 0.2s ease;
}
.footer-links a:hover { color: var(--c-ink); }
/* la flèche ↗ des liens externes est définie avec celle des boutons (.btn--ext),
   voir le bloc « Bouton pilule » plus haut */

/* le wordmark : une seule ligne, calée sur le viewport, rognée exprès par le
   wrap. Le 8.37 est le ratio mesuré de « WE ARE KJC » en Replique Sans à ce
   tracking — changer le texte ou la police impose de le recalculer. */
.footer-mark {
  font-family: var(--font-brand);
  font-weight: 900;
  font-size: min(calc((100vw - 4rem) / 8.37), 15rem);
  line-height: 0.86;
  letter-spacing: -0.02em;
  text-align: center;
  white-space: nowrap;
  color: rgb(var(--c-ink-rgb) / 0.16);
  padding: 1.4rem 0 1.8rem;
  user-select: none;
}
@media (min-width: 860px) { .footer-mark { padding: 2rem 0 2.2rem; } }

/* ── FICHE PROJET (/:slug) ───────────────────────────────────────────────────
   Port des styles « film detail » de l'ancien site (Références §.film-detail),
   remappés sur les tokens KJC. Deux variantes : film seul et campagne. */
.fd { background: var(--c-bg); }

/* Bande héro */
.fd-hero { position: relative; width: 100%; height: min(72vh, 620px); min-height: 360px; overflow: hidden; }
.fd-hero-media { position: absolute; inset: 0; }
.fd-hero-media img { width: 100%; height: 100%; object-fit: cover; transform: scale(1.04); }
.fd-hero-media::after {
  content: ""; position: absolute; inset: 0;
  background:
    linear-gradient(to top, rgb(var(--c-ink-rgb) / .98) 0%, rgb(var(--c-ink-rgb) / .55) 38%, rgb(var(--c-ink-rgb) / .18) 65%, rgb(var(--c-ink-rgb) / .45) 100%),
    linear-gradient(to right, rgb(var(--c-ink-rgb) / .55) 0%, rgb(var(--c-ink-rgb) / 0) 55%);
}
.fd-hero-content {
  position: relative; z-index: 2; height: 100%;
  display: flex; flex-direction: column; justify-content: flex-end;
  padding: clamp(5rem, 12vw, 8rem) var(--gutter-fluid) clamp(2rem, 3.5vw, 3.5rem);
  max-width: var(--container); margin-inline: auto;
}
.fd-back { margin-bottom: auto; align-self: flex-start; font-size: var(--fs-md); font-weight: var(--fw-label); letter-spacing: 0.08em; text-transform: uppercase; color: var(--c-text-mid); }
.fd-back:hover { color: var(--c-text); }
.fd-tags { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 1.1rem; }
.fd-tag {
  font-size: var(--fs-eyebrow); font-weight: 700; letter-spacing: 0.16em; text-transform: uppercase; color: var(--c-text);
  border: 1px solid var(--c-line-glass); background: rgb(var(--c-ink-rgb) / .4);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
  padding: 0.4rem 0.85rem; border-radius: var(--r-pill);
}
/* Pas de Figma pour la fiche projet : on applique la même règle (plafond =
   valeur 1440, X vw = plafond / 14,4) pour que la page reste dans l'échelle du
   reste du site — le titre s'assied entre --fs-display (85) et --fs-h2 (38). */
.fd-title { font-size: clamp(2rem, 3.333vw, 48px); font-weight: 900; line-height: 0.9; letter-spacing: -0.02em; text-transform: uppercase; max-width: 14ch; }
.fd-meta-row { display: flex; flex-wrap: wrap; gap: 0.5rem 1.1rem; margin-top: 1.25rem; font-size: var(--fs-sm); letter-spacing: 0.05em; text-transform: uppercase; color: var(--c-text-mid); }
.fd-meta-row span { white-space: nowrap; }
.fd-meta-row span:not(:last-child)::after { content: "·"; margin-left: 1.1rem; color: var(--c-text-dim); }

/* Corps */
.fd-body { position: relative; max-width: 880px; margin-inline: auto; padding: clamp(2.5rem, 5vw, 4.5rem) var(--gutter-fluid) clamp(4rem, 8vw, 7rem); }
.fd-hook { font-size: clamp(1.2rem, 2.222vw, 32px); font-weight: 800; line-height: 1.18; letter-spacing: -0.02em; color: var(--c-text); margin: 0 0 2.5rem; max-width: 18ch; }
.fd-hero-content .fd-hook { margin: 0.75rem 0 0; font-size: var(--fs-lead); max-width: 32ch; }
.fd-synopsis p { font-size: var(--fs-md); line-height: 1.85; color: var(--c-text-mid); margin: 0 0 1.1rem; }
.fd-synopsis p:last-child { margin-bottom: 0; }
.fd-note { margin: 1.5rem 0 0; font-size: var(--fs-sm); font-style: italic; color: var(--c-text-dim); }

/* Bloc « Regarder » : la cover mène, l'iframe n'arrive qu'au clic */
.fd-watch-wrap { margin: 0 0 clamp(3rem, 5vw, 3.5rem); }
.fd-watch { position: relative; width: 100%; aspect-ratio: 16/9; background: var(--c-ink); border-radius: var(--r-control); overflow: hidden; border: 1px solid var(--c-line); }
.fd-watch-cover { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; filter: brightness(0.62); transition: filter 0.4s var(--ease-out); }
.fd-watch:hover .fd-watch-cover { filter: brightness(0.5); }
.fd-watch::after { content: ""; position: absolute; inset: 0; background: linear-gradient(to top, rgb(var(--c-ink-rgb) / .55) 0%, rgb(var(--c-ink-rgb) / 0) 45%); pointer-events: none; }
.fd-watch-play { position: absolute; inset: 0; z-index: 2; display: flex; align-items: center; justify-content: center; border: 0; background: none; cursor: pointer; }
.fd-watch-play-btn {
  display: inline-flex; align-items: center; gap: 0.65rem;
  background: var(--c-paper); color: var(--c-ink);
  padding: 0.95rem 2.1rem 0.95rem 1.6rem; border-radius: var(--r-pill);
  box-shadow: var(--shadow-pop);
  transition: transform 0.25s var(--ease-out);
}
.fd-watch-play:hover .fd-watch-play-btn { transform: scale(1.05); }
.fd-watch-play-btn svg { width: 18px; height: 18px; fill: currentColor; }
.fd-watch-play-label { text-transform: uppercase; letter-spacing: 0.06em; font-size: var(--fs-xs); font-weight: 700; }
.fd-watch iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; z-index: 3; }
.fd-watch.is-playing .fd-watch-cover, .fd-watch.is-playing .fd-watch-play, .fd-watch.is-playing::after { display: none; }

/* Fiche technique */
.fd-info-grid {
  display: grid; grid-template-columns: repeat(2, 1fr); gap: 1.6rem 1.5rem;
  margin: clamp(2rem, 4vw, 3rem) 0; padding: 2rem 0;
  border-top: 1px solid var(--c-line); border-bottom: 1px solid var(--c-line);
}
@media (min-width: 640px) { .fd-info-grid { grid-template-columns: repeat(3, 1fr); } }
.fd-info-label { font-size: var(--fs-eyebrow); font-weight: 700; letter-spacing: 0.18em; text-transform: uppercase; color: var(--c-text-dim); margin-bottom: 0.4rem; }
.fd-info-value { font-size: var(--fs-sm); line-height: 1.5; font-weight: var(--fw-body); color: var(--c-text); }

/* Sections dépliables — ouvertes par défaut, repliées dès que le JS prend la main */
.fd-section { border-top: 1px solid var(--c-line); }
.fd-section:last-child { border-bottom: 1px solid var(--c-line); }
.fd-section-trigger { width: 100%; display: flex; align-items: center; gap: 1.1rem; padding: 1.35rem 0; background: none; border: 0; text-align: left; color: inherit; -webkit-tap-highlight-color: transparent; }
.fd:not(.is-live) .fd-section-trigger { cursor: default; }
.fd-section-label { font-size: var(--fs-xs); font-weight: 700; letter-spacing: 0.16em; text-transform: uppercase; color: var(--c-text); flex-shrink: 0; }
.fd-section-line { flex: 1; height: 1px; background: var(--c-line); transition: background 0.3s var(--ease-out); }
.fd-section-trigger:hover .fd-section-line { background: var(--c-border-mid); }
.fd-section-icon { flex-shrink: 0; color: var(--c-text-mid); font-weight: var(--fw-body); font-size: 19px; line-height: 1; transition: transform 0.45s var(--ease-out), color 0.3s var(--ease-out); }
.fd-section-trigger:hover .fd-section-icon { color: var(--c-text); }
.fd-section.is-open .fd-section-icon { transform: rotate(45deg); }
.fd:not(.is-live) .fd-section-icon { display: none; }
.fd-section-content { display: grid; grid-template-rows: 1fr; }
.fd.is-live .fd-section-content { grid-template-rows: 0fr; transition: grid-template-rows 0.6s var(--ease-out); }
.fd.is-live .fd-section.is-open .fd-section-content { grid-template-rows: 1fr; }
.fd-section-content-wrap { overflow: hidden; min-height: 0; }
.fd-section-inner { padding: 0.4rem 0 2rem; }

.fd-essay p { font-size: var(--fs-sm); line-height: 1.85; color: var(--c-text-mid); margin: 0 0 1.1rem; }
.fd-essay p:last-child { margin-bottom: 0; }
.fd-essay h4 { font-size: var(--fs-eyebrow); font-weight: 700; letter-spacing: 0.16em; text-transform: uppercase; color: var(--c-text-dim); margin: 1.6rem 0 0.7rem; }
.fd-essay h4:first-child { margin-top: 0; }

.fd-people-grid { display: grid; grid-template-columns: 1fr; gap: 0.9rem 1.5rem; }
@media (min-width: 640px) { .fd-people-grid { grid-template-columns: 1fr 1fr; } }
.fd-person-role { font-size: var(--fs-eyebrow); font-weight: 700; letter-spacing: 0.14em; text-transform: uppercase; color: var(--c-text-dim); }
.fd-person-name { font-size: var(--fs-sm); color: var(--c-text); margin-top: 0.2rem; }
.fd-thanks-list { font-size: var(--fs-sm); line-height: 2.1; color: var(--c-text-mid); }
.fd-thanks-list span:not(:last-child)::after { content: " · "; color: var(--c-text-dim); }

/* ── Campagne : carousel de pièces ─────────────────────────────────────────── */
.fd--campaign .fd-body { max-width: none; padding-left: 0; padding-right: 0; }
.fd--campaign .fd-body-inner { max-width: 880px; margin-inline: auto; padding-inline: var(--gutter-fluid); }
.cp-carousel { margin-bottom: clamp(2.5rem, 5vw, 4rem); }
.cp-stage-wrap-outer { position: relative; overflow: hidden; transition: height 0.6s var(--ease-out); }
.cp-stage-wrap { position: relative; padding-top: 1.5rem; transition: opacity 0.35s var(--ease-out), transform 0.4s var(--ease-out); }
.cp-carousel.is-explaining .cp-stage-wrap { opacity: 0; transform: translateY(-16px); pointer-events: none; }
/* Borné et centré : c'est la gouttière FLUIDE qui s'applique — la figée
   cumulerait un second centrage et étranglerait le rail au-delà de 1440. */
.cp-track { position: relative; display: flex; align-items: center; justify-content: space-between; gap: clamp(0.5rem, 2.5vw, 2.25rem); width: 100%; max-width: var(--container); padding-inline: var(--gutter-fluid); margin-inline: auto; }

.cp-peek {
  flex: 0 0 auto; width: clamp(48px, 11.806vw, 170px); aspect-ratio: 16/9;
  border-radius: var(--r-card); overflow: hidden; padding: 0; border: 0; background: var(--c-surface);
  opacity: 0.4; filter: saturate(0.6);
  transition: opacity 0.35s var(--ease-out), filter 0.35s var(--ease-out), transform 0.35s var(--ease-out);
}
.cp-peek:hover { opacity: 0.75; filter: saturate(0.85); transform: scale(1.02); }
.cp-peek.cp-peek-empty { visibility: hidden; pointer-events: none; }
.cp-peek img { width: 100%; height: 100%; object-fit: cover; }

.cp-stage { position: relative; flex: 1 1 auto; min-width: 0; border-radius: var(--r-display); overflow: hidden; background: var(--c-surface); border: 1px solid var(--c-line); }
.cp-slide { display: none; }
.cp-slide[data-active="true"] { display: block; }
.cp-stage-media { position: relative; width: 100%; aspect-ratio: 16/9; background: var(--c-ink); }
.cp-stage-media > img, .cp-stage-frame, .cp-stage-frame iframe { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; border: 0; }
/* vide tant que la vidéo n'est pas montée : la cover reste visible dessous */
.cp-stage-frame:empty { display: none; }
.cp-stage-info { padding: clamp(1.5rem, 2.4vw, 1.85rem) clamp(1.5rem, 2.8vw, 2.25rem) clamp(1.75rem, 3vw, 2.25rem); }
.cp-stage-title { font-size: var(--fs-lead); font-weight: 800; letter-spacing: -0.01em; color: var(--c-text); }
.cp-stage-subtitle { margin: 0.5rem 0 0; font-size: var(--fs-sm); line-height: 1.75; color: var(--c-text-mid); max-width: 56ch; }

.cp-mute-btn, .cp-expand-btn {
  position: absolute; bottom: 1rem; right: 1rem; z-index: 5;
  width: 38px; height: 38px; display: flex; align-items: center; justify-content: center;
  background: rgb(var(--c-ink-rgb) / .55); -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
  border: 1px solid var(--c-line-glass); border-radius: 50%; color: var(--c-text);
  transition: border-color 0.2s var(--ease-out), background 0.2s var(--ease-out), transform 0.2s var(--ease-out);
}
.cp-mute-btn:hover, .cp-expand-btn:hover { border-color: var(--c-text); background: rgb(var(--c-ink-rgb) / .8); transform: scale(1.06); }
.cp-mute-btn svg, .cp-expand-btn svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 1.6; }
.cp-mute-btn .cp-icon-muted { display: none; }
.cp-mute-btn.is-muted .cp-icon-unmuted { display: none; }
.cp-mute-btn.is-muted .cp-icon-muted { display: block; }
.fd:not(.is-live) .cp-mute-btn { display: none; }

.cp-chevron-row { display: flex; justify-content: center; margin: 1.5rem 0; }
.cp-chevron-btn { width: 46px; height: 46px; display: flex; align-items: center; justify-content: center; background: transparent; border: 1px solid var(--c-line); border-radius: 50%; color: var(--c-text-mid); transition: border-color 0.25s var(--ease-out), color 0.25s var(--ease-out), background 0.25s var(--ease-out); }
.cp-chevron-btn:hover { border-color: var(--c-text); color: var(--c-text); }
.cp-chevron-btn svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 1.6; transition: transform 0.4s var(--ease-out); }
.cp-carousel.is-explaining .cp-chevron-btn { background: var(--c-paper); border-color: var(--c-paper); color: var(--c-ink); }
.cp-carousel.is-explaining .cp-chevron-btn svg { transform: rotate(180deg); }
.fd:not(.is-live) .cp-chevron-row { display: none; }

.cp-explain { position: absolute; inset: 0; overflow-y: auto; opacity: 0; transform: translateY(16px); pointer-events: none; transition: opacity 0.4s 0.12s var(--ease-out), transform 0.45s 0.12s var(--ease-out); }
.cp-carousel.is-explaining .cp-explain { opacity: 1; transform: translateY(0); pointer-events: auto; }
.cp-explain-inner { max-width: 720px; margin-inline: auto; padding: 1.5rem var(--gutter-fluid) 3rem; display: none; }
.cp-explain-inner[data-active="true"] { display: block; }
.cp-explain-eyebrow { font-size: var(--fs-eyebrow); font-weight: 700; letter-spacing: 0.16em; text-transform: uppercase; color: var(--c-text-dim); margin-bottom: 0.5rem; }
.cp-explain-title { font-size: clamp(1.1rem, 1.8vw, 1.4rem); font-weight: 800; letter-spacing: -0.01em; color: var(--c-text); margin-bottom: 1.5rem; }
/* sans JS le panneau processus est simplement empilé sous le carousel */
.fd:not(.is-live) .cp-explain { position: static; opacity: 1; transform: none; pointer-events: auto; }
.fd:not(.is-live) .cp-explain-inner { display: block; }

.cp-fullscreen { position: fixed; inset: 0; z-index: 1300; background: rgb(var(--c-ink-rgb) / .97); display: flex; align-items: center; justify-content: center; padding: 2.5rem; }
.cp-fullscreen[hidden] { display: none; }
.cp-fullscreen img { max-width: 100%; max-height: 100%; object-fit: contain; border-radius: var(--r-control); }
.cp-fullscreen-close { position: fixed; top: 1.5rem; right: 1.5rem; z-index: 20; width: 42px; height: 42px; display: flex; align-items: center; justify-content: center; background: rgb(var(--c-ink-rgb) / .55); border: 1px solid var(--c-line-glass); border-radius: 50%; color: var(--c-text); transition: border-color 0.2s var(--ease-out), transform 0.3s var(--ease-out); }
.cp-fullscreen-close:hover { border-color: var(--c-text); transform: rotate(90deg); }

/* ── Invitation de fin de fiche ──────────────────────────────────────────── */
.fd-more { border-top: 1px solid var(--c-line); background: var(--c-surface); }
.fd-more-inner {
  max-width: 880px; margin-inline: auto;
  padding: clamp(3rem, 6vw, 6rem) var(--gutter-fluid);
  display: grid; gap: clamp(0.75rem, 1.4vw, 1.25rem); justify-items: start;
}
.fd-more-title { font-size: clamp(1.5rem, 2.222vw, 32px); font-weight: 900; text-transform: uppercase; line-height: 0.95; letter-spacing: -0.02em; }
.fd-more-text { margin: 0; font-size: var(--fs-sm); line-height: 1.7; color: var(--c-text-mid); max-width: 46ch; }
/* le CTA de fin de fiche est le bouton pilule standard (.btn), avec juste un
   peu d'air au-dessus */
.fd-more-inner .btn { margin-top: clamp(0.5rem, 1.2vw, 1rem); }

@media (prefers-reduced-motion: reduce) {
  .fd-section-content, .cp-stage-wrap-outer, .cp-stage-wrap, .cp-explain { transition-duration: 1ms !important; }
}

/* ── PAGE ABOUT — « notre histoire » (Figma 1440 : 74:436) ───────────────────
   Layout et motion portés de `Références/hildenkaira.fi:our-story`. L'effet
   « photos qui suivent le curseur » de la référence (.trail-item[data-trail])
   n'est PAS repris. Valeurs calées sur le design 1440px. */
.story { background: var(--c-bg); overflow-x: clip; }

/* Révélation générique au scroll (motion.js pose .is-in) */
.story [data-reveal] {
  opacity: 0; transform: translateY(28px);
  transition: opacity 0.8s var(--ease-out), transform 0.9s var(--ease-out);
}
.story [data-reveal].is-in { opacity: 1; transform: none; }
.story:not(.is-live) [data-reveal] { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  .story [data-reveal] { opacity: 1 !important; transform: none !important; transition: none; }
}

/* ── Hero : titre serif au centre, 3 photos dispersées ───────────────────── */
/* Figma 74:1005 : une scène de 1440×900 dans laquelle les 3 photos sont posées
   en %. La colonne (titre → texte → bouton) est calée sur le BAS de la scène,
   pas centrée. Les photos démarrant à 21,7 % (≈195 px), elles passent sous le
   bandeau de header (145 px) sans le percuter. */
.story-hero {
  position: relative; min-height: min(62.5vw, 900px);
  display: grid; place-items: center; align-content: end;
  padding: var(--header-h) var(--gutter) clamp(1.5rem, 4.167vw, 60px);
}
.story-hero__bg { position: absolute; inset: 0; z-index: 0; pointer-events: none; }
.story-hero__photo { position: absolute; margin: 0; will-change: transform; }
.story-hero__photo img, .story-hero__photo video { width: 100%; height: 100%; object-fit: cover; }
/* positions relevées au Figma 1440 : centre 348×252 @(532,5 ; 195),
   gauche 249×330 @(62,5 ; 355,7), droite 249×330 @(1138,6 ; 338) —
   les rotations sont portées par data-rotate côté motion.js. */
.story-hero__photo--left   { left: 4.34%;  top: 39.5%; width: 17.3%; aspect-ratio: 249 / 330; transform: rotate(-10deg); }
.story-hero__photo--centre { left: 36.98%; top: 21.7%; width: 24.2%; aspect-ratio: 348 / 252; transform: rotate(2deg); }
.story-hero__photo--right  { left: 79.07%; top: 37.6%; width: 17.3%; aspect-ratio: 249 / 330; transform: rotate(10deg); }
@media (max-width: 900px) {
  .story-hero__photo--centre { display: none; }
  .story-hero__photo--left  { left: -6%; top: 4%; width: 46vw; }
  .story-hero__photo--right { left: 62%; top: 52%; width: 46vw; }
  .story-hero__bg { opacity: 0.4; }
}

.story-hero__inner {
  position: relative; z-index: 2; max-width: 767px; text-align: center;
  display: grid; justify-items: center; gap: clamp(1rem, 2.083vw, 30px);
}
/* Tinos 85/70, tracking -2.234px, colonne de 767px @1440 — c'est ce gabarit
   qui provoque le retour à la ligne du Figma, il doit donc être porté par le
   titre lui-même (les éléments d'une grille `justify-items:center` prennent
   sinon leur largeur max-content et débordent du conteneur). */
.story-hero__title {
  max-width: min(100%, 767px);
  font-family: var(--font-serif); font-weight: 400; font-size: var(--fs-display);
  line-height: 0.824; letter-spacing: -0.0263em; color: var(--c-text);
}
/* Le Figma pose 24/1,334 dans une colonne de 650 — un corps d'ACCROCHE pour un
   paragraphe de quatre lignes : il occupe la page sans être plus lisible.
   Corps courant mis en avant (20) et interligne de lecture (IDENTITY §5 impose
   1,6–1,85 pour le texte courant) : moins haut ET plus lisible. */
.story-hero__text {
  margin: 0; max-width: 650px; text-align: left;
  font-weight: var(--fw-body); font-size: var(--fs-body-lg); line-height: 1.6;
}
/* seul bouton du Figma à 20 px (partout ailleurs les libellés sont à 15) */
.story-hero__cta .btn { font-size: 20px; }
@media (max-width: 620px) { .story-hero__text { text-align: center; } }

/* ── Intro : phrase d'ouverture + révélation « iris » des fondateurs ────────
   Deux cercles découpés (clip-path) dans DEUX COPIES de la même photo — la
   scène entière du désert (founder-1.jpg). Au repos les cercles cadrent les
   deux visages, noms dessous, comme les iris de fin d'un film ; au scroll la
   scène est épinglée et les cercles grandissent jusqu'à révéler la photo
   complète, qui remonte derrière le titre. motion.js pose --p (0 → 1) sur
   .founders-stage ; sans JS ou en mouvement réduit, --p reste à 1 (photo
   complète, statique). */
.story-intro {
  position: relative; z-index: 2;
  /* Figma 74:946 : 100 px entre le bas du hero et le titre d'intro. */
  padding: clamp(2rem, 6.944vw, 100px) var(--gutter) 0;
  scroll-margin-top: clamp(70px, 7vw, 130px);
}
/* Exposure 40/35, tracking -1.257px, colonne 740px */
.story-intro__title {
  position: relative; z-index: 2;
  max-width: 740px; text-align: center;
  font-family: var(--font-serif); font-weight: 400;
  font-size: var(--fs-serif-lg); line-height: 0.875; letter-spacing: -0.0314em;
  margin-bottom: clamp(1.5rem, 2.083vw, 30px);
}
.founders-stage {
  --p: 1;
  /* les bulles tiennent 18 % de la course avant de grandir ; les noms
     s'effacent sur le premier quart */
  --pg: clamp(0, calc((var(--p) - 0.18) / 0.82), 1);
  display: flex; flex-direction: column; align-items: center;
}
.founders-scene {
  position: relative; z-index: 1;
  width: min(88vw, 700px, 64vh); aspect-ratio: 1;
  /* la photo révélée remonte DERRIÈRE le titre (référence validée) — au stade
     « bulles », cette zone est vide, le chevauchement est invisible */
  margin-top: clamp(-80px, -5.5vw, -36px);
}
.founders-photo {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  /* centres = les deux visages dans la photo entière (repères mesurés).
     Plafond du rayon calibré sur la COUVERTURE RÉELLE : l'union des deux
     cercles couvre tout le cadre dès r ≈ 64 % (le coin le plus lointain est
     à 63,7 % du centre le plus proche) — on vise 67 % pour finir la
     révélation juste avant la fin de l'épinglage, sans temps mort. */
  --cx: 33%; --cy: 54.5%;
  clip-path: circle(calc(9% + var(--pg) * 58%) at var(--cx) var(--cy));
}
.founders-photo--jc { --cx: 68.5%; --cy: 46%; }
.founders-name {
  position: absolute; z-index: 2; margin: 0;
  width: 12em; max-width: 44vw; transform: translateX(-50%);
  text-align: center; font-family: var(--font-serif); font-weight: 400;
  font-size: var(--fs-lead); line-height: 0.931; letter-spacing: -0.0186em;
  opacity: calc(1 - clamp(0, calc(var(--p) * 4), 1));
}
.founders-name--k  { left: 33%;   top: calc(54.5% + 12%); }
.founders-name--jc { left: 68.5%; top: calc(46% + 12%); }
/* mode épinglé (motion.js) : la scène tient l'écran le temps de la course */
[data-founders].is-live .founders-pin { height: 220vh; }
[data-founders].is-live .founders-stage {
  --p: 0;
  position: sticky; top: 0; height: 100vh;
  justify-content: center;
}

/* ── Chapitres ────────────────────────────────────────────────────────────── */
.chapters { position: relative; }

/* Le cadrage des étapes est dans motion.js (initStoryDriver) et NON en
   scroll-snap CSS : le snap natif se cale sur l'arrêt le plus PROCHE — un petit
   geste repose donc là d'où l'on vient — et sa bascule ne se règle ni en durée
   ni en courbe. Le pilote, lui, vise l'arrêt suivant et y glisse en 900 ms. */
.chapter {
  position: relative; display: grid; justify-items: center;
  /* l'ancre de l'étape (/about#2018-2020) ne doit pas passer sous la nav */
  scroll-margin-top: clamp(70px, 7vw, 130px);
}
/* Bandeau rouge du Figma (rectangle 26:64) : il porte la section « Mission »,
   pas le pied de page. Le rouge ne démarre PAS au bord du chapitre : il prend
   au MILIEU du trait de liaison (marge haute + demi-hauteur du trait), pour
   que la moitié haute du trait reste sur le sombre et que le filigrane
   « 2026 » du chapitre précédent ne soit plus rogné net par le rouge. */
.chapter--accent {
  --red-start: calc(clamp(1.5rem, 4.167vw, 60px) + clamp(120px, 20.833vw, 300px) / 2);
  background: linear-gradient(to bottom, var(--c-bg) var(--red-start), var(--c-red) var(--red-start));
}
.chapter--accent .chapter__path-track { color: rgb(var(--c-paper-rgb) / 0.4); }

/* Trait de liaison (Figma « Vector 21…25 » : 300px @1440). Le motif pointillé
   et le remplissage progressif viennent de la référence (.chapter-path). */
/* Figma 1440 : 60 px de respiration de part et d'autre du trait. */
.chapter__path {
  position: relative; width: 2px; height: clamp(120px, 20.833vw, 300px);
  margin-block: clamp(1.5rem, 4.167vw, 60px);
  --path-fill: 0%;
}
.chapter__path-track, .chapter__path-fill {
  position: absolute; inset: 0;
  background-image: repeating-linear-gradient(
    to bottom, currentColor 0 8px, transparent 8px 16px
  );
  background-size: 100% 16px;
}
.chapter__path-track { color: var(--c-text-dim); }
.chapter__path-fill {
  color: var(--c-text); height: var(--path-fill); overflow: hidden;
  transition: height 120ms linear;
}
@media (prefers-reduced-motion: reduce) { .chapter__path-fill { display: none; } }

.chapter__content {
  --chapter-gap: clamp(1rem, 2.083vw, 30px);
  position: relative; z-index: 2; width: 100%;
  padding-inline: var(--gutter);
  display: grid; justify-items: center; gap: var(--chapter-gap);
  /* C'est CE bloc que le pilote cadre (`[data-stop]`), normalement centré dans
     la fenêtre. Le dégagement ne sert qu'au repli : un chapitre plus haut que
     l'écran ne peut pas être centré, il se cale en haut — et pas sous la nav. */
  scroll-margin-top: clamp(70px, 7vw, 130px);
}
/* polaroïd : 240×340 tourné de 3° au Figma 1440 (paysage 340×240 pour le
   chapitre large). Le Figma le fait chevaucher le bloc de texte de 15 px ; la
   photo étant opaque elle masquerait le titre, on ne reprend donc que le
   RAPPROCHEMENT (le gap est réduit de 15 px, pas inversé). */
.chapter__photo {
  margin: 0 0 -15px; width: clamp(150px, 16.667vw, 240px);
  aspect-ratio: 240 / 340; transform: rotate(3deg); overflow: hidden;
  box-shadow: var(--shadow-pop); background: var(--c-surface);
}
.chapter__photo--wide { width: clamp(200px, 23.611vw, 340px); aspect-ratio: 340 / 240; transform: rotate(-3deg); }
/* les vidéos de chapitre (*-about.mp4) sont toutes tournées en 4:3 paysage :
   le polaroïd adopte leur ratio, à la largeur du gabarit large */
.chapter__photo--video { width: clamp(200px, 23.611vw, 340px); aspect-ratio: 4 / 3; }
/* La révélation générique (.story [data-reveal]) porte son décalage par
   `transform` et le remet à `none` : plus spécifique que .chapter__photo, elle
   effaçait la rotation du Figma dès que le polaroïd apparaissait. On recompose
   donc les deux ici (le flottement, lui, passe par `translate` — pas de conflit). */
.story .chapter__photo[data-reveal] { transform: translateY(28px) rotate(3deg); }
.story .chapter__photo--wide[data-reveal] { transform: translateY(28px) rotate(-3deg); }
.story .chapter__photo[data-reveal].is-in { transform: rotate(3deg); }
.story .chapter__photo--wide[data-reveal].is-in { transform: rotate(-3deg); }
.chapter__photo img, .chapter__photo video { width: 100%; height: 100%; object-fit: cover; }
/* Tinos 40/35, tracking -1.117px, colonne 450px */
.chapter__title {
  max-width: 450px; text-align: center;
  font-family: var(--font-serif); font-weight: 400;
  font-size: var(--fs-serif-lg); line-height: 0.875; letter-spacing: -0.0279em;
}
/* Inter Regular 16, colonne étroite de 450px — Mission comprise */
.chapter__text { max-width: 450px; }
.chapter--accent .chapter__text { max-width: 450px; }
.chapter__text p { margin: 0 0 30px; font-weight: 400; font-size: var(--fs-md); line-height: 1.334; }
.chapter__text p:last-child { margin-bottom: 0; }

/* Année géante en filigrane, révélée par un masque — port de
   `.chapter-year_mask` / `.chapter-year_item` de la référence.
   Le mouvement est piloté par `--year-p` (0 → 1), calculé au scroll dans
   motion.js : il suit donc le doigt au lieu de se déclencher d'un bloc.
   Sens : l'année DESCEND depuis le haut du masque (translateY -100 % → 0). */
.chapter__year {
  --year-p: 1;
  /* largeur du texte en em — posée par la vue (About.tsx, yearWidthEm) ; le
     repli vaut la plus longue des années au cas où l'attribut manquerait */
  --year-w: 5.1;
  position: relative; z-index: 0; width: 100%;
  /* Figma 1440 : le haut des chiffres remonte de 120 px sur la fin du texte */
  margin-top: max(-120px, -8.333vw);
  font-family: var(--font-serif); font-weight: 400;
  /* Le corps du Figma (330 px) ne vaut que pour une année courte : « 2020  2023 »
     y mesure 5,08 em, soit 1676 px — l'année débordait donc de la page et se
     faisait rogner des deux côtés. On plafonne le corps à ce qui tient dans la
     colonne ; les années courtes (2026, 2030) gardent les 330 px du Figma. */
  font-size: min(var(--fs-year), calc((100vw - 2 * var(--gutter-fluid)) / var(--year-w)));
  line-height: 0.964;
  color: rgb(var(--c-paper-rgb) / 0.05); text-align: center; white-space: nowrap;
  user-select: none;
}
/* sur le bandeau rouge il faut un peu plus d'alpha pour rester lisible */
.chapter--accent .chapter__year { color: rgb(var(--c-paper-rgb) / 0.12); }
/* Le masque est taillé sur l'ENCRE des chiffres, pas sur la boîte de ligne (qui
   ajouterait ~167 px de vide sous chaque chapitre). Dans Exposure cette encre
   fait 0,775 em (0,723 de hauteur de capitale + 0,053 de jambage : les chiffres
   sont elzéviriens, le 3 et le 9 descendent) — le masque de 0,685 em rognait
   donc le haut ET le bas de chaque année. Hauteur et décalage ci-dessous
   l'enveloppent avec un cheveu de marge.
   Le bloc reste plus haut que le masque (interligne 0,964 em) : translateY(-100 %)
   continue de le cacher entièrement. */
.chapter__year-mask { display: block; overflow: hidden; height: 0.792em; }
.chapter__year-value {
  display: block; margin-top: -0.098em; letter-spacing: 0.02em; will-change: transform, opacity;
  transform:
    translateY(calc((var(--year-p) - 1) * 100%))
    scale(calc(0.985 + var(--year-p) * 0.015));
  opacity: calc(0.35 + var(--year-p) * 0.65);
  filter: blur(calc((1 - var(--year-p)) * 6px));
}
.story:not(.is-live) .chapter__year-value { transform: none; opacity: 1; filter: none; }
@media (prefers-reduced-motion: reduce) {
  .chapter__year-value { transform: none !important; opacity: 1 !important; filter: none !important; }
}

/* ── Clôture de l'About : le bandeau rouge se prolonge en CTA services ──────
   Même aplat que .chapter--accent : quand le dernier chapitre est la mission
   rouge, les deux blocs fusionnent en une seule bannière. */
/* Le bouton ne doit pas coller au filigrane « 2030 » qui le précède : le haut
   du bloc est nettement plus dégagé que le bas d'un chapitre courant, et la
   page se termine sur une vraie respiration plutôt qu'au ras du pied de page. */
.story-cta {
  background: var(--c-red);
  display: grid; place-items: center;
  padding: clamp(3rem, 8.333vw, 120px) var(--gutter) clamp(4.5rem, 11.111vw, 160px);
  /* Les deux blocs tombent sur une frontière fractionnaire (499,95 px) : la
     dernière rangée du dégradé du chapitre s'y anti-aliase et dessine un filet
     clair. On chevauche d'un pixel — rouge sur rouge, invisible — pour que le
     raccord soit franc. */
  margin-top: -1px;
}
/* même corps que le CTA du héro About (20 px) : les deux bornes du récit */
.story-cta .btn { font-size: 20px; }

/* ── Pages construction & légales ───────────────────────────────────────────── */
/* Ces deux pages n'ont pas de héro plein écran : le header étant en absolu,
   elles se dégagent elles-mêmes de sa hauteur (--header-h, 145 px @1440). */
.construction {
  min-height: 70svh; display: grid; place-content: center; text-align: center; gap: 1.5rem;
  padding: var(--header-h) var(--gutter-fluid) var(--space-6);
}
.construction h1 { font-size: var(--fs-h2); text-transform: uppercase; }
.legal { max-width: 720px; margin-inline: auto; padding: var(--header-h) var(--gutter-fluid) var(--space-6); }
.legal h1 { font-size: var(--fs-h2); margin-bottom: 1.5rem; text-transform: uppercase; }
.legal__updated { margin: -0.75rem 0 2.5rem; font-size: var(--fs-xs); letter-spacing: var(--eyebrow-tracking); text-transform: uppercase; color: var(--c-text-mid); }
.legal h2 { font-size: var(--fs-serif-md); margin: 2.5rem 0 1rem; }
.legal p { color: var(--c-text-80); }
.legal a { text-decoration: underline; }
.main-offset { }

/* ═══════════════════════════════════════════════════════════════════════════
   FINITIONS DE MOUVEMENT
   Aucune animation existante n'est remplacée : on affine les courbes et les
   durées des interactions déjà en place, on ajoute quelques micro-réactions
   (boutons, liens, cartes) et un flottement continu sur les images détourées.

   Le flottement passe par la propriété `translate` (et non `transform`) :
   motion.js écrit `transform` en ligne pour la parallaxe et les rotations du
   Figma sont portées par `transform` — les deux se composent sans conflit.
   ═══════════════════════════════════════════════════════════════════════════ */

@keyframes kjc-float {
  0%, 100% { translate: 0 calc(var(--float-y) * -0.5); }
  50%      { translate: 0 calc(var(--float-y) * 0.5); }
}
/* variante légèrement dérivante pour éviter l'effet « métronome » quand
   plusieurs images flottent côte à côte */
@keyframes kjc-float-alt {
  0%, 100% { translate: 0 calc(var(--float-y) * 0.5); }
  35%      { translate: calc(var(--float-y) * 0.18) calc(var(--float-y) * -0.2); }
  70%      { translate: calc(var(--float-y) * -0.12) calc(var(--float-y) * -0.5); }
}

.kjc-float {
  animation: kjc-float var(--float-dur) cubic-bezier(0.45, 0, 0.55, 1) infinite;
  will-change: translate;
}

/* ── Boutons ─────────────────────────────────────────────────────────────────
   Le bouton pilule reprend le geste d'aurore tel quel — scale(1.05) au survol,
   défini dans son bloc principal. Aucune finition supplémentaire ici. */

/* ── Navigation : l'emphase passe par la couleur seule ───────────────────── */
.site-nav a, .lang-switch { transition: color var(--dur-fast) var(--ease-soft); }

/* la légende du hero : flèche plus vive, léger rapprochement du bloc */
.hero__caption-more svg { transition: transform var(--dur-mid) var(--ease-emph); }
.hero__caption:hover .hero__caption-more svg { transform: translateX(7px); }
.hero__caption-title { transition: letter-spacing var(--dur-mid) var(--ease-soft); }
.hero__caption:hover .hero__caption-title { letter-spacing: 0.004em; }

.site-header__logo img { transition: transform var(--dur-mid) var(--ease-emph), opacity var(--dur-fast) var(--ease-soft); }
.site-header__logo:hover img { transform: scale(1.08) rotate(-3deg); }

/* ── Latest work ─────────────────────────────────────────────────────────── */
/* l'affiche respire au survol ; la carte réduite s'éclaircit déjà (plus haut) */
.work-card img { transition: transform 1.4s var(--ease-out), filter 0.6s var(--ease-out); }
.latest.is-live .work-card[data-size="large"]:hover img { transform: scale(1.06); }
.work-card__label { transition: transform var(--dur-mid) var(--ease-emph); }
.latest.is-live .work-card:hover .work-card__label { transform: translateY(-4px); }
.latest__bar { transition: opacity var(--dur-mid) var(--ease-soft), flex-grow 620ms var(--ease-out), transform var(--dur-fast) var(--ease-soft); }
.latest__bar:hover { opacity: 0.85; transform: scaleY(1.6); }
.latest__ring { transition: background 140ms linear, transform var(--dur-mid) var(--ease-emph); }
.work-card--end:hover .latest__ring { transform: scale(1.06); }

/* ── Cartes services : la photo flotte, détachée de la carte ─────────────── */
.service-card__photo {
  animation: kjc-float var(--float-dur) cubic-bezier(0.45, 0, 0.55, 1) infinite;
  will-change: translate;
  transition: filter var(--dur) var(--ease-out), opacity 380ms var(--ease-out);
}
.service-card:nth-of-type(2n) .service-card__photo { animation-name: kjc-float-alt; animation-duration: calc(var(--float-dur) * 1.25); }
.service-card:nth-of-type(3n) .service-card__photo { animation-delay: -2.4s; animation-duration: calc(var(--float-dur) * 1.1); }

/* ── About (home) : les polaroïds flottent par-dessus la parallaxe ───────── */
.polaroid { animation: kjc-float var(--float-dur) cubic-bezier(0.45, 0, 0.55, 1) infinite; will-change: translate, transform; }
.polaroid--right { animation-name: kjc-float-alt; animation-duration: calc(var(--float-dur) * 1.3); animation-delay: -1.8s; }
.about__title, .about__desc { transition: opacity var(--dur) var(--ease-out); }

/* ── Page About : photos du hero, portraits et polaroïds de chapitre ─────── */
.story-hero__photo { animation: kjc-float calc(var(--float-dur) * 1.15) cubic-bezier(0.45, 0, 0.55, 1) infinite; will-change: translate, transform; }
.story-hero__photo--centre { animation-name: kjc-float-alt; animation-duration: calc(var(--float-dur) * 0.9); animation-delay: -1.2s; }
.story-hero__photo--right  { animation-delay: -3.1s; animation-duration: calc(var(--float-dur) * 1.35); }

.chapter__photo {
  animation: kjc-float calc(var(--float-dur) * 1.2) cubic-bezier(0.45, 0, 0.55, 1) infinite;
  will-change: translate;
}
.chapter:nth-of-type(2n) .chapter__photo { animation-name: kjc-float-alt; animation-delay: -2.6s; }

/* ── Respect strict du mouvement réduit ──────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  .kjc-float, .service-card__photo, .polaroid, .story-hero__photo, .chapter__photo {
    animation: none !important; translate: none !important;
  }
  .work-card__label, .latest__bar, .latest__ring { transition: none !important; }
  .latest.is-live .work-card[data-size="large"]:hover img { transform: scale(1.05); }
}
