/* =========================================================
   AB-CONNECT — pages projet (index + fiches)
   Chargé uniquement par templates/pages/cases/*.

   Trois partis pris :
   — des lignes éditoriales pleine largeur au lieu d'une grille, parce que
     quatre projets ne remplissent pas une grille et que les titres y
     rétrécissent pour rien ;
   — chaque projet porte une couleur, reprise du marqueur de l'index
     jusqu'à la fiche entière, pour que quatre pages de même gabarit ne se
     ressemblent pas au point de se confondre ;
   — la pendule de service du reste du site (le point qui pulse) sert de
     repère de progression, au lieu d'une numérotation.

   Aucune couleur en dur ici : --case-accent et --row-accent viennent du
   contenu, tout le reste passe par les variables de style.css, sans quoi
   le thème clair casserait.
   ========================================================= */

/* Nappe colorée en haut de page. Très basse opacité et sous le contenu
   (.wrap est en z-index 3) : elle réchauffe le haut de page sans jamais
   passer devant du texte. */
.case-wash{
  position:absolute; top:0; left:0; right:0; height:520px; z-index:0;
  pointer-events:none;
  background:
    radial-gradient(720px 360px at 18% 0%,
      color-mix(in srgb, var(--case-accent, var(--signal)) 13%, transparent), transparent 70%),
    radial-gradient(520px 300px at 88% 6%,
      color-mix(in srgb, var(--case-accent, var(--signal)) 7%, transparent), transparent 72%);
}

/* ---------------------------------------------------------
   INDEX — /realisations/
   --------------------------------------------------------- */

.cases-page{ position:relative; }
.cases-page .page-hero h1{ font-size:clamp(40px,6.8vw,80px); line-height:1; letter-spacing:-.04em; max-width:100%; }
.cases-page .page-hero .lede{ max-width:56ch; font-size:18.5px; }

.cases-group{ padding:76px 0 0; }
.cases-group:last-of-type{ padding-bottom:16px; }

/* Le filet qui court entre le titre du groupe et sa note tient lieu de
   règle horizontale : une ligne pleine largeur en plus alourdirait une
   page déjà rythmée par les séparateurs de ligne. */
.cases-group-head{ display:flex; align-items:center; gap:20px; padding-bottom:20px; }
.cases-group-head h2{ order:1; font-size:clamp(19px,2.2vw,24px); letter-spacing:-.01em; white-space:nowrap; }
/* order plutôt que l'ordre du balisage : le filet doit s'intercaler entre le
   titre et sa note, or un pseudo-élément du parent ne peut qu'être placé en
   dernier dans le flux. */
.cases-group-head::after{ content:""; order:2; flex:1; height:1px; background:var(--line); }
.cases-group-note{
  order:3;
  font-family:var(--font-mono); font-size:11.5px; letter-spacing:.09em;
  text-transform:uppercase; color:var(--muted); white-space:nowrap;
}
@media (max-width:560px){
  .cases-group-head{ flex-wrap:wrap; gap:8px 20px; }
  .cases-group-head h2, .cases-group-note{ white-space:normal; }
  .cases-group-head::after{ display:none; }
}

.cases-rows{ border-top:1px solid var(--line); }
.cases-row{ border-bottom:1px solid var(--line); }

.cases-row-link{
  position:relative; display:grid;
  grid-template-columns:auto minmax(0,1fr) auto;
  align-items:start; gap:0 26px;
  padding:34px 0;
  transition:padding .45s var(--ease);
}
/* Le rail d'accent pousse la ligne vers la droite au survol : c'est ce
   décalage qui signale la ligne active, pas un fond coloré — illisible en
   thème clair et bruyant sur quatre teintes différentes. */
.cases-row-link::before{
  content:""; position:absolute; left:0; top:24px; bottom:24px; width:3px;
  border-radius:3px; background:var(--row-accent);
  transform:scaleY(0); transform-origin:top;
  transition:transform .45s var(--ease);
}
.cases-row-link:hover, .cases-row-link:focus-visible{ padding:44px 0 44px 26px; }
.cases-row-link:hover::before, .cases-row-link:focus-visible::before{ transform:scaleY(1); }

/* Halo suivant le curseur. --mx/--my sont posés par script.js ; sans JS ils
   restent centrés et l'opacité le garde invisible hors survol. */
.cases-row-glow{
  position:absolute; inset:-1px; pointer-events:none; opacity:0;
  transition:opacity .4s var(--ease);
  background:radial-gradient(360px circle at var(--mx,50%) var(--my,50%),
    color-mix(in srgb, var(--row-accent) 15%, transparent), transparent 70%);
}
.cases-row-link:hover .cases-row-glow{ opacity:1; }

.cases-row-body{ display:flex; flex-direction:column; gap:11px; min-width:0; }

.cases-row-kicker{
  display:inline-flex; align-items:center; gap:9px;
  font-family:var(--font-mono); font-size:11.5px; letter-spacing:.09em;
  text-transform:uppercase; color:var(--muted);
}
.cases-row-kicker::before{
  content:""; width:7px; height:7px; border-radius:50%; flex-shrink:0;
  background:var(--row-accent);
  box-shadow:0 0 0 3px color-mix(in srgb, var(--row-accent) 22%, transparent);
  animation:pulse-dot 2.4s ease-in-out infinite;
}

.cases-row-title{
  font-size:clamp(32px,5.2vw,62px); line-height:1; letter-spacing:-.035em;
  color:var(--ink);
  transition:color .35s var(--ease);
}
.cases-row-link:hover .cases-row-title{ color:var(--row-accent); }

.cases-row-text{ color:var(--muted); font-size:15.5px; line-height:1.62; max-width:62ch; }

.cases-row-go{
  align-self:end; display:inline-flex; align-items:center; gap:9px; white-space:nowrap;
  font-family:var(--font-mono); font-size:12.5px; letter-spacing:.05em;
  color:var(--row-accent); padding-bottom:6px;
}
.cases-row-arrow{ display:inline-block; transition:transform .35s var(--ease); }
.cases-row-link:hover .cases-row-arrow{ transform:translateX(6px); }

@media (max-width:820px){
  .cases-row-link{ gap:14px 18px; padding:28px 0; }
  .cases-row-link:hover, .cases-row-link:focus-visible{ padding:32px 0 32px 16px; }
}

/* ---------------------------------------------------------
   FICHE — /realisations/<projet>/
   --------------------------------------------------------- */

/* Toute la fiche bascule sur la couleur du projet en redéfinissant les trois
   variables de signal : eyebrow, filets, boutons et bordures suivent sans
   qu'aucune règle n'ait à être dupliquée quatre fois. L'en-tête et le pied de
   page sont hors de <main> et gardent donc le bleu de la marque. */
.case-page{
  position:relative;
  --signal: var(--case-accent);
  /* 84 % et pas moins : --signal-dim sert de bord aux cartes et aux encarts,
     et une teinte trop assombrie s'y confond avec la ligne neutre. */
  --signal-dim: color-mix(in srgb, var(--case-accent) 84%, #000);
  --signal-soft: color-mix(in srgb, var(--case-accent) 15%, transparent);
  /* Le bouton principal est un dégradé qui va de --signal à --accent-2. En
     laissant le violet du site, une fiche orange partait sur un dégradé
     orange-violet sans rapport avec elle ; on le ramène vers sa propre teinte
     tout en gardant le décalage qui fait lire un dégradé et non un aplat. */
  --accent-2: color-mix(in srgb, var(--case-accent) 55%, #7C5CFF);
}

.case-page .case-back{
  display:inline-flex; align-items:center; gap:9px; margin:6px 0 4px;
  font-family:var(--font-mono); font-size:12.5px; letter-spacing:.05em;
  color:var(--muted); transition:color .3s var(--ease);
}
.case-page .case-back:hover{ color:var(--case-accent); }
.case-back-arrow{ display:inline-block; transition:transform .3s var(--ease); }
.case-page .case-back:hover .case-back-arrow{ transform:translateX(-4px); }

.case-hero{ padding:30px 0 0; position:relative; }
.case-hero-top{ display:flex; align-items:center; gap:22px; }
.case-mark{
  display:grid; place-items:center; width:76px; height:76px; flex-shrink:0;
  border-radius:21px;
  font-family:var(--font-display); font-weight:700; font-size:32px; line-height:1;
  color:var(--case-accent);
  background:color-mix(in srgb, var(--case-accent) 12%, transparent);
  border:1px solid color-mix(in srgb, var(--case-accent) 34%, transparent);
  transition:opacity .6s var(--ease), transform .6s var(--ease);
}
.case-hero-copy{ min-width:0; }
.case-hero-copy .eyebrow{ margin-bottom:12px; }
.case-hero h1{ font-size:clamp(40px,6.8vw,84px); line-height:.98; letter-spacing:-.04em; }
.case-lede{ margin-top:24px; font-size:19px; line-height:1.55; color:var(--ink-dim); max-width:54ch; }

@media (max-width:640px){
  .case-hero-top{ gap:16px; }
  .case-mark{ width:56px; height:56px; border-radius:16px; font-size:24px; }
  .case-lede{ font-size:17px; }
}

/* Repères de tête. « Statut » est la première colonne parce qu'un visiteur
   qui prend un scénario pour une référence client doit l'apprendre ici, pas
   trois écrans plus bas. */
.case-facts{
  display:grid; grid-template-columns:repeat(auto-fit,minmax(180px,1fr));
  gap:24px 40px; margin:48px 0 0; padding:26px 0 0;
  border-top:1px solid var(--line);
}
.case-fact dt{
  font-family:var(--font-mono); font-size:11px; letter-spacing:.09em;
  text-transform:uppercase; color:var(--case-accent);
}
.case-fact dd{ margin:8px 0 0; font-size:16px; color:var(--ink); }

.case-section{ padding:92px 0 0; }
.case-section:last-of-type{ padding-bottom:12px; }
/* Le filet devant le titre remplace le numéro de section : même fonction de
   repère, sans la numérotation. */
.case-section-head{ margin-bottom:30px; max-width:none; }
.case-section-head h2{
  display:flex; align-items:center; gap:18px;
  font-size:clamp(24px,3vw,36px); letter-spacing:-.02em;
}
.case-section-head h2::before{
  content:""; width:34px; height:2px; flex-shrink:0; border-radius:2px;
  background:var(--case-accent);
}

.case-prose{ display:flex; flex-direction:column; gap:16px; max-width:66ch; }
.case-prose p{ color:var(--ink-dim); font-size:17px; line-height:1.68; }

/* Un relevé, pas un tableau. La grille auto-fit tombait à quatre colonnes dans
   un conteneur de 1180px : six entrées y laissaient deux cellules vides, et
   chaque rangée se calait sur son entrée la plus longue — une phrase de trois
   lignes traînait la hauteur d'une phrase de sept.

   Le multi-colonnes n'a ni rangées ni cellules : il équilibre les hauteurs
   lui-même et ne peut donc pas produire de trou, que la fiche compte trois,
   quatre, cinq ou six entrées. Deux colonnes et pas trois — à 1124px utiles,
   c'est la seule répartition qui garde une ligne lisible. */
.case-flow{
  columns:2; column-gap:72px;
  /* style.css ne neutralise les puces que sur ul : sans cette ligne, le
     navigateur numérote la liste par-dessus le compteur ci-dessous. */
  list-style:none;
  max-width:none; padding-left:0;
  counter-reset:case-step;
}
.case-flow li{
  counter-increment:case-step;
  /* Sans quoi le multi-colonnes coupe une entrée en deux au bas d'une colonne. */
  break-inside:avoid;
  display:grid; grid-template-columns:38px 1fr;
  margin:0 0 30px; padding:18px 0 0;
  border-top:1px solid var(--line);
  color:var(--ink-dim); font-size:16px; line-height:1.62;
}
/* Le numéro est produit par un compteur : renuméroter, insérer ou retirer une
   entrée ne demande de toucher à rien d'autre que le contenu.

   Il tient dans une gouttière au lieu d'occuper sa propre ligne : c'est un
   repère, pas un titre. `line-height` reprend la hauteur de ligne du texte
   (16 × 1.62) pour que le chiffre s'aligne sur la première ligne. */
.case-flow li::before{
  content:counter(case-step, decimal-leading-zero);
  font-family:var(--font-mono); font-size:12.5px; line-height:25.9px;
  letter-spacing:.08em; color:var(--case-accent);
}

/* Ce que le projet permet tient en trois affirmations : elles forment un seul
   objet à trois compartiments, pas trois cartes détachées. Trois cartes
   flottantes ressemblaient trop au relevé du dessus — même largeur, même gris,
   même densité — et les deux sections se lisaient comme une seule.

   Les filets sont obtenus par `gap:1px` sur un fond `--line` : un vrai
   `border-left` se tromperait de côté dès qu'une quatrième affirmation
   passerait à la ligne.

   Trois colonnes fixes et non `auto-fit` : entre 700 et 900px, `auto-fit` en
   plaçait deux et renvoyait la troisième seule à la ligne, ce qui rouvrait
   exactement le trou que cette section corrige. */
.case-outcomes{
  display:grid; grid-template-columns:1fr;
  gap:1px; background:var(--line);
  border:1px solid var(--line); border-radius:var(--radius); overflow:hidden;
}
/* Le fond `--line` du conteneur transparaîtrait dans toute piste laissée vide.
   Une quatrième affirmation prendrait donc la largeur de sa rangée plutôt que
   d'abandonner deux cellules au filet. */
.case-outcomes li:last-child{ grid-column:auto / -1; }
.case-outcomes li{
  background:linear-gradient(180deg, color-mix(in srgb, var(--case-accent) 7%, var(--bg-2)), var(--bg-2) 62%);
  padding:30px 28px 34px;
  color:var(--ink); font-size:16.5px; line-height:1.58;
}
/* Le même filet que devant les titres de section : le vocabulaire de la page
   n'a pas besoin d'un second signe pour dire « accent ». */
.case-outcomes li::before{
  content:""; display:block; width:26px; height:2px; margin-bottom:20px;
  border-radius:2px; background:var(--case-accent);
}

/* Un seul seuil pour les deux sections : sous 900px, le relevé se lirait sur
   une quarantaine de signes et le panneau perdrait sa troisième colonne. */
@media (min-width:900px){
  .case-outcomes{ grid-template-columns:repeat(3,1fr); }
}
@media (max-width:899px){
  .case-flow{ columns:1; }
}

/* ---------- projet suivant ---------- */

.case-next-section{ padding:88px 0 0; }
.case-next{
  display:flex; align-items:baseline; justify-content:space-between;
  gap:20px; flex-wrap:wrap;
  padding:34px 0 30px; border-top:1px solid var(--line);
  transition:padding .4s var(--ease);
}
.case-next:hover{ padding-left:22px; }
.case-next-label{
  font-family:var(--font-mono); font-size:11.5px; letter-spacing:.09em;
  text-transform:uppercase; color:var(--muted);
}
.case-next-name{
  display:inline-flex; align-items:center; gap:16px;
  font-family:var(--font-display); font-weight:700;
  font-size:clamp(28px,4.4vw,52px); line-height:1; letter-spacing:-.035em;
  color:var(--ink); transition:color .35s var(--ease);
}
.case-next:hover .case-next-name{ color:var(--case-accent); }
.case-next-arrow{ display:inline-block; color:var(--case-accent); transition:transform .35s var(--ease); }
.case-next:hover .case-next-arrow{ transform:translateX(8px); }

@media (prefers-reduced-motion: reduce){
  .cases-row-kicker::before{ animation:none; }
  .cases-row-link, .cases-row-link::before, .cases-row-glow,
  .cases-row-arrow, .cases-row-title, .case-back-arrow,
  .case-mark, .case-next, .case-next-name, .case-next-arrow{ transition:none; }
  .cases-row-link:hover, .cases-row-link:focus-visible{ padding:34px 0; }
  .case-next:hover{ padding-left:0; }
}

/* =========================================================
   VIGNETTES DE PROJET

   Le cadre est commun à une capture et à une scène dessinée : même bordure,
   même ombre, même rapport 8:5. templates/partials/case-visual.php décide de
   ce qu'il y met, la feuille ne fait pas la différence.

   Rien n'est peint en dur : chaque forme prend sa couleur dans les variables
   du thème, et --acc reprend l'accent de la ligne (index) ou de la fiche. Une
   même scène rend donc correctement en sombre, en clair, et dans toutes les
   teintes de projet.
   ========================================================= */

.case-scene{
  --acc: var(--row-accent, var(--case-accent, var(--signal)));
  position:relative; margin:0; overflow:hidden;
  border:1px solid var(--line); border-radius:var(--radius);
  background:
    radial-gradient(130% 100% at 50% 0%,
      color-mix(in srgb, var(--acc) 11%, transparent), transparent 72%),
    var(--bg-2);
  box-shadow:0 18px 40px -28px rgba(0,0,0,.85);
  transition:border-color .45s var(--ease), transform .45s var(--ease);
}
.case-scene .scene{ display:block; width:100%; height:auto; }

/* object-fit couvre le cadre si une capture n'est pas exactement au format,
   plutôt que de la déformer ; le haut de l'écran est ce qui compte. */
.case-scene img{
  display:block; width:100%; height:auto; aspect-ratio:8/5; object-fit:cover;
  object-position:top center;
}

/* Ride Safe est une application mobile : trois vraies captures donnent une
   lecture bien plus juste qu'un écran vertical recadré au format paysage. */
.case-device-gallery{
  display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:3.6%;
  align-items:start; height:auto; aspect-ratio:8/5; padding:5% 9%; overflow:hidden;
  background:
    radial-gradient(circle at 50% 0%, color-mix(in srgb,var(--acc) 20%,transparent), transparent 58%),
    #17191f;
}
.case-scene .case-device-gallery img{
  width:100%; height:auto; aspect-ratio:415/900; object-fit:cover; object-position:top;
  border:1px solid rgba(255,255,255,.15); border-radius:clamp(5px,1.2vw,16px);
  box-shadow:0 18px 34px rgba(0,0,0,.42);
}
.case-device-gallery img:nth-child(2){ transform:translateY(7%); }
.case-device-gallery img:nth-child(3){ transform:translateY(2%); }

/* ---------- pièces de la scène ---------- */
.scene-win rect{ fill:var(--bg); stroke:var(--line); stroke-width:1; }
.scene-win path{ fill:none; stroke:var(--line); stroke-width:1; }
.scene-win circle{ fill:var(--line); stroke:none; }
/* Spécificité descendante volontaire : .scene-omni seul perdrait contre
   « .scene-win rect » et la barre d'adresse ressortirait comme une fenêtre. */
.scene-win .scene-omni{ fill:var(--line-2); stroke:none; }

.scene-card{ fill:var(--bg-2); stroke:var(--line); stroke-width:1; }
.scene-field{ fill:var(--bg-3); stroke:var(--line); stroke-width:1; }
.scene-thumb{ fill:var(--bg-3); stroke:none; }
.scene-bar{ fill:var(--line); stroke:none; }
.scene-bar-2{ fill:var(--line-2); stroke:none; }
.scene-dot{ fill:var(--line); stroke:none; }
.scene-accent{ fill:var(--acc); stroke:none; }
.scene-glyph{ fill:none; stroke:var(--on-signal); stroke-width:2; stroke-linecap:round; stroke-linejoin:round; }

/* Le bandeau de lecture ne doit pas se lire comme une cinquième ligne de file
   d'attente : une teinte d'accent très diluée suffit à le détacher. */
.scene-now-card{
  fill:color-mix(in srgb, var(--acc) 10%, var(--bg-2));
  stroke:color-mix(in srgb, var(--acc) 32%, transparent);
}

/* La ligne « chaude » — le morceau qui vient d'être validé — se distingue par
   sa bordure et non par un fond plein : à cette échelle un aplat colorié
   mangerait tout le contraste. */
.scene-hot .scene-card{
  stroke:color-mix(in srgb, var(--acc) 55%, transparent);
  fill:color-mix(in srgb, var(--acc) 9%, var(--bg-2));
}

/* Un seul élément bouge : l'égaliseur, et une respiration lente sur le bouton
   d'ajout. Au-delà, la vignette deviendrait un panneau publicitaire. */
.scene-eq rect{
  fill:var(--acc);
  transform-box:fill-box; transform-origin:50% 100%;
  animation:scene-eq 1.05s var(--ease) infinite alternate;
}
.scene-eq rect:nth-child(2){ animation-delay:.14s; }
.scene-eq rect:nth-child(3){ animation-delay:.28s; }
.scene-eq rect:nth-child(4){ animation-delay:.42s; }
.scene-eq rect:nth-child(5){ animation-delay:.56s; }
@keyframes scene-eq{ from{ transform:scaleY(.26); } to{ transform:scaleY(1); } }

.scene-pulse{ animation:scene-pulse 3s var(--ease) infinite; }
@keyframes scene-pulse{ 0%,100%{ opacity:1; } 50%{ opacity:.52; } }

/* ---------------------------------------------------------
   La vignette dans une ligne de l'index
   --------------------------------------------------------- */

/* La vignette prend la première colonne, à la place de la pastille d'initiale
   qui occupait ce rôle : un aperçu de l'interface en dit nettement plus qu'une
   lettre. */
@media (min-width:1024px){
  .cases-row-link{
    grid-template-columns:312px minmax(0,1fr) auto;
    grid-template-areas:"scene body go";
    align-items:center;
    gap:0 36px;
  }
  .case-scene{ grid-area:scene; }
  .cases-row-body{ grid-area:body; }
  .cases-row-go{ grid-area:go; align-self:center; padding-bottom:0; }
  /* Le titre perd une quinzaine de pixels : la colonne de texte est plus
     étroite qu'avant, et un titre calibré pour la pleine largeur y passerait
     désormais sur deux lignes. */
  .cases-row-title{ font-size:clamp(30px,3.6vw,50px); }
  .cases-row-link:hover .case-scene,
  .cases-row-link:focus-visible .case-scene{
    border-color:color-mix(in srgb, var(--acc) 45%, transparent);
    transform:translateY(-4px);
  }
}

/* Colonne un peu plus étroite entre 1024 et 1200 px : à cette largeur, une
   vignette de 312 px laisserait au titre moins de place qu'il n'en faut. */
@media (min-width:1024px) and (max-width:1200px){
  .cases-row-link{ grid-template-columns:246px minmax(0,1fr) auto; gap:0 28px; }
}

/* Sous 1024 px la vignette passe au-dessus du texte, pleine largeur : la
   réduire davantage la rendrait illisible, autant lui donner la place. */
@media (max-width:1023px){
  .cases-row-link{
    grid-template-columns:minmax(0,1fr);
    grid-template-areas:
      "scene"
      "body"
      "go";
    gap:20px 0;
  }
  .case-scene{ grid-area:scene; }
  .cases-row-body{ grid-area:body; }
  .cases-row-go{ grid-area:go; align-self:start; padding-bottom:0; }
}

/* ---------------------------------------------------------
   La vignette en tête de fiche
   --------------------------------------------------------- */

/* Placée après les repères et avant le premier titre : le visiteur voit de
   quoi on parle avant de lire pourquoi. */
.case-scene-hero{ margin-top:52px; }
.case-hero-actions{ margin-top:28px; }
.case-scene-section{ margin-top:34px; }
@media (min-width:900px){
  .case-scene-hero{ border-radius:calc(var(--radius) + 6px); }
}

/* Le statut est le repère qui engage : en pastille, il se lit sans être
   cherché, alors qu'aligné avec les autres il se confondait. */
.case-facts .case-fact:first-child dd{
  display:inline-flex; align-items:center; gap:8px;
  padding:5px 13px 5px 11px; border-radius:var(--radius-pill);
  font-family:var(--font-mono); font-size:13px; letter-spacing:.02em;
  color:var(--case-accent);
  background:color-mix(in srgb, var(--case-accent) 12%, transparent);
  border:1px solid color-mix(in srgb, var(--case-accent) 38%, transparent);
}
.case-facts .case-fact:first-child dd::before{
  content:""; width:7px; height:7px; border-radius:50%; flex-shrink:0;
  background:var(--case-accent);
  box-shadow:0 0 0 3px color-mix(in srgb, var(--case-accent) 22%, transparent);
}

@media (prefers-reduced-motion: reduce){
  .scene-eq rect, .scene-pulse{ animation:none; }
  .scene-eq rect{ transform:scaleY(.62); }
  .case-scene{ transition:none; }
  .cases-row-link:hover .case-scene,
  .cases-row-link:focus-visible .case-scene{ transform:none; }
}

/* ---------------------------------------------------------
   Le halo ne doit pas se terminer sur une arête nette
   --------------------------------------------------------- */

/* Le halo est un dégradé radial centré sur le curseur, dans une boîte qui fait
   la largeur de la ligne. Curseur près d'un bord, le dégradé est encore opaque
   quand la boîte s'arrête : on voit une coupure franche. Un masque le fait
   tomber à zéro avant l'arête, où que soit le curseur.

   La coupure horizontale est la seule vraiment gênante — en haut et en bas,
   les filets de séparation font déjà une limite que l'œil attend. */
.cases-row-glow{
  -webkit-mask-image:linear-gradient(90deg, transparent 0, #000 13%, #000 87%, transparent 100%);
          mask-image:linear-gradient(90deg, transparent 0, #000 13%, #000 87%, transparent 100%);
}

/* Là où mask-composite existe, on ferme aussi le haut et le bas : sur une
   ligne haute, le halo dépasse la hauteur disponible et se coupe là aussi. */
@supports (mask-composite: intersect){
  .cases-row-glow{
    -webkit-mask-image:
      linear-gradient(90deg, transparent 0, #000 13%, #000 87%, transparent 100%),
      linear-gradient(180deg, transparent 0, #000 20%, #000 80%, transparent 100%);
            mask-image:
      linear-gradient(90deg, transparent 0, #000 13%, #000 87%, transparent 100%),
      linear-gradient(180deg, transparent 0, #000 20%, #000 80%, transparent 100%);
    -webkit-mask-composite:source-in;
            mask-composite:intersect;
  }
}

/* Give long project names the full width on phones. */
@media (max-width:640px){
  .case-hero-top{ flex-direction:column; align-items:flex-start; }
  .case-hero-copy{ width:100%; }
  .case-hero h1{ font-size:clamp(28px,8vw,44px); overflow-wrap:anywhere; }
}
