/* cta.css — section « Vous souhaitez qu'on travaille ensemble ? » : illustration,
   accroche et formulaire de contact (#contact), premier bloc du <footer>.

   Toutes les valeurs sont relevées sur la SOURCE VIVANTE le 2026-08-11, aux
   paliers 1440 / 1024 / 390, après parcours de la section par paliers puis
   dépassement et retour au bord haut (règle A₁.5). Les deux lectures — celle
   prise après le premier défilement et celle prise après l'aller-retour — sont
   identiques : pas d'artefact de 170 px sur cette section. `location.href` ET
   `innerWidth` ont été renvoyés dans le MÊME `browser_evaluate` que chaque
   mesure (règle A₁.6). Les quatre champs ont été énumérés un par un, pas
   échantillonnés (piège n° 8) : quatre bordures basses, une seule valeur
   distincte.

   Les règles CSS de la source ont pu être lues telles quelles (elles vivent
   dans des <style> de la page, pas dans le CSSOM des feuilles liées) ; la
   géométrie ci-dessous n'est donc pas déduite de boîtes mesurées mais copiée
   des déclarations, puis vérifiée par la mesure.

   Contrôle arithmétique de la hauteur de section :
     1440 : 50 (pad haut) + 716,30 (carte) + 10 (pad bas)              =  776,30
            carte = colonne gauche = 60 + 392,70 (illustr.) + 203,61 (texte) + 60
     1024 : 50 + [708 (gauche) + 10 (gap) + 641,59 (droite)] + 10      = 1419,59
      390 : 20 + [617,90 + 10 + 576,59] + 10                           = 1234,49
   Les trois totaux sont exactement les hauteurs mesurées sur la source ; la
   cible du brief à 1440 (776) est donc atteinte à 0,3 px près.

   ---------------------------------------------------------------------------
   FOND DE SECTION : AUCUN, ET C'EST VOULU. Relevé `rgba(0, 0, 0, 0)` sur la
   source : le jaune vient du <footer> qui porte la section. Le <footer> est
   l'affaire de la tâche 17, qui n'est pas faite — d'ici là on voit donc le
   crème du <body> derrière cette section. Ce n'est pas un défaut de cette
   feuille et il ne faut PAS le compenser par un fond local.

   ⚠ LE FESTON JAUNE AU-DESSUS DE LA SECTION N'EST PAS À NOUS. La source pose
   15 bosses de 96 × 116 (rayon 90px 90px 0 0, jaune) en `position: absolute;
   top: -61px` — mais sur le <FOOTER>, PAS sur la <section> : vérifié par
   `section.contains(feston)` → false, et par la chaîne des parents
   (DIV > FOOTER). C'est le `.scallop-top` du footer, dans la couleur du
   footer, et il revient donc à la tâche 17. La tâche 15 (faq.css, manque n° 5)
   l'avait renvoyé à « la section suivante » ; la section suivante est bien
   #contact, mais la mesure tranche : il appartient au footer. À signaler pour
   qu'il ne tombe entre les deux chaises.
   Bonne nouvelle pour la tâche 17 : la primitive `.scallop-top` convient telle
   quelle — 15 bosses, remontée 61, et une bosse de la source est un rectangle
   de 116 de haut à coins hauts arrondis de 48, dont seuls les 61 px du haut
   dépassent, soit exactement ce que peint la primitive (demi-disque de 48 +
   13 px de bande).

   ---------------------------------------------------------------------------
   MANQUES DU BRIEF (A₀) — relevés puis reconstruits ici :

   1. LA BORDURE BASSE DES CHAMPS. Le brief ne la donne pas et le relevé du
      10/08 non plus (« relève la bordure toi-même »). Ce n'est pas un `border`
      sur le champ : `getComputedStyle(champ).border` vaut `0px none` aux
      quatre champs. C'est un `::after` en `inset: 0` sur le conteneur, qui ne
      peint QUE son bord bas — invisible à tout balayage de sous-arbre
      (`querySelectorAll('*')` ne voit aucun pseudo-élément, piège n° 8), repéré
      sur la capture puis confirmé par `getComputedStyle(el, '::after')` :
        repos  : 2px solid 246·194·244  = --c-pink-light
        focus  : 3px solid 192·236·191  = --c-mint
      L'état de focus est donc une donnée de la source, pas un ajout d'accessi-
      bilité : la source le pose via `:focus-within::after`, reproduit tel quel.

   2. LE FOND DES CHAMPS À 5 % DE BLANC. Relevé 255·255·255 à 0,05 d'alpha sur
      le conteneur. Sur le crème l'effet est de l'ordre d'un niveau sur 255, donc
      invisible à l'œil — reproduit quand même, en `color-mix` pour rester sur
      les tokens (aucune couleur brute hors tokens.css). Même procédé qu'en
      tâche 8 (services.css).

   3. L'ILLUSTRATION EN HAUT DE LA COLONNE GAUCHE — signalée par le constat n° 1
      du contrôleur, absente du brief. `r3nm5qQvCGD77UJpNE0LsWxznk.png`, déjà
      présente dans `assets/`, 1024 × 1024 natifs. La description de
      `assets/README.md` est cette fois exacte, vérifiée en regardant l'image :
      mascotte « tranche de pain » qui court vers un gros bouton « LET'S GO! ».
      Rien d'autre dans la section : le balayage A₀ ne rend qu'une seule <img>,
      zéro <svg>, zéro `background-image`, et le balayage complémentaire sur
      `box-shadow`, `clip-path`, `mask-image`, `filter`, `opacity` et
      `transform` ne rend AUCUN élément (piège n° 8, corollaire 2).

   4. LE RECADRAGE DE L'ILLUSTRATION AU PALIER TABLETTE. Elle n'est pas posée en
      largeur fixe : `width: 66%` + `aspect-ratio: 1/1` + `max-height: 500px` +
      `object-fit: cover`. À 1440 elle est carrée (392,70) ; à 1024 les 66 %
      donnent 570,23 et le plafond de 500 la rogne en haut et en bas (règle
      A₁.4 : c'est bien `cover`, relevé, pas `contain`). À ≤ 809 la source
      change la largeur pour 97 % et l'illustration redevient carrée (261,90).

   ---------------------------------------------------------------------------
   `.btn` (layout.css) N'EST PAS RÉUTILISÉE, et le constat n° 4 du contrôleur
   n'est vrai qu'à moitié. La TYPOGRAPHIE du libellé correspond bien à `.btn`
   (Poppins 600 22px, `ls -0.88px`) — mais la FORME est celle du bouton de
   #projects (tâche 10), pas celle de `.btn` : une pastille jaune de rayon 18
   posée en bas d'une boîte de rayon 25 dont seul le BORD BAS de 12px est peint
   (`::after` en inset 0, couleur 59·0·27 = --c-ink), et non une pastille de
   rayon 999px à ombre dure décalée en x et y.

   Vérification faite : sur la SOURCE, le CTA du hero (« C'est parti ! ») est le
   MÊME composant que celui-ci — boîte de 68 de haut, `padding: 0 0 9px`, rayon
   25, `::after` à bord bas de 12px en --c-ink, pastille intérieure de 49,8 à
   rayon 18. `.btn` diverge donc de la source pour TOUS les CTA du site, pas
   seulement ici. Ce n'est pas à cette tâche de le corriger : `.btn` est partagée
   par seize sections et le brief l'interdit explicitement. C'est remonté au
   rapport comme matière pour la tâche 18.

   La géométrie ci-dessous est donc jumelle de `.projects__btn`. Les deux ne sont
   pas factorisées : « aucun sélecteur d'une section ne cible le DOM d'une autre
   section ». La factorisation des formes partagées est l'arbitrage de la
   tâche 18 — ce bouton en est le troisième exemplaire (hero, projects, cta).

   ---------------------------------------------------------------------------
   ÉCARTS DE STRUCTURE ASSUMÉS PAR RAPPORT À LA SOURCE :

   - Les libellés sont de vrais `<label for="…">`. Le constat n° 2 du contrôleur
     dit qu'ils « ne sont PAS des <label> au sens HTML » : c'est faux, et la
     source vivante le montre — chaque champ est enveloppé dans un `<label>` qui
     contient le texte visible ET le champ (association IMPLICITE). Le texte
     visible est bien un `<p>` en Climate Crisis 27/32,4, mais il est à
     l'intérieur du `<label>`. On passe ici à l'association EXPLICITE (`for` +
     `id`), plus robuste, au rendu strictement identique. Aucun
     `.visually-hidden` n'est nécessaire.

   - Deux niveaux d'emballage de la source sont supprimés parce qu'ils n'ont
     qu'un enfant et ne portent aucune propriété visible : le conteneur du
     formulaire (`gap: 31px` pour un unique enfant) et le conteneur de
     l'illustration (mêmes boîte et rayon que l'<img> qu'il contient, dont les
     règles sont reportées sur l'<img> elle-même). Le niveau
     carte / colonnes, lui, est CONSERVÉ : les deux boîtes portent des
     `max-width` différentes (1900 pour la carte crème, 1440 pour la paire de
     colonnes), qui ne se recouvrent qu'au-delà de 1440 px de viewport mais qui
     y produisent bien deux largeurs distinctes.

   - Le bouton n'est pas un lien. Sur la source, « Envoyer mon message » est un
     `<a>` vers un lien d'affiliation du marketplace Framer, enveloppé dans un
     `<button type="submit">`. On garde le `<button type="submit">` et on jette
     le `<a>` : c'est l'un des trois écarts autorisés par les contraintes
     globales, et `tools/check.py` refuse toute URL du domaine de l'éditeur.

   - Les attributs `type` et `required` sont ceux de la source, relevés champ
     par champ : text/email/tel/textarea, requis sur Nom, Email et Message,
     facultatif sur Téléphone. Les `name` passent en français (la source envoie
     `Name` / `Phone Number` à un backend Framer que nous n'avons pas).

   - `outline: none` sur les champs focalisés N'EST PAS repris : la source le
     pose, mais `css/base.css` (partagé) donne un anneau de focus à tout le
     site et le supprimer ici dégraderait l'accessibilité au clavier sans
     changer le rendu au repos, seul état comparé. */

/* ---------- Section ----------
   Fond volontairement absent (voir l'en-tête). Les 40px de gouttière
   horizontale ne sont PAS `--gutter` : la source garde 40 au palier tablette
   (où le token vaut 32) et ne descend à 20 qu'à ≤ 809. */
.cta {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 50px 40px 10px;
}

/* Carte crème à rayon 40. `max-width: 1900px` relevé sur la source ; sans effet
   à 1440 et en dessous, conservé pour les viewports plus larges. */
.cta__card {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  max-width: 1900px;
  border-radius: 40px;
  background: var(--c-cream);
}

/* Paire de colonnes : gouttière de 10, plafond de largeur à 1440 (relevé). */
.cta__cols {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  max-width: 1440px;
}

/* Deux colonnes égales : `flex: 1 0 0` de part et d'autre d'une gouttière de
   10 donne 675 chacune dans les 1360 de la zone de contenu à 1440.
   `align-items: center` sur le parent : la colonne de droite (665,59) est plus
   courte que celle de gauche (716,30), qui donne sa hauteur à la carte, et se
   centre verticalement — d'où son bord haut à +25,36 relevé sur la source. */
.cta__panel {
  flex: 1 0 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 60px 40px;
  border-radius: 30px;
  background: var(--c-cream);
}

/* Colonne gauche : illustration puis bloc de texte, sans gouttière (relevé
   `gap: 0`) — les 16px qui séparent visuellement le titre du paragraphe sont
   internes au bloc de texte, et les 10px de padding de ce bloc sont le seul
   espace entre l'illustration et le titre. */
.cta__illustration {
  flex: none;
  width: 66%;
  max-height: 500px;
  aspect-ratio: 1 / 1;
  object-fit: cover;
}

.cta__intro {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  width: 100%;
  padding: 10px;
}

/* Titre en <h2> et non en <h3> comme la source : les quinze sections déjà
   livrées posent toutes leur titre de section en <h2>, et le niveau <h3> de la
   source est un artefact de Framer sans portée sémantique (elle n'a pas de <h2>
   au-dessus). Le rendu est identique, la taille étant posée ici. */
.cta__heading {
  width: 100%;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--fs-37);
  line-height: 37px;
  color: var(--c-ink);
  text-align: center;
  /* Relevé sur la source (`text-wrap: balance` calculé), sur le titre COMME sur
     le paragraphe. Ce n'est pas cosmétique : sans lui le paragraphe garde ses
     trois lignes mais coupe à « …un coin—glissez / nous un message et faisons un
     bout de chemin / ensemble ! » (519 / 533 / 100 px mesurés), là où la source
     équilibre à 418,6 / 417,4 / 344. Écart visible sur la capture, à hauteur de
     bloc pourtant identique — d'où le contrôle par la mesure de chaque ligne
     (`Range.getClientRects()`), et pas seulement par la boîte englobante.
     Contrairement à #faq, aucun `font-kerning: none` n'est nécessaire : ce
     titre-ci est un simple nœud texte sur la source, pas une découpe
     lettre à lettre en <span>. */
  text-wrap: balance;
}

.cta__text {
  width: 100%;
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: var(--fs-24);
  line-height: 31.2px;
  letter-spacing: -0.96px;
  color: var(--c-ink);
  text-align: center;
  text-wrap: balance;
}

/* ---------- Formulaire ----------
   Gouttière de 20 entre groupes de champs, 12 entre un libellé et son champ.
   Hauteur à 1440 : 3 × 84,4 + 144,4 (message) + 68 (bouton) + 4 × 20 = 545,59. */
.cta__form {
  display: flex;
  flex-direction: column;
  gap: 20px;
  width: 100%;
}

.cta__field {
  display: flex;
  flex-direction: column;
  gap: 12px;
  width: 100%;
}

.cta__label {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--fs-27);
  line-height: 32.4px;
  color: var(--c-ink);
}

/* Conteneur du champ : porte le fond à 5 % de blanc (manque A₀ n° 2) et sert de
   repère au pseudo-élément qui peint la bordure basse (manque A₀ n° 1).
   En `flex` et non en `block` comme la source : un <input> en `inline-block`
   dans un bloc laisse un talon sous la ligne de base, que la source neutralise
   par une hauteur codée sur le conteneur ; `display: flex` donne la même boîte
   de 40 sans coder la hauteur deux fois — ce qui compte pour la zone de
   message, redimensionnable. */
.cta__input-wrap {
  position: relative;
  display: flex;
  width: 100%;
  background: color-mix(in srgb, var(--c-white) 5%, transparent);
}

.cta__input-wrap::after {
  content: "";
  position: absolute;
  inset: 0;
  border-bottom: 2px solid var(--c-pink-light);
  pointer-events: none;
}

/* État de focus relevé sur la source, pas un ajout : la bordure passe de 2px
   rose à 3px vert d'eau. Posé sur le conteneur en `:focus-within`, comme la
   source, pour que le libellé cliquable donne le même retour visuel. */
.cta__input-wrap:focus-within::after {
  border-bottom: 3px solid var(--c-mint);
}

.cta__input {
  width: 100%;
  height: 40px;
  padding: 0 10px;
  border: 0;
  border-radius: 0;
  background: transparent;
  font-family: var(--font-cond);
  font-weight: 400;
  font-size: var(--fs-20);
  line-height: 24px;
  color: var(--c-ink);
}

/* `resize: vertical` est relevé sur la source (la poignée est visible sur la
   capture, en bas à droite de la zone de message). Le conteneur n'est pas mis
   en `overflow: hidden` — la source le fait, mais son seul effet ici serait de
   rogner la poignée. */
.cta__textarea {
  display: block;
  height: 100px;
  min-height: 100px;
  padding: 0 10px;
  resize: vertical;
}

/* ---------- Bouton d'envoi ----------
   Boîte de 68 de haut à rayon 25, dont seul le bord bas de 12px est peint ;
   la pastille jaune de 49,8 à rayon 18 est alignée en bas avec 9px de padding,
   le liseré sombre reste donc visible sur 9px. Voir l'en-tête pour le refus de
   réutiliser `.btn`. */
.cta__submit {
  position: relative;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  width: 100%;
  height: 68px;
  padding-bottom: 9px;
  border-radius: 25px;
  overflow: hidden;
  transition: padding-bottom var(--dur-fast) var(--ease-out);
}

.cta__submit::after {
  content: "";
  position: absolute;
  inset: 0;
  border-bottom: 12px solid var(--c-ink);
  border-radius: 25px;
  pointer-events: none;
}

.cta__submit-face {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  padding: 14px 34px 16px;
  border-radius: 18px;
  background: var(--c-yellow);
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: var(--fs-22);
  line-height: 19.8px;
  letter-spacing: -0.88px;
  color: var(--c-ink);
  text-align: center;
}

/* Enfoncement au survol : le padding-bas passe de 9 à 4 (règle relevée sur la
   source, variante `framer-v-1klfovf`, celle que porte ce bouton aux trois
   paliers). La pastille descend donc de 5px et le liseré se réduit d'autant. */
.cta__submit:hover,
.cta__submit:focus-visible {
  padding-bottom: 4px;
}

@media (prefers-reduced-motion: reduce) {
  .cta__submit { transition: none; }
}

/* ---------- Tablette (810 – 1199) ----------
   La source passe la carte en colonne : l'illustration et le texte au-dessus,
   le formulaire en dessous, chacun sur toute la largeur. Le padding horizontal
   de la section reste à 40. La colonne gauche perd son padding bas (relevé
   `60px 40px 0`), d'où une hauteur de 708 = 60 + 500 + 148. */
@media (max-width: 1199px) {
  .cta__card,
  .cta__cols {
    flex-direction: column;
  }

  .cta__panel {
    flex: none;
    width: 100%;
  }

  .cta__panel--pitch {
    padding: 60px 40px 0;
  }

  .cta__heading {
    font-size: var(--fs-30);
    line-height: 30px;
  }

  .cta__text {
    font-size: var(--fs-20);
    line-height: 26px;
    letter-spacing: -0.8px;
  }

  .cta__label {
    font-size: var(--fs-22);
    line-height: 26.4px;
  }
}

/* ---------- Mobile (≤ 809) ----------
   L'illustration repasse en carré : la source la fait à 97 % de la largeur de
   contenu, où le plafond de 500 ne mord plus (261,90 à 390). Les paddings des
   deux colonnes deviennent dissymétriques (20/40 à gauche, 25/20/30 à droite) :
   ce sont les valeurs relevées, pas une harmonisation. */
@media (max-width: 809px) {
  .cta {
    flex-direction: column;
    padding: 20px 20px 10px;
  }

  .cta__illustration {
    width: 97%;
  }

  .cta__panel--pitch {
    padding: 20px 40px;
  }

  .cta__panel--form {
    padding: 25px 20px 30px;
  }

  .cta__heading {
    font-size: var(--fs-26);
  }
}

/* ═══════════════════════════════════════════════════════════════════════════════
   Formulaire branché — ajouté le 2026-08-17

   Ces règles ne relèvent PAS du relevé de la source : la source n'a pas de
   formulaire fonctionnel, son bouton d'envoi est un lien d'affiliation vers le
   marketplace Framer (vestige n° 15). Tout ce bloc est donc de notre main, et
   volontairement rangé en fin de fichier pour rester distinct du relevé.
   ═══════════════════════════════════════════════════════════════════════════════ */

/* ---- Champ piège (anti-spam) ----
   ⚠ Ni `display:none` ni `visibility:hidden` : les robots les plus soigneux lisent
   la feuille de style et sautent les champs ainsi masqués. Un champ sorti du cadre
   reste, pour eux, un champ ordinaire.
   `height:0` évite qu'il n'ouvre un espace dans la colonne du formulaire. */
.cta__honeypot {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 0;
  overflow: hidden;
}

/* ---- Zone d'état ----
   Elle reste dans le flux même vide (`min-height`) : sans cela, l'apparition du
   message ferait sauter la mention légale et le bas de la carte de plusieurs
   dizaines de pixels sous le doigt du visiteur, juste après son clic. */
/* ⚠ La carte de contact est sur fond CRÈME (`--c-cream`, voir `.cta__card` plus
   haut), pas sur un fond sombre. Tout ce qui s'écrit ici doit donc être FONCÉ.
   Le piège s'est refermé une première fois : ces textes avaient d'abord été
   coloriés en crème, et étaient purement et simplement invisibles.
   Les couleurs ci-dessous sont choisies pour passer le rapport de contraste
   WCAG AA (4,5:1) sur ce crème. Mesuré : `--c-ink` donne 16,7:1, `--c-forest`
   13,0:1 et `--c-red` 5,6:1 — tous conformes. `--c-mint` (1,25:1) et
   `--c-teal` (3,30:1) sont donc écartés, bien trop clairs pour du texte de
   cette taille. */

.cta__status {
  min-height: 1.5em;
  margin: 0;
  font-family: var(--font-sans);
  font-size: var(--fs-16);
  line-height: 1.5;
  color: var(--c-ink);
}

.cta__status.is-pending { color: var(--c-ink); opacity: .7; }
.cta__status.is-success { color: var(--c-forest); font-weight: 600; }
.cta__status.is-error   { color: var(--c-red); font-weight: 600; }

/* ---- Mention RGPD et repli sans JavaScript ---- */
.cta__legal {
  margin: 0;
  font-family: var(--font-sans);
  font-size: var(--fs-15);
  line-height: 1.5;
  color: color-mix(in srgb, var(--c-ink) 75%, transparent);
}

.cta__legal a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 3px;
}

.cta__legal a:hover,
.cta__legal a:focus-visible { color: var(--c-orange-deep); }

/* ---- Bouton pendant l'envoi ----
   Le bouton reste lisible mais visiblement inerte : c'est ce qui dit au visiteur
   que son clic a été pris en compte et qu'il n'a pas à recommencer. */
.cta__submit:disabled { cursor: progress; }
.cta__submit:disabled .cta__submit-face { opacity: .7; }
.cta__submit:disabled:hover { padding-bottom: 9px; }
