/* Tokens non liés au thème : uniquement sur :root, jamais dans un bloc
   [data-theme], sinon tailles et espacements diffèrent entre light et dark. */
:root {
  --font-sans: "Lufga", sans-serif;

  --space-xs: 0.5rem;
  --space-sm: 1rem;
  --space-md: 1.5rem;
  --space-lg: 2.5rem;
  --space-xl: 4rem;
  --space-xxl: 6rem;
  --space-xxxl: 10rem;

  --container-sm: 40rem;
  --container-md: 64rem;
  --container-lg: 80rem;

  --header-height: 4rem;
  --logo-size: 1.125rem;
  --font-weight-display: 400;
  --page-gutter: clamp(1.25rem, 5vw, 4rem);
}

/* Couleurs des thèmes. La classe is-inverted (posée par reveal.js quand le
   passage « Et vous… » se fixe en haut) affiche le thème opposé, sans
   changer la préférence choisie avec le bouton Light/Dark. */
:root,
html[data-theme="dark"],
html[data-theme="light"].is-inverted {
  --color-bg: #0a0a0a;
  --color-fg: #f5f5f5;
  --color-accent: #3d6bff;
  color-scheme: dark;
}

html[data-theme="light"],
html[data-theme="dark"].is-inverted {
  --color-bg: #ffffff;
  --color-fg: #000000;
  --color-accent: #002fa7;
  color-scheme: light;
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  min-height: 100vh;
  font-family: var(--font-sans);
  font-weight: var(--font-weight-display);
  font-size: 1rem;
  line-height: 1.5;
  color: var(--color-fg);
  background: var(--color-bg);
  transition: color 0.4s ease, background-color 0.4s ease;
}

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

a {
  color: inherit;
  text-decoration: none;
}

h1,
h2,
h3,
h4,
h5,
h6 {
  font-family: var(--font-sans);
  font-weight: var(--font-weight-display);
  line-height: 1.15;
  margin: 0;
}

/* -------------------------------------------------------------------------- */
/* Layout                                                                     */
/* -------------------------------------------------------------------------- */

/* Header transparent, par-dessus la page : il ne réserve pas de place, le
   contenu démarre tout en haut et passe sous lui. */
.site-header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  min-height: var(--header-height);
  padding-block: var(--space-sm);
  background: transparent;
}

.page-shell {
  box-sizing: border-box;
  width: 100%;
  max-width: var(--container-lg);
  margin-inline: auto;
  padding-inline: var(--page-gutter);
}

.site-header__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-md);
  max-width: none;
}

.site-nav {
  display: flex;
  align-items: center;
  gap: var(--space-md);
  margin-left: auto;
}

.logo {
  display: inline-flex;
  align-items: baseline;
  gap: 0.5em;
  font-family: var(--font-sans);
  font-size: var(--logo-size);
  font-weight: 900;
  color: var(--color-fg);
  letter-spacing: 0.02em;
  line-height: 1;
}

.logo__name {
  font-weight: 900;
  color: var(--color-fg);
}

.logo__tagline {
  font-weight: 200;
  color: var(--color-accent);
}

/* Bouton de thème : une fenêtre de 24 px où sont empilés le soleil et la
   lune. L'icône du thème actif est visible ; au survol, la pile glisse
   pour montrer celle du thème suivant. */
.theme-toggle {
  appearance: none;
  display: inline-flex;
  margin: 0;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--color-fg);
  cursor: pointer;
}

.theme-toggle__window {
  position: relative;
  display: block;
  width: 24px;
  height: 24px;
  overflow: hidden;
}

.theme-toggle__stack {
  position: absolute;
  top: 0;
  left: 0;
  display: flex;
  flex-direction: column;
  transform: translateY(var(--theme-shift, 0px));
  transition: transform 150ms ease-out;
}

.theme-toggle__icon {
  display: block;
  flex: none;
  width: 24px;
  height: 24px;
}

/* Clair : soleil visible, lune au survol. Sombre : l'inverse. */
html[data-theme="dark"] .theme-toggle,
html[data-theme="light"] .theme-toggle:hover {
  --theme-shift: -24px;
}

html[data-theme="dark"] .theme-toggle:hover {
  --theme-shift: 0px;
}

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

.theme-toggle:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 4px;
}

.site-main {
  padding: 0;
}

.intro {
  position: relative;
  box-sizing: border-box;
  min-height: 100vh;
  width: 100%;
  margin: 0;
  overflow: hidden;
}

.hero-marque {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 1;
  width: 100%;
  margin: 0;
  padding: 0;
  font-family: var(--font-sans);
  font-weight: 900;
  font-size: 18vw;
  line-height: 0.82;
  letter-spacing: -0.06em;
  white-space: nowrap;
  text-align: center;
  color: var(--color-fg);
  pointer-events: none;
  user-select: none;
}

.manifesto {
  padding-top: var(--space-xxl);
  padding-bottom: var(--space-xxl);
}

.manifesto__text {
  max-width: 22ch;
  margin: 0;
  font-family: var(--font-sans);
  font-weight: 700;
  font-size: clamp(1.75rem, 5vw, 4.5rem);
  line-height: 1.1;
  letter-spacing: -0.02em;
  color: var(--color-fg);
}

/* Opacité de chaque mot pilotée au scroll par reveal.js (--reveal : 0 → 1). */
.is-revealing .word {
  opacity: calc(0.15 + 0.85 * var(--reveal, 0));
}

/* min-height posée par dock.js : les lignes sont centrées dedans et
   s'écartent au survol sans faire bouger la suite de la page. */
.clients {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: var(--space-md);
  margin-bottom: var(--space-xxl);
}

.clients__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-md);
  margin: 0;
  padding: 0;
  list-style: none;
}

.client {
  position: relative;
  overflow: hidden;
}

/* Emplacement du visuel : remplacer par une <img> (même classe) une fois les
   visuels disponibles. */
.client__visual {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  background: color-mix(in srgb, var(--color-fg) 8%, var(--color-bg));
}

/* Dégradé pour garder le nom lisible sur n'importe quel visuel. */
.client::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, rgb(0 0 0 / 0.55), transparent 45%);
  pointer-events: none;
}

.client__link {
  display: block;
}

.client__link:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 4px;
}

.client__name {
  position: absolute;
  left: var(--space-sm);
  bottom: var(--space-sm);
  z-index: 1;
  margin: 0;
  font-weight: 700;
  font-size: 0.8125rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: #ffffff;
}

/* Dock (≥640px) : 2 lignes de 2, les vignettes proches de la souris
   grossissent, sur les deux lignes. --grow est piloté par dock.js. La ligne
   du haut est alignée en bas et celle du bas en haut : l'écart entre les
   blocs reste ainsi toujours égal au gap, à l'horizontale comme à la
   verticale. */
@media (min-width: 640px) {
  .clients__grid {
    display: flex;
    align-items: flex-end;
  }

  .clients__grid + .clients__grid {
    align-items: flex-start;
  }

  .client {
    flex: var(--grow, 1) 1 0;
    min-width: 0;
    transition: flex-grow 0.2s ease-out;
  }

  .clients.is-frozen .client {
    transition: none;
  }
}

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

/* L'espace au-dessus vient déjà de la marge basse de .clients. */
.values {
  padding-bottom: var(--space-xxl);
}


/* Titre bord à bord comme le « Royal Punk » du hero : chaque ligne est
   ajustée à la largeur de la page par intro.js (data-fit-width). */
.values__title {
  margin-bottom: var(--space-xxxl);
  font-weight: 900;
  line-height: 0.9;
  letter-spacing: -0.04em;
}

.values__line {
  display: block;
  width: fit-content;
  margin-inline: auto;
  font-size: 9vw;
  white-space: nowrap;
}

/* Emplacement à largeur fixe : la ligne ne bouge pas quand heart.js fait
   défiler les emojis. */
.values__emoji {
  display: inline-block;
  width: 1.15em;
  font-size: 0.85em;
  letter-spacing: 0;
  text-align: center;
}

.values__glyph {
  display: inline-block;
}

/* « Pop » à chaque battement ou changement d'emoji. */
.values__glyph.is-popping {
  animation: emoji-pop 0.3s ease-out;
}

@keyframes emoji-pop {
  0%,
  100% {
    transform: scale(1);
  }
  40% {
    transform: scale(1.2);
  }
}

.values__list {
  position: relative;
  margin: 0;
  padding: 0;
  list-style: none;
}

.value {
  position: relative;
  display: grid;
  grid-template-columns: 1fr;
  column-gap: var(--space-md);
  row-gap: var(--space-sm);
  align-items: baseline;
  padding-block: var(--space-lg);
}

/* Filets : un point rose (le 💘) au centre qui s'étire en ligne jusqu'aux
   bords de la colonne puis s'efface au fil du scroll.
   - Étirement : quand le filet entre à l'écran, reveal.js arme l'élément
     (is-line-armed, --stretch à 0) puis le déclenche (is-stretched). La
     transition de --stretch suit un ressort amorti : la ligne dépasse la
     colonne, revient en deçà et se stabilise, en s'affinant quand elle
     s'allonge. Sans JS, --stretch vaut 1 : la ligne est pleine.
   - Effacement : --line (0 → 1, posé par reveal.js ; 0.5 par défaut) fait
     disparaître la ligne sur son dernier quart. */
@property --stretch {
  syntax: "<number>";
  inherits: true;
  initial-value: 1;
}

[data-line].is-line-armed {
  --stretch: 0;
  transition: --stretch 0.4s ease-in;
}

[data-line].is-line-armed.is-stretched {
  --stretch: 1;
  transition: --stretch 1.4s
    linear(
      0, 0.065, 0.233, 0.462, 0.713, 0.948, 1.071, 1.14, 1.178, 1.186, 1.169,
      1.134, 1.09, 1.044, 1.001, 0.96, 0.933, 0.919, 0.918, 0.927, 0.944,
      0.964, 0.985, 1.003, 1.015, 1.022, 1.026, 1.025, 1.022, 1.016, 1.01,
      1.003, 0.997, 0.993, 0.99, 0.988, 0.989, 0.991, 0.993, 0.996, 1
    );
}

.value::before,
.values__list::after {
  --dot: 8px;
  content: "";
  position: absolute;
  left: 50%;
  width: calc(var(--dot) + (100% - var(--dot)) * var(--stretch));
  height: max(1px, var(--dot) - (var(--dot) - 1px) * var(--stretch));
  border-radius: var(--dot);
  background: color-mix(
    in srgb,
    var(--color-fg) calc(min(var(--stretch), 1) * 100%),
    #ff3fa0
  );
  opacity: clamp(0, (1 - var(--line, 0.5)) * 4, 1);
}

/* Centré sur l'emplacement du filet. */
.value::before {
  top: 0;
  translate: -50% -50%;
}

.values__list::after {
  bottom: 0;
  translate: -50% 50%;
}

.value__name {
  font-weight: 900;
  font-size: clamp(2.25rem, 5vw, 5rem);
  line-height: 0.9;
  letter-spacing: -0.04em;
  text-transform: uppercase;
}

.value__text {
  max-width: 34ch;
  margin: 0;
  font-size: clamp(1.125rem, 1.6vw, 1.375rem);
  line-height: 1.4;
}

/* S'ajoute au padding bas de .values pour marquer la transition. */
/* Expertises : titre (comme le manifeste) puis trois colonnes sous un
   filet, empilées sur mobile. */
.expertise {
  padding-top: var(--space-xxl);
  padding-bottom: var(--space-xxl);
}

.expertise__title {
  max-width: 24ch;
  margin: 0 0 var(--space-xxl);
  font-weight: 700;
  font-size: clamp(1.75rem, 4.2vw, 3.75rem);
  line-height: 1.1;
  letter-spacing: -0.02em;
}

.expertise__list {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-xl) var(--space-lg);
  margin: 0;
  padding: 0;
  list-style: none;
}

.expertise__item {
  padding-top: var(--space-md);
  border-top: 1px solid color-mix(in srgb, var(--color-fg) 35%, transparent);
}

.expertise__name {
  margin-bottom: var(--space-sm);
  font-weight: 900;
  font-size: clamp(1.5rem, 2.4vw, 2.25rem);
  line-height: 1;
  letter-spacing: -0.03em;
}

.expertise__text {
  max-width: 38ch;
  margin: 0;
  font-size: clamp(1rem, 1.3vw, 1.125rem);
  line-height: 1.5;
}

@media (min-width: 900px) {
  .expertise__list {
    grid-template-columns: repeat(3, 1fr);
  }
}

/* Expertise : titre puis six expertises en grille (1, 2 puis 3 colonnes),
   chacune sous un filet, avec sa promesse (→) en couleur d'accent. */
.skills {
  margin-top: var(--space-xxxl);
}

.skills__title {
  margin-bottom: var(--space-xl);
  font-weight: 900;
  font-size: clamp(2.25rem, 5vw, 5rem);
  line-height: 0.9;
  letter-spacing: -0.04em;
  text-transform: uppercase;
}

.skills__list {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-xl) var(--space-lg);
  margin: 0;
  padding: 0;
  list-style: none;
}

.skill {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  padding-top: var(--space-md);
  border-top: 1px solid color-mix(in srgb, var(--color-fg) 35%, transparent);
}

.skill__name {
  margin: 0;
  font-weight: 700;
  font-size: clamp(1.25rem, 1.8vw, 1.625rem);
  line-height: 1.1;
  letter-spacing: -0.02em;
}

.skill__text {
  max-width: 38ch;
  margin: 0;
  font-size: clamp(1rem, 1.2vw, 1.0625rem);
  line-height: 1.5;
}

.skill__promise {
  max-width: 38ch;
  margin: auto 0 0;
  font-weight: 700;
  line-height: 1.4;
  color: var(--color-accent);
}

@media (min-width: 640px) {
  .skills__list {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (min-width: 1024px) {
  .skills__list {
    grid-template-columns: repeat(3, 1fr);
  }
}

.brand-check {
  padding-top: var(--space-xl);
  padding-bottom: var(--space-xxl);
}

/* Même traitement que la phrase d'intro. */
.brand-check__title {
  max-width: 22ch;
  margin-bottom: var(--space-xl);
  font-weight: 900;
  font-size: clamp(1.75rem, 5vw, 4.5rem);
  line-height: 1.1;
  letter-spacing: -0.02em;
}

/* Passage épinglé (classes posées par reveal.js) : le titre monte seul et se
   fixe en haut de l'écran. is-pinned : le thème s'inverse et la phrase
   « Et vous… » laisse place à « Vos clients… ». is-step-2 : le texte « Chez RP… » sort du « sol »
   ligne à ligne. La hauteur de .brand-check__stage règle la durée du
   passage. Sans JS ou sans animation, tout s'affiche normalement. */
.brand-check__stage {
  margin-bottom: var(--space-xxl);
}

.brand-check__stage.is-staged {
  height: 180vh;
}

.brand-check__stage.is-staged .brand-check__sticky {
  position: sticky;
  top: var(--header-height);
}

/* Deux phrases dans le titre. Sans passage épinglé, elles se suivent. */
.brand-check__phrase {
  display: block;
}

.brand-check__phrase + .brand-check__phrase {
  margin-top: var(--space-sm);
}

/* Passage épinglé : superposées, chacune masquée sous elle-même. À
   l'inversion des couleurs (is-pinned), « Et vous… » sort vers le haut et
   « Vos clients… » monte à sa place. */
.brand-check__stage.is-staged .brand-check__title {
  display: grid;
}

.brand-check__stage.is-staged .brand-check__phrase {
  grid-area: 1 / 1;
  margin: 0;
  overflow: hidden;
}

.brand-check__stage.is-staged .phrase__inner {
  display: block;
  transition: transform 0.7s cubic-bezier(0.2, 0.7, 0.2, 1);
}

.brand-check__stage.is-staged .brand-check__phrase--next .phrase__inner {
  transform: translateY(110%);
}

.brand-check__stage.is-pinned .brand-check__phrase:not(.brand-check__phrase--next) .phrase__inner {
  transform: translateY(-110%);
}

.brand-check__stage.is-pinned .brand-check__phrase--next .phrase__inner {
  transform: none;
  transition-delay: 150ms;
}

/* Chaque ligne est masquée sous elle-même et remonte à sa place, avec un
   décalage selon son rang (--i, dans le HTML). */
.brand-check__stage.is-staged .brand-check__lead p {
  overflow: hidden;
}

.brand-check__stage.is-staged .lead__inner {
  display: block;
  transform: translateY(110%);
  transition: transform 0.7s cubic-bezier(0.2, 0.7, 0.2, 1);
  transition-delay: calc(var(--i, 0) * 80ms);
}

.brand-check__stage.is-step-2 .lead__inner {
  transform: none;
}

.brand-check__lead {
  margin: 0;
  padding: 0;
  list-style: none;
  font-weight: 700;
  font-size: clamp(1.125rem, 2vw, 1.75rem);
  line-height: 1.25;
  letter-spacing: -0.02em;
}

.brand-check__lead {
  max-width: 48ch;
}

.brand-check__lead p {
  margin: 0;
}

.brand-check__lead p + p {
  margin-top: var(--space-md);
}

.cta {
  display: inline-flex;
  flex-direction: column;
  gap: var(--space-xs);
}

.cta__lead {
  font-weight: 700;
  font-size: 0.8125rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.cta__label {
  font-weight: 900;
  font-size: clamp(2rem, 4.5vw, 4rem);
  line-height: 1;
  letter-spacing: -0.03em;
  color: var(--color-accent);
  transition: color 0.2s ease;
}

.cta:hover .cta__label {
  color: var(--color-fg);
}

.cta:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 6px;
}

/* -------------------------------------------------------------------------- */
/* Étude de cas                                                               */
/* -------------------------------------------------------------------------- */

/* Transition entre pages : la vignette cliquée et le grand visuel de l'étude
   de cas partagent le même view-transition-name et se transforment l'un en
   l'autre. Le header reste en place. Les navigateurs sans support changent
   simplement de page. */
@view-transition {
  navigation: auto;
}

.site-header__bar {
  view-transition-name: site-header;
}

::view-transition-group(*) {
  animation-duration: 0.6s;
  animation-timing-function: cubic-bezier(0.2, 0.7, 0.2, 1);
}

::view-transition-old(*),
::view-transition-new(*) {
  height: 100%;
  object-fit: cover;
}

/* Changement de thème (intro.js) : une seule capture de toute la page,
   sans les éléments nommés ni les transitions de couleur, que le nouveau
   thème recouvre en cercle depuis le bouton. */
html.is-theme-switching * {
  view-transition-name: none !important;
  transition: none !important;
}

html.is-theme-switching::view-transition-old(root),
html.is-theme-switching::view-transition-new(root) {
  animation: none;
  mix-blend-mode: normal;
}

@media (prefers-reduced-motion: reduce) {
  @view-transition {
    navigation: none;
  }
}

/* Au scroll, case.js fait passer --case-tint de 0 à 1 : la page vire vers
   les couleurs du client (--case-to-*), par défaut bleu nuit et texte blanc.
   Les mélanges sont calculés sur <html> (couleurs du thème), puis remplacent
   les tokens à partir de <body>. */
html:has(.case) {
  --case-to-bg: #00195c;
  --case-to-fg: #ffffff;
  --case-to-accent: #3d6bff;
  --case-bg: color-mix(
    in srgb,
    var(--case-to-bg)
      calc(var(--case-tint, 0) * (1 - var(--lift-progress, 0)) * 100%),
    var(--color-bg)
  );
  --case-fg: color-mix(
    in srgb,
    var(--case-to-fg)
      calc(var(--case-tint, 0) * (1 - var(--lift-progress, 0)) * 100%),
    var(--color-fg)
  );
  --case-accent: color-mix(
    in srgb,
    var(--case-to-accent)
      calc(var(--case-tint, 0) * (1 - var(--lift-progress, 0)) * 100%),
    var(--color-accent)
  );
}

/* --case-tint animé par le navigateur au fil du scroll (sur un tiers
   d'écran) ; sans animation-timeline, case.js le pose. */
@property --case-tint {
  syntax: "<number>";
  inherits: true;
  initial-value: 0;
}

@keyframes case-tint {
  to {
    --case-tint: 1;
  }
}

@supports (animation-timeline: scroll()) {
  html:has(.case) {
    animation: case-tint linear both;
    animation-timeline: scroll(root);
    animation-range: 0 calc(100vh / 3);
  }
}

/* ORSE : fond clair, texte noir. */
html:has(.case--orse) {
  --case-to-bg: #e7f9fa;
  --case-to-fg: #000000;
  --case-to-accent: #002fa7;
}

/* IKO : terracotta, texte noir (le blanc manque de contraste pour les
   paragraphes), accent blanc. */
html:has(.case--iko) {
  --case-to-bg: #d07658;
  --case-to-fg: #000000;
  --case-to-accent: #ffffff;
}

/* La Poste : jaune, texte noir, accent bleu La Poste. */
html:has(.case--la-poste) {
  --case-to-bg: #ffcb03;
  --case-to-fg: #000000;
  --case-to-accent: #003da5;
}

html:has(.case) body {
  --color-bg: var(--case-bg);
  --color-fg: var(--case-fg);
  --color-accent: var(--case-accent);
}

/* En haut de page, la photo reste en place (sticky) et rapetisse jusqu'à
   1200 px de large (--target, posé par case.js) pendant les --pin-d
   premiers pixels de scroll, puis défile normalement. Le texte remonte
   jusqu'à son bord bas (case-rise). Tout est animé par le navigateur au fil
   du scroll (animation-timeline), en scale/translate : pas de recalcul de
   mise en page, pas de décalage avec le scroll. Sans animation-timeline,
   case.js pose les mêmes valeurs. */
.case {
  --photo-h: calc(100vh - 2 * var(--page-gutter));
  --pin-d: 50vh;
}

.case__hero {
  box-sizing: content-box;
  height: calc(var(--photo-h) + var(--pin-d));
  padding-top: var(--page-gutter);
}

/* Rien à réduire (écran étroit) ou mouvement réduit : pas de maintien. */
.case.is-static {
  --pin-d: 0px;
}

.case__visual {
  position: sticky;
  top: var(--page-gutter);
  display: block;
  width: calc(100% - 2 * var(--page-gutter));
  height: var(--photo-h);
  margin: 0 auto;
  object-fit: cover;
  background: color-mix(in srgb, var(--color-fg) 8%, var(--color-bg));
  transform-origin: 50% 0;
}

@keyframes case-shrink {
  to {
    scale: var(--target, 1);
  }
}

/* Le texte suit le bord bas de la photo qui rapetisse. Sa place dans la
   page (margin-top) est celle de la fin du rétrécissement ; au départ il
   est remonté d'autant (translate), puis rejoint sa place : à la fin, plus
   aucun décalage, la page s'arrête bien sous le dernier texte. */
@keyframes case-rise {
  from {
    translate: 0
      calc(var(--photo-h) * (1 - var(--target, 1)) - var(--pin-d));
  }
  to {
    translate: 0 0;
  }
}

@supports (animation-timeline: scroll()) {
  .case:not(.is-static) .case__visual {
    animation: case-shrink linear both;
    animation-timeline: scroll(root);
    animation-range: 0 50vh;
  }

  .case:not(.is-static) .case__content {
    animation:
      case-in 0.6s cubic-bezier(0.2, 0.7, 0.2, 1) 0.45s both,
      case-rise linear both;
    animation-timeline: auto, scroll(root);
    animation-range: normal, 0 50vh;
  }
}

/* Le contenu apparaît une fois le visuel ouvert en plein écran. */
.case:not(.is-static) .case__content {
  margin-top: calc(-1 * var(--photo-h) * (1 - var(--target, 1)));
}

.case__content {
  padding-block: var(--space-xl) var(--space-xxl);
  animation: case-in 0.6s cubic-bezier(0.2, 0.7, 0.2, 1) 0.45s both;
}

@keyframes case-in {
  from {
    opacity: 0;
    transform: translateY(2rem);
  }
}

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

.case__client {
  margin: 0 0 var(--space-sm);
  font-weight: 700;
  font-size: 0.8125rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--color-accent);
}

.case__title {
  max-width: 26ch;
  margin-bottom: var(--space-xxl);
  font-weight: 900;
  font-size: clamp(2rem, 4.5vw, 4rem);
  line-height: 0.95;
  letter-spacing: -0.04em;
}

.case__title sup {
  font-size: 0.45em;
  vertical-align: 0.9em;
  line-height: 0;
}

.case__section {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-sm);
}

.case__label {
  font-weight: 700;
  font-size: 0.8125rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

/* Prestations : une ligne d'étiquettes entre le titre et le texte, sur un
   fond légèrement teinté de la couleur du texte (suit le virage de couleur
   de la page au scroll). */
.case__services {
  display: flex;
  flex-wrap: wrap;
  gap: 0.625rem;
  margin: calc(-1 * var(--space-xl)) 0 var(--space-xl);
  padding: 0;
  list-style: none;
}

.case__services li {
  display: inline-flex;
  align-items: center;
  gap: 0.6em;
  padding: 0.7em 1.15em;
  border-radius: 999px;
  background: color-mix(in srgb, var(--color-fg) 9%, transparent);
  font-weight: 500;
  font-size: 0.9375rem;
  letter-spacing: 0.01em;
  line-height: 1.15;
  transition:
    background-color 0.25s ease,
    color 0.25s ease;
}

/* Pastille d'accent devant chaque prestation. */
.case__services li::before {
  content: "";
  width: 0.45em;
  height: 0.45em;
  border-radius: 50%;
  background: var(--color-accent);
  flex: none;
}

.case__services li:hover {
  background: var(--color-fg);
  color: var(--color-bg);
}

.case__text {
  font-size: clamp(1.25rem, 1.9vw, 1.625rem);
  font-weight: 300;
  line-height: 1.3;
  letter-spacing: -0.01em;
}

.case__text p {
  margin: 0 0 0.9em;
}

/* Accueil affiché sous une page projet que l'on referme (case.js, via
   intro.js) : fond et texte aux couleurs du projet, dosées par --tint-mix
   (1 → 0 à mesure que la page projet remonte). Mélanges calculés sur
   <html> (couleurs du thème), appliqués à partir de <body>, sans transition
   pour suivre le scroll. */
html.is-tinted {
  --tinted-bg: color-mix(
    in srgb,
    var(--tint-bg) calc(var(--tint-mix, 1) * 100%),
    var(--color-bg)
  );
  --tinted-fg: color-mix(
    in srgb,
    var(--tint-fg) calc(var(--tint-mix, 1) * 100%),
    var(--color-fg)
  );
}

html.is-tinted body {
  --color-bg: var(--tinted-bg);
  --color-fg: var(--tinted-fg);
  transition: none;
}

/* Le header de l'accueil n'apparaît que sur la fin de la course. */
html.is-tinted .site-header {
  opacity: calc(1 - var(--tint-mix, 1) * 5);
}

/* Fin de page (case.js) : la page projet (header + contenu) remonte de
   --lift comme une feuille, au-dessus de l'accueil chargé dans une iframe
   fixe (.case-under). */
.case-under {
  position: fixed;
  inset: 0;
  z-index: 0;
  width: 100%;
  height: 100%;
  border: 0;
  pointer-events: none;
  visibility: hidden;
  transform: translateY(var(--under-shift, 0px));
  will-change: transform;
}

html.is-lifting .case-under {
  visibility: visible;
}

/* Transformation posée seulement pendant la remontée. */
html.is-lifting .site-header,
html.is-lifting .case {
  transform: translateY(calc(-1 * var(--lift, 0px)));
}

/* flow-root : la marge haute de la photo reste dans la page projet (sinon
   elle en sortirait et laisserait voir en haut le fond du body). */
html:has(.case) .case {
  position: relative;
  z-index: 1;
  display: flow-root;
  background: var(--color-bg);
}

/* Fond de page sans retard sur la couleur du projet, qui suit le scroll. */
html:has(.case) body {
  transition: none;
}

/* Pas de rebond élastique en bas de page : il se mêlerait au mouvement. */
html:has(.case) {
  overscroll-behavior-y: none;
}

html.is-lifting .site-header,
html.is-lifting .case {
  will-change: transform;
}

/* Témoignage client, sous le texte, séparé par un filet. */
.case__testimonial {
  margin: var(--space-xxl) 0 0;
  padding-top: var(--space-xl);
  border-top: 1px solid color-mix(in srgb, var(--color-fg) 25%, transparent);
}

.case__quote {
  position: relative;
  max-width: 34ch;
  margin: 0 0 var(--space-lg);
  font-weight: 500;
  font-size: clamp(1.5rem, 3vw, 2.5rem);
  line-height: 1.2;
  letter-spacing: -0.02em;
}

.case__quote p {
  margin: 0;
}

/* Guillemets français autour de la citation. */
.case__quote p::before {
  content: "« ";
  color: var(--color-accent);
}

.case__quote p::after {
  content: " »";
  color: var(--color-accent);
}

.case__author {
  display: grid;
  grid-template-columns: auto 1fr;
  column-gap: var(--space-sm);
  align-items: center;
}

.case__author-photo {
  grid-row: span 2;
  width: 64px;
  height: 64px;
  border-radius: 50%;
  object-fit: cover;
}

.case__author-name {
  align-self: end;
  font-weight: 700;
}

.case__author-role {
  align-self: start;
  font-size: 0.875rem;
  opacity: 0.7;
}

.container {
  width: 100%;
  max-width: var(--container-md);
  margin-inline: auto;
}

.container--sm {
  max-width: var(--container-sm);
}

.container--lg {
  max-width: var(--container-lg);
}

.stack {
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
}

.row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-md);
}

.row > * {
  flex: 1 1 100%;
}

/* -------------------------------------------------------------------------- */
/* Responsive utilities                                                       */
/* Breakpoints: sm ≥640px | md ≥768px | lg ≥1024px | xl ≥1280px               */
/* -------------------------------------------------------------------------- */

.u-hide {
  display: none !important;
}

.u-show {
  display: block !important;
}

@media (max-width: 639px) {
  .u-hide-sm-down {
    display: none !important;
  }
}

@media (min-width: 640px) {
  .site-header {
    padding-block: var(--space-sm);
  }

  .row > * {
    flex: 1 1 calc(50% - var(--space-md));
  }

  .u-hide-sm {
    display: none !important;
  }

  .u-show-sm {
    display: block !important;
  }

  .u-flex-sm {
    display: flex !important;
  }
}

@media (min-width: 768px) {
  .value {
    grid-template-columns: 1.4fr 1fr;
  }

  .value__text {
    align-self: end;
  }

  .row > * {
    flex: 1 1 calc(33.333% - var(--space-md));
  }

  .u-hide-md {
    display: none !important;
  }

  .u-show-md {
    display: block !important;
  }

  .u-flex-md {
    display: flex !important;
  }
}

@media (min-width: 1024px) {
  .site-header {
    padding-block: var(--space-md);
  }

  .u-hide-lg {
    display: none !important;
  }

  .u-show-lg {
    display: block !important;
  }

  .u-flex-lg {
    display: flex !important;
  }
}

@media (min-width: 1280px) {
  .u-hide-xl {
    display: none !important;
  }

  .u-show-xl {
    display: block !important;
  }

  .u-flex-xl {
    display: flex !important;
  }
}
