/* ============================================================
   Félix Jobbe — Portfolio
   Editorial / warm-cream system inspired by reference layout
   ============================================================ */

/* Les polices sont auto-hébergées, voir polices.css, chargée avant celle-ci.
   L'import Google Fonts de la maquette a été retiré : il annulait ce travail en
   allant chercher les mêmes fontes chez un tiers à chaque visite. */

:root{
  --bg:        #FFFBF5;   /* warm cream */
  --bg-2:      #ECE6D9;   /* deeper warm band */
  --card:      #FBF9F3;   /* light surface */
  --ink:       #1A1714;   /* warm near-black */
  --ink-soft:  #423E36;
  --muted:     #938C7D;   /* warm grey */
  --muted-2:   #B6AF9F;
  --line:      rgba(26,23,20,.13);
  --line-soft: rgba(26,23,20,.07);

  /* service card pastels (warm) */
  --c-lav:    #E2DAF1;
  --c-green:  #D6EBBE;
  --c-coral:  #F4D2C7;
  --c-yellow: #F1E6BC;
  --c-blue:   #D7E2F0;

  --maxw: 1680px;
  --gut-base: 32px;
  /* La marge des sections (demande de Félix, 13 septembre 2026) : la distance
     du bord au logo, reportée à droite du logo (30 px), soit 94 px en desktop
     et 78 px en tablette. La barre garde la marge simple, --bord. */
  --logo: 30px;
  --bord: var(--gut-base);
  --gut: calc(var(--gut-base) * 2 + var(--logo));

  /* ---- Le rythme du site, calé sur Bungee ------------------------------------
     Relevé calque par calque dans Framer le 12 septembre 2026
     (docs/superpowers/specs/mesures_bungee/bungee_calques.md). Bungee ne règle
     pas ses écarts sur la hauteur de l'écran, mais par palier de largeur :
     desktop ici, tablette sous 1200 px, mobile sous 810 px (voir plus bas).
     Les écarts collés à un titre ne sont pas ici : ils sont en em sur le titre,
     au prorata de ceux de Bungee, pour suivre l'échelle typographique de la V2. */
  --barre:         80px;   /* nav fixe */
  --tete-accueil: 153px;   /* haut de l'accueil → nom dessiné (Bungee, relevé du 13/09) */
  --tete-liste:   128px;   /* haut des listes sans fil d'Ariane (Works, Blog) */
  --tete-fiche:   120px;   /* haut des fiches et articles (Article › Hero) */
  --tete-page:    104px;   /* haut d'À propos et Contact (Contact › Container) */
  --section-haut:  32px;   /* padding haut d'une section (Portfolio, Main, FAQ) */
  --section-bas:  120px;   /* padding bas d'une section */
  --intro:        120px;   /* padding vertical du manifeste (Intro) */
  --grille:        56px;   /* entre deux colonnes de cartes (Portfolio › Container) */
  --items:         48px;   /* entre deux items d'une liste (Main › Container) */
  --chiffres:      40px;   /* entre deux chiffres (Metrics › Container) */
  --cartes-journal: 40px;  /* entre deux cartes d'articles (Blog › Container) */
  --corps:         24px;   /* entre deux blocs du corps de lecture (Article) */
  --corps-marge:   56px;   /* padding vertical du corps de fiche (Case Study › Text) */
  --cta:           96px;   /* padding vertical de l'appel final (CTA), aux trois tailles */
  --pied-haut:     32px;   /* padding haut du pied de page (Footer › Content) */
  --pied-bas:      32px;
  --pied-top:      96px;   /* logo du pied → contenu (Footer › Top) */
  --pied-ecart:   250px;   /* haut du pied → liens du bas (Footer › Content) */
  --faq:           60px;   /* titre de la FAQ → questions (FAQ) */
  /* La taille des titres de section, nommée pour que l'écart sous l'en-tête
     puisse s'y proportionner (voir .shead). */
  /* 15/09 retour Félix : titres réduits. Titres de section plafonnés à 64 px
     (1440) et 34 px (390) ; titre d'entrée de page à 80 / 40 px (--h1-page). */
  --h2: calc(clamp(34px,4.45vw,64px) * var(--tj-heads));
  --h1-page: clamp(40px,5.6vw,80px);
  /* Les trois mesures relevées sur Bungee (bungee.framer.website), à 1440 px :
     la couverture prend toute la largeur moins les marges, le bloc de titre
     fait 900, la colonne de lecture et les images du corps font 800. Les trois
     sont centrées sur le même axe. */
  --lecture: 800px;                         /* colonne de texte et images du corps */
  --titre:   900px;                         /* bloc de titre, plus large que le texte */
  --large:   1120px;

  /* Tweakable scale multipliers — set by Tweaks panel via JS */
  --tj-hero:  1;   /* hero wordmark */
  --tj-heads: 1;   /* section headings */
  --tj-body:  1;   /* body / intro text */
  --r-lg: 22px;
  --r-md: 16px;

  --ease: cubic-bezier(.22,.61,.36,1);
}

/* Tablette (Bungee : 810 à 1199 px). Seules les valeurs qui changent. */
@media (max-width:1199px){
  :root{
    --gut-base: 24px;
    --tete-accueil: 120px;
    --section-bas: 80px;
    --intro: 96px;
    --pied-haut: 24px;
    --pied-bas: 24px;
    --cartes-journal: 24px;
  }
}
/* Mobile (Bungee : moins de 810 px). */
@media (max-width:809px){
  :root{
    --gut-base: 16px;
    --gut: var(--gut-base);   /* mobile : alignées sur le bord du logo */
    --tete-accueil: 128px;
    --tete-liste: 100px;
    --tete-fiche: 100px;
    --tete-page: 100px;
    --section-bas: 32px;
    --intro: 32px;
    --grille: 24px;
    --items: 32px;
    --chiffres: 32px;
    --cartes-journal: 40px;
    --corps: 16px;
    --corps-marge: 40px;
    --pied-haut: 24px;
    --pied-bas: 16px;
    --pied-ecart: 134px;
  }
}

*{ box-sizing:border-box; }
html{ -webkit-font-smoothing:antialiased; -moz-osx-font-smoothing:grayscale; scroll-behavior:smooth; }
body{
  margin:0;
  background:var(--bg);
  color:var(--ink);
  font-family:'Hanken Grotesk',system-ui,sans-serif;
  font-size:17px;
  line-height:1.5;
  overflow-x:hidden;
}
img{ display:block; max-width:100%; }
a{ color:inherit; text-decoration:none; }

/* ---- selection ---- */
::selection{ background:var(--ink); color:var(--bg); }

/* ---- mono label ---- */
.mono{
  font-family:'DM Mono',ui-monospace,monospace;
  font-weight:400;
  letter-spacing:.04em;
  font-size:13px;
  color:var(--muted);
  text-transform:uppercase;
}

/* ---- image-slot placeholders ---- */
image-slot::part(frame){
  background: #E8E0D0;
  cursor:pointer;
}
image-slot::part(frame):hover{
  background: #DDD5C5;
}
image-slot::part(empty){
  color:rgba(26,23,20,.7);
  font-family:'Hanken Grotesk',sans-serif;
  font-size:13px;
  font-weight:500;
  letter-spacing:.04em;
}
image-slot::part(ring){ border-color:rgba(26,23,20,.25); border-width:1.5px; }

/* wrapper tint sits behind the near-transparent empty slot so placeholders
   read clearly even before the user drops an image */
.strip .arch,
.intro-strip .bud,
.proj .frame,
.post .frame,
.article .frame,
.carte .frame,
.testi-photo,
.reel-frame{
  position:relative;
  background:
    repeating-linear-gradient(135deg, rgba(26,23,20,.05) 0 2px, transparent 2px 12px),
    #E5DDCD;
}
/* fill wrappers regardless of aspect-ratio percentage-height quirks */
.strip .arch image-slot,
.intro-strip .bud image-slot,
.proj .frame image-slot,
.post .frame image-slot,
.article .frame image-slot,
.carte .frame image-slot,
.testi-photo image-slot,
.reel-frame image-slot{
  position:absolute; inset:0; width:100%; height:100%;
}

/* ---- shell ---- */
.wrap{ max-width:var(--maxw); margin:0 auto; padding-inline:var(--gut); }
section{ position:relative; }

/* ============================================================
   FIXED HEADER
   ============================================================ */
.topbar{
  position:fixed; inset:0 0 auto 0; z-index:80;
  display:flex; align-items:center; justify-content:space-between;
  height:var(--barre); padding:0 var(--bord);   /* Bungee : nav fixe de 80 px */
  background:rgba(255,251,245,.5);
  -webkit-backdrop-filter:blur(18px) saturate(1.5);
  backdrop-filter:blur(18px) saturate(1.5);
  view-transition-name:barre;
}
.brand{ display:flex; align-items:center; gap:10px; position:relative; z-index:2; }
.brand img{ width:30px; height:30px; }

/* ---- morphing menu button: + → hamburger(hover) → ✕(open) ---- */
.menu-btn{
  width:34px; height:34px; position:relative;
  background:none; border:none; padding:0; cursor:pointer;
  z-index:2;
}
.menu-btn .bar{
  position:absolute; left:50%; top:50%;
  width:25px; height:2.2px; border-radius:2px; background:var(--ink);
  transition:transform .45s var(--ease);
}
.menu-btn .bar:nth-child(1){ transform:translate(-50%,-50%) rotate(0deg); }
.menu-btn .bar:nth-child(2){ transform:translate(-50%,-50%) rotate(90deg); }
/* hover → two-bar hamburger */
.menu-btn:hover .bar:nth-child(1){ transform:translate(-50%,calc(-50% - 5px)) rotate(0deg); }
.menu-btn:hover .bar:nth-child(2){ transform:translate(-50%,calc(-50% + 5px)) rotate(0deg); }
/* open → ✕ (wins over hover via specificity) */
body.menu-open .menu-btn .bar:nth-child(1){ transform:translate(-50%,-50%) rotate(45deg); }
body.menu-open .menu-btn .bar:nth-child(2){ transform:translate(-50%,-50%) rotate(-45deg); }

/* ============================================================
   FULL-SCREEN MENU OVERLAY (blurry, rolls down)
   ============================================================ */
.menu-overlay{
  position:fixed; top:0; left:0; right:0; z-index:70;
  height:82svh; min-height:540px;
  background:rgba(255,251,245,.5);
  -webkit-backdrop-filter:blur(30px) saturate(1.5);
  backdrop-filter:blur(30px) saturate(1.5);
  display:flex; flex-direction:column; justify-content:flex-start;
  padding:96px var(--bord) 80px;
  opacity:0; visibility:hidden;
  clip-path:inset(0 0 100% 0);
  transition:clip-path .62s var(--ease), opacity .45s var(--ease), visibility .62s;
}
body.menu-open .menu-overlay{
  opacity:1; visibility:visible;
  clip-path:inset(0 0 0 0);
}
.menu-list{ list-style:none; margin:0; padding:0; position:relative; }
.menu-item{
  display:flex; align-items:baseline; gap:clamp(16px,2.6vw,46px);
  padding:clamp(2px,.5vh,7px) 0;
}
.menu-item .num{
  font-family:'DM Mono',monospace; font-size:14px; color:var(--muted);
  width:74px; flex:none; letter-spacing:.04em; white-space:nowrap;
  align-self:center;
}
.menu-item a{
  font-size:clamp(34px,5vw,70px); font-weight:600; letter-spacing:-.03em;
  line-height:1.0; display:block; padding:0 0 5px; transition:opacity .3s var(--ease);
}
.menu-list:hover .menu-item a{ opacity:.4; }
.menu-list:hover .menu-item:hover a{ opacity:1; }
/* full-row hit area — ::after covers the whole <li> row, click → link */
.menu-item{ position:relative; cursor:pointer; }
.menu-item a::after{ content:''; position:absolute; inset:0; z-index:1; }
/* underline: invisible by default, appears only on list hover */
.menu-underline{
  position:absolute; left:0; right:0; height:1.6px; background:var(--ink);
  top:0; transform:translateY(0); opacity:0;
  transition:transform .45s var(--ease), opacity .3s var(--ease);
  pointer-events:none;
}
.menu-list:hover .menu-underline{ opacity:1; }
.menu-foot{
  position:absolute; left:var(--bord); right:var(--bord); bottom:clamp(40px,7vh,72px);
  display:flex; align-items:flex-end; justify-content:space-between; gap:24px;
}
.menu-email{
  font-size:clamp(22px,2.6vw,40px); font-weight:500; letter-spacing:-.02em;
  border-bottom:2px solid var(--ink); padding-bottom:5px; transition:opacity .25s;
}
.menu-email:hover{ opacity:.6; }
.menu-social{
  display:flex; gap:14px; align-items:center;
  font-family:'DM Mono',monospace; font-size:14px; letter-spacing:.05em; color:var(--muted);
}
.menu-social a{ transition:color .25s; }
.menu-social a:hover{ color:var(--ink); }
.menu-social .sep{ color:var(--muted-2); }

@media (max-width:560px){
  .menu-item .num{ width:46px; font-size:12px; }
  .menu-foot{ flex-direction:column; align-items:flex-start; gap:18px; }
}

/* ============================================================
   HERO
   ============================================================ */
.hero{
  display:flex; flex-direction:column;
  padding-top:var(--tete-accueil);
  padding-bottom:0;
  overflow:hidden;
}
.hero-top{
  flex:0 0 auto;
  display:flex; flex-direction:column; align-items:center; justify-content:center;
  text-align:center;
  position:relative;
  padding-bottom:0;
}
.hero-clock{
  font-family:'DM Mono',monospace;
  font-size:14px; letter-spacing:.05em; color:var(--muted);
  /* Verticale contre le bord gauche, comme Bungee : son pied s'aligne sur celui
     des réseaux. */
  position:absolute; left:var(--bord); top:17px;
  writing-mode:vertical-rl; transform:translateY(-100%) rotate(180deg);
  white-space:nowrap;
}
/* Le nom est une image (images/accueil/felix_jobbe.png). Sa largeur suit l'ancien
   titre en texte : 4,9 fois le corps qu'il avait, marges transparentes comprises. */
.hero-mark{
  /* À 1 000 px, les lettres font la hauteur des capitales de « Bungee » (146 px) :
     le nom de Félix est long et bas, à 704 px (la largeur de Bungee) il paraissait
     maigre. Pleine largeur entre les bords dès que l'écran est plus étroit. */
  width:min(1000px, calc(100vw - var(--bord) * 2));
}
.hero-mark img{ width:100%; height:auto; }
.hero-tag{
  /* Toute la largeur entre les bords, comme l'accroche de Bungee ; si elle doit
     passer sur deux lignes, les deux sont équilibrées (pas de mot seul). */
  margin:32px 0 0; padding-inline:var(--bord); text-wrap:balance;
  font-size:24px;
  color:var(--ink);
  font-weight:400;
}
/* Sur ordinateur, les réseaux tombent à égale distance de l'accroche et des
   cadres : 34 px de chaque côté (Félix, 13/09). 51 = 34 + la ligne de 17 px. */
.hero-links{
  margin-top:34px; position:relative; height:51px;
  display:flex; align-items:flex-start;
  justify-content:flex-end;
  width:100%;
  padding-inline:var(--bord);
  font-family:'DM Mono',monospace; font-size:14px; letter-spacing:.05em;
  color:var(--muted);
}
.hero-socials{ display:flex; gap:14px; align-items:center; line-height:17px; }
/* Sur tablette et mobile, l'accroche prend toute la largeur ; les réseaux
   viennent juste dessous, puis l'horloge, couchée à l'horizontale sur sa propre
   ligne (15/09 retour Félix : verticale, elle s'intercalait entre le titre et
   les réseaux), puis 51 px jusqu'aux cadres, comme chez Bungee. */
@media (max-width:1199px){
  .hero-links{
    margin-top:0; height:auto;
    flex-direction:column; align-items:flex-end; justify-content:flex-start; gap:8px;
    padding-top:var(--corps); padding-bottom:51px;
  }
  .hero-socials{ order:0; }
  .hero-clock{ order:1; position:static; writing-mode:horizontal-tb; transform:none; line-height:17px; }
}
.hero-links a{ transition:color .25s; }
.hero-links a:hover{ color:var(--ink); }
.hero-links .sep{ color:var(--muted-2); }

/* --- Le bandeau d'arches, façon Bungee (relevé du 13 septembre 2026) ----------
   Cadres de 181 × 520 px, 10 px d'écart, sans marge : la rangée va d'un bord à
   l'autre et défile en continu à 60 px/s. Un fondu de 180 px, de la couleur du
   fond au transparent, la dissout aux deux bords : c'est le réglage « hero » du
   moteur edge-blur.js de la maquette Claude Design, refait en CSS. Coupé par le
   bas de l'écran, comme chez Bungee. Sous « Réduire les animations », la rangée
   s'arrête, comme chez Bungee. */
.strip{
  position:relative;
  overflow:hidden;
  height:520px;
  --pill-r:clamp(46px, 5.6vw, 88px);
  --pill-w:181px;
}
.strip::before, .strip::after{
  /* 180 px (Claude Design), mais jamais plus de 14 % de l'écran : sur mobile,
     deux fondus fixes mangeraient toute la rangée (Bungee : 13 % par côté). */
  content:""; position:absolute; top:0; bottom:0; width:min(180px, 14vw);
  z-index:2; pointer-events:none;
}
.strip::before{
  left:0;
  background:linear-gradient(to right, rgba(255,251,245,1) 0%, rgba(255,251,245,.85) 45%, rgba(255,251,245,.18) 80%, rgba(255,251,245,0) 100%);
}
.strip::after{
  right:0;
  background:linear-gradient(to left, rgba(255,251,245,1) 0%, rgba(255,251,245,.85) 45%, rgba(255,251,245,.18) 80%, rgba(255,251,245,0) 100%);
}
/* La piste répète la rangée ; elle recule de la moitié de sa largeur, puis
   recommence. Le padding de fin compte le dernier écart, sans quoi la boucle
   sauterait de 5 px. */
/* 15/09 retour Félix (saccade) : la piste garde son calque (will-change) et
   démarre en douceur. `fj-defile-entree` pousse la piste vers la droite
   (propriété `translate`, distincte du `transform` de la boucle) à 60 px/s au
   départ, en ralentissant jusqu'à 0 sur 0,8 s : la vitesse vue passe de 0 à
   60 px/s sans à-coup. Pente de départ de la courbe = 0,5 / 0,25 = 2, d'où
   24 px = 60 px/s × 0,8 s / 2. La boucle, elle, reste linéaire. */
.strip-piste{
  display:flex; gap:10px; padding-right:10px;
  width:max-content; height:100%;
  will-change:transform;
  animation:fj-defile var(--duree, 20s) linear infinite, fj-defile-entree .8s cubic-bezier(.25,.5,.55,1) both;
}
@keyframes fj-defile{ to{ transform:translateX(-50%); } }
@keyframes fj-defile-entree{ from{ translate:0 0; } to{ translate:24px 0; } }
/* Les cadres défilent : ils ne s'animent pas un à un. Chacun entrait à
   opacité 0 et attendait l'IntersectionObserver, qui ne tourne pas pendant une
   animation composée : trou puis fondu de 2 s en plein mouvement. Le fondu est
   porté par le bandeau entier (data-reveal="fondu" sur .strip). */
html.js .strip [data-reveal="fondu"]{ opacity:1; transition:none; }
@media (prefers-reduced-motion:reduce){
  .strip-piste{ animation:none; }
}
.strip .arch{
  flex:0 0 var(--pill-w);
  width:var(--pill-w);
  height:100%;
  overflow:hidden;
  min-width:0;
  /* L'alternance des arrondis en diagonale est portée par la classe arch-b,
     posée par le gabarit : nth-child casserait le raccord de la boucle. */
  border-radius:var(--pill-r) 0 var(--pill-r) 0;
}
.strip .arch.arch-b{ border-radius:0 var(--pill-r) 0 var(--pill-r); }

/* ============================================================
   SECTION HEAD (shared)
   ============================================================ */
.shead{
  display:flex; align-items:flex-end; justify-content:space-between;
  gap:30px; flex-wrap:wrap;
  margin-bottom:max(16px, calc(var(--h2) * .75));
}
.shead h2{
  font-size:var(--h2);
  line-height:.95;
  font-weight:600;
  letter-spacing:-.035em;
  margin:0;
}
.shead .link{
  display:inline-flex; align-items:center; gap:9px;
  font-size:18px; padding-bottom:5px;
  border-bottom:1.5px solid var(--ink);
  transition:gap .3s var(--ease);
}
.shead .link:hover{ gap:16px; }
.shead .link .pl{ position:relative; width:15px; height:15px; }
.shead .link .pl::before,.shead .link .pl::after{ content:''; position:absolute; inset:0; margin:auto; background:var(--ink); }
.shead .link .pl::before{ width:100%; height:1.6px; }
.shead .link .pl::after{ width:1.6px; height:100%; }

/* ============================================================
   INTRO (pastilles « Documentaire, Institutionnel… » retirées le 15/09)
   ============================================================ */
/* Espacements des sections : Bungee, calques Intro, Portfolio, Main, Metrics, FAQ et Blog. */
.intro{ padding:var(--intro) 0; }
.intro-strip{
  display:grid; grid-auto-flow:column; gap:14px;
  height:clamp(150px,20vh,230px);
  margin-bottom:var(--items);
  grid-auto-columns: minmax(150px,1fr);
  overflow:hidden;
}
.intro-strip image-slot{ width:100%; height:100%; }
.intro-strip .bud{ border-radius:0 0 120px 120px; overflow:hidden; }
/* 15/09 retour Félix : colonne élargie (600 → 1000 px pour la phrase, 820 px pour
   le texte) ; à 1440 px, la phrase tient sur 3 lignes et chaque paragraphe sur 4
   au plus, au lieu d'un bloc compact. Pleine largeur sur mobile. */
.intro-lead{
  max-width:1000px; text-wrap:balance;
  margin:0 auto max(16px,.4em);
  text-align:center;
  font-size:calc(clamp(23px,3.1vw,44px) * var(--tj-body));
  line-height:1.14;
  letter-spacing:-.02em;
  font-weight:500;
}
.intro-lead em{ font-style:normal; color:var(--muted); }
/* Le texte d'accueil, sous la grande phrase : corps de lecture normal, pour que la
   page dise qui, quoi et où sans casser la hiérarchie de la maquette. */
.intro-texte{
  max-width:820px; margin:0 auto;
  text-align:center; color:var(--muted);
  font-size:calc(clamp(15px,1.15vw,18px) * var(--tj-body)); line-height:1.55;
}
.intro-texte p{ margin:0 0 .9em; }
.intro-texte p:last-child{ margin-bottom:0; }

/* ============================================================
   PROJECTS
   ============================================================ */
.projects{ padding:var(--section-haut) 0 var(--section-bas); }
.proj-grid{
  display:grid; grid-template-columns:1fr 1fr; gap:var(--grille);
}
.proj{ cursor:pointer; }
.proj .frame{
  position:relative; overflow:hidden; border-radius:var(--r-lg);
  aspect-ratio:1/1.04;
}
.proj image-slot{ width:100%; height:100%; transition:transform .9s var(--ease); }
.proj:hover image-slot{ transform:scale(1.04); }
.proj-meta{
  display:flex; align-items:baseline; justify-content:space-between;
  margin-top:12px; gap:20px;
}
.proj-meta h3{ font-size:15px; font-weight:600; letter-spacing:.02em; text-transform:uppercase; margin:0; }
.proj-meta .date{ font-family:'DM Mono',monospace; font-size:13px; color:var(--muted); white-space:nowrap; }
.proj-tag{ font-family:'DM Mono',monospace; font-size:12px; color:var(--muted); margin-top:5px; text-transform:uppercase; letter-spacing:.05em; }

/* ============================================================
   SERVICES (horizontal scroll)
   ============================================================ */
.services{ padding:var(--section-haut) 0 var(--section-bas); overflow:hidden; }
.services .wrap{ position:relative; }
.svc-track{
  display:flex; gap:var(--corps);
  overflow-x:auto; scroll-snap-type:x mandatory;
  padding-bottom:8px;
  scrollbar-width:none;
}
.svc-track::-webkit-scrollbar{ display:none; }
.svc{
  scroll-snap-align:start;
  flex:0 0 clamp(336px, 31%, 460px);   /* 336 = 256 px de texte + 2 × 40 (15/09) */
  aspect-ratio:1/1.16;
  border-radius:var(--r-lg);
  padding:40px;
  display:flex; flex-direction:column;
  position:relative;
  transition:transform .5s var(--ease);
}
.svc:hover{ transform:none; }
.svc .num{ font-family:'DM Mono',monospace; font-size:14px; letter-spacing:.08em; color:rgba(26,23,20,.55); }
.svc .glyph{
  flex:1 1 auto; display:flex; align-items:center; justify-content:center;
  color:var(--ink);
}
.svc .glyph svg{ width:54px; height:54px; }
.svc .svc-name{ font-family:'DM Mono',monospace; font-size:14px; letter-spacing:.06em; text-transform:uppercase; margin-bottom:10px; }
/* Même nombre de lignes pour tous les blocs (Félix, 15/09) : textes de longueur
   voisine (141 à 158 caractères) sur une colonne de 256 px, où tous tombent sur
   5 lignes (plage mesurée : 248 à 263 px, à 1440 comme à 900). La hauteur de
   5 lignes est réservée, sans rien tronquer. Un texte de bloc ajouté ou modifié
   se vérifie au navigateur. */
.svc p{ margin:0; font-size:16px; line-height:1.4; width:256px; max-width:100%; min-height:calc(5 * 1lh); color:var(--ink-soft); }
.svc-arrow{
  position:absolute; right:calc(var(--gut) - 6px); top:50%; transform:translateY(-50%);
  width:46px; height:46px; border-radius:50%;
  background:rgba(255,255,255,.75); backdrop-filter:blur(6px);
  border:1px solid var(--line);
  display:flex; align-items:center; justify-content:center; cursor:pointer; z-index:10;
  transition:background .25s, transform .25s;
}
.svc-arrow:hover{ background:#fff; transform:translateY(-50%) scale(1.06); }
.svc-arrow svg{ width:18px; height:18px; }

/* ============================================================
   SHOWREEL
   ============================================================ */
.reel{ padding:var(--section-haut) 0 var(--section-bas); }
.reel h2{
  font-size:calc(clamp(26px,3.3vw,48px) * var(--tj-heads)); line-height:1.06; font-weight:600;
  letter-spacing:-.025em; max-width:22ch; margin:0 0 max(16px,.4em);
}
.reel-frame{
  position:relative; border-radius:var(--r-lg); overflow:hidden;
  aspect-ratio:16/9;
}
.reel-frame image-slot{ width:100%; height:100%; }
.play{
  position:absolute; inset:0; margin:auto;
  width:clamp(86px,9vw,128px); height:clamp(86px,9vw,128px);
  border-radius:50%;
  background:rgba(255,255,255,.82); backdrop-filter:blur(3px);
  display:flex; align-items:center; justify-content:center; cursor:pointer;
  transition:transform .4s var(--ease), background .3s;
}
.play:hover{ transform:scale(1.07); background:#fff; }
.play::after{
  content:''; width:0; height:0; margin-left:6px;
  border-left:22px solid var(--ink);
  border-top:14px solid transparent; border-bottom:14px solid transparent;
}

/* ============================================================
   STATS
   ============================================================ */
.stats{ padding:var(--section-haut) 0 var(--section-bas); }
.stats-grid{
  display:grid; grid-template-columns:repeat(4,1fr); gap:var(--chiffres);
}
.stat .num{ font-size:clamp(44px,5vw,80px); font-weight:700; letter-spacing:-.04em; line-height:1; }
.stat p{ margin:12px 0 0; color:var(--ink-soft); font-size:16px; max-width:20ch; }

/* ============================================================
   TESTIMONIALS
   ============================================================ */
.testi{ padding:var(--section-haut) 0 var(--section-bas); text-align:center; }
.testi .eyebrow{ letter-spacing:.18em; }
.testi h2{
  font-size:calc(clamp(34px,5vw,78px) * var(--tj-heads)); line-height:1.02; font-weight:600;
  letter-spacing:-.03em; margin:16px auto max(16px,.75em); max-width:16ch;
}
.testi-card{
  display:grid; grid-template-columns:1fr 1fr;
  background:var(--bg-2); border-radius:var(--r-lg); overflow:hidden;
  text-align:left; min-height:560px;
}
.testi-photo{ position:relative; overflow:hidden; }
.testi-photo image-slot{ width:100%; height:100%; }
.testi-body{
  display:flex; flex-direction:column; justify-content:center;
  padding:clamp(36px,5vw,80px);
}
.testi-body blockquote{
  margin:0; font-size:clamp(22px,2.3vw,38px); line-height:1.18; letter-spacing:-.02em;
  font-weight:400;
}
.testi-author{ margin-top:var(--corps); }
.testi-author .nm{ font-weight:500; font-size:18px; }
.testi-author .rl{ color:var(--muted); font-size:16px; margin-top:3px; }
.testi-dots{ display:flex; gap:9px; justify-content:center; margin-top:34px; }
.testi-dots button{
  width:9px; height:9px; border-radius:50%; border:none; cursor:pointer;
  background:var(--muted-2); padding:0; transition:background .3s, transform .3s;
}
.testi-dots button.on{ background:var(--ink); transform:scale(1.15); }

/* ============================================================
   FAQ
   ============================================================ */
.faq{ padding:var(--section-haut) 0 var(--section-bas); }
.faq-grid{ display:grid; grid-template-columns:1fr 1.15fr; gap:var(--faq); align-items:start; }
.faq h2{ font-size:var(--h2); font-weight:600; letter-spacing:-.035em; margin:0; line-height:.95; }
.faq-list{ border-top:1px solid var(--line); }
.faq-item{ border-bottom:1px solid var(--line); }
.faq-q{
  width:100%; background:none; border:none; cursor:pointer;
  display:flex; align-items:center; justify-content:space-between; gap:24px;
  padding:var(--corps) 4px; text-align:left;
  font-family:inherit; font-size:clamp(17px,1.35vw,21px); color:var(--ink); font-weight:500;
}
.faq-q .ic{ position:relative; width:18px; height:18px; flex:none; transition:transform .4s var(--ease); }
.faq-q .ic::before,.faq-q .ic::after{ content:''; position:absolute; inset:0; margin:auto; background:var(--ink); transition:opacity .3s; }
.faq-q .ic::before{ width:100%; height:1.7px; }
.faq-q .ic::after{ width:1.7px; height:100%; }
.faq-item.open .faq-q .ic::after{ opacity:0; }
.faq-a{ overflow:hidden; max-height:0; transition:max-height .5s var(--ease); }
.faq-a-inner{ padding:0 4px var(--corps); color:var(--ink-soft); font-size:16px; line-height:1.55; max-width:54ch; }

/* ============================================================
   JOURNAL (landing teaser)
   ============================================================ */
.journal{ padding:var(--section-haut) 0 var(--items); }
.journal-grid{ display:grid; grid-template-columns:repeat(3,1fr); gap:var(--cartes-journal); }
.post{ display:block; cursor:pointer; }
.post .frame{ aspect-ratio:1/0.84; border-radius:var(--r-lg); overflow:hidden; }
.post .frame image-slot{ transition:transform .9s var(--ease); }
.post:hover .frame image-slot{ transform:scale(1.04); }
.post .date{ display:block; margin-top:16px; }
.post h3{ margin:8px 0 0; font-size:clamp(19px,1.45vw,24px); font-weight:600; letter-spacing:-.018em; line-height:1.16; text-wrap:pretty; }

/* ============================================================
   BLOG PAGE
   ============================================================ */
.blog-hero{ padding:var(--tete-liste) 0 var(--items); }
.blog-hero h1{ font-size:var(--h1-page); font-weight:600; letter-spacing:-.038em; line-height:.95; margin:0 0 max(16px,.46em); }
.blog-hero p{ max-width:44ch; margin:0; font-size:clamp(18px,1.45vw,23px); color:var(--ink-soft); }
.articles{ padding-bottom:var(--section-bas); }
.article{
  display:grid; grid-template-columns:.92fr 1.4fr; gap:clamp(24px,4vw,72px);
  padding:calc(var(--items) / 2) 0; border-top:1px solid var(--line); align-items:center;
}
.article:last-child{ border-bottom:1px solid var(--line); }
.article .frame{ aspect-ratio:4/3; border-radius:var(--r-lg); overflow:hidden; }
.article .frame image-slot{ transition:transform .9s var(--ease); }
.article:hover .frame image-slot{ transform:scale(1.03); }
.article-body .meta{ display:flex; gap:14px; align-items:center; margin-bottom:16px; }
.article-body h2{
  font-size:clamp(26px,2.7vw,44px); font-weight:600; letter-spacing:-.028em;
  line-height:1.05; margin:0 0 16px; text-wrap:pretty;
}
.article-body p{ margin:0 0 var(--corps); color:var(--ink-soft); max-width:56ch; }
.article .read{
  display:inline-flex; align-items:center; gap:9px; font-size:16px;
  border-bottom:1.5px solid var(--ink); padding-bottom:4px; transition:gap .3s var(--ease);
}
.article:hover .read{ gap:16px; }

@media (max-width:900px){
  .journal-grid{ grid-template-columns:1fr; gap:var(--cartes-journal); }
}
@media (max-width:760px){
  .article{ grid-template-columns:1fr; gap:var(--corps); }
}

/* ============================================================
   FOOTER
   ============================================================ */
/* Bungee, calque Footer › Content : padding 32 / 24 / 24-16, 250 px (134 en mobile) entre le haut et les liens du bas. */
.footer{ background:var(--bg-2); padding:var(--pied-haut) 0 var(--pied-bas); margin-top:0; }
/* Haut du pied hors de `.wrap`, sur les bords de la barre de menu : logo au x du
   logo de la nav (15/09). Les réseaux reprennent `.hero-socials` du hero
   (même écart de 14 px, même taille). */
.footer-top{
  display:flex; align-items:flex-start; justify-content:space-between; gap:30px;
  padding-inline:var(--bord);
  margin-bottom:var(--pied-top);
}
.footer-top .hero-links{ width:auto; height:auto; justify-content:flex-end; margin-top:0; padding:0; }
.footer-grid{ display:grid; grid-template-columns:1fr 1fr; gap:40px; align-items:start; }
.contact h3{
  font-size:clamp(26px,3vw,48px); line-height:1.12; font-weight:400; letter-spacing:-.02em;
  margin:0 0 max(16px,.4em); max-width:16ch;
}
.contact h3 em{ font-style:normal; color:var(--muted); }
/* Titre puis phrase, à la même taille, la phrase en gris : l'allure de l'ancien
   « On serait ravis d'échanger. Que vous ayez… » (15/09). */
.contact h3:has(+ .contact-phrase){ margin-bottom:0; }
.contact .contact-phrase{
  font-size:clamp(26px,3vw,48px); line-height:1.12; font-weight:400; letter-spacing:-.02em;
  color:var(--muted); margin:0 0 max(16px,.4em); max-width:16ch;
}
.contact .email{
  font-size:clamp(24px,2.6vw,42px); font-weight:500; letter-spacing:-.02em;
  display:inline-block; border-bottom:2px solid var(--ink); padding-bottom:6px;
  transition:opacity .25s;
}
.contact .email:hover{ opacity:.6; }

/* La colonne de droite du pied de page. La maquette l'appelait `.news` et y
   mettait une inscription à une infolettre ; le site y met les liens de
   navigation, sous la classe `.news-block`. Les deux sélecteurs sont listés :
   sans ça le titre « Où me trouver » tombait aux styles par défaut du
   navigateur, seul texte du site à ne pas être dans la charte. */
.news h3, .news-block h3{ font-size:calc(clamp(26px,3.2vw,42px) * var(--tj-heads)); font-weight:600; letter-spacing:-.03em; line-height:1; margin:0 0 12px; }
.news .sub, .news-block .sub{ font-family:'DM Mono',monospace; font-size:14px; color:var(--muted); margin:0 0 var(--corps); }
.field{ margin-bottom:12px; }
.field input{
  width:100%; background:none; border:none; border-bottom:1px solid var(--line);
  padding:14px 2px; font-family:inherit; font-size:18px; color:var(--ink);
  transition:border-color .3s;
}
.field input::placeholder{ color:var(--muted); }
.field input:focus{ outline:none; border-color:var(--ink); }
.send{
  width:100%; margin-top:8px; background:var(--ink); color:var(--bg);
  border:none; border-radius:12px; padding:22px; cursor:pointer;
  font-family:'DM Mono',monospace; font-size:14px; letter-spacing:.12em; text-transform:uppercase;
  transition:transform .3s var(--ease), background .3s;
}
.send:hover{ transform:translateY(-2px); background:#000; }
.send.sent{ background:var(--c-green); color:var(--ink); }

.footer-bottom{
  display:flex; align-items:center; justify-content:space-between; gap:40px;
  margin-top:var(--pied-ecart); padding-top:var(--corps); border-top:1px solid var(--line);
  flex-wrap:wrap;
}
.footnav{ display:flex; gap:clamp(20px,3vw,44px); }
.footnav a{ font-size:16px; color:var(--ink-soft); transition:color .25s; }
.footnav a:hover{ color:var(--ink); }
.footer-bottom .copy{ font-family:'DM Mono',monospace; font-size:13px; color:var(--muted); }

/* ============================================================
   SCROLL REVEAL
   ============================================================ */
/* ---- Apparition au scroll, calée sur Bungee ------------------------------------
   Les trois animations « appear » de Framer relevées le 12 septembre 2026
   (docs/superpowers/specs/mesures_bungee/animations_bungee.md), sans cascade :
   - data-reveal           un bloc de texte monte de 40 px (ressort doux, bounce 0.2)
   - data-reveal="fondu"   une image apparaît (ressort doux, sur l'opacité)
   - data-reveal="chute"   le nom dessiné descend de 40 px (ressort vif, bounce 0.6)
   Les courbes sont le générateur `spring` de motion-dom 12 (keyframes [0, 1])
   échantillonné en 49 points : dépassement de 1,5 % pour le doux, 25 % pour le
   vif. Sans linear(), une courbe sans rebond prend le relais.
   Durées de Bungee (1 s, fondu 2 s, chute 1,4 s), mais sans l'attente de 0,4 s
   avant le départ : le mouvement part dès que le bloc entre à l'écran (demande
   de Félix, 13 septembre 2026). Comme sur Bungee, le réglage système
   « Réduire les animations » n'arrête pas les apparitions (son choix, même date).

   16/09 — « ça tremble quand ça arrive à la position finale » (Félix).
   Mesuré au navigateur (logs/sonde_tremblement.cjs, relevé de `transform` frame
   par frame) : sur un bloc de texte, le ressort doux passe sous le pixel dès
   t = 419 ms puis met encore 583 ms — 36 frames sur 61 — à traverser 35 positions
   sous-pixel distinctes ; une seule frame sur 61 tombe sur un pixel entier, et le
   dépassement culmine à 0,608 px. À 40 px de course, le rebond de 1,5 % est donc
   entièrement sous le pixel : il ne peut pas se voir comme un rebond, seulement
   comme un frémissement, parce qu'aucun [data-reveal] n'a de calque de
   composition (vérifié : LayerTree vide) et que le texte est donc re-rastérisé à
   chaque nouvelle fraction de pixel. Le ressort doux est retiré : la courbe
   maison, déjà le repli sans linear(), est monotone, sans dépassement, et sa
   traîne sous le pixel tombe de 583 à 250 ms.
   Le ressort vif ne sert qu'au nom dessiné du hero (une image, un seul élément) :
   son dépassement de 25 % fait 10 px, un vrai rebond, voulu — il est gardé, et
   l'élément reçoit un calque (`will-change`) pour que sa traîne sous-pixel soit
   composée et non re-rastérisée, comme .strip-piste et .post .frame img. */
:root{
  --ressort-doux: cubic-bezier(.22,.61,.36,1);
  --ressort-vif:  cubic-bezier(.22,.61,.36,1);
}
@supports (transition-timing-function: linear(0, 1)){
  :root{
    --ressort-vif: linear(0, 0.0458, 0.1651, 0.331, 0.5186, 0.7064, 0.878, 1.022, 1.1317, 1.2054, 1.2445, 1.2535, 1.2381, 1.2053, 1.1618, 1.1138, 1.0666, 1.0241, 0.989, 0.9627, 0.9455, 0.937, 0.9359, 0.9407, 0.9497, 0.961, 0.9732, 0.9851, 0.9956, 1.0041, 1.0104, 1.0143, 1.0162, 1.0161, 1.0147, 1.0123, 1.0094, 1.0063, 1.0033, 1.0007, 0.9986, 0.9971, 0.9962, 0.9959, 0.9959, 0.9964, 0.997, 0.9978, 1);
  }
}
[data-reveal]{ opacity:1; transform:none; }
html.js [data-reveal]{
  opacity:0; transform:translateY(40px);
  transition:opacity 1s var(--ressort-doux) 0s, transform 1s var(--ressort-doux) 0s;
}
html.js [data-reveal="fondu"]{
  transform:none;
  transition:opacity 2s var(--ressort-doux) 0s;
}
html.js [data-reveal="chute"]{
  transform:translateY(-40px);
  transition:opacity 1.4s var(--ressort-vif) 0s, transform 1.4s var(--ressort-vif) 0s;
  /* 16/09 : un seul élément sur tout le site (le nom dessiné du hero). Son
     ressort finit par 1,2 s de traîne sous le pixel avec 3 changements de sens ;
     sur son propre calque, le compositeur la joue sans re-rastériser l'image. */
  will-change:transform;
}
html.js [data-reveal].in{ opacity:1; transform:none; }

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

/* ============================================================
   RESPONSIVE
   ============================================================ */
@media (max-width:900px){
  .proj-grid{ grid-template-columns:1fr; }
  .stats-grid{ grid-template-columns:1fr 1fr; gap:var(--chiffres) var(--grille); }
  .testi-card{ grid-template-columns:1fr; }
  .testi-photo{ aspect-ratio:1/1; }
  .faq-grid{ grid-template-columns:1fr; gap:var(--items); }
  .footer-grid{ grid-template-columns:1fr; gap:40px; }
}

/* ============================================================
   BOTTOM BLUR BAR — fixed, follows scroll
   ============================================================ */
.bottom-blur{
  position:fixed;
  bottom:0; left:0; right:0;
  height:160px;
  pointer-events:none;
  z-index:60;
  /* Disparaît quand le pied de page entre dans la fenêtre (app.js, 15/09). */
  transition:opacity .5s ease;

  /* progressive blur: heavy at bottom, fades to nothing at top */
  -webkit-backdrop-filter:blur(18px) saturate(1.4);
  backdrop-filter:blur(18px) saturate(1.4);

  /* mask: full blur at bottom edge, transparent at top */
  -webkit-mask:linear-gradient(to top,
    rgba(0,0,0,1)   0%,
    rgba(0,0,0,.9)  25%,
    rgba(0,0,0,.55) 60%,
    rgba(0,0,0,0)   100%
  );
  mask:linear-gradient(to top,
    rgba(0,0,0,1)   0%,
    rgba(0,0,0,.9)  25%,
    rgba(0,0,0,.55) 60%,
    rgba(0,0,0,0)   100%
  );
}

.bottom-blur.pied-visible{ opacity:0; }

/* Section visibility */
.tj-hidden{ display:none !important; }

/* Scroll FX off */
body.no-fx [data-reveal]{
  opacity:1 !important; transform:none !important; transition:none !important;
}

/* Spacing presets — only override --gut and key section padding */
body.sp-dense{ --gut: calc(var(--gut-base) * .65); }
body.sp-airy { --gut: calc(var(--gut-base) * 1.45); }

body.sp-dense main > section,
body.sp-dense main > footer{
  padding-top:    calc(var(--_pt, 0px) * .6);
  padding-bottom: calc(var(--_pb, 0px) * .6);
}
body.sp-airy main > section,
body.sp-airy main > footer{
  padding-top:    calc(var(--_pt, 0px) * 1.5);
  padding-bottom: calc(var(--_pb, 0px) * 1.5);
}

/* Services fade zone — full-width, clips gradient at carousel height */
.svc-fade-zone{
  position:relative;
  overflow:hidden;
  margin-inline:calc(var(--gut) * -1);
  padding-inline:var(--gut);
}
/* Les fondus couleur de fond, mêmes dégradé et largeur que les bords du hero.
   app.js allume `fondu-gauche` dès qu'il reste des services à gauche,
   `fondu-droite` tant qu'il en reste à droite. La flèche passe au-dessus.
   16/09 : retour aux valeurs d'avant la tâche 3 — Félix trouve le fondu élargi
   « trop grand ». La tâche 3 l'avait ancré au bord du rail (`left:var(--gut)`) et
   rendu plein jusqu'à 35 % ; il repart du bord de la zone, avec les quatre arrêts
   d'origine (1 / .85 / .18 / 0), qui l'éteignent bien plus tôt. La largeur,
   `min(180px, 14vw)`, n'avait pas changé et ne change pas. */
.svc-fade-zone::before,
.svc-fade-zone::after{
  content:""; position:absolute; top:0; bottom:0; width:min(180px, 14vw);
  z-index:2; pointer-events:none; opacity:0; transition:opacity .35s;
}
.svc-fade-zone::before{
  left:0;
  background:linear-gradient(to right, rgba(255,251,245,1) 0%, rgba(255,251,245,.85) 45%, rgba(255,251,245,.18) 80%, rgba(255,251,245,0) 100%);
}
.svc-fade-zone::after{
  right:0;
  background:linear-gradient(to left, rgba(255,251,245,1) 0%, rgba(255,251,245,.85) 45%, rgba(255,251,245,.18) 80%, rgba(255,251,245,0) 100%);
}
.svc-fade-zone.fondu-gauche::before,
.svc-fade-zone.fondu-droite::after{ opacity:1; }

/* Reveal image-slot controls outside clipped frames */
.proj .frame:has(image-slot[data-filled]:hover),
.proj .frame:has(image-slot[data-reframe]),
.post .frame:has(image-slot[data-filled]:hover),
.post .frame:has(image-slot[data-reframe]),
.reel-frame:has(image-slot[data-filled]:hover),
.reel-frame:has(image-slot[data-reframe]),
.testi-photo:has(image-slot[data-filled]:hover),
.testi-photo:has(image-slot[data-reframe]){
  overflow:visible;
}
/* Trois lignes orphelines traînaient ici, reste d'un copier-coller de
   `.svc-fade-zone`. Un parseur CSS qui rencontre des déclarations hors bloc
   avale la règle suivante en cherchant son accolade : `.projects` était donc
   perdue, et la section projets de l'accueil ne recevait aucun rythme. */
.projects{ --_pt:80px; --_pb:80px; }
.services{ --_pt:76px; --_pb:76px; }
.reel    { --_pt:70px; --_pb:86px; }
.stats   { --_pt:80px; --_pb:80px; }
.testi   { --_pt:80px; --_pb:80px; }
.faq     { --_pt:100px; --_pb:100px; }
.journal { --_pt:80px; --_pb:80px; }
.footer  { --_pt:80px; --_pb:80px; }
@media (max-width:560px){
  .stats-grid{ grid-template-columns:1fr; }
  .svc{ flex-basis:78%; }
  /* La colonne de 256 px élargirait la carte au-delà de 78 %. Sur 199 px, aucune
     largeur ne met les douze textes sur le même nombre de lignes (6 ou 7) : la
     hauteur de 7 lignes est réservée pour que les titres restent alignés. */
  .svc p{ width:auto; min-height:calc(7 * 1lh); }
}

/* ---- Transition entre pages, calée sur Bungee ------------------------------------
   La page qui part remonte de 30 px et s'efface presque (opacité 0,1), la page qui
   arrive apparaît en fondu : 0,5 s, cubic-bezier(1, 0, .5, 1), relevé sur Framer.
   View Transitions de document à document : Chrome et Safari la jouent, Firefox
   change de page sans transition. La barre reste en place. */
@view-transition { navigation: auto; }
::view-transition-old(root){ animation: fj-sortie .5s cubic-bezier(1,0,.5,1) both; }
::view-transition-new(root){ animation: fj-entree .5s cubic-bezier(1,0,.5,1) both; }
@keyframes fj-sortie{ to{ opacity:.1; transform:translateY(-30px); } }
@keyframes fj-entree{ from{ opacity:0; } }
