/* ==========================================================================
   V&P Philadelphia — socle partage par toutes les pages
   Jetons, typographie, navigation, couche d'environnement, entrees, mouvement reduit.
   Une page interne qui invente sa propre couleur ou sa propre courbe casse l'unite.
   ========================================================================== */

:root{
  /* --- surfaces --- */
  --canvas:#08080B;
  --panel:#121218;
  --panel-raised:#1A1A22;
  --line:#26262F;
  --line-soft:#1B1B22;

  /* --- accent de marque V&P --- */
  --accent:#A855F7;
  --accent-hover:#C084FC;
  --accent-deep:#7E22CE;
  --accent-muted:rgba(168,85,247,.14);

  /* --- la ville (dose rare, jamais sur un bouton) --- */
  --ember:#F5A524;
  --ember-muted:rgba(245,165,36,.10);

  /* --- statut (fonctionnel, jamais decoratif) --- */
  --live:#34D399;
  --live-off:#71717A;

  /* --- texte --- */
  --text-primary:#F5F5F7;
  --text-secondary:#A1A1AA;
  --text-faint:#6E6E78;

  /* --- typographie --- */
  --font-display:'Sora',system-ui,sans-serif;
  --font-body:'Instrument Sans',system-ui,sans-serif;
  --font-mono:'JetBrains Mono',ui-monospace,monospace;

  /* --- les deux seules courbes du site --- */
  --ease:cubic-bezier(.22,.61,.36,1);
  --ease-slow:cubic-bezier(.16,.84,.44,1);
  --dur:.5s;
  --dur-slow:.9s;

  /* --- mesures --- */
  --nav-h:clamp(76px,7.5vw,100px);
  --gutter:clamp(20px,5vw,64px);
  --maxw:1240px;

  /* --- ombre de texte sur video (les 3 couches) --- */
  --tshadow:0 1px 2px rgba(5,5,10,.95),0 3px 12px rgba(5,5,10,.78),0 10px 44px rgba(5,5,10,.8);
  /* Halo de qualite sous-titre, pour du petit texte pose sur de la video sans
     aucun fond. Mesure sur le film : 179 images sur 424 ont un pixel au-dessus
     de Y=200 derriere les liens, une simple ombre portee ne tenait pas.
     Quatre couches serrees et multi-directionnelles qui detourent la lettre,
     au lieu d une diffusion large qui ne fait que salir. */
  --tshadow-sm:
    0 0 1px rgba(3,3,8,.98),
    0 1px 2px rgba(3,3,8,.95),
    0 0 5px rgba(3,3,8,.92),
    0 0 12px rgba(3,3,8,.75);
}

/* Le fond est declare sur html : sans ca, une navigation interne flashe en blanc. */
html{background:var(--canvas);color-scheme:dark;scroll-snap-type:y proximity}
html,body{overflow-x:hidden;overflow-x:clip}

*,*::before,*::after{box-sizing:border-box}

body{
  margin:0;
  background:var(--canvas);
  color:var(--text-primary);
  font-family:var(--font-body);
  font-size:16px;
  line-height:1.6;
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
}

/* Transitions de vue natives : la navigation entre deux pages devient un fondu.
   Aucune bibliotheque, et les navigateurs qui ne gerent pas naviguent normalement. */
@view-transition{navigation:auto}

img{max-width:100%;display:block}
a{color:inherit;text-decoration:none}

h1,h2,h3{font-family:var(--font-display);font-weight:700;line-height:1.05;letter-spacing:-.02em;margin:0}
h1{font-size:clamp(2.6rem,7vw,5.2rem)}
h2{font-size:clamp(2rem,4.4vw,3.4rem)}
h3{font-size:clamp(1.15rem,1.8vw,1.5rem);font-weight:600;letter-spacing:-.01em}
p{margin:0 0 1em}

.lede{font-size:clamp(1.05rem,1.5vw,1.25rem);color:var(--text-secondary);max-width:62ch}

/* Surtitre monospace : l'etiquette de section, partout la meme. */
.kicker{
  font-family:var(--font-mono);
  font-size:.72rem;
  font-weight:500;
  letter-spacing:.18em;
  text-transform:uppercase;
  color:var(--accent);
  display:block;
  margin-bottom:1.1rem;
}

.wrap{max-width:var(--maxw);margin-inline:auto;padding-inline:var(--gutter)}

/* Le lien d'evitement, visible seulement au clavier. */
.skip{position:absolute;left:-9999px;top:0;z-index:200;background:var(--accent);color:#0A0A0A;padding:.7rem 1.1rem;border-radius:0 0 8px 0;font-weight:600}
.skip:focus{left:0}

/* ==========================================================================
   Navigation
   ========================================================================== */

.nav{
  position:fixed;inset:0 0 auto;z-index:100;height:var(--nav-h);
  display:flex;align-items:center;justify-content:space-between;
  padding-inline:var(--gutter);
  background:transparent;
}
/* Le fond de la nav reste transparent en toutes circonstances, scroll compris.
   La lisibilite ne repose donc plus sur un bandeau mais sur l ombre portee,
   seule couche qui protege le texte sans assombrir la page derriere.
   L ombre est invisible sur les sections du bas, dont le fond est deja sombre,
   et fait tout le travail sur les zones claires de la video. */
.nav{text-shadow:var(--tshadow-sm)}
.nav .btn{text-shadow:none}   /* une ombre sur un bouton se lit comme de la crasse */
.page-interne main{padding-top:var(--nav-h)}

/* Au-dessus d'une section claire, la nav s'adapte. La transparence reste
   entiere : c'est la couleur du texte qui change, pas le fond. Sans ca, du
   blanc sur creme est illisible.

   Sur grand ecran la section claire n'occupe que la MOITIE DROITE, et le
   menu centre (des 1200px) chevauche pile la frontiere : une partie de ses
   liens tombe sur la carte sombre, l'autre sur le panneau clair, selon la
   largeur de fenetre. Une seule couleur ne peut pas convenir aux deux a la
   fois (bug reel signale par capture : encre sombre sur carte sombre,
   illisible). .nav__menu-dark est posee lien par lien en JS (chacun sait de
   quel cote de la fenetre il tombe, la frontiere etant exactement au
   milieu) : seuls ceux qui tombent reellement sur le panneau clair passent
   en encre sombre, les autres gardent le blanc par defaut. Le logo, lui,
   reste toujours sur la carte sombre a gauche et garde son blanc fixe. Le
   bouton Order, toujours a droite, reste sur le panneau clair et passe en
   encre sombre classique. */
@media (min-width:901px){
  body.nav-light .nav__menu a.nav__menu-dark{color:#111116;text-shadow:0 1px 2px rgba(255,255,255,.5)}
}
body.nav-light .nav .btn--primary{
  color:#111116;
  border-color:rgba(126,34,206,.5);
  background:rgba(168,85,247,.16);
  text-shadow:none;
}
/* Le panier est colle au bouton Order, donc toujours du cote clair lui aussi,
   a toutes les largeurs ou la section est scindee. */
body.nav-light .nav__cart{
  color:#111116;
  border-color:rgba(17,17,22,.2);
  background:rgba(255,255,255,.32);
  text-shadow:none;
}

/* Sous 900px la section claire n'est plus scindee : elle passe pleine largeur
   derriere la nav, donc tout doit basculer, logo et bouton du menu compris. */
@media (max-width:900px){
  body.nav-light .nav{color:#111116;text-shadow:0 1px 2px rgba(255,255,255,.5)}
  body.nav-light .nav__mark svg path[fill="currentColor"]{fill:#111116}
  body.nav-light .burger span{background:#111116}
}

/* nav-ink : une surface claire PLEINE LARGEUR passe derriere la nav, cas des
   cartes claires du processus. Rien de commun avec nav-light, qui traite une
   section scindee en deux moities et ne bascule donc que les liens tombant du
   cote clair. Ici il n'y a pas de moitie sombre : TOUT doit basculer, a toutes
   les largeurs.

   .nav__links et .nav__menu a sont nommes explicitement, et c'est le coeur du
   correctif. Poser la couleur sur .nav seul ne suffit pas : .nav__links
   declare la sienne (var(--text-primary), blanc), et une declaration propre
   bat toujours l'heritage. Les liens restaient donc blancs sur creme.
   Bug reel mesure : sur une carte claire, les deux premiers liens du menu
   ressortaient en rgb(245,245,247) sur le creme, invisibles, tandis que les
   deux derniers passaient bien en encre sombre. L'asymetrie venait de
   nav__menu-dark, pose une fois pour toutes sur les liens de la moitie droite
   pour le compte de la section "qui on est". */
body.nav-ink .nav,
body.nav-ink .nav__links,
body.nav-ink .nav__menu a{color:#111116;text-shadow:0 1px 2px rgba(255,255,255,.5)}
body.nav-ink .nav__mark svg path[fill="currentColor"]{fill:#111116}
body.nav-ink .burger span{background:#111116}
body.nav-ink .nav .btn--primary{
  color:#111116;
  border-color:rgba(126,34,206,.5);
  background:rgba(168,85,247,.16);
  text-shadow:none;
}
body.nav-ink .nav__cart{
  color:#111116;
  border-color:rgba(17,17,22,.2);
  background:rgba(255,255,255,.32);
  text-shadow:none;
}

.nav__links,.nav .btn--primary{transition:color var(--dur) var(--ease),background var(--dur) var(--ease),border-color var(--dur) var(--ease)}

.nav__mark{display:flex;align-items:center;gap:.7rem;font-family:var(--font-display);font-weight:800;letter-spacing:-.02em;font-size:clamp(1.2rem,1.6vw,1.5rem)}
.nav__mark svg{width:clamp(30px,3vw,40px);height:auto}

.nav__links{display:flex;align-items:center;gap:clamp(1.1rem,2.4vw,2.1rem);font-size:clamp(1rem,1.05vw,1.1rem);color:var(--text-primary)}
/* .nav__menu ne fait rien sous 1200px : il herite simplement de l'ecart de
   .nav__links, donc la nav reste exactement ce qu'elle etait. */
.nav__menu{display:flex;align-items:center;gap:inherit}

/* A partir de 1200px, le bandeau a quitte la barre : la place liberee sert a
   CENTRER le menu, le bouton Order restant a droite.
   Le menu est centre sur la FENETRE, pas sur l'espace restant a droite du
   logo : centre en flux, il aurait ete decale vers la droite de la moitie de
   la largeur du logo. D'ou le positionnement absolu, la nav etant deja fixe
   donc positionnee. */
@media (min-width:1200px){
  .nav__links{flex:1 1 auto;justify-content:flex-end}
  .nav__menu{
    position:absolute;left:50%;top:50%;
    transform:translate(-50%,-50%);
    gap:clamp(1.4rem,2.6vw,2.4rem);
  }
}
.nav__links a:not(.btn){
  position:relative;display:inline-flex;align-items:center;
  font-family:var(--font-display);font-weight:600;
  padding-block:.3rem;
  transition:opacity var(--dur) var(--ease),transform var(--dur) var(--ease);
}
/* La barre qui se trace sous le nom survole, meme motif que les filets qui
   se dessinent entre les sections : ici au survol plutot qu'au scroll. */
.nav__links a:not(.btn)::after{
  content:"";position:absolute;left:0;right:0;bottom:-2px;height:2px;
  background:var(--accent);border-radius:2px;
  transform:scaleX(0);transform-origin:0 50%;
  transition:transform var(--dur) var(--ease);
}
.nav__links a:not(.btn):hover,
.nav__links a:not(.btn):focus-visible{transform:scale(1.08)}
.nav__links a:not(.btn):hover::after,
.nav__links a:not(.btn):focus-visible::after,
.nav__links a[aria-current="page"]::after{transform:scaleX(1)}
/* Le nom survole se detache, les autres s'effacent un peu. */
.nav__links:has(a:not(.btn):hover) a:not(.btn):not(:hover){opacity:.45}

@media (max-width:720px){.nav__links a:not(.btn){display:none}}

/* --- Le panier dans la barre ---------------------------------------------
   Present sur les cinq pages, pas seulement sur la boutique : le panier vit
   dans le navigateur et survit au changement de page, donc s'il disparaissait
   de la barre ailleurs, un visiteur qui ajoute puis passe sur Home croirait
   l'avoir perdu.
   C'est un BOUTON et pas un lien, y compris sur les pages ou il ne fait que
   mener a la boutique : les regles de la nav visent `a:not(.btn)` et lui
   auraient donne le soulignement au survol, l'effacement des voisins et
   surtout display:none sous 720px, la ou il doit justement rester visible.
   Un bouton n'est pas non plus recopie dans le menu mobile, ou il n'aurait
   apporte qu'un chiffre nu en guise de libelle. */
.nav__cart{
  position:relative;flex:none;
  display:inline-flex;align-items:center;justify-content:center;
  width:clamp(38px,3.4vw,44px);aspect-ratio:1;
  border:1px solid var(--line);border-radius:12px;
  background:rgba(10,8,20,.34);
  color:inherit;cursor:pointer;
  transition:border-color var(--dur) var(--ease),background var(--dur) var(--ease);
}
.nav__cart:hover,
.nav__cart:focus-visible{border-color:rgba(168,85,247,.55);background:rgba(168,85,247,.18)}
.nav__cart svg{width:19px;height:19px;display:block}
/* La pastille ne s'affiche qu'une fois le panier rempli : a zero elle
   n'apprend rien et attire l'oeil sur du vide. */
.nav__cart-n{
  position:absolute;top:-7px;right:-7px;
  min-width:19px;height:19px;padding:0 5px;
  display:none;align-items:center;justify-content:center;
  border-radius:10px;background:var(--accent);color:#0A0A0A;
  font-family:var(--font-mono);font-size:.64rem;font-weight:500;
  font-variant-numeric:tabular-nums;text-shadow:none;
}
body.panier-plein .nav__cart-n{display:flex}

/* Le bouton Order de la nav : violet mais transparent, pas le plein aplat
   du CTA final. Scope a .nav pour ne pas toucher les autres boutons
   --primary du site, qui restent pleins pour convertir. */
/* Plus petit que les boutons du corps de page : dans la nav il accompagne,
   il ne doit pas concurrencer le titre du hero. La regle pointer:coarse plus
   bas lui garde quand meme ses 44px de hauteur tactile sur telephone. */
.nav .btn--primary{
  padding:.5rem 1rem;
  font-size:.82rem;
  border-radius:9px;
  background:rgba(168,85,247,.14);
  border:1px solid rgba(168,85,247,.55);
  color:var(--text-primary);
  backdrop-filter:blur(6px);
}
.nav .btn--primary:hover{
  background:rgba(168,85,247,.28);
  border-color:rgba(192,132,252,.8);
  color:#fff;
}

/* ==========================================================================
   Le menu mobile
   Le bouton et le panneau sont construits par app.js a partir des liens
   deja presents dans .nav__links : aucune des pages n'a a dupliquer ce
   balisage, et rien ne derive quand un lien change. Sans JavaScript, la
   nav reste ce qu'elle etait, il n'y a pas de regression.
   ========================================================================== */

.burger{
  display:none;
  width:44px;height:44px;padding:0;
  align-items:center;justify-content:center;
  flex-direction:column;gap:5px;
  background:none;border:none;cursor:pointer;
}
.burger span{
  display:block;width:22px;height:2px;border-radius:2px;
  background:var(--text-primary);
  transition:transform var(--dur) var(--ease),opacity var(--dur) var(--ease);
}
.burger[aria-expanded="true"] span:first-child{transform:translateY(3.5px) rotate(45deg)}
.burger[aria-expanded="true"] span:last-child{transform:translateY(-3.5px) rotate(-45deg)}

.navmenu{
  position:fixed;inset:0;z-index:99;
  background:rgba(6,6,12,.96);
  backdrop-filter:blur(14px);
  display:flex;flex-direction:column;justify-content:center;
  gap:.4rem;padding:var(--nav-h) var(--gutter) var(--gutter);
}
/* Obligatoire : le display ci-dessus bat la regle [hidden] du navigateur,
   donc sans cette ligne le panneau reste affiche en permanence. */
.navmenu[hidden]{display:none}
.navmenu nav{display:flex;flex-direction:column}
.navmenu__link{
  display:block;
  font-family:var(--font-display);font-weight:600;
  font-size:clamp(1.6rem,7vw,2.2rem);letter-spacing:-.02em;
  padding:.5rem 0;color:var(--text-primary);
  border-bottom:1px solid var(--line-soft);
  transition:color var(--dur) var(--ease);
}
.navmenu__link[aria-current="page"]{color:var(--accent)}
.navmenu__cta{
  margin-top:1.6rem;align-self:flex-start;
  display:inline-flex;align-items:center;
  font-family:var(--font-mono);font-size:.8rem;
  letter-spacing:.14em;text-transform:uppercase;
  padding:.95rem 1.5rem;border-radius:12px;
  background:rgba(168,85,247,.14);
  border:1px solid rgba(168,85,247,.55);
  color:var(--text-primary);
}

@media (max-width:720px){
  .burger{display:flex}
}
/* Le fond ne defile plus derriere le menu ouvert : sur l'accueil, ce scroll
   ferait avancer la video du hero sous le panneau. */
body.menu-open{overflow:hidden}

/* ==========================================================================
   Boutons
   ========================================================================== */

.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:.5rem;
  font-family:var(--font-body);font-size:.94rem;font-weight:600;
  padding:.78rem 1.35rem;border-radius:10px;border:1px solid transparent;
  cursor:pointer;text-shadow:none;
  transition:background var(--dur) var(--ease),border-color var(--dur) var(--ease),color var(--dur) var(--ease),transform var(--dur) var(--ease);
}
.btn--primary{background:var(--accent);color:#0A0A0A}
.btn--primary:hover{background:var(--accent-hover);transform:translateY(-1px)}
.btn--ghost{background:transparent;color:var(--text-primary);border-color:var(--line)}
.btn--ghost:hover{border-color:var(--accent);color:var(--accent-hover)}

:focus-visible{outline:2px solid var(--accent);outline-offset:3px;border-radius:4px}

/* Cibles tactiles : on ajoute la hauteur sans changer le type d'affichage,
   sinon les libelles se decalent a gauche et les rangees pleine largeur retrecissent. */
@media (pointer:coarse){
  .btn{min-height:44px}
  .nav__links a{min-height:44px;display:inline-flex;align-items:center}
}

/* ==========================================================================
   Le bandeau de statut vivant
   ========================================================================== */

.status{
  display:inline-flex;align-items:center;gap:.7rem;
  font-family:var(--font-mono);font-size:.72rem;font-weight:400;
  letter-spacing:.08em;text-transform:uppercase;
  color:var(--text-secondary);
  background:rgba(8,8,15,.55);
  border:1px solid rgba(96,96,126,.3);
  border-radius:10px;
  padding:.5rem .8rem;
  backdrop-filter:blur(10px);
  text-shadow:0 1px 3px rgba(5,5,10,.85);
  font-variant-numeric:tabular-nums;
}
.status__dot{width:7px;height:7px;border-radius:50%;background:var(--live-off);flex:none;position:relative}
.status.is-open .status__dot{background:var(--live)}
.status.is-open .status__dot::after{
  content:"";position:absolute;inset:-4px;border-radius:50%;
  background:var(--live);opacity:0;animation:pulse 2.4s var(--ease-slow) infinite;
}
@keyframes pulse{0%{opacity:.35;transform:scale(.6)}70%{opacity:0;transform:scale(1.9)}100%{opacity:0;transform:scale(1.9)}}
.status__sep{color:var(--text-faint)}
.status__time{color:var(--text-primary)}

/* ==========================================================================
   La couche d'environnement : la ville derriere la page.
   Presente sur CHAQUE page, sinon les pages internes se sentent vides.
   ========================================================================== */

.env{position:fixed;inset:0;z-index:0;pointer-events:none;overflow:hidden}
.env__glow{
  position:absolute;inset:-20%;
  background:radial-gradient(ellipse 60% 50% at 50% 8%,rgba(168,85,247,.10),transparent 70%),
             radial-gradient(ellipse 70% 40% at 20% 92%,rgba(245,165,36,.05),transparent 70%);
  animation:envdrift 90s linear infinite;
}
@keyframes envdrift{0%{transform:translate3d(0,0,0)}50%{transform:translate3d(2%,-1.5%,0)}100%{transform:translate3d(0,0,0)}}

/* Les particules derivent vers le HAUT, parce que le visiteur descend.
   C'est ce qui donne la sensation de chute permanente sur tout le site. */
.env__dust{position:absolute;inset:0}
.env__dust i{
  position:absolute;bottom:-10px;width:2px;height:2px;border-radius:50%;
  background:var(--accent);opacity:.06;
  animation:rise linear infinite;
}
@keyframes rise{
  0%{transform:translateY(0) translateX(0);opacity:0}
  12%{opacity:.09}
  88%{opacity:.05}
  100%{transform:translateY(-104vh) translateX(var(--dx,8px));opacity:0}
}

/* La nav est volontairement absente d ici : elle est en position:fixed plus
   haut, et la reintroduire dans ce groupe la remettait dans le flux normal,
   ce qui poussait toute la page de sa hauteur. Elle porte deja son z-index. */
main,footer{position:relative;z-index:1}

/* ==========================================================================
   Entrees au scroll : le vocabulaire, defini une seule fois.
   Etats prefixes par le conteneur pour gagner la cascade.
   ========================================================================== */

.rev .part{opacity:0;transform:translateY(22px);transition:opacity var(--dur-slow) var(--ease-slow),transform var(--dur-slow) var(--ease-slow)}
.rev.in .part{opacity:1;transform:none}
.rev.in .part:nth-child(2){transition-delay:.09s}
.rev.in .part:nth-child(3){transition-delay:.18s}
.rev.in .part:nth-child(4){transition-delay:.27s}
.rev.in .part:nth-child(5){transition-delay:.36s}

/* La retraite des delais, une fois l'entree finie. La specificite doit battre
   celle des regles nth-child ci-dessus, sinon les survols suivants restent en retard. */
.rev.in.done .part:nth-child(n){transition-delay:0s}

/* Le filet qui se dessine entre les sections. */
.rule{height:1px;background:var(--line-soft);transform:scaleX(0);transform-origin:0 50%;transition:transform 1.1s var(--ease-slow)}
.rev.in .rule,.rule.in{transform:scaleX(1)}

/* ==========================================================================
   Sections et cartes
   ========================================================================== */

section{padding-block:clamp(72px,10vw,140px);position:relative}

.card{
  background:var(--panel);
  border:1px solid var(--line-soft);
  border-radius:14px;
  padding:clamp(20px,2.4vw,30px);
  transition:border-color var(--dur) var(--ease),background var(--dur) var(--ease),transform var(--dur) var(--ease);
}
.card:hover{border-color:var(--line);background:var(--panel-raised);transform:translateY(-2px)}

footer{border-top:1px solid var(--line-soft);padding-block:clamp(48px,6vw,80px);color:var(--text-secondary);font-size:.9rem}

/* ==========================================================================
   Mouvement reduit : honore completement, et dans les deux sens.
   Les etats finaux sont montres, les moteurs sont arretes.
   ========================================================================== */

@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{
    animation-duration:.001ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.001ms !important;
    transition-delay:0s !important;
    scroll-behavior:auto !important;
  }
  .rev .part{opacity:1;transform:none}
  .rule{transform:scaleX(1)}
  .env__dust{display:none}
  @view-transition{navigation:none}
}

/* La pause globale sur onglet cache. animation-play-state n'est pas heritee,
   donc la regle doit viser les pseudo-elements explicitement. */
body.paused *,body.paused *::before,body.paused *::after{animation-play-state:paused !important}

/* Les petites surcouches scrollees n'ont pas de place sur un ecran court. */
@media (max-height:560px){.cue{display:none}}

/* ==========================================================================
   LE PORTAIL D'AGE ET L'OUVERTURE.
   Trois temps dans un seul element fixe : la verification, l'ecran noir ou le
   V se dessine, puis l'iris qui s'ouvre du centre vers les bords.

   L'iris n'est pas un masque mais une OMBRE PORTEE. Un disque minuscule au
   centre, entoure d'une ombre de 100vmax qui noircit tout l'ecran. L'agrandir
   fait grandir le trou et repousse le noir : l'ouverture est donc une simple
   transformation, composee par le GPU, au lieu d'un degrade masque recalcule
   a chaque image. C'est ce qui la rend fluide sur telephone.
   ========================================================================== */
.porte{
  position:fixed;inset:0;z-index:9999;
  /* align-content:center est indispensable des qu il y a deux rangees, la
     tete et le bloc de texte. Sans lui les rangees automatiques s etirent
     sur toute la hauteur, chacune centree dans sa moitie : un vide de pres
     de 200px separait le logo du texte. */
  display:grid;place-items:center;align-content:center;
  background:#05050A;
  padding:var(--gutter);
  text-align:center;
}
/* Deja verifie : le portail ne doit meme pas etre peint une image. La classe
   est posee par le script de tete, avant la premiere peinture. */
html.age-ok .porte{display:none}
/* Le defilement est bloque tant que le portail est la. */
html.porte-active,html.porte-active body{overflow:hidden}

.porte__iris{
  position:absolute;left:50%;top:50%;
  width:6px;height:6px;border-radius:50%;
  transform:translate(-50%,-50%) scale(1);
  box-shadow:0 0 0 100vmax #05050A;
  pointer-events:none;
}
/* Pendant la verification, le fond plein suffit : l'iris ne sert qu'a
   l'ouverture, et son trou de 6px se verrait au centre du texte. */
.porte:not(.porte--ouvre) .porte__iris{display:none}
/* A l'ouverture le fond plein s'efface et l'iris prend le relais. Il couvre
   deja tout l'ecran a cet instant, donc le relais ne se voit pas. */
.porte--ouvre{background:transparent;pointer-events:none}

.porte__in,.porte__stop{position:relative;z-index:1;max-width:34rem}

/* La tete du portail : le logo, puis un liseré violet qui le separe du texte.
   Elle est un enfant direct de .porte, donc une rangee de grille a part : elle
   reste en place quand le bloc de verification cede la place a celui du refus,
   et le script la masque pour le temps du chargement. */
.porte__tete{
  position:relative;z-index:1;
  display:flex;flex-direction:column;align-items:center;
  gap:clamp(.9rem,2vh,1.4rem);
  margin-bottom:clamp(1.3rem,3vh,2.1rem);
}
.porte__logo{display:flex;align-items:center;gap:.6rem;color:var(--text-primary)}
.porte__logo svg{display:block;width:clamp(42px,4.2vw,58px);height:auto}
.porte__logo b{
  font-family:var(--font-display);font-weight:800;
  font-size:clamp(1.72rem,3vw,2.5rem);letter-spacing:-.02em;
}
.porte__rule{
  display:block;width:clamp(54px,6.6vw,86px);height:2px;border-radius:2px;
  background:var(--accent);
  box-shadow:0 0 16px rgba(168,85,247,.65);
}
/* Le violet ne porte que le chiffre : c'est la seule information que le
   visiteur doit retenir de cet ecran. */
.porte__titre em{font-style:normal;color:var(--accent)}
.porte__kick{
  display:block;font-family:var(--font-mono);
  font-size:clamp(.58rem,.8vw,.7rem);letter-spacing:.28em;
  text-transform:uppercase;color:var(--accent);margin-bottom:1.1rem;
}
.porte__titre{
  font-family:var(--font-display);font-weight:800;
  font-size:clamp(1.7rem,4.4vw,3rem);line-height:1.04;letter-spacing:-.03em;
  color:var(--text-primary);margin:0 0 1rem;
}
.porte__txt{
  font-size:clamp(.92rem,1.2vw,1.05rem);line-height:1.55;
  color:var(--text-secondary);margin:0 auto;max-width:44ch;
}
.porte__btns{
  display:flex;flex-wrap:wrap;gap:.8rem;justify-content:center;
  margin:clamp(1.6rem,3vh,2.4rem) 0 0;
}
.porte__oui,.porte__non{
  font-family:var(--font-mono);font-size:.72rem;letter-spacing:.16em;
  text-transform:uppercase;cursor:pointer;
  padding:.95rem 1.6rem;border-radius:30px;
  transition:background var(--dur) var(--ease),border-color var(--dur) var(--ease),color var(--dur) var(--ease);
}
.porte__oui{
  color:var(--text-primary);
  border:1px solid var(--accent);
  background:rgba(168,85,247,.18);
  box-shadow:0 0 26px rgba(168,85,247,.28);
}
.porte__oui:hover,.porte__oui:focus-visible{background:rgba(168,85,247,.34)}
.porte__non{
  color:var(--text-secondary);
  border:1px solid var(--line);
  background:transparent;
}
.porte__non:hover,.porte__non:focus-visible{color:var(--text-primary);border-color:var(--text-faint)}
.porte__warn{
  font-family:var(--font-mono);font-size:clamp(.54rem,.75vw,.64rem);
  letter-spacing:.1em;line-height:1.7;color:var(--text-faint);
  margin:clamp(1.6rem,3vh,2.4rem) auto 0;max-width:46ch;
  text-transform:uppercase;
}

/* --- Le temps 2 : le V qui se dessine sur le noir --- */
.porte__load{position:relative;z-index:1}
.porte__v{width:clamp(120px,17vw,210px)}
.porte__v svg{display:block;width:100%;height:auto;overflow:visible}
.porte__v .trace{
  fill:none;stroke:var(--accent);stroke-width:6;
  stroke-linecap:square;stroke-linejoin:miter;
  stroke-dasharray:340;
  stroke-dashoffset:calc(340 * (1 - var(--hp,0)));
  filter:drop-shadow(0 2px 20px rgba(168,85,247,.5));
}
/* Le V s'efface pendant que l'iris s'ouvre : il ne doit pas rester en
   surimpression sur la video qui apparait derriere. */
.porte--ouvre .porte__load,
.porte--ouvre .porte__tete{
  opacity:0;transform:scale(1.12);
  transition:opacity .5s var(--ease-slow),transform .9s var(--ease-slow);
}

/* Mouvement reduit : pas de trace qui se dessine ni d'iris qui s'ouvre. Le
   portail disparait, c'est tout. */
@media (prefers-reduced-motion:reduce){
  .porte__v .trace{stroke-dashoffset:0}
  .porte--ouvre{opacity:0;transition:opacity .3s linear}
  .porte--ouvre .porte__iris{display:none}
}
