/* =========================================================================
   Propul — couche charte graphique (book de marque, version finale fond blanc).

   Chargée en DERNIER, après style.css / propulseo.css. Elle aligne le gabarit
   Agenio sur la charte sans toucher à sa structure :

     1. typographie : Source Serif 4 700 pour le H1/display, Inter partout
        ailleurs, JetBrains Mono 500 en capitales espacées pour les labels ;
     2. boutons : fond --accent, libellé blanc, rayon 6px, jamais de pilule ;
     3. cartes au filet 1px, rayon 10px, jamais d'ombre (l'ombre --shadow-
        flottant reste aux menus et modales) ;
     4. liens de contenu : couleur + soulignement ;
     5. extinction des résidus sombres du gabarit (préchargeur, carte tarif
        « dark ») : aucun fond de page coloré, aucune bande pleine largeur ;
     6. focus visible et grille de hero aux tokens.

   Toutes les couleurs passent par les tokens de propul-tokens.css : aucune
   valeur en dur ici, hors héritages fonctionnels blanc/noir d'overlay.
   ========================================================================= */

/* ------------------------------------------------------------ 1. TYPOGRAPHIE */

body {
  font-family: var(--font-corps);
  color: var(--color-body-1);
}

/* Le H1 et le titre de bannière portent le serif : c'est la voix éditoriale.
   Tout le reste du titrage travaille en Inter 600 (charte : H2..H4). */
h1, .h1,
.wpr-banner-area .banner-content-area .section-title {
  font-family: var(--font-display);
  font-weight: 700;
}

h2, .h2, h3, .h3, h4, .h4, h5, .h5, h6, .h6 {
  font-family: var(--font-corps);
  font-weight: 600;
}

/* Labels de section (« NOS EXPERTISES », etc.) : mono, capitales, approche
   0,2em, taille plancher 12px (11px rendus minimum, charte §04). Le carré
   12px du gabarit devient LA puce carrée accent de la charte. Le fond gris
   du gabarit disparaît : le label vit nu sur le blanc. */
.section-title-area .sub-title,
.sub-title {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-label);
  text-transform: uppercase;
  letter-spacing: 0.2em;
  color: var(--texte-2);
  background: transparent;
}

.section-title-area .sub-title::after {
  background: var(--accent);
}

/* La lecture longue est encre sur blanc (charte §03) : les paragraphes de
   contenu rédactionnel reprennent l'encre, les descriptions courtes sous les
   titres restent en texte second via --color-body-1. */
.details-area p,
.details-area li,
blockquote p {
  color: var(--encre);
}

/* --------------------------------------------------------------- 2. BOUTONS */

.wpr-btn {
  border-radius: var(--r-bouton);
  font-family: var(--font-corps);
  font-weight: 600;
  box-shadow: none;
}

.wpr-btn.btn-primary,
.wpr-btn:not(.btn-white) {
  background: var(--accent);
  color: var(--fond);
}

.wpr-btn.btn-primary:hover,
.wpr-btn:not(.btn-white):hover {
  background: var(--accent-hover);
  color: var(--fond);
}

/* L'icône verte glossy du gabarit devient un aplat accent-hover discret. */
.wpr-btn.with-icon .icon {
  background: var(--accent-hover);
  box-shadow: none;
  border-radius: var(--r-champ);
}

.wpr-btn.btn-primary *,
.wpr-btn:not(.btn-white) * {
  color: var(--fond);
}

/* Le bouton contour de la charte : fond blanc, filet, texte encre. Les
   dégradés radiaux et ombres du gabarit s'éteignent (interdit n° 5). */
.wpr-btn.btn-white {
  background: var(--fond);
  border: 1px solid var(--filet);
  box-shadow: none;
  color: var(--encre);
}

.wpr-btn.btn-white:hover {
  border-color: var(--encre);
  box-shadow: none;
  background: var(--fond);
}

/* Icônes/flèches internes des boutons pleins : blanches sur accent. */
.wpr-btn.btn-primary img,
.wpr-btn.btn-primary svg {
  filter: brightness(0) invert(1);
}

/* ---------------------------------------------------- 3. CARTES ET FILETS */

.border-1,
section .section-inner.border-1 {
  border-color: var(--filet) !important;
}

/* Cartes du gabarit : rayon charte, jamais d'ombre. */
.service-wrapper,
.pricing-wrapper,
.why-choose-wrapper,
.why-choose-wrapper2,
.working-process-wrapper,
.wpr-content-area {
  border-radius: var(--r-carte);
  box-shadow: none;
}

/* La carte tarif « dark » du gabarit : la charte interdit les fonds sombres.
   Elle devient la carte mise en avant : blanche, cernée par l'accent. */
.pricing-wrapper.dark {
  background: var(--fond);
  border: 1px solid var(--accent);
  box-shadow: none;
}

.pricing-wrapper.dark .pricing-header {
  background: transparent;
}

.pricing-wrapper.dark .pricing-header .plan-type .h6,
.pricing-wrapper.dark .pricing-header .title,
.pricing-wrapper.dark .pricing-body .h6,
.pricing-wrapper.dark .h6,
.pricing-wrapper.dark .title {
  color: var(--encre);
}

.pricing-wrapper.dark .pricing-header .plan-type p {
  background: transparent;
  border: 1px solid var(--accent);
  color: var(--accent);
}

.pricing-wrapper.dark .pricing-header .title span,
.pricing-wrapper.dark p,
.pricing-wrapper.dark li {
  color: var(--texte-2);
}

/* ------------------------------------------------------------------ 4. LIENS */

/* Liens de contenu : couleur + soulignement (jamais la couleur seule).
   La navigation, les boutons et les cartes cliquables gardent leur propre
   vocabulaire (filet animé du gabarit). */
.details-area p a,
.details-area li a,
.desc a,
p.desc a,
.lexicon-link {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 2px;
  text-decoration-color: color-mix(in srgb, var(--accent) 45%, transparent);
  transition: text-decoration-color var(--dur-base) var(--ease-out);
}

.details-area p a:hover,
.details-area li a:hover,
.desc a:hover,
.lexicon-link:hover {
  color: var(--accent);
  text-decoration-color: var(--accent);
}

/* ------------------------------------------- 5. EXTINCTION DES RÉSIDUS SOMBRES */

/* Préchargeur : il était noir plein écran. La charte le passe au blanc, nom
   en encre serif, barres en grille. Même mécanique, autre peau. */
.preloader {
  background-color: var(--fond);
}

.preloader span {
  color: var(--encre);
  font-family: var(--font-display);
  font-weight: 700;
}

.preloader .preloader-gutters .bar .inner-bar {
  background-color: var(--grille);
}

.preloader .preloader-overlay {
  background-color: var(--fond);
}

/* ---------------------------------------------------------- 6. NAVIGATION */

/* Lockup de marque en texte : Propul, nom seul en encre, serif 700 (charte :
   la maison ne porte jamais d'accent dans son nom). Remplace les SVG. */
.propul-lockup {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 26px;
  line-height: 1;
  letter-spacing: -0.01em;
  color: var(--encre);
}

.propul-lockup-pied {
  font-size: clamp(64px, 10vw, 140px);
}

/* Lockup de pôle (colonne « nous » de la section deux sociétés) : le mot de
   branche prend l'accent de son contexte data-branche. */
.propul-lockup-pole {
  font-size: clamp(28px, 3vw, 40px);
}

.propul-lockup .pole-accent {
  color: var(--accent);
}

/* Colonne de pôle en titre simple (« Propul AI ») : le gabarit grise le
   <span> de fin de titre, réservé aux mises en avant hors marque. Dans un
   contexte de branche, ce dernier mot est le nom du pôle : il prend l'accent
   display (orange vif, réservé aux grandes tailles ; ce titre fait 32 à
   42px), pour répondre au « SEO » violet du lockup d'en face. */
.why-choose-wrapper[data-branche] .wrapper-header .title span {
  color: var(--accent-display);
}

/* Le bandeau du haut n'a plus le droit d'être une bande sombre pleine largeur
   (interdit n° 4) : blanc, filet bas, label mono. */
.header-style-one .header-top {
  background: var(--fond);
  border-bottom: 1px solid var(--filet);
}

.header-style-one .header-top .header-top-inner .text {
  color: var(--texte-2);
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-label);
  letter-spacing: 0.2em;
}

.header-style-one .header-top .header-top-inner .text span {
  color: var(--accent);
}

/* Charte (book §05-07) : liens de nav en mono capitales, texte second, l'état
   actif et le survol passent à l'accent. Le CTA de nav est le bouton plein. */
.main-nav-area ul li > a.item-link,
.main-nav-area > ul > li > a {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-label);
  text-transform: uppercase;
  letter-spacing: 0.16em;
  color: var(--texte-2);
}

.main-nav-area ul li > a.item-link:hover,
.main-nav-area > ul > li > a:hover {
  color: var(--accent);
}

/* Menus déroulants : seuls porteurs légitimes de l'ombre flottante. */
.main-nav-area .sub-menu {
  box-shadow: var(--shadow-flottant);
  border: 1px solid var(--filet);
  border-radius: var(--r-carte);
}

/* Les entrées de sous-menu restent en Inter (lisibilité de liste), l'encre
   au survol de l'accent. */
.main-nav-area .sub-menu a {
  font-family: var(--font-corps);
  text-transform: none;
  letter-spacing: 0;
  font-size: 15px;
}

/* ---------------------------------------------------------------- 7. FOCUS */

a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
summary:focus-visible,
[tabindex]:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--r-champ);
}

/* ------------------------------------------------- 8. FORMULAIRES ET CHAMPS */

input[type='text'],
input[type='email'],
input[type='tel'],
input[type='number'],
select,
textarea {
  border-radius: var(--r-champ);
}

/* --------------------------------------------- 8bis. ZONE CONTACT EN CLAIR */

/* Le gabarit peint la zone contact de l'accueil en bande d'encre pleine
   largeur : interdit n° 4. On généralise sa propre variante claire (.inner)
   à toutes les pages : blanc, filets, encre. */
.wpr-contact-area .section-inner .left-content-area .get-in-touch .sub-title,
.wpr-contact-area .section-inner .left-content-area .location-area .sub-title,
.wpr-contact-area .section-inner .contact-form-area form .single-input label {
  color: var(--texte-2);
  background: transparent;
}

.wpr-contact-area .section-inner .left-content-area .get-in-touch ul li a,
.wpr-contact-area .section-inner .left-content-area .location-area ul li .h4 {
  color: var(--encre);
}

.wpr-contact-area .section-inner .left-content-area .location-area ul li p {
  color: var(--texte-2);
}

.wpr-contact-area .section-inner .contact-form-area {
  border-left: 1px solid var(--filet);
}

.wpr-contact-area .section-inner .contact-form-area form .single-input input,
.wpr-contact-area .section-inner .contact-form-area form .single-input textarea {
  color: var(--encre);
  border-bottom: 1px solid var(--filet);
}

.wpr-contact-area .section-inner .contact-form-area form .single-input input::placeholder,
.wpr-contact-area .section-inner .contact-form-area form .single-input textarea::placeholder {
  color: var(--texte-2) !important;
}

.wpr-contact-area .section-inner .contact-form-area form .single-input input:focus,
.wpr-contact-area .section-inner .contact-form-area form .single-input textarea:focus {
  border-bottom: 1px solid var(--accent);
}

/* --------------------------------------------------- 8ter. RETOUCHES FINES */

/* Bouton d'envoi du formulaire : aucun relief. */
.wpr-contact-area .section-inner .contact-form-area form .form-btn-area button {
  box-shadow: none;
  border-radius: var(--r-bouton);
}

/* Pied de page compact. Le gabarit intercalait entre les liens et le
   copyright un div.footer-logo-area de 422px (140px de marge haute, 140px de
   basse, un lockup de 140px de corps). Il est démonté au rendu ; ces deux
   règles reprennent ce qu'il portait :

   1. le filet qui séparait les deux rangées était son `border-width: 1px 0` —
      il revient sur la rangée du copyright, qui le suit désormais ;
   2. la rangée de liens gardait 64px de marge haute et basse parce qu'elle
      s'appuyait sur une bande de 422px. Sans elle, 28px suffisent à la
      détacher. Depuis le § 10.16 elle ne porte plus que les deux pages
      légales : les cinq rubriques qu'elle listait sont passées dans les
      colonnes. */
.wpr-footer-area .footer-top {
  padding-block: 28px;
}

.wpr-footer-area .copyright-area {
  border-top: 1px solid var(--filet);
}

/* Pied de page : les liens du bas portent couleur + soulignement (charte).
   Les deux noms de pole tiennent en deux mots : sans nowrap ils se coupent en
   « Propul / SEO » sur telephone, ou la rangee fait 390px. La liste, elle,
   passe a la ligne — sur ordinateur elle tient deja sur une seule. */
.wpr-footer-area .copyright-area .left-social-area ul {
  flex-wrap: wrap;
  row-gap: 8px;
}

.wpr-footer-area .copyright-area .left-social-area ul li a {
  white-space: nowrap;
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: var(--filet);
}

.wpr-footer-area .copyright-area .left-social-area ul li a:hover {
  color: var(--accent);
  text-decoration-color: var(--accent);
}

/* Zone établissement du bloc contact : « Lisbonne » cassait en deux lignes,
   Inter étant plus large que la Space Grotesk d'origine. */
.wpr-contact-area .section-inner .left-content-area .location-area ul li .h4 {
  font-size: var(--fs-h2);
  overflow-wrap: normal;
}

/* ------------------------------------- 8quater. CARTOUCHES ET CARTES RESTANTS */

/* Cartouche de légende des visuels de réalisations : le voile noir devient un
   cartouche blanc au filet, texte encre (la couleur n'est plus un voile). */
.wpr-project-area .slide .slide-content .product-intro,
.project-wrapper .slide-content .product-intro,
.project-wrapper2 .slide-content .product-intro,
.wpr-next-project-area .section-inner .section-mid-area .slide .slide-content .product-intro {
  background: color-mix(in srgb, var(--fond) 94%, transparent);
  border-color: var(--filet);
}

.product-intro,
.product-intro p,
.product-intro .title,
.product-intro .h5,
.product-intro .h6,
.product-intro a,
.product-intro span {
  color: var(--encre);
}

.product-intro .desc,
.product-intro .category {
  color: var(--texte-2);
}

/* Boîtes de fonctionnalités des pages services : blanches, filet, sans ombre. */
.services-details-banner .section-inner .service-overview .feature-wrapper-area .feature-box {
  background-color: var(--fond);
  border: 1px solid var(--filet);
  border-radius: var(--r-carte);
  box-shadow: none;
}

/* Citation : le bloc noir arrondi devient une carte blanche au filet. */
.blockquote-wrap {
  background-color: var(--fond);
  border: 1px solid var(--filet);
  border-radius: var(--r-carte);
  box-shadow: none;
}

.blockquote-wrap p,
.blockquote-wrap .title,
.blockquote-wrap blockquote {
  color: var(--encre);
}

.blockquote-wrap .desc,
.blockquote-wrap cite {
  color: var(--texte-2);
}

/* Ombres décoratives restantes (Bootstrap et gabarit) : les cartes se
   détachent par un filet. Le focus clavier est porté par l'outline accent. */
.accordion-item,
.accordion-button,
.accordion-button:focus,
.accordion-button:not(.collapsed),
.image-area,
.image-area img,
.project-wrapper2 .image-area {
  box-shadow: none !important;
}

/* Teinte bleutée du bouton de fermeture de la recherche. */
.search-input-area .search-close-icon i::after {
  background: color-mix(in srgb, var(--accent) 8%, white);
}

/* ------------------------------------------------------- 9. DIVERS GABARIT */

/* Les pastilles « check » et compteurs suivent l'encre et l'accent via les
   variables déjà retokenisées. Les ombres décoratives résiduelles du gabarit
   s'éteignent partout où elles marquaient des cartes. */
.rts-btn,
.testimonial-wrapper,
.blog-wrapper,
.brand-wrapper {
  box-shadow: none;
}

/* Le halo/dégradé décoratif du gabarit sur les zones CTA disparaît : le blanc
   respire, les filets structurent. */
.wpr-cta-area .section-inner .bg-shape,
.section-bg-shape {
  display: none;
}

/* --------------------------------------------------- 6bis. SÉLECTEUR DE LANGUE

   Le site est bilingue : le français à la racine, l'anglais sous `en/`. Le
   sélecteur vit dans la barre haute, la seule zone qui traverse toutes les
   pages sans concurrencer la navigation.

   Il reprend exactement la typographie de cette barre — mono, 11 px, capitales,
   interlettrage large — pour se lire comme une mention et non comme un bouton.
   La barre est un flex à trois enfants (icône, texte, icône) ; le sélecteur s'y
   ajoute en quatrième et se cale à droite en position absolue, pour ne pas
   déplacer le texte centré du gabarit. */

.header-style-one .header-top .header-top-inner {
  position: relative;
}

.ps-langues {
  position: absolute;
  /* Aligne sur la gouttiere du logo, qui commence a 50 px a 1440 : colle au
     bord, le selecteur donnait l impression d un debordement. */
  right: clamp(1rem, 3.5vw, 3.125rem);
  top: 50%;
  transform: translateY(-50%);
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-label);
  letter-spacing: 0.2em;
}

/* Le filet qui sépare les deux langues : la même valeur que toutes les
   séparations du site, jamais une barre oblique tapée en dur. */
.ps-langues > * + *::before {
  content: '';
  display: inline-block;
  width: 1px;
  height: 0.85em;
  margin-right: 0.5rem;
  vertical-align: -0.1em;
  background: var(--filet);
}

.ps-langues__actif {
  color: var(--accent);
}

.ps-langues__lien {
  color: var(--texte-2);
  text-decoration: none;
  transition: color var(--dur-rapide) var(--ease-out);
}

.ps-langues__lien:hover,
.ps-langues__lien:focus-visible {
  color: var(--accent);
}

/* Le gabarit masque la barre haute sous 992 px. Le tiroir mobile porte donc
   le second sélecteur, juste au-dessus du bouton d’appel : sans lui, le site
   ne serait bilingue que sur ordinateur. */
.ps-langues--tiroir {
  position: static;
  transform: none;
  justify-content: flex-start;
  padding: 1rem 0 0.75rem;
  margin-top: 0.5rem;
  border-top: 1px solid var(--filet);
}


/* ============================================================================
   10. BLOCS PROPUL AI
   ============================================================================

   Les sections portées depuis propul-ai.com. Elles ne recopient aucun bloc du
   gabarit Agenio : celui-ci n'a ni schéma de flux, ni rail de méthode, ni
   figure isométrique. Leurs classes portent donc le préfixe `ps-ia-`, et elles
   vivent ici, dans la couche chargée en dernier, jamais dans `style.css`.

   Chaque bloc ouvre par un RESET LOCAL. `style.css` fait 18 698 lignes et pose
   des règles globales sur `p`, `h2`, `ol`, `li`, `article`. Sans ce reset,
   aucune mesure de la spécification ne tient.

   Toutes les longueurs sont en `px`. La raison a CHANGÉ en session 3 : elle
   était que le gabarit posait `html { font-size: 10px }` et faussait tous les
   `rem`. La racine est revenue à 16 px, l'échelle de la charte est vivante, et
   ces valeurs pourraient s'y écrire. On les garde en pixels parce qu'une
   géométrie de composant se dimensionne au pixel, pas sur une échelle de
   texte — voir la règle `une-seule-echelle` de build/controles.mjs, qui ne
   réclame le jeton que là où il vaut exactement la même chose.
   ------------------------------------------------------------------------- */

/* ---- 10.0 Le cadre commun : rails verticaux, respiration, marge ---- */

/* Pas de `scroll-margin-top` ici : `propulseo.css` pose déjà
   `html { scroll-padding-top: 106px }` pour toutes les ancres du site, et les
   deux réserves S'ADDITIONNENT — mesuré à 202 px de retrait au saut, soit
   106 px de blanc de trop sous un en-tête qui n'en occupe que 80. Une seule
   réserve, celle du site. La constante HAUT de `propulseo-ia.js` porte la
   même valeur : c'est ce qui fait qu'une section visée est aussitôt marquée
   active dans le sommaire. */
.ps-ia {
  position: relative;
  background: var(--fond);
}

.ps-ia *,
.ps-ia *::before,
.ps-ia *::after {
  box-sizing: border-box;
}

.ps-ia :where(p, h2, h3, ol, ul, li, article, div, span, dl, dt, dd) {
  margin: 0;
  padding: 0;
}

.ps-ia :where(ol, ul) {
  list-style: none;
}

/* Le cadre de page et ses deux rails verticaux, qui se raboutent d'une section
   à l'autre. Largeur utile à 1440 : 1440 moins 2 px de filets moins 128 px de
   gouttières, soit 1310 px. */
.ps-ia-cadre {
  position: relative;
  margin: 0 auto;
  width: 100%;
  max-width: 1560px;
  padding: 56px 20px;
  border-left: 1px solid var(--filet);
  border-right: 1px solid var(--filet);
}

@media (min-width: 640px) {
  .ps-ia-cadre { padding: 64px 32px; }
}

@media (min-width: 1024px) {
  .ps-ia-cadre { padding: 80px 48px; }
}

@media (min-width: 1280px) {
  .ps-ia-cadre { padding: 80px 64px; }
}

/* La grille millimétrée du fond : deux trames, 96 px et 24 px, éteinte vers le
   bas. Chaque ligne cite --grille, ce qui la rend lisible par le validateur de
   charte : le dégradé n'est pas décoratif, il EST la grille. */
.ps-ia-grille {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image:
    linear-gradient(to right, var(--grille) 1px, transparent 1px),
    linear-gradient(to bottom, var(--grille) 1px, transparent 1px),
    linear-gradient(to right, color-mix(in srgb, var(--grille) 45%, transparent) 1px, transparent 1px),
    linear-gradient(to bottom, color-mix(in srgb, var(--grille) 45%, transparent) 1px, transparent 1px);
  background-size: 96px 96px, 96px 96px, 24px 24px, 24px 24px;
  mask-image: linear-gradient(to bottom, black, transparent 70%);
  -webkit-mask-image: linear-gradient(to bottom, black, transparent 70%);
}

/* ---- 10.1 La marge d'annotation ---- */

.ps-ia-marge {
  display: flex;
  align-items: center;
  gap: 16px;
  margin-bottom: 32px;
}

.ps-ia-marge__num {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: 13px;
  line-height: 1;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--accent);
}

.ps-ia-marge__filet {
  display: block;
  width: 32px;
  height: 1px;
  background: var(--filet);
}

.ps-ia-marge__libelle {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-label);
  line-height: var(--lh-label);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--texte-2);
}

/* ---- 10.2 Le titre de section ---- */

/* 52 px sur 1,12 partout. La source rendait un interligne de 1 à 1440 parce
   que la classe Tailwind text-5xl réécrit line-height : c'était un effet de
   bord, pas une intention. */
.ps-ia-titre {
  max-width: 24ch;
  /* style.css met les h2 du gabarit en capitales : ce titre est une phrase. */
  text-transform: none;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 34px;
  line-height: 1.12;
  letter-spacing: -0.015em;
  color: var(--encre);
}

@media (min-width: 640px) {
  .ps-ia-titre { font-size: 48px; }
}

@media (min-width: 1280px) {
  .ps-ia-titre { font-size: 52px; }
}

/* ---- 10.3 Le bloc source ---- */

.ps-ia-source {
  position: relative;
  border: 1px solid var(--encre);
  background: var(--fond);
  padding: 40px 32px;
  text-align: center;
}

.ps-ia-source--pile {
  padding: 28px 24px;
}

.ps-ia-source__ref {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-label);
  line-height: 1;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--accent);
}

.ps-ia-source__nom {
  margin-top: 12px;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 24px;
  line-height: 1.25;
  color: var(--encre);
}

.ps-ia-source--pile .ps-ia-source__nom {
  margin-top: 8px;
  font-size: 21px;
}

/* Le port carré d'où part la branche du milieu : il dépasse de 5 px, et c'est
   ce dépassement qui fait le raccord avec le filet. */
.ps-ia-source__port {
  position: absolute;
  right: -5px;
  top: 50%;
  transform: translateY(-50%);
  width: 9px;
  height: 9px;
  border: 1px solid var(--encre);
  background: var(--fond);
}

/* ---- 10.4 La figure large : bus, branches, losanges ---- */

.ps-ia-flux {
  display: none;
}

@media (min-width: 1024px) {
  .ps-ia-flux {
    display: grid;
    grid-template-columns: minmax(0, 300px) minmax(0, 150px) minmax(0, 1fr);
    /* Rangées égales : les centres tombent à 1/6, 1/2 et 5/6 de la hauteur,
       exactement où les branches arrivent. C'est ce qui dispense de tout
       calcul et de toute écoute de resize. */
    grid-auto-rows: 1fr;
    margin-top: 48px;
  }

  .ps-ia-pile { display: none; }
}

@media (min-width: 1280px) {
  .ps-ia-flux {
    grid-template-columns: minmax(0, 340px) minmax(0, 190px) minmax(0, 1fr);
  }
}

.ps-ia-flux__source {
  grid-column: 1;
  grid-row: 1 / span 3;
  align-self: center;
}

/* Le bus vertical. Il s'arrête aux centres des rangées 1 et 3 : il n'a pas de
   coin dessiné, c'est le croisement avec la branche qui fait l'angle. */
.ps-ia-flux__bus {
  grid-column: 2;
  grid-row: 1 / span 3;
  position: relative;
}

.ps-ia-flux__bus::before {
  content: "";
  position: absolute;
  left: 24px;
  top: 16.66%;
  bottom: 16.66%;
  width: 1px;
  background: var(--filet);
}

.ps-ia-flux__branche {
  grid-column: 2;
  position: relative;
}

/* Le rang est pose explicitement. Sans lui, le placement automatique de la
   grille envoie les trois branches dans des rangees 4, 5 et 6 creees pour
   l'occasion, sous la figure, et la figure double de hauteur. */
.ps-ia-flux__branche--r1 { grid-row: 1; }
.ps-ia-flux__branche--r2 { grid-row: 2; }
.ps-ia-flux__branche--r3 { grid-row: 3; }

.ps-ia-flux__branche::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 24px;
  right: 0;
  height: 1px;
  background: var(--filet);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.55s cubic-bezier(0.22, 1, 0.36, 1) 0.08s;
}

/* La rangée du milieu part du port du bloc, pas du bus. */
.ps-ia-flux__branche--directe::before {
  left: 0;
}

.ps-ia-flux[data-vu] .ps-ia-flux__branche::before {
  transform: none;
}

.ps-ia-flux__cartes {
  grid-column: 3;
  grid-row: 1 / span 3;
  display: grid;
  grid-auto-rows: 1fr;
}

/* Les rangées sont séparées par un padding, JAMAIS par un gap de grille : un
   gap déplacerait les centres et les branches rateraient les losanges. */
.ps-ia-flux__rangee {
  position: relative;
  padding: 10px 0;
}

.ps-ia-flux__rangee::before {
  content: "";
  position: absolute;
  left: -6px;
  top: 50%;
  width: 11px;
  height: 11px;
  transform: translateY(-50%) rotate(45deg);
  border: 1px solid var(--accent-display);
  background: var(--fond);
  z-index: 10;
}

/* ---- 10.5 Les paquets de données ----

   Cinq pixels qui traversent la branche : c'est le sens même de la figure,
   « ça sort en ce moment même ». Course de 2,6 s puis pause de 0,9 s, soit un
   cycle de 3,5 s ; les trois branches sont décalées de 0,85 s. */

.ps-ia-flux__paquet {
  position: absolute;
  top: 50%;
  left: -3%;
  width: 5px;
  height: 5px;
  transform: translateY(-50%);
  background: var(--accent-display);
  opacity: 0;
}

.ps-ia-flux[data-vu] .ps-ia-flux__paquet {
  animation: ps-ia-paquet 3.5s linear infinite;
  animation-delay: var(--ps-ia-delai, 0s);
}

.ps-ia-flux__branche--r2 .ps-ia-flux__paquet { --ps-ia-delai: 0.85s; }
.ps-ia-flux__branche--r3 .ps-ia-flux__paquet { --ps-ia-delai: 1.7s; }

@keyframes ps-ia-paquet {
  0%     { left: -3%;  opacity: 0; }
  8.9%   { opacity: 1; }
  65.4%  { opacity: 1; }
  74.3%  { left: 103%; opacity: 0; }
  100%   { left: 103%; opacity: 0; }
}

/* ---- 10.6 La carte de constat ---- */

.ps-ia-constat {
  position: relative;
  display: flex;
  flex-direction: column;
  height: 100%;
  border: 1px solid var(--filet);
  background: var(--fond);
  padding: 20px;
  transition: border-color var(--dur-rapide) var(--ease-out);
}

@media (min-width: 1280px) {
  .ps-ia-constat { padding: 24px; }
}

.ps-ia-constat:hover {
  border-color: var(--accent-display);
}

.ps-ia-constat__entete {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
}

.ps-ia-constat__num {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: 15px;
  line-height: 1;
  color: var(--accent);
}

.ps-ia-constat__tampon {
  flex-shrink: 0;
  padding: 4px 8px;
  border: 1px solid color-mix(in srgb, var(--accent) 35%, transparent);
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-label);
  line-height: 1;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--accent);
}

.ps-ia-constat__fait {
  margin-top: 12px;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 19px;
  line-height: 1.375;
  color: var(--encre);
}

@media (min-width: 640px) {
  .ps-ia-constat__fait { font-size: var(--fs-h3); }
}

.ps-ia-constat__detail {
  margin-top: 10px;
  font-family: var(--font-corps);
  font-size: 14.5px;
  line-height: 1.7;
  color: var(--texte-2);
}

/* ---- 10.7 La figure étroite : la même matière empilée ---- */

.ps-ia-pile {
  margin-top: 40px;
}

.ps-ia-pile__liste {
  position: relative;
  margin-left: 20px;
  padding-top: 8px;
}

.ps-ia-pile__rail {
  position: absolute;
  left: -1px;
  top: 0;
  height: 100%;
  width: 1px;
  background: var(--filet);
}

.ps-ia-pile__item {
  position: relative;
  margin-top: 24px;
  padding-left: 24px;
}

.ps-ia-pile__tenon {
  position: absolute;
  left: 0;
  top: 32px;
  width: 24px;
  height: 1px;
  background: var(--filet);
}

.ps-ia-pile__losange {
  position: absolute;
  left: 19px;
  top: 32px;
  width: 11px;
  height: 11px;
  transform: translateY(-50%) rotate(45deg);
  border: 1px solid var(--accent-display);
  background: var(--fond);
  z-index: 10;
}

/* ---- 10.8 La légende ---- */

.ps-ia-legende {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 32px;
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-label);
  line-height: 1.4;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--texte-2);
}

.ps-ia-legende__temoin {
  position: relative;
  flex-shrink: 0;
  display: inline-block;
  width: 40px;
  height: 1px;
  background: var(--filet);
}

.ps-ia-legende__temoin::before {
  content: "";
  position: absolute;
  top: -2px;
  left: 50%;
  transform: translateX(-50%);
  width: 5px;
  height: 5px;
  background: var(--accent-display);
}

/* ---- 10.9 Les révélations ----

   Translation de 20 px, une seule fois, à l'entrée dans le champ. La cascade
   décale les enfants de 60 ms. Sous prefers-reduced-motion, la règle générale
   de propul-tokens.css coupe les transitions mais pas l'opacité : on la
   neutralise ici explicitement, sinon le contenu resterait invisible. */

.ps-ia [data-reveal],
.ps-ia [data-reveal-cascade] > * {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity 0.5s var(--ease-out), transform 0.5s var(--ease-out);
}

.ps-ia [data-reveal][data-vu],
.ps-ia [data-reveal-cascade][data-vu] > * {
  opacity: 1;
  transform: none;
}

.ps-ia [data-reveal-cascade][data-vu] > *:nth-child(2) { transition-delay: 60ms; }
.ps-ia [data-reveal-cascade][data-vu] > *:nth-child(3) { transition-delay: 120ms; }
.ps-ia [data-reveal-cascade][data-vu] > *:nth-child(4) { transition-delay: 180ms; }

@media (prefers-reduced-motion: reduce) {
  .ps-ia [data-reveal],
  .ps-ia [data-reveal-cascade] > * {
    opacity: 1;
    transform: none;
  }

  .ps-ia-flux__paquet {
    display: none;
  }
}


/* ---- 10.10 Le rail à losanges ----

   Cinq postes équirépartis sur une règle graduée, quatre losanges de décision
   dans les intervalles. Les positions sont des pourcentages fixes : 10, 30,
   50, 70, 90 % pour les postes, 20, 40, 60, 80 % pour les décisions. Aucune
   mesure, aucun recalcul, aucune écoute de resize.

   Le rail lui-même est un fond CSS : une ligne de 1 px et des graduations tous
   les 24 px, en deux dégradés superposés. Chaque ligne cite --filet, ce qui la
   rend lisible par le validateur de charte. */

.ps-ia-titre--court {
  max-width: 22ch;
}

.ps-ia-corps {
  margin-top: 24px;
  max-width: 66ch;
  font-family: var(--font-corps);
  font-size: 17px;
  line-height: 1.75;
  color: var(--encre);
}

.ps-ia-chaine {
  margin-top: 44px;
}

/* Le rail n'existe qu'à partir de 1024 px : en dessous, la chaîne devient une
   pile verticale et le rail n'aurait pas la place de se lire. */
.ps-ia-chaine__rail {
  display: none;
}

@media (min-width: 1024px) {
  .ps-ia-chaine__rail {
    display: block;
    position: relative;
    height: 74px;
  }

  .ps-ia-pile-etapes { display: none; }
}

/* La règle graduée : ligne de 1 px en haut, graduations de 6 px tous les
   24 px. Deux dégradés sur un span de 6 px, pas un SVG. */
.ps-ia-chaine__regle {
  position: absolute;
  left: 0;
  top: 19px;
  width: 100%;
  height: 6px;
  background-image: linear-gradient(to bottom, var(--filet) 1px, transparent 1px), repeating-linear-gradient(to right, var(--filet) 0 1px, transparent 1px 24px);
  background-size: 100% 1px, 100% 6px;
  background-repeat: no-repeat, repeat-x;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 1.2s linear;
}

.ps-ia-chaine[data-vu] .ps-ia-chaine__regle {
  transform: none;
}

/* ---- Les postes ---- */

.ps-ia-chaine__poste {
  position: absolute;
  top: 0;
  transform: translateX(-50%);
}

.ps-ia-chaine__poste--p1 { left: 10%; }
.ps-ia-chaine__poste--p2 { left: 30%; }
.ps-ia-chaine__poste--p3 { left: 50%; }
.ps-ia-chaine__poste--p4 { left: 70%; }
.ps-ia-chaine__poste--p5 { left: 90%; }

.ps-ia-chaine__noeud {
  position: relative;
  z-index: 10;
  display: flex;
  width: 44px;
  height: 44px;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--accent-display);
  border-radius: var(--r-champ);
  background: var(--fond);
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: 15px;
  line-height: 1;
  color: var(--accent);
  /* Masque, pas ombre : l'anneau a la couleur exacte du fond et sert à
     interrompre la règle graduée autour du poste. La charte interdit les
     ombres décoratives ; celle-ci ne décore rien, elle découpe. */
  box-shadow: 0 0 0 6px var(--fond);
  transform: scale(0);
  transition: transform 0.13s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.ps-ia-chaine[data-vu] .ps-ia-chaine__noeud {
  transform: none;
}

/* Chaque poste s'allume quand la règle l'atteint : sa fraction multipliée par
   la durée du tracé. C'est ce qui donne l'impression que la règle les pose. */
.ps-ia-chaine[data-vu] .ps-ia-chaine__poste--p1 .ps-ia-chaine__noeud { transition-delay: 0.12s; }
.ps-ia-chaine[data-vu] .ps-ia-chaine__poste--p2 .ps-ia-chaine__noeud { transition-delay: 0.36s; }
.ps-ia-chaine[data-vu] .ps-ia-chaine__poste--p3 .ps-ia-chaine__noeud { transition-delay: 0.60s; }
.ps-ia-chaine[data-vu] .ps-ia-chaine__poste--p4 .ps-ia-chaine__noeud { transition-delay: 0.84s; }
.ps-ia-chaine[data-vu] .ps-ia-chaine__poste--p5 .ps-ia-chaine__noeud { transition-delay: 1.08s; }

/* L'onde : un anneau qui s'ouvre et s'efface au moment où le poste se pose. */
.ps-ia-chaine__onde {
  position: absolute;
  inset: 0;
  border: 1px solid var(--accent-display);
  border-radius: var(--r-champ);
  pointer-events: none;
  transform: scale(1);
  opacity: 0;
}

.ps-ia-chaine[data-vu] .ps-ia-chaine__onde {
  animation: ps-ia-onde 0.3s ease-out forwards;
}

.ps-ia-chaine[data-vu] .ps-ia-chaine__poste--p1 .ps-ia-chaine__onde { animation-delay: 0.14s; }
.ps-ia-chaine[data-vu] .ps-ia-chaine__poste--p2 .ps-ia-chaine__onde { animation-delay: 0.38s; }
.ps-ia-chaine[data-vu] .ps-ia-chaine__poste--p3 .ps-ia-chaine__onde { animation-delay: 0.62s; }
.ps-ia-chaine[data-vu] .ps-ia-chaine__poste--p4 .ps-ia-chaine__onde { animation-delay: 0.86s; }
.ps-ia-chaine[data-vu] .ps-ia-chaine__poste--p5 .ps-ia-chaine__onde { animation-delay: 1.10s; }

@keyframes ps-ia-onde {
  from { transform: scale(1);   opacity: 0.45; }
  to   { transform: scale(2.4); opacity: 0; }
}

/* ---- Les losanges de décision ---- */

.ps-ia-chaine__decision {
  position: absolute;
  top: 12px;
  z-index: 10;
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 112px;
  transform: translateX(-50%);
}

.ps-ia-chaine__decision--d1 { left: 20%; }
.ps-ia-chaine__decision--d2 { left: 40%; }
.ps-ia-chaine__decision--d3 { left: 60%; }
.ps-ia-chaine__decision--d4 { left: 80%; }

.ps-ia-chaine__jalon {
  display: block;
  width: 15px;
  height: 15px;
  border: 1px solid var(--accent-display);
  background: var(--fond);
  /* Même masque que les postes : la règle s'interrompt autour du losange. */
  box-shadow: 0 0 0 5px var(--fond);
  transform: rotate(45deg) scale(0);
  transition: transform 0.12s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.ps-ia-chaine[data-vu] .ps-ia-chaine__jalon {
  transform: rotate(45deg);
}

.ps-ia-chaine[data-vu] .ps-ia-chaine__decision--d1 .ps-ia-chaine__jalon { transition-delay: 0.24s; }
.ps-ia-chaine[data-vu] .ps-ia-chaine__decision--d2 .ps-ia-chaine__jalon { transition-delay: 0.48s; }
.ps-ia-chaine[data-vu] .ps-ia-chaine__decision--d3 .ps-ia-chaine__jalon { transition-delay: 0.72s; }
.ps-ia-chaine[data-vu] .ps-ia-chaine__decision--d4 .ps-ia-chaine__jalon { transition-delay: 0.96s; }

/* Le libellé est décoratif : le nom de l'étape est dans la carte, en clair.
   C'est pourquoi il peut passer par l'opacité sans rien cacher. */
.ps-ia-chaine__libelle {
  margin-top: 10px;
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-label);
  line-height: 1.2;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  text-align: center;
  color: var(--accent);
  opacity: 0;
  transform: translateY(6px);
  transition: opacity 0.12s var(--ease-out), transform 0.12s var(--ease-out);
}

.ps-ia-chaine[data-vu] .ps-ia-chaine__libelle {
  opacity: 1;
  transform: none;
}

.ps-ia-chaine[data-vu] .ps-ia-chaine__decision--d1 .ps-ia-chaine__libelle { transition-delay: 0.27s; }
.ps-ia-chaine[data-vu] .ps-ia-chaine__decision--d2 .ps-ia-chaine__libelle { transition-delay: 0.51s; }
.ps-ia-chaine[data-vu] .ps-ia-chaine__decision--d3 .ps-ia-chaine__libelle { transition-delay: 0.75s; }
.ps-ia-chaine[data-vu] .ps-ia-chaine__decision--d4 .ps-ia-chaine__libelle { transition-delay: 0.99s; }

/* ---- Les cartes d'étape ---- */

.ps-ia-chaine__cartes {
  display: none;
}

@media (min-width: 1024px) {
  .ps-ia-chaine__cartes {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    gap: 20px;
    margin-top: 12px;
  }
}

@media (min-width: 1280px) {
  .ps-ia-chaine__cartes { gap: 24px; }
}

.ps-ia-etape {
  display: flex;
  flex-direction: column;
  height: 100%;
  border: 1px solid var(--filet);
  border-radius: var(--r-carte);
  background: var(--fond);
  padding: 16px;
  transition: border-color var(--dur-rapide) var(--ease-out);
}

@media (min-width: 1280px) {
  .ps-ia-etape { padding: 20px; }
}

.ps-ia-etape:hover {
  border-color: var(--accent-display);
}

.ps-ia-etape__nom {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 17px;
  line-height: 1.375;
  color: var(--encre);
}

.ps-ia-etape__duree {
  margin-top: 8px;
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-label);
  line-height: 1;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent);
}

.ps-ia-etape__detail {
  margin-top: 10px;
  font-family: var(--font-corps);
  font-size: 13.5px;
  line-height: 1.65;
  color: var(--texte-2);
}

/* ---- La pile, sous 1024 px ----

   Le rail devient vertical : un filet, un losange, un filet entre chaque
   carte. Le numéro d'étape entre dans la carte, faute de place au-dessus. */

.ps-ia-pile-etapes {
  margin-top: 24px;
}

.ps-ia-pas__lien {
  display: flex;
  flex-direction: column;
  align-items: center;
  margin: 8px 0;
}

.ps-ia-pas__filet {
  display: block;
  width: 1px;
  height: 12px;
  background: var(--filet);
}

.ps-ia-pas__losange {
  display: block;
  width: 11px;
  height: 11px;
  margin: 4px 0;
  border: 1px solid var(--accent-display);
  background: var(--fond);
  transform: rotate(45deg);
}

.ps-ia-etape--pas {
  flex-direction: row;
  gap: 16px;
}

.ps-ia-pas__noeud {
  flex-shrink: 0;
  display: flex;
  width: 36px;
  height: 36px;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--accent-display);
  border-radius: var(--r-champ);
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: 13px;
  line-height: 1;
  color: var(--accent);
}

.ps-ia-pas__corps {
  min-width: 0;
}

.ps-ia-pas__corps .ps-ia-etape__nom {
  font-size: var(--fs-body);
}

.ps-ia-pas__corps .ps-ia-etape__duree {
  margin-top: 4px;
}

.ps-ia-pas__corps .ps-ia-etape__detail {
  margin-top: 8px;
}

/* ---- La légende de figure ---- */

.ps-ia-figure {
  margin-top: 20px;
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-label);
  line-height: 1.5;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--texte-2);
}

@media (prefers-reduced-motion: reduce) {
  .ps-ia-chaine__regle,
  .ps-ia-chaine__noeud,
  .ps-ia-chaine__libelle {
    transform: none;
    opacity: 1;
  }

  .ps-ia-chaine__jalon {
    transform: rotate(45deg);
  }

  .ps-ia-chaine__onde {
    display: none;
  }
}

/* ------------------------------------------- 11. LE SÉLECTEUR D'OFFRES
   « Que voulez-vous construire ? ». Le bloc build/blocks/offres.mjs.

   La section réemployait les cartes de service du gabarit. Sur le hub des
   expertises, dix-neuf offres y devenaient cinq rangées de cartes de 590 px :
   3 532 px, quarante pour cent de la page, pour une liste de liens dont la
   description était invisible tant qu'on ne survolait pas.

   Ici, un répertoire : une colonne par expertise, une ligne par offre, la
   description toujours lue. Les filets viennent du fond de la grille vu au
   travers d'un `gap: 1px` — pas de bordure par cellule, donc pas de règle
   `:last-child` à réécrire à chaque palier de largeur.                      */

.ps-offres__intro {
  max-width: 62ch;
  margin: 18px auto 0;
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: var(--texte-2);
}

/* ---- La grille ---- */

.ps-offres__grille {
  border-block: 1px solid var(--filet);
}

.ps-offres__grille:not(.ps-offres__grille--plate),
.ps-offres__liste--plate {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1px;
}

/* Le filet n'est pas peint par le fond de la grille : une rangée incomplète
   (trois groupes sur deux colonnes) laisserait alors voir un pavé gris à la
   place de la case manquante. Chaque cellule pose donc SON filet, à droite et
   dessous, dans le `gap` de 1 px. Au bord de la grille, ce trait tombe très
   exactement sur celui du cadre de section : même couleur, il s'y confond. */
.ps-offres__groupe,
.ps-offres__liste--plate .ps-offres__item {
  background: var(--fond);
  box-shadow: 1px 0 0 var(--filet), 0 1px 0 var(--filet);
}

.ps-offres__groupe {
  padding: 30px 30px 34px;
}

/* ---- L'en-tête de colonne : l'expertise ---- */

.ps-offres__entete {
  padding-bottom: 18px;
  border-bottom: 1px solid var(--filet);
}

.ps-offres__rang {
  display: flex;
  align-items: center;
  gap: 9px;
  margin: 0 0 10px;
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  line-height: var(--lh-label);
  letter-spacing: var(--tr-label);
  color: var(--texte-2);
}

.ps-offres__puce {
  flex: none;
  width: 8px;
  height: 8px;
  background: var(--accent); /* la puce carrée de la charte, seule couleur ici */
}

.ps-offres__titre {
  margin: 0;
  font-size: var(--fs-h3);
  line-height: var(--lh-h3);
  font-weight: var(--fw-h3);
  /* Le gabarit passe tous les titres en capitales. Ici le registre capitale
     appartient déjà au sur-titre mono ; le nom de l'expertise se lit comme il
     s'écrit, exactement comme dans le méga-menu. */
  text-transform: none;
  letter-spacing: -0.01em;
}

.ps-offres__titre a {
  color: var(--encre);
  text-decoration: none;
}

.ps-offres__titre a:hover,
.ps-offres__titre a:focus-visible {
  color: var(--accent);
}

.ps-offres__accroche {
  margin: 7px 0 0;
  font-size: var(--fs-small);
  line-height: var(--lh-small);
  color: var(--texte-2);
}

/* ---- Les lignes d'offre ---- */

.ps-offres__liste {
  margin: 0;
  padding-left: 0; /* le gabarit pousse toutes les <ul> de 20 px */
  list-style: none;
}

.ps-offres__item {
  margin: 0;
  list-style: none;
}

/* Le filet entre deux lignes d'une même colonne. En grille plate, c'est le
   `gap` qui sépare : aucune bordure à ajouter, et rien à retirer au dernier. */
.ps-offres__liste:not(.ps-offres__liste--plate) .ps-offres__item + .ps-offres__item .ps-offres__lien {
  border-top: 1px solid var(--filet);
}

.ps-offres__lien {
  display: grid;
  grid-template-columns: 1fr auto;
  grid-template-areas:
    "nom fleche"
    "note fleche";
  column-gap: 18px;
  align-items: start;
  padding: 16px 0;
  color: inherit;
  text-decoration: none;
}

.ps-offres__liste--plate .ps-offres__lien {
  height: 100%;
  padding: 24px 30px;
}

.ps-offres__nom {
  grid-area: nom;
  font-size: 1rem;
  line-height: 1.35;
  font-weight: 600;
  color: var(--encre);
  transition: color var(--dur-base) var(--ease-out);
}

/* Deux lignes au plus : la description est LUE, pas coupée au milieu d'un mot
   par le moteur de rendu du gabarit. Le texte complet reste dans le HTML. */
.ps-offres__note {
  grid-area: note;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  margin-top: 5px;
  font-size: var(--fs-small);
  line-height: 1.5;
  color: var(--texte-2);
}

.ps-offres__fleche {
  grid-area: fleche;
  align-self: center;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  flex: none;
  border: 1px solid var(--filet);
  border-radius: var(--r-champ);
  color: var(--texte-2);
  transition: color var(--dur-base) var(--ease-out),
    border-color var(--dur-base) var(--ease-out),
    transform var(--dur-base) var(--ease-out);
}

.ps-offres__lien:hover .ps-offres__nom,
.ps-offres__lien:focus-visible .ps-offres__nom {
  color: var(--accent);
}

.ps-offres__lien:hover .ps-offres__fleche,
.ps-offres__lien:focus-visible .ps-offres__fleche {
  color: var(--accent);
  border-color: var(--accent);
  transform: translateX(3px);
}

/* ---- Paliers ---- */

@media (max-width: 1199px) {
  .ps-offres__groupe {
    padding: 26px 22px 30px;
  }
  .ps-offres__liste--plate .ps-offres__lien {
    padding: 22px;
  }
}

@media (max-width: 991px) {
  .ps-offres__grille:not(.ps-offres__grille--plate),
  .ps-offres__liste--plate {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  /* Sur deux colonnes, trois groupes laissent une case en fin de rangée : le
     dernier prend la largeur entière. `1 / -1` se règle seul quand la grille
     retombe à une colonne, contrairement à `span 2`.

     La règle ne vaut que pour un GROUPE, qui reste lisible sur toute la
     largeur. Une ligne d'offre seule, elle, y serait étirée — son nom d'un
     bord, sa flèche de l'autre : elle garde sa colonne, et le blanc à côté
     se lit comme ce qu'il est, une rangée incomplète. */
  .ps-offres__groupe:nth-child(odd):last-child {
    grid-column: 1 / -1;
  }
}

@media (max-width: 639px) {
  .ps-offres__grille:not(.ps-offres__grille--plate),
  .ps-offres__liste--plate {
    grid-template-columns: minmax(0, 1fr);
  }
  .ps-offres__fleche {
    width: 30px;
    height: 30px;
  }
}


/* ---- 10.11 Les primitives partagées, et la figure des niveaux ----

   Deux primitives du dossier vivent ici parce que la figure est la première à
   les employer, et que la carte d'offre (§ 10.12) les reprend telles quelles :
   le BANDEAU DE SPEC (`.ps-ia-bandeau`) et l'ACTIVATION EN CASCADE. Elles ne
   sont pas propres à la figure ; les renommer plus tard coûterait plus cher
   que de les nommer justes tout de suite.


   Un panneau au filet : bandeau de spec, relevé isométrique en 4/3, trois
   boutons N1 / N2 / N3, légende. Décision figée : la figure reste CLAIRE.
   Le navy de la version d'origine est un bleu, donc l'interdit n° 6, et un
   aplat plein, donc l'interdit n° 4. Le contraste vient de l'encre sur blanc.

   L'ACTIVATION EN CASCADE. Un rang est allumé dès que le niveau courant lui
   est supérieur ou égal : le niveau 2 allume N1 et N2, parce que « chaque
   offre inclut la précédente ». Six couples (niveau, rang) sur neuf sont donc
   actifs. La liste est écrite UNE SEULE FOIS, ci-dessous, et elle ne pose que
   des variables ; tout ce qui change d'aspect les lit. Les cartes d'offre
   (§ 10.12) s'y brancheront avec le même attribut, sans rallonger la liste.

   Le niveau vit dans `data-ps-niveau` sur un conteneur : la figure elle-même
   quand elle est seule, la section des offres quand les cartes le partagent.
   Il est écrit au rendu, pas au chargement : sans JavaScript, la figure est
   juste, seule la bascule au clic manque.

   DEUX CONTENEURS D'ÉTAT NE S'IMBRIQUENT PAS. La cascade n'a pas de notion
   d'ancêtre le plus proche : posée dans une section qui porte déjà un niveau,
   une figure autonome verrait les deux règles s'appliquer, et le niveau le
   plus haut des deux gagnerait. Le JavaScript, lui, sait se limiter aux
   éléments dont il est l'ancêtre le plus proche ; le CSS ne le peut pas. Une
   page pose donc un conteneur par section, et `etat: false` sur la figure
   quand la section porte l'état. */

[data-ps-rang] {
  --ps-niv-dalle: 0.07;
  --ps-niv-trait: var(--encre);
  --ps-niv-ref:   var(--texte-2);
  --ps-niv-nom:   var(--texte-2);
  --ps-niv-fond:  var(--fond);
}

[data-ps-niveau="1"] [data-ps-rang="1"],
[data-ps-niveau="2"] [data-ps-rang="1"],
[data-ps-niveau="2"] [data-ps-rang="2"],
[data-ps-niveau="3"] [data-ps-rang="1"],
[data-ps-niveau="3"] [data-ps-rang="2"],
[data-ps-niveau="3"] [data-ps-rang="3"] {
  --ps-niv-dalle: 0.28;
  --ps-niv-trait: var(--accent-display);
  /* `--accent-grille` et non `--accent` : la tuile active est peinte en
     `--grille`, ou l'accent nu de la branche AI ne passe pas 4,5:1. */
  --ps-niv-ref:   var(--accent-grille);
  --ps-niv-nom:   var(--encre);
  --ps-niv-fond:  var(--grille);
}

/* Le panneau */

.ps-ia-fig__panneau {
  border: 1px solid var(--filet);
  background: var(--fond);
}

/* Le bandeau se replie plutot que de pousser sa carte. `__d` est en
   `flex-shrink: 0` (« Le plus choisi » coupe ne veut rien dire) et `__g` avait
   la min-width automatique d'un item flex, c'est-a-dire sa largeur de contenu
   minimale : les deux ensemble depassaient la carte des que la colonne se
   resserrait. Le `min-width: 0` rend `__g` compressible, le `flex-wrap` lui
   donne une seconde ligne quand la compression ne suffit plus. */
.ps-ia-bandeau {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 10px 20px;
  border-bottom: 1px solid var(--filet);
}

@media (min-width: 640px) {
  .ps-ia-bandeau { padding: 10px 28px; }
}

.ps-ia-bandeau__g,
.ps-ia-bandeau__d {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-label);
  line-height: 1.5;
  text-transform: uppercase;
}

.ps-ia-bandeau__g {
  min-width: 0;
  letter-spacing: 0.18em;
  color: var(--accent);
}

.ps-ia-bandeau__d {
  flex-shrink: 0;
  letter-spacing: 0.16em;
  color: var(--texte-2);
}

/* Le relevé : 480 × 360 à 1440, 440 × 330 à 1024, 348 × 261 à 390. Le viewBox
   de la source est en 5/4 et la zone en 4/3 : le SVG s'y ajuste en « meet »,
   centré, exactement comme en production. */

.ps-ia-fig__zone {
  position: relative;
  aspect-ratio: 4 / 3;
  background: var(--fond);
}

.ps-ia-fig__releve {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
}

.ps-ia-fig__dalle {
  fill-opacity: var(--ps-niv-dalle);
  stroke: var(--ps-niv-trait);
  transition: fill-opacity 300ms var(--ease-out), stroke 300ms var(--ease-out);
}

.ps-ia-fig__points {
  fill: var(--accent-display);
  opacity: 0.7;
}

/* Le sélecteur : trois boutons de largeur égale, séparés par un filet. */

.ps-ia-fig__selecteur {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  border-top: 1px solid var(--filet);
}

.ps-ia-fig__niveau {
  -webkit-appearance: none;
  appearance: none;
  display: block;
  width: 100%;
  margin: 0;
  padding: 16px 12px;
  border: 0;
  border-radius: 0;
  background: var(--ps-niv-fond);
  font-family: var(--font-corps);
  text-align: left;
  cursor: pointer;
  transition: background-color 150ms var(--ease-out);
}

@media (min-width: 640px) {
  .ps-ia-fig__niveau { padding: 16px; }
}

.ps-ia-fig__niveau + .ps-ia-fig__niveau {
  border-left: 1px solid var(--filet);
}

.ps-ia-fig__niveau:hover {
  --ps-niv-fond: var(--grille);
}

.ps-ia-fig__ref {
  display: block;
  margin: 0;
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-label);
  line-height: 1.5;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ps-niv-ref);
  transition: color 150ms var(--ease-out);
}

.ps-ia-fig__nom {
  display: block;
  margin: 6px 0 0;
  font-size: 13.5px;
  font-weight: 600;
  line-height: 1.25;
  color: var(--ps-niv-nom);
  transition: color 150ms var(--ease-out);
}

/* La ligne de détail disparaît sous 640 px : trois colonnes de 116 px ne la
   portent pas. C'est ce que fait la source, et le titre suffit à décider. */
.ps-ia-fig__detail {
  display: none;
  margin: 4px 0 0;
  font-size: var(--fs-label);
  line-height: 1.375;
  color: var(--texte-2);
}

@media (min-width: 640px) {
  .ps-ia-fig__detail { display: block; }
}

/* ---- 10.12 La section des offres, ses cartes et leur volet ----

   La figure des niveaux à gauche, trois cartes à droite, un seul niveau
   partagé : la section porte `data-ps-niveau`, la figure est appelée sans
   état, et les cartes s'activent au survol, au focus et au passage dans la
   bande centrale du viewport.

   La carte introduit trois primitives que la figure n'employait pas : le TAG
   (étiquette encadrée), la SPEC (ligne clé/valeur à conduite pointillée) et
   le VOLET (le dépliable). Elles sont nommées sans référence à la carte, car
   les pages profondes de la phase 4 les reprendront.

   L'ANNEAU de la carte active est un `box-shadow` sans flou ni décalage :
   c'est un second filet de 1 px, pas une ombre. Même statut que les masques du
   rail de méthode au § 10.10 — la charte interdit l'ombre décorative, pas le
   trait. Il marque la carte dont le niveau est EXACTEMENT le niveau courant,
   là où les plateaux de la figure s'allument en cascade : la figure dit « ce
   niveau et les précédents », la carte dit « celle-ci ». */

/* Le principe : trois barres qui montent, une phrase. */

.ps-ia-principe {
  display: flex;
  align-items: center;
  gap: 20px;
  margin-top: 28px;
  max-width: 760px;
  padding: 16px 20px;
  border: 1px solid var(--filet);
  background: var(--fond);
}

@media (min-width: 640px) {
  .ps-ia-principe { padding: 16px 24px; }
}

.ps-ia-principe__barres {
  flex-shrink: 0;
  display: flex;
  align-items: flex-end;
  gap: 6px;
  height: 28px;
}

.ps-ia-principe__barre {
  display: block;
  width: 8px;
  background: var(--accent-display);
  transform: scaleY(0);
  transform-origin: bottom;
  transition: transform 550ms cubic-bezier(0.33, 1, 0.68, 1);
}

.ps-ia-principe__barre--b1 { height: 10px; }
.ps-ia-principe__barre--b2 { height: 18px; transition-delay: 70ms; }
.ps-ia-principe__barre--b3 { height: 28px; transition-delay: 140ms; }

.ps-ia-principe[data-vu] .ps-ia-principe__barre { transform: none; }

.ps-ia-principe__texte {
  font-size: 16.5px;
  font-weight: 500;
  line-height: 1.6;
  color: var(--encre);
}

/* Les deux colonnes. La figure suit la lecture des cartes : elle est collante
   sous l'en-tête à partir de 1024 px. `sticky` dépend de l'`overflow` de tous
   ses ancêtres, et le gabarit en pose plusieurs : vérifié au navigateur. */

.ps-ia-offres__deux {
  display: grid;
  align-items: start;
  gap: 40px;
  margin-top: 48px;
}

/* La colonne des CARTES porte un plancher, et la figure prend ce qui reste.
   Avec `minmax(0, 440px) minmax(0, 1fr)`, la figure prenait ses 440px d'abord
   et les cartes heritaient du reste : a 1 024px de fenetre la grille ne fait
   que 662px, la colonne des cartes tombait donc a 174px et le bandeau comme le
   texte des offres sortaient du cadre (+110px de debordement mesure a 1 024,
   +84 a 1 050, +34 a 1 100). En inversant la priorite, les cartes gardent
   340px et c'est la figure qui se resserre — une illustration se lit encore
   etroite, une offre non. Des 1 200px la figure retrouve ses 440. */
@media (min-width: 1024px) {
  .ps-ia-offres__deux {
    grid-template-columns: minmax(0, 440px) minmax(340px, 1fr);
    gap: 48px;
    margin-top: 64px;
  }

  .ps-ia-offres__figure {
    position: sticky;
    top: 96px;
    align-self: start;
  }
}

@media (min-width: 1280px) {
  .ps-ia-offres__deux {
    grid-template-columns: minmax(0, 480px) minmax(0, 1fr);
    gap: 64px;
  }
}

.ps-ia-offres__cartes {
  display: flex;
  flex-direction: column;
  min-width: 0;
  gap: 32px;
}

.ps-ia-offres__action {
  margin-top: 48px;
}

/* La carte : deux gabarits, un seul corps. */

.ps-ia-offre {
  position: relative;
}

.ps-ia-offre__cadre {
  position: relative;
  border: 1px solid var(--filet);
  background: var(--fond);
  transition: box-shadow 200ms var(--ease-out);
}

[data-ps-niveau="1"] .ps-ia-offre[data-ps-rang="1"] .ps-ia-offre__cadre,
[data-ps-niveau="2"] .ps-ia-offre[data-ps-rang="2"] .ps-ia-offre__cadre,
[data-ps-niveau="3"] .ps-ia-offre[data-ps-rang="3"] .ps-ia-offre__cadre {
  box-shadow: 0 0 0 1px var(--accent);
}

/* La planche à badge : pas de repères de coin, pas d'anneau. Ce n'est pas un
   oubli — c'est le gabarit de l'offre mise en avant, dans la source. */
.ps-ia-offre--pleine {
  border: 1px solid var(--filet);
  background: var(--fond);
}

.ps-ia-offre__coin {
  position: absolute;
  pointer-events: none;
  -webkit-user-select: none;
  user-select: none;
  font-family: var(--font-mono);
  font-size: var(--fs-small);
  line-height: 1;
  color: var(--texte-2);
}

.ps-ia-offre__coin--hg { top: -7px; left: -7px; }
.ps-ia-offre__coin--hd { top: -7px; right: -7px; }
.ps-ia-offre__coin--bg { bottom: -7px; left: -7px; }
.ps-ia-offre__coin--bd { bottom: -7px; right: -7px; }

.ps-ia-offre__corps {
  padding: 24px;
}

@media (min-width: 640px) {
  .ps-ia-offre__corps { padding: 28px; }
}

.ps-ia-offre__nom {
  /* style.css met les titres du gabarit en capitales : c'est un nom propre. */
  text-transform: none;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 26px;
  line-height: 1.25;
  letter-spacing: -0.01em;
  color: var(--encre);
}

.ps-ia-offre__promesse {
  margin-top: 12px;
  font-size: var(--fs-body);
  font-weight: 500;
  line-height: 1.6;
  color: var(--encre);
}

/* Le volet. Le panneau ne quitte JAMAIS le document : il est replié sur sa
   hauteur, et son texte se lit dans la source de la page. Le JavaScript mesure
   la hauteur réelle, la pose en pixels, puis rend la main à `auto` à la fin de
   la transition — sans quoi un contenu qui grandit resterait coupé. */

.ps-ia-volet {
  margin-top: 16px;
}

.ps-ia-volet__bouton {
  -webkit-appearance: none;
  appearance: none;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  min-height: 44px;
  margin: 0;
  padding: 8px 0;
  border: 0;
  border-radius: var(--r-champ);
  background: none;
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-label);
  line-height: 1;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--accent);
  text-align: left;
  cursor: pointer;
  transition: color 150ms var(--ease-out);
}

.ps-ia-volet__bouton:hover {
  color: var(--accent-hover);
}

.ps-ia-volet__plus {
  flex-shrink: 0;
  display: inline-flex;
  transition: transform 260ms cubic-bezier(0.77, 0, 0.175, 1);
}

.ps-ia-volet__bouton[aria-expanded="true"] .ps-ia-volet__plus {
  transform: rotate(45deg);
}

.ps-ia-volet__filet {
  flex-shrink: 0;
  display: block;
  width: 32px;
  height: 1px;
  background: var(--filet);
}

.ps-ia-volet__panneau {
  overflow: hidden;
  height: 0;
  transition: height 260ms cubic-bezier(0.77, 0, 0.175, 1);
}

.ps-ia-volet__contenu {
  padding-top: 8px;
}

.ps-ia-offre__explication {
  font-size: 14.5px;
  line-height: 1.75;
  color: var(--encre);
}

.ps-ia-offre__points {
  padding-bottom: 4px;
}

.ps-ia-offre__points--apres {
  margin-top: 16px;
}

.ps-ia-offre__point {
  display: flex;
  gap: 12px;
  font-size: 14.5px;
  line-height: 1.65;
  color: var(--encre);
}

.ps-ia-offre__point + .ps-ia-offre__point {
  margin-top: 10px;
}

.ps-ia-offre__puce {
  flex-shrink: 0;
  display: block;
  margin-top: 7px;
  width: 6px;
  height: 6px;
  background: var(--accent);
}

/* La ligne de spécification : clé, conduite pointillée, valeur. */

.ps-ia-offre__specs {
  margin-top: 24px;
  padding-top: 8px;
  border-top: 1px solid var(--filet);
}

/* La ligne se replie plutot que de pousser la page. La cle et la valeur sont
   toutes deux en `flex-shrink: 0` — c'est voulu, un intitule de specification
   coupe ne dit plus rien et un montant coupe est un contresens. Sans repli,
   des que cle + valeur depassaient la colonne, la ligne sortait du cadre :
   mesure sur ia-offres.html, +110px a 1024, +84 a 1050, +34 a 1100, et zero a
   partir de 1150. Le defaut vivait entre deux des largeurs mesurees, comme
   celui de l'en-tete.

   Avec `flex-wrap`, la conduite a une base de 0 (`flex: 1`) : la premiere
   ligne accueille donc cle + valeur tant qu'elles tiennent, et la conduite
   grandit pour occuper le reste. Quand elles ne tiennent plus, la valeur passe
   a la ligne et `margin-left: auto` la garde alignee a droite — la lecture de
   gauche a droite est conservee, sur deux lignes au lieu d'une. */
.ps-ia-spec {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 12px;
  padding: 10px 0;
}

.ps-ia-spec__cle {
  flex-shrink: 0;
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-label);
  line-height: 1.4;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--texte-2);
}

/* La conduite garde 24 px même quand la colonne se resserre : sans ce plancher
   elle disparaît à 1024 px et la ligne perd sa lecture de gauche à droite. */
.ps-ia-spec__conduite {
  flex: 1;
  min-width: 24px;
  transform: translateY(-3px);
  border-bottom: 1px dotted var(--filet);
}

.ps-ia-spec__valeur {
  flex-shrink: 0;
  margin-left: auto;   /* seule sur sa ligne apres repli, elle reste a droite */
  font-size: 14.5px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--encre);
}

/* L'étiquette encadrée, et la gouttière de 104 px qui aligne les deux
   paragraphes étiquetés sur la même abscisse. Sans elle, « Données » et
   « Pas pour vous si » n'ont pas la même largeur et les deux textes démarrent
   à quatre lignes d'écart, à deux abscisses différentes. */

.ps-ia-tag {
  display: inline-flex;
  align-items: center;
  padding: 4px 10px;
  border: 1px solid var(--filet);
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-label);
  /* 1,4 et non 1 : l'etiquette « Pas pour vous si » passe a deux lignes dans
     une colonne etroite, et les deux se touchaient. */
  line-height: var(--lh-label);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--texte-2);
}

.ps-ia-offre__donnees {
  display: flex;
  gap: 12px;
  margin-top: 16px;
  padding-top: 20px;
  border-top: 1px solid var(--filet);
}

/* La contre-indication est au même rang que la réassurance, et jamais repliée :
   une réserve qu'il faut déplier pour lire ne produit plus la franchise qui la
   justifie. */
.ps-ia-offre__contre {
  display: flex;
  gap: 12px;
  margin-top: 16px;
}

.ps-ia-offre__etiquette {
  flex-shrink: 0;
  display: block;
  width: 104px;
}

.ps-ia-offre__texte {
  font-size: 13.5px;
  line-height: 1.65;
  color: var(--texte-2);
}

/* Le prix */

.ps-ia-offre__prix {
  margin-top: 20px;
  padding-top: 20px;
  border-top: 1px solid var(--filet);
}

.ps-ia-offre__prefixe {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-label);
  line-height: 1.4;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--texte-2);
}

.ps-ia-offre__montant {
  margin-top: 4px;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 34px;
  /* 1,15 et non 1 : un montant a fourchette (« 12 000 a 18 000 EUR ») se replie
     sur les colonnes etroites. */
  line-height: 1.15;
  font-variant-numeric: tabular-nums;
  color: var(--encre);
}

.ps-ia-offre__suffixe {
  margin-left: 8px;
  font-size: 17px;
  font-weight: 500;
}

.ps-ia-offre__note {
  margin-top: 12px;
  font-size: 13px;
  line-height: 1.6;
  color: var(--texte-2);
}

@media (prefers-reduced-motion: reduce) {
  .ps-ia-principe__barre {
    transform: none;
  }
}


/* ---- 10.13 Le sommaire de page dossier, et la gouttière qui le porte ----

   Les ancres des sections, dans une gouttière de 200 px à gauche du corps,
   collantes sous l'en-tête. C'est la marge d'annotation des sections qui
   change d'emploi : même mono, même filet, même trait de 12 px — il s'allonge
   à 20 px devant l'entrée active, et prend l'accent.

   LA VALEUR DE `top` EST MESURÉE, pas choisie. L'en-tête du site fait 119 px au
   repos et se rétracte de 39 px au défilement : il en reste 80 px de collant à
   partir de 1024 px. 112 px laissent donc 32 px d'air sous lui. Si la hauteur
   de l'en-tête change, trois valeurs sont à reprendre ensemble : cette ligne,
   le `scroll-padding-top` de `propulseo.css`, et la constante HAUT de
   `propulseo-ia.js`.

   LES LIENS DU SOMMAIRE NE SONT PAS DES LIENS ORDINAIRES POUR LE GABARIT.
   `main.js` intercepte tout clic sur `.onepage a[href^="#"]`, ignore le
   `scroll-margin-top` de la cible et n'écrit pas le fragment dans l'adresse.
   Le contournement est dans `propulseo-ia.js`, sur nos liens seuls.

   Le collant a été vérifié au navigateur SUR UNE PAGE RÉELLE, en-tête compris :
   le gabarit pose `overflow-x: hidden` sur `body`, mais toutes ses pages
   portent la classe `overflow-x-visible` qui le neutralise. Sans cette classe —
   sur un banc d'essai écrit à la main, par exemple — `body` devient un
   conteneur de défilement et AUCUN collant ne prend, sans le moindre message
   d'erreur. C'est le piège de cette section. */

.ps-ia-dossier {
  display: grid;
  gap: 40px;
}

@media (min-width: 1024px) {
  .ps-ia-dossier {
    grid-template-columns: 200px minmax(0, 1fr);
    align-items: start;
    gap: 64px;
  }
}

/* Sous 1024 px le sommaire n'est pas rendu : la lecture est linéaire et la
   gouttière n'existe pas. Les ancres restent atteignables par l'URL. */
.ps-ia-sommaire {
  display: none;
}

@media (min-width: 1024px) {
  .ps-ia-sommaire {
    display: block;
    position: sticky;
    top: 112px;
    align-self: start;
  }
}

.ps-ia-sommaire__titre {
  padding-bottom: 12px;
  border-bottom: 1px solid var(--filet);
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-label);
  line-height: 1.4;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--texte-2);
}

.ps-ia-sommaire__liste {
  margin-top: 12px;
}

.ps-ia-sommaire__lien {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 8px 0;
  border-radius: var(--r-champ);
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-label);
  line-height: 1.375;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--texte-2);
  text-decoration: none;
  transition: color 150ms var(--ease-out);
}

.ps-ia-sommaire__lien:hover,
.ps-ia-sommaire__lien:focus-visible,
.ps-ia-sommaire__lien[aria-current="true"] {
  color: var(--accent);
}

.ps-ia-sommaire__trait {
  flex-shrink: 0;
  display: block;
  width: 12px;
  height: 1px;
  background: var(--filet);
  transition: width 200ms var(--ease-out), background-color 200ms var(--ease-out);
}

.ps-ia-sommaire__lien:hover .ps-ia-sommaire__trait {
  background: var(--accent);
}

.ps-ia-sommaire__lien[aria-current="true"] .ps-ia-sommaire__trait {
  width: 20px;
  background: var(--accent);
}


/* ---- 10.14 Les blocs propres au hub Propul AI ----

   Le hero à pièce versée, le relevé compact des trois niveaux, les garanties
   de branchement, les repères de souveraineté et les trois portes d'entrée.
   Rien de neuf dans le vocabulaire : filets, mono en capitales pour les
   étiquettes, sérif pour les titres et les chiffres, accent pour ce qui se
   clique et pour ce qui se compte. */

/* Le hero : la promesse à gauche, la pièce versée à droite. */

.ps-ia-hero__deux {
  display: grid;
  align-items: start;
  gap: 40px;
}

@media (min-width: 1024px) {
  .ps-ia-hero__deux {
    grid-template-columns: minmax(0, 1fr) minmax(0, 380px);
    gap: 64px;
  }
}

@media (min-width: 1280px) {
  .ps-ia-hero__deux {
    grid-template-columns: minmax(0, 1fr) minmax(0, 420px);
  }
}

.ps-ia-hero__kicker {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-label);
  line-height: 1.4;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--accent);
}

.ps-ia-hero__titre {
  margin-top: 20px;
  max-width: 18ch;
  /* style.css met les titres du gabarit en capitales : c'est une phrase. */
  text-transform: none;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 36px;
  line-height: 1.08;
  letter-spacing: -0.02em;
  color: var(--encre);
}

@media (min-width: 640px) {
  .ps-ia-hero__titre { font-size: 50px; max-width: 20ch; }
}

@media (min-width: 1280px) {
  .ps-ia-hero__titre { font-size: 60px; }
}

/* Le second membre de la phrase prend la couleur : c'est lui qui porte la
   proposition, l'autre ne fait que constater. */
.ps-ia-hero__accent {
  color: var(--accent-display);
}

.ps-ia-hero__sous {
  margin-top: 24px;
  max-width: 60ch;
  font-size: 17px;
  line-height: 1.7;
  color: var(--encre);
}

.ps-ia-hero__pastilles {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 24px;
  margin-top: 28px;
}

.ps-ia-hero__pastille {
  position: relative;
  padding-left: 14px;
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-label);
  line-height: 1.5;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--texte-2);
}

.ps-ia-hero__pastille::before {
  content: "";
  position: absolute;
  top: 6px;
  left: 0;
  width: 5px;
  height: 5px;
  background: var(--accent);
}

.ps-ia-hero__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 16px 28px;
  margin-top: 32px;
}

.ps-ia-hero__secondaire {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-label);
  line-height: 1.4;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--accent);
  text-decoration: none;
  border-bottom: 1px solid var(--filet);
  padding-bottom: 3px;
  transition: border-color 150ms var(--ease-out);
}

.ps-ia-hero__secondaire:hover,
.ps-ia-hero__secondaire:focus-visible {
  color: var(--accent);
  border-bottom-color: var(--accent);
}

.ps-ia-hero__mention {
  margin-top: 20px;
  font-size: 13px;
  line-height: 1.6;
  color: var(--texte-2);
}

.ps-ia-hero__piece {
  border: 1px solid var(--filet);
  background: var(--fond);
}

.ps-ia-hero__corps {
  padding: 24px;
}

@media (min-width: 640px) {
  .ps-ia-hero__corps { padding: 28px; }
}

/* Le chiffre est un engagement contractuel, pas une statistique : les quatre
   lignes qui le suivent disent où il est écrit. */
.ps-ia-hero__chiffre {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-display);
  line-height: 1;
  letter-spacing: -0.02em;
  color: var(--accent-display);
}

.ps-ia-hero__legende {
  margin-top: 12px;
  font-size: var(--fs-small);
  line-height: 1.6;
  color: var(--texte-2);
}

.ps-ia-hero__preuves {
  margin-top: 20px;
  padding-top: 16px;
  border-top: 1px solid var(--filet);
}

.ps-ia-hero__preuve {
  position: relative;
  padding-left: 16px;
  font-size: 13.5px;
  line-height: 1.6;
  color: var(--encre);
}

.ps-ia-hero__preuve + .ps-ia-hero__preuve {
  margin-top: 10px;
}

.ps-ia-hero__preuve::before {
  content: "";
  position: absolute;
  top: 8px;
  left: 0;
  width: 6px;
  height: 6px;
  background: var(--accent);
}

/* Le relevé compact : la figure, trois lignes de prix, un renvoi. */

.ps-ia-releve__deux {
  display: grid;
  align-items: start;
  gap: 40px;
  margin-top: 48px;
}

@media (min-width: 1024px) {
  .ps-ia-releve__deux {
    grid-template-columns: minmax(0, 440px) minmax(0, 1fr);
    gap: 48px;
    margin-top: 64px;
  }
}

@media (min-width: 1280px) {
  .ps-ia-releve__deux {
    grid-template-columns: minmax(0, 480px) minmax(0, 1fr);
    gap: 64px;
  }
}

.ps-ia-releve__ligne {
  display: grid;
  gap: 4px 16px;
  padding: 20px 0;
  border-top: 1px solid var(--filet);
}

.ps-ia-releve__ligne:last-child {
  border-bottom: 1px solid var(--filet);
}

/* Les rangs sont posés explicitement : sans eux le placement automatique
   inventerait une rangée par enfant et la ligne ferait quatre étages. */
@media (min-width: 640px) {
  .ps-ia-releve__ligne {
    grid-template-columns: 48px minmax(0, 1fr) auto;
    align-items: baseline;
  }

  .ps-ia-releve__niveau { grid-column: 1; grid-row: 1 / span 2; }
  .ps-ia-releve__nom { grid-column: 2; grid-row: 1; }
  .ps-ia-releve__accroche { grid-column: 2; grid-row: 2; }
  .ps-ia-releve__prix { grid-column: 3; grid-row: 1 / span 2; text-align: right; }
}

.ps-ia-releve__niveau {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-label);
  line-height: 1.5;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--accent);
}

.ps-ia-releve__nom {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 22px;
  line-height: 1.25;
  letter-spacing: -0.01em;
  color: var(--encre);
}

.ps-ia-releve__accroche {
  font-size: 14.5px;
  line-height: 1.6;
  color: var(--texte-2);
}

.ps-ia-releve__prix {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-label);
  line-height: 1.6;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--texte-2);
  white-space: nowrap;
}

.ps-ia-releve__prix strong {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-h3);
  letter-spacing: 0;
  font-variant-numeric: tabular-nums;
  color: var(--encre);
}

.ps-ia-releve__renvoi {
  margin-top: 24px;
}

/* Les garanties du branchement, les repères, les portes : trois grilles de la
   même famille, un numéro ou une étiquette au-dessus d'un texte court. */

.ps-ia-cadrage {
  margin-top: 40px;
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-label);
  line-height: 1.5;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--texte-2);
}

.ps-ia-garanties,
.ps-ia-reperes,
.ps-ia-portes {
  display: grid;
  gap: 24px;
  margin-top: 24px;
}

@media (min-width: 640px) {
  .ps-ia-garanties { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 1024px) {
  .ps-ia-garanties { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 32px; }
  .ps-ia-reperes,
  .ps-ia-portes { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 32px; }
}

.ps-ia-garantie,
.ps-ia-repere,
.ps-ia-porte {
  padding-top: 16px;
  border-top: 1px solid var(--filet);
}

.ps-ia-garantie__texte {
  margin-top: 12px;
  font-size: 14.5px;
  line-height: 1.7;
  color: var(--encre);
}

.ps-ia-repere__ref,
.ps-ia-porte__ref {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-label);
  line-height: 1.5;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--accent);
}

.ps-ia-repere__titre,
.ps-ia-porte__titre {
  margin-top: 10px;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-h3);
  line-height: 1.25;
  color: var(--encre);
}

.ps-ia-repere__detail,
.ps-ia-porte__detail {
  margin-top: 10px;
  font-size: 14.5px;
  line-height: 1.7;
  color: var(--texte-2);
}

.ps-ia-porte__lien {
  margin-top: 16px;
}

/* La condition et l'engagement : une réserve qu'on ne noie pas dans le corps.
   Le filet d'accent à gauche la marque sans l'encadrer. */

.ps-ia-condition,
.ps-ia-engagement {
  margin-top: 32px;
  max-width: 66ch;
  padding-left: 16px;
  border-left: 1px solid var(--accent);
  font-size: 15px;
  line-height: 1.7;
  color: var(--texte-2);
}

/* Les renvois vers une autre page : mono, accent, filet qui s'allume. */

.ps-ia-renvoi,
.ps-ia-releve__renvoi,
.ps-ia-porte__lien {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-label);
  line-height: 1.4;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

.ps-ia-renvoi a,
.ps-ia-releve__renvoi a,
.ps-ia-porte__lien a {
  color: var(--accent);
  text-decoration: none;
  border-bottom: 1px solid var(--filet);
  padding-bottom: 3px;
  transition: border-color 150ms var(--ease-out);
}

.ps-ia-renvoi a:hover,
.ps-ia-renvoi a:focus-visible,
.ps-ia-releve__renvoi a:hover,
.ps-ia-releve__renvoi a:focus-visible,
.ps-ia-porte__lien a:hover,
.ps-ia-porte__lien a:focus-visible {
  color: var(--accent);
  border-bottom-color: var(--accent);
}


/* ------------------------------------ 12. LE TITRE DE BANNIÈRE INTERNE
   Les paliers posés par build/blocks/hero.mjs (`palierTitre`).

   Le gabarit compose ce H1 à 100-120 px sur ordinateur. C'est juste pour
   « Expertises » ; pour « Un site vitrine et une gestion quotidienne qui
   partagent enfin la même source de vérité », c'était quatre lignes de
   120 px — 520 px de titre avant le moindre contenu.

   Une taille par palier de longueur, calée pour que le titre tienne en deux
   lignes au plus jusqu'à 1200 px de fenêtre. La spécificité (cinq classes)
   passe volontairement au-dessus de la règle de propul-desktop.css, qui reste
   la référence pour les titres courts : eux ne changent pas.               */

.wpr-banner-area.breadcrumb .banner-content-area .section-title {
  /* Sans cela, « Propul SEO : sites, ERP et SaaS » laissait « SaaS » seul sur
     la seconde ligne. L'équilibrage répartit les mots entre les deux. */
  text-wrap: balance;
}

/* 84 px et non 92 : à 92 px, « Observatoire du digital des PME » remplissait
   la colonne d'un bord à l'autre et venait buter dans les carrés décoratifs
   de la bannière. */
.wpr-banner-area.breadcrumb .banner-content-area .section-title.ps-titre--moyen {
  font-size: clamp(42px, 6vw, 84px);
}

.wpr-banner-area.breadcrumb .banner-content-area .section-title.ps-titre--long {
  font-size: clamp(38px, 5.2vw, 72px);
}

.wpr-banner-area.breadcrumb .banner-content-area .section-title.ps-titre--tres-long {
  font-size: clamp(34px, 4.3vw, 60px);
}

.wpr-banner-area.breadcrumb .banner-content-area .section-title.ps-titre--fleuve {
  font-size: clamp(30px, 3.5vw, 50px);
}


/* ------------------------- 12bis. L'ÉCHELLE DE TITRES SUIT LE RANG DU H1

   LE DÉFAUT, MESURÉ. Les cinq paliers ci-dessus donnent au H1 une taille qui
   dépend de la LONGUEUR de son texte : 120 px pour « Expertises », 50 px pour
   un titre fleuve. Le H2 de section, lui, ne savait rien de ce choix et
   gardait l'échelle du gabarit — 64 px à 1440. Sur les pages à titre long, le
   titre de section rendait donc plus gros que le titre de la page.

   Relevé du 30/08/2026, 43 pages de l'échantillon × 4 largeurs (390, 768,
   1000, 1440), avant correction :

     H2 ≥ H1  : 149 nœuds, dont 96 sur les pages « tres-long » et 42 « fleuve »
     H3 ≥ H2  : 208 nœuds, dont 110 fois un `h3.h6` à 24 px sous un H2 à 24 px

   Le CSS ne sait pas compter les signes d'un titre. Le rang, lui, est écrit
   sur `<body data-rang>` par build/page.mjs, qui le LIT dans le hero déjà
   composé — même idiome que DECLENCHEURS. La feuille n'a plus qu'à porter une
   échelle par rang.

   POURQUOI DES clamp() ET NON DES PIXELS. Le H1 des quatre rangs longs est
   lui-même en clamp() et descend à son plancher sur téléphone : « fleuve »
   rend 50 px à 1440 mais 30 px à 390. Une échelle en pixels fixes serait
   juste sur grand écran et fausse sur petit. Chaque rang reprend donc la
   forme du clamp de son H1, à ratio constant — 0,62 pour le H2, 0,48 pour le
   H3, 0,40 pour le H4 — et les mêmes planchers 26 / 22 / 20 px pour tous.
   Ces planchers ne sont pas décoratifs : sous 26 px, le H2 rejoignait les
   24 px de `--h6` que portent les titres de carte du gabarit, et la hiérarchie
   s'aplatissait (les 110 nœuds ci-dessus).

   Le rang « court » n'a pas de clamp de H1 à reprendre — le gabarit y tient
   une échelle en marches (32 / 48 / 80 / 100 / 120 px). Son échelle h2/h3/h4
   est calée pour rejoindre EXACTEMENT les valeurs de la charte à 1440 px
   (64 / 48 / 40), qui sont celles rendues aujourd'hui sur ces 949 pages : sur
   grand écran, rien ne bouge là où rien n'était cassé.

   POURQUOI LA REDÉCLARATION NUE `h2 { font-size: var(--h2) }`. Le gabarit
   pose son échelle sur le SÉLECTEUR D'ÉLÉMENT, dans six media queries
   empilées (style.css:529-625) : `h2 { font-size: 36px }` et consorts. Une
   media query n'ajoute aucune spécificité — la même déclaration, écrite dans
   cette feuille qui est chargée en dernier, les couvre toutes les six d'un
   coup. Et parce qu'elle reste à spécificité (0,0,1), elle NE touche PAS les
   titres de carte qui portent leur propre classe (`.h6`, `.ps-offres__titre`,
   `.pk-carte__titre`) : ceux-là gardent leur taille, qui est juste. */

body[data-rang="court"] {
  --h2: clamp(26px, 4.44vw, 64px);
  --h3: clamp(22px, 3.33vw, 48px);
  --h4: clamp(20px, 2.78vw, 40px);
}

body[data-rang="moyen"] {
  /* H1 : clamp(42px, 6vw, 84px) */
  --h2: clamp(26px, 3.72vw, 52px);
  --h3: clamp(22px, 2.88vw, 40px);
  --h4: clamp(20px, 2.4vw, 34px);
}

body[data-rang="long"] {
  /* H1 : clamp(38px, 5.2vw, 72px) */
  --h2: clamp(26px, 3.22vw, 45px);
  --h3: clamp(22px, 2.5vw, 35px);
  --h4: clamp(20px, 2.08vw, 29px);
}

body[data-rang="tres-long"] {
  /* H1 : clamp(34px, 4.3vw, 60px) */
  --h2: clamp(26px, 2.67vw, 37px);
  --h3: clamp(22px, 2.06vw, 29px);
  --h4: clamp(20px, 1.72vw, 24px);
}

body[data-rang="fleuve"] {
  /* H1 : clamp(30px, 3.5vw, 50px) */
  --h2: clamp(26px, 2.17vw, 31px);
  --h3: clamp(22px, 1.68vw, 24px);
  --h4: clamp(20px, 1.4vw, 20px);
}

h2, .h2 { font-size: var(--h2); }
h3, .h3 { font-size: var(--h3); }
h4, .h4 { font-size: var(--h4); }

/* Cinq titres de bloc du gabarit portent leur taille sur un sélecteur de trois
   ou quatre classes, hors de portée de la redéclaration nue ci-dessus. Ils
   sont nommés ici parce que ce sont EUX que la mesure a laissés inversés
   après la première passe : 13 nœuds H2 ≥ H1 et 110 nœuds H3 ≥ H2 restants,
   tous sur ces sélecteurs-là. Le même sélecteur, réécrit dans cette feuille
   chargée en dernier, couvre toutes ses marches de media query d'un coup.

   Deux formes, et la différence compte :

   — sans `min()` quand le gabarit n'a AUCUNE valeur de base hors media query
     (les deux `.section-title` ci-dessous) : leur taille de repos vient déjà
     de `h2`, on ne fait que neutraliser les marches ;
   — avec `min(valeur du gabarit, jeton)` pour les quatre autres : ce sont des
     titres de bloc que le gabarit compose volontairement plus petits que le
     titre de section. La borne les fait DESCENDRE quand l'échelle du rang
     descend, et jamais monter — remonter un titre de carte, c'est un
     débordement sur 2 210 pages. */

.wpr-working-process .working-process-left .section-title-area .section-title,
.approch-area-left .section-title-area .section-title {
  font-size: var(--h2);
}

.why-choose-wrapper .wrapper-header .title,
.wpr-testimonials-area .section-inner .testimonials-content-slider .testimonials-content .top .title {
  font-size: min(32px, var(--h3));
}

.single-approach-area-start .title {
  font-size: min(24px, var(--h3));
}

/* -------------------------- 12ter. LA MESURE : LA LONGUEUR DE LIGNE

   Aucune largeur maximale n'etait posee sur le texte courant. Releve du
   30/08/2026, 43 pages de l'echantillon a 1440px, paragraphes rendant plus de
   90 signes par ligne :

      74 × p.desc                  pire 180 signes dans une boite de 1320px
      10 × p.ps-ann-groupe-desc    pire 103 dans 760px
       6 × p.ps-sim-tableau-note   pire 197 dans 1336px
       6 × p.ps-sim-cta-amorce     pire 161
       6 × p.ps-sim-avertissement  pire 153
       3 × p.ps-sim-methode-reserve  pire 119
       2 × p.ps-ia-constat__detail  pire 101
       1 × p.ps-sim-aide           pire 106
       1 × p.ps-ia-corps           pire  92
     ---
     109 paragraphes

   La borne est posee sur `p`, pas sur ces neuf classes : un paragraphe de
   texte courant qui depasse la mesure est un defaut, quelle que soit sa
   classe, et la regle doit couvrir celui qui sera ecrit demain. Elle est a
   specificite (0,0,1) et ne coute rien aux 1 421 paragraphes qui rendaient
   deja moins large que la mesure — `max-width` ne peut qu'enlever.

   LE CENTRAGE EST LE SEUL EFFET DE BORD, et il est borne. Sur les 591
   paragraphes plus larges que 580px, 38 sont centres : sans marges
   automatiques, la borne les collerait a gauche. Ils tiennent en quatre
   classes, nommees ci-dessous. Le chapeau de banniere avait deja `margin:
   auto` — mais aussi `max-width: max-content`, qui n'est pas une borne : il
   faut la remplacer, pas s'y ajouter. */

p {
  max-width: var(--mesure);
}

.wpr-banner-area.breadcrumb .banner-content-area .desc {
  max-width: min(var(--mesure), 100%);
  margin-inline: auto;
}

.ps-ann-intro,
.ps-offres__intro,
.ps-equipe-intro {
  margin-inline: auto;
}


/* ----------------- 12quater. LA DECORATION VIT DANS LA BANDE DE MARGE

   LE DEFAUT, MESURE. Le damier violet des deux coins de la banniere interne
   est peint PAR-DESSUS le titre et le chapeau : les rectangles de shape-02.svg
   sont en #7128D7 opaque, et l'image est en `z-index: 1` quand le texte n'est
   pas positionne. Le premier paragraphe que lit un prospect y perdait ses
   derniers mots, et certains titres leur premiere lettre.

   Releve du 30/08/2026 — methode : on repeint les carres en rouge pur, puis on
   relit le pixel EXACTEMENT au centre de chaque glyphe du titre et du chapeau.
   Un glyphe qui rend du rouge est un glyphe peint sous le carre. C'est le
   compositeur qui repond, pas une intersection de boites : `elementFromPoint`
   touche la boite de l'image, transparente sur les trois quarts de sa surface,
   et sur-declare largement.

   43 pages de l'echantillon, avant tout correctif de cette session :

        992px : 22 pages, 73 glyphes peints sous un carre
       1440px : 14 pages, 73 glyphes

   La mesure de lecture posee en §12ter (le chapeau borne a 68ch au lieu de
   `max-content`) en a ferme la plus grande part a elle seule. Restaient :

        640px : 13 pages, 26 glyphes      768px : 3 pages, 6 glyphes
        700px :  9 pages, 25 glyphes      992px : 4 pages, 4 glyphes

   LE CORRECTIF, ET POURQUOI CELUI-LA. Le gabarit pose une bande de marge de
   100px en haut et en bas de la banniere, et un carre de 85px de haut sur
   telephone : le carre TENAIT dans la bande, et c'est manifestement le dessin
   voulu. Mais le carre grandit avec la fenetre (85  103  128  141  189px)
   alors que la bande reste a 100px. Passe 576px, la decoration deborde de sa
   bande et entre dans la colonne de texte.

   On retablit la relation : la bande grandit avec la fenetre, et le carre est
   la bande moins une garde de 16px. La decoration ne peut plus, par
   construction, atteindre le texte — quelle que soit la longueur du titre,
   quelle que soit la largeur de la fenetre.

   Les deux ecartees, et pourquoi :

   · REMONTER LE TEXTE AU-DESSUS DU CARRE (z-index). Les carres sont d'un
     violet OPAQUE : le texte cesserait d'etre mange pour devenir illisible.

   · BORNER LA COLONNE DE TEXTE de la largeur du carre. Verifie : ferme bien
     les 60 glyphes, mais a 576px la colonne tombe a 274px et a 390px a 152px —
     un titre de huit signes par ligne. On ne corrige pas un defaut de six
     pages en cassant la banniere des 1 101 autres.

   Le cout est vertical et il est nul jusqu'a 909px de fenetre : en dessous, la
   bande vaut deja 100px. Au-dela elle grandit — +18px de hauteur de banniere a
   992px, +116px a 1440px — et la decoration passe de 220 a 166px de large sur
   grand ecran. C'est le prix du premier paragraphe lisible. */

.wpr-banner-area.breadcrumb .banner-content-area {
  padding-block: clamp(100px, 11vw, 160px);
}

.wpr-banner-area.breadcrumb .banner-shape-area img {
  /* `width: auto` est obligatoire : le gabarit fixe la LARGEUR par media query
     (100  120  150  165  200px). Une hauteur imposee sur une largeur fixe
     ne redimensionne pas l'image, elle l'ecrase. */
  width: auto;
  max-width: none;
  height: calc(clamp(100px, 11vw, 160px) - 16px);
}


/* ------------------------------- 12quinquies. LA GOUTTIERE, EN CONTINU

   Le cadre de page est desormais tenu par un seul jeton, du telephone a
   l'ultra-large — voir `--propul-gouttiere` dans propul-tokens.css pour la
   mesure de la marche qu'il remplace. La largeur maximale, elle, reste dans la
   couche ordinateurs : c'est la seule partie du reglage qui ne concerne que
   les grands ecrans. */

.container {
  width: 100%;
  padding-inline: var(--propul-gouttiere);
  margin-inline: auto;
}


/* --------------- 12sexies. LES TITRES DE CARTE, COUPES A UNE LIGNE

   `.article-blog .infor_name` et `.relatest-post-item .title` etaient bornes a
   UNE ligne par `-webkit-line-clamp: 1`. Sur solutions.html, 7 titres de carte
   sur 8 rendaient « PRENDRE LES RESERVATIONS… » — et la place existait juste
   dessous, vide, entre le titre et le bouton.

   Mesure du 30/08/2026, elements dont le texte est reellement coupe
   (scrollHeight > clientHeight), 43 pages de l'echantillon :

       a.link1  40 a 390px · 40 a 768px · 38 a 1024px · 27 a 1440px
                (jusqu'a 57px de texte cache sous le masque)

   Trois lignes, et non deux : a 1024px la colonne est la plus etroite des
   quatre largeurs mesurees, et deux lignes y coupaient encore. Le clamp reste
   — il empeche un titre aberrant de defoncer la grille — mais il est pose la
   ou il ne coupe plus rien de ce qui est ecrit aujourd'hui.

   Et le bouton descend en pied de carte : sans cela, un titre d'une ligne et
   un titre de deux lignes dans la meme rangee placent leur « Voir » a 29px
   d'ecart. La rangee etait alignee tant que TOUS les titres etaient coupes a
   une ligne — l'alignement tenait par la troncature. */

.article-blog .infor_name,
.relatest-post-item .title {
  -webkit-line-clamp: 3;
  line-clamp: 3;
}

/* `line-height: 1` sur un titre qui passe a la ligne colle les lignes bord a
   bord : les jambages de la premiere touchent les capitales de la seconde. */
.relatest-post-item .title {
  line-height: 1.25;
}

.article-blog {
  display: flex;
  flex-direction: column;
}

.article-blog .blog-content {
  display: flex;
  flex: 1;
  flex-direction: column;
  align-items: flex-start;
}

.article-blog .blog-content > .tf-btn-2 {
  margin-top: auto;
}


/* --------- 12septies. L'ACCORDEON QUI S'OUVRE ET CACHE ENCORE SON TEXTE

   `.award-item.active .left .content .desc` ouvrait sa description a une
   HAUTEUR FIXE — 70px, 80px selon la largeur (style.css:15736, 17609, 17720) —
   avec `overflow: hidden`. Une description plus longue que la boite etait
   coupee net, apres que le visiteur ait clique pour la lire.

   Mesure du 30/08/2026 : on ouvre chaque item a tour de role sur les six
   etudes de cas et on compare hauteur visible et hauteur reelle.

       390px  : 29 descriptions coupees sur 38, 732px de texte cache
       768px  :  4 sur 38, 16px
       1440px :  0 sur 38

   Le bloc est rendu sur 39 pages. `height: auto` ferme les trois largeurs.

   Ce que cela coute : le glissement de 600ms a l'ouverture. `height` ne
   s'anime pas vers `auto`, l'accordeon s'ouvre donc d'un coup. C'est le bon
   sens de l'echange — le glissement etait justement ce qui imposait une
   hauteur fixe, et donc ce qui coupait le texte. */

.award-item.active .left .content .desc {
  height: auto;
}


/* ------------------------- 12octies. L'ACCORDEON DE FAQ, EN `<details>`

   Le gabarit rendait la FAQ en accordeon Bootstrap sur 126 pages, et c'etait
   la SEULE raison pour laquelle `bootstrap.min.js` (79 Ko) y etait encore
   servi. Trois defauts mesures le 30/08/2026 sur agence.html :

   · aucun anneau de focus — `outline: 0px none` sur `.accordion-button`, aux
     deux largeurs. Un visiteur au clavier ne voyait pas ou il etait ;
   · le marqueur « + / — » etait ecrit dans `font-family: "Font Awsome 6 Pro"`
     (avec la faute), qui n'existe nulle part dans le depot : les pastilles
     violettes etaient VIDES. L'affordance ne disait rien ;
   · le filet des items etait simule par un `box-shadow: inset`, que la regle
     d'extinction des ombres de cette feuille eteignait : les items ne se
     distinguaient plus les uns des autres.

   `<details>` regle les trois sans une ligne de JavaScript : le focus est
   natif (et la regle §7 le prend maintenant en charge), le marqueur est
   l'icone maison `plus` qui tourne d'un quart de tour a l'ouverture, et le
   filet est un vrai filet.

   `.accordion-one` reste sur le conteneur : c'est lui qui porte la largeur de
   856px et le centrage du gabarit dans `.wpr-faq-area`. */

.ps-faq__item {
  margin-bottom: 16px;
  border: 1px solid var(--filet);
  border-radius: var(--r-carte);
  background: var(--fond);
  padding: 20px 24px;
}

.ps-faq__q {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  cursor: pointer;
  /* Les deux formes du triangle par defaut : `list-style` pour Firefox et les
     moteurs recents, le pseudo-element webkit pour Safari. */
  list-style: none;
}

.ps-faq__q::-webkit-details-marker {
  display: none;
}

.ps-faq__titre {
  margin: 0;
  font-family: var(--font-corps);
  font-size: 18px;
  font-weight: 600;
  line-height: 1.35;
  color: var(--encre);
  /* Le gabarit met TOUS les Hn en capitales (style.css:215). Une question de
     FAQ se lit en bas de casse : c'est une phrase, pas un intitule. Le bouton
     Bootstrap portait deja ce `text-transform: none` ; le titre le reprend. */
  text-transform: none;
  letter-spacing: 0;
}

@media (max-width: 767px) {
  .ps-faq__titre { font-size: var(--fs-body); }
  .ps-faq__item { padding: 16px 18px; }
}

/* Le marqueur : le carre accent du gabarit, mais avec un trait dedans. */
.ps-faq__marque {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  border-radius: var(--r-champ);
  background: var(--accent);
  color: var(--fond);
}

.ps-faq__marque svg {
  width: 18px;
  height: 18px;
  transition: transform var(--dur-base) var(--ease-out);
}

/* Le plus devient une croix : le meme trait dit « ouvrir » puis « refermer ».
   C'est le TRAIT qui tourne, pas la pastille — sinon le carre devient un
   losange et la rangee de marqueurs perd son alignement. */
.ps-faq__item[open] .ps-faq__marque svg {
  transform: rotate(45deg);
}

.ps-faq__r {
  padding-top: 16px;
}

.ps-faq__r .desc {
  margin: 0;
  color: var(--encre);
}


/* ---------------------- 12nonies. LES ETATS DES COMPOSANTS (bloc d3)

   1. LA PILULE BLANCHE DU GABARIT. `.tf-btn-2` — les treize boutons « Voir »
      de solutions.html, et tous les boutons de carte du site — etait rendu en
      `border-radius: 99px`, fond blanc sur page blanche, avec quatre ombres
      empilees dont une interne pour simuler un relief. La charte dit
      l'inverse, mot pour mot : rayon 6px, jamais de pilule, jamais d'ombre
      decorative, une carte se detache par son filet. C'est exactement le
      bouton contour deja defini pour `.wpr-btn.btn-white` : on lui donne la
      meme forme, pour que le meme role ait la meme geometrie.

   2. L'ETAT PRESSE N'EXISTAIT SUR AUCUN COMPOSANT. Le jeton `--accent-presse`
      etait ecrit dans la charte et reference NULLE PART. Un bouton qui ne
      repond pas a l'appui laisse croire que le clic n'a pas pris — c'est le
      retour le moins cher et le plus attendu de tous. */

.tf-btn-2 {
  border-radius: var(--r-bouton);
  border: 1px solid var(--filet);
  background: var(--fond);
  color: var(--encre);
  box-shadow: none;
}

.tf-btn-2:hover {
  border-color: var(--encre);
  color: var(--encre);
  background: var(--fond);
}

.tf-btn-2:active,
.wpr-btn.btn-white:active {
  border-color: var(--accent-presse);
  color: var(--accent-presse);
}

.wpr-btn.btn-primary:active,
.wpr-btn:not(.btn-white):active {
  background: var(--accent-presse);
  color: var(--fond);
}

.ps-faq__q:active .ps-faq__marque,
.ps-ann-groupe-tete:active .ps-ann-groupe-titre {
  color: var(--accent-presse);
}


/* ------------------- 12decies. TROIS CONTRASTES QUE axe NE VOIT PAS

   axe-core ne calcule pas un contraste quand le fond est une image ou quand il
   ne peut pas composer la pile : les trois defauts ci-dessous ne sont donc
   ressortis d'aucune des 86 passes, et ils sont pourtant les plus visibles des
   trois lots de couleur. Ils ont ete mesures autrement — couleur du texte et
   fond compose, releves au navigateur sur neuf pages, le 30/08/2026.

   1. LE SOUS-TITRE DE CARTE DE REALISATION, BLANC SUR BLANC. `.product-intro
      .top .desc` est en `rgba(255, 255, 255, .7)`, herite du gabarit ou la
      carte etait sombre ; la charte a aplati `.product-intro` en blanc a 94 %.
      Contraste mesure : 1:1. Le texte est litteralement invisible, sur 14
      elements de la seule page d'accueil. Il reprend le texte second de la
      charte, qui est fait pour le blanc.

   2. LA CITATION DU TEMOIGNAGE, TEXTE SECOND SUR PLANCHE SOMBRE. 3,09:1
      mesures. Voir `--texte-2-sombre` dans propul-tokens.css : la planche
      sombre et sa composition en angle sont des decisions de contraste qu'on
      ne touche pas, c'est la couleur du texte qui doit s'y adapter.

   3. LE MARQUEUR « + / — » DE L'ACCORDEON DES AVIS, VIOLET SUR VIOLET. La
      retokenisation a pose `color: var(--accent)` ET `background:
      var(--accent)` sur `.toggle` (style.css) : 1:1, le glyphe n'existe plus.
      C'est la meme faute que la police « Font Awsome 6 Pro » de l'accordeon de
      FAQ — une affordance qui ne dit rien —, et elle vit sur 39 pages. */

.wpr-project-area .slide .slide-content .product-intro .top .desc,
.project-wrapper .slide-content .product-intro .top .desc,
.project-wrapper2 .slide-content .product-intro .top .desc,
.wpr-next-project-area .section-inner .section-mid-area .slide .slide-content .product-intro .top .desc {
  color: var(--texte-2);
}

.wpr-testimonials-area .section-inner .testimonials-content-slider .testimonials-content .top .desc,
.wpr-testimonials-area .section-inner .testimonials-content-slider .testimonials-content blockquote p {
  color: var(--texte-2-sombre);
}

.toggle {
  color: var(--fond);
}


/* --------- 12undecies. L'ETAT D'ERREUR DU FORMULAIRE, AVANT L'ENVOI

   Le formulaire de contact n'avait AUCUN etat d'erreur avant l'envoi, sur les
   1 105 pages qui le portent. Il en avait un apres — `#form-messages.error`
   rend bien `--erreur`, l'ANNEXE l'a verifie — mais le visiteur devait envoyer
   pour apprendre que son adresse etait mal ecrite.

   Pire : le formulaire et le serveur ne disaient pas la meme chose. `api/
   contact.mjs` refuse un nom vide, un e-mail vide ou invalide, et un message de
   moins de dix signes ; le gabarit ne marquait `required` que le message, et
   n'annoncait aucune longueur minimale. Les trois contraintes sont maintenant
   ecrites dans le formulaire, et `MIN_MESSAGE` est LU dans le module de l'API
   plutot que recopie — deux ecritures d'un meme fait divergent le jour ou l'une
   bouge.

   `:user-invalid` et non `:invalid` : `:invalid` est vrai des le chargement,
   sur un formulaire vide que personne n'a touche, et peindrait la page en rouge
   avant le premier caractere. `:user-invalid` n'est vrai qu'apres que le
   visiteur a saisi puis quitte le champ — c'est exactement « l'etat d'erreur
   avant l'envoi » qui manquait. La ou il n'est pas reconnu, le formulaire se
   comporte comme avant : rien ne casse, il manque seulement le retour. */

#contact-form input:user-invalid,
#contact-form textarea:user-invalid {
  border-color: var(--erreur);
  background: color-mix(in srgb, var(--erreur) 6%, var(--fond));
}

#contact-form input:user-invalid:focus-visible,
#contact-form textarea:user-invalid:focus-visible {
  outline-color: var(--erreur);
}

/* Le libelle du champ fautif reprend la couleur d'erreur : sur un formulaire a
   trois champs, la bordure seule oblige a chercher lequel est en cause. */
#contact-form .single-input:has(:user-invalid) label {
  color: var(--erreur);
}


/* ------ 12duodecies. `line-height: 1` SUR DU TEXTE QUI PASSE A LA LIGNE

   Un interligne egal au corps colle les lignes bord a bord : les jambages de la
   premiere touchent les capitales de la seconde. Sur une ligne unique c'est
   sans consequence — une pastille, un montant —, et c'est pourquoi la regle ne
   vise QUE le texte qui se replie reellement.

   Mesure du 30/08/2026, elements dont l'interligne vaut au plus 1,05 fois le
   corps ET qui rendent au moins deux lignes, sur 6 pages :

     349 elements a 390px · 426 a 768px · 798 a 1440px

   Ils tiennent en ONZE regles du gabarit, toutes en `line-height: 1`, relevees
   par CDP sur les elements fautifs eux-memes. Chacune reprend ici l'interligne
   de la charte qui correspond a son role — c'est la meme echelle que celle des
   tailles, et elle existait deja sans etre lue :

     texte courant (listes, mentions)  --lh-small   1,6
     libelles et intitules             --lh-label   1,4
     titres de bloc                    --lh-h3      1,3
     texte d'affichage (piste geante)  --lh-display 1,08                   */

.wpr-services-area .section-bottom-content .service-wrapper .content .bottom ul li,
.why-choose-wrapper .wrapper-list li,
.pricing-wrapper .pricing-body ul li,
.wpr-footer-area .copyright-area p {
  line-height: var(--lh-small);
}

.pk-link,
.wpr-services-area .section-bottom-content .service-wrapper .content .top .tag,
.wpr-contact-area .section-inner .left-content-area .get-in-touch .sub-title,
.wpr-contact-area .section-inner .left-content-area .location-area .sub-title,
.wpr-btn {
  line-height: var(--lh-label);
}

.why-choose-wrapper2 .title,
.pricing-wrapper .pricing-header .plan-type .h6 {
  line-height: var(--lh-h3);
}

.services-details-banner .section-inner .service-overview .feature-wrapper-area .feature-box .top .text {
  line-height: var(--lh-label);
}

.wpr-marquee-area .section-inner .title {
  line-height: var(--lh-display);
}


/* ---------------------------------------------------------------- HERO ACCUEIL
   Repli de taille des deux mots geants.

   La bande du hero fait 800 px en overflow:hidden et le SVG central est
   incompressible (303 px) : il reste environ 620 px par mot, soit neuf signes a
   120 px. Au dela, le mot passe a la ligne et le bas du hero est rogne, sans
   aucun message au build. build/blocks/hero.mjs pose ces classes des que le plus
   long des deux mots depasse huit signes. Le desktop surcharge la taille en
   clamp() (propul-desktop.css) : ces regles reprennent la meme forme pour rester
   au-dessus par ordre de cascade. */

.wpr-banner-area .banner-content-area .section-title.ps-ia-hero--long {
  font-size: clamp(72px, 6.2vw, 96px);
}

.wpr-banner-area .banner-content-area .section-title.ps-ia-hero--tres-long {
  font-size: clamp(56px, 5vw, 78px);
}

/* -------------------------------------------------------- TEMOIGNAGES : TITRE
   Le bloc Agenio n'avait aucune zone de titre : ses seuls titres etaient les six
   noms de clients, en <h2>. Ces noms descendus au rang qui est le leur, la
   section se retrouvait sans titre et ses <h3> sans parent. La zone reutilise
   .section-title-area, qui porte deja toute sa typographie ; il ne reste que
   l'espacement propre a ce bloc, dont le .section-inner colle ses swipers au
   bord haut. */

.wpr-testimonials-area .section-inner .ps-ia-temoignages__titre {
  margin-bottom: 48px;
  max-width: 720px;
}

@media (max-width: 767px) {
  .wpr-testimonials-area .section-inner .ps-ia-temoignages__titre {
    margin-bottom: 32px;
  }
}

/* ===================================== 15. ACCUEIL — DIPTYQUE DU GROUPE

   Composition A validée pour le premier bloc « Le groupe » de l'accueil :
   le chapeau répond au titre dans l'en-tête, puis le visuel et les trois
   preuves forment deux panneaux de même importance. La classe est opt-in :
   les autres pages qui réutilisent `aboutArea` conservent le gabarit. */

.wpr-about-area.ps-about--diptyque .section-inner .section-top-area {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(260px, 0.85fr);
  gap: clamp(32px, 7vw, 96px);
  align-items: end;
}

.wpr-about-area.ps-about--diptyque .section-inner .section-top-area .section-title-area {
  max-width: none;
}

.ps-about-diptyque__intro {
  max-width: 55ch;
  margin: 0;
  color: var(--texte-2);
}

.wpr-about-area.ps-about--diptyque .section-inner .about-bottom-content {
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(320px, 0.8fr);
}

.wpr-about-area.ps-about--diptyque .section-inner .about-bottom-content .right-area {
  min-width: 0;
  border-right: 1px solid var(--filet);
}

.wpr-about-area.ps-about--diptyque .section-inner .about-bottom-content .right-area .image-area {
  height: 100%;
  min-height: 480px;
}

.wpr-about-area.ps-about--diptyque .section-inner .about-bottom-content .right-area .image-area > img:first-child {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.wpr-about-area.ps-about--diptyque .section-inner .about-bottom-content .left-area {
  max-width: none;
}

.wpr-about-area.ps-about--diptyque .section-inner .about-bottom-content .left-area ul li.with-icon {
  min-height: 160px;
}

@media (max-width: 860px) {
  .wpr-about-area.ps-about--diptyque .section-inner .section-top-area,
  .wpr-about-area.ps-about--diptyque .section-inner .about-bottom-content {
    grid-template-columns: 1fr;
  }

  .wpr-about-area.ps-about--diptyque .section-inner .section-top-area {
    gap: 20px;
  }

  .wpr-about-area.ps-about--diptyque .section-inner .about-bottom-content .right-area {
    border-right: 0;
    border-bottom: 1px solid var(--filet);
  }

  .wpr-about-area.ps-about--diptyque .section-inner .about-bottom-content .right-area .image-area {
    min-height: 340px;
  }
}

@media (max-width: 540px) {
  .wpr-about-area.ps-about--diptyque .section-inner .about-bottom-content .right-area .image-area {
    min-height: 260px;
  }

  .wpr-about-area.ps-about--diptyque .section-inner .about-bottom-content .left-area ul li.with-icon {
    min-height: 136px;
  }
}


/* ---- 10.15 Le commutateur d'univers ----

   Trois libelles dans la barre haute : Propul, Propul SEO, Propul AI. Celui de
   la page courante est en accent et n'est pas un lien — on ne propose pas
   d'aller ou l'on est deja ; les deux autres sont en texte secondaire. C'est le
   seul endroit du site ou les trois univers se voient ensemble, et il ne change
   jamais de place : c'est ce qui en fait un reperage et non une navigation de
   plus.

   Il reprend exactement la typographie du selecteur de langue (§ 9) — mono,
   11 px, capitales, interlettrage large — et se pose en miroir de lui : la
   langue est collee a droite de la barre haute, l'univers a gauche. Les deux
   sont en absolu pour ne pas deplacer le texte centre que le gabarit place
   entre eux ; .pk-topbar__inner porte deja position: relative
   (propul-header.css). Les valeurs d'ecart sont celles du § 9, a l'identique,
   pour que les deux retraits restent symetriques. */

.ps-univers {
  position: absolute;
  left: clamp(10px, 3.5vw, 31.25px);
  top: 50%;
  transform: translateY(-50%);
  display: flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-label);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  white-space: nowrap;
}

/* Le filet qui separe les univers : la meme valeur que toutes les separations
   du site, jamais un point median ni une barre oblique tapes en dur. */
.ps-univers > * + *::before {
  content: '';
  display: inline-block;
  width: 1px;
  height: 0.85em;
  margin-right: 8px;
  vertical-align: -0.1em;
  background: var(--filet);
}

.ps-univers__actif {
  color: var(--accent);
}

.ps-univers__lien {
  color: var(--texte-2);
  text-decoration: none;
  transition: color var(--dur-rapide) var(--ease-out);
}

.ps-univers__lien:hover,
.ps-univers__lien:focus-visible {
  color: var(--accent);
}

/* La barre haute n'a pas la largeur de porter les trois a la fois sur tous les
   ecrans. Mesure au navigateur sur la page rendue : le commutateur occupe
   254 px, la mention d'etablissement 572 px, et la barre n'existe qu'a partir de
   992 px. A 1440 px il reste 149 px entre les deux, a 1280 px 69 px, a 1200 px
   29 px seulement — deux runs de mono en capitales aussi proches se lisent
   comme un seul. Le seuil est donc a 1280.

   C'est la mention qui s'efface, pas le commutateur : elle est une precision,
   il est un reperage. Ce qu'elle dit d'essentiel — l'etablissement a Lisbonne —
   est repris par la ligne de copyright, en bas de la meme page.

   visibility plutot que display : la barre garde sa hauteur, donc l'en-tete
   garde la sienne, et les trois valeurs qui se tiennent (scroll-padding-top,
   le top du sommaire collant, la constante HAUT de propulseo-ia.js) restent
   justes. */
@media (max-width: 1279.98px) {
  .pk-topbar__texte {
    visibility: hidden;
  }
}

/* Le gabarit masque la barre haute sous 992 px. Le tiroir mobile porte donc le
   second commutateur, en tete de son corps : changer d'univers reencadre tout
   le menu qui suit, la place est donc au-dessus de lui — la ou le selecteur de
   langue, qui ne reencadre rien, se range en bas. */
.ps-univers--tiroir {
  position: static;
  transform: none;
  justify-content: flex-start;
  flex-wrap: wrap;
  row-gap: 8px;
  padding: 0 0 16px;
  margin-bottom: 8px;
  border-bottom: 1px solid var(--filet);
}


/* ---- 10.16 Les colonnes du pied de page ----

   Le gabarit Agenio n'a pas de pied en colonnes : il n'a qu'une rangee de liens
   a pastilles carrees, puis le copyright. La grille est donc un bloc porte,
   rendu par chrome.mjs au-dessus de .footer-top et seulement quand
   site.footer.colonnes existe — sans la donnee, le pied est exactement celui
   d'avant.

   Trois colonnes traversent tout le site ; la quatrieme est celle de l'univers
   ou l'on se trouve, substituee au rendu par page.mjs. Un visiteur des pages AI
   trouve donc au pied les pages AI, la ou un visiteur des pages maison trouve
   le sommaire du groupe.

   La rangee .footer-top qui suit ne porte plus que les deux pages legales : ses
   cinq rubriques sont ici, et les repeter deux fois dans le meme pied n'aide
   personne. */

.wpr-footer-area .ps-pied-colonnes {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 32px;
  padding-block: 48px 8px;
}

.wpr-footer-area .ps-pied-colonnes__titre {
  margin: 0 0 16px;
  color: var(--texte-2);
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-label);
  letter-spacing: 0.2em;
  text-transform: uppercase;
}

.wpr-footer-area .ps-pied-colonnes__col ul {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

/* Le lien nu, souligne au survol seulement : quatre colonnes toutes soulignees
   feraient une trame. C'est l'inverse de la rangee sociale, qui est courte et
   porte son soulignement en permanence. */
.wpr-footer-area .ps-pied-colonnes__col ul li a {
  color: var(--encre);
  font-size: 15px;
  line-height: 1.5;
  text-decoration: none;
  transition: color var(--dur-rapide) var(--ease-out);
}

.wpr-footer-area .ps-pied-colonnes__col ul li a:hover,
.wpr-footer-area .ps-pied-colonnes__col ul li a:focus-visible {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* Quatre colonnes ne tiennent plus sous 992 px : elles passent a deux, puis a
   une seule sous 560 px. A une colonne la grille redevient une liste, et les
   titres de rubrique sont ce qui la garde lisible. */
@media (max-width: 991.98px) {
  .wpr-footer-area .ps-pied-colonnes {
    grid-template-columns: repeat(2, 1fr);
    gap: 32px 24px;
    padding-block: 40px 8px;
  }
}

@media (max-width: 559.98px) {
  .wpr-footer-area .ps-pied-colonnes {
    grid-template-columns: 1fr;
    gap: 28px;
    padding-block: 32px 8px;
  }
}


/* La rangee .footer-top ne porte plus que les deux pages legales : ses cinq
   rubriques sont passees dans les colonnes ci-dessus. Le gabarit l'avait
   dessinee pour sept liens etales sur toute la largeur — 24 px, gras,
   justify-content: space-between. A deux liens, cela donne deux titres plantes
   a chaque bout du pied, plus gros que les colonnes qu'ils suivent : mesure au
   navigateur, c'etait le plus gros texte de tout le pied de page.

   Ils reprennent donc le calibre des liens de la rangee sociale, groupes a
   gauche, et la pastille carree du gabarit redevient une separation au lieu
   d'un ecart de 12 px entre deux extremites. */

.wpr-footer-area .footer-top ul {
  justify-content: flex-start;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
}

.wpr-footer-area .footer-top ul li a {
  font-size: 15px;
  font-weight: 500;
}

.wpr-footer-area .footer-top ul li.square-dot {
  width: 4px;
  height: 4px;
}

/* -------------------------------------------- PREMIER ECRAN : REPLI VISIBLE
   WOW.js pose `visibility: hidden` sur chaque .wow et ne la leve qu'au moment
   d'animer. Si le script ne s'execute pas — erreur JS, reseau coupe sur un
   fichier, extension qui bloque — le contenu reste invisible pour toujours,
   sans le moindre message. Le hero de l'accueil en depend entierement.

   Ces deux regles rendent le repli explicite : sans JS, l'animation se joue en
   CSS et se termine visible ; avec JS, WOW reprend la main avant qu'elle ne
   compte. Et quiconque demande moins de mouvement voit la page directement. */

@media (prefers-reduced-motion: reduce) {
  .wow,
  .wpr-text-anime,
  [data-wow-delay] {
    animation: none !important;
    transition: none !important;
    visibility: visible !important;
    opacity: 1 !important;
    transform: none !important;
  }

  .preloader {
    display: none !important;
  }
}

/* Le repli sans JavaScript n'est pas ici : il vit dans un <noscript><style>
   emis par build/page.mjs, seule forme qui garantisse qu'il ne s'applique
   jamais quand WOW.js tourne. */


/* ---- 10.17 Les pages profondes de l'univers Propul AI ----

   Le gabarit dossier : bandeau de reference, fil d'Ariane, H1, chapeau, corps
   en sections numerotees, et le bloc « aller plus loin » qui porte le maillage.

   Il ne redefinit NI la grille NI le sommaire : le § 10.13 les tient deja
   (`.ps-ia-dossier` a deux colonnes, le sommaire collant a 112 px, son repli
   sous 1024 px). Ce qui suit est le corps du document, et lui seul.

   LA MESURE DE LIGNE EST LA REGLE DE LA SECTION. Une page profonde fait deux
   mille mots ; au-dela de 70 signes par ligne, l'oeil rate le retour a la
   ligne suivante. Toute la prose est donc bornee en `ch`, jamais en pixels :
   la borne suit la police, pas l'ecran. */

.ps-ia-dossier__tete {
  padding-bottom: 40px;
  border-bottom: 1px solid var(--filet);
}

/* Le bandeau de reference documentaire : PAI-DOC-11 · 2026-07 · Confiance.
   Le code porte l'accent, les autres items sont des precisions. Nom distinct
   de `.ps-ia-bandeau` (§ 10.11), qui est le bandeau de spec des figures. */
.ps-ia-ref {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  margin: 0 0 20px;
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-label);
  letter-spacing: 0.2em;
  text-transform: uppercase;
}

.ps-ia-ref__code {
  color: var(--accent);
}

.ps-ia-ref__item {
  color: var(--texte-2);
}

/* Le meme filet de separation que partout : jamais un point median tape. */
.ps-ia-ref > * + *::before {
  content: '';
  display: inline-block;
  width: 1px;
  height: 0.85em;
  margin-right: 10px;
  vertical-align: -0.1em;
  background: var(--filet);
}

/* Le fil d'Ariane visible. Le dernier maillon n'est pas un lien : on ne
   propose pas d'aller ou l'on est deja, meme regle que le commutateur
   d'univers au § 10.15. */
.ps-ia-fil {
  margin-bottom: 24px;
}

.ps-ia-fil ol {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin: 0;
  padding: 0;
  list-style: none;
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.ps-ia-fil li + li::before {
  content: '';
  display: inline-block;
  width: 10px;
  height: 1px;
  margin-right: 8px;
  vertical-align: 0.3em;
  background: var(--filet);
}

.ps-ia-fil a {
  color: var(--texte-2);
  text-decoration: none;
  transition: color var(--dur-rapide) var(--ease-out);
}

.ps-ia-fil a:hover,
.ps-ia-fil a:focus-visible {
  color: var(--accent);
}

.ps-ia-fil [aria-current] {
  color: var(--encre);
}

/* Le H1 d'une page profonde porte plus de mots que le titre d'une section :
   la borne de 24ch du § 10 le couperait trop tot. */
.ps-ia-dossier__h1 {
  max-width: 20ch;
  font-size: 44px;
}

@media (min-width: 640px) {
  .ps-ia-dossier__h1 {
    max-width: 24ch;
    font-size: var(--fs-display);
  }
}

/* Le segment accentue du H1 : la meme grammaire que le TitreAccentue de la
   source, l'accent sur la partie qui porte la promesse. */
.ps-ia-titre__accent {
  color: var(--accent);
}

/* Le chapeau : deux ou trois phrases AUTONOMES, qui repondent seules a la
   requete. C'est ce qui les rend citables par un moteur de reponse, et c'est
   pourquoi chacune est un paragraphe et non une virgule de la precedente. */
.ps-ia-chapeau {
  margin: 20px 0 0;
  max-width: 62ch;
  font-family: var(--font-corps);
  font-size: 19px;
  line-height: 1.6;
  color: var(--texte-2);
}

.ps-ia-chapeau:first-of-type {
  margin-top: 28px;
  color: var(--encre);
}

/* --- Le corps, section par section --- */

.ps-ia-section {
  padding-top: 48px;
}

.ps-ia-section__num {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
  margin: 0 0 14px;
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-label);
  letter-spacing: 0.2em;
  text-transform: uppercase;
}

.ps-ia-section__rang {
  color: var(--accent);
}

.ps-ia-section__libelle {
  color: var(--texte-2);
}

.ps-ia-section__titre {
  margin: 0;
  max-width: 30ch;
  /* style.css met les h2 du gabarit en capitales : ce titre est une phrase. */
  text-transform: none;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-h2);
  line-height: 1.2;
  letter-spacing: -0.01em;
  color: var(--encre);
}

@media (min-width: 640px) {
  .ps-ia-section__titre {
    font-size: 32px;
  }
}

.ps-ia-section__p {
  margin: 20px 0 0;
  max-width: 68ch;
  font-family: var(--font-corps);
  font-size: 17px;
  line-height: 1.75;
  color: var(--encre);
}

/* --- Aller plus loin : le maillage --- */

.ps-ia-plus {
  margin-top: 64px;
  padding-top: 32px;
  border-top: 1px solid var(--filet);
}

.ps-ia-plus__titre {
  margin: 0 0 24px;
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-label);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--texte-2);
}

.ps-ia-plus__liste {
  display: grid;
  gap: 28px;
  margin: 0;
  padding: 0;
  list-style: none;
}

@media (min-width: 768px) {
  .ps-ia-plus__liste {
    grid-template-columns: repeat(3, 1fr);
    gap: 32px;
  }
}

.ps-ia-plus__item {
  padding-top: 16px;
  border-top: 1px solid var(--filet);
}

.ps-ia-plus__lien {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 18px;
  line-height: 1.3;
  color: var(--encre);
  text-decoration: none;
  transition: color var(--dur-rapide) var(--ease-out);
}

.ps-ia-plus__lien:hover,
.ps-ia-plus__lien:focus-visible {
  color: var(--accent);
}

/* La description n'est pas une politesse : elle dit pourquoi ce lien-la suit
   cette page-la. Un renvoi sans raison est un lien qu'on suit a l'aveugle. */
.ps-ia-plus__desc {
  margin: 8px 0 0;
  font-family: var(--font-corps);
  font-size: 15px;
  line-height: 1.6;
  color: var(--texte-2);
}


/* ---- 10.18 La figure « ou vivent vos donnees » ----

   Extension de la Fig. 03 du hub : la meme chaine a trois noeuds, plus le
   releve brique par brique que le hub replie, plus la ligne d'exclusion.

   L'EXCLUSION EST RENDUE A PART, avec son etiquette. « Aucune donnee client
   vers une API americaine » est une clause contractuelle, pas une puce de
   liste : la noyer parmi les briques la ferait lire comme un detail
   technique. La decision figee dit de ne jamais la bouger. */

.ps-ia-fig--donnees {
  margin: 28px 0 0;
  padding: 0;
  border: 1px solid var(--filet);
}

.ps-ia-fig__entete {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 8px;
  margin: 0;
  padding: 12px 20px;
  border-bottom: 1px solid var(--filet);
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-label);
  letter-spacing: 0.2em;
  text-transform: uppercase;
}

.ps-ia-fig__entete-g {
  color: var(--encre);
}

.ps-ia-fig__entete-d {
  color: var(--texte-2);
}

/* La chaine : trois noeuds, separes par un trait horizontal a partir de
   640 px, empiles en dessous. Le trait est un filet, pas une fleche dessinee :
   le sens de lecture suffit a dire la direction. */
.ps-ia-fig__chaine {
  display: grid;
  gap: 20px;
  margin: 0;
  padding: 24px 20px;
  list-style: none;
}

@media (min-width: 640px) {
  .ps-ia-fig__chaine {
    grid-template-columns: repeat(3, 1fr);
    gap: 28px;
    align-items: start;
  }

  .ps-ia-fig__noeud + .ps-ia-fig__noeud {
    position: relative;
    padding-left: 28px;
  }

  .ps-ia-fig__noeud + .ps-ia-fig__noeud::before {
    content: '';
    position: absolute;
    left: 0;
    top: 0.6em;
    width: 16px;
    height: 1px;
    background: var(--filet);
  }
}

.ps-ia-fig__noeud {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.ps-ia-fig__noeud-titre {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 17px;
  line-height: 1.25;
  color: var(--encre);
}

.ps-ia-fig__noeud-detail {
  font-family: var(--font-corps);
  font-size: 15px;
  line-height: 1.5;
  color: var(--texte-2);
}

/* Le releve brique par brique : une liste de definitions, parce que c'en est
   une. Le nom de la brique est le terme, ce qu'elle fait la definition. */
.ps-ia-fig__briques {
  display: grid;
  gap: 0;
  margin: 0;
  border-top: 1px solid var(--filet);
}

.ps-ia-fig__brique {
  display: grid;
  gap: 4px;
  padding: 16px 20px;
}

.ps-ia-fig__brique + .ps-ia-fig__brique {
  border-top: 1px solid var(--filet);
}

@media (min-width: 640px) {
  .ps-ia-fig__brique {
    grid-template-columns: 250px minmax(0, 1fr);
    gap: 24px;
    align-items: baseline;
  }
}

.ps-ia-fig__brique dt {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-label);
  letter-spacing: 0.08em;
  color: var(--encre);
}

.ps-ia-fig__brique dd {
  margin: 0;
  font-family: var(--font-corps);
  font-size: 15px;
  line-height: 1.6;
  color: var(--texte-2);
}

.ps-ia-fig__exclusion {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 12px;
  margin: 0;
  padding: 16px 20px;
  border-top: 1px solid var(--filet);
  font-family: var(--font-corps);
  font-size: 15px;
  line-height: 1.6;
  color: var(--encre);
}

/* L'etiquette de l'exclusion : un cadre au filet, jamais un aplat de couleur —
   la charte interdit le fond plein, et le mot se suffit. */
.ps-ia-fig__tag {
  flex: none;
  padding: 3px 8px;
  border: 1px solid var(--accent);
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-label);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--accent);
}

.ps-ia-fig__legende {
  margin: 0;
  padding: 12px 20px;
  border-top: 1px solid var(--filet);
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  letter-spacing: 0.08em;
  color: var(--texte-2);
}

/* ------------------------------------------------------------------------
   § 10.17 — LA CAPSULE DE REPONSE

   Le premier paragraphe d'une page de contenu : 40 a 80 mots qui repondent
   entierement a la question que pose le titre. Rendue par
   build/blocks/capsule.mjs, juste sous le hero.

   Elle est dessinee pour etre LUE, pas pour etre remarquee : un filet vertical
   a l'accent, une largeur de lecture bornee, un corps un cran au-dessus du
   texte courant. Aucun aplat de fond (interdit n° 4), aucune ombre
   decorative, aucun encadre : ce qui la detache est sa position et son filet.

   Note d'echelle, corrigee en session 3 : `1rem` valait 10px sur ce site tant
   que le gabarit posait html { font-size: 10px }, et l'echelle --fs-* de la
   charte etait rendue a 62,5 %. La racine est revenue a 16px, un rem vaut donc
   16px et l'echelle est vivante. Les tailles de ce bloc restent en pixels
   parce qu'elles etaient deja JUSTES : la capsule est le seul bloc du site qui
   posait ensemble les trois bonnes valeurs — 18px, interligne 1,65, largeur de
   lecture bornee a 68ch. Les changer pour les reecrire en jetons ne
   corrigerait rien et risquerait le seul bloc qui tenait. */

.ps-capsule {
  margin-top: -8px;   /* le hero laisse deja sa marge basse */
  margin-bottom: 56px;
}

.ps-capsule__inner {
  max-width: 68ch;    /* la longueur de ligne confortable, pas la largeur du conteneur */
  padding-left: 20px;
  border-left: 2px solid var(--accent);
}

.ps-capsule__libelle {
  margin: 0 0 8px;
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-label);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--texte-2);
}

.ps-capsule__texte {
  margin: 0;
  font-family: var(--font-corps);
  font-size: 18px;
  line-height: 1.65;
  color: var(--encre);
}

@media (max-width: 767px) {
  .ps-capsule {
    margin-bottom: 40px;
  }

  .ps-capsule__inner {
    padding-left: 16px;
  }

  .ps-capsule__texte {
    font-size: var(--fs-body);
  }
}

/* ------------------------------------------------------------------------
   § 10.18 — LE NUMERO FANTOME DES CARTES D'APPROCHE

   `.single-approach-area-start::after` pose un « 01 » de 72 px en contour, en
   absolu sur le coin haut droit de la carte. Le gabarit Agenio le dessine pour
   des cartes a deux lignes de texte ; le contour est donc trace a l'encre, et
   il croise la fin des premieres lignes des que le texte s'allonge. C'est deja
   le cas sur les huit pages de cas d'usage, ou « particuliers » passe sous le
   chiffre.

   Le chiffre est un ornement, le texte est le contenu : c'est l'ornement qui
   cede. Le contour passe au filet, valeur prevue par la charte pour ce qui
   separe sans peser. La mise en page ne bouge pas, aucune ligne ne se
   redistribue, et le repere numerique reste lisible sur fond blanc.

   Le survol n'est pas touche : le gabarit y remet --texte-2, et le chiffre se
   revele alors sous le curseur. Le geste devient lisible au lieu d'etre subi,
   et il ne gene qu'au moment ou la carte est deja regardee. */

.single-approach-area-start::after {
  -webkit-text-stroke-color: var(--filet);
}


/* ---- 10.19 La figure des niveaux en volume ----

   La scene portee de propul-ai.com, rendue sur un canevas 2D par
   `propulseo-ia-scene.js`. Elle se pose PAR-DESSUS le releve SVG, dans la meme
   zone en 4/3, et n'apparait qu'une fois montee.

   Le releve reste dans le HTML et garde son etat de niveau : sans JavaScript,
   sans canevas, ou pendant le temps ou le script n'a pas encore tourne, c'est
   lui qu'on voit — exactement comme la source montre son `<Suspense fallback>`
   en attendant son chunk. C'est aussi ce qu'un moteur de reponse lit, et c'est
   pour cela qu'on ne le retire du flux qu'apres coup. */

.ps-ia-fig__zone {
  position: relative;
}

.ps-ia-scene__toile {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
}

/* Le releve s'efface quand la scene a pris la main. `visibility` et non
   `display` : la zone garde sa hauteur, et le cadre ne saute pas au montage. */
.ps-ia-fig__releve[data-ps-remplace] {
  visibility: hidden;
}


/* ---- 10.20 La colonne figure collante du releve ----

   Sur propul-ai.com, la section « Trois niveaux, un principe » se lit en
   descendant : la figure reste a l'ecran pendant que les trois offres defilent
   a cote, et chaque offre qui traverse la bande centrale allume son plateau.
   Les etages se construisent sous les yeux du lecteur. Sans le collant, la
   figure sort de l'ecran des la premiere ligne et l'animation se joue dans le
   vide — c'est ce qui manquait au hub.

   Releve au navigateur sur la source : la figure s'y epingle a 135 px du haut.
   Ici c'est 96 px, la valeur deja retenue pour la figure de `ia-offres.html`
   (§ 10.12), parce que l'en-tete de ce site n'a pas la meme hauteur que celui
   de propul-ai.com : 80 px de collant, plus 16 px d'air. Reprendre 135 px tel
   quel laisserait un trou sous un en-tete qui ne le remplit pas.

   ORDINATEUR SEULEMENT. Sous 1024 px les deux colonnes s'empilent : la figure
   passe au-dessus des lignes, il n'y a plus rien a accompagner, et un collant
   n'aurait plus de sens. Les lignes continuent d'allumer les plateaux au
   defilement — elles passent alors sous la figure, ce que la source fait
   aussi. */

@media (min-width: 1024px) {
  .ps-ia-releve__colonne {
    position: sticky;
    top: 96px;
    align-self: start;
  }
}


/* La course du collant. Sur propul-ai.com la colonne de droite porte trois
   cartes d'offre et mesure 2 844 px : la figure y reste epinglee pendant plus
   de deux ecrans, et les trois niveaux s'allument un a un. Ici la colonne ne
   portait que trois lignes de prix, soit 551 px contre 560 px pour la figure —
   mesure au navigateur. Un element collant dont le conteneur fait sa propre
   hauteur n'a AUCUNE course : il ne colle jamais, et aucune regle n'est fausse
   pour autant. C'est ce qui manquait, et cela ne se voit qu'en mesurant.

   La liste recoit donc une hauteur minimale en `vh` et repartit ses trois
   lignes dedans. En `vh` et non en pixels : la course doit suivre la taille de
   l'ecran, puisque c'est elle qui decide de la distance a parcourir pour
   traverser la bande centrale. A 900 px de haut, la figure reste epinglee sur
   environ 790 px et chaque ligne dispose de 450 px de defilement pour elle.

   On ne remonte pas les cartes a volet sur le hub pour autant : c'est ce qui
   le ferait repasser de sept ecrans a dix-huit, et la decision de la phase 3
   le dit. Le releve garde sa forme, il prend le temps de se lire. */

@media (min-width: 1024px) {
  .ps-ia-releve__ligne {
    padding: 32px 0;
  }

  .ps-ia-releve__lignes {
    min-height: 150vh;
    display: flex;
    flex-direction: column;
    justify-content: space-around;
  }
}


/* ---- 10.9 Qui s'en occupe : les portraits du hub ----

   Le pendant AI des cartes de la page agence. Même donnée, autre forme : le
   hub pose ses fiches à plat sur sa grille, portrait carré en haut, texte
   aligné à gauche, aucun cartouche flottant.

   Les pastilles de pôle sont celles de la section 11 (`ps-equipe-pole`) : on
   ne redéclare que leur alignement, qui est centré sur la carte du gabarit
   Agenio et à gauche ici. */

/* Deux colonnes DÈS LE MOBILE, quatre à partir de 1024. Une colonne unique y
   donnait quatre portraits pleine largeur, soit une section de deux écrans
   sur un hub tenu à moins de huit — c'est le geste de cadrage de la phase 2,
   et une galerie de portraits n'est pas ce qui mérite de le défaire. */
.ps-ia-equipe {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 28px 20px;
  margin-top: 40px;
}

@media (min-width: 1024px) {
  .ps-ia-equipe {
    grid-template-columns: repeat(4, 1fr);
    gap: 32px 24px;
  }
}

.ps-ia-membre {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 10px;
}

/* Le portrait garde le format dans lequel il est livré (4/5) : ici rien ne
   vient se poser dessus, il n'y a donc aucune raison de le recadrer. Filet 1px,
   rayon de carte, jamais d'ombre. */
.ps-ia-membre__portrait {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  border: 1px solid var(--filet);
  border-radius: var(--r-carte);
  margin-bottom: 6px;
}

.ps-ia-membre__poles {
  justify-content: flex-start;
}

.ps-ia-membre__nom {
  font-family: var(--font-corps);
  font-weight: 600;
  font-size: 17px;
  line-height: 1.3;
  color: var(--encre);
}

.ps-ia-membre__role {
  font-size: var(--fs-small);
  line-height: 1.4;
  color: var(--encre);
}

.ps-ia-membre__detail {
  font-size: var(--fs-small);
  line-height: 1.6;
  color: var(--texte-2);
}

/* ============================================================================
   11. CARTES ÉQUIPE — page agence
   ============================================================================

   Le gabarit Agenio ne donne à sa carte équipe qu'un nom et une ligne de
   fonction. La page agence en demande deux de plus : le ou les pôles de la
   personne, et ce qu'elle fait concrètement sur un chantier. Les deux lignes
   ajoutées portent le préfixe `ps-equipe-`, le reste de la carte (photo,
   cartouche flottant, réseaux au survol, coins découpés) reste celui du
   gabarit.

   LA COULEUR NE PORTE JAMAIS L'INFORMATION SEULE. Chaque puce de pôle est
   suivie du nom du pôle en toutes lettres, et la phrase sous le titre de
   section dit qui intervient où. La couleur ne fait que répéter, ce qui la
   rend lisible en niveaux de gris comme pour un daltonien.

   Les longueurs sont en pixels, et depuis la session 3 c'est un choix et non
   une contrainte : la racine est revenue à 16 px, les `rem` de la charte valent
   ce qu'ils annoncent. Une géométrie de figure se dimensionne au pixel.
   ------------------------------------------------------------------------- */

/* La phrase de cadrage, sous le titre de section. */
.ps-equipe-intro {
  max-width: 640px;
  margin: 16px auto 0;
  text-align: center;
  font-size: 15px;
  line-height: 1.65;
  color: var(--texte-2);
}

/* Les portraits sont livrés au format du cadre (600 × 750). Le carré d'origine
   y est posé plus petit, sur son propre fond violet flouté : c'est l'image qui
   porte le recul, pas la CSS. La règle ne recadre donc plus rien — elle fixe le
   rapport pour que la hauteur de la colonne soit connue avant le chargement, et
   garde `cover` en garde-fou si un portrait revenait carré. */
.team-wrapper .image-area img {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  object-position: center top;
}

/* Le cartouche flottant accueille deux lignes de plus : il s'élargit de
   quelques pixels et resserre ses interlignes, sans changer de nature. */
.team-wrapper .author-area {
  max-width: calc(100% - 16px);
  padding: 13px 14px 15px;
  gap: 7px;
}

.team-wrapper .author-area .title {
  line-height: 1.2;
  text-align: center;
}

/* La fonction tenait sur une ligne dans le gabarit (`line-height: 1`) : elle
   en fait deux ou trois ici, il lui faut un interligne. */
.team-wrapper .author-area .designation {
  font-size: 13px;
  line-height: 1.4;
  text-align: center;
  color: var(--encre);
}

/* ---- Les pôles, en tête de carte ----

   Chaque <li> porte son `data-branche` : c'est lui qui choisit --accent et
   --accent-display dans le sous-arbre. Aucune couleur n'est écrite ici, et la
   même règle sert les deux pôles. C'est la mécanique des pages maison : la
   page n'a pas de branche, ses composants portent la leur. */
.ps-equipe-poles {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 4px 14px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.ps-equipe-pole {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin: 0;
  padding: 0;
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--fs-label);
  line-height: 1.2;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--accent);
}

/* La puce carrée de la charte, à la taille d'un label. */
.ps-equipe-pole__puce {
  flex: 0 0 8px;
  width: 8px;
  height: 8px;
  background: var(--accent-display);
}

/* Ce que la personne fait sur un chantier. Une phrase, jamais deux. */
.ps-equipe-bio {
  margin: 0;
  text-align: center;
  font-size: 13px;
  line-height: 1.5;
  color: var(--texte-2);
}

/* ============================================ 13. LE BOUTON DE CARTE DE SERVICE

   Le gabarit Agenio pose sur `.service-btn-area` un carre de 56x56 en
   `opacity: 0`, revele au seul `:hover` de la carte, et n'y met qu'une fleche
   SVG de 10x18. Sur telephone, ou il n'y a pas de survol, ce bouton n'existait
   donc jamais — et c'etait le seul chemin editorial d'une fiche d'integration,
   d'une categorie, d'un secteur ou d'une technologie vers une page d'offre :
   1 160 liens par locale, invisibles au doigt et sans nom pour un lecteur
   d'ecran.

   Le markup porte desormais un libelle (`.ps-service-btn__texte`, mot du
   registre) et un `aria-label` qui nomme l'entite visee. Il reste a le rendre
   VISIBLE : c'est tout ce que fait ce bloc.

   L'opacite passe donc a 1 en permanence, et le carre devient une barre qui
   accueille le mot. Le `:hover` du gabarit reste : il ne fait plus apparaitre
   le bouton, il l'accentue — ce qui etait deja son intention. */

/* Le bouton passe sur SA PROPRE LIGNE, sous les puces. Le gabarit le posait
   a cote d'elles : large de 56 px il ne genait pas, large d'un mot il volait
   60 px a une colonne de 205, et les puces passaient de trois lignes a cinq —
   donc hors du cadre, que `.service-wrapper` masque en `overflow: hidden`. */
.wpr-services-area .section-bottom-content .service-wrapper .content .bottom {
  flex-wrap: wrap;
  align-items: stretch;
}

.wpr-services-area .section-bottom-content .service-wrapper .content .bottom ul {
  flex: 1 1 100%;
}

.wpr-services-area .section-bottom-content .service-wrapper .content .bottom .service-btn-area {
  opacity: 1;
  flex: 0 0 auto;
  margin-top: 14px;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  width: auto;
  min-height: 44px;             /* la cible tactile recommandee, en entier */
  height: auto;
  line-height: 1.2;
  padding: 0 16px;
  border-radius: var(--r-bouton);   /* le rayon de la charte, jamais la pilule */
  text-align: left;
  white-space: nowrap;
}

/* Le mot lui-meme. Meme graisse et meme corps que les etiquettes de la charte,
   sans les capitales : c'est une action, pas un label de section. */
.ps-service-btn__texte {
  font-family: var(--font-corps);
  font-size: var(--fs-small);
  font-weight: 600;
  color: var(--color-heading-1);
}

/* La fleche du gabarit est peinte en `fill="black"` dans le SVG lui-meme :
   elle ne suit pas `currentColor`. On la laisse telle quelle et on l'aligne. */
.service-btn-area svg {
  flex: none;
  display: block;
}

/* Survol : le bouton prend l'accent, comme les autres actions de la charte. */
.wpr-services-area .section-bottom-content .service-wrapper:hover .content .bottom .service-btn-area {
  opacity: 1;
}

/* ============================================ 14. LE BANDEAU DE REPERES

   Trois faits sous le chapeau du hero : la fourchette, le delai, le bouton.
   Aucun n'est nouveau — ils arrivaient a 6 400 px, 4 000 px et 2 334 px du haut
   d'une page qui en fait 12 900. Le bandeau ne les invente pas, il les remonte.

   La mise en page est une bande horizontale sur ordinateur et une colonne sur
   telephone : ce sont trois faits courts, ils tiennent sur une ligne des qu'il
   y a la place. Les valeurs se lisent comme des chiffres — corps plus grand que
   leur etiquette, graisse pleine — et l'etiquette prend la forme des labels de
   la charte : mono, capitales, espacees. */

.ps-reperes {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 16px 32px;
  margin: 28px auto 0;
  padding: 20px 24px;
  max-width: 900px;
  border: 1px solid var(--filet);
  border-radius: var(--r-carte);
  background: var(--color-white);
  text-align: left;
}

.ps-reperes__fait {
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.ps-reperes__cle {
  font-family: var(--font-mono, monospace);
  font-weight: 500;
  font-size: var(--fs-label);
  line-height: 1.2;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--texte-2);
}

.ps-reperes__valeur {
  font-family: var(--font-corps);
  font-weight: 600;
  font-size: 18px;
  line-height: 1.3;
  color: var(--color-heading-1);
}

/* Le bouton pousse a droite quand la ligne le permet, et prend toute la
   largeur des qu'elle se casse : un bouton de 180 px isole sous deux faits
   pleine largeur se lit comme un residu. */
.ps-reperes__action {
  margin-left: auto;
}

@media (max-width: 767px) {
  .ps-reperes {
    gap: 14px;
    padding: 18px;
  }
  .ps-reperes__fait {
    flex-direction: row;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    width: 100%;
  }
  .ps-reperes__action {
    margin-left: 0;
    width: 100%;
    text-align: center;
  }
}
