/* ─────────────────────────────────────────────────────────────────────────────
   site.css · mise en page d'enopvp.fr

   Chargé APRÈS base.css. Ne contient aucun token et aucune valeur esthétique
   nouvelle : uniquement de la mise en page, construite avec les composants du
   design system. Toute couleur, toute ombre, tout rayon vient de base.css.

   Règle tenue partout : si un élément « manque de vie », on monte d'un cran
   dans la rampe d'encre ou on l'inverse. On n'ajoute jamais une teinte.
   ───────────────────────────────────────────────────────────────────────────── */

/* ---------- Ossature ---------- */

.wrap { max-width: var(--max-content); margin: 0 auto; padding: 0 clamp(18px, 3vw, 32px); }

/* La capsule est fixe : les pages sans héros commencent sous elle. */
.page { padding-top: 150px; }
/* Une page precedee d'un heros n'a plus a degager la capsule. */
.page--after-hero { padding-top: 54px; }

h1, h2, h3 { margin: 0; font-weight: 700; line-height: 1.15; letter-spacing: -.02em; color: var(--ink-hi); }
:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 3px; border-radius: 3px; }

/* Le motif court derrière toute la page. Les 3 % sont portés par la tuile
   elle-même (voir base.css) : pas d'opacité à réappliquer ici. */
body::before { content: ""; position: fixed; inset: 0; z-index: -1; pointer-events: none; background: var(--pattern-url) repeat; background-size: 80px 80px; }

/* ---------- Marque dans la capsule ----------
   Deux lignes, comme `.doc-brand` : le nom, puis un sur-titre mono. */
.brand { flex: none; display: flex; align-items: center; gap: 10px; }
.brand img { height: 26px; width: auto; }
.brand-txt { display: grid; line-height: 1.15; }
.brand-txt b { font-size: 14px; font-weight: 700; letter-spacing: -.01em; color: var(--ink); }
.brand-txt span { font-family: var(--font-mono); font-size: 9.5px; font-weight: 500; letter-spacing: .12em; text-transform: uppercase; color: var(--ink-decor); }

.nav-sep { flex: none; width: 1px; height: 26px; background: var(--line-1); }

/* La rangée de liens défile plutôt que de comprimer les libellés, masquée en
   fondu à ses deux extrémités.

   ⚠️ Ce défilement et ce fondu ne servent QUE quand la barre est trop étroite.
   Appliqués en permanence, ils coupaient ou estompaient des entrées en grand
   écran : le conteneur gardait sa position de défilement d'une page à l'autre,
   et le fondu de 3 % mordait sur le premier lien même quand tout tenait. La
   barre doit être entièrement lisible dès qu'il y a la place, sans exception. */
.nav-scroll { flex: 1; min-width: 0; overflow-x: auto; scrollbar-width: none; mask-image: linear-gradient(90deg, #0000, #000 3%, #000 97%, #0000); -webkit-mask-image: linear-gradient(90deg, #0000, #000 3%, #000 97%, #0000); }
.nav-scroll::-webkit-scrollbar { display: none; }
.nav-scroll .nav-links { width: max-content; padding: 2px 4px; }
@media (min-width: 1040px) {
    .nav-scroll { overflow-x: visible; mask-image: none; -webkit-mask-image: none; }
    .nav-scroll .nav-links { width: auto; }
}
.nav-end { flex: none; display: flex; align-items: center; gap: 8px; }

/* ---------- Compte dans la capsule ----------
   Construit par app.js à partir du seul stockage local. */

/* `.nav-login` n'a volontairement AUCUN style : le lien de connexion est un
   `.s-button--secondary.s-button--sm` écrit en dur dans la barre, la classe ne
   sert qu'à app.js pour le masquer quand un compte est là. Un bouton plein ici
   volerait la vedette à celui de la page. */
.acct-cart { position: relative; display: inline-flex; align-items: center; flex: none; color: var(--ink-nav); transition: color var(--transition-fast); }
.acct-cart:hover { color: var(--ink); }
.acct-cart svg { display: block; }
.acct-cart__n { position: absolute; top: -5px; right: -7px; min-width: 15px; padding: 0 4px; border-radius: 9999px; background: var(--invert); color: var(--on-invert); font-family: var(--font-mono); font-size: 9.5px; font-weight: 700; line-height: 15px; text-align: center; }

.acct { position: relative; display: inline-flex; align-items: center; flex: none; padding: 2px; border: 1px solid var(--line-1); border-radius: 9999px; cursor: pointer; transition: border-color var(--transition-fast); }
.acct:hover, .acct:focus-visible { border-color: var(--line-edge-hi); }
/* L'avatar vient du forum : on ne maîtrise ni son cadrage ni son format.
   `cover` sur un rond est le seul réglage qui ne déforme jamais. */
.acct__av { display: block; width: 28px; height: 28px; border-radius: 9999px; object-fit: cover; background: var(--surface-1); }
.acct__av--letter { display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 700; color: var(--ink-hi); }

.acct-menu { position: absolute; top: calc(100% + 10px); right: 0; z-index: 60; min-width: 210px; padding: 6px; border: 1px solid var(--line-1); border-radius: 1rem; background: rgba(0,0,0,.95); backdrop-filter: blur(24px); -webkit-backdrop-filter: blur(24px); box-shadow: inset 0 1px #ffffff0f, 0 20px 60px #0006; cursor: default; }
.acct-menu__who { padding: 8px 10px 10px; margin-bottom: 6px; border-bottom: 1px solid var(--line-0); font-size: 11.5px; color: var(--ink-meta); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Ligne d'une liste : le filet lumineux, redressé, au survol. */
.acct-menu__item { position: relative; display: block; width: 100%; padding: .75rem 1rem; border: none; border-left: 2px solid transparent; border-radius: 0 .5rem .5rem 0; background: none; color: var(--ink-nav); font: inherit; font-size: .875rem; text-align: left; cursor: pointer; transition: all var(--transition-fast); }
.acct-menu__item:hover, .acct-menu__item:focus-visible { border-left-color: var(--fil); background: var(--surface-1); color: var(--ink); font-weight: 600; }
.acct-menu__item:hover::before, .acct-menu__item:focus-visible::before { content: ""; position: absolute; top: 0; bottom: 0; left: -2px; width: 2px; box-shadow: var(--fil-bloom); mix-blend-mode: plus-lighter; pointer-events: none; }
.acct-menu__item--out:hover { border-left-color: var(--bad); color: var(--bad); }
.acct-menu__item--out:hover::before { box-shadow: 0 0 10px rgba(248,113,113,.45); }
@media (max-width: 480px) { .acct-menu { right: -6px; min-width: 180px; } }

/* Drapeaux de langue : la seule exception colorée assumée du site, un drapeau
   se reconnaît à sa couleur. L'inactif est atténué. */
.lang { display: inline-flex; align-items: center; gap: 4px; }
.lang button { display: inline-flex; padding: 3px; border: 1px solid transparent; border-radius: 4px; background: none; cursor: pointer; line-height: 0; opacity: .4; filter: grayscale(.6); transition: all var(--transition-fast); }
.lang button:hover { opacity: .85; filter: none; }
.lang button[aria-pressed="true"] { opacity: 1; filter: none; border-color: var(--line-2); }
.lang svg { display: block; border-radius: 2px; }
.lang button:focus-visible { outline: none; border-color: var(--fil); }

@media (max-width: 720px) {
  .nav { top: 12px; width: calc(100% - 20px); }
  .nav-in { padding: 8px 10px 8px 14px; gap: 12px; }
  .brand-txt span { display: none; }
  .nav-link { font-size: 13px; padding: 6px 8px; }
}

/* ---------- Héros ----------
   Composition de la doc : la photo est enterrée sous quatre voiles superposés,
   puis rejointe en bas par une bande de motif masquée en fondu. */

.hero { position: relative; isolation: isolate; overflow: hidden; padding: 172px 0 56px; }
.hero--photo { background: var(--base) center center / cover no-repeat; }
.hero--home { background-image: url('/img/hero-home.jpg'); }
.hero--shop { background-image: url('/img/hero-shop.jpg'); }
.hero--team { background-image: url('/img/hero-team.jpg'); }
.hero--log  { background-image: url('/img/hero-log.jpg'); }

/* Voile 1 : bande haute, la capsule ne bave pas sur l'image.
   Voile 2 : dégradé horizontal, la colonne de texte reste lisible à gauche.
   Voile 3 : bande basse, la photo fond dans la page.
   Voile 4 : assombrissement général. */
.hero::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -2;
  pointer-events: none;
  background:
    linear-gradient(to bottom, rgba(10,10,10,.8) 0, transparent 8rem),
    linear-gradient(to right, var(--base) 0%, rgba(10,10,10,.6) 45%, transparent 78%),
    linear-gradient(to top, var(--base) 0, var(--base) 8%, rgba(10,10,10,.7) 35%, transparent 55%),
    rgba(10,10,10,.45);
}
/* La bande de motif du bas, masquée en fondu vertical.
   Dans le héros, la photo cache le motif de la page : cette bande le REMET au
   moment où la photo s'efface, pour que la texture soit continue avec la suite.

   Deux réglages sont donc obligatoires, et c'est ce qui faisait la coupure :
   • `opacity: 1` et non `.6`, pour que la bande sorte à 3 %, la MÊME densité
     que `body::before`. À .6 elle tombait à 1,8 % et la jointure se lisait
     comme une marche.
   • `background-attachment: fixed`, pour tuiler depuis le coin de la FENÊTRE
     comme `body::before` qui est en `position: fixed`. Sans ça les deux motifs
     ne sont pas en phase, les E ne tombent pas au même endroit de part et
     d'autre de la jointure, et le décrochage se déplace au défilement. */
.hero::after {
    content: "";
    position: absolute;
    left: 0; right: 0; bottom: 0;
    height: 16rem;
    z-index: -1;
    pointer-events: none;
    background: var(--pattern-url) repeat fixed;
    background-size: 80px 80px;
    mask-image: linear-gradient(to top, #000, transparent);
    -webkit-mask-image: linear-gradient(to top, #000, transparent);
}

.hero__grid { display: grid; grid-template-columns: minmax(0, 1fr) 30rem; gap: clamp(32px, 5vw, 72px); align-items: center; }
.hero__card { min-width: 0; }

/* Titre : DEUX TONS D'ENCRE, jamais une teinte. La première ligne est à 82 %,
   le fragment accentué en encre pleine et plus gras. Le contraste se fait par
   l'opacité et la graisse, comme le prescrit la doc. */
.hero h1 { margin: 0 0 16px; font-size: clamp(38px, 5vw, 64px); font-weight: 700; line-height: 1.05; letter-spacing: -.03em; color: var(--ink-on-media); }
.hero h1 b { color: var(--ink); font-weight: 900; }
.hero__lede { margin: 0 0 28px; max-width: 46rem; font-size: 16.5px; line-height: 1.65; color: var(--ink-body); }
.hero__tags { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; margin-bottom: 20px; }
.hero__tags .eyebrow { margin: 0; }
.hero__cta { display: flex; flex-wrap: wrap; align-items: center; gap: 14px; }

/* Bas de héros : bandeau de mots-clés + invite de défilement. */
.hero__foot { display: flex; align-items: center; gap: 28px; margin-top: 56px; }
.hero__foot .marquee { flex: 1; min-width: 0; }
.hero__foot .hero-scroll__mouse { flex: none; }

/* Sur petit écran la composition passe en colonne, centrée : la carte fichier
   repasse dessous et le texte se recentre. */
@media (max-width: 1100px) {
  .hero__grid { grid-template-columns: 1fr; justify-items: center; text-align: center; }
  .hero__text { max-width: 42rem; }
  .hero__tags, .hero__cta { justify-content: center; }
  .hero__card { width: 100%; max-width: 32rem; }
}
@media (max-width: 720px) {
  .hero { padding-top: 132px; }
  .hero__foot .hero-scroll__mouse { display: none; }
}

/* ---------- Sections ---------- */

.sec { padding: 54px 0; border-bottom: 1px solid var(--line-0); }
.sec:last-of-type { border-bottom: none; }
.sec > .wrap > h2, .sec h2.sec__t { margin: 0 0 10px; font-size: clamp(26px, 3vw, 36px); font-weight: 700; letter-spacing: -.02em; color: var(--ink-hi); }
/* Le mot accentué reste sur la rampe d'encre : encre pleine et graisse
   supérieure, exactement comme le titre du héros. */
.sec h2 b { color: var(--ink); font-weight: 900; }
.sec__lede { max-width: 52rem; margin: 0 0 30px; color: var(--ink-mid); }
.sec .doc-num { margin-bottom: 10px; }

/* Titre de page, pour les pages sans héros. */
.page__t { margin: 0 0 16px; font-size: clamp(38px, 5vw, 64px); font-weight: 800; line-height: 1.05; letter-spacing: -.03em; color: var(--ink-hi); }
.page__t b { color: var(--ink); font-weight: 900; }
.page__lede { max-width: 46rem; margin: 0 0 12px; font-size: 16.5px; line-height: 1.65; color: var(--ink-body); }
.page__head { padding-bottom: 44px; border-bottom: 1px solid var(--line-1); margin-bottom: 46px; }

/* ---------- La fenêtre-fichier, en section ----------
   Chaque bloc du site est une fenêtre-fichier, comme chaque panneau du HUD en
   jeu. `.piece` est `.patch-hero__panel` posé à la largeur d'une section.

   ⚠️ L'entrée automatique du panneau est COUPÉE ici : `patch-hero-rise` se
   déclenche au chargement, or ces cartes sont sous la ligne de flottaison et
   l'animation serait jouée avant qu'on les voie. C'est `data-reveal` qui prend
   le relais, quand la carte entre vraiment dans le cadre (voir app.js). */
/* Une fenetre-fichier reagit au survol comme une carte du design system :
   la bordure s'eclaircit, l'ombre s'ouvre. Rien de plus. */
.piece { animation: none; transition: border-color .25s, box-shadow .25s; }
.piece:hover { border-color: var(--line-2); box-shadow: inset 0 1px #ffffff0f, 0 28px 80px #00000099, 0 4px 18px #0006; }
/* Deux classes, donc plus spécifique que `.piece` : sans ça `animation: none`
   l'emporterait, `.reveal` laisserait son `opacity: 0` et la carte resterait
   invisible pour de bon. */
.piece.reveal { animation: patch-hero-rise .7s cubic-bezier(.22, 1, .36, 1) both; }
.piece--narrow { max-width: 54rem; margin-left: auto; margin-right: auto; }
.piece .patch-hero__content { padding: 26px 30px 28px; }
.piece .note { margin: 22px 0 0; }
@media (max-width: 720px) { .piece .patch-hero__content { padding: 22px 18px 24px; } }

/* Grille de tuiles À L'INTÉRIEUR d'une fenêtre-fichier : les tuiles n'ont plus
   ni cadre ni fond, la fenêtre porte déjà la surface. Deux cartes translucides
   empilées se lisent boueux. */
.piece__grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 22px; margin: 24px 0 0; }
.piece__grid .tile { margin: 0; }
.piece__grid .tile__cover { border: 1px solid var(--line-1); border-radius: .625rem; overflow: hidden; transition: border-color .25s, box-shadow .25s; }
.piece__grid .tile__body { padding: 14px 2px 0; }
/* Survol : la bordure s'éclaircit, l'image se rapproche et s'éclaire par
   `filter`, jamais par un changement de teinte. Le titre monte d'un cran dans
   la rampe d'encre. Trois micro-états, même easing que tout le reste. */
.piece__grid .tile img { transition: transform .45s cubic-bezier(.22, 1, .36, 1), filter .45s cubic-bezier(.22, 1, .36, 1); }
.piece__grid .tile:hover .tile__cover { border-color: var(--line-2); box-shadow: 0 16px 44px #00000052; }
.piece__grid .tile:hover img { transform: scale(1.04); filter: brightness(1.08); }
.piece__grid .tile__body h3 { transition: color var(--transition-fast); }
.piece__grid .tile:hover .tile__body h3 { color: var(--ink); }

/* Contenu libre à l'intérieur d'une fenêtre : catalogue, calendrier, prose. */
.piece__body { margin-top: 24px; }
.piece .team { margin-top: 24px; }
.piece .prose { max-width: none; }
.piece .prose h2 { font-size: 15px; }
/* Le 404 : le chiffre fantôme sert de couverture à la fenêtre. */
.e404__num { margin: 22px 0 0; font-size: clamp(5rem, 14vw, 9rem); -webkit-text-stroke: 2px rgba(var(--acc-lum), .28); }
/* Respiration entre deux fenêtres d'une même page. */
.sec-gap { margin-top: 44px; }

/* Le panier est une fenêtre-fichier qui suit le défilement : c'est elle qui
   porte l'état de connexion et le bouton de paiement. Figée, elle disparaissait
   dès qu'on descendait dans le catalogue, au moment précis où l'on ajoute des
   articles. `top` = capsule (24 px + sa hauteur) + une gouttière. */
@media (min-width: 901px) {
    .cart-piece { position: sticky; top: 112px; max-height: calc(100vh - 132px); display: flex; flex-direction: column; }
    .cart-piece .patch-hero__content { overflow-y: auto; scrollbar-width: thin; scrollbar-color: #ffffff26 transparent; }
}

/* ---------- Grilles ---------- */

.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 16px; }
.grid--2 { grid-template-columns: minmax(0, 1.1fr) minmax(0, .9fr); }
@media (max-width: 900px) { .grid--2 { grid-template-columns: 1fr; } }

/* ---------- Tuile illustrée ----------
   Une `.s-card` avec une couverture, traitée comme `.patch-hero__cover` :
   voile montant compris. */
.tile { display: flex; flex-direction: column; }
.tile__cover { position: relative; overflow: hidden; border-bottom: 1px solid var(--line-1); }
.tile__cover img { width: 100%; height: auto; aspect-ratio: 16 / 9; object-fit: contain; background: #000; transition: transform .4s cubic-bezier(.22,1,.36,1); }
.tile__cover::after { content: ""; position: absolute; inset: 0; pointer-events: none; background: linear-gradient(to top, rgba(0,0,0,.55), transparent 60%); }
.s-card:hover .tile__cover img { transform: scale(1.03); }
.tile__body { padding: 22px 24px 24px; }
.tile__body h3 { margin: 0 0 6px; font-size: 16px; color: var(--ink-hi); }
.tile__body p { margin: 0; font-size: 13.5px; line-height: 1.5; color: var(--ink-mid); }

/* ---------- Carte simple ---------- */
.box { padding: 22px 24px; }
.box h3 { margin: 0 0 8px; font-size: 15px; color: var(--ink-hi); }
.box p { margin: 0 0 10px; font-size: 13.5px; line-height: 1.5; color: var(--ink-mid); }
.box p:last-child { margin-bottom: 0; }

/* ---------- Bandeau animé du serveur ----------
   Le GIF de la liste Cfx et des panneaux du bot. C'est une image de marque,
   posée entre deux filets, sans décor autour. */
.brandband { border-top: 1px solid var(--line-0); border-bottom: 1px solid var(--line-0); background: var(--base); overflow: hidden; }
.brandband img { width: 100%; height: auto; transition: filter .3s ease; }
.brandband:hover img { filter: brightness(1.06); }

/* ---------- Boutique ---------- */

.shop { display: grid; grid-template-columns: minmax(0, 1fr) 330px; gap: 24px; align-items: start; }
@media (max-width: 900px) { .shop { grid-template-columns: 1fr; } }

.shop__group { margin: 26px 0 12px; font-family: var(--font-mono); font-size: 10.5px; font-weight: 600; letter-spacing: .14em; text-transform: uppercase; color: var(--ink-decor); }
.shop__group:first-child { margin-top: 0; }
.shop__state { font-size: 14px; color: var(--ink-mid); }
.shop__state--err { color: var(--bad); }

.packs { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 16px; }
.pack { display: flex; flex-direction: column; padding: 22px 24px; }
/* Les visuels viennent de Tebex : hauteur imposée, largeur libre, jamais
   d'étirement. On ne maîtrise ni leur taille ni leur cadrage. */
.pack__img { margin: -4px 0 16px; text-align: center; }
.pack__img img { display: inline-block; height: 92px; width: auto; max-width: 100%; object-fit: contain; }
.pack h3 { margin: 0 0 6px; font-size: 16px; color: var(--ink-hi); }
.pack__txt { flex: 1; margin: 0 0 18px; font-size: 13.5px; line-height: 1.5; color: var(--ink-mid); }
.pack__foot { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
/* Un chiffre qui change : en mono, comme les versions et les compteurs. */
.pack__price { font-family: var(--font-mono); font-size: 16px; font-weight: 600; color: var(--ink-hi); font-variant-numeric: tabular-nums; }

.cart__txt { margin: 0 0 14px; font-size: 13.5px; color: var(--ink-mid); }
.cart__txt--err { color: var(--bad); }
.cart__who { margin: 0 0 12px; padding-bottom: 12px; border-bottom: 1px solid var(--line-0); font-size: 13.5px; color: var(--ink-hi); }
.cart__list { list-style: none; padding: 0; margin: 0 0 14px; }
/* Trois colonnes : nom, prix, retrait, sur une seule ligne. */
.cart__list li { display: grid; grid-template-columns: 1fr auto auto; align-items: center; gap: 2px 10px; padding: 10px 0; border-bottom: 1px solid var(--line-0); font-size: 13.5px; }
.cart__price { font-family: var(--font-mono); color: var(--ink-mid); font-variant-numeric: tabular-nums; }
/* La cible fait 30 px pour une icône de 16 : au doigt, une zone de la taille
   exacte du dessin se rate, et ce qu'on rate ici est collé au prix. La marge
   négative rattrape ce débord pour garder l'icône alignée à droite. */
.cart__rm { display: inline-flex; align-items: center; justify-content: center; width: 30px; height: 30px; margin: -6px -6px -6px 0; padding: 0; border: none; border-radius: .5rem; background: none; color: var(--ink-meta); cursor: pointer; transition: all var(--transition-fast); }
.cart__rm:hover { color: var(--bad); background: #ef44441f; }
.cart__total { margin: 0 0 14px; font-family: var(--font-mono); font-size: 15px; font-weight: 600; color: var(--ink-hi); font-variant-numeric: tabular-nums; }
.cart-piece .s-button { width: 100%; }
.cart__note { margin: 12px 0 0; font-size: 11.5px; line-height: 1.5; color: var(--ink-meta); }

/* ---------- Patchnotes ---------- */

.cal { margin: 0 0 34px; }
.cal__t { margin: 0 0 12px; font-size: 17px; font-weight: 600; color: var(--ink-hi); }
/* Le calendrier vit DANS la fenetre du journal : pas de carte imbriquee. */
.cal__frame { padding: 0; overflow-x: auto; }
.cal__months { display: grid; grid-auto-flow: column; grid-auto-columns: 15px; gap: 4px; margin: 0 0 7px 36px; min-width: max-content; font-family: var(--font-mono); font-size: 11px; color: var(--ink-decor); }
.cal__month { white-space: nowrap; overflow: visible; height: 13px; }
.cal__body { display: flex; gap: 7px; min-width: max-content; }
.cal__days { display: grid; grid-template-rows: repeat(7, 15px); gap: 4px; width: 29px; align-items: center; font-family: var(--font-mono); font-size: 10px; color: var(--ink-decor); }
.cal__grid { display: grid; grid-auto-flow: column; grid-auto-columns: 15px; grid-template-rows: repeat(7, 15px); gap: 4px; }
/* La case vide est un CREUX, comme un champ. L'échelle monte vers le pavé
   inversé : c'est la seule rampe de teinte du site, et elle porte du sens. */
.cal__cell { width: 15px; height: 15px; border: 1px solid var(--line-0); border-radius: 4px; background: var(--groove-fill); box-shadow: var(--groove-in); cursor: default; }
.cal__cell[data-l="1"] { background: #4a3d00; border-color: transparent; box-shadow: none; }
.cal__cell[data-l="2"] { background: #8a7100; border-color: transparent; box-shadow: none; }
.cal__cell[data-l="3"] { background: #c9a600; border-color: transparent; box-shadow: none; }
.cal__cell[data-l="4"] { background: var(--invert); border-color: transparent; box-shadow: none; }
.cal__foot { display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; margin-top: 18px; font-family: var(--font-mono); font-size: 11.5px; color: var(--ink-meta); }
.cal__legend { display: flex; align-items: center; gap: 5px; color: var(--ink-decor); }
.cal__legend .cal__cell { width: 13px; height: 13px; }
.cal__tip { position: fixed; z-index: 200; pointer-events: none; padding: 7px 10px; border: 1px solid var(--line-1); border-radius: .5rem; background: rgba(0,0,0,.8); backdrop-filter: blur(24px); -webkit-backdrop-filter: blur(24px); box-shadow: 0 20px 60px #0006; font-family: var(--font-mono); font-size: 11.5px; color: var(--ink-hi); white-space: nowrap; }

/* ---------- Une poussée, en fenêtre-fichier ----------
   Le type du commit conventionnel pilote le jeton : "feat" devient "added",
   "fix" devient "fixed", "perf" devient "optimized", "revert" devient
   "removed". C'est l'information la plus utile de la ligne, et elle était
   jusqu'ici jetée avec le préfixe. */
.log { display: grid; gap: 18px; }
.patch { max-width: 54rem; }
/* La portée du commit (le mot entre parenthèses) devant le sujet. */
.patch__scope { font-family: var(--font-mono); font-size: 11.5px; font-weight: 600; color: var(--ink-meta); }
.patch__foot { display: flex; align-items: center; gap: 9px; font-size: 12.5px; color: var(--ink-meta); }
.patch__foot img { width: 18px; height: 18px; border-radius: 9999px; object-fit: cover; }
.patch__hash { margin-left: auto; font-family: var(--font-mono); font-size: 11.5px; color: var(--ink-decor); }
.patch__reste { margin: 4px 0 0; font-family: var(--font-mono); font-size: 11.5px; letter-spacing: .06em; color: var(--ink-decor); }
.hero--patch { background-image: url('/img/hero-patch.jpg'); }
.hero--staff { background-image: url('/img/hero-staff.jpg'); }

/* ---------- Fiche de profil, en fenêtre-fichier ----------
   La bannière Discord occupe la couverture 21:8 du composant (`patch-hero__cover`,
   le rapport d'une bannière Discord est 2,5 : la différence ne se voit pas), et
   l'avatar chevauche son bord bas, comme sur un profil.

   ⚠️ La couverture a un fond de SECOURS : le motif du design system sous un
   dégradé. Tant qu'aucune bannière n'est posée, elle se lit comme un choix et
   non comme une image cassée. Pour poser la vraie, il suffit de déclarer
   `background-image` sur `.profil__cover`. */
.profil__cover {
    background: var(--pattern-url) repeat;
    background-size: 80px 80px;
    background-color: #0d0d0f;
}
.profil__cover::before {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(120deg, rgba(var(--acc-lum), .08), transparent 55%);
}
/* L'avatar remonte sur la couverture.

   ⚠️ `position: relative` et `z-index` sont OBLIGATOIRES ici, ce n'est pas une
   précaution. `.patch-hero__cover` est positionné (`position: relative`), donc
   il est peint dans la couche des éléments positionnés, APRÈS le contenu du
   panneau qui, lui, est un bloc statique. Sans ces deux lignes, la couverture
   passe par-dessus l'avatar et en masque la moitié haute, celle qui déborde.
   C'est l'ordre de peinture de CSS, pas un problème de marge. */
.profil__av { position: relative; z-index: 1; margin: -62px 0 14px; }
.profil__av img {
    width: 88px;
    height: 88px;
    border: 3px solid var(--base);
    border-radius: 9999px;
    /* L'avatar vient de Discord : on ne maîtrise ni son cadrage ni son format.
       `cover` sur un rond est le seul réglage qui ne déforme jamais. */
    object-fit: cover;
    background: var(--surface-1);
    box-shadow: 0 16px 44px #00000052;
}
.profil .patch-hero__content { padding-top: 0; }
.profil__av img { transition: transform .45s cubic-bezier(.22, 1, .36, 1), border-color .25s; }
.profil:hover .profil__av img { transform: scale(1.04); }
.profil__since { font-family: var(--font-mono); font-size: 11.5px; color: var(--ink-decor); }

/* ---------- Équipe ---------- */

.team { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 16px; }
.member { padding: 24px 18px 20px; text-align: center; }
.member__av { width: 84px; height: 84px; margin: 0 auto 14px; display: flex; align-items: center; justify-content: center; overflow: hidden; border: 1px solid var(--line-1); border-radius: 9999px; background: var(--surface-1); font-size: 30px; font-weight: 700; color: var(--ink-hi); }
.member__av img { width: 100%; height: 100%; object-fit: cover; transition: transform .45s cubic-bezier(.22, 1, .36, 1); }
.member:hover .member__av img { transform: scale(1.06); }
.member__n { font-size: 16px; font-weight: 600; letter-spacing: -.01em; color: var(--ink-hi); }
.member__r { margin-top: 2px; font-size: 13.5px; color: var(--ink-mid); }
/* La donnée mono d'une carte, comme `.patch-hero__tabmeta`. */
.member__since { display: inline-block; margin-top: 12px; padding: 3px 10px; border: 1px solid var(--line-1); border-radius: 9999px; font-family: var(--font-mono); font-size: 11px; color: var(--ink-meta); }

/* ---------- Pages de texte ---------- */

.prose { max-width: 52rem; }
.prose h2 { margin: 40px 0 12px; padding-top: 22px; border-top: 1px solid var(--line-0); font-size: 17px; font-weight: 600; color: var(--ink-hi); }
.prose h2:first-of-type { border-top: none; padding-top: 0; }
.prose p, .prose li { color: var(--ink-mid); }
.prose ul { padding-left: 18px; }
.prose li { margin-bottom: 7px; }
.prose b, .prose strong { color: var(--ink-hi); font-weight: 600; }
/* Marqueur des trous à combler avant mise en ligne. Volontairement criard :
   une mention légale incomplète ne doit pas pouvoir passer inaperçue. */
.todo { padding: 1px 7px; border: 1px dashed var(--bad); border-radius: .5rem; background: #ef44441f; color: var(--bad); font-weight: 600; font-size: 13px; }

/* ---------- 404 ---------- */

.e404 { text-align: left; }
.e404 .ghost-num { margin: 0 0 4px; font-size: clamp(5rem, 16vw, 11rem); -webkit-text-stroke: 2px rgba(var(--acc-lum), .28); }

/* ---------- Pied de page ---------- */

.foot { padding: 40px 0 56px; font-size: 13.5px; color: var(--ink-mid); }
.foot__row { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 12px; padding-top: 24px; border-top: 1px solid var(--line-0); }
.foot__links { display: flex; flex-wrap: wrap; gap: 24px; }
.foot__links a { transition: color var(--transition-fast); }
.foot__links a:hover { color: var(--ink); }
.foot__meta { font-family: var(--font-mono); font-size: 11.5px; letter-spacing: .06em; color: var(--ink-decor); }
/* Mention imposée par Rockstar et Cfx : la laisser visible évite l'ambiguïté. */
.foot__legal { max-width: 52rem; margin-top: 16px; font-size: 11.5px; line-height: 1.55; color: var(--ink-ghost); }

/* ═══════════════════ PANNEAU DE NAVIGATION LATÉRAL ═══════════════════
   Porté depuis la barre latérale escamotable du site PDM (`theme.css`,
   « Barre de navigation latérale escamotable »), à la demande du user :
   même mécanisme, mêmes durées, mêmes courbes, seuls les jetons changent.

   Le panneau est HORS CHAMP par défaut et passe PAR-DESSUS la page quand il
   s'ouvre : le contenu ne se décale jamais, rien ne se remet en page. Le
   bouton, lui, vit en dehors du panneau, sinon il glisserait avec lui.

   ⚠️ Tout est porté par `.has-rail`, posé sur le `body` des seules pages du
   site : `site.css` est PARTAGÉE avec le wiki, qui garde sa capsule.

   ⚠️ L'ouverture n'est pas retenue d'une page à l'autre, comme sur le PDM :
   le panneau repart fermé à chaque chargement. C'est ce qui permet de se
   passer du verrou anti-dépliage que demanderait un état restauré (la CSP
   interdit le script inline qui le rétablirait avant la feuille). */

/* Plus de capsule en haut : les dégagements d'origine n'ont plus lieu d'être.
   `.hero` et `.page` gardent les leurs pour le wiki, qui n'a pas `.has-rail`. */
.has-rail .hero { padding-top: 104px; }
.has-rail .page { padding-top: 92px; }

.rail { position: fixed; left: 24px; top: 24px; bottom: 24px; z-index: 50; width: min(248px, calc(100vw - 96px)); transform: translateX(calc(-100% - 40px)); transition: transform .7s cubic-bezier(.34,1.25,.5,1); will-change: transform; }
.rail-open .rail { transform: none; }

/* Le panneau ne fait pas que glisser : il se dévoile. Flou, échelle et opacité
   sont repris tels quels du PDM, c'est ce qui donne le poids au mouvement. */
.rail__in { display: flex; flex-direction: column; gap: 22px; height: 100%; padding: 22px 14px 16px; border: 1px solid var(--line-1); border-radius: 1rem; background: rgba(8,8,8,.86); backdrop-filter: blur(24px); -webkit-backdrop-filter: blur(24px); box-shadow: 0 30px 80px -20px #000; opacity: 0; transform: scale(.96) translateX(-10px); filter: blur(6px); transition: opacity .45s ease, transform .7s cubic-bezier(.34,1.25,.5,1), filter .5s ease; }
.rail-open .rail__in { opacity: 1; transform: none; filter: blur(0); }

.rail__brand { gap: 10px; padding: 0 8px; opacity: 0; transform: translateY(-8px); transition: opacity .4s ease .05s, transform .5s cubic-bezier(.22,1,.36,1) .05s; }
.rail-open .rail__brand { opacity: 1; transform: none; }
.rail__brand img { flex: none; height: 30px; width: auto; }

.rail__sep { flex: none; height: 1px; background: var(--line-1); }

/* Les entrées entrent l'une après l'autre, 50 ms d'écart, décalées de 14 px
   vers la gauche : la cascade du PDM, à l'identique. */
.rail__links { display: flex; flex-direction: column; align-items: stretch; gap: 3px; }
.rail .nav-link { justify-content: flex-start; gap: .625rem; padding: 10px 12px; font-size: 14px; border-radius: .5rem; opacity: 0; transform: translateX(-14px); transition: opacity .4s ease, transform .5s cubic-bezier(.22,1,.36,1), background var(--transition-fast), border-color var(--transition-fast), color var(--transition-fast); }
.rail-open .rail .nav-link { opacity: 1; transform: none; }
.rail-open .rail__links .nav-link:nth-child(1) { transition-delay: .12s; }
.rail-open .rail__links .nav-link:nth-child(2) { transition-delay: .17s; }
.rail-open .rail__links .nav-link:nth-child(3) { transition-delay: .22s; }
.rail-open .rail__links .nav-link:nth-child(4) { transition-delay: .27s; }
.rail-open .rail__links .nav-link:nth-child(5) { transition-delay: .32s; }
.rail-open .rail__links .nav-link:nth-child(6) { transition-delay: .37s; }
.rail .nav-link svg { width: 16px; height: 16px; }

/* Page courante : le filet en dégradé de la capsule ne veut plus rien dire à la
   verticale. Le PDM marque la sienne d'une pastille allumée, reprise ici dans
   le jaune de la marque, plus un fond très léger. */
.rail .nav-link[aria-current="page"] { background: var(--surface-1); border-color: var(--line-1); color: var(--ink); }
.rail .nav-link[aria-current="page"]::after { content: none; }
.rail .nav-link::before { content: ""; flex: none; width: 5px; height: 5px; border-radius: 50%; background: transparent; transition: background var(--transition-fast), box-shadow var(--transition-fast); }
.rail .nav-link[aria-current="page"]::before { background: var(--fil); box-shadow: var(--fil-bloom); }
.rail .nav-badge { margin-left: auto; }

/* Le bas du panneau arrive en dernier, une fois les entrées posées. */
.rail__end { margin-top: auto; display: flex; flex-direction: column; align-items: stretch; gap: 8px; opacity: 0; transform: translateY(10px); transition: opacity .4s ease, transform .5s cubic-bezier(.22,1,.36,1); }
.rail-open .rail__end { opacity: 1; transform: none; transition-delay: .4s; }
.rail .nav-login { width: 100%; justify-content: center; gap: .5rem; }
.rail .nav-login svg { flex: none; width: 15px; height: 15px; }
.rail .lang { justify-content: center; }
.rail .acct-menu { top: auto; bottom: calc(100% + 10px); left: 0; right: auto; }
.rail__end .acct, .rail__end .acct-cart { align-self: center; }

/* Bouton d'ouverture : trois chevrons qui pulsent en cascade tant que le
   panneau est fermé. Ouvert, il se déporte à droite du panneau, pivote d'un
   demi-tour et passe en jaune plein. */
.rail__toggle { position: fixed; left: 24px; top: 24px; z-index: 60; display: inline-flex; align-items: center; justify-content: center; width: 46px; height: 46px; padding: 0; border: 1px solid var(--line-1); border-radius: 12px; background: rgba(8,8,8,.7); backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px); color: var(--ink-hi); cursor: pointer; transition: transform .7s cubic-bezier(.34,1.25,.5,1), background .3s, border-color .3s, color .3s, box-shadow .3s; }
.rail__toggle:hover { background: #ffffff14; border-color: var(--line-2); }
.rail__toggle svg { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }
.rail__toggle svg path { animation: chev 1.6s ease-in-out infinite; }
.rail__toggle svg path:nth-child(2) { animation-delay: .15s; }
.rail__toggle svg path:nth-child(3) { animation-delay: .3s; }
@keyframes chev { 0%, 100% { opacity: .35; } 50% { opacity: 1; } }
.rail__toggle[aria-expanded="true"] { transform: translateX(calc(min(248px, 100vw - 96px) + 20px)) rotate(180deg); background: var(--invert); color: var(--on-invert); border-color: var(--invert); box-shadow: 0 10px 30px -10px #000; }
.rail__toggle[aria-expanded="true"] svg path { animation: none; opacity: 1; }

/* Voile : le noir du PDM, et sa lueur de marque partant du bord gauche. */
.rail__scrim { position: fixed; inset: 0; z-index: 49; background: radial-gradient(900px 600px at 0% 50%, rgba(var(--acc-lum), .1), transparent 60%), rgba(0,0,0,.45); backdrop-filter: blur(3px); -webkit-backdrop-filter: blur(3px); opacity: 0; pointer-events: none; transition: opacity .5s ease; }
.rail-open .rail__scrim { opacity: 1; pointer-events: auto; }

@media (max-width: 720px) {
  .has-rail .hero { padding-top: 88px; }
  .has-rail .page { padding-top: 76px; }
  .rail { left: 16px; top: 16px; bottom: 16px; width: min(248px, calc(100vw - 72px)); }
  .rail__toggle { left: 16px; top: 16px; }
  .rail__toggle[aria-expanded="true"] { transform: translateX(calc(min(248px, 100vw - 72px) + 14px)) rotate(180deg); }
}

/* `prefers-reduced-motion` n'est volontairement PAS repris ici : c'est le choix
   assumé du user sur le PDM, il veut le mouvement même réglage système actif. */

/* ---------- Coupure du son ----------
   Même traitement que les drapeaux : atténué au repos, plein au survol. L'état
   vit dans `aria-pressed`, qui choisit l'icône : pas de classe en double. */
.rail__row { display: flex; align-items: center; justify-content: center; gap: 10px; }
.sfx-btn { display: inline-flex; padding: 3px; border: 1px solid transparent; border-radius: 4px; background: none; color: var(--ink-nav); cursor: pointer; line-height: 0; opacity: .5; transition: all var(--transition-fast); }
.sfx-btn:hover { opacity: 1; color: var(--ink); }
.sfx-btn:focus-visible { outline: none; border-color: var(--fil); }
.sfx-btn svg { display: block; width: 16px; height: 16px; }
.sfx-btn[aria-pressed="true"] { opacity: .85; }
.sfx-btn__off, .sfx-btn[aria-pressed="false"] .sfx-btn__on { display: none; }
.sfx-btn[aria-pressed="false"] .sfx-btn__off { display: block; }

/* ═══════════════ PIÈCE MAÎTRESSE INCLINÉE ET SA BRILLANCE ═══════════════
   La carte « fichier » du hero n'est plus de face : elle est vue de biais, en
   perspective, et un trait de lumière la traverse toutes les 5 secondes, comme
   un objet neuf derrière une vitrine.

   ⚠️ L'inclinaison est posée sur `.hero__card`, l'ENVELOPPE, et surtout pas sur
   `.patch-hero__panel` : le panneau porte déjà l'animation d'arrivée
   `patch-hero-rise`, qui finit sur `transform: none` et qui, en `both`, écrase
   toute transformation écrite en règle normale. L'inclinaison disparaîtrait à
   la fin de l'arrivée, sans erreur ni indice.

   Au survol la carte se redresse presque de face : c'est ce qui donne la
   sensation de la prendre en main. */
.hero__grid { perspective: 1600px; }
.hero__card { transform: rotateY(-9deg) rotateX(1.5deg); transform-origin: 80% 50%; transition: transform .8s cubic-bezier(.22,1,.36,1); will-change: transform; }
.hero__card:hover { transform: rotateY(-3.5deg) rotateX(.5deg); }

/* La brillance vit sur le panneau et non sur l'enveloppe : c'est lui qui est en
   `overflow: hidden` et qui a les coins arrondis, donc lui seul rogne le reflet
   proprement. `::before` est déjà pris par le filet du haut, d'où `::after`.
   Le balayage dure 0,9 s puis la bande attend hors champ le reste du cycle. */
.hero__card .patch-hero__panel::after {
  content: ""; position: absolute; inset: -40% -60%; z-index: 3; pointer-events: none;
  background: linear-gradient(105deg, transparent 38%, #ffffff1a 46%, rgba(var(--acc-lum), .22) 50%, #ffffff1a 54%, transparent 62%);
  mix-blend-mode: plus-lighter;
  transform: translateX(-120%);
  animation: brillance 5s cubic-bezier(.22,1,.36,1) infinite;
}
@keyframes brillance {
  0%   { transform: translateX(-120%); }
  18%  { transform: translateX(120%); }
  100% { transform: translateX(120%); }
}

/* En colonne la carte repasse sous le texte, centrée : une carte penchée y
   serait bancale, et la perspective mordrait sur la largeur. */
@media (max-width: 1100px) {
  .hero__grid { perspective: none; }
  .hero__card, .hero__card:hover { transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .hero__card .patch-hero__panel::after { animation: none; opacity: 0; }
}

/* ═══════════════ BANDE DYNAMIQUE, PORTÉE DU TICKER DU PDM ═══════════════
   Reprise du `.ticker` de `PDM/site/public/catalogue.css` : un vrai bandeau de
   44 px, verre flouté entre deux filets, items en mono « libellé puis valeur »
   séparés par un losange, et le défilement qui S'ARRÊTE AU SURVOL.

   Les règles de `base.css` restent intactes, cette feuille ne fait que les
   couvrir : `base.css` est un port strict du design system, on n'y touche pas.
   La bande du wiki, elle, n'est pas concernée, tout est sous `.hero__foot`. */
.hero__foot .marquee { height: 44px; display: flex; align-items: center; border-top: 1px solid var(--line-1); border-bottom: 1px solid var(--line-0); border-radius: 0; background: rgba(10,10,10,.6); backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent); -webkit-mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent); }

/* 60 s en linéaire, le double lent du PDM ramené à notre piste, qui est bien
   plus courte. `width: max-content` est indispensable : sans lui la piste se
   comprime et le `-50 %` ne retombe plus sur la copie. */
.hero__foot .marquee__track { gap: 0; padding-right: 0; animation-duration: 60s; }
.hero__foot .marquee:hover .marquee__track { animation-play-state: paused; }

.hero__foot .marquee__item { display: inline-flex; align-items: center; gap: 12px; padding: 0 22px; font-family: var(--font-mono); font-size: 12px; font-weight: 500; letter-spacing: .04em; text-transform: none; color: var(--ink-mid); }
.hero__foot .marquee__item i { font-style: normal; font-size: 10.5px; letter-spacing: .12em; text-transform: uppercase; color: var(--ink-decor); }
.hero__foot .marquee__item b { font-weight: 600; color: var(--ink-hi); }
/* Le losange de séparation, en jaune : c'est le seul endroit coloré de la
   bande, comme le losange d'accent du PDM. */
.hero__foot .marquee__item::after { content: "◆"; margin-left: 22px; font-size: 7px; color: var(--fil); }

@media (max-width: 720px) {
  .hero__foot .marquee { height: 38px; }
  .hero__foot .marquee__item { padding: 0 16px; gap: 9px; font-size: 11.5px; }
  .hero__foot .marquee__item::after { margin-left: 16px; }
}

/* ═══════════════════ PIÈCE MAÎTRESSE V2 ═══════════════════
   La proposition D de `/v2/`, retenue par le user : la barre de session du
   terminal, la gouttière numérotée de l'éditeur, le biseau et les hachures du
   HUD. Appliquée aux 16 panneaux du site, du wiki et de `/connect/`.

   ⚠️ Tout est en SURCHARGE : `base.css` est un port strict du design system,
   on n'y touche pas. Les classes de markup ne changent pas non plus, sauf la
   barre d'état, seul élément ajouté.

   ⚠️ Le biseau est un `clip-path` posé sur le panneau lui-même, sans
   enveloppe : une enveloppe casserait les grilles (`.hero__grid`,
   `.piece__grid`) dont les panneaux sont des enfants directs. Conséquence
   assumée : les deux arêtes coupées n'ont pas de filet, seules les arêtes
   droites gardent la bordure. */
.patch-hero__panel { border-radius: 0; clip-path: polygon(16px 0, 100% 0, 100% calc(100% - 16px), calc(100% - 16px) 100%, 0 100%, 0 16px); }

/* En-tête : hachures du HUD, et les trois pastilles de fenêtre dessinées en
   dégradés radiaux plutôt qu'en trois éléments de plus dans le markup. */
.patch-hero__tabbar { padding-left: 74px; background-image: repeating-linear-gradient(135deg, #ffffff05 0 2px, transparent 2px 7px), radial-gradient(circle 4px at 26px 50%, #ffffff33 99%, transparent), radial-gradient(circle 4px at 40px 50%, #ffffff1f 99%, transparent), radial-gradient(circle 4px at 54px 50%, #ffffff1f 99%, transparent); }

/* Gouttière : le tiret du markup devient le numéro de ligne, et un filet
   vertical sépare la colonne, comme dans un éditeur. Les numéros viennent d'un
   compteur CSS, donc rien à écrire dans les pages. */
.patch-hero__entries { position: relative; counter-reset: pmligne; padding-left: 12px; }
.patch-hero__entries::before { content: ""; position: absolute; left: 34px; top: 2px; bottom: 2px; width: 1px; background: var(--line-0); }
.patch-hero__entries li { counter-increment: pmligne; grid-template-columns: 34px max-content 1fr; column-gap: 14px; padding-left: 0; }
.patch-hero__dash { position: relative; font-size: 0; }
.patch-hero__dash::after { content: counter(pmligne, decimal-leading-zero); position: absolute; right: 12px; top: 0; font-family: var(--font-mono); font-size: 11px; color: var(--ink-ghost); }
.patch-hero__entries li:hover .patch-hero__dash::after { color: var(--invert); }
/* Le filet jaune de la ligne survolée, repris de la ligne courante de l'éditeur. */
.patch-hero__entries li { position: relative; }
.patch-hero__entries li:hover::before { content: ""; position: absolute; left: -12px; top: 3px; bottom: 3px; width: 2px; background: var(--fil); box-shadow: var(--fil-bloom); }

/* Barre d'état : le seul élément ajouté au markup, en bas de chaque panneau. */
.patch-hero__status { display: flex; flex-wrap: wrap; gap: 16px; padding: 9px 22px; border-top: 1px solid var(--line-0); background: #ffffff06; font-family: var(--font-mono); font-size: 10.5px; letter-spacing: .08em; text-transform: uppercase; color: var(--ink-decor); }
.patch-hero__status b { color: var(--ink-meta); font-weight: 500; }
.patch-hero__status-r { margin-left: auto; }
.patch-hero__status i { display: inline-block; width: 6px; height: 6px; margin-right: 7px; border-radius: 50%; background: var(--ok); box-shadow: 0 0 8px var(--ok); vertical-align: 0; }

/* Ligne de commande, réservée aux deux panneaux de tête : ailleurs, l'onglet
   dit déjà le nom du fichier et la répétition alourdirait. */
.patch-hero__cmd { display: flex; align-items: center; margin: 0 0 14px; font-family: var(--font-mono); font-size: 13px; color: var(--ink-hi); }
.patch-hero__cmd span { margin-right: 8px; color: var(--invert); }
.patch-hero__caret { display: inline-block; width: 8px; height: 15px; margin-left: 3px; background: var(--invert); animation: pm-bat 1.1s steps(1) infinite; }
@keyframes pm-bat { 0%, 49% { opacity: 1; } 50%, 100% { opacity: 0; } }

@media (max-width: 720px) {
  .patch-hero__tabbar { padding-left: 62px; background-position: 0 0, -6px 0, -6px 0, -6px 0; }
  .patch-hero__status { padding: 8px 16px; }
}
@media (prefers-reduced-motion: reduce) {
  .patch-hero__caret { animation: none; }
}

/* ═══════════════ BOUTIQUE : LES PIÈCES ET LE PALIER D'OR ═══════════════
   Les visuels des paquets ne viennent plus de Tebex mais de chez nous :
   `/img/shop/coin-1.webp` à `coin-7.webp`, sept piles de pièces animées,
   choisies par shop.js selon le rang du paquet. WebP animé et non GIF : le GIF
   n'a qu'un bit de transparence et bave sur tout bord adouci.

   Les deux paquets les plus chers reçoivent `.pack--or` : cadre doré, halo, et
   un reflet qui traverse la carte toutes les 6 secondes. C'est la seule entorse
   assumée à la règle du jaune, et elle est justifiée : ici la couleur EST
   l'information, elle dit « offre la plus forte ». */
.pack__img img { height: 104px; filter: drop-shadow(0 6px 14px #00000073); }

.pack--or { position: relative; overflow: hidden; border-color: #ffd40059; background: linear-gradient(180deg, #ffd4000a, transparent 42%); box-shadow: inset 0 1px #ffffff14, 0 0 0 1px #ffd4001f, 0 18px 40px -22px #ffd4004d; }
.pack--or h3 { color: var(--ink); }
.pack--or .pack__price { color: var(--invert); }
.pack--or .pack__img img { filter: drop-shadow(0 6px 18px #ffd4003d) drop-shadow(0 2px 6px #0000008c); }

/* Le reflet : une bande claire penchée qui traverse la carte, puis attend. Elle
   est en `plus-lighter` pour éclaircir sans laver les couleurs dessous. */
.pack--or::after { content: ""; position: absolute; top: -60%; bottom: -60%; left: -40%; width: 46px; pointer-events: none; background: linear-gradient(90deg, #fff8e000, #fff8e04d 45%, #fff8e08c 50%, #fff8e04d 55%, #fff8e000); mix-blend-mode: plus-lighter; transform: rotate(18deg) translateX(-120px); animation: pack-or 6s cubic-bezier(.22,1,.36,1) infinite; }
@keyframes pack-or {
  0%   { transform: rotate(18deg) translateX(-120px); }
  22%  { transform: rotate(18deg) translateX(560px); }
  100% { transform: rotate(18deg) translateX(560px); }
}

/* Un liseré d'or sur le bord haut, comme le filet blanc des panneaux. */
.pack--or::before { content: ""; position: absolute; top: 0; left: 8%; right: 8%; height: 1px; background: linear-gradient(90deg, transparent, #ffd400a6, transparent); }

@media (prefers-reduced-motion: reduce) {
  .pack--or::after { animation: none; opacity: .35; }
}

/* ---------- Ruban « populaire » ----------
   Bandeau rouge penché dans le coin haut droit des deux paquets les plus pris,
   aujourd'hui ceux à 12 et 24 euros. Comme l'or du palier haut, le rouge porte
   ici une information et non une décoration : c'est la seule raison pour
   laquelle il entre dans une charte qui n'admet que le jaune.

   Le ruban déborde volontairement de la carte, c'est l'`overflow: hidden` du
   `.pack` qui le coupe net à l'angle et lui donne sa forme. */
.pack { position: relative; overflow: hidden; }
.pack__ruban { position: absolute; top: 15px; right: -48px; z-index: 2; width: 168px; padding: 5px 0; transform: rotate(45deg); background: linear-gradient(180deg, #f04b41, #bf1a16); box-shadow: 0 8px 20px -8px #000000d9, inset 0 1px #ffffff3d; color: #fff; font-family: var(--font-mono); font-size: 10px; font-weight: 700; letter-spacing: .16em; text-transform: uppercase; text-align: center; pointer-events: none; }

/* Sur une carte en or, le rouge et le doré se cognent : le ruban est légèrement
   assombri pour rester lisible sans écraser le cadre. */
.pack--or .pack__ruban { background: linear-gradient(180deg, #e0413a, #a81512); }

/* ---------- Boutique : les effets de carte ----------
   La pile de pièces bouge déjà toute seule (tour sur soi-même, respiration,
   reflet). Ici on s'occupe de la CARTE : elle se soulève et s'incline
   légèrement à l'approche, la pile grossit et s'éclaire, et sur les paliers en
   or le cadre s'anime. Tout est en `transform` et en `opacity`, donc rien ne
   déclenche de remise en page. */
.pack { transition: transform .45s cubic-bezier(.22,1,.36,1), border-color .3s, box-shadow .45s; transform-style: preserve-3d; }
.pack:hover { transform: translateY(-6px); border-color: var(--line-2); box-shadow: 0 24px 50px -28px #000000e6; }
.pack__img { perspective: 700px; }
.pack__img img { transition: transform .5s cubic-bezier(.22,1,.36,1), filter .4s; }
.pack:hover .pack__img img { transform: translateY(-4px) scale(1.08) rotateY(-9deg); filter: drop-shadow(0 12px 22px #00000099) drop-shadow(0 0 16px #ffd40033); }
.pack .pack__price { transition: color .3s, text-shadow .3s; }
.pack:hover .pack__price { color: var(--ink); }

/* Palier d'or : le cadre respire, le prix s'allume, le reflet accélère au
   survol. Le liseré du haut devient un balayage lent, c'est lui qui donne
   l'impression de métal sous une lumière qui tourne. */
.pack--or { background-image: linear-gradient(180deg, #ffd4000f, transparent 42%); }
.pack--or:hover { border-color: #ffd40096; box-shadow: inset 0 1px #ffffff1a, 0 0 0 1px #ffd4003d, 0 26px 54px -26px #ffd4005c; }
.pack--or:hover .pack__price { color: var(--invert); text-shadow: 0 0 14px rgba(var(--acc-lum), .45); }
.pack--or::before { left: 0; right: 0; background: linear-gradient(90deg, transparent, #ffd400a6 20%, #fff8e0 50%, #ffd400a6 80%, transparent); background-size: 220% 100%; animation: or-liseré 4.5s linear infinite; }
@keyframes or-liseré { from { background-position: 120% 0; } to { background-position: -120% 0; } }
.pack--or:hover::after { animation-duration: 2.4s; }

/* Le ruban : un éclat le traverse toutes les cinq secondes, sinon il reste
   fixe. Au survol de la carte il se redresse d'un degré, juste assez pour
   qu'on sente qu'il fait partie du même objet. */
.pack__ruban { overflow: hidden; transition: transform .45s cubic-bezier(.22,1,.36,1); }
.pack:hover .pack__ruban { transform: rotate(44deg) scale(1.03); }
.pack__ruban::after { content: ""; position: absolute; inset: 0; background: linear-gradient(105deg, transparent 38%, #ffffff5c 47%, #ffffffa6 50%, #ffffff5c 53%, transparent 62%); transform: translateX(-110%); animation: ruban-éclat 5s cubic-bezier(.22,1,.36,1) infinite; }
@keyframes ruban-éclat {
  0%   { transform: translateX(-110%); }
  16%  { transform: translateX(110%); }
  100% { transform: translateX(110%); }
}

@media (prefers-reduced-motion: reduce) {
  .pack, .pack__img img, .pack__ruban { transition: none; }
  .pack--or::before, .pack__ruban::after { animation: none; }
}

/* ---------- Tableaux ----------
   Ils n'existaient que dans le wiki : les pages légales en ont besoin aussi.
   Même trame que les panneaux, en-tête mono, filets, ligne survolée éclairée. */
.tbl { width: 100%; margin: 18px 0 0; border-collapse: collapse; font-size: 13.5px; }
.tbl thead th { padding: 0 12px 8px 0; border-bottom: 1px solid var(--line-1); font-family: var(--font-mono); font-size: 10.5px; font-weight: 600; letter-spacing: .12em; text-transform: uppercase; text-align: left; color: var(--ink-decor); }
.tbl tbody td { padding: 10px 12px 10px 0; border-bottom: 1px solid var(--line-0); color: var(--ink-body); vertical-align: top; }
.tbl tbody tr:last-child td { border-bottom: none; }
.tbl tbody tr:hover td { background: var(--hover); }
.tbl tbody td:first-child { color: var(--ink-hi); }
.tbl code { font-family: var(--font-mono); font-size: 12px; color: var(--ink-hi); white-space: nowrap; }
@media (max-width: 720px) {
  .tbl, .tbl thead, .tbl tbody, .tbl tr, .tbl td, .tbl th { display: block; }
  .tbl thead { display: none; }
  .tbl tbody tr { padding: 12px 0; border-bottom: 1px solid var(--line-0); }
  .tbl tbody td { padding: 2px 0; border: none; }
  .tbl tbody td:first-child { font-weight: 600; }
}
