/* ============================================================================
   STEVEN DIEU — Portfolio jouable
   Feuille de style des overlays HTML (par-dessus le canvas du jeu).
   La palette et les polices sont pilotées par les variables ci-dessous et
   seront ajustées à la direction artistique finale.
   ============================================================================ */

:root {
  /* Palette — « Les Lucioles de Nantes : Le Crépuscule de la Loire » */
  --sky-top:      #341552;
  --sky-bottom:   #ff7a3d;
  --ink:          #2a1733;
  --paper:        #fff3e4;
  --accent:       #ffd24a;   /* luciole dorée */
  --accent-2:     #ff7a3d;   /* amber horizon */
  --glow:         #ffd24a;
  --orb:          #5fe0c8;   /* orbe-projet teal */

  --panel:        rgba(28, 10, 34, 0.86);
  --panel-border: rgba(255, 233, 200, 0.18);

  /* Polices */
  --font-display: "Fraunces", Georgia, serif;
  --font-body:    "Quicksand", system-ui, sans-serif;

  --radius:   20px;
  --radius-sm:12px;
  --shadow:   0 24px 60px -12px rgba(0,0,0,.55);
}

* { box-sizing: border-box; margin: 0; padding: 0; }
[hidden] { display: none !important; }   /* prioritaire sur .btn, .overlay, etc. */

html, body {
  height: 100%;
  overflow: hidden;
  background: var(--sky-top);
  font-family: var(--font-body);
  color: var(--paper);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overscroll-behavior: none;
  touch-action: none;
}

#game {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  image-rendering: auto;
  cursor: default;
}

/* ===================== SCROLLBARS (assorties au thème dorée / crépuscule) =====================
   Pouce doré (accent -> amber) en pilule flottante, sur une rainure sombre et tiède.
   Ne s'affiche que dans les panneaux qui défilent (overlays, modal projet, vue projets) —
   le <body> est en overflow:hidden. */
/* Firefox */
* { scrollbar-width: thin; scrollbar-color: var(--accent) rgba(255, 233, 200, .10); }
/* WebKit / Chromium / Edge / Safari */
::-webkit-scrollbar { width: 12px; height: 12px; }
::-webkit-scrollbar-track {
  background: rgba(10, 5, 20, .35);
  border-radius: 999px;
  margin: 6px;                                   /* la rainure n'atteint pas les coins arrondis */
}
::-webkit-scrollbar-thumb {
  border-radius: 999px;
  border: 3px solid transparent;                 /* marge transparente -> pilule fine et flottante */
  background: linear-gradient(180deg, var(--accent), var(--accent-2)) content-box;
  box-shadow: 0 0 6px -1px rgba(255, 170, 70, .5);   /* halo doré discret */
}
::-webkit-scrollbar-thumb:hover {
  background: linear-gradient(180deg, #ffe79a, var(--accent) 55%, var(--accent-2)) content-box;
}
::-webkit-scrollbar-thumb:active { background: linear-gradient(180deg, var(--accent-2), #ff944a) content-box; }
::-webkit-scrollbar-corner { background: transparent; }

/* ===================== OVERLAYS (base) ===================== */
.overlay {
  position: fixed;
  inset: 0;
  z-index: 30;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: safe center;   /* centre, mais ne rogne pas si trop haut */
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding: clamp(16px, 4vw, 48px);
  animation: overlayIn .5s ease both;
}
.overlay[hidden] { display: none; }

.overlay__inner {
  position: relative;
  max-width: 540px;
  width: 100%;
  flex: 0 0 auto;
  margin: auto;
  text-align: center;
  background: var(--panel);
  border: 1px solid var(--panel-border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: clamp(28px, 5vw, 48px);
  backdrop-filter: blur(8px) saturate(1.2);
}

/* Écran de démarrage : on laisse voir le jeu derrière */
.overlay--start  { background: radial-gradient(120% 120% at 50% 0%, rgba(20,10,40,.35), rgba(10,6,24,.72)); }
.overlay--contact{ background: radial-gradient(120% 120% at 50% 100%, rgba(20,10,40,.5), rgba(10,6,24,.84)); backdrop-filter: blur(6px); }

/* ===== Écran de fin : DEUX cartes peintes côte à côte (desktop), FUSIONNÉES en une (mobile) =====
   Chaque carte reprend le cadre éprouvé de la vue projets (popup-vertical.png). */
.overlay--contact { flex-direction: column; gap: clamp(14px, 2.4vh, 22px); }

.contact__deck { display: flex; flex-direction: row; align-items: flex-start; justify-content: center; gap: 18px; }
.contact__deck[hidden] { display: none; }   /* bascule vers la vue « classement complet » */
.contact__deck-inner { display: contents; }   /* desktop : les 2 sections deviennent les cartes (flex items du deck) */
.contact__deck-frame { display: none; }        /* le cadre commun ne sert qu'en mobile (fusion) */

.contact__card {
  position: relative;
  width: min(340px, 42vw, calc(80dvh / 1.5));
  aspect-ratio: 1024 / 1536;
  filter: drop-shadow(0 30px 44px rgba(0,0,0,.55));
  animation: popIn .32s cubic-bezier(.2,1.2,.4,1) both;
}
.contact__card--rank { animation-delay: .05s; }
.contact__card--collab .contact__body { justify-content: center; }   /* contenu court : centré verticalement dans le parchemin (la carte rank, elle, reste ancrée en haut et défile) */
.contact__frame { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; user-select: none; }
.contact__body {
  position: absolute; left: 16%; right: 16%; top: 20%; bottom: 24%; z-index: 2;
  display: flex; flex-direction: column; text-align: center; color: #46280f;
  overflow-y: auto; padding-right: 4px;
  scrollbar-width: thin; scrollbar-color: #b98a3e rgba(120,80,30,.18);
}
.contact__body::-webkit-scrollbar, .contact__deck-inner::-webkit-scrollbar { width: 9px; }
.contact__body::-webkit-scrollbar-track, .contact__deck-inner::-webkit-scrollbar-track { background: rgba(120,80,30,.16); border-radius: 99px; }
.contact__body::-webkit-scrollbar-thumb, .contact__deck-inner::-webkit-scrollbar-thumb { border-radius: 99px; border: 2px solid transparent; background-clip: padding-box; background: linear-gradient(180deg, #e8c27a, #b98a3e); }
.contact__kicker { font-family: var(--font-body); font-weight: 700; font-size: .62rem; text-transform: uppercase; letter-spacing: .14em; color: #a8701e; }
.contact__title { font-family: "Cinzel", var(--font-display); font-weight: 900; font-size: clamp(1.05rem, 2.4vw, 1.5rem); line-height: 1.06; color: #46280f; text-shadow: 0 1px 0 rgba(255,255,255,.5); margin: 3px 0 0; text-wrap: balance; }
.contact__sub { font-family: var(--font-display); font-weight: 600; font-size: .8rem; color: #7a5226; margin: 6px 0 12px; text-wrap: balance; }

/* note hors-ligne : visible seulement quand le classement (#leaderboard) est masqué */
.leaderboard__offline { display: none; font-size: .68rem; color: #9a6a2a; margin: 8px 0 0; line-height: 1.4; }
#leaderboard[hidden] + .leaderboard__offline { display: block; }

/* ===== MOBILE : une seule pop up — les deux cartes fusionnent dans UN cadre ===== */
@media (max-width: 820px) {
  .contact__deck {
    position: relative; flex-direction: column; gap: 0;
    width: min(440px, 90vw, calc(86dvh / 1.5));
    aspect-ratio: 1024 / 1536;
    filter: drop-shadow(0 30px 44px rgba(0,0,0,.6));
    animation: popIn .32s cubic-bezier(.2,1.2,.4,1) both;
    top: 20px;   /* abaisse l'écran de fin de 20px (relatif : n'ajoute pas au flux, ne casse pas le popIn) */
  }
  /* les boutons NE descendent PAS avec le cadre (remontés de 20px) et tiennent sur UNE ligne -> tout rentre sans scroll.
     Sélecteur descendant (.contact__footer .contact__bigbtn) pour battre le min-width: 11em défini plus bas. */
  .overlay--contact { gap: 22px; }
  .contact__footer { gap: 10px; flex-wrap: nowrap; }
  /* chaque bouton se dimensionne à SON texte (flex-basis auto) au lieu d'être forcé à une demi-largeur
     égale (l'ancien flex 1 1 0 rognait « 🏆 Classement », plus long). min-width: 0 neutralise le
     min-width: 11em de base (sinon les 2 boutons seraient gonflés à 11em et déborderaient sur petit écran). */
  .contact__footer .contact__bigbtn { flex: 0 1 auto; min-width: 0; font-size: .9rem; padding: .64rem .9rem; }
  /* « Merci d'avoir joué » pas collé au bord du cadre */
  .contact__card--collab .contact__body { padding-top: 6px; }
  .contact__deck-frame { display: block; position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; user-select: none; }
  .contact__deck-inner {
    display: flex; flex-direction: column; gap: 12px;
    position: absolute; left: 15%; right: 15%; top: 19%; bottom: 23%; z-index: 2;
    overflow-y: auto; padding-right: 4px;
    scrollbar-width: thin; scrollbar-color: #b98a3e rgba(120,80,30,.18);
  }
  .contact__card { position: static; width: auto; aspect-ratio: auto; filter: none; animation: none; }
  .contact__card .contact__frame { display: none; }
  .contact__card--rank { border-top: 1px solid rgba(138,90,30,.25); padding-top: 11px; }
  .contact__body { position: static; inset: auto; left: auto; right: auto; top: auto; bottom: auto; overflow: visible; padding-right: 0; }
}

/* ===================== ÉCRAN DE FIN : croix de fermeture, boutons, vue classement complet ===================== */
/* croix de fermeture, posée sur le ✕ peint du cadre. Desktop : une par carte. Mobile : sur le cadre commun. */
.contact__close {
  position: absolute; top: 13.3%; right: 7%; width: 7.6%; aspect-ratio: 1;
  border: none; background: transparent; border-radius: 50%; cursor: pointer; z-index: 6;
  transition: box-shadow .12s;
}
.contact__close:hover { box-shadow: 0 0 0 2px rgba(255,220,120,.6), 0 0 16px rgba(255,200,90,.6); }
.contact__close:focus-visible { outline: 3px solid #ffd24a; outline-offset: 2px; }
.contact__close--deck { display: none; }   /* desktop : chaque carte a sa propre croix */

/* carte CLASSEMENT : le contenu remplit toute la carte, les boutons restent collés en bas */
.contact__body--rank { gap: 7px; }
.contact__actions { margin-top: auto; display: flex; gap: 8px; justify-content: center; }
.contact__btn {
  flex: 1 1 0; cursor: pointer; font: inherit; font-family: "Cinzel", var(--font-display);
  font-weight: 700; font-size: .85rem; border: none; border-radius: 11px; padding: .5rem .6rem; white-space: nowrap;
}
.contact__btn--play { color: #2a1033; background: linear-gradient(180deg, #ffe27a, #ffb43d); box-shadow: 0 4px 0 #7a3a12; }
.contact__btn--play:active { transform: translateY(2px); box-shadow: 0 2px 0 #7a3a12; }
.contact__btn--ghost {
  color: #7a4e12; background: linear-gradient(180deg, rgba(255,250,235,.6), rgba(206,170,110,.3));
  border: 1px solid rgba(138,90,30,.4); box-shadow: inset 0 1px 0 rgba(255,255,255,.5);
}
.contact__btn--ghost:hover { box-shadow: 0 0 0 2px rgba(224,168,58,.55); }

/* formulaire EMPILÉ : champ « Prénom Nom » au-dessus, bouton Valider en dessous */
.lb-form--stacked { display: flex; flex-direction: column; gap: 6px; margin: 8px 0 0; }
.lb-form--stacked .lb-form__btn { width: 100%; }
/* carte CLASSEMENT : top 10 qui DÉFILE en interne, boutons collés en bas, le tout dans le parchemin */
.contact__body--rank { overflow: hidden; gap: 6px; }
.contact__body--rank .leaderboard { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; margin: 4px 0 0; }
.contact__body--rank .leaderboard__list { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding-right: 4px; scrollbar-width: thin; scrollbar-color: #b98a3e rgba(120,80,30,.18); }
.contact__body--rank .leaderboard__list::-webkit-scrollbar { width: 8px; }
.contact__body--rank .leaderboard__list::-webkit-scrollbar-track { background: rgba(120,80,30,.16); border-radius: 99px; }
.contact__body--rank .leaderboard__list::-webkit-scrollbar-thumb { border-radius: 99px; border: 2px solid transparent; background-clip: padding-box; background: linear-gradient(180deg, #e8c27a, #b98a3e); }
.contact__body--rank .leaderboard__you { margin: 5px 0 2px; font-size: .82rem; }
.contact__body--rank .lb-row { padding: .26rem .55rem; font-size: .76rem; }
/* on COMPACTE l'en-tête + le formulaire pour laisser de la place à la liste top 10 */
.contact__body--rank .contact__kicker { display: none; }   /* gagne une ligne de liste sur la petite carte */
/* SWAP demandé : le SCORE devient le héros (gros + sombre), « Classement » petit label doré ; « Score : » affiché pour la clarté */
.contact__body--rank { padding-top: 10px; }   /* un peu d'air au-dessus de « Classement / Score » */
.contact__body--rank .contact__title { font-family: var(--font-body); font-weight: 800; font-size: .62rem; text-transform: uppercase; letter-spacing: .14em; color: #a8701e; text-shadow: none; margin: 0; }
.contact__body--rank .contact__score { display: flex; align-items: baseline; justify-content: center; gap: .4rem; margin: 2px 0 0; flex-wrap: wrap; }
.contact__body--rank .contact__score-label { display: inline; font-size: .82rem; font-weight: 800; text-transform: none; letter-spacing: 0; color: #a8701e; }
.contact__body--rank .contact__score-label::after { content: " :"; }
.contact__body--rank .contact__score-value { font-family: "Cinzel", var(--font-display); font-weight: 900; font-size: clamp(1.4rem, 3.2vw, 1.85rem); color: #46280f; line-height: 1; font-variant-numeric: tabular-nums; white-space: nowrap; word-spacing: .22em; }
.contact__body--rank .lb-form--stacked { gap: 5px; margin: 4px 0 0; padding: 0 6px; }
.contact__body--rank .lb-form__input { padding: .38rem .7rem; }
.contact__body--rank .lb-form__btn { padding: .38rem 1rem; }
.contact__body--rank .lb-form__hint { min-height: 0; margin: 2px 0 0; }
.contact__body--rank .lb-form__hint:empty { display: none; }
.contact__body--rank .contact__btn { font-size: .8rem; padding: .42rem .55rem; }
/* utilitaire : lu par les lecteurs d'écran, invisible à l'œil */
.visually-hidden { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

/* carte COLLABORATION : texte d'accroche CENTRÉ, les 3 pastilles de contact restent EN BAS, AUCUN scroll */
.contact__welcome { flex: 1 1 auto; display: flex; flex-direction: column; justify-content: center; gap: 4px; }
.contact__card--collab .contact-links { margin: 6px 0 15px; }   /* pastilles email/linkedin/github remontées (15px du bas : +5px, sinon rognées en bas) */
.contact__card--collab .contact__body { overflow: hidden; }   /* pas de scroll sur la pop up de gauche */
.contact__card--collab .contact__title { font-size: clamp(.92rem, 2.8vw, 1.1rem); line-height: 1.18; margin-top: 2px; }
.contact__card--collab .contact__kicker { font-size: .66rem; }

/* BOUTONS D'ACTION : SOUS les cartes, hors des cadres, bien gros et lisibles */
.contact__footer { display: flex; gap: 14px; justify-content: center; flex-wrap: wrap; }
.contact__footer[hidden] { display: none; }
/* ====================== BOUTONS D'ACTION UNIFIÉS ======================
   TOUS les boutons d'action du site partagent la MÊME forme et les MÊMES
   effets que les deux boutons de l'écran de fin (.contact__bigbtn) : pilule
   Cinzel, ombre 3D « empilée » (0 5px 0 var(--btn-sh)) qui grandit au survol
   et s'enfonce au clic. SEULE LA COULEUR change (fond + texte + couleur
   d'ombre --btn-sh). Cible : Jouer (accueil/prélude), Voir mes projets,
   Valider (classement), Classement + Rejouer (fin), Visiter le site (fiche
   projet : pop-up + panneau « Tous mes projets »). Les contrôles « chrome »
   (croix, flèches, son, HUD projets, tactile) NE sont PAS concernés. */
.contact__bigbtn,
.cover__play, .cover__see,
.prelude__btn,
.lb-form__btn,
.btn--card, .pdetail__link {
  cursor: pointer; font: inherit; font-family: "Cinzel", var(--font-display); font-weight: 700;
  font-size: 1.05rem; line-height: 1.2; border: 1px solid transparent; border-radius: 14px;
  padding: .78rem 1.5rem; white-space: nowrap; text-align: center; text-decoration: none;
  box-shadow: 0 5px 0 var(--btn-sh, #7a3a12);
  transition: transform .12s ease, box-shadow .12s ease;
}
.contact__bigbtn:hover, .cover__play:hover, .cover__see:hover,
.prelude__btn:hover, .lb-form__btn:hover,
.btn--card:hover, .pdetail__link:hover { transform: translateY(-2px); box-shadow: 0 7px 0 var(--btn-sh, #7a3a12); }
.contact__bigbtn:active, .cover__play:active, .cover__see:active,
.prelude__btn:active, .lb-form__btn:active,
.btn--card:active, .pdetail__link:active { transform: translateY(3px); box-shadow: 0 2px 0 var(--btn-sh, #7a3a12); }
.contact__bigbtn { min-width: 11em; }   /* les 2 boutons de fin restent larges et égaux */

/* COULEURS (uniquement) ------------------------------------------------ */
/* doré « jouer » : accueil, prélude, valider le pseudo, Rejouer (fin), Visiter le site (projets) */
.contact__bigbtn--play, .cover__play, .prelude__btn, .lb-form__btn,
.btn--card, .pdetail__link {
  --btn-sh: #7a3a12; color: #2a1033;
  background: linear-gradient(180deg, #ffe27a, #ffb43d); border-color: rgba(122,58,18,.45);
}
/* blanc nacré « projets » : « Voir mes projets » de l'accueil (texte prune) */
.cover__see {
  --btn-sh: #b58a52; color: #2a1033;
  background: linear-gradient(180deg, #fff8ee, #ffe9cf); border-color: rgba(122,58,18,.32);
}
/* brun foncé « fantôme » : « Classement » de la fin */
.contact__bigbtn--ghost { --btn-sh: #1c0e05; color: #ffe9c8; background: linear-gradient(180deg, #4a2a12, #301808); border-color: rgba(255,210,120,.5); }
/* animation d'appel sur « Rejouer » (via filter, ne gêne pas l'effet d'enfoncement). !important = exemptée
   du mode « mouvement réduit » car explicitement demandée. */
@keyframes rejouerPulse { 0%, 100% { filter: drop-shadow(0 0 0 rgba(255,200,90,0)); } 50% { filter: drop-shadow(0 0 11px rgba(255,200,90,.8)); } }
.contact__bigbtn--play { animation: rejouerPulse 1.7s ease-in-out infinite !important; }

/* ===== VUE PLEIN ÉCRAN : classement complet (recherche + pagination) ===== */
/* cadre PEINT (popup-square en desktop) : on garde l'empreinte ~680x600 d'avant, mais c'est
   l'image qui dessine fond + bordure ; le contenu vit dans .contact__full-inner (parchemin). */
.contact__full {
  position: relative;
  width: min(680px, 94vw, calc((100dvh - 40px) * 1.134));   /* tient en hauteur (ratio carré 532/469) */
  aspect-ratio: 532 / 469;
  color: #43260e;
  filter: drop-shadow(0 28px 50px rgba(0,0,0,.55));
  animation: popIn .3s cubic-bezier(.2,1.2,.4,1) both;
}
.contact__full[hidden] { display: none; }
.contact__full-frame, .contact__full-frame img { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; user-select: none; }
/* zone parchemin : en-tête, recherche, liste défilante et pagination y sont calés (le reste du cadre est peint) */
.contact__full-inner {
  position: absolute; left: 17%; right: 16%; top: 23%; bottom: 17%; z-index: 2;
  display: flex; flex-direction: column; gap: 9px; min-height: 0;
}
.contact__full-head { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 8px; margin-bottom: 8px; }   /* un peu d'air avant le champ de recherche */
.contact__full-back { justify-self: start; cursor: pointer; font: inherit; font-weight: 800; font-size: .82rem; color: #a8701e; background: none; border: none; padding: 4px; }
.contact__full-back:hover { color: #7a4e12; }
/* MÊME typo/taille que « Mes projets » (.projects__title) pour une vraie cohérence des deux pop ups */
.contact__full-title { grid-column: 2; font-family: "Cinzel", var(--font-display); font-weight: 900; font-size: clamp(1.3rem, 5vw, 1.9rem); line-height: 1; color: #46280f; text-shadow: 0 1px 0 rgba(255,255,255,.5); margin: 0; text-wrap: balance; }
/* icône classement (assets/ui/classement.png) devant le(s) bouton(s) « Classement » HUD + fin (remplace l'emoji 🏆) */
.lb-ic { height: 1.3em; width: auto; vertical-align: -0.27em; margin-right: .35em; }
/* icône play (assets/ui/play.png) devant « Jouer » (accueil + prélude) en remplacement de l'emoji ▶ */
.play-ic { height: 1.15em; width: auto; vertical-align: -0.2em; margin-right: .4em; }
/* ✕ : bouton transparent posé sur la croix ROUGE peinte (coin sup. droit du cadre carré) */
.contact__close--full { top: 12.3%; right: 8.7%; width: 5.8%; }
.contact__close--full::before { content: none; }
.contact__full-search {
  width: 100%; padding: .55rem .8rem; border-radius: 10px; font: inherit; font-weight: 600; color: #43260e;
  background: rgba(255,255,255,.72); border: 1px solid rgba(138,90,30,.4);
}
.contact__full-search::placeholder { color: rgba(122,82,38,.55); }
.contact__full-search:focus-visible { outline: 2px solid #c98a2e; outline-offset: 1px; }
.contact__full-list {
  list-style: none; margin: 0; padding: 2px; flex: 1 1 auto; min-height: 0; overflow-y: auto;
  display: flex; flex-direction: column; gap: 5px;
  scrollbar-width: thin; scrollbar-color: #b98a3e rgba(120,80,30,.18);
}
.contact__full-list::-webkit-scrollbar { width: 9px; }
.contact__full-list::-webkit-scrollbar-track { background: rgba(120,80,30,.16); border-radius: 99px; }
.contact__full-list::-webkit-scrollbar-thumb { border-radius: 99px; border: 2px solid transparent; background-clip: padding-box; background: linear-gradient(180deg, #e8c27a, #b98a3e); }
.contact__full-list .lb-row { padding: .5rem .8rem; font-size: .88rem; }
.contact__full-empty[hidden] { display: none; }
.contact__full-empty { text-align: center; color: #86592a; font-size: .85rem; padding: 1rem 0; }
.contact__full-pager { display: flex; align-items: center; justify-content: center; gap: 14px; }
.contact__pager-btn {
  cursor: pointer; width: 38px; height: 38px; border-radius: 10px; font-size: 1.2rem; font-weight: 800; color: #2a1033;
  border: none; background: linear-gradient(180deg, #ffe27a, #ffb43d); box-shadow: 0 3px 0 #7a3a12;
}
.contact__pager-btn:active { transform: translateY(2px); box-shadow: 0 1px 0 #7a3a12; }
.contact__pager-btn:disabled { opacity: .4; cursor: default; box-shadow: 0 1px 0 #7a3a12; }
.contact__pager-info { font-weight: 800; font-variant-numeric: tabular-nums; color: #7a4e12; min-width: 4.5em; text-align: center; }

/* loader du classement (pendant la récupération « 10 par 10 ») */
.lb-loader { flex: 1 1 auto; min-height: 0; display: flex; align-items: center; justify-content: center; gap: .55rem; padding: 1.6rem 0; color: #7a4e12; font-weight: 700; font-size: .9rem; }
.lb-loader[hidden] { display: none; }
.lb-spinner { width: 20px; height: 20px; border-radius: 50%; border: 3px solid rgba(138,90,30,.25); border-top-color: #b06a12; animation: lbSpin .7s linear infinite !important; }
@keyframes lbSpin { to { transform: rotate(360deg); } }

/* loader du mini-classement (petite carte de fin) : même esprit, plus compact */
.lb-loader--mini { padding: 1.1rem 0; font-size: .8rem; }
.lb-loader--mini .lb-spinner { width: 17px; height: 17px; border-width: 2.5px; }
/* pendant le chargement de la carte, on masque le message « hors-ligne » (sinon il clignote
   sous le loader) ; !important car #leaderboard[hidden] + … porte un ID plus spécifique */
.contact__body--rank.is-loading .leaderboard__offline { display: none !important; }

/* ===== MOBILE : croix sur le cadre commun, et formulaire/boutons adaptés ===== */
@media (max-width: 820px) {
  .contact__close--card { display: none; }
  .contact__close--deck { display: block; }
  /* mobile : on retire « ‹ Retour » (prend trop de place) ; la croix + Échap ramènent aux cartes.
     La grille 1fr/auto/1fr garde le titre centré (col 2) et la croix à droite (col 3). */
  .contact__full-back { display: none; }
  /* mobile : pop up « Classement mondial » COMPACTE — elle épouse son contenu quand il est court
     (height:auto), mais reste plafonnée bien en dessous du plein écran -> lecture « carte », pas
     « page ». Dès que la liste dépasse, c'est ELLE qui scrolle (flex:1 1 auto + min-height:0 +
     overflow-y déjà posés), jamais la page. Rangées + chrome resserrés pour gagner en hauteur. */
  .contact__full {
    width: min(420px, 90vw, calc((100dvh - 28px) * 0.667));   /* cadre PORTRAIT popup-vertical (ratio 1024/1536) */
    aspect-ratio: 1024 / 1536;
  }
  /* parchemin du cadre portrait : mêmes marges éprouvées que la fusion mobile du deck */
  .contact__full-inner { left: 15%; right: 15%; top: 19%; bottom: 22%; gap: 7px; }
  .contact__close--full { top: 13.3%; right: 7%; width: 7.6%; }
  .contact__full-head { margin-bottom: 2px; }
  .contact__full-search { padding: .42rem .7rem; }
  .contact__full-list { gap: 4px; }
  .contact__full-list .lb-row { padding: .34rem .6rem; font-size: .8rem; }
  .contact__full-pager { gap: 12px; }
  .contact__pager-btn { width: 33px; height: 33px; font-size: 1.05rem; }
}

.kicker {
  text-transform: uppercase;
  letter-spacing: .28em;
  font-size: .72rem;
  font-weight: 700;
  color: var(--accent);
  margin-bottom: .6rem;
}

.title {
  font-family: var(--font-display);
  font-size: clamp(2.6rem, 8vw, 4.4rem);
  line-height: .95;
  font-weight: 400;
  color: var(--paper);
  text-shadow: 0 2px 0 rgba(0,0,0,.25), 0 0 40px var(--accent-2);
}
.title--sm { font-size: clamp(1.9rem, 6vw, 3rem); }

.subtitle {
  margin-top: .8rem;
  font-size: clamp(1rem, 2.4vw, 1.2rem);
  color: color-mix(in srgb, var(--paper) 82%, transparent);
}

/* ===================== PORTRAIT HÉROS (image générée) ===================== */
.hero-art {
  display: block;
  width: min(220px, 52vw);
  aspect-ratio: 1 / 1;
  object-fit: cover;
  object-position: 50% 20%;            /* cadrage sur le visage */
  margin: 0 auto 1.2rem;
  border-radius: var(--radius);
  border: 2px solid var(--accent);
  box-shadow: 0 16px 40px -8px rgba(0,0,0,.6), 0 0 50px -6px var(--accent-2);
}
@media (max-height: 660px) {
  .hero-art { width: min(140px, 32vw); margin-bottom: .8rem; }
}

/* ===================== CONTRÔLES (légende) ===================== */
.controls {
  margin: 2rem auto 1.6rem;
  display: flex;
  flex-direction: column;
  gap: .7rem;
  width: fit-content;
}
.controls__row { display: flex; align-items: center; gap: .5rem; }
.controls__label {
  margin-left: .4rem;
  color: color-mix(in srgb, var(--paper) 72%, transparent);
  font-size: .95rem;
}
.controls__hint {
  margin-top: .8rem;
  font-size: .92rem;
  color: color-mix(in srgb, var(--paper) 72%, transparent);
}
.controls__hint strong { color: var(--orb); }

.key {
  display: inline-grid;
  place-items: center;
  min-width: 2.1rem;
  height: 2.1rem;
  padding: 0 .5rem;
  background: linear-gradient(180deg, #fff, #e4dcef);
  color: #2a1a3e;
  border-radius: 9px;
  border: 1px solid rgba(0,0,0,.15);
  box-shadow: 0 3px 0 rgba(0,0,0,.28), inset 0 1px 0 #fff;
  font-weight: 800;
  font-size: 1rem;
}
.key--sm { min-width: 1.6rem; height: 1.6rem; font-size: .8rem; box-shadow: 0 2px 0 rgba(0,0,0,.28); }

/* ===================== BOUTONS ===================== */
.btn {
  display: inline-block;
  cursor: pointer;
  font-family: var(--font-display);
  font-size: 1.1rem;
  letter-spacing: .02em;
  padding: .85rem 2rem;
  border-radius: 999px;
  border: none;
  transition: transform .12s ease, box-shadow .12s ease, filter .12s ease;
  text-decoration: none;
}
.btn--primary {
  background: linear-gradient(180deg, var(--accent), var(--accent-2));
  color: #2a1033;
  box-shadow: 0 8px 0 rgba(0,0,0,.28), 0 14px 30px -8px var(--accent-2);
}
.btn--primary:hover { transform: translateY(-2px); filter: brightness(1.05); }
.btn--primary:active { transform: translateY(2px); box-shadow: 0 3px 0 rgba(0,0,0,.28); }
.btn--ghost {
  margin-top: 1rem;
  background: transparent;
  color: var(--paper);
  border: 1.5px solid var(--panel-border);
  font-size: .98rem;
  padding: .7rem 1.4rem;
}
.btn--ghost:hover { background: rgba(255,255,255,.08); }

/* ===================== MODAL PROJET — carte à collectionner ===================== */
.overlay--modal { background: rgba(8,4,18,.55); z-index: 40; padding-top: calc(80px + env(safe-area-inset-top, 0px)); }
.modal__backdrop { position: absolute; inset: 0; }
/* carte projet OU écran de fin ouverts : le titre de carte « À suivre… » ne doit pas passer
   par-dessus la pop up (le HUD est en z-index 60, au-dessus des overlays), on le masque. */
body:has(.overlay--modal:not([hidden])) .hud__chapter,
body:has(.overlay--contact:not([hidden])) .hud__chapter { visibility: hidden; }

/* Cadre doré métallisé de la carte */
.modal__card {
  position: relative;
  max-width: 430px;   /* fiche « carte à collectionner » plus grosse (desktop ; sur mobile reste bornée par width:100%) */
  width: 100%;
  padding: 8px;
  border-radius: 18px;
  background: linear-gradient(150deg, #ffe9a8, #d9a23a 42%, #8a5a16);
  box-shadow: var(--shadow), 0 0 50px -14px var(--accent), inset 0 0 0 1px rgba(255,255,255,.45);
  overflow: visible;
  animation: popIn .42s cubic-bezier(.2,1.3,.4,1) both;
}
/* Pastille intérieure sombre où vit le contenu */
.modal__inner {
  position: relative;
  border-radius: 11px;
  padding: 24px 14px;   /* + de padding vertical -> carte un peu plus haute (horizontal inchangé) */
  max-height: calc(100vh - 112px);                                  /* repli sans dvh */
  max-height: calc(100dvh - 112px - env(safe-area-inset-top, 0px)); /* sous le HUD, un peu plus bas + scroll interne */
  overflow-y: auto;
  background: linear-gradient(180deg, #241033, #150a22);
  box-shadow: inset 0 0 0 1px rgba(0,0,0,.45);
}

/* Bouton fermer = jeton doré posé sur le coin */
.modal__close {
  position: absolute; top: -12px; right: -12px; z-index: 6;
  width: 34px; height: 34px; border-radius: 50%;
  border: 2px solid #160a26;
  background: radial-gradient(circle at 35% 30%, #ffe9a8, #d9a23a);
  color: #3a1a00; cursor: pointer; font-size: .8rem; font-weight: 800; line-height: 1;
  box-shadow: 0 4px 10px -2px rgba(0,0,0,.5);
  transition: background .12s, transform .12s;
}
.modal__close:hover { transform: rotate(90deg) scale(1.05); }
/* Anneau de focus cohérent avec le site (foncé sur les jetons dorés, accent sur fond sombre) */
.modal__close:focus-visible,
.btn--card:focus-visible { outline: 2px solid #160a26; outline-offset: 2px; }
.modal__art .carousel__nav:focus-visible,
.modal__art .carousel__dot:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* En-tête : bandeau-nom doré (à gauche) + coût en orbes (à droite) */
.modal__cardtop { display: flex; align-items: stretch; justify-content: space-between; gap: .6rem; margin-bottom: 12px; }
.modal__namebar {
  flex: 1 1 auto; min-width: 0;
  background: linear-gradient(180deg, #ffe27a, #f1b347);
  border-radius: 9px; padding: .4rem .7rem;
  box-shadow: inset 0 -2px 0 rgba(0,0,0,.18);
}
.modal__title { font-family: var(--font-display); font-weight: 600; font-size: 1.3rem; line-height: 1.1; margin: 0; color: #2a1033; overflow-wrap: anywhere; }
.modal__sub { display: flex; align-items: baseline; flex-wrap: wrap; gap: .1rem .55rem; margin: .14rem 0 0; }
.modal__sub:empty { display: none; }
.modal__tag {
  text-transform: uppercase; letter-spacing: .09em;
  font-size: .62rem; font-weight: 800; color: #5a2a00;
}
.modal__tag:empty { display: none; }
.modal__year { font-size: .68rem; color: rgba(42,16,51,.7); }
.modal__year:empty { display: none; }
/* Pastille ronde : logo du projet (au lieu de l'ancien coût en orbes) */
.modal__cost {
  flex: none; align-self: center;
  width: 45px; height: 45px; border-radius: 50%;
  display: grid; place-items: center; overflow: hidden;
  background: radial-gradient(circle at 34% 28%, #ffffff, #eafffb);
  box-shadow: inset 0 0 0 2px rgba(95,224,200,.6), 0 4px 12px -3px rgba(0,0,0,.45), 0 0 20px -6px var(--orb);
}
.modal__cost--gold {
  background: radial-gradient(circle at 34% 28%, #ffffff, #fff3d6);
  box-shadow: inset 0 0 0 2px rgba(255,210,74,.65), 0 4px 12px -3px rgba(0,0,0,.5), 0 0 22px -5px var(--accent);
}
.modal__costlogo { width: 100%; height: 100%; object-fit: contain; padding: 9px; }
.modal__costicon { font-size: 1.5rem; line-height: 1; }

/* Fenêtre d'illustration (carrousel OU vignette logo) + reflet holographique */
.modal__art { position: relative; margin: 0 0 30px; }   /* air entre les captures et la description (+ de hauteur de carte) */
.modal__art .carousel { margin: 0; }
.modal__art .carousel__viewport { border: none; }
.modal__art .carousel__nav, .modal__art .carousel__dots { z-index: 2; }   /* au-dessus du reflet holo */
.modal__artph {
  position: relative;
  aspect-ratio: var(--shot-ratio, 1920 / 911);   /* = ratio des captures ; JS l'ajuste à la 1re image */
  border-radius: 11px;
  overflow: hidden;
  display: grid; place-items: center;
  background:
    radial-gradient(70% 90% at 50% 28%, color-mix(in srgb, var(--orb) 22%, transparent), transparent 70%),
    linear-gradient(160deg, #3a1b4f, #160a26);
  box-shadow: inset 0 0 0 1px rgba(255,226,122,.30);
}
.modal__browserbar {
  position: absolute; top: 0; left: 0; right: 0; height: 20px;
  display: flex; align-items: center; gap: 5px; padding: 0 9px;
  background: rgba(255,255,255,.05);
}
.modal__browserbar i { width: 7px; height: 7px; border-radius: 50%; background: rgba(255,255,255,.30); }
.modal__orb { position: relative; width: 66px; height: 66px; }
.modal__icon {
  width: 66px; height: 66px; border-radius: 50%;
  display: grid; place-items: center; font-size: 1.9rem;
  background: radial-gradient(circle at 34% 28%, #c6fff2, #5fe0c8 46%, #1c8f7e);
  box-shadow: inset 0 0 16px rgba(255,255,255,.5), 0 0 26px -4px var(--orb);
}
.modal__icon--gold {
  background: radial-gradient(circle at 34% 28%, #fff4cf, #ffd24a 46%, #b9821f);
  box-shadow: inset 0 0 16px rgba(255,255,255,.55), 0 0 28px -4px var(--accent);
}
.modal__logo {
  position: absolute; inset: 0;
  width: 66px; height: 66px; object-fit: contain; padding: 10px;
  border-radius: 50%;
  background: radial-gradient(circle at 34% 28%, #ffffff, #fff3d6);
  box-shadow: inset 0 0 0 1px rgba(255,210,74,.5), 0 0 26px -4px var(--accent);
}
/* Reflet holo : ambiant (animé) hors mouvement réduit + glare suivant le curseur */
.modal__sheen {
  position: absolute; top: 0; left: 0; right: 0;
  aspect-ratio: var(--shot-ratio, 1920 / 911);   /* = ratio des captures ; JS l'ajuste à la 1re image */
  border-radius: 11px; overflow: hidden; pointer-events: none;
  mix-blend-mode: screen; opacity: .6;
  background: linear-gradient(115deg, transparent 28%, rgba(255,255,255,.20) 43%, rgba(120,255,230,.28) 50%, rgba(255,150,220,.18) 57%, transparent 72%);
  background-size: 260% 260%;
  animation: holoSheen 5.5s linear infinite;
  z-index: 1;   /* sous les contrôles du carrousel */
}
.modal__sheen::after {
  content: ""; position: absolute; inset: 0;
  background: radial-gradient(120px 120px at var(--gx, 50%) var(--gy, 28%), rgba(255,255,255,.30), transparent 60%);
  opacity: var(--glow, 0); transition: opacity .25s ease;
}
@keyframes holoSheen { 0% { background-position: 130% 0; } 100% { background-position: -130% 0; } }
@media (prefers-reduced-motion: reduce) {
  .modal__sheen { animation: none; background-position: 62% 0; }
}

/* Texte d'ambiance dans un encart (« flavor text » de carte) — hauteur
   limitée, on scrolle à l'intérieur si la description est longue */
.modal__desc {
  text-align: left; font-style: italic;
  font-size: .86rem; line-height: 1.5; margin: 0 0 10px;
  padding: .6rem .7rem; border-radius: 9px;
  background: rgba(255,255,255,.05); border: 1px solid var(--panel-border);
  color: color-mix(in srgb, var(--paper) 84%, transparent); overflow-wrap: anywhere;
  max-height: 7.2em; overflow-y: auto; overscroll-behavior: contain;
  scrollbar-width: thin; scrollbar-color: rgba(255,210,74,.55) transparent;
}
.modal__desc::-webkit-scrollbar { width: 7px; }
.modal__desc::-webkit-scrollbar-track { background: transparent; }
.modal__desc::-webkit-scrollbar-thumb {
  background: rgba(255,210,74,.45); border-radius: 7px;
  border: 1px solid rgba(255,226,122,.25);
}
.modal__desc:hover::-webkit-scrollbar-thumb { background: rgba(255,210,74,.65); }

/* Compétences / technologies */
.modal__stack {
  list-style: none; display: flex; flex-wrap: nowrap; gap: .4rem; margin: 0 0 12px;
  overflow: hidden; max-height: 1.7rem;   /* une seule ligne, le surplus est rogné */
}
.modal__stack:empty { display: none; }
.modal__stack li {
  flex: 0 0 auto; white-space: nowrap;
  font-size: .7rem; font-weight: 600;
  padding: .24rem .55rem; border-radius: 7px;
  background: rgba(255,255,255,.07);
  border: 1px solid var(--panel-border);
  color: color-mix(in srgb, var(--paper) 86%, transparent);
}

/* Forme/effets/couleur : bloc « BOUTONS D'ACTION UNIFIÉS » plus haut.
   Ici uniquement la mise en page : bouton lien pleine largeur dans la pop-up. */
.btn--card { display: block; width: 100%; margin: 0; }

/* Pied de carte : rareté (étoiles) + numéro de collection */
.modal__cardfoot {
  display: flex; align-items: center; justify-content: space-between;
  margin-top: 14px; padding-top: 10px;
  border-top: 1px solid var(--panel-border);
}
.modal__rarity { color: var(--accent); font-size: .95rem; letter-spacing: .14em; filter: drop-shadow(0 1px 0 rgba(0,0,0,.3)); }
.modal__setnum { font-size: .72rem; font-weight: 700; letter-spacing: .1em; color: color-mix(in srgb, var(--paper) 58%, transparent); }

.modal__resume { margin-top: 14px; text-align: center; font-size: .76rem; color: color-mix(in srgb, var(--paper) 55%, transparent); }
.modal__resume .shake-em { color: var(--accent); font-weight: 700; }

/* ===================== CARROUSEL (captures du projet) ===================== */
.carousel { position: relative; margin: 1.2rem 0 .2rem; }
.carousel__viewport {
  position: relative;                             /* ancre les flèches DANS l'image */
  overflow: hidden;
  border-radius: var(--radius-sm);
  border: 1px solid var(--panel-border);
  background: rgba(0,0,0,.28);
  aspect-ratio: var(--shot-ratio, 1920 / 911);   /* = ratio des captures ; JS l'ajuste à la 1re image */
}
.carousel__track { display: flex; height: 100%; transition: transform .42s cubic-bezier(.4,.1,.2,1); }
.carousel__slide {
  flex: 0 0 100%;
  height: 100%;
  display: grid; place-items: center;
}
.carousel__slide img { width: 100%; height: 100%; object-fit: contain; display: block; }
.carousel__slide--broken { background: repeating-linear-gradient(45deg, rgba(255,255,255,.04) 0 10px, transparent 10px 20px); }
.carousel__nav {
  position: absolute; top: 47%; transform: translateY(-50%);   /* un peu au-dessus du centre de l'image */
  width: 38px; height: 38px; border-radius: 50%;
  display: grid; place-items: center;
  border: 1.5px solid rgba(0,0,0,.55);                          /* bordure foncée */
  background: rgba(20,8,26,.78); color: var(--accent);          /* chevron jaune */
  font-size: 1.4rem; line-height: 1; cursor: pointer;
  transition: background .12s, transform .12s, color .12s;
}
.carousel__nav:hover { background: rgba(20,8,26,.94); color: #ffe27a; }
/* nudge optique du chevron dans le rond (box-sizing:border-box -> le rond reste à 38px, seul le glyphe bouge) */
.carousel__nav--prev { left: 8px; padding: 0 2px 2px 0; }   /* ‹ : 1px à gauche + 1px en haut */
.carousel__nav--next { right: 8px; padding: 0 0 2px 2px; }  /* › : 1px à droite + 1px en haut */
/* Points : SUPERPOSÉS en bas des captures (collés à l'image) pour coller la description juste sous le carrousel */
.carousel__dots {
  position: absolute; left: 50%; bottom: 8px; transform: translateX(-50%);
  display: flex; justify-content: center; gap: .4rem;
  z-index: 3;                                      /* au-dessus de l'image */
}
.carousel__dot {
  width: 9px; height: 9px; border-radius: 50%; padding: 0;
  border: 1.5px solid rgba(0,0,0,.6);              /* bordure foncée -> visible sur image claire */
  background: rgba(255,255,255,.9);                /* centre clair -> visible sur image foncée */
  box-shadow: 0 1px 3px rgba(0,0,0,.5);            /* lisibilité sur n'importe quel fond */
  cursor: pointer;
  transition: background .15s, transform .15s, border-color .15s;
}
.carousel__dot.is-active { background: var(--accent); border-color: rgba(0,0,0,.7); transform: scale(1.35); }
/* une seule capture : pas de flèches ni de points */
.carousel--single .carousel__nav,
.carousel--single .carousel__dots { display: none; }

/* Carrousels (carte projet + fiche « Tous mes projets ») : un clic agrandit la capture */
.modal__art .carousel__viewport,
.pdetail__carousel .carousel__viewport { cursor: zoom-in; }

/* ===================== AGRANDISSEMENT (lightbox) =====================
   La capture cliquée passe en grand PAR-DESSUS la carte projet (z-index 70 :
   au-dessus de la modal=40, des projets=45 et du HUD=60). Fond assombri,
   image contenue dans la fenêtre, flèches + compteur + croix. */
.lightbox {
  position: fixed; inset: 0; z-index: 70;
  display: flex; align-items: center; justify-content: center;
  padding: clamp(16px, 4vh, 48px);
  background: radial-gradient(120% 120% at 50% 30%, rgba(20,10,38,.82), rgba(6,3,16,.94));
  backdrop-filter: blur(7px);
  animation: lightboxIn .18s ease-out;
}
.lightbox[hidden] { display: none; }
@keyframes lightboxIn { from { opacity: 0; } to { opacity: 1; } }
.lightbox__stage {
  margin: 0; max-width: 92vw; max-height: 86vh;
  display: grid; place-items: center;
}
.lightbox__img {
  display: block; max-width: 92vw; max-height: 86vh;
  width: auto; height: auto;
  border-radius: var(--radius-sm);
  border: 1px solid rgba(255,226,122,.28);
  box-shadow: 0 24px 70px rgba(0,0,0,.6), 0 0 0 1px rgba(0,0,0,.4);
  background: rgba(0,0,0,.3);
}
.lightbox__close {
  position: absolute; top: clamp(10px, 2.4vh, 22px); right: clamp(10px, 2.4vw, 24px);
  width: 44px; height: 44px; border-radius: 50%;
  display: grid; place-items: center;
  border: 1.5px solid rgba(0,0,0,.55);
  background: rgba(20,8,26,.82); color: var(--accent);
  font-size: 1.25rem; line-height: 1; cursor: pointer;
  transition: background .12s, transform .12s, color .12s;
}
/* survol : on change UNIQUEMENT la couleur/fond, aucun déplacement (pas de scale) */
.lightbox__close:hover { background: rgba(20,8,26,.96); color: #ffe27a; }
.lightbox__nav {
  position: absolute; top: 50%; transform: translateY(-50%);
  width: 52px; height: 52px; border-radius: 50%;
  display: grid; place-items: center;
  border: 1.5px solid rgba(0,0,0,.55);
  background: rgba(20,8,26,.78); color: var(--accent);
  font-size: 2rem; line-height: 1; cursor: pointer;
  transition: background .12s, transform .12s, color .12s;
}
.lightbox__nav:hover { background: rgba(20,8,26,.94); color: #ffe27a; }
.lightbox__nav--prev { left: clamp(8px, 2.5vw, 28px); padding: 0 3px 3px 0; }
.lightbox__nav--next { right: clamp(8px, 2.5vw, 28px); padding: 0 0 3px 3px; }
.lightbox__count {
  position: absolute; left: 50%; bottom: clamp(4px, 1.2vh, 12px); transform: translateX(-50%);
  padding: .28em .8em; border-radius: 999px;
  background: rgba(12,6,22,.7); border: 1px solid var(--panel-border);
  color: rgba(255,255,255,.92); font-size: .9rem; letter-spacing: .03em;
}
/* une seule capture : ni flèches ni compteur */
.lightbox--single .lightbox__nav,
.lightbox--single .lightbox__count { display: none; }
.lightbox__close:focus-visible,
.lightbox__nav:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) {
  .lightbox { animation: none; }
}

/* ===================== CONTACT (fin) : 3 pastilles icône (email · linkedin · github) =====
   Boutons ronds côte à côte, SANS texte, avec une icône de marque ; au survol
   une étiquette animée apparaît pour dire de quel réseau il s'agit. L'intitulé
   (.cl) reste dans le DOM pour les lecteurs d'écran et sert d'étiquette. */
.contact-links { list-style: none; display: flex; flex-direction: row; flex-wrap: wrap; justify-content: center; align-items: center; gap: 16px; margin: 4px 0 12px; padding: 0; }
.contact-links li { margin: 0; }
.contact-links a {
  position: relative;
  display: grid; place-items: center;
  width: 54px; height: 54px; border-radius: 50%; text-decoration: none;
  background: linear-gradient(180deg, rgba(255,250,235,.7), rgba(206,170,110,.34));
  border: 1px solid rgba(138,90,30,.36);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.6), inset 0 -2px 5px rgba(150,100,40,.18), 0 3px 7px rgba(90,55,15,.22);
  transition: box-shadow .14s ease;
}
/* survol : halo doré SANS déplacement (pas de translate/scale -> aspect moins « IA ») */
.contact-links a:hover, .contact-links a:focus-visible {
  box-shadow: inset 0 1px 0 rgba(255,255,255,.75), 0 0 0 2px rgba(224,168,58,.7), 0 8px 16px rgba(255,180,70,.4);
  outline: none;
}
/* l'icône de marque (fichier SVG choisi selon le lien) */
.contact-links a::before {
  content: ""; width: 26px; height: 26px;
  background: center / contain no-repeat;
}
.contact-links a[href^="mailto:"]::before   { background-image: url("assets/ui/icons/email.svg"); }
.contact-links a[href*="linkedin.com"]::before { background-image: url("assets/ui/icons/linkedin.svg"); }
.contact-links a[href*="github.com"]::before { background-image: url("assets/ui/icons/github.svg"); }
/* on masque l'emoji de secours ET la valeur texte (display:none => retirés aussi de
   l'arbre d'accessibilité) : le nom lu par les lecteurs d'écran reste juste .cl
   (« Email » / « LinkedIn » / « GitHub »), et seule l'icône + l'étiquette au survol restent visibles. */
.contact-links .ci, .contact-links .cv { display: none; }
/* étiquette animée (tooltip) AU-DESSUS de la pastille ; le glissement vertical est animé via `bottom`
   pour laisser `transform` servir uniquement à l'ancrage horizontal (centré / aux bords). */
.contact-links .cl {
  position: absolute; bottom: calc(100% + 4px); top: auto; left: 50%;
  transform: translateX(-50%); opacity: 0; pointer-events: none; z-index: 4;
  font-family: var(--font-body); font-weight: 800; font-size: .72rem; letter-spacing: .02em;
  color: #ffe9c8; white-space: nowrap;
  background: linear-gradient(180deg, #3a2008, #28140a);
  padding: .26rem .58rem; border-radius: 8px;
  border: 1px solid rgba(255,210,120,.32);
  box-shadow: 0 6px 14px rgba(0,0,0,.4);
  transition: opacity .16s ease, bottom .16s cubic-bezier(.2,1.2,.4,1);
}
.contact-links .cl::after {   /* flèche sous l'étiquette, pointant vers la pastille */
  content: ""; position: absolute; top: 100%; left: 50%; transform: translateX(-50%);
  border: 5px solid transparent; border-top-color: #3a2008;
}
.contact-links a:hover .cl, .contact-links a:focus-visible .cl { opacity: 1; bottom: calc(100% + 9px); }
/* pastilles de bord (1re = email, dernière = github) : on ANCRE l'étiquette vers l'intérieur
   pour qu'elle ne soit jamais rognée par le bord de la zone de contenu sur petit écran. */
.contact-links li:first-child .cl { left: 0; right: auto; transform: none; }
.contact-links li:first-child .cl::after { left: 27px; right: auto; transform: translateX(-50%); }
.contact-links li:last-child .cl { left: auto; right: 0; transform: none; }
.contact-links li:last-child .cl::after { left: auto; right: 27px; transform: translateX(50%); }

/* écran de fin : on n'affiche QUE le score (pas le détail du calcul), et plus de sous-titre */
.contact__sub { display: none; }
.contact__score-detail { display: none; }

/* ===================== HUD ===================== */
.hud {
  position: fixed; top: 0; left: 0; right: 0; z-index: 60;   /* au-dessus de tous les overlays */
  display: flex; justify-content: space-between; align-items: center;
  padding: max(14px, env(safe-area-inset-top)) clamp(14px, 3vw, 28px) 14px;
  pointer-events: none;
}
.hud[hidden] { display: none; }
.hud__progress {
  pointer-events: auto;
  display: flex; align-items: center; gap: .5rem;
  background: var(--panel); border: 1px solid var(--panel-border);
  padding: .5rem .9rem; border-radius: 999px;
  font-weight: 800; font-size: .95rem;
  box-shadow: 0 8px 24px -10px rgba(0,0,0,.6);
}
.hud__icon { color: var(--orb); }
/* icône image (parchemin peint) du bouton « Mes projets » : suit la hauteur du pill */
.hud__icon--img {
  height: 22px; width: auto; display: block;
  margin: 0 -2px 0 -3px;                       /* recentre le parchemin (marge transparente du PNG) */
  filter: drop-shadow(0 1px 2px rgba(0,0,0,.5));
}
.hud__btn {
  pointer-events: auto;
  width: 42px; height: 42px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--panel-border); background: var(--panel);
  color: var(--paper); cursor: pointer; font-size: 1.1rem;
  transition: filter .12s, transform .12s;
}
.hud__btn:hover { filter: brightness(1.15); }
/* icônes son peintes (assets/ui/volume.png allumé · mute.png coupé) en remplacement des emojis 🔊/🔇/🎵 */
.audio-ic { display: block; width: 22px; height: 22px; object-fit: contain; filter: drop-shadow(0 1px 2px rgba(0,0,0,.45)); }
.audio-panel__mute .audio-ic { width: 20px; height: 20px; }
.cover__sound-ic .audio-ic { width: 30px; height: 30px; filter: none; }

/* ----- popover de réglage du son (clic sur le bouton) ----- */
.hud__audio { position: relative; pointer-events: auto; }
.audio-panel {
  position: absolute; top: calc(100% + 8px); right: 0;
  display: flex; flex-direction: column; gap: 9px;
  padding: 11px 14px;
  background: var(--panel); border: 1px solid var(--panel-border);
  border-radius: 16px;
  box-shadow: 0 12px 30px -10px rgba(0,0,0,.6);
  backdrop-filter: blur(8px) saturate(1.2);
  animation: popIn .18s ease both;
}
.audio-panel[hidden] { display: none; }
/* une ligne = un canal de son (Musique / Bruitages) : icône-toggle + slider */
.audio-row { display: flex; align-items: center; gap: 10px; }
.audio-panel__mute {
  flex: none; width: 30px; height: 30px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--panel-border); background: rgba(255,255,255,.06);
  color: var(--paper); cursor: pointer; font-size: .92rem; line-height: 1;
  transition: background .12s;
}
.audio-panel__mute:hover { background: rgba(255,255,255,.16); }
.audio-panel__slider {
  -webkit-appearance: none; appearance: none;
  width: 118px; height: 6px; border-radius: 999px; margin: 0;
  background: linear-gradient(90deg, var(--accent) var(--vol, 80%), rgba(255,255,255,.18) var(--vol, 80%));
  cursor: pointer; outline: none;
}
.audio-panel__slider::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 16px; height: 16px; border-radius: 50%;
  background: var(--accent); border: 2px solid #2a1033;
  box-shadow: 0 2px 6px rgba(0,0,0,.45); cursor: pointer;
}
.audio-panel__slider::-moz-range-thumb {
  width: 15px; height: 15px; border-radius: 50%;
  background: var(--accent); border: 2px solid #2a1033;
  box-shadow: 0 2px 6px rgba(0,0,0,.45); cursor: pointer;
}
.audio-panel__slider:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

/* ----- boutons d'action du HUD (Projets + Son) ----- */
.hud__actions { display: flex; align-items: center; gap: 10px; pointer-events: auto; margin-left: auto; }
/* bouton « Mes projets » : forme pill, MÊME hauteur (42px) que le bouton son */
.hud__btn--label {
  width: auto; height: 42px; border-radius: 999px;
  padding: 0 1rem;
  display: inline-flex; align-items: center; gap: .5rem;
  font-family: var(--font-body); font-size: .95rem; font-weight: 800;
  box-shadow: 0 8px 24px -10px rgba(0,0,0,.6);
}
.hud__btn--label .hud__btn-txt { white-space: nowrap; }
@media (max-width: 560px) {
  .hud__btn--label { padding: 0; width: 42px; }        /* sur petit écran : icône seule (cercle 42px) */
  .hud__btn--label .hud__btn-txt { display: none; }
  .hud__icon--img { margin: 0 -2px 0 0px; }            /* centrage du logo dans le cercle (icône seule) — Classement + Mes projets */
}

/* ----- groupe gauche du HUD : compteur de projets + score ----- */
.hud__cluster { display: flex; align-items: center; gap: 10px; min-width: 0; }

/* ----- CHRONO : juste à droite du compteur de projets ----- */
.hud__timer {
  pointer-events: auto;
  display: inline-flex; align-items: center; gap: .4rem;
  background: var(--panel); border: 1px solid var(--panel-border);
  padding: .5rem .9rem; border-radius: 999px;
  font-weight: 800; font-size: .95rem; color: var(--paper);
  box-shadow: 0 8px 24px -10px rgba(0,0,0,.6);
  font-variant-numeric: tabular-nums;            /* chiffres de largeur fixe -> pas de tremblement */
}
.hud__timer[hidden] { display: none; }
.hud__icon--timer { color: var(--accent); }
#timerText { min-width: 3.4ch; text-align: right; }

/* ----- TITRE DE CARTE (Lille, Paris…) : à droite du chrono, révélé à chaque entrée.
   Traitement « plaque illuminée » : nom en doré Fraunces + filet doré lumineux + sous-titre
   en petites capitales. Visibilité pilotée en JS (.is-show) -> reste visible même en
   « mouvement réduit » ; la transition n'est qu'un fondu de confort. ----- */
.hud__chapter {
  pointer-events: none;
  display: flex; flex-direction: column; justify-content: center;
  position: relative; min-width: 0;
  margin-left: 6px; padding: 6px 16px 7px 21px;
  /* fond léger frosté -> améliore la lisibilité du nom doré par-dessus le décor */
  background: rgba(18, 9, 28, .42);
  border: 1px solid rgba(255, 233, 200, .12);
  border-radius: 14px;
  backdrop-filter: blur(7px) saturate(1.15);
  -webkit-backdrop-filter: blur(7px) saturate(1.15);
  box-shadow: 0 10px 26px -14px rgba(0,0,0,.55);
  opacity: 0; transform: translateX(-12px);
  transition: opacity .5s ease, transform .55s cubic-bezier(.2,.8,.3,1);
}
.hud__chapter::before {                 /* filet doré lumineux, accent à gauche du panneau */
  content: ""; position: absolute; left: 9px; top: 50%; transform: translateY(-50%);
  width: 2px; height: 30px; border-radius: 2px;
  background: linear-gradient(180deg, transparent, var(--accent) 28%, var(--accent-2) 78%, transparent);
  box-shadow: 0 0 10px -1px var(--accent);
}
.hud__chapter.is-show { opacity: 1; transform: translateX(0); }
.hud__chapter__name {
  font-family: var(--font-display); font-weight: 600;
  font-size: clamp(1.3rem, 2.4vw, 1.75rem); line-height: 1.02; letter-spacing: .004em;
  background: linear-gradient(168deg, #fff6da 0%, var(--accent) 52%, var(--accent-2) 100%);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
  filter: drop-shadow(0 1px 2px rgba(0,0,0,.55)) drop-shadow(0 0 8px rgba(255,170,70,.45));
  white-space: nowrap;
}
.hud__chapter__sub {
  font-family: var(--font-body); font-weight: 700;
  font-size: .64rem; text-transform: uppercase; letter-spacing: .22em;
  color: color-mix(in srgb, var(--accent) 72%, var(--paper));
  margin-top: 3px; white-space: nowrap;
  text-shadow: 0 1px 3px rgba(0,0,0,.55);
  max-width: min(46vw, 480px); overflow: hidden; text-overflow: ellipsis;  /* anti-débordement (sous-titre désert) */
}
.hud__chapter__sub:empty { display: none; }
@media (max-width: 700px) {
  .hud__chapter__sub { display: none; }
  .hud__chapter__name { font-size: 1.15rem; }
  .hud__chapter::before { height: 22px; }
}
/* mobile : le nom de la ville passe SOUS la barre du HUD (à droite du chrono = trop serré).
   Comme il est seul sur sa ligne, on RÉ-AFFICHE le sous-titre (caché en mode inline ≤700px). */
@media (max-width: 560px) {
  .hud__cluster { position: relative; }              /* ancre pour le titre placé en dessous */
  .hud__chapter {
    position: absolute; top: calc(100% + 8px); left: 0;
    margin-left: 0;
  }
  .hud__chapter__sub { display: block; max-width: min(72vw, 320px); }
}
@media (max-width: 560px) {
  .hud__timer { padding: .5rem .7rem; font-size: .85rem; }
}

/* ===================== COLLECTION « cartes à collectionner » (desktop) =====================
   Une case par projet, en bas à droite. Vide = numéro de collection ; pleine = logo du projet.
   À la fermeture d'une fiche attrapée, la carte vole se ranger dans sa case (flyCardToSlot,
   game.js). Masquée en mobile et derrière tout overlay (refreshCollectionVis). */
.collection {
  position: fixed; right: 16px; bottom: 14px; z-index: 50;
  display: flex; flex-wrap: wrap-reverse; justify-content: flex-end; align-content: flex-end;
  gap: 7px; max-width: min(46vw, 520px);
  pointer-events: none; user-select: none;
}
.collection[hidden] { display: none; }
.collslot {
  position: relative; width: 40px; height: 53px; border-radius: 8px;
  background: linear-gradient(160deg, rgba(28,18,40,.5), rgba(14,8,24,.55));
  border: 1.5px solid rgba(255,212,128,.32);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.08), inset 0 0 12px rgba(0,0,0,.4);
  display: grid; place-items: center; overflow: hidden;
  transition: border-color .3s ease, box-shadow .3s ease, background .3s ease;
}
.collslot--gold { border-color: rgba(255,196,86,.42); }
.collslot__num {
  font-family: "Cinzel", var(--font-display); font-weight: 800; font-size: .82rem;
  color: rgba(255,214,140,.42); font-variant-numeric: tabular-nums; transition: opacity .25s ease;
}
.collslot__logo {
  position: absolute; inset: 14%; margin: auto; max-width: 72%; max-height: 72%;
  object-fit: contain; opacity: 0; transform: scale(.55);
  transition: opacity .35s ease, transform .35s cubic-bezier(.2,1.3,.4,1);
  filter: drop-shadow(0 2px 4px rgba(0,0,0,.4));
}
.collslot--filled {
  border-color: rgba(255,206,108,.85);
  background: linear-gradient(160deg, rgba(60,38,16,.62), rgba(34,20,8,.66));
  box-shadow: 0 0 14px rgba(255,190,90,.4), inset 0 1px 0 rgba(255,235,190,.18);
  pointer-events: auto; cursor: pointer;   /* case pleine -> cliquable pour rouvrir la fiche */
}
.collslot--filled:hover {
  border-color: rgba(255,228,150,1);
  box-shadow: 0 0 20px rgba(255,200,100,.6), inset 0 1px 0 rgba(255,235,190,.25);
}
.collslot--filled:focus-visible { outline: 2px solid #ffd24a; outline-offset: 2px; }
.collslot--filled .collslot__num { opacity: 0; }
.collslot--filled .collslot__logo { opacity: 1; transform: scale(1); }
/* petit « pop » doré quand la carte se range */
.collslot--pop { animation: collPop .5s cubic-bezier(.2,1.4,.4,1); }
@keyframes collPop {
  0% { transform: scale(1); }
  35% { transform: scale(1.22); box-shadow: 0 0 22px rgba(255,210,110,.85); }
  100% { transform: scale(1); }
}
/* la carte qui vole de la fiche vers sa case (créée en JS, retirée à la fin de l'anim) */
.collfly {
  position: fixed; z-index: 90; pointer-events: none; border-radius: 9px; overflow: hidden;
  background: linear-gradient(160deg, rgba(60,38,16,.92), rgba(34,20,8,.95));
  border: 1.5px solid rgba(255,206,108,.85);
  box-shadow: 0 10px 30px rgba(0,0,0,.5), 0 0 18px rgba(255,190,90,.5);
  display: grid; place-items: center; will-change: transform, opacity;
}
.collfly img { max-width: 74%; max-height: 74%; object-fit: contain; filter: drop-shadow(0 2px 6px rgba(0,0,0,.45)); }
.collfly__ic { font-size: 1.6rem; color: #ffe2a6; }
@media (max-width: 820px) { .collection { display: none !important; } }

/* ===================== VUE PROJETS (cadre peint) ===================== */
.overlay--projects { background: rgba(8,4,18,.72); z-index: 45; backdrop-filter: blur(6px); }
.projects__backdrop { position: absolute; inset: 0; }
.projects__panel {
  position: relative;
  /* tient toujours dans l'écran : largeur capée, hauteur (= largeur x1.5) <= 88dvh -> pas de scroll externe */
  width: min(440px, 90vw, calc(88dvh / 1.5));
  aspect-ratio: 1024 / 1536;
  filter: drop-shadow(0 30px 44px rgba(0,0,0,.6));
  animation: popIn .32s cubic-bezier(.2,1.2,.4,1) both;
}
.projects__frame { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; user-select: none; }
.projects__frame img { width: 100%; height: 100%; display: block; }
.projects__close {
  position: absolute; top: 13.3%; right: 7%; width: 7.6%; aspect-ratio: 1;
  border-radius: 50%; border: none; background: transparent; cursor: pointer; z-index: 3;
  transition: box-shadow .12s;
}
.projects__close:hover { box-shadow: 0 0 0 2px rgba(255,220,120,.6), 0 0 16px rgba(255,200,90,.6); }
.projects__close:focus-visible { outline: 3px solid #ffd24a; outline-offset: 2px; }
.projects__content {
  position: absolute; left: 16%; right: 16%; top: 20%; bottom: 24%; z-index: 2;
  display: flex; flex-direction: column; text-align: center; color: #46280f;
}
.projects__title { font-family: "Cinzel", var(--font-display); font-weight: 900; font-size: clamp(1.3rem, 5vw, 1.9rem); line-height: 1; color: #46280f; text-shadow: 0 1px 0 rgba(255,255,255,.5); }
.projects__rule { display: flex; align-items: center; justify-content: center; gap: 8px; margin: 5px 0 1px; }
.projects__rule i { height: 2px; width: 40px; background: linear-gradient(90deg, transparent, #b07a32); }
.projects__rule i:last-child { background: linear-gradient(90deg, #b07a32, transparent); }
.projects__rule b { color: #9a6a1e; font-size: .6rem; font-family: var(--font-body); }
.projects__sub { font-family: var(--font-display); font-weight: 600; font-size: .82rem; color: #7a5226; margin-bottom: 9px; }
.projects__list {
  flex: 1; min-height: 0; overflow-y: auto; display: flex; flex-direction: column; gap: 7px; padding: 2px 9px 2px 2px;
  scrollbar-width: thin; scrollbar-color: #b98a3e rgba(120,80,30,.18);
}
.projects__list::-webkit-scrollbar { width: 9px; }
.projects__list::-webkit-scrollbar-track { background: rgba(120,80,30,.16); border-radius: 99px; margin: 2px 0; }
.projects__list::-webkit-scrollbar-thumb { border-radius: 99px; border: 2px solid transparent; background-clip: padding-box; background: linear-gradient(180deg, #e8c27a, #b98a3e); }
.prow {
  display: flex; align-items: center; gap: 10px; width: 100%; text-align: left; cursor: pointer; font: inherit;
  padding: 7px 11px; border-radius: 11px;
  background: linear-gradient(180deg, rgba(255,250,235,.55), rgba(206,170,110,.28));
  border: 1px solid rgba(138,90,30,.30);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.55), inset 0 -2px 4px rgba(150,100,40,.16);
  transition: background .16s ease, border-color .16s ease, box-shadow .16s ease;
}
/* survol : la ligne se réchauffe sur place (lueur de bougie sur le parchemin),
   sans décalage du texte ni anneau flottant -> fusionne avec le décor peint */
.prow:hover {
  background: linear-gradient(180deg, rgba(255,243,202,.96), rgba(244,202,128,.66));
  border-color: rgba(198,142,52,.78);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.88), inset 0 0 22px rgba(255,196,90,.48), 0 5px 14px rgba(120,70,20,.30);
}
.prow:focus-visible { outline: 2px solid #c98a2e; outline-offset: 2px; }
.prow__orb {
  flex: none; width: 38px; height: 38px; display: grid; place-items: center; font-size: 1.1rem;
  background: none; box-shadow: none;
}
.prow--premium .prow__orb { background: none; box-shadow: none; }
/* logo du projet dans la bulle : transparent, sans pastille ni fond, centré et jamais rogné */
.prow__orb img { width: 100%; height: 100%; object-fit: contain; padding: 1px; }
/* PausePump uniquement : logo arrondi dans la liste */
.prow__orb[data-project="pausepump"] img { border-radius: 100%; }
.prow__meta { flex: 1; min-width: 0; }
.prow__title { font-family: var(--font-display); font-weight: 700; font-size: 1rem; line-height: 1.3; color: #43260e; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.prow__tag { font-size: .7rem; color: #86592a; }
.prow__go { flex: none; color: #a8701e; font-weight: 800; font-size: 1.05rem; }

/* deux vues dans le panneau : liste <-> détail projet */
.projects__view { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.projects__view[hidden] { display: none; }
.projects__back {
  align-self: flex-start; background: none; border: none; cursor: pointer; font: inherit;
  font-weight: 700; color: #a8701e; font-size: .82rem; padding: 0 2px 16px;
}
.projects__back:hover { color: #7a4e12; }
.pdetail__scroll {
  flex: 1; min-height: 0; overflow-y: auto; text-align: center; padding-right: 8px;
  scrollbar-width: thin; scrollbar-color: #b98a3e rgba(120,80,30,.18);
}
.pdetail__scroll::-webkit-scrollbar { width: 9px; }
.pdetail__scroll::-webkit-scrollbar-track { background: rgba(120,80,30,.16); border-radius: 99px; }
.pdetail__scroll::-webkit-scrollbar-thumb { border-radius: 99px; border: 2px solid transparent; background-clip: padding-box; background: linear-gradient(180deg, #e8c27a, #b98a3e); }
.pdetail__hero { display: flex; flex-direction: column; align-items: center; gap: 6px; margin-bottom: 12px; }
.pdetail__orb {
  width: 66px; height: 66px; border-radius: 50%; overflow: hidden; display: grid; place-items: center; font-size: 1.95rem;
  background: radial-gradient(circle at 34% 28%, #c6fff2, #5fe0c8 50%, #1c8f7e);
  box-shadow: inset 0 0 12px rgba(255,255,255,.5), 0 3px 6px rgba(120,70,20,.4);
}
.pdetail__orb--gold { background: radial-gradient(circle at 34% 28%, #fff4cf, #ffd24a 50%, #b9821f); }
.pdetail__orb img { width: 100%; height: 100%; object-fit: contain; padding: 9px; background: radial-gradient(circle at 35% 30%, #fff, #fff3d6); }
/* PausePump uniquement : fond sombre derrière le logo */
.pdetail__orb[data-project="pausepump"] img { background: radial-gradient(circle at 35% 30%, #0f1219, #0f1219); }
/* Aedile (dossier "landing") uniquement : fond sombre derrière le logo */
.pdetail__orb[data-project="landing"] img { background: radial-gradient(circle at 35% 30%, #141326, #111026); }
.pdetail__title { font-family: "Cinzel", var(--font-display); font-weight: 700; font-size: 1.45rem; line-height: 1.05; color: #43260e; }
.pdetail__meta { font-size: .68rem; text-transform: uppercase; letter-spacing: .1em; font-weight: 700; color: #a8701e; }
.pdetail__badge { font-size: .64rem; font-weight: 800; letter-spacing: .05em; color: #5a3a00; background: linear-gradient(180deg, #ffe27a, #ffae3d); padding: .2rem .6rem; border-radius: 999px; box-shadow: inset 0 -1px 0 rgba(0,0,0,.15); }
/* Captures de la fiche projet : carrousel (mêmes classes que la carte à collectionner) */
.pdetail__carousel { margin: 0 auto 10px; }
/* (points hérités de .carousel__dot : superposés en bas de l'image, bordure foncée + centre clair) */
.pdetail__desc { font-size: .9rem; line-height: 1.55; color: #5a3a1c; margin: 13px 0 0; padding-top: 13px; border-top: 1px solid rgba(138,90,30,.22); }
.pdetail__stack { list-style: none; display: flex; flex-wrap: wrap; gap: 6px; justify-content: center; margin: 0 0 13px; padding: 0; }
.pdetail__stack li { font-size: .7rem; font-weight: 600; padding: .22rem .6rem; border-radius: 999px; background: rgba(138,90,30,.14); border: 1px solid rgba(138,90,30,.3); color: #7a4e1e; }
/* Forme/effets/couleur : bloc « BOUTONS D'ACTION UNIFIÉS » plus haut.
   Ici uniquement la mise en page : lien centré (display inline-block). */
.pdetail__link { display: inline-block; }
.pdetail__num { margin-top: 12px; font-size: .68rem; font-weight: 700; letter-spacing: .12em; color: #9a6a2a; }

/* ---------- ÉCRAN LARGE (desktop) : cadre PAYSAGE popup-horizontal.png ----------
   Sur écran large la vue projets bascule sur le cadre horizontal (1672x941) :
   elle occupe bien plus de largeur, la LISTE passe en 2 colonnes et la FICHE
   en 2 volets (captures à gauche, texte à droite). Insets = zone parchemin
   mesurée sur l'image ; pastille « fermer » calée sur la pastille rouge peinte. */
@media (min-width: 900px) {
  .projects__panel {
    /* large mais toujours contenu dans l'écran (hauteur = largeur / 1.777) */
    width: min(1320px, 94vw, calc(90dvh * 1672 / 941));
    aspect-ratio: 1672 / 941;
  }
  .projects__close { top: 8%; right: 6.9%; width: 4.8%; }
  .projects__content { left: 13.5%; right: 13%; top: 19.5%; bottom: 19.5%; }   /* top/bottom remontés : le contenu n'est plus rogné en haut/bas */

  /* LISTE : grille 2 colonnes pour remplir la largeur du cadre paysage */
  .projects__list {
    display: grid; grid-template-columns: 1fr 1fr;
    align-content: start; gap: 9px 16px; padding: 2px 10px 2px 2px;
  }

  /* FICHE : la CAPTURE est la vedette -> elle prend TOUTE la largeur et devient
     bien plus grande. En-tête compact sur une ligne au-dessus, puis la capture
     pleine largeur, puis description / technos / lien dessous (scroll si besoin). */
  .pdetail__scroll {
    display: flex; flex-direction: column; text-align: left; padding-right: 10px;
  }
  .pdetail__hero {
    order: 0; flex-direction: row; align-items: center; flex-wrap: wrap;
    gap: 5px 12px; margin-bottom: 10px;
  }
  .pdetail__orb { width: 46px; height: 46px; font-size: 1.35rem; flex: none; }
  .pdetail__title { text-align: left; font-size: 1.4rem; flex: 1 1 auto; min-width: 0; }
  .pdetail__meta { text-align: left; }
  /* capture en PLEINE LARGEUR : le ratio est conservé (var --shot-ratio), donc grande */
  .pdetail__carousel { order: 1; width: 100%; max-width: none; margin: 0 0 14px; }
  .pdetail__desc  { order: 2; text-align: left; margin-top: 0; }
  .pdetail__stack { order: 3; justify-content: flex-start; }
  .pdetail__link  { order: 4; align-self: flex-start; }
  .pdetail__num   { order: 5; }
}

/* ===================== CONTRÔLES TACTILES ===================== */
.touch {
  position: fixed; inset: auto 0 0 0; z-index: 25;
  display: flex; justify-content: space-between; align-items: flex-end;
  padding: 0 max(18px, env(safe-area-inset-left)) max(20px, env(safe-area-inset-bottom)) max(18px, env(safe-area-inset-right));
  pointer-events: none;
}
.touch[hidden] { display: none; }
/* croix directionnelle : ← → à gauche (en ligne), ↑ ↓ à droite (en colonne) */
.touch__pad { display: flex; gap: 16px; align-items: center; }
.touch__pad--right { flex-direction: column; }

/* TOUS les boutons ont le MÊME design — discrets et semi-transparents.
   Taille « pouce » : on suit la largeur de l'écran (≈ 19vw) en restant dans une
   plage confortable (72–88px), bien au-dessus du minimum tactile (48px). */
.touch__btn {
  pointer-events: auto;
  width: clamp(72px, 19vw, 88px); height: clamp(72px, 19vw, 88px); border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  border: 1.5px solid rgba(232,202,128,.5);
  background: rgba(26,16,8,.22);
  color: rgba(247,234,205,.92);
  backdrop-filter: blur(1.5px); -webkit-backdrop-filter: blur(1.5px);
  opacity: .8;
  user-select: none; -webkit-user-select: none; -webkit-tap-highlight-color: transparent;
  touch-action: none; transition: transform .06s ease, background .1s ease, opacity .1s;
}
.touch__btn.is-on, .touch__btn:active {
  transform: scale(.92); opacity: 1;
  background: rgba(232,178,80,.4);
}
/* flèches en SVG : centrées au pixel + même icône pivotée par direction */
.touch__btn svg { width: 48%; height: 48%; display: block; fill: currentColor; filter: drop-shadow(0 1px 2px rgba(0,0,0,.5)); }
.touch__btn[data-act="left"] svg { transform: rotate(180deg); }
.touch__btn[data-act="jump"] svg { transform: rotate(-90deg); }
.touch__btn[data-act="down"] svg { transform: rotate(90deg); }
/* tablettes (vrai grand écran) : on garde des cibles généreuses */
@media (min-width: 1024px) {
  .touch__btn { width: 92px; height: 92px; }
}

/* ===================== PRÉLUDE (mode histoire) ===================== */
.overlay--prelude {
  z-index: 35;
  background:
    radial-gradient(120% 90% at 50% 18%, rgba(255,162,74,.10), transparent 55%),
    radial-gradient(140% 120% at 50% 38%, #241048 0%, #0e0722 55%, #05030e 100%);
  justify-content: safe center;   /* centre sans rogner le haut si trop grand */
  overflow-x: hidden;             /* y : auto (hérité) -> défilement sur écrans courts */
}

/* décor peint plein écran (si l'image manque, l'<img> se retire -> repli sur le dégradé) */
.prelude__bg {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover; object-position: 50% 42%;
  z-index: 0;
  opacity: 0; animation: preludeFade 1.4s ease .05s forwards;
}
/* voile sombre pour garder le texte lisible par-dessus l'image */
.prelude__scrim {
  position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background:
    radial-gradient(120% 95% at 50% 26%, rgba(10,6,24,.28), rgba(7,3,16,.72) 72%),
    linear-gradient(to bottom, rgba(7,3,16,.52), rgba(7,3,16,.30) 38%, rgba(7,3,16,.86));
}

/* poussière féérique : rush filmé en boucle (grains clairs sur fond noir), posé en
   blend additif. Le noir du rush disparaît (screen) -> seuls les grains GLOW sur le
   décor, comme l'ancien semis d'étoiles CSS mais vivant. object-fit:cover -> plein
   cadre quel que soit le ratio d'écran. */
.prelude__dust {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover;
  pointer-events: none; z-index: 2;
  mix-blend-mode: screen;            /* lumière additive : noir transparent, grains lumineux */
  opacity: .30;                        /* grains volontairement discrets (blancs moins présents) */
  /* Fondu d'entrée UNE SEULE FOIS, à l'apparition de l'écran (et non cuit dans la
     vidéo : sinon la boucle re-fondrait à chaque tour = effet « respiration »). La
     vidéo, elle, tourne déjà -> à la fin du fondu les grains sont EN MOUVEMENT, pas
     figés sur la 1re frame. En mouvement réduit, la durée globale .01ms fait juste
     atterrir l'opacité sur .30 d'emblée (visible), aucun fondu -> conforme. */
  animation: dustFadeIn 2.2s ease forwards;
}
/* fondu d'entrée de la poussière : du noir total vers son opacité de croisière */
@keyframes dustFadeIn { from { opacity: 0; } to { opacity: .30; } }

/* lucioles : MONTÉE aléatoire et ample, du BAS de l'écran vers le HAUT, en flux infini.
   - transform (montée verticale + balancier horizontal ample) sur l'élément
   - opacity (scintillement) sur l'élément aussi
   -> deux propriétés disjointes, toutes deux composées GPU, AUCUN repaint = aucun strobe.
   Le balayage vertical (±90vh) est plus grand que l'écran : chaque luciole entre par le
   bas, traverse et ressort par le haut (clip via overflow:hidden), puis reboucle —
   les extrémités étant hors-champ, la reprise de boucle est invisible (flux continu). */
.prelude__lucioles { position: absolute; inset: 0; pointer-events: none; overflow: hidden; z-index: 2; }
.prelude__luciole {
  --s: 1;       /* échelle de profondeur (variée par luciole) */
  --tw: .85;    /* opacité de crête du scintillement (variée par luciole) */
  position: absolute;
  bottom: -6%;                       /* DÉPART juste sous le bas de l'écran */
  width: 11px; height: 11px;         /* grain très fin, comme les étoiles d'orbe */
  /* coeur blanc-chaud minuscule + halo doré qui s'estompe en douceur (étoile-bijou, pas
     pastille plate) : calqué sur la poussière d'orbe -> petit point brillant + lueur chaude */
  background: radial-gradient(circle at 50% 50%,
    #fffdf6 0%,
    rgba(255,243,206,.95) 7%,
    rgba(255,214,128,.5) 22%,
    rgba(255,190,92,.16) 46%,
    transparent 70%);
  border-radius: 50%;
  opacity: var(--tw);
  transform: translateY(0) scale(var(--s));
  mix-blend-mode: screen;            /* lumière additive : les grains GLOW sur le décor sombre (comme drawDust en 'lighter') */
  will-change: transform, opacity;   /* couche GPU stable -> pas de « thrash » de couches */
}
/* ✦ éclat d'étoile à 4 branches (le « glint » signature des étoiles d'orbe), construit
   en pur CSS : deux faisceaux croisés masqués par un dégradé radial -> branches qui
   s'effilent vers la pointe. Un scintillement lent (échelle + légère rotation) le fait
   vivre comme une étoile. `!important` = même exemption volontaire que les lucioles
   (mouvement réduit, cf. le bloc plus bas). Désync via les variables propres à chaque
   luciole (--s, --tw) -> pas de twinkle synchronisé. */
.prelude__luciole::before {
  content: ""; position: absolute; left: 50%; top: 50%;
  width: 260%; height: 260%;
  transform: translate(-50%, -50%);
  background:
    linear-gradient(0deg,  transparent 46%, rgba(255,248,228,.85) 50%, transparent 54%),
    linear-gradient(90deg, transparent 46%, rgba(255,248,228,.85) 50%, transparent 54%);
  -webkit-mask: radial-gradient(closest-side, #000 2%, rgba(0,0,0,.4) 20%, transparent 72%);
          mask: radial-gradient(closest-side, #000 2%, rgba(0,0,0,.4) 20%, transparent 72%);
  pointer-events: none;
  animation: glint 5.5s ease-in-out calc(var(--s) * -3.7s + var(--tw) * -5.3s) infinite !important;
}
/* colonne (left) + profondeur (--s) + vitesse de montée, tous DIFFÉRENTS. La MONTÉE
   (translateY 0 -> -112vh, linear) est le mouvement DOMINANT : chaque luciole part du bas
   et sort par le haut, en boucle. Les délais NÉGATIFS les répartissent d'emblée sur toute
   la hauteur (flux déjà en cours). Le scintillement (twk) reste DISCRET et secondaire. */
/* NB : `!important` ici = EXEMPTION volontaire de la règle globale « mouvement réduit »
   (qui écrase sinon toutes les durées à .01ms et fige les lucioles). Élément déco voulu
   animé même quand prefers-reduced-motion est actif. Voir le bloc reduced-motion plus bas. */
.prelude__luciole:nth-child(1)  { left: 6%;  --s:1;    --tw:.85; animation: riseA 18s   linear -2s   infinite, twk1 4.5s ease-in-out -1s   infinite !important; }
.prelude__luciole:nth-child(2)  { left: 14%; --s:.72;  --tw:.7;  animation: riseB 24s   linear -12s  infinite, twk2 5.5s ease-in-out -2s   infinite !important; }
.prelude__luciole:nth-child(3)  { left: 22%; --s:.9;   --tw:.82; animation: riseC 16s   linear -6s   infinite, twk1 4s   ease-in-out -.5s  infinite !important; }
.prelude__luciole:nth-child(4)  { left: 30%; --s:1.05; --tw:.88; animation: riseD 22s   linear -16s  infinite, twk2 5s   ease-in-out -1.5s infinite !important; }
.prelude__luciole:nth-child(5)  { left: 38%; --s:.68;  --tw:.66; animation: riseA 27s   linear -9s   infinite, twk1 6s   ease-in-out -2.4s infinite !important; }
.prelude__luciole:nth-child(6)  { left: 46%; --s:.95;  --tw:.85; animation: riseB 17s   linear -14s  infinite, twk2 4.5s ease-in-out -.8s  infinite !important; }
.prelude__luciole:nth-child(7)  { left: 54%; --s:.78;  --tw:.72; animation: riseC 23s   linear -3s   infinite, twk1 5.2s ease-in-out -1.9s infinite !important; }
.prelude__luciole:nth-child(8)  { left: 62%; --s:1;    --tw:.86; animation: riseD 15s   linear -7s   infinite, twk2 4.2s ease-in-out -.3s  infinite !important; }
.prelude__luciole:nth-child(9)  { left: 70%; --s:.82;  --tw:.74; animation: riseA 26s   linear -20s  infinite, twk1 5.8s ease-in-out -2.1s infinite !important; }
.prelude__luciole:nth-child(10) { left: 78%; --s:.9;   --tw:.8;  animation: riseB 19s   linear -1s   infinite, twk2 4.8s ease-in-out -1.2s infinite !important; }
.prelude__luciole:nth-child(11) { left: 86%; --s:.72;  --tw:.68; animation: riseC 21s   linear -11s  infinite, twk1 6.2s ease-in-out -2.7s infinite !important; }
.prelude__luciole:nth-child(12) { left: 94%; --s:1.05; --tw:.88; animation: riseD 17.5s linear -5s   infinite, twk2 4.4s ease-in-out -.6s  infinite !important; }
.prelude__luciole:nth-child(13) { left: 10%; --s:.85;  --tw:.8;  animation: riseB 25s   linear -22s  infinite, twk1 5s   ease-in-out -1.4s infinite !important; }
.prelude__luciole:nth-child(14) { left: 34%; --s:.95;  --tw:.84; animation: riseC 16.5s linear -8s   infinite, twk2 4.6s ease-in-out -.9s  infinite !important; }
.prelude__luciole:nth-child(15) { left: 58%; --s:.75;  --tw:.7;  animation: riseD 23.5s linear -17s  infinite, twk1 5.4s ease-in-out -2.2s infinite !important; }
.prelude__luciole:nth-child(16) { left: 82%; --s:1;    --tw:.86; animation: riseA 20s   linear -13s  infinite, twk2 4.1s ease-in-out -1.7s infinite !important; }
/* lot ajouté : grains plus PETITS (--s bas) et plus LENTS -> étoiles lointaines, densifie
   le ciel sans l'encombrer (profondeur). Colonnes choisies pour combler les trous. */
.prelude__luciole:nth-child(17) { left: 18%; --s:.6;  --tw:.64; animation: riseC 28s   linear -4s   infinite, twk1 5.6s ease-in-out -1.1s infinite !important; }
.prelude__luciole:nth-child(18) { left: 42%; --s:.66; --tw:.7;  animation: riseA 30s   linear -15s  infinite, twk2 6.4s ease-in-out -2.6s infinite !important; }
.prelude__luciole:nth-child(19) { left: 66%; --s:.58; --tw:.6;  animation: riseD 26s   linear -9s   infinite, twk1 5s   ease-in-out -.7s  infinite !important; }
.prelude__luciole:nth-child(20) { left: 90%; --s:.64; --tw:.68; animation: riseB 29s   linear -19s  infinite, twk2 6s   ease-in-out -1.8s infinite !important; }
.prelude__luciole:nth-child(21) { left: 2%;  --s:.7;  --tw:.72; animation: riseA 24.5s linear -6s   infinite, twk1 4.8s ease-in-out -2.3s infinite !important; }
.prelude__luciole:nth-child(22) { left: 50%; --s:.56; --tw:.58; animation: riseC 31s   linear -21s  infinite, twk2 6.6s ease-in-out -.4s  infinite !important; }
.prelude__luciole:nth-child(23) { left: 74%; --s:.62; --tw:.66; animation: riseB 27.5s linear -3s   infinite, twk1 5.4s ease-in-out -1.5s infinite !important; }
.prelude__luciole:nth-child(24) { left: 26%; --s:.68; --tw:.7;  animation: riseD 25.5s linear -12s  infinite, twk2 5.8s ease-in-out -2.9s infinite !important; }

/* ✨ effets féériques SUBTILS : juste une lueur douce + un léger scintillement
   (les lucioles restent la vedette ; pas de god rays agressifs) */
.prelude__scrim::after {    /* lueur chaude STATIQUE (aucune animation -> zéro scintillement) */
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(44% 36% at 50% 28%, rgba(255,190,110,.09), transparent 72%);
}
.prelude__inner {
  position: relative; z-index: 3;
  max-width: 800px; width: 100%;   /* aligné sur l'accueil (.cover__inner) pour que le titre tienne sur UNE ligne ; le récit garde sa propre max-width */
  text-align: center;
  padding: clamp(20px, 4vw, 40px);
}
.prelude__inner::before {   /* halo chaud très discret derrière le titre */
  content: ""; position: absolute; left: 50%; top: 12%;
  width: 124%; height: 56%; transform: translateX(-50%);
  background: radial-gradient(50% 50% at 50% 50%, rgba(255,214,128,.05), transparent 70%);
  z-index: -1; pointer-events: none;
}
.prelude__kicker {
  opacity: 0; animation: preludeRise .5s ease .05s forwards;
}
.prelude__title {
  font-size: clamp(2.2rem, 7vw, 3.8rem);
  margin-bottom: clamp(.6rem, 2vh, 1rem);
  text-shadow: 0 2px 0 rgba(0,0,0,.3), 0 0 50px rgba(255,162,74,.55);
  opacity: 0; animation: preludeRise .55s ease .15s forwards;
}
.prelude__sub {
  margin: 0 0 clamp(1.4rem, 4vh, 2.2rem);
  font-size: clamp(.92rem, 2.2vw, 1.1rem);
  color: color-mix(in srgb, var(--accent) 80%, var(--paper));
  letter-spacing: .01em;
  opacity: 0; animation: preludeRise .5s ease .3s forwards;
}
.prelude__story {
  display: flex; flex-direction: column;
  gap: clamp(1.5rem, 4vh, 2.3rem);   /* espace ENTRE les deux blocs */
  margin: 0 auto clamp(1.6rem, 4vh, 2.2rem);
  max-width: 34.5em;   /* +15% : lignes un peu plus larges */
}
/* un bloc = 2 lignes regroupées (interligne serré) */
.prelude__block {
  display: flex; flex-direction: column;
  gap: clamp(.25rem, 1vh, .5rem);
}
.prelude__line {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(1.02rem, 2.5vw, 1.32rem);
  line-height: 1.55;
  color: color-mix(in srgb, var(--paper) 90%, transparent);
  opacity: 0;
  animation: preludeRise .5s ease forwards;
}
/* dernière ligne (CTA) en doré — via classe car les lignes sont dans des blocs */
.prelude__line--cta { color: var(--accent); }

/* ===== Révélation FÉÉRIQUE lettre par lettre (le JS découpe en .char) =====
   Les lettres se matérialisent depuis une poussière dorée floue. */
.prelude__kicker.is-split, .prelude__title.is-split,
.prelude__sub.is-split, .prelude__line.is-split { opacity: 1; animation: none; }
.prelude__inner .word { white-space: nowrap; }   /* empêche la coupure au milieu d'un mot */
.prelude__inner .char {
  display: inline-block;
  opacity: 0;
  animation-name: charFaerie;
  animation-timing-function: cubic-bezier(.2, .7, .3, 1);
  animation-fill-mode: both;       /* durée + délai posés en inline par le JS */
}
@keyframes charFaerie {
  0%   { opacity: 0; transform: translateY(12px) scale(.35) rotate(-8deg); filter: blur(6px);
         text-shadow: 0 0 16px var(--accent), 0 0 30px var(--accent-2); }
  55%  { opacity: 1; transform: translateY(-2px) scale(1.07) rotate(0deg); filter: blur(0);
         text-shadow: 0 0 12px var(--accent); }
  100% { opacity: 1; transform: none; filter: blur(0); text-shadow: inherit; }
}

/* aperçu de l'orbe-projet : montre tout de suite ce qu'on doit récupérer */
.prelude__orbhint {
  display: flex; align-items: center; justify-content: center;
  gap: .9rem;
  margin: 0 auto clamp(1.4rem, 3.5vh, 2rem);
  opacity: 0; animation: preludeRise .5s ease 1.55s forwards;
}
.prelude__orbwrap {
  position: relative; flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
  width: 88px; height: 88px;
}
/* halo doré qui respire derrière l'orbe (fusionne avec le décor féérique).
   `!important` = même EXEMPTION volontaire que les lucioles/glint : sans lui, la règle
   globale `*::before { animation-duration:.01ms !important }` du mode mouvement réduit
   ramène la durée à .01ms et le halo « scintille » ~100 000×/s au lieu de respirer. */
.prelude__orbwrap::before {
  content: ""; position: absolute; inset: -22%;
  border-radius: 50%;
  background: radial-gradient(circle, color-mix(in srgb, var(--accent) 60%, transparent) 0%, transparent 66%);
  animation: orbHalo 3.4s ease-in-out infinite !important;
}
.prelude__orb {
  position: relative;
  width: 100%; height: 100%; object-fit: contain;
  filter: drop-shadow(0 8px 16px rgba(0,0,0,.45));
  /* orbe figée : pas de float/rotation (ça donnait l'impression qu'elle tremblait) */
}
.prelude__orbtxt {
  max-width: 31ch; text-align: left;
  color: color-mix(in srgb, var(--paper) 78%, transparent);
  font-size: .95rem; line-height: 1.35;
}
.prelude__orbtxt strong { color: var(--accent); font-weight: 700; }

@keyframes orbHalo  { 0%, 100% { opacity: .5; transform: scale(.95); } 50% { opacity: .9; transform: scale(1.07); } }

/* Forme/effets/couleur : bloc « BOUTONS D'ACTION UNIFIÉS » plus haut.
   Ici uniquement l'animation d'ENTRÉE propre au prélude. */
.prelude__btn {
  opacity: 0; animation: preludeRise .55s cubic-bezier(.2,1.3,.4,1) 1.65s forwards;
}

@keyframes preludeRise { from { opacity: 0; transform: translateY(16px); } to { opacity: 1; transform: translateY(0); } }
@keyframes preludeFade { from { opacity: 0; } to { opacity: 1; } }

/* =========================================================================
   ÉCRAN D'ACCUEIL (#cover) — montré AVANT le prélude.
   Réutilise le décor peint + étoiles + lucioles du prélude (mêmes classes
   prelude__*) pour fusionner avec l'univers ; ne porte ici que la mise en
   page propre + les 3 boutons (son / projets / jouer).
   ========================================================================= */
.overlay--cover {
  z-index: 38;   /* au-dessus du prélude (35), sous la modal (40) et les projets (45) */
  background:
    radial-gradient(120% 90% at 50% 18%, rgba(255,162,74,.10), transparent 55%),
    radial-gradient(140% 120% at 50% 38%, #241048 0%, #0e0722 55%, #05030e 100%);
  justify-content: safe center;
  overflow-x: hidden;
  animation: none;   /* l'accueil s'affiche DIRECTEMENT (pas de fondu d'entrée) */
}
.cover__inner {
  position: relative; z-index: 3;
  max-width: 800px; width: 100%;
  text-align: center;
  padding: clamp(20px, 4vw, 40px);
}
/* Tout le contenu de l'accueil est affiché DIRECTEMENT : aucune animation
   d'apparition (et donc rien à « dégeler » en mode mouvement réduit). */
.cover__title {
  font-size: clamp(2.2rem, 7vw, 3.8rem);
  margin-bottom: clamp(.6rem, 2vh, 1rem);
  text-shadow: 0 2px 0 rgba(0,0,0,.3), 0 0 50px rgba(255,162,74,.55);
}
.cover__lead {
  margin: 0 auto clamp(1.4rem, 4vh, 2rem); max-width: 34em;
  font-family: var(--font-display); font-weight: 400;
  font-size: clamp(1.02rem, 2.5vw, 1.28rem); line-height: 1.55;
  color: color-mix(in srgb, var(--paper) 90%, transparent);
}
/* gros bouton SON : prévient qu'il y a du son et permet de couper tout de suite */
.cover__sound {
  display: inline-flex; align-items: center; gap: .9rem;
  margin: 0 auto clamp(1.6rem, 4vh, 2.2rem);
  padding: .85rem 1.4rem; border-radius: 18px; cursor: pointer; text-align: left;
  background: rgba(20,12,38,.45);
  border: 1.5px solid color-mix(in srgb, var(--accent) 45%, transparent);
  color: var(--paper);
  backdrop-filter: blur(6px) saturate(1.1);
  box-shadow: 0 10px 30px -12px rgba(0,0,0,.6), inset 0 1px 0 rgba(255,255,255,.06);
  transition: transform .12s ease, box-shadow .12s ease, border-color .12s ease, background .12s ease;
}
.cover__sound:hover { transform: translateY(-2px); border-color: var(--accent); box-shadow: 0 16px 34px -12px rgba(0,0,0,.6), 0 0 30px -10px var(--accent-2); }
.cover__sound:active { transform: translateY(0); }
.cover__sound-ic { font-size: 1.7rem; line-height: 1; filter: drop-shadow(0 0 10px var(--accent-2)); }
.cover__sound-tx { display: flex; flex-direction: column; gap: .12rem; }
.cover__sound-tx b { font-family: var(--font-body); font-weight: 800; font-size: 1.02rem; }
.cover__sound-tx i { font-style: normal; font-size: .82rem; color: color-mix(in srgb, var(--paper) 62%, transparent); }
.cover__sound.is-off { border-color: color-mix(in srgb, var(--paper) 22%, transparent); background: rgba(20,12,38,.32); }
.cover__sound.is-off .cover__sound-ic { filter: none; opacity: .7; }

.cover__actions {
  display: flex; flex-wrap: wrap; justify-content: center; align-items: center;
  gap: .9rem 1.1rem;
}
/* Forme + effets + couleurs de « ▶ Jouer » et « Voir mes projets » : gérés par
   le bloc « BOUTONS D'ACTION UNIFIÉS » plus haut. Ici, rien de spécifique.
   (Le préchargement du décor se fait désormais sur l'écran de chargement #loader,
   plus sur le bouton « Jouer » : voir setupBootLoader() dans game.js.) */

/* ===================== ÉCRAN DE CHARGEMENT (boot, #loader) =====================
   Premier écran : fond NOIR, l'orbe au centre, un anneau doré qui se remplit /
   tourne autour pendant le préchargement. TOUT le mouvement (remplissage de
   l'anneau, étincelle de tête, respiration de l'orbe, fondu de sortie) est piloté
   en JS (rAF / Web Animations) -> insensible à prefers-reduced-motion, sinon figé
   par la règle globale `* { animation-duration:.01ms }`. */
.loader {
  position: fixed; inset: 0; z-index: 100;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 1.15rem; background: #000;
}
.loader[hidden] { display: none; }
.loader__core { position: relative; width: clamp(150px, 33vmin, 230px); aspect-ratio: 1; }
/* cadre doré « loader.png » dévoilé comme une barre de chargement CIRCULAIRE : un
   secteur conique (avancé en JS au rAF) révèle le cadre depuis le HAUT, dans le sens
   horaire, en fonction du %. Départ = secteur nul -> cadre invisible. mask-mode:alpha
   -> opaque = visible. (-webkit-mask par défaut en alpha pour Chrome.) */
.loader__ring-img {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain;
  -webkit-mask-image: conic-gradient(#000 0deg, transparent 0deg);
          mask-image: conic-gradient(#000 0deg, transparent 0deg);
  mask-mode: alpha; will-change: mask-image;
}
.loader__orb {
  position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%);
  width: 48%; height: auto; filter: drop-shadow(0 0 18px rgba(255,200,90,.55));   /* posée dans le trou du cadre */
}
.loader__pct {
  margin: 0; font-family: var(--font-body, sans-serif); font-weight: 700;
  font-variant-numeric: tabular-nums; letter-spacing: .05em;
  color: rgba(255,225,160,.82); font-size: .92rem;
}

/* === Transition accueil -> prélude ======================================
   Un CERCLE plein écran se REFERME vers son centre (clip-path circle animé en
   JS, voir coverToPrelude dans game.js) et masque l'accueil ; à la fin, le
   prélude apparaît et « L'épopée de Steven Dieu » s'écrit. Aucun style dédié
   nécessaire ici (tout est piloté en clip-path inline via la Web Animations API). */

/* écrans courts : compacte l'accueil pour ne jamais couper les boutons */
@media (max-height: 720px) {
  .cover__title { font-size: clamp(1.9rem, 5.5vw, 3rem); margin-bottom: .4rem; }
  .cover__lead { font-size: clamp(.96rem, 2.2vw, 1.16rem); margin-bottom: 1.1rem; }
  .cover__sound { margin-bottom: 1.2rem; padding: .7rem 1.1rem; }
}
/* impulsion AMPLE (pop + rebond) pour les commandes & le bouton Jouer en fin de séquence */
@keyframes preludePop {
  0%   { opacity: 0; transform: translateY(28px) scale(.4); }
  55%  { opacity: 1; transform: translateY(-9px) scale(1.15); }
  78%  { transform: translateY(3px) scale(.97); }
  100% { opacity: 1; transform: translateY(0) scale(1); }
}

/* ✨ MONTÉE des lucioles : translateY va de 0 (départ, bottom:-6% = sous l'écran) à
   -112vh (bien au-dessus du haut) = elles montent du BAS vers le HAUT et sortent.
   X = balancier AMPLE pour un vol aléatoire. scale(var(--s)) garde la profondeur.
   linear -> vitesse de montée constante ; boucle invisible (départ + arrivée hors-champ). */
@keyframes riseA {   /* balancier moyen, plus retenu -> dérive gracieuse */
  0%   { transform: translate(0,     0)     scale(var(--s)); }
  20%  { transform: translate(42px, -22vh)  scale(var(--s)); }
  40%  { transform: translate(-34px,-45vh)  scale(var(--s)); }
  60%  { transform: translate(38px, -67vh)  scale(var(--s)); }
  80%  { transform: translate(-32px,-90vh)  scale(var(--s)); }
  100% { transform: translate(0,    -112vh) scale(var(--s)); }
}
@keyframes riseB {   /* balancier large, 1 vague, assoupli */
  0%   { transform: translate(0,     0)     scale(var(--s)); }
  33%  { transform: translate(-62px,-37vh)  scale(var(--s)); }
  66%  { transform: translate(58px, -75vh)  scale(var(--s)); }
  100% { transform: translate(0,    -112vh) scale(var(--s)); }
}
@keyframes riseC {   /* balancier serré, 2 vagues, assoupli */
  0%   { transform: translate(0,     0)     scale(var(--s)); }
  16%  { transform: translate(34px, -18vh)  scale(var(--s)); }
  33%  { transform: translate(0,    -37vh)  scale(var(--s)); }
  50%  { transform: translate(-38px,-56vh)  scale(var(--s)); }
  66%  { transform: translate(0,    -75vh)  scale(var(--s)); }
  83%  { transform: translate(34px, -93vh)  scale(var(--s)); }
  100% { transform: translate(0,    -112vh) scale(var(--s)); }
}
@keyframes riseD {   /* balancier ample, phase opposée, assoupli */
  0%   { transform: translate(0,     0)     scale(var(--s)); }
  25%  { transform: translate(-52px,-28vh)  scale(var(--s)); }
  50%  { transform: translate(56px, -56vh)  scale(var(--s)); }
  75%  { transform: translate(-48px,-84vh)  scale(var(--s)); }
  100% { transform: translate(0,    -112vh) scale(var(--s)); }
}
/* ✨ SCINTILLEMENT : l'opacité « respire » mais ne s'éteint jamais (mini ≈ 40 % de
   la crête) -> shimmer doux, pas un clignotement dur. twk2 est en opposition de
   phase de twk1 pour varier davantage entre lucioles. */
@keyframes twk1 {
  0%,100% { opacity: var(--tw); }
  50%     { opacity: calc(var(--tw) * .62); }   /* respiration douce (secondaire à la montée) */
}
@keyframes twk2 {
  0%,100% { opacity: calc(var(--tw) * .68); }
  50%     { opacity: var(--tw); }
}
/* ✦ scintillement de l'éclat 4 branches : il « respire » (apparaît, grandit, pivote
   à peine, s'efface) pendant que le coeur+halo restent visibles -> twinkle d'étoile.
   La rotation reste FAIBLE (±8°) pour scintiller sans virer en croix à 8 branches. */
@keyframes glint {
  0%,100% { opacity: .12; transform: translate(-50%,-50%) scale(.5) rotate(-8deg); }
  50%     { opacity: .7;  transform: translate(-50%,-50%) scale(1)  rotate(8deg); }
}

/* mouvement réduit : tout est visible d'emblée, pas de dérive */
@media (prefers-reduced-motion: reduce) {
  /* EXCEPTION lucioles : elles continuent de monter même en mouvement réduit
     (leur animation est en !important plus haut -> elle bat le `* { animation-duration:.01ms }`
     global ci-dessous, qui sinon les figerait). C'est un élément déco voulu animé. */
  .prelude__bg, .prelude__kicker, .prelude__title, .prelude__sub, .prelude__line,
  .prelude__orbhint, .prelude__btn { opacity: 1; animation: none; }
  /* La poussière (.prelude__dust) est une vidéo autoplay/loop : elle tourne même en
     mouvement réduit, comme les lucioles (déco voulue vivante sur l'intro). Son fondu
     d'ENTRÉE reste VOULU même ici (la machine de Steven est en mouvement réduit, et
     c'est justement ce fondu qu'il demande) : un fondu d'OPACITÉ n'est pas du mouvement
     gênant. !important pour battre le `* { animation-duration:.01ms }` global qui
     sinon le réduirait à un saut instantané (= l'apparition brutale qu'on veut éviter). */
  .prelude__dust { animation: dustFadeIn 2.2s ease forwards !important; }
  /* NB : les lettres .char gardent leur animation féérique même en mode réduit
     (effet voulu, piloté en inline !important par le JS) */
}

/* écrans moyens/portables : compacte pour que le bouton ne soit jamais coupé */
@media (max-height: 860px) {
  .prelude__title { font-size: clamp(1.9rem, 5.5vw, 3rem); margin-bottom: .35rem; }
  .prelude__sub { margin-bottom: .9rem; font-size: 1rem; }
  .prelude__story { gap: .45rem; margin-bottom: 1rem; }
  .prelude__line { font-size: clamp(.98rem, 2.2vw, 1.18rem); line-height: 1.4; }
}

/* Mobile : le décor peint du prélude reste FIXÉ et CENTRÉ pendant que le
   texte de l'histoire défile par-dessus (sinon l'image se décolle vers le haut
   au défilement sur les petits écrans). */
@media (hover: none) and (pointer: coarse) {
  .prelude__bg,
  .prelude__scrim,
  .prelude__dust,
  .prelude__lucioles { position: fixed; }
  .prelude__bg { object-position: 50% 50%; }

  /* TENIR EN HAUTEUR sur mobile (pas de scroll dans l'intro) SANS rien retirer :
     on COMPACTE tout pour laisser de l'air au bouton Jouer.
     1) orbe d'aperçu réduite + bloc resserré ;
     2) récit un peu plus serré. */
  .prelude__orbhint           { gap: .65rem; margin: 0 auto clamp(.9rem, 2.5vh, 1.3rem); }
  .prelude__orbwrap           { width: 56px; height: 56px; }
  .prelude__orbtxt            { font-size: .88rem; }
  .prelude__story             { gap: clamp(.9rem, 2.5vh, 1.5rem); margin-bottom: clamp(1rem, 3vh, 1.5rem); }
}

/* écrans courts : intro encore plus compacte */
@media (max-height: 560px) {
  .prelude__title { font-size: clamp(1.8rem, 6vw, 2.6rem); margin-bottom: .4rem; }
  .prelude__sub { margin-bottom: .8rem; font-size: .9rem; }
  .prelude__story { gap: .4rem; margin-bottom: .9rem; }
  .prelude__line { font-size: clamp(.92rem, 2.2vw, 1.1rem); line-height: 1.4; }
}

/* ===================== ANIMATIONS ===================== */
@keyframes overlayIn { from { opacity: 0; } to { opacity: 1; } }
@keyframes popIn { from { opacity: 0; transform: scale(.86) translateY(10px); } to { opacity: 1; transform: scale(1) translateY(0); } }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

/* Affiche les contrôles tactiles uniquement sur appareils tactiles fins */
@media (hover: none) and (pointer: coarse) {
  .controls { display: none; }
}

/* Écrans courts (paysage mobile) : on compacte les overlays */
@media (max-height: 480px) {
  .overlay__inner { padding: 18px 22px; }
  .title { font-size: clamp(2rem, 7vw, 3rem); }
  .subtitle { margin-top: .4rem; font-size: .95rem; }
  .kicker { margin-bottom: .3rem; }
  .controls { margin: 1rem auto .8rem; gap: .4rem; }
  .controls__hint { margin-top: .4rem; }
  .contact-links { margin: 0 0 8px; gap: 12px; }
  .contact-links a { width: 46px; height: 46px; }
  .btn { padding: .7rem 1.6rem; font-size: 1rem; }
}

/* ===================== ÉCRAN DE FIN : score + classement (parchemin) ===================== */
.contact__score { display: flex; align-items: baseline; justify-content: center; gap: .5rem; flex-wrap: wrap; }
.contact__score-label { font-size: .62rem; text-transform: uppercase; letter-spacing: .12em; font-weight: 800; color: #a8701e; }
.contact__score-value { font-family: "Cinzel", var(--font-display); font-weight: 900; font-size: 1.5rem; line-height: 1; color: #b06a12; font-variant-numeric: tabular-nums; white-space: nowrap; word-spacing: .22em; }

.lb-form { margin: 10px 0 0; }
.lb-form[hidden] { display: none; }
.lb-form__row { display: flex; gap: 7px; }
.lb-form__input {
  flex: 1 1 auto; min-width: 0;
  padding: .5rem .7rem; border-radius: 10px; font: inherit; font-weight: 700; color: #43260e;
  background: rgba(255,252,244,.72);
  border: 1px solid rgba(138,90,30,.4);
}
.lb-form__input::placeholder { color: rgba(122,82,38,.55); font-weight: 600; }
.lb-form__input:focus-visible { outline: 2px solid #c98a2e; outline-offset: 1px; }
/* Forme/effets/couleur : bloc « BOUTONS D'ACTION UNIFIÉS » plus haut.
   Ici uniquement la mise en page (flex) et l'état désactivé. */
.lb-form__btn { flex: none; }
.lb-form__btn:disabled { opacity: .7; cursor: default; transform: none; box-shadow: 0 2px 0 var(--btn-sh, #7a3a12); }
.lb-form__hint { margin: 6px 0 0; font-size: .72rem; color: #86592a; min-height: 1em; }

.leaderboard__you { margin: 9px 0 0; font-size: .82rem; font-weight: 800; color: #b06a12; }
.leaderboard__you[hidden] { display: none; }

/* le classement (carte droite) : liste directe sous le titre, masquée si hors-ligne */
.leaderboard { margin: 10px 0 0; text-align: left; }
.leaderboard[hidden] { display: none; }
.leaderboard__list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 4px; }
/* desktop court : on plafonne la liste (scroll interne) pour garder score + formulaire visibles */
@media (min-width: 821px) and (max-height: 700px) {
  .leaderboard__list { max-height: 34vh; overflow-y: auto; padding-right: 4px; scrollbar-width: thin; scrollbar-color: #b98a3e rgba(120,80,30,.18); }
}
.lb-row {
  display: flex; align-items: center; gap: 8px;
  padding: .35rem .6rem; border-radius: 9px; font-size: .8rem;
  background: rgba(255,250,235,.45); border: 1px solid rgba(138,90,30,.2);
}
.lb-row__rank { flex: 0 0 2.2em; font-weight: 800; color: #a8701e; font-variant-numeric: tabular-nums; }
.lb-row__name { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 700; color: #43260e; }
.lb-row__score { flex: none; font-weight: 800; color: #b06a12; font-variant-numeric: tabular-nums; white-space: nowrap; word-spacing: .18em; }
.lb-row--you { background: rgba(255,210,74,.3); border-color: rgba(184,130,30,.6); }
.leaderboard__empty { text-align: center; color: #86592a; font-size: .78rem; padding: .5rem 0; }

