/* ============================================================
   WOLFILMZ — LE FEED v2 « VITRINE »   (brouillon 2026-08-15)
   Page portfolio repensée : galerie vivante + mode REELS plein écran.

   Hérite de theme.css (tokens charbon & verre) — aucune couleur en dur
   hors des voiles noirs de lecture. Le redesign global annoncé pourra
   tout repeindre en changeant les variables, rien d'autre.

   LOI 3 respectée : le verre est l'INTERFACE (barre, pilules, plaques,
   contrôles du lecteur). Le mur reste mat — jamais de backdrop-filter
   posé sur une carte du feed (coût GPU × 100 cartes = scroll mort).
   ============================================================ */

/* ------------------------------------------------------------
   LE VERROU QUI TUAIT LA BARRE COLLANTE
   home-noir.css pose `body.noir{overflow-x:hidden}`. Dès qu'un axe
   passe à hidden, l'autre devient `auto` : body devient un conteneur
   de défilement, et TOUT position:sticky à l'intérieur cesse de coller
   (mesuré : la barre partait à -2698 px au lieu de se figer à 68).
   `clip` coupe le débordement horizontal exactement pareil, mais ne
   crée aucune boîte de défilement — sticky revit.
   Ciblé sur cette page pour ne pas remuer les dix autres.
   ------------------------------------------------------------ */
body[data-page="work"]{overflow-x:clip}

/* Le bouton flottant REELS était MORT dans les 656 derniers pixels de la page
   sur téléphone : il est en fixed z-index:82, mais enfermé dans le contexte
   d'empilement de <main> (z-index:1), et #chrome-footer est son frère plus bas
   dans le DOM — le pied de page passait devant et avalait les taps.
   Remonter main d'un cran suffit ; ne PAS déplacer le bouton dans <body>,
   il n'est pas fixed sur desktop et retomberait sous le pied de page. */
@media (max-width:680px){
  body.noir > main{z-index:2}
}

/* le mur respire large — la page portfolio déborde du gabarit 1280 */
.wrap--wide{max-width:1760px}

/* ============================================================
   1. HERO — une ligne, un compteur, rien d'autre
   ============================================================ */
.vhero{padding:58px 0 26px;display:flex;align-items:flex-end;justify-content:space-between;gap:32px;flex-wrap:wrap}
.vhero__t{min-width:0}
.vhero .eyebrow2{margin-bottom:16px}
.vhero h1{font-family:var(--sans);font-weight:620;font-size:clamp(36px,4.4vw,62px);line-height:.98;
  letter-spacing:-.035em;margin:0;color:var(--bone)}
.vhero h1 .serif-em{font-family:var(--serif);font-style:italic;font-weight:400;letter-spacing:-.01em}
.vhero p{margin:16px 0 0;max-width:440px;font-size:15.5px;line-height:1.6;color:var(--stone)}
.vhero__m{flex:0 0 auto;text-align:right;font-family:var(--mono);font-size:9.5px;letter-spacing:var(--ls-2);
  color:var(--stone);line-height:2.1;font-variant-numeric:tabular-nums}
.vhero__m b{display:block;font-weight:500;font-size:34px;letter-spacing:-.02em;color:var(--bone);line-height:1}
.vhero__m .l1,.vhero__m .l2{display:block}
/* Sur iPhone le hero mangeait tout le premier écran : titre + phrase +
   compteur sur trois lignes, et le mur commençait sous le pli. On resserre,
   et le compteur redevient une seule ligne de service. */
@media (max-width:760px){
  .vhero{padding:34px 0 16px;gap:14px}
  .vhero p{margin-top:12px;font-size:14.5px;max-width:34ch}
  .vhero__m{text-align:left;display:flex;align-items:baseline;gap:9px;line-height:1.4;font-size:9px}
  .vhero__m b{display:inline;font-size:19px}
  .vhero__m .l2{display:none}   /* MONTRÉAL / STATUS vit déjà dans le pied de page */
}
/* le plus petit : on ne garde que le nombre, le reste est du décor */
@media (max-width:430px){
  .vhero h1{font-size:33px}
  .vhero__m{font-size:8.5px}
}

/* ============================================================
   2. LA BARRE — verre, collante, segmented control iOS
   ============================================================ */
.vbar{position:sticky;top:64px;z-index:60;display:flex;align-items:center;gap:12px;
  padding:12px 0;margin-bottom:var(--s5)}
/* le voile évite que les cartes traversent le verre en transparence */
.vbar::before{content:"";position:absolute;inset:-12px 0 0;z-index:-1;pointer-events:none;
  background:linear-gradient(180deg,var(--coal-0) 58%,rgba(6,6,6,.72) 82%,transparent)}

/* -- segmented control : la pilule GLISSE d'un onglet à l'autre -- */
/* flex:1 1 auto + min-width:0 est ce qui autorise la barre à RÉTRÉCIR au lieu
   de pousser le bouton REELS hors de l'écran : sans ça, sur iPhone, la liste
   des catégories est coupée net en plein milieu d'un mot. */
.vseg{position:relative;display:flex;align-items:center;gap:2px;padding:4px;border-radius:999px;
  flex:1 1 auto;min-width:0;
  background:var(--glass-bg);border:1px solid var(--glass-brd);box-shadow:var(--glass-hl);
  -webkit-backdrop-filter:blur(var(--glass-blur)) saturate(1.35);
          backdrop-filter:blur(var(--glass-blur)) saturate(1.35);
  overflow-x:auto;scrollbar-width:none;-ms-overflow-style:none;scroll-behavior:smooth}
.vseg::-webkit-scrollbar{display:none}
/* la pastille garde sa taille de dessin même quand l'onglet monte à 44 px de
   cible tactile — on ne veut pas d'une pilule qui grossit, juste une zone
   d'appui qui respecte le minimum d'Apple */
.vseg i{position:absolute;top:calc(50% - 15.5px);left:0;height:31px;border-radius:999px;pointer-events:none;
  background:linear-gradient(180deg,var(--ember-hi),var(--ember) 62%,var(--ember-lo));
  box-shadow:inset 0 1px 0 rgba(255,255,255,.34),0 8px 22px -10px rgba(177,183,180,.65);
  transform:translateX(var(--x,0));width:var(--w,0);
  transition:transform .52s cubic-bezier(.22,1.2,.36,1),width .52s cubic-bezier(.22,1.2,.36,1)}
/* min-height:44px — le minimum d'Apple pour une cible tactile. Sans lui,
   l'onglet fait 31 px : on vise MUSIC, on touche EVENTS. Le padding de .vseg
   n'est PAS touché, sinon la pilule (asservie à lui) se désaligne. */
.vseg b{position:relative;z-index:1;flex:0 0 auto;cursor:pointer;white-space:nowrap;
  font-family:var(--mono);font-weight:500;font-size:10px;letter-spacing:var(--ls-2);color:var(--stone);
  padding:9px 15px;min-height:44px;display:flex;align-items:center;
  border-radius:999px;transition:color .34s var(--ease)}
.vseg b:hover{color:var(--bone)}
.vseg b.on{color:#0B0B0C}
.vseg b:focus-visible{outline:2px solid var(--white-led);outline-offset:2px}
.vseg b s{text-decoration:none;opacity:.55;margin-left:6px;font-size:9px;font-variant-numeric:tabular-nums}
.vseg b.on s{opacity:.6}
/* la pilule ne glisse pas au premier rendu — elle se pose */
.vseg.noanim i{transition:none}

/* -- le bouton REELS : l'entrée du plein écran -- */
.vreels{flex:0 0 auto;margin-left:auto;display:inline-flex;align-items:center;gap:9px;cursor:pointer;
  font-family:var(--mono);font-size:10px;letter-spacing:var(--ls-2);color:var(--bone);
  padding:10px 17px;border-radius:999px;
  background:var(--glass-bg);border:1px solid var(--glass-brd);box-shadow:var(--glass-hl);
  -webkit-backdrop-filter:blur(var(--glass-blur)) saturate(1.35);
          backdrop-filter:blur(var(--glass-blur)) saturate(1.35);
  transition:border-color .3s var(--ease),color .3s var(--ease),transform .3s var(--ease)}
.vreels:hover{transform:translateY(-1px);border-color:rgba(201,207,204,.42)}
.vreels:focus-visible{outline:2px solid var(--white-led);outline-offset:2px}
.vreels svg{display:block;flex:0 0 auto}
.vreels em{font-style:normal;color:var(--stone);font-variant-numeric:tabular-nums}
.vreels[hidden]{display:none}

@media (max-width:900px){
  .vbar{top:68px;gap:8px;padding:10px 0}
  .vreels{padding:10px 13px}
  .vreels em{display:none}
}
/* Neuf catégories font 890 px de large : sur un écran de 375 px il FAUT
   défiler. Ce qui ne doit pas arriver, c'est que ça ait l'air cassé —
   d'où le fondu au bord droit, qui dit « ça continue » au lieu de couper
   un mot en deux.
   Et le bouton REELS quitte la barre : en icône muette personne ne cliquerait
   dessus, et avec son libellé il volait 90 px aux catégories. Il devient un
   bouton flottant au-dessus de la tabbar — visible pendant tout le défilement,
   ce qui rend le mode plein écran bien plus découvrable qu'en haut de page. */
@media (max-width:680px){
  .vbar{gap:0}
  /* Fondu des DEUX côtés, posé par feed-v2.js selon la position de défilement.
     Un masque figé à droite seulement laissait un mot tranché net à gauche dès
     qu'on faisait glisser la barre, et REELS n'était jamais pleinement opaque
     en fin de course. À 0 px les deux bornes se superposent : masque opaque,
     aucun fondu parasite quand tout tient à l'écran. */
  .vseg{--fadeL:0px;--fadeR:0px;
    -webkit-mask:linear-gradient(90deg,transparent 0,#000 var(--fadeL),#000 calc(100% - var(--fadeR)),transparent 100%);
            mask:linear-gradient(90deg,transparent 0,#000 var(--fadeL),#000 calc(100% - var(--fadeR)),transparent 100%)}
  .vseg.f-l{--fadeL:26px}
  .vseg.f-r{--fadeR:34px}
  .vseg b{padding:9px 13px}
  .vreels{position:fixed;z-index:82;right:16px;margin-left:0;min-height:44px;
    bottom:calc(env(safe-area-inset-bottom) + 92px);
    padding:11px 16px;background:linear-gradient(180deg,var(--ember-hi),var(--ember) 62%,var(--ember-lo));
    color:#0B0B0C;border-color:transparent;
    box-shadow:inset 0 1px 0 rgba(255,255,255,.34),0 14px 34px -12px rgba(0,0,0,.9)}
  .vreels em{display:inline;color:rgba(11,11,12,.6)}
  /* le mur ne doit pas finir sous la tabbar flottante */
  #vwall{padding-bottom:calc(env(safe-area-inset-bottom) + 120px)}
}
/* tactile : le verre posé sur un voile quasi opaque ne se voit pas — on le coupe.
   La borne min-width est là exprès : en dessous de 680 px le bouton REELS n'est
   plus dans la barre mais flottant, et il garde son fond plein (voir plus haut).
   Sans cette borne, ce bloc le repeignait en gris et il devenait invisible. */
@media (hover:none){
  .vseg{-webkit-backdrop-filter:none;backdrop-filter:none;background:rgba(20,20,22,.88)}
}
@media (hover:none) and (min-width:681px){
  .vreels{-webkit-backdrop-filter:none;backdrop-filter:none;background:rgba(20,20,22,.88)}
}

/* ============================================================
   3. SPOTLIGHT — la pièce d'ouverture, pleine largeur
   ============================================================ */
/* le plafond de hauteur est la règle du feed : on doit TOUJOURS voir le
   haut de la mosaïque sans scroller — une ouverture, pas une page d'accueil */
.vspot{position:relative;display:block;width:100%;margin:0 0 22px;padding:0;border:0;cursor:pointer;
  border-radius:var(--r-xl);overflow:hidden;background:#0B0B0D;
  aspect-ratio:2.4;max-height:min(58vh,520px);-webkit-tap-highlight-color:transparent}
.vspot::after{content:"";position:absolute;inset:0;pointer-events:none;border-radius:inherit;
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.08)}
.vspot img,.vspot video{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block;
  filter:saturate(.95) contrast(1.03) brightness(.9)}
.vspot video{opacity:0;transition:opacity .7s var(--ease)}
.vspot video.on{opacity:1}
.vspot__g{position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(90deg,rgba(6,6,6,.86) 4%,rgba(6,6,6,.42) 44%,transparent 72%),
             linear-gradient(0deg,rgba(6,6,6,.72),transparent 46%)}
.vspot__c{position:absolute;left:clamp(20px,3.4vw,48px);bottom:clamp(20px,3vw,44px);right:clamp(20px,3.4vw,48px);
  text-align:left;pointer-events:none}
.vspot .eb{font-family:var(--mono);font-size:9px;letter-spacing:var(--ls-3);color:var(--led-hot);margin-bottom:12px}
/* balance + pas de césure : sans ça « GEORGES ST-PIERRE » se casse en
   « GEORGES ST- / PIERRE » au trait d'union — une coupure qui saute aux yeux */
.vspot h2{font-family:var(--sans);font-weight:620;font-size:clamp(24px,3.4vw,46px);line-height:1.02;
  letter-spacing:-.03em;margin:0;color:var(--bone);max-width:min(22ch,52%);
  text-wrap:balance;hyphens:none;overflow-wrap:normal;word-break:keep-all}
.vspot .sub{margin-top:10px;font-family:var(--mono);font-size:9.5px;letter-spacing:var(--ls-2);
  color:rgba(239,241,240,.66);text-transform:uppercase}
.vspot .go{position:absolute;right:0;bottom:2px;display:inline-flex;align-items:center;gap:9px;
  font-family:var(--mono);font-size:9.5px;letter-spacing:var(--ls-2);color:var(--bone);
  padding:11px 18px;border-radius:999px;
  background:var(--glass-bg);border:1px solid var(--glass-brd);box-shadow:var(--glass-hl);
  -webkit-backdrop-filter:blur(16px) saturate(1.3);backdrop-filter:blur(16px) saturate(1.3);
  transition:background-color .3s var(--ease),color .3s var(--ease)}
.vspot:hover .go{background:var(--ember);color:#0B0B0C;border-color:transparent}
.vspot:focus-visible{outline:2px solid var(--white-led);outline-offset:3px}
@media (max-width:900px){
  .vspot{aspect-ratio:1.5;border-radius:var(--r-l)}
  .vspot__g{background:linear-gradient(0deg,rgba(6,6,6,.9) 8%,rgba(6,6,6,.3) 52%,transparent 76%)}
  .vspot .go{position:static;display:none}
  .vspot h2{max-width:none}
}

/* ============================================================
   4. LA MOSAÏQUE — rangées justifiées à rythme variable
   ============================================================ */
#vwall{padding-bottom:var(--s8);min-height:60vh}
/* PAS de content-visibility ici, contrairement au feed v1 — deux raisons :
   1. le contenu « sauté » est invisible pour l'IntersectionObserver, donc
      l'autoplay ne verrait jamais aucune carte entrer à l'écran ;
   2. nos rangées vont de 240 à 520 px de haut : une hauteur estimée unique
      ferait sauter la barre de défilement à chaque rangée révélée.
   La perte est nulle en pratique : les covers sont en loading="lazy", une
   seule vidéo joue à la fois, et aucune carte ne porte de backdrop-filter. */
.vrow{display:flex;gap:12px;align-items:stretch;margin-bottom:12px}
/* une carte n'occupe jamais seule toute la largeur */
.vrow .vcard[data-vert]:only-child{flex:0 1 auto;width:min(400px,64%);margin-inline:auto}
.vrow .vcard:not([data-vert]):only-child{flex:0 1 auto;width:min(940px,82%);margin-inline:auto}

/* ---------- la carte ---------- */
.vcard{flex:var(--ar) 1 0;min-width:0;position:relative;cursor:pointer;
  -webkit-tap-highlight-color:transparent}
.vcard.still{cursor:default}
.vcard .m{position:relative;aspect-ratio:var(--ar);border-radius:16px;overflow:hidden;background:#0A0A0C;
  transform:translateZ(0);
  transition:transform .5s var(--ease),box-shadow .5s var(--ease)}
/* le liseré de verre : posé en inset, il ne déclenche aucun repaint au hover */
.vcard .m::after{content:"";position:absolute;inset:0;z-index:3;pointer-events:none;border-radius:inherit;
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.07),inset 0 1px 0 rgba(255,255,255,.06);
  transition:box-shadow .5s var(--ease)}
.vcard .m img{width:100%;height:100%;object-fit:cover;display:block;
  filter:saturate(.86) contrast(1.04) brightness(.86);
  transition:transform .8s var(--ease),filter .6s var(--ease)}

/* ---------- l'état VIVANT : la carte la plus centrée à l'écran ----------
   posé par feed-v2.js, un seul .live sur la page à la fois */
.vcard.live .m{box-shadow:0 22px 54px -26px rgba(0,0,0,.95),0 0 0 1px rgba(201,207,204,.16)}
.vcard.live .m::after{box-shadow:inset 0 0 0 1px rgba(201,207,204,.34),inset 0 1px 0 rgba(255,255,255,.14)}
.vcard.live .m img{filter:saturate(1) contrast(1.04) brightness(1)}
/* pièce sans aperçu vidéo : la cover respire lentement — le mur reste vivant */
.vcard.live.breathe .m img{transform:scale(1.055);transition:transform 9s linear}

/* ---------- l'aperçu muet ---------- */
.vcard .pv{position:absolute;inset:0;z-index:1;width:100%;height:100%;border:0;display:block;
  object-fit:cover;background:#0A0A0C;opacity:0;pointer-events:none;
  transition:opacity .55s var(--ease)}
.vcard .pv.on{opacity:1}

/* ---------- la plaque de titre (verre — interface) ---------- */
.vplate{position:absolute;left:10px;right:10px;bottom:10px;z-index:2;pointer-events:none;
  display:flex;align-items:center;justify-content:space-between;gap:10px;
  padding:9px 13px;border-radius:12px;
  background:linear-gradient(180deg,rgba(12,12,14,.72),rgba(8,8,10,.82));
  border:1px solid rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.08);
  opacity:0;transform:translateY(7px);
  transition:opacity .38s var(--ease),transform .38s var(--ease)}
.vcard.live .vplate,.vcard:hover .vplate,.vcard:focus-visible .vplate{opacity:1;transform:none}
.vplate .t{min-width:0}
.vplate b{display:block;font-family:var(--sans);font-weight:620;font-size:13.5px;letter-spacing:-.012em;
  color:var(--bone);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.vplate span{display:block;margin-top:3px;font-family:var(--mono);font-size:8.5px;letter-spacing:var(--ls-2);
  color:rgba(239,241,240,.62);text-transform:uppercase;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.vplate .y{flex:0 0 auto;font-family:var(--mono);font-size:8.5px;letter-spacing:var(--ls-1);
  color:rgba(239,241,240,.44);font-variant-numeric:tabular-nums}
/* carte étroite (reel en rangée dense) : la plaque perd son année */
.vcard[data-vert] .vplate .y{display:none}
.vcard[data-vert] .vplate{left:8px;right:8px;bottom:8px;padding:8px 11px}
.vcard[data-vert] .vplate b{font-size:12px}

/* ---------- la pastille de lecture ---------- */
.vplay{position:absolute;top:50%;left:50%;z-index:2;width:52px;height:52px;border-radius:50%;
  display:flex;align-items:center;justify-content:center;pointer-events:none;
  transform:translate(-50%,-50%) scale(.82);opacity:0;
  background:radial-gradient(62% 46% at 50% 12%,rgba(255,255,255,.16),transparent 70%),rgba(6,6,6,.5);
  border:1px solid rgba(255,255,255,.3);
  transition:opacity .34s var(--ease),transform .34s var(--ease)}
/* le flou n'existe QUE quand la pastille est visible — 100 backdrop-filter
   invisibles au repos tuent le scroll (leçon du feed v1) */
.vcard:hover .vplay{opacity:1;transform:translate(-50%,-50%) scale(1);
  -webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px)}
/* Tactile : pas de survol, donc la pastille doit rester visible — mais discrète.
   À 52 px et 80 % d'opacité elle plantait un gros bouton au milieu de chaque
   affiche, exactement ce qu'aucun feed ne fait. Et sur la carte qui joue déjà,
   elle n'a plus rien à annoncer : elle s'efface. */
@media (hover:none){
  .vcard:not(.still) .vplay{opacity:.5;width:40px;height:40px;
    transform:translate(-50%,-50%) scale(1);border-color:rgba(255,255,255,.24)}
  .vcard:not(.still) .vplay svg{width:11px;height:13px}
  .vcard.live .vplay{opacity:0}
}
/* le badge REEL, coin haut — signale ce qui vit dans le mode plein écran */
.vtag{position:absolute;top:10px;left:10px;z-index:2;font-family:var(--mono);font-size:8px;
  letter-spacing:var(--ls-3);color:rgba(239,241,240,.82);padding:5px 8px;border-radius:7px;
  background:rgba(6,6,6,.42);border:1px solid rgba(255,255,255,.14);
  opacity:0;transition:opacity .34s var(--ease)}
.vcard.live .vtag,.vcard:hover .vtag{opacity:1}
/* pièce qui vit chez Instagram : le badge le dit AVANT le clic, il n'y a pas
   de mauvaise surprise et le curseur reste cohérent avec la destination */
.vtag--ext{opacity:1;background:rgba(6,6,6,.62);border-color:rgba(255,255,255,.2)}
.vcard.ext .vplate{padding-right:10px}

/* ------------------------------------------------------------
   AU DOIGT, LE MUR DOIT PARLER
   La plaque et le badge n'avaient que trois déclencheurs : .live, :hover,
   :focus-visible. Sur écran tactile :hover n'existe pas et .live est unique
   par page — mesuré à mi-mur : 5 cartes à l'écran, 0 titre visible, 0 badge
   REEL visible. Un mur de 99 vignettes anonymes, sans titre, sans client,
   sans rien qui dise ce qui ouvre le plein écran. Et avec « Réduire les
   animations » activé, plus aucun titre nulle part.
   Ce bloc doit rester APRÈS la règle .vtag ci-dessus : à spécificité égale,
   c'est l'ordre source qui tranche — une media query n'ajoute aucun poids.
   ------------------------------------------------------------ */
@media (hover:none){
  .vplate{opacity:1;transform:none;transition:none}
  .vtag{opacity:1;transition:none}
  /* reel en demi-colonne (~180 px) : le titre seul, la ligne client/catégorie
     en 8,5 px n'a plus la largeur d'exister */
  .vcard[data-vert] .vplate span{display:none}
}

@media (hover:hover) and (pointer:fine){
  .vcard:hover .m{transform:translateY(-4px);box-shadow:var(--shadow-lift)}
  .vcard:hover .m img{transform:scale(1.04);filter:saturate(1) contrast(1.04) brightness(1)}
  /* la rangée survolée s'efface autour du curseur */
  .vrow:has(.vcard:hover) .vcard:not(:hover){opacity:.55}
  .vcard{transition:opacity .38s var(--ease)}
}
.vcard:active .m{transform:translateY(-1px) scale(.994)}
.vcard:focus-visible{outline:2px solid var(--white-led);outline-offset:3px;border-radius:16px}

/* pendant le scroll, toutes les transitions de survol se taisent :
   le curseur immobile sur un mur qui défile rallume des :hover en boucle */
body.is-scrolling .vcard .m,
body.is-scrolling .vcard .m img,
body.is-scrolling .vplate,
body.is-scrolling .vplay{transition:none}
@media (hover:hover) and (pointer:fine){
  body.is-scrolling .vrow:has(.vcard:hover) .vcard:not(:hover){opacity:1;transition:none}
}

/* ---------- arrivée : un seul fondu, aucune cascade ---------- */
.vrow.rv .vcard{opacity:0;transition:opacity .5s linear}
.vrow.rv.in .vcard{opacity:1}
@media (hover:none){ .vrow.rv .vcard,.vrow.rv.in .vcard{opacity:1;transition:none} }
.rv-late .vrow.rv .vcard{transition:none}
html.qc .vrow.rv .vcard{opacity:1!important}
@media (prefers-reduced-motion:reduce){
  .vrow.rv .vcard{opacity:1;transition:none}
  .vcard.live.breathe .m img{transform:none;transition:none}
}

/* ---------- placeholder de catégorie à venir ---------- */
.vcard.ph{cursor:default}
.vcard.ph .m{display:flex;align-items:center;justify-content:center;background:#09090B}
.vcard.ph .m::after{box-shadow:inset 0 0 0 1px rgba(255,255,255,.09)}
.vcard.ph .m{border:1px dashed rgba(255,255,255,.13)}
.vcard.ph:hover .m{transform:none;box-shadow:none}
.vphx{text-align:center;padding:14px}
.vphx b{display:block;font-family:var(--sans);font-weight:620;font-size:15px;color:var(--stone)}
.vphx span{display:block;margin-top:8px;font-family:var(--mono);font-size:8.5px;letter-spacing:var(--ls-3);
  color:rgba(239,241,240,.36)}

/* ---------- « VOIR PLUS » — le mur s'ouvre sur 30 pièces ---------- */
.vmore{display:flex;align-items:center;justify-content:center;gap:12px;cursor:pointer;
  margin:44px auto 8px;padding:16px 34px;min-height:44px;border-radius:999px;
  font-family:var(--mono);font-size:10px;letter-spacing:var(--ls-2);color:var(--bone);
  background:var(--glass-bg);border:1px solid var(--glass-brd);box-shadow:var(--glass-hl);
  -webkit-backdrop-filter:blur(var(--glass-blur)) saturate(1.35);
          backdrop-filter:blur(var(--glass-blur)) saturate(1.35);
  transition:border-color .3s var(--ease),transform .3s var(--ease),color .3s var(--ease)}
.vmore:hover{transform:translateY(-1px);border-color:rgba(201,207,204,.42)}
.vmore:active{transform:translateY(0) scale(.99)}
.vmore:focus-visible{outline:2px solid var(--white-led);outline-offset:3px}
.vmore em{font-style:normal;color:var(--stone);font-variant-numeric:tabular-nums}
.vmore em::before{content:"+"}
@media (hover:none){
  .vmore{-webkit-backdrop-filter:none;backdrop-filter:none;background:rgba(20,20,22,.9)}
}
/* le bouton flottant REELS occupe le coin bas-droit : sans cette réserve,
   il se pose exactement par-dessus « VOIR PLUS » et on ne peut plus charger
   la suite du mur (constaté à 375 px) */
@media (max-width:680px){
  .vmore{margin:44px 0 8px;width:calc(100% - 128px);padding:15px 20px}
}

/* ---------- fin de mur ---------- */
.vend{text-align:center;font-family:var(--mono);font-size:9.5px;letter-spacing:var(--ls-3);
  color:var(--stone);margin:72px 0 30px}
.vempty{text-align:center;padding:90px 0;font-family:var(--mono);font-size:10px;
  letter-spacing:var(--ls-2);color:var(--stone)}

/* ---------- responsive : le mur devient une colonne rythmée ---------- */
@media (max-width:1100px){ .vrow{gap:10px;margin-bottom:10px} }
@media (max-width:680px){
  .vrow{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:8px}
  .vcard{width:auto}
  .vcard:not([data-vert]){grid-column:span 2;order:-1}   /* les 16:9 passent devant */
  .vcard[data-vert]{grid-column:span 1}
  .vcard.orph{grid-column:span 2}
  .vcard.orph .m{aspect-ratio:4/5}
  .vrow .vcard[data-vert]:only-child,
  .vrow .vcard:not([data-vert]):only-child{width:auto;margin-inline:0}
  .vcard .m{border-radius:13px}
  .vplate b{font-size:12.5px}
}

/* ============================================================
   5. MODE REELS — plein écran, une pièce par écran
   ============================================================ */
.reels{position:fixed;inset:0;z-index:200;background:#000;opacity:0;visibility:hidden;
  transition:opacity .34s var(--ease),visibility 0s linear .34s}
.reels.open{opacity:1;visibility:visible;transition:opacity .34s var(--ease),visibility 0s}
body.reels-on{overflow:hidden}

/* le rail : scroll vertical avec accrochage — un écran par reel */
.rrail{position:absolute;inset:0;overflow-y:auto;overflow-x:hidden;
  scroll-snap-type:y mandatory;-webkit-overflow-scrolling:touch;
  scrollbar-width:none;-ms-overflow-style:none;overscroll-behavior:contain}
.rrail::-webkit-scrollbar{display:none}

/* height:100% suit le rail, qui suit .reels en position:fixed — donc la barre
   d'URL de Safari iOS qui se rétracte ne décale pas l'accrochage. C'est pour ça
   qu'on ne met NI 100vh (trop haut, coupe le bas) NI 100dvh (qui redimensionne
   chaque slide en plein geste et fait sauter le snap). */
.reel{position:relative;height:100%;container-type:size;
  scroll-snap-align:center;scroll-snap-stop:always;
  display:flex;align-items:center;justify-content:center;overflow:hidden}
/* le fond : la cover floutée remplit les côtés sur grand écran, jamais de barre
   noire morte. Assombri franchement — c'est une ambiance, pas une image. */
.reel__bg{position:absolute;inset:-6%;z-index:0;background-size:cover;background-position:center;
  filter:blur(52px) saturate(1.05) brightness(.26);transform:translateZ(0)}
/* une vignette éteint les bords : sans elle, le halo coloré tire l'œil hors du reel */
.reel::after{content:"";position:absolute;inset:0;z-index:0;pointer-events:none;
  background:radial-gradient(78% 62% at 50% 50%,transparent,rgba(0,0,0,.62))}
/* La scène doit être EXACTEMENT en 9:16, sinon object-fit:cover agrandit la
   vidéo pour remplir la hauteur et rogne les côtés. Mesuré avant correction à
   375×812 : scène en 0,46 au lieu de 0,5625 → 17,9 % de largeur perdue, ~34 px
   de chaque bord — pile là où vivent les logos clients et les cadrages latéraux.
   C'est la largeur qui porte la contrainte, la hauteur suit le ratio.
   Première ligne `width` = repli sans container queries. Aucune unité dvh :
   elle redimensionnerait chaque slide en plein geste et ferait sauter le snap. */
.reel__st{position:relative;z-index:1;
  width:min(100%, calc(100svh * 9 / 16));
  width:min(100%, calc(100cqh * 9 / 16));
  height:auto;aspect-ratio:9/16;flex:0 0 auto;
  display:flex;align-items:center;justify-content:center;background:#000;overflow:hidden}
@media (min-width:900px){
  /* même plafond, exprimé en largeur — le redonner en hauteur rouvrirait le rognage */
  .reel__st{border-radius:22px;
    width:min(100%, calc(92cqh * 9 / 16));height:auto;
    box-shadow:0 40px 120px -40px rgba(0,0,0,.95),inset 0 0 0 1px rgba(255,255,255,.08)}
}
.reel video{width:100%;height:100%;object-fit:cover;display:block;background:#000}
.reel__poster{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block;
  transition:opacity .5s var(--ease)}
.reel.playing .reel__poster{opacity:0}
/* le voile de lecture — le texte reste lisible sur n'importe quelle image */
.reel__sh{position:absolute;inset:0;z-index:2;pointer-events:none;
  background:linear-gradient(0deg,rgba(0,0,0,.72),rgba(0,0,0,.16) 34%,transparent 56%,rgba(0,0,0,.34))}

/* -- le pied : titre, client, catégorie — posé sur la scène --
   Le padding bas intègre la zone sûre : sans ça, sur un iPhone à barre
   d'accueil, le titre du reel passe SOUS la barre et devient illisible.
   (Sur desktop env() vaut 0, la règle ne coûte rien.) */
.reel__c{position:absolute;left:0;right:0;bottom:0;z-index:4;
  padding:20px 16px calc(26px + env(safe-area-inset-bottom));
  display:flex;align-items:flex-end;justify-content:space-between;gap:14px;pointer-events:none}
.reel__i{min-width:0;flex:1 1 auto}
.reel__i .cat{display:inline-block;font-family:var(--mono);font-size:8.5px;letter-spacing:var(--ls-3);
  color:var(--led-hot);padding:5px 9px;border-radius:7px;margin-bottom:11px;
  background:rgba(255,255,255,.09);border:1px solid rgba(255,255,255,.15)}
.reel__i b{display:block;font-family:var(--sans);font-weight:620;font-size:20px;letter-spacing:-.02em;
  line-height:1.2;color:#fff}
.reel__i span{display:block;margin-top:6px;font-family:var(--mono);font-size:9.5px;letter-spacing:var(--ls-2);
  color:rgba(255,255,255,.68);text-transform:uppercase}

/* -- la colonne d'actions à droite -- */
.reel__a{flex:0 0 auto;display:flex;flex-direction:column;gap:11px;pointer-events:auto}
.rbtn{width:44px;height:44px;border-radius:50%;display:flex;align-items:center;justify-content:center;
  cursor:pointer;color:#fff;padding:0;
  background:rgba(255,255,255,.1);border:1px solid rgba(255,255,255,.17);
  -webkit-backdrop-filter:blur(18px) saturate(1.4);backdrop-filter:blur(18px) saturate(1.4);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.16);
  transition:background-color .28s var(--ease),transform .28s var(--ease),border-color .28s var(--ease)}
.rbtn:hover{transform:scale(1.07);background:rgba(255,255,255,.17)}
.rbtn:active{transform:scale(.94)}
.rbtn:focus-visible{outline:2px solid var(--white-led);outline-offset:3px}
.rbtn svg{display:block;pointer-events:none}
.rbtn.on{background:var(--ember);border-color:transparent;color:#0B0B0C}

/* -- la barre de progression : un filet de LED, remonté au-dessus de la
      barre d'accueil de l'iPhone sinon il est invisible -- */
.reel__p{position:absolute;left:0;right:0;z-index:5;height:2.5px;background:rgba(255,255,255,.14);
  bottom:env(safe-area-inset-bottom)}
.reel__p i{display:block;height:100%;width:0;background:var(--led-hot);
  box-shadow:0 0 8px rgba(201,207,204,.7)}

/* -- le chrome du mode : fermer, compteur, catégorie -- */
/* l'encoche / Dynamic Island mangerait le bouton fermer et le compteur */
.reels__top{position:absolute;top:0;left:0;right:0;z-index:6;display:flex;align-items:center;
  justify-content:space-between;gap:14px;pointer-events:none;
  padding:calc(16px + env(safe-area-inset-top)) calc(18px + env(safe-area-inset-right))
          16px calc(18px + env(safe-area-inset-left));
  background:linear-gradient(180deg,rgba(0,0,0,.5),transparent)}
.reels__top > *{pointer-events:auto}
.rclose{width:44px;height:44px;border-radius:50%;display:flex;align-items:center;justify-content:center;
  cursor:pointer;color:#fff;padding:0;
  background:rgba(255,255,255,.1);border:1px solid rgba(255,255,255,.17);
  -webkit-backdrop-filter:blur(18px);backdrop-filter:blur(18px);
  transition:background-color .28s var(--ease),transform .28s var(--ease)}
.rclose:hover{background:rgba(255,255,255,.2);transform:scale(1.06)}
.rclose:focus-visible{outline:2px solid var(--white-led);outline-offset:3px}
.rcount{font-family:var(--mono);font-size:9.5px;letter-spacing:var(--ls-2);color:rgba(255,255,255,.72);
  font-variant-numeric:tabular-nums;padding:9px 14px;border-radius:999px;
  background:rgba(255,255,255,.09);border:1px solid rgba(255,255,255,.14);
  -webkit-backdrop-filter:blur(18px);backdrop-filter:blur(18px)}

/* -- l'indice du geste, une seule fois -- */
/* l'indice se pose EN HAUT : à 96 px du bas il recouvrait le titre du reel et
   effaçait le nom du client pendant ses trois premières secondes à l'écran */
.rhint{position:absolute;left:50%;top:calc(76px + env(safe-area-inset-top));z-index:6;
  transform:translateX(-50%);pointer-events:none;
  font-family:var(--mono);font-size:9px;letter-spacing:var(--ls-2);color:rgba(255,255,255,.62);
  padding:9px 15px;border-radius:999px;white-space:nowrap;
  background:rgba(0,0,0,.42);border:1px solid rgba(255,255,255,.13);
  -webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px);
  opacity:0;transition:opacity .5s var(--ease)}
.rhint.on{opacity:1}

/* -- flèches desktop -- */
.rnav{position:absolute;right:26px;z-index:6;width:44px;height:44px;border-radius:50%;cursor:pointer;
  display:none;align-items:center;justify-content:center;color:#fff;padding:0;
  background:rgba(255,255,255,.09);border:1px solid rgba(255,255,255,.15);
  -webkit-backdrop-filter:blur(18px);backdrop-filter:blur(18px);
  transition:background-color .28s var(--ease),opacity .28s var(--ease)}
.rnav:hover{background:rgba(255,255,255,.2)}
.rnav:disabled{opacity:.22;cursor:default}
.rnav.up{top:calc(50% - 50px)}
.rnav.dn{top:calc(50% + 10px)}
@media (min-width:900px){ .rnav{display:flex} }

@media (max-width:680px){
  /* Le raccourci `padding` écrasait le calc(26px + env(...)) de la règle de
     base : sur tous les iPhone, le titre et les boutons se posaient sur la
     barre d'accueil — exactement ce que la règle de base disait éviter.
     Et 41 px de bouton, c'est sous le minimum d'Apple : on vise « ouvrir sur
     Instagram », iOS comprend « retour à l'écran d'accueil ». */
  .reel__c{padding:18px 15px calc(26px + env(safe-area-inset-bottom))}
  .reel__i b{font-size:17px}
  .reel__a{gap:9px}
  .rbtn{width:44px;height:44px}
}
@media (prefers-reduced-motion:reduce){
  .rrail{scroll-behavior:auto}
  .rbtn:hover,.rclose:hover{transform:none}
}

/* ============================================================
   6. LIGHTBOX v2 — pour les films 16:9 (YouTube / Vimeo / MP4)
   Le mode REELS gère le vertical ; ici on garde une salle sobre.
   ============================================================ */
.vlbx{position:fixed;inset:0;z-index:190;display:flex;align-items:center;justify-content:center;
  padding:clamp(14px,3vw,40px);background:rgba(4,4,5,.9);
  -webkit-backdrop-filter:blur(28px) saturate(1.2);backdrop-filter:blur(28px) saturate(1.2);
  opacity:0;visibility:hidden;transition:opacity .3s var(--ease),visibility 0s linear .3s}
.vlbx.open{opacity:1;visibility:visible;transition:opacity .3s var(--ease),visibility 0s}
.vlbx__b{position:relative;width:min(1280px,100%);max-height:100%;display:flex;flex-direction:column;gap:14px}
.vlbx__f{position:relative;width:100%;aspect-ratio:16/9;border-radius:var(--r-l);overflow:hidden;
  background:#000;box-shadow:0 40px 120px -40px rgba(0,0,0,.95),inset 0 0 0 1px rgba(255,255,255,.09)}
.vlbx__f iframe,.vlbx__f video{position:absolute;inset:0;width:100%;height:100%;border:0;display:block;
  object-fit:contain;background:#000}
.vlbx__c{display:flex;align-items:flex-end;justify-content:space-between;gap:18px;padding:0 4px}
.vlbx__c b{display:block;font-family:var(--sans);font-weight:620;font-size:17px;letter-spacing:-.02em;color:var(--bone)}
.vlbx__c span{display:block;margin-top:5px;font-family:var(--mono);font-size:9.5px;letter-spacing:var(--ls-2);
  color:var(--stone);text-transform:uppercase}
.vlbx__c .y{flex:0 0 auto;font-family:var(--mono);font-size:9.5px;letter-spacing:var(--ls-2);color:var(--stone)}
/* fixed, pas absolute : en paysage téléphone la boîte dépasse la hauteur de
   l'écran, et un bouton accroché à -46 px au-dessus d'elle sortait du cadre —
   il ne restait qu'un liseré de 15 px collé sous la barre d'état, et plus
   aucun moyen de fermer (ni swipe, ni clavier sur iPhone). */
.vlbx__x{position:fixed;top:calc(10px + env(safe-area-inset-top));
  right:calc(10px + env(safe-area-inset-right));
  width:44px;height:44px;z-index:3;border-radius:50%;cursor:pointer;
  -webkit-tap-highlight-color:transparent;
  display:flex;align-items:center;justify-content:center;color:var(--bone);padding:0;
  background:var(--glass-bg);border:1px solid var(--glass-brd);
  -webkit-backdrop-filter:blur(16px);backdrop-filter:blur(16px);
  transition:background-color .28s var(--ease),transform .28s var(--ease)}
.vlbx__x:hover{background:var(--ember);color:#0B0B0C;transform:scale(1.06)}
.vlbx__x:focus-visible{outline:2px solid var(--white-led);outline-offset:3px}
/* z-index:3 — sans lui, les flèches sont AVANT le cadre vidéo dans le DOM et
   toutes deux en z-index auto : l'iframe se peint par-dessus. Mesuré,
   elementFromPoint au centre des deux boutons renvoyait IFRAME en 1440 comme
   en 375 : le clavier passait, la souris et le doigt non. */
.vlbx__n{position:absolute;top:50%;transform:translateY(-50%);width:40px;height:40px;border-radius:50%;
  z-index:3;
  cursor:pointer;display:flex;align-items:center;justify-content:center;color:var(--bone);padding:0;
  background:var(--glass-bg);border:1px solid var(--glass-brd);
  -webkit-backdrop-filter:blur(16px);backdrop-filter:blur(16px);
  transition:background-color .28s var(--ease),opacity .28s var(--ease)}
.vlbx__n:hover{background:rgba(255,255,255,.18)}
.vlbx__n:disabled{opacity:.2;cursor:default}
.vlbx__n.prev{left:-58px}
.vlbx__n.next{right:-58px}
/* l'attribut hidden ne cachait rien : display:flex ci-dessus l'écrasait, et
   les deux flèches restaient visibles ET mortes sur une pièce ouverte seule */
.vlbx__n[hidden]{display:none}
@media (max-width:1450px){
  .vlbx__n.prev{left:6px}
  .vlbx__n.next{right:6px}
  .vlbx__n{background:rgba(6,6,6,.6)}
}
@media (max-width:680px){
  .vlbx__c b{font-size:15px}
  /* Les flèches RESTENT sur téléphone. Masquées, la salle devenait un
     cul-de-sac : ni suivant, ni précédent, ni balayage — pour voir le film
     d'à côté il fallait fermer et retrouver sa place dans 99 cartes. L'ancien
     lecteur du site (wolfplay.js) avait le geste ; ne rien mettre à la place
     aurait fait moins bien que la page remplacée.
     top:50% tombe toujours dans le cadre vidéo, jamais sur la légende — un
     bouton posé en bas couvrirait 100 % de la bande titre/année (mesuré). */
  .vlbx__n{width:44px;height:44px;background:rgba(6,6,6,.72)}
}
