/* ==========================================================================
   sanjco.ch — feuille de style unique
   Charte dérivée du logo. Le noir pur n'est utilisé nulle part.
   Conception mobile d'abord : les styles de base valent pour le téléphone,
   les media queries n'ajoutent que ce qui devient possible en s'élargissant.
   ========================================================================== */

:root {
  /* Palette (brief, section 4) */
  --orange:       #D9430A;
  /* L’orange de la charte tenu sur du texte blanc plafonne à 4,41:1, juste sous
     le seuil WCAG AA. Les surfaces pleines qui portent du texte blanc utilisent
     donc cette nuance de trois points plus sombre, à 4,52:1. L’orange de la
     charte reste employé partout où il ne sert pas de fond à du texte. */
  --orange-ui:    #D6420A;
  --orange-fonce: #AE3506;
  --orange-pale:  #FCEDE5;
  --anthracite:   #333131;
  --anthracite-2: #454240;
  --gris:         #6B6866; /* assombri vs le relevé du logo pour tenir WCAG AA sur fond sable */
  --gris-clair:   #A7A7A7; /* décoratif uniquement, contraste insuffisant pour du texte */
  --ligne:        #E5E2DE;
  --ligne-claire: #EFEDEA;
  --sable:        #F7F6F4;
  --sable-2:      #F1EFEC;
  --papier:       #FFFFFF;

  /* Familles */
  --sans: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --mono: ui-monospace, "SF Mono", "Cascadia Mono", Consolas, monospace;

  /* Gabarit */
  --largeur:  1240px;
  --marge:    22px;
  --rayon-bouton: 4px;
  --rayon-carte:  10px;  /* petites cartes */
  --rayon-bloc:   16px;  /* grandes surfaces seulement : carte d’intro, appel
                            final, pied de page */

  /* Hauteur nominale de l’en-tête collant. Elle sert à dégager le haut du hero
     et à dimensionner le panneau du menu mobile. */
  --entete-h: 78px;

  /* Courbe d’assouplissement commune à toutes les transitions ajoutées. */
  --courbe: cubic-bezier(.65, .05, .36, 1);
}

@media (min-width: 760px) {
  :root { --marge: 28px; }
}

/* --- base ---------------------------------------------------------------- */

*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }

/* Les composants déclarent display: flex ; sans cette règle, l’attribut hidden
   posé par le JavaScript serait sans effet, la règle du navigateur étant de
   priorité inférieure à une règle d’auteur. */
[hidden] { display: none !important; }

html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { transition: none !important; animation: none !important; }
}

body {
  font-family: var(--sans);
  /* Le fond de page est le sable soutenu : il n’apparaît qu’autour des grandes
     cartes (appel final, pied de page), les sections portant leur propre fond. */
  background: var(--sable-2);
  color: var(--anthracite);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

img, svg, video { max-width: 100%; height: auto; display: block; }
button { font-family: inherit; cursor: pointer; }
a { color: inherit; }

:focus-visible {
  outline: 3px solid var(--orange);
  outline-offset: 3px;
  border-radius: 2px;
}

/* Sur les fonds sombres ou orange, un cerne orange serait invisible. */
/* Le hero de l’accueil et la barre transparente posée dessus reposent sur
   une photo voilée : l’orange y descendait sous 3:1 sur une bonne part de
   l’anneau. Le panneau du menu mobile ouvert, sur fond sable, garde l’orange —
   d’où :not(.ouvert). */
.cta-final :focus-visible,
footer :focus-visible,
.avis-demo :focus-visible,
.hero--photo :focus-visible,
header.accueil.sur-hero .logo:focus-visible,
header.accueil.sur-hero .burger:focus-visible,
header.accueil.sur-hero .nav-cta:focus-visible,
header.accueil.sur-hero .menu:not(.ouvert) a:focus-visible,
header.accueil.sur-hero .langue a:focus-visible {
  outline-color: #fff;
}

/* Lien d'évitement, premier élément focusable de chaque page */
.evitement {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 200;
  background: var(--anthracite);
  color: #fff;
  padding: 12px 20px;
  border-radius: 0 0 var(--rayon-bouton) 0;
  font-weight: 600;
  text-decoration: none;
}
.evitement:focus { left: 0; }

.hors-ecran {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

/* --- en-tête ------------------------------------------------------------- */

header {
  position: sticky;
  top: 0;
  z-index: 60;
  background: rgba(255, 255, 255, .94);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--ligne);
}

.nav {
  max-width: var(--largeur);
  margin: 0 auto;
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 13px var(--marge);
  position: relative;
  /* Hauteur fixe, et non laissée au contenu : sur l’accueil, le hero glisse
     sous l’en-tête d’exactement --entete-h pour paraître à travers lui quand
     il est transparent. Laissée libre, la barre mesurait 74 px sur téléphone,
     78 sur grand écran et 84 entre 980 et 1 100 px — autant de bandes de fond
     de page visibles entre l’en-tête et le hero. Le pixel retiré est celui de
     la bordure basse de <header>. */
  height: calc(var(--entete-h) - 1px);
}

/* Logo officiel, en PNG de 400 x 104 produit par outils/generer-logos.php. La
   hauteur est fixée, la largeur suit le rapport du fichier. */
.logo {
  display: flex;
  align-items: center;
  flex-shrink: 0;
  text-decoration: none;
}
.logo img {
  height: 27px;
  width: auto;
}

@media (min-width: 1100px) {
  .logo img { height: 30px; }
}

.logo-pied {
  height: 32px;
  width: auto;
  margin-bottom: 18px;
}

.menu { display: none; }

.menu a {
  color: var(--anthracite-2);
  text-decoration: none;
  font-size: 14.5px;
  font-weight: 500;
}
.menu a:hover { color: var(--orange); }

/* Panneau du menu mobile. Il est ancré sous la barre de navigation plutôt qu’à
   une position fixe : il suit ainsi l’en-tête, que le bandeau de démonstration
   soit affiché ou non. La classe « ouvert » est posée par le script, donc rien
   n’est masqué si celui-ci ne s’exécute pas — le repli <noscript> prend alors
   le relais. */
.menu.ouvert {
  display: flex;
  position: absolute;
  top: 100%;
  left: 0; right: 0;
  height: calc(100svh - var(--entete-h));
  overflow-y: auto;
  background: var(--sable-2);
  flex-direction: column;
  padding: 28px var(--marge);
  border-bottom: 1px solid var(--ligne);
  box-shadow: 0 12px 28px rgba(51, 49, 49, .10);
}

/* Les liens montent en cascade. L’animation part d’un état masqué et finit à
   l’état de base : si elle est coupée — mouvement réduit, impression — les
   liens restent simplement visibles. */
@media (prefers-reduced-motion: no-preference) {
  .menu.ouvert > * { animation: menu-entree .32s var(--courbe) both; }
  .menu.ouvert > *:nth-child(2) { animation-delay: .04s; }
  .menu.ouvert > *:nth-child(3) { animation-delay: .08s; }
  .menu.ouvert > *:nth-child(4) { animation-delay: .12s; }
  .menu.ouvert > *:nth-child(5) { animation-delay: .16s; }
  .menu.ouvert > *:nth-child(n+6) { animation-delay: .2s; }

  @keyframes menu-entree {
    from { opacity: 0; transform: translateY(12px); }
  }
}

/* Sélecteur de langue de la barre : FR / DE / EN, la langue courante en gras
   et plus sombre. Les liens sont rembourrés pour atteindre 24 px de cible
   (WCAG 2.5.8) sans élargir la barre. Sous 980 px, la barre n'a pas la place :
   les langues passent dans le panneau du menu (.menu-langues, plus bas). */
.langue {
  display: none;
  align-items: center;
  gap: 1px;
  font-size: 12.5px;
  color: var(--gris);
}
.langue a {
  display: inline-block;
  padding: 5px 3px;
  color: var(--gris);
  font-weight: 500;
  text-decoration: none;
}
.langue a:hover { color: var(--orange-fonce); text-decoration: underline; }
.langue a[aria-current] { color: var(--anthracite); font-weight: 800; }

.nav-cta {
  background: var(--orange-ui);
  color: #fff;
  border: 0;
  border-radius: var(--rayon-bouton);
  padding: 10px 14px;
  font-size: 14px;
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
}
.nav-cta:hover { background: var(--orange-fonce); }

.burger {
  background: none;
  border: 1px solid var(--ligne);
  border-radius: var(--rayon-bouton);
  color: var(--anthracite);
  padding: 9px 12px;
  font-size: 14px;
  font-weight: 500;
  /* Poussé à droite sans changer l’ordre du DOM : la tabulation suit ce que l’on voit. */
  margin-left: auto;
}

@media (min-width: 980px) {
  .nav { gap: 28px; }
  .burger { display: none; }
  .menu { display: flex; margin-left: auto; }
  .langue { display: flex; }
  .nav-cta { padding: 11px 18px; font-size: 14.5px; }
}

/* --- sections ------------------------------------------------------------ */

/* --- recouvrement du hero collant -----------------------------------------
   Deux règles distinctes, jamais fusionnées.
   La première place devant le hero tout ce qui le suit, quel que soit le
   nombre de blocs intercalés — d’où le combinateur « ~ » et non « + ».
   La seconde leur donne un fond opaque à une spécificité (0,0,1) que .alt,
   .sable-2, .hero-page, .cta-final et .hero — toutes en (0,1,0) — écrasent
   sans effort. Elle couvre aussi div.legal et article.article, qui ne sont
   pas des <section>. Aucun :not() porteur de classe n’est nécessaire.
   -------------------------------------------------------------------------- */

.hero ~ * { position: relative; z-index: 1; }
main > *  { background: var(--papier); }

section { position: relative; padding: 68px var(--marge); }
.interieur { max-width: var(--largeur); margin: 0 auto; width: 100%; }
.alt { background: var(--sable); }
.sable-2 { background: var(--sable-2); }

.surtitre {
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--orange-fonce);
  margin-bottom: 16px;
}

h1, h2, h3, h4 { color: var(--anthracite); }

h2 {
  font-size: clamp(26px, 3.6vw, 40px);
  font-weight: 800;
  letter-spacing: -.025em;
  line-height: 1.12;
  margin-bottom: 14px;
}

h3 { font-size: 20px; font-weight: 700; letter-spacing: -.02em; }

.chapeau {
  color: var(--gris);
  font-size: 17px;
  max-width: 66ch;
  margin-bottom: 36px;
}

/* --- plus de mot seul en dernière ligne -----------------------------------
   « balance » est réservé aux textes courts ; « pretty » est ciblé sur les
   blocs longs, dont il est le seul à porter le coût de mise en page. */
h1, h2, h3, blockquote { text-wrap: balance; }
.chapeau, .sous-titre, .prose p, .legal article p { text-wrap: pretty; }

@media (min-width: 760px) {
  section { padding: 100px var(--marge); }
  .chapeau { margin-bottom: 44px; }
}

/* --- boutons ------------------------------------------------------------- */

.rangee-cta {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
  margin-top: 32px;
}

.btn {
  border-radius: var(--rayon-bouton);
  padding: 14px 24px;
  font-size: 15.5px;
  font-weight: 600;
  border: 1px solid transparent;
  text-decoration: none;
  display: inline-block;
  text-align: center;
}
.btn-p { background: var(--orange-ui); color: #fff; }
.btn-p:hover { background: var(--orange-fonce); }
.btn-s { background: #fff; color: var(--anthracite); border-color: var(--ligne); }
.btn-s:hover { border-color: var(--anthracite); }
.btn-d { background: var(--anthracite); color: #fff; }
.btn-d:hover { background: var(--anthracite-2); }
.btn-blanc { background: #fff; color: var(--orange-fonce); }
.btn-blanc:hover { background: var(--orange-pale); }

.lien-fl {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  color: var(--orange-fonce);
  font-weight: 600;
  font-size: 14.5px;
  text-decoration: none;
}
.lien-fl:hover { text-decoration: underline; }
.lien-fl::after { content: "\2192"; }

/* --- une seule grammaire de réaction --------------------------------------
   Même durée et même courbe partout où le visiteur agit : celles déjà posées
   sur .carte-secteur. L’enfoncement d’un pixel accuse réception du clic — sur
   écran tactile, c’est le seul accusé de réception qui existe. .pied a
   n’attrape pas .pied-bas .pied-remonter, frère de .pied : les deux sont nommés.
   -------------------------------------------------------------------------- */

.btn, .nav-cta, .pilule, .filtres button, .menu a, .fil a, .sommaire a,
.pied a, .pied-haut .courriel, .pied-bas .pied-remonter,
.service-declinaisons a, .hero-descente, .lien-fl::after,
.carrousel-fleche {
  transition: background .18s var(--courbe), border-color .18s var(--courbe),
              color .18s var(--courbe), transform .18s var(--courbe);
}

/* Sans transform : un cadre de saisie ne s’enfonce pas. */
.champ input, .champ select, .champ textarea {
  transition: background .18s var(--courbe), border-color .18s var(--courbe);
}

.btn:active, .nav-cta:active, .pilule:active, .filtres button:active,
.carrousel-fleche:active {
  transform: translateY(1px);
}

/* --- la flèche des liens avance ------------------------------------------- */
.lien-fl:hover::after,
.lien-fl:focus-visible::after { transform: translateX(4px); }

/* --- hero d'accueil ------------------------------------------------------ */

/* Le hero occupe l’écran. Il ne se colle que là où le rideau existe : voir le
   bloc @supports plus bas, qui pose position: sticky et le fondu ensemble. */
.hero {
  background: var(--sable);
  /* Positionné pour contenir le motif de ::before, qui est en inset: 0. */
  position: relative;
  /* clip et non hidden : hidden ferait du hero un conteneur de défilement,
     ce qui tuerait à la fois position: sticky et la timeline de défilement. */
  overflow: clip;
  min-height: 100vh;   /* repli des Safari antérieurs à 15.4, écrit AVANT svh */
  min-height: 100svh;
  display: grid;
  align-content: center;
  /* Le hero remonte sous l’en-tête : c’est son motif, et non le fond de page,
     qu’on voit à travers la barre quand elle est transparente. Le rembourrage
     haut rend exactement ce que la marge retire, le contenu ne bouge donc pas
     par rapport à la barre. La hauteur de l’en-tête est fixée sur .nav. */
  margin-top: calc(-1 * var(--entete-h));
  padding: calc(var(--entete-h) + 24px) var(--marge) 48px;
  border-bottom: 1px solid var(--ligne);
}
.hero::before {
  content: "";
  position: absolute;
  inset: 0;
  background:
    radial-gradient(760px 400px at 82% 22%, rgba(217, 67, 10, .11), transparent 64%),
    repeating-linear-gradient(115deg, transparent, transparent 26px, rgba(51, 49, 49, .022) 26px, rgba(51, 49, 49, .022) 52px);
}
/* Tout le contenu du hero est centré : titre, texte, boutons, pilule et
   repère de descente. Les deux blocs de texte gardent leur largeur de lecture
   et se centrent par leurs marges. */
.hero .interieur { position: relative; z-index: 2; text-align: center; }
.hero h1, .hero .sous-titre { margin-inline: auto; }
.hero .rangee-cta { justify-content: center; }

.hero h1 {
  font-size: clamp(32px, 5.4vw, 60px);
  font-weight: 800;
  letter-spacing: -.035em;
  line-height: 1.06;
  max-width: 17ch;
}
.hero h1 em { color: var(--orange); font-style: normal; }

.hero .sous-titre {
  color: var(--gris);
  font-size: 18px;
  max-width: 56ch;
  margin-top: 22px;
}

/* --- hero avec photographie ------------------------------------------------
   La photo remplit le hero, recadrée par object-fit selon la forme de la
   fenêtre. Le voile, porté par ::before à la place du motif rayé, assombrit
   de 54 à 80 % pour que le texte blanc se lise sur n’importe quel pixel, toits
   clairs compris — mesuré sur la photo, pixel par pixel, sous chaque texte : il fonce vers le haut, sous la barre de navigation devenue
   transparente, et au centre, sous le titre.
   isolation: isolate borne au hero les z-index de la photo, du voile et du
   texte : sans elle, ils se mesureraient aux sections qui glissent par-dessus
   quand le hero est épinglé.
   -------------------------------------------------------------------------- */
.hero--photo {
  isolation: isolate;
  background: #2A2826;   /* le temps que la photo arrive */
  border-bottom: 0;
}
.hero-photo {
  position: absolute;
  inset: 0;
  z-index: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.hero--photo::before {
  z-index: 1;
  background:
    linear-gradient(180deg, rgba(24, 22, 21, .5) 0, rgba(24, 22, 21, 0) 200px),
    radial-gradient(ellipse 75% 65% at 50% 55%, rgba(24, 22, 21, .8), rgba(24, 22, 21, .54));
}
/* L’ombre, très diffuse, ne se voit pas comme telle : c’est une marge de
   contraste pour la photo définitive, dont les pixels ne seront pas ceux de
   l’aperçu mesuré. Les rapports relevés ne la comptent pas. */
.hero--photo h1 { color: #fff; text-shadow: 0 1px 22px rgba(24, 22, 21, .55); }
/* L’orange de la charte descend sous 3:1 au-dessus d’un toit clair, même
   voilé : le mot en valeur prend l’orange clair déjà employé sur fond sombre
   par le bandeau de démonstration. */
.hero--photo h1 em { color: #FF8A4C; }
.hero--photo .sous-titre { color: rgba(255, 255, 255, .92); }
.hero--photo .hero-descente { color: rgba(255, 255, 255, .88); }
.hero--photo .hero-descente:hover { color: #fff; }

/* Mouvement réduit : le hero n’est de toute façon pas collé, puisque
   l’épinglage est déclaré sous « no-preference ». On lui rend seulement sa
   hauteur ordinaire, pour ne pas imposer un écran entier avant le contenu. */
@media (prefers-reduced-motion: reduce) {
  .hero { min-height: 0; padding: calc(var(--entete-h) + 56px) var(--marge) 66px; }
}

/* Fondu de sortie du contenu du hero sur la première hauteur d’écran.
   scroll(root block) et non view() : le sujet est dans un élément collé, donc
   immobile dans la fenêtre, où les plages exit et exit-crossing ne seraient
   atteintes qu’en fin de <main>. Sans prise en charge — Firefox, Safari — la
   règle entière est ignorée et l’élément reste dans son état de base, visible. */
@supports (animation-timeline: scroll()) {
  @media (prefers-reduced-motion: no-preference) {
    /* L’épinglage est porté par l’animation, et non par une règle ordinaire.
       C’est délibéré : « @supports » dit seulement que le navigateur connaît
       la propriété, pas que la timeline s’active — elle reste inerte quand la
       racine ne défile pas, à l’impression, ou dans un navigateur embarqué.
       Un hero collé sans rideau resterait derrière les sections opaques avec
       ses quatre commandes dans l’ordre de tabulation : invisibles mais
       atteignables, cerne de focus masqué, ce que refusent les critères
       WCAG 2.4.7 (focus visible) et 2.4.11 (focus non masqué).
       Une animation dont la timeline est inactive n’a aucun effet : le hero
       retombe alors sur sa règle de base et défile normalement. Épinglage et
       rideau apparaissent donc ensemble, ou pas du tout. */
    /* hero-masque rend le hero invisible une fois le rideau tiré, quand la
       première section le recouvre en entier. Resté visible, le hero photo,
       épinglé derrière toute la page, se montrait aux coins arrondis de l’appel
       final : quatre encoches sombres au bord de l’écran. Comme pour le rideau,
       visibility ne bascule qu’à la dernière image. */
    .hero {
      animation: hero-epingle linear both, hero-masque linear both;
      animation-timeline: scroll(root block);
      animation-range: normal, 0 100svh;
    }
    @keyframes hero-masque { to { visibility: hidden; } }

    /* Valeur constante d’un bout à l’autre : rien n’est interpolé, la règle
       ne fait que suivre le sort de la timeline. */
    @keyframes hero-epingle {
      from, to { position: sticky; top: 0; z-index: 0; }
    }

    .hero .interieur {
      animation: hero-rideau linear both;
      animation-timeline: scroll(root block);
      animation-range: 0 100svh;
    }

    /* visibility retire le contenu de l’ordre de tabulation une fois le rideau
       tiré. La propriété s’interpole par palier et ne bascule qu’à la dernière
       image : tant que le hero se voit, ses commandes restent atteignables. */
    @keyframes hero-rideau {
      to { opacity: .15; transform: translateY(-40px); visibility: hidden; }
    }
  }
}

/* Pilule de contact et repère de descente, tous deux dans le flux du hero :
   le repère n’est jamais posé au bas de la fenêtre, donc jamais poussé sous la
   ligne de flottaison par le bandeau de démonstration. */
.hero-pilule { margin-top: 26px; }

.pilule {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 10px 20px;
  background: var(--papier);
  border: 1px solid var(--ligne);
  border-radius: 999px;
  color: var(--anthracite-2);
  font-size: 14.5px;
  font-weight: 600;
  text-decoration: none;
}
.pilule:hover { border-color: var(--anthracite); color: var(--anthracite); }

/* Masqué sous 700 px : sur un téléphone, le geste de défilement est acquis et
   la place manque sous les boutons. */
.hero-descente {
  display: none;
  margin-top: 34px;
  color: var(--gris);
  font-size: 14px;
  font-weight: 600;
  text-decoration: none;
}

@media (min-width: 700px) {
  .hero-descente {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    min-height: 24px;
  }
}

.hero-descente:hover { color: var(--orange-fonce); }

/* La flèche est décorative : elle vit dans le <span aria-hidden> du gabarit. */
.hero-descente span::after {
  content: "\2193";
  display: block;
  font-size: 17px;
  line-height: 1;
}

@media (prefers-reduced-motion: no-preference) {
  /* Deux itérations et non « infinite » : un mouvement sans fin en parallèle du
     contenu est un échec WCAG 2.2.2 de niveau A. 3,8 s restent sous le seuil. */
  .hero-descente span::after { animation: descente-invite 1.9s var(--courbe) 2; }

  @keyframes descente-invite {
    0%, 100% { transform: translateY(0); }
    50%      { transform: translateY(5px); }
  }
}

/* --- en-tête de page intérieure ------------------------------------------ */

.hero-page {
  background: var(--sable);
  border-bottom: 1px solid var(--ligne);
  padding: 34px var(--marge) 52px;
}
.hero-page h1 {
  font-size: clamp(28px, 4.2vw, 46px);
  font-weight: 800;
  letter-spacing: -.03em;
  line-height: 1.08;
  max-width: 20ch;
}
.hero-page .sous-titre {
  color: var(--gris);
  font-size: 17.5px;
  max-width: 62ch;
  margin-top: 18px;
}
.hero-page .pastille { margin-bottom: 18px; }

@media (min-width: 760px) {
  .hero-page { padding: 40px var(--marge) 72px; }
}

/* Fil d'Ariane */
.fil {
  font-size: 13px;
  color: var(--gris);
  margin-bottom: 18px;
}
.fil ol { list-style: none; display: flex; flex-wrap: wrap; gap: 8px; }
.fil li + li::before { content: "/"; margin-right: 8px; color: var(--gris-clair); }
.fil a { color: var(--gris); text-decoration: none; }
.fil a:hover { color: var(--orange-fonce); text-decoration: underline; }
.fil [aria-current="page"] { color: var(--anthracite); }

/* --- grande carte de contenu ---------------------------------------------
   Réservée aux grandes surfaces : bloc d’introduction de l’accueil. Elle porte
   --rayon-bloc, jamais --rayon-carte.
   -------------------------------------------------------------------------- */

.carte-bloc {
  background: var(--papier);
  border: 1px solid var(--ligne);
  border-radius: var(--rayon-bloc);
  padding: 28px 24px;
}

@media (min-width: 760px) {
  .carte-bloc { padding: 48px; }
}

/* --- bandeau de chiffres (page À propos) --------------------------------- */

.stats {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  background: #fff;
  border: 1px solid var(--ligne);
  border-radius: var(--rayon-carte);
  overflow: hidden;
}
.stat {
  padding: 26px 22px;
  border-bottom: 1px solid var(--ligne-claire);
  border-right: 1px solid var(--ligne-claire);
  position: relative;
}
.stat::before {
  content: "";
  position: absolute;
  top: 0; left: 0;
  width: 34px; height: 3px;
  background: var(--orange);
  transform-origin: 0 50%;
}

/* Le filet de 34 px déjà en tête de chaque chiffre se remplit à l’arrivée de la
   rangée. C’est le seul mouvement du troisième chiffre, que le compteur laisse
   volontairement immobile (nombre = 5, voir chiffres.php). 660 ms est la fin
   d’entrée de la première case, puis un pas de 120 ms, qui se voit. */
.apparition .stats .stat::before { transform: scaleX(0); }
.apparition.vu .stats .stat::before { transform: none; transition: transform .5s var(--courbe) 660ms; }
.apparition.vu .stats .stat:nth-child(2)::before { transition-delay: 780ms; }
.apparition.vu .stats .stat:nth-child(3)::before { transition-delay: 900ms; }

.stat:nth-child(2n) { border-right: 0; }
/* Un nombre impair de chiffres laisse le dernier seul sur sa rangée : sans
   cette règle, il traînerait un filet vertical au milieu du vide. */
.stat:last-child { border-right: 0; }
.stat b {
  display: block;
  font-size: clamp(28px, 3.8vw, 42px);
  font-weight: 800;
  letter-spacing: -.03em;
  line-height: 1;
  /* Chiffres de largeur fixe : la ligne ne bouge pas pendant que le compteur
     remonte, donc aucun décalage cumulé de mise en page. */
  font-variant-numeric: tabular-nums;
}
.stat b i { color: var(--orange); font-style: normal; }

/* Enfant direct : le libellé, et lui seul. Le sélecteur descendant attrapait
   aussi le <span class="compteur"> logé dans le <b> et la puce « démo » du
   libellé, qui se seraient retrouvés en gris de 14 px. */
.stat > span {
  display: block;
  color: var(--gris);
  font-size: 14px;
  margin-top: 10px;
  max-width: 22ch;
}

/* Sous 400 px, deux colonnes couperaient les libellés en tranches de trois
   mots : la rangée passe à une colonne. */
@media (max-width: 399px) {
  .stats { grid-template-columns: 1fr; }
  .stat { border-right: 0; }
}

/* Une colonne par chiffre, quel qu'en soit le nombre : auto-fit répartit ce
   qui est là au lieu de laisser une cellule vide le jour où l'on retire une
   valeur. Le minimum de 180 px empêche un cinquième chiffre de tout serrer. */
@media (min-width: 1000px) {
  .stats { grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); }
  .stat { padding: 32px 26px; border-bottom: 0; }
  .stat:nth-child(2n) { border-right: 1px solid var(--ligne-claire); }
  .stat:last-child { border-right: 0; }
}

/* --- grilles ------------------------------------------------------------- */

.grille-2, .grille-3, .grille-4 {
  display: grid;
  grid-template-columns: 1fr;
  gap: 16px;
}
.grille-3, .grille-2 { gap: 20px; }

@media (min-width: 700px) {
  .grille-2, .grille-3, .grille-4 { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 1000px) {
  .grille-3 { grid-template-columns: repeat(3, 1fr); }
  /* auto-fit et non repeat(4) : ces grilles reçoivent parfois trois éléments —
     trois solutions, trois actualités — et une piste vide laissait un trou à
     droite. Le minimum de 220 px garantit quatre colonnes quand il y a quatre
     éléments, la largeur utile étant de 1240 px. */
  .grille-4 { grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); }
}

/* --- cartes secteur ------------------------------------------------------ */

.carte-secteur {
  position: relative;
  background: #fff;
  border: 1px solid var(--ligne);
  border-radius: var(--rayon-carte);
  padding: 28px 24px 22px;
  min-height: 240px;
  display: flex;
  flex-direction: column;
  text-decoration: none;
  transition: transform .18s var(--courbe), border-color .18s var(--courbe), box-shadow .18s var(--courbe);
}
.carte-secteur:hover {
  transform: translateY(-4px);
  border-color: var(--orange);
  box-shadow: 0 12px 28px rgba(51, 49, 49, .09);
}
.carte-secteur:hover .pastille { background: var(--orange); color: #fff; }

/* Filet orange, effet de signature de la carte métier. Il est visible partout
   et en permanence — 34 px, comme celui de .stat — et ne se remplit au survol
   que là où un vrai pointeur existe et où la carte est assez large.
   L’animation porte sur transform, jamais sur width : seules opacity et
   transform sont animées dans les apparitions et les décors. Les changements
   d’état au pointeur transitionnent aussi couleur et bordure, qui ne
   déclenchent aucun recalcul de mise en page. */
.carte-secteur::before {
  content: "";
  display: block;
  height: 3px;
  width: 34px;
  margin-bottom: 18px;
  background: var(--orange);
  transform-origin: left center;
  transition: transform .3s var(--courbe);
}

@media (min-width: 1000px) and (hover: hover) {
  .carte-secteur::before { width: 100%; transform: scaleX(.11); }
  .carte-secteur:hover::before,
  .carte-secteur:focus-visible::before { transform: scaleX(1); }
}
.carte-secteur h3 { margin-bottom: 10px; font-size: 22px; }
.carte-secteur p { color: var(--gris); font-size: 14.5px; flex: 1; }
.carte-secteur .lien-fl { margin-top: 20px; }

/* Image du métier, en tête de carte et bord à bord. Elle passe avant le filet
   orange — le ::before est lui aussi un élément de la colonne flex, d’où
   order: -1 — et annule le rembourrage de la carte par des marges négatives.
   Ses coins hauts épousent ceux de la carte : rayon intérieur, la bordure de
   1 px déduite. Au survol, elle s’agrandit à peine, comme la vignette des
   articles, contenue par son propre overflow: hidden. */
.carte-secteur .vignette {
  order: -1;
  display: block;
  margin: -28px -24px 22px;
  aspect-ratio: 16 / 10;
  overflow: hidden;
  border-radius: calc(var(--rayon-carte) - 1px) calc(var(--rayon-carte) - 1px) 0 0;
  border-bottom: 1px solid var(--ligne);
  background: var(--sable-2);
}
.carte-secteur .vignette img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform .4s var(--courbe);
}
.carte-secteur:hover .vignette img,
.carte-secteur:focus-visible .vignette img { transform: scale(1.03); }

.pastille {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 36px;
  padding: 0 13px;
  border-radius: var(--rayon-bouton);
  background: var(--orange-pale);
  color: var(--orange-fonce);
  font-size: 12.5px;
  font-weight: 800;
  letter-spacing: .08em;
  margin-bottom: 20px;
  align-self: flex-start;
  transition: background .18s var(--courbe), color .18s var(--courbe);
}

/* --- cartes service ------------------------------------------------------ */

.service {
  background: #fff;
  border: 1px solid var(--ligne);
  border-radius: var(--rayon-carte);
  padding: 24px 20px 20px;
  display: flex;
  flex-direction: column;
  transition: border-color .18s var(--courbe);
}
.service:hover { border-color: var(--orange); }
/* Pictogramme de la prestation, dessiné en SVG en ligne dans l'esprit de ceux
   du site actuel (src/templates/pictogrammes/). Il prend la couleur du texte :
   l'orange de la charte, sans pastille de fond. Hauteur commune de 56 px, la
   largeur suit chaque dessin. */
.service .icone {
  display: block;
  color: var(--orange);
  margin-bottom: 18px;
}
.service h3 { font-size: 17px; margin-bottom: 14px; letter-spacing: -.01em; }
.service ul { list-style: none; flex: 1; }
.service li {
  font-size: 13.5px;
  color: var(--gris);
  padding: 6px 0;
  border-bottom: 1px solid var(--ligne-claire);
}
.service li:last-child { border-bottom: 0; }
.service .lien-fl { margin-top: 16px; }

/* Sur téléphone, chaque carte a sa ligne : son contenu est centré, du
   pictogramme au lien. Les filets entre les mots-clés gardent toute la
   largeur de la carte, seul le texte se centre. */
@media (max-width: 699px) {
  .service { text-align: center; }
  .service .icone svg { margin-inline: auto; }
  .service .lien-fl { align-self: center; }
}

/* --- cartes produit ------------------------------------------------------ */

.produit {
  background: #fff;
  border: 1px solid var(--ligne);
  border-radius: var(--rayon-carte);
  border-top: 3px solid var(--orange);
  padding: 24px;
  display: flex;
  flex-direction: column;
}
/* Logo de l'éditeur sur lequel repose la solution. La taille d'affichage est
   la moitié de celle du fichier : net sur un écran à double densité. */
.produit-logo { margin-bottom: 16px; }
.produit h3 { font-size: 16.5px; margin-bottom: 8px; }
.produit p { font-size: 13.5px; color: var(--gris); }
.produit ul { list-style: none; margin-top: 14px; flex: 1; }
.produit li {
  font-size: 13px;
  color: var(--gris);
  padding-left: 16px;
  position: relative;
  margin-bottom: 6px;
}
.produit li::before {
  content: "";
  position: absolute;
  left: 0; top: 8px;
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--orange);
}

/* --- blocs de texte en colonnes ------------------------------------------ */

.bloc {
  background: #fff;
  border: 1px solid var(--ligne);
  border-radius: var(--rayon-carte);
  padding: 26px 24px;
}
.bloc h3 { font-size: 17.5px; margin-bottom: 10px; }
.bloc p { color: var(--gris); font-size: 14.5px; }

.bloc .numero {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 34px; height: 34px;
  border-radius: 50%;
  background: var(--orange-pale);
  color: var(--orange-fonce);
  font-weight: 800;
  font-size: 14px;
  margin-bottom: 16px;
}

/* --- bascule avant / après (pages métier) ---------------------------------
   Le même bloc, deux registres : filet éteint pour le constat, filet orange
   pour la réponse. Aucune taille, aucune police, aucun fond ne change — le
   registre « éteint » sur fond sable ne donnait que 1,08:1, il est abandonné.
   -------------------------------------------------------------------------- */
.avant .bloc::before,
.apres .bloc::before {
  content: "";
  display: block;
  width: 34px; height: 3px;
  margin-bottom: 14px;
  background: var(--gris-clair);
  transform-origin: 0 50%;
}
.apres .bloc::before { background: var(--orange); }

/* Sûr par construction : le filet est tracé par défaut. Il n’est rembobiné que
   si le script a posé « apparition », donc seulement s’il peut le rendre.
   Délai de carte + 500 ms, sans quoi le filet se tracerait sous une carte
   encore à 8 % d’opacité, dont le pseudo-élément hérite. */
.apres.apparition .bloc::before { transform: scaleX(0); }
.apres.apparition.vu .bloc::before { transform: none; transition: transform .45s var(--courbe) 660ms; }
.apres.apparition.vu .bloc:nth-child(2)::before   { transition-delay: 715ms; }
.apres.apparition.vu .bloc:nth-child(3)::before   { transition-delay: 770ms; }
.apres.apparition.vu .bloc:nth-child(4)::before   { transition-delay: 825ms; }
.apres.apparition.vu .bloc:nth-child(n+5)::before { transition-delay: 880ms; }

/* Liste à puces orange, réutilisée sur les pages métier et service */
.liste-points { list-style: none; }
.liste-points li {
  position: relative;
  padding-left: 22px;
  margin-bottom: 10px;
  color: var(--gris);
  font-size: 15.5px;
}
.liste-points li::before {
  content: "";
  position: absolute;
  left: 0; top: 9px;
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--orange);
}

/* Étiquettes de documents gérés */
.etiquettes { display: flex; flex-wrap: wrap; gap: 9px; }
.etiquette {
  background: #fff;
  border: 1px solid var(--ligne);
  border-radius: 999px;
  padding: 8px 16px;
  font-size: 13.5px;
  color: var(--anthracite-2);
}

/* --- étude de cas -------------------------------------------------------- */

.cas .interieur {
  display: grid;
  grid-template-columns: 1fr;
  gap: 32px;
  align-items: center;
}
@media (min-width: 900px) {
  .cas .interieur { grid-template-columns: 1fr 1.15fr; gap: 56px; }
}

.visuel {
  background: repeating-linear-gradient(115deg, #EFEDEA, #EFEDEA 20px, #E8E5E1 20px, #E8E5E1 40px);
  border: 1px solid var(--ligne);
  border-radius: var(--rayon-carte);
  aspect-ratio: 4 / 3;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--anthracite-2);
  font-family: var(--mono);
  font-size: 11.5px;
  letter-spacing: .12em;
  text-align: center;
  padding: 20px;
}

blockquote {
  font-size: clamp(22px, 3vw, 34px);
  font-weight: 800;
  letter-spacing: -.03em;
  line-height: 1.2;
  margin-bottom: 18px;
}
blockquote em { color: var(--orange); font-style: normal; }
.attribution { color: var(--gris); font-size: 15px; margin-bottom: 24px; }

/* --- bandeaux déroulants --------------------------------------------------
   Références et partenaires. La bande défile pour de vrai : overflow-x et
   scroll-snap, c’est-à-dire le défilement du navigateur. Le doigt, le trackpad,
   la molette et les flèches du clavier fonctionnent donc sans une ligne de
   script, et le script n’a plus qu’à demander scrollBy(). Rien n’est jamais
   positionné en JavaScript : aucune carte ne reçoit de coordonnées.
   Un clic sur une flèche fige la rotation : c’est l’arrêt qu’exige WCAG 2.2.2
   de niveau A.
   -------------------------------------------------------------------------- */

.carrousel-piste {
  display: flex;
  gap: 12px;
  list-style: none;
  overflow-x: auto;
  /* Un geste horizontal arrivé au bout de la bande ne doit pas reculer dans
     l’historique du navigateur. */
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  /* Place pour le soulèvement et l’ombre portée des jetons au survol : un
     conteneur défilant rogne tout ce qui dépasse de sa boîte. */
  padding: 4px 0 10px;
  /* Pas de barre de défilement : la bande boucle, elle n’a donc pas de
     position à indiquer, et le curseur trahirait le retour d’un tour que le
     script opère aux extrémités. Les flèches restent le repère. */
  scrollbar-width: none;
}

/* Toutes les cartes ont la même largeur : c’est ce qui rend le pas de la
   rotation régulier. Le JavaScript mesure ce pas dans la page plutôt que de le
   redire ici, et scroll-snap rattrape de lui-même un pas devenu faux après un
   changement d’orientation — le défilement s’arrête toujours sur une carte. */
/* Une carte par écran : la largeur est celle de la bande, jamais une mesure en
   vw. La hauteur minimale tient les quinze cartes au même gabarit, quelle que
   soit la longueur du nom. */
.carrousel-piste > li {
  flex: 0 0 100%;
  scroll-snap-align: start;
  display: flex;
  min-height: 176px;
}
.carrousel-piste > li > * { width: 100%; height: 100%; }

@media (min-width: 760px) {
  .carrousel-piste > li { min-height: 210px; }
}

@media (prefers-reduced-motion: no-preference) {
  .carrousel-piste { scroll-behavior: smooth; }
}

/* Carte de bandeau, commune aux références et aux partenaires : le logo en
   grand, lien vers le site du client ou de l’éditeur, une légende au-dessous
   — l’activité du client, le rôle du partenaire — et le nom en infobulle au
   survol (voir plus bas). */
/* Contenu calé en haut, pas centré : les cartes d'une bande ont toutes la
   hauteur de la plus haute (deux partenaires ont un lien de plus), et un
   contenu centré ferait descendre le logo des cartes courtes — il sauterait
   d'une carte à l'autre pendant la rotation, loin de son infobulle. */
.jeton-logo {
  background: var(--sable-2);
  border: 1px solid var(--ligne);
  border-radius: var(--rayon-carte);
  padding: 32px 24px;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  gap: 12px;
  text-align: center;
}
.jeton-logo .nom {
  font-size: clamp(23px, 3.4vw, 38px);
  font-weight: 800;
  letter-spacing: -.03em;
  line-height: 1.1;
  text-wrap: balance;
}
.jeton-logo .metier {
  color: var(--orange-fonce);
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: .13em;
  text-transform: uppercase;
}

/* Le logo, 1,75 fois sa taille de la page Références. La zone a la même
   hauteur sur toutes les cartes, quelle que soit la forme du logo : la légende
   ne saute pas d'une carte à l'autre pendant la rotation. La carte déroge à la
   règle « 100 % de la carte » des enfants de bande : avec elle, la légende
   prenait toute la hauteur de la carte et la zone du logo, comprimée,
   retombait à la hauteur de chaque image. */
.carrousel-piste > .jeton-logo > * { height: auto; }
.jeton-logo > .jeton-logo-lien {
  width: auto;
  height: 112px;
  display: flex;
  align-items: center;
}

/* Le nom laisse la place au logo et n'apparaît qu'au survol de la
   carte ou au focus clavier du logo, en infobulle posée dans la marge haute de
   la carte : elle ne recouvre jamais le logo, même le plus haut (armoiries du
   diocèse), donc rien n'est masqué et aucune touche Échap n'est requise
   (WCAG 1.4.13). Survoler la carte suspend aussi la rotation : le nom reste
   lisible le temps qu'il faut. Le texte reste dans la page — opacity ne le
   retire pas aux lecteurs d'écran.
   Sans survol possible (écran tactile), le nom reste affiché sous le logo, en
   plus petit : il n'y aurait sinon aucun moyen de le lire. */
@media (hover: hover) {
  .jeton-logo {
    position: relative;
    padding-top: 54px;
  }
  .jeton-logo > .nom {
    position: absolute;
    top: 10px;
    left: 50%;
    width: max-content;
    max-width: calc(100% - 48px);
    height: auto;
    padding: 6px 14px;
    background: var(--anthracite);
    border-radius: var(--rayon-bouton);
    color: #fff;
    font-size: 15px;
    font-weight: 700;
    letter-spacing: 0;
    line-height: 1.35;
    opacity: 0;
    transform: translate(-50%, 4px);
    transition: opacity .18s var(--courbe), transform .18s var(--courbe);
    pointer-events: none;
  }
  /* Pointe de l'infobulle, tournée vers le logo. */
  .jeton-logo > .nom::after {
    content: "";
    position: absolute;
    top: 100%;
    left: 50%;
    margin-left: -6px;
    border: 6px solid transparent;
    border-bottom: 0;
    border-top-color: var(--anthracite);
  }
  .jeton-logo:hover > .nom,
  .jeton-logo:focus-within > .nom {
    opacity: 1;
    transform: translate(-50%, 0);
  }
}

@media (hover: none) {
  .jeton-logo .nom { font-size: 19px; }
}

/* --- commandes du bandeau ------------------------------------------------- */

.carrousel-commandes {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 16px;
}

.carrousel-fleche {
  width: 42px; height: 42px;
  display: grid;
  place-items: center;
  background: var(--sable-2);
  border: 1px solid var(--ligne);
  border-radius: 50%;
  color: var(--anthracite);
  font-size: 21px;
  line-height: 1;
}
/* Le chevron vient du CSS : le bouton n’a pas de texte, son nom accessible est
   porté par aria-label et diffère d’un bandeau à l’autre. */
.carrousel-fleche::before { content: "\203A"; }
.carrousel-fleche[data-carrousel="prec"]::before { content: "\2039"; }
.carrousel-fleche:hover { border-color: var(--orange); color: var(--orange-fonce); }

/* --- partenaires --------------------------------------------------------- */

/* Carte partenaire : la carte de bandeau commune (.jeton-logo), avec le rôle
   en phrase entière sous le logo. Le logo mène au site de l’éditeur ; quand le
   site de Sanjco a une page sur le partenaire (M-Files, Dina), un lien fléché
   y conduit sous le rôle — la carte entière ne peut plus être ce lien, elle
   en contient déjà un. */
.jeton-logo .role {
  color: var(--gris);
  font-size: 15px;
  line-height: 1.5;
  max-width: 52ch;
}
.jeton-logo > .lien-fl { width: auto; }

/* Partenaire sans logo : le nom reste en toutes lettres, à la place du logo,
   au survol comme au repos. La règle l'emporte sur l'infobulle (même
   spécificité augmentée de .sans-logo), écran tactile compris. */
.jeton-logo.sans-logo { padding-top: 32px; justify-content: center; }
.jeton-logo.sans-logo > .nom {
  position: static;
  width: 100%;
  padding: 0;
  background: none;
  color: inherit;
  font-size: clamp(23px, 3.4vw, 38px);
  font-weight: 800;
  letter-spacing: -.03em;
  line-height: 1.1;
  opacity: 1;
  transform: none;
}
.jeton-logo.sans-logo > .nom::after { content: none; }

/* --- actualités ---------------------------------------------------------- */

.article-carte {
  background: #fff;
  border: 1px solid var(--ligne);
  border-radius: var(--rayon-carte);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  text-decoration: none;
  transition: border-color .18s var(--courbe), box-shadow .18s var(--courbe);
}
.article-carte:hover {
  border-color: var(--orange);
  box-shadow: 0 12px 28px rgba(51, 49, 49, .08);
}
/* La vignette s’agrandit légèrement au survol, contenue par l’overflow: hidden
   de la carte. Seul transform est animé, donc aucun recalcul de mise en page. */
.article-carte .vignette {
  aspect-ratio: 16 / 9;
  background: repeating-linear-gradient(115deg, #F4F2EF, #F4F2EF 18px, #EDEAE6 18px, #EDEAE6 36px);
  border-bottom: 1px solid var(--ligne);
  transition: transform .4s var(--courbe);
}
.article-carte:hover .vignette,
.article-carte:focus-visible .vignette { transform: scale(1.03); }
.article-carte .texte { padding: 20px; flex: 1; display: flex; flex-direction: column; }
.article-carte .categorie {
  color: var(--orange-fonce);
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: .07em;
  text-transform: uppercase;
}
.article-carte h2,
.article-carte h3 { font-size: 16px; font-weight: 700; letter-spacing: -.01em; line-height: 1.3; margin-top: 8px; margin-bottom: 0; }
.article-carte p { font-size: 13.5px; color: var(--gris); margin-top: 8px; flex: 1; }
.article-carte .meta { font-size: 12.5px; color: var(--gris); margin-top: 14px; }

/* --- ce qui répond à la souris répond au clavier --------------------------
   108 px : l’en-tête collant fait 78 px ; au Maj+Tab, la carte remonterait
   sinon sous l’en-tête (WCAG 2.4.11). C’est la seule déclaration de
   scroll-margin-top pour ces trois sélecteurs.
   -------------------------------------------------------------------------- */
.carte-secteur, .service, .article-carte { scroll-margin-top: 108px; }

.carte-secteur:focus-visible {
  transform: translateY(-4px);
  border-color: var(--orange);
  box-shadow: 0 12px 28px rgba(51, 49, 49, .09);
}
.carte-secteur:focus-visible .pastille { background: var(--orange); color: #fff; }

/* .article-carte est un lien, d’où :focus-visible ; .service n’en est pas un. */
.article-carte:focus-visible { border-color: var(--orange); }
.service:focus-within { border-color: var(--orange); }

/* --- retour dans la liste : « vous étiez ici » ----------------------------
   L’anneau est un ::after dont on n’anime que l’opacity : la contrainte
   « seules opacity et transform » tient, et la carte ne bouge pas d’un pixel.
   inset: 0 et non -3px — .article-carte porte overflow: hidden et rognerait un
   anneau extérieur sur trois bords. Le halo dure 2,4 s, bien sous les cinq
   secondes de WCAG 2.2.2, et il ne démarre que sur une action du visiteur.
   -------------------------------------------------------------------------- */
.article-carte { position: relative; }

.carte-secteur::after,
.article-carte::after {
  content: "";
  position: absolute;
  inset: 0;
  border: 3px solid var(--orange);
  border-radius: inherit;
  opacity: 0;
  pointer-events: none;
}

@media (prefers-reduced-motion: no-preference) {
  .carte-secteur:target::after,
  .article-carte:target::after { animation: halo-retour 2.4s var(--courbe) both; }

  @keyframes halo-retour {
    from { opacity: 1; }
    to   { opacity: 0; }
  }
}

/* Sous mouvement réduit, le repère reste — immobile et permanent. La fonction
   est l’orientation, pas l’animation. */
@media (prefers-reduced-motion: reduce) {
  .carte-secteur:target::after,
  .article-carte:target::after { opacity: 1; }
}

/* --- corps d'article ----------------------------------------------------- */

.article { padding: 46px var(--marge) 72px; }
.article .interieur { max-width: 760px; }

.prose { font-size: 17px; color: var(--anthracite-2); }
.prose > * + * { margin-top: 20px; }
.prose h2 {
  font-size: 25px;
  margin-top: 42px;
  margin-bottom: 0;
  letter-spacing: -.02em;
}
.prose h3 { font-size: 19px; margin-top: 30px; }
.prose ul, .prose ol { padding-left: 22px; }
.prose li { margin-bottom: 8px; }
.prose li::marker { color: var(--orange); }
.prose strong { color: var(--anthracite); font-weight: 700; }
.prose blockquote {
  font-size: 19px;
  font-weight: 500;
  letter-spacing: 0;
  line-height: 1.5;
  border-left: 3px solid var(--orange);
  padding-left: 20px;
  color: var(--gris);
}
.prose a { color: var(--orange-fonce); }

/* --- filtres (références, actualités) ------------------------------------ */

.filtres {
  display: flex;
  gap: 9px;
  flex-wrap: wrap;
  margin-bottom: 28px;
}
.filtres button {
  background: #fff;
  border: 1px solid var(--ligne);
  border-radius: 999px;
  padding: 9px 18px;
  font-size: 14px;
  font-weight: 500;
  color: var(--anthracite-2);
}
.filtres button:hover { border-color: var(--anthracite); }
.filtres button[aria-pressed="true"] {
  background: var(--anthracite);
  border-color: var(--anthracite);
  color: #fff;
  font-weight: 600;
}

.reference {
  background: #fff;
  border: 1px solid var(--ligne);
  border-radius: var(--rayon-carte);
  padding: 24px;
  display: flex;
  flex-direction: column;
}
/* Logo du client, lien vers son site. Zone de hauteur fixe : les noms
   s'alignent d'une carte à l'autre, quelle que soit la forme du logo. Le lien
   épouse la largeur du logo, pas celle de la carte : seule l'image est
   cliquable. Tailles : outils/generer-logos-bandeaux.php. */
.reference-logo {
  align-self: flex-start;
  display: flex;
  align-items: center;
  height: 64px;
  margin-bottom: 18px;
}
.reference-logo,
.jeton-logo-lien { transition: transform .18s var(--courbe); }
.reference-logo:hover,
.jeton-logo-lien:hover { transform: translateY(-2px); }

.reference h2 { font-size: 16.5px; font-weight: 700; letter-spacing: -.01em; line-height: 1.3; margin-bottom: 4px; }
.reference .activite {
  color: var(--orange-fonce);
  font-size: 13px;
  font-weight: 600;
  margin-bottom: 12px;
}
.reference p { color: var(--gris); font-size: 14px; }
.reference > p:last-of-type { flex: 1; }
.reference .resultat {
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px solid var(--ligne-claire);
  color: var(--anthracite);
  font-size: 14px;
  font-weight: 600;
}
.reference .produit-nom {
  display: inline-block;
  margin-top: 12px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .06em;
  color: var(--orange-fonce);
  background: var(--orange-pale);
  border-radius: var(--rayon-bouton);
  padding: 5px 10px;
  align-self: flex-start;
}
.vide { color: var(--gris); font-size: 15.5px; }

/* Le compte change sans bouger : on le fait cligner une fois. Le nom est
   « compte-maj » et non « maj » — .maj existe déjà sur les pages légales. */
@media (prefers-reduced-motion: no-preference) {
  .compte-maj { animation: compte-maj .5s var(--courbe); }

  @keyframes compte-maj {
    from { opacity: .25; transform: translateY(-3px); }
  }
}

/* Aiguillage : la page Références n’avait aucun lien hors fil d’Ariane. */
.aiguillage { margin-top: 40px; }
.aiguillage h2 { font-size: 17.5px; margin-bottom: 12px; }
/* Sans list-style, la puce se peindrait hors de la boîte : le reset universel
   met le rembourrage à zéro. */
.aiguillage li { list-style: none; margin-bottom: 8px; }

/* --- questions fréquentes ------------------------------------------------ */

.faq { max-width: 780px; }
.faq details {
  border-bottom: 1px solid var(--ligne);
  padding: 18px 0;
}
.faq summary {
  cursor: pointer;
  font-weight: 700;
  font-size: 16.5px;
  list-style: none;
  display: flex;
  justify-content: space-between;
  gap: 16px;
  align-items: flex-start;
}
.faq summary::-webkit-details-marker { display: none; }
/* Le chevron pivote : content n’est pas animable, une rotation l’est. La boîte
   est carrée pour que le glyphe tourné ne sorte pas de son emplacement — le
   pseudo-élément est un enfant flex en flex-shrink: 0, rien ne le retiendrait. */
.faq summary::after {
  content: "\203A";
  color: var(--orange-fonce);
  font-size: 22px;
  line-height: 1;
  flex-shrink: 0;
  width: 22px;
  text-align: center;
  transform: rotate(90deg);
  transition: transform .25s var(--courbe);
}
.faq details[open] summary::after { transform: rotate(-90deg); }
.faq details p { color: var(--gris); font-size: 15.5px; margin-top: 12px; max-width: 70ch; }

/* La garde teste les DEUX dépendances de la règle : le sélecteur et le mode de
   transition discret. Sans elle, un panneau pourrait rester à opacité nulle,
   c’est-à-dire du contenu perdu. Le panneau garde son ouverture instantanée :
   l’animer imposerait d’interpoler une hauteur. */
@supports selector(details::details-content) and (transition-behavior: allow-discrete) {
  .faq details::details-content {
    opacity: 0;
    transition: opacity .25s var(--courbe), content-visibility .25s allow-discrete;
  }
  .faq details[open]::details-content { opacity: 1; }

  @starting-style {
    .faq details[open]::details-content { opacity: 0; }
  }
}

/* --- formulaire ---------------------------------------------------------- */

.formulaire {
  background: #fff;
  border: 1px solid var(--ligne);
  border-radius: var(--rayon-carte);
  padding: 26px 22px;
}
@media (min-width: 760px) { .formulaire { padding: 34px 32px; } }

.champs { display: grid; grid-template-columns: 1fr; gap: 18px; }
@media (min-width: 700px) {
  .champs { grid-template-columns: repeat(2, 1fr); }
  .champ-large { grid-column: 1 / -1; }
}

.champ label {
  display: block;
  font-size: 14px;
  font-weight: 600;
  margin-bottom: 7px;
}
.champ .facultatif { font-weight: 400; color: var(--gris); }

.champ input,
.champ select,
.champ textarea {
  width: 100%;
  font-family: inherit;
  font-size: 15.5px;
  color: var(--anthracite);
  background: var(--papier);
  border: 1px solid var(--ligne);
  border-radius: var(--rayon-bouton);
  padding: 12px 14px;
}
.champ textarea { min-height: 150px; resize: vertical; }
.champ input:hover, .champ select:hover, .champ textarea:hover { border-color: var(--gris-clair); }
.champ input[aria-invalid="true"],
.champ select[aria-invalid="true"],
.champ textarea[aria-invalid="true"] { border-color: var(--orange); background: var(--orange-pale); }

/* Retour immédiat sur un champ mal rempli. Confort visuel redondant, jamais un
   remplacement : l’information reste portée par aria-invalid et le
   <span class="erreur"> écrits par le serveur. select est absent — toutes les
   <option> de #sujet ont une valeur, le champ ne peut pas être invalide. */
.champ input:user-invalid,
.champ textarea:user-invalid { border-color: var(--orange); background: var(--orange-pale); }

.champ .erreur {
  display: block;
  margin-top: 6px;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--orange-fonce);
}

.case { display: flex; gap: 11px; align-items: flex-start; }
.case input { width: 18px; height: 18px; flex-shrink: 0; margin-top: 3px; }
.case label { font-weight: 400; font-size: 14px; color: var(--gris); margin-bottom: 0; }
.case a { color: var(--orange-fonce); }

/* Champ piège anti-robot : retiré du flux et de l'ordre de tabulation */
.piege {
  position: absolute;
  left: -9999px;
  opacity: 0;
  height: 0;
}

.message {
  border-radius: var(--rayon-carte);
  padding: 18px 20px;
  margin-bottom: 26px;
  font-size: 15.5px;
  border: 1px solid;
}
.message-succes { background: #F0F7F3; border-color: #BFDCCC; color: #14603A; }
.message-erreur { background: var(--orange-pale); border-color: #F0C4AF; color: var(--orange-fonce); }

/* --- appel à l'action final ---------------------------------------------- */

.cta-final { background: var(--orange-ui); color: #fff; padding: 58px var(--marge); }

/* L’appel final devient une grande carte : le fond de page sable apparaît sur
   ses quatre côtés. Règle séparée, qui ne touche ni au fond orange ni au
   color: #fff de la règle ci-dessus. */
.cta-final {
  margin: 0 12px;
  border-radius: var(--rayon-bloc);
}

.cta-final .interieur {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 28px;
  flex-wrap: wrap;
}
.cta-final h2 { color: #fff; margin-bottom: 8px; max-width: 20ch; }
.cta-final p { font-size: 16.5px; max-width: 46ch; }
@media (min-width: 760px) {
  .cta-final {
    padding: 76px var(--marge);
    margin: 0 16px;
  }
}

/* --- pied de page -------------------------------------------------------- */

/* Le pied est lui aussi une grande carte : le fond sable du body l’entoure. */
footer {
  background: var(--anthracite);
  color: #C6C3C1;
  border-radius: var(--rayon-bloc);
  margin: 0 12px 12px;
  padding: 56px var(--marge) 28px;
}

@media (min-width: 760px) {
  footer { margin: 0 16px 16px; padding: 88px var(--marge) 32px; }
}

.pied-haut {
  max-width: var(--largeur);
  margin: 0 auto 38px;
  padding-bottom: 34px;
  border-bottom: 1px solid #474443;
}
.pied-haut p {
  color: #fff;
  font-size: clamp(20px, 2.4vw, 28px);
  font-weight: 800;
  letter-spacing: -.025em;
  max-width: 24ch;
}
.pied-haut .courriel {
  margin-top: 16px;
  color: #FF8A4C;
  font-weight: 600;
  text-decoration: none;
  font-size: 16px;
}
.pied-haut .courriel:hover { text-decoration: underline; }

.pied {
  max-width: var(--largeur);
  margin: 0 auto;
  display: grid;
  grid-template-columns: 1fr;
  gap: 28px;
  font-size: 14px;
}
@media (min-width: 700px) { .pied { grid-template-columns: repeat(2, 1fr); gap: 32px; } }
@media (min-width: 1000px) { .pied { grid-template-columns: 1.3fr 1fr 1fr 1fr; } }

.pied h2 {
  color: #fff;
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  margin-bottom: 16px;
}
.pied li { list-style: none; }
.pied a { color: #C6C3C1; text-decoration: none; }
.pied a:hover { color: #fff; text-decoration: underline; }
.pied .bureau { color: #fff; font-weight: 600; margin-bottom: 4px; }
.pied address { font-style: normal; }

.pied-bas {
  max-width: var(--largeur);
  margin: 38px auto 0;
  padding-top: 22px;
  border-top: 1px solid #474443;
  display: flex;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  font-size: 13px;
}
.pied-bas a { color: #C6C3C1; }

/* Vrai lien d’ancre vers le contenu principal, donc opérant sans JavaScript.
   Le cerne de focus blanc lui vient déjà de « footer :focus-visible ».
   Le sélecteur est porté à deux classes pour passer devant la règle de cible
   tactile « .pied-bas a », qui impose sinon un display: inline-block. */
.pied-bas .pied-remonter {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-weight: 600;
  text-decoration: none;
}
.pied-bas .pied-remonter:hover { color: #fff; text-decoration: underline; }
.pied-bas .pied-remonter::after { content: "\2191"; }

/* --- badge de partenaire M-Files -----------------------------------------
   Sur toutes les pages (partials/pied.twig). Fixé en bas à gauche de la
   fenêtre, il reste visible pendant tout le défilement ; sur l'accueil, il se
   pose à l'arrivée sur le coin de la photo. Carte blanche, car le logo, sur
   fond transparent, serait illisible sur la photo et sur le pied anthracite.
   Il passe au-dessus des sections (z-index 1) et sous l'en-tête (60), donc
   sous le panneau du menu mobile. pointer-events: none laisse passer les clics
   vers ce qu'il recouvre : une image seule n'a rien à intercepter.
   Écran seulement : sur papier, un élément fixe se répète à chaque feuille.
   -------------------------------------------------------------------------- */

@media screen {
  .badge-partenaire {
    position: fixed;
    left: 12px;
    bottom: 12px;
    z-index: 50;
    margin: 0;
    padding: 8px 11px;
    background: #fff;
    border-radius: var(--rayon-carte);
    box-shadow: 0 4px 18px rgba(24, 22, 21, .22);
    line-height: 0;
    pointer-events: none;
  }
  .badge-partenaire img { width: 112px; }

  /* Tant que le badge est là, le bas de page lui laisse sa place : une fois
     la page défilée jusqu'au bout, la dernière ligne du pied, qui porte
     « Remonter en haut de la page » à gauche, finit au-dessus de lui.
     scroll-padding-bottom retire la même bande de la zone où le navigateur
     amène un élément qu'il fait défiler jusqu'à l'écran, au clavier
     notamment : un lien atteint par Tab s'arrête au-dessus du badge au lieu
     de glisser dessous (WCAG 2.4.11). */
  :root:has(.badge-partenaire) { scroll-padding-bottom: 66px; }
  :root:has(.badge-partenaire) footer { padding-bottom: 56px; }
}

@media screen and (min-width: 760px) {
  .badge-partenaire { left: 16px; bottom: 16px; padding: 10px 14px; }
  .badge-partenaire img { width: 150px; }
  :root:has(.badge-partenaire) { scroll-padding-bottom: 86px; }
  :root:has(.badge-partenaire) footer { padding-bottom: 72px; }
}

@media print {
  .badge-partenaire { display: none; }
}

/* --- bandeau « contenu de démonstration » -------------------------------- */

.avis-demo {
  background: var(--anthracite);
  color: #fff;
  font-size: 13px;
  padding: 9px var(--marge);
  text-align: center;
}
.avis-demo b { color: #FF8A4C; }
/* L'avertissement de licence a sa propre ligne : il ne se perd pas au milieu
   de la note sur le prototype. */
.avis-licence { display: block; margin-top: 2px; }

.demo {
  display: inline-block;
  vertical-align: middle;
  background: var(--sable-2);
  border: 1px solid var(--ligne);
  border-radius: 3px;
  color: var(--gris);
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: .08em;
  text-transform: uppercase;
  padding: 2px 6px;
  margin-left: 8px;
}

/* --- page 404 ------------------------------------------------------------ */

.erreur-404 { padding: 90px var(--marge) 110px; text-align: center; }
.erreur-404 .code {
  font-family: var(--mono);
  font-size: 13px;
  letter-spacing: .18em;
  color: var(--orange-fonce);
  margin-bottom: 16px;
}
.erreur-404 h1 { font-size: clamp(28px, 4vw, 42px); font-weight: 800; letter-spacing: -.03em; }
.erreur-404 p { color: var(--gris); font-size: 17px; margin: 16px auto 0; max-width: 52ch; }
.erreur-404 .rangee-cta { justify-content: center; }

/* --- pages légales ------------------------------------------------------- */

.legal { padding: 46px var(--marge) 78px; }
.legal .interieur {
  max-width: 1040px;
  display: grid;
  grid-template-columns: 1fr;
  gap: 36px;
  align-items: start;
}
@media (min-width: 1000px) {
  .legal .interieur { grid-template-columns: 240px 1fr; gap: 56px; }
  .legal .sommaire { position: sticky; top: 96px; }
}

.sommaire h2 {
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--gris);
  margin-bottom: 14px;
}
.sommaire ol { list-style: none; counter-reset: som; }
.sommaire li { counter-increment: som; }
.sommaire a {
  color: var(--anthracite-2);
  text-decoration: none;
  font-size: 14px;
}
.sommaire a::before { content: counter(som) ". "; color: var(--gris); }
.sommaire a:hover { color: var(--orange-fonce); }

.legal article > section {
  padding: 0;
  margin-bottom: 34px;
  scroll-margin-top: 92px;
}
.legal article h2 { font-size: 21px; margin-bottom: 12px; }
.legal article p { color: var(--anthracite-2); font-size: 15.5px; margin-bottom: 12px; max-width: 72ch; }
.legal article ul { padding-left: 22px; margin-bottom: 12px; color: var(--anthracite-2); font-size: 15.5px; }
.legal article li { margin-bottom: 7px; }
.legal article li::marker { color: var(--orange); }
.legal .maj { color: var(--gris); font-size: 14px; }

/* --- support ------------------------------------------------------------- */

.table-niveaux { width: 100%; border-collapse: collapse; font-size: 15px; }
.table-niveaux th, .table-niveaux td {
  text-align: left;
  padding: 14px 16px;
  border-bottom: 1px solid var(--ligne);
  vertical-align: top;
}
.table-niveaux th { font-size: 12.5px; letter-spacing: .08em; text-transform: uppercase; color: var(--gris); }
.table-niveaux td:first-child { font-weight: 700; white-space: nowrap; }
.table-niveaux td:last-child { color: var(--orange-fonce); font-weight: 600; white-space: nowrap; }
.defilant { overflow-x: auto; }

/* --- repères (à propos) -------------------------------------------------- */

.reperes { list-style: none; border-left: 2px solid var(--ligne); padding-left: 26px; }
.reperes li { position: relative; padding-bottom: 26px; }
.reperes li::before {
  content: "";
  position: absolute;
  left: -33px; top: 6px;
  width: 12px; height: 12px;
  border-radius: 50%;
  background: var(--orange);
  border: 3px solid var(--papier);
}
.reperes .annee { font-weight: 800; font-size: 17px; display: block; }
.reperes p { color: var(--gris); font-size: 15px; margin-top: 4px; }

/* --- ajustements de mise en page ----------------------------------------- */
/* Ces classes remplacent les attributs style en ligne dans les gabarits :
   la Content-Security-Policy déclarée dans public/.htaccess interdit le style
   en ligne, et les autoriser affaiblirait la protection pour trois marges. */

.haut         { align-items: start; }
.serre-bas    { margin-bottom: 0; }
.espace-haut  { margin-top: 20px; }
.etroit       { max-width: 840px; }
.paysage      { aspect-ratio: 16 / 10; }
.intercalaire { margin: 44px 0 16px; }

/* Colonne de blocs régulièrement espacés */
.pile > * + * { margin-top: 16px; }

/* Liens empilés au bas d'un bloc */
.liens-bloc {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 10px;
  margin-top: 14px;
}

.bloc address { font-style: normal; color: var(--gris); font-size: 14.5px; }
.bloc .detail { margin-top: 14px; font-weight: 600; font-size: 14px; color: var(--anthracite-2); }

/* Récit de la page À propos : titres et paragraphes qui s'enchaînent */
.recit h2 { margin-top: 36px; }
.recit > h2:first-child { margin-top: 0; }

.meta-article { margin-top: 18px; margin-bottom: 0; }

/* Repli de secours du menu, affiché uniquement si le JavaScript ne s'exécute pas.
   Au-delà du seuil, le menu normal est déjà visible : celui-ci s'efface. */
.menu-secours {
  display: flex;
  flex-wrap: wrap;
  gap: 12px 20px;
  padding: 14px var(--marge);
  border-top: 1px solid var(--ligne-claire);
}
.menu-secours a {
  color: var(--anthracite-2);
  text-decoration: none;
  font-size: 14.5px;
  font-weight: 500;
}
@media (min-width: 980px) {
  .menu-secours { display: none; }
}

/* --- cibles tactiles ------------------------------------------------------ */
/* WCAG 2.5.8 demande 24 px au minimum. Les listes de liens tiennent nativement
   19 à 22 px : quelques pixels de rembourrage vertical suffisent, sans modifier
   la mise en page puisque ces éléments sont centrés dans leur conteneur. */

.menu a,
.menu-secours a,
.pied a,
.pied-bas a,
.pied-haut .courriel,
.sommaire a,
.fil a,
.fil [aria-current="page"] {
  display: inline-block;
  padding-top: 4px;
  padding-bottom: 4px;
}

.lien-fl { padding-top: 4px; padding-bottom: 4px; }

.burger { min-height: 44px; }

/* Le rembourrage ajouté ci-dessus double l'espacement des listes du pied de page,
   du sommaire et du panneau du menu : on le compense. */
.pied li { margin-bottom: 2px; }
.sommaire li { margin-bottom: 2px; }
.menu.ouvert { gap: 8px; }

/* Libellé du bouton de rendez-vous, abrégé sur les écrans étroits. */
.cta-long { display: none; }
@media (min-width: 420px) {
  .cta-court { display: none; }
  .cta-long { display: inline; }
}

/* Écrans très étroits (320 px) : l'en-tête doit tenir sans défilement latéral.
   On resserre la barre plutôt que de sacrifier le bouton de rendez-vous, que le
   brief demande de garder visible à toutes les largeurs. */
@media (max-width: 379px) {
  .nav { gap: 10px; padding-left: 16px; padding-right: 16px; }
  .nav-cta { padding: 10px 11px; font-size: 13.5px; }
  .burger { padding: 9px 10px; font-size: 13.5px; }
}

/* Sur les pages juridiques traduites : la version française fait foi. */
.note-traduction {
  max-width: 68ch;
  margin-top: 18px;
  padding: 10px 14px;
  border-left: 3px solid var(--orange);
  background: var(--papier);
  color: var(--anthracite-2);
  font-size: 14px;
}

/* Note de rédaction en tête d'article : signale un texte encore à valider. */
.note-redaction {
  background: var(--sable-2);
  border-left: 3px solid var(--gris-clair);
  border-radius: 0 var(--rayon-bouton) var(--rayon-bouton) 0;
  padding: 12px 16px;
  margin-bottom: 26px;
  color: var(--gris);
  font-size: 14px;
}

/* --- apparition progressive des sections ---------------------------------
   La classe « apparition » n'est posée par le JavaScript qu'au moment où
   l'observateur signale un bloc hors de l'écran, donc seulement s'il est en
   mesure de le révéler ensuite. Aucune règle ci-dessous ne s'applique tant
   que cette preuve n'est pas faite : la page reste entièrement visible si le
   script ne s'exécute pas.
   Seuls opacity et transform sont animés : ni l'un ni l'autre ne déclenche
   de recalcul de mise en page, donc aucun décalage visuel.
   ------------------------------------------------------------------------ */

/* Les blocs de tête d'une section s'animent entiers ; les grilles laissent
   plutôt leurs cartes entrer une à une.
   Les deux listes ci-dessous se tiennent : tout conteneur nommé dans le :not()
   doit l'être aussi dans le :is(). En oublier un laisserait ses cartes à
   opacity: 0 pour toujours. */
.apparition > .interieur > *:not(.grille-2, .grille-3, .grille-4, .stats, .etiquettes),
.apparition > .interieur > :is(.grille-2, .grille-3, .grille-4, .stats, .etiquettes) > * {
  opacity: 0;
  transform: translateY(16px);
  transition: opacity .5s ease-out, transform .5s ease-out;
}

.apparition.vu > .interieur > *,
.apparition.vu > .interieur > * > * {
  opacity: 1;
  transform: none;
}

/* Cascade : surtitre, titre, chapeau, puis les cartes de la grille. */
.apparition.vu > .interieur > *:nth-child(2)   { transition-delay: 50ms; }
.apparition.vu > .interieur > *:nth-child(3)   { transition-delay: 100ms; }
.apparition.vu > .interieur > *:nth-child(n+4) { transition-delay: 140ms; }

.apparition.vu > .interieur > * > *              { transition-delay: 160ms; }
.apparition.vu > .interieur > * > *:nth-child(2) { transition-delay: 215ms; }
.apparition.vu > .interieur > * > *:nth-child(3) { transition-delay: 270ms; }
.apparition.vu > .interieur > * > *:nth-child(4) { transition-delay: 325ms; }
.apparition.vu > .interieur > * > *:nth-child(n+5) { transition-delay: 380ms; }

/* Un Tab peut atteindre un lien d’une section encore masquée : on la révèle
   sans attendre l’observateur, plutôt que d’y poser un focus invisible. */
.apparition:focus-within > .interieur > *,
.apparition:focus-within > .interieur > * > * { opacity: 1; transform: none; }

/* Filet de sécurité : si le réglage système change après le chargement,
   la règle globale coupe les transitions et laisserait tout à opacity 0.
   La dernière paire atteint les pseudo-éléments, hors de portée de « > * > * ». */
@media (prefers-reduced-motion: reduce) {
  .apparition > .interieur > *,
  .apparition > .interieur > * > * {
    opacity: 1 !important;
    transform: none !important;
  }
  .apres.apparition .bloc::before,
  .apparition .stats .stat::before { transform: none !important; }
}

/* --- en-tête : ombre au défilement, transparence sur le hero --------------
   L’en-tête ne se cache jamais : le repérage clavier en dépend (WCAG 2.4.7 et
   2.4.11), tout comme scroll-margin-top, la barre de progression et le lien
   d’évitement. La transparence est portée par une classe posée par le script :
   sans lui, aucune classe n’est posée et l’en-tête reste opaque, donc jamais
   illisible. C’est le principe « sûr par construction » appliqué à l’en-tête.
   -------------------------------------------------------------------------- */

header {
  transition: background .45s var(--courbe),
              border-color .45s ease-out,
              box-shadow .25s ease-out;
}
header.defile { box-shadow: 0 6px 20px rgba(51, 49, 49, .08); }
/* En haut de l’accueil, la barre est transparente : le hero glisse dessous
   (voir sa marge négative), c’est donc la photo qu’on voit à travers, et non
   une bande de couleur unie. Tant que la photo reste sous la barre, le script
   fait monter --givre de 0 à 1 : un voile blanc de 16 % au plus et un flou de
   10 px détachent peu à peu la barre de l’image. 16 % est le plafond qui garde
   le texte blanc au-dessus de 4,5:1 sur le pixel le plus clair du haut de la
   photo. La classe tombe quand la première section rejoint la barre : la
   barre blanche revient alors avec son ombre, en fondu (plus bas).
   Le rail de la barre de progression disparaît avec elle : à cet instant la
   lecture n’a pas commencé, il ne dessinerait qu’un trait gris sur le hero. */
header.sur-hero {
  background: rgba(255, 255, 255, calc(var(--givre, 0) * .16));
  backdrop-filter: blur(calc(var(--givre, 0) * 10px));
  border-bottom-color: transparent;
  box-shadow: none;
}
header.sur-hero .progression { opacity: 0; }

/* Sur l’accueil, la barre transparente repose sur la photographie du hero :
   logo, liens et sélecteur de langue passent en blanc.
   À l’écran seulement : sur papier, le hero n’a plus de photo et le logo
   blanc sortirait blanc sur blanc.
   Les liens ne blanchissent que dans le menu posé dans la barre, :not(.ouvert) :
   le panneau du menu mobile garde son fond sable et ses liens sombres, même
   si la fenêtre s’élargit au-delà de 980 px pendant qu’il est ouvert. */
.logo .logo-clair { display: none; }
@media screen {
  /* Les deux logos sont superposés et se relaient en fondu : display ne se
     prête à aucune transition. Ils ont les mêmes proportions. */
  header.accueil .logo { position: relative; }
  header.accueil .logo .logo-clair { display: block; position: absolute; top: 0; left: 0; opacity: 0; }
  header.accueil.sur-hero .logo .logo-sombre { opacity: 0; }
  header.accueil.sur-hero .logo .logo-clair { opacity: 1; }
  header.accueil.sur-hero .langue,
  header.accueil.sur-hero .langue a { color: rgba(255, 255, 255, .85); }
  header.accueil.sur-hero .langue a[aria-current] { color: #fff; }
  header.accueil.sur-hero .langue a:hover { color: #FF8A4C; }
  header.accueil.sur-hero .burger { color: #fff; border-color: rgba(255, 255, 255, .6); }
}
@media screen and (min-width: 980px) {
  header.accueil.sur-hero .menu:not(.ouvert) a { color: #fff; }
  header.accueil.sur-hero .menu:not(.ouvert) .lien-page { color: rgba(255, 255, 255, .85); }
  header.accueil.sur-hero .menu:not(.ouvert) a:hover { color: #FF8A4C; }
  header.accueil.sur-hero .menu:not(.ouvert) .menu-separateur { background: rgba(255, 255, 255, .4); }
}

/* Sur l’accueil, le passage au blanc est un fondu de .6 s, que fond, logos et
   couleurs suivent ensemble, à la même durée et à la même courbe : un fondu
   du seul fond montrait un logo blanc sur une barre déjà blanche, en remontant
   comme en descendant. Le survol d’un lien reste immédiat : sa couleur ne
   s’estompe qu’en sortant du survol, :not(:hover) portant la transition. */
header.accueil {
  transition: background-color .6s ease, backdrop-filter .6s ease,
              border-color .6s ease, box-shadow .6s ease;
}
header.accueil .logo img,
header.accueil .progression { transition: opacity .6s ease; }
header.accueil .langue,
header.accueil .burger { transition: color .6s ease, border-color .6s ease; }
header.accueil .langue a:not(:hover) { transition: color .6s ease; }
header.accueil .menu a { transition: transform .18s var(--courbe); }
header.accueil .menu a:not(:hover) { transition: color .6s ease, transform .18s var(--courbe); }
header.accueil .menu-separateur { transition: background-color .6s ease; }

/* Sur l'accueil, le logo est plus grand, en haut de page comme au défilement :
   la classe « accueil » est posée par le serveur et ne dépend pas de la
   position dans la page. Les autres pages gardent le logo ordinaire.
   La hauteur de la barre, fixée sur .nav, ne change pas — seule la place
   libre entre le logo et le menu est consommée, ce qui décide des paliers. Entre 980 et 1 100 px, le menu occupe déjà presque toute
   la barre : le logo n’y grandit pas. Sous 480 px non plus : à 420 px, le
   logo agrandi, le bouton du menu et celui du rendez-vous remplissaient la
   barre au pixel, sans un seul pixel d’air au-delà de la gouttière. */
@media (min-width: 480px) and (max-width: 979px) {
  header.accueil .logo img { height: 36px; }
}
@media (min-width: 1100px) {
  header.accueil .logo img { height: 44px; }
}
@media (min-width: 1240px) {
  header.accueil .logo img { height: 56px; }
}

/* --- navigation par ancres ------------------------------------------------
   Le menu principal ne contient que des ancres vers les sections de l'accueil.
   Les pages à part entière sont regroupées après un séparateur et portent un
   style plus discret : le visiteur voit avant de cliquer si le lien le déplace
   dans la page ou l'emmène ailleurs.
   ------------------------------------------------------------------------- */

.menu .lien-ancre { position: relative; }

/* Section en cours de lecture, posée par le JavaScript. */
.menu .lien-ancre[aria-current] {
  color: var(--orange-fonce);
  font-weight: 600;
}
.menu .lien-ancre[aria-current]::after {
  content: "";
  position: absolute;
  left: 0; right: 0;
  bottom: -2px;
  height: 2px;
  background: var(--orange);
  border-radius: 2px;
}

.menu .lien-page {
  color: var(--gris);
  font-size: 13.5px;
}
.menu .lien-page:hover { color: var(--anthracite); }
.menu .lien-page[aria-current="page"] { color: var(--orange-fonce); font-weight: 600; }

.menu-separateur { display: none; }

/* Les langues ferment le panneau du menu sur téléphone, sous leur nom complet,
   après un filet qui les sépare des pages. Au-delà de 980 px, le panneau
   n'existe plus et le sélecteur de la barre prend le relais. */
.menu-langues { display: none; }
@media (max-width: 979px) {
  .menu.ouvert .menu-langues {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 22px;
    margin-top: 6px;
    padding-top: 14px;
    border-top: 1px solid var(--ligne);
  }
  .menu.ouvert .menu-langues a[aria-current] { color: var(--orange-fonce); font-weight: 600; }
}
.menu-secours a[aria-current] { font-weight: 700; }

/* Dans le panneau déplié, la coupure entre les ancres de la page d'accueil et
   les pages à part entière doit se lire comme dans la barre : le même repère
   passe simplement de la verticale à l'horizontale. Sans lui, les sept entrées
   forment une liste continue où seule la nuance de gris distingue les deux
   familles — trop discret sur un téléphone. */
@media (max-width: 979px) {
  .menu.ouvert .menu-separateur {
    display: block;
    width: 100%;
    height: 1px;
    margin: 6px 0;
    background: var(--ligne);
  }
}

@media (min-width: 980px) {
  .menu { gap: 18px; }
  .menu-separateur {
    display: block;
    width: 1px;
    height: 18px;
    background: var(--ligne);
  }
}

/* Entre 980 et 1 240 px, le menu déplié, le sélecteur de langue et le logo se
   partagent la barre : le bouton de rendez-vous y reprend son libellé court et
   les espacements se resserrent. Sans cela, la barre débordait de 69 à 71 px à
   980 px, en allemand comme en français, depuis que le sélecteur propose trois
   langues. Au-delà, la place revient et le libellé complet avec elle. */
@media (min-width: 980px) and (max-width: 1239px) {
  .cta-court { display: inline; }
  .cta-long { display: none; }
  .nav { gap: 20px; }
  .menu { gap: 14px; }
}

/* Les ancres doivent s'arrêter sous l'en-tête collant, pas dessous. */
main > section[id] { scroll-margin-top: 92px; }

/* --- barre de progression de lecture --------------------------------------
   Entièrement en CSS, pilotée par le défilement du document. Elle n'apparaît
   que dans les navigateurs qui savent le faire : ailleurs, elle reste masquée
   plutôt que de rester bloquée à zéro ou à cent pour cent.
   ------------------------------------------------------------------------- */

.progression { display: none; }

@supports (animation-timeline: scroll()) {
  /* Posée sur la bordure basse de l’en-tête, hors du flux : dans le flux, elle
     ajoutait 3 px à la barre dans Chrome et rien dans Firefox ni Safari, et la
     hauteur de l’en-tête doit être la même partout pour que le hero glisse
     dessous au pixel près. */
  .progression {
    display: block;
    position: absolute;
    left: 0; right: 0;
    bottom: -1px;
    height: 3px;
    background: var(--ligne-claire);
    transition: opacity .45s ease-out;   /* au rythme du fond de l’en-tête */
  }

  .progression-barre {
    display: block;
    height: 100%;
    background: var(--orange);
    transform: scaleX(0);
    transform-origin: 0 50%;
    animation: progression-lecture linear;
    animation-timeline: scroll(root block);
  }

  @keyframes progression-lecture {
    from { transform: scaleX(0); }
    to   { transform: scaleX(1); }
  }
}

/* Sous mouvement réduit, la règle universelle coupe l’animation : la barre
   resterait à zéro. Une jauge qui ne mesure rien est pire qu’une jauge absente. */
@media (prefers-reduced-motion: reduce) {
  .progression { display: none; }
}

/* --- hiérarchie des prestations ------------------------------------------ */

.service-declinaisons-titre {
  margin-top: 16px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--gris);
}

.service-declinaisons {
  list-style: none;
  margin-top: 8px;
  border-left: 2px solid var(--orange-pale);
  padding-left: 12px;
}
.service-declinaisons li { border-bottom: 0; padding: 3px 0; }

/* En ligne, ces deux liens ne faisaient que 18 px de haut, sous le minimum de
   24 px de WCAG 2.5.8. Le passage en inline-block leur donne une hauteur propre
   que le rembourrage porte à 25 px, sans déplacer quoi que ce soit autour. */
.service-declinaisons a {
  display: inline-block;
  padding: 4px 0;
  color: var(--anthracite-2);
  font-size: 13.5px;
  font-weight: 600;
  text-decoration: none;
}
.service-declinaisons a:hover { color: var(--orange-fonce); text-decoration: underline; }

/* Déclinaisons dans le pied de page */
.pied-enfants {
  list-style: none;
  margin-top: 6px;
  padding-left: 12px;
  border-left: 1px solid #474443;
}
.pied-enfants a { font-size: 13px; }

.lien-souligne { color: var(--orange-fonce); font-weight: 600; }

/* --- transition entre les pages -------------------------------------------
   Fondu croisé natif d'une page à l'autre, sans une ligne de JavaScript.
   Absent de Firefox, où la navigation reste simplement instantanée.
   -------------------------------------------------------------------------- */

@view-transition { navigation: auto; }

/* La règle globale « *, *::before, *::after { animation: none } » n'atteint pas
   l'arbre ::view-transition-* : couper la navigation à la source est la seule
   façon correcte de respecter le réglage de mouvement réduit. */
@media (prefers-reduced-motion: reduce) {
  @view-transition { navigation: none; }
}

/* --- impression -----------------------------------------------------------
   Sur papier, rien n'est piloté par le défilement : le hero redevient une
   section ordinaire, les commandes qui n'ont de sens qu'à l'écran disparaissent
   et tout ce que l'observateur d'apparition aurait laissé transparent est
   ramené à l'état visible.
   -------------------------------------------------------------------------- */

@media print {
  /* L'épinglage étant porté par une animation, il faut la couper : une
     déclaration ordinaire ne l'emporte jamais sur une animation en cours. */
  .hero { animation: none; min-height: 0; }
  .hero .interieur { animation: none; }
  /* Sur papier, pas de photo sous un voile noir : le hero redevient clair et
     son titre sombre, comme avant la photographie. */
  .hero-photo { display: none; }
  .hero--photo { background: none; }
  .hero--photo::before { background: none; }
  .hero--photo h1, .hero--photo .sous-titre { color: var(--anthracite); text-shadow: none; }
  .hero--photo h1 em { color: var(--orange); }
  /* .vide part avec les filtres : sinon la page restaure les fiches masquées
     mais laisse « 3 références affichées » juste au-dessus. */
  .hero-descente, .filtres, .progression, .vide, .carrousel-commandes { display: none; }

  /* Un bandeau imprimé n’a plus de flèches : il redevient la liste qu’il est,
     sinon la feuille ne porterait que la carte visible à l’écran au moment
     de l’impression. Les copies posées par le script pour faire boucler la
     bande ne s’impriment pas : ce sont les mêmes cartes. */
  .carrousel-piste { display: block; overflow: visible; }
  .carrousel-piste > li { break-inside: avoid; margin-bottom: 8px; }
  .carrousel-piste > .copie { display: none; }
  /* Sur papier, pas de survol : le nom du client, en infobulle à l'écran,
     reprend sa place sous le logo. */
  .jeton-logo { padding-top: 32px; }
  .jeton-logo > .nom {
    position: static;
    opacity: 1;
    transform: none;
    background: none;
    color: var(--anthracite);
    font-size: 19px;
  }
  .jeton-logo > .nom::after { content: none; }

  /* Un visiteur qui a filtré puis imprimé ne doit pas imprimer un trou. */
  .reference[hidden] { display: flex !important; }

  /* Aucune propriété CSS n'ouvre un <details> fermé. Là où le pseudo-élément
     existe, on force son affichage ; ailleurs, seules les questions déjà
     ouvertes s'impriment — dégradation admise, signalée à la recette. */
  details::details-content { content-visibility: visible !important; }
  /* Sans elle, l'opacité nulle de l'accordéon imprimerait blanc sur blanc. */
  .faq details::details-content { opacity: 1 !important; }

  .apparition > .interieur > *,
  .apparition > .interieur > * > * { opacity: 1 !important; transform: none !important; }
  .apres.apparition .bloc::before,
  .apparition .stats .stat::before { transform: none !important; }
}
