/* ==========================================================================
   FAB — Design system web « sticker / cartoon premium » (DA 2026-08)
   Fond crème chaud, bleu roi saturé, yeux googly, bulles de dialogue,
   display Baloo 2 + corps Outfit. Une seule feuille partagée par toutes
   les pages (FR/EN + 8 langues), cache-friendly, éditable via Cyberduck.
   Échelle φ 2026-08-08 : cf. tokens --fib-N / --fs-N + charte §9.
   ========================================================================== */

/* ---- Reset ---- */
*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .001ms !important; animation-iteration-count: 1 !important; transition-duration: .001ms !important; }
}
img, svg, video { display: block; max-width: 100%; height: auto; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; cursor: pointer; background: none; border: none; }
ul { list-style: none; }
:focus-visible { outline: 2px solid var(--blue); outline-offset: 3px; border-radius: 6px; }

/* ---- Tokens ---- */
:root {
  /* Marque — bleu roi + encre chaude */
  /* 🚨 QUATRE VALEURS, PAS HUIT (2026-08-12, « trop de variations de bleu, on
     dirait qu'on s'est trompé de pipette »). La rampe en comptait 8 dont la
     moitié à 4 points de luminosité les unes des autres : un écart invisible
     ne se lit pas comme une intention, il se lit comme de la saleté.
     Chaque marche est maintenant perceptible et fait UN métier :
       47 %  --blue       LES TROIS PLAQUES de la page (plateau social, boîte
                          FAQ, bande App Store) + CTA, liens
       35 %  --blue-ink   texte bleu foncé, survol des boutons, halo encré
       22 %  --blue-deep  fonds profonds : pied de page
     🚨 TROIS MARCHES, UNE SEULE TEINTE (2026-08-12, « la FAQ est hors thème »).
     La coque FAQ portait #173E86, emprunté à la carte de membre du Bilan —
     donc à une MAQUETTE. Mesuré : #173E86 est à 219° de teinte quand --blue et
     --blue-ink sont à 228°. Ce n'était pas un bleu plus sombre, c'était un
     AUTRE bleu, 9° plus froid, posé sur la plus grande surface de la page —
     d'où la pipette qui dérape. Idem --blue-deep (220°) : il reste, mais réservé
     au pied de page, où rien ne le jouxte.
     🚨 ET AUCUNE MARCHE INTERMÉDIAIRE POUR UNE PLAQUE. Corrigé le soir même : la
     FAQ était passée en --blue-ink, ce qui réglait la teinte mais pas la mesure.
     L'alternance de la page va de PLAQUE BLEU ROI à FOND CRÈME — les trois
     plaques prennent donc --blue, sans exception. Une surface qui a besoin de
     descendre d'un cran assombrit sa propre coque (voile noir : la valeur baisse,
     la teinte ne bouge pas) au lieu de piocher un token voisin.
     🚨 Les bleus de l'APP (#0066FF, #1349DD, #2563EB, #0D47AB, navy du Bilan)
     ne comptent PAS dans cette rampe et ne vivent QUE dans `.mock` / `.oc*`.
     Les mélanger aux bleus du site est exactement ce qui a produit le désordre. */
  --blue: #2244CC;
  --blue-ink: #16309B;        /* pressed / texte bleu foncé / hover des boutons */
  --blue-deep: #0E2A61;       /* pied de page (seul emploi) */
  --ink: #201D15;             /* titres — noir chaud */
  --ink-2: #2A2721;           /* corps fort */
  --muted: #6E6655;           /* corps */
  --muted-2: #7A7263;
  --muted-soft: #A29A88;      /* tertiaire */

  /* Pastels chauds (chips / halos / covers) */
  /* 🚨 REMONTÉ AU-DESSUS DU SOL (2026-08-12). #DDE4F8 avait une luminance de
     77,6 % quand le crème de la page en fait 85,0 : la carte pervenche était donc
     plus SOMBRE que le sol sur lequel elle est posée, alors que la carte crème
     (98,2 %) est plus claire. Les deux ne se comportaient pas pareil : l'une
     montait comme du papier, l'autre s'enfonçait comme une plaque encastrée dans
     la carte du théâtre. D'où le « fond bleu » qu'on voyait sur les cartes 2 et 4
     et nulle part ailleurs. Même teinte (224°, à 4° du bleu de marque), luminance
     portée à 88,7 % : entre le sol et le papier. */
  --p-blue: #EEF2FC;
  --p-violet: #E6DFF3;
  --p-orange: #F8DFC2;
  --p-rose: #F7DCD2;
  --p-sky: #D8E9F2;
  --p-green: #DCEBCD;
  --p-yellow: #F5E8C2;

  /* Fonds & surfaces — crème chaud, jamais de blanc pur en fond de page */
  --bg: #F4EDDC;
  --bg-2: #EDE3CC;
  --card: #FFFDF6;
  --card-2: #FAF4E6;
  --card-3: #F6EFDE;
  --border: rgba(34, 68, 204, 0.13);      /* liseré bleu fin */
  --border-2: rgba(34, 68, 204, 0.24);
  --border-warm: rgba(93, 74, 54, 0.14);

  /* Sémantique */
  --green: #16A34A;
  --green-ink: #226B34;
  --error: #D9483B;

  /* Échelle φ (≈1,618 — 2026-08-08). Espacements : Fibonacci (px) ; typo :
     demi-pas ×√φ ≈ 1,272 → 13/16/21/26/34/42/55/68 (+89 display). Valeurs
     en dur dans les règles (poids), tokens = référence. Exception :
     l'intérieur des QuoteCards du hero (valeurs exactes app). */
  --fib-5: 5px; --fib-8: 8px; --fib-13: 13px; --fib-21: 21px;
  --fib-34: 34px; --fib-55: 55px; --fib-89: 89px; --fib-144: 144px;
  --fib-233: 233px; --fib-377: 377px;
  --fs-13: .8125rem; --fs-16: 1rem; --fs-21: 1.3125rem; --fs-26: 1.625rem;
  --fs-34: 2.125rem; --fs-42: 2.625rem; --fs-55: 3.4375rem; --fs-68: 4.25rem;
  --fs-89: 5.5625rem;

  /* Rayons — système « squircle 26 » :
     --radius-object = LE rayon de toutes les cartes-objets (features, blog,
     encarts, CTA banners). --radius-row = rayon serré des rangées de liste
     (FAQ, rangées de liens) — c'est ce qui les distingue des objets.
     Bulles & pills restent des pills ; la maquette garde son rayon device ;
     les icônes providers ont un rayon proportionnel (~41%, façon icône iOS). */
  --radius-object: 26px;
  --radius-row: 13px;
  --r-pill: 999px;
  --r-xl: var(--radius-object);
  --r-card: var(--radius-object);
  --r-md: 16px;
  --r-sm: var(--radius-row);
  --r-xs: 10px;

  /* Ombres douces, chaudes — layered (ambiante bleu froid + contact encre chaude) */
  --sh-sm: 0 1px 2px rgba(32, 29, 21, .05), 0 10px 22px -14px rgba(25, 44, 134, .12);
  --sh-card: 0 1px 2px rgba(32,29,21,.04), 0 14px 30px -16px rgba(25, 44, 134, .16);
  --sh-lg: 0 2px 4px rgba(32,29,21,.05), 0 38px 76px -30px rgba(25, 44, 134, .30);
  --sh-blue: 0 10px 24px -8px rgba(34, 68, 204, .40);
  --sh-sticker: drop-shadow(0 8px 18px rgba(32, 29, 21, .18));

  /* Type — display rounded joyeuse + corps géométrique */
  --fd: 'Baloo 2', 'Outfit', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  --fb: 'Outfit', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;

  --maxw: 1160px;
  --nav-h: 89px;
}

/* ---- Base ---- */
body {
  font-family: var(--fb);
  color: var(--ink-2);
  background: var(--bg);
  line-height: 1.618;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

/* Fond global : crème chaud, halos très diffus bleu + soleil */
body::before {
  content: '';
  position: fixed; inset: 0; z-index: -2; pointer-events: none;
  background:
    radial-gradient(58% 44% at 12% 0%, rgba(34, 68, 204, .07) 0%, transparent 62%),
    radial-gradient(50% 40% at 94% 6%, rgba(245, 232, 194, .8) 0%, transparent 60%),
    radial-gradient(55% 48% at 74% 102%, rgba(34, 68, 204, .055) 0%, transparent 62%),
    var(--bg);
}
/* grain subtil */
body::after {
  content: ''; position: fixed; inset: 0; z-index: -1; pointer-events: none; opacity: .03;
  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.8' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 200px;
}

/* ---- Layout ---- */
.container { width: 100%; max-width: var(--maxw); margin: 0 auto; padding: 0 26px; }
.container-tight { max-width: 800px; }
.section { padding: clamp(55px, 9vw, 144px) 0; position: relative; }
.section-sm { padding: clamp(42px, 6vw, 89px) 0; }
.center { text-align: center; }

/* ---- Type ---- */
h1, h2, h3, h4 { font-family: var(--fd); color: var(--ink); font-weight: 700; line-height: 1.272; letter-spacing: -0.012em; text-wrap: balance; }
.display {
  font-size: clamp(2.625rem, 6.2vw, 5.5625rem);
  font-weight: 800;
  line-height: 1;
  letter-spacing: -0.02em;
}
h2.h-section { font-size: clamp(2.125rem, 4vw, 2.625rem); font-weight: 800; letter-spacing: -0.018em; }
h3 { font-size: clamp(1.3125rem, 2vw, 1.625rem); }
.lead { font-family: var(--fb); font-size: clamp(1rem, 1.5vw, 1.3125rem); color: var(--muted); font-weight: 400; line-height: 1.618; text-wrap: pretty; }
.kicker {
  position: relative;
  display: inline-flex; align-items: center; gap: 8px;
  font-family: var(--fb); font-weight: 700; font-size: .8125rem; letter-spacing: .07em; text-transform: uppercase;
  color: var(--blue); background: var(--card); border: 1.5px solid var(--blue);
  padding: 8px 16px; border-radius: var(--r-pill);
}
/* Queue supprimée (2026-08-08) : les bulles à queue = les 5 verbes du hero, point. */
/* ex-dégradé : désormais bleu roi plein (pas de néon) */
.grad-text {
  background: none;
  -webkit-background-clip: initial; background-clip: initial;
  -webkit-text-fill-color: currentColor;
  color: var(--blue);
}
.muted { color: var(--muted); }
strong, b { font-weight: 600; color: var(--ink); }

/* ---- Yeux googly (logo) ---- */
.brand-eyes {
  width: 37px; height: 34px; border-radius: 0; flex-shrink: 0;
  filter: drop-shadow(0 2px 3px rgba(32,29,21,.22));
  animation: eyes-blink 7s ease-in-out infinite;
  transform-origin: 50% 58%;
}
.fab-eyes {
  display: block;
  filter: var(--sh-sticker);
}
.fab-eyes.blink { animation: eyes-blink 6.4s ease-in-out infinite; transform-origin: 50% 58%; }
@keyframes eyes-blink {
  0%, 94.5%, 100% { transform: scaleY(1); }
  96.6% { transform: scaleY(.08); }
  98.4% { transform: scaleY(1); }
}
.eyes-pupils { transition: transform .18s cubic-bezier(.2,.8,.3,1); will-change: transform; }

/* ---- Lockup de marque « Un trajet, Fab. / The Finest Cab » ---- */
.lockup { display: flex; flex-direction: column; align-items: flex-start; gap: 10px; margin: 21px 0 13px; }
.lockup .fab-eyes { width: clamp(89px, 11vw, 128px); height: auto; }
.lockup-line {
  font-family: var(--fd); font-weight: 800; color: var(--blue);
  font-size: clamp(2.625rem, 5.6vw, 4.25rem); line-height: 1.02; letter-spacing: -0.02em;
}
.lockup-tag {
  position: relative; display: inline-block;
  font-family: var(--fd); font-style: italic; font-weight: 600;
  color: var(--ink); font-size: clamp(1rem, 1.9vw, 1.625rem); line-height: 1.2;
  padding: 0 6px 12px 2px;
}
.lockup-tag .tag-stroke {
  position: absolute; inset-inline-start: 0; bottom: 0; width: 100%; height: 10px; overflow: visible;
}
.lockup-tag .tag-stroke path {
  fill: none; stroke: var(--blue); stroke-width: 4.6; stroke-linecap: round; stroke-linejoin: round;
}

/* Hero H1 SEO restylé : le texte reste, le lockup prend la lumière */
.hero-h1 {
  font-family: var(--fd); font-weight: 700; color: var(--ink);
  font-size: clamp(1.3125rem, 1.9vw, 1.625rem); line-height: 1.272; letter-spacing: 0;
  margin: 5px 0 13px;
}
.hero-h1 br { display: none; }

/* ---- Bulles de dialogue (motif signature) ---- */
.bubble {
  position: relative;
  display: inline-flex; align-items: center; gap: 8px;
  font-family: var(--fd); font-weight: 700; font-size: 1rem; line-height: 1.1;
  padding: 11px 21px 13px; border-radius: var(--r-pill);
  white-space: nowrap;
}
.bubble::after {
  content: ''; position: absolute; bottom: -5.5px; inset-inline-start: 22px;
  width: 12px; height: 12px; background: inherit;
  transform: rotate(45deg); border-radius: 0 0 3.5px 0;
}
.bubble--solid { background: var(--blue); color: #fff; box-shadow: 0 6px 16px -8px rgba(34,68,204,.5); }
.bubble--outline { background: var(--card); border: 1.5px solid var(--blue); color: var(--blue); }
.bubble--outline::after { border-right: 1.5px solid var(--blue); border-bottom: 1.5px solid var(--blue); }

/* Nuage de bulles (les 5 verbes de la campagne) */
/* Sommaire hero (2026-08-09) : les 5 verbes = PILLS cliquables (queue supprimée,
   plus grosses) qui font défiler vers leur chapitre, sous un voile d'expansion. */
.bubble-cloud { display: flex; flex-wrap: wrap; gap: 13px; margin: 21px 0 26px; max-width: 480px; }
.bubble-cloud .bubble { font-size: clamp(1.1875rem, 1.9vw, 1.625rem); padding: 15px 29px 17px; cursor: pointer; text-decoration: none; transition: transform .25s cubic-bezier(.16,1,.3,1), box-shadow .25s; }
.bubble-cloud .bubble::after { display: none; }
.bubble-cloud .bubble:nth-child(odd) { transform: rotate(-2deg); }
.bubble-cloud .bubble:nth-child(even) { transform: rotate(1.7deg); }
.bubble-cloud .bubble:nth-child(3) { transform: rotate(2.4deg); }
.bubble-cloud .bubble:nth-child(5) { transform: rotate(-1.4deg); }
.bubble-cloud .bubble:hover { transform: rotate(0deg) translateY(-3px); }
.bubble-cloud .bubble--solid:hover { box-shadow: 0 13px 26px -10px rgba(34,68,204,.55); }
.bubble-cloud .bubble--outline:hover { box-shadow: 0 8px 21px -10px rgba(25,44,134,.35); }
.bubble-cloud .bubble:focus-visible { outline: 3px solid var(--blue); outline-offset: 3px; border-radius: var(--r-pill); }
/* voile d'expansion : cercle depuis la pill, couvre le saut, se dissout */
.toc-veil { position: fixed; inset: 0; z-index: 240; pointer-events: none; background: var(--blue); clip-path: circle(0px at var(--x, 50%) var(--y, 50%)); transition: clip-path .48s cubic-bezier(.3, 0, .2, 1); }
.toc-veil--white { background: var(--paper); }
.toc-veil.grow { clip-path: circle(160% at var(--x, 50%) var(--y, 50%)); }
.toc-veil.fade { transition: opacity .55s ease .05s; opacity: 0; }
.toc-arrive { animation: toc-arrive .8s cubic-bezier(.16, 1, .3, 1) both; }
@keyframes toc-arrive { from { transform: scale(.965); opacity: .35; } to { transform: none; opacity: 1; } }
/* Les cinq gestes, FR puis EN, dans l'ordre des cartes. #pourquoi et #why
   sont sortis : ces deux ancres n'existent nulle part (vérifié 2026-08-12). */
#fonctionnement, #choisis, #personnalise, #compare, #organise, #economise,
#how-it-works, #choose, #customise, #plan, #save,
#apps, #amis, #friends, #faq { scroll-margin-top: 89px; }
@media (prefers-reduced-motion: reduce) { .toc-veil { display: none; } .toc-arrive { animation: none; } }

/* ---- Boutons = bulles ---- */
.btn {
  position: relative;
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  font-family: var(--fd); font-weight: 700; font-size: 1rem; line-height: 1.1;
  padding: 16px 26px; border-radius: var(--r-pill);
  transition: transform .18s cubic-bezier(.16,1,.3,1), box-shadow .25s, background .2s, color .2s, border-color .2s;
  white-space: nowrap;
}
/* Queue supprimée (2026-08-08) : les boutons sont des pills simples, la queue est réservée aux 5 bulles verbes du hero. */
.btn-primary { background: var(--blue); color: #fff; box-shadow: var(--sh-blue); }
.btn-primary:hover { background: var(--blue-ink); transform: translateY(-2px); box-shadow: 0 16px 32px -10px rgba(34,68,204,.55); }
.btn-ghost { background: var(--card); color: var(--blue); border: 1.5px solid var(--blue); }
.btn-ghost:hover { background: #fff; transform: translateY(-2px); box-shadow: var(--sh-card); }
.btn-lg { padding: 21px 34px; font-size: 1rem; }
.btn-block { width: 100%; }

/* Badge « sources préférées » Google (blog : fin d'article + index) — deeplink, pas de script tiers. 2026-09-03 */
.google-src { display: flex; flex-wrap: wrap; align-items: center; gap: 12px 18px; margin: 34px 0 44px; }
.google-src p { margin: 0; color: #8E8E93; font-size: .95rem; }
.google-src .btn { padding: 12px 20px; font-size: .92rem; white-space: normal; text-align: center; }

/* Boutons stores (badges) — logos officiels : tailles NON φ-isées, on n'y touche pas */
/* 🚨 LES DEUX BADGES SONT UNE PAIRE : ils doivent faire la même taille.
   Ils se dimensionnaient sur leur texte, et les libellés OFFICIELS des deux
   stores ne font pas la même longueur (« Télécharger sur / App Store » contre
   « Disponible sur / Google Play »). Mesuré : 188 contre 206 px dans le hero,
   154 contre 170 au pied et dans le CTA. Empilés au pied, ce bord droit en
   escalier est ce qu'Alex a vu (« ils font pas la même taille en plus »).
   ⚠️ On ne touche PAS aux libellés : ce sont les formulations imposées par
   Apple et Google, localisées dans les 10 langues. C'est la BOÎTE qu'on égalise.
   Grille à colonnes égales dimensionnée sur son contenu : chaque colonne prend
   la largeur du PLUS LARGE, et l'ensemble ne prend que la place qu'il lui faut
   (une grille en `1fr` sans `width: max-content` s'étirerait sur toute la
   largeur du conteneur, ce qui est faux dans le hero comme au pied). */
.stores { display: grid; grid-auto-flow: column; grid-auto-columns: 1fr;
  width: max-content; max-width: 100%; gap: 13px; }
.stores .store-badge { justify-content: center; }
/* 🚨 La paire reste CÔTE À CÔTE au pied. Elle s'y empilait parce que la colonne
   de marque faisait 337 px pour 353 px de paire : ce n'est pas la paire qu'il
   faut casser, c'est la colonne qu'il faut élargir (1,4fr → 1,9fr ci-dessous).
   Elle ne se met sur deux lignes que sur les vraies petites largeurs. */
.store-badge {
  display: inline-flex; align-items: center; gap: 12px;
  background: var(--ink); color: #FFFDF6; padding: 11px 20px 11px 18px; border-radius: 17px;
  transition: transform .18s cubic-bezier(.16,1,.3,1), box-shadow .25s;
  box-shadow: 0 10px 24px -14px rgba(32,29,21,.55); border: 1px solid rgba(255,253,246,.1);
}
.store-badge:hover { transform: translateY(-2px); box-shadow: 0 16px 34px -14px rgba(32,29,21,.5); }
.store-badge svg { width: 26px; height: 26px; flex-shrink: 0; }
/* 🚨 Les deux lignes s'alignent à GAUCHE l'une sous l'autre, toujours. Sans ça
   le badge hérite l'alignement de son contexte : centré dans le hero (qui est
   centré), à gauche au pied — le même composant ne se dessinait pas pareil
   selon l'endroit où on le posait. Les deux badges officiels sont dessinés
   ainsi, sur-titre calé à gauche du nom du store. */
.store-badge .sb-t { display: flex; flex-direction: column; line-height: 1.05; text-align: start; }
.store-badge .sb-t small { font-size: .62rem; font-weight: 500; opacity: .8; letter-spacing: .02em; }
.store-badge .sb-t span { font-size: 1.05rem; font-weight: 600; font-family: var(--fb); }

/* ---- Cartes ---- */
.card {
  background: var(--card); border: 1.5px solid var(--border); border-radius: var(--r-card);
  box-shadow: var(--sh-card); padding: 26px;
}
.card-warm { background: var(--card-2); border-color: var(--border-warm); }

/* ---- Chips / pills / badges ---- */
.pill {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 8px 16px; border-radius: var(--r-pill); font-weight: 700; font-size: .8125rem;
  font-family: var(--fd);
  background: var(--card); border: 1.5px solid var(--border-2); color: var(--blue);
}
.pill--blue { background: var(--p-blue); border-color: transparent; color: var(--blue-ink); }
.pill--violet { background: var(--p-violet); border-color: transparent; color: #5A34B0; }
.pill--orange { background: var(--p-orange); border-color: transparent; color: #96500F; }
.pill--rose { background: var(--p-rose); border-color: transparent; color: #A83A20; }
.badge-cheap {
  display: inline-flex; align-items: center; gap: 6px; font-weight: 700; font-size: .8125rem;
  color: var(--green-ink); background: var(--p-green); padding: 5px 11px; border-radius: var(--r-pill);
}

/* ---- Nav ---- */
.nav {
  position: fixed; top: 0; inset-inline: 0; z-index: 1000; height: var(--nav-h);
  display: flex; align-items: center;
  background: transparent; border-bottom: 1.5px solid transparent;
  transition: border-color .3s, background .3s, box-shadow .3s, backdrop-filter .3s;
}
/* En haut de page la carte du hero passe SOUS la barre (fondateur 2026-08-09) ;
   dès qu'on scrolle, la barre récupère son verre crème pour rester lisible. */
.nav.scrolled { background: rgba(244,237,220,.78); backdrop-filter: saturate(160%) blur(18px); -webkit-backdrop-filter: saturate(160%) blur(18px); border-bottom-color: var(--border); box-shadow: 0 4px 22px -18px rgba(25,44,134,.55); }
/* La barre s'étale sur TOUTE la largeur : le burger colle au bord écran (fondateur). */
.nav .container { display: flex; align-items: center; justify-content: flex-start; gap: 13px; max-width: none; padding: 0 21px; }
/* Nav bar ÎLOT CENTRAL squircle 26 (réf fondateur 2026-08-09) : conteneur
   flottant blanc, wordmark « Fab. » à gauche, liens gras au centre, CTA à
   droite ; la carte du hero passe autour. Burger+drawer survivent <1020px. */
.nav--bar { height: auto; padding-top: 21px; background: transparent; transition: transform .38s cubic-bezier(.16,1,.3,1); }
/* Nav escamotable v2 (2026-08-09, la languette qui coupait les textes = rejetée) :
   scroll vers le BAS = l'îlot sort entièrement de l'écran ; le MOINDRE scroll
   vers le haut le fait revenir (classe .nav-hidden posée par fab.js).
   Jamais caché au focus clavier ni menu langue ouvert. */
.nav--bar.nav-hidden { transform: translateY(-115%); }
.nav--bar.nav-hidden:focus-within, .nav--bar.nav-hidden:has(.lang-open) { transform: none; }
@media (prefers-reduced-motion: reduce) { .nav--bar { transition: none; } }
.nav--bar .container { position: relative; display: block; width: fit-content; max-width: calc(100% - 42px); background: var(--card); border: 1.5px solid var(--border); border-radius: var(--radius-object); filter: drop-shadow(0 2px 3px rgba(32,29,21,.06)) drop-shadow(0 18px 26px rgba(25,44,134,.16)); margin-inline: auto; padding: 0; }
.nav--bar .nav-row { display: flex; align-items: center; gap: 34px; height: 68px; padding: 0 13px 0 34px; }
.nav--bar.scrolled { background: transparent; backdrop-filter: none; -webkit-backdrop-filter: none; border-bottom-color: transparent; box-shadow: none; }
.nav--bar.scrolled .container { filter: drop-shadow(0 3px 5px rgba(32,29,21,.07)) drop-shadow(0 24px 34px rgba(25,44,134,.22)); }
/* MORPH un seul objet (fondateur 2026-08-09 « pas deux blocs ») : le tiroir est
   une RANGÉE de l'îlot ; sa hauteur s'anime par grid-rows 0fr→1fr — une seule
   bordure, un seul rayon, une seule ombre, aucune couture possible. */
.nav--bar .lang-tray { display: grid; grid-template-rows: 0fr; transition: grid-template-rows .34s cubic-bezier(.16,1,.3,1); }
.nav--bar .container.lang-open .lang-tray { grid-template-rows: 1fr; }
.nav--bar .lang-tray .lang-menu { display: grid; position: static; overflow: hidden; min-height: 0; border: none; box-shadow: none; background: none; grid-template-columns: repeat(auto-fit, minmax(152px, 1fr)); gap: 3px; padding: 0 13px; transition: padding .34s cubic-bezier(.16,1,.3,1); }
/* 152 et pas 140 : depuis que les langues s'écrivent dans la langue de la page,
   l'allemand met « Niederländisch » dans la cellule, qui demande 150 px. Mesuré
   langue par langue : au-delà de 160 on perd la cinquième colonne en français,
   dont le menu est le plus étroit (807 px contre 986 en polonais). */
.nav--bar .container.lang-open .lang-tray .lang-menu { padding: 3px 13px 13px; }
.nav--bar .brand { display: none; }
.nav--bar .brand .brand-eyes { display: none; }
.nav--bar .brand .wm { font-family: var(--fd); font-weight: 800; font-size: 1.625rem; line-height: 1; color: var(--blue); }
.nav--bar .brand .wm::after { content: '.'; }

.nav-links { display: flex; align-items: center; gap: 13px; }
.nav-links a { font-family: var(--fb); font-weight: 700; font-size: 1.0625rem; color: var(--ink); padding: 13px 21px; border-radius: 999px; white-space: nowrap; transition: background .2s, color .2s, box-shadow .2s, transform .2s; }
.nav-links a:hover { background: var(--p-blue); box-shadow: var(--sh-sm); transform: translateY(-1px); }
.nav-right { display: flex; align-items: center; gap: 13px; }
@media (min-width: 1020px) { .nav--bar .ham { display: none; } }
@media (max-width: 1019px) {
  .nav-links { display: none; }
  .nav-right .btn-primary { display: none; }
  /* 🚨 Deux ÎLOTS, pas une barre : compactée, la coque pleine largeur n'était
     plus qu'un rectangle blanc vide entre le burger et la langue (vu sur
     iPhone le soir de la mise en ligne, 13/08). La coque devient invisible,
     chaque bout garde la sienne, et le hero respire entre les deux. */
  .nav--bar .container, .nav--bar.scrolled .container { width: calc(100% - 26px); background: transparent; border-color: transparent; filter: none; }
  .nav--bar .nav-row { justify-content: space-between; padding: 0; height: auto; }
  .nav--bar .ham { width: 55px; height: 55px; border-radius: 21px; background: var(--card); border: 1.5px solid var(--border); box-shadow: 0 2px 5px rgba(32,29,21,.08), 0 21px 42px -13px rgba(25,44,134,.28); }
  .nav--bar .lang-btn { background: var(--card); border: 1.5px solid var(--border); padding: 15px 21px; box-shadow: 0 2px 5px rgba(32,29,21,.08), 0 21px 42px -13px rgba(25,44,134,.28); }
  /* le menu langues déplié n'a plus la coque du container : il prend la sienne
     — bordure et fond posés à l'ouverture seulement, sinon la bordure d'un
     élément replié à 0 dessinerait un trait. */
  /* 🚨 Fermeture (2026-08-14, « ça vrille » puis « petit résidu » sur les
     frames d'Alex) : le contenu du tiroir, écrasé par le repli de hauteur
     (.34s), se voyait une poignée de frames comme une LIGNE (fond bleu de
     l'item actif, bords gris). Le remède est double : la coquille-carte vit
     en permanence (bord transparent au repos) au lieu de disparaître à t=0,
     et TOUT le menu fond en .18s — à mi-repli il n'y a déjà plus rien à
     écraser. */
  .nav--bar .lang-tray .lang-menu { border: 1.5px solid transparent; border-radius: var(--radius-object); opacity: 0;
    transition: padding .34s cubic-bezier(.16,1,.3,1), margin .34s cubic-bezier(.16,1,.3,1),
      opacity .18s ease, background .25s ease, border-color .25s ease, box-shadow .25s ease; }
  .nav--bar .container.lang-open .lang-tray .lang-menu { opacity: 1; background: var(--card); border-color: var(--border); margin-top: 8px; padding: 13px; box-shadow: 0 2px 5px rgba(32,29,21,.08), 0 21px 42px -13px rgba(25,44,134,.28); }
}
.brand { display: inline-flex; align-items: center; gap: 10px; }
.brand img:not(.brand-eyes) { width: 30px; height: 30px; border-radius: 8px; }
.brand .wm { font-family: var(--fd); font-weight: 800; font-size: 1.3125rem; letter-spacing: -.02em; color: var(--blue); }
/* Liens inline supprimés (2026-08-08) : la navigation vit dans le drawer latéral. */
.nav-cta { display: flex; align-items: center; gap: 13px; }
.nav .btn-primary { padding: 13px 21px; font-size: 1rem; }
.nav--bar .btn-primary { padding: 13px 26px; font-size: 1.0625rem; font-weight: 700; }

/* language switcher */
.lang { position: relative; }
.lang-btn { display: inline-flex; align-items: center; gap: 8px; font-family: var(--fb); font-weight: 700; font-size: 1.0625rem; color: var(--ink); padding: 13px 18px; border-radius: var(--r-pill); border: none; background: transparent; transition: background .2s, color .2s; }
/* 🚨 UNE FLÈCHE FAITE DE DEUX BORDURES NE SE MET PAS EN LOGIQUE. Le chevron est
   un carré dont on ne garde que deux côtés, tourné de 45°. Avec
   `border-inline-end`, la bordure CHANGE de côté en arabe — mais la rotation,
   elle, est physique et ne change pas : le coin se retrouve à 90° de sa place,
   et le chevron pointait vers le côté au lieu du bas. « Vers le bas » n'est pas
   une direction qui se reflète : c'est `border-right`, dans les deux sens. */
.lang-btn::after { content: ''; width: 7px; height: 7px; border-right: 2px solid currentColor; border-bottom: 2px solid currentColor; transform: rotate(45deg) translateY(-1px); transition: transform .25s cubic-bezier(.16,1,.3,1); }
.lang-btn[aria-expanded="true"]::after { transform: rotate(-135deg) translateY(-2px); }
.lang-btn:hover { background: var(--p-blue); color: var(--blue-ink); }
.lang-btn[aria-expanded="true"] { background: var(--p-blue); color: var(--blue-ink); }
.lang-btn svg { width: 18px; height: 18px; }
.lang-menu {
  position: absolute; inset-inline-end: 0; top: calc(100% + 13px); min-width: 305px;
  background: var(--card); border: none; border-radius: 21px;
  box-shadow: 0 2px 5px rgba(32,29,21,.1), 0 42px 89px -26px rgba(25,44,134,.5);
  padding: 10px; display: none; grid-template-columns: 1fr 1fr; gap: 3px; z-index: 1100;
  transform-origin: top right;
}
.lang-menu.open { display: grid; animation: lang-pop .34s cubic-bezier(.34, 1.56, .64, 1); }
@keyframes lang-pop { from { opacity: 0; transform: translateY(-13px) scale(.92); } }
.lang-menu a { display: flex; align-items: center; gap: 11px; padding: 10px 13px; border-radius: 13px; font-size: .9375rem; font-weight: 600; color: var(--ink-2); transition: background .15s, transform .15s; }
.lang-menu.open a { animation: lang-item .42s cubic-bezier(.34, 1.56, .64, 1) both; }
.lang-menu.open a:nth-child(1) { animation-delay: .02s; } .lang-menu.open a:nth-child(2) { animation-delay: .05s; }
.lang-menu.open a:nth-child(3) { animation-delay: .08s; } .lang-menu.open a:nth-child(4) { animation-delay: .11s; }
.lang-menu.open a:nth-child(5) { animation-delay: .14s; } .lang-menu.open a:nth-child(6) { animation-delay: .17s; }
.lang-menu.open a:nth-child(7) { animation-delay: .2s; }  .lang-menu.open a:nth-child(8) { animation-delay: .23s; }
.lang-menu.open a:nth-child(9) { animation-delay: .26s; } .lang-menu.open a:nth-child(10) { animation-delay: .29s; }
@keyframes lang-item { from { opacity: 0; transform: translateY(8px) scale(.88); } }
.lang-menu a:hover { background: var(--p-blue); color: var(--blue-ink); transform: translateX(2px); }
.lang-menu a .fl { flex: none; font-size: 1.3125rem; line-height: 1; width: 26px; text-align: center; }
.lang-menu a[aria-current="true"] { color: #fff; font-weight: 700; background: var(--blue); }
@media (prefers-reduced-motion: reduce) { .lang-menu.open, .lang-menu.open a { animation: none; } }

/* hamburger */
.ham { display: flex; width: 42px; height: 42px; border-radius: 13px; border: 1.5px solid var(--border-2); align-items: center; justify-content: center; background: rgba(255,253,246,.65); cursor: pointer; }
.ham span { display: block; width: 18px; height: 2px; background: var(--blue-ink); border-radius: 2px; position: relative; transition: .3s; }
.ham span::before, .ham span::after { content: ''; position: absolute; left: 0; width: 18px; height: 2px; background: var(--blue-ink); border-radius: 2px; transition: .3s; }
.ham span::before { top: -6px; } .ham span::after { top: 6px; }
.ham.open span { background: transparent; }
.ham.open span::before { top: 0; transform: rotate(45deg); }
.ham.open span::after { top: 0; transform: rotate(-45deg); }

/* ---- Drawer latéral (navigation, 2026-08-08 — remplace nav-links inline + mobile-menu) ----
   377px (Fibonacci), côté inline-end (droite LTR / gauche RTL), overlay cliquable,
   liens en gros Baloo, CTA en bas. A11y : focus piégé, Esc, aria-expanded (fab.js). */
.drawer-overlay { position: fixed; inset: 0; height: 100vh; height: 100dvh; z-index: 1090; background: rgba(32,29,21,.4); opacity: 0; pointer-events: none; transition: opacity .3s; }
/* 🚨 2026-08-14 (constat device) : min(377px, 100%) couvrait TOUT un écran de
   393 pt — le drawer se lisait comme une page, plus comme un panneau, et
   l'overlay cliquable n'existait plus visuellement. 78vw plafonné à 330 px :
   la page reste visible derrière, on tape à côté pour fermer. */
/* 🚨 height 100dvh (2026-08-14) : même bug de viewport que la sheet-veil —
   `inset-block: 0` s'ancre au viewport de MISE EN PAGE iOS, le panneau
   s'arrêtait au-dessus du bas d'écran et son arrondi bas flottait en l'air.
   Décision (question d'Alex « rond ou droit ? ») : le panneau va désormais
   jusqu'en bas, donc l'arrondi RESTE — un bas carré à mi-air se lirait
   comme un bug de rendu. */
.drawer { position: fixed; inset-block: 0; inset-inline-start: 0; height: 100vh; height: 100dvh; z-index: 1100; width: min(78vw, 330px); background: var(--bg); display: flex; flex-direction: column; gap: 5px; padding: 76px 26px 29px; overflow-y: auto; transform: translateX(-102%); transition: transform .34s cubic-bezier(.16,1,.3,1); box-shadow: 8px 0 55px -21px rgba(25,44,134,.35); border-start-end-radius: 34px; border-end-end-radius: 34px; }
/* squircle demandé par le fondateur (14/08) — panneau étroit, rayon 34 : pas
   le cas « grande surface » interdit par WEB-DESIGN-GUIDELINES §2. */
@supports (corner-shape: squircle) { .drawer { corner-shape: squircle; } }
[dir="rtl"] .drawer { transform: translateX(102%); box-shadow: -8px 0 55px -21px rgba(25,44,134,.35); }
.drawer-open .drawer, [dir="rtl"] .drawer-open .drawer { transform: none; }
.drawer-open .drawer-overlay { opacity: 1; pointer-events: auto; }
body.drawer-open { overflow: hidden; }
.drawer a:not(.btn) { font-family: var(--fd); font-weight: 700; font-size: 1.375rem; line-height: 1.272; color: var(--ink); padding: 12px 5px; border-radius: 13px; }
.drawer a:not(.btn):hover { color: var(--blue-ink); background: rgba(255,253,246,.85); }
.drawer-lang { margin-top: auto; padding-top: 21px; }
.drawer .lang { position: static; width: 100%; }
.drawer .lang-btn { width: 100%; justify-content: center; font-size: 1rem; padding: 13px; border: 1.5px solid var(--border-2); }
.drawer .lang-menu { position: static; width: 100%; margin-top: 8px; box-shadow: none; border: 1.5px solid var(--border-2); }
.drawer .btn-primary { margin-top: 13px; }
/* Rangée sociale en pied de tiroir — la recette de la croix de fermeture
   (pastille 42, radius 13, bordure neutre), poussée en bas par le flex. */
.drawer .socials { display: flex; gap: 13px; margin-top: auto; padding-top: 21px; }
.drawer .socials a { display: inline-flex; align-items: center; justify-content: center;
  width: 42px; height: 42px; padding: 0; border-radius: 13px;
  border: 1.5px solid var(--border-2); background: rgba(255,253,246,.65); color: var(--ink); }
.drawer .socials a:hover { color: var(--blue-ink); background: rgba(255,253,246,.85); }
.drawer .socials svg { width: 20px; height: 20px; }
.drawer-close { position: absolute; top: 21px; inset-inline-end: 21px; width: 42px; height: 42px; border-radius: 13px; border: 1.5px solid var(--border-2); background: rgba(255,253,246,.65); display: flex; align-items: center; justify-content: center; cursor: pointer; color: var(--blue-ink); font-size: 1.3125rem; line-height: 1; }
/* Sans JS : le drawer devient un bloc de liens statique en fin de page — rien n'est perdu. */
@media (scripting: none) {
  .drawer { position: static; transform: none; width: auto; box-shadow: none; padding: 21px 26px; }
  .drawer-close, .drawer-overlay { display: none; }
}

/* ---- Hero ---- */
.hero { padding: calc(var(--nav-h) + 42px) 0 34px; }
.hero-grid { display: grid; grid-template-columns: 1.05fr .95fr; gap: 34px; align-items: center; }
.hero h1 { margin: 21px 0; }
.hero .hero-h1 { margin: 5px 0 13px; }
.hero .lead { max-width: 34ch; margin-bottom: 8px; }
.hero-cta { display: flex; flex-direction: column; gap: 21px; align-items: flex-start; }
.trust { display: flex; align-items: center; gap: 13px; flex-wrap: wrap; color: var(--muted); font-size: .8125rem; font-weight: 500; }

/* ---- Phone mockup (rayon device conservé, hors échelle φ) ---- */
.phone { position: relative; width: 300px; max-width: 78vw; margin: 0 auto; aspect-ratio: 1320 / 2868; }
.phone-frame { position: absolute; inset: 0; background: linear-gradient(150deg,#EBE2CD,#FCF8EE 45%,#E6DCC4); border-radius: 15% / 7%; box-shadow: inset 0 0 0 2px rgba(255,255,255,.75), var(--sh-lg); padding: 2.6%; }
.phone-screen { width: 100%; height: 100%; border-radius: 13% / 6.2%; overflow: hidden; background: #000; box-shadow: inset 0 0 0 2px #17150F; }
.phone-screen img { width: 100%; height: 100%; object-fit: cover; }
.phone-notch { position: absolute; top: 3.2%; left: 50%; transform: translateX(-50%); width: 32%; height: 3.4%; background: #17150F; border-radius: var(--r-pill); z-index: 3; }
.phone-float { position: absolute; z-index: 4; background: var(--card); border-radius: var(--r-md); box-shadow: var(--sh-lg); border: 1.5px solid var(--border); padding: 13px 16px; display: flex; align-items: center; gap: 11px; animation: floaty 6s ease-in-out infinite; }
@keyframes floaty { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-9px); } }

/* ---- Étagère d'apps (providers) ----
   Les 10 icônes posées directement sur le crème, comme sur un écran d'accueil
   iOS : squircle proportionnel (41% ≈ 26px à 64px), lettre + couleur EXACTES
   du registry de l'app (config/providers.ts), ombre teintée par la marque.
   Pas de boîte carte autour, pas d'étiquette répétée — le nom suffit. */
.app-shelf {
  display: flex; flex-wrap: wrap; justify-content: center; align-items: flex-start;
  gap: 21px 26px; padding-top: 5px; margin-inline: auto;
}
.shelf-app { display: flex; flex-direction: column; align-items: center; gap: 10px; width: 80px; }
.shelf-app:nth-child(even) { transform: translateY(7px); }
.shelf-icon {
  --pc: var(--blue);
  width: 64px; height: 64px; border-radius: 41%;
  display: flex; align-items: center; justify-content: center;
  font-family: var(--fd); font-weight: 800; font-size: 2.125rem; line-height: 1; color: #fff;
  background: var(--pc);
  background: linear-gradient(160deg,
    color-mix(in srgb, var(--pc) 84%, #fff) 0%,
    var(--pc) 55%,
    color-mix(in srgb, var(--pc) 86%, #000) 100%);
  box-shadow: 0 12px 24px -12px rgba(25, 44, 134, .35);
  box-shadow:
    inset 0 1px 1px rgba(255, 255, 255, .34),
    inset 0 -1px 1px rgba(32, 29, 21, .22),
    0 2px 3px color-mix(in srgb, var(--pc) 22%, rgba(25, 44, 134, .06)),
    0 14px 26px -12px color-mix(in srgb, var(--pc) 52%, rgba(25, 44, 134, .18));
  transition: transform .22s cubic-bezier(.16,1,.3,1), box-shadow .25s;
}
.shelf-icon--2 { font-size: 1.625rem; letter-spacing: -.02em; }
.shelf-name { font-weight: 600; font-size: .8125rem; color: var(--ink); line-height: 1.2; text-align: center; }
@media (hover: hover) {
  .shelf-app:hover .shelf-icon {
    transform: translateY(-4px);
    box-shadow:
      inset 0 1px 1px rgba(255, 255, 255, .34),
      inset 0 -1px 1px rgba(32, 29, 21, .22),
      0 3px 5px color-mix(in srgb, var(--pc) 26%, rgba(25, 44, 134, .08)),
      0 20px 34px -12px color-mix(in srgb, var(--pc) 60%, rgba(25, 44, 134, .22));
  }
}
/* en dessous d'une rangée de 10, l'étagère se plie proprement en 5 + 5 */
@media (max-width: 1119px) {
  .app-shelf { max-width: 560px; }
}
/* colonne étroite (comparateur) : jamais de rangée bancale 7 + 3 */
.container-tight .app-shelf { max-width: 560px; }

/* ---- Feature rows ---- */
.feature { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(34px,5vw,68px); align-items: center; }
.feature.rev .feature-media { order: -1; }
.feature + .feature { margin-top: clamp(55px, 8vw, 120px); }
.feature-media { display: flex; justify-content: center; }
.icon-badge { width: 55px; height: 55px; border-radius: 16px; background: var(--p-blue); display: flex; align-items: center; justify-content: center; margin-bottom: 21px; }
.icon-badge svg { width: 26px; height: 26px; color: var(--blue); }
.feature h3 { font-size: clamp(1.625rem, 2.6vw, 2.125rem); margin-bottom: 13px; }

/* ---- Steps ---- */
.steps { display: grid; grid-template-columns: repeat(3,1fr); gap: 21px; counter-reset: s; }
.step { position: relative; background: var(--card); border: 1.5px solid var(--border); border-radius: var(--r-card); padding: 34px 26px; box-shadow: var(--sh-sm); }
.step::before { counter-increment: s; content: counter(s); position: absolute; top: 21px; inset-inline-end: 26px; font-family: var(--fd); font-weight: 800; font-size: 2.625rem; color: rgba(34,68,204,.16); line-height: 1; }
.step h3 { font-size: 1.3125rem; margin: 13px 0 8px; }

/* ---- Value cards ---- */
.grid-cards { display: grid; grid-template-columns: repeat(3, 1fr); gap: 21px; }
.vcard { background: var(--card); border: 1.5px solid var(--border); border-radius: var(--r-card); padding: 26px; box-shadow: var(--sh-sm); transition: transform .2s, box-shadow .25s, border-color .25s; }
.vcard:hover { transform: translateY(-4px); box-shadow: var(--sh-card); border-color: var(--border-2); }
.vcard .icon-badge { margin-bottom: 16px; }
.vcard.v-violet .icon-badge { background: var(--p-violet); } .vcard.v-violet .icon-badge svg { color: #5A34B0; }
.vcard.v-orange .icon-badge { background: var(--p-orange); } .vcard.v-orange .icon-badge svg { color: #96500F; }
.vcard.v-green .icon-badge { background: var(--p-green); } .vcard.v-green .icon-badge svg { color: var(--green-ink); }
.vcard.v-rose .icon-badge { background: var(--p-rose); } .vcard.v-rose .icon-badge svg { color: #A8342C; }
.vcard.v-sky .icon-badge { background: var(--p-sky); } .vcard.v-sky .icon-badge svg { color: #14618E; }
.vcard h3 { font-size: 1.3125rem; margin-bottom: 8px; }
.vcard p { color: var(--muted); font-size: 1rem; }

/* ---- CTA band ---- */
.cta-band { background: var(--blue); border-radius: var(--r-xl); padding: clamp(42px,6vw,68px); color: #fff; text-align: center; position: relative; overflow: hidden; box-shadow: 0 30px 60px -24px rgba(34,68,204,.55); }
.cta-band::before { content: ''; position: absolute; inset: 0; background: radial-gradient(55% 65% at 18% 0%, rgba(255,255,255,.16), transparent 60%), radial-gradient(45% 60% at 88% 105%, rgba(23,48,155,.85), transparent 60%); pointer-events: none; }
.cta-band .cta-eyes { width: 74px; height: auto; margin: 0 auto 21px; position: relative; filter: drop-shadow(0 8px 16px rgba(15,26,80,.45)); animation: eyes-blink 6.4s ease-in-out infinite; transform-origin: 50% 58%; }
.cta-band h2 { color: #fff; position: relative; }
.cta-band p { color: rgba(255,255,255,.92); position: relative; }
.cta-band .stores { margin: 26px auto 0; position: relative; }
.cta-band .store-badge { background: #FFFDF6; color: var(--ink); border-color: transparent; }
/* LA PREUVE EN DERNIER (fondateur 2026-08-11) : les étoiles + la note réelle
   quittent le 3e chapitre du voyage pour s'installer dans la bande bleue, juste
   au-dessus des boutons — c'est la dernière chose lue avant de cliquer. */
.cta-band .cta-stars { justify-content: center; margin: 0 auto 13px; position: relative; }
.cta-band .cta-stars svg { width: 26px; height: 26px;
  filter: drop-shadow(0 3px 8px rgba(15, 26, 80, .45)); }
.cta-band .cta-eyes { margin-bottom: 16px; }
/* le point d'accent est bleu : sur du bleu il disparaît */
.cta-band .dot-blue { color: #FFFDF6; }


/* ---- FAQ accordion ---- */
.faq-list { display: flex; flex-direction: column; gap: 13px; }
.faq-item { background: var(--card); border: 1.5px solid var(--border); border-radius: var(--radius-row); overflow: hidden; box-shadow: var(--sh-sm); transition: border-color .25s; }
.faq-item:hover, .faq-item.open { border-color: var(--border-2); }
.faq-q { width: 100%; display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 21px 26px; text-align: start; font-family: var(--fb); font-weight: 600; font-size: 1rem; color: var(--ink); }
.faq-q .chev { flex-shrink: 0; width: 21px; height: 21px; color: var(--blue); transition: transform .3s cubic-bezier(.16,1,.3,1); }
.faq-item.open .faq-q .chev { transform: rotate(180deg); }
.faq-a { max-height: 0; overflow: hidden; transition: max-height .35s cubic-bezier(.16,1,.3,1); }
.faq-a-inner { padding: 0 26px 21px; color: var(--muted); font-size: 1rem; line-height: 1.618; }
.faq-a-inner a { color: var(--blue); font-weight: 500; }

/* ---- Blog ---- */
.blog-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 26px; }
.post-card { display: flex; flex-direction: column; background: var(--card); border: 1.5px solid var(--border); border-radius: var(--r-card); overflow: hidden; box-shadow: var(--sh-sm); transition: transform .2s, box-shadow .25s, border-color .25s; height: 100%; }
.post-card:hover { transform: translateY(-4px); box-shadow: var(--sh-card); border-color: var(--border-2); }
.post-cover { aspect-ratio: 16/10; background: var(--p-blue); display: flex; align-items: center; justify-content: center; }
.post-cover.c-2 { background: var(--p-orange); }
.post-cover.c-3 { background: var(--p-green); }
.post-cover .em { font-size: 2.625rem; filter: drop-shadow(0 4px 8px rgba(32,29,21,.15)); }
.post-body { padding: 21px 26px 26px; display: flex; flex-direction: column; gap: 10px; flex: 1; }
.post-body .tag { font-size: .8125rem; font-weight: 700; text-transform: uppercase; letter-spacing: .05em; color: var(--blue); }
.post-body h3 { font-size: 1.3125rem; line-height: 1.272; }
.post-body p { color: var(--muted); font-size: 1rem; flex: 1; }
.post-body .rd { font-weight: 700; color: var(--blue); font-size: .8125rem; }

/* ---- Article (blog post / legal) ---- */
.article { max-width: 760px; margin: 0 auto; }
.article-head { text-align: center; padding: calc(var(--nav-h) + 34px) 0 21px; }
.article-head .meta { color: var(--muted-soft); font-size: .8125rem; font-weight: 500; margin-top: 13px; }
.prose { font-size: 1rem; line-height: 1.618; color: #3A362C; }
.prose h2 { font-size: clamp(1.625rem,2.6vw,2.125rem); margin: 42px 0 16px; }
.prose h3 { font-size: 1.3125rem; margin: 34px 0 13px; }
.prose p { margin-bottom: 16px; }
.prose ul, .prose ol { margin: 0 0 16px 1.2em; }
.prose ul { list-style: disc; } .prose ol { list-style: decimal; }
.prose li { margin-bottom: 8px; }
.prose a { color: var(--blue); font-weight: 500; text-decoration: underline; text-underline-offset: 3px; }
.prose strong { color: var(--ink); }
.prose blockquote { border-inline-start: 4px solid var(--blue); background: var(--card); padding: 16px 21px; border-radius: 0 var(--r-sm) var(--r-sm) 0; margin: 0 0 21px; color: var(--ink-2); box-shadow: var(--sh-sm); }
.prose table { width: 100%; border-collapse: collapse; margin: 0 0 21px; font-size: 1rem; }
.prose th, .prose td { text-align: start; padding: 13px; border-bottom: 1px solid var(--border); }
.prose th { font-weight: 600; color: var(--ink); background: var(--card-2); }
.table-wrap { overflow-x: auto; border-radius: var(--r-sm); border: 1.5px solid var(--border); margin-bottom: 21px; }
.table-wrap table { margin: 0; }

/* breadcrumb */
.crumbs { font-size: .8125rem; color: var(--muted-soft); font-weight: 500; margin-bottom: 5px; }
.crumbs a { color: var(--muted); } .crumbs a:hover { color: var(--blue); }

/* ---- Footer — bleu roi profond ---- */
.footer { background: var(--blue-deep); color: #E9E4D5; padding: 55px 0 34px; margin-top: 34px; }
.footer .container { display: grid; grid-template-columns: minmax(0,1.9fr) 1fr 1fr 1fr; gap: 34px; }
/* Les huit autres langues n'ont ni FAQ ni blog traduits : leur pied compte trois
   colonnes, pas quatre. Sans cette règle la quatrième colonne reste vide et la
   marque se retrouve écrasée à gauche. */
.footer .container.fcols-3 { grid-template-columns: minmax(0,1.9fr) 1fr 1fr; }
.footer .brand .wm { color: #FFFDF6; }
.footer .brand-eyes { filter: drop-shadow(0 3px 6px rgba(10,18,60,.5)); }
/* margin-top 11 (2026-08-14, constat device toutes langues) : les titres
   PRODUIT/FAB démarraient 7 px PLUS HAUT que le wordmark « Fab » — l'œil
   lisait un déraillement. 11 px aligne les centres optiques des deux lignes
   (wordmark 26 px de haut, titre 17). */
.footer h4 { font-family: var(--fb); color: #FFFDF6; font-size: .8125rem; text-transform: uppercase; letter-spacing: .08em; margin-top: 11px; margin-bottom: 16px; font-weight: 700; }
.footer a { color: rgba(240,235,220,.72); font-size: 1rem; display: block; padding: 5px 0; transition: color .2s; }
.footer a:hover { color: #fff; }
/* Rangée sociale de la colonne marque — icônes sobres dans la teinte des liens. */
.footer .socials { display: flex; gap: 13px; margin-top: 16px; }
.footer .socials a { display: inline-flex; align-items: center; justify-content: center;
  width: 42px; height: 42px; padding: 0; border-radius: 14px;
  border: 1px solid rgba(240,235,220,.21); color: rgba(240,235,220,.72);
  transition: color .2s, border-color .2s; }
.footer .socials a:hover { color: #fff; border-color: rgba(255,255,255,.55); }
.footer .socials svg { width: 20px; height: 20px; }
.footer .fdesc { color: rgba(240,235,220,.68); font-size: 1rem; max-width: 34ch; margin: 13px 0 21px; }
.footer .stores .store-badge { display: inline-flex; padding: 11px 20px 11px 18px; background: #FFFDF6; color: var(--ink); border-color: transparent; box-shadow: 0 10px 24px -14px rgba(10,18,60,.7); flex-shrink: 0; }
.footer > .container:last-of-type { display: block; }
.footer-bottom { border-top: 1px solid rgba(255,253,246,.16); margin-top: 44px; padding-top: 26px; display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; color: rgba(240,235,220,.6); font-size: .8125rem; }
.footer-bottom .fl-langs { display: flex; flex-wrap: wrap; gap: 2px; }
.footer-bottom .fl-langs a { color: rgba(240,235,220,.6); padding: 8px 8px; margin: -8px 0; }
.footer-bottom .fl-langs a:hover { color: #fff; }
/* Où l'on se trouve. Le menu du haut le dit avec une pastille bleue ; en bas,
   sur le navy, la même idée en clair — assez pour se repérer, assez discret
   pour ne pas transformer le bandeau en rangée de boutons. */
.footer-bottom .fl-langs a[aria-current] { color: #FFFDF6; font-weight: 700;
  background: rgba(255,253,246,.14); border-radius: 999px; padding: 8px 11px; }

/* ---- Reveal on scroll ---- */
/* 🚨 Resserré le 13/08 (avec le pré-déclenchement de l'observer dans fab.js) :
   21px/.89s + délais jusqu'à .55s laissaient du vide au scroll rapide mobile.
   L'entrée reste douce, elle ne fait plus attendre. */
.reveal { opacity: 0; transform: translateY(13px); transition: opacity .34s cubic-bezier(.16,1,.3,1), transform .55s cubic-bezier(.16,1,.3,1); }
.reveal.in { opacity: 1; transform: none; }
.reveal.d1 { transition-delay: .08s; } .reveal.d2 { transition-delay: .13s; } .reveal.d3 { transition-delay: .21s; } .reveal.d4 { transition-delay: .34s; }
/* Sécurité no-JS : ne jamais masquer le contenu si le script ne tourne pas */
@media (scripting: none) { .reveal { opacity: 1 !important; transform: none !important; } }
.no-js .reveal { opacity: 1; transform: none; }

/* ---- Divider label ---- */
.eyebrow { text-align: center; margin-bottom: 13px; }
.section-head { max-width: 640px; margin: 0 auto clamp(34px,5vw,55px); text-align: center; }
.section-head .lead { margin-top: 16px; }

/* ---- Utilities ---- */
.mt-s { margin-top: 13px; } .mt-m { margin-top: 26px; } .mt-l { margin-top: 44px; }
.nowrap { white-space: nowrap; }
/* chiffres tabulaires partout où des prix s'alignent (maquette, badges, tableaux) */
.phone-float, .badge-cheap, .pill, .prose table { font-variant-numeric: tabular-nums; }
.hide-mobile { }

/* ---- RTL (Arabic) ---- */
[dir="rtl"] .step::before { inset-inline-end: auto; inset-inline-start: 26px; }
[dir="rtl"] .trust, [dir="rtl"] .hero-cta { align-items: flex-end; }
[dir="rtl"] .lockup { align-items: flex-end; }
[dir="rtl"] .lockup-tag { padding: 0 2px 12px 6px; }

/* ---- Responsive ---- */
@media (max-width: 960px) {
  .hero-grid { grid-template-columns: 1fr; text-align: center; gap: 34px; }
  .hero .lead { margin-inline: auto; }
  .hero-cta { align-items: center; }
  .hero-media { order: -1; }
  .lockup { align-items: center; }
  [dir="rtl"] .lockup { align-items: center; }
  .bubble-cloud { justify-content: center; margin-inline: auto; }
  [dir="rtl"] .trust, [dir="rtl"] .hero-cta { align-items: center; }
  .feature { grid-template-columns: 1fr; text-align: center; gap: 26px; }
  .feature.rev .feature-media { order: 0; }
  .feature .icon-badge { margin-inline: auto; }
  .steps { grid-template-columns: 1fr; }
  .grid-cards { grid-template-columns: 1fr 1fr; }
  .blog-grid { grid-template-columns: 1fr 1fr; }
  /* 🚨 `1fr` vaut `minmax(auto, 1fr)` : la colonne ne peut pas descendre sous
     son contenu. La paire de badges (352 px) la forçait donc à 352 px et
     poussait la grille hors du conteneur (débordement masqué par
     l'`overflow-x: hidden` global, donc invisible mais bien réel). Dès que le
     pied passe à deux colonnes, la paire s'empile — et `minmax(0,1fr)` autorise
     enfin les colonnes à se resserrer. */
  /* 🚨 fcols-3 aussi (2026-08-14) : les pieds des 8 langues portent
     `.fcols-3` (0,3,0) qui BATTAIT cet override (0,2,0) — ils gardaient
     3 colonnes squelettiques en mobile (un mot par ligne en allemand)
     pendant que le FR passait à 2. Constat device d'Alex. Et sur le modèle
     FR (validé par lui) : la marque occupe la colonne gauche, les DEUX
     menus s'empilent à droite (Produit au-dessus de Fab) — sans le span,
     le menu Fab passait SOUS le bloc marque et allongeait tout de vide. */
  .footer .container, .footer .container.fcols-3 { grid-template-columns: minmax(0,1fr) minmax(0,1fr); }
  .footer .fcols-3 > div:first-child { grid-row: span 2; }
  .footer .stores { grid-auto-flow: row; }
}
@media (max-width: 720px) {
  .app-shelf { gap: 16px 13px; max-width: 400px; }
  .shelf-app { width: 66px; }
  .shelf-app:nth-child(even) { transform: translateY(5px); }
  .shelf-icon { width: 58px; height: 58px; font-size: 1.625rem; }
  .shelf-icon--2 { font-size: 1.3125rem; }
  .grid-cards, .blog-grid { grid-template-columns: 1fr; }
  .footer .container, .footer .container.fcols-3 { grid-template-columns: minmax(0,1fr) minmax(0,1fr); }
  .container { padding: 0 21px; }
  .bubble { font-size: 1rem; padding: 10px 16px 11px; }
}
@media (max-width: 460px) {
  .stores { grid-auto-flow: row; }
}

/* ==== §10 Patterns de sections (2026-08-08) — c) .bpass boarding-pass (/en/compare).
   a) .route-steps et b) .why-collage ont été SUPPRIMÉS le 2026-08-12 : plus aucune page
   ne les référençait, et ils portaient à eux seuls 5 des bleus royaux en double
   (#1349DD ×3, #2563EB, #4C6CF0). `.steps`/`.vcard` restent (homes lite). ==== */
.fs-ic{width:34px;height:34px;flex:none;border-radius:50%;background:#F3F4F6;display:flex;align-items:center;justify-content:center;color:#6B7280}
.fs-ic svg{width:17px;height:17px}
.fs-t{display:flex;flex-direction:column;line-height:1.3;min-width:0}
.fs-t b{font-size:15px;font-weight:600;color:#1C1C1E;letter-spacing:-.2px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.fs-t small{font-size:13px;color:#8E8E93}
/* aéroport : carte-composition centrée, billet en pièce maîtresse */
.airport-grid{display:flex;flex-direction:column;align-items:center;text-align:center;gap:8px;position:relative;z-index:1}
.apt-card{position:relative;overflow:hidden}
.apt-card .h-section{font-size:clamp(1.625rem,2.6vw,2.125rem);text-wrap:balance}
.apt-card .lead{font-size:1rem;max-width:62ch;margin-inline:auto}
.apt-card .bp-wrap{margin-top:clamp(21px,3vw,34px)}
.apt-card .btn{white-space:normal;text-align:center}
.bp-wrap{position:relative;width:100%;max-width:403px;margin-inline:auto} /* 377+26 : legs EN entiers */
.bpass{position:relative;display:grid;grid-template-columns:minmax(0,1fr) 42px;background:var(--card);border-radius:var(--r-card);transform:rotate(1.2deg);box-shadow:0 2px 4px rgba(32,29,21,.07),0 26px 55px -24px rgba(25,44,134,.32)}
.bpass::before,.bpass::after{content:'';position:absolute;inset-inline-end:29px;width:26px;height:26px;border-radius:50%;background:radial-gradient(circle at 50% 38%,#EDE3CC 0%,var(--card-2) 62%);border:1.5px solid var(--border-warm);box-shadow:inset 0 2px 3px rgba(32,29,21,.08)}
.bpass::before{top:-13px}
.bpass::after{bottom:-13px}
.bp-main{padding:16px 13px 13px 16px;min-width:0}
.bp-stub{border-inline-start:2px dashed var(--border-2);display:flex;flex-direction:column;align-items:center;justify-content:space-between;gap:8px;padding:16px 8px 13px}
.bp-code{font-family:var(--fd);font-weight:800;font-size:.8125rem;line-height:1;color:var(--muted-soft);letter-spacing:.08em;writing-mode:vertical-rl}
.bp-bars{flex:1;width:21px;border-radius:4px;opacity:.78;background:repeating-linear-gradient(180deg,var(--ink) 0 2px,transparent 2px 6px),repeating-linear-gradient(180deg,var(--ink) 0 3px,transparent 3px 13px)}
.bp-route{display:flex;align-items:center;gap:8px;margin-bottom:13px}
.bp-route b{font-family:var(--fd);font-weight:800;font-size:1.625rem;line-height:1;letter-spacing:.01em;color:var(--ink);display:block}
.bpr-city{display:block;font-family:var(--fb);font-weight:600;font-size:.8125rem;line-height:1.2;color:var(--muted-soft);letter-spacing:.05em;text-transform:uppercase;margin-top:3px}
.bp-plane{flex:1;display:flex;align-items:center;gap:5px;color:var(--blue);min-width:26px}
.bp-plane::before,.bp-plane::after{content:'';flex:1;border-top:2px dashed var(--border-2)}
.bp-plane svg{width:16px;height:16px;flex:none}
.bp-rows{display:flex;flex-direction:column;gap:8px}
.bp-row{display:flex;align-items:center;justify-content:space-between;gap:6px;background:var(--card-2);border:1.5px solid var(--border-warm);border-radius:999px;padding:5px 6px 5px 13px;font-variant-numeric:tabular-nums}
.bp-row .badge-cheap,.bp-row .pill{flex:none;padding:4px 9px}
.bp-leg{display:flex;align-items:baseline;gap:6px;min-width:0;flex:1}
.bp-leg strong{font-size:.9375rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.bp-leg small{font-size:.8125rem;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.bp-row:nth-child(1){transform:rotate(-1.6deg);width:calc(100% - 13px)}
.bp-row:nth-child(2){transform:rotate(1.4deg);margin-inline-start:13px}
.bp-row:nth-child(3){transform:rotate(-1.2deg);width:calc(100% - 8px);margin-inline-start:5px}
.bp-foot{font-size:.72rem;margin-top:8px}
.bp-car{position:absolute;z-index:3;bottom:-29px;inset-inline-end:-26px;width:89px;height:auto;transform:rotate(-6deg);filter:drop-shadow(0 10px 13px rgba(32,29,21,.22));pointer-events:none}
/* ==== §10 e) L'ÉTABLI v2 (2026-08-11) — COLLAGE, plus de carrousel ====
   v1 : un plateau unique où 4 actes se remplaçaient, piloté par 4 traits. Verdict
   fondateur après la Cour : « on garde ce style et on adapte le reste ». Or un
   carrousel cache les trois quarts du produit derrière du temps, et son cadre vide
   crevait les yeux une fois le contour devenu franc. La section reprend donc la
   grammaire de la Cour : quatre BLOCS DE COULEUR, contour 3px, ombre dure 8px,
   et dans chacun l'objet réel de l'app qui déborde par un bord.
   Les blocs portent les ancres du sommaire du hero (#choisis, #organise,
   #personnalise, #economise) — dont deux ne pointaient sur RIEN avant. */
.fp-collage { grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr); }
.cr-blk--promo { background: var(--card); grid-row: span 2; }
.cr-blk--apps { background: var(--p-yellow); }
.cr-blk--plan { background: var(--p-blue); }
.cr-blk--bilan { background: var(--blue); border-color: #0A1F3B; box-shadow: 8px 8px 0 #0A1F3B; }
.cr-blk--bilan h3 { color: #fff; } .cr-blk--bilan p { color: rgba(255, 253, 246, .88); }
/* LE DÉBORDEMENT SE FAIT EN MARGE NÉGATIVE, JAMAIS EN ABSOLU : un objet en
   absolu ne réserve aucune place et vient recouvrir le texte (mesuré 2026-08-11). */
.fp-offers { display: grid; gap: 8px; margin: 26px -34px -55px -13px; }
.fp-offers .oc { background: #F8F9FA; border: 2.5px solid var(--ink); box-shadow: 4px 4px 0 var(--ink); }
/* les objets du collage prennent le contour franc, comme dans la Cour */
.fp-collage .fma, .fp-collage .fmb-hero, .fp-collage .fmpl-bar {
  border: 2.5px solid var(--ink); box-shadow: 4px 4px 0 var(--ink); }
.fp-collage .fmpl-plan, .fp-collage .fmpl-when, .fp-cats span, .fp-collage .fmb-eur {
  border: 2px solid var(--ink); box-shadow: 2px 2px 0 var(--ink); }
.fp-collage .shelf-icon { border: 2.5px solid var(--ink); box-shadow: 3px 3px 0 var(--ink); }
.fp-collage .fmb-stats { border: 2px solid var(--ink); }
.cr-blk--apps .fma { margin: -55px -34px 21px auto; width: min(288px, 100%); transform: rotate(1.4deg); }
 /* le bloc bilan prend TOUTE la largeur et se lit en deux temps : l'objet à
   gauche (il déborde), le texte à droite. Avant, il héritait d'une cellule de
   grille qui l'étirait et la carte flottait dans deux tiers de vide. */
.cr-blk--bilan { grid-column: 1 / -1; display: flex; align-items: center; gap: clamp(26px, 4vw, 55px); }
.cr-blk--bilan .cr-bil-copy { flex: 1; min-width: 0; }
.cr-blk--bilan .fmb { flex: none; margin: 0 0 0 -55px; width: min(377px, 46%); }
.cr-blk--bilan .fmb-hero { transform: rotate(-1.5deg); }
.cr-blk--bilan .fmb-head b { white-space: nowrap; }
.cr-blk--plan .fmpl { width: 100%; margin: 21px -21px 0 0; }
.fp-cats { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 13px; }
.fp-cats span { font-family: var(--fb); font-size: 13px; font-weight: 600; color: var(--ink);
  background: #FFFDF6; border-radius: 999px; padding: 6px 13px; }
@media (max-width: 1019px), (orientation: landscape) and (max-height: 520px) {
  /* 🚨 Le voyage recouvre le haut du plateau social de ~55 px (design : sa
     CARTE devait occuper cette zone). Sur mobile la carte ne se dessine pas
     (chantier iOS) et son fond nu DÉCAPITAIT les coins ronds du plateau —
     constaté par le fondateur le 13/08 : « le bord externe est à 90° ».
     Le plateau repasse devant ; la géométrie ne bouge pas. */
  .soc { position: relative; z-index: 1; }
  .fp-collage { grid-template-columns: minmax(0, 1fr); }
  .cr-blk--promo { grid-row: auto; }
  .fp-offers, .cr-blk--apps .fma, .cr-blk--bilan .fmb, .cr-blk--plan .fmpl { margin-inline: 0; }
  .cr-blk--bilan { flex-direction: column; align-items: stretch; }
  .cr-blk--bilan .fmb { width: 100%; margin: 0 0 21px; }
  .fp-offers { margin-bottom: -34px; }
}
@media (max-width: 640px){
.bpass{grid-template-columns:1fr}
.bp-stub{border-inline-start:0;border-top:2px dashed var(--border-2);flex-direction:row;padding:8px 16px}
.bp-code{writing-mode:horizontal-tb}
.bp-bars{width:auto;height:21px;align-self:stretch;background:repeating-linear-gradient(90deg,var(--ink) 0 2px,transparent 2px 6px),repeating-linear-gradient(90deg,var(--ink) 0 3px,transparent 3px 13px)}
.bpass::before,.bpass::after{top:auto;bottom:24px}
.bpass::before{inset-inline-end:auto;inset-inline-start:-13px}
.bpass::after{inset-inline-end:-13px}
.bp-car{width:68px;inset-inline-end:-8px;bottom:-21px}
.bp-leg small{display:none}
}

/* ==== §10 d) Parcours features « grosses cartes » (2026-08-08) — homes FR/EN.
   Directive fondateur : chaque moment = UNE grosse carte squircle 26 façon hub
   app (« Ton espace FAB »), GROS titre Baloo, pills secondaires, mock d'app NU
   DANS la carte (jamais d'iPhone frame). d2 .fmq cluster
   prix · d3 .fmb bilan · d4 .fma mes-apps · d5 .fms social (priorité).
   Intérieurs mock = fidélité app (typo système + Baloo display), HORS échelle φ. ==== */
/* Passe E 2026-08-09 : BENTO CENTRÉ. Chaque carte = composition centrée
   (pill kicker → gros titre → une phrase → mock pièce maîtresse), largeurs
   variées 7/5 · 5/7 · 6/6, fonds alternés (blanc/crème/navy/bleu). */
/* carte navy = le Bilan lui-même : le hero du mock fond dans la carte */
/* d2 — cluster QuoteCards nues + chip « surge ✕ · promo ✓ » */
/* d2bis — promos : pile de 2 offres Uber en promo (canon hero) */
/* d2ter — planifier : barre « Nouvelle course » + pill Planifier (canon
   AddressSheet : barre #F5F5F5, pill blanche ; #D9E8FF quand l'heure est posée) */
.fmpl{display:flex;flex-direction:column;gap:13px;width:min(420px,100%);margin-inline:auto}
.fmpl-bar{display:flex;align-items:center;gap:10px;background:#F5F5F5;border-radius:999px;padding:8px 8px 8px 18px;box-shadow:0 2px 4px rgba(32,29,21,.08),0 18px 38px -16px rgba(25,44,134,.26)}
.fmpl-bar>svg{width:18px;height:18px;flex:none;color:#111}
.fmpl-ph{flex:1;font-size:15.5px;font-weight:600;color:#111;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.fmpl-plan{display:inline-flex;align-items:center;gap:6px;flex:none;background:#fff;border-radius:999px;padding:9px 14px;font-size:14px;font-weight:700;color:#111;box-shadow:0 1px 2px rgba(0,0,0,.07)}
.fmpl-plan svg,.fmpl-when svg{width:14px;height:14px;flex:none}
.fmpl-when{align-self:flex-start;display:inline-flex;align-items:center;gap:7px;background:#D9E8FF;color:#16309B;border-radius:999px;padding:9px 16px;font-size:14px;font-weight:700;transform:rotate(-1.2deg) translateX(21px);box-shadow:0 2px 4px rgba(32,29,21,.07),0 13px 26px -12px rgba(25,44,134,.3)}
.fmpl-favs{display:flex;flex-wrap:wrap;gap:8px}
.fmpl-chip{display:inline-flex;align-items:center;gap:6px;border-radius:999px;padding:8px 14px;font-size:13.5px;font-weight:600;background:var(--cb,#F5F5F5);color:#3A3D45}
.fmpl-chip svg{width:13px;height:13px;flex:none}
/* d3 — bilan (Récap V4, canon BilanHeroCard/RepartitionCard/ProviderGrid :
   gradient ink #1B3A6B→#0A1F3B→#06152B, surfaces #F5F1EB, vert #1B7A3E,
   Outfit partout — PAS de Baloo dans l'app) */
.fmb{display:flex;flex-direction:column;gap:21px;width:min(377px,100%);margin-inline:auto;font-variant-numeric:tabular-nums;font-family:var(--fb)}
.fmb-hero{background:linear-gradient(175deg,#1B3A6B 0%,#0A1F3B 58%,#06152B 100%);border-radius:24px;padding:19px 19px 0;color:#fff;transform:rotate(-1deg);box-shadow:inset 0 1px 0 rgba(255,255,255,.14),0 2px 5px rgba(6,21,43,.2),0 26px 55px -22px rgba(6,21,43,.6)}
.fmb-head{display:flex;align-items:flex-start;justify-content:space-between;gap:13px}
.fmb-head b{font-weight:700;font-size:34px;line-height:1.05;letter-spacing:-.02em;color:#fff}
.fmb-eur{display:inline-flex;align-items:center;gap:6px;background:#F5F1EB;color:#0A1F3B;font-weight:700;font-size:12.5px;letter-spacing:.02em;border-radius:13px;padding:8px 12px;margin-top:2px;box-shadow:0 3px 8px -3px rgba(6,21,43,.5)}
.fmb-eur::after{content:'';width:6px;height:6px;border-right:2px solid #0A1F3B;border-bottom:2px solid #0A1F3B;transform:rotate(45deg);margin-top:-3px}
.fmb-since{display:block;font-size:12.5px;font-weight:500;color:rgba(255,255,255,.74);margin-top:3px}
/* 🚨 #F5F1EB est le crème des surfaces du Récap V4 dans l'app, où il est posé
   sur du crème. Ici le Bilan flotte sur une carte BLEU ROI : ce crème chaud
   y devient une tache jaune (fondateur 2026-08-12, même remarque que sur
   Freenow et les adresses). Écart assumé avec le canon de l'app. */
.fmb-stats{display:flex;background:#FBFBFC;border-radius:18px;margin:18px -6px -10px;padding:12px 4px;box-shadow:0 10px 24px -10px rgba(6,21,43,.5);color:#0A1F3B}
.fmb-stats>span{flex:1;min-width:0;display:flex;flex-direction:column;align-items:center;gap:2px}
.fmb-stats>span+span{border-inline-start:1px solid rgba(10,31,59,.08)}
.fmb-stats b{font-size:17px;font-weight:700;letter-spacing:-.3px;white-space:nowrap;color:#0A1F3B}
.fmb-stats small{display:inline-flex;align-items:center;gap:3px;font-size:10.5px;font-weight:500;color:#5A6B85}
.fmb-saved b{color:#1B7A3E}
.fmb-info{width:11px;height:11px;border-radius:50%;border:1.2px solid #939DAE;color:#939DAE;display:inline-flex;align-items:center;justify-content:center;font-size:7.5px;font-weight:700;font-style:normal;line-height:1}
.fmb-mid{background:rgba(255,252,245,.8);border:1px solid rgba(93,74,54,.10);border-radius:22px;padding:16px;transform:rotate(.8deg);box-shadow:0 1px 3px rgba(60,40,20,.08),0 18px 38px -16px rgba(60,40,20,.24)}
.fmb-mid-t{font-size:16px;font-weight:700;color:#0A1F3B;margin-bottom:12px}
.fmb-mid-b{display:flex;align-items:center;gap:18px}
.fmb-donut{width:110px;height:110px;flex:none;border-radius:50%;background:conic-gradient(#000 0 64%,#FF5A00 64% 90%,#34D186 90% 100%);display:flex;align-items:center;justify-content:center}
.fmb-donut>span{width:72px;height:72px;border-radius:50%;background:#FEFAF1;display:flex;flex-direction:column;align-items:center;justify-content:center;line-height:1;gap:2px}
.fmb-donut b{font-weight:700;font-size:29px;letter-spacing:-.03em;color:#0A1F3B}
.fmb-donut small{font-size:9.5px;font-weight:500;letter-spacing:.08em;color:#5A6B85}
.fmb-legend{display:flex;flex-direction:column;gap:10px;flex:1;min-width:0}
.fmb-legend li{display:grid;grid-template-columns:3px minmax(0,1fr) auto;grid-template-rows:auto auto;column-gap:10px;align-items:center}
.fmb-legend li::before{content:'';grid-row:1/3;width:3px;height:26px;border-radius:3px;background:var(--c)}
.fmb-legend b{grid-column:2;font-size:13.5px;font-weight:700;color:#0A1F3B;line-height:1.25}
.fmb-legend small{grid-column:2;grid-row:2;font-size:11px;color:#5A6B85;white-space:nowrap}
.fmb-legend .pc{grid-column:3;grid-row:1/3;font-size:13px;font-weight:700;color:#5A6B85}
.fmb-provs{display:flex;align-items:flex-start;gap:12px;transform:rotate(-.7deg)}
.fmb-prov{--pc:#000;flex:1;min-width:0;border-radius:20px;padding:13px 14px 12px;color:#fff;background:var(--pc);background:linear-gradient(172deg,color-mix(in srgb,var(--pc) 88%,#fff) 0%,var(--pc) 46%,color-mix(in srgb,var(--pc) 86%,#000) 100%);box-shadow:inset 0 1px 0 rgba(255,255,255,.3),0 2px 4px rgba(10,31,59,.16),0 18px 38px -14px color-mix(in srgb,var(--pc) 50%,rgba(10,31,59,.3))}
.fmb-ptop{display:flex;align-items:flex-start;justify-content:space-between;margin-bottom:12px}
.fmb-pic{display:flex;align-items:center;justify-content:center;width:38px;height:38px;border-radius:11px;background:rgba(0,0,0,.28);box-shadow:inset 0 1px 1px rgba(255,255,255,.28),inset 0 0 0 1px rgba(255,255,255,.14);font-weight:700;font-size:17px}
.fmb-chev{width:8px;height:8px;border-top:2.2px solid rgba(255,255,255,.65);border-inline-end:2.2px solid rgba(255,255,255,.65);transform:rotate(45deg);margin-top:6px;margin-inline-end:2px}
.fmb-prov b{display:block;font-weight:700;font-size:16px;line-height:1.2;letter-spacing:-.02em;color:#fff}
.fmb-amt{display:block;font-weight:700;font-size:20px;letter-spacing:-.03em;line-height:1.15;margin-top:2px}
.fmb-rides{display:block;font-size:11.5px;color:rgba(255,255,255,.78);margin-top:2px}
.fmb-sav{display:block;font-size:11.5px;font-weight:500;color:rgba(255,255,255,.85);border-top:1px solid rgba(255,255,255,.22);margin-top:9px;padding-top:8px}
.fmb-sav b{display:inline;font-weight:700;font-size:11.5px}
/* d4 — Mes apps : panneau tabs + grille squircle, pastille verte app */
/* — améliorations de la carte Bilan (2026-08-11, passe 2) : le canon Récap V4
   ci-dessus est celui de l'app, on ne le retouche pas ; on corrige seulement ce
   qui n'allait pas dans la SCÈNE. L'ancienne version n'affichait que le hero :
   161 px de haut dans une carte qui en veut 300, « app par app » promis par le
   texte et dessiné nulle part, et l'économie noyée en stat du milieu. */
.exp-scene .fmb{width:min(302px,100%);margin:0}
.exp-scene .fmb-hero{transform:rotate(-1.2deg)}
.exp-scene .fmb-hero{padding:16px 17px 0}
.exp-scene .fmb-stats{padding:10px 4px;margin-top:15px}
/* interlignes d'app, pas d'interlignes de page : le corps du site est à 1,618,
   ce qui gonflait chaque ligne du mock de ~8 px et donnait une scène de 346 px
   dans une carte qui en veut 300. L'app, elle, est serrée. */
.exp-scene .fmb-stats b{line-height:1.15}
.exp-scene .fmb-stats small{line-height:1.2}
.exp-scene .fmb-since{line-height:1.25}
/* l'économie sort du rang : le vert de l'app (#1B7A3E), pas un stat de plus */
.exp-scene .fmb-saved small{color:#1B7A3E;font-weight:600}

/* d4 — MES APPS, UNE FICHE QUI RESPIRE (2026-08-11, état livré).
   Historique des essais, tous rejetés : éventail qui se réorganise (« j'aime pas
   comment ça se réorganise »), éventail figé + fondu (« pas assez organique »),
   main de poker (« ça marche pas du tout, t'as rien de plus maîtrisé ? » — et sa
   capture le montrait : sur écran large les cartes tenues en main sortaient du
   bloc). Verdict final : « reviens à la disposition d'avant ».
   Donc UN SEUL objet, la vraie fiche « Mes apps », toujours à la même place.
   Ce qui vit, c'est le contenu : les vignettes sont des stickers posés de
   travers, elles se posent une par une avec un ressort quand une ville arrive,
   et le nom monte. Rien ne se déplace, rien ne peut déborder. */
.fmv{position:relative;width:min(292px,100%);height:272px;font-family:var(--fb)}
/* les deux feuilles : du papier, et rien d'autre — jamais de contenu qui dépasse,
   jamais un pixel hors du bloc. C'est l'éventail que le fondateur a retenu. */
.fmv-sheet{position:absolute;inset-inline:0;top:32px;height:186px;display:block;border-radius:22px;
  box-shadow:0 1px 2px rgba(32,29,21,.07)}
.fmv-sheet--1{background:var(--card-2);transform:rotate(3deg) translate(9px,-15px)}
.fmv-sheet--2{background:var(--card-3);transform:rotate(6.8deg) translate(19px,-28px)}
.fmv-city{position:absolute;inset-inline:0;top:32px;height:236px;display:flex;flex-direction:column;
  background:var(--card);border-radius:22px;padding:15px 16px 17px;transform:rotate(-1.4deg);z-index:2;
  --d:-.4s;box-shadow:0 2px 4px rgba(32,29,21,.08),0 21px 42px -16px rgba(25,44,134,.3)}
.fmv-city--2{--d:4.1s}
.fmv-city--3{--d:8.6s}
/* repli sans animation : Paris, et lui seul */
.fmv-city--2,.fmv-city--3{opacity:0}
.fmv-head{display:flex;align-items:center;gap:10px;margin-bottom:14px}
.fmv-head img{flex:none}
.fmv-ht{min-width:0}
.fmv-name{display:block;font-family:var(--fd);font-weight:800;font-size:20px;line-height:1.1;
  letter-spacing:-.02em;color:var(--ink);white-space:nowrap}
.fmv-ht small{display:block;font-size:11.5px;font-weight:500;color:var(--muted);margin-top:2px}
.fmv-grid{flex:1;display:flex;flex-wrap:wrap;align-content:flex-start;gap:12px 9px}
.fmv-app{width:53px;display:flex;flex-direction:column;align-items:center;gap:5px;min-width:0}
/* le sticker penche, le nom reste droit — la règle de la Cour */
.fmv .shelf-icon{width:43px;height:43px;font-size:1.125rem;border-radius:32%}
:where(.fmv-app) small{display:block;position:relative;text-align:center;font-size:10.5px;
  font-weight:600;line-height:1.2;color:var(--ink);white-space:nowrap}
/* 🚨 la pastille « liée » est HORS FLUX. Dans le flux, elle poussait le mot de
   4,5 px : le nom n'était plus centré sous sa vignette, et seules les apps liées
   décrochaient — c'est ce que le fondateur a vu à l'œil nu. */
.fmv-app.is-linked small::before{content:'';position:absolute;inset-inline-start:-9px;top:50%;
  width:5px;height:5px;margin-top:-2.5px;border-radius:50%;
  background:var(--green);box-shadow:0 0 0 2px rgba(22,163,74,.16)}
.fmv-app:not(.is-linked) small{color:var(--muted)}
.fmv-app:not(.is-linked) .shelf-icon{opacity:.9}

/* le relais : 4,5 s par ville. 🚨 La ville qui ARRIVE passe au-dessus (z-index,
   propriété discrète, posée par la même keyframe) et la sortante reste opaque
   dessous : sans ça deux fiches à fond opaque se croisent à 50 % et les textes
   se superposent. 🚨 Décalage de -0,4 s sur la première : sinon l'animation
   démarre à son 0 % (opacité 0) pile quand la carte entre et on regarde une
   scène vide pendant une demi-seconde. */
@media (prefers-reduced-motion:no-preference){
  .exp-card.in .fmv-city{animation:fmv-relay 13.5s linear infinite;animation-delay:var(--d)}
  @keyframes fmv-relay{
    0%{opacity:0;z-index:3}
    1%{opacity:1;z-index:3}
    33.33%{opacity:1;z-index:3}
    33.34%{opacity:1;z-index:2}
    100%{opacity:1;z-index:2}
  }
  /* les stickers se posent un par un — 60 ms d'écart, ressort court */
  .exp-card.in .fmv .shelf-icon{animation:fmv-pose 13.5s cubic-bezier(.34,1.56,.64,1) infinite;
    animation-delay:calc(var(--d) + var(--i,0) * 60ms)}
  @keyframes fmv-pose{
    0%{transform:scale(.58) rotate(-8deg)}
    4.4%{transform:none}
    100%{transform:none}
  }
  /* 🚨 LE CONTENU S'EFFACE AVANT QUE LA VILLE SUIVANTE N'ARRIVE. La fiche
     sortante reste opaque sous la nouvelle (c'est voulu, ça évite le trou) —
     mais pendant les 0,4 s de fondu, la nouvelle est semi-transparente et les
     vignettes de l'ancienne transparaissaient au travers : les deux jeux d'apps
     se mélangeaient. On sépare donc le CONTENU du CARTON : le contenu sortant
     part à 33,2 % (juste avant que la suivante démarre à 33,33 %), le fond crème
     ne bouge pas, et on ne voit jamais deux jeux de vignettes à la fois. */
  .exp-card.in .fmv-head{
    animation:fmv-rise 13.5s cubic-bezier(.16,1,.3,1) infinite,
              fmv-content 13.5s linear infinite;
    animation-delay:var(--d),var(--d)}
  .exp-card.in .fmv-grid{animation:fmv-content 13.5s linear infinite;animation-delay:var(--d)}
  @keyframes fmv-rise{0%{transform:translateY(7px)}5%{transform:none}100%{transform:none}}
  @keyframes fmv-content{0%{opacity:0}2.5%{opacity:1}32.6%{opacity:1}33.3%{opacity:0}100%{opacity:0}}
}

/* d5 — social (PRIORITÉ fondateur) : tuile profil + pills, amis, invite, carte QR */
.fms{display:flex;flex-direction:column;align-items:center;gap:21px;width:min(340px,100%);margin-inline:auto;font-family:var(--fb)}
.fms-head{position:relative;width:max-content;margin-top:8px}
.fms-tile{display:flex;align-items:center;justify-content:center;width:144px;height:144px;background:#fff;border-radius:26px;box-shadow:0 2px 4px rgba(60,40,20,.09),0 21px 42px -16px rgba(10,31,59,.28)}
.fms-ava{display:flex;align-items:center;justify-content:center;border-radius:50%;font-weight:700;background:var(--ac,#DDE4F8);color:var(--ai,#16309B)}
.fms-tile .fms-ava{width:100px;height:100px;font-size:2.625rem}
.fms-pill{position:absolute;font-weight:700;font-size:14px;color:#0A1F3B;background:#FFFDF6;border-radius:999px;padding:8px 15px 9px;box-shadow:0 2px 4px rgba(60,40,20,.12),0 13px 26px -10px rgba(10,31,59,.3);white-space:nowrap}
.fms-pill--amis{top:-8px;inset-inline-start:-47px;transform:rotate(-4deg)}
.fms-pill--courses{bottom:-5px;inset-inline-end:-50px;transform:rotate(2deg);color:#1B7A3E}
.fms-friends{display:flex;gap:16px}
.fms-fr{display:flex;flex-direction:column;align-items:center;gap:5px}
.fms-fr .fms-ava{width:55px;height:55px;font-size:1.3125rem;border:2.5px solid #fff;box-shadow:0 2px 4px rgba(60,40,20,.1),0 10px 21px -8px rgba(10,31,59,.26)}
.fms-fr small{font-size:11.5px;font-weight:600;color:#111}
.fms-flabel{align-self:flex-start;font-size:15px;font-weight:700;color:#0A1F3B;margin-bottom:-11px}
.fms-toast{display:flex;align-items:center;gap:10px;background:#fff;border-radius:16px;padding:10px 13px;transform:rotate(1deg);box-shadow:0 2px 5px rgba(60,40,20,.1),0 18px 38px -14px rgba(10,31,59,.28);font-size:13.5px;color:#111;width:max-content;max-width:100%}
.fms-toast .fms-ava{width:34px;height:34px;font-size:15px;flex:none;font-weight:700}
.fms-toast b{color:#111}
.fms-accept{font-weight:700;font-size:12px;color:#fff;background:#0066FF;border-radius:999px;padding:6px 12px;flex:none}
.fms-card{display:flex;align-items:center;gap:13px;width:100%;background:linear-gradient(160deg,#1B3A6B 0%,#0A1F3B 58%,#06152B 100%);border-radius:23px;padding:13px 16px;color:#fff;transform:rotate(-1.2deg);box-shadow:inset 0 1px 0 rgba(255,255,255,.14),0 2px 5px rgba(6,21,43,.2),0 26px 52px -20px rgba(6,21,43,.55)}
.fms-cava{display:flex;align-items:center;justify-content:center;flex:none;width:42px;height:42px;border-radius:11px;background:#F5F1EB;color:#0A1F3B;font-weight:700;font-size:19px}
.fms-ct{flex:1;min-width:0;line-height:1.25}
.fms-ct b{display:block;font-weight:700;font-size:16px;color:#fff}
.fms-ct small{font-size:12px;color:rgba(255,255,255,.75)}
.fms-qr{flex:none;width:44px;height:44px;border-radius:9px;padding:5px;background:conic-gradient(#0A1F3B 25%,transparent 0 50%,#0A1F3B 0 75%,transparent 0) 0 0/6px 6px content-box,#fff}
@media (max-width: 960px){
.fmpl-when{transform:rotate(-1.2deg)}
.fms-pill--amis{inset-inline-start:-34px}
.fms-pill--courses{inset-inline-end:-34px}
}
@media (max-width: 640px){
}
@media (max-width: 430px){
.fmv-app{width:50px}
}

/* ---- Vrais squircles (progressive enhancement) ----
   Chromium 139+ : corner-shape (squircle = superellipse(2)) sur les
   cartes-objets, rangées et icônes. Ailleurs, retombée propre sur le
   border-radius classique — c'est le comportement voulu, aucune lib JS. */
@supports (corner-shape: squircle) {
  .card, .step, .vcard, .post-card, .cta-band, .faq-item, .nav--bar .container,
  .icon-badge, .shelf-icon, .store-badge, .phone-float,
  .lang-menu, .table-wrap, .ham,
  .wp-card, .wp-gauge, .wp-note, .bpass,
    .fms-tile, .fms-card, .fms-toast, .fms-cava,
  .exp-card, .exp-scene, .app-sheet { corner-shape: squircle; }
}

/* ==== Chapitre COMPARE — « la course en direct » (2026-08-09) ====
   La pile du moment 2 joue l'arrivée des prix puis le re-tri : les cartes
   voyagent par transform (DOM = état final trié, no-JS parfait). */

/* ==== Refonte sous-hero (2026-08-09) — la langue du hero partout ==== */
/* étagère monumentale : la ligne SEO devient le titre géant, les icônes cascadent */
.apps-title { font-family: var(--fd); font-weight: 800; font-size: clamp(1.625rem, 3.3vw, 2.9375rem); line-height: 1.15; letter-spacing: -.018em; color: var(--ink); text-align: center; text-wrap: balance; max-width: 26ch; margin: clamp(21px,3vw,42px) auto clamp(26px, 3.4vw, 42px); }
.app-shelf--xl { gap: 26px 34px; max-width: 760px; margin-inline: auto; }
.app-shelf--xl .shelf-icon { width: 89px; height: 89px; font-size: 2.125rem; border-radius: 37px; }
.app-shelf--xl .shelf-icon--2 { font-size: 1.625rem; }
.app-shelf--xl .shelf-name { font-size: 1rem; }
.app-shelf--xl.reveal .shelf-app { opacity: 0; transform: translateY(13px) scale(.82); transition: opacity .45s ease, transform .55s cubic-bezier(.34, 1.56, .64, 1); }
.app-shelf--xl.reveal.in .shelf-app { opacity: 1; transform: none; }
.app-shelf--xl.reveal.in .shelf-app:nth-child(2) { transition-delay: 0.055s; } .app-shelf--xl.reveal.in .shelf-app:nth-child(3) { transition-delay: 0.110s; } .app-shelf--xl.reveal.in .shelf-app:nth-child(4) { transition-delay: 0.165s; } .app-shelf--xl.reveal.in .shelf-app:nth-child(5) { transition-delay: 0.220s; } .app-shelf--xl.reveal.in .shelf-app:nth-child(6) { transition-delay: 0.275s; } .app-shelf--xl.reveal.in .shelf-app:nth-child(7) { transition-delay: 0.330s; } .app-shelf--xl.reveal.in .shelf-app:nth-child(8) { transition-delay: 0.385s; } .app-shelf--xl.reveal.in .shelf-app:nth-child(9) { transition-delay: 0.440s; } .app-shelf--xl.reveal.in .shelf-app:nth-child(10) { transition-delay: 0.495s; } .app-shelf--xl.reveal.in .shelf-app:nth-child(11) { transition-delay: 0.550s; } .app-shelf--xl.reveal.in .shelf-app:nth-child(12) { transition-delay: 0.605s; }
/* chapitre : la pill du sommaire devient l'étendard, le titre passe à l'échelle hero */
.kicker--chapter { background: var(--blue); border-color: var(--blue); color: #fff; font-family: var(--fd); font-weight: 700; font-size: 1.1875rem; letter-spacing: 0; text-transform: none; padding: 10px 29px 12px; transform: rotate(-2deg); box-shadow: 0 6px 16px -8px rgba(34, 68, 204, .5); }
.h-chapter { font-size: clamp(2.625rem, 4.8vw, 4.25rem); line-height: 1.04; }
.section-head:has(.h-chapter) { max-width: 760px; }
/* la démo Compare : pièce unique centrale */
.cmp-steps { display: grid; grid-template-columns: repeat(3, 1fr); gap: 34px; max-width: 1000px; margin: clamp(42px, 5.5vw, 68px) auto 0; text-align: center; }
.cmp-n { display: block; font-family: var(--fd); font-weight: 800; font-size: 2.125rem; line-height: 1; color: var(--blue); margin-bottom: 8px; }
.cmp-steps h3 { font-size: 1.3125rem; margin: 0 0 5px; }
.cmp-steps p { font-size: .9375rem; color: var(--muted); max-width: 34ch; margin-inline: auto; }
@media (max-width: 760px) { .cmp-steps { grid-template-columns: 1fr; gap: 26px; } }

/* ==== APPS MINIMAL+ (2026-08-09) : monde cartoon fondu SOUS l'étagère (style
   carte du hero), 11 icônes-boutons + tuile « +26 », tap → SHEET superposée
   canon app (en-tête dégradé brand, note/présence/catégorie réels, App Store). ==== */
/* ==== LE VOYAGE (2026-08-10) : fond-monde commun sous les chapitres — la carte
   dézoome au scroll (Paris → Europe → Monde), cross-fade entre 3 calques réels,
   chaque dézoom centré sur Paris (transform-origin par calque). ==== */
/* 🚨 LA CASSURE À LA JONCTION CARTE → CRÈME (fondateur 2026-08-12, 2e passe).
   Le vrai coupable n'était NI le dégradé de sortie NI la carte : c'est
   l'OMBRE du plateau des apps. Mesuré : le plateau déborde déjà de 21 px sous
   `.journey`, et son ombre (`0 34px 89px -40px`) porte 83 px plus bas encore.
   `overflow: clip` tranche les deux d'un trait parfaitement horizontal, d'où
   une ligne nette avec le côté SOMBRE au-dessus.
   Remède qui ne déplace RIEN : on descend le bord de découpe de 144 px (pas φ,
   il faut 104) et on remonte la section suivante d'autant. L'ombre finit donc
   à l'intérieur du clip, et l'espacement visuel entre les deux sections est
   rigoureusement identique. */
.journey { position: relative; overflow: clip; padding-bottom: 144px; } /* clip, pas hidden : hidden créerait un scroll-container et tuerait le sticky */
#amis, #friends { margin-top: -144px; }
.journey-bg { position: sticky; top: 0; height: 100vh; margin-bottom: -100vh; overflow: hidden; pointer-events: none; z-index: 0; }
/* Calques débordants de 12% : un dézoom peut descendre jusqu'à scale ~.81 sans
   jamais montrer un bord d'image. Le PROCHE recouvre le LARGE (z 3>2>1) : le
   cross-fade révèle l'échelle suivante PAR-DESSOUS — jamais un rectangle qui fond. */
.jl { position: absolute; top: -12%; left: -12%; width: 124%; max-width: none; height: 124%; object-fit: cover; opacity: 0; will-change: transform, opacity; } /* max-width:none : sinon le reset img{max-width:100%} clampe la largeur et le bord du calque entre à l'écran */
.jl-paris  { opacity: .9; object-position: 30% 24%; z-index: 4; }
.jl-france { z-index: 3; }
.jl-europe { z-index: 2; }
.jl-world  { z-index: 1; }
/* loupe : fondu radial des bords pendant le rétrécissement (centré sur Paris du calque, posé par JS) */
.jl--edge { -webkit-mask-image: var(--edge-mask); mask-image: var(--edge-mask); }
.journey-veil { position: absolute; inset: 0; background: rgba(244,237,220,.4); z-index: 4; }
@media (max-width: 1019px) { .jl-paris { object-position: 34% 20%; } }
/* fondu de sortie du théâtre — calé sur le contenu, pas sur l'écran */
/* 🚨 LA JONCTION CARTE → CRÈME (fondateur 2026-08-12 : « on la distingue comme
   une cassure »). Deux causes cumulées :
   1. `.journey-bg` est `sticky; height: 100vh` : en bas de section il descend
      342 px PLUS BAS que `.journey`, et `overflow: clip` le TRANCHE net. Ce
      n'est pas un dégradé qui s'achève, c'est une coupe franche.
   2. Le voile ne la couvrait qu'avec un dégradé LINÉAIRE. Un linéaire a une
      cassure de pente à ses deux extrémités : l'œil la voit comme une bande
      (effet Mach), même quand les couleurs coïncident.
   Remède : le voile monte de 21vh à 34vh (pas φ) et ses arrêts approximent une
   courbe en S, ce qui supprime les deux ruptures de pente. */
.journey::after { content: ''; position: absolute; left: 0; right: 0; height: 34vh; bottom: 0;
  z-index: 1; pointer-events: none;
  /* 🚨 UN PALIER PLEIN AVANT LA COUPE, pas seulement une rampe. La rampe
     atteignait 100 % pile AU bord de découpe : au moindre écart d'arrondi ou
     de contexte d'empilement, un filet de carte survit sur la dernière ligne
     de pixels et se lit comme une couture. Le quart bas du voile est
     désormais du crème PLEIN : la carte a totalement disparu bien avant que
     le clip n'intervienne. */
  background: linear-gradient(0deg,
    rgb(244,237,220) 0%,
    rgb(244,237,220) 25%,
    rgba(244,237,220,.965) 33%,
    rgba(244,237,220,.90) 42%,
    rgba(244,237,220,.79) 51%,
    rgba(244,237,220,.63) 61%,
    rgba(244,237,220,.45) 71%,
    rgba(244,237,220,.28) 81%,
    rgba(244,237,220,.13) 90%,
    rgba(244,237,220,.04) 96%,
    rgba(244,237,220,0) 100%); }
.journey .chapter { position: relative; z-index: 2; }
/* respirations du VOYAGE — la carte seule occupe l'écran, c'est là que la
   cascade se déploie (temps d'écran Europe/Monde ; échelle φ 34/55/89). */
#fonctionnement, #how-it-works { padding-top: clamp(89px, 13vw, 178px); }
/* Écarts du théâtre : porté par le padding-TOP du chapitre suivant UNIQUEMENT
   (sinon les deux paddings s'additionnent → 350px, le double du reste du site). */
#fonctionnement, #how-it-works, #apps { padding-bottom: 0; }
#apps { padding-top: clamp(89px, 13vw, 178px); }
/* 🚨 Sortie du théâtre : `#apps` a `padding-bottom: 0` (convention ci-dessus),
   donc l'écart avant la section sociale était porté par les seuls 55 px de
   `#amis` — un sas trois fois plus court qu'entre deux chapitres. */
#amis, #friends { padding-top: clamp(89px, 13vw, 178px); }
/* (padding du chapitre preuve — défini plus bas, avec le bloc preuve) */
/* halo de lisibilité derrière les textes de chapitre — même geste que le scrim du hero */
.journey .eco-head, .journey .proof-wrap { position: relative; }
.journey .eco-head::before, .journey .proof-wrap::before { content: ''; position: absolute; inset: -21% -34% -34%; z-index: -1; pointer-events: none;
  background: radial-gradient(ellipse 62% 70% at 50% 50%, rgba(244,237,220,.9) 0%, rgba(244,237,220,.55) 55%, rgba(244,237,220,0) 78%); }

/* Chapitre preuve — la note réelle, rien d'autre */
#preuve, #proof { padding-top: clamp(89px, 13vw, 178px); padding-bottom: clamp(89px, 13vw, 178px); }
.proof-wrap { text-align: center; display: flex; flex-direction: column; align-items: center; gap: 13px; }
.proof-stars { display: flex; gap: 8px; }
.proof-stars svg { width: 31px; height: 31px; filter: drop-shadow(0 3px 8px rgba(242,176,30,.4)); }
.proof-wrap .eco-lead { max-width: 480px; }
.proof-stores { display: flex; flex-wrap: wrap; gap: 13px; justify-content: center; margin-top: 8px; }
.app-shelf--xl .shelf-app { background: none; border: none; padding: 0; cursor: pointer; font: inherit; }
.app-shelf--xl .shelf-app:focus-visible { outline: 2.5px solid var(--blue); outline-offset: 5px; border-radius: 21px; }
.shelf-more .shelf-icon { background: color-mix(in srgb, var(--blue) 8%, #FEFAF1); color: var(--blue); font-size: 1.4375rem; letter-spacing: -.02em; box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--blue) 25%, transparent); }
.shelf-more .shelf-name { color: var(--muted-soft); white-space: nowrap; font-size: .875rem; }

/* 🚨 height 100dvh (2026-08-14, constat device) : avec `inset: 0` seul, le bas
   de la veil s'ancrait sur le viewport de MISE EN PAGE iOS — barres Safari
   repliées, une bande de crème nue apparaissait sous la fiche. dvh suit le
   viewport VISIBLE au pixel (vh grand-viewport juste avant, en repli). */
.sheet-veil { position: fixed; inset: 0; height: 100vh; height: 100dvh; z-index: 1200; display: flex; align-items: center; justify-content: center; padding: 21px; background: rgba(32,29,21,.38); backdrop-filter: blur(3px); -webkit-backdrop-filter: blur(3px); animation: veil-in .22s ease; }
.sheet-veil[hidden] { display: none; }
@keyframes veil-in { from { opacity: 0; } }
.app-sheet { position: relative; width: min(430px, 100%); max-height: min(82vh, 640px); overflow: auto; background: var(--card); border-radius: var(--radius-object); box-shadow: var(--sh-lg); animation: sheet-in .34s cubic-bezier(.34,1.35,.4,1); }
@keyframes sheet-in { from { opacity: 0; transform: translateY(21px) scale(.96); } }
.as-close { position: absolute; top: 13px; inset-inline-end: 13px; z-index: 2; width: 34px; height: 34px; display: grid; place-items: center; background: rgba(255,253,246,.92); color: var(--ink); border: none; border-radius: 50%; cursor: pointer; font-size: .9375rem; box-shadow: 0 2px 6px rgba(32,29,21,.22); }
.as-hero { display: flex; flex-direction: column; align-items: center; gap: 11px; padding: 34px 21px 26px; background: linear-gradient(165deg, color-mix(in srgb, var(--pc) 68%, #fff) 0%, var(--pc) 45%, color-mix(in srgb, var(--pc) 70%, #000) 100%); color: #fff; text-align: center; }
.app-sheet .as-icon { --pc: inherit; width: 68px; height: 68px; font-size: 1.625rem; border-radius: 26px; color: #fff;
  box-shadow: inset 0 1px 1px rgba(255,255,255,.45), inset 0 -1px 1px rgba(32,29,21,.28), 0 0 0 2px rgba(255,253,246,.3), 0 12px 26px -10px rgba(0,0,0,.5); }
.as-icon.shelf-icon--2 { font-size: 1.3125rem; }
/* la fiche affiche le vrai logo quand la carte en porte un.
   🚨 PAS d'anneau autour : le `box-shadow: 0 0 0 2px rgba(255,253,246,.34)`
   dessinait un liseré clair qui suivait le squircle et se lisait comme un bug
   du logo (repéré sur Heetch, dont l'illustration est pourtant parfaitement
   plate : écart coin/bord de 3 sur 255). Même règle que dans l'amas — c'est
   l'ombre portée qui détache une icône, jamais un trait.
   Et le rayon revient au ratio iOS (22,37 %) : 26 px sur 68 faisait 38 %, donc
   un arrondi plus fort ici que dans la liste et dans l'amas. */
.app-sheet .as-icon--img { overflow: hidden; background: none; border-radius: 22.37%;
  box-shadow: 0 12px 26px -10px rgba(0,0,0,.5); }
@supports (corner-shape: squircle) { .app-sheet .as-icon--img { corner-shape: squircle; } }
.as-logo { width: 100%; height: 100%; display: block; object-fit: cover; border-radius: inherit; }
.as-name { font-family: var(--fd); font-weight: 800; font-size: 1.5rem; line-height: 1.1; color: #fff; }
.as-type { font-size: .75rem; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; border-radius: 999px; padding: 4px 12px; background: rgba(255,253,246,.92); color: var(--ink); }
/* Note et mention « bientôt » : petit texte (14 px), donc seuil 4,5:1. Plutôt
   que d'assombrir tout le bandeau jusqu'au bordeaux pour 38 marques, on les
   pose sur une pastille claire à encre sombre — le bandeau garde sa couleur. */
.as-rating { font-size: .8125rem; font-weight: 700; padding: 4px 12px; border-radius: 999px;
  background: rgba(255,253,246,.92); color: var(--ink); }
.as-rating[hidden] { display: none; }
.as-soon { margin: 0; font-size: .75rem; font-weight: 700; letter-spacing: .03em;
  padding: 4px 12px; border-radius: 999px; background: rgba(255,253,246,.92);
  color: var(--blue-ink); }
.as-soon[hidden] { display: none; }
.as-body { padding: 21px clamp(21px,4vw,29px) 26px; }
.as-blurb { color: var(--ink-2); font-size: .9375rem; line-height: 1.62; margin: 0 0 13px; }
.as-region { color: var(--muted); font-size: .875rem; margin: 0 0 18px; }
.as-region[hidden] { display: none; }
.app-sheet:focus { outline: none; }
.as-store { display: flex; justify-content: center; width: 100%; }
.as-store[hidden] { display: none; }
/* 🚨 align-items: center (2026-08-14) : la fiche était collée en bas façon
   bottom-sheet ; le fondateur veut « un fog et la carte surélevée bien au
   milieu » — au centre, comme en paysage et sur desktop. */
@media (max-width: 640px) { .sheet-veil { padding: 13px; align-items: center; } .app-sheet { width: 100%; } }
@media (prefers-reduced-motion: reduce) { .app-sheet, .sheet-veil { animation: none; } }
/* 🚨 TÉLÉPHONE COUCHÉ (2026-08-14, constat device) : `82vh` se calcule sur le
   GRAND viewport iOS (barres Safari non déduites) — la fiche dépassait l'écran,
   boutons magasins invisibles, « impossible à utiliser tel quel ». Plafond en
   svh (le viewport SÛR, barres déduites, vh juste avant en repli), et le
   bandeau passe en ligne — logo à gauche, nom et pastilles à côté — pour que
   fiche + boutons tiennent d'un bloc. Le padding inline-end 55 réserve la
   place de la croix ✕ (absolue, 13+34 px). */
@media (orientation: landscape) and (max-height: 520px) {
  .sheet-veil { align-items: center; padding: 13px; }
  .app-sheet { width: min(560px, 100%); max-height: calc(100vh - 26px); max-height: calc(100svh - 26px); }
  .as-hero { flex-direction: row; flex-wrap: wrap; justify-content: flex-start; align-items: center; text-align: start; padding: 18px 55px 14px 21px; gap: 10px 13px; }
  .app-sheet .as-icon { width: 55px; height: 55px; font-size: 1.3125rem; }
  .as-body { padding-top: 14px; }
  .drawer { padding-top: 55px; }
  .drawer a:not(.btn) { font-size: 1.25rem; padding: 8px 5px; }
}

/* ==== L'APP EN SIX TRAITS — compacté (2026-08-09) : la démo vit au chapitre
   Compare, ici le texte seul, bento serré aligné à gauche. ==== */

/* ==== EN-TÊTE DE CHAPITRE (partagé — la langue du titre géant à point bleu) ==== */
.eco-head { margin: 0 0 clamp(26px,3.4vw,42px); }
.eco-title { font-family: var(--fd); font-weight: 800; font-size: clamp(2.375rem,4.8vw,3.8125rem); line-height: 1.02; letter-spacing: -.022em; color: var(--ink); margin: 0; }
.dot-blue { color: var(--blue); }
.eco-lead { font-size: clamp(1rem,1.4vw,1.1875rem); line-height: 1.55; color: var(--muted); max-width: 46ch; margin: 13px 0 0; }
.eco-head--center { text-align: center; }
.eco-head--center .eco-lead { margin-inline: auto; }

/* 🚨 `.eco-head--card` (cartouche de chapitre) a été CONSTRUIT puis RETIRÉ le
   même jour. Verdict fondateur : « pas besoin de titre pour cette partie avec des
   cards, vu qu'il y a des cards, le titre sert à rien ». Le raisonnement tient :
   les cinq cartes portent chacune leur h3 numéroté, un sixième titre au-dessus
   ne fait que répéter. La h2 survit en `sr-only` dans les deux homes (plan du
   document + SEO), le lead a été supprimé. Détail complet : §28 F des guidelines. */

/* ==== OBJETS DE L'APP restaurés (2026-08-10) — les VRAIES cartes d'offre
   et fragments (retour Alex : « les petites cards d'offre, c'est LE bon
   élément — le reste doit être vrai ») ; CSS repris du backup 09d. ==== */
.frag-search{display:flex;align-items:center;gap:10px;background:#fff;border-radius:999px;padding:14px 21px;font-size:15.5px;font-weight:500;color:#8E8E93;transform:rotate(-1.2deg);box-shadow:0 2px 4px rgba(32,29,21,.09),0 21px 42px -18px rgba(25,44,134,.30)}
.frag-search svg{width:18px;height:18px;flex:none;color:#6B7280}
/* 🚨 LOUPE ET « NOUVELLE COURSE » EN ENCRE (fondateur 2026-08-12 : « mets en
   noir, cohérent avec le site »). Écart ASSUMÉ avec l'app, qui affiche son
   placeholder en #9CA3AF et son icône en #6B7280 : ici la barre est un objet
   de vitrine posé sur du bleu roi, et un gris clair y disparaissait. */
.exp-card .frag-search { color: var(--ink); }
.exp-card .frag-search svg { color: var(--ink); }
.frag-sugg{display:flex;align-items:center;gap:12px;background:#fff;border-radius:16px;padding:11px 16px;transform:rotate(1.1deg) translateX(21px);box-shadow:0 1px 3px rgba(32,29,21,.08),0 16px 34px -16px rgba(25,44,134,.26)}
.fs-ic{width:34px;height:34px;flex:none;border-radius:50%;background:#F3F4F6;display:flex;align-items:center;justify-content:center;color:#6B7280}
.fs-ic svg{width:17px;height:17px}
.fs-t{display:flex;flex-direction:column;line-height:1.3;min-width:0}
.fs-t b{font-size:15px;font-weight:600;color:#1C1C1E;letter-spacing:-.2px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.fs-t small{font-size:13px;color:#8E8E93}
.rs-stack .oc:nth-child(1){transform:rotate(-1.2deg)}
.rs-stack .oc:nth-child(2){transform:rotate(.9deg) translateX(13px)}
.rs-stack .oc:nth-child(3){transform:rotate(-.7deg) translateX(-8px)}
.frag-open{position:relative;width:max-content;max-width:100%;padding-top:16px}
.frag-open .oc-tag{position:absolute;top:0;inset-inline-start:-13px;z-index:2;transform:rotate(-2.2deg);box-shadow:0 5px 13px -5px rgba(6,95,70,.45)}
.frag-cta{display:inline-flex;align-items:center;gap:10px;background:#000;color:#fff;border-radius:999px;padding:15px 26px;font-size:15.5px;font-weight:600;letter-spacing:-.2px;transform:rotate(1deg);box-shadow:0 2px 4px rgba(32,29,21,.18),0 21px 42px -16px rgba(32,29,21,.45)}
.frag-sugg{transform:rotate(1.1deg)}
.rs-stack .oc:nth-child(2){transform:rotate(.9deg)}
.rs-stack .oc:nth-child(3){transform:rotate(-.7deg)}

/* ==== CARTES-EXPLICATION (2026-08-09) — la FORME de SocialWelcomeSteps de
   l'app (référence Alex : « ce que la maj sociale permet, avant de signer ») :
   rangée numéro + copy à gauche | SCÈNE-OBJET à droite, bord-à-bord, cousue
   au texte par un fondu (MapEdge). Sol des scènes = papier carte du hero. ==== */
/* écart 21 = pas φ (13 · 21 · 34), pas un 16 arbitraire */
.exp-cards { display: flex; flex-direction: column; gap: 21px; max-width: 840px; margin: clamp(34px,4vw,55px) auto 0; }
/* 🚨 HAUTEUR UNIQUE : 840 / φ² = 321. Les cinq étapes mesuraient 280 · 315 ·
   272 · 237 · 219 — cinq hauteurs pour cinq cartes qui racontent une seule
   suite. Le contenu le plus haut faisait 315, la marche φ juste au-dessus
   cadre tout le monde sans rien comprimer. En colonne (≤860) on relâche :
   une hauteur imposée y créerait du vide au lieu du rythme. */
.exp-card { position: relative; display: flex; align-items: stretch; min-height: 321px; background: var(--card); border: 1.5px solid var(--border); border-radius: var(--radius-object); overflow: visible; box-shadow: var(--sh-card); text-align: left; }
.exp-copy { flex: 1; min-width: 0; display: grid; grid-template-columns: auto minmax(0,1fr);
  align-content: center; align-items: start; gap: 13px; padding: clamp(23px,3vw,34px) 21px clamp(23px,3vw,34px) clamp(23px,3vw,34px); align-items: flex-start; }
.exp-n { flex: none; width: 34px; height: 34px; border-radius: 50%; background: rgba(34,68,204,.1); color: var(--blue); font-family: var(--fd); font-weight: 800; font-size: 1.125rem; display: grid; place-items: center; }
.exp-copy h3 { font-size: clamp(1.1875rem,1.9vw,1.4375rem); line-height: 1.2; margin: 4px 0 8px; letter-spacing: -.012em; }
.exp-copy p { font-size: clamp(.9375rem,1.2vw,1rem); line-height: 1.62; margin: 0; max-width: 44ch; }
.exp-scene { position: relative; flex: none; width: clamp(280px,34vw,410px); padding: 23px 21px; display: flex; flex-direction: column; align-items: center; justify-content: center; }
/* 🚨 2026-08-14 (constat device, téléphone couché) : à 852 pt de large c'est la
   rangée desktop qui s'appliquait — la scène tombait à 34vw ≈ 290 px, moins ses
   marges le mock n'avait plus que ~248 px, la grille d'apps passait à 3 colonnes
   et débordait de sa fiche à hauteur fixe, HORS de la card. Couché = colonne,
   comme en portrait : le mock retrouve sa largeur de conception. */
@media (max-width: 640px), (orientation: landscape) and (max-height: 520px) {
  .exp-card { flex-direction: column; min-height: 0; }
  .exp-scene { width: 100%; padding: 3px 16px 23px; align-items: center; }
  .exp-copy { padding: 16px 16px 8px; }
  .sg-list, .xs-stack--sorted { margin-right: 0; }
  .ride-duo { align-self: center; }
  .xs-sugg { max-width: 150px; font-size: .625rem; }
}

/* Les vraies offres dans les scènes des cartes-explication */
.exp-scene .frag-search { width: min(100%, 300px); }


/* Les petites cartes d'offre — LE bon element (Alex) : voiture + nom + prix. */
.xs-stack { display: flex; flex-direction: column; gap: 8px; }
.xs-oc { display: flex; align-items: center; gap: 9px; width: max-content; background: #fff; border-radius: 14px; padding: 8px 13px 8px 9px; box-shadow: 0 3px 8px -2px rgba(32,29,21,.16); font-size: .8125rem; }
.xs-oc b { font-weight: 700; color: var(--ink); }
/* tabular-nums : les chiffres gardent la même chasse — un prix qui change ne
   déplace plus rien autour de lui (le sliver du 14/08 venait aussi de là). */
.xs-price { margin-left: 11px; font-weight: 800; color: var(--ink); font-size: .9375rem; white-space: nowrap; font-variant-numeric: tabular-nums; }
/* 🚨 LA 4e OFFRE EST « EFFACÉE », PAS TRANSPARENTE (2026-08-12).
   Elle portait `opacity: .82`, ce qui laissait passer le fond de la carte :
   lisible comme de la profondeur sur crème, mais franchement lavande sale sur
   les cartes bleu roi. La pastille reste donc OPAQUE et ce sont son nom et son
   prix qui s'estompent. Deux mots, deux mécaniques (règle du fondateur, §24). */
/* 🚨 L'EFFACEMENT DE LA DERNIÈRE OFFRE EST SUPPRIMÉ (2026-08-12).
   Il venait du site, pas de l'app : `SLOT` posait une opacité de .82 sur le 4e
   rang pour dire « la plus chère ». Or dans `components/dev/QuoteCard.tsx` la
   SEULE variante atténuée est `quoteItemGhost`, réservée à un prix ESTIMÉ et
   non réel. On disait donc « estimation » en voulant dire « la plus chère » :
   un contresens produit, en plus d'un défaut visuel (« pourquoi Freenow est
   effacé ? », posé trois fois). Les quatre offres sont identiques ; **l'ordre
   EST le tri**, et le tag vert marque la gagnante. `.xs-oc--pale` n'existe
   plus, le JS ne le pose plus. */
/* 🚨 un prix en promo, DEUX bleus sur la même page : le hero peint le sien en
   #2563EB (`.oc-price--promo`, canon QuoteCard) et celui-ci l'était en #1D4ED8,
   qui est la couleur de l'ÉTIQUETTE promo, pas du prix. Recalé sur le prix. */
.xs-promo { color: #2563EB; }

/* Scènes v5 — objets riches sur le crème de la carte, débordement à droite */
.sg-list { display: flex; flex-direction: column; gap: 8px; margin-right: -34px; }
.sg-list .frag-search { transform: rotate(-1.1deg); margin-right: 21px; }
.sg-list .frag-sugg { padding: 8px 13px; }
.sg-list .frag-sugg:nth-of-type(2) { transform: rotate(.8deg) translateX(13px); }
/* 🚨 MÊME CORRECTION QUE LA PILE DE PRIX (2026-08-12) : ces deux rangées
   descendaient à .88 et .74 d'opacité. Sur une carte crème ça faisait de la
   profondeur ; depuis que la carte 1 est bleu roi, ça laissait remonter le bleu
   et les pastilles viraient au lavande. Elles restent OPAQUES et s'enfoncent
   par leur SURFACE (crème de plus en plus chaud) et par leur texte. */
/* 🚨 SURFACES BLANCHES (fondateur 2026-08-12 : « remets blanc »). Mon correctif
   du matin les passait en crème pour éviter le voile lavande dû à l'opacité ;
   sur la carte bleu roi, ce crème se lisait comme un « effet crème » parasite.
   Elles restent donc blanches et opaques, et seul le TEXTE recule, en gris
   neutre (#8E8E93, le secondaire de l'app), jamais en brun. */
.sg-list .frag-sugg:nth-of-type(3) { transform: rotate(-.5deg); }
.sg-list .frag-sugg:nth-of-type(4) { transform: rotate(.6deg) translateX(8px); }
.sg-list .frag-sugg:nth-of-type(3) .fs-t b { color: #48484A; }
.sg-list .frag-sugg:nth-of-type(4) .fs-t b { color: #6C6C70; }
.sg-list .frag-sugg:nth-of-type(4) .fs-t small { color: #AEAEB2; }
.sg-list .fs-t b { font-size: .78125rem; }
.sg-list .fs-t small { font-size: .65625rem; }
/* Scène 2 VIVANTE : les offres permutent (JS live-sort), le tag reste ancré sur
   la tête de liste — « Fab re-trie en direct ». Slots (x/rotation/opacité) pilotés
   JS ; no-JS et reduced-motion : flux statique, état canon. */
.xs-stack--sorted { gap: 8px; margin-right: -29px; }
.live-sort { position: relative; padding-top: 15px; }
.live-sort .oc-tag { position: absolute; top: 0; inset-inline-start: 2px; z-index: 3; white-space: nowrap; transform: rotate(-2.2deg); box-shadow: 0 5px 13px -5px rgba(6,95,70,.45); }
.live-sort.on { padding-top: 0; width: 100%; }
.live-sort.on .xs-oc { position: absolute; top: 0; left: 0; transition: transform 1s cubic-bezier(.3,1.25,.35,1), opacity .6s ease; will-change: transform; }
/* 🚨 « les chiffres vrillent une frame » (constat device 14/08) : la carte est
   une couche compositée (will-change) — au swap de texte, iOS repeignait une
   frame avec la texture PÉRIMÉE de l'ancien prix (sliver de chiffre fantôme).
   Le prix reçoit SA couche et un vrai fondu : le JS le passe à 0, échange le
   texte à 250 ms (invisible, fondu fini à 220), le remonte. */
.live-sort.on .xs-price { transition: opacity .22s ease; will-change: opacity; }
.live-sort .xs-price { transition: opacity .25s ease; }
@media (prefers-reduced-motion: reduce) { .live-sort.on .xs-oc { transition: none; } }
/* Étape 3 : trajet à arrêts + planif — copies de RouteAddressPill / RideScheduler
   (cercle départ #0066FF, arrêt ambre #D97706, pin noir, radio « Plus tard »). */
/* Multi-stop FIDÈLE à l'app : la mini-map réelle est le fond d'objet, la barre
   compacte remplie (routePillRow : cercle bleu · adresse · dot d'arrêt #9CA3AF ·
   pin · adresse) FLOTTE PAR-DESSUS — comme dans l'app. Planif compacte devant. */
.ride-duo { position: relative; width: min(300px, 100%); padding: 13px 0 55px; }
.rd-map { display: block; width: 100%; height: auto; border-radius: 21px; box-shadow: 0 3px 9px rgba(32,29,21,.1), 0 16px 34px -14px rgba(32,29,21,.26); }
/* 🚨 BARRE RESSERRÉE (fondateur 2026-08-12 : « trop longue, resserre les
   espaces »). Elle allait d'un bord à l'autre en `space-between`, ce qui
   plaquait les deux adresses aux extrémités et creusait un vide au milieu.
   Elle se centre maintenant sur sa propre largeur, les deux libellés se
   rapprochent du point d'arrêt, et elle ne dépasse plus la carte.
   ⚠️ Écart avec le canon `routePillRow` de l'app, où la barre occupe toute la
   largeur de l'écran : ici l'objet est une vignette, pas un écran. */
.rd-bar { position: absolute; top: 0; left: 50%; translate: -50% 0;
  width: max-content; max-width: calc(100% - 21px);
  z-index: 2; display: flex; align-items: center; justify-content: center; gap: 5px; background: #fff; border-radius: 999px; padding: 8px 13px; box-shadow: 0 2px 8px rgba(0,0,0,.08), 0 9px 21px -9px rgba(32,29,21,.24); transform: rotate(-.8deg); }
.rd-it { flex: 0 1 auto; display: flex; align-items: center; gap: 7px; min-width: 0; } /* routePillItem : chaque adresse occupe SA moitié, dots au centre */
.rd-bar b { font-size: .71875rem; font-weight: 600; color: #1F2937; letter-spacing: -.2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.rd-stopdot { width: 5px; height: 5px; border-radius: 50%; background: #9CA3AF; flex: none; margin: 0 2px; }
.rd-card { background: #fff; border-radius: 21px; }
/* 🚨 PLUS DE DÉCALAGE (fondateur 2026-08-12 : « que ce soit décalé me
   dérange »). Elle sortait de 8 px à gauche et penchait de 1° : composition
   « en triangle » assumée à l'époque, lue aujourd'hui comme un défaut
   d'alignement. Elle est redressée, CENTRÉE sur la carte et descendue de 13 px
   (pas φ) pour dégager le départ Tour Eiffel qu'elle masquait. */
.rd-sched { position: absolute; left: 50%; translate: -50% 0; bottom: -13px;
  width: max-content; min-width: 62%; max-width: 100%; padding: 8px;
  transform: none; z-index: 3; box-shadow: 0 2px 5px rgba(32,29,21,.09), 0 18px 38px -13px rgba(25,44,134,.32); }
.rd-sched .rp-pills { gap: 6px; }
.rd-sched .rp-selpill { padding: 7px 9px; border-radius: 15px; gap: 6px; }
.rd-sched .rp-selpill--time { opacity: 1; }
.rd-sched .rp-bub { width: 23px; height: 23px; }
.rd-sched .rp-pi small { font-size: .5rem; }
.rd-sched .rp-pi b { font-size: .65625rem; padding-right: 2px; }
.rd-sched .rp-cta { margin-top: 8px; padding: 9px 0; font-size: .75rem; }
.rp-dot { width: 8px; height: 8px; border-radius: 50%; flex: none; }
.rp-dot--start { border: 2px solid #0066FF; background: transparent; }
.rp-dot--stop { background: #D97706; }
/* SchedulePickerV2 réel (concept v5) : pills pastel Date #D9E8FF / Heure #FFE4CF,
   bulle blanche + icône navy #0A1F3B, cartes-jour, CTA « Planifier » royal #0D47AB.
   SANS panneau de fond : les éléments flottent, comme dans la sheet de l'app. */
.rp-pills { display: flex; gap: 8px; }
.rp-selpill { flex: 1; display: flex; align-items: center; gap: 6px; padding: 8px 9px; border-radius: 21px; min-width: 0; }
.rp-selpill--date { background: #D9E8FF; }
.rp-selpill--time { background: #FFE4CF; opacity: .66; }
.rp-bub { width: 21px; height: 21px; border-radius: 50%; background: rgba(255,255,255,.88); display: grid; place-items: center; flex: none; }
.rp-pi { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.rp-pi small { font-size: .5625rem; font-weight: 700; letter-spacing: .05em; color: rgba(10,31,59,.55); }
.rp-pi b { font-size: .84375rem; font-weight: 700; letter-spacing: -.01em; color: #0A1F3B; white-space: nowrap; overflow: hidden; }
.rp-cta { display: block; text-align: center; background: #0D47AB; color: #fff; font-weight: 700; font-size: .8125rem; border-radius: 999px; padding: 12px 0; border: 1px solid rgba(6,21,43,.45); box-shadow: 0 5px 14px -6px rgba(10,31,59,.55); }
/* min-height 521 : exclut le téléphone couché (SE couché = 667×375, il matchait
   les deux blocs et la scène retombait à largeur fixe au lieu de 100 %). */
@media (min-width: 641px) and (max-width: 760px) and (min-height: 521px) {
  .sg-list, .xs-stack--sorted { margin-right: 0; }
  .ride-duo { align-self: center; }
  .exp-scene { width: clamp(230px,42vw,300px); }
}


/* ==== CHAMBRES (2026-08-10) — principe emprunté à Wispr Flow, TRADUIT dans la DA
   Fab : alternance de pièces claires/sombres aux coins très arrondis, séparées
   par leur seule couleur (pas de ligne). Couleurs = les nôtres (crème/navy/bleu),
   PAS celles de la référence (lavande, #ffffeb, EB Garamond) — on emprunte la
   STRUCTURE, jamais la charte d'un autre. Le remède au « 6000px de crème plat ». ==== */
.chamber { position: relative; border-radius: clamp(47px, 4.2vw, 55px); }
.chamber > .container { position: relative; z-index: 1; }
.chamber--light { background: var(--card); box-shadow: inset 0 0 0 1.5px var(--border); }
.chamber--dark { background: linear-gradient(172deg, #1B3A6B 0%, #0A1F3B 58%, #06152B 100%); color: #fff; }
.chamber--dark .h-section, .chamber--dark h2, .chamber--dark h3 { color: #fff; }
.chamber--dark .lead, .chamber--dark .muted, .chamber--dark p { color: rgba(255,253,246,.82); }
.chamber--dark .kicker { color: #fff; border-color: rgba(255,255,255,.38); background: rgba(255,255,255,.07); }
/* la marge latérale fait exister la pièce comme un objet posé sur le fond */
@media (min-width: 720px) { .chamber { margin-inline: clamp(13px, 2.6vw, 34px); } }
/* .chamber : squircle RETIRÉ le 13/08 — sur iOS 26 (corner-shape supporté) la superellipse rendait le plateau presque carré ; arc circulaire plein partout. */

/* FAQ en chambre sombre : accordéon relu pour le fond navy */
.chamber--dark .faq-item { background: rgba(255,255,255,.05); border-color: rgba(255,255,255,.12); }
.chamber--dark .faq-q { color: #fff; }
.chamber--dark .faq-q .chev { color: rgba(255,255,255,.65); }
.chamber--dark .faq-a-inner { color: rgba(255,253,246,.8); }
.chamber--dark .faq-a-inner a { color: #9FC0FF; }
.chamber--dark .faq-item.open { background: rgba(255,255,255,.08); }

/* les chambres ont besoin d'air autour d'elles (elles sont des objets, pas des bandes) */
.chamber { margin-block: clamp(34px, 5vw, 89px); }
.chamber + .chamber { margin-top: clamp(21px, 3vw, 55px); }



/* ==== SOCIAL v6 — LA CARTE SOUS LA TYPO (2026-08-11) ====
   Itération demandée : « le tapis on va en faire une map · l'écrire en bleu dans
   la bonne police · les vrais infos qu'on a dans Fab · le bouton télécharger pas
   nécessaire · les 3 cards de la vraie info pas les CTA moches · les flèches
   rendent mal ». Tout est appliqué.
   🚨 Le plateau reprend la RECETTE DU HERO : carte + voile crème rgba(244,237,220,.45),
   titre BLEU en Baloo, PLUS D'UPPERCASE — c'est la même langue, pas une variante. */
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0; }
.soc { padding-block: clamp(34px, 5vw, 55px); }

/* 🚨 PLAFOND DE LARGEUR (fondateur 2026-08-12, constat au dézoom : « une seule
   section s'étire »). C'était le SEUL bloc de la page sans `max-width` : à
   1920 il faisait 1852 quand tout le reste était borné à 1160, et à 2560 il
   atteignait 2492, soit 1332 de plus que ses voisins. Il rejoint la seule
   exception de gabarit déjà documentée, celle du plateau des apps (1320), au
   lieu d'inventer une troisième largeur. La forme `width: calc(...)` conserve
   les gouttières en petit écran, ce qu'un simple `margin-inline: auto` aurait
   supprimé. */
.soc-stage { position: relative; overflow: hidden; isolation: isolate;
  width: calc(100% - 2 * clamp(13px, 2.6vw, 34px)); max-width: 1320px;
  margin-inline: auto;
  padding: clamp(42px, 7vw, 89px) clamp(21px, 4vw, 55px) clamp(55px, 8vw, 100px);
  border-radius: clamp(47px, 4.2vw, 55px); background: var(--blue); color: #fff; }
/* .soc-stage : squircle RETIRÉ le 13/08 — même raison que .chamber. */
/* « reviens sans map, mets juste du bleu » : le plateau est un aplat bleu roi.
   Sa matière est celle de la BANDE BLEUE du site (`.cta-band`) — deux halos
   radiaux, l'un clair en haut-gauche, l'autre encré en bas-droite — pour que les
   deux surfaces bleues de la page parlent la même langue. */
.soc-stage::before { content: ''; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background: radial-gradient(55% 65% at 18% 0%, rgba(255,255,255,.16), transparent 60%),
              radial-gradient(45% 60% at 88% 105%, rgba(23,48,155,.85), transparent 60%); }

/* ---- LA TYPO : bleue, Baloo, casse normale (la langue du hero). Trois lignes,
   trois retraits — c'est le décalage qui compose. L'ombre reste EMPILÉE (le
   relief de la référence) mais dans un bleu clair, pas une masse sombre. ---- */
.soc-type { position: relative; z-index: 2; display: flex; flex-direction: column;
  align-items: flex-start; gap: clamp(2px, .4vw, 8px); }
/* 🚨 line-height 1.08, pas .92 : Baloo 2 porte des métriques très hautes et à
   .92 les glyphes débordaient de leurs boîtes de ligne — le haut de « Vos
   amis » était TRANCHÉ net, sur tous les moteurs. Vu le soir de la mise en
   ligne (13/08/2026), première fois que le chapitre passait sur mobile réel.
   1.08 est le plus serré qui laisse les lettres entières. */
.soc-line { display: block; font-family: var(--fd); font-weight: 800; line-height: 1.08;
  letter-spacing: -.028em; color: #FFFDF6;
  text-shadow: 1px 1px 0 var(--blue-ink), 2px 2px 0 var(--blue-ink), 3px 3px 0 var(--blue-ink),
    4px 4px 0 var(--blue-ink), 5px 5px 0 var(--blue-ink), 6px 6px 0 var(--blue-ink),
    7px 7px 0 var(--blue-ink), 8px 8px 0 var(--blue-ink), 9px 9px 0 var(--blue-ink),
    10px 10px 0 var(--blue-ink); }
/* 🚨 .3em d'air au-dessus de la ligne 1 : sur iOS réel (Core Text), les
   ascendantes de Baloo débordent de la boîte de ligne plus que sur les autres
   moteurs, et le sommet de « Vos amis » passait au-dessus du bord du bloc —
   tranché par l'overflow du plateau. Les lignes 2 et 3 peuvent déborder sur
   leurs voisines (c'est le style empilé) ; seule la 1re rencontre un bord. */
.soc-line--1 { font-size: clamp(2.4rem, 8.5vw, 6.5rem); margin-inline-start: 4%; margin-top: .3em; }
.soc-line--2 { font-size: clamp(3.1rem, 11.5vw, 9rem); align-self: center; }
.soc-line--3 { font-size: clamp(2.4rem, 8.5vw, 6.5rem); margin-inline-start: 24%; }
.soc-line .dot-blue { color: var(--p-yellow); }

/* ---- LES CARTES QUI FLOTTENT : elles cassent la typo. Sur fond clair le verre
   dépoli ne dit plus rien → carte crème pleine, ombre douce du site. Elles
   portent les CHAMPS RÉELS de la fiche ami : nom · fraîcheur · distance. ---- */
.soc-float { position: absolute; z-index: 3; width: clamp(132px, 15vw, 178px);
  display: flex; flex-direction: column; align-items: center; text-align: center;
  padding: clamp(13px, 1.6vw, 19px); border-radius: 32px; background: var(--card);
  box-shadow: 0 2px 5px rgba(32,29,21,.09), 0 34px 68px -22px rgba(25,44,134,.42);
  transition: transform .5s cubic-bezier(.16,1,.3,1); }
@supports (corner-shape: squircle) { .soc-float { corner-shape: squircle; } }
.soc-float b { display: block; font-family: var(--fd); font-weight: 800;
  font-size: clamp(.9375rem, 1.2vw, 1.0625rem); color: var(--ink); margin-top: 10px; }
.soc-float small { display: block; font-family: var(--fb); font-size: clamp(.6875rem, .85vw, .78rem);
  color: var(--muted); margin-top: 2px; }
.soc-ava { display: grid; place-items: center; width: clamp(55px, 6.5vw, 84px); aspect-ratio: 1;
  border-radius: 50%; overflow: hidden; }
.soc-ava img { width: 100%; height: 100%; object-fit: cover; }
.soc-float--a { inset-inline-start: 3%; bottom: 15%; transform: rotate(-9deg); }
.soc-float--b { inset-inline-end: 4%; top: 12%; transform: rotate(9deg); }
@media (hover: hover) { .soc-float:hover { transform: rotate(0deg) scale(1.03); } }
@media (prefers-reduced-motion: no-preference) {
  .soc.in .soc-float--a { animation: soc-drift 5.5s ease-in-out infinite; }
  .soc.in .soc-float--b { animation: soc-drift2 6.5s ease-in-out infinite 1s; }
  @keyframes soc-drift { 0%,100% { transform: rotate(-9deg) translateY(0); }
    50% { transform: rotate(-9deg) translateY(-14px); } }
  @keyframes soc-drift2 { 0%,100% { transform: rotate(9deg) translateY(0); }
    50% { transform: rotate(9deg) translateY(-19px); } }
}

.soc-lead { position: relative; z-index: 2; max-width: 46ch; margin: clamp(34px, 5vw, 55px) auto 0;
  text-align: center; font-size: clamp(1rem, 1.4vw, 1.1875rem); line-height: 1.618;
  color: rgba(255, 253, 246, .92); }

/* ---- LA SÉQUENCE : elle chevauche le plateau. Plus de flèches (« rendent mal »),
   plus de CTA inventé : chaque carte porte un VRAI OBJET du produit. ---- */
.soc-flow { position: relative; z-index: 5; display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr)); gap: clamp(13px, 1.8vw, 21px);
  margin-top: clamp(-89px, -7vw, -55px); align-items: stretch; }
.soc-step { display: flex; flex-direction: column; background: var(--card);
  border-radius: var(--radius-object); padding: clamp(21px, 2.6vw, 34px);
  box-shadow: 0 2px 5px rgba(32,29,21,.07), 0 34px 68px -26px rgba(25,44,134,.34); }
@supports (corner-shape: squircle) { .soc-step { corner-shape: squircle; } }
.soc-k { font-family: var(--fd); font-weight: 800; font-size: .8125rem; letter-spacing: .08em;
  color: var(--blue); margin-bottom: 8px; }
.soc-step h3 { font-family: var(--fd); font-weight: 800; font-size: clamp(1.125rem, 1.6vw, 1.3125rem);
  line-height: 1.272; letter-spacing: -.012em; margin: 0 0 10px; color: var(--ink); }
.soc-step p { font-size: .9375rem; line-height: 1.618; color: var(--muted); margin: 0; }


/* ---- LES TROIS CARTES, REFAITES (verdict : « c'est pas du tout bien »).
   Ce qui n'allait pas, précisément :
     · TROIS GRAMMAIRES DIFFÉRENTES — une pastille sombre, un panneau beige à
       rail, une fiche crème : trois widgets sans parenté ;
     · les objets étaient MINUSCULES (avatars 40 px, libellés 9,5 px) ;
     · la carte 2 en portait DEUX quand les autres en portaient un ;
     · et ils étaient posés EN BAS, comme des notes de pied de page.
   Correction : une PLAQUE de même taille EN TÊTE de chaque carte, un seul objet
   dedans, et le texte dessous. L'objet mène — c'est lui la preuve ; le texte
   explique. ---- */
/* 🚨 152 px ne suffisait PAS : les quatre rangées de la première plaque
   mesuraient 172 px, et `overflow: hidden` coupait le haut et le bas. C'est ce
   débordement silencieux qu'Alex a vu (« attention au padding »). 178 est une
   valeur du site, et 178/355 ≈ 0,5 sur la largeur de carte : la plaque respire
   sans écraser le texte dessous. Les trois plaques partagent la hauteur, sinon
   les titres des trois cartes ne s'alignent plus. */
.soc-plate { display: grid; place-items: center; height: 178px; margin-bottom: 21px;
  padding: 16px; border-radius: 21px; background: var(--card-3); overflow: hidden; }
.soc-plate--rail { align-content: center; gap: 13px; }

/* 01 — LES QUATRE PORTES D'ENTRÉE, toutes montrées. Deux boutons + une ligne de
   texte ne représentaient que la moitié de ce que dit la carte : « on peut aussi
   chercher le pseudo de son ami, donc je comprends pas la carte ». La plaque
   liste donc les quatre routes réelles de l'écran « Ajouter des amis », Fab Tap
   en tête parce que c'est la signature. */
.soc-plate--ways { display: flex; flex-direction: column; align-items: stretch;
  justify-content: center; gap: 5px; padding: 13px; }
/* 4 rangées de 34 + 3 gouttières de 5 + 26 de padding = 177, la plaque en fait
   178. Rangée = rayon 13, pas 26 : c'est une rangée de liste, pas un objet. */
.soc-way { display: flex; align-items: center; gap: 13px; min-height: 34px;
  padding: 5px 13px; border-radius: var(--radius-row); text-align: start; width: 100%;
  font-family: var(--fb); color: var(--ink); background: none; border: 0; cursor: pointer;
  transition: background .18s ease, color .18s ease, transform .18s cubic-bezier(.16,1,.3,1); }
@media (hover: hover) {
  .soc-way:not(.is-on):hover { background: rgba(34, 68, 204, .07); transform: translateX(2px); }
}
.soc-way:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; }
.soc-way svg { width: 17px; height: 17px; flex: none; color: var(--blue); }
.soc-way-t { min-width: 0; line-height: 1.2; }
.soc-way-t b { display: block; font-size: 12.5px; font-weight: 700; color: var(--ink); }
.soc-way-t small { display: block; font-size: 10.5px; font-weight: 500; color: var(--muted);
  margin-top: 1px; }
/* la route signature porte le bleu, les trois autres restent des lignes */
.soc-way.is-on { background: var(--blue); }
.soc-way.is-on svg { color: #fff; }
.soc-way.is-on .soc-way-t b { color: #fff; }
.soc-way.is-on .soc-way-t small { color: rgba(255,255,255,.8); }

/* 02 — le rail d'amis + le contrôle qui DÉMONTRE */
.soc-rail-l { display: flex; justify-content: center; gap: 10px; }
.soc-r { display: flex; flex-direction: column; align-items: center; gap: 5px; }
.soc-r img { width: 46px; height: 46px; border-radius: 50%; }
.soc-r small { font-family: var(--fb); font-size: 10.5px; font-weight: 600; color: var(--ink); }
/* la ligne d'état de l'app, à la place du bouton décoratif qui « n'apportait rien » */
.soc-vis { font-family: var(--fb); font-size: 11.5px; font-weight: 600; color: var(--muted); }

/* 03 — la fiche ami */
.soc-pop { display: grid; grid-template-columns: auto 1fr; column-gap: 12px; align-items: center;
  width: min(100%, 232px); padding: 13px 14px; border-radius: 16px; background: var(--card);
  font-family: var(--fb); box-shadow: 0 10px 24px -12px rgba(25,44,134,.4); }
.soc-pop-a { grid-row: 1 / 3; display: grid; place-items: center; width: 46px; aspect-ratio: 1;
  border-radius: 50%; overflow: hidden; }
.soc-pop-a img { width: 100%; height: 100%; object-fit: cover; }
.soc-pop b { font-size: 15px; font-weight: 700; color: var(--ink); align-self: end; }
.soc-pop small { font-size: 11.5px; color: var(--muted); align-self: start; }
.soc-pop-cta { grid-column: 1 / 3; display: inline-flex; align-items: center; justify-content: center;
  gap: 5px; height: 34px; margin-top: 12px; border-radius: 999px; background: var(--blue);
  color: #fff; font-size: 13px; font-weight: 700; }
.soc-pop-cta em { font-style: normal; font-weight: 600; color: rgba(255,255,255,.82); }
@media (max-width: 980px) {
  .soc-flow { grid-template-columns: minmax(0, 1fr); gap: 21px; margin-top: clamp(-55px,-5vw,-34px); }
}
@media (max-width: 720px) {
  .soc-float { position: static; width: auto; margin: 21px auto 0; transform: none !important;
    animation: none !important; flex-direction: row; gap: 13px; text-align: left; max-width: 290px; }
  .soc-float b, .soc-float small { margin-top: 0; }
  .soc-float--b { display: none; }
  .soc-line--3 { margin-inline-start: 10%; }
}

/* ==== GRAMMAIRE FRANCHE (2026-08-11) — la langue de la Cour propagée ====
   Verdict fondateur devant la section sociale : « clairement élégant, beau design
   qui raconte quelque chose », suivi d'un constat de cohérence. Décision : on garde
   ce style et on adapte le reste. Ce n'est pas un style étranger — c'est la DA du
   hero (sticker die-cut, bulle à bord franc, squircle). Le reste de la page était
   l'exception : filets de 1,5 px invisibles, ombres floues, cartes blanches posées
   sur du crème.
   Trois règles, partout : CONTOUR 3px encre · OMBRE DURE décalée 8px SANS FLOU ·
   BLOC DE COULEUR par idée. Et l'objet déborde de son bloc. */
.exp-card { border: 3px solid var(--ink); box-shadow: 8px 8px 0 var(--ink); overflow: visible; }
/* ==== ALTERNANCE BLEU ROI / CRÈME (2026-08-12, décision fondateur) ====
   Le pervenche `--p-blue` est SORTI : il était la seule fois du site où ce jeton
   servait de fond (ailleurs, toujours une touche : survol, petit bouton, halo),
   et il inventait une troisième voie entre le crème et le bleu roi. Le site a
   déjà une langue pour le « bloc bleu » : `#2244CC` plein, celui de `.soc-stage`
   et de `.cta-band`. Les cartes la parlent maintenant aussi.
   🚨 Ce sont les cartes 1, 3 et 5 qui sont bleues (`--a`), pas 2 et 4 : la suite
   commence ET finit sur le bleu. Les deux classes n'ont pas été renommées ni
   permutées dans le HTML des 2 homes, ce sont leurs RÔLES qui ont été échangés
   ici. Inverser à nouveau = échanger les deux fonds ci-dessous.
   🚨 Un aplat bleu roi n'est pas qu'un `background`, c'est une MATIÈRE : on
   reprend à l'identique celle des deux autres surfaces bleues (deux halos
   radiaux, un clair en haut-gauche, un encré en bas-droite), sinon les trois
   bleus de la page ne parlent pas la même langue. */
.exp-card--a { background: var(--blue); color: #FFFDF6; }
.exp-card--b { background: var(--card); }
.exp-card--a::before { content: ''; position: absolute; inset: 0; z-index: 0;
  pointer-events: none; border-radius: inherit;
  background: radial-gradient(55% 65% at 18% 0%, rgba(255,255,255,.16), transparent 60%),
              radial-gradient(45% 60% at 88% 105%, rgba(23,48,155,.85), transparent 60%); }
@supports (corner-shape: squircle) { .exp-card--a::before { corner-shape: squircle; } }
/* le contenu repasse au-dessus des halos */
.exp-card--a .exp-copy, .exp-card--a .exp-scene { position: relative; z-index: 1; }
/* 🚨 le texte se retourne, sinon l'encre chaude sur bleu roi tombe à 1,7:1.
   Mesuré : titre crème 7,46:1 · corps crème à 82 % 5,55:1 (seuils 3:1 et 4,5:1). */
.exp-card--a .exp-copy h3 { color: #FFFDF6; }
.exp-card--a .exp-copy p, .exp-card--a .muted { color: rgba(255,253,246,.82); }
.exp-card--a .exp-copy strong { color: #FFFDF6; }
/* 🚨 la pastille numérotée était bleue sur crème : sur bleu roi elle disparaît.
   Elle s'inverse (crème pleine, chiffre bleu) et garde le même contraste, 7,46:1. */
.exp-card--a .exp-n { background: var(--card); color: var(--blue); }
/* 2 teintes, pas 3 (fondateur) : crème · bleu · crème · bleu · crème. Le jaune
   puis le ciel sont sortis — l'identité, c'est crème + bleu, rien d'autre. */
.exp-card:nth-child(odd) { transform: rotate(-.5deg); }
.exp-card:nth-child(even) { transform: rotate(.5deg); }
/* les objets ajoutés aux nouvelles étapes tiennent dans la colonne de scène */
.exp-scene .fmv { margin: 0; }
.exp-scene .fp-offers { width: min(340px, 100%); margin: 0; display: grid; gap: 8px; }
.exp-scene .fp-offers .oc { min-height: 84px; padding: 10px 16px; }
.exp-scene .fp-offers .oc-car { width: 58px; height: 39px; }
.exp-scene .fp-offers .oc-price { font-size: 19px; }
/* le numéro devient une pastille die-cut, pas un rond pâle */
.exp-n { background: var(--blue); color: #fff; border: 2.5px solid var(--ink);
  box-shadow: 3px 3px 0 var(--ink); border-radius: 30%; }
/* l'objet de chaque étape DÉBORDE du bloc par la droite */
.exp-scene { margin-inline-end: -21px; }
/* les objets de scène prennent le contour franc et l'ombre dure */
.exp-card .frag-search, .exp-card .frag-sugg, .exp-card .xs-oc, .exp-card .rd-bar,
.exp-card .rd-card {
  border: 2.5px solid var(--ink); box-shadow: 4px 4px 0 var(--ink); }
.exp-card .rd-map { border: 2.5px solid var(--ink); box-shadow: 4px 4px 0 var(--ink); }
.exp-card .rp-selpill { border: 2px solid var(--ink); box-shadow: 2px 2px 0 var(--ink); }
.exp-card .rp-cta { border: 2.5px solid var(--ink); box-shadow: 3px 3px 0 var(--ink); }
@media (max-width: 1019px), (orientation: landscape) and (max-height: 520px) {
  .exp-scene { margin-inline-end: 0; }
  /* la scène est plus étroite : on resserre l'éventail, sinon les feuilles du
     fond sortent du bloc et ça passe pour un accident. */
  .fmv{width:min(258px,100%);height:268px}
  .fmv-city{top:28px;height:226px;padding:14px 14px 15px}
  .fmv-sheet{top:28px;height:172px}
  .fmv-sheet--1{transform:rotate(2.4deg) translate(6px,-12px)}
  .fmv-sheet--2{transform:rotate(5.2deg) translate(13px,-23px)}
  .fmv-name{font-size:19px}
}


/* ==== ADOUCISSEMENT (2026-08-11) — la matière du HERO, pas du néo-brutalisme ====
   Verdict fondateur, capture du hero à l'appui : « on s'égare, fais un style plus
   cohérent avec la landing page ». Ses références (sticker sheet, Superlist)
   m'avaient emmené vers le contour noir épais et l'ombre dure décalée. Or le hero
   ne fait RIEN de ça : la bulle bleue n'a aucun contour, les pills blanches ont un
   filet BLEU FIN, les ombres sont DOUCES et TEINTÉES. La couleur est forte, la
   matière est douce. On garde donc la COMPOSITION (blocs, débordements, objets
   réels) et on remplace la surface. */
.cr-blk, .exp-card, .fp-offers .oc, .fp-collage .fma, .fp-collage .fmb-hero,
.fp-collage .fmpl-bar, .fp-collage .shelf-icon, .fp-collage .fmb-stats,
.fp-collage .fmpl-plan, .fp-collage .fmpl-when, .fp-cats span, .fp-collage .fmb-eur,
.exp-card .frag-search, .exp-card .frag-sugg, .exp-card .xs-oc, .exp-card .rd-bar,
.exp-card .rd-card, .exp-card .rd-map, .exp-card .rp-selpill, .exp-card .rp-cta,
.cr-sticker, .cr-name, .cr-c2, .cr-join, .cr-wave, .cr-ping, .cr-moon, .cr-privacy,
.cr-card, .cr-medal, .cr-lendrow .shelf-icon, .exp-n, .exp-card .oc-tag,
.exp-card .oc-tag-cheap, .exp-card .oc-tag-promo {
  border-color: transparent; border-width: 0;
}
/* les blocs : pas de trait, une ombre douce teintée bleu (celle des cartes du site) */
.cr-blk, .exp-card {
  box-shadow: 0 2px 5px rgba(32, 29, 21, .07), 0 34px 68px -26px rgba(25, 44, 134, .32); }
.cr-blk--bilan, .cr-blk--card { box-shadow: 0 2px 5px rgba(6, 21, 43, .18), 0 34px 68px -24px rgba(6, 21, 43, .5); }
/* les objets posés dans les blocs : la même ombre, en plus courte */
.fp-offers .oc, .fp-collage .fma, .fp-collage .fmb-hero, .fp-collage .fmpl-bar,
.exp-card .frag-search, .exp-card .frag-sugg, .exp-card .xs-oc, .exp-card .rd-bar,
.exp-card .rd-card, .exp-card .rd-map, .cr-c2, .cr-card,
/* 🚨 AJOUTÉS LE 2026-08-12. Ces trois-là étaient dans la liste qui remet les
   BORDURES à zéro juste au-dessus, mais avaient été oubliés dans celle qui
   remplace les OMBRES. Résultat : les pastilles DATE/HEURE et le bouton
   « Planifier » traînaient encore un décalage d'encre plein (2px 2px 0 et
   3px 3px 0), c'est-à-dire le néo-brutalisme annulé le 11/08, et ils étaient
   les 3 seuls objets du site à le porter. Repéré à l'œil par le fondateur sur
   une capture de la carte 4. Leçon : quand un bloc annule une grammaire, la
   liste des bordures ET la liste des ombres doivent contenir les MÊMES
   sélecteurs, à vérifier une par une. */
.exp-card .rp-selpill, .exp-card .rp-cta {
  box-shadow: 0 2px 4px rgba(32, 29, 21, .08), 0 21px 42px -16px rgba(25, 44, 134, .3); }
/* les stickers die-cut gardent leur cadre blanc : c'est la découpe, pas un trait */
.cr-sticker { box-shadow: 0 2px 5px rgba(60, 40, 20, .16), 0 13px 26px -10px rgba(30, 20, 8, .26); }
.cr-medal, .cr-moon, .cr-wave, .cr-ping, .cr-name {
  box-shadow: 0 2px 4px rgba(60, 40, 20, .16), 0 8px 16px -6px rgba(30, 20, 8, .24); }
.fp-collage .shelf-icon, .cr-lendrow .shelf-icon, .exp-n {
  box-shadow: inset 0 1px 1px rgba(255, 255, 255, .34), inset 0 -1px 1px rgba(32, 29, 21, .22),
    0 2px 3px rgba(25, 44, 134, .12), 0 13px 24px -12px rgba(25, 44, 134, .4); }
/* les petites capsules reprennent le filet FIN des pills du hero */
.fp-cats span, .fp-collage .fmpl-plan, .fp-collage .fmpl-when {
  border: 1.5px solid rgba(34, 68, 204, .16); box-shadow: 0 1px 3px rgba(32, 29, 21, .07); }
.fp-collage .fmb-eur { white-space: nowrap; box-shadow: 0 2px 5px rgba(6, 21, 43, .3); }
.cr-privacy { border: 1.5px solid rgba(34, 68, 204, .18);
  box-shadow: 0 2px 5px rgba(32, 29, 21, .1), 0 16px 30px -14px rgba(25, 44, 134, .34); }
.cr-privacy:hover { transform: translateY(-2px);
  box-shadow: 0 3px 7px rgba(32, 29, 21, .12), 0 22px 38px -14px rgba(25, 44, 134, .4); }
.cr-privacy:active { transform: translateY(0); }
.cr-join { box-shadow: 0 2px 5px rgba(25, 44, 134, .3); }
.cr-map { border-top: 0; }
.cr-mapclip { border-radius: 21px; }
.cr-map { border-radius: 21px; overflow: visible; }

/* ==== FAQ EN DEUX PANNEAUX (2026-08-10 v7 — boîte + resserrage + scroll interne) ====
   Hiérarchie de la réf. reproduite dans la DA : page crème `--bg` → BOÎTE un ton
   plus soutenu `--bg-2` → panneau questions navy plein → bulle `--card` (la plus
   claire). Espacements resserrés (8/13/21) : la liste ne s'étire plus. La bulle
   scrolle en interne quand la réponse dépasse la hauteur de la boîte. */
/* 🚨 FOND RETIRÉ (fondateur 2026-08-12, même famille de défaut que la jonction
   du théâtre). Le fond de page porte DEUX calques d'atmosphère en
   `position: fixed` sous le contenu : les halos radiaux (`body::before`,
   z-index -2) et le grain SVG (`body::after`, -1, opacité .03). Un élément du
   flux avec un fond OPAQUE les recouvre. `.faq-section` peignait donc
   `var(--bg)`, exactement la couleur du body, ce qui n'ajoutait rien mais
   effaçait halos et grain sur toute sa hauteur : d'où une ligne franche à la
   frontière avec la section sociale, qui, elle, est transparente.
   🚨 Règle : ne JAMAIS repeindre `var(--bg)` sur une section. C'est déjà la
   couleur du body, et ça coupe l'atmosphère. */
.faq-section { background: none; }
/* la boîte sort du gabarit étroit (800 px) du chapitre pour reprendre le gabarit
   NORMAL du site (--maxw), celui de la bande App Store. `max-width: none` la
   laissait filer sur toute la largeur de la fenêtre : elle devenait alors le
   bloc le plus large de la page, plus large que le plateau social lui-même. */
.faq-section .container-tight { max-width: var(--maxw); }
/* remontée (fondateur 2026-08-10) : l'overline « Questions fréquentes » a sauté,
   la boîte remonte d'un cran φ (55 → 34). */
/* NAVY (fondateur 2026-08-11) : le bleu CTA posé ici le 10/08 faisait une masse
   saturée d'un mètre de haut. Premier essai en #0A1F3B → « trop navy » : ce ton
   vire au noir sur une aussi grande surface. On avait alors pris le navy de la
   CARTE DE MEMBRE (#173E86).
   🚨 RETOUR AU BLEU ROI le 2026-08-12, et cette fois AVEC LA MATIÈRE. #173E86
   venait d'une maquette et tirait 9° plus froid que le bleu roi des deux blocs
   voisins — c'était ça, « hors thème ». Premier remède : --blue-ink, la bonne
   teinte pressée d'un cran. Verdict du fondateur en regardant la page ENTIÈRE :
   « on se demande pourquoi le bleu du plateau de la FAQ n'est pas le bleu qui
   alterne depuis le début ». Il a raison, et j'avais mal lu l'alternance : elle
   ne va pas de royal à profond, elle va de PLAQUE BLEU ROI à FOND CRÈME. Le
   crème est l'autre TEMPS de la mesure, pas un intervalle. Une plaque d'un
   troisième bleu ne rate pas une nuance, elle rate une mesure.
   🚨 Et l'écart n'était pas que de valeur : le plateau social et la bande App
   Store portent DEUX HALOS RADIAUX, la FAQ était un aplat plat. Deux surfaces
   ne parlent la même langue que si elles ont la même PEAU. La boîte reprend
   donc le `::before` de `.soc-stage` / `.cta-band` à l'identique.
   Le refus du 10/08 (« masse saturée d'un mètre de haut ») ne se rejoue pas :
   l'objet a changé. Mesuré, le roi VISIBLE passe de 49 % de la boîte à 39 % —
   l'en-tête est entré dedans, la bulle de réponse remplit sa colonne, et les
   halos cassent l'aplat. La bande App Store ne bouge pas : elle n'est pas
   COLLÉE à la FAQ, un temps de crème les sépare. */
/* 🚨 LARGEUR = CELLE DE LA BANDE APP STORE, pas une troisième. Mesuré à 1440 px
   avant correction : plateau social 1320 (bord à 60), boîte FAQ 1000 (bord à
   220), bande App Store 1108 (bord à 166) — trois blocs empilés, trois bords
   gauches différents, un escalier. La boîte lâche son max-width de 1000 et
   prend le gabarit `.container` comme la bande : il ne reste que DEUX bords
   dans le pied de page, celui du plateau (volontairement plus large) et celui
   du contenu. Voir §4ter des guidelines. */
.faq-box { position: relative; overflow: hidden; isolation: isolate;
  margin: 34px auto 0; background: var(--blue);
  border-radius: 34px; padding: 21px; }
.faq-box::before { content: ''; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background: radial-gradient(55% 65% at 18% 0%, rgba(255,255,255,.16), transparent 60%),
              radial-gradient(45% 60% at 88% 105%, rgba(23,48,155,.85), transparent 60%); }
/* le contenu repasse au-dessus des halos — même geste que `.soc-type` */
.faq-hd, .faq-split { position: relative; z-index: 1; }
@supports (corner-shape: squircle) { .faq-box { corner-shape: squircle; } }

/* ---------------------------------------------------------------------------
   §37 — LE TITRE ENTRE DANS LA BOÎTE (fondateur 2026-08-12, « le titre et le
   sous-titre pas intégrés »)
   La boîte est un OBJET : elle a sa coque, ses deux panneaux, ses libellés de
   colonne. Elle se suffit. Le `.section-head` posé 55 px au-dessus, centré sur
   la crème, n'avait donc rien à quoi s'accrocher : deux blocs voisins qui ne se
   touchent pas et ne se ressemblent pas. Le titre devient l'EN-TÊTE de l'objet.
   🚨 CENTRÉ, PAS EN DEUX COLONNES (fondateur 2026-08-12, « la disposition des
   textes me convient pas »). Premier montage : titre sur la colonne questions,
   chapô sur la colonne réponse, alignés par la ligne de base. Mesuré ensuite,
   la FAQ et la bande App Store portent EXACTEMENT la même paire typographique
   — titre 42/800 Baloo, chapô 21/400 Outfit — et ne diffèrent que par une
   chose : la bande centre, la FAQ coupait en deux. C'était le seul intrus des
   trois plaques. Et l'en-tête contredisait son propre corps : à gauche un titre
   court sur une ligne, à droite un paragraphe dense sur trois, quand en dessous
   c'est l'inverse (colonne gauche pleine, colonne droite creuse).
   🚨 Le titre reste un `<h2>` réel : c'est le seul titre de section de ce
   chapitre, le sortir du flux sémantique casserait le plan de la page. */
/* les 34 px de marge haute servaient à séparer la boîte du titre ; le titre est
   dedans, la marge n'a plus d'objet. Elle reste pour la page /faq/, dont la
   boîte suit un vrai `<h1>` de page (`.article-head`) et n'a pas d'en-tête. */
.faq-box:has(.faq-hd) { margin-top: 0; }
.faq-hd { display: grid; justify-items: center; text-align: center;
  gap: 8px; padding: 13px 8px 0; margin-bottom: 34px; }
.faq-hd h2 { color: #FFFDF6; margin: 0; text-wrap: balance; }
/* le chapô quitte la crème : il ne peut plus porter --ink-2 (et surtout pas
   --muted, qui est un brun). Sur bleu on atténue en crème translucide — et pas
   n'importe laquelle : EXACTEMENT celle du chapô du plateau social (`.soc-lead`,
   .92). Même plaque, même traitement de texte, sinon la parenté s'arrête à la
   couleur de fond. À .78 le contraste tombait à 5,16:1 ; à .92 il est à 6,55.
   🚨 21 → 18 px : à 21 il pesait le même rang que le titre de la bande App Store
   alors qu'il n'annonce qu'une liste. À 18 il parle au rang des RÉPONSES
   (`.fa-bubble`, 18 px) — ce qu'il est : du texte de contenu, pas un second
   titre. Le fondateur peut le supprimer d'une ligne (`display: none`) : la
   maquette « titre seul » ramenait la boîte à 543 px. Conservé parce que
   supprimer de la copie référencée est SA décision, pas la mienne. */
.faq-hd .faq-lead { max-width: 58ch; margin: 0; text-align: center;
  font-size: clamp(1rem, 1.25vw, 1.125rem); color: rgba(255,253,246,.92); }
/* 🚨 HAUTEUR PLAFONNÉE, PAS UNE FRACTION D'ÉCRAN. En 55vh la boîte grandissait
   avec la fenêtre : sur un grand écran elle montait à 640 px et écrasait tout.
   Le vh ne sert qu'à RÉTRÉCIR sur écran court, jamais à faire grandir.
   🚨 DESCENDUE DE 578 À 466 (2026-08-12). La grille était calée sur la réponse
   la plus LONGUE, donc creuse au repos : mesuré sur les 22 réponses, la bulle
   était remplie à 44 % en médiane et 17 réponses sur 22 en occupaient moins de
   la moitié — 230 px de crème vide sur la réponse d'ouverture. Et la boîte
   culminait à 708 px quand la bande App Store en fait 505. On dimensionne
   désormais pour la MÉDIANE ; les 5 réponses longues défilent, ce que le fondu
   de bord annonce déjà. 466 est une valeur calée à l'œil, comme l'était 578 :
   la gamme φ ne s'applique pas à une hauteur de scène (cf. §9). */
.faq-split { display: grid; grid-template-columns: minmax(0, .92fr) minmax(0, 1.08fr);
  gap: 21px; align-items: stretch; height: clamp(377px, 46vh, 466px); }
.faq-col { min-width: 0; min-height: 0; }
/* 🚨 PAS DE QUATRIÈME TOKEN. Le panneau questions descend d'un cran en
   ASSOMBRISSANT SA PROPRE COQUE (voile noir pur) : un voile noir ne déplace pas
   la teinte, il ne fait que baisser la valeur — le panneau reste donc à 228°,
   exactement comme la coque. C'est ce qu'on n'avait pas fait en piochant
   --blue-deep (220°), qui ajoutait une seconde teinte À L'INTÉRIEUR de la boîte.
   .32 et pas .40 : à .40 l'écart coque/panneau passait de 2,1× à 2,7× et le
   panneau virait au noir. À .32 il est à 2,21 % de luminance — exactement le
   rapport qu'avait --blue-deep sous l'ancienne coque. Contraste texte 8,7:1.
   🚨 LE FOND EST DESCENDU SUR `.faq-qlist`, PAS SUR LA COLONNE. Tant qu'il
   vivait sur `.faq-col--q`, le libellé « Questions » était DANS le panneau
   quand « Réponse » était DEHORS, sur le bleu : 13 px d'écart entre deux
   libellés censés être jumeaux, et deux panneaux qui ne commençaient pas à la
   même hauteur. `.faq-qlist` est précisément la zone SOUS le libellé, donc le
   miroir exact de la bulle de réponse. Les deux colonnes se lisent maintenant
   pareil : un libellé sur le bleu, puis un panneau pleine hauteur. */
.faq-col--q { display: flex; flex-direction: column; min-height: 0; }
.faq-qlist { background: rgba(0,0,0,.32); border-radius: 26px; overflow: hidden; }
.faq-qscroll::-webkit-scrollbar { width: 8px; }
.faq-qscroll::-webkit-scrollbar-thumb { background: rgba(255,253,246,.20); border-radius: 8px; }
.faq-qscroll::-webkit-scrollbar-track { background: transparent; }
@supports (corner-shape: squircle) { .faq-qlist { corner-shape: squircle; } }
.faq-col--a { display: flex; flex-direction: column; min-height: 0; }
/* 🚨 DES SURTITRES, PAS DES TITRES (2026-08-12). Ils étaient en Baloo 21 px/600,
   soit le POIDS du chapô (21 px/400) en plus lourd : une étiquette de colonne
   pesait davantage que le paragraphe au-dessus d'elle, et la boîte affichait
   trois rangs de texte avant le premier contenu. Ils reprennent la recette de
   surtitre déjà écrite dans cette feuille (13 px, 600, .12em, capitales) et
   passent en Outfit — ce sont des étiquettes, pas de la voix.
   ⚠️ La règle `.faq-section .overline` appelle `var(--fs)`, un token qui
   N'EXISTE PAS dans la feuille : ne pas la copier telle quelle, elle retombe
   silencieusement sur la police héritée. Ici on écrit `--fb` (Outfit).
   Une seule couleur pour les deux : ce sont des jumeaux, ils n'ont pas à
   diverger d'un blanc à l'autre. #E3EAF6 sur bleu roi = 6,28:1. */
.faq-col-label { font-family: var(--fb); font-weight: 600; font-size: .8125rem;
  line-height: 1.2; letter-spacing: .12em; text-transform: uppercase;
  color: #E3EAF6; margin: 0 8px 13px; }

/* 🚨 poids CONSTANT : passer de 500 à 600 à la sélection élargit le texte et le
   recompose (« les mots changent de place ») — la sélection se lit au FOND seul. */
/* 🚨 17 → 18 px : la liste est le MÉCANISME de la boîte, elle ne peut pas être
   écrite plus petit que le texte qu'elle sert. Les réponses sont à 18 px : on
   lit et on clique au même rang, et le 600 des questions fait la différence. */
.fq { display: block; width: 100%; text-align: left; background: none; border: 0; cursor: pointer;
  font: inherit; font-size: 1.125rem; font-weight: 600; line-height: 1.35; color: #C6D4E8;
  padding: 14px 15px; border-radius: 13px; transition: background .16s ease, color .16s ease; }
/* 🚨 le survol REPREND LA COQUE, il n'invente pas un bleu de plus. C'est la règle
   déjà posée en v4 : « un ton plus clair du panneau », pas une couleur vive.
   #1E4A9E et #2A5AB5 étaient deux royaux fabriqués pour l'occasion. Comme le
   panneau est la coque assombrie, survoler revient littéralement à retirer le
   voile — d'où `--blue`, la valeur de la coque. */
.fq:hover { background: var(--blue); color: #fff; }
.fq:focus { outline: none; }
.fq:focus-visible { outline: 2px solid #9FC0FF; outline-offset: -2px; }
.fq.is-active { background: var(--card); color: var(--ink); }
/* l'élément actif est déjà identifié par son fond : pas d'anneau par-dessus */
.fq.is-active:focus-visible { outline: none; }
.fq + .fq { margin-top: 8px; }

/* 🚨 SCROLL INTERNE : la bulle doit être SORTIE DU FLUX, sinon elle fait grandir
   la ligne de grille au lieu de scroller. `.fa-stack` occupe la place (flex:1) et
   les réponses sont posées en absolu dedans → la hauteur de la ligne est dictée
   par la colonne QUESTIONS, et le texte long scrolle dans la bulle. */
.fa-stack { position: relative; flex: 1; min-height: 0; }
.fa[hidden] { display: none; }
/* le FOND vit sur `.fa` (il reste plein), le masque ne s'applique qu'au CONTENU
   qui défile — sinon le fondu ronge la carte et laisse voir le navy au travers. */
/* 🚨 LA BULLE OCCUPE TOUTE LA COLONNE (2026-08-12). En `inset: 0 0 auto 0` elle
   épousait la hauteur du texte : sur la réponse d'ouverture, mesuré 262 px de
   bulle pour 504 px de colonne, soit 194 px de bleu VIDE en bas à droite — le
   creux qu'on voit sur la capture du fondateur. La boîte se lisait comme un
   panneau plein à gauche et un aplat troué à droite. En `inset: 0` les deux
   panneaux font la même hauteur : l'objet redevient symétrique, quelle que soit
   la longueur de la réponse. Le texte, lui, reste calé en haut et défile. */
.fa { position: absolute; inset: 0; display: flex; background: var(--card);
  border-radius: 26px; overflow: hidden; animation: fa-fade .28s ease; }
@supports (corner-shape: squircle) { .fa { corner-shape: squircle; } }
.fa-bubble { flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: auto;
  color: var(--ink-2); padding: 29px 26px; font-size: 1.125rem; line-height: 1.618; }
@keyframes fa-fade { from { opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .fa { animation: none; } }
.fa-bubble p { color: var(--ink-2); }
.fa-bubble a { color: var(--blue); text-decoration: underline; text-underline-offset: 2px; }
.fa-bubble::-webkit-scrollbar { width: 8px; }
.fa-bubble::-webkit-scrollbar-thumb { background: var(--border); border-radius: 8px; }
.fa-bubble::-webkit-scrollbar-track { background: transparent; }

.faq-more { text-align: center; margin: 21px 0 0; }
.faq-more a { font-family: var(--fs); font-weight: 600; font-size: .875rem; color: rgba(255,253,246,.82);
  text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 1px; }
.faq-more a:hover { color: #fff; }

/* LE BORD EST LE FONDU (pas un masque ajouté : un masque ronge les éléments et
   laisse voir le fond au travers). Un voile de la COULEUR DU PANNEAU est posé
   par-dessus le contenu qui défile, en haut et en bas. 34 = φ. */
.faq-qlist { position: relative; flex: 1; min-height: 0; }
/* respiration = hauteur du voile : au repos, rien n'est jamais recouvert ; dès
   qu'on défile, le texte passe dessous et s'efface dans le bord. */
/* le padding horizontal était porté par `.faq-col--q` (13 px) ; le fond ayant
   migré sur `.faq-qlist`, c'est la zone défilante qui le reprend : 13 à gauche,
   21 à droite pour laisser passer la barre de défilement comme avant. */
.faq-qscroll { height: 100%; overflow-y: auto; overscroll-behavior: auto;
  padding: 34px 21px 34px 13px; }
/* Le fondu EFFACE le contenu (masque), il ne le recouvre pas : un voile opaque
   posé par-dessus assombrissait la question active (carte crème) — rejeté.
   Le masque ne touche QUE les zones qui défilent ; les fonds vivent sur leurs
   parents (`.faq-col--q`, `.fa`) et restent donc intacts. */
.faq-qscroll, .fa-bubble {
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 34px, #000 calc(100% - 34px), transparent 100%);
  mask-image: linear-gradient(to bottom, transparent 0, #000 34px, #000 calc(100% - 34px), transparent 100%); }
/* φ : le lead de la FAQ était à 17px (hors gamme) → il reprend EXACTEMENT le clamp
   du `.lead` du site (16 → 21) et l'interligne de corps 1.618. */
.faq-lead { max-width: 610px; margin: 13px auto 0; text-align: center; color: var(--ink-2);
  font-size: clamp(1rem, 1.5vw, 1.3125rem); line-height: 1.618; }
.faq-section .overline { font-family: var(--fs); font-weight: 600; font-size: .8125rem;
  letter-spacing: .12em; text-transform: uppercase; color: var(--muted); margin: 0 0 13px; }

@media (max-width: 1019px), (orientation: landscape) and (max-height: 520px) {
  /* l'en-tête est déjà centré sur une colonne : il ne reste que la respiration
     à resserrer. Le chapô lâche son plafond de 58ch, la colonne est plus étroite
     que lui de toute façon. */
  .faq-hd { gap: 8px; margin-bottom: 21px; padding: 8px 8px 0; }
  .faq-hd .faq-lead { max-width: none; }
  .faq-split { grid-template-columns: 1fr; height: auto; }
  .faq-qlist { max-height: 233px; }
  /* 🚨 sur une colonne, la réponse SORT de sa cage : elle prend sa hauteur et
     c'est la page qui défile. Faire défiler cinq lignes dans une carte de
     288 px était déjà pénible en 16 px ; en 18 px (textes grossis 2026-08-11)
     c'était intenable — toutes les réponses étaient coupées. */
  .fa-stack { flex: none; min-height: 0; }
  .fa { position: static; max-height: none; }
  .fa-bubble { overflow: visible; -webkit-mask-image: none; mask-image: none; padding: 21px 21px 23px; }
}

/* ==== APPS — LE CATALOGUE (2026-08-11, passe 4) ============================
   Modèle : « Clay — Integrations catalog ». Mécaniques reprises, skin jamais :
   Clay est en dark, Fab reste crème, le bleu par TOUCHES (puce de type, loupe,
   compteur, focus) — le plateau navy a été rejeté net.

   Échelle φ partout : profondeurs 144 → 89 → 55 (rapport 1,618 exact), rayons
   21/34/55, gouttières 13/21/34, logo 55/47, hauteur de liste 610. */

/* ---- LE PLATEAU : un seul objet, TITRE COMPRIS. 🚨 Le titre vivait sur la
   carte du monde : les tracés et les noms de villes (« Los Angeles », « Dubaï »)
   passaient à travers le texte. Un titre ne se pose pas sur un décor animé, il
   entre dans l'objet qu'il nomme. ---- */
/* 🚨 Exception de largeur assumée : le conteneur du site est à 1160 (`--maxw`),
   ce plateau va à 1320. Demandé pour que la section « prenne moins de hauteur » :
   plus large = 4 colonnes au lieu de 3 = 10 rangées au lieu de 13. C'est le seul
   endroit du site qui déborde du gabarit, parce que c'est le seul qui porte un
   inventaire de 38 lignes. */
.apps .container { max-width: min(1320px, 100%); }
.ap-stage-wrap { position: relative; max-width: 100%;
  margin: clamp(21px, 3.4vw, 55px) auto 0; padding: clamp(21px, 2.6vw, 34px);
  background: var(--card); border-radius: clamp(47px, 4.2vw, 55px);
  box-shadow: 0 2px 5px rgba(32,29,21,.06), 0 34px 89px -40px rgba(25,44,134,.34); }
/* .ap-stage-wrap : squircle RETIRÉ le 13/08 — même raison que .soc-stage. */
.apps .ap-top { max-width: 720px; margin: clamp(13px, 1.6vw, 21px) auto 0; text-align: center; }
.ap-title { font-family: var(--fd); font-weight: 800; letter-spacing: -.02em;
  font-size: clamp(1.625rem, 3vw, 2.375rem); line-height: 1.15; color: var(--ink); margin: 0; }
.ap-lead { max-width: 54ch; margin: 13px auto 0; font-size: clamp(.9375rem, 1.3vw, 1.1875rem);
  line-height: 1.618; color: var(--muted); }

/* ---- L'AMAS : gros, serré, à trois profondeurs φ. 🚨 Positions posées à la
   main — c'est l'irrégularité qui fait la perspective, jamais une grille. ---- */
.ap-cluster { position: relative; overflow: hidden; isolation: isolate;
  height: clamp(150px, 32vw, 466px); margin-top: clamp(13px, 1.6vw, 21px);
  border-radius: clamp(21px, 2.6vw, 34px);
  background: radial-gradient(72% 62% at 50% 36%, var(--p-blue) 0%, var(--card-2) 62%); }
/* La scène prend toute la boîte élargie. 🚨 Elle a été REDENSIFIÉE en même
   temps (21 → 31 pastilles) : les positions étant en %, élargir sans ajouter de
   pastilles les aurait écartées et aurait détruit le serrage. Nombre calculé,
   pas au jugé — à 1200 px de large, 8 pastilles de 144 donnent un entraxe de
   147 px, soit 3 px d'écart entre les bords. */
.ap-stage { position: absolute; inset: 0; z-index: 1; }
.ap-ico { position: absolute; left: var(--x); top: var(--y);
  width: calc(var(--sz) * var(--s, 1)); height: calc(var(--sz) * var(--s, 1));
  margin: calc(var(--sz) * var(--s, 1) / -2) 0 0 calc(var(--sz) * var(--s, 1) / -2);
  display: grid; place-items: center; border-radius: 22.37%; overflow: hidden;
  transform: rotate(var(--r, 0deg));
  box-shadow: 0 calc(var(--sz) * .05) calc(var(--sz) * .09) calc(var(--sz) * -.04) rgba(32,29,21,.16),
    0 calc(var(--sz) * .16) calc(var(--sz) * .26) calc(var(--sz) * -.11) rgba(25,44,134,.24); }
@supports (corner-shape: squircle) { .ap-ico { corner-shape: squircle; } }
.ap-ico img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
/* 🚨 AUCUN effet de bord sur les pastilles. Quatre sources supprimées :
   · le vernis iOS en `::after` — les icônes de l'App Store portent DÉJÀ leur
     traitement, en rajouter un salit le bord ;
   · le liseré — c'est l'ombre portée qui détache une icône blanche (G7, Waymo,
     Grab) d'un fond clair, pas un trait de 1 px ;
   · `background: var(--pc)` sous l'image — l'antialiasing de l'arrondi sur un
     élément TOURNÉ en laissait fuiter un pixel, d'une teinte différente de
     l'illustration ;
   · la teinte `--pc` dans l'ombre — 21 marques = 21 ombres colorées = un
     frangeage tout autour de l'amas. L'ombre est neutre.
   (Le 5e cas, le plus retors, n'était pas du CSS : dix illustrations arrivent
   DÉJÀ MASQUÉES de l'App Store. Rognées à la source par `demask.py`.)

   🚨 Et plus AUCUN `filter: blur()` sur les plans lointains : sur fond CLAIR un
   flou déborde du bord arrondi et donne un halo de sticker mal découpé. Sur le
   noir de la référence il se fondait, ici il se voit. */
/* 🚨 Les PLANCHERS des clamp() sont bas exprès. Avec un plancher à 76 px, à
   390 px de large les 8 pastilles du premier plan s'empilaient en tas : 10vw
   valait 39 px mais le plancher reprenait la main. Les trois planchers gardent
   le rapport φ (34 / 21 / 13), donc la constellation rétrécit sans se déformer.
   Vérifié de 390 à 1500 px : le rapport reste entre 1,61 et 1,63, et l'entraxe
   du premier plan colle à la taille de pastille à moins de 15 px près. */
.ap-t0 { --sz: clamp(34px, 10vw, 144px); z-index: 3; }
/* 🚨 Les plans lointains sont EFFACÉS, pas TRANSPARENTS (demande explicite :
   « je ne veux pas les voir transparentes, mais un peu plus effacées »).
   `opacity` laisse voir au travers ; un filtre délave la pastille tout en la
   gardant pleine — c'est le voile d'atmosphère, pas un calque translucide. */
.ap-t1 { --sz: clamp(21px, 6.2vw, 89px); z-index: 2;
  filter: saturate(.84) brightness(1.05) contrast(.93); }
.ap-t2 { --sz: clamp(13px, 3.8vw, 55px); z-index: 1;
  filter: saturate(.62) brightness(1.11) contrast(.84); }

/* le miroir, revenu au reflet PLEIN demandé (« le reflet miroir était mieux
   avant »), à l'opacité d'alors. Seul le flou est monté à 4,5 px : à 2,6 px on
   LISAIT « Bolt » et « leCab » à l'envers, et un reflet lisible passe pour une
   erreur. C'est le compromis entre les deux remarques (« mal faits » puis
   « mieux avant ») : la présence d'avant, sans le doublon lisible. Deux détails le séparent malgré tout d'un doublon flou :
   · 🚨 il GARDE sa classe de plan, qui porte `--sz` — sans elle,
     `width: calc(var(--sz) * var(--s))` est invalide et le reflet n'a AUCUNE
     taille (il avait purement disparu) ;
   · 🚨 un miroir de sol RENVERSE l'inclinaison : `rotate(r) scaleY(-1)` gardait
     +r, le reflet penchait à 2r de sa pastille. Il faut -r. */
.ap-mirror { position: absolute; inset: 0; z-index: 0; pointer-events: none; }
.ap-refl { top: calc(var(--y) + var(--sz) * var(--s, 1)); opacity: .21; filter: blur(4.5px);
  box-shadow: none; transform: rotate(calc(var(--r, 0deg) * -1)) scaleY(-1);
  -webkit-mask-image: linear-gradient(to top, transparent 6%, #000 82%);
  mask-image: linear-gradient(to top, transparent 6%, #000 82%); }

/* ---- LE CHERCHEUR : un champ CENTRÉ qui s'ouvre au clic ----
   🚨 Quatre versions rejetées avant celle-ci : la pilule, le rectangle à liseré
   bleu de l'app (juste à 350 px, mur bleu à 1120), le champ de 377 px avec un
   compteur à l'autre bout, puis le panneau beige qui empilait trois surfaces
   (« pas fan de la DA adoptée »). Ce qui reste : **plus de meuble**. Le champ
   est petit, centré, et ne grandit QU'AU CLIC, avec un vrai volet de
   suggestions — pas des pastilles.
   🚨 `[hidden]` réaffirmé pour toute la section : 3 fois qu'un `display:` de
   classe bat la règle UA et laisse voir un élément masqué. */
.apps [hidden] { display: none !important; }

.ap-finder { margin-top: clamp(21px, 2.6vw, 34px); }
.ap-bar { display: flex; justify-content: center; }
/* le morphing : au repos 377, ouvert 610 — deux nombres de la série φ. Le volet
   est en `absolute`, donc l'ouverture ne pousse RIEN : la liste ne bouge pas. */
.ap-combo { position: relative; width: min(377px, 100%); z-index: 6;
  transition: width .3s cubic-bezier(.16,1,.3,1); }
.ap-combo:focus-within, .ap-combo.is-open { width: min(610px, 100%); }
.ap-search { position: relative; display: flex; align-items: center; gap: 13px; height: 55px;
  padding-inline: 18px; background: var(--card); border-radius: 999px;
  border: 1.5px solid rgba(34,68,204,.14);
  box-shadow: 0 1px 2px rgba(32,29,21,.05), 0 13px 26px -18px rgba(25,44,134,.45);
  transition: border-color .2s ease, box-shadow .2s ease, border-radius .3s ease; }
.ap-combo:focus-within .ap-search, .ap-combo.is-open .ap-search {
  border-color: var(--blue); border-radius: 26px;
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--blue) 12%, transparent),
    0 21px 42px -22px rgba(25,44,134,.5); }
.ap-mag { width: 20px; height: 20px; flex: none; color: var(--blue); }
.ap-q { flex: 1; min-width: 0; border: 0; background: none; outline: none;
  font-family: var(--fb); font-size: 15px; font-weight: 600; color: var(--ink); }
.ap-q::placeholder { color: var(--muted); font-weight: 500; }
.ap-q::-webkit-search-cancel-button { display: none; }
.ap-clear { flex: none; width: 26px; height: 26px; display: grid; place-items: center;
  border: 0; border-radius: 50%; cursor: pointer; font-size: 17px; line-height: 1;
  background: var(--p-blue); color: var(--blue-ink); }
.ap-clear:hover { background: color-mix(in srgb, var(--blue) 22%, transparent); }

/* ---- LE VOLET DE SUGGESTIONS : de vraies lignes, avec le logo de l'app ou une
   épingle pour un lieu. Il APPREND ce qui est cherchable — sans lui, personne
   ne devine qu'on peut taper un pays. ---- */
.ap-sugg { position: absolute; top: calc(100% + 8px); inset-inline: 0; z-index: 7;
  background: var(--card); border-radius: 21px; padding: 8px;
  box-shadow: 0 2px 6px rgba(32,29,21,.08), 0 26px 55px -26px rgba(25,44,134,.5);
  animation: ap-drop .22s cubic-bezier(.16,1,.3,1); max-height: 340px; overflow-y: auto;
  scrollbar-width: thin; scrollbar-color: rgba(34,68,204,.26) transparent; }
@supports (corner-shape: squircle) { .ap-sugg { corner-shape: squircle; } }
@keyframes ap-drop { from { opacity: 0; transform: translateY(-6px); } }
.ap-sh { margin: 5px 13px 8px; font-family: var(--fb); font-size: 11px; font-weight: 700;
  letter-spacing: .07em; text-transform: uppercase; color: var(--muted); }
.ap-opt { display: flex; align-items: center; gap: 13px; width: 100%; padding: 8px 13px;
  border: 0; background: none; cursor: pointer; font: inherit; text-align: left;
  border-radius: 13px; }
.ap-opt:hover, .ap-opt.is-cur { background: var(--card-2); }
.ap-opt img { width: 34px; height: 34px; flex: none; border-radius: 22.37%;
  box-shadow: 0 1px 3px rgba(32,29,21,.16); }
/* 🚨 `.ap-opt span` (0,1,1) écrasait le `flex:none` de `.ap-pin` (0,1,0) :
   l'épingle s'étirait en ellipse. Le libellé a sa propre classe. */
.ap-pin { width: 34px; height: 34px; flex: none; display: grid; place-items: center;
  border-radius: 50%; background: var(--p-blue); color: var(--blue-ink); }
.ap-pin svg { width: 17px; height: 17px; display: block; }
.ap-olab { flex: 1; min-width: 0; font-family: var(--fb); font-size: 14.5px;
  font-weight: 700; color: var(--ink); overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; }
.ap-opt i { flex: none; font-style: normal; font-family: var(--fb); font-size: 11.5px;
  font-weight: 600; color: var(--muted); }

.ap-count { margin: 16px 0 0; text-align: center; font-family: var(--fb); font-size: 13px;
  font-weight: 700; color: var(--muted); font-variant-numeric: tabular-nums; }

/* ---- LA ZONE QUI DÉFILE ----
   🚨 `height`, pas `max-height` : la boîte se rétractait à chaque frappe et
   toute la page sautait. Une zone de résultats garde SA taille. */
.ap-view { position: relative; margin-top: 13px; }
.ap-view::before, .ap-view::after { content: ''; position: absolute; inset-inline: 0;
  height: 42px; z-index: 2; pointer-events: none; opacity: 0; transition: opacity .2s ease; }
.ap-view::before { top: 0; background: linear-gradient(var(--card), transparent); }
.ap-view::after { bottom: 0; background: linear-gradient(transparent, var(--card)); }
.ap-view.has-up::before, .ap-view.has-down::after { opacity: 1; }
.ap-scroll { height: calc(73px * 4 + 8px * 3); overflow-y: auto; overscroll-behavior: auto;
  scrollbar-width: thin; scrollbar-color: rgba(34,68,204,.28) transparent; }
.ap-scroll::-webkit-scrollbar { width: 10px; }
.ap-scroll::-webkit-scrollbar-thumb { background: rgba(34,68,204,.26); border-radius: 99px;
  border: 3px solid transparent; background-clip: padding-box; }
.ap-list { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  grid-auto-rows: 73px; gap: 8px; padding-inline-end: 13px; }

/* ---- LES EMPLACEMENTS VIDES ----
   🚨 Demandé : « quand on n'a pas de résultat, plutôt que d'afficher 2 résultats
   seulement, mets des ghost cards. » Première version rejetée : « pas forcément
   en card, juste les éléments » — des blocs beiges pleins faisaient une masse
   grise en damier, plus lourde que le vide qu'ils comblaient.
   Ici il n'y a PLUS DE CARTE : juste l'empreinte du contenu (le carré du logo,
   deux barres de texte), posée sur rien. Et la teinte quitte le beige `--card-3`
   pour un voile de bleu Fab très dilué : sur de la crème, un gris beige lit
   « sale », un bleu dilué lit « en attente ».
   Ce ne sont pas des squelettes de chargement : rien ne charge, donc aucune
   animation, aucun miroitement. */
.ap-ghost { position: relative; background: none; }
.ap-ghost::before { content: ''; position: absolute; left: 13px; top: 13px;
  width: 47px; height: 47px; border-radius: 22.37%; background: rgba(34,68,204,.07); }
@supports (corner-shape: squircle) { .ap-ghost::before { corner-shape: squircle; } }
.ap-ghost::after { content: ''; position: absolute; left: 81px; top: 25px; width: 52%;
  height: 8px; border-radius: 99px; background: rgba(34,68,204,.07);
  box-shadow: 0 19px 0 -1px rgba(34,68,204,.05); }

/* 🚨 L'état vide ne dit plus « aucune correspondance » tout court : « Turquie »
   ne renvoyait rien alors qu'Uber, Bolt et inDrive y opèrent. Nos listes sont un
   ÉCHANTILLON DÉCLARÉ (le repo dit « Uber : 70+ pays » quand on n'en liste que
   20), pas la carte du monde. */
.ap-empty { height: 100%; display: flex; flex-direction: column; align-items: center;
  justify-content: center; gap: 8px; text-align: center; color: var(--muted);
  font-size: .9375rem; padding-inline: 21px; }
.ap-empty b { display: block; color: var(--ink); font-family: var(--fd); font-weight: 800;
  font-size: 1.0625rem; }
.ap-empty small { max-width: 46ch; font-size: .8125rem; line-height: 1.5; }
.ap-reset { margin-top: 5px; border: 1.5px solid var(--blue); background: none; cursor: pointer;
  border-radius: 999px; padding: 8px 18px; font-family: var(--fb); font-size: 13px;
  font-weight: 700; color: var(--blue); }
.ap-reset:hover { background: var(--p-blue); }

/* ---- LA LIGNE D'APP ----
   🚨 Les descriptions ont sauté (« la pire partie, dans l'état c'est pas ouf »).
   Le vrai défaut n'était pas la mise en page : le texte généré est un GABARIT.
   « regroupe taxis, VTC, trottinettes et parfois d'autres mobilités dans une
   seule app » revient à l'identique sur Uber, Bolt, Freenow, Lyft, Yandex… le
   répéter 38 fois remplit l'écran sans rien apprendre. Il reste dans
   `data-blurb`, donc dans la fiche, là où on l'a demandé.
   Ce qui est affiché est ce qui DIFFÈRE d'une app à l'autre : nom, type,
   région, note. Quatre faits, quatre valeurs distinctes par ligne. */
/* pas d'`overflow: hidden` ici : la pastille « soon » DÉBORDE du logo. */
.ap-card { position: relative; width: auto; display: grid;
  grid-template-columns: auto minmax(0, 1fr); align-items: center; gap: 21px; padding: 13px;
  text-align: left; border: 0; cursor: pointer; font: inherit; background: transparent;
  border-radius: 21px; transition: background .18s ease; }
@supports (corner-shape: squircle) { .ap-card { corner-shape: squircle; } }
@media (hover: hover) { .ap-card:hover { background: var(--card-2); } }
.ap-card[hidden] { display: none; }
.ap-mark { position: relative; flex: none; display: block; }
.ap-logo { display: block; width: 47px; height: 47px; border-radius: 22.37%;
  box-shadow: 0 1px 2px rgba(32,29,21,.14), 0 5px 12px -6px rgba(25,44,134,.34); }
@supports (corner-shape: squircle) { .ap-logo { corner-shape: squircle; } }
.ap-body { position: relative; min-width: 0; display: grid; gap: 3px; }
.ap-line { display: flex; align-items: baseline; gap: 8px; }
.ap-line b { flex: 1; min-width: 0; font-family: var(--fd); font-weight: 800; font-size: 1rem;
  line-height: 1.2; color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ap-star { flex: none; font-family: var(--fb); font-size: 12.5px; font-weight: 700;
  color: var(--ink-2); font-variant-numeric: tabular-nums; }
.ap-meta { display: flex; align-items: center; gap: 8px; min-width: 0;
  font-family: var(--fb); font-size: 11.5px; font-weight: 600; color: var(--muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* ---- « soon » : le marqueur DE L'APP FAB, repris tel quel.
   🚨 Le badge « BIENTÔT » en bout de ligne était de trop (« le bientôt est mal
   fait ; dans Fab on met un petit truc soon sur les app »). Dans
   `components/settings/ProviderIconCell.tsx`, un teaser porte une pastille
   blanche « soon » posée en haut à droite de SON ICÔNE, et l'icône est estompée.
   On reprend la géométrie (36×18, rayon 9, débord) et le mot (« soon »,
   identique en FR et EN dans les deux locales).
   ⚠️ Un seul écart, assumé : l'app écrit en `rgba(60,60,67,.6)`, qui ne fait que
   3,4:1 sur crème. À 9,5 px sur le web il faut 4,5:1, donc l'encre est opaque.
   Il s'enlève en supprimant `data-soon` sur le <button> et le <span> : rien
   d'autre n'en dépend. */
.ap-soon { position: absolute; top: -5px; inset-inline-end: -8px;
  min-width: 36px; height: 18px; display: grid; place-items: center;
  padding-inline: 6px; border-radius: 9px; background: var(--card);
  border: 1px solid rgba(32,29,21,.10); box-shadow: 0 1px 3px rgba(32,29,21,.13);
  font-family: var(--fb); font-size: 9.5px; font-weight: 700; letter-spacing: .2px;
  color: var(--muted); }
.ap-card--soon .ap-logo { opacity: .6; }
@media (hover: hover) { .ap-card--soon:hover .ap-logo { opacity: .85; } }

@media (min-width: 1180px) { .ap-list { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
@media (max-width: 1000px) { .ap-list { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 720px) { .ap-list { grid-template-columns: minmax(0, 1fr); }
  .ap-bar { flex-wrap: wrap; gap: 13px; }
  .ap-count { order: -1; margin-inline-start: 8px; }
  .ap-search { flex-basis: 100%; height: 47px; } }

/* ==== §29 — LES PAGES SECONDAIRES RECALÉES SUR LA LANDING (2026-08-12) ======
   Demande du fondateur : « on a construit plein de choses autres que l'accueil,
   mais au début, et niveau design rien n'a suivi. La landing page est le modèle
   et le reste doit suivre. »

   Ce qui vivait encore sur ces pages et qui est MORT sur la landing :
     · la pill étendard `.kicker` (« QUESTIONS FRÉQUENTES ») — remplacée par un
       vrai gros titre `.eco-title` à point bleu depuis le 2026-08-10 ;
     · la grille de cartes uniformes icône-titre-description + `.icon-badge`
       (l'anti-pattern n°1, jugé « IA » et retiré des homes le 2026-08-09) ;
     · l'accordéon `.faq-item` — remplacé par la boîte en deux panneaux ;
     · la matière à filet fin + ombre grise, alors que la page parle depuis le
       11/08 une seule langue : ZÉRO TRAIT + ombre douce teintée bleu.
   Les classes anciennes ne sont pas supprimées : les 8 homes localisées
   (es/de/it/pt/nl/pl/ar/tr) les utilisent encore et leur refonte est un
   chantier séparé. Elles sont seulement retirées des pages FR et EN.        */

/* --- a) La bande CTA : un seul bloc partagé, plus aucun style en ligne ------
   Le `style="max-width:42ch;margin:14px auto 0"` de la landing et le
   `style="margin-top:56px"` des sous-pages sont remontés ici. 14 → 13 et
   56 → 55 : deux valeurs qui rataient Fibonacci de moins de 8 %.            */
.cta-band .lead { max-width: 42ch; margin: 13px auto 0; }
.cta-sec { padding-top: 0; }
.cta-sec--tight { padding-block: 0 clamp(55px, 7vw, 89px); }

/* --- b) La tête de page : le gros titre à point bleu, comme les chapitres --
   `.article-head` gardait un `<h1 class="display">` avec un clamp écrit en
   ligne (2.4 → 3.6rem), hors de la gamme φ. Il reprend `.eco-title`, donc
   exactement l'échelle des têtes de chapitre de la landing (38 → 61 px).    */
.article-head .eco-title { text-wrap: balance; margin-inline: auto; max-width: 20ch; }
.article-head .eco-lead { margin: 21px auto 0; max-width: 56ch; text-align: center; }
.article-head .crumbs { margin-bottom: 13px; }
/* une tête de page n'est pas une tête de chapitre : elle est toujours centrée */
.article-head .eco-head { text-align: center; }

/* --- c) Les affirmations : trois blocs posés, aucun pictogramme ------------
   Remplace les trios `.vcard > .icon-badge` (carré pastel + pictogramme) des
   pages comparateur. La composition validée par le fondateur pour « trois
   arguments » est un RANG d'objets crème posés de travers, pas une grille
   d'icônes. Pas de trait, l'ombre du site, rotations ±1,5°.                 */
.claims { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 21px;
  margin: clamp(26px, 3.4vw, 42px) 0 0; }
.claim { background: var(--card); border-radius: var(--radius-object); padding: 26px 21px 29px;
  box-shadow: 0 2px 5px rgba(32, 29, 21, .07), 0 34px 68px -26px rgba(25, 44, 134, .32); }
.claim:nth-child(odd) { transform: rotate(-1.5deg); }
.claim:nth-child(even) { transform: rotate(1.5deg); background: var(--card-2); }
.claim h3 { font-family: var(--fd); font-weight: 800; font-size: 1.3125rem; line-height: 1.272;
  letter-spacing: -.01em; margin: 0 0 8px; text-wrap: balance; }
/* 🚨 le plafond de 30ch bridait le texte APRÈS l'élargissement des cartes :
   la carte passait à 379 px mais la ligne restait à 30 caractères, donc le
   gain était nul. 30ch avait été calé sur une carte de 245 px, où il ne
   servait à rien. Un plafond de mesure se recale quand son contenant
   change, sinon il devient le vrai bridage sans qu'on le voie. */
.claim p { color: var(--muted); font-size: 1rem; line-height: 1.618; max-width: 42ch; margin: 0; }
@supports (corner-shape: squircle) { .claim { corner-shape: squircle; } }
@media (max-width: 1019px), (orientation: landscape) and (max-height: 520px) {
  .claims { grid-template-columns: 1fr; gap: 16px; }
  .claim, .claim:nth-child(even) { transform: none; }
}

/* --- d) L'étagère d'apps porte les VRAIES illustrations App Store ----------
   Les pages comparateur affichaient dix pastilles à LETTRE (« U », « B »…)
   alors que le catalogue de la landing montre depuis le 11/08 les vraies
   illustrations. Même gabarit, même ombre teintée par la marque : seule la
   lettre laisse la place à l'image.                                         */
.app-shelf .shelf-icon--logo { background: none; box-shadow: none; padding: 0;
  border-radius: 0; overflow: visible; }
/* 22,37 % = le rayon d'icône iOS, exactement celui de `.ap-logo` du catalogue.
   🚨 Deux pièges déjà payés le 11/08 (§24) : PAS de `background: var(--pc)` sous
   l'image (l'antialiasing de l'arrondi laisse fuiter un pixel d'une autre teinte
   sur un élément tourné) et PAS d'ombre teintée par la marque (onze marques =
   onze ombres colorées = un frangeage tout autour de l'étagère). */
.app-shelf .shelf-icon--logo img { display: block; width: 100%; height: 100%; object-fit: cover;
  border-radius: 22.37%;
  box-shadow: 0 1px 2px rgba(32, 29, 21, .14), 0 8px 18px -8px rgba(25, 44, 134, .34); }
@supports (corner-shape: squircle) { .app-shelf .shelf-icon--logo img { corner-shape: squircle; } }
@media (hover: hover) {
  .app-shelf .shelf-app:hover .shelf-icon--logo { transform: translateY(-4px); box-shadow: none; }
  .app-shelf .shelf-app:hover .shelf-icon--logo img {
    box-shadow: 0 2px 4px rgba(32, 29, 21, .16), 0 14px 26px -8px rgba(25, 44, 134, .42); }
}

/* --- e) Le blog : des objets posés, plus de couvertures à emoji -----------
   Les couvertures portaient un emoji de 42 px en dégradé pastel (⚔️ ✈️ 💵),
   c'est-à-dire une illustration que Fab ne dessine nulle part ailleurs. La
   couverture devient TYPOGRAPHIQUE : la rubrique en gros Baloo sur le pastel.
   Et la grille passe de 3 à 2 colonnes : à quatre articles, 3 + 1 laissait
   une rangée orpheline (règle d'interface n°16).                           */
.blog-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 26px; max-width: 940px;
  margin-inline: auto; }
.post-card { border: 0; box-shadow: 0 2px 5px rgba(32, 29, 21, .07),
  0 34px 68px -26px rgba(25, 44, 134, .32); }
.post-card:hover { transform: translateY(-4px);
  box-shadow: 0 3px 7px rgba(32, 29, 21, .09), 0 42px 76px -26px rgba(25, 44, 134, .4); }
@supports (corner-shape: squircle) { .post-card { corner-shape: squircle; } }
.post-cover { aspect-ratio: 55/13; align-items: center; justify-content: flex-start;
  padding: 0 26px; }
.post-cover .em { font-family: var(--fd); font-weight: 800; font-size: clamp(1.625rem, 3vw, 2.125rem);
  line-height: 1; letter-spacing: -.02em; color: var(--ink); opacity: .5; filter: none; }
.post-body { gap: 8px; }
.post-body .tag { color: var(--blue-ink); }
.post-body h3 { font-size: 1.625rem; }
.post-card:hover .rd { text-decoration: underline; text-underline-offset: 3px; }
@media (max-width: 760px) { .blog-grid { grid-template-columns: 1fr; } }

/* --- f) La prose : les liens au poids du site ------------------------------
   `.prose a` était en 500 quand tout le reste des liens de corps est en 600.
   Le blockquote et le tableau gardent leur rayon de RANGÉE (13), c'est ce qui
   les distingue des objets posés (règle du squircle 26).                    */
.prose a { font-weight: 600; }
.prose h2 { text-wrap: balance; }
.prose .lead, .prose > p:first-child { text-wrap: pretty; }

/* --- g) Les rangées question-réponse (mini-FAQ des pages secondaires) -------
   Trois questions ne méritent pas la boîte en deux panneaux : elle est calibrée
   pour vingt-deux et son panneau navy resterait aux trois quarts vide. Elles
   deviennent des RANGÉES DE LISTE, donc rayon 13 et non 26 — c'est exactement
   ce que dit la règle du squircle : « seules les rangées de liste gardent leur
   rayon plus serré, c'est ce qui les distingue des objets ». Réponses visibles
   d'emblée : plus rien à déplier, et le texte est lu par les moteurs.        */
.qa-list { display: flex; flex-direction: column; gap: 13px; }
.qa-row { background: var(--card); border: 1.5px solid var(--border); border-radius: var(--radius-row);
  padding: 21px 26px; box-shadow: var(--sh-sm); }
.qa-row h3 { font-family: var(--fd); font-weight: 700; font-size: 1.3125rem; line-height: 1.272;
  letter-spacing: -.01em; margin: 0 0 8px; color: var(--ink); text-wrap: balance; }
.qa-row p { margin: 0; color: var(--muted); font-size: 1rem; line-height: 1.618; }
.qa-row + .qa-row { margin: 0; }
@media (max-width: 640px) { .qa-row { padding: 16px 21px; } }

/* --- h) L'étagère à onze : 6 + 5, jamais une rangée orpheline --------------
   610 px = 6 × 80 (l'app) + 5 × 26 (la gouttière), et 610 est de la suite.
   À dix, la borne de 560 pliait en 5 + 5 ; à onze elle laissait un seul
   logo tout seul sur la troisième ligne (règle d'interface n°16).           */
.container-tight .app-shelf { max-width: 610px; }

/* --- i) Tableau à intertitres de zone (guide « quelle app selon le pays ») --
   Un tableau de 49 lignes est illisible d'un bloc. Les lignes de zone ne sont
   pas des données : elles sont l'ossature, d'où le fond crème soutenu et la
   petite capitale. `--card-3` et non `--card-2` : la ligne doit se distinguer
   des en-têtes de colonnes, qui portent déjà `--card-2`.                     */
.prose th.zone { background: var(--card-3); color: var(--muted); font-family: var(--fb);
  font-weight: 700; font-size: .8125rem; letter-spacing: .07em; text-transform: uppercase;
  padding-block: 16px 8px; }
.prose td:first-child { white-space: normal; }
@media (max-width: 560px) { .prose th, .prose td { padding: 10px 8px; font-size: .9375rem; } }

/* --- j) La carte en vedette : la règle du compte impair --------------------
   La grille du blog est à 2 colonnes. À 4 articles elle tombe juste ; à 5 elle
   laisse une rangée orpheline (règle d'interface n°16). Plutôt qu'un nombre
   figé, une règle qui se tient toute seule à mesure que le blog grossit :
   COMPTE IMPAIR = le plus récent passe en vedette sur toute la largeur, et le
   reste retombe en paires. 5 → 1 + 2 + 2 · 7 → 1 + 2 + 2 + 2.
   La vedette n'invente aucune matière : même carte, couchée.               */
.post-card--feat { grid-column: 1 / -1; flex-direction: row; align-items: stretch; }
.post-card--feat .post-cover { aspect-ratio: auto; flex: 0 0 34%; align-items: flex-end;
  padding: 0 0 21px 26px; }
.post-card--feat .post-body { flex: 1; justify-content: center; padding: 34px 34px 34px 26px; }
.post-card--feat .post-body h3 { font-size: clamp(1.625rem, 2.6vw, 2.125rem); }
.post-card--feat .post-body p { max-width: 62ch; }
@media (max-width: 760px) {
  .post-card--feat { flex-direction: column; }
  .post-card--feat .post-cover { flex: none; aspect-ratio: 55/13; align-items: center;
    padding: 0 26px; }
  .post-card--feat .post-body { padding: 21px 26px 26px; }
}

/* --- k) Le lockup de marque du pied, réparé (2026-08-12) -------------------
   🚨 `.footer a { display: block }` (spécificité 0-1-1) écrasait le
   `display: inline-flex` de `.brand` (0-1-0). Le lockup perdait son contexte
   flex : `gap` et `align-items` devenaient inertes, et l'image, en block par
   le reset, tombait seule sur sa ligne. Les yeux flottaient donc AU-DESSUS du
   mot « Fab » au lieu de le regarder, sur les 20 pages à la fois.
   Leçon : une règle de PORTÉE (`.footer a`) écrase une règle de COMPOSANT
   (`.brand`) dès qu'elle est plus spécifique. Un composant posé dans une zone
   qui style ses balises doit redéclarer sa boîte. */
.footer .brand { display: inline-flex; align-items: center; gap: 13px; padding: 0; }
.footer .brand-eyes { width: 42px; height: 39px; }
.footer .brand .wm { font-size: 1.625rem; line-height: 1; }


/* --- m) En butée, le défilement repart sur la page (2026-08-12) ------------
   Alex : « quand j'arrive à la fin du scroll dans la section, j'aimerais bien
   ne pas rester bloqué et que le site continue sa descente ».
   🚨 `overscroll-behavior: contain` ne change RIEN pendant le défilement — une
   zone qui défile défile toujours seule. Il ne change que la BUTÉE : arrivé au
   bout, `contain` AVALE la molette, et il faut sortir le curseur de la zone
   pour que la page reparte. Trois zones l'avaient : le catalogue d'apps, la
   liste des questions de la FAQ et la bulle de réponse. Les trois sont passées
   à `auto`, le comportement par défaut du navigateur.
   La capture accidentelle qu'on redoutait en mettant `contain` est déjà traitée
   par les navigateurs : un geste commencé sur la page reste sur la page
   (scroll latching), même si le curseur survole une zone défilante en chemin.
   ⚠️ Ne remettre `contain` que sur une zone dont la butée NE DOIT PAS relancer
   la page — typiquement un panneau modal plein écran. Il n'y en a aucun ici. */

/* --- n) Les quatre gestes sont cliquables (2026-08-12) ---------------------
   Alex : « dommage de ne pas pouvoir cliquer les différents modes de connexion
   et d'avoir l'explication en dessous ». La plaque devient un vrai `tablist`
   de quatre boutons, et le paragraphe sous le titre change avec la sélection.
   Mêmes rôles ARIA que la boîte FAQ du site, même clavier (flèches).
   🚨 Les quatre explications sont EMPILÉES en `grid-area: 1/1`, jamais
   `hidden` : sinon la hauteur de la carte sauterait à chaque changement, et
   les trois cartes de la rangée cesseraient de s'aligner. C'est la leçon déjà
   payée sur l'établi (« JAMAIS display:none sur un acte »). La hauteur est
   donc celle de l'explication la plus longue, une bonne fois.
   Sans JS : le premier bouton porte `is-on` dans le HTML, donc la première
   explication s'affiche et la plaque reste lisible. */
.soc-ways-a { display: grid; }
.soc-ways-a > .soc-way-a { grid-area: 1 / 1; margin: 0; opacity: 0; visibility: hidden;
  transition: opacity .26s ease; }
.soc-ways-a > .soc-way-a.is-on { opacity: 1; visibility: visible; }

@media (max-width: 980px) {
  /* les cartes sont empilées : la plaque peut prendre la hauteur qu'il faut,
     et les cibles tactiles passent à 44 px (règle d'interface n°3). */
  .soc-plate--ways { height: auto; min-height: 178px; }
  .soc-way { min-height: 44px; }
}

/* ==========================================================================
   §29 — LES MAQUETTES DES ÉTAPES 2 ET 3, RECALÉES SUR L'APP (2026-08-12)
   Verdict fondateur : « les mocks des cartes 2 et 3 sont ratés ». Reprise
   entièrement adossée au code de l'app, jamais à l'œil.
   ========================================================================== */

/* ---- Étape 3 : la pile d'offres ----------------------------------------
   `components/dev/QuoteCard.tsx` : la carte est un BANDEAU pleine largeur
   (`marginHorizontal: sp(16)`), donc les 4 offres ont la MÊME longueur ; le
   site les laissait en `width: max-content` → 205/194/175/201 px, une largeur
   par offre, d'où la lecture « pastilles » au lieu de « cartes ».
   Ligne interne de l'app : véhicule · `infoContainer { flex: 1 }` ·
   `priceContainer { alignItems: 'flex-end' }` → le prix est au BORD DROIT.
   Longueur réduite de 55 px (pas φ) prise par la GAUCHE, demande fondateur :
   le bord droit reste calé sur le padding de la carte. */
/* 🚨 `.exp-scene` porte `margin-inline-end: -21px` (l'objet débordait par la
   droite dans l'ancienne mise en scène). Sans compensation, la pile vient
   coller EXACTEMENT le bord de la carte. On lui rend ses 21 px. */
.exp-scene .xs-stack--sorted { width: calc(100% - 55px); margin-inline-start: auto;
  margin-inline-end: 21px; padding-top: 9px; gap: 13px; }
.exp-card .xs-oc { width: 100%; box-sizing: border-box; }
.exp-card .xs-oc b { flex: 1; }
.exp-card .xs-price { margin-inline-start: 0; }
/* 🚨 le tag vit DANS la première offre (l'app le pose `position:absolute;
   top:6; left:8`), mais À CHEVAL sur le bord haut : ça, c'est le choix du
   SITE, assumé, pas une réplique. Ses cotes restent celles de l'app :
   padding 3/8, rayon 7, texte 10 en 700, icône 9. */
.exp-card .live-sort .oc-tag { position: absolute; top: -9px; inset-inline-start: 13px;
  z-index: 10; display: inline-flex; align-items: center; gap: 3px; height: auto;
  padding: 3px 8px; border-radius: 6px; font-size: 10px; font-weight: 700;
  line-height: 1.2; transform: none; box-shadow: 0 2px 5px -1px rgba(6,95,70,.30); }
.exp-card .live-sort .oc-tag svg { width: 9px; height: 9px; }
/* 🚨 la colonne texte partait CENTRÉE verticalement pendant que la pile commence
   en haut : d'où « le texte n'est pas réparti ». Les deux colonnes démarrent
   maintenant sur la même ligne. */
.exp-card--a .exp-copy, .exp-card--b .exp-copy { align-content: start; }
.exp-copy p { max-width: none; }

/* ---- Étape 2 : le nudge provider, ses états, et le changement de ville ---
   Réplique de `components/ProviderNudgePill.tsx`, dont l'en-tête décrit la
   machine : « collapsed → expanded → focus ». Valeurs relevées dans le
   fichier : pilule h 39 / padding H 12 / gap 8 / yeux 26 / texte 13,5 en 600
   #111827 / chevron 14 à 45 % · carte padding 11-16 / gap 8 / yeux 56 ·
   grille 4 colonnes de 66 · icône 62 au rayon 22,37 % (`ICON_RADIUS =
   ICON_SIZE * 0.2237`) · pastille « soon » 30×15 rayon 7,5, fond blanc 92 %,
   texte 8 en 700 à 60 %.
   🚨 `statusDot` est en `position:absolute` dans l'app : le point vert ne
   déplace JAMAIS le nom. En ligne, il décalait les libellés de 12 à 19 px
   selon la cellule — c'était ça, le « rien d'harmonieux ».
   🚨 La phrase `nudge.expanded.connected.line3` est ÉCARTÉE : elle dit
   « laquelle gagne le trajet », formulation bannie du site. */
/* 🚨 `.exp-scene` porte `margin-inline-end: -21px` (ancienne mise en scène où
   l'objet débordait volontairement). La carte du nudge sortait donc du
   rectangle par la droite. On annule le débord POUR CETTE SCÈNE et on centre. */
.exp-scene:has(.np-stage) { margin-inline-end: 0; padding: 21px; }
.np-stage { position: relative; width: 100%; max-width: 377px; height: 233px;
  margin-inline: auto; display: grid; place-items: center; }
/* 🚨 `inset: 13px` rétrécissait la boîte à 344 px alors que le CONTENU en exige
   350 au minimum (grille 4×66 + 3×18 = 318, plus 32 de padding). La carte
   débordait donc de 8 px à droite, en permanence et pas seulement pendant la
   transition. `width: 100%` ne protège de rien : c'est la largeur minimale du
   contenu qui gagne. L'inset passe à 0 (la course de la transition est un
   `transform`, elle n'a jamais eu besoin de place dans la mise en page). */
.np { position: absolute; inset: 0; opacity: 0; display: grid; place-items: center; }
.np:first-child { opacity: 1; }
/* 🚨 L'ÉTAT COMPACT (la pilule) A ÉTÉ RETIRÉ (fondateur 2026-08-12) : on ne
   montre que la carte dépliée, qui change de ville. La machine de l'app en a
   trois (collapsed → expanded → focus), le site n'en garde qu'un. */
/* 🚨 PLUS DE CONTENEUR (fondateur 2026-08-12 : « la couleur crème ne marche
   pas »). Le vrai défaut n'était pas la teinte mais la BOÎTE DANS LA BOÎTE :
   la carte-étape est déjà une carte crème, y poser un second conteneur donne
   le même défaut que le Bilan corrigé en §14. Blanc il disparaissait, crème il
   faisait une tache : aucune troisième couleur ne sauvait ça. Les tuiles sont
   donc posées directement sur la carte, sans fond ni ombre.
   La voix de Fab (yeux + phrase) est conservée : c'est elle qui porte le sens,
   pas le cadre. */
.np-card { position: relative; width: 100%; background: none; box-shadow: none;
  padding: 0; display: flex; flex-direction: column; gap: 13px; }
.np-speech { display: flex; align-items: center; gap: 10px; }
.np-et { font-family: var(--fb); font-weight: 500; font-size: 13.5px; line-height: 1.3; color: #111827; }
.np-et b, .np-all { color: var(--blue); font-weight: 700; text-decoration: underline;
  text-underline-offset: 2px; }
/* « Voir tout » mène vraiment à la section catalogue. Il garde le contraste
   qui augmente au survol (règle d'interface n°2). */
.np-all { cursor: pointer; transition: color .16s ease; }
.np-all:hover { color: var(--blue-ink); }
/* la grille garde ses 4 colonnes quelle que soit la ville : le rythme ne doit
   pas se recomposer d'une ville à l'autre. */
.np-grid { display: grid; grid-template-columns: repeat(4, 66px); gap: 13px 18px; justify-content: center; }
/* 🚨 HAUTEUR DE CELLULE FIXE. Le libellé d'une app réelle fait ~15 px de haut,
   celui d'un fantôme (une simple barre) 7 : la 2e rangée changeait donc de
   hauteur selon la ville, et la carte avec elle. 62 + 8 + 15 = 85. */
.np-cell { display: flex; flex-direction: column; align-items: center; gap: 8px;
  width: 66px; height: 85px; }
.np-ico { position: relative; width: 62px; height: 62px; border-radius: 22.37%;
  display: grid; place-items: center; font-family: var(--fb); font-weight: 700;
  font-size: 26px; color: #fff;
  background: linear-gradient(160deg, color-mix(in srgb, var(--pc) 84%, #fff), var(--pc) 52%,
    color-mix(in srgb, var(--pc) 86%, #000));
  box-shadow: 0 2px 4px rgba(32,29,21,.10), 0 8px 18px -8px color-mix(in srgb, var(--pc) 55%, transparent); }
/* 🚨 libellé à largeur de colonne et point vert EN ABSOLU : dans l'app,
   `statusDot` est absolu sur un `labelWrap` centré, il ne déplace jamais le nom. */
/* 🚨 LE POINT VERT SE CALE SUR LE TEXTE, PAS SUR LA CELLULE. Nuance ratée au
   premier passage : dans l'app, `statusDot` est absolu à l'intérieur de
   `labelWrap`, et `labelWrap` fait la largeur DU TEXTE (il est centré, pas
   étiré). Le point se pose donc au bord du NOM. En rendant le libellé large de
   toute la colonne, je l'avais collé au bord de la cellule : le point se
   retrouvait loin du mot, d'autant plus loin que le nom était court. */
.np-cell small { position: relative; display: inline-block; max-width: 100%;
  align-self: center; line-height: 15px; text-align: center;
  font-family: var(--fb); font-weight: 500; font-size: 12px; color: #000;
  letter-spacing: -.08px; white-space: nowrap; overflow: visible; }
.np-dot { position: absolute; top: 5px; inset-inline-start: -10px; width: 6px; height: 6px;
  border-radius: 50%; background: #34C759; box-shadow: 0 0 4px rgba(52,199,89,.5); }
/* la barre du fantôme occupe la même ligne de 15 px que les vrais noms */
.np-ghost small { display: block; width: 100%; height: 15px; }
.np-cell.is-teaser .np-ico { color: rgba(255,255,255,.9); }
.np-cell.is-teaser small { color: rgba(60,60,67,.40); font-weight: 400; }
.np-soon { position: absolute; top: -4px; inset-inline-end: -13px; min-width: 30px;
  height: 15px; border-radius: 7.5px; padding: 0 5px; background: rgba(255,255,255,.92);
  border: 1px solid rgba(255,255,255,.72); display: grid; place-items: center;
  font-size: 8px; line-height: 1; font-weight: 700; font-style: normal; color: rgba(60,60,67,.6); }
/* 🚨 GHOSTS — toutes les zones n'ont pas 8 apps. Sans eux la grille change de
   hauteur d'une ville à l'autre. Empreinte seule, même langage que #apps.
   L'app, elle, n'en dessine pas : c'est une invention du site. */
.np-ghost .np-ico { background: rgba(34,68,204,.07); box-shadow: none; }
.np-ghost small::before { content: ''; display: block; width: 34px; height: 8px;
  margin: 4px auto 0; border-radius: 4px; background: rgba(34,68,204,.07); }

/* 🚨 PLUS DE FONDU SUR PLACE (fondateur 2026-08-12 : « t'as pas mieux pour
   créer un mouvement d'une card à une autre ? »). Deux cartes qui se croisent
   en opacité, ça ne raconte rien. Ici c'est une carte qu'on DISTRIBUE : la
   sortante part vers la gauche en s'inclinant, l'entrante arrive de la droite
   avec l'inclinaison inverse et se pose à plat. C'est la langue du site
   (rotations légères, cartes posées), et ça reste transform + opacity.
   L'easing du site est porté par les keyframes qui AMORCENT un mouvement. */
@media (prefers-reduced-motion: no-preference) {
  .np { animation: np-deal 18s linear infinite; animation-delay: var(--d); }
}
/* 🚨 COURSE LIMITÉE À CE QUE LE BLOC PEUT ABSORBER. Le premier jet déplaçait
   la carte de 42 px : additionné aux ~6 px que la rotation pousse dans les
   coins, ça dépassait les 28 px de marge disponibles et la carte SORTAIT du
   bloc pendant la transition (fondateur : « fais pas déborder le nudge »).
   Calculé : au repos le bord droit est à 21 px du bord de la carte-étape ; une
   course de 13 px (pas φ) plus les 4,8 px que la rotation de 1,5° pousse dans
   le coin en consomment 17,8, il en reste 3. C'est `inset: 0` qui a rendu cette
   marge : avant, la carte débordait déjà de 8 px à l'arrêt. Une capture fixe ne montre jamais ce défaut : il
   n'existe qu'entre deux villes. */
@keyframes np-deal {
  0%     { opacity: 0; transform: translateX(13px) rotate(1.5deg) scale(.975);
           animation-timing-function: cubic-bezier(.16,1,.3,1); }
  3.6%   { opacity: 1; transform: translateX(0) rotate(0deg) scale(1); }
  30%    { opacity: 1; transform: translateX(0) rotate(0deg) scale(1);
           animation-timing-function: cubic-bezier(.55,0,.9,.35); }
  33.33% { opacity: 0; transform: translateX(-13px) rotate(-1.5deg) scale(.975); }
  100%   { opacity: 0; transform: translateX(-13px) rotate(-1.5deg) scale(.975); }
}

@media (max-width: 1019px), (orientation: landscape) and (max-height: 520px) {
  .exp-scene .xs-stack--sorted { width: 100%; margin-inline-start: 0; }
  .np-stage { width: 100%; max-width: 377px; margin-inline: auto; }
  .np-grid { justify-content: center; }
}
/* 🚨 Téléphone couché (2026-08-14) : la scène en colonne fait 852 pt — les
   offres « pleine largeur » devenaient des bandeaux d'un mètre. On les ramène
   à la largeur d'une liste d'app (377), centrée dans la scène. */
@media (orientation: landscape) and (max-height: 520px) {
  .exp-scene .xs-stack--sorted { width: min(100%, 377px); margin-inline: auto; }
}

/* 🚨 TRÈS PETITS ÉCRANS (≤ 360 : iPhone SE, vieux Android). Mesuré à 320 :
   la grille du nudge réclame 4×66 + 3×18 = 318 px, plus la marge de la carte,
   donc elle sortait de 23 px ; les suggestions d'adresse de 6. `overflow-x:
   hidden` masquait le symptôme (aucune barre de défilement) mais le contenu
   était bel et bien COUPÉ. Deux réglages suffisent : la gouttière tombe au
   plancher que l'app elle-même prévoit (`Math.max(sp(8), …)`) et la pile
   d'adresses arrête de se décaler. */
@media (max-width: 360px) {
  /* la tuile suit ce que ferait `cs(62)` sur un écran de 320 : plus petite.
     4×55 + 3×8 = 244 px, ça rentre là où 4×66 + 3×18 = 318 ne rentrait pas. */
  .np-grid { grid-template-columns: repeat(4, 55px); gap: 13px 8px; }
  .np-cell { width: 55px; height: 76px; }
  .np-ico { width: 55px; height: 55px; font-size: 23px; }
  .np-cell small { font-size: 11px; line-height: 13px; }
  .sg-list .frag-search { margin-right: 0; }
  .sg-list .frag-sugg { transform: none !important; }
  .sg-list .frag-sugg:nth-of-type(2),
  .sg-list .frag-sugg:nth-of-type(4) { margin-inline-start: 0; }
}

/* ---------------------------------------------------------------------------
   §38 — LA PAGE /faq/ DEVIENT UNE PAGE DE RÉFÉRENCE (fondateur 2026-08-12)
   « Son design reprend juste ce qu'on a déjà, on pourrait avoir quelque chose
   de plus complet. » Constat chiffré avant de dessiner : la page dédiée portait
   14 questions quand la home en porte 22. On atterrit dessus depuis la nav et
   elle ne dit pas ce qu'est Fab. Le `FAQPage` ne déclarait donc que 14 couples
   à Google. Cible : les 24 questions uniques des deux sources.
   🚨 LA CONSOLE À DEUX PANNEAUX RESTE SUR LA HOME, ELLE NE CONVIENT PAS ICI.
   Sur la home c'est un objet d'appel : on pioche, une réponse à la fois. Sur
   une page de référence on arrive de Google avec UNE question, on balaie, on
   lit plusieurs réponses, on veut envoyer un lien. Or la console : n'affiche
   qu'une réponse à la fois ; met les autres en `display:none`, donc `Ctrl+F`
   ne les trouve pas ; et n'offre aucune ancre par question. Trois défauts qui
   ne comptent pas sur la home et qui disqualifient le format ici.
   Le remède n'est pas un nouveau composant : les réponses deviennent des
   CARTES, la matière de base du site (`--card`, liseré bleu fin, squircle 26),
   groupées en chapitres. La page se lit d'un bout à l'autre. */
.faq-index { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px;
  max-width: 800px; margin: 34px auto 0; padding: 0; list-style: none; }
/* les 5 pastilles tiennent sur UNE ligne dans la colonne de lecture (800 px) :
   à 15 px et 16 px de padding elles totalisaient 847 px et la dernière tombait
   seule sur un second rang, centrée, ce qui se lisait comme un oubli. */
.faq-index a { display: inline-block; font-family: var(--fb); font-weight: 600; font-size: .875rem;
  color: var(--blue-ink); background: var(--p-blue); border-radius: 999px; padding: 8px 14px;
  transition: background .2s, color .2s, transform .2s; }
.faq-index a:hover { background: var(--blue); color: #FFFDF6; transform: translateY(-1px); }

.qa-group { max-width: 800px; margin: 0 auto; }
/* le sommaire collait au premier chapitre : un cran φ les sépare. */
.faq-index + .qa-group { margin-top: 55px; }
.qa-group + .qa-group { margin-top: 55px; }
/* le titre de chapitre porte le point bleu du site, pas un surtitre de plus */
.qa-group > h2 { font-family: var(--fd); font-weight: 800; font-size: clamp(1.5rem, 2.6vw, 1.9375rem);
  line-height: 1.15; letter-spacing: -.015em; color: var(--ink); margin: 0 0 21px; }
.qa-group > h2 .dot-blue { color: var(--blue); }

.qa { background: var(--card); border: 1.5px solid var(--border); border-radius: var(--radius-object);
  padding: 26px 26px 24px; box-shadow: var(--sh-sm); scroll-margin-top: 89px; }
@supports (corner-shape: squircle) { .qa { corner-shape: squircle; } }
.qa + .qa { margin-top: 13px; }
.qa h3 { font-family: var(--fd); font-weight: 700; font-size: 1.3125rem; line-height: 1.272;
  letter-spacing: -.01em; color: var(--ink); margin: 0 0 13px; }
.qa p { color: var(--ink-2); font-size: 1.0625rem; line-height: 1.618; margin: 0; }
.qa p + p { margin-top: 13px; }
.qa a { color: var(--blue); text-decoration: underline; text-underline-offset: 2px; }
/* 🚨 PAS DE DIÈSE D'ANCRE VISIBLE (fondateur 2026-08-12, « pk y a des petits # ? »).
   Un lien d'ancre au survol est une convention de DOCUMENTATION technique ; sur
   un site grand public il se lit comme un caractère parasite. Les `id` restent
   sur les `<article>`, donc /faq/#taxi-ou-vtc marche toujours : seule l'affordance
   disparaît. Si un jour on veut la rendre découvrable, ce sera par un geste du
   site (clic sur le titre), pas par un glyphe emprunté à GitHub. */

/* bloc de sortie : la page de référence doit dire où aller quand elle n'a pas
   la réponse, sinon elle est un cul-de-sac. */
.faq-help { max-width: 800px; margin: 55px auto 0; background: var(--card);
  border: 1.5px solid var(--border); border-radius: var(--radius-object);
  box-shadow: var(--sh-sm); padding: 34px; text-align: center; }
@supports (corner-shape: squircle) { .faq-help { corner-shape: squircle; } }
.faq-help h2 { font-family: var(--fd); font-weight: 800; font-size: 1.3125rem; color: var(--ink); margin: 0 0 8px; }
.faq-help p { color: var(--ink-2); font-size: 1.0625rem; line-height: 1.618; margin: 0 0 21px; }
.faq-help .fh-links { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; }

@media (max-width: 640px) {
  .qa { padding: 21px 21px 19px; }
  .qa-group + .qa-group { margin-top: 34px; }
  .faq-help { padding: 26px 21px; margin-top: 34px; }
}

/* ---------------------------------------------------------------------------
   §39 — LA RANGÉE DE PROMESSES SORT DU GABARIT DE LECTURE (2026-08-12)
   🚨 CE N'ÉTAIT PAS UN BUG DE CSS, C'ÉTAIT UN COMPOSANT SURCHARGÉ. `.claims`
   a été dessiné pour trois arguments d'UNE PHRASE (89 et 122 caractères
   mesurés). On y a mis la liste des tris et des filtres, 225 caractères, soit
   2,5 fois plus. Dans `.container-tight` les trois cartes tombent à 245 px de
   large, c'est-à-dire environ 28 CARACTÈRES PAR LIGNE quand la règle de
   lisibilité en demande 65 à 75 : le texte se hache sur huit lignes et les
   deux cartes courtes se retrouvent avec un grand vide en bas, puisque la
   grille les aligne sur la plus haute.
   Remède : la rangée sort du gabarit de LECTURE (800 px, fait pour du corps de
   texte) et reprend le gabarit du SITE. Les cartes passent de 245 à ~355 px,
   soit ~42 caractères par ligne. Le contenu n'est pas raccourci : le fondateur
   tient à la profondeur de cette liste, et c'est le contenant qui avait tort.
   🚨 Le débordement se fait en `left: 50%` + `translateX(-50%)` et PAS en
   marges négatives : `.claim` porte déjà une rotation, et des marges négatives
   sur le parent d'éléments tournés décalent leurs boîtes de survol. */
.container-tight > .claims {
  width: min(var(--maxw), calc(100vw - 52px));
  max-width: none; position: relative; left: 50%; transform: translateX(-50%); }
@media (max-width: 1019px), (orientation: landscape) and (max-height: 520px) {
  /* sur une colonne le débordement n'a plus d'objet : la carte reprend la
     largeur de lecture, sinon elle dépasserait le texte qui l'entoure. */
  .container-tight > .claims { width: auto; left: auto; transform: none; }
}

/* ---- renvois vers les autres pages : la carte du blog, pas une pastille ----
   🚨 Les liens sortants de cette page étaient des `btn btn-ghost` fléchés,
   un artefact qui n'existait plus que sur les deux pages comparateur. Les
   remplacer par un lien texte était une PERTE : ces renvois méritent d'être
   vus. Le site a déjà le bon objet, la carte d'article du blog (`.post-card`,
   couverture colorée, titre, résumé, « Lire l'article → »). On la réutilise
   telle quelle plutôt que d'inventer un troisième traitement. */
.next-reads { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 21px; margin-top: 34px; }
@media (max-width: 700px) { .next-reads { grid-template-columns: 1fr; } }

/* ---------------------------------------------------------------------------
   §40 — LA PAGE COMPARATEUR REDEVIENT UN ARTICLE (fondateur 2026-08-12)
   Première tentative : enfermer chaque section dans une carte crème pour lui
   « donner une forme ». Verdict : « t'as empilé des cards blanches ». Il a
   raison, et les sources le confirment.
   🚨 UNE CARTE PRÉSENTE DES ÉLÉMENTS PARALLÈLES QU'ON BALAIE, PAS DE LA PROSE
   QU'ON LIT. Six cartes empilées ne donnent pas un rythme, elles donnent six
   rectangles. CSS-Tricks (« Designing for Long-Form Articles ») le dit
   directement : les rectangles décoratifs captent de l'attention négative au
   détriment du texte. Le rythme d'un article se fait par l'ESPACEMENT et la
   TYPOGRAPHIE, pas par des contenants.
   Ce que les sources donnent comme cotes, et qu'on applique ici :
     · mesure 45 à 75 caractères par ligne (on vise ~68ch)
     · corps AU-DESSUS de 16 px pour du long format, on prend 19
     · interligne 1,5 à 1,6, on garde le 1.618 du site
     · le blanc entre les sections fait la respiration, pas une bordure
   Ce qui reste en cartes est ce qui le mérite : les trois promesses (éléments
   parallèles), les renvois d'articles, la mini-FAQ. Les deux plaques bleues
   restent aussi : ce ne sont pas des boîtes autour de prose, ce sont des
   déclarations, et elles donnent à la page ses deux seules ancres colorées. */
.art { max-width: 68ch; margin-inline: auto; }
.art > h2 { font-family: var(--fd); font-weight: 800; font-size: clamp(1.5rem, 2.8vw, 2rem);
  line-height: 1.15; letter-spacing: -.018em; color: var(--ink);
  /* la respiration EST le séparateur : 89 avant, 21 après (φ) */
  margin: 89px 0 21px; text-wrap: balance; }
.art > h2:first-child { margin-top: 0; }
.art > p { color: var(--ink-2); font-size: clamp(1.0625rem, 1.4vw, 1.1875rem); line-height: 1.618; margin: 0 0 21px; }
.art > p:last-child { margin-bottom: 0; }
.art strong { color: var(--ink); font-weight: 700; }
.art a:not(.btn) { color: var(--blue); text-decoration: underline;
  text-underline-offset: 3px; text-decoration-thickness: 1px; }
/* le seul objet autorisé dans le fil : une phrase qu'on veut détacher. Pas de
   boîte, juste un filet bleu et un cran de taille. */
.art-note { margin: 34px 0; padding-inline-start: 21px; border-inline-start: 3px solid var(--blue);
  font-family: var(--fd); font-weight: 600; font-size: clamp(1.1875rem, 1.8vw, 1.375rem);
  line-height: 1.35; color: var(--ink); }

/* --- la plaque : réservée aux DÉCLARATIONS --- */
.pf-plate { position: relative; overflow: hidden; isolation: isolate;
  background: var(--blue); color: #FFFDF6; border-radius: 34px; padding: clamp(34px, 5vw, 68px); }
@supports (corner-shape: squircle) { .pf-plate { corner-shape: squircle; } }
.pf-plate::before { content: ''; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background: radial-gradient(55% 65% at 18% 0%, rgba(255,255,255,.16), transparent 60%),
              radial-gradient(45% 60% at 88% 105%, rgba(23,48,155,.85), transparent 60%); }
.pf-plate > * { position: relative; z-index: 1; }
.pf-plate h2 { font-family: var(--fd); font-weight: 800; font-size: clamp(1.75rem, 3.4vw, 2.625rem);
  line-height: 1.1; letter-spacing: -.018em; color: #FFFDF6; margin: 0 0 16px; text-wrap: balance; }
.pf-plate p { color: rgba(255,253,246,.92); font-size: clamp(1rem, 1.4vw, 1.1875rem); line-height: 1.618; margin: 0; }
.pf-plate p + p { margin-top: 16px; }
/* 🚨 le <strong> héritait de l'encre du site : 1,7:1 sur bleu roi, illisible.
   Sur une plaque l'emphase se fait en crème PLEINE contre le corps à .92. */
.pf-plate strong, .pf-plate b { color: #FFFDF6; }
/* 🚨 un débord se voit ou n'existe pas : à -34 px sur des cartes de 254 le
   recouvrement ne faisait que 38 px. -89 (φ) = 35 % de la carte, le geste des
   cartes du plateau social sur la home. */
/* 🚨 UNE PLAQUE QUI PORTE DES CARTES À CHEVAL A UN REMBOURRAGE BAS PLUS GRAND
   QUE LE HAUT. Mesuré avec un rembourrage symétrique de 68 px : 22 px de texte
   passaient SOUS les cartes, la dernière ligne était mangée. Le débord n'était
   pas en cause, c'est la plaque qui n'avait pas réservé la place. C'est déjà
   la règle de `.soc-stage` sur la home (bas jusqu'à 100 px contre 89 en haut),
   on l'applique ici : le recouvrement mord du VIDE, jamais de la copie.
   `:has(+ .claims)` cible la seule plaque concernée — celle de clôture n'a
   rien sous elle et garde son rembourrage égal. */
.pf-plate:has(+ .claims) { padding-bottom: calc(clamp(34px, 5vw, 68px) + 55px); }
.pf-plate + .claims { margin-top: -89px; padding-inline: clamp(13px, 2vw, 34px); }

/* renvois vers les autres pages : la carte d'article du blog, réutilisée telle
   quelle plutôt qu'un troisième traitement inventé. */
.next-reads { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 21px; margin-top: 34px; }
@media (max-width: 700px) { .next-reads { grid-template-columns: 1fr; } }
@media (max-width: 1019px), (orientation: landscape) and (max-height: 520px) { .pf-plate + .claims { margin-top: -21px; padding-inline: 0; } }

/* ---------------------------------------------------------------------------
   §41 — UN LIEN DANS DU TEXTE EST BLEU ET SOULIGNÉ, PARTOUT (2026-08-12)
   « Tu veux pas mettre en bleu comme cela le lien ? c'est ce qu'on fait un peu
   partout. » Constat : la convention existait bien, mais écrite TROIS FOIS
   séparément (`.fa-bubble a`, `.qa a`, `.art a`) et jamais globalement. Donc
   tout lien posé hors de ces trois contextes héritait de l'encre du corps,
   sans soulignement : invisible. C'est ce qui est arrivé à « Toutes les
   questions sur les prix VTC → » quand on lui a retiré sa pastille — mesuré à
   rgb(42,39,33), texte-decoration none, c'est-à-dire un lien qu'aucun
   utilisateur ne peut deviner.
   🚨 RÈGLE : un lien DANS un paragraphe est bleu et souligné. On l'écrit une
   fois pour tout le site plutôt que de la répéter au cas par cas.
   Exclusions explicites : les boutons, les badges de store et le « lire la
   suite » des cartes, qui portent déjà leur propre traitement — et le lien
   qui EST une carte entière (`.post-card`), où c'est la carte qui répond au
   survol, pas le texte. */
/* 🚨 EXCLURE AUSSI CE QUI N'EST PAS UN LIEN DE TEXTE. Première version : les
   pastilles du sommaire FAQ (`.faq-index a`) sont des `a` dans des `li`, donc
   la règle les a happées. Deux dégâts : elles se sont soulignées comme de la
   prose, et surtout AU SURVOL le texte est resté bleu sur fond bleu, donc
   invisible — parce que cette règle pèse (0,5,2) avec ses quatre `:not()`
   quand `.faq-index a:hover` ne pèse que (0,2,1). Une règle globale doit
   nommer ce qu'elle ne touche pas, sinon elle gagne partout par accident. */
.section p > a:not(.btn):not(.store-badge):not(.rd):not(.post-card):not(.faq-index a),
.section li > a:not(.btn):not(.store-badge):not(.rd):not(.post-card):not(.faq-index a) {
  color: var(--blue); text-decoration: underline;
  text-underline-offset: 3px; text-decoration-thickness: 1px; }
/* sur une plaque bleue, un lien ne peut pas être bleu : il passe en crème */
.pf-plate p > a, .cta-band p > a { color: #FFFDF6; text-decoration-color: rgba(255,253,246,.5); }

/* ---------------------------------------------------------------------------
   §42 — LA NOTE DE SOURCE (fondateur 2026-08-12)
   « J'ai besoin que ces articles présentent des faits justes, avec de vraies
   sources d'information citées. » Le site n'avait AUCUN moyen de citer : les
   seuls liens externes des cinq articles du blog étaient les deux badges de
   store. Zéro source pour 53 phrases porteuses d'un fait vérifiable.
   🚨 LA DATE DE VÉRIFICATION FAIT PARTIE DE LA SOURCE. C'est la leçon de
   l'affaire Yango : la donnée était juste quand elle a été écrite, Yango a
   quitté l'Algérie le 1er août 2024, et rien dans le fichier ne disait quand
   la ligne avait été vérifiée. Une source sans date pourrit en silence.
   La note ne s'ajoute PAS partout : elle suit la phrase qui porte un chiffre,
   une date, un fait réglementaire ou une affirmation de marché. Le reste du
   texte n'en a pas besoin et une bibliographie décorative ne prouve rien. */
.src { font-size: .875rem; line-height: 1.55; color: var(--muted);
  border-inline-start: 2px solid var(--border-2); padding-inline-start: 13px;
  margin: -8px 0 21px; }
.src a { color: var(--blue); text-decoration: underline; text-underline-offset: 2px; }
.src time { font-variant-numeric: tabular-nums; }

/* ==========================================================================
   §43 — LA NOTE DE MÉTHODE DES NOTES D'APPLICATION (fondateur 2026-08-13)

   Les notes affichées sur les cartes venaient de deux sources sans le dire :
   du storefront français pour les unes, du store d'origine pour les autres.
   Waymo montrait ses 568 avis français, Curb ses 140 828 avis américains. Le
   biais n'était pas neutre — les apps françaises étaient déjà à leur taille
   réelle et toutes les autres écrasées d'un facteur 50 à 27 000, sur la page
   même qui prétend faire découvrir d'autres plateformes.

   Elles viennent maintenant d'une moyenne pondérée sur tous les storefronts où
   l'application est notée. Un chiffre construit doit dire comment il est
   construit : d'où cette note, et la date de relevé, parce qu'elle vieillira.

   Elle reprend `--muted` comme ses deux voisines `.ap-lead` et `.ap-count` —
   c'est du texte sur crème, le seul terrain pour lequel ce brun est calibré
   (4,87:1 sur #F4EDDC, au-dessus du seuil AA). */
.ap-note {
  max-width: 74ch;
  margin: 21px auto 0;
  padding-inline: 8px;
  font-size: .8125rem;
  line-height: 1.55;
  color: var(--muted);
  text-align: center;
  text-wrap: pretty;
}
/* L'astérisque marque le renvoi, il ne l'annonce pas. En bleu roi et en 700 à
   la taille du texte il pesait plus lourd que la phrase qu'il introduit ; il
   reste bleu pour se distinguer d'une virgule, mais en petit, sans graisse et
   remonté comme un vrai appel de note. */
.ap-ast {
  color: var(--blue); font-weight: 500;
  font-size: .78em; vertical-align: .35em; line-height: 1;
  margin-inline-end: 3px; opacity: .75;
}
.ap-note b { font-weight: 600; color: var(--ink-2); }
.ap-note time { font-variant-numeric: tabular-nums; }

/* Une carte d'étagère doit donner UN signal, pas deux. Deux notes côte à côte
   forçaient une comparaison que personne ne demande à ce niveau de lecture, et
   brouillaient l'indication au lieu de l'enrichir (constat du fondateur).

   La carte porte donc la note des DEUX magasins fondus, pondérée par leur
   nombre d'avis respectif. Les deux marques disent de quoi le chiffre est fait ;
   le détail magasin par magasin est dans la fiche, à un clic.

   Elles se SUPERPOSENT, comme une pile d'avatars : deux marques posées côte à
   côte se lisaient comme deux objets séparés, donc comme deux notes. Empilées,
   elles font un seul jeton, et c'est ce que le chiffre est. L'anneau à la
   couleur du plateau est ce qui rend le chevauchement lisible — sans lui les
   deux silhouettes fusionnent en une tache. */
.ap-score {
  flex: none; display: inline-flex; align-items: center; gap: 7px;
  font-family: var(--fb); font-size: 12.5px; font-weight: 700;
  color: var(--ink-2); font-variant-numeric: tabular-nums;
}
.ap-marks { display: inline-flex; align-items: center; flex: none; }
.ap-mk {
  width: 16px; height: 16px; flex: none; border-radius: 999px;
  background: var(--card); box-shadow: 0 0 0 1px rgba(32, 29, 21, .09);
  display: inline-grid; place-items: center;
}
.ap-mk::before {
  content: ''; width: 9px; height: 9px;
  background: var(--ink-2); opacity: .62;
  -webkit-mask: var(--mk) center / contain no-repeat;
          mask: var(--mk) center / contain no-repeat;
}
/* La première marque passe DEVANT : la pile se lit alors de gauche à droite,
   dans le sens de lecture, au lieu de sembler s'enfoncer. */
.ap-mk:first-child { position: relative; z-index: 1; }
.ap-mk + .ap-mk { margin-inline-start: -6px; }
.ap-mk--ios  { --mk: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M17.05 12.54c-.02-2.06 1.68-3.05 1.76-3.1-.96-1.4-2.45-1.6-2.98-1.62-1.27-.13-2.48.75-3.12.75-.64 0-1.64-.73-2.7-.71-1.39.02-2.67.81-3.38 2.05-1.44 2.5-.37 6.2 1.03 8.23.69 1 1.51 2.11 2.58 2.07 1.04-.04 1.43-.67 2.69-.67 1.25 0 1.61.67 2.7.65 1.11-.02 1.82-1.01 2.5-2.02.79-1.16 1.11-2.28 1.13-2.34-.02-.01-2.17-.83-2.19-3.29zM15.1 6.2c.57-.69.95-1.65.85-2.6-.82.03-1.81.55-2.4 1.23-.53.61-.99 1.58-.87 2.51.91.07 1.85-.46 2.42-1.14z'/%3E%3C/svg%3E"); }
.ap-mk--play { --mk: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M7 4.1c0-.9 1-1.4 1.7-.9l11.1 7.9c.6.4.6 1.4 0 1.8L8.7 20.8c-.7.5-1.7 0-1.7-.9z'/%3E%3C/svg%3E"); }
/* Le triangle plein occupe sa boîte : c'est la silhouette officielle en quatre
   morceaux qui demandait d'être rapetissée, parce qu'elle projetait un éclat
   détaché sur sa droite. Banc d'essai du 2026-08-13 : à 48 px elle se lisait
   comme deux formes, à 9 px comme une tache avec un point. */
.ap-mk--play::before { width: 8.5px; height: 8.5px; margin-inline-start: .5px; }

/* ---- La fiche : deux colonnes, pas deux lignes ----------------------------
   `.as-rating` était calibrée comme UNE pastille (4px 12px, rayon 999) ; en y
   empilant deux lignes elle devenait un losange. Les deux magasins prennent
   donc une colonne chacun, séparés d'un filet, avec la même grille interne :
   le nom du magasin, la note, le volume. Les deux notes tombent ainsi à la
   MÊME hauteur optique — c'est ce qui rend l'écart lisible d'un coup d'œil
   (Curb : 4,8 à gauche, 1,2 à droite). */
/* La capsule REVIENT, et elle n'est pas décorative : sur le bandeau, du texte
   crème passe sous 4,5:1 pour 26 des 39 couleurs de marque (DodoGo 1,07,
   Yandex Go 1,20). Elle porte seule la lisibilité. La sortir du bandeau pour
   s'en passer donnait « une case bizarre en dehors du plateau de la couleur de
   l'app » — rejeté par le fondateur. */
.as-rating {
  display: grid; grid-auto-flow: column; grid-auto-columns: 1fr;
  padding: 10px 5px; border-radius: 20px; min-width: 208px;
  background: rgba(255, 253, 246, .94); color: var(--ink);
  border: 0; margin: 0;
}
.as-rate {
  display: grid; gap: 3px; justify-items: center; align-content: center;
  padding: 0 16px;
}
.as-rate + .as-rate { border-inline-start: 1px solid rgba(32, 29, 21, .13); }
.as-rate .sr-val {
  display: inline-flex; align-items: center; gap: 5px;
  font-family: var(--fd); font-size: 1.125rem; font-weight: 800;
  line-height: 1; color: var(--ink); font-variant-numeric: tabular-nums;
}
.as-rate .sr-val::before {
  content: ''; width: 14px; height: 14px; flex: none;
  background: currentColor; opacity: .55;
  -webkit-mask: var(--mk) center / contain no-repeat;
          mask: var(--mk) center / contain no-repeat;
}
.as-rate .sr-n {
  font-family: var(--fb); font-size: .6875rem; font-weight: 600;
  color: var(--muted); white-space: nowrap; font-variant-numeric: tabular-nums;
}
.as-rate--ios  { --mk: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M17.05 12.54c-.02-2.06 1.68-3.05 1.76-3.1-.96-1.4-2.45-1.6-2.98-1.62-1.27-.13-2.48.75-3.12.75-.64 0-1.64-.73-2.7-.71-1.39.02-2.67.81-3.38 2.05-1.44 2.5-.37 6.2 1.03 8.23.69 1 1.51 2.11 2.58 2.07 1.04-.04 1.43-.67 2.69-.67 1.25 0 1.61.67 2.7.65 1.11-.02 1.82-1.01 2.5-2.02.79-1.16 1.11-2.28 1.13-2.34-.02-.01-2.17-.83-2.19-3.29zM15.1 6.2c.57-.69.95-1.65.85-2.6-.82.03-1.81.55-2.4 1.23-.53.61-.99 1.58-.87 2.51.91.07 1.85-.46 2.42-1.14z'/%3E%3C/svg%3E"); }
.as-rate--play { --mk: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M7 4.1c0-.9 1-1.4 1.7-.9l11.1 7.9c.6.4.6 1.4 0 1.8L8.7 20.8c-.7.5-1.7 0-1.7-.9z'/%3E%3C/svg%3E"); }

/* Les deux magasins partagent la ligne à parts égales. `flex: 1 1 0` et non
   `1 1 auto` : avec `auto`, la largeur naturelle des libellés les faisait
   passer à la ligne et la fiche devenait un empilement de dalles. */
.as-stores { display: flex; gap: 9px; }
.as-stores .btn { flex: 1 1 0; min-width: 0; min-height: 46px; padding-inline: 8px; }
.as-stores .btn-ghost {
  background: transparent; color: var(--blue-ink);
  border: 1.5px solid color-mix(in srgb, var(--blue) 28%, transparent);
}
.as-stores .btn-ghost:hover { border-color: var(--blue); background: rgba(34, 68, 204, .05); }
@media (max-width: 380px) { .as-stores { flex-direction: column; } }

/* ==== §45 — LE (i) AU COIN DU PLATEAU (fondateur 2026-08-13) ===============
   Deux corrections successives. D'abord un pavé de quatre lignes sous la
   section : trop long, et on lisait l'explication après avoir quitté ce qu'elle
   explique. Puis un (i) bleu centré sous le compteur : il ajoutait une
   TROISIÈME ligne au-dessus de la liste (recherche, compteur, méthode) et son
   bleu en faisait une action alors que c'est une précision.

   Il sort donc du flux, au coin du plateau, en encre atténuée. Sa phrase
   s'ouvre juste en dessous, alignée à droite sur lui. */
.ap-i {
  /* Posé DANS le plateau (`.ap-stage-wrap`, le seul ancêtre en `relative`),
     retiré de son angle : à `top/right: 0` il chevauchait l'arrondi du squircle
     et flottait à moitié sur le crème. Et sa bordure ne prend surtout pas
     `--border-2`, qui est un bleu à 24 % — le fondateur ne veut pas d'un bleu
     ici, qui ferait lire une action là où il n'y a qu'une précision. */
  position: absolute; bottom: 18px; right: 21px; z-index: 3;
  width: 20px; height: 20px; padding: 0;
  border: 1.5px solid rgba(32, 29, 21, .17); border-radius: 999px;
  background: transparent; cursor: pointer;
  font-family: var(--fb); font-size: 11px; font-weight: 700; line-height: 1;
  color: var(--muted);
  transition: color .18s, border-color .18s, background .18s;
}
.ap-i:hover { color: var(--ink-2); border-color: rgba(32, 29, 21, .38); }
.ap-i[aria-expanded="true"] { color: #FFFDF6; background: var(--ink-2); border-color: var(--ink-2); }
.ap-method {
  position: absolute; bottom: 46px; right: 21px; z-index: 3;
  width: min(320px, calc(100vw - 52px));
  margin: 0; padding: 14px 16px;
  background: var(--card); border-radius: 18px;
  box-shadow: 0 2px 5px rgba(32, 29, 21, .07), 0 18px 40px -18px rgba(32, 29, 21, .32);
  font-size: .8125rem; line-height: 1.5; color: var(--ink-2); text-align: start;
}
.ap-method[hidden] { display: none; }
.ap-method time { font-variant-numeric: tabular-nums; }

/* ============ 46 — LE FILET DU `mailto:` ============ */
/* N'apparaît que si le clic n'a ouvert aucune messagerie. Discret : c'est un
   secours, pas un élément de la composition. */
.mail-fallback { display: flex; flex-wrap: wrap; align-items: center;
  justify-content: center; gap: 8px; margin-top: 13px; width: 100%; }
.mail-fallback small { font-family: var(--fb); font-size: .8125rem;
  color: #8E8E93; }
.mail-copy { font-family: var(--fb); font-size: .875rem; font-weight: 600;
  color: var(--blue); background: var(--card); cursor: pointer;
  border: 1.5px solid rgba(32,29,21,.13); border-radius: 999px;
  padding: 7px 15px; transition: border-color .2s, color .2s; }
.mail-copy:hover { border-color: rgba(34,68,204,.4); }
.mail-copy.is-ok { color: #1F7A45; border-color: rgba(31,122,69,.35); }

/* ==== §47 — « Remonter » (fondateur 13/08, iPhone) : une pastille fixe en bas
   du côté de fin de lecture (inset-inline-end : droite en LTR, gauche en RTL),
   qui n'apparaît qu'après deux écrans de défilement. Sous le drawer (z 1100). */
/* Redessinée le 14/08 (fondateur : « pas très beau ») : pastille BLEU ROI
   pleine, flèche blanche — le langage des CTA de l'app, plus un fantôme à
   bordure. Et elle ne vit plus qu'en REMONTANT (logique gérée par fab.js). */
/* 🚨 Ombre = la recette des îlots nav, prouvée sur device le 13/08 : halo
   large mais SERRÉ (-13 de spread). L'ancienne (29px de flou, navy 50 %)
   se faisait recadrer par la couche de composition iOS pendant le fondu —
   voile rectangulaire autour de la pastille (constat d'Alex). Le
   tap-highlight iOS (flash rectangulaire au doigt) est coupé aussi. */
.to-top { position: fixed; inset-inline-end: 16px; bottom: calc(16px + env(safe-area-inset-bottom, 0px)); z-index: 55;
  width: 47px; height: 47px; border-radius: 999px; border: none;
  background: var(--blue); color: #FFFDF6; display: grid; place-items: center; cursor: pointer;
  box-shadow: 0 2px 5px rgba(32,29,21,.12), 0 21px 42px -13px rgba(25,44,134,.34);
  -webkit-tap-highlight-color: transparent;
  opacity: 0; transform: translateY(13px); pointer-events: none;
  transition: opacity .28s ease, transform .28s cubic-bezier(.16,1,.3,1), background .2s; }
.to-top.on { opacity: 1; transform: none; pointer-events: auto; }
/* 🚨 2026-08-14 (constat device) : la pastille se posait sur les boutons de la
   fiche app (elle vivait dans un autre contexte d'empilement que la veil).
   Drawer ou fiche ouverts -> elle s'efface, quoi qu'il arrive au z-order. */
body.drawer-open .to-top, body.sheet-open .to-top { opacity: 0; pointer-events: none; }
.to-top svg { width: 18px; height: 18px; display: block; transition: transform .21s cubic-bezier(.34,1.35,.4,1); }
/* v2 (14/08, demande d'Alex) : la MÊME pastille sert dans les deux sens —
   flèche vers le bas quand on descend (saut au pied de page), vers le haut
   quand on remonte. Le sens vit sur cette classe, posée par fab.js. */
.to-top--down svg { transform: rotate(180deg); }
/* rangée = flip instantané : sinon on la voyait APPARAÎTRE rotation en
   cours, lu comme « pas fluide » (constat d'Alex du 14/08 au soir). */
.to-top:not(.on) svg { transition: none; }
@media (hover: hover) { .to-top:hover { background: var(--blue-ink); } }
@media (prefers-reduced-motion: reduce) { .to-top, .to-top svg { transition: none; } }
