/* ===========================================================================
   REPREASE, site vitrine reprease.fr
   Refonte 2026-07-26 : brutalisme vers SOBRE, aligné sur app.reprease.fr
   (réf. Stripe / Linear / Pennylane). Fondation : tokens.css (chargé AVANT).

   Règle d'or reprise de l'app : en cas de doute, l'option la plus discrète.
   La donnée est la star, pas l'interface. Le NOIR porte le sérieux, le JAUNE
   #FFD60A ponctue (CTA principal, focus), jamais en grand aplat.

   INTERDITS (hérités de l'app) : emojis en guise d'icônes (SVG inline
   uniquement), border-left 4px colorée, em-dash, texte blanc sur fond clair,
   dégradés multicolores.

   MOUVEMENT (règle posée le 2026-07-26) : le site ne bouge que lorsque le
   visiteur agit. Aucune boucle, aucune apparition au défilement, aucun
   compteur, aucun texte qui se dessine, aucune nappe de couleur animée. Une
   page qui s'anime toute seule se lit comme un gabarit : sur un produit qui
   vend de la rigueur comptable, c'est exactement le signal à ne pas envoyer.
   Il ne reste donc que trois motifs de transition, tous en réponse à un geste :
     - survol / focus d'un élément cliquable (fond, bordure, couleur), 150 ms ;
     - ouverture d'un accordéon ou bascule d'onglet, 180 ms, opacité seule ;
     - entrée de la barre d'offre, déclenchée par le défilement, une seule fois.
   Rien d'autre. Pas de translation décorative, pas d'ombre qui enfle.

   HIÉRARCHIE : elle passe par la typographie, le blanc et un filet de 1 px.
   Pas par des ombres portées, des pilules colorées ou des lueurs radiales.
   =========================================================================== */

/* ── Alias de compatibilité avec app.css (mêmes noms, même vocabulaire) ── */
:root{
  --bg:var(--bg-app); --surface:var(--bg-surface); --surface-sunken:var(--bg-surface-sunken);
  --ink:var(--text-primary); --muted:var(--text-muted); --faint:var(--color-neutral-400);
  --line:var(--border-default); --line-2:var(--border-strong);
  --primary:var(--color-primary); --primary-hover:var(--color-primary-hover);
  --on-primary:var(--color-on-primary);
  --bad:var(--color-danger); --bad-strong:#F0836F; --bad-t:var(--color-danger-subtle);
  /* --bad-strong est calibré pour le fond charbon. Sur l'off-white du thème
     clair il tombe à 2,6:1 : on bascule sur le rouge sombre (5,4:1). */
  --ok:var(--color-success); --ok-t:var(--color-success-subtle);
  --warn:var(--color-warning); --warn-t:var(--color-warning-subtle);
  --radius:var(--radius-md);
  --font:var(--font-sans);
  --wrap:1160px;

  /* ── Rôles typographiques (ajoutés le 2026-07-28) ────────────────────────
     `--font-mono` (IBM Plex Mono) tenait cinq emplois à lui seul : les
     surtitres, les prix, les scores, les étiquettes et les sorties machine.
     Vingt-quatre déclarations dans cette feuille. Une chasse fixe sur tout ce
     qui n'est pas de la prose, c'est le réglage « terminal » : c'est de là que
     venait l'air brutaliste. Ni Linear ni Stripe ne composent leurs prix ou
     leurs surtitres en mono, ils les composent dans leur sans avec les
     chiffres tabulaires. Le résultat n'est pas plus mou, il est plus cher.

     Trois rôles, trois familles :
       --font-num    chiffres qui doivent s'aligner en colonne (prix, scores,
                     KPI, tableaux). Sans + chiffres tabulaires : même largeur
                     de chiffre, sans la silhouette de machine à écrire. Le
                     `font-feature-settings` du <body> pose déjà « tnum ».
       --font-label  étiquettes et surtitres. Sans, capitales, chasse ouverte.
       --font-code   ce que la MACHINE a lu ou produit, et rien d'autre : une
                     URL, un SIREN, la liste des postes extraits d'une liasse.
                     Là, la chasse fixe est une information et pas un effet.
                     C'est tout ce qui reste d'IBM Plex Mono, et ça lui rend
                     son sens : quand vous voyez du mono sur ce site, c'est que
                     vous regardez une sortie de l'outil.

     Aucun jeton de tokens.css n'est touché : ce fichier reste la copie
     conforme de l'app. Ces trois-là sont des rôles propres à la vitrine. */
  --font-num:   var(--font-sans);
  --font-label: var(--font-sans);
  --font-code:  var(--font-mono);
}

/* ===========================================================================
   COUCHE « FINITION », ajoutée le 2026-07-26 après relevé de linear.app et
   stripe.com dans le navigateur. Trois écarts assumés avec les tokens de
   l'app, tous mesurés sur ces deux références :

   1. RAYONS PLUS PETITS. Rayons les plus fréquents relevés chez Linear :
      2 px (48 occurrences), 6 px (43), 4 px (28), 8 px (15). Chez Stripe :
      4 px (66), 6 px (41), 1 px (31). Aucun des deux ne travaille à 8-12 px.
      Le grand rayon adoucit, et l'adoucissement fait « application grand
      public » ; l'angle vif fait « instrument ». On descend d'un cran partout.

   2. FILETS EN OMBRE INTERNE plutôt qu'en bordure. Linear cerne ses surfaces
      avec `inset 0 0 0 1px`. L'intérêt n'est pas cosmétique : une ombre ne
      participe pas à la mise en page, donc les grilles s'alignent au pixel
      sans avoir à compter les bordures, et le filet ne bouge pas quand un
      élément passe en survol.

   3. OMBRES LARGES, BASSES ET TEINTÉES. Relevé chez Stripe :
      `0 30px 60px -50px rgba(0,0,0,.1), 0 30px 60px -10px rgba(50,50,93,.25)`.
      Soixante pixels de flou, un étalement négatif, et une teinte bleutée et
      non du noir pur. C'est ce qui donne l'impression d'objet posé sur la page
      plutôt que de rectangle collé dessus. Nos anciennes ombres (3 px de flou,
      noir pur) ne faisaient que salir le bord.
   =========================================================================== */
:root{
  --radius-sm:4px; --radius-md:6px; --radius-lg:8px;
  /* Rayon minuscule, réservé à la coiffe des barres de données. Une barre de
     9 px de large avec un rayon de 4 px devient une gélule et perd sa lecture
     de valeur ; 3 px adoucit l'arête sans déformer la donnée. C'est un rôle,
     pas un cran de l'échelle : il ne s'emploie nulle part ailleurs. */
  --radius-bar:3px;

  /* Modulations de lumière sur les boutons pleins. Ce ne sont pas des couleurs
     de la charte, ce sont du blanc et du noir dosés très bas pour donner une
     arête haute éclairée et un bord refermé. Sortis des règles pour n'exister
     qu'une fois, comme les jaunes assombris du thème clair. */
  --edge-light:rgba(255,255,255,.45);
  --edge-dark:rgba(0,0,0,.06);

  /* Encre et papier. Ces deux valeurs ne servent QUE dans @media print et ne
     sont pas des couleurs de la charte : sur du papier, la cible est le noir
     sur blanc, pas l'off-white ni le charbon de l'écran. Elles sont ici parce
     qu'écrites en dur dans la règle d'impression elles ressemblaient à une
     dérive, alors que c'est un choix. Si un jour on veut économiser l'encre,
     --print-ink passe à #222 et c'est le seul endroit à toucher. */
  --print-bg:#fff;
  --print-ink:#000;

  /* Mêmes valeurs exactement que --border-default et --border-strong des
     tokens : filets en bordure et filets en ombre cohabitent dans la page
     (les tableaux et les listes gardent de vraies bordures), il ne faut pas
     qu'on voie deux gris de filet différents d'un bloc à l'autre. */
  --ring:       inset 0 0 0 1px rgba(255,255,255,.09);
  --ring-strong:inset 0 0 0 1px rgba(255,255,255,.15);
  /* Sur le charbon, une ombre noire ne se voit pas : c'est le filet qui porte
     la séparation, et l'ombre ne sert qu'aux objets réellement flottants. */
  --elev-1: 0 1px 2px rgba(0,0,0,.30);
  --elev-2: 0 16px 40px -12px rgba(0,0,0,.66), 0 2px 8px rgba(0,0,0,.28);
}
:root[data-theme="light"]{
  --ring:       inset 0 0 0 1px rgba(20,18,15,.10);
  --ring-strong:inset 0 0 0 1px rgba(20,18,15,.16);
  /* Teinte bleutée reprise de Stripe : une ombre grise pure fait terne, la
     même ombre poussée vers le bleu fait « imprimé ». */
  --elev-1: 0 1px 2px rgba(38,44,74,.07);
  --elev-2: 0 24px 48px -20px rgba(38,44,74,.28), 0 2px 6px rgba(38,44,74,.06);
}

/* ── Correctifs de contraste (WCAG AA) ──────────────────────────────────────
   Mesuré sur les tokens tels quels, texte normal, seuil 4,5:1 :
     - thème SOMBRE : --faint (#6A6F76) plafonne à 3,5:1 ;
     - thème CLAIR  : --text-muted (#86857D) à 3,6:1 et --faint (#A8A69E) à 2,2:1.
   Or une bonne partie du petit texte d'une vitrine porte du sens (mentions de
   prix, notes de bas de carte, disclaimers légaux) : ces tons ne peuvent pas
   rester décoratifs. On remonte donc UNIQUEMENT les gris de texte ; aucune
   teinte de marque n'est touchée, l'identité est identique à l'app.
   À répercuter dans app.reprease.fr/public/app/tokens.css. */
:root{ --color-neutral-400:#9298A0; }                 /* --faint sombre : 3,5 -> 6,2:1 */
:root[data-theme="light"]{
  --color-neutral-500:#6E6D66;                        /* --text-muted clair : 3,6 -> 4,9:1 */
  --color-neutral-400:#6B6A62;                        /* --faint clair     : 2,2 -> 5,2:1 */
  --bad-strong:var(--color-danger);

  /* Jaune de marque assombri pour le thème clair. Sur l'off-white, #FFD60A ne
     tient pas la lecture d'un trait fin : ces deux valeurs gardent la teinte de
     la marque et ne bougent que la luminosité. Deux crans, parce qu'un souligné
     de 3 px et un trait de schéma de 3 px n'ont pas le même besoin. Elles
     étaient écrites en dur dans deux règles : une seule source désormais. */
  --primary-ink:#E8BE00;      /* souligné de titre */
  --primary-stroke:#C9A400;   /* traits de schéma */
}

/* ── Reset ── */
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
html{scroll-behavior:smooth;-webkit-text-size-adjust:100%}
/* `background:transparent` et non `var(--bg)` : la couleur ET la trame sont
   portées par `html` (voir « La feuille réglée »). Un fond plein ici les
   recouvrirait toutes les deux. */
body{
  font-family:var(--font);background:transparent;color:var(--ink);
  line-height:var(--leading-normal);-webkit-font-smoothing:antialiased;
  font-feature-settings:var(--numeric-tabular);
  transition:color .2s ease;
  overflow-x:hidden;
}
/* ── Le fond de page ────────────────────────────────────────────────────────
   RETIRÉ le 2026-07-29 : le quadrillage.

   Jonathan : « j'ai bien l'impression que le quadrillage tu le fais à tout le
   monde ». Il avait raison, et c'était une critique que j'aurais dû me faire.
   Le fond quadrillé est LE cliché des pages techniques depuis trois ans, et je
   l'avais justifié après coup (« un bilan se lit sur du papier quadrillé »)
   alors que je l'avais posé parce que c'est ce qui vient en premier quand on
   cherche « de la texture technique ». Exactement le réflexe qu'on passe cette
   refonte à éliminer.

   Ce qui le remplace ne se pose pas sur `html` mais section par section : voir
   « LA MARGE DE CLASSEUR » plus bas. La couleur de fond reste ici, et le
   `body` reste transparent, parce que le grain a besoin que la couleur soit
   peinte par l'élément racine. */
html{
  background-color:var(--bg);
  transition:background-color .2s ease;
}

/* ── Grain ──────────────────────────────────────────────────────────────────
   Un aplat de couleur parfaitement uniforme n'existe pas dans le monde
   physique : ni sur du papier, ni sur une photo, ni sur une surface peinte.
   C'est pour ça qu'une page en aplats purs a toujours l'air d'un rendu, et
   c'est une des raisons pour lesquelles « ça fait généré » sans qu'on sache
   dire pourquoi. Trois pour cent de bruit fixe suffisent à donner de la
   matière au fond sans qu'on identifie le procédé.

   Le bruit est produit par un filtre SVG en `data:` : aucun fichier à charger,
   aucune requête réseau, 400 octets dans la feuille de style. La tuile fait
   160 px et se raccorde (`stitchTiles`), donc pas de couture visible.

   `position:fixed` : le grain appartient à l'ÉCRAN, pas au document. S'il
   défilait avec la page, il redeviendrait une texture posée sur un objet.
   `pointer-events:none` : il ne peut intercepter aucun clic.
   Si un jour il faut le retirer, c'est cette seule règle à supprimer. */
body::after{
  content:"";position:fixed;inset:0;z-index:9999;pointer-events:none;
  opacity:var(--grain-a);
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23g)'/%3E%3C/svg%3E");
}
/* Monté de 3,2 à 4,4 % le 2026-07-28 : à 3 % l'effet était mesurable mais
   invisible, ce qui revient à ne pas l'avoir fait. */
:root{ --grain-a:.044 }
/* Sur l'off-white, le même bruit se lit deux fois plus : le contraste entre le
   grain et un fond clair est plus fort qu'avec le charbon. On le baisse. */
:root[data-theme="light"]{ --grain-a:.026 }
/* Le grain est un effet de matière, pas une information. Sur les appareils qui
   demandent moins d'effets, et à l'impression, il disparaît entièrement. */
@media(prefers-reduced-transparency:reduce){ body::after{display:none} }

img,svg{max-width:100%;height:auto;display:block}
a{color:inherit;text-decoration:none}
button{font-family:inherit;cursor:pointer;border:none;background:none;color:inherit}
ul{list-style:none}
:focus-visible{outline:none;box-shadow:var(--focus-ring);border-radius:var(--radius-sm)}
::selection{background:var(--color-primary);color:var(--on-primary)}

/* ── Accessibilité ── */
.skip-link{position:absolute;left:-9999px;top:0;z-index:999;background:var(--primary);color:var(--on-primary);
  padding:10px 16px;font-weight:600;border-radius:0 0 var(--radius-sm) 0}
.skip-link:focus{left:0}
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}

/* ===========================================================================
   Layout
   =========================================================================== */
.wrap{max-width:var(--wrap);margin:0 auto;padding:0 24px}
.wrap-narrow{max-width:820px;margin:0 auto;padding:0 24px}
.section{padding:88px 0}
.section.tight{padding:56px 0}
.section.alt{background:var(--surface)}
.section+.section{border-top:1px solid var(--line)}
@media(max-width:760px){ .section{padding:56px 0} .wrap,.wrap-narrow{padding:0 18px} }

/* ===========================================================================
   LA MARGE DE CLASSEUR (2026-07-29)
   ===========================================================================
   Remplace la colonne réglée symétrique, elle-même venue remplacer le
   quadrillage. Le raisonnement complet est dans DESIGN.md ; l'essentiel tient
   en une phrase : le fond doit venir du bureau de Jonathan, pas d'une
   bibliothèque de composants.

   Une bande perforée court dans la marge GAUCHE, d'un bout à l'autre de la
   page, sans interruption d'une section à la suivante. C'est elle qui fait le
   liant que le quadrillage faisait : remplir le vide et rattacher les sections
   les unes aux autres. Elle le fait mieux, parce qu'elle est CONTINUE au lieu
   d'être répétée.

   L'ASYMÉTRIE EST LE SUJET. Le bord gauche est relié, le bord droit reste un
   simple filet. C'est une feuille rangée dans un classeur : elle est prise
   d'un côté et libre de l'autre. Deux filets symétriques ne disaient rien.
   Et au-delà de 1320 px la maquette du hero part à fond perdu vers la droite :
   la page est donc tenue à gauche et ouverte à droite, dans les deux registres
   à la fois.

   LA BANDE EST DANS LA MARGE, PAS DANS LA COLONNE. Elle se pose entre le bord
   de la fenêtre et le bord de la colonne utile, donc elle ne décale aucun
   contenu et ne coûte pas un pixel de largeur de lecture.

   AU-DESSUS DE 1320 px SEULEMENT, même seuil que le fond perdu. En dessous, il
   n'y a pas de marge où la mettre : elle se collerait au bord de la vitre. Sur
   téléphone il n'y a donc ni bande ni filet, seulement le grain, et c'est la
   bonne réponse : le vide qu'un fond doit remplir n'existe pas quand le
   contenu occupe toute la largeur.

   Tout est peint en couches de `background-image` sur un pseudo-élément : les
   perforations sont un dégradé radial répété verticalement, les deux filets
   des rectangles de 1 px. Ni balise, ni bordure, ni participation à la mise en
   page. */
:root{
  --rule:rgba(255,255,255,.055);      /* la perforation */
  --rule-fort:rgba(255,255,255,.085); /* les filets */
  /* Les equerres de coupe de la maquette, seul reste du vocabulaire
     d'imprimeur. Elles tiennent sur UN objet et pas sur le fond de page,
     donc elles restent : une epreuve d'imprimerie porte ses traits de
     coupe, et c'est le meme bureau que le stylo rouge. */
  --tick:rgba(255,255,255,.20);
}
:root[data-theme="light"]{
  --rule:rgba(20,18,15,.07);
  --rule-fort:rgba(20,18,15,.10);
  --tick:rgba(20,18,15,.24);
}
@media(min-width:1320px){
  .hero,.section,.sources{position:relative}
  .hero::after,.section::after,.sources::after{
    content:"";position:absolute;top:0;bottom:0;pointer-events:none;z-index:0;
    /* de 46 px à gauche de la colonne utile, jusqu'au bord droit de celle-ci */
    left:calc(50% - var(--wrap)/2 - 46px);
    right:calc(50% - var(--wrap)/2);
    background-repeat:repeat-y,no-repeat,no-repeat;
    background-image:
      /* perforations : le centre du cercle est au MILIEU de la tuile (18/46),
         pas sur son bord, sinon chaque trou est coupé en deux. */
      radial-gradient(circle at 18px 46px,var(--rule) 6px,transparent 6.5px),
      linear-gradient(var(--rule-fort),var(--rule-fort)),
      linear-gradient(var(--rule-fort),var(--rule-fort));
    background-size:36px 92px,1px 100%,1px 100%;
    /* la bande, son filet de fermeture à 36 px, et le bord libre à droite */
    background-position:left top,36px 0,right 0;
  }
  /* Le contenu passe devant. Sans ça, le pseudo-élément, qui est positionné,
     se peindrait par-dessus le texte de la section. */
  .hero>*,.section>*,.sources>*{position:relative;z-index:1}
}

/* ── Le filigrane ───────────────────────────────────────────────────────────
   Un chiffre de la section, énorme et presque invisible, en bas à droite.
   Ce n'est pas du remplissage : c'est le chiffre dont la section parle, redit
   en très grand. 78 derrière le score, 49 derrière les tarifs.

   Deux règles qui font la différence entre un procédé et un tic :
     - il porte une valeur RÉELLE de la section, jamais un numéro d'ordre ni un
       code de formulaire (Jonathan a écarté les codes de liasse comme trop
       jargonneux, et un numéro de section serait pire : il ne dirait rien) ;
     - toutes les sections n'en ont pas. Une sur deux ou sur trois, celles qui
       portent un chiffre qui compte. Posé partout, il s'annule.

   Le contenu vient de l'attribut `data-filigrane` : rien à écrire dans le
   markup au-delà de la valeur elle-même, et aucune balise vide à maintenir.
   `overflow:hidden` sur la section fait déborder le chiffre par le bas, ce qui
   lui donne son échelle : on ne le lit pas, on le devine.

   Taille en `clamp()` et non en valeur fixe : c'est un rôle typographique
   nouveau et assumé, documenté dans DESIGN.md. À 200 px sur un téléphone il
   passerait devant le texte au lieu de rester derrière. */
:root{ --filigrane:.055 }
:root[data-theme="light"]{ --filigrane:.05 }
.section[data-filigrane]{position:relative;overflow:hidden}
.section[data-filigrane]::before{
  content:attr(data-filigrane);
  position:absolute;z-index:0;pointer-events:none;
  right:calc(50% - var(--wrap)/2 + 6px);bottom:-.3em;
  font-size:clamp(104px,15vw,200px);font-weight:800;line-height:1;
  letter-spacing:-.05em;font-variant-numeric:tabular-nums;
  color:var(--ink);opacity:var(--filigrane);
  -webkit-user-select:none;user-select:none;
}
/* Sous la largeur de la colonne utile, le calcul ci-dessus sortirait le
   chiffre de l'écran : on le cale simplement sur la gouttière. */
@media(max-width:1208px){
  .section[data-filigrane]::before{right:18px}
}

/* ── Titrage ── */
/* Capitales composées dans le sans et non plus dans le mono : sur une étiquette
   de deux mots, la chasse fixe alourdit sans rien apprendre. La chasse passe en
   `em` (.085em) parce que des capitales serrées se lisent mal, et que le réglage
   doit tenir si la taille bouge. 12 px reste le plancher d'étiquette. */
.eyebrow{
  display:inline-flex;align-items:center;gap:10px;font-family:var(--font-label);
  font-size:12px;font-weight:600;text-transform:uppercase;letter-spacing:.085em;
  color:var(--muted);margin-bottom:18px;
}
.eyebrow::before{content:"";width:22px;height:1px;background:var(--line-2)}
/* Le centrage était posé en `style="justify-content:center"` sur cinq surtitres.
   Une règle de présentation répétée en ligne cinq fois est une classe qui
   s'ignore, et elle échappe au thème comme au reste de la feuille. */
.eyebrow.center-self{justify-content:center}
/* text-wrap:balance répartit les mots sur toutes les lignes d'un titre au lieu
   de laisser un orphelin en dernière ligne. C'est la composition, pas un
   détail : un titre mal cassé fait amateur. `pretty` évite les veuves dans le
   corps de texte. Ignoré sans dommage par les navigateurs qui ne le gèrent pas. */

/* ── Titrage : graisse, chasse et interligne ────────────────────────────────
   Relevé sur linear.app et stripe.com (mesuré dans le navigateur, pas de
   mémoire), parce que c'est là que se joue l'essentiel de l'écart de
   perception :

     Linear   H1 64px  graisse 510  chasse -0,022em  interligne 1,00
     Linear   H2 72px  graisse 510  chasse -0,022em  interligne 1,00
     Stripe   H2 56px  graisse 300  chasse -0,025em  interligne 1,03
     Stripe   H1 40px  graisse 300  chasse -0,020em  interligne 1,15

   Aucun des deux ne titre en gras. Le titrage à 700, c'est le réglage par
   défaut des gabarits, et c'est ce qui fait « site fait vite ». Une police de
   titrage chère se reconnaît à trois choses : une graisse moyenne, une chasse
   resserrée, un interligne proche de 1. On descend donc à 500 pour l'affichage
   (IBM Plex Sans Medium, déjà chargée) et on serre.

   Écart assumé avec les tokens de l'app : `--font-bold` reste défini, il sert
   toujours au petit texte fort (`<strong>`, `<b>`) ; seul le TITRAGE de la
   vitrine descend. À répercuter dans l'app si la direction est validée.

   La chasse passe en `em` et non en `px` : les tailles sont des `clamp()`, et
   une chasse fixe de -1,2 px sur un H1 rendu à 2 rem en mobile faisait -0,037em,
   soit un titre étouffé sur petit écran. En `em` le réglage suit la taille. */
h1,h2,h3,h4{color:var(--ink);text-wrap:balance;font-weight:var(--font-semibold);
  line-height:var(--leading-tight);letter-spacing:-.012em}
/* Interligne 1,12 et non 1,04 : Linear peut se permettre 1,00 parce que ses
   titres ne portent aucune décoration. Le nôtre porte un souligné jaune de
   3 px sur plusieurs lignes. Mesuré à 56 px : le bas du filet tombe à 17,56 px
   sous la ligne de base, les hampes de la ligne suivante (b, l, d) montent à
   17,24 px. À 1,04, le filet passe DANS le mot du dessous. 1,12 laisse quatre
   pixels de respiration. C'est une contrainte réelle, pas un arrondi de
   confort : si le souligné disparaît un jour, on peut redescendre à 1,04. */
h1{font-size:clamp(2.1rem,4.8vw,3.5rem);font-weight:var(--font-medium);
  letter-spacing:-.028em;line-height:1.12}
h2{font-size:clamp(1.65rem,3.2vw,2.45rem);font-weight:var(--font-medium);
  letter-spacing:-.024em;line-height:1.1}
h3{font-size:1.0625rem;letter-spacing:-.011em;line-height:1.35}
/* Un slogan porte ses propres retours à la ligne (voir config/landings.php) :
   l'équilibrage automatique les combattrait. */
h1.slogan{text-wrap:normal}
/* Le chapô est le deuxième niveau de lecture, pas le premier : chez Linear le
   sous-titre de 48 px est carrément en gris moyen. On reste au gris secondaire,
   mais avec la chasse légèrement resserrée qui va avec cette taille. */
.lead{font-size:clamp(1.02rem,1.5vw,1.18rem);color:var(--text-secondary);line-height:1.55;
  max-width:60ch;letter-spacing:-.011em;text-wrap:pretty}
.muted{color:var(--muted)}
.center{text-align:center}
.center .lead{margin-left:auto;margin-right:auto}
.section-title{max-width:44rem;margin-bottom:44px}
.section-title.center{margin-left:auto;margin-right:auto}
.section-title p{margin-top:14px}

/* Accentuation d'un membre de phrase dans un titre.
   Un aplat de surligneur (le « marqueur fluo » posé sur trois mots du H1) est
   devenu la signature des pages générées : il crie avant d'être lu, et le fond
   jaune force à retoucher le contraste dans les deux thèmes. Un simple souligné
   de 3 px sous le texte dit la même chose, se compose comme de la typographie
   et suit les retours à la ligne sans qu'on ait rien à gérer.

   Le décalage vaut .26em et non la valeur par défaut : les jambages d'IBM Plex
   Sans descendent à .224em sous la ligne de base (mesuré, pas estimé). En
   dessous de ça, le filet coupe les p, les y et les g du slogan. On le passe
   franchement dessous, et `skip-ink:none` le garde continu plutôt que troué. */
/* Épaisseur en `em` et non en px, pour la même raison que la chasse : le titre
   est un clamp(), il descend de 56 px à 33,6 px en mobile. Avec 3 px fixes, le
   filet gardait sa taille pendant que le texte rétrécissait, et la marge avec
   la ligne suivante tombait de 4,2 px à 0,9 px : le souligné semblait coller au
   mot du dessous sur téléphone. En `em`, le rapport reste constant à toutes les
   tailles. .054em fait 3 px à 56 px, la valeur d'origine. */
.hl-line{color:var(--ink);text-decoration:underline;text-decoration-color:var(--color-primary);
  text-decoration-thickness:.054em;text-underline-offset:.26em;text-decoration-skip-ink:none}
/* Sur l'off-white, le jaune pur perd en présence : on le fonce d'un cran.
   La teinte reste celle de la marque, seule la luminosité bouge. */
:root[data-theme="light"] .hl-line{text-decoration-color:var(--primary-ink)}

/* ===========================================================================
   Logo : REPRIS À L'IDENTIQUE de app.css `.side-logo .hl`.
   NE PAS MODIFIER (demande explicite de Jonathan). Si le logo change dans
   app.css, répercuter ici.
   =========================================================================== */
.site-logo{display:inline-flex;align-items:center}
.site-logo .hl{
  display:inline-block;background:var(--bru-yellow,#FFD60A);color:var(--bru-ink,#111);
  font-family:'Archivo Black','IBM Plex Sans',system-ui,sans-serif;font-weight:800;
  font-size:18px;letter-spacing:.4px;text-transform:uppercase;padding:4px .4em;
  border:3px solid var(--bru-ink,#111);box-shadow:3px 3px 0 0 var(--bru-ink,#111);
  transform:rotate(-2deg);
}
/* Le pavé se remplissait de jaune à chaque chargement, et rejouait au survol.
   Le logo est la première chose que l'œil voit : le voir se construire annonce
   une page qui va bouger toute seule. Il est désormais posé, dessiné, fini,
   dès la première image. L'apparence statique n'a pas changé d'un pixel.
   Reste le seul mouvement qui répond à un geste : le décalage au survol. */
.site-logo .hl{transition:transform var(--transition-base)}
@media(hover:hover){
  .site-logo:hover .hl{transform:rotate(-2deg) translate(-1px,-1px)}
}

/* ── Le logo posé DANS le titre (.brand-mark) ───────────────────────────────
   Le H1 disait « Reprease décrypte vos bilans » avec un souligné jaune sous
   les trois derniers mots. Le souligné est un bon procédé quand il n'y a rien
   d'autre à mettre ; ici il y avait le nom de la marque, et une marque dont
   le logo EST un pavé de texte n'a aucune raison d'écrire son nom deux fois de
   deux façons différentes. On remplace donc le mot par l'objet.

   LE LOGO N'EST PAS MODIFIÉ. Cette règle est la même que `.site-logo .hl`,
   valeur pour valeur, à ceci près que tout ce qui y était écrit en pixels pour
   une taille de 18 px est ici exprimé en `em`, donc en proportion :
       bordure   3 px / 18 px = .1667em
       ombre     3 px / 18 px = .1667em
       marge int 4 px / 18 px = .2222em   (l'horizontale était déjà en .4em)
       chasse   0,4 px / 18 px = .0222em
   Posée à `font-size:18px`, cette règle rend un pavé identique au pixel près
   à celui de la barre de navigation. La seule chose qui change est qu'il sait
   maintenant suivre un titre qui va de 33,6 px à 56 px.

   POURQUOI .48em ET PAS 1em. Le pavé n'est pas un mot, c'est un objet : ce qui
   doit s'accorder, ce n'est pas sa taille de police mais sa HAUTEUR DE BOÎTE.
   Bordures et marges internes comprises, le pavé mesure deux fois sa taille de
   police. Posé à 1em dans un titre, il ferait le double de la hauteur de ligne
   et démolirait le paragraphe. À .48em il fait 54 px de haut dans un titre de
   56 px, soit exactement la bande du texte qui l'entoure.

   POURQUOI IL EST REMONTÉ DE .36em. Aligné sur la ligne de base, un pavé pend
   sous elle de toute sa marge interne, de sa bordure et de son ombre : 14,5 px
   dans un titre de 56 px, là où les jambages n'en occupent que 12. Il posait
   donc son ombre sur le mot de la ligne suivante. Remonté de .36em (de sa
   propre taille, soit 9,7 px du titre), sa bordure HAUTE tombe pile sur la
   hauteur de capitale du texte voisin (écart mesuré : 0,0 px) et sa bordure
   basse deux pixels et demi sous la ligne des jambages. C'est la position
   exacte d'un tampon posé dans une ligne de texte.

   POURQUOI L'INTERLIGNE PASSE À 1,26. Un objet qui penche de 2 degrés ajoute
   « largeur x sin(2°) » à sa hauteur, et l'ombre dure ajoute encore .1667em.
   Le tout ne rentre pas dans un interligne de 1,12. Réglage vérifié sur les
   CINQ slogans du site (accueil et les quatre landings), à six largeurs de
   colonne entre 288 et 560 px, en cherchant à chaque fois le mot voisin le
   plus proche : la marge la plus faible de tout l'ensemble est de 5,8 px, sur
   « bilans. » à 38 px de corps. Aucun débordement horizontal.
   Les H1 qui ne portent pas de pavé gardent 1,12.

   Le repli `IBM Plex Sans` est intentionnel et repris de `.site-logo` : si
   Archivo Black n'arrive pas, le pavé reste un pavé, il change juste de dessin
   au lieu de disparaître. */
.brand-mark{
  display:inline-block;line-height:1;
  font-size:.48em;vertical-align:.36em;
  background:var(--bru-yellow,#FFD60A);color:var(--bru-ink,#111);
  font-family:'Archivo Black','IBM Plex Sans',system-ui,sans-serif;font-weight:800;
  letter-spacing:.0222em;text-transform:uppercase;
  padding:.2222em .4em;
  border:.1667em solid var(--bru-ink,#111);
  box-shadow:.1667em .1667em 0 0 var(--bru-ink,#111);
  transform:rotate(-2deg);
}
h1:has(.brand-mark){line-height:1.26}
/* Le pavé est déjà l'accent du titre. Le souligné jaune par-dessus ferait deux
   marques de couleur dans la même phrase, chacune affaiblissant l'autre. */
h1:has(.brand-mark) .hl-line{text-decoration:none}

/* ===========================================================================
   Boutons : mêmes classes que app.css (.btn / .btn.primary / .btn.ghost)
   =========================================================================== */
/* Graisse 500 et non 600 : Linear compose ses boutons en 510, Stripe en 300.
   Un libellé de bouton en semi-gras, c'est le réglage par défaut des gabarits.
   La chasse est très légèrement resserrée, comme le reste de l'interface.
   Le filet est une ombre interne, donc le bouton ne change pas de taille entre
   ses états et rien ne bouge autour au survol. */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:8px;
  font-size:14px;font-weight:var(--font-medium);letter-spacing:-.006em;
  border-radius:var(--radius);padding:12px 18px;
  background:var(--fill-subtle);color:var(--text-primary);
  box-shadow:var(--ring-strong);
  transition:background var(--transition-fast),box-shadow var(--transition-fast),
             transform var(--transition-fast);
  white-space:nowrap;
}
.btn:hover{background:var(--fill-hover)}
.btn:active{transform:translateY(1px)}
/* Le liseré clair sur l'arête haute d'un bouton plein est le détail qui coûte
   une ligne et se lit comme de la finition : la lumière vient d'en haut, donc
   le haut de l'objet est plus clair. Les deux références le font sur leurs
   boutons pleins. Il faut le doser bas, sinon on retombe sur le bouton en
   plastique brillant des années 2010. */
.btn.primary{background:var(--primary);color:var(--on-primary);
  box-shadow:inset 0 1px 0 var(--edge-light),inset 0 0 0 1px var(--edge-dark),var(--elev-1)}
.btn.primary:hover{background:var(--primary-hover)}
.btn.ghost{background:var(--surface);color:var(--text-secondary);box-shadow:var(--ring)}
.btn.ghost:hover{background:var(--surface-sunken);color:var(--ink);box-shadow:var(--ring-strong)}
.btn.lg{padding:15px 26px;font-size:15px}
.btn.sm{padding:8px 14px;font-size:13px}
.btn.block{width:100%}
.btn svg{width:17px;height:17px;flex-shrink:0}
/* padding vertical pour la cible tactile : ces liens sont autonomes, en bas de
   section, et non insérés dans une phrase. 21 px de haut, c'était trop peu. */
.link-arrow{display:inline-flex;align-items:center;gap:6px;padding:11px 0;
  font-size:14px;font-weight:600;
  color:var(--text-link);text-decoration:underline;text-underline-offset:3px;
  text-decoration-color:var(--line-2);transition:text-decoration-color var(--transition-fast)}
.link-arrow:hover{text-decoration-color:currentColor}

/* ===========================================================================
   Barre de navigation
   =========================================================================== */
/* Fond plein et non translucide-flouté : le verre dépoli est un effet de mode
   qui fait bouger le contenu de la barre à chaque défilement (le texte du
   dessous transparaît et se déplace). Un aplat de la couleur de page, un filet
   qui apparaît une fois la page défilée, et la barre se fait oublier. */
.nav{position:sticky;top:0;z-index:60;background:var(--bg);
  border-bottom:1px solid transparent;transition:border-color var(--transition-base)}
.nav.scrolled{border-bottom-color:var(--line)}
.nav-inner{max-width:var(--wrap);margin:0 auto;padding:14px 24px;display:flex;align-items:center;gap:22px}
.nav-links{display:flex;align-items:center;gap:2px;margin-left:14px}
/* nowrap obligatoire : un intitulé de nav qui se casse sur deux lignes fait
   immédiatement bâclé, et c'est la première chose que le visiteur voit. */
.nav-links a{font-size:14px;font-weight:500;color:var(--text-secondary);padding:8px 11px;
  white-space:nowrap;border-radius:var(--radius-sm);
  transition:background var(--transition-fast),color var(--transition-fast)}
.nav-links a:hover{background:var(--fill-subtle);color:var(--ink)}
.nav-links a[aria-current="page"]{color:var(--ink);font-weight:600;background:var(--fill-subtle)}
.nav-actions{display:flex;align-items:center;gap:10px;margin-left:auto}
.nav-burger{display:none;width:40px;height:40px;border-radius:var(--radius-sm);border:1px solid var(--line);
  align-items:center;justify-content:center;color:var(--ink)}
.nav-burger svg{width:20px;height:20px}

/* Bascule de thème */
.theme-toggle{width:38px;height:38px;border-radius:var(--radius-sm);border:1px solid var(--line);
  display:inline-flex;align-items:center;justify-content:center;color:var(--muted);
  transition:color var(--transition-fast),border-color var(--transition-fast)}
.theme-toggle:hover{color:var(--ink);border-color:var(--line-2)}
.theme-toggle svg{width:17px;height:17px}
.ic-sun,.lbl-light{display:none}
:root[data-theme="light"] .ic-sun{display:block}
:root[data-theme="light"] .ic-moon{display:none}
:root[data-theme="light"] .lbl-light{display:inline}
:root[data-theme="light"] .lbl-dark{display:none}

/* Libellé de CTA long en desktop, court en mobile : c'est la seule façon de
   garder logo + thème + CTA + burger sur une ligne de 360px. Sans ça la barre
   dépasse la largeur de l'écran et, `overflow-x` aidant, c'est TOUTE la page
   qui se retrouve rognée à droite. */
.only-narrow{display:none}
/* Doit rester AVANT la media query : les media queries n'ajoutent aucune
   spécificité, seul l'ordre du fichier départage. */
.nav-links .only-drawer{display:none}

/* 1120px et non 940 : avec cinq entrees, le logo et deux boutons, la barre
   demande environ 1110px. En dessous, on passe au tiroir plutot que de
   laisser les intitules se casser sur deux lignes. */
@media(max-width:1120px){
  .nav-burger{display:inline-flex}
  .nav-links{position:fixed;inset:64px 0 auto 0;flex-direction:column;align-items:stretch;gap:2px;
    background:var(--surface);border-bottom:1px solid var(--line);box-shadow:var(--shadow-md);
    padding:14px 18px 20px;margin:0;display:none}
  /* Le tiroir apparaissait d'un coup, sans lien avec le bouton qui l'ouvre.
     Il descend maintenant de la barre de navigation, d'où il sort réellement :
     six pixels et un fondu suffisent à rendre le geste lisible. Une seule fois,
     au clic. `transform-origin` en haut pour que le mouvement parte du bord
     collé à la barre, pas du centre du panneau. */
  .nav-links.open{display:flex}
  @media(prefers-reduced-motion:no-preference){
    .nav-links.open{transform-origin:top center;
      animation:rpDrawer .19s cubic-bezier(.16,1,.3,1) both}
  }
  @keyframes rpDrawer{from{opacity:0;transform:translateY(-6px)}to{opacity:1;transform:none}}
  .nav-links a{padding:12px 14px;font-size:15px}
  .nav-links .only-drawer{display:flex;align-items:center;gap:10px;width:100%;text-align:left;
    margin-top:6px;padding:12px 14px;font-size:15px;font-weight:600;color:var(--ink)}
  .nav-links a.only-drawer{margin-top:6px;padding-top:14px;border-top:1px solid var(--line)}
  .nav-links .drawer-theme svg{width:17px;height:17px;color:var(--muted)}
  .nav-actions .btn:not(.primary){display:none}
}

@media(max-width:640px){
  /* Les CTA de contenu passent en pleine largeur : cible tactile confortable,
     et surtout un libellé long ne peut plus depasser l'ecran (les .btn sont en
     white-space:nowrap par defaut). */
  .hero-cta,.cta-band .btns{flex-direction:column;align-items:stretch}
  .hero-cta .btn,.cta-band .btns .btn{width:100%;white-space:normal;text-align:center}
  .btn.lg{padding:13px 18px;font-size:15px}

  .nav-inner{padding:12px 16px;gap:10px}
  .nav-actions{gap:8px}

  /* ── Un seul jaune plein à l'écran ────────────────────────────────────────
     Jonathan, en regardant son téléphone : « avec tous les trucs en jaune on a
     l'impression que tout est important ». Il a raison, et c'est arithmétique.
     Dans le premier écran il y avait QUATRE objets jaunes : le logo, le bouton
     « Analyse offerte » de la barre, le pavé REPREASE du titre, et le bouton
     « Obtenir le score de ma cible ». Deux d'entre eux sont des boutons pleins
     qui disent la même chose et sont séparés de trois cents pixels. Quand tout
     crie, plus rien ne se distingue : c'est le contraire d'une hiérarchie.

     Tant qu'on est en HAUT de la page, le hero porte déjà son grand bouton
     jaune : celui de la barre n'a rien à y ajouter et passe en contour. Dès
     que la page défile, le hero et son bouton disparaissent, et celui de la
     barre redevient plein parce qu'il devient le seul.

     La classe `.scrolled` existait déjà (elle pose le filet sous la barre au
     premier pixel de défilement), donc pas une ligne de JavaScript en plus.
     Sans JavaScript du tout, `.scrolled` n'est jamais posée et le bouton reste
     en contour : il est toujours là, toujours lisible, simplement plus calme.
     C'est la bonne dégradation.

     Ce n'est pas une animation d'ambiance : c'est une réponse au geste du
     visiteur, la même catégorie que la barre d'offre. */
  .nav:not(.scrolled) .nav-actions .btn.primary{
    background:transparent;color:var(--ink);
    box-shadow:var(--ring-strong);
  }
  .nav:not(.scrolled) .nav-actions .btn.primary:hover{background:var(--fill-subtle)}
  .site-logo .hl{font-size:15px;border-width:2.5px;box-shadow:2.5px 2.5px 0 0 var(--bru-ink,#111)}
  /* Le sélecteur de thème quitte la barre : à 320px, logo + thème + CTA +
     burger ne tiennent plus sur une ligne. Il reste accessible dans le tiroir. */
  .nav-actions .theme-toggle{display:none}
  /* 44x44 et non 34x34. Le burger est la SEULE porte vers la navigation en
     mobile, et c'était la plus petite cible de la page : sous le seuil iOS (44)
     comme sous le seuil Android (48). Mesuré à 375 px, la barre tient large :
     logo 108 + CTA 126 + burger 44 + gouttières 48 = 326 px. */
  .nav-burger{width:44px;height:44px}
  .nav-actions .btn.primary{padding:12px 13px;font-size:13px}
  .only-wide{display:none}
  .only-narrow{display:inline}
  .nav-links{inset:58px 0 auto 0}
}

/* ===========================================================================
   Hero
   =========================================================================== */
/* Le hero portait trois couches de décor superposées : une lueur radiale jaune,
   une « aurore » de quatre disques colorés qui dérivaient en boucle sur un
   canevas flouté, et une inclinaison 3D de la maquette qui suivait la souris.
   Rien de tout ça ne dit ce que fait le produit, et l'ensemble se reconnaît
   au premier coup d'œil. Ce qui vend ici, c'est la maquette de rapport : elle
   se tient seule sur un fond de page uni.
   `overflow:hidden` reste utile, il retient les marges négatives du contenu. */
.hero{position:relative;padding:76px 0 64px;overflow:hidden}

/* ── Un dégradé, et un seul, réintroduit sciemment ──────────────────────────
   Attention, c'est un retour en arrière partiel : il faut savoir pourquoi.
   Ce qu'on avait retiré, c'était une lueur JAUNE, c'est-à-dire une tache de
   couleur de marque derrière le titre. Ce qu'on remet ici n'a pas de teinte du
   tout : c'est du blanc à 4,5 %, une variation de lumière et non de couleur.
   Relevé chez Linear, qui en pose plusieurs de ce type :
     radial-gradient(50% 50%, rgba(255,255,255,0.04), rgba(255,255,255,0) 90%)
   Personne ne le voit comme un dégradé ; ce qu'on perçoit, c'est que le haut de
   la page a de la profondeur et que le titre est éclairé. C'est exactement ce
   qui manque à une page entièrement plate.
   Test simple s'il faut trancher plus tard : si en le supprimant on voit
   disparaître une COULEUR, il est de trop. Si on voit la page s'aplatir, il
   fait son travail. */
.hero::before{
  content:"";position:absolute;inset:-35% -20% auto -20%;height:130%;
  pointer-events:none;z-index:0;
  background:radial-gradient(ellipse 52% 46% at 50% 30%,rgba(255,255,255,.045),rgba(255,255,255,0) 70%);
}
:root[data-theme="light"] .hero::before{
  background:radial-gradient(ellipse 52% 46% at 50% 30%,rgba(255,255,255,.92),rgba(255,255,255,0) 70%);
}

.hero>*{position:relative;z-index:1}
.hero-grid{display:grid;grid-template-columns:minmax(0,1.05fr) minmax(0,1fr);gap:56px;align-items:center}
.hero h1{margin-bottom:20px}
.hero .lead{margin-bottom:28px}
/* Si les deux boutons passent à la ligne, ils s'alignent sur la même largeur :
   deux blocs de tailles différentes empilés font un escalier. */
.hero-cta{display:flex;flex-wrap:wrap;gap:12px;align-items:stretch}
.hero-cta .btn{flex:0 1 auto}
@supports(selector(:has(*))){
  .hero-cta:has(.btn:nth-child(2)) .btn{min-width:min(100%,15rem)}
}
/* Grille 2x2 plutôt que flex-wrap : à quatre items, le flux laissait une ligne
   3+1 orpheline. Une colonne sous 560px. */
.hero-trust{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:9px 22px;
  margin-top:24px;font-size:13px;color:var(--muted);max-width:38rem}
.hero-trust li{display:inline-flex;align-items:center;gap:7px}
@media(max-width:560px){ .hero-trust{grid-template-columns:minmax(0,1fr)} }
.hero-trust svg{width:14px;height:14px;color:var(--ok);flex-shrink:0}
@media(max-width:980px){
  /* `minmax(0,1fr)` et NON `1fr`. C'est la correction du 2026-07-28, et c'est
     le piège le plus classique de CSS Grid : `1fr` est un raccourci pour
     `minmax(auto,1fr)`, donc la piste refuse de descendre sous la largeur
     min-content de son contenu. Or la maquette contient `.mock-bar`, dont le
     libellé et l'URL sont tous deux en `white-space:nowrap` : min-content
     mesuré à 436 px. Sur un écran de 390 px, la colonne du hero faisait donc
     436 px au lieu de 354, et TOUT le hero sortait de l'écran par la droite,
     titre, chapô, boutons compris. `overflow-x:hidden` sur le <body> coupait
     le débordement au lieu de le montrer : le texte était tronqué en silence.
     Avec `minmax(0,1fr)` la piste peut passer sous le min-content ; la
     maquette rentre alors dans la colonne et son URL s'abrège toute seule,
     comme son `text-overflow:ellipsis` le prévoit. */
  .hero-grid{grid-template-columns:minmax(0,1fr);gap:40px}
  .hero{padding:52px 0 44px}
}

/* ── La maquette déborde de la marge droite (2026-07-28) ────────────────────
   C'est le geste qui fait basculer un hero de « bien rangé » à « composé »,
   et c'est le seul endroit de la page où on se le permet. Tant que la maquette
   reste dans la colonne, la page se lit comme une grille remplie ; dès qu'un
   objet traverse la marge, on comprend que quelqu'un a décidé de la mise en
   page. Linear et Stripe le font tous les deux sur leur visuel de hero.

   La marge négative vaut la distance exacte entre le bord de la colonne utile
   et le bord de la fenêtre : `(100vw - --wrap) / 2` pour la marge extérieure,
   plus les 24 px de gouttière du `.wrap`. La maquette arrive donc pile au
   bord de la vitre. Le `100vw` inclut la barre de défilement dans la plupart
   des navigateurs, ce qui la fait dépasser d'une poignée de pixels : c'est
   tant mieux, un objet coupé net se lit mieux qu'un objet posé au ras.
   `overflow:hidden` sur `.hero` fait la coupe.

   SEULEMENT AU-DESSUS DE 1320 px. En dessous, le débord vaudrait moins de
   100 px : ça ne se lit plus comme un parti pris mais comme un alignement
   raté. À 1320 px il vaut 104 px, à 1440 px 164 px.

   La maquette passe DEVANT le filet de colonne (elle est en `z-index:1`, le
   filet en 0). Un objet posé sur une feuille réglée cache le trait : c'est
   exactement ce qu'on veut voir.

   Et elle perd ses équerres de coupe du côté droit. Ce n'est pas un oubli :
   en imprimerie, un objet qui part à fond perdu n'a pas de trait de coupe du
   côté où il déborde, puisqu'il n'y est justement pas coupé. */
@media(min-width:1320px){
  .mock-stage{margin-right:calc(-1 * ((100vw - var(--wrap)) / 2 + 24px))}
}

/* La ligne d'annonce au-dessus du H1 était une pilule contenant une seconde
   pilule jaune (« Nouveau »). C'est le cliché numéro un de la page d'accueil
   générée, et il coûte cher : deux bords arrondis, deux fonds et une capitale
   criarde avant même d'avoir lu le titre. La même phrase passe maintenant par
   le surtitre éditorial du site (.eyebrow), avec le filet qui sert partout
   ailleurs. Un seul niveau de lecture, aucun aplat.
   Le variant .offer met en évidence le mot qui porte l'offre, sans capsule. */
/* Ce surtitre-ci porte une phrase et non deux mots : il lui faut le droit de
   passer à la ligne, et une largeur maximale, sinon la capitale s'étire sur
   toute la colonne du hero et devient pénible à lire. */
/* Le filet de 22 px en tête ne marchait pas ici, et Jonathan avait raison de le
   trouver vilain. Il fonctionne sur une étiquette de deux mots, où il sert de
   tiret d'ouverture. Sur une phrase, avec `flex-wrap` et un alignement sur la
   ligne de base, il se retrouve suspendu à gauche d'un bloc qui peut passer à
   la ligne : un tiret orphelin qui ne pointe vers rien.
   Le trait n'est pas supprimé, il est déplacé là où il a un rôle : ENTRE le mot
   qui porte l'offre et la phrase qui la précise. Il devient une séparation, ce
   qu'un filet sait faire, au lieu d'une décoration d'ouverture. Vertical et non
   horizontal, parce qu'il sépare deux blocs côte à côte. */
.eyebrow.offer{color:var(--text-secondary);flex-wrap:wrap;max-width:52ch;
  align-items:center;line-height:1.5;gap:0}
.eyebrow.offer::before{display:none}
.eyebrow.offer b{
  color:var(--ink);font-weight:600;
  padding-right:11px;margin-right:11px;
  border-right:1px solid var(--line-2);
}
:root[data-theme="light"] .eyebrow.offer b{color:var(--color-black)}

/* ===========================================================================
   Maquette produit (aperçu du rapport) : pur CSS/SVG, aucune image
   =========================================================================== */
/* La maquette est LE visuel qui vend : c'est le seul objet de la page qui a le
   droit de se détacher du fond. Filet net plus ombre large et basse (le réglage
   Stripe : beaucoup de flou, étalement négatif, teinte plutôt que noir pur).
   L'ombre porte vers le bas, comme une lumière qui vient d'en haut ; c'est
   cette cohérence-là qui fait qu'un objet a l'air posé et pas collé. */
/* ===========================================================================
   L'ANNOTATION (2026-07-29)
   ===========================================================================
   Le geste du métier : on imprime la liasse, on entoure au stylo le chiffre
   qui décide, on écrit la question à côté. Jonathan l'a fait lui-même sans y
   penser, en annotant en rouge la capture d'écran qu'il m'a envoyée pour
   signaler un bug. C'est de là que vient l'idée.

   UNE SEULE FOIS SUR TOUT LE SITE. Répété, le procédé devient un tic et
   s'annule. Il est donc réservé au score de la maquette du hero de l'accueil,
   c'est-à-dire au seul chiffre de la page dont tout le reste dépend.

   LE ROUGE EST UNE ENCRE, PAS UN ÉTAT. C'est la précaution qui compte : la
   charte a déjà un rouge d'alerte (`--bad`), et un cercle rouge autour d'un
   score pourrait se lire « mauvaise note ». Deux garde-fous. D'abord `--pen`
   est un jeton distinct, jamais employé pour un état, jamais posé sur autre
   chose qu'un tracé à main levée. Ensuite la note qui accompagne le cercle dit
   explicitement que 78 est bon : sans elle, le cercle serait ambigu, et c'est
   la note qui porte le sens, pas la couleur.

   Le tracé est un vrai dessin, pas une police manuscrite : une ellipse
   irrégulière qui dépasse son point de départ, comme un stylo qui ne se relève
   pas au bon endroit. Une police « écriture » aurait fait bon marché. */
:root{ --pen:#F0554E }
:root[data-theme="light"]{ --pen:#C4211B }
.annot{position:relative}
/* DIMENSIONS EXPLICITES, et surtout pas `inset` avec `width:auto`.
   Un SVG est un élément REMPLACÉ : pour lui, `width:auto` ne se déduit pas des
   décalages gauche et droite comme sur une div, elle vaut sa taille
   intrinsèque, et le navigateur laisse alors tomber le décalage de droite.
   Le tracé faisait donc exactement la largeur du mot au lieu de l'englober, ce
   qui ne se voit pas sur une capture mais se mesure : 84 px de cercle autour
   d'un mot de 84 px. On calcule la boîte à la main. */
.annot .trace{
  position:absolute;left:-14px;top:-12px;
  width:calc(100% + 28px);height:calc(100% + 24px);
  /* La remise à zéro pose `max-width:100%` sur TOUS les svg, ce qui est bon
     pour une illustration mais plafonnait ici le tracé à la largeur exacte de
     ce qu'il doit entourer : le cercle ne débordait que d'un côté. */
  max-width:none;
  pointer-events:none;overflow:visible;color:var(--pen);z-index:2;
}
.annot .trace path{
  fill:none;stroke:currentColor;stroke-width:2.2;
  stroke-linecap:round;stroke-linejoin:round;opacity:.92;
}
/* La note vit SOUS la maquette et non à côté : à droite elle sortirait de
   l'écran dès que la maquette part à fond perdu. */
.annot-note{
  display:flex;align-items:flex-start;gap:9px;margin-top:15px;max-width:36ch;
  color:var(--pen);font-size:14px;font-weight:600;line-height:1.4;
}
.annot-note svg{width:26px;height:22px;flex:0 0 auto;margin-top:-1px}
.annot-note svg path{fill:none;stroke:currentColor;stroke-width:1.9;stroke-linecap:round;stroke-linejoin:round}
/* Variante sans flèche, sous un bloc centré (la grille tarifaire). */
.annot-note.centre{justify-content:center;text-align:center;margin-left:auto;margin-right:auto;margin-top:20px}

/* Cercle serré, pour un mot court. Le débordement par défaut (12 px en haut,
   14 px sur les côtés) est calibré sur un bloc de la taille du score ; autour
   d'un libellé de onze pixels de haut, il dessinait une ellipse deux fois et
   demie trop grande. */
.annot.annot-serre .trace{left:-11px;top:-7px;width:calc(100% + 22px);height:calc(100% + 14px)}

/* Le souligné à main levée. Il se pose SOUS la ligne de base, en dehors du
   flux (`position:absolute`), donc il n'ajoute pas un pixel de hauteur à la
   ligne et ne peut pas décaler la liste de la carte du milieu. */
.souligne{position:relative;white-space:nowrap;font-weight:600;color:var(--ink)}
/* Largeur calculée et non `left` + `right` : même piège d'élément remplacé que
   pour le cercle, le trait reprenait sa taille intrinsèque. */
.souligne .trait{
  position:absolute;left:-3px;top:100%;margin-top:1px;
  width:calc(100% + 8px);height:7px;max-width:none;
  color:var(--pen);overflow:visible;pointer-events:none;
}
/* `preserveAspectRatio="none"` étire la boîte 100x10 sur environ 55x7 : le
   trait s'amincit en même temps, d'où l'épaisseur relevée à 2,6. */
.souligne .trait path{fill:none;stroke:currentColor;stroke-width:2.6;stroke-linecap:round}
@media(max-width:560px){
  .annot-note{font-size:13px;max-width:none}
}

/* ── Repères de calage sur la maquette ──────────────────────────────────────
   Quatre équerres posées aux angles, à 8 px de l'objet. Ce sont les traits de
   coupe d'une épreuve d'imprimeur : ils ne décrivent pas la maquette, ils
   disent que c'est une PIÈCE, calée et vérifiée. Sur un produit qui vend une
   lecture rigoureuse, c'est le bon vocabulaire, et c'est un signe qu'aucun
   gabarit ne pose tout seul.

   Huit segments (deux bras par angle) peints en couches de fond sur un seul
   pseudo-élément : pas une balise de plus dans le document.
   Retirés sous 980 px : à cette taille la maquette occupe déjà toute la
   largeur utile, les équerres tomberaient dans la gouttière. */
.mock-stage{position:relative}
@media(min-width:980px){
  .mock-stage::before{
    content:"";position:absolute;inset:-8px;pointer-events:none;
    background-repeat:no-repeat;
    background-image:
      linear-gradient(var(--tick),var(--tick)),linear-gradient(var(--tick),var(--tick)),
      linear-gradient(var(--tick),var(--tick)),linear-gradient(var(--tick),var(--tick)),
      linear-gradient(var(--tick),var(--tick)),linear-gradient(var(--tick),var(--tick)),
      linear-gradient(var(--tick),var(--tick)),linear-gradient(var(--tick),var(--tick));
    background-size:12px 1px,1px 12px, 12px 1px,1px 12px, 12px 1px,1px 12px, 12px 1px,1px 12px;
    background-position:
      left top,left top,           /* équerre haut gauche  */
      right top,right top,         /* équerre haut droite  */
      left bottom,left bottom,     /* équerre bas gauche   */
      right bottom,right bottom;   /* équerre bas droite   */
  }
}
/* Au-delà de 1320 px la maquette part à fond perdu vers la droite (voir le
   bloc « La maquette déborde de la marge droite »). Les deux équerres de
   droite sautent : en imprimerie, un objet qui déborde n'a pas de trait de
   coupe du côté où il déborde, puisqu'il n'y est pas coupé.
   Cette règle DOIT rester après celle du dessus. Placée plus haut dans le
   fichier, à égalité de spécificité, c'est la règle à huit équerres qui
   l'emportait par ordre d'écriture, et les équerres de droite restaient
   suspendues hors de l'écran. */
@media(min-width:1320px){
  .mock-stage::before{
    background-image:
      linear-gradient(var(--tick),var(--tick)),linear-gradient(var(--tick),var(--tick)),
      linear-gradient(var(--tick),var(--tick)),linear-gradient(var(--tick),var(--tick));
    background-size:12px 1px,1px 12px,12px 1px,1px 12px;
    background-position:left top,left top,left bottom,left bottom;
  }
}

/* L'arête haute reçoit un liseré clair, comme le bouton plein : la lumière de
   la page vient d'en haut, donc le haut d'un objet posé est plus clair que son
   corps et son ombre part vers le bas. Un rectangle qui a la même valeur sur
   ses quatre bords est un rectangle dessiné ; celui-là a une épaisseur. */
.mock{background:var(--surface);border-radius:var(--radius-lg);overflow:hidden;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.07),var(--ring-strong),var(--elev-2)}
:root[data-theme="light"] .mock{
  box-shadow:inset 0 1px 0 rgba(255,255,255,.9),var(--ring-strong),var(--elev-2)}
/* En-tête de document, plus une fausse fenêtre de navigateur : les trois pastilles
   rouge-orange-verte imitaient macOS sans rien apporter. On annonce ce qu'on
   regarde (un rapport) et d'où il vient (l'app). */
.mock-bar{display:flex;align-items:baseline;justify-content:space-between;gap:14px;
  padding:11px 14px;border-bottom:1px solid var(--line);background:var(--surface-sunken)}
.mock-bar .tag{font-family:var(--font-label);font-size:11px;font-weight:600;text-transform:uppercase;
  letter-spacing:.075em;color:var(--muted);white-space:nowrap}
/* Une URL reste en chasse fixe : c'est une adresse, pas une phrase, et la
   largeur constante des caractères est précisément ce qui la rend lisible. */
.mock-bar .url{font-family:var(--font-code);font-size:11px;color:var(--faint);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}
.mock-body{padding:20px;display:flex;flex-direction:column;gap:16px}
.mock-head{display:flex;align-items:flex-start;justify-content:space-between;gap:14px}
.mock-co{font-size:15px;font-weight:700}
/* Le SIREN garde la chasse fixe : c'est un identifiant lu dans la liasse. */
.mock-co span{display:block;font-family:var(--font-code);font-size:11px;color:var(--faint);font-weight:400;margin-top:3px}
.mock-score{display:flex;align-items:center;gap:11px;border:1px solid var(--line);border-radius:var(--radius);
  padding:8px 13px;background:var(--bg)}
.mock-score b{font-family:var(--font-num);font-size:22px;font-weight:600;line-height:1;color:var(--primary);
  letter-spacing:-.02em;font-variant-numeric:tabular-nums}
/* Idem : le jaune de marque ne tient pas la lecture sur fond clair. */
:root[data-theme="light"] .mock-score b{color:var(--ink)}
.mock-score b small{font-size:12px;color:var(--faint)}
.mock-score span{font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.5px;color:var(--muted)}
.mock-kpis{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px}
.mock-kpi{border:1px solid var(--line);border-radius:var(--radius);padding:12px;background:var(--bg)}
.mock-kpi .k{font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.5px;color:var(--muted)}
.mock-kpi .v{font-family:var(--font-num);font-size:19px;font-weight:600;margin-top:6px;
  letter-spacing:-.02em;font-variant-numeric:tabular-nums}
.mock-kpi .d{font-size:11px;font-weight:600;margin-top:2px}
.mock-kpi .d.up{color:var(--ok)} .mock-kpi .d.down{color:var(--bad-strong)}
.mock-kpi .d.neutral{color:var(--muted)}
.mock-verdict{display:flex;gap:11px;align-items:flex-start;border:1px solid var(--line);
  border-radius:var(--radius);padding:13px;background:var(--bg)}
.mock-verdict .dot{width:9px;height:9px;border-radius:50%;background:var(--ok);flex-shrink:0;margin-top:5px}
.mock-verdict .t{font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.5px;color:var(--muted)}
.mock-verdict .s{font-size:13px;font-weight:600;margin-top:3px;line-height:1.45}
.mock-chart{border:1px solid var(--line);border-radius:var(--radius);padding:14px;background:var(--bg)}
.mock-chart .lbl{display:flex;justify-content:space-between;align-items:center;margin-bottom:12px}
.mock-chart .lbl b{font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.5px;color:var(--muted)}
.mock-chart .lbl em{font-family:var(--font-num);font-style:normal;font-size:11px;color:var(--faint);
  font-variant-numeric:tabular-nums}
/* Un graphique sans axe est une illustration de graphique. Cinq barres posées
   dans le vide, avec la plage « 2021 → 2025 » écrite à côté en légende, ça
   ressemblait à une image d'habillage : on ne pouvait dire à quelle année
   correspondait quelle barre. Le filet de base et les millésimes sous les
   barres en font une lecture. C'est le même volume à l'écran, mais on y lit
   quelque chose, et c'est ça la différence entre du décor et du produit. */
.mock-bars{display:flex;align-items:flex-end;gap:9px;height:78px;
  border-bottom:1px solid var(--line-2)}
.mock-bars i{flex:1;border-radius:var(--radius-bar) var(--radius-bar) 0 0;background:var(--ch-teal);opacity:.55;display:block}
.mock-bars i:last-child{opacity:1;background:var(--primary)}
/* Mêmes `display:flex` et `gap` que la rangée de barres : c'est ce qui garantit
   que chaque millésime tombe sous sa barre sans avoir à caler quoi que ce soit. */
.mock-x{display:flex;gap:9px;margin-top:7px}
/* `min-width:0` : sans lui, un element de flex refuse de descendre sous la
   largeur de son contenu (`min-width:auto`). Les barres, qui sont vides, se
   partagent la place a egalite ; les millesimes, eux, se seraient arc-boutes
   sur leurs quatre chiffres et la rangee aurait deborde en tres petite
   largeur, decalant chaque annee par rapport a sa barre. */
/* 11 px et non 10 : c'est le plancher de l'echelle des petits corps, et un
   millesime d'axe se lit, il ne se devine pas. Verifie a 260 px de maquette,
   les cinq annees tiennent sans troncature. */
.mock-x span{flex:1;min-width:0;text-align:center;font-family:var(--font-num);font-size:11px;
  font-variant-numeric:tabular-nums;color:var(--faint);line-height:1}
.mock-x span:last-child{color:var(--text-secondary);font-weight:600}
@media(max-width:520px){ .mock-kpis{grid-template-columns:minmax(0,1fr) minmax(0,1fr)} .mock-kpis>:last-child{display:none} }

/* ── Visuel des landing pages : le scan et trois chiffres ── */
.lp-visual{background:var(--surface);border-radius:var(--radius-lg);
  box-shadow:var(--ring-strong),var(--elev-2);
  padding:30px 26px 24px;text-align:center}
.lp-visual-cap{font-size:13px;color:var(--muted);margin:18px auto 0;max-width:34ch;line-height:1.55}
.lp-figures{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px;margin-top:22px;
  padding-top:20px;border-top:1px solid var(--line)}
.lp-figures div{display:flex;flex-direction:column;gap:3px}
.lp-figures b{font-family:var(--font-num);font-size:24px;font-weight:600;letter-spacing:-.022em;
  color:var(--ink);font-variant-numeric:tabular-nums}
.lp-figures span{font-size:11px;color:var(--muted);line-height:1.35}

/* ===========================================================================
   Liste des postes lus (remplace l'ancien bandeau défilant)
   Le bandeau faisait glisser une trentaine de sigles en boucle, 34 secondes par
   tour, sans jamais qu'on puisse en lire un correctement. C'était de la
   décoration mobile là où il y avait une vraie information à donner : la liste
   de ce que Reprease sait extraire. Elle est maintenant posée, lisible, et se
   parcourt à la vitesse du visiteur.
   =========================================================================== */
/* Descendue le 2026-07-28 du haut de page vers « Le contenu d'une analyse ».
   Elle n'est donc plus une bande pleine largeur posée entre deux sections,
   mais le pied d'une section, DÉJÀ à l'intérieur d'un `.wrap` : plus de fond,
   plus de largeur maximale et plus de gouttière à reposer, sinon on obtient
   une colonne dans la colonne et un décalage de 24 px avec le reste. */
.readout{border-top:1px solid var(--line);margin-top:38px;padding-top:26px}
.readout-inner{}
/* Plus de capitales ici : « Postes lus et recalculés dans chaque liasse » fait
   43 caractères, et au-delà d'une vingtaine la capitale supprime la silhouette
   du mot et se lit lettre à lettre. Relevé par le détecteur (all-caps-body).
   La capitale reste sur les surtitres, qui sont des étiquettes de deux mots. */
/* 12 px : en perdant la capitale, cette ligne cesse d'être une étiquette et
   redevient du texte courant, avec le plancher de lisibilité qui va avec. */
.readout .t{font-family:var(--font-label);font-size:12px;font-weight:600;
  letter-spacing:0;color:var(--muted);margin-bottom:14px}
/* Nombre de colonnes choisi pour que les douze postes remplissent exactement
   leurs lignes (6x2, 4x3, 2x6). Un séparateur suspendu en bout de ligne
   incomplète, c'est le genre de détail qui fait bâclé sans qu'on sache dire
   pourquoi. Le filet haut de chaque cellule dessine une table réglée. */
.readout ul{display:grid;grid-template-columns:repeat(6,minmax(0,1fr));gap:0 22px}
/* Ces douze entrées sont la liste de ce que la machine sait extraire d'une
   liasse : c'est une sortie d'outil, et c'est l'un des trois endroits du site
   où la chasse fixe dit quelque chose au lieu de faire un effet. */
.readout li{font-family:var(--font-code);font-size:12px;letter-spacing:.5px;text-transform:uppercase;
  color:var(--text-secondary);padding:9px 0;border-top:1px solid var(--line);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
@media(max-width:980px){ .readout ul{grid-template-columns:repeat(4,minmax(0,1fr))} }
@media(max-width:760px){
  .readout{margin-top:30px;padding-top:22px}
  .readout ul{grid-template-columns:repeat(2,minmax(0,1fr));gap:0 18px}
  .readout li{font-size:11px;padding:8px 0}
}

/* ===========================================================================
   D'OÙ VIENNENT LES CIBLES (bande sous le hero, 2026-07-28)
   ===========================================================================
   Remplace la liste des douze postes lus, qui posait un mur de sigles (BFR,
   Gearing, DSCR) juste après un hero promettant « en français, sans jargon ».
   Voir le commentaire dans app/Views/home.php pour le raisonnement complet.

   Ce qu'il y a à la place répond à la question suivante du visiteur : le hero
   dit « le cédant vous envoie ses liasses, déposez-les », et celui qui n'en est
   pas encore là se demande d'où sortent ses cibles. C'est aussi le seul endroit
   du site où l'on dit que le produit s'insère dans un flux de travail réel, ce
   qui était complètement absent.

   Deux entrées séparées par un filet vertical, pas deux cartes : ce sont deux
   chemins vers la même chose, pas deux offres à comparer. Un filet dit ça
   mieux que deux boîtes.
   =========================================================================== */
.sources{border-top:1px solid var(--line);border-bottom:1px solid var(--line);
  background:var(--surface);padding:26px 0}
.sources-inner{max-width:var(--wrap);margin:0 auto;padding:0 24px}
.sources .t{font-family:var(--font-label);font-size:12px;font-weight:600;
  text-transform:uppercase;letter-spacing:.085em;color:var(--muted);margin-bottom:20px}
.sources-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:0 40px}
.sources-grid>div+div{border-left:1px solid var(--line);padding-left:40px}
/* Le titre de la bande est un `h2` composé comme une étiquette : c'est bien un
   titre pour l'ossature du document, mais pas un titre de section à l'écran.
   Les deux entrées sont ses `h3`, ramenés au corps d'un titre de carte. */
.sources h2.t{margin-top:0}
.sources-grid h3{font-size:16px;font-weight:600;letter-spacing:-.011em;
  line-height:1.35;margin-bottom:8px}
.sources-grid p{font-size:14px;color:var(--muted);line-height:1.65;max-width:54ch}
.sources-grid b{color:var(--ink);font-weight:600}
.sources-grid a{color:var(--text-secondary);text-decoration:underline;
  text-underline-offset:3px;text-decoration-color:var(--line-2)}
.sources-grid a:hover{color:var(--ink);text-decoration-color:var(--primary)}
.sources .note{font-size:13px;color:var(--faint);margin-top:9px}
@media(max-width:760px){
  .sources{padding:22px 0}
  .sources-inner{padding:0 18px}
  .sources-grid{grid-template-columns:minmax(0,1fr);gap:0}
  /* Empilées, les deux entrées ne peuvent plus être séparées par un trait
     vertical : il devient horizontal, sinon il flotte à gauche du vide. */
  .sources-grid>div+div{border-left:none;padding-left:0;
    border-top:1px solid var(--line);margin-top:20px;padding-top:20px}
}

/* ===========================================================================
   Cartes génériques
   =========================================================================== */
.grid{display:grid;gap:18px}
.grid-2{grid-template-columns:repeat(auto-fit,minmax(290px,1fr))}
.grid-3{grid-template-columns:repeat(auto-fit,minmax(272px,1fr))}
.grid-4{grid-template-columns:repeat(auto-fit,minmax(220px,1fr))}

/* Toujours pas de soulèvement au survol : six cartes qui décollent de deux
   pixels, c'est le tic de gabarit le plus répandu. Mais le filet passe en ombre
   interne, donc la carte n'occupe plus de place pour sa bordure et le survol
   peut épaissir le trait sans décaler d'un pixel ce qu'il y a dedans. */
.card{background:var(--surface);border-radius:var(--radius);
  box-shadow:var(--ring);
  padding:24px;display:flex;flex-direction:column;gap:10px;
  transition:background var(--transition-fast),box-shadow var(--transition-fast)}
.card.hover:hover{background:var(--surface-sunken);box-shadow:var(--ring-strong)}
.card h2,.card h3{font-size:16px;font-weight:600;letter-spacing:-.2px}
.card p{font-size:14px;color:var(--muted);line-height:1.6}
/* Pastilles d'icône : le fond teinté (jaune pâle, vert pâle, ambre pâle) posait
   une tache de couleur sur chaque carte et obligeait à corriger le contraste au
   cas par cas. On garde le cadre, qui tient l'alignement et sert de support aux
   chiffres d'étape, mais il est vide : c'est l'icône qui porte la couleur, en
   trait, à la même épaisseur partout. */
.card .ic{width:36px;height:36px;border-radius:var(--radius-sm);display:flex;align-items:center;
  justify-content:center;border:1px solid var(--line-2);color:var(--text-secondary);margin-bottom:6px}
.card .ic svg{width:18px;height:18px;stroke-width:1.8}
/* Un seul écart de couleur, réservé aux numéros d'étape : le filet passe en
   jaune, le chiffre reste en encre. Le jaune ne sert jamais de remplissage. */
.card .ic.accent{border-color:var(--color-primary);color:var(--ink)}
.card .ic.ok{color:var(--ok)}
.card .ic.bad{color:var(--bad-strong)}
.card .ic.warn{color:var(--warn)}

/* Carte « douleur » (section problème) */
.pain{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);padding:24px}
.pain q{display:block;font-size:16px;font-weight:600;line-height:1.5;quotes:"«\00a0" "\00a0»"}
.pain q::before{content:open-quote} .pain q::after{content:close-quote}
.pain .who{margin-top:12px;font-family:var(--font-label);font-size:11px;text-transform:uppercase;
  letter-spacing:.075em;font-weight:600;color:var(--faint)}
.pain .fix{margin-top:16px;padding-top:16px;border-top:1px solid var(--line);font-size:14px;
  color:var(--text-secondary);line-height:1.6;display:flex;gap:9px}
.pain .fix svg{width:15px;height:15px;color:var(--ok);flex-shrink:0;margin-top:4px}

/* ===========================================================================
   Extraits du livrable (remplace la grille de six cartes à icône)
   Le détecteur relevait dix « pastille d'icône 36x36 au-dessus d'un h3 » sur
   cette page, dont six ici. Le problème n'était pas la couleur de la pastille,
   c'était le patron : une icône décorative pour ILLUSTRER ce que le rapport
   contient, alors que le rapport est précisément ce qui se vend. On montre
   trois morceaux du livrable, la légende dit ce qu'on regarde.
   =========================================================================== */
.artefacts{display:grid;grid-template-columns:repeat(auto-fit,minmax(272px,1fr));gap:18px}
.artefact{display:flex;flex-direction:column;gap:0;margin:0}
/* Le fragment est traité comme un morceau d'interface découpé dans le rapport :
   fond de page (et non de surface) pour qu'il se lise comme un écran, filet
   complet, coins du haut arrondis, la légende venant se souder dessous. */
.artefact .art-body{background:var(--bg);border-radius:var(--radius) var(--radius) 0 0;
  box-shadow:var(--ring-strong);padding:20px;min-height:118px;
  display:flex;flex-direction:column;justify-content:center;gap:10px}
.artefact figcaption{background:var(--surface);border-radius:0 0 var(--radius) var(--radius);
  box-shadow:var(--ring);padding:18px 20px 20px}
.artefact h3{font-size:15px;margin-bottom:7px}
.artefact p{font-size:14px;color:var(--muted);line-height:1.6}

/* Extrait 1 : le score, repris de la maquette du hero pour que le visiteur
   reconnaisse l'objet qu'il a déjà vu en haut de page. */
.art-score{flex-direction:row;align-items:center;gap:13px}
.art-score b{font-family:var(--font-num);font-size:34px;font-weight:600;line-height:1;
  color:var(--primary);font-variant-numeric:tabular-nums;letter-spacing:-.024em}
:root[data-theme="light"] .art-score b{color:var(--ink)}
.art-score b small{font-size:15px;color:var(--faint);letter-spacing:0}
.art-score span{font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.5px;
  color:var(--muted);line-height:1.35}

/* Extrait 2 : les trois valorisations, en tableau parce que c'en est un. */
table.art-valo{width:100%;border-collapse:collapse;font-size:13px}
table.art-valo th{text-align:left;font-weight:500;color:var(--text-secondary);padding:5px 0}
table.art-valo td{text-align:right;font-family:var(--font-num);font-size:14px;font-weight:500;
  color:var(--ink);font-variant-numeric:tabular-nums;padding:5px 0}
table.art-valo tr+tr th,table.art-valo tr+tr td{border-top:1px solid var(--line)}

/* Extrait 3 : un point de vigilance, tel qu'il est écrit dans le rapport. */
.art-flag{font-family:var(--font-label);font-size:11px;font-weight:600;text-transform:uppercase;
  letter-spacing:.075em;color:var(--warn)}
.art-quote{font-size:14px;line-height:1.55;color:var(--ink)}

/* ===========================================================================
   Engagements de confidentialité (remplace quatre cartes à icône verte)
   Du texte de réassurance juridique se lit, il ne se survole pas : une vignette
   par engagement n'ajoutait rien. La liste de définition dit ce que c'est,
   un engagement et sa portée, et se réduit à un filet entre deux entrées.
   =========================================================================== */
.pledges{display:grid;grid-template-columns:repeat(auto-fit,minmax(320px,1fr));
  gap:0 44px;border-top:1px solid var(--line)}
.pledges>div{padding:20px 0;border-bottom:1px solid var(--line)}
.pledges dt{font-size:15px;font-weight:600;letter-spacing:-.011em;color:var(--ink);margin-bottom:7px}
.pledges dd{font-size:14px;color:var(--muted);line-height:1.65;max-width:56ch}

/* Variante numérotée, pour les listes d'étapes.
   Le numéro était mis dans une pastille carrée de 36 px, comme s'il s'agissait
   d'une icône. Un numéro n'est pas une icône : il se compose. Ici il est posé
   en gros chiffre mono dans la marge, sans cadre ni fond, façon numérotation de
   revue. Le compteur CSS le génère, donc plus aucun chiffre en dur dans le
   markup et plus de renumérotation manuelle quand une étape bouge. */
.pledges.numbered{counter-reset:pledge}
.pledges.numbered>div{counter-increment:pledge;display:grid;
  grid-template-columns:2.4rem minmax(0,1fr);gap:0 14px}
/* Placement EXPLICITE des trois occupants de la grille.
   Il y avait `grid-row:1/-1` sur le numero, pour lui faire occuper toute la
   hauteur. Ca ne marche pas : `-1` designe la derniere ligne de la grille
   EXPLICITE, or aucune ligne n'est declaree ici (seules les colonnes le sont).
   Le numero ne prenait donc que la premiere case, et le placement automatique
   rangeait le premier <dd> dans la colonne restee libre en dessous, soit celle
   du numero : le paragraphe se retrouvait comprime sur 2,4 rem de large.
   On assigne donc les colonnes a la main, ce qui ne depend d'aucune ligne. */
.pledges.numbered>div::before{
  content:counter(pledge,decimal-leading-zero);
  font-family:var(--font-num);font-size:15px;font-weight:600;letter-spacing:-.01em;
  color:var(--primary);line-height:1.5;font-variant-numeric:tabular-nums;
  grid-column:1;grid-row:1}
.pledges.numbered>div>dt,
.pledges.numbered>div>dd{grid-column:2}
/* Une entrée peut porter une note secondaire sous son texte principal :
   un second <dd>, plus petit et plus discret. */
.pledges dd.aside{font-size:13px;color:var(--faint);margin-top:7px}
/* Note d'avertissement sous une entrée : c'est le libellé qui porte la couleur,
   pas un fond ni une bordure, et jamais la couleur seule (le mot « L'erreur »
   dit la même chose que le rouge, pour qui ne le distingue pas). */
.pledges dd.risk{font-size:13px;color:var(--muted);margin-top:7px;line-height:1.6}
.pledges dd.risk b{color:var(--bad-strong);font-weight:600}
/* Sur l'off-white, le jaune pur ne tient pas la lecture d'un chiffre. */
:root[data-theme="light"] .pledges.numbered>div::before{color:var(--color-black)}
@media(max-width:560px){
  .pledges.numbered>div{grid-template-columns:2rem minmax(0,1fr);gap:0 10px}
}
/* Sur deux colonnes, les filets du bas de chaque paire se rejoignent ; sur une
   seule colonne le dernier filet doublerait celui du bas de section. */
@media(max-width:759px){ .pledges>div:last-child{border-bottom:none} }

/* Encadré d'information en tête de page : un fait à poser avant le reste, sans
   en faire une alerte. Pas de bordure gauche colorée (interdite), pas de fond
   teinté : le filet et le mot en encre suffisent, et le sens est porté par la
   phrase, pas par la couleur. */
.notice{background:var(--surface);box-shadow:var(--ring);border-radius:var(--radius);
  padding:16px 18px;margin-bottom:24px;max-width:64ch}
.notice p{font-size:14px;color:var(--muted);line-height:1.65}
.notice b{color:var(--ink);font-weight:600}

/* ===========================================================================
   LE DÉROULÉ (.flow) — 2026-07-28
   ===========================================================================
   Les cinq étapes de /fonctionnement étaient cinq paragraphes de six lignes
   posés les uns sous les autres. Rien de faux, mais rien où poser l'œil : on
   lisait un mode d'emploi, pas un produit. Jonathan : « moins lourd à
   digérer ».

   La réponse n'est pas d'illustrer avec des icônes. Une icône décorative au-
   dessus d'un titre, c'est le patron qu'on a retiré partout ailleurs sur ce
   site, et ça n'apprend rien : dessiner une loupe à côté de « Reprease lit »
   ne dit pas ce qui est lu. Chaque étape montre donc CE QU'ELLE PRODUIT, en
   fragment d'interface : les trois fichiers déposés, les postes extraits avec
   leurs montants, le chiffre corrigé à côté du chiffre lu, le score obtenu.
   Même principe que les artefacts de l'accueil, et pour la même raison : le
   livrable est ce qui se vend, il n'a pas besoin d'être illustré.

   Trois colonnes : le numéro, le texte, le fragment. Placement EXPLICITE des
   trois occupants, comme sur `.pledges.numbered` : sans ça le placement
   automatique range le fragment dans la colonne du numéro.
   =========================================================================== */
.flow{border-top:1px solid var(--line);counter-reset:flow}
.flow-step{counter-increment:flow;display:grid;
  grid-template-columns:2.6rem minmax(0,1fr) minmax(0,318px);
  gap:0 34px;padding:30px 0;border-bottom:1px solid var(--line);align-items:start}
.flow-step::before{content:counter(flow,decimal-leading-zero);
  font-family:var(--font-num);font-size:15px;font-weight:600;letter-spacing:-.01em;
  color:var(--primary);line-height:1.55;font-variant-numeric:tabular-nums;
  grid-column:1;grid-row:1}
:root[data-theme="light"] .flow-step::before{color:var(--color-black)}
.flow-txt{grid-column:2;grid-row:1}
.flow-art{grid-column:3;grid-row:1}
.flow-txt h3{font-size:17px;letter-spacing:-.014em;margin-bottom:8px}
.flow-txt p{font-size:14px;color:var(--muted);line-height:1.65;max-width:56ch}
.flow-txt p+p{margin-top:11px}
.flow-txt a{text-decoration:underline;text-underline-offset:3px;
  text-decoration-color:var(--line-2);color:var(--text-secondary)}
.flow-txt a:hover{color:var(--ink);text-decoration-color:var(--primary)}
/* Ce que l'étape a produit, en une ligne. C'est le fil qui fait qu'on suit une
   progression au lieu de lire cinq paragraphes indépendants. */
.flow-out{margin-top:15px;font-family:var(--font-label);font-size:11px;font-weight:600;
  text-transform:uppercase;letter-spacing:.075em;color:var(--faint)}
.flow-out b{color:var(--text-secondary);font-weight:600}

/* Le fragment d'interface. Fond de PAGE et non de surface, comme les artefacts
   de l'accueil : il doit se lire comme un morceau d'écran découpé, pas comme
   une carte de la vitrine. */
.flow-art{background:var(--bg);border-radius:var(--radius);box-shadow:var(--ring-strong);
  padding:15px 16px;display:flex;flex-direction:column;gap:9px;justify-content:center;
  min-height:112px}
.fa-head{font-size:13px;font-weight:700;line-height:1.3}
.fa-head span{display:block;font-family:var(--font-code);font-size:11px;
  font-weight:400;color:var(--faint);margin-top:3px}
.fa-row{display:flex;align-items:baseline;justify-content:space-between;gap:14px;font-size:12px}
.fa-row+.fa-row{border-top:1px solid var(--line);padding-top:8px}
.fa-k{color:var(--muted);min-width:0}
.fa-v{font-family:var(--font-num);font-size:13px;font-weight:600;color:var(--ink);
  font-variant-numeric:tabular-nums;letter-spacing:-.012em;white-space:nowrap}
/* Une valeur qui n'est pas un nombre : même rôle dans la ligne, mais elle n'a
   rien à aligner en colonne, donc ni chiffres tabulaires ni chasse resserrée. */
.fa-t{font-size:12px;font-weight:600;color:var(--text-secondary);white-space:nowrap}
.fa-v.fix{color:var(--ok)}
/* Un nom de fichier est une sortie machine : chasse fixe, et un rectangle de
   la proportion d'une page en guise de repère. Pas un émoji, pas une icône
   décorative : la forme d'un document. */
.fa-file{font-family:var(--font-code);font-size:11px;color:var(--text-secondary);
  display:flex;align-items:center;gap:9px}
/* Angle vif : un rayon de 1 px sur un rectangle de 9 px ne se voit pas et
   introduisait une quatrième valeur dans une échelle qui en compte trois
   (relevé par le détecteur, design-system-radius). L'angle vif est de toute
   façon la bonne réponse, c'est la silhouette d'une feuille. */
.fa-file::before{content:"";width:9px;height:12px;flex:0 0 auto;
  border:1px solid var(--line-2)}
.fa-note{font-size:11px;color:var(--faint);line-height:1.45}
.fa-score{display:flex;align-items:baseline;gap:8px}
/* 34 px et non 30 : au-dessus de 16 px chaque taille est un RÔLE documenté, pas
   un cran libre. 34 px est déjà celui du score et des chiffres-clés
   (`.art-score b`, `.stat b`). Inventer un 30 px ajoutait un rôle de plus pour
   rien, et le détecteur avait raison de le relever. */
.fa-score b{font-family:var(--font-num);font-size:34px;font-weight:600;line-height:1;
  letter-spacing:-.024em;font-variant-numeric:tabular-nums;color:var(--primary)}
:root[data-theme="light"] .fa-score b{color:var(--ink)}
.fa-score span{font-size:12px;color:var(--muted)}

@media(max-width:900px){
  /* Le fragment passe sous le texte, dans la même colonne : aligné sur lui, et
     jamais dans la gouttière du numéro. */
  .flow-step{grid-template-columns:2.6rem minmax(0,1fr);gap:0 16px}
  .flow-art{grid-column:2;grid-row:2;margin-top:16px}
}
@media(max-width:560px){
  .flow-step{grid-template-columns:2rem minmax(0,1fr);gap:0 10px;padding:26px 0}
}

/* ===========================================================================
   Étapes numérotées
   =========================================================================== */
.steps{display:grid;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));gap:0;
  border:1px solid var(--line);border-radius:var(--radius-lg);overflow:hidden;background:var(--surface)}
.step{padding:28px 26px;border-right:1px solid var(--line);display:flex;flex-direction:column;gap:10px}
.step:last-child{border-right:none}
.step .n{font-family:var(--font-num);font-size:12px;font-weight:600;color:var(--on-primary);
  background:var(--primary);width:26px;height:26px;border-radius:var(--radius-sm);
  display:flex;align-items:center;justify-content:center}
.step h3{font-size:16px}
.step p{font-size:14px;color:var(--muted);line-height:1.6}
.step .out{margin-top:auto;padding-top:14px;font-family:var(--font-label);font-size:11px;
  font-weight:600;text-transform:uppercase;letter-spacing:.075em;color:var(--faint)}
@media(max-width:820px){ .step{border-right:none;border-bottom:1px solid var(--line)} .step:last-child{border-bottom:none} }

/* ===========================================================================
   Tarifs : classes identiques à app.css (.price-grid / .price-card / .pc-*)
   =========================================================================== */
.price-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(272px,1fr));gap:18px;align-items:stretch}
.price-card{position:relative;display:flex;flex-direction:column;gap:11px;background:var(--surface);
  border-radius:var(--radius);box-shadow:var(--ring);padding:26px}
/* L'offre recommandée se signale par son filet jaune, et par la seule ombre de
   la grille : elle avance d'un plan, les deux autres restent à plat. Ni carte
   agrandie ni carte plus haute, la hiérarchie tient dans la profondeur. */
.price-card.pro{box-shadow:inset 0 0 0 1px var(--color-primary),var(--elev-2)}
.price-card .pc-head{display:flex;align-items:baseline;justify-content:space-between;gap:12px}
.price-card .pc-name{font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.5px;color:var(--muted)}
/* Le prix est le chiffre le plus regardé du site. En mono à 36 px il ressemblait
   à une sortie de terminal ; dans le sans, chiffres tabulaires et chasse
   resserrée, il ressemble à un prix. Les trois cartes s'alignent toujours à la
   virgule près, c'est `tabular-nums` qui le garantit, pas la famille. */
.price-card .pc-price{font-family:var(--font-num);font-size:36px;font-weight:600;line-height:1;
  color:var(--ink);letter-spacing:-.026em;font-variant-numeric:tabular-nums}
.price-card .pc-price small{font-family:var(--font);font-size:13px;font-weight:600;color:var(--muted);letter-spacing:0}
.price-card .pc-desc{font-size:14px;color:var(--muted);line-height:1.55}
.price-card ul{display:flex;flex-direction:column;gap:8px;font-size:14px;color:var(--text-secondary);margin:6px 0}
.price-card ul li{display:flex;align-items:flex-start;gap:9px;line-height:1.5}
.price-card ul li svg{width:14px;height:14px;flex-shrink:0;margin-top:4px;color:var(--ok)}
.price-card .btn{justify-content:center;margin-top:auto}
.price-card.pro .btn:not(.ghost){background:var(--primary);color:var(--on-primary);border-color:var(--primary)}
.price-card.pro .btn:not(.ghost):hover{background:var(--primary-hover)}
/* La mention « Recommandé » était une pilule jaune posée à cheval sur le bord
   supérieur de la carte. Elle débordait, cassait l'alignement des trois cartes
   et répétait ce que la bordure jaune disait déjà. Elle rentre dans la carte,
   sur la ligne du nom de l'offre, dans la même graisse que les autres libellés. */
/* Le filet jaune est une ombre portée et non une bordure : une bordure basse
   plus son padding ajoutaient trois pixels à la hauteur de la ligne, et comme
   les trois cartes alignent leur contenu sur cette ligne, le prix du milieu
   descendait de trois pixels. Une box-shadow ne participe pas à la mise en
   page, l'en-tête garde exactement la hauteur du nom d'offre. */
/* 11 px et non 10,5 : c'est le plancher pour du texte fonctionnel, et « Recommandé »
   porte une décision d'achat. Relevé par le détecteur (undersized-ui-text). */
.pc-flag{font-family:var(--font-label);font-size:11px;font-weight:600;text-transform:uppercase;
  letter-spacing:.075em;color:var(--ink);white-space:nowrap;
  box-shadow:0 3px 0 -1px var(--color-primary)}
/* Quand la mention porte le cercle à main levée, le filet jaune saute : deux
   marques sur le même mot se disputent le regard, et c'est le cercle qui dit
   maintenant « regardez ici ». */
.pc-flag.annot{box-shadow:none}
.price-free{font-size:13px;color:var(--muted);text-align:center;line-height:1.7;margin-top:24px;
  max-width:70ch;margin-left:auto;margin-right:auto}
.price-free b{color:var(--ink)}

/* Tarifs compacts pour la page d'accueil. Les trois cartes complètes vivent sur
   /tarifs ; ici on donne les mêmes chiffres en un tiers de la hauteur. Un
   tableau et non une grille, parce que c'est une comparaison de trois offres
   sur deux mesures : c'est exactement ce qu'un tableau sait faire, et ça reste
   lisible au lecteur d'écran ligne par ligne. */
.price-compact{width:100%;border-collapse:collapse;font-size:15px;
  background:var(--surface);border-radius:var(--radius);box-shadow:var(--ring);overflow:hidden}
.price-compact caption{text-align:left}
.price-compact thead th{font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.6px;
  color:var(--muted);background:var(--surface-sunken);padding:11px 18px;text-align:right;white-space:nowrap}
.price-compact thead th:first-child{text-align:left}
.price-compact tbody th{text-align:left;font-weight:600;color:var(--ink);padding:15px 18px}
.price-compact tbody td{text-align:right;font-family:var(--font-num);font-variant-numeric:tabular-nums;
  font-weight:500;letter-spacing:-.012em;color:var(--ink);padding:15px 18px;white-space:nowrap}
.price-compact tbody tr+tr th,.price-compact tbody tr+tr td{border-top:1px solid var(--line)}
/* La ligne recommandée se signale par un filet jaune à gauche, seule entorse à
   la règle « pas de bordure colorée » : sur une ligne de tableau, c'est le seul
   endroit disponible, et il remplace la pilule qu'on a retirée ailleurs. */
.price-compact tr.hi th{box-shadow:inset 3px 0 0 var(--color-primary)}
.price-compact tr.hi th,.price-compact tr.hi td{background:var(--fill-subtle)}
.price-compact .pc-flag{margin-left:9px;vertical-align:1px}
@media(max-width:560px){
  .price-compact{font-size:14px}
  .price-compact thead th,.price-compact tbody th,.price-compact tbody td{padding:12px 12px}
  /* « Par analyse » n'a de sens que pour les packs et coûte une colonne entière
     sur un écran étroit : la valeur unitaire est déjà dans la ligne du haut. */
  .price-compact thead th:last-child,.price-compact tbody td:last-child{display:none}
}

/* Bandeau « gratuit pour toujours ».
   Le fond vert pâle traitait une information commerciale comme un message de
   succès applicatif : le vert veut dire « votre action a réussi », pas « c'est
   gratuit ». Fond de surface, filet neutre, et l'icône garde le vert : il en
   reste juste assez pour attirer l'œil. */
.free-banner{display:flex;flex-wrap:wrap;align-items:center;gap:18px;background:var(--surface);
  border:1px solid var(--line-2);border-radius:var(--radius-lg);padding:22px 26px;margin-bottom:26px}
.free-banner .ic{width:40px;height:40px;border-radius:var(--radius-sm);border:1px solid var(--line-2);
  display:flex;align-items:center;justify-content:center;color:var(--ok);flex-shrink:0}
.free-banner .ic svg{width:20px;height:20px}
.free-banner .tx{flex:1;min-width:220px}
.free-banner b{display:block;font-size:15px;font-weight:700;margin-bottom:3px}
.free-banner span{font-size:14px;color:var(--text-secondary);line-height:1.55}

/* ===========================================================================
   Tableau comparatif
   =========================================================================== */
.cmp-scroll{overflow-x:auto;border:1px solid var(--line);border-radius:var(--radius-lg);background:var(--surface)}
table.cmp{width:100%;border-collapse:collapse;min-width:640px;font-size:14px}
table.cmp th,table.cmp td{padding:15px 18px;text-align:left;border-bottom:1px solid var(--line);vertical-align:top}
table.cmp thead th{background:var(--surface-sunken);font-size:11px;font-weight:600;text-transform:uppercase;
  letter-spacing:.5px;color:var(--muted);white-space:nowrap}
table.cmp thead th.hi{color:var(--ink)}
table.cmp tbody tr:last-child td{border-bottom:none}
table.cmp td:first-child{font-weight:600;color:var(--text-secondary)}
table.cmp td.hi{background:var(--color-primary-subtle);font-weight:600;color:var(--ink)}
/* --text-secondary et non --muted : ces petites lignes tombent souvent dans une
   cellule .hi au fond teinté, où le gris muted passe sous le seuil AA. */
table.cmp td small{display:block;font-size:12px;font-weight:400;color:var(--text-secondary);margin-top:3px}

/* ===========================================================================
   FAQ (<details>)
   =========================================================================== */
.faq{border:1px solid var(--line);border-radius:var(--radius-lg);overflow:hidden;background:var(--surface)}
.faq details{border-bottom:1px solid var(--line)}
.faq details:last-child{border-bottom:none}
.faq summary{list-style:none;cursor:pointer;padding:18px 52px 18px 22px;font-size:15px;font-weight:600;
  position:relative;transition:background var(--transition-fast)}
.faq summary::-webkit-details-marker{display:none}
.faq summary:hover{background:var(--fill-subtle)}
.faq summary::after{content:"";position:absolute;right:22px;top:50%;width:10px;height:10px;
  border-right:2px solid var(--muted);border-bottom:2px solid var(--muted);
  transform:translateY(-70%) rotate(45deg);transition:transform var(--transition-fast)}
.faq details[open] summary::after{transform:translateY(-30%) rotate(-135deg)}
.faq .a{padding:0 22px 20px;font-size:14px;color:var(--text-secondary);line-height:1.7;max-width:75ch}

/* Ouverture d'une question : la réponse apparaissait d'un coup, sans rien dire
   d'où elle venait. Elle descend maintenant de quatre pixels en se révélant,
   depuis le titre qu'on vient de cliquer. C'est le seul mouvement autorisé par
   DESIGN.md pour un accordéon, et il répond à un geste : il ne se déclenche
   jamais tout seul.
   Le contenu est opaque par défaut : si l'animation ne joue pas, on lit quand
   même. Transform et opacité uniquement, aucune propriété de mise en page. */
/* `.rp-ouvert` est posée par site.js sur l'évènement `toggle`, qui ne se
   produit QUE si l'état change réellement. Un `<details open>` livré tel quel
   dans le HTML (/tarifs, /repreneur) ne le déclenche jamais : son animation
   d'ouverture ne peut donc plus se jouer toute seule à l'arrivée. */
/* PAS de `both`. Ce mode de remplissage fige l'état de DÉPART tant que
   l'animation n'a pas fini, or cet état est `opacity:0`. Toute situation où
   l'animation démarre sans s'achever laissait donc la réponse invisible, avec
   sa hauteur réservée : du texte présent dans le document, illisible à
   l'écran. Sans remplissage, l'élément est opaque avant et après ; l'opacité
   nulle n'existe plus qu'au premier instant de l'animation. Rendu identique,
   un mode de défaillance en moins. */
@media(prefers-reduced-motion:no-preference){
  .faq details.rp-ouvert[open] .a{animation:rpReveal .18s cubic-bezier(.16,1,.3,1)}
}
@keyframes rpReveal{from{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:none}}

/* La hauteur, elle, saute encore : un <details> ne sait pas interpoler entre
   zéro et « la hauteur du contenu ». `interpolate-size` lève cette limite, mais
   n'existe que sur les navigateurs récents. On l'active là où c'est possible et
   on laisse le saut ailleurs, ce qui est exactement le comportement actuel :
   aucun risque de régression pour personne. */
@supports (interpolate-size: allow-keywords){
  /* Sans cette declaration, `auto` reste non interpolable et la regle ci-dessous
     n'a aucun effet. Elle doit vivre sur un ancetre, d'ou :root. */
  :root{interpolate-size:allow-keywords}
  @media(prefers-reduced-motion:no-preference){
    .faq details::details-content{
      block-size:0;overflow:hidden;
      transition:block-size .22s cubic-bezier(.16,1,.3,1),content-visibility .22s allow-discrete;
    }
    .faq details[open]::details-content{block-size:auto}
  }
}
.faq .a p+p{margin-top:10px}
.faq .a a{text-decoration:underline;text-underline-offset:2px}

/* ===========================================================================
   Chiffre clé / preuve
   =========================================================================== */
.stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:18px}
.stat{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);padding:22px}
.stat b{display:block;font-family:var(--font-num);font-size:34px;font-weight:600;line-height:1;
  letter-spacing:-.028em;font-variant-numeric:tabular-nums;color:var(--ink)}
.stat span{display:block;font-size:13px;color:var(--muted);margin-top:9px;line-height:1.55}
.stat cite{display:block;font-style:normal;font-size:11px;color:var(--faint);margin-top:8px}

/* ===========================================================================
   Bloc CTA final
   =========================================================================== */
/* La lueur jaune en bas du bloc est partie : elle ne servait qu'à faire
   « premium » et virait au sale sur l'off-white du thème clair. Le bloc se
   distingue par un filet plus marqué que les cartes courantes, c'est assez
   pour signaler qu'on arrive à l'appel à l'action. */
.cta-band{background:var(--surface);border:1px solid var(--line-2);border-radius:var(--radius-lg);
  padding:52px 40px;text-align:center}
.cta-band h2{margin-bottom:14px}
.cta-band .lead{margin:0 auto 26px}
.cta-band .btns{display:flex;flex-wrap:wrap;gap:12px;justify-content:center}
.cta-band .fine{margin-top:20px;font-size:13px;color:var(--faint)}
@media(max-width:640px){ .cta-band{padding:38px 22px} }

/* ===========================================================================
   Barre d'offre persistante
   L'analyse offerte est le meilleur aimant du site : elle ne doit pas dépendre
   du fait que le visiteur atteigne un bloc précis. La barre apparaît une fois
   le hero dépassé, se referme d'un clic et ne revient pas de la session.
   =========================================================================== */
.offerbar{position:fixed;left:16px;right:16px;bottom:16px;z-index:150;
  max-width:760px;margin:0 auto;display:flex;align-items:center;gap:16px;
  background:var(--bg-surface);border:1px solid var(--border-strong);
  border-radius:var(--radius-lg);box-shadow:var(--shadow-md);padding:13px 14px 13px 18px;
  transform:translateY(140%);opacity:0;visibility:hidden;
  transition:transform .45s cubic-bezier(.22,1,.36,1),opacity .3s ease,visibility .45s}
.offerbar.show{transform:none;opacity:1;visibility:visible}
.offerbar .gift{width:38px;height:38px;flex:0 0 auto;border-radius:var(--radius-sm);
  background:var(--color-primary-subtle);color:var(--primary);display:flex;align-items:center;justify-content:center}
:root[data-theme="light"] .offerbar .gift{color:var(--color-black)}
.offerbar .gift svg{width:19px;height:19px}
.offerbar .tx{flex:1;min-width:0;font-size:14px;line-height:1.45;color:var(--text-secondary)}
.offerbar .tx b{display:block;color:var(--ink);font-size:15px;font-weight:700;margin-bottom:2px}
.offerbar .btn{flex:0 0 auto}
.offerbar .close{flex:0 0 auto;width:44px;height:44px;border-radius:var(--radius-sm);color:var(--faint);
  display:flex;align-items:center;justify-content:center;transition:color var(--transition-fast),background var(--transition-fast)}
.offerbar .close:hover{color:var(--ink);background:var(--fill-subtle)}
.offerbar .close svg{width:15px;height:15px}
@media(max-width:640px){
  .offerbar{flex-wrap:wrap;padding:14px;gap:12px;left:10px;right:10px;bottom:10px}
  .offerbar .gift{display:none}
  .offerbar .tx{flex:1 1 auto;font-size:13px;padding-right:38px}
  .offerbar .btn{width:100%;order:3;justify-content:center}
  /* La croix se retrouvait SEULE SUR SA LIGNE, calée à gauche entre le texte et
     le bouton : ça se voyait, et ça faisait mal codé. La cause est le passage à
     la ligne du flex : la taille souhaitée du texte (`flex-basis:auto`, donc sa
     largeur de contenu) dépasse la barre, donc la croix est renvoyée au rang
     suivant AVANT que le texte n'ait le droit de rétrécir.
     On la sort du flux et on la pose dans le coin, là où on ferme une chose.
     La barre est en `position:fixed`, elle sert donc de référence. Le texte
     réserve la place à droite pour ne pas passer dessous. */
  .offerbar{position:fixed}
  .offerbar .close{position:absolute;top:3px;right:3px;width:44px;height:44px}
}

/* ===========================================================================
   Bloc « ce que contient l'analyse offerte »
   =========================================================================== */
/* La bordure jaune reste : c'est le seul bloc du site à en porter une, elle
   signale l'offre sans avoir besoin d'une lueur ni d'une ombre. */
.gift-block{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,340px);gap:34px;align-items:center;
  background:var(--surface);border:1px solid var(--color-primary-border);border-radius:var(--radius-lg);
  padding:36px 34px}
.gift-block h2{margin-bottom:14px}
.gift-block .lead{margin-bottom:22px}
.gift-list{display:flex;flex-direction:column;gap:11px;background:var(--bg);border:1px solid var(--line);
  border-radius:var(--radius);padding:20px}
.gift-list .t{font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.5px;color:var(--muted);margin-bottom:3px}
.gift-list li{display:flex;align-items:flex-start;gap:10px;font-size:14px;color:var(--text-secondary);line-height:1.5}
.gift-list li svg{width:15px;height:15px;flex-shrink:0;margin-top:3px;color:var(--ok)}
.gift-list .no{color:var(--muted)}
.gift-list .no svg{color:var(--faint)}
.gift-block .fine{margin-top:16px;font-size:13px;color:var(--faint)}
@media(max-width:860px){ .gift-block{grid-template-columns:minmax(0,1fr);padding:28px 22px;gap:24px} }

/* ===========================================================================
   Pied de page
   =========================================================================== */
.footer{border-top:1px solid var(--line);background:var(--surface);padding:56px 0 28px;margin-top:0}
.footer-grid{display:grid;grid-template-columns:minmax(210px,1.3fr) repeat(4,minmax(130px,1fr));gap:30px}
.footer-brand p{font-size:13px;color:var(--muted);line-height:1.65;margin-top:18px;max-width:34ch}
.footer h3{font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.6px;color:var(--muted);margin-bottom:14px}
/* Les liens de pied de page faisaient 18 px de haut. On ne grossit pas le
   texte, on étend la zone tactile par le remplissage : la cible passe à 32 px
   sans que la maquette bouge. Les liens en pleine ligne de texte sont exclus
   du seuil des 44 px par la règle 2.5.8, mais une colonne de liens serrés
   reste pénible au pouce. */
.footer ul{display:flex;flex-direction:column;gap:2px}
.footer ul a{font-size:14px;color:var(--text-secondary);transition:color var(--transition-fast);
  display:inline-block;padding:7px 0}
.footer ul a:hover{color:var(--ink);text-decoration:underline;text-underline-offset:3px}
.footer-legal{margin-top:44px;padding-top:22px;border-top:1px solid var(--line);
  display:flex;flex-wrap:wrap;gap:10px 20px;align-items:center;font-size:13px;color:var(--faint)}
/* Environ 178 caractères par ligne avant correctif (relevé par le détecteur),
   soit plus du double du confortable. C'est pourtant le texte qu'on veut voir
   lu : il porte la limite « ni conseil en investissement, ni audit ». */
.footer-legal .disclaimer{flex-basis:100%;line-height:1.65;margin-top:6px;max-width:78ch}
@media(max-width:820px){ .footer-grid{grid-template-columns:minmax(0,1fr) minmax(0,1fr)} .footer-brand{grid-column:1/-1} }

/* ===========================================================================
   Pages internes (contenu éditorial : juridique, outils)
   =========================================================================== */
.page-head{padding:56px 0 8px}
.page-head .lead{margin-top:16px}
.prose{font-size:15px;line-height:1.75;color:var(--text-secondary);max-width:72ch}
.prose h2{font-size:1.35rem;margin:38px 0 14px;color:var(--ink)}
.prose h3{font-size:1.05rem;margin:26px 0 10px;color:var(--ink)}
.prose p{margin-bottom:14px}
.prose ul{list-style:disc;padding-left:20px;margin-bottom:16px}
.prose ul li{margin-bottom:7px}
.prose a{color:var(--ink);text-decoration:underline;text-underline-offset:3px}
.prose strong{color:var(--ink);font-weight:600}
/* Encart « à compléter ». Le texte est en encre courante et non en ambre :
   sur le fond ambre pâle du thème clair, l'ambre ne passe qu'à 3,3:1. */
.prose .todo{background:var(--warn-t);border:1px solid var(--color-warning-subtle);border-radius:var(--radius-sm);
  padding:12px 14px;font-size:14px;color:var(--ink)}

/* ===========================================================================
   Chiffres et schéma du produit
   (ancien « kit vivant » : le surligneur qui se dessinait, les compteurs qui
   montaient et le faisceau qui balayait la feuille en boucle de 3,6 s ont été
   déposés. Une page d'acquisition n'a que quelques secondes d'attention : les
   dépenser à regarder un chiffre grimper de 0 à 78, c'est retarder la lecture
   du chiffre. Le contenu est affiché à sa valeur finale, tout de suite.)
   =========================================================================== */

/* Chiffres alignés en colonne, quelle que soit la valeur. */
.mock-kpi .v,.lp-figures b,.mock-score b,.stat b,.price-card .pc-price{font-variant-numeric:tabular-nums}

/* ── Schéma du document lu : une feuille, ses lignes, les postes retenus ──
   Purement illustratif, donc aria-hidden. Immobile : ce sont les traits jaunes
   qui racontent l'extraction, pas un balayage. */
.rp-scan{width:100%;max-width:280px;margin:0 auto;display:block}
.rp-scan .sheet{fill:var(--bg-surface);stroke:var(--border-strong);stroke-width:1.5}
.rp-scan .ln{stroke:var(--color-neutral-400);stroke-width:3;stroke-linecap:round;opacity:.35}
.rp-scan .num{stroke:var(--color-primary);stroke-width:3;stroke-linecap:round}
/* Sur l'off-white, le jaune pur d'un trait de 3 px passe sous le seuil de
   lisibilité graphique (3:1) : même teinte, un cran plus sombre. */
:root[data-theme="light"] .rp-scan .num{stroke:var(--primary-stroke)}
.rp-scan .chip{fill:none;stroke:var(--border-strong);stroke-width:1}
/* Ces étiquettes sont posées DANS le schéma du scan : ce sont les cases de la
   liasse que la machine lit. La chasse fixe y garde son rôle documentaire. */
.rp-scan .chip-t{fill:var(--color-neutral-500);font:600 7px var(--font-code);letter-spacing:.4px}

/* ── Traducteur de jargon : le composant didactique ──
   Gauche : le terme que le repreneur voit dans son dossier.
   Droite : ce que ça veut dire, en français, avec le seuil qui compte. */
.jargon{display:grid;grid-template-columns:minmax(200px,270px) minmax(0,1fr);gap:0;
  border:1px solid var(--line);border-radius:var(--radius-lg);background:var(--surface);
  overflow:hidden}
.jargon-list{display:flex;flex-direction:column;border-right:1px solid var(--line);background:var(--bg)}
.jargon-list button{display:flex;align-items:center;gap:10px;text-align:left;padding:14px 16px;
  font-size:14px;font-weight:600;color:var(--text-secondary);border-bottom:1px solid var(--line);
  transition:background var(--transition-fast),color var(--transition-fast)}
.jargon-list button:last-child{border-bottom:none}
.jargon-list button:hover{background:var(--fill-subtle);color:var(--ink)}
.jargon-list button[aria-selected="true"]{background:var(--surface);color:var(--ink)}
.jargon-list button::before{content:"";width:3px;align-self:stretch;margin:-14px 0 -14px -16px;
  background:transparent;transition:background var(--transition-fast)}
.jargon-list button[aria-selected="true"]::before{background:var(--primary)}
.jargon-panel{padding:26px 28px;display:flex;flex-direction:column;gap:14px;min-height:230px}
/* Mise en forme des panneaux, reprise du style en ligne qui empechait le
   masquage. La regle [hidden] vient APRES et l'emporte : sans elle, le
   display:flex reaffiche les panneaux caches et le composant montre ses cinq
   definitions d'un coup. */
.jargon-panel [data-pane]{display:flex;flex-direction:column;gap:14px;flex:1}
.jargon-panel [data-pane][hidden]{display:none}
/* Idem : « Excédent brut d'exploitation » est un terme, pas une étiquette.
   En capitales il devient un sigle de plus, alors que tout le composant existe
   précisément pour rendre ces termes lisibles. */
.jargon-panel .term{font-family:var(--font-label);font-size:12px;font-weight:600;
  letter-spacing:0;color:var(--muted)}
.jargon-panel .say{font-size:clamp(1.05rem,2vw,1.3rem);font-weight:700;line-height:1.35;letter-spacing:-.3px}
.jargon-panel .why{font-size:14px;color:var(--text-secondary);line-height:1.65;max-width:56ch}
.jargon-panel .gauge{display:flex;align-items:center;gap:12px;margin-top:auto;padding-top:14px;
  border-top:1px solid var(--line);font-size:13px;color:var(--muted)}
/* `nowrap` : « 245 k€ » se cassait en « 245 » puis « k€ » sur deux lignes en
   mobile. Un nombre et son unité forment un seul mot, ils ne se séparent
   jamais. Même chose pour « 1,9 × » ou « 86 k€ ». */
.jargon-panel .gauge b{font-family:var(--font-num);font-size:15px;font-weight:600;
  letter-spacing:-.012em;font-variant-numeric:tabular-nums;color:var(--ink);
  white-space:nowrap}
.jargon-panel .gauge .bar{flex:1;height:7px;border-radius:var(--radius-full);background:var(--color-neutral-300);overflow:hidden;min-width:80px}
/* Le remplissage est animé en scaleX et non en width : la largeur force un
   recalcul de mise en page à chaque image, la transformation non. */
.jargon-panel .gauge .bar i{display:block;height:100%;border-radius:var(--radius-full);background:var(--ok);
  width:100%;transform:scaleX(0);transform-origin:left center;
  transition:transform .4s cubic-bezier(.22,1,.36,1)}
/* Le seul mouvement conservé ici : il répond au clic sur un onglet et signale
   que le panneau a bien changé. Opacité seule, 180 ms, pas de glissement. */
@media(prefers-reduced-motion:no-preference){
  .jargon-panel.swap{animation:rpFade .18s ease-out both}
}
@keyframes rpFade{from{opacity:0}to{opacity:1}}
@media(max-width:760px){
  .jargon{grid-template-columns:minmax(0,1fr)}
  .jargon-list{flex-direction:row;overflow-x:auto;border-right:none;border-bottom:1px solid var(--line);
    scrollbar-width:none}
  .jargon-list::-webkit-scrollbar{display:none}
  .jargon-list button{border-bottom:none;border-right:1px solid var(--line);white-space:nowrap;padding:12px 14px}
  .jargon-list button::before{display:none}
  .jargon-list button[aria-selected="true"]{box-shadow:inset 0 -3px 0 var(--primary)}
  .jargon-panel{padding:20px 18px;min-height:0}
}
/* La jauge tenait sur une seule rangée : libellé, valeur, barre et note.
   Quatre blocs sur 300 px de large, ça ne rentre pas : le libellé passait sur
   deux lignes, la barre était écrasée à son minimum de 80 px, et « 245 k€ » se
   coupait en deux. Elle se range donc en trois rangées, chacune avec une seule
   chose à faire : le libellé et sa valeur alignés aux deux bords, la barre sur
   toute la largeur, la note en dessous.
   Placement EXPLICITE des quatre occupants : sans ça le placement automatique
   remet la barre et la note dans la colonne de la valeur. */
@media(max-width:620px){
  .jargon-panel .gauge{display:grid;grid-template-columns:minmax(0,1fr) auto;
    gap:8px 12px;align-items:center}
  .jargon-panel .gauge>span:first-of-type{grid-column:1;grid-row:1}
  .jargon-panel .gauge b{grid-column:2;grid-row:1;justify-self:end;font-size:16px}
  .jargon-panel .gauge .bar{grid-column:1/-1;grid-row:2;min-width:0}
  .jargon-panel .gauge>span:last-child{grid-column:1/-1;grid-row:3;line-height:1.5}
}

/* ===========================================================================
   Apparitions au défilement : SUPPRIMÉES (2026-07-26)
   Chaque titre, chaque carte et chaque tableau montait de quatorze pixels en
   apparaissant, les grilles ajoutant un décalage de 60 ms entre leurs enfants.
   Sur une page longue, cela veut dire une trentaine d'animations pendant la
   lecture : le visiteur qui fait défiler vite arrive toujours sur du contenu à
   moitié transparent, et celui qui cherche une information précise attend que
   la page finisse de se mettre en place. C'est aussi ce qui se remarque le plus
   immédiatement comme « page générée ».
   Le contenu est là, opaque, dès le premier rendu. Les classes .reveal et .stag
   ont été retirées des vues ; ne pas les réintroduire.
   =========================================================================== */

@media(prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.001ms!important;animation-iteration-count:1!important;
    transition-duration:.001ms!important;scroll-behavior:auto!important}
}

/* ===========================================================================
   Impression
   =========================================================================== */
@media print{
  /* `.readout` retiré de cette liste : ce n'est plus un bandeau de transition
     mais l'inventaire des postes lus, à l'intérieur d'une section. Ça
     s'imprime. */
  .nav,.footer,.cta-band,.offerbar{display:none}
  body{background:var(--print-bg);color:var(--print-ink)}
  /* Le grain et la trame sont des effets d'ecran. Sur papier ils ne rendent
     rien de bon : le grain devient du bruit d'impression et la trame un
     quadrillage gris sur chaque page. Le grain est en `position:fixed`, donc
     sans cette regle il se reimprimerait a chaque feuille. */
  body::after,.hero::after,.hero::before{display:none}
}
