/* ============================================================================
   ADA CONSTRUCTION v2 — socle commun aux 6 pages
   Règle du 21/07 : pas d'encadré, pas de grille à filets, pas de cage.
   L'espace et la photo structurent.
   ============================================================================ */
:root{
  /* ---- Nuit, acier, vermillon ----
     Le site est en dominante nuit. Le clair n'apparaît plus qu'aux trois
     endroits où on lit longtemps : le déroulé des Prestations, le formulaire
     de Contact, les Mentions. Ailleurs, near-black. Ça supprime l'alternance
     sombre-clair-sombre, qui est un motif de gabarit en soi.

     Le vermillon ne bouge pas d'un degré : c'est la seule chose qui soit
     réellement la marque, et elle a été payée par un rejet client. Ce n'est
     pas l'argile d'Anthropic, c'est du minium, le rouge d'apprêt du bâtiment.
     Il était noyé dans un crème qui le tirait vers l'argile ; sur nuit il
     redevient violent. */
  /* La face nuit n'avait pas un étagement plat : elle n'en avait pas. Elle
     vivait sur DEUX valeurs, .138 et .186, et --nuit-2 n'était le fond de rien.
     Le rejet du 21/07 interdit le filet, l'encadré et la cage : il ne restait
     donc qu'un seul canal pour séparer une surface levée de son sol, un pas de
     clarté. La chroma en ouvre un second, qui ne coûte ni contraste ni bordure.
     Elle monte avec le barreau pour deux raisons : le gamut sRGB près du noir
     est trop étroit pour la porter en bas (à L .146, C .020 n'achète que 13
     niveaux d'écart bleu-rouge), et une petite surface demande plus de chroma
     qu'un grand aplat pour paraître aussi colorée.
     Le sol monte aussi : les 8 photos sont étalonnées chaudes (cible R 118,9 /
     B 102,9). Un support froid ne les concurrence pas, il les réchauffe.
     Le plafond n'est pas choisi, il est mesuré : au-delà de L .230, --on-nuit-3
     tombe à 4,43:1 et la limite du bouton vermillon à 3,04:1. D'où quatre
     barreaux et non cinq. Les L du sol et de la surface levée ne bougent
     pratiquement pas (.138→.140, .186→.184) : tous les contrastes déjà mesurés
     le 01/08 sont conservés par construction. */
  /* REVENU EN ARRIÈRE LE 06/08/2026 — la famille minium du 05/08 est abandonnée.
     Recolorer les quatre barreaux sur la teinte du vermillon supprimait le seul
     contraste de teinte que la DA « Nuit, acier, vermillon » utilisait pour
     faire ressortir l'accent : sol et accent sur la même famille, plus rien ne
     se détachait — sur un site de chantier, un aplat rouge-noir de bout en bout
     lit plus « incendie » que « confiance ». Retour à la famille bleue mesurée
     le 02/08 (teinte 254), chroma .012/.014/.020/.026 par barreau : 22 paires
     de contraste déjà validées ce jour-là, rien à remesurer.
     La chaleur voulue le 05/08 reste portée par la lumière rasante (plus bas)
     et le grain, pas par la teinte du sol : c'est ce qui garde le vermillon
     comme seule note chaude de la page. */
  --nuit-0:   oklch(0.104 0.012 254);   /* pied, menu : la page finit par s'enfoncer */
  --nuit:     oklch(0.140 0.014 254);   /* sol dominant, support des photos */
  --nuit-1:   oklch(0.184 0.020 254);   /* surface levée */
  --nuit-2:   oklch(0.222 0.026 254);   /* panneau, plafond mesuré de l'échelle */
  /* Un voile posé sur une photo doit finir exactement sur le sol, sinon une
     couture apparaît au bas de chaque photo à bord perdu — et elle se voit
     d'autant plus que le sol est froid et la photo chaude. Un seul triplet,
     douze valeurs en dur supprimées. */
  --nuit-lch: 0.140 0.014 254;
  /* Le béton suit la famille en teinte, jamais en clarté : la clarté est ce
     qui porte les contrastes déjà mesurés, la teinte ne coûte rien. Un gris
     chaud posé au milieu d'une page redevenue froide se lit comme une pièce
     rapportée. */
  --beton:    oklch(0.898 0.004 252);   /* uniquement lecture longue */
  --beton-1:  oklch(0.845 0.005 252);

  --verm:     oklch(0.548 0.201 29);    /* INCHANGÉ depuis le 21/07, c'est la marque */
  --verm-nuit:oklch(0.672 0.205 33);    /* accent sur nuit : 6,12:1, valeur du 02/08 */
  --verm-bet: oklch(0.512 0.198 30);    /* accent sur béton : 4,64:1 */

  --on-nuit:  oklch(0.965 0.002 252);   /* 18,03:1 */
  --on-nuit-2:oklch(0.772 0.005 252);   /*  9,70:1 */
  --on-nuit-3:oklch(0.615 0.007 252);   /*  5,37:1 */
  --on-bet:   oklch(0.178 0.005 252);   /* 13,92:1 */
  --on-bet-2: oklch(0.372 0.006 252);   /*  7,63:1 */
  --on-bet-3: oklch(0.478 0.007 252);   /*  4,86:1 */

  /* L'acier est le deuxième neutre réel. Avant, tous les filets étaient du
     blanc à 13 % d'opacité : 1,39:1, un raccourci et pas une couleur.
     Deux valeurs parce que deux seuils différents s'appliquent : un filet
     décoratif n'a pas de seuil, la limite d'un composant en a un de 3:1.
     Les servir avec la même couleur, c'est soit un filet qui hurle, soit un
     champ qu'on ne voit pas.
     Leur chroma suit celle de la famille : un rail resté neutre sur un champ
     devenu froid se lit comme une pièce rapportée. Le déplacement coûte 0,01
     de contraste, mesuré, donc rien. */
  --acier:    oklch(0.452 0.016 254);   /* filet décoratif sur nuit : 2,70:1, aucun seuil */
  --acier-h:  oklch(0.560 0.016 254);   /* limite de composant sur nuit : 4,28:1 */
  --filet-l:  oklch(0.660 0.006 252);   /* filet décoratif sur béton : 2,29:1 */
  --limite-l: oklch(0.520 0.008 252);   /* limite de composant sur béton : 4,06:1 */

  /* ---- Typographie « Massif » ----
     Deux grotesques ne formaient pas un couple : un couple se construit sur un
     axe de contraste. Ici empattement rectangulaire contre sans linéale.
     Le slab dit charge, structure, permanence, et ses empattements épais ne
     perdent rien en lisibilité en plein soleil. */
  --disp:'Zilla Slab', ui-serif, Georgia, serif;
  --body:'Public Sans', ui-sans-serif, system-ui, sans-serif;
  --mono:'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, monospace;

  /* Plancher d'interlettrage display. -.028em était calibré pour une grotesque
     très grasse ; sur un slab les empattements se soudent bien avant les fûts.
     -.012em est le plancher au-delà duquel « rr », « nn » et « ll » collent.

     TROIS CRANS, 07/08/2026. Une seule valeur servait de 1,05 rem à 4,6 rem via
     la règle `h1,h2,h3` : un interlettrage unique sur une plage de 4,4 fois est
     forcément faux à l'une des deux extrémités. Le resserrement est une
     correction optique, et l'œil ne le demande qu'au grand corps — plus les
     lettres sont grosses, plus les blancs entre elles paraissent larges. Au
     petit corps le même em ferme une lettre déjà courte et fait perdre du gris
     typographique, surtout sur un slab dont les empattements avancent déjà l'un
     vers l'autre.
     Le cran serré ne bouge pas : -.012em EST le plancher mesuré, on ne creuse
     pas en dessous. Ce sont les deux autres qui s'ouvrent.
       --lsd    grands titres, au-delà de ~2,6 rem (h1 de page, .h2, .pull)
       --lsd-m  corps intermédiaire, 2 à 2,6 rem
       --lsd-s  petits titres, sous 2 rem : légèrement positif
     Les capitales slab (.fam__t, .mg__t) restent hors échelle à 0 : leurs
     empattements ferment déjà la lettre, elles n'ont jamais rien demandé. */
  --lsd:-.012em;
  --lsd-m:-.006em;
  --lsd-s:.006em;


  /* ---- Echelle typographique, 06/08/2026 ----
     L'audit a releve 14 tailles fixes distinctes entre 11 et 19 px, dont onze
     dans une plage de 5 px : 11 / 11,5 / 12 / 12,5 / 13 / 13,5 / 14 / 14,5 /
     15 / 15,5 / 16. C'est de la derive au sens strict — on a ajuste d'un demi
     pixel au lieu de passer au cran suivant. Le rendu tient tant qu'une seule
     personne decide ; il derive des la premiere main supplementaire.
     Six crans remplacent les onze valeurs. Les seules fusions sont a 0,5 px
     (11,5→12, 13,5→13, 14,5→14, 15,5→15) et 1 px sur un unique usage (11→12) :
     invisibles, et aucun ne franchit un seuil WCAG de grand texte.
     Le corps (17 px, 18 px au-dela de 768) et le wordmark (19 px) ne sont pas
     de la derive : ce sont des roles distincts, ils restent hors echelle. */
  --t-micro:12px;   /* mentions de pied, barre legale */
  --t-mono:12.5px;  /* legendes et champs en attente, en mono */
  --t-lbl:13px;     /* eyebrow, ligne d'identification, brandline */
  --t-sm:14px;      /* navigation, burger */
  --t-ui:15px;      /* liens de pied, barre d'appel, CTA d'entete */
  --t-body:16px;    /* boutons */

  --maxw:1200px;
  /* Courbes expo-out. L'entrée démarre vite, donc l'interface répond avant
     d'avoir fini de bouger. Jamais d'ease-in sur une entrée : ça retarde
     l'instant précis que l'œil regarde. */
  --ease:cubic-bezier(.19,1,.22,1);
  --ease-2:cubic-bezier(.4,0,0,1);
  --ease-out:cubic-bezier(.23,1,.32,1);
  /* La sortie est plus rapide que l'entrée : ~65 %. */
  --t-in:.62s; --t-out:.4s; --t-ui:.18s;

  /* Échelle de plans nommée. Aucune valeur inventée au cas par cas. */
  --z-grain:5; --z-sticky:10; --z-callbar:40; --z-head:60; --z-progress:70; --z-menu:80;

  /* Hauteur de la barre d'appel, pour que rien ne se cache dessous. */
  --callbar-h:0px;
}
@media (max-width:1139px){:root{--callbar-h:56px}}
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth;background:var(--nuit)}
@media (prefers-reduced-motion:reduce){html{scroll-behavior:auto}}
body{font-family:var(--body);font-weight:400;background:var(--nuit);color:var(--on-nuit);
  font-size:17px;line-height:1.6;-webkit-font-smoothing:antialiased;overflow-x:hidden;
  padding-bottom:env(safe-area-inset-bottom)}
@media (min-width:768px){body{font-size:18px}}
img,video{max-width:100%;display:block}
a{color:inherit;text-decoration:none}
button{font:inherit;color:inherit;background:none;border:0;cursor:pointer;text-align:left}
::selection{background:var(--verm);color:var(--on-nuit)}

/* Un contour système de 2 px était le seul endroit non dessiné du site.
   Le halo dans la couleur de la surface fait tenir l'anneau aussi bien sur un
   aplat que sur une photo, où un simple trait se perd dans le détail. */
:focus-visible{outline:2px solid var(--verm-nuit);outline-offset:3px;
  box-shadow:0 0 0 6px oklch(var(--nuit-lch) / .62)}
.s-beton :focus-visible,.s-beton:focus-visible{outline-color:var(--verm-bet);
  box-shadow:0 0 0 6px oklch(0.898 0.004 252 / .72)}
.skip{position:absolute;left:-9999px}
.skip:focus{left:16px;top:16px;z-index:99;background:var(--verm);color:var(--on-nuit);padding:12px 18px}

.wrap{width:100%;max-width:var(--maxw);margin-inline:auto;padding-inline:clamp(22px,5vw,56px)}
.sec{padding-block:clamp(72px,11vw,140px)}
.s-nuit{background:var(--nuit);color:var(--on-nuit)}
.s-nuit-1{background:var(--nuit-1);color:var(--on-nuit)}
.s-nuit-2{background:var(--nuit-2);color:var(--on-nuit)}
/* Lumière rasante. Un aplat sans gradient de lumière se lit comme un à-plat
   d'imprimerie, et la dominante nuit multiplie les grands aplats. Très large,
   très faible : aucun rapport de contraste ne bouge d'un centième. */
/* 06/08 — la lumière prend une direction par surface.
   Elle existait déjà, mais au MÊME point sur les trois surfaces : posée à
   l'identique section après section, l'œil cesse de la lire comme une lumière
   et la lit comme une teinte du fond. Une lumière qui ne vient de nulle part
   n'est pas une lumière. Trois origines, une par barreau : en descendant la
   page on passe devant une source au lieu de traverser un motif répété.
   Couleur et opacité inchangées (.34, teinte 32) : aucun rapport de contraste
   ne bouge, seul le point d'application change. */
.s-nuit{background-repeat:no-repeat;
  background-image:radial-gradient(120% 80% at 8% 0%, oklch(0.330 0.070 32 / .34) 0%, transparent 62%)}
.s-nuit-1{background-repeat:no-repeat;
  background-image:
    linear-gradient(180deg, oklch(0.560 0.016 254 / .11) 0%, transparent 92px),
    radial-gradient(116% 78% at 88% 4%, oklch(0.330 0.070 32 / .34) 0%, transparent 62%)}
.s-nuit-2{background-repeat:no-repeat;
  background-image:
    linear-gradient(180deg, oklch(0.560 0.016 254 / .13) 0%, transparent 92px),
    radial-gradient(128% 86% at 46% 104%, oklch(0.330 0.070 32 / .34) 0%, transparent 66%)}
/* L'arête de lumière au-dessus des surfaces levées, ci-dessus.
   Le rejet du 21/07 interdit le filet et la cage : ce n'en est pas un. Un trait
   de 1 px dit « bordure » ; une rampe de 92 px dit « cette surface est plus
   haute que le sol et elle prend le jour ». C'est le seul canal qui restait
   pour lever une surface sans la mettre en boîte, et c'est ce qui fait la
   différence entre un aplat peint et une pièce usinée. */
.s-beton{background:var(--beton);color:var(--on-bet)}

/* ---- Couture de matière ----
   Une bascule franche entre nuit et béton fait clignoter la section. Le béton
   monte depuis le bas du cadre au lieu d'arriver d'un coup ; le grain fixe
   casse le dégradé, sinon la rampe se voit comme une bande.
   Les deux arrêts intermédiaires portent maintenant la chroma de la famille et
   la relâchent en montant vers le béton : sans ça la rampe traverse un gris
   neutre à mi-course et se lit comme une bande grise en travers du champ. */
.couture{height:clamp(56px,8vw,104px);background:linear-gradient(180deg,
  var(--nuit) 0%, oklch(0.225 0.024 254) 30%, oklch(0.475 0.014 253) 66%, var(--beton-1) 90%, var(--beton) 100%)}
.couture--vers-nuit{background:linear-gradient(180deg,
  var(--beton) 0%, var(--beton-1) 10%, oklch(0.475 0.014 253) 34%, oklch(0.225 0.024 254) 70%, var(--nuit) 100%)}
/* La couture est déjà de l'air : sans ça, la section qui suit démarre à
   200 px de son titre et le bloc paraît décroché. */
.couture + .sec{padding-top:clamp(34px,5vw,70px)}

/* Balance égalise les longueurs de ligne des titres, pretty évite les
   orphelines. 1.04 et non 1 : les empattements du slab ont besoin d'un
   demi-point d'air de plus qu'une grotesque pour ne pas se croiser. */
h1,h2,h3{font-family:var(--disp);font-weight:700;line-height:1.04;letter-spacing:var(--lsd);text-wrap:balance}
p,li{text-wrap:pretty}
/* Capitales + .2em de tracking en mono : c'est la moitié du gabarit par
   défaut. Même rôle, casse normale, tracking serré, filet plus franc. */
.eyebrow{display:inline-flex;align-items:center;gap:14px;font-family:var(--mono);font-weight:500;
  font-size:var(--t-lbl);letter-spacing:.01em;color:var(--on-nuit-2)}
.eyebrow::before{content:"";width:36px;height:2px;background:var(--verm-nuit);flex:none}
.s-beton .eyebrow{color:var(--on-bet-2)}
.s-beton .eyebrow::before{background:var(--verm-bet)}
/* Ligne d'identification : elle remplace le surtitre qui répétait le nom de la
   page. Un visiteur arrivé par annonce sur une page profonde n'avait aucun
   résumé de qui est ADA au-dessus de la ligne de flottaison. */
/* La ligne d'identification se décolle du titre par un filet, au lieu de le
   toucher : les neuf pages ouvraient toutes sur la même partition (ligne mono,
   titre, paragraphe), et cette amorce identique était le gabarit le plus
   visible du site. */
.ident{display:block;font-family:var(--mono);font-weight:500;font-size:var(--t-lbl);letter-spacing:.01em;
  color:var(--on-nuit-2);max-width:30ch;line-height:1.6;padding-top:14px;border-top:1px solid var(--acier)}
.s-beton .ident{color:var(--on-bet-2);border-top-color:var(--limite-l)}
.v{color:var(--verm-nuit)}.s-beton .v{color:var(--verm-bet)}
/* Le mot colorié par titre tombe, par défaut. Un accent lexical répété à
   l'identique sur neuf pages n'est pas une signature, c'est le gabarit.
   PORTÉE RÉELLE, à ne pas surestimer : cette règle ne couvre que les titres
   qui portent la classe .h2. Les entêtes de page (`.phead h1 em`), les
   dossiers de Réalisations (`.dos__h h2 em`), la chronologie
   (`.chrono__ttl em`) et, depuis le 06/08, le héros et le nom du gérant sur
   l'accueil (`.hero h1 b`, `.named__lead em`) redéclarent la couleur dans le
   <style> de leur page, avec une spécificité supérieure : le mot colorié y
   survit. Les retirer ou les remettre est une décision de contenu page par
   page, pas un effet de bord de la DA. */
.h2 em,.hero h1 b{color:inherit}
/* Échelle revue le 05/08/2026. Corrige le fait que rien n'écrasait rien : les
   titres et le corps étaient trop proches pour qu'un écart fasse événement.
   Les titres montent, le corps descend, donc l'écart se creuse par les deux
   bouts sans toucher à la lisibilité du corps. */
/* 06/08 — le chapô n'en était pas un, et c'est mesurable, pas une question de
   goût : à clamp(1rem,1.4vw,1.1rem) il valait 16 px sur mobile et 17,6 px à
   1440, contre un corps de texte à 17 px et 18 px. Le chapô était donc TOUJOURS
   plus petit que le corps qu'il introduit, et plus pâle (--on-nuit-2). Il ne se
   lisait pas comme une ouverture, il se lisait comme une note de bas de page
   posée en haut. La passe du 05/08 avait monté les titres et descendu le corps
   pour creuser l'écart ; le chapô est resté au milieu à ne rien faire.
   Il redevient ce qu'un chapô de magazine est : nettement plus grand que le
   corps, plus aéré, sur une mesure plus courte parce qu'un plus gros caractère
   demande une ligne plus brève pour que l'œil retombe juste. La couleur ne
   bouge pas : les contrastes mesurés le 02/08 sont conservés tels quels. */
.lede{font-size:clamp(1.18rem,1.9vw,1.4rem);line-height:1.5;max-width:46ch;color:var(--on-nuit-2)}
.s-beton .lede{color:var(--on-bet-2)}
/* L'ouverture respire : ligne d'identification, titre, chapô arrivaient collés,
   ce qui écrase l'effet du titre juste après l'avoir agrandi. */
.h2{font-size:clamp(2.2rem,5.8vw,4rem);max-width:16ch;margin-top:clamp(20px,2.6vw,34px)}
.h2 + .lede,.h2 + * > .lede{margin-top:clamp(16px,2vw,26px)}
/* Entête de page, commun aux quatre pages qui en ont une. 21ch plutôt que 15 :
   le slab est plus large que la grotesque à taille égale, le titre cassait sur
   une ligne de plus. */
.phead h1{max-width:21ch}
/* Même grammaire que le héros de l'accueil, propagée le 05/08 : au-delà de
   900 px la ligne d'identification quitte le dessus du titre et monte en
   annotation de marge à droite. Sept pages laissaient la moitié droite de leur
   entête en sol nu, ce qui n'est pas de l'espace mais un trou.
   Ces sept pages n'avaient PAS de photo derrière leur titre : il n'y a rien à
   renverser chez elles, seulement une amorce à aligner. */
@media(min-width:900px){
  .phead .wrap{display:grid;grid-template-columns:minmax(0,1fr) clamp(168px,15vw,260px);
    column-gap:clamp(32px,5vw,88px);align-items:start}
  .phead .ident{grid-column:2;grid-row:1;align-self:start;margin:0;max-width:none;
    border-top-color:var(--verm-nuit);border-top-width:2px}
}
.h2 em{font-style:normal;color:var(--verm-nuit)}
.s-beton .h2 em{color:var(--verm-bet)}

/* ---- Reveal ----
   Un révélé enrichit un état déjà visible. Il ne le conditionne jamais :
   une transition ne se joue pas dans un onglet en arrière-plan ni dans un
   moteur de rendu sans compositeur, et la section partirait vide. D'où le
   filet côté script, qui montre tout dès que le rendu n'est pas observable. */
.reveal{transition:opacity var(--t-in) var(--ease),transform var(--t-in) var(--ease)}
.js .reveal{opacity:0;transform:translateY(18px)}
.js .reveal.in{opacity:1;transform:none}
/* Décalage court : au-delà de 80 ms par cran, la page paraît lente. */
.d1{transition-delay:.06s}.d2{transition-delay:.12s}.d3{transition-delay:.18s}.d4{transition-delay:.24s}
.line-mask{display:block;overflow:hidden;padding:.18em 0 .08em;margin-block:-.13em}
.line-mask>span{display:block;line-height:1.06;transform:translateY(112%);transition:transform .78s var(--ease)}
.js .line-mask.in>span{transform:none}

/* ---- Filet de progression de lecture ----
   L'accueil fait onze écrans et demi. Sans repère, l'abandon vient du
   découragement avant de venir du contenu. Piloté par la position du scroll,
   natif, zéro octet de JS et aucun écouteur. Masqué là où la propriété n'existe
   pas : un filet vermillon plein en permanence dirait le contraire du vrai. */
.progress{display:none}
@supports (animation-timeline: scroll()){
  @media (prefers-reduced-motion:no-preference){
    .progress{display:block;position:fixed;inset:0 0 auto 0;height:2px;z-index:var(--z-progress);
      background:var(--verm-nuit);transform-origin:0 50%;transform:scaleX(0);pointer-events:none;
      animation:lecture linear both;animation-timeline:scroll(root block)}
  }
}
@keyframes lecture{from{transform:scaleX(0)}to{transform:scaleX(1)}}

/* ---- Grain ----
   Une DA photo-led sans matière laisse les grands aplats plats, et la
   dominante nuit multiplie les grands aplats. Fixe et pointer-events:none :
   sur un conteneur qui défile, un filtre de bruit repeint à chaque image et
   effondre le nombre d'images par seconde sur mobile. 2,8 % : assez pour que
   l'aplat vibre, trop peu pour déplacer un rapport de contraste. */
/* Remonté de 2,8 à 5,5 % le 05/08 : à 2,8 le grain ne se voyait plus une fois
   le sol assombri, et l'aplat redevenait plat. Toujours trop peu pour déplacer
   un rapport de contraste, vérifié au relevé. */
/* 06/08 — deux fréquences au lieu d'une.
   Un bruit à une seule échelle est un papier de verre : régulier, donc lu comme
   une trame, pas comme de la matière. La matière réelle a toujours un grain
   fin ET une inégalité large. La seconde couche est très basse fréquence (.22)
   et sur une tuile quatre fois plus grande : elle ne se voit pas, elle empêche
   la première de paraître mécanique. Coût nul : même élément fixe, même
   composite, une image de fond de plus et aucun repaint supplémentaire. */
.grain{position:fixed;inset:0;z-index:var(--z-grain);pointer-events:none;opacity:.055;
  mix-blend-mode:soft-light;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.82' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E"),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='640' height='640'%3E%3Cfilter id='m'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.22' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='640' height='640' filter='url(%23m)' opacity='.5'/%3E%3C/svg%3E");
  background-size:160px 160px,640px 640px}

/* ---- Boutons ---- */
/* 180 ms : un retour de pression au-delà de 200 ms ne se lit plus comme une
   réponse au doigt. Les propriétés sont nommées une par une, jamais `all`. */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:10px;font-weight:600;font-size:var(--t-body);
  padding:17px 28px;min-height:54px;border:1.5px solid transparent;border-radius:2px;
  transition:transform var(--t-ui) var(--ease-out),background var(--t-ui) var(--ease-out),
             border-color var(--t-ui) var(--ease-out),color var(--t-ui) var(--ease-out)}
.btn--pr{background:var(--verm);color:var(--on-nuit);border-color:var(--verm)}
.btn--pr:active{transform:scale(.97)}
@media (hover:hover) and (pointer:fine){
  .btn--pr:hover{background:var(--verm-nuit);border-color:var(--verm-nuit);transform:translateY(-2px)}
}
/* Le second bouton n'est pas une boîte. Il est souligné, comme les champs :
   c'est la même grammaire que le reste du site, et ça retire un rectangle
   vide de 460 px sur mobile sans rien perdre en contraste.
   Le souligné est une limite de composant, donc il prend --acier-h (4,28:1)
   et non --acier (2,70:1), qui est réservé aux filets décoratifs. */
.btn--gh{border:0;border-bottom:1.5px solid;border-radius:0;padding:12px 2px;min-height:48px;
  align-self:flex-start;gap:0}
.s-nuit .btn--gh,.s-nuit-1 .btn--gh,.s-nuit-2 .btn--gh,.hero .btn--gh,.cta-band .btn--gh{color:var(--on-nuit);border-bottom-color:var(--acier-h)}
.s-beton .btn--gh{color:var(--on-bet);border-bottom-color:var(--limite-l)}
.btn--gh:active{transform:scale(.97)}
@media (hover:hover) and (pointer:fine){
  .s-nuit .btn--gh:hover,.s-nuit-1 .btn--gh:hover,.s-nuit-2 .btn--gh:hover,.hero .btn--gh:hover,.cta-band .btn--gh:hover{
    border-bottom-color:var(--verm-nuit);color:var(--verm-nuit)}
  .s-beton .btn--gh:hover{border-bottom-color:var(--verm-bet);color:var(--verm-bet)}
}

/* ---- Header ---- */
/* Opaque, sans flou. Le noir translucide au-dessus d'une section claire
   donnait une bande grise où le logo blanc devenait illisible. Un fond plein
   se comporte pareil sur une photo sombre et sur du papier. */
.head{position:fixed;top:0;left:0;right:0;z-index:var(--z-head);
  transition:background var(--t-out) var(--ease-out),border-color var(--t-out) var(--ease-out);
  border-bottom:1px solid transparent}
.head.solid{background:var(--nuit);border-bottom-color:var(--acier)}
.head__in{display:flex;align-items:center;justify-content:space-between;gap:24px;height:68px}
/* Le point vermillon est le seul signe compact de la marque : il porte le
   favicon et l'image de partage, donc il doit se lire pareil dans l'entête. */
.brand{font-family:var(--disp);font-weight:700;font-size:19px;letter-spacing:-.006em;
  color:var(--on-nuit);flex:none;display:inline-flex;align-items:center;min-height:44px}
.brand i{color:var(--verm-nuit);font-style:normal}
.nav{display:none;align-items:center;gap:clamp(12px,1.6vw,20px)}
@media(min-width:1140px){.nav{display:flex}}
.nav a{font-size:var(--t-sm);color:var(--on-nuit-2);transition:color .3s;
  display:inline-flex;align-items:center;min-height:44px}
.nav a:hover{color:var(--on-nuit)}
.nav a[aria-current="page"]{color:var(--on-nuit)}
.head__cta{display:none}
@media(min-width:1140px){.head__cta{display:inline-flex;padding:12px 20px;min-height:44px;font-size:var(--t-ui)}}
.burger{display:inline-flex;align-items:center;gap:10px;font-size:var(--t-sm);font-weight:600;color:var(--on-nuit);
  min-height:44px;padding-inline:4px}
@media(min-width:1140px){.burger{display:none}}
.burger b{display:block;width:22px;height:9px;border-top:1.5px solid currentColor;border-bottom:1.5px solid currentColor}
/* Le menu recouvre le sol : sur le même barreau que lui, on ne sait pas si la
   page a disparu ou si elle est encore dessous. Un barreau plus bas le dit. */
.menu{position:fixed;inset:0;z-index:var(--z-menu);background:var(--nuit-0);display:flex;flex-direction:column;
  justify-content:center;padding:clamp(24px,7vw,64px);transform:translateY(-100%);
  transition:transform .55s var(--ease);visibility:hidden}
.menu.open{transform:none;visibility:visible}
.menu a{font-family:var(--disp);font-weight:700;font-size:clamp(1.8rem,6.4vw,2.8rem);letter-spacing:var(--lsd);
  text-transform:uppercase;padding-block:clamp(8px,1.4vw,12px);color:var(--on-nuit-2);transition:color .3s}
.menu a:hover,.menu a[aria-current="page"]{color:var(--on-nuit)}
.menu__x{position:absolute;top:22px;right:clamp(22px,5vw,56px);font-size:var(--t-ui);font-weight:600;min-height:44px}

/* ---- Footer ---- */
/* Le pied était au ras du sol et ne tenait que par un filet de 1 px. Il occupe
   maintenant le barreau du dessous : la page finit par s'enfoncer, et la
   séparation ne dépend plus du seul trait. */
.foot{padding-block:clamp(64px,9vw,110px) clamp(28px,4vw,40px);background:var(--nuit-0);color:var(--on-nuit)}
.foot__top{display:grid;grid-template-columns:1fr;gap:clamp(36px,5vw,48px)}
@media(min-width:560px){.foot__top{grid-template-columns:1fr 1fr}}
@media(min-width:900px){.foot__top{grid-template-columns:1.7fr 1fr 1fr}}
/* Le wordmark tombe pile sur la frontière des deux crans (2,6 rem à 1440). Il
   reste au cran serré : c'est la signature de marque, pas un titre courant, et
   la déplacer d'un cran pour un pixel de corps serait de la dérive. */
.foot__brand{font-family:var(--disp);font-weight:700;font-size:clamp(1.9rem,4.6vw,2.6rem);letter-spacing:var(--lsd)}
.foot__brand i{color:var(--verm-nuit);font-style:normal}
.foot__brand p{font-family:var(--body);font-weight:400;font-size:1rem;color:var(--on-nuit-2);margin-top:16px;
  max-width:34ch;line-height:1.6;letter-spacing:0}
.foot h4{font-size:var(--t-lbl);font-weight:600;letter-spacing:.02em;color:var(--on-nuit-3);margin-bottom:14px;font-family:var(--body)}
.foot__list{display:flex;flex-direction:column}
.foot__list a,.foot__list p{color:var(--on-nuit-2);font-size:var(--t-ui)}
.foot__list a{display:inline-flex;align-items:center;min-height:44px;overflow-wrap:anywhere;transition:color .3s}
.foot__list a:hover{color:var(--verm-nuit)}
.foot__list p{padding-block:6px}
.foot__list p b{color:var(--on-nuit);font-weight:600}
.foot__bar{margin-top:clamp(40px,5vw,56px);padding-top:20px;border-top:1px solid var(--acier);
  display:flex;flex-wrap:wrap;gap:12px 24px;justify-content:space-between;font-size:var(--t-mono);color:var(--on-nuit-3)}
.foot__bar a{display:inline-flex;align-items:center;min-height:44px}
.foot__bar a:hover{color:var(--on-nuit-2)}

/* ---- Barre d'appel mobile ----
   Elle se retire quand la bande de conversion est à l'écran : sinon le même
   bouton vermillon s'affiche deux fois, l'un sous l'autre. */
.callbar{position:fixed;left:0;right:0;bottom:0;z-index:var(--z-callbar);display:none;gap:1px;
  background:var(--acier);transform:translateY(110%);
  transition:transform var(--t-out) var(--ease-out);padding-bottom:env(safe-area-inset-bottom)}
.callbar.show{transform:none}
.callbar.off{transform:translateY(110%)}
.callbar a{flex:1;text-align:center;padding:16px;font-weight:600;font-size:var(--t-ui);min-height:56px;
  display:flex;align-items:center;justify-content:center;
  transition:transform var(--t-ui) var(--ease-out)}
.callbar .c-pr{background:var(--verm);color:var(--on-nuit)}
/* La barre flotte au-dessus de tout : sur le barreau du sol elle se confondait
   avec la section qui passait dessous. */
.callbar .c-gh{background:var(--nuit-0);color:var(--on-nuit)}
@media (max-width:1139px){.callbar{display:flex}body{padding-bottom:var(--callbar-h)}}

/* ---- Bande de conversion, réutilisée en bas de chaque page ----
   Le filet haut est là parce que la page est en dominante nuit : la bande
   suit parfois une section de même valeur, et sans lui la couture disparaît.
   C'est une séparation, pas une cage : un seul trait, jamais un cadre. */
.cta-band{background:var(--nuit-1);color:var(--on-nuit);padding-block:clamp(64px,9vw,110px);
  border-top:1px solid var(--acier)}
.cta-band__in{display:grid;gap:clamp(24px,3.4vw,40px);align-items:end}
@media(min-width:840px){.cta-band__in{grid-template-columns:1.4fr auto}}
.cta-band h2{font-size:clamp(1.75rem,4.2vw,2.7rem);max-width:19ch}
.cta-band p{color:var(--on-nuit-2);margin-top:16px;max-width:44ch;font-size:1rem}
.cta-band__a{display:flex;flex-wrap:wrap;gap:14px}

/* ============================================================================
   MOUVEMENT
   Chaque dispositif se justifie en une phrase, ou il saute.
   Tout est en transform/opacity/filter, donc sur le GPU, et tout tombe sous
   prefers-reduced-motion. Aucun écouteur de scroll, aucune bibliothèque.
   ============================================================================ */

/* 1. Continuité entre les pages.
   Le site raconte un seul chantier ; passer d'une page à l'autre ne doit pas
   clignoter. Natif, zéro octet de JS, ignoré par les navigateurs qui ne le
   connaissent pas. */
@view-transition{navigation:auto}
::view-transition-old(root){animation:vt-out .22s var(--ease-2) both}
::view-transition-new(root){animation:vt-in .42s var(--ease) both}
@keyframes vt-out{to{opacity:0}}
@keyframes vt-in{from{opacity:0;transform:translateY(10px)}}
/* L'entête ne participe pas au fondu : il est le point fixe du site. */
.head{view-transition-name:head}

/* 2. Profondeur sur les photos à bord perdu fixes.
   La promesse du site est photo-led ; une photo qui dérive pendant qu'on la
   dépasse donne la matière que la DA cherche. Piloté par la position de
   l'élément dans la fenêtre, pas par un écouteur.
   Réservé aux photos qui ne portent pas déjà leur propre transformation : sur
   la chronologie et le moteur Prestations, les couches ont un zoom lent, et
   deux animations de `transform` sur le même élément s'écrasent l'une l'autre. */
@supports (animation-timeline: view()){
  @media (prefers-reduced-motion:no-preference){
    .parallax{animation:drift linear both;animation-timeline:view();animation-range:cover 0% cover 100%}
  }
}
@keyframes drift{from{transform:scale(1.12) translateY(-2.2%)}to{transform:scale(1.12) translateY(2.2%)}}

/* 3. Retour tactile.
   Le doigt doit sentir qu'il a appuyé, y compris quand le réseau est lent et
   que la page suivante tarde. */
.btn:active,.callbar a:active{transform:scale(.985)}

@media (prefers-reduced-motion:reduce){
  .js .reveal{opacity:1;transform:none;transition:none}
  .js .line-mask>span{transform:none;transition:none}
  .btn:hover{transform:none}
  .menu{transition:none}
  .parallax{animation:none}
  ::view-transition-old(root),::view-transition-new(root){animation:none}
  /* La barre d'appel glissait de 110 % de sa hauteur : c'est un déplacement,
     donc il tombe aussi. Elle apparaît et disparaît, elle ne voyage plus. */
  .callbar{transition:none}
}

/* Toute ancre interne atterrissait sous l'entete fixe de 68px. Regle posee
   une fois pour toutes les cibles plutot qu'au cas par cas : #chrono l'avait
   encore, la prochaine ancre ajoutee l'aurait eu aussi. */
[id]{scroll-margin-top:84px}
