/* ===== Réalisations — vitrine PLEIN ÉCRAN : liseré néon animé qui longe les bords, galerie qu'on swipe.
   PAS de texte par-dessus (demande David 14 juil.). Rideau courbe au reveal, points + flèches. ===== */

@property --ga{ syntax:'<angle>'; initial-value:0deg; inherits:false; }
@keyframes real-rotate{ to{ --ga:360deg; } }

#realisations{ position:relative; padding:clamp(8px,1.2vw,14px); background:transparent; overflow:hidden; }  /* transparent : plus de rectangle #0a0a0a qui tranche sur le body #000 */

/* Cadre néon = PLEIN ÉCRAN comme l'affichage d'avant : il remplit toute la section,
   le liseré longe les bords (mini respiration pour voir le glow, pas de marge noire). */
/* ⚠️ LE NÉON EST SUR UN CALQUE À PART, PAS SUR LE CADRE LUI-MÊME (bug Chrome).
   Avant, le `conic-gradient` animé était le `background` de .real-frame — or c'est
   l'élément qui DÉCOUPE l'iframe de la démo Fizz (overflow:hidden). Chrome devait donc
   repeindre tout le contenu du cadre, iframe comprise, à chaque image des 6 s de boucle.
   Résultat : les animations du site Fizz à l'intérieur (changement de parfum, lettres du
   bouton, fruits) étaient étranglées et restaient figées à mi-course. Safari composite
   l'iframe séparément, d'où « nickel sur Safari, cassé sur Chrome ».
   Le liseré vit maintenant dans un ::after superposé : l'animer ne repeint plus que lui. */
/* ⚠️ FORMAT LARGE 12/5 (≈ 21:9) — CHOIX DE DAVID, NE PAS REPASSER EN 16:9.
   Testé le 8 août puis ANNULÉ : le 16:9 permettait de voir la démo en entier, mais il change
   le format du cadre, et ce n'est pas le rendu voulu — le cadre FIZZ est volontairement plus
   cinéma que les deux autres (italio, 404). La démo est donc rognée en haut et en bas, c'est
   assumé. */
#realisations .real-frame{ position:relative; width:100%; aspect-ratio:12/5; isolation:isolate;
  border-radius:24px; overflow:hidden; background:#000;
  box-shadow:none;   /* pas de halo : sur fond noir ça faisait un "carré" gris flou autour */ }
/* ⚠️⚠️ NÉON DU CADRE FIZZ — ZÉRO REPEINT (refait le 8 août, après 2 correctifs insuffisants).
   HISTORIQUE, pour ne pas refaire les mêmes erreurs :
     1. dégradé animé en `background` de `.real-frame`  → repeignait l'iframe, démo figée
     2. déplacé sur un `::after`                        → mieux, mais pas suffisant
     3. + `will-change` sur ce `::after`                → toujours insuffisant (testé en ligne)
   LA CAUSE DE FOND : on animait `--ga`, l'ANGLE du dégradé. Faire varier un dégradé oblige
   Chrome à le RECALCULER et le REPEINDRE à chaque image — 60 fois par seconde, sur toute la
   surface du cadre, en résolution Retina. D'où le néon qui saccade, les taches floues DANS la
   démo, et même des défauts derrière le cadre.
   LA SOLUTION : le dégradé est peint UNE SEULE FOIS, puis on fait simplement TOURNER le
   calque (`transform:rotate`). Chrome ne repeint plus rien — il pivote une image déjà prête
   sur sa puce graphique. Même principe que le rideau de l'intro, corrigé le même jour.
   POURQUOI DEUX NIVEAUX : l'anneau (le masque qui ne garde que le liseré) doit rester FIXE,
   sinon il tournerait avec le dégradé. Il faut donc un conteneur masqué (`.real-neon`) + un
   enfant qui tourne (`.real-neon i`). Un pseudo-élément ne pouvant pas avoir d'enfant, le
   conteneur est un vrai élément dans index.html.
   ⚠️ NE PAS revenir à un dégradé animé (`from var(--ga)`) ici. */
#realisations .real-neon{
  position:absolute; inset:0; z-index:5; pointer-events:none;
  border:2px solid transparent; border-radius:24px;
  overflow:hidden;                    /* garde le dégradé tournant dans le cadre */
  /* on ne garde que l'anneau : le centre est masqué pour laisser voir l'iframe dessous */
  -webkit-mask: linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor;
          mask: linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0);
          mask-composite: exclude; }
#realisations .real-neon i{
  position:absolute; top:50%; left:50%;
  /* carré assez grand pour couvrir le cadre quel que soit l'angle (diagonale d'un 12:5 ≈ 1,09 × largeur) */
  width:118%; aspect-ratio:1;
  background:
    conic-gradient(from 0deg,
      rgba(255,255,255,.04) 0%, rgba(255,255,255,.6) 15%, #ffffff 24%, rgba(255,255,255,.6) 33%,
      rgba(255,255,255,.05) 46%, rgba(255,255,255,.04) 54%, rgba(255,255,255,.6) 69%, #ffffff 78%,
      rgba(255,255,255,.6) 87%, rgba(255,255,255,.05) 96%);
  will-change:transform;              /* calque à part : la rotation ne touche rien d'autre */
  animation:real-spin 6s linear infinite; }
@keyframes real-spin{
  from{ transform:translate(-50%,-50%) rotate(0deg); }
  to  { transform:translate(-50%,-50%) rotate(360deg); } }
@media (prefers-reduced-motion: reduce){
  #realisations .real-neon i{ animation:none; will-change:auto;
    transform:translate(-50%,-50%); } }


/* galerie DANS le cadre (swipe horizontal) */
#realisations .vit-gallery{ position:absolute; inset:0; z-index:0; border-radius:22px; display:flex;
  overflow-x:auto; overflow-y:hidden;
  scroll-snap-type:x mandatory; scroll-behavior:smooth; touch-action:pan-x;   /* override du pan-y global */
  -ms-overflow-style:none; scrollbar-width:none; }
#realisations .vit-gallery::-webkit-scrollbar{ display:none; }
#realisations .vit-slide{ flex:0 0 100%; width:100%; height:100%; scroll-snap-align:center;
  background-size:cover; background-position:center; background-repeat:no-repeat; }

/* slide VIVANTE (démo réelle en iframe dans le cadre) */
#realisations .vit-live{ position:relative; background:#000; }
#realisations .vit-live iframe{ width:100%; height:100%; border:0; display:block; }
#realisations .vit-open{ position:absolute; bottom:14px; right:14px; z-index:3; padding:9px 16px; border-radius:999px;
  background:rgba(10,10,12,.55); backdrop-filter:blur(8px); -webkit-backdrop-filter:blur(8px);
  border:1px solid rgba(255,255,255,.35); color:#fff; font-size:12px; letter-spacing:.08em; text-decoration:none;
  transition:background .25s ease; }
#realisations .vit-open:hover{ background:rgba(10,10,12,.85); }
/* iframe interactive partout : une seule vitrine, on manipule les canettes (la démo ne scrolle pas). */

/* flèches (PC) */
#realisations .vit-arrow{ position:absolute; top:50%; transform:translateY(-50%); z-index:4; width:46px; height:46px;
  border-radius:50%; border:1px solid rgba(255,255,255,.4); background:rgba(10,10,12,.45); color:#fff; font-size:26px; line-height:1;
  display:flex; align-items:center; justify-content:center; cursor:pointer;
  transition:background .25s ease, transform .2s ease; -webkit-tap-highlight-color:transparent; }
#realisations .vit-arrow:hover{ background:rgba(10,10,12,.82); }
#realisations .vit-arrow:active{ transform:translateY(-50%) scale(.9); }
#realisations .vit-prev{ left:14px; } #realisations .vit-next{ right:14px; }
@media (hover:none){ #realisations .vit-arrow{ display:none; } }   /* mobile = on swipe */

/* points */
#realisations .vit-dots{ position:absolute; left:0; right:0; bottom:16px; z-index:4; display:flex; gap:9px; justify-content:center; }
#realisations .vit-dot{ width:9px; height:9px; padding:0; border:none; border-radius:999px; cursor:pointer;
  background:rgba(255,255,255,.4); transition:background .3s ease, width .3s ease; -webkit-tap-highlight-color:transparent; }
#realisations .vit-dot:hover{ background:rgba(255,255,255,.7); }
#realisations .vit-dot.is-active{ background:#fff; width:24px; }

/* rideau courbe (reveal au scroll) — retiré par le JS une fois levé */
#realisations .vit-curtain{ position:absolute; inset:0; z-index:5; pointer-events:none; border-radius:22px; overflow:hidden; }
#realisations .vit-curtain svg{ width:100%; height:100%; display:block; }
#realisations .vit-curtain path{ fill:#000; }
@media (prefers-reduced-motion: reduce){ #realisations .vit-gallery{ scroll-behavior:auto; } }

/* ===== 2e RÉALISATION : italio (visuel FIXE, pas de démo vivante) — même cadre néon animé.
   ⚠️ Cadre en 16:9 (≠ FIZZ qui remplit 86vh) : l'image italio EST en 16:9, donc elle s'affiche
   ENTIÈRE (nav du haut + boutons du bas visibles), sans rognage ET sans bande noire. ===== */
#realisations-italio{ position:relative; padding:clamp(8px,1.2vw,14px); background:transparent; overflow:hidden; }
#realisations-italio .real-frame{ position:relative; width:100%;
  aspect-ratio:16/9;   /* remis en 16:9 (demande David 20 juil.) */
  isolation:isolate;
  border:2px solid transparent; border-radius:24px; overflow:hidden;
  background:
    linear-gradient(#000,#000) padding-box,
    conic-gradient(from var(--ga),
      rgba(255,255,255,.04) 0%, rgba(255,255,255,.6) 15%, #ffffff 24%, rgba(255,255,255,.6) 33%,
      rgba(255,255,255,.05) 46%, rgba(255,255,255,.04) 54%, rgba(255,255,255,.6) 69%, #ffffff 78%,
      rgba(255,255,255,.6) 87%, rgba(255,255,255,.05) 96%) border-box;
  box-shadow:none;
  animation:real-rotate 6s linear infinite; }
@media (prefers-reduced-motion: reduce){ #realisations-italio .real-frame{ animation:none; } }
#realisations-italio .vit-still{ position:absolute; inset:0; border-radius:22px;
  background:url('img/realisations-italio.webp?v=2') center/cover no-repeat; }
@media (max-width:767px){
  #realisations-italio{ padding:14px 10px; }
  #realisations-italio .real-frame{ aspect-ratio:16/9; border-radius:18px; }
  #realisations-italio .vit-still{ border-radius:16px; }
}

/* MOBILE = carte paysage 16:9 pleine largeur façon Tekiyo, coins arrondis.
   La démo vivante y est affichée en RENDU PC : l'iframe est rendue à 1200×675 (desktop)
   puis réduite en scale par le JS → on voit le site comme sur un écran d'ordi, vivant. */
@media (max-width:767px){
  #realisations{ min-height:0; padding:14px 10px; }
  #realisations .real-frame{ position:relative; inset:auto; width:100%; aspect-ratio:16/9; border-radius:18px; }
  #realisations .vit-gallery{ border-radius:16px; }
  #realisations .vit-live iframe{ transform-origin:0 0; }   /* scale posé par realisations.js */
}


/* ===== 3e RÉALISATION : page 404 (visuel fixe) — cadre au ratio EXACT du visuel (1494×1052) ===== */
#realisations-404{ position:relative; padding:clamp(8px,1.2vw,14px); background:transparent; overflow:hidden; }
#realisations-404 .real-frame{ position:relative; width:100%;
  aspect-ratio:16/9;   /* remis en 16:9 (demande David 20 juil.) */
  isolation:isolate;
  border:2px solid transparent; border-radius:24px; overflow:hidden;
  background:
    linear-gradient(#000,#000) padding-box,
    conic-gradient(from var(--ga),
      rgba(255,255,255,.04) 0%, rgba(255,255,255,.6) 15%, #ffffff 24%, rgba(255,255,255,.6) 33%,
      rgba(255,255,255,.05) 46%, rgba(255,255,255,.04) 54%, rgba(255,255,255,.6) 69%, #ffffff 78%,
      rgba(255,255,255,.6) 87%, rgba(255,255,255,.05) 96%) border-box;
  animation:real-rotate 6s linear infinite; }
@media (prefers-reduced-motion: reduce){ #realisations-404 .real-frame{ animation:none; } }
#realisations-404 .vit-still{ position:absolute; inset:0; border-radius:22px;
  background:url('img/realisations-404.webp?v=2') center/cover no-repeat; }
@media (max-width:767px){
  #realisations-404{ padding:14px 10px; }
  #realisations-404 .real-frame{ aspect-ratio:16/9; border-radius:18px; }
  #realisations-404 .vit-still{ border-radius:16px; }
}


/* ===== Condensé (demande David 19 juil.) : les 3 vitrines partagent une largeur max
   et un espacement régulier — au lieu de remplir toute la largeur/hauteur de l'écran. ===== */
#realisations, #realisations-italio, #realisations-404{
  padding-top:8px; padding-bottom:8px;   /* PLEINE LARGEUR (demande David), juste peu de hauteur */
}
@media (max-width:767px){
  #realisations, #realisations-italio, #realisations-404{ padding:8px 10px; }
}

/* ===== Carte COUVERTURE "Création digitale" + panneau plein écran (esprit Tekiyo, 20 juil.) ===== */
/* carte DÉTOURÉE (fond transparent + halo cuit dans l'image) → pas de border-radius/box-shadow rectangulaire,
   on utilise drop-shadow qui épouse la forme arrondie (sinon un carré réapparaît derrière la carte). */
/* carte = VISUEL seul (non cliquable) : plus de curseur/hover — c'est le bouton qui ouvre le panneau */
#creas-cover .creas-card{ display:block; width:100%; max-width:660px; margin:0 auto; padding:0; border:none; background:none;
  filter:drop-shadow(0 34px 70px rgba(84,64,168,.28)); }
#creas-cover .creas-card img{ width:100%; height:auto; display:block; }
/* ⚠️ règles partagées par les 2 sections (créations ET logos) → boutons STRICTEMENT identiques */
#creas-cover .creas-pill, #logos-cover .creas-pill{ display:inline-block; width:auto; align-self:center; white-space:nowrap;   /* 1 SEULE ligne : sinon le texte se casse et les 2 boutons n'ont pas la même hauteur */
  margin-top:26px; background:#000; color:#fff; border:1px solid rgba(255,255,255,.18);
  border-radius:999px; padding:11px 24px; font-size:14px; font-weight:600; }
/* la pastille est LE bouton (cliquable) → curseur + hover */
#creas-cover .creas-pill--btn, #logos-cover .creas-pill--btn{ cursor:pointer; transition:transform .2s ease, background-color .2s ease, border-color .2s ease; }
#creas-cover .creas-pill--btn:hover, #logos-cover .creas-pill--btn:hover{ transform:translateY(-2px); background:#141414; border-color:rgba(255,255,255,.4); }
#creas-cover .creas-pill--btn:active, #logos-cover .creas-pill--btn:active{ transform:translateY(0); }
#creas-cover .creas-start{ margin-top:16px; display:inline-flex; align-items:center; gap:10px; background:#fff; color:#000; border:none;
  border-radius:999px; padding:14px 28px; font-family:'JetBrains Mono',monospace; font-weight:700; font-size:12px; letter-spacing:.12em;
  text-transform:uppercase; cursor:pointer; transition:transform .2s ease; }
#creas-cover .creas-start:hover{ transform:translateY(-2px); }
#creas-cover .creas-start:active{ transform:translateY(1px); }

/* .creas-panel = FOND assombri plein écran (on voit le site derrière, en haut) ; la FEUILLE glisse dessus.
   ⚠️ on anime le FOND (background-color), PAS l'opacity du panneau — sinon la feuille se fond au lieu de glisser
   → fermeture « brute ». Ici la feuille reste opaque et glisse en entier, le fond se dé-assombrit en douceur. */
/* ⚠️ pas de `visibility` toggle (ça coupait l'anim de RETOUR) → `pointer-events` : la feuille reste
   toujours rendue (juste hors écran en bas quand fermé) donc le slide joue dans les DEUX sens. */
/* ⚠️ HORS RENDU AU REPOS. Avant : les DEUX panneaux (créations + logos) restaient des calques
   `position:fixed` PLEIN ÉCRAN présents en permanence dans le rendu, dès le chargement de la
   page — le JS ne posait `display:none` qu'APRÈS une première fermeture, donc tant qu'on ne
   les avait jamais ouverts ils étaient là, superposés à tout le site. C'est le profil exact du
   « carré noir » Safari iOS (déjà identifié ici pour .grain et #page-fade). Le JS remet
   `display:block` à l'ouverture, donc l'animation de glissement joue normalement. */
.creas-panel{ display:none; position:fixed; inset:0; z-index:9999; background:rgba(4,4,6,0);
  pointer-events:none; transition:background-color .45s ease; }
.creas-panel.open{ display:block; }
  /* la feuille est toujours rendue mais poussée hors écran (translateY(130%)) → l'anim de glissement
     joue TOUJOURS dans les deux sens (ouverture ET fermeture). */
.creas-panel.open{ background:rgba(0,0,0,.82); pointer-events:auto; }   /* voile bien noir */
/* ⚠️ FERMETURE façon Tekiyo = la feuille DÉZOOME (scale down + fondu) vers la carte, PAS un slide vers le bas.
   (vérifié image par image dans la vidéo de David : le panneau rétrécit et le fond réapparaît autour) */
.creas-sheet{ position:absolute; left:0; right:0; bottom:0; top:clamp(52px,8vh,84px);   /* BANDEAU du site en haut (visible + tapable pour fermer), comme Tekiyo */
  background:#000; border-radius:26px 26px 0 0; overflow:hidden;   /* #000 (pas #080809) : si ça dépasse un poil en bas sur iOS, c'est NOIR-SUR-NOIR = invisible (fini le « carré gris ») */
  display:flex; flex-direction:column;
  transform:translateY(130%); transition:transform .7s cubic-bezier(.4,0,.2,1); }   /* repos fermé : poussée TRÈS loin hors écran (130%) */
/* la bordure des coins arrondis + l'ombre SEULEMENT à l'ouverture (sinon un liseré/halo dépasse en bas quand c'est fermé) */
.creas-panel:not(.open) #realisations .vit-live iframe{ display:none; }   /* l'iframe FIZZ est colorée → on la cache tant que le panneau est fermé (iOS l'affiche même hors écran) */
/* PANNEAU FERMÉ : le panneau ENTIER passe en display:none (posé par le JS après l'anim de fermeture).
   On stoppe aussi les néons quand il n'est pas ouvert (rien qui tourne en tâche de fond). */
/* ⚠️ `.real-neon i` AJOUTÉ le 8 août : le néon du cadre FIZZ n'est plus animé sur `.real-frame`
   (dégradé animé → repeints) mais sur cet enfant qui tourne. Sans l'ajouter ici, il aurait
   continué à tourner panneau fermé, hors écran — exactement ce que cette règle existe pour
   empêcher (animations infinies en tâche de fond = « carré » fantôme sur iPhone). */
.creas-panel:not(.open) .real-frame,
.creas-panel:not(.open) #realisations .real-neon i{ animation:none !important; will-change:auto !important; }
/* ⚠️ MÊME CHOSE POUR LE CARROUSEL DE LOGOS — ça manquait, et c'est le plus lourd du lot :
   2 pistes × 24 images qui défilent EN CONTINU avec will-change:transform, panneau FERMÉ,
   depuis le chargement de la page. Un calque composité GPU permanent que rien ne consomme,
   qui rame et parasite les animations du reste de la page (y compris en remontant).
   Panneau fermé → animation coupée ET will-change relâché (sinon la couche reste allouée). */
/* le liseré néon des cadres logo tourne aussi en boucle : coupé tant que le panneau est fermé */
.creas-panel:not(.open) .logo-frame{ animation:none !important; }
/* box-shadow SEULEMENT quand ouvert : sinon la feuille (hors écran en bas) projette une ombre qui remonte
   = le « carré noir en bas » sur mobile. */
.creas-panel.open .creas-sheet{ transform:translateY(0); box-shadow:0 -18px 60px -22px rgba(0,0,0,.55);
  border:none; }   /* PAS de liseré clair en haut (il était lu comme un « côté gris ») */
.creas-bar{ flex:0 0 auto; position:relative; display:flex; align-items:center; justify-content:center; padding:16px 20px 14px;
  cursor:grab; touch-action:none; background:#000; }   /* NOIR (pas #0b0b0d) : sinon bande grise en haut du panneau + dépasse en bas. Le grip suffit à la repérer. */
.creas-bar:active{ cursor:grabbing; }   /* la barre entière = zone « fermer » (grip) */
.creas-bar:hover .creas-grip{ background:rgba(255,255,255,.55); }
.creas-grip{ width:46px; height:5px; border-radius:999px; background:rgba(255,255,255,.3); }
.creas-close{ position:absolute; right:18px; top:50%; transform:translateY(-50%); background:rgba(255,255,255,.08);
  border:1px solid rgba(255,255,255,.18); color:#fff; border-radius:999px; padding:9px 18px; cursor:pointer;
  font-family:'JetBrains Mono',monospace; font-size:11px; letter-spacing:.1em; text-transform:uppercase; transition:background .2s ease; }
.creas-close:hover{ background:rgba(255,255,255,.18); }
/* ⚠️ PAS de `-webkit-overflow-scrolling:touch` : propriété WebKit-only (ignorée par Chromium, d'où le bug
   invisible en test desktop) qui, sur Safari iOS, crée un calque de scroll inertiel séparé. Combiné à la
   feuille .creas-sheet (transform + overflow:hidden + border-radius), ce calque décalait le contenu vers le
   bas = GRAND VIDE NOIR au-dessus du 1er titre à l'ouverture. iOS 13+ a le momentum natif → aucune perte.
   `min-height:0` = fix standard du flex-item scrollable (sinon min-size auto empêche le bon calcul). */
.creas-scroll{ flex:1 1 auto; min-height:0; overflow-y:auto; overflow-x:clip; overscroll-behavior:contain;
  overscroll-behavior-x:none; touch-action:pan-y; }
/* ⚠️ overflow-x:hidden OBLIGATOIRE : les bandes de logos débordent volontairement (132vw/150vw) pour
   que leurs extrémités sortent du champ — sans ça le panneau se swipe horizontalement sur mobile. */
.creas-scroll > section:first-child{ padding-top:clamp(40px,6vw,72px) !important; }
/* verrou iOS : overflow:hidden ne suffit PAS sur Safari mobile → body en position:fixed (le JS pose le top:-scrollY).
   Sinon le sweep scrolle la page DERRIÈRE le panneau au lieu du contenu du panneau. */
body.creas-locked{ position:fixed; left:0; right:0; width:100%; overflow:hidden; }
@media (prefers-reduced-motion: reduce){ .creas-panel{ transition:none } #creas-cover .creas-card{ transition:none } }

/* ===== Panneau façon Tekiyo — version SOMBRE (choix David 20 juil.) : colonne centrée,
   court récit entre chaque projet + cadres ÉPURÉS (plus de néon animé), tout contenu. ===== */
.creas-wrap{ max-width:920px; margin:0 auto; padding:0 clamp(20px,5vw,30px); }
.creas-beat{ max-width:700px; margin:clamp(60px,9vw,112px) 0 clamp(28px,3.5vw,44px); }
.creas-wrap > .creas-beat:first-child{ margin-top:clamp(40px,6vw,72px); }   /* respire sous la barre du haut */
.creas-beat h2{ margin-bottom:16px; }
.creas-beat p{ margin:0; }

/* les 3 réalisations vivent dans .creas-wrap → largeur pleine de la colonne, pas de marge propre */
.creas-scroll #realisations,
.creas-scroll #realisations-italio,
.creas-scroll #realisations-404{ padding:0; margin:0; max-width:none; }
.creas-scroll #realisations-404{ margin-bottom:clamp(64px,10vw,128px); }
/* NÉON RESTAURÉ (demande David) : on laisse les règles de base `.real-frame` (liseré conique animé
   `real-rotate 6s` + border 2px transparent) s'appliquer → pas d'override qui l'aplatit ici.
   (box-shadow reste `none` côté base : le halo faisait un « carré » gris sur le fond noir.) */
/* FIZZ reste INTERACTIF (on clique les canettes) ; c'est l'embed FIZZ qui renvoie la molette au #creasScroll
   pour que le scroll marche même par-dessus la démo. */
.creas-scroll #realisations .vit-gallery{ overflow:hidden; }

/* ===== MOBILE : anti « carré » iOS quand le panneau est OUVERT =====
   la box-shadow SUR la feuille transformée (transform = calque GPU) laisse une traînée/rectangle
   noir sur iOS Safari. Sur mobile on la supprime (le voile noir suffit à détacher la feuille). */
@media (max-width: 760px) {
  .creas-panel.open .creas-sheet { box-shadow: none !important; }

  /* 🟥 LE CARRÉ DU PORTFOLIO : la démo FIZZ est un IFRAME (calque à part). Sur Safari iOS, un iframe
     posé sur son propre calque N'EST PAS découpé par le border-radius+overflow:hidden du cadre → ses
     COINS CARRÉS dépassent = le « carré ». FIX iOS connu : appliquer un `mask` (même plein, invisible)
     sur le conteneur arrondi → force iOS à rendre dans un buffer où le border-radius EST appliqué,
     donc les coins de l'iframe sont enfin coupés. */
  .creas-scroll #realisations .real-frame,
  .creas-scroll #realisations .vit-gallery {
    -webkit-mask-image: -webkit-radial-gradient(#fff, #fff);
            mask-image: radial-gradient(#fff, #fff);
  }
}

/* ===== MOBILE : cause SYSTÉMIQUE du « carré » à l'ouverture du panneau =====
   Le contenu du panneau contient des DIZAINES d'éléments en will-change:opacity,transform (reveals),
   soit autant de calques GPU empilés dans un conteneur scrollable. Safire iOS sature et repeint des
   rectangles noirs. Le reveal est instantané ici (pas d'anim de scroll dans le panneau) → on retire
   TOUS ces calques. Invisible à l'œil, décisif pour le compositing. */
@media (max-width: 760px) {
  .creas-panel, .creas-panel * { will-change: auto !important; }
}

/* ===== Section LOGOS & IDENTITÉ (carte = l'ORBE) — même mécanique que le portfolio ===== */
/* orbe = VISUEL seul (non cliquable) : elle flotte, mais c'est le bouton qui ouvre le panneau */
/* ⚠️ ORBE = VISUEL SIMPLE, calqué sur la carte « Création digitale » (#creas-cover .creas-card),
   qui elle n'a jamais posé de problème d'affichage. Ont été retirés, dans l'ordre :
     — l'animation de flottement (boucle infinie = calque composité permanent) ;
     — la 2e ombre portée (drop-shadow empilé) ;
     — le halo ::before en filter:blur(40px) — un flou de 40px sur un cercle de ~440px,
       recalculé à chaque repaint : très coûteux sur mobile et connu pour faire apparaître
       des rectangles noirs sur Safari iOS.
   Il ne reste qu'UNE ombre douce, exactement comme la carte de référence. */
#logos-cover .logos-orb{ position:relative; display:block; width:clamp(240px,52vw,440px); aspect-ratio:1; margin:0 auto; padding:0;
  border:none; background:none; border-radius:50%;
  filter:drop-shadow(0 34px 70px rgba(84,64,168,.28)); }
#logos-cover .logos-orb img{ width:100%; height:100%; object-fit:contain; display:block; border-radius:50%; }

/* un logo montré dans le panneau : cadre arrondi sobre + légende */
.logos-item{ margin:clamp(28px,4vw,44px) 0 0; border-radius:20px; overflow:hidden; border:1px solid rgba(255,255,255,.10);
  background:#000; }
.logos-item img{ width:100%; height:auto; display:block; }
.logos-cap{ display:flex; align-items:baseline; justify-content:space-between; gap:16px; padding:16px 20px; }
.logos-name{ font-family:'Playfair Display',serif; font-size:22px; color:#fff; }
.logos-tag{ font-family:'JetBrains Mono',monospace; font-size:11px; letter-spacing:.1em; text-transform:uppercase; color:rgba(255,255,255,.45); }

/* ===== Cadre NÉON pour un logo (panneau Identité) — même liseré conique animé que le portfolio ===== */
#logosPanel .logo-frame-wrap{ position:relative; padding:clamp(8px,1.2vw,14px); background:transparent; overflow:hidden;
  margin:clamp(28px,4vw,44px) 0 clamp(48px,8vw,96px); }
#logosPanel .logo-frame{ position:relative; width:100%; aspect-ratio:16/9; isolation:isolate;
  border:2px solid transparent; border-radius:24px; overflow:hidden;
  background:
    linear-gradient(#000,#000) padding-box,
    conic-gradient(from var(--ga),
      rgba(255,255,255,.04) 0%, rgba(255,255,255,.6) 15%, #ffffff 24%, rgba(255,255,255,.6) 33%,
      rgba(255,255,255,.05) 46%, rgba(255,255,255,.04) 54%, rgba(255,255,255,.6) 69%, #ffffff 78%,
      rgba(255,255,255,.6) 87%, rgba(255,255,255,.05) 96%) border-box;
  animation:real-rotate 6s linear infinite; }
#logosPanel .logo-frame img{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover; display:block; border-radius:22px; }
@media (prefers-reduced-motion: reduce){ #logosPanel .logo-frame{ animation:none; } }
@media (max-width:767px){ #logosPanel .logo-frame{ border-radius:18px; } #logosPanel .logo-frame img{ border-radius:16px; } }

/* variante ratio ~4:3 pour la plaque chrome vectorielle (Grizzly SVG, 2047x1535 = ratio EXACT du SVG)
   → cover + zéro padding : la plaque touche directement le liseré néon. Le SVG reste NET quelle que soit la taille. */
/* plaque chrome Grizzly (webp détouré 1600x676) : ratio EXACT de l'image → cover + zéro padding,
   la plaque touche directement le liseré néon (pas de bordure noire entre les deux). */
#logosPanel .logo-frame--21x9{ aspect-ratio:1600/676; }
#logosPanel .logo-frame--21x9 img{ object-fit:cover; padding:0; background:transparent; }

/* ===== DÉCLINAISONS (panneau logos) — cases prêtes à illustrer =====
   Pour remplir une case : remplacer <div class="decl-ph" data-slot="..."></div>
   par <img src="img/mon-visuel.webp" alt=""/> (le style s'applique tout seul). */
#logosPanel .decl-grid{ display:grid; grid-template-columns:repeat(2,1fr); gap:14px;
  margin:clamp(24px,3.5vw,36px) 0 clamp(48px,8vw,96px); }
@media (min-width:760px){ #logosPanel .decl-grid{ grid-template-columns:repeat(4,1fr); gap:18px; } }
#logosPanel .decl-item{ margin:0; }
#logosPanel .decl-ph,
#logosPanel .decl-item img{ display:block; width:100%; aspect-ratio:1; border-radius:16px; object-fit:cover; }
/* case VIDE : liseré pointillé discret + damier léger (on voit que c'est un emplacement) */
#logosPanel .decl-ph{ border:1px dashed rgba(255,255,255,.16); background:
  linear-gradient(135deg, rgba(255,255,255,.03) 25%, transparent 25%, transparent 50%, rgba(255,255,255,.03) 50%, rgba(255,255,255,.03) 75%, transparent 75%) 0 0/18px 18px,
  rgba(255,255,255,.012); }
#logosPanel .decl-item img{ border:1px solid rgba(255,255,255,.10); }
#logosPanel .decl-cap{ display:flex; flex-direction:column; gap:2px; padding:10px 2px 0; }
#logosPanel .decl-name{ font-size:14px; color:#fff; font-weight:600; }
#logosPanel .decl-sub{ font-family:'JetBrains Mono',monospace; font-size:10px; letter-spacing:.06em;
  text-transform:uppercase; color:rgba(255,255,255,.38); }

/* pastilles de déclinaisons dans les cartes d'offre logos */
#logos-offres .decl-chip{ display:inline-block; font-family:'JetBrains Mono',monospace; font-size:9.5px;
  letter-spacing:.06em; text-transform:uppercase; padding:5px 10px; border-radius:999px;
  border:1px solid rgba(255,255,255,.14); background:rgba(255,255,255,.03); color:rgba(255,255,255,.62); }
#logos-offres .decl-chip--on{ border-color:rgba(255,255,255,.5); background:rgba(255,255,255,.10); color:#fff; font-weight:600; }

/* ===== Petite créature VEO (blob galaxie) — vanilla, pas de React =====
   Forme SVG + texture galaxie du logo qui dérive dedans + yeux qui suivent la souris et clignent. */
.veo-blob{ width:clamp(110px,16vw,168px); margin:34px auto 0; line-height:0;
  filter:drop-shadow(0 14px 30px rgba(0,0,0,.55));   /* PAS de halo coloré (demande David) : simple ombre noire */
  animation:veo-blob-float 3.4s ease-in-out infinite; transform-origin:top center; }
.veo-blob svg{ width:100%; height:auto; display:block; overflow:visible; }
@keyframes veo-blob-float{ 0%,100%{ transform:translateY(0) scaleY(1); } 50%{ transform:translateY(-7px) scaleY(1.05); } }

/* le logo VEO reste NET et centré (pas de dérive) — c'est le blob qui flotte */
.veo-blob-tex{ transform-box:fill-box; transform-origin:center; }

/* yeux : le GROUPE suit la souris (translate), les ellipses clignent (scaleY) — 2 niveaux, pas de conflit */
.veo-blob-eyes{ transform:translate(var(--ex,0px), var(--ey,0px));
  transition:transform .38s cubic-bezier(.2,.8,.2,1); }
.veo-blob-eye{ fill:#fff; transform-box:fill-box; transform-origin:center;
  animation:veo-blob-blink 4.6s infinite ease-in-out; }
.veo-blob-eye:nth-child(2){ animation-delay:.06s; }
@keyframes veo-blob-blink{ 0%,92%,100%{ transform:scaleY(1); } 95.5%{ transform:scaleY(.08); } }

@media (prefers-reduced-motion: reduce){
  .veo-blob, .veo-blob-tex, .veo-blob-eye{ animation:none; }
}

/* plaques Bunny / Gourmy (webp détourés 1600x686) : ratio exact → cover, zéro fond entre plaque et néon */
#logosPanel .logo-frame--plaque{ aspect-ratio:1600/686; }
#logosPanel .logo-frame--plaque img{ object-fit:cover; padding:0; background:transparent; }

/* ===== VEO qui s'écrit au trait (fin du panneau logos) ===== */
#logosPanel .veo-draw{ width:min(300px,62%); margin:clamp(30px,5vw,54px) auto clamp(20px,4vw,40px); line-height:0; }
#logosPanel .veo-draw svg{ width:100%; height:auto; display:block; overflow:visible; }
#logosPanel .vd-l{ fill:none; stroke:#fff; stroke-width:7; stroke-linecap:round; stroke-linejoin:round;
  stroke-dasharray:var(--len,400); stroke-dashoffset:var(--len,400);
  filter:drop-shadow(0 0 10px rgba(255,255,255,.35)); }
/* BOUCLE + REVERSE (alternate) : s'écrit, puis se dés-écrit à l'envers, sans jamais s'arrêter */
#logosPanel .vd-l{ animation:veo-draw-loop 2.8s cubic-bezier(.6,0,.25,1) infinite alternate; }
#logosPanel .vd-l:nth-child(2){ animation-delay:.18s; }
#logosPanel .vd-l:nth-child(3){ animation-delay:.36s; }
@keyframes veo-draw-loop{
  from { stroke-dashoffset:var(--len,400); }   /* invisible */
  to   { stroke-dashoffset:0; }                /* entièrement tracé */
}
@media (prefers-reduced-motion: reduce){
  #logosPanel .vd-l{ stroke-dashoffset:0; animation:none !important; }
}

/* ===== BANDE DE LOGOS INCLINÉS (panneau logos) : 1 bande = 1 logo =====
   ⚠️ On n'incline PAS la bande (ça laissait des coins vides = les "carrés" bizarres).
   On incline CHAQUE PLAQUE : la bande reste droite et pleine, seule la limite gauche/droite existe. */
/* la BANDE ENTIÈRE est inclinée (plus large que l'écran → ses extrémités sortent du champ,
   donc AUCUN coin vide) ; la marge verticale absorbe le débordement de la rotation. */
#logosPanel .diag-wall{ position:relative; overflow:visible;
  width:132vw; margin-left:-16vw; margin-right:-16vw;
  transform:rotate(-7deg);
  padding:clamp(10px,1.6vw,22px) 0;
  margin-top:clamp(34px,5vw,74px); margin-bottom:clamp(34px,5vw,74px); }
#logosPanel .diag-stage{ position:static; transform:none; width:auto; display:block; }
#logosPanel .diag-row{ display:flex; width:100%; overflow:hidden; }
#logosPanel .diag-track{ display:flex; width:max-content; will-change:transform; align-items:center; }
#logosPanel .diag-track[data-dir="left"] { animation:diag-left  var(--speed,50s) linear infinite; }
#logosPanel .diag-track[data-dir="right"]{ animation:diag-right var(--speed,50s) linear infinite; }
@keyframes diag-left { 0%{ transform:translate3d(0,0,0); }    100%{ transform:translate3d(-50%,0,0); } }
@keyframes diag-right{ 0%{ transform:translate3d(-50%,0,0); } 100%{ transform:translate3d(0,0,0); } }
/* chaque plaque penchée — c'est ELLE qui porte la diagonale */
/* ~3 plaques visibles à l'écran → chacune fait environ 1/3 de la largeur. Coins arrondis. */
/* ⚠️ width:auto seul veut dire que la largeur reste INCONNUE tant que l'image n'est pas chargée
   (surtout depuis qu'elles arrivent étalées dans le temps, pas d'un coup) : la piste change
   de largeur À CHAQUE arrivée d'image, donc rejoue son calcul de vitesse et redécale tout —
   plus visible en remontant sur du contenu pas encore fini de charger. aspect-ratio réserve
   la bonne largeur DÈS LE DÉPART (les 6 visuels du carrousel font tous ~2.33:1), donc plus
   aucun redécalage, peu importe l'ordre ou la vitesse de chargement. */
#logosPanel .diag-track img{ flex:0 0 auto; height:clamp(96px,13vw,172px); width:auto; aspect-ratio:2.33/1; display:block;
  margin-right:clamp(16px,2vw,32px); border-radius:18px; }
@media (prefers-reduced-motion: reduce){ #logosPanel .diag-track{ animation:none !important; } }

/* contour blanc du fantôme (rappel du liseré du logo VEO) */
.veo-blob-ring{ fill:none; stroke:#fff; stroke-width:3.5; vector-effect:non-scaling-stroke;
  opacity:.92; }


/* ===== MOBILE : le panneau logos était BEAUCOUP trop long → on compacte ===== */
@media (max-width:767px){
  /* ⚠️ la bande fait 150vw dans un cadre de 100vw → elle doit déborder de 25vw DE CHAQUE CÔTÉ
     (et surtout pas -75vw : ça la poussait entièrement hors du cadre = carrousel invisible). */
  #logosPanel .diag-wall{ padding:8px 0; margin-top:26px; margin-bottom:26px;
    width:150vw; margin-left:-25vw; margin-right:-25vw; }
  #logosPanel .diag-track img{ height:clamp(74px,22vw,108px); aspect-ratio:2.33/1; margin-right:12px; border-radius:12px; }
  #logosPanel .creas-beat{ margin:clamp(26px,6vw,40px) 0 clamp(16px,3vw,22px); }
  #logosPanel .decl-grid{ gap:10px; margin:clamp(16px,3vw,24px) 0 clamp(26px,5vw,40px); }
  #logosPanel .veo-blob{ width:clamp(96px,26vw,130px); margin-top:22px; }
  #logosPanel .veo-draw{ margin:clamp(22px,4vw,32px) auto clamp(14px,3vw,22px); }
  #logosPanel .logo-frame-wrap{ margin:clamp(18px,3vw,26px) 0; }
}
/* cadre qui coupe les bandes débordantes (créé par le JS) : le document ne déborde plus */
#logosPanel .diag-clip{ position:relative;
  overflow-x:clip; overflow-y:visible;   /* ⚠️ PAS overflow:hidden : la bande penchée dépasse de ~35px
                                            en haut/bas de sa boîte → hidden la coupait net = "la barrière" */
  width:100vw; left:50%; margin-left:-50vw; margin-right:-50vw; }
