/* ==========================================================================
   FASTGF — SYSTEME DE DESIGN (theme Azuriom)
   --------------------------------------------------------------------------
   Ce fichier reproduit, a l'identique, le langage visuel de fastgf.fr :
   les memes jetons de couleur, le meme biseau, les memes courbes, les memes
   composants. Il est volontairement INDEPENDANT de Bootstrap — c'est
   `bridge.css` qui traduit ensuite les classes Bootstrap d'Azuriom vers ce
   vocabulaire-ci.

   POURQUOI DEUX FICHIERS. Azuriom et ses plugins produisent du HTML qu'on ne
   controle pas entierement (modales, paginations, formulaires de passerelle).
   Un theme qui ne redefinirait que ses propres classes laisserait ces
   morceaux-la en Bootstrap brut. Un theme qui n'ecrirait que des surcharges
   Bootstrap, lui, perdrait l'identite des qu'on ecrit une page a la main.
   On garde donc les deux : le vocabulaire FastGF ici, sa traduction a cote.

   RIEN N'EST INVENTE : chaque valeur vient de assets/css/style.css du site
   principal, qui n'est pas modifie.
   ========================================================================== */

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

    color-scheme: dark;
}

/* ==================== 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;
    min-height: 100%;
    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. */
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%; height: auto; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; }

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

::-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); }

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

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

h1, h2, h3, h4, h5, h6, .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.1rem, 5.5vw, 3.6rem); }
h2 { font-size: clamp(1.7rem, 4vw, 2.7rem); }
h3 { font-size: clamp(1.15rem, 2.2vw, 1.5rem); letter-spacing: -.02em; }
h4 { font-size: 1.1rem; letter-spacing: -.02em; }
h5 { font-size: 1rem; letter-spacing: -.015em; }
h6 { font-size: .92rem; letter-spacing: -.01em; }

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

code, kbd, samp, pre {
    font-family: ui-monospace, 'SFMono-Regular', Menlo, Consolas, monospace;
    font-size: .88em;
}
code {
    padding: .12rem .38rem;
    color: var(--violet-clair);
    background: rgba(168,85,247,.12);
    border-radius: 5px;
}
pre {
    padding: 1rem 1.2rem;
    overflow-x: auto;
    background: var(--noir);
    border: 1px solid var(--bord);
    border-radius: var(--r-m);
}
pre code { background: none; padding: 0; color: var(--texte-doux); }

hr { border: 0; border-top: 1px solid var(--bord-clair); margin: 1.5rem 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. */
.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;
}
.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);
}

/* ==================== LA LARGEUR DE LA BARRE ====================

   LE MENU AVAIT GLISSE VERS LA GAUCHE, ET C'ETAIT ARITHMETIQUE.

   Sur fastgf.fr, `.marque` pousse `.liens` contre le bord droit : la derniere
   entree, « Recrutement », touche la marge. En ajoutant le groupe Azuriom
   APRES lui — notifications, panier, compte, environ 200 px — tout le menu
   reculait d'autant. Il n'etait pas casse, il etait pousse ; mais l'oeil, lui,
   voyait un menu qui n'est plus a sa place.

   On ne peut pas ajouter quelque chose a droite d'un menu colle a droite sans
   le deplacer. La seule issue est d'ELARGIR LA BARRE d'a peu pres la largeur
   du groupe ajoute : le menu retrouve alors sa position, et les pastilles
   occupent l'espace gagne. La barre sort du gabarit de 1240 px du contenu,
   mais c'est deja le cas sur le site principal (1400 px) — une barre de
   navigation n'a jamais eu la meme largeur que le texte qu'elle surplombe.

   Sur un ecran plus etroit que 1620 px, `100% - 2rem` reprend la main et le
   menu se comporte comme avant : rien n'est casse, on a seulement cesse de
   gaspiller la place quand il y en a. */
.nav .wrap {
    display: flex;
    align-items: center;
    gap: 1.5rem;
    width: min(100% - 2rem, 1620px);
}

/* L'ecart entre le menu et le groupe Azuriom : franc, pour qu'on lise deux
   ensembles et non une seule longue rangee. C'est ce qui fait comprendre que
   les pastilles sont un AJOUT a un menu connu, pas une partie de ce menu. */
.nav .liens { margin-right: .4rem; }

.marque { display: flex; align-items: center; gap: .7rem; margin-right: auto; }
.marque img {
    width: 40px; height: 40px;
    display: block;
    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);
    white-space: nowrap;
    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 grandit depuis le centre : le mouvement est symetrique. */
.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%; }

/* Le menu deroulant de la navbar (compte, elements Azuriom en dropdown).
   Il vit dans `.liens` et reprend exactement la matiere des cartes. */
.menu-deroulant { position: relative; }
.menu-deroulant > button {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    padding: .5rem .85rem;
    font-size: .9rem;
    font-weight: 600;
    color: var(--texte-doux);
    background: none;
    border: 0;
    border-radius: var(--r-s);
    cursor: pointer;
    transition: color .25s var(--net), background .25s var(--net);
}
.menu-deroulant > button:hover,
.menu-deroulant.ouvert > button { color: var(--texte); background: rgba(168,85,247,.10); }
.menu-deroulant__fleche { transition: transform .35s var(--douce); }
.menu-deroulant.ouvert .menu-deroulant__fleche { transform: rotate(180deg); }

.menu-deroulant__panneau {
    position: absolute;
    top: calc(100% + .5rem);
    right: 0;
    min-width: 230px;
    z-index: 110;
    display: grid;
    gap: .15rem;
    padding: .5rem;
    background: linear-gradient(160deg, var(--surface-2), var(--fond-2));
    border: 1px solid var(--bord-fort);
    border-radius: var(--r-m);
    box-shadow: var(--biseau), var(--ombre);
    opacity: 0;
    visibility: hidden;
    transform: translateY(-8px);
    transition: opacity .28s var(--net), transform .35s var(--douce), visibility .28s;
}
.menu-deroulant.ouvert .menu-deroulant__panneau {
    opacity: 1;
    visibility: visible;
    transform: none;
}
.menu-deroulant__panneau a,
.menu-deroulant__panneau button {
    display: flex;
    align-items: center;
    gap: .6rem;
    width: 100%;
    padding: .55rem .75rem;
    font-size: .88rem;
    font-weight: 600;
    text-align: left;
    color: var(--texte-doux);
    background: none;
    border: 0;
    border-radius: var(--r-s);
    cursor: pointer;
    transition: color .22s var(--net), background .22s var(--net), transform .25s var(--douce);
}
.menu-deroulant__panneau a:hover,
.menu-deroulant__panneau button:hover {
    color: var(--texte);
    background: rgba(168,85,247,.12);
    transform: translateX(3px);
}
.menu-deroulant__panneau a.actif { color: var(--violet-clair); }
.menu-deroulant__panneau hr { margin: .35rem .25rem; }
.menu-deroulant__panneau .sous-titre {
    padding: .35rem .75rem .15rem;
    font-size: .66rem;
    font-weight: 800;
    letter-spacing: .14em;
    text-transform: uppercase;
    color: var(--texte-faible);
}

.menu-deroulant__avatar {
    width: 24px; height: 24px;
    border-radius: 5px;
    image-rendering: pixelated;
}

/* ==================== LE GROUPE AZURIOM DE LA BARRE ====================

   CE QUE LA BOUTIQUE AJOUTE AU MENU DE FASTGF.FR, ET RIEN D'AUTRE.

   Le menu de gauche est celui du site principal, a l'identique. Ce groupe-ci
   est la seule chose qui le distingue : le panier, les notifications, le
   compte. Il arrive donc EN GLISSANT DEPUIS LA DROITE, l'un apres l'autre,
   au chargement de la boutique — le visiteur voit son menu habituel auquel
   quelque chose vient de s'ajouter, pas un autre menu.

   CE SONT DES BULLES, PAS DES BOUTONS EN LIGNE. Un long rectangle
   « Panier | Mes paiements | Mon compte » alourdit la barre et se lit comme
   un second menu. Des pastilles rondes, de la meme matiere que le bouton
   Discord flottant, se lisent comme des outils — et tiennent sur un
   telephone sans rien casser. */

.azuriom { display: flex; align-items: center; gap: .5rem; margin-left: .6rem; }

/* ==================== L'ALIGNEMENT D'UNE BULLE ====================

   LE PICTOGRAMME ETAIT DECALE VERS LA DROITE, ET CE N'ETAIT PAS UN HASARD.

   Trois causes se cumulaient, et chacune suffisait :

     1. `.nav-link` de Bootstrap porte un `padding: .5rem 1rem`. Dans une
        bulle de 42 px en `border-box`, il ne restait que 10 px de boite de
        contenu, et le glyphe debordait de son cote.
     2. Un `<i>` de Bootstrap Icons est une boite EN LIGNE : lui donner une
        largeur ne fait rien, et sa chasse (la largeur d'avance du glyphe)
        n'est pas celle du dessin. Le centrage portait donc sur une boite
        plus large que ce qu'on voit.
     3. Le corps du site pose `letter-spacing: -.005em`, qui s'ajoute APRES
        le glyphe — un demi-pixel de decalage, toujours du meme cote.

   On remet donc tout a plat : padding a zero, `line-height: 1`, plus de
   chasse residuelle, et un centrage par `flex` sur une boite que le glyphe
   ne peut plus deborder. */
.bulle-outil,
.nav-notifications .nav-link {
    position: relative;
    display: flex !important;
    align-items: center;
    justify-content: center;
    width: 42px; height: 42px;
    flex-shrink: 0;
    padding: 0 !important;
    margin: 0;
    line-height: 1;
    letter-spacing: 0;
    text-indent: 0;
    color: var(--texte-doux);
    background: linear-gradient(150deg, var(--surface-2), var(--fond-2));
    border: 1px solid var(--bord);
    border-radius: 14px;
    box-shadow: var(--biseau), var(--ombre-douce);
    cursor: pointer;
    transition: color .3s var(--net), border-color .35s var(--net),
                border-radius .5s var(--douce), box-shadow .45s var(--douce);
}
.bulle-outil:hover,
.nav-notifications .nav-link:hover,
.menu-deroulant.ouvert > .bulle-outil {
    color: var(--texte);
    border-color: var(--violet);
    border-radius: 20px;
    box-shadow: var(--biseau-fort), 0 18px 40px -16px rgba(168,85,247,.9);
}

/* Le glyphe lui-meme : une boite carree, centree, sans chasse ni
   `vertical-align` heritee de Bootstrap Icons. */
.bulle-outil > i,
.bulle-outil > svg,
.nav-notifications .nav-link > i,
.nav-notifications .nav-link > svg {
    display: block;
    width: 20px; height: 20px;
    font-size: 19px;
    line-height: 20px;
    text-align: center;
    vertical-align: middle;
}
.bulle-outil > i::before,
.nav-notifications .nav-link > i::before {
    display: block;
    width: 100%;
    vertical-align: middle;
}
.bulle-outil > img {
    display: block;
    width: 26px; height: 26px;
    border-radius: 8px;
    image-rendering: pixelated;
}

/* Le compteur du panier. Il sort du cadre : c'est ce qui le fait remarquer
   sans qu'il ait besoin de clignoter. */
.bulle-outil__compteur {
    position: absolute;
    top: -6px; right: -6px;
    display: grid;
    place-items: center;
    min-width: 20px; height: 20px;
    padding: 0 .3rem;
    font-family: 'Inter', sans-serif;
    font-size: .68rem;
    font-weight: 800;
    color: #fff;
    background: linear-gradient(135deg, var(--violet), var(--bleu));
    border: 2px solid var(--fond);
    border-radius: 99px;
    box-shadow: 0 0 14px rgba(168,85,247,.8);
    animation: pastille-arrive .5s var(--ressort) backwards;
}
@keyframes pastille-arrive {
    from { opacity: 0; transform: scale(.2); }
    to   { opacity: 1; transform: none; }
}

/* Le bouton de connexion. C'est le seul element du groupe qui porte du
   texte : sans compte, aucun achat n'est possible, et le dire vaut mieux
   que de le faire deviner derriere une icone. */
.bulle-connexion {
    display: inline-flex;
    align-items: center;
    gap: .55rem;
    padding: .62rem 1.05rem;
    font-family: 'Outfit', sans-serif;
    font-size: .88rem;
    font-weight: 700;
    letter-spacing: -.01em;
    white-space: nowrap;
    color: #fff;
    background: linear-gradient(135deg, var(--violet) 0%, var(--violet-fonce) 55%, var(--bleu) 130%);
    border: 1px solid transparent;
    border-radius: 14px;
    box-shadow: var(--biseau-fort), 0 14px 32px -14px rgba(168,85,247,.9);
    overflow: hidden;
    isolation: isolate;
    transition: border-radius .5s var(--douce), box-shadow .45s var(--douce);
}
.bulle-connexion:hover {
    border-radius: 20px;
    box-shadow: var(--biseau-fort), 0 22px 48px -16px rgba(168,85,247,1);
}
.bulle-connexion::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);
}
.bulle-connexion:hover::before { transform: translateX(130%); }
.bulle-connexion svg { width: 16px; height: 16px; flex: none; }
.bulle-connexion span { display: inline; }

/* L'ARRIVEE. Chaque bulle glisse depuis la droite, decalee de 70 ms sur la
   precedente. `backwards` retient l'etat initial pendant le delai : sans
   lui, les bulles seraient affichees en clair puis disparaitraient pour
   reapparaitre. */
@keyframes azuriom-arrive {
    from { opacity: 0; transform: translateX(22px) scale(.82); filter: blur(5px); }
    to   { opacity: 1; transform: none; filter: none; }
}
.azuriom > * { animation: azuriom-arrive .65s var(--douce) backwards; }
.azuriom > *:nth-child(1) { animation-delay: .20s; }
.azuriom > *:nth-child(2) { animation-delay: .27s; }
.azuriom > *:nth-child(3) { animation-delay: .34s; }
.azuriom > *:nth-child(4) { animation-delay: .41s; }

/* Les notifications d'Azuriom arrivent en <li> : il leur faut leur <ul>,
   qui ne doit pas se voir. Le lien natif est repeint en bulle plus haut,
   avec le panier et le compte — une seule regle pour les trois, donc aucun
   risque qu'ils divergent d'un pixel.

   Le chevron de `dropdown-toggle` est retire : dans une pastille de 42 px,
   il decale le pictogramme et ne designe rien. */
.nav-notifications { list-style: none; margin: 0; padding: 0; display: flex; }
.nav-notifications .nav-link::after { display: none !important; }
.nav-notifications .badge {
    position: absolute;
    top: -6px; right: -6px;
    border: 2px solid var(--fond);
    background: linear-gradient(135deg, var(--violet), var(--bleu)) !important;
    color: #fff !important;
}

/* Le panneau des notifications est un `dropdown-menu` de Bootstrap : il est
   ancre sur la bulle, et sur un telephone il sortirait de l'ecran par la
   droite. On le recale sous la barre, en pleine largeur utile. */
.azuriom .dropdown-menu {
    min-width: 290px;
    max-width: calc(100vw - 2rem);
}

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

/* La pastille du panier, posee sur son lien de navigation. */
.pastille-compteur {
    display: inline-grid;
    place-items: center;
    min-width: 18px;
    height: 18px;
    margin-left: .35rem;
    padding: 0 .35rem;
    font-family: 'Inter', sans-serif;
    font-size: .68rem;
    font-weight: 800;
    color: #fff;
    background: linear-gradient(135deg, var(--violet), var(--bleu));
    border-radius: 99px;
    box-shadow: 0 0 12px rgba(168,85,247,.6);
}

/* ==================== 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;
    color: var(--texte);
    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;
    text-align: center;
    transition: transform .35s var(--ressort), box-shadow .35s var(--douce),
                border-color .3s, background .3s;
}
.btn:hover { border-color: var(--violet); box-shadow: var(--biseau), var(--lueur); }
.btn:active { filter: brightness(.88); }
.btn:disabled, .btn[disabled], .btn.disabled {
    opacity: .5;
    pointer-events: none;
    box-shadow: var(--biseau);
}

.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. */
.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--petit { padding: .5rem 1rem; font-size: .84rem; border-radius: var(--r-s); }
.btn--plein { width: 100%; }
.btn--inerte { pointer-events: none; filter: grayscale(1); opacity: .55; }

/* ==================== LA COULEUR DIT CE QUE FAIT LE BOUTON ====================

   Trois familles, et jamais deux du meme ton cote a cote :

     violet  ACHETER        — le geste qui remplit le panier ;
     vert    PAYER          — celui qui finit la commande, et lui seul ;
     rouge   DETRUIRE       — retirer une ligne, vider le panier, annuler.

   Un panier entierement violet ne disait rien : « Mettre a jour », « Vider »
   et « Payer » avaient exactement la meme tete, et il fallait lire chaque
   libelle pour savoir lequel etait dangereux. */

/* ---- ROUGE : ce qui retire ou annule ---- */
.btn--danger {
    background: linear-gradient(135deg, #E5484D 0%, #B32731 100%);
    border-color: rgba(255,120,130,.5);
    color: #fff;
    box-shadow: var(--biseau-fort), 0 12px 28px -14px rgba(229,72,77,.85);
}
.btn--danger:hover {
    border-color: #FF8A93;
    color: #fff;
    box-shadow: var(--biseau-fort), 0 20px 46px -16px rgba(229,72,77,1);
}
/* La croix qui retire une ligne : carree, rouge pleine, sans libelle. Elle
   doit se reconnaitre a la forme et a la couleur, pas se lire. */
.btn--croix {
    width: 34px;
    height: 34px;
    padding: 0;
    gap: 0;
    flex-shrink: 0;
    border-radius: var(--r-s);
}
.btn--croix i { display: block; font-size: 14px; line-height: 1; }

/* ---- VERT : le paiement, et rien d'autre ---- */
.btn--payer {
    background: linear-gradient(135deg, #34D399 0%, #0E9F6E 55%, #2F7DF6 150%);
    border-color: transparent;
    color: #04231A;
    box-shadow: var(--biseau-fort), 0 14px 34px -14px rgba(52,211,153,.9);
}
.btn--payer:hover {
    border-color: transparent;
    color: #04231A;
    box-shadow: var(--biseau-fort), 0 22px 50px -16px rgba(52,211,153,1);
}
.btn--payer::before {
    content: '';
    position: absolute;
    inset: 0;
    z-index: -1;
    background: linear-gradient(105deg, transparent 35%, rgba(255,255,255,.42) 50%, transparent 65%);
    transform: translateX(-130%);
    transition: transform .75s var(--douce);
}
.btn--payer:hover::before { transform: translateX(130%); }

/* ---- LA SURBRILLANCE DU BOUTON D'ACHAT ----
   Sur une carte d'article, le bouton est ce qu'on cherche : il doit se voir
   avant le texte. Un lisere qui respire tres lentement le signale sans
   clignoter — un clignotement se fait ignorer en trois secondes, une
   respiration se remarque. */
@keyframes respire-achat {
    0%, 100% { box-shadow: var(--biseau-fort), 0 0 0 0 rgba(168,85,247,.42), 0 14px 34px -14px rgba(168,85,247,.9); }
    50%      { box-shadow: var(--biseau-fort), 0 0 0 7px rgba(168,85,247,0), 0 18px 40px -14px rgba(168,85,247,1); }
}
.btn--achat {
    animation: respire-achat 3.2s var(--douce) infinite;
    font-size: 1rem;
    padding: .95rem 1.6rem;
}
.btn--achat:hover {
    animation: none;
    box-shadow: var(--biseau-fort), 0 0 0 3px rgba(201,165,255,.5), 0 22px 50px -16px rgba(168,85,247,1);
}
/* Le survol d'une carte allume son bouton : le geste est le meme, la
   reponse doit l'etre aussi. */
.grade:hover .btn--achat { animation: none; box-shadow: var(--biseau-fort), 0 0 0 3px rgba(201,165,255,.4), 0 20px 46px -16px rgba(168,85,247,1); }

/* ==================== CARTES ====================
   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.
   Les variables --mx / --my sont posees par le champ magnetique (fastgf.js).
   ================================================================== */

.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 { transform-style: preserve-3d; }
.carte3d > * { transform: translateZ(28px); }

/* LE HALO SOUS LE CURSEUR. */
.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); }

.carte--serree { padding: 1.3rem 1.5rem; }
.carte--violette { background: linear-gradient(120deg, rgba(168,85,247,.09), var(--surface) 60%); }
.carte--doree {
    background: linear-gradient(120deg, rgba(242,179,61,.10), var(--surface) 60%);
    border-color: rgba(242,179,61,.28);
}
.carte.possede { opacity: .74; }
.carte.possede:hover { opacity: 1; }

/* ==================== ETIQUETTES ET LISTES ==================== */

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

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

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

/* ==================== ADRESSE DU SERVEUR ==================== */

.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 » d'une 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; }
}

/* ==================== L'ACCUEIL DE LA BOUTIQUE ==================== */

.contenu--accueil { padding-bottom: 0; }

.accueil__actions {
    display: flex;
    flex-wrap: wrap;
    gap: .9rem;
    align-items: center;
    margin-top: 1.8rem;
}
.entete-section.centre .accueil__actions { justify-content: center; }

.accueil__serveur {
    display: flex;
    flex-wrap: wrap;
    gap: .9rem;
    align-items: center;
    margin-top: 1.6rem;
}
.entete-section.centre .accueil__serveur { justify-content: center; }

/* ==================== ARTICLES (grades, packs, jetons) ==================== */

.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);
    z-index: 2;
}
.grade__image {
    display: block;
    width: 100%;
    max-height: 170px;
    object-fit: contain;
    margin-bottom: 1.2rem;
    filter: drop-shadow(0 12px 24px rgba(0,0,0,.6));
    transition: transform .55s var(--ressort);
}
.grade:hover .grade__image { transform: scale(1.06) rotate(-1.5deg); }
.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; flex-wrap: wrap; }
.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;
}
.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; }

/* Le bas d'une carte d'article. Les boutons ETAIENT COLLES : un ajout au
   panier et un retrait a deux pixels l'un de l'autre, c'est une commande
   annulee par erreur. L'ecart est franc, et le lien de detail se detache du
   bouton d'achat par sa forme, pas seulement par sa couleur. */
.grade__actions { display: grid; gap: .6rem; }
.grade__actions form { display: contents; }
.grade__detail {
    display: inline-block;
    margin-top: .2rem;
    text-align: center;
    font-size: .82rem;
    font-weight: 650;
    color: var(--texte-faible);
    text-decoration: underline;
    text-underline-offset: 3px;
    text-decoration-color: var(--bord-fort);
    transition: color .25s var(--net);
}
.grade__detail:hover { color: var(--violet-clair); }

.grade__indispo {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: .5rem;
    padding: .82rem 1rem;
    font-size: .86rem;
    font-weight: 650;
    color: var(--texte-faible);
    background: rgba(255,255,255,.03);
    border: 1px dashed var(--bord-clair);
    border-radius: var(--r-m);
}

/* La description libre d'un article, saisie dans l'admin Azuriom : elle
   arrive en HTML complet et doit se fondre dans la carte. */
.grade__texte { font-size: .92rem; color: var(--texte-doux); }
.grade__texte :is(h1,h2,h3,h4,h5,h6) { font-size: 1.05rem; margin: 1rem 0 .5rem; }
.grade__texte ul, .grade__texte ol { margin: .6rem 0; padding-left: 1.3rem; }
.grade__texte li { margin-bottom: .35rem; }
.grade__texte img { border-radius: var(--r-m); }

/* ==================== RAYONS (les familles d'articles) ==================== */

.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 ====================
   Trois plans empiles dans le meme espace 3D (`preserve-3d`), traverses par
   un reflet oblique : c'est ce qui fait lire du verre plutot qu'un carre
   colore. Elle reprend --rx / --ry de sa carte parente en les amplifiant :
   l'objet regarde le curseur plus fort que la surface qui le porte. */
.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);
}
.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);
}
.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,
.carte-vente__icone i {
    width: 32px; height: 32px;
    font-size: 30px;
    line-height: 1;
    display: grid;
    place-items: center;
    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. */
@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,
.carte-vente__icone.tourne i { 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;
}

/* Le flottement passe par `translate`, PAS par `transform` : une animation
   @keyframes qui ecrit `transform` gagne toujours contre une regle :hover
   qui ecrit `transform`. `translate` est compose AVEC lui. */
@keyframes flotte {
    0%, 100% { translate: 0 0; }
    50%      { translate: 0 -7px; }
}

/* ==================== BANDEAU DE PROMOTION ====================
   Une seule bande, en tete. Le liseré dore anime sert de signal sans
   clignoter — un clignotement se fait ignorer en trois secondes. */

.promo-bandeau {
    position: relative;
    display: flex;
    align-items: center;
    gap: 1.1rem;
    flex-wrap: wrap;
    padding: 1.1rem 1.5rem;
    margin-bottom: clamp(2rem, 4vw, 3rem);
    border-radius: var(--r-l);
    background: linear-gradient(120deg,
        rgba(242,179,61,.16), rgba(168,85,247,.10) 55%, var(--surface) 100%);
    border: 1px solid rgba(242,179,61,.38);
    box-shadow: var(--biseau), 0 18px 44px -26px rgba(242,179,61,.7);
    overflow: hidden;
    isolation: isolate;
}
.promo-bandeau::after {
    content: '';
    position: absolute;
    inset: 0;
    z-index: -1;
    background: linear-gradient(105deg, transparent 38%,
                rgba(255,255,255,.14) 50%, transparent 62%);
    transform: translateX(-130%);
    animation: promoReflet 6s var(--douce) infinite;
}
@keyframes promoReflet {
    0%, 62%   { transform: translateX(-130%); }
    88%, 100% { transform: translateX(130%); }
}
.promo-bandeau__etiquette {
    flex-shrink: 0;
    padding: .4rem .9rem;
    font-family: 'Outfit', sans-serif;
    font-size: .78rem;
    font-weight: 800;
    letter-spacing: .12em;
    color: #1A1206;
    background: var(--or);
    border-radius: 999px;
    box-shadow: var(--biseau);
}
.promo-bandeau__texte { flex: 1; min-width: 15rem; font-size: .95rem; }
.promo-bandeau__texte strong { color: var(--texte); }

/* Le code promo se copie en un clic. Le faire recopier a la main, c'est une
   faute de frappe au moment ou le joueur est le plus pres de payer. */
.promo-bandeau__code {
    display: inline-flex;
    align-items: center;
    gap: .5rem;
    margin-left: .4rem;
    padding: .2rem .3rem .2rem .7rem;
    font-family: 'Outfit', monospace;
    font-size: .88rem;
    font-weight: 800;
    letter-spacing: .04em;
    color: var(--or);
    background: rgba(242,179,61,.14);
    border: 1px solid rgba(242,179,61,.42);
    border-radius: var(--r-s);
    cursor: pointer;
    vertical-align: middle;
    transition: background .25s var(--net), border-color .25s var(--net);
}
.promo-bandeau__code:hover { background: rgba(242,179,61,.22); border-color: var(--or); }
.promo-bandeau__code .ip__badge { font-size: .62rem; padding: .2rem .45rem; }
.promo-bandeau__code.copie .ip__badge { background: rgba(52,211,153,.18); color: var(--vert); }
.promo-bandeau__taux {
    flex-shrink: 0;
    font-family: 'Outfit', sans-serif;
    font-size: clamp(1.4rem, 4vw, 1.9rem);
    font-weight: 800;
    letter-spacing: -.02em;
    color: var(--or);
    white-space: nowrap;
}

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

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

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

/* ==================== AVIS D'ACHAT ==================== */

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

/* ==================== DISCORD ==================== */

.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;
}
/* LA RESPIRATION EST SUR L'ICONE, PAS SUR LE BOUTON : le champ magnetique
   ecrit `scale` sur le bouton, et une @keyframes gagnerait contre lui. */
.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: attr(data-infobulle);
    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); }
.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__reseaux { display: flex; flex-wrap: wrap; gap: .5rem; margin-top: 1.2rem; }
.pied__reseaux a {
    display: grid;
    place-items: center;
    width: 38px; height: 38px;
    border-radius: var(--r-s);
    color: #fff;
    box-shadow: var(--biseau);
    transition: transform .35s var(--ressort), box-shadow .35s var(--douce);
}
.pied__reseaux a:hover { transform: translateY(-3px) scale(1.06); box-shadow: var(--biseau), var(--ombre); }
/* Un intitule lisible par un lecteur d'ecran, invisible a l'oeil. Les
   icones de reseaux sociaux n'ont pas d'autre texte. */
.visuellement-cache {
    position: absolute;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}

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

/* ==================== LA PAGE BOUTIQUE ====================

   DEUX COLONNES, ET LA PLUS IMPORTANTE EST A DROITE.

   A gauche : ce qui informe — l'objectif du mois, le meilleur acheteur, les
   derniers achats. A droite : ce qui se vend. Le panier, l'historique des
   paiements et la tete du joueur ont quitte cette colonne : ils vivent
   desormais dans la barre de navigation, ou ils sont accessibles depuis
   n'importe quelle page au lieu de n'exister que sur celle-ci.

   SUR TELEPHONE, LA COLONNE PASSE EN DESSOUS. Le classement des acheteurs
   est un a-cote : le lire avant les articles n'a aucun sens sur un ecran ou
   tout est empile. `order` le renvoie en bas sans toucher au HTML, donc
   sans changer l'ordre de lecture d'un lecteur d'ecran sur grand ecran. */

.boutique {
    display: grid;
    grid-template-columns: 290px minmax(0, 1fr);
    gap: clamp(1.5rem, 3vw, 2.5rem);
    align-items: start;
}
.boutique__cote { display: grid; gap: 1rem; position: sticky; top: calc(var(--nav-h) + 1.5rem); }
.boutique__contenu { min-width: 0; }

.boutique-bloc h4 {
    display: flex;
    align-items: center;
    gap: .5rem;
    font-size: .7rem;
    font-weight: 800;
    letter-spacing: .16em;
    text-transform: uppercase;
    color: var(--texte-faible);
    margin-bottom: 1rem;
}
.boutique-bloc__note { font-size: .84rem; color: var(--texte-faible); margin: .7rem 0 0; text-align: center; }

.boutique-joueur { display: flex; align-items: center; gap: .9rem; }
.boutique-joueur img { width: 46px; height: 46px; border-radius: var(--r-s); image-rendering: pixelated; flex-shrink: 0; }
.boutique-joueur__nom { font-family: 'Outfit', sans-serif; font-weight: 800; font-size: 1.05rem; color: var(--texte); margin: 0; letter-spacing: -.02em; }
.boutique-joueur__meta { font-size: .82rem; color: var(--or); margin: 0; }

.boutique-recents { display: grid; gap: .8rem; }
.boutique-recent { display: flex; align-items: center; gap: .7rem; }
.boutique-recent img { width: 30px; height: 30px; border-radius: 6px; image-rendering: pixelated; flex-shrink: 0; }
.boutique-recent p { margin: 0; }
.boutique-recent__nom { font-size: .88rem; font-weight: 650; color: var(--texte); }
.boutique-recent__meta { font-size: .76rem; color: var(--texte-faible); }

/* La jauge de l'objectif du mois. */
.jauge {
    height: 10px;
    background: var(--noir);
    border: 1px solid var(--bord);
    border-radius: 999px;
    box-shadow: var(--biseau);
    overflow: hidden;
}
.jauge span {
    display: block;
    height: 100%;
    background: linear-gradient(90deg, var(--violet), var(--bleu));
    box-shadow: 0 0 14px rgba(168,85,247,.7);
    transition: width .8s var(--douce);
}

/* ==================== L'AVERTISSEMENT PAYPAL ====================
   Il est rouge, et c'est assume : ce n'est pas une information, c'est la
   seule condition de la boutique qui decide si une commande sera livree.
   Le fondre dans la charte violette le ferait passer pour une note de bas de
   page — et il serait lu apres le paiement, quand il ne sert plus a rien. */

.avertissement-paypal {
    display: flex;
    align-items: flex-start;
    gap: 1rem;
    padding: 1.2rem 1.4rem;
    margin-bottom: 1.5rem;
    background: linear-gradient(120deg, rgba(229,72,77,.16), rgba(20,17,39,.9) 70%);
    border: 1px solid rgba(240,91,107,.42);
    border-radius: var(--r-l);
    box-shadow: var(--biseau), 0 18px 44px -26px rgba(229,72,77,.8);
}
.avertissement-paypal__icone {
    display: grid;
    place-items: center;
    width: 40px; height: 40px;
    flex-shrink: 0;
    color: #FFC9CC;
    background: rgba(229,72,77,.18);
    border: 1px solid rgba(240,91,107,.4);
    border-radius: var(--r-m);
}
.avertissement-paypal__icone svg { width: 22px; height: 22px; }
.avertissement-paypal p { margin: 0 0 .5rem; font-size: .92rem; color: var(--texte-doux); }
.avertissement-paypal p:last-child { margin-bottom: 0; }
.avertissement-paypal strong { color: var(--texte); }
.avertissement-paypal__titre {
    font-family: 'Outfit', sans-serif;
    font-size: 1.05rem !important;
    font-weight: 800;
    letter-spacing: -.02em;
    color: #FFC9CC !important;
}
.avertissement-paypal__consequence { color: #FFC9CC !important; }
.avertissement-paypal__consequence strong { color: #fff; }
.avertissement-paypal__note { font-size: .84rem !important; color: var(--texte-faible) !important; }

@media (max-width: 560px) {
    .avertissement-paypal { padding: 1rem 1.1rem; gap: .8rem; }
    .avertissement-paypal__icone { width: 32px; height: 32px; }
    .avertissement-paypal__icone svg { width: 18px; height: 18px; }
}

/* ==================== LE PROFIL DU JOUEUR ==================== */

.profil-tete {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    gap: clamp(1.5rem, 3vw, 2.5rem);
    align-items: start;
}
.profil-tete__avatar { display: grid; justify-items: center; gap: .9rem; }
.profil-tete__avatar img {
    width: 128px; height: 128px;
    border-radius: var(--r-m);
    image-rendering: pixelated;
    box-shadow: var(--biseau), var(--ombre);
}
.profil-tete__infos { min-width: 0; }
.profil-tete__actions { display: flex; flex-wrap: wrap; gap: .7rem; margin-top: 1.4rem; }
.profil-tete__actions form { display: contents; }

/* Les faits du compte, en paires intitulé / valeur. Une liste a puces
   melangeait « Inscription » et « UUID » sur la meme ligne visuelle : l'oeil
   ne savait plus ce qui etait un libelle et ce qui etait une donnee. */
.profil-faits {
    list-style: none;
    margin: 1.2rem 0 0;
    padding: 0;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 180px), 1fr));
    gap: .9rem 1.5rem;
}
.profil-faits li {
    display: grid;
    gap: .15rem;
    padding: .7rem .9rem;
    background: rgba(255,255,255,.03);
    border: 1px solid var(--bord-clair);
    border-radius: var(--r-s);
}
.profil-faits span {
    font-size: .68rem;
    font-weight: 800;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--texte-faible);
}
.profil-faits b {
    font-family: 'Outfit', sans-serif;
    font-size: 1.05rem;
    font-weight: 800;
    letter-spacing: -.02em;
    color: var(--texte);
}
.profil-faits__inconnu { color: var(--texte-faible) !important; }
/* Un UUID fait 32 caracteres : il doit pouvoir se couper, sinon il fait
   deborder la carte sur un telephone. */
.profil-faits__uuid {
    font-family: ui-monospace, monospace !important;
    font-size: .74rem !important;
    font-weight: 500 !important;
    overflow-wrap: anywhere;
    color: var(--texte-doux) !important;
}

.profil-grade { display: grid; gap: .6rem; justify-items: start; }
.profil-grade__nom {
    font-family: 'Outfit', sans-serif;
    font-size: 1.15rem;
    font-weight: 800;
    letter-spacing: -.03em;
    color: var(--texte);
}
.profil-grade__fin { margin: 0; font-size: .82rem; color: var(--texte-faible); }

@media (max-width: 620px) {
    .profil-tete { grid-template-columns: 1fr; justify-items: center; text-align: center; }
    .profil-tete__infos { text-align: left; width: 100%; }
    .profil-tete__actions { justify-content: stretch; }
    .profil-tete__actions .btn { flex: 1 1 100%; }
}

/* ==================== LA FICHE D'UN ARTICLE ====================

   L'IMAGE ETAIT EN `float`, ET LE TEXTE SE LISAIT EN ESCALIER.

   Les paragraphes s'enroulaient autour d'elle, se decalaient a droite sur
   quelques lignes, puis revenaient a gauche des qu'ils la depassaient. Sur
   une fiche de vente, c'est le pire endroit ou faire ca.

   L'image est redevenue ce qu'elle est : une VIGNETTE, petite, posee a gauche
   du NOM de l'article, dans l'en-tete. Le texte occupe toute la largeur, d'un
   bord a l'autre, sans rien contourner.

   LA VIGNETTE VIT, MAIS ELLE NE GENE PAS. Elle s'incline vers le curseur en
   reprenant --rx / --ry ecrits par le champ magnetique sur la modale, et
   flotte tres lentement. Elle reste DANS le flux : elle ne passe jamais
   par-dessus le texte. */

.fiche__tete { display: flex; align-items: center; gap: 1rem; }

.fiche__vignette {
    position: relative;
    display: grid;
    place-items: center;
    width: 58px; height: 58px;
    flex-shrink: 0;
    padding: 6px;
    border-radius: 16px;
    background: linear-gradient(150deg, rgba(168,85,247,.22), var(--fond-2));
    border: 1px solid var(--bord-fort);
    box-shadow: var(--biseau);
    animation: flotte 5.5s ease-in-out infinite;
    transform: perspective(420px)
               rotateX(calc(var(--rx, 0deg) * 1.8))
               rotateY(calc(var(--ry, 0deg) * 1.8));
    transition: transform .5s var(--douce), box-shadow .45s var(--douce), border-color .35s;
}
.fiche:hover .fiche__vignette {
    border-color: var(--violet);
    box-shadow: var(--biseau-fort), 0 14px 30px -12px rgba(168,85,247,.85);
}
.fiche__vignette img {
    width: 100%; height: 100%;
    object-fit: contain;
    filter: drop-shadow(0 4px 10px rgba(0,0,0,.6));
}

.fiche__titre { flex: 1; min-width: 0; margin-right: .5rem; }

.fiche__mention {
    display: inline-flex;
    align-items: center;
    gap: .5rem;
    margin: 0 0 1.2rem;
    padding: .35rem .8rem;
    font-size: .8rem;
    font-weight: 650;
    color: var(--violet-clair);
    background: rgba(168,85,247,.12);
    border: 1px solid var(--bord-fort);
    border-radius: 99px;
}

/* Le pied de la fiche : prix a gauche, achat a droite, et ils ne se touchent
   jamais. */
.fiche__pied { display: flex; flex-wrap: wrap; align-items: center; gap: 1rem; }
.fiche__prix { display: flex; align-items: baseline; gap: .6rem; margin-right: auto; }
.fiche__prix b {
    font-family: 'Outfit', sans-serif;
    font-size: 1.8rem;
    font-weight: 800;
    letter-spacing: -.04em;
}
.fiche__achat { display: flex; flex-wrap: wrap; align-items: center; gap: .7rem; }
.fiche__achat label { font-size: .84rem; color: var(--texte-doux); }
.fiche__achat .form-control { width: 90px; }
.fiche__indispo {
    display: inline-flex;
    align-items: center;
    gap: .5rem;
    font-size: .88rem;
    color: var(--texte-faible);
}

/* LA FICHE ELLE-MEME S'INCLINE VERS LE CURSEUR.
   Elle etait la seule surface figee de la boutique — et c'est celle ou l'on
   decide d'acheter. `perspective` est plus large que sur une carte (1400 px
   au lieu de 1000) : une modale fait 800 px de large, le meme angle y
   paraitrait deux fois plus fort. */
.modal-content.fiche {
    transform: perspective(1400px)
               rotateX(var(--rx, 0deg))
               rotateY(var(--ry, 0deg));
    transition: transform .55s var(--douce), box-shadow .5s var(--douce);
    will-change: transform;
}

/* Sur telephone, la vignette reste dans l'en-tete : elle ne fait que 58 px,
   elle tient partout. Seul le pied s'empile. */
@media (max-width: 560px) {
    .fiche__pied { flex-direction: column; align-items: stretch; }
    .fiche__prix { margin: 0 0 .4rem; justify-content: center; }
    .fiche__achat { justify-content: center; }
    .fiche__achat .btn { width: 100%; }
    .fiche__vignette { width: 46px; height: 46px; border-radius: 13px; }
}

/* Une page qui ne contient qu'un formulaire ou un recapitulatif : connexion,
   choix du moyen de paiement, options d'un article. Elle n'a pas besoin de
   toute la largeur, et centree elle se lit deux fois mieux. */
.page-etroite { max-width: 640px; margin-inline: auto; }

/* Le retour vers la boutique, sous un formulaire. C'est un chemin, pas une
   action : il a l'air d'un lien, jamais d'un bouton. */
.retour-boutique { margin-top: 1.5rem; text-align: center; }
.retour-boutique a {
    display: inline-flex;
    align-items: center;
    gap: .45rem;
    font-size: .88rem;
    font-weight: 650;
    color: var(--texte-doux);
    transition: color .25s var(--net), gap .3s var(--douce);
}
.retour-boutique a:hover { color: var(--violet-clair); gap: .7rem; }

.erreur-message { margin: .4rem 0 0; font-size: .82rem; color: #FFC9CC; }

.erreur-code {
    font-family: 'Outfit', sans-serif;
    font-size: clamp(4.5rem, 16vw, 9rem);
    font-weight: 800;
    line-height: 1;
    letter-spacing: -.05em;
    margin: 0 0 .5rem;
}

/* Le bandeau « connecte ton compte ». Il vit au-dessus des prix parce que
   c'est la que la question se pose, et il disparait des que le compte est
   connecte : un bandeau permanent finit par ne plus se voir. */
.bandeau-connexion {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 1.5rem;
    padding: 1.4rem 1.7rem;
    margin-bottom: clamp(1.6rem, 3vw, 2.2rem);
    border-color: var(--bord-fort);
}
.bandeau-connexion > div { flex: 1; min-width: 18rem; }
.bandeau-connexion .btn { flex-shrink: 0; }

@media (max-width: 620px) {
    .bandeau-connexion { flex-direction: column; align-items: stretch; padding: 1.2rem 1.3rem; }
    .bandeau-connexion > div { min-width: 0; }
    .bandeau-connexion .btn { width: 100%; }
}

/* ==================== LA GRILLE DES ARTICLES ====================
   ILS ETAIENT TROP SERRES, ET C'EST UN PROBLEME DE VENTE, PAS DE GOUT.
   Des cartes collees les unes aux autres se lisent comme un tableau : l'oeil
   les parcourt au lieu de s'arreter sur l'une d'elles. Un ecart franc
   (2 rem au lieu de 1,25) et une largeur minimale plus grande donnent a
   chaque article la place d'etre regarde seul. */
.articles {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr));
    gap: clamp(1.5rem, 2.4vw, 2rem);
    align-items: stretch;
}

/* ==================== LE PANIER ====================
   LES BOUTONS NE SE TOUCHENT PLUS, ET C'EST LE POINT.
   « Mettre a jour » et « Vider le panier » etaient a quelques pixels l'un de
   l'autre : c'est une commande effacee par erreur, et un joueur qui
   recommence tout. Les chemins de retour sont a gauche, celui qui fait
   avancer est a droite, et rien ne se frole. */

.panier { display: grid; gap: clamp(1.6rem, 3vw, 2.2rem); }
.panier h4 {
    font-size: .72rem;
    font-weight: 800;
    letter-spacing: .16em;
    text-transform: uppercase;
    color: var(--texte-faible);
    margin-bottom: .9rem;
}
.panier__quantite { max-width: 92px; }
.panier__maj { justify-self: end; margin-top: 1rem; }

.panier__codes {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr));
    gap: clamp(1.4rem, 3vw, 2.2rem);
}

/* Le champ et son bouton, colles volontairement : ils forment UNE commande,
   et l'ecart les ferait lire comme deux. C'est l'inverse exact du cas
   ci-dessus, ou deux actions differentes devaient se separer. */
.champ-groupe { display: flex; }
.champ-groupe .form-control { border-radius: var(--r-m) 0 0 var(--r-m); border-right: 0; }
.champ-groupe .btn { border-radius: 0 var(--r-m) var(--r-m) 0; flex-shrink: 0; }

.panier__codes-liste { list-style: none; margin: 1rem 0 0; padding: 0; display: grid; gap: .6rem; }
.panier__codes-liste li {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: .6rem .9rem;
    font-size: .88rem;
    color: var(--texte-doux);
    background: rgba(255,255,255,.03);
    border: 1px solid var(--bord-clair);
    border-radius: var(--r-s);
}
.panier__codes-liste strong { color: var(--texte); }

.panier__totaux { text-align: right; }
.panier__totaux p {
    margin: 0;
    font-family: 'Outfit', sans-serif;
    font-size: clamp(1.1rem, 2.4vw, 1.4rem);
    font-weight: 800;
    letter-spacing: -.03em;
    color: var(--texte);
}
.panier__payable { color: var(--or) !important; margin-top: .4rem !important; }

.panier__caisse {
    display: grid;
    gap: 1.2rem;
    padding-top: 1.4rem;
    border-top: 1px solid var(--bord-clair);
}
.panier__caisse-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 1.2rem;
}
.panier__retours { display: flex; flex-wrap: wrap; gap: .8rem; }
.panier__email { max-width: 260px; }

/* Les boutons d'une modale : separes, et l'action destructrice d'abord.
   Bootstrap les colle par defaut. */
.modal-actions { display: flex; flex-wrap: wrap; gap: .8rem; margin-left: auto; }

/* La case des conditions generales. Elle est obligatoire : elle doit se
   lire, donc etre cliquable sur toute sa ligne et non sur un carre de
   13 px. */
.conditions {
    display: flex;
    align-items: flex-start;
    gap: .7rem;
    padding: .8rem 1rem;
    font-size: .88rem;
    color: var(--texte-doux);
    background: rgba(255,255,255,.03);
    border: 1px solid var(--bord-clair);
    border-radius: var(--r-m);
    cursor: pointer;
    transition: border-color .3s var(--net), background .3s var(--net);
}
.conditions:hover { border-color: var(--bord-fort); background: rgba(168,85,247,.06); }
.conditions .form-check-input { margin: .2rem 0 0; flex: none; }

/* ==================== LES MOYENS DE PAIEMENT ====================
   Des logos de tailles tres differentes — une carte bleue, un « P » PayPal,
   un bandeau PaySafeCard. Une hauteur commune et un centrage les remettent
   sur la meme ligne visuelle, sans les deformer. */
.moyens {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 170px), 1fr));
    gap: 1.2rem;
}
.moyen {
    display: grid;
    place-items: center;
    gap: .9rem;
    padding: 1.5rem 1.2rem;
    text-align: center;
    cursor: pointer;
}
.moyen img { max-height: 46px; width: auto; object-fit: contain; }
.moyen span { font-size: .85rem; font-weight: 650; color: var(--texte-doux); }

@media (max-width: 620px) {
    .panier__caisse-actions { flex-direction: column; align-items: stretch; }
    .panier__retours { flex-direction: column; }
    .panier__caisse-actions > .btn,
    .panier__retours > .btn,
    .panier__email { width: 100%; max-width: none; }
    .panier__totaux { text-align: left; }
}

/* ==================== INFORMATIONS DEPLIANTES ====================
   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. */

.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; }
.repli__corps > div { overflow: hidden; }
.repli__contenu {
    padding: 1.4rem 1.4rem 1.5rem;
    border-top: 1px solid var(--bord-clair);
    margin-top: .2rem;
    font-size: .93rem;
    color: var(--texte-doux);
}
.repli__contenu p { margin-bottom: .8rem; }
.repli__contenu p:last-child { margin-bottom: 0; }
.repli__contenu strong { color: var(--texte); }

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

.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. Sur une connexion
   lente, c'est ce qui evite le second clic sur un lien « qui n'a pas
   marche ». */
.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); }

/* ==================== BOUTON DE SON ====================
   Un site qui bipe sans qu'on puisse l'arreter se ferme. L'interrupteur est
   donc toujours visible, et le choix garde dans le navigateur. */

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

/* ==================== L'ICONE QUI PART AU PANIER ====================
   Le formulaire d'ajout recharge la page : entre le clic et l'arrivee sur
   le panier, il ne se passait rien du tout, et l'on cliquait deux fois.
   L'icone du bouton s'envole vers la droite, le bouton se fige : la reponse
   est immediate, et la double commande impossible. */
@keyframes envol-panier {
    0%   { transform: translate(0, 0) scale(1);        opacity: 1; }
    45%  { transform: translate(6px, -14px) scale(1.3); opacity: 1; }
    100% { transform: translate(26px, 8px) scale(.5);   opacity: 0; }
}
.btn--envoi { pointer-events: none; }
.btn--envoi i, .btn--envoi svg { animation: envol-panier .7s var(--douce) forwards; }

/* ==================== APPARITION AU DEFILEMENT ====================
   L'ENTREE PASSE PAR UNE VARIABLE, ET NON PAR `transform` DIRECTEMENT.
   `.reveal.vu { transform: none }` pese deux classes ; `.bulle`, qui porte
   l'inclinaison 3D, n'en pese qu'une. Le "none" gagnerait sur les deux
   tableaux et tout element a la fois `.reveal` et `.bulle` perdrait son
   pivot. Les deux effets ne se disputent donc plus la meme propriete :
   l'entree pose sa translation dans --entree, le pivot la reprend telle
   quelle dans son propre `transform`. */
@property --entree {
    syntax: '<transform-list>';
    inherits: false;
    initial-value: translateY(0);
}

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

/* ==================== CHAMP MAGNETIQUE : LE PIVOT ====================
   Declare APRES `.reveal.vu`, et avec autant de classes que lui : c'est la
   seule facon que l'inclinaison survive a l'apparition au defilement.
   L'ordre des fonctions compte : `perspective()` ne s'applique qu'a ce qui
   la SUIT, donc la translation d'entree reste plate et seules les rotations
   prennent le relief. */
.bulle,
.reveal.bulle {
    transform: var(--entree, translateY(0))
               perspective(1000px)
               rotateX(var(--rx, 0deg))
               rotateY(var(--ry, 0deg));
    /* `transition` est un raccourci : il REMPLACE la regle du composant au
       lieu de s'y ajouter. On reprend ici l'union de ce que les elements
       aimantes animent reellement, sinon leurs couleurs changeraient d'un
       coup, sans fondu. */
    transition: translate .5s var(--douce),
                scale .5s var(--douce),
                transform .5s var(--douce),
                opacity .8s var(--douce),
                color .3s var(--net),
                background-color .3s var(--net),
                border-color .35s var(--net),
                border-radius .5s var(--douce),
                box-shadow .45s var(--douce),
                gap .35s 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". */
.bulle:not(.bulle--proche),
.reveal.bulle:not(.bulle--proche) {
    transition-duration: .85s, .85s, .85s, .8s,
                         .3s, .3s, .35s, .5s, .45s, .35s;
}

/* `will-change` UNIQUEMENT PENDANT L'EFFET, JAMAIS EN PERMANENCE : posee sur
   `.bulle`, elle creerait soixante couches GPU des le chargement et le
   compositeur saturerait. */
.bulle--proche { will-change: translate, scale, transform; }

/* ==================== LES PAGES CALMES ====================
   LE PIVOT DONNE MAL A LA TETE LA OU L'ON LIT DES CHIFFRES.

   Sur la page d'accueil, l'inclinaison vers le curseur fait respirer la
   page et pousse au clic. Sur le panier, le paiement ou l'historique des
   commandes, elle fait exactement l'inverse : on y verifie des montants,
   ligne par ligne, et le texte qui bascule sous les yeux empeche de lire.

   `.page-calme` divise l'effet par trois cote JS (voir `FACTEUR_CALME`) et
   plafonne ici le pivot restant. On ne le coupe pas : la matiere doit rester
   la meme d'une page a l'autre, sinon la boutique parait faite de deux
   sites. */
.page-calme .bulle,
.page-calme .reveal.bulle {
    transform: var(--entree, translateY(0))
               perspective(1600px)
               rotateX(var(--rx, 0deg))
               rotateY(var(--ry, 0deg));
}

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

/* ==================== L'ENTREE DE PAGE ====================
   Ce qui est deja a l'ecran au chargement n'apparait jamais via
   IntersectionObserver : sans cette cascade, la page s'afficherait d'un
   bloc, immobile. Le flou qui se leve 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. */
@keyframes entree-monte {
    from { opacity: 0; transform: translateY(28px); filter: blur(7px); }
    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; }
.entree main > .wrap > *:nth-child(1) { animation: entree-monte .75s var(--douce) .06s backwards; }
.entree main > .wrap > *:nth-child(2) { animation: entree-monte .75s var(--douce) .14s backwards; }
.entree main > .wrap > *:nth-child(3) { animation: entree-monte .75s var(--douce) .22s backwards; }
.entree main > .wrap > *:nth-child(4) { animation: entree-monte .75s var(--douce) .30s backwards; }

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

@media (max-width: 1080px) {
    .pied__grille { grid-template-columns: 1fr 1fr; }

    /* LA COLONNE D'INFORMATION PASSE SOUS LES ARTICLES.
       Le classement des acheteurs et l'objectif du mois sont des a-cotes :
       les lire avant les articles n'a aucun sens sur un ecran ou tout est
       empile. */
    .boutique { grid-template-columns: 1fr; }
    .boutique__cote { position: static; order: 2; margin-top: 1.5rem; }
    .boutique__contenu { order: 1; }
}

@media (max-width: 860px) {
    .liens {
        position: fixed;
        inset: var(--nav-h) 0 auto;
        flex-direction: column;
        align-items: stretch;
        gap: .3rem;
        padding: 1.2rem;
        max-height: calc(100svh - var(--nav-h));
        overflow-y: auto;
        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; }

    /* SUR TELEPHONE, LE GROUPE AZURIOM RESTE DANS LA BARRE.
       Panier et compte sont les deux gestes du tunnel d'achat : les
       enfermer dans le menu burger ajouterait un clic a chacun d'eux. Ils
       vivent donc a cote du burger, et seul le menu de navigation se
       replie. */
    .azuriom {
        order: 2;
        margin-left: auto;
        margin-right: .5rem;
        gap: .4rem;
    }
    .burger { order: 3; }
    .bulle-outil, .nav-notifications .nav-link { width: 38px; height: 38px; border-radius: 12px; }
    .bulle-connexion { padding: .55rem .7rem; }
    .bulle-connexion span { display: none; }
    .bloc-discord { grid-template-columns: 1fr; text-align: center; justify-items: center; }

    /* ---------- LES SOUS-MENUS SUR TELEPHONE ----------
       IL Y EN A DEUX SORTES, ET ILS N'ONT PAS LE MEME PROBLEME.

       Ceux du MENU (`.liens`) s'ouvrent a plat, en accordeon : le menu est
       deja un panneau opaque plein ecran, un second panneau flottant
       par-dessus n'aurait aucun sens.

       Celui du COMPTE vit dans la barre, PAS dans le menu. Aplati, il
       heritait d'un fond a 3 % d'opacite pose sur la page elle-meme : du
       texte clair sur des cartes claires, illisible. Il reste donc
       flottant, opaque, et se cale sur le bord droit de l'ecran plutot que
       sur sa bulle — sinon il en depasse. */
    .liens .menu-deroulant { width: 100%; }
    .liens .menu-deroulant > button { width: 100%; justify-content: space-between; padding: .8rem 1rem; font-size: 1rem; }
    .liens .menu-deroulant__panneau {
        position: static;
        min-width: 0;
        margin: .2rem 0 .4rem .6rem;
        background: rgba(255,255,255,.04);
        box-shadow: none;
        display: none;
        opacity: 1;
        visibility: visible;
        transform: none;
    }
    .liens .menu-deroulant.ouvert .menu-deroulant__panneau { display: grid; }

    .azuriom .menu-deroulant__panneau {
        position: fixed;
        top: calc(var(--nav-h) - 6px);
        right: .8rem;
        left: auto;
        width: min(280px, calc(100vw - 1.6rem));
        min-width: 0;
        /* Opaque, et franchement : c'est un panneau pose sur la page, pas un
           calque. `background-color` d'abord pour les navigateurs qui
           ignoreraient le degrade. */
        background-color: #16122B;
        background-image: linear-gradient(160deg, var(--surface-2), var(--fond-2));
        border-color: var(--violet);
        box-shadow: var(--biseau), 0 26px 60px -20px rgba(0,0,0,.95);
    }
    .azuriom .menu-deroulant__panneau a,
    .azuriom .menu-deroulant__panneau button { padding: .7rem .8rem; font-size: .95rem; }
}

@media (max-width: 620px) {
    :root { --nav-h: 64px; }
    .carte { padding: 1.4rem; }
    .grade { padding: 1.6rem 1.4rem; }
    .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; }
    .promo-bandeau {
        flex-direction: column;
        align-items: flex-start;
        padding: 1rem 1.1rem;
        gap: .55rem;
    }
    .promo-bandeau__texte { min-width: 0; flex: none; font-size: .9rem; }
    .promo-bandeau__taux { font-size: 1.45rem; }

    /* ---------- LES TABLEAUX SUR TELEPHONE ----------
       Un tableau de trois colonnes ne tient pas dans 360 px, et le faire
       defiler lateralement ne marche pas : rien n'indique qu'il y a une
       suite, et le lecteur repart en croyant avoir tout lu. Chaque LIGNE
       devient donc une petite carte, l'en-tete etant recopie par le JS dans
       `data-colonne`. */
    .tableau-enveloppe {
        overflow-x: visible;
        border: 0;
        background: none;
        box-shadow: none;
        border-radius: 0;
    }
    .tableau-enveloppe table { display: block; min-width: 0; width: 100%; font-size: .88rem; }
    .tableau-enveloppe thead { display: none; }
    .tableau-enveloppe tbody { display: block; }
    .tableau-enveloppe tbody tr {
        display: block;
        padding: .9rem 1.05rem;
        margin-bottom: .7rem;
        background: var(--surface);
        border: 1px solid var(--bord);
        border-radius: var(--r-m);
        box-shadow: var(--biseau);
    }
    .tableau-enveloppe tbody tr:last-child { margin-bottom: 0; }
    .tableau-enveloppe tbody tr:hover { background: var(--surface); }
    .tableau-enveloppe tbody td {
        display: grid;
        grid-template-columns: minmax(0, 7.5rem) minmax(0, 1fr);
        align-items: baseline;
        gap: .2rem .9rem;
        padding: .5rem 0 0;
        border-bottom: 0;
        overflow-wrap: anywhere;
    }
    .tableau-enveloppe tbody td::before {
        content: attr(data-colonne);
        font-size: .66rem;
        font-weight: 800;
        letter-spacing: .09em;
        text-transform: uppercase;
        color: var(--texte-faible);
    }
    .tableau-enveloppe tbody td[data-premiere] {
        display: block;
        padding: 0 0 .55rem;
        margin-bottom: .3rem;
        font-size: 1rem;
        color: var(--texte);
        border-bottom: 1px solid var(--bord-clair);
    }
    .tableau-enveloppe tbody td[data-premiere]::before { content: none; }
    .tableau-enveloppe tbody td:not([data-colonne]) { display: block; }
    .tableau-enveloppe tbody td:not([data-colonne])::before { content: none; }
    .tableau-enveloppe table[data-matrice] tbody td { grid-template-columns: minmax(0, 1fr) auto; }
}

/* ==================== 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. */
@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; --entree: translateY(0); }
    /* Le bouton d'achat garde sa couleur, il perd sa respiration. */
    .btn--achat { animation: none; }
    /* Le champ magnetique est ce qui bouge le plus : c'est la premiere
       chose a couper. */
    .bulle {
        translate: none !important;
        scale: none !important;
        transform: none !important;
    }
    /* Le voile ne sert qu'a occuper l'attente : sans animation, il ne
       ferait que masquer la page. */
    .voile { display: none; }
    .repli__corps { transition: none; }
}

/* Impression : une facture ou un recapitulatif finit parfois sur papier. */
@media print {
    body::before, body::after, .nav, .discord-flottant, .pied, .progression { display: none !important; }
    body { background: #fff; color: #000; }
    .carte { border: 1px solid #ccc; box-shadow: none; background: #fff; }
    * { color: #000 !important; }
}
