/* ============================================================================
   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--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; }

/* 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; }
/* 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 */
/* accroche « et si le prochain projet était le vôtre ? » MISE EN AVANT : plus grosse */
.contact__card--collab .contact__title { font-size: clamp(1.15rem, 3.6vw, 1.45rem); line-height: 1.16; margin-top: 4px; }
.contact__card--collab .contact__kicker { font-size: .78rem; }

/* 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,
.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,
.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,
.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, valider le pseudo, Rejouer (fin), Visiter le site (projets) */
.contact__bigbtn--play, .cover__play, .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);
}

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

@media (max-height: 660px) {
}


.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;
}

/* ===================== 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--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; }
/* La carte classique n'en montre que QUATRE : au-delà, la ligne unique (nowrap +
   overflow:hidden) trancherait une pastille en deux au bord de la carte. Le mode scène,
   lui, a la place de toutes les afficher et lève cette limite. Elles restent dans le DOM
   dans les deux cas, donc lues en entier par les lecteurs d'écran. */
.modal__stack li:nth-child(n+5) { display: none; }
.modal--pres .modal__stack li:nth-child(n+5) { display: block; }
.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; }

/* ===================== MODE SCÈNE (desktop) : le perso PRÉSENTE son projet =====================
   Classe .modal--pres posée sur #modal par game.js quand la mise en scène canvas joue :
   le perso (AGRANDI) déboule en courant, dérape dans la fumée et POSE sur une ÎLE
   FLOTTANTE peinte, sa réplique s'écrit dans une BULLE peinte (canvas : drawPresVeil /
   drawPresBubble). Ici : la FICHE, posée dans le grand CADRE PEINT généré pour la scène
   (assets/ui/fiche-frame.png : bois sculpté, or, lierre, médaillon ailé au sommet,
   chevrons ‹ › sur les bords, plaque en bas, croix rouge) — d'après la maquette
   assets/objectif.png de Steven. Colonne texte LISIBLE à gauche, capture dans une carte
   BLANCHE à droite. Les éléments interactifs (croix, chevrons, médaillon, plaque) sont
   des recouvrements transparents calés sur les zones PEINTES du cadre.
   L'entrée de la fiche est déclenchée par la scène (WAAPI via presRevealCard) ; tant que
   le perso joue, la fiche est invisible ET inerte. Le mobile garde la carte classique. */
.overlay--modal.modal--pres {
  background: transparent;                 /* l'assombrissement est PEINT sur le canvas */
  align-items: flex-end;                   /* fiche à droite ; la scène du perso reste dégagée à gauche */
  padding-right: min(3vw, 54px);
  padding-bottom: 24px;
  padding-left: 0;                         /* padding-top hérité (80px + safe-area) : jamais sous le HUD */
  overflow: hidden;
}
.modal__frame { display: none; }           /* cadre peint : uniquement en mode scène */
.modal--pres .modal__frame {
  display: block;
  position: absolute; inset: 0; width: 100%; height: 100%;
  pointer-events: none; user-select: none;
  filter: drop-shadow(0 26px 40px rgba(0,0,0,.55));
}
.modal--pres .modal__card {
  max-width: none;
  /* LA SCÈNE PEINTE EST UN OBSTACLE, pas un décor qu'on peut recouvrir. Le canvas se
     dessine dans un repère virtuel de 1280x720 étiré pour COUVRIR la fenêtre, donc son
     facteur d'échelle vaut max(largeur/1280, hauteur/720) : on le recalcule ici en CSS,
     c'est la seule façon de savoir où finit le perso. Le personnage est centré à 17 % de
     la largeur (PRES_STAGE_X) et l'élément le plus large de la scène est son île, 290 px
     virtuels (PRES_ISLE_W), donc la scène s'arrête à 17vw + 145 échelles.
     Sans cette borne, la fiche empiète : à 1600x900 elle recouvrait l'île de 21 px, et à
     1920x1080 il ne restait que 2 px entre les deux. */
  --vs: max(0.078125vw, 0.13888889dvh);          /* = max(100vw / 1280, 100dvh / 720) */
  --scene: calc(17vw + 145 * var(--vs));         /* bord droit de la scène peinte */
  /* large, mais TOUJOURS contenu dans l'écran : borné par la hauteur visible ET par la
     place laissée libre à droite de la scène (18 px d'air, plus la marge de l'overlay) */
  width: min(70vw, 1320px, calc((100dvh - 140px) * 1418 / 896),
             calc(100vw - var(--scene) - 18px - min(3vw, 54px)));
  aspect-ratio: 1418 / 896;
  padding: 0; border-radius: 0;
  background: none; box-shadow: none;
  animation: none;                         /* entrée pilotée en WAAPI quand le perso a posé */
  /* CONTENEUR DE REQUÊTE : tout le mode scène se mesure en cqw, c'est-à-dire en % de la
     LARGEUR DU CADRE. Les vw ne conviennent pas ici : la carte est bornée par la hauteur
     visible (min(70vw, 1320px, hauteur*ratio)), donc sur un écran bas elle rétrécit sans
     que vw bouge, et tout se décalait. En cqw, la fiche est rigoureusement homothétique
     du cadre peint, quel que soit l'écran : 1 cqw = 1 % de 1418 px de référence.
     SEULE la description garde un plancher, max(10px, …) : c'est le seul texte long, et
     sur un portable 1366x768 la carte tombe à 844 px où l'homothétie pure la mettrait à
     8,6 px. Ne PAS en poser sur la colonne de droite : elle ne fait que 34 % de large,
     donc du texte plancher-né y fait passer les puces sur trois rangs et le bandeau
     déborde. Tout le reste est homothétique, donc identique à la maquette validée. */
  container-type: inline-size;
}
/* ENVELOPPE UTILE DU CADRE, mesurée et non plus estimée (tools/zone_sure.py) : un
   remplissage part du centre de fiche-frame.png et s'arrête sur le bois, le lierre, les
   rinceaux, le médaillon et la plaque. L'ouverture réelle va de y 6,92 % à y 92,52 %, et
   les ANGLES sont ce qui l'étrangle : en posant la capture dans la bande médiane on
   récupère de la largeur qu'un simple rectangle inscrit ne voyait pas. D'où ces marges,
   les plus généreuses qui ne mordent nulle part :
       gauche/droite 6,84 %   haut 9 %   bas 8,5 %
   La capture y tient en 1211 x 574 (référentiel 1418 x 896), soit +23 % de hauteur
   d'image contre l'ancienne mise en page, avec encore de quoi loger le bandeau. */
.modal--pres .modal__inner {
  position: absolute; left: 6.84%; right: 6.84%; top: 9%; bottom: 8.5%;
  /* LE RETABLE : la capture est un TABLEAU accroché dans le cadre (passe-partout crème,
     clous d'or), son nom est gravé sur un cartel de bois qui chevauche son bas. Rien ne
     passe donc au-dessus de l'image, qui garde toute sa hauteur ; le bandeau du bas
     s'organise autour du cartel, description à gauche, faits et technos à droite. */
  display: grid;
  grid-template-columns: 1fr 34%;
  grid-template-rows: auto 1fr;
  grid-template-areas: 'art  art'
                       'desc side';
  column-gap: 1.8cqw;
  padding: 0;
  border-radius: 0;
  background: none; box-shadow: none;
  max-height: none;
  /* Le cadre est dimensionné pour que tout tienne (.modal__card est borné par la hauteur
     visible), mais sur un écran COURT — portable 768 px de haut, barre de favoris, zoom
     navigateur, texte long — le contenu peut dépasser. En overflow:hidden il était alors
     COUPÉ sans recours. On défile donc DANS le cadre, avec une fine barre dorée assortie
     au bois, comme la fiche « Mes projets ». overscroll-behavior évite d'entraîner la
     page derrière quand on arrive en bout de course. */
  overflow-y: auto; overflow-x: hidden;
  overscroll-behavior: contain;
  /* Firefox : la même paire de couleurs que ci-dessous, en version plate. */
  scrollbar-width: thin; scrollbar-color: #e9c274 rgba(46, 24, 12, .5);
}
/* PIÈGE, ET IL COÛTE CHER : depuis Chrome 121 la propriété standard scrollbar-color est
   supportée, et dès qu'elle est posée le navigateur dessine la barre STANDARD en
   ignorant TOUS les ::-webkit-scrollbar-*. Tout le soin ci-dessous (jonc doré, gouttière
   cerclée, flèches supprimées) était donc écrit pour rien : on ne voyait que la couleur
   plate de scrollbar-color, avec les petites flèches de Chrome par-dessus le marché.
   On rend donc la main aux pseudo-éléments là où ils existent, et on garde les propriétés
   standard pour Firefox, qui n'a pas les pseudo-éléments et ne sait pas faire mieux. */
@supports selector(::-webkit-scrollbar) {
  .modal--pres .modal__inner { scrollbar-width: auto; scrollbar-color: auto; }
}
/* LA BARRE DE DÉFILEMENT, accordée au cadre : même or que les clous du passe-partout et
   que les filets (#fff3cf -> #e9c274 -> #a3721f), posée dans une gouttière sombre cerclée
   d'un cheveu doré, comme la pastille des points du carrousel. Largeur en cqw pour
   qu'elle respire avec le cadre, avec un plancher : sous ~7 px elle n'est plus attrapable
   à la souris. */
.modal--pres .modal__inner::-webkit-scrollbar { width: max(7px, .62cqw); }
/* pas de petites flèches en bout : elles n'appartiennent à aucun langage du jeu */
.modal--pres .modal__inner::-webkit-scrollbar-button { display: none; height: 0; width: 0; }
.modal--pres .modal__inner::-webkit-scrollbar-track {
  background: rgba(46, 24, 12, .5); border-radius: 99px;
  box-shadow: inset 0 0 0 1px rgba(255, 214, 140, .28);
}
/* Dégradé SIMPLE, dans la hauteur. Un dégradé en largeur aurait donné un jonc tourné,
   mais le fond se cale sur la boîte de remplissage, large de 4 px : il se répétait et
   rayait la barre. À cette largeur, seul le simple tient. */
.modal--pres .modal__inner::-webkit-scrollbar-thumb {
  border-radius: 99px; border: 2px solid transparent; background-clip: padding-box;
  background: linear-gradient(180deg, #f6dfa8, #cf9d3f);
}
.modal--pres .modal__inner::-webkit-scrollbar-thumb:hover {
  background: linear-gradient(180deg, #fff3cf, #e0af52);
}
/* les enfants ne doivent pas se comprimer : sans ça, flex les écrase au lieu de laisser
   le conteneur défiler, et on retombe sur du contenu illisible plutôt que scrollable */
.modal--pres .modal__inner > * { flex-shrink: 0; }
/* croix : recouvrement transparent calé sur la CROIX PEINTE (coin haut droit du cadre) */
.modal--pres .modal__close {
  /* Calé sur la MÉDAILLE PEINTE du coin haut droit. Valeurs relevées à l'écran par
     Steven : mes coordonnées, pourtant mesurées sur fiche-frame.png, laissaient l'anneau
     doré du survol décentré par rapport à la croix. Ne pas les « recalculer ». */
  top: 1.9%; right: 1.2%; width: 4.6%; height: auto; aspect-ratio: 1;
  border: none; border-radius: 50%; background: none; box-shadow: none;
  color: transparent; font-size: 0;
  transition: box-shadow .12s;
}
.modal--pres .modal__close:hover { transform: none; box-shadow: 0 0 0 2px rgba(255,220,120,.6), 0 0 18px rgba(255,200,90,.65); }
.modal--pres .modal__close:focus-visible { outline: 3px solid #ffd24a; outline-offset: 2px; }
/* recouvrements posés SUR le cadre (coordonnées mesurées sur fiche-frame.png, en % de
   la carte) : logo du projet dans le disque crème du médaillon ailé, numéro de
   collection sur la plaque de bois. Hors de la fenêtre défilante -> jamais clippés. */
.modal__navpaint, .modal__medlogo, .modal__plaquenum { display: none; }
.modal--pres .modal__plaquenum {
  display: block;
  /* remonté de 2 px (soit 0,24 % de la hauteur d'un cadre de 1320) pour se poser au
     milieu de la plaque de bois peinte ; en pourcentage, la retouche suit le cadre */
  position: absolute; left: 50%; top: 95.66%;
  transform: translate(-50%, -50%);
  font-family: "Cinzel", var(--font-display);
  font-weight: 800; font-size: clamp(.6rem, .78vw, .8rem); letter-spacing: .2em;
  color: #f3dfae; text-shadow: 0 1px 2px rgba(30,14,4,.8);
  pointer-events: none; white-space: nowrap;
}
/* la pastille logo et le pied « carte à collectionner » restent au mobile : en mode
   scène, leurs infos vivent dans les recouvrements du cadre (médaillon + plaque) */
.modal--pres .modal__cost { display: none; }
.modal--pres .modal__cardfoot { display: none; }
.modal--pres .modal__rarity { display: none; }

/* Bannière « butin » : RETIRÉE du mode scène (demande de Steven) */
.modal__loot { display: none; }
.modal__band { display: contents; }   /* neutre : la carte classique empile comme avant */

/* L'EN-TÊTE DE CARTE N'A PLUS LIEU D'ÊTRE : le nom du projet est gravé sur le CARTEL de
   bois (voir .modal__cartel), donc il ne prend plus une ligne au-dessus de la capture.
   On ne le supprime pas pour autant : il reste dans le flux, invisible mais lisible par
   les lecteurs d'écran, sinon la boîte de dialogue perdrait son nom accessible
   (aria-labelledby="modalTitle"). */
.modal--pres .modal__cardtop {
  position: absolute; left: 0; top: 0; width: 1px; height: 1px; margin: 0; padding: 0;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
}
.modal--pres .modal__namebar { background: none; box-shadow: none; padding: 0; }

/* .modal__band et .modal__side sont NEUTRES ici (display:contents hérité) : leurs enfants
   deviennent directement des cases de la grille de .modal__inner. La carte classique, elle,
   continue de les empiler comme avant, sans rien savoir de tout ceci. */
.modal--pres .modal__desc {
  grid-area: desc;
  /* SANS ceci la grille étire la description sur toute la hauteur de sa rangée, et la
     coupe à 3 lignes ne coupe plus rien : les points de suspension s'affichent bien en
     fin de 3e ligne, mais la 4e reste visible dessous, dans la hauteur étirée. */
  align-self: start;
  /* la carte classique arrondit son encart a 9 px ; ici la description n'est pas un
     encart mais un texte derriere un filet droit, donc on remet l'angle a zero, sinon le
     filet d'or se recourbe en haut et en bas. */
  background: none; border: none; border-radius: 0;
  overflow-wrap: normal;
  /* le texte d'ambiance de la carte classique est en italique de carte à collectionner ;
     ici c'est un vrai paragraphe à lire, donc romaine, comme le reste de la fiche */
  font-style: normal;
  /* Le cartel de bois déborde du tableau de 2,05cqw et vient jusqu'ici : la description
     doit démarrer FRANCHEMENT SOUS lui. À 2,1cqw il ne restait que 0,05cqw de jeu et la
     première ligne se glissait sous la plaque ; 3cqw redonne le dégagement de la maquette
     (0,95cqw). Le décalage à gauche, lui, fait l'asymétrie du bandeau. */
  margin: 3cqw 0 0 2.4cqw;
  padding: 0 0 0 1cqw;
  /* le filet d'or aussi se mesure au cadre : figé à 2 px il s'amincissait visuellement
     dès que la carte grandissait (.17cqw = les 2 px de la maquette sur 1180) */
  border-left: .17cqw solid rgba(255, 198, 108, .6);
  font-size: max(10px, 1.02cqw); line-height: 1.56;
  color: rgba(255,246,228,.93);
  text-shadow: 0 1px 2px rgba(20,8,4,.6);
  text-align: left;
  min-width: 0; max-width: none; max-height: none;
  /* QUATRE lignes : les descriptions réelles de content.js font jusqu'à ~400 signes, et
     trois lignes les tranchaient en plein milieu de phrase. Quatre les tiennent en entier
     sur un grand cadre. Voir plus bas : on redescend à trois quand la carte rétrécit. */
  display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden;
}
/* COLONNE DE DROITE : les faits gravés, les technos, le bouton poussé tout en bas */
.modal__side { display: contents; }
.modal--pres .modal__side {
  grid-area: side;
  display: flex; flex-direction: column; align-items: flex-end;
  gap: .7cqw; padding-top: .9cqw; min-width: 0;
}
.modal__facts { display: none; }
/* UNE seule rangée, un seul espace partout : « RÔLE · valeur · ANNÉE · valeur », tous
   séparés de .9cqw. Le fait est en display:contents pour que son étiquette et sa valeur
   deviennent des éléments de CETTE rangée : sinon l'espace interne au fait s'ajoute à
   l'espace entre les faits, et la ligne se met à respirer de travers. */
.modal--pres .modal__facts { display: flex; align-items: center; gap: .9cqw; flex-wrap: wrap; justify-content: flex-end; }
.modal--pres .modal__fact { display: contents; }
.modal--pres .modal__fact[hidden] { display: none; }
.modal--pres .modal__fact b {
  font-size: .62cqw; font-weight: 800; letter-spacing: .16em; text-transform: uppercase;
  color: rgba(255,236,200,.48);
}
.modal--pres .modal__fact i {
  font-style: normal; font-family: "Fraunces", Georgia, serif;
  font-size: .92cqw; color: #ffe6a8; text-shadow: 0 1px 2px rgba(20,8,4,.7);
}
.modal--pres .modal__stack {
  max-height: none; overflow: visible; flex-wrap: wrap; gap: .34cqw; margin: 0; padding: 0;
  justify-content: flex-end; align-content: flex-start;
}
/* PUCES LAITON GRAVÉ, plus les pastilles blanches plates d'avant : le cadre est un objet
   peint, ce qu'il contient doit être en matière lui aussi. */
.modal--pres .modal__stack li {
  font-size: .74cqw; font-weight: 700;
  /* en cqw, PAS en rem : un rem ne suit pas le cadre, donc la pastille grossissait quand
     la carte rétrécissait et maigrissait quand elle grandissait. Valeurs reprises de la
     maquette (.16rem/.62rem sur une carte de 1180) et converties une fois pour toutes. */
  padding: .217cqw .841cqw; border-radius: 999px;
  background: linear-gradient(180deg, rgba(255,228,168,.24), rgba(150,98,32,.20));
  border: 1px solid rgba(255,214,140,.42);
  box-shadow: inset 0 1px 0 rgba(255,240,205,.32), 0 2px 5px rgba(0,0,0,.4);
  color: #ffeec6;
}
/* LE BOUTON, tombé en bas de colonne : il ferme la lecture.
   Il ne peut PAS garder la forme des boutons du jeu ici. Ceux-ci sont en Cinzel, une
   capitale romaine dont les bas-de-casse sont des petites capitales : « Visiter le site »
   y devient « VISITER LE SITE », deux fois plus long et d'un tout autre poids. Ils ont
   aussi des coins à 14 px et des paddings en rem, donc figés quand le cadre respire.
   On reprend donc le bouton de la maquette : pilule, texte courant, tout en cqw. */
.modal--pres .btn--card {
  position: static; display: inline-block; width: auto;
  font-family: var(--font-body), system-ui, sans-serif;
  /* PLUS GROS que dans la maquette : il ne va plus chercher le bas de la colonne, il se
     range juste sous les puces, dans la foulée de la lecture. Du coup il ne tient plus
     son rôle d'ancre de coin, c'est sa taille qui doit le faire ressortir. */
  font-weight: 800; font-size: 1.12cqw; line-height: normal;
  padding: .68cqw 2.35cqw; margin: .25cqw 0 0; flex: none;
  border: none; border-radius: 999px;
  color: #4a2c00;
  background: linear-gradient(180deg, #ffe27a, #ffb43d);
  box-shadow: 0 .254cqw 0 #b9791d, 0 .508cqw 1.356cqw rgba(0,0,0,.4);
}
.modal--pres .btn--card:hover {
  transform: translateY(-.13cqw);
  box-shadow: 0 .38cqw 0 #b9791d, 0 .7cqw 1.5cqw rgba(0,0,0,.45);
}
.modal--pres .btn--card:active {
  transform: translateY(.2cqw);
  box-shadow: 0 .1cqw 0 #b9791d, 0 .25cqw .8cqw rgba(0,0,0,.4);
}
/* PETITE CARTE (portable 1366x768 : le cadre tombe à ~844 px). Là, les planchers de
   lisibilité ci-dessus rendent la colonne de droite plus haute que son bandeau, et elle
   se met à défiler. On ne rapetisse pas le texte pour autant, on RESSERRE : moins d'air
   entre les blocs, pastilles et bouton plus compacts. Ça rend le double de ce qu'il
   manquait, et la fiche redevient d'un seul tenant. */
/* Tout le reste étant homothétique, il n'y a plus qu'UN réglage qui dépende de la taille :
   la description garde un plancher de lisibilité, donc sur un cadre étroit elle grandit
   par rapport au bandeau. On lui coupe alors une ligne plutôt que de la laisser mordre
   sur le bois du bas. */
@container (max-width: 1080px) {
  .modal--pres .modal__desc { -webkit-line-clamp: 3; }
}
/* Et un cran de plus quand la scène peinte force la fiche à se serrer (fenêtre étroite ou
   très haute : le perso grandit avec la HAUTEUR, la fiche est bornée par la LARGEUR qui
   reste). Sous ~640 px de cadre, le plancher de lisibilité rend la description presque
   deux fois plus haute que son homothétie et elle débordait de 6 à 8 px. */
@container (max-width: 640px) {
  .modal--pres .modal__desc { -webkit-line-clamp: 2; }
}

/* ===== LE TABLEAU : la capture dans son PASSE-PARTOUT crème, cloué aux quatre coins =====
   La capture n'est plus une image posée dans un trou, c'est un tableau accroché dans le
   cadre. Les quatre clous d'or sont PEINTS EN FOND (quatre dégradés radiaux) plutôt que
   posés en DOM : rien à ajouter au balisage, rien à masquer sur mobile. */
.modal--pres .modal__art {
  grid-area: art;
  position: relative;
  width: 100%; margin: 0;
  padding: .46cqw;
  border-radius: 5px;
  background: linear-gradient(178deg, #fff7e9 0%, #f3e2c6 62%, #e6d0ac 100%);
  box-shadow:
    inset 0 0 0 1px rgba(120,80,30,.5),
    0 0 0 1px rgba(255,214,140,.35),
    0 18px 40px rgba(0,0,0,.6);
}
/* Les quatre clous, PAR-DESSUS la capture. En fond ils étaient masqués : le passe-partout
   ne fait que .46cqw de large, donc des clous posés à .62cqw des bords tombaient sous
   l'image. Un seul calque suffit, quatre dégradés radiaux dans un pseudo-élément, donc
   toujours rien à ajouter au balisage. */
.modal--pres .modal__art::after {
  content: ''; position: absolute; inset: 0; z-index: 4; pointer-events: none;
  /* « closest-side » + une dernière teinte TRANSPARENTE : sans elle le dégradé remplit
     toute sa case et le clou sort en CARRÉ, pas en rond. */
  --clou: radial-gradient(circle closest-side,
            #fff3cf 0%, #e9c274 30%, #a3721f 72%, #5e3d0d 94%, rgba(94,61,13,0) 100%);
  --ct: .78cqw;
  background:
    var(--clou) no-repeat left  .62cqw top    .62cqw / var(--ct) var(--ct),
    var(--clou) no-repeat right .62cqw top    .62cqw / var(--ct) var(--ct),
    var(--clou) no-repeat left  .62cqw bottom .62cqw / var(--ct) var(--ct),
    var(--clou) no-repeat right .62cqw bottom .62cqw / var(--ct) var(--ct);
  filter: drop-shadow(0 1px 2px rgba(0,0,0,.55));
}
.modal--pres .modal__art .carousel { margin: 0; }
.modal--pres .modal__art .carousel__viewport {
  border: none; border-radius: 2px;
  background: #fff;
  aspect-ratio: var(--shot-ratio, 1920 / 911);
  box-shadow: 0 0 0 1px rgba(90,60,20,.45);
}
.modal--pres .modal__artph { aspect-ratio: var(--shot-ratio, 1920 / 911); border-radius: 2px; }
.modal--pres .modal__sheen { display: none; }    /* reflet holo = langage « carte » (mobile) */
/* les POINTS du carrousel remontent DANS l'image : collés en bas, ils se cognaient au
   passe-partout et au cartel. Les flèches, elles, restent au centre des captures. */
.modal--pres .modal__art .carousel__dots {
  /* Redescendus, ils arrivent à la hauteur du clou du coin, qu'ils frôlaient à 3 px.
     On les rentre donc un peu pour dégager l'angle du passe-partout. */
  left: auto; right: 2.4cqw; transform: none;
  /* valeur calée à l'écran par Steven */
  bottom: 1.1cqw; gap: .55cqw;
  padding: .28cqw .6cqw; border-radius: 999px;
  /* la pastille sombre de la maquette : sans elle, des gemmes claires posées sur une
     capture de site (blanche neuf fois sur dix) ne se voient tout simplement pas */
  background: rgba(24,10,30,.6);
  box-shadow: inset 0 0 0 1px rgba(255,214,140,.28);
}
.modal--pres .modal__art .carousel__dot {
  width: .62cqw; height: .62cqw; border: none;
  background: rgba(255,240,210,.16);
  box-shadow: inset 0 0 0 1px rgba(255,214,140,.38);
}
.modal--pres .modal__art .carousel__dot.is-active {
  transform: none;
  background: radial-gradient(circle at 34% 30%, #fff6d8, #f0bd57 55%, #a3721f 100%);
  box-shadow: 0 0 .6cqw rgba(255,196,90,.7);
}
.modal--pres .modal__art .carousel__nav {
  width: 2.9cqw; height: 2.9cqw; font-size: 1.7cqw;
  border-color: rgba(60,34,8,.6);
  background: rgba(28,12,34,.74); color: #ffd88a;
}
.modal--pres .modal__art .carousel__nav:hover { background: rgba(28,12,34,.92); color: #fff0be; }
.modal--pres .modal__art .carousel__nav--prev { left: 1.5cqw; }
.modal--pres .modal__art .carousel__nav--next { right: 1.5cqw; }

/* ===== LE CARTEL : plaque de bois gravée, clouée en travers du bas du tableau ===== */
.modal__cartel { display: none; }
.modal--pres .modal__cartel {
  display: flex; flex-direction: column; gap: .1cqw;
  position: absolute; left: 2.4cqw; bottom: -2.05cqw; z-index: 4;
  padding: .6cqw 1.5cqw .62cqw;
  border-radius: 5px;
  pointer-events: none;
  /* bois veiné, biseau clair au sommet, ombre creusée en pied */
  background:
    repeating-linear-gradient(94deg, rgba(0,0,0,.13) 0 2px, rgba(255,220,170,.035) 2px 6px),
    linear-gradient(180deg, #5e3a1b 0%, #40230f 55%, #2a1408 100%);
  border: 1px solid rgba(255,214,140,.32);
  box-shadow:
    inset 0 1px 0 rgba(255,224,170,.30),
    inset 0 -2px 7px rgba(0,0,0,.55),
    0 7px 20px rgba(0,0,0,.5);
}
/* les deux clous qui la tiennent, peints en fond comme ceux du passe-partout */
.modal--pres .modal__cartel::before,
.modal--pres .modal__cartel::after {
  content: ''; position: absolute; top: 50%; width: .78cqw; height: .78cqw;
  transform: translateY(-50%); border-radius: 50%;
  background: radial-gradient(circle at 32% 27%, #fff6d8 0%, #e9c274 42%, #a3721f 78%, #5e3d0d 100%);
  box-shadow: 0 1px 2px rgba(0,0,0,.65), inset 0 -1px 1px rgba(0,0,0,.4);
}
.modal--pres .modal__cartel::before { left: .48cqw; }
.modal--pres .modal__cartel::after  { right: .48cqw; }
.modal--pres .modal__cartelnom {
  font-family: "Cinzel", var(--font-display);
  font-weight: 800; font-size: 2.05cqw; line-height: 1.02;
  padding: 0 1.15cqw; white-space: nowrap;
  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: var(--accent);
  filter: drop-shadow(0 1px 1px rgba(30,14,4,.75));
}
.modal--pres .modal__cartelcat {
  font-size: .68cqw; font-weight: 700; letter-spacing: .18em; text-transform: uppercase;
  color: #7fe4cd; padding: 0 1.15cqw; white-space: nowrap;
  text-shadow: 0 1px 2px rgba(20,8,4,.75);
}
.modal--pres .modal__cartelcat:empty { display: none; }
/* ===================== 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: 50%; transform: translateY(-50%);   /* centre vertical 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; }

/* ===================== 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; }

/* --- HUD pendant la CINÉMATIQUE (.hud--intro) ---------------------------------
   Le film est plein écran : on ne garde de la barre que le réglage du son, pour
   qu'on puisse baisser ou couper la bande-son sans passer le film. « Classement »
   et « Mes projets » n'ont rien à faire là, et la rangée BRUITAGES non plus : c'est
   le canal MUSIQUE qui pilote le volume du film. */
.hud--intro .hud__cluster,
.hud--intro .hud__btn--label,
.hud--intro .audio-row--sfx { display: none !important; }
/* la barre se réduit à son bouton, calé à droite */
.hud--intro { justify-content: flex-end; }
.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; }
}

/* ===================== DÉCOR PEINT DE L'ACCUEIL =====================
   Ces classes `prelude__*` (fond peint + voile + poussière filmée) datent de
   l'ancien écran « prélude », retiré depuis (remplacé par la cinématique #intro).
   Elles servent DÉSORMAIS à l'écran d'accueil #cover, qui les réutilise telles
   quelles : on garde donc les noms pour ne pas casser l'existant. */

/* 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). */
/* ✦ é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é. */
/* 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. */
/* 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. */

/* ✨ 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%);
}
@keyframes preludeFade { from { opacity: 0; } to { opacity: 1; } }

/* =========================================================================
   CINÉMATIQUE D'INTRO (#intro) — remplace l'ancien écran « prélude »
   Le film occupe tout l'écran (fond noir : ses bords et sa dernière image,
   qui est noire, se fondent avec). Il est glissé SOUS l'accueil (z-index 36
   contre 38) : l'iris qui referme l'accueil le dévoile déjà en place.
   ========================================================================= */
.intro {
  position: fixed; inset: 0; z-index: 36;
  background: #000;
  overflow: hidden;
  /* on PASSE le film en gardant le doigt appuyé : ni sélection de texte ni menu
     contextuel iOS ne doivent s'inviter pendant l'appui long. */
  user-select: none; -webkit-user-select: none; -webkit-touch-callout: none;
}
.intro[hidden] { display: none; }
.intro__vid {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;               /* plein cadre, comme le jeu (pas de bandes) */
  background: #000;
  display: block;
  /* L'appui long sert à PASSER le film. S'il atteint la balise <video>, le mobile
     ouvre son menu média natif (« Télécharger la vidéo », « Copier l'image »…).
     On rend donc la vidéo non cliquable : l'appui vise #intro, qui porte l'écoute. */
  pointer-events: none;
  -webkit-touch-callout: none;
  -webkit-user-select: none; user-select: none;
}
/* téléphone tenu à la verticale : on montre l'IMAGE ENTIÈRE plutôt que d'en
   rogner les deux tiers (le conseil d'orientation propose déjà l'horizontale). */
@media (orientation: portrait) {
  .intro__vid { object-fit: contain; }
}

/* --- « Maintiens pour passer » : rappel + jauge circulaire, en bas à droite ---
   Le film se déroule presque tout le temps sur un CIEL CLAIR (bleu franc + gros
   cumulus blancs) : du blanc posé directement dessus disparaît. Le rappel est donc
   monté sur une PASTILLE SOMBRE floutée, teintée prune comme le reste du site, avec
   un filet doré discret : le contenu blanc ressort quel que soit le plan.
   Tout (opacité, remplissage) est piloté en JS au rAF -> insensible au mode
   « mouvement réduit », qui figerait une animation CSS. */
.intro__skip {
  position: absolute; z-index: 2;
  right: max(clamp(14px, 3vw, 34px), env(safe-area-inset-right, 0px));
  bottom: max(clamp(14px, 3vh, 34px), env(safe-area-inset-bottom, 0px));
  display: flex; align-items: center; gap: .7rem;
  padding: .34rem .4rem .34rem 1rem;
  border-radius: 999px;
  background: rgba(12,6,26,.72);
  border: 1px solid color-mix(in srgb, var(--accent) 34%, transparent);
  box-shadow: 0 8px 26px -8px rgba(0,0,0,.9), inset 0 1px 0 rgba(255,255,255,.07);
  backdrop-filter: blur(7px) saturate(1.15);
  opacity: 0;                       /* révélé par le JS dès la 1re image (fondu de 350 ms) */
  pointer-events: none;             /* purement indicatif : on maintient une touche / le doigt */
  transform-origin: 100% 50%;
}
.intro__skiptx {
  font-family: var(--font-body); font-weight: 600;
  font-size: .88rem; letter-spacing: .02em; white-space: nowrap;
  color: #fff;
  text-shadow: 0 1px 3px rgba(0,0,0,.9);
}
/* la touche à maintenir, mise en avant comme un capuchon de clavier */
.intro__skiptx b {
  font-weight: 800; color: var(--accent);
  text-shadow: 0 1px 3px rgba(0,0,0,.95);
}
.intro__gauge { position: relative; display: inline-flex; width: 44px; height: 44px; }
.intro__gsvg { width: 100%; height: 100%; overflow: visible; }
.intro__gbg {
  fill: rgba(0,0,0,.55); stroke: rgba(255,255,255,.34); stroke-width: 3;
}
/* l'arc BLANC qui se remplit : dash piloté en JS (stroke-dashoffset), départ en haut.
   Double ombre : un halo blanc pour la lumière, un liseré noir pour tenir le contraste
   même si la pastille laisse passer un nuage très clair derrière. */
.intro__gfg {
  fill: none; stroke: #fff; stroke-width: 3.4; stroke-linecap: round;
  stroke-dasharray: 125.66;         /* 2πr, r = 20 */
  stroke-dashoffset: 125.66;        /* 0 % au départ */
  transform: rotate(-90deg); transform-origin: 50% 50%;
  filter: drop-shadow(0 0 2px rgba(0,0,0,.85)) drop-shadow(0 0 7px rgba(255,255,255,.8));
}
.intro__gic { fill: #fff; }

/* =========================================================================
   TUTO DE PREMIÈRE PARTIE (#tuto) — rond de lumière sur la 1re orbe
   z-index 24 : au-dessus du canvas, mais SOUS les contrôles tactiles (25) et le
   HUD (60), qui restent donc pleinement lisibles pendant le voile. Le trou du
   voile suit l'orbe image par image (JS, voir tutoTick dans game.js).
   ========================================================================= */
.tuto {
  position: fixed; inset: 0; z-index: 24;
  pointer-events: none;             /* ne bloque JAMAIS le jeu : il suffit de bouger */
}
.tuto[hidden] { display: none; }
/* voile chaud-sombre, percé d'un rond de lumière par un masque radial posé en JS */
.tuto__veil {
  position: absolute; inset: 0;
  background: radial-gradient(120% 120% at 50% 60%, rgba(14,7,30,.60), rgba(6,3,16,.80));
}
/* liseré doré du rond, posé sur le bord du trou (même famille que l'iris du jeu) */
.tuto__ring {
  position: absolute; border-radius: 50%;
  border: 2px solid rgba(255,226,130,.8);
  box-shadow: 0 0 34px 10px rgba(255,200,90,.28), inset 0 0 30px rgba(255,210,74,.22);
}
.tuto__box {
  position: absolute; opacity: 0;   /* placement + apparition pilotés en JS */
  width: min(30rem, calc(100vw - 32px));
  padding: clamp(14px, 2.2vw, 20px) clamp(16px, 2.6vw, 24px);
  text-align: center; border-radius: 18px;
  background: rgba(20,12,38,.80);
  border: 1.5px solid color-mix(in srgb, var(--accent) 48%, transparent);
  box-shadow: 0 18px 44px -14px rgba(0,0,0,.85), inset 0 1px 0 rgba(255,255,255,.07);
  backdrop-filter: blur(7px) saturate(1.15);
}
.tuto__line {
  font-family: var(--font-display); font-weight: 600;
  font-size: clamp(1rem, 2.4vw, 1.22rem); line-height: 1.4;
  color: var(--paper); text-shadow: 0 1px 3px rgba(0,0,0,.7);
}
.tuto__line b { color: var(--accent-2); font-weight: 800; }
.tuto__sub {
  margin-top: .5rem;
  font-size: clamp(.88rem, 2vw, 1rem); line-height: 1.4;
  color: color-mix(in srgb, var(--paper) 80%, transparent);
}
.tuto__sub b { color: var(--accent); font-weight: 700; }
/* rappel de commande, discret : c'est le geste qui referme le tuto */
.tuto__go {
  margin-top: .8rem; font-size: .8rem; letter-spacing: .06em; text-transform: uppercase;
  color: color-mix(in srgb, var(--accent) 76%, var(--paper));
}

/* =========================================================================
   CONSEIL D'ORIENTATION (#rotate) — mobile, purement indicatif
   ========================================================================= */
.rotate {
  position: fixed; inset: 0; z-index: 44;
  display: flex; align-items: center; justify-content: center;
  padding: clamp(18px, 6vw, 40px);
  background: radial-gradient(120% 100% at 50% 40%, rgba(26,12,48,.86), rgba(6,3,14,.94));
  backdrop-filter: blur(7px) saturate(1.1);
}
.rotate[hidden] { display: none; }
.rotate__card {
  max-width: 26rem; width: 100%; text-align: center;
  padding: clamp(22px, 6vw, 32px);
  border-radius: 22px;
  background: rgba(20,12,38,.62);
  border: 1.5px solid color-mix(in srgb, var(--accent) 45%, transparent);
  box-shadow: 0 24px 60px -18px rgba(0,0,0,.75), inset 0 1px 0 rgba(255,255,255,.06);
}
/* Téléphone stylisé (rectangle arrondi + écran) : le JS le fait basculer de la
   verticale à l'horizontale en boucle (WAAPI -> joue aussi en mouvement réduit). */
.rotate__phone {
  display: block; width: 54px; height: 88px; margin: 0 auto clamp(14px, 3vh, 20px);
  border-radius: 11px;
  border: 2.5px solid color-mix(in srgb, var(--accent) 85%, var(--paper));
  background: rgba(255,214,128,.10);
  box-shadow: 0 0 22px -6px var(--accent);
  position: relative;
}
.rotate__phone i {
  position: absolute; inset: 8px 5px;
  border-radius: 4px;
  background: linear-gradient(160deg, rgba(255,214,128,.30), rgba(255,122,61,.16));
}
.rotate__title {
  font-family: var(--font-display); font-weight: 700;
  font-size: clamp(1.3rem, 5.5vw, 1.7rem);
  margin-bottom: .55rem; color: var(--paper);
}
.rotate__lead {
  font-size: .96rem; line-height: 1.5;
  color: color-mix(in srgb, var(--paper) 78%, transparent);
  margin-bottom: clamp(1.1rem, 3vh, 1.5rem);
}
/* bouton discret : le conseil n'impose rien, on peut continuer à la verticale */
.rotate__btn {
  font-family: var(--font-body); font-weight: 600; font-size: .95rem;
  color: color-mix(in srgb, var(--paper) 82%, transparent);
  background: rgba(255,255,255,.06);
  border: 1.5px solid color-mix(in srgb, var(--paper) 26%, transparent);
  border-radius: 999px; padding: .62rem 1.35rem; cursor: pointer;
}
.rotate__btn:hover { border-color: var(--accent); color: var(--paper); }

/* =========================================================================
   É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);
}
/* métier · âge · ville, juste sous le titre (héritée de l'ancien écran « prélude ») */
.cover__ident {
  margin: 0 0 clamp(.9rem, 2.5vh, 1.3rem);
  font-size: clamp(.92rem, 2.2vw, 1.1rem);
  color: color-mix(in srgb, var(--accent) 80%, var(--paper));
  letter-spacing: .01em;
}
.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;
}
/* Précision affichée seulement quand c'est le film d'intro qu'on attend (le plus
   lourd des assets) : sinon l'écran semble bloqué à 90 % sans qu'on sache pourquoi. */
.loader__hint {
  margin: -.5rem 0 0; font-family: var(--font-body, sans-serif);
  color: rgba(255,225,160,.45); font-size: .78rem; letter-spacing: .02em;
}
.loader__hint[hidden] { display: none; }

/* === 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; }
}
/* ✨ 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). */
/* ✨ 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. */
/* ✦ 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. */

/* 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 { 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; }
}

/* Mobile : le décor peint de l'accueil reste FIXÉ et CENTRÉ pendant que le
   contenu 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 { position: fixed; }
  .prelude__bg { object-position: 50% 50%; }
}

/* écrans courts (paysage mobile) : le rappel « passer » se fait tout petit */
@media (max-height: 480px) {
  .intro__skiptx { font-size: .76rem; }
  .intro__gauge { width: 40px; height: 40px; }
}

/* ===================== 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) {
}

/* Écrans courts (paysage mobile) : on compacte les overlays */
@media (max-height: 480px) {
  .title { font-size: clamp(2rem, 7vw, 3rem); }
  .subtitle { margin-top: .4rem; font-size: .95rem; }
  .kicker { margin-bottom: .3rem; }
  .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__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; }

