/* ==========================================================================
   FASTGF — FEUILLE DE STYLE UNIQUE
   --------------------------------------------------------------------------
   IDENTITE. Les couleurs viennent du logo, et de nulle part ailleurs : le
   cristal violet, le G bleu, les lettres blanches biseautees. Un site de
   serveur Minecraft qui reprend la palette de Hypixel ou de Funcraft n'a pas
   d'identite ; celui-ci se reconnait au premier coup d'oeil parce qu'il est
   litteralement fait de la matiere du logo.

   LE RELIEF EST LA CLE. Les lettres du logo sont EXTRUDEES : une face claire,
   une tranche sombre en bas a droite. Toutes les surfaces du site reprennent ce
   biseau (--biseau), et c'est ce qui donne l'aspect "3D Minecraft" sans une
   seule image de texture, donc sans un octet de plus a telecharger.

   SOBRIETE. Fond presque noir, deux accents seulement, beaucoup de vide. Les
   sites de serveurs FR sont satures de degrades et de neon ; celui-ci mise sur
   le contraste et le mouvement. C'est ce qui le fera passer pour "pro".
   ========================================================================== */

/* ==================== JETONS ==================== */

:root {
    /* Fonds — du plus profond au plus clair */
    --noir:        #060510;
    --fond:        #090814;
    --fond-2:      #0D0B1A;
    --surface:     #141127;
    --surface-2:   #1C1832;
    --surface-3:   #262040;

    /* Accents, tires du logo */
    --violet:        #A855F7;
    --violet-clair:  #C9A5FF;
    --violet-fonce:  #6D28D9;
    --violet-nuit:   #3B1D7A;
    --bleu:          #2F7DF6;
    --bleu-clair:    #6FA8FF;
    --or:            #F2B33D;
    --vert:          #34D399;
    --rouge:         #F05B6B;

    /* Texte */
    --texte:       #EFEDF8;
    --texte-doux:  #A8A2C4;
    --texte-faible:#6B6588;

    /* Bordures */
    --bord:        rgba(168, 85, 247, .14);
    --bord-fort:   rgba(168, 85, 247, .34);
    --bord-clair:  rgba(255, 255, 255, .07);

    /* BISEAU : la signature visuelle. Lumiere en haut a gauche, tranche
       sombre en bas a droite — exactement l'extrusion des lettres du logo. */
    --biseau: inset 1px 1px 0 rgba(255,255,255,.10),
              inset -1px -2px 0 rgba(0,0,0,.55);
    --biseau-fort: inset 1.5px 1.5px 0 rgba(255,255,255,.16),
                   inset -2px -3px 0 rgba(0,0,0,.65);

    /* Ombres */
    --ombre-douce: 0 2px 8px rgba(0,0,0,.4);
    --ombre:       0 18px 44px -18px rgba(0,0,0,.85);
    --ombre-haute: 0 40px 90px -30px rgba(0,0,0,.95);
    --lueur:       0 0 0 1px var(--bord-fort), 0 24px 60px -24px rgba(168,85,247,.65);

    /* Rythme */
    --r-s:  8px;
    --r-m:  14px;
    --r-l:  22px;
    --r-xl: 32px;

    /* Courbes. La "douce" est celle d'iOS : elle demarre vite et se pose,
       c'est ce qui fait qu'un mouvement parait pilote et non calcule. */
    --douce:   cubic-bezier(.22, 1, .36, 1);
    --ressort: cubic-bezier(.34, 1.56, .64, 1);
    --net:     cubic-bezier(.4, 0, .2, 1);

    --largeur: 1240px;
    --nav-h: 72px;
}

/* ==================== BASES ==================== */

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

html {
    scroll-behavior: smooth;
    /* La nav est fixe : sans ca, une ancre place le titre dessous. */
    scroll-padding-top: calc(var(--nav-h) + 24px);
    -webkit-text-size-adjust: 100%;
}

body {
    margin: 0;
    background: var(--fond);
    color: var(--texte);
    font-family: 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
    font-size: 16px;
    line-height: 1.65;
    letter-spacing: -.005em;
    overflow-x: hidden;
    -webkit-font-smoothing: antialiased;
}

/* Le fond n'est jamais uni : deux halos fixes, tres larges et tres faibles,
   donnent une profondeur que l'oeil percoit sans pouvoir la nommer. */
body::before {
    content: '';
    position: fixed;
    inset: 0;
    z-index: -2;
    background:
        radial-gradient(60rem 40rem at 12% -8%,  rgba(109,40,217,.26), transparent 62%),
        radial-gradient(52rem 38rem at 92% 12%,  rgba(47,125,246,.16), transparent 60%),
        radial-gradient(70rem 50rem at 50% 118%, rgba(168,85,247,.14), transparent 65%);
    pointer-events: none;
}

/* Grille isometrique tres discrete : le rappel Minecraft, a 3 % d'opacite.
   Au-dela, ca devient un fond d'ecran ; en dessous, ca ne sert a rien. */
body::after {
    content: '';
    position: fixed;
    inset: 0;
    z-index: -1;
    background-image:
        linear-gradient(rgba(168,85,247,.045) 1px, transparent 1px),
        linear-gradient(90deg, rgba(168,85,247,.045) 1px, transparent 1px);
    background-size: 56px 56px;
    mask-image: radial-gradient(90rem 60rem at 50% 0%, #000 20%, transparent 78%);
    -webkit-mask-image: radial-gradient(90rem 60rem at 50% 0%, #000 20%, transparent 78%);
    pointer-events: none;
}

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

::selection { background: rgba(168,85,247,.35); color: #fff; }

/* Barre de defilement assortie : un detail que personne ne remarque, mais
   dont l'absence fait "site pas fini". */
::-webkit-scrollbar { width: 11px; height: 11px; }
::-webkit-scrollbar-track { background: var(--noir); }
::-webkit-scrollbar-thumb {
    background: linear-gradient(var(--violet-fonce), var(--violet-nuit));
    border-radius: 99px;
    border: 3px solid var(--noir);
}
::-webkit-scrollbar-thumb:hover { background: var(--violet); }

/* Accessibilite : un anneau visible au clavier, sur TOUT ce qui se focalise. */
:focus-visible {
    outline: 2px solid var(--violet-clair);
    outline-offset: 3px;
    border-radius: 4px;
}

/* ==================== TYPOGRAPHIE ==================== */

h1, h2, h3, h4, .display {
    font-family: 'Outfit', 'Inter', system-ui, sans-serif;
    font-weight: 800;
    line-height: 1.05;
    letter-spacing: -.035em;
    margin: 0;
}

h1 { font-size: clamp(2.6rem, 7.5vw, 5.4rem); }
h2 { font-size: clamp(1.9rem, 4.4vw, 3.1rem); }
h3 { font-size: clamp(1.15rem, 2.2vw, 1.5rem); letter-spacing: -.02em; }

p { margin: 0 0 1rem; color: var(--texte-doux); }
p:last-child { margin-bottom: 0; }

.eyebrow {
    display: inline-flex;
    align-items: center;
    gap: .55rem;
    font-size: .7rem;
    font-weight: 700;
    letter-spacing: .22em;
    text-transform: uppercase;
    color: var(--violet-clair);
    margin-bottom: 1.1rem;
}
.eyebrow::before {
    content: '';
    width: 26px; height: 2px;
    background: linear-gradient(90deg, var(--violet), transparent);
}

/* Le degrade du logo, applique au texte. Reserve aux mots qui comptent :
   l'utiliser partout le viderait de son sens. */
.grad {
    background: linear-gradient(115deg, var(--violet-clair) 0%, var(--violet) 30%, var(--bleu) 72%, var(--bleu-clair) 100%);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
}

.doux  { color: var(--texte-doux); }
.faible{ color: var(--texte-faible); }
.lead  { font-size: clamp(1.02rem, 1.7vw, 1.2rem); line-height: 1.7; }

/* ==================== MISE EN PAGE ==================== */

.wrap {
    width: min(100% - 2.5rem, var(--largeur));
    margin-inline: auto;
}

.section { padding: clamp(4.5rem, 10vw, 8.5rem) 0; position: relative; }
.section--serre { padding: clamp(3rem, 6vw, 5rem) 0; }

.entete-section { max-width: 62ch; margin-bottom: clamp(2.5rem, 5vw, 4rem); }
.entete-section.centre { margin-inline: auto; text-align: center; }
.entete-section.centre .eyebrow::before { display: none; }
.entete-section p { margin-top: 1.1rem; font-size: 1.05rem; }

.grille { display: grid; gap: 1.25rem; }
.g-2 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr)); }
.g-3 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 290px), 1fr)); }
.g-4 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 230px), 1fr)); }

/* ==================== NAVIGATION ==================== */

.nav {
    position: fixed;
    top: 0; left: 0; right: 0;
    height: var(--nav-h);
    z-index: 100;
    display: flex;
    align-items: center;
    transition: background .4s var(--net), backdrop-filter .4s var(--net),
                border-color .4s var(--net), height .4s var(--net);
    border-bottom: 1px solid transparent;
}
/* Au repos la nav flotte sur le hero ; des le premier defilement elle se
   solidifie. Elle ne masque donc jamais l'image d'accueil. */
.nav.collee {
    height: 62px;
    background: rgba(9, 8, 20, .82);
    backdrop-filter: blur(18px) saturate(150%);
    -webkit-backdrop-filter: blur(18px) saturate(150%);
    border-bottom-color: var(--bord);
}

.nav .wrap { display: flex; align-items: center; gap: 1.5rem; width: min(100% - 2rem, 1400px); }

.marque { display: flex; align-items: center; gap: .7rem; margin-right: auto; }
.marque img {
    width: 40px; height: 40px;
    filter: drop-shadow(0 3px 10px rgba(168,85,247,.55));
    transition: transform .5s var(--ressort);
}
.marque:hover img { transform: rotate(-8deg) scale(1.12); }
.marque span {
    font-family: 'Outfit', sans-serif;
    font-weight: 800;
    font-size: 1.22rem;
    letter-spacing: -.03em;
}

.liens { display: flex; align-items: center; gap: .25rem; }
.liens a {
    position: relative;
    padding: .5rem .85rem;
    font-size: .9rem;
    font-weight: 600;
    color: var(--texte-doux);
    border-radius: var(--r-s);
    transition: color .25s var(--net), background .25s var(--net);
}
.liens a:hover, .liens a.actif { color: var(--texte); background: rgba(168,85,247,.10); }
/* Le trait ne grandit pas depuis la gauche mais depuis le centre : le
   mouvement est symetrique, donc plus calme. */
.liens a::after {
    content: '';
    position: absolute;
    left: 50%; bottom: 2px;
    width: 0; height: 2px;
    background: linear-gradient(90deg, var(--violet), var(--bleu));
    border-radius: 2px;
    transform: translateX(-50%);
    transition: width .35s var(--douce);
}
.liens a:hover::after, .liens a.actif::after { width: 42%; }

.burger {
    display: none;
    width: 42px; height: 42px;
    background: var(--surface);
    border: 1px solid var(--bord);
    border-radius: var(--r-s);
    box-shadow: var(--biseau);
    cursor: pointer;
    padding: 0;
    place-items: center;
}
.burger span {
    display: block;
    width: 18px; height: 2px;
    background: var(--texte);
    border-radius: 2px;
    transition: transform .35s var(--douce), opacity .2s;
}
.burger span + span { margin-top: 4px; }
.burger[aria-expanded="true"] span:nth-child(1) { transform: translateY(6px) rotate(45deg); }
.burger[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.burger[aria-expanded="true"] span:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

/* ==================== BOUTONS ==================== */

.btn {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: .55rem;
    padding: .82rem 1.6rem;
    font-family: 'Outfit', sans-serif;
    font-size: .95rem;
    font-weight: 700;
    letter-spacing: -.01em;
    border: 1px solid var(--bord-fort);
    border-radius: var(--r-m);
    background: var(--surface-2);
    box-shadow: var(--biseau), var(--ombre-douce);
    cursor: pointer;
    overflow: hidden;
    isolation: isolate;
    transition: transform .35s var(--ressort), box-shadow .35s var(--douce),
                border-color .3s, background .3s;
    will-change: transform;
}
.btn:hover { border-color: var(--violet); box-shadow: var(--biseau), var(--lueur); }
.btn:active { filter: brightness(.88); }

.btn--primaire {
    background: linear-gradient(135deg, var(--violet) 0%, var(--violet-fonce) 55%, var(--bleu) 130%);
    border-color: transparent;
    color: #fff;
    box-shadow: var(--biseau-fort), 0 14px 34px -14px rgba(168,85,247,.9);
}
.btn--primaire:hover { box-shadow: var(--biseau-fort), 0 22px 50px -16px rgba(168,85,247,1); }

/* Reflet qui balaie le bouton au survol. Une seule passe, pas une boucle :
   une brillance qui tourne en permanence devient un clignotant. */
.btn--primaire::before {
    content: '';
    position: absolute;
    inset: 0;
    z-index: -1;
    background: linear-gradient(105deg, transparent 35%, rgba(255,255,255,.32) 50%, transparent 65%);
    transform: translateX(-130%);
    transition: transform .75s var(--douce);
}
.btn--primaire:hover::before { transform: translateX(130%); }

.btn--fantome { background: rgba(255,255,255,.03); }
.btn--grand { padding: 1.05rem 2.2rem; font-size: 1.03rem; }
.btn--plein { width: 100%; }

/* ==================== CARTE 3D — LE COEUR DU SITE ====================
   Chaque carte s'incline vers le curseur et allume une lueur exactement
   sous lui. Les deux effets sont pilotes par deux variables posees en JS
   (--mx / --my en pourcentage, --rx / --ry en degres), ce qui evite de
   toucher au style en ligne a chaque mouvement de souris.

   Le relief tient a trois couches superposees :
     1. le biseau, qui donne l'epaisseur,
     2. le halo sous le curseur, qui donne la matiere,
     3. le liseré qui s'allume du cote eclaire, qui donne l'arete.
   ================================================================== */

.carte {
    position: relative;
    padding: 1.9rem;
    background: linear-gradient(160deg, var(--surface) 0%, var(--fond-2) 100%);
    border: 1px solid var(--bord);
    border-radius: var(--r-l);
    box-shadow: var(--biseau), var(--ombre);
    overflow: hidden;
    isolation: isolate;
    transition: transform .5s var(--douce), border-color .4s, box-shadow .5s var(--douce);
}

/* .carte3d ne porte plus l'inclinaison : .bulle le fait desormais pour TOUT
   le site. Il ne reste ici que la profondeur interne — le contenu qui flotte
   au-dessus du fond de la carte. */
.carte3d {
    transform-style: preserve-3d;
}
.carte3d > * { transform: translateZ(28px); }

/* LE HALO SOUS LE CURSEUR. C'est lui que l'oeil lit comme "de la lumiere
   sur une surface", et donc comme du volume. */
.carte::before {
    content: '';
    position: absolute;
    inset: -1px;
    z-index: -1;
    border-radius: inherit;
    background: radial-gradient(
        22rem 22rem at var(--mx, 50%) var(--my, 50%),
        rgba(168,85,247,.28), rgba(47,125,246,.10) 42%, transparent 68%);
    opacity: 0;
    transition: opacity .45s var(--net);
}
.carte:hover::before { opacity: 1; }

/* L'arete eclairee : un trait fin qui suit le curseur sur le bord. */
.carte::after {
    content: '';
    position: absolute;
    inset: 0;
    z-index: -1;
    border-radius: inherit;
    padding: 1px;
    background: radial-gradient(
        14rem 14rem at var(--mx, 50%) var(--my, 50%),
        rgba(201,165,255,.85), transparent 60%);
    -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
    -webkit-mask-composite: xor;
            mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
            mask-composite: exclude;
    opacity: 0;
    transition: opacity .45s var(--net);
}
.carte:hover::after { opacity: 1; }

.carte:hover { border-color: var(--bord-fort); box-shadow: var(--biseau-fort), var(--ombre-haute); }

/* ==================== MODES DE JEU ==================== */

.modes { display: grid; gap: 1.15rem; }

.mode {
    --teinte: var(--violet);
    position: relative;
    display: grid;
    grid-template-columns: auto auto 1fr auto;
    align-items: center;
    gap: 1.5rem;
    padding: 1.5rem 1.8rem;
    background: linear-gradient(150deg, var(--surface) 0%, var(--fond-2) 92%);
    border: 1px solid var(--bord);
    border-radius: var(--r-l);
    box-shadow: var(--biseau), var(--ombre);
    cursor: pointer;
    overflow: hidden;
    isolation: isolate;
    text-align: left;
    width: 100%;
    transition: transform .5s var(--douce), border-color .4s, box-shadow .5s var(--douce);
}
.mode::before {
    content: '';
    position: absolute;
    inset: -1px;
    z-index: -1;
    border-radius: inherit;
    background: radial-gradient(26rem 20rem at var(--mx, 50%) var(--my, 50%),
                color-mix(in srgb, var(--teinte) 30%, transparent), transparent 64%);
    opacity: 0;
    transition: opacity .45s var(--net);
}
.mode:hover::before, .mode.ouvert::before { opacity: 1; }
.mode:hover { border-color: color-mix(in srgb, var(--teinte) 45%, transparent); }
.mode.ouvert {
    border-color: color-mix(in srgb, var(--teinte) 50%, transparent);
    /* Ouvert, l'en-tete et le panneau ne font plus qu'un bloc : on aplatit
       les coins du bas, sinon un liseré arrondi coupe la carte en deux et
       le panneau parait flotter en dessous. */
    border-bottom-left-radius: 0;
    border-bottom-right-radius: 0;
    border-bottom-color: transparent;
}
/* Et surtout : la carte ne se souleve plus une fois ouverte. Un panneau
   ancre a un en-tete qui recule de 4 px laisse un trou visible entre les
   deux. */
.mode.ouvert:hover { border-color: color-mix(in srgb, var(--teinte) 50%, transparent); }

/* Le rang, en gros chiffre fantome. Il donne l'ordre voulu — Manhunt,
   FastPvp, RushFFA, TeamSpell — sans avoir a l'ecrire. */
.mode__rang {
    font-family: 'Outfit', sans-serif;
    font-size: 2.4rem;
    font-weight: 800;
    line-height: 1;
    color: transparent;
    -webkit-text-stroke: 1.5px color-mix(in srgb, var(--teinte) 55%, transparent);
    transition: -webkit-text-stroke-color .4s, transform .5s var(--ressort);
}
.mode:hover .mode__rang { transform: scale(1.1) translateX(2px); }

/* L'ICONE. Elle flotte en permanence, tres lentement ; au survol elle se
   redresse, grossit et prend la lumiere. C'est le "logo qui s'anime" :
   l'animation dit "ce bloc est vivant", pas "regardez-moi". */
.mode__icone {
    width: 72px; height: 72px;
    display: grid;
    place-items: center;
    border-radius: var(--r-m);
    background: linear-gradient(150deg,
        color-mix(in srgb, var(--teinte) 22%, var(--surface-2)),
        var(--fond-2));
    border: 1px solid color-mix(in srgb, var(--teinte) 30%, transparent);
    box-shadow: var(--biseau);
    flex-shrink: 0;
    animation: flotte 6s ease-in-out infinite;
    transition: transform .55s var(--ressort), box-shadow .5s, border-color .4s;
}
.mode__icone svg { width: 40px; height: 40px; }
.mode:hover .mode__icone {
    transform: rotate(-6deg) scale(1.1);
    translate: 0 -6px;
    border-color: var(--teinte);
    box-shadow: var(--biseau-fort), 0 16px 34px -12px color-mix(in srgb, var(--teinte) 80%, transparent);
}

/* LE FLOTTEMENT PASSE PAR `translate`, PAS PAR `transform`, ET C'EST LA
   RAISON POUR LAQUELLE IL FONCTIONNE.
   Une animation @keyframes qui ecrit `transform` gagne toujours contre une
   regle :hover qui ecrit `transform` — la valeur animee ecrase la valeur
   calculee. L'icone flottait donc, mais ne reagissait plus du tout au survol.
   `translate` est une propriete distincte, composee par le navigateur AVEC
   `transform` : les deux effets s'additionnent au lieu de se disputer. */
@keyframes flotte {
    0%, 100% { translate: 0 0; }
    50%      { translate: 0 -7px; }
}

.mode__titre {
    display: flex;
    align-items: center;
    gap: .7rem;
    flex-wrap: wrap;
    font-family: 'Outfit', sans-serif;
    font-size: clamp(1.2rem, 2.5vw, 1.55rem);
    font-weight: 800;
    letter-spacing: -.03em;
    margin: 0 0 .3rem;
}
.mode__titre, .mode__accroche, .mode__corps { display: block; }
.mode__accroche { color: var(--texte-doux); font-size: .95rem; margin: 0; }

/* L'etiquette d'etat. "OUVERT" en vert se lit avant le nom du mode : c'est
   la premiere question que se pose un visiteur devant une liste de modes. */
.etat {
    padding: .18rem .55rem;
    font-family: 'Inter', sans-serif;
    font-size: .64rem;
    font-weight: 800;
    letter-spacing: .12em;
    border-radius: 5px;
    white-space: nowrap;
}
.etat--ouvert { color: var(--vert);        background: rgba(52,211,153,.14); }
.etat--beta   { color: var(--violet-clair);background: rgba(168,85,247,.16); }
.etat--bientot{ color: var(--or);          background: rgba(242,179,61,.13); }

.mode__fleche {
    width: 38px; height: 38px;
    display: grid; place-items: center;
    border-radius: 50%;
    background: rgba(255,255,255,.04);
    border: 1px solid var(--bord);
    color: var(--texte-doux);
    transition: transform .45s var(--ressort), background .3s, color .3s;
}
.mode:hover .mode__fleche { background: var(--teinte); color: #fff; transform: scale(1.12); }
.mode.ouvert .mode__fleche { transform: rotate(180deg); background: var(--teinte); color: #fff; }

/* Le panneau qui se deplie. La hauteur est animee par grid-template-rows :
   c'est la seule facon d'animer "auto" sans mesurer en JS, donc sans saut
   quand le texte change de longueur ou que la fenetre est redimensionnee. */
.mode__detail {
    display: grid;
    grid-template-rows: 0fr;
    transition: grid-template-rows .55s var(--douce), opacity .4s var(--net);
    opacity: 0;
}
.mode__detail.ouvert { grid-template-rows: 1fr; opacity: 1; }
.mode__detail > div { overflow: hidden; }
.mode__detail-inner {
    display: grid;
    grid-template-columns: 1.25fr .95fr;
    gap: 2rem;
    padding: 1.7rem 1.8rem 1.9rem;
    margin-top: -1px;
    background: linear-gradient(var(--fond-2), var(--noir));
    border: 1px solid var(--bord);
    border-top: 0;
    border-radius: 0 0 var(--r-l) var(--r-l);
}

.pastilles { display: flex; flex-wrap: wrap; gap: .45rem; margin-top: 1.1rem; }
.pastille {
    padding: .28rem .7rem;
    font-size: .74rem;
    font-weight: 600;
    letter-spacing: .01em;
    color: var(--texte-doux);
    background: rgba(255,255,255,.045);
    border: 1px solid var(--bord-clair);
    border-radius: 99px;
}

.liste-points { list-style: none; margin: 1.1rem 0 0; padding: 0; display: grid; gap: .7rem; }
.liste-points li {
    position: relative;
    padding-left: 1.6rem;
    color: var(--texte-doux);
    font-size: .94rem;
    line-height: 1.6;
}
.liste-points li::before {
    content: '';
    position: absolute;
    left: 0; top: .55em;
    width: 8px; height: 8px;
    background: var(--teinte, var(--violet));
    /* Losange : le cristal du logo, en miniature. */
    transform: rotate(45deg);
    border-radius: 2px;
    box-shadow: 0 0 10px color-mix(in srgb, var(--teinte, var(--violet)) 80%, transparent);
}
.liste-points strong { color: var(--texte); font-weight: 650; }

/* Emplacement de la capture du mode. Tant qu'aucune image n'est fournie,
   le bloc affiche un cristal anime : le site ne parait jamais inachevee. */
.visuel-mode {
    position: relative;
    aspect-ratio: 4 / 3;
    border-radius: var(--r-m);
    background: radial-gradient(120% 100% at 50% 0%,
                color-mix(in srgb, var(--teinte) 24%, var(--surface)), var(--noir));
    border: 1px solid color-mix(in srgb, var(--teinte) 28%, transparent);
    box-shadow: var(--biseau);
    overflow: hidden;
    display: grid;
    place-items: center;
}
.visuel-mode img { width: 100%; height: 100%; object-fit: cover; }
.visuel-mode__vide { display: grid; place-items: center; gap: .8rem; text-align: center; padding: 1rem; }
.visuel-mode__vide svg { width: 74px; height: 74px; animation: pivote 9s linear infinite; }
.visuel-mode__vide span { font-size: .74rem; color: var(--texte-faible); letter-spacing: .06em; }
@keyframes pivote {
    from { transform: rotateY(0deg); }
    to   { transform: rotateY(360deg); }
}

/* ==================== HERO ==================== */

.hero {
    position: relative;
    min-height: 100svh;
    display: grid;
    align-items: center;
    padding: calc(var(--nav-h) + 3rem) 0 4rem;
    overflow: hidden;
}

.hero__grille {
    display: grid;
    grid-template-columns: 1.15fr .85fr;
    gap: clamp(2rem, 5vw, 4.5rem);
    align-items: center;
}

/* ==================== L'ENTREE DE PAGE ====================

   Ce qui est deja a l'ecran au chargement n'apparaissait jamais : le module
   d'apparition ne surveille que le defilement, et le haut de l'accueil est
   par definition deja visible. En revenant du wiki, la page s'affichait donc
   d'un bloc, immobile.

   Le flou qui se leve (`filter: blur`) fait plus que le glissement seul : il
   donne l'impression d'une mise au point, et c'est ce qui distingue une
   arrivee d'un simple deplacement.

   `backwards` retient l'etat initial pendant le delai : sans lui, chaque
   element serait affiche en clair puis disparaitrait pour reapparaitre.

   La classe est retiree par le JS au bout de 1,8 s. Une animation qui reste
   accrochee bloquerait `transform`, et le champ magnetique n'aurait plus la
   main sur ces memes elements. */
@keyframes entree-monte {
    from { opacity: 0; transform: translateY(28px); filter: blur(7px); }
    to   { opacity: 1; transform: none; filter: none; }
}
@keyframes entree-souffle {
    from { opacity: 0; transform: scale(.9) translateY(14px); filter: blur(10px); }
    to   { opacity: 1; transform: none; filter: none; }
}
@keyframes entree-glisse {
    from { opacity: 0; transform: translateY(-14px); }
    to   { opacity: 1; transform: none; }
}

.entree .nav { animation: entree-glisse .6s var(--douce) backwards; }

/* Colonne de gauche : chaque bloc arrive l'un apres l'autre, de haut en bas.
   80 ms d'ecart — assez pour lire une cascade, trop peu pour attendre. */
.entree .hero__grille > div:first-child > * {
    animation: entree-monte .8s var(--douce) backwards;
}
.entree .hero__grille > div:first-child > *:nth-child(1) { animation-delay: .06s; }
.entree .hero__grille > div:first-child > *:nth-child(2) { animation-delay: .14s; }
.entree .hero__grille > div:first-child > *:nth-child(3) { animation-delay: .22s; }
.entree .hero__grille > div:first-child > *:nth-child(4) { animation-delay: .30s; }
.entree .hero__grille > div:first-child > *:nth-child(5) { animation-delay: .38s; }
.entree .hero__grille > div:first-child > *:nth-child(6) { animation-delay: .46s; }

/* Colonne de droite : le cristal. Il gonfle au lieu de monter — c'est un
   objet, pas une ligne de texte, et il arrive en dernier. */
.entree .hero__grille > div:nth-child(2) {
    animation: entree-souffle .95s var(--douce) .28s backwards;
}

/* Les autres pages n'ont pas de hero : on anime leur premier ecran. */
.entree main > .wrap > .entete-section,
.entree main > .wrap > *:first-child {
    animation: entree-monte .75s var(--douce) .08s backwards;
}

.hero h1 { margin-bottom: 1.6rem; }
.hero .lead { max-width: 52ch; margin-bottom: 2.2rem; }

.hero__actions { display: flex; flex-wrap: wrap; gap: .9rem; align-items: center; }

/* L'ADRESSE DU SERVEUR, copiable en un clic. C'est l'element le plus
   utile de la page : un visiteur vient chercher ca, et rien d'autre. */
.ip {
    display: inline-flex;
    align-items: center;
    gap: .9rem;
    padding: .7rem .8rem .7rem 1.3rem;
    background: var(--surface);
    border: 1px solid var(--bord-fort);
    border-radius: var(--r-m);
    box-shadow: var(--biseau);
    cursor: pointer;
    font-family: 'Outfit', monospace;
    font-weight: 700;
    font-size: 1.02rem;
    letter-spacing: -.01em;
    transition: transform .35s var(--ressort), border-color .3s, box-shadow .35s;
}
.ip:hover { border-color: var(--violet); box-shadow: var(--biseau), var(--lueur); }
.ip__badge {
    padding: .3rem .65rem;
    font-family: 'Inter', sans-serif;
    font-size: .72rem;
    font-weight: 700;
    letter-spacing: .04em;
    color: var(--violet-clair);
    background: rgba(168,85,247,.14);
    border-radius: var(--r-s);
    transition: background .3s, color .3s;
}
.ip.copie .ip__badge { background: rgba(52,211,153,.18); color: var(--vert); }

/* Statut serveur : une pastille qui bat. Le battement ne s'arrete jamais —
   c'est ce qui distingue "en ligne maintenant" de "capture d'ecran". */
.statut {
    display: inline-flex;
    align-items: center;
    gap: .6rem;
    padding: .4rem .95rem .4rem .8rem;
    font-size: .84rem;
    font-weight: 600;
    color: var(--texte-doux);
    background: rgba(255,255,255,.035);
    border: 1px solid var(--bord-clair);
    border-radius: 99px;
}
.pouls {
    position: relative;
    width: 8px; height: 8px;
    border-radius: 50%;
    background: var(--texte-faible);
    flex-shrink: 0;
}
.statut.enligne .pouls { background: var(--vert); }
.statut.enligne .pouls::after {
    content: '';
    position: absolute;
    inset: -4px;
    border-radius: 50%;
    border: 1px solid var(--vert);
    animation: onde 2.2s ease-out infinite;
}
.statut.horsligne .pouls { background: var(--rouge); }
@keyframes onde {
    0%   { transform: scale(.6); opacity: .9; }
    100% { transform: scale(1.9); opacity: 0; }
}

/* LE CRISTAL DU HERO. Un vrai objet 3D en CSS : huit faces triangulaires
   assemblees en bipyramide, comme le logo. Il tourne lentement et suit la
   souris. Aucune image, aucune bibliotheque : il pese zero octet et reste
   net sur un ecran 4K. */
.scene {
    perspective: 1200px;
    display: grid;
    place-items: center;
    min-height: 380px;
}
/* Deux couches, et c'est indispensable : l'enveloppe porte l'inclinaison vers
   la souris, le cristal porte la rotation continue. Sur un seul element, la
   propriete `transform` ne peut pas etre a la fois animee par @keyframes et
   ecrite par le JS — l'animation gagne toujours, et le suivi du curseur
   n'aurait aucun effet visible. */
.cristal-enveloppe {
    /* `position: relative` est INDISPENSABLE : le logo qui se pose au centre
       est en `position: absolute`, et sans reference ici il se calait sur le
       hero entier — c'est-a-dire en haut a gauche de l'ecran, hors du cristal.
       Le defaut ne se voit qu'au rendu, jamais a la lecture du HTML. */
    position: relative;
    transform-style: preserve-3d;
    transform: rotateY(var(--souris-x, 0deg)) rotateX(var(--souris-y, 0deg));
    transition: transform .5s var(--net);
    display: grid;
    place-items: center;
}
.cristal {
    position: relative;
    width: 190px; height: 190px;
    transform-style: preserve-3d;
    animation: tourne 22s linear infinite;
}
@keyframes tourne {
    from { transform: rotateX(-14deg) rotateY(0deg); }
    to   { transform: rotateX(-14deg) rotateY(360deg); }
}
.cristal__face {
    position: absolute;
    inset: 0;
    background: linear-gradient(160deg, var(--violet-clair), var(--violet) 42%, var(--violet-nuit));
    clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);
    opacity: .88;
    box-shadow: inset 0 0 60px rgba(255,255,255,.22);
}
.cristal__face:nth-child(1) { transform: rotateY(0deg)   translateZ(58px); }
.cristal__face:nth-child(2) { transform: rotateY(60deg)  translateZ(58px); }
.cristal__face:nth-child(3) { transform: rotateY(120deg) translateZ(58px); }
.cristal__face:nth-child(4) { transform: rotateY(180deg) translateZ(58px); }
.cristal__face:nth-child(5) { transform: rotateY(240deg) translateZ(58px); }
.cristal__face:nth-child(6) { transform: rotateY(300deg) translateZ(58px); }

.cristal__halo {
    position: absolute;
    inset: -70%;
    background: radial-gradient(circle, rgba(168,85,247,.42), transparent 62%);
    filter: blur(28px);
    animation: respire 5s ease-in-out infinite;
    pointer-events: none;
}
@keyframes respire {
    0%, 100% { opacity: .55; transform: scale(.94); }
    50%      { opacity: 1;   transform: scale(1.08); }
}

.logo-hero {
    position: absolute;
    width: 168px;
    filter: drop-shadow(0 22px 45px rgba(0,0,0,.85));
    animation: flotte 7s ease-in-out infinite;
    /* `z-index` NE SUFFIT PAS ICI, et c'est le piege classique du 3D en CSS.
       Dans un contexte `preserve-3d`, l'ordre de peinture ne vient plus de
       z-index mais de la POSITION EN PROFONDEUR. Les faces du cristal sont a
       translateZ(58px) : le logo, reste a 0, se retrouvait donc a l'interieur
       du cristal, a moitie recouvert par les faces avant.
       On le pousse devant, en profondeur reelle. */
    transform: translateZ(112px);
}

/* Cubes voxel qui derivent en fond. Le rappel Minecraft le plus direct
   du site, et le seul assume comme tel. */
.voxels { position: absolute; inset: 0; pointer-events: none; overflow: hidden; z-index: 0; }
.voxel {
    position: absolute;
    width: 34px; height: 34px;
    background: linear-gradient(150deg, rgba(168,85,247,.28), rgba(47,125,246,.14));
    border: 1px solid rgba(201,165,255,.24);
    border-radius: 5px;
    box-shadow: var(--biseau);
    animation: derive linear infinite;
    opacity: 0;
}
@keyframes derive {
    0%   { transform: translateY(30px) rotate(0deg)   scale(.7); opacity: 0; }
    12%  { opacity: .8; }
    88%  { opacity: .55; }
    100% { transform: translateY(-118vh) rotate(320deg) scale(1.05); opacity: 0; }
}

/* ==================== CHIFFRES ==================== */

.chiffres {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
    gap: 1rem;
    margin-top: 2.6rem;
    padding-top: 2.2rem;
    border-top: 1px solid var(--bord-clair);
}
.chiffre__val {
    font-family: 'Outfit', sans-serif;
    font-size: clamp(1.7rem, 3.6vw, 2.5rem);
    font-weight: 800;
    letter-spacing: -.04em;
    line-height: 1;
}
.chiffre__lib {
    margin-top: .35rem;
    font-size: .78rem;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--texte-faible);
}

/* ==================== GRADES / BOUTIQUE ==================== */

.grade { display: flex; flex-direction: column; padding: 2rem 1.8rem; }
.grade--vedette {
    border-color: var(--bord-fort);
    background: linear-gradient(165deg, var(--surface-2), var(--fond-2) 70%);
}
.grade__ruban {
    position: absolute;
    top: 1.2rem; right: -2.6rem;
    padding: .3rem 3rem;
    font-size: .68rem;
    font-weight: 800;
    letter-spacing: .14em;
    text-transform: uppercase;
    color: #fff;
    background: linear-gradient(90deg, var(--violet), var(--bleu));
    transform: rotate(38deg);
    box-shadow: var(--ombre-douce);
}
.grade__nom {
    font-family: 'Outfit', sans-serif;
    font-size: 1.5rem;
    font-weight: 800;
    letter-spacing: -.03em;
}
.grade__prix { display: flex; align-items: baseline; gap: .6rem; margin: 1rem 0 .3rem; }
.grade__prix b {
    font-family: 'Outfit', sans-serif;
    font-size: 2.3rem;
    font-weight: 800;
    letter-spacing: -.045em;
}
.grade__barre { color: var(--texte-faible); text-decoration: line-through; font-size: 1rem; }
.grade__remise {
    padding: .2rem .55rem;
    font-size: .72rem;
    font-weight: 800;
    color: var(--vert);
    background: rgba(52,211,153,.13);
    border-radius: var(--r-s);
}
.grade__duree { font-size: .82rem; color: var(--texte-faible); margin-bottom: 1.4rem; }
.grade__liste { list-style: none; margin: 0 0 1.8rem; padding: 0; display: grid; gap: .65rem; flex: 1; }
.grade__liste li {
    position: relative;
    padding-left: 1.7rem;
    font-size: .9rem;
    color: var(--texte-doux);
    line-height: 1.55;
}
.grade__liste li::before {
    content: '';
    position: absolute;
    left: 0; top: .42em;
    width: 15px; height: 9px;
    border-left: 2px solid var(--vert);
    border-bottom: 2px solid var(--vert);
    transform: rotate(-45deg) scale(.85);
    transform-origin: center;
}
/* ==================== AVIS D'ACHAT ====================

   Pose sous la liste d'un article apres verification du pseudo. Trois tons,
   trois messages differents — et surtout, un seul BLOQUE :

     bloque   l'article est definitif et deja possede : le bouton devient
              inerte, parce que ce clic ne peut aboutir a rien de bon ;
     cumul    VIP ou VIP+ deja actif : l'achat ajoute des jours, on le dit ;
     inutile  l'achat marcherait mais n'apporterait rien (VIP par-dessus un
              VIP+). On previent, on ne bloque pas : c'est son argent, et il
              peut vouloir offrir le grade a quelqu'un d'autre. */
.avis-achat {
    margin: 0 0 1.1rem;
    padding: .8rem 1rem;
    border-radius: var(--r-s);
    font-size: .87rem;
    line-height: 1.5;
    border: 1px solid transparent;
}
.avis-achat--bloque {
    color: #FFC9CC;
    background: rgba(229,72,77,.12);
    border-color: rgba(229,72,77,.34);
}
.avis-achat--cumul {
    color: #BFF3D8;
    background: rgba(52,211,153,.11);
    border-color: rgba(52,211,153,.30);
}
.avis-achat--inutile {
    color: #FFE3B0;
    background: rgba(242,179,61,.11);
    border-color: rgba(242,179,61,.30);
}

/* La carte d'un article deja possede s'efface : elle reste lisible, mais ne
   se dispute plus l'attention avec celles qu'on peut encore acheter. */
.carte.possede { opacity: .74; }
.carte.possede:hover { opacity: 1; }

.btn--inerte {
    pointer-events: none;
    filter: grayscale(1);
    opacity: .55;
}

/* Une ligne de BONUS : ce n'est pas un avantage de plus dans la liste, c'est
   une offre liee a un autre article. Le violet et l'etoile la detachent des
   coches vertes, sans quoi elle se lisait comme un point ordinaire. */
.grade__liste li.bonus { color: var(--texte); }
.grade__liste li.bonus::before {
    content: '✦';
    border: 0;
    transform: none;
    top: .1em;
    width: auto; height: auto;
    color: var(--violet-clair);
    font-size: .95em;
}

.grade__liste li.non { color: var(--texte-faible); }
.grade__liste li.non::before {
    border: 0;
    top: .5em;
    width: 11px; height: 2px;
    background: var(--texte-faible);
    transform: none;
}
.grade__liste b { color: var(--texte); font-weight: 650; }

/* ==================== BOUTIQUE : DEUX BLOCS ====================
   BLOC 1 — les cartes de rayon. Une carte par famille d'articles, avec son
   icone. On choisit d'abord DE QUOI on parle.
   BLOC 2 — le panneau de detail, qui change de contenu sans que la page ne
   bouge. Choisir un autre rayon remplace ce qui est affiche.

   POURQUOI PAS TROIS SECTIONS EMPILEES. La page precedente demandait de
   faire defiler trois blocs pour comparer deux articles, et l'on perdait de
   vue ce qu'on avait lu plus haut. Ici le choix reste toujours visible en
   haut, et le detail se remplace dessous. */

.rayons {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 178px), 1fr));
    gap: 1rem;
}

.carte-vente {
    position: relative;
    display: grid;
    justify-items: center;
    gap: .75rem;
    padding: 1.6rem 1rem 1.4rem;
    background: linear-gradient(160deg, var(--surface), var(--fond-2));
    border: 1px solid var(--bord);
    border-radius: var(--r-l);
    box-shadow: var(--biseau), var(--ombre-douce);
    cursor: pointer;
    overflow: hidden;
    isolation: isolate;
    text-align: center;
    color: inherit;
    font: inherit;
    transition: border-color .35s var(--net), box-shadow .4s var(--douce),
                background .35s var(--net);
}
.carte-vente::before {
    content: '';
    position: absolute;
    inset: -1px;
    z-index: -1;
    border-radius: inherit;
    background: radial-gradient(16rem 16rem at 50% 0%,
                color-mix(in srgb, var(--teinte, var(--violet)) 34%, transparent), transparent 68%);
    opacity: 0;
    transition: opacity .4s var(--net);
}
.carte-vente:hover::before, .carte-vente[aria-selected="true"]::before { opacity: 1; }
.carte-vente:hover { border-color: color-mix(in srgb, var(--teinte, var(--violet)) 50%, transparent); }
.carte-vente[aria-selected="true"] {
    border-color: var(--teinte, var(--violet));
    box-shadow: var(--biseau-fort), 0 18px 44px -20px color-mix(in srgb, var(--teinte, var(--violet)) 90%, transparent);
}

/* ==================== L'ICONE 3D D'UN RAYON ====================

   UN VRAI VOLUME, PAS UNE VIGNETTE PLATE.

   Trois plans empiles dans le meme espace 3D (`preserve-3d`) :
     - le socle, avec sa bordure et son ombre portee ;
     - une face interieure legerement soulevee, qui cree l'epaisseur ;
     - le pictogramme, pousse encore plus haut, qui flotte au-dessus.
   Un reflet oblique traverse le tout : c'est lui qui fait lire du verre
   plutot qu'un carre colore.

   ELLE SUIT LE CURSEUR SANS UNE LIGNE DE JS EN PLUS. Le champ magnetique
   (module 3) ecrit deja `--rx` et `--ry` sur la carte parente pour son propre
   pivot ; les variables CSS descendent aux enfants, on les reutilise en les
   amplifiant. L'icone se tourne donc vers la souris plus fort que la carte
   qui la porte, et c'est exactement l'effet recherche : l'objet regarde le
   curseur.

   Le flottement passe par `translate` et le redressement par `rotate` :
   `transform` est reserve a l'inclinaison 3D. Les trois proprietes
   individuelles se composent au lieu de s'ecraser. */
.carte-vente__icone {
    position: relative;
    width: 62px; height: 62px;
    display: grid;
    place-items: center;
    border-radius: 18px;
    background: linear-gradient(150deg,
        color-mix(in srgb, var(--teinte, var(--violet)) 26%, var(--surface-2)), var(--fond-2));
    border: 1px solid color-mix(in srgb, var(--teinte, var(--violet)) 32%, transparent);
    box-shadow: var(--biseau);
    animation: flotte 5.5s ease-in-out infinite;
    transform-style: preserve-3d;
    transform: perspective(420px)
               rotateX(calc(var(--rx, 0deg) * 2.4))
               rotateY(calc(var(--ry, 0deg) * 2.4));
    transition: box-shadow .45s var(--douce), border-color .35s,
                rotate .5s var(--ressort), transform .5s var(--douce);
}

/* L'epaisseur : une face interieure soulevee de 6 px dans la profondeur. */
.carte-vente__icone::before {
    content: '';
    position: absolute;
    inset: 5px;
    border-radius: 13px;
    background: linear-gradient(160deg,
        color-mix(in srgb, var(--teinte, var(--violet)) 34%, transparent),
        transparent 68%);
    transform: translateZ(6px);
}

/* Le reflet. `pointer-events: none` : sans lui, il intercepterait le survol
   du pictogramme et l'icone ne suivrait plus la souris au centre. */
.carte-vente__icone::after {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: 18px;
    background: linear-gradient(140deg, rgba(255,255,255,.28), transparent 46%);
    transform: translateZ(19px);
    pointer-events: none;
    opacity: .7;
    transition: opacity .4s var(--net);
}

.carte-vente__icone svg {
    width: 32px; height: 32px;
    transform: translateZ(15px);
}

.carte-vente:hover .carte-vente__icone,
.carte-vente[aria-selected="true"] .carte-vente__icone {
    rotate: -7deg;
    border-color: var(--teinte, var(--violet));
    box-shadow: var(--biseau-fort),
                0 14px 30px -10px color-mix(in srgb, var(--teinte, var(--violet)) 85%, transparent);
}
.carte-vente:hover .carte-vente__icone::after { opacity: 1; }

/* LE TOUR SUR SOI-MEME, AU CLIC.
   C'est le pictogramme qui tourne, pas le socle : le socle continue pendant
   ce temps a suivre le curseur, et les deux mouvements se lisent ensemble au
   lieu de se combattre. Il sort aussi de la profondeur a mi-course — un tour
   a plat ne se distingue pas d'un simple clignotement. */
@keyframes pivot-icone {
      0% { transform: translateZ(15px) rotateY(0deg)   scale(1); }
     45% { transform: translateZ(34px) rotateY(200deg) scale(1.16); }
    100% { transform: translateZ(15px) rotateY(360deg) scale(1); }
}
.carte-vente__icone.tourne svg { animation: pivot-icone .72s var(--douce); }
.carte-vente__icone.tourne {
    box-shadow: var(--biseau-fort),
                0 20px 42px -12px color-mix(in srgb, var(--teinte, var(--violet)) 95%, transparent);
}

.carte-vente__nom {
    font-family: 'Outfit', sans-serif;
    font-size: 1.02rem;
    font-weight: 800;
    letter-spacing: -.02em;
}
.carte-vente__prix { font-size: .8rem; color: var(--texte-faible); }
.carte-vente__prix b { color: var(--or); font-weight: 700; }

/* Le panneau de detail. Il ne disparait jamais : il se remplace. */
.panneau-vente { position: relative; min-height: 220px; }
.rayon { display: none; }
.rayon.actif { display: block; animation: entree-rayon .5s var(--douce); }
@keyframes entree-rayon {
    from { opacity: 0; transform: translateY(14px); }
    to   { opacity: 1; transform: none; }
}
.rayon__titre {
    display: flex;
    align-items: center;
    gap: .9rem;
    margin-bottom: 1.4rem;
    flex-wrap: wrap;
}

/* ==================== COFFRE ====================
   Le defilement d'objets d'un coffre : une bande qui glisse et ralentit
   jusqu'a s'arreter sur une case. L'animation est PUREMENT DECORATIVE — le
   resultat est decide avant qu'elle ne commence, jamais par elle. */

.coffre {
    position: relative;
    overflow: hidden;
    border: 1px solid var(--bord-fort);
    border-radius: var(--r-m);
    background: var(--noir);
    box-shadow: var(--biseau);
    padding: 1rem 0;
}
.coffre__bande {
    display: flex;
    gap: .6rem;
    padding: 0 .6rem;
    will-change: transform;
}
.coffre__case {
    flex: 0 0 104px;
    height: 104px;
    display: grid;
    place-items: center;
    gap: .3rem;
    padding: .5rem;
    text-align: center;
    background: linear-gradient(155deg, var(--surface-2), var(--fond-2));
    border: 1px solid var(--bord);
    border-radius: var(--r-s);
    box-shadow: var(--biseau);
    font-size: .68rem;
    line-height: 1.25;
    color: var(--texte-doux);
}
.coffre__case svg { width: 26px; height: 26px; }
.coffre__case b { display: block; font-size: .72rem; color: var(--texte); }
.coffre__case.rare  { border-color: rgba(47,125,246,.5); }
.coffre__case.epique{ border-color: rgba(168,85,247,.6); }
.coffre__case.legend{ border-color: rgba(242,179,61,.7); }

/* Le curseur central : c'est lui qui designe la case gagnante. Sans repere
   fixe, un defilement qui s'arrete ne designe rien. */
.coffre__viseur {
    position: absolute;
    top: 0; bottom: 0; left: 50%;
    width: 2px;
    background: linear-gradient(var(--violet), var(--bleu));
    box-shadow: 0 0 14px rgba(168,85,247,.9);
    transform: translateX(-50%);
    z-index: 2;
    pointer-events: none;
}
.coffre__viseur::before, .coffre__viseur::after {
    content: '';
    position: absolute;
    left: 50%;
    border: 6px solid transparent;
    transform: translateX(-50%);
}
.coffre__viseur::before { top: -1px; border-top-color: var(--violet); }
.coffre__viseur::after  { bottom: -1px; border-bottom-color: var(--bleu); }

/* Un voile sur les bords : la bande parait sortir de l'ombre au lieu d'etre
   coupee net. */
.coffre::before, .coffre::after {
    content: '';
    position: absolute;
    top: 0; bottom: 0;
    width: 70px;
    z-index: 1;
    pointer-events: none;
}
.coffre::before { left: 0;  background: linear-gradient(90deg, var(--noir), transparent); }
.coffre::after  { right: 0; background: linear-gradient(-90deg, var(--noir), transparent); }

.coffre-gain {
    display: none;
    align-items: center;
    gap: 1rem;
    margin-top: 1rem;
    padding: 1rem 1.2rem;
    border: 1px solid var(--bord-fort);
    border-radius: var(--r-m);
    background: rgba(168,85,247,.09);
    animation: monte .5s var(--douce);
}
.coffre-gain.visible { display: flex; }

.table-chances td:last-child { text-align: right; font-variant-numeric: tabular-nums; }

/* ==================== WIKI ==================== */

.wiki { display: grid; grid-template-columns: 250px 1fr; gap: 2.5rem; align-items: start; }

.wiki__menu {
    position: sticky;
    top: calc(var(--nav-h) + 24px);
    display: grid;
    gap: .2rem;
    padding: 1rem;
    background: var(--surface);
    border: 1px solid var(--bord);
    border-radius: var(--r-l);
    box-shadow: var(--biseau);
}
.wiki__menu a {
    padding: .55rem .8rem;
    font-size: .89rem;
    font-weight: 600;
    color: var(--texte-doux);
    border-radius: var(--r-s);
    border-left: 2px solid transparent;
    transition: all .28s var(--net);
}
.wiki__menu a:hover, .wiki__menu a.actif {
    color: var(--texte);
    background: rgba(168,85,247,.10);
    border-left-color: var(--violet);
}
.wiki__menu .titre-menu {
    padding: .9rem .8rem .35rem;
    font-size: .68rem;
    font-weight: 800;
    letter-spacing: .16em;
    text-transform: uppercase;
    color: var(--texte-faible);
}

/* LES SECTIONS DEPLIANTES. Cliquer ouvre un panneau DANS la page, texte a
   gauche et image a droite : le joueur voit de quoi on parle en meme temps
   qu'il le lit. C'est toute la difference entre un wiki qu'on parcourt et
   un wiki qu'on comprend. */
/* On n'utilise PAS <details>, et c'est un choix technique.
   Un <details> ferme ne REND PAS ses enfants : le navigateur les retire de la
   mise en page. Une transition de hauteur n'a alors rien a animer — le contenu
   apparait d'un coup a l'ouverture, puis l'animation part d'un etat deja
   visible. Ici le contenu reste toujours dans le flux, simplement ecrase a
   zero et masque par `overflow`. Il s'anime donc vraiment, et il reste
   trouvable par la recherche du navigateur (Ctrl+F). */
.repli { border: 1px solid var(--bord); border-radius: var(--r-m); background: var(--surface); box-shadow: var(--biseau); overflow: hidden; }
.repli + .repli { margin-top: .8rem; }
.repli__tete {
    display: flex;
    align-items: center;
    gap: 1rem;
    width: 100%;
    padding: 1.1rem 1.4rem;
    background: none;
    border: 0;
    color: inherit;
    font: inherit;
    cursor: pointer;
    text-align: left;
    transition: background .3s var(--net);
}
.repli__tete:hover { background: rgba(168,85,247,.07); }
.repli__num {
    display: grid;
    place-items: center;
    width: 30px; height: 30px;
    flex-shrink: 0;
    font-family: 'Outfit', sans-serif;
    font-size: .82rem;
    font-weight: 800;
    color: var(--violet-clair);
    background: rgba(168,85,247,.13);
    border: 1px solid var(--bord);
    border-radius: var(--r-s);
}
.repli__titre {
    flex: 1;
    font-family: 'Outfit', sans-serif;
    font-size: 1.03rem;
    font-weight: 700;
    letter-spacing: -.02em;
}
.repli__plus {
    position: relative;
    width: 22px; height: 22px;
    flex-shrink: 0;
    transition: transform .45s var(--ressort);
}
.repli__plus::before, .repli__plus::after {
    content: '';
    position: absolute;
    top: 50%; left: 50%;
    background: var(--texte-doux);
    border-radius: 2px;
    transform: translate(-50%, -50%);
    transition: opacity .3s, background .3s;
}
.repli__plus::before { width: 13px; height: 2px; }
.repli__plus::after  { width: 2px; height: 13px; }
.repli.ouvert .repli__plus { transform: rotate(180deg); }
.repli.ouvert .repli__plus::after { opacity: 0; }
.repli.ouvert .repli__plus::before { background: var(--violet); }

.repli__corps { display: grid; grid-template-rows: 0fr; transition: grid-template-rows .5s var(--douce); }
.repli.ouvert .repli__corps { grid-template-rows: 1fr; }

/* Le temps d'un clic dans le sommaire, tout se fige : les volets se referment
   d'un coup et la fenetre se recale dessus. Sans cette parenthese, la page
   change de hauteur pendant une demi-seconde et le defilement vise une
   position qui n'existe deja plus — c'etait le bug du wiki et du reglement.
   Le JS retire la classe des la ligne suivante : rien de tout cela ne dure. */
.sans-transition { scroll-behavior: auto !important; }
.sans-transition .repli__corps,
.sans-transition .repli__plus,
.sans-transition .mode__detail { transition: none !important; }
.repli__corps > div { overflow: hidden; }
.repli__contenu {
    display: grid;
    grid-template-columns: 1fr .85fr;
    gap: 1.8rem;
    padding: 0 1.4rem 1.5rem;
    border-top: 1px solid var(--bord-clair);
    padding-top: 1.4rem;
    margin-top: .2rem;
}

/* Emplacement d'illustration du wiki. Vide, il indique quoi y mettre :
   personne n'oublie une image dont l'emplacement porte son nom. */
.figure { margin: 0; }
.figure__cadre {
    position: relative;
    aspect-ratio: 16 / 10;
    border-radius: var(--r-m);
    overflow: hidden;
    background: linear-gradient(150deg, var(--surface-2), var(--noir));
    border: 1px solid var(--bord);
    box-shadow: var(--biseau);
    display: grid;
    place-items: center;
}
.figure__cadre img { width: 100%; height: 100%; object-fit: cover; transition: transform .7s var(--douce); }
.figure__cadre:hover img { transform: scale(1.06); }
.figure__vide { text-align: center; padding: 1.2rem; display: grid; gap: .55rem; place-items: center; }
.figure__vide svg { width: 34px; height: 34px; color: var(--texte-faible); }
.figure__vide code {
    font-size: .72rem;
    color: var(--violet-clair);
    background: rgba(168,85,247,.10);
    padding: .2rem .5rem;
    border-radius: 5px;
    word-break: break-all;
}
.figure figcaption { margin-top: .6rem; font-size: .78rem; color: var(--texte-faible); text-align: center; }

/* ==================== TABLEAUX ==================== */

.tableau-enveloppe {
    overflow-x: auto;
    border: 1px solid var(--bord);
    border-radius: var(--r-m);
    box-shadow: var(--biseau);
    background: var(--surface);
}
table { width: 100%; border-collapse: collapse; font-size: .9rem; min-width: 460px; }
th, td { padding: .8rem 1.1rem; text-align: left; border-bottom: 1px solid var(--bord-clair); }
th {
    font-size: .72rem;
    font-weight: 800;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--texte-faible);
    background: rgba(255,255,255,.025);
}
td { color: var(--texte-doux); }
tbody tr { transition: background .25s var(--net); }
tbody tr:hover { background: rgba(168,85,247,.06); }
tbody tr:last-child td { border-bottom: 0; }
td strong, th strong { color: var(--texte); }

/* ==================== FORMULAIRES ==================== */

.champ { display: grid; gap: .45rem; margin-bottom: 1.1rem; }
.champ label { font-size: .82rem; font-weight: 650; color: var(--texte-doux); }
.champ input, .champ select, .champ textarea {
    width: 100%;
    padding: .82rem 1rem;
    font: inherit;
    font-size: .95rem;
    color: var(--texte);
    background: var(--noir);
    border: 1px solid var(--bord);
    border-radius: var(--r-m);
    box-shadow: var(--biseau);
    transition: border-color .3s, box-shadow .3s;
}
.champ input:focus, .champ select:focus, .champ textarea:focus {
    outline: 0;
    border-color: var(--violet);
    box-shadow: var(--biseau), 0 0 0 3px rgba(168,85,247,.18);
}
.champ input::placeholder { color: var(--texte-faible); }
.aide { font-size: .78rem; color: var(--texte-faible); }

.retour {
    display: none;
    align-items: center;
    gap: .7rem;
    padding: .85rem 1.1rem;
    font-size: .89rem;
    border-radius: var(--r-m);
    border: 1px solid;
    margin-top: 1rem;
}
.retour.visible { display: flex; animation: monte .45s var(--douce); }
.retour.ok  { color: var(--vert);  background: rgba(52,211,153,.09); border-color: rgba(52,211,153,.3); }
.retour.ko  { color: var(--rouge); background: rgba(240,91,107,.09); border-color: rgba(240,91,107,.3); }
.retour.info{ color: var(--violet-clair); background: rgba(168,85,247,.09); border-color: var(--bord-fort); }
.retour img { width: 34px; height: 34px; border-radius: 6px; image-rendering: pixelated; }

@keyframes monte {
    from { opacity: 0; transform: translateY(8px); }
    to   { opacity: 1; transform: none; }
}

/* ==================== DISCORD ====================
   Il tourne sur lui-meme et grossit vers le curseur, comme demande. Le
   bouton flottant est present sur TOUTES les pages : c'est le seul appel
   a l'action qui ne doit jamais demander de defiler pour etre trouve. */

.discord-flottant {
    position: fixed;
    right: clamp(1rem, 3vw, 2rem);
    bottom: clamp(1rem, 3vw, 2rem);
    z-index: 90;
    width: 60px; height: 60px;
    display: grid;
    place-items: center;
    border-radius: 20px;
    background: linear-gradient(150deg, #5865F2, #3C45C4);
    border: 1px solid rgba(255,255,255,.16);
    box-shadow: var(--biseau-fort), 0 14px 34px -10px rgba(88,101,242,.75);
    cursor: pointer;
    transition: box-shadow .5s var(--douce), border-radius .5s var(--douce);
    perspective: 600px;
}
/* IL RESPIRE EN PERMANENCE, meme sans souris. Un bouton parfaitement immobile
   dans un coin devient un element de decor : l'oeil cesse de le voir au bout
   de dix secondes.

   LA RESPIRATION EST SUR L'ICONE, PAS SUR LE BOUTON. Une animation @keyframes
   qui ecrit `scale` gagne toujours contre un `scale` pose en ligne — et c'est
   exactement ce que fait le champ magnetique sur ce bouton. Les deux se
   disputeraient la meme propriete, et le survol ne ferait plus rien.
   En placant la respiration un cran plus bas, les deux effets se cumulent :
   le bouton grossit vers la souris pendant que l'icone continue de battre. */
.discord-flottant svg {
    width: 32px; height: 32px;
    color: #fff;
    transition: transform .75s var(--ressort);
    animation: respiration-discord 3.4s ease-in-out infinite;
}
@keyframes respiration-discord {
    0%, 100% { scale: 1; }
    50%      { scale: 1.09; }
}
.discord-flottant:hover {
    border-radius: 28px;
    box-shadow: var(--biseau-fort), 0 26px 56px -12px rgba(88,101,242,1);
}
.discord-flottant:hover svg { transform: rotateY(360deg); }
.discord-flottant::after {
    content: 'Rejoins le Discord';
    position: absolute;
    right: calc(100% + 14px);
    top: 50%;
    transform: translateY(-50%) translateX(10px);
    padding: .5rem .9rem;
    font-size: .82rem;
    font-weight: 650;
    white-space: nowrap;
    color: var(--texte);
    background: var(--surface-2);
    border: 1px solid var(--bord);
    border-radius: var(--r-s);
    box-shadow: var(--biseau), var(--ombre);
    opacity: 0;
    pointer-events: none;
    transition: opacity .35s var(--net), transform .45s var(--douce);
}
.discord-flottant:hover::after { opacity: 1; transform: translateY(-50%) translateX(0); }

/* Onde qui part du bouton, une fois toutes les 4 s. Discrete, mais c'est
   elle qui fait remarquer le bouton sans le rendre agressif. */
.discord-flottant::before {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: inherit;
    border: 1.5px solid #5865F2;
    animation: onde-discord 4s ease-out infinite;
    pointer-events: none;
}
@keyframes onde-discord {
    0%       { transform: scale(1);   opacity: .8; }
    45%,100% { transform: scale(1.5); opacity: 0; }
}

.bloc-discord {
    display: grid;
    grid-template-columns: auto 1fr auto;
    align-items: center;
    gap: 2rem;
    padding: 2.4rem;
    background: linear-gradient(120deg, rgba(88,101,242,.16), var(--surface) 55%);
    border: 1px solid rgba(88,101,242,.32);
}
.bloc-discord__logo {
    width: 88px; height: 88px;
    display: grid; place-items: center;
    border-radius: 24px;
    background: linear-gradient(150deg, #5865F2, #3C45C4);
    box-shadow: var(--biseau-fort), 0 18px 40px -14px rgba(88,101,242,.8);
    animation: flotte 5.5s ease-in-out infinite;
    perspective: 600px;
    flex-shrink: 0;
}
.bloc-discord__logo svg { width: 48px; height: 48px; color: #fff; transition: transform .8s var(--ressort); }
.bloc-discord:hover .bloc-discord__logo svg { transform: rotateY(360deg); }

/* ==================== PIED DE PAGE ==================== */

.pied {
    margin-top: 4rem;
    padding: 4rem 0 2.5rem;
    border-top: 1px solid var(--bord);
    background: linear-gradient(var(--noir), var(--fond));
}
.pied__grille {
    display: grid;
    grid-template-columns: 1.5fr repeat(3, 1fr);
    gap: 2.5rem;
    margin-bottom: 3rem;
}
.pied h4 {
    font-size: .72rem;
    font-weight: 800;
    letter-spacing: .16em;
    text-transform: uppercase;
    color: var(--texte-faible);
    margin-bottom: 1.1rem;
}
.pied ul { list-style: none; margin: 0; padding: 0; display: grid; gap: .6rem; }
.pied ul a { font-size: .9rem; color: var(--texte-doux); transition: color .25s, transform .25s var(--douce); display: inline-block; }
.pied ul a:hover { color: var(--violet-clair); transform: translateX(4px); }
.pied__bas {
    display: flex;
    flex-wrap: wrap;
    gap: 1rem;
    justify-content: space-between;
    align-items: center;
    padding-top: 2rem;
    border-top: 1px solid var(--bord-clair);
    font-size: .82rem;
    color: var(--texte-faible);
}

/* ==================== CHAMP MAGNETIQUE ("BULLES") ====================
   Tout element porteur de .bulle reagit a la PROXIMITE du curseur, sans
   qu'il ait besoin d'etre survole : il grossit et derive doucement vers la
   souris a mesure qu'elle approche, et revient exactement a sa taille des
   qu'elle s'eloigne. C'est ce qui donne la sensation que la page entiere
   respire autour du pointeur.

   ON N'ECRIT PAS `transform`, ET C'EST TOUT L'ENJEU.
   Les cartes utilisent deja `transform` pour leur inclinaison 3D, et les
   boutons pour leur survol. Ecrire `transform` en JS ecraserait les deux.
   On passe donc par `translate` et `scale`, les proprietes individuelles :
   le navigateur les compose AVEC `transform` au lieu de les remplacer.
   Trois effets sur le meme element, aucun conflit. */

.bulle {
    /* LE PIVOT PASSE PAR `transform`, LE RESTE PAR `translate` ET `scale`.
       Trois proprietes distinctes, donc trois effets qui se composent au lieu
       de s'ecraser : le JS ecrit translate et scale en ligne, le CSS garde la
       main sur l'inclinaison via deux variables. */
    transform: perspective(1000px)
               rotateX(var(--rx, 0deg))
               rotateY(var(--ry, 0deg));
    transition: translate .5s var(--douce),
                scale .5s var(--douce),
                transform .5s var(--douce);
}
/* La transition est plus lente au RETOUR qu'a l'aller : approcher est vif,
   s'eloigner se pose. C'est ce decalage qui fait "vivant" plutot que
   "mecanique". */
.bulle:not(.bulle--proche) {
    transition: translate .85s var(--douce),
                scale .85s var(--douce),
                transform .85s var(--douce);
}
/* `will-change` UNIQUEMENT PENDANT L'EFFET, JAMAIS EN PERMANENCE.
   Cette propriete demande au navigateur de promouvoir l'element sur une
   couche GPU dediee. Posee sur `.bulle`, elle en creait SOIXANTE d'un coup,
   des le chargement, sur une page qui a deja un flou d'arriere-plan sur sa
   barre de navigation. Le compositeur saturait : la page se figeait
   plusieurs secondes sans qu'aucun script ne tourne — un blocage
   introuvable au debogueur, puisqu'il n'est pas dans le JavaScript.
   Ici, seuls les deux ou trois elements reellement sous le curseur sont
   promus, et ils reviennent au flux des que la souris s'eloigne. */
.bulle--proche { will-change: translate, scale, transform; }

/* ==================== CHARGEMENT ====================
   Le cristal du logo, en petit, qui tourne pendant qu'on attend. Il sert
   partout : verification d'un pseudo, passage d'une page a l'autre. */

.chargeur {
    display: inline-grid;
    place-items: center;
    width: 38px; height: 38px;
    perspective: 300px;
    flex-shrink: 0;
}
.chargeur__cristal {
    position: relative;
    width: 22px; height: 22px;
    transform-style: preserve-3d;
    animation: charge 1.5s linear infinite;
}
.chargeur__cristal i {
    position: absolute;
    inset: 0;
    background: linear-gradient(160deg, var(--violet-clair), var(--violet) 50%, var(--violet-nuit));
    clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);
    opacity: .9;
}
.chargeur__cristal i:nth-child(1) { transform: rotateY(0deg)   translateZ(7px); }
.chargeur__cristal i:nth-child(2) { transform: rotateY(90deg)  translateZ(7px); }
.chargeur__cristal i:nth-child(3) { transform: rotateY(180deg) translateZ(7px); }
.chargeur__cristal i:nth-child(4) { transform: rotateY(270deg) translateZ(7px); }
@keyframes charge {
    from { transform: rotateX(-18deg) rotateY(0deg); }
    to   { transform: rotateX(-18deg) rotateY(360deg); }
}

/* Voile de transition entre deux pages. Il ne masque pas la page : il pose
   un cristal au centre pendant les quelques centaines de millisecondes de
   navigation, pour que le clic ait une reponse immediate. */
.voile {
    position: fixed;
    inset: 0;
    z-index: 200;
    display: grid;
    place-items: center;
    background: rgba(6, 5, 16, .72);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    opacity: 0;
    pointer-events: none;
    transition: opacity .3s var(--net);
}
.voile.visible { opacity: 1; pointer-events: all; }
.voile .chargeur { width: 90px; height: 90px; perspective: 700px; }
.voile .chargeur__cristal { width: 52px; height: 52px; }
.voile .chargeur__cristal i:nth-child(1) { transform: rotateY(0deg)   translateZ(17px); }
.voile .chargeur__cristal i:nth-child(2) { transform: rotateY(90deg)  translateZ(17px); }
.voile .chargeur__cristal i:nth-child(3) { transform: rotateY(180deg) translateZ(17px); }
.voile .chargeur__cristal i:nth-child(4) { transform: rotateY(270deg) translateZ(17px); }

/* ==================== DIAPORAMA DES MODES ====================
   Trois images par mode, qui se succedent en fondu. Les images sont
   empilees au meme endroit et l'on ne change que l'opacite : aucun
   deplacement, donc aucun recalcul de mise en page a chaque transition. */

.diapo { position: relative; width: 100%; height: 100%; }
.diapo img {
    position: absolute;
    inset: 0;
    width: 100%; height: 100%;
    object-fit: cover;
    opacity: 0;
    transform: scale(1.06);
    transition: opacity 1.1s var(--net), transform 5s linear;
}
.diapo img.active { opacity: 1; transform: scale(1); }

.diapo__points {
    position: absolute;
    bottom: .7rem; left: 50%;
    transform: translateX(-50%);
    display: flex;
    gap: .4rem;
    z-index: 2;
}
.diapo__points b {
    width: 6px; height: 6px;
    border-radius: 50%;
    background: rgba(255,255,255,.3);
    transition: width .4s var(--douce), background .4s;
}
.diapo__points b.active { width: 18px; border-radius: 3px; background: var(--teinte, var(--violet)); }

/* ==================== SITES DE VOTE ====================
   Ces blocs etaient des cartes ordinaires : rien ne disait qu'on pouvait
   cliquer dessus. Un lien qui ne ressemble pas a un lien n'est pas clique.
   On ajoute donc les trois signaux qui manquaient : une fleche qui avance,
   un liseré qui s'allume, et un intitule d'action ecrit noir sur blanc. */

.site-vote {
    position: relative;
    display: block;
    padding: 1.6rem 1.8rem;
    background: linear-gradient(155deg, var(--surface), var(--fond-2));
    border: 1px solid var(--bord-fort);
    border-radius: var(--r-l);
    box-shadow: var(--biseau), var(--ombre-douce);
    overflow: hidden;
    isolation: isolate;
    transition: border-color .35s var(--net), box-shadow .4s var(--douce);
}
.site-vote::before {
    content: '';
    position: absolute;
    inset: -1px;
    z-index: -1;
    border-radius: inherit;
    background: radial-gradient(18rem 14rem at var(--mx, 50%) var(--my, 50%),
                rgba(242,179,61,.26), transparent 66%);
    opacity: 0;
    transition: opacity .4s var(--net);
}
.site-vote:hover::before { opacity: 1; }
.site-vote:hover {
    border-color: var(--or);
    box-shadow: var(--biseau-fort), 0 20px 46px -20px rgba(242,179,61,.75);
}

.site-vote__action {
    display: inline-flex;
    align-items: center;
    gap: .5rem;
    margin-top: 1.2rem;
    padding: .5rem 1rem;
    font-family: 'Outfit', sans-serif;
    font-size: .88rem;
    font-weight: 700;
    color: var(--or);
    background: rgba(242,179,61,.12);
    border: 1px solid rgba(242,179,61,.36);
    border-radius: var(--r-s);
    box-shadow: var(--biseau);
    transition: background .3s, color .3s, gap .35s var(--douce);
}
.site-vote:hover .site-vote__action {
    background: var(--or);
    color: #1A1206;
    gap: .85rem;
}
.site-vote__action svg { width: 15px; height: 15px; }

/* La petite icone "lien externe", en haut a droite : le signe universel
   qui dit "ceci ouvre un autre site". */
.site-vote__externe {
    position: absolute;
    top: 1.1rem; right: 1.2rem;
    width: 16px; height: 16px;
    color: var(--texte-faible);
    transition: color .3s, translate .4s var(--douce);
}
.site-vote:hover .site-vote__externe { color: var(--or); translate: 2px -2px; }

/* ==================== BOUTON DE SON ==================== */

.son {
    display: grid;
    place-items: center;
    width: 36px; height: 36px;
    background: rgba(255,255,255,.04);
    border: 1px solid var(--bord);
    border-radius: var(--r-s);
    box-shadow: var(--biseau);
    cursor: pointer;
    color: var(--texte-doux);
    padding: 0;
    transition: color .3s, border-color .3s, background .3s;
}
.son:hover { color: var(--violet-clair); border-color: var(--bord-fort); }
.son svg { width: 17px; height: 17px; }
.son .coupe { display: none; }
.son[aria-pressed="false"] { color: var(--texte-faible); }
.son[aria-pressed="false"] .actif { display: none; }
.son[aria-pressed="false"] .coupe { display: block; }

/* ==================== ETIQUETTE "CONFIGURABLE" ==================== */

.config-tag {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    padding: .22rem .6rem;
    font-size: .66rem;
    font-weight: 800;
    letter-spacing: .1em;
    color: var(--or);
    background: rgba(242,179,61,.13);
    border: 1px solid rgba(242,179,61,.3);
    border-radius: 5px;
    white-space: nowrap;
}
.config-tag svg { width: 11px; height: 11px; }

/* ==================== APPARITION AU DEFILEMENT ==================== */

.reveal {
    opacity: 0;
    transform: translateY(26px);
    transition: opacity .8s var(--douce), transform .8s var(--douce);
}
.reveal.vu { opacity: 1; transform: none; }

/* Barre de progression de lecture, en haut de page. */
.progression {
    position: fixed;
    top: 0; left: 0;
    height: 2px;
    width: 0;
    z-index: 101;
    background: linear-gradient(90deg, var(--violet), var(--bleu));
    box-shadow: 0 0 12px rgba(168,85,247,.8);
    transition: width .1s linear;
}

/* ==================== ADAPTATION AUX ECRANS ==================== */

@media (max-width: 1080px) {
    .hero__grille { grid-template-columns: 1fr; text-align: center; }
    .hero .lead, .hero .eyebrow { margin-inline: auto; }
    .hero__actions { justify-content: center; }
    .scene { order: -1; min-height: 300px; }
    .wiki { grid-template-columns: 1fr; }
    .wiki__menu { position: static; display: flex; flex-wrap: wrap; }
    .pied__grille { grid-template-columns: 1fr 1fr; }
}

@media (max-width: 860px) {
    .liens {
        position: fixed;
        inset: var(--nav-h) 0 auto;
        flex-direction: column;
        align-items: stretch;
        gap: .3rem;
        padding: 1.2rem;
        background: rgba(9,8,20,.97);
        backdrop-filter: blur(20px);
        -webkit-backdrop-filter: blur(20px);
        border-bottom: 1px solid var(--bord);
        transform: translateY(-120%);
        transition: transform .45s var(--douce);
    }
    .liens.ouvert { transform: none; }
    .liens a { padding: .8rem 1rem; font-size: 1rem; }
    .liens a::after { display: none; }
    .burger { display: grid; }
    .mode__detail-inner { grid-template-columns: 1fr; gap: 1.4rem; }
    .repli__contenu { grid-template-columns: 1fr; }
    .bloc-discord { grid-template-columns: 1fr; text-align: center; justify-items: center; }
}

@media (max-width: 620px) {
    :root { --nav-h: 64px; }
    .mode { grid-template-columns: auto 1fr; padding: 1.2rem; gap: 1rem; }
    .mode__rang { display: none; }
    .mode__fleche { display: none; }
    .mode__icone { width: 58px; height: 58px; }
    .mode__icone svg { width: 32px; height: 32px; }
    .mode__detail-inner { padding: 1.3rem; }
    .pied__grille { grid-template-columns: 1fr; gap: 2rem; }
    .discord-flottant { width: 54px; height: 54px; }
    .discord-flottant::after { display: none; }
    .ip { font-size: .92rem; padding-left: 1rem; }
}

/* ==================== MOUVEMENT REDUIT ====================
   Un visiteur qui a demande moins d'animations au systeme le fait pour une
   raison — vertiges, migraines, trouble vestibulaire. On coupe TOUT ce qui
   bouge, et l'on garde le site parfaitement utilisable : les elements
   reveles restent visibles, les panneaux s'ouvrent d'un coup. */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: .001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: .001ms !important;
        scroll-behavior: auto !important;
    }
    .reveal { opacity: 1; transform: none; }
    /* Le champ magnetique est ce qui bouge le plus sur ce site : c'est la
       premiere chose a couper. */
    .bulle {
        translate: none !important;
        scale: none !important;
        transform: none !important;
    }
    .voile { display: none; }
}

/* Impression : le reglement et le wiki finissent parfois sur papier. */
@media print {
    body::before, body::after, .nav, .discord-flottant, .voxels, .pied { display: none !important; }
    body { background: #fff; color: #000; }
    .carte, .repli { border: 1px solid #ccc; box-shadow: none; background: #fff; }
    .repli__corps { grid-template-rows: 1fr !important; }
    * { color: #000 !important; }
}
