/* ==========================================================================
   QUALITECH : composants
   Dépend de tokens.css et base.css.
   ========================================================================== */

/* ==========================================================================
   1. BOUTONS
   ========================================================================== */

.qt-btn {
  --btn-fond: var(--qt-marine);
  --btn-encre: var(--qt-blanc);
  --btn-bord: transparent;

  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--qt-e-2xs);
  padding: 0.95rem 1.6rem;
  border: var(--qt-trait) solid var(--btn-bord);
  border-radius: var(--qt-rayon-s);
  background-color: var(--btn-fond);
  color: var(--btn-encre);
  font-size: var(--qt-t-petit);
  font-weight: var(--qt-w-semi);
  letter-spacing: -0.005em;
  line-height: 1.2;
  text-align: center;
  isolation: isolate;
  transition:
    transform var(--qt-d-micro) var(--qt-ease),
    box-shadow var(--qt-d-micro) var(--qt-ease),
    background-color var(--qt-d-micro) var(--qt-ease),
    border-color var(--qt-d-micro) var(--qt-ease);
}

.qt-btn:hover { transform: translateY(-2px); }
.qt-btn:active { transform: translateY(0); }

/* Primaire : aplat doré, encre marine. Jamais de doré en texte sur clair. */
/* Primaire. Le bouton s'inverse selon le fond qui le porte :
   marine plein sur les sections crème, blanc plein sur les sections sombres.
   Un blanc unique aurait disparu sur le crème (#FFF sur #F5F1EA = 1,1:1),
   un doré unique était trop lourd. Les deux variantes tiennent au-delà
   de 13:1 de contraste. */
.qt-btn--primaire {
  --btn-fond: var(--qt-marine);
  --btn-encre: var(--qt-blanc);
  font-weight: var(--qt-w-gras);
  box-shadow: var(--qt-ombre-btn);
}

.qt-btn--primaire:hover {
  --btn-fond: var(--qt-marine-voile);
  box-shadow: var(--qt-ombre-btn-forte);
}

/* .qt-sombre-marine était absent de cette liste alors qu'il bascule les
   mêmes tokens que .qt-sombre dans tokens.css. Résultat : sur la carte de
   l'offre de lancement, le bouton primaire restait marine sur un fond
   marine, donc invisible. Tout contexte sombre doit inverser ses boutons. */
.qt-sombre .qt-btn--primaire,
.qt-sombre-marine .qt-btn--primaire,
.qt-pied .qt-btn--primaire {
  --btn-fond: var(--qt-blanc);
  --btn-encre: var(--qt-marine);
}

/* Au survol sur fond sombre : un blanc légèrement chaud, pas un gris.
   Un blanc pur qui s'assombrit fait « bouton désactivé ». */
.qt-sombre .qt-btn--primaire:hover,
.qt-sombre-marine .qt-btn--primaire:hover,
.qt-pied .qt-btn--primaire:hover {
  --btn-fond: var(--qt-creme-voile);
}

/* Secondaire : contour, s'adapte au contexte clair ou sombre */
.qt-btn--contour {
  --btn-fond: transparent;
  --btn-encre: var(--qt-encre);
  --btn-bord: var(--qt-filet-fort);
}

.qt-btn--contour:hover {
  --btn-bord: var(--qt-accent);
  --btn-fond: color-mix(in srgb, var(--qt-accent) 10%, transparent);
}

.qt-btn--large { padding: 1.15rem 2.2rem; font-size: var(--qt-t-corps); }
.qt-btn--pleine { width: 100%; }

/* Lien fléché : la flèche avance au survol */
.qt-lien-fleche {
  display: inline-flex;
  align-items: center;
  gap: var(--qt-e-2xs);
  font-weight: var(--qt-w-semi);
  font-size: var(--qt-t-petit);
  color: var(--qt-accent-texte);
  padding-block: var(--qt-e-3xs);
  border-bottom: 2px solid transparent;
  transition: border-color var(--qt-d-micro) var(--qt-ease);
}

.qt-lien-fleche svg {
  inline-size: 1.05em;
  transition: transform var(--qt-d-micro) var(--qt-ease);
}

.qt-lien-fleche:hover { border-bottom-color: var(--qt-accent); }
.qt-lien-fleche:hover svg { transform: translateX(4px); }


/* ==========================================================================
   2. PASTILLES ET BADGES
   ========================================================================== */

.qt-pastille {
  display: inline-flex;
  align-items: center;
  gap: var(--qt-e-2xs);
  padding: 0.42rem 0.85rem;
  border-radius: var(--qt-rayon-plein);
  border: var(--qt-trait) solid var(--qt-filet-fort);
  background-color: color-mix(in srgb, var(--qt-fond-alt) 60%, transparent);
  font-size: var(--qt-t-mention);
  font-weight: var(--qt-w-semi);
  letter-spacing: 0.01em;
  line-height: 1.2;
  color: var(--qt-encre-douce);
  white-space: nowrap;
}

.qt-pastille svg { inline-size: 1em; flex: none; color: var(--qt-accent-texte); }

.qt-pastille--or {
  border-color: color-mix(in srgb, var(--qt-or) 45%, transparent);
  background-color: color-mix(in srgb, var(--qt-or) 14%, transparent);
  color: var(--qt-accent-texte);
}

.qt-pastille--pleine {
  background-color: var(--qt-or);
  border-color: var(--qt-or);
  color: var(--qt-marine);
  font-weight: var(--qt-w-gras);
}


/* ==========================================================================
   3. EN-TÊTE
   ========================================================================== */

.qt-entete {
  position: sticky;
  top: 0;
  z-index: var(--qt-z-entete);
  background-color: color-mix(in srgb, var(--qt-nuit) 88%, transparent);
  backdrop-filter: saturate(150%) blur(14px);
  -webkit-backdrop-filter: saturate(150%) blur(14px);
  border-bottom: var(--qt-trait) solid transparent;
  transition:
    background-color var(--qt-d-court) var(--qt-ease),
    border-color var(--qt-d-court) var(--qt-ease);
}

.qt-entete.est-defilee {
  background-color: color-mix(in srgb, var(--qt-nuit) 97%, transparent);
  border-bottom-color: var(--qt-filet-sombre);
}

.qt-entete__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--qt-e-m);
  min-block-size: 4.75rem;
}

.qt-logo { display: flex; align-items: center; flex: none; }
.qt-logo img { block-size: clamp(2rem, 1.6rem + 1.1vw, 2.6rem); inline-size: auto; background: none; }

.qt-nav { display: flex; align-items: center; gap: var(--qt-e-3xs); }

.qt-nav__lien {
  position: relative;
  padding: 0.6rem 0.85rem;
  font-size: var(--qt-t-petit);
  font-weight: var(--qt-w-moyen);
  color: color-mix(in srgb, var(--qt-sable-clair) 82%, transparent);
  transition: color var(--qt-d-micro) var(--qt-ease);
  white-space: nowrap;
}

/* Le filet se dessine depuis la gauche au lieu d'apparaître d'un bloc.
   scaleX sur un pseudo-élément : aucun reflow, l'animation reste sur le
   compositeur. */
.qt-nav__lien::after {
  content: "";
  position: absolute;
  inset-inline: 0.85rem;
  bottom: 0.32rem;
  block-size: 1.5px;
  background-color: var(--qt-or);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--qt-d-micro) var(--qt-ease);
}

.qt-nav__lien:hover,
.qt-nav__lien:focus-visible,
.qt-nav__lien[aria-current="page"] { color: var(--qt-blanc); }

.qt-nav__lien:hover::after,
.qt-nav__lien:focus-visible::after,
.qt-nav__lien[aria-current="page"]::after { transform: scaleX(1); }


/* --------------------------------------------------------------------------
   MEGA-PANNEAU « SOLS DÉCORATIFS »
   Le groupe reste en position statique : le panneau se cale alors sur
   .qt-entete (sticky), ce qui lui donne la pleine largeur de l'en-tête
   sans hack de 100vw ni décalage dû à la barre de défilement.
   -------------------------------------------------------------------------- */

.qt-nav__groupe { position: static; }

.qt-nav__declencheur { display: inline-flex; align-items: center; gap: 0.3rem; }

.qt-nav__declencheur svg {
  inline-size: 0.85em;
  transition: transform var(--qt-d-micro) var(--qt-ease);
}

.qt-nav__groupe:hover .qt-nav__declencheur svg,
.qt-nav__groupe:focus-within .qt-nav__declencheur svg { transform: rotate(180deg); }

/* Voile : la page derrière recule. Fixé au viewport, sous le panneau. */
.qt-voile {
  position: fixed;
  inset: 0;
  z-index: -1;
  background-color: color-mix(in srgb, var(--qt-nuit) 62%, transparent);
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--qt-d-court) var(--qt-ease),
              visibility var(--qt-d-court);
}

.qt-mega {
  position: absolute;
  top: 100%;
  inset-inline: 0;
  background-color: var(--qt-nuit);
  border-block: var(--qt-trait) solid var(--qt-filet-sombre);
  box-shadow: 0 32px 64px -32px rgba(0, 0, 0, 0.7);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-8px);
  transition:
    opacity var(--qt-d-micro) var(--qt-ease),
    transform var(--qt-d-court) var(--qt-ease),
    visibility var(--qt-d-court);
}

.qt-nav__groupe:hover .qt-mega,
.qt-nav__groupe:focus-within .qt-mega,
.qt-nav__groupe:hover .qt-voile,
.qt-nav__groupe:focus-within .qt-voile {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}

.qt-mega__grille {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 22.5rem;
  gap: clamp(2rem, 4vw, 4rem);
  align-items: center;
  padding-block: var(--qt-e-l);
}

.qt-mega__label {
  font-size: var(--qt-t-sur-titre);
  font-weight: var(--qt-w-semi);
  letter-spacing: var(--qt-ls-sur-titre);
  text-transform: uppercase;
  color: var(--qt-accent-texte);
  margin-block-end: var(--qt-e-s);
}

/* Une ligne d'index, pas une carte. Filet en haut seulement : la liste se
   lit comme un sommaire d'ouvrage. */
.qt-mega__item {
  display: grid;
  grid-template-columns: 2.5rem minmax(0, 1fr) auto;
  align-items: baseline;
  gap: var(--qt-e-s);
  padding-block: var(--qt-e-s);
  border-block-start: var(--qt-trait) solid var(--qt-filet-sombre);
  transition: border-color var(--qt-d-micro) var(--qt-ease);
}

.qt-mega__item:last-child { border-block-end: var(--qt-trait) solid var(--qt-filet-sombre); }
.qt-mega__item.est-active { border-block-start-color: var(--qt-or); }

.qt-mega__num {
  font-size: var(--qt-t-mention);
  font-weight: var(--qt-w-semi);
  letter-spacing: 0.08em;
  font-variant-numeric: tabular-nums lining-nums;
  color: color-mix(in srgb, var(--qt-sable-clair) 45%, transparent);
  transition: color var(--qt-d-micro) var(--qt-ease);
}

.qt-mega__item.est-active .qt-mega__num { color: var(--qt-or); }

.qt-mega__corps { display: grid; gap: 0.3rem; }

.qt-mega__nom {
  font-size: var(--qt-t-sous-titre);
  font-weight: var(--qt-w-h2);
  line-height: 1.15;
  letter-spacing: -0.02em;
  color: color-mix(in srgb, var(--qt-blanc) 72%, transparent);
  transition: color var(--qt-d-micro) var(--qt-ease),
              transform var(--qt-d-court) var(--qt-ease);
}

.qt-mega__item.est-active .qt-mega__nom {
  color: var(--qt-blanc);
  transform: translateX(6px);
}

.qt-mega__desc {
  font-size: var(--qt-t-mention);
  color: color-mix(in srgb, var(--qt-sable-clair) 62%, transparent);
  transition: color var(--qt-d-micro) var(--qt-ease);
}

.qt-mega__item.est-active .qt-mega__desc { color: var(--qt-sable-clair); }

.qt-mega__prix {
  font-size: var(--qt-t-mention);
  font-weight: var(--qt-w-semi);
  font-variant-numeric: tabular-nums lining-nums;
  color: var(--qt-sable-clair);
  white-space: nowrap;
}

/* Scène photo : les trois couches se superposent, on croise les opacités.
   Un léger zoom sur la couche sortante donne la profondeur. */
.qt-mega__vue {
  position: relative;
  aspect-ratio: 4 / 3;
  border-radius: var(--qt-rayon-m);
  overflow: hidden;
  background-color: var(--qt-marine);
}

.qt-mega__couche {
  position: absolute;
  inset: 0;
  opacity: 0;
  transform: scale(1.06);
  transition: opacity var(--qt-d-court) var(--qt-ease),
              transform var(--qt-d-moyen) var(--qt-ease);
}

.qt-mega__couche.est-active { opacity: 1; transform: scale(1); }
.qt-mega__couche img { inline-size: 100%; block-size: 100%; object-fit: cover; }

.qt-mega__pied {
  border-block-start: var(--qt-trait) solid var(--qt-filet-sombre);
  background-color: color-mix(in srgb, var(--qt-marine) 34%, transparent);
}

.qt-mega__pied-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--qt-e-m);
  flex-wrap: wrap;
  padding-block: var(--qt-e-s);
}

.qt-mega__note {
  display: inline-flex;
  align-items: center;
  gap: var(--qt-e-2xs);
  font-size: var(--qt-t-mention);
  color: color-mix(in srgb, var(--qt-sable-clair) 72%, transparent);
}

.qt-mega__note svg { inline-size: 1rem; block-size: 1rem; color: var(--qt-or); flex: none; }

/* Au-delà de 1240px le panneau ne doit pas s'étirer sur toute la largeur :
   il se cale sur la même mesure que le contenu du site. */
@media (max-width: 1180px) {
  .qt-mega__grille { grid-template-columns: minmax(0, 1fr) 17rem; }
}

.qt-entete__actions { display: flex; align-items: center; gap: var(--qt-e-2xs); flex: none; }

/* Burger : deux traits seulement. Le troisième n'apportait rien et rendait
   la bascule en croix moins nette. Les traits sont de longueurs inégales
   au repos, ils s'égalisent en croix. */
.qt-burger {
  display: none;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: 6px;
  inline-size: 2.75rem;
  block-size: 2.75rem;
  border-radius: var(--qt-rayon-s);
  border: var(--qt-trait) solid var(--qt-filet-sombre);
  background-color: color-mix(in srgb, var(--qt-sable-pale) 5%, transparent);
  transition: border-color var(--qt-d-micro) var(--qt-ease),
              background-color var(--qt-d-micro) var(--qt-ease);
}

.qt-burger:hover { border-color: color-mix(in srgb, var(--qt-or) 55%, transparent); }

.qt-burger span {
  display: block;
  block-size: 1.5px;
  background-color: var(--qt-sable-pale);
  border-radius: 2px;
  transition: transform var(--qt-d-micro) var(--qt-ease),
              inline-size var(--qt-d-micro) var(--qt-ease),
              opacity var(--qt-d-instant) var(--qt-ease);
}

.qt-burger span:nth-child(1) { inline-size: 1.15rem; }
.qt-burger span:nth-child(2) { inline-size: 0.75rem; align-self: center; }
.qt-burger:hover span:nth-child(2) { inline-size: 1.15rem; }
.qt-burger span:nth-child(3) { display: none; }

.qt-burger[aria-expanded="true"] span:nth-child(1) { transform: translateY(3.75px) rotate(45deg); }
.qt-burger[aria-expanded="true"] span:nth-child(2) {
  inline-size: 1.15rem;
  transform: translateY(-3.75px) rotate(-45deg);
}

/* Menu ouvert : l'en-tête repasse au-dessus du panneau plein écran, sinon
   le burger passe dessous et on ne peut plus refermer. */
body.menu-ouvert .qt-entete { z-index: calc(var(--qt-z-panneau) + 1); }

/* --------------------------------------------------------------------------
   MENU PLEIN ÉCRAN
   Index numéroté sur une photo de chantier très assombrie. Le panneau
   couvre tout le viewport, en-tête compris : le burger reste au-dessus.
   -------------------------------------------------------------------------- */

.qt-panneau {
  position: fixed;
  inset: 0;
  z-index: var(--qt-z-panneau);
  background-color: var(--qt-nuit);
  overflow-y: auto;
  overscroll-behavior: contain;
  /* Pas de clip-path ici : sur le panneau flottant à coins arrondis, un
     inset() rectangulaire écraserait le border-radius. Translation et
     échelle font le même effet d'arrivée et respectent la forme. */
  opacity: 0;
  visibility: hidden;
  transform: translateY(-10px) scale(0.985);
  transform-origin: top center;
  transition:
    transform var(--qt-d-court) var(--qt-ease),
    opacity var(--qt-d-micro) var(--qt-ease),
    visibility var(--qt-d-court);
}

.qt-panneau[data-ouvert="true"] {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scale(1);
}

/* Photo de fond : très sombre, elle donne de la matière sans jamais
   disputer la lisibilité au texte. */
.qt-panneau__fond {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
}

.qt-panneau__fond img {
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
  opacity: 0.16;
  filter: grayscale(0.4);
}

.qt-panneau__fond::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image: linear-gradient(
    to bottom,
    color-mix(in srgb, var(--qt-nuit) 55%, transparent) 0%,
    color-mix(in srgb, var(--qt-nuit) 88%, transparent) 55%,
    var(--qt-nuit) 100%);
}

.qt-panneau__corps {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  min-block-size: 100%;
  gap: var(--qt-e-2xs);
  /* Le panneau est déjà encarté sous l'en-tête flottant par le media query :
     inutile d'ajouter ici une réserve pour la hauteur de l'en-tête. */
  padding: var(--qt-e-s) var(--qt-e-m) var(--qt-e-m);
}

.qt-panneau__label {
  font-size: var(--qt-t-sur-titre);
  font-weight: var(--qt-w-semi);
  letter-spacing: var(--qt-ls-sur-titre);
  text-transform: uppercase;
  color: var(--qt-accent-texte);
  margin-block-end: var(--qt-e-2xs);
}

.qt-panneau__label--second { margin-block-start: var(--qt-e-m); }

/* La ligne : numéro en colonne fixe, nom en display, méta alignée à droite.
   Le numéro tient la grille verticale, c'est lui qui fait « sommaire ». */
.qt-panneau__lien {
  display: grid;
  grid-template-columns: 2.25rem minmax(0, 1fr) auto auto;
  align-items: center;
  gap: 0.15rem var(--qt-e-s);
  padding-block: var(--qt-e-2xs);
  /* Les rangées se partagent la hauteur disponible au lieu de la laisser
     s'accumuler en un vide au milieu du panneau : sur un grand écran elles
     respirent, sur un petit elles retombent sur leur plancher de 2,75 rem,
     qui est la cible tactile minimale. */
  flex: 1 1 auto;
  min-block-size: 2.75rem;
  align-content: center;
  border-block-end: var(--qt-trait) solid var(--qt-filet-sombre);

  /* Cascade à l'ouverture : chaque ligne monte à son tour. */
  opacity: 0;
  transform: translateY(14px);
  transition: opacity var(--qt-d-court) var(--qt-ease),
              transform var(--qt-d-court) var(--qt-ease);
}

.qt-panneau[data-ouvert="true"] .qt-panneau__lien {
  opacity: 1;
  transform: translateY(0);
  transition-delay: var(--qt-delai, 0ms);
}

.qt-panneau__num {
  font-size: var(--qt-t-mention);
  font-weight: var(--qt-w-semi);
  letter-spacing: 0.08em;
  font-variant-numeric: tabular-nums lining-nums;
  color: color-mix(in srgb, var(--qt-sable-clair) 42%, transparent);
}

/* Un menu n'est pas un titre de section : il se parcourt, il ne s'annonce
   pas. Deux niveaux nets (prestations 19,5 px, entreprise 16 px) valent
   mieux qu'un seul niveau criard. */
.qt-panneau__nom {
  font-size: clamp(1.2rem, 1.05rem + 0.6vw, 1.5rem);
  font-weight: var(--qt-w-h2);
  line-height: 1.12;
  letter-spacing: -0.022em;
  color: var(--qt-blanc);
}

.qt-panneau__lien--mineur .qt-panneau__nom {
  font-size: var(--qt-t-corps);
  font-weight: var(--qt-w-semi);
  letter-spacing: -0.01em;
  color: color-mix(in srgb, var(--qt-blanc) 88%, transparent);
}

.qt-panneau__meta {
  font-size: var(--qt-t-mention);
  font-weight: var(--qt-w-semi);
  font-variant-numeric: tabular-nums lining-nums;
  color: var(--qt-sable-clair);
  white-space: nowrap;
}

.qt-panneau__pied {
  flex: none;
  padding-block-start: var(--qt-e-s);
  display: grid;
  gap: var(--qt-e-2xs);
  justify-items: center;
  text-align: center;
}

.qt-panneau__tel {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* Un numéro de téléphone dans un menu mobile est le lien le plus
     susceptible d'être touché du pouce : il lui faut sa cible pleine,
     pas la hauteur de sa ligne de texte. */
  min-block-size: 2.75rem;
  padding-inline: var(--qt-e-2xs);
  gap: var(--qt-e-2xs);
  font-size: var(--qt-t-sous-titre);
  font-weight: var(--qt-w-gras);
  color: var(--qt-sable-clair);
}

.qt-panneau__mention {
  font-size: var(--qt-t-mention);
  color: color-mix(in srgb, var(--qt-sable-clair) 58%, transparent);
}

@media (max-width: 1080px) {
  .qt-nav,
  .qt-entete__actions .qt-btn--contour { display: none; }
  .qt-burger { display: flex; }
}


/* --------------------------------------------------------------------------
   EN-TÊTE FLOTTANT MOBILE
   Sous 1080 px l'en-tête se détache des quatre bords et devient un objet
   de verre posé sur la page. Le verre est teinté marine, jamais gris :
   un glassmorphism neutre ferait générique.
   -------------------------------------------------------------------------- */

@media (max-width: 1080px) {

  .qt-entete {
    /* fixed, pour que le hero passe SOUS le verre. En sticky, le flux
       réservait la place de l'en-tête et laissait voir une bande de fond
       crème au-dessus du hero sombre. */
    position: fixed;
    inset-inline: 0;
    top: 0;
    margin: var(--qt-flottant-marge);
    border-radius: var(--qt-rayon-flottant);
    border: var(--qt-trait) solid color-mix(in srgb, var(--qt-sable) 18%, transparent);
    border-bottom-color: color-mix(in srgb, var(--qt-sable) 18%, transparent);

    /* Le verre : teinté marine, saturé, avec une lumière rasante sur l'arête
       haute qui rejoue celle du pictogramme du logo. */
    /* 62 % de marine sur du crème donnait un gris boueux. À 90 % le verre
       lit comme du marine, tout en gardant le flou quand une photo passe
       dessous au défilement. */
    background-color: color-mix(in srgb, var(--qt-marine) 90%, transparent);
    backdrop-filter: saturate(170%) blur(20px);
    -webkit-backdrop-filter: saturate(170%) blur(20px);
    box-shadow:
      inset 0 1px 0 color-mix(in srgb, var(--qt-sable-pale) 14%, transparent),
      0 10px 34px -12px rgba(5, 11, 20, 0.65);

    --qt-flottant-marge: 0.75rem;
  }

  /* Une fois défilé, le verre se densifie pour garder le texte lisible
     quand une photo claire passe dessous. */
  .qt-entete.est-defilee {
    background-color: color-mix(in srgb, var(--qt-marine) 82%, transparent);
    border-color: color-mix(in srgb, var(--qt-sable) 30%, transparent);
    box-shadow:
      inset 0 1px 0 color-mix(in srgb, var(--qt-sable-pale) 18%, transparent),
      0 14px 40px -12px rgba(5, 11, 20, 0.8);
  }

  /* La gouttière du conteneur est reprise par la marge flottante :
     sans ça le contenu serait doublement indenté. */
  .qt-entete__inner {
    padding-inline: var(--qt-e-s);
    min-block-size: 4.25rem;
  }

  /* Le panneau de menu s'aligne sur le même objet flottant */
  .qt-panneau {
    inset: calc(var(--qt-flottant-marge, 0.75rem) + 4.25rem + var(--qt-flottant-marge, 0.75rem))
           var(--qt-flottant-marge, 0.75rem) var(--qt-flottant-marge, 0.75rem);
    border-radius: var(--qt-rayon-flottant);
    border: var(--qt-trait) solid color-mix(in srgb, var(--qt-sable) 18%, transparent);
    background-color: color-mix(in srgb, var(--qt-nuit) 88%, transparent);
    backdrop-filter: saturate(170%) blur(24px);
    -webkit-backdrop-filter: saturate(170%) blur(24px);
    box-shadow: 0 18px 50px -16px rgba(5, 11, 20, 0.85);
  }
}

/* Safari iOS ne compose pas toujours backdrop-filter sur un élément sticky
   à coins arrondis. Repli opaque, le rendu reste propre. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  @media (max-width: 1080px) {
    .qt-entete { background-color: color-mix(in srgb, var(--qt-marine) 96%, transparent); }
    .qt-panneau { background-color: var(--qt-nuit); }
  }
}


/* ==========================================================================
   5. HERO  ·  patron ISO PRO
   Colonne de texte à gauche (badge, titre, chapeau, boutons, bande de
   preuves à filets verticaux), colonne média à droite (photo nue,
   piste-filet segmentée, légende dans la marge).

   Fond BLANC. Le sable et l'or ne peuvent donc plus servir de couleur de
   texte : ils passent en aplat (tirets, filets, jauge) ou en
   --qt-accent-texte pour les libellés.
   ========================================================================== */

.qt-hero {
  position: relative;
  /* Un padding bas volontairement plus court que la cadence des sections.
     Il était à 0, ce qui avait un effet pervers : la barre de preuves
     dépassait de 28 px sous la section et se faisait rogner par l'overflow
     ci-dessous. Assez d'air pour ne rien couper, pas assez pour rouvrir les
     135 px de vide qu'un padding pleine cadence créait avec la section
     suivante, qui apporte déjà le sien. */
  padding-block: clamp(5.5rem, 9vh, 7rem) clamp(3.25rem, 2.4rem + 2.8vw, 5.25rem);
  overflow: hidden;

  /* Un halo chaud très diffus en haut à droite, là où se trouvait la lueur
     dorée du fond sombre, puis une descente qui s'arrête sur le voile.
     Elle rejoignait auparavant le crème du corps, ce qui soudait le hero à
     la section suivante : les deux se lisaient comme un seul bloc. Le hero
     garde désormais son plan, et la rupture de ton marque la frontière. */
  background-color: var(--qt-lin);
  background-image:
    radial-gradient(120% 90% at 88% 0%,
      color-mix(in srgb, var(--qt-or) 9%, transparent) 0%,
      transparent 60%),
    var(--qt-degrade-hero);
}

.qt-hero__grille {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(2rem, 4.5vw, 4.25rem);
  /* En « stretch », la colonne de texte prenait la hauteur de la photo.
     Combinée au margin-block-start:auto des preuves, elle creusait jusqu'à
     554 px entre les boutons et la bande de chiffres (mesuré sur contact).
     En « start », chaque colonne garde sa hauteur propre. */
  align-items: start;
}

/* La photo passe À GAUCHE sur grand écran. Uniquement au-dessus du point de
   rupture : en une colonne, le titre doit rester le premier élément lu. */
@media (min-width: 1061px) {
  .qt-hero__texte { order: 2; }
  .qt-hero__media { order: 1; }
}

.qt-hero__texte { display: flex; flex-direction: column; }

/* ---- Badge ---- */

.qt-hero__badge {
  display: inline-flex;
  align-items: center;
  gap: var(--qt-e-2xs);
  align-self: start;
  padding: 0.45rem 0.8rem;
  border-radius: var(--qt-rayon-s);
  border: var(--qt-trait) solid var(--qt-filet-fort);
  background-color: var(--qt-creme);
  font-size: var(--qt-t-mention);
  font-weight: var(--qt-w-normal);
  letter-spacing: 0.01em;
  color: var(--qt-encre-douce);
  line-height: 1.5;
}

.qt-hero__badge b { color: var(--qt-encre); font-weight: var(--qt-w-semi); }

.qt-hero__point {
  inline-size: 5px;
  block-size: 5px;
  border-radius: 1px;
  background-color: var(--qt-or);
  flex: none;
}

/* ---- Titre ---- */

.qt-hero__titre {
  font-size: var(--qt-t-display-xl);
  /* Le H1 du hero est la seule exception à la règle « display jamais en
     gras » : c'est le point d'entrée, il porte la voix de la marque.
     Le tracking se resserre en conséquence, un gras large se déchire. */
  font-weight: var(--qt-w-h1);
  line-height: 1.02;
  letter-spacing: -0.035em;
  color: var(--qt-encre);
  max-width: 17ch;
  text-wrap: balance;
  margin-block: var(--qt-e-m) var(--qt-e-s);
}

/* Filet doré sous le mot d'accent, jamais une couleur de texte. */
.qt-hero__titre em {
  font-style: normal;
  position: relative;
  color: inherit;
  white-space: nowrap;
}

.qt-hero__titre em::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  bottom: 0.02em;
  block-size: 0.075em;
  background-color: var(--qt-or);
}

/* ---- Chapeau ---- */

.qt-hero__chapeau {
  font-size: var(--qt-t-chapeau);
  font-weight: var(--qt-w-leger);
  line-height: var(--qt-lh-corps);
  color: var(--qt-encre-douce);
  max-width: 48ch;
  margin-block-end: var(--qt-e-l);
}

.qt-hero__chapeau strong { color: var(--qt-encre); font-weight: var(--qt-w-moyen); }

/* ---- Boutons ---- */

.qt-hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--qt-e-xs);
  margin-block-end: var(--qt-e-2xl);
}

/* ---- Bande de preuves : trois colonnes, filets verticaux ---- */

.qt-hero__preuves {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  border-block-start: var(--qt-trait) solid var(--qt-filet-fort);
  /* Était « auto » : la bande était poussée au bas d'une colonne étirée à la
     hauteur de la photo, laissant un trou après les boutons. À zéro, et non
     à une valeur d'espacement : .qt-hero__actions porte DÉJÀ une marge basse
     de 85 px. Les marges de deux enfants de flex ne fusionnent pas, elles
     s'additionnent : 85 + 85 faisaient encore 171 px de vide. */
  margin-block-start: 0;
  padding: 0;
  list-style: none;
}

.qt-hero__preuves li {
  position: relative;
  padding: var(--qt-e-s) var(--qt-e-s) 0 0;
}

.qt-hero__preuves li + li {
  padding-inline-start: var(--qt-e-s);
  border-inline-start: var(--qt-trait) solid var(--qt-filet-clair);
}

.qt-preuve__label {
  display: flex;
  align-items: center;
  gap: var(--qt-e-3xs);
  font-size: 0.6rem;
  font-weight: var(--qt-w-gras);
  letter-spacing: 0.19em;
  text-transform: uppercase;
  /* --qt-sable sur blanc tombe à 2,57:1. Ici 5,6:1. */
  color: var(--qt-accent-texte);
}

.qt-preuve__label::before {
  content: "";
  inline-size: 11px;
  block-size: 2px;
  background-color: var(--qt-or);
  flex: none;
}

.qt-preuve__chiffre {
  display: block;
  font-size: clamp(1.55rem, 1.2rem + 1.1vw, 2.05rem);
  font-weight: var(--qt-w-titre);
  line-height: 1;
  letter-spacing: -0.032em;
  font-variant-numeric: tabular-nums;
  color: var(--qt-encre);
  margin-block: 0.75rem 0.4rem;
}

.qt-preuve__chiffre i {
  font-style: normal;
  font-size: 0.58em;
  font-weight: var(--qt-w-moyen);
  letter-spacing: -0.01em;
  color: var(--qt-encre-tenue);
  margin-inline-start: 0.13em;
}

.qt-preuve__detail {
  display: block;
  font-size: var(--qt-t-mention);
  line-height: 1.42;
  color: var(--qt-encre-tenue);
  text-wrap: balance;
  max-width: 22ch;
}

/* ---- Colonne média : la photo, nue ---- */

.qt-hero__media { display: flex; flex-direction: column; }

.qt-carrousel {
  position: relative;
  aspect-ratio: 5 / 6;
  overflow: hidden;
  background-color: var(--qt-nuit);
  /* Même rayon que tous les autres conteneurs photo du site (photo du hero,
     tuiles de la galerie, réalisations, scène du sélecteur). Le carrousel
     était le seul à angles droits, sans raison identifiable. */
  border-radius: var(--qt-rayon-l);
}

.qt-carrousel__vue {
  position: absolute;
  inset: 0;
  margin: 0;
  opacity: 0;
  transition: opacity 0.9s var(--qt-ease);
  will-change: opacity;
}

.qt-carrousel__vue.est-active { opacity: 1; }

.qt-carrousel__vue img {
  display: block;
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
  transform: scale(1.06);
  transition: transform 6s linear;
}

.qt-carrousel__vue.est-active img { transform: scale(1); }

/* ---- Piste : filet de séparation ET jauge d'avancement ---- */

.qt-carrousel__piste {
  display: flex;
  gap: 0;
  margin-block-start: var(--qt-e-s);
}

.qt-carrousel__seg {
  flex: 1;
  block-size: 1px;
  padding: 0;
  border: 0;
  background-color: var(--qt-filet-fort);
  position: relative;
  cursor: pointer;
  overflow: hidden;
}

.qt-carrousel__seg::after {
  content: "";
  position: absolute;
  inset: -11px 0;
}

.qt-carrousel__seg i {
  display: block;
  block-size: 100%;
  background-color: var(--qt-or);
  transform: scaleX(0);
  transform-origin: left;
}

.qt-carrousel__seg:focus-visible {
  outline: 2px solid var(--qt-focus);
  outline-offset: 6px;
}

/* ---- Légende dans la marge ---- */

.qt-carrousel__pied {
  display: flex;
  align-items: baseline;
  gap: var(--qt-e-s);
  margin-block-start: var(--qt-e-s);
}

.qt-carrousel__index {
  font-size: var(--qt-t-mention);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.06em;
  color: var(--qt-encre-tenue);
  flex: none;
}

.qt-carrousel__index b { font-weight: var(--qt-w-semi); color: var(--qt-accent-texte); }

.qt-carrousel__texte {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  min-inline-size: 0;
}

.qt-carrousel__texte b {
  font-size: var(--qt-t-petit);
  font-weight: var(--qt-w-moyen);
  letter-spacing: var(--qt-ls-sous);
  line-height: 1.25;
  color: var(--qt-encre);
}

.qt-carrousel__texte > span {
  font-size: var(--qt-t-mention);
  line-height: 1.4;
  color: var(--qt-encre-tenue);
}

/* ---- Adaptations ---- */

@media (min-width: 1061px) {
  /* La photo absorbe la hauteur restante pour que le bas de la légende
     s'aligne sur le bas de la bande de preuves, à gauche. */
  .qt-carrousel { flex: 1 1 auto; aspect-ratio: auto; min-block-size: 0; }
}

@media (max-width: 1060px) {
  .qt-hero__grille { grid-template-columns: 1fr; gap: 3.5rem; }
  .qt-hero__actions { margin-block-end: var(--qt-e-l); }
  .qt-hero__preuves { margin-block-start: 0; }
  .qt-hero__media { max-inline-size: 440px; margin-inline: auto; inline-size: 100%; }
}

@media (max-width: 620px) {
  /* Trois colonnes resserrées : les empiler triplait la hauteur. */
  .qt-hero__preuves li { padding: 0.95rem 0.5rem 0 0; }
  .qt-hero__preuves li + li { padding-inline-start: 0.7rem; }
  .qt-preuve__label { font-size: 0.53rem; letter-spacing: 0.09em; gap: 0.3rem; }
  .qt-preuve__label::before { inline-size: 9px; }
  .qt-preuve__chiffre { font-size: 1.4rem; margin-block: 0.5rem 0.28rem; }
  .qt-preuve__chiffre i { font-size: 0.55em; }
  .qt-preuve__detail { font-size: 0.7rem; line-height: 1.3; max-width: none; }
}

@media (prefers-reduced-motion: reduce) {
  .qt-carrousel__vue,
  .qt-carrousel__vue img { transition: none; }
  .qt-carrousel__vue img { transform: none; }
}


/* ==========================================================================
   8. CARTES
   ========================================================================== */

.qt-carte {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--qt-e-s);
  padding: var(--qt-e-m);
  border-radius: var(--qt-rayon-l);
  border: var(--qt-trait) solid var(--qt-filet-clair);
  background-color: var(--qt-fond-alt);
  transition:
    transform var(--qt-d-court) var(--qt-ease),
    border-color var(--qt-d-court) var(--qt-ease),
    box-shadow var(--qt-d-court) var(--qt-ease);
}

.qt-carte--liante:hover {
  transform: translateY(-4px);
  border-color: color-mix(in srgb, var(--qt-or) 42%, transparent);
  box-shadow: var(--qt-ombre-levee);
}

.qt-carte__media {
  margin: calc(var(--qt-e-m) * -1) calc(var(--qt-e-m) * -1) 0;
  border-radius: var(--qt-rayon-l) var(--qt-rayon-l) 0 0;
  overflow: hidden;
}

.qt-carte__media img {
  border-radius: 0;
  inline-size: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
}

.qt-carte__pied {
  margin-block-start: auto;
  padding-block-start: var(--qt-e-s);
  border-block-start: var(--qt-trait) solid var(--qt-filet-clair);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--qt-e-2xs);
  flex-wrap: wrap;
}

.qt-prix {
  display: flex;
  align-items: baseline;
  gap: 0.35rem;
  font-variant-numeric: tabular-nums lining-nums;
}

.qt-prix__valeur {
  font-size: var(--qt-t-titre);
  font-weight: var(--qt-w-normal);
  letter-spacing: -0.035em;
  line-height: 1;
  color: var(--qt-encre);
}

.qt-prix__mention {
  font-size: var(--qt-t-mention);
  font-weight: var(--qt-w-moyen);
  color: var(--qt-encre-tenue);
}


/* Liste à coches */
.qt-liste-coches { display: grid; gap: var(--qt-e-2xs); }

/* Retrait pendant, et non grille.
   En grille, chaque nœud de texte devient un item anonyme : un <strong> ou
   un <a> au milieu d'une puce renvoyait le reste du texte dans la colonne
   de l'icône, large de 1,15 rem, et la phrase tombait un mot par ligne.
   Ici la puce est un bloc normal : tout son contenu inline coule d'un seul
   tenant, et l'icône est posée dans la gouttière réservée. Le composant
   accepte donc n'importe quel balisage riche sans casser. */
.qt-liste-coches li {
  position: relative;
  padding-inline-start: calc(1.15rem + var(--qt-e-2xs));
  font-size: var(--qt-t-petit);
  line-height: var(--qt-lh-dense);
  color: var(--qt-encre-douce);
}

.qt-liste-coches svg {
  position: absolute;
  inset-inline-start: 0;
  inset-block-start: 0.18em;
  inline-size: 1.15rem;
  block-size: 1.15rem;
  color: var(--qt-accent-texte);
}


/* ==========================================================================
   9. DOMAINES D'INTERVENTION : lignes à filets
   Remplace le bento. Références mesurées sur Mobbin : Instrument, Koto et
   Phantom Studios traitent tous leur section « ce qu'on fait » en lignes
   séparées par des filets, jamais en cartes. Aucun fond de carte, donc
   aucune carte à moitié vide.
   ========================================================================== */

.qt-domaines {
  border-block-start: var(--qt-trait) solid var(--qt-filet-sombre);
}

.qt-domaine {
  position: relative;
  border-block-end: var(--qt-trait) solid var(--qt-filet-sombre);
  transition: background-color var(--qt-d-court) var(--qt-ease);
}

/* ---- Desktop : tout est déplié, la ligne reprend sa grille ---- */

@media (min-width: 761px) {
  .qt-domaine__entete { margin: 0; }

  .qt-domaine__declencheur {
    inline-size: 100%;
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--qt-e-m);
    align-items: start;
    text-align: left;
    background: none;
    border: 0;
    padding: clamp(1.05rem, 0.75rem + 1.05vw, 1.7rem) var(--qt-e-s) 0;
    margin-inline: calc(var(--qt-e-s) * -1);
    /* déplié en permanence : plus rien à déclencher */
    cursor: default;
    pointer-events: none;
  }

  .qt-domaine__signe { display: none; }

  .qt-domaine__contenu {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 8rem;
    gap: var(--qt-e-m);
    align-items: center;
    padding: var(--qt-e-2xs) var(--qt-e-s) clamp(1.05rem, 0.75rem + 1.05vw, 1.7rem);
    margin-inline: calc(var(--qt-e-s) * -1);
  }

/* L'entrée « Moquette de pierre » porte, en plus du texte, un lien vers sa
   page dédiée. Ce troisième enfant prenait la cellule de la vignette par
   placement automatique, et l'image basculait dans la colonne large : une
   photo pleine largeur au milieu d'une liste de vignettes de 8 rem.
   On fixe donc explicitement les deux colonnes.
   Scopé à ce media : sous 761 px la grille est désactivée et un
   grid-column créerait une colonne implicite. */
.qt-domaine__contenu > .qt-lien-fleche {
  grid-column: 1;
  justify-self: start;
  margin-block-start: var(--qt-e-2xs);
}

.qt-domaine__contenu > .qt-domaine__vue {
  grid-column: 2;
  grid-row: 1 / -1;
}
}

@media (min-width: 761px) and (max-width: 1000px) {
  .qt-domaine__contenu { grid-template-columns: minmax(0, 1fr) 5.5rem; }
}

@media (hover: hover) and (min-width: 761px) {
  .qt-domaine:hover { background-color: color-mix(in srgb, var(--qt-sable) 6%, transparent); }
  .qt-domaine:hover .qt-domaine__vue img { transform: scale(1.06); }
}

/* ---- Mobile : accordéon ----
   La section faisait 1911 px, soit 2,2 écrans de défilement pour dix
   lignes, et les 9 photos du balisage étaient purement masquées. Replié,
   le visiteur voit les dix domaines d'un coup et ouvre celui qui le
   concerne, photo comprise. ---- */

@media (max-width: 760px) {
  .qt-domaine__entete { margin: 0; }

  .qt-domaine__declencheur {
    inline-size: 100%;
    display: grid;
    grid-template-columns: minmax(0, 1fr) 1.25rem;
    gap: var(--qt-e-s);
    align-items: center;
    text-align: left;
    background: none;
    border: 0;
    padding-block: 0.95rem;
    padding-inline: var(--qt-e-s);
    margin-inline: calc(var(--qt-e-s) * -1);
    cursor: pointer;
    color: inherit;
    font: inherit;
  }

  .qt-domaine__declencheur:focus-visible {
    outline: 2px solid var(--qt-focus);
    outline-offset: -3px;
    border-radius: var(--qt-rayon-xs);
  }


  .qt-domaine__signe {
    inline-size: 1.15rem;
    block-size: 1.15rem;
    color: var(--qt-sable);
    justify-self: end;
    transition: transform var(--qt-d-court) var(--qt-ease);
  }

  .qt-domaine__declencheur[aria-expanded="true"] .qt-domaine__signe {
    transform: rotate(45deg);
  }

  /* Ouverture en douceur sans mesurer la hauteur en JS :
     la piste de grille passe de 0fr à 1fr. */
  .qt-domaine__panneau {
    display: grid;
    grid-template-rows: 0fr;
    transition: grid-template-rows var(--qt-d-court) var(--qt-ease);
  }

  .qt-domaine__panneau.est-ouvert { grid-template-rows: 1fr; }

  .qt-domaine__contenu {
    overflow: hidden;
    min-block-size: 0;
  }

  .qt-domaine__texte { padding-block-end: var(--qt-e-s); }

  /* La photo n'est plus masquée : elle devient la récompense de l'ouverture. */
  .qt-domaine__vue {
    display: block;
    inline-size: 100%;
    aspect-ratio: 16 / 10;
    overflow: hidden;
    border-radius: var(--qt-rayon-m);
    margin-block-end: var(--qt-e-m);
  }

  .qt-domaine__vue img {
    inline-size: 100%;
    block-size: 100%;
    object-fit: cover;
  }
}


.qt-domaine__nom {
  font-size: clamp(1.15rem, 1.02rem + 0.52vw, 1.5rem);
  font-weight: var(--qt-w-titre);
  line-height: 1.2;
  letter-spacing: var(--qt-ls-titre);
  color: var(--qt-blanc);
  text-wrap: balance;
}

.qt-domaine__texte {
  font-size: var(--qt-t-petit);
  line-height: var(--qt-lh-dense);
  color: var(--qt-sable-clair);
  max-width: 48ch;
}

/* Vignette : angles vifs, jamais de carte arrondie */
.qt-domaine__vue {
  overflow: hidden;
  border-radius: var(--qt-rayon-xs);
  aspect-ratio: 16 / 11;
  background-color: color-mix(in srgb, var(--qt-marine) 60%, transparent);
  justify-self: end;
  inline-size: 100%;
}

.qt-domaine__vue img {
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
  filter: saturate(0.82) contrast(1.04);
  transition: transform var(--qt-d-long) var(--qt-ease);
}

/* La ligne phare : moquette de pierre. Filet doré et prix à la place de la vignette. */
.qt-domaine--phare { border-block-end-color: color-mix(in srgb, var(--qt-or) 55%, transparent); }

.qt-domaine__prix {
  justify-self: end;
  text-align: right;
  font-size: var(--qt-t-sous-titre);
  font-weight: var(--qt-w-normal);
  font-variant-numeric: tabular-nums;
  color: var(--qt-sable);
  line-height: 1.1;
  white-space: nowrap;
}

.qt-domaine__prix small {
  display: block;
  font-size: 0.62rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: color-mix(in srgb, var(--qt-sable-clair) 62%, transparent);
  margin-block-start: 3px;
}

/* Toute la ligne est cliquable quand elle mène quelque part */
/* .qt-domaine__lien retiré : c'était un lien étiré posé DANS le bouton
   de dépliage. Il avalait tout le clic, donc la dixième entrée partait
   sur sa page au lieu de montrer sa photo comme les neuf autres. Le
   lien vit désormais dans le panneau. */


/* ==========================================================================
   10. AVANT / APRÈS
   Le geste signature. Pilotable souris, doigt et clavier.
   Ne s'affiche que s'il existe une vraie paire de photos.
   ========================================================================== */

.qt-avant-apres {
  position: relative;
  inline-size: 100%;
  aspect-ratio: 3 / 2;
  border-radius: var(--qt-rayon-l);
  overflow: hidden;
  user-select: none;
  touch-action: pan-y;
  cursor: ew-resize;
  background-color: var(--qt-marine);
}

.qt-avant-apres img {
  position: absolute;
  inset: 0;
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
  pointer-events: none;
}

.qt-avant-apres__apres {
  clip-path: inset(0 0 0 var(--qt-position, 50%));
}

.qt-avant-apres__poignee {
  position: absolute;
  inset-block: 0;
  left: var(--qt-position, 50%);
  inline-size: 2px;
  background-color: var(--qt-or);
  transform: translateX(-50%);
  pointer-events: none;
}

.qt-avant-apres__bouton {
  position: absolute;
  top: 50%;
  /* il suit la poignée : figé à 50 %, il se décollait du trait dès
     qu'on faisait glisser la comparaison */
  left: var(--qt-position, 50%);
  transform: translate(-50%, -50%);
  inline-size: 3rem;
  block-size: 3rem;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background-color: var(--qt-or);
  color: var(--qt-marine);
  box-shadow: var(--qt-lueur-or);
  pointer-events: auto;
  cursor: ew-resize;
}

.qt-avant-apres__bouton svg { inline-size: 1.35rem; }

.qt-avant-apres__etiquette {
  position: absolute;
  top: var(--qt-e-s);
  padding: 0.35rem 0.75rem;
  border-radius: var(--qt-rayon-plein);
  background-color: color-mix(in srgb, var(--qt-nuit) 78%, transparent);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  font-size: var(--qt-t-mention);
  font-weight: var(--qt-w-gras);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--qt-sable-pale);
  pointer-events: none;
}

.qt-avant-apres__etiquette--avant { left: var(--qt-e-s); }
.qt-avant-apres__etiquette--apres { right: var(--qt-e-s); }


/* ==========================================================================
   11. MÉTHODE : étapes en scroll collant
   ========================================================================== */

.qt-methode {
  display: grid;
  grid-template-columns: 1fr 1.15fr;
  gap: var(--qt-e-2xl);
  align-items: start;
}

@media (max-width: 1000px) { .qt-methode { grid-template-columns: 1fr; } }

.qt-methode__visuel {
  position: sticky;
  top: 7rem;
  border-radius: var(--qt-rayon-l);
  overflow: hidden;
  aspect-ratio: 4 / 5;
  background-color: var(--qt-marine);
}

@media (max-width: 1000px) { .qt-methode__visuel { display: none; } }

.qt-methode__visuel img {
  position: absolute;
  inset: 0;
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity var(--qt-d-moyen) var(--qt-ease);
}

.qt-methode__visuel img.est-active { opacity: 1; }

.qt-etape {
  display: grid;
  grid-template-columns: 3.25rem 1fr;
  gap: var(--qt-e-m);
  padding-block: var(--qt-e-l);
  border-block-end: var(--qt-trait) solid var(--qt-filet-clair);
  opacity: 0.42;
  transition: opacity var(--qt-d-court) var(--qt-ease);
}

.qt-etape.est-active { opacity: 1; }
.qt-etape:last-child { border-block-end: 0; }

.qt-etape__numero {
  inline-size: 3.25rem;
  block-size: 3.25rem;
  display: grid;
  place-items: center;
  border-radius: 50%;
  border: 2px solid var(--qt-filet-fort);
  font-size: var(--qt-t-sous-titre);
  font-weight: var(--qt-w-noir);
  font-variant-numeric: tabular-nums;
  color: var(--qt-encre);
  transition: border-color var(--qt-d-court) var(--qt-ease),
              background-color var(--qt-d-court) var(--qt-ease),
              color var(--qt-d-court) var(--qt-ease);
}

.qt-etape.est-active .qt-etape__numero {
  border-color: var(--qt-or);
  background-color: var(--qt-or);
  color: var(--qt-marine);
}


/* ==========================================================================
   12. GALERIE IRRÉGULIÈRE
   Tailles variables, aucune ligne de 3 cartes identiques.
   ========================================================================== */

.qt-galerie {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: var(--qt-grille-ecart);
  /* Les tuiles occupent 2 ou 4 colonnes sur 6. En flux normal, une tuile de
     4 qui ne tient pas dans les 2 colonnes restantes saute à la ligne
     suivante et laisse le trou derrière elle : la galerie avait cinq cases
     vides. « dense » fait remonter une tuile plus petite pour les combler. */
  grid-auto-flow: dense;
}

.qt-realisation {
  position: relative;
  grid-column: span 2;
  display: block;
  border-radius: var(--qt-rayon-l);
  overflow: hidden;
  background-color: var(--qt-marine);
  isolation: isolate;
}

/* Le « grid-row: span 2 » est retiré. Une tuile haute de deux lignes
   empêche la grille de combler autour d'elle : quatre lignes de la galerie
   restaient incomplètes, dont une à deux colonnes sur six. Le format portrait
   est conservé par le rapport d'image, qui lui ne perturbe pas le pavage. */
.qt-realisation--haute  { grid-column: span 2; }
.qt-realisation--large  { grid-column: span 4; }
.qt-realisation--pleine { grid-column: span 6; }

.qt-realisation img {
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
  aspect-ratio: 4 / 3;
  transition: transform var(--qt-d-long) var(--qt-ease);
}

.qt-realisation--haute img  { aspect-ratio: 3 / 4; }
.qt-realisation--large img  { aspect-ratio: 16 / 9; }
.qt-realisation--pleine img { aspect-ratio: 21 / 9; }

.qt-realisation:hover img { transform: scale(1.04); }

.qt-realisation__legende {
  position: absolute;
  inset-inline: 0;
  bottom: 0;
  padding: var(--qt-e-2xl) var(--qt-e-m) var(--qt-e-m);
  background: linear-gradient(to top,
    color-mix(in srgb, var(--qt-nuit) 92%, transparent) 0%,
    color-mix(in srgb, var(--qt-nuit) 55%, transparent) 45%,
    transparent 100%);
  color: var(--qt-blanc);
}

.qt-realisation__legende h3 {
  font-size: var(--qt-t-sous-titre);
  font-weight: var(--qt-w-gras);
  letter-spacing: var(--qt-ls-sous);
}

.qt-realisation__meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--qt-e-2xs);
  margin-block-start: var(--qt-e-3xs);
  font-size: var(--qt-t-mention);
  color: var(--qt-sable-clair);
  font-variant-numeric: tabular-nums;
}

.qt-realisation__meta span::after {
  content: "·";
  margin-inline-start: var(--qt-e-2xs);
  color: var(--qt-sable);
}

.qt-realisation__meta span:last-child::after { content: none; }

@media (max-width: 900px) {
  .qt-galerie { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .qt-realisation,
  .qt-realisation--haute,
  .qt-realisation--large,
  .qt-realisation--pleine { grid-column: span 2; grid-row: auto; }
  .qt-realisation--haute img { aspect-ratio: 4 / 3; }
}


/* ==========================================================================
   13. AVIS
   ========================================================================== */

.qt-avis {
  display: flex;
  flex-direction: column;
  gap: var(--qt-e-m);
  padding: var(--qt-e-l);
  border-radius: var(--qt-rayon-l);
  border: var(--qt-trait) solid var(--qt-filet-clair);
  background-color: var(--qt-fond-alt);
}

.qt-avis__note {
  display: flex;
  gap: 2px;
  color: var(--qt-or);
}

.qt-avis__note svg { inline-size: 1rem; block-size: 1rem; }

.qt-avis__texte {
  font-size: var(--qt-t-sous-titre);
  font-weight: var(--qt-w-leger);
  line-height: var(--qt-lh-sous);
  letter-spacing: var(--qt-ls-sous);
}

.qt-avis__auteur {
  display: flex;
  align-items: center;
  gap: var(--qt-e-xs);
  margin-block-start: auto;
  padding-block-start: var(--qt-e-s);
  border-block-start: var(--qt-trait) solid var(--qt-filet-clair);
}

.qt-avis__initiales {
  inline-size: 2.6rem;
  block-size: 2.6rem;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background-color: var(--qt-marine);
  color: var(--qt-sable-pale);
  font-weight: var(--qt-w-gras);
  font-size: var(--qt-t-petit);
  flex: none;
}

.qt-avis__nom { font-weight: var(--qt-w-semi); font-size: var(--qt-t-petit); }
.qt-avis__lieu { font-size: var(--qt-t-mention); color: var(--qt-encre-tenue); }


/* ==========================================================================
   14. FAQ
   ========================================================================== */

/* En-tête de la FAQ.

   Il était collant via un style inline « position:sticky;top:7rem ».
   Sur desktop c'est voulu : le titre reste accroché pendant qu'on parcourt
   les questions. Mais sous 900 px le .qt-split passe à une seule colonne,
   l'en-tête se figeait donc AU-DESSUS de la liste et les questions
   défilaient dessous. Le collant ne vaut qu'en deux colonnes. */

.qt-faq__entete { position: static; }

@media (min-width: 901px) {
  .qt-faq__entete {
    position: sticky;
    /* hauteur de l'en-tête de site + respiration */
    top: 7rem;
  }
}


.qt-faq { border-block-start: var(--qt-trait) solid var(--qt-filet-clair); }

.qt-faq__item { border-block-end: var(--qt-trait) solid var(--qt-filet-clair); }

.qt-faq__question {
  inline-size: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--qt-e-m);
  padding-block: var(--qt-e-m);
  text-align: left;
  font-size: var(--qt-t-sous-titre);
  font-weight: var(--qt-w-semi);
  letter-spacing: var(--qt-ls-sous);
  color: var(--qt-encre);
  transition: color var(--qt-d-micro) var(--qt-ease);
}

.qt-faq__question:hover { color: var(--qt-accent-texte); }

.qt-faq__chevron {
  inline-size: 1.4rem;
  block-size: 1.4rem;
  flex: none;
  color: var(--qt-accent-texte);
  transition: transform var(--qt-d-court) var(--qt-ease);
}

.qt-faq__question[aria-expanded="true"] .qt-faq__chevron { transform: rotate(180deg); }

.qt-faq__reponse {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows var(--qt-d-court) var(--qt-ease);
}

.qt-faq__reponse[data-ouvert="true"] { grid-template-rows: 1fr; }

.qt-faq__reponse > div { overflow: hidden; }

.qt-faq__reponse p {
  padding-block-end: var(--qt-e-m);
  color: var(--qt-encre-douce);
  max-width: var(--qt-mesure);
}


/* ==========================================================================
   15. CTA FINAL
   ========================================================================== */

/* Section claire. Même traitement de fond que le hero : blanc en haut,
   crème en bas. La descente vers le crème amorce le pied de page sombre
   au lieu de le laisser tomber d'un coup sur du blanc pur. */
.qt-cta-final {
  position: relative;
  overflow: hidden;
  text-align: center;
  padding-block: var(--qt-section-y-large);
  color: var(--qt-encre);
  background-color: var(--qt-lin);
  background-image:
    radial-gradient(
      100% 70% at 50% 8%,
      color-mix(in srgb, var(--qt-or) 8%, transparent) 0%,
      transparent 64%),
    var(--qt-degrade-clair);
  isolation: isolate;
}

/* Titre du CTA final : une seule ligne, sur toutes les pages.
   Le max-width de 14ch le cassait systématiquement en deux. Il est retiré,
   et nowrap interdit tout retour. La taille ne peut donc plus venir de
   l'échelle display : elle est proportionnelle à la largeur du viewport,
   calibrée sur le titre le plus long du site (30 caractères) pour qu'il
   tienne encore à 360 px. Le plafond reste celui du display-xl. */
.qt-cta-final__titre {
  margin-inline: auto;
  max-width: none;
  white-space: nowrap;
  font-size: clamp(1.3rem, 6vw, 4.1rem);
}

.qt-cta-final__chapeau {
  margin-inline: auto;
  margin-block: var(--qt-e-m) var(--qt-e-l);
  color: var(--qt-encre-douce);
  max-width: 48ch;
}

.qt-cta-final__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--qt-e-xs);
  justify-content: center;
}


/* ==========================================================================
   16. FORMULAIRE
   ========================================================================== */

.qt-champ { display: grid; gap: var(--qt-e-3xs); }

.qt-champ__etiquette {
  font-size: var(--qt-t-mention);
  font-weight: var(--qt-w-semi);
  letter-spacing: 0.02em;
  color: var(--qt-encre-douce);
}

.qt-champ__etiquette span { color: var(--qt-accent-texte); }

.qt-champ input,
.qt-champ select,
.qt-champ textarea {
  inline-size: 100%;
  padding: 0.85rem 1rem;
  border-radius: var(--qt-rayon-s);
  border: var(--qt-trait) solid var(--qt-filet-fort);
  /* Le champ était au même ton que le fond de la modale, et à peine plus
     clair que les sections --alt : un contour seul ne suffit pas à le
     désigner comme saisissable. Le lin le détache des deux. */
  background-color: var(--qt-lin);
  color: var(--qt-encre);
  font-size: var(--qt-t-petit);
  transition: border-color var(--qt-d-micro) var(--qt-ease),
              box-shadow var(--qt-d-micro) var(--qt-ease);
}

.qt-champ input::placeholder,
.qt-champ textarea::placeholder { color: var(--qt-encre-tenue); }

.qt-champ input:focus,
.qt-champ select:focus,
.qt-champ textarea:focus {
  outline: none;
  border-color: var(--qt-or);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--qt-or) 22%, transparent);
}

.qt-champ textarea { min-block-size: 7rem; resize: vertical; }

/* Choix en pastilles cliquables : plus engageant qu'un select */
/* .qt-choix retiré : les pastilles transparentes de la page devis ont
   été remplacées par .qt-options. Plus aucune page ne les utilisait. */



/* ==========================================================================
   17. PIED DE PAGE
   Éditorial, pas quatre colonnes génériques.
   ========================================================================== */

.qt-pied {
  background-color: var(--qt-nuit);
  color: var(--qt-sable-clair);
  padding-block: var(--qt-e-3xl) var(--qt-e-l);
  border-block-start: var(--qt-trait) solid var(--qt-filet-sombre);
}

.qt-pied__haut {
  display: grid;
  grid-template-columns: 1.7fr 1fr 1fr;
  gap: var(--qt-e-2xl);
  padding-block-end: var(--qt-e-2xl);
  border-block-end: var(--qt-trait) solid var(--qt-filet-sombre);
}

@media (max-width: 900px) { .qt-pied__haut { grid-template-columns: 1fr; } }

.qt-pied__titre {
  font-size: var(--qt-t-sur-titre);
  font-weight: var(--qt-w-semi);
  letter-spacing: var(--qt-ls-sur-titre);
  text-transform: uppercase;
  color: var(--qt-sable);
  margin-block-end: var(--qt-e-s);
}

.qt-pied__liste { display: grid; gap: var(--qt-e-2xs); }

.qt-pied__liste a {
  font-size: var(--qt-t-petit);
  color: var(--qt-sable-clair);
  transition: color var(--qt-d-instant) var(--qt-ease);
}

.qt-pied__liste a:hover { color: var(--qt-blanc); }

.qt-pied__bas {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--qt-e-s);
  padding-block-start: var(--qt-e-l);
  font-size: var(--qt-t-mention);
  color: color-mix(in srgb, var(--qt-sable-clair) 68%, transparent);
}

.qt-reseaux { display: flex; gap: var(--qt-e-2xs); }

.qt-reseaux a {
  inline-size: 2.4rem;
  block-size: 2.4rem;
  display: grid;
  place-items: center;
  border-radius: var(--qt-rayon-s);
  border: var(--qt-trait) solid var(--qt-filet-sombre);
  color: var(--qt-sable-clair);
  transition: all var(--qt-d-micro) var(--qt-ease);
}

.qt-reseaux a:hover {
  border-color: var(--qt-or);
  color: var(--qt-or);
  transform: translateY(-2px);
}

.qt-reseaux svg { inline-size: 1.15rem; block-size: 1.15rem; }


/* ==========================================================================
   18. UTILITAIRES DE DONNÉES À COMPLÉTER
   L'attribut data-attente reste dans le HTML : c'est lui qui recense les
   emplacements en attente d'information client (téléphone, e-mail, zone,
   BCE). Il n'a plus de rendu visuel — le contour pointillé de développement
   a été retiré. Pour les retrouver : grep -n 'data-attente' index.html
   ========================================================================== */


/* ==========================================================================
   19. SÉLECTEUR DE MATIÈRE
   Remplace les trois cards identiques de la première version.
   Une scène de matière plein cadre à gauche, la liste éditoriale à droite.
   La matière change au survol et au clic. C'est le produit qu'on regarde,
   pas trois rectangles alignés.
   ========================================================================== */

.qt-selecteur {
  display: grid;
  grid-template-columns: 1.15fr 0.85fr;
  gap: clamp(1.5rem, 1rem + 2.5vw, 3.5rem);
  align-items: stretch;
}

@media (max-width: 980px) { .qt-selecteur { grid-template-columns: 1fr; } }

.qt-selecteur__scene {
  position: relative;
  border-radius: var(--qt-rayon-l);
  overflow: hidden;
  min-block-size: clamp(22rem, 18rem + 16vw, 34rem);
  background-color: var(--qt-nuit);
  box-shadow: var(--qt-ombre-haute);
}

.qt-selecteur__couche {
  position: absolute;
  inset: 0;
  opacity: 0;
  transform: scale(1.04);
  transition:
    opacity var(--qt-d-moyen) var(--qt-ease),
    transform var(--qt-d-long) var(--qt-ease);
}

.qt-selecteur__couche.est-active { opacity: 1; transform: scale(1); }

/* Les couches portent désormais de vraies photos, plus des textures CSS.
   Le cadrage bas privilégie le sol, pas le plafond. */
.qt-selecteur__couche img {
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
  object-position: center 72%;
  display: block;
}

/* Bandeau d'information posé en bas de la scène */
.qt-selecteur__info {
  position: absolute;
  inset-inline: 0;
  bottom: 0;
  z-index: 3;
  padding: var(--qt-e-3xl) var(--qt-e-l) var(--qt-e-l);
  background: linear-gradient(to top,
    color-mix(in srgb, var(--qt-nuit) 95%, transparent) 0%,
    color-mix(in srgb, var(--qt-nuit) 70%, transparent) 42%,
    transparent 100%);
  color: var(--qt-blanc);
}

.qt-selecteur__nom {
  font-size: var(--qt-t-titre);
  font-weight: var(--qt-w-display);
  letter-spacing: var(--qt-ls-titre);
  line-height: 1.05;
}

.qt-selecteur__desc {
  margin-block-start: var(--qt-e-2xs);
  color: var(--qt-sable-clair);
  font-size: var(--qt-t-petit);
  max-width: 46ch;
}

.qt-selecteur__atouts {
  display: flex;
  flex-wrap: wrap;
  gap: var(--qt-e-2xs);
  margin-block-start: var(--qt-e-s);
}

.qt-selecteur__atout {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.3rem 0.65rem;
  border-radius: var(--qt-rayon-plein);
  border: var(--qt-trait) solid color-mix(in srgb, var(--qt-sable) 30%, transparent);
  background-color: color-mix(in srgb, var(--qt-nuit) 55%, transparent);
  font-size: var(--qt-t-mention);
  font-weight: var(--qt-w-moyen);
  color: var(--qt-sable-pale);
}

.qt-selecteur__atout svg { inline-size: 0.85rem; block-size: 0.85rem; color: var(--qt-or); }

/* Liste éditoriale : hairlines, gros chiffres, aucune card */
.qt-selecteur__liste {
  display: flex;
  flex-direction: column;
  justify-content: center;
  border-block-start: var(--qt-trait) solid var(--qt-filet-clair);
  /* de quoi loger la barre d'option active sans rogner le texte */
  padding-inline-start: var(--qt-e-2xs);
}

.qt-sol {
  position: relative;
  inline-size: 100%;
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: var(--qt-e-s) var(--qt-e-m);
  align-items: baseline;
  text-align: left;
  padding-block: clamp(1.1rem, 0.7rem + 1.2vw, 1.9rem);
  border-block-end: var(--qt-trait) solid var(--qt-filet-clair);
  color: var(--qt-encre);
  transition: color var(--qt-d-micro) var(--qt-ease);
}

/* Indicateur d'option active : une barre verticale à gauche.
   Un filet horizontal posé sous la ligne active se lisait comme
   appartenant à l'option SUIVANTE : l'œil rattache une ligne à ce
   qu'elle souligne, pas à ce qu'elle surligne. */
.qt-sol::after {
  content: "";
  position: absolute;
  inset-inline-start: calc(-1 * var(--qt-e-2xs));
  top: 50%;
  translate: 0 -50%;
  inline-size: 2px;
  block-size: 0;
  background-color: var(--qt-or);
  transition: block-size var(--qt-d-court) var(--qt-ease);
}

.qt-sol[aria-selected="true"]::after { block-size: 62%; }

.qt-sol__index {
  font-size: var(--qt-t-mention);
  font-weight: var(--qt-w-gras);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.1em;
  color: var(--qt-encre-tenue);
  transition: color var(--qt-d-micro) var(--qt-ease);
}

.qt-sol[aria-selected="true"] .qt-sol__index { color: var(--qt-accent-texte); }

.qt-sol__nom {
  font-size: clamp(1.2rem, 1.05rem + 0.65vw, 1.62rem);
  font-weight: var(--qt-w-titre);
  letter-spacing: var(--qt-ls-titre);
  line-height: 1.15;
  transition: opacity var(--qt-d-micro) var(--qt-ease);
}

.qt-sol[aria-selected="false"] .qt-sol__nom { opacity: 0.45; }

.qt-sol:hover .qt-sol__nom { opacity: 1; }

.qt-sol__prix {
  font-size: var(--qt-t-sous-titre);
  font-weight: var(--qt-w-normal);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.03em;
  color: var(--qt-encre);
  white-space: nowrap;
}

.qt-sol__prix small {
  display: block;
  font-size: 0.6rem;
  font-weight: var(--qt-w-moyen);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--qt-encre-tenue);
  margin-block-start: 2px;
}

.qt-sol__usage {
  grid-column: 2 / -1;
  font-size: var(--qt-t-mention);
  color: var(--qt-encre-tenue);
  letter-spacing: 0.01em;
}


/* ==========================================================================
   ENGAGEMENTS
   Liste éditoriale à filets. Trois colonnes sur desktop : l'index, le
   couple « moment + promesse », puis la preuve. Sur mobile la preuve
   passe sous le titre plutôt que de se tasser dans une colonne étroite,
   ce qui cassait les mots.
   ========================================================================== */

.qt-engagements {
  list-style: none;
  margin: 0;
  padding: 0;
  border-block-start: var(--qt-trait) solid var(--qt-filet-sombre-fort);
}

.qt-engagement {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 0.95fr) minmax(0, 1.15fr);
  gap: var(--qt-e-m);
  align-items: start;
  padding-block: clamp(1.25rem, 0.9rem + 1.3vw, 2rem);
  padding-inline: var(--qt-e-s);
  margin-inline: calc(var(--qt-e-s) * -1);
  border-block-end: var(--qt-trait) solid var(--qt-filet-sombre);
  transition: background-color var(--qt-d-court) var(--qt-ease);
}

@media (hover: hover) {
  .qt-engagement:hover { background-color: color-mix(in srgb, var(--qt-sable) 6%, transparent); }
  .qt-engagement:hover .qt-engagement__quand { color: var(--qt-sable); }
}

/* Plus d'index numéroté : c'est le libellé « quand » qui ouvre la ligne.
   Le site en comptait 257 sur sept composants, au point que chaque section
   se lisait comme une liste ordonnée. */
.qt-engagement__quand {
  font-size: 0.6rem;
  font-weight: var(--qt-w-gras);
  letter-spacing: 0.17em;
  text-transform: uppercase;
  color: var(--qt-accent-texte-inv);
  margin-block-end: 0.4rem;
  transition: color var(--qt-d-court) var(--qt-ease);
}

.qt-engagement__nom {
  font-size: clamp(1.1rem, 1rem + 0.5vw, 1.45rem);
  font-weight: var(--qt-w-titre);
  line-height: 1.2;
  letter-spacing: var(--qt-ls-titre);
  color: var(--qt-blanc);
  text-wrap: balance;
}

.qt-engagement__texte {
  font-size: var(--qt-t-petit);
  line-height: var(--qt-lh-dense);
  color: var(--qt-sable-clair);
  padding-block-start: 0.15rem;
}

@media (max-width: 900px) {
  /* Une seule colonne : en deux colonnes serrées, les mots se coupaient
     lettre à lettre. */
  .qt-engagement {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--qt-e-2xs);
  }
  .qt-engagement__texte { padding-block-start: var(--qt-e-2xs); }
}


/* ==========================================================================
   23. SÉPARATEURS ENTRE SECTIONS
   Filet dégradé posé en haut de chaque section qui suit une section de
   même fond. C'était déclaré mais jamais utilisé dans la première version.
   ========================================================================== */

.qt-section--filet { position: relative; }

.qt-section--filet::before {
  content: "";
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  inline-size: min(82%, var(--qt-largeur-max));
  block-size: 1px;
  background-image: linear-gradient(to right, transparent, var(--qt-filet-fort), transparent);
}


/* ==========================================================================
   25. FOOTER STATEMENT
   Remplace le footer trois colonnes générique.
   ========================================================================== */

.qt-pied__claim {
  font-size: clamp(1.7rem, 1.25rem + 1.9vw, 2.9rem);
  font-weight: var(--qt-w-display);
  line-height: 1.0;
  letter-spacing: var(--qt-ls-display);
  color: var(--qt-blanc);
  max-width: 16ch;
  text-wrap: balance;
}

.qt-pied__statement {
  display: grid;
  grid-template-columns: 1.3fr auto;
  gap: var(--qt-e-2xl);
  align-items: end;
  padding-block-end: var(--qt-e-2xl);
}

@media (max-width: 820px) {
  .qt-pied__statement { grid-template-columns: 1fr; align-items: start; }
}

.qt-pied__signature {
  display: flex;
  align-items: center;
  gap: var(--qt-e-2xs);
  font-size: var(--qt-t-mention);
  color: color-mix(in srgb, var(--qt-sable-clair) 62%, transparent);
}

.qt-pied__signature a {
  color: var(--qt-sable);
  border-bottom: 1px solid color-mix(in srgb, var(--qt-sable) 40%, transparent);
  transition: color var(--qt-d-instant) var(--qt-ease);
}

.qt-pied__signature a:hover { color: var(--qt-or); }


/* ==========================================================================
   26. TARIF MIS EN AVANT
   Lueur dorée et mesh sous la carte extérieur, qui est la plus demandée.
   ========================================================================== */

.qt-carte--phare {
  position: relative;
  border-color: color-mix(in srgb, var(--qt-or) 50%, transparent);
  background-image:
    radial-gradient(ellipse 70% 55% at 88% 6%,  color-mix(in srgb, var(--qt-or) 15%, transparent), transparent 62%),
    radial-gradient(ellipse 60% 50% at 6% 94%,  color-mix(in srgb, var(--qt-sable) 16%, transparent), transparent 64%);
  box-shadow: 0 22px 60px -30px color-mix(in srgb, var(--qt-or) 75%, transparent);
}

.qt-carte--phare::before {
  content: "";
  position: absolute;
  inset-inline: 12%;
  top: -1px;
  block-size: 2px;
  background: linear-gradient(to right, transparent, var(--qt-or), transparent);
}


/* ==========================================================================
   27. INDICATEURS DE CONFIANCE EN LIGNE
   Sous le CTA final. Chiffres réels uniquement.
   ========================================================================== */

.qt-preuves {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: var(--qt-e-xs) var(--qt-e-m);
  margin-block-start: var(--qt-e-l);
  padding-block-start: var(--qt-e-m);
  border-block-start: var(--qt-trait) solid var(--qt-filet-clair);
}

/* Le texte est enfermé dans un <span> : en inline-flex, chaque nœud de texte
   devient un item anonyme et prend le gap. Sans le span, la virgule de
   « 0 €, sur place » se décollait du montant. */
.qt-preuves__item {
  display: inline-flex;
  align-items: center;
  gap: var(--qt-e-2xs);
  font-size: var(--qt-t-petit);
  font-weight: var(--qt-w-moyen);
  color: var(--qt-encre-douce);
  font-variant-numeric: tabular-nums;
}

.qt-preuves__item strong {
  font-weight: var(--qt-w-noir);
  color: var(--qt-encre);
}

/* Bronze et non doré vif : l'or à 3,14:1 sur blanc tombe sous 3:1 dès que le
   fond passe au crème, et ces pictos sont à 1,05rem. */
.qt-preuves__item svg {
  inline-size: 1.05rem;
  block-size: 1.05rem;
  color: var(--qt-accent-texte);
  flex: none;
}


/* ==========================================================================
   28. FILET DÉGRADÉ AVANT LE PIED DE PAGE
   ========================================================================== */

.qt-pied {
  position: relative;
  border-block-start: 0;
}

.qt-pied::before {
  content: "";
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  inline-size: min(88%, var(--qt-largeur-max));
  block-size: 1px;
  background-image: linear-gradient(to right,
    transparent,
    color-mix(in srgb, var(--qt-sable) 42%, transparent) 30%,
    color-mix(in srgb, var(--qt-or) 55%, transparent) 50%,
    color-mix(in srgb, var(--qt-sable) 42%, transparent) 70%,
    transparent);
}


/* --------------------------------------------------------------------------
   EN-TÊTE FLOTTANT : ajustements de place
   -------------------------------------------------------------------------- */

.qt-entete__cta [data-court] { display: none; }

@media (max-width: 1080px) {
  /* Le hero passe sous l'en-tête fixe : il lui faut de quoi ne pas être masqué.
     12 px de marge + 68 px de barre + 12 px de respiration. */
  .qt-hero { padding-block-start: calc(var(--qt-section-y) + var(--qt-degagement-entete)); }
}

@media (max-width: 560px) {
  /* « Diagnostic gratuit » + logo + burger ne tiennent pas dans 351 px.
     Le libellé raccourcit, l'aria-label du lien garde l'intitulé complet. */
  .qt-entete__cta [data-long]  { display: none; }
  .qt-entete__cta [data-court] { display: inline; }

  .qt-entete__cta {
    padding-inline: var(--qt-e-s);
    font-size: var(--qt-t-mention);
  }

  .qt-entete__inner { gap: var(--qt-e-2xs); }
  .qt-logo img { block-size: 1.7rem; }
}


/* ==========================================================================
   COMPLÉMENTS DE RESTAURATION
   Classes utilisées par les sections reconstruites et qui n'avaient pas
   encore de règles propres.
   ========================================================================== */

/* Liste des étapes de la méthode : c'est un <ol>, il faut le dénuder. */
.qt-etapes {
  list-style: none;
  margin: 0;
  padding: 0;
  border-block-start: var(--qt-trait) solid var(--qt-filet-clair);
}

/* Tuiles de la galerie. La grille .qt-galerie fait 6 colonnes, chaque
   tuile déclare son empan en inline pour casser la régularité. */
.qt-galerie__tuile {
  position: relative;
  margin: 0;
  overflow: hidden;
  border-radius: var(--qt-rayon-l);
  background-color: var(--qt-marine);
  aspect-ratio: 4 / 3;
}

.qt-galerie__tuile img {
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
  transition: transform var(--qt-d-long) var(--qt-ease);
}

@media (hover: hover) {
  .qt-galerie__tuile:hover img { transform: scale(1.05); }
}

.qt-galerie__tuile figcaption {
  position: absolute;
  inset-inline: 0;
  bottom: 0;
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  padding: var(--qt-e-2xl) var(--qt-e-s) var(--qt-e-s);
  background-image: linear-gradient(to top,
    color-mix(in srgb, var(--qt-nuit) 88%, transparent) 0%,
    color-mix(in srgb, var(--qt-nuit) 55%, transparent) 30%,
    transparent 72%);
}

.qt-galerie__tuile figcaption b {
  font-size: var(--qt-t-petit);
  font-weight: var(--qt-w-moyen);
  color: var(--qt-blanc);
  line-height: 1.25;
}

.qt-galerie__tuile figcaption span {
  font-size: var(--qt-t-mention);
  color: var(--qt-sable-clair);
}

@media (max-width: 900px) {
  /* Six colonnes deviennent deux. Les empans doivent être ramenés à 1,
     sinon une tuile en « span 2 » réclame deux colonnes sur une grille qui
     n'en a plus assez et fabrique une colonne implicite de 0 px : la tuile
     déborde et la rangée se casse. Vaut pour les deux familles de tuiles. */
  .qt-galerie { grid-template-columns: repeat(2, minmax(0, 1fr)); }

  .qt-galerie__tuile,
  .qt-realisation,
  .qt-realisation--haute,
  .qt-realisation--large,
  .qt-realisation--pleine {
    grid-column: span 1 !important;
    grid-row: auto !important;
  }
}

@media (max-width: 560px) {
  .qt-galerie { grid-template-columns: 1fr; }

  /* En une seule colonne, tout le monde reprend le même format : garder des
     aspect-ratio différents ferait une colonne en accordéon. */
  .qt-realisation img,
  .qt-realisation--haute img,
  .qt-realisation--large img,
  .qt-realisation--pleine img { aspect-ratio: 4 / 3; }
}

/* Grille à deux colonnes égales, utilisée par les cartes de tarifs. */
.qt-grille-2 {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--qt-grille-ecart);
}

@media (max-width: 820px) {
  .qt-grille-2 { grid-template-columns: 1fr; }
}


/* ==========================================================================
   29. FIL D'ARIANE
   Sur les pages profondes uniquement. Sert autant au visiteur qu'aux
   moteurs : il double le BreadcrumbList du JSON-LD en version visible.
   ========================================================================== */

.qt-fil {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  font-size: var(--qt-t-mention);
  color: var(--qt-encre-tenue);
}

.qt-fil a {
  color: var(--qt-encre-tenue);
  transition: color var(--qt-d-micro) var(--qt-ease);
}

.qt-fil a:hover { color: var(--qt-accent-texte); }

.qt-fil__sep { color: color-mix(in srgb, var(--qt-encre-tenue) 55%, transparent); }
.qt-fil [aria-current="page"] { color: var(--qt-encre); font-weight: var(--qt-w-semi); }


/* ==========================================================================
   30. USAGES : où se pose la matière
   Lignes à filet, jamais des cartes. Chaque ligne porte un lieu, une
   raison technique et la contrainte qui va avec : c'est la raison qui
   fait décider, pas le nom du lieu.
   ========================================================================== */

.qt-usages { display: grid; }

.qt-usage {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.25fr);
  align-items: baseline;
  gap: var(--qt-e-2xs) var(--qt-e-m);
  padding-block: var(--qt-e-m);
  border-block-start: var(--qt-trait) solid var(--qt-filet-clair);
}

.qt-usages .qt-usage:last-child { border-block-end: var(--qt-trait) solid var(--qt-filet-clair); }

/* .qt-usage__icone retiré : voir blocs.usage(). */

.qt-usage__nom {
  font-size: var(--qt-t-sous-titre);
  font-weight: var(--qt-w-semi);
  letter-spacing: -0.015em;
  color: var(--qt-encre);
}

.qt-usage__detail {
  font-size: var(--qt-t-petit);
  color: var(--qt-encre-douce);
}

@media (max-width: 760px) {
  .qt-usage { grid-template-columns: minmax(0, 1fr); }
}


/* ==========================================================================
   31. FACE-À-FACE : deux matières sur un même critère
   Chaque côté porte son nom sur sa propre ligne, puis sa réponse dessous.
   L'ancienne version collait « Époxy — ✓ Conseillé » devant le texte : la
   ligne se lisait comme une phrase à rallonge et le début de chaque
   description tombait à une abscisse différente selon la présence de la
   pastille. Ici les textes s'alignent tous, et le côté conseillé se
   signale par un filet doré plutôt que par une interruption dans la phrase.
   ========================================================================== */

.qt-faces { display: grid; }

.qt-face {
  display: grid;
  grid-template-columns: minmax(0, 0.72fr) minmax(0, 1fr) minmax(0, 1fr);
  gap: var(--qt-e-s) var(--qt-e-m);
  padding-block: var(--qt-e-m);
  border-block-start: var(--qt-trait) solid var(--qt-filet-clair);
}

.qt-faces .qt-face:last-child { border-block-end: var(--qt-trait) solid var(--qt-filet-clair); }

.qt-face__critere {
  font-size: var(--qt-t-petit);
  font-weight: var(--qt-w-semi);
  letter-spacing: -0.01em;
  line-height: var(--qt-lh-dense);
  color: var(--qt-encre);
}

/* Le filet est toujours réservé, transparent quand la matière ne gagne pas
   le critère : sans ça les deux colonnes ne seraient pas alignées. */
.qt-face__cote {
  display: grid;
  gap: 0.3rem;
  align-content: start;
  padding-inline-start: var(--qt-e-s);
  border-inline-start: 2px solid transparent;
}

.qt-face__cote.est-conseille { border-inline-start-color: var(--qt-or); }

.qt-face__nom {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.45rem;
  font-size: var(--qt-t-sur-titre);
  font-weight: var(--qt-w-semi);
  letter-spacing: var(--qt-ls-sur-titre);
  text-transform: uppercase;
  color: var(--qt-encre-tenue);
}

.qt-face__cote.est-conseille .qt-face__nom { color: var(--qt-accent-texte); }

.qt-face__marque {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  padding: 0.1rem 0.45rem;
  border-radius: 999px;
  border: var(--qt-trait) solid color-mix(in srgb, var(--qt-or) 45%, transparent);
  background-color: color-mix(in srgb, var(--qt-or) 10%, transparent);
  letter-spacing: 0.06em;
  color: var(--qt-accent-texte);
}

.qt-face__marque svg { inline-size: 0.75rem; block-size: 0.75rem; }

.qt-face__dit {
  font-size: var(--qt-t-petit);
  line-height: var(--qt-lh-dense);
  color: var(--qt-encre-douce);
}

.qt-face__cote.est-conseille .qt-face__dit {
  color: var(--qt-encre);
  font-weight: var(--qt-w-moyen);
}

/* Empilé, le critère devient un vrai intertitre et les deux côtés se
   suivent. Aucun en-tête de colonne à masquer : chaque côté se nomme. */
@media (max-width: 860px) {
  .qt-face { grid-template-columns: 1fr; gap: var(--qt-e-2xs); }

  .qt-face__critere {
    font-size: var(--qt-t-sous-titre);
    margin-block-end: var(--qt-e-3xs);
  }
}


/* ==========================================================================
   32. COUCHES D'UN COMPLEXE DE SOL
   Liste numérotée décrivant un empilement, de la surface vers le support.
   Chaque ligne porte son épaisseur : c'est le chiffre que le client
   cherche en premier.
   ========================================================================== */

.qt-couches { display: grid; }

.qt-couche {
  display: grid;
  grid-template-columns: 2.5rem minmax(0, 1fr);
  align-items: baseline;
  gap: 0.35rem var(--qt-e-s);
  padding-block: var(--qt-e-s);
  border-block-start: var(--qt-trait) solid var(--qt-filet-sombre);
}

.qt-couches .qt-couche:last-child { border-block-end: var(--qt-trait) solid var(--qt-filet-sombre); }

.qt-couche__index {
  font-size: var(--qt-t-mention);
  font-weight: var(--qt-w-semi);
  letter-spacing: 0.08em;
  font-variant-numeric: tabular-nums lining-nums;
  color: var(--qt-or);
}

.qt-couche__nom {
  font-size: var(--qt-t-sous-titre);
  font-weight: var(--qt-w-semi);
  letter-spacing: -0.015em;
  color: var(--qt-encre);
}

.qt-couche__texte {
  grid-column: 2;
  font-size: var(--qt-t-petit);
  color: var(--qt-encre-douce);
}

.qt-couche__epaisseur {
  grid-column: 2;
  font-size: var(--qt-t-mention);
  font-weight: var(--qt-w-semi);
  font-variant-numeric: tabular-nums;
  color: var(--qt-accent-texte);
}



/* ==========================================================================
   33. MATRICE DE CHOIX : quelle matière pour quelle pièce
   Exclusif à la page pivot. Les pages filles comparent deux matières entre
   elles ; ici on part de la pièce du visiteur, qui est la seule chose qu'il
   connaisse avec certitude en arrivant.
   ========================================================================== */

.qt-matrice { display: grid; }

.qt-matrice__ligne {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 13rem minmax(0, 1.2fr);
  align-items: baseline;
  gap: 0.35rem var(--qt-e-m);
  padding-block: var(--qt-e-s);
  border-block-start: var(--qt-trait) solid var(--qt-filet-clair);
}

.qt-matrice .qt-matrice__ligne:last-child {
  border-block-end: var(--qt-trait) solid var(--qt-filet-clair);
}

.qt-matrice__lieu {
  font-size: var(--qt-t-sous-titre);
  font-weight: var(--qt-w-semi);
  letter-spacing: -0.015em;
  color: var(--qt-encre);
}

/* Le choix est un lien, pas une étiquette : c'est le point de sortie de la
   page pivot vers la page fille. Le soulignement se dessine au survol. */
.qt-matrice__choix {
  position: relative;
  justify-self: start;
  font-size: var(--qt-t-petit);
  font-weight: var(--qt-w-gras);
  color: var(--qt-accent-texte);
  white-space: nowrap;
}

.qt-matrice__choix::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  bottom: -2px;
  block-size: 1.5px;
  background-color: var(--qt-or);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--qt-d-micro) var(--qt-ease);
}

.qt-matrice__choix:hover::after,
.qt-matrice__choix:focus-visible::after { transform: scaleX(1); }

.qt-matrice__raison {
  font-size: var(--qt-t-petit);
  line-height: var(--qt-lh-dense);
  color: var(--qt-encre-douce);
}

@media (max-width: 860px) {
  .qt-matrice__ligne { grid-template-columns: 1fr; gap: 0.3rem; }
  .qt-matrice__raison { order: 3; }
}


/* ==========================================================================
   34. PAGE DEVIS
   Formulaire à gauche, colonne de réassurance à droite. La colonne reste
   visible pendant qu'on remplit : ce qu'elle contient (gratuit, sans
   engagement, délai annoncé) répond aux objections au moment exact où
   elles se posent, pas en haut de page où on les a déjà oubliées.
   ========================================================================== */

.qt-devis {
  display: grid;
  grid-template-columns: minmax(0, 1.35fr) minmax(0, 0.8fr);
  gap: clamp(2rem, 1.5rem + 3vw, 4rem);
  align-items: start;
}

@media (max-width: 940px) {
  .qt-devis { grid-template-columns: 1fr; }
}

.qt-devis__form { display: grid; gap: var(--qt-e-m); }

/* Deux champs par ligne quand ils sont courts (nom, téléphone). */
.qt-devis__duo {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--qt-e-m);
}

@media (max-width: 560px) {
  .qt-devis__duo { grid-template-columns: 1fr; }
}

.qt-devis__groupe {
  display: grid;
  gap: var(--qt-e-2xs);
  padding-block-start: var(--qt-e-2xs);
}

.qt-devis__legende {
  font-size: var(--qt-t-mention);
  font-weight: var(--qt-w-semi);
  letter-spacing: 0.02em;
  color: var(--qt-encre-douce);
}

.qt-devis__legende span { color: var(--qt-accent-texte); }

/* Message d'erreur : sous le champ, jamais en alerte globale en haut de
   page. Le visiteur doit voir quoi corriger sans chercher. */
.qt-erreur {
  font-size: var(--qt-t-mention);
  font-weight: var(--qt-w-moyen);
  color: var(--qt-erreur, #A6321F);
}

.qt-champ input[aria-invalid="true"],
.qt-champ textarea[aria-invalid="true"] {
  border-color: var(--qt-erreur, #A6321F);
}

.qt-champ input[aria-invalid="true"]:focus,
.qt-champ textarea[aria-invalid="true"]:focus {
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--qt-erreur, #A6321F) 20%, transparent);
}

/* Colonne de réassurance */
.qt-rassure {
  display: grid;
  gap: var(--qt-e-m);
  padding: var(--qt-e-l);
  border-radius: var(--qt-rayon-l);
  border: var(--qt-trait) solid var(--qt-filet-clair);
  background-color: color-mix(in srgb, var(--qt-creme-profond) 55%, transparent);
}

.qt-rassure__titre {
  font-size: var(--qt-t-sous-titre);
  font-weight: var(--qt-w-semi);
  letter-spacing: -0.015em;
  color: var(--qt-encre);
}

.qt-rassure__pas { display: grid; gap: var(--qt-e-s); }

.qt-pas {
  display: grid;
  grid-template-columns: 1.6rem minmax(0, 1fr);
  gap: 0.2rem var(--qt-e-2xs);
  align-items: baseline;
}

.qt-pas__index {
  font-size: var(--qt-t-mention);
  font-weight: var(--qt-w-semi);
  font-variant-numeric: tabular-nums lining-nums;
  color: var(--qt-accent-texte);
}

.qt-pas__nom {
  font-size: var(--qt-t-petit);
  font-weight: var(--qt-w-semi);
  color: var(--qt-encre);
}

.qt-pas__texte {
  grid-column: 2;
  font-size: var(--qt-t-mention);
  line-height: var(--qt-lh-dense);
  color: var(--qt-encre-douce);
}

/* État après envoi. Masqué tant que le formulaire n'a pas été soumis. */
.qt-etat {
  display: none;
  gap: var(--qt-e-s);
  padding: var(--qt-e-l);
  border-radius: var(--qt-rayon-l);
  border: var(--qt-trait) solid color-mix(in srgb, var(--qt-or) 45%, transparent);
  background-color: color-mix(in srgb, var(--qt-or) 8%, transparent);
}

.qt-etat.est-visible { display: grid; }

.qt-etat__titre {
  display: flex;
  align-items: center;
  gap: var(--qt-e-2xs);
  font-size: var(--qt-t-sous-titre);
  font-weight: var(--qt-w-semi);
  color: var(--qt-encre);
}

.qt-etat__titre svg {
  inline-size: 1.35rem;
  block-size: 1.35rem;
  color: var(--qt-accent-texte);
  flex: none;
}


/* ==========================================================================
   35. FILTRES DE GALERIE
   Des boutons, pas des liens : ils ne mènent nulle part, ils trient ce qui
   est déjà là. Un lien qui ne navigue pas ment au clavier et au lecteur
   d'écran.
   ========================================================================== */

.qt-filtres {
  display: flex;
  flex-wrap: wrap;
  gap: var(--qt-e-2xs);
  align-items: center;
}

.qt-filtre {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.6rem 1.05rem;
  border-radius: var(--qt-rayon-plein);
  border: var(--qt-trait) solid var(--qt-filet-fort);
  background-color: transparent;
  color: var(--qt-encre-douce);
  font-size: var(--qt-t-petit);
  font-weight: var(--qt-w-moyen);
  cursor: pointer;
  transition: border-color var(--qt-d-micro) var(--qt-ease),
              background-color var(--qt-d-micro) var(--qt-ease),
              color var(--qt-d-micro) var(--qt-ease);
}

.qt-filtre:hover { border-color: var(--qt-accent); color: var(--qt-encre); }

.qt-filtre[aria-pressed="true"] {
  border-color: var(--qt-or);
  background-color: var(--qt-or);
  color: var(--qt-marine);
  font-weight: var(--qt-w-gras);
}

/* Le compteur vit dans le bouton : on sait ce qu'on va obtenir avant de
   cliquer, et un filtre vide ne se présente jamais. */
.qt-filtre__compte {
  font-size: var(--qt-t-mention);
  font-variant-numeric: tabular-nums lining-nums;
  opacity: 0.7;
}

/* Masquage par attribut plutôt que par classe : hidden retire aussi la
   tuile de l'arbre d'accessibilité, donc du parcours au clavier. */
.qt-galerie [hidden] { display: none; }

.qt-galerie__compteur {
  font-size: var(--qt-t-petit);
  color: var(--qt-encre-tenue);
}


/* ==========================================================================
   36. PHOTO DE HERO (pages intérieures)
   Ces deux classes étaient utilisées par les pages filles sans avoir jamais
   été écrites. Ça tenait par accident : toutes les photos étaient des
   portraits, qui remplissaient la colonne d'eux-mêmes. La première photo
   paysage a laissé 280 px de vide sous elle, la colonne texte faisant
   589 px et l'image 309.

   La figure prend donc la hauteur de la colonne, quel que soit le format
   du fichier source. Une page ne doit jamais dépendre du cadrage d'une
   photo pour ne pas être trouée.
   ========================================================================== */

.qt-hero__photo {
  position: relative;
  display: flex;
  flex-direction: column;
  flex: 1;
  min-block-size: 0;
  margin: 0;
  border-radius: var(--qt-rayon-l);
  overflow: hidden;
  background-color: var(--qt-marine);
}

.qt-hero__photo img {
  inline-size: 100%;
  block-size: 100%;
  flex: 1;
  min-block-size: 0;
  object-fit: cover;
}

.qt-hero__legende {
  padding: var(--qt-e-2xs) var(--qt-e-s) var(--qt-e-s);
  font-size: var(--qt-t-mention);
  line-height: var(--qt-lh-dense);
  color: var(--qt-sable-clair);
  background-color: var(--qt-marine);
}

/* Empilé, la colonne média n'a plus de hauteur à remplir : on rend la main
   au rapport naturel de l'image plutôt que de la recadrer sans raison. */
@media (max-width: 1000px) {
  .qt-hero__photo { flex: none; }
  .qt-hero__photo img { block-size: auto; flex: none; }
}


/* ==========================================================================
   37. MOSAÏQUE DE HERO
   Réservée à la page Réalisations. Sur une page de portfolio, une seule
   photo ne dit pas « on en a fait beaucoup ». Trois vues, dont une en
   travaux, le disent en une seconde.
   ========================================================================== */

.qt-hero__mosaique {
  display: grid;
  grid-template-columns: 1.12fr 1fr;
  grid-template-rows: 1fr 1fr;
  gap: var(--qt-e-2xs);
  flex: 1;
  min-block-size: 0;
}

.qt-hero__vignette {
  position: relative;
  margin: 0;
  overflow: hidden;
  border-radius: var(--qt-rayon-m);
  background-color: var(--qt-marine);
  min-block-size: 0;
}

/* La première vue tient toute la hauteur : sans elle, trois cases égales
   feraient une grille de catalogue, pas une composition. */
.qt-hero__vignette:first-child { grid-row: span 2; }

.qt-hero__vignette img {
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
}

/* Étiquette discrète : elle situe la vue sans recouvrir la photo. */
.qt-hero__tag {
  position: absolute;
  inset-inline-start: var(--qt-e-2xs);
  bottom: var(--qt-e-2xs);
  padding: 0.25rem 0.6rem;
  border-radius: var(--qt-rayon-plein);
  background-color: color-mix(in srgb, var(--qt-nuit) 78%, transparent);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  font-size: var(--qt-t-mention);
  font-weight: var(--qt-w-semi);
  color: var(--qt-sable-pale);
}

@media (max-width: 1000px) {
  /* Empilée, la colonne n'impose plus de hauteur : on fixe un rapport pour
     que la mosaïque ne s'écrase pas à quelques dizaines de pixels. */
  .qt-hero__mosaique { flex: none; aspect-ratio: 4 / 3; }
}

@media (max-width: 480px) {
  .qt-hero__mosaique { aspect-ratio: 3 / 2; gap: var(--qt-e-3xs); }
}


/* ==========================================================================
   38. TITRE D'OFFRE
   Modificateur, et non changement de .qt-titre : ce composant sert partout
   sur le site en graisse normale. Seul le titre qui porte un argument
   commercial passe en gras.
   ========================================================================== */

.qt-titre--offre { font-weight: var(--qt-w-gras); }


/* ==========================================================================
   39. MENU : LIENS SECONDAIRES EN PUCES
   Réalisations, Notre méthode et Tarifs occupaient trois rangées pleines
   pour trois mots. Regroupés sur une ligne, ils rendent au panneau la
   hauteur qui le faisait défiler, et la hiérarchie devient lisible :
   les prestations sont des rangées, le reste des puces.
   ========================================================================== */

.qt-panneau__secondaires {
  display: flex;
  flex-wrap: wrap;
  gap: var(--qt-e-3xs);
  margin-block-start: var(--qt-e-3xs);
}

.qt-panneau__puce {
  display: inline-flex;
  align-items: center;
  /* 2,75 rem de haut : la cible tactile reste au-dessus du minimum de 44 px
     malgré la compacité. */
  min-block-size: 2.75rem;
  padding-inline: 0.95rem;
  border-radius: var(--qt-rayon-plein);
  border: var(--qt-trait) solid var(--qt-filet-sombre);
  background-color: color-mix(in srgb, var(--qt-sable-pale) 5%, transparent);
  font-size: var(--qt-t-petit);
  font-weight: var(--qt-w-semi);
  color: color-mix(in srgb, var(--qt-blanc) 88%, transparent);
  transition: border-color var(--qt-d-micro) var(--qt-ease),
              color var(--qt-d-micro) var(--qt-ease);
}

.qt-panneau__puce:hover,
.qt-panneau__puce:focus-visible {
  border-color: color-mix(in srgb, var(--qt-or) 55%, transparent);
  color: var(--qt-blanc);
}

.qt-panneau__puce[aria-current="page"] {
  border-color: var(--qt-or);
  color: var(--qt-or-vif);
}

/* La cascade s'applique aussi aux puces, sinon le bloc apparaît d'un coup
   alors que les rangées au-dessus montent une par une. */
.qt-panneau__secondaires {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity var(--qt-d-court) var(--qt-ease),
              transform var(--qt-d-court) var(--qt-ease);
}

.qt-panneau[data-ouvert="true"] .qt-panneau__secondaires {
  opacity: 1;
  transform: translateY(0);
  transition-delay: 260ms;
}


/* --------------------------------------------------------------------------
   MENU : écrans courts
   Un iPhone SE n'a que 667 px de haut : le panneau y débordait encore de
   57 px. On compacte à la hauteur disponible plutôt qu'à la largeur, parce
   que c'est la hauteur qui manque. La mention légale passe à la trappe :
   elle est déjà dans le pied de page, et elle coûte une ligne qu'on préfère
   donner au bouton de devis.
   -------------------------------------------------------------------------- */

@media (max-height: 720px) and (max-width: 1080px) {
  .qt-panneau__corps { gap: var(--qt-e-2xs); padding-block: var(--qt-e-2xs) var(--qt-e-s); }
  .qt-panneau__lien  { padding-block: var(--qt-e-3xs); min-block-size: 2.75rem; }
  .qt-panneau__nom   { font-size: 1.05rem; }
  .qt-panneau__label--second { margin-block-start: var(--qt-e-2xs); }
  .qt-panneau__pied  { padding-block-start: var(--qt-e-2xs); }
  /* Le bouton en taille --large montait à 77 px : c'est lui, et lui seul,
     qui faisait déborder un écran de 640 px de haut. */
  .qt-panneau__pied .qt-btn--large { padding-block: 0.8rem; font-size: var(--qt-t-petit); }
  .qt-panneau__mention { display: none; }
  .qt-panneau__fond img { opacity: 0.1; }
}


/* --------------------------------------------------------------------------
   MENU : la navigation absorbe la hauteur libre
   Sans ça, le pied était poussé en bas par un margin auto et toute la marge
   disponible s'accumulait en un seul trou de 400 px au milieu du panneau.
   Ici c'est la nav qui grandit, et ses rangées se partagent le surplus.
   -------------------------------------------------------------------------- */

.qt-panneau__corps > nav {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-block-size: 0;
}

/* Les libellés de groupe ne s'étirent pas : seule une rangée cliquable
   mérite de gagner de la hauteur. */
.qt-panneau__label { flex: none; }

.qt-panneau__chevron {
  inline-size: 1.1rem;
  block-size: 1.1rem;
  color: color-mix(in srgb, var(--qt-sable-clair) 45%, transparent);
  transition: transform var(--qt-d-micro) var(--qt-ease),
              color var(--qt-d-micro) var(--qt-ease);
}

.qt-panneau__lien:hover .qt-panneau__chevron,
.qt-panneau__lien:focus-visible .qt-panneau__chevron {
  transform: translateX(4px);
  color: var(--qt-or);
}

.qt-panneau__lien[aria-current="page"] .qt-panneau__chevron { color: var(--qt-or); }

/* La méta et le chevron cohabitent en fin de rangée. */
.qt-panneau__meta { justify-self: end; }


/* --------------------------------------------------------------------------
   40 · BANDE DE PRIX
   Une fourchette par matière, toutes trois posées sur la MÊME échelle
   (70 à 120 €/m²) : c'est ce qui permet de comparer d'un coup d'œil, ce
   qu'une liste de « dès X € » ne donne jamais. Les bornes sont nommées,
   parce qu'un prix haut sans sa raison ressemble à une marge.
   -------------------------------------------------------------------------- */

.qt-bandes {
  display: grid;
  gap: var(--qt-e-l);
  list-style: none;
  margin: 0;
  padding: 0;
}

.qt-bande {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--qt-e-2xs) var(--qt-e-m);
  padding-block-start: var(--qt-e-m);
  border-block-start: var(--qt-trait) solid var(--qt-filet-clair);
}

.qt-bande__nom {
  font-size: var(--qt-t-sous-titre);
  font-weight: var(--qt-w-semi);
  letter-spacing: var(--qt-ls-titre);
  line-height: var(--qt-lh-titre);
  margin: 0;
}

.qt-bande__nom a { color: inherit; text-decoration: none; }
.qt-bande__nom a:hover,
.qt-bande__nom a:focus-visible { color: var(--qt-accent-texte); }

.qt-bande__usage {
  grid-column: 1;
  font-size: var(--qt-t-mention);
  color: var(--qt-encre-tenue);
  margin: 0;
}

/* Le prix d'entrée est l'information que l'œil doit attraper en premier :
   c'est le seul chiffre en display de la ligne. */
.qt-bande__prix {
  grid-column: 2;
  grid-row: 1 / span 2;
  display: flex;
  align-items: baseline;
  gap: 0.3rem;
  align-self: center;
  font-variant-numeric: tabular-nums lining-nums;
  margin: 0;
}

.qt-bande__valeur {
  font-size: var(--qt-t-titre);
  font-weight: var(--qt-w-normal);
  letter-spacing: -0.035em;
  line-height: 1;
}

.qt-bande__unite {
  font-size: var(--qt-t-mention);
  font-weight: var(--qt-w-moyen);
  color: var(--qt-encre-tenue);
}

/* La jauge : piste sur toute la largeur, segment positionné par --de/--a
   exprimés en pourcentage de l'échelle commune. */
.qt-bande__jauge {
  grid-column: 1 / -1;
  position: relative;
  block-size: 0.5rem;
  margin-block-start: var(--qt-e-xs);
  border-radius: var(--qt-rayon-plein);
  background: var(--qt-filet-clair);
  overflow: hidden;
}

.qt-bande__segment {
  position: absolute;
  inset-block: 0;
  inset-inline-start: var(--de);
  inline-size: calc(var(--a) - var(--de));
  border-radius: var(--qt-rayon-plein);
  background: linear-gradient(90deg,
    var(--qt-or) 0%,
    color-mix(in srgb, var(--qt-or) 40%, var(--qt-filet-fort)) 100%);
  transform-origin: left center;
  animation: qt-bande-pousse var(--qt-d-long) var(--qt-ease) both;
}

@keyframes qt-bande-pousse {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}

.qt-bande__bornes {
  grid-column: 1 / -1;
  display: flex;
  justify-content: space-between;
  gap: var(--qt-e-m);
  margin-block-start: var(--qt-e-2xs);
  font-size: var(--qt-t-mention);
  color: var(--qt-encre-tenue);
}

.qt-bande__bornes b {
  font-weight: var(--qt-w-semi);
  color: var(--qt-encre-douce);
  font-variant-numeric: tabular-nums;
}

.qt-bande__bornes span:last-child { text-align: end; }

@media (max-width: 640px) {
  .qt-bande { grid-template-columns: minmax(0, 1fr); }
  .qt-bande__prix { grid-column: 1; grid-row: auto; margin-block-start: var(--qt-e-2xs); }
  .qt-bande__bornes { flex-direction: column; gap: 0.15rem; }
  .qt-bande__bornes span:last-child { text-align: start; }
}

@media (prefers-reduced-motion: reduce) {
  .qt-bande__segment { animation: none; }
}


/* --------------------------------------------------------------------------
   41 · BUDGET TYPE
   Un calcul posé en entier plutôt qu'un prix. Le total n'a de valeur que
   si la multiplication qui y mène est visible.
   -------------------------------------------------------------------------- */

.qt-budget {
  display: flex;
  flex-direction: column;
  padding: var(--qt-e-l);
  border: var(--qt-trait) solid var(--qt-filet-clair);
  border-radius: var(--qt-rayon-l);
  background: var(--qt-fond);
}

.qt-budget__lieu {
  font-size: var(--qt-t-sur-titre);
  font-weight: var(--qt-w-semi);
  letter-spacing: var(--qt-ls-sur-titre);
  text-transform: uppercase;
  color: var(--qt-accent-texte);
  margin: 0;
}

.qt-budget__quoi {
  font-size: var(--qt-t-sous-titre);
  font-weight: var(--qt-w-semi);
  letter-spacing: var(--qt-ls-titre);
  line-height: var(--qt-lh-titre);
  margin-block: var(--qt-e-2xs) var(--qt-e-m);
}

.qt-budget__calcul {
  display: grid;
  gap: var(--qt-e-2xs);
  margin: 0 0 var(--qt-e-m);
  padding: 0;
  list-style: none;
  font-size: var(--qt-t-petit);
}

.qt-budget__calcul li {
  display: flex;
  justify-content: space-between;
  gap: var(--qt-e-s);
  color: var(--qt-encre-douce);
}

.qt-budget__calcul b {
  font-weight: var(--qt-w-semi);
  color: var(--qt-encre);
  font-variant-numeric: tabular-nums lining-nums;
  white-space: nowrap;
}

/* Le total est poussé en bas pour que trois budgets côte à côte alignent
   leurs totaux, même si les listes au-dessus n'ont pas la même longueur. */
.qt-budget__total {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--qt-e-s);
  margin-block: auto 0;
  padding-block-start: var(--qt-e-m);
  border-block-start: var(--qt-trait) solid var(--qt-filet-fort);
}

.qt-budget__label {
  font-size: var(--qt-t-mention);
  color: var(--qt-encre-tenue);
}

.qt-budget__somme {
  font-size: var(--qt-t-titre);
  font-weight: var(--qt-w-normal);
  letter-spacing: -0.035em;
  line-height: 1;
  font-variant-numeric: tabular-nums lining-nums;
  white-space: nowrap;
}

.qt-budget__note {
  margin-block-start: var(--qt-e-s);
  font-size: var(--qt-t-mention);
  color: var(--qt-encre-tenue);
}

.qt-budgets {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--qt-grille-ecart);
}

@media (min-width: 60rem) {
  .qt-budgets { grid-template-columns: repeat(3, 1fr); }

  /* Les totaux doivent s'aligner d'une carte à l'autre, sinon l'œil compare
     trois chiffres posés à trois hauteurs différentes. Le `margin auto` ne
     suffit pas : les notes de bas de carte n'ont pas la même hauteur. La
     subgrid fait partager les cinq mêmes rangées aux trois cartes, et c'est
     la liste de calcul (1fr) qui absorbe l'écart.
     Le span explicite n'est appliqué qu'ici : en une seule colonne, les
     trois cartes se superposeraient sur les mêmes rangées. */
  @supports (grid-template-rows: subgrid) {
    .qt-budgets { grid-template-rows: auto auto 1fr auto auto; }
    .qt-budget {
      display: grid;
      grid-row: 1 / -1;
      grid-template-rows: subgrid;
    }
    .qt-budget__total { margin-block: 0; }
  }
}


/* --------------------------------------------------------------------------
   42 · DONNÉE LÉGALE À COMPLÉTER
   Contrairement à data-attente, qui n'est qu'un marqueur de grep, ceci se
   VOIT. Sur des pages légales, une donnée manquante qui passe inaperçue
   part en production et engage le client : elle doit sauter aux yeux.
   -------------------------------------------------------------------------- */

.qt-a-completer {
  display: inline;
  padding: 0.1em 0.45em;
  border-radius: var(--qt-rayon-xs);
  background: color-mix(in srgb, var(--qt-erreur) 12%, transparent);
  box-shadow: inset 0 0 0 var(--qt-trait) color-mix(in srgb, var(--qt-erreur) 45%, transparent);
  color: var(--qt-erreur);
  font-size: 0.92em;
  font-weight: var(--qt-w-semi);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

/* Mention d'information RGPD placée sous un bouton d'envoi. Séparée du reste
   par un filet : elle doit se lire comme une note de bas de formulaire, pas
   comme un argument de vente de plus. Le lien reste souligné, sinon la
   personne ne voit pas qu'elle peut aller vérifier. */
.qt-collecte {
  max-inline-size: 62ch;
  margin-block: var(--qt-e-l) 0;
  padding-block-start: var(--qt-e-m);
  border-block-start: var(--qt-trait) solid var(--qt-filet-clair);
}

.qt-collecte a {
  color: var(--qt-accent-texte);
  text-decoration: underline;
  text-underline-offset: 0.2em;
}

/* Démarche engagée, pièce officielle en attente. Même gabarit que le
   marqueur rouge, mais en or : le lecteur doit distinguer « il manque une
   information » de « le document est en cours ». Même traitement visuel pour
   les deux reviendrait à noyer le vrai manque. */
.qt-a-completer--encours {
  background: color-mix(in srgb, var(--qt-or) 14%, transparent);
  box-shadow: inset 0 0 0 var(--qt-trait) color-mix(in srgb, var(--qt-or) 50%, transparent);
  color: var(--qt-or-encre);
  text-transform: none;
  letter-spacing: 0;
}

/* Bandeau d'avertissement en tête des pages légales incomplètes. Il
   disparaît en supprimant le bloc, pas en modifiant du CSS. */
.qt-brouillon {
  display: flex;
  gap: var(--qt-e-s);
  align-items: flex-start;
  padding: var(--qt-e-m) var(--qt-e-l);
  margin-block-end: var(--qt-e-2xl);
  border-radius: var(--qt-rayon-m);
  border: var(--qt-trait) solid color-mix(in srgb, var(--qt-erreur) 35%, transparent);
  background: color-mix(in srgb, var(--qt-erreur) 7%, transparent);
}

.qt-brouillon svg {
  flex: none;
  inline-size: 1.25rem;
  block-size: 1.25rem;
  margin-block-start: 0.15rem;
  color: var(--qt-erreur);
}

.qt-brouillon p { margin: 0; font-size: var(--qt-t-petit); }
.qt-brouillon strong { color: var(--qt-erreur); }

/* Variante dorée : la page ne manque plus d'une donnée, elle attend
   l'aboutissement d'une démarche. Même raisonnement que .qt-a-completer--encours,
   et même raison de ne pas tout laisser en rouge : un signal d'alerte permanent
   finit par ne plus être lu. */
.qt-brouillon--encours {
  border-color: color-mix(in srgb, var(--qt-or) 40%, transparent);
  background: color-mix(in srgb, var(--qt-or) 8%, transparent);
}

.qt-brouillon--encours svg { color: var(--qt-or-encre); }
.qt-brouillon--encours strong { color: var(--qt-or-encre); }

/* --------------------------------------------------------------------------
   43 · PAGE LÉGALE
   Colonne de lecture étroite, titres numérotés, filets discrets. Une page
   légale se lit mal en pleine largeur.
   -------------------------------------------------------------------------- */

.qt-legal {
  max-inline-size: var(--qt-mesure-large);
}

.qt-legal__article { padding-block: var(--qt-e-l); }

.qt-legal__article + .qt-legal__article {
  border-block-start: var(--qt-trait) solid var(--qt-filet-clair);
}

.qt-legal__titre {
  display: grid;
  grid-template-columns: 2.5rem minmax(0, 1fr);
  gap: var(--qt-e-s);
  align-items: baseline;
  font-size: var(--qt-t-sous-titre);
  font-weight: var(--qt-w-semi);
  letter-spacing: var(--qt-ls-titre);
  line-height: var(--qt-lh-titre);
  margin-block-end: var(--qt-e-m);
}

.qt-legal__num {
  font-size: var(--qt-t-mention);
  font-weight: var(--qt-w-semi);
  letter-spacing: 0.08em;
  font-variant-numeric: tabular-nums lining-nums;
  color: var(--qt-or);
}

.qt-legal__corps > * + * { margin-block-start: var(--qt-e-s); }
.qt-legal__corps p { max-inline-size: var(--qt-mesure); }

/* Tableau d'identité : libellé à gauche, valeur à droite, sans bordures. */
.qt-legal__fiche {
  display: grid;
  grid-template-columns: minmax(8rem, 14rem) minmax(0, 1fr);
  gap: var(--qt-e-2xs) var(--qt-e-m);
  margin: 0;
}

.qt-legal__fiche dt {
  font-size: var(--qt-t-mention);
  color: var(--qt-encre-tenue);
}

.qt-legal__fiche dd {
  margin: 0;
  font-size: var(--qt-t-petit);
  font-variant-numeric: tabular-nums lining-nums;
}

@media (max-width: 560px) {
  .qt-legal__fiche { grid-template-columns: minmax(0, 1fr); }
  .qt-legal__fiche dd { margin-block-end: var(--qt-e-2xs); }
  .qt-legal__titre { grid-template-columns: minmax(0, 1fr); gap: 0.2rem; }
}


/* --------------------------------------------------------------------------
   44 · MODALE DE DEVIS
   <dialog> natif : le piège du focus, la touche Échap et l'inertisation du
   reste de la page sont fournis par le navigateur. Les réimplémenter à la
   main est la première source de modales inaccessibles.
   -------------------------------------------------------------------------- */

.qt-modale {
  inline-size: min(42rem, calc(100vw - 2rem));
  max-block-size: min(46rem, calc(100dvh - 2rem));
  padding: 0;
  border: 0;
  border-radius: var(--qt-rayon-xl);
  background: var(--qt-fond);
  color: var(--qt-encre);
  box-shadow: var(--qt-ombre-haute);
  overflow: hidden;
}

.qt-modale::backdrop {
  background: color-mix(in srgb, var(--qt-nuit) 68%, transparent);
  backdrop-filter: blur(3px);
}

/* L'ouverture part du bas sur mobile et du centre sur grand écran : une
   modale qui tombe du plafond sur un téléphone passe pour une publicité. */
.qt-modale[open] {
  animation: qt-modale-entre var(--qt-d-moyen) var(--qt-ease) both;
}

.qt-modale[open]::backdrop {
  animation: qt-voile-entre var(--qt-d-court) var(--qt-ease) both;
}

@keyframes qt-modale-entre {
  from { opacity: 0; transform: translateY(14px) scale(0.985); }
  to   { opacity: 1; transform: none; }
}

@keyframes qt-voile-entre { from { opacity: 0; } to { opacity: 1; } }

.qt-modale__cadre {
  display: flex;
  flex-direction: column;
  max-block-size: inherit;
}

/* ---- Tête : retour, compteur, fermeture ---- */

.qt-modale__tete {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: var(--qt-e-s);
  padding: var(--qt-e-s) var(--qt-e-m);
}

.qt-modale__retour {
  justify-self: start;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  min-block-size: 2.75rem;
  padding-inline: 0.5rem;
  border: 0;
  background: none;
  color: var(--qt-encre-tenue);
  font: inherit;
  font-size: var(--qt-t-mention);
  cursor: pointer;
}

.qt-modale__retour svg { transform: rotate(180deg); }
.qt-modale__retour:hover { color: var(--qt-accent-texte); }
.qt-modale__retour[hidden] { display: none; }

.qt-modale__compte {
  grid-column: 2;
  margin: 0;
  font-size: var(--qt-t-mention);
  color: var(--qt-encre-tenue);
  font-variant-numeric: tabular-nums lining-nums;
}

.qt-modale__compte b { color: var(--qt-accent-texte); font-weight: var(--qt-w-semi); }

.qt-modale__fermer {
  justify-self: end;
  display: grid;
  place-items: center;
  inline-size: 2.75rem;
  block-size: 2.75rem;
  border: 0;
  border-radius: var(--qt-rayon-s);
  background: none;
  color: var(--qt-encre-tenue);
  cursor: pointer;
}

/* Pas d'icône « croix » dans le sprite : le plus pivoté en fait une. */
.qt-modale__fermer svg { transform: rotate(45deg); }
.qt-modale__fermer:hover { background: var(--qt-fond-alt); color: var(--qt-encre); }

.qt-modale__jauge {
  block-size: 2px;
  margin: 0 var(--qt-e-m);
  border-radius: var(--qt-rayon-plein);
  background: var(--qt-filet-clair);
  overflow: hidden;
}

.qt-modale__jauge i {
  display: block;
  block-size: 100%;
  border-radius: inherit;
  background: var(--qt-or);
  transform: scaleX(var(--part, 0.3333));
  transform-origin: left center;
  transition: transform var(--qt-d-moyen) var(--qt-ease);
}

/* ---- Les étapes ---- */

.qt-modale__form {
  min-block-size: 0;
  overflow-y: auto;
  padding: var(--qt-e-m) var(--qt-e-l) var(--qt-e-l);
}

.qt-modale__pas {
  display: none;
  margin: 0;
  padding: 0;
  border: 0;
}

.qt-modale__pas.est-active { display: block; animation: qt-pas-entre var(--qt-d-court) var(--qt-ease) both; }

@keyframes qt-pas-entre {
  from { opacity: 0; transform: translateX(10px); }
  to   { opacity: 1; transform: none; }
}

.qt-modale__titre {
  display: block;
  padding: 0;
  font-size: var(--qt-t-sous-titre);
  font-weight: var(--qt-w-semi);
  letter-spacing: var(--qt-ls-titre);
  line-height: var(--qt-lh-titre);
}

.qt-modale__sous {
  margin-block: var(--qt-e-3xs) var(--qt-e-m);
  font-size: var(--qt-t-petit);
  color: var(--qt-encre-tenue);
}

/* ---- Options cliquables ---- */

/* Grille de choix, partagée par la modale ET la page devis. Le nom ne
   mentionne plus la modale : deux listes de choix dans le même produit
   ne peuvent pas avoir deux apparences. */
.qt-options {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 12rem), 1fr));
  gap: var(--qt-e-2xs);
}

.qt-options--duo { grid-template-columns: repeat(auto-fit, minmax(min(100%, 9rem), 1fr)); }

.qt-option { display: block; cursor: pointer; }
.qt-option--large { grid-column: 1 / -1; }

/* Le radio reste focusable : on le masque visuellement, jamais en display:none,
   sinon il sort de l'ordre de tabulation et le clavier ne peut plus choisir. */
.qt-option input {
  position: absolute;
  inline-size: 1px;
  block-size: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.qt-option__corps {
  display: grid;
  gap: 0.15rem;
  block-size: 100%;
  padding: var(--qt-e-s) var(--qt-e-m);
  border: var(--qt-trait) solid var(--qt-filet-fort);
  border-radius: var(--qt-rayon-m);
  /* --qt-lin, pas --qt-blanc : tokens.css réserve le blanc pur au texte sur
     fond sombre. Le lin reste franchement plus clair que le crème profond
     des sections --alt, donc la carte se détache sans sable sur sable. */
  background: var(--qt-lin);
  transition: border-color var(--qt-d-micro) var(--qt-ease),
              background-color var(--qt-d-micro) var(--qt-ease),
              transform var(--qt-d-micro) var(--qt-ease);
}

.qt-option__corps svg {
  inline-size: 1.25rem;
  block-size: 1.25rem;
  color: var(--qt-or);
  margin-block-end: 0.2rem;
}

.qt-option__corps b {
  font-size: var(--qt-t-petit);
  font-weight: var(--qt-w-semi);
  line-height: var(--qt-lh-titre);
}

.qt-option__corps em {
  font-style: normal;
  font-size: var(--qt-t-mention);
  color: var(--qt-encre-tenue);
}

.qt-option:hover .qt-option__corps {
  border-color: color-mix(in srgb, var(--qt-or) 55%, transparent);
  transform: translateY(-2px);
}

.qt-option input:checked + .qt-option__corps {
  border-color: var(--qt-or);
  background: color-mix(in srgb, var(--qt-or) 10%, var(--qt-lin));
}

.qt-option input:focus-visible + .qt-option__corps {
  outline: 2px solid var(--qt-focus);
  outline-offset: 2px;
}

/* ---- Dernière étape ---- */

.qt-modale__champs { display: grid; gap: var(--qt-e-s); }
.qt-modale__envoi { inline-size: 100%; margin-block-start: var(--qt-e-m); }

.qt-modale__rassure {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.45rem;
  margin-block-start: var(--qt-e-s);
  font-size: var(--qt-t-mention);
  color: var(--qt-encre-tenue);
  text-align: center;
}

.qt-modale__rassure svg { inline-size: 1rem; block-size: 1rem; color: var(--qt-or); flex: none; }

.qt-modale__fin { text-align: center; padding-block: var(--qt-e-l); }
.qt-modale__fin .qt-modale__sous { margin-inline: auto; max-inline-size: 42ch; }
/* Les SVG sont en display:block dans la base : text-align ne les centre
   pas, il leur faut une marge automatique. */
.qt-modale__sceau {
  inline-size: 2.5rem;
  block-size: 2.5rem;
  color: var(--qt-or);
  margin: 0 auto var(--qt-e-s);
}

@media (max-width: 560px) {
  /* Sur téléphone la modale se colle en bas : c'est là que se trouve le pouce. */
  .qt-modale {
    inline-size: 100vw;
    max-inline-size: 100vw;
    max-block-size: 92dvh;
    margin: auto auto 0;
    border-radius: var(--qt-rayon-xl) var(--qt-rayon-xl) 0 0;
  }
  @keyframes qt-modale-entre {
    from { opacity: 0; transform: translateY(100%); }
    to   { opacity: 1; transform: none; }
  }
  .qt-modale__form { padding-inline: var(--qt-e-m); }
}

@media (prefers-reduced-motion: reduce) {
  .qt-modale[open], .qt-modale__pas.est-active { animation: none; }
  .qt-modale__jauge i { transition: none; }
  .qt-option:hover .qt-option__corps { transform: none; }
}


/* --------------------------------------------------------------------------
   45 · LEURRE ANTI-ROBOT
   Déplacé hors écran plutôt que masqué en display:none : les robots les plus
   soignés ignorent les champs en display:none, et un lecteur d'écran passe
   déjà à côté grâce à aria-hidden sur le conteneur.
   -------------------------------------------------------------------------- */

.qt-leurre {
  position: absolute;
  inline-size: 1px;
  block-size: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}


/* --------------------------------------------------------------------------
   46 · RÉSULTAT D'ENVOI
   Le succès et l'échec partagent la même boîte : seule la couleur d'accent
   change. Un échec doit se distinguer au premier coup d'œil, sinon le
   visiteur repart en croyant sa demande partie.
   -------------------------------------------------------------------------- */

.qt-etat--erreur,
.qt-modale__fin--erreur { --qt-or: var(--qt-erreur); }

.qt-etat--erreur .qt-etat__titre,
.qt-modale__fin--erreur .qt-modale__titre { color: var(--qt-erreur); }

.qt-modale__fin--erreur .qt-modale__sceau { color: var(--qt-erreur); }

/* Bouton en cours d'envoi : plus cliquable, et on le dit. */
.qt-btn[aria-busy="true"] { opacity: 0.72; cursor: progress; }

/* --------------------------------------------------------------------------
   47 · PAGE MERCI
   -------------------------------------------------------------------------- */

.qt-merci {
  max-inline-size: var(--qt-mesure-large);
  margin-inline: auto;
  text-align: center;
  padding-block: var(--qt-e-2xl);
}

.qt-merci__sceau {
  inline-size: 3rem;
  block-size: 3rem;
  color: var(--qt-or);
  margin: 0 auto var(--qt-e-l);
}

.qt-merci .qt-chapeau { margin-inline: auto; max-inline-size: 54ch; }


/* --------------------------------------------------------------------------
   48 · BLOC DE FORMULAIRE
   Sept champs d'affilée se lisent comme un mur. Numérotés et séparés par
   un filet, les mêmes champs se lisent comme trois étapes courtes.
   -------------------------------------------------------------------------- */

.qt-bloc {
  margin: 0;
  padding: 0;
  border: 0;
  /* Un <fieldset> a un min-width:auto implicite qui empêche une grille
     enfant de rétrécir. Sans ça, .qt-options déborde sur petit écran. */
  min-inline-size: 0;
}

/* L'écart entre blocs passe UNIQUEMENT par la marge.
   Le padding-top d'un fieldset ne s'applique pas au-dessus de la légende
   mais EN DESSOUS : il s'ajoutait donc à la marge basse de la légende, et
   les blocs 02 et 03 avaient 56 px là où le 01 en avait 24. */
/* Aucun filet entre les blocs : le numéro dans le titre et l'écart
   suffisent à les séparer. Un border-block-start était écrit ici mais la
   légende, large de 100 %, le recouvrait : il ne s'était jamais affiché,
   et une fois rendu visible il alourdissait la colonne pour rien. */
.qt-bloc + .qt-bloc {
  margin-block-start: var(--qt-e-xl);
}

.qt-bloc__titre {
  display: flex;
  align-items: baseline;
  gap: var(--qt-e-2xs);
  inline-size: 100%;
  padding: 0;
  margin-block-end: var(--qt-e-m);
  font-size: var(--qt-t-sous-titre);
  font-weight: var(--qt-w-semi);
  letter-spacing: var(--qt-ls-titre);
  line-height: var(--qt-lh-titre);
}

.qt-bloc__num {
  font-size: var(--qt-t-mention);
  font-weight: var(--qt-w-semi);
  letter-spacing: 0.08em;
  font-variant-numeric: tabular-nums lining-nums;
  color: var(--qt-or);
}

.qt-bloc__requis { color: var(--qt-accent-texte); font-weight: var(--qt-w-normal); }

.qt-champ__option {
  margin-inline-start: 0.4rem;
  font-size: var(--qt-t-mention);
  font-weight: var(--qt-w-normal);
  color: var(--qt-encre-tenue);
}

/* La colonne de réassurance suit le défilement du formulaire. Statique,
   elle disparaissait dès le deuxième champ, c'est-à-dire exactement quand
   le doute arrive. */
@media (min-width: 60rem) {
  .qt-rassure--collante {
    position: sticky;
    top: calc(var(--qt-e-2xl) + 3.5rem);
    align-self: start;
  }
}


/* --------------------------------------------------------------------------
   49 · CHIFFRES DE LA COLONNE DE RÉASSURANCE
   Les trois preuves occupaient une bande pleine largeur au-dessus du
   formulaire : 108 px de haut, et elles disparaissaient au premier
   défilement. Dans la colonne collante, elles tiennent en trois lignes et
   restent lisibles pendant toute la saisie.
   -------------------------------------------------------------------------- */

.qt-chiffres {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--qt-e-s);
  margin: 0 0 var(--qt-e-l);
  padding-block-start: var(--qt-e-s);
  border-block-start: var(--qt-trait) solid var(--qt-filet-clair);
  list-style: none;
}

.qt-chiffres li {
  display: grid;
  gap: 0.15rem;
  align-content: start;
}

/* Pas de bascule en colonne unique ici : le point de rupture à 26 rem
   attrapait TOUS les téléphones et rendait la bande 35 px plus haute, ce
   qui repoussait le premier champ. Les libellés tiennent en un groupe
   court, donc trois colonnes passent dès 360 px. */
@media (max-width: 22rem) {
  .qt-chiffres { gap: var(--qt-e-2xs); }
}

.qt-chiffres__valeur {
  font-size: var(--qt-t-sous-titre);
  font-weight: var(--qt-w-semi);
  letter-spacing: -0.03em;
  line-height: 1;
  font-variant-numeric: tabular-nums lining-nums;
  color: var(--qt-accent-texte);
  white-space: nowrap;
}

.qt-chiffres__valeur i {
  font-style: normal;
  font-size: var(--qt-t-mention);
  font-weight: var(--qt-w-moyen);
  margin-inline-start: 0.1em;
}

.qt-chiffres__quoi {
  font-size: var(--qt-t-mention);
  line-height: 1.35;
  color: var(--qt-encre-tenue);
}


/* --------------------------------------------------------------------------
   50 · COUCHE SANS NUMÉRO
   Le composant .qt-couche sert à deux choses : les couches physiques d'un
   sol, qui se superposent dans un ordre réel et méritent un numéro, et des
   listes qui n'ont pas d'ordre (facteurs de prix, postes d'un devis).
   Pour les secondes, le numéro laissait croire à une séquence.
   -------------------------------------------------------------------------- */

.qt-couche--nue {
  grid-template-columns: minmax(0, 1fr);
}

.qt-couche--nue .qt-couche__epaisseur {
  grid-column: 1;
  margin-block-end: 0.15rem;
}

.qt-couche--nue .qt-couche__nom,
.qt-couche--nue .qt-couche__texte {
  grid-column: 1;
}


/* --------------------------------------------------------------------------
   51 · HERO DES PAGES MATIÈRE
   Les dix pages avaient le même hero : texte à gauche, photo à droite,
   trois preuves, deux actions. Répliqué dix fois, ce n'est plus une charte,
   c'est un gabarit, et ça se voit dès la troisième page.

   Les trois pages matière forment une famille. Elles prennent donc une
   composition verticale : le texte sur toute la largeur, puis la matière
   en pleine page. C'est aussi le bon geste pour un produit qu'on achète
   d'abord avec les yeux.
   -------------------------------------------------------------------------- */

/* La variante « matière » mettait le hero en UNE colonne, photo pleine
   largeur SOUS le texte. Trois pages étaient concernées (époxy, polyuréthane,
   moquette) et le résultat était une demi-page vide à droite du texte.
   Elle suit désormais la grille à deux colonnes comme les sept autres. */
.qt-hero--matiere .qt-hero__grille {
  gap: clamp(2rem, 4.5vw, 4.25rem);
}

/* Le texte reste dans une mesure lisible même si la colonne est large. */
.qt-hero--matiere .qt-hero__texte { max-inline-size: var(--qt-mesure-large); }

/* La photo sort du conteneur et touche les deux bords. On annule la
   gouttière plutôt que de sortir l'élément du flux : pas de débordement
   horizontal possible, et la légende suit. */
/* Plus de pleine largeur : la photo tient dans sa colonne. */
.qt-hero--matiere .qt-hero__media { max-inline-size: none; }

.qt-hero--matiere .qt-hero__photo {
  border-radius: var(--qt-rayon-l);
  aspect-ratio: 4 / 5;
}

.qt-hero--matiere .qt-hero__photo img {
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
}

/* La légende revient dans l'alignement du texte. */
.qt-hero--matiere .qt-hero__legende {
  padding-inline: var(--qt-gouttiere);
}

@media (min-width: 60rem) {
  /* Sur grand écran une photo 16/9 pleine largeur écrase tout : on la
     ramène à une bande plus basse, qui se lit comme une frise. */
  .qt-hero--matiere .qt-hero__photo { aspect-ratio: 21 / 9; }
}

@media (max-width: 40rem) {
  .qt-hero--matiere .qt-hero__photo { aspect-ratio: 4 / 3; }
}


/* --------------------------------------------------------------------------
   52 · VARIANTES D'EN-TÊTE DE SECTION
   69 % des sections du site ouvraient sur exactement le même bloc :
   sur-titre, H2 en display, chapeau, le tout en grille 1,6fr / 1fr. Le
   visiteur ne l'analyse pas, mais au bout de trois sections il sait ce qui
   vient. Deux variantes suffisent à rompre l'attente sans inventer une
   nouvelle grammaire.
   -------------------------------------------------------------------------- */

/* A · Empilé. Le chapeau passe SOUS le titre au lieu d'être à côté, dans
   une colonne de lecture étroite. Convient aux sections qui veulent
   installer une idée plutôt qu'annoncer une liste. */
.qt-entete-empile {
  max-inline-size: var(--qt-mesure-large);
}

.qt-entete-empile .qt-chapeau {
  margin-block-start: var(--qt-e-m);
  max-inline-size: var(--qt-mesure);
}

/* B · Large. Le titre occupe toute la largeur et le chapeau se cale à
   droite sous lui, en colonne courte. Donne de l'air aux sections qui
   suivent un bloc dense. */
.qt-entete-large .qt-display-l {
  max-inline-size: 18ch;
}

/* Sous 60 rem la grille ci-dessous ne s'applique pas et le chapeau suit le
   titre dans le flux : sans marge il y était collé, à 0 px au lieu des
   24 px du reste du site. L'écart est posé ici, pas laissé au gap. */
.qt-entete-large .qt-chapeau {
  margin-block-start: var(--qt-e-m);
}

@media (min-width: 60rem) {
  .qt-entete-large {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 0 var(--qt-grille-ecart);
    align-items: start;
  }

  /* PLACEMENT EXPLICITE, et c'est tout l'objet du correctif.

     Le bloc a TROIS enfants dans DEUX colonnes. Sans placement, la grille
     les range un par cellule dans l'ordre du source : sur-titre en haut à
     gauche, titre en haut à DROITE, chapeau en bas à gauche. À l'écran, le
     titre se retrouvait séparé de son sur-titre, et le chapeau pendait sous
     un vide. C'est ce que montraient les captures.

     La disposition voulue est celle de tous les autres en-têtes du site :
     sur-titre et titre empilés à gauche, chapeau à droite en face du titre. */
  .qt-entete-large .qt-sur-titre { grid-column: 1; grid-row: 1; }
  .qt-entete-large .qt-display-l { grid-column: 1; grid-row: 2; max-inline-size: none; }
  .qt-entete-large .qt-chapeau   { grid-column: 2; grid-row: 2; }

  /* En grille, le gap horizontal espace les colonnes ; l'écart vertical
     entre sur-titre et titre reste géré par la marge du titre. */
  .qt-entete-large .qt-chapeau { margin-block-start: 0; padding-block-start: 0.4rem; }
}


/* --------------------------------------------------------------------------
   53 · DEUX SECTIONS VOISINES NE PARTAGENT JAMAIS LEUR FOND
   Sur la page époxy, la FAQ et le comparatif étaient tous deux en --alt :
   deux sections distinctes fondues en un seul aplat beige, sans aucune
   frontière visible. Même chose sur moquette et rénovation avec deux fonds
   crème consécutifs.

   Réglé par adjacence plutôt qu'à la main dans chaque générateur : la règle
   vaut pour toute section ajoutée plus tard, et on ne peut plus réintroduire
   le défaut par inattention.
   -------------------------------------------------------------------------- */

/* Rien ici : l'alternance se décide dans les générateurs, section par
   section, et outils/verifier-sections.py refuse une page où deux sections
   voisines partagent leur fond. Une règle d'adjacence CSS ne faisait que
   déplacer la collision d'un cran : en changeant le fond d'une section, elle
   la mettait en collision avec la suivante. */

/* --------------------------------------------------------------------------
   54 · PHOTO D'APPUI DANS UN SPLIT
   Hors du hero, une photo en 4/5 pouvait monter à 946 px face à un texte de
   417 px : l'image écrasait le propos au lieu de l'illustrer. Plafonnée à une
   hauteur proche de celle du texte, le cadrage reste correct grâce au cover.
   -------------------------------------------------------------------------- */

.qt-split .qt-hero__photo,
.qt-split--inverse .qt-hero__photo {
  max-block-size: 30rem;
}

.qt-split .qt-hero__photo img,
.qt-split--inverse .qt-hero__photo img {
  block-size: 100%;
  object-fit: cover;
}

/* --------------------------------------------------------------------------
   55 · LES DEUX COMPARATEURS AVANT / APRÈS, CÔTE À CÔTE
   Ils étaient empilés dans une pile verticale : deux images de 545 px l'une
   sous l'autre sur un écran de 1400, avec toute la moitié droite vide.
   -------------------------------------------------------------------------- */

@media (min-width: 61rem) {
  .qt-duo-avant-apres {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--qt-grille-ecart);
    align-items: start;
  }
}

/* Marqueur d'intention, sans effet visuel : déclare qu'une section continue
   délibérément la précédente et partage son fond. Lu par
   outils/verifier-sections.py. */
.qt-section--suite { /* aucun style : c'est une déclaration, pas une règle */ }
