/* ==========================================================================
   PUTSCH.ORG — SYSTÈME
   Registre « affiche collée sur le mur » : sérigraphie mal repérée,
   bandes déchirées, tampons, tickers. Même ADN que putsch.agency.
   ========================================================================== */

/* --------------------------------------------------------------------------
   01 — RESET
   -------------------------------------------------------------------------- */
*,*::before,*::after{box-sizing:border-box}
*{margin:0}
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth}
body{
  min-height:100vh;
  background:var(--void);
  color:var(--bone);
  font-family:var(--body);
  font-size:clamp(.95rem,.5vw + .82rem,1.0625rem);
  line-height:1.62;
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
  overflow-x:hidden;
}
img,picture,svg,video,canvas{display:block;max-width:100%}
input,button,textarea,select{font:inherit;color:inherit}
button{background:none;border:0;cursor:pointer}
a{color:inherit;text-decoration:none}
ul,ol{list-style:none;padding:0}
h1,h2,h3,h4,h5,h6{font-weight:inherit;line-height:1.02;text-wrap:balance}
p{text-wrap:pretty}
:target{scroll-margin-top:6rem}

::selection{background:var(--hot);color:var(--on-hot)}

:focus-visible{outline:2px solid var(--hot-lite);outline-offset:3px}
:focus:not(:focus-visible){outline:none}

::-webkit-scrollbar{width:10px;height:10px}
::-webkit-scrollbar-track{background:var(--void)}
::-webkit-scrollbar-thumb{background:var(--hot-dim)}
::-webkit-scrollbar-thumb:hover{background:var(--hot)}
html{scrollbar-color:var(--hot-dim) var(--void);scrollbar-width:thin}

.sr-only{
  position:absolute;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0;
}
.skip{
  position:fixed;top:0;left:0;z-index:9999;
  transform:translateY(-120%);
  background:var(--hot);color:var(--on-hot);
  padding:.9rem 1.4rem;font-family:var(--mono);font-size:.78rem;
  letter-spacing:.14em;text-transform:uppercase;
  transition:transform .2s var(--ease);
}
.skip:focus{transform:none}

/* --------------------------------------------------------------------------
   02 — TEXTURE : grain + scan lines
   Purement CSS. Coupés au tactile et en reduced-motion.
   -------------------------------------------------------------------------- */
.grain,.scan{position:fixed;inset:-50%;pointer-events:none;z-index:var(--z-grain)}
.grain{
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
  opacity:.05;
  animation:grain 7s steps(6) infinite;
  will-change:transform;
}
/* Texture, pas rayures : cycle 4px à 25 % et faible opacité, sinon la
   grande typo os se retrouve hachée et devient illisible. */
.scan{
  inset:0;
  background:repeating-linear-gradient(
    to bottom,
    transparent 0 3px,
    rgba(0,0,0,.5) 3px 4px
  );
  opacity:.16;
  mix-blend-mode:multiply;
}
@keyframes grain{
  0%,100%{transform:translate(0,0)}
  16%{transform:translate(-4%,-3%)}
  33%{transform:translate(3%,-5%)}
  50%{transform:translate(-2%,4%)}
  66%{transform:translate(4%,2%)}
  83%{transform:translate(-3%,-2%)}
}
@media (hover:none),(pointer:coarse){ .grain,.scan{display:none} }

/* --------------------------------------------------------------------------
   03 — CURSEUR
   -------------------------------------------------------------------------- */
.cur{
  position:fixed;top:0;left:0;width:26px;height:26px;
  border:1px solid var(--bone);border-radius:50%;
  pointer-events:none;z-index:var(--z-cursor);
  mix-blend-mode:difference;
  transform:translate(-50%,-50%);
  transition:width .3s var(--ease),height .3s var(--ease),
             border-color .2s,background .2s,opacity .2s;
  opacity:0;
}
.cur.is-live{opacity:1}
body[data-cursor-on] .cur.is-hot{width:56px;height:56px;background:var(--bone)}
body[data-cursor-on]{cursor:none}
body[data-cursor-on] a,body[data-cursor-on] button{cursor:none}
@media (hover:none),(pointer:coarse){ .cur{display:none} body[data-cursor-on]{cursor:auto} }

/* --------------------------------------------------------------------------
   04 — COQUILLE & SECTIONS
   -------------------------------------------------------------------------- */
.shell{max-width:var(--maxw);margin-inline:auto;padding-inline:var(--gut);width:100%}
.sec{padding-block:var(--sec);position:relative}
.sec--tight{padding-block:calc(var(--sec) * .5)}
.sec--flush{padding-block:0}
/* Pages de référence (presse, légal) : le contenu est dense et consulté, pas
   contemplé. La respiration d'affiche y noyait l'information — trois quarts
   de la page presse étaient du vide. */
.sec--dense{padding-block:clamp(1.8rem,4vw,3.2rem)}
.sec--dense .shead{margin-bottom:clamp(1.1rem,2.4vw,1.8rem)}

/* En-tête de section : titre, filet, lien « voir tout ».
   Plus de numéro d'ordre : numéroter les sections d'une page n'apprend rien
   au lecteur et encombrait chaque titre d'un pochoir de 9 rem. */
.shead{
  display:flex;align-items:flex-end;gap:clamp(1rem,3vw,2.5rem);
  border-bottom:1px solid var(--edge);
  padding-bottom:1.1rem;margin-bottom:clamp(2rem,5vw,4.5rem);
  position:relative;
}
.shead__title{
  font-family:var(--display);
  font-size:clamp(1.5rem,4.4vw,3.4rem);
  font-weight:900;
  letter-spacing:var(--track-d);text-transform:uppercase;
  flex:1 1 auto;min-width:0;
}
.shead__more{
  font-family:var(--mono);font-size:.74rem;letter-spacing:.16em;
  text-transform:uppercase;color:var(--ash);flex:none;
  padding-bottom:.4rem;
  transition:color .2s;
}
.shead__more:hover{color:var(--hot)}
.shead__more::after{content:' →'}
/* En-tête de colonne : le corps pleine page écraserait une demi-largeur. */
.shead--sm .shead__title{font-size:clamp(1.05rem,2.2vw,1.7rem)}
.shead--sm{padding-bottom:.7rem;margin-bottom:clamp(1rem,2vw,1.5rem)}
@media (max-width:640px){
  .shead{flex-wrap:wrap;gap:.6rem}
  .shead__more{width:100%;padding-bottom:0}
}

/* --------------------------------------------------------------------------
   05 — TYPO UTILITAIRE
   -------------------------------------------------------------------------- */
.mono{
  font-family:var(--mono);font-size:.74rem;font-weight:400;
  letter-spacing:.16em;text-transform:uppercase;color:var(--ash);
}
.mono--hot{color:var(--hot);font-weight:700}
.mono--bone{color:var(--bone)}

.giant{
  font-family:var(--display);
  font-weight:900;
  text-transform:uppercase;
  line-height:.94;letter-spacing:var(--track-giant);
}
.trajan{font-family:var(--trajan);font-weight:700;letter-spacing:.06em;text-transform:uppercase}
/* Règle reprise de l'agency : l'emphase se fait par la graisse, pas l'italique */
.prose em,.lede em{font-style:normal;font-weight:900}
.lede{
  font-family:var(--serif-d);font-style:italic;
  font-size:clamp(1.15rem,2.2vw,1.85rem);
  line-height:1.42;color:var(--bone);
  max-width:34ch;
}
.prose{max-width:62ch;color:rgba(237,234,227,.86)}
.prose p + p{margin-top:1.2em}
.prose a{border-bottom:1px solid var(--hot);transition:background .2s}
.prose a:hover{background:var(--hot);color:var(--on-hot);border-color:var(--hot)}
.prose h2{
  font-family:var(--display);font-weight:800;letter-spacing:var(--track-d);
  text-transform:uppercase;font-size:1.35em;margin:2em 0 .6em;line-height:1.16;
}
.prose h3{font-family:var(--display);font-weight:700;letter-spacing:var(--track-d);text-transform:uppercase;font-size:1.1em;margin:1.6em 0 .4em;line-height:1.2}
.prose ul{margin:1.2em 0;padding-left:1.4em}
.prose li{list-style:none;position:relative;margin-bottom:.5em}
.prose li::before{content:'—';position:absolute;left:-1.4em;color:var(--hot)}
.prose blockquote{
  border-left:2px solid var(--hot);padding-left:1.4rem;margin:1.8em 0;
  font-family:var(--serif-d);font-style:italic;font-size:1.15em;color:var(--bone);
}
.prose hr{border:0;border-top:1px solid var(--edge);margin:2.6em 0}
.prose img{margin:2em 0;filter:grayscale(1) contrast(1.14)}
.prose code{font-family:var(--mono);font-size:.86em;background:var(--void);padding:.1em .35em}

/* Lettrine */
.prose > p:first-of-type::first-letter{
  font-family:var(--serif-d);font-size:4.2em;line-height:.78;
  float:left;padding:.06em .12em 0 0;color:var(--hot);font-weight:700;
}

/* --------------------------------------------------------------------------
   06 — SURIMPRESSION (registration error)
   Le mot est doublé en rouge, légèrement décalé. Au hover l'écart se creuse,
   comme une sérigraphie mal calée.
   -------------------------------------------------------------------------- */
.overprint{position:relative;display:inline-block;isolation:isolate}
/* L'écho doit être un FANTÔME GRIS : en monochrome, un écho blanc sous un
   texte blanc serait invisible. Le gris moyen donne la sensation de plaque
   décalée sans introduire la moindre couleur. */
.overprint::before{
  content:attr(data-echo);
  position:absolute;inset:0;z-index:-1;
  color:var(--hot-dim);
  transform:translate(3px,2px);
  opacity:1;
  transition:transform .45s var(--ease),color .45s var(--ease);
  pointer-events:none;
  white-space:inherit;
}
.overprint:hover::before,
a:hover .overprint::before,
.plate__link:hover .overprint::before{color:#6E6C66}
/* sur aplat blanc, l'écho s'inverse en noir */
.mass--inv .overprint::before,
.tick--inv .overprint::before{color:rgba(0,0,0,.42)}
.overprint:hover::before,
a:hover .overprint::before,
.plate__link:hover .overprint::before{transform:translate(7px,3px)}

/* --------------------------------------------------------------------------
   07 — TAMPON
   -------------------------------------------------------------------------- */
.stamp{
  position:absolute;top:50%;left:50%;
  transform:translate(-50%,-50%) rotate(calc(var(--shear) * -2.4));
  font-family:var(--cond);font-weight:900;font-stretch:70%;
  font-size:clamp(1.1rem,3.4vw,2.2rem);
  letter-spacing:.06em;text-transform:uppercase;
  color:var(--hot);
  border:3px solid var(--hot);
  padding:.28em .6em;
  z-index:3;pointer-events:none;
  opacity:.94;
  white-space:nowrap;
  mix-blend-mode:hard-light;
}
.stamp--sm{font-size:clamp(.8rem,1.6vw,1.05rem);border-width:2px}
.stamp--dim{color:var(--hot-dim);border-color:var(--hot-dim)}

/* --------------------------------------------------------------------------
   08 — REVEAL au scroll

   DEUX PIÈGES, TOUS DEUX DÉJÀ TOMBÉS. Ne pas les réintroduire.

   1. NE JAMAIS MASQUER AVEC `clip-path`.
      L'état caché s'écrivait `clip-path:inset(0 0 100% 0)`. Or le clip d'un
      élément entre dans le calcul de son rectangle d'intersection : réduit à
      zéro, il n'« intersecte » plus jamais rien, et l'IntersectionObserver
      chargé de le révéler ne se déclenche pas. L'élément se masquait
      lui-même de son propre observateur. Résultat mesuré : 1 bloc révélé sur
      8, tout le reste de la page invisible en production. Le masquage se fait
      donc par `opacity` + `transform`, qui laissent la boîte intacte.

   2. NE JAMAIS MASQUER SANS JS.
      L'état caché est conditionné à `.js`, posé par un script en ligne dans
      le <head>. Si le JavaScript ne s'exécute pas — erreur, blocage réseau,
      extension — la classe n'existe pas, rien n'est masqué, et la page reste
      entièrement lisible. C'est le troisième invariant du projet : aucun état
      de chargement terminal.
   -------------------------------------------------------------------------- */
.js .rv{
  opacity:0;
  transform:translate3d(0,2.4rem,0);
  transition:opacity .55s var(--ease),transform .8s var(--ease);
  transition-delay:var(--d,0ms);
}
.js .rv.is-in{opacity:1;transform:none}

/* --------------------------------------------------------------------------
   09 — BOUTONS
   -------------------------------------------------------------------------- */
.btn{
  display:inline-flex;align-items:center;gap:.7em;
  font-family:var(--mono);font-size:.76rem;font-weight:700;
  letter-spacing:.18em;text-transform:uppercase;
  padding:1.05em 1.7em;
  border:1px solid var(--bone);
  color:var(--bone);
  position:relative;overflow:hidden;
  transition:color .25s var(--ease),border-color .25s var(--ease);
}
.btn::before{
  content:'';position:absolute;inset:0;background:var(--bone);
  transform:translateY(101%);
  transition:transform .38s var(--ease);z-index:-1;
}
.btn>*{position:relative}
.btn:hover{color:var(--void);border-color:var(--bone)}
.btn:hover::before{transform:none}
.btn__arrow{transition:transform .38s var(--ease)}
.btn:hover .btn__arrow{transform:translateX(.35em)}

/* Le bouton plein est l'accent du site : blanc plein, texte noir.
   Au survol il s'inverse complètement — c'est ça, l'agressivité en N&B. */
.btn--solid{background:var(--hot);border-color:var(--hot);color:var(--on-hot)}
/* Le remplissage qui monte au survol est un `::before` en `z-index:-1` : il se
   peint donc DERRIÈRE le fond de son propre bouton. Sur un bouton fantôme,
   dont le fond est transparent, il se voit — c'est le geste de la DA. Sur un
   bouton PLEIN, le fond blanc opaque le masque intégralement, alors que la
   règle de survol passait déjà le texte au blanc : le libellé disparaissait,
   blanc sur blanc (contraste mesuré 1:1). « Passer commande » et « Ajouter au
   panier » étaient illisibles dès que la souris les touchait.
   On remonte donc le remplissage AU-DESSUS du fond pour ce seul cas, et le
   libellé au-dessus de lui. Le balayage est conservé, le texte redevient
   lisible. Ne pas rendre `z-index:-1` à ce `::before`. */
.btn--solid::before{background:var(--void);z-index:0}
.btn--solid > *{z-index:1}
.btn--solid:hover{color:var(--hot);border-color:var(--hot)}

.btn--ghost{border-color:var(--edge);color:var(--ash)}
.btn--ghost:hover{color:var(--void)}

.btn[disabled],.btn[aria-disabled='true']{
  opacity:.36;pointer-events:none;border-style:dashed;
}
.btn--block{width:100%;justify-content:center}

/* --------------------------------------------------------------------------
   10 — NAVIGATION
   -------------------------------------------------------------------------- */
.nav{
  position:fixed;top:0;left:0;right:0;z-index:var(--z-nav);
  display:flex;align-items:center;gap:clamp(1rem,3vw,2.6rem);
  /* viewport-fit=cover : sans la marge d'encoche, la barre passe SOUS la
     barre d'état des iPhone et le logo sort rogné en haut. env() vaut zéro
     partout ailleurs — aucun effet hors écrans à encoche. */
  padding:calc(1.05rem + env(safe-area-inset-top)) var(--gut) 1.05rem;
  transition:background .3s var(--ease),border-color .3s,padding .3s var(--ease);
  border-bottom:1px solid transparent;
}
.nav.is-stuck{
  background:rgba(0,0,0,.82);
  backdrop-filter:blur(14px) saturate(1.2);
  -webkit-backdrop-filter:blur(14px) saturate(1.2);
  border-bottom-color:var(--edge);
  padding-top:calc(.72rem + env(safe-area-inset-top));
  padding-bottom:.72rem;
}
/* Le vrai wordmark blackletter de la marque, blanc sur transparent. */
.nav__logo{flex:none;display:block;line-height:0}
.nav__logo img{
  height:clamp(26px,3.2vw,38px);width:auto;
  transition:opacity .22s var(--ease),transform .32s var(--ease);
}
.nav__logo:hover img{opacity:.72;transform:scale(1.04)}
.nav.is-stuck .nav__logo img{height:clamp(22px,2.6vw,30px)}

.nav__links{display:flex;gap:clamp(.9rem,2vw,1.9rem);margin-left:auto}
.nav__link{
  font-family:var(--mono);font-size:.71rem;font-weight:400;
  letter-spacing:.17em;text-transform:uppercase;color:var(--ash);
  padding-block:.3rem;position:relative;
  transition:color .2s;
}
.nav__link::after{
  content:'';position:absolute;left:0;right:0;bottom:0;height:1px;
  background:var(--hot);transform:scaleX(0);transform-origin:0 50%;
  transition:transform .3s var(--ease);
}
.nav__link:hover,.nav__link[aria-current='page']{color:var(--bone)}
.nav__link:hover::after,.nav__link[aria-current='page']::after{transform:none}
.nav__right{display:flex;align-items:center;gap:.85rem;flex:none}
/* --- SÉLECTEUR DE LANGUES -------------------------------------------------
   Trente-huit entrées, composant repris de l'agence. Un <details> natif :
   le menu s'ouvre et se ferme SANS JavaScript, au clavier comme au doigt.
   Panneau noir bordé — jamais d'aplat gris — et chaque entrée s'inverse au
   survol comme tout bloc interactif du site. Le champ de recherche n'existe
   qu'avec `.js` : sans script, un champ qui ne filtre rien serait une
   promesse cassée. */
.lang{position:relative}
.lang__toggle{
  display:flex;align-items:center;gap:.45em;cursor:pointer;list-style:none;
  font-family:var(--mono);font-size:.7rem;letter-spacing:.14em;
  text-transform:uppercase;color:var(--ash);
  border:1px solid var(--edge);padding:.42em .62em;
  transition:border-color .2s,color .2s,background .2s;
}
.lang__toggle::-webkit-details-marker{display:none}
.lang__toggle svg{width:1.1em;height:1.1em;flex:none}
.lang__toggle:hover{color:var(--bone);border-color:var(--bone)}
.lang[open] .lang__toggle{background:var(--hot);border-color:var(--hot);color:var(--on-hot)}
.lang__menu{
  position:absolute;top:calc(100% + .55rem);right:0;z-index:calc(var(--z-nav) + 2);
  width:min(20rem,calc(100vw - 2 * var(--gut)));
  background:var(--void);border:1px solid var(--edge);
  display:flex;flex-direction:column;
}
.lang__search{
  display:none;width:100%;
  font-family:var(--mono);font-size:.7rem;letter-spacing:.08em;
  background:none;border:0;border-bottom:1px solid var(--edge);
  color:var(--bone);padding:.7rem .9rem;
}
.js .lang__search{display:block}
.lang__search::placeholder{color:var(--hot-dim)}
.lang__search:focus{outline:none;border-bottom-color:var(--bone)}
.lang__list{
  max-height:min(21rem,58vh);overflow-y:auto;
  display:grid;grid-template-columns:1fr 1fr;padding:.3rem;
}
.lang__list a{
  font-family:var(--mono);font-size:.7rem;letter-spacing:.05em;
  color:var(--ash);padding:.5em .7em;min-height:24px;
  display:flex;align-items:center;
  transition:background .15s,color .15s;
}
.lang__list a:hover{background:var(--hot);color:var(--on-hot)}
.lang__list a[aria-current='true']{background:var(--hot);color:var(--on-hot);font-weight:700}
.lang__list a[hidden]{display:none}

.nav__cart{
  display:flex;align-items:center;gap:.45rem;
  font-family:var(--mono);font-size:.7rem;font-weight:700;
  letter-spacing:.14em;text-transform:uppercase;
  border:1px solid var(--bone);padding:.5em .8em;
  transition:background .22s var(--ease),color .22s var(--ease);
}
.nav__cart:hover{background:var(--bone);color:var(--void)}
.nav__cart-n{
  min-width:1.5em;height:1.5em;display:grid;place-items:center;
  background:var(--hot);color:var(--on-hot);border-radius:50%;
  font-size:.7rem;
}
.nav__cart[data-count='0'] .nav__cart-n{display:none}

/* zone tactile 44×44 (WCAG 2.5.8), traits centrés dedans */
.burger{
  display:none;width:44px;height:44px;position:relative;flex:none;
  margin-right:-.5rem;
}
/* --- PASTILLE AGENCE ------------------------------------------------------
   putsch.agency n'est PAS une page de ce site : la sortie ne se range pas
   parmi les onglets. Elle vit dans une pastille bordée, à l'écart des liens,
   libellée par son DOMAINE — c'est le domaine qui dit « autre site », pas une
   icône à deviner. Bas de casse volontaire : une adresse, pas une rubrique. */
.nav__ext{
  display:inline-flex;align-items:center;gap:.5em;flex:none;
  font-family:var(--mono);font-size:.7rem;font-weight:700;
  letter-spacing:.1em;
  color:var(--bone);
  border:1px solid var(--edge);
  padding:.52em .8em;
  transition:background .22s var(--ease),color .22s,border-color .22s;
}
.nav__ext i{
  font-style:normal;color:var(--hot);
  transition:transform .3s var(--ease),color .22s;
}
.nav__ext:hover{background:var(--bone);color:var(--void);border-color:var(--bone)}
.nav__ext:hover i{color:var(--void);transform:translate(.15em,-.15em)}
.burger span{
  position:absolute;left:5px;right:5px;height:2px;background:var(--bone);
  transition:transform .32s var(--ease),opacity .2s;
}
.burger span:nth-child(1){top:15px}
.burger span:nth-child(2){top:21px}
.burger span:nth-child(3){top:27px}
body[data-drawer-open] .burger span:nth-child(1){transform:translateY(6px) rotate(45deg)}
body[data-drawer-open] .burger span:nth-child(2){opacity:0}
body[data-drawer-open] .burger span:nth-child(3){transform:translateY(-6px) rotate(-45deg)}

/* Sous 1160 px les liens disparaissent au profit du burger. Le seuil était à
   1000 px ; la pastille agence ajoute ~150 px à la barre, qui débordait entre
   1000 et 1150. C'est `.nav__links` qui portait le `margin-left:auto` poussant
   tout le groupe de droite contre le bord : en le masquant, la marge auto
   disparaissait avec lui et lang/panier/burger revenaient se coller au logo,
   laissant jusqu'à 690 px de vide à droite. La marge auto doit donc passer sur
   `.nav__right`. La pastille suit les liens : au tiroir, elle a son encart. */
@media (max-width:1160px){
  .nav__links{display:none}
  .nav__ext{display:none}
  .burger{display:block}
  .nav__right{gap:.55rem;margin-left:auto}
}
/* Le libellé « Panier » tient jusqu'à 320 px de large (mesuré) : on le garde
   partout plutôt que de le remplacer par un pictogramme à deviner. */
@media (max-width:400px){
  .nav__cart{padding:.5em .62em;letter-spacing:.1em}
  .lang__toggle{padding:.42em .5em}
}

/* Tiroir mobile */
.drawer{
  position:fixed;inset:0;z-index:var(--z-drawer);
  background:var(--void);
  display:flex;flex-direction:column;
  /* Le tiroir porte les 38 langues : son contenu DÉPASSE l'écran d'un
     téléphone. Un `center` nu pousserait alors le haut du contenu au-dessus
     de l'origine de défilement — premiers liens coupés et inatteignables.
     `safe center` ne centre que quand ça tient ; les navigateurs qui
     l'ignorent retombent sur flex-start, toujours défilable. */
  justify-content:flex-start;
  justify-content:safe center;
  padding:calc(var(--gut) + env(safe-area-inset-top)) var(--gut) calc(var(--gut) + env(safe-area-inset-bottom));
  clip-path:inset(0 0 100% 0);
  transition:clip-path .55s var(--ease);
  overflow-y:auto;
}
body[data-drawer-open] .drawer{clip-path:inset(0 0 0 0)}
body[data-drawer-open]{overflow:hidden}
/* Grain et scan lines vivent AU-DESSUS de tout (z 9000) : sur les rangées
   inversées du tiroir (langue courante, survols), les stries se lisaient
   comme un bug d'affichage. Tiroir ouvert, il couvre l'écran : couper les
   effets ne retire rien d'autre que l'artefact. */
body[data-drawer-open] .grain,
body[data-drawer-open] .scan{display:none}
.drawer__close{
  align-self:flex-end;flex:none;
  font-family:var(--mono);font-size:.7rem;letter-spacing:.14em;text-transform:uppercase;
  color:var(--ash);border:1px solid var(--edge);padding:.5em .8em;
  min-height:24px;display:inline-flex;align-items:center;
  margin-bottom:clamp(1rem,3vw,1.6rem);
  transition:background .2s,color .2s,border-color .2s;
}
.drawer__close:hover{background:var(--hot);color:var(--on-hot);border-color:var(--hot)}
.drawer__link{
  font-family:var(--display);font-weight:900;letter-spacing:var(--track-d);
  font-size:clamp(1.5rem,7.4vw,3rem);
  text-transform:uppercase;line-height:1.16;
  padding-block:.16em;
  border-bottom:1px solid var(--edge);
  display:flex;align-items:baseline;gap:.7rem;
  transition:color .2s,padding-left .3s var(--ease);
}
.drawer__link:hover{color:var(--hot);padding-left:.4rem}
.drawer__foot{margin-top:2.4rem;display:flex;gap:1.4rem;flex-wrap:wrap;align-items:center}
/* Un libellé mono court fait moins de 24 px de large : la largeur minimale
   maintient la cible au seuil exigé par le WCAG 2.5.8. */
.drawer__foot .mono{min-width:44px;justify-content:center;text-align:center}

/* Les 38 langues du tiroir : grille mono compacte, bordée, chaque entrée
   dans sa langue. L'inversion signale la courante comme le survol. */
.drawer__langs{
  margin-top:clamp(1.2rem,3vw,1.8rem);
  display:grid;grid-template-columns:repeat(auto-fill,minmax(8.5rem,1fr));
  border:1px solid var(--edge);
}
.drawer__langs a{
  font-family:var(--mono);font-size:.7rem;letter-spacing:.05em;color:var(--ash);
  padding:.55em .8em;min-height:24px;display:flex;align-items:center;
  transition:background .15s,color .15s;
}
.drawer__langs a:hover{background:var(--hot);color:var(--on-hot)}
.drawer__langs a[aria-current='true']{background:var(--hot);color:var(--on-hot);font-weight:700}
.drawer__nav{display:grid}
.drawer__link span{flex:1;min-width:0;overflow-wrap:anywhere}

/* Encart agence du tiroir : bordé, à l'écart de la liste des pages, et il
   s'inverse au survol comme tous les blocs interactifs du site. */
.drawer__ext{
  margin-top:clamp(1.4rem,4vw,2.2rem);
  border:1px solid var(--edge);
  padding:1rem 1.2rem;
  display:flex;flex-direction:column;gap:.3rem;
  transition:background .25s var(--ease),border-color .25s;
}
.drawer__ext-k{
  font-family:var(--mono);font-size:.7rem;letter-spacing:.18em;
  text-transform:uppercase;color:var(--ash);
}
.drawer__ext b{
  font-family:var(--display);font-weight:900;letter-spacing:var(--track-d);
  font-size:clamp(1.1rem,4.6vw,1.6rem);
}
.drawer__ext b i{font-style:normal;color:var(--hot)}
.drawer__ext-p{color:var(--ash);font-size:.82rem}
.drawer__ext:hover{background:var(--hot);border-color:var(--hot)}
.drawer__ext:hover .drawer__ext-k,
.drawer__ext:hover .drawer__ext-p{color:rgba(0,0,0,.62)}
.drawer__ext:hover b{color:var(--on-hot)}
.drawer__ext:hover b i{color:var(--on-hot)}

/* --------------------------------------------------------------------------
   11 — HERO
   -------------------------------------------------------------------------- */
/* Composition d'affiche : tout est centré autour du logo. */
.hero{
  position:relative;min-height:100svh;
  display:flex;flex-direction:column;justify-content:center;
  /* haut : dégagement de la nav · bas : accroche + indicateur de défilement */
  padding:clamp(4.2rem,9svh,6.6rem) var(--gut) clamp(3.6rem,6.5svh,5rem);
  overflow:hidden;
  isolation:isolate;
  text-align:center;
}
.hero__bg{
  position:absolute;inset:0;z-index:-2;
  /* le hero est complet sans image : diagonale carbone + halo rouge sourd */
  background:
    linear-gradient(118deg,var(--void) 0%,var(--void) 100%),
    var(--void);
}
.hero__bg img{
  width:100%;height:100%;object-fit:cover;
  filter:grayscale(1) contrast(1.3) brightness(.72);
  opacity:0;transition:opacity .9s var(--ease);
}
.hero__bg.is-live img{opacity:1}
/* Le voile tient les DEUX bords, avec deux logiques différentes :

   · EN TÊTE : un bandeau 100 % NOIR OPAQUE, haut de 5rem — la zone de la
     nav, en rem donc CONSTANTE sur tous les écrans (un pourcentage gonflerait
     sur un grand écran et fondrait sur un téléphone). Puis la dissolution se
     joue tout de suite : dès ~14 % de la hauteur, la vidéo est visible.
     Le noir du haut est plein, mais il s'arrête haut.

   · EN PIED : noir plein sous l'accroche et les boutons, comme toujours. */
.hero__bg::after{
  content:'';position:absolute;inset:0;
  background:
    linear-gradient(to bottom,
      /* 1. CAPOT NOIR : opaque sur toute la zone de la nav, puis maintenu
            quasi plein jusqu'AU-DESSUS DU LOGO. C'est le point clé : la
            dissolution ne doit pas démarrer dans le vide sous la nav, sinon
            la vidéo remonte trop haut et le capot paraît commencer trop bas.
            `--cap` cale la fin du capot sur le haut réel du logo : padding du
            hero (clamp 4.2→6.6rem) plus une marge. En rem+svh, donc valable
            sur tous les écrans. */
      var(--void) 0,
      var(--void) var(--cap-solid,5.6rem),
      rgba(0,0,0,.96) calc(var(--cap-solid,5.6rem) + 3svh),
      /* 2. dissolution EN COURBE, à partir du haut du logo seulement. Un
            simple passage d'un point à un autre produit une bande de Mach —
            une arête grise bien visible. Paliers serrés d'abord, espacés
            ensuite : l'œil suit une décroissance douce, pas une rampe. */
      rgba(0,0,0,.88) calc(var(--cap-solid,5.6rem) + 7svh),
      rgba(0,0,0,.74) calc(var(--cap-solid,5.6rem) + 12svh),
      rgba(0,0,0,.58) calc(var(--cap-solid,5.6rem) + 18svh),
      rgba(0,0,0,.42) calc(var(--cap-solid,5.6rem) + 25svh),
      /* 3. fenêtre la plus ouverte, sur le corps du logo. Elle doit rester
            franchement ouverte : trop la refermer éteint la vidéo et le hero
            redevient un aplat noir. */
      rgba(0,0,0,.24) 52%,
      /* 4. remontée vers le noir plein. Elle démarrait à 78 %, donc SOUS le
            logo ; elle commence maintenant à 68 %, juste au-dessus de son
            bas, et s'étale en paliers pour ne laisser aucune arête. */
      rgba(0,0,0,.38) 68%,
      rgba(0,0,0,.58) 79%,
      rgba(0,0,0,.8) 88%,
      var(--void) 97%),
    radial-gradient(130% 86% at 50% 100%,transparent 38%,rgba(0,0,0,.9) 100%);
}
.hero__inner{position:relative;max-width:var(--maxw);margin-inline:auto;width:100%}
/* Bloc et non flex : en flex, le point devenait un élément à part entière et
   se retrouvait seul sur sa ligne dès que le texte se repliait. Inline, il
   suit la première ligne quoi qu'il arrive. */
.hero__kicker{
  display:block;text-align:center;
  margin-bottom:clamp(1rem,2.6vw,2rem);
}
.hero__kicker .dot{
  display:inline-block;vertical-align:middle;
  width:6px;height:6px;background:var(--hot);border-radius:50%;
  margin-right:.6em;margin-top:-.15em;
  animation:pulse 2.2s ease-in-out infinite;
}
@keyframes pulse{50%{opacity:.25;transform:scale(.7)}}
/* --------------------------------------------------------------------------
   LOGO TOURNANT — le titre du hero
   Le <h1> porte le logo en grand, qui tourne sur son axe vertical.

   Le problème d'un rotateY(360°) sur une image plate : entre 90° et 270° on
   voit le DOS, donc le logo en miroir — illisible. La parade est le montage
   classique de la carte qui se retourne : DEUX faces empilées, chacune en
   backface-visibility:hidden, la face arrière pré-tournée de 180°. Quand le
   conteneur atteint 180°, cette face arrive à 360° — donc endroit. Le tour
   est complet et le logo reste lisible en permanence.
   -------------------------------------------------------------------------- */
/* TAILLE DU LOGO : calculée, pas réglée.

   L'ancien système empilait des paliers `max-height` réglés à la main
   (86svh, puis 68, 54, 46…) : entre deux paliers le logo était tantôt
   trop timide (490 px de large sur un 1280×720), tantôt à recaler à chaque
   retouche du hero.

   Le remplaçant tient en une formule : on part de la hauteur d'écran, on
   retire `--rsv` — la place que le reste du hero occupe réellement (nav,
   accroche, boutons, respirations) — et tout ce qui reste devient la HAUTEUR
   du logo, convertie en largeur par son ratio (1400/910 ≈ 1.538). Le logo
   absorbe donc automatiquement chaque pixel disponible, sur n'importe quel
   écran, sans jamais pousser les boutons sous la pline.

   Les trois bornes qui l'encadrent :
   · 96vw   — il peut déborder la colonne de contenu (voir left/translate)
              jusqu'à frôler les bords : plein cadre sur téléphone ;
   · plancher 20rem — un écran très bas (paysage téléphone) préfère un logo
              lisible et un hero qui défile à un logo timbre-poste ;
   · `:has(.hero__next)` — quand le compteur de prochaine date est affiché,
              la réserve grandit d'autant. */
.hero__title{
  --rsv:20.5rem;
  display:block;
  width:min(96vw,calc((100svh - var(--rsv)) * 1.538));
  min-width:min(90vw,20rem);
  position:relative;left:50%;translate:-50% 0;
  margin:0 0 clamp(1rem,2.4svh,1.8rem);
  perspective:1600px;
}
.hero:has(.hero__next) .hero__title{--rsv:24rem}
.spin{
  --spin-t:7s;                /* les trois animations ci-dessous DOIVENT la partager */
  display:block;position:relative;
  transform-style:preserve-3d;
  animation:spin3d var(--spin-t) linear infinite;
  will-change:transform;
}
/* Deux défenses contre le dos en miroir, parce qu'une seule ne suffisait pas.

   1. `backface-visibility:hidden` — le mécanisme nominal. Mais quand la
      rotation tourne sur le compositeur GPU, certains navigateurs le laissent
      filer par moments : le DOS de la face avant (le logo en miroir) réappa-
      raissait alors sous la face arrière. Les deux faces étant EXACTEMENT
      coplanaires et le lettrage posé sur du transparent, le miroir se voyait
      à travers les vides — le logo semblait « cassé » pendant toute la moitié
      arrière du tour, puis redevenait net. Mesuré aussi en statique : à ~95°,
      bouillie de pixels dédoublés, les deux plans se disputant la tranche.

   2. La parade DÉTERMINISTE : chaque face porte une animation d'opacité
      calée sur la rotation — l'avant n'existe que sur 0–90° et 270–360°,
      l'arrière que sur 90–270°. Plus rien ne dépend d'une heuristique de
      rendu. La bascule se fait en 7 ms au moment où la face est de toute
      façon vue par la tranche : invisible.

   Et l'on écarte les faces d'un pixel en Z (`translateZ`) : fini la bataille
   de pixels entre deux plans confondus. À 1600 px de perspective, ce pixel
   grossit l'image de 0,06 % — imperceptible. */
.spin__face{
  display:block;backface-visibility:hidden;-webkit-backface-visibility:hidden;
  transform:translateZ(1px);
  animation:spin-avant var(--spin-t,7s) linear infinite;
}
.spin__face img{width:100%;height:auto}
.spin__face--back{
  position:absolute;inset:0;
  transform:rotateY(180deg) translateZ(1px);
  animation:spin-arriere var(--spin-t,7s) linear infinite;
}
@keyframes spin3d{to{transform:rotateY(360deg)}}
@keyframes spin-avant{0%,24.9%{opacity:1}25%,74.9%{opacity:0}75%,100%{opacity:1}}
@keyframes spin-arriere{0%,24.9%{opacity:0}25%,74.9%{opacity:1}75%,100%{opacity:0}}

/* Mouvement refusé : le logo se fige de face, parfaitement lisible.
   Couper AUSSI les animations de face : sans ça, la porte d'opacité
   continuerait de tourner et masquerait la face avant une moitié du temps. */
@media (prefers-reduced-motion:reduce){
  .spin{animation:none;transform:none}
  .spin__face{animation:none;transform:none}
  .spin__face--back{display:none}
}
.hero__sub{
  display:flex;flex-direction:column;align-items:center;
  gap:clamp(1.2rem,2.6vw,2rem);
  border-top:1px solid var(--edge);padding-top:clamp(1.3rem,3vw,2.2rem);
  max-width:52rem;margin-inline:auto;width:100%;
}
/* La signature du collectif remplace la phrase d'accroche : c'est une
   énumération, pas une phrase. Elle se compose donc en capitales monospacées
   très espacées, comme un cartouche, et non en italique de labeur. */
.hero__claim{
  display:block;text-align:center;max-width:none;
  font-family:var(--mono);font-weight:700;
  font-size:clamp(.72rem,1.5vw,.88rem);
  letter-spacing:.24em;text-transform:uppercase;
  color:var(--bone);
  overflow-wrap:anywhere;
}
.hero__claim .dot{
  display:inline-block;vertical-align:middle;
  width:6px;height:6px;background:var(--hot);border-radius:50%;
  margin-right:.8em;margin-top:-.15em;
  animation:pulse 2.2s ease-in-out infinite;
}
/* flex:none ferait déborder les boutons sur mobile : on laisse rétrécir */
.hero__cta{display:flex;gap:.8rem;flex-wrap:wrap;justify-content:center;min-width:0}
@media (max-width:560px){
  .hero__sub{align-items:stretch}
  .hero__cta{width:100%}
  .hero__cta .btn{flex:1 1 12rem;justify-content:center;padding-inline:1rem}
}
.hero__scroll{
  position:absolute;left:50%;transform:translateX(-50%);bottom:1.1rem;
  font-family:var(--mono);font-size:.7rem;letter-spacing:.2em;
  text-transform:uppercase;color:var(--ash);
  display:flex;align-items:center;gap:.5rem;
}
.hero__scroll::after{
  content:'';width:1px;height:26px;background:var(--edge);
  animation:drop 1.9s var(--ease) infinite;transform-origin:0 0;
}
@keyframes drop{0%{transform:scaleY(0)}50%{transform:scaleY(1)}100%{transform:scaleY(0);transform-origin:0 100%}}

/* --- Écrans bas : le calcul du logo fait le travail, on ne resserre plus
   que le CONTENU réel (ce qui donne du mou sous la réserve --rsv) --------- */
@media (max-height:820px){
  .hero__sub{padding-top:1.1rem;gap:1rem}
}
@media (max-height:620px){
  .hero__scroll{display:none}
  .hero{padding-block:4.2rem 1.6rem}
  .hero__title{--rsv:16rem}
  .hero__claim{font-size:.95rem}
  .hero__sub{padding-top:.8rem;gap:.8rem}
}
/* Paysage téléphone : la hauteur ne suffit plus, le hero se déroule. */
@media (max-height:460px){
  .hero{min-height:auto;padding-block:4.6rem 2rem}
}

/* --------------------------------------------------------------------------
   12 — TICKER
   -------------------------------------------------------------------------- */
.tick{
  overflow:hidden;white-space:nowrap;
  border-block:1px solid var(--edge);
  background:var(--void);
  padding-block:.85rem;
  user-select:none;
}
.tick--inv{background:var(--hot);border-color:var(--hot)}
.tick--inv .tick__item{color:var(--on-hot)}
.tick--inv .tick__sep{color:rgba(255,255,255,.5)}
.tick__track{display:inline-flex;gap:0;will-change:transform;animation:marq var(--dur,34s) linear infinite}
.tick:hover .tick__track{animation-play-state:paused}
/* Ticker en Trajan, comme le marquee de l'agency */
.tick__item{
  font-family:var(--display);font-weight:800;
  font-size:clamp(1rem,2.4vw,1.9rem);
  letter-spacing:var(--track-d);text-transform:uppercase;color:var(--bone);
  padding-inline:clamp(.8rem,2vw,1.5rem);flex:none;
}
.tick__sep{
  color:var(--hot);padding-inline:.2rem;flex:none;
  font-size:clamp(.8rem,1.8vw,1.4rem);align-self:center;
}
@keyframes marq{to{transform:translateX(-50%)}}
.tick--rev .tick__track{animation-direction:reverse}

/* --------------------------------------------------------------------------
   13 — PLAQUE D'AFFICHE  ← le composant central
   Un event, un produit, un article, un résident : même pièce.
   -------------------------------------------------------------------------- */
.plates{
  --pg:clamp(1.1rem,2.4vw,2.2rem);
  display:grid;
  grid-template-columns:repeat(auto-fill,minmax(min(100%,var(--col,19rem)),1fr));
  gap:var(--pg);
}
.plates--2{--col:27rem}
.plates--wide{--col:24rem}
/* Une archive est une matière SECONDAIRE : elle doit rester dense, y compris
   au doigt. À 14 rem fixes, 360 px de large ne tenaient qu'une colonne et les
   onze vignettes déroulaient 6 700 px de défilement — l'archive pesait alors
   plus lourd que les dates à venir. Le `min()` fait tomber la colonne à la
   moitié de la place disponible quand 14 rem ne rentrent pas deux fois : deux
   colonnes sur mobile, sans une seule media query. */
/* Largeur de colonne à trois niveaux, sans une seule media query :
     · la CIBLE vient du build (`--cols`, voir bestCols) et évite la vignette
       orpheline en fin de grille ;
     · la MOITIÉ garde deux colonnes au doigt, jamais une seule — une archive
       en pleine largeur déroulait 6 700 px sur mobile ;
     · le PLANCHER de 9 rem empêche la cible de dégénérer en meurtrières quand
       l'écran ne peut pas tenir le nombre de colonnes visé.
   `auto-fill` fait le reste : il retire des colonnes tout seul en rétrécissant. */
.plates--dense{
  --pg:clamp(.8rem,1.6vw,1.3rem);
  /* Le `- .5px` n'est pas un ajustement esthétique : `auto-fill` place
     `floor((W + gap) / (col + gap))` colonnes, et à la valeur EXACTE l'arrondi
     flottant retombe une colonne en dessous — 5,998 devient 5. Un demi-pixel
     de mou fait tomber la division du bon côté. */
  --col:max(8.5rem,min(
    calc((100% - (var(--cols,5) - 1) * var(--pg)) / var(--cols,5) - .5px),
    calc((100% - var(--pg)) / 2)
  ));
}
/* Peu de pièces : on impose le nombre de colonnes pour qu'elles occupent
   toute la ligne. Le `max()` garde une largeur minimale décente, donc les
   petits écrans repassent naturellement à une seule colonne. */
.plates--n2{--col:max(19rem,calc((100% - var(--pg)) / 2))}
.plates--n3{--col:max(17rem,calc((100% - var(--pg) * 2) / 3))}

.plate{position:relative;isolation:isolate}
.plate__link{display:flex;flex-direction:column;height:100%}

/* --------------------------------------------------------------------------
   ALIGNEMENT DES RANGS — ce qui redresse vraiment la grille.

   En colonne flex, chaque plaque répartissait sa hauteur pour son compte : le
   `margin-top:auto` du pied absorbait tout le reste. Deux plaques voisines
   n'avaient donc AUCUN rang commun — mesuré sur l'archive, le vide avant le
   pied allait de 0 à 94 px d'une vignette à l'autre, et le titre de la
   troisième commençait deux lignes plus bas que celui de la première. C'est ce
   décalage, pas les images, qui donnait la page « mal agencée ».

   `subgrid` fait porter les rangs par la GRILLE : toutes les plaques d'une
   même ligne alignent méta, lieu, titre, line-up et pied, quelle que soit la
   longueur de chacun. Le nombre de rangs dépend du type de plaque, d'où
   `--rows` — sans lui le pied d'un produit (3 rangs) flotterait au milieu.

   Le flex reste le socle : là où subgrid manque, la plaque garde exactement le
   comportement d'avant. Rien ne dépend de cette amélioration pour s'afficher.
   -------------------------------------------------------------------------- */
@supports (grid-template-rows: subgrid) {
  .plates{align-items:start}
  .plates > .plate{
    --rows:6;                       /* event : cadre, méta, lieu, titre, line-up, pied */
    display:grid;grid-template-rows:subgrid;grid-row:span var(--rows);
  }
  .plates > .plate--sq{--rows:3}    /* produit : cadre, titre, pied */
  .plates > .plate--wide{--rows:5}  /* article : cadre, méta, titre, extrait, pied */
  .plates > .plate > .plate__link{
    display:grid;grid-template-rows:subgrid;grid-row:1 / -1;height:auto;
  }
  /* La héro n'est jamais en ligne avec une autre : elle garde sa mise en pages
     en deux colonnes, où le subgrid n'a rien à aligner. */
  .plates > .plate--hero,
  .plates > .plate--hero > .plate__link{display:flex;flex-direction:column}
}

/* La découpe diagonale est exprimée en POURCENTAGE DU CADRE, pas en vw.
   En vw, `--band:7vw` valait 134 px sur un écran 1920 : anodin sur une plaque
   héro de 700 px de haut, mais dévorant 45 % d'une vignette d'archive de
   300 px. Le cisaillement paraissait aléatoire d'une grille à l'autre. En
   pourcentage il reste proportionnel partout — c'est la même signature à
   toutes les tailles. `--band` (en vw) reste réservé aux masses pleine
   largeur, où la diagonale doit bien se mesurer à l'écran. */
.plate__frame{
  --fb:5.5%;
  position:relative;overflow:hidden;
  aspect-ratio:var(--ar,3/4);
  background:var(--void);
  clip-path:polygon(0 var(--fb),100% 0,100% calc(100% - var(--fb)),0 100%);
  transition:clip-path .5s var(--ease);
}
.plate--flat .plate__frame{clip-path:none}
.plate--sq .plate__frame{--ar:1}
.plate--wide .plate__frame{--ar:16/10;--fb:4.5%}

.plate__img{
  width:100%;height:100%;object-fit:cover;
  filter:grayscale(1) contrast(1.28) brightness(1.06);
  /* Aucun zoom au repos : le cadre est au format du visuel, donc `cover` ne
     rogne rien. Le moindre agrandissement se reprendrait sur le lettrage du
     flyer, qui court jusqu'au bord. Le zoom reste au survol, où il est lu
     comme un geste et non comme un cadrage. */
  transition:filter .55s var(--ease),transform .7s var(--ease);
}
.plate__link:hover .plate__img{
  filter:grayscale(0) contrast(1.06) brightness(1);
  transform:scale(1.07);
}
/* Repli typographique si l'image manque ou échoue */
.plate__fallback{
  position:absolute;inset:0;display:grid;place-items:center;
  background:
    repeating-linear-gradient(135deg,var(--void) 0 9px,rgba(237,234,227,.07) 9px 18px);
  font-family:var(--trajan);font-weight:700;
  font-size:clamp(1.4rem,4vw,2.6rem);letter-spacing:.16em;
  color:var(--edge);text-transform:uppercase;
}
.plate__scrim{
  position:absolute;inset:0;
  background:linear-gradient(to top,rgba(0,0,0,.78) 0%,transparent 46%);
  opacity:.85;transition:opacity .4s var(--ease);
}
.plate__link:hover .plate__scrim{opacity:.55}

/* filet rouge décalé = erreur de repérage */
.plate__frame::after{
  content:'';position:absolute;inset:0;
  border:1px solid var(--hot);
  clip-path:inherit;
  opacity:0;transform:translate(3px,2px);
  transition:opacity .35s var(--ease),transform .5s var(--ease);
  pointer-events:none;
}
.plate__link:hover .plate__frame::after{opacity:.75;transform:translate(7px,4px)}

.plate__badge{
  position:absolute;top:calc(var(--fb) + .55rem);left:.6rem;z-index:2;
  font-family:var(--mono);font-size:.7rem;font-weight:700;
  letter-spacing:.16em;text-transform:uppercase;
  background:var(--hot);color:var(--on-hot);
  padding:.3em .55em;
}
.plate__badge--ghost{background:var(--void);color:var(--bone);border:1px solid var(--edge)}

.plate__meta{
  display:flex;gap:.65rem;align-items:baseline;flex-wrap:wrap;
  font-family:var(--mono);font-size:.7rem;letter-spacing:.15em;
  text-transform:uppercase;color:var(--ash);
  margin-top:.85rem;
}
.plate__meta b{color:var(--hot);font-weight:700}
.plate__meta .sep{color:var(--edge)}

/* Le lieu sur son propre rang, tenu à UNE ligne. Dans le flux de la méta, il
   faisait passer le bloc de 3 à 6 lignes selon le nom de la salle : « Palais
   des Sports Robert Charpentier, Issy-Les-Moulineaux » à côté de « Nexus,
   Pantin ». Isolé et borné, il ne déforme plus rien — et le nom complet reste
   lisible au survol comme aux lecteurs d'écran, puisque le texte est entier
   dans le HTML. */
.plate__where{
  margin-top:.3rem;
  font-family:var(--mono);font-size:.7rem;letter-spacing:.12em;
  text-transform:uppercase;color:var(--ash);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}

/* Le nom d'une plaque est un TITRE : il se compose dans la capitale impériale
   de la marque, comme tous les autres titres du site. Il était en condensé
   Archivo, ce qui faisait cohabiter deux systèmes typographiques sur la même
   page — une carte de journal ne ressemblait pas au titre de section juste
   au-dessus d'elle. */
.plate__name{
  font-family:var(--display);font-weight:900;
  font-size:clamp(1.02rem,1.85vw,1.5rem);
  text-transform:uppercase;letter-spacing:var(--track-d);line-height:1.08;
  margin-top:.4rem;overflow-wrap:anywhere;
  transition:color .25s;
}
.plate__link:hover .plate__name{color:var(--hot)}
/* Cinzel n'a pas d'axe de chasse : un nom long se règle au CORPS, pas à la
   largeur. `data-len` est posé au build (lenClass) et par putsch.js. */
.plate__name[data-len='short']{font-size:clamp(1.2rem,2.4vw,1.9rem)}
.plate__name[data-len='long']{font-size:clamp(.94rem,1.55vw,1.24rem)}
.plate__name[data-len='xlong']{font-size:clamp(.88rem,1.3vw,1.06rem)}

.plate__excerpt{
  margin-top:.5rem;color:var(--ash);font-size:.86rem;line-height:1.5;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;
}
.plate__foot{
  margin-top:auto;padding-top:.8rem;
  display:flex;justify-content:space-between;align-items:center;gap:.6rem;
  font-family:var(--mono);font-size:.7rem;letter-spacing:.14em;text-transform:uppercase;
}
.plate__price{color:var(--bone);font-weight:700}
.plate__price s{color:var(--ash);font-weight:400;margin-right:.4em}
.plate__go{color:var(--ash);transition:transform .3s var(--ease),color .2s}
.plate__link:hover .plate__go{transform:translateX(.3em);color:var(--hot)}

/* états
   Ces affiches sont des flyers hardcore : fond noir, lettrage blanc, déjà très
   sombres. L'assombrissement se cumulait — `brightness(.56)`, `opacity(.72)`
   et le voile du cadre — jusqu'à ce qu'une vignette d'archive ne se distingue
   plus du fond de la page. Une archive doit se lire comme une archive, pas
   disparaître : on garde le retrait, on le prend sur le CONTRASTE et non sur
   la luminosité, et le survol rend l'affiche pleine. */
.plate[data-status='soldout'] .plate__img,
.plate[data-status='cancelled'] .plate__img{filter:grayscale(1) contrast(.92) brightness(.66)}
.plate[data-status='soldout'] .plate__link:hover .plate__img,
.plate[data-status='cancelled'] .plate__link:hover .plate__img{filter:grayscale(1) contrast(1.02) brightness(.86);transform:scale(1.02)}
.plate--past .plate__img{filter:grayscale(1) contrast(1.04) brightness(.88)}
.plate--past .plate__link:hover .plate__img{filter:grayscale(0) contrast(1.06) brightness(1)}

/* plaque héro pleine largeur (prochaine date) */
.plate--hero .plate__frame{--fb:4%}
.plate--hero .plate__link{
  display:grid;grid-template-columns:minmax(0,1.05fr) minmax(0,1fr);
  gap:clamp(1.4rem,4vw,3.6rem);align-items:center;
}
.plate--hero .plate__frame{--ar:4/5}
.plate--hero .plate__name[data-len]{font-size:clamp(1.7rem,5.2vw,4rem);line-height:1.02}
.plate--hero .plate__body{display:flex;flex-direction:column;gap:.9rem}
@media (max-width:860px){
  .plate--hero .plate__link{grid-template-columns:1fr}
  .plate--hero .plate__frame{--ar:3/4}
}

/* --------------------------------------------------------------------------
   14 — ÉCRITEAU : l'absence, composée

   Remplace l'ancien cadre en pointillés, qui était littéralement un trou dans
   la page. Aucune date annoncée est un état NORMAL et durable ici : il reçoit
   donc le même soin qu'une affiche, en format paysage pleine largeur.
   -------------------------------------------------------------------------- */
.notice{
  --fb:2.6%;
  position:relative;overflow:hidden;isolation:isolate;
  clip-path:polygon(0 var(--fb),100% 0,100% calc(100% - var(--fb)),0 100%);
  background:var(--void);
  padding:clamp(2.4rem,6vw,4.5rem) clamp(1.3rem,5vw,4rem);
  display:grid;gap:clamp(.9rem,2.2vw,1.5rem);
}
.notice__grid{
  position:absolute;inset:0;z-index:-1;pointer-events:none;
  background:
    repeating-linear-gradient(to right,var(--edge) 0 1px,transparent 1px 12.5%),
    repeating-linear-gradient(to bottom,var(--edge) 0 1px,transparent 1px 33.33%);
  opacity:1;
}
.notice__top{
  display:flex;justify-content:space-between;gap:1rem;flex-wrap:wrap;
  font-family:var(--mono);font-size:.7rem;font-weight:700;letter-spacing:.2em;
  text-transform:uppercase;color:var(--ash);
  border-bottom:1px solid var(--edge);padding-bottom:1rem;
}
.notice__t{
  font-family:var(--display);font-weight:900;
  font-size:clamp(1.8rem,7.4vw,5rem);line-height:.96;letter-spacing:var(--track-giant);
  text-transform:uppercase;overflow-wrap:anywhere;
}
.notice__p{color:var(--ash);max-width:58ch;font-size:.97rem;line-height:1.62}
.notice__cta{display:flex;gap:.7rem;flex-wrap:wrap;margin-top:.3rem}
.notice__foot{
  display:flex;justify-content:space-between;gap:1rem;flex-wrap:wrap;
  border-top:1px solid var(--edge);padding-top:1rem;margin-top:.3rem;
  font-family:var(--mono);font-size:.7rem;letter-spacing:.14em;
  text-transform:uppercase;color:var(--hot-dim);
}
.notice__foot span:last-child{text-align:right;max-width:52ch}
@media (max-width:560px){
  .notice__cta .btn{flex:1 1 100%;justify-content:center}
  .notice__foot span:last-child{text-align:left}
}

/* --------------------------------------------------------------------------
   15 — CELLULES NUMÉROTÉES (branches du collectif, services)
   -------------------------------------------------------------------------- */
.cells{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,17rem),1fr));gap:1px;background:var(--edge)}
.cell{
  background:var(--void);padding:clamp(1.5rem,3.2vw,2.6rem);
  display:flex;flex-direction:column;gap:.7rem;
  position:relative;overflow:hidden;
  transition:background .3s var(--ease);
}
.cell:hover{background:var(--hot)}
.cell:hover .cell__t{color:var(--on-hot)}
.cell:hover .cell__p{color:rgba(0,0,0,.72)}
.cell:hover .cell__n{color:rgba(0,0,0,.24)}
.cell__n{
  font-family:var(--trajan);font-weight:700;
  font-size:clamp(2.6rem,6vw,4.4rem);line-height:.8;
  color:#2E2C2A;
  transition:color .3s;
}
.cell:hover .cell__n{color:var(--hot-dim)}
.cell__t{
  font-family:var(--display);font-weight:800;letter-spacing:var(--track-d);
  font-size:clamp(.98rem,1.7vw,1.28rem);text-transform:uppercase;line-height:1.18;
}
.cell__p{color:var(--ash);font-size:.92rem;line-height:1.56}

/* --------------------------------------------------------------------------
   16 — BANDE DIAGONALE (masse)
   -------------------------------------------------------------------------- */
/* La réserve verticale ne doit dépasser la découpe diagonale que de ce qu'il
   faut : à `--band + 40 %` de section, la bande faisait 380 px pour trois
   lignes de texte. Le contenu étant centré, seule la moitié de la diagonale
   le menace. */
.mass{
  clip-path:polygon(0 var(--band),100% 0,100% calc(100% - var(--band)),0 100%);
  padding-block:calc(var(--band) * .55 + var(--sec) * .3);
  position:relative;
}
.mass--inv{background:var(--hot);color:var(--on-hot)}
/* Noir plein, cadré par deux filets blancs : plus aucun aplat gris. Le
   bloc existe par ses règles, pas par une nuance de fond. */
.mass--carbon{
  background:var(--void);
  border-block:2px solid var(--bone);
}
.mass--inv .mono{color:rgba(255,255,255,.72)}
.mass--inv .btn{border-color:var(--on-hot);color:var(--on-hot)}
.mass--inv .btn::before{background:var(--on-hot)}
.mass--inv .btn:hover{color:var(--hot)}

/* --------------------------------------------------------------------------
   17 — PIED DE PAGE
   -------------------------------------------------------------------------- */
/* La dernière section de page apporte déjà sa propre respiration basse.
   Cumuler `var(--sec)` ici ajoutait jusqu'à 240 px de noir supplémentaire
   avant le pied de page — l'effet de page qui se vide. Une masse pleine
   largeur, elle, doit toucher le pied de page sans interstice. */
.footer{
  border-top:1px solid var(--edge);
  padding-top:clamp(2.6rem,6vw,5rem);
  margin-top:clamp(2.5rem,5vw,4.5rem);
  position:relative;overflow:hidden;
}
.mass + .footer{margin-top:0}
.footer__grid{
  display:grid;gap:clamp(1.8rem,4vw,3.4rem);
  grid-template-columns:minmax(0,1.6fr) repeat(3,minmax(0,1fr));
  padding-bottom:clamp(2.4rem,5vw,4rem);
}
@media (max-width:900px){ .footer__grid{grid-template-columns:1fr 1fr} }
@media (max-width:560px){ .footer__grid{grid-template-columns:1fr} }
.footer__tag{font-family:var(--serif-d);font-style:italic;font-size:1.1rem;color:var(--ash);max-width:30ch;margin-bottom:1.2rem}
.footer h4{
  font-family:var(--mono);font-size:.7rem;letter-spacing:.2em;
  text-transform:uppercase;color:var(--hot);margin-bottom:1rem;font-weight:700;
}
.footer li{margin-bottom:.5rem}
.footer li a{color:var(--ash);font-size:.9rem;transition:color .2s,padding-left .25s var(--ease)}
.footer li a:hover{color:var(--bone);padding-left:.25rem}
.footer__mail{
  font-family:var(--display);font-weight:900;letter-spacing:var(--track-d);
  font-size:clamp(.9rem,2.1vw,1.6rem);text-transform:uppercase;
  display:inline-block;overflow-wrap:anywhere;line-height:1.2;
}
.footer__mail:hover{color:var(--hot)}
.footer__bar{
  border-top:1px solid var(--edge);
  padding-block:1.3rem;
  display:flex;justify-content:space-between;gap:1rem;flex-wrap:wrap;
  font-family:var(--mono);font-size:.7rem;letter-spacing:.14em;
  text-transform:uppercase;color:var(--ash);
}
/* Logo sous le mail : la signature de marque du pied de page, à taille de
   colonne — le filigrane géant qu'il remplace mangeait tout l'écran. */
.footer__logo{display:block;width:clamp(120px,13vw,175px);margin:1.2rem 0 .4rem}
.footer__logo img{width:100%;height:auto;transition:opacity .25s var(--ease),transform .35s var(--ease)}
.footer__logo:hover img{opacity:.78;transform:scale(1.05)}

.social{display:flex;gap:.7rem}
.social a{
  width:38px;height:38px;display:grid;place-items:center;
  border:1px solid var(--edge);
  /* certaines pages listent des sigles (« IG », « SG ») plutôt que des SVG :
     la casse mono les fait passer pour un choix, pas pour un oubli */
  font-family:var(--mono);font-size:.7rem;font-weight:700;letter-spacing:.08em;
  transition:background .22s var(--ease),color .22s,border-color .22s;
}
.social a:hover{background:var(--bone);color:var(--void);border-color:var(--bone)}
.social svg{width:16px;height:16px;fill:currentColor}
/* variante contact : icônes + un lien nommé (Shotgun n'a pas de glyphe) */
.social--row{align-items:center}
.social--row a.mono{width:auto;padding:0 .8em;letter-spacing:.1em}

/* --------------------------------------------------------------------------
   18 — FORMULAIRES
   -------------------------------------------------------------------------- */
.field{display:flex;flex-direction:column;gap:.45rem;margin-bottom:1.3rem}
.field label{
  font-family:var(--mono);font-size:.7rem;letter-spacing:.16em;
  text-transform:uppercase;color:var(--ash);
}
.field label .req{color:var(--hot)}
.field input,.field textarea,.field select{
  background:transparent;border:0;border-bottom:1px solid var(--edge);
  padding:.75rem 0;font-family:var(--body);font-size:1rem;color:var(--bone);
  transition:border-color .22s;
}
.field input:focus,.field textarea:focus,.field select:focus{
  border-bottom-color:var(--hot);outline:none;
}
.field textarea{resize:vertical;min-height:8rem}
.field select{cursor:pointer}
.field select option{background:var(--void)}
.field__err{
  font-family:var(--mono);font-size:.7rem;letter-spacing:.13em;
  text-transform:uppercase;color:var(--hot-lite);min-height:1em;
}
.field[data-invalid] input,.field[data-invalid] textarea{border-bottom-color:var(--hot-lite)}

.form-note{
  font-family:var(--mono);font-size:.7rem;letter-spacing:.13em;
  text-transform:uppercase;padding:.9rem 1.1rem;border-left:2px solid var(--hot);
  background:var(--void);margin-bottom:1.4rem;
}

/* --------------------------------------------------------------------------
   19 — BANDEAU D'ALERTE (API indisponible, etc.)
   -------------------------------------------------------------------------- */
.alert{
  display:flex;align-items:center;gap:.9rem;flex-wrap:wrap;
  border:1px solid var(--hot);background:rgba(255,255,255,.06);
  padding:.85rem 1.1rem;margin-bottom:1.8rem;
  font-family:var(--mono);font-size:.7rem;letter-spacing:.13em;text-transform:uppercase;
}
.alert b{color:var(--hot)}
.alert button{
  margin-left:auto;border:1px solid var(--hot);color:var(--hot);
  padding:.4em .8em;font-family:var(--mono);font-size:.7rem;letter-spacing:.14em;
  text-transform:uppercase;transition:background .2s,color .2s;
}
.alert button:hover{background:var(--hot);color:var(--on-hot)}

/* --------------------------------------------------------------------------
   20 — PAGE 404 / EN-TÊTE DE PAGE
   -------------------------------------------------------------------------- */
.phead{
  padding-top:clamp(7rem,14vw,11rem);
  padding-bottom:clamp(1.6rem,4vw,3.2rem);
  border-bottom:1px solid var(--edge);
  margin-bottom:clamp(2rem,5vw,4rem);
}
.phead__k{margin-bottom:.9rem}
.phead__t{
  font-family:var(--display);font-weight:900;letter-spacing:var(--track-giant);
  font-size:clamp(2rem,8.6vw,6.4rem);line-height:.94;
  text-transform:uppercase;overflow-wrap:anywhere;
}
.phead__p{margin-top:1.2rem;max-width:52ch;color:var(--ash)}

.nf{
  min-height:100svh;display:grid;place-items:center;text-align:center;
  padding:clamp(6rem,14vw,9rem) var(--gut) var(--gut);
  position:relative;overflow:hidden;
}
.nf__in{max-width:54rem;margin-inline:auto}
.nf__code{
  font-family:var(--display);font-weight:900;
  font-size:min(30vw,13rem);line-height:.92;letter-spacing:var(--track-giant);
  color:var(--bone);
}
.nf__t{font-size:clamp(1.4rem,5vw,3.2rem);margin-bottom:1rem}
.nf__p{color:var(--ash);max-width:46ch;margin:0 auto 2rem}
/* Une 404 qui n'offre qu'un retour à l'accueil renvoie le visiteur à zéro :
   on rouvre ici toutes les portes du site. */
.nf__alt{margin-top:clamp(2rem,5vw,3rem);color:var(--hot-dim)}
.nf__links{margin-top:1rem;display:flex;flex-wrap:wrap;gap:.5rem;justify-content:center}
.nf__links a{
  font-family:var(--mono);font-size:.7rem;letter-spacing:.14em;text-transform:uppercase;
  border:1px solid var(--edge);padding:.6em .9em;color:var(--ash);
  display:inline-flex;align-items:center;min-height:24px;
  transition:color .2s,border-color .2s,background .2s;
}
.nf__links a:hover{background:var(--bone);color:var(--void);border-color:var(--bone)}

/* --------------------------------------------------------------------------
   21 — CIBLES TACTILES  (WCAG 2.5.8 : 24×24 minimum, 44×44 au doigt)
   Les petits libellés en mono restent visuellement fins, mais leur zone
   cliquable est étendue par le padding — sans décaler la mise en page.
   -------------------------------------------------------------------------- */
.shead__more,
.footer li a,
.footer__bar a,
.footer__mail,
/* enfants DIRECTS seulement : `.drawer__foot a` attrapait aussi les icônes
   sociales et son inline-flex écrasait leur centrage en grille — icône
   collée au bord gauche du carré */
.drawer__foot > a,
.drawer__foot > button,
.cart__rm,
.cart__close,
.sizes__guide,
.nav__link,
.lang__toggle,
.filters__count,
.aside__list a,
.crumb a,
.mail-xl,
.mono a,
a.mono{
  display:inline-flex;align-items:center;
  min-height:24px;
}
.footer li a,.footer__bar a{padding-block:.15rem}
.aside__list a{padding-block:.2rem}
/* La zone cliquable s'étend vers le HAUT et le BAS seulement : un padding
   horizontal décalait le libellé de 6 px vers la droite, si bien que
   « Retirer » ne s'alignait plus sur le nom du produit juste au-dessus. */
.cart__rm{padding-block:.25rem;padding-inline:0;margin-top:-.25rem}

@media (hover:none),(pointer:coarse){
  .shead__more,
  .footer li a,
  .footer__mail,
  .drawer__foot > a,
  .drawer__foot > button,
  .cart__rm,
  .cart__close,
  .sizes__guide,
  .lang__toggle,
  .drawer__close,
  .drawer__langs a,
  .lang__list a,
  .aside__list a,
  .crumb a,
  .nf__links a,
  .mono a,
  a.mono{min-height:44px}
  .footer li{margin-bottom:0}
  .social a{width:44px;height:44px}
  .chip{padding-block:.85em}
}

/* --------------------------------------------------------------------------
   22 — AFFICHE GÉNÉRÉE
   Le repli quand un visuel manque : une vraie affiche composée en HTML.

   TOUT EST EN `cqw` — pourcentage de la LARGEUR DU CADRE, pas de la fenêtre.
   Le même balisage tient donc de la vignette d'archive (≈200 px) à la plaque
   héro (≈700 px) sans une seule media query, et une grille dense reste lisible
   là où un `vw` aurait produit des titres démesurés.

   Seule exception : `.poster` lui-même ne peut pas consommer ses propres unités
   de conteneur. Son padding est donc en `%` — ce qui revient au même, un
   pourcentage de padding se mesurant toujours sur la largeur.
   -------------------------------------------------------------------------- */
.plate__frame--drawn{background:var(--void)}

/* `space-between` plutôt qu'un `margin-top:auto` sur le titre : la hauteur
   d'un cadre 3/4 dépasse toujours celle du texte, et concentrer le contenu
   en bas laissait un tiers de vide au milieu — exactement ce qu'on cherchait
   à supprimer. Réparti, l'excédent devient de la respiration d'affiche. */
.poster{
  position:absolute;inset:0;
  container-type:inline-size;
  display:flex;flex-direction:column;justify-content:space-between;
  padding:9% 12% 7% 6.5%;
  background:var(--void);color:var(--bone);
  overflow:hidden;isolation:isolate;
  text-transform:uppercase;
  user-select:none;
}
.poster--pr{padding-top:8%}
.poster--ar{padding:6% 10% 5.5% 5%}

/* trame de repérage : quatre colonnes, comme un gabarit d'imprimeur */
.poster__grid{
  position:absolute;inset:0;z-index:-1;
  background:
    repeating-linear-gradient(to right,var(--edge) 0 1px,transparent 1px 25%),
    repeating-linear-gradient(to bottom,var(--edge) 0 1px,transparent 1px 33.33%);
  opacity:.55;
}

.poster__top{
  display:flex;justify-content:space-between;align-items:center;gap:2cqw;
  font-family:var(--mono);font-size:2.5cqw;font-weight:700;letter-spacing:.18em;
  color:var(--ash);
  border-bottom:1px solid var(--edge);padding-bottom:2.2cqw;
  white-space:nowrap;overflow:hidden;
}
/* Le wordmark plutôt que le mot « PUTSCH » composé : c'est la marque elle-même
   qui signe l'affiche, et elle s'affiche sans dépendre d'une webfont. */
.poster__mark{width:16cqw;height:auto;flex:none}
.poster--ar .poster__mark{width:12cqw}
.poster--v2 .poster__mark{filter:invert(1)}

.poster__date{display:flex;align-items:baseline;gap:2.4cqw;margin-top:3cqw}
.poster__day{
  font-family:var(--trajan);font-weight:900;
  font-size:36cqw;line-height:.74;letter-spacing:-.035em;
  color:var(--hot);
}
.poster__mon{
  font-family:var(--mono);font-size:5cqw;font-weight:700;
  letter-spacing:.2em;color:var(--hot);
}
.poster__mon i{display:block;font-style:normal;color:var(--ash);font-size:.76em;margin-top:.5em}

/* `--pt` est calculé au build depuis la longueur de la ligne la plus longue
   (voir fitTitle) : le titre remplit la largeur utile sans jamais se replier
   tout seul, ce qui ferait déborder l'affiche de son cadre. */
.poster__title{
  display:flex;flex-direction:column;
  font-family:var(--cond);font-weight:900;font-stretch:74%;
  font-size:var(--pt,13cqw);line-height:.88;letter-spacing:-.015em;
  overflow-wrap:anywhere;
}
.poster__title span{white-space:nowrap}
.poster__title--ar span{white-space:normal}

.poster__list{
  margin-top:3.2cqw;display:flex;flex-wrap:wrap;gap:0 2.6cqw;
  font-family:var(--mono);font-size:3.2cqw;letter-spacing:.12em;color:var(--ash);
}
.poster__list span + span::before{content:'✕ ';color:var(--hot)}

.poster__foot{
  padding-top:2.6cqw;border-top:1px solid var(--edge);
  display:flex;justify-content:space-between;gap:2cqw;
  font-family:var(--mono);font-size:2.9cqw;letter-spacing:.12em;color:var(--ash);
}
.poster__foot span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* rail vertical le long du bord droit — le réflexe « affiche imprimée » */
.poster__rail{
  position:absolute;right:2.5%;top:6%;bottom:6%;
  writing-mode:vertical-rl;
  font-family:var(--mono);font-size:2.2cqw;letter-spacing:.42em;
  color:var(--hot-dim);white-space:nowrap;overflow:hidden;
  pointer-events:none;
}

/* --- variantes, tirées du slug : déterministes, jamais aléatoires ------- */

/* v1 — bandeau blanc sous le titre */
.poster--v1 .poster__title{
  position:relative;color:var(--on-hot);
  padding:2cqw 3cqw;margin-left:-3cqw;
}
.poster--v1 .poster__title::before{
  content:'';position:absolute;inset:0;z-index:-1;
  background:var(--hot);
  clip-path:polygon(0 7%,100% 0,100% 93%,0 100%);
}

/* v2 — affiche inversée : papier blanc, encre noire */
.poster--v2{background:var(--hot);color:var(--on-hot)}
.poster--v2 .poster__top,
.poster--v2 .poster__foot,
.poster--v2 .poster__list{color:rgba(0,0,0,.6);border-color:rgba(0,0,0,.22)}
.poster--v2 .poster__day{color:var(--on-hot)}
.poster--v2 .poster__mon{color:var(--on-hot)}
.poster--v2 .poster__mon i{color:rgba(0,0,0,.55)}
.poster--v2 .poster__rail{color:rgba(0,0,0,.28)}
.poster--v2 .poster__list span + span::before{color:var(--on-hot)}
.poster--v2 .poster__grid{
  background-image:
    repeating-linear-gradient(to right,rgba(0,0,0,.13) 0 1px,transparent 1px 25%),
    repeating-linear-gradient(to bottom,rgba(0,0,0,.13) 0 1px,transparent 1px 33.33%);
}

/* v3 — quantième plein et filet d'appui sous le titre */
.poster--v3 .poster__day{color:var(--hot-dim)}
.poster--v3 .poster__title{border-bottom:.9cqw solid var(--hot);padding-bottom:2cqw}

/* Au survol de la plaque, l'affiche respire comme le ferait une photo. */
.plate__link:hover .poster__title{transform:translateX(.6cqw)}
.poster__title{transition:transform .5s var(--ease)}
.plate__link:hover .poster__day{color:var(--bone)}
.poster__day{transition:color .4s var(--ease)}

/* Un event passé ou annulé s'éteint, comme une photo s'assombrit. */
.plate--past .poster,
.plate[data-status='cancelled'] .poster{opacity:.62}
.plate--past .plate__link:hover .poster,
.plate[data-status='cancelled'] .plate__link:hover .poster{opacity:.85}
.poster{transition:opacity .45s var(--ease)}

/* --------------------------------------------------------------------------
   23 — BLOCS DE PAGE
   -------------------------------------------------------------------------- */

/* Fil d'Ariane haut de page : remplace un `.phead` vide de sens sur les
   fiches, et porte la respiration sous la nav fixe. */
.crumb{
  display:flex;justify-content:space-between;align-items:center;
  gap:1rem;flex-wrap:wrap;
  padding-top:clamp(6.5rem,13vw,10rem);
  padding-bottom:clamp(1rem,2.4vw,1.8rem);
  border-bottom:1px solid var(--edge);
  margin-bottom:clamp(1.6rem,4vw,3rem);
}
.crumb a{transition:color .2s}
.crumb a:hover{color:var(--hot)}
.crumb span{color:var(--hot-dim);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

.phead--art{padding-top:0;border-bottom:0;margin-bottom:clamp(1.4rem,3vw,2.2rem)}
.phead__t--art{font-size:clamp(1.7rem,5.6vw,4.4rem)}

.lede--wide{max-width:56ch;margin-bottom:clamp(2rem,4.5vw,3.4rem)}
.prose--wide{max-width:74ch}
.prose--art{margin-inline:auto}

/* Duo de colonnes : le gabarit éditorial de tout le site. */
.duo{
  display:grid;grid-template-columns:minmax(0,1.15fr) minmax(0,.85fr);
  gap:clamp(1.8rem,5vw,5rem);align-items:start;
}
.duo--aside{grid-template-columns:minmax(0,1fr) minmax(0,17rem)}
@media (max-width:940px){ .duo,.duo--aside{grid-template-columns:1fr} }

.aside{
  border-left:1px solid var(--edge);
  padding-left:clamp(1rem,2vw,1.6rem);
  position:sticky;top:6.5rem;
}
.aside__list{margin-top:1rem;display:grid;gap:.45rem}
.aside__list a{color:var(--ash);transition:color .2s,padding-left .22s var(--ease)}
.aside__list a:hover{color:var(--hot);padding-left:.25rem}
@media (max-width:940px){
  .aside{
    position:static;border-left:0;border-top:1px solid var(--edge);
    padding-left:0;padding-top:1.4rem;margin-top:2.6rem;
  }
}

/* Compteur d'archives : un chiffre au pochoir vaut mieux qu'une phrase. */
.statline{
  display:flex;align-items:center;gap:clamp(1rem,3vw,2.2rem);
  border-bottom:1px solid var(--edge);
  padding-bottom:1.3rem;margin-bottom:clamp(1.6rem,4vw,3rem);
}
/* Chiffre PLEIN, là où le numéro de section est au trait : c'est ce qui
   distingue une donnée d'un index, quand les deux se suivent. */
.statline__n{
  font-family:var(--trajan);font-weight:900;line-height:.78;
  font-size:clamp(2.4rem,8vw,5.5rem);
  color:var(--hot);flex:none;
}
.statline__p{color:var(--ash);font-size:.9rem;max-width:58ch;line-height:1.55}
.statline__p b{
  color:var(--bone);font-family:var(--mono);font-weight:700;
  font-size:.78rem;letter-spacing:.12em;text-transform:uppercase;
}

.subhead{
  display:flex;align-items:center;gap:1rem;
  margin:clamp(2.2rem,5vw,3.6rem) 0 clamp(1.2rem,3vw,2rem);
}
.subhead::after{content:'';flex:1;height:1px;background:var(--edge)}

.mail-xl{
  font-family:var(--display);font-weight:900;letter-spacing:var(--track-d);
  font-size:clamp(1.05rem,3.4vw,2.3rem);text-transform:uppercase;
  display:inline-block;overflow-wrap:anywhere;line-height:1.16;margin-top:.6rem;
  border-bottom:2px solid var(--edge);
  transition:border-color .25s,color .25s;
}
.mail-xl:hover{color:var(--hot);border-bottom-color:var(--hot)}

/* --------------------------------------------------------------------------
   VOCABULAIRE DE BLOCS
   Chaque type de contenu a son traitement, pour qu'on se repère à l'œil sans
   lire : un aplat inversé n'est pas une fiche technique, qui n'est pas une
   liste de rangs, qui n'est pas une grille de cellules. Tout se ressemblait,
   et la page presse se lisait comme une seule colonne indistincte.
   -------------------------------------------------------------------------- */

/* 1 — CITATION : aplat blanc, encre noire. C'est le bloc que la presse copie,
       il doit se détacher comme un encart imprimé. */
.quote{
  --fb:2.2%;
  background:var(--hot);color:var(--on-hot);
  border:0;
  clip-path:polygon(0 var(--fb),100% 0,100% calc(100% - var(--fb)),0 100%);
  padding:clamp(1.6rem,4vw,3rem);
  display:flex;flex-direction:column;gap:1.5rem;align-items:flex-start;
  max-width:74ch;
}
.quote p{
  font-family:var(--serif-d);font-size:clamp(1.05rem,1.9vw,1.42rem);
  line-height:1.45;
}
.quote .btn{border-color:var(--on-hot);color:var(--on-hot)}
.quote .btn::before{background:var(--on-hot)}
.quote .btn:hover{color:var(--hot)}

/* 2 — FICHE TECHNIQUE : grille de cases réglées, lecture en diagonale. */
/* Les filets sont portés par les CASES, pas par le conteneur : une dernière
   ligne incomplète s'arrête net au lieu de laisser un pavé de fond visible
   là où il manque des cases. */
.spec{
  display:grid;
  grid-template-columns:repeat(auto-fit,minmax(min(100%,var(--sc,20rem)),1fr));
  border-top:1px solid var(--edge);
  border-left:1px solid var(--edge);
}
.spec > div{
  background:var(--void);
  border-right:1px solid var(--edge);
  border-bottom:1px solid var(--edge);
  padding:clamp(.95rem,2vw,1.35rem);
  display:flex;flex-direction:column;gap:.5rem;
  transition:background .3s var(--ease);
}
.spec > div:hover{background:var(--hot)}
.spec dt{
  font-family:var(--mono);font-size:.7rem;font-weight:700;
  letter-spacing:.18em;text-transform:uppercase;color:var(--hot-dim);
}
.spec dd{
  font-family:var(--mono);font-size:.82rem;letter-spacing:.04em;
  color:var(--bone);line-height:1.45;overflow-wrap:anywhere;
}
.spec > div:hover dt{color:rgba(0,0,0,.55)}
.spec > div:hover dd{color:var(--on-hot)}

/* 3 — RANGS : une liste qui se lit comme un sommaire, pas comme un paragraphe. */
.rows{display:grid;gap:1px;background:var(--edge);border-block:1px solid var(--edge)}
.rows__row{
  background:var(--void);
  display:grid;
  grid-template-columns:auto minmax(0,13rem) minmax(0,1fr);
  gap:clamp(.7rem,2.4vw,2rem);align-items:baseline;
  padding-block:clamp(.9rem,2vw,1.3rem);
  transition:background .3s var(--ease);
}
.rows__row:hover{background:var(--hot)}
.rows__n{
  font-family:var(--mono);font-size:.7rem;font-weight:700;
  letter-spacing:.14em;color:var(--hot-dim);
}
.rows__t{
  font-family:var(--display);font-weight:900;
  font-size:clamp(1rem,1.8vw,1.32rem);
  letter-spacing:var(--track-d);text-transform:uppercase;line-height:1.1;
}
.rows__p{color:var(--ash);font-size:.92rem;line-height:1.55}
.rows__row:hover .rows__n{color:rgba(0,0,0,.5)}
.rows__row:hover .rows__t{color:var(--on-hot)}
.rows__row:hover .rows__p{color:rgba(0,0,0,.74)}
@media (max-width:760px){
  .rows__row{grid-template-columns:auto minmax(0,1fr);row-gap:.35rem}
  .rows__p{grid-column:2}
}

.tagline{
  margin-top:2.4rem;border-top:1px solid var(--edge);padding-top:1.2rem;
  display:flex;flex-wrap:wrap;gap:.5rem;
}
.tagline span{border:1px solid var(--edge);padding:.4em .75em}

.art-cover{
  --fb:3.5%;
  position:relative;aspect-ratio:16/9;overflow:hidden;background:var(--void);
  clip-path:polygon(0 var(--fb),100% 0,100% calc(100% - var(--fb)),0 100%);
  margin-bottom:clamp(2rem,5vw,4rem);
}
.art-cover img{width:100%;height:100%;object-fit:cover}

.pdp__row{display:flex;gap:.7rem;flex-wrap:wrap}
.pdp__meta--wide{grid-template-columns:repeat(auto-fit,minmax(min(100%,13rem),1fr))}

/* --------------------------------------------------------------------------
   24 — LINE-UP ILLUSTRÉ
   Les portraits d'artistes déjà programmés donnent un visage au line-up.
   Un nom sans photo garde une pastille d'initiales : la colonne ne se troue
   jamais, et la ligne reste régulière.
   -------------------------------------------------------------------------- */
.lineup{display:grid;gap:1px;background:var(--edge);border-block:1px solid var(--edge)}
.lineup__row{
  background:var(--void);
  display:grid;
  grid-template-columns:auto 4.2rem minmax(0,1fr) auto;
  align-items:center;gap:clamp(.7rem,2vw,1.6rem);
  padding-block:clamp(.5rem,1.4vw,.85rem);
  position:relative;overflow:hidden;
  transition:background .35s var(--ease);
}
.lineup__row:hover{background:var(--hot)}
.lineup__row:hover .lineup__n,
.lineup__row:hover .lineup__meta{color:rgba(0,0,0,.6)}
.lineup__row:hover .lineup__name{color:var(--on-hot)}
.lineup__n{font-family:var(--mono);font-size:.7rem;letter-spacing:.14em;color:var(--ash)}
.lineup__face{
  width:4.2rem;aspect-ratio:3/4;overflow:hidden;background:var(--void);
  border:1px solid var(--edge);
  display:grid;place-items:center;
  clip-path:polygon(0 8%,100% 0,100% 92%,0 100%);
}
.lineup__face img{
  width:100%;height:100%;object-fit:cover;
  filter:grayscale(1) contrast(1.3) brightness(1.04);
  transition:filter .55s var(--ease),transform .7s var(--ease);
}
.lineup__row:hover .lineup__face img{filter:grayscale(0) contrast(1.05);transform:scale(1.09)}
.lineup__face b{font-family:var(--trajan);font-size:.85rem;letter-spacing:.06em;color:var(--ash)}
.lineup__name{
  font-size:clamp(1.2rem,4.2vw,2.5rem);overflow-wrap:anywhere;
  transition:color .25s,transform .45s var(--ease);
}
/* Le déplacement SEUL. La couleur du survol est fixée plus haut, avec le reste
   de l'inversion (`--on-hot`, du noir sur l'aplat blanc). Cette règle reposait
   la couleur à `--hot` — du blanc — et, à spécificité égale, c'est elle qui
   l'emportait : au survol le nom d'artiste passait blanc sur fond blanc, donc
   invisible. Ne pas remettre de `color` ici. */
.lineup__row:hover .lineup__name{transform:translateX(.3rem)}
.lineup__meta{text-align:right;color:var(--ash);font-size:.7rem}
.lineup__meta i{display:block;font-style:normal;color:var(--hot-dim);margin-top:.25em}
@media (max-width:680px){
  .lineup__row{grid-template-columns:auto 3rem minmax(0,1fr);row-gap:.15rem}
  .lineup__face{width:3rem}
  .lineup__meta{grid-column:2 / -1;text-align:left}
}

/* --------------------------------------------------------------------------
   25 — MASSE : le bloc de discours
   -------------------------------------------------------------------------- */
.mass__inner{
  display:flex;flex-direction:column;align-items:center;text-align:center;
  gap:clamp(.7rem,1.8vw,1.2rem);
}
.mass__k{letter-spacing:.2em}
.mass__t{font-size:clamp(1.45rem,5vw,4rem);max-width:22ch}
.mass__p{max-width:56ch;font-size:.96rem;line-height:1.62;color:var(--ash)}
.mass__cta{margin-top:clamp(.8rem,2vw,1.4rem)}
.mass--inv .mass__p{color:rgba(0,0,0,.72)}
.mass--inv .mass__k{color:rgba(0,0,0,.6)}
/* Le carbone seul se distingue à peine du noir absolu : une trame diagonale
   très basse le fait exister sans introduire la moindre teinte. */
.mass--carbon{
  background:var(--void);
  border-block:1px solid var(--edge);
  position:relative;overflow:hidden;
}
/* Un aplat net, sans trame ni filigrane : la diagonale répétée faisait un
   damier, et le pochoir en contour creux alourdissait la bande. */
.mass--carbon .mass__inner{position:relative}
.mass--carbon .mass__k{color:var(--hot)}

/* Catalogue à une seule pièce : elle passe en grand, centrée. Une grille à
   une colonne laisserait les deux tiers de la ligne vides. */
.plates--solo{grid-template-columns:minmax(0,1fr)}
.plates--solo .plate{max-width:min(100%,44rem);margin-inline:auto;width:100%}
.plates--solo .plate--sq .plate__frame{--ar:4/5}
.plates--solo .plate__name[data-len]{font-size:clamp(1.3rem,3.4vw,2.4rem)}

/* --------------------------------------------------------------------------
   26 — JAUGE DE LECTURE
   -------------------------------------------------------------------------- */
.progress{
  position:fixed;top:0;left:0;right:0;height:2px;
  z-index:calc(var(--z-nav) + 1);pointer-events:none;
}
.progress i{
  display:block;height:100%;background:var(--hot);
  transform:scaleX(var(--p,0));transform-origin:0 50%;
  will-change:transform;
}

/* --------------------------------------------------------------------------
   27 — EFFETS AU POINTEUR ET AU DÉFILEMENT
   -------------------------------------------------------------------------- */
[data-magnet]{will-change:transform}

/* Parallaxe : le visuel glisse un peu moins vite que la page (`--par`, posé
   par putsch.js), et déborde volontairement le cadre en haut et en bas — sans
   cette marge, un déplacement de 14 px découvrirait une bande de fond, très
   visible sur une affiche inversée à fond blanc.

   Elle ne vaut QUE pour l'affiche générée (`.poster`), dont nous composons les
   marges. Une affiche importée ne peut pas se le permettre : il fallait la
   zoomer de 6 % pour couvrir la course, et ces 6 % tombaient sur la date et
   les horaires imprimés en tête du flyer. Son cadre étant désormais au format
   mesuré du visuel, elle le remplit exactement, sans zoom ni glissement. */
.plate--hero .plate__frame > img,
.gal__main--ev > img{transform:none}
.plate--hero .plate__link:hover .plate__frame > img{transform:scale(1.04)}
.plate--hero .poster,
.gal__main--ev .poster{top:-18px;bottom:-18px;transform:translateY(var(--par,0));will-change:transform}

/* Retour visible d'une action de partage ou de copie */
[data-done]{border-color:var(--hot);color:var(--hot)}

.hero__next{
  display:inline-flex;align-items:center;gap:.7rem;flex-wrap:wrap;
  justify-content:center;
  border:1px solid var(--edge);padding:.7em 1.1em;
  font-size:.7rem;
}
.hero__next b{color:var(--hot);font-weight:700}
.hero__next-l{color:var(--hot-dim)}

/* --------------------------------------------------------------------------
   28 — FICHE (`.pdp`) ET GALERIE
   Gabarit partagé par la fiche produit ET la fiche event : deux colonnes,
   visuel à gauche, information à droite. Ces styles vivaient dans shop.css,
   qui n'est chargé que sur la boutique — les fiches event héritaient donc
   d'une mise en page inexistante et le visuel s'échappait de son cadre.
   -------------------------------------------------------------------------- */
.pdp{
  display:grid;
  grid-template-columns:minmax(0,1.15fr) minmax(0,.85fr);
  gap:clamp(1.6rem,5vw,5rem);
  align-items:start;
}
@media (max-width:940px){ .pdp{grid-template-columns:1fr} }

.gal{position:sticky;top:6rem}
@media (max-width:940px){ .gal{position:static} }
.gal__main{
  --fb:4.5%;
  position:relative;aspect-ratio:4/5;overflow:hidden;background:var(--void);
  max-height:calc(100svh - 8rem);
  clip-path:polygon(0 var(--fb),100% 0,100% calc(100% - var(--fb)),0 100%);
}
/* `--ar` est posé en ligne depuis les dimensions réelles de l'affiche ;
   3/4 n'est que le repli quand aucune affiche n'existe (affiche générée). */
.gal__main--ev{aspect-ratio:var(--ar,3/4)}
.gal__main > img{
  width:100%;height:100%;object-fit:cover;
  filter:grayscale(1) contrast(1.22) brightness(1.05);
  transition:filter .5s var(--ease),transform .8s var(--ease);
}
/* La fiche event exclue : son visuel porte déjà la parallaxe (section 27),
   un second `transform` au survol l'écraserait. */
.gal__main:not(.gal__main--ev):hover > img{filter:grayscale(0) contrast(1.04);transform:scale(1.04)}
.gal__main--ev:hover > img{filter:grayscale(0) contrast(1.04)}
.gal__thumbs{display:flex;gap:.5rem;margin-top:.7rem;flex-wrap:wrap}
.gal__thumb{
  width:70px;aspect-ratio:4/5;overflow:hidden;flex:none;
  border:1px solid var(--edge);opacity:.5;
  transition:opacity .22s,border-color .22s;
}
.gal__thumb img{width:100%;height:100%;object-fit:cover;filter:grayscale(1) contrast(1.2)}
.gal__thumb:hover{opacity:.85}
.gal__thumb[aria-current='true']{opacity:1;border-color:var(--hot)}

.pdp__info{display:flex;flex-direction:column;min-width:0}
.pdp__kicker{margin-bottom:.9rem}
.pdp__title{
  font-family:var(--display);font-weight:900;letter-spacing:var(--track-giant);
  font-size:clamp(1.55rem,4.8vw,3.4rem);line-height:1;
  text-transform:uppercase;overflow-wrap:anywhere;
}
.pdp__desc{margin-top:1.5rem;padding-top:1.5rem;border-top:1px solid var(--edge)}
.pdp__actions{margin-top:1.9rem;display:flex;flex-direction:column;gap:.75rem}
.pdp__note{
  font-family:var(--mono);font-size:.7rem;letter-spacing:.14em;
  text-transform:uppercase;color:var(--ash);
  border-left:2px solid var(--hot);padding-left:.85rem;line-height:1.7;
}
.pdp__meta{
  margin-top:2rem;padding-top:1.4rem;border-top:1px solid var(--edge);
  display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,9rem),1fr));gap:1.1rem;
}
.pdp__meta dt{
  font-family:var(--mono);font-size:.7rem;letter-spacing:.16em;
  text-transform:uppercase;color:var(--hot);margin-bottom:.3rem;
}
/* Les valeurs sont de la MÉTA (lieu, horaires, organisateur, matière) : elles
   se composent en mono comme leurs étiquettes. Sans famille déclarée elles
   héritaient du Baskerville de labeur, et « PUTSCH COLLECTIVE » se retrouvait
   en capitales de texte courant à côté d'une étiquette monospacée. */
.pdp__meta dd{
  font-family:var(--mono);font-size:.78rem;line-height:1.5;
  letter-spacing:.04em;color:var(--bone);
}

/* accordéons (livraison, retours, safer space) */
.acc{border-top:1px solid var(--edge);margin-top:2rem}
.acc details{border-bottom:1px solid var(--edge)}
.acc summary{
  display:flex;justify-content:space-between;align-items:center;gap:1rem;
  padding:1.05rem 0;cursor:pointer;list-style:none;
  font-family:var(--mono);font-size:.72rem;letter-spacing:.16em;
  text-transform:uppercase;transition:color .2s;
}
.acc summary::-webkit-details-marker{display:none}
.acc summary:hover{color:var(--hot)}
.acc summary::after{content:'+';font-size:1.1rem;color:var(--hot);transition:transform .3s var(--ease)}
.acc details[open] summary::after{transform:rotate(45deg)}
.acc__body{padding-bottom:1.2rem;color:var(--ash);font-size:.9rem;line-height:1.62}

/* --------------------------------------------------------------------------
   29 — TIROIR PANIER ET TOAST
   Rendus par la coquille sur TOUTES les pages (le bouton Panier est dans la
   navigation) : leurs styles doivent donc être chargés partout, sans quoi le
   balisage du panier s'affiche en clair au bas de chaque page.
   -------------------------------------------------------------------------- */
.scrim{
  position:fixed;inset:0;z-index:var(--z-scrim);
  background:rgba(0,0,0,.72);
  backdrop-filter:blur(3px);-webkit-backdrop-filter:blur(3px);
  opacity:0;pointer-events:none;transition:opacity .35s var(--ease);
}
body[data-cart-open] .scrim{opacity:1;pointer-events:auto}

.cart{
  position:fixed;left:0;right:0;bottom:0;z-index:var(--z-drawer);
  background:var(--void);
  border-top:1px solid var(--hot);
  transform:translateY(101%);
  transition:transform .5s var(--ease);
  max-height:min(86svh,44rem);
  display:flex;flex-direction:column;
}
body[data-cart-open] .cart{transform:none}

/* Le tiroir barre l'écran d'un bord à l'autre — c'est voulu, c'est un bandeau.
   Son CONTENU, lui, ne doit pas s'étirer avec : sur 1440 px la ligne de
   commande écartait la vignette et le prix de 1 325 px, avec un trou au milieu,
   et le bouton de commande faisait toute la largeur de l'écran pour un libellé
   de 142 px. On borne donc le contenu à une largeur de lecture, centrée, en
   gardant les filets pleine largeur : le `max()` retombe seul sur la gouttière
   dès que l'écran est plus étroit que la borne. */
.cart{--cartw:64rem}
.cart__bar,
.cart__body,
.cart__foot{padding-inline:max(var(--gut),calc((100% - var(--cartw)) / 2))}

.cart__bar{
  display:flex;align-items:center;gap:1rem;
  padding-block:1rem;
  border-bottom:1px solid var(--edge);flex:none;
}
.cart__title{
  font-family:var(--cond);font-weight:900;font-stretch:85%;
  font-size:1.15rem;text-transform:uppercase;letter-spacing:.02em;
}
.cart__n{
  font-family:var(--mono);font-size:.7rem;letter-spacing:.14em;
  background:var(--hot);color:var(--on-hot);padding:.28em .55em;
}
.cart__close{
  margin-left:auto;font-family:var(--mono);font-size:.7rem;
  letter-spacing:.16em;text-transform:uppercase;color:var(--ash);
  transition:color .2s;
}
.cart__close:hover{color:var(--hot)}

.cart__body{overflow-y:auto;flex:1}
.cart__line{
  display:grid;grid-template-columns:72px minmax(0,1fr) auto;
  gap:1rem;align-items:center;
  padding-block:1.1rem;border-bottom:1px solid var(--edge);
}
.cart__thumb{width:72px;aspect-ratio:4/5;object-fit:cover;filter:grayscale(1) contrast(1.2)}
.cart__name{
  font-family:var(--cond);font-weight:800;font-stretch:82%;
  font-size:.98rem;text-transform:uppercase;line-height:1.14;
}
.cart__var{
  font-family:var(--mono);font-size:.7rem;letter-spacing:.14em;
  text-transform:uppercase;color:var(--ash);margin-top:.3rem;
}
.cart__right{display:flex;flex-direction:column;align-items:flex-end;gap:.55rem}
.cart__lineprice{font-family:var(--mono);font-size:.85rem;font-weight:700}
.qty{display:flex;align-items:center;border:1px solid var(--edge)}
.qty button{
  width:28px;height:28px;display:grid;place-items:center;
  font-family:var(--mono);font-size:.9rem;color:var(--ash);
  transition:color .2s,background .2s;
}
.qty button:hover{color:var(--void);background:var(--bone)}
.qty span{
  min-width:2rem;text-align:center;font-family:var(--mono);
  font-size:.75rem;font-weight:700;
}
.cart__rm{
  font-family:var(--mono);font-size:.7rem;letter-spacing:.14em;
  text-transform:uppercase;color:var(--ash);transition:color .2s;
}
.cart__rm:hover{color:var(--hot)}

/* Le pied s'organise seul : total et bouton côte à côte tant qu'il y a la
   place, empilés dès que l'un des deux ne tient plus. Le `flex-basis` fait le
   choix, pas une media query. La mention de livraison passe sur sa propre
   ligne (`order`), sous les deux. */
.cart__foot{
  flex:none;border-top:1px solid var(--edge);
  padding-block:1.2rem calc(1.2rem + env(safe-area-inset-bottom));
  display:flex;flex-wrap:wrap;align-items:center;
  gap:.55rem clamp(1rem,3vw,2.4rem);
}
.cart__total{
  flex:1 1 14rem;
  display:flex;justify-content:space-between;align-items:baseline;gap:1rem;
  font-family:var(--mono);font-size:.72rem;letter-spacing:.16em;
  text-transform:uppercase;
}
.cart__total b{font-size:1.25rem;color:var(--bone)}
.cart__ship{
  flex:1 1 100%;order:3;
  font-family:var(--mono);font-size:.7rem;letter-spacing:.13em;
  text-transform:uppercase;color:var(--ash);
}
/* Le bouton reprend sa taille propre dès qu'il a la place, et ne redevient
   pleine largeur que lorsqu'il passe seul sur sa ligne. */
.cart__foot .btn--block{width:auto;flex:0 1 auto;min-width:min(100%,17rem)}
.cart__empty{padding:3.4rem 0;text-align:center}
.cart__empty p{color:var(--ash);margin-bottom:1.4rem}

@media (max-width:560px){
  .cart__line{grid-template-columns:56px minmax(0,1fr)}
  .cart__thumb{width:56px}
  .cart__right{grid-column:1 / -1;flex-direction:row;justify-content:space-between;align-items:center}
  /* Au doigt, le bouton de commande passe seul sur sa ligne : il prend toute
     la largeur plutôt que de laisser un vide à sa droite. */
  .cart__foot .btn--block{flex:1 1 100%;min-width:0}
}

.toast{
  position:fixed;left:50%;bottom:2rem;z-index:calc(var(--z-drawer) + 1);
  transform:translate(-50%,140%);
  background:var(--hot);color:var(--on-hot);
  font-family:var(--mono);font-size:.7rem;font-weight:700;
  letter-spacing:.16em;text-transform:uppercase;
  padding:.95em 1.5em;
  transition:transform .45s var(--ease);
  display:flex;align-items:center;gap:.7rem;
  max-width:calc(100vw - 2rem);
}
.toast.is-up{transform:translate(-50%,0)}
.toast--err{background:var(--void);border:1px solid var(--hot);color:var(--hot)}
/* Tiroir ouvert, le toast se posait à 2 rem du bas — c'est à dire EN PLEIN sur
   le bouton « Passer commande », le seul qu'il fallait pouvoir atteindre. Il
   passe donc au-dessus du tiroir, dont la hauteur est mesurée à l'ouverture
   (`--carth`, posé par cart.js). Le repli à 0 px garde le comportement
   d'origine si la mesure manque. */
body[data-cart-open] .toast{bottom:calc(var(--carth,0px) + 1.2rem)}

/* --------------------------------------------------------------------------
   30 — MOUVEMENT RÉDUIT
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{
    animation-duration:.001ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.001ms !important;
    scroll-behavior:auto !important;
  }
  .js .rv{opacity:1 !important;transform:none !important}
  .grain,.scan{display:none}
  .cur{display:none}
  .tick__track{animation:none;transform:none}
  /* les effets pilotés par JS sont neutralisés côté script ; ici on annule
     les transformations résiduelles pour qu'aucun élément ne reste décalé */
  [data-magnet]{transform:none !important}
  .poster__title{transform:none !important}
  .progress{display:none}
}

/* --------------------------------------------------------------------------
   31 — BANDEAU DE LANGUE
   La suggestion de langue est un BANDEAU, jamais une redirection (voir
   shell.mjs : seule une préférence explicitement mémorisée redirige).
   Injecté par putsch.js, écrit dans la langue PROPOSÉE : c'est la seule que
   son destinataire lit à coup sûr. Aplat inversé — l'accent du site.
   -------------------------------------------------------------------------- */
.langbar{
  position:fixed;left:0;right:0;bottom:0;z-index:calc(var(--z-drawer) - 20);
  background:var(--hot);color:var(--on-hot);
  display:flex;align-items:center;justify-content:center;gap:1rem;flex-wrap:wrap;
  /* marge de la barre home iOS : même logique d'encoche que la nav */
  padding:.7rem var(--gut) calc(.7rem + env(safe-area-inset-bottom));
  font-family:var(--mono);font-size:.72rem;letter-spacing:.06em;
}
.langbar p{margin:0}
.langbar a{
  font-weight:700;text-transform:uppercase;letter-spacing:.12em;
  border:1px solid var(--on-hot);padding:.45em .85em;color:var(--on-hot);
  display:inline-flex;align-items:center;min-height:24px;
  transition:background .2s,color .2s;
}
.langbar a:hover{background:var(--void);color:var(--hot)}
.langbar button{
  font-family:var(--mono);font-size:.95rem;color:var(--on-hot);
  width:32px;height:32px;display:grid;place-items:center;flex:none;
}
@media (hover:none),(pointer:coarse){
  .langbar a{min-height:44px}
  .langbar button{width:44px;height:44px}
}

/* --------------------------------------------------------------------------
   31 bis — CONSENTEMENT (mesure d'audience)
   Même registre que le bandeau de langue, mais INVERSÉ par rapport à lui :
   fond noir, filet blanc. Les deux peuvent théoriquement coexister ; le
   consentement passe au-dessus (z + 1) parce qu'un choix légal prime sur
   une suggestion de confort. Les deux boutons ont le même poids visuel :
   refuser doit être aussi simple qu'accepter.
   -------------------------------------------------------------------------- */
.consent{
  position:fixed;left:0;right:0;bottom:0;z-index:calc(var(--z-drawer) - 19);
  background:var(--void);color:var(--bone);
  border-top:1px solid var(--hot);
  display:flex;align-items:center;justify-content:center;gap:.9rem 1.6rem;flex-wrap:wrap;
  padding:.85rem var(--gut) calc(.85rem + env(safe-area-inset-bottom));
}
.consent[hidden]{display:none}
.consent__p{
  margin:0;font-family:var(--mono);font-size:.72rem;letter-spacing:.06em;
  color:var(--bone);max-width:46rem;
}
.consent__p a{
  color:var(--ash);text-decoration:underline;text-underline-offset:.2em;
  margin-inline-start:.6em;transition:color .2s;
}
.consent__p a:hover{color:var(--hot)}
.consent__actions{display:flex;gap:.6rem;flex:none}
.consent .btn{padding:.7em 1.2em;font-size:.7rem}

/* Le bouton de révision, discret dans la barre du pied de page */
.footer__consent{
  font-family:var(--mono);font-size:inherit;letter-spacing:inherit;
  color:inherit;text-decoration:underline;text-underline-offset:.2em;
  display:inline-flex;align-items:center;min-height:24px;
  transition:color .2s;
}
.footer__consent:hover{color:var(--hot)}

/* --------------------------------------------------------------------------
   32 — DROITE À GAUCHE
   L'arabe et l'hébreu posent dir="rtl" sur <html> (via t.dir). Flex et grid
   suivent d'eux-mêmes le sens d'écriture ; on ne corrige que ce qui est
   écrit en PHYSIQUE — marges auto, alignements, panneau du sélecteur — et
   les chiffres, dates et noms latins se placent tout seuls par le bidi.
   -------------------------------------------------------------------------- */
[dir="rtl"] .nav__links{margin-left:0;margin-right:auto}
[dir="rtl"] .lang__menu{right:auto;left:0}
[dir="rtl"] .burger{margin-right:0;margin-left:-.5rem}
[dir="rtl"] .notice__foot span:last-child{text-align:left}
[dir="rtl"] .lineup__meta{text-align:left}
[dir="rtl"] .drawer__link:hover{padding-left:0;padding-right:.4rem}
@media (max-width:1160px){
  [dir="rtl"] .nav__right{margin-left:0;margin-right:auto}
}

/* --------------------------------------------------------------------------
   33 — MOTS LONGS DES AUTRES LANGUES
   « Datenschutzerklärung », « Yksityisyydensuoja » : les capitales géantes ne
   doivent pas faire déborder l'écran à 360 px. Césure quand la langue de la
   page en donne les règles, coupe franche en dernier recours — invisible sur
   les textes qui tiennent.
   -------------------------------------------------------------------------- */
.phead__t,.shead__title,.giant,.pdp__title,.notice__t,.mail-xl{
  overflow-wrap:break-word;hyphens:auto;
}
