/* Portfolio de Greg Gargiulo
   Texte noir sur fond blanc, une seule famille (Geist). La couleur n'apparaît que dans les
   captures, sur l'aplat de chaque projet ; les sections se séparent par des filets et des blancs.
   Règle de formes : boutons, flèches et étiquettes en pilule ; images et scènes à angles vifs. */

@font-face { font-family: "Geist"; src: url("../fonts/geist-400.woff2") format("woff2"); font-weight: 400; font-style: normal; font-display: swap; }
@font-face { font-family: "Geist"; src: url("../fonts/geist-500.woff2") format("woff2"); font-weight: 500; font-style: normal; font-display: swap; }
@font-face { font-family: "Geist"; src: url("../fonts/geist-700.woff2") format("woff2"); font-weight: 700; font-style: normal; font-display: swap; }
@font-face { font-family: "Geist Mono"; src: url("../fonts/geist-mono-400.woff2") format("woff2"); font-weight: 400; font-style: normal; font-display: swap; }
/* Métriques de repli proches de Geist, pour limiter le décalage au chargement. */
@font-face { font-family: "Geist Fallback"; src: local("Arial"); size-adjust: 104%; ascent-override: 92%; descent-override: 22%; line-gap-override: 0%; }

:root {
  --paper: #fafafa;
  --ink: #0c0c0d;
  --bg: var(--paper);
  --fg: var(--ink);
  --line: color-mix(in srgb, currentColor 20%, transparent);
  --sans: "Geist", "Geist Fallback", "Helvetica Neue", Arial, sans-serif;
  --mono: "Geist Mono", ui-monospace, Menlo, monospace;
  --hdr: 64px;
  /* Hauteur du sommaire d'une étude, collé sous l'en-tête (ordinateur). */
  --toc: 3rem;
  /* Échelle typographique : chaque rôle a sa taille, du plus grand au plus petit. */
  --fs-display: clamp(2.5rem, 7vw, 7.5rem);   /* titre d'accueil */
  --fs-case: clamp(2.5rem, 6vw, 6.5rem);      /* titre d'une étude : le plus long tient sur une ligne */
  --fs-title: clamp(2.25rem, 5.4vw, 5.75rem); /* projet suivant, « M'écrire. », organisations */
  --fs-h2: clamp(2rem, 3.4vw, 3.25rem);       /* titres de section */
  --fs-figure: clamp(2.25rem, 3.8vw, 3.75rem);/* chiffres clés, année d'une étude */
  --fs-lead: clamp(1.5rem, 2.4vw, 2.375rem);  /* phrases d'introduction */
  --fs-h3: clamp(1.375rem, 2vw, 1.875rem);    /* titres de ligne, de bloc */
  --fs-body-l: 1.125rem;
  --fs-body: 1rem;
  --fs-small: 0.9375rem;
  --fs-caption: 0.8125rem;
  --fs-label: 0.75rem;
  --ease: cubic-bezier(0.4, 0, 0.2, 1);
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --pad: clamp(16px, 3.3vw, 48px);
  --gap: clamp(16px, 2.2vw, 32px);
  color-scheme: light;
}

*,
*::before,
*::after {
  box-sizing: border-box;
}
html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--hdr) + 1.5rem);
}
html[data-menu="open"] {
  overflow: hidden;
}
body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--sans);
  font-size: 1rem;
  line-height: 1.5;
  font-weight: 400;
  font-kerning: normal;
  font-feature-settings: "ss01" off;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
img {
  display: block;
  max-width: 100%;
  height: auto;
}
a {
  color: inherit;
}
button {
  font: inherit;
}
::selection {
  background: var(--fg);
  color: var(--bg);
}
:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 3px;
}


.visually-hidden {
  position: absolute !important;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.skip {
  position: fixed;
  left: var(--pad);
  top: 0.75rem;
  z-index: 100;
  padding: 0.6rem 1rem;
  background: var(--ink);
  color: var(--paper);
  border-radius: 999px;
  transform: translateY(-200%);
}
.skip:focus {
  transform: none;
}

.wrap {
  width: 100%;
  max-width: 1720px;
  margin-inline: auto;
  padding-inline: var(--pad);
}

/* Chaque grande section commence par un filet à la largeur du contenu : sans changement de fond,
   c'est lui qui structure la page (même règle que Méthode, Décisions et la fiche technique). */
.index > .wrap::before,
.career > .wrap::before,
.results > .wrap::before,
.next > .wrap::before,
.foot > .wrap::before {
  content: "";
  display: block;
  margin-bottom: clamp(2.5rem, 4vw, 3.5rem);
  border-top: 1px solid currentColor;
}

/* ------------------------------------------------------------------ Typographie */

.h-section {
  margin: 0;
  font-size: var(--fs-h2);
  font-weight: 700;
  line-height: 1.02;
  letter-spacing: -0.04em;
  text-transform: uppercase;
  text-wrap: balance;
}
.label {
  margin: 0 0 1rem;
  font-size: 0.75rem;
  font-weight: 400;
  line-height: 1.3;
  letter-spacing: 0.02em;
  text-transform: uppercase;
}
.ulink {
  display: inline-block;
  font-size: 0.9375rem;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.3em;
  transition: opacity 0.3s;
}
.ulink:hover {
  opacity: 0.6;
}

/* ------------------------------------------------------------------ En-tête */

.hdr {
  position: fixed;
  inset: 0 0 auto;
  z-index: 50;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  height: var(--hdr);
  padding: 0 var(--pad);
  background: color-mix(in srgb, var(--bg) 86%, transparent);
  color: var(--fg);
  -webkit-backdrop-filter: blur(16px) saturate(1.4);
  backdrop-filter: blur(16px) saturate(1.4);
  box-shadow: 0 1px 0 transparent;
  transition: box-shadow 0.3s;
}
.is-scrolled .hdr {
  box-shadow: 0 1px 0 var(--line);
}
[data-menu="open"] .hdr {
  background: transparent;
  box-shadow: none;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}
.hdr-name {
  /* Le nom comme un logotype : capitales grasses et serrées, comme les grands titres. */
  justify-self: start;
  font-size: 1.25rem;
  font-weight: 700;
  line-height: 1;
  letter-spacing: -0.035em;
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
}
/* Retour : en haut de chaque étude, un simple lien vers le haut de l'accueil. */
.back {
  align-self: flex-start;
  gap: 0.6rem;
  margin-bottom: auto;
}
.back-arrow {
  display: block;
  width: 1.25rem;
}
.back-arrow svg path {
  stroke-width: 2.9;
}
.back-arrow svg {
  display: block;
  width: 100%;
  height: auto;
  transform: scaleX(-1);
}
.hdr-nav {
  display: flex;
  gap: 2rem;
}
.hdr-nav a {
  position: relative;
  font-size: 0.9375rem;
  text-decoration: none;
  opacity: 0.72;
  transition: opacity 0.2s;
}
.hdr-nav a:hover,
.hdr-nav a[aria-current="true"] {
  opacity: 1;
}
.hdr-right {
  justify-self: end;
  display: flex;
  align-items: center;
  gap: 1rem;
}
.btn {
  display: inline-flex;
  align-items: center;
  height: 2.25rem;
  padding: 0 1.1rem;
  border: 1px solid currentColor;
  border-radius: 999px;
  font-size: 0.9375rem;
  font-weight: 500;
  line-height: 1;
  text-decoration: none;
  white-space: nowrap;
  transition: background-color 0.25s, color 0.25s, transform 0.15s;
}
.btn:hover {
  background: var(--fg);
  color: var(--bg);
}
.btn:active {
  transform: scale(0.98);
}
.toggle {
  position: relative;
  display: none;
  width: 44px;
  height: 44px;
  margin-right: -10px;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  cursor: pointer;
}
.toggle span {
  position: absolute;
  left: 10px;
  right: 10px;
  height: 1.5px;
  background: currentColor;
  transition: transform 0.5s var(--ease-out);
}
/* Contraste forcé (Windows) : les fonds sont neutralisés, le trait doit rester visible. */
@media (forced-colors: active) {
  .toggle span {
    background: CanvasText;
  }
}
.toggle span:first-child {
  top: 17px;
}
.toggle span:last-child {
  bottom: 17px;
}
[data-menu="open"] .toggle span:first-child {
  transform: translateY(4.25px) rotate(18deg);
}
[data-menu="open"] .toggle span:last-child {
  transform: translateY(-4.25px) rotate(-18deg);
}

/* ------------------------------------------------------------------ Menu plein écran */

.menu {
  position: fixed;
  inset: 0;
  z-index: 40;
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  gap: 2.5rem;
  overflow-y: auto;
  padding: calc(var(--hdr) + 3rem) var(--pad) var(--pad);
  background: var(--paper);
  color: var(--ink);
  visibility: hidden;
  clip-path: inset(0 0 100% 0);
  transition: clip-path 0.8s var(--ease-out), visibility 0s linear 0.8s;
}
/* En fenêtre basse (paysage téléphone, zoom 200 %), le menu défile ; sinon, les liens restent en bas. */
.menu-nav {
  margin-top: auto;
}
[data-menu="open"] .menu {
  visibility: visible;
  clip-path: inset(0);
  transition: clip-path 0.8s var(--ease-out);
}
.menu-nav ul {
  margin: 0;
  padding: 0;
  list-style: none;
}
.menu-nav li {
  overflow: hidden;
}
.menu-nav a {
  display: inline-block;
  font-size: clamp(3rem, 10vw, 9.5rem);
  font-weight: 700;
  line-height: 1.02;
  letter-spacing: -0.05em;
  text-transform: uppercase;
  text-decoration: none;
  transform: translateY(100%);
  transition: transform 0.8s var(--ease-out), opacity 0.3s;
}
[data-menu="open"] .menu-nav a {
  transform: none;
  transition-delay: calc(0.12s + var(--i, 0) * 0.06s), 0s;
}
.menu-nav a:hover {
  opacity: 0.45;
}
.menu-foot {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 2rem;
  font-size: 0.875rem;
}
.menu-foot a {
  display: inline-block;
  padding-block: 0.4rem;
  text-decoration: none;
}
.menu-foot a:hover {
  text-decoration: underline;
}

/* ------------------------------------------------------------------ Accueil : premier écran
   Le titre seul, ancré en bas de la fenêtre : rien ne dépasse du premier écran. */

.hero {
  padding-top: var(--hdr);
}
.hero-inner {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  height: calc(100svh - var(--hdr));
  min-height: 480px;
  padding-bottom: clamp(2.5rem, 8vh, 5.5rem);
}
.hero-title {
  max-width: 22ch;
  margin: 0;
  font-size: var(--fs-display);
  font-weight: 700;
  line-height: 1.02;
  letter-spacing: -0.045em;
  text-transform: uppercase;
  text-wrap: balance;
}
.hero-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.75rem 2rem;
  margin-top: clamp(1.5rem, 4vh, 2.5rem);
}
.hero-sub {
  max-width: 52ch;
  margin: 0;
  font-size: clamp(1.0625rem, 1.3vw, 1.25rem);
  line-height: 1.45;
  text-wrap: pretty;
}
.hero-avail {
  margin: 0.6rem 0 0;
  font-size: 0.9375rem;
  line-height: 1.45;
  opacity: 0.7;
  text-wrap: pretty;
}
.w {
  display: inline-block;
  overflow: hidden;
  vertical-align: top;
  /* Réserve pour les accents (É) et les jambages, sans changer l'interligne. */
  padding: 0.14em 0 0.08em;
  margin: -0.14em 0 -0.08em;
}
.w > span {
  display: inline-block;
  animation: rise 0.7s var(--ease-out) both;
  animation-delay: calc(0.05s + var(--i) * 0.035s);
}
@keyframes rise {
  from {
    transform: translateY(110%);
  }
}
/* Accueil : un + noir pivote et se pose devant le titre, les mots montent dans son sillage, puis il
   tourne de 45° et s'efface ; son espace se referme et le titre se cale à gauche. Dessiné en deux
   barres (épaisseur proche des fûts de Geist 700), à la taille des capitales. */
.hero-plus {
  position: relative;
  display: inline-block;
  width: 0.56em;
  height: 0.56em;
  margin-right: 0.18em;
  vertical-align: 0.08em;
}
.hero-plus::before,
.hero-plus::after {
  content: "";
  position: absolute;
  background: currentColor;
}
.hero-plus::before {
  top: calc(50% - 0.0575em);
  right: 0;
  left: 0;
  height: 0.115em;
}
.hero-plus::after {
  top: 0;
  bottom: 0;
  left: calc(50% - 0.0575em);
  width: 0.115em;
}
.js .hero-plus {
  opacity: 0;
  transform: rotate(-90deg) scale(0.4);
  animation:
    plus-in 0.4s var(--ease-out) 0.05s forwards,
    plus-out 0.35s var(--ease) 1.5s forwards,
    plus-gone 0.3s var(--ease) 1.85s forwards;
}
/* Les mots du titre attendent que le + soit posé ; les autres apparitions gardent la cadence de base. */
.js .hero-title .w > span {
  animation-delay: calc(0.45s + var(--i) * 0.06s);
}
@keyframes plus-in {
  to {
    opacity: 1;
    transform: none;
  }
}
@keyframes plus-out {
  to {
    opacity: 0;
    transform: rotate(45deg) scale(0.3);
  }
}
@keyframes plus-gone {
  from {
    opacity: 0;
  }
  to {
    width: 0;
    margin-right: 0;
    opacity: 0;
  }
}
.no-js .hero-plus {
  display: none;
}
/* Les noms du parcours et « M'écrire. » apparaissent comme le titre de l'accueil, quand leur bloc
   arrive à l'écran (le script pose is-in). Sans script, ils sont affichés d'emblée. */
.js [data-reveal] .w > span {
  animation: none;
  transform: translateY(110%);
}
.js [data-reveal].is-in .w > span {
  transform: none;
  animation: rise 0.7s var(--ease-out) both;
  animation-delay: calc(0.05s + var(--i) * 0.035s);
}
/* La flèche de « M'écrire. » glisse au survol : son masque lui laisse la place. */
.foot-big .w {
  padding-inline-end: 0.12em;
  padding-bottom: 0.16em;
  margin-inline-end: -0.12em;
  margin-bottom: -0.16em;
}

/* ------------------------------------------------------------------ Accueil : le défilé, en grand
   Toute la largeur, et toute l'image tient dans la hauteur de l'écran avec sa barre de légende. */

.showcase {
  position: relative;
  padding-top: clamp(1rem, 3vw, 2.5rem);
}
.reel-frame {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  max-height: calc(100svh - var(--hdr) - 6.5rem);
  min-height: 320px;
  overflow: hidden;
  background: var(--ink);
}
.reel-slide {
  position: absolute;
  inset: 0;
}
.reel.is-live .reel-slide {
  opacity: 0;
  transition: opacity 0.5s var(--ease);
}
.reel.is-live .reel-slide.is-on {
  opacity: 1;
}
.reel.is-live .reel-slide:not(.is-on, .is-near) {
  display: none;
}
.no-js .reel-slide:not(:first-child),
.reel:not(.is-live) .reel-slide:not(:first-child) {
  display: none;
}
.reel-slide .stage {
  position: absolute;
  inset: 0;
  aspect-ratio: auto;
}
.reel-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem 2rem;
  min-height: 4rem;
  padding-top: 0.9rem;
}
.reel-link {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.25rem 1rem;
  min-height: 24px;
  text-decoration: none;
}
.reel-title {
  font-size: 1.125rem;
  font-weight: 500;
  letter-spacing: -0.02em;
}
.reel-outcome {
  font-size: 0.9375rem;
  opacity: 0.7;
}
/* Dans une étude : la légende de l'écran affiché. */
.reel-caption {
  max-width: 56ch;
  margin: 0;
  font-size: 0.9375rem;
  line-height: 1.45;
  opacity: 0.75;
}
.reel-link:hover .reel-title {
  text-decoration: underline;
  text-underline-offset: 0.2em;
}
/* Position dans le carrousel. */
.reel-count {
  flex: none;
  font-size: 0.875rem;
  font-variant-numeric: tabular-nums;
  opacity: 0.7;
}
/* La position et les flèches du carrousel ; sans script, elles n'ont pas lieu d'être. */
.reel-ctrl {
  display: flex;
  flex: none;
  align-items: center;
  gap: 1.25rem;
}
.no-js .reel-ctrl {
  display: none;
}
/* Pause des animations : un rond à côté des flèches, avec l'icône de l'action possible. */
.arrow.reel-pause {
  width: 36px;
}
.reel-pause svg {
  width: 16px;
  height: 16px;
}
.reel-pause .i-play,
.is-still .reel-pause .i-pause {
  display: none;
}
.is-still .reel-pause .i-play {
  display: block;
}
/* Un glissement horizontal du doigt change de projet ; le défilement vertical reste au navigateur. */
.reel-frame {
  touch-action: pan-y pinch-zoom;
}
/* Accueil : un aimant léger, sur ordinateur seulement. Quand on s'arrête près du carrousel, il se
   cadre en entier sous l'en-tête ; près du début d'une section, son filet se cale sous l'en-tête.
   Dans une section plus haute que l'écran, le défilement reste libre ; sur les autres pages, il
   n'y a pas d'aimant. Au doigt, il contrariait le défilement : aucun aimant sur mobile. */
@media (min-width: 901px) {
  html:has(body.page-home) {
    scroll-snap-type: y proximity;
  }
  .page-home .showcase .reel {
    scroll-snap-align: center;
  }
  .page-home :is(.works, .index > .wrap, .steps-grid, .career > .wrap, .career-grid--side) {
    scroll-snap-align: start;
  }
}

/* Dans le défilé, chaque appareil est entier et centré. */
.stage--reel .phones .phone {
  height: min(78cqh, 50cqw);
}
.stage--reel .phone {
  height: 82cqh;
}
.stage--reel .paper,
.stage--reel .sheet {
  width: min(70cqw, 124cqh);
}
.stage--reel .compare {
  width: min(82cqw, 250cqh);
}
.stage--reel .cadence {
  width: min(76cqw, 150cqh);
}

.about {
  padding-block: clamp(4.5rem, 10vw, 9rem) clamp(3rem, 6vw, 6rem);
}
.about-lead {
  max-width: 30ch;
  margin: 0;
  font-size: var(--fs-lead);
  line-height: 1.2;
  letter-spacing: -0.03em;
  text-wrap: balance;
}
.about-facts {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--gap);
  margin: clamp(2.5rem, 5vw, 4rem) 0 0;
}
.about-facts div {
  padding-top: 1rem;
  border-top: 1px solid var(--line);
}
.about-facts dt {
  margin-bottom: 0.5rem;
  font-size: var(--fs-label);
  letter-spacing: 0.02em;
  text-transform: uppercase;
  opacity: 0.6;
}
.about-facts dd {
  max-width: 34ch;
  margin: 0;
  font-size: var(--fs-body);
  line-height: 1.5;
}

/* ------------------------------------------------------------------ Accueil : projets sélectionnés */

.works {
  padding-top: clamp(4rem, 8vw, 8rem);
}
/* Les trois titres de section de l'accueil, à la même taille. */
.page-home .h-section {
  font-size: clamp(1.875rem, 2.8vw, 2.75rem);
}
.works-grid {
  display: grid;
  grid-template-columns: minmax(270px, 27%) minmax(0, 1fr);
  border-bottom: 1px solid var(--line);
}
.works-side {
  display: flex;
  flex-direction: column;
  padding: 0 var(--gap) 2.5rem 0;
  border-right: 1px solid var(--line);
}
.works-intro {
  max-width: 30ch;
  margin: 1.5rem 0 2rem;
  font-size: 0.9375rem;
  line-height: 1.5;
  opacity: 0.7;
}
.works-ctrl {
  margin-top: auto;
  padding-top: 2rem;
}
.no-js .works-ctrl {
  display: none;
}
.arrows {
  display: flex;
  gap: 0.75rem;
}
.arrow {
  display: grid;
  place-items: center;
  width: 52px;
  height: 36px;
  padding: 0;
  border: 1px solid currentColor;
  border-radius: 999px;
  background: none;
  color: inherit;
  cursor: pointer;
  transition: background-color 0.3s, color 0.3s, opacity 0.3s;
}
.arrow svg {
  width: 26px;
  height: 12px;
}
.arrow--prev svg {
  transform: scaleX(-1);
}
/* Trait effectif d'environ 1,5 px à la taille de rendu de chaque pictogramme. */
.arrow:not(.reel-pause) svg path {
  stroke-width: 2.2;
}
.arrow:not(:disabled):hover {
  background: var(--fg);
  color: var(--bg);
}
.arrow:disabled {
  opacity: 0.25;
  cursor: default;
}
.works-track {
  position: relative;
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: min(44vw, 700px);
  gap: var(--gap);
  margin: 0 calc(-1 * var(--pad)) 0 0;
  padding: 0 var(--pad) 2.5rem var(--gap);
  list-style: none;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scroll-padding-inline: var(--gap) var(--pad);
  scrollbar-width: none;
}
.works-track::-webkit-scrollbar {
  display: none;
}
.works-track.is-dragging {
  scroll-snap-type: none;
  cursor: grabbing;
}
.works-track.is-dragging a {
  pointer-events: none;
}
.slide {
  scroll-snap-align: start;
}
.slide-link {
  display: block;
  text-decoration: none;
}
.slide-link .stage > * {
  transition: scale 0.9s var(--ease-out);
}
.slide-link:hover .stage > * {
  scale: 1.035;
}
.slide-cap {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1rem;
  margin-top: 1.1rem;
}
.slide-name {
  font-size: clamp(1.125rem, 1.5vw, 1.375rem);
  font-weight: 500;
  letter-spacing: -0.025em;
}
.slide-outcome {
  display: block;
  max-width: 44ch;
  margin-top: 0.35rem;
  font-size: 0.9375rem;
  line-height: 1.45;
  opacity: 0.7;
}
.slide-stack,
.irow-stack {
  margin-top: 0.85rem;
}
.tags--sm li {
  padding: 0.2rem 0.6rem;
  font-size: 0.75rem;
}
.status {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  font-size: 0.75rem;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  white-space: nowrap;
}
.status::before {
  content: "";
  width: 0.55em;
  height: 0.55em;
  border: 1px solid currentColor;
  border-radius: 50%;
}
.status--production::before {
  background: currentColor;
}

/* Défilement épinglé : la section se fige sous l'en-tête et le défilement vertical fait glisser
   les projets vers la gauche, jusqu'au dernier ; la page reprend ensuite. Le script n'active ce
   mode que sur ordinateur, si le navigateur gère les animations liées au défilement, si les
   animations ne sont pas réduites et si la grille tient dans l'écran. Il fournit --works-shift,
   la distance à parcourir.
   La section mesure un écran de plus que cette distance : un pixel de défilement vertical,
   un pixel de glissement. */
.works.is-pinned {
  --works-top: var(--hdr);
  height: calc(100svh - var(--works-top) + var(--works-shift, 0px));
  padding-top: 0;
  view-timeline: --works block;
  view-timeline-inset: var(--works-top) 0px;
}
.works.is-pinned .works-pin {
  position: sticky;
  top: var(--works-top);
  display: flex;
  flex-direction: column;
  justify-content: center;
  height: calc(100svh - var(--works-top));
}
/* Épinglée, la piste ne défile plus elle-même ; au doigt, un glissement horizontal lui est réservé
   (le script le traduit en défilement de la page), le vertical reste au navigateur. */
.works.is-pinned .works-track {
  overflow: clip;
  scroll-snap-type: none;
  touch-action: pan-y pinch-zoom;
}
.works.is-pinned .works-ctrl {
  display: none;
}
/* La piste figée ne défile plus : sans cela, l'accroche de chaque projet s'appliquerait à la page. */
.works.is-pinned .slide {
  scroll-snap-align: none;
  animation: works-pan linear both;
  animation-timeline: --works;
  animation-range: contain 0% contain 100%;
}
@keyframes works-pan {
  to {
    translate: calc(-1 * var(--works-shift, 0px)) 0;
  }
}

/* ------------------------------------------------------------------ Accueil : autres projets */

.index {
  padding-block: clamp(4rem, 7vw, 7rem) clamp(4rem, 7vw, 7rem);
}
.index-head {
  margin-bottom: clamp(2rem, 4vw, 3.5rem);
}
.index-head p {
  max-width: 52ch;
  margin: 1.25rem 0 0;
  font-size: 0.9375rem;
  opacity: 0.7;
}
.index-body {
  display: grid;
  grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
  gap: clamp(2rem, 4vw, 4rem);
  align-items: start;
}
.index-list {
  margin: 0;
  padding: 0;
  list-style: none;
  border-bottom: 1px solid var(--line);
}
.irow {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 0.4rem 1.5rem;
  padding: clamp(1.25rem, 2vw, 1.6rem) 0;
  border-top: 1px solid var(--line);
  text-decoration: none;
}
.irow-name {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  font-size: clamp(1.5rem, 2.3vw, 2.125rem);
  font-weight: 500;
  line-height: 1.05;
  letter-spacing: -0.035em;
}
/* Chaque ligne porte sa flèche, pour se lire comme un lien ; sur ordinateur, elle s'atténue avec
   le nom tant que la ligne n'est pas active, puis avance d'un cran. */
.irow-arrow {
  display: block;
  width: 0.8em;
}
.irow-arrow svg {
  display: block;
  width: 100%;
  height: auto;
}
.irow-meta {
  align-self: center;
  font-size: var(--fs-caption);
  opacity: 0.6;
  text-align: right;
  white-space: nowrap;
}
.irow-outcome {
  grid-column: 1 / -1;
  max-width: 52ch;
  font-size: var(--fs-small);
  line-height: 1.45;
  opacity: 0.75;
}
.irow-stack {
  grid-column: 1 / -1;
  margin-top: 0.35rem;
}
/* Vignette de la ligne : seulement sur mobile, où l'aperçu à droite n'existe pas. */
.irow-thumb {
  display: none;
}
/* Sur ordinateur, où l'aperçu suit la ligne active : chaque ligne occupe environ un quart d'écran,
   le temps de regarder l'aperçu, et le nom des autres lignes s'atténue (contraste conservé). */
@media (min-width: 901px) {
  .irow {
    padding-block: clamp(2.5rem, 7svh, 4.5rem);
  }
  .irow-name {
    transition: opacity 0.35s var(--ease);
  }
  .js .irow:not(.is-active) .irow-name {
    opacity: 0.55;
  }
  .irow-arrow {
    transition: transform 0.4s var(--ease-out);
  }
  .irow.is-active .irow-arrow {
    transform: translateX(0.25em);
  }
}
/* L'aperçu ouvre l'étude du projet affiché (voir site.js) ; au clavier, les lignes de la liste. */
.js .index-preview {
  cursor: pointer;
}
.index-preview {
  position: sticky;
  top: calc(var(--hdr) + 2rem);
  aspect-ratio: 4 / 3;
  overflow: hidden;
  background: color-mix(in srgb, currentColor 6%, transparent);
}
.index-shot {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity 0.45s var(--ease);
}
.index-shot.is-on {
  opacity: 1;
}
.index-shot .stage {
  position: absolute;
  inset: 0;
  aspect-ratio: auto;
}
.index-shot .stage > * {
  transition: scale 0.8s var(--ease-out);
  scale: 1.03;
}
.index-shot.is-on .stage > * {
  scale: 1;
}

/* ------------------------------------------------------------------ Lignes numérotées (méthode, décisions) */

.steps-section {
  padding-block: clamp(4rem, 8vw, 8rem) clamp(2rem, 4vw, 4rem);
}
.steps-grid {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: var(--gap);
  padding-top: clamp(2.5rem, 4vw, 3.5rem);
  border-top: 1px solid currentColor;
}
.steps-side {
  grid-column: 1 / 5;
  align-self: start;
  position: sticky;
  top: 6.5rem;
}
.steps-side p {
  max-width: 32ch;
  margin: 1.5rem 0 0;
  font-size: 0.9375rem;
  opacity: 0.7;
}
.steps {
  grid-column: 5 / 13;
  margin: 0;
  padding: 0;
  list-style: none;
}
.step {
  display: grid;
  grid-template-columns: repeat(8, minmax(0, 1fr));
  gap: 0 var(--gap);
  padding-bottom: clamp(3rem, 6vw, 5.5rem);
}
.step:last-child {
  padding-bottom: 0;
}
.step + .step {
  padding-top: clamp(1.75rem, 3vw, 2.5rem);
  border-top: 1px solid var(--line);
}
.step-title {
  grid-column: 1 / 5;
  margin: 0;
  font-size: var(--fs-h3);
  font-weight: 400;
  line-height: 1.08;
  letter-spacing: -0.035em;
  text-wrap: balance;
}
.step-num {
  margin-right: 0.35em;
  font-variant-numeric: tabular-nums;
}
.step-num::after {
  content: ".";
}
.step-body {
  grid-column: 5 / 9;
}
.step-body > p {
  max-width: 46ch;
  margin: 0;
  line-height: 1.55;
}
.step-body > p + p,
.spec-text > p + p {
  margin-top: 1em;
}
.spec-text > p {
  margin: 0;
}
.step-media {
  grid-column: 1 / 9;
  margin-top: clamp(1.75rem, 3vw, 2.5rem);
}

.artifact {
  margin: 1.75rem 0 0;
}
.artifact-source {
  margin-bottom: 0.75rem;
  font-size: 0.75rem;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  opacity: 0.6;
}
/* Un chemin de fichier ou une commande garde sa casse. */
.artifact-source code {
  font-family: var(--mono);
  letter-spacing: 0;
  text-transform: none;
}
.artifact-lines {
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: 0.9375rem;
  line-height: 1.5;
}
.artifact-lines li {
  padding: 0.1rem 0 0.1rem 1rem;
  border-left: 1px solid currentColor;
}
.artifact-lines li + li {
  margin-top: 0.7rem;
}
.artifact-term {
  margin: 0;
  padding: 1rem 1.15rem;
  overflow-x: auto;
  background: var(--ink);
  color: var(--paper);
  font-family: var(--mono);
  font-size: 0.8125rem;
  line-height: 1.65;
}
.artifact-note {
  margin: 0.75rem 0 0;
  font-size: 0.8125rem;
  opacity: 0.6;
}

/* ------------------------------------------------------------------ Accueil : parcours */

.career {
  padding-block: clamp(3rem, 6vw, 6rem) clamp(4rem, 8vw, 8rem);
}
.orgs {
  display: flex;
  flex-wrap: wrap;
  column-gap: 0.3em;
  margin: 0 0 clamp(4rem, 9vw, 9rem);
  padding: 0;
  list-style: none;
  font-size: var(--fs-title);
  font-weight: 700;
  line-height: 1.02;
  letter-spacing: -0.05em;
  text-transform: uppercase;
}
.career-grid {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: var(--gap);
}
.career-intro {
  grid-column: 1 / 5;
  max-width: 34ch;
  margin: 0;
  font-size: 1.125rem;
  line-height: 1.45;
  opacity: 0.8;
}
.jobs {
  grid-column: 5 / 13;
  margin: 0;
  padding: 0;
  list-style: none;
}
.job {
  display: grid;
  grid-template-columns: repeat(8, minmax(0, 1fr));
  gap: 0.25rem var(--gap);
  padding: 1.2rem 0;
  border-top: 1px solid var(--line);
}
.job-period {
  grid-column: 1 / 3;
  padding-top: 0.2rem;
  font-size: 0.8125rem;
  opacity: 0.6;
}
.job-role {
  grid-column: 3 / 6;
}
.job-role h3 {
  margin: 0;
  font-size: 1.0625rem;
  font-weight: 500;
  line-height: 1.3;
  letter-spacing: -0.01em;
}
.job-role p {
  margin: 0.2rem 0 0;
  font-size: 0.9375rem;
  opacity: 0.65;
}
.job-text {
  grid-column: 6 / 9;
  margin: 0;
  font-size: 0.9375rem;
  line-height: 1.5;
  opacity: 0.8;
}
.job-text a {
  text-underline-offset: 0.2em;
}
.career-grid--side {
  margin-top: clamp(3.5rem, 7vw, 6rem);
}
.career-grid--side > div:first-child {
  grid-column: 1 / 7;
}
.career-grid--side > div:last-child {
  grid-column: 7 / 13;
}
.jobs--compact .job {
  grid-template-columns: 7.5rem minmax(0, 1fr);
}
.jobs--compact .job-period {
  grid-column: 1;
  grid-row: 1 / 3;
}
.jobs--compact .job-role,
.jobs--compact .job-text {
  grid-column: 2;
}
.jobs--compact .job-text:empty {
  display: none;
}
/* Sans date (engagements bénévoles), l'intitulé et le texte prennent toute la largeur. */
.jobs--compact .job--undated :is(.job-role, .job-text) {
  grid-column: 1 / -1;
}

/* ------------------------------------------------------------------ Pied de page */

.foot {
  padding-block: clamp(4rem, 8vw, 8rem) 2rem;
}
.foot-kicker {
  max-width: 30ch;
  margin: 0 0 1.25rem;
  font-size: var(--fs-h3);
  line-height: 1.2;
  letter-spacing: -0.025em;
}
.foot-big {
  display: inline-block;
  font-size: var(--fs-title);
  font-weight: 700;
  line-height: 1.02;
  letter-spacing: -0.05em;
  text-transform: uppercase;
  text-decoration: none;
}
.foot-arrow {
  display: inline-block;
  width: 0.56em;
  height: 0.56em;
  margin-left: 0.06em;
  vertical-align: baseline;
  transition: transform 0.6s var(--ease-out);
}
.foot-arrow svg {
  display: block;
  width: 100%;
  height: 100%;
}
.foot-arrow svg,
.next-arrow svg {
  overflow: visible;
}
/* Un trait plus épais, à côté des titres gras (environ 0,06 em). */
.foot-arrow path {
  stroke-width: 2.5;
}
.next-arrow path {
  stroke-width: 4;
}
.foot-big:hover .foot-arrow {
  transform: translate(0.07em, 0.07em);
}
.foot-text {
  max-width: 46ch;
  margin: 1.75rem 0 clamp(4rem, 9vw, 8rem);
  opacity: 0.7;
}
.foot-cols {
  display: flex;
  flex-wrap: wrap;
  gap: 1.5rem clamp(2.5rem, 7vw, 7rem);
}
.foot-cols ul {
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: 0.8125rem;
  line-height: 1.7;
  text-transform: uppercase;
}
.foot-cols ul:first-child li:first-child {
  text-transform: none;
}
.foot-cols a {
  display: inline-block;
  padding-block: 0.3rem;
  text-decoration: none;
}
.foot-cols a:hover {
  text-decoration: underline;
}
.foot-legal {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 0.5rem 2rem;
  margin-top: clamp(3rem, 6vw, 5rem);
  font-size: 0.875rem;
  opacity: 0.8;
}

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

.case-intro {
  padding-top: var(--hdr);
}
/* Premier écran : le titre, l'année et la phrase de résultat, calés en bas comme le titre de
   l'accueil ; le défilé des écrans du projet vient juste en dessous. */
.case-intro-inner {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  height: calc(100svh - var(--hdr));
  min-height: 480px;
  padding-bottom: clamp(2.5rem, 8vh, 5.5rem);
}
.case-titlerow {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  gap: 1rem 2rem;
}
.case-title {
  margin: 0;
  font-size: var(--fs-case);
  font-weight: 700;
  line-height: 1.02;
  letter-spacing: -0.05em;
  text-wrap: balance;
}
.case-year {
  margin: 0;
  padding-bottom: 0.1em;
  font-size: var(--fs-figure);
  line-height: 1;
  letter-spacing: -0.04em;
  white-space: nowrap;
  opacity: 0.62;
}
.case-outcome {
  /* Deux lignes réservées : le titre est à la même hauteur d'une étude à l'autre. */
  min-height: 2.8em;
  max-width: 62ch;
  margin: 1rem 0 0;
  font-size: clamp(1.0625rem, 1.4vw, 1.3125rem);
  line-height: 1.4;
  letter-spacing: -0.01em;
  text-wrap: pretty;
}
.shot {
  margin: 0;
}
.shot figcaption {
  max-width: 56ch;
  margin-top: 0.8rem;
  font-size: 0.8125rem;
  line-height: 1.45;
  opacity: 0.65;
}
.overview {
  padding-block: clamp(4.5rem, 9vw, 8rem) 0;
}
.overview-grid {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: var(--gap);
}
.overview-side {
  grid-column: 1 / 5;
}
.overview-main {
  grid-column: 6 / 13;
}
.facts {
  margin: 0;
}
.facts div {
  padding: 0.85rem 0;
  border-top: 1px solid var(--line);
}
.facts dt {
  margin-bottom: 0.2rem;
  font-size: 0.75rem;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  opacity: 0.6;
}
.facts dd {
  margin: 0;
  line-height: 1.4;
}
.overview-lead {
  margin: 0 0 3.5rem;
  font-size: var(--fs-lead);
  line-height: 1.2;
  letter-spacing: -0.03em;
  text-wrap: pretty;
}
.overview-text {
  max-width: 60ch;
  margin: 0 0 2.75rem;
  font-size: 1.125rem;
  line-height: 1.55;
}
.constraints {
  margin: 0;
  padding: 0;
  list-style: none;
}
.constraints li {
  padding: 0.9rem 0;
  border-top: 1px solid var(--line);
  line-height: 1.45;
}

/* Sommaire d'une étude (ordinateur) : sous le carrousel, puis collé sous l'en-tête pendant la
   lecture ; la section en cours est soulignée. Sur mobile, il n'est pas affiché. */
.toc {
  display: none;
}
@media (min-width: 901px) {
  .toc {
    position: sticky;
    top: var(--hdr);
    z-index: 40;
    display: block;
    margin-top: clamp(2.5rem, 5vw, 4rem);
    border-block: 1px solid var(--line);
    background: color-mix(in srgb, var(--bg) 86%, transparent);
    -webkit-backdrop-filter: blur(16px) saturate(1.4);
    backdrop-filter: blur(16px) saturate(1.4);
  }
  .toc-list {
    display: flex;
    align-items: center;
    gap: 0.5rem 2rem;
    height: var(--toc);
    margin: 0;
    padding: 0;
    list-style: none;
    font-size: 0.875rem;
  }
  .toc a {
    display: inline-flex;
    align-items: center;
    min-height: 24px;
    text-decoration: none;
    opacity: 0.65;
    transition: opacity 0.2s;
  }
  .toc a:hover,
  .toc a[aria-current="true"] {
    opacity: 1;
  }
  .toc a[aria-current="true"] {
    text-decoration: underline;
    text-underline-offset: 0.35em;
  }
  html:has(body.page-case) {
    scroll-padding-top: calc(var(--hdr) + var(--toc) + 1.5rem);
  }
  .page-case .steps-side {
    top: calc(var(--hdr) + var(--toc) + 2.5rem);
  }
}

.tech {
  padding-block: clamp(4.5rem, 9vw, 8rem) 0;
}
.spec {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: var(--gap);
  padding: clamp(1.75rem, 3vw, 2.5rem) 0;
  border-top: 1px solid var(--line);
}
.spec:first-child {
  border-top-color: currentColor;
}
.spec-title {
  grid-column: 1 / 5;
  margin: 0;
  font-size: var(--fs-h3);
  font-weight: 400;
  line-height: 1.1;
  letter-spacing: -0.03em;
}
.spec-text,
.spec-list,
.stack-table {
  grid-column: 6 / 13;
  margin: 0;
}
.spec-text {
  max-width: 62ch;
  font-size: 1.125rem;
  line-height: 1.55;
  text-wrap: pretty;
}
.spec-list {
  padding: 0;
  list-style: none;
}
/* Mêmes filets nus que les Contraintes : une liste de livrables n'est pas une séquence. */
.spec-list li {
  padding: 0 0 0.9rem;
  line-height: 1.5;
}
.spec-list li + li {
  padding-top: 0.9rem;
  border-top: 1px solid var(--line);
}
.stack-table div {
  display: grid;
  grid-template-columns: minmax(8rem, 12rem) minmax(0, 1fr);
  gap: 0.5rem 1.5rem;
  padding: 0.8rem 0;
}
.stack-table div + div {
  border-top: 1px solid var(--line);
}
.stack-table dt {
  padding-top: 0.35rem;
  font-size: 0.8125rem;
  opacity: 0.6;
}
.stack-table dd {
  margin: 0;
}
.tags {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin: 0;
  padding: 0;
  list-style: none;
}
.tags li {
  padding: 0.3rem 0.75rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  font-size: 0.875rem;
  line-height: 1.3;
  white-space: nowrap;
}

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

.results {
  padding-block: clamp(4rem, 7vw, 7rem) clamp(3rem, 5vw, 5rem);
}
/* Autant de colonnes que de chiffres ; quatre chiffres passent en deux lignes de deux sur écran moyen. */
.figures {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 2rem var(--gap);
  margin: clamp(2.5rem, 5vw, 4.5rem) 0;
}
.figures--3 {
  grid-template-columns: repeat(3, minmax(0, 1fr));
}
.figures--2 {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
.figures div {
  padding-top: 1rem;
  border-top: 1px solid currentColor;
}
.figures dt {
  font-size: var(--fs-figure);
  font-weight: 700;
  line-height: 0.95;
  letter-spacing: -0.05em;
}
.figures dd {
  max-width: 30ch;
  margin: 0.85rem 0 0;
  font-size: 0.9375rem;
  line-height: 1.45;
  opacity: 0.7;
}
.results-text {
  max-width: 58ch;
  margin: 2rem 0 clamp(3.5rem, 7vw, 6rem);
  font-size: 1.125rem;
  line-height: 1.55;
}
.case-note {
  max-width: 62ch;
  margin: 3rem 0 0;
  font-size: 0.9375rem;
  opacity: 0.75;
}
.case-note a {
  text-underline-offset: 0.2em;
}

/* Projet suivant : bien visible, avec l'image du projet ; tout le bloc mène à l'étude. */
.next {
  padding-top: clamp(3rem, 6vw, 6rem);
}
.next-link {
  display: grid;
  grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
  gap: var(--gap);
  align-items: center;
  margin-bottom: 2rem;
  text-decoration: none;
}
.next-label {
  display: block;
  margin-bottom: 1.25rem;
  font-size: var(--fs-h3);
  font-weight: 500;
  line-height: 1.1;
  letter-spacing: -0.02em;
}
.next-count {
  margin-left: 0.4em;
  font-variant-numeric: tabular-nums;
  opacity: 0.7;
}
.next-shot .stage > * {
  transition: scale 0.9s var(--ease-out);
}
.next-link:hover .next-shot .stage > * {
  scale: 1.035;
}
.next-more {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem 2rem;
}
.next-name {
  display: inline-flex;
  align-items: center;
  gap: 0.25em;
  font-size: var(--fs-title);
  font-weight: 700;
  line-height: 1.02;
  letter-spacing: -0.05em;
}
.next-arrow {
  display: block;
  width: 0.55em;
  transition: transform 0.6s var(--ease-out);
}
.next-arrow svg {
  display: block;
  width: 100%;
  height: auto;
}
.next-link:hover .next-arrow {
  transform: translateX(0.12em);
}
.next-outcome {
  display: block;
  max-width: 44ch;
  margin-top: 1rem;
  font-size: 1.125rem;
  line-height: 1.4;
  opacity: 0.7;
}

.notfound {
  min-height: 72svh;
  padding-block: clamp(9rem, 22vh, 14rem) 5rem;
}
.notfound-title {
  margin: 0 0 1.5rem;
  font-size: var(--fs-display);
  font-weight: 700;
  line-height: 0.95;
  letter-spacing: -0.05em;
}
.notfound p {
  max-width: 44ch;
  font-size: 1.125rem;
}

/* ------------------------------------------------------------------ Scènes : la capture sur l'aplat du projet */

.stage {
  position: relative;
  display: grid;
  place-items: center;
  aspect-ratio: 16 / 10;
  overflow: hidden;
  container-type: size;
  background: var(--tone);
  color: var(--on);
}
.stage img {
  max-width: none;
}
.stage--slide {
  aspect-ratio: 5 / 4;
}
.stage--thumb,
.stage--mini {
  aspect-ratio: 4 / 3;
}
.stage--pair {
  aspect-ratio: 16 / 12;
}
.stage--pair.stage--phone .phone {
  height: 88cqh;
}

/* Téléphones : images déjà détourées, avec leur cadre. */
.phones {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 4cqw;
}
.phone {
  width: auto;
  filter: drop-shadow(0 2.2cqh 2.8cqh rgb(0 0 0 / 0.28));
}
.phones .phone {
  height: min(80cqh, 50cqw);
}
.stage--phone .phone {
  height: 86cqh;
}

/* Tablette : cadre noir régulier, liseré métallique, caméra au centre du bord supérieur.
   Entière et centrée dans sa scène, à la même taille d'un projet à l'autre. */
.tablet {
  position: absolute;
  left: 50%;
  top: 50%;
  width: min(76cqw, 138cqh);
  padding: 1.5cqw;
  border-radius: 2.4cqw;
  background: #0e0e10;
  box-shadow:
    0 0 0 0.22cqw #3b3b3f,
    inset 0 0 0 1px rgb(255 255 255 / 0.06),
    0 2.5cqw 6cqw rgb(0 0 0 / 0.3);
  transform: translate(-50%, -50%);
}
.tablet::before {
  content: "";
  position: absolute;
  left: 50%;
  top: 0.55cqw;
  width: 0.45cqw;
  height: 0.45cqw;
  border-radius: 50%;
  background: #26262a;
  transform: translateX(-50%);
}
.tablet img {
  /* Tous les écrans au même format (16:9) : les tablettes ont la même taille d'un projet à l'autre.
     Une capture plus haute (16:10) est calée en haut ; son bas passe sous le bord, comme une page. */
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  object-position: top;
  border-radius: 0.9cqw;
}

.tablet img.is-wide {
  object-fit: contain;
  background: var(--screen, var(--bg));
}

/* Écrans animés : la page entière qui défile, ou une courte vidéo posée sur la capture. Le script
   charge le média après la page, dans un défilé ou la visionneuse ; la capture reste en dessous et
   le média apparaît en fondu, sur la même image. */
.screen {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  border-radius: 0.9cqw;
  container-type: size;
}
/* Téléphone : l'écran sous la barre d'état, dans l'image de l'iPhone (voir PHONE_SCREEN_SIZES). */
.handset {
  position: relative;
  flex: none;
}
.screen--phone {
  position: absolute;
  top: 8.258%;
  left: 6.364%;
  width: 88.636%;
  height: 89.819%;
  aspect-ratio: auto;
  border-radius: 0 0 12.31% 12.31% / 0 0 6.05% 6.05%;
}
.live {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity 0.6s var(--ease);
}
.live.is-ready {
  opacity: 1;
}
.live--box {
  inset: auto;
}
.live img,
.live video {
  display: block;
  width: 100%;
}
.tablet .live img {
  height: auto;
  aspect-ratio: auto;
  object-fit: fill;
  border-radius: 0;
}
.live video {
  height: 100%;
  object-fit: cover;
}
/* Bord fondu en cercle : la vidéo se fond dans la capture, sans cadre visible. */
.live--round {
  mask-image: radial-gradient(closest-side, #000 92%, transparent);
}

/* Animations des écrans. Chacune va d'un état de départ à un état d'arrivée et tourne en boucle
   d'elle-même (data-motion="time", --loop : durée d'un passage) : sur l'écran affiché des carrousels,
   dans les figures des décisions, dans le projet suivant et dans la visionneuse. Le mode « scroll »,
   où elle suit le défilement (--slide-timeline), reste disponible. Avec les animations réduites, les
   écrans restent fixes. */
@property --cad {
  syntax: "<number>";
  inherits: true;
  initial-value: 6;
}
@property --wipe {
  syntax: "<number>";
  inherits: true;
  initial-value: 1;
}
@property --mp {
  syntax: "<number>";
  inherits: false;
  initial-value: 0;
}
.live--page img {
  --anim: screen-scroll;
}
/* Accueil et visionneuse : la scène n'est affichée que quelques secondes, l'arrêt sur le haut est bref. */
[data-motion="time"] .live--page img {
  --anim: screen-scroll-time;
}
/* La vidéo ne joue pas d'elle-même : le script règle sa position sur la progression de cette animation. */
.live--video video {
  --anim: motion-progress;
}
.cadence {
  --anim: cad-light;
  --loop: 6s;
}
.compare-frame--wipe {
  --anim: wipe;
  --loop: 3.5s;
}
/* Enchaînement d'écrans : le script place chaque écran (--i) selon sa position (--seq), tirée de cette
   animation ; il marque un temps d'arrêt puis glisse vers le suivant. Sur l'accueil, l'enchaînement
   tourne en boucle, sans retour en arrière. */
.live--seq {
  --anim: motion-progress;
  --m-dir: normal;
  --m-ease: linear;
  overflow: hidden;
}
.live--seq img {
  position: absolute;
  inset: 0;
  height: 100%;
  object-fit: cover;
  object-position: top;
  translate: calc((var(--i) - var(--seq, 0)) * 100%) 0;
}
/* Dans un téléphone, la page change sur place, en fondu, comme quand on navigue dans l'app. */
.screen--phone .live--seq img {
  translate: none;
  opacity: clamp(0, calc(1 - max(var(--seq, 0) - var(--i), var(--i) - var(--seq, 0))), 1);
}
@media (prefers-reduced-motion: no-preference) {
  [data-motion="time"] :is(.reel-slide.is-on, .viewer-stage) :is(.live--page img, .live--video video, .live--seq, .cadence, .compare-frame--wipe),
  :is(figure.shot, .next-shot)[data-motion="time"] :is(.live--page img, .live--video video, .live--seq, .cadence, .compare-frame--wipe) {
    animation: var(--anim) var(--loop, 8s) var(--m-ease, cubic-bezier(0.45, 0, 0.55, 1)) infinite var(--m-dir, alternate) both;
    animation-delay: var(--m-delay, 0s);
  }
  @supports (animation-timeline: view()) {
    [data-motion="scroll"] :is(.live--page img, .live--video video, .live--seq, .cadence, .compare-frame--wipe) {
      animation: var(--anim) linear both;
      animation-timeline: var(--slide-timeline, none);
    }
  }
}
/* Accueil : un arrêt d'environ 1 s, puis une vitesse de lecture constante, sans lente mise en route. */
@keyframes screen-scroll-time {
  0%,
  5% {
    translate: 0 0;
    animation-timing-function: linear;
  }
  95%,
  100% {
    translate: 0 calc(-100% + 100cqh);
  }
}
/* Une page qui défile marque d'abord un arrêt sur son haut, puis un court arrêt en bas. */
@keyframes screen-scroll {
  0%,
  14% {
    translate: 0 0;
  }
  94%,
  100% {
    translate: 0 calc(-100% + 100cqh);
  }
}
@keyframes motion-progress {
  from {
    --mp: 0;
  }
  to {
    --mp: 1;
  }
}
/* Cadence : le trait au-dessus des étapes se dessine de J+0 à J+56 ; le texte reste toujours lisible. */
@keyframes cad-light {
  from {
    --cad: 0;
  }
  to {
    --cad: 6;
  }
}
.cadence li {
  position: relative;
}
.cadence li::before {
  content: "";
  position: absolute;
  top: -2px;
  left: 0;
  right: 0;
  height: 3px;
  background: currentColor;
  transform-origin: left;
  scale: clamp(0, calc(var(--cad) - var(--n, 0)), 1) 1;
}
/* Avant / après : l'image traitée se révèle sur l'originale, derrière un fin trait. */
@keyframes wipe {
  from {
    --wipe: 0;
  }
  to {
    --wipe: 1;
  }
}
.compare-frame--wipe .compare-after {
  clip-path: inset(0 calc((1 - var(--wipe)) * 100%) 0 0);
}
.compare-frame--wipe::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: calc(var(--wipe) * 100%);
  width: 2px;
  margin-left: -1px;
  background: #fafafa;
  opacity: clamp(0, calc(min(var(--wipe), 1 - var(--wipe)) * 30), 0.9);
}
/* Support de restitution : les diapositives glissent dans le cadre de la page. */
.paper--seq {
  position: relative;
  overflow: hidden;
  box-shadow: 0 2cqw 5cqw rgb(0 0 0 / 0.3);
}
.paper--seq img {
  box-shadow: none;
}

/* Visionneuse : dans une étude, un clic sur un écran l'ouvre en grand, avec son animation qui va et
   vient d'elle-même. Au clavier : le bouton « Agrandir l'écran » du défilé, ou l'écran d'une figure.
   Sur l'accueil, un clic sur le carrousel ouvre l'étude du projet. */
.reel-frame {
  cursor: pointer;
}
.showcase--case .reel-frame {
  cursor: zoom-in;
}
.stage-zoom {
  position: absolute;
  inset: 0;
  z-index: 1;
  padding: 0;
  border: 0;
  background: none;
  cursor: zoom-in;
}
.stage-zoom:focus-visible {
  outline: 2px solid var(--fg);
  outline-offset: 4px;
}
/* Bouton du défilé : invisible jusqu'à ce qu'il reçoive le focus, comme le lien d'évitement. */
.reel-zoom {
  position: absolute;
  top: 1rem;
  left: 1rem;
  z-index: 2;
  opacity: 0;
  pointer-events: none;
}
.reel-zoom:focus-visible {
  opacity: 1;
  pointer-events: auto;
}
.reel {
  position: relative;
}
html:has(.viewer[open]) {
  overflow: hidden;
}
.viewer {
  width: 100vw;
  height: 100dvh;
  max-width: none;
  max-height: none;
  margin: 0;
  padding: clamp(4rem, 8vh, 5.5rem) var(--pad) clamp(1.5rem, 4vh, 3rem);
  border: 0;
  background: var(--paper);
  color: var(--ink);
}
.viewer[open] {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1.25rem;
}
.viewer::backdrop {
  background: rgb(12 12 13 / 0.5);
}
.viewer-body {
  display: flex;
  justify-content: center;
  width: 100%;
}
.viewer-stage {
  flex: none;
  width: min(100%, calc((100dvh - 12rem) * 16 / 9));
  aspect-ratio: 16 / 9;
}
/* Écran étroit : une scène plus haute, pour occuper l'écran du téléphone. */
@media (max-width: 600px) {
  .viewer-stage {
    width: 100%;
    aspect-ratio: 4 / 5;
  }
}
.viewer-caption {
  max-width: 72ch;
  margin: 0;
  font-size: 0.9375rem;
  line-height: 1.45;
  text-align: center;
  opacity: 0.75;
}
/* Pause des animations, aussi dans la visionneuse : le dialog rend les boutons de la page inatteignables. */
.viewer .reel-pause {
  position: absolute;
  top: clamp(1rem, 2.5vh, 1.5rem);
  left: var(--pad);
  background: var(--paper);
}
.viewer-close {
  position: absolute;
  top: clamp(1rem, 2.5vh, 1.5rem);
  right: var(--pad);
  background: var(--paper);
  color: var(--ink);
  cursor: pointer;
}
.viewer-close:hover {
  background: var(--ink);
  color: var(--paper);
}

/* Page de document, capture pleine. */
.paper,
.sheet {
  width: min(80cqw, 142cqh);
}
.paper img,
.sheet img {
  width: 100%;
  height: auto;
  box-shadow: 0 2cqw 5cqw rgb(0 0 0 / 0.3);
}
.sheet img {
  border-radius: 0.6cqw;
}

.art {
  width: min(78cqh, 80cqw);
  aspect-ratio: 1;
}
.art img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 1.2cqw;
  box-shadow: 0 2cqw 5cqw rgb(0 0 0 / 0.25);
}

/* Avant / après */
.compare {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 3cqw;
  width: min(90cqw, 300cqh);
}
.compare-label {
  display: block;
  margin-bottom: 1.4cqw;
  font-size: max(11px, 1.5cqw);
  letter-spacing: 0.02em;
  text-transform: uppercase;
}
.compare-frame {
  position: relative;
  aspect-ratio: 16 / 9;
  background: var(--fg);
  box-shadow: 0 2cqw 5cqw rgb(0 0 0 / 0.3);
}
.compare-frame img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
}

/* Cadence des relances */
.cadence {
  width: 86cqw;
}
.cadence ol {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 4cqh 2.4cqw;
  margin: 0;
  padding: 0;
  list-style: none;
}
.cadence li {
  padding-top: 1.4cqw;
  border-top: 1px solid color-mix(in srgb, currentColor 35%, transparent);
}
.cad-day {
  display: block;
  font-size: max(20px, 7cqw);
  line-height: 1;
  letter-spacing: -0.05em;
}
.cad-title {
  display: block;
  margin-top: 1cqw;
  font-size: max(11px, 2.3cqw);
  line-height: 1.25;
}

/* Scènes étroites ou verticales (mobile) : la mise en page suit la taille de la scène elle-même. */
@container (orientation: portrait) {
  .tablet {
    width: 94cqw;
  }
  /* Trois téléphones côte à côte : la plus grande hauteur qui tient dans la largeur. */
  .phones .phone,
  .stage--reel .phones .phone {
    height: min(72cqh, 58cqw);
  }
  /* Carrousel sur mobile : le document presque pleine largeur, l'avant et l'après l'un sous l'autre. */
  .stage--reel :is(.paper, .sheet) {
    width: 92cqw;
  }
  .stage--reel .compare {
    grid-template-columns: minmax(0, 1fr);
    gap: 4cqw;
    width: min(66cqw, 68cqh);
  }
}
@container (max-width: 600px) {
  .cadence ol {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 3.5cqh 5cqw;
  }
  .cadence {
    width: 84cqw;
  }
  .cad-day {
    font-size: max(22px, 9cqw);
  }
  .cad-title {
    margin-top: 1.5cqw;
    font-size: max(12px, 3.6cqw);
  }
  .cadence li {
    padding-top: 2.5cqw;
  }
}

/* ------------------------------------------------------------------ Écrans moyens et petits */

@media (max-width: 1100px) {
  .figures--4 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .hdr-nav {
    gap: 1.25rem;
  }
  .step-title {
    grid-column: 1 / -1;
  }
  .step-body {
    grid-column: 1 / -1;
    margin-top: 1rem;
  }
  .job-role {
    grid-column: 3 / 9;
  }
  .job-text {
    grid-column: 3 / 9;
  }
}

@media (max-width: 900px) {
  .hdr {
    grid-template-columns: 1fr auto;
  }
  .hdr-nav {
    display: none;
  }
  .toggle {
    display: block;
  }
  .no-js .toggle {
    display: none;
  }
  .about-facts {
    grid-template-columns: minmax(0, 1fr);
  }
  .index-body {
    grid-template-columns: minmax(0, 1fr);
  }
  .index-preview {
    display: none;
  }
  .spec {
    grid-template-columns: minmax(0, 1fr);
  }
  .spec-title,
  .spec-text,
  .spec-list,
  .stack-table {
    grid-column: 1;
  }
  .stack-table div {
    grid-template-columns: minmax(0, 1fr);
  }
  .works-grid {
    display: block;
    border-bottom: 0;
  }
  .works-side {
    padding: 0 0 2rem;
    border-right: 0;
  }
  /* Sur mobile, les projets sont les uns sous les autres : ni flèches, ni défilement horizontal. */
  .works-ctrl {
    display: none;
  }
  .works-track {
    grid-auto-flow: row;
    grid-template-columns: minmax(0, 1fr);
    row-gap: 3rem;
    margin: 0;
    padding: 0 0 2.5rem;
    overflow: visible;
    scroll-snap-type: none;
  }
  /* Sans aperçu à droite, chaque ligne a sa vignette à gauche et sa flèche au bout du nom. */
  .irow {
    grid-template-columns: 7.5rem minmax(0, 1fr);
    column-gap: 1rem;
    align-items: start;
  }
  .irow-thumb {
    display: block;
    grid-row: span 3;
  }
  .irow-name {
    justify-content: space-between;
  }
  .irow-arrow {
    flex: none;
  }
  .irow-meta,
  .irow-outcome {
    grid-column: 2;
    text-align: left;
  }
  .steps-grid,
  .career-grid,
  .overview-grid,
  .next-link {
    grid-template-columns: minmax(0, 1fr);
  }
  .steps-side,
  .steps,
  .career-intro,
  .jobs,
  .career-grid--side > div,
  .overview-side,
  .overview-main {
    grid-column: 1 !important;
  }
  .steps-side {
    position: static;
    margin-bottom: 2.5rem;
  }
  .career-intro {
    margin-bottom: 2rem;
  }
  /* Mobile : la fiche (rôle, équipe, période) vient juste après « En bref ». */
  .overview-grid {
    row-gap: 0;
  }
  .overview-main {
    display: contents;
  }
  .overview-main > * {
    order: 3;
    grid-column: 1;
  }
  .overview-main > :nth-child(-n + 2) {
    order: 1;
  }
  .overview-side {
    order: 2;
    margin-bottom: 3.5rem;
  }
  .case-titlerow {
    flex-wrap: wrap;
  }
}

@media (max-width: 600px) {
  .btn {
    height: 2.5rem;
  }
  .hero-inner {
    min-height: 520px;
  }
  /* Carré : les appareils, à leur plus grande taille dans la largeur, sans bande vide dessus et dessous. */
  .reel-frame {
    aspect-ratio: 1 / 1;
  }
  /* La légende sur toute la largeur, les commandes dessous, à droite. */
  .reel-bar {
    flex-direction: column;
    align-items: stretch;
    gap: 0.75rem;
  }
  .reel-ctrl {
    align-self: flex-end;
  }
  /* Figures des études : la tablette prend presque toute la largeur. */
  figure.shot .stage:not(.stage--pair) .tablet {
    width: min(90cqw, 150cqh);
  }
  /* La phrase de résultat reste visible sur téléphone, bornée à deux lignes. */
  .reel-outcome {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    overflow: hidden;
  }
  .hero-title {
    font-size: clamp(2.3rem, 10.6vw, 4rem);
  }
  .case-intro-inner {
    min-height: 520px;
  }
  .case-year {
    font-size: var(--fs-h3);
  }
  .job {
    grid-template-columns: minmax(0, 1fr);
  }
  .job-period,
  .job-role,
  .job-text {
    grid-column: 1 !important;
  }
  .jobs--compact .job {
    grid-template-columns: minmax(0, 1fr);
  }
  .jobs--compact .job-period {
    grid-row: auto;
  }
  .pair {
    grid-template-columns: minmax(0, 1fr);
  }
  .figures {
    grid-template-columns: minmax(0, 1fr);
  }
  .foot-big {
    font-size: clamp(2.75rem, 14vw, 4rem);
  }
}
@media (max-width: 359px) {
  .hdr-name {
    font-size: 1rem;
  }
}

/* ------------------------------------------------------------------ Transitions entre pages */

@view-transition {
  navigation: auto;
}
::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: 0.35s;
  animation-timing-function: var(--ease);
}

/* ------------------------------------------------------------------ Mouvement réduit */

/* Animations en pause (bouton des carrousels) : chaque écran s'arrête sur l'image en cours. */
.is-still :is(.live, .cadence, .compare-frame--wipe),
.is-still :is(.live, .cadence, .compare-frame--wipe) *,
.is-still .compare-frame--wipe::after {
  animation-play-state: paused !important;
}

@media (prefers-reduced-motion: reduce) {
  .reel-pause {
    display: none;
  }
  /* Les délais ne sont pas raccourcis par la règle générale : sans cette ligne, le + resterait visible. */
  .hero-plus {
    display: none;
  }
  @view-transition {
    navigation: none;
  }
  html {
    scroll-behavior: auto;
  }
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

/* ------------------------------------------------------------------ Impression
   Une étude imprimée ou enregistrée en PDF : sans en-tête, menu ni commandes, blocs non coupés. */

@media print {
  .js [data-reveal] .w > span {
    transform: none;
    animation: none;
  }
  .hdr,
  .menu,
  .skip,
  .reel-count,
  .reel-pause,
  .hero-plus,
  .toc,
  .back,
  .works-ctrl,
  .index-preview,
  .irow-arrow,
  .irow-thumb,
  .live,
  .viewer,
  .reel-zoom,
  .stage-zoom {
    display: none !important;
  }
  body {
    background: #fff;
    color: #000;
  }
  .hero,
  .case-intro {
    padding-top: 0;
  }
  .hero-inner,
  .case-intro-inner {
    height: auto;
    min-height: 0;
    padding-top: 0;
  }
  .works-track {
    display: block;
    overflow: visible;
    margin: 0;
    padding: 0;
  }
  .slide,
  .stage,
  .step,
  .spec,
  .figures div,
  .job,
  .irow {
    break-inside: avoid;
  }
  .slide + .slide {
    margin-top: 1.5rem;
  }
  a {
    text-decoration: none;
  }
}
