/* ============================================================
   OTSHO — Base styles
   Brutalist-Noir / Frank Miller. Noir & blanc + accent ambre.
   ============================================================ */

:root {
  /* Palette ajustée (passe "Ajustement Palette Globale") :
     - Le noir pur devient un noir charbon mat très sombre (--noir),
       moins dur à l'œil sur de grandes surfaces tout en gardant
       l'ambiance très sombre du site.
     - Un gris légèrement plus clair (--gris-carte) sert de fond aux
       cartes/conteneurs pour créer un relief subtil sur --noir.
     - --text-primary est la SEULE source du blanc cassé de la Gazette
       (#F2EFE9) désormais utilisé pour l'ensemble des titres, textes,
       overlays de cartes (dont les titres style L.A. Noire) et éléments
       de navigation. --blanc et --blanc-pur restent définies en alias
       de --text-primary uniquement pour ne pas avoir à retoucher tous
       les usages existants dans ce fichier — toute nouvelle règle doit
       utiliser directement var(--text-primary). */
  --text-primary: #F2EFE9; /* blanc cassé Gazette — texte/titres/nav/overlays */
  --noir: #121214;         /* noir charbon mat très sombre — fond de page, hors Gazette */
  --blanc: var(--text-primary);     /* alias historique — cf. --text-primary */
  --blanc-pur: var(--text-primary); /* alias historique — cf. --text-primary */
  --gris-carte: #1A1A1E;  /* fond des cartes/conteneurs — relief subtil sur --noir */
  --gris-bordure: #333333; /* bordure fine des cartes au repos */
  --ambre: #FFC700;       /* ambre vif — hover / accents actifs */
  --ambre-dim: #D4A300;   /* ambre sourd — badges permanents (CASE #0X) */
  --papier: #EFEAE0;      /* fond "papier journal" — section Gazette uniquement */
  --encre: #171512;       /* encre — texte sur fond papier */

  /* Étape 23 — variables utilisées pour calculer l'espace vertical
     disponible entre le bas de la navbar et le haut de l'illustration
     de skyline (centrage exact du tagline du Hero, voir .hero__headline
     plus bas). --skyline-h reprend exactement la formule déjà utilisée
     par .hero__skyline (height:74vh / max-height:680px / min-height:
     340px, équivalent à clamp(340px, 74vh, 680px)) pour rester
     cohérente si l'une des deux règles est modifiée plus tard.
     --navbar-h est une estimation de la hauteur réelle de la navbar
     (~65.6px sur la plupart des largeurs, ~52.8px sous 420px via le
     resserrement de .navbar__inner) ; l'écart de quelques px entre les
     deux cas est imperceptible sur un centrage vertical à l'échelle du
     Hero, donc une seule valeur suffit ici. */
  --navbar-h: 4.25rem;
  --skyline-h: clamp(340px, 74vh, 680px);
}

/* Reset minimal — le site s'appuie sur Tailwind CDN pour son preflight
   habituel (box-sizing, etc.), mais celui-ci est chargé en externe et
   sera retiré au passage en build CLI (cf. commentaire dans index.html).
   On pose donc ici, en dur, les deux règles dont TOUT le responsive du
   site dépend, pour rester correct avec ou sans Tailwind. */
*,
*::before,
*::after {
  box-sizing: border-box;
}

img,
video {
  max-width: 100%;
  height: auto;
}

html {
  scroll-behavior: smooth;
}

body {
  margin: 0; /* Étape 46 : ajouté au même titre que box-sizing/img ci-dessus —
                sans lui, la marge par défaut du navigateur (8px) empêche un
                vrai bord-à-bord sur les éléments plein cadre tant que le
                preflight Tailwind n'a pas chargé. Toujours utile pour le
                Hero (plein cadre depuis l'Étape 28) même si la galerie,
                elle, n'est plus en Full Bleed depuis l'Étape 52. */
  overflow-x: hidden;
}

/* ------------------------------------------------------------
   Pluie (canvas)
   ------------------------------------------------------------ */
#rain-canvas {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 1;
  pointer-events: none;
  opacity: 0.55;
}

/* ------------------------------------------------------------
   Navbar
   ------------------------------------------------------------ */
.navbar {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 50;
  background: transparent;
  border-bottom: 1px solid transparent;
  transition: background-color .4s ease, border-color .4s ease, backdrop-filter .4s ease;
}

.navbar.is-scrolled {
  /* rgb(18,18,20) = var(--noir) #121214 — même gris charbon que le
     reste du site (plus de noir pur #000000 sur le header, Étape 18) */
  background: rgba(18, 18, 20, 0.85);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border-bottom: 1px solid rgba(242, 239, 233, 0.1);
}

.navbar__inner {
  position: relative; /* ancre .navbar__nav en centrage absolu (Étape 22) */
  max-width: 1400px;
  margin: 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 1.1rem 2rem;
}

.navbar__logo {
  font-family: 'Bebas Neue', sans-serif;
  font-size: 1.9rem;
  letter-spacing: 0.12em;
  color: var(--blanc);
  text-decoration: none;
  line-height: 1;
  transition: color .25s ease;
}
.navbar__logo:hover {
  color: var(--ambre);
}

.navbar__nav {
  display: flex;
  gap: 2.25rem;
  /* Étape 22 : recentrage précis au milieu du header (annule le collage
     à droite contre l'icône SOUND de l'Étape 20, qui créait une tension
     visuelle). Position absolute + left:50%/translateX(-50%) sort la
     nav du flux flex de .navbar__inner : le logo (gauche) et
     .navbar__right (droite) restent écartés par justify-content:
     space-between, pendant que la nav est centrée indépendamment sur
     la largeur totale du header, pas seulement sur l'espace restant. */
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
}

.navbar__link {
  position: relative;
  font-size: 0.72rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--text-primary);
  text-decoration: none;
  padding-bottom: 4px;
  transition: color .25s ease;
}
.navbar__link::after {
  content: '';
  position: absolute;
  left: 0;
  bottom: 0;
  width: 0%;
  height: 1px;
  background: var(--ambre);
  transition: width .3s ease;
}
.navbar__link:hover {
  color: var(--ambre);
}
.navbar__link:hover::after {
  width: 100%;
}

.navbar__right {
  display: flex;
  align-items: center;
  gap: 1.25rem;
}

/* Widget SOUND — bouton "icône seule" : une note de musique (SVG,
   fill="currentColor") qui EST le bouton, sans bordure/pill/fond.
   Blanc (comme le texte du site) au repos, ambre quand activé
   (.is-on, posée par main.js). La couleur est pilotée uniquement via
   `color`, donc currentColor sur le <path> suit automatiquement. */
.sound-toggle {
  display: flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: none;
  padding: 0.25rem;
  margin: 0;
  color: var(--blanc);
  cursor: pointer;
  line-height: 0;
  transition: color .25s ease, transform .2s ease;
}
.sound-toggle:hover {
  color: var(--ambre);
}
.sound-toggle.is-on {
  color: var(--ambre);
}
.sound-toggle__icon {
  width: 20px;
  height: 20px;
  display: block;
}

/* Burger (mobile) */
.navbar__burger {
  display: none;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: 28px;
  height: 22px;
  background: none;
  border: none;
  cursor: pointer;
  padding: 0;
}
.navbar__burger span {
  display: block;
  height: 2px;
  width: 100%;
  background: var(--blanc);
  transition: transform .3s ease, opacity .3s ease;
}
.navbar__burger[aria-expanded="true"] span:nth-child(1) {
  transform: translateY(7px) rotate(45deg);
}
.navbar__burger[aria-expanded="true"] span:nth-child(2) {
  opacity: 0;
}
.navbar__burger[aria-expanded="true"] span:nth-child(3) {
  transform: translateY(-7px) rotate(-45deg);
}

.navbar__mobile {
  display: none;
  flex-direction: column;
  /* rgb(18,18,20) = var(--noir) #121214 — cohérent avec .navbar.is-scrolled */
  background: rgba(18, 18, 20, 0.97);
  border-bottom: 1px solid rgba(242, 239, 233, 0.1);
  padding: 0.5rem 2rem 1.5rem;
}
.navbar__mobile.is-open {
  display: flex;
}
.navbar__mobile .navbar__link {
  padding: 0.85rem 0;
  border-bottom: 1px solid rgba(242, 239, 233, 0.08);
}

@media (max-width: 860px) {
  .navbar__nav {
    display: none;
  }
  .navbar__burger {
    display: flex;
  }
}

/* Très petits écrans (<= 420px, ex. iPhone SE) : navbar resserrée.
   Le widget SOUND est déjà une icône seule (pas de libellé texte à
   masquer) — aria-label (mis à jour en JS) porte l'information pour
   les lecteurs d'écran. */
@media (max-width: 420px) {
  .navbar__inner {
    padding: 0.9rem 1.1rem;
  }
  .navbar__logo {
    font-size: 1.5rem;
  }
  .navbar__right {
    gap: 0.6rem;
  }
}

/* ------------------------------------------------------------
   Hero
   Empilement (arrière → avant) : fond noir < .hero__skyline
   < #rain-canvas (pluie, z-index:1, cf. plus haut) < texte/scroll.
   .hero ne pose PAS son propre z-index : ça laisse le skyline
   (z-index:auto) passer sous la pluie, tout en gardant le texte
   (z-index:2, explicite) au-dessus. Voir le commentaire sur
   #rain-canvas plus haut dans ce fichier.
   ------------------------------------------------------------ */
.hero {
  position: relative;
  overflow: hidden;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;
  text-align: center;
  padding: 0 1.5rem;
  /* Fond uni gris charbon (var(--noir), #121214) — même couleur que le
     header et que le reste du site (plus aucun noir pur #000000 sur le
     Hero depuis l'Étape 18). Le PNG hero/skyline.png a lui-même été
     réexporté avec ce même fond #121214 : raccord exact entre l'image
     et le reste de la section, sans dégradé/halo. */
  background: var(--noir);
}

/* Illustration skyline — image raster fournie par l'utilisateur
   (images/hero/skyline.png, 3200x800, ratio 4:1 — voir règle ferme en
   tête de document). object-fit cover + object-position bottom : recadre
   sur les côtés si besoin (jamais en hauteur, grâce au ratio 4:1),
   toujours ancrée en bas, jamais étirée. */
.hero__skyline {
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: var(--skyline-h); /* clamp(340px, 74vh, 680px) — voir :root, Étape 23 */
  display: block;
  object-fit: cover;
  object-position: center bottom;
  pointer-events: none;
  /* pas de z-index explicite : reste sous #rain-canvas (z-index:1) */
}

/* Headline jaune au-dessus de la ville — occupe l'espace libéré entre
   la navbar et le haut de l'illustration (.hero__skyline est ancrée en
   bas : le haut du Hero reste donc libre). Position absolute + centrage
   horizontal, indépendant du flex de .hero (qui ne régit désormais que
   .hero__scroll, ancré en bas — .hero__content a été retiré à l'Étape
   20). z-index:2 pour rester au-dessus de la pluie (#rain-canvas,
   z-index:1).
   Étape 23 — centrage vertical exact demandé ("à mi-chemin entre le
   header et le haut des immeubles") : `top` part du bas de la navbar
   (var(--navbar-h)) et `height` couvre exactement l'espace restant
   jusqu'au haut de l'illustration (calc(100vh - navbar - skyline), les
   deux valeurs reprenant celles réellement utilisées par la navbar et
   par .hero__skyline — voir :root). Un flex interne
   (display:flex; justify-content:center) centre alors le texte
   verticalement au milieu de cette zone, quelle que soit la hauteur
   d'écran — remplace l'ancien `top: clamp(5rem, 13vh, 8rem)` qui
   plaçait le bloc à une distance fixe du haut sans tenir compte de la
   position réelle du haut des immeubles. `max-width` (Étape 20) laisse
   la tagline se répartir naturellement sur 2 lignes sans forcer de
   <br> (le point de césure s'ajuste tout seul largeur par largeur —
   vérifié à 2 lignes maximum sur les 14 largeurs de référence). */
.hero__headline {
  position: absolute;
  top: var(--navbar-h);
  left: 50%;
  transform: translateX(-50%);
  z-index: 2;
  width: 100%;
  max-width: min(92vw, 80rem);
  height: calc(100vh - var(--navbar-h) - var(--skyline-h));
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 0 1.5rem;
  text-align: center;
  pointer-events: none;
}
/* Étape 23 — Typo plus incisive/éditoriale : Space Grotesk (sans-serif
   géométrique, chargée en 500/700 — voir index.html) remplace
   JetBrains Mono (Étape 22). letter-spacing resserré à 0.1em (valeur
   demandée, remplace 0.12em) — toujours aéré, mais un peu plus dense
   pour ce dessin de lettres proportionnel (vs. la chasse fixe du mono).
   Étape 47 — remplacée par Limelight (demande explicite). Limelight est
   une police d'affichage à graisse unique (une seule variante chargée,
   400 — voir index.html/case.html) : `font-weight:700` est retiré, un
   700 forcé sur une police sans graisse grasse réelle ne ferait que
   déclencher un gras synthétique du navigateur, peu fiable visuellement
   d'un navigateur à l'autre.
   Étape 48 — letter-spacing élargi de 0.1em à 0.14em (demande explicite,
   "très léger letter-spacing ... pour renforcer le côté cinématographique
   et haut de gamme" — 0.1em correspondait déjà au tracking le plus large
   de l'échelle Tailwind usuelle, 0.14em va légèrement au-delà). S'applique
   aux deux formats (mobile et desktop), cette règle étant commune aux
   deux — seule la taille desktop est modifiée séparément plus bas (voir
   Étape 48 sous la media query ≥769px ci-dessous, demande explicitement
   scopée "sur desktop"). */
.hero__headline p {
  font-family: 'Limelight', sans-serif;
  line-height: 1.3;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  text-align: center;
  color: var(--ambre); /* jaune de la charte — #FFC700 */
  text-shadow: 0 0 20px rgba(255, 199, 0, 0.25);
  overflow-wrap: break-word;
}

/* Segments de la tagline (voir index.html) : par défaut (mobile-first,
   <= 768px) chacun est sur sa propre ligne → 3 lignes fixes :
   "UNCOVERING" / "BRAND IDENTITIES" / "FROM THE DARK".
   Taille demandée : fixée à 1.75rem/28px. Vérifié à l'écran (méthode
   Étape 20 : boundary-search Playwright sur les 14 largeurs de
   référence, comptage de lignes réelles via Range.getClientRects()) :
   28px tient bien sur 3 lignes à partir de ~410px de large (tous les
   téléphones courants : 414 à 768px), MAIS casse sur 4 lignes en
   dessous (280-390px, ex. iPhone SE 375px) — "brand identities" et
   "from the dark" ne rentrent plus sur leur propre ligne à 28px sous
   ~410px. Écart minimal documenté : un clamp() remplace la valeur
   fixe, calé pour valoir exactement 28px dès ~410px (donc "fixe" sur
   la quasi-totalité de la plage mobile réelle) et ne redescend que
   sur les très petits écrans, où il reste la plus grande taille
   possible garantissant toujours 3 lignes. */
.hero__headline-seg {
  display: block;
}
.hero__headline p {
  font-size: clamp(1rem, calc(-9.85px + 9.231vw), 1.75rem);
}

/* Desktop (> 768px) : les segments 1 et 2 repassent en inline, donc
   l'espace du <span> source les rejoint naturellement sur une seule
   ligne ("UNCOVERING BRAND IDENTITIES") ; le segment 3 reste en
   display:block et retombe sur la 2e ligne ("FROM THE DARK") — 2
   lignes équilibrées, sans <br> forcé (cf. Étape 20 : un <br> forcé
   entre "identities" et "from" cassait la mise en page à cause du
   re-wrap interne).
   Taille demandée : "autour de 3rem à 3.5rem". Vérifié à l'écran
   (même méthode boundary-search) : en JetBrains Mono + letter-spacing
   0.12em, "UNCOVERING BRAND IDENTITIES" (27 caractères) ne tient sur
   une seule ligne à 3rem/48px qu'à partir de ~1150px de large — entre
   769px et ~1024px (petits laptops, fenêtres partagées, tablettes en
   paysage), 3rem fait déjà déborder sur une 3e ligne (mesuré : max
   ~2.1rem à 769px, ~2.9rem à 1024px). Écart minimal documenté : un
   clamp() progressif reste sous ce seuil sur toute la plage et
   atteint la fourchette demandée (3–3.5rem) dès ~1150-1280px, pour se
   stabiliser à 3.5rem (le plafond demandé) sur tous les écrans de
   bureau usuels (≥ 1391px, y compris 1440/1728/1920) — la contrainte
   "sur 2 lignes" (plus explicite et plus structurante dans la demande
   que la taille de police) est ainsi respectée sur toute la plage
   desktop, y compris les fenêtres étroites. */
@media (min-width: 769px) {
  .hero__headline-seg--1,
  .hero__headline-seg--2 {
    display: inline;
  }
  .hero__headline-seg--3 {
    display: block;
  }
  /* Étape 48 — taille augmentée sur desktop uniquement (demande explicite,
     "text-5xl/text-6xl" cité en référence) : plafond porté de 3.5rem à
     3.75rem (soit tout l'intervalle cité, calé sur le haut de la
     fourchette — l'équivalent Tailwind text-6xl). L'ensemble de la
     formule clamp() (plancher, pente/ordonnée de la partie fluide,
     plafond) est mis à l'échelle par le même facteur (×15/14 ≈ ×1,071)
     plutôt que de juste relever le plafond seul, pour préserver
     exactement la même courbe/les mêmes points de rupture que la version
     calibrée aux Étapes 20/22 (boundary-search Playwright, 2 lignes
     garanties sur toute la plage desktop) — seule l'échelle change, pas
     la forme. Réserve inchangée depuis l'Étape 47 (voir §7 du cadrage) :
     Limelight n'a pas pu être testée avec le vrai fichier de police dans
     cet environnement (Google Fonts y est bloqué) ; à revérifier par
     l'utilisateur sur le site réel, notamment autour de 769-1024px (zone
     historiquement la plus tendue). */
  .hero__headline p {
    font-size: clamp(2.04rem, calc(-2.38px + 4.55vw), 3.75rem);
  }
}

.hero__skyline-ground {
  fill: var(--noir);
}

.building__body {
  fill: var(--noir);
  stroke: var(--blanc);
  stroke-width: 1.6;
  vector-effect: non-scaling-stroke;
}

.building__spire {
  stroke: var(--blanc);
  stroke-width: 1.4;
  vector-effect: non-scaling-stroke;
}

.building__beacon {
  fill: var(--ambre);
}

.win {
  fill: none;
  stroke: rgba(242, 239, 233, 0.3);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
}

.win--lit {
  fill: rgba(242, 239, 233, 0.55);
  stroke: none;
}

/* Accent jaune/ambre — fenêtres "habitées" façon néon */
.win--amber {
  fill: var(--ambre);
  stroke: none;
}

/* Enseigne verticale HOTEL — accent néon ambre, léger scintillement */
.hero__neon-frame {
  fill: none;
  stroke: var(--ambre);
  stroke-width: 2;
  vector-effect: non-scaling-stroke;
}
.hero__neon-letter {
  font-family: 'Bebas Neue', sans-serif;
  font-size: 34px;
  letter-spacing: 0.02em;
  fill: var(--ambre);
}
.hero__neon {
  animation: neonFlicker 6s ease-in-out infinite;
}
@keyframes neonFlicker {
  0%, 89%, 92%, 100% { opacity: 1; }
  90%, 91% { opacity: 0.5; }
}

/* Scroll indicator : au-dessus de la pluie (z-index:2). L'accroche
   secondaire "Graphic design. Motion. Video. — ..." (.hero__content /
   .hero__tagline) a été retirée à l'Étape 20 (chevauchement avec
   l'enseigne HOTEL de l'illustration, jugée superflue par l'utilisateur
   une fois la nouvelle tagline en place) — .hero__scroll est donc
   maintenant le seul enfant du flex de .hero (justify-content:flex-end
   sur .hero l'ancre toujours en bas).
   Étape 23 : le cadre sombre flouté (fond + padding + border-radius,
   Étape 20) est retiré à la demande de l'utilisateur — le détachement
   par rapport aux fenêtres d'immeuble derrière se fait désormais par
   un halo sombre directement sur le texte (text-shadow) et sur le
   trait/flèche (filter: drop-shadow, car c'est un élément graphique,
   pas du texte — text-shadow n'aurait aucun effet dessus). */
.hero__scroll {
  position: relative;
  z-index: 2;
  margin-bottom: 1.75rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.6rem;
}
.hero__scroll span {
  width: 1px;
  height: 34px;
  background: linear-gradient(to bottom, var(--ambre), transparent);
  animation: scrollpulse 1.8s ease-in-out infinite;
  filter: drop-shadow(0px 0px 8px rgba(18, 18, 20, 1));
}
.hero__scroll p {
  font-family: 'JetBrains Mono', monospace;
  font-size: 0.65rem;
  letter-spacing: 0.3em;
  color: var(--ambre);
  text-shadow: 0 0 10px #121214, 0 0 20px #121214, 0 0 30px #121214;
}
@keyframes scrollpulse {
  0%, 100% { transform: scaleY(1); opacity: .6; }
  50% { transform: scaleY(0.6); opacity: 1; }
}

/* ------------------------------------------------------------
   Specialties (ex-"Modus Operandi", renommée à l'Étape 24 — voir le
   commentaire dans index.html) — 3 piliers de service, entre le Hero
   et Cases. Même langage visuel que Cases (fond noir pur, badge ambre
   discret), mais AUCUN effet de zoom/reveal : juste une légère lueur
   ambrée au survol du visuel. Photos réelles attendues dans
   images/modus/ (nom de dossier interne inchangé, voir index.html) —
   fallback CSS automatique tant qu'elles n'existent pas (cf. onerror).
   ------------------------------------------------------------ */
.specialties {
  position: relative;
  z-index: 2;
  background: var(--noir);
  color: var(--blanc);
  padding: 6rem 1.5rem 6.5rem;
}

.specialties__inner {
  max-width: 1400px;
  margin: 0 auto;
}

.specialties__header {
  margin-bottom: 3rem;
  border-bottom: 1px solid rgba(255, 255, 255, 0.14);
  padding-bottom: 2rem;
}

.specialties__eyebrow {
  display: block;
  font-family: 'JetBrains Mono', monospace;
  font-size: 0.75rem;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--ambre-dim);
  margin-bottom: 0.75rem;
}

.specialties__title {
  font-family: 'Bebas Neue', sans-serif;
  font-size: clamp(3rem, 8vw, 6rem);
  line-height: 0.9;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--blanc-pur);
  overflow-wrap: break-word;
}

.specialties__grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 3rem 2rem;
}

@media (max-width: 900px) {
  .specialties__grid {
    grid-template-columns: 1fr;
    gap: 3rem;
  }
}

.specialty-card {
  outline: none;
}

.specialty-card__visual {
  position: relative;
  overflow: hidden;
  aspect-ratio: 4 / 3;
  background: var(--gris-carte);
  border: 1px solid var(--gris-bordure);
  transition: border-color 0.4s ease, box-shadow 0.4s ease;
}

/* Lueur ambrée légère au survol/focus — PAS de scale(), juste une touche
   de couleur sur la bordure et un halo doux (contrairement à Cases,
   aucun agrandissement du visuel n'est souhaité ici). */
.specialty-card:hover .specialty-card__visual,
.specialty-card:focus-within .specialty-card__visual {
  border-color: var(--ambre);
  box-shadow: 0 0 28px rgba(255, 199, 0, 0.25);
}

/* Étape 31 (correctif) — le filtre grayscale(100%) contrast(140%) posé ici
   depuis l'Étape 12 désaturait les 3 photos Specialties en permanence.
   Demande explicite de l'utilisateur : garder ces images telles qu'envoyées
   (en couleur) — filtre retiré, aucun autre changement sur cette section
   (le halo ambré bordure/box-shadow au survol, lui, reste inchangé). */
.specialty-card__photo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Repli tant qu'aucune vraie photo n'est fournie au chemin indiqué
   (voir onerror sur .specialty-card__photo dans le HTML) */
.specialty-card__placeholder {
  display: none;
  position: absolute;
  inset: 0;
  background-color: var(--gris-carte);
  background-image:
    repeating-linear-gradient(135deg, rgba(255, 255, 255, 0.05) 0 2px, transparent 2px 7px),
    linear-gradient(160deg, #1c1c1c 0%, #0a0a0a 60%, var(--noir) 100%);
}

/* Étape 24 : le badge séparé "TACTIC #0X" (Bebas/mono) est retiré — le
   numéro est désormais intégré au titre lui-même ("01. Cover
   Operation", demande explicite "Titre : 01. COVER OPERATION" en une
   seule chaîne). letter-spacing porté à 0.08em (demande explicite,
   remplace 0.03em) — scopé aux titres de carte uniquement : le grand
   titre de section .specialties__title (Bebas Neue, jusqu'à 6rem) n'est
   volontairement pas touché, un tracking plus large sur un texte aussi
   grand aurait risqué de reproduire le bug de débordement déjà corrigé
   sur MANIFESTO/OPERANDI (voir plus bas) — écart non demandé. */
.specialty-card__name {
  display: block;
  margin-top: 1.25rem;
  font-family: 'Bebas Neue', sans-serif;
  font-size: 1.65rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--blanc-pur);
}

.specialty-card__category {
  display: block;
  margin-top: 0.3rem;
  font-family: 'JetBrains Mono', monospace;
  font-size: 0.68rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: rgba(242, 239, 233, 0.5);
}

.specialty-card__desc {
  margin-top: 0.75rem;
  font-family: 'Inter', sans-serif;
  font-size: 0.9rem;
  line-height: 1.7;
  color: rgba(242, 239, 233, 0.55);
}

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

/* "OPERANDI" était plus large que sa colonne sous ~360px avec le
   plancher de 3rem du clamp() ci-dessus — même bug que celui déjà
   corrigé sur le titre Manifesto. "SPECIALTIES" (11 caractères, un seul
   mot) est en réalité moins contraint qu'"OPERANDI" ne l'était, mais ce
   filet de sécurité est conservé tel quel (inoffensif, et continue de
   protéger contre un même type de débordement si le texte du titre
   change à nouveau). Ce bloc doit rester APRÈS la règle de base
   .specialties__title : à spécificité égale, l'ordre dans la cascade
   décide, et un @media placé avant une règle non conditionnelle de même
   poids perd toujours face à elle. */
@media (max-width: 420px) {
  .specialties__title {
    font-size: clamp(2rem, 11vw, 3rem);
  }
}

/* ------------------------------------------------------------
   Cases — grille de portfolio (9 projets, tap/hover-to-reveal)
   Fond NOIR PUR strict (var(--noir) = #000). Aucune couleur en
   dehors du survol / des petits badges "CASE #0X" (var(--ambre-dim)).
   ------------------------------------------------------------ */
.cases {
  position: relative; /* nécessaire pour que le z-index ci-dessous s'applique */
  z-index: 2; /* au-dessus de la pluie, cf. commentaire sur #rain-canvas */
  background: var(--noir);
  color: var(--blanc);
  padding: 6rem 1.5rem 6.5rem;
}

.cases__inner {
  max-width: 1400px;
  margin: 0 auto;
}

.cases__header {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: flex-end;
  gap: 2rem;
  margin-bottom: 3rem;
  border-bottom: 1px solid rgba(255, 255, 255, 0.14);
  padding-bottom: 2rem;
}

.cases__eyebrow {
  display: block;
  font-family: 'JetBrains Mono', monospace;
  font-size: 0.75rem;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--ambre-dim);
  margin-bottom: 0.75rem;
}

.cases__title {
  font-family: 'Bebas Neue', sans-serif;
  font-size: clamp(3rem, 8vw, 6rem);
  line-height: 0.9;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--blanc-pur);
}

.cases__desc {
  max-width: 26rem;
  font-family: 'Inter', sans-serif;
  font-size: 0.95rem;
  line-height: 1.65;
  color: rgba(242, 239, 233, 0.55);
  text-align: right;
}

/* Étape 54 (mosaïque asymétrique 12 colonnes) essayée puis intégralement
   annulée à l'Étape 55 — demande explicite de l'utilisateur après avoir vu
   le résultat en vrai ("je n'aime pas du tout le resultat"). Retour à la
   grille rigide 3 colonnes d'origine (repeat(3,1fr), paliers 2 colonnes/
   1 colonne à 900px/600px), identique à son état pré-Étape-54. Avec les
   10 projets désormais au tableau (AND ONE ajouté à l'Étape 54, conservé),
   cette grille à 3 par ligne place naturellement le 10ᵉ projet seul sur sa
   propre 4ᵉ ligne — comportement explicitement voulu par l'utilisateur,
   aucun traitement spécial nécessaire. */
.cases__grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 2rem 1.5rem;
}

@media (max-width: 900px) {
  .cases__grid { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 600px) {
  .cases__grid { grid-template-columns: 1fr; }
  .cases__desc { text-align: left; }
}

/* --- Carte projet --- */
/* Étape 28 : <article class="case-card"> devient <a class="case-card">
   (lien réel vers case.html?case=NN) — display:block + reset couleur/
   soulignement nécessaires, un <a> n'étant pas block ni "sans style"
   par défaut comme l'était <article>. Le reste de la règle (curseur,
   outline) ne change pas. */
.case-card {
  display: block;
  cursor: pointer;
  outline: none;
  color: inherit;
  text-decoration: none;
}

.case-card__visual {
  position: relative;
  overflow: hidden;
  aspect-ratio: 4 / 5;
  background: var(--gris-carte);
  border: 1px solid var(--gris-bordure);
  transition: border-color 0.4s ease;
}

/* La couleur ambrée n'apparaît QU'au survol / focus / tap */
.case-card:hover .case-card__visual,
.case-card:focus-within .case-card__visual,
.case-card.is-revealed .case-card__visual {
  border-color: var(--ambre);
}

/* Cadre blanc (marge "photo imprimée") autour de chaque visuel de Case —
   20px de marge sur les 4 côtés, fond #FFFFFF. Reste statique au survol :
   seul le contenu (.case-card__photo-image) réagit. */
.case-card__photo {
  position: absolute;
  inset: 0;
  display: flex;
  padding: 20px;
  background-color: #FFFFFF;
}

/* Étape 31 (correctif) — État repos : la vraie photo du projet (ou le
   placeholder en niveaux de gris tant qu'aucune n'est fournie) reste en
   COULEUR, sans filtre. Avant ce correctif, un filtre grayscale(1) était
   déjà actif au repos, ce qui désaturait aussi toute vraie photo couleur
   posée ici (ex. Théâtre 140) dès l'état par défaut — contraire à la
   demande explicite de l'utilisateur ("l'image doit rester en couleur et
   ne devenir noir et blanc que sur le hover"). */
.case-card__photo-image {
  position: relative;
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: var(--gris-carte);
  background-image:
    repeating-linear-gradient(135deg, rgba(255, 255, 255, 0.05) 0 2px, transparent 2px 7px),
    linear-gradient(160deg, #1c1c1c 0%, #0a0a0a 60%, var(--noir) 100%);
  background-size: cover;
  background-position: center;
  filter: none;
  transition: filter 0.6s ease;
}

/* État survol / focus / tap : c'est UNIQUEMENT ici que la photo passe en
   noir & blanc contrasté. Pas de scale() ici — sur demande explicite,
   l'effet de zoom a été retiré : seuls le filtre et l'apparition du titre
   (.case-card__reveal) signalent le survol. */
.case-card:hover .case-card__photo-image,
.case-card:focus-within .case-card__photo-image,
.case-card.is-revealed .case-card__photo-image {
  filter: grayscale(1) contrast(1.4) brightness(0.85);
}

/* Étape 29 (correctifs hover) — l'ancien voile dégradé .case-card__scrim
   (qui montait depuis le bas) est retiré : un seul overlay plat et
   uniforme (.case-card__reveal ci-dessous) couvre désormais toute
   l'image au survol, sans dégradé. */

/* Overlay au survol — fond gris sombre uniforme et plat (demande
   explicite : plus de dégradé), centré horizontalement ET verticalement
   sur toute la vignette. Étape 33 : ne contient plus QUE le titre
   poétique (le rappel du nom réel .case-card__reveal-subtitle est
   retiré — demande explicite, ce nom est déjà affiché en permanence en
   blanc sous l'image, voir .case-card__title plus bas). */
.case-card__reveal {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 1.5rem;
  background: rgba(30, 30, 34, 0.88); /* ~#1E1E22, flat — plus de gradient */
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 0.45s ease, transform 0.45s ease;
  pointer-events: none;
}
.case-card:hover .case-card__reveal,
.case-card:focus-within .case-card__reveal,
.case-card.is-revealed .case-card__reveal {
  opacity: 1;
  transform: translateY(0);
}

/* Étape 29 — le mécanisme de PNG de titre (.case-card__title-img +
   repli .case-card__title-fallback) est retiré : aucun des 9 nouveaux
   projets ne fournit de logotype de titre, et les identifiants sont
   désormais des slugs texte (ex. "theatre-140") plutôt que des
   numéros — la convention de chemin images/cases/case-0X-title.png
   n'a plus de sens. Le survol affiche le nom "poétique" du cas
   (traitement "title card" polar années 40 inchangé : Bebas Neue
   condensée + skewY/rotation + ombre portée en escalier + guillemets
   automatiques). Étape 33 : c'est désormais le SEUL élément de
   l'overlay — taille augmentée (clamp relevé) pour occuper pleinement
   l'espace libéré par le retrait du rappel de nom en sous-titre. */
.case-card__reveal-title {
  font-family: 'Bebas Neue', sans-serif;
  font-weight: 700;
  font-size: clamp(1.8rem, 3.4vw, 2.6rem);
  line-height: 1.05;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--blanc-pur);
  text-align: center;
  transform: skewY(-6deg) rotate(-2deg);
  text-shadow:
    3px 3px 0px #000,
    6px 6px 0px rgba(0, 0, 0, 0.7);
}
.case-card__reveal-title::before,
.case-card__reveal-title::after {
  content: '"';
}

/* Étape 32 (correctif final) — le badge .case-card__sector-tag (posé en
   bas à droite de l'image depuis l'Étape 29, masqué au survol depuis
   l'Étape 30) est retiré intégralement : demande explicite de
   l'utilisateur, la vignette doit rester "totalement pure", sans aucun
   encadré superposé. Le secteur reste visible ailleurs, en permanence,
   via .case-card__subtitle juste en dessous de l'image (voir plus bas). */

/* Étape 29 — bloc sous la carte : remplace l'ancien badge "CASE #0X" +
   catégorie générique par le nom de l'institution/marque (titre,
   état par défaut) et son secteur (sous-titre), en colonne plutôt
   qu'en ligne justifiée (plus de 2e élément à aligner à droite
   depuis le retrait du badge). */
.case-card__meta {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  margin-top: 0.85rem;
}

.case-card__title {
  font-family: 'Bebas Neue', sans-serif;
  font-size: 1.3rem;
  line-height: 1.05;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--blanc-pur);
}

/* Étape 32 — couleur passée de rgba(242,239,233,0.5) (gris clair sourd) à
   l'ambre vif var(--ambre) (#FFC700, même teinte que le logo/les accents
   du site) : demande explicite de l'utilisateur. Le titre juste au-dessus
   (.case-card__title) reste lui en blanc/gris clair, inchangé. */
.case-card__subtitle {
  font-family: 'JetBrains Mono', monospace;
  font-size: 0.65rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ambre);
}

@media (prefers-reduced-motion: reduce) {
  .case-card__photo,
  .case-card__photo-image,
  .case-card__reveal,
  .case-card__visual {
    transition: none;
  }
}

/* ------------------------------------------------------------
   Gazette — "The Noir Times", pastiche de journal (fond papier).
   Seule section volontairement CLAIRE : contraste tranché avec le
   reste du site (noir pur). Aucun ambre ici — l'encre reste noire,
   comme un vrai journal ; l'accent de la charte (var(--ambre)) est
   réservé au fil conducteur sombre du reste du site.
   ------------------------------------------------------------ */
.gazette {
  position: relative;
  z-index: 2;
  background: var(--papier);
  color: var(--encre);
  padding: 6rem 1.5rem 5rem;
}

.gazette__inner {
  max-width: 1200px;
  margin: 0 auto;
}

.gazette__eyebrow {
  display: block;
  font-family: 'JetBrains Mono', monospace;
  font-size: 0.75rem;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: rgba(23, 21, 18, 0.5);
  text-align: center;
  margin-bottom: 2rem;
}

/* --- Masthead --- */
.gazette__masthead {
  text-align: center;
  border-top: 4px double var(--encre);
  border-bottom: 2px solid var(--encre);
  padding: 1.75rem 0 1.25rem;
  margin-bottom: 3rem;
}

.gazette__title {
  font-family: 'Pirata One', 'Playfair Display', serif;
  font-size: clamp(2.75rem, 8vw, 5.5rem);
  line-height: 1;
  letter-spacing: 0.01em;
  color: var(--encre);
}

.gazette__subtitle {
  margin-top: 0.75rem;
  font-family: 'PT Serif', serif;
  font-style: italic;
  font-size: 0.95rem;
  color: rgba(23, 21, 18, 0.75);
}

.gazette__byline {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.75rem 1.5rem;
  margin-top: 1.25rem;
  padding-top: 1rem;
  border-top: 1px solid rgba(23, 21, 18, 0.35);
  font-family: 'JetBrains Mono', monospace;
  font-size: 0.65rem;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: rgba(23, 21, 18, 0.6);
}

/* --- Colonnes de journal --- */
.gazette__columns {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
}

.gazette__article {
  position: relative;
  padding: 0 2rem;
  border-left: 1px solid rgba(23, 21, 18, 0.25);
}
.gazette__article:first-child {
  border-left: none;
  padding-left: 0;
}
.gazette__article:last-child {
  padding-right: 0;
}

/* Tampon "Pièce Nº0X" — effet cachet légèrement de travers */
.gazette__stamp {
  display: inline-block;
  font-family: 'JetBrains Mono', monospace;
  font-size: 0.62rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: rgba(23, 21, 18, 0.7);
  border: 1px solid rgba(23, 21, 18, 0.55);
  padding: 0.15rem 0.5rem;
  transform: rotate(-2deg);
  margin-bottom: 0.9rem;
}

.gazette__kicker {
  display: block;
  font-family: 'JetBrains Mono', monospace;
  font-size: 0.65rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(23, 21, 18, 0.55);
  margin-bottom: 0.6rem;
}

.gazette__headline {
  font-family: 'Playfair Display', serif;
  font-weight: 900;
  font-size: 1.5rem;
  line-height: 1.22;
  margin-bottom: 1rem;
}

.gazette__body {
  font-family: 'PT Serif', serif;
  font-size: 0.92rem;
  line-height: 1.7;
  text-align: justify;
  hyphens: auto;
  color: rgba(23, 21, 18, 0.88);
}

/* Lettrine — première lettre du témoignage, façon composition de presse */
.gazette__body::first-letter {
  font-family: 'Playfair Display', serif;
  font-weight: 900;
  font-size: 3.4rem;
  line-height: 0.75;
  float: left;
  padding: 0.1rem 0.35rem 0 0;
}

.gazette__attribution {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-top: 1.5rem;
  padding-top: 1rem;
  border-top: 1px solid rgba(23, 21, 18, 0.2);
}

/* Avatar placeholder — trame demi-teinte façon impression offset */
.gazette__avatar {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 50%;
  background-color: var(--encre);
  background-image: radial-gradient(rgba(239, 234, 224, 0.35) 1px, transparent 1.4px);
  background-size: 4px 4px;
  color: var(--papier);
  font-family: 'JetBrains Mono', monospace;
  font-size: 0.7rem;
  letter-spacing: 0.05em;
}

.gazette__attribution-text {
  display: flex;
  flex-direction: column;
  font-family: 'JetBrains Mono', monospace;
  font-size: 0.68rem;
  letter-spacing: 0.04em;
  color: rgba(23, 21, 18, 0.75);
  line-height: 1.5;
}
.gazette__attribution-text strong {
  font-size: 0.78rem;
  letter-spacing: 0.02em;
  color: var(--encre);
}

.gazette__footer {
  margin-top: 3.5rem;
  padding-top: 1.5rem;
  border-top: 1px solid rgba(23, 21, 18, 0.3);
  text-align: center;
  font-family: 'JetBrains Mono', monospace;
  font-size: 0.65rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: rgba(23, 21, 18, 0.5);
}

@media (max-width: 900px) {
  .gazette__columns {
    grid-template-columns: 1fr;
    gap: 2.5rem;
  }
  .gazette__article {
    border-left: none;
    padding: 2rem 0 0;
    border-top: 1px solid rgba(23, 21, 18, 0.25);
  }
  .gazette__article:first-child {
    padding-top: 0;
    border-top: none;
  }
}

/* ------------------------------------------------------------
   Manifesto — 2 colonnes : texte à gauche, visuel à droite.
   Fond noir pur, comme le reste du site hors Gazette.
   ------------------------------------------------------------ */
.manifesto {
  position: relative;
  z-index: 2;
  background: var(--noir);
  color: var(--blanc);
  padding: 7rem 1.5rem;
}

.manifesto__inner {
  max-width: 1300px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: 1.15fr 0.85fr;
  gap: 5rem;
  align-items: center;
}

.manifesto__eyebrow {
  display: block;
  font-family: 'JetBrains Mono', monospace;
  font-size: 0.75rem;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  /* Étape 27 — ambre rétabli sur l'eyebrow (demande explicite, revient
     sur le retrait de l'Étape 26) : var(--ambre-dim), même convention
     que les eyebrows des autres sections du site (Specialties, etc.). */
  color: var(--ambre-dim);
  margin-bottom: 0.75rem;
}

.manifesto__title {
  font-family: 'Bebas Neue', sans-serif;
  font-size: clamp(3rem, 7vw, 5rem);
  line-height: 0.9;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--blanc-pur);
  margin-bottom: 2.25rem;
  /* Filet de sécurité : "MANIFESTO" est un seul mot, donc insécable —
     sans ça, un mot trop large pour sa colonne déborderait silencieusement
     hors de l'écran (masqué par overflow-x:hidden sur body) plutôt que
     de passer à la ligne. Voir aussi le correctif de taille ci-dessous
     pour les très petits écrans (≤420px), où le plancher de 3rem est
     lui-même trop grand pour la colonne disponible. */
  overflow-wrap: break-word;
}

/* Étape 25 — Manifesto en 4 actes (remplace l'ancien blockquote unique +
   paragraphe de pratique). Chaque acte : un label façon rapport
   d'enquête ("I. THE TERRAIN", etc., JetBrains Mono — même langage
   typographique que les eyebrows/badges du site) suivi d'un paragraphe
   en Blanc Cassé plein (var(--text-primary), demande explicite).
   Étape 26 — les filets de séparation entre actes sont retirés (demande
   explicite : plus de ligne physique entre les blocs) ; l'espacement
   entre actes passe par un `gap` sur le conteneur flex plutôt que par
   un margin+padding+border sur `+`, et légèrement augmenté (2.75rem,
   contre l'espace visuel combiné de ~3rem obtenu avant par margin +
   padding de part et d'autre de l'ancien filet) pour laisser le texte
   respirer naturellement sans séparateur. */
.manifesto__acts {
  max-width: 38rem;
  display: flex;
  flex-direction: column;
  gap: 2.75rem;
}

/* Étape 27 — titres d'actes repassés en Blanc Cassé plein (demande
   explicite, revient sur l'opacité réduite de l'Étape 26) : couleur
   identique à .manifesto__act-text (var(--text-primary)), aucune
   différence de teinte entre le label et son paragraphe. La
   différenciation se joue uniquement par la typographie :
   font-weight:700 (déjà en place depuis l'Étape 25), letter-spacing
   resserré à 0.1em (valeur demandée, remplace 0.15em), uppercase (déjà
   en place), et le margin-bottom existant (0.5rem, déjà "petit" tel
   que demandé) qui décale le label de son paragraphe. */
.manifesto__act-label {
  display: block;
  margin-bottom: 0.5rem;
  font-family: 'JetBrains Mono', monospace;
  font-weight: 700; /* poids réellement chargé via Google Fonts (voir index.html) */
  font-size: 0.85rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-primary); /* Blanc Cassé #F2EFE9 plein, demande explicite */
}

.manifesto__act-text {
  font-family: 'Inter', sans-serif;
  font-size: 0.95rem;
  line-height: 1.75; /* dans la fourchette demandée (1.6 à 1.8) */
  color: var(--text-primary); /* Blanc Cassé #F2EFE9 plein, demande explicite */
}

/* --- Visuel : porte de bureau en verre dépoli --- */
.manifesto__visual {
  position: relative;
  width: 100%;
  aspect-ratio: 3 / 4;
  overflow: hidden;
  border: 1px solid var(--gris-bordure);
  background: #050505;
}

.manifesto__photo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Repli tant qu'aucune photo n'est fournie au chemin indiqué dans le HTML
   (voir onerror sur .manifesto__photo). Composition "porte en verre dépoli"
   entièrement en CSS — à remplacer par la vraie photo, sans rien changer
   d'autre. */
.manifesto__placeholder {
  display: none;
  position: absolute;
  inset: 0;
  align-items: center;
  justify-content: center;
  background-image:
    repeating-linear-gradient(100deg, rgba(242, 239, 233, 0.035) 0 1px, transparent 1px 40px),
    radial-gradient(120% 90% at 30% 0%, rgba(242, 239, 233, 0.07), transparent 60%),
    linear-gradient(165deg, #1c1c1c 0%, #0a0a0a 65%, var(--noir) 100%);
}

.manifesto__placeholder-rain {
  position: absolute;
  inset: 0;
  background-image: repeating-linear-gradient(102deg, rgba(242, 239, 233, 0.05) 0 1px, transparent 1px 90px);
}

.manifesto__placeholder-plate {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.9rem;
  padding: 2.25rem 1.75rem;
  border: 1px solid rgba(242, 239, 233, 0.22);
  background: rgba(242, 239, 233, 0.03);
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
}

.manifesto__placeholder-name {
  font-family: 'Bebas Neue', sans-serif;
  font-size: clamp(1.8rem, 4vw, 2.5rem);
  letter-spacing: 0.08em;
  line-height: 1.05;
  color: var(--blanc-pur);
  text-align: center;
  text-transform: uppercase;
}

.manifesto__placeholder-rule {
  width: 38px;
  height: 1px;
  background: var(--ambre-dim);
}

.manifesto__placeholder-role {
  font-family: 'JetBrains Mono', monospace;
  font-size: 0.7rem;
  letter-spacing: 0.35em;
  text-transform: uppercase;
  color: rgba(242, 239, 233, 0.6);
}

@media (max-width: 900px) {
  .manifesto__inner {
    grid-template-columns: 1fr;
    gap: 3rem;
  }
  .manifesto__visual {
    max-width: 22rem;
    margin: 0 auto;
  }
}

/* "MANIFESTO" est un mot unique (insécable) : sous ~360px, le plancher
   de 3rem du clamp() de base (.manifesto__title plus haut) dépasse la
   largeur de la colonne texte et le mot se retrouve tronqué — invisible
   au-delà du bord, à cause d'overflow-x:hidden sur body. Ce bloc doit
   rester APRÈS la règle de base ci-dessus dans le fichier : à
   spécificité égale, c'est l'ordre dans la cascade qui décide, et un
   bloc @media placé avant une règle non conditionnelle de même poids
   perd toujours face à elle. */
@media (max-width: 420px) {
  .manifesto__title {
    font-size: clamp(2rem, 11vw, 3rem);
  }
}

/* ------------------------------------------------------------
   Contact — 2 colonnes : coordonnées à gauche, formulaire à droite.
   ------------------------------------------------------------ */
.contact {
  position: relative;
  z-index: 2;
  background: var(--noir);
  color: var(--blanc);
  padding: 7rem 1.5rem 5rem;
}

.contact__inner {
  max-width: 1300px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 5rem;
}

.contact__title {
  font-family: 'Inter', sans-serif;
  font-weight: 700;
  font-size: clamp(2.1rem, 4.5vw, 3.1rem);
  line-height: 1.15;
  max-width: 18ch;
  color: var(--blanc-pur);
  margin-bottom: 1.25rem;
}

.contact__desc {
  font-family: 'Inter', sans-serif;
  font-size: 1rem;
  line-height: 1.7;
  max-width: 28rem;
  color: rgba(242, 239, 233, 0.6);
  margin-bottom: 3rem;
}

.contact__coordinates-label {
  display: block;
  font-family: 'JetBrains Mono', monospace;
  font-size: 0.75rem;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--ambre-dim);
  margin-bottom: 0.9rem;
}

.contact__address {
  font-style: normal;
  font-family: 'Inter', sans-serif;
  font-size: 0.95rem;
  line-height: 1.9;
  color: rgba(242, 239, 233, 0.85);
}
.contact__address a {
  color: inherit;
  text-decoration: none;
  border-bottom: 1px solid rgba(242, 239, 233, 0.3);
  transition: color 0.25s ease, border-color 0.25s ease;
}
.contact__address a:hover {
  color: var(--ambre);
  border-color: var(--ambre);
}

/* --- Formulaire --- */
.contact__form {
  display: flex;
  flex-direction: column;
  gap: 1.75rem;
}

.form-field {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.form-field label {
  font-family: 'JetBrains Mono', monospace;
  font-size: 0.68rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: rgba(242, 239, 233, 0.5);
}

.form-field input,
.form-field textarea {
  background: transparent;
  border: none;
  border-bottom: 1px solid rgba(242, 239, 233, 0.28);
  padding: 0.6rem 0.05rem;
  font-family: 'Inter', sans-serif;
  font-size: 0.95rem;
  color: var(--blanc-pur);
  resize: vertical;
  transition: border-color 0.3s ease;
}
.form-field input::placeholder,
.form-field textarea::placeholder {
  color: rgba(242, 239, 233, 0.3);
}
.form-field input:focus,
.form-field textarea:focus {
  outline: none;
  border-color: var(--ambre);
}

/* Honeypot anti-spam — invisible pour les humains, piège pour les bots */
.contact__honeypot {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

.contact__submit {
  align-self: flex-start;
  margin-top: 0.5rem;
  padding: 0.9rem 2.25rem;
  background: var(--ambre);
  border: none;
  color: var(--noir);
  font-family: 'JetBrains Mono', monospace;
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.25em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background-color 0.3s ease, transform 0.15s ease;
}
.contact__submit:hover {
  background: var(--ambre-dim);
}
.contact__submit:active {
  transform: translateY(1px);
}
.contact__submit:disabled {
  opacity: 0.6;
  cursor: progress;
}

.contact__form-status {
  min-height: 1.3em;
  font-family: 'JetBrains Mono', monospace;
  font-size: 0.72rem;
  letter-spacing: 0.04em;
  color: rgba(242, 239, 233, 0.6);
}
.contact__form-status[data-state="success"] {
  color: var(--ambre);
}
.contact__form-status[data-state="error"] {
  color: var(--blanc-pur);
}

@media (max-width: 900px) {
  .contact__inner {
    grid-template-columns: 1fr;
    gap: 3rem;
  }
}

/* ------------------------------------------------------------
   Footer
   ------------------------------------------------------------ */
.site-footer {
  position: relative;
  z-index: 2;
  background: var(--noir);
  border-top: 1px solid rgba(242, 239, 233, 0.12);
  padding: 1.75rem 1.5rem;
}

.site-footer__inner {
  max-width: 1300px;
  margin: 0 auto;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem 2rem;
}

.site-footer__copyright,
.site-footer__legal {
  font-family: 'JetBrains Mono', monospace;
  font-size: 0.7rem;
  letter-spacing: 0.08em;
  color: rgba(242, 239, 233, 0.5);
}

.site-footer__legal {
  text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: color 0.25s ease, border-color 0.25s ease;
}
.site-footer__legal:hover {
  color: var(--blanc);
  border-color: var(--ambre);
}

.site-footer__socials {
  display: flex;
  gap: 1.5rem;
}
.site-footer__socials a {
  position: relative;
  padding-bottom: 2px;
  font-family: 'JetBrains Mono', monospace;
  font-size: 0.7rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: rgba(242, 239, 233, 0.6);
  text-decoration: none;
  transition: color 0.25s ease;
}
.site-footer__socials a::after {
  content: '';
  position: absolute;
  left: 0;
  bottom: 0;
  width: 0;
  height: 1px;
  background: var(--ambre);
  transition: width 0.3s ease;
}
.site-footer__socials a:hover {
  color: var(--blanc);
}
.site-footer__socials a:hover::after {
  width: 100%;
}

@media (max-width: 640px) {
  .site-footer__inner {
    flex-direction: column;
    text-align: center;
  }
}

/* ------------------------------------------------------------
   Sections stub (placeholders — remplacées étape par étape)
   ------------------------------------------------------------ */
.section-stub {
  position: relative;
  z-index: 2;
  min-height: 60vh;
  display: flex;
  align-items: center;
  justify-content: center;
  border-top: 1px solid rgba(242, 239, 233, 0.08);
  background: var(--noir);
}
.section-stub--light {
  background: var(--blanc);
  color: var(--noir);
  border-top-color: rgba(10, 10, 10, 0.1);
}
.section-stub__label {
  font-family: 'JetBrains Mono', monospace;
  font-size: 0.8rem;
  letter-spacing: 0.15em;
  opacity: 0.35;
  text-transform: uppercase;
}

/* ------------------------------------------------------------
   Case Detail — gabarit "CaseTemplate" (Étape 28)
   Page case.html, réutilisée pour les 9 projets : contenu injecté par
   js/case.js à partir de js/cases-data.js (voir les deux fichiers).
   Reprend strictement les tokens/polices du reste du site (aucune
   nouvelle couleur) — seule nouveauté : les classes .case-detail__*.
   .case-detail porte position:relative + z-index:2 UNE SEULE FOIS
   pour toute la page (contrairement aux sections de la Homepage qui
   sont sœurs de .hero et doivent chacune repasser au-dessus de la
   pluie) : ici .case-detail est l'unique enfant direct de <main>, ses
   descendants héritent donc déjà du bon contexte d'empilement.
   ------------------------------------------------------------ */
.case-detail {
  position: relative;
  z-index: 2;
  background: var(--noir);
  color: var(--text-primary);
}

/* --- 1. En-tête (Header & Metadata) --- */
.case-detail__header {
  /* calc(navbar + marge) : la navbar est fixed/transparente comme sur
     la Homepage, mais ici aucun visuel plein cadre ne la "couvre" —
     il faut donc explicitement repousser le contenu sous elle. */
  padding: calc(var(--navbar-h) + 3rem) 1.5rem 4rem;
}

.case-detail__header-inner {
  max-width: 1300px;
  margin: 0 auto;
}

.case-detail__back {
  display: inline-block;
  margin-bottom: 2.75rem;
  font-family: 'JetBrains Mono', monospace;
  font-size: 0.72rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: rgba(242, 239, 233, 0.6);
  text-decoration: none;
  transition: color 0.25s ease;
}
.case-detail__back:hover {
  color: var(--ambre);
}

.case-detail__tag {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin-bottom: 1.5rem;
  font-family: 'JetBrains Mono', monospace;
  font-size: 0.75rem;
  letter-spacing: 0.25em;
  text-transform: uppercase;
  color: var(--ambre-dim);
}

.case-detail__title {
  font-family: 'Bebas Neue', sans-serif;
  font-size: clamp(3rem, 9vw, 7rem);
  line-height: 0.9;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--blanc-pur);
  margin-bottom: 1.5rem;
  overflow-wrap: break-word;
}

.case-detail__subheader {
  max-width: 42rem;
  font-family: 'Inter', sans-serif;
  font-size: 1.05rem;
  line-height: 1.65;
  color: rgba(242, 239, 233, 0.65);
  margin-bottom: 3rem;
}

.case-detail__meta {
  display: grid;
  /* Étape 33 : repassé de 4 à 3 colonnes — le champ "Year" (4e item) est
     retiré (demande explicite : plus aucune date/année sur le site). */
  grid-template-columns: repeat(3, 1fr);
  gap: 2rem;
  border-top: 1px solid rgba(255, 255, 255, 0.14);
  padding-top: 2rem;
}
.case-detail__meta-item {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}
.case-detail__meta-label {
  font-family: 'JetBrains Mono', monospace;
  font-size: 0.65rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: rgba(242, 239, 233, 0.45);
}
.case-detail__meta-value {
  font-family: 'Inter', sans-serif;
  font-weight: 600;
  font-size: 0.95rem;
  color: var(--blanc-pur);
}

@media (max-width: 700px) {
  .case-detail__meta {
    grid-template-columns: repeat(2, 1fr);
    gap: 1.75rem 1.5rem;
  }
}

/* Étape 54 : rangée de tags optionnelle (champ `tags` de cases-data.js,
   introduit pour AND ONE — voir case.html et js/case.js, masquée en JS
   si le champ est absent/vide). Puces discrètes, même famille
   typographique que .case-detail__meta-label, posées sous la grille
   meta plutôt qu'en remplacement d'un des 3 champs existants. */
.case-detail__tags {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin-top: 1.5rem;
}
.case-detail__tag-chip {
  font-family: 'JetBrains Mono', monospace;
  font-size: 0.65rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: rgba(242, 239, 233, 0.75);
  border: 1px solid var(--gris-bordure);
  padding: 0.4rem 0.75rem;
  border-radius: 999px;
}

/* --- 2. Hero Asset --- */
/* Étape 72 : bandeau Hero réduit de moitié en hauteur à la demande explicite
   de l'utilisateur ("le hero des pages case studies prend trop de place, on
   va passer à un bandeau qui garde la largeur mais ne fait que la moitié de
   la hauteur") — largeur full-bleed inchangée, seul le ratio change de 16:9
   à 32:9 (même largeur, hauteur divisée par deux). `object-fit: cover` est
   conservé sur `.case-detail__hero-photo` : les 5 photos Hero déjà fournies
   et recadrées en 16:9 (Théâtre 140, Carolocataires, Floki & the Crispies,
   Amsterdam Stories, AND ONE) se trouvent donc re-recadrées par le
   navigateur pour remplir ce nouveau ratio plus large. Un point de focale
   vertical par défaut (`object-position`) est réglé au cas par cas ci-dessous
   lorsque le centrage par défaut coupait un élément important du cadrage
   d'origine (voir règles `[data-case]` plus bas). */
.case-detail__hero {
  position: relative;
  width: 100%;
  aspect-ratio: 32 / 9;
  overflow: hidden;
  background: var(--gris-carte);
  border-top: 1px solid var(--gris-bordure);
  border-bottom: 1px solid var(--gris-bordure);
}
.case-detail__hero-photo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
/* Étape 72 : point de focale ajusté pour Amsterdam Stories USA uniquement —
   le centrage vertical par défaut, sur ce bandeau 32:9 deux fois moins haut,
   ne montrait plus que du ciel (la route et les montagnes qui ancrent la
   composition d'origine, voir Étape 64, se trouvaient en bas du cadre 16:9
   initial, donc hors du centrage par défaut). Les 4 autres Hero réels
   (Théâtre 140, Carolocataires, Floki & the Crispies, AND ONE) restent au
   centrage par défaut, vérifié visuellement satisfaisant tel quel. */
[data-case="amsterdam-stories"] .case-detail__hero-photo {
  object-position: center bottom;
}
/* Repli tant qu'aucune photo n'est fournie au chemin indiqué dans
   cases-data.js (voir onerror posé par js/case.js). */
.case-detail__hero-placeholder {
  display: none;
  position: absolute;
  inset: 0;
  align-items: center;
  justify-content: center;
  background-image:
    repeating-linear-gradient(135deg, rgba(255, 255, 255, 0.05) 0 2px, transparent 2px 7px),
    linear-gradient(160deg, #1c1c1c 0%, #0a0a0a 60%, var(--noir) 100%);
}
.case-detail__hero-placeholder-label {
  font-family: 'JetBrains Mono', monospace;
  font-size: 0.75rem;
  letter-spacing: 0.25em;
  text-transform: uppercase;
  color: rgba(242, 239, 233, 0.35);
}

/* --- 3. Récit & Stratégie (3 blocs) --- */
.case-detail__narrative {
  padding: 6rem 1.5rem;
}
.case-detail__narrative-inner {
  max-width: 1300px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 3rem;
}
.case-detail__narrative-label {
  display: block;
  margin-bottom: 1rem;
  font-family: 'JetBrains Mono', monospace;
  font-weight: 700;
  font-size: 0.85rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ambre-dim);
}
.case-detail__narrative-text {
  font-family: 'Inter', sans-serif;
  font-size: 0.95rem;
  line-height: 1.75;
  color: rgba(242, 239, 233, 0.85);
}

@media (max-width: 900px) {
  .case-detail__narrative-inner {
    grid-template-columns: 1fr;
    gap: 2.5rem;
  }
}

/* --- 4. Galerie de Livrables (Showcase Grid) --- */
/* Étape 46 : la galerie était passée en Full Bleed (pleine largeur,
   jusqu'aux bords de l'écran), en sortant de `.case-detail__showcase-inner`.
   Étape 52 — retour en arrière complet sur demande explicite : une fois
   de vrais visuels en place (Étape 51), le Full Bleed rendait les images
   trop imposantes. La galerie réintègre donc `.case-detail__showcase-inner`
   (même conteneur à largeur de lecture restreinte 1300px que le Récit,
   §3 ci-dessus), aux côtés de la zone Action — `.case-detail__showcase`
   redevient un simple conteneur de padding vertical, toute la largeur et
   l'espacement interne (galerie + zone Action) sont désormais portés par
   `.case-detail__showcase-inner`. */
.case-detail__showcase {
  padding: 1rem 0 6rem;
}
.case-detail__showcase-inner {
  max-width: 1300px;
  margin: 0 auto;
  width: 100%;
  padding: 0 1.5rem;
  display: flex;
  flex-direction: column;
  gap: 4rem;
}
/* Étape 45 : .case-detail__showcase-zone-label (en-têtes "ZONE 01 —
   SYSTEM" / "ZONE 02 — APPLICATION" / "ZONE 03 — ACTION") est retirée —
   plus aucun en-tête de section au-dessus de la galerie ni de la zone
   Action, règle désormais inutilisée côté HTML. */

/* Étape 69 — masonry éditorial par colonnes (remplace intégralement la
   mosaïque à colSpan/aspectRatio forcés de l'Étape 45/51/65 ci-dessus).
   Demande explicite de l'utilisateur : plus aucun visuel de cette galerie
   ne doit être recadré ni tronqué — chaque mockup doit conserver
   strictement son ratio d'affichage naturel (référence : davidgenco.com).
   Le mécanisme Tailwind `grid grid-cols-1 md:grid-cols-12` + classes
   `col-span-N`/`aspect-[W/H]` posées par js/case.js, ainsi que son filet
   de sécurité CSS grid (grid-template-columns/grid-column/aspect-ratio
   pilotés par --col-span/--aspect-ratio), sont entièrement retirés — plus
   aucune classe Tailwind dynamique ni variable --col-span posée sur les
   items (voir js/case.js, fillGallery()).
   Nouveau mécanisme, CSS natif pur (aucune dépendance au CDN Tailwind) :
   `.case-detail__showcase-grid` est un conteneur multi-colonnes
   (`column-count`), chaque `.case-detail__showcase-item` est un bloc qui
   ne doit jamais être coupé entre deux colonnes (`break-inside: avoid`)
   et s'empile verticalement dans sa colonne avec une marge basse
   régulière — exactement le comportement Masonry/colonnes d'édition
   demandé. Les vraies photos sont désormais des <img> natifs (plus des
   divs en background-image) avec `width: 100%; height: auto;` : leur
   hauteur affichée découle entièrement du ratio réel du fichier, jamais
   d'un recadrage CSS — voir règle .case-detail__showcase-item img
   ci-dessous. Les champs `colSpan`/`aspectRatio` de js/cases-data.js ne
   pilotent donc plus la largeur/le recadrage des vraies photos (elles
   affichent leur ratio de fichier tel quel, qui correspond déjà à ce que
   `aspectRatio` déclarait puisque tous les fichiers ont été recadrés à
   l'export lors des étapes précédentes) ; `aspectRatio` reste seulement
   utilisé pour donner une hauteur aux placeholders qui n'ont pas encore
   de vrai fichier (voir .case-detail__showcase-item--placeholder), faute
   de quoi un placeholder sans <img> n'aurait aucune hauteur intrinsèque. */
.case-detail__showcase-grid {
  column-count: 1;
  column-gap: 1.5rem;
  width: 100%;
}
@media (min-width: 601px) {
  .case-detail__showcase-grid {
    column-count: 2;
  }
}
@media (min-width: 901px) {
  .case-detail__showcase-grid {
    column-count: 3;
  }
}
.case-detail__showcase-item {
  display: block;
  width: 100%;
  break-inside: avoid;
  -webkit-column-break-inside: avoid;
  page-break-inside: avoid;
  margin: 0 0 1.5rem;
  overflow: hidden;
  border: 1px solid var(--gris-bordure);
  background-color: var(--gris-carte);
}
/* Vraie photo : <img> natif posé par js/case.js (fillGallery()), jamais
   recadrée — la hauteur affichée découle uniquement du ratio réel du
   fichier, la largeur de celle de la colonne. */
.case-detail__showcase-item img {
  display: block;
  width: 100%;
  height: auto;
}
/* Placeholder (aucun `src` fourni pour cette entrée de `gallery`) : pas
   d'<img>, donc pas de ratio intrinsèque à dériver — on retombe sur le
   champ `aspectRatio` de la donnée (posé en variable CSS --aspect-ratio
   par js/case.js, uniquement sur les items placeholder) pour donner une
   hauteur raisonnable au bloc, avec la même trame que les autres
   placeholders du site (Specialties, Cases). */
.case-detail__showcase-item--placeholder {
  aspect-ratio: var(--aspect-ratio, 4 / 3);
  background-size: cover;
  background-position: center;
  background-image:
    repeating-linear-gradient(135deg, rgba(255, 255, 255, 0.05) 0 2px, transparent 2px 7px),
    linear-gradient(160deg, #1c1c1c 0%, #0a0a0a 60%, var(--noir) 100%);
}

/* Zone 03 — Action : masquée par défaut en HTML (style="display:none"),
   affichée par case.js (display:flex) uniquement si l'entrée de
   données fournit un cta (voir cases-data.js). */
.case-detail__showcase-zone--action {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 1.5rem;
}
.case-detail__cta {
  display: inline-flex;
  align-items: center;
  padding: 1rem 2.25rem;
  background: var(--ambre);
  border: none;
  color: var(--noir);
  font-family: 'JetBrains Mono', monospace;
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  text-decoration: none;
  transition: background-color 0.3s ease, transform 0.15s ease;
}
.case-detail__cta:hover {
  background: var(--ambre-dim);
}
.case-detail__cta:active {
  transform: translateY(1px);
}

/* --- 5. Footer Navigation (prev/next) & Contact --- */
.case-detail__pagination {
  border-top: 1px solid rgba(255, 255, 255, 0.14);
}
.case-detail__pagination-inner {
  max-width: 1300px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: 1fr 1fr;
}
.case-detail__pagination-link {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  padding: 3rem 1.5rem;
  /* min-width:0 nécessaire : par défaut, un enfant de grille ne peut pas
     rétrécir sous la largeur de son contenu (min-width:auto implicite) —
     avec les nouveaux noms de projet plus longs (Étape 29, ex.
     "CAROLOCATAIRES ENSEMBLE") et aucun espace pour couper la ligne,
     ça débordait de la colonne sous ~320px. Voir aussi overflow-wrap
     sur .case-detail__pagination-name juste en dessous. */
  min-width: 0;
  text-decoration: none;
  transition: background-color 0.3s ease;
}
.case-detail__pagination-link--prev {
  align-items: flex-start;
  text-align: left;
  border-right: 1px solid rgba(255, 255, 255, 0.14);
}
.case-detail__pagination-link--next {
  align-items: flex-end;
  text-align: right;
}
.case-detail__pagination-link:hover {
  background: rgba(255, 255, 255, 0.03);
}
.case-detail__pagination-dir {
  font-family: 'JetBrains Mono', monospace;
  font-size: 0.68rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: rgba(242, 239, 233, 0.45);
  transition: color 0.3s ease;
}
.case-detail__pagination-link:hover .case-detail__pagination-dir {
  color: var(--ambre);
}
.case-detail__pagination-name {
  font-family: 'Bebas Neue', sans-serif;
  font-size: 1.6rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--blanc-pur);
  overflow-wrap: break-word;
}

@media (max-width: 700px) {
  .case-detail__pagination-inner {
    grid-template-columns: 1fr;
  }
  .case-detail__pagination-link--prev {
    border-right: none;
    border-bottom: 1px solid rgba(255, 255, 255, 0.14);
  }
  .case-detail__pagination-link--next {
    align-items: flex-start;
    text-align: left;
  }
}

.case-detail__contact-cta {
  padding: 5rem 1.5rem;
  text-align: center;
  border-top: 1px solid rgba(255, 255, 255, 0.14);
}
.case-detail__contact-cta-inner {
  max-width: 34rem;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.75rem;
}
.case-detail__contact-cta-text {
  font-family: 'Inter', sans-serif;
  font-size: 1.1rem;
  color: var(--blanc-pur);
}
.case-detail__contact-cta-btn {
  display: inline-flex;
  padding: 0.9rem 2.25rem;
  background: var(--ambre);
  border: none;
  color: var(--noir);
  font-family: 'JetBrains Mono', monospace;
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.25em;
  text-transform: uppercase;
  text-decoration: none;
  transition: background-color 0.3s ease, transform 0.15s ease;
}
.case-detail__contact-cta-btn:hover {
  background: var(--ambre-dim);
}
.case-detail__contact-cta-btn:active {
  transform: translateY(1px);
}

@media (prefers-reduced-motion: reduce) {
  .case-detail__cta,
  .case-detail__contact-cta-btn,
  .case-detail__pagination-link {
    transition: none;
  }
}

/* ------------------------------------------------------------
   Accessibilité
   ------------------------------------------------------------ */
@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
  .hero__scroll span,
  .hero__neon {
    animation: none;
  }
}
