/* projects.css — section portfolio « Regardez ce qu'on a fait ! » (#projects).

   Toutes les valeurs ci-dessous sont relevées sur la source le 2026-08-11, aux
   trois paliers, animations terminées (`document.getAnimations()` vide) et
   confirmées par une seconde lecture après un aller-retour de défilement
   (règle A1#5). `location.href` a été renvoyé dans le même `browser_evaluate`
   que chaque mesure (règle A1#6). Rien n'est extrapolé sauf mention explicite.

   ⚠ Les positions verticales du brief (grille à `top 426 / 1046`, logos à
   `454 / 1074`) sont FAUSSES de +170px : elles ont été prises pendant
   l'animation d'apparition de la source, qui translate ses blocs de 170px.
   Valeurs réelles : grille à `top 256`, rangée 2 à `875,8`, logos à
   `284 / 903,8`. Contrôle arithmétique : 60 (padding haut) + 136 (titre)
   + 60 (gap) + 1199,5 (grille) + 145 (padding bas) = 1600,5 = hauteur de
   section mesurée. La cible du plan (1601) est donc bien atteinte.

   Structure de section (identique aux trois paliers) : colonne centrée
   [intro] — gap — [grille].
     1440 : padding 60px 40px 145px, gap 60 ; intro large de 800 ; grille
            2 × 665, gouttières 30 (colonnes) / 40 (rangées) ; h 1600,5
     1024 : mêmes paddings et gap ; intro large de 600 ; grille 2 × 462,
            gouttières 20 / 40 ; h 1304
     390  : padding 30px 20px 70px, gap 40 ; intro pleine largeur ; grille
            à UNE colonne (la source garde deux pistes mais chaque carte
            occupe les deux), gouttière 40 ; h 1947,5

   Carte : colonne, gap 5, sans fond ni rayon propre — `.card` (layout.css)
   n'est donc PAS utilisée (règle A1#0).
     média  ratio 4/3 EXACTEMENT aux trois paliers (665 × 498,8 · 462 × 346,5
            · 350 × 262,5), rayon 40, `overflow: hidden`
     pied   1440 : ligne, gap 30, `align-items: center`, padding-haut 8,
                   hauteur 76 (= 8 + 68, imposée par le bouton)
            1024 et 390 : COLONNE, gap 0, alignée à gauche, hauteur 96
                   (= 8 + 28 de titre + 60 de bouton)

   ⚠ Le brief annonçait « images en border-radius: 0, parent en overflow
   visible ». C'est faux : c'est l'`<img>` lui-même qui est à 0, mais son
   conteneur porte `border-radius: 40px; overflow: hidden` (style en ligne
   `border-radius: 40px` sur `.framer-13pj6d5`, `overflow` calculé `hidden`),
   et les coins arrondis sont nettement visibles sur la capture de la source.

   Typographie relevée :
     titre h2   Climate Crisis 400 — 68/68 (1440) · 52/52 (1024) ·
                42/42 ls -1,6px (390), couleur --c-ink, centré
     titre h3   Climate Crisis 400 — 22/30,8 (1440) · 20/28 (1024 et 390)
     sticker    Poppins 600 — 20/26 ls -0,8 · 16/20,8 ls -0,64 · 15/19,5 ls -0,6
     bouton     Oswald 600 22/19,8 ls -0,88px aux TROIS paliers (la taille ne
                bouge pas ; seuls les paddings de la pastille changent)

   Deux manques du brief (A0), tous deux relevés puis reconstruits ici :
     — le bord festonné de haut de section (15 bosses 96 × 75,6 remontées de
       61px, en --c-orange-deep sur l'olive de #benefits) : la primitive
       partagée `.scallop-top` (layout.css) convient telle quelle, seuls les
       tokens --scallop-* de tokens.css la pilotent, et ils correspondent
       exactement aux trois paliers mesurés ici (96/75,6/61 · 68,27/53,76/40 ·
       26/20,47/20) ;
     — la pastille crème derrière chaque logo client : 109 × 55, padding
       7px 14px, rayon 16, fond --c-cream, en absolu à 17 / 21 du coin haut
       gauche de l'image, aux trois paliers (elle ne change pas de taille).

   Le sticker « Portfolio » n'est PAS `.sticker` (règle A1#0) : la source pose
   un tracé SVG unique (viewBox 0 0 157 105, un seul `path`, fill relevé à
   199 202 255, soit --c-lavender) dans une boîte pivotée de -20°, le libellé
   par-dessus. Le SVG est inliné dans le markup, comme les mascottes de la
   tâche 6. Géométrie déduite des AABB mesurées en dépivotant de 20° :
     boîte  137,05 × 86,0 (1440) · 121,7 × 80,75 (1024) · 117,8 × 79,5 (390)
     — soit EXACTEMENT le libellé + 30px de padding sur les quatre côtés aux
     trois paliers. La boîte n'est donc pas dimensionnée en dur ici : elle est
     laissée au contenu, ce qui garantit aussi que le libellé y entre
     (règle A1#3).
     SVG    largeur = 100% de la boîte, hauteur = largeur × 105/157, centré ;
     il déborde volontairement en hauteur (91,7 pour une boîte de 86) et le
     `overflow` de la boîte reste visible, comme sur la source.
   Position : centre du sticker à 3% / 91% de la boîte du titre (vérifié
   identique à 1440 et à 1024 : 24/800 = 18/600 = 3% ; 123,75/136 =
   94,65/104 = 91,0%). À 390 il repasse EN FLUX, centré, collé au-dessus du
   titre — même bascule qu'en `benefits.css`. */

.projects {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 60px;
  padding: 60px 40px 145px;
  background: var(--c-orange-deep);

  /* Bord festonné du haut : primitive `.scallop-top` (layout.css), portée par
     la section dans le markup. La section ne doit donc pas passer en
     overflow: hidden/clip, sous peine de rogner son propre feston. */
  --scallop-color: var(--c-orange-deep);
}

/* ---------- Intro (sticker + titre) ----------
   Même largeur que le conteneur de titre de la source (800px), pour que la
   position du sticker, exprimée en pourcentage de cette boîte, se transpose
   telle quelle. */
.projects__intro {
  position: relative;
  width: 800px;
}

.projects__heading {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--fs-68);
  line-height: 1;
  color: var(--c-ink);
  text-align: center;
  /* Relevé sur la source (`text-wrap: balance` calculé sur le h1). Sans lui,
     la coupe gloutonne donne à 390px « Regardez / ce qu'on a / fait ! » là où
     la source équilibre en « Regardez / ce qu'on / a fait ! ». Sans effet aux
     deux autres paliers, où le titre tient en deux lignes identiques. */
  text-wrap: balance;
}

/* Le sticker est dimensionné par son contenu (libellé + 30px de padding),
   pas par une largeur codée : c'est ce que fait la source, et c'est la seule
   façon de garantir que le libellé tient dans la forme (règle A1#3). */
.projects__sticker {
  position: absolute;
  left: 3%;
  top: 91%;
  display: inline-grid;
  place-items: center;
  padding: 30px;
  transform: translate(-50%, -50%) rotate(-20deg);
}

.projects__sticker-shape {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 100%;
  height: auto;
  aspect-ratio: 157 / 105;
  transform: translate(-50%, -50%);
  fill: var(--c-lavender);
  pointer-events: none;
}

.projects__sticker-label {
  position: relative;
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: var(--fs-20);
  line-height: 26px;
  letter-spacing: -0.8px;
  color: var(--c-ink);
  white-space: nowrap;
}

/* ---------- Grille 2 × 2 ---------- */
.projects__grid {
  width: 100%;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  column-gap: 30px;
  row-gap: 40px;
}

.projects__card {
  display: flex;
  flex-direction: column;
  gap: 5px;
}

/* ---------- Média ----------
   Rapport 4/3 mesuré identique aux trois paliers ; le rayon et le
   `overflow: hidden` sont portés par le conteneur, pas par l'image. */
.projects__media {
  position: relative;
  aspect-ratio: 4 / 3;
  border-radius: 40px;
  overflow: hidden;
}

.projects__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Zoom au survol de la carte : mesuré sur la source (la boîte de l'image
     passe de 665 × 498,8 à 731,5 × 548,6, soit exactement ×1,1, et reste
     rognée par le conteneur).
     ⚠ DURÉE CORRIGÉE le 2026-08-13 : 320ms, soit trois fois trop rapide. Relevé
     image par image sur la source, curseur amené d'un point neutre : le
     mouvement démarre à t=101ms (latence de son gestionnaire de pointeur, pas
     un délai CSS — non reproduite, la nôtre part tout de suite) et se termine à
     t=1062, soit ~960ms de course. Profil et courbe : voir --dur-zoom et
     --ease-expo dans tokens.css. Vérifié après correction, en temps propre
     d'animation : 64 % à +200ms contre 69 % sur la source, 96 % à +600 contre 96.
     ⚠ Ce zoom avait été déclaré ABSENT de la source par la passe du 2026-08-13
     au matin. C'était faux, et c'est le piège A₁.10 en action : la mesure
     comparait deux états survolés, le curseur étant resté sur la carte depuis
     un test précédent — sur la source l'état de survol PERSISTE sans mouseout.
     D'où la reprise ici, curseur ramené hors zone et attente avant relevé. */
  transition: transform var(--dur-zoom) var(--ease-out);
  /* Déclaration séparée : un navigateur sans `linear()` ignore cette ligne et
     garde --ease-out, soit le même zoom avec une courbe un peu plus vive. */
  transition-timing-function: var(--ease-expo);
}

.projects__card:hover .projects__img { transform: scale(1.1); }

/* Pastille crème derrière le logo client — manque du brief (A0). Dimensions
   constantes aux trois paliers. */
.projects__logo {
  position: absolute;
  left: 17px;
  top: 21px;
  display: block;
  padding: 7px 14px;
  background: var(--c-cream);
  border-radius: var(--r-md);
}

.projects__logo img {
  width: 81px;
  height: 41px;
  object-fit: contain;
}

/* ---------- Pied de carte ---------- */
.projects__foot {
  display: flex;
  align-items: center;
  gap: 30px;
  padding-top: 8px;
}

.projects__title {
  flex: 1;
  padding-left: 2px;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--fs-22);
  line-height: 30.8px;
  color: var(--c-ink);
  /* Relevé sur la source (calculé `balance` sur les h3 aussi) : c'est ce qui
     coupe « SpeedShip / Logistics Branding » plutôt que « SpeedShip Logistics /
     Branding ». */
  text-wrap: balance;
}

/* ---------- Bouton « View Case Study » ----------
   Ce n'est PAS un lien : la source ne contient aucune balise <a> dans la
   section (`#projects a` → 0 élément). C'est un <button> inerte, sans cible.

   `.btn` (layout.css) n'est pas réutilisée : même taille et même
   interlettrage, mais la source est ici en Oswald (et non en Poppins), et
   surtout la forme diffère entièrement — `.btn` est une pastille pleine à
   rayon 999px avec ombre dure décalée en x et y ; celle-ci est une pastille
   à rayon 18px posée dans une boîte à rayon 25px dont seul le BORD BAS de
   12px est peint (relevé : `--border-bottom-width: 12px`, couleur de bord
   59 0 27 soit --c-ink, rendu par un `::after` en inset 0). Étendre
   `.btn` par modificateur aurait demandé d'annuler presque toutes ses
   déclarations ; `.btn` n'est donc pas touchée (tous les CTA du site en
   héritent).

   Géométrie : boîte 197,5 × 68, padding-bas 9, pastille 197,5 × 49,8 alignée
   en bas → le liseré sombre reste visible sur 9px. Largeur non codée : elle
   vient du libellé + 34px de padding de chaque côté (129,5 + 68 = 197,5). */
.projects__btn {
  position: relative;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  height: 68px;
  padding-bottom: 9px;
  border-radius: 25px;
  transition: padding-bottom var(--dur-fast) var(--ease-out);
}

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

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

/* Enfoncement au survol : le padding-bas passe de 9 à 4 (mesuré sur la
   source), la pastille descend donc de 5px et le liseré se réduit d'autant.
   Uniquement à ce palier : à 1024 le survol ne change RIEN sur la source
   (padding-bas relevé à 6 avec et sans survol) — voir le palier tablette. */
.projects__btn:hover,
.projects__btn:focus-visible { padding-bottom: 4px; }

@media (prefers-reduced-motion: reduce) {
  .projects__img,
  .projects__btn { transition: none; }
  .projects__card:hover .projects__img { transform: none; }

  /* Carte d'invitation : ni zoom de la mascotte, ni rotation de l'étoile. La
     carte reste identique au survol, comme les trois autres. */
  .projects__invite-mascot,
  .projects__invite::before { transition: none; }

  .projects__card:hover .projects__invite-mascot,
  .projects__card:focus-within .projects__invite-mascot { transform: none; }

  .projects__card:hover .projects__invite::before,
  .projects__card:focus-within .projects__invite::before {
    transform: translate(-50%, -50%);
  }
}

@media (max-width: 1199px) {
  .projects__intro { width: 600px; }

  .projects__heading { font-size: var(--fs-52); }

  .projects__sticker-label {
    font-size: var(--fs-16);
    line-height: 20.8px;
    letter-spacing: -0.64px;
  }

  .projects__grid { column-gap: 20px; }

  /* Le pied passe en colonne, aligné à gauche, sans gap : hauteur 96 =
     8 (padding) + 28 (titre) + 60 (bouton). */
  .projects__foot {
    flex-direction: column;
    align-items: flex-start;
    gap: 0;
  }

  .projects__title {
    flex: none;
    align-self: stretch;
    font-size: var(--fs-20);
    line-height: 28px;
  }

  .projects__btn {
    height: 60px;
    padding-bottom: 6px;
  }

  /* Pas d'enfoncement au survol à ce palier : relevé sur la source, le
     padding-bas reste à 6px pendant le survol. */
  .projects__btn:hover,
  .projects__btn:focus-visible { padding-bottom: 6px; }

  /* Pas de zoom au survol non plus — la source coupe les DEUX interactions sous
     1200px. Relevé sur la source à 1024 : le conteneur d'image reste à
     462 × 346,5 et `transform: none` pendant le survol, lu à 200, 700 et
     1500 ms. Constat de la revue de la tâche 10, re-vérifié par le contrôleur. */
  .projects__card:hover .projects__img { transform: none; }

  .projects__btn-face { padding: 12px 24px; }
}

@media (max-width: 809px) {
  .projects {
    gap: 40px;
    padding: 30px 20px 70px;
  }

  .projects__intro { width: 100%; }

  /* Le sticker repasse EN FLUX, centré, collé au-dessus du titre (mesuré :
     l'intro y fait 205,5 = 79,5 de sticker + 126 de titre, sans espace).
     Le centrage passe par des marges automatiques et non par un `transform`,
     qui porte déjà la rotation. */
  .projects__sticker {
    position: static;
    display: grid;
    width: max-content;
    margin-inline: auto;
    transform: rotate(-20deg);
  }

  .projects__sticker-label {
    font-size: var(--fs-15);
    line-height: 19.5px;
    letter-spacing: -0.6px;
  }

  .projects__heading {
    font-size: var(--fs-42);
    letter-spacing: -1.6px;
  }

  /* Une seule colonne. La source garde deux pistes de grille mais fait
     couvrir les deux à chaque carte : le résultat rendu est identique. */
  .projects__grid {
    grid-template-columns: 1fr;
    row-gap: 40px;
  }
}

/* ============================================================
   POP-UP D'ÉTUDE DE CAS
   ============================================================
   Ouverte au clic sur l'image d'une carte ou sur son bouton. Structure et
   géométrie relevées sur la source le 2026-08-13, à 1440 :

     voile        noir à 80 % d'opacité sur toute la fenêtre (token --c-scrim)
     panneau      fixe, 1296 × 780, à 72px des bords et 80px du haut
     carte        rayon 30, `overflow: hidden`, fond --c-cream
     fermeture    42 × 42, rayon 11, fond --c-sand, à 30px du bord droit et
                  15px du haut
     contenu      encarts d'images à 20px des bords du panneau ; titre en
                  Climate Crisis 68/68 centré sur 800 ; pastilles de service
                  Poppins 15, padding 4px 10px, rayon 10, écart 10, dans
                  l'ordre --c-sand, --c-lavender, --c-yellow, --c-pink-light ;
                  bloc méta sur 4 colonnes de 228 ; texte Poppins 20 sur 1000 ;
                  grille d'images 2 × 623 × 467, écart 10 ; sous-titre
                  Climate Crisis 37.

   ⚠ Trois écarts assumés, décidés avec le propriétaire :
   1. Le bloc VIDÉO de la source est retiré : il charge une vidéo YouTube,
      ce que la règle « zéro requête sortante » du chantier interdit.
   2. Le contenu est du remplissage (voir le commentaire dans `index.html`) :
      les quatre pop-ups de la source sont des études de cas du gabarit, en
      anglais, dont deux ne correspondent même pas à leur carte (« Les Moulins
      bleus » y ouvre « Bold Brew Coffee Co. »). Seule la structure est reprise.
   3. Les marges du panneau aux paliers tablette et mobile ne sont PAS
      relevées : le contenu diffère de la source, la mesure n'aurait rien
      cadré de comparable. Valeurs choisies pour garder les mêmes proportions.

   L'élément est un <dialog> natif : la touche Échap, le piège de focus, le
   fond inerte et la restitution du focus au bouton d'origine sont gérés par le
   navigateur. Même parti pris que le menu en <details> — le natif d'abord. */
.case {
  width: auto;
  max-width: none;
  max-height: none;
  margin: 0;
  padding: 0;
  border: 0;
  background: transparent;
  overflow: visible;
  inset: 80px 72px 40px;
  /* ⚠ Indispensable. La feuille du navigateur pose `height: fit-content` sur
     <dialog> : sans cette ligne, la boîte se dimensionne sur son contenu et le
     `bottom` de l'inset est ignoré — mesuré à 3083px de haut au lieu de 780,
     la carte débordant très largement sous la fenêtre. Avec `height: auto`,
     `top` et `bottom` étirent la boîte, et le contenu défile à l'intérieur. */
  height: auto;
}

.case::backdrop {
  background: var(--c-scrim);
}

.case__card {
  position: relative;
  height: 100%;
  border-radius: 30px;
  overflow: hidden;
  background: var(--c-cream);
}

.case__close {
  position: absolute;
  right: 30px;
  top: 15px;
  z-index: 2;
  width: 42px;
  height: 42px;
  display: grid;
  place-items: center;
  padding: 0;
  border: 0;
  border-radius: 11px;
  background: var(--c-sand);
  color: var(--c-ink);
  cursor: pointer;
}

.case__close svg { width: 26px; height: 26px; }

/* La colonne de contenu défile dans la carte, pas la page derrière. */
.case__scroll {
  height: 100%;
  overflow-y: auto;
  padding: 40px 20px 60px;
  text-align: center;
}

.case__title {
  max-width: 800px;
  margin: 0 auto;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--fs-68);
  line-height: 1;
  color: var(--c-ink);
  text-wrap: balance;
}

.case__tags {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 10px;
  margin: 21px 0 0;
  padding: 0;
  list-style: none;
}

.case__tag {
  padding: 4px 10px;
  border-radius: 10px;
  font-family: var(--font-sans);
  font-weight: 500;
  font-size: var(--fs-15);
  line-height: 23px;
  color: var(--c-ink);
}

.case__tag--sand     { background: var(--c-sand); }
.case__tag--lavender { background: var(--c-lavender); }
.case__tag--yellow   { background: var(--c-yellow); }
.case__tag--pink     { background: var(--c-pink-light); }

.case__cover {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  margin-block-start: 40px;
  border-radius: 30px;
}

/* Quatre colonnes égales, libellé au-dessus de la valeur — relevé : colonnes
   de 228 à 220, 478, 735 et 993, soit un écart constant de 29. */
.case__meta {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 29px;
  max-width: 1000px;
  margin: 50px auto 0;
  padding: 0 128px;
  text-align: start;
}

.case__meta dt {
  font-family: var(--font-sans);
  font-weight: 500;
  font-size: var(--fs-12);
  line-height: 17px;
  color: var(--c-ink);
}

.case__meta dd {
  margin: 5px 0 0;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--fs-22);
  line-height: 31px;
  color: var(--c-ink);
}

.case__text {
  max-width: 1000px;
  margin: 45px auto 0;
  font-family: var(--font-sans);
  font-weight: 500;
  font-size: var(--fs-20);
  line-height: 28px;
  color: var(--c-ink);
  text-align: start;
}

.case__grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 10px;
  margin-block-start: 45px;
}

.case__shot {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: 30px;
}

/* Aligné sur la colonne de texte (2026-08-14). Le sous-titre était pleine
   largeur et centré, alors que le texte et les listes tiennent dans 1000px
   alignés à gauche : les titres de section flottaient au-dessus de leur propre
   contenu. Le site modèle les aligne à gauche, comme le reste. */
.case__subtitle {
  max-width: 1000px;
  margin: 60px auto 0;
  text-align: start;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--fs-37);
  line-height: 49px;
  color: var(--c-ink);
}

/* Deuxième paragraphe et suivants. Le gabarit n'en prévoyait qu'un : la marge
   de 45px ci-dessus sépare le texte des étiquettes au-dessus, elle est bien trop
   large entre deux paragraphes d'un même bloc. Posé le 2026-08-14, quand la fiche
   « Les Moulins Bleus » est passée à deux paragraphes (contexte, puis résultats). */
.case__text + .case__text { margin-top: 20px; }

/* ---------- Blocs de récit d'une étude de cas (2026-08-14) ----------
   Repris de la structure du site modèle : « Le défi », « Notre approche »,
   « Ce que nous avons fait », « Les résultats », « Le mot du client ». Tous
   partagent la colonne de 1000px et l'alignement à gauche du reste de la fiche. */

/* Liste numérotée, pour les points d'une approche. */
.case__steps {
  max-width: 1000px;
  margin: 20px auto 0;
  padding-inline-start: 28px;
  list-style: decimal;   /* base.css l'avait retiré */
  text-align: start;
  font-family: var(--font-sans);
  font-weight: 500;
  font-size: var(--fs-18);
  line-height: 25px;
  color: var(--c-ink);
}

/* Liste à puces de premier niveau, pour les résultats. */
.case__points {
  max-width: 1000px;
  margin: 20px auto 0;
  padding-inline-start: 24px;
  list-style: disc;      /* base.css l'avait retiré */
  text-align: start;
  font-family: var(--font-sans);
  font-weight: 500;
  font-size: var(--fs-18);
  line-height: 25px;
  color: var(--c-ink);
}

.case__steps li + li,
.case__points li + li { margin-top: 10px; }

/* Le mot du client. L'italique est celui de la citation, pas une emphase :
   Poppins 500 italique est chargé, il n'y a donc pas de faux italique. */
.case__quote {
  max-width: 1000px;
  margin: 20px auto 0;
  text-align: start;
  font-family: var(--font-sans);
  font-weight: 500;
  font-style: italic;
  font-size: var(--fs-20);
  line-height: 28px;
  color: var(--c-ink);
}

.case__quote-author {
  display: block;
  margin-top: 10px;
  font-style: normal;
  font-weight: 600;
  font-size: var(--fs-18);
  line-height: 25px;
}

/* L'émoji d'un titre de section est décoratif : `aria-hidden` dans le markup
   l'écarte des lecteurs d'écran, qui annonceraient sinon « ampoule » avant le
   titre. Ici on lui donne seulement son espacement. */
.case__subtitle-emoji { margin-inline-end: 12px; }

.case__lead {
  max-width: 1000px;
  margin: 12px auto 0;
  font-family: var(--font-sans);
  font-weight: 500;
  font-size: var(--fs-18);
  line-height: 25px;
  color: var(--c-ink);
  text-align: start;
}

.case__services {
  max-width: 1000px;
  margin: 25px auto 0;
  padding: 0;
  list-style: none;
  text-align: start;
}

.case__service + .case__service { margin-block-start: 25px; }

/* ⚠ Déclaré APRÈS `.case__services`, et pas avant : les deux sélecteurs ont la
   même spécificité, c'est donc le dernier écrit qui gagne. Posé plus haut dans
   le fichier, ce `list-style: decimal` était annulé par le `list-style: none`
   de `.case__services`, et la liste sortait sans numéros.
   Modificateur plutôt que changement de `.case__services` : les deux autres
   fiches gardent leur liste sans numéros tant qu'elles ne sont pas réécrites. */
.case__services--numbered {
  padding-inline-start: 28px;
  list-style: decimal;
}

.case__services--numbered .case__service + .case__service { margin-block-start: 14px; }

.case__service-title {
  margin: 0;
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: var(--fs-18);
  line-height: 25px;
  color: var(--c-ink);
}

.case__service-list {
  margin: 0;
  padding-inline-start: 35px;
  /* base.css pose `list-style: none` sur tous les ul/ol : on redemande les
     puces ici, comme le site modèle les affiche. */
  list-style: disc;
  font-family: var(--font-sans);
  font-weight: 500;
  font-size: var(--fs-18);
  line-height: 25px;
  color: var(--c-ink);
}

/* L'image d'une carte ouvre la pop-up : le curseur doit le dire. Le clavier
   passe, lui, par le bouton « Voir l'étude de cas » — l'image n'est pas un
   second arrêt de tabulation pour la même action. */
.projects__media { cursor: pointer; }

/* ---------- Quatrième carte : l'invitation ----------
   Ajoutée le 2026-08-14 à la demande du propriétaire, en remplacement d'une
   étude de cas de remplissage. Rien ici ne vient de la source : c'est une
   carte à nous, et elle est signalée comme telle dans le README.

   Le parti pris est de NE PAS inventer une carte à part. Elle reprend le
   squelette exact des trois autres — média 4/3 arrondi à 40, pastille de logo
   au même endroit, pied titre + bouton — et n'en change qu'une chose : la
   pastille qui porte le logo d'un client sur les autres cartes est ici vide et
   attend le vôtre. C'est ce vide, pas un décor ajouté, qui porte le message.

   Le reste est tenu volontairement silencieux : un aplat jaune et la mascotte
   du site en filigrane. Aucune animation propre — la carte n'a pas d'image, le
   zoom au survol des trois autres ne la concerne donc pas, et le seul mouvement
   reste celui du bouton, commun à toute la section. */
.projects__invite {
  display: grid;
  place-items: end center;
  background: var(--c-yellow);
  /* Écrase le `cursor: pointer` ci-dessus : ici rien n'est cliquable dans le
     média, l'action est le bouton du pied. */
  cursor: default;
}

/* La mascotte « toast » du site, en filigrane. C'est le fichier de #studio
   (`6PqPWAQp…svg`, celle au pinceau), employé en `mask-image` comme l'étoile du
   bandeau de logos : le fichier est peint en blanc, un masque le rend
   recolorable par la feuille de style, sans copier un tracé de plus dans
   index.html ni écrire une couleur en dur.
   Elle monte du bas et le média la rogne (`overflow: hidden` sur
   `.projects__media`) : le personnage entre dans le cadre plutôt que d'y être
   posé, ce qui laisse la pastille vide seule au premier plan. */
.projects__invite-mascot {
  position: relative;   /* passe devant l'étoile */
  z-index: 1;
  width: 52%;
  aspect-ratio: 219 / 200;
  background: var(--c-ink);
  mask: url(../../assets/svg/6PqPWAQpDC12qlwCTboiTOQwbUg.svg) bottom center / contain no-repeat;
  -webkit-mask: url(../../assets/svg/6PqPWAQpDC12qlwCTboiTOQwbUg.svg) bottom center / contain no-repeat;
  /* Le zoom au survol est celui des TROIS AUTRES CARTES : mêmes durée et courbe
     que `.projects__img` (--dur-zoom / --ease-expo, relevés sur la source). La
     carte d'invitation réagit donc comme ses voisines, au même rythme.
     `transform-origin` en bas : la mascotte est posée sur le bord bas du cadre,
     elle doit grandir vers le haut et non s'enfoncer. */
  transform-origin: bottom center;
  transition: transform var(--dur-zoom) var(--ease-out);
  transition-timing-function: var(--ease-expo);
}

/* L'étoile derrière la mascotte, reprise de l'illustration du Process.
   ⚠ Ce n'est PAS le même tracé que le halo du Process : celui-là compte 42
   pointes et n'existe qu'en `data:` dans process.css. Ici on emploie le fichier
   `Bf3S7lr…svg` (21 pointes, déjà dans assets/svg/, déjà employé pour l'étoile
   du bandeau de logos) plutôt que de recopier une troisième fois un tracé de
   2,6 ko — le README signale déjà 86 tracés pour 36 formes distinctes.

   Couleur : --c-cream, plus CLAIRE que le jaune du cadre. C'est ce qui fait
   ressortir la mascotte en prune, alors qu'une couleur soutenue l'aurait noyée. */
.projects__invite::before {
  content: "";
  position: absolute;
  left: 50%;
  /* 74 % de large et centrée : à 1440 l'étoile mesure alors 492 × 490 dans un
     cadre de 665 × 499 et tient tout entière (y 4 à 495), pointes comprises.
     Plus bas ou plus grande, elle se ferait trancher net par le bord du cadre —
     calculé, pas ajusté à l'œil. */
  top: 50%;
  width: 74%;
  aspect-ratio: 473 / 471;
  background: var(--c-cream);
  mask: url(../../assets/svg/Bf3S7lrMf4RLc0FEbNVgXCJTvI.svg) center / 100% 100% no-repeat;
  -webkit-mask: url(../../assets/svg/Bf3S7lrMf4RLc0FEbNVgXCJTvI.svg) center / 100% 100% no-repeat;
  /* La rotation est dans `transform`, APRÈS la translation de centrage, et non
     dans la propriété `rotate` : CSS applique `rotate` après `transform`, donc
     autour du centre d'origine de la boîte — l'étoile décentrée de -50 %
     partirait en orbite au lieu de tourner sur place. Même piège et même parade
     que le halo du Process. */
  transform: translate(-50%, -50%) rotate(0deg);
  transition: transform var(--dur-halo) var(--ease-out);
  /* Déclaration séparée : un navigateur sans `linear()` l'ignore et garde
     --ease-out, ce qui donne la rotation sans le petit recul. */
  transition-timing-function: var(--ease-halo);
  pointer-events: none;
}

/* Un quart de tour, comme le halo du Process. L'étoile ayant 21 pointes, elle
   retombe presque sur elle-même tous les 17,14° : ce n'est donc pas la position
   d'arrivée qui se voit, c'est le MOUVEMENT pendant les 500ms — d'où un angle
   franc plutôt qu'un léger décalage, qui ne se lirait pas. */
.projects__card:hover .projects__invite::before,
.projects__card:focus-within .projects__invite::before {
  transform: translate(-50%, -50%) rotate(90deg);
}

.projects__card:hover .projects__invite-mascot,
.projects__card:focus-within .projects__invite-mascot {
  transform: scale(1.08);
}

/* La pastille vide. Mêmes position, taille et rayon que celles qui portent un
   logo client — c'est la comparaison qui fait sens, pas la pastille seule. Le
   trait discontinu dit « emplacement à pourvoir » sans un mot de plus. */
.projects__logo--empty {
  display: grid;
  place-items: center;
  width: 109px;
  height: 55px;
  padding: 0;
  border: 2px dashed var(--c-ink);
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: var(--fs-15);
  line-height: 19px;
  letter-spacing: -0.45px;
  text-align: center;
  color: var(--c-ink);
}

/* Le bouton est un <a> et non un <button> : il mène au formulaire de contact
   au lieu d'ouvrir une pop-up. Il garde la classe `.projects__btn`, donc la
   forme, l'ombre portée et l'enfoncement au survol des trois autres. */
.projects__btn--go { text-decoration: none; }

@media (max-width: 1199px) {
  .case { inset: 40px 32px 32px; }
  .case__scroll { padding: 32px 16px 48px; }
  .case__title { font-size: var(--fs-52); }
  .case__meta { padding: 0 40px; gap: 20px; }
  .case__subtitle { font-size: var(--fs-30); line-height: 40px; }
}

@media (max-width: 809px) {
  .case { inset: 20px 12px 12px; }
  .case__card { border-radius: 24px; }
  .case__scroll { padding: 24px 12px 40px; }
  .case__title { font-size: var(--fs-42); }
  .case__close { right: 16px; top: 12px; }
  .case__tags { gap: 6px; }
  .case__meta { grid-template-columns: repeat(2, 1fr); padding: 0; gap: 20px; }
  .case__grid { grid-template-columns: 1fr; }
  .case__cover, .case__shot { border-radius: 20px; }
  .case__subtitle { font-size: var(--fs-26); line-height: 34px; }
}
